Add name to create ec2 snapshot python script - python

I am a novice at Python but am learning as I go. I found this script and it works well but I wanted to make some edits to it so that it also saves the name of the instance that it created a snapshot for.
import boto3
import collections
import datetime
#allows Python developers to write software that makes use of Amazon services like S3 and EC2
ec = boto3.client('ec2')
#finds tags-keys with the name "backup" or "Backup"
def lambda_handler(event, context):
reservations = ec.describe_instances(
Filters=[
{'Name': 'tag-key', 'Values': ['backup', 'Backup']},
]
).get(
'Reservations', []
)
instances = [
i for r in reservations
for i in r['Instances']
]
print "Found %d instances that need backing up" % len(instances)
to_tag = collections.defaultdict(list)
#find tag-keys with the name Retention default value if NULL is 7 days
for instance in instances:
try:
retention_days = [
int(t.get('Value')) for t in instance['Tags']
if t['Key'] == 'Retention'][0]
except IndexError:
retention_days = 7
for dev in instance['BlockDeviceMappings']:
if dev.get('Ebs', None) is None:
continue
vol_id = dev['Ebs']['VolumeId']
print "Found EBS volume %s on instance %s" % (
vol_id, instance['InstanceId'])
snap = ec.create_snapshot(
VolumeId=vol_id,
)
to_tag[retention_days].append(snap['SnapshotId'])
print "Retaining snapshot %s of volume %s from instance %s for %d days" % (
snap['SnapshotId'],
vol_id,
instance['InstanceId'],
retention_days,
)
#set retention days according to the value int input
for retention_days in to_tag.keys():
delete_date = datetime.date.today() + datetime.timedelta(days=retention_days)
delete_fmt = delete_date.strftime('%Y-%m-%d')
print "Will delete %d snapshots on %s" % (len(to_tag[retention_days]), delete_fmt)
ec.create_tags(
Resources=to_tag[retention_days],
Tags=[
{'Key': 'DeleteOn', 'Value': delete_fmt},
]
)
So far I have this but am a little lost as to how to make it work in with the current script above:
snapshot = ec(to_tag['SnapshotId'])
volumename = ''
# Add volume name to snapshot for easier identification
snapshot.create_tags(Tags=[{'Key': 'Name', 'Value': volumename}])
Any ideas welcomed! Thanks.
import boto3
import collections
import datetime
#allows Python developers to write software that makes use of Amazon services like S3 and EC2
ec = boto3.client('ec2')
sns_client = boto3.client('sns')
#finds tags-keys with the name "backup" or "Backup"
def lambda_handler(event, context):
reservations = ec.describe_instances(
Filters=[
{'Name': 'tag-key', 'Values': ['backup', 'Backup']},
]
).get(
'Reservations', []
)
instances = [
i for r in reservations
for i in r['Instances']
]
print "Found %d instances that need backing up" % len(instances)
to_tag = collections.defaultdict(list)
#find tag-keys with the name Retention default value if NULL is 7 days
for instance in instances:
try:
retention_days = [
int(t.get('Value')) for t in instance['Tags']
if t['Key'] == 'Retention'][0]
except IndexError:
retention_days = 7
for dev in instance['BlockDeviceMappings']:
if dev.get('Ebs', None) is None:
continue
vol_id = dev['Ebs']['VolumeId']
print "Found EBS volume %s on instance %s" % (
vol_id, instance['InstanceId'])
volumes = ec2_client.describe_volumes()
volumes = volumes["Volumes"]
volumes_list = []
for volume in volumes:
volumes_list.append([volume["Tags"][0]["Value"], volume["VolumeId"]])
for volume in volumes_list:
try:
create_snapshot_response = ec2_client.create_snapshot(
VolumeId=volume[1],
Description=volume[0] + " " + str(datetime.now()).split(" ")[0],
)
snapshot_id = create_snapshot_response["SnapshotId"]
tags = ec2_client.create_tags(
Resources=[snapshot_id],
Tags=[{
"Key": "Name",
"Value": "{}: {}".format(volume[0], str(datetime.now()).split(" ")[0])
}]
)
to_tag[retention_days].append(snap['SnapshotId'])
print "Retaining snapshot %s of volume %s from instance %s for %d days" % (
snap['SnapshotId'],
vol_id,
instance['InstanceId'],
retention_days,
)
#set retention days according to the value int input
for retention_days in to_tag.keys():
delete_date = datetime.date.today() + datetime.timedelta(days=retention_days)
delete_fmt = delete_date.strftime('%Y-%m-%d')
print "Will delete %d snapshots on %s" % (len(to_tag[retention_days]), delete_fmt)
ec.create_tags(
Resources=to_tag[retention_days],
Tags=[
{'Key': 'DeleteOn', 'Value': delete_fmt},
]
)

import boto3
ec2_client = boto3.client('ec2')
def lambda_handler(event, context):
instances = ec2_client.describe_instances()['Reservations']
for i in instances:
try:
create_snapshot_response = ec2_client.create_snapshot(
VolumeId=i['Instances'][0]['BlockDeviceMappings'][0]["Ebs"]["VolumeId"]
)
snapshot_id = create_snapshot_response["SnapshotId"]
tags = ec2_client.create_tags(
Resources=[snapshot_id],
Tags=[{
"Key": "Name",
"Value": "{}".format(i['Instances'][0]["Tags"][0]['Value'])
}]
)
except Exception as e:
print(e)
return "Success"

Krishna did what I have in my lambda for providing instance names on my snapshots....one change i had was
instance_name = ""
if 'Tags' in instance:
for tag in instance['Tags']:
if tag['Key'] == 'Name':
instance_name = tag['Value']
if not instance_name:
instance_name = instance['InstanceId']
snap = ec.create_snapshot(
VolumeId=vol_id,
TagSpecifications=[{
'ResourceType': 'snapshot',
'Tags': [{
'Key': 'Name',
'Value': instance_name
}]
}]
)

Update lines 43-45 to following:
instance_name = ""
if 'Tags' in instance:
for tag in instance['Tags']:
if tag['Key'] == 'Name':
instance_name = tag['Value']
if not instance_name:
instance_name = instance['InstanceId']
snap = ec.create_snapshot(
VolumeId=vol_id,
TagSpecifications=[{
'ResourceType': 'snapshot',
'Tags': [{
'Key': 'Name',
'Value': instance['InstanceId']
}]
}]
)

Related

Only update the value given and ignore other values in dynamodb

Hi I am writing a lambda function that will update the DynamoDb using boto3. In this code employee_id is auto-generated but you have to provide last_name or first_name. I am doing it with if-else. If the attribute tends to increase so does the checks. I can't keep on going with if condition. How can I tackle this what changes should I make
import boto3
import json
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('Employee')
def lambda_handler(event, context):
employee_id = event['employee_id']
if 'first_name' in event and 'last_name' not in event:
first_name = event['first_name']
UpdateExpression = 'SET first_name = :val1'
ExpressionAttributeValues = {':val1': first_name }
elif 'last_name' in event and 'first_name' not in event:
last_name = event['last_name']
UpdateExpression = 'SET last_name = :val1'
ExpressionAttributeValues = {':val1': last_name}
elif 'first_name' in event and 'last_name' in event:
last_name = event['last_name']
first_name= event['first_name']
UpdateExpression = 'SET last_name = :val1, first_name = :val2'
ExpressionAttributeValues = {
':val1': last_name,
':val2': first_name
}
else:
raise ValueError("first_name and last_name not given")
update = table.update_item(
Key={
'employee_id': employee_id
},
ConditionExpression= 'attribute_exists(employee_id)',
UpdateExpression=UpdateExpression,
ExpressionAttributeValues=ExpressionAttributeValues
)
The code that I came up with but is not working
import boto3
import json
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('Employee')
def lambda_handler(event, context):
employee_id = event['employee_id']
last_name= event['last_name']
first_name= event['first_name']
column = [first_name,last_name]
for i in range(0,len(column):
query = 'SET {} = :val1,:val2'.format(column[i])
response = table.update_item(
Key={
'employee_id': employee_id
},
ConditionExpression= 'attribute_exists(employee_id)',
UpdateExpression = query,
ExpressionAttributeValues={
':val1': first_name,
':val2': last_name
},
ReturnValues="UPDATED_NEW"
)
You should look at storing the update expression and expression values separately, then passing the complete set into the Lambda function.
This would also allow you to validate against each parameter (perhaps breaking this into a validate function to avoid excessive size of function). This way you support both required and optional parameters, then at the end validate that the update expression has valid parameters.
Perhaps something like the below?
import boto3
import json
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('Employee')
def lambda_handler(event, context):
update_expression_values = []
expression_attribute_values = {}
if 'employee_id' in event:
employee_id = event['employee_id']
else:
raise ValueError("employee_id not given")
if 'first_name' in event:
update_expression_values.append('first_name = :val_first_name')
expression_attribute_values[':val_first_name'] = event['first_name']
if 'last_name' in event:
update_expression_values.append('last_name = :val_last_name')
expression_attribute_values[':val_last_name'] = event['last_name']
if len(update_expression_values) < 1:
raise ValueError("first_name and last_name not given")
seperator = ','
update = table.update_item(
Key={
'employee_id': employee_id
},
ConditionExpression= 'attribute_exists(employee_id)',
UpdateExpression='SET ' + seperator.join(update_expression_values),
ExpressionAttributeValues=expression_attribute_values
)
This could be broken down further to reuse the logic through a function that can perform these checks such as the below.
import boto3
import json
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('Employee')
update_expression_values = []
expression_attribute_values = {}
def lambda_handler(event, context):
global update_expression_values
global expression_attribute_values
update_expression_values = []
expression_attribute_values = {}
if 'employee_id' in event:
employee_id = event['employee_id']
else:
raise ValueError("employee_id not given")
process_event_key(event, 'first_name')
process_event_key(event, 'last_name')
process_event_key(event, 'new_value')
if len(update_expression_values) < 1:
raise ValueError("first_name and last_name not given")
seperator = ','
update = table.update_item(
Key={
'employee_id': employee_id
},
ConditionExpression= 'attribute_exists(employee_id)',
UpdateExpression='SET ' + seperator.join(update_expression_values),
ExpressionAttributeValues=expression_attribute_values
)
def process_event_key(event, key):
global update_expression_values
global expression_attribute_values
if key in event:
update_expression_values.append(key + ' = :val_' + key)
expression_attribute_values[':val_' + key] = event[key]
Test Event
{
"new_value": "test",
"employee_id": "value2",
"last_name": "value3",
"first_name": "value4"
}

Python KeyError: 'destinationAccount'

i've code with the following structure from a website i'm scraping data:
destinationAccount:
ownerBuilding: ( collapse to destinationAccount)
label: ( collapse to ownerBuilding )
_id: ( collapse to ownerBuilding )
vban: ( collapse to destinationAccount)
_id: ( collapse to destinationAccount)
When I try to read this Key with this
vban = str(transaction["destinationAccount"]["vban"])
It gives me KeyError: 'destinationAccount'
Anyone have an Idea why this comes up? When I run my Code, it will copy everything I need into the MySQL Database but as I already said, the KeyError popup and the Interval isn't working
sched = BlockingScheduler()
sched.add_job(start, 'interval', seconds=5)
sched.start()
because it stop runing after the error appears. When I comment out this one vban = str(transaction["destinationAccount"]["vban"]) no error is coming up. I checked now more than 10 times, the structure is there on the website as I showed at the top. Any solution would be amazing.
def getData():
databaseConn = dbConnect()
cursor = databaseConn.cursor()
for x in range(3):
x = x * 25
transactions = json.loads(makeRequest("URL.bla/transactions?offset=" + str(x), authToken, True).text)
for transaction in transactions:
person = ""
try:
person = transaction["destinationAccount"]["ownerCharacter"]["name"]
except:
try:
person = transaction["destinationAccount"]["ownerFactory"]["label"]
except:
try:
person = transaction["destinationAccount"]["ownerBuilding"]["label"]
except:
person = str("unbekannt")
reference = ""
try:
reference = str(translateTable[transaction["reference"]])
except:
reference = str(transaction["reference"])
vban = str(transaction["destinationAccount"]["vban"])
amount = str(transaction["amount"])
taxAmount =str(transaction["taxAmount"])
gesamt = (float(amount) + float(taxAmount))
created = parse(str(transaction["created"]))
date = str(created.date())
time = str(created.time()).split(".")[0]
sql = "INSERT INTO finanzen (transaktion, date, time, sendto, vban, amount, tax, gesamt, text) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)"
val = (str(transaction["uuid"]), date, time, str(person), vban, amount, taxAmount, gesamt, reference)
try:
cursor.execute(sql, val)
databaseConn.commit()
except:
print("Fehler Datenbank")
dbClose(databaseConn,cursor)
Print result :
{'_id': 'CENSORED',
'uuid': 'CENSORED',
'amount': 11.8421,
'taxAmount': 3.1479,
'type': 'digital',
'created': 'Date',
'reference': 'CENSORED',
'sourceAccount': {'_id': 'CENSORED',
'ownerCharacter': {'_id': 'CENSORED',
'name': 'NAME'},
'vban': 'NUMBER'},
'destinationAccount': {'_id': 'CENSORED',
'vban': 'NUMBER',
'ownerBuilding': {'_id': 'CENSORED',
'label': 'Eclipse Towers'}}}
Difficult without seeing the full list but I suspect some of the items are missing the key. Have you tried a check on the key existing. Using your example:
transaction = {
"_id":"CENSORED",
"uuid":"CENSORED",
"amount":11.8421,
"taxAmount":3.1479,
"type":"digital",
"created":"Date",
"reference":"CENSORED",
"sourceAccount":{
"_id":"CENSORED",
"ownerCharacter":{
"_id":"CENSORED",
"name":"NAME"
},
"vban":"NUMBER"
},
"destinationAccount":{
"_id":"CENSORED",
"ownerBuilding":{
"_id":"CENSORED",
"label":"Eclipse Towers"
}
}
}
if 'vban' in transaction['destinationAccount']:
vban = str(transaction["destinationAccount"]["vban"])
else:
vban = "none"
Thanks to #Johnny John Boy for the Hint.
vban = ""
try:
vban = str(transaction["destinationAccount"]["vban"])
except:
try:
vban = str(transaction["sourceAccount"]["vban"])
except:
vban = str("Unbekannt")
This is the solution to fix the KeyError because there was a second part. now it works as it should without any error.

AWS lambda to delete default VPC

New to cloud, Can anyone help to correct this code
This module is to list the regions and delete the complete default vpc via a lambda function.
Getting below error while testing this:
Syntax error in module 'lambda function': unindent does not match any outer indentation level
Please help on this
Removed other function like vpc, sc as the block looks very big here in the post just added the igw for understanding..
Need assistance
def lambda_handler(event, context):
# TODO implement
#for looping across the regions
regionList=[]
region=boto3.client('ec2')
regions=region.describe_regions()
#print('the total region in aws are : ',len(regions['Regions']))
for r in range(0,len(regions['Regions'])):
regionaws=regions['Regions'][r]['RegionName']
regionList.append(regionaws)
#print(regionList)
#regionsl=['us-east-1']
#sending regions as a parameter to the remove_default_vps function
res=remove_default_vpcs(regionList)
return {
'status':res
}
def get_default_vpcs(client):
vpc_list = []
vpcs = client.describe_vpcs(
Filters=[
{
'Name' : 'isDefault',
'Values' : [
'true',
],
},
]
)
vpcs_str = json.dumps(vpcs)
resp = json.loads(vpcs_str)
data = json.dumps(resp['Vpcs'])
vpcs = json.loads(data)
for vpc in vpcs:
vpc_list.append(vpc['VpcId'])
return vpc_list
def del_igw(ec2, vpcid):
""" Detach and delete the internet-gateway """
vpc_resource = ec2.Vpc(vpcid)
igws = vpc_resource.internet_gateways.all()
if igws:
for igw in igws:
try:
print("Detaching and Removing igw-id: ", igw.id) if (VERBOSE == 1) else ""
igw.detach_from_vpc(
VpcId=vpcid
)
igw.delete(
)
except boto3.exceptions.Boto3Error as e:
print(e)
def remove_default_vpcs():
for region in res:
try:
client = boto3.client('ec2', region_name = region)
ec2 = boto3.resource('ec2', region_name = region)
vpcs = get_default_vpcs(client)
except boto3.exceptions.Boto3Error as e:
print(e)
exit(1)
else:
for vpc in vpcs:
print("\n" + "\n" + "REGION:" + region + "\n" + "VPC Id:" + vpc)
del_igw(ec2, vpc)
print(completed)
It looks to me a code indentation issue. Please try with this
def lambda_handler(event, context):
# TODO implement
#for looping across the regions
regionList=[]
region=boto3.client('ec2')
regions=region.describe_regions()
#print('the total region in aws are : ',len(regions['Regions']))
for r in range(0,len(regions['Regions'])):
regionaws=regions['Regions'][r]['RegionName']
regionList.append(regionaws)
#print(regionList)
#regionsl=['us-east-1']
#sending regions as a parameter to the remove_default_vps function
res=remove_default_vpcs(regionList)
return {
'status':res
}
def get_default_vpcs(client):
vpc_list = []
vpcs = client.describe_vpcs(
Filters=[
{
'Name' : 'isDefault',
'Values' : [
'true',
],
},
]
)
vpcs_str = json.dumps(vpcs)
resp = json.loads(vpcs_str)
data = json.dumps(resp['Vpcs'])
vpcs = json.loads(data)
for vpc in vpcs:
vpc_list.append(vpc['VpcId'])
return vpc_list
def del_igw(ec2, vpcid):
""" Detach and delete the internet-gateway """
vpc_resource = ec2.Vpc(vpcid)
igws = vpc_resource.internet_gateways.all()
if igws:
for igw in igws:
try:
print("Detaching and Removing igw-id: ", igw.id) if (VERBOSE == 1) else ""
igw.detach_from_vpc(
VpcId=vpcid
)
igw.delete(
)
except boto3.exceptions.Boto3Error as e:
print(e)
def remove_default_vpcs():
for region in res:
try:
client = boto3.client('ec2', region_name = region)
ec2 = boto3.resource('ec2', region_name = region)
vpcs = get_default_vpcs(client)
except boto3.exceptions.Boto3Error as e:
print(e)
exit(1)
else:
for vpc in vpcs:
print("\n" + "\n" + "REGION:" + region + "\n" + "VPC Id:" + vpc)
del_igw(ec2, vpc)
print(completed)

ElasticSearch and Python : Issue with search function

I'm trying to use for the first time ElasticSearch 6.4 with an existing web application wrote in Python/Django. I have some issues and I would like to understand why and how I can solve these issues.
###########
# Existing : #
###########
In my application, it's possible to upload document files (.pdf or .doc for example). Then, I have a search function in my application which let to search over documents indexed by ElasticSearch when they are uploaded.
Document title is always written through the same way :
YEAR - DOC_TYPE - ORGANISATION - document_title.extension
For example :
1970_ANNUAL_REPORT_APP-TEST_1342 - loremipsum.pdf
The search function is always done among doc_type = ANNUAL_REPORT. because there are several doc_types (ANNUAL_REPORT, OTHERS, ....).
##################
# My environment : #
##################
This is some data according to my ElasticSearch part. I'm learning ES commands too.
$ curl -XGET http://127.0.0.1:9200/_cat/indices?v
health status index uuid pri rep docs.count docs.deleted store.size pri.store.size
yellow open app 5T0HZTbmQU2-ZNJXlNb-zg 5 1 742 2 396.4kb 396.4kb
So my index is app
For the above example, if I search this document : 1970_ANNUAL_REPORT_APP-TEST_1342 - loremipsum.pdf, I have :
$ curl -XGET http://127.0.0.1:9200/app/annual-report/1343?pretty
{
"_index" : "app",
"_type" : "annual-report",
"_id" : "1343",
"_version" : 33,
"found" : true,
"_source" : {
"attachment" : {
"date" : "2010-03-04T12:08:00Z",
"content_type" : "application/pdf",
"author" : "manshanden",
"language" : "et",
"title" : "Microsoft Word - Test document Word.doc",
"content" : "some text ...",
"content_length" : 3926
},
"relative_path" : "app_docs/APP-TEST/1970_ANNUAL_REPORT_APP-TEST_1342.pdf",
"title" : "1970_ANNUAL_REPORT_APP-TEST_1342 - loremipsum.pdf"
}
}
Now, with my search part in my web application, I would like to find this document with this search : 1970.
def search_in_annual(self, q):
try:
response = self.es.search(
index='app', doc_type='annual-report',
q=q, _source_exclude=['data'], size=5000)
except ConnectionError:
return -1, None
total = 0
hits = []
if response:
for hit in response["hits"]["hits"]:
hits.append({
'id': hit['_id'],
'title': hit['_source']['title'],
'file': hit['_source']['relative_path'],
})
total = response["hits"]["total"]
return total, hits
But when q=1970, the result is 0
If I write :
response = self.es.search(
index='app', doc_type='annual-report',
q="q*", _source_exclude=['data'], size=5000)
It returns my document, but many documents too with no 1970 inside the title or the document content.
#################
# My global code : #
#################
This is the global class which manage indexing functions :
class EdqmES(object):
host = 'localhost'
port = 9200
es = None
def __init__(self, *args, **kwargs):
self.host = kwargs.pop('host', self.host)
self.port = kwargs.pop('port', self.port)
# Connect to ElasticSearch server
self.es = Elasticsearch([{
'host': self.host,
'port': self.port
}])
def __str__(self):
return self.host + ':' + self.port
#staticmethod
def file_encode(filename):
with open(filename, "rb") as f:
return b64encode(f.read()).decode('utf-8')
def create_pipeline(self):
body = {
"description": "Extract attachment information",
"processors": [
{"attachment": {
"field": "data",
"target_field": "attachment",
"indexed_chars": -1
}},
{"remove": {"field": "data"}}
]
}
self.es.index(
index='_ingest',
doc_type='pipeline',
id='attachment',
body=body
)
def index_document(self, doc, bulk=False):
filename = doc.get_filename()
try:
data = self.file_encode(filename)
except IOError:
data = ''
print('ERROR with ' + filename)
# TODO: log error
item_body = {
'_id': doc.id,
'data': data,
'relative_path': str(doc.file),
'title': doc.title,
}
if bulk:
return item_body
result1 = self.es.index(
index='app', doc_type='annual-report',
id=doc.id,
pipeline='attachment',
body=item_body,
request_timeout=60
)
print(result1)
return result1
def index_annual_reports(self):
list_docs = Document.objects.filter(category=Document.OPT_ANNUAL)
print(list_docs.count())
self.create_pipeline()
bulk = []
inserted = 0
for doc in list_docs:
inserted += 1
bulk.append(self.index_document(doc, True))
if inserted == 20:
inserted = 0
try:
print(helpers.bulk(self.es, bulk, index='app',
doc_type='annual-report',
pipeline='attachment',
request_timeout=60))
except BulkIndexError as err:
print(err)
bulk = []
if inserted:
print(helpers.bulk(
self.es, bulk, index='app',
doc_type='annual-report',
pipeline='attachment', request_timeout=60))
My document is indexed when he's submitted thanks a Django form with a signal :
#receiver(signals.post_save, sender=Document, dispatch_uid='add_new_doc')
def add_document_handler(sender, instance=None, created=False, **kwargs):
""" When a document is created index new annual report (only) with Elasticsearch and update conformity date if the
document is a new declaration of conformity
:param sender: Class which is concerned
:type sender: the model class
:param instance: Object which was just saved
:type instance: model instance
:param created: True for a creation, False for an update
:type created: boolean
:param kwargs: Additional parameter of the signal
:type kwargs: dict
"""
if not created:
return
# Index only annual reports
elif instance.category == Document.OPT_ANNUAL:
es = EdqmES()
es.index_document(instance)
This is what I've done and it seems to work :
def search_in_annual(self, q):
try:
response = self.es.search(
index='app', doc_type='annual-report', q=q, _source_exclude=['data'], size=5000)
if response['hits']['total'] == 0:
response = self.es.search(
index='app', doc_type='annual-report',
body={
"query":
{"prefix": {"title": q}},
}, _source_exclude=['data'], size=5000)
except ConnectionError:
return -1, None
total = 0
hits = []
if response:
for hit in response["hits"]["hits"]:
hits.append({
'id': hit['_id'],
'title': hit['_source']['title'],
'file': hit['_source']['relative_path'],
})
total = response["hits"]["total"]
return total, hits
It lets to search over title, prefix and content to find my document.

Lambda function to check if specific tag do NOT exists-python

I'm trying to get following:
Get all EC2 instances that either:
are Tagged with tag Owner and value Unknown or unknown
are missing tag Owner
I'm able to accomplish 1) but no idea how to get 2)
import boto3
import collections
import datetime
import time
import sys
ec = boto3.client('ec2', 'eu-west-1')
ec2 = boto3.resource('ec2', 'eu-west-1')
def lambda_handler(event, context):
instance_ids = []
reservations = ec.describe_instances(
Filters=[
{'Name': 'tag:Owner', 'Values': ['Unknown', 'unknown']},
]
).get('Reservations', [])
for reservation in reservations:
instances = reservation['Instances']
for instance in instances:
instance_ids.append(instance['InstanceId'])
print("Stopping instances: {}".format(','.join(instance_ids)))
Like I said in the comment you want to forgo the Owner filter so your response includes instances without Owner tag as well, and then you get to filtering locally.
reservations = ec.describe_instances().get('Reservations', [])
for reservation in reservations:
for instance in reservation['Instances']:
tags = {}
for tag in instance['Tags']:
tags[tag['Key']] = tag['Value']
if not 'Owner' in tags:
print instance['InstanceId'] + " does not have Owner tag"
elif tags['Owner'] in ['Unknown', 'unknown']:
print instance['InstanceId'] + " has [U|u]nknown Owner tag"
If you have a large number of instances in your account, the response to describe_instances may be paginated, and you'll have to deal with that as well.
Combining code from my question and #Rage answer i managed to get what i want
Thanks again RaGe !!
import boto3
import collections
import datetime
import time
import sys
ses = boto3.client('ses')
email_from = 'Email'
email_to = 'Email'
email_cc = 'Email'
emaiL_subject = 'Subject'
email_body = 'Body'
ec = boto3.client('ec2', 'eu-west-1')
ec2 = boto3.resource('ec2', 'eu-west-1')
from datetime import datetime
from dateutil.relativedelta import relativedelta
#create date variables
date_after_month = datetime.now()+ relativedelta(days=7)
#date_after_month.strftime('%d/%m/%Y')
today=datetime.now().strftime('%d/%m/%Y')
def lambda_handler(event, context):
#Get instances with Owner Taggs and values Unknown/known
instance_ids = []
reservations = ec.describe_instances().get('Reservations', [])
for reservation in reservations:
for instance in reservation['Instances']:
tags = {}
for tag in instance['Tags']:
tags[tag['Key']] = tag['Value']
if not 'Owner' in tags or tags['Owner']=='unknown' or tags['Owner']=='Unknown':
instance_ids.append(instance['InstanceId'])
#Check if "TerminateOn" tag exists:
if 'TerminateOn' in tags:
#compare TerminteOn value with current date
if tags["TerminateOn"]==today:
#Check if termination protection is enabled
terminate_protection=ec.describe_instance_attribute(InstanceId =instance['InstanceId'] ,Attribute = 'disableApiTermination')
protection_value=(terminate_protection['DisableApiTermination']['Value'])
#if enabled disable it
if protection_value == True:
ec.modify_instance_attribute(InstanceId=instance['InstanceId'],Attribute="disableApiTermination",Value= "False" )
#terminate instance
ec.terminate_instances(InstanceIds=instance_ids)
print "terminated" + str(instance_ids)
#send email that instance is terminated
else:
#Send an email to engineering that this instance will be removed X amount of days (calculate the date based on today's date and the termination date."
now=datetime.now()
future=tags["TerminateOn"]
TerminateOn = datetime.strptime(future, "%d/%m/%Y")
days= (TerminateOn-now).days
print str(instance_ids) + " will be removed in "+ str(days) + " days"
else:
if not 'TerminateOn' in tags:#, create it
ec2.create_tags(Resources=instance_ids,Tags=[{'Key':'TerminateOn','Value':date_after_month.strftime('%d/%m/%Y')}])
ec.stop_instances(InstanceIds=instance_ids)
print "was shut down "+format(','.join(instance_ids))

Categories