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.CommandStatus.*
import com.amazonaws.services.simplesystemsmanagement.model.ListCommandsRequest
import com.amazonaws.services.simplesystemsmanagement.model.SendCommandRequest
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 command = systemsManagement.sendCommand(request).command
log.info("Awaiting termination of $command")
awaitTermination(command.commandId)
} 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(
commandId: String
) {
val terminalStates = setOf(
Cancelled,
Failed,
Success,
TimedOut
)
while (true) {
val status = pollStatus(commandId)
if (terminalStates.contains(status)) {
if (status == Success) {
log.info("$commandId successfully terminated")
break
} else {
throw RuntimeException("$commandId unsuccessfully terminated")
}
} else {
log.info("$commandId did not terminate yet")
Thread.sleep(5000)
}
}
}
private fun pollStatus(
commandId: String
): CommandStatus {
val command = systemsManagement
.listCommands(ListCommandsRequest().withCommandId(commandId))
.commands
.first()
log.info("Polled $command")
return CommandStatus.fromValue(command.status)
}
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 }
}
}