diff --git a/pom.xml b/pom.xml index b5bf34f..267b59d 100644 --- a/pom.xml +++ b/pom.xml @@ -124,7 +124,7 @@ org.jenkins-ci.plugins token-macro - 2.1 + 2.3 org.jenkins-ci.main diff --git a/src/main/java/br/com/ingenieux/jenkins/plugins/awsebdeployment/AWSEBDeploymentBuilder.java b/src/main/java/br/com/ingenieux/jenkins/plugins/awsebdeployment/AWSEBDeploymentBuilder.java index 601f9bd..2bc0597 100644 --- a/src/main/java/br/com/ingenieux/jenkins/plugins/awsebdeployment/AWSEBDeploymentBuilder.java +++ b/src/main/java/br/com/ingenieux/jenkins/plugins/awsebdeployment/AWSEBDeploymentBuilder.java @@ -39,6 +39,9 @@ import com.amazonaws.services.elasticbeanstalk.model.ApplicationDescription; import com.amazonaws.services.elasticbeanstalk.model.DescribeEnvironmentsRequest; import com.amazonaws.services.elasticbeanstalk.model.DescribeEnvironmentsResult; +import com.amazonaws.services.route53.AmazonRoute53; +import com.amazonaws.services.route53.AmazonRoute53Client; +import com.amazonaws.services.route53.model.HostedZone; import com.amazonaws.services.s3.AmazonS3; import com.amazonaws.services.s3.AmazonS3Client; import com.cloudbees.jenkins.plugins.awscredentials.AmazonWebServicesCredentials; @@ -49,6 +52,19 @@ import com.google.common.base.Function; import com.google.common.collect.Lists; +import org.apache.commons.lang.StringUtils; +import org.kohsuke.stapler.AncestorInPath; +import org.kohsuke.stapler.DataBoundConstructor; +import org.kohsuke.stapler.QueryParameter; + +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.Arrays; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + import edu.umd.cs.findbugs.annotations.NonNull; import hudson.Extension; import hudson.FilePath; @@ -161,6 +177,42 @@ public class AWSEBDeploymentBuilder extends Builder implements SimpleBuildStep { @Getter private Integer maxAttempts; + /** + * Create Environment If Not Exist + */ + @Getter + private boolean createEnvironmentIfNotExist; + + /** + * Environment CNAME Prefix + */ + @Getter + private String environmentCNAMEPrefix; + + /** + * Environment Template Name + */ + @Getter + private String environmentTemplateName; + + /** + * Environment Settings + */ + private List environmentSettings; + + @Getter + private boolean route53UpdateRecordSet; + + @Getter + private String route53HostedZoneId; + + private List route53DomainNames; + + @Getter + private Long route53RecordTTL; + + @Getter + private String route53RecordType; @DataBoundConstructor public AWSEBDeploymentBuilder(String credentialId, String awsRegion, String applicationName, @@ -168,7 +220,13 @@ public AWSEBDeploymentBuilder(String credentialId, String awsRegion, String appl String versionLabelFormat, String versionDescriptionFormat, String rootObject, String includes, String excludes, boolean zeroDowntime, Integer sleepTime, boolean checkHealth, - Integer maxAttempts) { + Integer maxAttempts, boolean createEnvironmentIfNotExist, + String environmentCNAMEPrefix, + String environmentTemplateName, + List environmentSettings, + boolean route53UpdateRecordSet, String route53HostedZoneId, + List route53DomainNames, Long route53RecordTTL, + String route53RecordType) { this.credentialId = credentialId; this.awsRegion = awsRegion; this.applicationName = applicationName; @@ -184,6 +242,15 @@ public AWSEBDeploymentBuilder(String credentialId, String awsRegion, String appl this.sleepTime = sleepTime; this.checkHealth = checkHealth; this.maxAttempts = maxAttempts; + this.createEnvironmentIfNotExist = createEnvironmentIfNotExist; + this.environmentCNAMEPrefix = environmentCNAMEPrefix; + this.environmentTemplateName = environmentTemplateName; + this.environmentSettings = environmentSettings; + this.route53UpdateRecordSet = route53UpdateRecordSet; + this.route53HostedZoneId = route53HostedZoneId; + this.route53DomainNames = route53DomainNames; + this.route53RecordTTL = route53RecordTTL; + this.route53RecordType = route53RecordType; } @Override @@ -228,7 +295,30 @@ public AWSEBDeploymentConfig asConfig() { sleepTime, checkHealth, maxAttempts, - null); + null, + createEnvironmentIfNotExist, + environmentCNAMEPrefix, + environmentTemplateName, + environmentSettings, + route53UpdateRecordSet, + route53HostedZoneId, + route53DomainNames, + route53RecordTTL, + route53RecordType); + } + + public List getEnvironmentSettings() { + if (environmentSettings == null) { + return new ArrayList(); + } + return environmentSettings; + } + + public List getRoute53DomainNames() { + if (route53DomainNames == null) { + return new ArrayList(); + } + return route53DomainNames; } @Extension @@ -358,9 +448,30 @@ public String apply(ApplicationDescription input) { w.printf("
  • Applications Found: %d (%s)
  • %n", applicationList.size(), StringUtils.join(applicationList, ", ")); - w.printf("%n"); + w.printf("\n"); + AmazonRoute53 amazonRoute53 = factory.getService(AmazonRoute53Client.class); + String route53Endpoint = factory.getEndpointFor((AmazonRoute53Client) amazonRoute53); + + w.printf("
  • Testing Amazon Route 53 Service (endpoint: %s)
  • %n", route53Endpoint); + + List + hostedZoneList = + Lists.transform(amazonRoute53.listHostedZones().getHostedZones(), + new Function() { + @Override + public String apply(HostedZone input) { + return input.getName(); + } + }); + + w.printf("
  • Hosted Zones Found: %d (%s)
  • %n", hostedZoneList.size(), + StringUtils.join(hostedZoneList, ", ")); + + w.printf("\n"); return FormValidation.okWithMarkup(stringWriter.toString()); + } catch (RuntimeException e) { + throw e; } catch (Exception exc) { return FormValidation.error(exc, "Failure"); } diff --git a/src/main/java/br/com/ingenieux/jenkins/plugins/awsebdeployment/AWSEBDeploymentConfig.java b/src/main/java/br/com/ingenieux/jenkins/plugins/awsebdeployment/AWSEBDeploymentConfig.java index ffc3d32..06cc134 100644 --- a/src/main/java/br/com/ingenieux/jenkins/plugins/awsebdeployment/AWSEBDeploymentConfig.java +++ b/src/main/java/br/com/ingenieux/jenkins/plugins/awsebdeployment/AWSEBDeploymentConfig.java @@ -21,6 +21,8 @@ import java.io.IOException; import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; import org.jenkinsci.plugins.tokenmacro.MacroEvaluationException; @@ -111,6 +113,24 @@ public class AWSEBDeploymentConfig implements Serializable { */ private AmazonWebServicesCredentials credentials; + private boolean createEnvironmentIfNotExist; + + private String environmentCNAMEPrefix; + + private String environmentTemplateName; + + private List environmentSettings; + + private boolean route53UpdateRecordSet; + + private String route53HostedZoneId; + + private List route53DomainNames; + + private Long route53RecordTTL; + + private String route53RecordType; + /** * Copy Factory * @@ -118,6 +138,24 @@ public class AWSEBDeploymentConfig implements Serializable { * @return replaced copy */ public AWSEBDeploymentConfig replacedCopy(Utils.Replacer r) throws MacroEvaluationException, IOException, InterruptedException { + List evalSettings = new ArrayList(); + + if (this.getEnvironmentSettings() != null) { + for(AWSEBRawConfigurationOptionSetting setting :this.getEnvironmentSettings()){ + AWSEBRawConfigurationOptionSetting evalSetting = new AWSEBRawConfigurationOptionSetting(r.r(setting.getNamespace()), r.r(setting.getOptionName()), r.r(setting.getValue())); + evalSettings.add(evalSetting); + } + } + + List evalDomainNames = new ArrayList(); + + if (this.getRoute53DomainNames() != null) { + for (AWSEBRoute53DomainName domainName : this.getRoute53DomainNames()) { + AWSEBRoute53DomainName evalDomainName = new AWSEBRoute53DomainName(r.r(domainName.getName())); + evalDomainNames.add(evalDomainName); + } + } + return new AWSEBDeploymentConfig( r.r(this.getCredentialId()), r.r(this.getAwsRegion()), @@ -134,7 +172,16 @@ public AWSEBDeploymentConfig replacedCopy(Utils.Replacer r) throws MacroEvaluati this.getSleepTime(), this.isCheckHealth(), this.getMaxAttempts(), - this.credentials + this.credentials, + this.isCreateEnvironmentIfNotExist(), + r.r(this.getEnvironmentCNAMEPrefix()), + r.r(this.getEnvironmentTemplateName()), + evalSettings, + this.isRoute53UpdateRecordSet(), + r.r(this.getRoute53HostedZoneId()), + evalDomainNames, + this.route53RecordTTL, + r.r(this.getRoute53RecordType()) ); } } diff --git a/src/main/java/br/com/ingenieux/jenkins/plugins/awsebdeployment/AWSEBRawConfigurationOptionSetting.java b/src/main/java/br/com/ingenieux/jenkins/plugins/awsebdeployment/AWSEBRawConfigurationOptionSetting.java new file mode 100644 index 0000000..8b18723 --- /dev/null +++ b/src/main/java/br/com/ingenieux/jenkins/plugins/awsebdeployment/AWSEBRawConfigurationOptionSetting.java @@ -0,0 +1,34 @@ +package br.com.ingenieux.jenkins.plugins.awsebdeployment; + +import java.io.Serializable; +import hudson.Extension; +import hudson.model.AbstractDescribableImpl; +import hudson.model.Descriptor; +import lombok.Getter; +import lombok.Setter; +import org.kohsuke.stapler.DataBoundConstructor; + +public class AWSEBRawConfigurationOptionSetting extends AbstractDescribableImpl implements Serializable { + static final long serialVersionUID = 1L; + + @Getter @Setter private String namespace; + + @Getter @Setter private String optionName; + + @Getter @Setter private String value; + + @DataBoundConstructor + public AWSEBRawConfigurationOptionSetting(String namespace, String optionName, String value) { + this.namespace = namespace.trim(); + this.optionName = optionName.trim(); + this.value = value.trim(); + } + + @Extension + public static class DescriptorImpl extends Descriptor { + @Override + public String getDisplayName() { + return "Configuration Option Setting"; + } + } +} diff --git a/src/main/java/br/com/ingenieux/jenkins/plugins/awsebdeployment/AWSEBRoute53DomainName.java b/src/main/java/br/com/ingenieux/jenkins/plugins/awsebdeployment/AWSEBRoute53DomainName.java new file mode 100644 index 0000000..0d008ba --- /dev/null +++ b/src/main/java/br/com/ingenieux/jenkins/plugins/awsebdeployment/AWSEBRoute53DomainName.java @@ -0,0 +1,32 @@ +package br.com.ingenieux.jenkins.plugins.awsebdeployment; + +import hudson.Extension; +import hudson.model.AbstractDescribableImpl; +import hudson.model.Descriptor; +import lombok.Getter; +import lombok.Setter; +import org.kohsuke.stapler.DataBoundConstructor; + +import java.io.Serializable; + +public class AWSEBRoute53DomainName extends AbstractDescribableImpl implements Serializable { + static final long serialVersionUID = 1L; + + @Getter + @Setter + private String name; + + + @DataBoundConstructor + public AWSEBRoute53DomainName(String name) { + this.name = name.trim(); + } + + @Extension + public static class DescriptorImpl extends Descriptor { + @Override + public String getDisplayName() { + return "Domain Name"; + } + } +} diff --git a/src/main/java/br/com/ingenieux/jenkins/plugins/awsebdeployment/Constants.java b/src/main/java/br/com/ingenieux/jenkins/plugins/awsebdeployment/Constants.java index e4a57c7..0af3c71 100644 --- a/src/main/java/br/com/ingenieux/jenkins/plugins/awsebdeployment/Constants.java +++ b/src/main/java/br/com/ingenieux/jenkins/plugins/awsebdeployment/Constants.java @@ -19,9 +19,9 @@ public interface Constants { String DEFAULT_REGION = "us-east-1"; - int MAX_ATTEMPTS = 30; + int MAX_ATTEMPTS = 90; - int SLEEP_TIME = 90; + int SLEEP_TIME = 30; int MAX_ENVIRONMENT_NAME_LENGTH = 40; diff --git a/src/main/java/br/com/ingenieux/jenkins/plugins/awsebdeployment/cmd/CreateOrUpdateEnvironment.java b/src/main/java/br/com/ingenieux/jenkins/plugins/awsebdeployment/cmd/CreateOrUpdateEnvironment.java new file mode 100644 index 0000000..b743ac4 --- /dev/null +++ b/src/main/java/br/com/ingenieux/jenkins/plugins/awsebdeployment/cmd/CreateOrUpdateEnvironment.java @@ -0,0 +1,64 @@ +package br.com.ingenieux.jenkins.plugins.awsebdeployment.cmd; + + +import br.com.ingenieux.jenkins.plugins.awsebdeployment.AWSEBRawConfigurationOptionSetting; +import com.amazonaws.services.elasticbeanstalk.model.*; + +import java.util.ArrayList; +import java.util.List; + +public class CreateOrUpdateEnvironment extends DeployerCommand { + + @Override + public boolean perform() throws Exception { + DescribeEnvironmentsRequest deReq = new DescribeEnvironmentsRequest(). + withApplicationName(getApplicationName()). + withEnvironmentNames(getEnvironmentName()). + withIncludeDeleted(false); + + DescribeEnvironmentsResult deRes = getAwseb().describeEnvironments(deReq); + final String environmentId; + + List list = new ArrayList(); + for(AWSEBRawConfigurationOptionSetting setting :getEnvironmentSettings()){ + ConfigurationOptionSetting configurationOptionSetting = new ConfigurationOptionSetting( + setting.getNamespace(), + setting.getOptionName(), + setting.getValue() + ); + list.add(configurationOptionSetting); + } + ConfigurationOptionSetting[] configurationOptionSettings = list.toArray(new ConfigurationOptionSetting[list.size()]); + + if (1 > deRes.getEnvironments().size()) { + CreateEnvironmentRequest ceReq = new CreateEnvironmentRequest() + .withApplicationName(getApplicationName()) + .withEnvironmentName(getEnvironmentName()) + .withCNAMEPrefix(getEnvironmentCNAMEPrefix()) + .withTemplateName(getEnvironmentTemplateName()) + .withVersionLabel(getVersionLabel()) + .withOptionSettings(configurationOptionSettings); + + final CreateEnvironmentResult ceRes = getAwseb().createEnvironment(ceReq); + + environmentId = ceRes.getEnvironmentId(); + + log("Created environmentId '%s' with Version Label set to '%s'", environmentId, getVersionLabel()); + } else { + environmentId = deRes.getEnvironments().get(0).getEnvironmentId(); + + UpdateEnvironmentRequest ueReq = new UpdateEnvironmentRequest() + .withEnvironmentId(environmentId) + .withVersionLabel(getVersionLabel()) + .withOptionSettings(configurationOptionSettings); + + getAwseb().updateEnvironment(ueReq); + + log("Updated environmentId '%s' with Version Label set to '%s'", environmentId, getVersionLabel()); + } + + setEnvironmentId(environmentId); + + return false; + } +} diff --git a/src/main/java/br/com/ingenieux/jenkins/plugins/awsebdeployment/cmd/DeployerChain.java b/src/main/java/br/com/ingenieux/jenkins/plugins/awsebdeployment/cmd/DeployerChain.java index 504a8bf..3a35883 100644 --- a/src/main/java/br/com/ingenieux/jenkins/plugins/awsebdeployment/cmd/DeployerChain.java +++ b/src/main/java/br/com/ingenieux/jenkins/plugins/awsebdeployment/cmd/DeployerChain.java @@ -89,7 +89,9 @@ private void buildCommandList() { new DeployerCommand.CreateApplicationVersion() ); - if (c.deployerConfig.isZeroDowntime()) { + if (c.deployerConfig.isCreateEnvironmentIfNotExist()) { + commandList.add(new CreateOrUpdateEnvironment()); + } else if (c.deployerConfig.isZeroDowntime()) { commandList.add(new ZeroDowntime()); } else { commandList.add(new DeployerCommand.LookupEnvironmentId()); @@ -107,6 +109,10 @@ private void buildCommandList() { commandList.add(new DeployerCommand.WaitForEnvironment(WaitFor.Status)); } + if (c.deployerConfig.isRoute53UpdateRecordSet()) { + commandList.add(new UpdateCNAME()); + } + commandList.add(new DeployerCommand.MarkAsSuccessful()); } } diff --git a/src/main/java/br/com/ingenieux/jenkins/plugins/awsebdeployment/cmd/DeployerCommand.java b/src/main/java/br/com/ingenieux/jenkins/plugins/awsebdeployment/cmd/DeployerCommand.java index a43add0..07ea9e8 100644 --- a/src/main/java/br/com/ingenieux/jenkins/plugins/awsebdeployment/cmd/DeployerCommand.java +++ b/src/main/java/br/com/ingenieux/jenkins/plugins/awsebdeployment/cmd/DeployerCommand.java @@ -28,6 +28,7 @@ import com.amazonaws.services.elasticbeanstalk.model.EventDescription; import com.amazonaws.services.elasticbeanstalk.model.S3Location; import com.amazonaws.services.elasticbeanstalk.model.UpdateEnvironmentRequest; +import com.amazonaws.services.route53.AmazonRoute53Client; import com.amazonaws.services.s3.AmazonS3Client; import com.amazonaws.util.VersionInfoUtils; @@ -119,6 +120,13 @@ public boolean perform() throws Exception { setVersionLabel(getDeployerConfig().getVersionLabelFormat()); setVersionDescription(getDeployerConfig().getVersionDescriptionFormat()); setEnvironmentName(getDeployerConfig().getEnvironmentName()); + setEnvironmentCNAMEPrefix(getDeployerConfig().getEnvironmentCNAMEPrefix()); + setEnvironmentTemplateName(getDeployerConfig().getEnvironmentTemplateName()); + setEnvironmentSettings(getDeployerConfig().getEnvironmentSettings()); + setRoute53HostedZoneId(getDeployerConfig().getRoute53HostedZoneId()); + setRoute53DomainNames(getDeployerConfig().getRoute53DomainNames()); + setRoute53RecordTTL(getDeployerConfig().getRoute53RecordTTL()); + setRoute53RecordType(getDeployerConfig().getRoute53RecordType()); Validate.notEmpty(getEnvironmentName(), "Empty/blank environmentName parameter"); Validate.notEmpty(getApplicationName(), "Empty/blank applicationName parameter"); @@ -150,6 +158,7 @@ public boolean perform() throws Exception { setS3(factory.getService(AmazonS3Client.class)); setAwseb(factory.getService(AWSElasticBeanstalkClient.class)); + setRoute53(factory.getService(AmazonRoute53Client.class)); return false; } @@ -447,4 +456,5 @@ public boolean perform() throws Exception { return false; } } + } diff --git a/src/main/java/br/com/ingenieux/jenkins/plugins/awsebdeployment/cmd/DeployerContext.java b/src/main/java/br/com/ingenieux/jenkins/plugins/awsebdeployment/cmd/DeployerContext.java index 735bfcf..734ded4 100644 --- a/src/main/java/br/com/ingenieux/jenkins/plugins/awsebdeployment/cmd/DeployerContext.java +++ b/src/main/java/br/com/ingenieux/jenkins/plugins/awsebdeployment/cmd/DeployerContext.java @@ -17,8 +17,11 @@ package br.com.ingenieux.jenkins.plugins.awsebdeployment.cmd; import br.com.ingenieux.jenkins.plugins.awsebdeployment.AWSEBDeploymentConfig; +import br.com.ingenieux.jenkins.plugins.awsebdeployment.AWSEBRawConfigurationOptionSetting; +import br.com.ingenieux.jenkins.plugins.awsebdeployment.AWSEBRoute53DomainName; import br.com.ingenieux.jenkins.plugins.awsebdeployment.Constants; import com.amazonaws.services.elasticbeanstalk.AWSElasticBeanstalk; +import com.amazonaws.services.route53.AmazonRoute53; import com.amazonaws.services.s3.AmazonS3; import hudson.FilePath; import hudson.model.TaskListener; @@ -27,6 +30,7 @@ import java.io.PrintStream; import java.io.Serializable; +import java.util.List; @RequiredArgsConstructor @Data @@ -58,6 +62,11 @@ public class DeployerContext implements Constants, Serializable { */ transient AWSElasticBeanstalk awseb; + /** + * Elastic Beanstalk Client + */ + transient AmazonRoute53 route53; + /** * Logger Object */ @@ -112,4 +121,27 @@ public class DeployerContext implements Constants, Serializable { * SuccessfulP */ boolean successfulP; + + /** + * Environment CNAME Prefix + */ + String environmentCNAMEPrefix; + + /** + * Environment Template Name + */ + String environmentTemplateName; + + /** + * Environment Config Option Settings + */ + List environmentSettings; + + String route53HostedZoneId; + + List route53DomainNames; + + Long route53RecordTTL; + + String route53RecordType; } diff --git a/src/main/java/br/com/ingenieux/jenkins/plugins/awsebdeployment/cmd/UpdateCNAME.java b/src/main/java/br/com/ingenieux/jenkins/plugins/awsebdeployment/cmd/UpdateCNAME.java new file mode 100644 index 0000000..aea5633 --- /dev/null +++ b/src/main/java/br/com/ingenieux/jenkins/plugins/awsebdeployment/cmd/UpdateCNAME.java @@ -0,0 +1,77 @@ +package br.com.ingenieux.jenkins.plugins.awsebdeployment.cmd; + +import br.com.ingenieux.jenkins.plugins.awsebdeployment.AWSEBRoute53DomainName; +import com.amazonaws.services.elasticbeanstalk.model.DescribeEnvironmentsRequest; +import com.amazonaws.services.elasticbeanstalk.model.DescribeEnvironmentsResult; +import com.amazonaws.services.route53.model.Change; +import com.amazonaws.services.route53.model.ChangeAction; +import com.amazonaws.services.route53.model.ChangeBatch; +import com.amazonaws.services.route53.model.ChangeResourceRecordSetsRequest; +import com.amazonaws.services.route53.model.ResourceRecord; +import com.amazonaws.services.route53.model.ResourceRecordSet; + +import java.util.ArrayList; +import java.util.List; + +/** + * Update CNAME + */ +public class UpdateCNAME extends DeployerCommand { + + @Override + public boolean perform() throws Exception { + final DescribeEnvironmentsRequest req = new DescribeEnvironmentsRequest(). + withApplicationName(getApplicationName()). + withEnvironmentIds(getEnvironmentId()). + withIncludeDeleted(false); + + final DescribeEnvironmentsResult result = getAwseb().describeEnvironments(req); + + if (1 != result.getEnvironments().size()) { + log("Environment w/ environmentId '%s' not found. Aborting.", getEnvironmentId()); + + return true; + } + + if (getRoute53DomainNames().isEmpty()) { + return false; + } + + String newRecordValue = result.getEnvironments().get(0).getCNAME(); + + ResourceRecord resourceRecord = new ResourceRecord() + .withValue(newRecordValue); + + List resourceRecords = new ArrayList(); + resourceRecords.add(resourceRecord); + + List changes = new ArrayList(); + + for (AWSEBRoute53DomainName domainName : getRoute53DomainNames()) { + ResourceRecordSet resourceRecordSet = new ResourceRecordSet() + .withName(domainName.getName()) + .withTTL(getRoute53RecordTTL()) + .withType(getRoute53RecordType()) + .withResourceRecords(resourceRecords); + + Change change = new Change() + .withAction(ChangeAction.UPSERT) + .withResourceRecordSet(resourceRecordSet); + + changes.add(change); + + log("Pointing %s to %s", newRecordValue, domainName.getName()); + } + + ChangeBatch changeBatch = new ChangeBatch() + .withChanges(changes); + + final ChangeResourceRecordSetsRequest crrsReq = new ChangeResourceRecordSetsRequest() + .withHostedZoneId(getRoute53HostedZoneId()) + .withChangeBatch(changeBatch); + + getRoute53().changeResourceRecordSets(crrsReq); + + return false; + } +} \ No newline at end of file diff --git a/src/main/resources/br/com/ingenieux/jenkins/plugins/awsebdeployment/AWSEBDeploymentBuilder/config.jelly b/src/main/resources/br/com/ingenieux/jenkins/plugins/awsebdeployment/AWSEBDeploymentBuilder/config.jelly index c1388c4..f28da8d 100644 --- a/src/main/resources/br/com/ingenieux/jenkins/plugins/awsebdeployment/AWSEBDeploymentBuilder/config.jelly +++ b/src/main/resources/br/com/ingenieux/jenkins/plugins/awsebdeployment/AWSEBDeploymentBuilder/config.jelly @@ -48,6 +48,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    +
    +
    +
    +
    @@ -106,4 +139,37 @@ + + + + + + + + + + + + + + + + + +
    + +
    +
    +
    +
    +
    + + + + + + + + +