SSM: add support for maintenance window tasks (#6430)
This commit is contained in:
parent
22774e8d08
commit
8ba1a61424
@ -6784,7 +6784,7 @@
|
||||
- [ ] deregister_managed_instance
|
||||
- [ ] deregister_patch_baseline_for_patch_group
|
||||
- [X] deregister_target_from_maintenance_window
|
||||
- [ ] deregister_task_from_maintenance_window
|
||||
- [X] deregister_task_from_maintenance_window
|
||||
- [ ] describe_activations
|
||||
- [ ] describe_association
|
||||
- [ ] describe_association_execution_targets
|
||||
@ -6807,7 +6807,7 @@
|
||||
- [ ] describe_maintenance_window_executions
|
||||
- [ ] describe_maintenance_window_schedule
|
||||
- [X] describe_maintenance_window_targets
|
||||
- [ ] describe_maintenance_window_tasks
|
||||
- [X] describe_maintenance_window_tasks
|
||||
- [X] describe_maintenance_windows
|
||||
- [ ] describe_maintenance_windows_for_target
|
||||
- [ ] describe_ops_items
|
||||
@ -6868,7 +6868,7 @@
|
||||
- [ ] register_default_patch_baseline
|
||||
- [ ] register_patch_baseline_for_patch_group
|
||||
- [X] register_target_with_maintenance_window
|
||||
- [ ] register_task_with_maintenance_window
|
||||
- [X] register_task_with_maintenance_window
|
||||
- [X] remove_tags_from_resource
|
||||
- [ ] reset_service_setting
|
||||
- [ ] resume_session
|
||||
|
@ -975,6 +975,65 @@ class FakeMaintenanceWindowTarget:
|
||||
return str(random.uuid4())
|
||||
|
||||
|
||||
class FakeMaintenanceWindowTask:
|
||||
def __init__(
|
||||
self,
|
||||
window_id: str,
|
||||
targets: Optional[List[Dict[str, Any]]],
|
||||
task_arn: str,
|
||||
service_role_arn: Optional[str],
|
||||
task_type: str,
|
||||
task_parameters: Optional[Dict[str, Any]],
|
||||
task_invocation_parameters: Optional[Dict[str, Any]],
|
||||
priority: Optional[int],
|
||||
max_concurrency: Optional[str],
|
||||
max_errors: Optional[str],
|
||||
logging_info: Optional[Dict[str, Any]],
|
||||
name: Optional[str],
|
||||
description: Optional[str],
|
||||
cutoff_behavior: Optional[str],
|
||||
alarm_configurations: Optional[Dict[str, Any]],
|
||||
):
|
||||
self.window_task_id = FakeMaintenanceWindowTask.generate_id()
|
||||
self.window_id = window_id
|
||||
self.task_type = task_type
|
||||
self.task_arn = task_arn
|
||||
self.service_role_arn = service_role_arn
|
||||
self.task_parameters = task_parameters
|
||||
self.priority = priority
|
||||
self.max_concurrency = max_concurrency
|
||||
self.max_errors = max_errors
|
||||
self.logging_info = logging_info
|
||||
self.name = name
|
||||
self.description = description
|
||||
self.targets = targets
|
||||
self.task_invocation_parameters = task_invocation_parameters
|
||||
self.cutoff_behavior = cutoff_behavior
|
||||
self.alarm_configurations = alarm_configurations
|
||||
|
||||
def to_json(self) -> Dict[str, Any]:
|
||||
return {
|
||||
"WindowId": self.window_id,
|
||||
"WindowTaskId": self.window_task_id,
|
||||
"TaskType": self.task_type,
|
||||
"TaskArn": self.task_arn,
|
||||
"ServiceRoleArn": self.service_role_arn,
|
||||
"TaskParameters": self.task_parameters,
|
||||
"Priority": self.priority,
|
||||
"MaxConcurrency": self.max_concurrency,
|
||||
"MaxErrors": self.max_errors,
|
||||
"LoggingInfo": self.logging_info,
|
||||
"Name": self.name,
|
||||
"Description": self.description,
|
||||
"Targets": self.targets,
|
||||
"TaskInvocationParameters": self.task_invocation_parameters,
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def generate_id() -> str:
|
||||
return str(random.uuid4())
|
||||
|
||||
|
||||
def _maintenance_window_target_filter_match(
|
||||
filters: Optional[List[Dict[str, Any]]], target: FakeMaintenanceWindowTarget
|
||||
) -> bool:
|
||||
@ -983,6 +1042,14 @@ def _maintenance_window_target_filter_match(
|
||||
return False
|
||||
|
||||
|
||||
def _maintenance_window_task_filter_match(
|
||||
filters: Optional[List[Dict[str, Any]]], task: FakeMaintenanceWindowTask
|
||||
) -> bool:
|
||||
if not filters and task:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
class FakeMaintenanceWindow:
|
||||
def __init__(
|
||||
self,
|
||||
@ -1007,6 +1074,7 @@ class FakeMaintenanceWindow:
|
||||
self.start_date = start_date
|
||||
self.end_date = end_date
|
||||
self.targets: Dict[str, FakeMaintenanceWindowTarget] = {}
|
||||
self.tasks: Dict[str, FakeMaintenanceWindowTask] = {}
|
||||
|
||||
def to_json(self) -> Dict[str, Any]:
|
||||
return {
|
||||
@ -2351,5 +2419,62 @@ class SimpleSystemManagerBackend(BaseBackend):
|
||||
]
|
||||
return targets
|
||||
|
||||
def register_task_with_maintenance_window(
|
||||
self,
|
||||
window_id: str,
|
||||
targets: Optional[List[Dict[str, Any]]],
|
||||
task_arn: str,
|
||||
service_role_arn: Optional[str],
|
||||
task_type: str,
|
||||
task_parameters: Optional[Dict[str, Any]],
|
||||
task_invocation_parameters: Optional[Dict[str, Any]],
|
||||
priority: Optional[int],
|
||||
max_concurrency: Optional[str],
|
||||
max_errors: Optional[str],
|
||||
logging_info: Optional[Dict[str, Any]],
|
||||
name: Optional[str],
|
||||
description: Optional[str],
|
||||
cutoff_behavior: Optional[str],
|
||||
alarm_configurations: Optional[Dict[str, Any]],
|
||||
) -> str:
|
||||
|
||||
window = self.get_maintenance_window(window_id)
|
||||
task = FakeMaintenanceWindowTask(
|
||||
window_id,
|
||||
targets,
|
||||
task_arn,
|
||||
service_role_arn,
|
||||
task_type,
|
||||
task_parameters,
|
||||
task_invocation_parameters,
|
||||
priority,
|
||||
max_concurrency,
|
||||
max_errors,
|
||||
logging_info,
|
||||
name,
|
||||
description,
|
||||
cutoff_behavior,
|
||||
alarm_configurations,
|
||||
)
|
||||
window.tasks[task.window_task_id] = task
|
||||
return task.window_task_id
|
||||
|
||||
def describe_maintenance_window_tasks(
|
||||
self, window_id: str, filters: List[Dict[str, Any]]
|
||||
) -> List[FakeMaintenanceWindowTask]:
|
||||
window = self.get_maintenance_window(window_id)
|
||||
tasks = [
|
||||
task
|
||||
for task in window.tasks.values()
|
||||
if _maintenance_window_task_filter_match(filters, task)
|
||||
]
|
||||
return tasks
|
||||
|
||||
def deregister_task_from_maintenance_window(
|
||||
self, window_id: str, window_task_id: str
|
||||
) -> None:
|
||||
window = self.get_maintenance_window(window_id)
|
||||
del window.tasks[window_task_id]
|
||||
|
||||
|
||||
ssm_backends = BackendDict(SimpleSystemManagerBackend, "ssm")
|
||||
|
@ -513,3 +513,42 @@ class SimpleSystemManagerResponse(BaseResponse):
|
||||
baseline_id = self._get_param("BaselineId")
|
||||
self.ssm_backend.delete_patch_baseline(baseline_id)
|
||||
return "{}"
|
||||
|
||||
def register_task_with_maintenance_window(self) -> str:
|
||||
window_task_id = self.ssm_backend.register_task_with_maintenance_window(
|
||||
window_id=self._get_param("WindowId"),
|
||||
targets=self._get_param("Targets"),
|
||||
task_arn=self._get_param("TaskArn"),
|
||||
service_role_arn=self._get_param("ServiceRoleArn"),
|
||||
task_type=self._get_param("TaskType"),
|
||||
task_parameters=self._get_param("TaskParameters"),
|
||||
task_invocation_parameters=self._get_param("TaskInvocationParameters"),
|
||||
priority=self._get_param("Priority"),
|
||||
max_concurrency=self._get_param("MaxConcurrency"),
|
||||
max_errors=self._get_param("MaxErrors"),
|
||||
logging_info=self._get_param("LoggingInfo"),
|
||||
name=self._get_param("Name"),
|
||||
description=self._get_param("Description"),
|
||||
cutoff_behavior=self._get_param("CutoffBehavior"),
|
||||
alarm_configurations=self._get_param("AlarmConfigurations"),
|
||||
)
|
||||
return json.dumps({"WindowTaskId": window_task_id})
|
||||
|
||||
def describe_maintenance_window_tasks(self) -> str:
|
||||
window_id = self._get_param("WindowId")
|
||||
filters = self._get_param("Filters", [])
|
||||
tasks = [
|
||||
task.to_json()
|
||||
for task in self.ssm_backend.describe_maintenance_window_tasks(
|
||||
window_id, filters
|
||||
)
|
||||
]
|
||||
return json.dumps({"Tasks": tasks})
|
||||
|
||||
def deregister_task_from_maintenance_window(self) -> str:
|
||||
window_id = self._get_param("WindowId")
|
||||
window_task_id = self._get_param("WindowTaskId")
|
||||
self.ssm_backend.deregister_task_from_maintenance_window(
|
||||
window_id, window_task_id
|
||||
)
|
||||
return "{}"
|
||||
|
@ -274,3 +274,111 @@ def test_deregister_target_from_maintenance_window():
|
||||
WindowId=window_id,
|
||||
)
|
||||
resp.should.have.key("Targets").should.have.length_of(0)
|
||||
|
||||
|
||||
@mock_ssm
|
||||
def test_describe_maintenance_window_with_no_task_or_targets():
|
||||
ssm = boto3.client("ssm", region_name="us-east-1")
|
||||
|
||||
resp = ssm.create_maintenance_window(
|
||||
Name="simple-window",
|
||||
Schedule="cron(15 12 * * ? *)",
|
||||
Duration=2,
|
||||
Cutoff=1,
|
||||
AllowUnassociatedTargets=False,
|
||||
)
|
||||
window_id = resp["WindowId"]
|
||||
|
||||
resp = ssm.describe_maintenance_window_tasks(
|
||||
WindowId=window_id,
|
||||
)
|
||||
resp.should.have.key("Tasks").should.have.length_of(0)
|
||||
|
||||
resp = ssm.describe_maintenance_window_targets(
|
||||
WindowId=window_id,
|
||||
)
|
||||
resp.should.have.key("Targets").should.have.length_of(0)
|
||||
|
||||
|
||||
@mock_ssm
|
||||
def test_register_maintenance_window_task():
|
||||
ssm = boto3.client("ssm", region_name="us-east-1")
|
||||
|
||||
resp = ssm.create_maintenance_window(
|
||||
Name="simple-window",
|
||||
Schedule="cron(15 12 * * ? *)",
|
||||
Duration=2,
|
||||
Cutoff=1,
|
||||
AllowUnassociatedTargets=False,
|
||||
)
|
||||
window_id = resp["WindowId"]
|
||||
|
||||
resp = ssm.register_target_with_maintenance_window(
|
||||
WindowId=window_id,
|
||||
ResourceType="INSTANCE",
|
||||
Targets=[{"Key": "tag:Name", "Values": ["my-instance"]}],
|
||||
)
|
||||
window_target_id = resp["WindowTargetId"]
|
||||
|
||||
resp = ssm.register_task_with_maintenance_window(
|
||||
WindowId=window_id,
|
||||
Targets=[{"Key": "WindowTargetIds", "Values": [window_target_id]}],
|
||||
TaskArn="AWS-RunShellScript",
|
||||
TaskType="RUN_COMMAND",
|
||||
MaxConcurrency="1",
|
||||
MaxErrors="1",
|
||||
)
|
||||
|
||||
resp.should.have.key("WindowTaskId")
|
||||
_id = resp["WindowTaskId"]
|
||||
|
||||
resp = ssm.describe_maintenance_window_tasks(
|
||||
WindowId=window_id,
|
||||
)
|
||||
resp.should.have.key("Tasks").should.have.length_of(1)
|
||||
resp["Tasks"][0].should.have.key("WindowTaskId").equal(_id)
|
||||
resp["Tasks"][0].should.have.key("WindowId").equal(window_id)
|
||||
resp["Tasks"][0].should.have.key("TaskArn").equal("AWS-RunShellScript")
|
||||
resp["Tasks"][0].should.have.key("MaxConcurrency").equal("1")
|
||||
resp["Tasks"][0].should.have.key("MaxErrors").equal("1")
|
||||
|
||||
|
||||
@mock_ssm
|
||||
def test_deregister_maintenance_window_task():
|
||||
ssm = boto3.client("ssm", region_name="us-east-1")
|
||||
|
||||
resp = ssm.create_maintenance_window(
|
||||
Name="simple-window",
|
||||
Schedule="cron(15 12 * * ? *)",
|
||||
Duration=2,
|
||||
Cutoff=1,
|
||||
AllowUnassociatedTargets=False,
|
||||
)
|
||||
window_id = resp["WindowId"]
|
||||
|
||||
resp = ssm.register_target_with_maintenance_window(
|
||||
WindowId=window_id,
|
||||
ResourceType="INSTANCE",
|
||||
Targets=[{"Key": "tag:Name", "Values": ["my-instance"]}],
|
||||
)
|
||||
window_target_id = resp["WindowTargetId"]
|
||||
|
||||
resp = ssm.register_task_with_maintenance_window(
|
||||
WindowId=window_id,
|
||||
Targets=[{"Key": "WindowTargetIds", "Values": [window_target_id]}],
|
||||
TaskArn="AWS-RunShellScript",
|
||||
TaskType="RUN_COMMAND",
|
||||
MaxConcurrency="1",
|
||||
MaxErrors="1",
|
||||
)
|
||||
window_task_id = resp["WindowTaskId"]
|
||||
|
||||
ssm.deregister_task_from_maintenance_window(
|
||||
WindowId=window_id,
|
||||
WindowTaskId=window_task_id,
|
||||
)
|
||||
|
||||
resp = ssm.describe_maintenance_window_tasks(
|
||||
WindowId=window_id,
|
||||
)
|
||||
resp.should.have.key("Tasks").should.have.length_of(0)
|
||||
|
Loading…
Reference in New Issue
Block a user