Completed events
This commit is contained in:
parent
6e28c58e26
commit
a6e5ffb99b
@ -917,13 +917,13 @@
|
||||
- [ ] unpeer_vpc
|
||||
- [ ] update_domain_entry
|
||||
|
||||
## xray - 0% implemented
|
||||
- [ ] batch_get_traces
|
||||
- [ ] get_service_graph
|
||||
- [ ] get_trace_graph
|
||||
- [ ] get_trace_summaries
|
||||
- [ ] put_telemetry_records
|
||||
- [ ] put_trace_segments
|
||||
## xray - 100% implemented
|
||||
- [X] batch_get_traces
|
||||
- [X] get_service_graph
|
||||
- [X] get_trace_graph
|
||||
- [X] get_trace_summaries
|
||||
- [X] put_telemetry_records
|
||||
- [X] put_trace_segments
|
||||
|
||||
## ec2 - 41% implemented
|
||||
- [ ] accept_reserved_instances_exchange_quote
|
||||
@ -1700,16 +1700,16 @@
|
||||
- [ ] stop_db_instance
|
||||
|
||||
## acm - 100% implemented
|
||||
- [x] add_tags_to_certificate
|
||||
- [x] delete_certificate
|
||||
- [x] describe_certificate
|
||||
- [x] get_certificate
|
||||
- [x] import_certificate
|
||||
- [x] list_certificates
|
||||
- [x] list_tags_for_certificate
|
||||
- [x] remove_tags_from_certificate
|
||||
- [x] request_certificate
|
||||
- [x] resend_validation_email
|
||||
- [X] add_tags_to_certificate
|
||||
- [X] delete_certificate
|
||||
- [X] describe_certificate
|
||||
- [X] get_certificate
|
||||
- [X] import_certificate
|
||||
- [X] list_certificates
|
||||
- [X] list_tags_for_certificate
|
||||
- [X] remove_tags_from_certificate
|
||||
- [X] request_certificate
|
||||
- [X] resend_validation_email
|
||||
|
||||
## elasticache - 0% implemented
|
||||
- [ ] add_tags_to_resource
|
||||
@ -3089,20 +3089,20 @@
|
||||
- [ ] start_configuration_recorder
|
||||
- [ ] stop_configuration_recorder
|
||||
|
||||
## events - 73% implemented
|
||||
## events - 100% implemented
|
||||
- [X] delete_rule
|
||||
- [ ] describe_event_bus
|
||||
- [X] describe_event_bus
|
||||
- [X] describe_rule
|
||||
- [X] disable_rule
|
||||
- [X] enable_rule
|
||||
- [X] list_rule_names_by_target
|
||||
- [X] list_rules
|
||||
- [X] list_targets_by_rule
|
||||
- [ ] put_events
|
||||
- [ ] put_permission
|
||||
- [X] put_events
|
||||
- [X] put_permission
|
||||
- [X] put_rule
|
||||
- [X] put_targets
|
||||
- [ ] remove_permission
|
||||
- [X] remove_permission
|
||||
- [X] remove_targets
|
||||
- [X] test_event_pattern
|
||||
|
||||
|
@ -68,6 +68,8 @@ It gets even better! Moto isn't just for Python code and it isn't just for S3. L
|
||||
|------------------------------------------------------------------------------|
|
||||
| Cloudwatch | @mock_cloudwatch | basic endpoints done |
|
||||
|------------------------------------------------------------------------------|
|
||||
| CloudwatchEvents | @mock_events | all endpoints done |
|
||||
|------------------------------------------------------------------------------|
|
||||
| Data Pipeline | @mock_datapipeline| basic endpoints done |
|
||||
|------------------------------------------------------------------------------|
|
||||
| DynamoDB | @mock_dynamodb | core endpoints done |
|
||||
@ -127,7 +129,7 @@ It gets even better! Moto isn't just for Python code and it isn't just for S3. L
|
||||
|------------------------------------------------------------------------------|
|
||||
| SWF | @mock_swf | basic endpoints done |
|
||||
|------------------------------------------------------------------------------|
|
||||
| X-Ray | @mock_xray | core endpoints done |
|
||||
| X-Ray | @mock_xray | all endpoints done |
|
||||
|------------------------------------------------------------------------------|
|
||||
```
|
||||
|
||||
|
@ -34,6 +34,8 @@ ERROR_JSON_RESPONSE = u"""{
|
||||
|
||||
|
||||
class RESTError(HTTPException):
|
||||
code = 400
|
||||
|
||||
templates = {
|
||||
'single_error': SINGLE_ERROR_RESPONSE,
|
||||
'error': ERROR_RESPONSE,
|
||||
@ -54,7 +56,6 @@ class DryRunClientError(RESTError):
|
||||
|
||||
|
||||
class JsonRESTError(RESTError):
|
||||
|
||||
def __init__(self, error_type, message, template='error_json', **kwargs):
|
||||
super(JsonRESTError, self).__init__(
|
||||
error_type, message, template, **kwargs)
|
||||
|
@ -1,6 +1,7 @@
|
||||
import os
|
||||
import re
|
||||
|
||||
from moto.core.exceptions import JsonRESTError
|
||||
from moto.core import BaseBackend, BaseModel
|
||||
|
||||
|
||||
@ -50,6 +51,8 @@ class Rule(BaseModel):
|
||||
|
||||
|
||||
class EventsBackend(BaseBackend):
|
||||
ACCOUNT_ID = re.compile(r'^(\d{1,12}|\*)$')
|
||||
STATEMENT_ID = re.compile(r'^[a-zA-Z0-9-_]{1,64}$')
|
||||
|
||||
def __init__(self):
|
||||
self.rules = {}
|
||||
@ -58,6 +61,8 @@ class EventsBackend(BaseBackend):
|
||||
self.rules_order = []
|
||||
self.next_tokens = {}
|
||||
|
||||
self.permissions = {}
|
||||
|
||||
def _get_rule_by_index(self, i):
|
||||
return self.rules.get(self.rules_order[i])
|
||||
|
||||
@ -181,6 +186,17 @@ class EventsBackend(BaseBackend):
|
||||
|
||||
return False
|
||||
|
||||
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:
|
||||
raise JsonRESTError('ValidationError', 'Can only submit 10 events at once')
|
||||
|
||||
# We dont really need to store the events yet
|
||||
return []
|
||||
|
||||
def remove_targets(self, name, ids):
|
||||
rule = self.rules.get(name)
|
||||
|
||||
@ -193,5 +209,40 @@ class EventsBackend(BaseBackend):
|
||||
def test_event_pattern(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
def put_permission(self, action, principal, statement_id):
|
||||
if action is None or action != 'PutEvents':
|
||||
raise JsonRESTError('InvalidParameterValue', 'Action must be PutEvents')
|
||||
|
||||
if principal is None or self.ACCOUNT_ID.match(principal) is None:
|
||||
raise JsonRESTError('InvalidParameterValue', 'Principal must match ^(\d{1,12}|\*)$')
|
||||
|
||||
if statement_id is None or self.STATEMENT_ID.match(statement_id) is None:
|
||||
raise JsonRESTError('InvalidParameterValue', 'StatementId must match ^[a-zA-Z0-9-_]{1,64}$')
|
||||
|
||||
self.permissions[statement_id] = {'action': action, 'principal': principal}
|
||||
|
||||
def remove_permission(self, statement_id):
|
||||
try:
|
||||
del self.permissions[statement_id]
|
||||
except KeyError:
|
||||
raise JsonRESTError('ResourceNotFoundException', 'StatementId not found')
|
||||
|
||||
def describe_event_bus(self):
|
||||
arn = "arn:aws:events:us-east-1:000000000000:event-bus/default"
|
||||
statements = []
|
||||
for statement_id, data in self.permissions.items():
|
||||
statements.append({
|
||||
'Sid': statement_id,
|
||||
'Effect': 'Allow',
|
||||
'Principal': {'AWS': 'arn:aws:iam::{0}:root'.format(data['principal'])},
|
||||
'Action': 'events:{0}'.format(data['action']),
|
||||
'Resource': arn
|
||||
})
|
||||
return {
|
||||
'Policy': {'Version': '2012-10-17', 'Statement': statements},
|
||||
'Name': 'default',
|
||||
'Arn': arn
|
||||
}
|
||||
|
||||
|
||||
events_backend = EventsBackend()
|
||||
|
@ -18,9 +18,17 @@ class EventsHandler(BaseResponse):
|
||||
'RoleArn': rule.role_arn
|
||||
}
|
||||
|
||||
def load_body(self):
|
||||
decoded_body = self.body
|
||||
return json.loads(decoded_body or '{}')
|
||||
@property
|
||||
def request_params(self):
|
||||
if not hasattr(self, '_json_body'):
|
||||
try:
|
||||
self._json_body = json.loads(self.body)
|
||||
except ValueError:
|
||||
self._json_body = {}
|
||||
return self._json_body
|
||||
|
||||
def _get_param(self, param, if_none=None):
|
||||
return self.request_params.get(param, if_none)
|
||||
|
||||
def error(self, type_, message='', status=400):
|
||||
headers = self.response_headers
|
||||
@ -28,8 +36,7 @@ class EventsHandler(BaseResponse):
|
||||
return json.dumps({'__type': type_, 'message': message}), headers,
|
||||
|
||||
def delete_rule(self):
|
||||
body = self.load_body()
|
||||
name = body.get('Name')
|
||||
name = self._get_param('Name')
|
||||
|
||||
if not name:
|
||||
return self.error('ValidationException', 'Parameter Name is required.')
|
||||
@ -38,8 +45,7 @@ class EventsHandler(BaseResponse):
|
||||
return '', self.response_headers
|
||||
|
||||
def describe_rule(self):
|
||||
body = self.load_body()
|
||||
name = body.get('Name')
|
||||
name = self._get_param('Name')
|
||||
|
||||
if not name:
|
||||
return self.error('ValidationException', 'Parameter Name is required.')
|
||||
@ -53,8 +59,7 @@ class EventsHandler(BaseResponse):
|
||||
return json.dumps(rule_dict), self.response_headers
|
||||
|
||||
def disable_rule(self):
|
||||
body = self.load_body()
|
||||
name = body.get('Name')
|
||||
name = self._get_param('Name')
|
||||
|
||||
if not name:
|
||||
return self.error('ValidationException', 'Parameter Name is required.')
|
||||
@ -65,8 +70,7 @@ class EventsHandler(BaseResponse):
|
||||
return '', self.response_headers
|
||||
|
||||
def enable_rule(self):
|
||||
body = self.load_body()
|
||||
name = body.get('Name')
|
||||
name = self._get_param('Name')
|
||||
|
||||
if not name:
|
||||
return self.error('ValidationException', 'Parameter Name is required.')
|
||||
@ -80,10 +84,9 @@ class EventsHandler(BaseResponse):
|
||||
pass
|
||||
|
||||
def list_rule_names_by_target(self):
|
||||
body = self.load_body()
|
||||
target_arn = body.get('TargetArn')
|
||||
next_token = body.get('NextToken')
|
||||
limit = body.get('Limit')
|
||||
target_arn = self._get_param('TargetArn')
|
||||
next_token = self._get_param('NextToken')
|
||||
limit = self._get_param('Limit')
|
||||
|
||||
if not target_arn:
|
||||
return self.error('ValidationException', 'Parameter TargetArn is required.')
|
||||
@ -94,10 +97,9 @@ class EventsHandler(BaseResponse):
|
||||
return json.dumps(rule_names), self.response_headers
|
||||
|
||||
def list_rules(self):
|
||||
body = self.load_body()
|
||||
prefix = body.get('NamePrefix')
|
||||
next_token = body.get('NextToken')
|
||||
limit = body.get('Limit')
|
||||
prefix = self._get_param('NamePrefix')
|
||||
next_token = self._get_param('NextToken')
|
||||
limit = self._get_param('Limit')
|
||||
|
||||
rules = events_backend.list_rules(prefix, next_token, limit)
|
||||
rules_obj = {'Rules': []}
|
||||
@ -111,10 +113,9 @@ class EventsHandler(BaseResponse):
|
||||
return json.dumps(rules_obj), self.response_headers
|
||||
|
||||
def list_targets_by_rule(self):
|
||||
body = self.load_body()
|
||||
rule_name = body.get('Rule')
|
||||
next_token = body.get('NextToken')
|
||||
limit = body.get('Limit')
|
||||
rule_name = self._get_param('Rule')
|
||||
next_token = self._get_param('NextToken')
|
||||
limit = self._get_param('Limit')
|
||||
|
||||
if not rule_name:
|
||||
return self.error('ValidationException', 'Parameter Rule is required.')
|
||||
@ -128,13 +129,25 @@ class EventsHandler(BaseResponse):
|
||||
return json.dumps(targets), self.response_headers
|
||||
|
||||
def put_events(self):
|
||||
events = self._get_param('Entries')
|
||||
|
||||
failed_entries = events_backend.put_events(events)
|
||||
|
||||
if failed_entries:
|
||||
return json.dumps({
|
||||
'FailedEntryCount': len(failed_entries),
|
||||
'Entries': failed_entries
|
||||
})
|
||||
|
||||
return '', self.response_headers
|
||||
|
||||
def put_rule(self):
|
||||
body = self.load_body()
|
||||
name = body.get('Name')
|
||||
event_pattern = body.get('EventPattern')
|
||||
sched_exp = body.get('ScheduleExpression')
|
||||
name = self._get_param('Name')
|
||||
event_pattern = self._get_param('EventPattern')
|
||||
sched_exp = self._get_param('ScheduleExpression')
|
||||
state = self._get_param('State')
|
||||
desc = self._get_param('Description')
|
||||
role_arn = self._get_param('RoleArn')
|
||||
|
||||
if not name:
|
||||
return self.error('ValidationException', 'Parameter Name is required.')
|
||||
@ -156,17 +169,16 @@ class EventsHandler(BaseResponse):
|
||||
name,
|
||||
ScheduleExpression=sched_exp,
|
||||
EventPattern=event_pattern,
|
||||
State=body.get('State'),
|
||||
Description=body.get('Description'),
|
||||
RoleArn=body.get('RoleArn')
|
||||
State=state,
|
||||
Description=desc,
|
||||
RoleArn=role_arn
|
||||
)
|
||||
|
||||
return json.dumps({'RuleArn': rule_arn}), self.response_headers
|
||||
|
||||
def put_targets(self):
|
||||
body = self.load_body()
|
||||
rule_name = body.get('Rule')
|
||||
targets = body.get('Targets')
|
||||
rule_name = self._get_param('Rule')
|
||||
targets = self._get_param('Targets')
|
||||
|
||||
if not rule_name:
|
||||
return self.error('ValidationException', 'Parameter Rule is required.')
|
||||
@ -180,9 +192,8 @@ class EventsHandler(BaseResponse):
|
||||
return '', self.response_headers
|
||||
|
||||
def remove_targets(self):
|
||||
body = self.load_body()
|
||||
rule_name = body.get('Rule')
|
||||
ids = body.get('Ids')
|
||||
rule_name = self._get_param('Rule')
|
||||
ids = self._get_param('Ids')
|
||||
|
||||
if not rule_name:
|
||||
return self.error('ValidationException', 'Parameter Rule is required.')
|
||||
@ -197,3 +208,22 @@ class EventsHandler(BaseResponse):
|
||||
|
||||
def test_event_pattern(self):
|
||||
pass
|
||||
|
||||
def put_permission(self):
|
||||
action = self._get_param('Action')
|
||||
principal = self._get_param('Principal')
|
||||
statement_id = self._get_param('StatementId')
|
||||
|
||||
events_backend.put_permission(action, principal, statement_id)
|
||||
|
||||
return ''
|
||||
|
||||
def remove_permission(self):
|
||||
statement_id = self._get_param('StatementId')
|
||||
|
||||
events_backend.remove_permission(statement_id)
|
||||
|
||||
return ''
|
||||
|
||||
def describe_event_bus(self):
|
||||
return json.dumps(events_backend.describe_event_bus())
|
||||
|
@ -3,6 +3,8 @@ import random
|
||||
import boto3
|
||||
|
||||
from moto.events import mock_events
|
||||
from botocore.exceptions import ClientError
|
||||
from nose.tools import assert_raises
|
||||
|
||||
|
||||
RULES = [
|
||||
@ -171,11 +173,36 @@ def test_remove_targets():
|
||||
assert(targets_before - 1 == targets_after)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_list_rules()
|
||||
test_describe_rule()
|
||||
test_enable_disable_rule()
|
||||
test_list_rule_names_by_target()
|
||||
test_list_rules()
|
||||
test_list_targets_by_rule()
|
||||
test_remove_targets()
|
||||
@mock_events
|
||||
def test_permissions():
|
||||
client = boto3.client('events', 'eu-central-1')
|
||||
|
||||
client.put_permission(Action='PutEvents', Principal='111111111111', StatementId='Account1')
|
||||
client.put_permission(Action='PutEvents', Principal='222222222222', StatementId='Account2')
|
||||
|
||||
resp = client.describe_event_bus()
|
||||
assert len(resp['Policy']['Statement']) == 2
|
||||
|
||||
client.remove_permission(StatementId='Account2')
|
||||
|
||||
resp = client.describe_event_bus()
|
||||
assert len(resp['Policy']['Statement']) == 1
|
||||
assert resp['Policy']['Statement'][0]['Sid'] == 'Account1'
|
||||
|
||||
|
||||
@mock_events
|
||||
def test_put_events():
|
||||
client = boto3.client('events', 'eu-central-1')
|
||||
|
||||
event = {
|
||||
"Source": "com.mycompany.myapp",
|
||||
"Detail": '{"key1": "value3", "key2": "value4"}',
|
||||
"Resources": ["resource1", "resource2"],
|
||||
"DetailType": "myDetailType"
|
||||
}
|
||||
|
||||
client.put_events(Entries=[event])
|
||||
# Boto3 would error if it didn't return 200 OK
|
||||
|
||||
with assert_raises(ClientError):
|
||||
client.put_events(Entries=[event]*20)
|
||||
|
Loading…
Reference in New Issue
Block a user