Skip to content

Commit

Permalink
#1877 kills and pings
Browse files Browse the repository at this point in the history
  • Loading branch information
yegor256 committed Feb 27, 2024
1 parent df9b9d5 commit bc8f5e8
Show file tree
Hide file tree
Showing 5 changed files with 261 additions and 28 deletions.
22 changes: 10 additions & 12 deletions src/main/java/com/rultor/agents/Agents.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@
import com.jcabi.s3.retry.ReRegion;
import com.jcabi.ssh.Ssh;
import com.rultor.agents.aws.AwsEc2;
import com.rultor.agents.aws.KillsInstance;
import com.rultor.agents.aws.PingsInstance;
import com.rultor.agents.aws.StartsInstance;
import com.rultor.agents.aws.StopsInstance;
import com.rultor.agents.daemons.ArchivesDaemon;
Expand Down Expand Up @@ -255,6 +257,10 @@ public Agent agent(final Talk talk, final Profile profile)
)
)
);
final AwsEc2 aws = new AwsEc2(
Manifests.read("Rultor-EC2Key"),
Manifests.read("Rultor-EC2Secret")
);
return new VerboseAgent(
new Agent.Iterative(
new SanitizesDaemon(),
Expand All @@ -268,10 +274,7 @@ public Agent agent(final Talk talk, final Profile profile)
new Agent.Quiet(
new Agent.Disabled(
new StartsInstance(
new AwsEc2(
Manifests.read("Rultor-EC2Key"),
Manifests.read("Rultor-EC2Secret")
),
aws,
new PfShell(
profile,
"none",
Expand Down Expand Up @@ -317,14 +320,9 @@ public Agent agent(final Talk talk, final Profile profile)
new ReleaseBinaries(this.github, profile),
new Dephantomizes(this.github),
new Reports(this.github),
new Agent.Quiet(
new StopsInstance(
new AwsEc2(
Manifests.read("Rultor-EC2Key"),
Manifests.read("Rultor-EC2Secret")
)
)
),
new Agent.Quiet(new StopsInstance(aws)),
new Agent.Quiet(new PingsInstance()),
new Agent.Quiet(new KillsInstance(aws, TimeUnit.HOURS.toMinutes(2L))),
new RemovesShell(),
new ArchivesDaemon(
new ReRegion(
Expand Down
85 changes: 85 additions & 0 deletions src/main/java/com/rultor/agents/aws/KillsInstance.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*
* 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.StopInstancesRequest;
import com.jcabi.aspects.Immutable;
import com.jcabi.log.Logger;
import com.jcabi.xml.XML;
import com.rultor.agents.AbstractAgent;
import java.io.IOException;
import lombok.ToString;
import org.xembly.Directive;
import org.xembly.Directives;

/**
* Kills EC2 instance if it's older than X hours.
*
* @since 1.77
*/
@Immutable
@ToString
public final class KillsInstance extends AbstractAgent {

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

/**
* Ctor.
* @param aws API
* @param mins Max age in minutes
*/
public KillsInstance(final AwsEc2 aws, final long mins) {
super(
"/talk/ec2",
"/talk/daemon[started and not(code) and not(ended)]",
"/talk/daemon/dir",
String.format(
// @checkstyle LineLength (1 line)
"/talk[(current-dateTime() - xs:dateTime(daemon/started)) div xs:dayTimeDuration('PT1M') > %d]",
mins
)
);
this.api = aws;
}

@Override
public Iterable<Directive> process(final XML xml) throws IOException {
final String instance = xml.xpath("/talk/ec2/@id").get(0);
this.api.aws().stopInstances(
new StopInstancesRequest()
.withInstanceIds(instance)
);
Logger.info("Killed AWS instance %s because it's too old", instance);
return new Directives();
}
}
92 changes: 92 additions & 0 deletions src/main/java/com/rultor/agents/aws/PingsInstance.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/*
* 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.jcabi.aspects.Immutable;
import com.jcabi.log.Logger;
import com.jcabi.ssh.Shell;
import com.jcabi.xml.XML;
import com.rultor.agents.AbstractAgent;
import com.rultor.agents.shells.TalkShells;
import java.io.IOException;
import lombok.ToString;
import org.xembly.Directive;
import org.xembly.Directives;

/**
* Ping EC2 instance and deletes "daemon" if it doesn't reply.
*
* @since 1.77
*/
@Immutable
@ToString
public final class PingsInstance extends AbstractAgent {

/**
* Ctor.
*/
public PingsInstance() {
super(
"/talk/ec2",
"/talk/daemon",
"/talk/shell[host and port and login and key]"
);
}

@Override
@SuppressWarnings("PMD.AvoidCatchingGenericException")
public Iterable<Directive> process(final XML xml) throws IOException {
final Shell shell = new TalkShells(xml).get();
final Directives dirs = new Directives();
int attempt = 0;
while (true) {
try {
new Shell.Empty(new Shell.Safe(shell)).exec("whoami");
break;
// @checkstyle IllegalCatchCheck (1 line)
} catch (final Exception ex) {
Logger.warn(
this, "Failed to ping AWS instance %s at %s (attempt no.%d): %s",
xml.xpath("/talk/ec2/@id").get(0),
xml.xpath("/talk/shell/host/text()").get(0),
attempt,
ex.getMessage()
);
++attempt;
if (attempt > 5) {
dirs.xpath("/talk/daemon").remove();
break;
}
new Sleep(10L).now();
}
}
return dirs;
}
}
72 changes: 72 additions & 0 deletions src/main/java/com/rultor/agents/aws/Sleep.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* 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.jcabi.aspects.Immutable;
import com.jcabi.log.Logger;
import java.util.concurrent.TimeUnit;
import lombok.ToString;

/**
* Sleep.
*
* @since 1.77
*/
@Immutable
@ToString
final class Sleep {

/**
* Seconds.
*/
private final transient long seconds;

/**
* Ctor.
* @param scnd Seconds
*/
Sleep(final long scnd) {
this.seconds = scnd;
}

/**
* Sleep for a while.
*/
void now() {
try {
Logger.info(StartsInstance.class, "Sleeping for %d seconds...", this.seconds);
Thread.sleep(TimeUnit.SECONDS.toMillis(this.seconds));
} catch (final InterruptedException ex) {
Thread.currentThread().interrupt();
throw new IllegalStateException(ex);
}
}

}
18 changes: 2 additions & 16 deletions src/main/java/com/rultor/agents/aws/StartsInstance.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@
import com.rultor.agents.shells.PfShell;
import com.rultor.spi.Profile;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import lombok.ToString;
import org.xembly.Directive;
import org.xembly.Directives;
Expand Down Expand Up @@ -190,7 +189,7 @@ private Instance run(final String talk) {
if ("running".equals(state.getName())) {
break;
}
StartsInstance.sleep(5L);
new Sleep(5L).now();
}
final Instance ready = this.api.aws().describeInstances(
new DescribeInstancesRequest()
Expand All @@ -200,20 +199,7 @@ private Instance run(final String talk) {
this, "AWS instance %s launched and running at %s",
ready.getInstanceId(), ready.getPublicIpAddress()
);
StartsInstance.sleep(30L);
new Sleep(60L).now();
return ready;
}

/**
* Sleep for a while.
* @param seconds Seconds
*/
private static void sleep(final long seconds) {
try {
Thread.sleep(TimeUnit.SECONDS.toMillis(seconds));
} catch (final InterruptedException ex) {
Thread.currentThread().interrupt();
throw new IllegalStateException(ex);
}
}
}

0 comments on commit bc8f5e8

Please sign in to comment.