parent
fcc5a165ea
commit
4207a8e182
@ -475,19 +475,19 @@
|
|||||||
- [ ] continue_update_rollback
|
- [ ] continue_update_rollback
|
||||||
- [X] create_change_set
|
- [X] create_change_set
|
||||||
- [X] create_stack
|
- [X] create_stack
|
||||||
- [ ] create_stack_instances
|
- [X] create_stack_instances
|
||||||
- [ ] create_stack_set
|
- [X] create_stack_set
|
||||||
- [ ] delete_change_set
|
- [ ] delete_change_set
|
||||||
- [X] delete_stack
|
- [X] delete_stack
|
||||||
- [ ] delete_stack_instances
|
- [X] delete_stack_instances
|
||||||
- [ ] delete_stack_set
|
- [X] delete_stack_set
|
||||||
- [ ] describe_account_limits
|
- [ ] describe_account_limits
|
||||||
- [ ] describe_change_set
|
- [ ] describe_change_set
|
||||||
- [ ] describe_stack_events
|
- [ ] describe_stack_events
|
||||||
- [ ] describe_stack_instance
|
- [X] describe_stack_instance
|
||||||
- [ ] describe_stack_resource
|
- [ ] describe_stack_resource
|
||||||
- [ ] describe_stack_resources
|
- [ ] describe_stack_resources
|
||||||
- [ ] describe_stack_set
|
- [X] describe_stack_set
|
||||||
- [ ] describe_stack_set_operation
|
- [ ] describe_stack_set_operation
|
||||||
- [X] describe_stacks
|
- [X] describe_stacks
|
||||||
- [ ] estimate_template_cost
|
- [ ] estimate_template_cost
|
||||||
@ -498,18 +498,18 @@
|
|||||||
- [ ] list_change_sets
|
- [ ] list_change_sets
|
||||||
- [X] list_exports
|
- [X] list_exports
|
||||||
- [ ] list_imports
|
- [ ] list_imports
|
||||||
- [ ] list_stack_instances
|
- [X] list_stack_instances
|
||||||
- [X] list_stack_resources
|
- [X] list_stack_resources
|
||||||
- [ ] list_stack_set_operation_results
|
- [ ] 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
|
||||||
- [ ] set_stack_policy
|
- [ ] set_stack_policy
|
||||||
- [ ] signal_resource
|
- [ ] signal_resource
|
||||||
- [ ] stop_stack_set_operation
|
- [ ] stop_stack_set_operation
|
||||||
- [X] update_stack
|
- [X] update_stack
|
||||||
- [ ] update_stack_instances
|
- [X] update_stack_instances
|
||||||
- [ ] update_stack_set
|
- [X] update_stack_set
|
||||||
- [ ] update_termination_protection
|
- [ ] update_termination_protection
|
||||||
- [ ] validate_template
|
- [ ] validate_template
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
from datetime import datetime
|
from datetime import datetime, timedelta
|
||||||
import json
|
import json
|
||||||
import yaml
|
import yaml
|
||||||
import uuid
|
import uuid
|
||||||
@ -12,12 +12,137 @@ from .parsing import ResourceMap, OutputMap
|
|||||||
from .utils import (
|
from .utils import (
|
||||||
generate_changeset_id,
|
generate_changeset_id,
|
||||||
generate_stack_id,
|
generate_stack_id,
|
||||||
|
generate_stackset_arn,
|
||||||
|
generate_stackset_id,
|
||||||
yaml_tag_constructor,
|
yaml_tag_constructor,
|
||||||
validate_template_cfn_lint,
|
validate_template_cfn_lint,
|
||||||
)
|
)
|
||||||
from .exceptions import ValidationError
|
from .exceptions import ValidationError
|
||||||
|
|
||||||
|
|
||||||
|
class FakeStackSet(BaseModel):
|
||||||
|
|
||||||
|
def __init__(self, stackset_id, name, template, region='us-east-1', status='ACTIVE', description=None, parameters=None, tags=None, admin_role=None, execution_role=None):
|
||||||
|
self.id = stackset_id
|
||||||
|
self.arn = generate_stackset_arn(stackset_id, region)
|
||||||
|
self.name = name
|
||||||
|
self.template = template
|
||||||
|
self.description = description
|
||||||
|
self.parameters = parameters
|
||||||
|
self.tags = tags
|
||||||
|
self.admin_role = admin_role
|
||||||
|
self.execution_role = execution_role
|
||||||
|
self.status = status
|
||||||
|
self.instances = FakeStackInstances(parameters, self.id, self.name)
|
||||||
|
self.operations = []
|
||||||
|
|
||||||
|
@property
|
||||||
|
def stack_instances(self):
|
||||||
|
return self.instances.stack_instances
|
||||||
|
|
||||||
|
def _create_operation(self, operation_id, action, status):
|
||||||
|
operation = {
|
||||||
|
'OperationId': str(operation_id),
|
||||||
|
'Action': action,
|
||||||
|
'Status': status,
|
||||||
|
'CreationTimestamp': datetime.now(),
|
||||||
|
'EndTimestamp': datetime.now() + timedelta(minutes=2),
|
||||||
|
}
|
||||||
|
|
||||||
|
self.operations += [operation]
|
||||||
|
return operation
|
||||||
|
|
||||||
|
def delete(self):
|
||||||
|
self.status = 'DELETED'
|
||||||
|
|
||||||
|
def update(self, template, description, parameters, tags, admin_role,
|
||||||
|
execution_role, accounts, regions, operation_id=None):
|
||||||
|
if not operation_id:
|
||||||
|
operation_id = uuid.uuid4()
|
||||||
|
|
||||||
|
self.template = template if template else self.template
|
||||||
|
self.description = description if description is not None else self.description
|
||||||
|
self.parameters = parameters if parameters else self.parameters
|
||||||
|
self.tags = tags if tags else self.tags
|
||||||
|
self.admin_role = admin_role if admin_role else self.admin_role
|
||||||
|
self.execution_role = execution_role if execution_role else self.execution_role
|
||||||
|
|
||||||
|
if accounts and regions:
|
||||||
|
self.update_instances(accounts, regions, self.parameters)
|
||||||
|
|
||||||
|
operation = self._create_operation(operation_id=operation_id, action='UPDATE', status='SUCCEEDED')
|
||||||
|
return operation
|
||||||
|
|
||||||
|
def create_stack_instances(self, accounts, regions, parameters, operation_id=None):
|
||||||
|
if not operation_id:
|
||||||
|
operation_id = uuid.uuid4()
|
||||||
|
if not parameters:
|
||||||
|
parameters = self.parameters
|
||||||
|
|
||||||
|
self.instances.create_instances(accounts, regions, parameters, operation_id)
|
||||||
|
self._create_operation(operation_id=operation_id, action='CREATE', status='SUCCEEDED')
|
||||||
|
|
||||||
|
def delete_stack_instances(self, accounts, regions, operation_id=None):
|
||||||
|
if not operation_id:
|
||||||
|
operation_id = uuid.uuid4()
|
||||||
|
|
||||||
|
self.instances.delete(accounts, regions)
|
||||||
|
|
||||||
|
self._create_operation(operation_id=operation_id, action='DELETE', status='SUCCEEDED')
|
||||||
|
|
||||||
|
def update_instances(self, accounts, regions, parameters, operation_id=None):
|
||||||
|
if not operation_id:
|
||||||
|
operation_id = uuid.uuid4()
|
||||||
|
|
||||||
|
self.instances.update(accounts, regions, parameters)
|
||||||
|
operation = self._create_operation(operation_id=operation_id, action='UPDATE', status='SUCCEEDED')
|
||||||
|
return operation
|
||||||
|
|
||||||
|
|
||||||
|
class FakeStackInstances(BaseModel):
|
||||||
|
def __init__(self, parameters, stackset_id, stackset_name):
|
||||||
|
self.parameters = parameters if parameters else {}
|
||||||
|
self.stackset_id = stackset_id
|
||||||
|
self.stack_name = "StackSet-{}".format(stackset_id)
|
||||||
|
self.stackset_name = stackset_name
|
||||||
|
self.stack_instances = []
|
||||||
|
|
||||||
|
def create_instances(self, accounts, regions, parameters, operation_id):
|
||||||
|
new_instances = []
|
||||||
|
for region in regions:
|
||||||
|
for account in accounts:
|
||||||
|
instance = {
|
||||||
|
'StackId': generate_stack_id(self.stack_name, region, account),
|
||||||
|
'StackSetId': self.stackset_id,
|
||||||
|
'Region': region,
|
||||||
|
'Account': account,
|
||||||
|
'Status': "CURRENT",
|
||||||
|
'ParameterOverrides': parameters if parameters else [],
|
||||||
|
}
|
||||||
|
new_instances.append(instance)
|
||||||
|
self.stack_instances += new_instances
|
||||||
|
return new_instances
|
||||||
|
|
||||||
|
def update(self, accounts, regions, parameters):
|
||||||
|
for account in accounts:
|
||||||
|
for region in regions:
|
||||||
|
instance = self.get_instance(account, region)
|
||||||
|
if parameters:
|
||||||
|
instance['ParameterOverrides'] = parameters
|
||||||
|
else:
|
||||||
|
instance['ParameterOverrides'] = []
|
||||||
|
|
||||||
|
def delete(self, accounts, regions):
|
||||||
|
for i, instance in enumerate(self.stack_instances):
|
||||||
|
if instance['Region'] in regions and instance['Account'] in accounts:
|
||||||
|
self.stack_instances.pop(i)
|
||||||
|
|
||||||
|
def get_instance(self, account, region):
|
||||||
|
for i, instance in enumerate(self.stack_instances):
|
||||||
|
if instance['Region'] == region and instance['Account'] == account:
|
||||||
|
return self.stack_instances[i]
|
||||||
|
|
||||||
|
|
||||||
class FakeStack(BaseModel):
|
class FakeStack(BaseModel):
|
||||||
|
|
||||||
def __init__(self, stack_id, name, template, parameters, region_name, notification_arns=None, tags=None, role_arn=None, cross_stack_resources=None, create_change_set=False):
|
def __init__(self, stack_id, name, template, parameters, region_name, notification_arns=None, tags=None, role_arn=None, cross_stack_resources=None, create_change_set=False):
|
||||||
@ -146,10 +271,72 @@ class CloudFormationBackend(BaseBackend):
|
|||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.stacks = OrderedDict()
|
self.stacks = OrderedDict()
|
||||||
|
self.stacksets = OrderedDict()
|
||||||
self.deleted_stacks = {}
|
self.deleted_stacks = {}
|
||||||
self.exports = OrderedDict()
|
self.exports = OrderedDict()
|
||||||
self.change_sets = OrderedDict()
|
self.change_sets = OrderedDict()
|
||||||
|
|
||||||
|
def create_stack_set(self, name, template, parameters, tags=None, description=None, region='us-east-1', admin_role=None, execution_role=None):
|
||||||
|
stackset_id = generate_stackset_id(name)
|
||||||
|
new_stackset = FakeStackSet(
|
||||||
|
stackset_id=stackset_id,
|
||||||
|
name=name,
|
||||||
|
template=template,
|
||||||
|
parameters=parameters,
|
||||||
|
description=description,
|
||||||
|
tags=tags,
|
||||||
|
admin_role=admin_role,
|
||||||
|
execution_role=execution_role,
|
||||||
|
)
|
||||||
|
self.stacksets[stackset_id] = new_stackset
|
||||||
|
return new_stackset
|
||||||
|
|
||||||
|
def get_stack_set(self, name):
|
||||||
|
stacksets = self.stacksets.keys()
|
||||||
|
for stackset in stacksets:
|
||||||
|
if self.stacksets[stackset].name == name:
|
||||||
|
return self.stacksets[stackset]
|
||||||
|
raise ValidationError(name)
|
||||||
|
|
||||||
|
def delete_stack_set(self, name):
|
||||||
|
stacksets = self.stacksets.keys()
|
||||||
|
for stackset in stacksets:
|
||||||
|
if self.stacksets[stackset].name == name:
|
||||||
|
self.stacksets[stackset].delete()
|
||||||
|
|
||||||
|
def create_stack_instances(self, stackset_name, accounts, regions, parameters, operation_id=None):
|
||||||
|
stackset = self.get_stack_set(stackset_name)
|
||||||
|
|
||||||
|
stackset.create_stack_instances(
|
||||||
|
accounts=accounts,
|
||||||
|
regions=regions,
|
||||||
|
parameters=parameters,
|
||||||
|
operation_id=operation_id,
|
||||||
|
)
|
||||||
|
return stackset
|
||||||
|
|
||||||
|
def update_stack_set(self, stackset_name, template=None, description=None,
|
||||||
|
parameters=None, tags=None, admin_role=None, execution_role=None,
|
||||||
|
accounts=None, regions=None, operation_id=None):
|
||||||
|
stackset = self.get_stack_set(stackset_name)
|
||||||
|
update = stackset.update(
|
||||||
|
template=template,
|
||||||
|
description=description,
|
||||||
|
parameters=parameters,
|
||||||
|
tags=tags,
|
||||||
|
admin_role=admin_role,
|
||||||
|
execution_role=execution_role,
|
||||||
|
accounts=accounts,
|
||||||
|
regions=regions,
|
||||||
|
operation_id=operation_id
|
||||||
|
)
|
||||||
|
return update
|
||||||
|
|
||||||
|
def delete_stack_instances(self, stackset_name, accounts, regions, operation_id=None):
|
||||||
|
stackset = self.get_stack_set(stackset_name)
|
||||||
|
stackset.delete_stack_instances(accounts, regions, operation_id)
|
||||||
|
return stackset
|
||||||
|
|
||||||
def create_stack(self, name, template, parameters, region_name, notification_arns=None, tags=None, role_arn=None, create_change_set=False):
|
def create_stack(self, name, template, parameters, region_name, notification_arns=None, tags=None, role_arn=None, create_change_set=False):
|
||||||
stack_id = generate_stack_id(name)
|
stack_id = generate_stack_id(name)
|
||||||
new_stack = FakeStack(
|
new_stack = FakeStack(
|
||||||
|
@ -312,6 +312,151 @@ class CloudFormationResponse(BaseResponse):
|
|||||||
template = self.response_template(VALIDATE_STACK_RESPONSE_TEMPLATE)
|
template = self.response_template(VALIDATE_STACK_RESPONSE_TEMPLATE)
|
||||||
return template.render(description=description)
|
return template.render(description=description)
|
||||||
|
|
||||||
|
def create_stack_set(self):
|
||||||
|
stackset_name = self._get_param('StackSetName')
|
||||||
|
stack_body = self._get_param('TemplateBody')
|
||||||
|
template_url = self._get_param('TemplateURL')
|
||||||
|
# role_arn = self._get_param('RoleARN')
|
||||||
|
parameters_list = self._get_list_prefix("Parameters.member")
|
||||||
|
tags = dict((item['key'], item['value'])
|
||||||
|
for item in self._get_list_prefix("Tags.member"))
|
||||||
|
|
||||||
|
# Copy-Pasta - Hack dict-comprehension
|
||||||
|
parameters = dict([
|
||||||
|
(parameter['parameter_key'], parameter['parameter_value'])
|
||||||
|
for parameter
|
||||||
|
in parameters_list
|
||||||
|
])
|
||||||
|
if template_url:
|
||||||
|
stack_body = self._get_stack_from_s3_url(template_url)
|
||||||
|
|
||||||
|
stackset = self.cloudformation_backend.create_stack_set(
|
||||||
|
name=stackset_name,
|
||||||
|
template=stack_body,
|
||||||
|
parameters=parameters,
|
||||||
|
tags=tags,
|
||||||
|
# role_arn=role_arn,
|
||||||
|
)
|
||||||
|
if self.request_json:
|
||||||
|
return json.dumps({
|
||||||
|
'CreateStackSetResponse': {
|
||||||
|
'CreateStackSetResult': {
|
||||||
|
'StackSetId': stackset.stackset_id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
template = self.response_template(CREATE_STACK_SET_RESPONSE_TEMPLATE)
|
||||||
|
return template.render(stackset=stackset)
|
||||||
|
|
||||||
|
def create_stack_instances(self):
|
||||||
|
stackset_name = self._get_param('StackSetName')
|
||||||
|
accounts = self._get_multi_param('Accounts.member')
|
||||||
|
regions = self._get_multi_param('Regions.member')
|
||||||
|
parameters = self._get_multi_param('ParameterOverrides.member')
|
||||||
|
self.cloudformation_backend.create_stack_instances(stackset_name, accounts, regions, parameters)
|
||||||
|
template = self.response_template(CREATE_STACK_INSTANCES_TEMPLATE)
|
||||||
|
return template.render()
|
||||||
|
|
||||||
|
def delete_stack_set(self):
|
||||||
|
stackset_name = self._get_param('StackSetName')
|
||||||
|
self.cloudformation_backend.delete_stack_set(stackset_name)
|
||||||
|
template = self.response_template(DELETE_STACK_SET_RESPONSE_TEMPLATE)
|
||||||
|
return template.render()
|
||||||
|
|
||||||
|
def delete_stack_instances(self):
|
||||||
|
stackset_name = self._get_param('StackSetName')
|
||||||
|
accounts = self._get_multi_param('Accounts.member')
|
||||||
|
regions = self._get_multi_param('Regions.member')
|
||||||
|
self.cloudformation_backend.delete_stack_instances(stackset_name, accounts, regions)
|
||||||
|
|
||||||
|
template = self.response_template(DELETE_STACK_INSTANCES_TEMPLATE)
|
||||||
|
return template.render()
|
||||||
|
|
||||||
|
def describe_stack_set(self):
|
||||||
|
stackset_name = self._get_param('StackSetName')
|
||||||
|
stackset = self.cloudformation_backend.get_stack_set(stackset_name)
|
||||||
|
|
||||||
|
if not stackset.admin_role:
|
||||||
|
stackset.admin_role = 'arn:aws:iam::123456789012:role/AWSCloudFormationStackSetAdministrationRole'
|
||||||
|
if not stackset.execution_role:
|
||||||
|
stackset.execution_role = 'AWSCloudFormationStackSetExecutionRole'
|
||||||
|
|
||||||
|
template = self.response_template(DESCRIBE_STACK_SET_RESPONSE_TEMPLATE)
|
||||||
|
return template.render(stackset=stackset)
|
||||||
|
|
||||||
|
def describe_stack_instance(self):
|
||||||
|
stackset_name = self._get_param('StackSetName')
|
||||||
|
account = self._get_param('StackInstanceAccount')
|
||||||
|
region = self._get_param('StackInstanceRegion')
|
||||||
|
|
||||||
|
instance = self.cloudformation_backend.get_stack_set(stackset_name).instances.get_instance(account, region)
|
||||||
|
template = self.response_template(DESCRIBE_STACK_INSTANCE_TEMPLATE)
|
||||||
|
rendered = template.render(instance=instance)
|
||||||
|
return rendered
|
||||||
|
|
||||||
|
def list_stack_sets(self):
|
||||||
|
stacksets = self.cloudformation_backend.stacksets
|
||||||
|
template = self.response_template(LIST_STACK_SETS_TEMPLATE)
|
||||||
|
return template.render(stacksets=stacksets)
|
||||||
|
|
||||||
|
def list_stack_instances(self):
|
||||||
|
stackset_name = self._get_param('StackSetName')
|
||||||
|
stackset = self.cloudformation_backend.get_stack_set(stackset_name)
|
||||||
|
template = self.response_template(LIST_STACK_INSTANCES_TEMPLATE)
|
||||||
|
return template.render(stackset=stackset)
|
||||||
|
|
||||||
|
def list_stack_set_operations(self):
|
||||||
|
stackset_name = self._get_param('StackSetName')
|
||||||
|
stackset = self.cloudformation_backend.get_stack_set(stackset_name)
|
||||||
|
template = self.response_template(LIST_STACK_SET_OPERATIONS_RESPONSE_TEMPLATE)
|
||||||
|
return template.render(stackset=stackset)
|
||||||
|
|
||||||
|
def update_stack_set(self):
|
||||||
|
stackset_name = self._get_param('StackSetName')
|
||||||
|
operation_id = self._get_param('OperationId')
|
||||||
|
description = self._get_param('Description')
|
||||||
|
execution_role = self._get_param('ExecutionRoleName')
|
||||||
|
admin_role = self._get_param('AdministrationRoleARN')
|
||||||
|
accounts = self._get_multi_param('Accounts.member')
|
||||||
|
regions = self._get_multi_param('Regions.member')
|
||||||
|
template_body = self._get_param('TemplateBody')
|
||||||
|
template_url = self._get_param('TemplateURL')
|
||||||
|
if template_url:
|
||||||
|
template_body = self._get_stack_from_s3_url(template_url)
|
||||||
|
tags = dict((item['key'], item['value'])
|
||||||
|
for item in self._get_list_prefix("Tags.member"))
|
||||||
|
parameters_list = self._get_list_prefix("Parameters.member")
|
||||||
|
parameters = dict([
|
||||||
|
(parameter['parameter_key'], parameter['parameter_value'])
|
||||||
|
for parameter
|
||||||
|
in parameters_list
|
||||||
|
])
|
||||||
|
operation = self.cloudformation_backend.update_stack_set(
|
||||||
|
stackset_name=stackset_name,
|
||||||
|
template=template_body,
|
||||||
|
description=description,
|
||||||
|
parameters=parameters,
|
||||||
|
tags=tags,
|
||||||
|
admin_role=admin_role,
|
||||||
|
execution_role=execution_role,
|
||||||
|
accounts=accounts,
|
||||||
|
regions=regions,
|
||||||
|
operation_id=operation_id
|
||||||
|
)
|
||||||
|
|
||||||
|
template = self.response_template(UPDATE_STACK_SET_RESPONSE_TEMPLATE)
|
||||||
|
return template.render(operation=operation)
|
||||||
|
|
||||||
|
def update_stack_instances(self):
|
||||||
|
stackset_name = self._get_param('StackSetName')
|
||||||
|
accounts = self._get_multi_param('Accounts.member')
|
||||||
|
regions = self._get_multi_param('Regions.member')
|
||||||
|
parameters = self._get_multi_param('ParameterOverrides.member')
|
||||||
|
operation = self.cloudformation_backend.get_stack_set(stackset_name).update_instances(accounts, regions, parameters)
|
||||||
|
template = self.response_template(UPDATE_STACK_INSTANCES_RESPONSE_TEMPLATE)
|
||||||
|
return template.render(operation=operation)
|
||||||
|
|
||||||
|
|
||||||
VALIDATE_STACK_RESPONSE_TEMPLATE = """<ValidateTemplateResponse>
|
VALIDATE_STACK_RESPONSE_TEMPLATE = """<ValidateTemplateResponse>
|
||||||
<ValidateTemplateResult>
|
<ValidateTemplateResult>
|
||||||
@ -553,3 +698,183 @@ LIST_EXPORTS_RESPONSE = """<ListExportsResponse xmlns="http://cloudformation.ama
|
|||||||
<RequestId>5ccc7dcd-744c-11e5-be70-example</RequestId>
|
<RequestId>5ccc7dcd-744c-11e5-be70-example</RequestId>
|
||||||
</ResponseMetadata>
|
</ResponseMetadata>
|
||||||
</ListExportsResponse>"""
|
</ListExportsResponse>"""
|
||||||
|
|
||||||
|
CREATE_STACK_SET_RESPONSE_TEMPLATE = """<CreateStackSetResponse xmlns="http://internal.amazon.com/coral/com.amazonaws.maestro.service.v20160713/">
|
||||||
|
<CreateStackSetResult>
|
||||||
|
<StackSetId>{{ stackset.stackset_id }}</StackSetId>
|
||||||
|
</CreateStackSetResult>
|
||||||
|
<ResponseMetadata>
|
||||||
|
<RequestId>f457258c-391d-41d1-861f-example</RequestId>
|
||||||
|
</ResponseMetadata>
|
||||||
|
</CreateStackSetResponse>
|
||||||
|
"""
|
||||||
|
|
||||||
|
DESCRIBE_STACK_SET_RESPONSE_TEMPLATE = """<DescribeStackSetResponse xmlns="http://internal.amazon.com/coral/com.amazonaws.maestro.service.v20160713/">
|
||||||
|
<DescribeStackSetResult>
|
||||||
|
<StackSet>
|
||||||
|
<Capabilities/>
|
||||||
|
<StackSetARN>{{ stackset.arn }}</StackSetARN>
|
||||||
|
<ExecutionRoleName>{{ stackset.execution_role }}</ExecutionRoleName>
|
||||||
|
<AdministrationRoleARN>{{ stackset.admin_role }}</AdministrationRoleARN>
|
||||||
|
<StackSetId>{{ stackset.id }}</StackSetId>
|
||||||
|
<TemplateBody>{{ stackset.template }}</TemplateBody>
|
||||||
|
<StackSetName>{{ stackset.name }}</StackSetName>
|
||||||
|
<Parameters>
|
||||||
|
{% for param_name, param_value in stackset.parameters.items() %}
|
||||||
|
<member>
|
||||||
|
<ParameterKey>{{ param_name }}</ParameterKey>
|
||||||
|
<ParameterValue>{{ param_value }}</ParameterValue>
|
||||||
|
</member>
|
||||||
|
{% endfor %}
|
||||||
|
</Parameters>
|
||||||
|
<Tags>
|
||||||
|
{% for tag_key, tag_value in stackset.tags.items() %}
|
||||||
|
<member>
|
||||||
|
<Key>{{ tag_key }}</Key>
|
||||||
|
<Value>{{ tag_value }}</Value>
|
||||||
|
</member>
|
||||||
|
{% endfor %}
|
||||||
|
</Tags>
|
||||||
|
<Status>{{ stackset.status }}</Status>
|
||||||
|
</StackSet>
|
||||||
|
</DescribeStackSetResult>
|
||||||
|
<ResponseMetadata>
|
||||||
|
<RequestId>d8b64e11-5332-46e1-9603-example</RequestId>
|
||||||
|
</ResponseMetadata>
|
||||||
|
</DescribeStackSetResponse>"""
|
||||||
|
|
||||||
|
DELETE_STACK_SET_RESPONSE_TEMPLATE = """<DeleteStackSetResponse xmlns="http://internal.amazon.com/coral/com.amazonaws.maestro.service.v20160713/">
|
||||||
|
<DeleteStackSetResult/>
|
||||||
|
<ResponseMetadata>
|
||||||
|
<RequestId>c35ec2d0-d69f-4c4d-9bd7-example</RequestId>
|
||||||
|
</ResponseMetadata>
|
||||||
|
</DeleteStackSetResponse>"""
|
||||||
|
|
||||||
|
CREATE_STACK_INSTANCES_TEMPLATE = """<CreateStackInstancesResponse xmlns="http://internal.amazon.com/coral/com.amazonaws.maestro.service.v20160713/">
|
||||||
|
<CreateStackInstancesResult>
|
||||||
|
<OperationId>1459ad6d-63cc-4c96-a73e-example</OperationId>
|
||||||
|
</CreateStackInstancesResult>
|
||||||
|
<ResponseMetadata>
|
||||||
|
<RequestId>6b29f7e3-69be-4d32-b374-example</RequestId>
|
||||||
|
</ResponseMetadata>
|
||||||
|
</CreateStackInstancesResponse>
|
||||||
|
"""
|
||||||
|
|
||||||
|
LIST_STACK_INSTANCES_TEMPLATE = """<ListStackInstancesResponse xmlns="http://internal.amazon.com/coral/com.amazonaws.maestro.service.v20160713/">
|
||||||
|
<ListStackInstancesResult>
|
||||||
|
<Summaries>
|
||||||
|
{% for instance in stackset.stack_instances %}
|
||||||
|
<member>
|
||||||
|
<StackId>{{ instance.StackId }}</StackId>
|
||||||
|
<StackSetId>{{ instance.StackSetId }}</StackSetId>
|
||||||
|
<Region>{{ instance.Region }}</Region>
|
||||||
|
<Account>{{ instance.Account }}</Account>
|
||||||
|
<Status>{{ instance.Status }}</Status>
|
||||||
|
</member>
|
||||||
|
{% endfor %}
|
||||||
|
</Summaries>
|
||||||
|
</ListStackInstancesResult>
|
||||||
|
<ResponseMetadata>
|
||||||
|
<RequestId>83c27e73-b498-410f-993c-example</RequestId>
|
||||||
|
</ResponseMetadata>
|
||||||
|
</ListStackInstancesResponse>
|
||||||
|
"""
|
||||||
|
|
||||||
|
DELETE_STACK_INSTANCES_TEMPLATE = """<DeleteStackInstancesResponse xmlns="http://internal.amazon.com/coral/com.amazonaws.maestro.service.v20160713/">
|
||||||
|
<DeleteStackInstancesResult>
|
||||||
|
<OperationId>d76a070d-279a-45f3-b9b4-example</OperationId>
|
||||||
|
</DeleteStackInstancesResult>
|
||||||
|
<ResponseMetadata>
|
||||||
|
<RequestId>e5325090-66f6-4ecd-a531-example</RequestId>
|
||||||
|
</ResponseMetadata>
|
||||||
|
</DeleteStackInstancesResponse>
|
||||||
|
"""
|
||||||
|
|
||||||
|
DESCRIBE_STACK_INSTANCE_TEMPLATE = """<DescribeStackInstanceResponse xmlns="http://internal.amazon.com/coral/com.amazonaws.maestro.service.v20160713/">
|
||||||
|
<DescribeStackInstanceResult>
|
||||||
|
<StackInstance>
|
||||||
|
<StackId>{{ instance.StackId }}</StackId>
|
||||||
|
<StackSetId>{{ instance.StackSetId }}</StackSetId>
|
||||||
|
{% if instance.ParameterOverrides %}
|
||||||
|
<ParameterOverrides>
|
||||||
|
{% for override in instance.ParameterOverrides %}
|
||||||
|
{% if override['ParameterKey'] or override['ParameterValue'] %}
|
||||||
|
<member>
|
||||||
|
<ParameterKey>{{ override.ParameterKey }}</ParameterKey>
|
||||||
|
<UsePreviousValue>false</UsePreviousValue>
|
||||||
|
<ParameterValue>{{ override.ParameterValue }}</ParameterValue>
|
||||||
|
</member>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</ParameterOverrides>
|
||||||
|
{% else %}
|
||||||
|
<ParameterOverrides/>
|
||||||
|
{% endif %}
|
||||||
|
<Region>{{ instance.Region }}</Region>
|
||||||
|
<Account>{{ instance.Account }}</Account>
|
||||||
|
<Status>{{ instance.Status }}</Status>
|
||||||
|
</StackInstance>
|
||||||
|
</DescribeStackInstanceResult>
|
||||||
|
<ResponseMetadata>
|
||||||
|
<RequestId>c6c7be10-0343-4319-8a25-example</RequestId>
|
||||||
|
</ResponseMetadata>
|
||||||
|
</DescribeStackInstanceResponse>
|
||||||
|
"""
|
||||||
|
|
||||||
|
LIST_STACK_SETS_TEMPLATE = """<ListStackSetsResponse xmlns="http://internal.amazon.com/coral/com.amazonaws.maestro.service.v20160713/">
|
||||||
|
<ListStackSetsResult>
|
||||||
|
<Summaries>
|
||||||
|
{% for key, value in stacksets.items() %}
|
||||||
|
<member>
|
||||||
|
<StackSetName>{{ value.name }}</StackSetName>
|
||||||
|
<StackSetId>{{ value.id }}</StackSetId>
|
||||||
|
<Status>{{ value.status }}</Status>
|
||||||
|
</member>
|
||||||
|
{% endfor %}
|
||||||
|
</Summaries>
|
||||||
|
</ListStackSetsResult>
|
||||||
|
<ResponseMetadata>
|
||||||
|
<RequestId>4dcacb73-841e-4ed8-b335-example</RequestId>
|
||||||
|
</ResponseMetadata>
|
||||||
|
</ListStackSetsResponse>
|
||||||
|
"""
|
||||||
|
|
||||||
|
UPDATE_STACK_INSTANCES_RESPONSE_TEMPLATE = """<UpdateStackInstancesResponse xmlns="http://internal.amazon.com/coral/com.amazonaws.maestro.service.v20160713/">
|
||||||
|
<UpdateStackInstancesResult>
|
||||||
|
<OperationId>{{ operation }}</OperationId>
|
||||||
|
</UpdateStackInstancesResult>
|
||||||
|
<ResponseMetadata>
|
||||||
|
<RequestId>bdbf8e94-19b6-4ce4-af85-example</RequestId>
|
||||||
|
</ResponseMetadata>
|
||||||
|
</UpdateStackInstancesResponse>
|
||||||
|
"""
|
||||||
|
|
||||||
|
UPDATE_STACK_SET_RESPONSE_TEMPLATE = """<UpdateStackSetResponse xmlns="http://internal.amazon.com/coral/com.amazonaws.maestro.service.v20160713/">
|
||||||
|
<UpdateStackSetResult>
|
||||||
|
<OperationId>{{ operation.OperationId }}</OperationId>
|
||||||
|
</UpdateStackSetResult>
|
||||||
|
<ResponseMetadata>
|
||||||
|
<RequestId>adac907b-17e3-43e6-a254-example</RequestId>
|
||||||
|
</ResponseMetadata>
|
||||||
|
</UpdateStackSetResponse>
|
||||||
|
"""
|
||||||
|
|
||||||
|
LIST_STACK_SET_OPERATIONS_RESPONSE_TEMPLATE = """<ListStackSetOperationsResponse xmlns="http://internal.amazon.com/coral/com.amazonaws.maestro.service.v20160713/">
|
||||||
|
<ListStackSetOperationsResult>
|
||||||
|
<Summaries>
|
||||||
|
{% for operation in stackset.operations %}
|
||||||
|
<member>
|
||||||
|
<CreationTimestamp>{{ operation.CreationTimestamp }}</CreationTimestamp>
|
||||||
|
<OperationId>{{ operation.OperationId }}</OperationId>
|
||||||
|
<Action>{{ operation.Action }}</Action>
|
||||||
|
<EndTimestamp>{{ operation.EndTimestamp }}</EndTimestamp>
|
||||||
|
<Status>{{ operation.Status }}</Status>
|
||||||
|
</member>
|
||||||
|
{% endfor %}
|
||||||
|
</Summaries>
|
||||||
|
</ListStackSetOperationsResult>
|
||||||
|
<ResponseMetadata>
|
||||||
|
<RequestId>65b9d9be-08bb-4a43-9a21-example</RequestId>
|
||||||
|
</ResponseMetadata>
|
||||||
|
</ListStackSetOperationsResponse>
|
||||||
|
"""
|
||||||
|
@ -8,9 +8,9 @@ import os
|
|||||||
from cfnlint import decode, core
|
from cfnlint import decode, core
|
||||||
|
|
||||||
|
|
||||||
def generate_stack_id(stack_name):
|
def generate_stack_id(stack_name, region="us-east-1", account="123456789"):
|
||||||
random_id = uuid.uuid4()
|
random_id = uuid.uuid4()
|
||||||
return "arn:aws:cloudformation:us-east-1:123456789:stack/{0}/{1}".format(stack_name, random_id)
|
return "arn:aws:cloudformation:{}:{}:stack/{}/{}".format(region, account, stack_name, random_id)
|
||||||
|
|
||||||
|
|
||||||
def generate_changeset_id(changeset_name, region_name):
|
def generate_changeset_id(changeset_name, region_name):
|
||||||
@ -18,6 +18,15 @@ def generate_changeset_id(changeset_name, region_name):
|
|||||||
return 'arn:aws:cloudformation:{0}:123456789:changeSet/{1}/{2}'.format(region_name, changeset_name, random_id)
|
return 'arn:aws:cloudformation:{0}:123456789:changeSet/{1}/{2}'.format(region_name, changeset_name, random_id)
|
||||||
|
|
||||||
|
|
||||||
|
def generate_stackset_id(stackset_name):
|
||||||
|
random_id = uuid.uuid4()
|
||||||
|
return '{}:{}'.format(stackset_name, random_id)
|
||||||
|
|
||||||
|
|
||||||
|
def generate_stackset_arn(stackset_id, region_name):
|
||||||
|
return 'arn:aws:cloudformation:{}:123456789012:stackset/{}'.format(region_name, stackset_id)
|
||||||
|
|
||||||
|
|
||||||
def random_suffix():
|
def random_suffix():
|
||||||
size = 12
|
size = 12
|
||||||
chars = list(range(10)) + ['A-Z']
|
chars = list(range(10)) + ['A-Z']
|
||||||
|
@ -184,6 +184,343 @@ dummy_import_template_json = json.dumps(dummy_import_template)
|
|||||||
dummy_redrive_template_json = json.dumps(dummy_redrive_template)
|
dummy_redrive_template_json = json.dumps(dummy_redrive_template)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_cloudformation
|
||||||
|
def test_boto3_describe_stack_instances():
|
||||||
|
cf_conn = boto3.client('cloudformation', region_name='us-east-1')
|
||||||
|
cf_conn.create_stack_set(
|
||||||
|
StackSetName="test_stack_set",
|
||||||
|
TemplateBody=dummy_template_json,
|
||||||
|
)
|
||||||
|
cf_conn.create_stack_instances(
|
||||||
|
StackSetName="test_stack_set",
|
||||||
|
Accounts=['123456789012'],
|
||||||
|
Regions=['us-east-1', 'us-west-2'],
|
||||||
|
)
|
||||||
|
usw2_instance = cf_conn.describe_stack_instance(
|
||||||
|
StackSetName="test_stack_set",
|
||||||
|
StackInstanceAccount='123456789012',
|
||||||
|
StackInstanceRegion='us-west-2',
|
||||||
|
)
|
||||||
|
use1_instance = cf_conn.describe_stack_instance(
|
||||||
|
StackSetName="test_stack_set",
|
||||||
|
StackInstanceAccount='123456789012',
|
||||||
|
StackInstanceRegion='us-east-1',
|
||||||
|
)
|
||||||
|
|
||||||
|
usw2_instance['StackInstance'].should.have.key('Region').which.should.equal('us-west-2')
|
||||||
|
usw2_instance['StackInstance'].should.have.key('Account').which.should.equal('123456789012')
|
||||||
|
use1_instance['StackInstance'].should.have.key('Region').which.should.equal('us-east-1')
|
||||||
|
use1_instance['StackInstance'].should.have.key('Account').which.should.equal('123456789012')
|
||||||
|
|
||||||
|
|
||||||
|
@mock_cloudformation
|
||||||
|
def test_boto3_list_stacksets_length():
|
||||||
|
cf_conn = boto3.client('cloudformation', region_name='us-east-1')
|
||||||
|
cf_conn.create_stack_set(
|
||||||
|
StackSetName="test_stack_set",
|
||||||
|
TemplateBody=dummy_template_json,
|
||||||
|
)
|
||||||
|
cf_conn.create_stack_set(
|
||||||
|
StackSetName="test_stack_set2",
|
||||||
|
TemplateBody=dummy_template_yaml,
|
||||||
|
)
|
||||||
|
stacksets = cf_conn.list_stack_sets()
|
||||||
|
stacksets.should.have.length_of(2)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_cloudformation
|
||||||
|
def test_boto3_list_stacksets_contents():
|
||||||
|
cf_conn = boto3.client('cloudformation', region_name='us-east-1')
|
||||||
|
cf_conn.create_stack_set(
|
||||||
|
StackSetName="test_stack_set",
|
||||||
|
TemplateBody=dummy_template_json,
|
||||||
|
)
|
||||||
|
stacksets = cf_conn.list_stack_sets()
|
||||||
|
stacksets['Summaries'][0].should.have.key('StackSetName').which.should.equal('test_stack_set')
|
||||||
|
stacksets['Summaries'][0].should.have.key('Status').which.should.equal('ACTIVE')
|
||||||
|
|
||||||
|
|
||||||
|
@mock_cloudformation
|
||||||
|
def test_boto3_update_stack_instances():
|
||||||
|
cf_conn = boto3.client('cloudformation', region_name='us-east-1')
|
||||||
|
param = [
|
||||||
|
{'ParameterKey': 'SomeParam', 'ParameterValue': 'StackSetValue'},
|
||||||
|
{'ParameterKey': 'AnotherParam', 'ParameterValue': 'StackSetValue2'},
|
||||||
|
]
|
||||||
|
param_overrides = [
|
||||||
|
{'ParameterKey': 'SomeParam', 'ParameterValue': 'OverrideValue'},
|
||||||
|
{'ParameterKey': 'AnotherParam', 'ParameterValue': 'OverrideValue2'}
|
||||||
|
]
|
||||||
|
cf_conn.create_stack_set(
|
||||||
|
StackSetName="test_stack_set",
|
||||||
|
TemplateBody=dummy_template_yaml_with_ref,
|
||||||
|
Parameters=param,
|
||||||
|
)
|
||||||
|
cf_conn.create_stack_instances(
|
||||||
|
StackSetName="test_stack_set",
|
||||||
|
Accounts=['123456789012'],
|
||||||
|
Regions=['us-east-1', 'us-west-1', 'us-west-2'],
|
||||||
|
)
|
||||||
|
cf_conn.update_stack_instances(
|
||||||
|
StackSetName="test_stack_set",
|
||||||
|
Accounts=['123456789012'],
|
||||||
|
Regions=['us-west-1', 'us-west-2'],
|
||||||
|
ParameterOverrides=param_overrides,
|
||||||
|
)
|
||||||
|
usw2_instance = cf_conn.describe_stack_instance(
|
||||||
|
StackSetName="test_stack_set",
|
||||||
|
StackInstanceAccount='123456789012',
|
||||||
|
StackInstanceRegion='us-west-2',
|
||||||
|
)
|
||||||
|
usw1_instance = cf_conn.describe_stack_instance(
|
||||||
|
StackSetName="test_stack_set",
|
||||||
|
StackInstanceAccount='123456789012',
|
||||||
|
StackInstanceRegion='us-west-1',
|
||||||
|
)
|
||||||
|
use1_instance = cf_conn.describe_stack_instance(
|
||||||
|
StackSetName="test_stack_set",
|
||||||
|
StackInstanceAccount='123456789012',
|
||||||
|
StackInstanceRegion='us-east-1',
|
||||||
|
)
|
||||||
|
|
||||||
|
usw2_instance['StackInstance']['ParameterOverrides'][0]['ParameterKey'].should.equal(param_overrides[0]['ParameterKey'])
|
||||||
|
usw2_instance['StackInstance']['ParameterOverrides'][0]['ParameterValue'].should.equal(param_overrides[0]['ParameterValue'])
|
||||||
|
usw2_instance['StackInstance']['ParameterOverrides'][1]['ParameterKey'].should.equal(param_overrides[1]['ParameterKey'])
|
||||||
|
usw2_instance['StackInstance']['ParameterOverrides'][1]['ParameterValue'].should.equal(param_overrides[1]['ParameterValue'])
|
||||||
|
|
||||||
|
usw1_instance['StackInstance']['ParameterOverrides'][0]['ParameterKey'].should.equal(param_overrides[0]['ParameterKey'])
|
||||||
|
usw1_instance['StackInstance']['ParameterOverrides'][0]['ParameterValue'].should.equal(param_overrides[0]['ParameterValue'])
|
||||||
|
usw1_instance['StackInstance']['ParameterOverrides'][1]['ParameterKey'].should.equal(param_overrides[1]['ParameterKey'])
|
||||||
|
usw1_instance['StackInstance']['ParameterOverrides'][1]['ParameterValue'].should.equal(param_overrides[1]['ParameterValue'])
|
||||||
|
|
||||||
|
use1_instance['StackInstance']['ParameterOverrides'].should.be.empty
|
||||||
|
|
||||||
|
|
||||||
|
@mock_cloudformation
|
||||||
|
def test_boto3_delete_stack_instances():
|
||||||
|
cf_conn = boto3.client('cloudformation', region_name='us-east-1')
|
||||||
|
cf_conn.create_stack_set(
|
||||||
|
StackSetName="test_stack_set",
|
||||||
|
TemplateBody=dummy_template_json,
|
||||||
|
)
|
||||||
|
cf_conn.create_stack_instances(
|
||||||
|
StackSetName="test_stack_set",
|
||||||
|
Accounts=['123456789012'],
|
||||||
|
Regions=['us-east-1', 'us-west-2'],
|
||||||
|
)
|
||||||
|
|
||||||
|
cf_conn.delete_stack_instances(
|
||||||
|
StackSetName="test_stack_set",
|
||||||
|
Accounts=['123456789012'],
|
||||||
|
Regions=['us-east-1'],
|
||||||
|
RetainStacks=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
cf_conn.list_stack_instances(StackSetName="test_stack_set")['Summaries'].should.have.length_of(1)
|
||||||
|
cf_conn.list_stack_instances(StackSetName="test_stack_set")['Summaries'][0]['Region'].should.equal(
|
||||||
|
'us-west-2')
|
||||||
|
|
||||||
|
|
||||||
|
@mock_cloudformation
|
||||||
|
def test_boto3_create_stack_instances():
|
||||||
|
cf_conn = boto3.client('cloudformation', region_name='us-east-1')
|
||||||
|
cf_conn.create_stack_set(
|
||||||
|
StackSetName="test_stack_set",
|
||||||
|
TemplateBody=dummy_template_json,
|
||||||
|
)
|
||||||
|
cf_conn.create_stack_instances(
|
||||||
|
StackSetName="test_stack_set",
|
||||||
|
Accounts=['123456789012'],
|
||||||
|
Regions=['us-east-1', 'us-west-2'],
|
||||||
|
)
|
||||||
|
|
||||||
|
cf_conn.list_stack_instances(StackSetName="test_stack_set")['Summaries'].should.have.length_of(2)
|
||||||
|
cf_conn.list_stack_instances(StackSetName="test_stack_set")['Summaries'][0]['Account'].should.equal(
|
||||||
|
'123456789012')
|
||||||
|
|
||||||
|
|
||||||
|
@mock_cloudformation
|
||||||
|
def test_boto3_create_stack_instances_with_param_overrides():
|
||||||
|
cf_conn = boto3.client('cloudformation', region_name='us-east-1')
|
||||||
|
param = [
|
||||||
|
{'ParameterKey': 'TagDescription', 'ParameterValue': 'StackSetValue'},
|
||||||
|
{'ParameterKey': 'TagName', 'ParameterValue': 'StackSetValue2'},
|
||||||
|
]
|
||||||
|
param_overrides = [
|
||||||
|
{'ParameterKey': 'TagDescription', 'ParameterValue': 'OverrideValue'},
|
||||||
|
{'ParameterKey': 'TagName', 'ParameterValue': 'OverrideValue2'}
|
||||||
|
]
|
||||||
|
cf_conn.create_stack_set(
|
||||||
|
StackSetName="test_stack_set",
|
||||||
|
TemplateBody=dummy_template_yaml_with_ref,
|
||||||
|
Parameters=param,
|
||||||
|
)
|
||||||
|
cf_conn.create_stack_instances(
|
||||||
|
StackSetName="test_stack_set",
|
||||||
|
Accounts=['123456789012'],
|
||||||
|
Regions=['us-east-1', 'us-west-2'],
|
||||||
|
ParameterOverrides=param_overrides,
|
||||||
|
)
|
||||||
|
usw2_instance = cf_conn.describe_stack_instance(
|
||||||
|
StackSetName="test_stack_set",
|
||||||
|
StackInstanceAccount='123456789012',
|
||||||
|
StackInstanceRegion='us-west-2',
|
||||||
|
)
|
||||||
|
|
||||||
|
usw2_instance['StackInstance']['ParameterOverrides'][0]['ParameterKey'].should.equal(param_overrides[0]['ParameterKey'])
|
||||||
|
usw2_instance['StackInstance']['ParameterOverrides'][1]['ParameterKey'].should.equal(param_overrides[1]['ParameterKey'])
|
||||||
|
usw2_instance['StackInstance']['ParameterOverrides'][0]['ParameterValue'].should.equal(param_overrides[0]['ParameterValue'])
|
||||||
|
usw2_instance['StackInstance']['ParameterOverrides'][1]['ParameterValue'].should.equal(param_overrides[1]['ParameterValue'])
|
||||||
|
|
||||||
|
|
||||||
|
@mock_cloudformation
|
||||||
|
def test_update_stack_set():
|
||||||
|
cf_conn = boto3.client('cloudformation', region_name='us-east-1')
|
||||||
|
param = [
|
||||||
|
{'ParameterKey': 'TagDescription', 'ParameterValue': 'StackSetValue'},
|
||||||
|
{'ParameterKey': 'TagName', 'ParameterValue': 'StackSetValue2'},
|
||||||
|
]
|
||||||
|
param_overrides = [
|
||||||
|
{'ParameterKey': 'TagDescription', 'ParameterValue': 'OverrideValue'},
|
||||||
|
{'ParameterKey': 'TagName', 'ParameterValue': 'OverrideValue2'}
|
||||||
|
]
|
||||||
|
cf_conn.create_stack_set(
|
||||||
|
StackSetName="test_stack_set",
|
||||||
|
TemplateBody=dummy_template_yaml_with_ref,
|
||||||
|
Parameters=param,
|
||||||
|
)
|
||||||
|
cf_conn.update_stack_set(
|
||||||
|
StackSetName='test_stack_set',
|
||||||
|
TemplateBody=dummy_template_yaml_with_ref,
|
||||||
|
Parameters=param_overrides,
|
||||||
|
)
|
||||||
|
stackset = cf_conn.describe_stack_set(StackSetName='test_stack_set')
|
||||||
|
|
||||||
|
stackset['StackSet']['Parameters'][0]['ParameterValue'].should.equal(param_overrides[0]['ParameterValue'])
|
||||||
|
stackset['StackSet']['Parameters'][1]['ParameterValue'].should.equal(param_overrides[1]['ParameterValue'])
|
||||||
|
stackset['StackSet']['Parameters'][0]['ParameterKey'].should.equal(param_overrides[0]['ParameterKey'])
|
||||||
|
stackset['StackSet']['Parameters'][1]['ParameterKey'].should.equal(param_overrides[1]['ParameterKey'])
|
||||||
|
|
||||||
|
|
||||||
|
@mock_cloudformation
|
||||||
|
def test_boto3_list_stack_set_operations():
|
||||||
|
cf_conn = boto3.client('cloudformation', region_name='us-east-1')
|
||||||
|
cf_conn.create_stack_set(
|
||||||
|
StackSetName="test_stack_set",
|
||||||
|
TemplateBody=dummy_template_json,
|
||||||
|
)
|
||||||
|
cf_conn.create_stack_instances(
|
||||||
|
StackSetName="test_stack_set",
|
||||||
|
Accounts=['123456789012'],
|
||||||
|
Regions=['us-east-1', 'us-west-2'],
|
||||||
|
)
|
||||||
|
cf_conn.update_stack_instances(
|
||||||
|
StackSetName="test_stack_set",
|
||||||
|
Accounts=['123456789012'],
|
||||||
|
Regions=['us-east-1', 'us-west-2'],
|
||||||
|
)
|
||||||
|
|
||||||
|
list_operation = cf_conn.list_stack_set_operations(StackSetName="test_stack_set")
|
||||||
|
list_operation['Summaries'].should.have.length_of(2)
|
||||||
|
list_operation['Summaries'][-1]['Action'].should.equal('UPDATE')
|
||||||
|
|
||||||
|
|
||||||
|
@mock_cloudformation
|
||||||
|
def test_boto3_delete_stack_set():
|
||||||
|
cf_conn = boto3.client('cloudformation', region_name='us-east-1')
|
||||||
|
cf_conn.create_stack_set(
|
||||||
|
StackSetName="test_stack_set",
|
||||||
|
TemplateBody=dummy_template_json,
|
||||||
|
)
|
||||||
|
cf_conn.delete_stack_set(StackSetName='test_stack_set')
|
||||||
|
|
||||||
|
cf_conn.describe_stack_set(StackSetName="test_stack_set")['StackSet']['Status'].should.equal(
|
||||||
|
'DELETED')
|
||||||
|
|
||||||
|
|
||||||
|
@mock_cloudformation
|
||||||
|
def test_boto3_create_stack_set():
|
||||||
|
cf_conn = boto3.client('cloudformation', region_name='us-east-1')
|
||||||
|
cf_conn.create_stack_set(
|
||||||
|
StackSetName="test_stack_set",
|
||||||
|
TemplateBody=dummy_template_json,
|
||||||
|
)
|
||||||
|
|
||||||
|
cf_conn.describe_stack_set(StackSetName="test_stack_set")['StackSet']['TemplateBody'].should.equal(
|
||||||
|
dummy_template_json)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_cloudformation
|
||||||
|
def test_boto3_create_stack_set_with_yaml():
|
||||||
|
cf_conn = boto3.client('cloudformation', region_name='us-east-1')
|
||||||
|
cf_conn.create_stack_set(
|
||||||
|
StackSetName="test_stack_set",
|
||||||
|
TemplateBody=dummy_template_yaml,
|
||||||
|
)
|
||||||
|
|
||||||
|
cf_conn.describe_stack_set(StackSetName="test_stack_set")['StackSet']['TemplateBody'].should.equal(
|
||||||
|
dummy_template_yaml)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_cloudformation
|
||||||
|
@mock_s3
|
||||||
|
def test_create_stack_set_from_s3_url():
|
||||||
|
s3 = boto3.client('s3')
|
||||||
|
s3_conn = boto3.resource('s3')
|
||||||
|
bucket = s3_conn.create_bucket(Bucket="foobar")
|
||||||
|
|
||||||
|
key = s3_conn.Object(
|
||||||
|
'foobar', 'template-key').put(Body=dummy_template_json)
|
||||||
|
key_url = s3.generate_presigned_url(
|
||||||
|
ClientMethod='get_object',
|
||||||
|
Params={
|
||||||
|
'Bucket': 'foobar',
|
||||||
|
'Key': 'template-key'
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
cf_conn = boto3.client('cloudformation', region_name='us-west-1')
|
||||||
|
cf_conn.create_stack_set(
|
||||||
|
StackSetName='stack_from_url',
|
||||||
|
TemplateURL=key_url,
|
||||||
|
)
|
||||||
|
cf_conn.describe_stack_set(StackSetName="stack_from_url")['StackSet']['TemplateBody'].should.equal(
|
||||||
|
dummy_template_json)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_cloudformation
|
||||||
|
def test_boto3_create_stack_set_with_ref_yaml():
|
||||||
|
cf_conn = boto3.client('cloudformation', region_name='us-east-1')
|
||||||
|
params = [
|
||||||
|
{'ParameterKey': 'TagDescription', 'ParameterValue': 'desc_ref'},
|
||||||
|
{'ParameterKey': 'TagName', 'ParameterValue': 'name_ref'},
|
||||||
|
]
|
||||||
|
cf_conn.create_stack_set(
|
||||||
|
StackSetName="test_stack",
|
||||||
|
TemplateBody=dummy_template_yaml_with_ref,
|
||||||
|
Parameters=params
|
||||||
|
)
|
||||||
|
|
||||||
|
cf_conn.describe_stack_set(StackSetName="test_stack")['StackSet']['TemplateBody'].should.equal(
|
||||||
|
dummy_template_yaml_with_ref)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_cloudformation
|
||||||
|
def test_boto3_describe_stack_set_params():
|
||||||
|
cf_conn = boto3.client('cloudformation', region_name='us-east-1')
|
||||||
|
params = [
|
||||||
|
{'ParameterKey': 'TagDescription', 'ParameterValue': 'desc_ref'},
|
||||||
|
{'ParameterKey': 'TagName', 'ParameterValue': 'name_ref'},
|
||||||
|
]
|
||||||
|
cf_conn.create_stack_set(
|
||||||
|
StackSetName="test_stack",
|
||||||
|
TemplateBody=dummy_template_yaml_with_ref,
|
||||||
|
Parameters=params
|
||||||
|
)
|
||||||
|
|
||||||
|
cf_conn.describe_stack_set(StackSetName="test_stack")['StackSet']['Parameters'].should.equal(
|
||||||
|
params)
|
||||||
|
|
||||||
|
|
||||||
@mock_cloudformation
|
@mock_cloudformation
|
||||||
def test_boto3_create_stack():
|
def test_boto3_create_stack():
|
||||||
|
Loading…
Reference in New Issue
Block a user