diff --git a/lower-constraints.txt b/lower-constraints.txt index 4ca0c96d4..9f8ea4ee9 100644 --- a/lower-constraints.txt +++ b/lower-constraints.txt @@ -117,7 +117,6 @@ python-glanceclient==2.8.0 python-keystoneclient==3.15.0 python-mimeparse==1.6.0 python-neutronclient==6.7.0 -python-novaclient==9.1.0 python-subunit==1.2.0 pytz==2018.3 PyYAML==3.12 diff --git a/requirements.txt b/requirements.txt index 0d0eaa1fb..a67585e5b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,7 +10,6 @@ pecan!=1.0.2,!=1.0.3,!=1.0.4,!=1.2,>=1.0.0 # BSD python-etcd>=0.4.3 # MIT License python-glanceclient>=2.8.0 # Apache-2.0 python-neutronclient>=6.7.0 # Apache-2.0 -python-novaclient>=9.1.0 # Apache-2.0 python-cinderclient>=3.3.0 # Apache-2.0 oslo.i18n>=3.15.3 # Apache-2.0 oslo.log>=3.36.0 # Apache-2.0 diff --git a/zun/common/clients.py b/zun/common/clients.py index 68466414a..3bc5669aa 100644 --- a/zun/common/clients.py +++ b/zun/common/clients.py @@ -15,7 +15,6 @@ from cinderclient import client as cinderclient from glanceclient import client as glanceclient from neutronclient.v2_0 import client as neutronclient -from novaclient import client as novaclient from zun.common import exception from zun.common import keystone @@ -29,7 +28,6 @@ class OpenStackClients(object): self.context = context self._keystone = None self._glance = None - self._nova = None self._neutron = None self._cinder = None @@ -87,17 +85,6 @@ class OpenStackClients(object): return self._glance - @exception.wrap_keystone_exception - def nova(self): - if self._nova: - return self._nova - - nova_api_version = self._get_client_option('nova', 'api_version') - session = self.keystone().session - self._nova = novaclient.Client(nova_api_version, session=session) - - return self._nova - @exception.wrap_keystone_exception def neutron(self): if self._neutron: diff --git a/zun/common/nova.py b/zun/common/nova.py deleted file mode 100644 index 51438e1f2..000000000 --- a/zun/common/nova.py +++ /dev/null @@ -1,255 +0,0 @@ -# -# 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 requests -import six - -from novaclient import exceptions -from oslo_log import log as logging -from oslo_utils import excutils -from oslo_utils import uuidutils - -from zun.common import clients -from zun.common import exception -from zun.common.i18n import _ - - -LOG = logging.getLogger(__name__) - - -def retry_if_connection_err(exception): - return isinstance(exception, requests.ConnectionError) - - -class NovaClient(object): - - deferred_server_statuses = ['BUILD', - 'HARD_REBOOT', - 'PASSWORD', - 'REBOOT', - 'RESCUE', - 'RESIZE', - 'REVERT_RESIZE', - 'SHUTOFF', - 'SUSPENDED', - 'VERIFY_RESIZE'] - - def __init__(self, context): - self.context = context - self._client = None - - def client(self): - if not self._client: - self._client = clients.OpenStackClients(self.context).nova() - return self._client - - def is_not_found(self, ex): - return isinstance(ex, exceptions.NotFound) - - def create_server(self, name, image, flavor, **kwargs): - image = self.get_image_by_name_or_id(image) - flavor = self.get_flavor_by_name_or_id(flavor) - return self.client().servers.create(name, image, flavor, **kwargs) - - def get_image_by_name_or_id(self, image_ident): - """Get an image by name or ID.""" - try: - return self.client().glance.find_image(image_ident) - except exceptions.NotFound as e: - raise exception.ImageNotFound(six.text_type(e)) - except exceptions.NoUniqueMatch as e: - raise exception.Conflict(six.text_type(e)) - - def get_flavor_by_name_or_id(self, flavor_ident): - """Get the flavor object for the specified flavor name or id. - - :param flavor_identifier: the name or id of the flavor to find - :returns: a flavor object with name or id :flavor: - """ - try: - flavor = self.client().flavors.get(flavor_ident) - except exceptions.NotFound: - flavor = self.client().flavors.find(name=flavor_ident) - - return flavor - - def fetch_server(self, server_id): - """Fetch fresh server object from Nova. - - Log warnings and return None for non-critical API errors. - Use this method in various ``check_*_complete`` resource methods, - where intermittent errors can be tolerated. - """ - server = None - try: - server = self.client().servers.get(server_id) - except exceptions.OverLimit as exc: - LOG.warning("Received an OverLimit response when " - "fetching server (%(id)s) : %(exception)s", - {'id': server_id, - 'exception': exc}) - except exceptions.ClientException as exc: - if ((getattr(exc, 'http_status', getattr(exc, 'code', None)) in - (500, 503))): - LOG.warning("Received the following exception when " - "fetching server (%(id)s) : %(exception)s", - {'id': server_id, - 'exception': exc}) - else: - raise - return server - - def refresh_server(self, server): - """Refresh server's attributes. - - Also log warnings for non-critical API errors. - """ - try: - server.get() - except exceptions.OverLimit as exc: - LOG.warning("Server %(name)s (%(id)s) received an OverLimit " - "response during server.get(): %(exception)s", - {'name': server.name, - 'id': server.id, - 'exception': exc}) - except exceptions.ClientException as exc: - if ((getattr(exc, 'http_status', getattr(exc, 'code', None)) in - (500, 503))): - LOG.warning('Server "%(name)s" (%(id)s) received the ' - 'following exception during server.get(): ' - '%(exception)s', - {'name': server.name, - 'id': server.id, - 'exception': exc}) - else: - raise - - def get_status(self, server): - """Return the server's status. - - :param server: server object - :returns: status as a string - """ - # Some clouds append extra (STATUS) strings to the status, strip it - return server.status.split('(')[0] - - def check_active(self, server): - """Check server status. - - Accepts both server IDs and server objects. - Returns True if server is ACTIVE, - raises errors when server has an ERROR or unknown to Zun status, - returns False otherwise. - - """ - # not checking with is_uuid_like as most tests use strings e.g. '1234' - if isinstance(server, six.string_types): - server = self.fetch_server(server) - if server is None: - return False - else: - status = self.get_status(server) - else: - status = self.get_status(server) - if status != 'ACTIVE': - self.refresh_server(server) - status = self.get_status(server) - - if status in self.deferred_server_statuses: - return False - elif status == 'ACTIVE': - return True - elif status == 'ERROR': - fault = getattr(server, 'fault', {}) - raise exception.ServerInError( - resource_status=status, - status_reason=_("Message: %(message)s, Code: %(code)s") % { - 'message': fault.get('message', _('Unknown')), - 'code': fault.get('code', _('Unknown')) - }) - else: - raise exception.ServerUnknownStatus( - resource_status=server.status, - status_reason=_('Unknown'), - result=_('Server is not active')) - - def delete_server(self, server): - server_id = self.get_server_id(server, raise_on_error=False) - if server_id: - self.client().servers.delete(server_id) - return server_id - - def stop_server(self, server): - server_id = self.get_server_id(server, raise_on_error=False) - if server_id: - self.client().servers.stop(server_id) - return server_id - - def check_delete_server_complete(self, server_id): - """Wait for server to disappear from Nova.""" - try: - server = self.fetch_server(server_id) - except Exception as exc: - self.ignore_not_found(exc) - return True - if not server: - return False - task_state_in_nova = getattr(server, 'OS-EXT-STS:task_state', None) - # the status of server won't change until the delete task has done - if task_state_in_nova == 'deleting': - return False - - status = self.get_status(server) - if status in ("DELETED", "SOFT_DELETED"): - return True - if status == 'ERROR': - fault = getattr(server, 'fault', {}) - message = fault.get('message', 'Unknown') - code = fault.get('code') - errmsg = _("Server %(name)s delete failed: (%(code)s) " - "%(message)s") % dict(name=server.name, - code=code, - message=message) - raise exception.ServerInError(resource_status=status, - status_reason=errmsg) - return False - - @excutils.exception_filter - def ignore_not_found(self, ex): - """Raises the exception unless it is a not-found.""" - return self.is_not_found(ex) - - def get_addresses(self, server): - """Return the server's IP address, fetching it from Nova.""" - try: - server_id = self.get_server_id(server) - server = self.client().servers.get(server_id) - except exceptions.NotFound as ex: - LOG.warning('Instance (%(server)s) not found: %(ex)s', - {'server': server, 'ex': ex}) - else: - return server.addresses - - def get_server_id(self, server, raise_on_error=True): - if uuidutils.is_uuid_like(server): - return server - elif isinstance(server, six.string_types): - servers = self.client().servers.list(search_opts={'name': server}) - if len(servers) == 1: - return servers[0].id - - if raise_on_error: - raise exception.ZunException(_( - "Unable to get server id with name %s") % server) - else: - raise exception.ZunException(_("Unexpected server type")) diff --git a/zun/conf/__init__.py b/zun/conf/__init__.py index 07e28ec72..9e6172a9c 100644 --- a/zun/conf/__init__.py +++ b/zun/conf/__init__.py @@ -27,7 +27,6 @@ from zun.conf import keystone from zun.conf import netconf from zun.conf import network from zun.conf import neutron_client -from zun.conf import nova_client from zun.conf import path from zun.conf import pci from zun.conf import profiler @@ -49,7 +48,6 @@ docker.register_opts(CONF) glance_client.register_opts(CONF) image_driver.register_opts(CONF) keystone.register_opts(CONF) -nova_client.register_opts(CONF) path.register_opts(CONF) scheduler.register_opts(CONF) services.register_opts(CONF) diff --git a/zun/conf/nova_client.py b/zun/conf/nova_client.py deleted file mode 100644 index dccb37083..000000000 --- a/zun/conf/nova_client.py +++ /dev/null @@ -1,51 +0,0 @@ -# -*- encoding: utf-8 -*- -# -# Copyright © 2012 eNovance -# -# 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 oslo_config import cfg - - -nova_group = cfg.OptGroup(name='nova_client', - title='Options for the Nova client') - -common_security_opts = [ - cfg.StrOpt('ca_file', - help='Optional CA cert file to use in SSL connections.'), - cfg.StrOpt('cert_file', - help='Optional PEM-formatted certificate chain file.'), - cfg.StrOpt('key_file', - help='Optional PEM-formatted file that contains the ' - 'private key.'), - cfg.BoolOpt('insecure', - default=False, - help="If set, then the server's certificate will not " - "be verified.")] - -nova_client_opts = [ - cfg.StrOpt('api_version', - default='2.37', - help='Version of Nova API to use in novaclient.')] - - -ALL_OPTS = (nova_client_opts + common_security_opts) - - -def register_opts(conf): - conf.register_group(nova_group) - conf.register_opts(ALL_OPTS, group=nova_group) - - -def list_opts(): - return {nova_group: ALL_OPTS} diff --git a/zun/hacking/checks.py b/zun/hacking/checks.py index 96009cc6f..ded476a66 100644 --- a/zun/hacking/checks.py +++ b/zun/hacking/checks.py @@ -22,7 +22,7 @@ Guidelines for writing new hacking checks should be submitted to the common 'hacking' module. - Pick numbers in the range Z3xx. Find the current test with the highest allocated number and then pick the next value. - If nova has an N3xx code for that test, use the same number. + If zun has an N3xx code for that test, use the same number. - Keep the test method code in the source file ordered based on the Z3xx value. - List the new rule in the top level HACKING.rst file