Package: aws-tag-a-day
aws-tag-a-dayA tool for simplifying multiple people fixing tags by proposing a tag a day for resources with those missing tags.Installationpipinstallaws-tag-a-dayQuickstart# Generate configuration filemkdir-p~/.config/tagaday/
cat>~/.config/tagaday/config.yml<<EOYdynamodb-table-name: 'tag-proposals'dynamodb-table-region: 'eu-west-2'services:- rds- ec2- s3- emrregions:- us-east-1- us-west-1- eu-west-1- ap-southeast-1- ap-northeast-1required-tags:- Project- Owner- Name- Service- AvailabilityEOY# Create dynamodb table defined in the above config file.# If the table exists already, the utility will not overwrite it.tag-a-day-initialise# Start proposing tagstag-a-dayMotivationThere are a lot of tools for handling batch tagging, but not many tools for aiding in filling in empty tags on a large scale.The suggested workflow is:Create configuration file.Create a DynamoDB table by runningtag-a-day-initialise. This is not a destructive operation, and existing tables will not be modified or removed. The utility will throw an error if the table already exists.Have 1 or more people start usingtag-a-day.Reconcile any divergent or duplicate tags by runningtag-a-day-reconcile, and discuss any duplicate tagging suggestions.Apply the tags to the resources.NOTE: Steps 4 and 5 are not yet implemented by this utility.ReferenceSupported Servicesemrec2s3rdsConfiguration File & CLI optionsConfiguration File KeyTypeCLI OptionTypeDescriptionregions:List--regionsComma separated stringList of regions to audit resources inservices:List--servicesComma separated stringList of services to auditrequired-tags:List--required-tagsComma separated stringList of tags which must be present on all resourcesdynamodb-table-name:String--dynamodb-table-nameStringName of the DynamoDB table to propose tags to. If used in conjunction withtag-a-day-initialise, this will be the DynamoDB table to be created.dynamodb-table-region:String--dynamodb-table-regionStringAWS Region in which to look for--dynamodb-table-name. If used in conjunction withtag-a-day-initialisethis will be the region which the DynamoDB table will be created in.--resource-idsComma separated stringList of resource ids, to filter only for specific resources to propose tags for.--profile-pathStringFile path pointing to a folder where tag profiles are located--profileStringFile name (including .yaml/.yml suffix) point to a particular tagging profile in--profile-pathExtendingaws-tag-a-dayis built on a plugin architecture, usingentry_pointinsetuptools.To add more TagHandlers, you can either add classes to this repo, or create a new python package with its
own setup.py, and hook into the plugin architecture using thetag_a_day.tag_handlersentrypoint.Create a new class, inheriting fromtag_a_day.services.service.Servicefromtag_a_day.services.serviceimportServiceclassCustomTagHandler(Service):passSet a unique name for the Tag handlerfromtag_a_day.services.serviceimportServiceclassCustomTagHandler(Service):name='custom_handler'Create two stub methods,resourcesandhandlermatching the signatures below:fromtag_a_day.services.serviceimportServiceclassVpcTagHandler(Service):name='ec2_vpc'defresources(self,session):passdefhandler(self,resource,expected_tags,region,session,cache,proposals):passImplementresources(...)to return an iterable. If using boto3 resources,
this should look like:defresources(self,session):returnsession.resource('ec2').vpc.all()If using boto3 client, don't forget to implement pagination, and should look like:defresources(self,session):ec2=session.client('ec2')paginator=ec2.get_paginator('describe_vpcs')forpageinpaginator.paginate():forvpcinpage:yieldvpcImplementhandle(...)to yield a payload describing the tag proposal (example is using boto3.resources):defhandle(self,vpc,expected_tags,region,session,cache,proposals):# This boilerplate logic will handle checking the tags which have already been# evaluated for this user.evaluated_tags=self._progress.evaluated_tags(vpc.vpc_id)vpc_info,missing_tags=\self._build_tag_sets(expected_tags,evaluated_tags,vpc.tags)# Check if the user has proposed values for all the missing tagsifself._progress.has_finished(vpc.vpc_id,expected_tags):# Print a skip messageself._skip(vpc.vpc_id)returnifany(missing_tags):# Print information about this resource, which could be useful# to provide context around tagging.self._print_table(("VpcID",vpc.vpc_id),*vpc_info)# Allow the user to skip auditing this resourceifself._user_skip():return# Build our user prompt to ask for new tagstag_prompt=self._build_tag_prompt(missing_tags)fortag_keyinmissing_tags:# Yield a proposal for a new tag key/value pair for the given# resource id.yield{'resource_id':vpc.vpc_id,'tag_key':tag_key,'tag_value':tag_prompt(tag_key),}Finally, add the entrypoint by extendingsetup.py:fromsetuptoolsimportsetupsetup(...,entry_points={'tag_a_day.tag_handlers':['vpc = my_package.my_module:VPCTagHandler',],})