All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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