regions = bc.filter_regions(boto.sns.regions(), args.region) # execute business logic log.info("Describing SNS topics:") if args.topic: iam = boto.connect_iam(**credentials) for region in regions: try: sns = boto.connect_sns(region=region, **credentials) subscriptions = [] next_token = None while True: if not args.topic: result = sns.get_all_subscriptions(next_token) subscriptions.extend(result['ListSubscriptionsResponse']['ListSubscriptionsResult']['Subscriptions']) next_token = result['ListSubscriptionsResponse']['ListSubscriptionsResult']['NextToken'] else: arn = bc.create_arn(iam, 'sns', region.name, args.topic) result = sns.get_all_subscriptions_by_topic(arn, next_token) subscriptions.extend(result['ListSubscriptionsByTopicResponse']['ListSubscriptionsByTopicResult']['Subscriptions']) next_token = result['ListSubscriptionsByTopicResponse']['ListSubscriptionsByTopicResult']['NextToken'] if not next_token: break print region.name + ": " + str(len(subscriptions)) + " subscriptions" for subscription in subscriptions: if args.verbose: pprint(subscription) else: print subscription['Endpoint']
def alarmProcessor(): # Firstly we need to connect to the Simple Notification Service and CloudWatch service - this was a bit tricky and again the documentation was unclear. I thought you would use boto.connect_sns(region=reg) # which seems to successfully connect and is similar to how we connected to S3 and EC2 services. However calling methods e.g. get_all_topics() yields the error "The requested version (2010-03-31) of # service AmazonEC2 does not exist". On further investigation I found that to connect use boto.sns.connect_to_region(). You have to supply the region as an argument - note that it expected a string # not a region object - which again is inconsistent with EC2. To connect to the CloudWatch service as with SNS you have to use the connect_to_region() method sns = boto.sns.connect_to_region("eu-west-1") cw = boto.ec2.cloudwatch.connect_to_region("eu-west-1") if (not args.clear): print "\nCreating new topics (+ subscription) and alarms:\n" # Once connected we create a topic which is basically an access point composed of an identifier and recipients to send message to. create_topic() returns a unique ARN (Amazon Resource Name) which # will include the service name (SNS), region, AWS ID of the user and the topic name - this is a dict so we need to go three levels in to get the actual ARN number. We will use the arn when # we create a subscription which is how we link a topic to an endpoint like an email address. topicName = 'TopicStephenCIT-1-UID'+str(random.randrange(1000000)) response = sns.create_topic(topicName) topicARN = response['CreateTopicResponse']['CreateTopicResult']['TopicArn'] print '\tTopic ARN created: ',topicARN #Subscribe links a topic with an endpoint - in this case an email address sns.subscribe(topicARN, 'email', args.email) #We now have topic/subscription - the email address supplied will have to accept the AWS Notification Subscription Confirmation email message to ensure they get alerts # We will now create a unique alarm per instance. We can use the create_alarm method which expects a boto.ec2.cloudwatch.alarm.MetricAlarm object. This object defines # all the properties of the alarm - name,metric,topic etc. We loop through all the instance and create an alarm for each instance. Note we use the ARN that was created # above which ties the alarm to notification logic for index, inst in enumerate(instances): alarmName = "StephenMurrayCPU-" + str(index) + inst.id +'-UID' + str(random.randrange(1000000)) alarm = boto.ec2.cloudwatch.MetricAlarm(name=alarmName, namespace='AWS/EC2',metric='CPUUtilization', statistic='Average',comparison='<', threshold='40',period='60', evaluation_periods=2, dimensions = {"InstanceId": inst.id}, alarm_actions= topicARN) cw.create_alarm(alarm) print "\tAlarm created", alarmName else: print "\nClearing topics, subscriptions (confirmed) and alarms:\n" #Get all topics returnAllTopicsObject = sns.get_all_topics() #to access the ARN field we need have to go 3 levels deep into returned object topics = returnAllTopicsObject['ListTopicsResponse']['ListTopicsResult']['Topics'] #now we have a list containing dicts where the only value is the TopicArn which is what we need to supply the delete method # only do action if list is not empty - there has to be some topics to delete if topics: for t in (topics): topicARNDelete = t['TopicArn'] #delete topics sns.delete_topic(topicARNDelete) print "\tTopic Deleted: ", topicARNDelete else: print "\tNo topics found" # Get all subscriptions # Very similar to topics - get subscriptions, extract relevant parameter from retuned dict object, loop through, get SubscriptionArn # and send for deletion - also do a check to ensure subscriptions exist returnAllSubObject = sns.get_all_subscriptions() #to access the Sub ARN field we need have to go 3 levels deep into returned object subscriptions = returnAllSubObject['ListSubscriptionsResponse']['ListSubscriptionsResult']['Subscriptions'] if subscriptions: for s in (subscriptions): subARNDelete = s['SubscriptionArn'] #delete subscription only if returned value is not equal to PendingConfirmation if (subARNDelete != 'PendingConfirmation'): sns.unsubscribe(subARNDelete) print "\tSunscription Deleted: ", subARNDelete else: print "\tNo subscriptions found" #Get all alarms #describe_alarms() returns a list of boto.ec2.cloudwatch.alarm.MetricAlarms object from which we can extract the alarm name (.name method) which we can # use to delete it - Note in this case we do not require the ARN to delete - on testing with IDLE it was noted that when a complete arn # arn:aws:cloudwatch:eu-west-1:135577527805:alarm:StephenMurrayCPU0i-690b332b was supplied the delete_alarms() method returned True even though it was # not deleted...this is not good as as when StephenMurrayCPU0i-690b332b was supplied it deleted the alarm and also returned True. alarms = cw.describe_alarms() if alarms: for a in (alarms): cw.delete_alarms(a.name) print "\tAlarms Deleted: ", a.name else: print "\tNo alarms found"