[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