From f92ac6bb7022bdf420e6f18ffd012feee7758b75 Mon Sep 17 00:00:00 2001 From: Stu Pollock Date: Wed, 13 Mar 2019 17:20:22 -0400 Subject: [PATCH] feat(cf): Add Sharing / Unsharing of services - Also removed Autowired fields from com.netflix.spinnaker.orca.clouddriver.pipeline.servicebroker.*ServiceStage - Also converted all service-related tests from Spock to JUnit spinnaker/spinnaker#4065 Co-Authored-By: Jason Chu --- ...oundryDestroyServiceStagePreprocessor.java | 1 - ...dFoundryShareServiceStagePreprocessor.java | 40 +++++ ...oundryUnshareServiceStagePreprocessor.java | 40 +++++ .../servicebroker/DeployServiceStage.java | 17 +- .../servicebroker/DestroyServiceStage.java | 17 +- .../servicebroker/ShareServiceStage.java | 50 ++++++ .../ShareServiceStagePreprocessor.java | 32 ++++ .../servicebroker/UnshareServiceStage.java | 50 ++++++ .../UnshareServiceStagePreprocessor.java | 32 ++++ .../cf/AbstractCloudFoundryServiceTask.java | 60 +++++++ .../cf/CloudFoundryDestroyServiceTask.java | 33 +--- .../CloudFoundryMonitorKatoServicesTask.java | 2 +- .../cf/CloudFoundryShareServiceTask.java | 32 ++++ .../cf/CloudFoundryUnshareServiceTask.java | 32 ++++ .../CloudFoundryWaitForDeployServiceTask.java | 12 +- ...CloudFoundryWaitForDestroyServiceTask.java | 12 +- .../AbstractWaitForServiceTask.java | 16 +- ...yDeployServiceStagePreprocessorSpec.groovy | 53 ------- ...DestroyServiceStagePreprocessorSpec.groovy | 50 ------ .../CloudFoundryDestroyServiceTaskTest.groovy | 66 -------- ...dFoundryMonitorKatoServicesTaskTest.groovy | 148 ------------------ ...FoundryWaitForDeployServiceTaskTest.groovy | 130 --------------- ...oundryWaitForDestroyServiceTaskTest.groovy | 129 --------------- ...dryDeployServiceStagePreprocessorTest.java | 57 +++++++ ...ryDestroyServiceStagePreprocessorTest.java | 55 +++++++ ...ndryShareServiceStagePreprocessorTest.java | 55 +++++++ ...ryUnshareServiceStagePreprocessorTest.java | 55 +++++++ ...oundryWaitForServiceOperationTaskTest.java | 76 +++++++++ .../cf/CloudFoundryDeployServiceTaskTest.java | 16 ++ .../CloudFoundryDestroyServiceTaskTest.java | 71 +++++++++ ...oudFoundryMonitorKatoServicesTaskTest.java | 127 +++++++++++++++ ...udFoundryWaitForDeployServiceTaskTest.java | 54 +++++++ ...dFoundryWaitForDestroyServiceTaskTest.java | 49 ++++++ 33 files changed, 1021 insertions(+), 648 deletions(-) create mode 100644 orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/providers/cf/CloudFoundryShareServiceStagePreprocessor.java create mode 100644 orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/providers/cf/CloudFoundryUnshareServiceStagePreprocessor.java create mode 100644 orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/servicebroker/ShareServiceStage.java create mode 100644 orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/servicebroker/ShareServiceStagePreprocessor.java create mode 100644 orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/servicebroker/UnshareServiceStage.java create mode 100644 orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/servicebroker/UnshareServiceStagePreprocessor.java create mode 100644 orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/AbstractCloudFoundryServiceTask.java create mode 100644 orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/CloudFoundryShareServiceTask.java create mode 100644 orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/CloudFoundryUnshareServiceTask.java delete mode 100644 orca-clouddriver/src/test/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/providers/cf/CloudFoundryDeployServiceStagePreprocessorSpec.groovy delete mode 100644 orca-clouddriver/src/test/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/providers/cf/CloudFoundryDestroyServiceStagePreprocessorSpec.groovy delete mode 100644 orca-clouddriver/src/test/groovy/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/CloudFoundryDestroyServiceTaskTest.groovy delete mode 100644 orca-clouddriver/src/test/groovy/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/CloudFoundryMonitorKatoServicesTaskTest.groovy delete mode 100644 orca-clouddriver/src/test/groovy/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/CloudFoundryWaitForDeployServiceTaskTest.groovy delete mode 100644 orca-clouddriver/src/test/groovy/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/CloudFoundryWaitForDestroyServiceTaskTest.groovy create mode 100644 orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/clouddriver/pipeline/providers/cf/CloudFoundryDeployServiceStagePreprocessorTest.java create mode 100644 orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/clouddriver/pipeline/providers/cf/CloudFoundryDestroyServiceStagePreprocessorTest.java create mode 100644 orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/clouddriver/pipeline/providers/cf/CloudFoundryShareServiceStagePreprocessorTest.java create mode 100644 orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/clouddriver/pipeline/providers/cf/CloudFoundryUnshareServiceStagePreprocessorTest.java create mode 100644 orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/AbstractCloudFoundryWaitForServiceOperationTaskTest.java create mode 100644 orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/CloudFoundryDestroyServiceTaskTest.java create mode 100644 orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/CloudFoundryMonitorKatoServicesTaskTest.java create mode 100644 orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/CloudFoundryWaitForDeployServiceTaskTest.java create mode 100644 orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/CloudFoundryWaitForDestroyServiceTaskTest.java diff --git a/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/providers/cf/CloudFoundryDestroyServiceStagePreprocessor.java b/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/providers/cf/CloudFoundryDestroyServiceStagePreprocessor.java index 37b0984990..908a81e70d 100644 --- a/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/providers/cf/CloudFoundryDestroyServiceStagePreprocessor.java +++ b/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/providers/cf/CloudFoundryDestroyServiceStagePreprocessor.java @@ -19,7 +19,6 @@ import com.netflix.spinnaker.orca.clouddriver.pipeline.servicebroker.DestroyServiceStagePreprocessor; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.cf.CloudFoundryDestroyServiceTask; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.cf.CloudFoundryMonitorKatoServicesTask; -import com.netflix.spinnaker.orca.clouddriver.tasks.providers.cf.CloudFoundryWaitForDeployServiceTask; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.cf.CloudFoundryWaitForDestroyServiceTask; import com.netflix.spinnaker.orca.kato.pipeline.support.StageData; import com.netflix.spinnaker.orca.pipeline.TaskNode; diff --git a/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/providers/cf/CloudFoundryShareServiceStagePreprocessor.java b/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/providers/cf/CloudFoundryShareServiceStagePreprocessor.java new file mode 100644 index 0000000000..3782b52c7e --- /dev/null +++ b/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/providers/cf/CloudFoundryShareServiceStagePreprocessor.java @@ -0,0 +1,40 @@ +/* + * Copyright 2019 Pivotal, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.netflix.spinnaker.orca.clouddriver.pipeline.providers.cf; + +import com.netflix.spinnaker.orca.clouddriver.pipeline.servicebroker.ShareServiceStagePreprocessor; +import com.netflix.spinnaker.orca.clouddriver.tasks.providers.cf.CloudFoundryMonitorKatoServicesTask; +import com.netflix.spinnaker.orca.clouddriver.tasks.providers.cf.CloudFoundryShareServiceTask; +import com.netflix.spinnaker.orca.kato.pipeline.support.StageData; +import com.netflix.spinnaker.orca.pipeline.TaskNode; +import com.netflix.spinnaker.orca.pipeline.model.Stage; +import org.springframework.stereotype.Component; + +@Component +public class CloudFoundryShareServiceStagePreprocessor implements ShareServiceStagePreprocessor { + @Override + public boolean supports(Stage stage) { + return "cloudfoundry".equals(stage.mapTo(StageData.class).getCloudProvider()); + } + + @Override + public void addSteps(TaskNode.Builder builder, Stage stage) { + builder + .withTask("shareService", CloudFoundryShareServiceTask.class) + .withTask("monitorShareService", CloudFoundryMonitorKatoServicesTask.class); + } +} diff --git a/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/providers/cf/CloudFoundryUnshareServiceStagePreprocessor.java b/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/providers/cf/CloudFoundryUnshareServiceStagePreprocessor.java new file mode 100644 index 0000000000..2590ea0dc9 --- /dev/null +++ b/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/providers/cf/CloudFoundryUnshareServiceStagePreprocessor.java @@ -0,0 +1,40 @@ +/* + * Copyright 2019 Pivotal, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.netflix.spinnaker.orca.clouddriver.pipeline.providers.cf; + +import com.netflix.spinnaker.orca.clouddriver.pipeline.servicebroker.UnshareServiceStagePreprocessor; +import com.netflix.spinnaker.orca.clouddriver.tasks.providers.cf.CloudFoundryMonitorKatoServicesTask; +import com.netflix.spinnaker.orca.clouddriver.tasks.providers.cf.CloudFoundryUnshareServiceTask; +import com.netflix.spinnaker.orca.kato.pipeline.support.StageData; +import com.netflix.spinnaker.orca.pipeline.TaskNode; +import com.netflix.spinnaker.orca.pipeline.model.Stage; +import org.springframework.stereotype.Component; + +@Component +public class CloudFoundryUnshareServiceStagePreprocessor implements UnshareServiceStagePreprocessor { + @Override + public boolean supports(Stage stage) { + return "cloudfoundry".equals(stage.mapTo(StageData.class).getCloudProvider()); + } + + @Override + public void addSteps(TaskNode.Builder builder, Stage stage) { + builder + .withTask("unshareService", CloudFoundryUnshareServiceTask.class) + .withTask("monitorUnshareService", CloudFoundryMonitorKatoServicesTask.class); + } +} diff --git a/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/servicebroker/DeployServiceStage.java b/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/servicebroker/DeployServiceStage.java index e06ff8ba69..539cc5d561 100644 --- a/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/servicebroker/DeployServiceStage.java +++ b/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/servicebroker/DeployServiceStage.java @@ -16,27 +16,28 @@ package com.netflix.spinnaker.orca.clouddriver.pipeline.servicebroker; -import com.netflix.spinnaker.orca.clouddriver.pipeline.AbstractCloudProviderAwareStage; -import com.netflix.spinnaker.orca.clouddriver.pipeline.servicebroker.DeployServiceStagePreprocessor; +import com.netflix.spinnaker.orca.clouddriver.utils.CloudProviderAware; +import com.netflix.spinnaker.orca.pipeline.StageDefinitionBuilder; import com.netflix.spinnaker.orca.pipeline.TaskNode; import com.netflix.spinnaker.orca.pipeline.model.Stage; -import groovy.transform.CompileStatic; -import org.springframework.beans.factory.annotation.Autowired; +import lombok.AllArgsConstructor; import org.springframework.stereotype.Component; import javax.annotation.Nonnull; import java.util.ArrayList; import java.util.List; +@AllArgsConstructor @Component -class DeployServiceStage extends AbstractCloudProviderAwareStage { +class DeployServiceStage implements StageDefinitionBuilder, CloudProviderAware { public static final String PIPELINE_CONFIG_TYPE = "deployService"; - @Autowired(required = false) List deployServiceStagePreprocessors = new ArrayList<>(); - public DeployServiceStage() { - super(PIPELINE_CONFIG_TYPE); + @Nonnull + @Override + public String getType() { + return PIPELINE_CONFIG_TYPE; } @Override diff --git a/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/servicebroker/DestroyServiceStage.java b/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/servicebroker/DestroyServiceStage.java index 6c839ef56a..f17f1ade7f 100644 --- a/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/servicebroker/DestroyServiceStage.java +++ b/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/servicebroker/DestroyServiceStage.java @@ -16,27 +16,28 @@ package com.netflix.spinnaker.orca.clouddriver.pipeline.servicebroker; -import com.netflix.spinnaker.orca.clouddriver.pipeline.AbstractCloudProviderAwareStage; -import com.netflix.spinnaker.orca.clouddriver.pipeline.servicebroker.DestroyServiceStagePreprocessor; +import com.netflix.spinnaker.orca.clouddriver.utils.CloudProviderAware; +import com.netflix.spinnaker.orca.pipeline.StageDefinitionBuilder; import com.netflix.spinnaker.orca.pipeline.TaskNode; import com.netflix.spinnaker.orca.pipeline.model.Stage; -import groovy.transform.CompileStatic; -import org.springframework.beans.factory.annotation.Autowired; +import lombok.AllArgsConstructor; import org.springframework.stereotype.Component; import javax.annotation.Nonnull; import java.util.ArrayList; import java.util.List; +@AllArgsConstructor @Component -class DestroyServiceStage extends AbstractCloudProviderAwareStage { +class DestroyServiceStage implements StageDefinitionBuilder, CloudProviderAware { public static final String PIPELINE_CONFIG_TYPE = "destroyService"; - @Autowired(required = false) List destroyServiceStagePreprocessors = new ArrayList<>(); - public DestroyServiceStage() { - super(PIPELINE_CONFIG_TYPE); + @Nonnull + @Override + public String getType() { + return PIPELINE_CONFIG_TYPE; } @Override diff --git a/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/servicebroker/ShareServiceStage.java b/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/servicebroker/ShareServiceStage.java new file mode 100644 index 0000000000..5582e60d08 --- /dev/null +++ b/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/servicebroker/ShareServiceStage.java @@ -0,0 +1,50 @@ +/* + * Copyright 2019 Pivotal, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.netflix.spinnaker.orca.clouddriver.pipeline.servicebroker; + +import com.netflix.spinnaker.orca.clouddriver.utils.CloudProviderAware; +import com.netflix.spinnaker.orca.pipeline.StageDefinitionBuilder; +import com.netflix.spinnaker.orca.pipeline.TaskNode; +import com.netflix.spinnaker.orca.pipeline.model.Stage; +import lombok.AllArgsConstructor; +import org.springframework.stereotype.Component; + +import javax.annotation.Nonnull; +import java.util.ArrayList; +import java.util.List; + +@AllArgsConstructor +@Component +class ShareServiceStage implements StageDefinitionBuilder, CloudProviderAware { + public static final String PIPELINE_CONFIG_TYPE = "shareService"; + + List shareServiceStagePreprocessors = new ArrayList<>(); + + @Nonnull + @Override + public String getType() { + return PIPELINE_CONFIG_TYPE; + } + + @Override + public void taskGraph(@Nonnull Stage stage, @Nonnull TaskNode.Builder builder) { + shareServiceStagePreprocessors + .stream() + .filter(it -> it.supports(stage)) + .forEach(it -> it.addSteps(builder, stage)); + } +} diff --git a/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/servicebroker/ShareServiceStagePreprocessor.java b/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/servicebroker/ShareServiceStagePreprocessor.java new file mode 100644 index 0000000000..dea10c30ba --- /dev/null +++ b/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/servicebroker/ShareServiceStagePreprocessor.java @@ -0,0 +1,32 @@ +/* + * Copyright 2019 Pivotal, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.netflix.spinnaker.orca.clouddriver.pipeline.servicebroker; + +import com.netflix.spinnaker.orca.pipeline.TaskNode; +import com.netflix.spinnaker.orca.pipeline.model.Stage; + +/** + * Supports generic modification of a Share Service stage. + * + * Common use-cases: + * - injecting cloud-aware steps + */ +public interface ShareServiceStagePreprocessor { + boolean supports(Stage stage); + + void addSteps(TaskNode.Builder builder, Stage stage); +} diff --git a/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/servicebroker/UnshareServiceStage.java b/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/servicebroker/UnshareServiceStage.java new file mode 100644 index 0000000000..2ff0dfb2e3 --- /dev/null +++ b/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/servicebroker/UnshareServiceStage.java @@ -0,0 +1,50 @@ +/* + * Copyright 2019 Pivotal, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.netflix.spinnaker.orca.clouddriver.pipeline.servicebroker; + +import com.netflix.spinnaker.orca.clouddriver.utils.CloudProviderAware; +import com.netflix.spinnaker.orca.pipeline.StageDefinitionBuilder; +import com.netflix.spinnaker.orca.pipeline.TaskNode; +import com.netflix.spinnaker.orca.pipeline.model.Stage; +import lombok.AllArgsConstructor; +import org.springframework.stereotype.Component; + +import javax.annotation.Nonnull; +import java.util.ArrayList; +import java.util.List; + +@AllArgsConstructor +@Component +class UnshareServiceStage implements StageDefinitionBuilder, CloudProviderAware { + public static final String PIPELINE_CONFIG_TYPE = "unshareService"; + + List unshareServiceStagePreprocessors = new ArrayList<>(); + + @Nonnull + @Override + public String getType() { + return PIPELINE_CONFIG_TYPE; + } + + @Override + public void taskGraph(@Nonnull Stage stage, @Nonnull TaskNode.Builder builder) { + unshareServiceStagePreprocessors + .stream() + .filter(it -> it.supports(stage)) + .forEach(it -> it.addSteps(builder, stage)); + } +} diff --git a/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/servicebroker/UnshareServiceStagePreprocessor.java b/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/servicebroker/UnshareServiceStagePreprocessor.java new file mode 100644 index 0000000000..867993ae28 --- /dev/null +++ b/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/servicebroker/UnshareServiceStagePreprocessor.java @@ -0,0 +1,32 @@ +/* + * Copyright 2019 Pivotal, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.netflix.spinnaker.orca.clouddriver.pipeline.servicebroker; + +import com.netflix.spinnaker.orca.pipeline.TaskNode; +import com.netflix.spinnaker.orca.pipeline.model.Stage; + +/** + * Supports generic modification of an Unshare Service stage. + * + * Common use-cases: + * - injecting cloud-aware steps + */ +public interface UnshareServiceStagePreprocessor { + boolean supports(Stage stage); + + void addSteps(TaskNode.Builder builder, Stage stage); +} diff --git a/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/AbstractCloudFoundryServiceTask.java b/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/AbstractCloudFoundryServiceTask.java new file mode 100644 index 0000000000..a259ef184d --- /dev/null +++ b/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/AbstractCloudFoundryServiceTask.java @@ -0,0 +1,60 @@ +/* + * Copyright 2019 Pivotal, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.netflix.spinnaker.orca.clouddriver.tasks.providers.cf; + +import com.google.common.collect.ImmutableMap; +import com.netflix.spinnaker.orca.ExecutionStatus; +import com.netflix.spinnaker.orca.TaskResult; +import com.netflix.spinnaker.orca.clouddriver.KatoService; +import com.netflix.spinnaker.orca.clouddriver.model.TaskId; +import com.netflix.spinnaker.orca.clouddriver.tasks.AbstractCloudProviderAwareTask; +import com.netflix.spinnaker.orca.pipeline.model.Stage; +import org.springframework.stereotype.Component; + +import javax.annotation.Nonnull; +import java.util.Collections; +import java.util.Map; +import java.util.Optional; + +@Component +abstract class AbstractCloudFoundryServiceTask extends AbstractCloudProviderAwareTask { + private KatoService kato; + + public AbstractCloudFoundryServiceTask(KatoService kato) { + this.kato = kato; + } + + abstract String getStageName(); + + @Nonnull + @Override + public TaskResult execute(@Nonnull Stage stage) { + String cloudProvider = getCloudProvider(stage); + String account = getCredentials(stage); + Map operation = new ImmutableMap.Builder() + .put(getStageName(), stage.getContext()) + .build(); + TaskId taskId = kato.requestOperations(cloudProvider, Collections.singletonList(operation)).toBlocking().first(); + Map outputs = new ImmutableMap.Builder() + .put("notification.type", getStageName()) + .put("kato.last.task.id", taskId) + .put("service.region", Optional.ofNullable(stage.getContext().get("region")).orElse("")) + .put("service.account", account) + .build(); + return new TaskResult(ExecutionStatus.SUCCEEDED, outputs); + } +} diff --git a/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/CloudFoundryDestroyServiceTask.java b/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/CloudFoundryDestroyServiceTask.java index eb945ce5bf..09f65dcfb0 100644 --- a/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/CloudFoundryDestroyServiceTask.java +++ b/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/CloudFoundryDestroyServiceTask.java @@ -16,42 +16,17 @@ package com.netflix.spinnaker.orca.clouddriver.tasks.providers.cf; -import com.google.common.collect.ImmutableMap; -import com.netflix.spinnaker.orca.ExecutionStatus; -import com.netflix.spinnaker.orca.TaskResult; import com.netflix.spinnaker.orca.clouddriver.KatoService; -import com.netflix.spinnaker.orca.clouddriver.model.TaskId; -import com.netflix.spinnaker.orca.clouddriver.tasks.AbstractCloudProviderAwareTask; -import com.netflix.spinnaker.orca.pipeline.model.Stage; import org.springframework.stereotype.Component; -import javax.annotation.Nonnull; -import java.util.Collections; -import java.util.Map; - @Component -public class CloudFoundryDestroyServiceTask extends AbstractCloudProviderAwareTask { - private KatoService kato; - +public class CloudFoundryDestroyServiceTask extends AbstractCloudFoundryServiceTask { public CloudFoundryDestroyServiceTask(KatoService kato) { - this.kato = kato; + super(kato); } - @Nonnull @Override - public TaskResult execute(@Nonnull Stage stage) { - String cloudProvider = getCloudProvider(stage); - String account = getCredentials(stage); - Map operation = new ImmutableMap.Builder() - .put("destroyService", stage.getContext()) - .build(); - TaskId taskId = kato.requestOperations(cloudProvider, Collections.singletonList(operation)).toBlocking().first(); - Map outputs = new ImmutableMap.Builder() - .put("notification.type", "destroyService") - .put("kato.last.task.id", taskId) - .put("service.region", stage.getContext().get("region")) - .put("service.account", account) - .build(); - return new TaskResult(ExecutionStatus.SUCCEEDED, outputs); + String getStageName() { + return "destroyService"; } } diff --git a/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/CloudFoundryMonitorKatoServicesTask.java b/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/CloudFoundryMonitorKatoServicesTask.java index 1774b8d2d9..00ab1dd900 100644 --- a/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/CloudFoundryMonitorKatoServicesTask.java +++ b/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/CloudFoundryMonitorKatoServicesTask.java @@ -92,7 +92,7 @@ public TaskResult execute(@Nonnull Stage stage) { } case SUCCEEDED: { builder - .put("service.region", stageContext.get("region").toString()) + .put("service.region", Optional.ofNullable(stageContext.get("region")).orElse("")) .put("service.account", getCredentials(stage)) .put("service.operation.type", results.get(0).get("type")) .put("service.instance.name", results.get(0).get("serviceInstanceName")); diff --git a/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/CloudFoundryShareServiceTask.java b/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/CloudFoundryShareServiceTask.java new file mode 100644 index 0000000000..b91cb7de9e --- /dev/null +++ b/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/CloudFoundryShareServiceTask.java @@ -0,0 +1,32 @@ +/* + * Copyright 2019 Pivotal, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.netflix.spinnaker.orca.clouddriver.tasks.providers.cf; + +import com.netflix.spinnaker.orca.clouddriver.KatoService; +import org.springframework.stereotype.Component; + +@Component +public class CloudFoundryShareServiceTask extends AbstractCloudFoundryServiceTask { + public CloudFoundryShareServiceTask(KatoService kato) { + super(kato); + } + + @Override + String getStageName() { + return "shareService"; + } +} diff --git a/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/CloudFoundryUnshareServiceTask.java b/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/CloudFoundryUnshareServiceTask.java new file mode 100644 index 0000000000..54479fa02b --- /dev/null +++ b/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/CloudFoundryUnshareServiceTask.java @@ -0,0 +1,32 @@ +/* + * Copyright 2019 Pivotal, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.netflix.spinnaker.orca.clouddriver.tasks.providers.cf; + +import com.netflix.spinnaker.orca.clouddriver.KatoService; +import org.springframework.stereotype.Component; + +@Component +public class CloudFoundryUnshareServiceTask extends AbstractCloudFoundryServiceTask { + public CloudFoundryUnshareServiceTask(KatoService kato) { + super(kato); + } + + @Override + String getStageName() { + return "unshareService"; + } +} diff --git a/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/CloudFoundryWaitForDeployServiceTask.java b/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/CloudFoundryWaitForDeployServiceTask.java index e5cdb417bb..ed0c5d1906 100644 --- a/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/CloudFoundryWaitForDeployServiceTask.java +++ b/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/CloudFoundryWaitForDeployServiceTask.java @@ -27,22 +27,12 @@ import java.util.Optional; @Component -public class CloudFoundryWaitForDeployServiceTask extends AbstractWaitForServiceTask implements RetryableTask { +public class CloudFoundryWaitForDeployServiceTask extends AbstractWaitForServiceTask { @Autowired public CloudFoundryWaitForDeployServiceTask(OortService oortService) { super(oortService); } - @Override - public long getBackoffPeriod() { - return 10 * 1000L; - } - - @Override - public long getTimeout() { - return 30 * 60 * 1000L; - } - protected ExecutionStatus oortStatusToTaskStatus(Map m) { return Optional.ofNullable(m) .map(myMap -> { diff --git a/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/CloudFoundryWaitForDestroyServiceTask.java b/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/CloudFoundryWaitForDestroyServiceTask.java index e6266272c7..7d329bfbbd 100644 --- a/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/CloudFoundryWaitForDestroyServiceTask.java +++ b/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/CloudFoundryWaitForDestroyServiceTask.java @@ -27,22 +27,12 @@ import java.util.Optional; @Component -public class CloudFoundryWaitForDestroyServiceTask extends AbstractWaitForServiceTask implements RetryableTask { +public class CloudFoundryWaitForDestroyServiceTask extends AbstractWaitForServiceTask { @Autowired public CloudFoundryWaitForDestroyServiceTask(OortService oortService) { super(oortService); } - @Override - public long getBackoffPeriod() { - return 10 * 1000L; - } - - @Override - public long getTimeout() { - return 30 * 60 * 1000L; - } - protected ExecutionStatus oortStatusToTaskStatus(Map m) { return Optional.ofNullable(m).map( myMap -> { diff --git a/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/tasks/servicebroker/AbstractWaitForServiceTask.java b/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/tasks/servicebroker/AbstractWaitForServiceTask.java index b2aefff283..b11737cba2 100644 --- a/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/tasks/servicebroker/AbstractWaitForServiceTask.java +++ b/orca-clouddriver/src/main/groovy/com/netflix/spinnaker/orca/clouddriver/tasks/servicebroker/AbstractWaitForServiceTask.java @@ -17,6 +17,7 @@ package com.netflix.spinnaker.orca.clouddriver.tasks.servicebroker; import com.netflix.spinnaker.orca.ExecutionStatus; +import com.netflix.spinnaker.orca.RetryableTask; import com.netflix.spinnaker.orca.TaskResult; import com.netflix.spinnaker.orca.clouddriver.OortService; import com.netflix.spinnaker.orca.clouddriver.tasks.AbstractCloudProviderAwareTask; @@ -25,13 +26,23 @@ import javax.annotation.Nonnull; import java.util.Map; -public abstract class AbstractWaitForServiceTask extends AbstractCloudProviderAwareTask { +public abstract class AbstractWaitForServiceTask extends AbstractCloudProviderAwareTask implements RetryableTask { protected OortService oortService; public AbstractWaitForServiceTask(OortService oortService) { this.oortService = oortService; } + @Override + public long getBackoffPeriod() { + return 10 * 1000L; + } + + @Override + public long getTimeout() { + return 30 * 60 * 1000L; + } + @Nonnull @Override public TaskResult execute(@Nonnull Stage stage) { @@ -40,8 +51,7 @@ public TaskResult execute(@Nonnull Stage stage) { String region = stage.mapTo("/service.region", String.class); String serviceInstanceName = stage.mapTo("/service.instance.name", String.class); - Map m = oortService.getServiceInstance(account, cloudProvider, region, serviceInstanceName); - return new TaskResult(oortStatusToTaskStatus(m)); + return new TaskResult(oortStatusToTaskStatus(oortService.getServiceInstance(account, cloudProvider, region, serviceInstanceName))); } abstract protected ExecutionStatus oortStatusToTaskStatus(Map m); diff --git a/orca-clouddriver/src/test/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/providers/cf/CloudFoundryDeployServiceStagePreprocessorSpec.groovy b/orca-clouddriver/src/test/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/providers/cf/CloudFoundryDeployServiceStagePreprocessorSpec.groovy deleted file mode 100644 index 0279de2966..0000000000 --- a/orca-clouddriver/src/test/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/providers/cf/CloudFoundryDeployServiceStagePreprocessorSpec.groovy +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2019 Pivotal, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.netflix.spinnaker.orca.clouddriver.pipeline.providers.cf - -import com.netflix.spinnaker.orca.clouddriver.tasks.providers.cf.CloudFoundryDeployServiceTask -import com.netflix.spinnaker.orca.clouddriver.tasks.providers.cf.CloudFoundryMonitorKatoServicesTask -import com.netflix.spinnaker.orca.clouddriver.tasks.providers.cf.CloudFoundryWaitForDeployServiceTask -import com.netflix.spinnaker.orca.pipeline.TaskNode -import com.netflix.spinnaker.orca.pipeline.model.Execution -import com.netflix.spinnaker.orca.pipeline.model.Stage -import spock.lang.Specification -import spock.lang.Subject - -class CloudFoundryDeployServiceStagePreprocessorSpec extends Specification { - @Subject preprocessor = new CloudFoundryDeployServiceStagePreprocessor() - - def "ensure that the correct tasks are added for deploying a Cloud Foundry service"() { - given: - TaskNode.Builder builder = new TaskNode.Builder(TaskNode.GraphType.FULL) - Stage stage = new Stage(Execution.newPipeline("orca"), "deployService", [ - "cloudProvider": "my-cloud", - "manifest": [ - "type": "direct" - ] - ]) - - when: - preprocessor.addSteps(builder, stage) - - then: - builder.graph.size() == 3 - (builder.graph.get(0) as TaskNode.TaskDefinition).name == "deployService" - (builder.graph.get(0) as TaskNode.TaskDefinition).implementingClass == CloudFoundryDeployServiceTask - (builder.graph.get(1) as TaskNode.TaskDefinition).name == "monitorDeployService" - (builder.graph.get(1) as TaskNode.TaskDefinition).implementingClass == CloudFoundryMonitorKatoServicesTask - (builder.graph.get(2) as TaskNode.TaskDefinition).name == "waitForDeployService" - (builder.graph.get(2) as TaskNode.TaskDefinition).implementingClass == CloudFoundryWaitForDeployServiceTask - } -} diff --git a/orca-clouddriver/src/test/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/providers/cf/CloudFoundryDestroyServiceStagePreprocessorSpec.groovy b/orca-clouddriver/src/test/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/providers/cf/CloudFoundryDestroyServiceStagePreprocessorSpec.groovy deleted file mode 100644 index dce86162d5..0000000000 --- a/orca-clouddriver/src/test/groovy/com/netflix/spinnaker/orca/clouddriver/pipeline/providers/cf/CloudFoundryDestroyServiceStagePreprocessorSpec.groovy +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2019 Pivotal, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.netflix.spinnaker.orca.clouddriver.pipeline.providers.cf - -import com.netflix.spinnaker.orca.clouddriver.tasks.providers.cf.CloudFoundryDestroyServiceTask -import com.netflix.spinnaker.orca.clouddriver.tasks.providers.cf.CloudFoundryMonitorKatoServicesTask -import com.netflix.spinnaker.orca.clouddriver.tasks.providers.cf.CloudFoundryWaitForDestroyServiceTask -import com.netflix.spinnaker.orca.pipeline.TaskNode -import com.netflix.spinnaker.orca.pipeline.model.Execution -import com.netflix.spinnaker.orca.pipeline.model.Stage -import spock.lang.Specification -import spock.lang.Subject - -class CloudFoundryDestroyServiceStagePreprocessorSpec extends Specification { - @Subject preprocessor = new CloudFoundryDestroyServiceStagePreprocessor() - - def "ensure that the correct tasks are added for destroying a Cloud Foundry service"() { - given: - TaskNode.Builder builder = new TaskNode.Builder(TaskNode.GraphType.FULL) - Stage stage = new Stage(Execution.newPipeline("orca"), "destroyService", [ - "cloudProvider": "my-cloud" - ]) - - when: - preprocessor.addSteps(builder, stage) - - then: - builder.graph.size() == 3 - (builder.graph.get(0) as TaskNode.TaskDefinition).name == "destroyService" - (builder.graph.get(0) as TaskNode.TaskDefinition).implementingClass == CloudFoundryDestroyServiceTask - (builder.graph.get(1) as TaskNode.TaskDefinition).name == "monitorDestroyService" - (builder.graph.get(1) as TaskNode.TaskDefinition).implementingClass == CloudFoundryMonitorKatoServicesTask - (builder.graph.get(2) as TaskNode.TaskDefinition).name == "waitForDestroyService" - (builder.graph.get(2) as TaskNode.TaskDefinition).implementingClass == CloudFoundryWaitForDestroyServiceTask - } -} diff --git a/orca-clouddriver/src/test/groovy/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/CloudFoundryDestroyServiceTaskTest.groovy b/orca-clouddriver/src/test/groovy/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/CloudFoundryDestroyServiceTaskTest.groovy deleted file mode 100644 index 9ebf2e3811..0000000000 --- a/orca-clouddriver/src/test/groovy/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/CloudFoundryDestroyServiceTaskTest.groovy +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2019 Pivotal, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.netflix.spinnaker.orca.clouddriver.tasks.providers.cf - -import com.netflix.spinnaker.orca.ExecutionStatus -import com.netflix.spinnaker.orca.clouddriver.KatoService -import com.netflix.spinnaker.orca.clouddriver.model.TaskId -import com.netflix.spinnaker.orca.pipeline.model.Execution -import com.netflix.spinnaker.orca.pipeline.model.Stage -import rx.Observable -import spock.lang.Specification -import spock.lang.Subject - -class CloudFoundryDestroyServiceTaskTest extends Specification { - @Subject task = new CloudFoundryDestroyServiceTask(null) - - def "should make a request to clouddriver to destroy a service"() { - given: - task.kato = Stub(KatoService) { - requestOperations(cloudProvider, [["destroyService": context]]) >> - Observable.from(taskId) - } - - and: - def stage = new Stage(Execution.newPipeline("orca"), type, context) - - when: - def result = task.execute(stage) - - then: - result.status == ExecutionStatus.SUCCEEDED - result.context == [ - "notification.type": type, - "kato.last.task.id": taskId, - "service.region": region, - "service.account": credentials, - ] - - where: - type = "destroyService" - taskIdString = "kato-task-id" - credentials = "cf-foundation" - region = "org > space" - taskId = new TaskId(taskIdString) - cloudProvider = "my-cloud" - context = [ - "cloudProvider": cloudProvider, - "credentials": credentials, - "region": region - ] - } -} diff --git a/orca-clouddriver/src/test/groovy/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/CloudFoundryMonitorKatoServicesTaskTest.groovy b/orca-clouddriver/src/test/groovy/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/CloudFoundryMonitorKatoServicesTaskTest.groovy deleted file mode 100644 index f9d47980b9..0000000000 --- a/orca-clouddriver/src/test/groovy/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/CloudFoundryMonitorKatoServicesTaskTest.groovy +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright 2019 Pivotal, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.netflix.spinnaker.orca.clouddriver.tasks.providers.cf - -import com.netflix.spinnaker.orca.ExecutionStatus -import com.netflix.spinnaker.orca.clouddriver.KatoService -import com.netflix.spinnaker.orca.clouddriver.model.Task -import com.netflix.spinnaker.orca.clouddriver.model.TaskId -import com.netflix.spinnaker.orca.pipeline.model.Execution -import com.netflix.spinnaker.orca.pipeline.model.Stage -import rx.Observable -import spock.lang.Specification -import spock.lang.Subject -import spock.lang.Unroll - -class CloudFoundryMonitorKatoServicesTaskTest extends Specification { - @Subject task = new CloudFoundryMonitorKatoServicesTask(null) - - @Unroll("result is #expectedStatus if kato task is #katoStatus and resultObjects is #resultObjects") - def "result depends on Kato task status and result object content"() { - given: - task.kato = Stub(KatoService) { - lookupTask(taskIdString, true) >> - Observable.from(new Task(taskIdString, new Task.Status(completed: completed, failed: failed), resultObjects, [])) - } - - and: - def stage = new Stage(Execution.newPipeline("orca"), "deployService", context) - - when: - def result = task.execute(stage) - - then: - result.status == expectedStatus - result.context == ["kato.last.task.id" : new TaskId(taskIdString), - "kato.task.firstNotFoundRetry": -1, - "kato.task.notFoundRetryCount": 0, - "kato.tasks" : [["id" : taskIdString, - "status" : new Task.Status(completed, failed), - "history" : [], - "resultObjects": resultObjects ?: []]] - ] - - where: - cloudProvider = "cloud" - taskIdString = "kato-task-id" - credentials = "my-account" - region = "org > space" - taskId = new TaskId(taskIdString) - context = [ - "cloudProvider" : cloudProvider, - "kato.last.task.id": taskId, - "credentials" : credentials, - "region" : region - ] - - completed | failed | resultObjects | expectedStatus - false | false | [] | ExecutionStatus.RUNNING - true | false | null | ExecutionStatus.RUNNING - true | false | [] | ExecutionStatus.RUNNING - true | true | [] | ExecutionStatus.TERMINAL - - katoStatus = completed ? "completed" : "incomplete" - } - - def "should return SUCCEEDED when the kato task completes"() { - given: - def inProgressResult = ["type" : "CREATE", - "state" : "IN_PROGRESS", - "serviceInstanceName": "service-instance-name"] - - task.kato = Stub(KatoService) { - lookupTask("kato-task-id", true) >> - Observable.from(new Task("kato-task-id", new Task.Status(completed: true, failed: false), [inProgressResult], [])) - } - - and: - def stage = new Stage(Execution.newPipeline("orca"), "deployService", ["cloudProvider" : "cloud", - "kato.last.task.id": new TaskId("kato-task-id"), - "credentials" : "my-account", - "region" : "org > space" ]) - - when: - def result = task.execute(stage) - - then: - result.status == ExecutionStatus.SUCCEEDED - result.context == ["kato.last.task.id" : new TaskId("kato-task-id"), - "kato.task.firstNotFoundRetry": -1, - "kato.task.notFoundRetryCount": 0, - "kato.tasks" : [["id" : "kato-task-id", - "status" : new Task.Status(true, false), - "history" : [], - "resultObjects": [inProgressResult]]], - "service.account": "my-account", - "service.instance.name": "service-instance-name", - "service.operation.type": "CREATE", - "service.region": "org > space"] - } - - def "should return TERMINAL and an exception should be present when one is received from kato"() { - given: - def expectedException = ["type" : "EXCEPTION", - "operation": "my-atomic-operation", - "cause" : "MyException", - "message" : "Epic Failure"] - task.kato = Stub(KatoService) { - lookupTask("kato-task-id", true) >> - Observable.from(new Task("kato-task-id", new Task.Status(completed: true, failed: true), [expectedException], [])) - } - - and: - def stage = new Stage(Execution.newPipeline("orca"), "deployService", ["cloudProvider" : "cloud", - "kato.last.task.id": new TaskId("kato-task-id"), - "credentials" : "my-account", - "region" : "org > space" ]) - - - when: - def result = task.execute(stage) - - then: - result.status == ExecutionStatus.TERMINAL - result.context == ["kato.last.task.id" : new TaskId("kato-task-id"), - "kato.task.firstNotFoundRetry": -1, - "kato.task.notFoundRetryCount": 0, - "kato.tasks" : [["id" : "kato-task-id", - "status" : new Task.Status(true, true), - "history" : [], - "exception" : expectedException, - "resultObjects": [expectedException]]], - ] - } -} diff --git a/orca-clouddriver/src/test/groovy/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/CloudFoundryWaitForDeployServiceTaskTest.groovy b/orca-clouddriver/src/test/groovy/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/CloudFoundryWaitForDeployServiceTaskTest.groovy deleted file mode 100644 index 9eb006f09f..0000000000 --- a/orca-clouddriver/src/test/groovy/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/CloudFoundryWaitForDeployServiceTaskTest.groovy +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright 2019 Pivotal, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.netflix.spinnaker.orca.clouddriver.tasks.providers.cf - -import com.google.common.collect.ImmutableMap -import com.netflix.spinnaker.orca.ExecutionStatus -import com.netflix.spinnaker.orca.clouddriver.OortService -import com.netflix.spinnaker.orca.pipeline.model.Execution -import com.netflix.spinnaker.orca.pipeline.model.Stage -import spock.lang.Specification -import spock.lang.Subject -import spock.lang.Unroll - -class CloudFoundryWaitForDeployServiceTaskTest extends Specification { - @Subject task = new CloudFoundryWaitForDeployServiceTask(null) - - @Unroll("result is #expectedStatus if oort service is #serviceStatus") - def "result depends on Oort service status"() { - given: - task.oortService = Stub(OortService) { - getServiceInstance(credentials, cloudProvider, region, serviceInstanceName) >> - new ImmutableMap.Builder() - .put("status", serviceStatus) - .build() - } - - and: - def stage = new Stage(Execution.newPipeline("orca"), opType, context) - - when: - def result = task.execute(stage) - - then: - result.status == expectedStatus - - where: - credentials = "my-account" - cloudProvider = "cloud" - opType = "deployService" - region = "org > space" - serviceInstanceName = "service-instance-name" - - context = [ - "cloudProvider": cloudProvider, - "service.account": credentials, - "service.region": region, - "service.instance.name": serviceInstanceName - ] - - serviceStatus | expectedStatus - "FAILED" | ExecutionStatus.TERMINAL - "SUCCEEDED" | ExecutionStatus.SUCCEEDED - "IN_PROGRESS" | ExecutionStatus.RUNNING - } - - def "returns RUNNING for empty Oort service status"() { - given: - task.oortService = Stub(OortService) { - getServiceInstance(credentials, cloudProvider, region, serviceInstanceName) >> - new ImmutableMap.Builder().build() - } - - and: - def stage = new Stage(Execution.newPipeline("orca"), opType, context) - - when: - def result = task.execute(stage) - - then: - result.status == ExecutionStatus.RUNNING - - where: - credentials = "my-account" - cloudProvider = "cloud" - opType = "deployService" - region = "org > space" - serviceInstanceName = "service-instance-name" - - context = [ - "cloudProvider": cloudProvider, - "service.account": credentials, - "service.region": region, - "service.instance.name": serviceInstanceName - ] - } - - def "returns TERMINAL for non-existent Oort service status"() { - given: - task.oortService = Stub(OortService) { - getServiceInstance(credentials, cloudProvider, region, serviceInstanceName) >> null - } - - and: - def stage = new Stage(Execution.newPipeline("orca"), opType, context) - - when: - def result = task.execute(stage) - - then: - result.status == ExecutionStatus.TERMINAL - - where: - credentials = "my-account" - cloudProvider = "cloud" - opType = "deployService" - region = "org > space" - serviceInstanceName = "service-instance-name" - - context = [ - "cloudProvider": cloudProvider, - "service.account": credentials, - "service.region": region, - "service.instance.name": serviceInstanceName - ] - } -} diff --git a/orca-clouddriver/src/test/groovy/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/CloudFoundryWaitForDestroyServiceTaskTest.groovy b/orca-clouddriver/src/test/groovy/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/CloudFoundryWaitForDestroyServiceTaskTest.groovy deleted file mode 100644 index 69aada6289..0000000000 --- a/orca-clouddriver/src/test/groovy/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/CloudFoundryWaitForDestroyServiceTaskTest.groovy +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright 2019 Pivotal, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.netflix.spinnaker.orca.clouddriver.tasks.providers.cf - -import com.google.common.collect.ImmutableMap -import com.netflix.spinnaker.orca.ExecutionStatus -import com.netflix.spinnaker.orca.clouddriver.OortService -import com.netflix.spinnaker.orca.pipeline.model.Execution -import com.netflix.spinnaker.orca.pipeline.model.Stage -import spock.lang.Specification -import spock.lang.Subject -import spock.lang.Unroll - -class CloudFoundryWaitForDestroyServiceTaskTest extends Specification { - @Subject task = new CloudFoundryWaitForDestroyServiceTask(null) - - @Unroll("result is #expectedStatus if oort service is #serviceStatus") - def "result depends on Oort service status"() { - given: - task.oortService = Stub(OortService) { - getServiceInstance(credentials, cloudProvider, region, serviceInstanceName) >> - new ImmutableMap.Builder() - .put("status", serviceStatus) - .build() - } - - and: - def stage = new Stage(Execution.newPipeline("orca"), opType, context) - - when: - def result = task.execute(stage) - - then: - result.status == expectedStatus - - where: - credentials = "my-account" - cloudProvider = "cloud" - opType = "destroyService" - region = "org > space" - serviceInstanceName = "service-instance-name" - - context = [ - "cloudProvider": cloudProvider, - "service.account": credentials, - "service.region": region, - "service.instance.name": serviceInstanceName - ] - - serviceStatus | expectedStatus - "FAILED" | ExecutionStatus.TERMINAL - "IN_PROGRESS" | ExecutionStatus.RUNNING - } - - def "returns RUNNING for empty Oort service status"() { - given: - task.oortService = Stub(OortService) { - getServiceInstance(credentials, cloudProvider, region, serviceInstanceName) >> - new ImmutableMap.Builder().build() - } - - and: - def stage = new Stage(Execution.newPipeline("orca"), opType, context) - - when: - def result = task.execute(stage) - - then: - result.status == ExecutionStatus.RUNNING - - where: - credentials = "my-account" - cloudProvider = "cloud" - opType = "deployService" - region = "org > space" - serviceInstanceName = "service-instance-name" - - context = [ - "cloudProvider": cloudProvider, - "service.account": credentials, - "service.region": region, - "service.instance.name": serviceInstanceName - ] - } - - def "returns SUCCEEDED for non-existent Oort service status"() { - given: - task.oortService = Stub(OortService) { - getServiceInstance(credentials, cloudProvider, region, serviceInstanceName) >> null - } - - and: - def stage = new Stage(Execution.newPipeline("orca"), opType, context) - - when: - def result = task.execute(stage) - - then: - result.status == ExecutionStatus.SUCCEEDED - - where: - credentials = "my-account" - cloudProvider = "cloud" - opType = "destroyService" - region = "org > space" - serviceInstanceName = "service-instance-name" - - context = [ - "cloudProvider": cloudProvider, - "service.account": credentials, - "service.region": region, - "service.instance.name": serviceInstanceName - ] - } -} diff --git a/orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/clouddriver/pipeline/providers/cf/CloudFoundryDeployServiceStagePreprocessorTest.java b/orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/clouddriver/pipeline/providers/cf/CloudFoundryDeployServiceStagePreprocessorTest.java new file mode 100644 index 0000000000..16ddd586ab --- /dev/null +++ b/orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/clouddriver/pipeline/providers/cf/CloudFoundryDeployServiceStagePreprocessorTest.java @@ -0,0 +1,57 @@ +/* + * Copyright 2019 Pivotal, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.netflix.spinnaker.orca.clouddriver.pipeline.providers.cf; + +import com.netflix.spinnaker.orca.clouddriver.tasks.providers.cf.CloudFoundryDeployServiceTask; +import com.netflix.spinnaker.orca.clouddriver.tasks.providers.cf.CloudFoundryMonitorKatoServicesTask; +import com.netflix.spinnaker.orca.clouddriver.tasks.providers.cf.CloudFoundryWaitForDeployServiceTask; +import com.netflix.spinnaker.orca.pipeline.TaskNode; +import com.netflix.spinnaker.orca.pipeline.model.Execution; +import com.netflix.spinnaker.orca.pipeline.model.Stage; +import org.junit.jupiter.api.Test; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import static com.netflix.spinnaker.orca.pipeline.model.Execution.ExecutionType.PIPELINE; +import static org.assertj.core.api.Assertions.assertThat; + +class CloudFoundryDeployServiceStagePreprocessorTest { + @Test + void ensureThatCorrectTasksAreAddedForDeployingCloudFoundryService() { + TaskNode.Builder expectedBuilder = TaskNode.Builder(TaskNode.GraphType.FULL); + expectedBuilder + .withTask("deployService", CloudFoundryDeployServiceTask.class) + .withTask("monitorDeployService", CloudFoundryMonitorKatoServicesTask.class) + .withTask("waitForDeployService", CloudFoundryWaitForDeployServiceTask.class); + + CloudFoundryDeployServiceStagePreprocessor preprocessor = new CloudFoundryDeployServiceStagePreprocessor(); + Map context = new HashMap<>(); + context.put("cloudProvider", "my-cloud"); + context.put("manifest", Collections.singletonMap("type", "direct")); + Stage stage = new Stage( + new Execution(PIPELINE, "orca"), + "deployService", + context); + + TaskNode.Builder builder = new TaskNode.Builder(TaskNode.GraphType.FULL); + preprocessor.addSteps(builder, stage); + + assertThat(builder).isEqualToComparingFieldByFieldRecursively(expectedBuilder); + } +} diff --git a/orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/clouddriver/pipeline/providers/cf/CloudFoundryDestroyServiceStagePreprocessorTest.java b/orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/clouddriver/pipeline/providers/cf/CloudFoundryDestroyServiceStagePreprocessorTest.java new file mode 100644 index 0000000000..453ef16fbb --- /dev/null +++ b/orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/clouddriver/pipeline/providers/cf/CloudFoundryDestroyServiceStagePreprocessorTest.java @@ -0,0 +1,55 @@ +/* + * Copyright 2019 Pivotal, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.netflix.spinnaker.orca.clouddriver.pipeline.providers.cf; + +import com.netflix.spinnaker.orca.clouddriver.tasks.providers.cf.*; +import com.netflix.spinnaker.orca.pipeline.TaskNode; +import com.netflix.spinnaker.orca.pipeline.model.Execution; +import com.netflix.spinnaker.orca.pipeline.model.Stage; +import org.junit.jupiter.api.Test; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import static com.netflix.spinnaker.orca.pipeline.model.Execution.ExecutionType.PIPELINE; +import static org.assertj.core.api.Assertions.assertThat; + +class CloudFoundryDestroyServiceStagePreprocessorTest { + @Test + void ensureThatCorrectTasksAreAddedForDestroyingCloudFoundryService() { + TaskNode.Builder expectedBuilder = TaskNode.Builder(TaskNode.GraphType.FULL); + expectedBuilder + .withTask("destroyService", CloudFoundryDestroyServiceTask.class) + .withTask("monitorDestroyService", CloudFoundryMonitorKatoServicesTask.class) + .withTask("waitForDestroyService", CloudFoundryWaitForDestroyServiceTask.class); + + CloudFoundryDestroyServiceStagePreprocessor preprocessor = new CloudFoundryDestroyServiceStagePreprocessor(); + Map context = new HashMap<>(); + context.put("cloudProvider", "my-cloud"); + context.put("manifest", Collections.singletonMap("type", "direct")); + Stage stage = new Stage( + new Execution(PIPELINE, "orca"), + "destroyService", + context); + + TaskNode.Builder builder = new TaskNode.Builder(TaskNode.GraphType.FULL); + preprocessor.addSteps(builder, stage); + + assertThat(builder).isEqualToComparingFieldByFieldRecursively(expectedBuilder); + } +} diff --git a/orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/clouddriver/pipeline/providers/cf/CloudFoundryShareServiceStagePreprocessorTest.java b/orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/clouddriver/pipeline/providers/cf/CloudFoundryShareServiceStagePreprocessorTest.java new file mode 100644 index 0000000000..e9e8c4421b --- /dev/null +++ b/orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/clouddriver/pipeline/providers/cf/CloudFoundryShareServiceStagePreprocessorTest.java @@ -0,0 +1,55 @@ +/* + * Copyright 2019 Pivotal, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.netflix.spinnaker.orca.clouddriver.pipeline.providers.cf; + +import com.netflix.spinnaker.orca.clouddriver.tasks.providers.cf.CloudFoundryMonitorKatoServicesTask; +import com.netflix.spinnaker.orca.clouddriver.tasks.providers.cf.CloudFoundryShareServiceTask; +import com.netflix.spinnaker.orca.pipeline.TaskNode; +import com.netflix.spinnaker.orca.pipeline.model.Execution; +import com.netflix.spinnaker.orca.pipeline.model.Stage; +import org.junit.jupiter.api.Test; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import static com.netflix.spinnaker.orca.pipeline.model.Execution.ExecutionType.PIPELINE; +import static org.assertj.core.api.Assertions.assertThat; + +class CloudFoundryShareServiceStagePreprocessorTest { + @Test + void ensureThatCorrectTasksAreAddedForSharingCloudFoundryService() { + TaskNode.Builder expectedBuilder = TaskNode.Builder(TaskNode.GraphType.FULL); + expectedBuilder + .withTask("shareService", CloudFoundryShareServiceTask.class) + .withTask("monitorShareService", CloudFoundryMonitorKatoServicesTask.class); + + CloudFoundryShareServiceStagePreprocessor preprocessor = new CloudFoundryShareServiceStagePreprocessor(); + Map context = new HashMap<>(); + context.put("cloudProvider", "my-cloud"); + context.put("manifest", Collections.singletonMap("type", "direct")); + Stage stage = new Stage( + new Execution(PIPELINE, "orca"), + "shareService", + context); + + TaskNode.Builder builder = new TaskNode.Builder(TaskNode.GraphType.FULL); + preprocessor.addSteps(builder, stage); + + assertThat(builder).isEqualToComparingFieldByFieldRecursively(expectedBuilder); + } +} diff --git a/orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/clouddriver/pipeline/providers/cf/CloudFoundryUnshareServiceStagePreprocessorTest.java b/orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/clouddriver/pipeline/providers/cf/CloudFoundryUnshareServiceStagePreprocessorTest.java new file mode 100644 index 0000000000..d64971a135 --- /dev/null +++ b/orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/clouddriver/pipeline/providers/cf/CloudFoundryUnshareServiceStagePreprocessorTest.java @@ -0,0 +1,55 @@ +/* + * Copyright 2019 Pivotal, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.netflix.spinnaker.orca.clouddriver.pipeline.providers.cf; + +import com.netflix.spinnaker.orca.clouddriver.tasks.providers.cf.CloudFoundryMonitorKatoServicesTask; +import com.netflix.spinnaker.orca.clouddriver.tasks.providers.cf.CloudFoundryUnshareServiceTask; +import com.netflix.spinnaker.orca.pipeline.TaskNode; +import com.netflix.spinnaker.orca.pipeline.model.Execution; +import com.netflix.spinnaker.orca.pipeline.model.Stage; +import org.junit.jupiter.api.Test; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import static com.netflix.spinnaker.orca.pipeline.model.Execution.ExecutionType.PIPELINE; +import static org.assertj.core.api.Assertions.assertThat; + +class CloudFoundryUnshareServiceStagePreprocessorTest { + @Test + void ensureThatCorrectTasksAreAddedForUnsharingCloudFoundryService() { + TaskNode.Builder expectedBuilder = TaskNode.Builder(TaskNode.GraphType.FULL); + expectedBuilder + .withTask("unshareService", CloudFoundryUnshareServiceTask.class) + .withTask("monitorUnshareService", CloudFoundryMonitorKatoServicesTask.class); + + CloudFoundryUnshareServiceStagePreprocessor preprocessor = new CloudFoundryUnshareServiceStagePreprocessor(); + Map context = new HashMap<>(); + context.put("cloudProvider", "my-cloud"); + context.put("manifest", Collections.singletonMap("type", "direct")); + Stage stage = new Stage( + new Execution(PIPELINE, "orca"), + "unshareService", + context); + + TaskNode.Builder builder = new TaskNode.Builder(TaskNode.GraphType.FULL); + preprocessor.addSteps(builder, stage); + + assertThat(builder).isEqualToComparingFieldByFieldRecursively(expectedBuilder); + } +} diff --git a/orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/AbstractCloudFoundryWaitForServiceOperationTaskTest.java b/orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/AbstractCloudFoundryWaitForServiceOperationTaskTest.java new file mode 100644 index 0000000000..6243021c15 --- /dev/null +++ b/orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/AbstractCloudFoundryWaitForServiceOperationTaskTest.java @@ -0,0 +1,76 @@ +/* + * Copyright 2019 Pivotal, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.netflix.spinnaker.orca.clouddriver.tasks.providers.cf; + +import com.netflix.spinnaker.orca.ExecutionStatus; +import com.netflix.spinnaker.orca.TaskResult; +import com.netflix.spinnaker.orca.clouddriver.OortService; +import com.netflix.spinnaker.orca.clouddriver.tasks.servicebroker.AbstractWaitForServiceTask; +import com.netflix.spinnaker.orca.pipeline.model.Execution; +import com.netflix.spinnaker.orca.pipeline.model.Stage; + +import javax.annotation.Nullable; +import java.util.HashMap; +import java.util.Map; +import java.util.function.Function; + +import static com.netflix.spinnaker.orca.pipeline.model.Execution.ExecutionType.PIPELINE; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.matches; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +class AbstractCloudFoundryWaitForServiceOperationTaskTest { + private final String operationType; + private final Function subjectConstructor; + + AbstractCloudFoundryWaitForServiceOperationTaskTest( + String operationType, + Function subjectConstructor) { + this.operationType = operationType; + this.subjectConstructor = subjectConstructor; + } + + void testOortServiceStatus(ExecutionStatus expectedStatus, @Nullable Map serviceInstance) { + OortService oortService = mock(OortService.class); + String credentials = "my-account"; + String cloudProvider = "cloud"; + String region = "org > space"; + String serviceInstanceName = "service-instance-name"; + when(oortService.getServiceInstance( + matches(credentials), + matches(cloudProvider), + matches(region), + matches(serviceInstanceName))) + .thenReturn(serviceInstance); + + T task = subjectConstructor.apply(oortService); + + Map context = new HashMap<>(); + context.put("cloudProvider", cloudProvider); + context.put("service.account", credentials); + context.put("service.region", region); + context.put("service.instance.name", serviceInstanceName); + + TaskResult result = task.execute(new Stage( + new Execution(PIPELINE, "orca"), + operationType, + context)); + + assertThat(result.getStatus()).isEqualTo(expectedStatus); + } +} diff --git a/orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/CloudFoundryDeployServiceTaskTest.java b/orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/CloudFoundryDeployServiceTaskTest.java index aec3889d1c..831326cdf6 100644 --- a/orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/CloudFoundryDeployServiceTaskTest.java +++ b/orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/CloudFoundryDeployServiceTaskTest.java @@ -1,3 +1,19 @@ +/* + * Copyright 2019 Pivotal, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.netflix.spinnaker.orca.clouddriver.tasks.providers.cf; import com.fasterxml.jackson.databind.DeserializationFeature; diff --git a/orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/CloudFoundryDestroyServiceTaskTest.java b/orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/CloudFoundryDestroyServiceTaskTest.java new file mode 100644 index 0000000000..6cd21c6efd --- /dev/null +++ b/orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/CloudFoundryDestroyServiceTaskTest.java @@ -0,0 +1,71 @@ +/* + * Copyright 2019 Pivotal, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.netflix.spinnaker.orca.clouddriver.tasks.providers.cf; + +import com.google.common.collect.ImmutableMap; +import com.netflix.spinnaker.orca.ExecutionStatus; +import com.netflix.spinnaker.orca.TaskResult; +import com.netflix.spinnaker.orca.clouddriver.KatoService; +import com.netflix.spinnaker.orca.clouddriver.model.TaskId; +import com.netflix.spinnaker.orca.pipeline.model.Execution; +import com.netflix.spinnaker.orca.pipeline.model.Stage; +import org.junit.jupiter.api.Test; +import rx.Observable; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import static com.netflix.spinnaker.orca.pipeline.model.Execution.ExecutionType.PIPELINE; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.matches; +import static org.mockito.Mockito.*; + +class CloudFoundryDestroyServiceTaskTest { + @Test + void shouldMakeRequestToKatoToDestroyService() { + KatoService kato = mock(KatoService.class); + String cloudProvider = "my-cloud"; + String credentials = "cf-foundation"; + String region = "org > space"; + TaskId taskId = new TaskId("kato-task-id"); + Map context = new HashMap<>(); + context.put("cloudProvider", cloudProvider); + context.put("credentials", credentials); + context.put("region", region); + when(kato.requestOperations(matches(cloudProvider), + eq(Collections.singletonList(Collections.singletonMap("destroyService", context))))) + .thenReturn(Observable.from(new TaskId[] { taskId })); + CloudFoundryDestroyServiceTask task = new CloudFoundryDestroyServiceTask(kato); + + String type = "destroyService"; + Map expectedContext = new ImmutableMap.Builder() + .put("notification.type", type) + .put("kato.last.task.id", taskId) + .put("service.region", region) + .put("service.account", credentials) + .build(); + TaskResult expected = new TaskResult(ExecutionStatus.SUCCEEDED, expectedContext); + + TaskResult result = task.execute(new Stage( + new Execution(PIPELINE, "orca"), + "destroyService", + context)); + + assertThat(result).isEqualToComparingFieldByFieldRecursively(expected); + } +} diff --git a/orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/CloudFoundryMonitorKatoServicesTaskTest.java b/orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/CloudFoundryMonitorKatoServicesTaskTest.java new file mode 100644 index 0000000000..a14f17dbe4 --- /dev/null +++ b/orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/CloudFoundryMonitorKatoServicesTaskTest.java @@ -0,0 +1,127 @@ +/* + * Copyright 2019 Pivotal, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.netflix.spinnaker.orca.clouddriver.tasks.providers.cf; + +import com.google.common.collect.ImmutableMap; +import com.netflix.spinnaker.orca.ExecutionStatus; +import com.netflix.spinnaker.orca.TaskResult; +import com.netflix.spinnaker.orca.clouddriver.KatoService; +import com.netflix.spinnaker.orca.clouddriver.model.Task; +import com.netflix.spinnaker.orca.clouddriver.model.TaskId; +import com.netflix.spinnaker.orca.pipeline.model.Execution; +import com.netflix.spinnaker.orca.pipeline.model.Stage; +import org.junit.jupiter.api.Test; +import rx.Observable; + +import javax.annotation.Nullable; +import java.util.*; + +import static com.netflix.spinnaker.orca.pipeline.model.Execution.ExecutionType.PIPELINE; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.matches; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +class CloudFoundryMonitorKatoServicesTaskTest { + private void testKatoServiceStatus(boolean completed, boolean failed, @Nullable List resultObjects, ExecutionStatus expectedStatus) { + KatoService katoService = mock(KatoService.class); + String taskIdString = "kato-task-id"; + String credentials = "my-account"; + String cloudProvider = "cloud"; + String region = "org > space"; + when(katoService.lookupTask( + matches(taskIdString), + eq(true))) + .thenReturn(Observable.from(new Task[] { new Task(taskIdString, new Task.Status(completed, failed), resultObjects, Collections.emptyList()) })); + + CloudFoundryMonitorKatoServicesTask task = new CloudFoundryMonitorKatoServicesTask(katoService); + + ImmutableMap.Builder katoTaskMapBuilder = new ImmutableMap.Builder() + .put("id", taskIdString) + .put("status", new Task.Status(completed, failed)) + .put("history", Collections.emptyList()) + .put("resultObjects", Optional.ofNullable(resultObjects).orElse(Collections.emptyList())); + Optional.ofNullable(resultObjects) + .ifPresent(results -> results.stream() + .filter(result -> "EXCEPTION".equals(result.get("type"))) + .findFirst() + .ifPresent(r -> katoTaskMapBuilder.put("exception", r))); + + Map expectedContext = new HashMap<>(); + TaskId taskId = new TaskId(taskIdString); + expectedContext.put("kato.last.task.id", taskId); + expectedContext.put("kato.task.firstNotFoundRetry", -1L); + expectedContext.put("kato.task.notFoundRetryCount", 0); + expectedContext.put("kato.tasks", Collections.singletonList(katoTaskMapBuilder.build())); + TaskResult expected = new TaskResult(expectedStatus, expectedContext); + + Map context = new HashMap<>(); + context.put("cloudProvider", cloudProvider); + context.put("kato.last.task.id", taskId); + context.put("credentials", credentials); + context.put("region", region); + + TaskResult result = task.execute(new Stage( + new Execution(PIPELINE, "orca"), + "deployService", + context)); + + assertThat(result).isEqualToComparingFieldByFieldRecursively(expected); + } + + @Test + void returnsStatusRunningWhenIncompleteAndNotFailedWithEmptyResults() { + testKatoServiceStatus(false, false, Collections.emptyList(), ExecutionStatus.RUNNING); + } + + @Test + void returnsStatusRunningWhenCompleteAndNotFailedWithNullResults() { + testKatoServiceStatus(true, false, null, ExecutionStatus.RUNNING); + } + + @Test + void returnsStatusRunningWhenCompleteAndNotFailedWithEmptyResults() { + testKatoServiceStatus(true, false, Collections.emptyList(), ExecutionStatus.RUNNING); + } + + @Test + void returnsStatusTerminalWhenCompleteAndFailedWithEmptyResults() { + testKatoServiceStatus(true, true, Collections.emptyList(), ExecutionStatus.TERMINAL); + } + + @Test + void returnsStatusSucceededWhenCompleteAndNotFailedWithAResult() { + Map inProgressResult = new ImmutableMap.Builder() + .put("type", "CREATE") + .put("state", "IN_PROGRESS") + .put("serviceInstanceName", "service-instance-name") + .build(); + testKatoServiceStatus(true, true, Collections.singletonList(inProgressResult), ExecutionStatus.TERMINAL); + } + + @Test + void returnsStatusTerminalWithExceptionWhenCompleteAndailedWithAnExceptionResult() { + Map inProgressResult = new ImmutableMap.Builder() + .put("type", "EXCEPTION") + .put("operation", "my-atomic-operation") + .put("cause", "MyException") + .put("message", "Epic Failure") + .build(); + testKatoServiceStatus(true, true, Collections.singletonList(inProgressResult), ExecutionStatus.TERMINAL); + } +} diff --git a/orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/CloudFoundryWaitForDeployServiceTaskTest.java b/orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/CloudFoundryWaitForDeployServiceTaskTest.java new file mode 100644 index 0000000000..e986cd04e5 --- /dev/null +++ b/orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/CloudFoundryWaitForDeployServiceTaskTest.java @@ -0,0 +1,54 @@ +/* + * Copyright 2019 Pivotal, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.netflix.spinnaker.orca.clouddriver.tasks.providers.cf; + +import com.netflix.spinnaker.orca.ExecutionStatus; +import org.junit.jupiter.api.Test; + +import java.util.Collections; + +class CloudFoundryWaitForDeployServiceTaskTest + extends AbstractCloudFoundryWaitForServiceOperationTaskTest { + CloudFoundryWaitForDeployServiceTaskTest() { + super("deployService", CloudFoundryWaitForDeployServiceTask::new); + } + + @Test + void isTerminalWhenOortResultIsFailed() { + testOortServiceStatus(ExecutionStatus.TERMINAL, Collections.singletonMap("status", "FAILED")); + } + + @Test + void isSuccessWhenOortResultIsSucceeded() { + testOortServiceStatus(ExecutionStatus.SUCCEEDED, Collections.singletonMap("status", "SUCCEEDED")); + } + + @Test + void isRunningWhenOortResultIsInProgress() { + testOortServiceStatus(ExecutionStatus.RUNNING, Collections.singletonMap("status", "IN_PROGRESS")); + } + + @Test + void isRunningWhenOortResultsAreEmpty() { + testOortServiceStatus(ExecutionStatus.RUNNING, Collections.emptyMap()); + } + + @Test + void isTerminalWhenOortResultsAreNull() { + testOortServiceStatus(ExecutionStatus.TERMINAL, null); + } +} diff --git a/orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/CloudFoundryWaitForDestroyServiceTaskTest.java b/orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/CloudFoundryWaitForDestroyServiceTaskTest.java new file mode 100644 index 0000000000..ca7c7db868 --- /dev/null +++ b/orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/cf/CloudFoundryWaitForDestroyServiceTaskTest.java @@ -0,0 +1,49 @@ +/* + * Copyright 2019 Pivotal, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.netflix.spinnaker.orca.clouddriver.tasks.providers.cf; + +import com.netflix.spinnaker.orca.ExecutionStatus; +import org.junit.jupiter.api.Test; + +import java.util.Collections; + +class CloudFoundryWaitForDestroyServiceTaskTest + extends AbstractCloudFoundryWaitForServiceOperationTaskTest { + CloudFoundryWaitForDestroyServiceTaskTest() { + super("destroyService", CloudFoundryWaitForDestroyServiceTask::new); + } + + @Test + void isTerminalWhenOortResultIsFailed() { + testOortServiceStatus(ExecutionStatus.TERMINAL, Collections.singletonMap("status", "FAILED")); + } + + @Test + void isRunningWhenOortResultIsInProgress() { + testOortServiceStatus(ExecutionStatus.RUNNING, Collections.singletonMap("status", "IN_PROGRESS")); + } + + @Test + void isRunningWhenOortResultsAreEmpty() { + testOortServiceStatus(ExecutionStatus.RUNNING, Collections.emptyMap()); + } + + @Test + void isSuccessWhenOortResultsAreNull() { + testOortServiceStatus(ExecutionStatus.SUCCEEDED, null); + } +}