From 81f330cec5c4e0d11df0826112c7b01861326252 Mon Sep 17 00:00:00 2001 From: mattgogerly Date: Thu, 27 Jul 2023 08:20:20 +0100 Subject: [PATCH] chore(lambda): rewrite to use Kato/Oort --- .../CloudDriverCacheStatusService.java | 7 + .../CloudDriverTaskStatusService.java | 3 + ...legatingCloudDriverCacheStatusService.java | 6 + ...elegatingCloudDriverTaskStatusService.java | 5 + .../clouddriver/DelegatingOortService.java | 6 + .../orca/clouddriver/KatoService.java | 4 + .../orca/clouddriver/OortService.java | 7 + .../model/SubmitOperationResult.java | 1 + .../lambda/BaseLambdaDeploymentStrategy.java | 51 +- .../LambdaBlueGreenDeploymentStrategy.java | 100 ++-- .../LambdaSimpleDeploymentStrategy.java | 34 +- .../LambdaTrafficUpdateStrategyInjector.java | 22 +- .../LambdaWeightedDeploymentStrategy.java | 33 +- .../providers/aws/LambdaUtils.java} | 278 +++-------- .../aws/lambda/LambdaCacheRefreshTask.java | 247 +++++----- .../aws/lambda/LambdaCreateTask.java | 68 +-- .../lambda/LambdaDeleteConcurrencyTask.java | 66 +-- .../aws/lambda/LambdaDeleteTask.java | 59 +-- .../lambda/LambdaDeleteVerificationTask.java | 10 +- .../LambdaFunctionForceRefreshTask.java | 13 +- .../aws/lambda/LambdaFunctionTask.java | 8 +- .../aws/lambda/LambdaInvokeTask.java | 57 +-- .../lambda/LambdaInvokeVerificationTask.java | 30 +- .../aws/lambda/LambdaOutputTask.java | 34 +- .../aws/lambda/LambdaPublishVersionTask.java | 75 +-- .../aws/lambda/LambdaPutConcurrencyTask.java | 65 ++- .../aws/lambda/LambdaStageBaseTask.java | 4 + .../aws/lambda/LambdaTrafficUpdateTask.java | 37 +- .../LambdaTrafficUpdateVerificationTask.java | 28 +- .../aws/lambda/LambdaUpdateAliasesTask.java | 63 ++- .../aws/lambda/LambdaUpdateCodeTask.java | 52 +- .../lambda/LambdaUpdateConfigurationTask.java | 55 ++- .../LambdaUpdateEventConfigurationTask.java | 110 ++--- .../aws/lambda/LambdaVerificationTask.java | 29 +- .../LambdaWaitForCacheCodeUpdateTask.java | 20 +- .../lambda/LambdaWaitForCachePublishTask.java | 19 +- .../aws/lambda/LambdaWaitToStabilizeTask.java | 25 +- .../orca/clouddriver/MortServiceSpec.groovy | 47 +- .../com/netflix/spinnaker/orca/TestUtils.java | 47 +- .../tasks/providers/aws/LambdaUtilsTest.java | 416 ++++++++++++++++ .../lambda/LambdaCacheRefreshTaskTest.java | 129 +++-- .../aws/lambda/LambdaCreateTaskTest.java | 99 ++-- .../LambdaDeleteConcurrencyTaskTest.java | 76 ++- ...mbdaTrafficUpdateVerificationTaskTest.java | 15 +- .../utils/LambdaClouddriverUtilsTest.java | 458 ------------------ .../tasks/providers/aws/lambda/functions.json | 39 ++ .../lambda/kato-published-version-empty.json | 3 + .../aws/lambda/kato-published-version.json | 7 + .../aws/lambda/kato-status-success.json | 16 + 49 files changed, 1459 insertions(+), 1624 deletions(-) rename orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/{utils/LambdaCloudDriverUtils.java => tasks/providers/aws/LambdaUtils.java} (51%) create mode 100644 orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/LambdaUtilsTest.java delete mode 100644 orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/clouddriver/utils/LambdaClouddriverUtilsTest.java create mode 100644 orca-clouddriver/src/test/resources/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/functions.json create mode 100644 orca-clouddriver/src/test/resources/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/kato-published-version-empty.json create mode 100644 orca-clouddriver/src/test/resources/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/kato-published-version.json create mode 100644 orca-clouddriver/src/test/resources/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/kato-status-success.json diff --git a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/CloudDriverCacheStatusService.java b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/CloudDriverCacheStatusService.java index db9ef6a36f..97a0928a4d 100644 --- a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/CloudDriverCacheStatusService.java +++ b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/CloudDriverCacheStatusService.java @@ -20,9 +20,16 @@ import java.util.Map; import retrofit.http.GET; import retrofit.http.Path; +import retrofit.http.Query; public interface CloudDriverCacheStatusService { @GET("/cache/{cloudProvider}/{type}") Collection pendingForceCacheUpdates( @Path("cloudProvider") String cloudProvider, @Path("type") String type); + + @GET("/cache/{cloudProvider}/{type}") + Collection pendingForceCacheUpdatesById( + @Path("cloudProvider") String cloudProvider, + @Path("type") String type, + @Query("id") String id); } diff --git a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/CloudDriverTaskStatusService.java b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/CloudDriverTaskStatusService.java index 344f308cba..794c03e4d2 100644 --- a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/CloudDriverTaskStatusService.java +++ b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/CloudDriverTaskStatusService.java @@ -23,4 +23,7 @@ public interface CloudDriverTaskStatusService { @GET("/task/{id}") Task lookupTask(@Path("id") String id); + + @GET("{uri}") + Task lookupTaskWithUri(@Path(value = "fullUrl", encode = false) String uri); } diff --git a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/DelegatingCloudDriverCacheStatusService.java b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/DelegatingCloudDriverCacheStatusService.java index cf5bbc12a7..b179152fd5 100644 --- a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/DelegatingCloudDriverCacheStatusService.java +++ b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/DelegatingCloudDriverCacheStatusService.java @@ -32,4 +32,10 @@ public DelegatingCloudDriverCacheStatusService(SelectableService selectableServi public Collection pendingForceCacheUpdates(String cloudProvider, String type) { return getService().pendingForceCacheUpdates(cloudProvider, type); } + + @Override + public Collection pendingForceCacheUpdatesById( + String cloudProvider, String type, String id) { + return getService().pendingForceCacheUpdatesById(cloudProvider, type, id); + } } diff --git a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/DelegatingCloudDriverTaskStatusService.java b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/DelegatingCloudDriverTaskStatusService.java index de14b406d2..a2d06db7dc 100644 --- a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/DelegatingCloudDriverTaskStatusService.java +++ b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/DelegatingCloudDriverTaskStatusService.java @@ -31,4 +31,9 @@ public DelegatingCloudDriverTaskStatusService(SelectableService selectableServic public Task lookupTask(String id) { return getService().lookupTask(id); } + + @Override + public Task lookupTaskWithUri(String uri) { + return getService().lookupTaskWithUri(uri); + } } diff --git a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/DelegatingOortService.java b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/DelegatingOortService.java index 11e9ba013b..ec87b231f4 100644 --- a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/DelegatingOortService.java +++ b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/DelegatingOortService.java @@ -21,6 +21,7 @@ import com.netflix.spinnaker.orca.clouddriver.model.Ami; import com.netflix.spinnaker.orca.clouddriver.model.Manifest; import com.netflix.spinnaker.orca.clouddriver.model.ManifestCoordinates; +import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.LambdaDefinition; import java.util.List; import java.util.Map; import org.apache.commons.lang3.StringUtils; @@ -131,6 +132,11 @@ public Response getInstance(String account, String region, String instanceId) { return getService().getInstance(account, region, instanceId); } + @Override + public List getFunction(String account, String region, String functionName) { + return getService().getFunction(account, region, functionName); + } + @Override public Response fetchArtifact(Artifact artifact) { return getService().fetchArtifact(artifact); diff --git a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/KatoService.java b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/KatoService.java index 965d7078ff..5194afeb98 100644 --- a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/KatoService.java +++ b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/KatoService.java @@ -85,6 +85,10 @@ public Task lookupTask(String id, boolean skipReplica) { return cloudDriverTaskStatusService.lookupTask(id); } + public Task lookupTaskWithUri(String uri) { + return cloudDriverTaskStatusService.lookupTask(uri); + } + @Nonnull public TaskId resumeTask(@Nonnull String id) { return katoRestService.resumeTask(id); diff --git a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/OortService.java b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/OortService.java index d29b94a8f6..4371747f35 100644 --- a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/OortService.java +++ b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/OortService.java @@ -20,6 +20,7 @@ import com.netflix.spinnaker.orca.clouddriver.model.Ami; import com.netflix.spinnaker.orca.clouddriver.model.Manifest; import com.netflix.spinnaker.orca.clouddriver.model.ManifestCoordinates; +import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.LambdaDefinition; import java.util.List; import java.util.Map; import retrofit.client.Response; @@ -132,6 +133,12 @@ Response getInstance( @Path("region") String region, @Path("instanceId") String instanceId); + @GET("/functions") + List getFunction( + @Path("account") String account, + @Path("region") String region, + @Path("functionName") String functionName); + @PUT("/artifacts/fetch/") Response fetchArtifact(@Body Artifact artifact); diff --git a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/model/SubmitOperationResult.java b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/model/SubmitOperationResult.java index da391e7412..4137bda196 100644 --- a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/model/SubmitOperationResult.java +++ b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/model/SubmitOperationResult.java @@ -20,5 +20,6 @@ @Data public class SubmitOperationResult { private String id; + private String resourceUri; private int status; } diff --git a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/pipeline/servergroup/strategies/lambda/BaseLambdaDeploymentStrategy.java b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/pipeline/servergroup/strategies/lambda/BaseLambdaDeploymentStrategy.java index d72a93a420..2b863f931b 100644 --- a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/pipeline/servergroup/strategies/lambda/BaseLambdaDeploymentStrategy.java +++ b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/pipeline/servergroup/strategies/lambda/BaseLambdaDeploymentStrategy.java @@ -16,40 +16,49 @@ package com.netflix.spinnaker.orca.clouddriver.pipeline.servergroup.strategies.lambda; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; import com.netflix.spinnaker.orca.api.pipeline.models.StageExecution; +import com.netflix.spinnaker.orca.clouddriver.KatoService; +import com.netflix.spinnaker.orca.clouddriver.model.OperationContext; +import com.netflix.spinnaker.orca.clouddriver.model.SubmitOperationResult; +import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.LambdaUtils; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.*; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.input.LambdaBaseStrategyInput; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.output.LambdaCloudOperationOutput; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.output.LambdaDeploymentStrategyOutput; -import com.netflix.spinnaker.orca.clouddriver.utils.LambdaCloudDriverUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; public class BaseLambdaDeploymentStrategy { - private static final Logger logger = LoggerFactory.getLogger(BaseLambdaDeploymentStrategy.class); - static String CLOUDDRIVER_UPSERT_ALIAS_PATH = "/aws/ops/upsertLambdaFunctionAlias"; + private static final String CLOUD_PROVIDER = "aws"; - @Autowired protected LambdaCloudDriverUtils utils; + protected final LambdaUtils lambdaUtils; + protected final KatoService katoService; + protected final ObjectMapper objectMapper; + + public BaseLambdaDeploymentStrategy( + LambdaUtils lambdaUtils, KatoService katoService, ObjectMapper objectMapper) { + this.lambdaUtils = lambdaUtils; + this.katoService = katoService; + this.objectMapper = objectMapper; + } public LambdaDeploymentStrategyOutput deploy(T inp) { throw new RuntimeException("Not Implemented"); } - public LambdaCloudOperationOutput postToCloudDriver( - LambdaBaseStrategyInput inp, String cloudDriverUrl, LambdaCloudDriverUtils utils) { - String endPoint = cloudDriverUrl + CLOUDDRIVER_UPSERT_ALIAS_PATH; - String rawString = utils.asString(inp); - LambdaCloudDriverResponse respObj = utils.postToCloudDriver(endPoint, rawString); - String url = cloudDriverUrl + respObj.getResourceUri(); - logger.debug("Posted to cloudDriver for deployment: " + url); - LambdaCloudOperationOutput out = - LambdaCloudOperationOutput.builder().resourceId(respObj.getId()).url(url).build(); - return out; + public LambdaCloudOperationOutput updateAlias(LambdaBaseStrategyInput inp) { + OperationContext context = objectMapper.convertValue(inp, new TypeReference<>() {}); + context.setOperationType("upsertLambdaFunctionAlias"); + SubmitOperationResult result = katoService.submitOperation(CLOUD_PROVIDER, context); + + return LambdaCloudOperationOutput.builder() + .resourceId(result.getId()) + .url(result.getResourceUri()) + .build(); } - public LambdaCloudDriverUtils getUtils() { - return null; + public LambdaUtils getUtils() { + return lambdaUtils; } public T setupInput(StageExecution stage) { @@ -65,7 +74,7 @@ public String getVersion(StageExecution stage, String version, String versionNum return versionNumberProvided; } - LambdaDefinition lf = utils.retrieveLambdaFromCache(stage, true); - return getUtils().getCanonicalVersion(lf, version, versionNumberProvided, 0); + LambdaDefinition lf = lambdaUtils.retrieveLambdaFromCache(stage); + return lambdaUtils.getCanonicalVersion(lf, version, versionNumberProvided, 0); } } diff --git a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/pipeline/servergroup/strategies/lambda/LambdaBlueGreenDeploymentStrategy.java b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/pipeline/servergroup/strategies/lambda/LambdaBlueGreenDeploymentStrategy.java index 617ba98ac4..46343ff8e8 100644 --- a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/pipeline/servergroup/strategies/lambda/LambdaBlueGreenDeploymentStrategy.java +++ b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/pipeline/servergroup/strategies/lambda/LambdaBlueGreenDeploymentStrategy.java @@ -16,37 +16,35 @@ package com.netflix.spinnaker.orca.clouddriver.pipeline.servergroup.strategies.lambda; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; import com.netflix.spinnaker.orca.api.pipeline.models.StageExecution; -import com.netflix.spinnaker.orca.clouddriver.config.CloudDriverConfigurationProperties; +import com.netflix.spinnaker.orca.clouddriver.KatoService; +import com.netflix.spinnaker.orca.clouddriver.model.OperationContext; +import com.netflix.spinnaker.orca.clouddriver.model.SubmitOperationResult; +import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.LambdaUtils; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.*; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.input.LambdaBlueGreenStrategyInput; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.input.LambdaTrafficUpdateInput; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.output.LambdaCloudOperationOutput; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.output.LambdaDeploymentStrategyOutput; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.output.LambdaInvokeFunctionOutput; -import com.netflix.spinnaker.orca.clouddriver.utils.LambdaCloudDriverUtils; import java.util.HashMap; import java.util.Map; -import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.tuple.Pair; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -@RequiredArgsConstructor @Component +@Slf4j public class LambdaBlueGreenDeploymentStrategy extends BaseLambdaDeploymentStrategy { - private static final Logger logger = - LoggerFactory.getLogger(LambdaBlueGreenDeploymentStrategy.class); - @Autowired private LambdaCloudDriverUtils utils; - - @Autowired CloudDriverConfigurationProperties props; - - static String CLOUDDRIVER_INVOKE_LAMBDA_FUNCTION_PATH = "/aws/ops/invokeLambdaFunction"; + public LambdaBlueGreenDeploymentStrategy( + LambdaUtils utils, KatoService katoService, ObjectMapper objectMapper) { + super(utils, katoService, objectMapper); + } @Override public LambdaDeploymentStrategyOutput deploy(LambdaBlueGreenStrategyInput inp) { @@ -58,11 +56,12 @@ public LambdaDeploymentStrategyOutput deploy(LambdaBlueGreenStrategyInput inp) { LambdaCloudOperationOutput cloudOperationOutput = LambdaCloudOperationOutput.builder().build(); LambdaDeploymentStrategyOutput deploymentStrategyOutput = - LambdaDeploymentStrategyOutput.builder().build(); - deploymentStrategyOutput.setSucceeded(false); - deploymentStrategyOutput.setErrorMessage(results.getRight()); - deploymentStrategyOutput.setOutput(cloudOperationOutput); - logger.error("BlueGreen Deployment failed: " + results.getRight()); + LambdaDeploymentStrategyOutput.builder() + .succeeded(false) + .errorMessage(results.getRight()) + .output(cloudOperationOutput) + .build(); + log.error("BlueGreen Deployment failed: " + results.getRight()); return deploymentStrategyOutput; } } @@ -70,23 +69,23 @@ public LambdaDeploymentStrategyOutput deploy(LambdaBlueGreenStrategyInput inp) { private Pair verifyResults( LambdaBlueGreenStrategyInput inp, LambdaInvokeFunctionOutput output) { int timeout = inp.getTimeout() * 1000; - String url = output.getUrl(); int sleepTime = 10000; + String taskUri = output.getUrl(); + LambdaCloudDriverTaskResults taskResult = null; boolean done = false; while (timeout > 0) { - taskResult = utils.verifyStatus(url); + taskResult = lambdaUtils.verifyStatus(taskUri); if (taskResult.getStatus().isCompleted()) { done = true; break; } try { - utils.await(); + lambdaUtils.await(); timeout -= sleepTime; } catch (Throwable e) { - logger.error("Error waiting for blue green test to complete"); - continue; + log.error("Error waiting for blue green test to complete"); } } @@ -96,9 +95,12 @@ private Pair verifyResults( return Pair.of(Boolean.FALSE, "Lambda Invocation returned failure"); } - LambdaCloudDriverInvokeOperationResults invokeResponse = utils.getLambdaInvokeResults(url); + LambdaCloudDriverInvokeOperationResults invokeResponse = + lambdaUtils.getLambdaInvokeResults(taskUri); String expected = - utils.getPipelinesArtifactContent(inp.getOutputArtifact()).replaceAll("[\\n\\t ]", ""); + lambdaUtils + .getPipelinesArtifactContent(inp.getOutputArtifact()) + .replaceAll("[\\n\\t ]", ""); String actual = null; if (invokeResponse != null) { if (invokeResponse.getBody() != null) { @@ -113,10 +115,10 @@ private Pair verifyResults( String.format( "BlueGreenDeployment failed: Comparison failed. expected : [%s], actual : [%s]", expected, actual); - logger.error("Response string: " + invokeResponse.getResponseString()); + log.error("Response string: {}", invokeResponse.getResponseString()); String errMsg = String.format("%s \n %s", err, invokeResponse.getErrorMessage()); - logger.error("Log results: " + invokeResponse.getInvokeResult().getLogResult()); - logger.error(err); + log.error("Log results: {}", invokeResponse.getInvokeResult().getLogResult()); + log.error(err); return Pair.of(Boolean.FALSE, errMsg); } return Pair.of(Boolean.TRUE, ""); @@ -126,24 +128,22 @@ private LambdaDeploymentStrategyOutput updateLambdaToLatest(LambdaBlueGreenStrat inp.setWeightToMinorFunctionVersion(0.0); inp.setMajorFunctionVersion(inp.getLatestVersionQualifier()); inp.setMinorFunctionVersion(null); - String cloudDriverUrl = props.getCloudDriverBaseUrl(); - Map outputMap = new HashMap(); + + Map outputMap = new HashMap<>(); outputMap.put("deployment:majorVersionDeployed", inp.getMajorFunctionVersion()); outputMap.put("deployment:aliasDeployed", inp.getAliasName()); outputMap.put("deployment:strategyUsed", "BlueGreenDeploymentStrategy"); - LambdaCloudOperationOutput out = postToCloudDriver(inp, cloudDriverUrl, utils); + + LambdaCloudOperationOutput out = updateAlias(inp); out.setOutputMap(outputMap); - LambdaDeploymentStrategyOutput deployOutput = LambdaDeploymentStrategyOutput.builder().build(); - deployOutput.setSucceeded(true); - deployOutput.setOutput(out); - return deployOutput; + + return LambdaDeploymentStrategyOutput.builder().succeeded(true).output(out).build(); } @Override public LambdaBlueGreenStrategyInput setupInput(StageExecution stage) { - LambdaTrafficUpdateInput aliasInp = utils.getInput(stage, LambdaTrafficUpdateInput.class); - LambdaBlueGreenStrategyInput blueGreenInput = - utils.getInput(stage, LambdaBlueGreenStrategyInput.class); + LambdaTrafficUpdateInput aliasInp = stage.mapTo(LambdaTrafficUpdateInput.class); + LambdaBlueGreenStrategyInput blueGreenInput = stage.mapTo(LambdaBlueGreenStrategyInput.class); aliasInp.setAppName(stage.getExecution().getApplication()); blueGreenInput.setCredentials(aliasInp.getAccount()); @@ -152,10 +152,9 @@ public LambdaBlueGreenStrategyInput setupInput(StageExecution stage) { blueGreenInput.setPayloadArtifact(aliasInp.getPayloadArtifact().getArtifact()); blueGreenInput.setOutputArtifact(aliasInp.getOutputArtifact().getArtifact()); - LambdaDefinition lf = null; - lf = utils.retrieveLambdaFromCache(stage, true); + LambdaDefinition lf = lambdaUtils.retrieveLambdaFromCache(stage); - String qual = utils.getCanonicalVersion(lf, "$LATEST", "", 1); + String qual = lambdaUtils.getCanonicalVersion(lf, "$LATEST", "", 1); blueGreenInput.setQualifier(qual); String latestVersion = this.getVersion(stage, "$LATEST", ""); blueGreenInput.setLatestVersionQualifier(latestVersion); @@ -164,19 +163,10 @@ public LambdaBlueGreenStrategyInput setupInput(StageExecution stage) { } private LambdaInvokeFunctionOutput invokeLambdaFunction(LambdaBlueGreenStrategyInput ldi) { - // ldi.setPayload(utils.getPipelinesArtifactContent(ldi.getPayloadArtifact())); - String cloudDriverUrl = props.getCloudDriverBaseUrl(); - String endPoint = cloudDriverUrl + CLOUDDRIVER_INVOKE_LAMBDA_FUNCTION_PATH; - String rawString = utils.asString(ldi); - LambdaCloudDriverResponse respObj = utils.postToCloudDriver(endPoint, rawString); - String url = cloudDriverUrl + respObj.getResourceUri(); - logger.debug("Posted to cloudDriver for blueGreenDeployment: " + url); - LambdaInvokeFunctionOutput ldso = LambdaInvokeFunctionOutput.builder().url(url).build(); - return ldso; - } + OperationContext context = objectMapper.convertValue(ldi, new TypeReference<>() {}); + context.setOperationType("invokeLambdaFunction"); + SubmitOperationResult result = katoService.submitOperation("aws", context); - @Override - public LambdaCloudDriverUtils getUtils() { - return utils; + return LambdaInvokeFunctionOutput.builder().url(result.getResourceUri()).build(); } } diff --git a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/pipeline/servergroup/strategies/lambda/LambdaSimpleDeploymentStrategy.java b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/pipeline/servergroup/strategies/lambda/LambdaSimpleDeploymentStrategy.java index 95cd290c57..521ac69b02 100644 --- a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/pipeline/servergroup/strategies/lambda/LambdaSimpleDeploymentStrategy.java +++ b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/pipeline/servergroup/strategies/lambda/LambdaSimpleDeploymentStrategy.java @@ -16,54 +16,46 @@ package com.netflix.spinnaker.orca.clouddriver.pipeline.servergroup.strategies.lambda; +import com.fasterxml.jackson.databind.ObjectMapper; import com.netflix.spinnaker.orca.api.pipeline.models.StageExecution; -import com.netflix.spinnaker.orca.clouddriver.config.CloudDriverConfigurationProperties; +import com.netflix.spinnaker.orca.clouddriver.KatoService; +import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.LambdaUtils; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.input.LambdaSimpleStrategyInput; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.output.LambdaCloudOperationOutput; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.output.LambdaDeploymentStrategyOutput; -import com.netflix.spinnaker.orca.clouddriver.utils.LambdaCloudDriverUtils; import java.util.HashMap; import java.util.Map; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component public class LambdaSimpleDeploymentStrategy extends BaseLambdaDeploymentStrategy { - @Autowired private LambdaCloudDriverUtils utils; - - @Autowired CloudDriverConfigurationProperties props; + public LambdaSimpleDeploymentStrategy( + LambdaUtils lambdaUtils, KatoService katoService, ObjectMapper objectMapper) { + super(lambdaUtils, katoService, objectMapper); + } @Override public LambdaDeploymentStrategyOutput deploy(LambdaSimpleStrategyInput inp) { - String cloudDriverUrl = props.getCloudDriverBaseUrl(); - Map outputMap = new HashMap(); + Map outputMap = new HashMap<>(); outputMap.put("deployment:majorVersionDeployed", inp.getMajorFunctionVersion()); outputMap.put("deployment:strategyUsed", "SimpleDeploymentStrategy"); outputMap.put("deployment:aliasDeployed", inp.getAliasName()); - LambdaCloudOperationOutput out = postToCloudDriver(inp, cloudDriverUrl, utils); + + LambdaCloudOperationOutput out = updateAlias(inp); out.setOutputMap(outputMap); - LambdaDeploymentStrategyOutput deployOutput = LambdaDeploymentStrategyOutput.builder().build(); - deployOutput.setSucceeded(true); - deployOutput.setOutput(out); - return deployOutput; + + return LambdaDeploymentStrategyOutput.builder().succeeded(true).output(out).build(); } @Override public LambdaSimpleStrategyInput setupInput(StageExecution stage) { - LambdaSimpleStrategyInput aliasInp = utils.getInput(stage, LambdaSimpleStrategyInput.class); - + LambdaSimpleStrategyInput aliasInp = stage.mapTo(LambdaSimpleStrategyInput.class); aliasInp.setCredentials(aliasInp.getAccount()); aliasInp.setAppName(stage.getExecution().getApplication()); - aliasInp.setMajorFunctionVersion( getVersion(stage, aliasInp.getVersionNameA(), aliasInp.getVersionNumberA())); return aliasInp; } - - @Override - public LambdaCloudDriverUtils getUtils() { - return utils; - } } diff --git a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/pipeline/servergroup/strategies/lambda/LambdaTrafficUpdateStrategyInjector.java b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/pipeline/servergroup/strategies/lambda/LambdaTrafficUpdateStrategyInjector.java index d4797ba5f1..d0030ecdb6 100644 --- a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/pipeline/servergroup/strategies/lambda/LambdaTrafficUpdateStrategyInjector.java +++ b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/pipeline/servergroup/strategies/lambda/LambdaTrafficUpdateStrategyInjector.java @@ -19,25 +19,27 @@ import java.util.HashMap; import java.util.Map; import javax.annotation.PostConstruct; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @Component +@Slf4j public class LambdaTrafficUpdateStrategyInjector { - private static final Logger logger = - LoggerFactory.getLogger(LambdaTrafficUpdateStrategyInjector.class); - @Autowired private LambdaSimpleDeploymentStrategy simpleStrat; - @Autowired private LambdaWeightedDeploymentStrategy weightedStrat; - @Autowired private LambdaBlueGreenDeploymentStrategy blueGreenStrat; + private final LambdaSimpleDeploymentStrategy simpleStrat; + private final LambdaWeightedDeploymentStrategy weightedStrat; + private final LambdaBlueGreenDeploymentStrategy blueGreenStrat; private final Map factoryMap = new HashMap<>(); - public LambdaTrafficUpdateStrategyInjector() { - logger.debug("Start strategy injector"); + public LambdaTrafficUpdateStrategyInjector( + LambdaSimpleDeploymentStrategy simpleStrat, + LambdaWeightedDeploymentStrategy weightedStrat, + LambdaBlueGreenDeploymentStrategy blueGreenStrat) { + this.simpleStrat = simpleStrat; + this.weightedStrat = weightedStrat; + this.blueGreenStrat = blueGreenStrat; } public BaseLambdaDeploymentStrategy getStrategy(LambdaDeploymentStrategyEnum inp) { diff --git a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/pipeline/servergroup/strategies/lambda/LambdaWeightedDeploymentStrategy.java b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/pipeline/servergroup/strategies/lambda/LambdaWeightedDeploymentStrategy.java index deb33f4e4c..f3d2ed4165 100644 --- a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/pipeline/servergroup/strategies/lambda/LambdaWeightedDeploymentStrategy.java +++ b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/pipeline/servergroup/strategies/lambda/LambdaWeightedDeploymentStrategy.java @@ -16,48 +16,46 @@ package com.netflix.spinnaker.orca.clouddriver.pipeline.servergroup.strategies.lambda; +import com.fasterxml.jackson.databind.ObjectMapper; import com.netflix.spinnaker.orca.api.pipeline.models.StageExecution; -import com.netflix.spinnaker.orca.clouddriver.config.CloudDriverConfigurationProperties; +import com.netflix.spinnaker.orca.clouddriver.KatoService; +import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.LambdaUtils; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.input.LambdaTrafficUpdateInput; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.input.LambdaWeightedStrategyInput; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.output.LambdaCloudOperationOutput; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.output.LambdaDeploymentStrategyOutput; -import com.netflix.spinnaker.orca.clouddriver.utils.LambdaCloudDriverUtils; import java.util.HashMap; import java.util.Map; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component public class LambdaWeightedDeploymentStrategy extends BaseLambdaDeploymentStrategy { - @Autowired private LambdaCloudDriverUtils utils; - - @Autowired CloudDriverConfigurationProperties props; + public LambdaWeightedDeploymentStrategy( + LambdaUtils lambdaUtils, KatoService katoService, ObjectMapper objectMapper) { + super(lambdaUtils, katoService, objectMapper); + } @Override public LambdaDeploymentStrategyOutput deploy(LambdaWeightedStrategyInput inp) { - String cloudDriverUrl = props.getCloudDriverBaseUrl(); Map outputMap = new HashMap<>(); outputMap.put("deployment:majorVersionDeployed", inp.getMajorFunctionVersion()); outputMap.put("deployment:minorVersionDeployed", inp.getMinorFunctionVersion()); outputMap.put("deployment:aliasDeployed", inp.getAliasName()); outputMap.put("deployment:strategyUsed", "WeightedDeploymentStrategy"); + // TODO: Form a new inputObject such as SimpleStrategyInput and just have the - LambdaCloudOperationOutput out = postToCloudDriver(inp, cloudDriverUrl, utils); + LambdaCloudOperationOutput out = updateAlias(inp); out.setOutputMap(outputMap); - LambdaDeploymentStrategyOutput deployOutput = LambdaDeploymentStrategyOutput.builder().build(); - deployOutput.setSucceeded(true); - deployOutput.setOutput(out); - return deployOutput; + + return LambdaDeploymentStrategyOutput.builder().succeeded(true).output(out).build(); } @Override public LambdaWeightedStrategyInput setupInput(StageExecution stage) { - LambdaTrafficUpdateInput aliasInp = utils.getInput(stage, LambdaTrafficUpdateInput.class); - LambdaWeightedStrategyInput weightedInput = - utils.getInput(stage, LambdaWeightedStrategyInput.class); + LambdaTrafficUpdateInput aliasInp = stage.mapTo(LambdaTrafficUpdateInput.class); + LambdaWeightedStrategyInput weightedInput = stage.mapTo(LambdaWeightedStrategyInput.class); weightedInput.setAppName(stage.getExecution().getApplication()); weightedInput.setAccount(aliasInp.getAccount()); weightedInput.setCredentials(aliasInp.getAccount()); @@ -70,9 +68,4 @@ public LambdaWeightedStrategyInput setupInput(StageExecution stage) { getVersion(stage, aliasInp.getVersionNameB(), aliasInp.getVersionNumberB())); return weightedInput; } - - @Override - public LambdaCloudDriverUtils getUtils() { - return utils; - } } diff --git a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/utils/LambdaCloudDriverUtils.java b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/LambdaUtils.java similarity index 51% rename from orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/utils/LambdaCloudDriverUtils.java rename to orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/LambdaUtils.java index 9fef41529f..9220b86c46 100644 --- a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/utils/LambdaCloudDriverUtils.java +++ b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/LambdaUtils.java @@ -1,7 +1,7 @@ /* * Copyright 2018 Amazon.com, Inc. or its affiliates. * - * Licensed under the Apache License, Version 2.0 (the "License") + * 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 * @@ -14,27 +14,22 @@ * limitations under the License. */ -package com.netflix.spinnaker.orca.clouddriver.utils; +package com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws; -import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ArrayNode; -import com.fasterxml.jackson.databind.type.TypeFactory; import com.google.common.io.CharStreams; import com.netflix.spinnaker.kork.artifacts.model.Artifact; import com.netflix.spinnaker.kork.core.RetrySupport; -import com.netflix.spinnaker.kork.exceptions.SpinnakerException; import com.netflix.spinnaker.orca.api.pipeline.models.StageExecution; +import com.netflix.spinnaker.orca.clouddriver.KatoService; import com.netflix.spinnaker.orca.clouddriver.OortService; -import com.netflix.spinnaker.orca.clouddriver.config.CloudDriverConfigurationProperties; -import com.netflix.spinnaker.orca.clouddriver.config.LambdaConfigurationProperties; +import com.netflix.spinnaker.orca.clouddriver.model.Task; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.*; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.input.LambdaDeploymentInput; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.input.LambdaGetInput; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.output.LambdaVerificationStatusOutput; -import com.netflix.spinnaker.security.AuthenticatedRequest; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; @@ -42,80 +37,42 @@ import java.util.ArrayList; import java.util.Comparator; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; -import okhttp3.*; +import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.math.NumberUtils; import org.pf4j.util.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import retrofit.client.Response; @Component -public class LambdaCloudDriverUtils { - private static final Logger logger = LoggerFactory.getLogger(LambdaCloudDriverUtils.class); - private static final ObjectMapper objectMapper = new ObjectMapper(); - private static final String CLOUDDRIVER_GET_PATH = "/functions"; +@Slf4j +public class LambdaUtils { - static { - objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); - objectMapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true); - } - - @Autowired LambdaConfigurationProperties config; - - @Autowired CloudDriverConfigurationProperties props; - - @Autowired OortService oort; - - public LambdaCloudDriverResponse postToCloudDriver(String endPointUrl, String jsonString) { - return postToCloudDriver(endPointUrl, jsonString, config.getCloudDriverPostRequestRetries()); - } - - public LambdaCloudDriverResponse postToCloudDriver( - String endPointUrl, String jsonString, int retries) { - final RequestBody body = RequestBody.create(MediaType.parse("application/json"), jsonString); - final Request request = - new Request.Builder().url(endPointUrl).headers(buildHeaders()).post(body).build(); - return new RetrySupport() - .retry( - () -> { - try { - OkHttpClient client = new OkHttpClient(); - Call call = client.newCall(request); - Response response = call.execute(); - String respString = response.body().string(); + private final KatoService katoService; + private final OortService oortService; + private final ObjectMapper objectMapper; + private final RetrySupport retrySupport = new RetrySupport(); - if (200 == response.code() || 202 == response.code()) { - logger.debug(respString); - return objectMapper.readValue(respString, LambdaCloudDriverResponse.class); - } + public LambdaUtils(KatoService katoService, OortService oortService) { + this.katoService = katoService; + this.oortService = oortService; - logger.error("Error calling cloud driver"); - logger.error(respString); - - throw new SpinnakerException("Error calling cloud driver: " + respString) - .setRetryable(409 == response.code()); - } catch (Exception e) { - throw new SpinnakerException(e).setRetryable(false); - } - }, - retries, - Duration.ofSeconds(30), - false); + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + objectMapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true); + this.objectMapper = objectMapper; } - public LambdaCloudDriverInvokeOperationResults getLambdaInvokeResults(String endPoint) { - String respString = getFromCloudDriver(endPoint); + public LambdaCloudDriverInvokeOperationResults getLambdaInvokeResults(String uri) { + Task task = katoService.lookupTaskWithUri(uri); LambdaCloudDriverInvokeOperationResults respObject = null; try { - JsonNode jsonResults = objectMapper.readTree(respString); - ArrayNode resultsNode = (ArrayNode) jsonResults.get("resultObjects"); - if ((resultsNode != null) && resultsNode.isArray() && resultsNode.size() > 0) { + if (task != null && task.getResultObjects() != null && task.getResultObjects().size() > 0) { respObject = objectMapper.convertValue( - resultsNode.get(0), LambdaCloudDriverInvokeOperationResults.class); + task.getResultObjects().get(0), LambdaCloudDriverInvokeOperationResults.class); JsonNode respStringNode = objectMapper.readTree(respObject.getResponseString()); if (respStringNode.has("statusCode")) { int statusCode = respStringNode.get("statusCode").intValue(); @@ -138,157 +95,72 @@ public LambdaCloudDriverInvokeOperationResults getLambdaInvokeResults(String end } return respObject; } catch (Exception e) { - logger.error("Failed getLambdaInvokeResults task at {}", endPoint, e); + log.error("Failed getLambdaInvokeResults task at {}", uri, e); return respObject; } } - public String getPublishedVersion(String endPoint) { - String respString = getFromCloudDriver(endPoint); + public String getPublishedVersion(String uri) { try { - JsonNode jsonResults = objectMapper.readTree(respString); - ArrayNode resultsNode = (ArrayNode) jsonResults.get("resultObjects"); - if (resultsNode.isArray() && resultsNode.size() > 0) { - JsonNode result = resultsNode.get(0); - if (result.has("version")) { - return result.get("version").textValue(); + Task task = katoService.lookupTaskWithUri(uri); + List resultObjects = task.getResultObjects(); + if (resultObjects != null && resultObjects.size() > 0) { + Map result = resultObjects.get(0); + if (result.containsKey("version")) { + return result.get("version").toString(); } } } catch (Exception e) { - logger.error("Failed getPublishedVersion task at {}", endPoint, e); + log.error("Failed getPublishedVersion task at {}", uri, e); } return "$LATEST"; } - public LambdaCloudDriverTaskResults verifyStatus(String endPoint) { - String respString = getFromCloudDriver(endPoint); + public LambdaCloudDriverTaskResults verifyStatus(String uri) { + Task task = katoService.lookupTaskWithUri(uri); try { - JsonNode jsonResults = objectMapper.readTree(respString); - JsonNode statusNode = jsonResults.get("status"); - ArrayNode resultsNode = (ArrayNode) jsonResults.get("resultObjects"); + Task.Status status = task.getStatus(); + LambdaVerificationStatusOutput st = + objectMapper.convertValue(status, LambdaVerificationStatusOutput.class); + + List resultObjects = task.getResultObjects(); LambdaCloudDriverResultObject ro = null; LambdaCloudDriverErrorObject err = null; - if ((resultsNode != null) && resultsNode.isArray()) { - ro = objectMapper.convertValue(resultsNode.get(0), LambdaCloudDriverResultObject.class); - err = objectMapper.convertValue(resultsNode.get(0), LambdaCloudDriverErrorObject.class); + if (resultObjects != null && resultObjects.size() > 0) { + ro = objectMapper.convertValue(resultObjects.get(0), LambdaCloudDriverResultObject.class); + err = objectMapper.convertValue(resultObjects.get(0), LambdaCloudDriverErrorObject.class); } - LambdaVerificationStatusOutput st = - objectMapper.convertValue(statusNode, LambdaVerificationStatusOutput.class); return LambdaCloudDriverTaskResults.builder().results(ro).status(st).errors(err).build(); } catch (Exception e) { - logger.error("Failed verifying task at {}", endPoint, e); - throw new RuntimeException(e); - } - } - - public String getFromCloudDriver(String endPoint) { - Request request = new Request.Builder().url(endPoint).headers(buildHeaders()).get().build(); - OkHttpClient client = - new OkHttpClient.Builder() - .connectTimeout(Duration.ofSeconds(config.getCloudDriverConnectTimeout())) - .readTimeout(Duration.ofSeconds(config.getCloudDriverReadTimeout())) - .build(); - Call call = client.newCall(request); - try { - Response response = call.execute(); - return response.body().string(); - } catch (Exception e) { - logger.error("Exception verifying task", e); + log.error("Failed verifying task at {}", uri, e); throw new RuntimeException(e); } } - public Headers buildHeaders() { - Headers.Builder headersBuilder = new Headers.Builder(); + public LambdaDefinition retrieveLambdaFromCache(LambdaGetInput input, String appName) { + String appPrefix = String.format("%s-", appName); + String functionName = input.getFunctionName(); - AuthenticatedRequest.getAuthenticationHeaders() - .forEach( - (key, value) -> { - value.ifPresent(s -> headersBuilder.add(key, s)); - }); - - return headersBuilder.build(); - } - - public LambdaDefinition retrieveLambdaFromCache(LambdaGetInput inp) { - // {{clouddriver_url}}/functions?functionName=a1-json_simple_lambda_222®ion=us-west-2&account=aws-managed-1 - logger.debug("Retrieve Lambda"); - String cloudDriverUrl = props.getCloudDriverBaseUrl(); - String region = inp.getRegion(); - String acc = inp.getAccount(); - String fName = inp.getFunctionName(); - String appPrefix = String.format("%s-", inp.getAppName()); - if (!fName.startsWith(appPrefix)) { - fName = String.format("%s-%s", inp.getAppName(), inp.getFunctionName()); + // todo(mattg) why do this + if (!functionName.startsWith(appPrefix)) { + functionName = String.format("%s-%s", appName, functionName); } - String url = cloudDriverUrl + CLOUDDRIVER_GET_PATH; - HttpUrl.Builder httpBuilder = HttpUrl.parse(url).newBuilder(); - httpBuilder.addQueryParameter("region", region); - httpBuilder.addQueryParameter("account", acc); - httpBuilder.addQueryParameter("functionName", fName); - Request request = - new Request.Builder().url(httpBuilder.build()).headers(buildHeaders()).build(); - OkHttpClient client = new OkHttpClient(); - Call call = client.newCall(request); - try { - Response response = call.execute(); - if (200 != response.code()) { - logger.error("Could not retrieve lambda"); - return null; - } - logger.debug("Found a function"); - String respString = response.body().string(); - return this.asObjectFromList(respString, LambdaDefinition.class); - } catch (Exception e) { - logger.error("Error calling clouddriver to find lambda.", e); - throw new RuntimeException(e); - } - } - public T getInput(StageExecution stage, Class type) { - try { - return objectMapper.convertValue(stage.getContext(), type); - } catch (Throwable e) { - e.printStackTrace(); - logger.error("Could not convert value"); - } - return null; - } - - public T asObjectFromList(String inpString, Class type) { - try { - TypeFactory typeFactory = objectMapper.getTypeFactory(); - List someClassList = - objectMapper.readValue(inpString, typeFactory.constructCollectionType(List.class, type)); - if (someClassList.size() == 0) { - return null; - } - return someClassList.get(0); - } catch (Throwable e) { - e.printStackTrace(); - logger.error("Could not convert value"); - } - return null; - } + String finalFunctionName = functionName; + List definitions = + retrySupport.retry( + () -> oortService.getFunction(input.getAccount(), input.getRegion(), finalFunctionName), + 5, + Duration.ofMillis(500), + true); - public T asObject(String inpString, Class type) { - try { - return objectMapper.convertValue(inpString, type); - } catch (Throwable e) { - e.printStackTrace(); - logger.error("Could not convert value"); - } - return null; + return definitions.size() > 0 ? definitions.get(0) : null; } - public String asString(Object inp) { - try { - return objectMapper.writeValueAsString(inp); - } catch (JsonProcessingException e) { - logger.error("Could not jsonify", e); - throw new RuntimeException(e); - } + public LambdaDefinition retrieveLambdaFromCache(StageExecution stage) { + LambdaGetInput lgi = stage.mapTo(LambdaGetInput.class); + return retrieveLambdaFromCache(lgi, stage.getExecution().getApplication()); } public String getCanonicalVersion( @@ -319,10 +191,10 @@ public String getCanonicalVersion( } } // Couldnt find it. - logger.error(String.format("Found invalid version string %s", inputVersion)); + log.error(String.format("Found invalid version string %s", inputVersion)); return null; } - logger.error("No published versions exist for function."); + log.error("No published versions exist for function."); return null; } @@ -337,19 +209,6 @@ public List getSortedRevisions(LambdaDefinition lf) { return revInt.stream().map(x -> Integer.toString(x)).collect(Collectors.toList()); } - public LambdaDefinition retrieveLambdaFromCache(StageExecution stage, boolean shouldRetry) { - LambdaGetInput lgi = this.getInput(stage, LambdaGetInput.class); - lgi.setAppName(stage.getExecution().getApplication()); - LambdaDefinition lf = this.retrieveLambdaFromCache(lgi); - int count = 0; - while (lf == null && count < 5 && shouldRetry) { - count++; - lf = this.retrieveLambdaFromCache((lgi)); - this.await(); - } - return lf; - } - public boolean validateUpsertLambdaInput( LambdaDeploymentInput inputLambda, List errorMessages) { if (validateBasicLambdaDeploymentInput(inputLambda, errorMessages)) { @@ -421,15 +280,15 @@ public boolean validateLambdaEdgeInput( } public void await() { - this.await(20000); + await(20000); } public void await(long duration) { try { - logger.debug("Going to sleep during lambda"); + log.debug("Going to sleep during lambda"); Thread.sleep(duration); } catch (Throwable e) { - logger.error("Error during await of lambda ", e); + log.error("Error during await of lambda", e); } } @@ -445,12 +304,9 @@ private Artifact resolvePipelineArtifact(LambdaPipelineArtifact artifact) { } public String getPipelinesArtifactContent(LambdaPipelineArtifact pipelineArtifact) { - RetrySupport retrySupport = new RetrySupport(); - return retrySupport.retry( () -> { - retrofit.client.Response response = - oort.fetchArtifact(resolvePipelineArtifact(pipelineArtifact)); + Response response = oortService.fetchArtifact(resolvePipelineArtifact(pipelineArtifact)); InputStream artifactInputStream; try { artifactInputStream = response.getBody().in(); diff --git a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaCacheRefreshTask.java b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaCacheRefreshTask.java index 642f0effa2..8977f751c4 100644 --- a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaCacheRefreshTask.java +++ b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaCacheRefreshTask.java @@ -16,57 +16,62 @@ package com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda; -import com.fasterxml.jackson.core.JsonProcessingException; +import static java.net.HttpURLConnection.HTTP_ACCEPTED; +import static java.net.HttpURLConnection.HTTP_OK; + +import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; -import com.netflix.spinnaker.kork.core.RetrySupport; import com.netflix.spinnaker.kork.web.exceptions.NotFoundException; +import com.netflix.spinnaker.orca.api.pipeline.OverridableTimeoutRetryableTask; import com.netflix.spinnaker.orca.api.pipeline.TaskResult; import com.netflix.spinnaker.orca.api.pipeline.models.ExecutionStatus; import com.netflix.spinnaker.orca.api.pipeline.models.StageExecution; -import com.netflix.spinnaker.orca.clouddriver.config.CloudDriverConfigurationProperties; +import com.netflix.spinnaker.orca.clouddriver.CloudDriverCacheService; +import com.netflix.spinnaker.orca.clouddriver.CloudDriverCacheStatusService; import com.netflix.spinnaker.orca.clouddriver.config.LambdaConfigurationProperties; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.input.LambdaCacheRefreshInput; -import com.netflix.spinnaker.orca.clouddriver.utils.LambdaCloudDriverUtils; -import java.io.IOException; -import java.time.Duration; -import java.util.Collection; -import java.util.List; -import java.util.Map; +import java.util.*; +import java.util.concurrent.TimeUnit; import javax.annotation.Nonnull; import lombok.Data; -import okhttp3.*; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; -import org.springframework.util.StringUtils; +import retrofit.client.Response; @Component -public class LambdaCacheRefreshTask implements LambdaStageBaseTask { - private static final Logger logger = LoggerFactory.getLogger(LambdaCacheRefreshTask.class); - private static final String CLOUDDRIVER_REFRESH_CACHE_PATH = "/cache/aws/function"; - - @Autowired CloudDriverConfigurationProperties props; +@Slf4j +public class LambdaCacheRefreshTask + implements LambdaStageBaseTask, OverridableTimeoutRetryableTask { - @Autowired private LambdaCloudDriverUtils utils; + private static final String PENDING_ID_KEY = "pendingId"; - @Autowired LambdaConfigurationProperties config; + private final ObjectMapper objectMapper; + private final LambdaConfigurationProperties lambdaConfigurationProperties; + private final CloudDriverCacheService cacheService; + private final CloudDriverCacheStatusService cacheStatusService; - private static final ObjectMapper objectMapper = new ObjectMapper(); + public LambdaCacheRefreshTask( + ObjectMapper objectMapper, + LambdaConfigurationProperties lambdaConfigurationProperties, + CloudDriverCacheService cacheService, + CloudDriverCacheStatusService cacheStatusService) { + this.objectMapper = objectMapper; + this.lambdaConfigurationProperties = lambdaConfigurationProperties; + this.cacheService = cacheService; + this.cacheStatusService = cacheStatusService; + } @Nonnull @Override public TaskResult execute(@Nonnull StageExecution stage) { - logger.debug("Executing LambdaCacheRefreshTask..."); prepareTask(stage); - try { - forceCacheRefresh(stage, 15); - return taskComplete(stage); - } catch (Exception e) { - return TaskResult.builder(ExecutionStatus.TERMINAL) - .context(getTaskContext(stage)) - .outputs(stage.getOutputs()) - .build(); + + if (getTaskContext(stage).get(PENDING_ID_KEY) == null) { + // trigger cache refresh + return forceCacheRefresh(stage); + } else { + // check status of pending cache refresh + return checkCacheRefreshStatus(stage); } } @@ -75,117 +80,85 @@ public static class OnDemandResponse { Map> cachedIdentifiersByType; } - /* - TWO try loops in here, ONE is embedded in the other. - - Retry until a force cache operation actually goes through - - AFTER that, retry until cache refresh finishes - */ - private void forceCacheRefresh(StageExecution stage, int tries) { - LambdaCacheRefreshInput inp = utils.getInput(stage, LambdaCacheRefreshInput.class); - inp.setAppName(stage.getExecution().getApplication()); - inp.setCredentials(inp.getAccount()); - - final RequestBody body = - RequestBody.create(MediaType.parse("application/json"), utils.asString(inp)); - final Request request = - new Request.Builder() - .url(props.getCloudDriverBaseUrl() + CLOUDDRIVER_REFRESH_CACHE_PATH) - .headers(utils.buildHeaders()) - .post(body) - .build(); - long startTime = System.currentTimeMillis(); - new RetrySupport() - .retry( - () -> { - try { - OkHttpClient client = - new OkHttpClient.Builder() - .connectTimeout(Duration.ofSeconds(config.getCloudDriverConnectTimeout())) - .readTimeout(Duration.ofSeconds(config.getCloudDriverReadTimeout())) - .build(); - Call call = client.newCall(request); - Response response = call.execute(); - String respString = response.body().string(); - OnDemandResponse onDemandRefreshResponse; - switch (response.code()) { - // 200 == usually a Delete operation... aka an eviction. - case 200: - logger.debug("cache refresh responded with 200"); - return true; - // Async processing... meaning we have to poll to see when the refresh - // finished.... - case 202: - logger.debug("cache refresh responded with 202"); - onDemandRefreshResponse = - objectMapper.readValue(respString, OnDemandResponse.class); - if (StringUtils.isEmpty( - onDemandRefreshResponse - .getCachedIdentifiersByType() - .get("onDemand") - .isEmpty())) { - throw new NotFoundException( - "Force cache refresh did not return the id of the cache to run. We failed or cache refresh isn't working as expected"); - } - String id = - onDemandRefreshResponse.getCachedIdentifiersByType().get("onDemand").get(0); - waitForCacheToComplete(id, startTime, props.getCloudDriverBaseUrl(), 30); - return true; - default: - logger.warn( - "Failed to generate a force cache refresh with response code of " - + response.code() - + "... retrying."); - throw new RuntimeException( - "Failed to process cache request due to an invalid response code... retrying..."); - } - } catch (IOException e) { - logger.error("cache- refresh failed: " + e.getMessage()); - logger.error(e.getStackTrace().toString()); - throw new RuntimeException("Error communicating with clouddriver", e); - } - }, - tries, - Duration.ofSeconds(config.getCacheRefreshRetryWaitTime()), - false); + private TaskResult forceCacheRefresh(StageExecution stage) { + LambdaCacheRefreshInput input = stage.mapTo(LambdaCacheRefreshInput.class); + input.setAppName(stage.getExecution().getApplication()); + input.setCredentials(input.getAccount()); + + Map request = toMap(input); + Response response = cacheService.forceCacheUpdate("aws", "function", request); + + if (response.getStatus() == HTTP_OK) { + // 200 == usually a Delete operation... aka an eviction. + return TaskResult.builder(ExecutionStatus.SUCCEEDED).context(stage.getContext()).build(); + } else if (response.getStatus() == HTTP_ACCEPTED) { + // Async processing... meaning we have to poll to see when the refresh finishes + OnDemandResponse onDemandRefreshResponse = + objectMapper.convertValue(response.getBody(), OnDemandResponse.class); + if (onDemandRefreshResponse.getCachedIdentifiersByType().get("onDemand").isEmpty()) { + throw new NotFoundException( + "Force cache refresh did not return the ID of the cache to poll. We failed or cache refresh isn't working as expected"); + } + + String id = onDemandRefreshResponse.getCachedIdentifiersByType().get("onDemand").get(0); + addToTaskContext(stage, PENDING_ID_KEY, id); + } else { + log.warn( + "Failed to generate a force cache refresh with response code of {}", + response.getStatus()); + } + + return TaskResult.builder(ExecutionStatus.RUNNING).context(stage.getContext()).build(); } /* - IF no data, trigger a force refresh - if processedCount > 0 && processedTime > stageStart + IF processedCount > 0 && processedTime > stageStart SUCCESS ELSE - TRIGGER A REFRESH + TRY AGAIN */ - private void waitForCacheToComplete( - String id, long taskStartTime, String cloudDriverUrl, int retries) { - - new RetrySupport() - .retry( - () -> { - try { - String response = - utils.getFromCloudDriver(cloudDriverUrl + "/cache/aws/function?id=" + id); - Collection> onDemands = - objectMapper.readValue(response, Collection.class); - for (Map results : onDemands) { - if ((int) results.getOrDefault("processedCount", 0) > 0 - && (long) results.getOrDefault("cacheTime", 0) > taskStartTime) { - logger.info("Caching should be completed for " + id); - return true; - } else { - // This short circuits the loop and triggers a retry after 15 seconds, to see if - // processedCount is finished yet... - throw new RuntimeException("No cache data has been processed... retrying..."); - } - } - logger.warn("No on demand cache refresh found for " + id); - throw new RuntimeException("No on demand cache refresh found for " + id); - } catch (JsonProcessingException e) { - throw new RuntimeException(e); - } - }, - retries, - Duration.ofSeconds(config.getCacheOnDemandRetryWaitTime()), - false); + private TaskResult checkCacheRefreshStatus(StageExecution stage) { + Long startTime = stage.getStartTime(); + if (startTime == null) { + throw new IllegalStateException("Stage has no start time, cannot be executed."); + } + + String id = (String) getTaskContext(stage).get(PENDING_ID_KEY); + + Collection> onDemands = + objectMapper.convertValue( + cacheStatusService.pendingForceCacheUpdatesById("aws", "function", id), + new TypeReference<>() {}); + + for (Map results : onDemands) { + if ((int) results.getOrDefault("processedCount", 0) > 0 + && (long) results.getOrDefault("cacheTime", 0) > startTime) { + log.info("Caching should be completed for " + id); + return TaskResult.builder(ExecutionStatus.SUCCEEDED).context(stage.getContext()).build(); + } else { + return TaskResult.builder(ExecutionStatus.RUNNING).context(stage.getContext()).build(); + } + } + + String error = String.format("No on demand cache refresh found for ID %s", id); + addErrorMessage(stage, error); + return TaskResult.builder(ExecutionStatus.TERMINAL) + .context(stage.getContext()) + .outputs(stage.getOutputs()) + .build(); + } + + private Map toMap(LambdaCacheRefreshInput input) { + return objectMapper.convertValue(input, new TypeReference<>() {}); + } + + @Override + public long getBackoffPeriod() { + return lambdaConfigurationProperties.getCacheOnDemandRetryWaitTime(); + } + + @Override + public long getTimeout() { + return TimeUnit.MINUTES.toMillis(15); } } diff --git a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaCreateTask.java b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaCreateTask.java index 1eec7908f9..190823b960 100644 --- a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaCreateTask.java +++ b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaCreateTask.java @@ -16,52 +16,59 @@ package com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; import com.netflix.spinnaker.orca.api.pipeline.TaskResult; import com.netflix.spinnaker.orca.api.pipeline.models.ExecutionStatus; import com.netflix.spinnaker.orca.api.pipeline.models.StageExecution; -import com.netflix.spinnaker.orca.clouddriver.config.CloudDriverConfigurationProperties; +import com.netflix.spinnaker.orca.clouddriver.KatoService; +import com.netflix.spinnaker.orca.clouddriver.model.OperationContext; +import com.netflix.spinnaker.orca.clouddriver.model.SubmitOperationResult; import com.netflix.spinnaker.orca.clouddriver.pipeline.providers.aws.lambda.LambdaStageConstants; +import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.LambdaUtils; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.*; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.input.LambdaDeploymentInput; -import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.input.LambdaGetInput; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.output.LambdaCloudOperationOutput; -import com.netflix.spinnaker.orca.clouddriver.utils.LambdaCloudDriverUtils; +import com.netflix.spinnaker.orca.clouddriver.utils.CloudProviderAware; import java.util.ArrayList; import java.util.List; import javax.annotation.Nonnull; import javax.annotation.Nullable; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @Component -public class LambdaCreateTask implements LambdaStageBaseTask { - private static final Logger logger = LoggerFactory.getLogger(LambdaCreateTask.class); - private static final String CLOUDDRIVER_CREATE_PATH = "/aws/ops/createLambdaFunction"; +@Slf4j +public class LambdaCreateTask implements CloudProviderAware, LambdaStageBaseTask { - @Autowired CloudDriverConfigurationProperties props; - private String cloudDriverUrl; + private final LambdaUtils utils; + private final KatoService katoService; + private final ObjectMapper objectMapper; - @Autowired private LambdaCloudDriverUtils utils; + public LambdaCreateTask( + LambdaUtils lambdaUtils, KatoService katoService, ObjectMapper objectMapper) { + this.utils = lambdaUtils; + this.katoService = katoService; + this.objectMapper = objectMapper; + } @Nonnull @Override public TaskResult execute(@Nonnull StageExecution stage) { - logger.debug("Executing LambdaDeploymentTask..."); - cloudDriverUrl = props.getCloudDriverBaseUrl(); + log.debug("Executing LambdaDeploymentTask..."); prepareTask(stage); - LambdaDeploymentInput ldi = utils.getInput(stage, LambdaDeploymentInput.class); + LambdaDeploymentInput ldi = stage.mapTo(LambdaDeploymentInput.class); + List errors = new ArrayList<>(); if (!utils.validateUpsertLambdaInput(ldi, errors)) { - return this.formErrorListTaskResult(stage, errors); + return formErrorListTaskResult(stage, errors); } + ldi.setAppName(stage.getExecution().getApplication()); - LambdaGetInput lgi = utils.getInput(stage, LambdaGetInput.class); - lgi.setAppName(stage.getExecution().getApplication()); - LambdaDefinition lambdaDefinition = utils.retrieveLambdaFromCache(stage, false); + LambdaDefinition lambdaDefinition = utils.retrieveLambdaFromCache(stage); + if (lambdaDefinition != null) { - logger.debug("noOp. Lambda already exists. only needs updating."); + log.debug("noOp. Lambda already exists. only needs updating."); addToTaskContext(stage, LambdaStageConstants.lambaCreatedKey, Boolean.FALSE); addToTaskContext(stage, LambdaStageConstants.lambdaObjectKey, lambdaDefinition); addToTaskContext( @@ -73,6 +80,7 @@ public TaskResult execute(@Nonnull StageExecution stage) { stage, LambdaStageConstants.originalRevisionIdKey, lambdaDefinition.getRevisionId()); return taskComplete(stage); } + addToOutput(stage, LambdaStageConstants.lambaCreatedKey, Boolean.TRUE); addToTaskContext(stage, LambdaStageConstants.lambaCreatedKey, Boolean.TRUE); LambdaCloudOperationOutput output = createLambda(stage); @@ -81,15 +89,18 @@ public TaskResult execute(@Nonnull StageExecution stage) { } private LambdaCloudOperationOutput createLambda(StageExecution stage) { - LambdaDeploymentInput ldi = utils.getInput(stage, LambdaDeploymentInput.class); + LambdaDeploymentInput ldi = stage.mapTo(LambdaDeploymentInput.class); ldi.setAppName(stage.getExecution().getApplication()); ldi.setCredentials(ldi.getAccount()); - String endPoint = cloudDriverUrl + CLOUDDRIVER_CREATE_PATH; - String rawString = utils.asString(ldi); - LambdaCloudDriverResponse respObj = utils.postToCloudDriver(endPoint, rawString); - String url = cloudDriverUrl + respObj.getResourceUri(); - logger.debug("Posted to cloudDriver for createLambda: " + url); - return LambdaCloudOperationOutput.builder().resourceId(respObj.getId()).url(url).build(); + + OperationContext context = objectMapper.convertValue(ldi, new TypeReference<>() {}); + context.setOperationType("createLambdaFunction"); + SubmitOperationResult result = katoService.submitOperation(getCloudProvider(), context); + + return LambdaCloudOperationOutput.builder() + .resourceId(result.getId()) + .url(result.getResourceUri()) + .build(); } @Nullable @@ -97,7 +108,4 @@ private LambdaCloudOperationOutput createLambda(StageExecution stage) { public TaskResult onTimeout(@Nonnull StageExecution stage) { return TaskResult.builder(ExecutionStatus.SKIPPED).build(); } - - @Override - public void onCancel(@Nonnull StageExecution stage) {} } diff --git a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaDeleteConcurrencyTask.java b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaDeleteConcurrencyTask.java index 2c9701bcb9..b902981629 100644 --- a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaDeleteConcurrencyTask.java +++ b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaDeleteConcurrencyTask.java @@ -15,45 +15,43 @@ */ package com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; import com.netflix.spinnaker.orca.api.pipeline.TaskResult; import com.netflix.spinnaker.orca.api.pipeline.models.ExecutionStatus; import com.netflix.spinnaker.orca.api.pipeline.models.StageExecution; -import com.netflix.spinnaker.orca.clouddriver.config.CloudDriverConfigurationProperties; +import com.netflix.spinnaker.orca.clouddriver.KatoService; +import com.netflix.spinnaker.orca.clouddriver.model.OperationContext; +import com.netflix.spinnaker.orca.clouddriver.model.SubmitOperationResult; import com.netflix.spinnaker.orca.clouddriver.pipeline.providers.aws.lambda.LambdaStageConstants; import com.netflix.spinnaker.orca.clouddriver.pipeline.servergroup.strategies.lambda.LambdaDeploymentStrategyEnum; -import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.LambdaCloudDriverResponse; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.input.LambdaConcurrencyInput; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.output.LambdaCloudOperationOutput; -import com.netflix.spinnaker.orca.clouddriver.utils.LambdaCloudDriverUtils; import java.util.Optional; import javax.annotation.Nonnull; import javax.annotation.Nullable; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @Component +@Slf4j public class LambdaDeleteConcurrencyTask implements LambdaStageBaseTask { - private static final Logger logger = LoggerFactory.getLogger(LambdaDeleteConcurrencyTask.class); - private static final String CLOUDDRIVER_DELETE_PROVISIONED_CONCURRENCY_PATH = - "/aws/ops/deleteLambdaProvisionedConcurrency"; - private static final String CLOUDDRIVER_DELETE_RESERVED_CONCURRENCY_PATH = - "/aws/ops/deleteLambdaReservedConcurrency"; + private final KatoService katoService; + private final ObjectMapper objectMapper; - @Autowired CloudDriverConfigurationProperties props; - - @Autowired private LambdaCloudDriverUtils utils; - private String cloudDriverUrl; + public LambdaDeleteConcurrencyTask(KatoService katoService, ObjectMapper objectMapper) { + this.katoService = katoService; + this.objectMapper = objectMapper; + } @Nonnull @Override public TaskResult execute(@Nonnull StageExecution stage) { - logger.debug("Executing LambdaDeleteConcurrencyTask..."); - cloudDriverUrl = props.getCloudDriverBaseUrl(); + log.debug("Executing LambdaDeleteConcurrencyTask..."); prepareTask(stage); - LambdaConcurrencyInput inp = utils.getInput(stage, LambdaConcurrencyInput.class); + + LambdaConcurrencyInput inp = stage.mapTo(LambdaConcurrencyInput.class); inp.setAppName(stage.getExecution().getApplication()); LambdaCloudOperationOutput output; @@ -77,21 +75,26 @@ public TaskResult execute(@Nonnull StageExecution stage) { private LambdaCloudOperationOutput deleteProvisionedConcurrency(LambdaConcurrencyInput inp) { inp.setQualifier(inp.getAliasName()); - String rawString = utils.asString(inp); - String endPoint = cloudDriverUrl + CLOUDDRIVER_DELETE_PROVISIONED_CONCURRENCY_PATH; - LambdaCloudDriverResponse respObj = utils.postToCloudDriver(endPoint, rawString); - String url = cloudDriverUrl + respObj.getResourceUri(); - logger.debug("Posted to cloudDriver for deleteProvisionedConcurrency: " + url); - return LambdaCloudOperationOutput.builder().resourceId(respObj.getId()).url(url).build(); + + OperationContext context = objectMapper.convertValue(inp, new TypeReference<>() {}); + context.setOperationType("deleteLambdaProvisionedConcurrency"); + SubmitOperationResult result = katoService.submitOperation(getCloudProvider(), context); + + return LambdaCloudOperationOutput.builder() + .resourceId(result.getId()) + .url(result.getResourceUri()) + .build(); } private LambdaCloudOperationOutput deleteReservedConcurrency(LambdaConcurrencyInput inp) { - String rawString = utils.asString(inp); - String endPoint = cloudDriverUrl + CLOUDDRIVER_DELETE_RESERVED_CONCURRENCY_PATH; - LambdaCloudDriverResponse respObj = utils.postToCloudDriver(endPoint, rawString); - String url = cloudDriverUrl + respObj.getResourceUri(); - logger.debug("Posted to cloudDriver for deleteReservedConcurrency: " + url); - return LambdaCloudOperationOutput.builder().resourceId(respObj.getId()).url(url).build(); + OperationContext context = objectMapper.convertValue(inp, new TypeReference<>() {}); + context.setOperationType("deleteLambdaReservedConcurrency"); + SubmitOperationResult result = katoService.submitOperation(getCloudProvider(), context); + + return LambdaCloudOperationOutput.builder() + .resourceId(result.getId()) + .url(result.getResourceUri()) + .build(); } @Nullable @@ -99,7 +102,4 @@ private LambdaCloudOperationOutput deleteReservedConcurrency(LambdaConcurrencyIn public TaskResult onTimeout(@Nonnull StageExecution stage) { return TaskResult.builder(ExecutionStatus.SKIPPED).build(); } - - @Override - public void onCancel(@Nonnull StageExecution stage) {} } diff --git a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaDeleteTask.java b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaDeleteTask.java index 341d72da9b..bff50c7cb8 100644 --- a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaDeleteTask.java +++ b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaDeleteTask.java @@ -16,45 +16,49 @@ package com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; import com.netflix.spinnaker.orca.api.pipeline.TaskResult; import com.netflix.spinnaker.orca.api.pipeline.models.StageExecution; -import com.netflix.spinnaker.orca.clouddriver.config.CloudDriverConfigurationProperties; -import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.LambdaCloudDriverResponse; +import com.netflix.spinnaker.orca.clouddriver.KatoService; +import com.netflix.spinnaker.orca.clouddriver.model.OperationContext; +import com.netflix.spinnaker.orca.clouddriver.model.SubmitOperationResult; +import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.LambdaUtils; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.LambdaDefinition; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.input.LambdaDeleteStageInput; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.output.LambdaCloudOperationOutput; -import com.netflix.spinnaker.orca.clouddriver.utils.LambdaCloudDriverUtils; import java.util.*; import javax.annotation.Nonnull; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @Component +@Slf4j public class LambdaDeleteTask implements LambdaStageBaseTask { - private static final Logger logger = LoggerFactory.getLogger(LambdaDeleteTask.class); - private String cloudDriverUrl; + private final LambdaUtils utils; + private final KatoService katoService; + private final ObjectMapper objectMapper; - @Autowired CloudDriverConfigurationProperties props; - - @Autowired private LambdaCloudDriverUtils utils; - - private static final String CLOUDDRIVER_DELETE_LAMBDA_PATH = "/aws/ops/deleteLambdaFunction"; + public LambdaDeleteTask( + LambdaUtils lambdaUtils, KatoService katoService, ObjectMapper objectMapper) { + this.utils = lambdaUtils; + this.katoService = katoService; + this.objectMapper = objectMapper; + } @Nonnull @Override public TaskResult execute(@Nonnull StageExecution stage) { - logger.debug("Executing LambdaDeletionTask..."); - cloudDriverUrl = props.getCloudDriverBaseUrl(); + log.debug("Executing LambdaDeletionTask..."); prepareTask(stage); - LambdaDeleteStageInput ldi = utils.getInput(stage, LambdaDeleteStageInput.class); + + LambdaDeleteStageInput ldi = stage.mapTo(LambdaDeleteStageInput.class); ldi.setAppName(stage.getExecution().getApplication()); if (ldi.getVersion().equals("$ALL")) { addToTaskContext(stage, "deleteTask:deleteVersion", ldi.getVersion()); - return formTaskResult(stage, deleteLambda(ldi), stage.getOutputs()); + return formTaskResult(stage, deleteLambda(stage), stage.getOutputs()); } String versionToDelete = getVersion(stage, ldi); @@ -69,7 +73,7 @@ public TaskResult execute(@Nonnull StageExecution stage) { if (!versionToDelete.contains(",")) { ldi.setQualifier(versionToDelete); - return formTaskResult(stage, deleteLambda(ldi), stage.getOutputs()); + return formTaskResult(stage, deleteLambda(stage), stage.getOutputs()); } String[] allVersionsList = versionToDelete.split(","); @@ -77,7 +81,7 @@ public TaskResult execute(@Nonnull StageExecution stage) { for (String currVersion : allVersionsList) { ldi.setQualifier(currVersion); - LambdaCloudOperationOutput ldso = deleteLambda(ldi); + LambdaCloudOperationOutput ldso = deleteLambda(stage); urlList.add(ldso.getUrl()); } addToTaskContext(stage, "urlList", urlList); @@ -96,7 +100,7 @@ private String getVersion(StageExecution stage, LambdaDeleteStageInput ldi) { return ldi.getVersionNumber(); } - LambdaDefinition lf = utils.retrieveLambdaFromCache(stage, true); + LambdaDefinition lf = utils.retrieveLambdaFromCache(stage); if (lf != null) { return utils.getCanonicalVersion( lf, ldi.getVersion(), ldi.getVersionNumber(), ldi.getRetentionNumber()); @@ -104,13 +108,14 @@ private String getVersion(StageExecution stage, LambdaDeleteStageInput ldi) { return null; } - private LambdaCloudOperationOutput deleteLambda(LambdaDeleteStageInput inp) { + private LambdaCloudOperationOutput deleteLambda(StageExecution stage) { + LambdaDeleteStageInput inp = stage.mapTo(LambdaDeleteStageInput.class); inp.setCredentials(inp.getAccount()); - String endPoint = cloudDriverUrl + CLOUDDRIVER_DELETE_LAMBDA_PATH; - String rawString = utils.asString(inp); - LambdaCloudDriverResponse respObj = utils.postToCloudDriver(endPoint, rawString); - String url = cloudDriverUrl + respObj.getResourceUri(); - logger.debug("Posted to cloudDriver for deleteLambda: " + url); - return LambdaCloudOperationOutput.builder().url(url).build(); + + OperationContext context = objectMapper.convertValue(inp, new TypeReference<>() {}); + context.setOperationType("deleteLambdaFunction"); + SubmitOperationResult result = katoService.submitOperation("aws", context); + + return LambdaCloudOperationOutput.builder().url(result.getResourceUri()).build(); } } diff --git a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaDeleteVerificationTask.java b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaDeleteVerificationTask.java index df1211bd16..ec00f94c25 100644 --- a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaDeleteVerificationTask.java +++ b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaDeleteVerificationTask.java @@ -19,20 +19,20 @@ import com.netflix.spinnaker.orca.api.pipeline.TaskResult; import com.netflix.spinnaker.orca.api.pipeline.models.ExecutionStatus; import com.netflix.spinnaker.orca.api.pipeline.models.StageExecution; -import com.netflix.spinnaker.orca.clouddriver.config.CloudDriverConfigurationProperties; +import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.LambdaUtils; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.LambdaCloudDriverTaskResults; -import com.netflix.spinnaker.orca.clouddriver.utils.LambdaCloudDriverUtils; import java.util.*; import javax.annotation.Nonnull; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component public class LambdaDeleteVerificationTask implements LambdaStageBaseTask { - @Autowired CloudDriverConfigurationProperties props; + private final LambdaUtils utils; - @Autowired private LambdaCloudDriverUtils utils; + public LambdaDeleteVerificationTask(LambdaUtils utils) { + this.utils = utils; + } @Nonnull @Override diff --git a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaFunctionForceRefreshTask.java b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaFunctionForceRefreshTask.java index ac65fbc00b..12e5b680a3 100644 --- a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaFunctionForceRefreshTask.java +++ b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaFunctionForceRefreshTask.java @@ -25,17 +25,19 @@ import java.util.HashMap; import java.util.Map; import javax.annotation.Nonnull; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component -public class LambdaFunctionForceRefreshTask implements CloudProviderAware, Task { - - static final String REFRESH_TYPE = "Function"; +public class LambdaFunctionForceRefreshTask implements Task, CloudProviderAware { public static final String TASK_NAME = "forceCacheRefresh"; + private static final String REFRESH_TYPE = "Function"; + + private final CloudDriverCacheService cacheService; - @Autowired private CloudDriverCacheService cacheService; + public LambdaFunctionForceRefreshTask(CloudDriverCacheService cacheService) { + this.cacheService = cacheService; + } @Nonnull @Override @@ -46,7 +48,6 @@ public TaskResult execute(@Nonnull StageExecution stage) { task.put("appName", stage.getExecution().getApplication()); cacheService.forceCacheUpdate(cloudProvider, REFRESH_TYPE, task); - return TaskResult.ofStatus(ExecutionStatus.SUCCEEDED); } } diff --git a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaFunctionTask.java b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaFunctionTask.java index 50ff6e08ef..9745cb634f 100644 --- a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaFunctionTask.java +++ b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaFunctionTask.java @@ -28,7 +28,6 @@ import java.util.Map; import javax.annotation.Nonnull; import org.apache.commons.lang3.StringUtils; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; /* @@ -40,9 +39,12 @@ @Component public class LambdaFunctionTask implements CloudProviderAware, Task { - @Autowired KatoService katoService; - public static final String TASK_NAME = "lambdaFunction"; + private final KatoService katoService; + + public LambdaFunctionTask(KatoService katoService) { + this.katoService = katoService; + } @Nonnull @Override diff --git a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaInvokeTask.java b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaInvokeTask.java index acebc6f634..1eef56186c 100644 --- a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaInvokeTask.java +++ b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaInvokeTask.java @@ -16,46 +16,53 @@ package com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; import com.netflix.spinnaker.orca.api.pipeline.TaskResult; import com.netflix.spinnaker.orca.api.pipeline.models.StageExecution; -import com.netflix.spinnaker.orca.clouddriver.config.CloudDriverConfigurationProperties; -import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.LambdaCloudDriverResponse; +import com.netflix.spinnaker.orca.clouddriver.KatoService; +import com.netflix.spinnaker.orca.clouddriver.model.OperationContext; +import com.netflix.spinnaker.orca.clouddriver.model.SubmitOperationResult; +import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.LambdaUtils; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.LambdaDefinition; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.input.LambdaInvokeStageInput; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.input.LambdaTrafficUpdateInput; -import com.netflix.spinnaker.orca.clouddriver.utils.LambdaCloudDriverUtils; import java.util.ArrayList; import java.util.Collection; import java.util.List; import javax.annotation.Nonnull; +import lombok.extern.slf4j.Slf4j; import org.pf4j.util.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component +@Slf4j public class LambdaInvokeTask implements LambdaStageBaseTask { - private static final Logger logger = LoggerFactory.getLogger(LambdaInvokeTask.class); - @Autowired CloudDriverConfigurationProperties props; + private final LambdaUtils utils; + private final KatoService katoService; + private final ObjectMapper objectMapper; - @Autowired private LambdaCloudDriverUtils utils; - - static String CLOUDDRIVER_INVOKE_LAMBDA_FUNCTION_PATH = "/aws/ops/invokeLambdaFunction"; + public LambdaInvokeTask(LambdaUtils utils, KatoService katoService, ObjectMapper objectMapper) { + this.utils = utils; + this.katoService = katoService; + this.objectMapper = objectMapper; + } @Nonnull @Override public TaskResult execute(@Nonnull StageExecution stage) { - logger.debug("Executing LambdaInvokeTask..."); + log.debug("Executing LambdaInvokeTask..."); prepareTask(stage); - LambdaDefinition lf = utils.retrieveLambdaFromCache(stage, true); + + LambdaDefinition lf = utils.retrieveLambdaFromCache(stage); if (lf == null) { - logger.error("Could not find lambda"); + log.error("Could not find lambda"); return this.formErrorTaskResult(stage, "No such lambda found."); } - LambdaInvokeStageInput ldi = utils.getInput(stage, LambdaInvokeStageInput.class); - LambdaTrafficUpdateInput tui = utils.getInput(stage, LambdaTrafficUpdateInput.class); + + LambdaInvokeStageInput ldi = stage.mapTo(LambdaInvokeStageInput.class); + LambdaTrafficUpdateInput tui = stage.mapTo(LambdaTrafficUpdateInput.class); ldi.setPayloadArtifact(tui.getPayloadArtifact().getArtifact()); ldi.setQualifier( StringUtils.isNullOrEmpty(ldi.getAliasName()) ? "$LATEST" : ldi.getAliasName()); @@ -63,7 +70,7 @@ public TaskResult execute(@Nonnull StageExecution stage) { ldi.setCredentials(ldi.getAccount()); List urlList = new ArrayList<>(); for (int i = 0; i < ldi.getExecutionCount(); i++) { - String url = this.invokeLambdaFunction(ldi); + String url = invokeLambdaFunction(ldi); urlList.add(url); } addToTaskContext(stage, "urlList", urlList); @@ -71,19 +78,15 @@ public TaskResult execute(@Nonnull StageExecution stage) { } private String invokeLambdaFunction(LambdaInvokeStageInput ldi) { - String cloudDriverUrl = props.getCloudDriverBaseUrl(); - String endPoint = cloudDriverUrl + CLOUDDRIVER_INVOKE_LAMBDA_FUNCTION_PATH; - String rawString = utils.asString(ldi); - LambdaCloudDriverResponse respObj = utils.postToCloudDriver(endPoint, rawString); - String url = cloudDriverUrl + respObj.getResourceUri(); - logger.debug("Posted to cloudDriver for lambda invocation: " + url); - return url; + OperationContext context = objectMapper.convertValue(ldi, new TypeReference<>() {}); + context.setOperationType("invokeLambdaFunction"); + + SubmitOperationResult result = katoService.submitOperation(getCloudProvider(), context); + return result.getResourceUri(); } @Override public Collection aliases() { - List ss = new ArrayList<>(); - ss.add("lambdaInvokeTask"); - return ss; + return List.of("lambdaInvokeTask"); } } diff --git a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaInvokeVerificationTask.java b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaInvokeVerificationTask.java index b72fd86bc3..64dda3639f 100644 --- a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaInvokeVerificationTask.java +++ b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaInvokeVerificationTask.java @@ -19,39 +19,37 @@ import com.netflix.spinnaker.orca.api.pipeline.TaskResult; import com.netflix.spinnaker.orca.api.pipeline.models.ExecutionStatus; import com.netflix.spinnaker.orca.api.pipeline.models.StageExecution; -import com.netflix.spinnaker.orca.clouddriver.config.CloudDriverConfigurationProperties; +import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.LambdaUtils; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.LambdaCloudDriverInvokeOperationResults; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.LambdaCloudDriverTaskResults; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.input.LambdaInvokeStageInput; -import com.netflix.spinnaker.orca.clouddriver.utils.LambdaCloudDriverUtils; import java.util.*; import java.util.stream.Collectors; import javax.annotation.Nonnull; +import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.tuple.Pair; import org.pf4j.util.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component +@Slf4j public class LambdaInvokeVerificationTask implements LambdaStageBaseTask { - private static final Logger logger = LoggerFactory.getLogger(LambdaInvokeVerificationTask.class); + private final LambdaUtils utils; - @Autowired CloudDriverConfigurationProperties props; - - @Autowired private LambdaCloudDriverUtils utils; + public LambdaInvokeVerificationTask(LambdaUtils utils) { + this.utils = utils; + } @Nonnull @Override public TaskResult execute(@Nonnull StageExecution stage) { - logger.debug("Executing LambdaInvokeVerificationTask..."); + log.debug("Executing LambdaInvokeVerificationTask..."); prepareTask(stage); try { return doVerify(stage); } catch (Throwable e) { - logger.error("Exception verifying task", e); + log.error("Exception verifying task", e); logException(stage, e); addExceptionToOutput(stage, e); return formErrorTaskResult(stage, "Exception during task verification"); @@ -94,8 +92,8 @@ public TaskResult doVerify(@Nonnull StageExecution stage) { }); } - LambdaInvokeStageInput ldi = utils.getInput(stage, LambdaInvokeStageInput.class); - List> invokeResultsList = new ArrayList>(); + LambdaInvokeStageInput ldi = stage.mapTo(LambdaInvokeStageInput.class); + List> invokeResultsList = new ArrayList<>(); listOfTaskResults.forEach( op -> { Map invokeResults = null; @@ -138,7 +136,7 @@ private Map verifyInvokeResults(String url, int seconds) { utils.await(); timeout -= sleepTime; } catch (Throwable e) { - logger.error("Error waiting for lambda invocation to complete"); + log.error("Error waiting for lambda invocation to complete"); } } @@ -165,8 +163,6 @@ private Map verifyInvokeResults(String url, int seconds) { @Override public Collection aliases() { - List ss = new ArrayList<>(); - ss.add("lambdaInvokeVerificationTask"); - return ss; + return List.of("lambdaInvokeVerificationTask"); } } diff --git a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaOutputTask.java b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaOutputTask.java index b0a615f6af..e34dc0e285 100644 --- a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaOutputTask.java +++ b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaOutputTask.java @@ -19,40 +19,35 @@ import com.netflix.spinnaker.orca.api.pipeline.TaskResult; import com.netflix.spinnaker.orca.api.pipeline.models.ExecutionStatus; import com.netflix.spinnaker.orca.api.pipeline.models.StageExecution; -import com.netflix.spinnaker.orca.clouddriver.config.CloudDriverConfigurationProperties; import com.netflix.spinnaker.orca.clouddriver.pipeline.providers.aws.lambda.LambdaStageConstants; +import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.LambdaUtils; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.LambdaDefinition; -import com.netflix.spinnaker.orca.clouddriver.utils.LambdaCloudDriverUtils; -import java.util.ArrayList; import java.util.Collection; import java.util.List; import javax.annotation.Nonnull; import javax.annotation.Nullable; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component public class LambdaOutputTask implements LambdaStageBaseTask { - private static final Logger logger = LoggerFactory.getLogger(LambdaOutputTask.class); - @Autowired CloudDriverConfigurationProperties props; + private final LambdaUtils lambdaUtils; - @Autowired private LambdaCloudDriverUtils utils; + public LambdaOutputTask(LambdaUtils lambdaUtils) { + this.lambdaUtils = lambdaUtils; + } @Nonnull @Override public TaskResult execute(@Nonnull StageExecution stage) { - logger.debug("Executing LambdaOutputTask..."); prepareTask(stage); - Boolean justCreated = - (Boolean) stage.getContext().getOrDefault(LambdaStageConstants.lambaCreatedKey, false); - LambdaDefinition lf = utils.retrieveLambdaFromCache(stage, justCreated); - if (lf != null) { - addToOutput(stage, LambdaStageConstants.revisionIdKey, lf.getRevisionId()); - addToOutput(stage, LambdaStageConstants.lambdaObjectKey, lf); + + LambdaDefinition lambda = lambdaUtils.retrieveLambdaFromCache(stage); + if (lambda != null) { + addToOutput(stage, LambdaStageConstants.revisionIdKey, lambda.getRevisionId()); + addToOutput(stage, LambdaStageConstants.lambdaObjectKey, lambda); } + copyContextToOutput(stage); return taskComplete(stage); } @@ -63,13 +58,8 @@ public TaskResult onTimeout(@Nonnull StageExecution stage) { return TaskResult.builder(ExecutionStatus.SKIPPED).build(); } - @Override - public void onCancel(@Nonnull StageExecution stage) {} - @Override public Collection aliases() { - List ss = new ArrayList<>(); - ss.add("lambdaOutputTask"); - return ss; + return List.of("lambdaOutputTask"); } } diff --git a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaPublishVersionTask.java b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaPublishVersionTask.java index 869f3f501e..7d8d5d4dc9 100644 --- a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaPublishVersionTask.java +++ b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaPublishVersionTask.java @@ -16,47 +16,55 @@ package com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; import com.netflix.spinnaker.orca.api.pipeline.TaskResult; import com.netflix.spinnaker.orca.api.pipeline.models.ExecutionStatus; import com.netflix.spinnaker.orca.api.pipeline.models.StageExecution; -import com.netflix.spinnaker.orca.clouddriver.config.CloudDriverConfigurationProperties; +import com.netflix.spinnaker.orca.clouddriver.KatoService; +import com.netflix.spinnaker.orca.clouddriver.model.OperationContext; +import com.netflix.spinnaker.orca.clouddriver.model.SubmitOperationResult; import com.netflix.spinnaker.orca.clouddriver.pipeline.providers.aws.lambda.LambdaStageConstants; +import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.LambdaUtils; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.*; -import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.input.LambdaGetInput; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.input.LambdaPublisVersionInput; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.output.LambdaCloudOperationOutput; -import com.netflix.spinnaker.orca.clouddriver.utils.LambdaCloudDriverUtils; +import com.netflix.spinnaker.orca.clouddriver.utils.CloudProviderAware; import javax.annotation.Nonnull; import javax.annotation.Nullable; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @Component -public class LambdaPublishVersionTask implements LambdaStageBaseTask { - private static final Logger logger = LoggerFactory.getLogger(LambdaPublishVersionTask.class); - private static final String CLOUDDRIVER_PUBLISH_VERSION_PATH = - "/aws/ops/publishLambdaFunctionVersion"; +@Slf4j +public class LambdaPublishVersionTask implements LambdaStageBaseTask, CloudProviderAware { - @Autowired CloudDriverConfigurationProperties props; - private String cloudDriverUrl; + private final LambdaUtils utils; + private final KatoService katoService; + private final ObjectMapper objectMapper; - @Autowired private LambdaCloudDriverUtils utils; + public LambdaPublishVersionTask( + LambdaUtils utils, KatoService katoService, ObjectMapper objectMapper) { + this.utils = utils; + this.katoService = katoService; + this.objectMapper = objectMapper; + } @Nonnull @Override public TaskResult execute(@Nonnull StageExecution stage) { - logger.debug("Executing LambdaPublishVersionTask..."); - cloudDriverUrl = props.getCloudDriverBaseUrl(); + log.debug("Executing LambdaPublishVersionTask..."); prepareTask(stage); + if (!requiresVersionPublish(stage)) { addToOutput(stage, LambdaStageConstants.lambaVersionPublishedKey, Boolean.FALSE); return taskComplete(stage); } + LambdaCloudOperationOutput output = this.publishVersion(stage); addCloudOperationToContext(stage, output, LambdaStageConstants.publishVersionUrlKey); - this.addToTaskContext(stage, LambdaStageConstants.lambaVersionPublishedKey, Boolean.TRUE); + + addToTaskContext(stage, LambdaStageConstants.lambaVersionPublishedKey, Boolean.TRUE); return taskComplete(stage); } @@ -64,13 +72,17 @@ private boolean requiresVersionPublish(StageExecution stage) { Boolean justCreated = (Boolean) stage.getContext().getOrDefault(LambdaStageConstants.lambaCreatedKey, Boolean.FALSE); - if (justCreated) return false; + if (justCreated) { + return false; + } + Boolean requiresPublishFlag = (Boolean) stage.getContext().getOrDefault("publish", Boolean.FALSE); - if (!requiresPublishFlag) return false; - LambdaGetInput lgi = utils.getInput(stage, LambdaGetInput.class); - lgi.setAppName(stage.getExecution().getApplication()); - LambdaDefinition lf = utils.retrieveLambdaFromCache(stage, true); + if (!requiresPublishFlag) { + return false; + } + + LambdaDefinition lf = utils.retrieveLambdaFromCache(stage); String newRevisionId = lf.getRevisionId(); String origRevisionId = (String) stage.getContext().get(LambdaStageConstants.originalRevisionIdKey); @@ -79,17 +91,21 @@ private boolean requiresVersionPublish(StageExecution stage) { } private LambdaCloudOperationOutput publishVersion(StageExecution stage) { - LambdaPublisVersionInput inp = utils.getInput(stage, LambdaPublisVersionInput.class); + LambdaPublisVersionInput inp = stage.mapTo(LambdaPublisVersionInput.class); inp.setAppName(stage.getExecution().getApplication()); inp.setCredentials(inp.getAccount()); - String rawString = utils.asString(inp); - String endPoint = cloudDriverUrl + CLOUDDRIVER_PUBLISH_VERSION_PATH; + String revisionId = (String) stage.getContext().get(LambdaStageConstants.newRevisionIdKey); inp.setRevisionId(revisionId); - LambdaCloudDriverResponse respObj = utils.postToCloudDriver(endPoint, rawString); - String url = cloudDriverUrl + respObj.getResourceUri(); - logger.debug("Posted to cloudDriver for publishVersion: " + url); - return LambdaCloudOperationOutput.builder().resourceId(respObj.getId()).url(url).build(); + + OperationContext context = objectMapper.convertValue(inp, new TypeReference<>() {}); + context.setOperationType("publishLambdaFunctionVersion"); + SubmitOperationResult result = katoService.submitOperation(getCloudProvider(), context); + + return LambdaCloudOperationOutput.builder() + .resourceId(result.getId()) + .url(result.getResourceUri()) + .build(); } @Nullable @@ -97,7 +113,4 @@ private LambdaCloudOperationOutput publishVersion(StageExecution stage) { public TaskResult onTimeout(@Nonnull StageExecution stage) { return TaskResult.builder(ExecutionStatus.SKIPPED).build(); } - - @Override - public void onCancel(@Nonnull StageExecution stage) {} } diff --git a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaPutConcurrencyTask.java b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaPutConcurrencyTask.java index badc4ecb35..b43af7e5ac 100644 --- a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaPutConcurrencyTask.java +++ b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaPutConcurrencyTask.java @@ -15,45 +15,44 @@ */ package com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; import com.netflix.spinnaker.orca.api.pipeline.TaskResult; import com.netflix.spinnaker.orca.api.pipeline.models.ExecutionStatus; import com.netflix.spinnaker.orca.api.pipeline.models.StageExecution; -import com.netflix.spinnaker.orca.clouddriver.config.CloudDriverConfigurationProperties; +import com.netflix.spinnaker.orca.clouddriver.KatoService; +import com.netflix.spinnaker.orca.clouddriver.model.OperationContext; +import com.netflix.spinnaker.orca.clouddriver.model.SubmitOperationResult; import com.netflix.spinnaker.orca.clouddriver.pipeline.providers.aws.lambda.LambdaStageConstants; import com.netflix.spinnaker.orca.clouddriver.pipeline.servergroup.strategies.lambda.LambdaDeploymentStrategyEnum; -import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.LambdaCloudDriverResponse; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.input.LambdaConcurrencyInput; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.output.LambdaCloudOperationOutput; -import com.netflix.spinnaker.orca.clouddriver.utils.LambdaCloudDriverUtils; import java.util.Optional; import javax.annotation.Nonnull; import javax.annotation.Nullable; +import lombok.extern.slf4j.Slf4j; import org.pf4j.util.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component +@Slf4j public class LambdaPutConcurrencyTask implements LambdaStageBaseTask { - private static final Logger logger = LoggerFactory.getLogger(LambdaPutConcurrencyTask.class); - private static final String CLOUDDRIVER_PUT_PROVISIONED_CONCURRENCY_PATH = - "/aws/ops/putLambdaProvisionedConcurrency"; - private static final String CLOUDDRIVER_PUT_RESERVED_CONCURRENCY_PATH = - "/aws/ops/putLambdaReservedConcurrency"; - @Autowired CloudDriverConfigurationProperties props; + private final KatoService katoService; + private final ObjectMapper objectMapper; - @Autowired private LambdaCloudDriverUtils utils; - private String cloudDriverUrl; + public LambdaPutConcurrencyTask(KatoService katoService, ObjectMapper objectMapper) { + this.katoService = katoService; + this.objectMapper = objectMapper; + } @Nonnull @Override public TaskResult execute(@Nonnull StageExecution stage) { - logger.debug("Executing LambdaPutConcurrencyTask..."); - cloudDriverUrl = props.getCloudDriverBaseUrl(); + log.debug("Executing LambdaPutConcurrencyTask..."); prepareTask(stage); - LambdaConcurrencyInput inp = utils.getInput(stage, LambdaConcurrencyInput.class); + + LambdaConcurrencyInput inp = stage.mapTo(LambdaConcurrencyInput.class); inp.setAppName(stage.getExecution().getApplication()); if ((inp.getReservedConcurrentExecutions() == null @@ -84,22 +83,25 @@ private LambdaCloudOperationOutput putConcurrency(LambdaConcurrencyInput inp) { } private LambdaCloudOperationOutput putReservedConcurrency(LambdaConcurrencyInput inp) { - String rawString = utils.asString(inp); - String endPoint = cloudDriverUrl + CLOUDDRIVER_PUT_RESERVED_CONCURRENCY_PATH; - LambdaCloudDriverResponse respObj = utils.postToCloudDriver(endPoint, rawString); - String url = cloudDriverUrl + respObj.getResourceUri(); - logger.debug("Posted to cloudDriver for putReservedConcurrency: " + url); - return LambdaCloudOperationOutput.builder().resourceId(respObj.getId()).url(url).build(); + OperationContext context = objectMapper.convertValue(inp, new TypeReference<>() {}); + context.setOperationType("putLambdaReservedConcurrency"); + SubmitOperationResult result = katoService.submitOperation(getCloudProvider(), context); + + return LambdaCloudOperationOutput.builder() + .resourceId(result.getId()) + .url(result.getResourceUri()) + .build(); } private LambdaCloudOperationOutput putProvisionedConcurrency(LambdaConcurrencyInput inp) { - inp.setQualifier(inp.getAliasName()); - String rawString = utils.asString(inp); - String endPoint = cloudDriverUrl + CLOUDDRIVER_PUT_PROVISIONED_CONCURRENCY_PATH; - LambdaCloudDriverResponse respObj = utils.postToCloudDriver(endPoint, rawString); - String url = cloudDriverUrl + respObj.getResourceUri(); - logger.debug("Posted to cloudDriver for putProvisionedConcurrency: " + url); - return LambdaCloudOperationOutput.builder().resourceId(respObj.getId()).url(url).build(); + OperationContext context = objectMapper.convertValue(inp, new TypeReference<>() {}); + context.setOperationType("putLambdaProvisionedConcurrency"); + SubmitOperationResult result = katoService.submitOperation(getCloudProvider(), context); + + return LambdaCloudOperationOutput.builder() + .resourceId(result.getId()) + .url(result.getResourceUri()) + .build(); } @Nullable @@ -107,7 +109,4 @@ private LambdaCloudOperationOutput putProvisionedConcurrency(LambdaConcurrencyIn public TaskResult onTimeout(@Nonnull StageExecution stage) { return TaskResult.builder(ExecutionStatus.SKIPPED).build(); } - - @Override - public void onCancel(@Nonnull StageExecution stage) {} } diff --git a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaStageBaseTask.java b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaStageBaseTask.java index 703366c655..d097be42eb 100644 --- a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaStageBaseTask.java +++ b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaStageBaseTask.java @@ -29,6 +29,10 @@ public interface LambdaStageBaseTask extends Task { + default String getCloudProvider() { + return "aws"; + } + default boolean validateInput(StageExecution stage, List errors) { return true; } diff --git a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaTrafficUpdateTask.java b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaTrafficUpdateTask.java index a8599d4e5f..0d45db141b 100644 --- a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaTrafficUpdateTask.java +++ b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaTrafficUpdateTask.java @@ -18,57 +18,51 @@ import com.netflix.spinnaker.orca.api.pipeline.TaskResult; import com.netflix.spinnaker.orca.api.pipeline.models.StageExecution; -import com.netflix.spinnaker.orca.clouddriver.config.CloudDriverConfigurationProperties; import com.netflix.spinnaker.orca.clouddriver.pipeline.servergroup.strategies.lambda.BaseLambdaDeploymentStrategy; import com.netflix.spinnaker.orca.clouddriver.pipeline.servergroup.strategies.lambda.LambdaDeploymentStrategyEnum; import com.netflix.spinnaker.orca.clouddriver.pipeline.servergroup.strategies.lambda.LambdaTrafficUpdateStrategyInjector; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.input.LambdaBaseStrategyInput; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.output.LambdaDeploymentStrategyOutput; -import com.netflix.spinnaker.orca.clouddriver.utils.LambdaCloudDriverUtils; import java.util.*; import javax.annotation.Nonnull; import javax.annotation.Nullable; +import lombok.extern.slf4j.Slf4j; import org.pf4j.util.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component +@Slf4j public class LambdaTrafficUpdateTask implements LambdaStageBaseTask { - private static final Logger logger = LoggerFactory.getLogger(LambdaTrafficUpdateTask.class); - @Autowired LambdaTrafficUpdateStrategyInjector injector; + private final LambdaTrafficUpdateStrategyInjector injector; - @Autowired CloudDriverConfigurationProperties props; - - @Autowired private LambdaCloudDriverUtils utils; + public LambdaTrafficUpdateTask(LambdaTrafficUpdateStrategyInjector injector) { + this.injector = injector; + } @Nonnull @Override public TaskResult execute(@Nonnull StageExecution stage) { - logger.debug("Executing LambdaTrafficUpdateTask..."); + log.debug("Executing LambdaTrafficUpdateTask..."); prepareTask(stage); + LambdaDeploymentStrategyOutput result; BaseLambdaDeploymentStrategy deploymentStrategy = getDeploymentStrategy(stage); + List validationErrors = new ArrayList<>(); if (!validateInput(stage, validationErrors)) { - logger.error("Validation failed for traffic update task"); - return this.formErrorListTaskResult(stage, validationErrors); + log.error("Validation failed for traffic update task"); + return formErrorListTaskResult(stage, validationErrors); } + LambdaBaseStrategyInput input = deploymentStrategy.setupInput(stage); result = deploymentStrategy.deploy(input); if (!result.isSucceeded()) { return formErrorTaskResult(stage, result.getErrorMessage()); } + final StageExecution tmpStage = stage; - result - .getOutput() - .getOutputMap() - .forEach( - (x, y) -> { - addToTaskContext(tmpStage, x, y); - }); + result.getOutput().getOutputMap().forEach((x, y) -> addToTaskContext(tmpStage, x, y)); addCloudOperationToContext(stage, result.getOutput(), "url"); return taskComplete(stage); @@ -100,7 +94,4 @@ private BaseLambdaDeploymentStrategy getDeploymentStrategy(StageExecution stage) public TaskResult onTimeout(@Nonnull StageExecution stage) { return null; } - - @Override - public void onCancel(@Nonnull StageExecution stage) {} } diff --git a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaTrafficUpdateVerificationTask.java b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaTrafficUpdateVerificationTask.java index cb0fe40a0d..e5a75ebaa1 100644 --- a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaTrafficUpdateVerificationTask.java +++ b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaTrafficUpdateVerificationTask.java @@ -21,32 +21,30 @@ import com.netflix.spinnaker.orca.api.pipeline.TaskResult; import com.netflix.spinnaker.orca.api.pipeline.models.ExecutionStatus; import com.netflix.spinnaker.orca.api.pipeline.models.StageExecution; -import com.netflix.spinnaker.orca.clouddriver.config.CloudDriverConfigurationProperties; import com.netflix.spinnaker.orca.clouddriver.config.LambdaConfigurationProperties; import com.netflix.spinnaker.orca.clouddriver.pipeline.servergroup.strategies.lambda.LambdaDeploymentStrategyEnum; +import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.LambdaUtils; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.LambdaCloudDriverTaskResults; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.LambdaDefinition; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.input.LambdaTrafficUpdateInput; -import com.netflix.spinnaker.orca.clouddriver.utils.LambdaCloudDriverUtils; import java.util.*; import java.util.concurrent.TimeUnit; import javax.annotation.Nonnull; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @Component +@Slf4j public class LambdaTrafficUpdateVerificationTask implements LambdaStageBaseTask { - private static final Logger logger = - LoggerFactory.getLogger(LambdaTrafficUpdateVerificationTask.class); + private final LambdaUtils utils; + private final LambdaConfigurationProperties config; - @Autowired CloudDriverConfigurationProperties props; - - @Autowired private LambdaCloudDriverUtils utils; - - @Autowired LambdaConfigurationProperties config; + public LambdaTrafficUpdateVerificationTask( + LambdaUtils utils, LambdaConfigurationProperties config) { + this.utils = utils; + this.config = config; + } @Nonnull @Override @@ -102,11 +100,11 @@ private boolean validateWeights(StageExecution stage) { TimeUnit.SECONDS.toMillis(config.getCloudDriverRetrieveNewPublishedLambdaWaitSeconds())); AliasRoutingConfiguration weights = null; long startTime = System.currentTimeMillis(); - LambdaTrafficUpdateInput inp = utils.getInput(stage, LambdaTrafficUpdateInput.class); + LambdaTrafficUpdateInput inp = stage.mapTo(LambdaTrafficUpdateInput.class); boolean status = false; do { utils.await(TimeUnit.SECONDS.toMillis(config.getCacheRefreshRetryWaitTime())); - LambdaDefinition lf = utils.retrieveLambdaFromCache(stage, false); + LambdaDefinition lf = utils.retrieveLambdaFromCache(stage); Optional aliasConfiguration = lf.getAliasConfigurations().stream() .filter(al -> al.getName().equals(inp.getAliasName())) @@ -120,7 +118,7 @@ private boolean validateWeights(StageExecution stage) { if ((System.currentTimeMillis() - startTime) > TimeUnit.SECONDS.toMillis( config.getCloudDriverRetrieveMaxValidateWeightsTimeSeconds())) { - logger.warn( + log.warn( "alias weights did not update in {} seconds. waited {} seconds", config.getCloudDriverRetrieveMaxValidateWeightsTimeSeconds(), TimeUnit.MILLISECONDS.toSeconds((System.currentTimeMillis() - startTime))); diff --git a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaUpdateAliasesTask.java b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaUpdateAliasesTask.java index bece13f1ad..4154f1d029 100644 --- a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaUpdateAliasesTask.java +++ b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaUpdateAliasesTask.java @@ -16,47 +16,50 @@ package com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; import com.netflix.spinnaker.orca.api.pipeline.TaskResult; import com.netflix.spinnaker.orca.api.pipeline.models.ExecutionStatus; import com.netflix.spinnaker.orca.api.pipeline.models.StageExecution; -import com.netflix.spinnaker.orca.clouddriver.config.CloudDriverConfigurationProperties; +import com.netflix.spinnaker.orca.clouddriver.KatoService; +import com.netflix.spinnaker.orca.clouddriver.model.OperationContext; +import com.netflix.spinnaker.orca.clouddriver.model.SubmitOperationResult; import com.netflix.spinnaker.orca.clouddriver.pipeline.providers.aws.lambda.LambdaStageConstants; -import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.LambdaCloudDriverResponse; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.input.LambdaUpdateAliasesInput; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.output.LambdaCloudOperationOutput; -import com.netflix.spinnaker.orca.clouddriver.utils.LambdaCloudDriverUtils; import java.util.ArrayList; import java.util.List; import javax.annotation.Nonnull; import javax.annotation.Nullable; +import lombok.extern.slf4j.Slf4j; import org.pf4j.util.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component +@Slf4j public class LambdaUpdateAliasesTask implements LambdaStageBaseTask { - private static final Logger logger = LoggerFactory.getLogger(LambdaUpdateAliasesTask.class); - private static final String CLOUDDRIVER_UPDATE_ALIAS_PATH = "/aws/ops/upsertLambdaFunctionAlias"; private static final String DEFAULT_ALIAS_DESCRIPTION = "Created via Spinnaker"; private static final String LATEST_VERSION_STRING = "$LATEST"; - @Autowired CloudDriverConfigurationProperties props; - private String cloudDriverUrl; + private final KatoService katoService; + private final ObjectMapper objectMapper; - @Autowired private LambdaCloudDriverUtils utils; + public LambdaUpdateAliasesTask(KatoService katoService, ObjectMapper objectMapper) { + this.katoService = katoService; + this.objectMapper = objectMapper; + } @Nonnull @Override public TaskResult execute(@Nonnull StageExecution stage) { - logger.debug("Executing LambdaUpdateAliasesTask..."); - cloudDriverUrl = props.getCloudDriverBaseUrl(); + log.debug("Executing LambdaUpdateAliasesTask..."); prepareTask(stage); + if (!shouldAddAliases(stage)) { addToOutput(stage, LambdaStageConstants.lambaAliasesUpdatedKey, Boolean.FALSE); return taskComplete(stage); } + List output = updateLambdaAliases(stage); buildContextOutput(stage, output); addToTaskContext(stage, LambdaStageConstants.lambaAliasesUpdatedKey, Boolean.TRUE); @@ -79,24 +82,35 @@ private LambdaCloudOperationOutput updateSingleAlias(LambdaUpdateAliasesInput in inp.setAliasDescription(DEFAULT_ALIAS_DESCRIPTION); inp.setAliasName(alias); inp.setMajorFunctionVersion(LATEST_VERSION_STRING); - String endPoint = cloudDriverUrl + CLOUDDRIVER_UPDATE_ALIAS_PATH; - String rawString = utils.asString(inp); - LambdaCloudDriverResponse respObj = utils.postToCloudDriver(endPoint, rawString); - String url = cloudDriverUrl + respObj.getResourceUri(); - logger.debug("Posted to cloudDriver for updateLambdaAliases: " + url); - return LambdaCloudOperationOutput.builder().resourceId(respObj.getId()).url(url).build(); + + OperationContext context = objectMapper.convertValue(inp, new TypeReference<>() {}); + context.setOperationType("upsertLambdaFunctionAlias"); + SubmitOperationResult result = katoService.submitOperation(getCloudProvider(), context); + + return LambdaCloudOperationOutput.builder() + .resourceId(result.getId()) + .url(result.getResourceUri()) + .build(); } private List updateLambdaAliases(StageExecution stage) { List result = new ArrayList<>(); - List aliases = (List) stage.getContext().get("aliases"); - LambdaUpdateAliasesInput inp = utils.getInput(stage, LambdaUpdateAliasesInput.class); + + LambdaUpdateAliasesInput inp = stage.mapTo(LambdaUpdateAliasesInput.class); inp.setAppName(stage.getExecution().getApplication()); inp.setCredentials(inp.getAccount()); + + List aliases = (List) stage.getContext().get("aliases"); for (String alias : aliases) { - if (StringUtils.isNullOrEmpty(alias)) continue; + if (StringUtils.isNullOrEmpty(alias)) { + continue; + } + String formattedAlias = alias.trim(); - if (StringUtils.isNullOrEmpty(formattedAlias)) continue; + if (StringUtils.isNullOrEmpty(formattedAlias)) { + continue; + } + LambdaCloudOperationOutput operationOutput = updateSingleAlias(inp, formattedAlias); result.add(operationOutput); } @@ -108,7 +122,4 @@ private List updateLambdaAliases(StageExecution stag public TaskResult onTimeout(@Nonnull StageExecution stage) { return TaskResult.builder(ExecutionStatus.SKIPPED).build(); } - - @Override - public void onCancel(@Nonnull StageExecution stage) {} } diff --git a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaUpdateCodeTask.java b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaUpdateCodeTask.java index e9e3e14354..b08c7d8875 100644 --- a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaUpdateCodeTask.java +++ b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaUpdateCodeTask.java @@ -16,40 +16,41 @@ package com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; import com.netflix.spinnaker.orca.api.pipeline.TaskResult; import com.netflix.spinnaker.orca.api.pipeline.models.ExecutionStatus; import com.netflix.spinnaker.orca.api.pipeline.models.StageExecution; import com.netflix.spinnaker.orca.api.pipeline.models.TaskExecution; -import com.netflix.spinnaker.orca.clouddriver.config.CloudDriverConfigurationProperties; +import com.netflix.spinnaker.orca.clouddriver.KatoService; +import com.netflix.spinnaker.orca.clouddriver.model.OperationContext; +import com.netflix.spinnaker.orca.clouddriver.model.SubmitOperationResult; import com.netflix.spinnaker.orca.clouddriver.pipeline.providers.aws.lambda.LambdaStageConstants; -import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.LambdaCloudDriverResponse; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.input.LambdaUpdateCodeInput; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.output.LambdaCloudOperationOutput; -import com.netflix.spinnaker.orca.clouddriver.utils.LambdaCloudDriverUtils; import com.netflix.spinnaker.orca.pipeline.model.StageContext; import java.util.List; import javax.annotation.Nonnull; import javax.annotation.Nullable; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @Component +@Slf4j public class LambdaUpdateCodeTask implements LambdaStageBaseTask { - private static final Logger logger = LoggerFactory.getLogger(LambdaUpdateCodeTask.class); - private static final String CLOUDDRIVER_UPDATE_CODE_PATH = "/aws/ops/updateLambdaFunctionCode"; - @Autowired CloudDriverConfigurationProperties props; - private String cloudDriverUrl; + private final KatoService katoService; + private final ObjectMapper objectMapper; - @Autowired private LambdaCloudDriverUtils utils; + public LambdaUpdateCodeTask(KatoService katoService, ObjectMapper objectMapper) { + this.katoService = katoService; + this.objectMapper = objectMapper; + } @Nonnull @Override public TaskResult execute(@Nonnull StageExecution stage) { - logger.debug("Executing LambdaUpdateCodeTask..."); - cloudDriverUrl = props.getCloudDriverBaseUrl(); + log.debug("Executing LambdaUpdateCodeTask..."); prepareTask(stage); StageContext stageContext = (StageContext) stage.getContext(); @@ -57,10 +58,11 @@ public TaskResult execute(@Nonnull StageExecution stage) { stageContext.containsKey(LambdaStageConstants.lambaCreatedKey) && (Boolean) stageContext.getOrDefault(LambdaStageConstants.lambaCreatedKey, Boolean.FALSE); - logger.debug("justCreated GetCurrent:" + justCreated); + log.debug("justCreated GetCurrent:" + justCreated); if (justCreated) { return taskComplete(stage); } + LambdaCloudOperationOutput output = updateLambdaCode(stage); addCloudOperationToContext(stage, output, LambdaStageConstants.updateCodeUrlKey); addToTaskContext(stage, LambdaStageConstants.lambaCodeUpdatedKey, Boolean.TRUE); @@ -68,7 +70,7 @@ public TaskResult execute(@Nonnull StageExecution stage) { } private LambdaCloudOperationOutput updateLambdaCode(StageExecution stage) { - LambdaUpdateCodeInput inp = utils.getInput(stage, LambdaUpdateCodeInput.class); + LambdaUpdateCodeInput inp = stage.mapTo(LambdaUpdateCodeInput.class); List taskExecutions = stage.getTasks(); boolean deferPublish = taskExecutions.stream() @@ -78,16 +80,19 @@ private LambdaCloudOperationOutput updateLambdaCode(StageExecution stage) { && t.getStatus().equals(ExecutionStatus.NOT_STARTED)); inp.setPublish(inp.isPublish() && !deferPublish); - logger.debug("Publish flag for UpdateCodeTask is set to " + (inp.isPublish() && !deferPublish)); + log.debug("Publish flag for UpdateCodeTask is set to " + (inp.isPublish() && !deferPublish)); inp.setAppName(stage.getExecution().getApplication()); inp.setCredentials(inp.getAccount()); - String endPoint = cloudDriverUrl + CLOUDDRIVER_UPDATE_CODE_PATH; - String rawString = utils.asString(inp); - LambdaCloudDriverResponse respObj = utils.postToCloudDriver(endPoint, rawString); - String url = cloudDriverUrl + respObj.getResourceUri(); - logger.debug("Posted to cloudDriver for updateLambdaCode: " + url); - return LambdaCloudOperationOutput.builder().resourceId(respObj.getId()).url(url).build(); + + OperationContext context = objectMapper.convertValue(inp, new TypeReference<>() {}); + context.setOperationType("updateLambdaFunctionCode"); + SubmitOperationResult result = katoService.submitOperation(getCloudProvider(), context); + + return LambdaCloudOperationOutput.builder() + .resourceId(result.getId()) + .url(result.getResourceUri()) + .build(); } @Nullable @@ -95,7 +100,4 @@ private LambdaCloudOperationOutput updateLambdaCode(StageExecution stage) { public TaskResult onTimeout(@Nonnull StageExecution stage) { return TaskResult.builder(ExecutionStatus.SKIPPED).build(); } - - @Override - public void onCancel(@Nonnull StageExecution stage) {} } diff --git a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaUpdateConfigurationTask.java b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaUpdateConfigurationTask.java index 054483d4ee..fb6a93b47e 100644 --- a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaUpdateConfigurationTask.java +++ b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaUpdateConfigurationTask.java @@ -16,52 +16,59 @@ package com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; import com.netflix.spinnaker.orca.api.pipeline.TaskResult; import com.netflix.spinnaker.orca.api.pipeline.models.ExecutionStatus; import com.netflix.spinnaker.orca.api.pipeline.models.StageExecution; -import com.netflix.spinnaker.orca.clouddriver.config.CloudDriverConfigurationProperties; +import com.netflix.spinnaker.orca.clouddriver.KatoService; +import com.netflix.spinnaker.orca.clouddriver.model.OperationContext; +import com.netflix.spinnaker.orca.clouddriver.model.SubmitOperationResult; import com.netflix.spinnaker.orca.clouddriver.pipeline.providers.aws.lambda.LambdaStageConstants; -import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.LambdaCloudDriverResponse; +import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.LambdaUtils; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.input.LambdaDeploymentInput; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.output.LambdaCloudOperationOutput; -import com.netflix.spinnaker.orca.clouddriver.utils.LambdaCloudDriverUtils; import java.util.ArrayList; import java.util.List; import javax.annotation.Nonnull; import javax.annotation.Nullable; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @Component +@Slf4j public class LambdaUpdateConfigurationTask implements LambdaStageBaseTask { - private static final Logger logger = LoggerFactory.getLogger(LambdaUpdateConfigurationTask.class); - private static final String CLOUDDRIVER_UPDATE_CONFIG_PATH = - "/aws/ops/updateLambdaFunctionConfiguration"; - @Autowired CloudDriverConfigurationProperties props; - private String cloudDriverUrl; + private final LambdaUtils utils; + private final KatoService katoService; + private final ObjectMapper objectMapper; - @Autowired private LambdaCloudDriverUtils utils; + public LambdaUpdateConfigurationTask( + LambdaUtils utils, KatoService katoService, ObjectMapper objectMapper) { + this.utils = utils; + this.katoService = katoService; + this.objectMapper = objectMapper; + } @Nonnull @Override public TaskResult execute(@Nonnull StageExecution stage) { - logger.debug("Executing LambdaUpdateConfigurationTask..."); - cloudDriverUrl = props.getCloudDriverBaseUrl(); + log.debug("Executing LambdaUpdateConfigurationTask..."); prepareTask(stage); + Boolean justCreated = (Boolean) stage.getContext().getOrDefault(LambdaStageConstants.lambaCreatedKey, Boolean.FALSE); if (justCreated) { return TaskResult.builder(ExecutionStatus.SUCCEEDED).context(stage.getContext()).build(); } + List errors = new ArrayList<>(); - LambdaDeploymentInput ldi = utils.getInput(stage, LambdaDeploymentInput.class); + LambdaDeploymentInput ldi = stage.mapTo(LambdaDeploymentInput.class); if (!utils.validateUpsertLambdaInput(ldi, errors)) { return this.formErrorListTaskResult(stage, errors); } + LambdaCloudOperationOutput output = this.updateLambdaConfig(stage, ldi); addCloudOperationToContext(stage, output, LambdaStageConstants.updateConfigUrlKey); addToTaskContext(stage, LambdaStageConstants.lambaConfigurationUpdatedKey, Boolean.TRUE); @@ -72,12 +79,15 @@ private LambdaCloudOperationOutput updateLambdaConfig( StageExecution stage, LambdaDeploymentInput ldi) { ldi.setAppName(stage.getExecution().getApplication()); ldi.setCredentials(ldi.getAccount()); - String rawString = utils.asString(ldi); - String endPoint = cloudDriverUrl + CLOUDDRIVER_UPDATE_CONFIG_PATH; - LambdaCloudDriverResponse respObj = utils.postToCloudDriver(endPoint, rawString); - String url = cloudDriverUrl + respObj.getResourceUri(); - logger.debug("Posted to cloudDriver for updateLambdaConfig: " + url); - return LambdaCloudOperationOutput.builder().resourceId(respObj.getId()).url(url).build(); + + OperationContext context = objectMapper.convertValue(ldi, new TypeReference<>() {}); + context.setOperationType("updateLambdaFunctionConfiguration"); + SubmitOperationResult result = katoService.submitOperation(getCloudProvider(), context); + + return LambdaCloudOperationOutput.builder() + .resourceId(result.getId()) + .url(result.getResourceUri()) + .build(); } @Nullable @@ -85,7 +95,4 @@ private LambdaCloudOperationOutput updateLambdaConfig( public TaskResult onTimeout(@Nonnull StageExecution stage) { return TaskResult.builder(ExecutionStatus.SKIPPED).build(); } - - @Override - public void onCancel(@Nonnull StageExecution stage) {} } diff --git a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaUpdateEventConfigurationTask.java b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaUpdateEventConfigurationTask.java index 84c854fd02..0d5ea316a1 100644 --- a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaUpdateEventConfigurationTask.java +++ b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaUpdateEventConfigurationTask.java @@ -17,63 +17,62 @@ package com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda; import com.amazonaws.services.lambda.model.EventSourceMappingConfiguration; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; import com.netflix.spinnaker.orca.api.pipeline.TaskResult; import com.netflix.spinnaker.orca.api.pipeline.models.ExecutionStatus; import com.netflix.spinnaker.orca.api.pipeline.models.StageExecution; -import com.netflix.spinnaker.orca.clouddriver.config.CloudDriverConfigurationProperties; +import com.netflix.spinnaker.orca.clouddriver.KatoService; +import com.netflix.spinnaker.orca.clouddriver.model.OperationContext; +import com.netflix.spinnaker.orca.clouddriver.model.SubmitOperationResult; import com.netflix.spinnaker.orca.clouddriver.pipeline.providers.aws.lambda.LambdaStageConstants; +import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.LambdaUtils; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.*; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.input.LambdaDeleteEventTaskInput; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.input.LambdaUpdateEventConfigurationTaskInput; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.output.LambdaCloudOperationOutput; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.output.LambdaUpdateEventConfigurationTaskOutput; -import com.netflix.spinnaker.orca.clouddriver.utils.LambdaCloudDriverUtils; import java.util.*; import java.util.stream.Collectors; import javax.annotation.Nonnull; -import org.apache.commons.lang3.tuple.Pair; +import lombok.extern.slf4j.Slf4j; import org.pf4j.util.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component +@Slf4j public class LambdaUpdateEventConfigurationTask implements LambdaStageBaseTask { - private static final Logger logger = - LoggerFactory.getLogger(LambdaUpdateEventConfigurationTask.class); - private static final String CLOUDDRIVER_UPDATE_EVENT_CONFIGURATION_LAMBDA_PATH = - "/aws/ops/upsertLambdaFunctionEventMapping"; - private static final String CLOUDDRIVER_DELETE_EVENT_CONFIGURATION_LAMBDA_PATH = - "/aws/ops/deleteLambdaFunctionEventMapping"; + + private static final String DEFAULT_STARTING_POSITION = "LATEST"; private static final String DYNAMO_EVENT_PREFIX = "arn:aws:dynamodb:"; private static final String KINESIS_EVENT_PREFIX = "arn:aws:kinesis"; - String cloudDriverUrl; - - @Autowired CloudDriverConfigurationProperties props; + private final LambdaUtils utils; + private final KatoService katoService; + private final ObjectMapper objectMapper; - @Autowired LambdaCloudDriverUtils utils; - - private static final String DEFAULT_STARTING_POSITION = "LATEST"; + public LambdaUpdateEventConfigurationTask( + LambdaUtils utils, KatoService katoService, ObjectMapper objectMapper) { + this.utils = utils; + this.katoService = katoService; + this.objectMapper = objectMapper; + } @Nonnull @Override public TaskResult execute(@Nonnull StageExecution stage) { - logger.debug("Executing LambdaUpdateEventConfigurationTask"); - cloudDriverUrl = props.getCloudDriverBaseUrl(); + log.debug("Executing LambdaUpdateEventConfigurationTask"); LambdaUpdateEventConfigurationTaskInput taskInput = - utils.getInput(stage, LambdaUpdateEventConfigurationTaskInput.class); + stage.mapTo(LambdaUpdateEventConfigurationTaskInput.class); taskInput.setAppName(stage.getExecution().getApplication()); - Boolean justCreated = - (Boolean) stage.getContext().getOrDefault(LambdaStageConstants.lambaCreatedKey, false); - LambdaDefinition lf = utils.retrieveLambdaFromCache(stage, justCreated); + + LambdaDefinition lf = utils.retrieveLambdaFromCache(stage); if (lf == null) { return formErrorTaskResult(stage, "Could not find lambda to update event config for"); } String functionArn = lf.getFunctionArn(); if (StringUtils.isNotNullOrEmpty(taskInput.getAliasName())) { - logger.debug("LambdaUpdateEventConfigurationTask for alias"); + log.debug("LambdaUpdateEventConfigurationTask for alias"); functionArn = String.format("%s:%s", lf.getFunctionArn(), taskInput.getAliasName()); taskInput.setQualifier(taskInput.getAliasName()); } @@ -88,8 +87,7 @@ private TaskResult updateEventsForLambdaFunction( return TaskResult.builder(ExecutionStatus.SUCCEEDED).context(context).build(); } deleteRemovedAndChangedEvents(taskInput, lf, functionArn); - LambdaUpdateEventConfigurationTaskOutput ldso = - updateEventConfiguration(taskInput, lf, functionArn); + LambdaUpdateEventConfigurationTaskOutput ldso = updateEventConfiguration(taskInput); Map context = buildContextOutput(ldso); return TaskResult.builder(ExecutionStatus.SUCCEEDED).context(context).build(); } @@ -97,9 +95,6 @@ private TaskResult updateEventsForLambdaFunction( /** * New configuration has zero events. So find all existing events in the lambda cache and delete * them all. - * - * @param taskInput - * @param lf */ private void deleteAllExistingEvents( LambdaUpdateEventConfigurationTaskInput taskInput, LambdaDefinition lf, String targetArn) { @@ -110,21 +105,14 @@ private void deleteAllExistingEvents( /** * For each eventTriggerArn that already exists at backend: delete from backend if it does not * exist in input - * - * @param taskInput - * @param lf */ - private LambdaUpdateEventConfigurationTaskOutput deleteRemovedAndChangedEvents( + private void deleteRemovedAndChangedEvents( LambdaUpdateEventConfigurationTaskInput taskInput, LambdaDefinition lf, String targetArn) { - LambdaUpdateEventConfigurationTaskOutput ans = - LambdaUpdateEventConfigurationTaskOutput.builder().build(); - ans.setEventOutputs(new ArrayList<>()); List eventArnList = getExistingEvents(lf, targetArn); // Does not deal with change in batch size(s) eventArnList.stream() .filter(x -> !taskInput.getTriggerArns().contains(x)) .forEach(eventArn -> deleteEvent(eventArn, taskInput, lf, targetArn)); - return ans; } List getExistingEvents(LambdaDefinition lf, String targetArn) { @@ -139,23 +127,12 @@ List getExistingEvents(LambdaDefinition lf, String targetArn) { .collect(Collectors.toList()); } - List> getExistingEventsDetails(LambdaDefinition lf) { - List esmList = lf.getEventSourceMappings(); - if (esmList == null) { - return new ArrayList<>(); - } - return esmList.stream() - .filter(x -> StringUtils.isNotNullOrEmpty(x.getEventSourceArn())) - .map(x -> Pair.of(x.getEventSourceArn(), x.getBatchSize())) - .collect(Collectors.toList()); - } - private void deleteEvent( String eventArn, LambdaUpdateEventConfigurationTaskInput ti, LambdaDefinition lgo, String aliasOrFunctionArn) { - logger.debug("To be deleted: " + eventArn); + log.debug("To be deleted: " + eventArn); List esmList = lgo.getEventSourceMappings(); Optional oo = esmList.stream() @@ -186,27 +163,26 @@ private void deleteEvent( } private LambdaUpdateEventConfigurationTaskOutput updateEventConfiguration( - LambdaUpdateEventConfigurationTaskInput taskInput, LambdaDefinition lf, String targetArn) { + LambdaUpdateEventConfigurationTaskInput taskInput) { LambdaUpdateEventConfigurationTaskOutput ans = LambdaUpdateEventConfigurationTaskOutput.builder().build(); - ans.setEventOutputs(new ArrayList<>()); + ans.setEventOutputs(List.of()); taskInput.setCredentials(taskInput.getAccount()); - String endPoint = cloudDriverUrl + CLOUDDRIVER_UPDATE_EVENT_CONFIGURATION_LAMBDA_PATH; taskInput .getTriggerArns() .forEach( curr -> { LambdaEventConfigurationDescription singleEvent = formEventObject(curr, taskInput); - String rawString = utils.asString(singleEvent); - LambdaCloudDriverResponse respObj = utils.postToCloudDriver(endPoint, rawString); - String url = cloudDriverUrl + respObj.getResourceUri(); - logger.debug("Posted to cloudDriver for updateEventConfiguration: " + url); + + OperationContext context = + objectMapper.convertValue(singleEvent, new TypeReference<>() {}); + context.setOperationType("upsertLambdaFunctionEventMapping"); + SubmitOperationResult result = + katoService.submitOperation(getCloudProvider(), context); + LambdaCloudOperationOutput z = - LambdaCloudOperationOutput.builder() - .url(url) - .resourceId(respObj.getResourceUri()) - .build(); + LambdaCloudOperationOutput.builder().resourceId(result.getResourceUri()).build(); ans.getEventOutputs().add(z); }); @@ -289,14 +265,12 @@ private Map formDestinationConfig( return destinationConfig; } - private LambdaCloudOperationOutput deleteLambdaEventConfig(LambdaDeleteEventTaskInput inp) { + private void deleteLambdaEventConfig(LambdaDeleteEventTaskInput inp) { inp.setCredentials(inp.getAccount()); - String endPoint = cloudDriverUrl + CLOUDDRIVER_DELETE_EVENT_CONFIGURATION_LAMBDA_PATH; - String rawString = utils.asString(inp); - LambdaCloudDriverResponse respObj = utils.postToCloudDriver(endPoint, rawString); - String url = cloudDriverUrl + respObj.getResourceUri(); - logger.debug("Posted to cloudDriver for deleteLambdaEventConfig: " + url); - return LambdaCloudOperationOutput.builder().url(url).build(); + + OperationContext context = objectMapper.convertValue(inp, new TypeReference<>() {}); + context.setOperationType("deleteLambdaFunctionEventMapping"); + katoService.submitOperation(getCloudProvider(), context); } /** Fill up with values required for next task */ diff --git a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaVerificationTask.java b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaVerificationTask.java index 85eb4843e1..f58288d80c 100644 --- a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaVerificationTask.java +++ b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaVerificationTask.java @@ -19,39 +19,37 @@ import com.netflix.spinnaker.orca.api.pipeline.TaskResult; import com.netflix.spinnaker.orca.api.pipeline.models.ExecutionStatus; import com.netflix.spinnaker.orca.api.pipeline.models.StageExecution; -import com.netflix.spinnaker.orca.clouddriver.config.CloudDriverConfigurationProperties; import com.netflix.spinnaker.orca.clouddriver.pipeline.providers.aws.lambda.LambdaStageConstants; +import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.LambdaUtils; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.LambdaCloudDriverTaskResults; -import com.netflix.spinnaker.orca.clouddriver.utils.LambdaCloudDriverUtils; -import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import javax.annotation.Nonnull; import javax.annotation.Nullable; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @Component +@Slf4j public class LambdaVerificationTask implements LambdaStageBaseTask { - private static final Logger logger = LoggerFactory.getLogger(LambdaVerificationTask.class); - @Autowired CloudDriverConfigurationProperties props; + private final LambdaUtils utils; - @Autowired private LambdaCloudDriverUtils utils; + public LambdaVerificationTask(LambdaUtils utils) { + this.utils = utils; + } @Nonnull @Override public TaskResult execute(@Nonnull StageExecution stage) { - logger.debug("Executing lambdaVerificationTask..."); + log.debug("Executing lambdaVerificationTask..."); prepareTask(stage); try { return doVerify(stage); } catch (Throwable e) { - logger.error("Exception verifying task", e); + log.error("Exception verifying task", e); logException(stage, e); addExceptionToOutput(stage, e); return formErrorTaskResult(stage, "Exception during task verification"); @@ -74,7 +72,7 @@ private TaskResult doVerify(StageExecution stage) { urlList.addAll((List) stageContext.get(LambdaStageConstants.aliasTaskKey)); List listOfTaskResults = - urlList.stream().map(url -> utils.verifyStatus(url)).collect(Collectors.toList()); + urlList.stream().map(utils::verifyStatus).collect(Collectors.toList()); boolean anyRunning = listOfTaskResults.stream().anyMatch(taskResult -> !taskResult.getStatus().isCompleted()); @@ -128,13 +126,8 @@ public TaskResult onTimeout(@Nonnull StageExecution stage) { return TaskResult.builder(ExecutionStatus.SKIPPED).build(); } - @Override - public void onCancel(@Nonnull StageExecution stage) {} - @Override public Collection aliases() { - List ss = new ArrayList<>(); - ss.add("lambdaVerificationTask"); - return ss; + return List.of("lambdaVerificationTask"); } } diff --git a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaWaitForCacheCodeUpdateTask.java b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaWaitForCacheCodeUpdateTask.java index b69ca4219d..bb86a69fac 100644 --- a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaWaitForCacheCodeUpdateTask.java +++ b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaWaitForCacheCodeUpdateTask.java @@ -18,30 +18,28 @@ import com.netflix.spinnaker.orca.api.pipeline.TaskResult; import com.netflix.spinnaker.orca.api.pipeline.models.StageExecution; -import com.netflix.spinnaker.orca.clouddriver.config.CloudDriverConfigurationProperties; import com.netflix.spinnaker.orca.clouddriver.pipeline.providers.aws.lambda.LambdaStageConstants; +import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.LambdaUtils; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.LambdaDefinition; -import com.netflix.spinnaker.orca.clouddriver.utils.LambdaCloudDriverUtils; import java.util.Map; import javax.annotation.Nonnull; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @Component +@Slf4j public class LambdaWaitForCacheCodeUpdateTask implements LambdaStageBaseTask { - private static final Logger logger = - LoggerFactory.getLogger(LambdaWaitForCacheCodeUpdateTask.class); - @Autowired CloudDriverConfigurationProperties props; + private final LambdaUtils utils; - @Autowired private LambdaCloudDriverUtils utils; + public LambdaWaitForCacheCodeUpdateTask(LambdaUtils utils) { + this.utils = utils; + } @Nonnull @Override public TaskResult execute(@Nonnull StageExecution stage) { - logger.debug("Executing LambdaWaitForCacheCodeUpdateTask..."); + log.debug("Executing LambdaWaitForCacheCodeUpdateTask..."); return waitForCacheUpdate(stage); } @@ -53,7 +51,7 @@ private TaskResult waitForCacheUpdate(@Nonnull StageExecution stage) { String codeUpdateUrl = (String) stage.getContext().get(LambdaStageConstants.updateCodeUrlKey); String version = utils.getPublishedVersion(codeUpdateUrl); for (int i = 0; i < 10; i++) { - LambdaDefinition lf = utils.retrieveLambdaFromCache(stage, true); + LambdaDefinition lf = utils.retrieveLambdaFromCache(stage); if (lf != null) { Map revisions = lf.getRevisions(); if (revisions.containsValue(version)) { diff --git a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaWaitForCachePublishTask.java b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaWaitForCachePublishTask.java index dcf70712de..b700f0018f 100644 --- a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaWaitForCachePublishTask.java +++ b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaWaitForCachePublishTask.java @@ -18,30 +18,29 @@ import com.netflix.spinnaker.orca.api.pipeline.TaskResult; import com.netflix.spinnaker.orca.api.pipeline.models.StageExecution; -import com.netflix.spinnaker.orca.clouddriver.config.CloudDriverConfigurationProperties; import com.netflix.spinnaker.orca.clouddriver.pipeline.providers.aws.lambda.LambdaStageConstants; +import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.LambdaUtils; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.LambdaDefinition; -import com.netflix.spinnaker.orca.clouddriver.utils.LambdaCloudDriverUtils; import java.time.Duration; import java.util.Map; import javax.annotation.Nonnull; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @Component +@Slf4j public class LambdaWaitForCachePublishTask implements LambdaStageBaseTask { - private static final Logger logger = LoggerFactory.getLogger(LambdaWaitForCachePublishTask.class); - @Autowired CloudDriverConfigurationProperties props; + private final LambdaUtils utils; - @Autowired private LambdaCloudDriverUtils utils; + public LambdaWaitForCachePublishTask(LambdaUtils utils) { + this.utils = utils; + } @Nonnull @Override public TaskResult execute(@Nonnull StageExecution stage) { - logger.debug("Executing LambdaWaitForCachePublishTask..."); + log.debug("Executing LambdaWaitForCachePublishTask..."); return waitForCacheUpdate(stage); } @@ -51,7 +50,7 @@ private TaskResult waitForCacheUpdate(@Nonnull StageExecution stage) { (String) stage.getContext().get(LambdaStageConstants.publishVersionUrlKey); String version = utils.getPublishedVersion(publishUrl); for (int i = 0; i < 10; i++) { - LambdaDefinition lf = utils.retrieveLambdaFromCache(stage, true); + LambdaDefinition lf = utils.retrieveLambdaFromCache(stage); if (lf != null) { Map revisions = lf.getRevisions(); if (revisions.containsValue(version)) { diff --git a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaWaitToStabilizeTask.java b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaWaitToStabilizeTask.java index 0dafb0efe5..7e28a1c16e 100644 --- a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaWaitToStabilizeTask.java +++ b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaWaitToStabilizeTask.java @@ -18,32 +18,31 @@ import com.netflix.spinnaker.orca.api.pipeline.TaskResult; import com.netflix.spinnaker.orca.api.pipeline.models.StageExecution; -import com.netflix.spinnaker.orca.clouddriver.config.CloudDriverConfigurationProperties; +import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.LambdaUtils; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.LambdaDefinition; -import com.netflix.spinnaker.orca.clouddriver.utils.LambdaCloudDriverUtils; import java.time.Duration; import javax.annotation.Nonnull; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @Component +@Slf4j public class LambdaWaitToStabilizeTask implements LambdaStageBaseTask { - private static final Logger logger = LoggerFactory.getLogger(LambdaWaitToStabilizeTask.class); final String PENDING_STATE = "Pending"; final String ACTIVE_STATE = "Active"; final String FUNCTION_CREATING = "Creating"; - @Autowired CloudDriverConfigurationProperties props; + private final LambdaUtils utils; - @Autowired private LambdaCloudDriverUtils utils; + public LambdaWaitToStabilizeTask(LambdaUtils utils) { + this.utils = utils; + } @Nonnull @Override public TaskResult execute(@Nonnull StageExecution stage) { - logger.debug("Executing LambdaWaitToStabilizeTask..."); + log.debug("Executing LambdaWaitToStabilizeTask..."); return waitForStableState(stage); } @@ -51,9 +50,9 @@ private TaskResult waitForStableState(@Nonnull StageExecution stage) { LambdaDefinition lf; int counter = 0; while (true) { - lf = utils.retrieveLambdaFromCache(stage, true); + lf = utils.retrieveLambdaFromCache(stage); if (lf != null && lf.getState() != null) { - logger.info( + log.info( String.format( "%s lambda state from the cache %s", lf.getFunctionName(), lf.getState())); if (lf.getState().equals(PENDING_STATE) @@ -63,11 +62,11 @@ private TaskResult waitForStableState(@Nonnull StageExecution stage) { continue; } if (lf.getState().equals(ACTIVE_STATE)) { - logger.info(lf.getFunctionName() + " is active"); + log.info(lf.getFunctionName() + " is active"); return taskComplete(stage); } } else { - logger.info( + log.info( "waiting for up to 10 minutes for it to show up in the cache... requires a full cache refresh cycle"); utils.await(Duration.ofMinutes(1).toMillis()); if (++counter > 10) break; diff --git a/orca-clouddriver/src/test/groovy/com/netflix/spinnaker/orca/clouddriver/MortServiceSpec.groovy b/orca-clouddriver/src/test/groovy/com/netflix/spinnaker/orca/clouddriver/MortServiceSpec.groovy index faaaf05d09..e44acc77f1 100644 --- a/orca-clouddriver/src/test/groovy/com/netflix/spinnaker/orca/clouddriver/MortServiceSpec.groovy +++ b/orca-clouddriver/src/test/groovy/com/netflix/spinnaker/orca/clouddriver/MortServiceSpec.groovy @@ -17,12 +17,11 @@ package com.netflix.spinnaker.orca.clouddriver import com.fasterxml.jackson.databind.ObjectMapper +import com.netflix.spinnaker.orca.TestUtils import retrofit.RestAdapter import retrofit.client.Client import retrofit.client.Response -import retrofit.converter.Converter import retrofit.converter.JacksonConverter -import retrofit.mime.TypedInput import spock.lang.Specification import spock.lang.Unroll @@ -206,7 +205,7 @@ class MortServiceSpec extends Specification { 200, "OK", [], - new MockTypedInput(converter, [ + new TestUtils.MockTypedInput(converter, [ accountName: "account", description: [ "account": null, @@ -243,7 +242,7 @@ class MortServiceSpec extends Specification { 200, "OK", [], - new MockTypedInput(converter, [ + new TestUtils.MockTypedInput(converter, [ accountName: "account", description: "simple description", name: "sg1", @@ -253,44 +252,4 @@ class MortServiceSpec extends Specification { ) } - - static class MockTypedInput implements TypedInput { - private final Converter converter - private final Object body - - private byte[] bytes - - MockTypedInput(Converter converter, Object body) { - this.converter = converter - this.body = body - } - - @Override String mimeType() { - return "application/unknown" - } - - @Override long length() { - try { - initBytes() - } catch (IOException e) { - throw new RuntimeException(e) - } - return bytes.length - } - - @Override InputStream "in"() throws IOException { - initBytes() - return new ByteArrayInputStream(bytes) - } - - private synchronized void initBytes() throws IOException { - if (bytes == null) { - ByteArrayOutputStream out = new ByteArrayOutputStream() - converter.toBody(body).writeTo(out) - bytes = out.toByteArray() - } - } - } - - } diff --git a/orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/TestUtils.java b/orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/TestUtils.java index 8d8ba9cfcf..cf058b67dc 100644 --- a/orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/TestUtils.java +++ b/orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/TestUtils.java @@ -18,10 +18,10 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.io.Resources; -import java.io.IOException; -import java.io.InputStream; -import java.io.UncheckedIOException; +import java.io.*; import java.nio.charset.StandardCharsets; +import retrofit.converter.Converter; +import retrofit.mime.TypedInput; public class TestUtils { @@ -44,4 +44,45 @@ public static T getResource(ObjectMapper objectMapper, String name, Class public static InputStream getResourceAsStream(String name) { return TestUtils.class.getResourceAsStream(name); } + + public static class MockTypedInput implements TypedInput { + private final Converter converter; + private final Object body; + + private byte[] bytes; + + public MockTypedInput(Converter converter, Object body) { + this.converter = converter; + this.body = body; + } + + @Override + public String mimeType() { + return "application/unknown"; + } + + @Override + public long length() { + try { + initBytes(); + } catch (IOException e) { + throw new RuntimeException(e); + } + return bytes.length; + } + + @Override + public InputStream in() throws IOException { + initBytes(); + return new ByteArrayInputStream(bytes); + } + + private synchronized void initBytes() throws IOException { + if (bytes == null) { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + converter.toBody(body).writeTo(out); + bytes = out.toByteArray(); + } + } + } } diff --git a/orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/LambdaUtilsTest.java b/orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/LambdaUtilsTest.java new file mode 100644 index 0000000000..7a08bb81ba --- /dev/null +++ b/orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/LambdaUtilsTest.java @@ -0,0 +1,416 @@ +/* + * Copyright 2021 Armory, LLC + * + * 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.aws; + +import static com.netflix.spinnaker.orca.TestUtils.getResource; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.collect.ImmutableMap; +import com.netflix.spinnaker.orca.api.pipeline.models.ExecutionType; +import com.netflix.spinnaker.orca.api.pipeline.models.PipelineExecution; +import com.netflix.spinnaker.orca.api.pipeline.models.StageExecution; +import com.netflix.spinnaker.orca.clouddriver.KatoService; +import com.netflix.spinnaker.orca.clouddriver.OortService; +import com.netflix.spinnaker.orca.clouddriver.model.Task; +import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.LambdaCloudDriverInvokeOperationResults; +import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.LambdaCloudDriverTaskResults; +import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.LambdaDefinition; +import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.input.LambdaDeploymentInput; +import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.input.LambdaGetInput; +import com.netflix.spinnaker.orca.pipeline.model.PipelineExecutionImpl; +import com.netflix.spinnaker.orca.pipeline.model.StageExecutionImpl; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.*; +import org.springframework.http.HttpStatus; +import org.springframework.web.client.HttpServerErrorException; + +public class LambdaUtilsTest { + + @InjectMocks private LambdaUtils lambdaUtils; + + @Mock private KatoService katoService; + + @Mock private OortService oortService; + + private final ObjectMapper objectMapper = new ObjectMapper(); + + @BeforeEach + void init() { + MockitoAnnotations.openMocks(this); + } + + @Test + public void validateUpsertLambdaInput_EnableLambdaAtEdgeIsFalse_True() { + LambdaDeploymentInput ldi = + LambdaDeploymentInput.builder() + .account("account-test") + .region("us-west-2") + .functionName("function-test") + .runtime("runtime") + .s3bucket("s3-bucket") + .s3key("abcdefg123456") + .handler("handler") + .role("arn:aws:iam::123456789012:role/LambdaAccess") + .enableLambdaAtEdge(false) + .build(); + assertTrue(lambdaUtils.validateUpsertLambdaInput(ldi, new ArrayList<>())); + } + + @Test + public void validateLambdaEdgeInput_EnvVariablesIsNotEmpty_False() { + HashMap envVariables = new HashMap<>(); + envVariables.put("ENV_TEST_PORT", "8888"); + LambdaDeploymentInput ldi = + LambdaDeploymentInput.builder() + .envVariables(envVariables) + .region("us-east-1") + .memorySize(128) + .subnetIds(new ArrayList<>()) + .securityGroupIds(new ArrayList<>()) + .build(); + assertFalse(lambdaUtils.validateLambdaEdgeInput(ldi, new ArrayList<>())); + } + + @Test + public void validateLambdaEdgeInput_TimeoutGreaterThan5_False() { + LambdaDeploymentInput ldi = + LambdaDeploymentInput.builder() + .envVariables(new HashMap<>()) + .timeout(10) + .memorySize(128) + .subnetIds(new ArrayList<>()) + .securityGroupIds(new ArrayList<>()) + .region("us-east-1") + .build(); + assertFalse(lambdaUtils.validateLambdaEdgeInput(ldi, new ArrayList<>())); + } + + @Test + public void validateLambdaEdgeInput_MemorySizeGreaterThan128_False() { + LambdaDeploymentInput ldi = + LambdaDeploymentInput.builder() + .envVariables(new HashMap<>()) + .timeout(5) + .region("us-east-1") + .memorySize(256) + .subnetIds(new ArrayList<>()) + .securityGroupIds(new ArrayList<>()) + .build(); + assertFalse(lambdaUtils.validateLambdaEdgeInput(ldi, new ArrayList<>())); + } + + @Test + public void validateLambdaEdgeInput_RegionIsNotUsEast1_False() { + LambdaDeploymentInput ldi = + LambdaDeploymentInput.builder() + .envVariables(new HashMap<>()) + .timeout(5) + .region("us-west-2") + .memorySize(128) + .subnetIds(new ArrayList<>()) + .securityGroupIds(new ArrayList<>()) + .build(); + assertFalse(lambdaUtils.validateLambdaEdgeInput(ldi, new ArrayList<>())); + } + + @Test + public void validateLambdaEdgeInput_VpcIdIsNotNull_False() { + LambdaDeploymentInput ldi = + LambdaDeploymentInput.builder() + .envVariables(new HashMap<>()) + .timeout(5) + .region("us-east-1") + .memorySize(128) + .subnetIds(new ArrayList<>()) + .securityGroupIds(new ArrayList<>()) + .vpcId("vpc-2f09a348") + .build(); + assertFalse(lambdaUtils.validateLambdaEdgeInput(ldi, new ArrayList<>())); + } + + @Test + public void validateLambdaEdgeInput_HaveSubNetIds_False() { + LambdaDeploymentInput ldi = + LambdaDeploymentInput.builder() + .envVariables(new HashMap<>()) + .timeout(5) + .region("us-east-1") + .memorySize(128) + .subnetIds(Stream.of("subnet-b46032ec").collect(Collectors.toList())) + .securityGroupIds(new ArrayList<>()) + .build(); + assertFalse(lambdaUtils.validateLambdaEdgeInput(ldi, new ArrayList<>())); + } + + @Test + public void validateLambdaEdgeInput_HaveSecurityGroups_False() { + LambdaDeploymentInput ldi = + LambdaDeploymentInput.builder() + .envVariables(new HashMap<>()) + .timeout(5) + .region("us-east-1") + .memorySize(128) + .subnetIds(new ArrayList<>()) + .securityGroupIds(Stream.of("sg-b46032ec").collect(Collectors.toList())) + .build(); + assertFalse(lambdaUtils.validateLambdaEdgeInput(ldi, new ArrayList<>())); + } + + @Test + public void getSortedRevisions_SortVersion_321() { + Map revisions = new HashMap<>(); + revisions.put("first", "1"); + revisions.put("second", "2"); + revisions.put("third", "3"); + List sortedList = Stream.of("3", "2", "1").collect(Collectors.toList()); + LambdaDefinition lambdaDefinition = LambdaDefinition.builder().revisions(revisions).build(); + assertEquals(sortedList, lambdaUtils.getSortedRevisions(lambdaDefinition)); + } + + @Test + public void getCanonicalVersion_NoRevisions_NoPublishedVersionsExist() { + Map revisions = new HashMap<>(); + LambdaDefinition lambdaDefinition = LambdaDefinition.builder().revisions(revisions).build(); + assertNull(lambdaUtils.getCanonicalVersion(lambdaDefinition, "", "", 1)); + } + + @Test + public void getCanonicalVersion_ProvidedRevision_PROVIDED() { + Map revisions = new HashMap<>(); + revisions.put("first", "1"); + LambdaDefinition lambdaDefinition = LambdaDefinition.builder().revisions(revisions).build(); + assertEquals("3", lambdaUtils.getCanonicalVersion(lambdaDefinition, "$PROVIDED", "3", 0)); + } + + @Test + public void getCanonicalVersion_LatestRevision_GetLatestVersion() { + Map revisions = new HashMap<>(); + revisions.put("first", "1"); + revisions.put("third", "3"); + revisions.put("second", "2"); + LambdaDefinition lambdaDefinition = LambdaDefinition.builder().revisions(revisions).build(); + assertEquals("3", lambdaUtils.getCanonicalVersion(lambdaDefinition, "$LATEST", "5", 0)); + } + + @Test + public void getCanonicalVersion_OldestRevision_GetOldestVersion() { + Map revisions = new HashMap<>(); + revisions.put("first", "5"); + revisions.put("third", "1"); + revisions.put("second", "7"); + LambdaDefinition lambdaDefinition = LambdaDefinition.builder().revisions(revisions).build(); + assertEquals("1", lambdaUtils.getCanonicalVersion(lambdaDefinition, "$OLDEST", "5", 0)); + } + + @Test + public void getCanonicalVersion_PreviousRevision_GetPreviousVersion() { + Map revisions = new HashMap<>(); + revisions.put("first", "5"); + revisions.put("third", "1"); + revisions.put("second", "7"); + LambdaDefinition lambdaDefinition = LambdaDefinition.builder().revisions(revisions).build(); + assertEquals("5", lambdaUtils.getCanonicalVersion(lambdaDefinition, "$PREVIOUS", "5", 0)); + } + + @Test + public void getCanonicalVersion_MovingRevision_GetMovingVersion() { + Map revisions = new HashMap<>(); + revisions.put("first", "5"); + revisions.put("third", "1"); + revisions.put("second", "7"); + revisions.put("other", "8"); + LambdaDefinition lambdaDefinition = LambdaDefinition.builder().revisions(revisions).build(); + assertEquals("5,1", lambdaUtils.getCanonicalVersion(lambdaDefinition, "$MOVING", "5", 2)); + } + + @Test + public void getCanonicalVersion_InvalidInputVersion_Null() { + Map revisions = new HashMap<>(); + revisions.put("first", "5"); + LambdaDefinition lambdaDefinition = LambdaDefinition.builder().revisions(revisions).build(); + assertNull(lambdaUtils.getCanonicalVersion(lambdaDefinition, "$FAKE_INOUT_VERSION", "5", 2)); + } + + @Test + public void getCanonicalVersion_NoRevisions_Null() { + LambdaDefinition lambdaDefinition = + LambdaDefinition.builder().revisions(new HashMap<>()).build(); + assertNull(lambdaUtils.getCanonicalVersion(lambdaDefinition, "$PREVIOUS", "5", 2)); + } + + @Test + public void retrieveLambdaFromCache_ShouldGetLambdaGetInput_NotNull() { + List definitions = + List.of( + getResource( + objectMapper, + "clouddriver/tasks/providers/aws/lambda/functions.json", + LambdaDefinition[].class)); + Mockito.when(oortService.getFunction("account1", "us-west-2", "app-test-function-test")) + .thenReturn(definitions); + + LambdaGetInput lambdaGetInput = + LambdaGetInput.builder() + .region("us-west-2") + .account("account1") + .functionName("function-test") + .appName("app-test") + .build(); + + StageExecution execution = new StageExecutionImpl(); + execution.setExecution(new PipelineExecutionImpl(ExecutionType.PIPELINE, "app-test")); + execution.setContext(inputToMap(lambdaGetInput)); + + assertNotNull(lambdaUtils.retrieveLambdaFromCache(execution)); + } + + @Test + public void retrieveLambdaFromCache_ShouldNotGetLambdaGetInput_Null() { + Mockito.when(oortService.getFunction("account1", "us-west-2", "app-test-function-test")) + .thenReturn(List.of()); + + LambdaGetInput lambdaGetInput = + LambdaGetInput.builder() + .region("us-west-2") + .account("account2") + .functionName("function-test") + .appName("app-test") + .build(); + + StageExecution execution = new StageExecutionImpl(); + execution.setExecution(new PipelineExecutionImpl(ExecutionType.PIPELINE, "app-test")); + execution.setContext(inputToMap(lambdaGetInput)); + + assertNull(lambdaUtils.retrieveLambdaFromCache(execution)); + } + + @Test + public void getLambdaInvokeResults_ShouldGetLambdaCloudDriverInvokeOperationResults_NotNull() { + Task task = + getResource( + objectMapper, + "clouddriver/tasks/providers/aws/lambda/kato-status-success.json", + Task.class); + Mockito.when(katoService.lookupTaskWithUri(any())).thenReturn(task); + + LambdaCloudDriverInvokeOperationResults results = lambdaUtils.getLambdaInvokeResults("/uri"); + assertNotNull(results); + assertEquals(200, results.getStatusCode()); + } + + @Test + public void getPublishedVersion_getVersion_1() { + Task task = + getResource( + objectMapper, + "clouddriver/tasks/providers/aws/lambda/kato-published-version.json", + Task.class); + Mockito.when(katoService.lookupTaskWithUri(any())).thenReturn(task); + + String publishedVersion = lambdaUtils.getPublishedVersion("/uri"); + assertNotNull(publishedVersion); + assertEquals("1", publishedVersion); + } + + @Test + public void getPublishedVersion_getLatest_$LATEST() { + Task task = + getResource( + objectMapper, + "clouddriver/tasks/providers/aws/lambda/kato-published-version-empty.json", + Task.class); + Mockito.when(katoService.lookupTaskWithUri(any())).thenReturn(task); + + String publishedVersion = lambdaUtils.getPublishedVersion("/uri"); + assertNotNull(publishedVersion); + assertEquals("$LATEST", publishedVersion); + } + + @Test + public void getPublishedVersion_ShouldGetLatestIfNoVersionIsSpecified_$LATEST() { + Mockito.when(katoService.lookupTaskWithUri(any())) + .thenThrow(new HttpServerErrorException(HttpStatus.BAD_REQUEST)); + + String publishedVersion = lambdaUtils.getPublishedVersion("/uri"); + assertNotNull(publishedVersion); + assertEquals("$LATEST", publishedVersion); + } + + @Test + public void verifyStatus_getTheStatus_ShouldNotBeNull() { + Task task = + getResource( + objectMapper, + "clouddriver/tasks/providers/aws/lambda/kato-status-success.json", + Task.class); + Mockito.when(katoService.lookupTaskWithUri(any())).thenReturn(task); + + LambdaCloudDriverTaskResults lambdaCloudDriverTaskResults = lambdaUtils.verifyStatus("/uri"); + assertNotNull(lambdaCloudDriverTaskResults); + } + + @Test + public void retrieveLambdaFromCache_ShouldNotBeNull() { + List definitions = + List.of( + getResource( + objectMapper, + "clouddriver/tasks/providers/aws/lambda/functions.json", + LambdaDefinition[].class)); + Mockito.when(oortService.getFunction("account1", "us-west-2", "lambdaApp-function-test")) + .thenReturn(definitions); + + StageExecution stageExecutionMock = Mockito.mock(StageExecution.class); + Map lambdaGetInput = + ImmutableMap.of( + "region", "us-west-2", + "account", "account1", + "functionName", "function-test"); + Mockito.when(stageExecutionMock.getContext()).thenReturn(lambdaGetInput); + + PipelineExecution pipelineExecutionMock = Mockito.mock(PipelineExecution.class); + Mockito.when(pipelineExecutionMock.getApplication()).thenReturn("lambdaApp"); + Mockito.when(stageExecutionMock.getExecution()).thenReturn(pipelineExecutionMock); + + LambdaGetInput lgi = + LambdaGetInput.builder() + .region("us-west-2") + .account("account1") + .functionName("function-test") + .build(); + Mockito.when(stageExecutionMock.mapTo(any())).thenReturn(lgi); + + LambdaDefinition lambdaDefinition = lambdaUtils.retrieveLambdaFromCache(stageExecutionMock); + + assertNotNull(lambdaDefinition); + assertEquals("account1", lambdaDefinition.getAccount()); + } + + private Map inputToMap(T input) { + return objectMapper.convertValue(input, new TypeReference<>() {}); + } +} diff --git a/orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaCacheRefreshTaskTest.java b/orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaCacheRefreshTaskTest.java index f9a9dfee08..880472e506 100644 --- a/orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaCacheRefreshTaskTest.java +++ b/orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaCacheRefreshTaskTest.java @@ -17,130 +17,113 @@ package com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; -import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.client.ResponseDefinitionBuilder; -import com.github.tomakehurst.wiremock.client.WireMock; +import com.netflix.spinnaker.orca.TestUtils; import com.netflix.spinnaker.orca.api.pipeline.models.ExecutionStatus; import com.netflix.spinnaker.orca.api.pipeline.models.PipelineExecution; import com.netflix.spinnaker.orca.api.pipeline.models.StageExecution; -import com.netflix.spinnaker.orca.clouddriver.config.CloudDriverConfigurationProperties; -import com.netflix.spinnaker.orca.clouddriver.config.LambdaConfigurationProperties; +import com.netflix.spinnaker.orca.clouddriver.CloudDriverCacheService; +import com.netflix.spinnaker.orca.clouddriver.CloudDriverCacheStatusService; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.input.LambdaCacheRefreshInput; -import com.netflix.spinnaker.orca.clouddriver.utils.LambdaCloudDriverUtils; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import okhttp3.Headers; +import java.util.*; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; -import ru.lanwen.wiremock.ext.WiremockResolver; -import ru.lanwen.wiremock.ext.WiremockUriResolver; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import retrofit.client.Header; +import retrofit.client.Response; +import retrofit.converter.Converter; +import retrofit.converter.JacksonConverter; +import retrofit.mime.TypedInput; -@ExtendWith({WiremockResolver.class, WiremockUriResolver.class}) public class LambdaCacheRefreshTaskTest { - WireMockServer wireMockServer; - @InjectMocks private LambdaCacheRefreshTask lambdaCacheRefreshTask; - @Mock private CloudDriverConfigurationProperties propsMock; + @Mock private CloudDriverCacheService cloudDriverCacheService; + + @Mock private CloudDriverCacheStatusService cloudDriverCacheStatusService; @Mock private StageExecution stageExecution; @Mock private PipelineExecution pipelineExecution; - @Mock private LambdaCloudDriverUtils lambdaCloudDriverUtilsMock; + @Mock private ObjectMapper objectMapper; - @Mock private LambdaConfigurationProperties config; + private final Converter converter = new JacksonConverter(objectMapper); + private final List
responseHeaders = + List.of(new Header(HttpHeaders.CONTENT_TYPE, "application/json")); @BeforeEach - void init( - @WiremockResolver.Wiremock WireMockServer wireMockServer, - @WiremockUriResolver.WiremockUri String uri) { - this.wireMockServer = wireMockServer; - MockitoAnnotations.initMocks(this); - Mockito.when(propsMock.getCloudDriverBaseUrl()).thenReturn(uri); + void init() { + MockitoAnnotations.openMocks(this); + pipelineExecution.setApplication("lambdaApp"); Mockito.when(stageExecution.getExecution()).thenReturn(pipelineExecution); + Mockito.when(stageExecution.getContext()).thenReturn(new HashMap<>()); - LambdaCacheRefreshInput inp = LambdaCacheRefreshInput.builder().account("account").build(); + // would rather just call the real method here, but StageExecution ends up being + // an abstract class, so forced to mock + LambdaCacheRefreshInput input = LambdaCacheRefreshInput.builder().appName("lambdaApp").build(); + Mockito.when(stageExecution.mapTo(any())).thenReturn(input); - Mockito.when(stageExecution.getContext()).thenReturn(new HashMap<>()); - Mockito.when(lambdaCloudDriverUtilsMock.getInput(Mockito.any(), Mockito.any())).thenReturn(inp); - Mockito.when(lambdaCloudDriverUtilsMock.asString(Mockito.any())) - .thenReturn("LambdaCacheRefreshInput"); - Mockito.when(lambdaCloudDriverUtilsMock.buildHeaders()) - .thenReturn(Headers.of("Content-Disposition", "form-data; name=\"fs_exp\"")); - - String responseDefinitionBuilderJson = - "{\"cachedIdentifiersByType\":{\"onDemand\":[\"123456789\"]}}"; - ResponseDefinitionBuilder mockResponse = - new ResponseDefinitionBuilder().withStatus(202).withBody(responseDefinitionBuilderJson); - - this.wireMockServer.stubFor(WireMock.post("/cache/aws/function").willReturn(mockResponse)); + TypedInput mockTypedInput = new TestUtils.MockTypedInput(converter, Map.of()); + Response response = + new Response("", HttpStatus.OK.value(), "", responseHeaders, mockTypedInput); + Mockito.when(cloudDriverCacheService.forceCacheUpdate(any(), any(), any())) + .thenReturn(response); } @Test public void execute_ShouldForceCacheRefreshAndGet200Code_SUCCEDED() { - ResponseDefinitionBuilder mockResponse = - new ResponseDefinitionBuilder().withStatus(200).withBody("Success"); + Map map = Map.of(); + Mockito.when(cloudDriverCacheStatusService.pendingForceCacheUpdatesById(any(), any(), any())) + .thenReturn(List.of(map)); - wireMockServer.stubFor(WireMock.post("/cache/aws/function").willReturn(mockResponse)); assertEquals( ExecutionStatus.SUCCEEDED, lambdaCacheRefreshTask.execute(stageExecution).getStatus()); } @Test - public void execute_ShouldWaitForCacheToComplete_CachingShouldBeCompleted_SUCCEEDED() - throws JsonProcessingException { - Map map = new HashMap<>(); - map.put("processedCount", 1); - // increase 15 seconds - map.put("cacheTime", System.currentTimeMillis() + 15 * 1000); - String getFromCloudDriverJson = new ObjectMapper().writeValueAsString(List.of(map)); - Mockito.when(lambdaCloudDriverUtilsMock.getFromCloudDriver(Mockito.any())) - .thenReturn(getFromCloudDriverJson); + public void execute_ShouldWaitForCacheToComplete_CachingShouldBeCompleted_SUCCEEDED() { + Map map = + Map.of("processedCount", 1, "cacheTime", System.currentTimeMillis() + 15 * 1000); + Mockito.when(cloudDriverCacheStatusService.pendingForceCacheUpdatesById(any(), any(), any())) + .thenReturn(List.of(map)); + assertEquals( ExecutionStatus.SUCCEEDED, lambdaCacheRefreshTask.execute(stageExecution).getStatus()); } @Test public void - forceCacheRefresh_waitForCacheToComplete_NotFoundAndThenCachingShouldBeCompleted_SUCCEEDED() - throws JsonProcessingException { - Map mapSecondCall = new HashMap<>(); - mapSecondCall.put("processedCount", 1); - // increase 15 seconds - mapSecondCall.put("cacheTime", System.currentTimeMillis() + 15 * 1000); - String secondCallJson = new ObjectMapper().writeValueAsString(List.of(mapSecondCall)); - - Mockito.when(lambdaCloudDriverUtilsMock.getFromCloudDriver(Mockito.any())) - .thenReturn("[]") - .thenReturn(secondCallJson); + forceCacheRefresh_waitForCacheToComplete_NotFoundAndThenCachingShouldBeCompleted_SUCCEEDED() { + Map mapSecondCall = + Map.of("processedCount", 1, "cacheTime", System.currentTimeMillis() + 15 * 1000); + Mockito.when(cloudDriverCacheStatusService.pendingForceCacheUpdatesById(any(), any(), any())) + .thenReturn(List.of()) + .thenReturn(List.of(mapSecondCall)); + assertEquals( ExecutionStatus.SUCCEEDED, lambdaCacheRefreshTask.execute(stageExecution).getStatus()); } @Test public void - forceCacheRefresh_waitForCacheToComplete_ShouldRetryAndThenCachingShouldBeCompleted_SUCCEEDED() - throws JsonProcessingException { - Map mapSecondCall = new HashMap<>(); - mapSecondCall.put("processedCount", 1); - mapSecondCall.put("cacheTime", System.currentTimeMillis() + 15 * 1000); - String secondCallJson = new ObjectMapper().writeValueAsString(List.of(mapSecondCall)); - - Mockito.when(lambdaCloudDriverUtilsMock.getFromCloudDriver(Mockito.any())) - .thenReturn("[{\"processedCount\":0}]") - .thenReturn(secondCallJson); + forceCacheRefresh_waitForCacheToComplete_ShouldRetryAndThenCachingShouldBeCompleted_SUCCEEDED() { + Map mapFirstCall = Map.of("processedCount", 0); + Map mapSecondCall = + Map.of("processedCount", 1, "cacheTime", System.currentTimeMillis() + 15 * 1000); + Mockito.when(cloudDriverCacheStatusService.pendingForceCacheUpdatesById(any(), any(), any())) + .thenReturn(List.of(mapFirstCall)) + .thenReturn(List.of(mapSecondCall)); + assertEquals( ExecutionStatus.SUCCEEDED, lambdaCacheRefreshTask.execute(stageExecution).getStatus()); } diff --git a/orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaCreateTaskTest.java b/orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaCreateTaskTest.java index 0aea032068..f6a9612ea8 100644 --- a/orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaCreateTaskTest.java +++ b/orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaCreateTaskTest.java @@ -17,98 +17,93 @@ package com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; -import com.github.tomakehurst.wiremock.WireMockServer; +import com.fasterxml.jackson.databind.ObjectMapper; import com.netflix.spinnaker.orca.api.pipeline.models.ExecutionStatus; import com.netflix.spinnaker.orca.api.pipeline.models.PipelineExecution; import com.netflix.spinnaker.orca.api.pipeline.models.StageExecution; -import com.netflix.spinnaker.orca.clouddriver.config.CloudDriverConfigurationProperties; -import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.LambdaCloudDriverResponse; +import com.netflix.spinnaker.orca.clouddriver.KatoService; +import com.netflix.spinnaker.orca.clouddriver.model.SubmitOperationResult; +import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.LambdaUtils; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.LambdaDefinition; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.input.LambdaDeploymentInput; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.input.LambdaGetInput; -import com.netflix.spinnaker.orca.clouddriver.utils.LambdaCloudDriverUtils; import java.util.HashMap; import java.util.Map; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.MockitoAnnotations; -import ru.lanwen.wiremock.ext.WiremockResolver; -import ru.lanwen.wiremock.ext.WiremockUriResolver; - -@ExtendWith({WiremockResolver.class, WiremockUriResolver.class}) -public class LambdaCreateTaskTest { +import org.mockito.*; - WireMockServer wireMockServer; +public class LambdaCreateTaskTest { @InjectMocks private LambdaCreateTask lambdaCreateTask; - @Mock private CloudDriverConfigurationProperties propsMock; + @Mock private LambdaUtils lambdaUtils; - @Mock private LambdaCloudDriverUtils lambdaCloudDriverUtilsMock; + @Mock private KatoService katoService; @Mock private StageExecution stageExecution; @Mock private PipelineExecution pipelineExecution; + @Spy private ObjectMapper objectMapper; + @BeforeEach - void init( - @WiremockResolver.Wiremock WireMockServer wireMockServer, - @WiremockUriResolver.WiremockUri String uri) { - this.wireMockServer = wireMockServer; - MockitoAnnotations.initMocks(this); - Mockito.when(propsMock.getCloudDriverBaseUrl()).thenReturn(uri); + void init() { + MockitoAnnotations.openMocks(this); + pipelineExecution.setApplication("lambdaApp"); Mockito.when(stageExecution.getExecution()).thenReturn(pipelineExecution); Mockito.when(stageExecution.getContext()).thenReturn(new HashMap<>()); - LambdaDeploymentInput ldi = - LambdaDeploymentInput.builder().functionName("functionName").build(); - Mockito.when( - lambdaCloudDriverUtilsMock.validateUpsertLambdaInput(Mockito.any(), Mockito.anyList())) - .thenReturn(true); - Mockito.when(lambdaCloudDriverUtilsMock.getInput(stageExecution, LambdaDeploymentInput.class)) - .thenReturn(ldi); - LambdaGetInput lgi = LambdaGetInput.builder().build(); - Mockito.when(lambdaCloudDriverUtilsMock.getInput(stageExecution, LambdaGetInput.class)) - .thenReturn(lgi); - Mockito.when(lambdaCloudDriverUtilsMock.asString(ldi)).thenReturn("asString"); + + Mockito.when(stageExecution.mapTo(LambdaDeploymentInput.class)) + .thenReturn(mockLambdaDeploymentInput()); + LambdaGetInput input = LambdaGetInput.builder().appName("lambdaApp").build(); + Mockito.when(stageExecution.mapTo(LambdaGetInput.class)).thenReturn(input); } @Test public void execute_InsertLambda_SUCCEEDED() { - Mockito.when(lambdaCloudDriverUtilsMock.retrieveLambdaFromCache(stageExecution, false)) - .thenReturn(null); - LambdaCloudDriverResponse lambdaCloudDriverResponse = - LambdaCloudDriverResponse.builder().resourceUri("/resourceUri").build(); - Mockito.when(lambdaCloudDriverUtilsMock.postToCloudDriver(Mockito.any(), Mockito.any())) - .thenReturn(lambdaCloudDriverResponse); + Mockito.when(lambdaUtils.validateUpsertLambdaInput(any(), any())).thenReturn(true); + Mockito.when(lambdaUtils.retrieveLambdaFromCache(any())).thenReturn(null); + + SubmitOperationResult result = new SubmitOperationResult(); + result.setResourceUri("/resourceUri"); + Mockito.when(katoService.submitOperation(any(), any())).thenReturn(result); + assertEquals(ExecutionStatus.SUCCEEDED, lambdaCreateTask.execute(stageExecution).getStatus()); } @Test public void execute_UpsertLambda_SUCCEEDED() { - Map revisions = new HashMap<>(); - revisions.put("revision", "1"); + Mockito.when(lambdaUtils.validateUpsertLambdaInput(any(), any())).thenReturn(true); + + Map revisions = Map.of("revision", "1"); LambdaDefinition ld = LambdaDefinition.builder().revisions(revisions).build(); - Mockito.when(lambdaCloudDriverUtilsMock.retrieveLambdaFromCache(stageExecution, false)) - .thenReturn(ld); + Mockito.when(lambdaUtils.retrieveLambdaFromCache(any())).thenReturn(ld); + assertEquals(ExecutionStatus.SUCCEEDED, lambdaCreateTask.execute(stageExecution).getStatus()); } @Test public void execute_InvalidUpsertLambdaInput_TERMINAL() { - Map revisions = new HashMap<>(); - revisions.put("revision", "1"); - LambdaDefinition ld = LambdaDefinition.builder().revisions(revisions).build(); - Mockito.when(lambdaCloudDriverUtilsMock.retrieveLambdaFromCache(stageExecution, false)) - .thenReturn(ld); - Mockito.when( - lambdaCloudDriverUtilsMock.validateUpsertLambdaInput(Mockito.any(), Mockito.anyList())) - .thenReturn(false); + Mockito.when(lambdaUtils.validateUpsertLambdaInput(any(), any())).thenReturn(false); assertEquals(ExecutionStatus.TERMINAL, lambdaCreateTask.execute(stageExecution).getStatus()); } + + private LambdaDeploymentInput mockLambdaDeploymentInput() { + return LambdaDeploymentInput.builder() + .appName("lambdaApp") + .functionName("functionName") + .account("account") + .credentials("credentials") + .region("us-east-1") + .runtime("java17") + .s3bucket("bucket") + .s3key("key") + .handler("handler") + .role("role") + .build(); + } } diff --git a/orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaDeleteConcurrencyTaskTest.java b/orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaDeleteConcurrencyTaskTest.java index aa20a4b589..19622bd128 100644 --- a/orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaDeleteConcurrencyTaskTest.java +++ b/orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaDeleteConcurrencyTaskTest.java @@ -17,83 +17,74 @@ package com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; -import com.github.tomakehurst.wiremock.WireMockServer; +import com.fasterxml.jackson.databind.ObjectMapper; import com.netflix.spinnaker.orca.api.pipeline.models.ExecutionStatus; import com.netflix.spinnaker.orca.api.pipeline.models.PipelineExecution; import com.netflix.spinnaker.orca.api.pipeline.models.StageExecution; -import com.netflix.spinnaker.orca.clouddriver.config.CloudDriverConfigurationProperties; -import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.LambdaCloudDriverResponse; +import com.netflix.spinnaker.orca.clouddriver.KatoService; +import com.netflix.spinnaker.orca.clouddriver.model.SubmitOperationResult; +import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.LambdaUtils; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.input.LambdaConcurrencyInput; -import com.netflix.spinnaker.orca.clouddriver.utils.LambdaCloudDriverUtils; import java.util.HashMap; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.MockitoAnnotations; -import ru.lanwen.wiremock.ext.WiremockResolver; -import ru.lanwen.wiremock.ext.WiremockUriResolver; - -@ExtendWith({WiremockResolver.class, WiremockUriResolver.class}) -public class LambdaDeleteConcurrencyTaskTest { +import org.mockito.*; - WireMockServer wireMockServer; +public class LambdaDeleteConcurrencyTaskTest { @InjectMocks private LambdaDeleteConcurrencyTask lambdaDeleteConcurrencyTask; - @Mock private CloudDriverConfigurationProperties propsMock; + @Mock private KatoService katoService; - @Mock private LambdaCloudDriverUtils lambdaCloudDriverUtilsMock; + @Mock private LambdaUtils lambdaUtils; @Mock private StageExecution stageExecution; @Mock private PipelineExecution pipelineExecution; + @Spy private ObjectMapper objectMapper; + @BeforeEach - void init( - @WiremockResolver.Wiremock WireMockServer wireMockServer, - @WiremockUriResolver.WiremockUri String uri) { - this.wireMockServer = wireMockServer; - MockitoAnnotations.initMocks(this); - Mockito.when(propsMock.getCloudDriverBaseUrl()).thenReturn(uri); + void init() { + MockitoAnnotations.openMocks(this); + pipelineExecution.setApplication("lambdaApp"); Mockito.when(stageExecution.getExecution()).thenReturn(pipelineExecution); Mockito.when(stageExecution.getContext()).thenReturn(new HashMap<>()); Mockito.when(stageExecution.getOutputs()).thenReturn(new HashMap<>()); + + Mockito.when(lambdaUtils.validateUpsertLambdaInput(any(), any())).thenReturn(true); + LambdaConcurrencyInput ldi = LambdaConcurrencyInput.builder().functionName("functionName").build(); - Mockito.when( - lambdaCloudDriverUtilsMock.validateUpsertLambdaInput(Mockito.any(), Mockito.anyList())) - .thenReturn(true); - Mockito.when(lambdaCloudDriverUtilsMock.getInput(stageExecution, LambdaConcurrencyInput.class)) - .thenReturn(ldi); + Mockito.when(stageExecution.mapTo(LambdaConcurrencyInput.class)).thenReturn(ldi); } @Test public void execute_DeleteReservedConcurrency_SUCCEEDED() { Mockito.when(stageExecution.getType()).thenReturn("Aws.LambdaDeploymentStage"); - LambdaCloudDriverResponse lambdaCloudDriverResponse = - LambdaCloudDriverResponse.builder().resourceUri("/resourceUri").build(); - Mockito.when(lambdaCloudDriverUtilsMock.postToCloudDriver(Mockito.any(), Mockito.any())) - .thenReturn(lambdaCloudDriverResponse); + + SubmitOperationResult result = new SubmitOperationResult(); + result.setResourceUri("/resourceUri"); + Mockito.when(katoService.submitOperation(any(), any())).thenReturn(result); + assertEquals( ExecutionStatus.SUCCEEDED, lambdaDeleteConcurrencyTask.execute(stageExecution).getStatus()); } @Test public void execute_DeleteReservedConcurrency_NOTHING_TO_DELETE() { + Mockito.when(stageExecution.getType()).thenReturn("Aws.LambdaDeploymentStage"); + LambdaConcurrencyInput ldi = LambdaConcurrencyInput.builder() .functionName("functionName") .reservedConcurrentExecutions(10) .build(); - Mockito.when(lambdaCloudDriverUtilsMock.getInput(stageExecution, LambdaConcurrencyInput.class)) - .thenReturn(ldi); + Mockito.when(stageExecution.mapTo(LambdaConcurrencyInput.class)).thenReturn(ldi); - Mockito.when(stageExecution.getType()).thenReturn("Aws.LambdaDeploymentStage"); assertEquals( ExecutionStatus.SUCCEEDED, lambdaDeleteConcurrencyTask.execute(stageExecution).getStatus()); assertEquals( @@ -104,25 +95,26 @@ public void execute_DeleteReservedConcurrency_NOTHING_TO_DELETE() { @Test public void execute_DeleteProvisionedConcurrency_SUCCEEDED() { Mockito.when(stageExecution.getType()).thenReturn("Aws.LambdaTrafficRoutingStage"); - LambdaCloudDriverResponse lambdaCloudDriverResponse = - LambdaCloudDriverResponse.builder().resourceUri("/resourceUri").build(); - Mockito.when(lambdaCloudDriverUtilsMock.postToCloudDriver(Mockito.any(), Mockito.any())) - .thenReturn(lambdaCloudDriverResponse); + + SubmitOperationResult result = new SubmitOperationResult(); + result.setResourceUri("/resourceUri"); + Mockito.when(katoService.submitOperation(any(), any())).thenReturn(result); + assertEquals( ExecutionStatus.SUCCEEDED, lambdaDeleteConcurrencyTask.execute(stageExecution).getStatus()); } @Test public void execute_DeleteProvisionedConcurrency_NOTHING_TO_DELETE() { + Mockito.when(stageExecution.getType()).thenReturn("Aws.LambdaTrafficRoutingStage"); + LambdaConcurrencyInput ldi = LambdaConcurrencyInput.builder() .functionName("functionName") .provisionedConcurrentExecutions(10) .build(); - Mockito.when(lambdaCloudDriverUtilsMock.getInput(stageExecution, LambdaConcurrencyInput.class)) - .thenReturn(ldi); + Mockito.when(stageExecution.mapTo(LambdaConcurrencyInput.class)).thenReturn(ldi); - Mockito.when(stageExecution.getType()).thenReturn("Aws.LambdaTrafficRoutingStage"); assertEquals( ExecutionStatus.SUCCEEDED, lambdaDeleteConcurrencyTask.execute(stageExecution).getStatus()); assertEquals( diff --git a/orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaTrafficUpdateVerificationTaskTest.java b/orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaTrafficUpdateVerificationTaskTest.java index 65246fb0ab..775e2a5270 100644 --- a/orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaTrafficUpdateVerificationTaskTest.java +++ b/orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/LambdaTrafficUpdateVerificationTaskTest.java @@ -27,13 +27,12 @@ import com.netflix.spinnaker.orca.api.pipeline.models.StageExecution; import com.netflix.spinnaker.orca.clouddriver.config.CloudDriverConfigurationProperties; import com.netflix.spinnaker.orca.clouddriver.config.LambdaConfigurationProperties; +import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.LambdaUtils; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.LambdaCloudDriverErrorObject; -import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.LambdaCloudDriverResponse; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.LambdaCloudDriverTaskResults; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.LambdaDefinition; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.input.LambdaTrafficUpdateInput; import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.output.LambdaVerificationStatusOutput; -import com.netflix.spinnaker.orca.clouddriver.utils.LambdaCloudDriverUtils; import java.util.HashMap; import java.util.List; import org.junit.jupiter.api.BeforeEach; @@ -55,7 +54,7 @@ public class LambdaTrafficUpdateVerificationTaskTest { @Mock private CloudDriverConfigurationProperties propsMock; - @Mock private LambdaCloudDriverUtils lambdaCloudDriverUtilsMock; + @Mock private LambdaUtils lambdaCloudDriverUtilsMock; @Mock private StageExecution stageExecution; @@ -81,11 +80,7 @@ void init( .aliasName("develop") .deploymentStrategy("$BLUEGREEN") .build(); - Mockito.when(lambdaCloudDriverUtilsMock.postToCloudDriver(Mockito.any(), Mockito.any())) - .thenReturn(LambdaCloudDriverResponse.builder().build()); - Mockito.when( - lambdaCloudDriverUtilsMock.getInput(stageExecution, LambdaTrafficUpdateInput.class)) - .thenReturn(ldi); + Mockito.when(stageExecution.mapTo(LambdaTrafficUpdateInput.class)).thenReturn(ldi); } @Test @@ -142,7 +137,7 @@ public void execute_UpdateVerification_validateWeights() { Mockito.when(config.getCloudDriverRetrieveNewPublishedLambdaWaitSeconds()).thenReturn(40); Mockito.when(config.getCacheRefreshRetryWaitTime()).thenReturn(15); Mockito.when(config.getCloudDriverRetrieveMaxValidateWeightsTimeSeconds()).thenReturn(240); - Mockito.when(lambdaCloudDriverUtilsMock.retrieveLambdaFromCache(stageExecution, false)) + Mockito.when(lambdaCloudDriverUtilsMock.retrieveLambdaFromCache(stageExecution)) .thenReturn(lambdaDefinition); assertEquals( @@ -170,7 +165,7 @@ public void execute_UpdateVerification_validateWeights_TERMINAL() { Mockito.when(config.getCloudDriverRetrieveNewPublishedLambdaWaitSeconds()).thenReturn(1); Mockito.when(config.getCacheRefreshRetryWaitTime()).thenReturn(1); Mockito.when(config.getCloudDriverRetrieveMaxValidateWeightsTimeSeconds()).thenReturn(1); - Mockito.when(lambdaCloudDriverUtilsMock.retrieveLambdaFromCache(stageExecution, false)) + Mockito.when(lambdaCloudDriverUtilsMock.retrieveLambdaFromCache(stageExecution)) .thenReturn(lambdaDefinition); assertEquals( diff --git a/orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/clouddriver/utils/LambdaClouddriverUtilsTest.java b/orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/clouddriver/utils/LambdaClouddriverUtilsTest.java deleted file mode 100644 index f0a6d61a78..0000000000 --- a/orca-clouddriver/src/test/java/com/netflix/spinnaker/orca/clouddriver/utils/LambdaClouddriverUtilsTest.java +++ /dev/null @@ -1,458 +0,0 @@ -/* - * Copyright 2021 Armory, LLC - * - * 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.utils; - -import static org.junit.jupiter.api.Assertions.*; - -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.client.ResponseDefinitionBuilder; -import com.github.tomakehurst.wiremock.client.WireMock; -import com.google.common.collect.ImmutableMap; -import com.netflix.spinnaker.orca.api.pipeline.models.PipelineExecution; -import com.netflix.spinnaker.orca.api.pipeline.models.StageExecution; -import com.netflix.spinnaker.orca.clouddriver.config.CloudDriverConfigurationProperties; -import com.netflix.spinnaker.orca.clouddriver.config.LambdaConfigurationProperties; -import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.LambdaCloudDriverInvokeOperationResults; -import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.LambdaCloudDriverTaskResults; -import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.LambdaDefinition; -import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.input.LambdaDeploymentInput; -import com.netflix.spinnaker.orca.clouddriver.tasks.providers.aws.lambda.model.input.LambdaGetInput; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.MockitoAnnotations; -import ru.lanwen.wiremock.ext.WiremockResolver; -import ru.lanwen.wiremock.ext.WiremockUriResolver; - -@ExtendWith({WiremockResolver.class, WiremockUriResolver.class}) -public class LambdaClouddriverUtilsTest { - - WireMockServer wireMockServer; - - String CLOUDDRIVER_BASE_URL; - - @InjectMocks private LambdaCloudDriverUtils lambdaCloudDriverUtils; - - @Mock private CloudDriverConfigurationProperties propsMock; - - @Mock private LambdaConfigurationProperties config; - - @BeforeEach - void init( - @WiremockResolver.Wiremock WireMockServer wireMockServer, - @WiremockUriResolver.WiremockUri String uri) { - this.wireMockServer = wireMockServer; - CLOUDDRIVER_BASE_URL = uri; - MockitoAnnotations.initMocks(this); - Mockito.when(propsMock.getCloudDriverBaseUrl()).thenReturn(uri); - } - - @Test - public void validateUpsertLambdaInput_EnableLambdaAtEdgeIsFalse_True() { - LambdaDeploymentInput ldi = - LambdaDeploymentInput.builder() - .account("account-test") - .region("us-west-2") - .functionName("function-test") - .runtime("runtime") - .s3bucket("s3-bucket") - .s3key("abcdefg123456") - .handler("handler") - .role("arn:aws:iam::123456789012:role/LambdaAccess") - .enableLambdaAtEdge(false) - .build(); - assertTrue(lambdaCloudDriverUtils.validateUpsertLambdaInput(ldi, new ArrayList<>())); - } - - @Test - public void validateLambdaEdgeInput_EnvVariablesIsNotEmpty_False() { - HashMap envVariables = new HashMap<>(); - envVariables.put("ENV_TEST_PORT", "8888"); - LambdaDeploymentInput ldi = - LambdaDeploymentInput.builder() - .envVariables(envVariables) - .region("us-east-1") - .memorySize(128) - .subnetIds(new ArrayList<>()) - .securityGroupIds(new ArrayList<>()) - .build(); - assertFalse(lambdaCloudDriverUtils.validateLambdaEdgeInput(ldi, new ArrayList<>())); - } - - @Test - public void validateLambdaEdgeInput_TimeoutGreaterThan5_False() { - LambdaDeploymentInput ldi = - LambdaDeploymentInput.builder() - .envVariables(new HashMap<>()) - .timeout(10) - .memorySize(128) - .subnetIds(new ArrayList<>()) - .securityGroupIds(new ArrayList<>()) - .region("us-east-1") - .build(); - assertFalse(lambdaCloudDriverUtils.validateLambdaEdgeInput(ldi, new ArrayList<>())); - } - - @Test - public void validateLambdaEdgeInput_MemorySizeGreaterThan128_False() { - LambdaDeploymentInput ldi = - LambdaDeploymentInput.builder() - .envVariables(new HashMap<>()) - .timeout(5) - .region("us-east-1") - .memorySize(256) - .subnetIds(new ArrayList<>()) - .securityGroupIds(new ArrayList<>()) - .build(); - assertFalse(lambdaCloudDriverUtils.validateLambdaEdgeInput(ldi, new ArrayList<>())); - } - - @Test - public void validateLambdaEdgeInput_RegionIsNotUsEast1_False() { - LambdaDeploymentInput ldi = - LambdaDeploymentInput.builder() - .envVariables(new HashMap<>()) - .timeout(5) - .region("us-west-2") - .memorySize(128) - .subnetIds(new ArrayList<>()) - .securityGroupIds(new ArrayList<>()) - .build(); - assertFalse(lambdaCloudDriverUtils.validateLambdaEdgeInput(ldi, new ArrayList<>())); - } - - @Test - public void validateLambdaEdgeInput_VpcIdIsNotNull_False() { - LambdaDeploymentInput ldi = - LambdaDeploymentInput.builder() - .envVariables(new HashMap<>()) - .timeout(5) - .region("us-east-1") - .memorySize(128) - .subnetIds(new ArrayList<>()) - .securityGroupIds(new ArrayList<>()) - .vpcId("vpc-2f09a348") - .build(); - assertFalse(lambdaCloudDriverUtils.validateLambdaEdgeInput(ldi, new ArrayList<>())); - } - - @Test - public void validateLambdaEdgeInput_HaveSubNetIds_False() { - LambdaDeploymentInput ldi = - LambdaDeploymentInput.builder() - .envVariables(new HashMap<>()) - .timeout(5) - .region("us-east-1") - .memorySize(128) - .subnetIds(Stream.of("subnet-b46032ec").collect(Collectors.toList())) - .securityGroupIds(new ArrayList<>()) - .build(); - assertFalse(lambdaCloudDriverUtils.validateLambdaEdgeInput(ldi, new ArrayList<>())); - } - - @Test - public void validateLambdaEdgeInput_HaveSecurityGroups_False() { - LambdaDeploymentInput ldi = - LambdaDeploymentInput.builder() - .envVariables(new HashMap<>()) - .timeout(5) - .region("us-east-1") - .memorySize(128) - .subnetIds(new ArrayList<>()) - .securityGroupIds(Stream.of("sg-b46032ec").collect(Collectors.toList())) - .build(); - assertFalse(lambdaCloudDriverUtils.validateLambdaEdgeInput(ldi, new ArrayList<>())); - } - - @Test - public void getSortedRevisions_SortVersion_321() { - Map revisions = new HashMap<>(); - revisions.put("first", "1"); - revisions.put("second", "2"); - revisions.put("third", "3"); - List sortedList = Stream.of("3", "2", "1").collect(Collectors.toList()); - LambdaDefinition lambdaDefinition = LambdaDefinition.builder().revisions(revisions).build(); - assertEquals(sortedList, lambdaCloudDriverUtils.getSortedRevisions(lambdaDefinition)); - } - - @Test - public void getCanonicalVersion_NoRevisions_NoPublishedVersionsExist() { - Map revisions = new HashMap<>(); - LambdaDefinition lambdaDefinition = LambdaDefinition.builder().revisions(revisions).build(); - assertNull(lambdaCloudDriverUtils.getCanonicalVersion(lambdaDefinition, "", "", 1)); - } - - @Test - public void getCanonicalVersion_ProvidedRevision_PROVIDED() { - Map revisions = new HashMap<>(); - revisions.put("first", "1"); - LambdaDefinition lambdaDefinition = LambdaDefinition.builder().revisions(revisions).build(); - assertEquals( - "3", lambdaCloudDriverUtils.getCanonicalVersion(lambdaDefinition, "$PROVIDED", "3", 0)); - } - - @Test - public void getCanonicalVersion_LatestRevision_GetLatestVersion() { - Map revisions = new HashMap<>(); - revisions.put("first", "1"); - revisions.put("third", "3"); - revisions.put("second", "2"); - LambdaDefinition lambdaDefinition = LambdaDefinition.builder().revisions(revisions).build(); - assertEquals( - "3", lambdaCloudDriverUtils.getCanonicalVersion(lambdaDefinition, "$LATEST", "5", 0)); - } - - @Test - public void getCanonicalVersion_OldestRevision_GetOldestVersion() { - Map revisions = new HashMap<>(); - revisions.put("first", "5"); - revisions.put("third", "1"); - revisions.put("second", "7"); - LambdaDefinition lambdaDefinition = LambdaDefinition.builder().revisions(revisions).build(); - assertEquals( - "1", lambdaCloudDriverUtils.getCanonicalVersion(lambdaDefinition, "$OLDEST", "5", 0)); - } - - @Test - public void getCanonicalVersion_PreviousRevision_GetPreviousVersion() { - Map revisions = new HashMap<>(); - revisions.put("first", "5"); - revisions.put("third", "1"); - revisions.put("second", "7"); - LambdaDefinition lambdaDefinition = LambdaDefinition.builder().revisions(revisions).build(); - assertEquals( - "5", lambdaCloudDriverUtils.getCanonicalVersion(lambdaDefinition, "$PREVIOUS", "5", 0)); - } - - @Test - public void getCanonicalVersion_MovingRevision_GetMovingVersion() { - Map revisions = new HashMap<>(); - revisions.put("first", "5"); - revisions.put("third", "1"); - revisions.put("second", "7"); - revisions.put("other", "8"); - LambdaDefinition lambdaDefinition = LambdaDefinition.builder().revisions(revisions).build(); - assertEquals( - "5,1", lambdaCloudDriverUtils.getCanonicalVersion(lambdaDefinition, "$MOVING", "5", 2)); - } - - @Test - public void getCanonicalVersion_InvalidInputVersion_Null() { - Map revisions = new HashMap<>(); - revisions.put("first", "5"); - LambdaDefinition lambdaDefinition = LambdaDefinition.builder().revisions(revisions).build(); - assertNull( - lambdaCloudDriverUtils.getCanonicalVersion( - lambdaDefinition, "$FAKE_INOUT_VERSION", "5", 2)); - } - - @Test - public void getCanonicalVersion_NoRevisions_Null() { - LambdaDefinition lambdaDefinition = - LambdaDefinition.builder().revisions(new HashMap<>()).build(); - assertNull(lambdaCloudDriverUtils.getCanonicalVersion(lambdaDefinition, "$PREVIOUS", "5", 2)); - } - - @Test - public void getFromCloudDriver_Success() { - ResponseDefinitionBuilder mockResponse = - new ResponseDefinitionBuilder().withStatus(200).withBody("Success"); - - this.wireMockServer.stubFor(WireMock.get("/healthcheck").willReturn(mockResponse)); - assertEquals( - "Success", - lambdaCloudDriverUtils.getFromCloudDriver(CLOUDDRIVER_BASE_URL.concat("/healthcheck"))); - } - - @Test - public void retrieveLambdaFromCache_ShouldGetLambdaGetInput_NotNull() { - ResponseDefinitionBuilder mockFunctionResponse = - new ResponseDefinitionBuilder() - .withStatus(200) - .withBody( - "[{\"account\":\"account1\",\"aliasConfigurations\":[],\"code\":{\"location\":\"https:\\/\\/awslambda-us-west-2-tasks.s3.us-west-2.amazonaws.com\\/snapshots\\/569630529054\\/hello-world-9d719f9e\",\"repositoryType\":\"S3\"},\"codeSha256\":\"gEfN8j47XTW9VAGo6+dTbppFm3HZRnsOFI3\\/C6v05Xs=\",\"codeSize\":343,\"description\":\"A starter AWS Lambda function.\",\"eventSourceMappings\":[],\"fileSystemConfigs\":[],\"functionArn\":\"arn:aws:lambda:us-west-2:569630529054:function:hello-world\",\"functionName\":\"function-test\",\"handler\":\"lambda_function.lambda_handler\",\"lastModified\":\"2021-04-19T22:58:03.358+0000\",\"layers\":[],\"memorySize\":128,\"packageType\":\"Zip\",\"region\":\"us-west-2\",\"revisionId\":\"dc635189-fb73-4bd7-93d5-3b955568101e\",\"revisions\":{\"dc635189-fb73-4bd7-93d5-3b955568101e\":\"$LATEST\"},\"role\":\"arn:aws:iam::569630529054:role\\/service-role\\/hello-world-role-ff9v8sy0\",\"runtime\":\"python3.7\",\"state\":\"Active\",\"tags\":{\"lambda-console:blueprint\":\"hello-world-python\"},\"targetGroups\":[],\"timeout\":3,\"tracingConfig\":{\"mode\":\"PassThrough\"},\"version\":\"$LATEST\"}]"); - - this.wireMockServer.stubFor( - WireMock.get( - "/functions?region=us-west-2&account=account1&functionName=app-test-function-test") - .willReturn(mockFunctionResponse)); - - LambdaGetInput lambdaGetInput = - LambdaGetInput.builder() - .region("us-west-2") - .account("account1") - .functionName("function-test") - .appName("app-test") - .build(); - - assertNotNull(lambdaCloudDriverUtils.retrieveLambdaFromCache(lambdaGetInput)); - } - - @Test - public void retrieveLambdaFromCache_ShouldNotGetLambdaGetInput_Null() { - ResponseDefinitionBuilder mockFunctionNotFoundResponse = - new ResponseDefinitionBuilder().withStatus(204).withBody("[]"); - - this.wireMockServer.stubFor( - WireMock.get( - "/functions?region=us-west-2&account=account2&functionName=app-test-function-test") - .willReturn(mockFunctionNotFoundResponse)); - - LambdaGetInput lambdaGetInput = - LambdaGetInput.builder() - .region("us-west-2") - .account("account2") - .functionName("function-test") - .appName("app-test") - .build(); - - assertNull(lambdaCloudDriverUtils.retrieveLambdaFromCache(lambdaGetInput)); - } - - @Test - public void postToCloudDriver_ShouldGetLambdaCloudDriverResponse_NotNull() { - ResponseDefinitionBuilder mockPostToCloudDriverResponse = - new ResponseDefinitionBuilder() - .withStatus(200) - .withBody("{\"id\":\"id-123456789\",\"resourceUri\":\"http://resourceUri\"}"); - - this.wireMockServer.stubFor(WireMock.post("/post").willReturn(mockPostToCloudDriverResponse)); - assertNotNull( - lambdaCloudDriverUtils.postToCloudDriver( - CLOUDDRIVER_BASE_URL.concat("/post"), "{\"spinnaker\":\"test\"}")); - } - - @Test - public void postToCloudDriver_ShouldNotGetLambdaCloudDriverResponse_Null() { - ResponseDefinitionBuilder mockPostToCloudDriverResponse = - new ResponseDefinitionBuilder().withStatus(204).withBody("Error"); - - this.wireMockServer.stubFor(WireMock.post("/post").willReturn(mockPostToCloudDriverResponse)); - assertThrows( - RuntimeException.class, - () -> - lambdaCloudDriverUtils.postToCloudDriver( - CLOUDDRIVER_BASE_URL.concat("/post"), "{\"spinnaker\":\"test\"}")); - } - - @Test - public void getLambdaInvokeResults_ShouldGetLambdaCloudDriverInvokeOperationResults_NotNull() { - ResponseDefinitionBuilder mockResponse = - new ResponseDefinitionBuilder() - .withStatus(200) - .withBody( - "{\"status\":{\"complete\":true,\"completed\":true,\"retryable\":false,\"failed\":false,\"phase\":\"phase\",\"status\":\"status\"},\"resultObjects\":[{\"responseString\":\"{\\\"statusCode\\\": 200, \\\"body\\\": \\\"something\\\"}\",\"statusCode\":\"200\",\"body\":\"something\",\"errorMessage\":\"errorMessage\",\"hasErrors\":false}]}"); - - this.wireMockServer.stubFor(WireMock.get("/lambdaInvokeResults").willReturn(mockResponse)); - LambdaCloudDriverInvokeOperationResults results = - lambdaCloudDriverUtils.getLambdaInvokeResults( - CLOUDDRIVER_BASE_URL.concat("/lambdaInvokeResults")); - assertNotNull(results); - assertEquals(200, results.getStatusCode()); - } - - @Test - public void getPublishedVersion_getVersion_1() { - ResponseDefinitionBuilder mockResponse = - new ResponseDefinitionBuilder() - .withStatus(200) - .withBody("{\"resultObjects\":[{\"version\":\"1\"}]}"); - - this.wireMockServer.stubFor(WireMock.get("/publishedVersion").willReturn(mockResponse)); - String publishedVersion = - lambdaCloudDriverUtils.getPublishedVersion( - CLOUDDRIVER_BASE_URL.concat("/publishedVersion")); - assertNotNull(publishedVersion); - assertEquals("1", publishedVersion); - } - - @Test - public void getPublishedVersion_getLatest_$LATEST() { - ResponseDefinitionBuilder mockResponse = - new ResponseDefinitionBuilder().withStatus(200).withBody("{\"resultObjects\":[{}]}"); - - this.wireMockServer.stubFor(WireMock.get("/publishedVersion").willReturn(mockResponse)); - String publishedVersion = - lambdaCloudDriverUtils.getPublishedVersion( - CLOUDDRIVER_BASE_URL.concat("/publishedVersion")); - assertNotNull(publishedVersion); - assertEquals("$LATEST", publishedVersion); - } - - @Test - public void getPublishedVersion_ShouldGetLatestIfNoVersionIsSpecified_$LATEST() { - ResponseDefinitionBuilder mockResponse = - new ResponseDefinitionBuilder().withStatus(200).withBody("{\"error\":[{}]}"); - - this.wireMockServer.stubFor(WireMock.get("/publishedVersion").willReturn(mockResponse)); - assertEquals( - "$LATEST", - lambdaCloudDriverUtils.getPublishedVersion( - CLOUDDRIVER_BASE_URL.concat("/publishedVersion"))); - } - - @Test - public void verifyStatus_getTheStatus_ShouldNotBeNull() { - ResponseDefinitionBuilder mockResponse = - new ResponseDefinitionBuilder() - .withStatus(200) - .withBody( - "{\"status\":{\"complete\":true,\"completed\":true,\"retryable\":false,\"failed\":false,\"phase\":\"phase\",\"status\":\"status\"},\"resultObjects\":[{\"version\":\"1\",\"functionName\":\"functionName\",\"eventSourceArn\":\"arn:aws:dynamodb:us-east-1:123456789012\",\"functionArn\":\"arn:aws:lambda:region:AccountID:function:function_name\",\"uuid\":\"32dc501c-f3d5-11eb-9a03-0242ac130003\",\"state\":\"completed\"}]}"); - - this.wireMockServer.stubFor(WireMock.get("/verifyStatus").willReturn(mockResponse)); - LambdaCloudDriverTaskResults lambdaCloudDriverTaskResults = - lambdaCloudDriverUtils.verifyStatus(CLOUDDRIVER_BASE_URL.concat("/verifyStatus")); - assertNotNull(lambdaCloudDriverTaskResults); - } - - @Test - public void retrieveLambdaFromCache_ShouldNotBeNull() { - ResponseDefinitionBuilder mockFunctionResponse = - new ResponseDefinitionBuilder() - .withStatus(200) - .withBody( - "[{\"account\":\"account1\",\"aliasConfigurations\":[],\"code\":{\"location\":\"https:\\/\\/awslambda-us-west-2-tasks.s3.us-west-2.amazonaws.com\\/snapshots\\/569630529054\\/hello-world-9d719f9e\",\"repositoryType\":\"S3\"},\"codeSha256\":\"gEfN8j47XTW9VAGo6+dTbppFm3HZRnsOFI3\\/C6v05Xs=\",\"codeSize\":343,\"description\":\"A starter AWS Lambda function.\",\"eventSourceMappings\":[],\"fileSystemConfigs\":[],\"functionArn\":\"arn:aws:lambda:us-west-2:569630529054:function:hello-world\",\"functionName\":\"function-test\",\"handler\":\"lambda_function.lambda_handler\",\"lastModified\":\"2021-04-19T22:58:03.358+0000\",\"layers\":[],\"memorySize\":128,\"packageType\":\"Zip\",\"region\":\"us-west-2\",\"revisionId\":\"dc635189-fb73-4bd7-93d5-3b955568101e\",\"revisions\":{\"dc635189-fb73-4bd7-93d5-3b955568101e\":\"$LATEST\"},\"role\":\"arn:aws:iam::569630529054:role\\/service-role\\/hello-world-role-ff9v8sy0\",\"runtime\":\"python3.7\",\"state\":\"Active\",\"tags\":{\"lambda-console:blueprint\":\"hello-world-python\"},\"targetGroups\":[],\"timeout\":3,\"tracingConfig\":{\"mode\":\"PassThrough\"},\"version\":\"$LATEST\"}]"); - - this.wireMockServer.stubFor( - WireMock.get( - "/functions?region=us-west-2&account=account1&functionName=lambdaApp-function-test") - .willReturn(mockFunctionResponse)); - StageExecution stageExecutionMock = Mockito.mock(StageExecution.class); - Map lambdaGetInput = - ImmutableMap.of( - "region", "us-west-2", - "account", "account1", - "functionName", "function-test"); - Mockito.when(stageExecutionMock.getContext()).thenReturn(lambdaGetInput); - PipelineExecution pipelineExecutionMock = Mockito.mock(PipelineExecution.class); - Mockito.when(pipelineExecutionMock.getApplication()).thenReturn("lambdaApp"); - Mockito.when(stageExecutionMock.getExecution()).thenReturn(pipelineExecutionMock); - LambdaDefinition lambdaDefinition = - lambdaCloudDriverUtils.retrieveLambdaFromCache(stageExecutionMock, false); - assertNotNull(lambdaDefinition); - assertEquals("account1", lambdaDefinition.getAccount()); - } -} diff --git a/orca-clouddriver/src/test/resources/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/functions.json b/orca-clouddriver/src/test/resources/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/functions.json new file mode 100644 index 0000000000..104c5af950 --- /dev/null +++ b/orca-clouddriver/src/test/resources/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/functions.json @@ -0,0 +1,39 @@ +[ + { + "account": "account1", + "aliasConfigurations": [], + "code": { + "location": "https:\\/\\/awslambda-us-west-2-tasks.s3.us-west-2.amazonaws.com\\/snapshots\\/569630529054\\/hello-world-9d719f9e", + "repositoryType": "S3" + }, + "codeSha256": "gEfN8j47XTW9VAGo6+dTbppFm3HZRnsOFI3\\/C6v05Xs=", + "codeSize": 343, + "description": "A starter AWS Lambda function.", + "eventSourceMappings": [], + "fileSystemConfigs": [], + "functionArn": "arn:aws:lambda:us-west-2:569630529054:function:hello-world", + "functionName": "function-test", + "handler": "lambda_function.lambda_handler", + "lastModified": "2021-04-19T22:58:03.358+0000", + "layers": [], + "memorySize": 128, + "packageType": "Zip", + "region": "us-west-2", + "revisionId": "dc635189-fb73-4bd7-93d5-3b955568101e", + "revisions": { + "dc635189-fb73-4bd7-93d5-3b955568101e": "$LATEST" + }, + "role": "arn:aws:iam::569630529054:role\\/service-role\\/hello-world-role-ff9v8sy0", + "runtime": "python3.7", + "state": "Active", + "tags": { + "lambda-console:blueprint": "hello-world-python" + }, + "targetGroups": [], + "timeout": 3, + "tracingConfig": { + "mode": "PassThrough" + }, + "version": "$LATEST" + } +] diff --git a/orca-clouddriver/src/test/resources/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/kato-published-version-empty.json b/orca-clouddriver/src/test/resources/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/kato-published-version-empty.json new file mode 100644 index 0000000000..916a11d8b2 --- /dev/null +++ b/orca-clouddriver/src/test/resources/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/kato-published-version-empty.json @@ -0,0 +1,3 @@ +{ + "resultObjects": [{}] +} diff --git a/orca-clouddriver/src/test/resources/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/kato-published-version.json b/orca-clouddriver/src/test/resources/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/kato-published-version.json new file mode 100644 index 0000000000..83706e70cb --- /dev/null +++ b/orca-clouddriver/src/test/resources/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/kato-published-version.json @@ -0,0 +1,7 @@ +{ + "resultObjects": [ + { + "version": "1" + } + ] +} diff --git a/orca-clouddriver/src/test/resources/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/kato-status-success.json b/orca-clouddriver/src/test/resources/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/kato-status-success.json new file mode 100644 index 0000000000..deae75e869 --- /dev/null +++ b/orca-clouddriver/src/test/resources/com/netflix/spinnaker/orca/clouddriver/tasks/providers/aws/lambda/kato-status-success.json @@ -0,0 +1,16 @@ +{ + "status": { + "completed": true, + "retryable": false, + "failed": false + }, + "resultObjects": [ + { + "responseString": "{\"statusCode\": 200, \"body\": \"something\"}", + "statusCode": "200", + "body": "something", + "errorMessage": "errorMessage", + "hasErrors": false + } + ] +}