13 from .
import REGISTRIES
14 from .
import REPOSITORIES
15 from concurrent
import futures
21 AWS_REGION = os.environ.get(
'AWS_REGION',
'us-east-2')
25 '''Manage ECR Images and Tags''' 28 def setup_args(self, parser):
29 self.add_subcommand(PushCommand)
30 self.add_subcommand(CatalogCommand)
31 self.add_subcommand(ListImagesCommand)
32 self.add_subcommand(RemoveTagCommand)
36 '''Push Current Images to AWS ECR''' 40 def setup_args(self, paser):
41 self.add_argument(
'--image-tag', help=
'Override Image Tag')
42 self.add_argument(
'--verbose',
'-v',
44 help=
'Turn on verbose output')
47 git_sha = os.environ.get(
'GIT_SHORT_REV')
48 image_tags = [(
'g-%s' % git_sha)]
50 image_tags.append(args.image_tag)
52 for region
in AWS_REGIONS:
53 for tag
in image_tags:
54 push_odyssey_images(tag, region, args.verbose)
58 '''Display List of Images and Tags in ECR''' 62 def setup_args(self, parser):
63 self.add_argument(
'--region', help=
'Only list images from this region')
66 display_image_catalog(args.region)
70 '''Display List of Images and Tags in ECR''' 74 def setup_args(self, parser):
75 self.add_argument(
'--region', help=
'Only list images from this region')
78 display_image_catalog(args.region)
82 '''Remove Docker tag from images in ECR''' 86 def setup_args(self, parser):
87 self.add_argument(
'tag_name', help=
'Name of tag to delete')
88 self.add_argument(
'--verbose',
'-v', action=
'store_true',
89 help=
'Print verbose output')
91 def confirm_action(self, message):
92 confirm = input(message)
94 raise SystemExit(
'Aborted')
97 self.
confirm_action(
'Are you sure you want to remove image tag "%s" ' 98 '[yes|NO]: ' % args.tag_name)
100 remove_image_tag(args.tag_name, verbose=args.verbose)
103 def display_image_catalog(region=None):
104 regions = AWS_REGIONS
105 if region
in AWS_REGIONS:
107 for region
in regions:
108 print_image_catalog_table(region)
111 def print_image_catalog_table(region):
113 for repository
in catalog.keys():
127 'title':
'Images from %s/%s' % (region, repository)
129 t = shellish.Table(**table_config)
131 for image
in catalog[repository]:
133 ','.join(image[
'imageTags']),
134 humanize.naturaldate(image[
'imagePushedAt']),
135 image[
'imageDigest'],
136 humanize.naturalsize(image[
'imageSizeInBytes']),
144 '''build table of images for each repository''' 146 for repository
in REPOSITORIES:
147 table[repository] = list(get_ecr_images(region, repository))
152 def get_ecr_images(region, repository_name):
153 def _get_ecr_images_(region, repository_name):
154 client = boto3.client(
'ecr', region_name=region)
155 paginator = client.get_paginator(
'describe_images')
156 pages = paginator.paginate(
157 repositoryName=repository_name,
159 'tagStatus':
'TAGGED' 163 yield from page[
'imageDetails']
165 return itertools.chain(_get_ecr_images_(region, repository_name))
168 def push_odyssey_images(tag, region, verbose):
169 registry = REGISTRIES[region]
170 cmd(
'$(aws --region %s ecr get-login --no-include-email)' % region,
172 with futures.ThreadPoolExecutor(max_workers=10)
as pool:
174 for image, remote_image
in IMAGES:
175 def fn(_image=image, _remote_image=remote_image):
176 ecr_tag =
'%s/%s:%s' % (registry,
179 cmd(
'docker tag', _image, ecr_tag, verbose=verbose)
181 cmd(
'docker push', ecr_tag, verbose=verbose)
183 cmd(
'docker rmi', ecr_tag, verbose=verbose)
184 push_futures.append(pool.submit(fn))
185 for f
in futures.as_completed(push_futures):
188 except Exception
as e:
189 raise SystemExit(str(e))
192 def remove_image_tag(tag_name, **kwargs):
193 def __remove_tag_from_ecr__(tag_name, region_name):
194 client = boto3.client(
'ecr', region_name=region_name)
195 for repository
in REPOSITORIES:
196 response = client.batch_delete_image(
197 repositoryName=repository,
200 'imageTag': tag_name,
204 for image_id
in response[
'imageIds']:
206 '<red>Deleted image: %s</red>' % (
207 image_id[
'imageTag']))
208 for failure
in response[
'failures']:
210 '<red>Unable to delete: "%s": %s</red>' % (
211 failure[
'imageId'][
'imageTag'],
212 failure[
'failureReason']))
214 verbose = kwargs.get(
'verbose',
False)
215 with futures.ThreadPoolExecutor(max_workers=10)
as pool:
218 for region
in AWS_REGIONS:
219 push_futures.append(pool.submit(__remove_tag_from_ecr__,
222 for f
in futures.as_completed(push_futures):
225 except Exception
as ex:
227 print(str(ex), file=sys.stderr)
def confirm_action(self, message)
def build_catalog_table(region)