From c01ef80c28309f431456b223d8605fe87cb6aee1 Mon Sep 17 00:00:00 2001 From: Victory Petrenko Date: Fri, 29 Jul 2016 19:37:04 +0300 Subject: [PATCH] TW-46415, TW-45071 --- .../runner/codedeploy/CodeDeployRunner.java | 41 ++++++++++++++----- .../codedeploy/LoggingDeploymentListener.java | 24 ++++++++--- .../LoggingDeploymentListenerTest.java | 14 ++++--- .../runner/codedeploy/AWSClient.java | 36 ++++++++-------- .../codedeploy/CodeDeployConstants.java | 1 + 5 files changed, 77 insertions(+), 39 deletions(-) diff --git a/aws-codedeploy-agent/src/main/java/jetbrains/buildServer/runner/codedeploy/CodeDeployRunner.java b/aws-codedeploy-agent/src/main/java/jetbrains/buildServer/runner/codedeploy/CodeDeployRunner.java index 6929b1f..d5da15d 100644 --- a/aws-codedeploy-agent/src/main/java/jetbrains/buildServer/runner/codedeploy/CodeDeployRunner.java +++ b/aws-codedeploy-agent/src/main/java/jetbrains/buildServer/runner/codedeploy/CodeDeployRunner.java @@ -26,7 +26,6 @@ import java.io.File; import java.util.HashMap; import java.util.Map; -import java.util.concurrent.atomic.AtomicBoolean; import static jetbrains.buildServer.runner.codedeploy.CodeDeployConstants.*; import static jetbrains.buildServer.util.amazon.AWSCommonParams.*; @@ -47,21 +46,31 @@ protected BuildFinishedStatus runImpl() throws RunBuildException { final Map runnerParameters = validateParams(); final Map configParameters = context.getConfigParameters(); - final AtomicBoolean problemOccurred = new AtomicBoolean(); + final Mutable m = new Mutable(configParameters); + m.problemOccurred = false; + m.s3ObjectVersion = nullIfEmpty(configParameters.get(S3_OBJECT_VERSION_CONFIG_PARAM)); + m.s3ObjectETag = nullIfEmpty(configParameters.get(S3_OBJECT_ETAG_CONFIG_PARAM)); final AWSClient awsClient = createAWSClient(runnerParameters, runningBuild).withListener( new LoggingDeploymentListener(runnerParameters, runningBuild.getBuildLogger(), runningBuild.getCheckoutDirectory().getAbsolutePath()) { @Override protected void problem(int identity, @NotNull String type, @NotNull String descr) { super.problem(identity, type, descr); - problemOccurred.set(true); + m.problemOccurred = true; + } + + @Override + void uploadRevisionFinished(@NotNull File revision, @NotNull String s3BucketName, @NotNull String s3ObjectKey, @Nullable String s3ObjectVersion, @Nullable String s3ObjectETag, @NotNull String url) { + super.uploadRevisionFinished(revision, s3BucketName, s3ObjectKey, s3ObjectVersion, s3ObjectETag, url); + m.s3ObjectVersion = s3ObjectVersion; + m.s3ObjectETag = s3ObjectETag; } }); final String s3BucketName = runnerParameters.get(S3_BUCKET_NAME_PARAM); String s3ObjectKey = runnerParameters.get(S3_OBJECT_KEY_PARAM); - if (CodeDeployUtil.isUploadStepEnabled(runnerParameters) && !problemOccurred.get() && !isInterrupted()) { + if (CodeDeployUtil.isUploadStepEnabled(runnerParameters) && !m.problemOccurred && !isInterrupted()) { final File readyRevision = new ApplicationRevision( isEmptyOrSpaces(s3ObjectKey) ? runningBuild.getBuildTypeExternalId() : s3ObjectKey, runnerParameters.get(REVISION_PATHS_PARAM), @@ -77,30 +86,29 @@ protected void problem(int identity, @NotNull String type, @NotNull String descr final String applicationName = runnerParameters.get(APP_NAME_PARAM); final String bundleType = "" + AWSUtil.getBundleType(s3ObjectKey); - final String s3ObjectVersion = nullIfEmpty(configParameters.get(S3_OBJECT_VERSION_CONFIG_PARAM)); - if (CodeDeployUtil.isRegisterStepEnabled(runnerParameters) && !problemOccurred.get() && !isInterrupted()) { - awsClient.registerRevision(s3BucketName, s3ObjectKey, bundleType, s3ObjectVersion, applicationName); + if (CodeDeployUtil.isRegisterStepEnabled(runnerParameters) && !m.problemOccurred && !isInterrupted()) { + awsClient.registerRevision(s3BucketName, s3ObjectKey, bundleType, m.s3ObjectVersion, m.s3ObjectETag, applicationName); } - if (CodeDeployUtil.isDeployStepEnabled(runnerParameters) && !problemOccurred.get() && !isInterrupted()) { + if (CodeDeployUtil.isDeployStepEnabled(runnerParameters) && !m.problemOccurred && !isInterrupted()) { final String deploymentGroupName = runnerParameters.get(DEPLOYMENT_GROUP_NAME_PARAM); final String deploymentConfigName = nullIfEmpty(runnerParameters.get(DEPLOYMENT_CONFIG_NAME_PARAM)); if (CodeDeployUtil.isDeploymentWaitEnabled(runnerParameters)) { awsClient.deployRevisionAndWait( - s3BucketName, s3ObjectKey, bundleType, s3ObjectVersion, + s3BucketName, s3ObjectKey, bundleType, m.s3ObjectVersion, m.s3ObjectETag, applicationName, deploymentGroupName, deploymentConfigName, Integer.parseInt(runnerParameters.get(WAIT_TIMEOUT_SEC_PARAM)), getIntegerOrDefault(configParameters.get(WAIT_POLL_INTERVAL_SEC_CONFIG_PARAM), WAIT_POLL_INTERVAL_SEC_DEFAULT)); } else { awsClient.deployRevision( - s3BucketName, s3ObjectKey, bundleType, s3ObjectVersion, + s3BucketName, s3ObjectKey, bundleType, m.s3ObjectVersion, m.s3ObjectETag, applicationName, deploymentGroupName, deploymentConfigName); } } - return problemOccurred.get() ? BuildFinishedStatus.FINISHED_WITH_PROBLEMS : BuildFinishedStatus.FINISHED_SUCCESS; + return m.problemOccurred ? BuildFinishedStatus.FINISHED_WITH_PROBLEMS : BuildFinishedStatus.FINISHED_SUCCESS; } @NotNull @@ -147,4 +155,15 @@ public CodeDeployRunnerException(@NotNull String message, @Nullable Throwable ca this.setLogStacktrace(false); } } + + private class Mutable { + public Mutable(@NotNull Map configParameters) { + problemOccurred = false; + s3ObjectVersion = nullIfEmpty(configParameters.get(S3_OBJECT_VERSION_CONFIG_PARAM)); + s3ObjectETag = nullIfEmpty(configParameters.get(S3_OBJECT_ETAG_CONFIG_PARAM)); + } + boolean problemOccurred; + String s3ObjectVersion; + String s3ObjectETag; + } } diff --git a/aws-codedeploy-agent/src/main/java/jetbrains/buildServer/runner/codedeploy/LoggingDeploymentListener.java b/aws-codedeploy-agent/src/main/java/jetbrains/buildServer/runner/codedeploy/LoggingDeploymentListener.java index 2722df9..a9a9d62 100644 --- a/aws-codedeploy-agent/src/main/java/jetbrains/buildServer/runner/codedeploy/LoggingDeploymentListener.java +++ b/aws-codedeploy-agent/src/main/java/jetbrains/buildServer/runner/codedeploy/LoggingDeploymentListener.java @@ -60,22 +60,34 @@ void uploadRevisionStarted(@NotNull File revision, @NotNull String s3BucketName, } @Override - void uploadRevisionFinished(@NotNull File revision, @NotNull String s3BucketName, @NotNull String key, @NotNull String url) { - log("Uploaded application revision " + url); + void uploadRevisionFinished(@NotNull File revision, @NotNull String s3BucketName, @NotNull String s3ObjectKey, @Nullable String s3ObjectVersion, @Nullable String s3ObjectETag, @NotNull String url) { + final boolean hasVersion = StringUtil.isNotEmpty(s3ObjectVersion); + final boolean hasETag = StringUtil.isNotEmpty(s3ObjectETag); + + final String directUrl = + url + + (hasVersion || hasETag ? "?" : "") + + (hasVersion ? "versionId=" + s3ObjectVersion : "") + + (hasVersion && hasETag ? "&" : "") + + (hasETag ? "etag=" + s3ObjectETag : ""); + + log("Uploaded application revision " + directUrl); if (!CodeDeployUtil.isRegisterStepEnabled(myRunnerParameters)) { - statusText("Uploaded " + url); + statusText("Uploaded " + directUrl); } + if (hasVersion) parameter(CodeDeployConstants.S3_OBJECT_VERSION_CONFIG_PARAM, s3ObjectVersion); + if (hasETag) parameter(CodeDeployConstants.S3_OBJECT_ETAG_CONFIG_PARAM, s3ObjectETag); close(UPLOAD_REVISION); } @Override - void registerRevisionStarted(@NotNull String applicationName, @NotNull String s3BucketName, @NotNull String s3ObjectKey, @NotNull String s3BundleType, @Nullable String s3ObjectVersion) { + void registerRevisionStarted(@NotNull String applicationName, @NotNull String s3BucketName, @NotNull String s3ObjectKey, @NotNull String s3BundleType, @Nullable String s3ObjectVersion, @Nullable String s3ObjectETag) { open(REGISTER_REVISION); - log(String.format("Registering application %s revision from S3 bucket %s with key %s, bundle type %s and %s version", applicationName, s3BucketName, s3ObjectKey, s3BundleType, StringUtil.isEmptyOrSpaces(s3ObjectVersion) ? "latest" : s3ObjectVersion)); + log(String.format("Registering application %s revision from S3 bucket %s with key %s, bundle type %s, %s version and %s ETag", applicationName, s3BucketName, s3ObjectKey, s3BundleType, StringUtil.isEmptyOrSpaces(s3ObjectVersion) ? "latest" : s3ObjectVersion, StringUtil.isEmptyOrSpaces(s3ObjectETag) ? "no" : s3ObjectETag)); } @Override - void registerRevisionFinished(@NotNull String applicationName, @NotNull String s3BucketName, @NotNull String s3ObjectKey, @NotNull String s3BundleType, @Nullable String s3ObjectVersion) { + void registerRevisionFinished(@NotNull String applicationName, @NotNull String s3BucketName, @NotNull String s3ObjectKey, @NotNull String bundleType, @Nullable String s3ObjectVersion, @Nullable String s3ObjectETag) { if (!CodeDeployUtil.isDeployStepEnabled(myRunnerParameters)) { statusText("Registered revision"); } diff --git a/aws-codedeploy-agent/src/test/java/jetbrains.buildServer.runner.codedeploy/LoggingDeploymentListenerTest.java b/aws-codedeploy-agent/src/test/java/jetbrains.buildServer.runner.codedeploy/LoggingDeploymentListenerTest.java index c1c71a0..535843c 100644 --- a/aws-codedeploy-agent/src/test/java/jetbrains.buildServer.runner.codedeploy/LoggingDeploymentListenerTest.java +++ b/aws-codedeploy-agent/src/test/java/jetbrains.buildServer.runner.codedeploy/LoggingDeploymentListenerTest.java @@ -52,18 +52,19 @@ public void common_events() throws Exception { final File revision = writeFile(revisionName); final String bucketName = "bucketName"; final String key = "path/key.zip"; + final String eTag = "12345"; listener.uploadRevisionStarted(revision, bucketName, key); final String url = "https://s3-eu-west-1.amazonaws.com/bucketName/path/key.zip"; - listener.uploadRevisionFinished(revision, bucketName, key, url); + listener.uploadRevisionFinished(revision, bucketName, key, null, eTag, url); final String applicationName = "App Name"; final String bundleType = ".zip"; - listener.registerRevisionStarted(applicationName, bucketName, key, bundleType, null); - listener.registerRevisionFinished(applicationName, bucketName, key, bundleType, null); + listener.registerRevisionStarted(applicationName, bucketName, key, bundleType, null, eTag); + listener.registerRevisionFinished(applicationName, bucketName, key, bundleType, null, eTag); final String groupName = "Deployment Fleet"; @@ -76,11 +77,12 @@ public void common_events() throws Exception { assertLog( "OPEN " + LoggingDeploymentListener.UPLOAD_REVISION, "LOG Uploading application revision ##BASE_DIR##/" + revisionName + " to S3 bucket " + bucketName + " using key " + key, - "LOG Uploaded application revision " + url, - "STATUS_TEXT Uploaded " + url, + "LOG Uploaded application revision " + url + "?etag=" + eTag, + "STATUS_TEXT Uploaded " + url + "?etag=" + eTag, + "PARAM " + CodeDeployConstants.S3_OBJECT_ETAG_CONFIG_PARAM + " -> " + eTag, "CLOSE " + LoggingDeploymentListener.UPLOAD_REVISION, "OPEN " + LoggingDeploymentListener.REGISTER_REVISION, - "LOG Registering application " + applicationName + " revision from S3 bucket " + bucketName + " with key " + key + ", bundle type " + bundleType + " and latest version", + "LOG Registering application " + applicationName + " revision from S3 bucket " + bucketName + " with key " + key + ", bundle type " + bundleType + ", latest version and " + eTag + " ETag", "STATUS_TEXT Registered revision", "CLOSE " + LoggingDeploymentListener.REGISTER_REVISION, "OPEN " + LoggingDeploymentListener.DEPLOY_APPLICATION, diff --git a/aws-codedeploy-common/src/main/java/jetbrains/buildServer/runner/codedeploy/AWSClient.java b/aws-codedeploy-common/src/main/java/jetbrains/buildServer/runner/codedeploy/AWSClient.java index 59435ff..b11c995 100644 --- a/aws-codedeploy-common/src/main/java/jetbrains/buildServer/runner/codedeploy/AWSClient.java +++ b/aws-codedeploy-common/src/main/java/jetbrains/buildServer/runner/codedeploy/AWSClient.java @@ -20,6 +20,7 @@ import com.amazonaws.services.codedeploy.model.*; import com.amazonaws.services.s3.AmazonS3Client; import com.amazonaws.services.s3.model.PutObjectRequest; +import com.amazonaws.services.s3.model.PutObjectResult; import jetbrains.buildServer.util.StringUtil; import jetbrains.buildServer.util.amazon.AWSClients; import jetbrains.buildServer.util.amazon.AWSException; @@ -83,12 +84,13 @@ public void uploadRevision(@NotNull File revision, * @param s3ObjectKey valid S3 object key * @param bundleType one of zip, tar or tar.gz * @param s3ObjectVersion S3 object version (for versioned buckets) or null to use the latest version + * @param s3ObjectETag S3 object ETag (file checksum) for object validation or null if no validation should be performed * @param applicationName CodeDeploy application name */ - public void registerRevision(@NotNull String s3BucketName, @NotNull String s3ObjectKey, @NotNull String bundleType, @Nullable String s3ObjectVersion, + public void registerRevision(@NotNull String s3BucketName, @NotNull String s3ObjectKey, @NotNull String bundleType, @Nullable String s3ObjectVersion, @Nullable String s3ObjectETag, @NotNull String applicationName) { try { - doRegisterRevision(getRevisionLocation(s3BucketName, s3ObjectKey, bundleType, s3ObjectVersion), applicationName); + doRegisterRevision(getRevisionLocation(s3BucketName, s3ObjectKey, bundleType, s3ObjectVersion, s3ObjectETag), applicationName); } catch (Throwable t) { processFailure(t); } @@ -105,32 +107,33 @@ public void registerRevision(@NotNull String s3BucketName, @NotNull String s3Obj * @param s3ObjectKey valid S3 object key * @param bundleType one of zip, tar or tar.gz * @param s3ObjectVersion S3 object version (for versioned buckets) or null to use the latest version + * @param s3ObjectETag S3 object ETag (file checksum) for object validation or null if no validation should be performed * @param applicationName CodeDeploy application name * @param deploymentGroupName deployment group name * @param deploymentConfigName deployment configuration name or null for default deployment configuration * @param waitTimeoutSec seconds to wait for the created deployment finish or fail * @param waitIntervalSec seconds between polling CodeDeploy for the created deployment status */ - public void deployRevisionAndWait(@NotNull String s3BucketName, @NotNull String s3ObjectKey, @NotNull String bundleType, @Nullable String s3ObjectVersion, + public void deployRevisionAndWait(@NotNull String s3BucketName, @NotNull String s3ObjectKey, @NotNull String bundleType, @Nullable String s3ObjectVersion, @Nullable String s3ObjectETag, @NotNull String applicationName, @NotNull String deploymentGroupName, @Nullable String deploymentConfigName, int waitTimeoutSec, int waitIntervalSec) { - doDeployAndWait(s3BucketName, s3ObjectKey, bundleType, s3ObjectVersion, applicationName, deploymentGroupName, deploymentConfigName, true, waitTimeoutSec, waitIntervalSec); + doDeployAndWait(s3BucketName, s3ObjectKey, bundleType, s3ObjectVersion, s3ObjectETag, applicationName, deploymentGroupName, deploymentConfigName, true, waitTimeoutSec, waitIntervalSec); } /** * The same as {@link #deployRevisionAndWait} but without waiting */ - public void deployRevision(@NotNull String s3BucketName, @NotNull String s3ObjectKey, @NotNull String bundleType, @Nullable String s3ObjectVersion, + public void deployRevision(@NotNull String s3BucketName, @NotNull String s3ObjectKey, @NotNull String bundleType, @Nullable String s3ObjectVersion, @Nullable String s3ObjectETag, @NotNull String applicationName, @NotNull String deploymentGroupName, @Nullable String deploymentConfigName) { - doDeployAndWait(s3BucketName, s3ObjectKey, bundleType, s3ObjectVersion, applicationName, deploymentGroupName, deploymentConfigName, false, null, null); + doDeployAndWait(s3BucketName, s3ObjectKey, bundleType, s3ObjectVersion, s3ObjectETag, applicationName, deploymentGroupName, deploymentConfigName, false, null, null); } @SuppressWarnings("ConstantConditions") - private void doDeployAndWait(@NotNull String s3BucketName, @NotNull String s3ObjectKey, @NotNull String bundleType, @Nullable String s3ObjectVersion, + private void doDeployAndWait(@NotNull String s3BucketName, @NotNull String s3ObjectKey, @NotNull String bundleType, @Nullable String s3ObjectVersion, @Nullable String s3ObjectETag, @NotNull String applicationName, @NotNull String deploymentGroupName, @Nullable String deploymentConfigName, boolean wait, @Nullable Integer waitTimeoutSec, @Nullable Integer waitIntervalSec) { try { - final String deploymentId = createDeployment(getRevisionLocation(s3BucketName, s3ObjectKey, bundleType, s3ObjectVersion), applicationName, deploymentGroupName, deploymentConfigName); + final String deploymentId = createDeployment(getRevisionLocation(s3BucketName, s3ObjectKey, bundleType, s3ObjectVersion, s3ObjectETag), applicationName, deploymentGroupName, deploymentConfigName); if (wait) { waitForDeployment(deploymentId, waitTimeoutSec, waitIntervalSec); @@ -177,21 +180,22 @@ private void waitForDeployment(@NotNull String deploymentId, int waitTimeoutSec, private void doUploadRevision(@NotNull File revision, @NotNull String s3BucketName, @NotNull String s3ObjectKey) { myListener.uploadRevisionStarted(revision, s3BucketName, s3ObjectKey); - myS3Client.putObject(new PutObjectRequest(s3BucketName, s3ObjectKey, revision)); + final PutObjectResult putObjectResult = myS3Client.putObject(new PutObjectRequest(s3BucketName, s3ObjectKey, revision)); - myListener.uploadRevisionFinished(revision, s3BucketName, s3ObjectKey, myS3Client.getUrl(s3BucketName, s3ObjectKey).toString()); + myListener.uploadRevisionFinished(revision, s3BucketName, s3ObjectKey, putObjectResult.getVersionId(), putObjectResult.getETag(), myS3Client.getUrl(s3BucketName, s3ObjectKey).toString()); } @NotNull - private RevisionLocation getRevisionLocation(@NotNull String s3BucketName, @NotNull String s3ObjectKey, @NotNull String bundleType, @Nullable String s3ObjectVersion) { + private RevisionLocation getRevisionLocation(@NotNull String s3BucketName, @NotNull String s3ObjectKey, @NotNull String bundleType, @Nullable String s3ObjectVersion, @Nullable String s3ObjectETag) { final S3Location loc = new S3Location().withBucket(s3BucketName).withKey(s3ObjectKey).withBundleType(bundleType); if (StringUtil.isNotEmpty(s3ObjectVersion)) loc.withVersion(s3ObjectVersion); + if (StringUtil.isNotEmpty(s3ObjectETag)) loc.withETag(s3ObjectETag); return new RevisionLocation().withRevisionType(RevisionLocationType.S3).withS3Location(loc); } private void doRegisterRevision(@NotNull RevisionLocation revisionLocation, @NotNull String applicationName) { final S3Location s3Location = revisionLocation.getS3Location(); - myListener.registerRevisionStarted(applicationName, s3Location.getBucket(), s3Location.getKey(), s3Location.getBundleType(), s3Location.getVersion()); + myListener.registerRevisionStarted(applicationName, s3Location.getBucket(), s3Location.getKey(), s3Location.getBundleType(), s3Location.getVersion(), s3Location.getETag()); myCodeDeployClient.registerApplicationRevision( new RegisterApplicationRevisionRequest() @@ -199,7 +203,7 @@ private void doRegisterRevision(@NotNull RevisionLocation revisionLocation, @Not .withApplicationName(applicationName) .withDescription(getDescription("Application revision registered by ", 100))); - myListener.registerRevisionFinished(applicationName, s3Location.getBucket(), s3Location.getKey(), s3Location.getBundleType(), s3Location.getVersion()); + myListener.registerRevisionFinished(applicationName, s3Location.getBucket(), s3Location.getKey(), s3Location.getBundleType(), s3Location.getVersion(), s3Location.getETag()); } @NotNull @@ -292,9 +296,9 @@ private String removeTrailingDot(@Nullable String msg) { public static class Listener { void uploadRevisionStarted(@NotNull File revision, @NotNull String s3BucketName, @NotNull String s3ObjectKey) {} - void uploadRevisionFinished(@NotNull File revision, @NotNull String s3BucketName, @NotNull String s3ObjectKey, @NotNull String url) {} - void registerRevisionStarted(@NotNull String applicationName, @NotNull String s3BucketName, @NotNull String s3ObjectKey, @NotNull String bundleType, @Nullable String s3ObjectVersion) {} - void registerRevisionFinished(@NotNull String applicationName, @NotNull String s3BucketName, @NotNull String s3ObjectKey, @NotNull String bundleType, @Nullable String s3ObjectVersion) {} + void uploadRevisionFinished(@NotNull File revision, @NotNull String s3BucketName, @NotNull String s3ObjectKey, @Nullable String s3ObjectVersion, @Nullable String s3ObjectETag, @NotNull String url) {} + void registerRevisionStarted(@NotNull String applicationName, @NotNull String s3BucketName, @NotNull String s3ObjectKey, @NotNull String bundleType, @Nullable String s3ObjectVersion, @Nullable String s3ObjectETag) {} + void registerRevisionFinished(@NotNull String applicationName, @NotNull String s3BucketName, @NotNull String s3ObjectKey, @NotNull String bundleType, @Nullable String s3ObjectVersion, @Nullable String s3ObjectETag) {} void createDeploymentStarted(@NotNull String applicationName, @NotNull String deploymentGroupName, @Nullable String deploymentConfigName) {} void createDeploymentFinished(@NotNull String applicationName, @NotNull String deploymentGroupName, @Nullable String deploymentConfigName, @NotNull String deploymentId) {} void deploymentWaitStarted(@NotNull String deploymentId) {} diff --git a/aws-codedeploy-common/src/main/java/jetbrains/buildServer/runner/codedeploy/CodeDeployConstants.java b/aws-codedeploy-common/src/main/java/jetbrains/buildServer/runner/codedeploy/CodeDeployConstants.java index 7bbd868..436a289 100644 --- a/aws-codedeploy-common/src/main/java/jetbrains/buildServer/runner/codedeploy/CodeDeployConstants.java +++ b/aws-codedeploy-common/src/main/java/jetbrains/buildServer/runner/codedeploy/CodeDeployConstants.java @@ -30,6 +30,7 @@ public interface CodeDeployConstants { String DEPLOYMENT_ID_BUILD_CONFIG_PARAM = "codedeploy.deployment.id"; String S3_OBJECT_VERSION_CONFIG_PARAM = "codedeploy.revision.s3.version"; + String S3_OBJECT_ETAG_CONFIG_PARAM = "codedeploy.revision.s3.etag"; String CUSTOM_APPSPEC_YML_CONFIG_PARAM = "codedeploy.custom.appspec.yml";