19

I'm launching an EC2 instance, by invoking ec2-run-instances from simple a bash script, and want to perform further operations on that instance (e.g. associate elastic IP), for which I need the instance id.

The command is something like ec2-run-instances ami-dd8ea5a9 -K pk.pem -C cert.pem --region eu-west-1 -t c1.medium -n 1, and its output:

RESERVATION r-b6ea58c1    696664755663    default
INSTANCE    i-945af9e3    ami-dd8ea5b9    pending    0    c1.medium    2010-04-15T10:47:56+0000    eu-west-1a    aki-b02a01c4    ari-39c2e94d   

In this example, i-945af9e3 is the id I'm after.

So, I'd need a simple way to parse the id from what the command returns - how would you go about doing it? My AWK is a little rusty... Feel free to use any tool available on a typical Linux box. (If there's a way to get it directly using EC2-API-tools, all the better. But afaik there's no EC2 command to e.g. return the id of the most recently launched instance.)

Jonik
  • 80,077
  • 70
  • 264
  • 372

5 Answers5

22

Completing your correct answer, here is a shell script which creates an instance, runs some commands and deletes the instance. It uses awk in the same way as yours.

#!/bin/sh

# Creates an Amazon EC2 virtual machine (an instance) and runs some
# shell commands on it before terminating it. Just an example.
# Stephane Bortzmeyer <stephane+amazon@bortzmeyer.org>

# Parameters you can set.
# Choose an AMI you like (ami-02103876 is a Debian "lenny")
AMI=ami-02103876
# Create your key pair first, for instance on the Web interface
KEY=test-b
KEYDIR=.
# The user name to use depends on the AMI. "root" is common but check
# the documentation of the AMI.
USERNAME=root
# Needs to be a legal Unix group of commands
COMMANDS="(uname -a; df -h; cat /etc/debian_version)"
MAX_CONNECTS=4
MAX_TESTS=6

# If you want to change from the default region, set the environment
# variable EC2_URL for instance 'export
# EC2_URL=https://ec2.eu-west-1.amazonaws.com' to use the 'eu-west-1'
# region

# Also, be sure your default security group allows incoming SSH.

if [ "${EC2_PRIVATE_KEY}" = "" ] || [ "${EC2_CERT}" = "" ]; then
    echo "You need to have X.509 certificate and private key locally, and to set the environment variables EC2_PRIVATE_KEY and EC2_CERT to indicate their locations" 1>&2
    exit 1
fi

start=$(ec2-run-instances --key ${KEY} $AMI)
if [ $? != 0 ]; then
    echo "Machine did not start" 1>&2
    exit 1
fi

AMI_E=$(echo "$start" | awk '/^INSTANCE/ {print $3}')
if [ "$AMI_E" != "$AMI" ]; then
    echo "AMI does not match (got $AMI_E instead of $AMI), the machine probably did not start" 1>&2
    exit 1
fi
INSTANCE=$(echo "$start" | awk '/^INSTANCE/ {print $2}')

# I do not find a way to block until the machine is ready. We

# apparently have to poll.
OVER=0
TESTS=0
while [ $OVER != 1 ] && [ $TESTS -lt $MAX_TESTS ]; do
    description=$(ec2-describe-instances ${INSTANCE})
    STATE=$(echo "$description" | awk '/^INSTANCE/ {print $6}')
    NAME=$(echo "$description" | awk '/^INSTANCE/ {print $4}')
    if [ "$NAME" = "" ]; then
        echo "No instance ${INSTANCE} available. Crashed or was terminated." 1>&2
        exit 1
    fi
    if [ $STATE = "running" ]; then
        OVER=1
    else
        # I like bc but 'echo $(( TESTS+=1 ))' should work, too. Or expr.
        TESTS=$(echo $TESTS+1 | bc)
        sleep 2
    fi
done
if [ $TESTS = $MAX_TESTS ]; then
    echo "${INSTANCE} never got to running state" 1>&2
    ec2-terminate-instances ${INSTANCE}
    exit 1
fi
echo "$INSTANCE is running, name is $NAME"
# The SSH server does not seem reachable immediately. We again have to poll
OVER=0
TESTS=0
while [ $OVER != 1 ] && [ $TESTS -lt $MAX_CONNECTS ]; do
    ssh -o "StrictHostKeyChecking no" -i ${KEYDIR}/${KEY}.pem ${USERNAME}@$NAME "${COMMANDS}"
    if [ $? != 255 ]; then
        # It means we connected successfully (even if the remote command failed)
        OVER=1
    else
        TESTS=$(echo $TESTS+1 | bc)
        sleep 3
    fi
done
if [ $TESTS = $MAX_CONNECTS ]; then
    echo "Cannot connect to ${NAME}" 1>&2
fi
ec2-terminate-instances ${INSTANCE}
bortzmeyer
  • 34,164
  • 12
  • 67
  • 91
12

Ok, at least something like this should work:

instance_id=$(ec2-run-instances ami-dd8ea5a9 [...] | awk '/INSTANCE/{print $2}') 

Admittedly I was a bit lazy thinking that it's quicker to ask on SO than to relearn some AWK basics... :-)

Edit: simplified AWK usage as Dennis suggested. Also, using $() instead of `` for clarity, and got rid of intermediate variable.

Jonik
  • 80,077
  • 70
  • 264
  • 372
  • 2
    No need for `grep`: `awk '/INSTANCE/{print $2}' – Dennis Williamson Apr 15 '10 at 11:31
  • 1
    Thanks @Dennis - it's somewhat cleaner now – Jonik Apr 15 '10 at 12:14
  • I can't get your awk to work in Ubuntu bash. instance_id=$((ec2-run-instances ami-2b0b1442 -O aws-access-key-id -W aws-secret-access-key -k my-key -g default -t m1.small | awk '/INSTANCE/{print $2}') | awk '/INSTANCE/{prin $2}') ; echo $instance_id >> ~/instance_id.txt – Dennis Jun 14 '14 at 04:17
  • I see the error in the print, the edit times out, couldn't finish. Also discovered no key is allowed in comments. – Dennis Jun 14 '14 at 04:32
  • When I substituted the 'egrep and cut' commands from below, it worked. – Dennis Jun 14 '14 at 04:41
9

As an alternative to ec2-run-instances, you can create one ec2 instance and get InstanceId by one line by awscli run-instances:

export MyServerID=$(aws ec2 run-instances --image-id AMI --count 1 --instance-type t2.micro --key-name "my_ssh_key" --security-group-ids sg-xxx --subnet-id subnet-yyy --query 'Instances[0].InstanceId' --output text)
Alexey Vazhnov
  • 1,291
  • 17
  • 20
3

No need to use awk:

# create the instance and capture the instance id
echo "Launching instance..."
instanceid=$(ec2-run-instances --key $pemkeypair --availability-zone $avzone $ami | egrep ^INSTANCE | cut -f2)
if [ -z "$instanceid" ]; then
    echo "ERROR: could not create instance";
    exit;
else
    echo "Launched with instanceid=$instanceid"
fi

from http://www.hulen.com/post/22802124410/unattended-amazon-ec2-install-script

ttst
  • 493
  • 1
  • 5
  • 10
-1
http://www.tothenew.com/blog/how-to-parse-json-by-command-line-in-linux/
best tool to parse json in shell

#get instance id 
cat sample.json | jq '.Instances[0].InstanceId'|sed -e 's/^"//' -e 's/"$//' 
#check instances is running or not 
cat status.json | jq '.InstanceStatuses[0].InstanceState.Name'|sed -e 's/^"//' -e 's/"$//' 
Aakash Kag
  • 362
  • 6
  • 16
  • A link to a potential solution is always welcome, but please [add context around the link](http://meta.stackoverflow.com/a/8259/169503) so your fellow users will have some idea what it is and why it’s there. Always quote the most relevant part of an important link, in case the target site is unreachable or goes permanently offline. Take into account that being _barely more than a link to an external site_ is a possible reason as to [Why and how are some answers deleted?](http://stackoverflow.com/help/deleted-answers). – Tunaki Nov 09 '16 at 10:26
  • #get instance id cat sample.json | jq '.Instances[0].InstanceId'|sed -e 's/^"//' -e 's/"$//' #check instances is running or not cat status.json | jq '.InstanceStatuses[0].InstanceState.Name'|sed -e 's/^"//' -e 's/"$//' – Aakash Kag Nov 09 '16 at 10:26
  • To run above command install jq and then save json response in file and then try..installation link for jq is already shared in above my answer – Aakash Kag Nov 09 '16 at 10:31
  • Please [edit] your answer with this information, instead of posting comments. – Tunaki Nov 09 '16 at 10:32