diff --git a/pom.xml b/pom.xml index ef51b79df9..ba4f5d27f6 100644 --- a/pom.xml +++ b/pom.xml @@ -117,12 +117,12 @@ OF THE POSSIBILITY OF SUCH DAMAGE. com.amazonaws aws-java-sdk-ec2 - 1.12.658 + 1.12.659 com.amazonaws aws-java-sdk-core - 1.12.658 + 1.12.659 com.jcabi.incubator diff --git a/src/main/java/com/rultor/agents/Agents.java b/src/main/java/com/rultor/agents/Agents.java index c5cc1e151f..95e9ebe501 100644 --- a/src/main/java/com/rultor/agents/Agents.java +++ b/src/main/java/com/rultor/agents/Agents.java @@ -270,7 +270,10 @@ public Agent agent(final Talk talk, final Profile profile) Manifests.read("Rultor-EC2Secret") ), Manifests.read("Rultor-EC2Image") - ) + ), + profile, + Agents.PORT, Agents.LOGIN, + Agents.priv() ), new RegistersShell( profile, diff --git a/src/main/java/com/rultor/agents/aws/AwsEc2Instance.java b/src/main/java/com/rultor/agents/aws/AwsEc2Instance.java index 76c4cf369e..85c07acae7 100644 --- a/src/main/java/com/rultor/agents/aws/AwsEc2Instance.java +++ b/src/main/java/com/rultor/agents/aws/AwsEc2Instance.java @@ -33,6 +33,7 @@ import com.amazonaws.services.ec2.model.CreateTagsRequest; import com.amazonaws.services.ec2.model.DryRunResult; import com.amazonaws.services.ec2.model.DryRunSupportedRequest; +import com.amazonaws.services.ec2.model.Instance; import com.amazonaws.services.ec2.model.StopInstancesRequest; import com.amazonaws.services.ec2.model.Tag; import com.jcabi.aspects.Immutable; @@ -48,7 +49,8 @@ @ToString @SuppressWarnings({"PMD.ShortMethodName", "PMD.ConstructorOnlyInitializesOrCallOtherConstructors", - "PMD.AvoidFieldNameMatchingMethodName" + "PMD.AvoidFieldNameMatchingMethodName", + "PMD.OnlyOneConstructorShouldDoInitialization" }) public final class AwsEc2Instance { /** @@ -56,11 +58,32 @@ public final class AwsEc2Instance { */ private final transient AwsEc2 api; + /** + * AWS Instance. + */ + private final Instance instance; + /** * AWS Instance id. */ private final String id; + /** + * Ctor. + * @param api AwsEc2 api client + * @param inst Instance + */ + public AwsEc2Instance(final AwsEc2 api, final Instance inst) { + if (inst == null) { + throw new IllegalArgumentException( + "Instance id is mandatory" + ); + } + this.api = api; + this.instance = inst; + this.id = this.instance.getInstanceId(); + } + /** * Ctor. * @param api AwsEc2 api client @@ -74,6 +97,7 @@ public AwsEc2Instance(final AwsEc2 api, final String id) { } this.api = api; this.id = id; + this.instance = new Instance().withInstanceId(id); } /** @@ -82,7 +106,7 @@ public AwsEc2Instance(final AwsEc2 api, final String id) { public void stop() { final DryRunSupportedRequest draft = () -> { final StopInstancesRequest request = new StopInstancesRequest() - .withInstanceIds(this.id); + .withInstanceIds(this.instance.getInstanceId()); return request.getDryRunRequest(); }; final AmazonEC2 client = this.api.aws(); @@ -126,4 +150,13 @@ public AwsEc2Instance tag(final String key, final String tag) { public String id() { return this.id; } + + /** + * Instance Ip. + * @return Instance Ipv6 address + * @checkstyle MethodNameCheck (3 lines) + */ + public String ipv6() { + return this.instance.getIpv6Address(); + } } diff --git a/src/main/java/com/rultor/agents/aws/StartsInstance.java b/src/main/java/com/rultor/agents/aws/StartsInstance.java index 56bd4cea6c..fd88321b8b 100644 --- a/src/main/java/com/rultor/agents/aws/StartsInstance.java +++ b/src/main/java/com/rultor/agents/aws/StartsInstance.java @@ -30,8 +30,11 @@ package com.rultor.agents.aws; import com.jcabi.aspects.Immutable; +import com.jcabi.log.Logger; import com.jcabi.xml.XML; import com.rultor.agents.AbstractAgent; +import com.rultor.agents.shells.PfShell; +import com.rultor.spi.Profile; import java.io.IOException; import lombok.ToString; import org.xembly.Directive; @@ -44,6 +47,7 @@ */ @Immutable @ToString +@SuppressWarnings("PMD.ConstructorOnlyInitializesOrCallOtherConstructors") public final class StartsInstance extends AbstractAgent { /** @@ -56,34 +60,95 @@ public final class StartsInstance extends AbstractAgent { */ private final String tag; + /** + * Shell in profile. + */ + private final transient PfShell shell; + /** * Ctor. * @param image Instance image to run + * @param profile Profile + * @param port Default Port of server + * @param user Default Login + * @param key Default Private SSH key + * @checkstyle ParameterNumberCheck (6 lines) */ - public StartsInstance(final AwsEc2Image image) { - this(image, "rultor"); + public StartsInstance(final AwsEc2Image image, final Profile profile, + final int port, final String user, final String key) { + this(image, "rultor", profile, port, user, key); } /** * Ctor. * @param image Instance image to run * @param tag Name tag value + * @param profile Profile + * @param port Default Port of server + * @param user Default Login + * @param key Default Private SSH key + * @checkstyle ParameterNumberCheck (6 lines) */ - public StartsInstance(final AwsEc2Image image, final String tag) { + public StartsInstance(final AwsEc2Image image, final String tag, + final Profile profile, final int port, + final String user, final String key) { super("/talk[daemon and not(shell)]"); + if (user.isEmpty()) { + throw new IllegalArgumentException( + "User name is mandatory" + ); + } + if (key.isEmpty()) { + throw new IllegalArgumentException( + "SSH key is mandatory" + ); + } this.image = image; this.tag = tag; + this.shell = new PfShell(profile, "", port, user, key); } @Override public Iterable process(final XML xml) throws IOException { + final String hash = xml.xpath("/talk/daemon/@id").get(0); final Directives dirs = new Directives(); - final AwsEc2Instance inst = this.image.run(); - if (!this.tag.isEmpty()) { - inst.tag("Name", this.tag); + try { + final String login = this.shell.login(); + if (login.isEmpty()) { + throw new Profile.ConfigException( + "SSH login is empty, it's a mistake" + ); + } + final String key = this.shell.key(); + if (key.isEmpty()) { + throw new Profile.ConfigException( + "SSH key is empty, it's a mistake" + ); + } + final AwsEc2Instance inst = this.image.run(); + if (!this.tag.isEmpty()) { + inst.tag("Name", this.tag); + } + Logger.info( + this, "EC2 instance %s on %s started in %s", + inst.id(), inst.ipv6(), + xml.xpath("/talk/@name").get(0) + ); + dirs.xpath("/talk").add("ec2") + .attr("id", inst.id()); + dirs.xpath("/talk").add("shell") + .attr("id", hash) + .add("host").set(inst.ipv6()).up() + .add("port").set(Integer.toString(this.shell.port())).up() + .add("login").set(login).up() + .add("key").set(key); + } catch (final Profile.ConfigException ex) { + dirs.xpath("/talk/daemon/script").set( + String.format( + "Failed to read profile: %s", ex.getLocalizedMessage() + ) + ); } - dirs.xpath("/talk").add("ec2") - .attr("id", inst.id()); return dirs; } }