SSM: add support for maintenance window targets (#6429)
This commit is contained in:
parent
883d01dd76
commit
9a247d5943
@ -6744,7 +6744,7 @@
|
|||||||
- [ ] delete_resource_policy
|
- [ ] delete_resource_policy
|
||||||
- [ ] deregister_managed_instance
|
- [ ] deregister_managed_instance
|
||||||
- [ ] deregister_patch_baseline_for_patch_group
|
- [ ] deregister_patch_baseline_for_patch_group
|
||||||
- [ ] deregister_target_from_maintenance_window
|
- [X] deregister_target_from_maintenance_window
|
||||||
- [ ] deregister_task_from_maintenance_window
|
- [ ] deregister_task_from_maintenance_window
|
||||||
- [ ] describe_activations
|
- [ ] describe_activations
|
||||||
- [ ] describe_association
|
- [ ] describe_association
|
||||||
@ -6767,7 +6767,7 @@
|
|||||||
- [ ] describe_maintenance_window_execution_tasks
|
- [ ] describe_maintenance_window_execution_tasks
|
||||||
- [ ] describe_maintenance_window_executions
|
- [ ] describe_maintenance_window_executions
|
||||||
- [ ] describe_maintenance_window_schedule
|
- [ ] describe_maintenance_window_schedule
|
||||||
- [ ] describe_maintenance_window_targets
|
- [X] describe_maintenance_window_targets
|
||||||
- [ ] describe_maintenance_window_tasks
|
- [ ] describe_maintenance_window_tasks
|
||||||
- [X] describe_maintenance_windows
|
- [X] describe_maintenance_windows
|
||||||
- [ ] describe_maintenance_windows_for_target
|
- [ ] describe_maintenance_windows_for_target
|
||||||
@ -6828,7 +6828,7 @@
|
|||||||
- [ ] put_resource_policy
|
- [ ] put_resource_policy
|
||||||
- [ ] register_default_patch_baseline
|
- [ ] register_default_patch_baseline
|
||||||
- [ ] register_patch_baseline_for_patch_group
|
- [ ] register_patch_baseline_for_patch_group
|
||||||
- [ ] register_target_with_maintenance_window
|
- [X] register_target_with_maintenance_window
|
||||||
- [ ] register_task_with_maintenance_window
|
- [ ] register_task_with_maintenance_window
|
||||||
- [X] remove_tags_from_resource
|
- [X] remove_tags_from_resource
|
||||||
- [ ] reset_service_setting
|
- [ ] reset_service_setting
|
||||||
|
@ -941,6 +941,48 @@ def _valid_parameter_data_type(data_type: str) -> bool:
|
|||||||
return data_type in ("text", "aws:ec2:image")
|
return data_type in ("text", "aws:ec2:image")
|
||||||
|
|
||||||
|
|
||||||
|
class FakeMaintenanceWindowTarget:
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
window_id: str,
|
||||||
|
resource_type: str,
|
||||||
|
targets: List[Dict[str, Any]],
|
||||||
|
owner_information: Optional[str],
|
||||||
|
name: Optional[str],
|
||||||
|
description: Optional[str],
|
||||||
|
):
|
||||||
|
self.window_id = window_id
|
||||||
|
self.window_target_id = self.generate_id()
|
||||||
|
self.resource_type = resource_type
|
||||||
|
self.targets = targets
|
||||||
|
self.name = name
|
||||||
|
self.description = description
|
||||||
|
self.owner_information = owner_information
|
||||||
|
|
||||||
|
def to_json(self) -> Dict[str, Any]:
|
||||||
|
return {
|
||||||
|
"WindowId": self.window_id,
|
||||||
|
"WindowTargetId": self.window_target_id,
|
||||||
|
"ResourceType": self.resource_type,
|
||||||
|
"Targets": self.targets,
|
||||||
|
"OwnerInformation": "",
|
||||||
|
"Name": self.name,
|
||||||
|
"Description": self.description,
|
||||||
|
}
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def generate_id() -> str:
|
||||||
|
return str(random.uuid4())
|
||||||
|
|
||||||
|
|
||||||
|
def _maintenance_window_target_filter_match(
|
||||||
|
filters: Optional[List[Dict[str, Any]]], target: FakeMaintenanceWindowTarget
|
||||||
|
) -> bool:
|
||||||
|
if not filters and target:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
class FakeMaintenanceWindow:
|
class FakeMaintenanceWindow:
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
@ -964,6 +1006,7 @@ class FakeMaintenanceWindow:
|
|||||||
self.schedule_offset = schedule_offset
|
self.schedule_offset = schedule_offset
|
||||||
self.start_date = start_date
|
self.start_date = start_date
|
||||||
self.end_date = end_date
|
self.end_date = end_date
|
||||||
|
self.targets: Dict[str, FakeMaintenanceWindowTarget] = {}
|
||||||
|
|
||||||
def to_json(self) -> Dict[str, Any]:
|
def to_json(self) -> Dict[str, Any]:
|
||||||
return {
|
return {
|
||||||
@ -2254,5 +2297,53 @@ class SimpleSystemManagerBackend(BaseBackend):
|
|||||||
"""
|
"""
|
||||||
del self.baselines[baseline_id]
|
del self.baselines[baseline_id]
|
||||||
|
|
||||||
|
def register_target_with_maintenance_window(
|
||||||
|
self,
|
||||||
|
window_id: str,
|
||||||
|
resource_type: str,
|
||||||
|
targets: List[Dict[str, Any]],
|
||||||
|
owner_information: Optional[str],
|
||||||
|
name: Optional[str],
|
||||||
|
description: Optional[str],
|
||||||
|
) -> str:
|
||||||
|
"""
|
||||||
|
Registers a target with a maintenance window. No error handling has been implemented yet.
|
||||||
|
"""
|
||||||
|
window = self.get_maintenance_window(window_id)
|
||||||
|
|
||||||
|
target = FakeMaintenanceWindowTarget(
|
||||||
|
window_id,
|
||||||
|
resource_type,
|
||||||
|
targets,
|
||||||
|
owner_information=owner_information,
|
||||||
|
name=name,
|
||||||
|
description=description,
|
||||||
|
)
|
||||||
|
window.targets[target.window_target_id] = target
|
||||||
|
return target.window_target_id
|
||||||
|
|
||||||
|
def deregister_target_from_maintenance_window(
|
||||||
|
self, window_id: str, window_target_id: str
|
||||||
|
) -> None:
|
||||||
|
"""
|
||||||
|
Deregisters a target from a maintenance window. No error handling has been implemented yet.
|
||||||
|
"""
|
||||||
|
window = self.get_maintenance_window(window_id)
|
||||||
|
del window.targets[window_target_id]
|
||||||
|
|
||||||
|
def describe_maintenance_window_targets(
|
||||||
|
self, window_id: str, filters: Optional[List[Dict[str, Any]]]
|
||||||
|
) -> List[FakeMaintenanceWindowTarget]:
|
||||||
|
"""
|
||||||
|
Describes all targets for a maintenance window. No error handling has been implemented yet.
|
||||||
|
"""
|
||||||
|
window = self.get_maintenance_window(window_id)
|
||||||
|
targets = [
|
||||||
|
target
|
||||||
|
for target in window.targets.values()
|
||||||
|
if _maintenance_window_target_filter_match(filters, target)
|
||||||
|
]
|
||||||
|
return targets
|
||||||
|
|
||||||
|
|
||||||
ssm_backends = BackendDict(SimpleSystemManagerBackend, "ssm")
|
ssm_backends = BackendDict(SimpleSystemManagerBackend, "ssm")
|
||||||
|
@ -437,6 +437,36 @@ class SimpleSystemManagerResponse(BaseResponse):
|
|||||||
window = self.ssm_backend.get_maintenance_window(window_id)
|
window = self.ssm_backend.get_maintenance_window(window_id)
|
||||||
return json.dumps(window.to_json())
|
return json.dumps(window.to_json())
|
||||||
|
|
||||||
|
def register_target_with_maintenance_window(self) -> str:
|
||||||
|
window_target_id = self.ssm_backend.register_target_with_maintenance_window(
|
||||||
|
window_id=self._get_param("WindowId"),
|
||||||
|
resource_type=self._get_param("ResourceType"),
|
||||||
|
targets=self._get_param("Targets"),
|
||||||
|
owner_information=self._get_param("OwnerInformation"),
|
||||||
|
name=self._get_param("Name"),
|
||||||
|
description=self._get_param("Description"),
|
||||||
|
)
|
||||||
|
return json.dumps({"WindowTargetId": window_target_id})
|
||||||
|
|
||||||
|
def describe_maintenance_window_targets(self) -> str:
|
||||||
|
window_id = self._get_param("WindowId")
|
||||||
|
filters = self._get_param("Filters", [])
|
||||||
|
targets = [
|
||||||
|
target.to_json()
|
||||||
|
for target in self.ssm_backend.describe_maintenance_window_targets(
|
||||||
|
window_id, filters
|
||||||
|
)
|
||||||
|
]
|
||||||
|
return json.dumps({"Targets": targets})
|
||||||
|
|
||||||
|
def deregister_target_from_maintenance_window(self) -> str:
|
||||||
|
window_id = self._get_param("WindowId")
|
||||||
|
window_target_id = self._get_param("WindowTargetId")
|
||||||
|
self.ssm_backend.deregister_target_from_maintenance_window(
|
||||||
|
window_id, window_target_id
|
||||||
|
)
|
||||||
|
return "{}"
|
||||||
|
|
||||||
def describe_maintenance_windows(self) -> str:
|
def describe_maintenance_windows(self) -> str:
|
||||||
filters = self._get_param("Filters", None)
|
filters = self._get_param("Filters", None)
|
||||||
windows = [
|
windows = [
|
||||||
|
@ -212,3 +212,65 @@ def test_tags():
|
|||||||
ResourceType="MaintenanceWindow", ResourceId=mw_id
|
ResourceType="MaintenanceWindow", ResourceId=mw_id
|
||||||
)["TagList"]
|
)["TagList"]
|
||||||
assert tags == [{"Key": "k2", "Value": "v2"}]
|
assert tags == [{"Key": "k2", "Value": "v2"}]
|
||||||
|
|
||||||
|
|
||||||
|
@mock_ssm
|
||||||
|
def test_register_maintenance_window_target():
|
||||||
|
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"]}],
|
||||||
|
)
|
||||||
|
resp.should.have.key("WindowTargetId")
|
||||||
|
_id = resp["WindowTargetId"]
|
||||||
|
|
||||||
|
resp = ssm.describe_maintenance_window_targets(
|
||||||
|
WindowId=window_id,
|
||||||
|
)
|
||||||
|
resp.should.have.key("Targets").should.have.length_of(1)
|
||||||
|
resp["Targets"][0].should.have.key("ResourceType").equal("INSTANCE")
|
||||||
|
resp["Targets"][0].should.have.key("WindowTargetId").equal(_id)
|
||||||
|
resp["Targets"][0]["Targets"][0].should.have.key("Key").equal("tag:Name")
|
||||||
|
resp["Targets"][0]["Targets"][0].should.have.key("Values").equal(["my-instance"])
|
||||||
|
|
||||||
|
|
||||||
|
@mock_ssm
|
||||||
|
def test_deregister_target_from_maintenance_window():
|
||||||
|
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"]}],
|
||||||
|
)
|
||||||
|
_id = resp["WindowTargetId"]
|
||||||
|
|
||||||
|
ssm.deregister_target_from_maintenance_window(
|
||||||
|
WindowId=window_id,
|
||||||
|
WindowTargetId=_id,
|
||||||
|
)
|
||||||
|
|
||||||
|
resp = ssm.describe_maintenance_window_targets(
|
||||||
|
WindowId=window_id,
|
||||||
|
)
|
||||||
|
resp.should.have.key("Targets").should.have.length_of(0)
|
||||||
|
Loading…
Reference in New Issue
Block a user