Add dry-run provisioning command generation
This commit is contained in:
@@ -2,6 +2,7 @@ package com.litoralregas.openvpn.openvpn;
|
|||||||
|
|
||||||
import org.springframework.data.jpa.repository.JpaRepository;
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
public interface IpAllocationRepository extends JpaRepository<IpAllocation, UUID> {
|
public interface IpAllocationRepository extends JpaRepository<IpAllocation, UUID> {
|
||||||
@@ -11,4 +12,5 @@ public interface IpAllocationRepository extends JpaRepository<IpAllocation, UUID
|
|||||||
boolean existsByLanSubnet(String lanSubnet);
|
boolean existsByLanSubnet(String lanSubnet);
|
||||||
|
|
||||||
boolean existsByVpnIp(String vpnIp);
|
boolean existsByVpnIp(String vpnIp);
|
||||||
|
Optional<IpAllocation> findByRouterId(UUID routerId);
|
||||||
}
|
}
|
||||||
@@ -113,4 +113,9 @@ public class IpAllocationService {
|
|||||||
public void delete(UUID id) {
|
public void delete(UUID id) {
|
||||||
repository.deleteById(id);
|
repository.deleteById(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IpAllocation findByRouterId(UUID routerId) {
|
||||||
|
return repository.findByRouterId(routerId)
|
||||||
|
.orElseThrow(() -> new IllegalArgumentException("No IP allocation found for router: " + routerId));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -64,4 +64,22 @@ public class OpenVpnService {
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String buildProvisionCommand(String clientName, String lanSubnet, String vpnIp) {
|
||||||
|
validateShellSafe(clientName);
|
||||||
|
validateShellSafe(lanSubnet);
|
||||||
|
validateShellSafe(vpnIp);
|
||||||
|
|
||||||
|
return properties.getToolsPath()
|
||||||
|
+ "/provision-client.sh "
|
||||||
|
+ clientName + " "
|
||||||
|
+ lanSubnet + " "
|
||||||
|
+ vpnIp;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateShellSafe(String value) {
|
||||||
|
if (value == null || !value.matches("^[a-zA-Z0-9._/-]+$")) {
|
||||||
|
throw new IllegalArgumentException("Unsafe command value: " + value);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -3,6 +3,8 @@ package com.litoralregas.openvpn.router;
|
|||||||
import com.litoralregas.openvpn.deployment.DeploymentAction;
|
import com.litoralregas.openvpn.deployment.DeploymentAction;
|
||||||
import com.litoralregas.openvpn.deployment.DeploymentResponse;
|
import com.litoralregas.openvpn.deployment.DeploymentResponse;
|
||||||
import com.litoralregas.openvpn.deployment.DeploymentService;
|
import com.litoralregas.openvpn.deployment.DeploymentService;
|
||||||
|
import com.litoralregas.openvpn.openvpn.IpAllocationService;
|
||||||
|
import com.litoralregas.openvpn.openvpn.OpenVpnService;
|
||||||
import com.litoralregas.openvpn.ssh.SshService;
|
import com.litoralregas.openvpn.ssh.SshService;
|
||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
@@ -17,11 +19,15 @@ public class RouterController {
|
|||||||
private final RouterService service;
|
private final RouterService service;
|
||||||
private final DeploymentService deploymentService;
|
private final DeploymentService deploymentService;
|
||||||
private final SshService sshService;
|
private final SshService sshService;
|
||||||
|
private final IpAllocationService ipAllocationService;
|
||||||
|
private final OpenVpnService openVpnService;
|
||||||
|
|
||||||
public RouterController(RouterService service, DeploymentService deploymentService, SshService sshService) {
|
public RouterController(RouterService service, DeploymentService deploymentService, SshService sshService, IpAllocationService ipAllocationService, OpenVpnService openVpnService) {
|
||||||
this.service = service;
|
this.service = service;
|
||||||
this.deploymentService = deploymentService;
|
this.deploymentService = deploymentService;
|
||||||
this.sshService = sshService;
|
this.sshService = sshService;
|
||||||
|
this.ipAllocationService = ipAllocationService;
|
||||||
|
this.openVpnService = openVpnService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping
|
@GetMapping
|
||||||
@@ -61,20 +67,22 @@ public class RouterController {
|
|||||||
try {
|
try {
|
||||||
service.forceStatus(id, RouterStatus.PROVISIONING);
|
service.forceStatus(id, RouterStatus.PROVISIONING);
|
||||||
|
|
||||||
var result = sshService.executeOnConfiguredVps(
|
var allocation = ipAllocationService.findByRouterId(id);
|
||||||
"echo 'Provisioning router: " + router.getName() + "' && whoami && hostname"
|
|
||||||
);
|
|
||||||
|
|
||||||
if (result.exitCode() != 0) {
|
String command = openVpnService.buildProvisionCommand(
|
||||||
throw new IllegalStateException(result.stderr());
|
allocation.getClientName(),
|
||||||
}
|
allocation.getLanSubnet(),
|
||||||
|
allocation.getVpnIp()
|
||||||
|
);
|
||||||
|
|
||||||
var finishedDeployment = deploymentService.finishSuccess(
|
var finishedDeployment = deploymentService.finishSuccess(
|
||||||
deployment,
|
deployment,
|
||||||
result.stdout()
|
"DRY RUN ONLY. Would execute: " + command
|
||||||
);
|
);
|
||||||
|
|
||||||
service.forceStatus(id, RouterStatus.REMOVING);
|
// Keep this as PROVISIONING? No — dry run succeeded but real provision did not happen.
|
||||||
|
// So we should NOT mark as PROVISIONED yet.
|
||||||
|
service.forceStatus(id, RouterStatus.PENDING);
|
||||||
|
|
||||||
return DeploymentResponse.from(finishedDeployment);
|
return DeploymentResponse.from(finishedDeployment);
|
||||||
} catch (Exception exception) {
|
} catch (Exception exception) {
|
||||||
|
|||||||
Reference in New Issue
Block a user