def get_parser(self, prog_name):
        parser = super(ListStrategy, self).get_parser(prog_name)
        parser.add_argument('--goal',
                            metavar='<goal>',
                            dest='goal',
                            help=_('UUID or name of the goal'))
        parser.add_argument(
            '--detail',
            dest='detail',
            action='store_true',
            default=False,
            help=_("Show detailed information about each strategy."))
        parser.add_argument(
            '--limit',
            metavar='<limit>',
            type=int,
            help=_('Maximum number of strategies to return per request, '
                   '0 for no limit. Default is the maximum number used '
                   'by the Watcher API Service.'))
        parser.add_argument(
            '--sort-key',
            metavar='<field>',
            help=_('Goal field that will be used for sorting.'))
        parser.add_argument(
            '--sort-dir',
            metavar='<direction>',
            choices=['asc', 'desc'],
            help='Sort direction: "asc" (the default) or "desc".')

        return parser
    def get_parser(self, prog_name):
        parser = super(ListActionPlan, self).get_parser(prog_name)
        parser.add_argument('--audit',
                            metavar='<audit>',
                            help=_('UUID of an audit used for filtering.'))
        parser.add_argument(
            '--detail',
            dest='detail',
            action='store_true',
            default=False,
            help=_("Show detailed information about action plans."))
        parser.add_argument(
            '--limit',
            metavar='<limit>',
            type=int,
            help=_('Maximum number of action plans to return per request, '
                   '0 for no limit. Default is the maximum number used '
                   'by the Watcher API Service.'))
        parser.add_argument(
            '--sort-key',
            metavar='<field>',
            help=_('Action Plan field that will be used for sorting.'))
        parser.add_argument(
            '--sort-dir',
            metavar='<direction>',
            choices=['asc', 'desc'],
            help=_('Sort direction: "asc" (the default) or "desc".'))

        return parser
Exemple #3
0
    def get_parser(self, prog_name):
        parser = super(ListGoal, self).get_parser(prog_name)
        parser.add_argument(
            '--detail',
            dest='detail',
            action='store_true',
            default=False,
            help=_("Show detailed information about each goal."))
        parser.add_argument(
            '--limit',
            metavar='<limit>',
            type=int,
            help=_('Maximum number of goals to return per request, '
                   '0 for no limit. Default is the maximum number used '
                   'by the Watcher API Service.'))
        parser.add_argument(
            '--sort-key',
            metavar='<field>',
            help=_('Goal field that will be used for sorting.'))
        parser.add_argument(
            '--sort-dir',
            metavar='<direction>',
            choices=['asc', 'desc'],
            help=_('Sort direction: "asc" (the default) or "desc".'))
        parser.add_argument('--marker',
                            dest='marker',
                            metavar='<marker>',
                            default=None,
                            help=_(
                                'UUID of the last goal in the previous page; '
                                'displays list of goals after "marker".'))

        return parser
    def get_parser(self, prog_name):
        parser = super(ListScoringEngine, self).get_parser(prog_name)
        parser.add_argument(
            '--detail',
            dest='detail',
            action='store_true',
            default=False,
            help=_("Show detailed information about scoring engines."))
        parser.add_argument(
            '--limit',
            metavar='<limit>',
            type=int,
            help=_('Maximum number of actions to return per request, '
                   '0 for no limit. Default is the maximum number used '
                   'by the Watcher API Service.'))
        parser.add_argument(
            '--sort-key',
            metavar='<field>',
            help=_('Action field that will be used for sorting.'))
        parser.add_argument(
            '--sort-dir',
            metavar='<direction>',
            choices=['asc', 'desc'],
            help=_('Sort direction: "asc" (the default) or "desc".'))

        return parser
Exemple #5
0
    def negotiate_version(self, conn, resp):
        """Negotiate the server version

        Assumption: Called after receiving a 406 error when doing a request.

        param conn: A connection object
        param resp: The response object from http request
        """
        if self.api_version_select_state not in API_VERSION_SELECTED_STATES:
            raise RuntimeError(
                _('Error: self.api_version_select_state should be one of the '
                  'values in: "%(valid)s" but had the value: "%(value)s"') % {
                      'valid': ', '.join(API_VERSION_SELECTED_STATES),
                      'value': self.api_version_select_state
                  })
        min_ver, max_ver = self._parse_version_headers(resp)
        # If the user requested an explicit version or we have negotiated a
        # version and still failing then error now. The server could
        # support the version requested but the requested operation may not
        # be supported by the requested version.
        if self.api_version_select_state == 'user':
            raise exceptions.UnsupportedVersion(
                textwrap.fill(
                    _("Requested API version %(req)s is not supported by the "
                      "server or the requested operation is not supported by the "
                      "requested version.  Supported version range is %(min)s to "
                      "%(max)s") % {
                          'req': self.os_infra_optim_api_version,
                          'min': min_ver,
                          'max': max_ver
                      }))
        if self.api_version_select_state == 'negotiated':
            raise exceptions.UnsupportedVersion(
                textwrap.fill(
                    _("No API version was specified and the requested operation "
                      "was not supported by the client's negotiated API version "
                      "%(req)s.  Supported version range is: %(min)s to %(max)s"
                      ) % {
                          'req': self.os_infra_optim_api_version,
                          'min': min_ver,
                          'max': max_ver
                      }))

        negotiated_ver = str(
            min(version.StrictVersion(self.os_infra_optim_api_version),
                version.StrictVersion(max_ver)))
        if negotiated_ver < min_ver:
            negotiated_ver = min_ver
        # server handles microversions, but doesn't support
        # the requested version, so try a negotiated version
        self.api_version_select_state = 'negotiated'
        self.os_infra_optim_api_version = negotiated_ver
        LOG.debug('Negotiated API version is %s', negotiated_ver)

        return negotiated_ver
Exemple #6
0
class ServiceUnavailable(HttpServerError):
    """HTTP 503 - Service Unavailable.

    The server is currently unavailable.
    """
    http_status = 503
    message = _("Service Unavailable")
    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
Exemple #8
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
Exemple #9
0
    def __init__(self, endpoint, **kwargs):
        self.endpoint = endpoint
        self.endpoint_trimmed = _trim_endpoint_api_version(endpoint)
        self.auth_token = kwargs.get('token')
        self.auth_ref = kwargs.get('auth_ref')
        self.os_watcher_api_version = kwargs.get('os_watcher_api_version',
                                                 DEFAULT_VER)
        self.api_version_select_state = kwargs.get('api_version_select_state',
                                                   'default')
        self.conflict_max_retries = kwargs.pop('max_retries',
                                               DEFAULT_MAX_RETRIES)
        self.conflict_retry_interval = kwargs.pop('retry_interval',
                                                  DEFAULT_RETRY_INTERVAL)
        self.session = requests.Session()

        parts = urlparse.urlparse(endpoint)
        if parts.scheme not in SUPPORTED_ENDPOINT_SCHEME:
            msg = _('Unsupported scheme: %s') % parts.scheme
            raise exceptions.EndpointException(msg)

        if parts.scheme == 'https':
            if kwargs.get('insecure') is True:
                self.session.verify = False
            elif kwargs.get('ca_file'):
                self.session.verify = kwargs['ca_file']
            self.session.cert = (kwargs.get('cert_file'),
                                 kwargs.get('key_file'))
Exemple #10
0
    def get_parser(self, prog_name):
        parser = super(CancelActionPlan, self).get_parser(prog_name)
        parser.add_argument('action_plan',
                            metavar='<action-plan>',
                            help=_("UUID of the action_plan."))

        return parser
    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":
                    # NOTE(andreykurilin): 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 exceptions.UnsupportedVersion(msg)
Exemple #12
0
class RequestUriTooLong(HTTPClientError):
    """HTTP 414 - Request-URI Too Long.

    The URI provided was too long for the server to process.
    """
    http_status = 414
    message = _("Request-URI Too Long")
def print_dict(dct, dict_property="Property", wrap=0):
    """Print a `dict` as a table of two columns.

    :param dct: `dict` to print
    :param dict_property: name of the first column
    :param wrap: wrapping for the second column
    """
    pt = prettytable.PrettyTable([dict_property, 'Value'])
    pt.align = 'l'
    for k, v in dct.items():
        # convert dict to str to check length
        if isinstance(v, dict):
            v = six.text_type(v)
        if wrap > 0:
            v = textwrap.fill(six.text_type(v), wrap)
        elif wrap < 0:
            raise ValueError(_("Wrap argument should be a positive integer"))
        # if value has a newline, add in multiple rows
        # e.g. fault with stacktrace
        if v and isinstance(v, six.string_types) and r'\n' in v:
            lines = v.strip().split(r'\n')
            col1 = k
            for line in lines:
                pt.add_row([col1, line])
                col1 = ''
        else:
            if v is None:
                v = '-'
            pt.add_row([k, v])

    if six.PY3:
        print(encodeutils.safe_encode(pt.get_string()).decode())
    else:
        print(encodeutils.safe_encode(pt.get_string()))
Exemple #14
0
class ProxyAuthenticationRequired(HTTPClientError):
    """HTTP 407 - Proxy Authentication Required.

    The client must first authenticate itself with the proxy.
    """
    http_status = 407
    message = _("Proxy Authentication Required")
Exemple #15
0
class RequestTimeout(HTTPClientError):
    """HTTP 408 - Request Timeout.

    The server timed out waiting for the request.
    """
    http_status = 408
    message = _("Request Timeout")
Exemple #16
0
class PaymentRequired(HTTPClientError):
    """HTTP 402 - Payment Required.

    Reserved for future use.
    """
    http_status = 402
    message = _("Payment Required")
Exemple #17
0
class BadRequest(HTTPClientError):
    """HTTP 400 - Bad Request.

    The request cannot be fulfilled due to bad syntax.
    """
    http_status = 400
    message = _("Bad Request")
Exemple #18
0
class HttpServerError(HttpError):
    """Server-side HTTP error.

    Exception for cases in which the server is aware that it has
    erred or is incapable of performing the request.
    """
    message = _("HTTP Server Error")
Exemple #19
0
class HttpVersionNotSupported(HttpServerError):
    """HTTP 505 - HttpVersion Not Supported.

    The server does not support the HTTP protocol version used in the request.
    """
    http_status = 505
    message = _("HTTP Version Not Supported")
    def find(self, base_url=None, **kwargs):
        """Find a single item with attributes matching ``**kwargs``.

        :param base_url: if provided, the generated URL will be appended to it
        """
        kwargs = self._filter_kwargs(kwargs)

        rl = self._list(
            '%(base_url)s%(query)s' % {
                'base_url': self.build_url(base_url=base_url, **kwargs),
                'query': '?%s' % parse.urlencode(kwargs) if kwargs else '',
            },
            self.collection_key)
        num = len(rl)

        if num == 0:
            msg = _("No %(name)s matching %(args)s.") % {
                'name': self.resource_class.__name__,
                'args': kwargs
            }
            raise exceptions.NotFound(404, msg)
        elif num > 1:
            raise exceptions.NoUniqueMatch
        else:
            return rl[0]
    def __init__(self, endpoint=None, *args, **kwargs):
        """Initialize a new client for the Watcher v1 API."""
        if kwargs.get('os_infra_optim_api_version'):
            kwargs['api_version_select_state'] = "user"
        else:
            if not endpoint:
                raise exceptions.EndpointException(
                    _("Must provide 'endpoint' if os_infra_optim_api_version "
                      "isn't specified"))

            # If the user didn't specify a version, use a cached version if
            # one has been stored
            host, netport = httpclient.get_server(endpoint)
            kwargs['api_version_select_state'] = "default"
            kwargs['os_infra_optim_api_version'] = httpclient.DEFAULT_VER

        self.http_client = httpclient._construct_http_client(
            endpoint, *args, **kwargs)

        self.audit = v1.AuditManager(self.http_client)
        self.audit_template = v1.AuditTemplateManager(self.http_client)
        self.action = v1.ActionManager(self.http_client)
        self.action_plan = v1.ActionPlanManager(self.http_client)
        self.goal = v1.GoalManager(self.http_client)
        self.scoring_engine = v1.ScoringEngineManager(self.http_client)
        self.service = v1.ServiceManager(self.http_client)
        self.strategy = v1.StrategyManager(self.http_client)
Exemple #22
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":
                    # NOTE(andreykurilin): 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 exceptions.UnsupportedVersion(msg)
    def __init__(self, endpoint, **kwargs):
        self.endpoint = endpoint
        self.endpoint_trimmed = _trim_endpoint_api_version(endpoint)
        self.auth_token = kwargs.get('token')
        self.auth_ref = kwargs.get('auth_ref')
        self.os_infra_optim_api_version = kwargs.get(
            'os_infra_optim_api_version', DEFAULT_VER)
        self.api_version_select_state = kwargs.get(
            'api_version_select_state', 'default')
        self.conflict_max_retries = kwargs.pop('max_retries',
                                               DEFAULT_MAX_RETRIES)
        self.conflict_retry_interval = kwargs.pop('retry_interval',
                                                  DEFAULT_RETRY_INTERVAL)
        self.session = requests.Session()

        parts = urlparse.urlparse(endpoint)
        if parts.scheme not in SUPPORTED_ENDPOINT_SCHEME:
            msg = _('Unsupported scheme: %s') % parts.scheme
            raise exceptions.EndpointException(msg)

        if parts.scheme == 'https':
            if kwargs.get('insecure') is True:
                self.session.verify = False
            elif kwargs.get('ca_file'):
                self.session.verify = kwargs['ca_file']
            self.session.cert = (kwargs.get('cert_file'),
                                 kwargs.get('key_file'))
Exemple #24
0
class InternalServerError(HttpServerError):
    """HTTP 500 - Internal Server Error.

    A generic error message, given when no more specific message is suitable.
    """
    http_status = 500
    message = _("Internal Server Error")
Exemple #25
0
class ExpectationFailed(HTTPClientError):
    """HTTP 417 - Expectation Failed.

    The server cannot meet the requirements of the Expect request-header field.
    """
    http_status = 417
    message = _("Expectation Failed")
Exemple #26
0
    def __init__(self, endpoint=None, *args, **kwargs):
        """Initialize a new client for the Watcher v1 API."""
        if kwargs.get('os_watcher_api_version'):
            kwargs['api_version_select_state'] = "user"
        else:
            if not endpoint:
                raise exceptions.EndpointException(
                    _("Must provide 'endpoint' if os_watcher_api_version "
                      "isn't specified"))

            # If the user didn't specify a version, use a cached version if
            # one has been stored
            host, netport = httpclient.get_server(endpoint)
            kwargs['api_version_select_state'] = "default"
            kwargs['os_watcher_api_version'] = httpclient.DEFAULT_VER

        self.http_client = httpclient._construct_http_client(
            endpoint, *args, **kwargs)

        self.audit = v1.AuditManager(self.http_client)
        self.audit_template = v1.AuditTemplateManager(self.http_client)
        self.action = v1.ActionManager(self.http_client)
        self.action_plan = v1.ActionPlanManager(self.http_client)
        self.goal = v1.GoalManager(self.http_client)
        self.scoring_engine = v1.ScoringEngineManager(self.http_client)
        self.service = v1.ServiceManager(self.http_client)
        self.strategy = v1.StrategyManager(self.http_client)
    def negotiate_version(self, conn, resp):
        """Negotiate the server version

        Assumption: Called after receiving a 406 error when doing a request.

        param conn: A connection object
        param resp: The response object from http request
        """
        if self.api_version_select_state not in API_VERSION_SELECTED_STATES:
            raise RuntimeError(
                _('Error: self.api_version_select_state should be one of the '
                  'values in: "%(valid)s" but had the value: "%(value)s"') %
                {'valid': ', '.join(API_VERSION_SELECTED_STATES),
                 'value': self.api_version_select_state})
        min_ver, max_ver = self._parse_version_headers(resp)
        # If the user requested an explicit version or we have negotiated a
        # version and still failing then error now. The server could
        # support the version requested but the requested operation may not
        # be supported by the requested version.
        if self.api_version_select_state == 'user':
            raise exceptions.UnsupportedVersion(textwrap.fill(
                _("Requested API version %(req)s is not supported by the "
                  "server or the requested operation is not supported by the "
                  "requested version.  Supported version range is %(min)s to "
                  "%(max)s")
                % {'req': self.os_infra_optim_api_version,
                   'min': min_ver, 'max': max_ver}))
        if self.api_version_select_state == 'negotiated':
            raise exceptions.UnsupportedVersion(textwrap.fill(
                _("No API version was specified and the requested operation "
                  "was not supported by the client's negotiated API version "
                  "%(req)s.  Supported version range is: %(min)s to %(max)s")
                % {'req': self.os_infra_optim_api_version,
                   'min': min_ver, 'max': max_ver}))

        negotiated_ver = str(
            min(version.StrictVersion(self.os_infra_optim_api_version),
                version.StrictVersion(max_ver)))
        if negotiated_ver < min_ver:
            negotiated_ver = min_ver
        # server handles microversions, but doesn't support
        # the requested version, so try a negotiated version
        self.api_version_select_state = 'negotiated'
        self.os_infra_optim_api_version = negotiated_ver
        LOG.debug('Negotiated API version is %s', negotiated_ver)

        return negotiated_ver
Exemple #28
0
class BadGateway(HttpServerError):
    """HTTP 502 - Bad Gateway.

    The server was acting as a gateway or proxy and received an invalid
    response from the upstream server.
    """
    http_status = 502
    message = _("Bad Gateway")
 def get_parser(self, prog_name):
     parser = super(ShowAudit, self).get_parser(prog_name)
     parser.add_argument(
         'audit',
         metavar='<audit>',
         help=_('UUID or name of the audit'),
     )
     return parser
 def get_parser(self, prog_name):
     parser = super(ShowGoal, self).get_parser(prog_name)
     parser.add_argument(
         'goal',
         metavar='<goal>',
         help=_('UUID or name of the goal'),
     )
     return parser
Exemple #31
0
class GatewayTimeout(HttpServerError):
    """HTTP 504 - Gateway Timeout.

    The server was acting as a gateway or proxy and did not receive a timely
    response from the upstream server.
    """
    http_status = 504
    message = _("Gateway Timeout")
    def get_parser(self, prog_name):
        parser = super(CreateActionPlan, self).get_parser(prog_name)
        parser.add_argument(
            '-a',
            '--audit-template',
            required=True,
            dest='audit_template_uuid',
            metavar='<audit_template>',
            help=_('ActionPlan template used for this audit (name or uuid).'))
        parser.add_argument('-t',
                            '--audit_type',
                            dest='audit_type',
                            metavar='<audit_type>',
                            default='ONESHOT',
                            help=_("ActionPlan type."))

        return parser
Exemple #33
0
 def get_parser(self, prog_name):
     parser = super(StateStrategy, self).get_parser(prog_name)
     parser.add_argument(
         'strategy',
         metavar='<strategy>',
         help=_('Name of the strategy'),
     )
     return parser
 def get_parser(self, prog_name):
     parser = super(ShowAuditTemplate, self).get_parser(prog_name)
     parser.add_argument(
         'audit_template',
         metavar='<audit-template>',
         help=_('UUID or name of the audit template'),
     )
     return parser
Exemple #35
0
 def get_parser(self, prog_name):
     parser = super(ShowActionPlan, self).get_parser(prog_name)
     parser.add_argument(
         'action_plan',
         metavar='<action-plan>',
         help=_('UUID of the action plan'),
     )
     return parser
 def get_parser(self, prog_name):
     parser = super(ShowScoringEngine, self).get_parser(prog_name)
     parser.add_argument(
         'scoring_engine',
         metavar='<scoring_engine>',
         help=_('Name of the scoring engine'),
     )
     return parser
 def get_parser(self, prog_name):
     parser = super(ShowScoringEngine, self).get_parser(prog_name)
     parser.add_argument(
         'scoring_engine',
         metavar='<scoring_engine>',
         help=_('Name of the scoring engine'),
     )
     return parser
 def get_parser(self, prog_name):
     parser = super(ShowService, self).get_parser(prog_name)
     parser.add_argument(
         'service',
         metavar='<service>',
         help=_('ID or name of the service'),
     )
     return parser
Exemple #39
0
class HttpNotImplemented(HttpServerError):
    """HTTP 501 - Not Implemented.

    The server either does not recognize the request method, or it lacks
    the ability to fulfill the request.
    """
    http_status = 501
    message = _("Not Implemented")
    def get_parser(self, prog_name):
        parser = super(CancelActionPlan, self).get_parser(prog_name)
        parser.add_argument(
            'action_plan',
            metavar='<action-plan>',
            help=_("UUID of the action_plan."))

        return parser
 def get_parser(self, prog_name):
     parser = super(ShowActionPlan, self).get_parser(prog_name)
     parser.add_argument(
         'action_plan',
         metavar='<action-plan>',
         help=_('UUID of the action plan'),
     )
     return parser
Exemple #42
0
 def get_parser(self, prog_name):
     parser = super(ShowAudit, self).get_parser(prog_name)
     parser.add_argument(
         'audit',
         metavar='<audit>',
         help=_('UUID or name of the audit'),
     )
     return parser
Exemple #43
0
class UnprocessableEntity(HTTPClientError):
    """HTTP 422 - Unprocessable Entity.

    The request was well-formed but was unable to be followed due to semantic
    errors.
    """
    http_status = 422
    message = _("Unprocessable Entity")
 def get_parser(self, prog_name):
     parser = super(ShowAuditTemplate, self).get_parser(prog_name)
     parser.add_argument(
         'audit_template',
         metavar='<audit-template>',
         help=_('UUID or name of the audit template'),
     )
     return parser
def common_params_for_list(args, fields, field_labels):
    """Generate 'params' dict that is common for every 'list' command.

    :param args: arguments from command line.
    :param fields: possible fields for sorting.
    :param field_labels: possible field labels for sorting.
    :returns: a dict with params to pass to the client method.
    """
    params = {}
    if args.limit is not None:
        if args.limit < 0:
            raise exc.CommandError(
                _('Expected non-negative --limit, got %s') % args.limit)
        params['limit'] = args.limit

    if args.sort_key is not None:
        # Support using both heading and field name for sort_key
        fields_map = dict(zip(field_labels, fields))
        fields_map.update(zip(fields, fields))
        try:
            sort_key = fields_map[args.sort_key]
        except KeyError:
            raise exc.CommandError(
                _("%(sort_key)s is an invalid field for sorting, "
                  "valid values for --sort-key are: %(valid)s") %
                {'sort_key': args.sort_key,
                 'valid': list(fields_map)})
        params['sort_key'] = sort_key
    if args.sort_dir is not None:
        if args.sort_dir not in ('asc', 'desc'):
            raise exc.CommandError(
                _("%s is an invalid value for sort direction, "
                  "valid values for --sort-dir are: 'asc', 'desc'") %
                args.sort_dir)
        params['sort_dir'] = args.sort_dir

    marker = getattr(args, 'marker', None)
    if marker is not None:
        params['marker'] = marker
    params['detail'] = args.detail

    return params
def check_major_version(api_version):
    """Checks major part of ``APIVersion`` obj is supported.

    :raises watcherclient.exceptions.UnsupportedVersion: if major part is not
                                                      supported
    """
    available_versions = get_available_major_versions()
    if (not api_version.is_null() and
            str(api_version.ver_major) not in available_versions):
        if len(available_versions) == 1:
            msg = _("Invalid client version '%(version)s'. "
                    "Major part should be '%(major)s'") % {
                        "version": api_version.get_string(),
                        "major": available_versions[0]}
        else:
            msg = _("Invalid client version '%(version)s'. "
                    "Major part must be one of: '%(major)s'") % {
                        "version": api_version.get_string(),
                        "major": ", ".join(available_versions)}
        raise exceptions.UnsupportedVersion(msg)
    def get_parser(self, prog_name):
        parser = super(UpdateActionPlan, self).get_parser(prog_name)
        parser.add_argument(
            'action_plan',
            metavar='<action-plan>',
            help=_("UUID of the action_plan."))
        parser.add_argument(
            'op',
            metavar='<op>',
            choices=['add', 'replace', 'remove'],
            help=_("Operation: 'add', 'replace', or 'remove'."))
        parser.add_argument(
            'attributes',
            metavar='<path=value>',
            nargs='+',
            action='append',
            default=[],
            help=_("Attribute to add, replace, or remove. Can be specified "
                   "multiple times. For 'remove', only <path> is necessary."))

        return parser
    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)
    def get_parser(self, prog_name):
        parser = super(ListActionPlan, self).get_parser(prog_name)
        parser.add_argument(
            '--audit',
            metavar='<audit>',
            help=_('UUID of an audit used for filtering.'))
        parser.add_argument(
            '--detail',
            dest='detail',
            action='store_true',
            default=False,
            help=_("Show detailed information about action plans."))
        parser.add_argument(
            '--limit',
            metavar='<limit>',
            type=int,
            help=_('Maximum number of action plans to return per request, '
                   '0 for no limit. Default is the maximum number used '
                   'by the Watcher API Service.'))
        parser.add_argument(
            '--marker',
            metavar='<actionplan>',
            help=_('The last actionplan UUID of the previous page; '
                   'displays list of actionplans after "marker".'))
        parser.add_argument(
            '--sort-key',
            metavar='<field>',
            help=_('Action Plan field that will be used for sorting.'))
        parser.add_argument(
            '--sort-dir',
            metavar='<direction>',
            choices=['asc', 'desc'],
            help=_('Sort direction: "asc" (the default) or "desc".'))

        return parser
def print_list(objs, fields, formatters=None, sortby_index=0,
               mixed_case_fields=None, field_labels=None):
    """Print a list or objects as a table, one row per object.

    :param objs: iterable of :class:`Resource`
    :param fields: attributes that correspond to columns, in order
    :param formatters: `dict` of callables for field formatting
    :param sortby_index: index of the field for sorting table rows
    :param mixed_case_fields: fields corresponding to object attributes that
        have mixed case names (e.g., 'serverId')
    :param field_labels: Labels to use in the heading of the table, default to
        fields.
    """
    formatters = formatters or {}
    mixed_case_fields = mixed_case_fields or []
    field_labels = field_labels or fields
    if len(field_labels) != len(fields):
        raise ValueError(_("Field labels list %(labels)s has different number "
                           "of elements than fields list %(fields)s"),
                         {'labels': field_labels, 'fields': fields})

    if sortby_index is None:
        kwargs = {}
    else:
        kwargs = {'sortby': field_labels[sortby_index]}
    pt = prettytable.PrettyTable(field_labels)
    pt.align = 'l'

    for o in objs:
        row = []
        for field in fields:
            data = '-'
            if field in formatters:
                data = formatters[field](o)
            else:
                if field in mixed_case_fields:
                    field_name = field.replace(' ', '_')
                else:
                    field_name = field.lower().replace(' ', '_')
                data = getattr(o, field_name, '')
            if data is None:
                data = '-'
            row.append(data)
        pt.add_row(row)

    if six.PY3:
        print(encodeutils.safe_encode(pt.get_string(**kwargs)).decode())
    else:
        print(encodeutils.safe_encode(pt.get_string(**kwargs)))
def args_array_to_patch(op, attributes, exclude_fields=[]):
    patch = []
    for attr in attributes:
        # Sanitize
        if not attr.startswith('/'):
            attr = '/' + attr

        if op in ['add', 'replace']:
            path, value = split_and_deserialize(attr,
                                                exclude_fields=exclude_fields)
            patch.append({'op': op, 'path': path, 'value': value})

        elif op == "remove":
            # For remove only the key is needed
            patch.append({'op': op, 'path': attr})
        else:
            raise exc.CommandError(_('Unknown PATCH operation: %s') % op)
    return patch
    def find(self, **kwargs):
        """Find a single item with attributes matching ``**kwargs``.

        This isn't very efficient: it loads the entire list then filters on
        the Python side.
        """
        matches = self.findall(**kwargs)
        num_matches = len(matches)
        if num_matches == 0:
            msg = _("No %(name)s matching %(args)s.") % {
                'name': self.resource_class.__name__,
                'args': kwargs
            }
            raise exceptions.NotFound(msg)
        elif num_matches > 1:
            raise exceptions.NoUniqueMatch()
        else:
            return matches[0]
def split_and_deserialize(string, exclude_fields=[]):
    """Split and try to JSON deserialize a string.

    Gets a string with the KEY=VALUE format, split it (using '=' as the
    separator) and try to JSON deserialize the VALUE.

    :returns: A tuple of (key, value).
    """
    try:
        key, value = string.split("=", 1)
    except ValueError:
        raise exc.CommandError(_('Attributes must be a list of '
                                 'PATH=VALUE not "%s"') % string)
    if key not in exclude_fields:
        try:
            value = jsonutils.loads(value)
        except ValueError:
            pass

    return (key, value)
    def _http_request(self, url, method, **kwargs):
        """Send an http request with the specified characteristics.

        Wrapper around request.Session.request to handle tasks such
        as setting headers and error handling.
        """
        # Copy the kwargs so we can reuse the original in case of redirects
        kwargs['headers'] = copy.deepcopy(kwargs.get('headers', {}))
        kwargs['headers'].setdefault('User-Agent', USER_AGENT)
        if self.os_infra_optim_api_version:
            api_version = api_versioning.get_api_version(
                self.os_infra_optim_api_version)
            if api_version.is_latest():
                api_version = api_versioning.get_api_version(
                    LATEST_VERSION)
            kwargs['headers'].setdefault(
                'OpenStack-API-Version',
                ' '.join(['infra-optim', api_version.get_string()]))
        if self.auth_token:
            kwargs['headers'].setdefault('X-Auth-Token', self.auth_token)

        self.log_curl_request(method, url, kwargs)

        # NOTE(aarefiev): This is for backwards compatibility, request
        # expected body in 'data' field, previously we used httplib,
        # which expected 'body' field.
        body = kwargs.pop('body', None)
        if body:
            kwargs['data'] = body

        conn_url = self._make_connection_url(url)
        try:
            resp = self.session.request(method,
                                        conn_url,
                                        **kwargs)

            # TODO(deva): implement graceful client downgrade when connecting
            # to servers that did not support microversions. Details here:
            # http://specs.openstack.org/openstack/watcher-specs/specs/kilo/api-microversions.html#use-case-3b-new-client-communicating-with-a-old-watcher-user-specified  # noqa

            if resp.status_code == http_client.NOT_ACCEPTABLE:
                negotiated_ver = self.negotiate_version(self.session, resp)
                kwargs['headers']['OpenStack-API-Version'] = (
                    ' '.join(['infra-optim', negotiated_ver]))
                return self._http_request(url, method, **kwargs)

        except requests.exceptions.RequestException as e:
            message = (_("Error has occurred while handling "
                       "request for %(url)s: %(e)s") %
                       dict(url=conn_url, e=e))
            # NOTE(aarefiev): not valid request(invalid url, missing schema,
            # and so on), retrying is not needed.
            if isinstance(e, ValueError):
                raise exceptions.ValidationError(message)

            raise exceptions.ConnectionRefused(message)

        body_iter = resp.iter_content(chunk_size=CHUNKSIZE)

        # Read body into string if it isn't obviously image data
        body_str = None
        if resp.headers.get('Content-Type') != 'application/octet-stream':
            # decoding byte to string is necessary for Python 3 compatibility
            # this issues has not been found with Python 3 unit tests
            # because the test creates a fake http response of type str
            # the if statement satisfies test (str) and real (bytes) behavior
            body_list = [
                chunk.decode("utf-8") if isinstance(chunk, bytes)
                else chunk for chunk in body_iter
            ]
            body_str = ''.join(body_list)
            self.log_http_response(resp, body_str)
            body_iter = six.StringIO(body_str)
        else:
            self.log_http_response(resp)

        if resp.status_code >= http_client.BAD_REQUEST:
            error_json = _extract_error_json(body_str)
            raise exceptions.from_response(
                resp, error_json.get('faultstring'),
                error_json.get('debuginfo'), method, url)
        elif resp.status_code in (http_client.MOVED_PERMANENTLY,
                                  http_client.FOUND,
                                  http_client.USE_PROXY):
            # Redirected. Reissue the request to the new location.
            return self._http_request(resp['location'], method, **kwargs)
        elif resp.status_code == http_client.MULTIPLE_CHOICES:
            raise exceptions.from_response(resp, method=method, url=url)

        return resp, body_iter
    def get_parser(self, prog_name):
        class SmartFormatter(argparse.HelpFormatter):

            def _split_lines(self, text, width):
                if '\n' in text:
                    return text.splitlines()
                else:
                    return argparse.HelpFormatter._split_lines(
                        self, text, width)

        parser = super(CreateAuditTemplate, self).get_parser(
            prog_name, formatter_class=SmartFormatter)
        parser.add_argument(
            'name',
            metavar='<name>',
            help=_('Name for this audit template.'))
        parser.add_argument(
            'goal',
            metavar='<goal>',
            help=_('Goal UUID or name associated to this audit template.'))
        parser.add_argument(
            '-s', '--strategy',
            dest='strategy',
            metavar='<strategy>',
            help=_('Strategy UUID or name associated to this audit template.'))
        parser.add_argument(
            '-d', '--description',
            metavar='<description>',
            help=_('Description of the audit template.'))
        parser.add_argument(
            '--scope',
            metavar='<path>',
            help=_("Part of the cluster on which an audit will be done.\n"
                   "Can be provided either in yaml or json file.\n"
                   "YAML example:\n"
                   "---\n"
                   " - compute:\n"
                   "   - host_aggregates:\n"
                   "     - id: 1\n"
                   "     - id: 2\n"
                   "     - id: 3\n"
                   "   - availability_zones:\n"
                   "     - name: AZ1\n"
                   "     - name: AZ2\n"
                   "   - exclude:\n"
                   "     - instances:\n"
                   "       - uuid: UUID1\n"
                   "       - uuid: UUID2\n"
                   "     - compute_nodes:\n"
                   "       - name: compute1\n"
                   " - storage: \n"
                   "   - availability_zones:\n"
                   "     - name: AZ1\n"
                   "     - name: AZ2\n"
                   "   - volume_types:\n"
                   "     - name: lvm1\n"
                   "     - name: lvm2\n"
                   "   - exclude:\n"
                   "     - storage_pools:\n"
                   "       - name: host0@backend0#pool0\n"
                   "       - name: host1@backend1#pool1\n"
                   "     - volumes:\n"
                   "       - uuid: UUID1\n"
                   "       - uuid: UUID2\n"
                   "     - projects:\n"
                   "       - uuid: UUID1\n"
                   "       - uuid: UUID2\n"
                   "\n"
                   "JSON example:\n"
                   "[\n"
                   " {\"compute\":\n"
                   "      [{\"host_aggregates\": [\n"
                   "            {\"id\": 1},\n"
                   "            {\"id\": 2},\n"
                   "            {\"id\": 3}]},\n"
                   "       {\"availability_zones\": [\n"
                   "            {\"name\": \"AZ1\"},\n"
                   "            {\"name\": \"AZ2\"}]},\n"
                   "       {\"exclude\": [\n"
                   "            {\"instances\": [\n"
                   "                 {\"uuid\": \"UUID1\"},\n"
                   "                 {\"uuid\": \"UUID2\"}\n"
                   "            ]},\n"
                   "            {\"compute_nodes\": [\n"
                   "                 {\"name\": \"compute1\"}\n"
                   "            ]}\n"
                   "       ]}]\n"
                   "  },\n"
                   " {\"storage\":\n"
                   "      [{\"availability_zones\": [\n"
                   "            {\"name\": \"AZ1\"},\n"
                   "            {\"name\": \"AZ2\"}]},\n"
                   "       {\"volume_types\": [\n"
                   "            {\"name\": \"lvm1\"},\n"
                   "            {\"name\": \"lvm2\"}]},\n"
                   "       {\"exclude\": [\n"
                   "            {\"storage_pools\": [\n"
                   "                 {\"name\": \"host0@backend0#pool0\"},\n"
                   "                 {\"name\": \"host1@backend1#pool1\"}\n"
                   "            ]},\n"
                   "            {\"volumes\": [\n"
                   "                 {\"uuid\": \"UUID1\"},\n"
                   "                 {\"uuid\": \"UUID2\"}\n"
                   "            ]},\n"
                   "            {\"projects\": [\n"
                   "                 {\"uuid\": \"UUID1\"},\n"
                   "                 {\"uuid\": \"UUID2\"}\n"
                   "            ]},\n"
                   "       ]}]\n"
                   "  }\n"
                   " ]\n"
                   )
        )

        return parser
from oslo_utils import strutils

from watcherclient._i18n import _
from watcherclient import exceptions

LOG = logging.getLogger(__name__)
if not LOG.handlers:
    LOG.addHandler(logging.StreamHandler())


MINOR_1_START_END_TIMING = '1.1'
HEADER_NAME = "OpenStack-API-Version"
# key is a deprecated version and value is an alternative version.
DEPRECATED_VERSIONS = {}

_type_error_msg = _("'%(other)s' should be an instance of '%(cls)s'")


def allow_start_end_audit_time(requested_version):
    """Check if we should support optional start/end attributes for Audit.

    Version 1.1 of the API added support for start and end time of continuous
    audits.
    """
    return (APIVersion(requested_version) >=
            APIVersion(MINOR_1_START_END_TIMING))


class APIVersion(object):
    """This class represents an API Version Request.
 def __init__(self, endpoints=None):
     super(AmbiguousEndpoints, self).__init__(
         _("AmbiguousEndpoints: %r") % endpoints)
     self.endpoints = endpoints
 def __init__(self, opt_names):
     super(AuthPluginOptionsMissing, self).__init__(
         _("Authentication failed. Missing options: %s") %
         ", ".join(opt_names))
     self.opt_names = opt_names
 def __init__(self, auth_system):
     super(AuthSystemNotFound, self).__init__(
         _("AuthSystemNotFound: %r") % auth_system)
     self.auth_system = auth_system
 def __init__(self, missing):
     self.missing = missing
     msg = _("Missing arguments: %s") % ", ".join(missing)
     super(MissingArgs, self).__init__(msg)