Esempio n. 1
0
    def take_action(self, parsed_args):
        masakari_client = self.app.client_manager.ha

        uuid = masakariclient_utils.get_uuid_by_name(masakari_client,
                                                     parsed_args.segment)

        attrs = {
            'name': parsed_args.name,
            'description': parsed_args.description,
            'recovery_method': parsed_args.recovery_method,
            'service_type': parsed_args.service_type,
        }

        if masakari_client.default_microversion:
            api_version = api_versions.APIVersion(
                masakari_client.default_microversion)
            if (api_version >= api_versions.APIVersion("1.2")
                    and parsed_args.is_enabled is not None):
                attrs['is_enabled'] = strutils.bool_from_string(
                    parsed_args.is_enabled, strict=True)

        # Remove not specified keys
        attrs = masakariclient_utils.remove_unspecified_items(attrs)

        try:
            masakari_client.update_segment(segment=uuid, **attrs)
        # Reraise. To unify exceptions with other functions.
        except sdk_exc.NotFoundException:
            LOG.debug(_("Segment is not found: %s"), parsed_args)
            raise sdk_exc.ResourceNotFound(_('No Segment found for %s') % uuid)
        except Exception as ex:
            LOG.debug(_("Failed to update segment: %s"), parsed_args)
            raise ex
        return _show_segment(masakari_client, uuid)
Esempio n. 2
0
 def get_parser(self, prog_name):
     parser = super(ListNotification, self).get_parser(prog_name)
     parser.add_argument(
         '--limit',
         metavar='<limit>',
         help=_('Limit the number of notifications returned')
     )
     parser.add_argument(
         '--marker',
         metavar='<id>',
         help=_('Only return notifications that appear after the given '
                'notification ID')
     )
     parser.add_argument(
         '--sort',
         metavar='<key>[:<direction>]',
         help=_("Sorting option which is a string containing a list of "
                "keys separated by commas. Each key can be optionally "
                "appended by a sort direction (:asc or :desc). The valid "
                "sort keys are: ['type', 'created_at', 'updated_at']")
     )
     parser.add_argument(
         '--filters',
         metavar='<"key1=value1;key2=value2...">',
         help=_("Filter parameters to apply on returned notifications. "
                "This can be specified multiple times, or once with "
                "parameters separated by a semicolon. The valid filter "
                "keys are: ['source_host_uuid', 'type', 'status', "
                "generated-since]"),
         action='append'
     )
     return parser
Esempio n. 3
0
    def take_action(self, parsed_args):
        masakari_client = self.app.client_manager.ha

        uuid = masakariclient_utils.get_uuid_by_name(masakari_client,
                                                     parsed_args.segment)

        attrs = {
            'name': parsed_args.name,
            'description': parsed_args.description,
            'recovery_method': parsed_args.recovery_method,
            'service_type': parsed_args.service_type,
        }
        # Remove not specified keys
        attrs = masakariclient_utils.remove_unspecified_items(attrs)

        try:
            masakari_client.update_segment(segment=uuid, **attrs)
        # Reraise. To unify exceptions with other functions.
        except sdk_exc.NotFoundException:
            LOG.debug(_("Segment is not found: %s"), parsed_args)
            raise sdk_exc.ResourceNotFound(_('No Segment found for %s') % uuid)
        except Exception as ex:
            LOG.debug(_("Failed to update segment: %s"), parsed_args)
            raise ex
        return _show_segment(masakari_client, uuid)
Esempio n. 4
0
    def take_action(self, parsed_args):
        masakari_client = self.app.client_manager.ha
        segment_id = masakariclient_utils.get_uuid_by_name(
            masakari_client, parsed_args.segment_id)
        uuid = masakariclient_utils.get_uuid_by_name(masakari_client,
                                                     parsed_args.host,
                                                     segment=segment_id)
        attrs = {
            'name': parsed_args.name,
            'type': parsed_args.type,
            'control_attributes': parsed_args.control_attributes,
            'reserved': parsed_args.reserved,
            'on_maintenance': parsed_args.on_maintenance,
        }
        # Remove not specified keys
        attrs = masakariclient_utils.remove_unspecified_items(attrs)

        try:
            masakari_client.update_host(uuid, segment_id=segment_id, **attrs)
        except sdk_exc.NotFoundException:
            # Reraise. To unify exceptions with other functions.
            LOG.debug(_("Segment host is not found: %s"), parsed_args)
            raise sdk_exc.ResourceNotFound(_('No Host found for %s') % uuid)
        except Exception as ex:
            LOG.debug(_("Failed to update segment host: %s"), parsed_args)
            raise ex

        return _show_host(masakari_client, segment_id, uuid)
Esempio n. 5
0
 def get_parser(self, prog_name):
     parser = super(ListHost, self).get_parser(prog_name)
     parser.add_argument('segment_id',
                         metavar='<segment_id>',
                         help=_('Name or ID of segment.'))
     parser.add_argument('--limit',
                         metavar='<limit>',
                         help=_('Limit the number of hosts returned'))
     parser.add_argument(
         '--marker',
         metavar='<id>',
         help=_('Only return hosts that appear after the given host ID'))
     parser.add_argument(
         '--sort',
         metavar='<key>[:<direction>]',
         help=_("Sorting option which is a string containing a list of "
                "keys separated by commas. Each key can be optionally "
                "appended by a sort direction (:asc or :desc). The valid "
                "sort keys are: ['type', 'name', 'created_at', "
                "'updated_at']"))
     parser.add_argument(
         '--filters',
         metavar='<"key1=value1;key2=value2...">',
         help=_("Filter parameters to apply on returned hosts. "
                "This can be specified multiple times, or once with "
                "parameters separated by a semicolon. The valid filter "
                "keys are: ['failover_segment_id', 'type', "
                "'on_maintenance', 'reserved']"),
         action='append')
     return parser
Esempio n. 6
0
 def get_parser(self, prog_name):
     parser = super(CreateNotification, self).get_parser(prog_name)
     parser.add_argument(
         'type',
         metavar='<type>',
         choices=['COMPUTE_HOST', 'VM', 'PROCESS'],
         help=_('Type of failure. The supported options are: '
                'COMPUTE_HOST, VM, PROCESS.')
     )
     parser.add_argument(
         'hostname',
         metavar='<hostname>',
         help=_('Hostname of notification.')
     )
     parser.add_argument(
         'generated_time',
         metavar='<generated_time>',
         help=_('Timestamp for notification. e.g. 2016-01-01T01:00:00.000')
     )
     parser.add_argument(
         'payload',
         metavar='<payload>',
         help=_('JSON string about failure event.')
     )
     return parser
    def test_do_host_delete_with_non_existing_uuid(self, mock_get_uuid_by_name,
                                                   mock_delete_host):
        mock_get_uuid_by_name.return_value = self.segment_vals.get('uuid')
        host_id = self.hosts_vals.get('uuid')
        expected_msg = _("Host '%(host_id)s' under failover_segment "
                         "'"
                         "%(seg_id)s' "
                         "could not be found") % {
                             'host_id': host_id,
                             'seg_id': mock_get_uuid_by_name
                         }

        def fake_delete_host(host_id,
                             mock_get_uuid_by_name,
                             ignore_missing=False):
            if not ignore_missing:
                raise sdk_exc.ResourceNotFound(expected_msg)

        mock_delete_host.side_effect = fake_delete_host
        service = mock.Mock()
        args = mock.Mock()

        original = sys.stdout
        sys.stdout = six.StringIO()
        ms.do_host_delete(service, args)
        output = sys.stdout.getvalue()
        sys.stdout = original
        self.assertIn(expected_msg, output)
Esempio n. 8
0
def _show_notification(masakari_client, notification_uuid):
    try:
        notification = masakari_client.get_notification(notification_uuid)
    except sdk_exc.ResourceNotFound:
        raise exceptions.CommandError(_('Notification not found: %s'
                                        ) % notification_uuid)

    formatters = {}
    columns = [
        'created_at',
        'updated_at',
        'notification_uuid',
        'type',
        'status',
        'source_host_uuid',
        'generated_time',
        'payload'
    ]

    if masakari_client.default_microversion:
        api_version = api_versions.APIVersion(
            masakari_client.default_microversion)
        if api_version >= api_versions.APIVersion("1.1"):
            columns.append('recovery_workflow_details')

    return columns, utils.get_dict_properties(notification.to_dict(), columns,
                                              formatters=formatters)
Esempio n. 9
0
    def __init__(self, version_str=None):
        """Create an API version object.

        :param version_str: String representation of APIVersionRequest.
                            Correct format is 'X.Y', where 'X' and 'Y'
                            are int values. None value should be used
                            to create Null APIVersionRequest, which is
                            equal to 0.0
        """
        self.ver_major = 0
        self.ver_minor = 0

        if version_str is not None:
            match = re.match(r"^([1-9]\d*)\.([1-9]\d*|0|latest)$", version_str)
            if match:
                self.ver_major = int(match.group(1))
                if match.group(2) == "latest":
                    # Infinity allows to easily determine latest version and
                    # doesn't require any additional checks in comparison
                    # methods.
                    self.ver_minor = float("inf")
                else:
                    self.ver_minor = int(match.group(2))
            else:
                msg = _("Invalid format of client version '%s'. "
                        "Expected format 'X.Y', where X is a major part and Y "
                        "is a minor part of version.") % version_str
                raise exception.UnsupportedVersion(msg)
Esempio n. 10
0
    def matches(self, min_version, max_version):
        """Matches the version object.

        Returns whether the version object represents a version
        greater than or equal to the minimum version and less than
        or equal to the maximum version.

        :param min_version: Minimum acceptable version.
        :param max_version: Maximum acceptable version.
        :returns: boolean

        If min_version is null then there is no minimum limit.
        If max_version is null then there is no maximum limit.
        If self is null then raise ValueError
        """

        if self.is_null():
            raise ValueError(_("Null APIVersion doesn't support 'matches'."))
        if max_version.is_null() and min_version.is_null():
            return True
        elif max_version.is_null():
            return min_version <= self
        elif min_version.is_null():
            return self <= max_version
        else:
            return min_version <= self <= max_version
Esempio n. 11
0
def format_sort_filter_params(parsed_args):
    queries = {}
    limit = parsed_args.limit
    marker = parsed_args.marker
    sort = parsed_args.sort
    if limit:
        queries['limit'] = limit
    if marker:
        queries['marker'] = marker

    sort_keys = []
    sort_dirs = []
    if sort:
        for sort_param in sort.split(','):
            sort_key, _sep, sort_dir = sort_param.partition(':')
            if not sort_dir:
                sort_dir = 'desc'
            elif sort_dir not in ('asc', 'desc'):
                raise exc.CommandError(_(
                    'Unknown sort direction: %s') % sort_dir)
            sort_keys.append(sort_key)
            sort_dirs.append(sort_dir)

        queries['sort_key'] = sort_keys
        queries['sort_dir'] = sort_dirs

    if parsed_args.filters:
        queries.update(_format_parameters(parsed_args.filters))

    return queries
Esempio n. 12
0
    def take_action(self, parsed_args):
        masakari_client = self.app.client_manager.ha
        attrs = {
            'name': parsed_args.name,
            'description': parsed_args.description,
            'recovery_method': parsed_args.recovery_method,
            'service_type': parsed_args.service_type,
        }

        if masakari_client.default_microversion:
            api_version = api_versions.APIVersion(
                masakari_client.default_microversion)
            if (api_version >= api_versions.APIVersion("1.2")
                    and parsed_args.is_enabled is not None):
                attrs['is_enabled'] = strutils.bool_from_string(
                    parsed_args.is_enabled, strict=True)

        # Remove not specified keys
        attrs = masakariclient_utils.remove_unspecified_items(attrs)

        try:
            segment = masakari_client.create_segment(**attrs)
        except Exception as ex:
            LOG.debug(_("Failed to create segment: %s"), parsed_args)
            raise ex
        return _show_segment(masakari_client, segment.uuid)
Esempio n. 13
0
 def get_parser(self, prog_name):
     parser = super(DeleteSegment, self).get_parser(prog_name)
     parser.add_argument('segment',
                         metavar='<segment>',
                         nargs='+',
                         help=_('Name or ID of segment(s) to delete'))
     return parser
Esempio n. 14
0
def _format_parameters(params, parse_semicolon=True):
    """Reformat parameters into dict of format expected by the API."""
    if not params:
        return {}

    if parse_semicolon:
        # expect multiple invocations of --parameters but fall back to ';'
        # delimited if only one --parameters is specified
        if len(params) == 1:
            params = params[0].split(';')

    parameters = {}
    for p in params:
        try:
            (n, v) = p.split(('='), 1)
        except ValueError:
            msg = _('Malformed parameter(%s). Use the key=value format.') % p
            raise exc.CommandError(msg)

        if n not in parameters:
            parameters[n] = v
        else:
            if not isinstance(parameters[n], list):
                parameters[n] = [parameters[n]]
            parameters[n].append(v)

    return parameters
Esempio n. 15
0
def _show_segment(masakari_client, segment_uuid):
    try:
        segment = masakari_client.get_segment(segment_uuid)
    except sdk_exc.ResourceNotFound:
        raise exceptions.CommandError(
            _('Segment is not found: %s') % segment_uuid)

    formatters = {}
    columns = [
        'created_at',
        'updated_at',
        'uuid',
        'name',
        'description',
        'id',
        'service_type',
        'recovery_method',
    ]

    if masakari_client.default_microversion:
        api_version = api_versions.APIVersion(
            masakari_client.default_microversion)
        if api_version >= api_versions.APIVersion("1.2"):
            columns.append('is_enabled')

    return columns, utils.get_dict_properties(segment.to_dict(),
                                              columns,
                                              formatters=formatters)
Esempio n. 16
0
def main(args=None):
    try:
        print(_("Deprecated: masakari CLI is deprecated and will be removed "
                "after Stein is released. Use openstack CLI instead."),
              file=sys.stderr)
        if args is None:
            args = sys.argv[1:]

        MasakariShell().main(args)
    except KeyboardInterrupt:
        print(_("KeyboardInterrupt masakari client"), sys.stderr)
        return 130
    except Exception as e:
        if '--debug' in args or '-d' in args:
            raise
        else:
            print(encodeutils.safe_encode(six.text_type(e)), sys.stderr)
        return 1
Esempio n. 17
0
 def get_parser(self, prog_name):
     parser = super(CreateSegment, self).get_parser(prog_name)
     parser.add_argument('name',
                         metavar='<name>',
                         help=_('Name of segment.'))
     parser.add_argument(
         'recovery_method',
         metavar='<recovery_method>',
         choices=['auto', 'reserved_host', 'auto_priority', 'rh_priority'],
         help=_('Recovery method of segment. The supported options are: '
                'auto, reserved_host, auto_priority, rh_priority.'))
     parser.add_argument('service_type',
                         metavar='<service_type>',
                         help=_('Service type of segment.'))
     parser.add_argument('--description',
                         metavar='<description>',
                         help=_('Description of segment.'))
     return parser
Esempio n. 18
0
def add_global_args(parser, version):
    # GLOBAL ARGUMENTS
    parser.add_argument('-h',
                        '--help',
                        action='store_true',
                        help=argparse.SUPPRESS)

    parser.add_argument(
        '--masakari-api-version',
        action='version',
        version=version,
        default=utils.env('MASAKARI_API_VERSION', default='1'),
        help=_('Version number for Masakari API to use, Default to "1".'))

    parser.add_argument('-d',
                        '--debug',
                        action='store_true',
                        default=False,
                        help=_('Print debugging output.'))
Esempio n. 19
0
 def get_parser(self, prog_name):
     parser = super(ShowHost, self).get_parser(prog_name)
     parser.add_argument('segment_id',
                         metavar='<segment_id>',
                         help=_('Name or ID of segment.'))
     parser.add_argument(
         'host',
         metavar='<host>',
         help='Name or ID of the Host',
     )
     return parser
Esempio n. 20
0
    def get_string(self):
        """Version string representation.

        Converts object to string representation which if used to create
        an APIVersion object results in the same version.
        """
        if self.is_null():
            raise ValueError(
                _("Null APIVersion cannot be converted to string."))
        elif self.is_latest():
            return "%s.%s" % (self.ver_major, "latest")
        return "%s.%s" % (self.ver_major, self.ver_minor)
Esempio n. 21
0
 def get_parser(self, prog_name):
     parser = super(UpdateHost, self).get_parser(prog_name)
     parser.add_argument('segment_id',
                         metavar='<segment_id>',
                         help=_('Name or ID of segment.'))
     parser.add_argument(
         'host',
         metavar='<host>',
         help='Name or ID of the Host',
     )
     parser.add_argument('--reserved',
                         metavar='<reserved>',
                         choices=['True', 'False'],
                         help=_(
                             'Host reservation. The supported options are: '
                             'True, False.'))
     parser.add_argument(
         '--on_maintenance',
         metavar='<on_maintenance>',
         choices=['True', 'False'],
         help=_('Maintenance status of host. The supported options are: '
                'True, False.'))
     parser.add_argument('--name',
                         metavar='<name>',
                         help=_('Name of host.'))
     parser.add_argument('--type',
                         metavar='<type>',
                         help=_('Type of host.'))
     parser.add_argument('--control_attributes',
                         metavar='<control_attributes>',
                         help=_('Attributes about control.'))
     return parser
Esempio n. 22
0
 def get_parser(self, prog_name):
     parser = super(UpdateSegment, self).get_parser(prog_name)
     parser.add_argument('segment',
                         metavar='<segment>',
                         help=_('Name or ID of the segment to update.'))
     parser.add_argument('--name',
                         metavar='<name>',
                         help=_('Name of segment.'))
     parser.add_argument(
         '--recovery_method',
         metavar='<recovery_method>',
         choices=['auto', 'reserved_host', 'auto_priority', 'rh_priority'],
         help=_('Recovery method of segment. The supported options are: '
                'auto, reserved_host, auto_priority, rh_priority'))
     parser.add_argument('--service_type',
                         metavar='<service_type>',
                         help=_('Service type of segment.'))
     parser.add_argument('--is_enabled',
                         metavar='<boolean>',
                         help=_('The enabled flag of this segment. '
                                'Supported after microversion 1.2.'))
     parser.add_argument('--description',
                         metavar='<description>',
                         help=_('Description of segment.'))
     return parser
Esempio n. 23
0
def main(args=None):
    try:
        if args is None:
            args = sys.argv[1:]

        MasakariShell().main(args)
    except KeyboardInterrupt:
        print(_("KeyboardInterrupt masakari client"), sys.stderr)
        return 130
    except Exception as e:
        if '--debug' in args or '-d' in args:
            raise
        else:
            print(encodeutils.safe_encode(six.text_type(e)), sys.stderr)
        return 1
Esempio n. 24
0
    def take_action(self, parsed_args):
        masakari_client = self.app.client_manager.ha
        attrs = {
            'name': parsed_args.name,
            'description': parsed_args.description,
            'recovery_method': parsed_args.recovery_method,
            'service_type': parsed_args.service_type,
        }
        # Remove not specified keys
        attrs = masakariclient_utils.remove_unspecified_items(attrs)

        try:
            segment = masakari_client.create_segment(**attrs)
        except Exception as ex:
            LOG.debug(_("Failed to create segment: %s"), parsed_args)
            raise ex
        return _show_segment(masakari_client, segment.uuid)
Esempio n. 25
0
    def take_action(self, parsed_args):
        masakari_client = self.app.client_manager.ha
        segment_id = masakariclient_utils.get_uuid_by_name(
            masakari_client, parsed_args.segment_id)
        attrs = {
            'name': parsed_args.name,
            'type': parsed_args.type,
            'control_attributes': parsed_args.control_attributes,
            'reserved': parsed_args.reserved,
            'on_maintenance': parsed_args.on_maintenance,
        }
        # Remove not specified keys
        attrs = masakariclient_utils.remove_unspecified_items(attrs)

        try:
            host = masakari_client.create_host(segment_id=segment_id, **attrs)
        except Exception as ex:
            LOG.debug(_("Failed to create segment host: %s"), parsed_args)
            raise ex
        return _show_host(masakari_client, segment_id, host.uuid)
Esempio n. 26
0
def _show_segment(masakari_client, segment_uuid):
    try:
        segment = masakari_client.get_segment(segment_uuid)
    except sdk_exc.ResourceNotFound:
        raise exceptions.CommandError(
            _('Segment is not found: %s') % segment_uuid)

    formatters = {}
    columns = [
        'created_at',
        'updated_at',
        'uuid',
        'name',
        'description',
        'id',
        'service_type',
        'recovery_method',
    ]
    return columns, utils.get_dict_properties(segment.to_dict(),
                                              columns,
                                              formatters=formatters)
Esempio n. 27
0
def _show_notification(masakari_client, notification_uuid):
    try:
        notification = masakari_client.get_notification(notification_uuid)
    except sdk_exc.ResourceNotFound:
        raise exceptions.CommandError(
            _('Notification not found: %s') % notification_uuid)

    formatters = {}
    columns = [
        'created_at',
        'updated_at',
        'notification_uuid',
        'type',
        'status',
        'source_host_uuid',
        'generated_time',
        'payload',
    ]
    return columns, utils.get_dict_properties(notification.to_dict(),
                                              columns,
                                              formatters=formatters)
Esempio n. 28
0
def _show_host(masakari_client, segment_id, uuid):
    try:
        host = masakari_client.get_host(uuid, segment_id=segment_id)
    except sdk_exc.ResourceNotFound:
        raise exceptions.CommandError(
            _('Segment host is not found: %s') % uuid)

    formatters = {}
    columns = [
        'created_at',
        'updated_at',
        'uuid',
        'name',
        'type',
        'control_attributes',
        'reserved',
        'on_maintenance',
        'failover_segment_id',
    ]
    return columns, utils.get_dict_properties(host.to_dict(),
                                              columns,
                                              formatters=formatters)
Esempio n. 29
0
    def test_do_segment_delete_with_non_existing_uuid(self,
                                                      mock_get_uuid_by_name,
                                                      mock_delete_segment):
        mock_get_uuid_by_name.return_value = self.segment_vals.get('uuid')

        expected_msg = _("No failover segment with "
                         "id (%s)") % mock_get_uuid_by_name

        def fake_delete_segment(self,
                                mock_get_uuid_by_name,
                                ignore_missing=False):
            if not ignore_missing:
                raise sdk_exc.ResourceNotFound(expected_msg)

        mock_delete_segment.side_effect = fake_delete_segment
        service = mock.Mock()
        args = mock.Mock()

        original = sys.stdout
        sys.stdout = six.StringIO()
        ms.do_segment_delete(service, args)
        output = sys.stdout.getvalue()
        sys.stdout = original
        self.assertIn(expected_msg, output)
Esempio n. 30
0
class MasakariShell(object):
    def __init__(self):
        pass

    def do_bash_completion(self, args):
        """All of the commands and options to stdout."""
        commands = set()
        options = set()
        for sc_str, sc in self.subcommands.items():
            if sc_str == 'bash_completion' or sc_str == 'bash-completion':
                continue

            commands.add(sc_str)
            for option in list(sc._optionals._option_string_actions):
                options.add(option)

        print(' '.join(commands | options))

    def _add_bash_completion_subparser(self, subparsers):
        subparser = subparsers.add_parser('bash_completion',
                                          add_help=False,
                                          formatter_class=HelpFormatter)

        subparser.set_defaults(func=self.do_bash_completion)
        self.subcommands['bash_completion'] = subparser

    def _get_subcommand_parser(self, base_parser, version):
        parser = base_parser

        self.subcommands = {}
        subparsers = parser.add_subparsers(metavar='<subcommand>')
        submodule = utils.import_versioned_module(version, 'shell')
        self._find_actions(subparsers, submodule)
        self._add_bash_completion_subparser(subparsers)

        return parser

    def _find_actions(self, subparsers, actions_module):
        for attr in (a for a in dir(actions_module) if a.startswith('do_')):
            command = attr[3:].replace('_', '-')
            callback = getattr(actions_module, attr)

            desc = callback.__doc__ or ''
            help = desc.strip().split('\n')[0]
            arguments = getattr(callback, 'arguments', [])

            subparser = subparsers.add_parser(command,
                                              help=help,
                                              description=desc,
                                              add_help=False,
                                              formatter_class=HelpFormatter)

            subparser.add_argument('-h',
                                   '--help',
                                   action='help',
                                   help=argparse.SUPPRESS)

            for (args, kwargs) in arguments:
                subparser.add_argument(*args, **kwargs)
            subparser.set_defaults(func=callback)

            self.subcommands[command] = subparser

    def _setup_masakari_client(self, api_ver, args):
        """Create masakari client using given args."""
        kwargs = {
            'auth_plugin': args.auth_plugin or 'password',
            'auth_url': args.auth_url,
            'project_name': args.project_name or args.tenant_name,
            'project_id': args.project_id or args.tenant_id,
            'domain_name': args.domain_name,
            'domain_id': args.domain_id,
            'project_domain_name': args.project_domain_name,
            'project_domain_id': args.project_domain_id,
            'user_domain_name': args.user_domain_name,
            'user_domain_id': args.user_domain_id,
            'username': args.username,
            'user_id': args.user_id,
            'password': args.password,
            'verify': args.verify,
            'token': args.token,
            'trust_id': args.trust_id,
            'interface': args.interface,
            'region_name': args.region_name,
        }

        return masakari_client.Client(api_ver, user_agent=USER_AGENT, **kwargs)

    def _setup_logging(self, debug):
        if debug:
            log_level = logging.DEBUG
        else:
            log_level = logging.WARNING
        log_format = "%(levelname)s (%(module)s) %(message)s"
        logging.basicConfig(format=log_format, level=log_level)
        logging.getLogger('iso8601').setLevel(logging.WARNING)
        logging.getLogger('urllib3.connectionpool').setLevel(logging.WARNING)

    def main(self, argv):

        parser = argparse.ArgumentParser(
            prog='masakari',
            description="masakari shell",
            epilog='Type "masakari help <COMMAND>" for help on a specific '
            'command.',
            add_help=False,
        )
        # add add arguments
        cliargs.add_global_args(parser, masakariclient.__version__)
        cliargs.add_global_identity_args(parser)

        # parse main arguments
        (options, args) = parser.parse_known_args(argv)

        self._setup_logging(options.debug)

        base_parser = parser
        api_ver = options.masakari_api_version

        # add subparser
        subcommand_parser = self._get_subcommand_parser(base_parser, api_ver)
        self.parser = subcommand_parser

        # --help/-h or no arguments
        if not args and options.help or not argv:
            self.do_help(options)
            return 0

        args = subcommand_parser.parse_args(argv)

        sc = self._setup_masakari_client(api_ver, args)
        # call specified function
        args.func(sc.service, args)

    @utils.arg('command',
               metavar='<subcommand>',
               nargs='?',
               help=_('Display help for <subcommand>.'))
    def do_help(self, args):
        """Display help about this program or one of its subcommands."""
        if getattr(args, 'command', None):
            if args.command in self.subcommands:
                self.subcommands[args.command].print_help()
            else:
                raise exc.CommandError("'%s' is not a valid subcommand" %
                                       args.command)
        else:
            self.parser.print_help()