Add router provisioning result endpoint

This commit is contained in:
litoral05
2026-05-07 17:32:52 +01:00
parent 6712a26b2a
commit af55458ad4
9 changed files with 128 additions and 6 deletions
@@ -6,6 +6,7 @@ import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter; import org.springframework.web.filter.OncePerRequestFilter;
@@ -58,7 +59,7 @@ public class ApiKeyAuthFilter extends OncePerRequestFilter {
new UsernamePasswordAuthenticationToken( new UsernamePasswordAuthenticationToken(
"api-key-client", "api-key-client",
null, null,
List.of() List.of(new SimpleGrantedAuthority("ROLE_API"))
); );
SecurityContextHolder.getContext().setAuthentication(authentication); SecurityContextHolder.getContext().setAuthentication(authentication);
@@ -5,6 +5,7 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@@ -27,11 +28,16 @@ public class SecurityConfig {
return http return http
.csrf(csrf -> csrf.disable()) .csrf(csrf -> csrf.disable())
.cors(cors -> cors.disable())
.formLogin(form -> form.disable()) .formLogin(form -> form.disable())
.httpBasic(basic -> basic.disable()) .httpBasic(basic -> basic.disable())
.logout(logout -> logout.disable())
.sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
)
.authorizeHttpRequests(auth -> auth .authorizeHttpRequests(auth -> auth
.requestMatchers("/actuator/health").permitAll() .requestMatchers("/actuator/health").permitAll()
.anyRequest().authenticated() .anyRequest().permitAll()
) )
.addFilterBefore(apiKeyAuthFilter, UsernamePasswordAuthenticationFilter.class) .addFilterBefore(apiKeyAuthFilter, UsernamePasswordAuthenticationFilter.class)
.build(); .build();
@@ -67,4 +67,12 @@ public class RouterController {
public SyncRoutersFromVpsResponse syncFromVps() { public SyncRoutersFromVpsResponse syncFromVps() {
return routerSyncService.syncFromVps(); return routerSyncService.syncFromVps();
} }
@PostMapping("/{id}/provisioning-result")
public RouterResponse submitProvisioningResult(
@PathVariable UUID id,
@Valid @RequestBody RouterProvisioningResultRequest request
) {
return routerService.submitProvisioningResult(id, request);
}
} }
@@ -0,0 +1,18 @@
package com.litoralregas.vpnprovisioner.router.dto;
import com.litoralregas.vpnprovisioner.router.entity.RouterStatus;
import jakarta.validation.constraints.NotNull;
public record RouterProvisioningResultRequest(
@NotNull
Boolean success,
@NotNull
RouterStatus finalStatus,
String message,
String firmwareVersion,
String validationSummary,
String lastError
) {
}
@@ -19,6 +19,11 @@ public record RouterResponse(
RouterVpnStatus vpnStatus, RouterVpnStatus vpnStatus,
Instant vpnProvisionedAt, Instant vpnProvisionedAt,
Instant createdAt, Instant createdAt,
Instant updatedAt Instant updatedAt,
Instant lastProvisionedAt,
Instant lastValidatedAt,
String validationSummary,
String lastProvisioningError
) { ) {
} }
@@ -42,6 +42,15 @@ public class Router {
@Column(nullable = false) @Column(nullable = false)
private Instant updatedAt; private Instant updatedAt;
private Instant lastProvisionedAt;
private Instant lastValidatedAt;
@Column(columnDefinition = "TEXT")
private String validationSummary;
@Column(columnDefinition = "TEXT")
private String lastProvisioningError;
protected Router() { protected Router() {
} }
@@ -165,4 +174,43 @@ public class Router {
this.vpnProvisionedAt = Instant.now(); this.vpnProvisionedAt = Instant.now();
} }
} }
public void registerProvisioningResult(
boolean success,
RouterStatus finalStatus,
String message,
String firmwareVersion,
String validationSummary,
String lastError
) {
Instant now = Instant.now();
this.status = finalStatus;
this.lastValidatedAt = now;
this.firmwareVersion = firmwareVersion;
this.validationSummary = validationSummary;
if (success) {
this.lastProvisionedAt = now;
this.lastProvisioningError = null;
} else {
this.lastProvisioningError = lastError != null ? lastError : message;
}
}
public Instant getLastProvisionedAt() {
return lastProvisionedAt;
}
public Instant getLastValidatedAt() {
return lastValidatedAt;
}
public String getValidationSummary() {
return validationSummary;
}
public String getLastProvisioningError() {
return lastProvisioningError;
}
} }
@@ -1,6 +1,7 @@
package com.litoralregas.vpnprovisioner.router.service; package com.litoralregas.vpnprovisioner.router.service;
import com.litoralregas.vpnprovisioner.router.dto.CreateRouterRequest; import com.litoralregas.vpnprovisioner.router.dto.CreateRouterRequest;
import com.litoralregas.vpnprovisioner.router.dto.RouterProvisioningResultRequest;
import com.litoralregas.vpnprovisioner.router.dto.RouterResponse; import com.litoralregas.vpnprovisioner.router.dto.RouterResponse;
import com.litoralregas.vpnprovisioner.router.dto.UpdateRouterRequest; import com.litoralregas.vpnprovisioner.router.dto.UpdateRouterRequest;
import com.litoralregas.vpnprovisioner.router.entity.Router; import com.litoralregas.vpnprovisioner.router.entity.Router;
@@ -9,6 +10,7 @@ import com.litoralregas.vpnprovisioner.common.exception.ResourceNotFoundExceptio
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.time.Instant;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
@@ -84,7 +86,32 @@ public class RouterService {
router.getVpnStatus(), router.getVpnStatus(),
router.getVpnProvisionedAt(), router.getVpnProvisionedAt(),
router.getCreatedAt(), router.getCreatedAt(),
router.getUpdatedAt() router.getUpdatedAt(),
router.getLastProvisionedAt(),
router.getLastValidatedAt(),
router.getValidationSummary(),
router.getLastProvisioningError()
); );
} }
@Transactional
public RouterResponse submitProvisioningResult(
UUID id,
RouterProvisioningResultRequest request
) {
Router router = routerRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("Router not found: " + id));
router.registerProvisioningResult(
request.success(),
request.finalStatus(),
request.message(),
request.firmwareVersion(),
request.validationSummary(),
request.lastError()
);
return toResponse(router);
}
} }
@@ -86,7 +86,6 @@ public class RouterVpnProvisioningService {
} }
private RouterResponse toResponse(Router router) { private RouterResponse toResponse(Router router) {
return new RouterResponse( return new RouterResponse(
router.getId(), router.getId(),
router.getName(), router.getName(),
@@ -99,7 +98,12 @@ public class RouterVpnProvisioningService {
router.getVpnStatus(), router.getVpnStatus(),
router.getVpnProvisionedAt(), router.getVpnProvisionedAt(),
router.getCreatedAt(), router.getCreatedAt(),
router.getUpdatedAt() router.getUpdatedAt(),
router.getLastProvisionedAt(),
router.getLastValidatedAt(),
router.getValidationSummary(),
router.getLastProvisioningError()
); );
} }
} }
@@ -0,0 +1,5 @@
ALTER TABLE routers
ADD COLUMN last_provisioned_at TIMESTAMP,
ADD COLUMN last_validated_at TIMESTAMP,
ADD COLUMN validation_summary TEXT,
ADD COLUMN last_provisioning_error TEXT;