
com.atlassian.maven.plugins.aws.it.Executor.kt Maven / Gradle / Ivy
package com.atlassian.maven.plugins.aws.it
import com.amazonaws.services.ec2.model.Instance
import com.amazonaws.services.simplesystemsmanagement.AWSSimpleSystemsManagement
import com.amazonaws.services.simplesystemsmanagement.model.CommandStatus
import com.amazonaws.services.simplesystemsmanagement.model.GetCommandInvocationRequest
import com.amazonaws.services.simplesystemsmanagement.model.SendCommandRequest
import com.amazonaws.services.simplesystemsmanagement.model.SendCommandResult
import org.apache.maven.plugin.logging.Log
class Executor(
private val systemsManagement: AWSSimpleSystemsManagement,
private val log: Log
) {
fun execute(
steps: List,
instances: List
) {
steps.forEach { step ->
execute(step, instances)
}
}
private fun execute(
step: ProperExecutionStep,
instances: List
) {
val request = SendCommandRequest().withDocumentName("AWS-RunShellScript")
.withParameters(
mapOf(
"commands" to step.commands
)
)
.withInstanceIds(matchInstanceIds(step.target, instances))
.withTimeoutSeconds(step.timeout.seconds.toInt())
.withOutputS3BucketName("aws-integration-test-plugin")
.withOutputS3KeyPrefix("executor-output")
try {
log.info("Executing $request")
val execution = systemsManagement.sendCommand(request)
awaitTermination(execution)
} catch (e: Exception) {
val message = "Failed to execute $request, " +
"see https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/systems-manager-prereqs.html " +
"and https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/troubleshooting-remote-commands.html"
throw RuntimeException(message, e)
}
}
private fun awaitTermination(
execution: SendCommandResult
) {
val statusRequest = GetCommandInvocationRequest().withCommandId(execution.command.commandId)
val terminalStates = setOf(
CommandStatus.Cancelled,
CommandStatus.Failed,
CommandStatus.Success,
CommandStatus.TimedOut
)
while (true) {
val commands = execution
.command
.instanceIds
.map { statusRequest.withInstanceId(it) }
.map { systemsManagement.getCommandInvocation(it) }
val statuses = commands
.map { it.status }
.map { CommandStatus.fromValue(it) }
val terminated = statuses.all { terminalStates.contains(it) }
if (terminated) {
if (statuses.all { it == CommandStatus.Success }) {
log.info("All commands successfully terminated: $commands")
break
} else {
throw RuntimeException("Some commands unsuccessfully terminated: $commands")
}
} else {
log.info("Some commands are still not terminated: $commands")
Thread.sleep(5000)
}
}
}
private fun matchInstanceIds(
target: ResourceTag,
instances: Collection
): List {
return instances
.filter {
it.tags.any {
it.key == target.key && it.value == target.value
}
}
.map { it.instanceId }
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy