Groovy Programmer : How to start / stop a EC2 instance with Groovy

Groovy is a great language for scripting. As a JVM language, it allows us to use many Java libraries already available. In this project we are going to start and stop a EC2 instance from a Spock test.

ec2_management_console

Lets create a Gradle project with the Groovy plugin. Add Spock dependencies and AWS Java SDK.

apply plugin: 'groovy'
repositories {
    jcenter()
}
ext {
    groovyVersion = '2.4.7'
}
dependencies {
    compile "org.codehaus.groovy:groovy-all:$groovyVersion"
    testCompile "org.spockframework:spock-core:1.0-groovy-2.4"
    compile 'com.amazonaws:aws-java-sdk-ec2:1.10.61'
}
test {
    systemProperties System.properties
}

Lets add a class <i>src/main/groovy/gwebbot/ec2/AWSCreds.groovy</i>. It implements the AWSCredentials Interface.

package gwebbot.ec2

import com.amazonaws.auth.AWSCredentials

class AWSCreds implements AWSCredentials {
    String access
    String secret

    @Override
    String getAWSAccessKeyId() {
        access
    }

    @Override
    String getAWSSecretKey() {
        secret
    }
}

I coded a <i>src/main/groovy/gwebbot/ec2/AEC2Utils.groovy</i> class to help me with the start / stop of instances.

package gwebbot.ec2

import com.amazonaws.services.ec2.AmazonEC2
import com.amazonaws.services.ec2.model.Instance
import com.amazonaws.services.ec2.model.Reservation
import com.amazonaws.services.ec2.model.StartInstancesRequest
import com.amazonaws.services.ec2.model.StopInstancesRequest
import com.amazonaws.services.ec2.model.Tag

class EC2Utils {

    static String instanceStateByName(AmazonEC2 ec2client, String intanceName) {
        for ( Reservation reservation : ec2client.describeInstances().reservations ) {
            Instance instance = reservation.instances.find { findInstanceNameWithTags(it) == intanceName }
            if (instance) {
                return instance.state.name
            }
        }
        null
    }

    static String instancePublicDnsNameByName(AmazonEC2 ec2client, String intanceName) {
        for ( Reservation reservation : ec2client.describeInstances().reservations ) {
            Instance instance = reservation.instances.find { findInstanceNameWithTags(it) == intanceName }
            if ( instance ) {
                return instance.publicDnsName
            }
        }
        null
    }

    static void startInstanceWithName(AmazonEC2 ec2client, String name) {
        for ( Reservation reservation : ec2client.describeInstances().reservations ) {
            Instance inst = reservation.instances.find {findInstanceNameWithTags(it) == name }
            if ( inst ) {
                ec2client.startInstances(new StartInstancesRequest([inst.instanceId]))
            }
        }
    }
    static void stopInstanceWithName(AmazonEC2 ec2client, String name) {
        for (Reservation reservation : ec2client.describeInstances().reservations) {
            Instance inst = reservation.instances.find {findInstanceNameWithTags(it) == name }
            if ( inst ) {
                ec2client.stopInstances(new StopInstancesRequest([inst.instanceId]))
            }
        }
    }

    static String findInstanceNameWithTags(Instance instance) {
        for ( Tag tag : instance.tags ) {
            if ( tag.key.toLowerCase() == 'name' ) {
                return tag.value
            }
        }
        null
    }
}

And this is the test which verifies the start / stop works.

 
package gwebbot.ec2

import com.amazonaws.services.ec2.AmazonEC2
import com.amazonaws.services.ec2.AmazonEC2Client
import spock.lang.IgnoreIf
import spock.lang.Specification

class EC2UtilsSpec extends Specification {

    @IgnoreIf({ !System.properties['AWS_ACCESS_KEY_ID'] || 
                !System.properties['AWS_SECRET_KEY'] || 
                !System.properties['EC2_ENDPOINT'] })
    def "test start and stop a machine"() {
        given:
        AWSCreds credentials = new AWSCreds(access: System.properties['AWS_ACCESS_KEY_ID'],
                secret: System.properties['AWS_SECRET_KEY'])

        // http://docs.aws.amazon.com/general/latest/gr/rande.html#ec2_region
        String endpoint = System.properties['EC2_ENDPOINT']
        AmazonEC2 ec2client = new AmazonEC2Client(credentials)
        ec2client.endpoint = endpoint
        int fiveMinutes = 60 * 5 * 1_000

        when:
        String instanceName = 'Wolf1'
        String state = EC2Utils.instanceStateByName(ec2client, instanceName)

        then:
        notThrown AmazonServiceException
        state == 'stopped'

        when:
        EC2Utils.startInstanceWithName(ec2client, instanceName)
        sleep(fiveMinutes)
        state = EC2Utils.instanceStateByName(ec2client, instanceName)

        then:
        state == 'running'

        when:
        EC2Utils.stopInstanceWithName(ec2client, instanceName)
        sleep(fiveMinutes)
        state = EC2Utils.instanceStateByName(ec2client, instanceName)

        then:
        state == 'stopped'
    }
}

We can execute the tests with:

 ./gradlew -DAWS_ACCESS_KEY_ID=XXXXX -DAWS_SECRET_KEY=XXXXX -DEC2_ENDPOINT=ec2.eu-west-1.amazonaws.com test

Do you like to read about Grails / Groovy development? If the answer is yes, subscribe to Groovy Calamari. A weekly curated email newsletter about the Groovy ecosystem. Curated by me 🎉

Leave a Reply

Your email address will not be published. Required fields are marked *