[lxc-devel] [nova-lxd/master] Single session class
rockstar on Github
lxc-bot at linuxcontainers.org
Tue Feb 2 12:20:39 UTC 2016
A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 508 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20160202/625f3d2f/attachment.bin>
-------------- next part --------------
From d42df7f1247cbd0f6ef8521efbc06ae59bb3dc09 Mon Sep 17 00:00:00 2001
From: Paul Hummer <paul.hummer at canonical.com>
Date: Tue, 2 Feb 2016 03:50:01 -0700
Subject: [PATCH 1/8] Consolidate image session handling.
---
nova_lxd/nova/virt/lxd/session/image.py | 115 ------------------------------
nova_lxd/nova/virt/lxd/session/session.py | 90 ++++++++++++++++++++++-
2 files changed, 88 insertions(+), 117 deletions(-)
delete mode 100644 nova_lxd/nova/virt/lxd/session/image.py
diff --git a/nova_lxd/nova/virt/lxd/session/image.py b/nova_lxd/nova/virt/lxd/session/image.py
deleted file mode 100644
index 5fa6275..0000000
--- a/nova_lxd/nova/virt/lxd/session/image.py
+++ /dev/null
@@ -1,115 +0,0 @@
-# Copyright 2015 Canonical Ltd
-# 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.
-
-from nova import exception
-from nova import i18n
-from pylxd import exceptions as lxd_exceptions
-
-from oslo_config import cfg
-from oslo_log import log as logging
-from oslo_utils import excutils
-
-_ = i18n._
-_LE = i18n._LE
-
-CONF = cfg.CONF
-LOG = logging.getLogger(__name__)
-
-
-class ImageMixin(object):
- """Image functions for LXD."""
-
- def image_defined(self, instance):
- """Checks existence of an image on the local LXD image store
-
- :param instance: The nova instance
-
- Returns True if supplied image exists on the host, False otherwise
- """
- LOG.debug('image_defined called for instance', instance=instance)
- try:
- client = self.get_session(instance.host)
- return client.alias_defined(instance.image_ref)
- except lxd_exceptions.APIError as ex:
- if ex.status_code == 404:
- return False
- else:
- msg = _('Failed to communicate with LXD API %(instance)s:'
- ' %(reason)s') % {'instance': instance.image_ref,
- 'reason': ex}
- LOG.error(msg)
- raise exception.NovaException(msg)
- except Exception as e:
- with excutils.save_and_reraise_exception():
- LOG.error(_LE('Error from LXD during image_defined '
- '%(instance)s: %(reason)s'),
- {'instance': instance.image_ref, 'reason': e},
- instance=instance)
-
- def create_alias(self, alias, instance):
- """Creates an alias for a given image
-
- :param alias: The alias to be crerated
- :param instance: The nove instnace
- :return: true if alias is created, false otherwise
-
- """
- LOG.debug('create_alias called for instance', instance=instance)
- try:
- client = self.get_session(instance.host)
- return client.alias_create(alias)
- except lxd_exceptions.APIError as ex:
- msg = _('Failed to communicate with LXD API %(instance)s:'
- ' %(reason)s') % {'instance': instance.image_ref,
- 'reason': ex}
- LOG.error(msg)
- raise exception.NovaException(msg)
- except Exception as e:
- with excutils.save_and_reraise_exception():
- LOG.error(_LE('Error from LXD during create alias'
- '%(instance)s: %(reason)s'),
- {'instance': instance.image_ref, 'reason': e},
- instance=instance)
-
- def image_upload(self, data, headers, instance):
- """Upload an image to the local LXD image store
-
- :param data: image data
- :param headers: image headers
- :param intance: The nova instance
-
- """
- LOG.debug('upload_image called for instnace', instance=instance)
- try:
- client = self.get_session(instance.host)
- (state, data) = client.image_upload(data=data,
- headers=headers)
- # XXX - zulcss (Dec 8, 2015) - Work around for older
- # versions of LXD.
- if 'operation' in data:
- self.operation_wait(data.get('operation'), instance)
- except lxd_exceptions.APIError as ex:
- msg = _('Failed to communicate with LXD API %(instance)s:'
- '%(reason)s') % {'instance': instance.image_ref,
- 'reason': ex}
- LOG.error(msg)
- raise exception.NovaException(msg)
- except Exception as e:
- with excutils.save_and_reraise_exception():
- LOG.error(_LE('Error from LXD during image upload'
- '%(instance)s: %(reason)s'),
- {'instance': instance.image_ref, 'reason': e},
- instance=instance)
diff --git a/nova_lxd/nova/virt/lxd/session/session.py b/nova_lxd/nova/virt/lxd/session/session.py
index f9a31a9..c906984 100644
--- a/nova_lxd/nova/virt/lxd/session/session.py
+++ b/nova_lxd/nova/virt/lxd/session/session.py
@@ -19,13 +19,14 @@
from nova import i18n
from nova import rpc
from pylxd import api
+from pylxd import exceptions as lxd_exceptions
from oslo_config import cfg
from oslo_log import log as logging
+from oslo_utils import excutils
from nova_lxd.nova.virt.lxd.session import container
from nova_lxd.nova.virt.lxd.session import event
-from nova_lxd.nova.virt.lxd.session import image
from nova_lxd.nova.virt.lxd.session import migrate
from nova_lxd.nova.virt.lxd.session import profile
from nova_lxd.nova.virt.lxd.session import snapshot
@@ -40,7 +41,6 @@
class LXDAPISession(container.ContainerMixin,
event.EventMixin,
- image.ImageMixin,
migrate.MigrateMixin,
profile.ProfileMixin,
snapshot.SnapshotMixin):
@@ -78,3 +78,89 @@ def get_session(self, host=None):
raise exception.HypervisorUnavailable(host=CONF.host)
return conn
+
+ #
+ # Image related API methods.
+ #
+
+ def image_defined(self, instance):
+ """Checks existence of an image on the local LXD image store
+
+ :param instance: The nova instance
+
+ Returns True if supplied image exists on the host, False otherwise
+ """
+ LOG.debug('image_defined called for instance', instance=instance)
+ try:
+ client = self.get_session(instance.host)
+ return client.alias_defined(instance.image_ref)
+ except lxd_exceptions.APIError as ex:
+ if ex.status_code == 404:
+ return False
+ else:
+ msg = _('Failed to communicate with LXD API %(instance)s:'
+ ' %(reason)s') % {'instance': instance.image_ref,
+ 'reason': ex}
+ LOG.error(msg)
+ raise exception.NovaException(msg)
+ except Exception as e:
+ with excutils.save_and_reraise_exception():
+ LOG.error(_LE('Error from LXD during image_defined '
+ '%(instance)s: %(reason)s'),
+ {'instance': instance.image_ref, 'reason': e},
+ instance=instance)
+
+ def create_alias(self, alias, instance):
+ """Creates an alias for a given image
+
+ :param alias: The alias to be crerated
+ :param instance: The nove instnace
+ :return: true if alias is created, false otherwise
+
+ """
+ LOG.debug('create_alias called for instance', instance=instance)
+ try:
+ client = self.get_session(instance.host)
+ return client.alias_create(alias)
+ except lxd_exceptions.APIError as ex:
+ msg = _('Failed to communicate with LXD API %(instance)s:'
+ ' %(reason)s') % {'instance': instance.image_ref,
+ 'reason': ex}
+ LOG.error(msg)
+ raise exception.NovaException(msg)
+ except Exception as e:
+ with excutils.save_and_reraise_exception():
+ LOG.error(_LE('Error from LXD during create alias'
+ '%(instance)s: %(reason)s'),
+ {'instance': instance.image_ref, 'reason': e},
+ instance=instance)
+
+ def image_upload(self, data, headers, instance):
+ """Upload an image to the local LXD image store
+
+ :param data: image data
+ :param headers: image headers
+ :param intance: The nova instance
+
+ """
+ LOG.debug('upload_image called for instnace', instance=instance)
+ try:
+ client = self.get_session(instance.host)
+ (state, data) = client.image_upload(data=data,
+ headers=headers)
+ # XXX - zulcss (Dec 8, 2015) - Work around for older
+ # versions of LXD.
+ if 'operation' in data:
+ self.operation_wait(data.get('operation'), instance)
+ except lxd_exceptions.APIError as ex:
+ msg = _('Failed to communicate with LXD API %(instance)s:'
+ '%(reason)s') % {'instance': instance.image_ref,
+ 'reason': ex}
+ LOG.error(msg)
+ raise exception.NovaException(msg)
+ except Exception as e:
+ with excutils.save_and_reraise_exception():
+ LOG.error(_LE('Error from LXD during image upload'
+ '%(instance)s: %(reason)s'),
+ {'instance': instance.image_ref, 'reason': e},
+ instance=instance)
From 54928e3e796b28536de641ee8984721c8d259d2a Mon Sep 17 00:00:00 2001
From: Paul Hummer <paul.hummer at canonical.com>
Date: Tue, 2 Feb 2016 03:56:03 -0700
Subject: [PATCH 2/8] Consolidate container session stuff
---
nova_lxd/nova/virt/lxd/session/container.py | 484 ----------------------------
nova_lxd/nova/virt/lxd/session/session.py | 458 +++++++++++++++++++++++++-
2 files changed, 455 insertions(+), 487 deletions(-)
delete mode 100644 nova_lxd/nova/virt/lxd/session/container.py
diff --git a/nova_lxd/nova/virt/lxd/session/container.py b/nova_lxd/nova/virt/lxd/session/container.py
deleted file mode 100644
index 2817e51..0000000
--- a/nova_lxd/nova/virt/lxd/session/container.py
+++ /dev/null
@@ -1,484 +0,0 @@
-# Copyright 2015 Canonical Ltd
-# 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.
-
-from nova.compute import power_state
-from nova import exception
-from nova import i18n
-from pylxd import exceptions as lxd_exceptions
-
-from oslo_config import cfg
-from oslo_log import log as logging
-from oslo_utils import excutils
-
-from nova_lxd.nova.virt.lxd import constants
-
-_ = i18n._
-_LE = i18n._LE
-_LW = i18n._LW
-_LI = i18n._LI
-
-CONF = cfg.CONF
-LOG = logging.getLogger(__name__)
-
-
-class ContainerMixin(object):
- """Container functions for LXD."""
-
- def container_list(self):
- """List of containers running on a given host
-
- Returns a list of running containers
-
- """
- LOG.debug('container_list called')
- try:
- client = self.get_session()
- return client.container_list()
- except lxd_exceptions.APIError as ex:
- msg = _('Failed to communicate with LXD API: %(reason)s') \
- % {'reason': ex}
- LOG.error(msg)
- raise exception.NovaException(msg)
- except Exception as ex:
- with excutils.save_and_reraise_exception():
- LOG.error(_LE('Error from LXD during container_list: '
- '%(reason)s') % {'reason': ex})
-
- def container_update(self, config, instance):
- """Update the LXD configuration of a given container
-
- :param config: LXD configuration dictionary
- :param instance: nova instance object
- :return: an update LXD configuration dictionary
-
- """
- LOG.debug('container_update called fo instance', instance=instance)
- try:
- client = self.get_session(instance.host)
- if not self.container_defined(instance.name, instance):
- msg = _('Instance is not found..: %s') % instance.name
- raise exception.InstanceNotFound(msg)
-
- return client.container_update(instance.name,
- config)
- except lxd_exceptions.APIError as ex:
- msg = _('Failed to communicate with LXD API %(instance)s:'
- ' %(reason)s') % {'instance': instance.name,
- 'reason': ex}
- raise exception.NovaException(msg)
- except Exception as e:
- with excutils.save_and_reraise_exception():
- LOG.error(_LE('Error from LXD during container_update'
- '%(instance)s: %(reason)s'),
- {'instance': instance.name, 'reason': e},
- instance=instance)
-
- def container_running(self, instance):
- """Determine if the container is running
-
- :param instance: nova instance object
- :return: True if container is running otherwise false
-
- """
- LOG.debug('container_running for instance', instance=instance)
- try:
- client = self.get_session(instance.host)
- return client.container_running(instance.name)
- except lxd_exceptions.APIError as ex:
- msg = _('Failed to communicate with LXD API %(instance)s:'
- ' %(reason)s') % {'instance': instance.name,
- 'reason': ex}
- raise exception.NovaException(msg)
- except Exception as e:
- with excutils.save_and_reraise_exception():
- LOG.error(_LE('Error from LXD during container_running'
- '%(instance)s: %(reason)s'),
- {'instance': instance.name, 'reason': e},
- instance=instance)
-
- def container_state(self, instance):
- """Determine container_state and translate state
-
- :param instance: nova instance object
- :return: nova power_state
-
- """
- LOG.debug('container_state called for instance', instance=instance)
- try:
- client = self.get_session(instance.host)
- if not self.container_defined(instance.name, instance):
- return power_state.NOSTATE
-
- (state, data) = client.container_state(instance.name)
- state = constants.LXD_POWER_STATES[data['metadata']['status_code']]
- except lxd_exceptions.APIError as ex:
- msg = _('Failed to communicate with LXD API %(instance)s:'
- ' %(reason)s') % {'instance': instance.name,
- 'reason': ex}
- LOG.error(msg)
- state = power_state.NOSTATE
- except Exception as e:
- with excutils.save_and_reraise_exception():
- LOG.error(_LE('Error from LXD during container_state'
- '%(instance)s: %(reason)s'),
- {'instance': instance.name, 'reason': e},
- instance=instance)
- state = power_state.NOSTATE
- return state
-
- def container_config(self, instance):
- """Fetches the configuration of a given LXD container
-
- :param instance: nova instance object
- :return: dictionary represenation of a LXD container
-
- """
- LOG.debug('container_config called for instance', instance=instance)
- try:
- if not self.container_defined(instance.name, instance):
- msg = _('Instance is not found.. %s') % instance.name
- raise exception.InstanceNotFound(msg)
-
- client = self.get_session(instance.host)
- return client.get_container_config(instance.name)
- except lxd_exceptions.APIError as ex:
- msg = _('Failed to communicate with LXD API %(instance)s:'
- ' %(reason)s') % {'instance': instance.name,
- 'reason': ex}
- raise exception.NovaException(msg)
- except Exception as e:
- with excutils.save_and_reraise_exception():
- LOG.error(_LE('Error from LXD during container_config'
- '%(instance)s: %(reason)s'),
- {'instance': instance.name, 'reason': e},
- instance=instance)
-
- def container_info(self, instance):
- """Returns basic information about a LXD container
-
- :param instance: nova instance object
- :return: LXD container information
-
- """
- LOG.debug('container_info called for instance', instance=instance)
- try:
- if not self.container_defined(instance.name, instance):
- msg = _('Instance is not found.. %s') % instance.name
- raise exception.InstanceNotFound(msg)
-
- client = self.get_session(instance.host)
- return client.container_info(instance.name)
- except lxd_exceptions.APIError as ex:
- msg = _('Failed to communicate with LXD API %(instance)s:'
- ' %(reason)s') % {'instance': instance.name,
- 'reason': ex}
- raise exception.NovaException(msg)
- except Exception as e:
- with excutils.save_and_reraise_exception():
- LOG.error(_LE('Error from LXD during container_info'
- '%(instance)s: %(reason)s'),
- {'instance': instance.name, 'reason': e},
- instance=instance)
-
- def container_defined(self, instance_name, instance):
- """Determine if the container exists
-
- :param instance_name: container anme
- :param instance: nova instance opbject
- :return: True if exists otherwise False
-
- """
- LOG.debug('container_defined for instance', instance=instance)
- try:
- client = self.get_session(instance.host)
- return client.container_defined(instance_name)
- except lxd_exceptions.APIError as ex:
- if ex.status_code == 404:
- return False
- else:
- msg = _('Failed to get container status: %s') % ex
- raise exception.NovaException(msg)
- except Exception as e:
- with excutils.save_and_reraise_exception():
- LOG.error(_LE('Error from LXD during container_defined'
- '%(instance)s: %(reason)s'),
- {'instance': instance.name, 'reason': e},
- instance=instance)
-
- def container_start(self, instance_name, instance):
- """Start an LXD container
-
- :param instance_name: name of container
- :param instance: nova instance object
-
- """
- LOG.debug('container_start called for instance', instance=instance)
- try:
- LOG.info(_LI('Starting instance %(instance)s with '
- '%(image)s'), {'instance': instance.name,
- 'image': instance.image_ref})
- # Start the container
- client = self.get_session(instance.host)
-
- # (chuck): Something wicked could happen between
- # container
- if not self.container_defined(instance_name, instance):
- msg = _('Instance is not found.. %s ') % instance.name
- raise exception.InstanceNotFound(msg)
-
- (state, data) = client.container_start(instance_name,
- CONF.lxd.timeout)
- self.operation_wait(data.get('operation'), instance)
-
- LOG.info(_LI('Successfully started instance %(instance)s with'
- '%(image)s'), {'instance': instance.name,
- 'image': instance.image_ref})
- except lxd_exceptions.APIError as ex:
- msg = _('Failed to communicate with LXD API %(instance)s:'
- ' %(reason)s') % {'instance': instance.name,
- 'reason': ex}
- raise exception.NovaException(msg)
- except Exception as ex:
- with excutils.save_and_reraise_exception():
- LOG.error(
- _LE('Failed to start container %(instance)s: %(reason)s'),
- {'instance': instance_name, 'reason': ex},
- instance=instance)
-
- def container_stop(self, instance_name, host, instance):
- """Stops an LXD container
-
- :param instance_name: instance name
- :param host: host where the container is running
- :param instance: nova instance object
-
- """
- LOG.debug('container_stop called for instance', instance=instance)
- try:
- if not self.container_defined(instance_name, instance):
- msg = _('Instance is not found..: %s') % instance.name
- raise exception.InstanceNotFound(msg)
-
- LOG.info(_LI('Stopping instance %(instance)s with'
- '%(image)s'), {'instance': instance.name,
- 'image': instance.image_ref})
- # Stop the container
- client = self.get_session(host)
- (state, data) = client.container_stop(instance_name,
- CONF.lxd.timeout)
- self.operation_wait(data.get('operation'), instance)
-
- LOG.info(_LI('Successfully stopped instance %(instance)s with'
- '%(image)s'), {'instance': instance.name,
- 'image': instance.image_ref})
- except lxd_exceptions.APIError as ex:
- msg = _('Failed to communicate with LXD API %(instance)s:'
- ' %(reason)s') % {'instance': instance.name,
- 'reason': ex}
- raise exception.NovaException(msg)
- except Exception as ex:
- with excutils.save_and_reraise_exception():
- LOG.error(
- _LE('Failed to stop container %(instance)s: '
- '%(reason)s'), {'instance': instance_name,
- 'reason': ex})
-
- def container_reboot(self, instance):
- """Reboot a LXD container
-
- :param instance: nova instance object
-
- """
- LOG.debug('container_reboot called for instance', instance=instance)
- try:
- if not self.container_defined(instance.name, instance):
- msg = _('Instance is not found..: %s') % instance.name
- raise exception.InstanceNotFound(msg)
-
- LOG.info(_LI('Rebooting instance %(instance)s with'
- '%(image)s'), {'instance': instance.name,
- 'image': instance.image_ref})
-
- # Container reboot
- client = self.get_session(instance.host)
- (state, data) = client.container_reboot(instance.name,
- CONF.lxd.timeout)
- self.operation_wait(data.get('operation'), instance)
-
- LOG.info(_LI('Successfully rebooted instance %(instance)s with'
- '%(image)s'), {'instance': instance.name,
- 'image': instance.image_ref})
- except lxd_exceptions.APIError as ex:
- msg = _('Failed to communicate with LXD API %(instance)s:'
- ' %(reason)s') % {'instance': instance.name,
- 'reason': ex}
- raise exception.NovaException(msg)
- except Exception as ex:
- with excutils.save_and_reraise_exception():
- LOG.error(
- _LE('Failed to reboot container %(instance)s: '
- '%(reason)s'), {'instance': instance.name,
- 'reason': ex}, instance=instance)
-
- def container_destroy(self, instance_name, host, instance):
- """Destroy a LXD container
-
- :param instance_name: container name
- :param host: container host
- :param instance: nova instance object
-
- """
- LOG.debug('container_destroy for instance', instance=instance)
- try:
- if not self.container_defined(instance_name, instance):
- return
-
- LOG.info(_LI('Destroying instance %(instance)s with'
- '%(image)s'), {'instance': instance.name,
- 'image': instance.image_ref})
-
- # Destroying container
- self.container_stop(instance_name, host, instance)
-
- client = self.get_session(host)
- (state, data) = client.container_destroy(instance_name)
- self.operation_wait(data.get('operation'), instance)
-
- LOG.info(_LI('Successfully destroyed instance %(instance)s with'
- '%(image)s'), {'instance': instance.name,
- 'image': instance.image_ref})
- except lxd_exceptions.APIError as ex:
- msg = _('Failed to communicate with LXD API %(instance)s:'
- ' %(reason)s') % {'instance': instance.name,
- 'reason': ex}
- raise exception.NovaException(msg)
- except Exception as ex:
- with excutils.save_and_reraise_exception():
- LOG.error(_LE('Failed to destroy container %(instance)s: '
- '%(reason)s'), {'instance': instance_name,
- 'reason': ex})
-
- def container_pause(self, instance_name, instance):
- """Pause a LXD container
-
- :param instance_name: container name
- :param instance: nova instance object
-
- """
- LOG.debug('container_paused called for instance', instance=instance)
- try:
- if not self.container_defined(instance_name, instance):
- msg = _('Instance is not found. %s') % instance_name
- raise exception.InstanceNotFound(msg)
-
- LOG.info(_LI('Pausing instance %(instance)s with'
- '%(image)s'), {'instance': instance_name,
- 'image': instance.image_ref})
-
- client = self.get_session(instance.host)
- (state, data) = client.container_suspend(instance_name,
- CONF.lxd.timeout)
- self.operation_wait(data.get('operation'), instance)
-
- LOG.info(_LI('Successfully paused instance %(instance)s with'
- '%(image)s'), {'instance': instance_name,
- 'image': instance.image_ref})
- except lxd_exceptions.APIError as ex:
- msg = _('Failed to communicate with LXD API %(instance)s:'
- ' %(reason)s') % {'instance': instance_name,
- 'reason': ex}
- raise exception.NovaException(msg)
- except Exception as ex:
- with excutils.save_and_reraise_exception():
- LOG.error(
- _LE('Failed to pause container %(instance)s: '
- '%(reason)s'),
- {'instance': instance_name,
- 'reason': ex}, instance=instance)
-
- def container_unpause(self, instance_name, instance):
- """Unpause a LXD container
-
- :param instance_name: container name
- :param instance: nova instance object
-
- """
- LOG.debug('container_unpause called for instance', instance=instance)
- try:
- if not self.container_defined(instance_name, instance):
- msg = _('Instance is not found. %s') % instance_name
- raise exception.InstanceNotFound(msg)
-
- LOG.info(_LI('Unpausing instance %(instance)s with'
- '%(image)s'), {'instance': instance.name,
- 'image': instance.image_ref})
-
- client = self.get_session(instance.host)
- (state, data) = client.container_resume(instance_name,
- CONF.lxd.timeout)
- self.operation_wait(data.get('operation'), instance)
-
- LOG.info(_LI('Successfully unpaused instance %(instance)s with'
- '%(image)s'), {'instance': instance.name,
- 'image': instance.image_ref})
- except lxd_exceptions.APIError as ex:
- msg = _('Failed to communicate with LXD API %(instance)s:'
- ' %(reason)s') % {'instance': instance.name,
- 'reason': ex}
- raise exception.NovaException(msg)
- except Exception as ex:
- with excutils.save_and_reraise_exception():
- LOG.error(
- _LE('Failed to unpause container %(instance)s: '
- '%(reason)s'), {'instance': instance_name,
- 'reason': ex})
-
- def container_init(self, config, instance, host):
- """Create a LXD container
-
- :param config: LXD container config as a dict
- :param instance: nova instance object
- :param host: host to create the container on
-
- """
- LOG.debug('container_init called for instance', instance=instance)
- try:
- LOG.info(_LI('Creating container %(instance)s with'
- '%(image)s'), {'instance': instance.name,
- 'image': instance.image_ref})
-
- client = self.get_session(host)
- (state, data) = client.container_init(config)
- operation = data.get('operation')
- self.operation_wait(operation, instance)
- status, data = self.operation_info(operation, instance)
- data = data.get('metadata')
- if not data['status_code'] == 200:
- raise exception.NovaException(data['metadata'])
-
- LOG.info(_LI('Successfully created container %(instance)s with'
- '%(image)s'), {'instance': instance.name,
- 'image': instance.image_ref})
- except lxd_exceptions.APIError as ex:
- msg = _('Failed to communicate with LXD API %(instance)s:'
- ' %(reason)s') % {'instance': instance.name,
- 'reason': ex}
- raise exception.NovaException(msg)
- except Exception as ex:
- with excutils.save_and_reraise_exception():
- LOG.error(
- _LE('Failed to create container %(instance)s: %(reason)s'),
- {'instance': instance.name,
- 'reason': ex}, instance=instance)
diff --git a/nova_lxd/nova/virt/lxd/session/session.py b/nova_lxd/nova/virt/lxd/session/session.py
index c906984..68171bf 100644
--- a/nova_lxd/nova/virt/lxd/session/session.py
+++ b/nova_lxd/nova/virt/lxd/session/session.py
@@ -18,6 +18,7 @@
from nova import exception
from nova import i18n
from nova import rpc
+from nova.compute import power_state
from pylxd import api
from pylxd import exceptions as lxd_exceptions
@@ -25,7 +26,7 @@
from oslo_log import log as logging
from oslo_utils import excutils
-from nova_lxd.nova.virt.lxd.session import container
+from nova_lxd.nova.virt.lxd import constants
from nova_lxd.nova.virt.lxd.session import event
from nova_lxd.nova.virt.lxd.session import migrate
from nova_lxd.nova.virt.lxd.session import profile
@@ -33,14 +34,14 @@
_ = i18n._
_LE = i18n._LE
+_LI = i18n._LI
CONF = cfg.CONF
CONF.import_opt('host', 'nova.netconf')
LOG = logging.getLogger(__name__)
-class LXDAPISession(container.ContainerMixin,
- event.EventMixin,
+class LXDAPISession(event.EventMixin,
migrate.MigrateMixin,
profile.ProfileMixin,
snapshot.SnapshotMixin):
@@ -80,6 +81,457 @@ def get_session(self, host=None):
return conn
#
+ # Container related API methods
+ #
+
+ def container_list(self):
+ """List of containers running on a given host
+
+ Returns a list of running containers
+
+ """
+ LOG.debug('container_list called')
+ try:
+ client = self.get_session()
+ return client.container_list()
+ except lxd_exceptions.APIError as ex:
+ msg = _('Failed to communicate with LXD API: %(reason)s') \
+ % {'reason': ex}
+ LOG.error(msg)
+ raise exception.NovaException(msg)
+ except Exception as ex:
+ with excutils.save_and_reraise_exception():
+ LOG.error(_LE('Error from LXD during container_list: '
+ '%(reason)s') % {'reason': ex})
+
+ def container_update(self, config, instance):
+ """Update the LXD configuration of a given container
+
+ :param config: LXD configuration dictionary
+ :param instance: nova instance object
+ :return: an update LXD configuration dictionary
+
+ """
+ LOG.debug('container_update called fo instance', instance=instance)
+ try:
+ client = self.get_session(instance.host)
+ if not self.container_defined(instance.name, instance):
+ msg = _('Instance is not found..: %s') % instance.name
+ raise exception.InstanceNotFound(msg)
+
+ return client.container_update(instance.name,
+ config)
+ except lxd_exceptions.APIError as ex:
+ msg = _('Failed to communicate with LXD API %(instance)s:'
+ ' %(reason)s') % {'instance': instance.name,
+ 'reason': ex}
+ raise exception.NovaException(msg)
+ except Exception as e:
+ with excutils.save_and_reraise_exception():
+ LOG.error(_LE('Error from LXD during container_update'
+ '%(instance)s: %(reason)s'),
+ {'instance': instance.name, 'reason': e},
+ instance=instance)
+
+ def container_running(self, instance):
+ """Determine if the container is running
+
+ :param instance: nova instance object
+ :return: True if container is running otherwise false
+
+ """
+ LOG.debug('container_running for instance', instance=instance)
+ try:
+ client = self.get_session(instance.host)
+ return client.container_running(instance.name)
+ except lxd_exceptions.APIError as ex:
+ msg = _('Failed to communicate with LXD API %(instance)s:'
+ ' %(reason)s') % {'instance': instance.name,
+ 'reason': ex}
+ raise exception.NovaException(msg)
+ except Exception as e:
+ with excutils.save_and_reraise_exception():
+ LOG.error(_LE('Error from LXD during container_running'
+ '%(instance)s: %(reason)s'),
+ {'instance': instance.name, 'reason': e},
+ instance=instance)
+
+ def container_state(self, instance):
+ """Determine container_state and translate state
+
+ :param instance: nova instance object
+ :return: nova power_state
+
+ """
+ LOG.debug('container_state called for instance', instance=instance)
+ try:
+ client = self.get_session(instance.host)
+ if not self.container_defined(instance.name, instance):
+ return power_state.NOSTATE
+
+ (state, data) = client.container_state(instance.name)
+ state = constants.LXD_POWER_STATES[data['metadata']['status_code']]
+ except lxd_exceptions.APIError as ex:
+ msg = _('Failed to communicate with LXD API %(instance)s:'
+ ' %(reason)s') % {'instance': instance.name,
+ 'reason': ex}
+ LOG.error(msg)
+ state = power_state.NOSTATE
+ except Exception as e:
+ with excutils.save_and_reraise_exception():
+ LOG.error(_LE('Error from LXD during container_state'
+ '%(instance)s: %(reason)s'),
+ {'instance': instance.name, 'reason': e},
+ instance=instance)
+ state = power_state.NOSTATE
+ return state
+
+ def container_config(self, instance):
+ """Fetches the configuration of a given LXD container
+
+ :param instance: nova instance object
+ :return: dictionary represenation of a LXD container
+
+ """
+ LOG.debug('container_config called for instance', instance=instance)
+ try:
+ if not self.container_defined(instance.name, instance):
+ msg = _('Instance is not found.. %s') % instance.name
+ raise exception.InstanceNotFound(msg)
+
+ client = self.get_session(instance.host)
+ return client.get_container_config(instance.name)
+ except lxd_exceptions.APIError as ex:
+ msg = _('Failed to communicate with LXD API %(instance)s:'
+ ' %(reason)s') % {'instance': instance.name,
+ 'reason': ex}
+ raise exception.NovaException(msg)
+ except Exception as e:
+ with excutils.save_and_reraise_exception():
+ LOG.error(_LE('Error from LXD during container_config'
+ '%(instance)s: %(reason)s'),
+ {'instance': instance.name, 'reason': e},
+ instance=instance)
+
+ def container_info(self, instance):
+ """Returns basic information about a LXD container
+
+ :param instance: nova instance object
+ :return: LXD container information
+
+ """
+ LOG.debug('container_info called for instance', instance=instance)
+ try:
+ if not self.container_defined(instance.name, instance):
+ msg = _('Instance is not found.. %s') % instance.name
+ raise exception.InstanceNotFound(msg)
+
+ client = self.get_session(instance.host)
+ return client.container_info(instance.name)
+ except lxd_exceptions.APIError as ex:
+ msg = _('Failed to communicate with LXD API %(instance)s:'
+ ' %(reason)s') % {'instance': instance.name,
+ 'reason': ex}
+ raise exception.NovaException(msg)
+ except Exception as e:
+ with excutils.save_and_reraise_exception():
+ LOG.error(_LE('Error from LXD during container_info'
+ '%(instance)s: %(reason)s'),
+ {'instance': instance.name, 'reason': e},
+ instance=instance)
+
+ def container_defined(self, instance_name, instance):
+ """Determine if the container exists
+
+ :param instance_name: container anme
+ :param instance: nova instance opbject
+ :return: True if exists otherwise False
+
+ """
+ LOG.debug('container_defined for instance', instance=instance)
+ try:
+ client = self.get_session(instance.host)
+ return client.container_defined(instance_name)
+ except lxd_exceptions.APIError as ex:
+ if ex.status_code == 404:
+ return False
+ else:
+ msg = _('Failed to get container status: %s') % ex
+ raise exception.NovaException(msg)
+ except Exception as e:
+ with excutils.save_and_reraise_exception():
+ LOG.error(_LE('Error from LXD during container_defined'
+ '%(instance)s: %(reason)s'),
+ {'instance': instance.name, 'reason': e},
+ instance=instance)
+
+ def container_start(self, instance_name, instance):
+ """Start an LXD container
+
+ :param instance_name: name of container
+ :param instance: nova instance object
+
+ """
+ LOG.debug('container_start called for instance', instance=instance)
+ try:
+ LOG.info(_LI('Starting instance %(instance)s with '
+ '%(image)s'), {'instance': instance.name,
+ 'image': instance.image_ref})
+ # Start the container
+ client = self.get_session(instance.host)
+
+ # (chuck): Something wicked could happen between
+ # container
+ if not self.container_defined(instance_name, instance):
+ msg = _('Instance is not found.. %s ') % instance.name
+ raise exception.InstanceNotFound(msg)
+
+ (state, data) = client.container_start(instance_name,
+ CONF.lxd.timeout)
+ self.operation_wait(data.get('operation'), instance)
+
+ LOG.info(_LI('Successfully started instance %(instance)s with'
+ '%(image)s'), {'instance': instance.name,
+ 'image': instance.image_ref})
+ except lxd_exceptions.APIError as ex:
+ msg = _('Failed to communicate with LXD API %(instance)s:'
+ ' %(reason)s') % {'instance': instance.name,
+ 'reason': ex}
+ raise exception.NovaException(msg)
+ except Exception as ex:
+ with excutils.save_and_reraise_exception():
+ LOG.error(
+ _LE('Failed to start container %(instance)s: %(reason)s'),
+ {'instance': instance_name, 'reason': ex},
+ instance=instance)
+
+ def container_stop(self, instance_name, host, instance):
+ """Stops an LXD container
+
+ :param instance_name: instance name
+ :param host: host where the container is running
+ :param instance: nova instance object
+
+ """
+ LOG.debug('container_stop called for instance', instance=instance)
+ try:
+ if not self.container_defined(instance_name, instance):
+ msg = _('Instance is not found..: %s') % instance.name
+ raise exception.InstanceNotFound(msg)
+
+ LOG.info(_LI('Stopping instance %(instance)s with'
+ '%(image)s'), {'instance': instance.name,
+ 'image': instance.image_ref})
+ # Stop the container
+ client = self.get_session(host)
+ (state, data) = client.container_stop(instance_name,
+ CONF.lxd.timeout)
+ self.operation_wait(data.get('operation'), instance)
+
+ LOG.info(_LI('Successfully stopped instance %(instance)s with'
+ '%(image)s'), {'instance': instance.name,
+ 'image': instance.image_ref})
+ except lxd_exceptions.APIError as ex:
+ msg = _('Failed to communicate with LXD API %(instance)s:'
+ ' %(reason)s') % {'instance': instance.name,
+ 'reason': ex}
+ raise exception.NovaException(msg)
+ except Exception as ex:
+ with excutils.save_and_reraise_exception():
+ LOG.error(
+ _LE('Failed to stop container %(instance)s: '
+ '%(reason)s'), {'instance': instance_name,
+ 'reason': ex})
+
+ def container_reboot(self, instance):
+ """Reboot a LXD container
+
+ :param instance: nova instance object
+
+ """
+ LOG.debug('container_reboot called for instance', instance=instance)
+ try:
+ if not self.container_defined(instance.name, instance):
+ msg = _('Instance is not found..: %s') % instance.name
+ raise exception.InstanceNotFound(msg)
+
+ LOG.info(_LI('Rebooting instance %(instance)s with'
+ '%(image)s'), {'instance': instance.name,
+ 'image': instance.image_ref})
+
+ # Container reboot
+ client = self.get_session(instance.host)
+ (state, data) = client.container_reboot(instance.name,
+ CONF.lxd.timeout)
+ self.operation_wait(data.get('operation'), instance)
+
+ LOG.info(_LI('Successfully rebooted instance %(instance)s with'
+ '%(image)s'), {'instance': instance.name,
+ 'image': instance.image_ref})
+ except lxd_exceptions.APIError as ex:
+ msg = _('Failed to communicate with LXD API %(instance)s:'
+ ' %(reason)s') % {'instance': instance.name,
+ 'reason': ex}
+ raise exception.NovaException(msg)
+ except Exception as ex:
+ with excutils.save_and_reraise_exception():
+ LOG.error(
+ _LE('Failed to reboot container %(instance)s: '
+ '%(reason)s'), {'instance': instance.name,
+ 'reason': ex}, instance=instance)
+
+ def container_destroy(self, instance_name, host, instance):
+ """Destroy a LXD container
+
+ :param instance_name: container name
+ :param host: container host
+ :param instance: nova instance object
+
+ """
+ LOG.debug('container_destroy for instance', instance=instance)
+ try:
+ if not self.container_defined(instance_name, instance):
+ return
+
+ LOG.info(_LI('Destroying instance %(instance)s with'
+ '%(image)s'), {'instance': instance.name,
+ 'image': instance.image_ref})
+
+ # Destroying container
+ self.container_stop(instance_name, host, instance)
+
+ client = self.get_session(host)
+ (state, data) = client.container_destroy(instance_name)
+ self.operation_wait(data.get('operation'), instance)
+
+ LOG.info(_LI('Successfully destroyed instance %(instance)s with'
+ '%(image)s'), {'instance': instance.name,
+ 'image': instance.image_ref})
+ except lxd_exceptions.APIError as ex:
+ msg = _('Failed to communicate with LXD API %(instance)s:'
+ ' %(reason)s') % {'instance': instance.name,
+ 'reason': ex}
+ raise exception.NovaException(msg)
+ except Exception as ex:
+ with excutils.save_and_reraise_exception():
+ LOG.error(_LE('Failed to destroy container %(instance)s: '
+ '%(reason)s'), {'instance': instance_name,
+ 'reason': ex})
+
+ def container_pause(self, instance_name, instance):
+ """Pause a LXD container
+
+ :param instance_name: container name
+ :param instance: nova instance object
+
+ """
+ LOG.debug('container_paused called for instance', instance=instance)
+ try:
+ if not self.container_defined(instance_name, instance):
+ msg = _('Instance is not found. %s') % instance_name
+ raise exception.InstanceNotFound(msg)
+
+ LOG.info(_LI('Pausing instance %(instance)s with'
+ '%(image)s'), {'instance': instance_name,
+ 'image': instance.image_ref})
+
+ client = self.get_session(instance.host)
+ (state, data) = client.container_suspend(instance_name,
+ CONF.lxd.timeout)
+ self.operation_wait(data.get('operation'), instance)
+
+ LOG.info(_LI('Successfully paused instance %(instance)s with'
+ '%(image)s'), {'instance': instance_name,
+ 'image': instance.image_ref})
+ except lxd_exceptions.APIError as ex:
+ msg = _('Failed to communicate with LXD API %(instance)s:'
+ ' %(reason)s') % {'instance': instance_name,
+ 'reason': ex}
+ raise exception.NovaException(msg)
+ except Exception as ex:
+ with excutils.save_and_reraise_exception():
+ LOG.error(
+ _LE('Failed to pause container %(instance)s: '
+ '%(reason)s'),
+ {'instance': instance_name,
+ 'reason': ex}, instance=instance)
+
+ def container_unpause(self, instance_name, instance):
+ """Unpause a LXD container
+
+ :param instance_name: container name
+ :param instance: nova instance object
+
+ """
+ LOG.debug('container_unpause called for instance', instance=instance)
+ try:
+ if not self.container_defined(instance_name, instance):
+ msg = _('Instance is not found. %s') % instance_name
+ raise exception.InstanceNotFound(msg)
+
+ LOG.info(_LI('Unpausing instance %(instance)s with'
+ '%(image)s'), {'instance': instance.name,
+ 'image': instance.image_ref})
+
+ client = self.get_session(instance.host)
+ (state, data) = client.container_resume(instance_name,
+ CONF.lxd.timeout)
+ self.operation_wait(data.get('operation'), instance)
+
+ LOG.info(_LI('Successfully unpaused instance %(instance)s with'
+ '%(image)s'), {'instance': instance.name,
+ 'image': instance.image_ref})
+ except lxd_exceptions.APIError as ex:
+ msg = _('Failed to communicate with LXD API %(instance)s:'
+ ' %(reason)s') % {'instance': instance.name,
+ 'reason': ex}
+ raise exception.NovaException(msg)
+ except Exception as ex:
+ with excutils.save_and_reraise_exception():
+ LOG.error(
+ _LE('Failed to unpause container %(instance)s: '
+ '%(reason)s'), {'instance': instance_name,
+ 'reason': ex})
+
+ def container_init(self, config, instance, host):
+ """Create a LXD container
+
+ :param config: LXD container config as a dict
+ :param instance: nova instance object
+ :param host: host to create the container on
+
+ """
+ LOG.debug('container_init called for instance', instance=instance)
+ try:
+ LOG.info(_LI('Creating container %(instance)s with'
+ '%(image)s'), {'instance': instance.name,
+ 'image': instance.image_ref})
+
+ client = self.get_session(host)
+ (state, data) = client.container_init(config)
+ operation = data.get('operation')
+ self.operation_wait(operation, instance)
+ status, data = self.operation_info(operation, instance)
+ data = data.get('metadata')
+ if not data['status_code'] == 200:
+ raise exception.NovaException(data['metadata'])
+
+ LOG.info(_LI('Successfully created container %(instance)s with'
+ '%(image)s'), {'instance': instance.name,
+ 'image': instance.image_ref})
+ except lxd_exceptions.APIError as ex:
+ msg = _('Failed to communicate with LXD API %(instance)s:'
+ ' %(reason)s') % {'instance': instance.name,
+ 'reason': ex}
+ raise exception.NovaException(msg)
+ except Exception as ex:
+ with excutils.save_and_reraise_exception():
+ LOG.error(
+ _LE('Failed to create container %(instance)s: %(reason)s'),
+ {'instance': instance.name,
+ 'reason': ex}, instance=instance)
+
+ #
# Image related API methods.
#
From 3136511420aec676f8d889077cb7e7ceb2c809c6 Mon Sep 17 00:00:00 2001
From: Paul Hummer <paul.hummer at canonical.com>
Date: Tue, 2 Feb 2016 03:59:51 -0700
Subject: [PATCH 3/8] Unify the operations handling.
---
nova_lxd/nova/virt/lxd/session/event.py | 75 -------------------------------
nova_lxd/nova/virt/lxd/session/session.py | 50 +++++++++++++++++++--
2 files changed, 47 insertions(+), 78 deletions(-)
delete mode 100644 nova_lxd/nova/virt/lxd/session/event.py
diff --git a/nova_lxd/nova/virt/lxd/session/event.py b/nova_lxd/nova/virt/lxd/session/event.py
deleted file mode 100644
index b4ec050..0000000
--- a/nova_lxd/nova/virt/lxd/session/event.py
+++ /dev/null
@@ -1,75 +0,0 @@
-# Copyright 2015 Canonical Ltd
-# 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.
-
-from nova import exception
-from nova import i18n
-from pylxd import exceptions as lxd_exceptions
-
-from oslo_config import cfg
-from oslo_log import log as logging
-from oslo_utils import excutils
-
-_ = i18n._
-_LE = i18n._LE
-
-CONF = cfg.CONF
-LOG = logging.getLogger(__name__)
-
-
-class EventMixin(object):
- """Operation functions for LXD."""
-
- def operation_wait(self, operation_id, instance):
- """Waits for an operation to return 200 (Success)
-
- :param operation_id: The operation to wait for.
- """
- LOG.debug('wait_for_contianer for instance', instance=instance)
- try:
- client = self.get_session(instance.host)
- if not client.wait_container_operation(operation_id, 200, -1):
- msg = _('Container creation timed out')
- raise exception.NovaException(msg)
- except lxd_exceptions.APIError as ex:
- msg = _('Failed to communicate with LXD API %(instance)s:'
- '%(reason)s') % {'instance': instance.image_ref,
- 'reason': ex}
- LOG.error(msg)
- raise exception.NovaException(msg)
- except Exception as e:
- with excutils.save_and_reraise_exception():
- LOG.error(_LE('Error from LXD during operation wait'
- '%(instance)s: %(reason)s'),
- {'instance': instance.image_ref, 'reason': e},
- instance=instance)
-
- def operation_info(self, operation_id, instance):
- LOG.debug('operation_info called for instance', instance=instance)
- try:
- client = self.get_session(instance.host)
- return client.operation_info(operation_id)
- except lxd_exceptions.APIError as ex:
- msg = _('Failed to communicate with LXD API %(instance)s:'
- '%(reason)s') % {'instance': instance.image_ref,
- 'reason': ex}
- LOG.error(msg)
- raise exception.NovaException(msg)
- except Exception as e:
- with excutils.save_and_reraise_exception():
- LOG.error(_LE('Error from LXD during operation_info '
- '%(instance)s: %(reason)s'),
- {'instance': instance.image_ref, 'reason': e},
- instance=instance)
diff --git a/nova_lxd/nova/virt/lxd/session/session.py b/nova_lxd/nova/virt/lxd/session/session.py
index 68171bf..bcc94d4 100644
--- a/nova_lxd/nova/virt/lxd/session/session.py
+++ b/nova_lxd/nova/virt/lxd/session/session.py
@@ -27,7 +27,6 @@
from oslo_utils import excutils
from nova_lxd.nova.virt.lxd import constants
-from nova_lxd.nova.virt.lxd.session import event
from nova_lxd.nova.virt.lxd.session import migrate
from nova_lxd.nova.virt.lxd.session import profile
from nova_lxd.nova.virt.lxd.session import snapshot
@@ -41,8 +40,7 @@
LOG = logging.getLogger(__name__)
-class LXDAPISession(event.EventMixin,
- migrate.MigrateMixin,
+class LXDAPISession(migrate.MigrateMixin,
profile.ProfileMixin,
snapshot.SnapshotMixin):
"""The session to invoke the LXD API session."""
@@ -616,3 +614,49 @@ def image_upload(self, data, headers, instance):
'%(instance)s: %(reason)s'),
{'instance': instance.image_ref, 'reason': e},
instance=instance)
+
+ #
+ # Operation methods
+ #
+
+ def operation_wait(self, operation_id, instance):
+ """Waits for an operation to return 200 (Success)
+
+ :param operation_id: The operation to wait for.
+ """
+ LOG.debug('wait_for_contianer for instance', instance=instance)
+ try:
+ client = self.get_session(instance.host)
+ if not client.wait_container_operation(operation_id, 200, -1):
+ msg = _('Container creation timed out')
+ raise exception.NovaException(msg)
+ except lxd_exceptions.APIError as ex:
+ msg = _('Failed to communicate with LXD API %(instance)s:'
+ '%(reason)s') % {'instance': instance.image_ref,
+ 'reason': ex}
+ LOG.error(msg)
+ raise exception.NovaException(msg)
+ except Exception as e:
+ with excutils.save_and_reraise_exception():
+ LOG.error(_LE('Error from LXD during operation wait'
+ '%(instance)s: %(reason)s'),
+ {'instance': instance.image_ref, 'reason': e},
+ instance=instance)
+
+ def operation_info(self, operation_id, instance):
+ LOG.debug('operation_info called for instance', instance=instance)
+ try:
+ client = self.get_session(instance.host)
+ return client.operation_info(operation_id)
+ except lxd_exceptions.APIError as ex:
+ msg = _('Failed to communicate with LXD API %(instance)s:'
+ '%(reason)s') % {'instance': instance.image_ref,
+ 'reason': ex}
+ LOG.error(msg)
+ raise exception.NovaException(msg)
+ except Exception as e:
+ with excutils.save_and_reraise_exception():
+ LOG.error(_LE('Error from LXD during operation_info '
+ '%(instance)s: %(reason)s'),
+ {'instance': instance.image_ref, 'reason': e},
+ instance=instance)
From d84bb2e51c32063642137539b2fdf714fe59a007 Mon Sep 17 00:00:00 2001
From: Paul Hummer <paul.hummer at canonical.com>
Date: Tue, 2 Feb 2016 04:03:08 -0700
Subject: [PATCH 4/8] Consolidate profile session code
---
nova_lxd/nova/virt/lxd/session/profile.py | 124 ------------------------------
nova_lxd/nova/virt/lxd/session/session.py | 95 ++++++++++++++++++++++-
2 files changed, 93 insertions(+), 126 deletions(-)
delete mode 100644 nova_lxd/nova/virt/lxd/session/profile.py
diff --git a/nova_lxd/nova/virt/lxd/session/profile.py b/nova_lxd/nova/virt/lxd/session/profile.py
deleted file mode 100644
index 9097f1b..0000000
--- a/nova_lxd/nova/virt/lxd/session/profile.py
+++ /dev/null
@@ -1,124 +0,0 @@
-# Copyright 2015 Canonical Ltd
-# 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.
-
-from nova import exception
-from nova import i18n
-from pylxd import exceptions as lxd_exceptions
-
-from oslo_config import cfg
-from oslo_log import log as logging
-from oslo_utils import excutils
-
-_ = i18n._
-_LE = i18n._LE
-_LI = i18n._LI
-
-CONF = cfg.CONF
-LOG = logging.getLogger(__name__)
-
-
-class ProfileMixin(object):
- """Mixin for profiles methods."""
-
- def profile_defined(self, instance):
- """Validate if the profile is available on the LXD
- host
-
- :param instance: nova instance object
- """
- LOG.debug('profile_defined called for instance',
- instance=instance)
- try:
- client = self.get_session(instance.host)
- client.profile_defined(instance.name)
- except lxd_exceptions.APIError as ex:
- if ex.status_code == 404:
- return False
- else:
- msg = _('Failed to communicate with LXD API %(instance)s:'
- ' %(reason)s') % {'instance': instance.name,
- 'reason': ex}
- raise exception.NovaException(msg)
- except Exception as ex:
- with excutils.save_and_reraise_exception():
- LOG.error(
- _LE('Failed to determine profile %(instance)s:'
- ' %(reason)s'),
- {'instance': instance.name, 'reason': ex})
-
- def profile_create(self, config, instance):
- """Create an LXD container profile
-
- :param config: profile dictionary
- :param instnace: nova instance object
- """
- LOG.debug('profile_create called for instance',
- instance=instance)
- try:
- client = self.get_session(instance.host)
- client.profile_create(config)
- except lxd_exceptions.APIError as ex:
- msg = _('Failed to communicate with LXD API %(instance)s:'
- ' %(reason)s') % {'instance': instance.name,
- 'reason': ex}
- raise exception.NovaException(msg)
- except Exception as ex:
- with excutils.save_and_reraise_exception():
- LOG.error(
- _LE('Failed to create profile %(instance)s: %(reason)s'),
- {'instance': instance.name, 'reason': ex})
-
- def profile_update(self, config, instance):
- """Update an LXD container profile
-
- :param config: LXD profile dictironary
- :param instance: nova instance object
- """
- LOG.debug('profile_udpate called for instance', instance=instance)
- try:
- client = self.get_session(instance.host)
- client.profile_update(instance.name, config)
- except lxd_exceptions.APIError as ex:
- msg = _('Failed to communicate with LXD API %(instance)s:'
- ' %(reason)s') % {'instance': instance.name,
- 'reason': ex}
- raise exception.NovaException(msg)
- except Exception as ex:
- with excutils.save_and_reraise_exception():
- LOG.error(
- _LE('Failed to update profile %(instance)s: '
- '%(reason)s'),
- {'instance': instance.name, 'reason': ex})
-
- def profile_delete(self, instance):
- """Delete a LXD container profile.
-
- :param instance: nova instance object
- """
- LOG.debug('profile_delete called for instance', instance=instance)
- try:
- client = self.get_session(instance.host)
- client.profile_delete(instance.name)
- except lxd_exceptions.APIError as ex:
- msg = _('Failed to communicate with LXD API %(instance)s:'
- ' %(reason)s') % {'instance': instance.name,
- 'reason': ex}
- raise exception.NovaException(msg)
- except Exception as ex:
- with excutils.save_and_reraise_exception():
- LOG.error(
- _LE('Failed to delete profile %(instance)s: %(reason)s'),
- {'instance': instance.name, 'reason': ex})
diff --git a/nova_lxd/nova/virt/lxd/session/session.py b/nova_lxd/nova/virt/lxd/session/session.py
index bcc94d4..807a421 100644
--- a/nova_lxd/nova/virt/lxd/session/session.py
+++ b/nova_lxd/nova/virt/lxd/session/session.py
@@ -28,7 +28,6 @@
from nova_lxd.nova.virt.lxd import constants
from nova_lxd.nova.virt.lxd.session import migrate
-from nova_lxd.nova.virt.lxd.session import profile
from nova_lxd.nova.virt.lxd.session import snapshot
_ = i18n._
@@ -41,7 +40,6 @@
class LXDAPISession(migrate.MigrateMixin,
- profile.ProfileMixin,
snapshot.SnapshotMixin):
"""The session to invoke the LXD API session."""
@@ -660,3 +658,96 @@ def operation_info(self, operation_id, instance):
'%(instance)s: %(reason)s'),
{'instance': instance.image_ref, 'reason': e},
instance=instance)
+
+ #
+ # Profile methods
+ #
+ def profile_defined(self, instance):
+ """Validate if the profile is available on the LXD
+ host
+
+ :param instance: nova instance object
+ """
+ LOG.debug('profile_defined called for instance',
+ instance=instance)
+ try:
+ client = self.get_session(instance.host)
+ client.profile_defined(instance.name)
+ except lxd_exceptions.APIError as ex:
+ if ex.status_code == 404:
+ return False
+ else:
+ msg = _('Failed to communicate with LXD API %(instance)s:'
+ ' %(reason)s') % {'instance': instance.name,
+ 'reason': ex}
+ raise exception.NovaException(msg)
+ except Exception as ex:
+ with excutils.save_and_reraise_exception():
+ LOG.error(
+ _LE('Failed to determine profile %(instance)s:'
+ ' %(reason)s'),
+ {'instance': instance.name, 'reason': ex})
+
+ def profile_create(self, config, instance):
+ """Create an LXD container profile
+
+ :param config: profile dictionary
+ :param instnace: nova instance object
+ """
+ LOG.debug('profile_create called for instance',
+ instance=instance)
+ try:
+ client = self.get_session(instance.host)
+ client.profile_create(config)
+ except lxd_exceptions.APIError as ex:
+ msg = _('Failed to communicate with LXD API %(instance)s:'
+ ' %(reason)s') % {'instance': instance.name,
+ 'reason': ex}
+ raise exception.NovaException(msg)
+ except Exception as ex:
+ with excutils.save_and_reraise_exception():
+ LOG.error(
+ _LE('Failed to create profile %(instance)s: %(reason)s'),
+ {'instance': instance.name, 'reason': ex})
+
+ def profile_update(self, config, instance):
+ """Update an LXD container profile
+
+ :param config: LXD profile dictironary
+ :param instance: nova instance object
+ """
+ LOG.debug('profile_udpate called for instance', instance=instance)
+ try:
+ client = self.get_session(instance.host)
+ client.profile_update(instance.name, config)
+ except lxd_exceptions.APIError as ex:
+ msg = _('Failed to communicate with LXD API %(instance)s:'
+ ' %(reason)s') % {'instance': instance.name,
+ 'reason': ex}
+ raise exception.NovaException(msg)
+ except Exception as ex:
+ with excutils.save_and_reraise_exception():
+ LOG.error(
+ _LE('Failed to update profile %(instance)s: '
+ '%(reason)s'),
+ {'instance': instance.name, 'reason': ex})
+
+ def profile_delete(self, instance):
+ """Delete a LXD container profile.
+
+ :param instance: nova instance object
+ """
+ LOG.debug('profile_delete called for instance', instance=instance)
+ try:
+ client = self.get_session(instance.host)
+ client.profile_delete(instance.name)
+ except lxd_exceptions.APIError as ex:
+ msg = _('Failed to communicate with LXD API %(instance)s:'
+ ' %(reason)s') % {'instance': instance.name,
+ 'reason': ex}
+ raise exception.NovaException(msg)
+ except Exception as ex:
+ with excutils.save_and_reraise_exception():
+ LOG.error(
+ _LE('Failed to delete profile %(instance)s: %(reason)s'),
+ {'instance': instance.name, 'reason': ex})
From 5b342f69a5fa1e539d7278576acbb72b22fe5194 Mon Sep 17 00:00:00 2001
From: Paul Hummer <paul.hummer at canonical.com>
Date: Tue, 2 Feb 2016 04:06:01 -0700
Subject: [PATCH 5/8] Merge migrate mixin code into session
---
nova_lxd/nova/virt/lxd/session/migrate.py | 69 -------------------------------
nova_lxd/nova/virt/lxd/session/session.py | 42 +++++++++++++++++--
2 files changed, 39 insertions(+), 72 deletions(-)
delete mode 100644 nova_lxd/nova/virt/lxd/session/migrate.py
diff --git a/nova_lxd/nova/virt/lxd/session/migrate.py b/nova_lxd/nova/virt/lxd/session/migrate.py
deleted file mode 100644
index 2e7346c..0000000
--- a/nova_lxd/nova/virt/lxd/session/migrate.py
+++ /dev/null
@@ -1,69 +0,0 @@
-# Copyright 2015 Canonical Ltd
-# 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.
-
-from nova import exception
-from nova import i18n
-from pylxd import exceptions as lxd_exceptions
-
-from oslo_config import cfg
-from oslo_log import log as logging
-from oslo_utils import excutils
-
-_ = i18n._
-_LE = i18n._LE
-_LI = i18n._LI
-
-CONF = cfg.CONF
-LOG = logging.getLogger(__name__)
-
-
-class MigrateMixin(object):
- """Migrate LXD oerations."""
-
- def container_migrate(self, instance_name, host, instance):
- """Initialize a container migration for LXD
-
- :param instance_name: container name
- :param host: host to move container from
- :param instance: nova instance object
- :return: dictionary of the container keys
-
- """
- LOG.debug('container_migrate called for instance', instance=instance)
- try:
- LOG.info(_LI('Migrating instance %(instance)s with'
- '%(image)s'), {'instance': instance_name,
- 'image': instance.image_ref})
-
- client = self.get_session(host)
- (state, data) = client.container_migrate(instance_name)
-
- LOG.info(_LI('Successfully initialized migration for instance '
- '%(instance)s with %(image)s'),
- {'instance': instance.name,
- 'image': instance.image_ref})
- return (state, data)
- except lxd_exceptions.APIError as ex:
- msg = _('Failed to communicate with LXD API %(instance)s:'
- ' %(reason)s') % {'instance': instance.name,
- 'reason': ex}
- raise exception.NovaException(msg)
- except Exception as ex:
- with excutils.save_and_reraise_exception():
- LOG.error(
- _LE('Failed to migrate container %(instance)s: %('
- 'reason)s'), {'instance': instance.name,
- 'reason': ex}, instance=instance)
diff --git a/nova_lxd/nova/virt/lxd/session/session.py b/nova_lxd/nova/virt/lxd/session/session.py
index 807a421..2ca4314 100644
--- a/nova_lxd/nova/virt/lxd/session/session.py
+++ b/nova_lxd/nova/virt/lxd/session/session.py
@@ -27,7 +27,6 @@
from oslo_utils import excutils
from nova_lxd.nova.virt.lxd import constants
-from nova_lxd.nova.virt.lxd.session import migrate
from nova_lxd.nova.virt.lxd.session import snapshot
_ = i18n._
@@ -39,8 +38,7 @@
LOG = logging.getLogger(__name__)
-class LXDAPISession(migrate.MigrateMixin,
- snapshot.SnapshotMixin):
+class LXDAPISession(snapshot.SnapshotMixin):
"""The session to invoke the LXD API session."""
def __init__(self):
@@ -751,3 +749,41 @@ def profile_delete(self, instance):
LOG.error(
_LE('Failed to delete profile %(instance)s: %(reason)s'),
{'instance': instance.name, 'reason': ex})
+
+ #
+ # Migrate methods
+ #
+ def container_migrate(self, instance_name, host, instance):
+ """Initialize a container migration for LXD
+
+ :param instance_name: container name
+ :param host: host to move container from
+ :param instance: nova instance object
+ :return: dictionary of the container keys
+
+ """
+ LOG.debug('container_migrate called for instance', instance=instance)
+ try:
+ LOG.info(_LI('Migrating instance %(instance)s with'
+ '%(image)s'), {'instance': instance_name,
+ 'image': instance.image_ref})
+
+ client = self.get_session(host)
+ (state, data) = client.container_migrate(instance_name)
+
+ LOG.info(_LI('Successfully initialized migration for instance '
+ '%(instance)s with %(image)s'),
+ {'instance': instance.name,
+ 'image': instance.image_ref})
+ return (state, data)
+ except lxd_exceptions.APIError as ex:
+ msg = _('Failed to communicate with LXD API %(instance)s:'
+ ' %(reason)s') % {'instance': instance.name,
+ 'reason': ex}
+ raise exception.NovaException(msg)
+ except Exception as ex:
+ with excutils.save_and_reraise_exception():
+ LOG.error(
+ _LE('Failed to migrate container %(instance)s: %('
+ 'reason)s'), {'instance': instance.name,
+ 'reason': ex}, instance=instance)
From 8fb535756224b3a7cd0d9caa90c50b8cf9a0a4ec Mon Sep 17 00:00:00 2001
From: Paul Hummer <paul.hummer at canonical.com>
Date: Tue, 2 Feb 2016 04:34:26 -0700
Subject: [PATCH 6/8] Add session mixin consolidation
---
nova_lxd/nova/virt/lxd/session/session.py | 161 ++++++++++++++++++++++++-
nova_lxd/nova/virt/lxd/session/snapshot.py | 187 -----------------------------
2 files changed, 159 insertions(+), 189 deletions(-)
delete mode 100644 nova_lxd/nova/virt/lxd/session/snapshot.py
diff --git a/nova_lxd/nova/virt/lxd/session/session.py b/nova_lxd/nova/virt/lxd/session/session.py
index 2ca4314..b5d44d8 100644
--- a/nova_lxd/nova/virt/lxd/session/session.py
+++ b/nova_lxd/nova/virt/lxd/session/session.py
@@ -24,10 +24,10 @@
from oslo_config import cfg
from oslo_log import log as logging
+from oslo_service import loopingcall
from oslo_utils import excutils
from nova_lxd.nova.virt.lxd import constants
-from nova_lxd.nova.virt.lxd.session import snapshot
_ = i18n._
_LE = i18n._LE
@@ -38,7 +38,7 @@
LOG = logging.getLogger(__name__)
-class LXDAPISession(snapshot.SnapshotMixin):
+class LXDAPISession(object):
"""The session to invoke the LXD API session."""
def __init__(self):
@@ -787,3 +787,160 @@ def container_migrate(self, instance_name, host, instance):
_LE('Failed to migrate container %(instance)s: %('
'reason)s'), {'instance': instance.name,
'reason': ex}, instance=instance)
+
+ #
+ # Snapshot methods
+ #
+
+ def container_move(self, old_name, config, instance):
+ """Move a container from one host to another
+
+ :param old_name: Old container name
+ :param config: Old container config
+ :param instance: nova instance object
+ :return:
+
+ """
+ LOG.debug('container_move called for instance', instnace=instance)
+ try:
+ LOG.info(_LI('Moving container %(instance)s with'
+ '%(image)s'), {'instance': instance.name,
+ 'image': instance.image_ref})
+
+ # Container move
+ client = self.get_session(instance.host)
+ (state, data) = client.container_local_move(old_name, config)
+ self.operation_wait(data.get('operation'), instance)
+
+ LOG.info(_LI('Successfully moved container %(instance)s with'
+ '%(image)s'), {'instance': instance.name,
+ 'image': instance.image_ref})
+ except lxd_exceptions.APIError as ex:
+ msg = _('Failed to communicate with LXD API %(instance)s:'
+ ' %(reason)s') % {'instance': instance.name,
+ 'reason': ex}
+ raise exception.NovaException(msg)
+ except Exception as ex:
+ with excutils.save_and_reraise_exception():
+ LOG.error(
+ _LE('Failed to move container %(instance)s: %('
+ 'reason)s'),
+ {'instance': instance.name,
+ 'reason': ex}, instance=instance)
+
+ def container_snapshot(self, snapshot, instance):
+ """Snapshot a LXD container
+
+ :param snapshot: snapshot config dictionary
+ :param instance: nova instance object
+
+ """
+ LOG.debug('container_snapshot called for instance', instance=instance)
+ try:
+ LOG.info(_LI('Snapshotting container %(instance)s with '
+ '%(image)s'), {'instance': instance.name,
+ 'image': instance.image_ref})
+
+ # Container snapshot
+ client = self.get_session(instance.host)
+ (state, data) = client.container_snapshot_create(
+ instance.name, snapshot)
+ self.operation_wait(data.get('operation'), instance)
+
+ LOG.info(_LI('Successfully snapshotted container %(instance)s with'
+ '%(image)s'), {'instance': instance.name,
+ 'image': instance.image_ref})
+ except lxd_exceptions.APIError as ex:
+ msg = _('Failed to communicate with LXD API %(instance)s:'
+ ' %(reason)s') % {'instance': instance.name,
+ 'reason': ex}
+ raise exception.NovaException(msg)
+ except Exception as ex:
+ with excutils.save_and_reraise_exception():
+ LOG.error(
+ _LE('Failed to snapshot container %(instance)s: '
+ '%(reason)s'),
+ {'instance': instance.name,
+ 'reason': ex}, instance=instance)
+
+ def container_publish(self, image, instance):
+ """Publish a container to the local LXD image store
+
+ :param image: LXD fingerprint
+ :param instance: nova instance object
+ :return: True if published, False otherwise
+
+ """
+ LOG.debug('container_publish called for instance', instance=instance)
+ try:
+ client = self.get_session(instance.host)
+ return client.container_publish(image)
+ except lxd_exceptions.APIError as ex:
+ msg = _('Failed to communicate with LXD API %(instance)s:'
+ ' %(reason)s') % {'instance': instance.name,
+ 'reason': ex}
+ raise exception.NovaException(msg)
+ except Exception as ex:
+ with excutils.save_and_reraise_exception():
+ LOG.error(
+ _LE('Failed to publish container %(instance)s: '
+ '%(reason)s'),
+ {'instance': instance.name,
+ 'reason': ex}, instance=instance)
+
+ def container_export(self, image, instance):
+ """
+ Export an image from the local LXD image store into
+ an file.
+
+ :param image: image dictionary
+ :param instance: nova instance object
+ """
+ LOG.debug('container_export called for instance', instance=instance)
+ try:
+ client = self.get_session(instance.host)
+ return client.image_export(image)
+ except lxd_exceptions.APIError as ex:
+ msg = _('Failed to export image: %s') % ex
+ raise exception.NovaException(msg)
+ except Exception as ex:
+ with excutils.save_and_reraise_exception():
+ LOG.error(
+ _LE('Failed to export container %(instance)s: '
+ '%(reason)s'),
+ {'instance': instance.name,
+ 'reason': ex}, instance=instance)
+
+ def wait_for_snapshot(self, event_id, instance):
+ """Poll snapshot operation for the snapshot to be ready.
+
+ :param event_id: operation id
+ :param instnace: nova instance object
+ """
+ LOG.debug('wait_for_snapshot called for instance', instance=instance)
+
+ timer = loopingcall.FixedIntervalLoopingCall(self._wait_for_snapshot,
+ event_id, instance)
+ try:
+ timer.start(interval=2).wait()
+ except Exception as ex:
+ with excutils.save_and_reraise_exception():
+ LOG.error(_LE('Failed to create snapshot for %(instance)s: '
+ '%(ex)s'), {'instance': instance.name, 'ex': ex},
+ instance=instance)
+
+ def _wait_for_snapshot(self, event_id, instance):
+ """Check the status code of the opeation id.
+
+ :param event_id: operation id
+ :param instance: nova instance object
+ """
+ client = self.get_session(instance.host)
+ (state, data) = client.operation_info(event_id)
+ status_code = data['metadata']['status_code']
+
+ if status_code == 200:
+ raise loopingcall.LoopingCallDone()
+ elif status_code == 400:
+ msg = _('Snapshot failed')
+ raise exception.NovaException(msg)
diff --git a/nova_lxd/nova/virt/lxd/session/snapshot.py b/nova_lxd/nova/virt/lxd/session/snapshot.py
deleted file mode 100644
index 3cf5de6..0000000
--- a/nova_lxd/nova/virt/lxd/session/snapshot.py
+++ /dev/null
@@ -1,187 +0,0 @@
-# Copyright 2015 Canonical Ltd
-# 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.
-
-from nova import exception
-from nova import i18n
-from pylxd import exceptions as lxd_exceptions
-
-from oslo_config import cfg
-from oslo_log import log as logging
-from oslo_service import loopingcall
-from oslo_utils import excutils
-
-_ = i18n._
-_LE = i18n._LE
-_LI = i18n._LI
-
-CONF = cfg.CONF
-LOG = logging.getLogger(__name__)
-
-
-class SnapshotMixin(object):
-
- def container_move(self, old_name, config, instance):
- """Move a container from one host to another
-
- :param old_name: Old container name
- :param config: Old container config
- :param instance: nova instance object
- :return:
-
- """
- LOG.debug('container_move called for instance', instnace=instance)
- try:
- LOG.info(_LI('Moving container %(instance)s with'
- '%(image)s'), {'instance': instance.name,
- 'image': instance.image_ref})
-
- # Container move
- client = self.get_session(instance.host)
- (state, data) = client.container_local_move(old_name, config)
- self.operation_wait(data.get('operation'), instance)
-
- LOG.info(_LI('Successfully moved container %(instance)s with'
- '%(image)s'), {'instance': instance.name,
- 'image': instance.image_ref})
- except lxd_exceptions.APIError as ex:
- msg = _('Failed to communicate with LXD API %(instance)s:'
- ' %(reason)s') % {'instance': instance.name,
- 'reason': ex}
- raise exception.NovaException(msg)
- except Exception as ex:
- with excutils.save_and_reraise_exception():
- LOG.error(
- _LE('Failed to move container %(instance)s: %('
- 'reason)s'),
- {'instance': instance.name,
- 'reason': ex}, instance=instance)
-
- def container_snapshot(self, snapshot, instance):
- """Snapshot a LXD container
-
- :param snapshot: snapshot config dictionary
- :param instance: nova instance object
-
- """
- LOG.debug('container_snapshot called for instance', instance=instance)
- try:
- LOG.info(_LI('Snapshotting container %(instance)s with '
- '%(image)s'), {'instance': instance.name,
- 'image': instance.image_ref})
-
- # Container snapshot
- client = self.get_session(instance.host)
- (state, data) = client.container_snapshot_create(
- instance.name, snapshot)
- self.operation_wait(data.get('operation'), instance)
-
- LOG.info(_LI('Successfully snapshotted container %(instance)s with'
- '%(image)s'), {'instance': instance.name,
- 'image': instance.image_ref})
- except lxd_exceptions.APIError as ex:
- msg = _('Failed to communicate with LXD API %(instance)s:'
- ' %(reason)s') % {'instance': instance.name,
- 'reason': ex}
- raise exception.NovaException(msg)
- except Exception as ex:
- with excutils.save_and_reraise_exception():
- LOG.error(
- _LE('Failed to snapshot container %(instance)s: '
- '%(reason)s'),
- {'instance': instance.name,
- 'reason': ex}, instance=instance)
-
- def container_publish(self, image, instance):
- """Publish a container to the local LXD image store
-
- :param image: LXD fingerprint
- :param instance: nova instance object
- :return: True if published, False otherwise
-
- """
- LOG.debug('container_publish called for instance', instance=instance)
- try:
- client = self.get_session(instance.host)
- return client.container_publish(image)
- except lxd_exceptions.APIError as ex:
- msg = _('Failed to communicate with LXD API %(instance)s:'
- ' %(reason)s') % {'instance': instance.name,
- 'reason': ex}
- raise exception.NovaException(msg)
- except Exception as ex:
- with excutils.save_and_reraise_exception():
- LOG.error(
- _LE('Failed to publish container %(instance)s: '
- '%(reason)s'),
- {'instance': instance.name,
- 'reason': ex}, instance=instance)
-
- def container_export(self, image, instance):
- """
- Export an image from the local LXD image store into
- an file.
-
- :param image: image dictionary
- :param instance: nova instance object
- """
- LOG.debug('container_export called for instance', instance=instance)
- try:
- client = self.get_session(instance.host)
- return client.image_export(image)
- except lxd_exceptions.APIError as ex:
- msg = _('Failed to export image: %s') % ex
- raise exception.NovaException(msg)
- except Exception as ex:
- with excutils.save_and_reraise_exception():
- LOG.error(
- _LE('Failed to export container %(instance)s: '
- '%(reason)s'),
- {'instance': instance.name,
- 'reason': ex}, instance=instance)
-
- def wait_for_snapshot(self, event_id, instance):
- """Poll snapshot operation for the snapshot to be ready.
-
- :param event_id: operation id
- :param instnace: nova instance object
- """
- LOG.debug('wait_for_snapshot called for instance', instance=instance)
-
- timer = loopingcall.FixedIntervalLoopingCall(self._wait_for_snapshot,
- event_id, instance)
- try:
- timer.start(interval=2).wait()
- except Exception as ex:
- with excutils.save_and_reraise_exception():
- LOG.error(_LE('Failed to create snapshot for %(instance)s: '
- '%(ex)s'), {'instance': instance.name, 'ex': ex},
- instance=instance)
-
- def _wait_for_snapshot(self, event_id, instance):
- """Check the status code of the opeation id.
-
- :param event_id: operation id
- :param instance: nova instance object
- """
- client = self.get_session(instance.host)
- (state, data) = client.operation_info(event_id)
- status_code = data['metadata']['status_code']
-
- if status_code == 200:
- raise loopingcall.LoopingCallDone()
- elif status_code == 400:
- msg = _('Snapshot failed')
- raise exception.NovaException(msg)
From 7832bfee09401237b6ae820097075a4e82d66beb Mon Sep 17 00:00:00 2001
From: Paul Hummer <paul.hummer at canonical.com>
Date: Tue, 2 Feb 2016 04:40:33 -0700
Subject: [PATCH 7/8] Consolidate utils into session.
---
nova_lxd/nova/virt/lxd/session/session.py | 22 ++++++++++++++++
nova_lxd/nova/virt/lxd/session/utils.py | 43 -------------------------------
2 files changed, 22 insertions(+), 43 deletions(-)
delete mode 100644 nova_lxd/nova/virt/lxd/session/utils.py
diff --git a/nova_lxd/nova/virt/lxd/session/session.py b/nova_lxd/nova/virt/lxd/session/session.py
index b5d44d8..1bc56ed 100644
--- a/nova_lxd/nova/virt/lxd/session/session.py
+++ b/nova_lxd/nova/virt/lxd/session/session.py
@@ -18,9 +18,12 @@
from nova import exception
from nova import i18n
from nova import rpc
+from nova import utils
from nova.compute import power_state
+from oslo_concurrency import processutils
from pylxd import api
from pylxd import exceptions as lxd_exceptions
+import six
from oslo_config import cfg
from oslo_log import log as logging
@@ -38,6 +41,25 @@
LOG = logging.getLogger(__name__)
+def mount_filesystem(self, dev_path, dir_path):
+ try:
+ _out, err = utils.execute('mount',
+ '-t', 'ext4',
+ dev_path, dir_path, run_as_root=True)
+ except processutils.ProcessExecutionError as e:
+ err = six.text_type(e)
+ return err
+
+
+def umount_filesystem(self, dir_path):
+ try:
+ _out, err = utils.execute('umount',
+ dir_path, run_as_root=True)
+ except processutils.ProcessExecutionError as e:
+ err = six.text_type(e)
+ return err
+
+
class LXDAPISession(object):
"""The session to invoke the LXD API session."""
diff --git a/nova_lxd/nova/virt/lxd/session/utils.py b/nova_lxd/nova/virt/lxd/session/utils.py
deleted file mode 100644
index b024528..0000000
--- a/nova_lxd/nova/virt/lxd/session/utils.py
+++ /dev/null
@@ -1,43 +0,0 @@
-# Copyright 2015 Canonical Ltd
-# 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.
-
-from nova import utils
-
-from oslo_concurrency import processutils
-from oslo_config import cfg
-from oslo_log import log as logging
-import six
-
-CONF = cfg.CONF
-LOG = logging.getLogger(__name__)
-
-
-def mount_filesystem(self, dev_path, dir_path):
- try:
- _out, err = utils.execute('mount',
- '-t', 'ext4',
- dev_path, dir_path, run_as_root=True)
- except processutils.ProcessExecutionError as e:
- err = six.text_type(e)
- return err
-
-
-def umount_filesystem(self, dir_path):
- try:
- _out, err = utils.execute('umount',
- dir_path, run_as_root=True)
- except processutils.ProcessExecutionError as e:
- err = six.text_type(e)
- return err
From fcf98ccb0589fcc9a7395ad19b66ff8b70b55074 Mon Sep 17 00:00:00 2001
From: Paul Hummer <paul.hummer at canonical.com>
Date: Tue, 2 Feb 2016 05:17:13 -0700
Subject: [PATCH 8/8] Change session to package rather than a module
---
nova_lxd/nova/virt/lxd/config.py | 2 +-
nova_lxd/nova/virt/lxd/container_migrate.py | 2 +-
nova_lxd/nova/virt/lxd/container_snapshot.py | 2 +-
nova_lxd/nova/virt/lxd/image.py | 2 +-
nova_lxd/nova/virt/lxd/operations.py | 2 +-
nova_lxd/nova/virt/lxd/session.py | 968 +++++++++++++++++++++++++++
nova_lxd/nova/virt/lxd/session/__init__.py | 0
nova_lxd/nova/virt/lxd/session/session.py | 968 ---------------------------
nova_lxd/tests/session/test_container.py | 2 +-
nova_lxd/tests/session/test_event.py | 2 +-
nova_lxd/tests/session/test_image.py | 2 +-
nova_lxd/tests/session/test_migrate.py | 2 +-
nova_lxd/tests/session/test_snapshot.py | 2 +-
nova_lxd/tests/test_container_migration.py | 2 +-
nova_lxd/tests/test_driver_api.py | 2 +-
nova_lxd/tests/test_image.py | 2 +-
nova_lxd/tests/test_operations.py | 2 +-
17 files changed, 982 insertions(+), 982 deletions(-)
create mode 100644 nova_lxd/nova/virt/lxd/session.py
delete mode 100644 nova_lxd/nova/virt/lxd/session/__init__.py
delete mode 100644 nova_lxd/nova/virt/lxd/session/session.py
diff --git a/nova_lxd/nova/virt/lxd/config.py b/nova_lxd/nova/virt/lxd/config.py
index 10fd6e1..3fb79c9 100644
--- a/nova_lxd/nova/virt/lxd/config.py
+++ b/nova_lxd/nova/virt/lxd/config.py
@@ -23,7 +23,7 @@
from oslo_log import log as logging
from oslo_utils import excutils
-from nova_lxd.nova.virt.lxd.session import session
+from nova_lxd.nova.virt.lxd import session
from nova_lxd.nova.virt.lxd import utils as container_dir
from nova_lxd.nova.virt.lxd import vif
diff --git a/nova_lxd/nova/virt/lxd/container_migrate.py b/nova_lxd/nova/virt/lxd/container_migrate.py
index 1aaf2d2..f55e15b 100644
--- a/nova_lxd/nova/virt/lxd/container_migrate.py
+++ b/nova_lxd/nova/virt/lxd/container_migrate.py
@@ -20,7 +20,7 @@
from nova_lxd.nova.virt.lxd import config
from nova_lxd.nova.virt.lxd import operations
-from nova_lxd.nova.virt.lxd.session import session
+from nova_lxd.nova.virt.lxd import session
_ = i18n._
diff --git a/nova_lxd/nova/virt/lxd/container_snapshot.py b/nova_lxd/nova/virt/lxd/container_snapshot.py
index ef7a108..2be4da9 100644
--- a/nova_lxd/nova/virt/lxd/container_snapshot.py
+++ b/nova_lxd/nova/virt/lxd/container_snapshot.py
@@ -25,7 +25,7 @@
from oslo_log import log as logging
from oslo_utils import excutils
-from nova_lxd.nova.virt.lxd.session import session
+from nova_lxd.nova.virt.lxd import session
_ = i18n._
_LE = i18n._LE
diff --git a/nova_lxd/nova/virt/lxd/image.py b/nova_lxd/nova/virt/lxd/image.py
index 9e0f536..a39d54c 100644
--- a/nova_lxd/nova/virt/lxd/image.py
+++ b/nova_lxd/nova/virt/lxd/image.py
@@ -34,7 +34,7 @@
from oslo_utils import excutils
from oslo_utils import fileutils
-from nova_lxd.nova.virt.lxd.session import session
+from nova_lxd.nova.virt.lxd import session
from nova_lxd.nova.virt.lxd import utils as container_dir
_ = i18n._
diff --git a/nova_lxd/nova/virt/lxd/operations.py b/nova_lxd/nova/virt/lxd/operations.py
index b6306b7..2db014e 100644
--- a/nova_lxd/nova/virt/lxd/operations.py
+++ b/nova_lxd/nova/virt/lxd/operations.py
@@ -35,7 +35,7 @@
from nova_lxd.nova.virt.lxd import config as container_config
from nova_lxd.nova.virt.lxd import container_firewall
from nova_lxd.nova.virt.lxd import image
-from nova_lxd.nova.virt.lxd.session import session
+from nova_lxd.nova.virt.lxd import session
from nova_lxd.nova.virt.lxd import utils as container_dir
from nova_lxd.nova.virt.lxd import vif
diff --git a/nova_lxd/nova/virt/lxd/session.py b/nova_lxd/nova/virt/lxd/session.py
new file mode 100644
index 0000000..1bc56ed
--- /dev/null
+++ b/nova_lxd/nova/virt/lxd/session.py
@@ -0,0 +1,968 @@
+# Copyright 2015 Canonical Ltd
+# 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.
+
+from nova import context as nova_context
+from nova import exception
+from nova import i18n
+from nova import rpc
+from nova import utils
+from nova.compute import power_state
+from oslo_concurrency import processutils
+from pylxd import api
+from pylxd import exceptions as lxd_exceptions
+import six
+
+from oslo_config import cfg
+from oslo_log import log as logging
+from oslo_service import loopingcall
+from oslo_utils import excutils
+
+from nova_lxd.nova.virt.lxd import constants
+
+_ = i18n._
+_LE = i18n._LE
+_LI = i18n._LI
+
+CONF = cfg.CONF
+CONF.import_opt('host', 'nova.netconf')
+LOG = logging.getLogger(__name__)
+
+
+def mount_filesystem(self, dev_path, dir_path):
+ try:
+ _out, err = utils.execute('mount',
+ '-t', 'ext4',
+ dev_path, dir_path, run_as_root=True)
+ except processutils.ProcessExecutionError as e:
+ err = six.text_type(e)
+ return err
+
+
+def umount_filesystem(self, dir_path):
+ try:
+ _out, err = utils.execute('umount',
+ dir_path, run_as_root=True)
+ except processutils.ProcessExecutionError as e:
+ err = six.text_type(e)
+ return err
+
+
+class LXDAPISession(object):
+ """The session to invoke the LXD API session."""
+
+ def __init__(self):
+ super(LXDAPISession, self).__init__()
+
+ def get_session(self, host=None):
+ """Returns a connection to the LXD hypervisor
+
+ This method should be used to create a connection
+ to the LXD hypervisor via the pylxd API call.
+
+ :param host: host is the LXD daemon to connect to
+ :return: pylxd object
+ """
+ try:
+ if host is None:
+ conn = api.API()
+ elif host == CONF.host:
+ conn = api.API()
+ else:
+ conn = api.API(host=host)
+ except Exception as ex:
+ # notify the compute host that the connection failed
+ # via an rpc call
+ LOG.exception(_LE('Connection to LXD failed'))
+ payload = dict(ip=CONF.host,
+ method='_connect',
+ reason=ex)
+ rpc.get_notifier('compute').error(nova_context.get_admin_context,
+ 'compute.nova_lxd.error',
+ payload)
+ raise exception.HypervisorUnavailable(host=CONF.host)
+
+ return conn
+
+ #
+ # Container related API methods
+ #
+
+ def container_list(self):
+ """List of containers running on a given host
+
+ Returns a list of running containers
+
+ """
+ LOG.debug('container_list called')
+ try:
+ client = self.get_session()
+ return client.container_list()
+ except lxd_exceptions.APIError as ex:
+ msg = _('Failed to communicate with LXD API: %(reason)s') \
+ % {'reason': ex}
+ LOG.error(msg)
+ raise exception.NovaException(msg)
+ except Exception as ex:
+ with excutils.save_and_reraise_exception():
+ LOG.error(_LE('Error from LXD during container_list: '
+ '%(reason)s') % {'reason': ex})
+
+ def container_update(self, config, instance):
+ """Update the LXD configuration of a given container
+
+ :param config: LXD configuration dictionary
+ :param instance: nova instance object
+ :return: an update LXD configuration dictionary
+
+ """
+ LOG.debug('container_update called fo instance', instance=instance)
+ try:
+ client = self.get_session(instance.host)
+ if not self.container_defined(instance.name, instance):
+ msg = _('Instance is not found..: %s') % instance.name
+ raise exception.InstanceNotFound(msg)
+
+ return client.container_update(instance.name,
+ config)
+ except lxd_exceptions.APIError as ex:
+ msg = _('Failed to communicate with LXD API %(instance)s:'
+ ' %(reason)s') % {'instance': instance.name,
+ 'reason': ex}
+ raise exception.NovaException(msg)
+ except Exception as e:
+ with excutils.save_and_reraise_exception():
+ LOG.error(_LE('Error from LXD during container_update'
+ '%(instance)s: %(reason)s'),
+ {'instance': instance.name, 'reason': e},
+ instance=instance)
+
+ def container_running(self, instance):
+ """Determine if the container is running
+
+ :param instance: nova instance object
+ :return: True if container is running otherwise false
+
+ """
+ LOG.debug('container_running for instance', instance=instance)
+ try:
+ client = self.get_session(instance.host)
+ return client.container_running(instance.name)
+ except lxd_exceptions.APIError as ex:
+ msg = _('Failed to communicate with LXD API %(instance)s:'
+ ' %(reason)s') % {'instance': instance.name,
+ 'reason': ex}
+ raise exception.NovaException(msg)
+ except Exception as e:
+ with excutils.save_and_reraise_exception():
+ LOG.error(_LE('Error from LXD during container_running'
+ '%(instance)s: %(reason)s'),
+ {'instance': instance.name, 'reason': e},
+ instance=instance)
+
+ def container_state(self, instance):
+ """Determine container_state and translate state
+
+ :param instance: nova instance object
+ :return: nova power_state
+
+ """
+ LOG.debug('container_state called for instance', instance=instance)
+ try:
+ client = self.get_session(instance.host)
+ if not self.container_defined(instance.name, instance):
+ return power_state.NOSTATE
+
+ (state, data) = client.container_state(instance.name)
+ state = constants.LXD_POWER_STATES[data['metadata']['status_code']]
+ except lxd_exceptions.APIError as ex:
+ msg = _('Failed to communicate with LXD API %(instance)s:'
+ ' %(reason)s') % {'instance': instance.name,
+ 'reason': ex}
+ LOG.error(msg)
+ state = power_state.NOSTATE
+ except Exception as e:
+ with excutils.save_and_reraise_exception():
+ LOG.error(_LE('Error from LXD during container_state'
+ '%(instance)s: %(reason)s'),
+ {'instance': instance.name, 'reason': e},
+ instance=instance)
+ state = power_state.NOSTATE
+ return state
+
+ def container_config(self, instance):
+ """Fetches the configuration of a given LXD container
+
+ :param instance: nova instance object
+ :return: dictionary represenation of a LXD container
+
+ """
+ LOG.debug('container_config called for instance', instance=instance)
+ try:
+ if not self.container_defined(instance.name, instance):
+ msg = _('Instance is not found.. %s') % instance.name
+ raise exception.InstanceNotFound(msg)
+
+ client = self.get_session(instance.host)
+ return client.get_container_config(instance.name)
+ except lxd_exceptions.APIError as ex:
+ msg = _('Failed to communicate with LXD API %(instance)s:'
+ ' %(reason)s') % {'instance': instance.name,
+ 'reason': ex}
+ raise exception.NovaException(msg)
+ except Exception as e:
+ with excutils.save_and_reraise_exception():
+ LOG.error(_LE('Error from LXD during container_config'
+ '%(instance)s: %(reason)s'),
+ {'instance': instance.name, 'reason': e},
+ instance=instance)
+
+ def container_info(self, instance):
+ """Returns basic information about a LXD container
+
+ :param instance: nova instance object
+ :return: LXD container information
+
+ """
+ LOG.debug('container_info called for instance', instance=instance)
+ try:
+ if not self.container_defined(instance.name, instance):
+ msg = _('Instance is not found.. %s') % instance.name
+ raise exception.InstanceNotFound(msg)
+
+ client = self.get_session(instance.host)
+ return client.container_info(instance.name)
+ except lxd_exceptions.APIError as ex:
+ msg = _('Failed to communicate with LXD API %(instance)s:'
+ ' %(reason)s') % {'instance': instance.name,
+ 'reason': ex}
+ raise exception.NovaException(msg)
+ except Exception as e:
+ with excutils.save_and_reraise_exception():
+ LOG.error(_LE('Error from LXD during container_info'
+ '%(instance)s: %(reason)s'),
+ {'instance': instance.name, 'reason': e},
+ instance=instance)
+
+ def container_defined(self, instance_name, instance):
+ """Determine if the container exists
+
+ :param instance_name: container anme
+ :param instance: nova instance opbject
+ :return: True if exists otherwise False
+
+ """
+ LOG.debug('container_defined for instance', instance=instance)
+ try:
+ client = self.get_session(instance.host)
+ return client.container_defined(instance_name)
+ except lxd_exceptions.APIError as ex:
+ if ex.status_code == 404:
+ return False
+ else:
+ msg = _('Failed to get container status: %s') % ex
+ raise exception.NovaException(msg)
+ except Exception as e:
+ with excutils.save_and_reraise_exception():
+ LOG.error(_LE('Error from LXD during container_defined'
+ '%(instance)s: %(reason)s'),
+ {'instance': instance.name, 'reason': e},
+ instance=instance)
+
+ def container_start(self, instance_name, instance):
+ """Start an LXD container
+
+ :param instance_name: name of container
+ :param instance: nova instance object
+
+ """
+ LOG.debug('container_start called for instance', instance=instance)
+ try:
+ LOG.info(_LI('Starting instance %(instance)s with '
+ '%(image)s'), {'instance': instance.name,
+ 'image': instance.image_ref})
+ # Start the container
+ client = self.get_session(instance.host)
+
+ # (chuck): Something wicked could happen between
+ # container
+ if not self.container_defined(instance_name, instance):
+ msg = _('Instance is not found.. %s ') % instance.name
+ raise exception.InstanceNotFound(msg)
+
+ (state, data) = client.container_start(instance_name,
+ CONF.lxd.timeout)
+ self.operation_wait(data.get('operation'), instance)
+
+ LOG.info(_LI('Successfully started instance %(instance)s with'
+ '%(image)s'), {'instance': instance.name,
+ 'image': instance.image_ref})
+ except lxd_exceptions.APIError as ex:
+ msg = _('Failed to communicate with LXD API %(instance)s:'
+ ' %(reason)s') % {'instance': instance.name,
+ 'reason': ex}
+ raise exception.NovaException(msg)
+ except Exception as ex:
+ with excutils.save_and_reraise_exception():
+ LOG.error(
+ _LE('Failed to start container %(instance)s: %(reason)s'),
+ {'instance': instance_name, 'reason': ex},
+ instance=instance)
+
+ def container_stop(self, instance_name, host, instance):
+ """Stops an LXD container
+
+ :param instance_name: instance name
+ :param host: host where the container is running
+ :param instance: nova instance object
+
+ """
+ LOG.debug('container_stop called for instance', instance=instance)
+ try:
+ if not self.container_defined(instance_name, instance):
+ msg = _('Instance is not found..: %s') % instance.name
+ raise exception.InstanceNotFound(msg)
+
+ LOG.info(_LI('Stopping instance %(instance)s with'
+ '%(image)s'), {'instance': instance.name,
+ 'image': instance.image_ref})
+ # Stop the container
+ client = self.get_session(host)
+ (state, data) = client.container_stop(instance_name,
+ CONF.lxd.timeout)
+ self.operation_wait(data.get('operation'), instance)
+
+ LOG.info(_LI('Successfully stopped instance %(instance)s with'
+ '%(image)s'), {'instance': instance.name,
+ 'image': instance.image_ref})
+ except lxd_exceptions.APIError as ex:
+ msg = _('Failed to communicate with LXD API %(instance)s:'
+ ' %(reason)s') % {'instance': instance.name,
+ 'reason': ex}
+ raise exception.NovaException(msg)
+ except Exception as ex:
+ with excutils.save_and_reraise_exception():
+ LOG.error(
+ _LE('Failed to stop container %(instance)s: '
+ '%(reason)s'), {'instance': instance_name,
+ 'reason': ex})
+
+ def container_reboot(self, instance):
+ """Reboot a LXD container
+
+ :param instance: nova instance object
+
+ """
+ LOG.debug('container_reboot called for instance', instance=instance)
+ try:
+ if not self.container_defined(instance.name, instance):
+ msg = _('Instance is not found..: %s') % instance.name
+ raise exception.InstanceNotFound(msg)
+
+ LOG.info(_LI('Rebooting instance %(instance)s with'
+ '%(image)s'), {'instance': instance.name,
+ 'image': instance.image_ref})
+
+ # Container reboot
+ client = self.get_session(instance.host)
+ (state, data) = client.container_reboot(instance.name,
+ CONF.lxd.timeout)
+ self.operation_wait(data.get('operation'), instance)
+
+ LOG.info(_LI('Successfully rebooted instance %(instance)s with'
+ '%(image)s'), {'instance': instance.name,
+ 'image': instance.image_ref})
+ except lxd_exceptions.APIError as ex:
+ msg = _('Failed to communicate with LXD API %(instance)s:'
+ ' %(reason)s') % {'instance': instance.name,
+ 'reason': ex}
+ raise exception.NovaException(msg)
+ except Exception as ex:
+ with excutils.save_and_reraise_exception():
+ LOG.error(
+ _LE('Failed to reboot container %(instance)s: '
+ '%(reason)s'), {'instance': instance.name,
+ 'reason': ex}, instance=instance)
+
+ def container_destroy(self, instance_name, host, instance):
+ """Destroy a LXD container
+
+ :param instance_name: container name
+ :param host: container host
+ :param instance: nova instance object
+
+ """
+ LOG.debug('container_destroy for instance', instance=instance)
+ try:
+ if not self.container_defined(instance_name, instance):
+ return
+
+ LOG.info(_LI('Destroying instance %(instance)s with'
+ '%(image)s'), {'instance': instance.name,
+ 'image': instance.image_ref})
+
+ # Destroying container
+ self.container_stop(instance_name, host, instance)
+
+ client = self.get_session(host)
+ (state, data) = client.container_destroy(instance_name)
+ self.operation_wait(data.get('operation'), instance)
+
+ LOG.info(_LI('Successfully destroyed instance %(instance)s with'
+ '%(image)s'), {'instance': instance.name,
+ 'image': instance.image_ref})
+ except lxd_exceptions.APIError as ex:
+ msg = _('Failed to communicate with LXD API %(instance)s:'
+ ' %(reason)s') % {'instance': instance.name,
+ 'reason': ex}
+ raise exception.NovaException(msg)
+ except Exception as ex:
+ with excutils.save_and_reraise_exception():
+ LOG.error(_LE('Failed to destroy container %(instance)s: '
+ '%(reason)s'), {'instance': instance_name,
+ 'reason': ex})
+
+ def container_pause(self, instance_name, instance):
+ """Pause a LXD container
+
+ :param instance_name: container name
+ :param instance: nova instance object
+
+ """
+ LOG.debug('container_paused called for instance', instance=instance)
+ try:
+ if not self.container_defined(instance_name, instance):
+ msg = _('Instance is not found. %s') % instance_name
+ raise exception.InstanceNotFound(msg)
+
+ LOG.info(_LI('Pausing instance %(instance)s with'
+ '%(image)s'), {'instance': instance_name,
+ 'image': instance.image_ref})
+
+ client = self.get_session(instance.host)
+ (state, data) = client.container_suspend(instance_name,
+ CONF.lxd.timeout)
+ self.operation_wait(data.get('operation'), instance)
+
+ LOG.info(_LI('Successfully paused instance %(instance)s with'
+ '%(image)s'), {'instance': instance_name,
+ 'image': instance.image_ref})
+ except lxd_exceptions.APIError as ex:
+ msg = _('Failed to communicate with LXD API %(instance)s:'
+ ' %(reason)s') % {'instance': instance_name,
+ 'reason': ex}
+ raise exception.NovaException(msg)
+ except Exception as ex:
+ with excutils.save_and_reraise_exception():
+ LOG.error(
+ _LE('Failed to pause container %(instance)s: '
+ '%(reason)s'),
+ {'instance': instance_name,
+ 'reason': ex}, instance=instance)
+
+ def container_unpause(self, instance_name, instance):
+ """Unpause a LXD container
+
+ :param instance_name: container name
+ :param instance: nova instance object
+
+ """
+ LOG.debug('container_unpause called for instance', instance=instance)
+ try:
+ if not self.container_defined(instance_name, instance):
+ msg = _('Instance is not found. %s') % instance_name
+ raise exception.InstanceNotFound(msg)
+
+ LOG.info(_LI('Unpausing instance %(instance)s with'
+ '%(image)s'), {'instance': instance.name,
+ 'image': instance.image_ref})
+
+ client = self.get_session(instance.host)
+ (state, data) = client.container_resume(instance_name,
+ CONF.lxd.timeout)
+ self.operation_wait(data.get('operation'), instance)
+
+ LOG.info(_LI('Successfully unpaused instance %(instance)s with'
+ '%(image)s'), {'instance': instance.name,
+ 'image': instance.image_ref})
+ except lxd_exceptions.APIError as ex:
+ msg = _('Failed to communicate with LXD API %(instance)s:'
+ ' %(reason)s') % {'instance': instance.name,
+ 'reason': ex}
+ raise exception.NovaException(msg)
+ except Exception as ex:
+ with excutils.save_and_reraise_exception():
+ LOG.error(
+ _LE('Failed to unpause container %(instance)s: '
+ '%(reason)s'), {'instance': instance_name,
+ 'reason': ex})
+
+ def container_init(self, config, instance, host):
+ """Create a LXD container
+
+ :param config: LXD container config as a dict
+ :param instance: nova instance object
+ :param host: host to create the container on
+
+ """
+ LOG.debug('container_init called for instance', instance=instance)
+ try:
+ LOG.info(_LI('Creating container %(instance)s with'
+ '%(image)s'), {'instance': instance.name,
+ 'image': instance.image_ref})
+
+ client = self.get_session(host)
+ (state, data) = client.container_init(config)
+ operation = data.get('operation')
+ self.operation_wait(operation, instance)
+ status, data = self.operation_info(operation, instance)
+ data = data.get('metadata')
+ if not data['status_code'] == 200:
+ raise exception.NovaException(data['metadata'])
+
+ LOG.info(_LI('Successfully created container %(instance)s with'
+ '%(image)s'), {'instance': instance.name,
+ 'image': instance.image_ref})
+ except lxd_exceptions.APIError as ex:
+ msg = _('Failed to communicate with LXD API %(instance)s:'
+ ' %(reason)s') % {'instance': instance.name,
+ 'reason': ex}
+ raise exception.NovaException(msg)
+ except Exception as ex:
+ with excutils.save_and_reraise_exception():
+ LOG.error(
+ _LE('Failed to create container %(instance)s: %(reason)s'),
+ {'instance': instance.name,
+ 'reason': ex}, instance=instance)
+
+ #
+ # Image related API methods.
+ #
+
+ def image_defined(self, instance):
+ """Checks existence of an image on the local LXD image store
+
+ :param instance: The nova instance
+
+ Returns True if supplied image exists on the host, False otherwise
+ """
+ LOG.debug('image_defined called for instance', instance=instance)
+ try:
+ client = self.get_session(instance.host)
+ return client.alias_defined(instance.image_ref)
+ except lxd_exceptions.APIError as ex:
+ if ex.status_code == 404:
+ return False
+ else:
+ msg = _('Failed to communicate with LXD API %(instance)s:'
+ ' %(reason)s') % {'instance': instance.image_ref,
+ 'reason': ex}
+ LOG.error(msg)
+ raise exception.NovaException(msg)
+ except Exception as e:
+ with excutils.save_and_reraise_exception():
+ LOG.error(_LE('Error from LXD during image_defined '
+ '%(instance)s: %(reason)s'),
+ {'instance': instance.image_ref, 'reason': e},
+ instance=instance)
+
+ def create_alias(self, alias, instance):
+ """Creates an alias for a given image
+
+ :param alias: The alias to be crerated
+ :param instance: The nove instnace
+ :return: true if alias is created, false otherwise
+
+ """
+ LOG.debug('create_alias called for instance', instance=instance)
+ try:
+ client = self.get_session(instance.host)
+ return client.alias_create(alias)
+ except lxd_exceptions.APIError as ex:
+ msg = _('Failed to communicate with LXD API %(instance)s:'
+ ' %(reason)s') % {'instance': instance.image_ref,
+ 'reason': ex}
+ LOG.error(msg)
+ raise exception.NovaException(msg)
+ except Exception as e:
+ with excutils.save_and_reraise_exception():
+ LOG.error(_LE('Error from LXD during create alias'
+ '%(instance)s: %(reason)s'),
+ {'instance': instance.image_ref, 'reason': e},
+ instance=instance)
+
+ def image_upload(self, data, headers, instance):
+ """Upload an image to the local LXD image store
+
+ :param data: image data
+ :param headers: image headers
+ :param intance: The nova instance
+
+ """
+ LOG.debug('upload_image called for instnace', instance=instance)
+ try:
+ client = self.get_session(instance.host)
+ (state, data) = client.image_upload(data=data,
+ headers=headers)
+ # XXX - zulcss (Dec 8, 2015) - Work around for older
+ # versions of LXD.
+ if 'operation' in data:
+ self.operation_wait(data.get('operation'), instance)
+ except lxd_exceptions.APIError as ex:
+ msg = _('Failed to communicate with LXD API %(instance)s:'
+ '%(reason)s') % {'instance': instance.image_ref,
+ 'reason': ex}
+ LOG.error(msg)
+ raise exception.NovaException(msg)
+ except Exception as e:
+ with excutils.save_and_reraise_exception():
+ LOG.error(_LE('Error from LXD during image upload'
+ '%(instance)s: %(reason)s'),
+ {'instance': instance.image_ref, 'reason': e},
+ instance=instance)
+
+ #
+ # Operation methods
+ #
+
+ def operation_wait(self, operation_id, instance):
+ """Waits for an operation to return 200 (Success)
+
+ :param operation_id: The operation to wait for.
+ """
+ LOG.debug('wait_for_contianer for instance', instance=instance)
+ try:
+ client = self.get_session(instance.host)
+ if not client.wait_container_operation(operation_id, 200, -1):
+ msg = _('Container creation timed out')
+ raise exception.NovaException(msg)
+ except lxd_exceptions.APIError as ex:
+ msg = _('Failed to communicate with LXD API %(instance)s:'
+ '%(reason)s') % {'instance': instance.image_ref,
+ 'reason': ex}
+ LOG.error(msg)
+ raise exception.NovaException(msg)
+ except Exception as e:
+ with excutils.save_and_reraise_exception():
+ LOG.error(_LE('Error from LXD during operation wait'
+ '%(instance)s: %(reason)s'),
+ {'instance': instance.image_ref, 'reason': e},
+ instance=instance)
+
+ def operation_info(self, operation_id, instance):
+ LOG.debug('operation_info called for instance', instance=instance)
+ try:
+ client = self.get_session(instance.host)
+ return client.operation_info(operation_id)
+ except lxd_exceptions.APIError as ex:
+ msg = _('Failed to communicate with LXD API %(instance)s:'
+ '%(reason)s') % {'instance': instance.image_ref,
+ 'reason': ex}
+ LOG.error(msg)
+ raise exception.NovaException(msg)
+ except Exception as e:
+ with excutils.save_and_reraise_exception():
+ LOG.error(_LE('Error from LXD during operation_info '
+ '%(instance)s: %(reason)s'),
+ {'instance': instance.image_ref, 'reason': e},
+ instance=instance)
+
+ #
+ # Profile methods
+ #
+ def profile_defined(self, instance):
+ """Validate if the profile is available on the LXD
+ host
+
+ :param instance: nova instance object
+ """
+ LOG.debug('profile_defined called for instance',
+ instance=instance)
+ try:
+ client = self.get_session(instance.host)
+ client.profile_defined(instance.name)
+ except lxd_exceptions.APIError as ex:
+ if ex.status_code == 404:
+ return False
+ else:
+ msg = _('Failed to communicate with LXD API %(instance)s:'
+ ' %(reason)s') % {'instance': instance.name,
+ 'reason': ex}
+ raise exception.NovaException(msg)
+ except Exception as ex:
+ with excutils.save_and_reraise_exception():
+ LOG.error(
+ _LE('Failed to determine profile %(instance)s:'
+ ' %(reason)s'),
+ {'instance': instance.name, 'reason': ex})
+
+ def profile_create(self, config, instance):
+ """Create an LXD container profile
+
+ :param config: profile dictionary
+ :param instnace: nova instance object
+ """
+ LOG.debug('profile_create called for instance',
+ instance=instance)
+ try:
+ client = self.get_session(instance.host)
+ client.profile_create(config)
+ except lxd_exceptions.APIError as ex:
+ msg = _('Failed to communicate with LXD API %(instance)s:'
+ ' %(reason)s') % {'instance': instance.name,
+ 'reason': ex}
+ raise exception.NovaException(msg)
+ except Exception as ex:
+ with excutils.save_and_reraise_exception():
+ LOG.error(
+ _LE('Failed to create profile %(instance)s: %(reason)s'),
+ {'instance': instance.name, 'reason': ex})
+
+ def profile_update(self, config, instance):
+ """Update an LXD container profile
+
+ :param config: LXD profile dictironary
+ :param instance: nova instance object
+ """
+ LOG.debug('profile_udpate called for instance', instance=instance)
+ try:
+ client = self.get_session(instance.host)
+ client.profile_update(instance.name, config)
+ except lxd_exceptions.APIError as ex:
+ msg = _('Failed to communicate with LXD API %(instance)s:'
+ ' %(reason)s') % {'instance': instance.name,
+ 'reason': ex}
+ raise exception.NovaException(msg)
+ except Exception as ex:
+ with excutils.save_and_reraise_exception():
+ LOG.error(
+ _LE('Failed to update profile %(instance)s: '
+ '%(reason)s'),
+ {'instance': instance.name, 'reason': ex})
+
+ def profile_delete(self, instance):
+ """Delete a LXD container profile.
+
+ :param instance: nova instance object
+ """
+ LOG.debug('profile_delete called for instance', instance=instance)
+ try:
+ client = self.get_session(instance.host)
+ client.profile_delete(instance.name)
+ except lxd_exceptions.APIError as ex:
+ msg = _('Failed to communicate with LXD API %(instance)s:'
+ ' %(reason)s') % {'instance': instance.name,
+ 'reason': ex}
+ raise exception.NovaException(msg)
+ except Exception as ex:
+ with excutils.save_and_reraise_exception():
+ LOG.error(
+ _LE('Failed to delete profile %(instance)s: %(reason)s'),
+ {'instance': instance.name, 'reason': ex})
+
+ #
+ # Migrate methods
+ #
+ def container_migrate(self, instance_name, host, instance):
+ """Initialize a container migration for LXD
+
+ :param instance_name: container name
+ :param host: host to move container from
+ :param instance: nova instance object
+ :return: dictionary of the container keys
+
+ """
+ LOG.debug('container_migrate called for instance', instance=instance)
+ try:
+ LOG.info(_LI('Migrating instance %(instance)s with'
+ '%(image)s'), {'instance': instance_name,
+ 'image': instance.image_ref})
+
+ client = self.get_session(host)
+ (state, data) = client.container_migrate(instance_name)
+
+ LOG.info(_LI('Successfully initialized migration for instance '
+ '%(instance)s with %(image)s'),
+ {'instance': instance.name,
+ 'image': instance.image_ref})
+ return (state, data)
+ except lxd_exceptions.APIError as ex:
+ msg = _('Failed to communicate with LXD API %(instance)s:'
+ ' %(reason)s') % {'instance': instance.name,
+ 'reason': ex}
+ raise exception.NovaException(msg)
+ except Exception as ex:
+ with excutils.save_and_reraise_exception():
+ LOG.error(
+ _LE('Failed to migrate container %(instance)s: %('
+ 'reason)s'), {'instance': instance.name,
+ 'reason': ex}, instance=instance)
+
+ #
+ # Snapshot methods
+ #
+
+ def container_move(self, old_name, config, instance):
+ """Move a container from one host to another
+
+ :param old_name: Old container name
+ :param config: Old container config
+ :param instance: nova instance object
+ :return:
+
+ """
+ LOG.debug('container_move called for instance', instnace=instance)
+ try:
+ LOG.info(_LI('Moving container %(instance)s with'
+ '%(image)s'), {'instance': instance.name,
+ 'image': instance.image_ref})
+
+ # Container move
+ client = self.get_session(instance.host)
+ (state, data) = client.container_local_move(old_name, config)
+ self.operation_wait(data.get('operation'), instance)
+
+ LOG.info(_LI('Successfully moved container %(instance)s with'
+ '%(image)s'), {'instance': instance.name,
+ 'image': instance.image_ref})
+ except lxd_exceptions.APIError as ex:
+ msg = _('Failed to communicate with LXD API %(instance)s:'
+ ' %(reason)s') % {'instance': instance.name,
+ 'reason': ex}
+ raise exception.NovaException(msg)
+ except Exception as ex:
+ with excutils.save_and_reraise_exception():
+ LOG.error(
+ _LE('Failed to move container %(instance)s: %('
+ 'reason)s'),
+ {'instance': instance.name,
+ 'reason': ex}, instance=instance)
+
+ def container_snapshot(self, snapshot, instance):
+ """Snapshot a LXD container
+
+ :param snapshot: snapshot config dictionary
+ :param instance: nova instance object
+
+ """
+ LOG.debug('container_snapshot called for instance', instance=instance)
+ try:
+ LOG.info(_LI('Snapshotting container %(instance)s with '
+ '%(image)s'), {'instance': instance.name,
+ 'image': instance.image_ref})
+
+ # Container snapshot
+ client = self.get_session(instance.host)
+ (state, data) = client.container_snapshot_create(
+ instance.name, snapshot)
+ self.operation_wait(data.get('operation'), instance)
+
+ LOG.info(_LI('Successfully snapshotted container %(instance)s with'
+ '%(image)s'), {'instance': instance.name,
+ 'image': instance.image_ref})
+ except lxd_exceptions.APIError as ex:
+ msg = _('Failed to communicate with LXD API %(instance)s:'
+ ' %(reason)s') % {'instance': instance.name,
+ 'reason': ex}
+ raise exception.NovaException(msg)
+ except Exception as ex:
+ with excutils.save_and_reraise_exception():
+ LOG.error(
+ _LE('Failed to snapshot container %(instance)s: '
+ '%(reason)s'),
+ {'instance': instance.name,
+ 'reason': ex}, instance=instance)
+
+ def container_publish(self, image, instance):
+ """Publish a container to the local LXD image store
+
+ :param image: LXD fingerprint
+ :param instance: nova instance object
+ :return: True if published, False otherwise
+
+ """
+ LOG.debug('container_publish called for instance', instance=instance)
+ try:
+ client = self.get_session(instance.host)
+ return client.container_publish(image)
+ except lxd_exceptions.APIError as ex:
+ msg = _('Failed to communicate with LXD API %(instance)s:'
+ ' %(reason)s') % {'instance': instance.name,
+ 'reason': ex}
+ raise exception.NovaException(msg)
+ except Exception as ex:
+ with excutils.save_and_reraise_exception():
+ LOG.error(
+ _LE('Failed to publish container %(instance)s: '
+ '%(reason)s'),
+ {'instance': instance.name,
+ 'reason': ex}, instance=instance)
+
+ def container_export(self, image, instance):
+ """
+ Export an image from the local LXD image store into
+ an file.
+
+ :param image: image dictionary
+ :param instance: nova instance object
+ """
+ LOG.debug('container_export called for instance', instance=instance)
+ try:
+ client = self.get_session(instance.host)
+ return client.image_export(image)
+ except lxd_exceptions.APIError as ex:
+ msg = _('Failed to export image: %s') % ex
+ raise exception.NovaException(msg)
+ except Exception as ex:
+ with excutils.save_and_reraise_exception():
+ LOG.error(
+ _LE('Failed to export container %(instance)s: '
+ '%(reason)s'),
+ {'instance': instance.name,
+ 'reason': ex}, instance=instance)
+
+ def wait_for_snapshot(self, event_id, instance):
+ """Poll snapshot operation for the snapshot to be ready.
+
+ :param event_id: operation id
+ :param instnace: nova instance object
+ """
+ LOG.debug('wait_for_snapshot called for instance', instance=instance)
+
+ timer = loopingcall.FixedIntervalLoopingCall(self._wait_for_snapshot,
+ event_id, instance)
+ try:
+ timer.start(interval=2).wait()
+ except Exception as ex:
+ with excutils.save_and_reraise_exception():
+ LOG.error(_LE('Failed to create snapshot for %(instance)s: '
+ '%(ex)s'), {'instance': instance.name, 'ex': ex},
+ instance=instance)
+
+ def _wait_for_snapshot(self, event_id, instance):
+ """Check the status code of the opeation id.
+
+ :param event_id: operation id
+ :param instance: nova instance object
+ """
+ client = self.get_session(instance.host)
+ (state, data) = client.operation_info(event_id)
+ status_code = data['metadata']['status_code']
+
+ if status_code == 200:
+ raise loopingcall.LoopingCallDone()
+ elif status_code == 400:
+ msg = _('Snapshot failed')
+ raise exception.NovaException(msg)
diff --git a/nova_lxd/nova/virt/lxd/session/__init__.py b/nova_lxd/nova/virt/lxd/session/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/nova_lxd/nova/virt/lxd/session/session.py b/nova_lxd/nova/virt/lxd/session/session.py
deleted file mode 100644
index 1bc56ed..0000000
--- a/nova_lxd/nova/virt/lxd/session/session.py
+++ /dev/null
@@ -1,968 +0,0 @@
-# Copyright 2015 Canonical Ltd
-# 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.
-
-from nova import context as nova_context
-from nova import exception
-from nova import i18n
-from nova import rpc
-from nova import utils
-from nova.compute import power_state
-from oslo_concurrency import processutils
-from pylxd import api
-from pylxd import exceptions as lxd_exceptions
-import six
-
-from oslo_config import cfg
-from oslo_log import log as logging
-from oslo_service import loopingcall
-from oslo_utils import excutils
-
-from nova_lxd.nova.virt.lxd import constants
-
-_ = i18n._
-_LE = i18n._LE
-_LI = i18n._LI
-
-CONF = cfg.CONF
-CONF.import_opt('host', 'nova.netconf')
-LOG = logging.getLogger(__name__)
-
-
-def mount_filesystem(self, dev_path, dir_path):
- try:
- _out, err = utils.execute('mount',
- '-t', 'ext4',
- dev_path, dir_path, run_as_root=True)
- except processutils.ProcessExecutionError as e:
- err = six.text_type(e)
- return err
-
-
-def umount_filesystem(self, dir_path):
- try:
- _out, err = utils.execute('umount',
- dir_path, run_as_root=True)
- except processutils.ProcessExecutionError as e:
- err = six.text_type(e)
- return err
-
-
-class LXDAPISession(object):
- """The session to invoke the LXD API session."""
-
- def __init__(self):
- super(LXDAPISession, self).__init__()
-
- def get_session(self, host=None):
- """Returns a connection to the LXD hypervisor
-
- This method should be used to create a connection
- to the LXD hypervisor via the pylxd API call.
-
- :param host: host is the LXD daemon to connect to
- :return: pylxd object
- """
- try:
- if host is None:
- conn = api.API()
- elif host == CONF.host:
- conn = api.API()
- else:
- conn = api.API(host=host)
- except Exception as ex:
- # notify the compute host that the connection failed
- # via an rpc call
- LOG.exception(_LE('Connection to LXD failed'))
- payload = dict(ip=CONF.host,
- method='_connect',
- reason=ex)
- rpc.get_notifier('compute').error(nova_context.get_admin_context,
- 'compute.nova_lxd.error',
- payload)
- raise exception.HypervisorUnavailable(host=CONF.host)
-
- return conn
-
- #
- # Container related API methods
- #
-
- def container_list(self):
- """List of containers running on a given host
-
- Returns a list of running containers
-
- """
- LOG.debug('container_list called')
- try:
- client = self.get_session()
- return client.container_list()
- except lxd_exceptions.APIError as ex:
- msg = _('Failed to communicate with LXD API: %(reason)s') \
- % {'reason': ex}
- LOG.error(msg)
- raise exception.NovaException(msg)
- except Exception as ex:
- with excutils.save_and_reraise_exception():
- LOG.error(_LE('Error from LXD during container_list: '
- '%(reason)s') % {'reason': ex})
-
- def container_update(self, config, instance):
- """Update the LXD configuration of a given container
-
- :param config: LXD configuration dictionary
- :param instance: nova instance object
- :return: an update LXD configuration dictionary
-
- """
- LOG.debug('container_update called fo instance', instance=instance)
- try:
- client = self.get_session(instance.host)
- if not self.container_defined(instance.name, instance):
- msg = _('Instance is not found..: %s') % instance.name
- raise exception.InstanceNotFound(msg)
-
- return client.container_update(instance.name,
- config)
- except lxd_exceptions.APIError as ex:
- msg = _('Failed to communicate with LXD API %(instance)s:'
- ' %(reason)s') % {'instance': instance.name,
- 'reason': ex}
- raise exception.NovaException(msg)
- except Exception as e:
- with excutils.save_and_reraise_exception():
- LOG.error(_LE('Error from LXD during container_update'
- '%(instance)s: %(reason)s'),
- {'instance': instance.name, 'reason': e},
- instance=instance)
-
- def container_running(self, instance):
- """Determine if the container is running
-
- :param instance: nova instance object
- :return: True if container is running otherwise false
-
- """
- LOG.debug('container_running for instance', instance=instance)
- try:
- client = self.get_session(instance.host)
- return client.container_running(instance.name)
- except lxd_exceptions.APIError as ex:
- msg = _('Failed to communicate with LXD API %(instance)s:'
- ' %(reason)s') % {'instance': instance.name,
- 'reason': ex}
- raise exception.NovaException(msg)
- except Exception as e:
- with excutils.save_and_reraise_exception():
- LOG.error(_LE('Error from LXD during container_running'
- '%(instance)s: %(reason)s'),
- {'instance': instance.name, 'reason': e},
- instance=instance)
-
- def container_state(self, instance):
- """Determine container_state and translate state
-
- :param instance: nova instance object
- :return: nova power_state
-
- """
- LOG.debug('container_state called for instance', instance=instance)
- try:
- client = self.get_session(instance.host)
- if not self.container_defined(instance.name, instance):
- return power_state.NOSTATE
-
- (state, data) = client.container_state(instance.name)
- state = constants.LXD_POWER_STATES[data['metadata']['status_code']]
- except lxd_exceptions.APIError as ex:
- msg = _('Failed to communicate with LXD API %(instance)s:'
- ' %(reason)s') % {'instance': instance.name,
- 'reason': ex}
- LOG.error(msg)
- state = power_state.NOSTATE
- except Exception as e:
- with excutils.save_and_reraise_exception():
- LOG.error(_LE('Error from LXD during container_state'
- '%(instance)s: %(reason)s'),
- {'instance': instance.name, 'reason': e},
- instance=instance)
- state = power_state.NOSTATE
- return state
-
- def container_config(self, instance):
- """Fetches the configuration of a given LXD container
-
- :param instance: nova instance object
- :return: dictionary represenation of a LXD container
-
- """
- LOG.debug('container_config called for instance', instance=instance)
- try:
- if not self.container_defined(instance.name, instance):
- msg = _('Instance is not found.. %s') % instance.name
- raise exception.InstanceNotFound(msg)
-
- client = self.get_session(instance.host)
- return client.get_container_config(instance.name)
- except lxd_exceptions.APIError as ex:
- msg = _('Failed to communicate with LXD API %(instance)s:'
- ' %(reason)s') % {'instance': instance.name,
- 'reason': ex}
- raise exception.NovaException(msg)
- except Exception as e:
- with excutils.save_and_reraise_exception():
- LOG.error(_LE('Error from LXD during container_config'
- '%(instance)s: %(reason)s'),
- {'instance': instance.name, 'reason': e},
- instance=instance)
-
- def container_info(self, instance):
- """Returns basic information about a LXD container
-
- :param instance: nova instance object
- :return: LXD container information
-
- """
- LOG.debug('container_info called for instance', instance=instance)
- try:
- if not self.container_defined(instance.name, instance):
- msg = _('Instance is not found.. %s') % instance.name
- raise exception.InstanceNotFound(msg)
-
- client = self.get_session(instance.host)
- return client.container_info(instance.name)
- except lxd_exceptions.APIError as ex:
- msg = _('Failed to communicate with LXD API %(instance)s:'
- ' %(reason)s') % {'instance': instance.name,
- 'reason': ex}
- raise exception.NovaException(msg)
- except Exception as e:
- with excutils.save_and_reraise_exception():
- LOG.error(_LE('Error from LXD during container_info'
- '%(instance)s: %(reason)s'),
- {'instance': instance.name, 'reason': e},
- instance=instance)
-
- def container_defined(self, instance_name, instance):
- """Determine if the container exists
-
- :param instance_name: container anme
- :param instance: nova instance opbject
- :return: True if exists otherwise False
-
- """
- LOG.debug('container_defined for instance', instance=instance)
- try:
- client = self.get_session(instance.host)
- return client.container_defined(instance_name)
- except lxd_exceptions.APIError as ex:
- if ex.status_code == 404:
- return False
- else:
- msg = _('Failed to get container status: %s') % ex
- raise exception.NovaException(msg)
- except Exception as e:
- with excutils.save_and_reraise_exception():
- LOG.error(_LE('Error from LXD during container_defined'
- '%(instance)s: %(reason)s'),
- {'instance': instance.name, 'reason': e},
- instance=instance)
-
- def container_start(self, instance_name, instance):
- """Start an LXD container
-
- :param instance_name: name of container
- :param instance: nova instance object
-
- """
- LOG.debug('container_start called for instance', instance=instance)
- try:
- LOG.info(_LI('Starting instance %(instance)s with '
- '%(image)s'), {'instance': instance.name,
- 'image': instance.image_ref})
- # Start the container
- client = self.get_session(instance.host)
-
- # (chuck): Something wicked could happen between
- # container
- if not self.container_defined(instance_name, instance):
- msg = _('Instance is not found.. %s ') % instance.name
- raise exception.InstanceNotFound(msg)
-
- (state, data) = client.container_start(instance_name,
- CONF.lxd.timeout)
- self.operation_wait(data.get('operation'), instance)
-
- LOG.info(_LI('Successfully started instance %(instance)s with'
- '%(image)s'), {'instance': instance.name,
- 'image': instance.image_ref})
- except lxd_exceptions.APIError as ex:
- msg = _('Failed to communicate with LXD API %(instance)s:'
- ' %(reason)s') % {'instance': instance.name,
- 'reason': ex}
- raise exception.NovaException(msg)
- except Exception as ex:
- with excutils.save_and_reraise_exception():
- LOG.error(
- _LE('Failed to start container %(instance)s: %(reason)s'),
- {'instance': instance_name, 'reason': ex},
- instance=instance)
-
- def container_stop(self, instance_name, host, instance):
- """Stops an LXD container
-
- :param instance_name: instance name
- :param host: host where the container is running
- :param instance: nova instance object
-
- """
- LOG.debug('container_stop called for instance', instance=instance)
- try:
- if not self.container_defined(instance_name, instance):
- msg = _('Instance is not found..: %s') % instance.name
- raise exception.InstanceNotFound(msg)
-
- LOG.info(_LI('Stopping instance %(instance)s with'
- '%(image)s'), {'instance': instance.name,
- 'image': instance.image_ref})
- # Stop the container
- client = self.get_session(host)
- (state, data) = client.container_stop(instance_name,
- CONF.lxd.timeout)
- self.operation_wait(data.get('operation'), instance)
-
- LOG.info(_LI('Successfully stopped instance %(instance)s with'
- '%(image)s'), {'instance': instance.name,
- 'image': instance.image_ref})
- except lxd_exceptions.APIError as ex:
- msg = _('Failed to communicate with LXD API %(instance)s:'
- ' %(reason)s') % {'instance': instance.name,
- 'reason': ex}
- raise exception.NovaException(msg)
- except Exception as ex:
- with excutils.save_and_reraise_exception():
- LOG.error(
- _LE('Failed to stop container %(instance)s: '
- '%(reason)s'), {'instance': instance_name,
- 'reason': ex})
-
- def container_reboot(self, instance):
- """Reboot a LXD container
-
- :param instance: nova instance object
-
- """
- LOG.debug('container_reboot called for instance', instance=instance)
- try:
- if not self.container_defined(instance.name, instance):
- msg = _('Instance is not found..: %s') % instance.name
- raise exception.InstanceNotFound(msg)
-
- LOG.info(_LI('Rebooting instance %(instance)s with'
- '%(image)s'), {'instance': instance.name,
- 'image': instance.image_ref})
-
- # Container reboot
- client = self.get_session(instance.host)
- (state, data) = client.container_reboot(instance.name,
- CONF.lxd.timeout)
- self.operation_wait(data.get('operation'), instance)
-
- LOG.info(_LI('Successfully rebooted instance %(instance)s with'
- '%(image)s'), {'instance': instance.name,
- 'image': instance.image_ref})
- except lxd_exceptions.APIError as ex:
- msg = _('Failed to communicate with LXD API %(instance)s:'
- ' %(reason)s') % {'instance': instance.name,
- 'reason': ex}
- raise exception.NovaException(msg)
- except Exception as ex:
- with excutils.save_and_reraise_exception():
- LOG.error(
- _LE('Failed to reboot container %(instance)s: '
- '%(reason)s'), {'instance': instance.name,
- 'reason': ex}, instance=instance)
-
- def container_destroy(self, instance_name, host, instance):
- """Destroy a LXD container
-
- :param instance_name: container name
- :param host: container host
- :param instance: nova instance object
-
- """
- LOG.debug('container_destroy for instance', instance=instance)
- try:
- if not self.container_defined(instance_name, instance):
- return
-
- LOG.info(_LI('Destroying instance %(instance)s with'
- '%(image)s'), {'instance': instance.name,
- 'image': instance.image_ref})
-
- # Destroying container
- self.container_stop(instance_name, host, instance)
-
- client = self.get_session(host)
- (state, data) = client.container_destroy(instance_name)
- self.operation_wait(data.get('operation'), instance)
-
- LOG.info(_LI('Successfully destroyed instance %(instance)s with'
- '%(image)s'), {'instance': instance.name,
- 'image': instance.image_ref})
- except lxd_exceptions.APIError as ex:
- msg = _('Failed to communicate with LXD API %(instance)s:'
- ' %(reason)s') % {'instance': instance.name,
- 'reason': ex}
- raise exception.NovaException(msg)
- except Exception as ex:
- with excutils.save_and_reraise_exception():
- LOG.error(_LE('Failed to destroy container %(instance)s: '
- '%(reason)s'), {'instance': instance_name,
- 'reason': ex})
-
- def container_pause(self, instance_name, instance):
- """Pause a LXD container
-
- :param instance_name: container name
- :param instance: nova instance object
-
- """
- LOG.debug('container_paused called for instance', instance=instance)
- try:
- if not self.container_defined(instance_name, instance):
- msg = _('Instance is not found. %s') % instance_name
- raise exception.InstanceNotFound(msg)
-
- LOG.info(_LI('Pausing instance %(instance)s with'
- '%(image)s'), {'instance': instance_name,
- 'image': instance.image_ref})
-
- client = self.get_session(instance.host)
- (state, data) = client.container_suspend(instance_name,
- CONF.lxd.timeout)
- self.operation_wait(data.get('operation'), instance)
-
- LOG.info(_LI('Successfully paused instance %(instance)s with'
- '%(image)s'), {'instance': instance_name,
- 'image': instance.image_ref})
- except lxd_exceptions.APIError as ex:
- msg = _('Failed to communicate with LXD API %(instance)s:'
- ' %(reason)s') % {'instance': instance_name,
- 'reason': ex}
- raise exception.NovaException(msg)
- except Exception as ex:
- with excutils.save_and_reraise_exception():
- LOG.error(
- _LE('Failed to pause container %(instance)s: '
- '%(reason)s'),
- {'instance': instance_name,
- 'reason': ex}, instance=instance)
-
- def container_unpause(self, instance_name, instance):
- """Unpause a LXD container
-
- :param instance_name: container name
- :param instance: nova instance object
-
- """
- LOG.debug('container_unpause called for instance', instance=instance)
- try:
- if not self.container_defined(instance_name, instance):
- msg = _('Instance is not found. %s') % instance_name
- raise exception.InstanceNotFound(msg)
-
- LOG.info(_LI('Unpausing instance %(instance)s with'
- '%(image)s'), {'instance': instance.name,
- 'image': instance.image_ref})
-
- client = self.get_session(instance.host)
- (state, data) = client.container_resume(instance_name,
- CONF.lxd.timeout)
- self.operation_wait(data.get('operation'), instance)
-
- LOG.info(_LI('Successfully unpaused instance %(instance)s with'
- '%(image)s'), {'instance': instance.name,
- 'image': instance.image_ref})
- except lxd_exceptions.APIError as ex:
- msg = _('Failed to communicate with LXD API %(instance)s:'
- ' %(reason)s') % {'instance': instance.name,
- 'reason': ex}
- raise exception.NovaException(msg)
- except Exception as ex:
- with excutils.save_and_reraise_exception():
- LOG.error(
- _LE('Failed to unpause container %(instance)s: '
- '%(reason)s'), {'instance': instance_name,
- 'reason': ex})
-
- def container_init(self, config, instance, host):
- """Create a LXD container
-
- :param config: LXD container config as a dict
- :param instance: nova instance object
- :param host: host to create the container on
-
- """
- LOG.debug('container_init called for instance', instance=instance)
- try:
- LOG.info(_LI('Creating container %(instance)s with'
- '%(image)s'), {'instance': instance.name,
- 'image': instance.image_ref})
-
- client = self.get_session(host)
- (state, data) = client.container_init(config)
- operation = data.get('operation')
- self.operation_wait(operation, instance)
- status, data = self.operation_info(operation, instance)
- data = data.get('metadata')
- if not data['status_code'] == 200:
- raise exception.NovaException(data['metadata'])
-
- LOG.info(_LI('Successfully created container %(instance)s with'
- '%(image)s'), {'instance': instance.name,
- 'image': instance.image_ref})
- except lxd_exceptions.APIError as ex:
- msg = _('Failed to communicate with LXD API %(instance)s:'
- ' %(reason)s') % {'instance': instance.name,
- 'reason': ex}
- raise exception.NovaException(msg)
- except Exception as ex:
- with excutils.save_and_reraise_exception():
- LOG.error(
- _LE('Failed to create container %(instance)s: %(reason)s'),
- {'instance': instance.name,
- 'reason': ex}, instance=instance)
-
- #
- # Image related API methods.
- #
-
- def image_defined(self, instance):
- """Checks existence of an image on the local LXD image store
-
- :param instance: The nova instance
-
- Returns True if supplied image exists on the host, False otherwise
- """
- LOG.debug('image_defined called for instance', instance=instance)
- try:
- client = self.get_session(instance.host)
- return client.alias_defined(instance.image_ref)
- except lxd_exceptions.APIError as ex:
- if ex.status_code == 404:
- return False
- else:
- msg = _('Failed to communicate with LXD API %(instance)s:'
- ' %(reason)s') % {'instance': instance.image_ref,
- 'reason': ex}
- LOG.error(msg)
- raise exception.NovaException(msg)
- except Exception as e:
- with excutils.save_and_reraise_exception():
- LOG.error(_LE('Error from LXD during image_defined '
- '%(instance)s: %(reason)s'),
- {'instance': instance.image_ref, 'reason': e},
- instance=instance)
-
- def create_alias(self, alias, instance):
- """Creates an alias for a given image
-
- :param alias: The alias to be crerated
- :param instance: The nove instnace
- :return: true if alias is created, false otherwise
-
- """
- LOG.debug('create_alias called for instance', instance=instance)
- try:
- client = self.get_session(instance.host)
- return client.alias_create(alias)
- except lxd_exceptions.APIError as ex:
- msg = _('Failed to communicate with LXD API %(instance)s:'
- ' %(reason)s') % {'instance': instance.image_ref,
- 'reason': ex}
- LOG.error(msg)
- raise exception.NovaException(msg)
- except Exception as e:
- with excutils.save_and_reraise_exception():
- LOG.error(_LE('Error from LXD during create alias'
- '%(instance)s: %(reason)s'),
- {'instance': instance.image_ref, 'reason': e},
- instance=instance)
-
- def image_upload(self, data, headers, instance):
- """Upload an image to the local LXD image store
-
- :param data: image data
- :param headers: image headers
- :param intance: The nova instance
-
- """
- LOG.debug('upload_image called for instnace', instance=instance)
- try:
- client = self.get_session(instance.host)
- (state, data) = client.image_upload(data=data,
- headers=headers)
- # XXX - zulcss (Dec 8, 2015) - Work around for older
- # versions of LXD.
- if 'operation' in data:
- self.operation_wait(data.get('operation'), instance)
- except lxd_exceptions.APIError as ex:
- msg = _('Failed to communicate with LXD API %(instance)s:'
- '%(reason)s') % {'instance': instance.image_ref,
- 'reason': ex}
- LOG.error(msg)
- raise exception.NovaException(msg)
- except Exception as e:
- with excutils.save_and_reraise_exception():
- LOG.error(_LE('Error from LXD during image upload'
- '%(instance)s: %(reason)s'),
- {'instance': instance.image_ref, 'reason': e},
- instance=instance)
-
- #
- # Operation methods
- #
-
- def operation_wait(self, operation_id, instance):
- """Waits for an operation to return 200 (Success)
-
- :param operation_id: The operation to wait for.
- """
- LOG.debug('wait_for_contianer for instance', instance=instance)
- try:
- client = self.get_session(instance.host)
- if not client.wait_container_operation(operation_id, 200, -1):
- msg = _('Container creation timed out')
- raise exception.NovaException(msg)
- except lxd_exceptions.APIError as ex:
- msg = _('Failed to communicate with LXD API %(instance)s:'
- '%(reason)s') % {'instance': instance.image_ref,
- 'reason': ex}
- LOG.error(msg)
- raise exception.NovaException(msg)
- except Exception as e:
- with excutils.save_and_reraise_exception():
- LOG.error(_LE('Error from LXD during operation wait'
- '%(instance)s: %(reason)s'),
- {'instance': instance.image_ref, 'reason': e},
- instance=instance)
-
- def operation_info(self, operation_id, instance):
- LOG.debug('operation_info called for instance', instance=instance)
- try:
- client = self.get_session(instance.host)
- return client.operation_info(operation_id)
- except lxd_exceptions.APIError as ex:
- msg = _('Failed to communicate with LXD API %(instance)s:'
- '%(reason)s') % {'instance': instance.image_ref,
- 'reason': ex}
- LOG.error(msg)
- raise exception.NovaException(msg)
- except Exception as e:
- with excutils.save_and_reraise_exception():
- LOG.error(_LE('Error from LXD during operation_info '
- '%(instance)s: %(reason)s'),
- {'instance': instance.image_ref, 'reason': e},
- instance=instance)
-
- #
- # Profile methods
- #
- def profile_defined(self, instance):
- """Validate if the profile is available on the LXD
- host
-
- :param instance: nova instance object
- """
- LOG.debug('profile_defined called for instance',
- instance=instance)
- try:
- client = self.get_session(instance.host)
- client.profile_defined(instance.name)
- except lxd_exceptions.APIError as ex:
- if ex.status_code == 404:
- return False
- else:
- msg = _('Failed to communicate with LXD API %(instance)s:'
- ' %(reason)s') % {'instance': instance.name,
- 'reason': ex}
- raise exception.NovaException(msg)
- except Exception as ex:
- with excutils.save_and_reraise_exception():
- LOG.error(
- _LE('Failed to determine profile %(instance)s:'
- ' %(reason)s'),
- {'instance': instance.name, 'reason': ex})
-
- def profile_create(self, config, instance):
- """Create an LXD container profile
-
- :param config: profile dictionary
- :param instnace: nova instance object
- """
- LOG.debug('profile_create called for instance',
- instance=instance)
- try:
- client = self.get_session(instance.host)
- client.profile_create(config)
- except lxd_exceptions.APIError as ex:
- msg = _('Failed to communicate with LXD API %(instance)s:'
- ' %(reason)s') % {'instance': instance.name,
- 'reason': ex}
- raise exception.NovaException(msg)
- except Exception as ex:
- with excutils.save_and_reraise_exception():
- LOG.error(
- _LE('Failed to create profile %(instance)s: %(reason)s'),
- {'instance': instance.name, 'reason': ex})
-
- def profile_update(self, config, instance):
- """Update an LXD container profile
-
- :param config: LXD profile dictironary
- :param instance: nova instance object
- """
- LOG.debug('profile_udpate called for instance', instance=instance)
- try:
- client = self.get_session(instance.host)
- client.profile_update(instance.name, config)
- except lxd_exceptions.APIError as ex:
- msg = _('Failed to communicate with LXD API %(instance)s:'
- ' %(reason)s') % {'instance': instance.name,
- 'reason': ex}
- raise exception.NovaException(msg)
- except Exception as ex:
- with excutils.save_and_reraise_exception():
- LOG.error(
- _LE('Failed to update profile %(instance)s: '
- '%(reason)s'),
- {'instance': instance.name, 'reason': ex})
-
- def profile_delete(self, instance):
- """Delete a LXD container profile.
-
- :param instance: nova instance object
- """
- LOG.debug('profile_delete called for instance', instance=instance)
- try:
- client = self.get_session(instance.host)
- client.profile_delete(instance.name)
- except lxd_exceptions.APIError as ex:
- msg = _('Failed to communicate with LXD API %(instance)s:'
- ' %(reason)s') % {'instance': instance.name,
- 'reason': ex}
- raise exception.NovaException(msg)
- except Exception as ex:
- with excutils.save_and_reraise_exception():
- LOG.error(
- _LE('Failed to delete profile %(instance)s: %(reason)s'),
- {'instance': instance.name, 'reason': ex})
-
- #
- # Migrate methods
- #
- def container_migrate(self, instance_name, host, instance):
- """Initialize a container migration for LXD
-
- :param instance_name: container name
- :param host: host to move container from
- :param instance: nova instance object
- :return: dictionary of the container keys
-
- """
- LOG.debug('container_migrate called for instance', instance=instance)
- try:
- LOG.info(_LI('Migrating instance %(instance)s with'
- '%(image)s'), {'instance': instance_name,
- 'image': instance.image_ref})
-
- client = self.get_session(host)
- (state, data) = client.container_migrate(instance_name)
-
- LOG.info(_LI('Successfully initialized migration for instance '
- '%(instance)s with %(image)s'),
- {'instance': instance.name,
- 'image': instance.image_ref})
- return (state, data)
- except lxd_exceptions.APIError as ex:
- msg = _('Failed to communicate with LXD API %(instance)s:'
- ' %(reason)s') % {'instance': instance.name,
- 'reason': ex}
- raise exception.NovaException(msg)
- except Exception as ex:
- with excutils.save_and_reraise_exception():
- LOG.error(
- _LE('Failed to migrate container %(instance)s: %('
- 'reason)s'), {'instance': instance.name,
- 'reason': ex}, instance=instance)
-
- #
- # Snapshot methods
- #
-
- def container_move(self, old_name, config, instance):
- """Move a container from one host to another
-
- :param old_name: Old container name
- :param config: Old container config
- :param instance: nova instance object
- :return:
-
- """
- LOG.debug('container_move called for instance', instnace=instance)
- try:
- LOG.info(_LI('Moving container %(instance)s with'
- '%(image)s'), {'instance': instance.name,
- 'image': instance.image_ref})
-
- # Container move
- client = self.get_session(instance.host)
- (state, data) = client.container_local_move(old_name, config)
- self.operation_wait(data.get('operation'), instance)
-
- LOG.info(_LI('Successfully moved container %(instance)s with'
- '%(image)s'), {'instance': instance.name,
- 'image': instance.image_ref})
- except lxd_exceptions.APIError as ex:
- msg = _('Failed to communicate with LXD API %(instance)s:'
- ' %(reason)s') % {'instance': instance.name,
- 'reason': ex}
- raise exception.NovaException(msg)
- except Exception as ex:
- with excutils.save_and_reraise_exception():
- LOG.error(
- _LE('Failed to move container %(instance)s: %('
- 'reason)s'),
- {'instance': instance.name,
- 'reason': ex}, instance=instance)
-
- def container_snapshot(self, snapshot, instance):
- """Snapshot a LXD container
-
- :param snapshot: snapshot config dictionary
- :param instance: nova instance object
-
- """
- LOG.debug('container_snapshot called for instance', instance=instance)
- try:
- LOG.info(_LI('Snapshotting container %(instance)s with '
- '%(image)s'), {'instance': instance.name,
- 'image': instance.image_ref})
-
- # Container snapshot
- client = self.get_session(instance.host)
- (state, data) = client.container_snapshot_create(
- instance.name, snapshot)
- self.operation_wait(data.get('operation'), instance)
-
- LOG.info(_LI('Successfully snapshotted container %(instance)s with'
- '%(image)s'), {'instance': instance.name,
- 'image': instance.image_ref})
- except lxd_exceptions.APIError as ex:
- msg = _('Failed to communicate with LXD API %(instance)s:'
- ' %(reason)s') % {'instance': instance.name,
- 'reason': ex}
- raise exception.NovaException(msg)
- except Exception as ex:
- with excutils.save_and_reraise_exception():
- LOG.error(
- _LE('Failed to snapshot container %(instance)s: '
- '%(reason)s'),
- {'instance': instance.name,
- 'reason': ex}, instance=instance)
-
- def container_publish(self, image, instance):
- """Publish a container to the local LXD image store
-
- :param image: LXD fingerprint
- :param instance: nova instance object
- :return: True if published, False otherwise
-
- """
- LOG.debug('container_publish called for instance', instance=instance)
- try:
- client = self.get_session(instance.host)
- return client.container_publish(image)
- except lxd_exceptions.APIError as ex:
- msg = _('Failed to communicate with LXD API %(instance)s:'
- ' %(reason)s') % {'instance': instance.name,
- 'reason': ex}
- raise exception.NovaException(msg)
- except Exception as ex:
- with excutils.save_and_reraise_exception():
- LOG.error(
- _LE('Failed to publish container %(instance)s: '
- '%(reason)s'),
- {'instance': instance.name,
- 'reason': ex}, instance=instance)
-
- def container_export(self, image, instance):
- """
- Export an image from the local LXD image store into
- an file.
-
- :param image: image dictionary
- :param instance: nova instance object
- """
- LOG.debug('container_export called for instance', instance=instance)
- try:
- client = self.get_session(instance.host)
- return client.image_export(image)
- except lxd_exceptions.APIError as ex:
- msg = _('Failed to export image: %s') % ex
- raise exception.NovaException(msg)
- except Exception as ex:
- with excutils.save_and_reraise_exception():
- LOG.error(
- _LE('Failed to export container %(instance)s: '
- '%(reason)s'),
- {'instance': instance.name,
- 'reason': ex}, instance=instance)
-
- def wait_for_snapshot(self, event_id, instance):
- """Poll snapshot operation for the snapshot to be ready.
-
- :param event_id: operation id
- :param instnace: nova instance object
- """
- LOG.debug('wait_for_snapshot called for instance', instance=instance)
-
- timer = loopingcall.FixedIntervalLoopingCall(self._wait_for_snapshot,
- event_id, instance)
- try:
- timer.start(interval=2).wait()
- except Exception as ex:
- with excutils.save_and_reraise_exception():
- LOG.error(_LE('Failed to create snapshot for %(instance)s: '
- '%(ex)s'), {'instance': instance.name, 'ex': ex},
- instance=instance)
-
- def _wait_for_snapshot(self, event_id, instance):
- """Check the status code of the opeation id.
-
- :param event_id: operation id
- :param instance: nova instance object
- """
- client = self.get_session(instance.host)
- (state, data) = client.operation_info(event_id)
- status_code = data['metadata']['status_code']
-
- if status_code == 200:
- raise loopingcall.LoopingCallDone()
- elif status_code == 400:
- msg = _('Snapshot failed')
- raise exception.NovaException(msg)
diff --git a/nova_lxd/tests/session/test_container.py b/nova_lxd/tests/session/test_container.py
index ac05f4d..431e285 100644
--- a/nova_lxd/tests/session/test_container.py
+++ b/nova_lxd/tests/session/test_container.py
@@ -28,7 +28,7 @@
from nova import test
from pylxd import exceptions as lxd_exceptions
-from nova_lxd.nova.virt.lxd.session import session
+from nova_lxd.nova.virt.lxd import session
from nova_lxd.tests import fake_api
from nova_lxd.tests import stubs
diff --git a/nova_lxd/tests/session/test_event.py b/nova_lxd/tests/session/test_event.py
index b6a3763..f50b879 100644
--- a/nova_lxd/tests/session/test_event.py
+++ b/nova_lxd/tests/session/test_event.py
@@ -18,7 +18,7 @@
from nova import test
-from nova_lxd.nova.virt.lxd.session import session
+from nova_lxd.nova.virt.lxd import session
from nova_lxd.tests import stubs
diff --git a/nova_lxd/tests/session/test_image.py b/nova_lxd/tests/session/test_image.py
index ce43ce8..fa0c6dc 100644
--- a/nova_lxd/tests/session/test_image.py
+++ b/nova_lxd/tests/session/test_image.py
@@ -18,7 +18,7 @@
from nova import test
-from nova_lxd.nova.virt.lxd.session import session
+from nova_lxd.nova.virt.lxd import session
from nova_lxd.tests import stubs
diff --git a/nova_lxd/tests/session/test_migrate.py b/nova_lxd/tests/session/test_migrate.py
index c80ee53..9f96638 100644
--- a/nova_lxd/tests/session/test_migrate.py
+++ b/nova_lxd/tests/session/test_migrate.py
@@ -18,7 +18,7 @@
from nova import test
-from nova_lxd.nova.virt.lxd.session import session
+from nova_lxd.nova.virt.lxd import session
from nova_lxd.tests import stubs
diff --git a/nova_lxd/tests/session/test_snapshot.py b/nova_lxd/tests/session/test_snapshot.py
index c0ff716..a2984d9 100644
--- a/nova_lxd/tests/session/test_snapshot.py
+++ b/nova_lxd/tests/session/test_snapshot.py
@@ -20,7 +20,7 @@
from nova import test
from pylxd import exceptions as lxd_exceptions
-from nova_lxd.nova.virt.lxd.session import session
+from nova_lxd.nova.virt.lxd import session
from nova_lxd.tests import fake_api
from nova_lxd.tests import stubs
diff --git a/nova_lxd/tests/test_container_migration.py b/nova_lxd/tests/test_container_migration.py
index e2659d1..b18ff26 100644
--- a/nova_lxd/tests/test_container_migration.py
+++ b/nova_lxd/tests/test_container_migration.py
@@ -19,7 +19,7 @@
from nova.virt import fake
from nova_lxd.nova.virt.lxd import container_migrate
-from nova_lxd.nova.virt.lxd.session import session
+from nova_lxd.nova.virt.lxd import session
from nova_lxd.tests import stubs
diff --git a/nova_lxd/tests/test_driver_api.py b/nova_lxd/tests/test_driver_api.py
index 6387d43..fa2fc7b 100644
--- a/nova_lxd/tests/test_driver_api.py
+++ b/nova_lxd/tests/test_driver_api.py
@@ -36,7 +36,7 @@
from nova_lxd.nova.virt.lxd import driver
from nova_lxd.nova.virt.lxd import host
from nova_lxd.nova.virt.lxd import operations as container_ops
-from nova_lxd.nova.virt.lxd.session import session
+from nova_lxd.nova.virt.lxd import session
from nova_lxd.nova.virt.lxd import utils as container_dir
from nova_lxd.tests import stubs
diff --git a/nova_lxd/tests/test_image.py b/nova_lxd/tests/test_image.py
index 96cebd4..4d3b8d7 100644
--- a/nova_lxd/tests/test_image.py
+++ b/nova_lxd/tests/test_image.py
@@ -28,7 +28,7 @@
from nova_lxd.nova.virt.lxd import image
-from nova_lxd.nova.virt.lxd.session import session
+from nova_lxd.nova.virt.lxd import session
from nova_lxd.tests import stubs
diff --git a/nova_lxd/tests/test_operations.py b/nova_lxd/tests/test_operations.py
index 3da7a89..378fe3d 100644
--- a/nova_lxd/tests/test_operations.py
+++ b/nova_lxd/tests/test_operations.py
@@ -22,7 +22,7 @@
from nova_lxd.nova.virt.lxd import config
from nova_lxd.nova.virt.lxd import image
from nova_lxd.nova.virt.lxd import operations as container_ops
-from nova_lxd.nova.virt.lxd.session import session
+from nova_lxd.nova.virt.lxd import session
from nova_lxd.tests import stubs
More information about the lxc-devel
mailing list