def subscribe_sqs_queue(sns_conn, sqs_conn, topic_arn, queue_url, queue_arn): """ Handles all the details around hooking up an SNS topic to a SQS queue. Requires a previously created SNS topic & a previously created SQS queue. Specifically, this method does the following: * creates the subscription * checks for an existing policy * if there's no policy for the given topic/queue combination, it creates a policy allowing ``SendMessage`` * finally, it updates the policy & returns the output :param sns_conn: A ``Connection`` subclass for SNS :type sns_conn: A <boto3.core.connection.Connection> subclass :param sqs_conn: A ``Connection`` subclass for SQS :type sqs_conn: A <boto3.core.connection.Connection> subclass :param topic_arn: The ARN for the topic :type topic_arn: string :param queue_url: The URL for the queue :type queue_url: string :param queue_arn: The ARN for the queue :type queue_arn: string """ to_md5 = topic_arn + queue_arn sid = hashlib.md5(to_md5.encode("utf-8")).hexdigest() sid_exists = False resp = sns_conn.subscribe(topic_arn=topic_arn, protocol="sqs", notification_endpoint=queue_arn) attr = sqs_conn.get_queue_attributes(queue_url=queue_url, attribute_names=["Policy"]) policy = {} if "Policy" in attr: policy = json.loads(attr["Policy"]) policy.setdefault("Version", "2008-10-17") policy.setdefault("Statement", []) # See if a Statement with the Sid exists already. for s in policy["Statement"]: if s["Sid"] == sid: sid_exists = True if not sid_exists: statement = { "Action": "SQS:SendMessage", "Effect": "Allow", "Principal": {"AWS": "*"}, "Resource": queue_arn, "Sid": sid, "Condition": {"StringLike": {"aws:SourceArn": topic_arn}}, } policy["Statement"].append(statement) sqs_conn.set_queue_attributes(queue_url=queue_url, attributes={"Policy": json.dumps(policy)}) return resp
def test_integration(self): name = 'boto3_lives' topic_arn = self.conn.create_topic( name=name )['TopicArn'] self.addCleanup(self.conn.delete_topic, topic_arn=topic_arn) # FIXME: Needs 100% more waiters. time.sleep(5) arns = [info['TopicArn'] for info in self.conn.list_topics()['Topics']] self.assertTrue(topic_arn in arns) # Subscribe first, so we get the notification. # To get the notification, we'll create an SQS queue it can deliver to. sqs = self.session.connect_to('sqs') url = sqs.create_queue(queue_name='boto3_sns_test')['QueueUrl'] self.addCleanup(sqs.delete_queue, queue_url=url) queue_arn = convert_queue_url_to_arn(sqs, url) # Run the convenience method to do all the kinda-painful SNS/SQS setup. subscribe_sqs_queue( self.conn, sqs, topic_arn, url, queue_arn ) # Now publish a test message. self.conn.publish( topic_arn=topic_arn, message=json.dumps({ 'default': 'This is a test.' }) ) time.sleep(5) # Ensure the publish succeeded. messages = sqs.receive_message( queue_url=url ) self.assertTrue(len(messages['Messages']) > 0) raw_body = messages['Messages'][0]['Body'] body = json.loads(raw_body) msg = json.loads(body.get('Message', '{}')) self.assertEqual(msg, {'default': 'This is a test.'})
from boto3.utils import json # FIXME: From Boto v2. Perhaps this should move/be assumed elsewhere? ASSUME_ROLE_POLICY_DOCUMENT = json.dumps({ 'Statement': [ { 'Principal': { 'Service': ['ec2.amazonaws.com'] }, 'Effect': 'Allow', 'Action': ['sts:AssumeRole'] } ] })
def test_integration(self): TopicCollection = boto3.session.get_collection( 'sns', 'TopicCollection' ) Topic = boto3.session.get_resource('sns', 'Topic') SubscriptionCollection = boto3.session.get_collection( 'sns', 'SubscriptionCollection' ) Subscription = boto3.session.get_resource('sns', 'Subscription') topic = TopicCollection(connection=self.conn).create( name='my_test_topic' ) self.addCleanup(topic.delete) # FIXME: Needs 100% more waiters. time.sleep(5) self.assertTrue(isinstance(topic, Topic)) self.assertTrue(':my_test_topic' in topic.topic_arn) url = self.sqs.create_queue(queue_name='sns_test')['QueueUrl'] self.addCleanup(self.sqs.delete_queue, queue_url=url) # TODO: For now, we'll lean on the utility method. # This should be built into the resource objects, but more thought # is needed on how to manage extension. # Ideally, this looks like something to the effect of: # subscription = SubscriptionCollection().create_with_sqs( # topic=topic_instance, # queue=queue_instance # ) queue_arn = convert_queue_url_to_arn(self.sqs, url) subscribe_sqs_queue( self.conn, self.sqs, topic.get_identifiers()['topic_arn'], url, queue_arn ) # Now publish a message to the topic. result = topic.publish( message=json.dumps({ 'default': 'This is a notification!', }) ) # FIXME: Needs 100% more waiters. time.sleep(5) # Then check the queue for the message. messages = self.sqs.receive_message( queue_url=url ) self.assertTrue(len(messages['Messages']) > 0) raw_body = messages['Messages'][0]['Body'] body = json.loads(raw_body) msg = json.loads(body.get('Message', '{}')) self.assertEqual(msg, {'default': 'This is a notification!'})