EntandoBundleOperationResourceController.java
package org.entando.kubernetes.controller.digitalexchange.job;
import static org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder.on;
import java.net.URI;
import java.util.Collections;
import java.util.Optional;
import javax.servlet.http.HttpServletRequest;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import org.entando.kubernetes.controller.digitalexchange.job.model.InstallPlan;
import org.entando.kubernetes.controller.digitalexchange.job.model.InstallPlansRequest;
import org.entando.kubernetes.controller.digitalexchange.job.model.InstallRequest;
import org.entando.kubernetes.controller.digitalexchange.job.model.InstallWithPlansRequest;
import org.entando.kubernetes.exception.digitalexchange.InvalidBundleException;
import org.entando.kubernetes.exception.job.JobConflictException;
import org.entando.kubernetes.exception.job.JobNotFoundException;
import org.entando.kubernetes.exception.k8ssvc.BundleNotFoundException;
import org.entando.kubernetes.model.debundle.EntandoDeBundle;
import org.entando.kubernetes.model.debundle.EntandoDeBundleTag;
import org.entando.kubernetes.model.job.EntandoBundleJobEntity;
import org.entando.kubernetes.model.job.JobType;
import org.entando.kubernetes.model.web.response.RestError;
import org.entando.kubernetes.model.web.response.SimpleRestResponse;
import org.entando.kubernetes.service.KubernetesService;
import org.entando.kubernetes.service.digitalexchange.BundleUtilities;
import org.entando.kubernetes.service.digitalexchange.job.EntandoBundleInstallService;
import org.entando.kubernetes.service.digitalexchange.job.EntandoBundleJobService;
import org.entando.kubernetes.service.digitalexchange.job.EntandoBundleUninstallService;
import org.entando.kubernetes.validator.InstallPlanValidator;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder;
@RestController
@RequiredArgsConstructor
public class EntandoBundleOperationResourceController implements EntandoBundleOperationResource {
private final @NonNull KubernetesService kubeService;
private final @NonNull EntandoBundleJobService jobService;
private final @NonNull EntandoBundleInstallService installService;
private final @NonNull EntandoBundleUninstallService uninstallService;
private final @NonNull InstallPlanValidator installPlanValidator;
@Override
public ResponseEntity<SimpleRestResponse<InstallPlan>> installPlans(
@PathVariable("component") String componentId,
@RequestBody(required = false) InstallPlansRequest installPlansRequest) {
final InstallPlansRequest request = Optional.ofNullable(installPlansRequest).orElse(new InstallPlansRequest());
EntandoDeBundle bundle = kubeService.fetchBundleByName(componentId)
.orElseThrow(() -> new BundleNotFoundException(componentId));
EntandoDeBundleTag tag = getBundleTagOrFail(bundle, request.getVersion());
InstallPlan installPlan = installService
.generateInstallPlan(bundle, tag, EntandoBundleInstallService.PERFORM_CONCURRENT_CHECKS);
return ResponseEntity.ok(new SimpleRestResponse<>(installPlan));
}
@Override
public ResponseEntity<SimpleRestResponse<EntandoBundleJobEntity>> install(
@PathVariable("component") String componentId,
@RequestBody(required = false) InstallRequest installRequest) {
final InstallRequest request = Optional.ofNullable(installRequest).orElse(new InstallRequest());
EntandoDeBundle bundle = kubeService.fetchBundleByName(componentId)
.orElseThrow(() -> new BundleNotFoundException(componentId));
EntandoDeBundleTag tag = getBundleTagOrFail(bundle, request.getVersion());
EntandoBundleJobEntity installJob = jobService.findCompletedOrConflictingInstallJob(bundle)
.orElseGet(() -> installService.install(bundle, tag, request.getConflictStrategy()));
return ResponseEntity.created(
getJobLocationURI(installJob))
.body(new SimpleRestResponse<>(installJob));
}
@Override
public ResponseEntity<SimpleRestResponse<EntandoBundleJobEntity>> installWithInstallPlan(
@PathVariable("component") String componentId,
@RequestBody(required = false) InstallWithPlansRequest installRequest) {
final InstallWithPlansRequest request = Optional.ofNullable(installRequest).orElse(new InstallWithPlansRequest());
installPlanValidator.validateInstallPlanOrThrow(installRequest);
EntandoDeBundle bundle = kubeService.fetchBundleByName(componentId)
.orElseThrow(() -> new BundleNotFoundException(componentId));
EntandoDeBundleTag tag = getBundleTagOrFail(bundle, request.getVersion());
EntandoBundleJobEntity installJob = jobService.findCompletedOrConflictingInstallJob(bundle)
.orElseGet(() -> installService.installWithInstallPlan(bundle, tag, request));
return ResponseEntity.created(
getJobLocationURI(installJob))
.body(new SimpleRestResponse<>(installJob));
}
@Override
public SimpleRestResponse<EntandoBundleJobEntity> getLastInstallJob(@PathVariable("component") String componentId) {
return new SimpleRestResponse<>(executeGetLastInstallJow(componentId));
}
@Override
public SimpleRestResponse<EntandoBundleJobEntity> getLastInstallJobWithInstallPlan(String componentId) {
return new SimpleRestResponse<>(executeGetLastInstallJow(componentId));
}
private EntandoBundleJobEntity executeGetLastInstallJow(String componentId) {
return jobService.getJobs(componentId)
.stream().filter(j -> j.getStatus().isOfType(JobType.INSTALL))
.findFirst()
.orElseThrow(JobNotFoundException::new);
}
@Override
public ResponseEntity<SimpleRestResponse<EntandoBundleJobEntity>> uninstall(
@PathVariable("component") String componentId, HttpServletRequest request) {
try {
EntandoBundleJobEntity uninstallJob = uninstallService.uninstall(componentId);
return ResponseEntity.created(
getJobLocationURI(uninstallJob))
.body(new SimpleRestResponse<>(uninstallJob));
} catch (JobConflictException e) {
SimpleRestResponse<EntandoBundleJobEntity> restResponse = new SimpleRestResponse<>();
restResponse.setErrors(Collections.singletonList(new RestError("100", e.getMessage())));
return ResponseEntity.status(e.getStatus())
.body(restResponse);
}
}
@Override
public SimpleRestResponse<EntandoBundleJobEntity> getLastUninstallJob(
@PathVariable("component") String componentId) {
EntandoBundleJobEntity lastUninstallJob = jobService.getJobs(componentId)
.stream()
.filter(j -> j.getStatus().isOfType(JobType.UNINSTALL))
.findFirst()
.orElseThrow(JobNotFoundException::new);
return new SimpleRestResponse<>(lastUninstallJob);
}
private URI getJobLocationURI(EntandoBundleJobEntity job) {
return MvcUriComponentsBuilder
.fromMethodCall(on(EntandoBundleJobResourceController.class).getJob(job.getId().toString()))
.build().toUri();
}
private EntandoDeBundleTag getBundleTagOrFail(EntandoDeBundle bundle, String version) {
String versionToFind = BundleUtilities.getBundleVersionOrFail(bundle, version);
return bundle.getSpec().getTags().stream().filter(t -> t.getVersion().equals(versionToFind)).findAny()
.orElseThrow(
() -> new InvalidBundleException("Version " + versionToFind + " not defined in bundle versions"));
}
}