package com.sequenceiq.cloudbreak.core.flow2.stack.provision.action; import static com.sequenceiq.cloudbreak.core.flow2.stack.provision.StackProvisionConstants.START_DATE; import java.util.Date; import java.util.List; import java.util.Map; import java.util.Optional; import javax.inject.Inject; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.statemachine.action.Action; import com.sequenceiq.cloudbreak.cloud.event.Selectable; import com.sequenceiq.cloudbreak.cloud.event.instance.CollectMetadataRequest; import com.sequenceiq.cloudbreak.cloud.event.instance.CollectMetadataResult; import com.sequenceiq.cloudbreak.cloud.event.instance.GetSSHFingerprintsRequest; import com.sequenceiq.cloudbreak.cloud.event.instance.GetSSHFingerprintsResult; import com.sequenceiq.cloudbreak.cloud.event.instance.GetTlsInfoRequest; import com.sequenceiq.cloudbreak.cloud.event.instance.GetTlsInfoResult; import com.sequenceiq.cloudbreak.cloud.event.resource.CreateCredentialRequest; import com.sequenceiq.cloudbreak.cloud.event.resource.CreateCredentialResult; import com.sequenceiq.cloudbreak.cloud.event.resource.LaunchStackRequest; import com.sequenceiq.cloudbreak.cloud.event.resource.LaunchStackResult; import com.sequenceiq.cloudbreak.cloud.event.setup.PrepareImageRequest; import com.sequenceiq.cloudbreak.cloud.event.setup.SetupRequest; import com.sequenceiq.cloudbreak.cloud.event.setup.SetupResult; import com.sequenceiq.cloudbreak.cloud.event.setup.ValidationRequest; import com.sequenceiq.cloudbreak.cloud.event.setup.ValidationResult; import com.sequenceiq.cloudbreak.cloud.model.CloudInstance; import com.sequenceiq.cloudbreak.cloud.model.CloudResource; import com.sequenceiq.cloudbreak.cloud.model.CloudStack; import com.sequenceiq.cloudbreak.cloud.model.Image; import com.sequenceiq.cloudbreak.converter.spi.InstanceMetaDataToCloudInstanceConverter; import com.sequenceiq.cloudbreak.converter.spi.ResourceToCloudResourceConverter; import com.sequenceiq.cloudbreak.converter.spi.StackToCloudStackConverter; import com.sequenceiq.cloudbreak.core.CloudbreakImageNotFoundException; import com.sequenceiq.cloudbreak.core.flow2.stack.AbstractStackFailureAction; import com.sequenceiq.cloudbreak.core.flow2.stack.StackContext; import com.sequenceiq.cloudbreak.core.flow2.stack.StackFailureContext; import com.sequenceiq.cloudbreak.core.flow2.stack.provision.StackCreationEvent; import com.sequenceiq.cloudbreak.core.flow2.stack.provision.StackCreationState; import com.sequenceiq.cloudbreak.domain.FailurePolicy; import com.sequenceiq.cloudbreak.domain.InstanceMetaData; import com.sequenceiq.cloudbreak.domain.Stack; import com.sequenceiq.cloudbreak.reactor.api.event.StackEvent; import com.sequenceiq.cloudbreak.reactor.api.event.StackFailureEvent; import com.sequenceiq.cloudbreak.reactor.api.event.stack.StackWithFingerprintsEvent; import com.sequenceiq.cloudbreak.service.CloudbreakServiceException; import com.sequenceiq.cloudbreak.service.image.ImageService; @Configuration public class StackCreationActions { public static final String TLS_INFO_KEY = "TLS_INFO"; @Inject private ImageService imageService; @Inject private StackToCloudStackConverter cloudStackConverter; @Inject private StackCreationService stackCreationService; @Inject private ResourceToCloudResourceConverter cloudResourceConverter; @Inject private InstanceMetaDataToCloudInstanceConverter metadataConverter; @Bean(name = "VALIDATION_STATE") public Action provisioningValidationAction() { return new AbstractStackCreationAction<StackEvent>(StackEvent.class) { @Override protected void doExecute(StackContext context, StackEvent payload, Map<Object, Object> variables) throws Exception { sendEvent(context); } @Override protected Selectable createRequest(StackContext context) { return new ValidationRequest(context.getCloudContext(), context.getCloudCredential(), context.getCloudStack()); } }; } @Bean(name = "SETUP_STATE") public Action provisioningSetupAction() { return new AbstractStackCreationAction<ValidationResult>(ValidationResult.class) { @Override protected void doExecute(StackContext context, ValidationResult payload, Map<Object, Object> variables) throws Exception { stackCreationService.setupProvision(context.getStack()); sendEvent(context); } @Override protected Selectable createRequest(StackContext context) { return new SetupRequest<SetupResult>(context.getCloudContext(), context.getCloudCredential(), context.getCloudStack()); } }; } @Bean(name = "IMAGESETUP_STATE") public Action prepareImageAction() { return new AbstractStackCreationAction<SetupResult>(SetupResult.class) { @Override protected void doExecute(StackContext context, SetupResult payload, Map<Object, Object> variables) throws Exception { stackCreationService.prepareImage(context.getStack()); sendEvent(context); } @Override protected Selectable createRequest(StackContext context) { try { CloudStack cloudStack = cloudStackConverter.convert(context.getStack()); Image image = imageService.getImage(context.getCloudContext().getId()); return new PrepareImageRequest<>(context.getCloudContext(), context.getCloudCredential(), cloudStack, image); } catch (CloudbreakImageNotFoundException e) { throw new CloudbreakServiceException(e); } } }; } @Bean(name = "CREATE_CREDENTIAL_STATE") public Action createCredentialAction() { return new AbstractStackCreationAction<StackEvent>(StackEvent.class) { @Override protected void doExecute(StackContext context, StackEvent payload, Map<Object, Object> variables) throws Exception { variables.put(START_DATE, new Date()); stackCreationService.startProvisioning(context); sendEvent(context); } @Override protected Selectable createRequest(StackContext context) { return new CreateCredentialRequest(context.getCloudContext(), context.getCloudCredential(), context.getCloudStack()); } }; } @Bean(name = "START_PROVISIONING_STATE") public Action startProvisioningAction() { return new AbstractStackCreationAction<CreateCredentialResult>(CreateCredentialResult.class) { @Override protected void doExecute(StackContext context, CreateCredentialResult payload, Map<Object, Object> variables) throws Exception { sendEvent(context); } @Override protected Selectable createRequest(StackContext context) { FailurePolicy policy = Optional.ofNullable(context.getStack().getFailurePolicy()).orElse(new FailurePolicy()); return new LaunchStackRequest(context.getCloudContext(), context.getCloudCredential(), context.getCloudStack(), policy.getAdjustmentType(), policy.getThreshold()); } }; } @Bean(name = "PROVISIONING_FINISHED_STATE") public Action provisioningFinishedAction() { return new AbstractStackCreationAction<LaunchStackResult>(LaunchStackResult.class) { @Override protected void doExecute(StackContext context, LaunchStackResult payload, Map<Object, Object> variables) throws Exception { Stack stack = stackCreationService.provisioningFinished(context, payload, variables); StackContext newContext = new StackContext(context.getFlowId(), stack, context.getCloudContext(), context.getCloudCredential(), context.getCloudStack()); sendEvent(newContext); } @Override protected Selectable createRequest(StackContext context) { List<CloudInstance> cloudInstances = cloudStackConverter.buildInstances(context.getStack()); List<CloudResource> cloudResources = cloudResourceConverter.convert(context.getStack().getResources()); return new CollectMetadataRequest(context.getCloudContext(), context.getCloudCredential(), cloudResources, cloudInstances); } }; } @Bean(name = "COLLECTMETADATA_STATE") public Action collectMetadataAction() { return new AbstractStackCreationAction<CollectMetadataResult>(CollectMetadataResult.class) { @Override protected void doExecute(StackContext context, CollectMetadataResult payload, Map<Object, Object> variables) throws Exception { Stack stack = stackCreationService.setupMetadata(context, payload); StackContext newContext = new StackContext(context.getFlowId(), stack, context.getCloudContext(), context.getCloudCredential(), context.getCloudStack()); sendEvent(newContext); } @Override protected Selectable createRequest(StackContext context) { CloudStack cloudStack = cloudStackConverter.convert(context.getStack()); return new GetTlsInfoRequest<GetTlsInfoResult>(context.getCloudContext(), context.getCloudCredential(), cloudStack); } }; } @Bean(name = "GET_TLS_INFO_STATE") public Action getTlsInfoAction() { return new AbstractStackCreationAction<GetTlsInfoResult>(GetTlsInfoResult.class) { @Override protected void doExecute(StackContext context, GetTlsInfoResult payload, Map<Object, Object> variables) throws Exception { Stack stack = stackCreationService.saveTlsInfo(context, payload.getTlsInfo()); StackContext newContext = new StackContext(context.getFlowId(), stack, context.getCloudContext(), context.getCloudCredential(), context.getCloudStack()); sendEvent(newContext); } @Override protected Selectable createRequest(StackContext context) { InstanceMetaData gatewayMetaData = context.getStack().getPrimaryGatewayInstance(); CloudInstance gatewayInstance = metadataConverter.convert(gatewayMetaData); return new GetSSHFingerprintsRequest<GetSSHFingerprintsResult>(context.getCloudContext(), context.getCloudCredential(), gatewayInstance); } }; } @Bean(name = "TLS_SETUP_STATE") public Action tlsSetupAction() { return new AbstractStackCreationAction<GetSSHFingerprintsResult>(GetSSHFingerprintsResult.class) { @Override protected void doExecute(StackContext context, GetSSHFingerprintsResult payload, Map<Object, Object> variables) throws Exception { stackCreationService.setupTls(context, payload); StackWithFingerprintsEvent fingerprintsEvent = new StackWithFingerprintsEvent(payload.getStackId(), payload.getSshFingerprints()); sendEvent(context.getFlowId(), StackCreationEvent.TLS_SETUP_FINISHED_EVENT.event(), fingerprintsEvent); } }; } @Bean(name = "STACK_CREATION_FINISHED_STATE") public Action stackCreationFinishedAction() { return new AbstractStackCreationAction<StackWithFingerprintsEvent>(StackWithFingerprintsEvent.class) { @Override protected void doExecute(StackContext context, StackWithFingerprintsEvent payload, Map<Object, Object> variables) throws Exception { stackCreationService.removeTemporarySShKey(context, payload.getSshFingerprints()); stackCreationService.stackCreationFinished(context.getStack()); sendEvent(context); } @Override protected Selectable createRequest(StackContext context) { return new StackEvent(StackCreationEvent.STACK_CREATION_FINISHED_EVENT.event(), context.getStack().getId()); } }; } @Bean(name = "STACK_CREATION_FAILED_STATE") public Action stackCreationFailureAction() { return new AbstractStackFailureAction<StackCreationState, StackCreationEvent>() { @Override protected void doExecute(StackFailureContext context, StackFailureEvent payload, Map<Object, Object> variables) throws Exception { stackCreationService.handleStackCreationFailure(context.getStack(), payload.getException()); sendEvent(context); } @Override protected Selectable createRequest(StackFailureContext context) { return new StackEvent(StackCreationEvent.STACKCREATION_FAILURE_HANDLED_EVENT.event(), context.getStack().getId()); } }; } }