Merge "oslo sync apiclient and cliutils"

This commit is contained in:
Jenkins 2014-02-28 15:19:22 +00:00 committed by Gerrit Code Review
commit 06582e0c1d
6 changed files with 137 additions and 31 deletions

View File

@ -1,14 +0,0 @@
# Copyright 2013 OpenStack Foundation
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

View File

@ -19,7 +19,6 @@
import abc
import argparse
import logging
import os
import six
@ -28,9 +27,6 @@ from stevedore import extension
from novaclient.openstack.common.apiclient import exceptions
logger = logging.getLogger(__name__)
_discovered_plugins = {}
@ -80,7 +76,7 @@ def load_plugin_from_args(args):
alphabetical order.
:type args: argparse.Namespace
:raises: AuthorizationFailure
:raises: AuthPluginOptionsMissing
"""
auth_system = args.os_auth_system
if auth_system:

View File

@ -24,11 +24,12 @@ Base utilities to build API operation managers and objects on top of.
# pylint: disable=E1102
import abc
import copy
import six
from six.moves.urllib import parse
from novaclient.openstack.common.apiclient import exceptions
from novaclient.openstack.common.py3kcompat import urlutils
from novaclient.openstack.common import strutils
@ -327,7 +328,7 @@ class CrudManager(BaseManager):
return self._list(
'%(base_url)s%(query)s' % {
'base_url': self.build_url(base_url=base_url, **kwargs),
'query': '?%s' % urlutils.urlencode(kwargs) if kwargs else '',
'query': '?%s' % parse.urlencode(kwargs) if kwargs else '',
},
self.collection_key)
@ -366,7 +367,7 @@ class CrudManager(BaseManager):
rl = self._list(
'%(base_url)s%(query)s' % {
'base_url': self.build_url(base_url=base_url, **kwargs),
'query': '?%s' % urlutils.urlencode(kwargs) if kwargs else '',
'query': '?%s' % parse.urlencode(kwargs) if kwargs else '',
},
self.collection_key)
num = len(rl)
@ -465,6 +466,11 @@ class Resource(object):
return self.__dict__[k]
def get(self):
"""Support for lazy loading details.
Some clients, such as novaclient have the option to lazy load the
details, details which can be loaded with this function.
"""
# set_loaded() first ... so if we have to bail, we know we tried.
self.set_loaded(True)
if not hasattr(self.manager, 'get'):
@ -489,3 +495,6 @@ class Resource(object):
def set_loaded(self, val):
self._loaded = val
def to_dict(self):
return copy.deepcopy(self._info)

View File

@ -60,6 +60,11 @@ class AuthorizationFailure(ClientException):
pass
class ConnectionRefused(ClientException):
"""Cannot connect to API service."""
pass
class AuthPluginOptionsMissing(AuthorizationFailure):
"""Auth plugin misses some options."""
def __init__(self, opt_names):
@ -122,6 +127,11 @@ class HttpError(ClientException):
super(HttpError, self).__init__(formatted_string)
class HTTPRedirection(HttpError):
"""HTTP Redirection."""
message = "HTTP Redirection"
class HTTPClientError(HttpError):
"""Client-side HTTP error.
@ -139,6 +149,16 @@ class HttpServerError(HttpError):
message = "HTTP Server Error"
class MultipleChoices(HTTPRedirection):
"""HTTP 300 - Multiple Choices.
Indicates multiple options for the resource that the client may follow.
"""
http_status = 300
message = "Multiple Choices"
class BadRequest(HTTPClientError):
"""HTTP 400 - Bad Request.
@ -420,8 +440,8 @@ def from_response(response, method, url):
except ValueError:
pass
else:
if hasattr(body, "keys"):
error = body[body.keys()[0]]
if isinstance(body, dict):
error = list(body.values())[0]
kwargs["message"] = error.get("message")
kwargs["details"] = error.get("details")
elif content_type.startswith("text/"):

View File

@ -28,10 +28,9 @@ import json
import requests
import six
from six.moves.urllib import parse
from novaclient.openstack.common.apiclient import client
from novaclient.openstack.common.py3kcompat import urlutils
from novaclient.openstack.common import strutils
def assert_has_keys(dct, required=[], optional=[]):
@ -64,7 +63,7 @@ class TestResponse(requests.Response):
self._content = text
default_headers = {}
if six.PY3 and isinstance(self._content, six.string_types):
self._content = strutils.safe_encode(self._content)
self._content = self._content.encode('utf-8', 'strict')
self.headers = data.get('headers') or default_headers
else:
self.status_code = data
@ -148,7 +147,7 @@ class FakeHTTPClient(client.HTTPClient):
"text": fixture[1]})
# Call the method
args = urlutils.parse_qsl(urlutils.urlparse(url)[4])
args = parse.parse_qsl(parse.urlparse(url)[4])
kwargs.update(args)
munged_url = url.rsplit('?', 1)[0]
munged_url = munged_url.strip('/').replace('/', '_').replace('.', '_')

View File

@ -16,6 +16,8 @@
# W0621: Redefining name %s from outer scope
# pylint: disable=W0603,W0621
from __future__ import print_function
import getpass
import inspect
import os
@ -27,7 +29,9 @@ import six
from six import moves
from novaclient.openstack.common.apiclient import exceptions
from novaclient.openstack.common.gettextutils import _
from novaclient.openstack.common import strutils
from novaclient.openstack.common import uuidutils
def validate_args(fn, *args, **kwargs):
@ -176,9 +180,9 @@ def print_dict(dct, dict_property="Property", wrap=0):
for k, v in six.iteritems(dct):
# convert dict to str to check length
if isinstance(v, dict):
v = str(v)
v = six.text_type(v)
if wrap > 0:
v = textwrap.fill(str(v), wrap)
v = textwrap.fill(six.text_type(v), wrap)
# 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:
@ -199,7 +203,7 @@ def get_password(max_password_prompts=3):
if hasattr(sys.stdin, "isatty") and sys.stdin.isatty():
# Check for Ctrl-D
try:
for _ in moves.range(max_password_prompts):
for __ in moves.range(max_password_prompts):
pw1 = getpass.getpass("OS Password: ")
if verify:
pw2 = getpass.getpass("Please verify: ")
@ -211,3 +215,95 @@ def get_password(max_password_prompts=3):
except EOFError:
pass
return pw
def find_resource(manager, name_or_id, **find_args):
"""Look for resource in a given manager.
Used as a helper for the _find_* methods.
Example:
def _find_hypervisor(cs, hypervisor):
#Get a hypervisor by name or ID.
return cliutils.find_resource(cs.hypervisors, hypervisor)
"""
# first try to get entity as integer id
try:
return manager.get(int(name_or_id))
except (TypeError, ValueError, exceptions.NotFound):
pass
# now try to get entity as uuid
try:
tmp_id = strutils.safe_encode(name_or_id)
if uuidutils.is_uuid_like(tmp_id):
return manager.get(tmp_id)
except (TypeError, ValueError, exceptions.NotFound):
pass
# for str id which is not uuid
if getattr(manager, 'is_alphanum_id_allowed', False):
try:
return manager.get(name_or_id)
except exceptions.NotFound:
pass
try:
try:
return manager.find(human_id=name_or_id, **find_args)
except exceptions.NotFound:
pass
# finally try to find entity by name
try:
resource = getattr(manager, 'resource_class', None)
name_attr = resource.NAME_ATTR if resource else 'name'
kwargs = {name_attr: name_or_id}
kwargs.update(find_args)
return manager.find(**kwargs)
except exceptions.NotFound:
msg = _("No %(name)s with a name or "
"ID of '%(name_or_id)s' exists.") % \
{
"name": manager.resource_class.__name__.lower(),
"name_or_id": name_or_id
}
raise exceptions.CommandError(msg)
except exceptions.NoUniqueMatch:
msg = _("Multiple %(name)s matches found for "
"'%(name_or_id)s', use an ID to be more specific.") % \
{
"name": manager.resource_class.__name__.lower(),
"name_or_id": name_or_id
}
raise exceptions.CommandError(msg)
def service_type(stype):
"""Adds 'service_type' attribute to decorated function.
Usage:
@service_type('volume')
def mymethod(f):
...
"""
def inner(f):
f.service_type = stype
return f
return inner
def get_service_type(f):
"""Retrieves service type from function."""
return getattr(f, 'service_type', None)
def pretty_choice_list(l):
return ', '.join("'%s'" % i for i in l)
def exit(msg=''):
if msg:
print (msg, file=sys.stderr)
sys.exit(1)