Fix events rule ARN for custom event bus (#3809)

* Fix events rule ARN for custom event bus

* Fix cloudformation test
This commit is contained in:
Anton Grübel 2021-03-28 20:41:24 +02:00 committed by GitHub
parent 57aa83e6c1
commit 9a020e6120
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 119 additions and 21 deletions

View File

@ -27,23 +27,34 @@ from uuid import uuid4
class Rule(CloudFormationModel):
Arn = namedtuple("Arn", ["service", "resource_type", "resource_id"])
def _generate_arn(self, name):
return "arn:aws:events:{region_name}:{account}:rule/{name}".format(
region_name=self.region_name, account=ACCOUNT_ID, name=name
)
def __init__(self, name, region_name, **kwargs):
self.name = name
self.region_name = region_name
self.arn = kwargs.get("Arn") or self._generate_arn(name)
self.event_pattern = kwargs.get("EventPattern")
self.schedule_exp = kwargs.get("ScheduleExpression")
self.state = kwargs.get("State") or "ENABLED"
self.description = kwargs.get("Description")
self.role_arn = kwargs.get("RoleArn")
self.event_bus_name = kwargs.get("EventBusName") or "default"
self.managed_by = kwargs.get("ManagedBy") # can only be set by AWS services
self.event_bus_name = kwargs.get("EventBusName")
self.created_by = ACCOUNT_ID
self.targets = []
@property
def arn(self):
event_bus_name = (
""
if self.event_bus_name == "default"
else "{}/".format(self.event_bus_name)
)
return "arn:aws:events:{region}:{account_id}:rule/{event_bus_name}{name}".format(
region=self.region_name,
account_id=ACCOUNT_ID,
event_bus_name=event_bus_name,
name=self.name,
)
@property
def physical_resource_id(self):
return self.name
@ -196,6 +207,8 @@ class Rule(CloudFormationModel):
cls, resource_name, cloudformation_json, region_name
):
properties = cloudformation_json["Properties"]
properties.setdefault("EventBusName", "default")
event_backend = events_backends[region_name]
event_name = resource_name
return event_backend.put_rule(name=event_name, **properties)
@ -682,6 +695,11 @@ class EventsBackend(BaseBackend):
rule.event_bus_name = kwargs.get("EventBusName") or rule.event_bus_name
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]
@ -932,6 +950,7 @@ class EventsBackend(BaseBackend):
**{
"EventPattern": json.dumps(rule_event_pattern),
"EventBusName": event_bus.name,
"ManagedBy": "prod.vhs.events.aws.internal",
}
)
self.put_targets(

View File

@ -25,7 +25,9 @@ class EventsHandler(BaseResponse):
"Description": rule.description,
"ScheduleExpression": rule.schedule_exp,
"RoleArn": rule.role_arn,
"ManagedBy": rule.managed_by,
"EventBusName": rule.event_bus_name,
"CreatedBy": rule.created_by,
}
@property
@ -168,10 +170,7 @@ class EventsHandler(BaseResponse):
state = self._get_param("State")
desc = self._get_param("Description")
role_arn = self._get_param("RoleArn")
event_bus_name = self._get_param("EventBusName")
if not name:
return self.error("ValidationException", "Parameter Name is required.")
event_bus_name = self._get_param("EventBusName", "default")
if event_pattern:
try:

View File

@ -88,7 +88,6 @@ def test_put_rule():
"Name": "my-event",
"ScheduleExpression": "rate(5 minutes)",
"EventPattern": '{"source": ["test-source"]}',
"EventBusName": "test-bus",
}
client.put_rule(**rule_data)
@ -99,10 +98,34 @@ def test_put_rule():
rules[0]["Name"].should.equal(rule_data["Name"])
rules[0]["ScheduleExpression"].should.equal(rule_data["ScheduleExpression"])
rules[0]["EventPattern"].should.equal(rule_data["EventPattern"])
rules[0]["EventBusName"].should.equal(rule_data["EventBusName"])
rules[0]["State"].should.equal("ENABLED")
@mock_events
def test_put_rule_error_schedule_expression_custom_event_bus():
# given
client = boto3.client("events", "eu-central-1")
event_bus_name = "test-bus"
client.create_event_bus(Name=event_bus_name)
# when
with pytest.raises(ClientError) as e:
client.put_rule(
Name="test-rule",
ScheduleExpression="rate(5 minutes)",
EventBusName=event_bus_name,
)
# then
ex = e.value
ex.operation_name.should.equal("PutRule")
ex.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400)
ex.response["Error"]["Code"].should.contain("ValidationException")
ex.response["Error"]["Message"].should.equal(
"ScheduleExpression is supported only on the default event bus."
)
@mock_events
def test_list_rules():
client = generate_environment()
@ -118,15 +141,51 @@ def test_describe_rule():
client = generate_environment()
response = client.describe_rule(Name=rule_name)
assert response is not None
assert response.get("Name") == rule_name
rule_arn = response.get("Arn")
assert rule_arn == "arn:aws:events:us-west-2:{account}:rule/{name}".format(
account=ACCOUNT_ID, name=rule_name
response["Name"].should.equal(rule_name)
response["Arn"].should.equal(
"arn:aws:events:us-west-2:{0}:rule/{1}".format(ACCOUNT_ID, rule_name)
)
@mock_events
def test_describe_rule_with_event_bus_name():
# given
client = boto3.client("events", "eu-central-1")
event_bus_name = "test-bus"
rule_name = "test-rule"
client.create_event_bus(Name=event_bus_name)
client.put_rule(
Name=rule_name,
EventPattern=json.dumps({"account": [ACCOUNT_ID]}),
State="DISABLED",
Description="test rule",
RoleArn="arn:aws:iam::{}:role/test-role".format(ACCOUNT_ID),
EventBusName=event_bus_name,
)
# when
response = client.describe_rule(Name=rule_name, EventBusName=event_bus_name)
# then
response["Arn"].should.equal(
"arn:aws:events:eu-central-1:{0}:rule/{1}/{2}".format(
ACCOUNT_ID, event_bus_name, rule_name
)
)
response["CreatedBy"].should.equal(ACCOUNT_ID)
response["Description"].should.equal("test rule")
response["EventBusName"].should.equal(event_bus_name)
json.loads(response["EventPattern"]).should.equal({"account": [ACCOUNT_ID]})
response["Name"].should.equal(rule_name)
response["RoleArn"].should.equal(
"arn:aws:iam::{}:role/test-role".format(ACCOUNT_ID)
)
response["State"].should.equal("DISABLED")
response.should_not.have.key("ManagedBy")
response.should_not.have.key("ScheduleExpression")
@mock_events
def test_enable_disable_rule():
rule_name = get_random_rule()["Name"]
@ -791,10 +850,11 @@ def test_list_tags_for_resource_error_unknown_arn():
def test_create_archive():
# given
client = boto3.client("events", "eu-central-1")
archive_name = "test-archive"
# when
response = client.create_archive(
ArchiveName="test-archive",
ArchiveName=archive_name,
EventSourceArn="arn:aws:events:eu-central-1:{}:event-bus/default".format(
ACCOUNT_ID
),
@ -802,11 +862,31 @@ def test_create_archive():
# then
response["ArchiveArn"].should.equal(
"arn:aws:events:eu-central-1:{}:archive/test-archive".format(ACCOUNT_ID)
"arn:aws:events:eu-central-1:{0}:archive/{1}".format(ACCOUNT_ID, archive_name)
)
response["CreationTime"].should.be.a(datetime)
response["State"].should.equal("ENABLED")
# check for archive rule existence
rule_name = "Events-Archive-{}".format(archive_name)
response = client.describe_rule(Name=rule_name)
response["Arn"].should.equal(
"arn:aws:events:eu-central-1:{0}:rule/{1}".format(ACCOUNT_ID, rule_name)
)
response["CreatedBy"].should.equal(ACCOUNT_ID)
response["EventBusName"].should.equal("default")
json.loads(response["EventPattern"]).should.equal(
{"replay-name": [{"exists": False}]}
)
response["ManagedBy"].should.equal("prod.vhs.events.aws.internal")
response["Name"].should.equal(rule_name)
response["State"].should.equal("ENABLED")
response.should_not.have.key("Description")
response.should_not.have.key("RoleArn")
response.should_not.have.key("ScheduleExpression")
@mock_events
def test_create_archive_custom_event_bus():