Cloudformation: Various attributes (#5732)
This commit is contained in:
parent
aeb507f091
commit
d10a8e9900
@ -565,7 +565,7 @@
|
|||||||
|
|
||||||
## cloudformation
|
## cloudformation
|
||||||
<details>
|
<details>
|
||||||
<summary>34% implemented</summary>
|
<summary>50% implemented</summary>
|
||||||
|
|
||||||
- [ ] activate_type
|
- [ ] activate_type
|
||||||
- [ ] batch_describe_type_configurations
|
- [ ] batch_describe_type_configurations
|
||||||
@ -586,13 +586,13 @@
|
|||||||
- [ ] describe_change_set_hooks
|
- [ ] describe_change_set_hooks
|
||||||
- [ ] describe_publisher
|
- [ ] describe_publisher
|
||||||
- [ ] describe_stack_drift_detection_status
|
- [ ] describe_stack_drift_detection_status
|
||||||
- [ ] describe_stack_events
|
- [X] describe_stack_events
|
||||||
- [X] describe_stack_instance
|
- [X] describe_stack_instance
|
||||||
- [ ] describe_stack_resource
|
- [X] describe_stack_resource
|
||||||
- [ ] describe_stack_resource_drifts
|
- [ ] describe_stack_resource_drifts
|
||||||
- [ ] describe_stack_resources
|
- [X] describe_stack_resources
|
||||||
- [ ] describe_stack_set
|
- [X] describe_stack_set
|
||||||
- [ ] describe_stack_set_operation
|
- [X] describe_stack_set_operation
|
||||||
- [X] describe_stacks
|
- [X] describe_stacks
|
||||||
- [ ] describe_type
|
- [ ] describe_type
|
||||||
- [ ] describe_type_registration
|
- [ ] describe_type_registration
|
||||||
@ -602,7 +602,7 @@
|
|||||||
- [ ] estimate_template_cost
|
- [ ] estimate_template_cost
|
||||||
- [X] execute_change_set
|
- [X] execute_change_set
|
||||||
- [X] get_stack_policy
|
- [X] get_stack_policy
|
||||||
- [ ] get_template
|
- [X] get_template
|
||||||
- [ ] get_template_summary
|
- [ ] get_template_summary
|
||||||
- [ ] import_stacks_to_stack_set
|
- [ ] import_stacks_to_stack_set
|
||||||
- [X] list_change_sets
|
- [X] list_change_sets
|
||||||
@ -610,9 +610,9 @@
|
|||||||
- [ ] list_imports
|
- [ ] list_imports
|
||||||
- [X] list_stack_instances
|
- [X] list_stack_instances
|
||||||
- [X] list_stack_resources
|
- [X] list_stack_resources
|
||||||
- [ ] list_stack_set_operation_results
|
- [X] list_stack_set_operation_results
|
||||||
- [ ] list_stack_set_operations
|
- [X] list_stack_set_operations
|
||||||
- [ ] list_stack_sets
|
- [X] list_stack_sets
|
||||||
- [X] list_stacks
|
- [X] list_stacks
|
||||||
- [ ] list_type_registrations
|
- [ ] list_type_registrations
|
||||||
- [ ] list_type_versions
|
- [ ] list_type_versions
|
||||||
@ -626,7 +626,7 @@
|
|||||||
- [ ] set_type_configuration
|
- [ ] set_type_configuration
|
||||||
- [ ] set_type_default_version
|
- [ ] set_type_default_version
|
||||||
- [ ] signal_resource
|
- [ ] signal_resource
|
||||||
- [ ] stop_stack_set_operation
|
- [X] stop_stack_set_operation
|
||||||
- [ ] test_type
|
- [ ] test_type
|
||||||
- [X] update_stack
|
- [X] update_stack
|
||||||
- [X] update_stack_instances
|
- [X] update_stack_instances
|
||||||
|
@ -62,13 +62,13 @@ cloudformation
|
|||||||
- [ ] describe_change_set_hooks
|
- [ ] describe_change_set_hooks
|
||||||
- [ ] describe_publisher
|
- [ ] describe_publisher
|
||||||
- [ ] describe_stack_drift_detection_status
|
- [ ] describe_stack_drift_detection_status
|
||||||
- [ ] describe_stack_events
|
- [X] describe_stack_events
|
||||||
- [X] describe_stack_instance
|
- [X] describe_stack_instance
|
||||||
- [ ] describe_stack_resource
|
- [X] describe_stack_resource
|
||||||
- [ ] describe_stack_resource_drifts
|
- [ ] describe_stack_resource_drifts
|
||||||
- [ ] describe_stack_resources
|
- [X] describe_stack_resources
|
||||||
- [ ] describe_stack_set
|
- [X] describe_stack_set
|
||||||
- [ ] describe_stack_set_operation
|
- [X] describe_stack_set_operation
|
||||||
- [X] describe_stacks
|
- [X] describe_stacks
|
||||||
- [ ] describe_type
|
- [ ] describe_type
|
||||||
- [ ] describe_type_registration
|
- [ ] describe_type_registration
|
||||||
@ -78,7 +78,7 @@ cloudformation
|
|||||||
- [ ] estimate_template_cost
|
- [ ] estimate_template_cost
|
||||||
- [X] execute_change_set
|
- [X] execute_change_set
|
||||||
- [X] get_stack_policy
|
- [X] get_stack_policy
|
||||||
- [ ] get_template
|
- [X] get_template
|
||||||
- [ ] get_template_summary
|
- [ ] get_template_summary
|
||||||
- [ ] import_stacks_to_stack_set
|
- [ ] import_stacks_to_stack_set
|
||||||
- [X] list_change_sets
|
- [X] list_change_sets
|
||||||
@ -91,9 +91,9 @@ cloudformation
|
|||||||
|
|
||||||
|
|
||||||
- [X] list_stack_resources
|
- [X] list_stack_resources
|
||||||
- [ ] list_stack_set_operation_results
|
- [X] list_stack_set_operation_results
|
||||||
- [ ] list_stack_set_operations
|
- [X] list_stack_set_operations
|
||||||
- [ ] list_stack_sets
|
- [X] list_stack_sets
|
||||||
- [X] list_stacks
|
- [X] list_stacks
|
||||||
- [ ] list_type_registrations
|
- [ ] list_type_registrations
|
||||||
- [ ] list_type_versions
|
- [ ] list_type_versions
|
||||||
@ -111,7 +111,7 @@ cloudformation
|
|||||||
- [ ] set_type_configuration
|
- [ ] set_type_configuration
|
||||||
- [ ] set_type_default_version
|
- [ ] set_type_default_version
|
||||||
- [ ] signal_resource
|
- [ ] signal_resource
|
||||||
- [ ] stop_stack_set_operation
|
- [X] stop_stack_set_operation
|
||||||
- [ ] test_type
|
- [ ] test_type
|
||||||
- [X] update_stack
|
- [X] update_stack
|
||||||
- [X] update_stack_instances
|
- [X] update_stack_instances
|
||||||
|
@ -48,6 +48,16 @@ class StackSetNotEmpty(RESTError):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class StackSetNotFoundException(RESTError):
|
||||||
|
def __init__(self, name: str):
|
||||||
|
template = Template(ERROR_RESPONSE)
|
||||||
|
message = f"StackSet {name} not found"
|
||||||
|
super().__init__(error_type="StackSetNotFoundException", message=message)
|
||||||
|
self.description = template.render(
|
||||||
|
code="StackSetNotFoundException", message=message
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class UnsupportedAttribute(ValidationError):
|
class UnsupportedAttribute(ValidationError):
|
||||||
def __init__(self, resource: str, attr: str):
|
def __init__(self, resource: str, attr: str):
|
||||||
template = Template(ERROR_RESPONSE)
|
template = Template(ERROR_RESPONSE)
|
||||||
|
@ -26,7 +26,7 @@ from .utils import (
|
|||||||
yaml_tag_constructor,
|
yaml_tag_constructor,
|
||||||
validate_template_cfn_lint,
|
validate_template_cfn_lint,
|
||||||
)
|
)
|
||||||
from .exceptions import ValidationError, StackSetNotEmpty
|
from .exceptions import ValidationError, StackSetNotEmpty, StackSetNotFoundException
|
||||||
|
|
||||||
|
|
||||||
class FakeStackSet(BaseModel):
|
class FakeStackSet(BaseModel):
|
||||||
@ -40,9 +40,9 @@ class FakeStackSet(BaseModel):
|
|||||||
description: Optional[str],
|
description: Optional[str],
|
||||||
parameters: Dict[str, str],
|
parameters: Dict[str, str],
|
||||||
permission_model: str,
|
permission_model: str,
|
||||||
tags: Optional[Dict[str, str]] = None,
|
tags: Optional[Dict[str, str]],
|
||||||
admin_role: str = "AWSCloudFormationStackSetAdministrationRole",
|
admin_role: Optional[str],
|
||||||
execution_role: str = "AWSCloudFormationStackSetExecutionRole",
|
execution_role: Optional[str],
|
||||||
):
|
):
|
||||||
self.id = stackset_id
|
self.id = stackset_id
|
||||||
self.arn = generate_stackset_arn(stackset_id, region, account_id)
|
self.arn = generate_stackset_arn(stackset_id, region, account_id)
|
||||||
@ -53,7 +53,7 @@ class FakeStackSet(BaseModel):
|
|||||||
self.tags = tags
|
self.tags = tags
|
||||||
self.admin_role = admin_role
|
self.admin_role = admin_role
|
||||||
self.admin_role_arn = f"arn:aws:iam::{account_id}:role/{self.admin_role}"
|
self.admin_role_arn = f"arn:aws:iam::{account_id}:role/{self.admin_role}"
|
||||||
self.execution_role = execution_role
|
self.execution_role = execution_role or "AWSCloudFormationStackSetExecutionRole"
|
||||||
self.status = "ACTIVE"
|
self.status = "ACTIVE"
|
||||||
self.instances = FakeStackInstances(
|
self.instances = FakeStackInstances(
|
||||||
account_id, template, parameters, self.id, self.name
|
account_id, template, parameters, self.id, self.name
|
||||||
@ -76,8 +76,10 @@ class FakeStackSet(BaseModel):
|
|||||||
"OperationId": operation_id,
|
"OperationId": operation_id,
|
||||||
"Action": action,
|
"Action": action,
|
||||||
"Status": status,
|
"Status": status,
|
||||||
"CreationTimestamp": datetime.now(),
|
"CreationTimestamp": datetime.now().strftime("%Y-%m-%dT%H:%M:%S.%f"),
|
||||||
"EndTimestamp": datetime.now() + timedelta(minutes=2),
|
"EndTimestamp": (datetime.now() + timedelta(minutes=2)).strftime(
|
||||||
|
"%Y-%m-%dT%H:%M:%S.%f"
|
||||||
|
),
|
||||||
"Instances": [
|
"Instances": [
|
||||||
{account: region} for account in accounts for region in regions
|
{account: region} for account in accounts for region in regions
|
||||||
],
|
],
|
||||||
@ -368,6 +370,8 @@ class FakeStack(BaseModel):
|
|||||||
role_arn: Optional[str] = None,
|
role_arn: Optional[str] = None,
|
||||||
cross_stack_resources: Optional[Dict[str, Export]] = None,
|
cross_stack_resources: Optional[Dict[str, Export]] = None,
|
||||||
enable_termination_protection: Optional[bool] = False,
|
enable_termination_protection: Optional[bool] = False,
|
||||||
|
timeout_in_mins: Optional[int] = None,
|
||||||
|
stack_policy_body: Optional[str] = None,
|
||||||
):
|
):
|
||||||
self.stack_id = stack_id
|
self.stack_id = stack_id
|
||||||
self.name = name
|
self.name = name
|
||||||
@ -385,7 +389,8 @@ class FakeStack(BaseModel):
|
|||||||
self.role_arn = role_arn
|
self.role_arn = role_arn
|
||||||
self.tags = tags if tags else {}
|
self.tags = tags if tags else {}
|
||||||
self.events: List[FakeEvent] = []
|
self.events: List[FakeEvent] = []
|
||||||
self.policy = ""
|
self.timeout_in_mins = timeout_in_mins
|
||||||
|
self.policy = stack_policy_body or ""
|
||||||
|
|
||||||
self.cross_stack_resources: Dict[str, Export] = cross_stack_resources or {}
|
self.cross_stack_resources: Dict[str, Export] = cross_stack_resources or {}
|
||||||
self.enable_termination_protection: bool = (
|
self.enable_termination_protection: bool = (
|
||||||
@ -716,6 +721,9 @@ class CloudFormationBackend(BaseBackend):
|
|||||||
parameters: Dict[str, str],
|
parameters: Dict[str, str],
|
||||||
tags: Dict[str, str],
|
tags: Dict[str, str],
|
||||||
permission_model: str,
|
permission_model: str,
|
||||||
|
admin_role: Optional[str],
|
||||||
|
exec_role: Optional[str],
|
||||||
|
description: Optional[str],
|
||||||
) -> FakeStackSet:
|
) -> FakeStackSet:
|
||||||
"""
|
"""
|
||||||
The following parameters are not yet implemented: StackId, AdministrationRoleARN, AutoDeployment, ExecutionRoleName, CallAs, ClientRequestToken, ManagedExecution
|
The following parameters are not yet implemented: StackId, AdministrationRoleARN, AutoDeployment, ExecutionRoleName, CallAs, ClientRequestToken, ManagedExecution
|
||||||
@ -728,21 +736,26 @@ class CloudFormationBackend(BaseBackend):
|
|||||||
region=self.region_name,
|
region=self.region_name,
|
||||||
template=template,
|
template=template,
|
||||||
parameters=parameters,
|
parameters=parameters,
|
||||||
description=None,
|
description=description,
|
||||||
tags=tags,
|
tags=tags,
|
||||||
permission_model=permission_model,
|
permission_model=permission_model,
|
||||||
|
admin_role=admin_role,
|
||||||
|
execution_role=exec_role,
|
||||||
)
|
)
|
||||||
self.stacksets[stackset_id] = new_stackset
|
self.stacksets[stackset_id] = new_stackset
|
||||||
return new_stackset
|
return new_stackset
|
||||||
|
|
||||||
def get_stack_set(self, name: str) -> FakeStackSet:
|
def describe_stack_set(self, name: str) -> FakeStackSet:
|
||||||
stacksets = self.stacksets.keys()
|
stacksets = self.stacksets.keys()
|
||||||
if name in stacksets:
|
if name in stacksets and self.stacksets[name].status != "DELETED":
|
||||||
return self.stacksets[name]
|
return self.stacksets[name]
|
||||||
for stackset in stacksets:
|
for stackset in stacksets:
|
||||||
if self.stacksets[stackset].name == name:
|
if (
|
||||||
|
self.stacksets[stackset].name == name
|
||||||
|
and self.stacksets[stackset].status != "DELETED"
|
||||||
|
):
|
||||||
return self.stacksets[stackset]
|
return self.stacksets[stackset]
|
||||||
raise ValidationError(name)
|
raise StackSetNotFoundException(name)
|
||||||
|
|
||||||
def delete_stack_set(self, name: str) -> None:
|
def delete_stack_set(self, name: str) -> None:
|
||||||
stackset_to_delete: Optional[FakeStackSet] = None
|
stackset_to_delete: Optional[FakeStackSet] = None
|
||||||
@ -755,8 +768,33 @@ class CloudFormationBackend(BaseBackend):
|
|||||||
if stackset_to_delete is not None:
|
if stackset_to_delete is not None:
|
||||||
if stackset_to_delete.stack_instances:
|
if stackset_to_delete.stack_instances:
|
||||||
raise StackSetNotEmpty()
|
raise StackSetNotEmpty()
|
||||||
|
# We don't remove StackSets from the list - they still show up when calling list_stack_sets
|
||||||
stackset_to_delete.delete()
|
stackset_to_delete.delete()
|
||||||
|
|
||||||
|
def list_stack_sets(self) -> Iterable[FakeStackSet]:
|
||||||
|
return self.stacksets.values()
|
||||||
|
|
||||||
|
def list_stack_set_operations(self, stackset_name: str) -> List[Dict[str, Any]]:
|
||||||
|
stackset = self.describe_stack_set(stackset_name)
|
||||||
|
return stackset.operations
|
||||||
|
|
||||||
|
def stop_stack_set_operation(self, stackset_name: str, operation_id: str) -> None:
|
||||||
|
stackset = self.describe_stack_set(stackset_name)
|
||||||
|
stackset.update_operation(operation_id, "STOPPED")
|
||||||
|
|
||||||
|
def describe_stack_set_operation(
|
||||||
|
self, stackset_name: str, operation_id: str
|
||||||
|
) -> Tuple[FakeStackSet, Dict[str, Any]]:
|
||||||
|
stackset = self.describe_stack_set(stackset_name)
|
||||||
|
operation = stackset.get_operation(operation_id)
|
||||||
|
return stackset, operation
|
||||||
|
|
||||||
|
def list_stack_set_operation_results(
|
||||||
|
self, stackset_name: str, operation_id: str
|
||||||
|
) -> Dict[str, Any]:
|
||||||
|
stackset = self.describe_stack_set(stackset_name)
|
||||||
|
return stackset.get_operation(operation_id)
|
||||||
|
|
||||||
def create_stack_instances(
|
def create_stack_instances(
|
||||||
self,
|
self,
|
||||||
stackset_name: str,
|
stackset_name: str,
|
||||||
@ -768,7 +806,7 @@ class CloudFormationBackend(BaseBackend):
|
|||||||
"""
|
"""
|
||||||
The following parameters are not yet implemented: DeploymentTargets.AccountFilterType, DeploymentTargets.AccountsUrl, OperationPreferences, CallAs
|
The following parameters are not yet implemented: DeploymentTargets.AccountFilterType, DeploymentTargets.AccountsUrl, OperationPreferences, CallAs
|
||||||
"""
|
"""
|
||||||
stackset = self.get_stack_set(stackset_name)
|
stackset = self.describe_stack_set(stackset_name)
|
||||||
|
|
||||||
operation_id = stackset.create_stack_instances(
|
operation_id = stackset.create_stack_instances(
|
||||||
accounts=accounts,
|
accounts=accounts,
|
||||||
@ -788,7 +826,7 @@ class CloudFormationBackend(BaseBackend):
|
|||||||
"""
|
"""
|
||||||
Calling this will update the parameters, but the actual resources are not updated
|
Calling this will update the parameters, but the actual resources are not updated
|
||||||
"""
|
"""
|
||||||
stack_set = self.get_stack_set(stackset_name)
|
stack_set = self.describe_stack_set(stackset_name)
|
||||||
return stack_set.update_instances(accounts, regions, parameters)
|
return stack_set.update_instances(accounts, regions, parameters)
|
||||||
|
|
||||||
def update_stack_set(
|
def update_stack_set(
|
||||||
@ -804,7 +842,7 @@ class CloudFormationBackend(BaseBackend):
|
|||||||
regions: List[str],
|
regions: List[str],
|
||||||
operation_id: str,
|
operation_id: str,
|
||||||
) -> Dict[str, Any]:
|
) -> Dict[str, Any]:
|
||||||
stackset = self.get_stack_set(stackset_name)
|
stackset = self.describe_stack_set(stackset_name)
|
||||||
resolved_parameters = self._resolve_update_parameters(
|
resolved_parameters = self._resolve_update_parameters(
|
||||||
instance=stackset, incoming_params=parameters
|
instance=stackset, incoming_params=parameters
|
||||||
)
|
)
|
||||||
@ -827,7 +865,7 @@ class CloudFormationBackend(BaseBackend):
|
|||||||
"""
|
"""
|
||||||
The following parameters are not yet implemented: DeploymentTargets, OperationPreferences, RetainStacks, OperationId, CallAs
|
The following parameters are not yet implemented: DeploymentTargets, OperationPreferences, RetainStacks, OperationId, CallAs
|
||||||
"""
|
"""
|
||||||
stackset = self.get_stack_set(stackset_name)
|
stackset = self.describe_stack_set(stackset_name)
|
||||||
stackset.delete_stack_instances(accounts, regions)
|
stackset.delete_stack_instances(accounts, regions)
|
||||||
return stackset
|
return stackset
|
||||||
|
|
||||||
@ -840,6 +878,8 @@ class CloudFormationBackend(BaseBackend):
|
|||||||
tags: Optional[Dict[str, str]] = None,
|
tags: Optional[Dict[str, str]] = None,
|
||||||
role_arn: Optional[str] = None,
|
role_arn: Optional[str] = None,
|
||||||
enable_termination_protection: Optional[bool] = False,
|
enable_termination_protection: Optional[bool] = False,
|
||||||
|
timeout_in_mins: Optional[int] = None,
|
||||||
|
stack_policy_body: Optional[str] = None,
|
||||||
) -> FakeStack:
|
) -> FakeStack:
|
||||||
"""
|
"""
|
||||||
The functionality behind EnableTerminationProtection is not yet implemented.
|
The functionality behind EnableTerminationProtection is not yet implemented.
|
||||||
@ -857,6 +897,8 @@ class CloudFormationBackend(BaseBackend):
|
|||||||
role_arn=role_arn,
|
role_arn=role_arn,
|
||||||
cross_stack_resources=self.exports,
|
cross_stack_resources=self.exports,
|
||||||
enable_termination_protection=enable_termination_protection,
|
enable_termination_protection=enable_termination_protection,
|
||||||
|
timeout_in_mins=timeout_in_mins,
|
||||||
|
stack_policy_body=stack_policy_body,
|
||||||
)
|
)
|
||||||
self.stacks[stack_id] = new_stack
|
self.stacks[stack_id] = new_stack
|
||||||
self._validate_export_uniqueness(new_stack)
|
self._validate_export_uniqueness(new_stack)
|
||||||
@ -1012,7 +1054,7 @@ class CloudFormationBackend(BaseBackend):
|
|||||||
def describe_stack_instance(
|
def describe_stack_instance(
|
||||||
self, stack_set_name: str, account_id: str, region: str
|
self, stack_set_name: str, account_id: str, region: str
|
||||||
) -> Dict[str, Any]:
|
) -> Dict[str, Any]:
|
||||||
stack_set = self.get_stack_set(stack_set_name)
|
stack_set = self.describe_stack_set(stack_set_name)
|
||||||
return stack_set.instances.get_instance(account_id, region).to_dict()
|
return stack_set.instances.get_instance(account_id, region).to_dict()
|
||||||
|
|
||||||
def list_stack_instances(self, stackset_name: str) -> List[Dict[str, Any]]:
|
def list_stack_instances(self, stackset_name: str) -> List[Dict[str, Any]]:
|
||||||
@ -1020,7 +1062,7 @@ class CloudFormationBackend(BaseBackend):
|
|||||||
Pagination is not yet implemented.
|
Pagination is not yet implemented.
|
||||||
The parameters StackInstanceAccount/StackInstanceRegion are not yet implemented.
|
The parameters StackInstanceAccount/StackInstanceRegion are not yet implemented.
|
||||||
"""
|
"""
|
||||||
stack_set = self.get_stack_set(stackset_name)
|
stack_set = self.describe_stack_set(stackset_name)
|
||||||
return [i.to_dict() for i in stack_set.instances.stack_instances]
|
return [i.to_dict() for i in stack_set.instances.stack_instances]
|
||||||
|
|
||||||
def list_change_sets(self) -> Iterable[FakeChangeSet]:
|
def list_change_sets(self) -> Iterable[FakeChangeSet]:
|
||||||
@ -1076,6 +1118,26 @@ class CloudFormationBackend(BaseBackend):
|
|||||||
raise ValidationError(message=f"Stack: {stack_name} does not exist")
|
raise ValidationError(message=f"Stack: {stack_name} does not exist")
|
||||||
stack.policy = policy_body
|
stack.policy = policy_body
|
||||||
|
|
||||||
|
def describe_stack_resource(
|
||||||
|
self, stack_name: str, logical_resource_id: str
|
||||||
|
) -> Tuple[FakeStack, Type[CloudFormationModel]]:
|
||||||
|
stack = self.get_stack(stack_name)
|
||||||
|
|
||||||
|
for stack_resource in stack.stack_resources:
|
||||||
|
if stack_resource.logical_resource_id == logical_resource_id: # type: ignore[attr-defined]
|
||||||
|
return stack, stack_resource
|
||||||
|
|
||||||
|
message = (
|
||||||
|
f"Resource {logical_resource_id} does not exist for stack {stack_name}"
|
||||||
|
)
|
||||||
|
raise ValidationError(stack_name, message)
|
||||||
|
|
||||||
|
def describe_stack_resources(
|
||||||
|
self, stack_name: str
|
||||||
|
) -> Tuple[FakeStack, Iterable[Type[CloudFormationModel]]]:
|
||||||
|
stack = self.get_stack(stack_name)
|
||||||
|
return stack, stack.stack_resources
|
||||||
|
|
||||||
def list_stack_resources(
|
def list_stack_resources(
|
||||||
self, stack_name_or_id: str
|
self, stack_name_or_id: str
|
||||||
) -> Iterable[Type[CloudFormationModel]]:
|
) -> Iterable[Type[CloudFormationModel]]:
|
||||||
@ -1111,6 +1173,12 @@ class CloudFormationBackend(BaseBackend):
|
|||||||
next_token = str(token + 100) if len(all_exports) > token + 100 else None
|
next_token = str(token + 100) if len(all_exports) > token + 100 else None
|
||||||
return exports, next_token
|
return exports, next_token
|
||||||
|
|
||||||
|
def describe_stack_events(self, stack_name: str) -> List[FakeEvent]:
|
||||||
|
return self.get_stack(stack_name).events
|
||||||
|
|
||||||
|
def get_template(self, name_or_stack_id: str) -> Union[str, Dict[str, Any]]:
|
||||||
|
return self.get_stack(name_or_stack_id).template
|
||||||
|
|
||||||
def validate_template(self, template: str) -> List[Any]:
|
def validate_template(self, template: str) -> List[Any]:
|
||||||
return validate_template_cfn_lint(template)
|
return validate_template_cfn_lint(template)
|
||||||
|
|
||||||
|
@ -125,6 +125,8 @@ class CloudFormationResponse(BaseResponse):
|
|||||||
template_url = self._get_param("TemplateURL")
|
template_url = self._get_param("TemplateURL")
|
||||||
role_arn = self._get_param("RoleARN")
|
role_arn = self._get_param("RoleARN")
|
||||||
enable_termination_protection = self._get_param("EnableTerminationProtection")
|
enable_termination_protection = self._get_param("EnableTerminationProtection")
|
||||||
|
timeout_in_mins = self._get_param("TimeoutInMinutes")
|
||||||
|
stack_policy_body = self._get_param("StackPolicyBody")
|
||||||
parameters_list = self._get_list_prefix("Parameters.member")
|
parameters_list = self._get_list_prefix("Parameters.member")
|
||||||
tags = dict(
|
tags = dict(
|
||||||
(item["key"], item["value"])
|
(item["key"], item["value"])
|
||||||
@ -151,6 +153,8 @@ class CloudFormationResponse(BaseResponse):
|
|||||||
tags=tags,
|
tags=tags,
|
||||||
role_arn=role_arn,
|
role_arn=role_arn,
|
||||||
enable_termination_protection=enable_termination_protection,
|
enable_termination_protection=enable_termination_protection,
|
||||||
|
timeout_in_mins=timeout_in_mins,
|
||||||
|
stack_policy_body=stack_policy_body,
|
||||||
)
|
)
|
||||||
if self.request_json:
|
if self.request_json:
|
||||||
return json.dumps(
|
return json.dumps(
|
||||||
@ -271,37 +275,29 @@ class CloudFormationResponse(BaseResponse):
|
|||||||
|
|
||||||
def describe_stack_resource(self) -> str:
|
def describe_stack_resource(self) -> str:
|
||||||
stack_name = self._get_param("StackName")
|
stack_name = self._get_param("StackName")
|
||||||
stack = self.cloudformation_backend.get_stack(stack_name)
|
|
||||||
logical_resource_id = self._get_param("LogicalResourceId")
|
logical_resource_id = self._get_param("LogicalResourceId")
|
||||||
|
stack, resource = self.cloudformation_backend.describe_stack_resource(
|
||||||
resource = None
|
stack_name, logical_resource_id
|
||||||
for stack_resource in stack.stack_resources:
|
)
|
||||||
if stack_resource.logical_resource_id == logical_resource_id: # type: ignore[attr-defined]
|
|
||||||
resource = stack_resource
|
|
||||||
break
|
|
||||||
|
|
||||||
if not resource:
|
|
||||||
message = (
|
|
||||||
f"Resource {logical_resource_id} does not exist for stack {stack_name}"
|
|
||||||
)
|
|
||||||
raise ValidationError(stack_name, message)
|
|
||||||
|
|
||||||
template = self.response_template(DESCRIBE_STACK_RESOURCE_RESPONSE_TEMPLATE)
|
template = self.response_template(DESCRIBE_STACK_RESOURCE_RESPONSE_TEMPLATE)
|
||||||
return template.render(stack=stack, resource=resource)
|
return template.render(stack=stack, resource=resource)
|
||||||
|
|
||||||
def describe_stack_resources(self) -> str:
|
def describe_stack_resources(self) -> str:
|
||||||
stack_name = self._get_param("StackName")
|
stack_name = self._get_param("StackName")
|
||||||
stack = self.cloudformation_backend.get_stack(stack_name)
|
stack, resources = self.cloudformation_backend.describe_stack_resources(
|
||||||
|
stack_name
|
||||||
|
)
|
||||||
|
|
||||||
template = self.response_template(DESCRIBE_STACK_RESOURCES_RESPONSE)
|
template = self.response_template(DESCRIBE_STACK_RESOURCES_RESPONSE)
|
||||||
return template.render(stack=stack)
|
return template.render(stack=stack, resources=resources)
|
||||||
|
|
||||||
def describe_stack_events(self) -> str:
|
def describe_stack_events(self) -> str:
|
||||||
stack_name = self._get_param("StackName")
|
stack_name = self._get_param("StackName")
|
||||||
stack = self.cloudformation_backend.get_stack(stack_name)
|
events = self.cloudformation_backend.describe_stack_events(stack_name)
|
||||||
|
|
||||||
template = self.response_template(DESCRIBE_STACK_EVENTS_RESPONSE)
|
template = self.response_template(DESCRIBE_STACK_EVENTS_RESPONSE)
|
||||||
return template.render(stack=stack)
|
return template.render(events=events)
|
||||||
|
|
||||||
def list_change_sets(self) -> str:
|
def list_change_sets(self) -> str:
|
||||||
change_sets = self.cloudformation_backend.list_change_sets()
|
change_sets = self.cloudformation_backend.list_change_sets()
|
||||||
@ -323,14 +319,14 @@ class CloudFormationResponse(BaseResponse):
|
|||||||
|
|
||||||
def get_template(self) -> str:
|
def get_template(self) -> str:
|
||||||
name_or_stack_id = self.querystring.get("StackName")[0] # type: ignore[index]
|
name_or_stack_id = self.querystring.get("StackName")[0] # type: ignore[index]
|
||||||
stack = self.cloudformation_backend.get_stack(name_or_stack_id)
|
stack_template = self.cloudformation_backend.get_template(name_or_stack_id)
|
||||||
|
|
||||||
if self.request_json:
|
if self.request_json:
|
||||||
return json.dumps(
|
return json.dumps(
|
||||||
{
|
{
|
||||||
"GetTemplateResponse": {
|
"GetTemplateResponse": {
|
||||||
"GetTemplateResult": {
|
"GetTemplateResult": {
|
||||||
"TemplateBody": stack.template,
|
"TemplateBody": stack_template,
|
||||||
"ResponseMetadata": {
|
"ResponseMetadata": {
|
||||||
"RequestId": "2d06e36c-ac1d-11e0-a958-f9382b6eb86bEXAMPLE"
|
"RequestId": "2d06e36c-ac1d-11e0-a958-f9382b6eb86bEXAMPLE"
|
||||||
},
|
},
|
||||||
@ -340,7 +336,7 @@ class CloudFormationResponse(BaseResponse):
|
|||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
template = self.response_template(GET_TEMPLATE_RESPONSE_TEMPLATE)
|
template = self.response_template(GET_TEMPLATE_RESPONSE_TEMPLATE)
|
||||||
return template.render(stack=stack)
|
return template.render(stack_template=stack_template)
|
||||||
|
|
||||||
def get_template_summary(self) -> str:
|
def get_template_summary(self) -> str:
|
||||||
stack_name = self._get_param("StackName")
|
stack_name = self._get_param("StackName")
|
||||||
@ -471,6 +467,9 @@ class CloudFormationResponse(BaseResponse):
|
|||||||
template_url = self._get_param("TemplateURL")
|
template_url = self._get_param("TemplateURL")
|
||||||
permission_model = self._get_param("PermissionModel")
|
permission_model = self._get_param("PermissionModel")
|
||||||
parameters_list = self._get_list_prefix("Parameters.member")
|
parameters_list = self._get_list_prefix("Parameters.member")
|
||||||
|
admin_role = self._get_param("AdministrationRoleARN")
|
||||||
|
exec_role = self._get_param("ExecutionRoleName")
|
||||||
|
description = self._get_param("Description")
|
||||||
tags = dict(
|
tags = dict(
|
||||||
(item["key"], item["value"])
|
(item["key"], item["value"])
|
||||||
for item in self._get_list_prefix("Tags.member")
|
for item in self._get_list_prefix("Tags.member")
|
||||||
@ -492,6 +491,9 @@ class CloudFormationResponse(BaseResponse):
|
|||||||
parameters=parameters,
|
parameters=parameters,
|
||||||
tags=tags,
|
tags=tags,
|
||||||
permission_model=permission_model,
|
permission_model=permission_model,
|
||||||
|
admin_role=admin_role,
|
||||||
|
exec_role=exec_role,
|
||||||
|
description=description,
|
||||||
)
|
)
|
||||||
if self.request_json:
|
if self.request_json:
|
||||||
return json.dumps(
|
return json.dumps(
|
||||||
@ -549,7 +551,7 @@ class CloudFormationResponse(BaseResponse):
|
|||||||
|
|
||||||
def describe_stack_set(self) -> str:
|
def describe_stack_set(self) -> str:
|
||||||
stackset_name = self._get_param("StackSetName")
|
stackset_name = self._get_param("StackSetName")
|
||||||
stackset = self.cloudformation_backend.get_stack_set(stackset_name)
|
stackset = self.cloudformation_backend.describe_stack_set(stackset_name)
|
||||||
|
|
||||||
if not stackset.admin_role:
|
if not stackset.admin_role:
|
||||||
stackset.admin_role = f"arn:aws:iam::{self.current_account}:role/AWSCloudFormationStackSetAdministrationRole"
|
stackset.admin_role = f"arn:aws:iam::{self.current_account}:role/AWSCloudFormationStackSetAdministrationRole"
|
||||||
@ -572,7 +574,7 @@ class CloudFormationResponse(BaseResponse):
|
|||||||
return rendered
|
return rendered
|
||||||
|
|
||||||
def list_stack_sets(self) -> str:
|
def list_stack_sets(self) -> str:
|
||||||
stacksets = self.cloudformation_backend.stacksets
|
stacksets = self.cloudformation_backend.list_stack_sets()
|
||||||
template = self.response_template(LIST_STACK_SETS_TEMPLATE)
|
template = self.response_template(LIST_STACK_SETS_TEMPLATE)
|
||||||
return template.render(stacksets=stacksets)
|
return template.render(stacksets=stacksets)
|
||||||
|
|
||||||
@ -584,31 +586,36 @@ class CloudFormationResponse(BaseResponse):
|
|||||||
|
|
||||||
def list_stack_set_operations(self) -> str:
|
def list_stack_set_operations(self) -> str:
|
||||||
stackset_name = self._get_param("StackSetName")
|
stackset_name = self._get_param("StackSetName")
|
||||||
stackset = self.cloudformation_backend.get_stack_set(stackset_name)
|
operations = self.cloudformation_backend.list_stack_set_operations(
|
||||||
|
stackset_name
|
||||||
|
)
|
||||||
template = self.response_template(LIST_STACK_SET_OPERATIONS_RESPONSE_TEMPLATE)
|
template = self.response_template(LIST_STACK_SET_OPERATIONS_RESPONSE_TEMPLATE)
|
||||||
return template.render(stackset=stackset)
|
return template.render(operations=operations)
|
||||||
|
|
||||||
def stop_stack_set_operation(self) -> str:
|
def stop_stack_set_operation(self) -> str:
|
||||||
stackset_name = self._get_param("StackSetName")
|
stackset_name = self._get_param("StackSetName")
|
||||||
operation_id = self._get_param("OperationId")
|
operation_id = self._get_param("OperationId")
|
||||||
stackset = self.cloudformation_backend.get_stack_set(stackset_name)
|
self.cloudformation_backend.stop_stack_set_operation(
|
||||||
stackset.update_operation(operation_id, "STOPPED")
|
stackset_name, operation_id
|
||||||
|
)
|
||||||
template = self.response_template(STOP_STACK_SET_OPERATION_RESPONSE_TEMPLATE)
|
template = self.response_template(STOP_STACK_SET_OPERATION_RESPONSE_TEMPLATE)
|
||||||
return template.render()
|
return template.render()
|
||||||
|
|
||||||
def describe_stack_set_operation(self) -> str:
|
def describe_stack_set_operation(self) -> str:
|
||||||
stackset_name = self._get_param("StackSetName")
|
stackset_name = self._get_param("StackSetName")
|
||||||
operation_id = self._get_param("OperationId")
|
operation_id = self._get_param("OperationId")
|
||||||
stackset = self.cloudformation_backend.get_stack_set(stackset_name)
|
stackset, operation = self.cloudformation_backend.describe_stack_set_operation(
|
||||||
operation = stackset.get_operation(operation_id)
|
stackset_name, operation_id
|
||||||
|
)
|
||||||
template = self.response_template(DESCRIBE_STACKSET_OPERATION_RESPONSE_TEMPLATE)
|
template = self.response_template(DESCRIBE_STACKSET_OPERATION_RESPONSE_TEMPLATE)
|
||||||
return template.render(stackset=stackset, operation=operation)
|
return template.render(stackset=stackset, operation=operation)
|
||||||
|
|
||||||
def list_stack_set_operation_results(self) -> str:
|
def list_stack_set_operation_results(self) -> str:
|
||||||
stackset_name = self._get_param("StackSetName")
|
stackset_name = self._get_param("StackSetName")
|
||||||
operation_id = self._get_param("OperationId")
|
operation_id = self._get_param("OperationId")
|
||||||
stackset = self.cloudformation_backend.get_stack_set(stackset_name)
|
operation = self.cloudformation_backend.list_stack_set_operation_results(
|
||||||
operation = stackset.get_operation(operation_id)
|
stackset_name, operation_id
|
||||||
|
)
|
||||||
template = self.response_template(
|
template = self.response_template(
|
||||||
LIST_STACK_SET_OPERATION_RESULTS_RESPONSE_TEMPLATE
|
LIST_STACK_SET_OPERATION_RESULTS_RESPONSE_TEMPLATE
|
||||||
)
|
)
|
||||||
@ -814,7 +821,7 @@ DESCRIBE_STACKS_TEMPLATE = """<DescribeStacksResponse>
|
|||||||
<StackName>{{ stack.name }}</StackName>
|
<StackName>{{ stack.name }}</StackName>
|
||||||
<StackId>{{ stack.stack_id }}</StackId>
|
<StackId>{{ stack.stack_id }}</StackId>
|
||||||
{% if stack.change_set_id %}
|
{% if stack.change_set_id %}
|
||||||
<ChangeSetId>{{ stack.change_set_id }}</ChangeSetId>
|
<ChangeSetId>{{ stack.change_set_id }}</stack.timeout_in_minsChangeSetId>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<Description><![CDATA[{{ stack.description }}]]></Description>
|
<Description><![CDATA[{{ stack.description }}]]></Description>
|
||||||
<CreationTime>{{ stack.creation_time_iso_8601 }}</CreationTime>
|
<CreationTime>{{ stack.creation_time_iso_8601 }}</CreationTime>
|
||||||
@ -861,6 +868,9 @@ DESCRIBE_STACKS_TEMPLATE = """<DescribeStacksResponse>
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</Tags>
|
</Tags>
|
||||||
<EnableTerminationProtection>{{ stack.enable_termination_protection }}</EnableTerminationProtection>
|
<EnableTerminationProtection>{{ stack.enable_termination_protection }}</EnableTerminationProtection>
|
||||||
|
{% if stack.timeout_in_mins %}
|
||||||
|
<TimeoutInMinutes>{{ stack.timeout_in_mins }}</TimeoutInMinutes>
|
||||||
|
{% endif %}
|
||||||
</member>
|
</member>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</Stacks>
|
</Stacks>
|
||||||
@ -887,7 +897,7 @@ DESCRIBE_STACK_RESOURCE_RESPONSE_TEMPLATE = """<DescribeStackResourceResponse>
|
|||||||
DESCRIBE_STACK_RESOURCES_RESPONSE = """<DescribeStackResourcesResponse>
|
DESCRIBE_STACK_RESOURCES_RESPONSE = """<DescribeStackResourcesResponse>
|
||||||
<DescribeStackResourcesResult>
|
<DescribeStackResourcesResult>
|
||||||
<StackResources>
|
<StackResources>
|
||||||
{% for resource in stack.stack_resources %}
|
{% for resource in resources %}
|
||||||
<member>
|
<member>
|
||||||
<StackId>{{ stack.stack_id }}</StackId>
|
<StackId>{{ stack.stack_id }}</StackId>
|
||||||
<StackName>{{ stack.name }}</StackName>
|
<StackName>{{ stack.name }}</StackName>
|
||||||
@ -905,7 +915,7 @@ DESCRIBE_STACK_RESOURCES_RESPONSE = """<DescribeStackResourcesResponse>
|
|||||||
DESCRIBE_STACK_EVENTS_RESPONSE = """<DescribeStackEventsResponse xmlns="http://cloudformation.amazonaws.com/doc/2010-05-15/">
|
DESCRIBE_STACK_EVENTS_RESPONSE = """<DescribeStackEventsResponse xmlns="http://cloudformation.amazonaws.com/doc/2010-05-15/">
|
||||||
<DescribeStackEventsResult>
|
<DescribeStackEventsResult>
|
||||||
<StackEvents>
|
<StackEvents>
|
||||||
{% for event in stack.events[::-1] %}
|
{% for event in events[::-1] %}
|
||||||
<member>
|
<member>
|
||||||
<Timestamp>{{ event.timestamp.strftime('%Y-%m-%dT%H:%M:%S.%fZ') }}</Timestamp>
|
<Timestamp>{{ event.timestamp.strftime('%Y-%m-%dT%H:%M:%S.%fZ') }}</Timestamp>
|
||||||
<ResourceStatus>{{ event.resource_status }}</ResourceStatus>
|
<ResourceStatus>{{ event.resource_status }}</ResourceStatus>
|
||||||
@ -983,7 +993,7 @@ LIST_STACKS_RESOURCES_RESPONSE = """<ListStackResourcesResponse>
|
|||||||
|
|
||||||
GET_TEMPLATE_RESPONSE_TEMPLATE = """<GetTemplateResponse>
|
GET_TEMPLATE_RESPONSE_TEMPLATE = """<GetTemplateResponse>
|
||||||
<GetTemplateResult>
|
<GetTemplateResult>
|
||||||
<TemplateBody>{{ stack.template }}</TemplateBody>
|
<TemplateBody>{{ stack_template }}</TemplateBody>
|
||||||
</GetTemplateResult>
|
</GetTemplateResult>
|
||||||
<ResponseMetadata>
|
<ResponseMetadata>
|
||||||
<RequestId>b9b4b068-3a41-11e5-94eb-example</RequestId>
|
<RequestId>b9b4b068-3a41-11e5-94eb-example</RequestId>
|
||||||
@ -1054,6 +1064,10 @@ DESCRIBE_STACK_SET_RESPONSE_TEMPLATE = """<DescribeStackSetResponse xmlns="http:
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</Tags>
|
</Tags>
|
||||||
<Status>{{ stackset.status }}</Status>
|
<Status>{{ stackset.status }}</Status>
|
||||||
|
<PermissionModel>{{ stackset.permission_model }}</PermissionModel>
|
||||||
|
{% if stackset.description %}
|
||||||
|
<Description>{{ stackset.description }}</Description>
|
||||||
|
{% endif %}
|
||||||
</StackSet>
|
</StackSet>
|
||||||
</DescribeStackSetResult>
|
</DescribeStackSetResult>
|
||||||
<ResponseMetadata>
|
<ResponseMetadata>
|
||||||
@ -1142,11 +1156,11 @@ DESCRIBE_STACK_INSTANCE_TEMPLATE = """<DescribeStackInstanceResponse xmlns="http
|
|||||||
LIST_STACK_SETS_TEMPLATE = """<ListStackSetsResponse xmlns="http://internal.amazon.com/coral/com.amazonaws.maestro.service.v20160713/">
|
LIST_STACK_SETS_TEMPLATE = """<ListStackSetsResponse xmlns="http://internal.amazon.com/coral/com.amazonaws.maestro.service.v20160713/">
|
||||||
<ListStackSetsResult>
|
<ListStackSetsResult>
|
||||||
<Summaries>
|
<Summaries>
|
||||||
{% for key, value in stacksets.items() %}
|
{% for stackset in stacksets %}
|
||||||
<member>
|
<member>
|
||||||
<StackSetName>{{ value.name }}</StackSetName>
|
<StackSetName>{{ stackset.name }}</StackSetName>
|
||||||
<StackSetId>{{ value.id }}</StackSetId>
|
<StackSetId>{{ stackset.id }}</StackSetId>
|
||||||
<Status>{{ value.status }}</Status>
|
<Status>{{ stackset.status }}</Status>
|
||||||
</member>
|
</member>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</Summaries>
|
</Summaries>
|
||||||
@ -1180,7 +1194,7 @@ UPDATE_STACK_SET_RESPONSE_TEMPLATE = """<UpdateStackSetResponse xmlns="http://in
|
|||||||
LIST_STACK_SET_OPERATIONS_RESPONSE_TEMPLATE = """<ListStackSetOperationsResponse xmlns="http://internal.amazon.com/coral/com.amazonaws.maestro.service.v20160713/">
|
LIST_STACK_SET_OPERATIONS_RESPONSE_TEMPLATE = """<ListStackSetOperationsResponse xmlns="http://internal.amazon.com/coral/com.amazonaws.maestro.service.v20160713/">
|
||||||
<ListStackSetOperationsResult>
|
<ListStackSetOperationsResult>
|
||||||
<Summaries>
|
<Summaries>
|
||||||
{% for operation in stackset.operations %}
|
{% for operation in operations %}
|
||||||
<member>
|
<member>
|
||||||
<CreationTimestamp>{{ operation.CreationTimestamp }}</CreationTimestamp>
|
<CreationTimestamp>{{ operation.CreationTimestamp }}</CreationTimestamp>
|
||||||
<OperationId>{{ operation.OperationId }}</OperationId>
|
<OperationId>{{ operation.OperationId }}</OperationId>
|
||||||
|
@ -61,6 +61,24 @@ batch:
|
|||||||
- TestAccBatchJobQueue_ComputeEnvironments_externalOrderUpdate
|
- TestAccBatchJobQueue_ComputeEnvironments_externalOrderUpdate
|
||||||
ce:
|
ce:
|
||||||
- TestAccCECostCategory
|
- TestAccCECostCategory
|
||||||
|
cloudformation:
|
||||||
|
- TestAccCloudFormationExportDataSource
|
||||||
|
- TestAccCloudFormationStackDataSource_DataSource
|
||||||
|
- TestAccCloudFormationStackSet_basic
|
||||||
|
- TestAccCloudFormationStackSet_templateBody
|
||||||
|
- TestAccCloudFormationStackSet_templateURL
|
||||||
|
- TestAccCloudFormationStackSet_description
|
||||||
|
- TestAccCloudFormationStackSet_operationPreferences
|
||||||
|
- TestAccCloudFormationStackSet_name
|
||||||
|
- TestAccCloudFormationStackSet_executionRoleName
|
||||||
|
- TestAccCloudFormationStackSet_disappears
|
||||||
|
- TestAccCloudFormationStack_basic
|
||||||
|
- TestAccCloudFormationStack_disappears
|
||||||
|
- TestAccCloudFormationStack_onFailure
|
||||||
|
- TestAccCloudFormationStack_yaml
|
||||||
|
- TestAccCloudFormationStack_withTransform
|
||||||
|
- TestAccCloudFormationStack_WithURLWithParams_withYAML
|
||||||
|
- TestAccCloudFormationStack_WithURL_withParams
|
||||||
cloudfront:
|
cloudfront:
|
||||||
- TestAccCloudFrontDistributionDataSource_basic
|
- TestAccCloudFrontDistributionDataSource_basic
|
||||||
- TestAccCloudFrontDistribution_isIPV6Enabled
|
- TestAccCloudFrontDistribution_isIPV6Enabled
|
||||||
|
@ -321,19 +321,18 @@ def test_create_stack():
|
|||||||
|
|
||||||
|
|
||||||
@mock_cloudformation
|
@mock_cloudformation
|
||||||
def test_create_stack_with_termination_protection():
|
def test_create_stack_with_additional_properties():
|
||||||
cf_conn = boto3.client("cloudformation", region_name="us-east-1")
|
cf_conn = boto3.client("cloudformation", region_name="us-east-1")
|
||||||
cf_conn.create_stack(
|
cf_conn.create_stack(
|
||||||
StackName="test_stack",
|
StackName="test_stack",
|
||||||
TemplateBody=dummy_template_json,
|
TemplateBody=dummy_template_json,
|
||||||
EnableTerminationProtection=True,
|
EnableTerminationProtection=True,
|
||||||
|
TimeoutInMinutes=25,
|
||||||
)
|
)
|
||||||
stack = cf_conn.describe_stacks()["Stacks"][0]
|
stack = cf_conn.describe_stacks()["Stacks"][0]
|
||||||
stack.should.have.key("StackName").equal("test_stack")
|
stack.should.have.key("StackName").equal("test_stack")
|
||||||
stack.should.have.key("EnableTerminationProtection").equal(True)
|
stack.should.have.key("EnableTerminationProtection").equal(True)
|
||||||
|
stack.should.have.key("TimeoutInMinutes").equals(25)
|
||||||
template = cf_conn.get_template(StackName="test_stack")["TemplateBody"]
|
|
||||||
template.should.equal(dummy_template)
|
|
||||||
|
|
||||||
|
|
||||||
@mock_cloudformation
|
@mock_cloudformation
|
||||||
@ -765,9 +764,16 @@ def test_delete_stack_set_by_name():
|
|||||||
)
|
)
|
||||||
cf_conn.delete_stack_set(StackSetName="teststackset")
|
cf_conn.delete_stack_set(StackSetName="teststackset")
|
||||||
|
|
||||||
cf_conn.describe_stack_set(StackSetName="teststackset")["StackSet"][
|
stacks = cf_conn.list_stack_sets()["Summaries"]
|
||||||
"Status"
|
stacks.should.have.length_of(1)
|
||||||
].should.equal("DELETED")
|
stacks[0].should.have.key("StackSetName").equals("teststackset")
|
||||||
|
stacks[0].should.have.key("Status").equals("DELETED")
|
||||||
|
|
||||||
|
with pytest.raises(ClientError) as exc:
|
||||||
|
cf_conn.describe_stack_set(StackSetName="teststackset")
|
||||||
|
err = exc.value.response["Error"]
|
||||||
|
err["Code"].should.equal("StackSetNotFoundException")
|
||||||
|
err["Message"].should.equal("StackSet teststackset not found")
|
||||||
|
|
||||||
|
|
||||||
@mock_cloudformation
|
@mock_cloudformation
|
||||||
@ -779,9 +785,10 @@ def test_delete_stack_set_by_id():
|
|||||||
stack_set_id = response["StackSetId"]
|
stack_set_id = response["StackSetId"]
|
||||||
cf_conn.delete_stack_set(StackSetName=stack_set_id)
|
cf_conn.delete_stack_set(StackSetName=stack_set_id)
|
||||||
|
|
||||||
cf_conn.describe_stack_set(StackSetName="teststackset")["StackSet"][
|
stacks = cf_conn.list_stack_sets()["Summaries"]
|
||||||
"Status"
|
stacks.should.have.length_of(1)
|
||||||
].should.equal("DELETED")
|
stacks[0].should.have.key("StackSetName").equals("teststackset")
|
||||||
|
stacks[0].should.have.key("Status").equals("DELETED")
|
||||||
|
|
||||||
|
|
||||||
@mock_cloudformation
|
@mock_cloudformation
|
||||||
@ -814,14 +821,20 @@ def test_delete_stack_set__while_instances_are_running():
|
|||||||
def test_create_stack_set():
|
def test_create_stack_set():
|
||||||
cf_conn = boto3.client("cloudformation", region_name="us-east-1")
|
cf_conn = boto3.client("cloudformation", region_name="us-east-1")
|
||||||
response = cf_conn.create_stack_set(
|
response = cf_conn.create_stack_set(
|
||||||
StackSetName="teststackset", TemplateBody=dummy_template_json
|
StackSetName="teststackset",
|
||||||
|
TemplateBody=dummy_template_json,
|
||||||
|
Description="desc",
|
||||||
|
AdministrationRoleARN="admin/role/arn:asdfasdfadsf",
|
||||||
)
|
)
|
||||||
|
|
||||||
cf_conn.describe_stack_set(StackSetName="teststackset")["StackSet"][
|
|
||||||
"TemplateBody"
|
|
||||||
].should.equal(dummy_template_json)
|
|
||||||
response["StackSetId"].should_not.equal(None)
|
response["StackSetId"].should_not.equal(None)
|
||||||
|
|
||||||
|
stack_set = cf_conn.describe_stack_set(StackSetName="teststackset")["StackSet"]
|
||||||
|
stack_set["TemplateBody"].should.equal(dummy_template_json)
|
||||||
|
stack_set.should.have.key("AdministrationRoleARN").should.equal(
|
||||||
|
"admin/role/arn:asdfasdfadsf"
|
||||||
|
)
|
||||||
|
stack_set.should.have.key("Description").equals("desc")
|
||||||
|
|
||||||
|
|
||||||
@mock_cloudformation
|
@mock_cloudformation
|
||||||
@pytest.mark.parametrize("name", ["1234", "stack_set", "-set"])
|
@pytest.mark.parametrize("name", ["1234", "stack_set", "-set"])
|
||||||
|
@ -71,6 +71,19 @@ def test_set_stack_policy_with_body():
|
|||||||
resp.should.have.key("StackPolicyBody").equals(policy)
|
resp.should.have.key("StackPolicyBody").equals(policy)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_cloudformation
|
||||||
|
def test_set_stack_policy_on_create():
|
||||||
|
cf_conn = boto3.client("cloudformation", region_name="us-east-1")
|
||||||
|
cf_conn.create_stack(
|
||||||
|
StackName="test_stack",
|
||||||
|
TemplateBody=dummy_template_json,
|
||||||
|
StackPolicyBody="stack_policy_body",
|
||||||
|
)
|
||||||
|
|
||||||
|
resp = cf_conn.get_stack_policy(StackName="test_stack")
|
||||||
|
resp.should.have.key("StackPolicyBody").equals("stack_policy_body")
|
||||||
|
|
||||||
|
|
||||||
@mock_cloudformation
|
@mock_cloudformation
|
||||||
@mock_s3
|
@mock_s3
|
||||||
def test_set_stack_policy_with_url():
|
def test_set_stack_policy_with_url():
|
||||||
|
Loading…
x
Reference in New Issue
Block a user