def Run(self, args): """This is what is called when the user runs this command. Args: args: an argparse namespace. All the arguments that were provided to this command invocation. Raises: util.InvalidImageNameError: If the user specified an invalid (or non-existent) image name. Returns: A list of the deleted docker_name.Tag objects """ # IMAGE_NAME: The fully-qualified image name to delete (with a tag). # Removes the tag from the image. Ex. gcr.io/google-appengine/java:TAG. http_obj = util.Http() # collect input/validate tags = self._ParseArgs(args.image_names) digests = dict() with util.WrapExpectedDockerlessErrors(): for tag in tags: try: # Resolve tags to digests. Throws InvalidImageNameError on 404. digests[tag] = util.GetDigestFromName(six.text_type(tag)) except util.InvalidImageNameError: # We already validated the image string in _ParseArgs, this is a 404 raise util.InvalidImageNameError( 'Image could not be found: [{}]'.format( six.text_type(tag))) if not tags: log.warning('No tags found matching image names [%s].', ', '.join(args.image_names)) return for tag, digest in six.iteritems(digests): log.status.Print('Tag: [{}]'.format(six.text_type(tag))) log.status.Print('- referencing digest: [{}]'.format( six.text_type(digest))) log.status.Print('') console_io.PromptContinue( 'This operation will remove the above tags. ' 'Tag removals only delete the tags; ' 'The underlying image layers (referenced by the above digests) will ' 'continue to exist.', cancel_on_no=True) # delete and collect output result = [] for tag in tags: self._DeleteDockerTag(tag, digests, http_obj) result.append({'name': six.text_type(tag)}) return result
def Run(self, args): # pylint: disable=missing-docstring def Push(image, dest_names, creds, http_obj, src_name, session_push_type): for dest_name in dest_names: with session_push_type(dest_name, creds, http_obj) as push: push.upload(image) log.CreatedResource(dest_name) log.UpdatedResource(src_name) http_obj = util.Http() src_name = util.GetDockerImageFromTagOrDigest(args.src_image) dest_names = [] for dest_image in args.dest_image: try: dest_name = docker_name.Tag(dest_image) except docker_name.BadNameException as e: raise util.InvalidImageNameError(six.text_type(e)) if '/' not in dest_name.repository: raise exceptions.Error( 'Pushing to project root-level images is disabled. ' 'Please designate an image within a project, ' 'e.g. gcr.io/project-id/my-image:tag') dest_names.append(dest_name) console_io.PromptContinue('This will tag {} with:\n{}'.format( src_name, '\n'.join(str(dest_name) for dest_name in dest_names)), default=True, cancel_on_no=True) creds = util.CredentialProvider() with util.WrapExpectedDockerlessErrors(): with docker_image_list.FromRegistry(src_name, creds, http_obj) as manifest_list: if manifest_list.exists(): Push(manifest_list, dest_names, creds, http_obj, src_name, v2_2_session.Push) return with v2_2_image.FromRegistry(src_name, creds, http_obj, accepted_mimes=docker_http. SUPPORTED_MANIFEST_MIMES) as v2_2_img: if v2_2_img.exists(): Push(v2_2_img, dest_names, creds, http_obj, src_name, v2_2_session.Push) return with v2_image.FromRegistry(src_name, creds, http_obj) as v2_img: Push(v2_img, dest_names, creds, http_obj, src_name, v2_session.Push)
def Run(self, args): """This is what gets called when the user runs this command. Args: args: an argparse namespace. All the arguments that were provided to this command invocation. Raises: ArgumentError: If the user provided the flag --show-occurrences-from but --show-occurrences=False. InvalidImageNameError: If the user specified an invalid image name. Returns: Some value that we want to have printed later. """ # Verify that --show-occurrences-from is set iff --show-occurrences=True. if args.IsSpecified( 'show_occurrences_from') and not args.show_occurrences: raise ArgumentError( '--show-occurrences-from may only be set if --show-occurrences=True' ) repository = util.ValidateRepositoryPath(args.image_name) http_obj = util.Http() with util.WrapExpectedDockerlessErrors(repository): with docker_image.FromRegistry( basic_creds=util.CredentialProvider(), name=repository, transport=http_obj) as image: manifests = image.manifests() # Only consider the top _DEFAULT_SHOW_OCCURRENCES_FROM images # to reduce computation time. most_recent_resource_urls = None occ_filter = filter_util.ContainerAnalysisFilter() occ_filter.WithCustomFilter(args.occurrence_filter) occ_filter.WithResourcePrefix('https://{}'.format(repository)) if args.show_occurrences_from: # This block is skipped when the user provided # --show-occurrences-from=unlimited on the CLI. most_recent_resource_urls = [ 'https://%s@%s' % (args.image_name, k) for k in heapq.nlargest( args.show_occurrences_from, manifests, key=lambda k: manifests[k]['timeCreatedMs']) ] occ_filter.WithResources(most_recent_resource_urls) return util.TransformManifests( manifests, repository, show_occurrences=args.show_occurrences, occurrence_filter=occ_filter)
def Run(self, args): """This is what gets called when the user runs this command. Args: args: an argparse namespace. All the arguments that were provided to this command invocation. Returns: Some value that we want to have printed later. Raises: exceptions.Error: If the repository could not be found, or access was denied. docker_http.V2DiagnosticException: Any other error occurred while accessing GCR. """ repository_arg = args.repository self._epilog = None if not repository_arg: project_id = properties.VALUES.core.project.Get(required=True) # Handle domain-scoped projects... project_id = project_id.replace(':', '/', 1) repository_arg = 'gcr.io/{0}'.format(project_id) self._epilog = 'Only listing images in {0}. '.format( repository_arg) self._epilog += 'Use --repository to list images in other repositories.' # Throws if invalid. repository = util.ValidateRepositoryPath(repository_arg) def _DisplayName(c): """Display the fully-qualified name.""" return '{0}/{1}'.format(repository, c) http_obj = util.Http() with util.WrapExpectedDockerlessErrors(repository): with docker_image.FromRegistry( basic_creds=util.CredentialProvider(), name=repository, transport=http_obj) as r: images = [{'name': _DisplayName(c)} for c in r.children()] return images
def Run(self, args): """This is what gets called when the user runs this command. Args: args: an argparse namespace. All the arguments that were provided to this command invocation. Raises: InvalidImageNameError: If the user specified an invalid image name. Returns: Some value that we want to have printed later. """ repository = util.ValidateRepositoryPath(args.image_name) http_obj = util.Http() with util.WrapExpectedDockerlessErrors(repository): with docker_image.FromRegistry( basic_creds=util.CredentialProvider(), name=repository, transport=http_obj) as image: manifests = image.manifests() return util.TransformManifests(manifests, repository)
def Run(self, args): """This is what ts called when the user runs this command. Args: args: an argparse namespace. All the arguments that were provided to this command invocation. Raises: InvalidImageNameError: If the user specified an invalid image name. Returns: A list of the deleted docker_name.Tag and docker_name.Digest objects """ # IMAGE_NAME: The fully-qualified image name to delete (with a digest). # Deletes the layers. Ex. gcr.io/google-appengine/java(@DIGEST|:TAG). http_obj = util.Http() with util.WrapExpectedDockerlessErrors(): # collect input/validate digests, explicit_tags = self._ProcessImageNames(args.image_names) # Resolve tags to digests. for tag in explicit_tags: digests.add(util.GetDigestFromName(six.text_type(tag))) # Find all the tags that reference digests to be deleted. all_tags = set() for digest in digests: all_tags.update(util.GetDockerTagsForDigest(digest, http_obj)) # Find all the tags that weren't specified explicitly. implicit_tags = all_tags.difference(explicit_tags) if implicit_tags and not args.force_delete_tags: log.error('Tags:') for tag in explicit_tags: log.error('- ' + six.text_type(tag)) raise exceptions.Error( 'This operation will implicitly delete the tags listed above. ' 'Please manually remove with the `untag` command or re-run with ' '--force-delete-tags to confirm.') # Print the digests to be deleted. if digests: log.status.Print('Digests:') for digest in digests: self._PrintDigest(digest, http_obj) # Print the tags to be deleted. if explicit_tags: log.status.Print('Tags:') for tag in explicit_tags: log.status.Print('- ' + six.text_type(tag)) # Prompt the user for consent to delete all the above. console_io.PromptContinue( 'This operation will delete the tags and images identified by the ' 'digests above.', default=True, cancel_on_no=True) # The user has given explicit consent, merge the tags. explicit_tags.update(implicit_tags) # delete and collect output result = [] for tag in explicit_tags: # tags must be deleted before digests self._DeleteDockerTagOrDigest(tag, http_obj) result.append({'name': six.text_type(tag)}) for digest in digests: self._DeleteDockerTagOrDigest(digest, http_obj) result.append({'name': six.text_type(digest)}) return result