Exemplo n.º 1
0
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
Exemplo n.º 2
0
    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.'})
Exemplo n.º 3
0
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']
        }
    ]
})
Exemplo n.º 4
0
    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!'})