From 4a1a934d86705d4723748ec84cd1632b8a1938b6 Mon Sep 17 00:00:00 2001 From: Rodrigo Fernandes Date: Sun, 30 Oct 2016 00:11:15 +0100 Subject: [PATCH] Show Elastic Beanstalk logs during deployment Prepare for v1.0.0 release --- CONTRIBUTING.md | 2 +- LICENSE.md | 1 + README.md | 7 +- .../ElasticBeanstalkRunner.java | 17 ++- .../LoggingDeploymentListener.java | 49 ++++---- .../LoggingDeploymentListenerTest.java | 82 ++++++------ .../runner/elasticbeanstalk/AWSClient.java | 117 +++++++++++------- build/build.gradle | 2 +- 8 files changed, 158 insertions(+), 119 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 106cff3..2dd8415 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -14,7 +14,7 @@ * Use `git rebase` (not `git merge`) to sync your work from time to time with the master branch. -* After creating your pull request make sure the build is passing in [Travis](https://travis-ci.org/rtfpessoa/teamcity-aws-elasticbeanstalk-plugin). +* After creating your pull request make sure the build is passing in [CircleCI](https://circleci.com/gh/rtfpessoa/teamcity-aws-elasticbeanstalk-plugin). ### Commit Style diff --git a/LICENSE.md b/LICENSE.md index 274c734..d33d695 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,3 +1,4 @@ +Copyright 2010-2016 JetBrains s.r.o. Copyright 2016 rtfpessoa Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/README.md b/README.md index 0f18c9d..794f2a0 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ [![CircleCI](https://circleci.com/gh/rtfpessoa/teamcity-aws-elasticbeanstalk-plugin.svg?style=svg)](https://circleci.com/gh/rtfpessoa/teamcity-aws-elasticbeanstalk-plugin) [![Dependency Status](https://dependencyci.com/github/rtfpessoa/teamcity-aws-elasticbeanstalk-plugin/badge)](https://dependencyci.com/github/rtfpessoa/teamcity-aws-elasticbeanstalk-plugin) -teamcity-aws-elasticbeanstalk-plugin is a **VERY EARLY STAGE** Teamcity plugin that allows deployments +teamcity-aws-elasticbeanstalk-plugin is a Teamcity plugin that allows deployments to Elastic Beanstalk. This plugin started from the code in [teamcity-aws-codedeploy-plugin](https://github.com/JetBrains/teamcity-aws-codedeploy-plugin) @@ -16,7 +16,8 @@ and was adapted for Elastic Beanstalk and slightly ajusted. ## Release -* 1.0.0-alpha1 [aws-elasticbeanstalk-plugin.zip](https://github.com/rtfpessoa/teamcity-aws-elasticbeanstalk-plugin/releases/download/1.0.0-alpha1/aws-elasticbeanstalk-plugin.zip) +* [1.0.0](https://github.com/rtfpessoa/teamcity-aws-elasticbeanstalk-plugin/releases/tag/v1.0.0) +* [Previous versions](https://github.com/rtfpessoa/teamcity-aws-elasticbeanstalk-plugin/releases) ## Contributions @@ -26,7 +27,7 @@ I will try to review them as soon as possible. ## License -Copyright 2016 Rodrigo Fernandes. Licensed under the Apache License, Version 2.0 (the "License"). +Licensed under the Apache License, Version 2.0 (the "License"). ## Thanks diff --git a/aws-elasticbeanstalk-agent/src/main/java/jetbrains/buildServer/runner/elasticbeanstalk/ElasticBeanstalkRunner.java b/aws-elasticbeanstalk-agent/src/main/java/jetbrains/buildServer/runner/elasticbeanstalk/ElasticBeanstalkRunner.java index f51c3ef..dbdcced 100644 --- a/aws-elasticbeanstalk-agent/src/main/java/jetbrains/buildServer/runner/elasticbeanstalk/ElasticBeanstalkRunner.java +++ b/aws-elasticbeanstalk-agent/src/main/java/jetbrains/buildServer/runner/elasticbeanstalk/ElasticBeanstalkRunner.java @@ -46,7 +46,7 @@ protected BuildFinishedStatus runImpl() throws RunBuildException { m.s3ObjectVersion = nullIfEmpty(configParameters.get(S3_OBJECT_VERSION_CONFIG_PARAM)); final AWSClient awsClient = createAWSClient(runnerParameters, runningBuild).withListener( - new LoggingDeploymentListener(runnerParameters, runningBuild.getBuildLogger(), runningBuild.getCheckoutDirectory().getAbsolutePath())); + new LoggingDeploymentListener(runnerParameters, runningBuild.getBuildLogger(), runningBuild.getCheckoutDirectory().getAbsolutePath())); final String s3BucketName = runnerParameters.get(S3_BUCKET_NAME_PARAM); String s3ObjectKey = runnerParameters.get(S3_OBJECT_KEY_PARAM); @@ -62,8 +62,8 @@ protected BuildFinishedStatus runImpl() throws RunBuildException { if (!m.problemOccurred && !isInterrupted()) { if (ElasticBeanstalkUtil.isDeploymentWaitEnabled(runnerParameters)) { awsClient.updateEnvironmentAndWait(environmentName, versionLabel, - Integer.parseInt(runnerParameters.get(WAIT_TIMEOUT_SEC_PARAM)), - getIntegerOrDefault(configParameters.get(WAIT_POLL_INTERVAL_SEC_CONFIG_PARAM), WAIT_POLL_INTERVAL_SEC_DEFAULT)); + Integer.parseInt(runnerParameters.get(WAIT_TIMEOUT_SEC_PARAM)), + getIntegerOrDefault(configParameters.get(WAIT_POLL_INTERVAL_SEC_CONFIG_PARAM), WAIT_POLL_INTERVAL_SEC_DEFAULT)); } else { awsClient.updateEnvironment(environmentName, versionLabel); } @@ -101,30 +101,29 @@ public boolean canRun(@NotNull BuildAgentConfiguration agentConfiguration) { @NotNull private AWSClient createAWSClient(final Map runnerParameters, @NotNull final AgentRunningBuild runningBuild) { - final Map params = new HashMap(runnerParameters); + final Map params = new HashMap<>(runnerParameters); params.put(TEMP_CREDENTIALS_SESSION_NAME_PARAM, runningBuild.getBuildTypeExternalId() + runningBuild.getBuildId()); if (ElasticBeanstalkUtil.isDeploymentWaitEnabled(runnerParameters)) { params.put(TEMP_CREDENTIALS_DURATION_SEC_PARAM, String.valueOf(2 * Integer.parseInt(runnerParameters.get(WAIT_TIMEOUT_SEC_PARAM)))); } - return new AWSClient(createAWSClients(params, true)).withDescription("TeamCity build \"" + runningBuild.getBuildTypeName() + "\" #" + runningBuild.getBuildNumber()); + return new AWSClient(createAWSClients(params, true)); } - static class ElasticBeanstalkRunnerException extends RunBuildException { - public ElasticBeanstalkRunnerException(@NotNull String message, @Nullable Throwable cause) { + private static class ElasticBeanstalkRunnerException extends RunBuildException { + ElasticBeanstalkRunnerException(@NotNull String message, @Nullable Throwable cause) { super(message, cause, ErrorData.BUILD_RUNNER_ERROR_TYPE); this.setLogStacktrace(false); } } private class Mutable { - public Mutable(@NotNull Map configParameters) { + Mutable(@NotNull Map configParameters) { problemOccurred = false; s3ObjectVersion = nullIfEmpty(configParameters.get(S3_OBJECT_VERSION_CONFIG_PARAM)); } boolean problemOccurred; String s3ObjectVersion; - String s3ObjectETag; } } diff --git a/aws-elasticbeanstalk-agent/src/main/java/jetbrains/buildServer/runner/elasticbeanstalk/LoggingDeploymentListener.java b/aws-elasticbeanstalk-agent/src/main/java/jetbrains/buildServer/runner/elasticbeanstalk/LoggingDeploymentListener.java index 7f2f7ec..5666c3e 100644 --- a/aws-elasticbeanstalk-agent/src/main/java/jetbrains/buildServer/runner/elasticbeanstalk/LoggingDeploymentListener.java +++ b/aws-elasticbeanstalk-agent/src/main/java/jetbrains/buildServer/runner/elasticbeanstalk/LoggingDeploymentListener.java @@ -34,8 +34,8 @@ class LoggingDeploymentListener extends AWSClient.Listener { @NotNull private static final Logger LOG = Logger.getInstance(Loggers.VCS_CATEGORY + ElasticBeanstalkRunner.class); - static final String CREATE_VERSION = "create version"; - static final String UPDATE_ENVIRONMENT = "update environment"; + static final String CREATE_VERSION = "Create version"; + static final String UPDATE_ENVIRONMENT = "Update environment"; @NotNull private final Map myRunnerParameters; @@ -65,24 +65,29 @@ void createVersionFinished(@NotNull String applicationName, @NotNull String vers } @Override - void deploymentStarted(@NotNull String environmentId, @NotNull String applicationName, @NotNull String versionLabel) { + void deploymentStarted(@NotNull String applicationName, @NotNull String environmentName, @NotNull String versionLabel) { open(UPDATE_ENVIRONMENT); - log(String.format("Started deployment of application %s version %s to %s", applicationName, versionLabel, environmentId)); + log(String.format("Started deployment of application %s version %s to %s", applicationName, versionLabel, environmentName)); } @Override - void deploymentWaitStarted(@NotNull String environmentId) { + void deploymentWaitStarted(@NotNull String environmentName) { log("Waiting for deployment finish"); - log(String.format("Waiting for deployment on environment %s", environmentId)); + log(String.format("Waiting for deployment on environment %s", environmentName)); } @Override - void deploymentInProgress(@NotNull String environmentId) { - progress(String.format("Waiting for deployment on environment %s", environmentId)); + void deploymentInProgress(@NotNull String environmentName) { + progress(String.format("Waiting for deployment on environment %s", environmentName)); } @Override - void deploymentFailed(@NotNull String environmentId, @NotNull String applicationName, @NotNull String versionLabel, + void deploymentUpdate(@NotNull String message) { + progress(message); + } + + @Override + void deploymentFailed(@NotNull String applicationName, @NotNull String environmentName, @NotNull String versionLabel, @NotNull Boolean hasTimeout, @Nullable ErrorInfo errorInfo) { String msg = (!hasTimeout ? "Error, " : "Timeout exceeded, "); @@ -108,8 +113,8 @@ void deploymentFailed(@NotNull String environmentId, @NotNull String application } @Override - void deploymentSucceeded(@NotNull String environmentId, @NotNull String applicationName, @NotNull String versionLabel) { - String message = String.format("Application %s version %s was deployed successfully to %s", applicationName, versionLabel, environmentId); + void deploymentSucceeded(@NotNull String versionLabel) { + String message = String.format("Version %s was deployed successfully", versionLabel); log(message); statusText(message); close(UPDATE_ENVIRONMENT); @@ -135,11 +140,11 @@ private int getIdentity(String... parts) { @NotNull private Collection getIdentityFormingParameters() { return Arrays.asList( - myRunnerParameters.get(ElasticBeanstalkConstants.S3_OBJECT_KEY_PARAM), - myRunnerParameters.get(ElasticBeanstalkConstants.S3_BUCKET_NAME_PARAM), - myRunnerParameters.get(ElasticBeanstalkConstants.ENV_NAME_PARAM), - myRunnerParameters.get(ElasticBeanstalkConstants.APP_NAME_PARAM), - myRunnerParameters.get(ElasticBeanstalkConstants.APP_VERSION_PARAM)); + myRunnerParameters.get(ElasticBeanstalkConstants.S3_OBJECT_KEY_PARAM), + myRunnerParameters.get(ElasticBeanstalkConstants.S3_BUCKET_NAME_PARAM), + myRunnerParameters.get(ElasticBeanstalkConstants.ENV_NAME_PARAM), + myRunnerParameters.get(ElasticBeanstalkConstants.APP_NAME_PARAM), + myRunnerParameters.get(ElasticBeanstalkConstants.APP_VERSION_PARAM)); } protected void log(@NotNull String message) { @@ -173,11 +178,11 @@ protected void statusText(@NotNull String text) { @NotNull private String escape(@NotNull String s) { return s. - replace("|", "||"). - replace("'", "|'"). - replace("\n", "|n"). - replace("\r", "|r"). - replace("\\uNNNN", "|0xNNNN"). - replace("[", "|[").replace("]", "|]"); + replace("|", "||"). + replace("'", "|'"). + replace("\n", "|n"). + replace("\r", "|r"). + replace("\\uNNNN", "|0xNNNN"). + replace("[", "|[").replace("]", "|]"); } } diff --git a/aws-elasticbeanstalk-agent/src/test/java/jetbrains.buildServer.runner.elasticbeanstalk/LoggingDeploymentListenerTest.java b/aws-elasticbeanstalk-agent/src/test/java/jetbrains.buildServer.runner.elasticbeanstalk/LoggingDeploymentListenerTest.java index ee659cc..2e6d6dc 100644 --- a/aws-elasticbeanstalk-agent/src/test/java/jetbrains.buildServer.runner.elasticbeanstalk/LoggingDeploymentListenerTest.java +++ b/aws-elasticbeanstalk-agent/src/test/java/jetbrains.buildServer.runner.elasticbeanstalk/LoggingDeploymentListenerTest.java @@ -28,8 +28,8 @@ public class LoggingDeploymentListenerTest extends LoggingTestCase { - private static final String FAKE_ID = "ID-123XYZ"; - private static final String FAKE_APP_NAME = "NAME-FOO"; + private static final String FAKE_ENV_NAME = "ENV-NAME-FOO"; + private static final String FAKE_APP_NAME = "APP-NAME-BAR"; private static final String FAKE_APP_VERSION = "1.0.0-alpha1"; @BeforeMethod(alwaysRun = true) @@ -53,79 +53,79 @@ public void common_events() throws Exception { listener.createVersionFinished(FAKE_APP_NAME, FAKE_APP_VERSION, bucketName, key); - listener.deploymentStarted(FAKE_ID, FAKE_APP_NAME, FAKE_APP_VERSION); + listener.deploymentStarted(FAKE_APP_NAME, FAKE_ENV_NAME, FAKE_APP_VERSION); - listener.deploymentWaitStarted(FAKE_ID); + listener.deploymentWaitStarted(FAKE_ENV_NAME); - listener.deploymentInProgress(FAKE_ID); + listener.deploymentInProgress(FAKE_ENV_NAME); - listener.deploymentSucceeded(FAKE_ID, FAKE_APP_NAME, FAKE_APP_VERSION); + listener.deploymentSucceeded(FAKE_APP_VERSION); assertLog( - "OPEN " + LoggingDeploymentListener.CREATE_VERSION, - "LOG Creating application " + FAKE_APP_NAME + " version " + FAKE_APP_VERSION + " with bucket " + bucketName + " and key " + key, - "LOG Created application " + FAKE_APP_NAME + " version " + FAKE_APP_VERSION + " with bucket " + bucketName + " and key " + key, - "CLOSE " + LoggingDeploymentListener.CREATE_VERSION, - "OPEN " + LoggingDeploymentListener.UPDATE_ENVIRONMENT, - "LOG Started deployment of application " + FAKE_APP_NAME + " version " + FAKE_APP_VERSION + " to " + FAKE_ID, - "LOG Waiting for deployment finish", - "LOG Waiting for deployment on environment " + FAKE_ID, - "PROGRESS Waiting for deployment on environment " + FAKE_ID, - "LOG Application " + FAKE_APP_NAME + " version " + FAKE_APP_VERSION + " was deployed successfully to " + FAKE_ID, - "STATUS_TEXT Application " + FAKE_APP_NAME + " version " + FAKE_APP_VERSION + " was deployed successfully to " + FAKE_ID, - "CLOSE " + LoggingDeploymentListener.UPDATE_ENVIRONMENT); + "OPEN " + LoggingDeploymentListener.CREATE_VERSION, + "LOG Creating application " + FAKE_APP_NAME + " version " + FAKE_APP_VERSION + " with bucket " + bucketName + " and key " + key, + "LOG Created application " + FAKE_APP_NAME + " version " + FAKE_APP_VERSION + " with bucket " + bucketName + " and key " + key, + "CLOSE " + LoggingDeploymentListener.CREATE_VERSION, + "OPEN " + LoggingDeploymentListener.UPDATE_ENVIRONMENT, + "LOG Started deployment of application " + FAKE_APP_NAME + " version " + FAKE_APP_VERSION + " to " + FAKE_ENV_NAME, + "LOG Waiting for deployment finish", + "LOG Waiting for deployment on environment " + FAKE_ENV_NAME, + "PROGRESS Waiting for deployment on environment " + FAKE_ENV_NAME, + "LOG Version " + FAKE_APP_VERSION + " was deployed successfully", + "STATUS_TEXT Version " + FAKE_APP_VERSION + " was deployed successfully", + "CLOSE " + LoggingDeploymentListener.UPDATE_ENVIRONMENT); } @Test public void deployment_progress() throws Exception { - create().deploymentInProgress(FAKE_ID); - assertLog("PROGRESS Waiting for deployment on environment " + FAKE_ID); + create().deploymentInProgress(FAKE_ENV_NAME); + assertLog("PROGRESS Waiting for deployment on environment " + FAKE_ENV_NAME); } @Test public void deployment_succeeded() throws Exception { - create().deploymentSucceeded(FAKE_ID, FAKE_APP_NAME, FAKE_APP_VERSION); + create().deploymentSucceeded(FAKE_APP_VERSION); assertLog( - "LOG Application " + FAKE_APP_NAME + " version " + FAKE_APP_VERSION + " was deployed successfully to " + FAKE_ID, - "STATUS_TEXT Application " + FAKE_APP_NAME + " version " + FAKE_APP_VERSION + " was deployed successfully to " + FAKE_ID, - "CLOSE " + LoggingDeploymentListener.UPDATE_ENVIRONMENT); + "LOG Version " + FAKE_APP_VERSION + " was deployed successfully", + "STATUS_TEXT Version " + FAKE_APP_VERSION + " was deployed successfully", + "CLOSE " + LoggingDeploymentListener.UPDATE_ENVIRONMENT); } @Test public void deployment_failed_timeout() throws Exception { - create().deploymentFailed(FAKE_ID, FAKE_APP_NAME, FAKE_APP_VERSION, true, null); + create().deploymentFailed(FAKE_APP_NAME, FAKE_ENV_NAME, FAKE_APP_VERSION, true, null); assertLog( - "PROBLEM identity: 3569038 type: ELASTICBEANSTALK_TIMEOUT descr: Timeout exceeded, ", - "CLOSE update environment"); + "PROBLEM identity: 3569038 type: ELASTICBEANSTALK_TIMEOUT descr: Timeout exceeded, ", + "CLOSE " + LoggingDeploymentListener.UPDATE_ENVIRONMENT); } @Test public void deployment_failed() throws Exception { - create().deploymentFailed(FAKE_ID, FAKE_APP_NAME, FAKE_APP_VERSION, false, createError("abc", "Some error message")); + create().deploymentFailed(FAKE_APP_NAME, FAKE_ENV_NAME, FAKE_APP_VERSION, false, createError("abc", "Some error message")); assertLog( - "ERR Associated error: Some error message", - "ERR Error severity: abc", - "PROBLEM identity: 79914740 type: ELASTICBEANSTALK_FAILURE descr: Error, : Some error message", - "CLOSE update environment"); + "ERR Associated error: Some error message", + "ERR Error severity: abc", + "PROBLEM identity: 79914740 type: ELASTICBEANSTALK_FAILURE descr: Error, : Some error message", + "CLOSE " + LoggingDeploymentListener.UPDATE_ENVIRONMENT); } @Test public void deployment_exception_type() throws Exception { create().exception(new AWSException("Some exception message", null, AWSException.EXCEPTION_BUILD_PROBLEM_TYPE, null)); assertLog( - "ERR Some exception message", - "PROBLEM identity: 2086901196 type: ELASTICBEANSTALK_EXCEPTION descr: Some exception message", - "CLOSE update environment"); + "ERR Some exception message", + "PROBLEM identity: 2086901196 type: ELASTICBEANSTALK_EXCEPTION descr: Some exception message", + "CLOSE " + LoggingDeploymentListener.UPDATE_ENVIRONMENT); } @Test public void deployment_exception_description_type() throws Exception { create().exception(new AWSException("Some exception message", null, AWSException.CLIENT_PROBLEM_TYPE, "Some exception details")); assertLog( - "ERR Some exception message", - "ERR Some exception details", - "PROBLEM identity: 2086901196 type: ELASTICBEANSTALK_CLIENT descr: Some exception message", - "CLOSE update environment"); + "ERR Some exception message", + "ERR Some exception details", + "PROBLEM identity: 2086901196 type: ELASTICBEANSTALK_CLIENT descr: Some exception message", + "CLOSE " + LoggingDeploymentListener.UPDATE_ENVIRONMENT); } @Override @@ -144,8 +144,8 @@ private AWSClient.Listener.ErrorInfo createError(@Nullable String severity, @Nul @NotNull private LoggingDeploymentListener create() { return new LoggingDeploymentListener(Collections.emptyMap(), - new NullBuildProgressLogger(), - "fake_checkout_dir") { + new NullBuildProgressLogger(), + "fake_checkout_dir") { @Override protected void log(@NotNull String message) { logMessage("LOG " + message); diff --git a/aws-elasticbeanstalk-common/src/main/java/jetbrains/buildServer/runner/elasticbeanstalk/AWSClient.java b/aws-elasticbeanstalk-common/src/main/java/jetbrains/buildServer/runner/elasticbeanstalk/AWSClient.java index 0c6a876..3441764 100644 --- a/aws-elasticbeanstalk-common/src/main/java/jetbrains/buildServer/runner/elasticbeanstalk/AWSClient.java +++ b/aws-elasticbeanstalk-common/src/main/java/jetbrains/buildServer/runner/elasticbeanstalk/AWSClient.java @@ -24,29 +24,26 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; import java.util.List; public class AWSClient { @NotNull private AWSElasticBeanstalkClient myElasticBeanstalkClient; - @Nullable - private String myDescription; @NotNull private Listener myListener = new Listener(); + @NotNull + private HashMap pastEvents = new HashMap<>(); - public AWSClient(@NotNull AWSClients clients) { + AWSClient(@NotNull AWSClients clients) { myElasticBeanstalkClient = clients.createElasticBeanstalkClient(); } @NotNull - public AWSClient withDescription(@NotNull String description) { - myDescription = description; - return this; - } - - @NotNull - public AWSClient withListener(@NotNull Listener listener) { + AWSClient withListener(@NotNull Listener listener) { myListener = listener; return this; } @@ -59,8 +56,8 @@ public AWSClient withListener(@NotNull Listener listener) { * @param s3BucketName valid S3 bucket name * @param s3ObjectKey valid S3 object key */ - public void createApplicationVersion(@NotNull String applicationName, @NotNull String versionLabel, - @NotNull String s3BucketName, @NotNull String s3ObjectKey) { + void createApplicationVersion(@NotNull String applicationName, @NotNull String versionLabel, + @NotNull String s3BucketName, @NotNull String s3ObjectKey) { try { myListener.createVersionStarted(applicationName, versionLabel, s3BucketName, s3ObjectKey); S3Location location = new S3Location().withS3Bucket(s3BucketName).withS3Key(s3ObjectKey); @@ -85,15 +82,15 @@ public void createApplicationVersion(@NotNull String applicationName, @NotNull S * @param waitTimeoutSec seconds to wait for the created deployment finish or fail * @param waitIntervalSec seconds between polling ElasticBeanstalk for the created deployment status */ - public void updateEnvironmentAndWait(@NotNull String environmentName, @NotNull String versionLabel, - int waitTimeoutSec, int waitIntervalSec) { + void updateEnvironmentAndWait(@NotNull String environmentName, @NotNull String versionLabel, + int waitTimeoutSec, int waitIntervalSec) { doUpdateAndWait(environmentName, versionLabel, true, waitTimeoutSec, waitIntervalSec); } /** * The same as {@link #updateEnvironmentAndWait} but without waiting */ - public void updateEnvironment(@NotNull String environmentName, @NotNull String versionLabel) { + void updateEnvironment(@NotNull String environmentName, @NotNull String versionLabel) { doUpdateAndWait(environmentName, versionLabel, false, null, null); } @@ -104,6 +101,9 @@ private void doUpdateAndWait(@NotNull String environmentName, @NotNull String ve UpdateEnvironmentRequest request = new UpdateEnvironmentRequest() .withEnvironmentName(environmentName) .withVersionLabel(versionLabel); + + long startTime = System.currentTimeMillis(); + UpdateEnvironmentResult result = myElasticBeanstalkClient.updateEnvironment(request); String environmentId = result.getEnvironmentId(); @@ -111,53 +111,65 @@ private void doUpdateAndWait(@NotNull String environmentName, @NotNull String ve myListener.deploymentStarted(environmentId, environmentName, versionLabel); if (wait) { - waitForDeployment(environmentId, versionLabel, waitTimeoutSec, waitIntervalSec); + waitForDeployment(environmentId, versionLabel, startTime, waitTimeoutSec, waitIntervalSec); } } catch (Throwable t) { processFailure(t); } } - private void waitForDeployment(@NotNull String environmentId, String versionLabel, int waitTimeoutSec, int waitIntervalSec) { - myListener.deploymentWaitStarted(environmentId); + private void waitForDeployment(@NotNull String environmentId, String versionLabel, long startTime, + int waitTimeoutSec, int waitIntervalSec) { + myListener.deploymentWaitStarted(getEnvironment(environmentId).getEnvironmentName()); - EnvironmentDescription environment = getEnvironment(environmentId); - String status = getHumanReadableStatus(environment.getStatus()); - List events = getErrorEvents(environmentId, versionLabel); - boolean hasError = events.size() > 0; + EnvironmentDescription environment; + String status; + List newEvents; + List errorEvents; + boolean hasError; - long startTime = System.currentTimeMillis(); + Date startDate = new Date(startTime); - while (status.equals("updating") && !hasError) { - myListener.deploymentInProgress(environmentId); + while (true) { + environment = getEnvironment(environmentId); + + myListener.deploymentInProgress(environment.getEnvironmentName()); + + status = getHumanReadableStatus(environment.getStatus()); + newEvents = getNewEvents(environmentId, startDate); + + for (EventDescription event : newEvents) { + myListener.deploymentUpdate(event.getMessage()); + } if (System.currentTimeMillis() - startTime > waitTimeoutSec * 1000) { - myListener.deploymentFailed(environmentId, environment.getApplicationName(), versionLabel, true, null); + myListener.deploymentFailed(environment.getApplicationName(), environment.getEnvironmentName(), versionLabel, true, null); return; } + errorEvents = getErrorEvents(environmentId, versionLabel); + hasError = errorEvents.size() > 0; + if (!status.equals("updating") || hasError) { + break; + } + try { Thread.sleep(waitIntervalSec * 1000); } catch (InterruptedException e) { processFailure(e); return; } - - environment = getEnvironment(environmentId); - status = getHumanReadableStatus(environment.getStatus()); - events = getErrorEvents(environmentId, versionLabel); - hasError = events.size() > 0; } if (isSuccess(environment, versionLabel)) { - myListener.deploymentSucceeded(environmentId, environment.getApplicationName(), versionLabel); + myListener.deploymentSucceeded(versionLabel); } else { - Listener.ErrorInfo errorEvent = events.size() > 0 ? getErrorInfo(events.get(0)) : null; - myListener.deploymentFailed(environmentId, environment.getApplicationName(), versionLabel, false, errorEvent); + Listener.ErrorInfo errorEvent = hasError ? getErrorInfo(errorEvents.get(0)) : null; + myListener.deploymentFailed(environment.getApplicationName(), environment.getEnvironmentName(), versionLabel, false, errorEvent); } } - public EnvironmentDescription getEnvironment(@NotNull String environmentId) { + private EnvironmentDescription getEnvironment(@NotNull String environmentId) { return myElasticBeanstalkClient.describeEnvironments(new DescribeEnvironmentsRequest().withEnvironmentIds(environmentId)) .getEnvironments().get(0); } @@ -171,6 +183,24 @@ private List getErrorEvents(@NotNull String environmentId, Str .getEvents(); } + private List getNewEvents(@NotNull String environmentId, @NotNull Date startTime) { + List events = myElasticBeanstalkClient.describeEvents(new DescribeEventsRequest() + .withEnvironmentId(environmentId) + .withStartTime(startTime) + .withMaxRecords(20)) + .getEvents(); + + List newEvents = new ArrayList<>(); + for (EventDescription event : events) { + if (!pastEvents.containsKey(event.hashCode())) { + newEvents.add(event); + pastEvents.put(event.hashCode(), event); + } + } + + return newEvents; + } + private boolean isSuccess(@NotNull EnvironmentDescription environment, @NotNull String versionLabel) { return environment.getVersionLabel().equals(versionLabel); } @@ -203,7 +233,7 @@ private String removeTrailingDot(@Nullable String msg) { return (msg != null && msg.endsWith(".")) ? msg.substring(0, msg.length() - 1) : msg; } - public static class Listener { + static class Listener { void createVersionStarted(@NotNull String applicationName, @NotNull String versionLabel, @NotNull String s3BucketName, @NotNull String s3ObjectKey) { } @@ -212,26 +242,29 @@ void createVersionFinished(@NotNull String applicationName, @NotNull String vers @NotNull String s3BucketName, @NotNull String s3ObjectKey) { } - void deploymentStarted(@NotNull String environmentId, @NotNull String applicationName, @NotNull String versionLabel) { + void deploymentStarted(@NotNull String environmentId, @NotNull String environmentName, @NotNull String versionLabel) { + } + + void deploymentWaitStarted(@NotNull String environmentName) { } - void deploymentWaitStarted(@NotNull String environmentId) { + void deploymentInProgress(@NotNull String environmentName) { } - void deploymentInProgress(@NotNull String environmentId) { + void deploymentUpdate(@NotNull String message) { } - void deploymentFailed(@NotNull String environmentId, @NotNull String applicationName, @NotNull String versionLabel, + void deploymentFailed(@NotNull String applicationName, @NotNull String environmentName, @NotNull String versionLabel, @NotNull Boolean hasTimeout, @Nullable ErrorInfo errorInfo) { } - void deploymentSucceeded(@NotNull String environmentId, @NotNull String applicationName, @NotNull String versionLabel) { + void deploymentSucceeded(@NotNull String versionLabel) { } void exception(@NotNull AWSException exception) { } - public static class ErrorInfo { + static class ErrorInfo { @Nullable String severity; @Nullable diff --git a/build/build.gradle b/build/build.gradle index 2484161..680c30f 100644 --- a/build/build.gradle +++ b/build/build.gradle @@ -41,7 +41,7 @@ teamcity { server { descriptor = file("$rootDir/teamcity-plugin.xml") - tokens = [Plugin_Version: '1.0.0-alpha1'] + tokens = [Plugin_Version: '1.0.0'] files { into('server') { from awsSDKFiles()