def forward_request(self, method, path, data, headers): req_data = parse_request_data(method, path, data) action = req_data.get('Action') if action == 'TagResource': arn = req_data.get('ResourceARN') tags = aws_stack.extract_tags(req_data) TAGS.tag_resource(arn, tags) return aws_responses.requests_response_xml(action, {}, xmlns=XMLNS_CLOUDWATCH) if action == 'UntagResource': arn = req_data.get('ResourceARN') tag_names = [v for k, v in req_data.items() if k.startswith('TagKeys.member.')] TAGS.untag_resource(arn, tag_names) return aws_responses.requests_response_xml(action, {}, xmlns=XMLNS_CLOUDWATCH) if action == 'ListTagsForResource': arn = req_data.get('ResourceARN') tags = TAGS.list_tags_for_resource(arn) result = {'Tags': {'member': tags.get('Tags', [])}} return aws_responses.requests_response_xml(action, result, xmlns=XMLNS_CLOUDWATCH) if path.startswith(PATH_GET_RAW_METRICS): result = cloudwatch_backends[aws_stack.get_region()].metric_data result = [ {'ns': r.namespace, 'n': r.name, 'v': r.value, 't': r.timestamp, 'd': [{'n': d.name, 'v': d.value} for d in r.dimensions]} for r in result ] return {'metrics': result} return True
def forward_request(self, method, path, data, headers): req_data = parse_request_data(method, path, data) action = req_data.get('Action') if action == 'TagResource': arn = req_data.get('ResourceARN') tags = aws_stack.extract_tags(req_data) TAGS.tag_resource(arn, tags) return aws_responses.requests_response_xml(action, {}, xmlns=XMLNS_CLOUDWATCH) if action == 'UntagResource': arn = req_data.get('ResourceARN') tag_names = [ v for k, v in req_data.items() if k.startswith('TagKeys.member.') ] TAGS.untag_resource(arn, tag_names) return aws_responses.requests_response_xml(action, {}, xmlns=XMLNS_CLOUDWATCH) if action == 'ListTagsForResource': arn = req_data.get('ResourceARN') tags = TAGS.list_tags_for_resource(arn) result = {'Tags': {'member': tags.get('Tags', [])}} return aws_responses.requests_response_xml(action, result, xmlns=XMLNS_CLOUDWATCH) return True
def forward_request(self, method, path, data, headers): req_data = parse_request_data(method, path, data) action = req_data.get("Action") if action == "TagResource": arn = req_data.get("ResourceARN") tags = aws_responses.extract_tags(req_data) TAGS.tag_resource(arn, tags) return aws_responses.requests_response_xml(action, {}, xmlns=XMLNS_CLOUDWATCH) if action == "UntagResource": arn = req_data.get("ResourceARN") tag_names = [ v for k, v in req_data.items() if k.startswith("TagKeys.member.") ] TAGS.untag_resource(arn, tag_names) return aws_responses.requests_response_xml(action, {}, xmlns=XMLNS_CLOUDWATCH) if action == "ListTagsForResource": arn = req_data.get("ResourceARN") tags = TAGS.list_tags_for_resource(arn) result = {"Tags": tags.get("Tags", [])} return aws_responses.requests_response_xml(action, result, xmlns=XMLNS_CLOUDWATCH) if path.startswith(PATH_GET_RAW_METRICS): result = cloudwatch_backends[aws_stack.get_region()].metric_data result = [{ "ns": r.namespace, "n": r.name, "v": r.value, "t": r.timestamp, "d": [{ "n": d.name, "v": d.value } for d in r.dimensions], } for r in result] return {"metrics": result} return True
def _response(action, result): if isinstance(result, (dict, str)): result = requests_response_xml(action, result, xmlns=XMLNS_CF) if isinstance(result, Response): result = requests_to_flask_response(result) return result
def forward_request(self, method, path, data, headers): if method == "OPTIONS": return 200 # check region try: aws_stack.check_valid_region(headers) aws_stack.set_default_region_in_headers(headers) except Exception as e: return make_error(message=str(e), code=400) if method == "POST": # parse payload and extract fields req_data = parse_qs(to_str(data), keep_blank_values=True) # parse data from query path if not req_data: parsed_path = urlparse(path) req_data = parse_qs(parsed_path.query, keep_blank_values=True) req_action = req_data["Action"][0] topic_arn = (req_data.get("TargetArn") or req_data.get("TopicArn") or req_data.get("ResourceArn")) if topic_arn: topic_arn = topic_arn[0] topic_arn = aws_stack.fix_account_id_in_arns(topic_arn) if req_action == "SetSubscriptionAttributes": sub = get_subscription_by_arn(req_data["SubscriptionArn"][0]) if not sub: return make_error( message="Unable to find subscription for given ARN", code=400) attr_name = req_data["AttributeName"][0] attr_value = req_data["AttributeValue"][0] sub[attr_name] = attr_value return make_response(req_action) elif req_action == "GetSubscriptionAttributes": sub = get_subscription_by_arn(req_data["SubscriptionArn"][0]) if not sub: return make_error( message="Subscription with arn {0} not found".format( req_data["SubscriptionArn"][0]), code=404, code_string="NotFound", ) content = "<Attributes>" for key, value in sub.items(): if key in HTTP_SUBSCRIPTION_ATTRIBUTES: continue content += "<entry><key>%s</key><value>%s</value></entry>\n" % ( key, value, ) content += "</Attributes>" return make_response(req_action, content=content) elif req_action == "Subscribe": if "Endpoint" not in req_data: return make_error( message="Endpoint not specified in subscription", code=400) if req_data["Protocol"][0] not in SNS_PROTOCOLS: return make_error( message= f"Invalid parameter: Amazon SNS does not support this protocol string: " f"{req_data['Protocol'][0]}", code=400, ) if ".fifo" in req_data["Endpoint"][ 0] and ".fifo" not in topic_arn: return make_error( message= "FIFO SQS Queues can not be subscribed to standard SNS topics", code=400, code_string="InvalidParameter", ) elif req_action == "ConfirmSubscription": if "TopicArn" not in req_data: return make_error( message= "TopicArn not specified in confirm subscription request", code=400, ) if "Token" not in req_data: return make_error( message= "Token not specified in confirm subscription request", code=400, ) do_confirm_subscription( req_data.get("TopicArn")[0], req_data.get("Token")[0]) elif req_action == "Unsubscribe": if "SubscriptionArn" not in req_data: return make_error( message= "SubscriptionArn not specified in unsubscribe request", code=400, ) do_unsubscribe(req_data.get("SubscriptionArn")[0]) elif req_action == "DeleteTopic": do_delete_topic(topic_arn) elif req_action == "Publish": if req_data.get("Subject") == [""]: return make_error(code=400, code_string="InvalidParameter", message="Subject") if not req_data.get("Message") or all( not message for message in req_data.get("Message")): return make_error(code=400, code_string="InvalidParameter", message="Empty message") if topic_arn and ".fifo" in topic_arn and not req_data.get( "MessageGroupId"): return make_error( code=400, code_string="InvalidParameter", message= "The MessageGroupId parameter is required for FIFO topics", ) sns_backend = SNSBackend.get() # No need to create a topic to send SMS or single push notifications with SNS # but we can't mock a sending so we only return that it went well if "PhoneNumber" not in req_data and "TargetArn" not in req_data: if topic_arn not in sns_backend.sns_subscriptions: return make_error( code=404, code_string="NotFound", message="Topic does not exist", ) message_id = publish_message(topic_arn, req_data, headers) # return response here because we do not want the request to be forwarded to SNS backend return make_response(req_action, message_id=message_id) elif req_action == "PublishBatch": entries = parse_urlencoded_data( req_data, "PublishBatchRequestEntries.member", "MessageAttributes.entry") if len(entries) > 10: return make_error( message= "The batch request contains more entries than permissible", code=400, code_string="TooManyEntriesInBatchRequest", ) ids = [entry["Id"] for entry in entries] if len(set(ids)) != len(entries): return make_error( message= "Two or more batch entries in the request have the same Id", code=400, code_string="BatchEntryIdsNotDistinct", ) if topic_arn and ".fifo" in topic_arn: if not all( ["MessageGroupId" in entry for entry in entries]): return make_error( message= "The MessageGroupId parameter is required for FIFO topics", code=400, code_string="InvalidParameter", ) response = publish_batch(topic_arn, entries, headers) return requests_response_xml( req_action, response, xmlns="http://sns.amazonaws.com/doc/2010-03-31/") elif req_action == "ListTagsForResource": tags = do_list_tags_for_resource(topic_arn) content = "<Tags/>" if len(tags) > 0: content = "<Tags>" for tag in tags: content += "<member>" content += "<Key>%s</Key>" % tag["Key"] content += "<Value>%s</Value>" % tag["Value"] content += "</member>" content += "</Tags>" return make_response(req_action, content=content) elif req_action == "CreateTopic": sns_backend = SNSBackend.get() topic_arn = aws_stack.sns_topic_arn(req_data["Name"][0]) tag_resource_success = self._extract_tags( topic_arn, req_data, True, sns_backend) sns_backend.sns_subscriptions[topic_arn] = ( sns_backend.sns_subscriptions.get(topic_arn) or []) # in case if there is an error it returns an error , other wise it will continue as expected. if not tag_resource_success: return make_error( code=400, code_string="InvalidParameter", message="Topic already exists with different tags", ) elif req_action == "TagResource": sns_backend = SNSBackend.get() self._extract_tags(topic_arn, req_data, False, sns_backend) return make_response(req_action) elif req_action == "UntagResource": tags_to_remove = [] req_tags = { k: v for k, v in req_data.items() if k.startswith("TagKeys.member.") } req_tags = req_tags.values() for tag in req_tags: tags_to_remove.append(tag[0]) do_untag_resource(topic_arn, tags_to_remove) return make_response(req_action) data = self._reset_account_id(data) return Request(data=data, headers=headers, method=method) return True