How to access the event object with python in AWS Lambda?

23.3k Views Asked by At

To follow up on this question: Filter CloudWatch Logs to extract Instance ID

I think it leaves the question incomplete because it does not say how to access the event object with python.

My goal is to:

  • read the instance that was triggered by a change in running state
  • get a tag value associated with the instance
  • start all other instances that have the same tag

The Cloudwatch trigger event is:

{
  "source": [
    "aws.ec2"
  ],
  "detail-type": [
    "EC2 Instance State-change Notification"
  ],
  "detail": {
    "state": [
      "running"
    ]
  }
}

I can see examples like this:

def lambda_handler(event, context):

    # here I want to get the instance tag value
    # and set the tag filter based on the instance that 
    # triggered the event

    filters = [{
            'Name': 'tag:StartGroup',
            'Values': ['startgroup1'] 
        },
        {
            'Name': 'instance-state-name', 
            'Values': ['running']
        }
    ]

    instances = ec2.instances.filter(Filters=filters)

I can see the event object but I don't see how to drill down into the tag of the instance that had it's state changed to running.

Please, what is the object attribute through which I can get a tag from the triggered instance?

I suspect it is something like:

myTag = event.details.instance-id.tags["startgroup1"]
4

There are 4 best solutions below

1
Vaisakh PS On

In the Details Section of the Event, you will get the instance Id's. Using the instance id and AWS SDK you can query the tags. The following is the sample event

{
  "version": "0",
  "id": "ee376907-2647-4179-9203-343cfb3017a4",
  "detail-type": "EC2 Instance State-change Notification",
  "source": "aws.ec2",
  "account": "123456789012",
  "time": "2015-11-11T21:30:34Z",
  "region": "us-east-1",
  "resources": [
    "arn:aws:ec2:us-east-1:123456789012:instance/i-abcd1111"
  ],
  "detail": {
    "instance-id": "i-abcd1111",
    "state": "running"
  }
}
1
John Rotenstein On

The event data passed to Lambda contains the Instance ID.

You then need to call describe_tags() to retrieve a dictionary of the tags.

import boto3
client = boto3.client('ec2')

client.describe_tags(Filters=[
        {
            'Name': 'resource-id',
            'Values': [
                event['detail']['instance-id']
            ]
        }
    ]
)
0
Chrisjx On

This is what I came up with...

Please let me know how it can be done better. Thanks for the help.

# StartMeUp_Instances_byOne
#
# This lambda script is triggered by a CloudWatch Event, startGroupByInstance.
# Every evening a separate lambda script is launched on a schedule to stop
# all non-essential instances.
# 
# This script will turn on all instances with a LaunchGroup tag that matches 
# a single instance which has been changed to the running state.
#
# To start all instances in a LaunchGroup, 
# start one of the instances in the LaunchGroup and wait about 5 minutes.
# 
# Costs to run: approx. $0.02/month
# https://s3.amazonaws.com/lambda-tools/pricing-calculator.html
# 150 executions per month * 128 MB Memory * 60000 ms Execution Time
# 
# Problems: talk to chrisj
# ======================================

# test system
# this is what the event object looks like (see below)
# it is configured in the test event object with a specific instance-id
# change that to test a different instance-id with a different LaunchGroup

# {  "version": "0",
#   "id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
#   "detail-type": "EC2 Instance State-change Notification",
#   "source": "aws.ec2",
#   "account": "999999999999999",
#   "time": "2015-11-11T21:30:34Z",
#   "region": "us-east-1",
#   "resources": [
#     "arn:aws:ec2:us-east-1:123456789012:instance/i-abcd1111"
#   ],
#   "detail": {
#     "instance-id": "i-0aad9474",  # <---------- chg this
#     "state": "running"
#   }
# }
# ======================================

import boto3
import logging
import json

ec2 = boto3.resource('ec2')

def get_instance_LaunchGroup(iid):
    # When given an instance ID as str e.g. 'i-1234567', 
    # return the instance LaunchGroup.
    ec2 = boto3.resource('ec2')
    ec2instance = ec2.Instance(iid)
    thisTag = ''
    for tags in ec2instance.tags:
        if tags["Key"] == 'LaunchGroup':
            thisTag = tags["Value"]
    return thisTag

# this is the entry point for the cloudwatch trigger
def lambda_handler(event, context):

    # get the instance id that triggered the event
    thisInstanceID = event['detail']['instance-id']
    print("instance-id: " + thisInstanceID)

    # get the LaunchGroup tag value of the thisInstanceID
    thisLaunchGroup = get_instance_LaunchGroup(thisInstanceID)
    print("LaunchGroup: " + thisLaunchGroup)
    if thisLaunchGroup == '':
        print("No LaunchGroup associated with this InstanceID - ending lambda function")
        return

    # set the filters
    filters = [{
            'Name': 'tag:LaunchGroup',
            'Values': [thisLaunchGroup] 
        },
        {
            'Name': 'instance-state-name', 
            'Values': ['stopped']
        }
    ]

    # get the instances based on the filter, thisLaunchGroup and stopped
    instances = ec2.instances.filter(Filters=filters)

    # get the stopped instance IDs
    stoppedInstances = [instance.id for instance in instances]

    # make sure there are some instances not already started
    if len(stoppedInstances) > 0:
        startingUp = ec2.instances.filter(InstanceIds=stoppedInstances).start()

    print ("Finished launching all instances for tag: " + thisLaunchGroup)
0
J Roysdon On

So, here's how I got the tags in my Python code for my Lambda function.

  ec2 = boto3.resource('ec2')
  instance = ec2.Instance(instanceId)

# get image_id from instance-id
  imageId = instance.image_id
  print(imageId)

  for tags in instance.tags:
    if tags["Key"] == 'Name':
      newName = tags["Value"] + ".mydomain.com"
  print(newName)

So, using instance.tags and then checking the "Key" matching my Name tags and pulling out the "Value" for creating the FQDN (Fully Qualified Domain Name).