Skip to content

Commit

Permalink
#1877 ConnectsInstance
Browse files Browse the repository at this point in the history
  • Loading branch information
yegor256 committed Feb 27, 2024
1 parent 5bfd789 commit afdcf97
Show file tree
Hide file tree
Showing 3 changed files with 128 additions and 63 deletions.
20 changes: 13 additions & 7 deletions src/main/java/com/rultor/agents/Agents.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import com.jcabi.s3.retry.ReRegion;
import com.jcabi.ssh.Ssh;
import com.rultor.agents.aws.AwsEc2;
import com.rultor.agents.aws.ConnectsInstance;
import com.rultor.agents.aws.KillsInstance;
import com.rultor.agents.aws.PingsInstance;
import com.rultor.agents.aws.StartsInstance;
Expand Down Expand Up @@ -275,13 +276,6 @@ public Agent agent(final Talk talk, final Profile profile)
new Agent.Disabled(
new StartsInstance(
aws,
new PfShell(
profile,
"none",
Agents.PORT,
"ubuntu",
Agents.priv()
),
Manifests.read("Rultor-EC2Image"),
Manifests.read("Rultor-EC2Type"),
Manifests.read("Rultor-EC2Group"),
Expand All @@ -290,6 +284,18 @@ public Agent agent(final Talk talk, final Profile profile)
false
)
),
new Agent.Quiet(
new ConnectsInstance(
aws,
new PfShell(
profile,
"none",
Agents.PORT,
"ubuntu",
Agents.priv()
)
)
),
new RegistersShell(
profile,
Agents.HOST, Agents.PORT, Agents.LOGIN,
Expand Down
111 changes: 111 additions & 0 deletions src/main/java/com/rultor/agents/aws/ConnectsInstance.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/*
* Copyright (c) 2009-2024 Yegor Bugayenko
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met: 1) Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer. 2) Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution. 3) Neither the name of the rultor.com nor
* the names of its contributors may be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
* NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.rultor.agents.aws;

import com.amazonaws.services.ec2.model.DescribeInstanceStatusRequest;
import com.amazonaws.services.ec2.model.DescribeInstanceStatusResult;
import com.amazonaws.services.ec2.model.DescribeInstancesRequest;
import com.amazonaws.services.ec2.model.Instance;
import com.amazonaws.services.ec2.model.InstanceState;
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 java.io.IOException;
import lombok.ToString;
import org.xembly.Directive;
import org.xembly.Directives;

/**
* Connects a running EC2 instance: detects its IP.
*
* @since 1.77
*/
@Immutable
@ToString
public final class ConnectsInstance extends AbstractAgent {

/**
* AWS Client.
*/
private final transient AwsEc2 api;

/**
* Shell.
*/
private final transient PfShell shell;

/**
* Ctor.
* @param aws API
* @param shll The shell
*/
public ConnectsInstance(final AwsEc2 aws, final PfShell shll) {
super("/talk[daemon and ec2 and not(shell)]");
this.api = aws;
this.shell = shll;
}

@Override
public Iterable<Directive> process(final XML xml) throws IOException {
final String instance = xml.xpath("/talk/ec2/@id").get(0);
while (true) {
final DescribeInstanceStatusResult res = this.api.aws().describeInstanceStatus(
new DescribeInstanceStatusRequest()
.withIncludeAllInstances(true)
.withInstanceIds(instance)
);
final InstanceState state = res.getInstanceStatuses().get(0).getInstanceState();
Logger.info(this, "AWS instance %s state: %s", instance, state.getName());
if ("running".equals(state.getName())) {
break;
}
new Sleep(5L).now();
}
final Instance ready = this.api.aws().describeInstances(
new DescribeInstancesRequest()
.withInstanceIds(instance)
).getReservations().get(0).getInstances().get(0);
Logger.info(
this, "AWS instance %s launched and running at %s",
ready.getInstanceId(), ready.getPublicIpAddress()
);
new Sleep(60L).now();
final Directives dirs = new Directives();
dirs.xpath("/talk").add("shell")
.attr("id", xml.xpath("/talk/daemon/@id").get(0))
.add("host").set(ready.getPublicDnsName()).up()
.add("port").set(Integer.toString(this.shell.port())).up()
.add("login").set(this.shell.login()).up()
.add("key").set(this.shell.key());
return dirs;
}
}
60 changes: 4 additions & 56 deletions src/main/java/com/rultor/agents/aws/StartsInstance.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,19 +30,14 @@
package com.rultor.agents.aws;

import com.amazonaws.services.ec2.model.CreateTagsRequest;
import com.amazonaws.services.ec2.model.DescribeInstanceStatusRequest;
import com.amazonaws.services.ec2.model.DescribeInstanceStatusResult;
import com.amazonaws.services.ec2.model.DescribeInstancesRequest;
import com.amazonaws.services.ec2.model.Instance;
import com.amazonaws.services.ec2.model.InstanceState;
import com.amazonaws.services.ec2.model.RunInstancesRequest;
import com.amazonaws.services.ec2.model.RunInstancesResult;
import com.amazonaws.services.ec2.model.Tag;
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;
Expand All @@ -63,11 +58,6 @@ public final class StartsInstance extends AbstractAgent {
*/
private final transient AwsEc2 api;

/**
* Shell.
*/
private final transient PfShell shell;

/**
* Amazon machine image id.
*/
Expand All @@ -91,19 +81,17 @@ public final class StartsInstance extends AbstractAgent {
/**
* Ctor.
* @param aws API
* @param shll The shell
* @param image Instance AMI image name to run
* @param tpe Type of instance, like "t1.micro"
* @param grp Security group, like "sg-38924038290"
* @param net Subnet, like "subnet-0890890"
* @checkstyle ParameterNumberCheck (5 lines)
*/
public StartsInstance(final AwsEc2 aws,
final PfShell shll, final String image, final String tpe,
final String image, final String tpe,
final String grp, final String net) {
super("/talk[daemon and not(shell)]");
this.api = aws;
this.shell = shll;
this.image = image;
this.type = tpe;
this.sgroup = grp;
Expand All @@ -112,35 +100,17 @@ public StartsInstance(final AwsEc2 aws,

@Override
public Iterable<Directive> process(final XML xml) throws IOException {
final String hash = xml.xpath("/talk/daemon/@id").get(0);
final Directives dirs = new Directives();
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 Instance instance = this.run(xml.xpath("/talk/@name").get(0));
Logger.info(
this, "EC2 instance %s on %s started in %s",
instance.getInstanceId(), instance.getPublicIpAddress(),
xml.xpath("/talk/@name").get(0)
);
dirs.xpath("/talk").add("ec2")
dirs.xpath("/talk")
.add("ec2")
.attr("id", instance.getInstanceId());
dirs.xpath("/talk").add("shell")
.attr("id", hash)
.add("host").set(instance.getPublicDnsName()).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(
Expand Down Expand Up @@ -178,28 +148,6 @@ private Instance run(final String talk) {
.withResources(iid)
.withTags(new Tag().withKey("Name").withValue(talk))
);
while (true) {
final DescribeInstanceStatusResult res = this.api.aws().describeInstanceStatus(
new DescribeInstanceStatusRequest()
.withIncludeAllInstances(true)
.withInstanceIds(iid)
);
final InstanceState state = res.getInstanceStatuses().get(0).getInstanceState();
Logger.info(this, "AWS instance %s state: %s", iid, state.getName());
if ("running".equals(state.getName())) {
break;
}
new Sleep(5L).now();
}
final Instance ready = this.api.aws().describeInstances(
new DescribeInstancesRequest()
.withInstanceIds(iid)
).getReservations().get(0).getInstances().get(0);
Logger.info(
this, "AWS instance %s launched and running at %s",
ready.getInstanceId(), ready.getPublicIpAddress()
);
new Sleep(60L).now();
return ready;
return instance;
}
}

0 comments on commit afdcf97

Please sign in to comment.