Merge pull request #2859 from gmcrocetti/fix-rules-cfn

CloudFormation support for events
This commit is contained in:
Bert Blommers 2020-04-02 07:46:43 +01:00 committed by GitHub
commit c87ab973c9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 88 additions and 33 deletions

View File

@ -431,7 +431,9 @@ class LogGroup(BaseModel):
properties = cloudformation_json["Properties"]
log_group_name = properties["LogGroupName"]
tags = properties.get("Tags", {})
return logs_backends[region_name].create_log_group(log_group_name, tags)
return logs_backends[region_name].create_log_group(
log_group_name, tags, **properties
)
cloudwatch_backends = {}

View File

@ -26,6 +26,10 @@ class Rule(BaseModel):
self.role_arn = kwargs.get("RoleArn")
self.targets = []
@property
def physical_resource_id(self):
return self.name
# This song and dance for targets is because we need order for Limits and NextTokens, but can't use OrderedDicts
# with Python 2.6, so tracking it with an array it is.
def _check_target_exists(self, target_id):
@ -59,6 +63,14 @@ class Rule(BaseModel):
if index is not None:
self.targets.pop(index)
def get_cfn_attribute(self, attribute_name):
from moto.cloudformation.exceptions import UnformattedGetAttTemplateException
if attribute_name == "Arn":
return self.arn
raise UnformattedGetAttTemplateException()
@classmethod
def create_from_cloudformation_json(
cls, resource_name, cloudformation_json, region_name

View File

@ -134,7 +134,7 @@ class LogStream:
return None, 0
events = sorted(
filter(filter_func, self.events), key=lambda event: event.timestamp,
filter(filter_func, self.events), key=lambda event: event.timestamp
)
direction, index = get_index_and_direction_from_token(next_token)
@ -169,11 +169,7 @@ class LogStream:
if end_index > final_index:
end_index = final_index
elif end_index < 0:
return (
[],
"b/{:056d}".format(0),
"f/{:056d}".format(0),
)
return ([], "b/{:056d}".format(0), "f/{:056d}".format(0))
events_page = [
event.to_response_dict() for event in events[start_index : end_index + 1]
@ -219,7 +215,7 @@ class LogStream:
class LogGroup:
def __init__(self, region, name, tags):
def __init__(self, region, name, tags, **kwargs):
self.name = name
self.region = region
self.arn = "arn:aws:logs:{region}:1:log-group:{log_group}".format(
@ -228,9 +224,9 @@ class LogGroup:
self.creationTime = int(unix_time_millis())
self.tags = tags
self.streams = dict() # {name: LogStream}
self.retentionInDays = (
None # AWS defaults to Never Expire for log group retention
)
self.retention_in_days = kwargs.get(
"RetentionInDays"
) # AWS defaults to Never Expire for log group retention
def create_log_stream(self, log_stream_name):
if log_stream_name in self.streams:
@ -368,12 +364,12 @@ class LogGroup:
"storedBytes": sum(s.storedBytes for s in self.streams.values()),
}
# AWS only returns retentionInDays if a value is set for the log group (ie. not Never Expire)
if self.retentionInDays:
log_group["retentionInDays"] = self.retentionInDays
if self.retention_in_days:
log_group["retentionInDays"] = self.retention_in_days
return log_group
def set_retention_policy(self, retention_in_days):
self.retentionInDays = retention_in_days
self.retention_in_days = retention_in_days
def list_tags(self):
return self.tags if self.tags else {}
@ -401,10 +397,12 @@ class LogsBackend(BaseBackend):
self.__dict__ = {}
self.__init__(region_name)
def create_log_group(self, log_group_name, tags):
def create_log_group(self, log_group_name, tags, **kwargs):
if log_group_name in self.groups:
raise ResourceAlreadyExistsException()
self.groups[log_group_name] = LogGroup(self.region_name, log_group_name, tags)
self.groups[log_group_name] = LogGroup(
self.region_name, log_group_name, tags, **kwargs
)
return self.groups[log_group_name]
def ensure_log_group(self, log_group_name, tags):

View File

@ -2373,13 +2373,12 @@ def test_create_log_group_using_fntransform():
}
cf_conn = boto3.client("cloudformation", "us-west-2")
cf_conn.create_stack(
StackName="test_stack", TemplateBody=json.dumps(template),
)
cf_conn.create_stack(StackName="test_stack", TemplateBody=json.dumps(template))
logs_conn = boto3.client("logs", region_name="us-west-2")
log_group = logs_conn.describe_log_groups()["logGroups"][0]
log_group["logGroupName"].should.equal("some-log-group")
log_group["retentionInDays"].should.be.equal(90)
@mock_cloudformation
@ -2400,7 +2399,7 @@ def test_stack_events_create_rule_integration():
}
cf_conn = boto3.client("cloudformation", "us-west-2")
cf_conn.create_stack(
StackName="test_stack", TemplateBody=json.dumps(events_template),
StackName="test_stack", TemplateBody=json.dumps(events_template)
)
rules = boto3.client("events", "us-west-2").list_rules()
@ -2428,7 +2427,7 @@ def test_stack_events_delete_rule_integration():
}
cf_conn = boto3.client("cloudformation", "us-west-2")
cf_conn.create_stack(
StackName="test_stack", TemplateBody=json.dumps(events_template),
StackName="test_stack", TemplateBody=json.dumps(events_template)
)
rules = boto3.client("events", "us-west-2").list_rules()
@ -2457,8 +2456,45 @@ def test_stack_events_create_rule_without_name_integration():
}
cf_conn = boto3.client("cloudformation", "us-west-2")
cf_conn.create_stack(
StackName="test_stack", TemplateBody=json.dumps(events_template),
StackName="test_stack", TemplateBody=json.dumps(events_template)
)
rules = boto3.client("events", "us-west-2").list_rules()
rules["Rules"][0]["Name"].should.contain("test_stack-Event-")
@mock_cloudformation
@mock_events
@mock_logs
def test_stack_events_create_rule_as_target():
events_template = {
"AWSTemplateFormatVersion": "2010-09-09",
"Resources": {
"SecurityGroup": {
"Type": "AWS::Logs::LogGroup",
"Properties": {
"LogGroupName": {"Fn::GetAtt": ["Event", "Arn"]},
"RetentionInDays": 3,
},
},
"Event": {
"Type": "AWS::Events::Rule",
"Properties": {
"State": "ENABLED",
"ScheduleExpression": "rate(5 minutes)",
},
},
},
}
cf_conn = boto3.client("cloudformation", "us-west-2")
cf_conn.create_stack(
StackName="test_stack", TemplateBody=json.dumps(events_template)
)
rules = boto3.client("events", "us-west-2").list_rules()
log_groups = boto3.client("logs", "us-west-2").describe_log_groups()
rules["Rules"][0]["Name"].should.contain("test_stack-Event-")
log_groups["logGroups"][0]["logGroupName"].should.equal(rules["Rules"][0]["Arn"])
log_groups["logGroups"][0]["retentionInDays"].should.equal(3)

View File

@ -79,13 +79,23 @@ def generate_environment():
@mock_events
def test_put_rule():
client = boto3.client("events", "us-west-2")
client.list_rules()["Rules"].should.have.length_of(0)
rule_data = get_random_rule()
rule_data = {
"Name": "my-event",
"ScheduleExpression": "rate(5 minutes)",
"EventPattern": '{"source": ["test-source"]}',
}
client.put_rule(**rule_data)
client.list_rules()["Rules"].should.have.length_of(1)
rules = client.list_rules()["Rules"]
rules.should.have.length_of(1)
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]["State"].should.equal("ENABLED")
@mock_events

View File

@ -12,17 +12,14 @@ _logs_region = "us-east-1" if settings.TEST_SERVER_MODE else "us-west-2"
@mock_logs
def test_log_group_create():
def test_create_log_group():
conn = boto3.client("logs", "us-west-2")
log_group_name = "dummy"
response = conn.create_log_group(logGroupName=log_group_name)
response = conn.describe_log_groups(logGroupNamePrefix=log_group_name)
assert len(response["logGroups"]) == 1
# AWS defaults to Never Expire for log group retention
assert response["logGroups"][0].get("retentionInDays") == None
response = conn.create_log_group(logGroupName="dummy")
response = conn.describe_log_groups()
response = conn.delete_log_group(logGroupName=log_group_name)
response["logGroups"].should.have.length_of(1)
response["logGroups"][0].should_not.have.key("retentionInDays")
@mock_logs