mirror of
https://github.com/ansible/awx.git
synced 2026-01-19 05:31:22 -03:30
Rev pyrax to 1.9.3 and lower python-novaclient to 2.20.0 due to a
strange deprecation warning message that is not suppressable.
This commit is contained in:
parent
6525120c15
commit
c350fafe22
@ -53,13 +53,13 @@ pexpect==3.1 (pexpect/*, excluded pxssh.py, fdpexpect.py, FSM.py, screen.py,
|
||||
ANSI.py)
|
||||
pip==1.5.4 (pip/*, excluded bin/pip*)
|
||||
prettytable==0.7.2 (prettytable.py)
|
||||
pyrax==1.9.0 (pyrax/*)
|
||||
pyrax==1.9.3 (pyrax/*)
|
||||
python-cinderclient==1.1.1 (cinderclient/*)
|
||||
python-dateutil==2.4.0 (dateutil/*)
|
||||
python-glanceclient==0.17.0 (glanceclient/*)
|
||||
python-ironicclient==0.5.0 (ironicclient/*)
|
||||
python-neutronclient==2.3.11 (neutronclient/*)
|
||||
python-novaclient==2.23.0 (novaclient/*, excluded bin/nova)
|
||||
python-novaclient==2.20.0 (novaclient/*, excluded bin/nova)
|
||||
python-swiftclient==2.2.0 (swiftclient/*, excluded bin/swift)
|
||||
python-troveclient==1.0.9 (troveclient/*)
|
||||
pytz==2014.10 (pytz/*)
|
||||
|
||||
@ -20,17 +20,13 @@ Base utilities to build API operation managers and objects on top of.
|
||||
"""
|
||||
|
||||
import abc
|
||||
import contextlib
|
||||
import hashlib
|
||||
import inspect
|
||||
import os
|
||||
import threading
|
||||
|
||||
import six
|
||||
|
||||
from novaclient import exceptions
|
||||
from novaclient.openstack.common.apiclient import base
|
||||
from novaclient.openstack.common import cliutils
|
||||
from novaclient import utils
|
||||
|
||||
Resource = base.Resource
|
||||
|
||||
@ -46,17 +42,24 @@ def getid(obj):
|
||||
return obj
|
||||
|
||||
|
||||
class Manager(base.HookableMixin):
|
||||
class Manager(utils.HookableMixin):
|
||||
"""
|
||||
Managers interact with a particular type of API (servers, flavors, images,
|
||||
etc.) and provide CRUD operations for them.
|
||||
"""
|
||||
resource_class = None
|
||||
cache_lock = threading.RLock()
|
||||
|
||||
def __init__(self, api):
|
||||
self.api = api
|
||||
|
||||
def _write_object_to_completion_cache(self, obj):
|
||||
if hasattr(self.api, 'write_object_to_completion_cache'):
|
||||
self.api.write_object_to_completion_cache(obj)
|
||||
|
||||
def _clear_completion_cache_for_class(self, obj_class):
|
||||
if hasattr(self.api, 'clear_completion_cache_for_class'):
|
||||
self.api.clear_completion_cache_for_class(obj_class)
|
||||
|
||||
def _list(self, url, response_key, obj_class=None, body=None):
|
||||
if body:
|
||||
_resp, body = self.api.client.post(url, body=body)
|
||||
@ -75,86 +78,22 @@ class Manager(base.HookableMixin):
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
with self.completion_cache('human_id', obj_class, mode="w"):
|
||||
with self.completion_cache('uuid', obj_class, mode="w"):
|
||||
return [obj_class(self, res, loaded=True)
|
||||
for res in data if res]
|
||||
self._clear_completion_cache_for_class(obj_class)
|
||||
|
||||
@contextlib.contextmanager
|
||||
def alternate_service_type(self, service_type):
|
||||
original_service_type = self.api.client.service_type
|
||||
self.api.client.service_type = service_type
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
self.api.client.service_type = original_service_type
|
||||
objs = []
|
||||
for res in data:
|
||||
if res:
|
||||
obj = obj_class(self, res, loaded=True)
|
||||
self._write_object_to_completion_cache(obj)
|
||||
objs.append(obj)
|
||||
|
||||
@contextlib.contextmanager
|
||||
def completion_cache(self, cache_type, obj_class, mode):
|
||||
"""
|
||||
The completion cache store items that can be used for bash
|
||||
autocompletion, like UUIDs or human-friendly IDs.
|
||||
|
||||
A resource listing will clear and repopulate the cache.
|
||||
|
||||
A resource create will append to the cache.
|
||||
|
||||
Delete is not handled because listings are assumed to be performed
|
||||
often enough to keep the cache reasonably up-to-date.
|
||||
"""
|
||||
# NOTE(wryan): This lock protects read and write access to the
|
||||
# completion caches
|
||||
with self.cache_lock:
|
||||
base_dir = cliutils.env('NOVACLIENT_UUID_CACHE_DIR',
|
||||
default="~/.novaclient")
|
||||
|
||||
# NOTE(sirp): Keep separate UUID caches for each username +
|
||||
# endpoint pair
|
||||
username = cliutils.env('OS_USERNAME', 'NOVA_USERNAME')
|
||||
url = cliutils.env('OS_URL', 'NOVA_URL')
|
||||
uniqifier = hashlib.md5(username.encode('utf-8') +
|
||||
url.encode('utf-8')).hexdigest()
|
||||
|
||||
cache_dir = os.path.expanduser(os.path.join(base_dir, uniqifier))
|
||||
|
||||
try:
|
||||
os.makedirs(cache_dir, 0o755)
|
||||
except OSError:
|
||||
# NOTE(kiall): This is typically either permission denied while
|
||||
# attempting to create the directory, or the
|
||||
# directory already exists. Either way, don't
|
||||
# fail.
|
||||
pass
|
||||
|
||||
resource = obj_class.__name__.lower()
|
||||
filename = "%s-%s-cache" % (resource, cache_type.replace('_', '-'))
|
||||
path = os.path.join(cache_dir, filename)
|
||||
|
||||
cache_attr = "_%s_cache" % cache_type
|
||||
|
||||
try:
|
||||
setattr(self, cache_attr, open(path, mode))
|
||||
except IOError:
|
||||
# NOTE(kiall): This is typically a permission denied while
|
||||
# attempting to write the cache file.
|
||||
pass
|
||||
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
cache = getattr(self, cache_attr, None)
|
||||
if cache:
|
||||
cache.close()
|
||||
delattr(self, cache_attr)
|
||||
|
||||
def write_to_completion_cache(self, cache_type, val):
|
||||
cache = getattr(self, "_%s_cache" % cache_type, None)
|
||||
if cache:
|
||||
cache.write("%s\n" % val)
|
||||
return objs
|
||||
|
||||
def _get(self, url, response_key):
|
||||
_resp, body = self.api.client.get(url)
|
||||
return self.resource_class(self, body[response_key], loaded=True)
|
||||
obj = self.resource_class(self, body[response_key], loaded=True)
|
||||
self._write_object_to_completion_cache(obj)
|
||||
return obj
|
||||
|
||||
def _create(self, url, body, response_key, return_raw=False, **kwargs):
|
||||
self.run_hooks('modify_body_for_create', body, **kwargs)
|
||||
@ -162,9 +101,9 @@ class Manager(base.HookableMixin):
|
||||
if return_raw:
|
||||
return body[response_key]
|
||||
|
||||
with self.completion_cache('human_id', self.resource_class, mode="a"):
|
||||
with self.completion_cache('uuid', self.resource_class, mode="a"):
|
||||
return self.resource_class(self, body[response_key])
|
||||
obj = self.resource_class(self, body[response_key])
|
||||
self._write_object_to_completion_cache(obj)
|
||||
return obj
|
||||
|
||||
def _delete(self, url):
|
||||
_resp, _body = self.api.client.delete(url)
|
||||
@ -241,10 +180,6 @@ class ManagerWithFind(Manager):
|
||||
list_kwargs['search_opts'] = {"name": kwargs["name"]}
|
||||
elif "display_name" in kwargs:
|
||||
list_kwargs['search_opts'] = {"name": kwargs["display_name"]}
|
||||
if "all_tenants" in kwargs:
|
||||
all_tenants = kwargs['all_tenants']
|
||||
list_kwargs['search_opts']['all_tenants'] = all_tenants
|
||||
searches = [(k, v) for k, v in searches if k != 'all_tenants']
|
||||
|
||||
listing = self.list(**list_kwargs)
|
||||
|
||||
|
||||
@ -21,15 +21,16 @@ OpenStack Client interface. Handles the REST calls and responses.
|
||||
"""
|
||||
|
||||
import copy
|
||||
import errno
|
||||
import functools
|
||||
import glob
|
||||
import hashlib
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
import socket
|
||||
import time
|
||||
|
||||
from keystoneclient import adapter
|
||||
from oslo.utils import importutils
|
||||
from oslo.utils import netutils
|
||||
import requests
|
||||
from requests import adapters
|
||||
@ -42,19 +43,9 @@ except ImportError:
|
||||
from six.moves.urllib import parse
|
||||
|
||||
from novaclient import exceptions
|
||||
from novaclient.i18n import _
|
||||
from novaclient.openstack.common.gettextutils import _
|
||||
from novaclient import service_catalog
|
||||
|
||||
|
||||
class TCPKeepAliveAdapter(adapters.HTTPAdapter):
|
||||
"""The custom adapter used to set TCP Keep-Alive on all connections."""
|
||||
def init_poolmanager(self, *args, **kwargs):
|
||||
if requests.__version__ >= '2.4.1':
|
||||
kwargs.setdefault('socket_options', [
|
||||
(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1),
|
||||
(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1),
|
||||
])
|
||||
super(TCPKeepAliveAdapter, self).init_poolmanager(*args, **kwargs)
|
||||
from novaclient import utils
|
||||
|
||||
|
||||
class _ClientConnectionPool(object):
|
||||
@ -67,42 +58,98 @@ class _ClientConnectionPool(object):
|
||||
Store and reuse HTTP adapters per Service URL.
|
||||
"""
|
||||
if url not in self._adapters:
|
||||
self._adapters[url] = TCPKeepAliveAdapter()
|
||||
self._adapters[url] = adapters.HTTPAdapter()
|
||||
|
||||
return self._adapters[url]
|
||||
|
||||
|
||||
class SessionClient(adapter.LegacyJsonAdapter):
|
||||
class CompletionCache(object):
|
||||
"""The completion cache is how we support tab-completion with novaclient.
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.times = []
|
||||
super(SessionClient, self).__init__(*args, **kwargs)
|
||||
The `Manager` writes object IDs and Human-IDs to the completion-cache on
|
||||
object-show, object-list, and object-create calls.
|
||||
|
||||
The `nova.bash_completion` script then uses these files to provide the
|
||||
actual tab-completion.
|
||||
|
||||
The cache directory layout is:
|
||||
|
||||
~/.novaclient/
|
||||
<hash-of-endpoint-and-username>/
|
||||
<resource>-id-cache
|
||||
<resource>-human-id-cache
|
||||
"""
|
||||
def __init__(self, username, auth_url, attributes=('id', 'human_id')):
|
||||
self.directory = self._make_directory_name(username, auth_url)
|
||||
self.attributes = attributes
|
||||
|
||||
def _make_directory_name(self, username, auth_url):
|
||||
"""Creates a unique directory name based on the auth_url and username
|
||||
of the current user.
|
||||
"""
|
||||
uniqifier = hashlib.md5(username.encode('utf-8') +
|
||||
auth_url.encode('utf-8')).hexdigest()
|
||||
base_dir = utils.env('NOVACLIENT_UUID_CACHE_DIR',
|
||||
default="~/.novaclient")
|
||||
return os.path.expanduser(os.path.join(base_dir, uniqifier))
|
||||
|
||||
def _prepare_directory(self):
|
||||
try:
|
||||
os.makedirs(self.directory, 0o755)
|
||||
except OSError:
|
||||
# NOTE(kiall): This is typically either permission denied while
|
||||
# attempting to create the directory, or the
|
||||
# directory already exists. Either way, don't
|
||||
# fail.
|
||||
pass
|
||||
|
||||
def clear_class(self, obj_class):
|
||||
self._prepare_directory()
|
||||
|
||||
resource = obj_class.__name__.lower()
|
||||
resource_glob = os.path.join(self.directory, "%s-*-cache" % resource)
|
||||
|
||||
for filename in glob.iglob(resource_glob):
|
||||
try:
|
||||
os.unlink(filename)
|
||||
except OSError as e:
|
||||
if e.errno != errno.ENOENT:
|
||||
raise
|
||||
|
||||
def _write_attribute(self, resource, attribute, value):
|
||||
self._prepare_directory()
|
||||
|
||||
filename = "%s-%s-cache" % (resource, attribute.replace('_', '-'))
|
||||
path = os.path.join(self.directory, filename)
|
||||
|
||||
with open(path, 'a') as f:
|
||||
f.write("%s\n" % value)
|
||||
|
||||
def write_object(self, obj):
|
||||
resource = obj.__class__.__name__.lower()
|
||||
|
||||
for attribute in self.attributes:
|
||||
value = getattr(obj, attribute, None)
|
||||
if value:
|
||||
self._write_attribute(resource, attribute, value)
|
||||
|
||||
|
||||
class SessionClient(adapter.LegacyJsonAdapter):
|
||||
|
||||
def request(self, url, method, **kwargs):
|
||||
# NOTE(jamielennox): The standard call raises errors from
|
||||
# keystoneclient, where we need to raise the novaclient errors.
|
||||
raise_exc = kwargs.pop('raise_exc', True)
|
||||
start_time = time.time()
|
||||
resp, body = super(SessionClient, self).request(url,
|
||||
method,
|
||||
raise_exc=False,
|
||||
**kwargs)
|
||||
|
||||
end_time = time.time()
|
||||
self.times.append(('%s %s' % (method, url),
|
||||
start_time, end_time))
|
||||
|
||||
if raise_exc and resp.status_code >= 400:
|
||||
raise exceptions.from_response(resp, body, url, method)
|
||||
|
||||
return resp, body
|
||||
|
||||
def get_timings(self):
|
||||
return self.times
|
||||
|
||||
def reset_timings(self):
|
||||
self.times = []
|
||||
|
||||
|
||||
def _original_only(f):
|
||||
"""Indicates and enforces that this function can only be used if we are
|
||||
@ -145,7 +192,7 @@ class HTTPClient(object):
|
||||
self.tenant_id = tenant_id
|
||||
|
||||
self._connection_pool = (_ClientConnectionPool()
|
||||
if connection_pool else None)
|
||||
if connection_pool else None)
|
||||
|
||||
# This will be called by #_get_password if self.password is None.
|
||||
# EG if a password can only be obtained by prompting the user, but a
|
||||
@ -212,11 +259,6 @@ class HTTPClient(object):
|
||||
# otherwise we will get all the requests logging messages
|
||||
rql.setLevel(logging.WARNING)
|
||||
|
||||
# NOTE(melwitt): Service catalog is only set if bypass_url isn't
|
||||
# used. Otherwise, we can cache using services_url.
|
||||
self.service_catalog = None
|
||||
self.services_url = {}
|
||||
|
||||
def use_token_cache(self, use_it):
|
||||
self.os_cache = use_it
|
||||
|
||||
@ -274,7 +316,7 @@ class HTTPClient(object):
|
||||
if not self.http_log_debug:
|
||||
return
|
||||
|
||||
string_parts = ['curl -g -i']
|
||||
string_parts = ['curl -i']
|
||||
|
||||
if not kwargs.get('verify', True):
|
||||
string_parts.append(' --insecure')
|
||||
@ -335,10 +377,10 @@ class HTTPClient(object):
|
||||
self._session.close()
|
||||
self._current_url = service_url
|
||||
self._logger.debug(
|
||||
"New session created for: (%s)" % service_url)
|
||||
"New session created for: (%s)" % service_url)
|
||||
self._session = requests.Session()
|
||||
self._session.mount(service_url,
|
||||
self._connection_pool.get(service_url))
|
||||
self._connection_pool.get(service_url))
|
||||
return self._session
|
||||
elif self._session:
|
||||
return self._session
|
||||
@ -378,7 +420,7 @@ class HTTPClient(object):
|
||||
# or 'actively refused' in the body, so that's what we'll do.
|
||||
if resp.status_code == 400:
|
||||
if ('Connection refused' in resp.text or
|
||||
'actively refused' in resp.text):
|
||||
'actively refused' in resp.text):
|
||||
raise exceptions.ConnectionRefused(resp.text)
|
||||
try:
|
||||
body = json.loads(resp.text)
|
||||
@ -410,12 +452,7 @@ class HTTPClient(object):
|
||||
path = re.sub(r'v[1-9]/[a-z0-9]+$', '', path)
|
||||
url = parse.urlunsplit((scheme, netloc, path, None, None))
|
||||
else:
|
||||
if self.service_catalog:
|
||||
url = self.get_service_url(self.service_type) + url
|
||||
else:
|
||||
# NOTE(melwitt): The service catalog is not available
|
||||
# when bypass_url is used.
|
||||
url = self.management_url + url
|
||||
url = self.management_url + url
|
||||
|
||||
# Perform the request once. If we get a 401 back then it
|
||||
# might be because the auth token expired, so try to
|
||||
@ -458,19 +495,6 @@ class HTTPClient(object):
|
||||
def delete(self, url, **kwargs):
|
||||
return self._cs_request(url, 'DELETE', **kwargs)
|
||||
|
||||
def get_service_url(self, service_type):
|
||||
if service_type not in self.services_url:
|
||||
url = self.service_catalog.url_for(
|
||||
attr='region',
|
||||
filter_value=self.region_name,
|
||||
endpoint_type=self.endpoint_type,
|
||||
service_type=service_type,
|
||||
service_name=self.service_name,
|
||||
volume_service_name=self.volume_service_name,)
|
||||
url = url.rstrip('/')
|
||||
self.services_url[service_type] = url
|
||||
return self.services_url[service_type]
|
||||
|
||||
def _extract_service_catalog(self, url, resp, body, extract_token=True):
|
||||
"""See what the auth service told us and process the response.
|
||||
We may get redirected to another site, fail or actually get
|
||||
@ -487,7 +511,14 @@ class HTTPClient(object):
|
||||
self.auth_token = self.service_catalog.get_token()
|
||||
self.tenant_id = self.service_catalog.get_tenant_id()
|
||||
|
||||
self.management_url = self.get_service_url(self.service_type)
|
||||
management_url = self.service_catalog.url_for(
|
||||
attr='region',
|
||||
filter_value=self.region_name,
|
||||
endpoint_type=self.endpoint_type,
|
||||
service_type=self.service_type,
|
||||
service_name=self.service_name,
|
||||
volume_service_name=self.volume_service_name,)
|
||||
self.management_url = management_url.rstrip('/')
|
||||
return None
|
||||
except exceptions.AmbiguousEndpoints:
|
||||
print(_("Found more than one valid endpoint. Use a more "
|
||||
@ -527,10 +558,6 @@ class HTTPClient(object):
|
||||
extract_token=False)
|
||||
|
||||
def authenticate(self):
|
||||
if not self.auth_url:
|
||||
msg = _("Authentication requires 'auth_url', which should be "
|
||||
"specified in '%s'") % self.__class__.__name__
|
||||
raise exceptions.AuthorizationFailure(msg)
|
||||
magic_tuple = netutils.urlsplit(self.auth_url)
|
||||
scheme, netloc, path, query, frag = magic_tuple
|
||||
port = magic_tuple.port
|
||||
@ -677,11 +704,11 @@ def _construct_http_client(username=None, password=None, project_id=None,
|
||||
auth_token=None, cacert=None, tenant_id=None,
|
||||
user_id=None, connection_pool=False, session=None,
|
||||
auth=None, user_agent='python-novaclient',
|
||||
interface=None, **kwargs):
|
||||
**kwargs):
|
||||
if session:
|
||||
return SessionClient(session=session,
|
||||
auth=auth,
|
||||
interface=interface or endpoint_type,
|
||||
interface=endpoint_type,
|
||||
service_type=service_type,
|
||||
region_name=region_name,
|
||||
service_name=service_name,
|
||||
@ -718,9 +745,9 @@ def _construct_http_client(username=None, password=None, project_id=None,
|
||||
|
||||
def get_client_class(version):
|
||||
version_map = {
|
||||
'1.1': 'novaclient.v2.client.Client',
|
||||
'2': 'novaclient.v2.client.Client',
|
||||
'3': 'novaclient.v2.client.Client',
|
||||
'1.1': 'novaclient.v1_1.client.Client',
|
||||
'2': 'novaclient.v1_1.client.Client',
|
||||
'3': 'novaclient.v3.client.Client',
|
||||
}
|
||||
try:
|
||||
client_path = version_map[str(version)]
|
||||
@ -730,7 +757,7 @@ def get_client_class(version):
|
||||
'keys': ', '.join(version_map.keys())}
|
||||
raise exceptions.UnsupportedVersion(msg)
|
||||
|
||||
return importutils.import_class(client_path)
|
||||
return utils.import_class(client_path)
|
||||
|
||||
|
||||
def Client(version, *args, **kwargs):
|
||||
|
||||
@ -14,11 +14,10 @@
|
||||
# under the License.
|
||||
|
||||
from novaclient import base
|
||||
from novaclient.openstack.common.apiclient import base as common_base
|
||||
from novaclient import utils
|
||||
|
||||
|
||||
class Extension(common_base.HookableMixin):
|
||||
class Extension(utils.HookableMixin):
|
||||
"""Extension descriptor."""
|
||||
|
||||
SUPPORTED_HOOKS = ('__pre_parse_args__', '__post_parse_args__')
|
||||
|
||||
@ -0,0 +1,17 @@
|
||||
#
|
||||
# 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.
|
||||
|
||||
import six
|
||||
|
||||
|
||||
six.add_move(six.MovedModule('mox', 'mox', 'mox3.mox'))
|
||||
@ -26,12 +26,13 @@ Base utilities to build API operation managers and objects on top of.
|
||||
import abc
|
||||
import copy
|
||||
|
||||
from oslo.utils import strutils
|
||||
import six
|
||||
from six.moves.urllib import parse
|
||||
|
||||
from novaclient.openstack.common._i18n import _
|
||||
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 getid(obj):
|
||||
@ -99,13 +100,12 @@ class BaseManager(HookableMixin):
|
||||
super(BaseManager, self).__init__()
|
||||
self.client = client
|
||||
|
||||
def _list(self, url, response_key=None, obj_class=None, json=None):
|
||||
def _list(self, url, response_key, obj_class=None, json=None):
|
||||
"""List the collection.
|
||||
|
||||
:param url: a partial URL, e.g., '/servers'
|
||||
:param response_key: the key to be looked up in response dictionary,
|
||||
e.g., 'servers'. If response_key is None - all response body
|
||||
will be used.
|
||||
e.g., 'servers'
|
||||
:param obj_class: class for constructing the returned objects
|
||||
(self.resource_class will be used by default)
|
||||
:param json: data that will be encoded as JSON and passed in POST
|
||||
@ -119,7 +119,7 @@ class BaseManager(HookableMixin):
|
||||
if obj_class is None:
|
||||
obj_class = self.resource_class
|
||||
|
||||
data = body[response_key] if response_key is not None else body
|
||||
data = body[response_key]
|
||||
# NOTE(ja): keystone returns values as list as {'values': [ ... ]}
|
||||
# unlike other services which just return the list...
|
||||
try:
|
||||
@ -129,17 +129,15 @@ class BaseManager(HookableMixin):
|
||||
|
||||
return [obj_class(self, res, loaded=True) for res in data if res]
|
||||
|
||||
def _get(self, url, response_key=None):
|
||||
def _get(self, url, response_key):
|
||||
"""Get an object from collection.
|
||||
|
||||
:param url: a partial URL, e.g., '/servers'
|
||||
:param response_key: the key to be looked up in response dictionary,
|
||||
e.g., 'server'. If response_key is None - all response body
|
||||
will be used.
|
||||
e.g., 'server'
|
||||
"""
|
||||
body = self.client.get(url).json()
|
||||
data = body[response_key] if response_key is not None else body
|
||||
return self.resource_class(self, data, loaded=True)
|
||||
return self.resource_class(self, body[response_key], loaded=True)
|
||||
|
||||
def _head(self, url):
|
||||
"""Retrieve request headers for an object.
|
||||
@ -149,23 +147,21 @@ class BaseManager(HookableMixin):
|
||||
resp = self.client.head(url)
|
||||
return resp.status_code == 204
|
||||
|
||||
def _post(self, url, json, response_key=None, return_raw=False):
|
||||
def _post(self, url, json, response_key, return_raw=False):
|
||||
"""Create an object.
|
||||
|
||||
:param url: a partial URL, e.g., '/servers'
|
||||
:param json: data that will be encoded as JSON and passed in POST
|
||||
request (GET will be sent by default)
|
||||
:param response_key: the key to be looked up in response dictionary,
|
||||
e.g., 'server'. If response_key is None - all response body
|
||||
will be used.
|
||||
e.g., 'servers'
|
||||
:param return_raw: flag to force returning raw JSON instead of
|
||||
Python object of self.resource_class
|
||||
"""
|
||||
body = self.client.post(url, json=json).json()
|
||||
data = body[response_key] if response_key is not None else body
|
||||
if return_raw:
|
||||
return data
|
||||
return self.resource_class(self, data)
|
||||
return body[response_key]
|
||||
return self.resource_class(self, body[response_key])
|
||||
|
||||
def _put(self, url, json=None, response_key=None):
|
||||
"""Update an object with PUT method.
|
||||
@ -174,8 +170,7 @@ class BaseManager(HookableMixin):
|
||||
:param json: data that will be encoded as JSON and passed in POST
|
||||
request (GET will be sent by default)
|
||||
:param response_key: the key to be looked up in response dictionary,
|
||||
e.g., 'servers'. If response_key is None - all response body
|
||||
will be used.
|
||||
e.g., 'servers'
|
||||
"""
|
||||
resp = self.client.put(url, json=json)
|
||||
# PUT requests may not return a body
|
||||
@ -193,8 +188,7 @@ class BaseManager(HookableMixin):
|
||||
:param json: data that will be encoded as JSON and passed in POST
|
||||
request (GET will be sent by default)
|
||||
:param response_key: the key to be looked up in response dictionary,
|
||||
e.g., 'servers'. If response_key is None - all response body
|
||||
will be used.
|
||||
e.g., 'servers'
|
||||
"""
|
||||
body = self.client.patch(url, json=json).json()
|
||||
if response_key is not None:
|
||||
@ -443,6 +437,21 @@ class Resource(object):
|
||||
self._info = info
|
||||
self._add_details(info)
|
||||
self._loaded = loaded
|
||||
self._init_completion_cache()
|
||||
|
||||
def _init_completion_cache(self):
|
||||
cache_write = getattr(self.manager, 'write_to_completion_cache', None)
|
||||
if not cache_write:
|
||||
return
|
||||
|
||||
# NOTE(sirp): ensure `id` is already present because if it isn't we'll
|
||||
# enter an infinite loop of __getattr__ -> get -> __init__ ->
|
||||
# __getattr__ -> ...
|
||||
if 'id' in self.__dict__ and uuidutils.is_uuid_like(self.id):
|
||||
cache_write('uuid', self.id)
|
||||
|
||||
if self.human_id:
|
||||
cache_write('human_id', self.human_id)
|
||||
|
||||
def __repr__(self):
|
||||
reprkeys = sorted(k
|
||||
|
||||
@ -33,11 +33,11 @@ try:
|
||||
except ImportError:
|
||||
import json
|
||||
|
||||
from oslo.utils import importutils
|
||||
import requests
|
||||
|
||||
from novaclient.openstack.common._i18n import _
|
||||
from novaclient.openstack.common.apiclient import exceptions
|
||||
from novaclient.openstack.common.gettextutils import _
|
||||
from novaclient.openstack.common import importutils
|
||||
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
@ -104,7 +104,7 @@ class HTTPClient(object):
|
||||
return
|
||||
|
||||
string_parts = [
|
||||
"curl -g -i",
|
||||
"curl -i",
|
||||
"-X '%s'" % method,
|
||||
"'%s'" % url,
|
||||
]
|
||||
@ -156,7 +156,7 @@ class HTTPClient(object):
|
||||
requests.Session.request (such as `headers`) or `json`
|
||||
that will be encoded as JSON and used as `data` argument
|
||||
"""
|
||||
kwargs.setdefault("headers", {})
|
||||
kwargs.setdefault("headers", kwargs.get("headers", {}))
|
||||
kwargs["headers"]["User-Agent"] = self.user_agent
|
||||
if self.original_ip:
|
||||
kwargs["headers"]["Forwarded"] = "for=%s;by=%s" % (
|
||||
@ -247,10 +247,6 @@ class HTTPClient(object):
|
||||
raise
|
||||
self.cached_token = None
|
||||
client.cached_endpoint = None
|
||||
if self.auth_plugin.opts.get('token'):
|
||||
self.auth_plugin.opts['token'] = None
|
||||
if self.auth_plugin.opts.get('endpoint'):
|
||||
self.auth_plugin.opts['endpoint'] = None
|
||||
self.authenticate()
|
||||
try:
|
||||
token, endpoint = self.auth_plugin.token_and_endpoint(
|
||||
@ -361,7 +357,8 @@ class BaseClient(object):
|
||||
"Must be one of: %(version_map)s") % {
|
||||
'api_name': api_name,
|
||||
'version': version,
|
||||
'version_map': ', '.join(version_map.keys())}
|
||||
'version_map': ', '.join(version_map.keys())
|
||||
}
|
||||
raise exceptions.UnsupportedVersion(msg)
|
||||
|
||||
return importutils.import_class(client_path)
|
||||
|
||||
@ -25,7 +25,7 @@ import sys
|
||||
|
||||
import six
|
||||
|
||||
from novaclient.openstack.common._i18n import _
|
||||
from novaclient.openstack.common.gettextutils import _
|
||||
|
||||
|
||||
class ClientException(Exception):
|
||||
@ -34,6 +34,14 @@ class ClientException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class MissingArgs(ClientException):
|
||||
"""Supplied arguments are not sufficient for calling a function."""
|
||||
def __init__(self, missing):
|
||||
self.missing = missing
|
||||
msg = _("Missing arguments: %s") % ", ".join(missing)
|
||||
super(MissingArgs, self).__init__(msg)
|
||||
|
||||
|
||||
class ValidationError(ClientException):
|
||||
"""Error in validation on API client side."""
|
||||
pass
|
||||
@ -439,8 +447,8 @@ def from_response(response, method, url):
|
||||
except ValueError:
|
||||
pass
|
||||
else:
|
||||
if isinstance(body, dict) and isinstance(body.get("error"), dict):
|
||||
error = body["error"]
|
||||
if isinstance(body, dict):
|
||||
error = list(body.values())[0]
|
||||
kwargs["message"] = error.get("message")
|
||||
kwargs["details"] = error.get("details")
|
||||
elif content_type.startswith("text/"):
|
||||
|
||||
@ -33,9 +33,7 @@ from six.moves.urllib import parse
|
||||
from novaclient.openstack.common.apiclient import client
|
||||
|
||||
|
||||
def assert_has_keys(dct, required=None, optional=None):
|
||||
required = required or []
|
||||
optional = optional or []
|
||||
def assert_has_keys(dct, required=[], optional=[]):
|
||||
for k in required:
|
||||
try:
|
||||
assert k in dct
|
||||
|
||||
@ -24,21 +24,14 @@ import os
|
||||
import sys
|
||||
import textwrap
|
||||
|
||||
from oslo.utils import encodeutils
|
||||
from oslo.utils import strutils
|
||||
import prettytable
|
||||
import six
|
||||
from six import moves
|
||||
|
||||
from novaclient.openstack.common._i18n import _
|
||||
|
||||
|
||||
class MissingArgs(Exception):
|
||||
"""Supplied arguments are not sufficient for calling a function."""
|
||||
def __init__(self, missing):
|
||||
self.missing = missing
|
||||
msg = _("Missing arguments: %s") % ", ".join(missing)
|
||||
super(MissingArgs, self).__init__(msg)
|
||||
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):
|
||||
@ -63,7 +56,7 @@ def validate_args(fn, *args, **kwargs):
|
||||
required_args = argspec.args[:len(argspec.args) - num_defaults]
|
||||
|
||||
def isbound(method):
|
||||
return getattr(method, '__self__', None) is not None
|
||||
return getattr(method, 'im_self', None) is not None
|
||||
|
||||
if isbound(fn):
|
||||
required_args.pop(0)
|
||||
@ -71,7 +64,7 @@ def validate_args(fn, *args, **kwargs):
|
||||
missing = [arg for arg in required_args if arg not in kwargs]
|
||||
missing = missing[len(args):]
|
||||
if missing:
|
||||
raise MissingArgs(missing)
|
||||
raise exceptions.MissingArgs(missing)
|
||||
|
||||
|
||||
def arg(*args, **kwargs):
|
||||
@ -139,7 +132,7 @@ def isunauthenticated(func):
|
||||
|
||||
|
||||
def print_list(objs, fields, formatters=None, sortby_index=0,
|
||||
mixed_case_fields=None, field_labels=None):
|
||||
mixed_case_fields=None):
|
||||
"""Print a list or objects as a table, one row per object.
|
||||
|
||||
:param objs: iterable of :class:`Resource`
|
||||
@ -148,22 +141,14 @@ def print_list(objs, fields, formatters=None, sortby_index=0,
|
||||
: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)
|
||||
kwargs = {'sortby': fields[sortby_index]}
|
||||
pt = prettytable.PrettyTable(fields, caching=False)
|
||||
pt.align = 'l'
|
||||
|
||||
for o in objs:
|
||||
@ -180,7 +165,7 @@ def print_list(objs, fields, formatters=None, sortby_index=0,
|
||||
row.append(data)
|
||||
pt.add_row(row)
|
||||
|
||||
print(encodeutils.safe_encode(pt.get_string(**kwargs)))
|
||||
print(strutils.safe_encode(pt.get_string(**kwargs)))
|
||||
|
||||
|
||||
def print_dict(dct, dict_property="Property", wrap=0):
|
||||
@ -190,7 +175,7 @@ def print_dict(dct, dict_property="Property", wrap=0):
|
||||
:param dict_property: name of the first column
|
||||
:param wrap: wrapping for the second column
|
||||
"""
|
||||
pt = prettytable.PrettyTable([dict_property, 'Value'])
|
||||
pt = prettytable.PrettyTable([dict_property, 'Value'], caching=False)
|
||||
pt.align = 'l'
|
||||
for k, v in six.iteritems(dct):
|
||||
# convert dict to str to check length
|
||||
@ -208,7 +193,7 @@ def print_dict(dct, dict_property="Property", wrap=0):
|
||||
col1 = ''
|
||||
else:
|
||||
pt.add_row([k, v])
|
||||
print(encodeutils.safe_encode(pt.get_string()))
|
||||
print(strutils.safe_encode(pt.get_string()))
|
||||
|
||||
|
||||
def get_password(max_password_prompts=3):
|
||||
@ -232,16 +217,76 @@ def get_password(max_password_prompts=3):
|
||||
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:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@service_type('volume')
|
||||
def mymethod(f):
|
||||
...
|
||||
@service_type('volume')
|
||||
def mymethod(f):
|
||||
...
|
||||
"""
|
||||
def inner(f):
|
||||
f.service_type = stype
|
||||
|
||||
@ -32,24 +32,113 @@ import os
|
||||
from babel import localedata
|
||||
import six
|
||||
|
||||
_localedir = os.environ.get('novaclient'.upper() + '_LOCALEDIR')
|
||||
_t = gettext.translation('novaclient', localedir=_localedir, fallback=True)
|
||||
|
||||
# We use separate translation catalogs for each log level, so set up a
|
||||
# mapping between the log level name and the translator. The domain
|
||||
# for the log level is project_name + "-log-" + log_level so messages
|
||||
# for each level end up in their own catalog.
|
||||
_t_log_levels = dict(
|
||||
(level, gettext.translation('novaclient' + '-log-' + level,
|
||||
localedir=_localedir,
|
||||
fallback=True))
|
||||
for level in ['info', 'warning', 'error', 'critical']
|
||||
)
|
||||
|
||||
_AVAILABLE_LANGUAGES = {}
|
||||
|
||||
# FIXME(dhellmann): Remove this when moving to oslo.i18n.
|
||||
USE_LAZY = False
|
||||
|
||||
|
||||
class TranslatorFactory(object):
|
||||
"""Create translator functions
|
||||
"""
|
||||
|
||||
def __init__(self, domain, lazy=False, localedir=None):
|
||||
"""Establish a set of translation functions for the domain.
|
||||
|
||||
:param domain: Name of translation domain,
|
||||
specifying a message catalog.
|
||||
:type domain: str
|
||||
:param lazy: Delays translation until a message is emitted.
|
||||
Defaults to False.
|
||||
:type lazy: Boolean
|
||||
:param localedir: Directory with translation catalogs.
|
||||
:type localedir: str
|
||||
"""
|
||||
self.domain = domain
|
||||
self.lazy = lazy
|
||||
if localedir is None:
|
||||
localedir = os.environ.get(domain.upper() + '_LOCALEDIR')
|
||||
self.localedir = localedir
|
||||
|
||||
def _make_translation_func(self, domain=None):
|
||||
"""Return a new translation function ready for use.
|
||||
|
||||
Takes into account whether or not lazy translation is being
|
||||
done.
|
||||
|
||||
The domain can be specified to override the default from the
|
||||
factory, but the localedir from the factory is always used
|
||||
because we assume the log-level translation catalogs are
|
||||
installed in the same directory as the main application
|
||||
catalog.
|
||||
|
||||
"""
|
||||
if domain is None:
|
||||
domain = self.domain
|
||||
if self.lazy:
|
||||
return functools.partial(Message, domain=domain)
|
||||
t = gettext.translation(
|
||||
domain,
|
||||
localedir=self.localedir,
|
||||
fallback=True,
|
||||
)
|
||||
if six.PY3:
|
||||
return t.gettext
|
||||
return t.ugettext
|
||||
|
||||
@property
|
||||
def primary(self):
|
||||
"The default translation function."
|
||||
return self._make_translation_func()
|
||||
|
||||
def _make_log_translation_func(self, level):
|
||||
return self._make_translation_func(self.domain + '-log-' + level)
|
||||
|
||||
@property
|
||||
def log_info(self):
|
||||
"Translate info-level log messages."
|
||||
return self._make_log_translation_func('info')
|
||||
|
||||
@property
|
||||
def log_warning(self):
|
||||
"Translate warning-level log messages."
|
||||
return self._make_log_translation_func('warning')
|
||||
|
||||
@property
|
||||
def log_error(self):
|
||||
"Translate error-level log messages."
|
||||
return self._make_log_translation_func('error')
|
||||
|
||||
@property
|
||||
def log_critical(self):
|
||||
"Translate critical-level log messages."
|
||||
return self._make_log_translation_func('critical')
|
||||
|
||||
|
||||
# NOTE(dhellmann): When this module moves out of the incubator into
|
||||
# oslo.i18n, these global variables can be moved to an integration
|
||||
# module within each application.
|
||||
|
||||
# Create the global translation functions.
|
||||
_translators = TranslatorFactory('novaclient')
|
||||
|
||||
# The primary translation function using the well-known name "_"
|
||||
_ = _translators.primary
|
||||
|
||||
# Translators for log levels.
|
||||
#
|
||||
# The abbreviated names are meant to reflect the usual use of a short
|
||||
# name like '_'. The "L" is for "log" and the other letter comes from
|
||||
# the level.
|
||||
_LI = _translators.log_info
|
||||
_LW = _translators.log_warning
|
||||
_LE = _translators.log_error
|
||||
_LC = _translators.log_critical
|
||||
|
||||
# NOTE(dhellmann): End of globals that will move to the application's
|
||||
# integration module.
|
||||
|
||||
|
||||
def enable_lazy():
|
||||
"""Convenience function for configuring _() to use lazy gettext
|
||||
|
||||
@ -58,41 +147,18 @@ def enable_lazy():
|
||||
your project is importing _ directly instead of using the
|
||||
gettextutils.install() way of importing the _ function.
|
||||
"""
|
||||
global USE_LAZY
|
||||
# FIXME(dhellmann): This function will be removed in oslo.i18n,
|
||||
# because the TranslatorFactory makes it superfluous.
|
||||
global _, _LI, _LW, _LE, _LC, USE_LAZY
|
||||
tf = TranslatorFactory('novaclient', lazy=True)
|
||||
_ = tf.primary
|
||||
_LI = tf.log_info
|
||||
_LW = tf.log_warning
|
||||
_LE = tf.log_error
|
||||
_LC = tf.log_critical
|
||||
USE_LAZY = True
|
||||
|
||||
|
||||
def _(msg):
|
||||
if USE_LAZY:
|
||||
return Message(msg, domain='novaclient')
|
||||
else:
|
||||
if six.PY3:
|
||||
return _t.gettext(msg)
|
||||
return _t.ugettext(msg)
|
||||
|
||||
|
||||
def _log_translation(msg, level):
|
||||
"""Build a single translation of a log message
|
||||
"""
|
||||
if USE_LAZY:
|
||||
return Message(msg, domain='novaclient' + '-log-' + level)
|
||||
else:
|
||||
translator = _t_log_levels[level]
|
||||
if six.PY3:
|
||||
return translator.gettext(msg)
|
||||
return translator.ugettext(msg)
|
||||
|
||||
# Translators for log levels.
|
||||
#
|
||||
# The abbreviated names are meant to reflect the usual use of a short
|
||||
# name like '_'. The "L" is for "log" and the other letter comes from
|
||||
# the level.
|
||||
_LI = functools.partial(_log_translation, level='info')
|
||||
_LW = functools.partial(_log_translation, level='warning')
|
||||
_LE = functools.partial(_log_translation, level='error')
|
||||
_LC = functools.partial(_log_translation, level='critical')
|
||||
|
||||
|
||||
def install(domain, lazy=False):
|
||||
"""Install a _() function using the given translation domain.
|
||||
|
||||
@ -112,26 +178,9 @@ def install(domain, lazy=False):
|
||||
any available locale.
|
||||
"""
|
||||
if lazy:
|
||||
# NOTE(mrodden): Lazy gettext functionality.
|
||||
#
|
||||
# The following introduces a deferred way to do translations on
|
||||
# messages in OpenStack. We override the standard _() function
|
||||
# and % (format string) operation to build Message objects that can
|
||||
# later be translated when we have more information.
|
||||
def _lazy_gettext(msg):
|
||||
"""Create and return a Message object.
|
||||
|
||||
Lazy gettext function for a given domain, it is a factory method
|
||||
for a project/module to get a lazy gettext function for its own
|
||||
translation domain (i.e. nova, glance, cinder, etc.)
|
||||
|
||||
Message encapsulates a string so that we can translate
|
||||
it later when needed.
|
||||
"""
|
||||
return Message(msg, domain=domain)
|
||||
|
||||
from six import moves
|
||||
moves.builtins.__dict__['_'] = _lazy_gettext
|
||||
tf = TranslatorFactory(domain, lazy=True)
|
||||
moves.builtins.__dict__['_'] = tf.primary
|
||||
else:
|
||||
localedir = '%s_LOCALEDIR' % domain.upper()
|
||||
if six.PY3:
|
||||
@ -274,13 +323,14 @@ class Message(six.text_type):
|
||||
def __radd__(self, other):
|
||||
return self.__add__(other)
|
||||
|
||||
def __str__(self):
|
||||
# NOTE(luisg): Logging in python 2.6 tries to str() log records,
|
||||
# and it expects specifically a UnicodeError in order to proceed.
|
||||
msg = _('Message objects do not support str() because they may '
|
||||
'contain non-ascii characters. '
|
||||
'Please use unicode() or translate() instead.')
|
||||
raise UnicodeError(msg)
|
||||
if six.PY2:
|
||||
def __str__(self):
|
||||
# NOTE(luisg): Logging in python 2.6 tries to str() log records,
|
||||
# and it expects specifically a UnicodeError in order to proceed.
|
||||
msg = _('Message objects do not support str() because they may '
|
||||
'contain non-ascii characters. '
|
||||
'Please use unicode() or translate() instead.')
|
||||
raise UnicodeError(msg)
|
||||
|
||||
|
||||
def get_available_languages(domain):
|
||||
@ -323,8 +373,8 @@ def get_available_languages(domain):
|
||||
'zh_Hant_HK': 'zh_HK',
|
||||
'zh_Hant': 'zh_TW',
|
||||
'fil': 'tl_PH'}
|
||||
for (locale, alias) in six.iteritems(aliases):
|
||||
if locale in language_list and alias not in language_list:
|
||||
for (locale_, alias) in six.iteritems(aliases):
|
||||
if locale_ in language_list and alias not in language_list:
|
||||
language_list.append(alias)
|
||||
|
||||
_AVAILABLE_LANGUAGES[domain] = language_list
|
||||
|
||||
@ -24,10 +24,10 @@ import traceback
|
||||
def import_class(import_str):
|
||||
"""Returns a class from a string including module and class."""
|
||||
mod_str, _sep, class_str = import_str.rpartition('.')
|
||||
__import__(mod_str)
|
||||
try:
|
||||
__import__(mod_str)
|
||||
return getattr(sys.modules[mod_str], class_str)
|
||||
except (ValueError, AttributeError):
|
||||
except AttributeError:
|
||||
raise ImportError('Class %s cannot be found (%s)' %
|
||||
(class_str,
|
||||
traceback.format_exception(*sys.exc_info())))
|
||||
|
||||
@ -32,8 +32,8 @@ class ServiceCatalog(object):
|
||||
return self.catalog['access']['token']['tenant']['id']
|
||||
|
||||
def url_for(self, attr=None, filter_value=None,
|
||||
service_type=None, endpoint_type='publicURL',
|
||||
service_name=None, volume_service_name=None):
|
||||
service_type=None, endpoint_type='publicURL',
|
||||
service_name=None, volume_service_name=None):
|
||||
"""Fetch the public URL from the Compute service for
|
||||
a particular endpoint attribute. If none given, return
|
||||
the first. See tests for sample service catalog.
|
||||
@ -72,11 +72,11 @@ class ServiceCatalog(object):
|
||||
endpoints = service['endpoints']
|
||||
for endpoint in endpoints:
|
||||
# Ignore 1.0 compute endpoints
|
||||
if (service.get("type") == 'compute' and
|
||||
endpoint.get('versionId', '2') not in ('1.1', '2')):
|
||||
if service.get("type") == 'compute' and \
|
||||
endpoint.get('versionId', '2') not in ('1.1', '2'):
|
||||
continue
|
||||
if (not filter_value or
|
||||
endpoint.get(attr).lower() == filter_value.lower()):
|
||||
if not filter_value or \
|
||||
endpoint.get(attr).lower() == filter_value.lower():
|
||||
endpoint["serviceName"] = service.get("name")
|
||||
matching_endpoints.append(endpoint)
|
||||
|
||||
@ -84,6 +84,6 @@ class ServiceCatalog(object):
|
||||
raise novaclient.exceptions.EndpointNotFound()
|
||||
elif len(matching_endpoints) > 1:
|
||||
raise novaclient.exceptions.AmbiguousEndpoints(
|
||||
endpoints=matching_endpoints)
|
||||
endpoints=matching_endpoints)
|
||||
else:
|
||||
return matching_endpoints[0][endpoint_type]
|
||||
|
||||
@ -28,12 +28,7 @@ import logging
|
||||
import os
|
||||
import pkgutil
|
||||
import sys
|
||||
import time
|
||||
|
||||
from keystoneclient.auth.identity.generic import password
|
||||
from keystoneclient.auth.identity.generic import token
|
||||
from keystoneclient.auth.identity import v3 as identity
|
||||
from keystoneclient import session as ksession
|
||||
from oslo.utils import encodeutils
|
||||
from oslo.utils import strutils
|
||||
import pkg_resources
|
||||
@ -52,12 +47,13 @@ import novaclient.auth_plugin
|
||||
from novaclient import client
|
||||
from novaclient import exceptions as exc
|
||||
import novaclient.extension
|
||||
from novaclient.i18n import _
|
||||
from novaclient.openstack.common import cliutils
|
||||
from novaclient.openstack.common.gettextutils import _
|
||||
from novaclient import utils
|
||||
from novaclient.v2 import shell as shell_v2
|
||||
from novaclient.v1_1 import shell as shell_v1_1
|
||||
from novaclient.v3 import shell as shell_v3
|
||||
|
||||
DEFAULT_OS_COMPUTE_API_VERSION = "2"
|
||||
DEFAULT_OS_COMPUTE_API_VERSION = "1.1"
|
||||
DEFAULT_NOVA_ENDPOINT_TYPE = 'publicURL'
|
||||
# NOTE(cyeoh): Having the service type dependent on the API version
|
||||
# is pretty ugly, but we have to do this because traditionally the
|
||||
@ -139,7 +135,7 @@ class SecretsHelper(object):
|
||||
if not HAS_KEYRING or not self.args.os_cache:
|
||||
return
|
||||
if (auth_token == self.auth_token and
|
||||
management_url == self.management_url):
|
||||
management_url == self.management_url):
|
||||
# Nothing changed....
|
||||
return
|
||||
if not all([management_url, auth_token, tenant_id]):
|
||||
@ -159,7 +155,7 @@ class SecretsHelper(object):
|
||||
self._password = self.args.os_password
|
||||
else:
|
||||
verify_pass = strutils.bool_from_string(
|
||||
cliutils.env("OS_VERIFY_PASSWORD", default=False), True)
|
||||
utils.env("OS_VERIFY_PASSWORD", default=False), True)
|
||||
self._password = self._prompt_password(verify_pass)
|
||||
if not self._password:
|
||||
raise exc.CommandError(
|
||||
@ -228,47 +224,13 @@ class NovaClientArgumentParser(argparse.ArgumentParser):
|
||||
choose_from = ' (choose from'
|
||||
progparts = self.prog.partition(' ')
|
||||
self.exit(2, _("error: %(errmsg)s\nTry '%(mainp)s help %(subp)s'"
|
||||
" for more information.\n") %
|
||||
{'errmsg': message.split(choose_from)[0],
|
||||
'mainp': progparts[0],
|
||||
'subp': progparts[2]})
|
||||
|
||||
def _get_option_tuples(self, option_string):
|
||||
"""returns (action, option, value) candidates for an option prefix
|
||||
|
||||
Returns [first candidate] if all candidates refers to current and
|
||||
deprecated forms of the same options: "nova boot ... --key KEY"
|
||||
parsing succeed because --key could only match --key-name,
|
||||
--key_name which are current/deprecated forms of the same option.
|
||||
"""
|
||||
option_tuples = (super(NovaClientArgumentParser, self)
|
||||
._get_option_tuples(option_string))
|
||||
if len(option_tuples) > 1:
|
||||
normalizeds = [option.replace('_', '-')
|
||||
for action, option, value in option_tuples]
|
||||
if len(set(normalizeds)) == 1:
|
||||
return option_tuples[:1]
|
||||
return option_tuples
|
||||
" for more information.\n") %
|
||||
{'errmsg': message.split(choose_from)[0],
|
||||
'mainp': progparts[0],
|
||||
'subp': progparts[2]})
|
||||
|
||||
|
||||
class OpenStackComputeShell(object):
|
||||
times = []
|
||||
|
||||
def _append_global_identity_args(self, parser):
|
||||
# Register the CLI arguments that have moved to the session object.
|
||||
ksession.Session.register_cli_options(parser)
|
||||
|
||||
parser.set_defaults(insecure=cliutils.env('NOVACLIENT_INSECURE',
|
||||
default=False))
|
||||
|
||||
identity.Password.register_argparse_arguments(parser)
|
||||
|
||||
parser.set_defaults(os_username=cliutils.env('OS_USERNAME',
|
||||
'NOVA_USERNAME'))
|
||||
parser.set_defaults(os_password=cliutils.env('OS_PASSWORD',
|
||||
'NOVA_PASSWORD'))
|
||||
parser.set_defaults(os_auth_url=cliutils.env('OS_AUTH_URL',
|
||||
'NOVA_URL'))
|
||||
|
||||
def get_base_parser(self):
|
||||
parser = NovaClientArgumentParser(
|
||||
@ -281,8 +243,7 @@ class OpenStackComputeShell(object):
|
||||
)
|
||||
|
||||
# Global arguments
|
||||
parser.add_argument(
|
||||
'-h', '--help',
|
||||
parser.add_argument('-h', '--help',
|
||||
action='store_true',
|
||||
help=argparse.SUPPRESS,
|
||||
)
|
||||
@ -291,118 +252,111 @@ class OpenStackComputeShell(object):
|
||||
action='version',
|
||||
version=novaclient.__version__)
|
||||
|
||||
parser.add_argument(
|
||||
'--debug',
|
||||
parser.add_argument('--debug',
|
||||
default=False,
|
||||
action='store_true',
|
||||
help=_("Print debugging output"))
|
||||
|
||||
parser.add_argument(
|
||||
'--os-cache',
|
||||
parser.add_argument('--os-cache',
|
||||
default=strutils.bool_from_string(
|
||||
cliutils.env('OS_CACHE', default=False), True),
|
||||
utils.env('OS_CACHE', default=False), True),
|
||||
action='store_true',
|
||||
help=_("Use the auth token cache. Defaults to False if "
|
||||
"env[OS_CACHE] is not set."))
|
||||
|
||||
parser.add_argument(
|
||||
'--timings',
|
||||
parser.add_argument('--timings',
|
||||
default=False,
|
||||
action='store_true',
|
||||
help=_("Print call timing info"))
|
||||
|
||||
parser.add_argument(
|
||||
'--os-auth-token',
|
||||
default=cliutils.env('OS_AUTH_TOKEN'),
|
||||
help='Defaults to env[OS_AUTH_TOKEN]')
|
||||
parser.add_argument('--timeout',
|
||||
default=600,
|
||||
metavar='<seconds>',
|
||||
type=positive_non_zero_float,
|
||||
help=_("Set HTTP call timeout (in seconds)"))
|
||||
|
||||
parser.add_argument(
|
||||
'--os_username',
|
||||
parser.add_argument('--os-auth-token',
|
||||
default=utils.env('OS_AUTH_TOKEN'),
|
||||
help='Defaults to env[OS_AUTH_TOKEN]')
|
||||
|
||||
parser.add_argument('--os-username',
|
||||
metavar='<auth-user-name>',
|
||||
default=utils.env('OS_USERNAME', 'NOVA_USERNAME'),
|
||||
help=_('Defaults to env[OS_USERNAME].'))
|
||||
parser.add_argument('--os_username',
|
||||
help=argparse.SUPPRESS)
|
||||
|
||||
parser.add_argument(
|
||||
'--os_password',
|
||||
parser.add_argument('--os-user-id',
|
||||
metavar='<auth-user-id>',
|
||||
default=utils.env('OS_USER_ID'),
|
||||
help=_('Defaults to env[OS_USER_ID].'))
|
||||
|
||||
parser.add_argument('--os-password',
|
||||
metavar='<auth-password>',
|
||||
default=utils.env('OS_PASSWORD', 'NOVA_PASSWORD'),
|
||||
help=_('Defaults to env[OS_PASSWORD].'))
|
||||
parser.add_argument('--os_password',
|
||||
help=argparse.SUPPRESS)
|
||||
|
||||
parser.add_argument(
|
||||
'--os-tenant-name',
|
||||
parser.add_argument('--os-tenant-name',
|
||||
metavar='<auth-tenant-name>',
|
||||
default=cliutils.env('OS_TENANT_NAME', 'NOVA_PROJECT_ID'),
|
||||
default=utils.env('OS_TENANT_NAME', 'NOVA_PROJECT_ID'),
|
||||
help=_('Defaults to env[OS_TENANT_NAME].'))
|
||||
parser.add_argument(
|
||||
'--os_tenant_name',
|
||||
parser.add_argument('--os_tenant_name',
|
||||
help=argparse.SUPPRESS)
|
||||
|
||||
parser.add_argument(
|
||||
'--os-tenant-id',
|
||||
parser.add_argument('--os-tenant-id',
|
||||
metavar='<auth-tenant-id>',
|
||||
default=cliutils.env('OS_TENANT_ID'),
|
||||
default=utils.env('OS_TENANT_ID'),
|
||||
help=_('Defaults to env[OS_TENANT_ID].'))
|
||||
|
||||
parser.add_argument(
|
||||
'--os_auth_url',
|
||||
parser.add_argument('--os-auth-url',
|
||||
metavar='<auth-url>',
|
||||
default=utils.env('OS_AUTH_URL', 'NOVA_URL'),
|
||||
help=_('Defaults to env[OS_AUTH_URL].'))
|
||||
parser.add_argument('--os_auth_url',
|
||||
help=argparse.SUPPRESS)
|
||||
|
||||
parser.add_argument(
|
||||
'--os-region-name',
|
||||
parser.add_argument('--os-region-name',
|
||||
metavar='<region-name>',
|
||||
default=cliutils.env('OS_REGION_NAME', 'NOVA_REGION_NAME'),
|
||||
default=utils.env('OS_REGION_NAME', 'NOVA_REGION_NAME'),
|
||||
help=_('Defaults to env[OS_REGION_NAME].'))
|
||||
parser.add_argument(
|
||||
'--os_region_name',
|
||||
parser.add_argument('--os_region_name',
|
||||
help=argparse.SUPPRESS)
|
||||
|
||||
parser.add_argument(
|
||||
'--os-auth-system',
|
||||
parser.add_argument('--os-auth-system',
|
||||
metavar='<auth-system>',
|
||||
default=cliutils.env('OS_AUTH_SYSTEM'),
|
||||
default=utils.env('OS_AUTH_SYSTEM'),
|
||||
help='Defaults to env[OS_AUTH_SYSTEM].')
|
||||
parser.add_argument(
|
||||
'--os_auth_system',
|
||||
parser.add_argument('--os_auth_system',
|
||||
help=argparse.SUPPRESS)
|
||||
|
||||
parser.add_argument(
|
||||
'--service-type',
|
||||
parser.add_argument('--service-type',
|
||||
metavar='<service-type>',
|
||||
help=_('Defaults to compute for most actions'))
|
||||
parser.add_argument(
|
||||
'--service_type',
|
||||
parser.add_argument('--service_type',
|
||||
help=argparse.SUPPRESS)
|
||||
|
||||
parser.add_argument(
|
||||
'--service-name',
|
||||
parser.add_argument('--service-name',
|
||||
metavar='<service-name>',
|
||||
default=cliutils.env('NOVA_SERVICE_NAME'),
|
||||
default=utils.env('NOVA_SERVICE_NAME'),
|
||||
help=_('Defaults to env[NOVA_SERVICE_NAME]'))
|
||||
parser.add_argument(
|
||||
'--service_name',
|
||||
parser.add_argument('--service_name',
|
||||
help=argparse.SUPPRESS)
|
||||
|
||||
parser.add_argument(
|
||||
'--volume-service-name',
|
||||
parser.add_argument('--volume-service-name',
|
||||
metavar='<volume-service-name>',
|
||||
default=cliutils.env('NOVA_VOLUME_SERVICE_NAME'),
|
||||
default=utils.env('NOVA_VOLUME_SERVICE_NAME'),
|
||||
help=_('Defaults to env[NOVA_VOLUME_SERVICE_NAME]'))
|
||||
parser.add_argument(
|
||||
'--volume_service_name',
|
||||
parser.add_argument('--volume_service_name',
|
||||
help=argparse.SUPPRESS)
|
||||
|
||||
parser.add_argument(
|
||||
'--os-endpoint-type',
|
||||
parser.add_argument('--endpoint-type',
|
||||
metavar='<endpoint-type>',
|
||||
dest='endpoint_type',
|
||||
default=cliutils.env(
|
||||
'NOVA_ENDPOINT_TYPE',
|
||||
default=cliutils.env(
|
||||
'OS_ENDPOINT_TYPE',
|
||||
default=DEFAULT_NOVA_ENDPOINT_TYPE)),
|
||||
help=_('Defaults to env[NOVA_ENDPOINT_TYPE], '
|
||||
'env[OS_ENDPOINT_TYPE] or ') +
|
||||
DEFAULT_NOVA_ENDPOINT_TYPE + '.')
|
||||
|
||||
parser.add_argument(
|
||||
'--endpoint-type',
|
||||
help=argparse.SUPPRESS)
|
||||
default=utils.env('NOVA_ENDPOINT_TYPE',
|
||||
default=DEFAULT_NOVA_ENDPOINT_TYPE),
|
||||
help=_('Defaults to env[NOVA_ENDPOINT_TYPE] or ')
|
||||
+ DEFAULT_NOVA_ENDPOINT_TYPE + '.')
|
||||
# NOTE(dtroyer): We can't add --endpoint_type here due to argparse
|
||||
# thinking usage-list --end is ambiguous; but it
|
||||
# works fine with only --endpoint-type present
|
||||
@ -410,32 +364,42 @@ class OpenStackComputeShell(object):
|
||||
# parser.add_argument('--endpoint_type',
|
||||
# help=argparse.SUPPRESS)
|
||||
|
||||
parser.add_argument(
|
||||
'--os-compute-api-version',
|
||||
parser.add_argument('--os-compute-api-version',
|
||||
metavar='<compute-api-ver>',
|
||||
default=cliutils.env('OS_COMPUTE_API_VERSION',
|
||||
default=DEFAULT_OS_COMPUTE_API_VERSION),
|
||||
default=utils.env('OS_COMPUTE_API_VERSION',
|
||||
default=DEFAULT_OS_COMPUTE_API_VERSION),
|
||||
help=_('Accepts 1.1 or 3, '
|
||||
'defaults to env[OS_COMPUTE_API_VERSION].'))
|
||||
parser.add_argument(
|
||||
'--os_compute_api_version',
|
||||
'defaults to env[OS_COMPUTE_API_VERSION].'))
|
||||
parser.add_argument('--os_compute_api_version',
|
||||
help=argparse.SUPPRESS)
|
||||
|
||||
parser.add_argument(
|
||||
'--bypass-url',
|
||||
parser.add_argument('--os-cacert',
|
||||
metavar='<ca-certificate>',
|
||||
default=utils.env('OS_CACERT', default=None),
|
||||
help='Specify a CA bundle file to use in '
|
||||
'verifying a TLS (https) server certificate. '
|
||||
'Defaults to env[OS_CACERT]')
|
||||
|
||||
parser.add_argument('--insecure',
|
||||
default=utils.env('NOVACLIENT_INSECURE', default=False),
|
||||
action='store_true',
|
||||
help=_("Explicitly allow novaclient to perform \"insecure\" "
|
||||
"SSL (https) requests. The server's certificate will "
|
||||
"not be verified against any certificate authorities. "
|
||||
"This option should be used with caution."))
|
||||
|
||||
parser.add_argument('--bypass-url',
|
||||
metavar='<bypass-url>',
|
||||
dest='bypass_url',
|
||||
default=cliutils.env('NOVACLIENT_BYPASS_URL'),
|
||||
default=utils.env('NOVACLIENT_BYPASS_URL'),
|
||||
help="Use this API endpoint instead of the Service Catalog. "
|
||||
"Defaults to env[NOVACLIENT_BYPASS_URL]")
|
||||
parser.add_argument('--bypass_url',
|
||||
help=argparse.SUPPRESS)
|
||||
help=argparse.SUPPRESS)
|
||||
|
||||
# The auth-system-plugins might require some extra options
|
||||
novaclient.auth_plugin.load_auth_system_opts(parser)
|
||||
|
||||
self._append_global_identity_args(parser)
|
||||
|
||||
return parser
|
||||
|
||||
def get_subcommand_parser(self, version):
|
||||
@ -446,12 +410,12 @@ class OpenStackComputeShell(object):
|
||||
|
||||
try:
|
||||
actions_module = {
|
||||
'1.1': shell_v2,
|
||||
'2': shell_v2,
|
||||
'3': shell_v2,
|
||||
'1.1': shell_v1_1,
|
||||
'2': shell_v1_1,
|
||||
'3': shell_v3,
|
||||
}[version]
|
||||
except KeyError:
|
||||
actions_module = shell_v2
|
||||
actions_module = shell_v1_1
|
||||
|
||||
self._find_actions(subparsers, actions_module)
|
||||
self._find_actions(subparsers, self)
|
||||
@ -491,10 +455,6 @@ class OpenStackComputeShell(object):
|
||||
def _discover_via_contrib_path(self, version):
|
||||
module_path = os.path.dirname(os.path.abspath(__file__))
|
||||
version_str = "v%s" % version.replace('.', '_')
|
||||
# NOTE(akurilin): v1.1, v2 and v3 have one implementation, so
|
||||
# we should discover contrib modules in one place.
|
||||
if version_str in ["v1_1", "v3"]:
|
||||
version_str = "v2"
|
||||
ext_path = os.path.join(module_path, version_str, 'contrib')
|
||||
ext_glob = os.path.join(ext_path, "*.py")
|
||||
|
||||
@ -515,8 +475,7 @@ class OpenStackComputeShell(object):
|
||||
yield name, module
|
||||
|
||||
def _add_bash_completion_subparser(self, subparsers):
|
||||
subparser = subparsers.add_parser(
|
||||
'bash_completion',
|
||||
subparser = subparsers.add_parser('bash_completion',
|
||||
add_help=False,
|
||||
formatter_class=OpenStackHelpFormatter
|
||||
)
|
||||
@ -532,14 +491,13 @@ class OpenStackComputeShell(object):
|
||||
action_help = desc.strip()
|
||||
arguments = getattr(callback, 'arguments', [])
|
||||
|
||||
subparser = subparsers.add_parser(
|
||||
command,
|
||||
subparser = subparsers.add_parser(command,
|
||||
help=action_help,
|
||||
description=desc,
|
||||
add_help=False,
|
||||
formatter_class=OpenStackHelpFormatter)
|
||||
subparser.add_argument(
|
||||
'-h', '--help',
|
||||
formatter_class=OpenStackHelpFormatter
|
||||
)
|
||||
subparser.add_argument('-h', '--help',
|
||||
action='help',
|
||||
help=argparse.SUPPRESS,
|
||||
)
|
||||
@ -558,20 +516,6 @@ class OpenStackComputeShell(object):
|
||||
logging.basicConfig(level=logging.DEBUG,
|
||||
format=streamformat)
|
||||
|
||||
def _get_keystone_auth(self, session, auth_url, **kwargs):
|
||||
auth_token = kwargs.pop('auth_token', None)
|
||||
if auth_token:
|
||||
return token.Token(auth_url, auth_token, **kwargs)
|
||||
else:
|
||||
return password.Password(
|
||||
auth_url,
|
||||
username=kwargs.pop('username'),
|
||||
user_id=kwargs.pop('user_id'),
|
||||
password=kwargs.pop('password'),
|
||||
user_domain_id=kwargs.pop('user_domain_id'),
|
||||
user_domain_name=kwargs.pop('user_domain_name'),
|
||||
**kwargs)
|
||||
|
||||
def main(self, argv):
|
||||
# Parse args once to find version and debug settings
|
||||
parser = self.get_base_parser()
|
||||
@ -583,7 +527,7 @@ class OpenStackComputeShell(object):
|
||||
|
||||
# build available subcommands based on version
|
||||
self.extensions = self._discover_extensions(
|
||||
options.os_compute_api_version)
|
||||
options.os_compute_api_version)
|
||||
self._run_extension_hooks('__pre_parse_args__')
|
||||
|
||||
# NOTE(dtroyer): Hackery to handle --endpoint_type due to argparse
|
||||
@ -595,7 +539,7 @@ class OpenStackComputeShell(object):
|
||||
argv[spot] = '--endpoint-type'
|
||||
|
||||
subcommand_parser = self.get_subcommand_parser(
|
||||
options.os_compute_api_version)
|
||||
options.os_compute_api_version)
|
||||
self.parser = subcommand_parser
|
||||
|
||||
if options.help or not argv:
|
||||
@ -631,9 +575,6 @@ class OpenStackComputeShell(object):
|
||||
cacert = args.os_cacert
|
||||
timeout = args.timeout
|
||||
|
||||
keystone_session = None
|
||||
keystone_auth = None
|
||||
|
||||
# We may have either, both or none of these.
|
||||
# If we have both, we don't need USERNAME, PASSWORD etc.
|
||||
# Fill in the blanks from the SecretsHelper if possible.
|
||||
@ -651,11 +592,6 @@ class OpenStackComputeShell(object):
|
||||
if not endpoint_type:
|
||||
endpoint_type = DEFAULT_NOVA_ENDPOINT_TYPE
|
||||
|
||||
# This allow users to use endpoint_type as (internal, public or admin)
|
||||
# just like other openstack clients (glance, cinder etc)
|
||||
if endpoint_type in ['internal', 'public', 'admin']:
|
||||
endpoint_type += 'URL'
|
||||
|
||||
if not service_type:
|
||||
os_compute_api_version = (options.os_compute_api_version or
|
||||
DEFAULT_OS_COMPUTE_API_VERSION)
|
||||
@ -665,20 +601,13 @@ class OpenStackComputeShell(object):
|
||||
except KeyError:
|
||||
service_type = DEFAULT_NOVA_SERVICE_TYPE_MAP[
|
||||
DEFAULT_OS_COMPUTE_API_VERSION]
|
||||
service_type = cliutils.get_service_type(args.func) or service_type
|
||||
service_type = utils.get_service_type(args.func) or service_type
|
||||
|
||||
# If we have an auth token but no management_url, we must auth anyway.
|
||||
# Expired tokens are handled by client.py:_cs_request
|
||||
must_auth = not (cliutils.isunauthenticated(args.func)
|
||||
or (auth_token and management_url))
|
||||
|
||||
# Do not use Keystone session for cases with no session support. The
|
||||
# presence of auth_plugin means os_auth_system is present and is not
|
||||
# keystone.
|
||||
use_session = True
|
||||
if auth_plugin or bypass_url or os_cache or volume_service_name:
|
||||
use_session = False
|
||||
|
||||
# FIXME(usrleon): Here should be restrict for project id same as
|
||||
# for os_username or os_password but for compatibility it is not.
|
||||
if must_auth:
|
||||
@ -687,86 +616,54 @@ class OpenStackComputeShell(object):
|
||||
|
||||
if not auth_plugin or not auth_plugin.opts:
|
||||
if not os_username and not os_user_id:
|
||||
raise exc.CommandError(
|
||||
_("You must provide a username "
|
||||
"or user id via --os-username, --os-user-id, "
|
||||
"env[OS_USERNAME] or env[OS_USER_ID]"))
|
||||
raise exc.CommandError(_("You must provide a username "
|
||||
"or user id via --os-username, --os-user-id, "
|
||||
"env[OS_USERNAME] or env[OS_USER_ID]"))
|
||||
|
||||
if not any([args.os_tenant_name, args.os_tenant_id,
|
||||
args.os_project_id, args.os_project_name]):
|
||||
raise exc.CommandError(_("You must provide a project name or"
|
||||
" project id via --os-project-name,"
|
||||
" --os-project-id, env[OS_PROJECT_ID]"
|
||||
" or env[OS_PROJECT_NAME]. You may"
|
||||
" use os-project and os-tenant"
|
||||
" interchangeably."))
|
||||
if not os_tenant_name and not os_tenant_id:
|
||||
raise exc.CommandError(_("You must provide a tenant name "
|
||||
"or tenant id via --os-tenant-name, "
|
||||
"--os-tenant-id, env[OS_TENANT_NAME] "
|
||||
"or env[OS_TENANT_ID]"))
|
||||
|
||||
if not os_auth_url:
|
||||
if os_auth_system and os_auth_system != 'keystone':
|
||||
os_auth_url = auth_plugin.get_auth_url()
|
||||
|
||||
if not os_auth_url:
|
||||
raise exc.CommandError(
|
||||
_("You must provide an auth url "
|
||||
"via either --os-auth-url or env[OS_AUTH_URL] "
|
||||
"or specify an auth_system which defines a "
|
||||
"default url with --os-auth-system "
|
||||
"or env[OS_AUTH_SYSTEM]"))
|
||||
|
||||
project_id = args.os_project_id or args.os_tenant_id
|
||||
project_name = args.os_project_name or args.os_tenant_name
|
||||
if use_session:
|
||||
# Not using Nova auth plugin, so use keystone
|
||||
start_time = time.time()
|
||||
keystone_session = ksession.Session.load_from_cli_options(args)
|
||||
keystone_auth = self._get_keystone_auth(
|
||||
keystone_session,
|
||||
args.os_auth_url,
|
||||
username=args.os_username,
|
||||
user_id=args.os_user_id,
|
||||
user_domain_id=args.os_user_domain_id,
|
||||
user_domain_name=args.os_user_domain_name,
|
||||
password=args.os_password,
|
||||
auth_token=args.os_auth_token,
|
||||
project_id=project_id,
|
||||
project_name=project_name,
|
||||
project_domain_id=args.os_project_domain_id,
|
||||
project_domain_name=args.os_project_domain_name)
|
||||
end_time = time.time()
|
||||
self.times.append(
|
||||
('%s %s' % ('auth_url', args.os_auth_url),
|
||||
start_time, end_time))
|
||||
raise exc.CommandError(_("You must provide an auth url "
|
||||
"via either --os-auth-url or env[OS_AUTH_URL] "
|
||||
"or specify an auth_system which defines a "
|
||||
"default url with --os-auth-system "
|
||||
"or env[OS_AUTH_SYSTEM]"))
|
||||
|
||||
if (options.os_compute_api_version and
|
||||
options.os_compute_api_version != '1.0'):
|
||||
if not any([args.os_tenant_id, args.os_tenant_name,
|
||||
args.os_project_id, args.os_project_name]):
|
||||
raise exc.CommandError(_("You must provide a project name or"
|
||||
" project id via --os-project-name,"
|
||||
" --os-project-id, env[OS_PROJECT_ID]"
|
||||
" or env[OS_PROJECT_NAME]. You may"
|
||||
" use os-project and os-tenant"
|
||||
" interchangeably."))
|
||||
if not os_tenant_name and not os_tenant_id:
|
||||
raise exc.CommandError(_("You must provide a tenant name "
|
||||
"or tenant id via --os-tenant-name, "
|
||||
"--os-tenant-id, env[OS_TENANT_NAME] "
|
||||
"or env[OS_TENANT_ID]"))
|
||||
|
||||
if not os_auth_url:
|
||||
raise exc.CommandError(
|
||||
_("You must provide an auth url "
|
||||
"via either --os-auth-url or env[OS_AUTH_URL]"))
|
||||
raise exc.CommandError(_("You must provide an auth url "
|
||||
"via either --os-auth-url or env[OS_AUTH_URL]"))
|
||||
|
||||
self.cs = client.Client(
|
||||
options.os_compute_api_version,
|
||||
os_username, os_password, os_tenant_name,
|
||||
tenant_id=os_tenant_id, user_id=os_user_id,
|
||||
auth_url=os_auth_url, insecure=insecure,
|
||||
region_name=os_region_name, endpoint_type=endpoint_type,
|
||||
extensions=self.extensions, service_type=service_type,
|
||||
service_name=service_name, auth_system=os_auth_system,
|
||||
auth_plugin=auth_plugin, auth_token=auth_token,
|
||||
volume_service_name=volume_service_name,
|
||||
timings=args.timings, bypass_url=bypass_url,
|
||||
os_cache=os_cache, http_log_debug=options.debug,
|
||||
cacert=cacert, timeout=timeout,
|
||||
session=keystone_session, auth=keystone_auth)
|
||||
completion_cache = client.CompletionCache(os_username, os_auth_url)
|
||||
|
||||
self.cs = client.Client(options.os_compute_api_version,
|
||||
os_username, os_password, os_tenant_name,
|
||||
tenant_id=os_tenant_id, user_id=os_user_id,
|
||||
auth_url=os_auth_url, insecure=insecure,
|
||||
region_name=os_region_name, endpoint_type=endpoint_type,
|
||||
extensions=self.extensions, service_type=service_type,
|
||||
service_name=service_name, auth_system=os_auth_system,
|
||||
auth_plugin=auth_plugin, auth_token=auth_token,
|
||||
volume_service_name=volume_service_name,
|
||||
timings=args.timings, bypass_url=bypass_url,
|
||||
os_cache=os_cache, http_log_debug=options.debug,
|
||||
cacert=cacert, timeout=timeout,
|
||||
completion_cache=completion_cache)
|
||||
|
||||
# Now check for the password/token of which pieces of the
|
||||
# identifying keyring key can come from the underlying client
|
||||
@ -799,11 +696,7 @@ class OpenStackComputeShell(object):
|
||||
# This does a couple of bits which are useful even if we've
|
||||
# got the token + service URL already. It exits fast in that case.
|
||||
if not cliutils.isunauthenticated(args.func):
|
||||
if not use_session:
|
||||
# Only call authenticate() if Nova auth plugin is used.
|
||||
# If keystone is used, authentication is handled as part
|
||||
# of session.
|
||||
self.cs.authenticate()
|
||||
self.cs.authenticate()
|
||||
except exc.Unauthorized:
|
||||
raise exc.CommandError(_("Invalid OpenStack Nova credentials."))
|
||||
except exc.AuthorizationFailure:
|
||||
@ -832,13 +725,12 @@ class OpenStackComputeShell(object):
|
||||
volume_service_name=volume_service_name,
|
||||
timings=args.timings, bypass_url=bypass_url,
|
||||
os_cache=os_cache, http_log_debug=options.debug,
|
||||
session=keystone_session, auth=keystone_auth,
|
||||
cacert=cacert, timeout=timeout)
|
||||
|
||||
args.func(self.cs, args)
|
||||
|
||||
if args.timings:
|
||||
self._dump_timings(self.times + self.cs.get_timings())
|
||||
self._dump_timings(self.cs.get_timings())
|
||||
|
||||
def _dump_timings(self, timings):
|
||||
class Tyme(object):
|
||||
@ -873,11 +765,8 @@ class OpenStackComputeShell(object):
|
||||
commands.remove('bash_completion')
|
||||
print(' '.join(commands | options))
|
||||
|
||||
@cliutils.arg(
|
||||
'command',
|
||||
metavar='<subcommand>',
|
||||
nargs='?',
|
||||
help='Display help for <subcommand>')
|
||||
@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.
|
||||
@ -897,7 +786,7 @@ class OpenStackHelpFormatter(argparse.HelpFormatter):
|
||||
def __init__(self, prog, indent_increment=2, max_help_position=32,
|
||||
width=None):
|
||||
super(OpenStackHelpFormatter, self).__init__(prog, indent_increment,
|
||||
max_help_position, width)
|
||||
max_help_position, width)
|
||||
|
||||
def start_section(self, heading):
|
||||
# Title-case the headings
|
||||
@ -917,9 +806,9 @@ def main():
|
||||
print("ERROR (%(name)s): %(msg)s" % details,
|
||||
file=sys.stderr)
|
||||
sys.exit(1)
|
||||
except KeyboardInterrupt:
|
||||
print("... terminating nova client", file=sys.stderr)
|
||||
sys.exit(130)
|
||||
except KeyboardInterrupt as e:
|
||||
print("Shutting down novaclient", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@ -10,9 +10,6 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import httpretty
|
||||
|
||||
from novaclient.openstack.common import jsonutils
|
||||
from novaclient.tests.fixture_data import base
|
||||
|
||||
|
||||
@ -35,9 +32,9 @@ class Fixture(base.Fixture):
|
||||
}
|
||||
}
|
||||
|
||||
httpretty.register_uri(httpretty.POST, self.url(),
|
||||
body=jsonutils.dumps(post_os_agents),
|
||||
content_type='application/json')
|
||||
self.requests.register_uri('POST', self.url(),
|
||||
json=post_os_agents,
|
||||
headers=self.json_headers)
|
||||
|
||||
put_os_agents_1 = {
|
||||
"agent": {
|
||||
@ -48,10 +45,10 @@ class Fixture(base.Fixture):
|
||||
}
|
||||
}
|
||||
|
||||
httpretty.register_uri(httpretty.PUT, self.url(1),
|
||||
body=jsonutils.dumps(put_os_agents_1),
|
||||
content_type='application/json')
|
||||
self.requests.register_uri('PUT', self.url(1),
|
||||
json=put_os_agents_1,
|
||||
headers=self.json_headers)
|
||||
|
||||
httpretty.register_uri(httpretty.DELETE, self.url(1),
|
||||
content_type='application/json',
|
||||
status=202)
|
||||
self.requests.register_uri('DELETE', self.url(1),
|
||||
headers=self.json_headers,
|
||||
status_code=202)
|
||||
|
||||
@ -10,9 +10,6 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import httpretty
|
||||
|
||||
from novaclient.openstack.common import jsonutils
|
||||
from novaclient.tests.fixture_data import base
|
||||
|
||||
|
||||
@ -32,21 +29,24 @@ class Fixture(base.Fixture):
|
||||
'availability_zone': 'nova1'},
|
||||
]}
|
||||
|
||||
httpretty.register_uri(httpretty.GET, self.url(),
|
||||
body=jsonutils.dumps(get_os_aggregates),
|
||||
content_type='application/json')
|
||||
self.requests.register_uri('GET', self.url(),
|
||||
json=get_os_aggregates,
|
||||
headers=self.json_headers)
|
||||
|
||||
r = jsonutils.dumps({'aggregate': get_os_aggregates['aggregates'][0]})
|
||||
get_aggregates_1 = {'aggregate': get_os_aggregates['aggregates'][0]}
|
||||
|
||||
httpretty.register_uri(httpretty.POST, self.url(), body=r,
|
||||
content_type='application/json')
|
||||
self.requests.register_uri('POST', self.url(),
|
||||
json=get_aggregates_1,
|
||||
headers=self.json_headers)
|
||||
|
||||
for agg_id in (1, 2):
|
||||
for method in (httpretty.GET, httpretty.PUT):
|
||||
httpretty.register_uri(method, self.url(agg_id), body=r,
|
||||
content_type='application/json')
|
||||
for method in ('GET', 'PUT'):
|
||||
self.requests.register_uri(method, self.url(agg_id),
|
||||
json=get_aggregates_1,
|
||||
headers=self.json_headers)
|
||||
|
||||
httpretty.register_uri(httpretty.POST, self.url(agg_id, 'action'),
|
||||
body=r, content_type='application/json')
|
||||
self.requests.register_uri('POST', self.url(agg_id, 'action'),
|
||||
json=get_aggregates_1,
|
||||
headers=self.json_headers)
|
||||
|
||||
httpretty.register_uri(httpretty.DELETE, self.url(1), status=202)
|
||||
self.requests.register_uri('DELETE', self.url(1), status_code=202)
|
||||
|
||||
@ -10,9 +10,6 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import httpretty
|
||||
|
||||
from novaclient.openstack.common import jsonutils
|
||||
from novaclient.tests.fixture_data import base
|
||||
|
||||
|
||||
@ -41,9 +38,10 @@ class V1(base.Fixture):
|
||||
}
|
||||
]
|
||||
}
|
||||
httpretty.register_uri(httpretty.GET, self.url(),
|
||||
body=jsonutils.dumps(get_os_availability_zone),
|
||||
content_type='application/json')
|
||||
|
||||
self.requests.register_uri('GET', self.url(),
|
||||
json=get_os_availability_zone,
|
||||
headers=self.json_headers)
|
||||
|
||||
get_os_zone_detail = {
|
||||
self.zone_info_key: [
|
||||
@ -88,9 +86,9 @@ class V1(base.Fixture):
|
||||
]
|
||||
}
|
||||
|
||||
httpretty.register_uri(httpretty.GET, self.url('detail'),
|
||||
body=jsonutils.dumps(get_os_zone_detail),
|
||||
content_type='application/json')
|
||||
self.requests.register_uri('GET', self.url('detail'),
|
||||
json=get_os_zone_detail,
|
||||
headers=self.json_headers)
|
||||
|
||||
|
||||
class V3(V1):
|
||||
|
||||
@ -19,9 +19,11 @@ COMPUTE_URL = 'http://compute.host'
|
||||
class Fixture(fixtures.Fixture):
|
||||
|
||||
base_url = None
|
||||
json_headers = {'Content-Type': 'application/json'}
|
||||
|
||||
def __init__(self, compute_url=COMPUTE_URL):
|
||||
def __init__(self, requests, compute_url=COMPUTE_URL):
|
||||
super(Fixture, self).__init__()
|
||||
self.requests = requests
|
||||
self.compute_url = compute_url
|
||||
|
||||
def url(self, *args, **kwargs):
|
||||
|
||||
@ -10,9 +10,6 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import httpretty
|
||||
|
||||
from novaclient.openstack.common import jsonutils
|
||||
from novaclient.tests.fixture_data import base
|
||||
|
||||
|
||||
@ -43,9 +40,9 @@ class Fixture(base.Fixture):
|
||||
'data': 'foo'
|
||||
}
|
||||
}
|
||||
httpretty.register_uri(httpretty.GET, self.url('root'),
|
||||
body=jsonutils.dumps(get_os_certificate),
|
||||
content_type='application/json')
|
||||
self.requests.register_uri('GET', self.url('root'),
|
||||
json=get_os_certificate,
|
||||
headers=self.json_headers)
|
||||
|
||||
post_os_certificates = {
|
||||
'certificate': {
|
||||
@ -53,6 +50,6 @@ class Fixture(base.Fixture):
|
||||
'data': 'bar'
|
||||
}
|
||||
}
|
||||
httpretty.register_uri(httpretty.POST, self.url(),
|
||||
body=jsonutils.dumps(post_os_certificates),
|
||||
content_type='application/json')
|
||||
self.requests.register_uri('POST', self.url(),
|
||||
json=post_os_certificates,
|
||||
headers=self.json_headers)
|
||||
|
||||
@ -11,11 +11,10 @@
|
||||
# under the License.
|
||||
|
||||
import fixtures
|
||||
import httpretty
|
||||
from keystoneclient.auth.identity import v2
|
||||
from keystoneclient import fixture
|
||||
from keystoneclient import session
|
||||
|
||||
from novaclient.openstack.common import jsonutils
|
||||
from novaclient.v1_1 import client as v1_1client
|
||||
from novaclient.v3 import client as v3client
|
||||
|
||||
@ -25,74 +24,31 @@ COMPUTE_URL = 'http://compute.host'
|
||||
|
||||
class V1(fixtures.Fixture):
|
||||
|
||||
def __init__(self, compute_url=COMPUTE_URL, identity_url=IDENTITY_URL):
|
||||
def __init__(self, requests,
|
||||
compute_url=COMPUTE_URL, identity_url=IDENTITY_URL):
|
||||
super(V1, self).__init__()
|
||||
self.identity_url = identity_url
|
||||
self.compute_url = compute_url
|
||||
self.client = None
|
||||
self.requests = requests
|
||||
|
||||
self.token = {
|
||||
'access': {
|
||||
"token": {
|
||||
"id": "ab48a9efdfedb23ty3494",
|
||||
"expires": "2010-11-01T03:32:15-05:00",
|
||||
"tenant": {
|
||||
"id": "345",
|
||||
"name": "My Project"
|
||||
}
|
||||
},
|
||||
"user": {
|
||||
"id": "123",
|
||||
"name": "jqsmith",
|
||||
"roles": [
|
||||
{
|
||||
"id": "234",
|
||||
"name": "compute:admin",
|
||||
},
|
||||
{
|
||||
"id": "235",
|
||||
"name": "object-store:admin",
|
||||
"tenantId": "1",
|
||||
}
|
||||
],
|
||||
"roles_links": [],
|
||||
},
|
||||
"serviceCatalog": [
|
||||
{
|
||||
"name": "Cloud Servers",
|
||||
"type": "compute",
|
||||
"endpoints": [
|
||||
{
|
||||
"publicURL": self.compute_url,
|
||||
"internalURL": "https://compute1.host/v1/1",
|
||||
},
|
||||
],
|
||||
"endpoints_links": [],
|
||||
},
|
||||
{
|
||||
"name": "Cloud Servers",
|
||||
"type": "computev3",
|
||||
"endpoints": [
|
||||
{
|
||||
"publicURL": self.compute_url,
|
||||
"internalURL": "https://compute1.host/v1/1",
|
||||
},
|
||||
],
|
||||
"endpoints_links": [],
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
self.token = fixture.V2Token()
|
||||
self.token.set_scope()
|
||||
|
||||
s = self.token.add_service('compute')
|
||||
s.add_endpoint(self.compute_url)
|
||||
|
||||
s = self.token.add_service('computev3')
|
||||
s.add_endpoint(self.compute_url)
|
||||
|
||||
def setUp(self):
|
||||
super(V1, self).setUp()
|
||||
httpretty.enable()
|
||||
self.addCleanup(httpretty.disable)
|
||||
|
||||
auth_url = '%s/tokens' % self.identity_url
|
||||
httpretty.register_uri(httpretty.POST, auth_url,
|
||||
body=jsonutils.dumps(self.token),
|
||||
content_type='application/json')
|
||||
headers = {'X-Content-Type': 'application/json'}
|
||||
self.requests.register_uri('POST', auth_url,
|
||||
json=self.token,
|
||||
headers=headers)
|
||||
self.client = self.new_client()
|
||||
|
||||
def new_client(self):
|
||||
|
||||
@ -10,9 +10,6 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import httpretty
|
||||
|
||||
from novaclient.openstack.common import jsonutils
|
||||
from novaclient.tests.fixture_data import base
|
||||
|
||||
|
||||
@ -24,17 +21,17 @@ class Fixture(base.Fixture):
|
||||
super(Fixture, self).setUp()
|
||||
|
||||
get_os_cloudpipe = {'cloudpipes': [{'project_id': 1}]}
|
||||
httpretty.register_uri(httpretty.GET, self.url(),
|
||||
body=jsonutils.dumps(get_os_cloudpipe),
|
||||
content_type='application/json')
|
||||
self.requests.register_uri('GET', self.url(),
|
||||
json=get_os_cloudpipe,
|
||||
headers=self.json_headers)
|
||||
|
||||
instance_id = '9d5824aa-20e6-4b9f-b967-76a699fc51fd'
|
||||
post_os_cloudpipe = {'instance_id': instance_id}
|
||||
httpretty.register_uri(httpretty.POST, self.url(),
|
||||
body=jsonutils.dumps(post_os_cloudpipe),
|
||||
content_type='application/json',
|
||||
status=202)
|
||||
self.requests.register_uri('POST', self.url(),
|
||||
json=post_os_cloudpipe,
|
||||
headers=self.json_headers,
|
||||
status_code=202)
|
||||
|
||||
httpretty.register_uri(httpretty.PUT, self.url('configure-project'),
|
||||
content_type='application/json',
|
||||
status=202)
|
||||
self.requests.register_uri('PUT', self.url('configure-project'),
|
||||
headers=self.json_headers,
|
||||
status_code=202)
|
||||
|
||||
@ -10,9 +10,6 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import httpretty
|
||||
|
||||
from novaclient.openstack.common import jsonutils
|
||||
from novaclient.tests.fixture_data import base
|
||||
|
||||
|
||||
@ -31,11 +28,12 @@ class Fixture(base.Fixture):
|
||||
'host': 'bar'
|
||||
}
|
||||
}
|
||||
httpretty.register_uri(httpretty.GET, self.url('192.168.1.1'),
|
||||
body=jsonutils.dumps(get_os_fixed_ips),
|
||||
content_type='application/json')
|
||||
|
||||
httpretty.register_uri(httpretty.POST,
|
||||
self.url('192.168.1.1', 'action'),
|
||||
content_type='application/json',
|
||||
status=202)
|
||||
self.requests.register_uri('GET', self.url('192.168.1.1'),
|
||||
json=get_os_fixed_ips,
|
||||
headers=self.json_headers)
|
||||
|
||||
self.requests.register_uri('POST',
|
||||
self.url('192.168.1.1', 'action'),
|
||||
headers=self.json_headers,
|
||||
status_code=202)
|
||||
|
||||
@ -10,8 +10,6 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import httpretty
|
||||
|
||||
from novaclient.openstack.common import jsonutils
|
||||
from novaclient.tests import fakes
|
||||
from novaclient.tests.fixture_data import base
|
||||
@ -28,29 +26,28 @@ class FloatingFixture(base.Fixture):
|
||||
{'id': 2, 'fixed_ip': '10.0.0.2', 'ip': '11.0.0.2'}]
|
||||
|
||||
get_os_floating_ips = {'floating_ips': floating_ips}
|
||||
httpretty.register_uri(httpretty.GET, self.url(),
|
||||
body=jsonutils.dumps(get_os_floating_ips),
|
||||
content_type='application/json')
|
||||
self.requests.register_uri('GET', self.url(),
|
||||
json=get_os_floating_ips,
|
||||
headers=self.json_headers)
|
||||
|
||||
for ip in floating_ips:
|
||||
get_os_floating_ip = {'floating_ip': ip}
|
||||
httpretty.register_uri(httpretty.GET, self.url(ip['id']),
|
||||
body=jsonutils.dumps(get_os_floating_ip),
|
||||
content_type='application/json')
|
||||
self.requests.register_uri('GET', self.url(ip['id']),
|
||||
json=get_os_floating_ip,
|
||||
headers=self.json_headers)
|
||||
|
||||
httpretty.register_uri(httpretty.DELETE, self.url(ip['id']),
|
||||
content_type='application/json',
|
||||
status=204)
|
||||
self.requests.register_uri('DELETE', self.url(ip['id']),
|
||||
headers=self.json_headers,
|
||||
status_code=204)
|
||||
|
||||
def post_os_floating_ips(request, url, headers):
|
||||
body = jsonutils.loads(request.body.decode('utf-8'))
|
||||
def post_os_floating_ips(request, context):
|
||||
body = jsonutils.loads(request.body)
|
||||
ip = floating_ips[0].copy()
|
||||
ip['pool'] = body.get('pool')
|
||||
ip = jsonutils.dumps({'floating_ip': ip})
|
||||
return 200, headers, ip
|
||||
httpretty.register_uri(httpretty.POST, self.url(),
|
||||
body=post_os_floating_ips,
|
||||
content_type='application/json')
|
||||
return {'floating_ip': ip}
|
||||
self.requests.register_uri('POST', self.url(),
|
||||
json=post_os_floating_ips,
|
||||
headers=self.json_headers)
|
||||
|
||||
|
||||
class DNSFixture(base.Fixture):
|
||||
@ -66,10 +63,10 @@ class DNSFixture(base.Fixture):
|
||||
{'domain': 'example.com'}
|
||||
]
|
||||
}
|
||||
httpretty.register_uri(httpretty.GET, self.url(),
|
||||
body=jsonutils.dumps(get_os_floating_ip_dns),
|
||||
content_type='application/json',
|
||||
status=205)
|
||||
self.requests.register_uri('GET', self.url(),
|
||||
json=get_os_floating_ip_dns,
|
||||
headers=self.json_headers,
|
||||
status_code=205)
|
||||
|
||||
get_dns_testdomain_entries_testname = {
|
||||
'dns_entry': {
|
||||
@ -80,31 +77,30 @@ class DNSFixture(base.Fixture):
|
||||
}
|
||||
}
|
||||
url = self.url('testdomain', 'entries', 'testname')
|
||||
body = jsonutils.dumps(get_dns_testdomain_entries_testname)
|
||||
httpretty.register_uri(httpretty.GET, url,
|
||||
body=body,
|
||||
content_type='application/json',
|
||||
status=205)
|
||||
self.requests.register_uri('GET', url,
|
||||
json=get_dns_testdomain_entries_testname,
|
||||
headers=self.json_headers,
|
||||
status_code=205)
|
||||
|
||||
httpretty.register_uri(httpretty.DELETE, self.url('testdomain'),
|
||||
status=200)
|
||||
self.requests.register_uri('DELETE', self.url('testdomain'))
|
||||
|
||||
url = self.url('testdomain', 'entries', 'testname')
|
||||
httpretty.register_uri(httpretty.DELETE, url, status=200)
|
||||
self.requests.register_uri('DELETE', url)
|
||||
|
||||
def put_dns_testdomain_entries_testname(request, url, headers):
|
||||
body = jsonutils.loads(request.body.decode('utf-8'))
|
||||
def put_dns_testdomain_entries_testname(request, context):
|
||||
body = jsonutils.loads(request.body)
|
||||
fakes.assert_has_keys(body['dns_entry'],
|
||||
required=['ip', 'dns_type'])
|
||||
return 205, headers, request.body
|
||||
httpretty.register_uri(httpretty.PUT, url,
|
||||
body=put_dns_testdomain_entries_testname,
|
||||
content_type='application/json')
|
||||
context.status_code = 205
|
||||
return request.body
|
||||
self.requests.register_uri('PUT', url,
|
||||
text=put_dns_testdomain_entries_testname,
|
||||
headers=self.json_headers)
|
||||
|
||||
url = self.url('testdomain', 'entries')
|
||||
httpretty.register_uri(httpretty.GET, url, status=404)
|
||||
self.requests.register_uri('GET', url, status_code=404)
|
||||
|
||||
get_os_floating_ip_dns_testdomain_entries = {
|
||||
get_os_floating_ip_dns_testdomain = {
|
||||
'dns_entries': [
|
||||
{
|
||||
'dns_entry': {
|
||||
@ -124,14 +120,13 @@ class DNSFixture(base.Fixture):
|
||||
},
|
||||
]
|
||||
}
|
||||
body = jsonutils.dumps(get_os_floating_ip_dns_testdomain_entries)
|
||||
httpretty.register_uri(httpretty.GET, url + '?ip=1.2.3.4',
|
||||
body=body,
|
||||
status=205,
|
||||
content_type='application/json')
|
||||
self.requests.register_uri('GET', url + '?ip=1.2.3.4',
|
||||
json=get_os_floating_ip_dns_testdomain,
|
||||
status_code=205,
|
||||
headers=self.json_headers)
|
||||
|
||||
def put_os_floating_ip_dns_testdomain(request, url, headers):
|
||||
body = jsonutils.loads(request.body.decode('utf-8'))
|
||||
def put_os_floating_ip_dns_testdomain(request, context):
|
||||
body = jsonutils.loads(request.body)
|
||||
if body['domain_entry']['scope'] == 'private':
|
||||
fakes.assert_has_keys(body['domain_entry'],
|
||||
required=['availability_zone', 'scope'])
|
||||
@ -142,11 +137,12 @@ class DNSFixture(base.Fixture):
|
||||
fakes.assert_has_keys(body['domain_entry'],
|
||||
required=['project', 'scope'])
|
||||
|
||||
headers['Content-Type'] = 'application/json'
|
||||
return (205, headers, request.body)
|
||||
return request.body
|
||||
|
||||
httpretty.register_uri(httpretty.PUT, self.url('testdomain'),
|
||||
body=put_os_floating_ip_dns_testdomain)
|
||||
self.requests.register_uri('PUT', self.url('testdomain'),
|
||||
text=put_os_floating_ip_dns_testdomain,
|
||||
status_code=205,
|
||||
headers=self.json_headers)
|
||||
|
||||
|
||||
class BulkFixture(base.Fixture):
|
||||
@ -162,40 +158,38 @@ class BulkFixture(base.Fixture):
|
||||
{'id': 2, 'fixed_ip': '10.0.0.2', 'ip': '11.0.0.2'},
|
||||
]
|
||||
}
|
||||
httpretty.register_uri(httpretty.GET, self.url(),
|
||||
body=jsonutils.dumps(get_os_floating_ips_bulk),
|
||||
content_type='application/json')
|
||||
httpretty.register_uri(httpretty.GET, self.url('testHost'),
|
||||
body=jsonutils.dumps(get_os_floating_ips_bulk),
|
||||
content_type='application/json')
|
||||
self.requests.register_uri('GET', self.url(),
|
||||
json=get_os_floating_ips_bulk,
|
||||
headers=self.json_headers)
|
||||
self.requests.register_uri('GET', self.url('testHost'),
|
||||
json=get_os_floating_ips_bulk,
|
||||
headers=self.json_headers)
|
||||
|
||||
def put_os_floating_ips_bulk_delete(request, url, headers):
|
||||
body = jsonutils.loads(request.body.decode('utf-8'))
|
||||
def put_os_floating_ips_bulk_delete(request, context):
|
||||
body = jsonutils.loads(request.body)
|
||||
ip_range = body.get('ip_range')
|
||||
data = {'floating_ips_bulk_delete': ip_range}
|
||||
return 200, headers, jsonutils.dumps(data)
|
||||
return {'floating_ips_bulk_delete': ip_range}
|
||||
|
||||
httpretty.register_uri(httpretty.PUT, self.url('delete'),
|
||||
body=put_os_floating_ips_bulk_delete,
|
||||
content_type='application/json')
|
||||
self.requests.register_uri('PUT', self.url('delete'),
|
||||
json=put_os_floating_ips_bulk_delete,
|
||||
headers=self.json_headers)
|
||||
|
||||
def post_os_floating_ips_bulk(request, url, headers):
|
||||
body = jsonutils.loads(request.body.decode('utf-8'))
|
||||
def post_os_floating_ips_bulk(request, context):
|
||||
body = jsonutils.loads(request.body)
|
||||
params = body.get('floating_ips_bulk_create')
|
||||
pool = params.get('pool', 'defaultPool')
|
||||
interface = params.get('interface', 'defaultInterface')
|
||||
data = {
|
||||
return {
|
||||
'floating_ips_bulk_create': {
|
||||
'ip_range': '192.168.1.0/30',
|
||||
'pool': pool,
|
||||
'interface': interface
|
||||
}
|
||||
}
|
||||
return 200, headers, jsonutils.dumps(data)
|
||||
|
||||
httpretty.register_uri(httpretty.POST, self.url(),
|
||||
body=post_os_floating_ips_bulk,
|
||||
content_type='application/json')
|
||||
self.requests.register_uri('POST', self.url(),
|
||||
json=post_os_floating_ips_bulk,
|
||||
headers=self.json_headers)
|
||||
|
||||
|
||||
class PoolsFixture(base.Fixture):
|
||||
@ -211,6 +205,6 @@ class PoolsFixture(base.Fixture):
|
||||
{'name': 'bar'}
|
||||
]
|
||||
}
|
||||
httpretty.register_uri(httpretty.GET, self.url(),
|
||||
body=jsonutils.dumps(get_os_floating_ip_pools),
|
||||
content_type='application/json')
|
||||
self.requests.register_uri('GET', self.url(),
|
||||
json=get_os_floating_ip_pools,
|
||||
headers=self.json_headers)
|
||||
|
||||
@ -10,9 +10,6 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import httpretty
|
||||
|
||||
from novaclient.openstack.common import jsonutils
|
||||
from novaclient.tests.fixture_data import base
|
||||
|
||||
|
||||
@ -30,9 +27,9 @@ class Fixture(base.Fixture):
|
||||
"alive": True,
|
||||
}
|
||||
}
|
||||
httpretty.register_uri(httpretty.GET, self.url(1),
|
||||
body=jsonutils.dumps(get_os_fping_1),
|
||||
content_type='application/json')
|
||||
self.requests.register_uri('GET', self.url(1),
|
||||
json=get_os_fping_1,
|
||||
headers=self.json_headers)
|
||||
|
||||
get_os_fping = {
|
||||
'servers': [
|
||||
@ -44,6 +41,6 @@ class Fixture(base.Fixture):
|
||||
},
|
||||
]
|
||||
}
|
||||
httpretty.register_uri(httpretty.GET, self.url(),
|
||||
body=jsonutils.dumps(get_os_fping),
|
||||
content_type='application/json')
|
||||
self.requests.register_uri('GET', self.url(),
|
||||
json=get_os_fping,
|
||||
headers=self.json_headers)
|
||||
|
||||
@ -10,7 +10,6 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import httpretty
|
||||
from six.moves.urllib import parse
|
||||
|
||||
from novaclient.openstack.common import jsonutils
|
||||
@ -36,13 +35,17 @@ class BaseFixture(base.Fixture):
|
||||
'cpu': 1, 'memory_mb': 2048, 'disk_gb': 30}}
|
||||
]
|
||||
}
|
||||
httpretty.register_uri(httpretty.GET, self.url('host'),
|
||||
body=jsonutils.dumps(get_os_hosts_host),
|
||||
content_type='application/json')
|
||||
|
||||
def get_os_hosts(request, url, headers):
|
||||
host, query = parse.splitquery(url)
|
||||
headers = {'Content-Type': 'application/json'}
|
||||
|
||||
self.requests.register_uri('GET', self.url('host'),
|
||||
json=get_os_hosts_host,
|
||||
headers=headers)
|
||||
|
||||
def get_os_hosts(request, context):
|
||||
host, query = parse.splitquery(request.url)
|
||||
zone = 'nova1'
|
||||
service = None
|
||||
|
||||
if query:
|
||||
qs = parse.parse_qs(query)
|
||||
@ -51,70 +54,71 @@ class BaseFixture(base.Fixture):
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
data = {
|
||||
try:
|
||||
service = qs['service'][0]
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return {
|
||||
'hosts': [
|
||||
{
|
||||
'host': 'host1',
|
||||
'service': 'nova-compute',
|
||||
'service': service or 'nova-compute',
|
||||
'zone': zone
|
||||
},
|
||||
{
|
||||
'host': 'host1',
|
||||
'service': 'nova-cert',
|
||||
'service': service or 'nova-cert',
|
||||
'zone': zone
|
||||
}
|
||||
]
|
||||
}
|
||||
return 200, headers, jsonutils.dumps(data)
|
||||
|
||||
httpretty.register_uri(httpretty.GET, self.url(),
|
||||
body=get_os_hosts,
|
||||
content_type='application/json')
|
||||
self.requests.register_uri('GET', self.url(),
|
||||
json=get_os_hosts,
|
||||
headers=headers)
|
||||
|
||||
get_os_hosts_sample_host = {
|
||||
'host': [
|
||||
{'resource': {'host': 'sample_host'}}
|
||||
],
|
||||
}
|
||||
httpretty.register_uri(httpretty.GET, self.url('sample_host'),
|
||||
body=jsonutils.dumps(get_os_hosts_sample_host),
|
||||
content_type='application/json')
|
||||
self.requests.register_uri('GET', self.url('sample_host'),
|
||||
json=get_os_hosts_sample_host,
|
||||
headers=headers)
|
||||
|
||||
httpretty.register_uri(httpretty.PUT, self.url('sample_host', 1),
|
||||
body=jsonutils.dumps(self.put_host_1()),
|
||||
content_type='application/json')
|
||||
self.requests.register_uri('PUT', self.url('sample_host', 1),
|
||||
json=self.put_host_1(),
|
||||
headers=headers)
|
||||
|
||||
httpretty.register_uri(httpretty.PUT, self.url('sample_host', 2),
|
||||
body=jsonutils.dumps(self.put_host_2()),
|
||||
content_type='application/json')
|
||||
self.requests.register_uri('PUT', self.url('sample_host', 2),
|
||||
json=self.put_host_2(),
|
||||
headers=headers)
|
||||
|
||||
httpretty.register_uri(httpretty.PUT, self.url('sample_host', 3),
|
||||
body=jsonutils.dumps(self.put_host_3()),
|
||||
content_type='application/json')
|
||||
self.requests.register_uri('PUT', self.url('sample_host', 3),
|
||||
json=self.put_host_3(),
|
||||
headers=headers)
|
||||
|
||||
url = self.url('sample_host', 'reboot')
|
||||
httpretty.register_uri(httpretty.GET, url,
|
||||
body=jsonutils.dumps(self.get_host_reboot()),
|
||||
content_type='application/json')
|
||||
self.requests.register_uri('GET', self.url('sample_host', 'reboot'),
|
||||
json=self.get_host_reboot(),
|
||||
headers=headers)
|
||||
|
||||
url = self.url('sample_host', 'startup')
|
||||
httpretty.register_uri(httpretty.GET, url,
|
||||
body=jsonutils.dumps(self.get_host_startup()),
|
||||
content_type='application/json')
|
||||
self.requests.register_uri('GET', self.url('sample_host', 'startup'),
|
||||
json=self.get_host_startup(),
|
||||
headers=headers)
|
||||
|
||||
url = self.url('sample_host', 'shutdown')
|
||||
httpretty.register_uri(httpretty.GET, url,
|
||||
body=jsonutils.dumps(self.get_host_shutdown()),
|
||||
content_type='application/json')
|
||||
self.requests.register_uri('GET', self.url('sample_host', 'shutdown'),
|
||||
json=self.get_host_shutdown(),
|
||||
headers=headers)
|
||||
|
||||
def put_os_hosts_sample_host(request, url, headers):
|
||||
def put_os_hosts_sample_host(request, context):
|
||||
result = {'host': 'dummy'}
|
||||
result.update(jsonutils.loads(request.body.decode('utf-8')))
|
||||
return 200, headers, jsonutils.dumps(result)
|
||||
result.update(jsonutils.loads(request.body))
|
||||
return result
|
||||
|
||||
httpretty.register_uri(httpretty.PUT, self.url('sample_host'),
|
||||
body=put_os_hosts_sample_host,
|
||||
content_type='application/json')
|
||||
self.requests.register_uri('PUT', self.url('sample_host'),
|
||||
json=put_os_hosts_sample_host,
|
||||
headers=headers)
|
||||
|
||||
|
||||
class V1(BaseFixture):
|
||||
|
||||
@ -10,9 +10,6 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import httpretty
|
||||
|
||||
from novaclient.openstack.common import jsonutils
|
||||
from novaclient.tests.fixture_data import base
|
||||
|
||||
|
||||
@ -30,15 +27,20 @@ class V1(base.Fixture):
|
||||
]
|
||||
}
|
||||
|
||||
httpretty.register_uri(httpretty.GET, self.url(),
|
||||
body=jsonutils.dumps(get_os_hypervisors),
|
||||
content_type='application/json')
|
||||
self.headers = {'Content-Type': 'application/json'}
|
||||
|
||||
self.requests.register_uri('GET', self.url(),
|
||||
json=get_os_hypervisors,
|
||||
headers=self.headers)
|
||||
|
||||
get_os_hypervisors_detail = {
|
||||
'hypervisors': [
|
||||
{
|
||||
'id': 1234,
|
||||
'service': {'id': 1, 'host': 'compute1'},
|
||||
'service': {
|
||||
'id': 1,
|
||||
'host': 'compute1',
|
||||
},
|
||||
'vcpus': 4,
|
||||
'memory_mb': 10 * 1024,
|
||||
'local_gb': 250,
|
||||
@ -57,29 +59,32 @@ class V1(base.Fixture):
|
||||
},
|
||||
{
|
||||
'id': 2,
|
||||
'service': {'id': 2, 'host': 'compute2'},
|
||||
'vcpus': 4,
|
||||
'memory_mb': 10 * 1024,
|
||||
'local_gb': 250,
|
||||
'vcpus_used': 2,
|
||||
'memory_mb_used': 5 * 1024,
|
||||
'local_gb_used': 125,
|
||||
'hypervisor_type': 'xen',
|
||||
'hypervisor_version': 3,
|
||||
'hypervisor_hostname': 'hyper2',
|
||||
'free_ram_mb': 5 * 1024,
|
||||
'free_disk_gb': 125,
|
||||
'current_workload': 2,
|
||||
'running_vms': 2,
|
||||
'cpu_info': 'cpu_info',
|
||||
'disk_available_least': 100
|
||||
'service': {
|
||||
'id': 2,
|
||||
'host': 'compute2',
|
||||
},
|
||||
'vcpus': 4,
|
||||
'memory_mb': 10 * 1024,
|
||||
'local_gb': 250,
|
||||
'vcpus_used': 2,
|
||||
'memory_mb_used': 5 * 1024,
|
||||
'local_gb_used': 125,
|
||||
'hypervisor_type': 'xen',
|
||||
'hypervisor_version': 3,
|
||||
'hypervisor_hostname': 'hyper2',
|
||||
'free_ram_mb': 5 * 1024,
|
||||
'free_disk_gb': 125,
|
||||
'current_workload': 2,
|
||||
'running_vms': 2,
|
||||
'cpu_info': 'cpu_info',
|
||||
'disk_available_least': 100
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
httpretty.register_uri(httpretty.GET, self.url('detail'),
|
||||
body=jsonutils.dumps(get_os_hypervisors_detail),
|
||||
content_type='application/json')
|
||||
self.requests.register_uri('GET', self.url('detail'),
|
||||
json=get_os_hypervisors_detail,
|
||||
headers=self.headers)
|
||||
|
||||
get_os_hypervisors_stats = {
|
||||
'hypervisor_statistics': {
|
||||
@ -98,9 +103,9 @@ class V1(base.Fixture):
|
||||
}
|
||||
}
|
||||
|
||||
httpretty.register_uri(httpretty.GET, self.url('statistics'),
|
||||
body=jsonutils.dumps(get_os_hypervisors_stats),
|
||||
content_type='application/json')
|
||||
self.requests.register_uri('GET', self.url('statistics'),
|
||||
json=get_os_hypervisors_stats,
|
||||
headers=self.headers)
|
||||
|
||||
get_os_hypervisors_search = {
|
||||
'hypervisors': [
|
||||
@ -109,9 +114,9 @@ class V1(base.Fixture):
|
||||
]
|
||||
}
|
||||
|
||||
httpretty.register_uri(httpretty.GET, self.url('hyper', 'search'),
|
||||
body=jsonutils.dumps(get_os_hypervisors_search),
|
||||
content_type='application/json')
|
||||
self.requests.register_uri('GET', self.url('hyper', 'search'),
|
||||
json=get_os_hypervisors_search,
|
||||
headers=self.headers)
|
||||
|
||||
get_hyper_server = {
|
||||
'hypervisors': [
|
||||
@ -134,9 +139,9 @@ class V1(base.Fixture):
|
||||
]
|
||||
}
|
||||
|
||||
httpretty.register_uri(httpretty.GET, self.url('hyper', 'servers'),
|
||||
body=jsonutils.dumps(get_hyper_server),
|
||||
content_type='application/json')
|
||||
self.requests.register_uri('GET', self.url('hyper', 'servers'),
|
||||
json=get_hyper_server,
|
||||
headers=self.headers)
|
||||
|
||||
get_os_hypervisors_1234 = {
|
||||
'hypervisor': {
|
||||
@ -160,9 +165,9 @@ class V1(base.Fixture):
|
||||
}
|
||||
}
|
||||
|
||||
httpretty.register_uri(httpretty.GET, self.url(1234),
|
||||
body=jsonutils.dumps(get_os_hypervisors_1234),
|
||||
content_type='application/json')
|
||||
self.requests.register_uri('GET', self.url(1234),
|
||||
json=get_os_hypervisors_1234,
|
||||
headers=self.headers)
|
||||
|
||||
get_os_hypervisors_uptime = {
|
||||
'hypervisor': {
|
||||
@ -172,9 +177,9 @@ class V1(base.Fixture):
|
||||
}
|
||||
}
|
||||
|
||||
httpretty.register_uri(httpretty.GET, self.url(1234, 'uptime'),
|
||||
body=jsonutils.dumps(get_os_hypervisors_uptime),
|
||||
content_type='application/json')
|
||||
self.requests.register_uri('GET', self.url(1234, 'uptime'),
|
||||
json=get_os_hypervisors_uptime,
|
||||
headers=self.headers)
|
||||
|
||||
|
||||
class V3(V1):
|
||||
@ -189,10 +194,10 @@ class V3(V1):
|
||||
]
|
||||
}
|
||||
|
||||
httpretty.register_uri(httpretty.GET,
|
||||
self.url('search', query='hyper'),
|
||||
body=jsonutils.dumps(get_os_hypervisors_search),
|
||||
content_type='application/json')
|
||||
self.requests.register_uri('GET',
|
||||
self.url('search', query='hyper'),
|
||||
json=get_os_hypervisors_search,
|
||||
headers=self.headers)
|
||||
|
||||
get_1234_servers = {
|
||||
'hypervisor': {
|
||||
@ -205,6 +210,6 @@ class V3(V1):
|
||||
},
|
||||
}
|
||||
|
||||
httpretty.register_uri(httpretty.GET, self.url(1234, 'servers'),
|
||||
body=jsonutils.dumps(get_1234_servers),
|
||||
content_type='application/json')
|
||||
self.requests.register_uri('GET', self.url(1234, 'servers'),
|
||||
json=get_1234_servers,
|
||||
headers=self.headers)
|
||||
|
||||
@ -10,8 +10,6 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import httpretty
|
||||
|
||||
from novaclient.openstack.common import jsonutils
|
||||
from novaclient.tests import fakes
|
||||
from novaclient.tests.fixture_data import base
|
||||
@ -31,9 +29,11 @@ class V1(base.Fixture):
|
||||
]
|
||||
}
|
||||
|
||||
httpretty.register_uri(httpretty.GET, self.url(),
|
||||
body=jsonutils.dumps(get_images),
|
||||
content_type='application/json')
|
||||
headers = {'Content-Type': 'application/json'}
|
||||
|
||||
self.requests.register_uri('GET', self.url(),
|
||||
json=get_images,
|
||||
headers=headers)
|
||||
|
||||
image_1 = {
|
||||
'id': 1,
|
||||
@ -58,60 +58,53 @@ class V1(base.Fixture):
|
||||
"links": {},
|
||||
}
|
||||
|
||||
get_images_detail = {'images': [image_1, image_2]}
|
||||
self.requests.register_uri('GET', self.url('detail'),
|
||||
json={'images': [image_1, image_2]},
|
||||
headers=headers)
|
||||
|
||||
httpretty.register_uri(httpretty.GET, self.url('detail'),
|
||||
body=jsonutils.dumps(get_images_detail),
|
||||
content_type='application/json')
|
||||
self.requests.register_uri('GET', self.url(1),
|
||||
json={'image': image_1},
|
||||
headers=headers)
|
||||
|
||||
get_images_1 = {'image': image_1}
|
||||
self.requests.register_uri('GET', self.url(2),
|
||||
json={'image': image_2},
|
||||
headers=headers)
|
||||
|
||||
httpretty.register_uri(httpretty.GET, self.url(1),
|
||||
body=jsonutils.dumps(get_images_1),
|
||||
content_type='application/json')
|
||||
self.requests.register_uri('GET', self.url(456),
|
||||
json={'image': image_2},
|
||||
headers=headers)
|
||||
|
||||
get_images_2 = {'image': image_2}
|
||||
|
||||
httpretty.register_uri(httpretty.GET, self.url(2),
|
||||
body=jsonutils.dumps(get_images_2),
|
||||
content_type='application/json')
|
||||
|
||||
httpretty.register_uri(httpretty.GET, self.url(456),
|
||||
body=jsonutils.dumps(get_images_2),
|
||||
content_type='application/json')
|
||||
|
||||
def post_images(request, url, headers):
|
||||
body = jsonutils.loads(request.body.decode('utf-8'))
|
||||
def post_images(request, context):
|
||||
body = jsonutils.loads(request.body)
|
||||
assert list(body) == ['image']
|
||||
fakes.assert_has_keys(body['image'], required=['serverId', 'name'])
|
||||
return 202, headers, jsonutils.dumps(images_1)
|
||||
return images_1
|
||||
|
||||
httpretty.register_uri(httpretty.POST, self.url(),
|
||||
body=post_images,
|
||||
content_type='application/json')
|
||||
self.requests.register_uri('POST', self.url(),
|
||||
json=post_images,
|
||||
headers=headers,
|
||||
status_code=202)
|
||||
|
||||
def post_images_1_metadata(request, url, headers):
|
||||
body = jsonutils.loads(request.body.decode('utf-8'))
|
||||
def post_images_1_metadata(request, context):
|
||||
body = jsonutils.loads(request.body)
|
||||
assert list(body) == ['metadata']
|
||||
fakes.assert_has_keys(body['metadata'], required=['test_key'])
|
||||
data = jsonutils.dumps({'metadata': image_1['metadata']})
|
||||
return 200, headers, data
|
||||
return {'metadata': image_1['metadata']}
|
||||
|
||||
httpretty.register_uri(httpretty.POST, self.url(1, 'metadata'),
|
||||
body=post_images_1_metadata,
|
||||
content_type='application/json')
|
||||
self.requests.register_uri('POST', self.url(1, 'metadata'),
|
||||
json=post_images_1_metadata,
|
||||
headers=headers)
|
||||
|
||||
for u in (1, 2, '1/metadata/test_key'):
|
||||
httpretty.register_uri(httpretty.DELETE, self.url(u),
|
||||
status=204)
|
||||
self.requests.register_uri('DELETE', self.url(u), status_code=204)
|
||||
|
||||
httpretty.register_uri(httpretty.HEAD, self.url(1), status=200,
|
||||
x_image_meta_id=1,
|
||||
x_image_meta_name='CentOS 5.2',
|
||||
x_image_meta_updated='2010-10-10T12:00:00Z',
|
||||
x_image_meta_created='2010-10-10T12:00:00Z',
|
||||
x_image_meta_status='ACTIVE',
|
||||
x_image_meta_property_test_key='test_value')
|
||||
image_headers = {'x-image-meta-id': '1',
|
||||
'x-image-meta-name': 'CentOS 5.2',
|
||||
'x-image-meta-updated': '2010-10-10T12:00:00Z',
|
||||
'x-image-meta-created': '2010-10-10T12:00:00Z',
|
||||
'x-image-meta-status': 'ACTIVE',
|
||||
'x-image-meta-property-test-key': 'test_value'}
|
||||
self.requests.register_uri('HEAD', self.url(1), headers=image_headers)
|
||||
|
||||
|
||||
class V3(V1):
|
||||
|
||||
@ -10,9 +10,6 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
|
||||
import httpretty
|
||||
|
||||
from novaclient.openstack.common import jsonutils
|
||||
from novaclient.tests import fakes
|
||||
from novaclient.tests.fixture_data import base
|
||||
@ -26,25 +23,27 @@ class V1(base.Fixture):
|
||||
super(V1, self).setUp()
|
||||
keypair = {'fingerprint': 'FAKE_KEYPAIR', 'name': 'test'}
|
||||
|
||||
httpretty.register_uri(httpretty.GET, self.url(),
|
||||
body=jsonutils.dumps({'keypairs': [keypair]}),
|
||||
content_type='application/json')
|
||||
headers = {'Content-Type': 'application/json'}
|
||||
|
||||
httpretty.register_uri(httpretty.GET, self.url('test'),
|
||||
body=jsonutils.dumps({'keypair': keypair}),
|
||||
content_type='application/json')
|
||||
self.requests.register_uri('GET', self.url(),
|
||||
json={'keypairs': [keypair]},
|
||||
headers=headers)
|
||||
|
||||
httpretty.register_uri(httpretty.DELETE, self.url('test'), status=202)
|
||||
self.requests.register_uri('GET', self.url('test'),
|
||||
json={'keypair': keypair},
|
||||
headers=headers)
|
||||
|
||||
def post_os_keypairs(request, url, headers):
|
||||
body = jsonutils.loads(request.body.decode('utf-8'))
|
||||
self.requests.register_uri('DELETE', self.url('test'), status_code=202)
|
||||
|
||||
def post_os_keypairs(request, context):
|
||||
body = jsonutils.loads(request.body)
|
||||
assert list(body) == ['keypair']
|
||||
fakes.assert_has_keys(body['keypair'], required=['name'])
|
||||
return 202, headers, jsonutils.dumps({'keypair': keypair})
|
||||
return {'keypair': keypair}
|
||||
|
||||
httpretty.register_uri(httpretty.POST, self.url(),
|
||||
body=post_os_keypairs,
|
||||
content_type='application/json')
|
||||
self.requests.register_uri('POST', self.url(),
|
||||
json=post_os_keypairs,
|
||||
headers=headers)
|
||||
|
||||
|
||||
class V3(V1):
|
||||
|
||||
@ -10,9 +10,6 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import httpretty
|
||||
|
||||
from novaclient.openstack.common import jsonutils
|
||||
from novaclient.tests.fixture_data import base
|
||||
|
||||
|
||||
@ -77,6 +74,7 @@ class Fixture(base.Fixture):
|
||||
},
|
||||
}
|
||||
|
||||
httpretty.register_uri(httpretty.GET, self.url(),
|
||||
body=jsonutils.dumps(get_limits),
|
||||
content_type='application/json')
|
||||
headers = {'Content-Type': 'application/json'}
|
||||
self.requests.register_uri('GET', self.url(),
|
||||
json=get_limits,
|
||||
headers=headers)
|
||||
|
||||
@ -10,8 +10,6 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import httpretty
|
||||
|
||||
from novaclient.openstack.common import jsonutils
|
||||
from novaclient.tests.fixture_data import base
|
||||
|
||||
@ -34,29 +32,30 @@ class Fixture(base.Fixture):
|
||||
]
|
||||
}
|
||||
|
||||
httpretty.register_uri(httpretty.GET, self.url(),
|
||||
body=jsonutils.dumps(get_os_networks),
|
||||
content_type='application/json')
|
||||
headers = {'Content-Type': 'application/json'}
|
||||
|
||||
def post_os_networks(request, url, headers):
|
||||
body = jsonutils.loads(request.body.decode('utf-8'))
|
||||
data = jsonutils.dumps({'network': body})
|
||||
return 202, headers, data
|
||||
self.requests.register_uri('GET', self.url(),
|
||||
json=get_os_networks,
|
||||
headers=headers)
|
||||
|
||||
httpretty.register_uri(httpretty.POST, self.url(),
|
||||
body=post_os_networks,
|
||||
content_type='application/json')
|
||||
def post_os_networks(request, context):
|
||||
body = jsonutils.loads(request.body)
|
||||
return {'network': body}
|
||||
|
||||
self.requests.register_uri("POST", self.url(),
|
||||
json=post_os_networks,
|
||||
headers=headers)
|
||||
|
||||
get_os_networks_1 = {'network': {"label": "1", "cidr": "10.0.0.0/24"}}
|
||||
|
||||
httpretty.register_uri(httpretty.GET, self.url(1),
|
||||
body=jsonutils.dumps(get_os_networks_1),
|
||||
content_type='application/json')
|
||||
self.requests.register_uri('GET', self.url(1),
|
||||
json=get_os_networks_1,
|
||||
headers=headers)
|
||||
|
||||
httpretty.register_uri(httpretty.DELETE,
|
||||
self.url('networkdelete'),
|
||||
stauts=202)
|
||||
self.requests.register_uri('DELETE',
|
||||
self.url('networkdelete'),
|
||||
status_code=202)
|
||||
|
||||
for u in ('add', 'networkdisassociate/action', 'networktest/action',
|
||||
'1/action', '2/action'):
|
||||
httpretty.register_uri(httpretty.POST, self.url(u), stauts=202)
|
||||
self.requests.register_uri('POST', self.url(u), status_code=202)
|
||||
|
||||
@ -10,9 +10,6 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import httpretty
|
||||
|
||||
from novaclient.openstack.common import jsonutils
|
||||
from novaclient.tests.fixture_data import base
|
||||
|
||||
|
||||
@ -25,32 +22,32 @@ class V1(base.Fixture):
|
||||
|
||||
uuid = '97f4c221-bff4-4578-b030-0df4ef119353'
|
||||
uuid2 = '97f4c221bff44578b0300df4ef119353'
|
||||
test_json = jsonutils.dumps({'quota_set': self.test_quota('test')})
|
||||
test_json = {'quota_set': self.test_quota('test')}
|
||||
self.headers = {'Content-Type': 'application/json'}
|
||||
|
||||
for u in ('test', 'tenant-id', 'tenant-id/defaults',
|
||||
'%s/defaults' % uuid2):
|
||||
httpretty.register_uri(httpretty.GET, self.url(u),
|
||||
body=test_json,
|
||||
content_type='application/json')
|
||||
self.requests.register_uri('GET', self.url(u),
|
||||
json=test_json,
|
||||
headers=self.headers)
|
||||
|
||||
quota_json = jsonutils.dumps({'quota_set': self.test_quota(uuid)})
|
||||
httpretty.register_uri(httpretty.PUT, self.url(uuid),
|
||||
body=quota_json,
|
||||
content_type='application/json')
|
||||
httpretty.register_uri(httpretty.GET, self.url(uuid),
|
||||
body=quota_json,
|
||||
content_type='application/json')
|
||||
self.requests.register_uri('PUT', self.url(uuid),
|
||||
json={'quota_set': self.test_quota(uuid)},
|
||||
headers=self.headers)
|
||||
|
||||
quota_json2 = jsonutils.dumps({'quota_set': self.test_quota(uuid2)})
|
||||
httpretty.register_uri(httpretty.PUT, self.url(uuid2),
|
||||
body=quota_json2,
|
||||
content_type='application/json')
|
||||
httpretty.register_uri(httpretty.GET, self.url(uuid2),
|
||||
body=quota_json2,
|
||||
content_type='application/json')
|
||||
self.requests.register_uri('GET', self.url(uuid),
|
||||
json={'quota_set': self.test_quota(uuid)},
|
||||
headers=self.headers)
|
||||
|
||||
self.requests.register_uri('PUT', self.url(uuid2),
|
||||
json={'quota_set': self.test_quota(uuid2)},
|
||||
headers=self.headers)
|
||||
self.requests.register_uri('GET', self.url(uuid2),
|
||||
json={'quota_set': self.test_quota(uuid2)},
|
||||
headers=self.headers)
|
||||
|
||||
for u in ('test', uuid2):
|
||||
httpretty.register_uri(httpretty.DELETE, self.url(u), status=202)
|
||||
self.requests.register_uri('DELETE', self.url(u), status_code=202)
|
||||
|
||||
def test_quota(self, tenant_id='test'):
|
||||
return {
|
||||
@ -82,6 +79,6 @@ class V3(V1):
|
||||
}
|
||||
}
|
||||
|
||||
httpretty.register_uri(httpretty.GET, self.url('test', 'detail'),
|
||||
body=jsonutils.dumps(get_detail),
|
||||
content_type='application/json')
|
||||
self.requests.register_uri('GET', self.url('test', 'detail'),
|
||||
json=get_detail,
|
||||
headers=self.headers)
|
||||
|
||||
@ -10,8 +10,6 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import httpretty
|
||||
|
||||
from novaclient.openstack.common import jsonutils
|
||||
from novaclient.tests import fakes
|
||||
from novaclient.tests.fixture_data import base
|
||||
@ -34,24 +32,26 @@ class Fixture(base.Fixture):
|
||||
'cidr': '10.0.0.0/8'
|
||||
}
|
||||
|
||||
get_rules = {'security_group_rules': [rule]}
|
||||
httpretty.register_uri(httpretty.GET, self.url(),
|
||||
body=jsonutils.dumps(get_rules),
|
||||
content_type='application/json')
|
||||
headers = {'Content-Type': 'application/json'}
|
||||
|
||||
self.requests.register_uri('GET', self.url(),
|
||||
json={'security_group_rules': [rule]},
|
||||
headers=headers)
|
||||
|
||||
for u in (1, 11, 12):
|
||||
httpretty.register_uri(httpretty.DELETE, self.url(u), status=202)
|
||||
self.requests.register_uri('DELETE', self.url(u), status_code=202)
|
||||
|
||||
def post_rules(request, url, headers):
|
||||
body = jsonutils.loads(request.body.decode('utf-8'))
|
||||
def post_rules(request, context):
|
||||
body = jsonutils.loads(request.body)
|
||||
assert list(body) == ['security_group_rule']
|
||||
fakes.assert_has_keys(body['security_group_rule'],
|
||||
required=['parent_group_id'],
|
||||
optional=['group_id', 'ip_protocol',
|
||||
'from_port', 'to_port', 'cidr'])
|
||||
|
||||
return 202, headers, jsonutils.dumps({'security_group_rule': rule})
|
||||
return {'security_group_rule': rule}
|
||||
|
||||
httpretty.register_uri(httpretty.POST, self.url(),
|
||||
body=post_rules,
|
||||
content_type='application/json')
|
||||
self.requests.register_uri('POST', self.url(),
|
||||
json=post_rules,
|
||||
headers=headers,
|
||||
status_code=202)
|
||||
|
||||
@ -10,9 +10,6 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
|
||||
import httpretty
|
||||
|
||||
from novaclient.openstack.common import jsonutils
|
||||
from novaclient.tests import fakes
|
||||
from novaclient.tests.fixture_data import base
|
||||
@ -64,36 +61,39 @@ class Fixture(base.Fixture):
|
||||
}
|
||||
|
||||
get_groups = {'security_groups': [security_group_1, security_group_2]}
|
||||
httpretty.register_uri(httpretty.GET, self.url(),
|
||||
body=jsonutils.dumps(get_groups),
|
||||
content_type='application/json')
|
||||
headers = {'Content-Type': 'application/json'}
|
||||
|
||||
self.requests.register_uri('GET', self.url(),
|
||||
json=get_groups,
|
||||
headers=headers)
|
||||
|
||||
get_group_1 = {'security_group': security_group_1}
|
||||
httpretty.register_uri(httpretty.GET, self.url(1),
|
||||
body=jsonutils.dumps(get_group_1),
|
||||
content_type='application/json')
|
||||
self.requests.register_uri('GET', self.url(1),
|
||||
json=get_group_1,
|
||||
headers=headers)
|
||||
|
||||
httpretty.register_uri(httpretty.DELETE, self.url(1), status=202)
|
||||
self.requests.register_uri('DELETE', self.url(1), status_code=202)
|
||||
|
||||
def post_os_security_groups(request, url, headers):
|
||||
body = jsonutils.loads(request.body.decode('utf-8'))
|
||||
def post_os_security_groups(request, context):
|
||||
body = jsonutils.loads(request.body)
|
||||
assert list(body) == ['security_group']
|
||||
fakes.assert_has_keys(body['security_group'],
|
||||
required=['name', 'description'])
|
||||
r = jsonutils.dumps({'security_group': security_group_1})
|
||||
return 202, headers, r
|
||||
return {'security_group': security_group_1}
|
||||
|
||||
httpretty.register_uri(httpretty.POST, self.url(),
|
||||
body=post_os_security_groups,
|
||||
content_type='application/json')
|
||||
self.requests.register_uri('POST', self.url(),
|
||||
json=post_os_security_groups,
|
||||
headers=headers,
|
||||
status_code=202)
|
||||
|
||||
def put_os_security_groups_1(request, url, headers):
|
||||
body = jsonutils.loads(request.body.decode('utf-8'))
|
||||
def put_os_security_groups_1(request, context):
|
||||
body = jsonutils.loads(request.body)
|
||||
assert list(body) == ['security_group']
|
||||
fakes.assert_has_keys(body['security_group'],
|
||||
required=['name', 'description'])
|
||||
return 205, headers, request.body
|
||||
return body
|
||||
|
||||
httpretty.register_uri(httpretty.PUT, self.url(1),
|
||||
body=put_os_security_groups_1,
|
||||
content_type='application/json')
|
||||
self.requests.register_uri('PUT', self.url(1),
|
||||
json=put_os_security_groups_1,
|
||||
headers=headers,
|
||||
status_code=205)
|
||||
|
||||
@ -10,9 +10,6 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
|
||||
import httpretty
|
||||
|
||||
from novaclient.openstack.common import jsonutils
|
||||
from novaclient.tests.fixture_data import base
|
||||
|
||||
@ -54,22 +51,23 @@ class Fixture(base.Fixture):
|
||||
}
|
||||
]
|
||||
|
||||
get_server_groups = {'server_groups': server_groups}
|
||||
httpretty.register_uri(httpretty.GET, self.url(),
|
||||
body=jsonutils.dumps(get_server_groups),
|
||||
content_type='application/json')
|
||||
headers = {'Content-Type': 'application/json'}
|
||||
|
||||
self.requests.register_uri('GET', self.url(),
|
||||
json={'server_groups': server_groups},
|
||||
headers=headers)
|
||||
|
||||
server = server_groups[0]
|
||||
server_json = jsonutils.dumps({'server_group': server})
|
||||
server_j = jsonutils.dumps({'server_group': server})
|
||||
|
||||
def _register(method, *args):
|
||||
httpretty.register_uri(method, self.url(*args), body=server_json)
|
||||
self.requests.register_uri(method, self.url(*args), text=server_j)
|
||||
|
||||
_register(httpretty.POST)
|
||||
_register(httpretty.POST, server['id'])
|
||||
_register(httpretty.GET, server['id'])
|
||||
_register(httpretty.PUT, server['id'])
|
||||
_register(httpretty.POST, server['id'], '/action')
|
||||
_register('POST')
|
||||
_register('POST', server['id'])
|
||||
_register('GET', server['id'])
|
||||
_register('PUT', server['id'])
|
||||
_register('POST', server['id'], '/action')
|
||||
|
||||
httpretty.register_uri(httpretty.DELETE, self.url(server['id']),
|
||||
status=202)
|
||||
self.requests.register_uri('DELETE', self.url(server['id']),
|
||||
status_code=202)
|
||||
|
||||
612
awx/lib/site-packages/novaclient/tests/fixture_data/servers.py
Normal file
612
awx/lib/site-packages/novaclient/tests/fixture_data/servers.py
Normal file
@ -0,0 +1,612 @@
|
||||
# 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.
|
||||
|
||||
from novaclient.openstack.common import jsonutils
|
||||
from novaclient.tests import fakes
|
||||
from novaclient.tests.fixture_data import base
|
||||
|
||||
|
||||
class Base(base.Fixture):
|
||||
|
||||
base_url = 'servers'
|
||||
|
||||
def setUp(self):
|
||||
super(Base, self).setUp()
|
||||
|
||||
get_servers = {
|
||||
"servers": [
|
||||
{'id': 1234, 'name': 'sample-server'},
|
||||
{'id': 5678, 'name': 'sample-server2'}
|
||||
]
|
||||
}
|
||||
|
||||
self.requests.register_uri('GET', self.url(),
|
||||
json=get_servers,
|
||||
headers=self.json_headers)
|
||||
|
||||
self.server_1234 = {
|
||||
"id": 1234,
|
||||
"name": "sample-server",
|
||||
"image": {
|
||||
"id": 2,
|
||||
"name": "sample image",
|
||||
},
|
||||
"flavor": {
|
||||
"id": 1,
|
||||
"name": "256 MB Server",
|
||||
},
|
||||
"hostId": "e4d909c290d0fb1ca068ffaddf22cbd0",
|
||||
"status": "BUILD",
|
||||
"progress": 60,
|
||||
"addresses": {
|
||||
"public": [{
|
||||
"version": 4,
|
||||
"addr": "1.2.3.4",
|
||||
},
|
||||
{
|
||||
"version": 4,
|
||||
"addr": "5.6.7.8",
|
||||
}],
|
||||
"private": [{
|
||||
"version": 4,
|
||||
"addr": "10.11.12.13",
|
||||
}],
|
||||
},
|
||||
"metadata": {
|
||||
"Server Label": "Web Head 1",
|
||||
"Image Version": "2.1"
|
||||
},
|
||||
"OS-EXT-SRV-ATTR:host": "computenode1",
|
||||
"security_groups": [{
|
||||
'id': 1, 'name': 'securitygroup1',
|
||||
'description': 'FAKE_SECURITY_GROUP',
|
||||
'tenant_id': '4ffc664c198e435e9853f2538fbcd7a7'
|
||||
}],
|
||||
"OS-EXT-MOD:some_thing": "mod_some_thing_value",
|
||||
}
|
||||
|
||||
self.server_5678 = {
|
||||
"id": 5678,
|
||||
"name": "sample-server2",
|
||||
"image": {
|
||||
"id": 2,
|
||||
"name": "sample image",
|
||||
},
|
||||
"flavor": {
|
||||
"id": 1,
|
||||
"name": "256 MB Server",
|
||||
},
|
||||
"hostId": "9e107d9d372bb6826bd81d3542a419d6",
|
||||
"status": "ACTIVE",
|
||||
"addresses": {
|
||||
"public": [{
|
||||
"version": 4,
|
||||
"addr": "4.5.6.7",
|
||||
},
|
||||
{
|
||||
"version": 4,
|
||||
"addr": "5.6.9.8",
|
||||
}],
|
||||
"private": [{
|
||||
"version": 4,
|
||||
"addr": "10.13.12.13",
|
||||
}],
|
||||
},
|
||||
"metadata": {
|
||||
"Server Label": "DB 1"
|
||||
},
|
||||
"OS-EXT-SRV-ATTR:host": "computenode2",
|
||||
"security_groups": [{
|
||||
'id': 1, 'name': 'securitygroup1',
|
||||
'description': 'FAKE_SECURITY_GROUP',
|
||||
'tenant_id': '4ffc664c198e435e9853f2538fbcd7a7'
|
||||
},
|
||||
{
|
||||
'id': 2, 'name': 'securitygroup2',
|
||||
'description': 'ANOTHER_FAKE_SECURITY_GROUP',
|
||||
'tenant_id': '4ffc664c198e435e9853f2538fbcd7a7'
|
||||
}],
|
||||
}
|
||||
|
||||
self.server_9012 = {
|
||||
"id": 9012,
|
||||
"name": "sample-server3",
|
||||
"image": "",
|
||||
"flavor": {
|
||||
"id": 1,
|
||||
"name": "256 MB Server",
|
||||
},
|
||||
"hostId": "9e107d9d372bb6826bd81d3542a419d6",
|
||||
"status": "ACTIVE",
|
||||
"addresses": {
|
||||
"public": [{
|
||||
"version": 4,
|
||||
"addr": "4.5.6.7",
|
||||
},
|
||||
{
|
||||
"version": 4,
|
||||
"addr": "5.6.9.8",
|
||||
}],
|
||||
"private": [{
|
||||
"version": 4,
|
||||
"addr": "10.13.12.13",
|
||||
}],
|
||||
},
|
||||
"metadata": {
|
||||
"Server Label": "DB 1"
|
||||
}
|
||||
}
|
||||
|
||||
servers = [self.server_1234, self.server_5678, self.server_9012]
|
||||
get_servers_detail = {"servers": servers}
|
||||
|
||||
self.requests.register_uri('GET', self.url('detail'),
|
||||
json=get_servers_detail,
|
||||
headers=self.json_headers)
|
||||
|
||||
self.server_1235 = self.server_1234.copy()
|
||||
self.server_1235['id'] = 1235
|
||||
self.server_1235['status'] = 'error'
|
||||
self.server_1235['fault'] = {'message': 'something went wrong!'}
|
||||
|
||||
for s in servers + [self.server_1235]:
|
||||
self.requests.register_uri('GET', self.url(s['id']),
|
||||
json={'server': s},
|
||||
headers=self.json_headers)
|
||||
|
||||
for s in (1234, 5678):
|
||||
self.requests.register_uri('DELETE', self.url(s), status_code=202)
|
||||
|
||||
for k in ('test_key', 'key1', 'key2'):
|
||||
self.requests.register_uri('DELETE',
|
||||
self.url(1234, 'metadata', k),
|
||||
status_code=204)
|
||||
|
||||
metadata1 = {'metadata': {'test_key': 'test_value'}}
|
||||
self.requests.register_uri('POST', self.url(1234, 'metadata'),
|
||||
json=metadata1,
|
||||
headers=self.json_headers)
|
||||
self.requests.register_uri('PUT',
|
||||
self.url(1234, 'metadata', 'test_key'),
|
||||
json=metadata1,
|
||||
headers=self.json_headers)
|
||||
|
||||
self.diagnostic = {'data': 'Fake diagnostics'}
|
||||
|
||||
metadata2 = {'metadata': {'key1': 'val1'}}
|
||||
for u in ('uuid1', 'uuid2', 'uuid3', 'uuid4'):
|
||||
self.requests.register_uri('POST', self.url(u, 'metadata'),
|
||||
json=metadata2, status_code=204)
|
||||
self.requests.register_uri('DELETE',
|
||||
self.url(u, 'metadata', 'key1'),
|
||||
json=self.diagnostic,
|
||||
headers=self.json_headers)
|
||||
|
||||
get_security_groups = {
|
||||
"security_groups": [{
|
||||
'id': 1,
|
||||
'name': 'securitygroup1',
|
||||
'description': 'FAKE_SECURITY_GROUP',
|
||||
'tenant_id': '4ffc664c198e435e9853f2538fbcd7a7',
|
||||
'rules': []}]
|
||||
}
|
||||
|
||||
self.requests.register_uri('GET',
|
||||
self.url('1234', 'os-security-groups'),
|
||||
json=get_security_groups)
|
||||
|
||||
self.requests.register_uri('POST', self.url(),
|
||||
json=self.post_servers,
|
||||
headers=self.json_headers)
|
||||
|
||||
self.requests.register_uri('POST', self.url('1234', 'action'),
|
||||
json=self.post_servers_1234_action,
|
||||
headers=self.json_headers)
|
||||
|
||||
get_os_interface = {
|
||||
"interfaceAttachments": [
|
||||
{
|
||||
"port_state": "ACTIVE",
|
||||
"net_id": "net-id-1",
|
||||
"port_id": "port-id-1",
|
||||
"mac_address": "aa:bb:cc:dd:ee:ff",
|
||||
"fixed_ips": [{"ip_address": "1.2.3.4"}],
|
||||
},
|
||||
{
|
||||
"port_state": "ACTIVE",
|
||||
"net_id": "net-id-1",
|
||||
"port_id": "port-id-1",
|
||||
"mac_address": "aa:bb:cc:dd:ee:ff",
|
||||
"fixed_ips": [{"ip_address": "1.2.3.4"}],
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
self.requests.register_uri('GET',
|
||||
self.url('1234', 'os-interface'),
|
||||
json=get_os_interface,
|
||||
headers=self.json_headers)
|
||||
|
||||
interface_data = {'interfaceAttachment': {}}
|
||||
self.requests.register_uri('POST',
|
||||
self.url('1234', 'os-interface'),
|
||||
json=interface_data,
|
||||
headers=self.json_headers)
|
||||
|
||||
def put_servers_1234(request, context):
|
||||
body = jsonutils.loads(request.body)
|
||||
assert list(body) == ['server']
|
||||
fakes.assert_has_keys(body['server'],
|
||||
optional=['name', 'adminPass'])
|
||||
return request.body
|
||||
|
||||
self.requests.register_uri('PUT', self.url(1234),
|
||||
text=put_servers_1234,
|
||||
status_code=204,
|
||||
headers=self.json_headers)
|
||||
|
||||
def post_os_volumes_boot(request, context):
|
||||
body = jsonutils.loads(request.body)
|
||||
assert (set(body.keys()) <=
|
||||
set(['server', 'os:scheduler_hints']))
|
||||
|
||||
fakes.assert_has_keys(body['server'],
|
||||
required=['name', 'flavorRef'],
|
||||
optional=['imageRef'])
|
||||
|
||||
data = body['server']
|
||||
|
||||
# Require one, and only one, of the keys for bdm
|
||||
if 'block_device_mapping' not in data:
|
||||
if 'block_device_mapping_v2' not in data:
|
||||
msg = "missing required keys: 'block_device_mapping'"
|
||||
raise AssertionError(msg)
|
||||
elif 'block_device_mapping_v2' in data:
|
||||
msg = "found extra keys: 'block_device_mapping'"
|
||||
raise AssertionError(msg)
|
||||
|
||||
return {'server': self.server_9012}
|
||||
|
||||
# NOTE(jamielennox): hack to make os_volumes mock go to the right place
|
||||
base_url = self.base_url
|
||||
self.base_url = None
|
||||
self.requests.register_uri('POST', self.url('os-volumes_boot'),
|
||||
json=post_os_volumes_boot,
|
||||
status_code=202,
|
||||
headers=self.json_headers)
|
||||
self.base_url = base_url
|
||||
|
||||
#
|
||||
# Server password
|
||||
#
|
||||
|
||||
self.requests.register_uri('DELETE',
|
||||
self.url(1234, 'os-server-password'),
|
||||
status_code=202)
|
||||
|
||||
|
||||
class V1(Base):
|
||||
|
||||
def setUp(self):
|
||||
super(V1, self).setUp()
|
||||
|
||||
#
|
||||
# Server Addresses
|
||||
#
|
||||
|
||||
add = self.server_1234['addresses']
|
||||
self.requests.register_uri('GET', self.url(1234, 'ips'),
|
||||
json={'addresses': add},
|
||||
headers=self.json_headers)
|
||||
|
||||
self.requests.register_uri('GET', self.url(1234, 'ips', 'public'),
|
||||
json={'public': add['public']},
|
||||
headers=self.json_headers)
|
||||
|
||||
self.requests.register_uri('GET', self.url(1234, 'ips', 'private'),
|
||||
json={'private': add['private']},
|
||||
headers=self.json_headers)
|
||||
|
||||
self.requests.register_uri('DELETE',
|
||||
self.url(1234, 'ips', 'public', '1.2.3.4'),
|
||||
status_code=202)
|
||||
|
||||
self.requests.register_uri('GET',
|
||||
self.url('1234', 'diagnostics'),
|
||||
json=self.diagnostic)
|
||||
|
||||
self.requests.register_uri('DELETE',
|
||||
self.url('1234', 'os-interface', 'port-id'))
|
||||
|
||||
# Testing with the following password and key
|
||||
#
|
||||
# Clear password: FooBar123
|
||||
#
|
||||
# RSA Private Key: novaclient/tests/idfake.pem
|
||||
#
|
||||
# Encrypted password
|
||||
# OIuEuQttO8Rk93BcKlwHQsziDAnkAm/V6V8VPToA8ZeUaUBWwS0gwo2K6Y61Z96r
|
||||
# qG447iRz0uTEEYq3RAYJk1mh3mMIRVl27t8MtIecR5ggVVbz1S9AwXJQypDKl0ho
|
||||
# QFvhCBcMWPohyGewDJOhDbtuN1IoFI9G55ZvFwCm5y7m7B2aVcoLeIsJZE4PLsIw
|
||||
# /y5a6Z3/AoJZYGG7IH5WN88UROU3B9JZGFB2qtPLQTOvDMZLUhoPRIJeHiVSlo1N
|
||||
# tI2/++UsXVg3ow6ItqCJGgdNuGG5JB+bslDHWPxROpesEIHdczk46HCpHQN8f1sk
|
||||
# Hi/fmZZNQQqj1Ijq0caOIw==
|
||||
|
||||
get_server_password = {'password':
|
||||
'OIuEuQttO8Rk93BcKlwHQsziDAnkAm/V6V8VPToA8ZeUaUBWwS0gwo2K6Y61Z96r'
|
||||
'qG447iRz0uTEEYq3RAYJk1mh3mMIRVl27t8MtIecR5ggVVbz1S9AwXJQypDKl0ho'
|
||||
'QFvhCBcMWPohyGewDJOhDbtuN1IoFI9G55ZvFwCm5y7m7B2aVcoLeIsJZE4PLsIw'
|
||||
'/y5a6Z3/AoJZYGG7IH5WN88UROU3B9JZGFB2qtPLQTOvDMZLUhoPRIJeHiVSlo1N'
|
||||
'tI2/++UsXVg3ow6ItqCJGgdNuGG5JB+bslDHWPxROpesEIHdczk46HCpHQN8f1sk'
|
||||
'Hi/fmZZNQQqj1Ijq0caOIw=='}
|
||||
self.requests.register_uri('GET',
|
||||
self.url(1234, 'os-server-password'),
|
||||
json=get_server_password)
|
||||
|
||||
def post_servers(self, request, context):
|
||||
body = jsonutils.loads(request.body)
|
||||
context.status_code = 202
|
||||
assert (set(body.keys()) <=
|
||||
set(['server', 'os:scheduler_hints']))
|
||||
fakes.assert_has_keys(body['server'],
|
||||
required=['name', 'imageRef', 'flavorRef'],
|
||||
optional=['metadata', 'personality'])
|
||||
if 'personality' in body['server']:
|
||||
for pfile in body['server']['personality']:
|
||||
fakes.assert_has_keys(pfile, required=['path', 'contents'])
|
||||
if body['server']['name'] == 'some-bad-server':
|
||||
body = self.server_1235
|
||||
else:
|
||||
body = self.server_1234
|
||||
|
||||
return {'server': body}
|
||||
|
||||
def post_servers_1234_action(self, request, context):
|
||||
_body = ''
|
||||
body = jsonutils.loads(request.body)
|
||||
context.status_code = 202
|
||||
assert len(body.keys()) == 1
|
||||
action = list(body)[0]
|
||||
if action == 'reboot':
|
||||
assert list(body[action]) == ['type']
|
||||
assert body[action]['type'] in ['HARD', 'SOFT']
|
||||
elif action == 'rebuild':
|
||||
body = body[action]
|
||||
adminPass = body.get('adminPass', 'randompassword')
|
||||
assert 'imageRef' in body
|
||||
_body = self.server_1234.copy()
|
||||
_body['adminPass'] = adminPass
|
||||
elif action == 'resize':
|
||||
keys = body[action].keys()
|
||||
assert 'flavorRef' in keys
|
||||
elif action == 'confirmResize':
|
||||
assert body[action] is None
|
||||
# This one method returns a different response code
|
||||
context.status_code = 204
|
||||
return None
|
||||
elif action == 'revertResize':
|
||||
assert body[action] is None
|
||||
elif action == 'migrate':
|
||||
assert body[action] is None
|
||||
elif action == 'os-stop':
|
||||
assert body[action] is None
|
||||
elif action == 'os-start':
|
||||
assert body[action] is None
|
||||
elif action == 'forceDelete':
|
||||
assert body[action] is None
|
||||
elif action == 'restore':
|
||||
assert body[action] is None
|
||||
elif action == 'pause':
|
||||
assert body[action] is None
|
||||
elif action == 'unpause':
|
||||
assert body[action] is None
|
||||
elif action == 'lock':
|
||||
assert body[action] is None
|
||||
elif action == 'unlock':
|
||||
assert body[action] is None
|
||||
elif action == 'rescue':
|
||||
assert body[action] is None
|
||||
_body = {'Password': 'RescuePassword'}
|
||||
elif action == 'unrescue':
|
||||
assert body[action] is None
|
||||
elif action == 'resume':
|
||||
assert body[action] is None
|
||||
elif action == 'suspend':
|
||||
assert body[action] is None
|
||||
elif action == 'lock':
|
||||
assert body[action] is None
|
||||
elif action == 'unlock':
|
||||
assert body[action] is None
|
||||
elif action == 'shelve':
|
||||
assert body[action] is None
|
||||
elif action == 'shelveOffload':
|
||||
assert body[action] is None
|
||||
elif action == 'unshelve':
|
||||
assert body[action] is None
|
||||
elif action == 'addFixedIp':
|
||||
assert list(body[action]) == ['networkId']
|
||||
elif action == 'removeFixedIp':
|
||||
assert list(body[action]) == ['address']
|
||||
elif action == 'addFloatingIp':
|
||||
assert (list(body[action]) == ['address'] or
|
||||
sorted(list(body[action])) == ['address',
|
||||
'fixed_address'])
|
||||
elif action == 'removeFloatingIp':
|
||||
assert list(body[action]) == ['address']
|
||||
elif action == 'createImage':
|
||||
assert set(body[action].keys()) == set(['name', 'metadata'])
|
||||
context.headers['location'] = "http://blah/images/456"
|
||||
elif action == 'changePassword':
|
||||
assert list(body[action]) == ['adminPass']
|
||||
elif action == 'os-getConsoleOutput':
|
||||
assert list(body[action]) == ['length']
|
||||
context.status_code = 202
|
||||
return {'output': 'foo'}
|
||||
elif action == 'os-getVNCConsole':
|
||||
assert list(body[action]) == ['type']
|
||||
elif action == 'os-getSPICEConsole':
|
||||
assert list(body[action]) == ['type']
|
||||
elif action == 'os-getRDPConsole':
|
||||
assert list(body[action]) == ['type']
|
||||
elif action == 'os-getSerialConsole':
|
||||
assert list(body[action]) == ['type']
|
||||
elif action == 'os-migrateLive':
|
||||
assert set(body[action].keys()) == set(['host',
|
||||
'block_migration',
|
||||
'disk_over_commit'])
|
||||
elif action == 'os-resetState':
|
||||
assert list(body[action]) == ['state']
|
||||
elif action == 'resetNetwork':
|
||||
assert body[action] is None
|
||||
elif action == 'addSecurityGroup':
|
||||
assert list(body[action]) == ['name']
|
||||
elif action == 'removeSecurityGroup':
|
||||
assert list(body[action]) == ['name']
|
||||
elif action == 'createBackup':
|
||||
assert set(body[action]) == set(['name',
|
||||
'backup_type',
|
||||
'rotation'])
|
||||
elif action == 'evacuate':
|
||||
keys = list(body[action])
|
||||
if 'adminPass' in keys:
|
||||
keys.remove('adminPass')
|
||||
assert set(keys) == set(['host', 'onSharedStorage'])
|
||||
else:
|
||||
raise AssertionError("Unexpected server action: %s" % action)
|
||||
return {'server': _body}
|
||||
|
||||
|
||||
class V3(Base):
|
||||
|
||||
def setUp(self):
|
||||
super(V3, self).setUp()
|
||||
|
||||
get_interfaces = {
|
||||
"interface_attachments": [
|
||||
{
|
||||
"port_state": "ACTIVE",
|
||||
"net_id": "net-id-1",
|
||||
"port_id": "port-id-1",
|
||||
"mac_address": "aa:bb:cc:dd:ee:ff",
|
||||
"fixed_ips": [{"ip_address": "1.2.3.4"}],
|
||||
},
|
||||
{
|
||||
"port_state": "ACTIVE",
|
||||
"net_id": "net-id-1",
|
||||
"port_id": "port-id-1",
|
||||
"mac_address": "aa:bb:cc:dd:ee:ff",
|
||||
"fixed_ips": [{"ip_address": "1.2.3.4"}],
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
self.requests.register_uri('GET',
|
||||
self.url('1234', 'os-attach-interfaces'),
|
||||
json=get_interfaces,
|
||||
headers=self.json_headers)
|
||||
|
||||
attach_body = {'interface_attachment': {}}
|
||||
self.requests.register_uri('POST',
|
||||
self.url('1234', 'os-attach-interfaces'),
|
||||
json=attach_body,
|
||||
headers=self.json_headers)
|
||||
|
||||
self.requests.register_uri('GET',
|
||||
self.url('1234', 'os-server-diagnostics'),
|
||||
json=self.diagnostic)
|
||||
|
||||
url = self.url('1234', 'os-attach-interfaces', 'port-id')
|
||||
self.requests.register_uri('DELETE', url)
|
||||
|
||||
self.requests.register_uri('GET',
|
||||
self.url(1234, 'os-server-password'),
|
||||
json={'password': ''})
|
||||
|
||||
def post_servers(self, request, context):
|
||||
body = jsonutils.loads(request.body)
|
||||
assert set(body.keys()) <= set(['server'])
|
||||
fakes.assert_has_keys(body['server'],
|
||||
required=['name', 'image_ref', 'flavor_ref'],
|
||||
optional=['metadata', 'personality',
|
||||
'os-scheduler-hints:scheduler_hints'])
|
||||
if body['server']['name'] == 'some-bad-server':
|
||||
body = self.server_1235
|
||||
else:
|
||||
body = self.server_1234
|
||||
|
||||
context.status_code = 202
|
||||
return {'server': body}
|
||||
|
||||
def post_servers_1234_action(self, request, context):
|
||||
context.status_code = 202
|
||||
body_is_none_list = [
|
||||
'revert_resize', 'migrate', 'stop', 'start', 'force_delete',
|
||||
'restore', 'pause', 'unpause', 'lock', 'unlock', 'unrescue',
|
||||
'resume', 'suspend', 'lock', 'unlock', 'shelve', 'shelve_offload',
|
||||
'unshelve', 'reset_network', 'rescue', 'confirm_resize']
|
||||
body_return_map = {
|
||||
'rescue': {'admin_password': 'RescuePassword'},
|
||||
'get_console_output': {'output': 'foo'},
|
||||
'rebuild': {'server': self.server_1234},
|
||||
}
|
||||
body_param_check_exists = {
|
||||
'rebuild': 'image_ref',
|
||||
'resize': 'flavor_ref'}
|
||||
body_params_check_exact = {
|
||||
'reboot': ['type'],
|
||||
'add_fixed_ip': ['network_id'],
|
||||
'evacuate': ['host', 'on_shared_storage'],
|
||||
'remove_fixed_ip': ['address'],
|
||||
'change_password': ['admin_password'],
|
||||
'get_console_output': ['length'],
|
||||
'get_vnc_console': ['type'],
|
||||
'get_spice_console': ['type'],
|
||||
'get_serial_console': ['type'],
|
||||
'reset_state': ['state'],
|
||||
'create_image': ['name', 'metadata'],
|
||||
'migrate_live': ['host', 'block_migration', 'disk_over_commit'],
|
||||
'create_backup': ['name', 'backup_type', 'rotation'],
|
||||
'attach': ['volume_id', 'device'],
|
||||
'detach': ['volume_id'],
|
||||
'swap_volume_attachment': ['old_volume_id', 'new_volume_id']}
|
||||
|
||||
body = jsonutils.loads(request.body)
|
||||
assert len(body.keys()) == 1
|
||||
action = list(body)[0]
|
||||
_body = body_return_map.get(action, '')
|
||||
|
||||
if action in body_is_none_list:
|
||||
assert body[action] is None
|
||||
|
||||
if action in body_param_check_exists:
|
||||
assert body_param_check_exists[action] in body[action]
|
||||
|
||||
if action == 'evacuate':
|
||||
body[action].pop('admin_password', None)
|
||||
|
||||
if action in body_params_check_exact:
|
||||
assert set(body[action]) == set(body_params_check_exact[action])
|
||||
|
||||
if action == 'reboot':
|
||||
assert body[action]['type'] in ['HARD', 'SOFT']
|
||||
elif action == 'confirm_resize':
|
||||
# This one method returns a different response code
|
||||
context.status_code = 204
|
||||
elif action == 'create_image':
|
||||
context.headers['location'] = "http://blah/images/456"
|
||||
|
||||
if action not in set.union(set(body_is_none_list),
|
||||
set(body_params_check_exact.keys()),
|
||||
set(body_param_check_exists.keys())):
|
||||
raise AssertionError("Unexpected server action: %s" % action)
|
||||
|
||||
return _body
|
||||
@ -14,6 +14,8 @@
|
||||
# under the License.
|
||||
|
||||
import argparse
|
||||
|
||||
from keystoneclient import fixture
|
||||
import mock
|
||||
import pkg_resources
|
||||
import requests
|
||||
@ -32,30 +34,10 @@ from novaclient.v1_1 import client
|
||||
def mock_http_request(resp=None):
|
||||
"""Mock an HTTP Request."""
|
||||
if not resp:
|
||||
resp = {
|
||||
"access": {
|
||||
"token": {
|
||||
"expires": "12345",
|
||||
"id": "FAKE_ID",
|
||||
"tenant": {
|
||||
"id": "FAKE_TENANT_ID",
|
||||
}
|
||||
},
|
||||
"serviceCatalog": [
|
||||
{
|
||||
"type": "compute",
|
||||
"endpoints": [
|
||||
{
|
||||
"region": "RegionOne",
|
||||
"adminURL": "http://localhost:8774/v1.1",
|
||||
"internalURL": "http://localhost:8774/v1.1",
|
||||
"publicURL": "http://localhost:8774/v1.1/",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
resp = fixture.V2Token()
|
||||
resp.set_scope()
|
||||
s = resp.add_service('compute')
|
||||
s.add_endpoint("http://localhost:8774/v1.1", region='RegionOne')
|
||||
|
||||
auth_response = utils.TestResponse({
|
||||
"status_code": 200,
|
||||
@ -171,7 +153,7 @@ class DeprecatedAuthPluginTest(utils.TestCase):
|
||||
auth_system="fakewithauthurl",
|
||||
auth_plugin=plugin)
|
||||
cs.client.authenticate()
|
||||
self.assertEqual(cs.client.auth_url, "http://faked/v2.0")
|
||||
self.assertEqual("http://faked/v2.0", cs.client.auth_url)
|
||||
|
||||
test_auth_call()
|
||||
|
||||
@ -301,7 +283,7 @@ class AuthPluginTest(utils.TestCase):
|
||||
cs = client.Client("username", "password", "project_id",
|
||||
auth_system="fakewithauthurl",
|
||||
auth_plugin=plugin)
|
||||
self.assertEqual(cs.client.auth_url, "http://faked/v2.0")
|
||||
self.assertEqual("http://faked/v2.0", cs.client.auth_url)
|
||||
|
||||
@mock.patch.object(pkg_resources, "iter_entry_points")
|
||||
def test_exception_if_no_authenticate(self, mock_iter_entry_points):
|
||||
|
||||
@ -25,18 +25,18 @@ class BaseTest(utils.TestCase):
|
||||
|
||||
def test_resource_repr(self):
|
||||
r = base.Resource(None, dict(foo="bar", baz="spam"))
|
||||
self.assertEqual(repr(r), "<Resource baz=spam, foo=bar>")
|
||||
self.assertEqual("<Resource baz=spam, foo=bar>", repr(r))
|
||||
|
||||
def test_getid(self):
|
||||
self.assertEqual(base.getid(4), 4)
|
||||
self.assertEqual(4, base.getid(4))
|
||||
|
||||
class TmpObject(object):
|
||||
id = 4
|
||||
self.assertEqual(base.getid(TmpObject), 4)
|
||||
self.assertEqual(4, base.getid(TmpObject))
|
||||
|
||||
def test_resource_lazy_getattr(self):
|
||||
f = flavors.Flavor(cs.flavors, {'id': 1})
|
||||
self.assertEqual(f.name, '256 MB Server')
|
||||
self.assertEqual('256 MB Server', f.name)
|
||||
cs.assert_called('GET', '/flavors/1')
|
||||
|
||||
# Missing stuff still fails after a second get
|
||||
|
||||
@ -14,11 +14,12 @@
|
||||
# under the License.
|
||||
|
||||
|
||||
import json
|
||||
import logging
|
||||
import mock
|
||||
import requests
|
||||
|
||||
import fixtures
|
||||
import mock
|
||||
import requests
|
||||
|
||||
import novaclient.client
|
||||
import novaclient.extension
|
||||
@ -27,8 +28,6 @@ from novaclient.tests import utils
|
||||
import novaclient.v1_1.client
|
||||
import novaclient.v3.client
|
||||
|
||||
import json
|
||||
|
||||
|
||||
class ClientConnectionPoolTest(utils.TestCase):
|
||||
|
||||
@ -48,7 +47,7 @@ class ClientTest(utils.TestCase):
|
||||
projectid='project',
|
||||
timeout=2,
|
||||
auth_url="http://www.blah.com")
|
||||
self.assertEqual(instance.timeout, 2)
|
||||
self.assertEqual(2, instance.timeout)
|
||||
mock_request = mock.Mock()
|
||||
mock_request.return_value = requests.Response()
|
||||
mock_request.return_value.status_code = 200
|
||||
@ -107,7 +106,38 @@ class ClientTest(utils.TestCase):
|
||||
allow_redirects=mock.ANY,
|
||||
data=json.dumps(data),
|
||||
verify=mock.ANY)]
|
||||
self.assertEqual(mock_request.call_args_list, expected)
|
||||
self.assertEqual(expected, mock_request.call_args_list)
|
||||
|
||||
@mock.patch.object(novaclient.client.HTTPClient, 'request',
|
||||
return_value=(200, "{'versions':[]}"))
|
||||
def _check_version_url(self, management_url, version_url, mock_request):
|
||||
projectid = '25e469aa1848471b875e68cde6531bc5'
|
||||
instance = novaclient.client.HTTPClient(user='user',
|
||||
password='password',
|
||||
projectid=projectid,
|
||||
auth_url="http://www.blah.com")
|
||||
instance.auth_token = 'foobar'
|
||||
instance.management_url = management_url % projectid
|
||||
instance.version = 'v2.0'
|
||||
|
||||
# If passing None as the part of url, a client accesses the url which
|
||||
# doesn't include "v2/<projectid>" for getting API version info.
|
||||
instance.get(None)
|
||||
mock_request.assert_called_once_with(version_url, 'GET',
|
||||
headers=mock.ANY)
|
||||
mock_request.reset_mock()
|
||||
|
||||
# Otherwise, a client accesses the url which includes "v2/<projectid>".
|
||||
instance.get('servers')
|
||||
url = instance.management_url + 'servers'
|
||||
mock_request.assert_called_once_with(url, 'GET', headers=mock.ANY)
|
||||
|
||||
def test_client_version_url(self):
|
||||
self._check_version_url('http://foo.com/v2/%s', 'http://foo.com/')
|
||||
|
||||
def test_client_version_url_with_project_name(self):
|
||||
self._check_version_url('http://foo.com/nova/v2/%s',
|
||||
'http://foo.com/nova/')
|
||||
|
||||
def test_get_client_class_v3(self):
|
||||
output = novaclient.client.get_client_class('3')
|
||||
@ -233,7 +263,7 @@ class ClientTest(utils.TestCase):
|
||||
def test_get_password_simple(self):
|
||||
cs = novaclient.client.HTTPClient("user", "password", "", "")
|
||||
cs.password_func = mock.Mock()
|
||||
self.assertEqual(cs._get_password(), "password")
|
||||
self.assertEqual("password", cs._get_password())
|
||||
self.assertFalse(cs.password_func.called)
|
||||
|
||||
def test_get_password_none(self):
|
||||
@ -243,26 +273,26 @@ class ClientTest(utils.TestCase):
|
||||
def test_get_password_func(self):
|
||||
cs = novaclient.client.HTTPClient("user", None, "", "")
|
||||
cs.password_func = mock.Mock(return_value="password")
|
||||
self.assertEqual(cs._get_password(), "password")
|
||||
self.assertEqual("password", cs._get_password())
|
||||
cs.password_func.assert_called_once_with()
|
||||
|
||||
cs.password_func = mock.Mock()
|
||||
self.assertEqual(cs._get_password(), "password")
|
||||
self.assertEqual("password", cs._get_password())
|
||||
self.assertFalse(cs.password_func.called)
|
||||
|
||||
def test_auth_url_rstrip_slash(self):
|
||||
cs = novaclient.client.HTTPClient("user", "password", "project_id",
|
||||
auth_url="foo/v2/")
|
||||
self.assertEqual(cs.auth_url, "foo/v2")
|
||||
self.assertEqual("foo/v2", cs.auth_url)
|
||||
|
||||
def test_token_and_bypass_url(self):
|
||||
cs = novaclient.client.HTTPClient(None, None, None,
|
||||
auth_token="12345",
|
||||
bypass_url="compute/v100/")
|
||||
self.assertIsNone(cs.auth_url)
|
||||
self.assertEqual(cs.auth_token, "12345")
|
||||
self.assertEqual(cs.bypass_url, "compute/v100")
|
||||
self.assertEqual(cs.management_url, "compute/v100")
|
||||
self.assertEqual("12345", cs.auth_token)
|
||||
self.assertEqual("compute/v100", cs.bypass_url)
|
||||
self.assertEqual("compute/v100", cs.management_url)
|
||||
|
||||
@mock.patch("novaclient.client.requests.Session")
|
||||
def test_session(self, mock_session):
|
||||
@ -343,6 +373,9 @@ class ClientTest(utils.TestCase):
|
||||
{'X-Foo': 'bar',
|
||||
'X-Auth-Token': 'totally_bogus'}
|
||||
})
|
||||
cs.http_log_req('GET', '/foo', {'headers': {},
|
||||
'data': '{"auth": {"passwordCredentials": '
|
||||
'{"password": "zhaoqin"}}}'})
|
||||
|
||||
output = self.logger.output.split('\n')
|
||||
|
||||
@ -356,3 +389,32 @@ class ClientTest(utils.TestCase):
|
||||
'"X-Auth-Token: {SHA1}b42162b6ffdbd7c3c37b7c95b7ba9f51dda0236d"'
|
||||
' -H "X-Foo: bar"',
|
||||
output)
|
||||
self.assertIn(
|
||||
"REQ: curl -i '/foo' -X GET -d "
|
||||
'\'{"auth": {"passwordCredentials": {"password":'
|
||||
' "{SHA1}4fc49c6a671ce889078ff6b250f7066cf6d2ada2"}}}\'',
|
||||
output)
|
||||
|
||||
def test_log_resp(self):
|
||||
self.logger = self.useFixture(
|
||||
fixtures.FakeLogger(
|
||||
format="%(message)s",
|
||||
level=logging.DEBUG,
|
||||
nuke_handlers=True
|
||||
)
|
||||
)
|
||||
|
||||
cs = novaclient.client.HTTPClient("user", None, "",
|
||||
connection_pool=True)
|
||||
cs.http_log_debug = True
|
||||
text = ('{"access": {"token": {"id": "zhaoqin"}}}')
|
||||
resp = utils.TestResponse({'status_code': 200, 'headers': {},
|
||||
'text': text})
|
||||
|
||||
cs.http_log_resp(resp)
|
||||
output = self.logger.output.split('\n')
|
||||
|
||||
self.assertIn('RESP: [200] {}', output)
|
||||
self.assertIn('RESP BODY: {"access": {"token": {"id":'
|
||||
' "{SHA1}4fc49c6a671ce889078ff6b250f7066cf6d2ada2"}}}',
|
||||
output)
|
||||
|
||||
@ -40,7 +40,7 @@ class DiscoverTest(utils.TestCase):
|
||||
def test():
|
||||
shell = novaclient.shell.OpenStackComputeShell()
|
||||
for name, module in shell._discover_via_entry_points():
|
||||
self.assertEqual(name, 'foo')
|
||||
self.assertEqual('foo', name)
|
||||
self.assertTrue(inspect.ismodule(module))
|
||||
|
||||
test()
|
||||
@ -68,7 +68,7 @@ class DiscoverTest(utils.TestCase):
|
||||
def test():
|
||||
shell = novaclient.shell.OpenStackComputeShell()
|
||||
extensions = shell._discover_extensions('1.1')
|
||||
self.assertEqual(len(extensions), 3)
|
||||
self.assertEqual(3, len(extensions))
|
||||
names = sorted(['foo', 'bar', 'baz'])
|
||||
sorted_extensions = sorted(extensions, key=lambda ext: ext.name)
|
||||
for i in range(len(names)):
|
||||
|
||||
@ -44,6 +44,32 @@ unknown_error_response = utils.TestResponse({
|
||||
})
|
||||
unknown_error_mock_request = mock.Mock(return_value=unknown_error_response)
|
||||
|
||||
retry_after_response = utils.TestResponse({
|
||||
"status_code": 413,
|
||||
"text": '',
|
||||
"headers": {
|
||||
"retry-after": "5"
|
||||
},
|
||||
})
|
||||
retry_after_mock_request = mock.Mock(return_value=retry_after_response)
|
||||
|
||||
retry_after_no_headers_response = utils.TestResponse({
|
||||
"status_code": 413,
|
||||
"text": '',
|
||||
})
|
||||
retry_after_no_headers_mock_request = mock.Mock(
|
||||
return_value=retry_after_no_headers_response)
|
||||
|
||||
retry_after_non_supporting_response = utils.TestResponse({
|
||||
"status_code": 403,
|
||||
"text": '',
|
||||
"headers": {
|
||||
"retry-after": "5"
|
||||
},
|
||||
})
|
||||
retry_after_non_supporting_mock_request = mock.Mock(
|
||||
return_value=retry_after_non_supporting_response)
|
||||
|
||||
|
||||
def get_client():
|
||||
cl = client.HTTPClient("username", "password",
|
||||
@ -79,7 +105,7 @@ class ClientTest(utils.TestCase):
|
||||
headers=headers,
|
||||
**self.TEST_REQUEST_BASE)
|
||||
# Automatic JSON parsing
|
||||
self.assertEqual(body, {"hi": "there"})
|
||||
self.assertEqual({"hi": "there"}, body)
|
||||
|
||||
test_get_call()
|
||||
|
||||
@ -136,11 +162,11 @@ class ClientTest(utils.TestCase):
|
||||
def test_client_logger(self):
|
||||
cl1 = client.HTTPClient("username", "password", "project_id",
|
||||
"auth_test", http_log_debug=True)
|
||||
self.assertEqual(len(cl1._logger.handlers), 1)
|
||||
self.assertEqual(1, len(cl1._logger.handlers))
|
||||
|
||||
cl2 = client.HTTPClient("username", "password", "project_id",
|
||||
"auth_test", http_log_debug=True)
|
||||
self.assertEqual(len(cl2._logger.handlers), 1)
|
||||
self.assertEqual(1, len(cl2._logger.handlers))
|
||||
|
||||
@mock.patch.object(requests, 'request', unknown_error_mock_request)
|
||||
def test_unknown_server_error(self):
|
||||
@ -154,3 +180,33 @@ class ClientTest(utils.TestCase):
|
||||
self.assertIn('Unknown Error', six.text_type(exc))
|
||||
else:
|
||||
self.fail('Expected exceptions.ClientException')
|
||||
|
||||
@mock.patch.object(requests, "request", retry_after_mock_request)
|
||||
def test_retry_after_request(self):
|
||||
cl = get_client()
|
||||
|
||||
try:
|
||||
cl.get("/hi")
|
||||
except exceptions.OverLimit as exc:
|
||||
self.assertEqual(5, exc.retry_after)
|
||||
else:
|
||||
self.fail('Expected exceptions.OverLimit')
|
||||
|
||||
@mock.patch.object(requests, "request",
|
||||
retry_after_no_headers_mock_request)
|
||||
def test_retry_after_request_no_headers(self):
|
||||
cl = get_client()
|
||||
|
||||
try:
|
||||
cl.get("/hi")
|
||||
except exceptions.OverLimit as exc:
|
||||
self.assertEqual(0, exc.retry_after)
|
||||
else:
|
||||
self.fail('Expected exceptions.OverLimit')
|
||||
|
||||
@mock.patch.object(requests, "request",
|
||||
retry_after_non_supporting_mock_request)
|
||||
def test_retry_after_request_non_supporting_exc(self):
|
||||
cl = get_client()
|
||||
|
||||
self.assertRaises(exceptions.Forbidden, cl.get, "/hi")
|
||||
|
||||
@ -11,116 +11,32 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from keystoneclient import fixture
|
||||
|
||||
from novaclient import exceptions
|
||||
from novaclient import service_catalog
|
||||
from novaclient.tests import utils
|
||||
|
||||
|
||||
# Taken directly from keystone/content/common/samples/auth.json
|
||||
# Do not edit this structure. Instead, grab the latest from there.
|
||||
SERVICE_CATALOG = fixture.V2Token()
|
||||
SERVICE_CATALOG.set_scope()
|
||||
|
||||
SERVICE_CATALOG = {
|
||||
"access": {
|
||||
"token": {
|
||||
"id": "ab48a9efdfedb23ty3494",
|
||||
"expires": "2010-11-01T03:32:15-05:00",
|
||||
"tenant": {
|
||||
"id": "345",
|
||||
"name": "My Project"
|
||||
}
|
||||
},
|
||||
"user": {
|
||||
"id": "123",
|
||||
"name": "jqsmith",
|
||||
"roles": [
|
||||
{
|
||||
"id": "234",
|
||||
"name": "compute:admin",
|
||||
},
|
||||
{
|
||||
"id": "235",
|
||||
"name": "object-store:admin",
|
||||
"tenantId": "1",
|
||||
}
|
||||
],
|
||||
"roles_links": [],
|
||||
},
|
||||
"serviceCatalog": [
|
||||
{
|
||||
"name": "Cloud Servers",
|
||||
"type": "compute",
|
||||
"endpoints": [
|
||||
{
|
||||
# Tenant 1, no region, v1.0
|
||||
"tenantId": "1",
|
||||
"publicURL": "https://compute1.host/v1/1",
|
||||
"internalURL": "https://compute1.host/v1/1",
|
||||
"versionId": "1.0",
|
||||
"versionInfo": "https://compute1.host/v1.0/",
|
||||
"versionList": "https://compute1.host/"
|
||||
},
|
||||
{
|
||||
# Tenant 2, with region, v1.1
|
||||
"tenantId": "2",
|
||||
"publicURL": "https://compute1.host/v1.1/2",
|
||||
"internalURL": "https://compute1.host/v1.1/2",
|
||||
"region": "North",
|
||||
"versionId": "1.1",
|
||||
"versionInfo": "https://compute1.host/v1.1/",
|
||||
"versionList": "https://compute1.host/"
|
||||
},
|
||||
{
|
||||
# Tenant 1, with region, v2.0
|
||||
"tenantId": "1",
|
||||
"publicURL": "https://compute1.host/v2/1",
|
||||
"internalURL": "https://compute1.host/v2/1",
|
||||
"region": "North",
|
||||
"versionId": "2",
|
||||
"versionInfo": "https://compute1.host/v2/",
|
||||
"versionList": "https://compute1.host/"
|
||||
},
|
||||
],
|
||||
"endpoints_links": [],
|
||||
},
|
||||
{
|
||||
"name": "Nova Volumes",
|
||||
"type": "volume",
|
||||
"endpoints": [
|
||||
{
|
||||
"tenantId": "1",
|
||||
"publicURL": "https://volume1.host/v1/1",
|
||||
"internalURL": "https://volume1.host/v1/1",
|
||||
"region": "South",
|
||||
"versionId": "1.0",
|
||||
"versionInfo": "uri",
|
||||
"versionList": "uri"
|
||||
},
|
||||
{
|
||||
"tenantId": "2",
|
||||
"publicURL": "https://volume1.host/v1.1/2",
|
||||
"internalURL": "https://volume1.host/v1.1/2",
|
||||
"region": "South",
|
||||
"versionId": "1.1",
|
||||
"versionInfo": "https://volume1.host/v1.1/",
|
||||
"versionList": "https://volume1.host/"
|
||||
},
|
||||
],
|
||||
"endpoints_links": [
|
||||
{
|
||||
"rel": "next",
|
||||
"href": "https://identity1.host/v2.0/endpoints"
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
"serviceCatalog_links": [
|
||||
{
|
||||
"rel": "next",
|
||||
"href": "https://identity.host/v2.0/endpoints?session=2hfh8Ar",
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
_s = SERVICE_CATALOG.add_service('compute')
|
||||
_e = _s.add_endpoint("https://compute1.host/v1/1")
|
||||
_e["tenantId"] = "1"
|
||||
_e["versionId"] = "1.0"
|
||||
_e = _s.add_endpoint("https://compute1.host/v1.1/2", region="North")
|
||||
_e["tenantId"] = "2"
|
||||
_e["versionId"] = "1.1"
|
||||
_e = _s.add_endpoint("https://compute1.host/v2/1", region="North")
|
||||
_e["tenantId"] = "1"
|
||||
_e["versionId"] = "2"
|
||||
|
||||
_s = SERVICE_CATALOG.add_service('volume')
|
||||
_e = _s.add_endpoint("https://volume1.host/v1/1", region="South")
|
||||
_e["tenantId"] = "1"
|
||||
_e = _s.add_endpoint("https://volume1.host/v1.1/2", region="South")
|
||||
_e["tenantId"] = "2"
|
||||
|
||||
|
||||
class ServiceCatalogTest(utils.TestCase):
|
||||
@ -129,10 +45,10 @@ class ServiceCatalogTest(utils.TestCase):
|
||||
|
||||
self.assertRaises(exceptions.AmbiguousEndpoints, sc.url_for,
|
||||
service_type='compute')
|
||||
self.assertEqual(sc.url_for('tenantId', '1', service_type='compute'),
|
||||
"https://compute1.host/v2/1")
|
||||
self.assertEqual(sc.url_for('tenantId', '2', service_type='compute'),
|
||||
"https://compute1.host/v1.1/2")
|
||||
self.assertEqual("https://compute1.host/v2/1",
|
||||
sc.url_for('tenantId', '1', service_type='compute'))
|
||||
self.assertEqual("https://compute1.host/v1.1/2",
|
||||
sc.url_for('tenantId', '2', service_type='compute'))
|
||||
|
||||
self.assertRaises(exceptions.EndpointNotFound, sc.url_for,
|
||||
"region", "South", service_type='compute')
|
||||
@ -148,10 +64,10 @@ class ServiceCatalogTest(utils.TestCase):
|
||||
|
||||
self.assertRaises(exceptions.AmbiguousEndpoints, sc.url_for,
|
||||
service_type='volume')
|
||||
self.assertEqual(sc.url_for('tenantId', '1', service_type='volume'),
|
||||
"https://volume1.host/v1/1")
|
||||
self.assertEqual(sc.url_for('tenantId', '2', service_type='volume'),
|
||||
"https://volume1.host/v1.1/2")
|
||||
self.assertEqual("https://volume1.host/v1/1",
|
||||
sc.url_for('tenantId', '1', service_type='volume'))
|
||||
self.assertEqual("https://volume1.host/v1.1/2",
|
||||
sc.url_for('tenantId', '2', service_type='volume'))
|
||||
|
||||
self.assertRaises(exceptions.EndpointNotFound, sc.url_for,
|
||||
"region", "North", service_type='volume')
|
||||
|
||||
@ -11,15 +11,14 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import prettytable
|
||||
import distutils.version as dist_version
|
||||
import re
|
||||
import six
|
||||
import sys
|
||||
|
||||
from distutils.version import StrictVersion
|
||||
|
||||
import fixtures
|
||||
import mock
|
||||
import prettytable
|
||||
import six
|
||||
from testtools import matchers
|
||||
|
||||
import novaclient.client
|
||||
@ -201,7 +200,8 @@ class ShellTest(utils.TestCase):
|
||||
# default output of empty tables differs depending between prettytable
|
||||
# versions
|
||||
if (hasattr(prettytable, '__version__') and
|
||||
StrictVersion(prettytable.__version__) < StrictVersion('0.7.2')):
|
||||
dist_version.StrictVersion(prettytable.__version__) <
|
||||
dist_version.StrictVersion('0.7.2')):
|
||||
ex = '\n'
|
||||
else:
|
||||
ex = (
|
||||
@ -232,7 +232,8 @@ class ShellTest(utils.TestCase):
|
||||
if version is None:
|
||||
cmd = 'list'
|
||||
else:
|
||||
cmd = '--os-compute-api-version %s list' % version
|
||||
cmd = ('--service_type %s --os-compute-api-version %s list' %
|
||||
(service_type, version))
|
||||
self.make_env()
|
||||
self.shell(cmd)
|
||||
_, client_kwargs = mock_client.call_args_list[0]
|
||||
|
||||
@ -140,26 +140,26 @@ class PrintResultTestCase(test_utils.TestCase):
|
||||
def test_print_dict(self):
|
||||
dict = {'key': 'value'}
|
||||
utils.print_dict(dict)
|
||||
self.assertEqual(sys.stdout.getvalue(),
|
||||
'+----------+-------+\n'
|
||||
self.assertEqual('+----------+-------+\n'
|
||||
'| Property | Value |\n'
|
||||
'+----------+-------+\n'
|
||||
'| key | value |\n'
|
||||
'+----------+-------+\n')
|
||||
'+----------+-------+\n',
|
||||
sys.stdout.getvalue())
|
||||
|
||||
@mock.patch('sys.stdout', six.StringIO())
|
||||
def test_print_dict_wrap(self):
|
||||
dict = {'key1': 'not wrapped',
|
||||
'key2': 'this will be wrapped'}
|
||||
utils.print_dict(dict, wrap=16)
|
||||
self.assertEqual(sys.stdout.getvalue(),
|
||||
'+----------+--------------+\n'
|
||||
self.assertEqual('+----------+--------------+\n'
|
||||
'| Property | Value |\n'
|
||||
'+----------+--------------+\n'
|
||||
'| key1 | not wrapped |\n'
|
||||
'| key2 | this will be |\n'
|
||||
'| | wrapped |\n'
|
||||
'+----------+--------------+\n')
|
||||
'+----------+--------------+\n',
|
||||
sys.stdout.getvalue())
|
||||
|
||||
@mock.patch('sys.stdout', six.StringIO())
|
||||
def test_print_list_sort_by_str(self):
|
||||
@ -169,14 +169,14 @@ class PrintResultTestCase(test_utils.TestCase):
|
||||
|
||||
utils.print_list(objs, ["Name", "Value"], sortby_index=0)
|
||||
|
||||
self.assertEqual(sys.stdout.getvalue(),
|
||||
'+------+-------+\n'
|
||||
self.assertEqual('+------+-------+\n'
|
||||
'| Name | Value |\n'
|
||||
'+------+-------+\n'
|
||||
'| k1 | 1 |\n'
|
||||
'| k2 | 3 |\n'
|
||||
'| k3 | 2 |\n'
|
||||
'+------+-------+\n')
|
||||
'+------+-------+\n',
|
||||
sys.stdout.getvalue())
|
||||
|
||||
@mock.patch('sys.stdout', six.StringIO())
|
||||
def test_print_list_sort_by_integer(self):
|
||||
@ -186,14 +186,14 @@ class PrintResultTestCase(test_utils.TestCase):
|
||||
|
||||
utils.print_list(objs, ["Name", "Value"], sortby_index=1)
|
||||
|
||||
self.assertEqual(sys.stdout.getvalue(),
|
||||
'+------+-------+\n'
|
||||
self.assertEqual('+------+-------+\n'
|
||||
'| Name | Value |\n'
|
||||
'+------+-------+\n'
|
||||
'| k1 | 1 |\n'
|
||||
'| k3 | 2 |\n'
|
||||
'| k2 | 3 |\n'
|
||||
'+------+-------+\n')
|
||||
'+------+-------+\n',
|
||||
sys.stdout.getvalue())
|
||||
|
||||
# without sorting
|
||||
@mock.patch('sys.stdout', six.StringIO())
|
||||
@ -204,47 +204,47 @@ class PrintResultTestCase(test_utils.TestCase):
|
||||
|
||||
utils.print_list(objs, ["Name", "Value"], sortby_index=None)
|
||||
|
||||
self.assertEqual(sys.stdout.getvalue(),
|
||||
'+------+-------+\n'
|
||||
self.assertEqual('+------+-------+\n'
|
||||
'| Name | Value |\n'
|
||||
'+------+-------+\n'
|
||||
'| k1 | 1 |\n'
|
||||
'| k3 | 3 |\n'
|
||||
'| k2 | 2 |\n'
|
||||
'+------+-------+\n')
|
||||
'+------+-------+\n',
|
||||
sys.stdout.getvalue())
|
||||
|
||||
@mock.patch('sys.stdout', six.StringIO())
|
||||
def test_print_dict_dictionary(self):
|
||||
dict = {'k': {'foo': 'bar'}}
|
||||
utils.print_dict(dict)
|
||||
self.assertEqual(sys.stdout.getvalue(),
|
||||
'+----------+----------------+\n'
|
||||
self.assertEqual('+----------+----------------+\n'
|
||||
'| Property | Value |\n'
|
||||
'+----------+----------------+\n'
|
||||
'| k | {"foo": "bar"} |\n'
|
||||
'+----------+----------------+\n')
|
||||
'+----------+----------------+\n',
|
||||
sys.stdout.getvalue())
|
||||
|
||||
@mock.patch('sys.stdout', six.StringIO())
|
||||
def test_print_dict_list_dictionary(self):
|
||||
dict = {'k': [{'foo': 'bar'}]}
|
||||
utils.print_dict(dict)
|
||||
self.assertEqual(sys.stdout.getvalue(),
|
||||
'+----------+------------------+\n'
|
||||
self.assertEqual('+----------+------------------+\n'
|
||||
'| Property | Value |\n'
|
||||
'+----------+------------------+\n'
|
||||
'| k | [{"foo": "bar"}] |\n'
|
||||
'+----------+------------------+\n')
|
||||
'+----------+------------------+\n',
|
||||
sys.stdout.getvalue())
|
||||
|
||||
@mock.patch('sys.stdout', six.StringIO())
|
||||
def test_print_dict_list(self):
|
||||
dict = {'k': ['foo', 'bar']}
|
||||
utils.print_dict(dict)
|
||||
self.assertEqual(sys.stdout.getvalue(),
|
||||
'+----------+----------------+\n'
|
||||
self.assertEqual('+----------+----------------+\n'
|
||||
'| Property | Value |\n'
|
||||
'+----------+----------------+\n'
|
||||
'| k | ["foo", "bar"] |\n'
|
||||
'+----------+----------------+\n')
|
||||
'+----------+----------------+\n',
|
||||
sys.stdout.getvalue())
|
||||
|
||||
|
||||
class FlattenTestCase(test_utils.TestCase):
|
||||
@ -270,22 +270,22 @@ class FlattenTestCase(test_utils.TestCase):
|
||||
def test_pretty_choice_list(self):
|
||||
l = []
|
||||
r = utils.pretty_choice_list(l)
|
||||
self.assertEqual(r, "")
|
||||
self.assertEqual("", r)
|
||||
|
||||
l = ["v1", "v2", "v3"]
|
||||
r = utils.pretty_choice_list(l)
|
||||
self.assertEqual(r, "'v1', 'v2', 'v3'")
|
||||
self.assertEqual("'v1', 'v2', 'v3'", r)
|
||||
|
||||
def test_pretty_choice_dict(self):
|
||||
d = {}
|
||||
r = utils.pretty_choice_dict(d)
|
||||
self.assertEqual(r, "")
|
||||
self.assertEqual("", r)
|
||||
|
||||
d = {"k1": "v1",
|
||||
"k2": "v2",
|
||||
"k3": "v3"}
|
||||
r = utils.pretty_choice_dict(d)
|
||||
self.assertEqual(r, "'k1=v1', 'k2=v2', 'k3=v3'")
|
||||
self.assertEqual("'k1=v1', 'k2=v2', 'k3=v3'", r)
|
||||
|
||||
|
||||
class ValidationsTestCase(test_utils.TestCase):
|
||||
|
||||
@ -67,6 +67,25 @@ class V1(base.Fixture):
|
||||
json={'image': image_1},
|
||||
headers=headers)
|
||||
|
||||
self.requests.register_uri('GET', self.url(2),
|
||||
json={'image': image_2},
|
||||
headers=headers)
|
||||
|
||||
self.requests.register_uri('GET', self.url(456),
|
||||
json={'image': image_2},
|
||||
headers=headers)
|
||||
|
||||
def post_images(request, context):
|
||||
body = jsonutils.loads(request.body)
|
||||
assert list(body) == ['image']
|
||||
fakes.assert_has_keys(body['image'], required=['serverId', 'name'])
|
||||
return images_1
|
||||
|
||||
self.requests.register_uri('POST', self.url(),
|
||||
json=post_images,
|
||||
headers=headers,
|
||||
status_code=202)
|
||||
|
||||
def post_images_1_metadata(request, context):
|
||||
body = jsonutils.loads(request.body)
|
||||
assert list(body) == ['metadata']
|
||||
@ -77,9 +96,17 @@ class V1(base.Fixture):
|
||||
json=post_images_1_metadata,
|
||||
headers=headers)
|
||||
|
||||
for u in (1, '1/metadata/test_key'):
|
||||
for u in (1, 2, '1/metadata/test_key'):
|
||||
self.requests.register_uri('DELETE', self.url(u), status_code=204)
|
||||
|
||||
image_headers = {'x-image-meta-id': '1',
|
||||
'x-image-meta-name': 'CentOS 5.2',
|
||||
'x-image-meta-updated': '2010-10-10T12:00:00Z',
|
||||
'x-image-meta-created': '2010-10-10T12:00:00Z',
|
||||
'x-image-meta-status': 'ACTIVE',
|
||||
'x-image-meta-property-test-key': 'test_value'}
|
||||
self.requests.register_uri('HEAD', self.url(1), headers=image_headers)
|
||||
|
||||
|
||||
class V3(V1):
|
||||
|
||||
|
||||
@ -14,7 +14,6 @@ from oslo.serialization import jsonutils
|
||||
|
||||
from novaclient.tests.unit import fakes
|
||||
from novaclient.tests.unit.fixture_data import base
|
||||
from novaclient.tests.unit.v2 import fakes as v2_fakes
|
||||
|
||||
|
||||
class Base(base.Fixture):
|
||||
@ -383,24 +382,43 @@ class V1(Base):
|
||||
context.status_code = 202
|
||||
assert len(body.keys()) == 1
|
||||
action = list(body)[0]
|
||||
|
||||
if v2_fakes.FakeHTTPClient.check_server_actions(body):
|
||||
# NOTE(snikitin): No need to do any operations here. This 'pass'
|
||||
# is needed to avoid AssertionError in the last 'else' statement
|
||||
# if we found 'action' in method check_server_actions and
|
||||
# raise AssertionError if we didn't find 'action' at all.
|
||||
pass
|
||||
if action == 'reboot':
|
||||
assert list(body[action]) == ['type']
|
||||
assert body[action]['type'] in ['HARD', 'SOFT']
|
||||
elif action == 'rebuild':
|
||||
body = body[action]
|
||||
adminPass = body.get('adminPass', 'randompassword')
|
||||
assert 'imageRef' in body
|
||||
_body = self.server_1234.copy()
|
||||
_body['adminPass'] = adminPass
|
||||
elif action == 'resize':
|
||||
keys = body[action].keys()
|
||||
assert 'flavorRef' in keys
|
||||
elif action == 'confirmResize':
|
||||
assert body[action] is None
|
||||
# This one method returns a different response code
|
||||
context.status_code = 204
|
||||
return None
|
||||
elif action == 'revertResize':
|
||||
assert body[action] is None
|
||||
elif action == 'migrate':
|
||||
assert body[action] is None
|
||||
elif action == 'os-stop':
|
||||
assert body[action] is None
|
||||
elif action == 'os-start':
|
||||
assert body[action] is None
|
||||
elif action == 'forceDelete':
|
||||
assert body[action] is None
|
||||
elif action == 'restore':
|
||||
assert body[action] is None
|
||||
elif action == 'pause':
|
||||
assert body[action] is None
|
||||
elif action == 'unpause':
|
||||
assert body[action] is None
|
||||
elif action == 'lock':
|
||||
assert body[action] is None
|
||||
elif action == 'unlock':
|
||||
assert body[action] is None
|
||||
elif action == 'rescue':
|
||||
if body[action]:
|
||||
keys = set(body[action].keys())
|
||||
@ -408,15 +426,65 @@ class V1(Base):
|
||||
else:
|
||||
assert body[action] is None
|
||||
_body = {'adminPass': 'RescuePassword'}
|
||||
elif action == 'unrescue':
|
||||
assert body[action] is None
|
||||
elif action == 'resume':
|
||||
assert body[action] is None
|
||||
elif action == 'suspend':
|
||||
assert body[action] is None
|
||||
elif action == 'lock':
|
||||
assert body[action] is None
|
||||
elif action == 'unlock':
|
||||
assert body[action] is None
|
||||
elif action == 'shelve':
|
||||
assert body[action] is None
|
||||
elif action == 'shelveOffload':
|
||||
assert body[action] is None
|
||||
elif action == 'unshelve':
|
||||
assert body[action] is None
|
||||
elif action == 'addFixedIp':
|
||||
assert list(body[action]) == ['networkId']
|
||||
elif action == 'removeFixedIp':
|
||||
assert list(body[action]) == ['address']
|
||||
elif action == 'addFloatingIp':
|
||||
assert (list(body[action]) == ['address'] or
|
||||
sorted(list(body[action])) == ['address',
|
||||
'fixed_address'])
|
||||
elif action == 'removeFloatingIp':
|
||||
assert list(body[action]) == ['address']
|
||||
elif action == 'createImage':
|
||||
assert set(body[action].keys()) == set(['name', 'metadata'])
|
||||
context.headers['location'] = "http://blah/images/456"
|
||||
elif action == 'changePassword':
|
||||
assert list(body[action]) == ['adminPass']
|
||||
elif action == 'os-getConsoleOutput':
|
||||
assert list(body[action]) == ['length']
|
||||
context.status_code = 202
|
||||
return {'output': 'foo'}
|
||||
elif action == 'os-getVNCConsole':
|
||||
assert list(body[action]) == ['type']
|
||||
elif action == 'os-getSPICEConsole':
|
||||
assert list(body[action]) == ['type']
|
||||
elif action == 'os-getRDPConsole':
|
||||
assert list(body[action]) == ['type']
|
||||
elif action == 'os-getSerialConsole':
|
||||
assert list(body[action]) == ['type']
|
||||
elif action == 'os-migrateLive':
|
||||
assert set(body[action].keys()) == set(['host',
|
||||
'block_migration',
|
||||
'disk_over_commit'])
|
||||
elif action == 'os-resetState':
|
||||
assert list(body[action]) == ['state']
|
||||
elif action == 'resetNetwork':
|
||||
assert body[action] is None
|
||||
elif action == 'addSecurityGroup':
|
||||
assert list(body[action]) == ['name']
|
||||
elif action == 'removeSecurityGroup':
|
||||
assert list(body[action]) == ['name']
|
||||
elif action == 'createBackup':
|
||||
assert set(body[action]) == set(['name',
|
||||
'backup_type',
|
||||
'rotation'])
|
||||
elif action == 'evacuate':
|
||||
keys = list(body[action])
|
||||
if 'adminPass' in keys:
|
||||
|
||||
@ -36,7 +36,7 @@ class BaseTest(utils.TestCase):
|
||||
|
||||
def test_resource_lazy_getattr(self):
|
||||
f = flavors.Flavor(cs.flavors, {'id': 1})
|
||||
self.assertEqual('256 mb server', f.name)
|
||||
self.assertEqual('256 MB Server', f.name)
|
||||
cs.assert_called('GET', '/flavors/1')
|
||||
|
||||
# Missing stuff still fails after a second get
|
||||
|
||||
@ -16,7 +16,6 @@
|
||||
|
||||
import json
|
||||
import logging
|
||||
import socket
|
||||
|
||||
import fixtures
|
||||
import mock
|
||||
@ -28,24 +27,6 @@ from novaclient.tests.unit import utils
|
||||
import novaclient.v2.client
|
||||
|
||||
|
||||
class TCPKeepAliveAdapterTest(utils.TestCase):
|
||||
|
||||
@mock.patch.object(requests.adapters.HTTPAdapter, 'init_poolmanager')
|
||||
def test_init_poolmanager(self, mock_init_poolmgr):
|
||||
adapter = novaclient.client.TCPKeepAliveAdapter()
|
||||
kwargs = {}
|
||||
adapter.init_poolmanager(**kwargs)
|
||||
if requests.__version__ >= '2.4.1':
|
||||
kwargs.setdefault('socket_options', [
|
||||
(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1),
|
||||
(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1),
|
||||
])
|
||||
# NOTE(melwitt): This is called twice because
|
||||
# HTTPAdapter.__init__ calls it first.
|
||||
self.assertEqual(2, mock_init_poolmgr.call_count)
|
||||
mock_init_poolmgr.assert_called_with(**kwargs)
|
||||
|
||||
|
||||
class ClientConnectionPoolTest(utils.TestCase):
|
||||
|
||||
@mock.patch("novaclient.client.TCPKeepAliveAdapter")
|
||||
@ -86,7 +67,6 @@ class ClientTest(utils.TestCase):
|
||||
auth_url="http://www.blah.com")
|
||||
instance.auth_token = 'foobar'
|
||||
instance.management_url = 'http://example.com'
|
||||
instance.get_service_url = mock.Mock(return_value='http://example.com')
|
||||
instance.version = 'v2.0'
|
||||
mock_request = mock.Mock()
|
||||
mock_request.side_effect = novaclient.exceptions.Unauthorized(401)
|
||||
@ -137,8 +117,6 @@ class ClientTest(utils.TestCase):
|
||||
auth_url="http://www.blah.com")
|
||||
instance.auth_token = 'foobar'
|
||||
instance.management_url = management_url % projectid
|
||||
mock_get_service_url = mock.Mock(return_value=instance.management_url)
|
||||
instance.get_service_url = mock_get_service_url
|
||||
instance.version = 'v2.0'
|
||||
|
||||
# If passing None as the part of url, a client accesses the url which
|
||||
@ -183,26 +161,26 @@ class ClientTest(utils.TestCase):
|
||||
def test_client_with_os_cache_enabled(self):
|
||||
cs = novaclient.v2.client.Client("user", "password", "project_id",
|
||||
auth_url="foo/v2", os_cache=True)
|
||||
self.assertTrue(cs.os_cache)
|
||||
self.assertTrue(cs.client.os_cache)
|
||||
self.assertEqual(True, cs.os_cache)
|
||||
self.assertEqual(True, cs.client.os_cache)
|
||||
|
||||
def test_client_with_os_cache_disabled(self):
|
||||
cs = novaclient.v2.client.Client("user", "password", "project_id",
|
||||
auth_url="foo/v2", os_cache=False)
|
||||
self.assertFalse(cs.os_cache)
|
||||
self.assertFalse(cs.client.os_cache)
|
||||
self.assertEqual(False, cs.os_cache)
|
||||
self.assertEqual(False, cs.client.os_cache)
|
||||
|
||||
def test_client_with_no_cache_enabled(self):
|
||||
cs = novaclient.v2.client.Client("user", "password", "project_id",
|
||||
auth_url="foo/v2", no_cache=True)
|
||||
self.assertFalse(cs.os_cache)
|
||||
self.assertFalse(cs.client.os_cache)
|
||||
self.assertEqual(False, cs.os_cache)
|
||||
self.assertEqual(False, cs.client.os_cache)
|
||||
|
||||
def test_client_with_no_cache_disabled(self):
|
||||
cs = novaclient.v2.client.Client("user", "password", "project_id",
|
||||
auth_url="foo/v2", no_cache=False)
|
||||
self.assertTrue(cs.os_cache)
|
||||
self.assertTrue(cs.client.os_cache)
|
||||
self.assertEqual(True, cs.os_cache)
|
||||
self.assertEqual(True, cs.client.os_cache)
|
||||
|
||||
def test_client_set_management_url_v1_1(self):
|
||||
cs = novaclient.v2.client.Client("user", "password", "project_id",
|
||||
|
||||
@ -82,7 +82,6 @@ def get_authed_client():
|
||||
cl = get_client()
|
||||
cl.management_url = "http://example.com"
|
||||
cl.auth_token = "token"
|
||||
cl.get_service_url = mock.Mock(return_value="http://example.com")
|
||||
return cl
|
||||
|
||||
|
||||
|
||||
@ -311,7 +311,7 @@ class ValidationsTestCase(test_utils.TestCase):
|
||||
utils.validate_flavor_metadata_keys([key])
|
||||
self.fail("Invalid key passed validation: %s" % key)
|
||||
except exceptions.CommandError as ce:
|
||||
self.assertIn(key, str(ce))
|
||||
self.assertTrue(key in str(ce))
|
||||
|
||||
|
||||
class ResourceManagerExtraKwargsHookTestCase(test_utils.TestCase):
|
||||
|
||||
@ -258,7 +258,7 @@ class FakeHTTPClient(base_client.HTTPClient):
|
||||
},
|
||||
"flavor": {
|
||||
"id": 1,
|
||||
"name": "256 mb server",
|
||||
"name": "256 MB Server",
|
||||
},
|
||||
"hostId": "e4d909c290d0fb1ca068ffaddf22cbd0",
|
||||
"status": "BUILD",
|
||||
@ -299,7 +299,7 @@ class FakeHTTPClient(base_client.HTTPClient):
|
||||
},
|
||||
"flavor": {
|
||||
"id": 1,
|
||||
"name": "256 mb server",
|
||||
"name": "256 MB Server",
|
||||
},
|
||||
"hostId": "9e107d9d372bb6826bd81d3542a419d6",
|
||||
"status": "ACTIVE",
|
||||
@ -340,7 +340,7 @@ class FakeHTTPClient(base_client.HTTPClient):
|
||||
"image": "",
|
||||
"flavor": {
|
||||
"id": 1,
|
||||
"name": "256 mb server",
|
||||
"name": "256 MB Server",
|
||||
},
|
||||
"hostId": "9e107d9d372bb6826bd81d3542a419d6",
|
||||
"status": "ACTIVE",
|
||||
@ -542,73 +542,48 @@ class FakeHTTPClient(base_client.HTTPClient):
|
||||
# Server actions
|
||||
#
|
||||
|
||||
none_actions = ['revertResize', 'migrate', 'os-stop', 'os-start',
|
||||
'forceDelete', 'restore', 'pause', 'unpause', 'unlock',
|
||||
'unrescue', 'resume', 'suspend', 'lock', 'shelve',
|
||||
'shelveOffload', 'unshelve', 'resetNetwork']
|
||||
type_actions = ['os-getVNCConsole', 'os-getSPICEConsole',
|
||||
'os-getRDPConsole']
|
||||
|
||||
@classmethod
|
||||
def check_server_actions(cls, body):
|
||||
action = list(body)[0]
|
||||
if action == 'reboot':
|
||||
assert list(body[action]) == ['type']
|
||||
assert body[action]['type'] in ['HARD', 'SOFT']
|
||||
elif action == 'resize':
|
||||
assert 'flavorRef' in body[action]
|
||||
elif action in cls.none_actions:
|
||||
assert body[action] is None
|
||||
elif action == 'addFixedIp':
|
||||
assert list(body[action]) == ['networkId']
|
||||
elif action in ['removeFixedIp', 'removeFloatingIp']:
|
||||
assert list(body[action]) == ['address']
|
||||
elif action == 'addFloatingIp':
|
||||
assert (list(body[action]) == ['address'] or
|
||||
sorted(list(body[action])) == ['address', 'fixed_address'])
|
||||
elif action == 'changePassword':
|
||||
assert list(body[action]) == ['adminPass']
|
||||
elif action in cls.type_actions:
|
||||
assert list(body[action]) == ['type']
|
||||
elif action == 'os-migrateLive':
|
||||
assert set(body[action].keys()) == set(['host', 'block_migration',
|
||||
'disk_over_commit'])
|
||||
elif action == 'os-resetState':
|
||||
assert list(body[action]) == ['state']
|
||||
elif action == 'resetNetwork':
|
||||
assert body[action] is None
|
||||
elif action in ['addSecurityGroup', 'removeSecurityGroup']:
|
||||
assert list(body[action]) == ['name']
|
||||
elif action == 'createBackup':
|
||||
assert set(body[action]) == set(['name', 'backup_type',
|
||||
'rotation'])
|
||||
else:
|
||||
return False
|
||||
return True
|
||||
|
||||
def post_servers_1234_action(self, body, **kw):
|
||||
_headers = None
|
||||
_body = None
|
||||
resp = 202
|
||||
assert len(body.keys()) == 1
|
||||
action = list(body)[0]
|
||||
|
||||
if self.check_server_actions(body):
|
||||
# NOTE(snikitin): No need to do any operations here. This 'pass'
|
||||
# is needed to avoid AssertionError in the last 'else' statement
|
||||
# if we found 'action' in method check_server_actions and
|
||||
# raise AssertionError if we didn't find 'action' at all.
|
||||
pass
|
||||
if action == 'reboot':
|
||||
assert list(body[action]) == ['type']
|
||||
assert body[action]['type'] in ['HARD', 'SOFT']
|
||||
elif action == 'rebuild':
|
||||
body = body[action]
|
||||
adminPass = body.get('adminPass', 'randompassword')
|
||||
assert 'imageRef' in body
|
||||
_body = self.get_servers_1234()[2]
|
||||
_body['server']['adminPass'] = adminPass
|
||||
elif action == 'resize':
|
||||
keys = body[action].keys()
|
||||
assert 'flavorRef' in keys
|
||||
elif action == 'confirmResize':
|
||||
assert body[action] is None
|
||||
# This one method returns a different response code
|
||||
return (204, {}, None)
|
||||
elif action == 'revertResize':
|
||||
assert body[action] is None
|
||||
elif action == 'migrate':
|
||||
assert body[action] is None
|
||||
elif action == 'os-stop':
|
||||
assert body[action] is None
|
||||
elif action == 'os-start':
|
||||
assert body[action] is None
|
||||
elif action == 'forceDelete':
|
||||
assert body[action] is None
|
||||
elif action == 'restore':
|
||||
assert body[action] is None
|
||||
elif action == 'pause':
|
||||
assert body[action] is None
|
||||
elif action == 'unpause':
|
||||
assert body[action] is None
|
||||
elif action == 'lock':
|
||||
assert body[action] is None
|
||||
elif action == 'unlock':
|
||||
assert body[action] is None
|
||||
elif action == 'rescue':
|
||||
if body[action]:
|
||||
keys = set(body[action].keys())
|
||||
@ -616,12 +591,62 @@ class FakeHTTPClient(base_client.HTTPClient):
|
||||
else:
|
||||
assert body[action] is None
|
||||
_body = {'adminPass': 'RescuePassword'}
|
||||
elif action == 'unrescue':
|
||||
assert body[action] is None
|
||||
elif action == 'resume':
|
||||
assert body[action] is None
|
||||
elif action == 'suspend':
|
||||
assert body[action] is None
|
||||
elif action == 'lock':
|
||||
assert body[action] is None
|
||||
elif action == 'unlock':
|
||||
assert body[action] is None
|
||||
elif action == 'shelve':
|
||||
assert body[action] is None
|
||||
elif action == 'shelveOffload':
|
||||
assert body[action] is None
|
||||
elif action == 'unshelve':
|
||||
assert body[action] is None
|
||||
elif action == 'addFixedIp':
|
||||
assert list(body[action]) == ['networkId']
|
||||
elif action == 'removeFixedIp':
|
||||
assert list(body[action]) == ['address']
|
||||
elif action == 'addFloatingIp':
|
||||
assert (list(body[action]) == ['address'] or
|
||||
sorted(list(body[action])) == ['address',
|
||||
'fixed_address'])
|
||||
elif action == 'removeFloatingIp':
|
||||
assert list(body[action]) == ['address']
|
||||
elif action == 'createImage':
|
||||
assert set(body[action].keys()) == set(['name', 'metadata'])
|
||||
_headers = dict(location="http://blah/images/456")
|
||||
elif action == 'changePassword':
|
||||
assert list(body[action]) == ['adminPass']
|
||||
elif action == 'os-getConsoleOutput':
|
||||
assert list(body[action]) == ['length']
|
||||
return (202, {}, {'output': 'foo'})
|
||||
elif action == 'os-getVNCConsole':
|
||||
assert list(body[action]) == ['type']
|
||||
elif action == 'os-getSPICEConsole':
|
||||
assert list(body[action]) == ['type']
|
||||
elif action == 'os-getRDPConsole':
|
||||
assert list(body[action]) == ['type']
|
||||
elif action == 'os-migrateLive':
|
||||
assert set(body[action].keys()) == set(['host',
|
||||
'block_migration',
|
||||
'disk_over_commit'])
|
||||
elif action == 'os-resetState':
|
||||
assert list(body[action]) == ['state']
|
||||
elif action == 'resetNetwork':
|
||||
assert body[action] is None
|
||||
elif action == 'addSecurityGroup':
|
||||
assert list(body[action]) == ['name']
|
||||
elif action == 'removeSecurityGroup':
|
||||
assert list(body[action]) == ['name']
|
||||
elif action == 'createBackup':
|
||||
assert set(body[action]) == set(['name',
|
||||
'backup_type',
|
||||
'rotation'])
|
||||
elif action == 'evacuate':
|
||||
keys = list(body[action])
|
||||
if 'adminPass' in keys:
|
||||
@ -672,19 +697,19 @@ class FakeHTTPClient(base_client.HTTPClient):
|
||||
|
||||
def get_flavors_detail(self, **kw):
|
||||
flavors = {'flavors': [
|
||||
{'id': 1, 'name': '256 mb server', 'ram': 256, 'disk': 10,
|
||||
{'id': 1, 'name': '256 MB Server', 'ram': 256, 'disk': 10,
|
||||
'OS-FLV-EXT-DATA:ephemeral': 10,
|
||||
'os-flavor-access:is_public': True,
|
||||
'links': {}},
|
||||
{'id': 2, 'name': '512 mb server', 'ram': 512, 'disk': 20,
|
||||
{'id': 2, 'name': '512 MB Server', 'ram': 512, 'disk': 20,
|
||||
'OS-FLV-EXT-DATA:ephemeral': 20,
|
||||
'os-flavor-access:is_public': False,
|
||||
'links': {}},
|
||||
{'id': 4, 'name': '1024 mb server', 'ram': 1024, 'disk': 10,
|
||||
{'id': 4, 'name': '1024 MB Server', 'ram': 1024, 'disk': 10,
|
||||
'OS-FLV-EXT-DATA:ephemeral': 10,
|
||||
'os-flavor-access:is_public': True,
|
||||
'links': {}},
|
||||
{'id': 'aa1', 'name': '128 mb server', 'ram': 128, 'disk': 0,
|
||||
{'id': 'aa1', 'name': '128 MB Server', 'ram': 128, 'disk': 0,
|
||||
'OS-FLV-EXT-DATA:ephemeral': 0,
|
||||
'os-flavor-access:is_public': True,
|
||||
'links': {}}
|
||||
@ -736,16 +761,16 @@ class FakeHTTPClient(base_client.HTTPClient):
|
||||
{},
|
||||
{'flavor': {
|
||||
'id': 3,
|
||||
'name': '256 mb server',
|
||||
'name': '256 MB Server',
|
||||
'ram': 256,
|
||||
'disk': 10,
|
||||
}},
|
||||
)
|
||||
|
||||
def get_flavors_512_mb_server(self, **kw):
|
||||
def get_flavors_512_MB_Server(self, **kw):
|
||||
raise exceptions.NotFound('404')
|
||||
|
||||
def get_flavors_128_mb_server(self, **kw):
|
||||
def get_flavors_128_MB_Server(self, **kw):
|
||||
raise exceptions.NotFound('404')
|
||||
|
||||
def get_flavors_aa1(self, **kw):
|
||||
@ -2196,7 +2221,6 @@ class FakeSessionMockClient(base_client.SessionClient, FakeHTTPClient):
|
||||
self.callstack = []
|
||||
self.auth = mock.Mock()
|
||||
self.session = mock.Mock()
|
||||
self.service_type = 'service_type'
|
||||
|
||||
self.auth.get_auth_ref.return_value.project_id = 'tenant_id'
|
||||
|
||||
|
||||
@ -363,7 +363,6 @@ class AuthenticationTests(utils.TestCase):
|
||||
"project_id", utils.AUTH_URL)
|
||||
http_client = cs.client
|
||||
http_client.management_url = ''
|
||||
http_client.get_service_url = mock.Mock(return_value='')
|
||||
mock_request = mock.Mock(return_value=(None, None))
|
||||
|
||||
@mock.patch.object(http_client, 'request', mock_request)
|
||||
|
||||
@ -70,7 +70,7 @@ class FlavorsTest(utils.TestCase):
|
||||
self.assertEqual(256, f.ram)
|
||||
self.assertEqual(10, f.disk)
|
||||
self.assertEqual(10, f.ephemeral)
|
||||
self.assertTrue(f.is_public)
|
||||
self.assertEqual(True, f.is_public)
|
||||
|
||||
def test_get_flavor_details_alphanum_id(self):
|
||||
f = self.cs.flavors.get('aa1')
|
||||
@ -79,7 +79,7 @@ class FlavorsTest(utils.TestCase):
|
||||
self.assertEqual(128, f.ram)
|
||||
self.assertEqual(0, f.disk)
|
||||
self.assertEqual(0, f.ephemeral)
|
||||
self.assertTrue(f.is_public)
|
||||
self.assertEqual(True, f.is_public)
|
||||
|
||||
def test_get_flavor_details_diablo(self):
|
||||
f = self.cs.flavors.get(3)
|
||||
@ -93,10 +93,10 @@ class FlavorsTest(utils.TestCase):
|
||||
def test_find(self):
|
||||
f = self.cs.flavors.find(ram=256)
|
||||
self.cs.assert_called('GET', '/flavors/detail')
|
||||
self.assertEqual('256 mb server', f.name)
|
||||
self.assertEqual('256 MB Server', f.name)
|
||||
|
||||
f = self.cs.flavors.find(disk=0)
|
||||
self.assertEqual('128 mb server', f.name)
|
||||
self.assertEqual('128 MB Server', f.name)
|
||||
|
||||
self.assertRaises(exceptions.NotFound, self.cs.flavors.find,
|
||||
disk=12345)
|
||||
|
||||
@ -34,7 +34,7 @@ class FpingTest(utils.FixturedTestCase):
|
||||
for f in fl:
|
||||
self.assertIsInstance(f, fping.Fping)
|
||||
self.assertEqual("fake-project", f.project_id)
|
||||
self.assertTrue(f.alive)
|
||||
self.assertEqual(True, f.alive)
|
||||
|
||||
def test_list_fpings_all_tenants(self):
|
||||
fl = self.cs.fping.list(all_tenants=True)
|
||||
@ -59,4 +59,4 @@ class FpingTest(utils.FixturedTestCase):
|
||||
self.assert_called('GET', '/os-fping/1')
|
||||
self.assertIsInstance(f, fping.Fping)
|
||||
self.assertEqual("fake-project", f.project_id)
|
||||
self.assertTrue(f.alive)
|
||||
self.assertEqual(True, f.alive)
|
||||
|
||||
@ -26,7 +26,6 @@ class ImagesTest(utils.FixturedTestCase):
|
||||
il = self.cs.images.list()
|
||||
self.assert_called('GET', '/images/detail')
|
||||
[self.assertIsInstance(i, images.Image) for i in il]
|
||||
self.assertEqual(2, len(il))
|
||||
|
||||
def test_list_images_undetailed(self):
|
||||
il = self.cs.images.list(detailed=False)
|
||||
|
||||
@ -47,7 +47,7 @@ class LimitsTest(utils.FixturedTestCase):
|
||||
self.assertEqual(len(abs_limits), len(expected))
|
||||
|
||||
for limit in abs_limits:
|
||||
self.assertIn(limit, expected)
|
||||
self.assertTrue(limit in expected)
|
||||
|
||||
def test_absolute_limits_reserved(self):
|
||||
obj = self.cs.limits.get(reserved=True)
|
||||
@ -65,7 +65,7 @@ class LimitsTest(utils.FixturedTestCase):
|
||||
self.assertEqual(len(abs_limits), len(expected))
|
||||
|
||||
for limit in abs_limits:
|
||||
self.assertIn(limit, expected)
|
||||
self.assertTrue(limit in expected)
|
||||
|
||||
def test_rate_limits(self):
|
||||
obj = self.cs.limits.get()
|
||||
@ -85,4 +85,4 @@ class LimitsTest(utils.FixturedTestCase):
|
||||
self.assertEqual(len(rate_limits), len(expected))
|
||||
|
||||
for limit in rate_limits:
|
||||
self.assertIn(limit, expected)
|
||||
self.assertTrue(limit in expected)
|
||||
|
||||
@ -212,7 +212,7 @@ class ServersTest(utils.FixturedTestCase):
|
||||
# verify disk config param was used in the request:
|
||||
body = jsonutils.loads(self.requests.last_request.body)
|
||||
server = body['server']
|
||||
self.assertIn('OS-DCF:diskConfig', server)
|
||||
self.assertTrue('OS-DCF:diskConfig' in server)
|
||||
self.assertEqual(disk_config, server['OS-DCF:diskConfig'])
|
||||
|
||||
def test_create_server_disk_config_auto(self):
|
||||
@ -302,7 +302,7 @@ class ServersTest(utils.FixturedTestCase):
|
||||
body = jsonutils.loads(self.requests.last_request.body)
|
||||
|
||||
d = body[operation]
|
||||
self.assertIn('OS-DCF:diskConfig', d)
|
||||
self.assertTrue('OS-DCF:diskConfig' in d)
|
||||
self.assertEqual(disk_config, d['OS-DCF:diskConfig'])
|
||||
|
||||
def test_rebuild_server_disk_config_auto(self):
|
||||
@ -318,7 +318,7 @@ class ServersTest(utils.FixturedTestCase):
|
||||
body = jsonutils.loads(self.requests.last_request.body)
|
||||
d = body['rebuild']
|
||||
self.assertIn('preserve_ephemeral', d)
|
||||
self.assertTrue(d['preserve_ephemeral'])
|
||||
self.assertEqual(True, d['preserve_ephemeral'])
|
||||
|
||||
def test_rebuild_server_name_meta_files(self):
|
||||
files = {'/etc/passwd': 'some data'}
|
||||
@ -560,11 +560,11 @@ class ServersTest(utils.FixturedTestCase):
|
||||
def test_get_server_diagnostics(self):
|
||||
s = self.cs.servers.get(1234)
|
||||
diagnostics = s.diagnostics()
|
||||
self.assertIsNotNone(diagnostics)
|
||||
self.assertTrue(diagnostics is not None)
|
||||
self.assert_called('GET', '/servers/1234/diagnostics')
|
||||
|
||||
diagnostics_from_manager = self.cs.servers.diagnostics(1234)
|
||||
self.assertIsNotNone(diagnostics_from_manager)
|
||||
self.assertTrue(diagnostics_from_manager is not None)
|
||||
self.assert_called('GET', '/servers/1234/diagnostics')
|
||||
|
||||
self.assertEqual(diagnostics[1], diagnostics_from_manager[1])
|
||||
|
||||
@ -661,10 +661,10 @@ class ShellTest(utils.TestCase):
|
||||
|
||||
def test_boot_named_flavor(self):
|
||||
self.run_command(["boot", "--image", "1",
|
||||
"--flavor", "512 mb server",
|
||||
"--flavor", "512 MB Server",
|
||||
"--max-count", "3", "server"])
|
||||
self.assert_called('GET', '/images/1', pos=0)
|
||||
self.assert_called('GET', '/flavors/512 mb server', pos=1)
|
||||
self.assert_called('GET', '/flavors/512 MB Server', pos=1)
|
||||
self.assert_called('GET', '/flavors?is_public=None', pos=2)
|
||||
self.assert_called('GET', '/flavors/2', pos=3)
|
||||
self.assert_called(
|
||||
@ -701,15 +701,15 @@ class ShellTest(utils.TestCase):
|
||||
self.assert_called_anytime('GET', '/flavors/aa1')
|
||||
|
||||
def test_flavor_show_by_name(self):
|
||||
self.run_command(['flavor-show', '128 mb server'])
|
||||
self.assert_called('GET', '/flavors/128 mb server', pos=0)
|
||||
self.run_command(['flavor-show', '128 MB Server'])
|
||||
self.assert_called('GET', '/flavors/128 MB Server', pos=0)
|
||||
self.assert_called('GET', '/flavors?is_public=None', pos=1)
|
||||
self.assert_called('GET', '/flavors/aa1', pos=2)
|
||||
self.assert_called('GET', '/flavors/aa1/os-extra_specs', pos=3)
|
||||
|
||||
def test_flavor_show_by_name_priv(self):
|
||||
self.run_command(['flavor-show', '512 mb server'])
|
||||
self.assert_called('GET', '/flavors/512 mb server', pos=0)
|
||||
self.run_command(['flavor-show', '512 MB Server'])
|
||||
self.assert_called('GET', '/flavors/512 MB Server', pos=0)
|
||||
self.assert_called('GET', '/flavors?is_public=None', pos=1)
|
||||
self.assert_called('GET', '/flavors/2', pos=2)
|
||||
self.assert_called('GET', '/flavors/2/os-extra_specs', pos=3)
|
||||
@ -746,7 +746,7 @@ class ShellTest(utils.TestCase):
|
||||
{'addTenantAccess': {'tenant': 'proj2'}})
|
||||
|
||||
def test_flavor_access_add_by_name(self):
|
||||
self.run_command(['flavor-access-add', '512 mb server', 'proj2'])
|
||||
self.run_command(['flavor-access-add', '512 MB Server', 'proj2'])
|
||||
self.assert_called('POST', '/flavors/2/action',
|
||||
{'addTenantAccess': {'tenant': 'proj2'}})
|
||||
|
||||
@ -756,7 +756,7 @@ class ShellTest(utils.TestCase):
|
||||
{'removeTenantAccess': {'tenant': 'proj2'}})
|
||||
|
||||
def test_flavor_access_remove_by_name(self):
|
||||
self.run_command(['flavor-access-remove', '512 mb server', 'proj2'])
|
||||
self.run_command(['flavor-access-remove', '512 MB Server', 'proj2'])
|
||||
self.assert_called('POST', '/flavors/2/action',
|
||||
{'removeTenantAccess': {'tenant': 'proj2'}})
|
||||
|
||||
@ -2145,7 +2145,7 @@ class ShellTest(utils.TestCase):
|
||||
|
||||
def test_volume_show(self):
|
||||
self.run_command('volume-show Work')
|
||||
self.assert_called('GET', '/volumes?display_name=Work', pos=-2)
|
||||
self.assert_called('GET', '/volumes?name=Work', pos=-2)
|
||||
self.assert_called(
|
||||
'GET',
|
||||
'/volumes/15e59938-07d5-11e1-90e3-e3dffe0c5983',
|
||||
|
||||
@ -14,8 +14,8 @@
|
||||
import os
|
||||
|
||||
import fixtures
|
||||
import httpretty
|
||||
import requests
|
||||
from requests_mock.contrib import fixture as requests_mock_fixture
|
||||
import six
|
||||
import testscenarios
|
||||
import testtools
|
||||
@ -52,24 +52,26 @@ class FixturedTestCase(testscenarios.TestWithScenarios, TestCase):
|
||||
def setUp(self):
|
||||
super(FixturedTestCase, self).setUp()
|
||||
|
||||
httpretty.reset()
|
||||
self.requests = self.useFixture(requests_mock_fixture.Fixture())
|
||||
self.data_fixture = None
|
||||
self.client_fixture = None
|
||||
self.cs = None
|
||||
|
||||
if self.client_fixture_class:
|
||||
self.client_fixture = self.useFixture(self.client_fixture_class())
|
||||
fix = self.client_fixture_class(self.requests)
|
||||
self.client_fixture = self.useFixture(fix)
|
||||
self.cs = self.client_fixture.client
|
||||
|
||||
if self.data_fixture_class:
|
||||
self.data_fixture = self.useFixture(self.data_fixture_class())
|
||||
fix = self.data_fixture_class(self.requests)
|
||||
self.data_fixture = self.useFixture(fix)
|
||||
|
||||
def assert_called(self, method, path, body=None):
|
||||
self.assertEqual(httpretty.last_request().method, method)
|
||||
self.assertEqual(httpretty.last_request().path, path)
|
||||
self.assertEqual(self.requests.last_request.method, method)
|
||||
self.assertEqual(self.requests.last_request.path_url, path)
|
||||
|
||||
if body:
|
||||
req_data = httpretty.last_request().body
|
||||
req_data = self.requests.last_request.body
|
||||
if isinstance(req_data, six.binary_type):
|
||||
req_data = req_data.decode('utf-8')
|
||||
if not isinstance(body, six.string_types):
|
||||
|
||||
@ -15,10 +15,9 @@
|
||||
|
||||
|
||||
from novaclient import extension
|
||||
from novaclient.v1_1.contrib import baremetal
|
||||
|
||||
from novaclient.tests import utils
|
||||
from novaclient.tests.v1_1.contrib import fakes
|
||||
from novaclient.v1_1.contrib import baremetal
|
||||
|
||||
|
||||
extensions = [
|
||||
|
||||
@ -12,11 +12,11 @@
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
from novaclient import extension
|
||||
from novaclient.v1_1.contrib import instance_action
|
||||
|
||||
from novaclient import extension
|
||||
from novaclient.tests import utils
|
||||
from novaclient.tests.v1_1.contrib import fakes
|
||||
from novaclient.v1_1.contrib import instance_action
|
||||
|
||||
|
||||
extensions = [
|
||||
|
||||
@ -12,10 +12,9 @@
|
||||
# under the License.
|
||||
|
||||
from novaclient import extension
|
||||
from novaclient.v1_1.contrib import list_extensions
|
||||
|
||||
from novaclient.tests import utils
|
||||
from novaclient.tests.v1_1 import fakes
|
||||
from novaclient.v1_1.contrib import list_extensions
|
||||
|
||||
|
||||
extensions = [
|
||||
|
||||
@ -14,10 +14,9 @@
|
||||
# under the License.
|
||||
|
||||
from novaclient import extension
|
||||
from novaclient.v1_1.contrib import tenant_networks
|
||||
|
||||
from novaclient.tests import utils
|
||||
from novaclient.tests.v1_1.contrib import fakes
|
||||
from novaclient.v1_1.contrib import tenant_networks
|
||||
|
||||
|
||||
extensions = [
|
||||
|
||||
@ -14,14 +14,14 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from datetime import datetime
|
||||
import datetime
|
||||
|
||||
from oslo.utils import strutils
|
||||
import six
|
||||
from six.moves.urllib import parse
|
||||
|
||||
from novaclient import client as base_client
|
||||
from novaclient import exceptions
|
||||
from novaclient.openstack.common import strutils
|
||||
from novaclient.tests import fakes
|
||||
from novaclient.tests import utils
|
||||
from novaclient.v1_1 import client
|
||||
@ -636,7 +636,9 @@ class FakeHTTPClient(base_client.HTTPClient):
|
||||
keys = list(body[action])
|
||||
if 'adminPass' in keys:
|
||||
keys.remove('adminPass')
|
||||
assert set(keys) == set(['host', 'onSharedStorage'])
|
||||
if 'host' in keys:
|
||||
keys.remove('host')
|
||||
assert set(keys) == set(['onSharedStorage'])
|
||||
else:
|
||||
raise AssertionError("Unexpected server action: %s" % action)
|
||||
return (resp, _headers, _body)
|
||||
@ -710,14 +712,14 @@ class FakeHTTPClient(base_client.HTTPClient):
|
||||
if filter_is_public is not None:
|
||||
if filter_is_public:
|
||||
flavors['flavors'] = [
|
||||
v for v in flavors['flavors']
|
||||
if v['os-flavor-access:is_public']
|
||||
]
|
||||
v for v in flavors['flavors']
|
||||
if v['os-flavor-access:is_public']
|
||||
]
|
||||
else:
|
||||
flavors['flavors'] = [
|
||||
v for v in flavors['flavors']
|
||||
if not v['os-flavor-access:is_public']
|
||||
]
|
||||
v for v in flavors['flavors']
|
||||
if not v['os-flavor-access:is_public']
|
||||
]
|
||||
|
||||
return (200, {}, flavors)
|
||||
|
||||
@ -1311,7 +1313,7 @@ class FakeHTTPClient(base_client.HTTPClient):
|
||||
def get_os_security_group_rules(self, **kw):
|
||||
return (200, {}, {"security_group_rules": [
|
||||
{'id': 1, 'parent_group_id': 1, 'group_id': 2,
|
||||
'ip_protocol': 'TCP', 'from_port': '22', 'to_port': 22,
|
||||
'ip_protocol': 'TCP', 'from_port': 22, 'to_port': 22,
|
||||
'cidr': '10.0.0.0/8'}
|
||||
]})
|
||||
|
||||
@ -1334,6 +1336,34 @@ class FakeHTTPClient(base_client.HTTPClient):
|
||||
self.get_os_security_group_rules()[2]['security_group_rules'][0]}
|
||||
return (202, {}, r)
|
||||
|
||||
#
|
||||
# Security Group Default Rules
|
||||
#
|
||||
def get_os_security_group_default_rules(self, **kw):
|
||||
return (200, {}, {"security_group_default_rules": [
|
||||
{'id': 1, 'ip_protocol': 'TCP', 'from_port': 22,
|
||||
'to_port': 22, 'cidr': '10.0.0.0/8'}
|
||||
]})
|
||||
|
||||
def delete_os_security_group_default_rules_1(self, **kw):
|
||||
return (202, {}, None)
|
||||
|
||||
def delete_os_security_group_default_rules_11(self, **kw):
|
||||
return (202, {}, None)
|
||||
|
||||
def delete_os_security_group_default_rules_12(self, **kw):
|
||||
return (202, {}, None)
|
||||
|
||||
def post_os_security_group_default_rules(self, body, **kw):
|
||||
assert list(body) == ['security_group_default_rule']
|
||||
fakes.assert_has_keys(body['security_group_default_rule'],
|
||||
optional=['ip_protocol', 'from_port',
|
||||
'to_port', 'cidr'])
|
||||
rules = self.get_os_security_group_default_rules()
|
||||
r = {'security_group_default_rule':
|
||||
rules[2]['security_group_default_rules'][0]}
|
||||
return (202, {}, r)
|
||||
|
||||
#
|
||||
# Tenant Usage
|
||||
#
|
||||
@ -1344,7 +1374,7 @@ class FakeHTTPClient(base_client.HTTPClient):
|
||||
six.u('total_vcpus_usage'): 49.71047423333333,
|
||||
six.u('total_hours'): 49.71047423333333,
|
||||
six.u('tenant_id'):
|
||||
six.u('7b0a1d73f8fb41718f3343c207597869'),
|
||||
six.u('7b0a1d73f8fb41718f3343c207597869'),
|
||||
six.u('stop'): six.u('2012-01-22 19:48:41.750722'),
|
||||
six.u('server_usages'): [{
|
||||
six.u('hours'): 49.71047423333333,
|
||||
@ -1353,7 +1383,7 @@ class FakeHTTPClient(base_client.HTTPClient):
|
||||
six.u('ended_at'): None,
|
||||
six.u('name'): six.u('f15image1'),
|
||||
six.u('tenant_id'):
|
||||
six.u('7b0a1d73f8fb41718f3343c207597869'),
|
||||
six.u('7b0a1d73f8fb41718f3343c207597869'),
|
||||
six.u('vcpus'): 1,
|
||||
six.u('memory_mb'): 512,
|
||||
six.u('state'): six.u('active'),
|
||||
@ -1370,7 +1400,7 @@ class FakeHTTPClient(base_client.HTTPClient):
|
||||
six.u('total_vcpus_usage'): 49.71047423333333,
|
||||
six.u('total_hours'): 49.71047423333333,
|
||||
six.u('tenant_id'):
|
||||
six.u('7b0a1d73f8fb41718f3343c207597869'),
|
||||
six.u('7b0a1d73f8fb41718f3343c207597869'),
|
||||
six.u('stop'): six.u('2012-01-22 19:48:41.750722'),
|
||||
six.u('server_usages'): [{
|
||||
six.u('hours'): 49.71047423333333,
|
||||
@ -1456,15 +1486,25 @@ class FakeHTTPClient(base_client.HTTPClient):
|
||||
{'id': '2',
|
||||
'name': 'test2',
|
||||
'availability_zone': 'nova1'},
|
||||
{'id': '3',
|
||||
'name': 'test3',
|
||||
'metadata': {'test': "dup", "none_key": "Nine"}},
|
||||
]})
|
||||
|
||||
def _return_aggregate(self):
|
||||
r = {'aggregate': self.get_os_aggregates()[2]['aggregates'][0]}
|
||||
return (200, {}, r)
|
||||
|
||||
def _return_aggregate_3(self):
|
||||
r = {'aggregate': self.get_os_aggregates()[2]['aggregates'][2]}
|
||||
return (200, {}, r)
|
||||
|
||||
def get_os_aggregates_1(self, **kw):
|
||||
return self._return_aggregate()
|
||||
|
||||
def get_os_aggregates_3(self, **kw):
|
||||
return self._return_aggregate_3()
|
||||
|
||||
def post_os_aggregates(self, body, **kw):
|
||||
return self._return_aggregate()
|
||||
|
||||
@ -1474,12 +1514,18 @@ class FakeHTTPClient(base_client.HTTPClient):
|
||||
def put_os_aggregates_2(self, body, **kw):
|
||||
return self._return_aggregate()
|
||||
|
||||
def put_os_aggregates_3(self, body, **kw):
|
||||
return self._return_aggregate_3()
|
||||
|
||||
def post_os_aggregates_1_action(self, body, **kw):
|
||||
return self._return_aggregate()
|
||||
|
||||
def post_os_aggregates_2_action(self, body, **kw):
|
||||
return self._return_aggregate()
|
||||
|
||||
def post_os_aggregates_3_action(self, body, **kw):
|
||||
return self._return_aggregate_3()
|
||||
|
||||
def delete_os_aggregates_1(self, **kw):
|
||||
return (202, {}, None)
|
||||
|
||||
@ -1495,13 +1541,17 @@ class FakeHTTPClient(base_client.HTTPClient):
|
||||
'zone': 'nova',
|
||||
'status': 'enabled',
|
||||
'state': 'up',
|
||||
'updated_at': datetime(2012, 10, 29, 13, 42, 2)},
|
||||
'updated_at': datetime.datetime(
|
||||
2012, 10, 29, 13, 42, 2
|
||||
)},
|
||||
{'binary': binary,
|
||||
'host': host,
|
||||
'zone': 'nova',
|
||||
'status': 'disabled',
|
||||
'state': 'down',
|
||||
'updated_at': datetime(2012, 9, 18, 8, 3, 38)},
|
||||
'updated_at': datetime.datetime(
|
||||
2012, 9, 18, 8, 3, 38
|
||||
)},
|
||||
]})
|
||||
|
||||
def put_os_services_enable(self, body, **kw):
|
||||
@ -1708,13 +1758,17 @@ class FakeHTTPClient(base_client.HTTPClient):
|
||||
def get_os_networks(self, **kw):
|
||||
return (200, {}, {'networks': [{"label": "1", "cidr": "10.0.0.0/24",
|
||||
'project_id': '4ffc664c198e435e9853f2538fbcd7a7',
|
||||
'id': '1'}]})
|
||||
'id': '1', 'vlan': '1234'}]})
|
||||
|
||||
def delete_os_networks_1(self, **kw):
|
||||
return (202, {}, None)
|
||||
|
||||
def post_os_networks(self, **kw):
|
||||
return (202, {}, {'network': kw})
|
||||
|
||||
def get_os_networks_1(self, **kw):
|
||||
return (200, {}, {'network': {"label": "1", "cidr": "10.0.0.0/24"}})
|
||||
return (200, {}, {'network': {"label": "1", "cidr": "10.0.0.0/24",
|
||||
"id": "1"}})
|
||||
|
||||
def delete_os_networks_networkdelete(self, **kw):
|
||||
return (202, {}, None)
|
||||
@ -1781,7 +1835,9 @@ class FakeHTTPClient(base_client.HTTPClient):
|
||||
"nova-compute": {"active": True,
|
||||
"available": True,
|
||||
"updated_at":
|
||||
datetime(2012, 12, 26, 14, 45, 25, 0)}}}},
|
||||
datetime.datetime(
|
||||
2012, 12, 26, 14, 45, 25, 0
|
||||
)}}}},
|
||||
{"zoneName": "internal",
|
||||
"zoneState": {"available": True},
|
||||
"hosts": {
|
||||
@ -1790,13 +1846,17 @@ class FakeHTTPClient(base_client.HTTPClient):
|
||||
"active": True,
|
||||
"available": True,
|
||||
"updated_at":
|
||||
datetime(2012, 12, 26, 14, 45, 25, 0)}},
|
||||
datetime.datetime(
|
||||
2012, 12, 26, 14, 45, 25, 0
|
||||
)}},
|
||||
"fake_host-2": {
|
||||
"nova-network": {
|
||||
"active": True,
|
||||
"available": False,
|
||||
"updated_at":
|
||||
datetime(2012, 12, 26, 14, 45, 24, 0)}}}},
|
||||
datetime.datetime(
|
||||
2012, 12, 26, 14, 45, 24, 0
|
||||
)}}}},
|
||||
{"zoneName": "zone-2",
|
||||
"zoneState": {"available": False},
|
||||
"hosts": None}]})
|
||||
|
||||
@ -13,9 +13,6 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import httpretty
|
||||
|
||||
from novaclient.openstack.common import jsonutils
|
||||
from novaclient.tests.fixture_data import agents as data
|
||||
from novaclient.tests.fixture_data import client
|
||||
from novaclient.tests import utils
|
||||
@ -53,9 +50,10 @@ class AgentsTest(utils.FixturedTestCase):
|
||||
]
|
||||
}
|
||||
|
||||
httpretty.register_uri(httpretty.GET, self.data_fixture.url(),
|
||||
body=jsonutils.dumps(get_os_agents),
|
||||
content_type='application/json')
|
||||
headers = {'Content-Type': 'application/json'}
|
||||
self.requests.register_uri('GET', self.data_fixture.url(),
|
||||
json=get_os_agents,
|
||||
headers=headers)
|
||||
|
||||
def test_list_agents(self):
|
||||
self.stub_hypervisors()
|
||||
@ -63,7 +61,7 @@ class AgentsTest(utils.FixturedTestCase):
|
||||
self.assert_called('GET', '/os-agents')
|
||||
for a in ags:
|
||||
self.assertIsInstance(a, agents.Agent)
|
||||
self.assertEqual(a.hypervisor, 'kvm')
|
||||
self.assertEqual('kvm', a.hypervisor)
|
||||
|
||||
def test_list_agents_with_hypervisor(self):
|
||||
self.stub_hypervisors('xen')
|
||||
@ -71,7 +69,7 @@ class AgentsTest(utils.FixturedTestCase):
|
||||
self.assert_called('GET', '/os-agents?hypervisor=xen')
|
||||
for a in ags:
|
||||
self.assertIsInstance(a, agents.Agent)
|
||||
self.assertEqual(a.hypervisor, 'xen')
|
||||
self.assertEqual('xen', a.hypervisor)
|
||||
|
||||
def test_agents_create(self):
|
||||
ag = self.cs.agents.create('win', 'x86', '7.0',
|
||||
|
||||
@ -14,6 +14,7 @@
|
||||
import copy
|
||||
import json
|
||||
|
||||
from keystoneclient import fixture
|
||||
import mock
|
||||
import requests
|
||||
|
||||
@ -23,33 +24,21 @@ from novaclient.v1_1 import client
|
||||
|
||||
|
||||
class AuthenticateAgainstKeystoneTests(utils.TestCase):
|
||||
|
||||
def get_token(self, **kwargs):
|
||||
resp = fixture.V2Token(**kwargs)
|
||||
resp.set_scope()
|
||||
|
||||
s = resp.add_service('compute')
|
||||
s.add_endpoint('http://localhost:8774/v1.1', region='RegionOne')
|
||||
|
||||
return resp
|
||||
|
||||
def test_authenticate_success(self):
|
||||
cs = client.Client("username", "password", "project_id",
|
||||
utils.AUTH_URL_V2, service_type='compute')
|
||||
resp = {
|
||||
"access": {
|
||||
"token": {
|
||||
"expires": "12345",
|
||||
"id": "FAKE_ID",
|
||||
"tenant": {
|
||||
"id": "FAKE_TENANT_ID",
|
||||
}
|
||||
},
|
||||
"serviceCatalog": [
|
||||
{
|
||||
"type": "compute",
|
||||
"endpoints": [
|
||||
{
|
||||
"region": "RegionOne",
|
||||
"adminURL": "http://localhost:8774/v1.1",
|
||||
"internalURL": "http://localhost:8774/v1.1",
|
||||
"publicURL": "http://localhost:8774/v1.1/",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
resp = self.get_token()
|
||||
|
||||
auth_response = utils.TestResponse({
|
||||
"status_code": 200,
|
||||
"text": json.dumps(resp),
|
||||
@ -112,30 +101,7 @@ class AuthenticateAgainstKeystoneTests(utils.TestCase):
|
||||
def test_v1_auth_redirect(self):
|
||||
cs = client.Client("username", "password", "project_id",
|
||||
utils.AUTH_URL_V1, service_type='compute')
|
||||
dict_correct_response = {
|
||||
"access": {
|
||||
"token": {
|
||||
"expires": "12345",
|
||||
"id": "FAKE_ID",
|
||||
"tenant": {
|
||||
"id": "FAKE_TENANT_ID",
|
||||
}
|
||||
},
|
||||
"serviceCatalog": [
|
||||
{
|
||||
"type": "compute",
|
||||
"endpoints": [
|
||||
{
|
||||
"adminURL": "http://localhost:8774/v1.1",
|
||||
"region": "RegionOne",
|
||||
"internalURL": "http://localhost:8774/v1.1",
|
||||
"publicURL": "http://localhost:8774/v1.1/",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
dict_correct_response = self.get_token()
|
||||
correct_response = json.dumps(dict_correct_response)
|
||||
dict_responses = [
|
||||
{"headers": {'location': 'http://127.0.0.1:5001'},
|
||||
@ -173,9 +139,9 @@ class AuthenticateAgainstKeystoneTests(utils.TestCase):
|
||||
'passwordCredentials': {
|
||||
'username': cs.client.user,
|
||||
'password': cs.client.password,
|
||||
},
|
||||
'tenantName': cs.client.projectid,
|
||||
},
|
||||
},
|
||||
'tenantName': cs.client.projectid,
|
||||
},
|
||||
}
|
||||
|
||||
token_url = cs.client.auth_url + "/tokens"
|
||||
@ -200,30 +166,7 @@ class AuthenticateAgainstKeystoneTests(utils.TestCase):
|
||||
def test_v2_auth_redirect(self):
|
||||
cs = client.Client("username", "password", "project_id",
|
||||
utils.AUTH_URL_V2, service_type='compute')
|
||||
dict_correct_response = {
|
||||
"access": {
|
||||
"token": {
|
||||
"expires": "12345",
|
||||
"id": "FAKE_ID",
|
||||
"tenant": {
|
||||
"id": "FAKE_TENANT_ID",
|
||||
}
|
||||
},
|
||||
"serviceCatalog": [
|
||||
{
|
||||
"type": "compute",
|
||||
"endpoints": [
|
||||
{
|
||||
"adminURL": "http://localhost:8774/v1.1",
|
||||
"region": "RegionOne",
|
||||
"internalURL": "http://localhost:8774/v1.1",
|
||||
"publicURL": "http://localhost:8774/v1.1/",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
dict_correct_response = self.get_token()
|
||||
correct_response = json.dumps(dict_correct_response)
|
||||
dict_responses = [
|
||||
{"headers": {'location': 'http://127.0.0.1:5001'},
|
||||
@ -261,9 +204,9 @@ class AuthenticateAgainstKeystoneTests(utils.TestCase):
|
||||
'passwordCredentials': {
|
||||
'username': cs.client.user,
|
||||
'password': cs.client.password,
|
||||
},
|
||||
'tenantName': cs.client.projectid,
|
||||
},
|
||||
},
|
||||
'tenantName': cs.client.projectid,
|
||||
},
|
||||
}
|
||||
|
||||
token_url = cs.client.auth_url + "/tokens"
|
||||
@ -288,42 +231,12 @@ class AuthenticateAgainstKeystoneTests(utils.TestCase):
|
||||
def test_ambiguous_endpoints(self):
|
||||
cs = client.Client("username", "password", "project_id",
|
||||
utils.AUTH_URL_V2, service_type='compute')
|
||||
resp = {
|
||||
"access": {
|
||||
"token": {
|
||||
"expires": "12345",
|
||||
"id": "FAKE_ID",
|
||||
"tenant": {
|
||||
"id": "FAKE_TENANT_ID",
|
||||
}
|
||||
},
|
||||
"serviceCatalog": [
|
||||
{
|
||||
"adminURL": "http://localhost:8774/v1.1",
|
||||
"type": "compute",
|
||||
"name": "Compute CLoud",
|
||||
"endpoints": [
|
||||
{
|
||||
"region": "RegionOne",
|
||||
"internalURL": "http://localhost:8774/v1.1",
|
||||
"publicURL": "http://localhost:8774/v1.1/",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
"adminURL": "http://localhost:8774/v1.1",
|
||||
"type": "compute",
|
||||
"name": "Hyper-compute Cloud",
|
||||
"endpoints": [
|
||||
{
|
||||
"internalURL": "http://localhost:8774/v1.1",
|
||||
"publicURL": "http://localhost:8774/v1.1/",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
resp = self.get_token()
|
||||
|
||||
# duplicate existing service
|
||||
s = resp.add_service('compute')
|
||||
s.add_endpoint('http://localhost:8774/v1.1', region='RegionOne')
|
||||
|
||||
auth_response = utils.TestResponse({
|
||||
"status_code": 200,
|
||||
"text": json.dumps(resp),
|
||||
@ -342,30 +255,7 @@ class AuthenticateAgainstKeystoneTests(utils.TestCase):
|
||||
cs = client.Client("username", None, "project_id",
|
||||
utils.AUTH_URL_V2, service_type='compute')
|
||||
cs.client.auth_token = "FAKE_ID"
|
||||
resp = {
|
||||
"access": {
|
||||
"token": {
|
||||
"expires": "12345",
|
||||
"id": "FAKE_ID",
|
||||
"tenant": {
|
||||
"id": "FAKE_TENANT_ID",
|
||||
}
|
||||
},
|
||||
"serviceCatalog": [
|
||||
{
|
||||
"type": "compute",
|
||||
"endpoints": [
|
||||
{
|
||||
"region": "RegionOne",
|
||||
"adminURL": "http://localhost:8774/v1.1",
|
||||
"internalURL": "http://localhost:8774/v1.1",
|
||||
"publicURL": "http://localhost:8774/v1.1/",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
resp = self.get_token(token_id="FAKE_ID")
|
||||
auth_response = utils.TestResponse({
|
||||
"status_code": 200,
|
||||
"text": json.dumps(resp),
|
||||
|
||||
@ -58,7 +58,7 @@ class AvailabilityZoneTest(utils.FixturedTestCase):
|
||||
z0 = self.shell._treeizeAvailabilityZone(zones[0])
|
||||
z1 = self.shell._treeizeAvailabilityZone(zones[1])
|
||||
|
||||
self.assertEqual((len(z0), len(z1)), (1, 1))
|
||||
self.assertEqual((1, 1), (len(z0), len(z1)))
|
||||
|
||||
self._assertZone(z0[0], l0[0], l0[1])
|
||||
self._assertZone(z1[0], l1[0], l1[1])
|
||||
@ -89,7 +89,7 @@ class AvailabilityZoneTest(utils.FixturedTestCase):
|
||||
z1 = self.shell._treeizeAvailabilityZone(zones[1])
|
||||
z2 = self.shell._treeizeAvailabilityZone(zones[2])
|
||||
|
||||
self.assertEqual((len(z0), len(z1), len(z2)), (3, 5, 1))
|
||||
self.assertEqual((3, 5, 1), (len(z0), len(z1), len(z2)))
|
||||
|
||||
self._assertZone(z0[0], l0[0], l0[1])
|
||||
self._assertZone(z0[1], l1[0], l1[1])
|
||||
|
||||
@ -28,10 +28,10 @@ class FixedIpsTest(utils.FixturedTestCase):
|
||||
def test_get_fixed_ip(self):
|
||||
info = self.cs.fixed_ips.get(fixed_ip='192.168.1.1')
|
||||
self.assert_called('GET', '/os-fixed-ips/192.168.1.1')
|
||||
self.assertEqual(info.cidr, '192.168.1.0/24')
|
||||
self.assertEqual(info.address, '192.168.1.1')
|
||||
self.assertEqual(info.hostname, 'foo')
|
||||
self.assertEqual(info.host, 'bar')
|
||||
self.assertEqual('192.168.1.0/24', info.cidr)
|
||||
self.assertEqual('192.168.1.1', info.address)
|
||||
self.assertEqual('foo', info.hostname)
|
||||
self.assertEqual('bar', info.host)
|
||||
|
||||
def test_reserve_fixed_ip(self):
|
||||
body = {"reserve": None}
|
||||
|
||||
@ -67,36 +67,36 @@ class FlavorsTest(utils.TestCase):
|
||||
f = self.cs.flavors.get(1)
|
||||
self.cs.assert_called('GET', '/flavors/1')
|
||||
self.assertIsInstance(f, self.flavor_type)
|
||||
self.assertEqual(f.ram, 256)
|
||||
self.assertEqual(f.disk, 10)
|
||||
self.assertEqual(f.ephemeral, 10)
|
||||
self.assertEqual(f.is_public, True)
|
||||
self.assertEqual(256, f.ram)
|
||||
self.assertEqual(10, f.disk)
|
||||
self.assertEqual(10, f.ephemeral)
|
||||
self.assertEqual(True, f.is_public)
|
||||
|
||||
def test_get_flavor_details_alphanum_id(self):
|
||||
f = self.cs.flavors.get('aa1')
|
||||
self.cs.assert_called('GET', '/flavors/aa1')
|
||||
self.assertIsInstance(f, self.flavor_type)
|
||||
self.assertEqual(f.ram, 128)
|
||||
self.assertEqual(f.disk, 0)
|
||||
self.assertEqual(f.ephemeral, 0)
|
||||
self.assertEqual(f.is_public, True)
|
||||
self.assertEqual(128, f.ram)
|
||||
self.assertEqual(0, f.disk)
|
||||
self.assertEqual(0, f.ephemeral)
|
||||
self.assertEqual(True, f.is_public)
|
||||
|
||||
def test_get_flavor_details_diablo(self):
|
||||
f = self.cs.flavors.get(3)
|
||||
self.cs.assert_called('GET', '/flavors/3')
|
||||
self.assertIsInstance(f, self.flavor_type)
|
||||
self.assertEqual(f.ram, 256)
|
||||
self.assertEqual(f.disk, 10)
|
||||
self.assertEqual(f.ephemeral, 'N/A')
|
||||
self.assertEqual(f.is_public, 'N/A')
|
||||
self.assertEqual(256, f.ram)
|
||||
self.assertEqual(10, f.disk)
|
||||
self.assertEqual('N/A', f.ephemeral)
|
||||
self.assertEqual('N/A', f.is_public)
|
||||
|
||||
def test_find(self):
|
||||
f = self.cs.flavors.find(ram=256)
|
||||
self.cs.assert_called('GET', '/flavors/detail')
|
||||
self.assertEqual(f.name, '256 MB Server')
|
||||
self.assertEqual('256 MB Server', f.name)
|
||||
|
||||
f = self.cs.flavors.find(disk=0)
|
||||
self.assertEqual(f.name, '128 MB Server')
|
||||
self.assertEqual('128 MB Server', f.name)
|
||||
|
||||
self.assertRaises(exceptions.NotFound, self.cs.flavors.find,
|
||||
disk=12345)
|
||||
|
||||
@ -25,13 +25,13 @@ class FloatingIPDNSDomainTest(utils.FixturedTestCase):
|
||||
|
||||
def test_dns_domains(self):
|
||||
domainlist = self.cs.dns_domains.domains()
|
||||
self.assertEqual(len(domainlist), 2)
|
||||
self.assertEqual(2, len(domainlist))
|
||||
|
||||
for entry in domainlist:
|
||||
self.assertIsInstance(entry,
|
||||
floating_ip_dns.FloatingIPDNSDomain)
|
||||
|
||||
self.assertEqual(domainlist[1].domain, 'example.com')
|
||||
self.assertEqual('example.com', domainlist[1].domain)
|
||||
|
||||
def test_create_private_domain(self):
|
||||
self.cs.dns_domains.create_private(self.testdomain, 'test_avzone')
|
||||
@ -61,13 +61,13 @@ class FloatingIPDNSEntryTest(utils.FixturedTestCase):
|
||||
def test_get_dns_entries_by_ip(self):
|
||||
entries = self.cs.dns_entries.get_for_ip(self.testdomain,
|
||||
ip=self.testip)
|
||||
self.assertEqual(len(entries), 2)
|
||||
self.assertEqual(2, len(entries))
|
||||
|
||||
for entry in entries:
|
||||
self.assertIsInstance(entry,
|
||||
floating_ip_dns.FloatingIPDNSEntry)
|
||||
|
||||
self.assertEqual(entries[1].dns_entry['name'], 'host2')
|
||||
self.assertEqual('host2', entries[1].dns_entry['name'])
|
||||
self.assertEqual(entries[1].dns_entry['ip'], self.testip)
|
||||
|
||||
def test_get_dns_entry_by_name(self):
|
||||
|
||||
@ -55,5 +55,5 @@ class FloatingIPsTest(utils.FixturedTestCase):
|
||||
def test_create_floating_ip_with_pool(self):
|
||||
fl = self.cs.floating_ips.create('nova')
|
||||
self.assert_called('POST', '/os-floating-ips')
|
||||
self.assertEqual(fl.pool, 'nova')
|
||||
self.assertEqual('nova', fl.pool)
|
||||
self.assertIsInstance(fl, floating_ips.FloatingIP)
|
||||
|
||||
@ -26,15 +26,15 @@ class FpingTest(utils.FixturedTestCase):
|
||||
|
||||
def test_fping_repr(self):
|
||||
r = self.cs.fping.get(1)
|
||||
self.assertEqual(repr(r), "<Fping: 1>")
|
||||
self.assertEqual("<Fping: 1>", repr(r))
|
||||
|
||||
def test_list_fpings(self):
|
||||
fl = self.cs.fping.list()
|
||||
self.assert_called('GET', '/os-fping')
|
||||
for f in fl:
|
||||
self.assertIsInstance(f, fping.Fping)
|
||||
self.assertEqual(f.project_id, "fake-project")
|
||||
self.assertEqual(f.alive, True)
|
||||
self.assertEqual("fake-project", f.project_id)
|
||||
self.assertEqual(True, f.alive)
|
||||
|
||||
def test_list_fpings_all_tenants(self):
|
||||
fl = self.cs.fping.list(all_tenants=True)
|
||||
@ -58,5 +58,5 @@ class FpingTest(utils.FixturedTestCase):
|
||||
f = self.cs.fping.get(1)
|
||||
self.assert_called('GET', '/os-fping/1')
|
||||
self.assertIsInstance(f, fping.Fping)
|
||||
self.assertEqual(f.project_id, "fake-project")
|
||||
self.assertEqual(f.alive, True)
|
||||
self.assertEqual("fake-project", f.project_id)
|
||||
self.assertEqual(True, f.alive)
|
||||
|
||||
@ -78,3 +78,7 @@ class HostsTest(utils.FixturedTestCase):
|
||||
host.shutdown()
|
||||
self.assert_called(
|
||||
'GET', '/os-hosts/sample_host/shutdown')
|
||||
|
||||
def test_hosts_repr(self):
|
||||
hs = self.cs.hosts.get('host')
|
||||
self.assertEqual('<Host: dummy>', repr(hs[0]))
|
||||
|
||||
@ -40,8 +40,8 @@ class ImagesTest(utils.FixturedTestCase):
|
||||
i = self.cs.images.get(1)
|
||||
self.assert_called('GET', '/images/1')
|
||||
self.assertIsInstance(i, images.Image)
|
||||
self.assertEqual(i.id, 1)
|
||||
self.assertEqual(i.name, 'CentOS 5.2')
|
||||
self.assertEqual(1, i.id)
|
||||
self.assertEqual('CentOS 5.2', i.name)
|
||||
|
||||
def test_delete_image(self):
|
||||
self.cs.images.delete(1)
|
||||
@ -58,9 +58,9 @@ class ImagesTest(utils.FixturedTestCase):
|
||||
|
||||
def test_find(self):
|
||||
i = self.cs.images.find(name="CentOS 5.2")
|
||||
self.assertEqual(i.id, 1)
|
||||
self.assertEqual(1, i.id)
|
||||
self.assert_called('GET', '/images/1')
|
||||
|
||||
iml = self.cs.images.findall(status='SAVING')
|
||||
self.assertEqual(len(iml), 1)
|
||||
self.assertEqual(iml[0].name, 'My Server Backup')
|
||||
self.assertEqual(1, len(iml))
|
||||
self.assertEqual('My Server Backup', iml[0].name)
|
||||
|
||||
@ -37,7 +37,7 @@ class KeypairsTest(utils.FixturedTestCase):
|
||||
kp = self.cs.keypairs.get('test')
|
||||
self.assert_called('GET', '/%s/test' % self.keypair_prefix)
|
||||
self.assertIsInstance(kp, keypairs.Keypair)
|
||||
self.assertEqual(kp.name, 'test')
|
||||
self.assertEqual('test', kp.name)
|
||||
|
||||
def test_list_keypairs(self):
|
||||
kps = self.cs.keypairs.list()
|
||||
|
||||
@ -59,7 +59,13 @@ class NetworksTest(utils.FixturedTestCase):
|
||||
'project_id': '1',
|
||||
'vlan': 5,
|
||||
'vlan_start': 1,
|
||||
'vpn_start': 1
|
||||
'vpn_start': 1,
|
||||
'mtu': 1500,
|
||||
'enable_dhcp': 'T',
|
||||
'dhcp_server': '1920.2.2',
|
||||
'share_address': 'T',
|
||||
'allowed_start': '192.0.2.10',
|
||||
'allowed_end': '192.0.2.20',
|
||||
}
|
||||
|
||||
f = self.cs.networks.create(**params)
|
||||
|
||||
@ -16,48 +16,55 @@ import mock
|
||||
import six
|
||||
|
||||
from novaclient import exceptions
|
||||
from novaclient.openstack.common import jsonutils
|
||||
from novaclient.tests.fixture_data import client
|
||||
from novaclient.tests.fixture_data import floatingips
|
||||
from novaclient.tests.fixture_data import servers as data
|
||||
from novaclient.tests import utils
|
||||
from novaclient.tests.v1_1 import fakes
|
||||
from novaclient.v1_1 import servers
|
||||
|
||||
|
||||
cs = fakes.FakeClient()
|
||||
class ServersTest(utils.FixturedTestCase):
|
||||
|
||||
client_fixture_class = client.V1
|
||||
data_fixture_class = data.V1
|
||||
|
||||
class ServersTest(utils.TestCase):
|
||||
def setUp(self):
|
||||
super(ServersTest, self).setUp()
|
||||
self.useFixture(floatingips.FloatingFixture(self.requests))
|
||||
|
||||
def test_list_servers(self):
|
||||
sl = cs.servers.list()
|
||||
cs.assert_called('GET', '/servers/detail')
|
||||
sl = self.cs.servers.list()
|
||||
self.assert_called('GET', '/servers/detail')
|
||||
[self.assertIsInstance(s, servers.Server) for s in sl]
|
||||
|
||||
def test_list_servers_undetailed(self):
|
||||
sl = cs.servers.list(detailed=False)
|
||||
cs.assert_called('GET', '/servers')
|
||||
sl = self.cs.servers.list(detailed=False)
|
||||
self.assert_called('GET', '/servers')
|
||||
[self.assertIsInstance(s, servers.Server) for s in sl]
|
||||
|
||||
def test_list_servers_with_marker_limit(self):
|
||||
sl = cs.servers.list(marker=1234, limit=2)
|
||||
cs.assert_called('GET', '/servers/detail?limit=2&marker=1234')
|
||||
sl = self.cs.servers.list(marker=1234, limit=2)
|
||||
self.assert_called('GET', '/servers/detail?limit=2&marker=1234')
|
||||
for s in sl:
|
||||
self.assertIsInstance(s, servers.Server)
|
||||
|
||||
def test_get_server_details(self):
|
||||
s = cs.servers.get(1234)
|
||||
cs.assert_called('GET', '/servers/1234')
|
||||
s = self.cs.servers.get(1234)
|
||||
self.assert_called('GET', '/servers/1234')
|
||||
self.assertIsInstance(s, servers.Server)
|
||||
self.assertEqual(s.id, 1234)
|
||||
self.assertEqual(s.status, 'BUILD')
|
||||
self.assertEqual(1234, s.id)
|
||||
self.assertEqual('BUILD', s.status)
|
||||
|
||||
def test_get_server_promote_details(self):
|
||||
s1 = cs.servers.list(detailed=False)[0]
|
||||
s2 = cs.servers.list(detailed=True)[0]
|
||||
s1 = self.cs.servers.list(detailed=False)[0]
|
||||
s2 = self.cs.servers.list(detailed=True)[0]
|
||||
self.assertNotEqual(s1._info, s2._info)
|
||||
s1.get()
|
||||
self.assertEqual(s1._info, s2._info)
|
||||
|
||||
def test_create_server(self):
|
||||
s = cs.servers.create(
|
||||
s = self.cs.servers.create(
|
||||
name="My server",
|
||||
image=1,
|
||||
flavor=1,
|
||||
@ -69,11 +76,11 @@ class ServersTest(utils.TestCase):
|
||||
'/tmp/foo.txt': six.StringIO('data'), # a stream
|
||||
}
|
||||
)
|
||||
cs.assert_called('POST', '/servers')
|
||||
self.assert_called('POST', '/servers')
|
||||
self.assertIsInstance(s, servers.Server)
|
||||
|
||||
def test_create_server_boot_from_volume_with_nics(self):
|
||||
old_boot = cs.servers._boot
|
||||
old_boot = self.cs.servers._boot
|
||||
|
||||
nics = [{'net-id': '11111111-1111-1111-1111-111111111111',
|
||||
'v4-fixed-ip': '10.0.0.7'}]
|
||||
@ -87,9 +94,9 @@ class ServersTest(utils.TestCase):
|
||||
self.assertEqual(boot_kwargs['nics'], nics)
|
||||
return old_boot(url, key, *boot_args, **boot_kwargs)
|
||||
|
||||
@mock.patch.object(cs.servers, '_boot', wrapped_boot)
|
||||
@mock.patch.object(self.cs.servers, '_boot', wrapped_boot)
|
||||
def test_create_server_from_volume():
|
||||
s = cs.servers.create(
|
||||
s = self.cs.servers.create(
|
||||
name="My server",
|
||||
image=1,
|
||||
flavor=1,
|
||||
@ -99,13 +106,13 @@ class ServersTest(utils.TestCase):
|
||||
block_device_mapping=bdm,
|
||||
nics=nics
|
||||
)
|
||||
cs.assert_called('POST', '/os-volumes_boot')
|
||||
self.assert_called('POST', '/os-volumes_boot')
|
||||
self.assertIsInstance(s, servers.Server)
|
||||
|
||||
test_create_server_from_volume()
|
||||
|
||||
def test_create_server_boot_with_nics_ipv6(self):
|
||||
old_boot = cs.servers._boot
|
||||
old_boot = self.cs.servers._boot
|
||||
nics = [{'net-id': '11111111-1111-1111-1111-111111111111',
|
||||
'v6-fixed-ip': '2001:db9:0:1::10'}]
|
||||
|
||||
@ -113,8 +120,8 @@ class ServersTest(utils.TestCase):
|
||||
self.assertEqual(boot_kwargs['nics'], nics)
|
||||
return old_boot(url, key, *boot_args, **boot_kwargs)
|
||||
|
||||
with mock.patch.object(cs.servers, '_boot', wrapped_boot):
|
||||
s = cs.servers.create(
|
||||
with mock.patch.object(self.cs.servers, '_boot', wrapped_boot):
|
||||
s = self.cs.servers.create(
|
||||
name="My server",
|
||||
image=1,
|
||||
flavor=1,
|
||||
@ -123,11 +130,11 @@ class ServersTest(utils.TestCase):
|
||||
key_name="fakekey",
|
||||
nics=nics
|
||||
)
|
||||
cs.assert_called('POST', '/servers')
|
||||
self.assert_called('POST', '/servers')
|
||||
self.assertIsInstance(s, servers.Server)
|
||||
|
||||
def test_create_server_userdata_file_object(self):
|
||||
s = cs.servers.create(
|
||||
s = self.cs.servers.create(
|
||||
name="My server",
|
||||
image=1,
|
||||
flavor=1,
|
||||
@ -138,11 +145,11 @@ class ServersTest(utils.TestCase):
|
||||
'/tmp/foo.txt': six.StringIO('data'), # a stream
|
||||
},
|
||||
)
|
||||
cs.assert_called('POST', '/servers')
|
||||
self.assert_called('POST', '/servers')
|
||||
self.assertIsInstance(s, servers.Server)
|
||||
|
||||
def test_create_server_userdata_unicode(self):
|
||||
s = cs.servers.create(
|
||||
s = self.cs.servers.create(
|
||||
name="My server",
|
||||
image=1,
|
||||
flavor=1,
|
||||
@ -154,11 +161,11 @@ class ServersTest(utils.TestCase):
|
||||
'/tmp/foo.txt': six.StringIO('data'), # a stream
|
||||
},
|
||||
)
|
||||
cs.assert_called('POST', '/servers')
|
||||
self.assert_called('POST', '/servers')
|
||||
self.assertIsInstance(s, servers.Server)
|
||||
|
||||
def test_create_server_userdata_utf8(self):
|
||||
s = cs.servers.create(
|
||||
s = self.cs.servers.create(
|
||||
name="My server",
|
||||
image=1,
|
||||
flavor=1,
|
||||
@ -170,22 +177,21 @@ class ServersTest(utils.TestCase):
|
||||
'/tmp/foo.txt': six.StringIO('data'), # a stream
|
||||
},
|
||||
)
|
||||
cs.assert_called('POST', '/servers')
|
||||
self.assert_called('POST', '/servers')
|
||||
self.assertIsInstance(s, servers.Server)
|
||||
|
||||
def _create_disk_config(self, disk_config):
|
||||
s = cs.servers.create(
|
||||
s = self.cs.servers.create(
|
||||
name="My server",
|
||||
image=1,
|
||||
flavor=1,
|
||||
disk_config=disk_config
|
||||
)
|
||||
cs.assert_called('POST', '/servers')
|
||||
self.assert_called('POST', '/servers')
|
||||
self.assertIsInstance(s, servers.Server)
|
||||
|
||||
# verify disk config param was used in the request:
|
||||
last_request = cs.client.callstack[-1]
|
||||
body = last_request[-1]
|
||||
body = jsonutils.loads(self.requests.last_request.body)
|
||||
server = body['server']
|
||||
self.assertTrue('OS-DCF:diskConfig' in server)
|
||||
self.assertEqual(disk_config, server['OS-DCF:diskConfig'])
|
||||
@ -197,86 +203,84 @@ class ServersTest(utils.TestCase):
|
||||
self._create_disk_config('MANUAL')
|
||||
|
||||
def test_update_server(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
|
||||
# Update via instance
|
||||
s.update(name='hi')
|
||||
cs.assert_called('PUT', '/servers/1234')
|
||||
self.assert_called('PUT', '/servers/1234')
|
||||
s.update(name='hi')
|
||||
cs.assert_called('PUT', '/servers/1234')
|
||||
self.assert_called('PUT', '/servers/1234')
|
||||
|
||||
# Silly, but not an error
|
||||
s.update()
|
||||
|
||||
# Update via manager
|
||||
cs.servers.update(s, name='hi')
|
||||
cs.assert_called('PUT', '/servers/1234')
|
||||
self.cs.servers.update(s, name='hi')
|
||||
self.assert_called('PUT', '/servers/1234')
|
||||
|
||||
def test_delete_server(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.delete()
|
||||
cs.assert_called('DELETE', '/servers/1234')
|
||||
cs.servers.delete(1234)
|
||||
cs.assert_called('DELETE', '/servers/1234')
|
||||
cs.servers.delete(s)
|
||||
cs.assert_called('DELETE', '/servers/1234')
|
||||
self.assert_called('DELETE', '/servers/1234')
|
||||
self.cs.servers.delete(1234)
|
||||
self.assert_called('DELETE', '/servers/1234')
|
||||
self.cs.servers.delete(s)
|
||||
self.assert_called('DELETE', '/servers/1234')
|
||||
|
||||
def test_delete_server_meta(self):
|
||||
cs.servers.delete_meta(1234, ['test_key'])
|
||||
cs.assert_called('DELETE', '/servers/1234/metadata/test_key')
|
||||
self.cs.servers.delete_meta(1234, ['test_key'])
|
||||
self.assert_called('DELETE', '/servers/1234/metadata/test_key')
|
||||
|
||||
def test_set_server_meta(self):
|
||||
cs.servers.set_meta(1234, {'test_key': 'test_value'})
|
||||
cs.assert_called('POST', '/servers/1234/metadata',
|
||||
{'metadata': {'test_key': 'test_value'}})
|
||||
self.cs.servers.set_meta(1234, {'test_key': 'test_value'})
|
||||
self.assert_called('POST', '/servers/1234/metadata',
|
||||
{'metadata': {'test_key': 'test_value'}})
|
||||
|
||||
def test_set_server_meta_item(self):
|
||||
cs.servers.set_meta_item(1234, 'test_key', 'test_value')
|
||||
cs.assert_called('PUT', '/servers/1234/metadata/test_key',
|
||||
{'meta': {'test_key': 'test_value'}})
|
||||
self.cs.servers.set_meta_item(1234, 'test_key', 'test_value')
|
||||
self.assert_called('PUT', '/servers/1234/metadata/test_key',
|
||||
{'meta': {'test_key': 'test_value'}})
|
||||
|
||||
def test_find(self):
|
||||
server = cs.servers.find(name='sample-server')
|
||||
cs.assert_called('GET', '/servers', pos=-2)
|
||||
cs.assert_called('GET', '/servers/1234', pos=-1)
|
||||
self.assertEqual(server.name, 'sample-server')
|
||||
server = self.cs.servers.find(name='sample-server')
|
||||
self.assert_called('GET', '/servers/1234')
|
||||
self.assertEqual('sample-server', server.name)
|
||||
|
||||
self.assertRaises(exceptions.NoUniqueMatch, cs.servers.find,
|
||||
self.assertRaises(exceptions.NoUniqueMatch, self.cs.servers.find,
|
||||
flavor={"id": 1, "name": "256 MB Server"})
|
||||
|
||||
sl = cs.servers.findall(flavor={"id": 1, "name": "256 MB Server"})
|
||||
self.assertEqual([s.id for s in sl], [1234, 5678, 9012])
|
||||
sl = self.cs.servers.findall(flavor={"id": 1, "name": "256 MB Server"})
|
||||
self.assertEqual([1234, 5678, 9012], [s.id for s in sl])
|
||||
|
||||
def test_reboot_server(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.reboot()
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
cs.servers.reboot(s, reboot_type='HARD')
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
self.cs.servers.reboot(s, reboot_type='HARD')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
def test_rebuild_server(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.rebuild(image=1)
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
cs.servers.rebuild(s, image=1)
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
self.cs.servers.rebuild(s, image=1)
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
s.rebuild(image=1, password='5678')
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
cs.servers.rebuild(s, image=1, password='5678')
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
self.cs.servers.rebuild(s, image=1, password='5678')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
def _rebuild_resize_disk_config(self, disk_config, operation="rebuild"):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
|
||||
if operation == "rebuild":
|
||||
s.rebuild(image=1, disk_config=disk_config)
|
||||
elif operation == "resize":
|
||||
s.resize(flavor=1, disk_config=disk_config)
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
# verify disk config param was used in the request:
|
||||
last_request = cs.client.callstack[-1]
|
||||
body = last_request[-1]
|
||||
body = jsonutils.loads(self.requests.last_request.body)
|
||||
|
||||
d = body[operation]
|
||||
self.assertTrue('OS-DCF:diskConfig' in d)
|
||||
@ -289,20 +293,31 @@ class ServersTest(utils.TestCase):
|
||||
self._rebuild_resize_disk_config('MANUAL')
|
||||
|
||||
def test_rebuild_server_preserve_ephemeral(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.rebuild(image=1, preserve_ephemeral=True)
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
body = cs.client.callstack[-1][-1]
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
body = jsonutils.loads(self.requests.last_request.body)
|
||||
d = body['rebuild']
|
||||
self.assertIn('preserve_ephemeral', d)
|
||||
self.assertEqual(d['preserve_ephemeral'], True)
|
||||
self.assertEqual(True, d['preserve_ephemeral'])
|
||||
|
||||
def test_rebuild_server_name_meta_files(self):
|
||||
files = {'/etc/passwd': 'some data'}
|
||||
s = self.cs.servers.get(1234)
|
||||
s.rebuild(image=1, name='new', meta={'foo': 'bar'}, files=files)
|
||||
body = jsonutils.loads(self.requests.last_request.body)
|
||||
d = body['rebuild']
|
||||
self.assertEqual('new', d['name'])
|
||||
self.assertEqual({'foo': 'bar'}, d['metadata'])
|
||||
self.assertEqual('/etc/passwd',
|
||||
d['personality'][0]['path'])
|
||||
|
||||
def test_resize_server(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.resize(flavor=1)
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
cs.servers.resize(s, flavor=1)
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
self.cs.servers.resize(s, flavor=1)
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
def test_resize_server_disk_config_auto(self):
|
||||
self._rebuild_resize_disk_config('AUTO', 'resize')
|
||||
@ -311,162 +326,163 @@ class ServersTest(utils.TestCase):
|
||||
self._rebuild_resize_disk_config('MANUAL', 'resize')
|
||||
|
||||
def test_confirm_resized_server(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.confirm_resize()
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
cs.servers.confirm_resize(s)
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
self.cs.servers.confirm_resize(s)
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
def test_revert_resized_server(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.revert_resize()
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
cs.servers.revert_resize(s)
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
self.cs.servers.revert_resize(s)
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
def test_migrate_server(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.migrate()
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
cs.servers.migrate(s)
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
self.cs.servers.migrate(s)
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
def test_add_fixed_ip(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.add_fixed_ip(1)
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
cs.servers.add_fixed_ip(s, 1)
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
self.cs.servers.add_fixed_ip(s, 1)
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
def test_remove_fixed_ip(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.remove_fixed_ip('10.0.0.1')
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
cs.servers.remove_fixed_ip(s, '10.0.0.1')
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
self.cs.servers.remove_fixed_ip(s, '10.0.0.1')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
def test_add_floating_ip(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.add_floating_ip('11.0.0.1')
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
cs.servers.add_floating_ip(s, '11.0.0.1')
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
f = cs.floating_ips.list()[0]
|
||||
cs.servers.add_floating_ip(s, f)
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
self.cs.servers.add_floating_ip(s, '11.0.0.1')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
f = self.cs.floating_ips.list()[0]
|
||||
self.cs.servers.add_floating_ip(s, f)
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
s.add_floating_ip(f)
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
def test_add_floating_ip_to_fixed(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.add_floating_ip('11.0.0.1', fixed_address='12.0.0.1')
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
cs.servers.add_floating_ip(s, '11.0.0.1',
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
self.cs.servers.add_floating_ip(s, '11.0.0.1',
|
||||
fixed_address='12.0.0.1')
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
f = cs.floating_ips.list()[0]
|
||||
cs.servers.add_floating_ip(s, f)
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
f = self.cs.floating_ips.list()[0]
|
||||
self.cs.servers.add_floating_ip(s, f)
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
s.add_floating_ip(f)
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
def test_remove_floating_ip(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.remove_floating_ip('11.0.0.1')
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
cs.servers.remove_floating_ip(s, '11.0.0.1')
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
f = cs.floating_ips.list()[0]
|
||||
cs.servers.remove_floating_ip(s, f)
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
self.cs.servers.remove_floating_ip(s, '11.0.0.1')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
f = self.cs.floating_ips.list()[0]
|
||||
self.cs.servers.remove_floating_ip(s, f)
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
s.remove_floating_ip(f)
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
def test_stop(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.stop()
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
cs.servers.stop(s)
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
self.cs.servers.stop(s)
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
def test_force_delete(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.force_delete()
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
cs.servers.force_delete(s)
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
self.cs.servers.force_delete(s)
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
def test_restore(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.restore()
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
cs.servers.restore(s)
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
self.cs.servers.restore(s)
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
def test_start(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.start()
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
cs.servers.start(s)
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
self.cs.servers.start(s)
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
def test_rescue(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.rescue()
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
cs.servers.rescue(s)
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
self.cs.servers.rescue(s)
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
def test_unrescue(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.unrescue()
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
cs.servers.unrescue(s)
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
self.cs.servers.unrescue(s)
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
def test_lock(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.lock()
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
cs.servers.lock(s)
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
self.cs.servers.lock(s)
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
def test_unlock(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.unlock()
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
cs.servers.unlock(s)
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
self.cs.servers.unlock(s)
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
def test_backup(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.backup('back1', 'daily', 1)
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
cs.servers.backup(s, 'back1', 'daily', 2)
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
self.cs.servers.backup(s, 'back1', 'daily', 2)
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
def test_get_console_output_without_length(self):
|
||||
success = 'foo'
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.get_console_output()
|
||||
self.assertEqual(s.get_console_output(), success)
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.assertEqual(success, s.get_console_output())
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
cs.servers.get_console_output(s)
|
||||
self.assertEqual(cs.servers.get_console_output(s), success)
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.cs.servers.get_console_output(s)
|
||||
self.assertEqual(success, self.cs.servers.get_console_output(s))
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
def test_get_console_output_with_length(self):
|
||||
success = 'foo'
|
||||
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.get_console_output(length=50)
|
||||
self.assertEqual(s.get_console_output(length=50), success)
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.assertEqual(success, s.get_console_output(length=50))
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
cs.servers.get_console_output(s, length=50)
|
||||
self.assertEqual(cs.servers.get_console_output(s, length=50), success)
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.cs.servers.get_console_output(s, length=50)
|
||||
self.assertEqual(success,
|
||||
self.cs.servers.get_console_output(s, length=50))
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
# Testing password methods with the following password and key
|
||||
#
|
||||
@ -483,126 +499,135 @@ class ServersTest(utils.TestCase):
|
||||
# Hi/fmZZNQQqj1Ijq0caOIw==
|
||||
|
||||
def test_get_password(self):
|
||||
s = cs.servers.get(1234)
|
||||
self.assertEqual(s.get_password('novaclient/tests/idfake.pem'),
|
||||
b'FooBar123')
|
||||
cs.assert_called('GET', '/servers/1234/os-server-password')
|
||||
s = self.cs.servers.get(1234)
|
||||
self.assertEqual(b'FooBar123',
|
||||
s.get_password('novaclient/tests/idfake.pem'))
|
||||
self.assert_called('GET', '/servers/1234/os-server-password')
|
||||
|
||||
def test_get_password_without_key(self):
|
||||
s = cs.servers.get(1234)
|
||||
self.assertEqual(s.get_password(),
|
||||
s = self.cs.servers.get(1234)
|
||||
self.assertEqual(
|
||||
'OIuEuQttO8Rk93BcKlwHQsziDAnkAm/V6V8VPToA8ZeUaUBWwS0gwo2K6Y61Z96r'
|
||||
'qG447iRz0uTEEYq3RAYJk1mh3mMIRVl27t8MtIecR5ggVVbz1S9AwXJQypDKl0ho'
|
||||
'QFvhCBcMWPohyGewDJOhDbtuN1IoFI9G55ZvFwCm5y7m7B2aVcoLeIsJZE4PLsIw'
|
||||
'/y5a6Z3/AoJZYGG7IH5WN88UROU3B9JZGFB2qtPLQTOvDMZLUhoPRIJeHiVSlo1N'
|
||||
'tI2/++UsXVg3ow6ItqCJGgdNuGG5JB+bslDHWPxROpesEIHdczk46HCpHQN8f1sk'
|
||||
'Hi/fmZZNQQqj1Ijq0caOIw==')
|
||||
cs.assert_called('GET', '/servers/1234/os-server-password')
|
||||
'Hi/fmZZNQQqj1Ijq0caOIw==', s.get_password())
|
||||
self.assert_called('GET', '/servers/1234/os-server-password')
|
||||
|
||||
def test_clear_password(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.clear_password()
|
||||
cs.assert_called('DELETE', '/servers/1234/os-server-password')
|
||||
self.assert_called('DELETE', '/servers/1234/os-server-password')
|
||||
|
||||
def test_get_server_diagnostics(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
diagnostics = s.diagnostics()
|
||||
self.assertTrue(diagnostics is not None)
|
||||
cs.assert_called('GET', '/servers/1234/diagnostics')
|
||||
self.assert_called('GET', '/servers/1234/diagnostics')
|
||||
|
||||
diagnostics_from_manager = cs.servers.diagnostics(1234)
|
||||
diagnostics_from_manager = self.cs.servers.diagnostics(1234)
|
||||
self.assertTrue(diagnostics_from_manager is not None)
|
||||
cs.assert_called('GET', '/servers/1234/diagnostics')
|
||||
self.assert_called('GET', '/servers/1234/diagnostics')
|
||||
|
||||
self.assertEqual(diagnostics, diagnostics_from_manager)
|
||||
self.assertEqual(diagnostics[1], diagnostics_from_manager[1])
|
||||
|
||||
def test_get_vnc_console(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.get_vnc_console('fake')
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
cs.servers.get_vnc_console(s, 'fake')
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.cs.servers.get_vnc_console(s, 'fake')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
def test_get_spice_console(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.get_spice_console('fake')
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
cs.servers.get_spice_console(s, 'fake')
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.cs.servers.get_spice_console(s, 'fake')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
def test_get_serial_console(self):
|
||||
s = self.cs.servers.get(1234)
|
||||
s.get_serial_console('fake')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
self.cs.servers.get_serial_console(s, 'fake')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
def test_get_rdp_console(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.get_rdp_console('fake')
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
cs.servers.get_rdp_console(s, 'fake')
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.cs.servers.get_rdp_console(s, 'fake')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
def test_create_image(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.create_image('123')
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
s.create_image('123', {})
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
cs.servers.create_image(s, '123')
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
cs.servers.create_image(s, '123', {})
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
self.cs.servers.create_image(s, '123')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
self.cs.servers.create_image(s, '123', {})
|
||||
|
||||
def test_live_migrate_server(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.live_migrate(host='hostname', block_migration=False,
|
||||
disk_over_commit=False)
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
cs.servers.live_migrate(s, host='hostname', block_migration=False,
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
self.cs.servers.live_migrate(s, host='hostname', block_migration=False,
|
||||
disk_over_commit=False)
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
def test_reset_state(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.reset_state('newstate')
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
cs.servers.reset_state(s, 'newstate')
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
self.cs.servers.reset_state(s, 'newstate')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
def test_reset_network(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.reset_network()
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
cs.servers.reset_network(s)
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
self.cs.servers.reset_network(s)
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
def test_add_security_group(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.add_security_group('newsg')
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
cs.servers.add_security_group(s, 'newsg')
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
self.cs.servers.add_security_group(s, 'newsg')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
def test_remove_security_group(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.remove_security_group('oldsg')
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
cs.servers.remove_security_group(s, 'oldsg')
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
self.cs.servers.remove_security_group(s, 'oldsg')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
def test_list_security_group(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.list_security_group()
|
||||
cs.assert_called('GET', '/servers/1234/os-security-groups')
|
||||
self.assert_called('GET', '/servers/1234/os-security-groups')
|
||||
|
||||
def test_evacuate(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.evacuate('fake_target_host', 'True')
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
cs.servers.evacuate(s, 'fake_target_host', 'False', 'NewAdminPassword')
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
self.cs.servers.evacuate(s, 'fake_target_host',
|
||||
'False', 'NewAdminPassword')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
def test_interface_list(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.interface_list()
|
||||
cs.assert_called('GET', '/servers/1234/os-interface')
|
||||
self.assert_called('GET', '/servers/1234/os-interface')
|
||||
|
||||
def test_interface_list_result_string_representable(self):
|
||||
"""Test for bugs.launchpad.net/python-novaclient/+bug/1280453."""
|
||||
@ -631,11 +656,11 @@ class ServersTest(utils.TestCase):
|
||||
self.assertEqual('<Server: unknown-name>', '%r' % s)
|
||||
|
||||
def test_interface_attach(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.interface_attach(None, None, None)
|
||||
cs.assert_called('POST', '/servers/1234/os-interface')
|
||||
self.assert_called('POST', '/servers/1234/os-interface')
|
||||
|
||||
def test_interface_detach(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.interface_detach('port-id')
|
||||
cs.assert_called('DELETE', '/servers/1234/os-interface/port-id')
|
||||
self.assert_called('DELETE', '/servers/1234/os-interface/port-id')
|
||||
|
||||
@ -35,8 +35,8 @@ class ServicesTest(utils.TestCase):
|
||||
self.cs.assert_called('GET', '/os-services')
|
||||
for s in svs:
|
||||
self.assertIsInstance(s, self._get_service_type())
|
||||
self.assertEqual(s.binary, 'nova-compute')
|
||||
self.assertEqual(s.host, 'host1')
|
||||
self.assertEqual('nova-compute', s.binary)
|
||||
self.assertEqual('host1', s.host)
|
||||
self.assertTrue(str(s).startswith('<Service: '))
|
||||
|
||||
def test_list_services_with_hostname(self):
|
||||
@ -44,16 +44,16 @@ class ServicesTest(utils.TestCase):
|
||||
self.cs.assert_called('GET', '/os-services?host=host2')
|
||||
for s in svs:
|
||||
self.assertIsInstance(s, self._get_service_type())
|
||||
self.assertEqual(s.binary, 'nova-compute')
|
||||
self.assertEqual(s.host, 'host2')
|
||||
self.assertEqual('nova-compute', s.binary)
|
||||
self.assertEqual('host2', s.host)
|
||||
|
||||
def test_list_services_with_binary(self):
|
||||
svs = self.cs.services.list(binary='nova-cert')
|
||||
self.cs.assert_called('GET', '/os-services?binary=nova-cert')
|
||||
for s in svs:
|
||||
self.assertIsInstance(s, self._get_service_type())
|
||||
self.assertEqual(s.binary, 'nova-cert')
|
||||
self.assertEqual(s.host, 'host1')
|
||||
self.assertEqual('nova-cert', s.binary)
|
||||
self.assertEqual('host1', s.host)
|
||||
|
||||
def test_list_services_with_host_binary(self):
|
||||
svs = self.cs.services.list(host='host2', binary='nova-cert')
|
||||
@ -61,8 +61,8 @@ class ServicesTest(utils.TestCase):
|
||||
'/os-services?host=host2&binary=nova-cert')
|
||||
for s in svs:
|
||||
self.assertIsInstance(s, self._get_service_type())
|
||||
self.assertEqual(s.binary, 'nova-cert')
|
||||
self.assertEqual(s.host, 'host2')
|
||||
self.assertEqual('nova-cert', s.binary)
|
||||
self.assertEqual('host2', s.host)
|
||||
|
||||
def _update_body(self, host, binary, disabled_reason=None):
|
||||
body = {"host": host,
|
||||
@ -76,7 +76,7 @@ class ServicesTest(utils.TestCase):
|
||||
values = self._update_body("host1", "nova-cert")
|
||||
self.cs.assert_called('PUT', '/os-services/enable', values)
|
||||
self.assertIsInstance(service, self._get_service_type())
|
||||
self.assertEqual(service.status, 'enabled')
|
||||
self.assertEqual('enabled', service.status)
|
||||
|
||||
def test_services_delete(self):
|
||||
self.cs.services.delete('1')
|
||||
@ -87,7 +87,7 @@ class ServicesTest(utils.TestCase):
|
||||
values = self._update_body("host1", "nova-cert")
|
||||
self.cs.assert_called('PUT', '/os-services/disable', values)
|
||||
self.assertIsInstance(service, self._get_service_type())
|
||||
self.assertEqual(service.status, 'disabled')
|
||||
self.assertEqual('disabled', service.status)
|
||||
|
||||
def test_services_disable_log_reason(self):
|
||||
service = self.cs.services.disable_log_reason(
|
||||
@ -96,4 +96,4 @@ class ServicesTest(utils.TestCase):
|
||||
"disable bad host")
|
||||
self.cs.assert_called('PUT', '/os-services/disable-log-reason', values)
|
||||
self.assertIsInstance(service, self._get_service_type())
|
||||
self.assertEqual(service.status, 'disabled')
|
||||
self.assertEqual('disabled', service.status)
|
||||
|
||||
@ -22,6 +22,7 @@ import os
|
||||
|
||||
import fixtures
|
||||
import mock
|
||||
from oslo.utils import timeutils
|
||||
import six
|
||||
from six.moves import builtins
|
||||
|
||||
@ -266,7 +267,10 @@ class ShellTest(utils.TestCase):
|
||||
{
|
||||
'volume_id': 'blah',
|
||||
'delete_on_termination': '0',
|
||||
'device_name': 'vda'
|
||||
'device_name': 'vda',
|
||||
'uuid': 'blah',
|
||||
'boot_index': 0,
|
||||
'source_type': ''
|
||||
}
|
||||
],
|
||||
'imageRef': '',
|
||||
@ -652,7 +656,7 @@ class ShellTest(utils.TestCase):
|
||||
'max_count': 1,
|
||||
}},
|
||||
)
|
||||
self.assertEqual(poll_method.call_count, 1)
|
||||
self.assertEqual(1, poll_method.call_count)
|
||||
poll_method.assert_has_calls(
|
||||
[mock.call(self.shell.cs.servers.get, 1234, 'building',
|
||||
['active'])])
|
||||
@ -853,7 +857,7 @@ class ShellTest(utils.TestCase):
|
||||
|
||||
def test_rebuild(self):
|
||||
output = self.run_command('rebuild sample-server 1')
|
||||
self.assert_called('GET', '/servers', pos=-6)
|
||||
self.assert_called('GET', '/servers?name=sample-server', pos=-6)
|
||||
self.assert_called('GET', '/servers/1234', pos=-5)
|
||||
self.assert_called('GET', '/images/1', pos=-4)
|
||||
self.assert_called('POST', '/servers/1234/action',
|
||||
@ -865,7 +869,7 @@ class ShellTest(utils.TestCase):
|
||||
def test_rebuild_password(self):
|
||||
output = self.run_command('rebuild sample-server 1'
|
||||
' --rebuild-password asdf')
|
||||
self.assert_called('GET', '/servers', pos=-6)
|
||||
self.assert_called('GET', '/servers?name=sample-server', pos=-6)
|
||||
self.assert_called('GET', '/servers/1234', pos=-5)
|
||||
self.assert_called('GET', '/images/1', pos=-4)
|
||||
self.assert_called('POST', '/servers/1234/action',
|
||||
@ -877,7 +881,7 @@ class ShellTest(utils.TestCase):
|
||||
|
||||
def test_rebuild_preserve_ephemeral(self):
|
||||
self.run_command('rebuild sample-server 1 --preserve-ephemeral')
|
||||
self.assert_called('GET', '/servers', pos=-6)
|
||||
self.assert_called('GET', '/servers?name=sample-server', pos=-6)
|
||||
self.assert_called('GET', '/servers/1234', pos=-5)
|
||||
self.assert_called('GET', '/images/1', pos=-4)
|
||||
self.assert_called('POST', '/servers/1234/action',
|
||||
@ -886,6 +890,19 @@ class ShellTest(utils.TestCase):
|
||||
self.assert_called('GET', '/flavors/1', pos=-2)
|
||||
self.assert_called('GET', '/images/2')
|
||||
|
||||
def test_rebuild_name_meta(self):
|
||||
self.run_command('rebuild sample-server 1 --name asdf --meta '
|
||||
'foo=bar')
|
||||
self.assert_called('GET', '/servers?name=sample-server', pos=-6)
|
||||
self.assert_called('GET', '/servers/1234', pos=-5)
|
||||
self.assert_called('GET', '/images/1', pos=-4)
|
||||
self.assert_called('POST', '/servers/1234/action',
|
||||
{'rebuild': {'imageRef': 1,
|
||||
'name': 'asdf',
|
||||
'metadata': {'foo': 'bar'}}}, pos=-3)
|
||||
self.assert_called('GET', '/flavors/1', pos=-2)
|
||||
self.assert_called('GET', '/images/2')
|
||||
|
||||
def test_start(self):
|
||||
self.run_command('start sample-server')
|
||||
self.assert_called('POST', '/servers/1234/action', {'os-start': None})
|
||||
@ -1026,17 +1043,19 @@ class ShellTest(utils.TestCase):
|
||||
self.assert_called('DELETE', '/servers/1234', pos=-3)
|
||||
self.assert_called('DELETE', '/servers/5678', pos=-1)
|
||||
self.run_command('delete sample-server sample-server2')
|
||||
self.assert_called('GET', '/servers', pos=-6)
|
||||
self.assert_called('GET', '/servers?name=sample-server', pos=-6)
|
||||
self.assert_called('GET', '/servers/1234', pos=-5)
|
||||
self.assert_called('DELETE', '/servers/1234', pos=-4)
|
||||
self.assert_called('GET', '/servers', pos=-3)
|
||||
self.assert_called('GET', '/servers?name=sample-server2', pos=-3)
|
||||
self.assert_called('GET', '/servers/5678', pos=-2)
|
||||
self.assert_called('DELETE', '/servers/5678', pos=-1)
|
||||
|
||||
def test_delete_two_with_one_nonexistent(self):
|
||||
self.run_command('delete 1234 123456789')
|
||||
cmd = 'delete 1234 123456789'
|
||||
self.assertRaises(exceptions.CommandError, self.run_command, cmd)
|
||||
self.assert_called_anytime('DELETE', '/servers/1234')
|
||||
self.run_command('delete sample-server nonexistentserver')
|
||||
cmd = 'delete sample-server nonexistentserver'
|
||||
self.assertRaises(exceptions.CommandError, self.run_command, cmd)
|
||||
self.assert_called_anytime('DELETE', '/servers/1234')
|
||||
|
||||
def test_delete_one_with_one_nonexistent(self):
|
||||
@ -1214,9 +1233,9 @@ class ShellTest(utils.TestCase):
|
||||
'end=2005-02-01T00:00:00&' +
|
||||
'detailed=1')
|
||||
|
||||
@mock.patch('novaclient.openstack.common.timeutils.utcnow')
|
||||
def test_usage_list_no_args(self, mock_utcnow):
|
||||
mock_utcnow.return_value = datetime.datetime(2005, 2, 1, 0, 0)
|
||||
def test_usage_list_no_args(self):
|
||||
timeutils.set_time_override(datetime.datetime(2005, 2, 1, 0, 0))
|
||||
self.addCleanup(timeutils.clear_time_override)
|
||||
self.run_command('usage-list')
|
||||
self.assert_called('GET',
|
||||
'/os-simple-tenant-usage?' +
|
||||
@ -1293,17 +1312,29 @@ class ShellTest(utils.TestCase):
|
||||
self.assert_called('PUT', '/os-aggregates/1', body, pos=-2)
|
||||
self.assert_called('GET', '/os-aggregates/1', pos=-1)
|
||||
|
||||
def test_aggregate_set_metadata_by_id(self):
|
||||
self.run_command('aggregate-set-metadata 1 foo=bar delete_key')
|
||||
body = {"set_metadata": {"metadata": {"foo": "bar",
|
||||
"delete_key": None}}}
|
||||
self.assert_called('POST', '/os-aggregates/1/action', body, pos=-2)
|
||||
self.assert_called('GET', '/os-aggregates/1', pos=-1)
|
||||
def test_aggregate_set_metadata_add_by_id(self):
|
||||
self.run_command('aggregate-set-metadata 3 foo=bar')
|
||||
body = {"set_metadata": {"metadata": {"foo": "bar"}}}
|
||||
self.assert_called('POST', '/os-aggregates/3/action', body, pos=-2)
|
||||
self.assert_called('GET', '/os-aggregates/3', pos=-1)
|
||||
|
||||
def test_aggregate_set_metadata_add_duplicate_by_id(self):
|
||||
cmd = 'aggregate-set-metadata 3 test=dup'
|
||||
self.assertRaises(exceptions.CommandError, self.run_command, cmd)
|
||||
|
||||
def test_aggregate_set_metadata_delete_by_id(self):
|
||||
self.run_command('aggregate-set-metadata 3 none_key')
|
||||
body = {"set_metadata": {"metadata": {"none_key": None}}}
|
||||
self.assert_called('POST', '/os-aggregates/3/action', body, pos=-2)
|
||||
self.assert_called('GET', '/os-aggregates/3', pos=-1)
|
||||
|
||||
def test_aggregate_set_metadata_delete_missing_by_id(self):
|
||||
cmd = 'aggregate-set-metadata 3 delete_key2'
|
||||
self.assertRaises(exceptions.CommandError, self.run_command, cmd)
|
||||
|
||||
def test_aggregate_set_metadata_by_name(self):
|
||||
self.run_command('aggregate-set-metadata test foo=bar delete_key')
|
||||
body = {"set_metadata": {"metadata": {"foo": "bar",
|
||||
"delete_key": None}}}
|
||||
self.run_command('aggregate-set-metadata test foo=bar')
|
||||
body = {"set_metadata": {"metadata": {"foo": "bar"}}}
|
||||
self.assert_called('POST', '/os-aggregates/1/action', body, pos=-2)
|
||||
self.assert_called('GET', '/os-aggregates/1', pos=-1)
|
||||
|
||||
@ -1511,17 +1542,13 @@ class ShellTest(utils.TestCase):
|
||||
self.run_command('host-evacuate --on-shared-storage hyper')
|
||||
self.assert_called('GET', '/os-hypervisors/hyper/servers', pos=0)
|
||||
self.assert_called('POST', '/servers/uuid1/action',
|
||||
{'evacuate': {'host': None,
|
||||
'onSharedStorage': True}}, pos=1)
|
||||
{'evacuate': {'onSharedStorage': True}}, pos=1)
|
||||
self.assert_called('POST', '/servers/uuid2/action',
|
||||
{'evacuate': {'host': None,
|
||||
'onSharedStorage': True}}, pos=2)
|
||||
{'evacuate': {'onSharedStorage': True}}, pos=2)
|
||||
self.assert_called('POST', '/servers/uuid3/action',
|
||||
{'evacuate': {'host': None,
|
||||
'onSharedStorage': True}}, pos=3)
|
||||
{'evacuate': {'onSharedStorage': True}}, pos=3)
|
||||
self.assert_called('POST', '/servers/uuid4/action',
|
||||
{'evacuate': {'host': None,
|
||||
'onSharedStorage': True}}, pos=4)
|
||||
{'evacuate': {'onSharedStorage': True}}, pos=4)
|
||||
|
||||
def test_host_servers_migrate(self):
|
||||
self.run_command('host-servers-migrate hyper')
|
||||
@ -1656,7 +1683,8 @@ class ShellTest(utils.TestCase):
|
||||
'--instances', '--cores', '--ram', '--floating-ips', '--fixed-ips',
|
||||
'--metadata-items', '--injected-files',
|
||||
'--injected-file-content-bytes', '--injected-file-path-bytes',
|
||||
'--key-pairs', '--security-groups', '--security-group-rules'
|
||||
'--key-pairs', '--security-groups', '--security-group-rules',
|
||||
'--server-groups', '--server-group-members'
|
||||
)
|
||||
for arg in args:
|
||||
self.run_command('quota-class-update '
|
||||
@ -1672,6 +1700,13 @@ class ShellTest(utils.TestCase):
|
||||
self.run_command('network-list')
|
||||
self.assert_called('GET', '/os-networks')
|
||||
|
||||
def test_network_list_fields(self):
|
||||
output = self.run_command('network-list --fields '
|
||||
'vlan,project_id')
|
||||
self.assert_called('GET', '/os-networks')
|
||||
self.assertIn('1234', output)
|
||||
self.assertIn('4ffc664c198e435e9853f2538fbcd7a7', output)
|
||||
|
||||
def test_network_show(self):
|
||||
self.run_command('network-show 1')
|
||||
self.assert_called('GET', '/os-networks/1')
|
||||
@ -1757,16 +1792,32 @@ class ShellTest(utils.TestCase):
|
||||
self.run_command('network-create --fixed-range-v4 192.168.0.0/24'
|
||||
' --vlan=200 new_network')
|
||||
body = {'network': {'cidr': '192.168.0.0/24', 'label': 'new_network',
|
||||
'vlan': '200'}}
|
||||
'vlan': 200}}
|
||||
self.assert_called('POST', '/os-networks', body)
|
||||
|
||||
def test_network_create_vlan_start(self):
|
||||
self.run_command('network-create --fixed-range-v4 192.168.0.0/24'
|
||||
' --vlan-start=100 new_network')
|
||||
body = {'network': {'cidr': '192.168.0.0/24', 'label': 'new_network',
|
||||
'vlan_start': '100'}}
|
||||
'vlan_start': 100}}
|
||||
self.assert_called('POST', '/os-networks', body)
|
||||
|
||||
def test_network_create_extra_args(self):
|
||||
self.run_command('network-create --fixed-range-v4 192.168.0.0/24'
|
||||
' --enable-dhcp F --dhcp-server 192.168.0.2'
|
||||
' --share-address T --allowed-start 192.168.0.10'
|
||||
' --allowed-end 192.168.0.20 --mtu 9000 new_network')
|
||||
body = {'network': {'cidr': '192.168.0.0/24', 'label': 'new_network',
|
||||
'enable_dhcp': False, 'dhcp_server': '192.168.0.2',
|
||||
'share_address': True, 'mtu': 9000,
|
||||
'allowed_start': '192.168.0.10',
|
||||
'allowed_end': '192.168.0.20'}}
|
||||
self.assert_called('POST', '/os-networks', body)
|
||||
|
||||
def test_network_delete(self):
|
||||
self.run_command('network-delete 1')
|
||||
self.assert_called('DELETE', '/os-networks/1')
|
||||
|
||||
def test_add_fixed_ip(self):
|
||||
self.run_command('add-fixed-ip sample-server 1')
|
||||
self.assert_called('POST', '/servers/1234/action',
|
||||
@ -1810,16 +1861,24 @@ class ShellTest(utils.TestCase):
|
||||
{'evacuate': {'host': 'new_host',
|
||||
'onSharedStorage': False,
|
||||
'adminPass': 'NewAdminPass'}})
|
||||
self.run_command('evacuate sample-server new_host')
|
||||
self.assert_called('POST', '/servers/1234/action',
|
||||
{'evacuate': {'host': 'new_host',
|
||||
'onSharedStorage': False}})
|
||||
self.run_command('evacuate sample-server new_host '
|
||||
'--on-shared-storage')
|
||||
self.assert_called('POST', '/servers/1234/action',
|
||||
{'evacuate': {'host': 'new_host',
|
||||
'onSharedStorage': True}})
|
||||
|
||||
def test_evacuate_with_no_target_host(self):
|
||||
self.run_command('evacuate sample-server')
|
||||
self.assert_called('POST', '/servers/1234/action',
|
||||
{'evacuate': {'onSharedStorage': False}})
|
||||
self.run_command('evacuate sample-server --password NewAdminPass')
|
||||
self.assert_called('POST', '/servers/1234/action',
|
||||
{'evacuate': {'onSharedStorage': False,
|
||||
'adminPass': 'NewAdminPass'}})
|
||||
self.run_command('evacuate sample-server --on-shared-storage')
|
||||
self.assert_called('POST', '/servers/1234/action',
|
||||
{'evacuate': {'onSharedStorage': True}})
|
||||
|
||||
def test_get_password(self):
|
||||
self.run_command('get-password sample-server /foo/id_rsa')
|
||||
self.assert_called('GET', '/servers/1234/os-server-password')
|
||||
@ -1937,7 +1996,7 @@ class ShellTest(utils.TestCase):
|
||||
|
||||
def test_volume_show(self):
|
||||
self.run_command('volume-show Work')
|
||||
self.assert_called('GET', '/volumes', pos=-2)
|
||||
self.assert_called('GET', '/volumes?name=Work', pos=-2)
|
||||
self.assert_called(
|
||||
'GET',
|
||||
'/volumes/15e59938-07d5-11e1-90e3-e3dffe0c5983',
|
||||
@ -2031,10 +2090,15 @@ class ShellTest(utils.TestCase):
|
||||
def test_ssh(self, mock_system, mock_find_server):
|
||||
class FakeResources(object):
|
||||
addresses = {
|
||||
"private": [{'version': 4, 'addr': "1.1.1.1"},
|
||||
{'version': 6, 'addr': "2607:f0d0:1002::4"}],
|
||||
"public": [{'version': 4, 'addr': "2.2.2.2"},
|
||||
{'version': 6, 'addr': "7612:a1b2:2004::6"}]
|
||||
"skynet": [
|
||||
{'version': 4, 'addr': "1.1.1.1",
|
||||
"OS-EXT-IPS:type": 'fixed'},
|
||||
{'version': 4, 'addr': "2.2.2.2",
|
||||
"OS-EXT-IPS:type": 'floating'},
|
||||
{'version': 6, 'addr': "2607:f0d0:1002::4",
|
||||
"OS-EXT-IPS:type": 'fixed'},
|
||||
{'version': 6, 'addr': "7612:a1b2:2004::6"}
|
||||
]
|
||||
}
|
||||
mock_find_server.return_value = FakeResources()
|
||||
|
||||
@ -2069,6 +2133,33 @@ class ShellTest(utils.TestCase):
|
||||
mock_system.assert_called_with("ssh -6 -p22 "
|
||||
"root@2607:f0d0:1002::4 -1")
|
||||
|
||||
@mock.patch('novaclient.v1_1.shell._find_server')
|
||||
@mock.patch('os.system')
|
||||
def test_ssh_multinet(self, mock_system, mock_find_server):
|
||||
class FakeResources(object):
|
||||
addresses = {
|
||||
"skynet": [
|
||||
{'version': 4, 'addr': "1.1.1.1",
|
||||
"OS-EXT-IPS:type": 'fixed'},
|
||||
{'version': 4, 'addr': "2.2.2.2"},
|
||||
{'version': 6, 'addr': "2607:f0d0:1002::4",
|
||||
"OS-EXT-IPS:type": 'fixed'}
|
||||
],
|
||||
"other": [
|
||||
{'version': 4, 'addr': "2.3.4.5"},
|
||||
{'version': 6, 'addr': "7612:a1b2:2004::6"}
|
||||
]
|
||||
}
|
||||
mock_find_server.return_value = FakeResources()
|
||||
|
||||
self.run_command("ssh --network other server")
|
||||
mock_system.assert_called_with("ssh -4 -p22 root@2.3.4.5 ")
|
||||
self.run_command("ssh --ipv6 --network other server")
|
||||
mock_system.assert_called_with("ssh -6 -p22 root@7612:a1b2:2004::6 ")
|
||||
self.assertRaises(exceptions.ResourceNotFound,
|
||||
self.run_command,
|
||||
"ssh --ipv6 --network nonexistent server")
|
||||
|
||||
def test_keypair_add(self):
|
||||
self.run_command('keypair-add test')
|
||||
self.assert_called('POST', '/os-keypairs',
|
||||
@ -2116,7 +2207,7 @@ class GetSecgroupTest(utils.TestCase):
|
||||
'security_groups.list.return_value': [],
|
||||
})
|
||||
result = novaclient.v1_1.shell._get_secgroup(cs, '1')
|
||||
self.assertEqual(result, 'sec_group')
|
||||
self.assertEqual('sec_group', result)
|
||||
cs.security_groups.get.assert_called_once_with('1')
|
||||
|
||||
def test_with_uuid(self):
|
||||
@ -2126,7 +2217,7 @@ class GetSecgroupTest(utils.TestCase):
|
||||
})
|
||||
result = novaclient.v1_1.shell._get_secgroup(
|
||||
cs, 'c0c32459-dc5f-44dc-9a0a-473b28bac831')
|
||||
self.assertEqual(result, 'sec_group')
|
||||
self.assertEqual('sec_group', result)
|
||||
cs.security_groups.get.assert_called_once_with(
|
||||
'c0c32459-dc5f-44dc-9a0a-473b28bac831')
|
||||
|
||||
@ -2151,3 +2242,44 @@ class GetSecgroupTest(utils.TestCase):
|
||||
novaclient.v1_1.shell._get_secgroup,
|
||||
cs,
|
||||
'group_one')
|
||||
|
||||
|
||||
class GetFirstEndpointTest(utils.TestCase):
|
||||
def test_only_one_endpoint(self):
|
||||
"""If there is only one endpoint, it is returned."""
|
||||
endpoint = {"url": "test"}
|
||||
result = novaclient.v1_1.shell._get_first_endpoint([endpoint], "XYZ")
|
||||
self.assertEqual(endpoint, result)
|
||||
|
||||
def test_multiple_endpoints(self):
|
||||
"""If there are multiple endpoints, the first one of the appropriate
|
||||
region is returned.
|
||||
|
||||
"""
|
||||
endpoints = [
|
||||
{"region": "XYZ"},
|
||||
{"region": "ORD", "number": 1},
|
||||
{"region": "ORD", "number": 2}
|
||||
]
|
||||
result = novaclient.v1_1.shell._get_first_endpoint(endpoints, "ORD")
|
||||
self.assertEqual(endpoints[1], result)
|
||||
|
||||
def test_multiple_endpoints_but_none_suitable(self):
|
||||
"""If there are multiple endpoints but none of them are suitable, an
|
||||
exception is raised.
|
||||
|
||||
"""
|
||||
endpoints = [
|
||||
{"region": "XYZ"},
|
||||
{"region": "PQR"},
|
||||
{"region": "STU"}
|
||||
]
|
||||
self.assertRaises(LookupError,
|
||||
novaclient.v1_1.shell._get_first_endpoint,
|
||||
endpoints, "ORD")
|
||||
|
||||
def test_no_endpoints(self):
|
||||
"""If there are no endpoints available, an exception is raised."""
|
||||
self.assertRaises(LookupError,
|
||||
novaclient.v1_1.shell._get_first_endpoint,
|
||||
[], "ORD")
|
||||
|
||||
@ -14,9 +14,10 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from datetime import datetime
|
||||
import datetime
|
||||
|
||||
from oslo.utils import strutils
|
||||
|
||||
from novaclient.openstack.common import strutils
|
||||
from novaclient.tests import fakes
|
||||
from novaclient.tests.v1_1 import fakes as fakes_v1_1
|
||||
from novaclient.v3 import client
|
||||
@ -104,14 +105,14 @@ class FakeHTTPClient(fakes_v1_1.FakeHTTPClient):
|
||||
if filter_is_public is not None:
|
||||
if filter_is_public:
|
||||
flavors['flavors'] = [
|
||||
v for v in flavors['flavors']
|
||||
if v['flavor-access:is_public']
|
||||
]
|
||||
v for v in flavors['flavors']
|
||||
if v['flavor-access:is_public']
|
||||
]
|
||||
else:
|
||||
flavors['flavors'] = [
|
||||
v for v in flavors['flavors']
|
||||
if not v['flavor-access:is_public']
|
||||
]
|
||||
v for v in flavors['flavors']
|
||||
if not v['flavor-access:is_public']
|
||||
]
|
||||
|
||||
return (200, {}, flavors)
|
||||
|
||||
@ -197,11 +198,11 @@ class FakeHTTPClient(fakes_v1_1.FakeHTTPClient):
|
||||
}
|
||||
body_param_check_exists = {
|
||||
'rebuild': 'image_ref',
|
||||
'resize': 'flavor_ref'}
|
||||
'resize': 'flavor_ref',
|
||||
'evacuate': 'on_shared_storage'}
|
||||
body_params_check_exact = {
|
||||
'reboot': ['type'],
|
||||
'add_fixed_ip': ['network_id'],
|
||||
'evacuate': ['host', 'on_shared_storage'],
|
||||
'remove_fixed_ip': ['address'],
|
||||
'change_password': ['admin_password'],
|
||||
'get_console_output': ['length'],
|
||||
@ -226,9 +227,6 @@ class FakeHTTPClient(fakes_v1_1.FakeHTTPClient):
|
||||
if action in body_param_check_exists:
|
||||
assert body_param_check_exists[action] in body[action]
|
||||
|
||||
if action == 'evacuate':
|
||||
body[action].pop('admin_password', None)
|
||||
|
||||
if action in body_params_check_exact:
|
||||
assert set(body[action]) == set(body_params_check_exact[action])
|
||||
|
||||
@ -282,7 +280,9 @@ class FakeHTTPClient(fakes_v1_1.FakeHTTPClient):
|
||||
"nova-compute": {"active": True,
|
||||
"available": True,
|
||||
"updated_at":
|
||||
datetime(2012, 12, 26, 14, 45, 25, 0)}}}},
|
||||
datetime.datetime(
|
||||
2012, 12, 26, 14, 45, 25, 0
|
||||
)}}}},
|
||||
{"zone_name": "internal",
|
||||
"zone_state": {"available": True},
|
||||
"hosts": {
|
||||
@ -291,13 +291,17 @@ class FakeHTTPClient(fakes_v1_1.FakeHTTPClient):
|
||||
"active": True,
|
||||
"available": True,
|
||||
"updated_at":
|
||||
datetime(2012, 12, 26, 14, 45, 25, 0)}},
|
||||
datetime.datetime(
|
||||
2012, 12, 26, 14, 45, 25, 0
|
||||
)}},
|
||||
"fake_host-2": {
|
||||
"nova-network": {
|
||||
"active": True,
|
||||
"available": False,
|
||||
"updated_at":
|
||||
datetime(2012, 12, 26, 14, 45, 24, 0)}}}},
|
||||
datetime.datetime(
|
||||
2012, 12, 26, 14, 45, 24, 0
|
||||
)}}}},
|
||||
{"zone_name": "zone-2",
|
||||
"zone_state": {"available": False},
|
||||
"hosts": None}]})
|
||||
@ -319,7 +323,9 @@ class FakeHTTPClient(fakes_v1_1.FakeHTTPClient):
|
||||
'cores': 1,
|
||||
'keypairs': 1,
|
||||
'security_groups': 1,
|
||||
'security_group_rules': 1}})
|
||||
'security_group_rules': 1,
|
||||
'server_groups': 1,
|
||||
'server_group_members': 1}})
|
||||
|
||||
def get_os_quota_sets_test_detail(self, **kw):
|
||||
return (200, {}, {'quota_set': {
|
||||
|
||||
@ -38,7 +38,7 @@ class FlavorsTest(test_flavors.FlavorsTest):
|
||||
"ephemeral": ephemeral,
|
||||
"id": id,
|
||||
"swap": swap,
|
||||
"rxtx_factor": rxtx_factor,
|
||||
"os-flavor-rxtx:rxtx_factor": rxtx_factor,
|
||||
"flavor-access:is_public": is_public,
|
||||
}
|
||||
}
|
||||
|
||||
@ -34,14 +34,29 @@ class HostsTest(utils.FixturedTestCase):
|
||||
self.assert_called('GET', '/os-hosts')
|
||||
for h in hs:
|
||||
self.assertIsInstance(h, hosts.Host)
|
||||
self.assertEqual(h.zone, 'nova1')
|
||||
self.assertEqual('nova1', h.zone)
|
||||
|
||||
def test_list_host_with_zone(self):
|
||||
hs = self.cs.hosts.list('nova')
|
||||
self.assert_called('GET', '/os-hosts?zone=nova')
|
||||
for h in hs:
|
||||
self.assertIsInstance(h, hosts.Host)
|
||||
self.assertEqual('nova', h.zone)
|
||||
|
||||
def test_list_host_with_service(self):
|
||||
hs = self.cs.hosts.list(service='nova-compute')
|
||||
self.assert_called('GET', '/os-hosts?service=nova-compute')
|
||||
for h in hs:
|
||||
self.assertIsInstance(h, hosts.Host)
|
||||
self.assertEqual(h.service, 'nova-compute')
|
||||
|
||||
def test_list_host_with_zone_and_service(self):
|
||||
hs = self.cs.hosts.list(service='nova-compute', zone='nova')
|
||||
self.assert_called('GET', '/os-hosts?zone=nova&service=nova-compute')
|
||||
for h in hs:
|
||||
self.assertIsInstance(h, hosts.Host)
|
||||
self.assertEqual(h.zone, 'nova')
|
||||
self.assertEqual(h.service, 'nova-compute')
|
||||
|
||||
def test_update_enable(self):
|
||||
host = self.cs.hosts.get('sample_host')[0]
|
||||
|
||||
@ -44,14 +44,14 @@ class ImagesTest(utils.FixturedTestCase):
|
||||
i = self.cs.images.get(1)
|
||||
self.assert_called('HEAD', '/v1/images/1')
|
||||
self.assertIsInstance(i, images.Image)
|
||||
self.assertEqual(i.id, '1')
|
||||
self.assertEqual(i.name, 'CentOS 5.2')
|
||||
self.assertEqual('1', i.id)
|
||||
self.assertEqual('CentOS 5.2', i.name)
|
||||
|
||||
def test_find(self):
|
||||
i = self.cs.images.find(name="CentOS 5.2")
|
||||
self.assertEqual(i.id, '1')
|
||||
self.assertEqual('1', i.id)
|
||||
self.assert_called('HEAD', '/v1/images/1')
|
||||
|
||||
iml = self.cs.images.findall(status='SAVING')
|
||||
self.assertEqual(len(iml), 1)
|
||||
self.assertEqual(iml[0].name, 'My Server Backup')
|
||||
self.assertEqual(1, len(iml))
|
||||
self.assertEqual('My Server Backup', iml[0].name)
|
||||
|
||||
@ -17,50 +17,51 @@ import mock
|
||||
import six
|
||||
|
||||
from novaclient import exceptions
|
||||
from novaclient.tests.fixture_data import client
|
||||
from novaclient.tests.fixture_data import servers as data
|
||||
from novaclient.tests import utils
|
||||
from novaclient.tests.v3 import fakes
|
||||
from novaclient.v3 import servers
|
||||
|
||||
|
||||
cs = fakes.FakeClient()
|
||||
class ServersTest(utils.FixturedTestCase):
|
||||
|
||||
|
||||
class ServersTest(utils.TestCase):
|
||||
client_fixture_class = client.V3
|
||||
data_fixture_class = data.V3
|
||||
|
||||
def test_list_servers(self):
|
||||
sl = cs.servers.list()
|
||||
cs.assert_called('GET', '/servers/detail')
|
||||
sl = self.cs.servers.list()
|
||||
self.assert_called('GET', '/servers/detail')
|
||||
for s in sl:
|
||||
self.assertIsInstance(s, servers.Server)
|
||||
|
||||
def test_list_servers_undetailed(self):
|
||||
sl = cs.servers.list(detailed=False)
|
||||
cs.assert_called('GET', '/servers')
|
||||
sl = self.cs.servers.list(detailed=False)
|
||||
self.assert_called('GET', '/servers')
|
||||
for s in sl:
|
||||
self.assertIsInstance(s, servers.Server)
|
||||
|
||||
def test_list_servers_with_marker_limit(self):
|
||||
sl = cs.servers.list(marker=1234, limit=2)
|
||||
cs.assert_called('GET', '/servers/detail?limit=2&marker=1234')
|
||||
sl = self.cs.servers.list(marker=1234, limit=2)
|
||||
self.assert_called('GET', '/servers/detail?limit=2&marker=1234')
|
||||
for s in sl:
|
||||
self.assertIsInstance(s, servers.Server)
|
||||
|
||||
def test_get_server_details(self):
|
||||
s = cs.servers.get(1234)
|
||||
cs.assert_called('GET', '/servers/1234')
|
||||
s = self.cs.servers.get(1234)
|
||||
self.assert_called('GET', '/servers/1234')
|
||||
self.assertIsInstance(s, servers.Server)
|
||||
self.assertEqual(s.id, 1234)
|
||||
self.assertEqual(s.status, 'BUILD')
|
||||
self.assertEqual(1234, s.id)
|
||||
self.assertEqual('BUILD', s.status)
|
||||
|
||||
def test_get_server_promote_details(self):
|
||||
s1 = cs.servers.list(detailed=False)[0]
|
||||
s2 = cs.servers.list(detailed=True)[0]
|
||||
s1 = self.cs.servers.list(detailed=False)[0]
|
||||
s2 = self.cs.servers.list(detailed=True)[0]
|
||||
self.assertNotEqual(s1._info, s2._info)
|
||||
s1.get()
|
||||
self.assertEqual(s1._info, s2._info)
|
||||
|
||||
def test_create_server(self):
|
||||
s = cs.servers.create(
|
||||
s = self.cs.servers.create(
|
||||
name="My server",
|
||||
image=1,
|
||||
flavor=1,
|
||||
@ -72,11 +73,11 @@ class ServersTest(utils.TestCase):
|
||||
'/tmp/foo.txt': six.StringIO('data'), # a stream
|
||||
}
|
||||
)
|
||||
cs.assert_called('POST', '/servers')
|
||||
self.assert_called('POST', '/servers')
|
||||
self.assertIsInstance(s, servers.Server)
|
||||
|
||||
def test_create_server_boot_with_nics_ipv4(self):
|
||||
old_boot = cs.servers._boot
|
||||
old_boot = self.cs.servers._boot
|
||||
nics = [{'net-id': '11111111-1111-1111-1111-111111111111',
|
||||
'v4-fixed-ip': '10.10.0.7'}]
|
||||
|
||||
@ -84,8 +85,8 @@ class ServersTest(utils.TestCase):
|
||||
self.assertEqual(boot_kwargs['nics'], nics)
|
||||
return old_boot(url, key, *boot_args, **boot_kwargs)
|
||||
|
||||
with mock.patch.object(cs.servers, '_boot', wrapped_boot):
|
||||
s = cs.servers.create(
|
||||
with mock.patch.object(self.cs.servers, '_boot', wrapped_boot):
|
||||
s = self.cs.servers.create(
|
||||
name="My server",
|
||||
image=1,
|
||||
flavor=1,
|
||||
@ -94,20 +95,20 @@ class ServersTest(utils.TestCase):
|
||||
key_name="fakekey",
|
||||
nics=nics
|
||||
)
|
||||
cs.assert_called('POST', '/servers')
|
||||
self.assert_called('POST', '/servers')
|
||||
self.assertIsInstance(s, servers.Server)
|
||||
|
||||
def test_create_server_boot_with_nics_ipv6(self):
|
||||
old_boot = cs.servers._boot
|
||||
old_boot = self.cs.servers._boot
|
||||
nics = [{'net-id': '11111111-1111-1111-1111-111111111111',
|
||||
'v6-fixed-ip': '2001:db9:0:1::10'}]
|
||||
|
||||
def wrapped_boot(url, key, *boot_args, **boot_kwargs):
|
||||
self.assertEqual(boot_kwargs['nics'], nics)
|
||||
self.assertEqual(nics, boot_kwargs['nics'])
|
||||
return old_boot(url, key, *boot_args, **boot_kwargs)
|
||||
|
||||
with mock.patch.object(cs.servers, '_boot', wrapped_boot):
|
||||
s = cs.servers.create(
|
||||
with mock.patch.object(self.cs.servers, '_boot', wrapped_boot):
|
||||
s = self.cs.servers.create(
|
||||
name="My server",
|
||||
image=1,
|
||||
flavor=1,
|
||||
@ -116,11 +117,11 @@ class ServersTest(utils.TestCase):
|
||||
key_name="fakekey",
|
||||
nics=nics
|
||||
)
|
||||
cs.assert_called('POST', '/servers')
|
||||
self.assert_called('POST', '/servers')
|
||||
self.assertIsInstance(s, servers.Server)
|
||||
|
||||
def test_create_server_userdata_file_object(self):
|
||||
s = cs.servers.create(
|
||||
s = self.cs.servers.create(
|
||||
name="My server",
|
||||
image=1,
|
||||
flavor=1,
|
||||
@ -131,11 +132,11 @@ class ServersTest(utils.TestCase):
|
||||
'/tmp/foo.txt': six.StringIO('data'), # a stream
|
||||
},
|
||||
)
|
||||
cs.assert_called('POST', '/servers')
|
||||
self.assert_called('POST', '/servers')
|
||||
self.assertIsInstance(s, servers.Server)
|
||||
|
||||
def test_create_server_userdata_unicode(self):
|
||||
s = cs.servers.create(
|
||||
s = self.cs.servers.create(
|
||||
name="My server",
|
||||
image=1,
|
||||
flavor=1,
|
||||
@ -147,11 +148,11 @@ class ServersTest(utils.TestCase):
|
||||
'/tmp/foo.txt': six.StringIO('data'), # a stream
|
||||
},
|
||||
)
|
||||
cs.assert_called('POST', '/servers')
|
||||
self.assert_called('POST', '/servers')
|
||||
self.assertIsInstance(s, servers.Server)
|
||||
|
||||
def test_create_server_userdata_utf8(self):
|
||||
s = cs.servers.create(
|
||||
s = self.cs.servers.create(
|
||||
name="My server",
|
||||
image=1,
|
||||
flavor=1,
|
||||
@ -163,11 +164,11 @@ class ServersTest(utils.TestCase):
|
||||
'/tmp/foo.txt': six.StringIO('data'), # a stream
|
||||
},
|
||||
)
|
||||
cs.assert_called('POST', '/servers')
|
||||
self.assert_called('POST', '/servers')
|
||||
self.assertIsInstance(s, servers.Server)
|
||||
|
||||
def test_create_server_return_reservation_id(self):
|
||||
s = cs.servers.create(
|
||||
s = self.cs.servers.create(
|
||||
name="My server",
|
||||
image=1,
|
||||
flavor=1,
|
||||
@ -183,294 +184,295 @@ class ServersTest(utils.TestCase):
|
||||
'os-multiple-create:return_reservation_id': True,
|
||||
}
|
||||
}
|
||||
cs.assert_called('POST', '/servers', expected_body)
|
||||
self.assert_called('POST', '/servers', expected_body)
|
||||
self.assertIsInstance(s, servers.Server)
|
||||
|
||||
def test_update_server(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
|
||||
# Update via instance
|
||||
s.update(name='hi')
|
||||
cs.assert_called('PUT', '/servers/1234')
|
||||
self.assert_called('PUT', '/servers/1234')
|
||||
s.update(name='hi')
|
||||
cs.assert_called('PUT', '/servers/1234')
|
||||
self.assert_called('PUT', '/servers/1234')
|
||||
|
||||
# Silly, but not an error
|
||||
s.update()
|
||||
|
||||
# Update via manager
|
||||
cs.servers.update(s, name='hi')
|
||||
cs.assert_called('PUT', '/servers/1234')
|
||||
self.cs.servers.update(s, name='hi')
|
||||
self.assert_called('PUT', '/servers/1234')
|
||||
|
||||
def test_delete_server(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.delete()
|
||||
cs.assert_called('DELETE', '/servers/1234')
|
||||
cs.servers.delete(1234)
|
||||
cs.assert_called('DELETE', '/servers/1234')
|
||||
cs.servers.delete(s)
|
||||
cs.assert_called('DELETE', '/servers/1234')
|
||||
self.assert_called('DELETE', '/servers/1234')
|
||||
self.cs.servers.delete(1234)
|
||||
self.assert_called('DELETE', '/servers/1234')
|
||||
self.cs.servers.delete(s)
|
||||
self.assert_called('DELETE', '/servers/1234')
|
||||
|
||||
def test_delete_server_meta(self):
|
||||
cs.servers.delete_meta(1234, ['test_key'])
|
||||
cs.assert_called('DELETE', '/servers/1234/metadata/test_key')
|
||||
self.cs.servers.delete_meta(1234, ['test_key'])
|
||||
self.assert_called('DELETE', '/servers/1234/metadata/test_key')
|
||||
|
||||
def test_set_server_meta(self):
|
||||
cs.servers.set_meta(1234, {'test_key': 'test_value'})
|
||||
cs.assert_called('POST', '/servers/1234/metadata',
|
||||
{'metadata': {'test_key': 'test_value'}})
|
||||
self.cs.servers.set_meta(1234, {'test_key': 'test_value'})
|
||||
self.assert_called('POST', '/servers/1234/metadata',
|
||||
{'metadata': {'test_key': 'test_value'}})
|
||||
|
||||
def test_find(self):
|
||||
server = cs.servers.find(name='sample-server')
|
||||
cs.assert_called('GET', '/servers', pos=-2)
|
||||
cs.assert_called('GET', '/servers/1234', pos=-1)
|
||||
self.assertEqual(server.name, 'sample-server')
|
||||
server = self.cs.servers.find(name='sample-server')
|
||||
self.assert_called('GET', '/servers/1234')
|
||||
self.assertEqual('sample-server', server.name)
|
||||
|
||||
self.assertRaises(exceptions.NoUniqueMatch, cs.servers.find,
|
||||
self.assertRaises(exceptions.NoUniqueMatch, self.cs.servers.find,
|
||||
flavor={"id": 1, "name": "256 MB Server"})
|
||||
|
||||
sl = cs.servers.findall(flavor={"id": 1, "name": "256 MB Server"})
|
||||
self.assertEqual([s.id for s in sl], [1234, 5678, 9012])
|
||||
sl = self.cs.servers.findall(flavor={"id": 1, "name": "256 MB Server"})
|
||||
self.assertEqual([1234, 5678, 9012], [s.id for s in sl])
|
||||
|
||||
def test_reboot_server(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.reboot()
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
cs.servers.reboot(s, reboot_type='HARD')
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
self.cs.servers.reboot(s, reboot_type='HARD')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
def test_rebuild_server(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.rebuild(image=1)
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
cs.servers.rebuild(s, image=1)
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
self.cs.servers.rebuild(s, image=1)
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
s.rebuild(image=1, password='5678')
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
cs.servers.rebuild(s, image=1, password='5678')
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
self.cs.servers.rebuild(s, image=1, password='5678')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
def test_resize_server(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.resize(flavor=1)
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
cs.servers.resize(s, flavor=1)
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
self.cs.servers.resize(s, flavor=1)
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
def test_confirm_resized_server(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.confirm_resize()
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
cs.servers.confirm_resize(s)
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
self.cs.servers.confirm_resize(s)
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
def test_revert_resized_server(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.revert_resize()
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
cs.servers.revert_resize(s)
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
self.cs.servers.revert_resize(s)
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
def test_migrate_server(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.migrate()
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
cs.servers.migrate(s)
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
self.cs.servers.migrate(s)
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
def test_add_fixed_ip(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.add_fixed_ip(1)
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
cs.servers.add_fixed_ip(s, 1)
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
self.cs.servers.add_fixed_ip(s, 1)
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
def test_remove_fixed_ip(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.remove_fixed_ip('10.0.0.1')
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
cs.servers.remove_fixed_ip(s, '10.0.0.1')
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
self.cs.servers.remove_fixed_ip(s, '10.0.0.1')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
def test_stop(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.stop()
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
cs.servers.stop(s)
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
self.cs.servers.stop(s)
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
def test_force_delete(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.force_delete()
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
cs.servers.force_delete(s)
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
self.cs.servers.force_delete(s)
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
def test_restore(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.restore()
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
cs.servers.restore(s)
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
self.cs.servers.restore(s)
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
def test_start(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.start()
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
cs.servers.start(s)
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
self.cs.servers.start(s)
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
def test_rescue(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.rescue()
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
cs.servers.rescue(s)
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
self.cs.servers.rescue(s)
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
def test_unrescue(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.unrescue()
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
cs.servers.unrescue(s)
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
self.cs.servers.unrescue(s)
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
def test_lock(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.lock()
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
cs.servers.lock(s)
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
self.cs.servers.lock(s)
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
def test_unlock(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.unlock()
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
cs.servers.unlock(s)
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
self.cs.servers.unlock(s)
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
def test_backup(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.backup('back1', 'daily', 1)
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
cs.servers.backup(s, 'back1', 'daily', 2)
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
self.cs.servers.backup(s, 'back1', 'daily', 2)
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
def test_get_console_output_without_length(self):
|
||||
success = 'foo'
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.get_console_output()
|
||||
self.assertEqual(s.get_console_output(), success)
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.assertEqual(success, s.get_console_output())
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
cs.servers.get_console_output(s)
|
||||
self.assertEqual(cs.servers.get_console_output(s), success)
|
||||
cs.assert_called('POST', '/servers/1234/action',
|
||||
{'get_console_output': {'length': -1}})
|
||||
self.cs.servers.get_console_output(s)
|
||||
self.assertEqual(success, self.cs.servers.get_console_output(s))
|
||||
self.assert_called('POST', '/servers/1234/action',
|
||||
{'get_console_output': {'length': -1}})
|
||||
|
||||
def test_get_console_output_with_length(self):
|
||||
success = 'foo'
|
||||
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.get_console_output(length=50)
|
||||
self.assertEqual(s.get_console_output(length=50), success)
|
||||
cs.assert_called('POST', '/servers/1234/action',
|
||||
{'get_console_output': {'length': 50}})
|
||||
self.assertEqual(success, s.get_console_output(length=50))
|
||||
self.assert_called('POST', '/servers/1234/action',
|
||||
{'get_console_output': {'length': 50}})
|
||||
|
||||
cs.servers.get_console_output(s, length=50)
|
||||
self.assertEqual(cs.servers.get_console_output(s, length=50), success)
|
||||
cs.assert_called('POST', '/servers/1234/action',
|
||||
{'get_console_output': {'length': 50}})
|
||||
self.cs.servers.get_console_output(s, length=50)
|
||||
self.assertEqual(success,
|
||||
self.cs.servers.get_console_output(s, length=50))
|
||||
self.assert_called('POST', '/servers/1234/action',
|
||||
{'get_console_output': {'length': 50}})
|
||||
|
||||
def test_get_password(self):
|
||||
s = cs.servers.get(1234)
|
||||
self.assertEqual(s.get_password('/foo/id_rsa'), '')
|
||||
cs.assert_called('GET', '/servers/1234/os-server-password')
|
||||
s = self.cs.servers.get(1234)
|
||||
self.assertEqual('', s.get_password('/foo/id_rsa'))
|
||||
self.assert_called('GET', '/servers/1234/os-server-password')
|
||||
|
||||
def test_clear_password(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.clear_password()
|
||||
cs.assert_called('DELETE', '/servers/1234/os-server-password')
|
||||
self.assert_called('DELETE', '/servers/1234/os-server-password')
|
||||
|
||||
def test_get_server_diagnostics(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
diagnostics = s.diagnostics()
|
||||
self.assertTrue(diagnostics is not None)
|
||||
cs.assert_called('GET', '/servers/1234/os-server-diagnostics')
|
||||
self.assert_called('GET', '/servers/1234/os-server-diagnostics')
|
||||
|
||||
diagnostics_from_manager = cs.servers.diagnostics(1234)
|
||||
diagnostics_from_manager = self.cs.servers.diagnostics(1234)
|
||||
self.assertTrue(diagnostics_from_manager is not None)
|
||||
cs.assert_called('GET', '/servers/1234/os-server-diagnostics')
|
||||
self.assert_called('GET', '/servers/1234/os-server-diagnostics')
|
||||
|
||||
self.assertEqual(diagnostics, diagnostics_from_manager)
|
||||
self.assertEqual(diagnostics_from_manager[1], diagnostics[1])
|
||||
|
||||
def test_get_vnc_console(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.get_vnc_console('fake')
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
cs.servers.get_vnc_console(s, 'fake')
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.cs.servers.get_vnc_console(s, 'fake')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
def test_get_spice_console(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.get_spice_console('fake')
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
cs.servers.get_spice_console(s, 'fake')
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.cs.servers.get_spice_console(s, 'fake')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
def test_create_image(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.create_image('123')
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
s.create_image('123', {})
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
cs.servers.create_image(s, '123')
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
cs.servers.create_image(s, '123', {})
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
self.cs.servers.create_image(s, '123')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
self.cs.servers.create_image(s, '123', {})
|
||||
|
||||
def test_live_migrate_server(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.live_migrate(host='hostname', block_migration=False,
|
||||
disk_over_commit=False)
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
cs.servers.live_migrate(s, host='hostname', block_migration=False,
|
||||
disk_over_commit=False)
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
self.cs.servers.live_migrate(s, host='hostname', block_migration=False,
|
||||
disk_over_commit=False)
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
def test_reset_state(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.reset_state('newstate')
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
cs.servers.reset_state(s, 'newstate')
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
self.cs.servers.reset_state(s, 'newstate')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
def test_reset_network(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.reset_network()
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
cs.servers.reset_network(s)
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
self.cs.servers.reset_network(s)
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
def test_evacuate(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.evacuate('fake_target_host', 'True')
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
cs.servers.evacuate(s, 'fake_target_host', 'False', 'NewAdminPassword')
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
self.cs.servers.evacuate(s, 'fake_target_host',
|
||||
'False', 'NewAdminPassword')
|
||||
self.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
def test_interface_list(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.interface_list()
|
||||
cs.assert_called('GET', '/servers/1234/os-attach-interfaces')
|
||||
self.assert_called('GET', '/servers/1234/os-attach-interfaces')
|
||||
|
||||
def test_interface_attach(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.interface_attach(None, None, None)
|
||||
cs.assert_called('POST', '/servers/1234/os-attach-interfaces')
|
||||
self.assert_called('POST', '/servers/1234/os-attach-interfaces')
|
||||
|
||||
def test_interface_detach(self):
|
||||
s = cs.servers.get(1234)
|
||||
s = self.cs.servers.get(1234)
|
||||
s.interface_detach('port-id')
|
||||
cs.assert_called('DELETE',
|
||||
'/servers/1234/os-attach-interfaces/port-id')
|
||||
self.assert_called('DELETE',
|
||||
'/servers/1234/os-attach-interfaces/port-id')
|
||||
|
||||
@ -127,17 +127,29 @@ class ShellTest(utils.TestCase):
|
||||
self.assert_called('PUT', '/os-aggregates/1', body, pos=-2)
|
||||
self.assert_called('GET', '/os-aggregates/1', pos=-1)
|
||||
|
||||
def test_aggregate_set_metadata_by_id(self):
|
||||
self.run_command('aggregate-set-metadata 1 foo=bar delete_key')
|
||||
body = {"set_metadata": {"metadata": {"foo": "bar",
|
||||
"delete_key": None}}}
|
||||
self.assert_called('POST', '/os-aggregates/1/action', body, pos=-2)
|
||||
self.assert_called('GET', '/os-aggregates/1', pos=-1)
|
||||
def test_aggregate_set_metadata_add_by_id(self):
|
||||
self.run_command('aggregate-set-metadata 3 foo=bar')
|
||||
body = {"set_metadata": {"metadata": {"foo": "bar"}}}
|
||||
self.assert_called('POST', '/os-aggregates/3/action', body, pos=-2)
|
||||
self.assert_called('GET', '/os-aggregates/3', pos=-1)
|
||||
|
||||
def test_aggregate_set_metadata_add_duplicate_by_id(self):
|
||||
cmd = 'aggregate-set-metadata 3 test=dup'
|
||||
self.assertRaises(exceptions.CommandError, self.run_command, cmd)
|
||||
|
||||
def test_aggregate_set_metadata_delete_by_id(self):
|
||||
self.run_command('aggregate-set-metadata 3 none_key')
|
||||
body = {"set_metadata": {"metadata": {"none_key": None}}}
|
||||
self.assert_called('POST', '/os-aggregates/3/action', body, pos=-2)
|
||||
self.assert_called('GET', '/os-aggregates/3', pos=-1)
|
||||
|
||||
def test_aggregate_set_metadata_delete_missing_by_id(self):
|
||||
cmd = 'aggregate-set-metadata 3 delete_key2'
|
||||
self.assertRaises(exceptions.CommandError, self.run_command, cmd)
|
||||
|
||||
def test_aggregate_set_metadata_by_name(self):
|
||||
self.run_command('aggregate-set-metadata test foo=bar delete_key')
|
||||
body = {"set_metadata": {"metadata": {"foo": "bar",
|
||||
"delete_key": None}}}
|
||||
self.run_command('aggregate-set-metadata test foo=bar')
|
||||
body = {"set_metadata": {"metadata": {"foo": "bar"}}}
|
||||
self.assert_called('POST', '/os-aggregates/1/action', body, pos=-2)
|
||||
self.assert_called('GET', '/os-aggregates/1', pos=-1)
|
||||
|
||||
@ -235,7 +247,7 @@ class ShellTest(utils.TestCase):
|
||||
'image_ref': '1',
|
||||
'os-multiple-create:min_count': 1,
|
||||
'os-multiple-create:max_count': 1,
|
||||
'os-user-data:user_data': user_data}},
|
||||
'user_data': user_data}},
|
||||
)
|
||||
|
||||
def test_boot_avzone(self):
|
||||
@ -261,8 +273,8 @@ class ShellTest(utils.TestCase):
|
||||
self.assert_called_anytime(
|
||||
'POST', '/servers',
|
||||
{'server': {
|
||||
'os-security-groups:security_groups': [{'name': 'secgroup1'},
|
||||
{'name': 'secgroup2'}],
|
||||
'security_groups': [{'name': 'secgroup1'},
|
||||
{'name': 'secgroup2'}],
|
||||
'flavor_ref': '1',
|
||||
'name': 'some-server',
|
||||
'image_ref': '1',
|
||||
@ -325,11 +337,14 @@ class ShellTest(utils.TestCase):
|
||||
{'server': {
|
||||
'flavor_ref': '1',
|
||||
'name': 'some-server',
|
||||
'os-block-device-mapping:block_device_mapping': [
|
||||
'block_device_mapping': [
|
||||
{
|
||||
'volume_id': 'blah',
|
||||
'delete_on_termination': '0',
|
||||
'device_name': 'vda'
|
||||
'device_name': 'vda',
|
||||
'boot_index': 0,
|
||||
'uuid': 'blah',
|
||||
'source_type': ''
|
||||
}
|
||||
],
|
||||
'image_ref': '',
|
||||
@ -344,15 +359,16 @@ class ShellTest(utils.TestCase):
|
||||
'source=volume,dest=volume,device=vda,size=1,format=ext4,'
|
||||
'type=disk,shutdown=preserve some-server'
|
||||
)
|
||||
id = ('fake-id,source=volume,dest=volume,device=vda,size=1,'
|
||||
'format=ext4,type=disk,shutdown=preserve')
|
||||
self.assert_called_anytime(
|
||||
'POST', '/servers',
|
||||
{'server': {
|
||||
'flavor_ref': '1',
|
||||
'name': 'some-server',
|
||||
'os-block-device-mapping:block_device_mapping': [
|
||||
{'device_name': 'id', 'volume_id':
|
||||
'fake-id,source=volume,dest=volume,device=vda,size=1,'
|
||||
'format=ext4,type=disk,shutdown=preserve'}],
|
||||
'block_device_mapping': [
|
||||
{'device_name': 'id', 'volume_id': id,
|
||||
'source_type': 'volume', 'boot_index': 0, 'uuid': id}],
|
||||
'image_ref': '1',
|
||||
'os-multiple-create:min_count': 1,
|
||||
'os-multiple-create:max_count': 1,
|
||||
@ -550,7 +566,7 @@ class ShellTest(utils.TestCase):
|
||||
'os-multiple-create:max_count': 1,
|
||||
}},
|
||||
)
|
||||
self.assertEqual(poll_method.call_count, 1)
|
||||
self.assertEqual(1, poll_method.call_count)
|
||||
poll_method.assert_has_calls(
|
||||
[mock.call(self.shell.cs.servers.get, 1234, 'building',
|
||||
['active'])])
|
||||
@ -559,6 +575,39 @@ class ShellTest(utils.TestCase):
|
||||
self.assertRaises(exceptions.InstanceInErrorState, self.run_command,
|
||||
'boot --flavor 1 --image 1 some-bad-server --poll')
|
||||
|
||||
def test_evacuate(self):
|
||||
self.run_command('evacuate sample-server new_host')
|
||||
self.assert_called('POST', '/servers/1234/action',
|
||||
{'evacuate': {'host': 'new_host',
|
||||
'on_shared_storage': False}})
|
||||
self.run_command('evacuate sample-server new_host '
|
||||
'--password NewAdminPass')
|
||||
self.assert_called('POST', '/servers/1234/action',
|
||||
{'evacuate': {'host': 'new_host',
|
||||
'on_shared_storage': False,
|
||||
'admin_password': 'NewAdminPass'}})
|
||||
self.run_command('evacuate sample-server new_host')
|
||||
self.assert_called('POST', '/servers/1234/action',
|
||||
{'evacuate': {'host': 'new_host',
|
||||
'on_shared_storage': False}})
|
||||
self.run_command('evacuate sample-server new_host '
|
||||
'--on-shared-storage')
|
||||
self.assert_called('POST', '/servers/1234/action',
|
||||
{'evacuate': {'host': 'new_host',
|
||||
'on_shared_storage': True}})
|
||||
|
||||
def test_evacuate_with_no_target_host(self):
|
||||
self.run_command('evacuate sample-server')
|
||||
self.assert_called('POST', '/servers/1234/action',
|
||||
{'evacuate': {'on_shared_storage': False}})
|
||||
self.run_command('evacuate sample-server --password NewAdminPass')
|
||||
self.assert_called('POST', '/servers/1234/action',
|
||||
{'evacuate': {'on_shared_storage': False,
|
||||
'admin_password': 'NewAdminPass'}})
|
||||
self.run_command('evacuate sample-server --on-shared-storage')
|
||||
self.assert_called('POST', '/servers/1234/action',
|
||||
{'evacuate': {'on_shared_storage': True}})
|
||||
|
||||
def test_boot_named_flavor(self):
|
||||
self.run_command(["boot", "--image", "1",
|
||||
"--flavor", "512 MB Server",
|
||||
@ -594,3 +643,82 @@ class ShellTest(utils.TestCase):
|
||||
self.assert_called('GET', '/flavors?is_public=None', pos=2)
|
||||
self.assert_called('GET', '/flavors/2', pos=3)
|
||||
self.assert_called('GET', '/flavors/2/flavor-extra-specs', pos=4)
|
||||
|
||||
def test_delete(self):
|
||||
self.run_command('delete 1234')
|
||||
self.assert_called('DELETE', '/servers/1234')
|
||||
self.run_command('delete sample-server')
|
||||
self.assert_called('DELETE', '/servers/1234')
|
||||
|
||||
def test_delete_two_with_two_existent(self):
|
||||
self.run_command('delete 1234 5678')
|
||||
self.assert_called('DELETE', '/servers/1234', pos=-3)
|
||||
self.assert_called('DELETE', '/servers/5678', pos=-1)
|
||||
self.run_command('delete sample-server sample-server2')
|
||||
self.assert_called('GET', '/servers?name=sample-server', pos=-6)
|
||||
self.assert_called('GET', '/servers/1234', pos=-5)
|
||||
self.assert_called('DELETE', '/servers/1234', pos=-4)
|
||||
self.assert_called('GET', '/servers?name=sample-server2', pos=-3)
|
||||
self.assert_called('GET', '/servers/5678', pos=-2)
|
||||
self.assert_called('DELETE', '/servers/5678', pos=-1)
|
||||
|
||||
def test_delete_two_with_one_nonexistent(self):
|
||||
cmd = 'delete 1234 123456789'
|
||||
self.assertRaises(exceptions.CommandError, self.run_command, cmd)
|
||||
self.assert_called_anytime('DELETE', '/servers/1234')
|
||||
cmd = 'delete sample-server nonexistentserver'
|
||||
self.assertRaises(exceptions.CommandError, self.run_command, cmd)
|
||||
self.assert_called_anytime('DELETE', '/servers/1234')
|
||||
|
||||
def test_delete_one_with_one_nonexistent(self):
|
||||
cmd = 'delete 123456789'
|
||||
self.assertRaises(exceptions.CommandError, self.run_command, cmd)
|
||||
cmd = 'delete nonexistent-server1'
|
||||
self.assertRaises(exceptions.CommandError, self.run_command, cmd)
|
||||
|
||||
def test_delete_two_with_two_nonexistent(self):
|
||||
cmd = 'delete 123456789 987654321'
|
||||
self.assertRaises(exceptions.CommandError, self.run_command, cmd)
|
||||
cmd = 'delete nonexistent-server1 nonexistent-server2'
|
||||
self.assertRaises(exceptions.CommandError, self.run_command, cmd)
|
||||
|
||||
|
||||
class GetFirstEndpointTest(utils.TestCase):
|
||||
def test_only_one_endpoint(self):
|
||||
"""If there is only one endpoint, it is returned."""
|
||||
endpoint = {"url": "test"}
|
||||
result = novaclient.v3.shell._get_first_endpoint([endpoint], "XYZ")
|
||||
self.assertEqual(endpoint, result)
|
||||
|
||||
def test_multiple_endpoints(self):
|
||||
"""If there are multiple endpoints, the first one of the appropriate
|
||||
region is returned.
|
||||
|
||||
"""
|
||||
endpoints = [
|
||||
{"region": "XYZ"},
|
||||
{"region": "ORD", "number": 1},
|
||||
{"region": "ORD", "number": 2}
|
||||
]
|
||||
result = novaclient.v3.shell._get_first_endpoint(endpoints, "ORD")
|
||||
self.assertEqual(endpoints[1], result)
|
||||
|
||||
def test_multiple_endpoints_but_none_suitable(self):
|
||||
"""If there are multiple endpoints but none of them are suitable, an
|
||||
exception is raised.
|
||||
|
||||
"""
|
||||
endpoints = [
|
||||
{"region": "XYZ"},
|
||||
{"region": "PQR"},
|
||||
{"region": "STU"}
|
||||
]
|
||||
self.assertRaises(LookupError,
|
||||
novaclient.v3.shell._get_first_endpoint,
|
||||
endpoints, "ORD")
|
||||
|
||||
def test_no_endpoints(self):
|
||||
"""If there are no endpoints available, an exception is raised."""
|
||||
self.assertRaises(LookupError,
|
||||
novaclient.v3.shell._get_first_endpoint,
|
||||
[], "ORD")
|
||||
|
||||
@ -13,20 +13,24 @@
|
||||
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
import textwrap
|
||||
import uuid
|
||||
|
||||
from oslo.serialization import jsonutils
|
||||
from oslo.utils import encodeutils
|
||||
import pkg_resources
|
||||
import prettytable
|
||||
import six
|
||||
|
||||
from novaclient import exceptions
|
||||
from novaclient.i18n import _
|
||||
from novaclient.openstack.common import cliutils
|
||||
from novaclient.openstack.common.gettextutils import _
|
||||
from novaclient.openstack.common import jsonutils
|
||||
|
||||
|
||||
arg = cliutils.arg
|
||||
env = cliutils.env
|
||||
|
||||
VALID_KEY_REGEX = re.compile(r"[\w\.\- :]+$", re.UNICODE)
|
||||
|
||||
|
||||
@ -67,10 +71,34 @@ def get_resource_manager_extra_kwargs(f, args, allow_conflicts=False):
|
||||
return extra_kwargs
|
||||
|
||||
|
||||
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 pretty_choice_dict(d):
|
||||
"""Returns a formatted dict as 'key=value'."""
|
||||
return cliutils.pretty_choice_list(
|
||||
['%s=%s' % (k, d[k]) for k in sorted(d.keys())])
|
||||
return pretty_choice_list(['%s=%s' % (k, d[k]) for k in sorted(d.keys())])
|
||||
|
||||
|
||||
def print_list(objs, fields, formatters={}, sortby_index=None):
|
||||
@ -208,6 +236,12 @@ def find_resource(manager, name_or_id, **find_args):
|
||||
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'
|
||||
@ -215,15 +249,9 @@ def find_resource(manager, name_or_id, **find_args):
|
||||
kwargs.update(find_args)
|
||||
return manager.find(**kwargs)
|
||||
except exceptions.NotFound:
|
||||
pass
|
||||
|
||||
# finally try to find entity by human_id
|
||||
try:
|
||||
return manager.find(human_id=name_or_id, **find_args)
|
||||
except exceptions.NotFound:
|
||||
msg = (_("No %(class)s with a name or ID of '%(name)s' exists.") %
|
||||
{'class': manager.resource_class.__name__.lower(),
|
||||
'name': name_or_id})
|
||||
msg = _("No %(class)s with a name or ID of '%(name)s' exists.") % \
|
||||
{'class': manager.resource_class.__name__.lower(),
|
||||
'name': name_or_id}
|
||||
raise exceptions.CommandError(msg)
|
||||
except exceptions.NoUniqueMatch:
|
||||
msg = (_("Multiple %(class)s matches found for '%(name)s', use an ID "
|
||||
@ -285,6 +313,24 @@ def _make_field_formatter(attr, filters=None):
|
||||
return name, formatter
|
||||
|
||||
|
||||
class HookableMixin(object):
|
||||
"""Mixin so classes can register and run hooks."""
|
||||
_hooks_map = {}
|
||||
|
||||
@classmethod
|
||||
def add_hook(cls, hook_type, hook_func):
|
||||
if hook_type not in cls._hooks_map:
|
||||
cls._hooks_map[hook_type] = []
|
||||
|
||||
cls._hooks_map[hook_type].append(hook_func)
|
||||
|
||||
@classmethod
|
||||
def run_hooks(cls, hook_type, *args, **kwargs):
|
||||
hook_funcs = cls._hooks_map.get(hook_type) or []
|
||||
for hook_func in hook_funcs:
|
||||
hook_func(*args, **kwargs)
|
||||
|
||||
|
||||
def safe_issubclass(*args):
|
||||
"""Like issubclass, but will just return False if not a class."""
|
||||
|
||||
@ -297,20 +343,11 @@ def safe_issubclass(*args):
|
||||
return False
|
||||
|
||||
|
||||
def do_action_on_many(action, resources, success_msg, error_msg):
|
||||
"""Helper to run an action on many resources."""
|
||||
failure_flag = False
|
||||
|
||||
for resource in resources:
|
||||
try:
|
||||
action(resource)
|
||||
print(success_msg % resource)
|
||||
except Exception as e:
|
||||
failure_flag = True
|
||||
print(e)
|
||||
|
||||
if failure_flag:
|
||||
raise exceptions.CommandError(error_msg)
|
||||
def import_class(import_str):
|
||||
"""Returns a class from a string including module and class."""
|
||||
mod_str, _sep, class_str = import_str.rpartition('.')
|
||||
__import__(mod_str)
|
||||
return getattr(sys.modules[mod_str], class_str)
|
||||
|
||||
|
||||
def _load_entry_point(ep_name, name=None):
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
# Copyright (c) 2012 OpenStack Foundation
|
||||
#
|
||||
# All Rights Reserved.
|
||||
#
|
||||
@ -13,31 +14,4 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
# NOTE(akurilin): This module is left for backward compatibility. Feel free to
|
||||
# remove it, when openstack project will use correct way to
|
||||
# obtain novaclient object.
|
||||
# Known problems:
|
||||
# * python-openstackclient -
|
||||
# https://bugs.launchpad.net/python-openstackclient/+bug/1418024
|
||||
# * neutron - https://bugs.launchpad.net/neutron/+bug/1418017
|
||||
|
||||
|
||||
import sys
|
||||
import warnings
|
||||
|
||||
from novaclient import v2
|
||||
|
||||
warnings.warn("Module novaclient.v1_1 is deprecated (taken as a basis for "
|
||||
"novaclient.v2). "
|
||||
"The preferable way to get client class or object you can find "
|
||||
"in novaclient.client module.")
|
||||
|
||||
|
||||
class MovedModule(object):
|
||||
def __init__(self, new_module):
|
||||
self.new_module = new_module
|
||||
|
||||
def __getattr__(self, attr):
|
||||
return getattr(self.new_module, attr)
|
||||
|
||||
sys.modules["novaclient.v1_1"] = MovedModule(v2)
|
||||
from novaclient.v1_1.client import Client # noqa
|
||||
|
||||
@ -35,12 +35,14 @@ from novaclient.v1_1 import limits
|
||||
from novaclient.v1_1 import networks
|
||||
from novaclient.v1_1 import quota_classes
|
||||
from novaclient.v1_1 import quotas
|
||||
from novaclient.v1_1 import security_group_default_rules
|
||||
from novaclient.v1_1 import security_group_rules
|
||||
from novaclient.v1_1 import security_groups
|
||||
from novaclient.v1_1 import server_groups
|
||||
from novaclient.v1_1 import servers
|
||||
from novaclient.v1_1 import services
|
||||
from novaclient.v1_1 import usage
|
||||
from novaclient.v1_1 import versions
|
||||
from novaclient.v1_1 import virtual_interfaces
|
||||
from novaclient.v1_1 import volume_snapshots
|
||||
from novaclient.v1_1 import volume_types
|
||||
@ -55,6 +57,19 @@ class Client(object):
|
||||
|
||||
>>> client = Client(USERNAME, PASSWORD, PROJECT_ID, AUTH_URL)
|
||||
|
||||
Or, alternatively, you can create a client instance using the
|
||||
keystoneclient.session API::
|
||||
|
||||
>>> from keystoneclient.auth.identity import v2
|
||||
>>> from keystoneclient import session
|
||||
>>> from novaclient.client import Client
|
||||
>>> auth = v2.Password(auth_url=AUTH_URL,
|
||||
username=USERNAME,
|
||||
password=PASSWORD,
|
||||
tenant_name=PROJECT_ID)
|
||||
>>> sess = session.Session(auth=auth)
|
||||
>>> nova = client.Client(VERSION, session=sess)
|
||||
|
||||
Then call methods on its managers::
|
||||
|
||||
>>> client.servers.list()
|
||||
@ -107,6 +122,7 @@ class Client(object):
|
||||
self.images = images.ImageManager(self)
|
||||
self.limits = limits.LimitsManager(self)
|
||||
self.servers = servers.ServerManager(self)
|
||||
self.versions = versions.VersionManager(self)
|
||||
|
||||
# extensions
|
||||
self.agents = agents.AgentsManager(self)
|
||||
@ -127,6 +143,8 @@ class Client(object):
|
||||
self.security_groups = security_groups.SecurityGroupManager(self)
|
||||
self.security_group_rules = \
|
||||
security_group_rules.SecurityGroupRuleManager(self)
|
||||
self.security_group_default_rules = \
|
||||
security_group_default_rules.SecurityGroupDefaultRuleManager(self)
|
||||
self.usage = usage.UsageManager(self)
|
||||
self.virtual_interfaces = \
|
||||
virtual_interfaces.VirtualInterfaceManager(self)
|
||||
|
||||
@ -19,7 +19,7 @@ from novaclient import base
|
||||
|
||||
|
||||
class Cloudpipe(base.Resource):
|
||||
"""A cloudpipe instance is a VPN attached to a proejct's VLAN."""
|
||||
"""A cloudpipe instance is a VPN attached to a project's VLAN."""
|
||||
|
||||
def __repr__(self):
|
||||
return "<Cloudpipe: %s>" % self.project_id
|
||||
|
||||
@ -26,8 +26,8 @@ def _server_evacuate(cs, server, args):
|
||||
success = True
|
||||
error_message = ""
|
||||
try:
|
||||
cs.servers.evacuate(server['uuid'], args.target_host,
|
||||
args.on_shared_storage)
|
||||
cs.servers.evacuate(server=server['uuid'], host=args.target_host,
|
||||
on_shared_storage=args.on_shared_storage)
|
||||
except Exception as e:
|
||||
success = False
|
||||
error_message = _("Error while evacuating instance: %s") % e
|
||||
@ -41,7 +41,9 @@ def _server_evacuate(cs, server, args):
|
||||
@utils.arg('--target_host',
|
||||
metavar='<target_host>',
|
||||
default=None,
|
||||
help=_('Name of target host.'))
|
||||
help=_('Name of target host. '
|
||||
'If no host is specified the scheduler'
|
||||
' will select a target.'))
|
||||
@utils.arg('--on-shared-storage',
|
||||
dest='on_shared_storage',
|
||||
action="store_true",
|
||||
@ -49,7 +51,7 @@ def _server_evacuate(cs, server, args):
|
||||
help=_('Specifies whether all instances files are on shared '
|
||||
' storage'))
|
||||
def do_host_evacuate(cs, args):
|
||||
"""Evacuate all instances from failed host to specified one."""
|
||||
"""Evacuate all instances from failed host."""
|
||||
hypervisors = cs.hypervisors.search(args.host, servers=True)
|
||||
response = []
|
||||
for hyper in hypervisors:
|
||||
|
||||
@ -16,12 +16,12 @@
|
||||
Flavor interface.
|
||||
"""
|
||||
|
||||
from oslo.utils import strutils
|
||||
from six.moves.urllib import parse
|
||||
|
||||
from novaclient import base
|
||||
from novaclient import exceptions
|
||||
from novaclient.openstack.common.gettextutils import _
|
||||
from novaclient.openstack.common import strutils
|
||||
from novaclient import utils
|
||||
|
||||
|
||||
|
||||
@ -21,7 +21,7 @@ from novaclient import base
|
||||
|
||||
class Host(base.Resource):
|
||||
def __repr__(self):
|
||||
return "<Host: %s>" % self.host_name
|
||||
return "<Host: %s>" % self.host
|
||||
|
||||
def _add_details(self, info):
|
||||
dico = 'resource' in info and info['resource'] or info
|
||||
|
||||
@ -26,7 +26,7 @@ class Network(base.Resource):
|
||||
"""
|
||||
A network.
|
||||
"""
|
||||
HUMAN_ID = False
|
||||
HUMAN_ID = True
|
||||
NAME_ATTR = "label"
|
||||
|
||||
def __repr__(self):
|
||||
@ -89,8 +89,14 @@ class NetworkManager(base.ManagerWithFind):
|
||||
:param vlan: int
|
||||
:param vlan_start: int
|
||||
:param vpn_start: int
|
||||
:param mtu: int
|
||||
:param enable_dhcp: int
|
||||
:param dhcp_server: str
|
||||
:param share_address: int
|
||||
:param allowed_start: str
|
||||
:param allowed_end: str
|
||||
|
||||
:rtype: list of :class:`Network`
|
||||
:rtype: object of :class:`Network`
|
||||
"""
|
||||
body = {"network": kwargs}
|
||||
return self._create('/os-networks', body, 'network')
|
||||
|
||||
@ -0,0 +1,81 @@
|
||||
# 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.
|
||||
|
||||
"""
|
||||
Security group default rules interface.
|
||||
"""
|
||||
|
||||
from novaclient import base
|
||||
from novaclient import exceptions
|
||||
from novaclient.openstack.common.gettextutils import _
|
||||
|
||||
|
||||
class SecurityGroupDefaultRule(base.Resource):
|
||||
def __str__(self):
|
||||
return str(self.id)
|
||||
|
||||
def delete(self):
|
||||
self.manager.delete(self)
|
||||
|
||||
|
||||
class SecurityGroupDefaultRuleManager(base.Manager):
|
||||
resource_class = SecurityGroupDefaultRule
|
||||
|
||||
def create(self, ip_protocol=None, from_port=None, to_port=None,
|
||||
cidr=None):
|
||||
"""
|
||||
Create a security group default rule
|
||||
|
||||
:param ip_protocol: IP protocol, one of 'tcp', 'udp' or 'icmp'
|
||||
:param from_port: Source port
|
||||
:param to_port: Destination port
|
||||
:param cidr: Destination IP address(es) in CIDR notation
|
||||
"""
|
||||
|
||||
try:
|
||||
from_port = int(from_port)
|
||||
except (TypeError, ValueError):
|
||||
raise exceptions.CommandError(_("From port must be an integer."))
|
||||
try:
|
||||
to_port = int(to_port)
|
||||
except (TypeError, ValueError):
|
||||
raise exceptions.CommandError(_("To port must be an integer."))
|
||||
if ip_protocol.upper() not in ['TCP', 'UDP', 'ICMP']:
|
||||
raise exceptions.CommandError(_("Ip protocol must be 'tcp', 'udp'"
|
||||
", or 'icmp'."))
|
||||
|
||||
body = {"security_group_default_rule": {
|
||||
"ip_protocol": ip_protocol,
|
||||
"from_port": from_port,
|
||||
"to_port": to_port,
|
||||
"cidr": cidr}}
|
||||
|
||||
return self._create('/os-security-group-default-rules', body,
|
||||
'security_group_default_rule')
|
||||
|
||||
def delete(self, rule):
|
||||
"""
|
||||
Delete a security group default rule
|
||||
|
||||
:param rule: The security group default rule to delete (ID or Class)
|
||||
"""
|
||||
self._delete('/os-security-group-default-rules/%s' % base.getid(rule))
|
||||
|
||||
def list(self):
|
||||
"""
|
||||
Get a list of all security group default rules
|
||||
|
||||
:rtype: list of :class:`SecurityGroupDefaultRule`
|
||||
"""
|
||||
|
||||
return self._list('/os-security-group-default-rules',
|
||||
'security_group_default_rules')
|
||||
@ -21,14 +21,15 @@ Server interface.
|
||||
|
||||
import base64
|
||||
|
||||
from oslo.utils import encodeutils
|
||||
import six
|
||||
from six.moves.urllib import parse
|
||||
|
||||
from novaclient import base
|
||||
from novaclient import crypto
|
||||
from novaclient.openstack.common.gettextutils import _
|
||||
from novaclient.openstack.common import strutils
|
||||
from novaclient.v1_1.security_groups import SecurityGroup
|
||||
from novaclient.v1_1 import security_groups
|
||||
|
||||
|
||||
REBOOT_SOFT, REBOOT_HARD = 'SOFT', 'HARD'
|
||||
|
||||
@ -85,6 +86,14 @@ class Server(base.Resource):
|
||||
"""
|
||||
return self.manager.get_rdp_console(self, console_type)
|
||||
|
||||
def get_serial_console(self, console_type):
|
||||
"""
|
||||
Get serial console for a Server.
|
||||
|
||||
:param console_type: Type of console ('serial')
|
||||
"""
|
||||
return self.manager.get_serial_console(self, console_type)
|
||||
|
||||
def get_password(self, private_key=None):
|
||||
"""
|
||||
Get password for a Server.
|
||||
@ -364,7 +373,7 @@ class Server(base.Resource):
|
||||
"""
|
||||
return self.manager.list_security_group(self)
|
||||
|
||||
def evacuate(self, host, on_shared_storage, password=None):
|
||||
def evacuate(self, host=None, on_shared_storage=True, password=None):
|
||||
"""
|
||||
Evacuate an instance from failed host to specified host.
|
||||
|
||||
@ -419,7 +428,7 @@ class ServerManager(base.BootingManagerWithFind):
|
||||
file-like object). A maximum of five entries is allowed,
|
||||
and each file must be 10k or less.
|
||||
:param reservation_id: a UUID for the set of servers being requested.
|
||||
:param return_raw: If True, don't try to coearse the result into
|
||||
:param return_raw: If True, don't try to coerce the result into
|
||||
a Resource object.
|
||||
:param security_groups: list of security group names
|
||||
:param key_name: (optional extension) name of keypair to inject into
|
||||
@ -453,7 +462,7 @@ class ServerManager(base.BootingManagerWithFind):
|
||||
if six.PY3:
|
||||
userdata = userdata.encode("utf-8")
|
||||
else:
|
||||
userdata = strutils.safe_encode(userdata)
|
||||
userdata = encodeutils.safe_encode(userdata)
|
||||
|
||||
userdata_b64 = base64.b64encode(userdata).decode('utf-8')
|
||||
body["server"]["user_data"] = userdata_b64
|
||||
@ -674,6 +683,17 @@ class ServerManager(base.BootingManagerWithFind):
|
||||
return self._action('os-getRDPConsole', server,
|
||||
{'type': console_type})[1]
|
||||
|
||||
def get_serial_console(self, server, console_type):
|
||||
"""
|
||||
Get a serial console for an instance
|
||||
|
||||
:param server: The :class:`Server` (or its ID) to add an IP to.
|
||||
:param console_type: Type of serial console to get ('serial')
|
||||
"""
|
||||
|
||||
return self._action('os-getSerialConsole', server,
|
||||
{'type': console_type})[1]
|
||||
|
||||
def get_password(self, server, private_key=None):
|
||||
"""
|
||||
Get password for an instance
|
||||
@ -922,7 +942,8 @@ class ServerManager(base.BootingManagerWithFind):
|
||||
self._action('reboot', server, {'type': reboot_type})
|
||||
|
||||
def rebuild(self, server, image, password=None, disk_config=None,
|
||||
preserve_ephemeral=False, **kwargs):
|
||||
preserve_ephemeral=False, name=None, meta=None, files=None,
|
||||
**kwargs):
|
||||
"""
|
||||
Rebuild -- shut down and then re-image -- a server.
|
||||
|
||||
@ -933,6 +954,15 @@ class ServerManager(base.BootingManagerWithFind):
|
||||
Valid values are 'AUTO' or 'MANUAL'
|
||||
:param preserve_ephemeral: If True, request that any ephemeral device
|
||||
be preserved when rebuilding the instance. Defaults to False.
|
||||
:param name: Something to name the server.
|
||||
:param meta: A dict of arbitrary key/value metadata to store for this
|
||||
server. A maximum of five entries is allowed, and both
|
||||
keys and values must be 255 characters or less.
|
||||
:param files: A dict of files to overwrite on the server upon boot.
|
||||
Keys are file names (i.e. ``/etc/passwd``) and values
|
||||
are the file contents (either as a string or as a
|
||||
file-like object). A maximum of five entries is allowed,
|
||||
and each file must be 10k or less.
|
||||
"""
|
||||
body = {'imageRef': base.getid(image)}
|
||||
if password is not None:
|
||||
@ -941,6 +971,24 @@ class ServerManager(base.BootingManagerWithFind):
|
||||
body['OS-DCF:diskConfig'] = disk_config
|
||||
if preserve_ephemeral is not False:
|
||||
body['preserve_ephemeral'] = True
|
||||
if name is not None:
|
||||
body['name'] = name
|
||||
if meta:
|
||||
body['metadata'] = meta
|
||||
if files:
|
||||
personality = body['personality'] = []
|
||||
for filepath, file_or_string in sorted(files.items(),
|
||||
key=lambda x: x[0]):
|
||||
if hasattr(file_or_string, 'read'):
|
||||
data = file_or_string.read()
|
||||
else:
|
||||
data = file_or_string
|
||||
|
||||
cont = base64.b64encode(data.encode('utf-8')).decode('utf-8')
|
||||
personality.append({
|
||||
'path': filepath,
|
||||
'contents': cont,
|
||||
})
|
||||
|
||||
_resp, body = self._action('rebuild', server, body, **kwargs)
|
||||
return Server(self, body['server'])
|
||||
@ -1119,9 +1167,11 @@ class ServerManager(base.BootingManagerWithFind):
|
||||
|
||||
"""
|
||||
return self._list('/servers/%s/os-security-groups' %
|
||||
base.getid(server), 'security_groups', SecurityGroup)
|
||||
base.getid(server), 'security_groups',
|
||||
security_groups.SecurityGroup)
|
||||
|
||||
def evacuate(self, server, host, on_shared_storage, password=None):
|
||||
def evacuate(self, server, host=None, on_shared_storage=True,
|
||||
password=None):
|
||||
"""
|
||||
Evacuate a server instance.
|
||||
|
||||
@ -1131,10 +1181,10 @@ class ServerManager(base.BootingManagerWithFind):
|
||||
on shared storage
|
||||
:param password: string to set as password on the evacuated server.
|
||||
"""
|
||||
body = {
|
||||
'host': host,
|
||||
'onSharedStorage': on_shared_storage,
|
||||
}
|
||||
|
||||
body = {'onSharedStorage': on_shared_storage}
|
||||
if host is not None:
|
||||
body['host'] = host
|
||||
|
||||
if password is not None:
|
||||
body['adminPass'] = password
|
||||
|
||||
@ -23,16 +23,18 @@ import copy
|
||||
import datetime
|
||||
import getpass
|
||||
import locale
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
|
||||
from oslo.utils import encodeutils
|
||||
from oslo.utils import strutils
|
||||
from oslo.utils import timeutils
|
||||
import six
|
||||
|
||||
from novaclient import exceptions
|
||||
from novaclient.openstack.common.gettextutils import _
|
||||
from novaclient.openstack.common import strutils
|
||||
from novaclient.openstack.common import timeutils
|
||||
from novaclient.openstack.common import uuidutils
|
||||
from novaclient import utils
|
||||
from novaclient.v1_1 import availability_zones
|
||||
@ -40,6 +42,9 @@ from novaclient.v1_1 import quotas
|
||||
from novaclient.v1_1 import servers
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
CLIENT_BDM2_KEYS = {
|
||||
'id': 'uuid',
|
||||
'source': 'source_type',
|
||||
@ -356,6 +361,7 @@ def _boot(cs, args):
|
||||
help=_("Store arbitrary files from <src-path> locally to <dst-path> "
|
||||
"on the new server. You may store up to 5 files."))
|
||||
@utils.arg('--key-name',
|
||||
default=os.environ.get('NOVACLIENT_DEFAULT_KEY_NAME'),
|
||||
metavar='<key-name>',
|
||||
help=_("Key name of keypair that should be created earlier with \
|
||||
the command keypair-add"))
|
||||
@ -506,7 +512,7 @@ def _poll_for_status(poll_fn, obj_id, action, final_ok_states,
|
||||
sys.stdout.flush()
|
||||
|
||||
if not silent:
|
||||
print
|
||||
print()
|
||||
|
||||
while True:
|
||||
obj = poll_fn(obj_id)
|
||||
@ -586,7 +592,7 @@ def _print_flavor_list(flavors, show_extra_specs=False):
|
||||
'Memory_MB',
|
||||
'Disk',
|
||||
'Ephemeral',
|
||||
'Swap_MB',
|
||||
'Swap',
|
||||
'VCPUs',
|
||||
'RXTX_Factor',
|
||||
'Is_Public',
|
||||
@ -778,10 +784,25 @@ def do_scrub(cs, args):
|
||||
cs.security_groups.delete(group)
|
||||
|
||||
|
||||
def do_network_list(cs, _args):
|
||||
@utils.arg('--fields',
|
||||
default=None,
|
||||
metavar='<fields>',
|
||||
help='Comma-separated list of fields to display. '
|
||||
'Use the show command to see which fields are available.')
|
||||
def do_network_list(cs, args):
|
||||
"""Print a list of available networks."""
|
||||
network_list = cs.networks.list()
|
||||
columns = ['ID', 'Label', 'Cidr']
|
||||
|
||||
formatters = {}
|
||||
field_titles = []
|
||||
if args.fields:
|
||||
for field in args.fields.split(','):
|
||||
field_title, formatter = utils._make_field_formatter(field, {})
|
||||
field_titles.append(field_title)
|
||||
formatters[field_title] = formatter
|
||||
|
||||
columns = columns + field_titles
|
||||
utils.print_list(network_list, columns)
|
||||
|
||||
|
||||
@ -794,6 +815,15 @@ def do_network_show(cs, args):
|
||||
utils.print_dict(network._info)
|
||||
|
||||
|
||||
@utils.arg('network',
|
||||
metavar='<network>',
|
||||
help=_("uuid or label of network"))
|
||||
def do_network_delete(cs, args):
|
||||
"""Delete network by label or id."""
|
||||
network = utils.find_resource(cs.networks, args.network)
|
||||
network.delete()
|
||||
|
||||
|
||||
@utils.arg('--host-only',
|
||||
dest='host_only',
|
||||
metavar='<0|1>',
|
||||
@ -844,7 +874,8 @@ def _filter_network_create_options(args):
|
||||
valid_args = ['label', 'cidr', 'vlan_start', 'vpn_start', 'cidr_v6',
|
||||
'gateway', 'gateway_v6', 'bridge', 'bridge_interface',
|
||||
'multi_host', 'dns1', 'dns2', 'uuid', 'fixed_cidr',
|
||||
'project_id', 'priority', 'vlan']
|
||||
'project_id', 'priority', 'vlan', 'mtu', 'dhcp_server',
|
||||
'allowed_start', 'allowed_end']
|
||||
kwargs = {}
|
||||
for k, v in args.__dict__.items():
|
||||
if k in valid_args and v is not None:
|
||||
@ -865,15 +896,18 @@ def _filter_network_create_options(args):
|
||||
help=_('IPv6 subnet (ex: fe80::/64'))
|
||||
@utils.arg('--vlan',
|
||||
dest='vlan',
|
||||
type=int,
|
||||
metavar='<vlan id>',
|
||||
help=_("vlan id to be assigned to project"))
|
||||
help=_("The vlan ID to be assigned to the project."))
|
||||
@utils.arg('--vlan-start',
|
||||
dest='vlan_start',
|
||||
type=int,
|
||||
metavar='<vlan start>',
|
||||
help=_('First vlan ID to be assigned to project. Subsequent vlan'
|
||||
' IDs will be assigned incrementally'))
|
||||
help=_('First vlan ID to be assigned to the project. Subsequent vlan '
|
||||
'IDs will be assigned incrementally.'))
|
||||
@utils.arg('--vpn',
|
||||
dest='vpn_start',
|
||||
type=int,
|
||||
metavar='<vpn start>',
|
||||
help=_("vpn start"))
|
||||
@utils.arg('--gateway',
|
||||
@ -881,15 +915,15 @@ def _filter_network_create_options(args):
|
||||
help=_('gateway'))
|
||||
@utils.arg('--gateway-v6',
|
||||
dest="gateway_v6",
|
||||
help=_('ipv6 gateway'))
|
||||
help=_('IPv6 gateway'))
|
||||
@utils.arg('--bridge',
|
||||
dest="bridge",
|
||||
metavar='<bridge>',
|
||||
help=_('VIFs on this network are connected to this bridge'))
|
||||
help=_('VIFs on this network are connected to this bridge.'))
|
||||
@utils.arg('--bridge-interface',
|
||||
dest="bridge_interface",
|
||||
metavar='<bridge interface>',
|
||||
help=_('the bridge is connected to this interface'))
|
||||
help=_('The bridge is connected to this interface.'))
|
||||
@utils.arg('--multi-host',
|
||||
dest="multi_host",
|
||||
metavar="<'T'|'F'>",
|
||||
@ -908,25 +942,52 @@ def _filter_network_create_options(args):
|
||||
@utils.arg('--fixed-cidr',
|
||||
dest="fixed_cidr",
|
||||
metavar='<x.x.x.x/yy>',
|
||||
help=_('IPv4 subnet for fixed IPS (ex: 10.20.0.0/16)'))
|
||||
help=_('IPv4 subnet for fixed IPs (ex: 10.20.0.0/16)'))
|
||||
@utils.arg('--project-id',
|
||||
dest="project_id",
|
||||
metavar="<project id>",
|
||||
help=_('Project id'))
|
||||
help=_('Project ID'))
|
||||
@utils.arg('--priority',
|
||||
dest="priority",
|
||||
metavar="<number>",
|
||||
help=_('Network interface priority'))
|
||||
@utils.arg('--mtu',
|
||||
dest="mtu",
|
||||
type=int,
|
||||
help=_('MTU for network'))
|
||||
@utils.arg('--enable-dhcp',
|
||||
dest="enable_dhcp",
|
||||
metavar="<'T'|'F'>",
|
||||
help=_('Enable dhcp'))
|
||||
@utils.arg('--dhcp-server',
|
||||
dest="dhcp_server",
|
||||
help=_('Dhcp-server (defaults to gateway address)'))
|
||||
@utils.arg('--share-address',
|
||||
dest="share_address",
|
||||
metavar="<'T'|'F'>",
|
||||
help=_('Share address'))
|
||||
@utils.arg('--allowed-start',
|
||||
dest="allowed_start",
|
||||
help=_('Start of allowed addresses for instances'))
|
||||
@utils.arg('--allowed-end',
|
||||
dest="allowed_end",
|
||||
help=_('End of allowed addresses for instances'))
|
||||
def do_network_create(cs, args):
|
||||
"""Create a network."""
|
||||
|
||||
if not (args.cidr or args.cidr_v6):
|
||||
raise exceptions.CommandError(
|
||||
_("Must specify eith fixed_range_v4 or fixed_range_v6"))
|
||||
_("Must specify either fixed_range_v4 or fixed_range_v6"))
|
||||
kwargs = _filter_network_create_options(args)
|
||||
if args.multi_host is not None:
|
||||
kwargs['multi_host'] = bool(args.multi_host == 'T' or
|
||||
strutils.bool_from_string(args.multi_host))
|
||||
if args.enable_dhcp is not None:
|
||||
kwargs['enable_dhcp'] = bool(args.enable_dhcp == 'T' or
|
||||
strutils.bool_from_string(args.enable_dhcp))
|
||||
if args.share_address is not None:
|
||||
kwargs['share_address'] = bool(args.share_address == 'T' or
|
||||
strutils.bool_from_string(args.share_address))
|
||||
|
||||
cs.networks.create(**kwargs)
|
||||
|
||||
@ -934,7 +995,7 @@ def do_network_create(cs, args):
|
||||
@utils.arg('--limit',
|
||||
dest="limit",
|
||||
metavar="<limit>",
|
||||
help=_('number of images to return per request'))
|
||||
help=_('Number of images to return per request.'))
|
||||
def do_image_list(cs, _args):
|
||||
"""Print a list of available images to boot from."""
|
||||
limit = _args.limit
|
||||
@ -1110,7 +1171,7 @@ def do_image_delete(cs, args):
|
||||
const=1,
|
||||
help=argparse.SUPPRESS)
|
||||
@utils.arg('--tenant',
|
||||
#nova db searches by project_id
|
||||
# nova db searches by project_id
|
||||
dest='tenant',
|
||||
metavar='<tenant>',
|
||||
nargs='?',
|
||||
@ -1242,6 +1303,23 @@ def do_reboot(cs, args):
|
||||
action="store_true",
|
||||
default=False,
|
||||
help='Preserve the default ephemeral storage partition on rebuild.')
|
||||
@utils.arg('--name',
|
||||
metavar='<name>',
|
||||
default=None,
|
||||
help=_('Name for the new server'))
|
||||
@utils.arg('--meta',
|
||||
metavar="<key=value>",
|
||||
action='append',
|
||||
default=[],
|
||||
help=_("Record arbitrary key/value metadata to /meta.js "
|
||||
"on the new server. Can be specified multiple times."))
|
||||
@utils.arg('--file',
|
||||
metavar="<dst-path=src-path>",
|
||||
action='append',
|
||||
dest='files',
|
||||
default=[],
|
||||
help=_("Store arbitrary files from <src-path> locally to <dst-path> "
|
||||
"on the new server. You may store up to 5 files."))
|
||||
def do_rebuild(cs, args):
|
||||
"""Shutdown, re-image, and re-boot a server."""
|
||||
server = _find_server(cs, args.server)
|
||||
@ -1254,6 +1332,25 @@ def do_rebuild(cs, args):
|
||||
|
||||
kwargs = utils.get_resource_manager_extra_kwargs(do_rebuild, args)
|
||||
kwargs['preserve_ephemeral'] = args.preserve_ephemeral
|
||||
kwargs['name'] = args.name
|
||||
meta = dict(v.split('=', 1) for v in args.meta)
|
||||
kwargs['meta'] = meta
|
||||
|
||||
files = {}
|
||||
for f in args.files:
|
||||
try:
|
||||
dst, src = f.split('=', 1)
|
||||
with open(src, 'r') as s:
|
||||
files[dst] = s.read()
|
||||
except IOError as e:
|
||||
raise exceptions.CommandError(_("Can't open '%(src)s': %(exc)s") %
|
||||
{'src': src, 'exc': e})
|
||||
except ValueError as e:
|
||||
raise exceptions.CommandError(_("Invalid file argument '%s'. "
|
||||
"File arguments must be of the "
|
||||
"form '--file "
|
||||
"<dst-path=src-path>'") % f)
|
||||
kwargs['files'] = files
|
||||
server = server.rebuild(image, _password, **kwargs)
|
||||
_print_server(cs, args, server)
|
||||
|
||||
@ -1529,8 +1626,11 @@ def _print_server(cs, args, server=None):
|
||||
flavor_id)
|
||||
|
||||
if 'security_groups' in info:
|
||||
info['security_groups'] = \
|
||||
', '.join(group['name'] for group in info['security_groups'])
|
||||
# when we have multiple nics the info will include the
|
||||
# security groups N times where N == number of nics. Be nice
|
||||
# and only display it once.
|
||||
info['security_groups'] = ', '.join(
|
||||
sorted(set(group['name'] for group in info['security_groups'])))
|
||||
|
||||
image = info.get('image', {})
|
||||
if image:
|
||||
@ -1567,19 +1667,19 @@ def do_show(cs, args):
|
||||
help=_('Name or ID of server(s).'))
|
||||
def do_delete(cs, args):
|
||||
"""Immediately shut down and delete specified server(s)."""
|
||||
failure_count = 0
|
||||
failure_flag = False
|
||||
|
||||
for server in args.server:
|
||||
try:
|
||||
_find_server(cs, server).delete()
|
||||
print(_("Request to delete server %s has been accepted.") % server)
|
||||
except Exception as e:
|
||||
failure_count += 1
|
||||
failure_flag = True
|
||||
print(e)
|
||||
|
||||
if failure_count == len(args.server):
|
||||
raise exceptions.CommandError(_("Unable to delete any of the "
|
||||
"specified servers."))
|
||||
if failure_flag:
|
||||
raise exceptions.CommandError(_("Unable to delete the "
|
||||
"specified server(s)."))
|
||||
|
||||
|
||||
def _find_server(cs, server):
|
||||
@ -1940,6 +2040,27 @@ def do_get_rdp_console(cs, args):
|
||||
utils.print_list([RDPConsole(data['console'])], ['Type', 'Url'])
|
||||
|
||||
|
||||
@utils.arg('server', metavar='<server>', help=_('Name or ID of server.'))
|
||||
@utils.arg('--console_type', default='serial',
|
||||
help=_('Type of serial console, default="serial".'))
|
||||
def do_get_serial_console(cs, args):
|
||||
"""Get a serial console to a server."""
|
||||
if args.console_type not in ('serial',):
|
||||
raise exceptions.CommandError(
|
||||
_("Invalid parameter value for 'console_type', "
|
||||
"currently supported 'serial'."))
|
||||
|
||||
server = _find_server(cs, args.server)
|
||||
data = server.get_serial_console(args.console_type)
|
||||
|
||||
class SerialConsole:
|
||||
def __init__(self, console_dict):
|
||||
self.type = console_dict['type']
|
||||
self.url = console_dict['url']
|
||||
|
||||
utils.print_list([SerialConsole(data['console'])], ['Type', 'Url'])
|
||||
|
||||
|
||||
@utils.arg('server', metavar='<server>', help='Name or ID of server.')
|
||||
@utils.arg('private_key',
|
||||
metavar='<private-key>',
|
||||
@ -2194,7 +2315,7 @@ def do_dns_create_public_domain(cs, args):
|
||||
args.project)
|
||||
|
||||
|
||||
def _print_secgroup_rules(rules):
|
||||
def _print_secgroup_rules(rules, show_source_group=True):
|
||||
class FormattedRule:
|
||||
def __init__(self, obj):
|
||||
items = (obj if isinstance(obj, dict) else obj._info).items()
|
||||
@ -2210,8 +2331,10 @@ def _print_secgroup_rules(rules):
|
||||
setattr(self, k, v)
|
||||
|
||||
rules = [FormattedRule(rule) for rule in rules]
|
||||
utils.print_list(rules, ['IP Protocol', 'From Port', 'To Port',
|
||||
'IP Range', 'Source Group'])
|
||||
headers = ['IP Protocol', 'From Port', 'To Port', 'IP Range']
|
||||
if show_source_group:
|
||||
headers.append('Source Group')
|
||||
utils.print_list(rules, headers)
|
||||
|
||||
|
||||
def _print_secgroups(secgroups):
|
||||
@ -2220,7 +2343,7 @@ def _print_secgroups(secgroups):
|
||||
|
||||
def _get_secgroup(cs, secgroup):
|
||||
# Check secgroup is an ID (nova-network) or UUID (neutron)
|
||||
if (utils.is_integer_like(strutils.safe_encode(secgroup))
|
||||
if (utils.is_integer_like(encodeutils.safe_encode(secgroup))
|
||||
or uuidutils.is_uuid_like(secgroup)):
|
||||
try:
|
||||
return cs.security_groups.get(secgroup)
|
||||
@ -2504,7 +2627,7 @@ def _find_keypair(cs, keypair):
|
||||
|
||||
|
||||
@utils.arg('--tenant',
|
||||
#nova db searches by project_id
|
||||
# nova db searches by project_id
|
||||
dest='tenant',
|
||||
metavar='<tenant>',
|
||||
nargs='?',
|
||||
@ -2786,6 +2909,14 @@ def do_aggregate_set_metadata(cs, args):
|
||||
"""Update the metadata associated with the aggregate."""
|
||||
aggregate = _find_aggregate(cs, args.aggregate)
|
||||
metadata = _extract_metadata(args)
|
||||
currentmetadata = getattr(aggregate, 'metadata', {})
|
||||
if set(metadata.items()) & set(currentmetadata.items()):
|
||||
raise exceptions.CommandError(_("metadata already exists"))
|
||||
for key, value in metadata.items():
|
||||
if value is None and key not in currentmetadata:
|
||||
raise exceptions.CommandError(_("metadata key %s does not exist"
|
||||
" hence can not be deleted")
|
||||
% key)
|
||||
aggregate = cs.aggregates.set_metadata(aggregate.id, metadata)
|
||||
print(_("Metadata has been successfully updated for aggregate %s.") %
|
||||
aggregate.id)
|
||||
@ -3102,9 +3233,41 @@ def ensure_service_catalog_present(cs):
|
||||
def do_endpoints(cs, _args):
|
||||
"""Discover endpoints that get returned from the authenticate services."""
|
||||
ensure_service_catalog_present(cs)
|
||||
|
||||
catalog = cs.client.service_catalog.catalog
|
||||
for e in catalog['access']['serviceCatalog']:
|
||||
utils.print_dict(e['endpoints'][0], e['name'])
|
||||
region = cs.client.region_name
|
||||
|
||||
for service in catalog['access']['serviceCatalog']:
|
||||
name, endpoints = service["name"], service["endpoints"]
|
||||
|
||||
try:
|
||||
endpoint = _get_first_endpoint(endpoints, region)
|
||||
utils.print_dict(endpoint, name)
|
||||
except LookupError:
|
||||
print(_("WARNING: %(service)s has no endpoint in %(region)s! "
|
||||
"Available endpoints for this service:") %
|
||||
{'service': name, 'region': region})
|
||||
for other_endpoint in endpoints:
|
||||
utils.print_dict(other_endpoint, name)
|
||||
|
||||
|
||||
def _get_first_endpoint(endpoints, region):
|
||||
"""Find the first suitable endpoint in endpoints.
|
||||
|
||||
If there is only one endpoint, return it. If there is more than
|
||||
one endpoint, return the first one with the given region. If there
|
||||
are no endpoints, or there is more than one endpoint but none of
|
||||
them match the given region, raise KeyError.
|
||||
|
||||
"""
|
||||
if len(endpoints) == 1:
|
||||
return endpoints[0]
|
||||
else:
|
||||
for candidate_endpoint in endpoints:
|
||||
if candidate_endpoint["region"] == region:
|
||||
return candidate_endpoint
|
||||
|
||||
raise LookupError("No suitable endpoint found")
|
||||
|
||||
|
||||
@utils.arg('--wrap', dest='wrap', metavar='<integer>', default=64,
|
||||
@ -3130,9 +3293,16 @@ def do_credentials(cs, _args):
|
||||
dest='private',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help=_('Optional flag to indicate whether to only use private address '
|
||||
'attached to an instance. (Default=False). If no public address is '
|
||||
'found try private address'))
|
||||
help=argparse.SUPPRESS)
|
||||
@utils.arg('--address-type',
|
||||
dest='address_type',
|
||||
action='store',
|
||||
type=str,
|
||||
default='floating',
|
||||
help=_('Optional flag to indicate which IP type to use. Possible values '
|
||||
'includes fixed and floating (the Default).'))
|
||||
@utils.arg('--network', metavar='<network>',
|
||||
help=_('Network to use for the ssh.'), default=None)
|
||||
@utils.arg('--ipv6',
|
||||
dest='ipv6',
|
||||
action='store_true',
|
||||
@ -3157,42 +3327,65 @@ def do_ssh(cs, args):
|
||||
args.server = server
|
||||
|
||||
addresses = _find_server(cs, args.server).addresses
|
||||
address_type = "private" if args.private else "public"
|
||||
address_type = "fixed" if args.private else args.address_type
|
||||
version = 6 if args.ipv6 else 4
|
||||
pretty_version = 'IPv%d' % version
|
||||
|
||||
if (address_type == "public" and address_type not in addresses and
|
||||
"private" in addresses):
|
||||
address_type = "private"
|
||||
# Select the network to use.
|
||||
if args.network:
|
||||
network_addresses = addresses.get(args.network)
|
||||
if not network_addresses:
|
||||
msg = _("Server '%(server)s' is not attached to network "
|
||||
"'%(network)s'")
|
||||
raise exceptions.ResourceNotFound(
|
||||
msg % {'server': args.server, 'network': args.network})
|
||||
else:
|
||||
if len(addresses) > 1:
|
||||
msg = _("Server '%(server)s' is attached to more than one network."
|
||||
" Please pick the network to use.")
|
||||
raise exceptions.CommandError(msg % {'server': args.server})
|
||||
elif not addresses:
|
||||
msg = _("Server '%(server)s' is not attached to any network.")
|
||||
raise exceptions.CommandError(msg % {'server': args.server})
|
||||
else:
|
||||
network_addresses = list(six.itervalues(addresses))[0]
|
||||
|
||||
if address_type not in addresses:
|
||||
print(_("ERROR: No %(addr_type)s addresses found for '%(server)s'.") %
|
||||
{'addr_type': address_type, 'server': args.server})
|
||||
return
|
||||
|
||||
ip_address = None
|
||||
for address in addresses[address_type]:
|
||||
if address['version'] == version:
|
||||
ip_address = address['addr']
|
||||
break
|
||||
# Select the address in the selected network.
|
||||
# If the extension is not present, we assume the address to be floating.
|
||||
match = lambda addr: all((
|
||||
addr.get('version') == version,
|
||||
addr.get('OS-EXT-IPS:type', 'floating') == address_type))
|
||||
matching_addresses = [address.get('addr') for address in network_addresses
|
||||
if match(address)]
|
||||
if not any(matching_addresses):
|
||||
msg = _("No address that would match network '%(network)s'"
|
||||
" and type '%(address_type)s' of version %(pretty_version)s "
|
||||
"has been found for server '%(server)s'.")
|
||||
raise exceptions.ResourceNotFound(msg % {
|
||||
'network': args.network, 'address_type': address_type,
|
||||
'pretty_version': pretty_version, 'server': args.server})
|
||||
elif len(matching_addresses) > 1:
|
||||
msg = _("More than one %(pretty_version)s %(address_type)s address"
|
||||
"found.")
|
||||
raise exceptions.CommandError(msg % {'pretty_version': pretty_version,
|
||||
'address_type': address_type})
|
||||
else:
|
||||
ip_address = matching_addresses[0]
|
||||
|
||||
identity = '-i %s' % args.identity if len(args.identity) else ''
|
||||
|
||||
if ip_address:
|
||||
os.system("ssh -%d -p%d %s %s@%s %s" % (version, args.port, identity,
|
||||
args.login, ip_address,
|
||||
args.extra))
|
||||
else:
|
||||
pretty_version = "IPv%d" % version
|
||||
print(_("ERROR: No %(addr_type)s %(pretty_version)s address found.") %
|
||||
{'addr_type': address_type, 'pretty_version': pretty_version})
|
||||
return
|
||||
cmd = "ssh -%d -p%d %s %s@%s %s" % (version, args.port, identity,
|
||||
args.login, ip_address, args.extra)
|
||||
logger.debug("Executing cmd '%s'", cmd)
|
||||
os.system(cmd)
|
||||
|
||||
|
||||
_quota_resources = ['instances', 'cores', 'ram',
|
||||
'floating_ips', 'fixed_ips', 'metadata_items',
|
||||
'injected_files', 'injected_file_content_bytes',
|
||||
'injected_file_path_bytes', 'key_pairs',
|
||||
'security_groups', 'security_group_rules']
|
||||
'security_groups', 'security_group_rules',
|
||||
'server_groups', 'server_group_members']
|
||||
|
||||
|
||||
def _quota_show(quotas):
|
||||
@ -3337,6 +3530,16 @@ def do_quota_defaults(cs, args):
|
||||
type=int,
|
||||
default=None,
|
||||
help=_('New value for the "security-group-rules" quota.'))
|
||||
@utils.arg('--server-groups',
|
||||
metavar='<server-groups>',
|
||||
type=int,
|
||||
default=None,
|
||||
help=_('New value for the "server-groups" quota.'))
|
||||
@utils.arg('--server-group-members',
|
||||
metavar='<server-group-members>',
|
||||
type=int,
|
||||
default=None,
|
||||
help=_('New value for the "server-group-members" quota.'))
|
||||
@utils.arg('--force',
|
||||
dest='force',
|
||||
action="store_true",
|
||||
@ -3351,6 +3554,7 @@ def do_quota_update(cs, args):
|
||||
|
||||
@utils.arg('--tenant',
|
||||
metavar='<tenant-id>',
|
||||
required=True,
|
||||
help=_('ID of tenant to delete quota for.'))
|
||||
@utils.arg('--user',
|
||||
metavar='<user-id>',
|
||||
@ -3444,6 +3648,16 @@ def do_quota_class_show(cs, args):
|
||||
type=int,
|
||||
default=None,
|
||||
help=_('New value for the "security-group-rules" quota.'))
|
||||
@utils.arg('--server-groups',
|
||||
metavar='<server-groups>',
|
||||
type=int,
|
||||
default=None,
|
||||
help=_('New value for the "server-groups" quota.'))
|
||||
@utils.arg('--server-group-members',
|
||||
metavar='<server-group-members>',
|
||||
type=int,
|
||||
default=None,
|
||||
help=_('New value for the "server-group-members" quota.'))
|
||||
def do_quota_class_update(cs, args):
|
||||
"""Update the quotas for a quota class."""
|
||||
|
||||
@ -3451,11 +3665,12 @@ def do_quota_class_update(cs, args):
|
||||
|
||||
|
||||
@utils.arg('server', metavar='<server>', help=_('Name or ID of server.'))
|
||||
@utils.arg('host', metavar='<host>', help=_('Name or ID of target host.'))
|
||||
@utils.arg('host', metavar='<host>', nargs='?',
|
||||
help=_("Name or ID of the target host. "
|
||||
"If no host is specified, the scheduler will choose one."))
|
||||
@utils.arg('--password',
|
||||
dest='password',
|
||||
metavar='<password>',
|
||||
default=None,
|
||||
help=_("Set the provided password on the evacuated server. Not applicable "
|
||||
"with on-shared-storage flag"))
|
||||
@utils.arg('--on-shared-storage',
|
||||
@ -3464,7 +3679,8 @@ def do_quota_class_update(cs, args):
|
||||
default=False,
|
||||
help=_('Specifies whether server files are located on shared storage'))
|
||||
def do_evacuate(cs, args):
|
||||
"""Evacuate server from failed host to specified one."""
|
||||
"""Evacuate server from failed host."""
|
||||
|
||||
server = _find_server(cs, args.server)
|
||||
|
||||
res = server.evacuate(args.host, args.on_shared_storage, args.password)[1]
|
||||
@ -3597,6 +3813,55 @@ def do_server_group_list(cs, args):
|
||||
_print_server_group_details(server_groups)
|
||||
|
||||
|
||||
def do_secgroup_list_default_rules(cs, args):
|
||||
"""List rules for the default security group."""
|
||||
_print_secgroup_rules(cs.security_group_default_rules.list(),
|
||||
show_source_group=False)
|
||||
|
||||
|
||||
@utils.arg('ip_proto',
|
||||
metavar='<ip-proto>',
|
||||
help=_('IP protocol (icmp, tcp, udp).'))
|
||||
@utils.arg('from_port',
|
||||
metavar='<from-port>',
|
||||
help=_('Port at start of range.'))
|
||||
@utils.arg('to_port',
|
||||
metavar='<to-port>',
|
||||
help=_('Port at end of range.'))
|
||||
@utils.arg('cidr', metavar='<cidr>', help=_('CIDR for address range.'))
|
||||
def do_secgroup_add_default_rule(cs, args):
|
||||
"""Add a rule to the default security group."""
|
||||
rule = cs.security_group_default_rules.create(args.ip_proto,
|
||||
args.from_port,
|
||||
args.to_port,
|
||||
args.cidr)
|
||||
_print_secgroup_rules([rule], show_source_group=False)
|
||||
|
||||
|
||||
@utils.arg('ip_proto',
|
||||
metavar='<ip-proto>',
|
||||
help=_('IP protocol (icmp, tcp, udp).'))
|
||||
@utils.arg('from_port',
|
||||
metavar='<from-port>',
|
||||
help=_('Port at start of range.'))
|
||||
@utils.arg('to_port',
|
||||
metavar='<to-port>',
|
||||
help=_('Port at end of range.'))
|
||||
@utils.arg('cidr', metavar='<cidr>', help=_('CIDR for address range.'))
|
||||
def do_secgroup_delete_default_rule(cs, args):
|
||||
"""Delete a rule from the default security group."""
|
||||
for rule in cs.security_group_default_rules.list():
|
||||
if (rule.ip_protocol and
|
||||
rule.ip_protocol.upper() == args.ip_proto.upper() and
|
||||
rule.from_port == int(args.from_port) and
|
||||
rule.to_port == int(args.to_port) and
|
||||
rule.ip_range['cidr'] == args.cidr):
|
||||
_print_secgroup_rules([rule], show_source_group=False)
|
||||
return cs.security_group_default_rules.delete(rule.id)
|
||||
|
||||
raise exceptions.CommandError(_("Rule not found"))
|
||||
|
||||
|
||||
@utils.arg('name', metavar='<name>', help='Server group name.')
|
||||
# NOTE(wingwj): The '--policy' way is still reserved here for preserving
|
||||
# the backwards compatibility of CLI, even if a user won't get this usage
|
||||
@ -3654,3 +3919,10 @@ def do_server_group_get(cs, args):
|
||||
"""Get a specific server group."""
|
||||
server_group = cs.server_groups.get(args.id)
|
||||
_print_server_group_details([server_group])
|
||||
|
||||
|
||||
def do_version_list(cs, args):
|
||||
"""List all API versions."""
|
||||
result = cs.versions.list()
|
||||
columns = ["Id", "Status", "Updated"]
|
||||
utils.print_list(result, columns)
|
||||
|
||||
35
awx/lib/site-packages/novaclient/v1_1/versions.py
Normal file
35
awx/lib/site-packages/novaclient/v1_1/versions.py
Normal file
@ -0,0 +1,35 @@
|
||||
# Copyright 2014 NEC Corporation. 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.
|
||||
|
||||
"""
|
||||
version interface
|
||||
"""
|
||||
|
||||
from novaclient import base
|
||||
|
||||
|
||||
class Version(base.Resource):
|
||||
"""
|
||||
Compute REST API information
|
||||
"""
|
||||
def __repr__(self):
|
||||
return "<Version>"
|
||||
|
||||
|
||||
class VersionManager(base.ManagerWithFind):
|
||||
resource_class = Version
|
||||
|
||||
def list(self):
|
||||
"""List all versions."""
|
||||
return self._list(None, "versions")
|
||||
@ -104,36 +104,6 @@ class Client(object):
|
||||
cacert=None, tenant_id=None, user_id=None,
|
||||
connection_pool=False, session=None, auth=None,
|
||||
**kwargs):
|
||||
"""
|
||||
:param str username: Username
|
||||
:param str api_key: API Key
|
||||
:param str project_id: Project ID
|
||||
:param str auth_url: Auth URL
|
||||
:param bool insecure: Allow insecure
|
||||
:param float timeout: API timeout, None or 0 disables
|
||||
:param str proxy_tenant_id: Tenant ID
|
||||
:param str proxy_token: Proxy Token
|
||||
:param str region_name: Region Name
|
||||
:param str endpoint_type: Endpoint Type
|
||||
:param str extensions: Exensions
|
||||
:param str service_type: Service Type
|
||||
:param str service_name: Service Name
|
||||
:param str volume_service_name: Volume Service Name
|
||||
:param bool timings: Timings
|
||||
:param str bypass_url: Bypass URL
|
||||
:param bool os_cache: OS cache
|
||||
:param bool no_cache: No cache
|
||||
:param bool http_log_debug: Enable debugging for HTTP connections
|
||||
:param str auth_system: Auth system
|
||||
:param str auth_plugin: Auth plugin
|
||||
:param str auth_token: Auth token
|
||||
:param str cacert: cacert
|
||||
:param str tenant_id: Tenant ID
|
||||
:param str user_id: User ID
|
||||
:param bool connection_pool: Use a connection pool
|
||||
:param str session: Session
|
||||
:param str auth: Auth
|
||||
"""
|
||||
# FIXME(comstud): Rename the api_key argument above when we
|
||||
# know it's not being used as keyword argument
|
||||
|
||||
|
||||
@ -423,6 +423,40 @@ class ServerManager(base.BootingManagerWithFind):
|
||||
config_drive=None, admin_pass=None, disk_config=None, **kwargs):
|
||||
"""
|
||||
Create (boot) a new server.
|
||||
|
||||
:param name: Something to name the server.
|
||||
:param image: The :class:`Image` to boot with.
|
||||
:param flavor: The :class:`Flavor` to boot onto.
|
||||
:param meta: A dict of arbitrary key/value metadata to store for this
|
||||
server. A maximum of five entries is allowed, and both
|
||||
keys and values must be 255 characters or less.
|
||||
:param files: A dict of files to overwrite on the server upon boot.
|
||||
Keys are file names (i.e. ``/etc/passwd``) and values
|
||||
are the file contents (either as a string or as a
|
||||
file-like object). A maximum of five entries is allowed,
|
||||
and each file must be 10k or less.
|
||||
:param reservation_id: a UUID for the set of servers being requested.
|
||||
:param return_raw: If True, don't try to coerce the result into
|
||||
a Resource object.
|
||||
:param security_groups: list of security group names
|
||||
:param key_name: (optional extension) name of keypair to inject into
|
||||
the instance
|
||||
:param availability_zone: Name of the availability zone for instance
|
||||
placement.
|
||||
:param block_device_mapping: A dict of block device mappings for this
|
||||
server.
|
||||
:param block_device_mapping_v2: A dict of block device mappings V2 for
|
||||
this server.
|
||||
:param nics: (optional extension) an ordered list of nics to be
|
||||
added to this server, with information about
|
||||
connected networks, fixed IPs, etc.
|
||||
:param scheduler_hints: (optional extension) arbitrary key-value pairs
|
||||
specified by the client to help boot an instance.
|
||||
:param config_drive: (optional extension) If True, enable config drive
|
||||
on the server.
|
||||
:param admin_pass: admin password for the server.
|
||||
:param disk_config: (optional extension) control how the disk is
|
||||
partitioned when the server is created.
|
||||
"""
|
||||
body = {"server": {
|
||||
"name": name,
|
||||
@ -839,15 +873,10 @@ class ServerManager(base.BootingManagerWithFind):
|
||||
are the file contents (either as a string or as a
|
||||
file-like object). A maximum of five entries is allowed,
|
||||
and each file must be 10k or less.
|
||||
:param reservation_id: a UUID for the set of servers being requested.
|
||||
:param min_count: (optional extension) The minimum number of
|
||||
servers to launch.
|
||||
:param max_count: (optional extension) The maximum number of
|
||||
servers to launch.
|
||||
:param security_groups: A list of security group names
|
||||
:param userdata: user data to pass to be exposed by the metadata
|
||||
server this can be a file type object as well or a
|
||||
string.
|
||||
:param reservation_id: a UUID for the set of servers being requested.
|
||||
:param key_name: (optional extension) name of previously created
|
||||
keypair to inject into the instance.
|
||||
:param availability_zone: Name of the availability zone for instance
|
||||
|
||||
@ -372,7 +372,7 @@ def _boot(cs, args):
|
||||
dest='files',
|
||||
default=[],
|
||||
help=_("Store arbitrary files from <src-path> locally to <dst-path> "
|
||||
"on the new server. Limited by the injected_files quota value."))
|
||||
"on the new server. You may store up to 5 files."))
|
||||
@cliutils.arg(
|
||||
'--key-name',
|
||||
default=os.environ.get('NOVACLIENT_DEFAULT_KEY_NAME'),
|
||||
@ -1897,17 +1897,6 @@ def _find_image(cs, image):
|
||||
def _find_flavor(cs, flavor):
|
||||
"""Get a flavor by name, ID, or RAM size."""
|
||||
try:
|
||||
# isinstance() is being used to check if flavor is an instance of
|
||||
# integer. It will help us to check if the user has entered flavor
|
||||
# name or flavorid. If flavor name has been entered it is being
|
||||
# converted to lowercase using lower(). Incase it is an ID the user
|
||||
# has passed it will not go through the "flavor = flavor.lower()"
|
||||
# code.The reason for checking if it is a flavor name or flavorid is
|
||||
# that int has no lower() so it will give an error.
|
||||
if isinstance(flavor, six.integer_types):
|
||||
pass
|
||||
else:
|
||||
flavor = flavor.lower()
|
||||
return utils.find_resource(cs.flavors, flavor, is_public=None)
|
||||
except exceptions.NotFound:
|
||||
return cs.flavors.find(ram=flavor)
|
||||
@ -1983,6 +1972,7 @@ def _translate_availability_zone_keys(collection):
|
||||
type=int,
|
||||
const=1,
|
||||
help=argparse.SUPPRESS)
|
||||
@cliutils.service_type('volume')
|
||||
def do_volume_list(cs, args):
|
||||
"""List all the volumes."""
|
||||
search_opts = {'all_tenants': args.all_tenants}
|
||||
@ -2001,6 +1991,7 @@ def do_volume_list(cs, args):
|
||||
'volume',
|
||||
metavar='<volume>',
|
||||
help=_('Name or ID of the volume.'))
|
||||
@cliutils.service_type('volume')
|
||||
def do_volume_show(cs, args):
|
||||
"""Show details about a volume."""
|
||||
volume = _find_volume(cs, args.volume)
|
||||
@ -2053,6 +2044,7 @@ def do_volume_show(cs, args):
|
||||
'--availability-zone', metavar='<availability-zone>',
|
||||
help=_('Optional Availability Zone for volume. (Default=None)'),
|
||||
default=None)
|
||||
@cliutils.service_type('volume')
|
||||
def do_volume_create(cs, args):
|
||||
"""Add a new volume."""
|
||||
volume = cs.volumes.create(args.size,
|
||||
@ -2069,6 +2061,7 @@ def do_volume_create(cs, args):
|
||||
'volume',
|
||||
metavar='<volume>', nargs='+',
|
||||
help=_('Name or ID of the volume(s) to delete.'))
|
||||
@cliutils.service_type('volume')
|
||||
def do_volume_delete(cs, args):
|
||||
"""Remove volume(s)."""
|
||||
for volume in args.volume:
|
||||
@ -2135,6 +2128,7 @@ def do_volume_detach(cs, args):
|
||||
args.attachment_id)
|
||||
|
||||
|
||||
@cliutils.service_type('volume')
|
||||
def do_volume_snapshot_list(cs, _args):
|
||||
"""List all the snapshots."""
|
||||
snapshots = cs.volume_snapshots.list()
|
||||
@ -2147,6 +2141,7 @@ def do_volume_snapshot_list(cs, _args):
|
||||
'snapshot',
|
||||
metavar='<snapshot>',
|
||||
help=_('Name or ID of the snapshot.'))
|
||||
@cliutils.service_type('volume')
|
||||
def do_volume_snapshot_show(cs, args):
|
||||
"""Show details about a snapshot."""
|
||||
snapshot = _find_volume_snapshot(cs, args.snapshot)
|
||||
@ -2179,6 +2174,7 @@ def do_volume_snapshot_show(cs, args):
|
||||
@cliutils.arg(
|
||||
'--display_description',
|
||||
help=argparse.SUPPRESS)
|
||||
@cliutils.service_type('volume')
|
||||
def do_volume_snapshot_create(cs, args):
|
||||
"""Add a new snapshot."""
|
||||
snapshot = cs.volume_snapshots.create(args.volume_id,
|
||||
@ -2192,6 +2188,7 @@ def do_volume_snapshot_create(cs, args):
|
||||
'snapshot',
|
||||
metavar='<snapshot>',
|
||||
help=_('Name or ID of the snapshot to delete.'))
|
||||
@cliutils.service_type('volume')
|
||||
def do_volume_snapshot_delete(cs, args):
|
||||
"""Remove a snapshot."""
|
||||
snapshot = _find_volume_snapshot(cs, args.snapshot)
|
||||
@ -2202,6 +2199,7 @@ def _print_volume_type_list(vtypes):
|
||||
utils.print_list(vtypes, ['ID', 'Name'])
|
||||
|
||||
|
||||
@cliutils.service_type('volume')
|
||||
def do_volume_type_list(cs, args):
|
||||
"""Print a list of available 'volume types'."""
|
||||
vtypes = cs.volume_types.list()
|
||||
@ -2212,6 +2210,7 @@ def do_volume_type_list(cs, args):
|
||||
'name',
|
||||
metavar='<name>',
|
||||
help=_("Name of the new volume type"))
|
||||
@cliutils.service_type('volume')
|
||||
def do_volume_type_create(cs, args):
|
||||
"""Create a new volume type."""
|
||||
vtype = cs.volume_types.create(args.name)
|
||||
@ -2222,6 +2221,7 @@ def do_volume_type_create(cs, args):
|
||||
'id',
|
||||
metavar='<id>',
|
||||
help=_("Unique ID of the volume type to delete"))
|
||||
@cliutils.service_type('volume')
|
||||
def do_volume_type_delete(cs, args):
|
||||
"""Delete a specific volume type."""
|
||||
cs.volume_types.delete(args.id)
|
||||
@ -4326,9 +4326,7 @@ def do_server_group_list(cs, args):
|
||||
|
||||
|
||||
def do_secgroup_list_default_rules(cs, args):
|
||||
"""List rules that will be added to the 'default' security group for
|
||||
new tenants.
|
||||
"""
|
||||
"""List rules for the default security group."""
|
||||
_print_secgroup_rules(cs.security_group_default_rules.list(),
|
||||
show_source_group=False)
|
||||
|
||||
@ -4347,9 +4345,7 @@ def do_secgroup_list_default_rules(cs, args):
|
||||
help=_('Port at end of range.'))
|
||||
@cliutils.arg('cidr', metavar='<cidr>', help=_('CIDR for address range.'))
|
||||
def do_secgroup_add_default_rule(cs, args):
|
||||
"""Add a rule to the set of rules that will be added to the 'default'
|
||||
security group for new tenants.
|
||||
"""
|
||||
"""Add a rule to the default security group."""
|
||||
rule = cs.security_group_default_rules.create(args.ip_proto,
|
||||
args.from_port,
|
||||
args.to_port,
|
||||
@ -4371,9 +4367,7 @@ def do_secgroup_add_default_rule(cs, args):
|
||||
help=_('Port at end of range.'))
|
||||
@cliutils.arg('cidr', metavar='<cidr>', help=_('CIDR for address range.'))
|
||||
def do_secgroup_delete_default_rule(cs, args):
|
||||
"""Delete a rule from the set of rules that will be added to the
|
||||
'default' security group for new tenants.
|
||||
"""
|
||||
"""Delete a rule from the default security group."""
|
||||
for rule in cs.security_group_default_rules.list():
|
||||
if (rule.ip_protocol and
|
||||
rule.ip_protocol.upper() == args.ip_proto.upper() and
|
||||
|
||||
@ -55,12 +55,11 @@ class SnapshotManager(base.ManagerWithFind):
|
||||
:param display_description: Description of the snapshot
|
||||
:rtype: :class:`Snapshot`
|
||||
"""
|
||||
with self.alternate_service_type('volume'):
|
||||
body = {'snapshot': {'volume_id': volume_id,
|
||||
'force': force,
|
||||
'display_name': display_name,
|
||||
'display_description': display_description}}
|
||||
return self._create('/snapshots', body, 'snapshot')
|
||||
body = {'snapshot': {'volume_id': volume_id,
|
||||
'force': force,
|
||||
'display_name': display_name,
|
||||
'display_description': display_description}}
|
||||
return self._create('/snapshots', body, 'snapshot')
|
||||
|
||||
def get(self, snapshot_id):
|
||||
"""
|
||||
@ -69,8 +68,7 @@ class SnapshotManager(base.ManagerWithFind):
|
||||
:param snapshot_id: The ID of the snapshot to get.
|
||||
:rtype: :class:`Snapshot`
|
||||
"""
|
||||
with self.alternate_service_type('volume'):
|
||||
return self._get("/snapshots/%s" % snapshot_id, "snapshot")
|
||||
return self._get("/snapshots/%s" % snapshot_id, "snapshot")
|
||||
|
||||
def list(self, detailed=True):
|
||||
"""
|
||||
@ -78,11 +76,10 @@ class SnapshotManager(base.ManagerWithFind):
|
||||
|
||||
:rtype: list of :class:`Snapshot`
|
||||
"""
|
||||
with self.alternate_service_type('volume'):
|
||||
if detailed is True:
|
||||
return self._list("/snapshots/detail", "snapshots")
|
||||
else:
|
||||
return self._list("/snapshots", "snapshots")
|
||||
if detailed is True:
|
||||
return self._list("/snapshots/detail", "snapshots")
|
||||
else:
|
||||
return self._list("/snapshots", "snapshots")
|
||||
|
||||
def delete(self, snapshot):
|
||||
"""
|
||||
@ -90,5 +87,4 @@ class SnapshotManager(base.ManagerWithFind):
|
||||
|
||||
:param snapshot: The :class:`Snapshot` to delete.
|
||||
"""
|
||||
with self.alternate_service_type('volume'):
|
||||
self._delete("/snapshots/%s" % base.getid(snapshot))
|
||||
self._delete("/snapshots/%s" % base.getid(snapshot))
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user