I am trying to create an automation document in AWS for a maintenance task- which will add a tag to all the stopped EC2 instances in a region.
This is the yaml I'm working with:
schemaVersion: '0.3'
description: Automation to add tags to stopped instances.
parameters:
- name: Region
type: String
description: The AWS region to run the automation in.
default: us-east-1
- name: TagKey
type: String
description: The key of the tag to be added to the instances.
default: Status
- name: TagValue
type: String
description: The value of the tag to be added to the instances.
default: Stopped
mainSteps:
- action: 'aws:runCommand'
name: 'FindStoppedInstances'
inputs:
DocumentName: 'AWS-RunShellScript'
Parameters:
commands:
- |
# Get the list of stopped EC2 instance IDs
instance_ids=$(aws ec2 describe-instances \
--filters "Name=instance-state-name,Values=stopped" \
--query "Reservations[*].Instances[*].InstanceId" \
--output text)
echo "$instance_ids"
executionTimeout: ['3600']
outputs:
- Name: 'instance_ids'
Selector: '$.Payload'
Type: 'StringList'
- action: 'aws:runCommand'
name: 'TagStoppedInstances'
inputs:
DocumentName: 'AWS-RunShellScript'
Parameters:
commands:
- |
# Loop through each stopped instance and tag it
for instance_id in {{ instance_ids }}; do
echo "Adding tag to instance $instance_id"
aws ec2 create-tags --resources $instance_id --tags Key={{ TagKey }},Value={{ TagValue }}
done
executionTimeout: ['3600']
frankly, I have not used YAML before and took help from chatgpt. I don't want to use lambda for this task. This document is giving an error - (parameters) Parameter definition does not match any following types, String, StringList, Boolean, Integer, StringMap, MapList, AWS::EC2::Instance::Id, AWS::IAM::Role::Arn, AWS::S3::Bucket::Name, List<AWS::EC2::Instance::Id>, List<AWS::IAM::Role::Arn>, List<AWS::S3::Bucket::Name>
Can someone please help me on how to correct this script? After putting the tags, I want to start those EC2s. Once my patching task is complete (for which I am using run command), I want to shut down the EC2s which have this tag again and remove this tag.
Script using AWS API actions:
description: Automation to add tags to stopped EC2 instances.
schemaVersion: '0.3'
assumeRole: "{{ AutomationAssumeRole }}"
parameters:
AutomationAssumeRole:
type: String
description: "The ARN of the role that allows Automation to perform the actions on your behalf."
default: ''
Region:
type: String
description: "The AWS region to run the automation in."
default: "us-east-1"
TagKey:
type: String
description: "The key of the tag to be added to the instances."
default: "Status"
TagValue:
type: String
description: "The value of the tag to be added to the instances."
default: "Stopped"
mainSteps:
- name: findStoppedInstances
action: aws:executeAwsApi
inputs:
Service: ec2
Api: DescribeInstances
Filters:
- Name: "instance-state-name"
Values:
- "stopped"
outputs:
- Name: instanceIds
Selector: "$.Reservations[*].Instances[*].InstanceId"
Type: "StringList"
- name: tagStoppedInstances
action: aws:executeAwsApi
inputs:
Service: ec2
Api: CreateTags
Resources: "{{ findStoppedInstances.instanceIds }}"
Tags:
- Key: "{{ TagKey }}"
Value: "{{ TagValue }}"
outputs:
- Name: "instanceIds"
Selector: "{{ findStoppedInstances.instanceIds }}"
Type: "StringList"
There are couple of issues with the script. You have to update the parameter section to have keys, not list:
parameters: Region: type: String description: The AWS region to run the automation in. default: us-east-1 TagKey: type: String description: The key of the tag to be added to the instances. default: Status TagValue: type: String description: The value of the tag to be added to the instances. default: Stopped
Then update the script in action TagStoppedInstances
to reference the previous action:
- action: 'aws:runCommand' name: 'TagStoppedInstances' inputs: DocumentName: 'AWS-RunShellScript' Parameters: commands: - | # Loop through each stopped instance and tag it for instance_id in {{ FindStoppedInstances.instance_ids }}; do echo "Adding tag to instance $instance_id" aws ec2 create-tags --resources $instance_id --tags Key={{ TagKey }},Value={{ TagValue }} done executionTimeout: ['3600']
Instead of running scripts that call AWS CLI I would suggest using actions that run AWS API. A sample of similar workflow can be found on AWS Systems Manager User Guide.
Update:
The error you are getting is because the main outputs object is a list.
You have to edit the findStoppedInstances
selector to get all of the instances.
Full automation script should look like:
schemaVersion: '0.3'
description: Automation to add tags to stopped instances.
assumeRole: '{{ AutomationAssumeRole }}'
parameters:
AutomationAssumeRole:
type: String
description: The ARN of the role that allows Automation to perform the actions on your behalf.
default: ''
Region:
type: String
description: The AWS region to run the automation in.
default: us-east-1
TagKey:
type: String
description: The key of the tag to be added to the instances.
default: Status
TagValue:
type: String
description: The value of the tag to be added to the instances.
default: Stopped
mainSteps:
- name: findStoppedInstances
action: aws:executeAwsApi
nextStep: tagStoppedInstances
isEnd: false
inputs:
Service: ec2
Api: DescribeInstances
Filters:
- Name: instance-state-name
Values:
- stopped
outputs:
- Name: instanceIds
Selector: $.Reservations..Instances..InstanceId
Type: StringList
- name: tagStoppedInstances
action: aws:executeAwsApi
isEnd: true
inputs:
Service: ec2
Api: CreateTags
Resources:
- '{{ findStoppedInstances.instanceIds }}'
Tags:
- Key: '{{ TagKey }}'
Value: '{{ TagValue }}'
outputs:
- findStoppedInstances.instanceIds