def test_get_undercloud_registry(self, mock_interfaces, mock_addresses): mock_interfaces.return_value = ['lo', 'eth0'] self.assertEqual('localhost:8787', image_uploader.get_undercloud_registry()) mock_interfaces.return_value = ['lo', 'eth0', 'br-ctlplane'] mock_addresses.return_value = {2: [{'addr': '192.0.2.0'}]} self.assertEqual('192.0.2.0:8787', image_uploader.get_undercloud_registry())
def take_action(self, parsed_args): self.log.debug("take_action(%s)" % parsed_args) if not parsed_args.yes: confirm = utils.prompt_user_for_confirmation( message=_("Are you sure you want to delete this image " "[y/N]? "), logger=self.log) if not confirm: raise oscexc.CommandError("Action not confirmed, exiting.") lock = processlock.ProcessLock() manager = image_uploader.ImageUploadManager(lock=lock) uploader = manager.uploader('python') registry_url_arg = parsed_args.registry_url if registry_url_arg is None: registry_url_arg = image_uploader.get_undercloud_registry() url = uploader._image_to_url(registry_url_arg) session = uploader.authenticate(url, parsed_args.username, parsed_args.password) try: uploader.delete(parsed_args.image_to_delete, session=session) except OSError as e: self.log.error("Unable to remove due to permissions. " "Please prefix command with sudo.") raise oscexc.CommandError(e)
def get_parser(self, prog_name): parser = super(TripleOContainerImageDelete, self).get_parser(prog_name) parser.add_argument( "--registry-url", dest="registry_url", metavar='<registry url>', default=image_uploader.get_undercloud_registry(), help=_("URL of registry images are to be listed from in the " "form <fqdn>:<port>.")) parser.add_argument(dest="image_to_delete", metavar='<image to delete>', help=_("Full URL of image to be deleted in the " "form <fqdn>:<port>/path/to/image")) parser.add_argument("--username", dest="username", metavar='<username>', help=_("Username for image registry.")) parser.add_argument("--password", dest="password", metavar='<password>', help=_("Password for image registry.")) parser.add_argument('-y', '--yes', help=_('Skip yes/no prompt (assume yes).'), default=False, action="store_true") return parser
def get_parser(self, prog_name): parser = super(TripleOContainerImagePush, self).get_parser(prog_name) parser.add_argument( "--local", dest="local", default=False, action="store_true", help=_("Use this flag if the container image is already on the " "current system and does not need to be pulled from a " "remote registry.")) parser.add_argument("--registry-url", dest="registry_url", metavar='<registry url>', default=image_uploader.get_undercloud_registry(), help=_( "URL of the destination registry in the form " "<fqdn>:<port>.")) parser.add_argument( "--append-tag", dest="append_tag", default='', help=_("Tag to append to the existing tag when pushing the " "container. ")) parser.add_argument( "--username", dest="username", metavar='<username>', help=_("Username for the destination image registry.")) parser.add_argument( "--password", dest="password", metavar='<password>', help=_("Password for the destination image registry.")) parser.add_argument( "--dry-run", dest="dry_run", action="store_true", help=_("Perform a dry run upload. The upload action is not " "performed, but the authentication process is attempted.")) parser.add_argument( "--multi-arch", dest="multi_arch", action="store_true", help=_("Enable multi arch support for the upload.")) parser.add_argument( "--cleanup", dest="cleanup", action="store_true", default=False, help=_("Remove local copy of the image after uploading")) parser.add_argument( dest="image_to_push", metavar='<image to push>', help=_("Container image to upload. Should be in the form of " "<registry>/<namespace>/<name>:<tag>. If tag is " "not provided, then latest will be used.")) return parser
def take_action(self, parsed_args): self.log.debug("take_action(%s)" % parsed_args) cip = copy.deepcopy(kolla_builder.CONTAINER_IMAGE_PREPARE_PARAM) if parsed_args.push_destination: local_registry = image_uploader.get_undercloud_registry() for entry in cip: entry['push_destination'] = local_registry params = {'ContainerImagePrepare': cip} env_data = build_env_file(params, self.app.command_options) self.app.stdout.write(env_data) if parsed_args.output_env_file: with os.fdopen( os.open(parsed_args.output_env_file, os.O_CREAT | os.O_TRUNC | os.O_WRONLY, 0o666), 'w') as f: f.write(env_data)
def take_action(self, parsed_args): self.log.debug("take_action(%s)" % parsed_args) lock = processlock.ProcessLock() manager = image_uploader.ImageUploadManager(lock=lock) uploader = manager.uploader('python') registry_url_arg = parsed_args.registry_url if registry_url_arg is None: registry_url_arg = image_uploader.get_undercloud_registry() url = uploader._image_to_url(registry_url_arg) session = uploader.authenticate(url, parsed_args.username, parsed_args.password) results = uploader.list(url.geturl(), session=session) cliff_results = [] for r in results: cliff_results.append((r,)) return (("Image Name",), cliff_results)
def get_parser(self, prog_name): parser = super(TripleOContainerImageList, self).get_parser(prog_name) parser.add_argument( "--registry-url", dest="registry_url", metavar='<registry url>', default=image_uploader.get_undercloud_registry(), help=_("URL of registry images are to be listed from in the " "form <fqdn>:<port>.")) parser.add_argument("--username", dest="username", metavar='<username>', help=_("Username for image registry.")) parser.add_argument("--password", dest="password", metavar='<password>', help=_("Password for image registry.")) return parser
def container_images_prepare(template_file=DEFAULT_TEMPLATE_FILE, excludes=None, includes=None, service_filter=None, pull_source=None, push_destination=None, mapping_args=None, output_env_file=None, output_images_file=None, tag_from_label=None, append_tag=None, modify_role=None, modify_vars=None, modify_only_with_labels=None, mirrors=None): """Perform container image preparation :param template_file: path to Jinja2 file containing all image entries :param excludes: list of image name substrings to use for exclude filter :param includes: list of image name substrings, at least one must match. All excludes are ignored if includes is specified. :param service_filter: set of heat resource types for containerized services to filter by. Disable by passing None. :param pull_source: DEPRECATED namespace for pulling during image uploads :param push_destination: namespace for pushing during image uploads. When specified the image parameters will use this namespace too. :param mapping_args: dict containing substitutions for template file. See CONTAINER_IMAGES_DEFAULTS for expected keys. :param output_env_file: key to use for heat environment parameter data :param output_images_file: key to use for image upload data :param tag_from_label: string when set will trigger tag discovery on every image :param append_tag: string to append to the tag for the destination image :param modify_role: string of ansible role name to run during upload before the push to destination :param modify_vars: dict of variables to pass to modify_role :param modify_only_with_labels: only modify the container images with the given labels :param mirrors: dict of registry netloc values to mirror urls :returns: dict with entries for the supplied output_env_file or output_images_file """ if mapping_args is None: mapping_args = {} def ffunc(entry): imagename = entry.get('imagename', '') if service_filter is not None: # check the entry is for a service being deployed image_services = set(entry.get('services', [])) if not image_services.intersection(service_filter): return None if includes: for p in includes: if re.search(p, imagename): return entry return None if excludes: for p in excludes: if re.search(p, imagename): return None return entry builder = KollaImageBuilder([template_file]) result = builder.container_images_from_template(filter=ffunc, **mapping_args) manager = image_uploader.ImageUploadManager(mirrors=mirrors) uploader = manager.uploader('python') images = [i.get('imagename', '') for i in result] if tag_from_label: image_version_tags = uploader.discover_image_tags( images, tag_from_label) for entry in result: imagename = entry.get('imagename', '') image_no_tag = imagename.rpartition(':')[0] if image_no_tag in image_version_tags: entry['imagename'] = '%s:%s' % ( image_no_tag, image_version_tags[image_no_tag]) if modify_only_with_labels: images_with_labels = uploader.filter_images_with_labels( images, modify_only_with_labels) params = {} modify_append_tag = append_tag for entry in result: imagename = entry.get('imagename', '') append_tag = '' if modify_role and ((not modify_only_with_labels) or imagename in images_with_labels): entry['modify_role'] = modify_role if modify_append_tag: entry['modify_append_tag'] = modify_append_tag append_tag = modify_append_tag if modify_vars: entry['modify_vars'] = modify_vars if pull_source: entry['pull_source'] = pull_source if push_destination: # substitute discovered registry if push_destination is set to true if isinstance(push_destination, bool): push_destination = image_uploader.get_undercloud_registry() entry['push_destination'] = push_destination # replace the host portion of the imagename with the # push_destination, since that is where they will be uploaded to image = imagename.partition('/')[2] imagename = '/'.join((push_destination, image)) if 'params' in entry: for p in entry.pop('params'): params[p] = imagename + append_tag if 'services' in entry: del (entry['services']) params.update(detect_insecure_registries(params)) return_data = {} if output_env_file: return_data[output_env_file] = params if output_images_file: return_data[output_images_file] = result return return_data
def container_images_prepare(template_file=DEFAULT_TEMPLATE_FILE, excludes=None, includes=None, service_filter=None, pull_source=None, push_destination=None, mapping_args=None, output_env_file=None, output_images_file=None, tag_from_label=None, append_tag=None, modify_role=None, modify_vars=None, modify_only_with_labels=None, mirrors=None, registry_credentials=None): """Perform container image preparation :param template_file: path to Jinja2 file containing all image entries :param excludes: list of image name substrings to use for exclude filter :param includes: list of image name substrings, at least one must match. All excludes are ignored if includes is specified. :param service_filter: set of heat resource types for containerized services to filter by. Disable by passing None. :param pull_source: DEPRECATED namespace for pulling during image uploads :param push_destination: namespace for pushing during image uploads. When specified the image parameters will use this namespace too. :param mapping_args: dict containing substitutions for template file. See CONTAINER_IMAGES_DEFAULTS for expected keys. :param output_env_file: key to use for heat environment parameter data :param output_images_file: key to use for image upload data :param tag_from_label: string when set will trigger tag discovery on every image :param append_tag: string to append to the tag for the destination image :param modify_role: string of ansible role name to run during upload before the push to destination :param modify_vars: dict of variables to pass to modify_role :param modify_only_with_labels: only modify the container images with the given labels :param mirrors: dict of registry netloc values to mirror urls :param registry_credentials: dict of registry netloc values to authentication credentials for that registry. The value is a single-entry dict where the username is the key and the password is the value. :returns: dict with entries for the supplied output_env_file or output_images_file """ if mapping_args is None: mapping_args = {} def ffunc(entry): imagename = entry.get('imagename', '') if service_filter is not None: # check the entry is for a service being deployed image_services = set(entry.get('services', [])) if not image_services.intersection(service_filter): return None if includes: for p in includes: if re.search(p, imagename): return entry return None if excludes: for p in excludes: if re.search(p, imagename): return None return entry builder = KollaImageBuilder([template_file]) result = builder.container_images_from_template( filter=ffunc, **mapping_args) manager = image_uploader.ImageUploadManager( mirrors=mirrors, registry_credentials=registry_credentials) uploader = manager.uploader('python') images = [i.get('imagename', '') for i in result] if tag_from_label: image_version_tags = uploader.discover_image_tags( images, tag_from_label) for entry in result: imagename = entry.get('imagename', '') image_no_tag = imagename.rpartition(':')[0] if image_no_tag in image_version_tags: entry['imagename'] = '%s:%s' % ( image_no_tag, image_version_tags[image_no_tag]) if modify_only_with_labels: images_with_labels = uploader.filter_images_with_labels( images, modify_only_with_labels) params = {} modify_append_tag = append_tag for entry in result: imagename = entry.get('imagename', '') append_tag = '' if modify_role and ( (not modify_only_with_labels) or imagename in images_with_labels): entry['modify_role'] = modify_role if modify_append_tag: entry['modify_append_tag'] = modify_append_tag append_tag = modify_append_tag if modify_vars: entry['modify_vars'] = modify_vars if pull_source: entry['pull_source'] = pull_source if push_destination: # substitute discovered registry if push_destination is set to true if isinstance(push_destination, bool): push_destination = image_uploader.get_undercloud_registry() entry['push_destination'] = push_destination # replace the host portion of the imagename with the # push_destination, since that is where they will be uploaded to image = imagename.partition('/')[2] imagename = '/'.join((push_destination, image)) if 'params' in entry: for p in entry.pop('params'): params[p] = imagename + append_tag if 'services' in entry: del(entry['services']) params.update( detect_insecure_registries(params)) return_data = {} if output_env_file: return_data[output_env_file] = params if output_images_file: return_data[output_images_file] = result return return_data
def container_images_prepare(template_file=DEFAULT_TEMPLATE_FILE, template_dir=DEFAULT_TEMPLATE_DIR, excludes=None, includes=None, service_filter=None, pull_source=None, push_destination=None, mapping_args=None, output_env_file=None, output_images_file=None, tag_from_label=None, append_tag=None, modify_role=None, modify_vars=None, modify_only_with_labels=None, modify_only_with_source=None, mirrors=None, registry_credentials=None, multi_arch=False, lock=None): """Perform container image preparation :param template_file: path to Jinja2 file containing all image entries :param template_dir: path to Jinja2 files included in the main template :param excludes: list of image name substrings to use for exclude filter :param includes: list of image name substrings, at least one must match. All excludes are ignored if includes is specified. :param service_filter: set of heat resource types for containerized services to filter by. Disable by passing None. :param pull_source: DEPRECATED namespace for pulling during image uploads :param push_destination: namespace for pushing during image uploads. When specified the image parameters will use this namespace too. :param mapping_args: dict containing substitutions for template file. See CONTAINER_IMAGES_DEFAULTS for expected keys. :param output_env_file: key to use for heat environment parameter data :param output_images_file: key to use for image upload data :param tag_from_label: string when set will trigger tag discovery on every image :param append_tag: string to append to the tag for the destination image :param modify_role: string of ansible role name to run during upload before the push to destination :param modify_vars: dict of variables to pass to modify_role :param modify_only_with_labels: only modify the container images with the given labels :param modify_only_with_source: only modify the container images from a image_source in the tripleo-common service to container mapping (e.g. kolla/tripleo) :param mirrors: dict of registry netloc values to mirror urls :param registry_credentials: dict of registry netloc values to authentication credentials for that registry. The value is a single-entry dict where the username is the key and the password is the value. :param multi_arch: boolean whether to prepare every architecture of each image :param lock: a locking object to use when handling uploads :returns: dict with entries for the supplied output_env_file or output_images_file """ if mapping_args is None: mapping_args = {} if not lock: lock = threadinglock.ThreadingLock() def ffunc(entry): imagename = entry.get('imagename', '') if service_filter is not None: # check the entry is for a service being deployed image_services = set(entry.get('services', [])) if not image_services.intersection(service_filter): return None if includes: for p in includes: if re.search(p, imagename): return entry return None if excludes: for p in excludes: if re.search(p, imagename): return None return entry builder = KollaImageBuilder([template_file], template_dir) result = builder.container_images_from_template(filter=ffunc, **mapping_args) manager = image_uploader.ImageUploadManager( mirrors=mirrors, registry_credentials=registry_credentials, multi_arch=multi_arch, lock=lock) uploader = manager.uploader('python') images = [i.get('imagename', '') for i in result] # set a flag to record whether the default tag is used or not. the # logic here is that if the tag key is not already in mapping then it # wil be added during the template render, so default_tag is set to # True. default_tag = 'tag' not in mapping_args if tag_from_label: image_version_tags = uploader.discover_image_tags( images, tag_from_label, default_tag) for entry in result: imagename = entry.get('imagename', '') image_no_tag = imagename.rpartition(':')[0] if image_no_tag in image_version_tags: entry['imagename'] = '%s:%s' % ( image_no_tag, image_version_tags[image_no_tag]) images_with_labels = [] if modify_only_with_labels: images_with_labels = uploader.filter_images_with_labels( images, modify_only_with_labels) images_with_source = [] if modify_only_with_source: images_with_source = [ i.get('imagename') for i in result if i.get('image_source', '') in modify_only_with_source ] params = {} modify_append_tag = append_tag for entry in result: imagename = entry.get('imagename', '') append_tag = '' if modify_role and ( (not modify_only_with_labels and not modify_only_with_source) or (imagename in images_with_labels or imagename in images_with_source)): entry['modify_role'] = modify_role if modify_append_tag: entry['modify_append_tag'] = modify_append_tag append_tag = modify_append_tag if modify_vars: entry['modify_vars'] = modify_vars if pull_source: entry['pull_source'] = pull_source if push_destination: # substitute discovered registry if push_destination is set to true if isinstance(push_destination, bool): push_destination = image_uploader.get_undercloud_registry() entry['push_destination'] = push_destination # replace the host portion of the imagename with the # push_destination, since that is where they will be uploaded to image = imagename.partition('/')[2] imagename = '/'.join((push_destination, image)) if 'params' in entry: for p in entry.pop('params'): params[p] = imagename + append_tag if 'services' in entry: del (entry['services']) params.update(detect_insecure_registries(params, lock=lock)) return_data = {} if output_env_file: return_data[output_env_file] = params if output_images_file: return_data[output_images_file] = result return return_data
def take_action(self, parsed_args): self.log.debug("take_action(%s)" % parsed_args) lock = processlock.ProcessLock() manager = image_uploader.ImageUploadManager(lock=lock) uploader = manager.uploader('python') source_image = parsed_args.image_to_push if parsed_args.local or source_image.startswith('containers-storage:'): storage = 'containers-storage:' if not source_image.startswith(storage): source_image = storage + source_image.replace('docker://', '') elif not parsed_args.local: self.log.warning('Assuming local container based on provided ' 'container path. (e.g. starts with ' 'containers-storage:)') source_url = parse.urlparse(source_image) image_name = source_url.geturl() image_source = None if parsed_args.source_username or parsed_args.source_password: self.log.warning('Source credentials ignored for local images') else: storage = 'docker://' if not source_image.startswith(storage): source_image = storage + source_image source_url = parse.urlparse(source_image) image_source = source_url.netloc image_name = source_url.path[1:] if len(image_name.split('/')) != 2: raise exceptions.DownloadError('Invalid container. Provided ' 'container image should be ' '<registry>/<namespace>/<name>:' '<tag>') if parsed_args.source_username or parsed_args.source_password: if not parsed_args.source_username: self.log.warning('Skipping authentication - missing source' ' username') elif not parsed_args.source_password: self.log.warning('Skipping authentication - missing source' ' password') else: uploader.authenticate(source_url, parsed_args.source_username, parsed_args.source_password) registry_url_arg = parsed_args.registry_url if registry_url_arg is None: registry_url_arg = image_uploader.get_undercloud_registry() if not registry_url_arg.startswith('docker://'): registry_url = 'docker://%s' % registry_url_arg else: registry_url = registry_url_arg reg_url = parse.urlparse(registry_url) uploader.authenticate(reg_url, parsed_args.username, parsed_args.password) task = image_uploader.UploadTask( image_name=image_name, pull_source=image_source, push_destination=registry_url_arg, append_tag=parsed_args.append_tag, modify_role=None, modify_vars=None, dry_run=parsed_args.dry_run, cleanup=parsed_args.cleanup, multi_arch=parsed_args.multi_arch) try: uploader.add_upload_task(task) uploader.run_tasks() except OSError as e: self.log.error("Unable to upload due to permissions. " "Please prefix command with sudo.") raise oscexc.CommandError(e)