Ejemplo n.º 1
0
    def __init__(self, option_strings, dest, nargs=None,
                 required_keys=None, optional_keys=None, **kwargs):
        """Initialize the action object, and parse customized options

        Required keys and optional keys can be specified when initializing
        the action to enable the key validation. If none of them specified,
        the key validation will be skipped.

        :param required_keys: a list of required keys
        :param optional_keys: a list of optional keys
        """
        if nargs:
            msg = _("Parameter 'nargs' is not allowed, but got %s")
            raise ValueError(msg % nargs)

        super(MultiKeyValueAction, self).__init__(option_strings,
                                                  dest, **kwargs)

        # required_keys: A list of keys that is required. None by default.
        if required_keys and not isinstance(required_keys, list):
            msg = _("'required_keys' must be a list")
            raise TypeError(msg)
        self.required_keys = set(required_keys or [])

        # optional_keys: A list of keys that is optional. None by default.
        if optional_keys and not isinstance(optional_keys, list):
            msg = _("'optional_keys' must be a list")
            raise TypeError(msg)
        self.optional_keys = set(optional_keys or [])
    def take_action(self, parsed_args):
        if parsed_args.check_errors and not parsed_args.wait:
            raise exceptions.CommandError(
                _("--check-errors can only be used with --wait"))

        client = self.app.client_manager.baremetal_introspection
        for uuid in parsed_args.node:
            client.introspect(uuid)

        if parsed_args.wait:
            print('Waiting for introspection to finish...', file=sys.stderr)
            result = client.wait_for_finish(parsed_args.node)
            result = [(uuid, s.get('error'))
                      for uuid, s in result.items()]
            if parsed_args.check_errors:
                uuids_errors = "\n".join("%s (%s)" % node_info
                                         for node_info in result
                                         if node_info[1] is not None)
                if uuids_errors:
                    raise Exception(
                        _("Introspection failed for some nodes: %s")
                        % uuids_errors)
        else:
            result = []

        return self.COLUMNS, result
Ejemplo n.º 3
0
    def get_parser(self, prog_name):
        parser = super(ResourceList, self).get_parser(prog_name)
        parser.add_argument(
            'stack',
            metavar='<stack>',
            help=_('Name or ID of stack to query')
        )
        parser.add_argument(
            '--long',
            action='store_true',
            help=_('Enable detailed information presented for each resource '
                   'in resource list')
        )
        parser.add_argument(
            '-n', '--nested-depth',
            metavar='<nested-depth>',
            type=int,
            help=_('Depth of nested stacks from which to display resources')
        )

        parser.add_argument(
            '--filter',
            metavar='<key=value>',
            action='append',
            help=_('Filter parameters to apply on returned resources based on '
                   'their name, status, type, action, id and '
                   'physical_resource_id')
        )

        return parser
Ejemplo n.º 4
0
 def get_parser(self, prog_name):
     parser = super(ResourceMarkUnhealthy, self).get_parser(prog_name)
     parser.add_argument(
         'stack',
         metavar='<stack>',
         help=_('Name or ID of stack the resource belongs to')
     )
     parser.add_argument(
         'resource',
         metavar='<resource>',
         help=_('Name of the resource')
     )
     parser.add_argument(
         'reason',
         default="",
         nargs='?',
         help=_('Reason for state change')
     )
     parser.add_argument(
         '--reset',
         default=False,
         action="store_true",
         help=_('Set the resource as healthy')
     )
     return parser
Ejemplo n.º 5
0
def _resource_signal(heat_client, args):
    fields = {'stack_id': args.stack,
              'resource_name': args.resource}
    data = args.data
    data_file = args.data_file
    if data and data_file:
        raise exc.CommandError(_('Should only specify one of data or '
                                 'data-file'))

    if data_file:
        data_url = heat_utils.normalise_file_path_to_url(data_file)
        data = request.urlopen(data_url).read()

    if data:
        try:
            data = jsonutils.loads(data)
        except ValueError as ex:
            raise exc.CommandError(_('Data should be in JSON format: %s') % ex)
        if not isinstance(data, dict):
            raise exc.CommandError(_('Data should be a JSON dict'))

        fields['data'] = data
    try:
        heat_client.resources.signal(**fields)
    except heat_exc.HTTPNotFound:
        raise exc.CommandError(_('Stack %(stack)s or resource %(resource)s '
                                 'not found.') %
                               {'stack': args.stack,
                                'resource': args.resource})
 def get_parser(self, prog_name):
     parser = super(UploadOvercloudImage, self).get_parser(prog_name)
     parser.add_argument(
         "--image-path",
         default=os.environ.get("IMAGE_PATH", "./"),
         help=_("Path to directory containing image files"),
     )
     parser.add_argument(
         "--os-image",
         default=os.environ.get("OS_IMAGE", "overcloud-full.qcow2"),
         help=_("OpenStack disk image filename"),
     )
     parser.add_argument(
         "--http-boot",
         default=os.environ.get("HTTP_BOOT", "/httpboot"),
         help=_("Root directory for the introspection image"),
     )
     parser.add_argument(
         "--update-existing", dest="update_existing", action="store_true", help=_("Update images if already exist")
     )
     parser.add_argument(
         "--whole-disk",
         dest="whole_disk",
         action="store_true",
         default=False,
         help=_("When set, the overcloud-full image to be uploaded " "will be considered as a whole disk one"),
     )
     return parser
Ejemplo n.º 7
0
def build_auth_plugins_option_parser(parser):
    """Auth plugins options builder

    Builds dynamically the list of options expected by each available
    authentication plugin.

    """
    available_plugins = list(get_plugin_list())
    parser.add_argument(
        '--os-auth-type',
        metavar='<auth-type>',
        dest='auth_type',
        default=utils.env('OS_AUTH_TYPE'),
        help=_('Select an authentication type. Available types: %s.'
               ' Default: selected based on --os-username/--os-token'
               ' (Env: OS_AUTH_TYPE)') % ', '.join(available_plugins),
        choices=available_plugins
    )
    # Maintain compatibility with old tenant env vars
    envs = {
        'OS_PROJECT_NAME': utils.env(
            'OS_PROJECT_NAME',
            default=utils.env('OS_TENANT_NAME')
        ),
        'OS_PROJECT_ID': utils.env(
            'OS_PROJECT_ID',
            default=utils.env('OS_TENANT_ID')
        ),
    }
    for o in get_options_list():
        # Remove tenant options from KSC plugins and replace them below
        if 'tenant' not in o:
            parser.add_argument(
                '--os-' + o,
                metavar='<auth-%s>' % o,
                dest=o.replace('-', '_'),
                default=envs.get(
                    OPTIONS_LIST[o]['env'],
                    utils.env(OPTIONS_LIST[o]['env']),
                ),
                help=_('%(help)s\n(Env: %(env)s)') % {
                    'help': OPTIONS_LIST[o]['help'],
                    'env': OPTIONS_LIST[o]['env'],
                },
            )
    # add tenant-related options for compatibility
    # this is deprecated but still used in some tempest tests...
    parser.add_argument(
        '--os-tenant-name',
        metavar='<auth-tenant-name>',
        dest='os_project_name',
        help=argparse.SUPPRESS,
    )
    parser.add_argument(
        '--os-tenant-id',
        metavar='<auth-tenant-id>',
        dest='os_project_id',
        help=argparse.SUPPRESS,
    )
    return parser
    def get_parser(self, prog_name):
        parser = super(DeleteNode, self).get_parser(prog_name)
        parser.add_argument('nodes', metavar='<node>', nargs="+",
                            help=_('Node ID(s) to delete'))
        parser.add_argument('--stack', dest='stack',
                            help=_('Name or ID of heat stack to scale '
                                   '(default=Env: OVERCLOUD_STACK_NAME)'),
                            default=utils.env('OVERCLOUD_STACK_NAME',
                                              default='overcloud'))
        parser.add_argument(
            '--templates', nargs='?', const=constants.TRIPLEO_HEAT_TEMPLATES,
            help=_("The directory containing the Heat templates to deploy. "
                   "This argument is deprecated. The command now utilizes "
                   "a deployment plan, which should be updated prior to "
                   "running this command, should that be required. Otherwise "
                   "this argument will be silently ignored."),
        )
        parser.add_argument(
            '-e', '--environment-file', metavar='<HEAT ENVIRONMENT FILE>',
            action='append', dest='environment_files',
            help=_("Environment files to be passed to the heat stack-create "
                   "or heat stack-update command. (Can be specified more than "
                   "once.) This argument is deprecated. The command now "
                   "utilizes a deployment plan, which should be updated prior "
                   "to running this command, should that be required. "
                   "Otherwise this argument will be silently ignored."),
        )

        return parser
Ejemplo n.º 9
0
    def take_action(self, parsed_args):
        self.log.debug('take_action(%s)', parsed_args)
        heat_client = self.app.client_manager.orchestration
        msg = ('User did not confirm snapshot delete '
               '%sso taking no action.')
        try:
            if not parsed_args.yes and sys.stdin.isatty():
                sys.stdout.write(
                    _('Are you sure you want to delete the snapshot of this '
                      'stack [Y/N]?'))
                prompt_response = sys.stdin.readline().lower()
                if not prompt_response.startswith('y'):
                    self.log.info(msg, '')
                    return
        except KeyboardInterrupt:  # ctrl-c
            self.log.info(msg, '(ctrl-c) ')
            return
        except EOFError:  # ctrl-d
            self.log.info(msg, '(ctrl-d) ')
            return

        try:
            heat_client.stacks.snapshot_delete(parsed_args.stack,
                                               parsed_args.snapshot)
        except heat_exc.HTTPNotFound:
            raise exc.CommandError(_('Snapshot ID <%(snapshot_id)s> not found '
                                     'for stack <%(stack_id)s>')
                                   % {'snapshot_id': parsed_args.snapshot,
                                      'stack_id': parsed_args.stack})
 def get_parser(self, prog_name):
     parser = super(DeployPlan, self).get_parser(prog_name)
     parser.add_argument('name', help=_('The name of the plan to deploy.'))
     parser.add_argument('--timeout', '-t', metavar='<TIMEOUT>',
                         type=int,
                         help=_('Deployment timeout in minutes.'))
     return parser
 def get_parser(self, prog_name):
     parser = super(DeleteOvercloud, self).get_parser(prog_name)
     parser.add_argument('stack', nargs='?',
                         help=_('Name or ID of heat stack to delete'
                                '(default=Env: OVERCLOUD_STACK_NAME)'),
                         default=osc_utils.env('OVERCLOUD_STACK_NAME'))
     parser.add_argument('-y', '--yes',
                         help=_('Skip yes/no prompt (assume yes).'),
                         default=False,
                         action="store_true")
     return parser
Ejemplo n.º 12
0
 def get_parser(self, prog_name):
     parser = super(ResourceMetadata, self).get_parser(prog_name)
     parser.add_argument(
         'stack',
         metavar='<stack>',
         help=_('Stack to display (name or ID)'),
     )
     parser.add_argument(
         'resource',
         metavar='<resource>',
         help=_('Name of the resource to show the metadata for'))
     return parser
Ejemplo n.º 13
0
def sort_items(items, sort_str, sort_type=None):
    """Sort items based on sort keys and sort directions given by sort_str.

    :param items: a list or generator object of items
    :param sort_str: a string defining the sort rules, the format is
        '<key1>:[direction1],<key2>:[direction2]...', direction can be 'asc'
        for ascending or 'desc' for descending, if direction is not given,
        it's ascending by default
    :return: sorted items
    """
    if not sort_str:
        return items
    # items may be a generator object, transform it to a list
    items = list(items)
    sort_keys = sort_str.strip().split(',')
    for sort_key in reversed(sort_keys):
        reverse = False
        if ':' in sort_key:
            sort_key, direction = sort_key.split(':', 1)
            if not sort_key:
                msg = _("'<empty string>'' is not a valid sort key")
                raise exceptions.CommandError(msg)
            if direction not in ['asc', 'desc']:
                if not direction:
                    direction = "<empty string>"
                msg = _(
                    "'%(direction)s' is not a valid sort direction for "
                    "sort key %(sort_key)s, use 'asc' or 'desc' instead"
                )
                raise exceptions.CommandError(msg % {
                    'direction': direction,
                    'sort_key': sort_key,
                })
            if direction == 'desc':
                reverse = True

        def f(x):
            # Attempts to convert items to same 'sort_type' if provided.
            # This is due to Python 3 throwing TypeError if you attempt to
            # compare different types
            item = get_field(x, sort_key)
            if sort_type and not isinstance(item, sort_type):
                try:
                    item = sort_type(item)
                except Exception:
                    # Can't convert, so no sensible way to compare
                    item = sort_type()
            return item

        items.sort(key=f, reverse=reverse)

    return items
Ejemplo n.º 14
0
 def get_parser(self, prog_name):
     parser = super(CreateSnapshot, self).get_parser(prog_name)
     parser.add_argument(
         'stack',
         metavar='<stack>',
         help=_('Name or ID of stack')
     )
     parser.add_argument(
         '--name',
         metavar='<name>',
         help=_('Name of snapshot')
     )
     return parser
Ejemplo n.º 15
0
 def get_parser(self, prog_name):
     parser = super(DeleteSnapshot, self).get_parser(prog_name)
     parser.add_argument(
         'stack',
         metavar='<stack>',
         help=_('Name or ID of stack')
     )
     parser.add_argument(
         'snapshot',
         metavar='<snapshot>',
         help=_('ID of stack snapshot')
     )
     return parser
Ejemplo n.º 16
0
 def get_parser(self, prog_name):
     parser = super(ShowSnapshot, self).get_parser(prog_name)
     parser.add_argument(
         'stack',
         metavar='<stack>',
         help=_('Name or ID of stack containing the snapshot')
     )
     parser.add_argument(
         'snapshot',
         metavar='<snapshot>',
         help=_('ID of the snapshot to show')
     )
     return parser
 def get_parser(self, prog_name):
     parser = super(ProvideNode, self).get_parser(prog_name)
     group = parser.add_mutually_exclusive_group(required=True)
     group.add_argument('node_uuids',
                        nargs="*",
                        metavar="<node_uuid>",
                        default=[],
                        help=_('Baremetal Node UUIDs for the node(s) to be '
                               'provided'))
     group.add_argument("--all-manageable",
                        action='store_true',
                        help=_("Provide all nodes currently in 'manageable'"
                               " state"))
     return parser
Ejemplo n.º 18
0
    def get_parser(self, prog_name):
        parser = super(ImportBaremetal, self).get_parser(prog_name)
        parser.add_argument('-s', '--service-host', dest='service_host',
                            help=_('Deprecated, this argument has no impact.'))
        parser.add_argument(
            '--json', dest='json', action='store_true',
            help=_('Deprecated, now detected via file extension.'))
        parser.add_argument(
            '--csv', dest='csv', action='store_true',
            help=_('Deprecated, now detected via file extension.'))
        parser.add_argument('--deploy-kernel',
                            default='bm-deploy-kernel',
                            help=_('Image with deploy kernel.'))
        parser.add_argument('--deploy-ramdisk',
                            default='bm-deploy-ramdisk',
                            help=_('Image with deploy ramdisk.'))
        parser.add_argument('--no-deploy-image', action='store_true',
                            help=_('Skip setting the deploy kernel and '
                                   'ramdisk.'))
        parser.add_argument('--instance-boot-option',
                            choices=['local', 'netboot'], default='local',
                            help=_('Whether to set instances for booting from '
                                   'local hard drive (local) or network '
                                   '(netboot).'))
        parser.add_argument('file_in', type=argparse.FileType('r'))
        parser.add_argument(
            '--initial-state',
            choices=['enroll', 'available'],
            default='available',
            help=_('Provision state for newly-enrolled nodes.')
        )

        return parser
Ejemplo n.º 19
0
    def __call__(self, parser, namespace, values, metavar=None):
        # Make sure we have an empty list rather than None
        if getattr(namespace, self.dest, None) is None:
            setattr(namespace, self.dest, [])

        params = {}
        for kv in values.split(','):
            # Add value if an assignment else raise ArgumentTypeError
            if '=' in kv:
                kv_list = kv.split('=', 1)
                # NOTE(qtang): Prevent null key setting in property
                if '' == kv_list[0]:
                    msg = _("Each property key must be specified: %s")
                    raise argparse.ArgumentTypeError(msg % str(kv))
                else:
                    params.update([kv_list])
            else:
                msg = _(
                    "Expected comma separated 'key=value' pairs, but got: %s"
                )
                raise argparse.ArgumentTypeError(msg % str(kv))

        # Check key validation
        valid_keys = self.required_keys | self.optional_keys
        if valid_keys:
            invalid_keys = [k for k in params if k not in valid_keys]
            if invalid_keys:
                msg = _(
                    "Invalid keys %(invalid_keys)s specified.\n"
                    "Valid keys are: %(valid_keys)s"
                )
                raise argparse.ArgumentTypeError(msg % {
                    'invalid_keys': ', '.join(invalid_keys),
                    'valid_keys': ', '.join(valid_keys),
                })

        if self.required_keys:
            missing_keys = [k for k in self.required_keys if k not in params]
            if missing_keys:
                msg = _(
                    "Missing required keys %(missing_keys)s.\n"
                    "Required keys are: %(required_keys)s"
                )
                raise argparse.ArgumentTypeError(msg % {
                    'missing_keys': ', '.join(missing_keys),
                    'required_keys': ', '.join(self.required_keys),
                })

        # Update the dest dict
        getattr(namespace, self.dest, []).append(params)
    def get_parser(self, prog_name):
        parser = super(CreatePlan, self).get_parser(prog_name)
        parser.add_argument(
            'name',
            help=_('The name of the plan, which is used for the object '
                   'storage container, workflow environment and orchestration '
                   'stack names.'))
        parser.add_argument(
            '--templates',
            help=_('The directory containing the Heat templates to deploy. '
                   'If this isn\'t provided, the templates packaged on the '
                   'Undercloud will be used.'),
        )

        return parser
    def take_action(self, parsed_args):
        self.log.debug("take_action(%s)" % parsed_args)

        if parsed_args.file_in.name.endswith('.json'):
            params = simplejson.load(parsed_args.file_in)
        elif parsed_args.file_in.name.endswith('.yaml'):
            params = yaml.safe_load(parsed_args.file_in)
        else:
            raise exceptions.InvalidConfiguration(
                _("Invalid file extension for %s, must be json or yaml") %
                parsed_args.file_in.name)

        if 'parameter_defaults' in params:
            params = params['parameter_defaults']

        clients = self.app.client_manager
        workflow_client = clients.workflow_engine

        name = parsed_args.name

        parameters.update_parameters(
            workflow_client,
            container=name,
            parameters=params
        )
Ejemplo n.º 22
0
def backward_compat_col_showone(show_object, columns, column_map):
    """Convert the output object to keep column backward compatibility.

    Replace the new column name of output object by old name, so that
    the object can continue to support to show the old column name by
    --column/-c option with old name, like: volume show -c 'display_name'

    :param show_object: The object to be output in create/show commands.
    :param columns: The columns to be output.
    :param column_map: The key of map is old column name, the value is new
        column name, like: {'old_col': 'new_col'}
    """
    if not columns:
        return show_object

    show_object = copy.deepcopy(show_object)
    for old_col, new_col in six.iteritems(column_map):
        if old_col in columns:
            LOG.warning(_('The column "%(old_column)s" was deprecated, '
                          'please use "%(new_column)s" replace.') % {
                              'old_column': old_col,
                              'new_column': new_col}
                        )
            if new_col in show_object:
                show_object.update({old_col: show_object.pop(new_col)})
    return show_object
Ejemplo n.º 23
0
def backward_compat_col_lister(column_headers, columns, column_map):
    """Convert the column headers to keep column backward compatibility.

    Replace the new column name of column headers by old name, so that
    the column headers can continue to support to show the old column name by
    --column/-c option with old name, like: volume list -c 'Display Name'

    :param column_headers: The column headers to be output in list command.
    :param columns: The columns to be output.
    :param column_map: The key of map is old column name, the value is new
            column name, like: {'old_col': 'new_col'}
    """
    if not columns:
        return column_headers
    # NOTE(RuiChen): column_headers may be a tuple in some code, like:
    #                volume v1, convert it to a list in order to change
    #                the column name.
    column_headers = list(column_headers)
    for old_col, new_col in six.iteritems(column_map):
        if old_col in columns:
            LOG.warning(_('The column "%(old_column)s" was deprecated, '
                          'please use "%(new_column)s" replace.') % {
                              'old_column': old_col,
                              'new_column': new_col}
                        )
            if new_col in column_headers:
                column_headers[column_headers.index(new_col)] = old_col
    return column_headers
 def get_parser(self, prog_name):
     parser = super(CephUpgrade, self).get_parser(prog_name)
     parser.add_argument('--container-registry-file',
                         dest='container_registry_file',
                         default=None,
                         help=_("Optional path to file with container "
                                "registry data for the update"),
                         )
     parser.add_argument('--ceph-ansible-playbook',
                         action="store",
                         default="/usr/share/ceph-ansible"
                                 "/infrastructure-playbooks"
                                 "/rolling_update.yml",
                         help=_('Path to switch the ceph-ansible playbook '
                                'used for update. '))
     return parser
Ejemplo n.º 25
0
def backward_compat_col_showone(show_object, columns, column_map):
    """Convert the output object to keep column backward compatibility.

    Replace the new column name of output object by old name, so that
    the object can continue to support to show the old column name by
    --column/-c option with old name, like: volume show -c 'display_name'

    :param show_object: The object to be output in create/show commands.
    :param columns: The columns to be output.
    :param column_map: The key of map is old column name, the value is new
        column name, like: {'old_col': 'new_col'}
    """
    if not columns:
        return show_object

    show_object = copy.deepcopy(show_object)
    for old_col, new_col in six.iteritems(column_map):
        if old_col in columns:
            LOG.warning(_('The column "%(old_column)s" was deprecated, '
                          'please use "%(new_column)s" replace.') % {
                              'old_column': old_col,
                              'new_column': new_col}
                        )
            if new_col in show_object:
                show_object.update({old_col: show_object.pop(new_col)})
    return show_object
Ejemplo n.º 26
0
    def take_action(self, parsed_args):
        self.log.debug('take_action(%s)', parsed_args)

        client = self.app.client_manager.orchestration

        fields = {
            'nested_depth': parsed_args.nested_depth,
            'with_detail': parsed_args.long,
            'filters': heat_utils.format_parameters(parsed_args.filter),
        }

        try:
            resources = client.resources.list(parsed_args.stack, **fields)
        except heat_exc.HTTPNotFound:
            msg = _('Stack not found: %s') % parsed_args.stack
            raise exc.CommandError(msg)

        if parsed_args.formatter == 'dot':
            return [], resources

        columns = ['physical_resource_id', 'resource_type', 'resource_status',
                   'updated_time']

        if len(resources) >= 1 and not hasattr(resources[0], 'resource_name'):
            columns.insert(0, 'logical_resource_id')
        else:
            columns.insert(0, 'resource_name')

        if parsed_args.nested_depth or parsed_args.long:
            columns.append('stack_name')

        return (
            columns,
            (utils.get_item_properties(r, columns) for r in resources)
        )
Ejemplo n.º 27
0
 def get_parser(self, prog_name):
     parser = super(TripleOContainerImageShow, self).get_parser(prog_name)
     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(dest="image_to_inspect",
                         metavar='<image to inspect>',
                         help=_("Image to be inspected, for example: "
                                "docker.io/library/centos:7 or "
                                "docker://docker.io/library/centos:7"))
     return parser
def _check_memory():
    """Check system memory

    The undercloud will not run properly in less than 8 GB of memory.
    This function verifies that at least that much is available before
    proceeding with install.
    """
    mem = psutil.virtual_memory()
    swap = psutil.swap_memory()
    total_mb = (mem.total + swap.total) / 1024 / 1024
    if total_mb < REQUIRED_MB:
        LOG.error(
            _('At least {0} MB of memory is required for undercloud '
              'installation.  A minimum of 8 GB is recommended. '
              'Only detected {1} MB').format(REQUIRED_MB, total_mb))
        raise RuntimeError(_('Insufficient memory available'))
Ejemplo n.º 29
0
 def get_parser(self, prog_name):
     parser = super(ExportPlan, self).get_parser(prog_name)
     parser.add_argument('plan',
                         metavar='<name>',
                         help=_('Name of the plan to export.'))
     parser.add_argument('--output-file',
                         '-o',
                         metavar='<output file>',
                         help=_('Name of the output file for export. '
                                'It will default to "<name>.tar.gz".'))
     parser.add_argument('--force-overwrite',
                         '-f',
                         action='store_true',
                         default=False,
                         help=_('Overwrite output file if it exists.'))
     return parser
    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 take_action(self, parsed_args):
        self.log.debug("take_action({args})".format(args=parsed_args))

        self._validate_args(parsed_args)

        if not parsed_args.yes:
            confirm = utils.prompt_user_for_confirmation(message=_(
                "Are you sure you want to delete this overcloud "
                "[y/N]? "),
                                                         logger=self.log)
            if not confirm:
                raise oscexc.CommandError("Action not confirmed, exiting.")

        if parsed_args.skip_ipa_cleanup:
            playbooks = ["cli-overcloud-delete.yaml"]
        else:
            # Order is important, let's make sure we cleanup FreeIPA before we
            # start removing infrastructure.
            playbooks = ["cli-cleanup-ipa.yml", "cli-overcloud-delete.yaml"]

        with utils.TempDirs() as tmp:
            utils.run_ansible_playbook(
                playbooks,
                constants.ANSIBLE_INVENTORY,
                workdir=tmp,
                playbook_dir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS,
                verbosity=utils.playbook_verbosity(self=self),
                extra_vars={"stack_name": parsed_args.stack})

        print("Success.")
Ejemplo n.º 32
0
 def get_parser(self, prog_name):
     parser = super(ValidateInstackEnv, self).get_parser(prog_name)
     parser.add_argument(
         '-f', '--file', dest='instackenv',
         help=_("Path to the instackenv.json file."),
         default='instackenv.json')
     return parser
Ejemplo n.º 33
0
 def get_parser(self, prog_name):
     parser = super(DeletePlan, self).get_parser(prog_name)
     parser.add_argument('plans',
                         metavar='<name>',
                         nargs="+",
                         help=_('Name of the plan(s) to delete'))
     return parser
 def get_parser(self, prog_name):
     parser = super(ValidateOvercloudNetenv, self).get_parser(prog_name)
     parser.add_argument(
         '-f', '--file', dest='netenv',
         help=_("Path to the network environment file"),
         default='network-environment.yaml')
     return parser
 def get_parser(self, prog_name):
     parser = super(DeployPlan, self).get_parser(prog_name)
     parser.add_argument('name', help=_('The name of the plan to deploy.'))
     parser.add_argument('--timeout',
                         '-t',
                         metavar='<TIMEOUT>',
                         type=int,
                         default=240,
                         help=_('Deployment timeout in minutes.'))
     parser.add_argument('--run-validations',
                         action='store_true',
                         default=False,
                         help=_('Run the pre-deployment validations. These '
                                'external validations are from the TripleO '
                                'Validations project.'))
     return parser
def _validate_no_ip_change():
    """Disallow provisioning interface IP changes

    Changing the provisioning network IP causes a number of issues, so we
    need to disallow it early in the install before configurations start to
    be changed.
    """
    if CONF.net_config_override:
        os_net_config_file = CONF.net_config_override
    else:
        os_net_config_file = '/etc/os-net-config/config.json'
    # Nothing to do if we haven't already installed
    if not os.path.isfile(os.path.expanduser(os_net_config_file)):
        return
    try:
        with open(os_net_config_file) as f:
            network_config = json.loads(f.read())
        ctlplane = [
            i for i in network_config.get('network_config', [])
            if i['name'] == 'br-ctlplane'
        ][0]
    except ValueError:
        # File was empty
        return
    except IndexError:
        # Nothing to check if br-ctlplane wasn't configured
        return
    existing_ip = ctlplane['addresses'][0]['ip_netmask']
    if existing_ip != CONF.local_ip:
        message = _('Changing the local_ip is not allowed.  Existing IP: '
                    '{0}, Configured IP: {1}').format(existing_ip,
                                                      CONF.local_ip)
        LOG.error(message)
        raise FailedValidation(message)
Ejemplo n.º 37
0
 def get_parser(self, prog_name):
     parser = super(UpgradePrepare, self).get_parser(prog_name)
     parser.add_argument('--container-registry-file',
                         dest='container_registry_file',
                         default=None,
                         help=_("File which contains the container "
                                "registry data for the upgrade"),
                         )
     parser.add_argument('--ceph-ansible-playbook',
                         action="store",
                         default="/usr/share/ceph-ansible"
                                 "/site-docker.yml.sample",
                         help=_('Path to switch the ceph-ansible playbook '
                                'used for upgrade. '),
                         )
     return parser
 def wrapped(user_input):
     try:
         return datetime.strptime(user_input, date_format)
     except ValueError:
         tpl = _("%s is not a valid date with format %s")
         msg = tpl % (user_input, date_format)
     raise argparse.ArgumentTypeError(msg)
Ejemplo n.º 39
0
def backward_compat_col_lister(column_headers, columns, column_map):
    """Convert the column headers to keep column backward compatibility.

    Replace the new column name of column headers by old name, so that
    the column headers can continue to support to show the old column name by
    --column/-c option with old name, like: volume list -c 'Display Name'

    :param column_headers: The column headers to be output in list command.
    :param columns: The columns to be output.
    :param column_map: The key of map is old column name, the value is new
            column name, like: {'old_col': 'new_col'}
    """
    if not columns:
        return column_headers
    # NOTE(RuiChen): column_headers may be a tuple in some code, like:
    #                volume v1, convert it to a list in order to change
    #                the column name.
    column_headers = list(column_headers)
    for old_col, new_col in six.iteritems(column_map):
        if old_col in columns:
            LOG.warning(_('The column "%(old_column)s" was deprecated, '
                          'please use "%(new_column)s" replace.') % {
                              'old_column': old_col,
                              'new_column': new_col}
                        )
            if new_col in column_headers:
                column_headers[column_headers.index(new_col)] = old_col
    return column_headers
Ejemplo n.º 40
0
    def find(
        self,
        path,
        value=None,
        attr=None,
    ):
        """Find a single resource by name or ID

        :param string path:
            The API-specific portion of the URL path
        :param string value:
            search expression (required, really)
        :param string attr:
            name of attribute for secondary search
        """

        try:
            ret = self._request('GET', "/%s/%s" % (path, value)).json()
            if isinstance(ret, dict):
                # strip off the enclosing dict
                key = list(ret.keys())[0]
                ret = ret[key]
        except (
            ksa_exceptions.NotFound,
            ksa_exceptions.BadRequest,
        ):
            kwargs = {attr: value}
            try:
                ret = self.find_one(path, **kwargs)
            except ksa_exceptions.NotFound:
                msg = _("%s not found") % value
                raise exceptions.NotFound(msg)

        return ret
Ejemplo n.º 41
0
    def find(
        self,
        path,
        value=None,
        attr=None,
    ):
        """Find a single resource by name or ID

        :param string path:
            The API-specific portion of the URL path
        :param string value:
            search expression (required, really)
        :param string attr:
            name of attribute for secondary search
        """

        try:
            ret = self._request('GET', "/%s/%s" % (path, value)).json()
            if isinstance(ret, dict):
                # strip off the enclosing dict
                key = list(ret.keys())[0]
                ret = ret[key]
        except (
            ksa_exceptions.NotFound,
            ksa_exceptions.BadRequest,
        ):
            kwargs = {attr: value}
            try:
                ret = self.find_one(path, **kwargs)
            except ksa_exceptions.NotFound:
                msg = _("%s not found") % value
                raise exceptions.NotFound(msg)

        return ret
    def __call__(self, parser, namespace, values, metavar=None):
        # Make sure we have an empty list rather than None
        if getattr(namespace, self.dest, None) is None:
            setattr(namespace, self.dest, [])

        params = {}
        for kv in values.split(','):
            # Add value if an assignment else raise ArgumentTypeError
            if '=' in kv:
                kv_list = kv.split('=', 1)
                # NOTE(qtang): Prevent null key setting in property
                if '' == kv_list[0]:
                    msg = _("Each property key must be specified: %s")
                    raise argparse.ArgumentTypeError(msg % str(kv))
                else:
                    params.update([kv_list])
            else:
                msg = _(
                    "Expected comma separated 'key=value' pairs, but got: %s")
                raise argparse.ArgumentTypeError(msg % str(kv))

        # Check key validation
        valid_keys = self.required_keys | self.optional_keys
        if valid_keys:
            invalid_keys = [k for k in params if k not in valid_keys]
            if invalid_keys:
                msg = _("Invalid keys %(invalid_keys)s specified.\n"
                        "Valid keys are: %(valid_keys)s")
                raise argparse.ArgumentTypeError(
                    msg % {
                        'invalid_keys': ', '.join(invalid_keys),
                        'valid_keys': ', '.join(valid_keys),
                    })

        if self.required_keys:
            missing_keys = [k for k in self.required_keys if k not in params]
            if missing_keys:
                msg = _("Missing required keys %(missing_keys)s.\n"
                        "Required keys are: %(required_keys)s")
                raise argparse.ArgumentTypeError(
                    msg % {
                        'missing_keys': ', '.join(missing_keys),
                        'required_keys': ', '.join(self.required_keys),
                    })

        # Update the dest dict
        getattr(namespace, self.dest, []).append(params)
def _validate_interface_exists():
    """Validate the provided local interface exists"""
    if (not CONF.net_config_override
            and CONF.local_interface not in netifaces.interfaces()):
        message = (_('Invalid local_interface specified. '
                     '%s is not available.') % CONF.local_interface)
        LOG.error(message)
        raise FailedValidation(message)
Ejemplo n.º 44
0
    def get_parser(self, prog_name):
        parser = super(Attach, self).get_parser(prog_name)
        parser.add_argument("node",
                            metavar="<node>",
                            help=_("Name or UUID of the node"))
        parser.add_argument("volume",
                            metavar="<volume>",
                            help=_("Name or UUID of the volume"))
        parser.add_argument("--network",
                            metavar="<network>",
                            help=_("Name or UUID of the network"))
        parser.add_argument('--port',
                            dest='port',
                            metavar='<port>',
                            help=_("Name or UUID of the port"))

        return parser
Ejemplo n.º 45
0
 def deprecated_option_warning(self, old_option, new_option):
     """Emit a warning for use of a deprecated option"""
     self.log.warning(
         _("The %(old)s option is deprecated, please use %(new)s instead.")
         % {
             'old': old_option,
             'new': new_option
         })
Ejemplo n.º 46
0
def read_blob_file_contents(blob_file):
    try:
        with open(blob_file) as file:
            blob = file.read().strip()
        return blob
    except IOError:
        msg = _("Error occurred trying to read from file %s")
        raise exceptions.CommandError(msg % blob_file)
Ejemplo n.º 47
0
 def is_ip(value, param_name):
     try:
         netaddr.IPAddress(value)
     except netaddr.core.AddrFormatError:
         msg = (_('{0} "{1}" must be a valid IP address').format(
             param_name, value))
         LOG.error(msg)
         raise FailedValidation(msg)
Ejemplo n.º 48
0
def _validate_inspection_range(subnet_props):
    start = netaddr.IPAddress(subnet_props.inspection_iprange.split(',')[0])
    end = netaddr.IPAddress(subnet_props.inspection_iprange.split(',')[1])
    if start >= end:
        message = (_('Invalid inspection range specified, inspection_iprange '
                     '"{0}" does not come before "{1}"').format(start, end))
        LOG.error(message)
        raise FailedValidation(message)
Ejemplo n.º 49
0
def read_blob_file_contents(blob_file):
    try:
        with open(blob_file) as file:
            blob = file.read().strip()
        return blob
    except IOError:
        msg = _("Error occurred trying to read from file %s")
        raise exceptions.CommandError(msg % blob_file)
    def __call__(self, parser, namespace, values, option_string=None):
        # Make sure we have an empty dict rather than None
        if getattr(namespace, self.dest, None) is None:
            setattr(namespace, self.dest, {})

        # Add value if an assignment else remove it
        if '=' in values:
            values_list = values.split('=', 1)
            # NOTE(qtang): Prevent null key setting in property
            if '' == values_list[0]:
                msg = _("Property key must be specified: %s")
                raise argparse.ArgumentTypeError(msg % str(values))
            else:
                getattr(namespace, self.dest, {}).update([values_list])
        else:
            msg = _("Expected 'key=value' type, but got: %s")
            raise argparse.ArgumentTypeError(msg % str(values))
Ejemplo n.º 51
0
 def get_parser(self, prog_name):
     parser = super(ListSnapshot, self).get_parser(prog_name)
     parser.add_argument(
         'stack',
         metavar='<stack>',
         help=_('Name or ID of stack containing the snapshots')
     )
     return parser
 def get_parser(self, prog_name):
     parser = super(ValidateOvercloudNetenv, self).get_parser(prog_name)
     parser.add_argument('-f',
                         '--file',
                         dest='netenv',
                         help=_("Path to the network environment file"),
                         default='network-environment.yaml')
     return parser
Ejemplo n.º 53
0
 def get_parser(self, prog_name):
     parser = super(TripleOImagePrepareDefault, self).get_parser(prog_name)
     parser.add_argument(
         "--output-env-file",
         dest="output_env_file",
         metavar='<file path>',
         help=_("File to write environment file containing default "
                "ContainerImagePrepare value."),
     )
     parser.add_argument(
         '--local-push-destination',
         dest='push_destination',
         action='store_true',
         default=False,
         help=_('Include a push_destination to trigger upload to a local '
                'registry.'))
     return parser
Ejemplo n.º 54
0
    def get_parser(self, prog_name):
        parser = super(DeleteNode, self).get_parser(prog_name)
        parser.add_argument('nodes',
                            metavar='<node>',
                            nargs="+",
                            help=_('Node ID(s) to delete'))
        parser.add_argument('--stack',
                            dest='stack',
                            help=_('Name or ID of heat stack to scale '
                                   '(default=Env: OVERCLOUD_STACK_NAME)'),
                            default=utils.env('OVERCLOUD_STACK_NAME',
                                              default='overcloud'))
        parser.add_argument(
            '--templates',
            nargs='?',
            const=constants.TRIPLEO_HEAT_TEMPLATES,
            help=_("The directory containing the Heat templates to deploy. "
                   "This argument is deprecated. The command now utilizes "
                   "a deployment plan, which should be updated prior to "
                   "running this command, should that be required. Otherwise "
                   "this argument will be silently ignored."),
        )
        parser.add_argument(
            '-e',
            '--environment-file',
            metavar='<HEAT ENVIRONMENT FILE>',
            action='append',
            dest='environment_files',
            help=_("Environment files to be passed to the heat stack-create "
                   "or heat stack-update command. (Can be specified more than "
                   "once.) This argument is deprecated. The command now "
                   "utilizes a deployment plan, which should be updated prior "
                   "to running this command, should that be required. "
                   "Otherwise this argument will be silently ignored."),
        )

        parser.add_argument(
            '--timeout',
            metavar='<TIMEOUT>',
            type=int,
            default=constants.STACK_TIMEOUT,
            dest='timeout',
            help=_("Timeout in minutes to wait for the nodes to be deleted. "
                   "Keep in mind that due to keystone session duration "
                   "that timeout has an upper bound of 4 hours "))
        return parser
def _validate_dhcp_range(subnet_props):
    start = netaddr.IPAddress(subnet_props.dhcp_start)
    end = netaddr.IPAddress(subnet_props.dhcp_end)
    if start >= end:
        message = (_('Invalid dhcp range specified, dhcp_start "{0}" does '
                     'not come before dhcp_end "{1}"').format(start, end))
        LOG.error(message)
        raise FailedValidation(message)
Ejemplo n.º 56
0
 def get_parser(self, prog_name):
     parser = super(GetDeploymentFailures, self).get_parser(prog_name)
     parser.add_argument('--plan',
                         '--stack',
                         help=_('Name of the stack/plan. '
                                '(default: overcloud)'),
                         default='overcloud')
     return parser
Ejemplo n.º 57
0
def add_project_owner_option_to_parser(parser):
    """Register project and project domain options.

    :param parser: argparse.Argument parser object.
    """
    parser.add_argument(
        '--project',
        metavar='<project>',
        help=_("Owner's project (name or ID)")
    )
    parser.add_argument(
        '--project-domain',
        metavar='<project-domain>',
        help=_('Domain the project belongs to (name or ID). '
               'This can be used in case collisions between project names '
               'exist.'),
    )
Ejemplo n.º 58
0
    def __call__(self, parser, namespace, values, option_string=None):
        # Make sure we have an empty dict rather than None
        if getattr(namespace, self.dest, None) is None:
            setattr(namespace, self.dest, {})

        # Add value if an assignment else remove it
        if '=' in values:
            values_list = values.split('=', 1)
            # NOTE(qtang): Prevent null key setting in property
            if '' == values_list[0]:
                msg = _("Property key must be specified: %s")
                raise argparse.ArgumentTypeError(msg % str(values))
            else:
                getattr(namespace, self.dest, {}).update([values_list])
        else:
            msg = _("Expected 'key=value' type, but got: %s")
            raise argparse.ArgumentTypeError(msg % str(values))
Ejemplo n.º 59
0
def get_field(item, field):
    try:
        if isinstance(item, dict):
            return item[field]
        else:
            return getattr(item, field)
    except Exception:
        msg = _("Resource doesn't have field %s")
        raise exceptions.CommandError(msg % field)
Ejemplo n.º 60
0
def get_password(stdin, prompt=None, confirm=True):
    message = prompt or "User Password:"******"Repeat " + message)
                if first_pass == second_pass:
                    return first_pass
                msg = _("The passwords entered were not the same")
                print(msg)
        except EOFError:  # Ctl-D
            msg = _("Error reading password")
            raise exceptions.CommandError(msg)
    msg = _("No terminal detected attempting to read password")
    raise exceptions.CommandError(msg)