Beispiel #1
0
    def view_func(path):
        if _is_binary_cloud_event(request):
            # Support CloudEvents in binary content mode, with data being the
            # whole request body and context attributes retrieved from request
            # headers.
            data = request.get_data()
            context = Context(
                eventId=request.headers.get("ce-eventId"),
                timestamp=request.headers.get("ce-timestamp"),
                eventType=request.headers.get("ce-eventType"),
                resource=request.headers.get("ce-resource"),
            )
            function(data, context)
        else:
            # This is a regular CloudEvent
            event_data = request.get_json()
            if not event_data:
                flask.abort(400)
            if _is_pub_sub_message(request):
                event_object = _PubSubPushEvent(**event_data)
            else:
                event_object = _Event(**event_data)
            data = event_object.data
            context = Context(**event_object.context)
            function(data, context)

        return "OK"
Beispiel #2
0
    def view_func(path):
        if event_conversion.is_convertable_cloud_event(request):
            # Convert this CloudEvent to the equivalent background event data and context.
            data, context = event_conversion.cloud_event_to_background_event(
                request)
            function(data, context)
        elif is_binary(request.headers):
            # Support CloudEvents in binary content mode, with data being the
            # whole request body and context attributes retrieved from request
            # headers.
            data = request.get_data()
            context = Context(
                eventId=request.headers.get("ce-eventId"),
                timestamp=request.headers.get("ce-timestamp"),
                eventType=request.headers.get("ce-eventType"),
                resource=request.headers.get("ce-resource"),
            )
            function(data, context)
        else:
            # This is a regular CloudEvent
            event_data = event_conversion.marshal_background_event_data(
                request)
            if not event_data:
                flask.abort(400)
            event_object = BackgroundEvent(**event_data)
            data = event_object.data
            context = Context(**event_object.context)
            function(data, context)

        return "OK"
def test_split_resource(background_resource):
    context = Context(eventType="google.storage.object.finalize",
                      resource=background_resource)
    service, resource, subject = event_conversion._split_resource(context)
    assert service == "storage.googleapis.com"
    assert resource == "projects/_/buckets/some-bucket"
    assert subject == "objects/folder/Test.cs"
Beispiel #4
0
def _run_legacy_event(function, request):
    event_data = request.get_json()
    if not event_data:
        flask.abort(400)
    event_object = _Event(**event_data)
    data = event_object.data
    context = Context(**event_object.context)
    function(data, context)
Beispiel #5
0
def cloud_event_to_background_event(request) -> Tuple[Any, Context]:
    """Converts a background event represented by the given HTTP request into a CloudEvent."""
    try:
        event = from_http(request.headers, request.get_data())
        data = event.data
        service, name = _split_ce_source(event["source"])

        if event["type"] not in _CE_TO_BACKGROUND_TYPE:
            raise EventConversionException(
                f'Unable to find background event equivalent type for "{event["type"]}"'
            )

        if service == _PUBSUB_CE_SERVICE:
            resource = {
                "service": service,
                "name": name,
                "type": _PUBSUB_MESSAGE_TYPE
            }
            if "message" in data:
                data = data["message"]
            if "messageId" in data:
                del data["messageId"]
            if "publishTime" in data:
                del data["publishTime"]
        elif service == _FIREBASE_AUTH_CE_SERVICE:
            resource = name
            if "metadata" in data:
                for old, new in _FIREBASE_AUTH_METADATA_FIELDS_CE_TO_BACKGROUND.items(
                ):
                    if old in data["metadata"]:
                        data["metadata"][new] = data["metadata"][old]
                        del data["metadata"][old]
        elif service == _STORAGE_CE_SERVICE:
            resource = {
                "name": f"{name}/{event['subject']}",
                "service": service,
                "type": data["kind"],
            }
        elif service == _FIREBASE_DB_CE_SERVICE:
            name = re.sub("/locations/[^/]+", "", name)
            resource = f"{name}/{event['subject']}"
        else:
            resource = f"{name}/{event['subject']}"

        context = Context(
            eventId=event["id"],
            timestamp=event["time"],
            eventType=_CE_TO_BACKGROUND_TYPE[event["type"]],
            resource=resource,
        )
        return (data, context)
    except (AttributeError, KeyError, TypeError, MissingRequiredFields):
        raise EventConversionException(
            "Failed to convert CloudEvent to BackgroundEvent.")
Beispiel #6
0
def fixture_to_pubsub(fixture):
    with open('test/fixtures/%s.json' % fixture, 'r') as file:
        data = json.loads(file.read())

        event = {
            'data': data[0]['message']['data'],
            'attributes': data[0]['message']['attributes']
        }
        context = Context(eventId=data[0]['message']['messageId'],
                          timestamp=data[0]['message']['publishTime'])
        return event, context
def test_split_resource_no_resource_regex_match():
    background_resource = {
        "service": "storage.googleapis.com",
        # This name will not match the regex associated with the service.
        "name": "foo/bar/baz",
        "type": "storage#object",
    }
    context = Context(eventType="google.storage.object.finalize",
                      resource=background_resource)
    with pytest.raises(EventConversionException) as exc_info:
        event_conversion._split_resource(context)
    assert "Resource regex did not match" in exc_info.value.args[0]
def test_split_resource_without_service_unknown_event_type():
    background_resource = {
        "name": "projects/_/buckets/some-bucket/objects/folder/Test.cs",
        "type": "storage#object",
    }
    # This event type cannot be mapped to an equivalent CloudEvent type.
    context = Context(eventType="not_a_known_event_type",
                      resource=background_resource)
    with pytest.raises(EventConversionException) as exc_info:
        event_conversion._split_resource(context)
    assert "Unable to find CloudEvent equivalent service" in exc_info.value.args[
        0]
def test_split_resource_unknown_service_and_event_type():
    # With both an unknown service and an unknown event type, we won't attempt any
    # event type mapping or resource/subject splitting.
    background_resource = {
        "service": "not_a_known_service",
        "name": "projects/_/my/stuff/at/test.txt",
        "type": "storage#object",
    }
    context = Context(eventType="not_a_known_event_type",
                      resource=background_resource)
    service, resource, subject = event_conversion._split_resource(context)
    assert service == "not_a_known_service"
    assert resource == "projects/_/my/stuff/at/test.txt"
    assert subject == ""
def background_event_to_cloudevent(request) -> CloudEvent:
    """Converts a background event represented by the given HTTP request into a CloudEvent."""
    event_data = marshal_background_event_data(request)
    if not event_data:
        raise EventConversionException("Failed to parse JSON")

    event_object = BackgroundEvent(**event_data)
    data = event_object.data
    context = Context(**event_object.context)

    if context.event_type not in _BACKGROUND_TO_CE_TYPE:
        raise EventConversionException(
            f'Unable to find CloudEvent equivalent type for "{context.event_type}"'
        )
    new_type = _BACKGROUND_TO_CE_TYPE[context.event_type]

    service, resource, subject = _split_resource(context)

    # Handle Pub/Sub events.
    if service == _PUBSUB_CE_SERVICE:
        data = {"message": data}

    # Handle Firebase Auth events.
    if service == _FIREBASE_AUTH_CE_SERVICE:
        if "metadata" in data:
            for old, new in _FIREBASE_AUTH_METADATA_FIELDS_BACKGROUND_TO_CE.items(
            ):
                if old in data["metadata"]:
                    data["metadata"][new] = data["metadata"][old]
                    del data["metadata"][old]
        if "uid" in data:
            uid = data["uid"]
            subject = f"users/{uid}"

    metadata = {
        "id": context.event_id,
        "time": context.timestamp,
        "specversion": _CLOUDEVENT_SPEC_VERSION,
        "datacontenttype": "application/json",
        "type": new_type,
        "source": f"//{service}/{resource}",
    }

    if subject:
        metadata["subject"] = subject

    return CloudEvent(metadata, data)
Beispiel #11
0
def _run_legacy_event(function, request):
    event_data = request.get_json()
    if not event_data:
        flask.abort(400)

    ###############
    # Need to add this code to make pubsub events work.
    if 'message' in event_data:
        if 'data' not in event_data:
            message = event_data['message']
            event_data['data'] = {
                'data': message.get('data'),
                'attributes': message.get('attributes')
            }
    ###############

    event_object = _Event(**event_data)
    data = event_object.data
    context = Context(**event_object.context)
    function(data, context)
Beispiel #12
0
def background_event_to_cloud_event(request) -> CloudEvent:
    """Converts a background event represented by the given HTTP request into a CloudEvent."""
    event_data = marshal_background_event_data(request)
    if not event_data:
        raise EventConversionException("Failed to parse JSON")

    event_object = BackgroundEvent(**event_data)
    data = event_object.data
    context = Context(**event_object.context)

    if context.event_type not in _BACKGROUND_TO_CE_TYPE:
        raise EventConversionException(
            f'Unable to find CloudEvent equivalent type for "{context.event_type}"'
        )
    new_type = _BACKGROUND_TO_CE_TYPE[context.event_type]

    service, resource, subject = _split_resource(context)
    source = f"//{service}/{resource}"

    # Handle Pub/Sub events.
    if service == _PUBSUB_CE_SERVICE:
        if "messageId" not in data:
            data["messageId"] = context.event_id
        if "publishTime" not in data:
            data["publishTime"] = context.timestamp
        data = {"message": data}

    # Handle Firebase Auth events.
    if service == _FIREBASE_AUTH_CE_SERVICE:
        if "metadata" in data:
            for old, new in _FIREBASE_AUTH_METADATA_FIELDS_BACKGROUND_TO_CE.items(
            ):
                if old in data["metadata"]:
                    data["metadata"][new] = data["metadata"][old]
                    del data["metadata"][old]
        if "uid" in data:
            uid = data["uid"]
            subject = f"users/{uid}"

    # Handle Firebase DB events.
    if service == _FIREBASE_DB_CE_SERVICE:
        # The CE source of firebasedatabase CloudEvents includes location information
        # that is inferred from the 'domain' field of legacy events.
        if "domain" not in event_data:
            raise EventConversionException(
                "Invalid FirebaseDB event payload: missing 'domain'")

        domain = event_data["domain"]
        location = "us-central1"
        if domain != "firebaseio.com":
            location = domain.split(".")[0]

        resource = f"projects/_/locations/{location}/{resource}"
        source = f"//{service}/{resource}"

    metadata = {
        "id": context.event_id,
        "time": context.timestamp,
        "specversion": _CLOUD_EVENT_SPEC_VERSION,
        "datacontenttype": "application/json",
        "type": new_type,
        "source": source,
    }

    if subject:
        metadata["subject"] = subject

    return CloudEvent(metadata, data)
Beispiel #13
0
        logger.setLevel(logging.INFO)
    json_handler = logging.StreamHandler()
    formatter = jsonlogger.JsonFormatter()
    json_handler.setFormatter(formatter)
    logger.addHandler(json_handler)
    return logger


if __name__ == '__main__':
    arg_parser = argparse.ArgumentParser(
        description='Pub/Sub to Inbox, turn Pub/Sub messages into emails')
    arg_parser.add_argument('--config', type=str, help='Configuration file')
    arg_parser.add_argument('message',
                            type=str,
                            help='JSON file containing the message(s)')
    args = arg_parser.parse_args()
    if args.config:
        config_file_name = args.config
    with open(args.message) as f:
        contents = f.read()
        messages = json.loads(contents)
        for message in messages:
            event = {
                'data': message['message']['data'],
                'attributes': message['message']['attributes']
                if 'attributes' in message['message'] else {}
            }
            context = Context(eventId=message['message']['messageId'],
                              timestamp=message['message']['publishTime'])
            process_pubsub(event, context)