Beispiel #1
0
 def __init__(self, metadata=None, template={}):
     self.metadata = metadata or {}
     self.template = template or {}
     self._template_raw = clone_safe(self.template)
     self.template_original = clone_safe(self.template)
     # initialize resources
     for resource_id, resource in self.template_resources.items():
         resource['LogicalResourceId'] = self.template_original['Resources'][resource_id]['LogicalResourceId'] = (
             resource.get('LogicalResourceId') or resource_id)
     # initialize stack template attributes
     self.template['StackId'] = self.metadata['StackId'] = (self.metadata.get('StackId') or
         aws_stack.cloudformation_stack_arn(self.stack_name, short_uid()))
     self.template['Parameters'] = self.template.get('Parameters') or {}
     self.template['Outputs'] = self.template.get('Outputs') or {}
     # initialize metadata
     self.metadata['Parameters'] = self.metadata.get('Parameters') or []
     self.metadata['StackStatus'] = 'CREATE_IN_PROGRESS'
     self.metadata['CreationTime'] = self.metadata.get('CreationTime') or timestamp_millis()
     # maps resource id to resource state
     self.resource_states = {}
     # maps resource id to moto resource class instance (TODO: remove in the future)
     self.moto_resource_statuses = {}
     # list of stack events
     self.events = []
     # list of stack change sets
     self.change_sets = []
     # initialize parameters
     for i in range(1, 100):
         key = 'Parameters.member.%s.ParameterKey' % i
         value = 'Parameters.member.%s.ParameterValue' % i
         key = self.metadata.get(key)
         value = self.metadata.get(value)
         if not key:
             break
         self.metadata['Parameters'].append({'ParameterKey': key, 'ParameterValue': value})
Beispiel #2
0
 def list_templates(self):
     email_templates = ses_backend.list_templates()
     for template in email_templates:
         if isinstance(template['Timestamp'], (date, datetime)):
             # Hack to change the last digits to Java SDKv2 compatible format
             template['Timestamp'] = timestamp_millis(template['Timestamp'])
     return email_responses_list_templates_orig(self)
Beispiel #3
0
    def get_function_event_invoke_config(self):
        response = {}

        if self.max_retry_attempts is not None:
            response.update({"MaximumRetryAttempts": self.max_retry_attempts})

        if self.max_event_age is not None:
            response.update({"MaximumEventAgeInSeconds": self.max_event_age})

        if self.on_successful_invocation or self.on_failed_invocation:
            response.update({"DestinationConfig": {}})
            if self.on_successful_invocation:
                response["DestinationConfig"].update({
                    "OnSuccess": {
                        "Destination": self.on_successful_invocation
                    }
                })
            if self.on_failed_invocation:
                response["DestinationConfig"].update(
                    {"OnFailure": {
                        "Destination": self.on_failed_invocation
                    }})
        if not response:
            return None
        response.update({
            "LastModified": timestamp_millis(self.last_modified),
            "FunctionArn": str(self.id),
        })
        return response
def lambda_result_to_destination(func_details, event, result, is_async, error):
    if not func_details.destination_enabled():
        return

    payload = {
        "version": "1.0",
        "timestamp": timestamp_millis(),
        "requestContext": {
            "requestId": long_uid(),
            "functionArn": func_details.arn(),
            "condition": "RetriesExhausted",
            "approximateInvokeCount": 1,
        },
        "requestPayload": event,
        "responseContext": {"statusCode": 200, "executedVersion": "$LATEST"},
        "responsePayload": {},
    }

    if result and result.result:
        try:
            payload["requestContext"]["condition"] = "Success"
            payload["responsePayload"] = json.loads(result.result)
        except Exception:
            payload["responsePayload"] = result.result

    if error:
        payload["responseContext"]["functionError"] = "Unhandled"
        # add the result in the response payload
        if error.result is not None:
            payload["responsePayload"] = json.loads(error.result)
        send_event_to_target(func_details.on_failed_invocation, payload)
        return

    if func_details.on_successful_invocation is not None:
        send_event_to_target(func_details.on_successful_invocation, payload)
Beispiel #5
0
    def get_function_event_invoke_config(self):
        response = {}

        if self.max_retry_attempts:
            response.update({'MaximumRetryAttempts': self.max_retry_attempts})

        if self.max_event_age:
            response.update({'MaximumEventAgeInSeconds': self.max_event_age})

        if self.on_successful_invocation or self.on_failed_invocation:
            response.update({'DestinationConfig': {}})
            if self.on_successful_invocation:
                response['DestinationConfig'].update({
                    'OnSuccess': {
                        'Destination': self.on_successful_invocation
                    }
                })
            if self.on_failed_invocation:
                response['DestinationConfig'].update({
                    'OnFailure': {
                        'Destination': self.on_failed_invocation
                    }
                })
        if not response:
            return None
        response.update({
            'LastModified': timestamp_millis(self.last_modified),
            'FunctionArn': str(self.id),
        })
        return response
 def set_resource_status(self, resource_id: str, status: str, physical_res_id: str = None):
     """Update the deployment status of the given resource ID and publish a corresponding stack event."""
     self._set_resource_status_details(resource_id, physical_res_id=physical_res_id)
     state = self.resource_states.setdefault(resource_id, {})
     state["PreviousResourceStatus"] = state.get("ResourceStatus")
     state["ResourceStatus"] = status
     state["LastUpdatedTimestamp"] = timestamp_millis()
     self.add_stack_event(resource_id, physical_res_id, status)
Beispiel #7
0
def create_sns_message_body(subscriber, req_data):
    message = req_data['Message'][0]
    subject = req_data.get('Subject', [None])[0]
    protocol = subscriber['Protocol']

    if six.PY2 and type(message).__name__ == 'unicode':
        # fix non-ascii unicode characters under Python 2
        message = message.encode('raw-unicode-escape')

    if is_raw_message_delivery(subscriber):
        return message

    if req_data.get('MessageStructure') == ['json']:
        message = json.loads(message)
        try:
            message = message.get(protocol, message['default'])
        except KeyError:
            raise Exception("Unable to find 'default' key in message payload")

    token = short_uid()
    external_url = external_service_url('sns')
    topic_arn = subscriber['TopicArn']

    data = {
        'Type':
        req_data.get('Type', ['Notification'])[0],
        'MessageId':
        str(uuid.uuid4()),
        'TopicArn':
        topic_arn,
        'Message':
        message,
        'Timestamp':
        timestamp_millis(),
        'SignatureVersion':
        '1',
        # TODO Add a more sophisticated solution with an actual signature
        # Hardcoded
        'Signature':
        'EXAMPLEpH+..',
        'SigningCertURL':
        'https://sns.us-east-1.amazonaws.com/SimpleNotificationService-0000000000000000000000.pem',
        'UnsubscribeURL':
        '%s/?Action=Unsubscribe&TopicArn=%s&Token=%s' %
        (external_url, topic_arn, token)
    }

    if subject is not None:
        data['Subject'] = subject

    attributes = get_message_attributes(req_data)
    if attributes:
        data['MessageAttributes'] = attributes

    return json.dumps(data)
Beispiel #8
0
 def add_stack_event(self, resource_id, physical_res_id, status):
     event = {
         'EventId': long_uid(),
         'Timestamp': timestamp_millis(),
         'StackId': self.stack_id,
         'StackName': self.stack_name,
         'LogicalResourceId': resource_id,
         'PhysicalResourceId': physical_res_id,
         'ResourceStatus': status,
         'ResourceType': 'AWS::CloudFormation::Stack'
     }
     self.events.insert(0, event)
Beispiel #9
0
 def add_stack_event(self, resource_id, physical_res_id, status):
     event = {
         "EventId": long_uid(),
         "Timestamp": timestamp_millis(),
         "StackId": self.stack_id,
         "StackName": self.stack_name,
         "LogicalResourceId": resource_id,
         "PhysicalResourceId": physical_res_id,
         "ResourceStatus": status,
         "ResourceType": "AWS::CloudFormation::Stack",
     }
     self.events.insert(0, event)
def create_sns_message_body(subscriber, req_data, message_id=None):
    message = req_data["Message"][0]
    protocol = subscriber["Protocol"]

    if six.PY2 and type(message).__name__ == "unicode":
        # fix non-ascii unicode characters under Python 2
        message = message.encode("raw-unicode-escape")

    if req_data.get("MessageStructure") == ["json"]:
        message = json.loads(message)
        try:
            message = message.get(protocol, message["default"])
        except KeyError:
            raise Exception("Unable to find 'default' key in message payload")

    if is_raw_message_delivery(subscriber):
        return message

    data = {
        "Type":
        req_data.get("Type", ["Notification"])[0],
        "MessageId":
        message_id,
        "TopicArn":
        subscriber["TopicArn"],
        "Message":
        message,
        "Timestamp":
        timestamp_millis(),
        "SignatureVersion":
        "1",
        # TODO Add a more sophisticated solution with an actual signature
        # Hardcoded
        "Signature":
        "EXAMPLEpH+..",
        "SigningCertURL":
        "https://sns.us-east-1.amazonaws.com/SimpleNotificationService-0000000000000000000000.pem",
    }

    for key in ["Subject", "SubscribeURL", "Token"]:
        if req_data.get(key):
            data[key] = req_data[key][0]

    for key in HTTP_SUBSCRIPTION_ATTRIBUTES:
        if key in subscriber:
            data[key] = subscriber[key]

    attributes = get_message_attributes(req_data)
    if attributes:
        data["MessageAttributes"] = attributes

    return json.dumps(data)
Beispiel #11
0
def create_sns_message_body(subscriber, req_data, message_id=None):
    message = req_data['Message'][0]
    protocol = subscriber['Protocol']

    if six.PY2 and type(message).__name__ == 'unicode':
        # fix non-ascii unicode characters under Python 2
        message = message.encode('raw-unicode-escape')

    if req_data.get('MessageStructure') == ['json']:
        message = json.loads(message)
        try:
            message = message.get(protocol, message['default'])
        except KeyError:
            raise Exception("Unable to find 'default' key in message payload")

    if is_raw_message_delivery(subscriber):
        return message

    data = {
        'Type':
        req_data.get('Type', ['Notification'])[0],
        'MessageId':
        message_id,
        'TopicArn':
        subscriber['TopicArn'],
        'Message':
        message,
        'Timestamp':
        timestamp_millis(),
        'SignatureVersion':
        '1',
        # TODO Add a more sophisticated solution with an actual signature
        # Hardcoded
        'Signature':
        'EXAMPLEpH+..',
        'SigningCertURL':
        'https://sns.us-east-1.amazonaws.com/SimpleNotificationService-0000000000000000000000.pem'
    }

    for key in ['Subject', 'SubscribeURL', 'Token']:
        if req_data.get(key):
            data[key] = req_data[key][0]

    for key in HTTP_SUBSCRIPTION_ATTRIBUTES:
        if key in subscriber:
            data[key] = subscriber[key]

    attributes = get_message_attributes(req_data)
    if attributes:
        data['MessageAttributes'] = attributes

    return json.dumps(data)
Beispiel #12
0
 def set_stack_status(self, status):
     self.metadata['StackStatus'] = status
     event = {
         'EventId': long_uid(),
         'Timestamp': timestamp_millis(),
         'StackId': self.stack_id,
         'StackName': self.stack_name,
         'LogicalResourceId': self.stack_name,
         'PhysicalResourceId': self.stack_id,
         'ResourceStatus': status,
         'ResourceType': 'AWS::CloudFormation::Stack'
     }
     self.events.insert(0, event)
Beispiel #13
0
 def set_resource_status(self, resource_id, status, physical_res_id=None):
     resource = self.resources[resource_id]
     state = self.resource_states[resource_id] = self.resource_states.get(resource_id) or {}
     attr_defaults = (('LogicalResourceId', resource_id), ('PhysicalResourceId', physical_res_id))
     for res in [resource, state]:
         for attr, default in attr_defaults:
             res[attr] = res.get(attr) or default
     state['ResourceStatus'] = status
     state['StackName'] = state.get('StackName') or self.stack_name
     state['StackId'] = state.get('StackId') or self.stack_id
     state['ResourceType'] = state.get('ResourceType') or self.resources[resource_id].get('Type')
     state['LastUpdatedTimestamp'] = timestamp_millis()
     self.add_stack_event(resource_id, physical_res_id, status)
Beispiel #14
0
    def forward_request(self, method, path, data, headers):
        global STREAM_CONSUMERS
        data = json.loads(to_str(data or '{}'))
        action = headers.get('X-Amz-Target')

        if action == '%s.RegisterStreamConsumer' % ACTION_PREFIX:
            consumer = clone(data)
            consumer['ConsumerStatus'] = 'ACTIVE'
            consumer['ConsumerARN'] = '%s/consumer/%s' % (data['StreamARN'], data['ConsumerName'])
            consumer['ConsumerCreationTimestamp'] = timestamp_millis()
            consumer = json_safe(consumer)
            STREAM_CONSUMERS.append(consumer)
            return {'Consumer': consumer}
        elif action == '%s.DeregisterStreamConsumer' % ACTION_PREFIX:
            def consumer_matches(c):
                stream_arn = data.get('StreamARN')
                cons_name = data.get('ConsumerName')
                cons_arn = data.get('ConsumerARN')
                return (c.get('ConsumerARN') == cons_arn or
                    (c.get('StreamARN') == stream_arn and c.get('ConsumerName') == cons_name))
            STREAM_CONSUMERS = [c for c in STREAM_CONSUMERS if not consumer_matches(c)]
            return {}
        elif action == '%s.ListStreamConsumers' % ACTION_PREFIX:
            result = {
                'Consumers': [c for c in STREAM_CONSUMERS if c.get('StreamARN') == data.get('StreamARN')]
            }
            return result
        elif action == '%s.DescribeStreamConsumer' % ACTION_PREFIX:
            consumer_arn = data.get('ConsumerARN') or data['ConsumerName']
            consumer_name = data.get('ConsumerName') or data['ConsumerARN']
            result = {
                'ConsumerDescription': {
                    'ConsumerARN': consumer_arn,
                    # 'ConsumerCreationTimestamp': number,
                    'ConsumerName': consumer_name,
                    'ConsumerStatus': 'ACTIVE',
                    'StreamARN': data.get('StreamARN')
                }
            }
            return result

        if random.random() < config.KINESIS_ERROR_PROBABILITY:
            action = headers.get('X-Amz-Target')
            if action in [ACTION_PUT_RECORD, ACTION_PUT_RECORDS]:
                return kinesis_error_response(data, action)
        return True
Beispiel #15
0
def get_event_message(event_name,
                      bucket_name,
                      file_name='testfile.txt',
                      version_id=None,
                      file_size=0):
    # Based on: http://docs.aws.amazon.com/AmazonS3/latest/dev/notification-content-structure.html
    bucket_name = normalize_bucket_name(bucket_name)
    return {
        'Records': [{
            'eventVersion': '2.0',
            'eventSource': 'aws:s3',
            'awsRegion': aws_stack.get_region(),
            'eventTime': timestamp_millis(),
            'eventName': event_name,
            'userIdentity': {
                'principalId': 'AIDAJDPLRKLG7UEXAMPLE'
            },
            'requestParameters': {
                'sourceIPAddress': '127.0.0.1'  # TODO determine real source IP
            },
            'responseElements': {
                'x-amz-request-id': short_uid(),
                'x-amz-id-2':
                'eftixk72aD6Ap51TnqcoF8eFidJG9Z/2'  # Amazon S3 host that processed the request
            },
            's3': {
                's3SchemaVersion': '1.0',
                'configurationId': 'testConfigRule',
                'bucket': {
                    'name': bucket_name,
                    'ownerIdentity': {
                        'principalId': 'A3NL1KOZZKExample'
                    },
                    'arn': 'arn:aws:s3:::%s' % bucket_name
                },
                'object': {
                    'key': file_name,
                    'size': file_size,
                    'eTag': 'd41d8cd98f00b204e9800998ecf8427e',
                    'versionId': version_id,
                    'sequencer': '0055AED6DCD90281E5'
                }
            }
        }]
    }
 def __init__(self, metadata=None, template=None):
     if template is None:
         template = {}
     self.metadata = metadata or {}
     self.template = template or {}
     self._template_raw = clone_safe(self.template)
     self.template_original = clone_safe(self.template)
     # initialize resources
     for resource_id, resource in self.template_resources.items():
         resource["LogicalResourceId"] = self.template_original[
             "Resources"][resource_id]["LogicalResourceId"] = (
                 resource.get("LogicalResourceId") or resource_id)
     # initialize stack template attributes
     self.template["StackId"] = self.metadata[
         "StackId"] = self.metadata.get(
             "StackId") or aws_stack.cloudformation_stack_arn(
                 self.stack_name, short_uid())
     self.template["Parameters"] = self.template.get("Parameters") or {}
     self.template["Outputs"] = self.template.get("Outputs") or {}
     self.template["Conditions"] = self.template.get("Conditions") or {}
     # initialize metadata
     self.metadata["Parameters"] = self.metadata.get("Parameters") or []
     self.metadata["StackStatus"] = "CREATE_IN_PROGRESS"
     self.metadata["CreationTime"] = self.metadata.get(
         "CreationTime") or timestamp_millis()
     # maps resource id to resource state
     self._resource_states = {}
     # list of stack events
     self.events = []
     # list of stack change sets
     self.change_sets = []
     # initialize parameters
     for i in range(1, 100):
         key = "Parameters.member.%s.ParameterKey" % i
         value = "Parameters.member.%s.ParameterValue" % i
         key = self.metadata.get(key)
         value = self.metadata.get(value)
         if not key:
             break
         self.metadata["Parameters"].append({
             "ParameterKey": key,
             "ParameterValue": value
         })
Beispiel #17
0
 def set_resource_status(self, resource_id, status, physical_res_id=None):
     resource = self.resources[resource_id]
     state = self.resource_states[resource_id] = self.resource_states.get(
         resource_id) or {}
     attr_defaults = (
         ("LogicalResourceId", resource_id),
         ("PhysicalResourceId", physical_res_id),
     )
     for res in [resource, state]:
         for attr, default in attr_defaults:
             res[attr] = res.get(attr) or default
     state["PreviousResourceStatus"] = state.get("ResourceStatus")
     state["ResourceStatus"] = status
     state["StackName"] = state.get("StackName") or self.stack_name
     state["StackId"] = state.get("StackId") or self.stack_id
     state["ResourceType"] = state.get(
         "ResourceType") or self.resources[resource_id].get("Type")
     state["LastUpdatedTimestamp"] = timestamp_millis()
     self.add_stack_event(resource_id, physical_res_id, status)
Beispiel #18
0
 def _send_to_failure_destination(
     self,
     shard_id,
     start_sequence_num,
     end_sequence_num,
     source_arn,
     func_arn,
     invoke_count,
     status_code,
     batch_size,
     first_record_arrival_time,
     last_record_arrival_time,
     destination,
 ):
     """
     Creates a metadata payload relating to a failed Lambda invocation and delivers it to the given destination
     """
     payload = {
         "version": "1.0",
         "timestamp": timestamp_millis(),
         "requestContext": {
             "requestId": long_uid(),
             "functionArn": func_arn,
             "condition": "RetryAttemptsExhausted",
             "approximateInvokeCount": invoke_count,
         },
         "responseContext": {
             "statusCode": status_code,
             "executedVersion": "$LATEST",  # TODO: don't hardcode these fields
             "functionError": "Unhandled",
         },
     }
     details = {
         "shardId": shard_id,
         "startSequenceNumber": start_sequence_num,
         "endSequenceNumber": end_sequence_num,
         "approximateArrivalOfFirstRecord": first_record_arrival_time,
         "approximateArrivalOfLastRecord": last_record_arrival_time,
         "batchSize": batch_size,
         "streamArn": source_arn,
     }
     payload[self._FAILURE_PAYLOAD_DETAILS_FIELD_NAME] = details
     send_event_to_target(destination, payload)
Beispiel #19
0
def handle_associate_vpc_request(method, path, data):
    is_associate = path.endswith("/associatevpc")
    region_details = Route53Backend.get()
    zone_id = extract_zone_id(path)
    req_data = clone(xmltodict.parse(to_str(data)))
    zone_details = region_details.vpc_hosted_zone_associations.get(zone_id) or []
    if is_associate:
        assoc_id = short_uid()
        zone_data = req_data.get("AssociateVPCWithHostedZoneRequest", {})
        zone_data["Id"] = assoc_id
        zone_data["HostedZoneId"] = zone_id
        zone_details.append(zone_data)
        response_entry = {
            "ChangeInfo": {
                "Id": assoc_id,
                "Status": "INSYNC",
                "SubmittedAt": timestamp_millis(),
            }
        }
        # update VPC info in hosted zone moto object - fixes required after https://github.com/spulec/moto/pull/4786
        hosted_zone = route53_backend.zones.get(zone_id)
        if not getattr(hosted_zone, "vpcid", None):
            hosted_zone.vpcid = zone_data["VPC"].get("VPCId")
        if not getattr(hosted_zone, "vpcregion", None):
            hosted_zone.vpcregion = aws_stack.get_region()
    else:

        def _match(z):
            return z["HostedZoneId"] == zone_id and z["VPC"]["VPCId"] == zone_data["VPC"]["VPCId"]

        zone_data = req_data.get("DisassociateVPCFromHostedZoneRequest", {})
        response_entry = [z for z in zone_details if _match(z)]
        zone_details = [z for z in zone_details if not _match(z)]

        if not response_entry:
            return 404
        response_entry = response_entry[0]

    region_details.vpc_hosted_zone_associations[zone_id] = zone_details

    response_tag = "%sVPCWithHostedZoneResponse" % ("Associate" if is_associate else "Disassociate")
    return {response_tag: response_entry}
Beispiel #20
0
    def forward_request(self, method, path, data, headers):
        parsed_url = urlparse(path)
        action = parsed_url.path.split("/")[2]

        if method == "GET" and action == "change":
            resource_id = parsed_url.path.split("/")[-1]
            change_response = {
                "GetChangeResponse": {
                    "ChangeInfo": {
                        "Id": resource_id,
                        "Status": "INSYNC",
                        "SubmittedAt": timestamp_millis(),
                    }
                }
            }
            body = xmltodict.unparse(change_response)
            response = requests_response(body)
            return response

        return True
    def forward_request(self, method, path, data, headers):
        parsed_url = urlparse(path)
        action = parsed_url.path.split('/')[2]

        if action == 'change':
            if method == 'GET':
                resource_id = parsed_url.path.split('/')[-1]
                change_response = {
                    'GetChangeResponse': {
                        'ChangeInfo': {
                            'Id': resource_id,
                            'Status': 'INSYNC',
                            'SubmittedAt': timestamp_millis()
                        }
                    }
                }
                body = xmltodict.unparse(change_response)
                response = requests_response(body)
                return response

        return True
Beispiel #22
0
def handle_associate_vpc_request(method, path, data):
    is_associate = path.endswith("/associatevpc")
    region_details = Route53Backend.get()
    path_parts = path.lstrip("/").split("/")
    zone_id = path_parts[2]
    req_data = xmltodict.parse(to_str(data))
    zone_details = region_details.vpc_hosted_zone_associations.get(
        zone_id) or []
    if is_associate:
        assoc_id = short_uid()
        zone_data = req_data.get("AssociateVPCWithHostedZoneRequest", {})
        zone_data["Id"] = assoc_id
        zone_data["HostedZoneId"] = zone_id
        zone_details.append(zone_data)
        response_entry = {
            "ChangeInfo": {
                "Id": assoc_id,
                "Status": "INSYNC",
                "SubmittedAt": timestamp_millis(),
            }
        }
    else:

        def _match(z):
            return z["HostedZoneId"] == zone_id and z["VPC"][
                "VPCId"] == zone_data["VPC"]["VPCId"]

        zone_data = req_data.get("DisassociateVPCFromHostedZoneRequest", {})
        response_entry = [z for z in zone_details if _match(z)]
        zone_details = [z for z in zone_details if not _match(z)]
        if not response_entry:
            return 404
        response_entry = response_entry[0]

    region_details.vpc_hosted_zone_associations[zone_id] = zone_details

    response_tag = "%sVPCWithHostedZoneResponse" % ("Associate" if is_associate
                                                    else "Disassociate")
    return {response_tag: response_entry}
Beispiel #23
0
def lambda_result_to_destination(func_details, event, result, is_async, error):
    if not func_details.destination_enabled():
        return

    payload = {
        'version': '1.0',
        'timestamp': timestamp_millis(),
        'requestContext': {
            'requestId': long_uid(),
            'functionArn': func_details.arn(),
            'condition': 'RetriesExhausted',
            'approximateInvokeCount': 1
        },
        'requestPayload': event,
        'responseContext': {
            'statusCode': 200,
            'executedVersion': '$LATEST'
        },
        'responsePayload': {}
    }

    if is_async:
        payload['responsePayload']['statusCode'] = 200
        payload['responsePayload']['headers'] = None
        payload['responsePayload']['multiValueHeaders'] = None
        payload['responsePayload']['body'] = ''
    else:
        payload['responsePayload'] = result.result

    if error:
        payload['responseContext']['functionError'] = 'Unhandled'
        # add the result in the response payload
        if error.result is not None:
            payload['responsePayload'] = json.loads(error.result)
        send_event_to_target(func_details.on_failed_invocation, payload)
        return

    send_event_to_target(func_details.on_successful_invocation, payload)
Beispiel #24
0
    def forward_request(self, method, path, data, headers):
        parsed_url = urlparse(path)
        action = parsed_url.path.split('/')[2]

        is_associate = path.endswith('/associatevpc')
        if is_associate or path.endswith('/disassociatevpc'):
            path_parts = path.split('/')
            zone_id = path_parts[3]
            req_data = xmltodict.parse(to_str(data))
            region_details = Route53Backend.get()
            zone_details = region_details.vpc_hosted_zone_associations.get(
                zone_id) or []
            if is_associate:
                assoc_id = short_uid()
                zone_data = req_data.get('AssociateVPCWithHostedZoneRequest',
                                         {})
                zone_data['Id'] = assoc_id
                zone_data['HostedZoneId'] = zone_id
                zone_details.append(zone_data)
                response_entry = {
                    'ChangeInfo': {
                        'Id': assoc_id,
                        'Status': 'INSYNC',
                        'SubmittedAt': timestamp_millis()
                    }
                }
            else:

                def _match(z):
                    return z['HostedZoneId'] == zone_id and z['VPC'][
                        'VPCId'] == zone_data['VPC']['VPCId']

                zone_data = req_data.get(
                    'DisassociateVPCFromHostedZoneRequest', {})
                response_entry = [z for z in zone_details if _match(z)]
                zone_details = [z for z in zone_details if not _match(z)]
                if not response_entry:
                    return 404
                response_entry = response_entry[0]

            region_details.vpc_hosted_zone_associations[zone_id] = zone_details

            response_tag = '%sVPCWithHostedZoneResponse' % (
                'Associate' if is_associate else 'Disassociate')
            response = {response_tag: response_entry}
            body = xmltodict.unparse(response)
            response = requests_response(body)
            return response

        if action == 'change':
            if method == 'GET':
                resource_id = parsed_url.path.split('/')[-1]
                change_response = {
                    'GetChangeResponse': {
                        'ChangeInfo': {
                            'Id': resource_id,
                            'Status': 'INSYNC',
                            'SubmittedAt': timestamp_millis()
                        }
                    }
                }
                body = xmltodict.unparse(change_response)
                response = requests_response(body)
                return response

        return True
Beispiel #25
0
    def return_response(self, method, path, data, headers, response):
        action = headers.get('X-Amz-Target')
        data = json.loads(to_str(data or '{}'))

        records = []
        if action in (ACTION_CREATE_STREAM, ACTION_DELETE_STREAM):
            event_type = (event_publisher.EVENT_KINESIS_CREATE_STREAM if action == ACTION_CREATE_STREAM
                          else event_publisher.EVENT_KINESIS_DELETE_STREAM)
            payload = {'n': event_publisher.get_hash(data.get('StreamName'))}
            if action == ACTION_CREATE_STREAM:
                payload['s'] = data.get('ShardCount')
            event_publisher.fire_event(event_type, payload=payload)
        elif action == ACTION_PUT_RECORD:
            response_body = json.loads(to_str(response.content))
            event_record = {
                'approximateArrivalTimestamp': timestamp_millis(),
                'data': data['Data'],
                'encryptionType': 'NONE',
                'partitionKey': data['PartitionKey'],
                'sequenceNumber': response_body.get('SequenceNumber')
            }
            event_records = [event_record]
            stream_name = data['StreamName']
            lambda_api.process_kinesis_records(event_records, stream_name)
        elif action == ACTION_PUT_RECORDS:
            event_records = []
            response_body = json.loads(to_str(response.content))
            if 'Records' in response_body:
                response_records = response_body['Records']
                records = data['Records']
                for index in range(0, len(records)):
                    record = records[index]
                    event_record = {
                        'approximateArrivalTimestamp': timestamp_millis(),
                        'data': record['Data'],
                        'encryptionType': 'NONE',
                        'partitionKey': record['PartitionKey'],
                        'sequenceNumber': response_records[index].get('SequenceNumber')
                    }
                    event_records.append(event_record)
                stream_name = data['StreamName']
                lambda_api.process_kinesis_records(event_records, stream_name)
        elif action == ACTION_UPDATE_SHARD_COUNT:
            # Currently kinesalite, which backs the Kinesis implementation for localstack, does
            # not support UpdateShardCount:
            # https://github.com/mhart/kinesalite/issues/61
            #
            # [Terraform](https://www.terraform.io) makes the call to UpdateShardCount when it
            # applies Kinesis resources. A Terraform run fails when this is not present.
            #
            # The code that follows just returns a successful response, bypassing the 400
            # response that kinesalite returns.
            #
            response = Response()
            response.status_code = 200
            content = {
                'CurrentShardCount': 1,
                'StreamName': data['StreamName'],
                'TargetShardCount': data['TargetShardCount']
            }
            response.encoding = 'UTF-8'
            response._content = json.dumps(content)
            return response
    def return_response(self, method, path, data, headers, response):
        if response.status_code < 400 or response.status_code >= 500:
            return

        region_details = Route53Backend.get()

        is_associate = path.endswith('/associatevpc')
        if is_associate or path.endswith('/disassociatevpc'):
            path_parts = path.lstrip('/').split('/')
            zone_id = path_parts[2]
            req_data = xmltodict.parse(to_str(data))
            zone_details = region_details.vpc_hosted_zone_associations.get(
                zone_id) or []
            if is_associate:
                assoc_id = short_uid()
                zone_data = req_data.get('AssociateVPCWithHostedZoneRequest',
                                         {})
                zone_data['Id'] = assoc_id
                zone_data['HostedZoneId'] = zone_id
                zone_details.append(zone_data)
                response_entry = {
                    'ChangeInfo': {
                        'Id': assoc_id,
                        'Status': 'INSYNC',
                        'SubmittedAt': timestamp_millis()
                    }
                }
            else:

                def _match(z):
                    return z['HostedZoneId'] == zone_id and z['VPC'][
                        'VPCId'] == zone_data['VPC']['VPCId']

                zone_data = req_data.get(
                    'DisassociateVPCFromHostedZoneRequest', {})
                response_entry = [z for z in zone_details if _match(z)]
                zone_details = [z for z in zone_details if not _match(z)]
                if not response_entry:
                    return 404
                response_entry = response_entry[0]

            region_details.vpc_hosted_zone_associations[zone_id] = zone_details

            response_tag = '%sVPCWithHostedZoneResponse' % (
                'Associate' if is_associate else 'Disassociate')
            response = {response_tag: response_entry}
            body = xmltodict.unparse(response)
            response = requests_response(body)
            return response

        if '/hostedzonesbyvpc' in path and method == 'GET':
            req_data = parse_request_data(method, path, data)
            vpc_id = req_data.get('vpcid')
            zone_details = region_details.vpc_hosted_zone_associations
            result = [
                z for z_list in zone_details.values() for z in z_list
                if z['VPC']['VPCId'] == vpc_id
            ]
            response = {
                'ListHostedZonesByVPCResponse': {
                    'HostedZoneSummaries': {
                        'HostedZoneSummary': result
                    }
                }
            }
            body = xmltodict.unparse(response)
            response = requests_response(body)
            return response
Beispiel #27
0
def fix_hardcoded_creation_date(response):
    # TODO: remove once this is fixed upstream
    search = r'<CreationTime>\s*(2011-05-23T15:47:44Z)?\s*</CreationTime>'
    replace = r'<CreationTime>%s</CreationTime>' % timestamp_millis()
    fix_in_response(search, replace, response)
Beispiel #28
0
 def test_timestamp_millis(self):
     result = common.timestamp_millis(datetime.now())
     assert "T" in result
     result = common.timestamp_millis(date.today())
     assert "00:00:00" in result
     assert "T" in result
Beispiel #29
0
 def test_timestamp_millis(self):
     result = common.timestamp_millis(datetime.now())
     self.assertIn('T', result)
     result = common.timestamp_millis(date.today())
     self.assertIn('00:00:00', result)
     self.assertIn('T', result)