def forward_request(self, method, path, data, headers): if method == 'OPTIONS': return 200 if path.split('?')[0] == '/health': return serve_health_endpoint(method, path, data) if method == 'POST' and path == '/graph': return serve_resource_graph(data) # kill the process if we receive this header headers.get(HEADER_KILL_SIGNAL) and os._exit(0) target = headers.get('x-amz-target', '') auth_header = headers.get('authorization', '') host = headers.get('host', '') headers[HEADER_LOCALSTACK_EDGE_URL] = 'https://%s' % host # extract API details api, port, path, host = get_api_from_headers(headers, path) set_default_region_in_headers(headers) if port and int(port) < 0: return 404 if not port: port = get_port_from_custom_rules(method, path, data, headers) or port if not port: if api in ['', None, '_unknown_']: truncated = truncate(data) LOG.info(( 'Unable to find forwarding rule for host "%s", path "%s", ' 'target header "%s", auth header "%s", data "%s"') % (host, path, target, auth_header, truncated)) else: LOG.info(( 'Unable to determine forwarding port for API "%s" - please ' 'make sure this API is enabled via the SERVICES configuration' ) % api) response = Response() response.status_code = 404 response._content = '{"status": "running"}' return response connect_host = '%s:%s' % (config.HOSTNAME, port) url = '%s://%s%s' % (get_service_protocol(), connect_host, path) headers['Host'] = host function = getattr(requests, method.lower()) if isinstance(data, dict): data = json.dumps(data) response = function(url, data=data, headers=headers, verify=False, stream=True) return response
def forward_request(self, method, path, data, headers): if path.split('?')[0] == '/health': return serve_health_endpoint(method, path, data) if method == 'POST' and path == '/graph': return serve_resource_graph(data) # kill the process if we receive this header headers.get(HEADER_KILL_SIGNAL) and os._exit(0) target = headers.get('x-amz-target', '') auth_header = headers.get('authorization', '') host = headers.get('host', '') headers[HEADER_LOCALSTACK_EDGE_URL] = 'https://%s' % host # extract API details api, port, path, host = get_api_from_headers(headers, method=method, path=path, data=data) set_default_region_in_headers(headers) if port and int(port) < 0: return 404 if not port: api, port = get_api_from_custom_rules(method, path, data, headers) or (api, port) if not port: if method == 'OPTIONS': return 200 if api in ['', None, '_unknown_']: truncated = truncate(data) LOG.info(('Unable to find forwarding rule for host "%s", path "%s %s", ' 'target header "%s", auth header "%s", data "%s"') % ( host, method, path, target, auth_header, truncated)) else: LOG.info(('Unable to determine forwarding port for API "%s" - please ' 'make sure this API is enabled via the SERVICES configuration') % api) response = Response() response.status_code = 404 response._content = '{"status": "running"}' return response if api and not headers.get('Authorization'): headers['Authorization'] = aws_stack.mock_aws_request_headers(api)['Authorization'] headers['Host'] = host if isinstance(data, dict): data = json.dumps(data) return do_forward_request(api, port, method, path, data, headers)
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' and path == '/': # parse payload and extract fields req_data = urlparse.parse_qs(to_str(data), 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='Unable to find subscription for given ARN', code=400) content = '<Attributes>' for key, value in sub.items(): 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) 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') # 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_SUBSCRIPTIONS.keys(): return make_error(code=404, code_string='NotFound', message='Topic does not exist') publish_message(topic_arn, req_data) # return response here because we do not want the request to be forwarded to SNS backend return make_response(req_action) 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': topic_arn = aws_stack.sns_topic_arn(req_data['Name'][0]) tag_resource_success = self._extract_tags(topic_arn, req_data, True) # 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': self._extract_tags(topic_arn, req_data, False) 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
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
def forward_request(self, method, path, data, headers): if path.split('?')[0] == '/health': return serve_health_endpoint(method, path, data) if method == 'POST' and path == '/graph': return serve_resource_graph(data) # kill the process if we receive this header headers.get(HEADER_KILL_SIGNAL) and os._exit(0) target = headers.get('x-amz-target', '') auth_header = headers.get('authorization', '') host = headers.get('host', '') headers[HEADER_LOCALSTACK_EDGE_URL] = 'https://%s' % host # extract API details api, port, path, host = get_api_from_headers(headers, method=method, path=path, data=data) set_default_region_in_headers(headers) if port and int(port) < 0: return 404 if not port: api, port = get_api_from_custom_rules(method, path, data, headers) or (api, port) if not port: if method == 'OPTIONS': return 200 if api in ['', None, '_unknown_']: truncated = truncate(data) if auth_header or target or data or path not in ['/', '/favicon.ico']: LOG.info(('Unable to find forwarding rule for host "%s", path "%s %s", ' 'target header "%s", auth header "%s", data "%s"') % ( host, method, path, target, auth_header, truncated)) else: LOG.info(('Unable to determine forwarding port for API "%s" - please ' 'make sure this API is enabled via the SERVICES configuration') % api) response = Response() response.status_code = 404 response._content = '{"status": "running"}' return response if api and not headers.get('Authorization'): headers['Authorization'] = aws_stack.mock_aws_request_headers(api)['Authorization'] headers['Host'] = host if isinstance(data, dict): data = json.dumps(data) encoding_type = headers.get('content-encoding') or '' if encoding_type.upper() == GZIP_ENCODING and api is not S3: headers.set('content-encoding', IDENTITY_ENCODING) data = gzip.decompress(data) lock_ctx = BOOTSTRAP_LOCK if persistence.API_CALLS_RESTORED or is_internal_call_context(headers): lock_ctx = empty_context_manager() with lock_ctx: return do_forward_request(api, method, path, data, headers, port=port)
def forward_request(self, method, path, data, headers): if common.INFRA_STOPPED: return 503 if config.EDGE_FORWARD_URL: return do_forward_request_network( 0, method, path, data, headers, target_url=config.EDGE_FORWARD_URL) # kill the process if we receive this header headers.get(HEADER_KILL_SIGNAL) and sys.exit(0) target = headers.get("x-amz-target", "") auth_header = get_auth_string(method, path, headers, data) if auth_header and not headers.get("authorization"): headers["authorization"] = auth_header host = headers.get("host", "") orig_req_url = headers.pop(HEADER_LOCALSTACK_REQUEST_URL, "") headers[HEADER_LOCALSTACK_EDGE_URL] = (re.sub( r"^([^:]+://[^/]+).*", r"\1", orig_req_url) or "http://%s" % host) # extract API details api, port, path, host = get_api_from_headers(headers, method=method, path=path, data=data) set_default_region_in_headers(headers) if port and int(port) < 0: return 404 if not port: api, port = get_api_from_custom_rules(method, path, data, headers) or ( api, port, ) should_log_trace = is_trace_logging_enabled(headers) if api and should_log_trace: # print request trace for debugging, if enabled LOG.debug('IN(%s): "%s %s" - headers: %s - data: %s', api, method, path, dict(headers), data) if not port: if method == "OPTIONS": if api and should_log_trace: # print request trace for debugging, if enabled LOG.debug('IN(%s): "%s %s" - status: %s', api, method, path, 200) return 200 if api in ["", None, API_UNKNOWN]: truncated = truncate(data) if auth_header or target or data or path not in [ "/", "/favicon.ico" ]: LOG.info( ('Unable to find forwarding rule for host "%s", path "%s %s", ' 'target header "%s", auth header "%s", data "%s"'), host, method, path, target, auth_header, truncated, ) else: LOG.info( ('Unable to determine forwarding port for API "%s" - please ' "make sure this API is enabled via the SERVICES configuration" ), api, ) response = Response() response.status_code = 404 response._content = '{"status": "running"}' return response if api and not headers.get("Authorization"): headers["Authorization"] = aws_stack.mock_aws_request_headers( api)["Authorization"] headers[HEADER_TARGET_API] = str(api) headers["Host"] = host if isinstance(data, dict): data = json.dumps(data) encoding_type = headers.get("Content-Encoding") or "" if encoding_type.upper() == GZIP_ENCODING.upper( ) and api not in SKIP_GZIP_APIS: headers.set("Content-Encoding", IDENTITY_ENCODING) data = gzip.decompress(data) is_internal_call = is_internal_call_context(headers) self._require_service(api) lock_ctx = BOOTSTRAP_LOCK if is_internal_call or persistence.is_persistence_restored(): lock_ctx = empty_context_manager() with lock_ctx: result = do_forward_request(api, method, path, data, headers, port=port) if should_log_trace and result not in [None, False, True]: result_status_code = getattr(result, "status_code", result) result_headers = getattr(result, "headers", {}) result_content = getattr(result, "content", "") LOG.debug( 'OUT(%s): "%s %s" - status: %s - response headers: %s - response: %s', api, method, path, result_status_code, dict(result_headers or {}), result_content, ) return result
def forward_request(self, method, path, data, headers): if path.split('?')[0] == '/health': return serve_health_endpoint(method, path, data) if method == 'POST' and path == '/graph': return serve_resource_graph(data) # kill the process if we receive this header headers.get(HEADER_KILL_SIGNAL) and sys.exit(0) target = headers.get('x-amz-target', '') auth_header = get_auth_string(method, path, headers, data) if auth_header and not headers.get('authorization'): headers['authorization'] = auth_header host = headers.get('host', '') orig_req_url = headers.pop(HEADER_LOCALSTACK_REQUEST_URL, '') headers[HEADER_LOCALSTACK_EDGE_URL] = (re.sub( r'^([^:]+://[^/]+).*', r'\1', orig_req_url) or 'http://%s' % host) # extract API details api, port, path, host = get_api_from_headers(headers, method=method, path=path, data=data) if api and config.LS_LOG: # print request trace for debugging, if enabled LOG.debug('IN(%s): "%s %s" - headers: %s - data: %s' % (api, method, path, dict(headers), data)) set_default_region_in_headers(headers) if port and int(port) < 0: return 404 if not port: api, port = get_api_from_custom_rules(method, path, data, headers) or (api, port) if not port: if method == 'OPTIONS': if api and config.LS_LOG: # print request trace for debugging, if enabled LOG.debug('OUT(%s): "%s %s" - status: %s' % (api, method, path, 200)) return 200 if api in ['', None, API_UNKNOWN]: truncated = truncate(data) if auth_header or target or data or path not in [ '/', '/favicon.ico' ]: LOG.info(( 'Unable to find forwarding rule for host "%s", path "%s %s", ' 'target header "%s", auth header "%s", data "%s"') % (host, method, path, target, auth_header, truncated)) else: LOG.info(( 'Unable to determine forwarding port for API "%s" - please ' 'make sure this API is enabled via the SERVICES configuration' ) % api) response = Response() response.status_code = 404 response._content = '{"status": "running"}' return response if api and not headers.get('Authorization'): headers['Authorization'] = aws_stack.mock_aws_request_headers( api)['Authorization'] headers[HEADER_TARGET_API] = str(api) headers['Host'] = host if isinstance(data, dict): data = json.dumps(data) encoding_type = headers.get('Content-Encoding') or '' if encoding_type.upper() == GZIP_ENCODING.upper() and api not in [S3]: headers.set('Content-Encoding', IDENTITY_ENCODING) data = gzip.decompress(data) lock_ctx = BOOTSTRAP_LOCK if persistence.API_CALLS_RESTORED or is_internal_call_context(headers): lock_ctx = empty_context_manager() with lock_ctx: return do_forward_request(api, method, path, data, headers, port=port)
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 = urlparse.parse_qs(to_str(data), keep_blank_values=True) # parse data from query path if not req_data: parsed_path = urlparse.urlparse(path) req_data = urlparse.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) 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") 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 == "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