Exemplo n.º 1
0
    def put_targets(self, name, event_bus_name, targets):
        # super simple ARN check
        invalid_arn = next(
            (target["Arn"] for target in targets
             if not re.match(r"arn:[\d\w:\-/]*", target["Arn"])),
            None,
        )
        if invalid_arn:
            raise ValidationException(
                "Parameter {} is not valid. "
                "Reason: Provided Arn is not in correct format.".format(
                    invalid_arn))

        for target in targets:
            arn = target["Arn"]

            if (":sqs:" in arn and arn.endswith(".fifo")
                    and not target.get("SqsParameters")):
                raise ValidationException(
                    "Parameter(s) SqsParameters must be specified for target: {}."
                    .format(target["Id"]))

        rule = self.rules.get(name)

        if not rule:
            raise ResourceNotFoundException(
                "Rule {0} does not exist on EventBus {1}.".format(
                    name, event_bus_name))

        rule.put_targets(targets)
Exemplo n.º 2
0
    def list_archives(self, name_prefix, source_arn, state):
        if [name_prefix, source_arn, state].count(None) < 2:
            raise ValidationException(
                "At most one filter is allowed for ListArchives. "
                "Use either : State, EventSourceArn, or NamePrefix.")

        if state and state not in Archive.VALID_STATES:
            raise ValidationException(
                "1 validation error detected: "
                "Value '{0}' at 'state' failed to satisfy constraint: "
                "Member must satisfy enum value set: "
                "[{1}]".format(state, ", ".join(Archive.VALID_STATES)))

        if [name_prefix, source_arn, state].count(None) == 3:
            return [
                archive.describe_short() for archive in self.archives.values()
            ]

        result = []

        for archive in self.archives.values():
            if name_prefix and archive.name.startswith(name_prefix):
                result.append(archive.describe_short())
            elif source_arn and archive.source_arn == source_arn:
                result.append(archive.describe_short())
            elif state and archive.state == state:
                result.append(archive.describe_short())

        return result
Exemplo n.º 3
0
    def list_replays(self, name_prefix, source_arn, state):
        if [name_prefix, source_arn, state].count(None) < 2:
            raise ValidationException(
                "At most one filter is allowed for ListReplays. "
                "Use either : State, EventSourceArn, or NamePrefix.")

        valid_states = sorted([item.value for item in ReplayState])
        if state and state not in valid_states:
            raise ValidationException(
                "1 validation error detected: "
                "Value '{0}' at 'state' failed to satisfy constraint: "
                "Member must satisfy enum value set: "
                "[{1}]".format(state, ", ".join(valid_states)))

        if [name_prefix, source_arn, state].count(None) == 3:
            return [
                replay.describe_short() for replay in self.replays.values()
            ]

        result = []

        for replay in self.replays.values():
            if name_prefix and replay.name.startswith(name_prefix):
                result.append(replay.describe_short())
            elif source_arn and replay.source_arn == source_arn:
                result.append(replay.describe_short())
            elif state and replay.state == state:
                result.append(replay.describe_short())

        return result
Exemplo n.º 4
0
    def start_replay(
        self, name, description, source_arn, start_time, end_time, destination
    ):
        event_bus_arn = destination["Arn"]
        event_bus_arn_pattern = r"^arn:aws:events:[a-zA-Z0-9-]+:\d{12}:event-bus/"
        if not re.match(event_bus_arn_pattern, event_bus_arn):
            raise ValidationException(
                "Parameter Destination.Arn is not valid. "
                "Reason: Must contain an event bus ARN."
            )

        self._get_event_bus(event_bus_arn)

        archive_name = source_arn.split("/")[-1]
        archive = self.archives.get(archive_name)
        if not archive:
            raise ValidationException(
                "Parameter EventSourceArn is not valid. "
                "Reason: Archive {} does not exist.".format(archive_name)
            )

        if event_bus_arn != archive.source_arn:
            raise ValidationException(
                "Parameter Destination.Arn is not valid. "
                "Reason: Cross event bus replay is not permitted."
            )

        if start_time > end_time:
            raise ValidationException(
                "Parameter EventEndTime is not valid. "
                "Reason: EventStartTime must be before EventEndTime."
            )

        if name in self.replays:
            raise ResourceAlreadyExistsException(
                "Replay {} already exists.".format(name)
            )

        replay = Replay(
            self.region_name,
            name,
            description,
            source_arn,
            start_time,
            end_time,
            destination,
        )

        self.replays[name] = replay

        replay.replay_events(archive)

        return {
            "ReplayArn": replay.arn,
            "ReplayStartTime": replay.start_time,
            "State": ReplayState.STARTING.value,  # the replay will be done before returning the response
        }
Exemplo n.º 5
0
    def create_archive(self, name, source_arn, description, event_pattern,
                       retention):
        if len(name) > 48:
            raise ValidationException(
                " 1 validation error detected: "
                "Value '{}' at 'archiveName' failed to satisfy constraint: "
                "Member must have length less than or equal to 48".format(
                    name))

        if event_pattern:
            self._validate_event_pattern(event_pattern)

        event_bus_name = source_arn.split("/")[-1]
        if event_bus_name not in self.event_buses:
            raise ResourceNotFoundException(
                "Event bus {} does not exist.".format(event_bus_name))

        if name in self.archives:
            raise ResourceAlreadyExistsException(
                "Archive {} already exists.".format(name))

        archive = Archive(self.region_name, name, source_arn, description,
                          event_pattern, retention)

        self.archives[name] = archive

        return archive
Exemplo n.º 6
0
    def create_archive(self, name, source_arn, description, event_pattern, retention):
        if len(name) > 48:
            raise ValidationException(
                " 1 validation error detected: "
                "Value '{}' at 'archiveName' failed to satisfy constraint: "
                "Member must have length less than or equal to 48".format(name)
            )

        if event_pattern:
            self._validate_event_pattern(event_pattern)

        event_bus = self._get_event_bus(source_arn)

        if name in self.archives:
            raise ResourceAlreadyExistsException(
                "Archive {} already exists.".format(name)
            )

        archive = Archive(
            self.region_name, name, source_arn, description, event_pattern, retention
        )

        rule_event_pattern = json.loads(event_pattern or "{}")
        rule_event_pattern["replay-name"] = [{"exists": False}]

        rule = self.put_rule(
            "Events-Archive-{}".format(name),
            **{
                "EventPattern": json.dumps(rule_event_pattern),
                "EventBusName": event_bus.name,
                "ManagedBy": "prod.vhs.events.aws.internal",
            }
        )
        self.put_targets(
            rule.name,
            rule.event_bus_name,
            [
                {
                    "Id": rule.name,
                    "Arn": "arn:aws:events:{}:::".format(self.region_name),
                    "InputTransformer": {
                        "InputPathsMap": {},
                        "InputTemplate": json.dumps(
                            {
                                "archive-arn": "{0}:{1}".format(
                                    archive.arn, archive.uuid
                                ),
                                "event": "<aws.events.event.json>",
                                "ingestion-time": "<aws.events.event.ingestion-time>",
                            }
                        ),
                    },
                }
            ],
        )

        self.archives[name] = archive

        return archive
Exemplo n.º 7
0
    def put_rule(self, name, **kwargs):
        if kwargs.get("ScheduleExpression") and kwargs.get("EventBusName") != "default":
            raise ValidationException(
                "ScheduleExpression is supported only on the default event bus."
            )

        if name in self.rules:
            self.update_rule(self.rules[name], **kwargs)
            new_rule = self.rules[name]
        else:
            new_rule = Rule(name, self.region_name, **kwargs)
            self.rules[new_rule.name] = new_rule
            self.rules_order.append(new_rule.name)
        return new_rule
Exemplo n.º 8
0
    def put_events(self, events):
        num_events = len(events)

        if num_events < 1:
            raise JsonRESTError("ValidationError", "Need at least 1 event")
        elif num_events > 10:
            # the exact error text is longer, the Value list consists of all the put events
            raise ValidationException(
                "1 validation error detected: "
                "Value '[PutEventsRequestEntry]' at 'entries' failed to satisfy constraint: "
                "Member must have length less than or equal to 10")

        entries = []
        for event in events:
            if "Source" not in event:
                entries.append({
                    "ErrorCode":
                    "InvalidArgument",
                    "ErrorMessage":
                    "Parameter Source is not valid. Reason: Source is a required argument.",
                })
            elif "DetailType" not in event:
                entries.append({
                    "ErrorCode":
                    "InvalidArgument",
                    "ErrorMessage":
                    "Parameter DetailType is not valid. Reason: DetailType is a required argument.",
                })
            elif "Detail" not in event:
                entries.append({
                    "ErrorCode":
                    "InvalidArgument",
                    "ErrorMessage":
                    "Parameter Detail is not valid. Reason: Detail is a required argument.",
                })
            else:
                try:
                    json.loads(event["Detail"])
                except ValueError:  # json.JSONDecodeError exists since Python 3.5
                    entries.append({
                        "ErrorCode": "MalformedDetail",
                        "ErrorMessage": "Detail is malformed.",
                    })
                    continue

                entries.append({"EventId": str(uuid4())})

        # We dont really need to store the events yet
        return entries
Exemplo n.º 9
0
    def put_targets(self, name, event_bus_name, targets):
        # super simple ARN check
        invalid_arn = next(
            (
                target["Arn"]
                for target in targets
                if not re.match(r"arn:[\d\w:\-/]*", target["Arn"])
            ),
            None,
        )
        if invalid_arn:
            raise ValidationException(
                "Parameter {} is not valid. "
                "Reason: Provided Arn is not in correct format.".format(invalid_arn)
            )

        rule = self.rules.get(name)

        if not rule:
            raise ResourceNotFoundException(
                "Rule {0} does not exist on EventBus {1}.".format(name, event_bus_name)
            )

        rule.put_targets(targets)
Exemplo n.º 10
0
    def put_events(self, events):
        num_events = len(events)

        if num_events > 10:
            # the exact error text is longer, the Value list consists of all the put events
            raise ValidationException(
                "1 validation error detected: "
                "Value '[PutEventsRequestEntry]' at 'entries' failed to satisfy constraint: "
                "Member must have length less than or equal to 10")

        entries = []
        for event in events:
            if "Source" not in event:
                entries.append({
                    "ErrorCode":
                    "InvalidArgument",
                    "ErrorMessage":
                    "Parameter Source is not valid. Reason: Source is a required argument.",
                })
            elif "DetailType" not in event:
                entries.append({
                    "ErrorCode":
                    "InvalidArgument",
                    "ErrorMessage":
                    "Parameter DetailType is not valid. Reason: DetailType is a required argument.",
                })
            elif "Detail" not in event:
                entries.append({
                    "ErrorCode":
                    "InvalidArgument",
                    "ErrorMessage":
                    "Parameter Detail is not valid. Reason: Detail is a required argument.",
                })
            else:
                try:
                    json.loads(event["Detail"])
                except ValueError:  # json.JSONDecodeError exists since Python 3.5
                    entries.append({
                        "ErrorCode": "MalformedDetail",
                        "ErrorMessage": "Detail is malformed.",
                    })
                    continue

                event_id = str(uuid4())
                entries.append({"EventId": event_id})

                # if 'EventBusName' is not especially set, it will be sent to the default one
                event_bus_name = event.get("EventBusName", "default")

                for rule in self.rules.values():
                    rule.send_to_targets(
                        event_bus_name,
                        {
                            "version": "0",
                            "id": event_id,
                            "detail-type": event["DetailType"],
                            "source": event["Source"],
                            "account": ACCOUNT_ID,
                            "time": event.get("Time",
                                              unix_time(datetime.utcnow())),
                            "region": self.region_name,
                            "resources": event.get("Resources", []),
                            "detail": json.loads(event["Detail"]),
                        },
                    )

        return entries
Exemplo n.º 11
0
    def put_events(self, events):
        num_events = len(events)

        if num_events < 1:
            raise JsonRESTError("ValidationError", "Need at least 1 event")
        elif num_events > 10:
            # the exact error text is longer, the Value list consists of all the put events
            raise ValidationException(
                "1 validation error detected: "
                "Value '[PutEventsRequestEntry]' at 'entries' failed to satisfy constraint: "
                "Member must have length less than or equal to 10")

        entries = []
        for event in events:
            if "Source" not in event:
                entries.append({
                    "ErrorCode":
                    "InvalidArgument",
                    "ErrorMessage":
                    "Parameter Source is not valid. Reason: Source is a required argument.",
                })
            elif "DetailType" not in event:
                entries.append({
                    "ErrorCode":
                    "InvalidArgument",
                    "ErrorMessage":
                    "Parameter DetailType is not valid. Reason: DetailType is a required argument.",
                })
            elif "Detail" not in event:
                entries.append({
                    "ErrorCode":
                    "InvalidArgument",
                    "ErrorMessage":
                    "Parameter Detail is not valid. Reason: Detail is a required argument.",
                })
            else:
                try:
                    json.loads(event["Detail"])
                except ValueError:  # json.JSONDecodeError exists since Python 3.5
                    entries.append({
                        "ErrorCode": "MalformedDetail",
                        "ErrorMessage": "Detail is malformed.",
                    })
                    continue

                entries.append({"EventId": str(uuid4())})

                # add to correct archive
                # if 'EventBusName' is not espically set, it will stored in the default
                event_bus_name = event.get("EventBusName", "default")
                archives = [
                    archive for archive in self.archives.values()
                    if archive.event_bus_name == event_bus_name
                ]

                for archive in archives:
                    event_copy = copy.deepcopy(event)
                    event_copy.pop("EventBusName", None)

                    if archive.matches_pattern(event):
                        archive.events.append(event_copy)

        # We dont really need to store the events yet
        return entries