From 441c27e66a11801af911fe4d6124f4846e8d47ed Mon Sep 17 00:00:00 2001 From: Garison Draper Date: Fri, 20 Oct 2017 16:13:43 -0700 Subject: [PATCH 01/11] inital s3 bucket creation tagging from context --- stacker/actions/base.py | 3 ++- stacker/hooks/aws_lambda.py | 2 +- stacker/util.py | 10 +++++++++- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/stacker/actions/base.py b/stacker/actions/base.py index 36c69209d..7f58cf4f6 100644 --- a/stacker/actions/base.py +++ b/stacker/actions/base.py @@ -86,7 +86,8 @@ def bucket_region(self): def ensure_cfn_bucket(self): """The CloudFormation bucket where templates will be stored.""" - ensure_s3_bucket(self.s3_conn, self.bucket_name, self.bucket_region) + ensure_s3_bucket(self.s3_conn, self.bucket_name, self.bucket_region, + self.context) def stack_template_url(self, blueprint): return stack_template_url( diff --git a/stacker/hooks/aws_lambda.py b/stacker/hooks/aws_lambda.py index 245d1bff2..978972901 100644 --- a/stacker/hooks/aws_lambda.py +++ b/stacker/hooks/aws_lambda.py @@ -490,7 +490,7 @@ def create_template(self): session = get_session(bucket_region) s3_client = session.client('s3') - ensure_s3_bucket(s3_client, bucket_name, bucket_region) + ensure_s3_bucket(s3_client, bucket_name, bucket_region, context) prefix = kwargs.get('prefix', '') diff --git a/stacker/util.py b/stacker/util.py index 3301d4b9c..5d7a354b7 100644 --- a/stacker/util.py +++ b/stacker/util.py @@ -16,6 +16,8 @@ from collections import OrderedDict import botocore.client +from git import Repo +import stacker.actions.build import botocore.exceptions import dateutil import yaml @@ -503,7 +505,7 @@ def s3_bucket_location_constraint(region): return region -def ensure_s3_bucket(s3_client, bucket_name, bucket_region): +def ensure_s3_bucket(s3_client, bucket_name, bucket_region, context): """Ensure an s3 bucket exists, if it does not then create it. Args: @@ -512,6 +514,9 @@ def ensure_s3_bucket(s3_client, bucket_name, bucket_region): bucket_name (str): The bucket being checked/created. bucket_region (str, optional): The region to create the bucket in. If not provided, will be determined by s3_client's region. + context (:class:`stacker.context.Context`): context instance, used to + get tags from the stacker run + """ try: s3_client.head_bucket(Bucket=bucket_name) @@ -526,7 +531,10 @@ def ensure_s3_bucket(s3_client, bucket_name, bucket_region): create_args["CreateBucketConfiguration"] = { "LocationConstraint": location_constraint } + tagset = stacker.actions.build.build_stack_tags(context) s3_client.create_bucket(**create_args) + s3_client.put_bucket_tagging(Bucket=bucket_name, + Tagging={'TagSet': tagset}) elif e.response['Error']['Message'] == "Forbidden": logger.exception("Access denied for bucket %s. Did " + "you remember to use a globally unique name?", From 4f9d494e9e2243b7bca1c4807b36ff8eaa854086 Mon Sep 17 00:00:00 2001 From: Garison Draper Date: Fri, 20 Oct 2017 16:31:01 -0700 Subject: [PATCH 02/11] added help comments and set to update tags on every run --- stacker/util.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/stacker/util.py b/stacker/util.py index 5d7a354b7..643277758 100644 --- a/stacker/util.py +++ b/stacker/util.py @@ -515,11 +515,18 @@ def ensure_s3_bucket(s3_client, bucket_name, bucket_region, context): bucket_region (str, optional): The region to create the bucket in. If not provided, will be determined by s3_client's region. context (:class:`stacker.context.Context`): context instance, used to - get tags from the stacker run + set tags on the S3 bucket created from the stacker config """ try: + # Checking is bucket exists s3_client.head_bucket(Bucket=bucket_name) + # pulling tags from context + tagset = stacker.actions.build.build_stack_tags(context) + # setting tags on every run - must have permission to perform + # the s3:PutBucketTagging action + s3_client.put_bucket_tagging(Bucket=bucket_name, + Tagging={'TagSet': tagset}) except botocore.exceptions.ClientError as e: if e.response['Error']['Message'] == "Not Found": logger.debug("Creating bucket %s.", bucket_name) @@ -531,8 +538,11 @@ def ensure_s3_bucket(s3_client, bucket_name, bucket_region, context): create_args["CreateBucketConfiguration"] = { "LocationConstraint": location_constraint } + # pulling tags from context tagset = stacker.actions.build.build_stack_tags(context) s3_client.create_bucket(**create_args) + # setting tags on every run - must have permission to perform + # the s3:PutBucketTagging action s3_client.put_bucket_tagging(Bucket=bucket_name, Tagging={'TagSet': tagset}) elif e.response['Error']['Message'] == "Forbidden": From 134d323d52a1ab38566c3d78773a24190e391cf0 Mon Sep 17 00:00:00 2001 From: Garison Draper Date: Fri, 20 Oct 2017 16:54:19 -0700 Subject: [PATCH 03/11] updating documentation --- docs/config.rst | 18 +++++++++++++----- stacker/util.py | 4 ++-- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/docs/config.rst b/docs/config.rst index 1fb90a337..0e24c9182 100644 --- a/docs/config.rst +++ b/docs/config.rst @@ -236,12 +236,18 @@ the build action:: Tags ---- -CloudFormation supports arbitrary key-value pair tags. All stack-level, including automatically created tags, are -propagated to resources that AWS CloudFormation supports. See `AWS CloudFormation Resource Tags Type`_ for more details. -If no tags are specified, the `stacker_namespace` tag is applied to your stack with the value of `namespace` as the -tag value. +Verious resources in AWS support arbitrary key-value pair tags. You can set +the `tags` Top Level Keyword to populate tags on all Resources that support +that feature. The S3 bucket created by stacker for CFN uploads and all +Cloudformation stack-level resouces, including automatically created tags, +are propagated to resources that AWS CloudFormation supports. See +`AWS CloudFormation Resource Tags Type`_ for more details. -If you prefer to apply a custom set of tags, specify the top-level keyword `tags` as a map. Example:: +If no tags are specified, the `stacker_namespace` tag is applied to your stack +with the value of `namespace` as the tag value. + +If you prefer to apply a custom set of tags, specify the top-level keyword +`tags` as a map. Example:: tags: "hello": world @@ -253,6 +259,8 @@ map for the top-level keyword:: tags: {} +Tags are updated on every stacker run + .. _`AWS CloudFormation Resource Tags Type`: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-resource-tags.html Mappings diff --git a/stacker/util.py b/stacker/util.py index 643277758..2cf72fc8a 100644 --- a/stacker/util.py +++ b/stacker/util.py @@ -514,8 +514,8 @@ def ensure_s3_bucket(s3_client, bucket_name, bucket_region, context): bucket_name (str): The bucket being checked/created. bucket_region (str, optional): The region to create the bucket in. If not provided, will be determined by s3_client's region. - context (:class:`stacker.context.Context`): context instance, used to - set tags on the S3 bucket created from the stacker config + context (:class:`stacker.context.Context`): The stacker context, used + set the S3 bucket tags from the stacker config """ try: From e99e8eb0f8b5177f8e3872af2f8295a91a94410d Mon Sep 17 00:00:00 2001 From: Garison Draper Date: Fri, 20 Oct 2017 16:56:01 -0700 Subject: [PATCH 04/11] spelling is hard --- docs/config.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/config.rst b/docs/config.rst index 0e24c9182..fdce116ba 100644 --- a/docs/config.rst +++ b/docs/config.rst @@ -236,10 +236,10 @@ the build action:: Tags ---- -Verious resources in AWS support arbitrary key-value pair tags. You can set +Various resources in AWS support arbitrary key-value pair tags. You can set the `tags` Top Level Keyword to populate tags on all Resources that support -that feature. The S3 bucket created by stacker for CFN uploads and all -Cloudformation stack-level resouces, including automatically created tags, +that feature. The S3 bucket created by stacker for CloudFormation uploads and +all CloudFormation stack-level resources, including automatically created tags, are propagated to resources that AWS CloudFormation supports. See `AWS CloudFormation Resource Tags Type`_ for more details. From f71fc6ea998a2ee16add18c5b43bd46226910a6f Mon Sep 17 00:00:00 2001 From: Garison Draper Date: Mon, 23 Oct 2017 14:02:36 -0700 Subject: [PATCH 05/11] added TLK for bucket_tags w/ failback method to tags function if not set --- docs/config.rst | 43 +++++++++++++++++++++++++----- stacker/config/__init__.py | 2 ++ stacker/context.py | 16 +++++++++++ stacker/tests/actions/test_base.py | 33 +++++++++++++++++++++++ stacker/util.py | 29 +++++++++++++------- 5 files changed, 107 insertions(+), 16 deletions(-) diff --git a/docs/config.rst b/docs/config.rst index fdce116ba..ed3ecbb69 100644 --- a/docs/config.rst +++ b/docs/config.rst @@ -90,6 +90,33 @@ See the `CloudFormation Limits Reference`_. .. _`CloudFormation Limits Reference`: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cloudformation-limits.html + +S3 Bucket tags +---- + +Various resources in AWS support arbitrary key-value pair tags. You can set +the `bucket_tags` Top Level Keyword to populate tags on all S3 buckets Staker +attempts to create for CloudFormation template uploads, inclduing the S3 bucket +created by the aws_lambda pre-hook. + +If bucket_tags is not set in your Configuration, stacker will fallback to the +method used to determine tags in your config by the `tags` top level keyword. +The `bucket_tags` keyword takes precedence over `tags` when applying. Example:: + + bucket_tags: + "hello": world + "my_tag:with_colons_in_key": ${dynamic_tag_value_from_my_env} + simple_tag: simple value + +If you prefer to have no tags applied to your stacks (versus the default tags +that stacker applies), specify an empty map for the top-level keyword:: + + bucket_tags: {} + +Tags updates get applied on every stacker run + +.. _`AWS CloudFormation Resource Tags Type`: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-resource-tags.html + Module Paths ------------ When setting the ``classpath`` for blueprints/hooks, it is sometimes desirable to @@ -237,29 +264,31 @@ Tags ---- Various resources in AWS support arbitrary key-value pair tags. You can set -the `tags` Top Level Keyword to populate tags on all Resources that support -that feature. The S3 bucket created by stacker for CloudFormation uploads and -all CloudFormation stack-level resources, including automatically created tags, -are propagated to resources that AWS CloudFormation supports. See -`AWS CloudFormation Resource Tags Type`_ for more details. +the `tags` Top Level Keyword to populate tags on all Resources that Staker +attempts to create via CloudFormation. All CloudFormation stack-level resources, +including automatically created tags, are propagated to resources that AWS +CloudFormation supports. See `AWS CloudFormation Resource Tags Type`_ for +more details. If no tags are specified, the `stacker_namespace` tag is applied to your stack with the value of `namespace` as the tag value. If you prefer to apply a custom set of tags, specify the top-level keyword -`tags` as a map. Example:: +`tags` as a map. The `stacker_namespace` tag will be automaticly added as well +to help identify resources created by Stacker. Example:: tags: "hello": world "my_tag:with_colons_in_key": ${dynamic_tag_value_from_my_env} simple_tag: simple value + If you prefer to have no tags applied to your stacks (versus the default tags that stacker applies), specify an empty map for the top-level keyword:: tags: {} -Tags are updated on every stacker run +Tags updates get applied on every stacker run .. _`AWS CloudFormation Resource Tags Type`: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-resource-tags.html diff --git a/stacker/config/__init__.py b/stacker/config/__init__.py index fe1966620..471403ed9 100644 --- a/stacker/config/__init__.py +++ b/stacker/config/__init__.py @@ -351,6 +351,8 @@ class Config(Model): tags = DictType(StringType, serialize_when_none=False) + bucket_tags = DictType(StringType, serialize_when_none=False) + mappings = DictType( DictType(DictType(StringType)), serialize_when_none=False) diff --git a/stacker/context.py b/stacker/context.py index 3bcc31762..5bc0ad1ce 100644 --- a/stacker/context.py +++ b/stacker/context.py @@ -97,11 +97,27 @@ def upload_templates_to_s3(self): def tags(self): tags = self.config.tags if tags is not None: + if "stacker_namespace" in tags: + return tags + tags["stacker_namespace"] = self.namespace return tags if self.namespace: return {"stacker_namespace": self.namespace} return {} + @property + def s3_bucket_tags(self): + s3_bucket_tags = self.config.bucket_tags + if s3_bucket_tags is not None: + return s3_bucket_tags + else: + s3_bucket_tags = self.config.tags + if s3_bucket_tags is not None: + return s3_bucket_tags + if self.namespace: + return {"stacker_namespace": self.namespace} + return {} + @property def _base_fqn(self): return self.namespace.replace(".", "-").lower() diff --git a/stacker/tests/actions/test_base.py b/stacker/tests/actions/test_base.py index 446b07b2e..9c86b1245 100644 --- a/stacker/tests/actions/test_base.py +++ b/stacker/tests/actions/test_base.py @@ -42,6 +42,17 @@ def test_ensure_cfn_bucket_exists(self): "Bucket": ANY, } ) + stubber.add_response( + "put_bucket_tagging", + service_response={}, + expected_params={ + "Bucket": ANY, + "Tagging": { + "TagSet": [ + {"Key": "stacker_namespace", + "Value": u"mynamespace"}]} + } + ) with stubber: action.ensure_cfn_bucket() @@ -65,6 +76,17 @@ def test_ensure_cfn_bucket_doesnt_exist_us_east(self): "Bucket": ANY, } ) + stubber.add_response( + "put_bucket_tagging", + service_response={}, + expected_params={ + "Bucket": ANY, + "Tagging": { + "TagSet": [ + {"Key": "stacker_namespace", + "Value": u"mynamespace"}]} + } + ) with stubber: action.ensure_cfn_bucket() @@ -91,6 +113,17 @@ def test_ensure_cfn_bucket_doesnt_exist_us_west(self): } } ) + stubber.add_response( + "put_bucket_tagging", + service_response={}, + expected_params={ + "Bucket": ANY, + "Tagging": { + "TagSet": [ + {"Key": "stacker_namespace", + "Value": u"mynamespace"}]} + } + ) with stubber: action.ensure_cfn_bucket() diff --git a/stacker/util.py b/stacker/util.py index 2cf72fc8a..49ffeb230 100644 --- a/stacker/util.py +++ b/stacker/util.py @@ -17,7 +17,6 @@ import botocore.client from git import Repo -import stacker.actions.build import botocore.exceptions import dateutil import yaml @@ -521,8 +520,8 @@ def ensure_s3_bucket(s3_client, bucket_name, bucket_region, context): try: # Checking is bucket exists s3_client.head_bucket(Bucket=bucket_name) - # pulling tags from context - tagset = stacker.actions.build.build_stack_tags(context) + # pulling tags from s3_bucket_tags function + tagset = _s3_bucket_tags(context) # setting tags on every run - must have permission to perform # the s3:PutBucketTagging action s3_client.put_bucket_tagging(Bucket=bucket_name, @@ -538,8 +537,8 @@ def ensure_s3_bucket(s3_client, bucket_name, bucket_region, context): create_args["CreateBucketConfiguration"] = { "LocationConstraint": location_constraint } - # pulling tags from context - tagset = stacker.actions.build.build_stack_tags(context) + # pulling tags from s3_bucket_tags function + tagset = _s3_bucket_tags(context) s3_client.create_bucket(**create_args) # setting tags on every run - must have permission to perform # the s3:PutBucketTagging action @@ -555,6 +554,19 @@ def ensure_s3_bucket(s3_client, bucket_name, bucket_region, context): bucket_name, e.response) raise +def _s3_bucket_tags(context): + """Returns the tags to be applied for a S3 bucket. + + Args: + context (:class:`stacker.context.Context`): The stacker context, used + set the S3 bucket tags from the stacker config + + Returns: + List of dictionaries containing tags to apply to that bucket. + """ + return [ + {'Key': t[0], 'Value': t[1]} for t in context.s3_bucket_tags.items()] + class Extractor(object): """Base class for extractors.""" @@ -625,10 +637,9 @@ def extension(): return '.zip' -class SourceProcessor(object): - """Makes remote python package sources available in current environment.""" - - ISO8601_FORMAT = '%Y%m%dT%H%M%SZ' +class SourceProcessor(): + """Makes remote python package sources available in the running python + environment.""" def __init__(self, sources, stacker_cache_dir=None): """ From cda591b7145dc0f31215f34e28c0ba54e9258f42 Mon Sep 17 00:00:00 2001 From: Garison Draper Date: Mon, 6 Nov 2017 19:17:25 -0800 Subject: [PATCH 06/11] removed last issue 496 items - PR is only for issue 495 now --- docs/config.rst | 6 ++---- stacker/context.py | 3 --- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/docs/config.rst b/docs/config.rst index ed3ecbb69..1a4da6546 100644 --- a/docs/config.rst +++ b/docs/config.rst @@ -113,9 +113,8 @@ that stacker applies), specify an empty map for the top-level keyword:: bucket_tags: {} -Tags updates get applied on every stacker run +S3 Bucket Tags updates get applied on every stacker run -.. _`AWS CloudFormation Resource Tags Type`: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-resource-tags.html Module Paths ------------ @@ -274,8 +273,7 @@ If no tags are specified, the `stacker_namespace` tag is applied to your stack with the value of `namespace` as the tag value. If you prefer to apply a custom set of tags, specify the top-level keyword -`tags` as a map. The `stacker_namespace` tag will be automaticly added as well -to help identify resources created by Stacker. Example:: +`tags` as a map. Example:: tags: "hello": world diff --git a/stacker/context.py b/stacker/context.py index 5bc0ad1ce..d76346652 100644 --- a/stacker/context.py +++ b/stacker/context.py @@ -97,9 +97,6 @@ def upload_templates_to_s3(self): def tags(self): tags = self.config.tags if tags is not None: - if "stacker_namespace" in tags: - return tags - tags["stacker_namespace"] = self.namespace return tags if self.namespace: return {"stacker_namespace": self.namespace} From c9abbc98b3e0587e8fa7501867dbf99124d05270 Mon Sep 17 00:00:00 2001 From: Garison Draper Date: Thu, 9 Nov 2017 06:53:08 -0800 Subject: [PATCH 07/11] fixing E302 and F811 introduced when rebased from master --- stacker/util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stacker/util.py b/stacker/util.py index 49ffeb230..c27212bf5 100644 --- a/stacker/util.py +++ b/stacker/util.py @@ -20,7 +20,6 @@ import botocore.exceptions import dateutil import yaml -from git import Repo from yaml.constructor import ConstructorError from yaml.nodes import MappingNode @@ -554,6 +553,7 @@ def ensure_s3_bucket(s3_client, bucket_name, bucket_region, context): bucket_name, e.response) raise + def _s3_bucket_tags(context): """Returns the tags to be applied for a S3 bucket. From 7b9c9b8e10d5a974b6b50d48b106417e54cb8742 Mon Sep 17 00:00:00 2001 From: Michael Barrett Date: Sat, 23 Dec 2017 20:55:34 -0800 Subject: [PATCH 08/11] Fix some typos & case inconsistency --- docs/config.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/config.rst b/docs/config.rst index 1a4da6546..135347bf8 100644 --- a/docs/config.rst +++ b/docs/config.rst @@ -92,7 +92,7 @@ See the `CloudFormation Limits Reference`_. S3 Bucket tags ----- +-------------- Various resources in AWS support arbitrary key-value pair tags. You can set the `bucket_tags` Top Level Keyword to populate tags on all S3 buckets Staker @@ -163,7 +163,7 @@ The only required key for a git repository config is ``uri``, but ``branch``, commit: 12345678 If no specific commit or tag is specified for a repo, the remote repository -will be checked for newer commits on every execution of Stacker. +will be checked for newer commits on every execution of stacker. For ``.tar.gz`` & ``zip`` archives on s3, specify a ``bucket`` & ``key``:: @@ -183,7 +183,7 @@ For ``.tar.gz`` & ``zip`` archives on s3, specify a ``bucket`` & ``key``:: use_latest: false Use the ``paths`` option when subdirectories of the repo/archive should be -added to Stacker's ``sys.path``. +added to stacker's ``sys.path``. Cloned repos/archives will be cached between builds; the cache location defaults to ~/.stacker but can be manually specified via the **stacker_cache_dir** top @@ -263,7 +263,7 @@ Tags ---- Various resources in AWS support arbitrary key-value pair tags. You can set -the `tags` Top Level Keyword to populate tags on all Resources that Staker +the `tags` Top Level Keyword to populate tags on all Resources that stacker attempts to create via CloudFormation. All CloudFormation stack-level resources, including automatically created tags, are propagated to resources that AWS CloudFormation supports. See `AWS CloudFormation Resource Tags Type`_ for From 142cc90404f4b03d45ee1e9a70e7554c4518af3f Mon Sep 17 00:00:00 2001 From: Michael Barrett Date: Sat, 23 Dec 2017 21:01:19 -0800 Subject: [PATCH 09/11] Fix bad merge, add back ISO format class variable --- stacker/util.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/stacker/util.py b/stacker/util.py index 2076ee010..12589055a 100644 --- a/stacker/util.py +++ b/stacker/util.py @@ -663,6 +663,8 @@ class SourceProcessor(): """Makes remote python package sources available in the running python environment.""" + ISO8601_FORMAT = '%Y%m%dT%H%M%SZ' + def __init__(self, sources, stacker_cache_dir=None): """ Process a config's defined package sources. From dd952ae159ac00a455f60b0847229021bf78abaf Mon Sep 17 00:00:00 2001 From: Michael Barrett Date: Sat, 23 Dec 2017 21:05:07 -0800 Subject: [PATCH 10/11] Clean up imports --- stacker/util.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/stacker/util.py b/stacker/util.py index 12589055a..a8014b07f 100644 --- a/stacker/util.py +++ b/stacker/util.py @@ -16,9 +16,12 @@ from collections import OrderedDict import botocore.client -from git import Repo import botocore.exceptions + import dateutil + +from git import Repo + import yaml from yaml.constructor import ConstructorError from yaml.nodes import MappingNode From cb127916f4964ac42c91c801884711a65f5cd809 Mon Sep 17 00:00:00 2001 From: Michael Barrett Date: Sat, 23 Dec 2017 21:10:38 -0800 Subject: [PATCH 11/11] Clean up tagging logic, add some logging. --- stacker/util.py | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/stacker/util.py b/stacker/util.py index a8014b07f..9e8a832a9 100644 --- a/stacker/util.py +++ b/stacker/util.py @@ -541,15 +541,10 @@ def ensure_s3_bucket(s3_client, bucket_name, bucket_region, context): set the S3 bucket tags from the stacker config """ + tagset = _s3_bucket_tags(context) try: - # Checking is bucket exists + logger.debug("Checking that bucket '%s' exists.", bucket_name) s3_client.head_bucket(Bucket=bucket_name) - # pulling tags from s3_bucket_tags function - tagset = _s3_bucket_tags(context) - # setting tags on every run - must have permission to perform - # the s3:PutBucketTagging action - s3_client.put_bucket_tagging(Bucket=bucket_name, - Tagging={'TagSet': tagset}) except botocore.exceptions.ClientError as e: if e.response['Error']['Message'] == "Not Found": logger.debug("Creating bucket %s.", bucket_name) @@ -562,12 +557,7 @@ def ensure_s3_bucket(s3_client, bucket_name, bucket_region, context): "LocationConstraint": location_constraint } # pulling tags from s3_bucket_tags function - tagset = _s3_bucket_tags(context) s3_client.create_bucket(**create_args) - # setting tags on every run - must have permission to perform - # the s3:PutBucketTagging action - s3_client.put_bucket_tagging(Bucket=bucket_name, - Tagging={'TagSet': tagset}) elif e.response['Error']['Message'] == "Forbidden": logger.exception("Access denied for bucket %s. Did " + "you remember to use a globally unique name?", @@ -578,6 +568,15 @@ def ensure_s3_bucket(s3_client, bucket_name, bucket_region, context): bucket_name, e.response) raise + logger.debug( + "Setting tags on bucket '%s': %s", bucket_name, context.s3_bucket_tags + ) + + # setting tags on every run - must have permission to perform + # the s3:PutBucketTagging action + s3_client.put_bucket_tagging(Bucket=bucket_name, + Tagging={'TagSet': tagset}) + def _s3_bucket_tags(context): """Returns the tags to be applied for a S3 bucket.