I'm fairly new to Python and I'm trying to write a boto3 script that would find certain tags with certain criteria like "missing, incorrect, unknown, etc.." and then email to the appropriate contact tag for the EC2 instance. Now, it works but other than collecting the tags that are wrong I may have gone down the wrong rabbit hole. I was thinking that I could use the values collected in the list as indexes, like "instance_ids['instance_ids']['unknowntagvalues'].append(tagissue)", but this does not work since indices have to be integers. I wanted the outcome to be something like for each instance, you would have a nested dictionary that have all the wrong tags in them and I just don't know how. Any assistance would be much appreciated. Thank you
def lambda_handler(event, context):
return_value = {} #creates empty dictionary#
return_value['missingtagkeys'] = [] #within return values dictionary, create a missing tag key list#
return_value['missingtagvalues'] = [] #within return values dictionart, creates a missing tag values key list#
return_value['incorrecttagkeys'] = [] #within return values dictionary, create a incorrect tag key list#
return_value['incorrecttagvalues'] = [] #within return values dictionary, create a incorrect tag value list#
return_value['unknowntagvalues'] = [] #within return values dictionary, create a unknown tag value list#
# THE BELOW IS A SAMPLE OF WHAT THE DICTIONARY STRUCTURE WILL END UP AS #
# instance_tag_issues = {}
# instance_tag_issues{'instance_ids'} = {}
# instance_tag_issues{'instance_ids'}{'tags'} = {}
buildertag = [{
"Key": "builder",
"Value": "unknown"
}]
instance_ids = []
reservations = ec.describe_instances().get('Reservations', [])
for reservation in reservations:
tags = {}
for instance in reservation['Instances']:
try:
for tag in instance['Tags']:
tags[tag['Key']] = tag['Value']
if tag['Key'] == 'Name':
# print(tag['Value'])
instance_nametag = tag['Value']
except:
pass
#section almost works but has error
try:
if tag['Key'] == 'contact':
instance_contacttag = tag['Value']
print(instance_contacttag)
# We receive the following error when uncommenting the below print statement. Need to figure out why instance_nametag is unassigned?
# "errorMessage": "local variable 'instance_nametag' referenced before assignment",
print(instance_nametag + " (" + instance['InstanceId'] + ")" + " has a contact tag of '" + instance_contacttag + "'.")
except:
print("CONTACT TAG MISSING")
# Checks if builder tag exist and adds if it doesn't #
if not 'builder' in tags:
tagissue = (instance_nametag + " (" + instance['InstanceId'] + " does not have builder tag. Adding 'builder' tag with value of 'unknown'.")
print(instance_nametag + " (" + instance['InstanceId'] + ")" + " does not have builder tag. Adding 'builder' tag with value of 'unknown'.")
ec.create_tags(Resources=[instance["InstanceId"]], Tags=buildertag)
return_value['missingtagkeys'].append(tagissue)
instance_ids['missingtagkeys'].append(tagissue)
# print(instance_ids['instance_ids']['missingtagkeys'])
# print(instance_ids['instance_ids']['missingtagkeys'])
# print(instance_ids['instance_ids']['missingtagkeys'])
# print(instance_ids['instance_ids']['missingtagkeys'])
# print(instance_ids['instance_ids']['missingtagkeys'])
# print(instance_tag_issues['i-xyz123454596']['missingtagkeys'])
# Checks for null tag value and print output #
elif tags['builder'] in ['']:
print(instance_nametag + " (" + instance['InstanceId'] + ")" + " has no value for builder tag.")
tagissue = (instance_nametag + " (" + instance['InstanceId'] + ")" + " has no value for builder tag.")
ec.create_tags(Resources=[instance["InstanceId"]], Tags=buildertag)
return_value['missingtagvalues'].append(tagissue)
# instance_ids['instance_ids']['missingtagvalues'].append(tagissue)
print(instance_ids['instance_ids']['missingtagvalues'])
# Checks for unknown tag value and print output #
elif tags['builder'] in ['Unknown', 'unknown']:
print(instance_nametag + " (" + instance['InstanceId'] + ")" + " has unknown for it's builder tag value.")
tagissue = (instance_nametag + " (" + instance['InstanceId'] + ")" + " has unknown for it's builder tag value.")
return_value['unknowntagvalues'].append(tagissue)
# instance_ids['instance_ids']['unknowntagvalues'].append(tagissue)
# print(instance_ids['instance_ids']['unknowntagvalues'])
# print(instance_ids['instance_ids']['unknowntagvalues'])
# print(instance_ids['instance_ids']['unknowntagvalues'])
# print(instance_ids['instance_ids']['unknowntagvalues'])
# print(instance_ids['instance_ids']['unknowntagvalues'])
# Checks for builder tags equal to approved values and print output #
elif tags['builder'] in ['r', 'k', 'c', 'a', 'm']:
print(instance_nametag + " (" + instance['InstanceId'] + ")" + " has an approved builder tag value.")
tagissue = (instance_nametag + " (" + instance['InstanceId'] + ")" + " has an approved builder tag value.")
# return_value['unknowntagvalues'].append(tagissue) ###resources with approved tag values doesn't need reporting
# Checks for builder tags equal to unapproved values and print output #
elif tags['builder'] not in ['r', 'k', 'c', 'a', 'm']:
print(instance_nametag + " (" + instance['InstanceId'] + ")" + " has a incorrect builder tag value.")
tagissue = (instance_nametag + " (" + instance['InstanceId'] + ")" + " has a incorrect builder tag value.")
return_value['incorrecttagvalues'].append(tagissue)
# Sets variables for sns formatting
instanceids = instance_ids
incorrect_keys = '\n'.join(return_value['incorrecttagkeys'])
incorrect_values = '\n'.join(return_value['incorrecttagvalues'])
missing_keys = '\n'.join(return_value['missingtagkeys'])
missing_values = '\n'.join(return_value['missingtagvalues'])
unknown_values = '\n'.join(return_value['unknowntagvalues'])
# instance_tagissues = (instance_tag_issues['i-abc12354568']['tags']['contact'])
# contact_tag = '\n'.join(str(instance_contacttag))
# approvedtags_approvedvalues = print(approvedtagsapprovedvalues)
email_body = """
Here is a list of EC2 tags that need review.
Please correct the tags using the approved values list located below
<insert site here>.
------------------------------------------------------------------------------------
Summary of incorrect tags keys and/or values:
------------------------------------------------------------------------------------
Incorrect Tag Keys : {incorrect_keys}
Incorrect Tag Values : {incorrect_values}
------------------------------------------------------------------------------------
Summary of missing tags keys and/or values:
------------------------------------------------------------------------------------
Missing Tag Keys : {missing_keys}
Missing Tag Values : {missing_values}
------------------------------------------------------------------------------------
Summary of unknown values:
------------------------------------------------------------------------------------
Unknown Tag Values:
{unknown_values}
------------------------------------------------------------------------------------
Below is a list of approved tag keys/values:
{instanceids}
<insert approved tags/values dic here>
""".format(incorrect_keys = incorrect_keys,
incorrect_values = incorrect_values,
missing_keys = missing_keys,
missing_values = missing_values,
unknown_values = unknown_values,
instanceids = instanceids
# instance_tagissues = instance_tagissues
# contact_tag = contact_tag
# approvedtags_approvedvalues = approvedtags_approvedvalues
)
sns_client.publish(
TopicArn = 'arn',
Subject = 'Incorrect Tags Detected',
Message = str(email_body) + str(return_value),
)
return return_value
Alright, so there is really no error and this is the output:
Test Event Name Testingtaggingautomation
>
> Response { "missingtagkeys": [
> "Testing-lambda-tagging-script-missingtags (i-06958aa5b does not have builder tag. Adding 'builder' tag with value of 'unknown'." ],
> "missingtagvalues": [
> "Testing-lambda-tagging-script-nullvaluetags (i-0097b990b) has no value for builder tag." ], "incorrecttagkeys": [],
> "incorrecttagvalues": [
> "Testing-lambda-tagging-script-badtags (i-00cd48f3c) has a incorrect builder tag value." ], "unknowntagvalues": [
> "Testing-lambda-tagging-script-unknownvalue (i-04c9468d) has unknown for it's builder tag value." ] }
>
> Function Logs START RequestId: 81b926c0-07c6-4311-b76f-fc77a1ef9ecf
> Version: $LATEST i-0e2d43b046 is the instance id within the
> instance_ids dictionary Testing-lambda-tagging-script-goodtags
> (i-0e2d43b04) has an approved builder tag value. i-00cd48f36 is the
> instance id within the instance_ids dictionary
> Testing-lambda-tagging-script-badtags (i-00cd48f3c02178736) has a
> incorrect builder tag value. i-0097b990b is the instance id within the
> instance_ids dictionary Testing-lambda-tagging-script-nullvaluetags
> (i-0097b990b) has no value for builder tag. i-06958aa5b is the
> instance id within the instance_ids dictionary
> Testing-lambda-tagging-script-missingtags (i-06958aa5b) does not have
> builder tag. Adding 'builder' tag with value of 'unknown'.
> i-04c9468ddbc1b996e is the instance id within the instance_ids
> dictionary Testing-lambda-tagging-script-unknownvalue (i-04c9468dd)
> has unknown for it's builder tag value. END RequestId:
> 81b926c0-07c6-4311-b76f-fc77a1ef9ecf REPORT RequestId:
> 81b926c0-07c6-4311-b76f-fc77a1ef9ecf Duration: 1295.80 ms Billed
> Duration: 1296 ms Memory Size: 128 MB Max Memory Used: 80 MB Init
> Duration: 490.50 ms
The output that I want is to get the value of "contact" in each instance and throw all the "incorrect, missing, unknown" list in there, so that we can email that person of the issue. I don't have anything in the code to email a specific person but I'm assuming it would look something like:
Contact1 = {john@doe.com,
Missingtagkeys,
Missingtagvalues,
incorrecttagkeys,
incorrecttagvalues,
unknowntagvalues}
Contact2 = {jane@doe.com,
Missingtagkeys,
Missingtagvalues,
incorrecttagkeys,
incorrecttagvalues,
unknowntagvalues}
Basically, go through and iterate through each dictionary and send an email to each contact with their tag issue.
I'm sorry if this is not what you requested, but please let me know if you need anything else. I seriously don't think I have the logic right here to accomplish what I want.
The hard part is that the program is collecting information by looping through instances
, but you then want to send emails based on contact
.
It will need to create a dictionary of contacts, which contains a dictionary of categories (missing tag key, missing tag values, incorrect tag keys, etc), which contains a list with the details, eg:
{
'jane@doe.com`: {
'Missingtagkeys': ['important-key1', 'important-key2'],
'Missingtagvalues': ['finance', 'HR']
},
'john@doe.com': {
'Missingtagkeys': ['important-key1', 'important-key5'],
'Missingtagvalues': ['IT'],
'incorrecttagkeys': ['dpartment']
}
}
Your code would need to intelligently add or update the 'contact dictionary' entries, and then the categories within it. For example:
everything_dict = {}
contact = 'john@doe.com'
# Add contact to dictionary if not already there
if contact not in everything_dict:
everything_dict[contact] = {
'Missingtagkeys' : [],
'Missingtagvalues' : [],
'incorrecttagkeys' : [],
'incorrecttagvalues' : [],
'unknowntagvalues' : []
}
# Store values
everything_dict[contact]['incorrecttagkeys'].append('foo-key')
...
# Retrieve contacts and values for emailing
for email, data in everything_dict.items():
print(email) # Recipient email address
print(data['incorrecttagkeys']) # Access data like this