def import_template(migration_environment, aws_stack_name, template_path): """ Saves a template imported from AWS CloudFormation. :param path: The absolute path to the file which stores the template. :type path: str :param body: The body of the imported template. :type region: str or dict :raises: UnsupportedTemplateFileTypeError """ abs_template_path = os.path.join( migration_environment.environment_config.sceptre_dir, template_path) logging.getLogger(__name__).debug( "%s - Preparing to Import CloudFormation to %s", os.path.basename(template_path).split(".")[0], abs_template_path) response = migration_environment.connection_manager.call( service='cloudformation', command='get_template', kwargs={ 'StackName': aws_stack_name, 'TemplateStage': 'Original' }) _write_template( abs_template_path, _normalize_template_for_write(response['TemplateBody'], os.path.splitext(template_path)[1])) template = Template(abs_template_path, []) template.relative_template_path = template_path return template
def test_import_config__empty_stack(self, mock_isfile, mock_open, mock_print): self.migration_environment.connection_manager\ .call.return_value = {'Stacks': [ { } ]} mock_isfile.return_value = False fake_template = Template('fake-path', []) fake_template.relative_template_path = 'fake-relative-path' config.import_config(migration_environment=self.migration_environment, aws_stack_name="fake-aws-stack-name", config_path="environment-path/fake-stack", template=fake_template) mock_open.assert_called_with( "fake-spectre-dir/config/environment-path/fake-stack.yaml", 'w') mock_print.assert_has_calls([ call("template_path: fake-relative-path", file=mock_open.return_value.__enter__.return_value), call("stack_name: fake-aws-stack-name", file=mock_open.return_value.__enter__.return_value) ], any_order=False)
def setup_method(self, test_method): self.region = "region" self.bucket_name = "bucket_name" self.environment_path = "environment_path" self.stack_name = "stack_name" self.connection_manager = Mock(spec=ConnectionManager) self.connection_manager.create_bucket_lock = threading.Lock() self.template = Template(path="/folder/template.py", sceptre_user_data={})
def test_render_jinja_template_j2_environment_config(mock_environment, stack_group_config, expected_keys): filename = "vpc.j2" sceptre_user_data = {"vpc_id": "10.0.0.0/16"} template = Template(path=filename, sceptre_user_data=sceptre_user_data, stack_group_config=stack_group_config) jinja_template_dir = os.path.join( os.getcwd(), "tests/fixtures/templates" ) template._render_jinja_template( template_dir=jinja_template_dir, filename=filename, jinja_vars={"sceptre_user_data": sceptre_user_data} ) assert list(mock_environment.call_args.kwargs) == expected_keys
def test_render_jinja_template(filename, sceptre_user_data, expected): jinja_template_dir = os.path.join( os.getcwd(), "tests/fixtures/templates" ) template = Template(path=filename, sceptre_user_data=sceptre_user_data, stack_group_config={}) result = template._render_jinja_template( template_dir=jinja_template_dir, filename=filename, jinja_vars={"sceptre_user_data": sceptre_user_data} ) expected_yaml = yaml.safe_load(expected) result_yaml = yaml.safe_load(result) assert expected_yaml == result_yaml
def setup_method(self, test_method): self.patcher_connection_manager = patch( "sceptre.plan.actions.ConnectionManager") self.mock_ConnectionManager = self.patcher_connection_manager.start() self.stack = Stack(name='prod/app/stack', project_code=sentinel.project_code, template_path=sentinel.template_path, region=sentinel.region, profile=sentinel.profile, parameters={"key1": "val1"}, sceptre_user_data=sentinel.sceptre_user_data, hooks={}, s3_details=None, dependencies=sentinel.dependencies, role_arn=sentinel.role_arn, protected=False, tags={"tag1": "val1"}, external_name=sentinel.external_name, notifications=[sentinel.notification], on_failure=sentinel.on_failure, stack_timeout=sentinel.stack_timeout) self.actions = StackActions(self.stack) self.template = Template("fixtures/templates", self.stack.sceptre_user_data, self.actions.connection_manager, self.stack.s3_details) self.stack._template = self.template
def template(self): """ Returns the CloudFormation Template used to create the Stack. :returns: The Stack's template. :rtype: Template """ if self._template is None: if self.template_path: handler_config = { "type": "file", "path": self.template_path } else: handler_config = self.template_handler_config self._template = Template( name=self.name, handler_config=handler_config, sceptre_user_data=self.sceptre_user_data, stack_group_config=self.stack_group_config, s3_details=self.s3_details, connection_manager=self.connection_manager ) return self._template
def test_import_config__exists(self, mock_isfile): mock_isfile.return_value = True with pytest.raises(ImportFailureError): config.import_config( migration_environment=self.migration_environment, aws_stack_name="fake-aws-stack-name", config_path="environment-path/fake-stack", template=Template('fake-path', []))
def setup_method(self, test_method): self.region = "region" self.bucket_name = "bucket_name" self.stack_group_path = "stack_group_path" self.stack_name = "stack_name" connection_manager = Mock(spec=ConnectionManager) connection_manager.create_bucket_lock = threading.Lock() self.template = Template( name="template_name", handler_config={"type": "file", "path": "/folder/template.py"}, sceptre_user_data={}, stack_group_config={ "project_path": "projects" }, connection_manager=connection_manager, )
def test_initialise_template_default_handler_type(self): template = Template( name="template_name", handler_config={"path": "/folder/template.py"}, sceptre_user_data={}, stack_group_config={}, connection_manager={}, ) assert template.handler_config == {"type": "file", "path": "/folder/template.py"}
def template(self): """ Returns the CloudFormation Template used to create the Stack. :returns: The Stack's template. :rtype: str """ if self._template is None: self._template = Template( path=self.template_path, sceptre_user_data=self.sceptre_user_data, s3_details=self.s3_details, connection_manager=self.connection_manager) return self._template
def template(self): """ Returns the CloudFormation Template used to create the Stack. :returns: The Stack's template. :rtype: str """ self.connection_manager = ConnectionManager( self.region, self.profile, self.external_name ) if self._template is None: self._template = Template( path=self.template_path, sceptre_user_data=self.sceptre_user_data, s3_details=self.s3_details, connection_manager=self.connection_manager ) return self._template
def __init__(self, connection_manager, environment_config, import_stack_list=[]): self.logger = logging.getLogger(__name__) self.connection_manager = connection_manager self.environment_config = environment_config self.import_stack_list = import_stack_list self._reversed_env_config = { str(v): "{{ var." + str(k) + " }}" for k, v in self.environment_config['user_variables'].items() } self._config_re_pattern = '|'.join([ re.escape(str(config_value)) for config_value in self.environment_config['user_variables'].values() ]) self._reverse_resolver_list = None self.config_path = "" self.aws_stack_name = "" self.aws_stack = {} self.template = Template("", {})
def resolve(self): """ Retrieves the parameter value from SSM Parameter Store. :returns: parameter value :rtype: str """ if self._resolver_started: return self._resolved_value else: self._resolver_started = True if self.argument: # Generate template data using the sceptre template submodule if self._template is None: self._template = Template( path=self.argument, sceptre_user_data=self.stack.sceptre_user_data, s3_details=self.stack.s3_details, connection_manager=self.stack.connection_manager) self._resolved_value = self._template.body return self._resolved_value else: raise ValueError("No template path given.")
class TestTemplate(object): def setup_method(self, test_method): self.region = "region" self.bucket_name = "bucket_name" self.stack_group_path = "stack_group_path" self.stack_name = "stack_name" connection_manager = Mock(spec=ConnectionManager) connection_manager.create_bucket_lock = threading.Lock() self.template = Template( path="/folder/template.py", sceptre_user_data={}, stack_group_config={}, connection_manager=connection_manager, ) def test_initialise_template(self): assert self.template.path == "/folder/template.py" assert self.template.name == "template" assert self.template.sceptre_user_data == {} assert self.template._body is None def test_repr(self): representation = self.template.__repr__() assert representation == "sceptre.template.Template(" \ "name='template', path='/folder/template.py'"\ ", sceptre_user_data={}, s3_details=None)" def test_body_with_cache(self): self.template._body = sentinel.body body = self.template.body assert body == sentinel.body @freeze_time("2012-01-01") @patch("sceptre.template.Template._bucket_exists") def test_upload_to_s3_with_valid_s3_details(self, mock_bucket_exists): self.template._body = '{"template": "mock"}' mock_bucket_exists.return_value = True self.template.s3_details = { "bucket_name": "bucket-name", "bucket_key": "bucket-key" } self.template.upload_to_s3() get_bucket_location_call, put_object_call = self.template.connection_manager.call.call_args_list get_bucket_location_call.assert_called_once_with( service="s3", command="get_bucket_location", kwargs={ "Bucket": "bucket-name" } ) put_object_call.assert_called_once_with( service="s3", command="put_object", kwargs={ "Bucket": "bucket-name", "Key": "bucket-key", "Body": '{"template": "mock"}', "ServerSideEncryption": "AES256" } ) def test_domain_from_region(self): assert self.template._domain_from_region("us-east-1") == "com" assert self.template._domain_from_region("cn-north-1") == "com.cn" assert self.template._domain_from_region("cn-northwest-1") == "com.cn" def test_bucket_exists_with_bucket_that_exists(self): # connection_manager.call doesn't raise an exception, mimicing the # behaviour when head_bucket successfully executes. self.template.s3_details = { "bucket_name": "bucket-name", "bucket_key": "bucket-key" } assert self.template._bucket_exists() is True def test_create_bucket_with_unreadable_bucket(self): self.template.connection_manager.region = "eu-west-1" self.template.s3_details = { "bucket_name": "bucket-name", "bucket_key": "bucket-key" } self.template.connection_manager.call.side_effect = ClientError( { "Error": { "Code": 500, "Message": "Bucket Unreadable" } }, sentinel.operation ) with pytest.raises(ClientError) as e: self.template._create_bucket() assert e.value.response["Error"]["Code"] == 500 assert e.value.response["Error"]["Message"] == "Bucket Unreadable" def test_bucket_exists_with_non_existent_bucket(self): # connection_manager.call is called twice, and should throw the # Not Found ClientError only for the first call. self.template.s3_details = { "bucket_name": "bucket-name", "bucket_key": "bucket-key" } self.template.connection_manager.call.side_effect = [ ClientError( { "Error": { "Code": 404, "Message": "Not Found" } }, sentinel.operation ), None ] existance = self.template._bucket_exists() assert existance is False def test_create_bucket_in_us_east_1(self): # connection_manager.call is called twice, and should throw the # Not Found ClientError only for the first call. self.template.connection_manager.region = "us-east-1" self.template.s3_details = { "bucket_name": "bucket-name", "bucket_key": "bucket-key" } self.template._create_bucket() self.template.connection_manager.call.assert_any_call( service="s3", command="create_bucket", kwargs={"Bucket": "bucket-name"} ) @patch("sceptre.template.Template.upload_to_s3") def test_get_boto_call_parameter_with_s3_details(self, mock_upload_to_s3): # self.stack._template = Mock(spec=Template) mock_upload_to_s3.return_value = sentinel.template_url self.template.s3_details = { "bucket_name": sentinel.bucket_name, "bucket_key": sentinel.bucket_key } boto_parameter = self.template.get_boto_call_parameter() assert boto_parameter == {"TemplateURL": sentinel.template_url} def test_get_template_details_without_upload(self): self.template.s3_details = None self.template._body = sentinel.body boto_parameter = self.template.get_boto_call_parameter() assert boto_parameter == {"TemplateBody": sentinel.body} def test_body_with_json_template(self): self.template.name = "vpc" self.template.path = os.path.join( os.getcwd(), "tests/fixtures/templates/vpc.json" ) output = self.template.body output_dict = json.loads(output) with open("tests/fixtures/templates/compiled_vpc.json", "r") as f: expected_output_dict = json.loads(f.read()) assert output_dict == expected_output_dict def test_body_with_yaml_template(self): self.template.name = "vpc" self.template.path = os.path.join( os.getcwd(), "tests/fixtures/templates/vpc.yaml" ) output = self.template.body output_dict = yaml.safe_load(output) with open("tests/fixtures/templates/compiled_vpc.json", "r") as f: expected_output_dict = json.loads(f.read()) assert output_dict == expected_output_dict def test_body_with_generic_template(self): self.template.name = "vpc" self.template.path = os.path.join( os.getcwd(), "tests/fixtures/templates/vpc.template" ) output = self.template.body output_dict = json.loads(output) with open("tests/fixtures/templates/compiled_vpc.json", "r") as f: expected_output_dict = json.loads(f.read()) assert output_dict == expected_output_dict def test_body_with_chdir_template(self): self.template.sceptre_user_data = None self.template.name = "chdir" current_dir = os.getcwd() self.template.path = os.path.join( os.getcwd(), "tests/fixtures/templates/chdir.py" ) try: json.loads(self.template.body) except ValueError: assert False finally: os.chdir(current_dir) def test_body_with_missing_file(self): self.template.path = "incorrect/template/path.py" with pytest.raises(IOError): self.template.body def test_body_with_python_template(self): self.template.sceptre_user_data = None self.template.name = "vpc" self.template.path = os.path.join( os.getcwd(), "tests/fixtures/templates/vpc.py" ) actual_output = json.loads(self.template.body) with open("tests/fixtures/templates/compiled_vpc.json", "r") as f: expected_output = json.loads(f.read()) assert actual_output == expected_output def test_body_with_python_template_with_sgt(self): self.template.sceptre_user_data = None self.template.name = "vpc_sgt" self.template.path = os.path.join( os.getcwd(), "tests/fixtures/templates/vpc_sgt.py" ) actual_output = json.loads(self.template.body) with open("tests/fixtures/templates/compiled_vpc.json", "r") as f: expected_output = json.loads(f.read()) assert actual_output == expected_output def test_body_injects_sceptre_user_data(self): self.template.sceptre_user_data = { "cidr_block": "10.0.0.0/16" } self.template.name = "vpc_sud" self.template.path = os.path.join( os.getcwd(), "tests/fixtures/templates/vpc_sud.py" ) actual_output = json.loads(self.template.body) with open("tests/fixtures/templates/compiled_vpc_sud.json", "r") as f: expected_output = json.loads(f.read()) assert actual_output == expected_output def test_body_injects_sceptre_user_data_incorrect_function(self): self.template.sceptre_user_data = { "cidr_block": "10.0.0.0/16" } self.template.name = "vpc_sud_incorrect_function" self.template.path = os.path.join( os.getcwd(), "tests/fixtures/templates/vpc_sud_incorrect_function.py" ) with pytest.raises(TemplateSceptreHandlerError): self.template.body def test_body_injects_sceptre_user_data_incorrect_handler(self): self.template.sceptre_user_data = { "cidr_block": "10.0.0.0/16" } self.template.name = "vpc_sud_incorrect_handler" self.template.path = os.path.join( os.getcwd(), "tests/fixtures/templates/vpc_sud_incorrect_handler.py" ) with pytest.raises(TypeError): self.template.body def test_body_with_incorrect_filetype(self): self.template.path = ( "path/to/something.ext" ) with pytest.raises(UnsupportedTemplateFileTypeError): self.template.body
class TestTemplate(object): def setup_method(self, test_method): self.region = "region" self.bucket_name = "bucket_name" self.environment_path = "environment_path" self.stack_name = "stack_name" self.connection_manager = Mock(spec=ConnectionManager) self.connection_manager.create_bucket_lock = threading.Lock() self.template = Template(path="/folder/template.py", sceptre_user_data={}) def test_initialise_template(self): assert self.template.path == "/folder/template.py" assert self.template.name == "template" assert self.template.sceptre_user_data == {} assert self.template._body is None def test_repr(self): representation = self.template.__repr__() assert representation == "sceptre.template.Template(" \ "name='template', path='/folder/template.py'"\ ", sceptre_user_data={})" def test_body_with_cache(self): self.template._body = sentinel.body body = self.template.body assert body == sentinel.body @freeze_time("2012-01-01") @patch("sceptre.template.Template._bucket_exists") def test_upload_to_s3_with_valid_arguments(self, mock_bucket_exists): self.template._body = '{"template": "mock"}' mock_bucket_exists.return_value = True url = self.template.upload_to_s3( region="eu-west-1", bucket_name="bucket-name", key_prefix="/prefix/", environment_path="environment/path", stack_name="stack-name", connection_manager=self.connection_manager) expected_template_key = ("prefix/eu-west-1/environment/path/" "stack-name-2012-01-01-00-00-00-000000Z.json") self.connection_manager.call.assert_called_once_with( service="s3", command="put_object", kwargs={ "Bucket": "bucket-name", "Key": expected_template_key, "Body": '{"template": "mock"}', "ServerSideEncryption": "AES256" }) assert url == "https://bucket-name.s3.amazonaws.com/{0}".format( expected_template_key) def test_bucket_exists_with_bucket_that_exists(self): # connection_manager.call doesn't raise an exception, mimicing the # behaviour when head_bucket successfully executes. self.template._bucket_exists("bucket_name", self.connection_manager) def test_create_bucket_with_unreadable_bucket(self): self.connection_manager.call.side_effect = ClientError( {"Error": { "Code": 500, "Message": "Bucket Unreadable" }}, sentinel.operation) with pytest.raises(ClientError) as e: self.template._create_bucket("region", "bucket_name", self.connection_manager) assert e.value.response["Error"]["Code"] == 500 assert e.value.response["Error"]["Message"] == "Bucket Unreadable" def test_bucket_exists_with_non_existent_bucket(self): # connection_manager.call is called twice, and should throw the # Not Found ClientError only for the first call. self.connection_manager.call.side_effect = [ ClientError({"Error": { "Code": 404, "Message": "Not Found" }}, sentinel.operation), None ] existance = self.template._bucket_exists(self.bucket_name, self.connection_manager) assert existance is False def test_create_bucket_in_us_east_1(self): # connection_manager.call is called twice, and should throw the # Not Found ClientError only for the first call. self.template._create_bucket("us-east-1", self.bucket_name, self.connection_manager) self.connection_manager.call.assert_any_call( service="s3", command="create_bucket", kwargs={"Bucket": self.bucket_name}) def test_body_with_json_template(self): self.template.name = "vpc" self.template.path = os.path.join(os.getcwd(), "tests/fixtures/templates/vpc.json") output = self.template.body output_dict = json.loads(output) with open("tests/fixtures/templates/compiled_vpc.json", "r") as f: expected_output_dict = json.loads(f.read()) assert output_dict == expected_output_dict def test_body_with_yaml_template(self): self.template.name = "vpc" self.template.path = os.path.join(os.getcwd(), "tests/fixtures/templates/vpc.yaml") output = self.template.body output_dict = yaml.load(output) with open("tests/fixtures/templates/compiled_vpc.json", "r") as f: expected_output_dict = json.loads(f.read()) assert output_dict == expected_output_dict def test_body_with_missing_file(self): self.template.path = "incorrect/template/path.py" with pytest.raises(IOError): self.template.body def test_body_with_python_template(self): self.template.sceptre_user_data = None self.template.name = "vpc" self.template.path = os.path.join(os.getcwd(), "tests/fixtures/templates/vpc.py") actual_output = json.loads(self.template.body) with open("tests/fixtures/templates/compiled_vpc.json", "r") as f: expected_output = json.loads(f.read()) assert actual_output == expected_output def test_body_with_python_template_with_sgt(self): self.template.sceptre_user_data = None self.template.name = "vpc_sgt" self.template.path = os.path.join( os.getcwd(), "tests/fixtures/templates/vpc_sgt.py") actual_output = json.loads(self.template.body) with open("tests/fixtures/templates/compiled_vpc.json", "r") as f: expected_output = json.loads(f.read()) assert actual_output == expected_output def test_body_injects_sceptre_user_data(self): self.template.sceptre_user_data = {"cidr_block": "10.0.0.0/16"} self.template.name = "vpc_sud" self.template.path = os.path.join( os.getcwd(), "tests/fixtures/templates/vpc_sud.py") actual_output = json.loads(self.template.body) with open("tests/fixtures/templates/compiled_vpc_sud.json", "r") as f: expected_output = json.loads(f.read()) assert actual_output == expected_output def test_body_injects_sceptre_user_data_incorrect_function(self): self.template.sceptre_user_data = {"cidr_block": "10.0.0.0/16"} self.template.name = "vpc_sud_incorrect_function" self.template.path = os.path.join( os.getcwd(), "tests/fixtures/templates/vpc_sud_incorrect_function.py") with pytest.raises(TemplateSceptreHandlerError): self.template.body def test_body_injects_sceptre_user_data_incorrect_handler(self): self.template.sceptre_user_data = {"cidr_block": "10.0.0.0/16"} self.template.name = "vpc_sud_incorrect_handler" self.template.path = os.path.join( os.getcwd(), "tests/fixtures/templates/vpc_sud_incorrect_handler.py") with pytest.raises(TypeError): self.template.body def test_body_with_incorrect_filetype(self): self.template.path = ("path/to/something.ext") with pytest.raises(UnsupportedTemplateFileTypeError): self.template.body