-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
16 changed files
with
783 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
.. _implementedservice_scheduler: | ||
|
||
.. |start-h3| raw:: html | ||
|
||
<h3> | ||
|
||
.. |end-h3| raw:: html | ||
|
||
</h3> | ||
|
||
========= | ||
scheduler | ||
========= | ||
|
||
.. autoclass:: moto.scheduler.models.EventBridgeSchedulerBackend | ||
|
||
|start-h3| Example usage |end-h3| | ||
|
||
.. sourcecode:: python | ||
|
||
@mock_scheduler | ||
def test_scheduler_behaviour: | ||
boto3.client("scheduler") | ||
... | ||
|
||
|
||
|
||
|start-h3| Implemented features for this service |end-h3| | ||
|
||
- [X] create_schedule | ||
|
||
The ClientToken parameter is not yet implemented | ||
|
||
|
||
- [X] create_schedule_group | ||
|
||
The ClientToken parameter is not yet implemented | ||
|
||
|
||
- [X] delete_schedule | ||
- [X] delete_schedule_group | ||
- [X] get_schedule | ||
- [X] get_schedule_group | ||
- [X] list_schedule_groups | ||
|
||
The MaxResults-parameter and pagination options are not yet implemented | ||
|
||
|
||
- [ ] list_schedules | ||
- [X] list_tags_for_resource | ||
- [X] tag_resource | ||
- [X] untag_resource | ||
- [X] update_schedule | ||
|
||
The ClientToken is not yet implemented | ||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
"""scheduler module initialization; sets value for base decorator.""" | ||
from .models import scheduler_backends | ||
from ..core.models import base_decorator | ||
|
||
mock_scheduler = base_decorator(scheduler_backends) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
"""Exceptions raised by the scheduler service.""" | ||
from moto.core.exceptions import JsonRESTError | ||
|
||
|
||
class ScheduleNotFound(JsonRESTError): | ||
def __init__(self) -> None: | ||
super().__init__("ResourceNotFoundException", "Schedule not found") | ||
|
||
|
||
class ScheduleGroupNotFound(JsonRESTError): | ||
def __init__(self) -> None: | ||
super().__init__("ResourceNotFoundException", "ScheduleGroup not found") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,240 @@ | ||
"""EventBridgeSchedulerBackend class with methods for supported APIs.""" | ||
from typing import Any, Dict, List, Iterable, Optional | ||
|
||
from moto.core import BaseBackend, BackendDict, BaseModel | ||
from moto.core.utils import unix_time | ||
from moto.utilities.tagging_service import TaggingService | ||
|
||
from .exceptions import ScheduleNotFound, ScheduleGroupNotFound | ||
|
||
|
||
class Schedule(BaseModel): | ||
def __init__( | ||
self, | ||
region: str, | ||
account_id: str, | ||
group_name: str, | ||
name: str, | ||
description: Optional[str], | ||
schedule_expression: str, | ||
schedule_expression_timezone: Optional[str], | ||
flexible_time_window: Dict[str, Any], | ||
target: Dict[str, Any], | ||
state: Optional[str], | ||
kms_key_arn: Optional[str], | ||
start_date: Optional[str], | ||
end_date: Optional[str], | ||
): | ||
self.name = name | ||
self.group_name = group_name | ||
self.description = description | ||
self.arn = ( | ||
f"arn:aws:scheduler:{region}:{account_id}:schedule/{group_name}/{name}" | ||
) | ||
self.schedule_expression = schedule_expression | ||
self.schedule_expression_timezone = schedule_expression_timezone | ||
self.flexible_time_window = flexible_time_window | ||
self.target = Schedule.validate_target(target) | ||
self.state = state or "ENABLED" | ||
self.kms_key_arn = kms_key_arn | ||
self.start_date = start_date | ||
self.end_date = end_date | ||
|
||
@staticmethod | ||
def validate_target(target: Dict[str, Any]) -> Dict[str, Any]: # type: ignore[misc] | ||
if "RetryPolicy" not in target: | ||
target["RetryPolicy"] = { | ||
"MaximumEventAgeInSeconds": 86400, | ||
"MaximumRetryAttempts": 185, | ||
} | ||
return target | ||
|
||
def to_dict(self, short: bool = False) -> Dict[str, Any]: | ||
dct: Dict[str, Any] = { | ||
"Arn": self.arn, | ||
"Name": self.name, | ||
"GroupName": self.group_name, | ||
"Description": self.description, | ||
"ScheduleExpression": self.schedule_expression, | ||
"ScheduleExpressionTimezone": self.schedule_expression_timezone, | ||
"FlexibleTimeWindow": self.flexible_time_window, | ||
"Target": self.target, | ||
"State": self.state, | ||
"KmsKeyArn": self.kms_key_arn, | ||
"StartDate": self.start_date, | ||
"EndDate": self.end_date, | ||
} | ||
if short: | ||
dct["Target"] = {"Arn": dct["Target"]["Arn"]} | ||
return dct | ||
|
||
|
||
class ScheduleGroup(BaseModel): | ||
def __init__(self, region: str, account_id: str, name: str): | ||
self.name = name | ||
self.arn = f"arn:aws:scheduler:{region}:{account_id}:schedule-group/{name}" | ||
self.schedules: Dict[str, Schedule] = dict() | ||
self.created_on = None if self.name == "default" else unix_time() | ||
self.last_modified = None if self.name == "default" else unix_time() | ||
|
||
def add_schedule(self, schedule: Schedule) -> None: | ||
self.schedules[schedule.name] = schedule | ||
|
||
def get_schedule(self, name: str) -> Schedule: | ||
if name not in self.schedules: | ||
raise ScheduleNotFound | ||
return self.schedules[name] | ||
|
||
def delete_schedule(self, name: str) -> None: | ||
self.schedules.pop(name) | ||
|
||
def to_dict(self) -> Dict[str, Any]: | ||
return { | ||
"Arn": self.arn, | ||
"CreationDate": self.created_on, | ||
"LastModificationDate": self.last_modified, | ||
"Name": self.name, | ||
"State": "ACTIVE", | ||
} | ||
|
||
|
||
class EventBridgeSchedulerBackend(BaseBackend): | ||
"""Implementation of EventBridgeScheduler APIs.""" | ||
|
||
def __init__(self, region_name: str, account_id: str): | ||
super().__init__(region_name, account_id) | ||
self.schedules: List[Schedule] = list() | ||
self.schedule_groups = { | ||
"default": ScheduleGroup( | ||
region=region_name, account_id=account_id, name="default" | ||
) | ||
} | ||
self.tagger = TaggingService() | ||
|
||
def create_schedule( | ||
self, | ||
description: str, | ||
end_date: str, | ||
flexible_time_window: Dict[str, Any], | ||
group_name: str, | ||
kms_key_arn: str, | ||
name: str, | ||
schedule_expression: str, | ||
schedule_expression_timezone: str, | ||
start_date: str, | ||
state: str, | ||
target: Dict[str, Any], | ||
) -> Schedule: | ||
""" | ||
The ClientToken parameter is not yet implemented | ||
""" | ||
group = self.schedule_groups[group_name or "default"] | ||
schedule = Schedule( | ||
region=self.region_name, | ||
account_id=self.account_id, | ||
group_name=group.name, | ||
name=name, | ||
description=description, | ||
schedule_expression=schedule_expression, | ||
schedule_expression_timezone=schedule_expression_timezone, | ||
flexible_time_window=flexible_time_window, | ||
target=target, | ||
state=state, | ||
kms_key_arn=kms_key_arn, | ||
start_date=start_date, | ||
end_date=end_date, | ||
) | ||
group.add_schedule(schedule) | ||
return schedule | ||
|
||
def get_schedule(self, group_name: Optional[str], name: str) -> Schedule: | ||
group = self.get_schedule_group(group_name) | ||
return group.get_schedule(name) | ||
|
||
def delete_schedule(self, group_name: Optional[str], name: str) -> None: | ||
group = self.get_schedule_group(group_name) | ||
group.delete_schedule(name) | ||
|
||
def update_schedule( | ||
self, | ||
description: str, | ||
end_date: str, | ||
flexible_time_window: Dict[str, Any], | ||
group_name: str, | ||
kms_key_arn: str, | ||
name: str, | ||
schedule_expression: str, | ||
schedule_expression_timezone: str, | ||
start_date: str, | ||
state: str, | ||
target: Dict[str, Any], | ||
) -> Schedule: | ||
""" | ||
The ClientToken is not yet implemented | ||
""" | ||
schedule = self.get_schedule(group_name=group_name, name=name) | ||
schedule.schedule_expression = schedule_expression | ||
schedule.schedule_expression_timezone = schedule_expression_timezone | ||
schedule.flexible_time_window = flexible_time_window | ||
schedule.target = Schedule.validate_target(target) | ||
schedule.description = description | ||
schedule.state = state | ||
schedule.kms_key_arn = kms_key_arn | ||
schedule.start_date = start_date | ||
schedule.end_date = end_date | ||
return schedule | ||
|
||
def list_schedules( | ||
self, group_names: Optional[str], state: Optional[str] | ||
) -> Iterable[Schedule]: | ||
""" | ||
The following parameters are not yet implemented: MaxResults, NamePrefix, NextToken | ||
""" | ||
results = [] | ||
for group in self.schedule_groups.values(): | ||
if not group_names or group.name in group_names: | ||
for schedule in group.schedules.values(): | ||
if not state or schedule.state == state: | ||
results.append(schedule) | ||
return results | ||
|
||
def create_schedule_group( | ||
self, name: str, tags: List[Dict[str, str]] | ||
) -> ScheduleGroup: | ||
""" | ||
The ClientToken parameter is not yet implemented | ||
""" | ||
group = ScheduleGroup( | ||
region=self.region_name, account_id=self.account_id, name=name | ||
) | ||
self.schedule_groups[name] = group | ||
self.tagger.tag_resource(group.arn, tags) | ||
return group | ||
|
||
def get_schedule_group(self, group_name: Optional[str]) -> ScheduleGroup: | ||
if (group_name or "default") not in self.schedule_groups: | ||
raise ScheduleGroupNotFound | ||
return self.schedule_groups[group_name or "default"] | ||
|
||
def list_schedule_groups(self) -> Iterable[ScheduleGroup]: | ||
""" | ||
The MaxResults-parameter and pagination options are not yet implemented | ||
""" | ||
return self.schedule_groups.values() | ||
|
||
def delete_schedule_group(self, name: Optional[str]) -> None: | ||
self.schedule_groups.pop(name or "default") | ||
|
||
def list_tags_for_resource( | ||
self, resource_arn: str | ||
) -> Dict[str, List[Dict[str, str]]]: | ||
return self.tagger.list_tags_for_resource(resource_arn) | ||
|
||
def tag_resource(self, resource_arn: str, tags: List[Dict[str, str]]) -> None: | ||
self.tagger.tag_resource(resource_arn, tags) | ||
|
||
def untag_resource(self, resource_arn: str, tag_keys: List[str]) -> None: | ||
self.tagger.untag_resource_using_names(resource_arn, tag_keys) | ||
|
||
|
||
scheduler_backends = BackendDict(EventBridgeSchedulerBackend, "scheduler") |
Oops, something went wrong.