Samuel Rodriguez
Samuel Rodriguez

Reputation: 51

How to run shell script on multiple EC2 instances using AWS CLI?

I'm trying to do a simple AWS CLI command that can run a shell command to multiple instances.

I know first I need to get the list of instances ids:

aws ec2 describe-instances --filter "Name=tag:Group,Values=Development" --query 'Reservations[].Instances[].[InstanceId]' --output text

I then will have to assign them to an array. Then loop through each instance id and send the command.

Do we have an option for aws to send a shell command to an instance with a specific id?

Something like this:

aws ssm send-command --instance-ids "i-xxxxxxxxxxxxxxxx" --document-name "shellscript"

I keep getting this error:

An error occurred (InvalidInstanceId) when calling the SendCommand operation:

I've made sure that the SSM agent is running on that specific instance and made sure everything is correct according to these docs pages.

Upvotes: 3

Views: 6832

Answers (2)

Kush Vyas
Kush Vyas

Reputation: 6099

You can use ssm send-command.

A sample command to see ip address of instance:

aws ssm send-command --instance-ids "your id's" --document-name "AWS-RunShellScript" --comment "IP config" --parameters "commands=ifconfig" --output text

Modify command as per your needs.


In case you've got the error, this can happen when you don't have SSM setup on the instance you're trying to access. For a list of instances where you can run SSM commands, run:

aws ssm describe-instance-information --output text

See: InvalidInstanceId: An error occurred (InvalidInstanceId) when calling the SendCommand operation.

Upvotes: 6

Samuel Rodriguez
Samuel Rodriguez

Reputation: 51

I was able to create a script with Python using Boto3.

import boto3
import botocore
import paramiko

tagkey = 'Environment'
tagvalue = 'DEV'

# list_instances functions returns a list of ip addresses containing a set of tags
def list_instances(tagkey, tagvalue):

    ec2client = boto3.client('ec2')

    response = ec2client.describe_instances(
        Filters=[
            {
                'Name': 'tag:'+tagkey,
                'Values': [tagvalue]
            }
       ]
    )
    instancelist = []
    for reservation in (response["Reservations"]):
        for instance in reservation["Instances"]:
            instancelist.append(instance["PublicDnsName"])
    return instancelist

# Results of the function get stored in a list.
list = list_instances(tagkey, tagvalue)

key = paramiko.RSAKey.from_private_key_file("/home/ec2-user/key.pem")
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())

# Looping through all the instannces in the list
for instance_ip in list[:]:
                # Connect/ssh to an instance
    try:
                # Here 'ec2-user' is user name and 'instance_ip' is public IP of EC2
                client.connect(hostname=instance_ip, username="ec2-user", pkey=key)

                # Execute a command after connecting/ssh to an instance
                stdin, stdout, stderr = client.exec_command("touch test")

                # close the client connection once the job is done
                print "Command sent:",instance_ip

    except Exception, e:
        print e

Upvotes: 0

Related Questions