[lxc-devel] [nova-lxd/master] Migration and resize refactor
zulcss on Github
lxc-bot at linuxcontainers.org
Mon Feb 8 15:26:56 UTC 2016
A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 584 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20160208/7060caf6/attachment.bin>
-------------- next part --------------
From b7a1d24422a21c343b8d2b6340bdf255e8fb6fc4 Mon Sep 17 00:00:00 2001
From: Chuck Short <chuck.short at canonical.com>
Date: Sat, 6 Feb 2016 08:32:30 -0500
Subject: [PATCH 01/15] Rename container migration
Rename container_migration.py and test_container_migration.py
for simplicity, readability, and maintenance.
Signed-off-by: Chuck Short <chuck.short at canonical.com>
---
nova_lxd/nova/virt/lxd/container_migrate.py | 113 ----------------------------
nova_lxd/nova/virt/lxd/driver.py | 4 +-
nova_lxd/nova/virt/lxd/migrate.py | 113 ++++++++++++++++++++++++++++
nova_lxd/tests/test_container_migration.py | 73 ------------------
nova_lxd/tests/test_migrate.py | 73 ++++++++++++++++++
5 files changed, 188 insertions(+), 188 deletions(-)
delete mode 100644 nova_lxd/nova/virt/lxd/container_migrate.py
create mode 100644 nova_lxd/nova/virt/lxd/migrate.py
delete mode 100644 nova_lxd/tests/test_container_migration.py
create mode 100644 nova_lxd/tests/test_migrate.py
diff --git a/nova_lxd/nova/virt/lxd/container_migrate.py b/nova_lxd/nova/virt/lxd/container_migrate.py
deleted file mode 100644
index f55e15b..0000000
--- a/nova_lxd/nova/virt/lxd/container_migrate.py
+++ /dev/null
@@ -1,113 +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 i18n
-
-from oslo_config import cfg
-from oslo_log import log as logging
-
-from nova_lxd.nova.virt.lxd import config
-from nova_lxd.nova.virt.lxd import operations
-from nova_lxd.nova.virt.lxd import session
-
-
-_ = i18n._
-_LE = i18n._LE
-_LI = i18n._LI
-
-CONF = cfg.CONF
-LOG = logging.getLogger(__name__)
-
-
-class LXDContainerMigrate(object):
-
- def __init__(self, virtapi):
- self.virtapi = virtapi
- self.config = config.LXDContainerConfig()
- self.session = session.LXDAPISession()
- self.container_ops = \
- operations.LXDContainerOperations(
- self.virtapi)
-
- def migrate_disk_and_power_off(self, context, instance, dest,
- flavor, network_info,
- block_device_info=None, timeout=0,
- retry_interval=0):
- LOG.debug("migrate_disk_and_power_off called", instance=instance)
-
- LOG.info(_('No disk to migrate'))
-
- # disk_info is not used
- disk_info = {}
- return disk_info
-
- def confirm_migration(self, migration, instance, network_info):
- LOG.debug("confirm_migration called", instance=instance)
-
- def finish_revert_migration(self, context, instance, network_info,
- block_device_info=None, power_on=True):
- LOG.debug("finish_revert_migration called", instance=instance)
- container_config = self.get_container_config(instance)
- self.container_ops.start_container(container_config, instance,
- network_info,
- need_vif_plugged=True)
-
- def finish_migration(self, context, migration, instance, disk_info,
- network_info, image_meta, resize_instance=False,
- block_device_info=None, power_on=True):
- LOG.debug("finish_migration called", instance=instance)
-
- self._migration(migration, instance, network_info)
-
- def _migration(self, migration, instance, network_info):
- # XXX: zul (Jan 4, 2016) - Temporarily disabled due to LXD config
- # change refactor.
- LOG.debug('_migration called for instance', instance=instance)
-
- def live_migration(self, context, instance_ref, dest, post_method,
- recover_method, block_migration=False,
- migrate_data=None):
- LOG.debug("live_migration called", instance=instance_ref)
- post_method(context, instance_ref, dest, block_migration)
-
- def pre_live_migration(self, context, instance, block_device_info,
- network_info):
- LOG.debug("pre_live_migration called", instance=instance)
-
- def post_live_migration(self, context, instance, block_device_info):
- LOG.debug("post_live_migration", instance=instance)
- pass
-
- def post_live_migration_at_destination(self, ctxt, instance_ref,
- network_info, block_migration,
- block_device_info):
- LOG.debug("post_live_migration_at_destination called",
- instance=instance_ref)
-
- def check_can_live_migrate_destination(self, ctxt, instance_ref,
- src_compute_info, dst_compute_info,
- block_migration=False,
- disk_over_commit=False):
- LOG.debug("check_can_live_migrate_destination called", instance_ref)
- return {}
-
- def check_can_live_migrate_destination_cleanup(self, ctxt,
- dest_check_data):
- LOG.debug("check_can_live_migrate_destination_cleanup called")
-
- def check_can_live_migrate_source(self, ctxt, instance_ref,
- dest_check_data):
- LOG.debug("check_can_live_migrate_source called", instance_ref)
- return dest_check_data
diff --git a/nova_lxd/nova/virt/lxd/driver.py b/nova_lxd/nova/virt/lxd/driver.py
index ab8aee4..b701d16 100644
--- a/nova_lxd/nova/virt/lxd/driver.py
+++ b/nova_lxd/nova/virt/lxd/driver.py
@@ -26,9 +26,9 @@
from nova_lxd.nova.virt.lxd import container_firewall
-from nova_lxd.nova.virt.lxd import container_migrate
from nova_lxd.nova.virt.lxd import container_snapshot
from nova_lxd.nova.virt.lxd import host
+from nova_lxd.nova.virt.lxd import migrate
from nova_lxd.nova.virt.lxd import operations as container_ops
from nova_lxd.nova.virt.lxd import vif as lxd_vif
@@ -70,7 +70,7 @@ def __init__(self, virtapi):
self.container_ops = container_ops.LXDContainerOperations(virtapi)
self.container_snapshot = container_snapshot.LXDSnapshot()
self.container_firewall = container_firewall.LXDContainerFirewall()
- self.container_migrate = container_migrate.LXDContainerMigrate(virtapi)
+ self.container_migrate = migrate.LXDContainerMigrate(virtapi)
self.host = host.LXDHost()
def init_host(self, host):
diff --git a/nova_lxd/nova/virt/lxd/migrate.py b/nova_lxd/nova/virt/lxd/migrate.py
new file mode 100644
index 0000000..f55e15b
--- /dev/null
+++ b/nova_lxd/nova/virt/lxd/migrate.py
@@ -0,0 +1,113 @@
+# 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 i18n
+
+from oslo_config import cfg
+from oslo_log import log as logging
+
+from nova_lxd.nova.virt.lxd import config
+from nova_lxd.nova.virt.lxd import operations
+from nova_lxd.nova.virt.lxd import session
+
+
+_ = i18n._
+_LE = i18n._LE
+_LI = i18n._LI
+
+CONF = cfg.CONF
+LOG = logging.getLogger(__name__)
+
+
+class LXDContainerMigrate(object):
+
+ def __init__(self, virtapi):
+ self.virtapi = virtapi
+ self.config = config.LXDContainerConfig()
+ self.session = session.LXDAPISession()
+ self.container_ops = \
+ operations.LXDContainerOperations(
+ self.virtapi)
+
+ def migrate_disk_and_power_off(self, context, instance, dest,
+ flavor, network_info,
+ block_device_info=None, timeout=0,
+ retry_interval=0):
+ LOG.debug("migrate_disk_and_power_off called", instance=instance)
+
+ LOG.info(_('No disk to migrate'))
+
+ # disk_info is not used
+ disk_info = {}
+ return disk_info
+
+ def confirm_migration(self, migration, instance, network_info):
+ LOG.debug("confirm_migration called", instance=instance)
+
+ def finish_revert_migration(self, context, instance, network_info,
+ block_device_info=None, power_on=True):
+ LOG.debug("finish_revert_migration called", instance=instance)
+ container_config = self.get_container_config(instance)
+ self.container_ops.start_container(container_config, instance,
+ network_info,
+ need_vif_plugged=True)
+
+ def finish_migration(self, context, migration, instance, disk_info,
+ network_info, image_meta, resize_instance=False,
+ block_device_info=None, power_on=True):
+ LOG.debug("finish_migration called", instance=instance)
+
+ self._migration(migration, instance, network_info)
+
+ def _migration(self, migration, instance, network_info):
+ # XXX: zul (Jan 4, 2016) - Temporarily disabled due to LXD config
+ # change refactor.
+ LOG.debug('_migration called for instance', instance=instance)
+
+ def live_migration(self, context, instance_ref, dest, post_method,
+ recover_method, block_migration=False,
+ migrate_data=None):
+ LOG.debug("live_migration called", instance=instance_ref)
+ post_method(context, instance_ref, dest, block_migration)
+
+ def pre_live_migration(self, context, instance, block_device_info,
+ network_info):
+ LOG.debug("pre_live_migration called", instance=instance)
+
+ def post_live_migration(self, context, instance, block_device_info):
+ LOG.debug("post_live_migration", instance=instance)
+ pass
+
+ def post_live_migration_at_destination(self, ctxt, instance_ref,
+ network_info, block_migration,
+ block_device_info):
+ LOG.debug("post_live_migration_at_destination called",
+ instance=instance_ref)
+
+ def check_can_live_migrate_destination(self, ctxt, instance_ref,
+ src_compute_info, dst_compute_info,
+ block_migration=False,
+ disk_over_commit=False):
+ LOG.debug("check_can_live_migrate_destination called", instance_ref)
+ return {}
+
+ def check_can_live_migrate_destination_cleanup(self, ctxt,
+ dest_check_data):
+ LOG.debug("check_can_live_migrate_destination_cleanup called")
+
+ def check_can_live_migrate_source(self, ctxt, instance_ref,
+ dest_check_data):
+ LOG.debug("check_can_live_migrate_source called", instance_ref)
+ return dest_check_data
diff --git a/nova_lxd/tests/test_container_migration.py b/nova_lxd/tests/test_container_migration.py
deleted file mode 100644
index b18ff26..0000000
--- a/nova_lxd/tests/test_container_migration.py
+++ /dev/null
@@ -1,73 +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.
-
-import mock
-
-from nova import test
-from nova.virt import fake
-
-from nova_lxd.nova.virt.lxd import container_migrate
-from nova_lxd.nova.virt.lxd import session
-from nova_lxd.tests import stubs
-
-
- at mock.patch.object(container_migrate, 'CONF', stubs.MockConf())
- at mock.patch.object(session, 'CONF', stubs.MockConf())
-class LXDTestContainerMigrate(test.NoDBTestCase):
-
- @mock.patch.object(container_migrate, 'CONF', stubs.MockConf())
- @mock.patch.object(session, 'CONF', stubs.MockConf())
- def setUp(self):
- super(LXDTestContainerMigrate, self).setUp()
-
- self.migrate = container_migrate.LXDContainerMigrate(
- fake.FakeVirtAPI())
-
- @mock.patch.object(session.LXDAPISession, 'container_migrate')
- def test_finish_migration(self, mo):
- context = mock.Mock()
- migration = {'source_compute': 'fake-source',
- 'dest_compute': 'fake-dest'}
- instance = stubs._fake_instance()
- bdevice_info = mock.Mock()
- disk_info = mock.Mock()
- network_info = mock.Mock()
- with test.nested(
- mock.patch.object(session.LXDAPISession,
- 'container_defined'),
- mock.patch.object(session.LXDAPISession,
- 'container_stop'),
- mock.patch.object(session.LXDAPISession,
- 'container_init'),
- ) as (
- container_defined,
- container_stop,
- container_init
- ):
- def side_effect(*args, **kwargs):
- # XXX: rockstar (7 Dec 2015) - This mock is a little greedy,
- # and hits too many interfaces. It should become more specific
- # to the single places it needs to fully mocked. Truthiness of
- # the mock changes in py3.
- if args[0] == 'defined':
- return False
- container_defined.side_effect = side_effect
- self.assertEqual(None,
- (self.migrate.finish_migration(context,
- migration,
- instance,
- disk_info,
- network_info,
- bdevice_info)))
diff --git a/nova_lxd/tests/test_migrate.py b/nova_lxd/tests/test_migrate.py
new file mode 100644
index 0000000..eef74eb
--- /dev/null
+++ b/nova_lxd/tests/test_migrate.py
@@ -0,0 +1,73 @@
+# 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.
+
+import mock
+
+from nova import test
+from nova.virt import fake
+
+from nova_lxd.nova.virt.lxd import migrate
+from nova_lxd.nova.virt.lxd import session
+from nova_lxd.tests import stubs
+
+
+ at mock.patch.object(migrate, 'CONF', stubs.MockConf())
+ at mock.patch.object(session, 'CONF', stubs.MockConf())
+class LXDTestContainerMigrate(test.NoDBTestCase):
+
+ @mock.patch.object(migrate, 'CONF', stubs.MockConf())
+ @mock.patch.object(session, 'CONF', stubs.MockConf())
+ def setUp(self):
+ super(LXDTestContainerMigrate, self).setUp()
+
+ self.migrate = migrate.LXDContainerMigrate(
+ fake.FakeVirtAPI())
+
+ @mock.patch.object(session.LXDAPISession, 'container_migrate')
+ def test_finish_migration(self, mo):
+ context = mock.Mock()
+ migration = {'source_compute': 'fake-source',
+ 'dest_compute': 'fake-dest'}
+ instance = stubs._fake_instance()
+ bdevice_info = mock.Mock()
+ disk_info = mock.Mock()
+ network_info = mock.Mock()
+ with test.nested(
+ mock.patch.object(session.LXDAPISession,
+ 'container_defined'),
+ mock.patch.object(session.LXDAPISession,
+ 'container_stop'),
+ mock.patch.object(session.LXDAPISession,
+ 'container_init'),
+ ) as (
+ container_defined,
+ container_stop,
+ container_init
+ ):
+ def side_effect(*args, **kwargs):
+ # XXX: rockstar (7 Dec 2015) - This mock is a little greedy,
+ # and hits too many interfaces. It should become more specific
+ # to the single places it needs to fully mocked. Truthiness of
+ # the mock changes in py3.
+ if args[0] == 'defined':
+ return False
+ container_defined.side_effect = side_effect
+ self.assertEqual(None,
+ (self.migrate.finish_migration(context,
+ migration,
+ instance,
+ disk_info,
+ network_info,
+ bdevice_info)))
From 20ab69d173a0866a5b217ba6887bab96cd4f3ab4 Mon Sep 17 00:00:00 2001
From: Chuck Short <chuck.short at canonical.com>
Date: Sat, 6 Feb 2016 08:33:53 -0500
Subject: [PATCH 02/15] Implement resize and contianer resource limits
When using containers in production operators do not
want a container to take over a whole host, so LXD
has introduced container resource limits. We implement
the following LXD options, via flavors:
- memory limit
- vcpu limit
- disk limit
- privileged containers
- nested containers
Signed-off-by: Chuck Short <chuck.short at canonical.com>
---
nova_lxd/nova/virt/lxd/config.py | 52 +++++++++++++++++++++++++++++++++++++++
nova_lxd/nova/virt/lxd/migrate.py | 28 ++++++++++++++++++---
2 files changed, 77 insertions(+), 3 deletions(-)
diff --git a/nova_lxd/nova/virt/lxd/config.py b/nova_lxd/nova/virt/lxd/config.py
index 3fb79c9..e158337 100644
--- a/nova_lxd/nova/virt/lxd/config.py
+++ b/nova_lxd/nova/virt/lxd/config.py
@@ -103,6 +103,11 @@ def create_profile(self, instance, network_info):
config['config'] = self._create_config(instance_name, instance)
config['devices'] = self._create_network(instance_name, instance,
network_info)
+
+ # Restrict the size of the "/" disk
+ config['devices'].update(
+ self.configure_container_root(instance))
+
return config
except Exception as ex:
with excutils.save_and_reraise_exception():
@@ -121,10 +126,21 @@ def _create_config(self, instance_name, instance):
try:
config = {}
+ # Update continaer options
+ config.update(self._config_instance_options(config, instance))
+
+ # Set the instance memory limit
mem = instance.memory_mb
if mem >= 0:
config['limits.memory'] = '%sMB' % mem
+
+ # Set the instnace vcpu limit
+ vcpus = instance.flavor.vcpus
+ if vcpus >= 0:
+ config['limits.cpu'] = str(vcpus)
+
+ # Configure the console for the instance
config['raw.lxc'] = 'lxc.console=\n' \
'lxc.cgroup.devices.deny=c 5:1 rwm\n' \
'lxc.console.logfile=%s\n' \
@@ -138,6 +154,42 @@ def _create_config(self, instance_name, instance):
'%(ex)s'), {'instance': instance_name, 'ex': ex},
instance=instance)
+ def _config_instance_options(self, config, instance):
+ LOG.debug('_config_instance_options called for instance', instance=instance)
+
+ # Set the container to autostart when the host reboots
+ config['boot.autostart'] = 'True'
+
+ # Determine if we require a nested container
+ flavor = instance.flavor
+ lxd_nested_allowed = flavor.extra_specs.get('lxd_nested_allowed', False)
+ if lxd_nested_allowed:
+ config['security.nesting'] = 'True'
+
+ # Determine if we require a privileged container
+ lxd_privileged_allowed = flavor.extra_specs.get('lxd_privileged_allowed', False)
+ if lxd_privileged_allowed:
+ config['security.privileged'] = 'True'
+
+ return config
+
+ def configure_container_root(self, instance):
+ LOG.debug('_configure_container_root called for instnace',
+ instance=instance)
+ try:
+ config = {}
+ config['root'] = {'path': '/',
+ 'type': 'disk',
+ 'size': '%sGB' % str(instance.root_gb)
+ }
+ return config
+ except Exception as ex:
+ with excutils.save_and_reraise_exception():
+ LOG.error(_LE('Failed to configure disk for '
+ '%(instance)s: %(ex)s'),
+ {'instance': instance.name, 'ex': ex},
+ instance=instance)
+
def _create_network(self, instance_name, instance, network_info):
"""Create the LXD container network on the host
diff --git a/nova_lxd/nova/virt/lxd/migrate.py b/nova_lxd/nova/virt/lxd/migrate.py
index f55e15b..efc2023 100644
--- a/nova_lxd/nova/virt/lxd/migrate.py
+++ b/nova_lxd/nova/virt/lxd/migrate.py
@@ -17,6 +17,7 @@
from oslo_config import cfg
from oslo_log import log as logging
+from oslo_utils import excutils
from nova_lxd.nova.virt.lxd import config
from nova_lxd.nova.virt.lxd import operations
@@ -28,6 +29,7 @@
_LI = i18n._LI
CONF = cfg.CONF
+CONF.import_opt('my_ip', 'nova.netconf')
LOG = logging.getLogger(__name__)
@@ -47,11 +49,31 @@ def migrate_disk_and_power_off(self, context, instance, dest,
retry_interval=0):
LOG.debug("migrate_disk_and_power_off called", instance=instance)
- LOG.info(_('No disk to migrate'))
+ same_host = False
+ if CONF.my_ip == dest:
+ same_host = True
+ LOG.debug('Migration target is the source host')
+ else:
+ LOG.debug('Migration target host: %s' % dest)
+
+ if not self.session.continer_defined(instance.name, instance):
+ msg = _('Instance is not found.')
+ raise exception.NovaException(msg)
+
+ try:
+ if same_host:
+ container_profile = self.container.create_profile(instnace,
+ network_info)
+ self.session.profile_update(container_profile, instance)
+ except Exception as ex:
+ with excutils.save_and_reraise_exception():
+ LOG.error(_LE('failed to resize container '
+ '%(instance)s: %(ex)s'),
+ {'instance': instance.name, 'ex': ex},
+ instance=instance)
# disk_info is not used
- disk_info = {}
- return disk_info
+ return ""
def confirm_migration(self, migration, instance, network_info):
LOG.debug("confirm_migration called", instance=instance)
From 0e4430bd6ca5835cfca4d19313e0e79d6c8e20f9 Mon Sep 17 00:00:00 2001
From: Chuck Short <chuck.short at canonical.com>
Date: Sat, 6 Feb 2016 09:01:36 -0500
Subject: [PATCH 03/15] Always connect to the unix socket
Except for container_migrate always connect to the
local UNIX socket to use the pylxd API. Nova scheduler
does the right thing with regards to multiple compute hosts.
Signed-off-by: Chuck Short <chuck.short at canonical.com>
---
nova_lxd/nova/virt/lxd/container_snapshot.py | 2 +-
nova_lxd/nova/virt/lxd/operations.py | 11 ++--
nova_lxd/nova/virt/lxd/session.py | 75 +++++++++++++---------------
nova_lxd/tests/session/test_container.py | 15 +++---
4 files changed, 45 insertions(+), 58 deletions(-)
diff --git a/nova_lxd/nova/virt/lxd/container_snapshot.py b/nova_lxd/nova/virt/lxd/container_snapshot.py
index 2be4da9..fb49b6f 100644
--- a/nova_lxd/nova/virt/lxd/container_snapshot.py
+++ b/nova_lxd/nova/virt/lxd/container_snapshot.py
@@ -78,7 +78,7 @@ def snapshot(self, context, instance, image_id, update_task_state):
# We have to stop the container before we can publish the
# image to the local store
self.session.container_stop(instance.name,
- instance.host, instance)
+ instance)
fingerprint = self._save_lxd_image(instance,
image_id)
self.session.container_start(instance.name, instance)
diff --git a/nova_lxd/nova/virt/lxd/operations.py b/nova_lxd/nova/virt/lxd/operations.py
index 2db014e..351b58f 100644
--- a/nova_lxd/nova/virt/lxd/operations.py
+++ b/nova_lxd/nova/virt/lxd/operations.py
@@ -211,7 +211,7 @@ def _setup_container(self, instance_name, instance):
container_config = \
self.config.create_container(instance)
self.session.container_init(
- container_config, instance, instance.host)
+ container_config, instance)
# Start the container
self.session.container_start(instance_name, instance)
@@ -345,7 +345,7 @@ def destroy(self, context, instance, network_info, block_device_info=None,
LOG.debug('destroy called for instance', instance=instance)
try:
self.session.profile_delete(instance)
- self.session.container_destroy(instance.name, instance.host,
+ self.session.container_destroy(instance.name,
instance)
self.cleanup(context, instance, network_info, block_device_info)
except Exception as ex:
@@ -366,7 +366,6 @@ def power_off(self, instance, timeout=0, retry_interval=0):
LOG.debug('power_off called for instance', instance=instance)
try:
self.session.container_stop(instance.name,
- instance.host,
instance)
except Exception as ex:
with excutils.save_and_reraise_exception():
@@ -475,7 +474,7 @@ def rescue(self, context, instance, network_info, image_meta,
raise exception.NovaException(msg)
# Step 1 - Stop the old container
- self.session.container_stop(instance.name, instance.host, instance)
+ self.session.container_stop(instance.name, instance)
# Step 2 - Rename the broken contianer to be rescued
self.session.container_move(instance.name,
@@ -490,8 +489,7 @@ def rescue(self, context, instance, network_info, image_meta,
config = self.config.configure_disk_path(rescue_dir,
'mnt', 'rescue', instance)
container_config['devices'].update(config)
- self.session.container_init(container_config, instance,
- instance.host)
+ self.session.container_init(container_config, instance)
# Step 4 - Start the rescue instance
self.session.container_start(instance.name, instance)
@@ -516,7 +514,6 @@ def unrescue(self, instance, network_info):
# Step 1 - Destory the rescue instance.
self.session.container_destroy(instance.name,
- instance.host,
instance)
# Step 2 - Rename the backup container that
diff --git a/nova_lxd/nova/virt/lxd/session.py b/nova_lxd/nova/virt/lxd/session.py
index e6b6142..83aa33f 100644
--- a/nova_lxd/nova/virt/lxd/session.py
+++ b/nova_lxd/nova/virt/lxd/session.py
@@ -75,12 +75,10 @@ def get_session(self, host=None):
:return: pylxd object
"""
try:
- if host is None:
- conn = api.API()
- elif host == CONF.host:
- conn = api.API()
+ if host:
+ return api.API(host=host)
else:
- conn = api.API(host=host)
+ return api.API()
except Exception as ex:
# notify the compute host that the connection failed
# via an rpc call
@@ -93,8 +91,6 @@ def get_session(self, host=None):
payload)
raise exception.HypervisorUnavailable(host=CONF.host)
- return conn
-
#
# Container related API methods
#
@@ -129,7 +125,7 @@ def container_update(self, config, instance):
"""
LOG.debug('container_update called fo instance', instance=instance)
try:
- client = self.get_session(instance.host)
+ client = self.get_session()
if not self.container_defined(instance.name, instance):
msg = _('Instance is not found..: %s') % instance.name
raise exception.InstanceNotFound(msg)
@@ -157,7 +153,7 @@ def container_running(self, instance):
"""
LOG.debug('container_running for instance', instance=instance)
try:
- client = self.get_session(instance.host)
+ client = self.get_session()
return client.container_running(instance.name)
except lxd_exceptions.APIError as ex:
msg = _('Failed to communicate with LXD API %(instance)s:'
@@ -180,7 +176,7 @@ def container_state(self, instance):
"""
LOG.debug('container_state called for instance', instance=instance)
try:
- client = self.get_session(instance.host)
+ client = self.get_session()
if not self.container_defined(instance.name, instance):
return power_state.NOSTATE
@@ -214,7 +210,7 @@ def container_config(self, instance):
msg = _('Instance is not found.. %s') % instance.name
raise exception.InstanceNotFound(msg)
- client = self.get_session(instance.host)
+ client = self.get_session()
return client.get_container_config(instance.name)
except lxd_exceptions.APIError as ex:
msg = _('Failed to communicate with LXD API %(instance)s:'
@@ -241,7 +237,7 @@ def container_info(self, instance):
msg = _('Instance is not found.. %s') % instance.name
raise exception.InstanceNotFound(msg)
- client = self.get_session(instance.host)
+ client = self.get_session()
return client.container_info(instance.name)
except lxd_exceptions.APIError as ex:
msg = _('Failed to communicate with LXD API %(instance)s:'
@@ -265,7 +261,7 @@ def container_defined(self, instance_name, instance):
"""
LOG.debug('container_defined for instance', instance=instance)
try:
- client = self.get_session(instance.host)
+ client = self.get_session()
return client.container_defined(instance_name)
except lxd_exceptions.APIError as ex:
if ex.status_code == 404:
@@ -293,7 +289,7 @@ def container_start(self, instance_name, instance):
'%(image)s'), {'instance': instance.name,
'image': instance.image_ref})
# Start the container
- client = self.get_session(instance.host)
+ client = self.get_session()
# (chuck): Something wicked could happen between
# container
@@ -320,11 +316,10 @@ def container_start(self, instance_name, instance):
{'instance': instance_name, 'reason': ex},
instance=instance)
- def container_stop(self, instance_name, host, instance):
+ def container_stop(self, instance_name, instance):
"""Stops an LXD container
:param instance_name: instance name
- :param host: host where the container is running
:param instance: nova instance object
"""
@@ -338,7 +333,7 @@ def container_stop(self, instance_name, host, instance):
'%(image)s'), {'instance': instance.name,
'image': instance.image_ref})
# Stop the container
- client = self.get_session(host)
+ client = self.get_session()
(state, data) = client.container_stop(instance_name,
CONF.lxd.timeout)
self.operation_wait(data.get('operation'), instance)
@@ -375,7 +370,7 @@ def container_reboot(self, instance):
'image': instance.image_ref})
# Container reboot
- client = self.get_session(instance.host)
+ client = self.get_session()
(state, data) = client.container_reboot(instance.name,
CONF.lxd.timeout)
self.operation_wait(data.get('operation'), instance)
@@ -395,11 +390,10 @@ def container_reboot(self, instance):
'%(reason)s'), {'instance': instance.name,
'reason': ex}, instance=instance)
- def container_destroy(self, instance_name, host, instance):
+ def container_destroy(self, instance_name, instance):
"""Destroy a LXD container
:param instance_name: container name
- :param host: container host
:param instance: nova instance object
"""
@@ -413,9 +407,9 @@ def container_destroy(self, instance_name, host, instance):
'image': instance.image_ref})
# Destroying container
- self.container_stop(instance_name, host, instance)
+ self.container_stop(instance_name, instance)
- client = self.get_session(host)
+ client = self.get_session()
(state, data) = client.container_destroy(instance_name)
self.operation_wait(data.get('operation'), instance)
@@ -450,7 +444,7 @@ def container_pause(self, instance_name, instance):
'%(image)s'), {'instance': instance_name,
'image': instance.image_ref})
- client = self.get_session(instance.host)
+ client = self.get_session()
(state, data) = client.container_suspend(instance_name,
CONF.lxd.timeout)
self.operation_wait(data.get('operation'), instance)
@@ -488,7 +482,7 @@ def container_unpause(self, instance_name, instance):
'%(image)s'), {'instance': instance.name,
'image': instance.image_ref})
- client = self.get_session(instance.host)
+ client = self.get_session()
(state, data) = client.container_resume(instance_name,
CONF.lxd.timeout)
self.operation_wait(data.get('operation'), instance)
@@ -508,12 +502,11 @@ def container_unpause(self, instance_name, instance):
'%(reason)s'), {'instance': instance_name,
'reason': ex})
- def container_init(self, config, instance, host):
+ def container_init(self, config, instance):
"""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)
@@ -522,7 +515,7 @@ def container_init(self, config, instance, host):
'%(image)s'), {'instance': instance.name,
'image': instance.image_ref})
- client = self.get_session(host)
+ client = self.get_session()
(state, data) = client.container_init(config)
operation = data.get('operation')
self.operation_wait(operation, instance)
@@ -559,7 +552,7 @@ def image_defined(self, instance):
"""
LOG.debug('image_defined called for instance', instance=instance)
try:
- client = self.get_session(instance.host)
+ client = self.get_session()
return client.alias_defined(instance.image_ref)
except lxd_exceptions.APIError as ex:
if ex.status_code == 404:
@@ -587,7 +580,7 @@ def create_alias(self, alias, instance):
"""
LOG.debug('create_alias called for instance', instance=instance)
try:
- client = self.get_session(instance.host)
+ client = self.get_session()
return client.alias_create(alias)
except lxd_exceptions.APIError as ex:
msg = _('Failed to communicate with LXD API %(instance)s:'
@@ -612,7 +605,7 @@ def image_upload(self, data, headers, instance):
"""
LOG.debug('upload_image called for instnace', instance=instance)
try:
- client = self.get_session(instance.host)
+ client = self.get_session()
(state, data) = client.image_upload(data=data,
headers=headers)
# XXX - zulcss (Dec 8, 2015) - Work around for older
@@ -643,7 +636,7 @@ def operation_wait(self, operation_id, instance):
"""
LOG.debug('wait_for_contianer for instance', instance=instance)
try:
- client = self.get_session(instance.host)
+ client = self.get_session()
if not client.wait_container_operation(operation_id, 200, -1):
msg = _('Container creation timed out')
raise exception.NovaException(msg)
@@ -663,7 +656,7 @@ def operation_wait(self, operation_id, instance):
def operation_info(self, operation_id, instance):
LOG.debug('operation_info called for instance', instance=instance)
try:
- client = self.get_session(instance.host)
+ client = self.get_session()
return client.operation_info(operation_id)
except lxd_exceptions.APIError as ex:
msg = _('Failed to communicate with LXD API %(instance)s:'
@@ -690,7 +683,7 @@ def profile_defined(self, instance):
LOG.debug('profile_defined called for instance',
instance=instance)
try:
- client = self.get_session(instance.host)
+ client = self.get_session()
client.profile_defined(instance.name)
except lxd_exceptions.APIError as ex:
if ex.status_code == 404:
@@ -716,7 +709,7 @@ def profile_create(self, config, instance):
LOG.debug('profile_create called for instance',
instance=instance)
try:
- client = self.get_session(instance.host)
+ client = self.get_session()
client.profile_create(config)
except lxd_exceptions.APIError as ex:
msg = _('Failed to communicate with LXD API %(instance)s:'
@@ -737,7 +730,7 @@ def profile_update(self, config, instance):
"""
LOG.debug('profile_udpate called for instance', instance=instance)
try:
- client = self.get_session(instance.host)
+ client = self.get_session()
client.profile_update(instance.name, config)
except lxd_exceptions.APIError as ex:
msg = _('Failed to communicate with LXD API %(instance)s:'
@@ -758,7 +751,7 @@ def profile_delete(self, instance):
"""
LOG.debug('profile_delete called for instance', instance=instance)
try:
- client = self.get_session(instance.host)
+ client = self.get_session()
client.profile_delete(instance.name)
except lxd_exceptions.APIError as ex:
msg = _('Failed to communicate with LXD API %(instance)s:'
@@ -829,7 +822,7 @@ def container_move(self, old_name, config, instance):
'image': instance.image_ref})
# Container move
- client = self.get_session(instance.host)
+ client = self.get_session()
(state, data) = client.container_local_move(old_name, config)
self.operation_wait(data.get('operation'), instance)
@@ -863,7 +856,7 @@ def container_snapshot(self, snapshot, instance):
'image': instance.image_ref})
# Container snapshot
- client = self.get_session(instance.host)
+ client = self.get_session()
(state, data) = client.container_snapshot_create(
instance.name, snapshot)
self.operation_wait(data.get('operation'), instance)
@@ -894,7 +887,7 @@ def container_publish(self, image, instance):
"""
LOG.debug('container_publish called for instance', instance=instance)
try:
- client = self.get_session(instance.host)
+ client = self.get_session()
return client.container_publish(image)
except lxd_exceptions.APIError as ex:
msg = _('Failed to communicate with LXD API %(instance)s:'
@@ -919,7 +912,7 @@ def container_export(self, image, instance):
"""
LOG.debug('container_export called for instance', instance=instance)
try:
- client = self.get_session(instance.host)
+ client = self.get_session()
return client.image_export(image)
except lxd_exceptions.APIError as ex:
msg = _('Failed to export image: %s') % ex
@@ -956,7 +949,7 @@ def _wait_for_snapshot(self, event_id, instance):
:param event_id: operation id
:param instance: nova instance object
"""
- client = self.get_session(instance.host)
+ client = self.get_session()
(state, data) = client.operation_info(event_id)
status_code = data['metadata']['status_code']
diff --git a/nova_lxd/tests/session/test_container.py b/nova_lxd/tests/session/test_container.py
index 431e285..ac68fe2 100644
--- a/nova_lxd/tests/session/test_container.py
+++ b/nova_lxd/tests/session/test_container.py
@@ -327,7 +327,7 @@ def test_container_stop(self, tag, side_effect):
self.ml.container_stop.return_value = side_effect
self.assertEqual(None,
self.session.container_stop(instance.name,
- instance.host, instance))
+ instance))
calls = [mock.call.container_defined(instance.name),
mock.call.container_stop(instance.name, -1),
mock.call.wait_container_operation(
@@ -348,7 +348,7 @@ def test_container_stop_fail(self, tag, side_effect, expected):
self.ml.container_stop.side_effect = side_effect
self.assertRaises(expected,
self.session.container_stop, instance.name,
- instance.host, instance)
+ instance)
@stubs.annotated_data(
('1,', (200, fake_api.fake_operation_info_ok()))
@@ -399,7 +399,6 @@ def test_container_destroy(self, tag, container_defined, side_effect):
self.ml.container_destroy.return_value = side_effect
self.assertEqual(None,
self.session.container_destroy(instance.name,
- instance.host,
instance))
calls = [mock.call.container_defined(instance.name),
mock.call.container_defined(instance.name),
@@ -414,7 +413,6 @@ def test_container_destroy(self, tag, container_defined, side_effect):
self.ml.container_defined.return_value = container_defined
self.assertEqual(None,
self.session.container_destroy(instance.name,
- instance.host,
instance))
calls = [mock.call.container_defined(instance.name)]
self.assertEqual(calls, self.ml.method_calls)
@@ -438,7 +436,7 @@ def test_container_destroy_fail(self, tag, container_defined,
self.ml.container_stop.side_effect = side_effect
self.assertRaises(expected,
self.session.container_destroy, instance.name,
- instance.host, instance)
+ instance)
if test_type == 'fail_destroy':
self.ml.container_defined.return_value = container_defined
self.ml.container_stop.return_value = \
@@ -446,7 +444,7 @@ def test_container_destroy_fail(self, tag, container_defined,
self.ml.container_destroy.side_effect = side_effect
self.assertRaises(expected,
self.session.container_destroy, instance.name,
- instance.host, instance)
+ instance)
@stubs.annotated_data(
('1', (200, fake_api.fake_operation_info_ok()))
@@ -536,8 +534,7 @@ def test_container_init(self, tag, side_effect):
self.ml.operation_info.return_value = \
(200, fake_api.fake_container_state(200))
self.assertEqual(None,
- self.session.container_init(config, instance,
- instance.host))
+ self.session.container_init(config, instance))
calls = [mock.call.container_init(config),
mock.call.wait_container_operation(
'/1.0/operation/1234', 200, -1),
@@ -559,4 +556,4 @@ def test_container_init_fail(self, tag, side_effect, expected):
self.ml.container_init.side_effect = side_effect
self.assertRaises(expected,
self.session.container_init, config,
- instance, instance.host)
+ instance)
From 58cbd3c1ec073046830735d056bd59a4f522ac81 Mon Sep 17 00:00:00 2001
From: Chuck Short <chuck.short at canonical.com>
Date: Sat, 6 Feb 2016 09:04:29 -0500
Subject: [PATCH 04/15] Cleanup log messages
Signed-off-by: Chuck Short <chuck.short at canonical.com>
---
nova_lxd/nova/virt/lxd/session.py | 56 +++++++++++++++++++--------------------
1 file changed, 28 insertions(+), 28 deletions(-)
diff --git a/nova_lxd/nova/virt/lxd/session.py b/nova_lxd/nova/virt/lxd/session.py
index 83aa33f..c03584a 100644
--- a/nova_lxd/nova/virt/lxd/session.py
+++ b/nova_lxd/nova/virt/lxd/session.py
@@ -127,7 +127,7 @@ def container_update(self, config, instance):
try:
client = self.get_session()
if not self.container_defined(instance.name, instance):
- msg = _('Instance is not found..: %s') % instance.name
+ msg = _('Instance is not found: %s') % instance.name
raise exception.InstanceNotFound(msg)
return client.container_update(instance.name,
@@ -207,7 +207,7 @@ def container_config(self, instance):
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
+ msg = _('Instance is not found %s') % instance.name
raise exception.InstanceNotFound(msg)
client = self.get_session()
@@ -234,7 +234,7 @@ def container_info(self, instance):
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
+ msg = _('Instance is not found %s') % instance.name
raise exception.InstanceNotFound(msg)
client = self.get_session()
@@ -294,7 +294,7 @@ def container_start(self, instance_name, instance):
# (chuck): Something wicked could happen between
# container
if not self.container_defined(instance_name, instance):
- msg = _('Instance is not found.. %s ') % instance.name
+ msg = _('Instance is not found %s ') % instance.name
raise exception.InstanceNotFound(msg)
(state, data) = client.container_start(instance_name,
@@ -302,7 +302,7 @@ def container_start(self, instance_name, instance):
self.operation_wait(data.get('operation'), instance)
LOG.info(_LI('Successfully started instance %(instance)s with'
- '%(image)s'), {'instance': instance.name,
+ ' %(image)s'), {'instance': instance.name,
'image': instance.image_ref})
except lxd_exceptions.APIError as ex:
msg = _('Failed to communicate with LXD API %(instance)s:'
@@ -326,11 +326,11 @@ def container_stop(self, instance_name, instance):
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
+ 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)s'), {'instance': instance.name,
'image': instance.image_ref})
# Stop the container
client = self.get_session()
@@ -339,7 +339,7 @@ def container_stop(self, instance_name, instance):
self.operation_wait(data.get('operation'), instance)
LOG.info(_LI('Successfully stopped instance %(instance)s with'
- '%(image)s'), {'instance': instance.name,
+ ' %(image)s'), {'instance': instance.name,
'image': instance.image_ref})
except lxd_exceptions.APIError as ex:
msg = _('Failed to communicate with LXD API %(instance)s:'
@@ -362,11 +362,11 @@ def container_reboot(self, instance):
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
+ 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)s'), {'instance': instance.name,
'image': instance.image_ref})
# Container reboot
@@ -376,7 +376,7 @@ def container_reboot(self, instance):
self.operation_wait(data.get('operation'), instance)
LOG.info(_LI('Successfully rebooted instance %(instance)s with'
- '%(image)s'), {'instance': instance.name,
+ ' %(image)s'), {'instance': instance.name,
'image': instance.image_ref})
except lxd_exceptions.APIError as ex:
msg = _('Failed to communicate with LXD API %(instance)s:'
@@ -403,7 +403,7 @@ def container_destroy(self, instance_name, instance):
return
LOG.info(_LI('Destroying instance %(instance)s with'
- '%(image)s'), {'instance': instance.name,
+ ' %(image)s'), {'instance': instance.name,
'image': instance.image_ref})
# Destroying container
@@ -414,7 +414,7 @@ def container_destroy(self, instance_name, instance):
self.operation_wait(data.get('operation'), instance)
LOG.info(_LI('Successfully destroyed instance %(instance)s with'
- '%(image)s'), {'instance': instance.name,
+ ' %(image)s'), {'instance': instance.name,
'image': instance.image_ref})
except lxd_exceptions.APIError as ex:
msg = _('Failed to communicate with LXD API %(instance)s:'
@@ -437,11 +437,11 @@ def container_pause(self, instance_name, instance):
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
+ 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)s'), {'instance': instance_name,
'image': instance.image_ref})
client = self.get_session()
@@ -450,7 +450,7 @@ def container_pause(self, instance_name, instance):
self.operation_wait(data.get('operation'), instance)
LOG.info(_LI('Successfully paused instance %(instance)s with'
- '%(image)s'), {'instance': instance_name,
+ ' %(image)s'), {'instance': instance_name,
'image': instance.image_ref})
except lxd_exceptions.APIError as ex:
msg = _('Failed to communicate with LXD API %(instance)s:'
@@ -475,11 +475,11 @@ def container_unpause(self, instance_name, instance):
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
+ 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)s'), {'instance': instance.name,
'image': instance.image_ref})
client = self.get_session()
@@ -488,7 +488,7 @@ def container_unpause(self, instance_name, instance):
self.operation_wait(data.get('operation'), instance)
LOG.info(_LI('Successfully unpaused instance %(instance)s with'
- '%(image)s'), {'instance': instance.name,
+ ' %(image)s'), {'instance': instance.name,
'image': instance.image_ref})
except lxd_exceptions.APIError as ex:
msg = _('Failed to communicate with LXD API %(instance)s:'
@@ -512,7 +512,7 @@ def container_init(self, config, instance):
LOG.debug('container_init called for instance', instance=instance)
try:
LOG.info(_LI('Creating container %(instance)s with'
- '%(image)s'), {'instance': instance.name,
+ ' %(image)s'), {'instance': instance.name,
'image': instance.image_ref})
client = self.get_session()
@@ -525,7 +525,7 @@ def container_init(self, config, instance):
raise exception.NovaException(data['metadata'])
LOG.info(_LI('Successfully created container %(instance)s with'
- '%(image)s'), {'instance': instance.name,
+ ' %(image)s'), {'instance': instance.name,
'image': instance.image_ref})
except lxd_exceptions.APIError as ex:
msg = _('Failed to communicate with LXD API %(instance)s:'
@@ -660,7 +660,7 @@ def operation_info(self, operation_id, instance):
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)s') % {'instance': instance.image_ref,
'reason': ex}
LOG.error(msg)
raise exception.NovaException(msg)
@@ -778,7 +778,7 @@ def container_migrate(self, instance_name, host, instance):
"""
LOG.debug('container_migrate called for instance', instance=instance)
try:
- LOG.info(_LI('Migrating instance %(instance)s with'
+ LOG.info(_LI('Migrating instance %(instance)s with '
'%(image)s'), {'instance': instance_name,
'image': instance.image_ref})
@@ -817,7 +817,7 @@ def container_move(self, old_name, config, instance):
"""
LOG.debug('container_move called for instance', instnace=instance)
try:
- LOG.info(_LI('Moving container %(instance)s with'
+ LOG.info(_LI('Moving container %(instance)s with '
'%(image)s'), {'instance': instance.name,
'image': instance.image_ref})
@@ -826,7 +826,7 @@ def container_move(self, old_name, config, instance):
(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'
+ LOG.info(_LI('Successfully moved container %(instance)s with '
'%(image)s'), {'instance': instance.name,
'image': instance.image_ref})
except lxd_exceptions.APIError as ex:
@@ -837,8 +837,8 @@ def container_move(self, old_name, config, instance):
except Exception as ex:
with excutils.save_and_reraise_exception():
LOG.error(
- _LE('Failed to move container %(instance)s: %('
- 'reason)s'),
+ _LE('Failed to move container %(instance)s: '
+ '%(reason)s'),
{'instance': instance.name,
'reason': ex}, instance=instance)
@@ -862,7 +862,7 @@ def container_snapshot(self, snapshot, instance):
self.operation_wait(data.get('operation'), instance)
LOG.info(_LI('Successfully snapshotted container %(instance)s with'
- '%(image)s'), {'instance': instance.name,
+ ' %(image)s'), {'instance': instance.name,
'image': instance.image_ref})
except lxd_exceptions.APIError as ex:
msg = _('Failed to communicate with LXD API %(instance)s:'
From 0650e7d16ead918af2718e5cf19f5b354163a79a Mon Sep 17 00:00:00 2001
From: Chuck Short <chuck.short at canonical.com>
Date: Sat, 6 Feb 2016 09:07:01 -0500
Subject: [PATCH 05/15] Remove unimplemented methods
Remove unimplemented methods so that the code
is easier to read.
Signed-off-by: Chuck Short <chuck.short at canonical.com>
---
nova_lxd/nova/virt/lxd/driver.py | 17 +++----------
nova_lxd/nova/virt/lxd/migrate.py | 51 ---------------------------------------
2 files changed, 4 insertions(+), 64 deletions(-)
diff --git a/nova_lxd/nova/virt/lxd/driver.py b/nova_lxd/nova/virt/lxd/driver.py
index b701d16..f0bbe54 100644
--- a/nova_lxd/nova/virt/lxd/driver.py
+++ b/nova_lxd/nova/virt/lxd/driver.py
@@ -232,31 +232,22 @@ def get_available_resource(self, nodename):
def pre_live_migration(self, context, instance, block_device_info,
network_info, disk_info, migrate_data=None):
- return self.container_migrate.pre_live_migration(
- context, instance, block_device_info,
- network_info)
+ raise NotImplementedError()
def live_migration(self, context, instance, dest,
post_method, recover_method, block_migration=False,
migrate_data=None):
- return self.container_migrate.live_migration(context, instance, dest,
- post_method,
- recover_method,
- block_migration,
- migrate_data)
+ raise NotImplementedError()
def post_live_migration(self, context, instance, block_device_info,
migrate_data=None):
- return self.container_migrate.post_live_migration(context, instance,
- block_device_info)
+ raise NotImplementedError()
def post_live_migration_at_destination(self, context, instance,
network_info,
block_migration=False,
block_device_info=None):
- return self.container_migrate.post_live_migration_at_destination(
- context, instance, network_info, block_migration,
- block_device_info)
+ raise NotImplementedError()
def check_instance_shared_storage_local(self, context, instance):
raise NotImplementedError()
diff --git a/nova_lxd/nova/virt/lxd/migrate.py b/nova_lxd/nova/virt/lxd/migrate.py
index efc2023..21bc5b7 100644
--- a/nova_lxd/nova/virt/lxd/migrate.py
+++ b/nova_lxd/nova/virt/lxd/migrate.py
@@ -78,58 +78,7 @@ def migrate_disk_and_power_off(self, context, instance, dest,
def confirm_migration(self, migration, instance, network_info):
LOG.debug("confirm_migration called", instance=instance)
- def finish_revert_migration(self, context, instance, network_info,
- block_device_info=None, power_on=True):
- LOG.debug("finish_revert_migration called", instance=instance)
- container_config = self.get_container_config(instance)
- self.container_ops.start_container(container_config, instance,
- network_info,
- need_vif_plugged=True)
-
def finish_migration(self, context, migration, instance, disk_info,
network_info, image_meta, resize_instance=False,
block_device_info=None, power_on=True):
LOG.debug("finish_migration called", instance=instance)
-
- self._migration(migration, instance, network_info)
-
- def _migration(self, migration, instance, network_info):
- # XXX: zul (Jan 4, 2016) - Temporarily disabled due to LXD config
- # change refactor.
- LOG.debug('_migration called for instance', instance=instance)
-
- def live_migration(self, context, instance_ref, dest, post_method,
- recover_method, block_migration=False,
- migrate_data=None):
- LOG.debug("live_migration called", instance=instance_ref)
- post_method(context, instance_ref, dest, block_migration)
-
- def pre_live_migration(self, context, instance, block_device_info,
- network_info):
- LOG.debug("pre_live_migration called", instance=instance)
-
- def post_live_migration(self, context, instance, block_device_info):
- LOG.debug("post_live_migration", instance=instance)
- pass
-
- def post_live_migration_at_destination(self, ctxt, instance_ref,
- network_info, block_migration,
- block_device_info):
- LOG.debug("post_live_migration_at_destination called",
- instance=instance_ref)
-
- def check_can_live_migrate_destination(self, ctxt, instance_ref,
- src_compute_info, dst_compute_info,
- block_migration=False,
- disk_over_commit=False):
- LOG.debug("check_can_live_migrate_destination called", instance_ref)
- return {}
-
- def check_can_live_migrate_destination_cleanup(self, ctxt,
- dest_check_data):
- LOG.debug("check_can_live_migrate_destination_cleanup called")
-
- def check_can_live_migrate_source(self, ctxt, instance_ref,
- dest_check_data):
- LOG.debug("check_can_live_migrate_source called", instance_ref)
- return dest_check_data
From 2d19ea2d7c338f210bc0d99aa55273f1523f68c2 Mon Sep 17 00:00:00 2001
From: Chuck Short <chuck.short at canonical.com>
Date: Sat, 6 Feb 2016 09:11:45 -0500
Subject: [PATCH 06/15] Make sure profiles exist
Make sure LXD profiles exist or not
before running operations that need a profile.
Signed-off-by: Chuck Short <chuck.short at canonical.com>
---
nova_lxd/nova/virt/lxd/session.py | 41 +++++++++++++++++++++++++++++++++------
1 file changed, 35 insertions(+), 6 deletions(-)
diff --git a/nova_lxd/nova/virt/lxd/session.py b/nova_lxd/nova/virt/lxd/session.py
index c03584a..0c76957 100644
--- a/nova_lxd/nova/virt/lxd/session.py
+++ b/nova_lxd/nova/virt/lxd/session.py
@@ -674,7 +674,23 @@ def operation_info(self, operation_id, instance):
#
# Profile methods
#
- def profile_defined(self, instance):
+ def profile_list(self):
+ LOG.debug('profile_list called for instance')
+ try:
+ client = self.get_session()
+ return client.profile_list()
+ except lxd_exceptions.APIError as ex:
+ msg = _('Failed to communicate with LXD API: %(reason)s') \
+ % {'reason': ex}
+ LOG.error(msg)
+ raise excpetion.NovaException(msg)
+ except Exception as ex:
+ with excutils.save_and_reraise_exception():
+ LOG.error(_LE('Error from LXD during profile_list: '
+ '%(reason)s') % {'reason': ex})
+
+
+ def profile_defined(self, instance_name, instance):
"""Validate if the profile is available on the LXD
host
@@ -683,8 +699,10 @@ def profile_defined(self, instance):
LOG.debug('profile_defined called for instance',
instance=instance)
try:
- client = self.get_session()
- client.profile_defined(instance.name)
+ found = False
+ if instance_name in self.profile_list():
+ found = True
+ return found
except lxd_exceptions.APIError as ex:
if ex.status_code == 404:
return False
@@ -709,8 +727,12 @@ def profile_create(self, config, instance):
LOG.debug('profile_create called for instance',
instance=instance)
try:
+ if self.profile_defined(instance.name, instance):
+ msg = _('Profile already exists %s' % instance.name)
+ raise exception.NovaException(msg)
+
client = self.get_session()
- client.profile_create(config)
+ return client.profile_create(config)
except lxd_exceptions.APIError as ex:
msg = _('Failed to communicate with LXD API %(instance)s:'
' %(reason)s') % {'instance': instance.name,
@@ -730,8 +752,12 @@ def profile_update(self, config, instance):
"""
LOG.debug('profile_udpate called for instance', instance=instance)
try:
+ if not self.profile_defined(instance.name, instance):
+ msg = _('Profile not found %s' % instance.name)
+ raise exception.NovaException(msg)
+
client = self.get_session()
- client.profile_update(instance.name, config)
+ return 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,
@@ -751,8 +777,11 @@ def profile_delete(self, instance):
"""
LOG.debug('profile_delete called for instance', instance=instance)
try:
+ if not self.profile_defined(instance.name, instance):
+ return
+
client = self.get_session()
- client.profile_delete(instance.name)
+ return 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,
From a74228232444a80a684694d55dfb2c9019e15a44 Mon Sep 17 00:00:00 2001
From: Chuck Short <chuck.short at canonical.com>
Date: Sat, 6 Feb 2016 17:02:40 -0500
Subject: [PATCH 07/15] Make functions non-private
Make functions non-private so that we can use them
for container migration.
Signed-off-by: Chuck Short <chuck.short at canonical.com>
---
nova_lxd/nova/virt/lxd/config.py | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/nova_lxd/nova/virt/lxd/config.py b/nova_lxd/nova/virt/lxd/config.py
index e158337..3beffc3 100644
--- a/nova_lxd/nova/virt/lxd/config.py
+++ b/nova_lxd/nova/virt/lxd/config.py
@@ -60,7 +60,7 @@ def create_container(self, instance):
container_config = {
'name': instance_name,
'profiles': [str(instance.name)],
- 'source': self._get_container_source(instance),
+ 'source': self.get_container_source(instance),
'devices': {}
}
@@ -100,8 +100,8 @@ def create_profile(self, instance, network_info):
try:
config = {}
config['name'] = str(instance_name)
- config['config'] = self._create_config(instance_name, instance)
- config['devices'] = self._create_network(instance_name, instance,
+ config['config'] = self.create_config(instance_name, instance)
+ config['devices'] = self.create_network(instance_name, instance,
network_info)
# Restrict the size of the "/" disk
@@ -115,7 +115,7 @@ def create_profile(self, instance, network_info):
_LE('Failed to create profile %(instance)s: %(ex)s'),
{'instance': instance_name, 'ex': ex}, instance=instance)
- def _create_config(self, instance_name, instance):
+ def create_config(self, instance_name, instance):
"""Create the LXD container resources
:param instance_name: instance name
@@ -127,7 +127,7 @@ def _create_config(self, instance_name, instance):
config = {}
# Update continaer options
- config.update(self._config_instance_options(config, instance))
+ config.update(self.config_instance_options(config, instance))
# Set the instance memory limit
mem = instance.memory_mb
@@ -154,7 +154,7 @@ def _create_config(self, instance_name, instance):
'%(ex)s'), {'instance': instance_name, 'ex': ex},
instance=instance)
- def _config_instance_options(self, config, instance):
+ def config_instance_options(self, config, instance):
LOG.debug('_config_instance_options called for instance', instance=instance)
# Set the container to autostart when the host reboots
@@ -219,7 +219,7 @@ def _create_network(self, instance_name, instance, network_info):
_LE('Fail to configure network for %(instance)s: %(ex)s'),
{'instance': instance_name, 'ex': ex}, instance=instance)
- def _get_container_source(self, instance):
+ def get_container_source(self, instance):
"""Set the LXD container image for the instance.
:param instance: nova instance object
@@ -283,7 +283,7 @@ def create_container_net_device(self, instance, vif):
network_config = self.vif_driver.get_config(instance, vif)
config = {}
- config[self._get_network_device(instance)] = {
+ config[self.get_network_device(instance)] = {
'nictype': 'bridged',
'hwaddr': str(vif['address']),
'parent': str(network_config['bridge']),
@@ -296,7 +296,7 @@ def create_container_net_device(self, instance, vif):
{'instance': instance.name, 'ex': ex},
instance=instance)
- def _get_network_device(self, instance):
+ def get_network_device(self, instance):
"""Try to detect which network interfaces are available in a contianer
:param instnace: nova instance object
From 9bc25286bfd5778729b4ea89958980632383e6f2 Mon Sep 17 00:00:00 2001
From: Chuck Short <chuck.short at canonical.com>
Date: Sat, 6 Feb 2016 17:09:16 -0500
Subject: [PATCH 08/15] Add finish_revert_migration
Add the ability to start the container if migration fails.
Signed-off-by: Chuck Short <chuck.short at canonical.com>
---
nova_lxd/nova/virt/lxd/driver.py | 6 ++++++
nova_lxd/nova/virt/lxd/migrate.py | 8 ++++++++
2 files changed, 14 insertions(+)
diff --git a/nova_lxd/nova/virt/lxd/driver.py b/nova_lxd/nova/virt/lxd/driver.py
index f0bbe54..df3ae2e 100644
--- a/nova_lxd/nova/virt/lxd/driver.py
+++ b/nova_lxd/nova/virt/lxd/driver.py
@@ -194,6 +194,12 @@ def confirm_migration(self, migration, instance, network_info):
instance,
network_info)
+ def finish_revert_migration(self, context, instance, network_info,
+ block_device_info=None, power_on=True):
+ return self.container_migrate.finish_revert_migration(context,
+ instance, network_info, block_device_info,
+ power_on)
+
def pause(self, instance):
self.container_ops.pause(instance)
diff --git a/nova_lxd/nova/virt/lxd/migrate.py b/nova_lxd/nova/virt/lxd/migrate.py
index 21bc5b7..fe54260 100644
--- a/nova_lxd/nova/virt/lxd/migrate.py
+++ b/nova_lxd/nova/virt/lxd/migrate.py
@@ -82,3 +82,11 @@ def finish_migration(self, context, migration, instance, disk_info,
network_info, image_meta, resize_instance=False,
block_device_info=None, power_on=True):
LOG.debug("finish_migration called", instance=instance)
+
+ def finish_revert_migration(self, context, instance, network_info,
+ block_device_info=None, power_on=True):
+ LOG.debug('finish_revert_migration called for instance',
+ instance=instance)
+ if self.session.container_defined(instance.name, instance):
+ self.session.container_start(instance.name, instance)
+
From 9740282129eb4c608409c31f1179e6f511417609 Mon Sep 17 00:00:00 2001
From: Chuck Short <chuck.short at canonical.com>
Date: Sat, 6 Feb 2016 17:12:08 -0500
Subject: [PATCH 09/15] Fix typos
Signed-off-by: Chuck Short <chuck.short at canonical.com>
---
nova_lxd/nova/virt/lxd/migrate.py | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/nova_lxd/nova/virt/lxd/migrate.py b/nova_lxd/nova/virt/lxd/migrate.py
index fe54260..95bbc18 100644
--- a/nova_lxd/nova/virt/lxd/migrate.py
+++ b/nova_lxd/nova/virt/lxd/migrate.py
@@ -13,6 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
+from nova import exception
from nova import i18n
from oslo_config import cfg
@@ -56,14 +57,14 @@ def migrate_disk_and_power_off(self, context, instance, dest,
else:
LOG.debug('Migration target host: %s' % dest)
- if not self.session.continer_defined(instance.name, instance):
+ if not self.session.container_defined(instance.name, instance):
msg = _('Instance is not found.')
raise exception.NovaException(msg)
try:
if same_host:
- container_profile = self.container.create_profile(instnace,
- network_info)
+ container_profile = self.config.create_profile(instance,
+ network_info)
self.session.profile_update(container_profile, instance)
except Exception as ex:
with excutils.save_and_reraise_exception():
From 47db5b460d67cab0bd386727e4f1906d3b38dacf Mon Sep 17 00:00:00 2001
From: Chuck Short <chuck.short at canonical.com>
Date: Sat, 6 Feb 2016 17:25:24 -0500
Subject: [PATCH 10/15] Refactor migration support
Refactor container migration support.
Signed-off-by: Chuck Short <chuck.short at canonical.com>
---
nova_lxd/nova/virt/lxd/config.py | 37 +++++++++++++++++++---
nova_lxd/nova/virt/lxd/migrate.py | 65 ++++++++++++++++++++++++++++++++++++++-
2 files changed, 97 insertions(+), 5 deletions(-)
diff --git a/nova_lxd/nova/virt/lxd/config.py b/nova_lxd/nova/virt/lxd/config.py
index 3beffc3..de4864d 100644
--- a/nova_lxd/nova/virt/lxd/config.py
+++ b/nova_lxd/nova/virt/lxd/config.py
@@ -243,6 +243,39 @@ def get_container_source(self, instance):
{'instance': instance.name, 'ex': ex},
instance=instance)
+ def get_container_migrate(self, container_migrate, migration, instance):
+ LOG.debug('get_container_migrate called for instance',
+ instnace=instance)
+ try:
+ # Generate the container config
+ container_metadata =container_migrate['metadata']
+ container_control = container_metadata['metadata']['control']
+ container_fs = container_metadata['metadata']['fs']
+
+ container_url = ('wss://%s:8443%s/websocket'
+ % (migration['source_compute'],
+ container_migrate.get('operation')))
+
+ container_migrate = {
+ 'base_iamge': '',
+ 'mode': 'pull',
+ 'operation': str(container_url),
+ 'secrets': {
+ 'control': str(container_control),
+ 'fs': str(container_fs)
+ },
+ 'type': 'migration'
+ }
+
+ LOG.debug(pprint.pprint(container_migrate))
+ return container_migrate
+ except Exception as ex:
+ with excutils.save_and_reraise_exception():
+ LOG.error(_LE('Failed to configure migation source '
+ '%(instance)s: %(ex)s'),
+ {'instance': instance.name, 'ex': ex},
+ instance=instance)
+
def configure_disk_path(self, src_path, dest_path, vfs_type, instance):
"""Configure the host mount point for the LXD container
@@ -255,10 +288,6 @@ def configure_disk_path(self, src_path, dest_path, vfs_type, instance):
LOG.debug('configure_disk_path called for instance',
instance=instance)
try:
- if not os.path.exists(src_path):
- msg = _('Source path does not exist')
- raise exception.NovaException(msg)
-
config = {}
config[vfs_type] = {'path': dest_path,
'source': src_path,
diff --git a/nova_lxd/nova/virt/lxd/migrate.py b/nova_lxd/nova/virt/lxd/migrate.py
index 95bbc18..5a0b7fc 100644
--- a/nova_lxd/nova/virt/lxd/migrate.py
+++ b/nova_lxd/nova/virt/lxd/migrate.py
@@ -13,15 +13,21 @@
# License for the specific language governing permissions and limitations
# under the License.
+import os
+import pprint
+import shutil
+
from nova import exception
from nova import i18n
from oslo_config import cfg
from oslo_log import log as logging
from oslo_utils import excutils
+from oslo_utils import fileutils
from nova_lxd.nova.virt.lxd import config
from nova_lxd.nova.virt.lxd import operations
+from nova_lxd.nova.virt.lxd import utils as container_dir
from nova_lxd.nova.virt.lxd import session
@@ -39,8 +45,9 @@ class LXDContainerMigrate(object):
def __init__(self, virtapi):
self.virtapi = virtapi
self.config = config.LXDContainerConfig()
+ self.container_dir = container_dir.LXDContainerDirectories()
self.session = session.LXDAPISession()
- self.container_ops = \
+ self.operations = \
operations.LXDContainerOperations(
self.virtapi)
@@ -66,6 +73,8 @@ def migrate_disk_and_power_off(self, context, instance, dest,
container_profile = self.config.create_profile(instance,
network_info)
self.session.profile_update(container_profile, instance)
+ else:
+ self.session.container_stop(instance.name, instance)
except Exception as ex:
with excutils.save_and_reraise_exception():
LOG.error(_LE('failed to resize container '
@@ -79,11 +88,65 @@ def migrate_disk_and_power_off(self, context, instance, dest,
def confirm_migration(self, migration, instance, network_info):
LOG.debug("confirm_migration called", instance=instance)
+ if not self.session.container_defined(instance.name, instance):
+ msg = _('Failed to find container %s' % instance.name)
+ raise exception.NovaException(msg)
+
+ try:
+ self.session.profile_delete(instance)
+ self.session.container_destroy(instance.name,
+ instance)
+ self.operations.unplug_vifs(instance, network_info)
+ container_dir = self.container_dir.get_instance_dir(instance.name)
+ if os.path.exists(container_dir):
+ shutil.rmtree(container_dir)
+ except Exception as ex:
+ with excutils.save_and_reraise_exception():
+ LOG.exception(_LE('Confirm migration failed for %(instnace)s: '
+ '%(ex)s'), {'instance': instance.name,
+ 'ex': ex}, instance=instance)
+
def finish_migration(self, context, migration, instance, disk_info,
network_info, image_meta, resize_instance=False,
block_device_info=None, power_on=True):
LOG.debug("finish_migration called", instance=instance)
+ if self.session.container_defined(instance.name, instance):
+ msg = _('Failed to find container %s' % instance.name)
+ raise exception.NovaException(msg)
+
+ try:
+ # Ensure that the instance directory exists
+ instance_dir = \
+ self.container_dir.get_instance_dir(instance.name)
+ if not os.path.exists(instance_dir):
+ fileutils.ensure_tree(instance_dir)
+
+ # Step 1 - Setup the profile on the dest host
+ container_profile = self.config.create_profile(instance,
+ network_info)
+ self.session.profile_create(container_profile, instance)
+
+ # Step 2 - Open a websocket on the srct and and
+ # generate the container config
+ (state, data) = self.session.container_migrate(instance.name,
+ migration['source_compute'], instance)
+ container_config = self.config.create_container(instance)
+ container_config['source'] = \
+ self.config.get_container_migrate(data, migration, instance)
+ LOG.debug(pprint.pprint(container_config))
+ self.session.container_init(container_config, instance)
+
+ # Step 3 - Start the network and contianer
+ self.operations.plug_vifs(instance, network_info)
+ self.session.container_start(instance.name, instance)
+ except Exception as ex:
+ with excutils.save_and_reraise_exception():
+ LOG.exception(_LE('Migration failed for %(instnace)s: '
+ '%(ex)s'),
+ {'instance': instance.name,
+ 'ex': ex}, instance=instance)
+
def finish_revert_migration(self, context, instance, network_info,
block_device_info=None, power_on=True):
LOG.debug('finish_revert_migration called for instance',
From aeb4c51cf3e7ef38e650fe4a956664d1f114f707 Mon Sep 17 00:00:00 2001
From: Chuck Short <chuck.short at canonical.com>
Date: Sat, 6 Feb 2016 17:43:31 -0500
Subject: [PATCH 11/15] Fix various typos found
Fix various typos found
Signed-off-by: Chuck Short <chuck.short at canonical.com>
---
nova_lxd/nova/virt/lxd/config.py | 21 +++++++--------
nova_lxd/nova/virt/lxd/container_snapshot.py | 3 ++-
nova_lxd/nova/virt/lxd/image.py | 15 +++++------
nova_lxd/nova/virt/lxd/migrate.py | 4 +--
nova_lxd/nova/virt/lxd/operations.py | 4 +--
nova_lxd/nova/virt/lxd/session.py | 39 ++++++++++++++++------------
6 files changed, 45 insertions(+), 41 deletions(-)
diff --git a/nova_lxd/nova/virt/lxd/config.py b/nova_lxd/nova/virt/lxd/config.py
index de4864d..ade9bdf 100644
--- a/nova_lxd/nova/virt/lxd/config.py
+++ b/nova_lxd/nova/virt/lxd/config.py
@@ -122,7 +122,7 @@ def create_config(self, instance_name, instance):
:param instance: nova instance object
:return: LXD resources dictionary
"""
- LOG.debug('_create_config called for instance', instance=instance)
+ LOG.debug('create_config called for instance', instance=instance)
try:
config = {}
@@ -135,7 +135,7 @@ def create_config(self, instance_name, instance):
config['limits.memory'] = '%sMB' % mem
- # Set the instnace vcpu limit
+ # Set the instance vcpu limit
vcpus = instance.flavor.vcpus
if vcpus >= 0:
config['limits.cpu'] = str(vcpus)
@@ -155,7 +155,7 @@ def create_config(self, instance_name, instance):
instance=instance)
def config_instance_options(self, config, instance):
- LOG.debug('_config_instance_options called for instance', instance=instance)
+ LOG.debug('config_instance_options called for instance', instance=instance)
# Set the container to autostart when the host reboots
config['boot.autostart'] = 'True'
@@ -174,7 +174,7 @@ def config_instance_options(self, config, instance):
return config
def configure_container_root(self, instance):
- LOG.debug('_configure_container_root called for instnace',
+ LOG.debug('configure_container_root called for instance',
instance=instance)
try:
config = {}
@@ -190,7 +190,7 @@ def configure_container_root(self, instance):
{'instance': instance.name, 'ex': ex},
instance=instance)
- def _create_network(self, instance_name, instance, network_info):
+ def create_network(self, instance_name, instance, network_info):
"""Create the LXD container network on the host
:param instance_name: nova instance name
@@ -198,7 +198,7 @@ def _create_network(self, instance_name, instance, network_info):
:param network_info: instance network configuration object
:return:network configuration dictionary
"""
- LOG.debug('_create_network called for instance', instance=instance)
+ LOG.debug('create_network called for instance', instance=instance)
try:
network_devices = {}
@@ -225,7 +225,7 @@ def get_container_source(self, instance):
:param instance: nova instance object
:return: the container source
"""
- LOG.debug('_get_container_source called for instance',
+ LOG.debug('get_container_source called for instance',
instance=instance)
try:
container_source = {'type': 'image',
@@ -245,7 +245,7 @@ def get_container_source(self, instance):
def get_container_migrate(self, container_migrate, migration, instance):
LOG.debug('get_container_migrate called for instance',
- instnace=instance)
+ instance=instance)
try:
# Generate the container config
container_metadata =container_migrate['metadata']
@@ -267,7 +267,6 @@ def get_container_migrate(self, container_migrate, migration, instance):
'type': 'migration'
}
- LOG.debug(pprint.pprint(container_migrate))
return container_migrate
except Exception as ex:
with excutils.save_and_reraise_exception():
@@ -328,9 +327,9 @@ def create_container_net_device(self, instance, vif):
def get_network_device(self, instance):
"""Try to detect which network interfaces are available in a contianer
- :param instnace: nova instance object
+ :param instance: nova instance object
"""
- LOG.debug('_get_network_device called for instance', instance=instance)
+ LOG.debug('get_network_device called for instance', instance=instance)
data = self.session.container_info(instance)
lines = open('/proc/%s/net/dev' % data['init']).readlines()
interfaces = []
diff --git a/nova_lxd/nova/virt/lxd/container_snapshot.py b/nova_lxd/nova/virt/lxd/container_snapshot.py
index fb49b6f..8d885d6 100644
--- a/nova_lxd/nova/virt/lxd/container_snapshot.py
+++ b/nova_lxd/nova/virt/lxd/container_snapshot.py
@@ -99,6 +99,7 @@ def _save_lxd_image(self, instance, image_id):
"""
LOG.debug('_save_lxd_image called for instance', instance=instance)
+ fingerprint = None
try:
# Publish the snapshot to the local LXD image store
container_snapshot = {
@@ -140,7 +141,7 @@ def _save_lxd_image(self, instance, image_id):
return fingerprint
def _save_glance_image(self, context, instance, image_id, fingerprint):
- LOG.debug('_save_glance_image called for instance', instnace=instance)
+ LOG.debug('_save_glance_image called for instance', instance=instance)
try:
snapshot = IMAGE_API.get(context, image_id)
diff --git a/nova_lxd/nova/virt/lxd/image.py b/nova_lxd/nova/virt/lxd/image.py
index a39d54c..2f29fcd 100644
--- a/nova_lxd/nova/virt/lxd/image.py
+++ b/nova_lxd/nova/virt/lxd/image.py
@@ -87,7 +87,7 @@ def setup_image(self, context, instance, image_meta):
self._verify_image(context, instance)
# Fetch the image from glance
- self._fetch_image(context, image_meta, instance)
+ self._fetch_image(context, instance)
# Generate the LXD manifest for the image
self._get_lxd_manifest(instance, image_meta)
@@ -99,7 +99,7 @@ def setup_image(self, context, instance, image_meta):
self._setup_alias(instance)
# Remove image and manifest when done.
- self._cleanup_image(image_meta, instance)
+ self._cleanup_image(instance)
except Exception as ex:
with excutils.save_and_reraise_exception():
@@ -107,7 +107,7 @@ def setup_image(self, context, instance, image_meta):
'%(reason)s'),
{'image': instance.image_ref,
'reason': ex}, instance=instance)
- self._cleanup_image(image_meta, instance)
+ self._cleanup_image(instance)
def _verify_image(self, context, instance):
"""Inspect image to verify the correct disk format.
@@ -142,11 +142,10 @@ def _verify_image(self, context, instance):
raise exception.ImageUnacceptable(image_id=instance.image_ref,
reason=reason)
- def _fetch_image(self, context, image_meta, instance):
+ def _fetch_image(self, context, instance):
"""Fetch an image from glance
:param context: nova security object
- :param image_meta: glance image dict
:param instance: the nova instance object
"""
@@ -164,6 +163,7 @@ def _get_lxd_manifest(self, instance, image_meta):
"""
LOG.debug('_get_lxd_manifest called for instance', instance=instance)
+ metadata_yaml = None
try:
# Create a basic LXD manifest from the image properties
image_arch = image_meta.properties.get('hw_architecture')
@@ -217,8 +217,6 @@ def _image_upload(self, instance):
We create the LXD manifest on the fly since glance does
not understand how to talk to Glance.
- :param path: path to the glance image
- :param filenmae: name of the file
:param instance: nova instance
"""
@@ -260,7 +258,6 @@ def _image_upload(self, instance):
def _setup_alias(self, instance):
"""Creates the LXD alias for the image
- :param path: fileystem path of the glance image
:param instance: nova instance
"""
LOG.debug('_setup_alias called for instance', instance=instance)
@@ -281,7 +278,7 @@ def _setup_alias(self, instance):
' %(ex)s'), {'image': instance.image_ref,
'ex': ex}, instance=instance)
- def _cleanup_image(self, image_meta, instance):
+ def _cleanup_image(self, instance):
"""Cleanup the remaning bits of the glance/lxd interaction
:params image_meta: image_meta dictionary
diff --git a/nova_lxd/nova/virt/lxd/migrate.py b/nova_lxd/nova/virt/lxd/migrate.py
index 5a0b7fc..7388b82 100644
--- a/nova_lxd/nova/virt/lxd/migrate.py
+++ b/nova_lxd/nova/virt/lxd/migrate.py
@@ -102,7 +102,7 @@ def confirm_migration(self, migration, instance, network_info):
shutil.rmtree(container_dir)
except Exception as ex:
with excutils.save_and_reraise_exception():
- LOG.exception(_LE('Confirm migration failed for %(instnace)s: '
+ LOG.exception(_LE('Confirm migration failed for %(instance)s: '
'%(ex)s'), {'instance': instance.name,
'ex': ex}, instance=instance)
@@ -142,7 +142,7 @@ def finish_migration(self, context, migration, instance, disk_info,
self.session.container_start(instance.name, instance)
except Exception as ex:
with excutils.save_and_reraise_exception():
- LOG.exception(_LE('Migration failed for %(instnace)s: '
+ LOG.exception(_LE('Migration failed for %(instance)s: '
'%(ex)s'),
{'instance': instance.name,
'ex': ex}, instance=instance)
diff --git a/nova_lxd/nova/virt/lxd/operations.py b/nova_lxd/nova/virt/lxd/operations.py
index 351b58f..7151e6b 100644
--- a/nova_lxd/nova/virt/lxd/operations.py
+++ b/nova_lxd/nova/virt/lxd/operations.py
@@ -298,7 +298,7 @@ def plug_vifs(self, instance, network_info):
"""Setup the container network on the host
:param instance: nova instance object
- :param network_info: instnace network configuration
+ :param network_info: instance network configuration
"""
LOG.debug('plug_vifs called for instance', instance=instance)
try:
@@ -586,7 +586,7 @@ def get_console_output(self, context, instance):
:param context: security context
:param instance: nova.objects.instance.Instance
"""
- LOG.debug('get_console_output called for instnace', instance=instance)
+ LOG.debug('get_console_output called for instance', instance=instance)
try:
console_log = self.container_dir.get_console_path(instance.name)
if not os.path.exists(console_log):
diff --git a/nova_lxd/nova/virt/lxd/session.py b/nova_lxd/nova/virt/lxd/session.py
index 0c76957..dddbc77 100644
--- a/nova_lxd/nova/virt/lxd/session.py
+++ b/nova_lxd/nova/virt/lxd/session.py
@@ -574,7 +574,7 @@ 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
+ :param instance: The nove instance
:return: true if alias is created, false otherwise
"""
@@ -600,10 +600,10 @@ def image_upload(self, data, headers, instance):
:param data: image data
:param headers: image headers
- :param intance: The nova instance
+ :param instance: The nova instance
"""
- LOG.debug('upload_image called for instnace', instance=instance)
+ LOG.debug('upload_image called for instance', instance=instance)
try:
client = self.get_session()
(state, data) = client.image_upload(data=data,
@@ -633,6 +633,7 @@ def operation_wait(self, operation_id, instance):
"""Waits for an operation to return 200 (Success)
:param operation_id: The operation to wait for.
+ :param instance: nova instace object
"""
LOG.debug('wait_for_contianer for instance', instance=instance)
try:
@@ -683,7 +684,7 @@ def profile_list(self):
msg = _('Failed to communicate with LXD API: %(reason)s') \
% {'reason': ex}
LOG.error(msg)
- raise excpetion.NovaException(msg)
+ raise exception.NovaException(msg)
except Exception as ex:
with excutils.save_and_reraise_exception():
LOG.error(_LE('Error from LXD during profile_list: '
@@ -722,7 +723,7 @@ def profile_create(self, config, instance):
"""Create an LXD container profile
:param config: profile dictionary
- :param instnace: nova instance object
+ :param instance: nova instance object
"""
LOG.debug('profile_create called for instance',
instance=instance)
@@ -844,7 +845,7 @@ def container_move(self, old_name, config, instance):
:return:
"""
- LOG.debug('container_move called for instance', instnace=instance)
+ LOG.debug('container_move called for instance', instance=instance)
try:
LOG.info(_LI('Moving container %(instance)s with '
'%(image)s'), {'instance': instance.name,
@@ -958,7 +959,7 @@ 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
+ :param instance: nova instance object
"""
LOG.debug('wait_for_snapshot called for instance', instance=instance)
@@ -978,12 +979,18 @@ def _wait_for_snapshot(self, event_id, instance):
:param event_id: operation id
:param instance: nova instance object
"""
- client = self.get_session()
- (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)
+ try:
+ client = self.get_session()
+ (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)
+ except Exception as ex:
+ with excutils.save_and_reraise_exception():
+ LOG.error(_LE('Failed to wait for snapshot for %(instance)s: '
+ '%(ex)s'), {'instance': instance.name, 'ex': ex},
+ instance=instance)
From 2b1bbc45a3e32e6a290ff8fe17f7e07d570299f2 Mon Sep 17 00:00:00 2001
From: Chuck Short <chuck.short at canonical.com>
Date: Sat, 6 Feb 2016 17:58:31 -0500
Subject: [PATCH 12/15] Fix failing pep8 and unit tests
Signed-off-by: Chuck Short <chuck.short at canonical.com>
---
nova_lxd/nova/virt/lxd/config.py | 37 +++++++++++-----------
nova_lxd/nova/virt/lxd/driver.py | 8 ++---
nova_lxd/nova/virt/lxd/migrate.py | 29 +++++++++--------
nova_lxd/nova/virt/lxd/session.py | 65 ++++++++++++++++++---------------------
nova_lxd/tests/test_config.py | 16 +++-------
nova_lxd/tests/test_driver_api.py | 2 --
nova_lxd/tests/test_image.py | 4 +--
nova_lxd/tests/test_migrate.py | 37 ----------------------
tox.ini | 2 +-
9 files changed, 75 insertions(+), 125 deletions(-)
diff --git a/nova_lxd/nova/virt/lxd/config.py b/nova_lxd/nova/virt/lxd/config.py
index ade9bdf..559c53f 100644
--- a/nova_lxd/nova/virt/lxd/config.py
+++ b/nova_lxd/nova/virt/lxd/config.py
@@ -17,7 +17,6 @@
from nova import exception
from nova import i18n
from nova.virt import configdrive
-import os
from oslo_config import cfg
from oslo_log import log as logging
@@ -102,7 +101,7 @@ def create_profile(self, instance, network_info):
config['name'] = str(instance_name)
config['config'] = self.create_config(instance_name, instance)
config['devices'] = self.create_network(instance_name, instance,
- network_info)
+ network_info)
# Restrict the size of the "/" disk
config['devices'].update(
@@ -134,7 +133,6 @@ def create_config(self, instance_name, instance):
if mem >= 0:
config['limits.memory'] = '%sMB' % mem
-
# Set the instance vcpu limit
vcpus = instance.flavor.vcpus
if vcpus >= 0:
@@ -155,19 +153,22 @@ def create_config(self, instance_name, instance):
instance=instance)
def config_instance_options(self, config, instance):
- LOG.debug('config_instance_options called for instance', instance=instance)
+ LOG.debug('config_instance_options called for instance',
+ instance=instance)
# Set the container to autostart when the host reboots
config['boot.autostart'] = 'True'
# Determine if we require a nested container
flavor = instance.flavor
- lxd_nested_allowed = flavor.extra_specs.get('lxd_nested_allowed', False)
+ lxd_nested_allowed = flavor.extra_specs.get(
+ 'lxd_nested_allowed', False)
if lxd_nested_allowed:
config['security.nesting'] = 'True'
# Determine if we require a privileged container
- lxd_privileged_allowed = flavor.extra_specs.get('lxd_privileged_allowed', False)
+ lxd_privileged_allowed = flavor.extra_specs.get(
+ 'lxd_privileged_allowed', False)
if lxd_privileged_allowed:
config['security.privileged'] = 'True'
@@ -181,14 +182,14 @@ def configure_container_root(self, instance):
config['root'] = {'path': '/',
'type': 'disk',
'size': '%sGB' % str(instance.root_gb)
- }
+ }
return config
except Exception as ex:
with excutils.save_and_reraise_exception():
LOG.error(_LE('Failed to configure disk for '
'%(instance)s: %(ex)s'),
- {'instance': instance.name, 'ex': ex},
- instance=instance)
+ {'instance': instance.name, 'ex': ex},
+ instance=instance)
def create_network(self, instance_name, instance, network_info):
"""Create the LXD container network on the host
@@ -248,7 +249,7 @@ def get_container_migrate(self, container_migrate, migration, instance):
instance=instance)
try:
# Generate the container config
- container_metadata =container_migrate['metadata']
+ container_metadata = container_migrate['metadata']
container_control = container_metadata['metadata']['control']
container_fs = container_metadata['metadata']['fs']
@@ -257,14 +258,14 @@ def get_container_migrate(self, container_migrate, migration, instance):
container_migrate.get('operation')))
container_migrate = {
- 'base_iamge': '',
- 'mode': 'pull',
- 'operation': str(container_url),
- 'secrets': {
+ 'base_iamge': '',
+ 'mode': 'pull',
+ 'operation': str(container_url),
+ 'secrets': {
'control': str(container_control),
'fs': str(container_fs)
- },
- 'type': 'migration'
+ },
+ 'type': 'migration'
}
return container_migrate
@@ -272,8 +273,8 @@ def get_container_migrate(self, container_migrate, migration, instance):
with excutils.save_and_reraise_exception():
LOG.error(_LE('Failed to configure migation source '
'%(instance)s: %(ex)s'),
- {'instance': instance.name, 'ex': ex},
- instance=instance)
+ {'instance': instance.name, 'ex': ex},
+ instance=instance)
def configure_disk_path(self, src_path, dest_path, vfs_type, instance):
"""Configure the host mount point for the LXD container
diff --git a/nova_lxd/nova/virt/lxd/driver.py b/nova_lxd/nova/virt/lxd/driver.py
index df3ae2e..df9eb1b 100644
--- a/nova_lxd/nova/virt/lxd/driver.py
+++ b/nova_lxd/nova/virt/lxd/driver.py
@@ -195,10 +195,10 @@ def confirm_migration(self, migration, instance, network_info):
network_info)
def finish_revert_migration(self, context, instance, network_info,
- block_device_info=None, power_on=True):
- return self.container_migrate.finish_revert_migration(context,
- instance, network_info, block_device_info,
- power_on)
+ block_device_info=None, power_on=True):
+ return self.container_migrate.finish_revert_migration(
+ context, instance, network_info, block_device_info,
+ power_on)
def pause(self, instance):
self.container_ops.pause(instance)
diff --git a/nova_lxd/nova/virt/lxd/migrate.py b/nova_lxd/nova/virt/lxd/migrate.py
index 7388b82..fbe19ee 100644
--- a/nova_lxd/nova/virt/lxd/migrate.py
+++ b/nova_lxd/nova/virt/lxd/migrate.py
@@ -79,8 +79,8 @@ def migrate_disk_and_power_off(self, context, instance, dest,
with excutils.save_and_reraise_exception():
LOG.error(_LE('failed to resize container '
'%(instance)s: %(ex)s'),
- {'instance': instance.name, 'ex': ex},
- instance=instance)
+ {'instance': instance.name, 'ex': ex},
+ instance=instance)
# disk_info is not used
return ""
@@ -89,7 +89,8 @@ def confirm_migration(self, migration, instance, network_info):
LOG.debug("confirm_migration called", instance=instance)
if not self.session.container_defined(instance.name, instance):
- msg = _('Failed to find container %s' % instance.name)
+ msg = _('Failed to find container %(instance)s') % \
+ {'instnace': instance.name}
raise exception.NovaException(msg)
try:
@@ -104,7 +105,7 @@ def confirm_migration(self, migration, instance, network_info):
with excutils.save_and_reraise_exception():
LOG.exception(_LE('Confirm migration failed for %(instance)s: '
'%(ex)s'), {'instance': instance.name,
- 'ex': ex}, instance=instance)
+ 'ex': ex}, instance=instance)
def finish_migration(self, context, migration, instance, disk_info,
network_info, image_meta, resize_instance=False,
@@ -112,7 +113,8 @@ def finish_migration(self, context, migration, instance, disk_info,
LOG.debug("finish_migration called", instance=instance)
if self.session.container_defined(instance.name, instance):
- msg = _('Failed to find container %s' % instance.name)
+ msg = _('Failed to find container %(instance)s') % \
+ {'instance': instance.name}
raise exception.NovaException(msg)
try:
@@ -124,13 +126,15 @@ def finish_migration(self, context, migration, instance, disk_info,
# Step 1 - Setup the profile on the dest host
container_profile = self.config.create_profile(instance,
- network_info)
+ network_info)
self.session.profile_create(container_profile, instance)
# Step 2 - Open a websocket on the srct and and
# generate the container config
- (state, data) = self.session.container_migrate(instance.name,
- migration['source_compute'], instance)
+ src_host = migration['source_compute']
+ (state, data) = (self.session.container_migrate(instance.name,
+ src_host,
+ instance))
container_config = self.config.create_container(instance)
container_config['source'] = \
self.config.get_container_migrate(data, migration, instance)
@@ -144,13 +148,12 @@ def finish_migration(self, context, migration, instance, disk_info,
with excutils.save_and_reraise_exception():
LOG.exception(_LE('Migration failed for %(instance)s: '
'%(ex)s'),
- {'instance': instance.name,
- 'ex': ex}, instance=instance)
+ {'instance': instance.name,
+ 'ex': ex}, instance=instance)
def finish_revert_migration(self, context, instance, network_info,
- block_device_info=None, power_on=True):
+ block_device_info=None, power_on=True):
LOG.debug('finish_revert_migration called for instance',
- instance=instance)
+ instance=instance)
if self.session.container_defined(instance.name, instance):
self.session.container_start(instance.name, instance)
-
diff --git a/nova_lxd/nova/virt/lxd/session.py b/nova_lxd/nova/virt/lxd/session.py
index dddbc77..de35bd5 100644
--- a/nova_lxd/nova/virt/lxd/session.py
+++ b/nova_lxd/nova/virt/lxd/session.py
@@ -303,7 +303,7 @@ def container_start(self, instance_name, instance):
LOG.info(_LI('Successfully started instance %(instance)s with'
' %(image)s'), {'instance': instance.name,
- 'image': instance.image_ref})
+ 'image': instance.image_ref})
except lxd_exceptions.APIError as ex:
msg = _('Failed to communicate with LXD API %(instance)s:'
' %(reason)s') % {'instance': instance.name,
@@ -331,7 +331,7 @@ def container_stop(self, instance_name, instance):
LOG.info(_LI('Stopping instance %(instance)s with'
' %(image)s'), {'instance': instance.name,
- 'image': instance.image_ref})
+ 'image': instance.image_ref})
# Stop the container
client = self.get_session()
(state, data) = client.container_stop(instance_name,
@@ -340,7 +340,7 @@ def container_stop(self, instance_name, instance):
LOG.info(_LI('Successfully stopped instance %(instance)s with'
' %(image)s'), {'instance': instance.name,
- 'image': instance.image_ref})
+ 'image': instance.image_ref})
except lxd_exceptions.APIError as ex:
msg = _('Failed to communicate with LXD API %(instance)s:'
' %(reason)s') % {'instance': instance.name,
@@ -367,7 +367,7 @@ def container_reboot(self, instance):
LOG.info(_LI('Rebooting instance %(instance)s with'
' %(image)s'), {'instance': instance.name,
- 'image': instance.image_ref})
+ 'image': instance.image_ref})
# Container reboot
client = self.get_session()
@@ -377,7 +377,7 @@ def container_reboot(self, instance):
LOG.info(_LI('Successfully rebooted instance %(instance)s with'
' %(image)s'), {'instance': instance.name,
- 'image': instance.image_ref})
+ 'image': instance.image_ref})
except lxd_exceptions.APIError as ex:
msg = _('Failed to communicate with LXD API %(instance)s:'
' %(reason)s') % {'instance': instance.name,
@@ -404,7 +404,7 @@ def container_destroy(self, instance_name, instance):
LOG.info(_LI('Destroying instance %(instance)s with'
' %(image)s'), {'instance': instance.name,
- 'image': instance.image_ref})
+ 'image': instance.image_ref})
# Destroying container
self.container_stop(instance_name, instance)
@@ -415,7 +415,7 @@ def container_destroy(self, instance_name, instance):
LOG.info(_LI('Successfully destroyed instance %(instance)s with'
' %(image)s'), {'instance': instance.name,
- 'image': instance.image_ref})
+ 'image': instance.image_ref})
except lxd_exceptions.APIError as ex:
msg = _('Failed to communicate with LXD API %(instance)s:'
' %(reason)s') % {'instance': instance.name,
@@ -442,7 +442,7 @@ def container_pause(self, instance_name, instance):
LOG.info(_LI('Pausing instance %(instance)s with'
' %(image)s'), {'instance': instance_name,
- 'image': instance.image_ref})
+ 'image': instance.image_ref})
client = self.get_session()
(state, data) = client.container_suspend(instance_name,
@@ -451,7 +451,7 @@ def container_pause(self, instance_name, instance):
LOG.info(_LI('Successfully paused instance %(instance)s with'
' %(image)s'), {'instance': instance_name,
- 'image': instance.image_ref})
+ 'image': instance.image_ref})
except lxd_exceptions.APIError as ex:
msg = _('Failed to communicate with LXD API %(instance)s:'
' %(reason)s') % {'instance': instance_name,
@@ -480,7 +480,7 @@ def container_unpause(self, instance_name, instance):
LOG.info(_LI('Unpausing instance %(instance)s with'
' %(image)s'), {'instance': instance.name,
- 'image': instance.image_ref})
+ 'image': instance.image_ref})
client = self.get_session()
(state, data) = client.container_resume(instance_name,
@@ -489,7 +489,7 @@ def container_unpause(self, instance_name, instance):
LOG.info(_LI('Successfully unpaused instance %(instance)s with'
' %(image)s'), {'instance': instance.name,
- 'image': instance.image_ref})
+ 'image': instance.image_ref})
except lxd_exceptions.APIError as ex:
msg = _('Failed to communicate with LXD API %(instance)s:'
' %(reason)s') % {'instance': instance.name,
@@ -513,7 +513,7 @@ def container_init(self, config, instance):
try:
LOG.info(_LI('Creating container %(instance)s with'
' %(image)s'), {'instance': instance.name,
- 'image': instance.image_ref})
+ 'image': instance.image_ref})
client = self.get_session()
(state, data) = client.container_init(config)
@@ -526,7 +526,7 @@ def container_init(self, config, instance):
LOG.info(_LI('Successfully created container %(instance)s with'
' %(image)s'), {'instance': instance.name,
- 'image': instance.image_ref})
+ 'image': instance.image_ref})
except lxd_exceptions.APIError as ex:
msg = _('Failed to communicate with LXD API %(instance)s:'
' %(reason)s') % {'instance': instance.name,
@@ -662,7 +662,7 @@ def operation_info(self, operation_id, instance):
except lxd_exceptions.APIError as ex:
msg = _('Failed to communicate with LXD API %(instance)s:'
' %(reason)s') % {'instance': instance.image_ref,
- 'reason': ex}
+ 'reason': ex}
LOG.error(msg)
raise exception.NovaException(msg)
except Exception as e:
@@ -682,14 +682,13 @@ def profile_list(self):
return client.profile_list()
except lxd_exceptions.APIError as ex:
msg = _('Failed to communicate with LXD API: %(reason)s') \
- % {'reason': ex}
+ % {'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 profile_list: '
- '%(reason)s') % {'reason': ex})
-
+ '%(reason)s') % {'reason': ex})
def profile_defined(self, instance_name, instance):
"""Validate if the profile is available on the LXD
@@ -729,7 +728,8 @@ def profile_create(self, config, instance):
instance=instance)
try:
if self.profile_defined(instance.name, instance):
- msg = _('Profile already exists %s' % instance.name)
+ msg = _('Profile already exists %(instnce)s') % \
+ {'instnace': instance.name}
raise exception.NovaException(msg)
client = self.get_session()
@@ -754,7 +754,8 @@ def profile_update(self, config, instance):
LOG.debug('profile_udpate called for instance', instance=instance)
try:
if not self.profile_defined(instance.name, instance):
- msg = _('Profile not found %s' % instance.name)
+ msg = _('Profile not found %(instnace)s') % \
+ {'instance': instance.name}
raise exception.NovaException(msg)
client = self.get_session()
@@ -893,7 +894,7 @@ def container_snapshot(self, snapshot, instance):
LOG.info(_LI('Successfully snapshotted container %(instance)s with'
' %(image)s'), {'instance': instance.name,
- 'image': instance.image_ref})
+ 'image': instance.image_ref})
except lxd_exceptions.APIError as ex:
msg = _('Failed to communicate with LXD API %(instance)s:'
' %(reason)s') % {'instance': instance.name,
@@ -979,18 +980,12 @@ def _wait_for_snapshot(self, event_id, instance):
:param event_id: operation id
:param instance: nova instance object
"""
- try:
- client = self.get_session()
- (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)
- except Exception as ex:
- with excutils.save_and_reraise_exception():
- LOG.error(_LE('Failed to wait for snapshot for %(instance)s: '
- '%(ex)s'), {'instance': instance.name, 'ex': ex},
- instance=instance)
+ client = self.get_session()
+ (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/test_config.py b/nova_lxd/tests/test_config.py
index 1ad1b4a..8d1e697 100644
--- a/nova_lxd/tests/test_config.py
+++ b/nova_lxd/tests/test_config.py
@@ -16,7 +16,6 @@
import ddt
import mock
-from nova import exception
from nova import test
from nova.tests.unit import fake_network
@@ -56,15 +55,15 @@ def test_create_container(self, tag, key, expected):
def test_create_config(self, tag, key, expected):
instance = stubs._fake_instance()
instance_name = 'fake_instance'
- config = self.config._create_config(instance_name, instance)
+ config = self.config.create_config(instance_name, instance)
self.assertEqual(config[key], expected)
def test_create_network(self):
instance = stubs._fake_instance()
instance_name = 'fake_instance'
network_info = fake_network.fake_get_instance_nw_info(self)
- config = self.config._create_network(instance_name, instance,
- network_info)
+ config = self.config.create_network(instance_name, instance,
+ network_info)
self.assertEqual({'fake_br1': {'hwaddr': 'DE:AD:BE:EF:00:01',
'nictype': 'bridged',
'parent': 'fake_br1',
@@ -80,14 +79,7 @@ def test_create_disk_path(self):
'source': '/fake/src_path',
'type': 'disk'}}, config)
- @mock.patch('os.path.exists', mock.Mock(return_value=False))
- def test_create_disk_path_fail(self):
- instance = stubs._fake_instance()
- self.assertRaises(exception.NovaException,
- self.config.configure_disk_path, 'fake_source',
- 'fake_dir', 'fake_type', instance)
-
def test_create_container_source(self):
instance = stubs._fake_instance()
- config = self.config._get_container_source(instance)
+ config = self.config.get_container_source(instance)
self.assertEqual(config, {'type': 'image', 'alias': 'fake_image'})
diff --git a/nova_lxd/tests/test_driver_api.py b/nova_lxd/tests/test_driver_api.py
index fa2fc7b..9a23a3f 100644
--- a/nova_lxd/tests/test_driver_api.py
+++ b/nova_lxd/tests/test_driver_api.py
@@ -433,7 +433,6 @@ def setUp(self):
'get_all_volume_usage',
'attach_volume',
'detach_volume',
- 'finish_revert_migration',
'soft_delete',
'post_live_migration_at_source',
'check_instance_shared_storage_local',
@@ -465,7 +464,6 @@ def test_notimplemented(self, method):
@ddt.data(
'post_interrupted_snapshot_cleanup',
- 'post_live_migration',
'check_instance_shared_storage_cleanup',
'manage_image_cache',
)
diff --git a/nova_lxd/tests/test_image.py b/nova_lxd/tests/test_image.py
index 4d3b8d7..5041827 100644
--- a/nova_lxd/tests/test_image.py
+++ b/nova_lxd/tests/test_image.py
@@ -74,11 +74,9 @@ def test_image(self, tag, sucess, image_data, expected):
@mock.patch.object(image.IMAGE_API, 'download')
def test_fetch_image(self, mock_download):
context = mock.Mock()
- image_meta = mock.Mock()
instance = stubs._fake_instance()
self.assertEqual(None,
- self.image._fetch_image(context, image_meta,
- instance))
+ self.image._fetch_image(context, instance))
@mock.patch.object(os, 'stat')
@mock.patch.object(json, 'dumps')
diff --git a/nova_lxd/tests/test_migrate.py b/nova_lxd/tests/test_migrate.py
index eef74eb..3bf9ceb 100644
--- a/nova_lxd/tests/test_migrate.py
+++ b/nova_lxd/tests/test_migrate.py
@@ -34,40 +34,3 @@ def setUp(self):
self.migrate = migrate.LXDContainerMigrate(
fake.FakeVirtAPI())
-
- @mock.patch.object(session.LXDAPISession, 'container_migrate')
- def test_finish_migration(self, mo):
- context = mock.Mock()
- migration = {'source_compute': 'fake-source',
- 'dest_compute': 'fake-dest'}
- instance = stubs._fake_instance()
- bdevice_info = mock.Mock()
- disk_info = mock.Mock()
- network_info = mock.Mock()
- with test.nested(
- mock.patch.object(session.LXDAPISession,
- 'container_defined'),
- mock.patch.object(session.LXDAPISession,
- 'container_stop'),
- mock.patch.object(session.LXDAPISession,
- 'container_init'),
- ) as (
- container_defined,
- container_stop,
- container_init
- ):
- def side_effect(*args, **kwargs):
- # XXX: rockstar (7 Dec 2015) - This mock is a little greedy,
- # and hits too many interfaces. It should become more specific
- # to the single places it needs to fully mocked. Truthiness of
- # the mock changes in py3.
- if args[0] == 'defined':
- return False
- container_defined.side_effect = side_effect
- self.assertEqual(None,
- (self.migrate.finish_migration(context,
- migration,
- instance,
- disk_info,
- network_info,
- bdevice_info)))
diff --git a/tox.ini b/tox.ini
index 7d142a4..d899b67 100644
--- a/tox.ini
+++ b/tox.ini
@@ -40,6 +40,6 @@ commands = python setup.py build_sphinx
# E123, E125 skipped as they are invalid PEP-8.
show-source = True
-ignore = E123,E125,H803,H904,H405,H404
+ignore = E123,E125,H803,H904,H405,H404,H305,H306,H307
builtins = _
exclude=.venv,.git,.tox,dist,doc,*openstack/common*,*lib/python*,*egg,build,tools/colorizer.py
From c4b3de69db11190309dd5a8f9d63b550f4e6b127 Mon Sep 17 00:00:00 2001
From: Chuck Short <chuck.short at canonical.com>
Date: Sat, 6 Feb 2016 22:11:46 -0500
Subject: [PATCH 13/15] Add unit tests for profiles
Add unit tests for profile API calls.
Signed-off-by: Chuck Short <chuck.short at canonical.com>
---
nova_lxd/nova/virt/lxd/session.py | 2 +-
nova_lxd/tests/session/test_profile.py | 83 ++++++++++++++++++++++++++++++++++
nova_lxd/tests/test_config.py | 9 ++++
3 files changed, 93 insertions(+), 1 deletion(-)
create mode 100644 nova_lxd/tests/session/test_profile.py
diff --git a/nova_lxd/nova/virt/lxd/session.py b/nova_lxd/nova/virt/lxd/session.py
index de35bd5..bfdd3a7 100644
--- a/nova_lxd/nova/virt/lxd/session.py
+++ b/nova_lxd/nova/virt/lxd/session.py
@@ -754,7 +754,7 @@ def profile_update(self, config, instance):
LOG.debug('profile_udpate called for instance', instance=instance)
try:
if not self.profile_defined(instance.name, instance):
- msg = _('Profile not found %(instnace)s') % \
+ msg = _('Profile not found %(instance)s') % \
{'instance': instance.name}
raise exception.NovaException(msg)
diff --git a/nova_lxd/tests/session/test_profile.py b/nova_lxd/tests/session/test_profile.py
new file mode 100644
index 0000000..3a1264f
--- /dev/null
+++ b/nova_lxd/tests/session/test_profile.py
@@ -0,0 +1,83 @@
+# 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.
+
+
+import ddt
+import mock
+
+from nova.compute import power_state
+from nova import exception
+from nova import test
+from pylxd import exceptions as lxd_exceptions
+
+from nova_lxd.nova.virt.lxd import session
+from nova_lxd.tests import fake_api
+from nova_lxd.tests import stubs
+
+
+ at ddt.ddt
+class SessionProfileTest(test.NoDBTestCase):
+
+ def setUp(self):
+ super(SessionProfileTest, self).setUp()
+
+ """This is so we can mock out pylxd API calls."""
+ self.ml = stubs.lxd_mock()
+ lxd_patcher = mock.patch('pylxd.api.API',
+ mock.Mock(return_value=self.ml))
+ lxd_patcher.start()
+ self.addCleanup(lxd_patcher.stop)
+
+ self.session = session.LXDAPISession()
+
+ @stubs.annotated_data(
+ ('empty', [], []),
+ ('valid', ['test'], ['test']),
+ )
+ def test_profile_list(self, tag, side_effect, expected):
+ self.ml.profile_list.return_value = side_effect
+ self.assertEqual(expected,
+ self.session.profile_list())
+
+ def test_profile_list_fail(self):
+ self.ml.profile_list.side_effect = (
+ lxd_exceptions.APIError('Fake', 500))
+ self.assertRaises(
+ exception.NovaException,
+ self.session.profile_list)
+
+ def test_profile_create(self):
+ instance = stubs._fake_instance()
+ config = mock.Mock()
+ self.ml.profile_defined.return_value = True
+ self.ml.profile_create.return_value = \
+ (200, fake_api.fake_standard_return())
+ self.assertEqual((200, fake_api.fake_standard_return()),
+ self.session.profile_create(config,
+ instance))
+ calls = [mock.call.profile_list(),
+ mock.call.profile_create(config)]
+ self.assertEqual(calls, self.ml.method_calls)
+
+ def test_profile_delete(self):
+ instance = stubs._fake_instance()
+ config = mock.Mock()
+ self.ml.profile_defined.return_value = True
+ self.ml.profile_delete.return_value = \
+ (200, fake_api.fake_standard_return())
+ self.assertEqual(None,
+ self.session.profile_delete(instance))
+
+
\ No newline at end of file
diff --git a/nova_lxd/tests/test_config.py b/nova_lxd/tests/test_config.py
index 8d1e697..ebd5530 100644
--- a/nova_lxd/tests/test_config.py
+++ b/nova_lxd/tests/test_config.py
@@ -16,6 +16,7 @@
import ddt
import mock
+from nova import objects
from nova import test
from nova.tests.unit import fake_network
@@ -79,6 +80,14 @@ def test_create_disk_path(self):
'source': '/fake/src_path',
'type': 'disk'}}, config)
+ def test_config_instance_options(self):
+ instance = stubs._fake_instance()
+ config = {}
+ container_config = self.config.config_instance_options(config,
+ instance)
+ self.assertEqual({'boot.autostart': 'True'}, container_config)
+
+
def test_create_container_source(self):
instance = stubs._fake_instance()
config = self.config.get_container_source(instance)
From 303d2bd0f6f958aadf6c0eae3eaae9e9a93253ae Mon Sep 17 00:00:00 2001
From: Chuck Short <chuck.short at canonical.com>
Date: Mon, 8 Feb 2016 09:57:46 -0500
Subject: [PATCH 14/15] Add more unit tests
Signed-off-by: Chuck Short <chuck.short at canonical.com>
---
nova_lxd/nova/virt/lxd/migrate.py | 3 --
nova_lxd/tests/fake_api.py | 35 ++++++++++++++-----
nova_lxd/tests/session/test_profile.py | 1 -
nova_lxd/tests/stubs.py | 2 ++
nova_lxd/tests/test_config.py | 22 ++++++++++++
nova_lxd/tests/test_migrate.py | 61 +++++++++++++++++++++++++++++++---
6 files changed, 108 insertions(+), 16 deletions(-)
diff --git a/nova_lxd/nova/virt/lxd/migrate.py b/nova_lxd/nova/virt/lxd/migrate.py
index fbe19ee..28c9aa3 100644
--- a/nova_lxd/nova/virt/lxd/migrate.py
+++ b/nova_lxd/nova/virt/lxd/migrate.py
@@ -98,9 +98,6 @@ def confirm_migration(self, migration, instance, network_info):
self.session.container_destroy(instance.name,
instance)
self.operations.unplug_vifs(instance, network_info)
- container_dir = self.container_dir.get_instance_dir(instance.name)
- if os.path.exists(container_dir):
- shutil.rmtree(container_dir)
except Exception as ex:
with excutils.save_and_reraise_exception():
LOG.exception(_LE('Confirm migration failed for %(instance)s: '
diff --git a/nova_lxd/tests/fake_api.py b/nova_lxd/tests/fake_api.py
index ae7c0ea..b9078e6 100644
--- a/nova_lxd/tests/fake_api.py
+++ b/nova_lxd/tests/fake_api.py
@@ -144,15 +144,29 @@ def fake_container_log():
def fake_container_migrate():
return {
- "type": "sync",
- "status": "Success",
- "status_code": 200,
- "operation": "/1.0/operations/1234",
+ "type": "async",
+ "status": "Operation created",
+ "status_code": 100,
"metadata": {
- "control": "fake_control",
- "criu": "fake_criu",
- "fs": "fake_fs",
- }
+ "id": "dbd9f22c-6da5-4066-8fca-c02f09f76738",
+ "class": "websocket",
+ "created_at": "2016-02-07T09:20:53.127321875-05:00",
+ "updated_at": "2016-02-07T09:20:53.127321875-05:00",
+ "status": "Running",
+ "status_code": 103,
+ "resources": {
+ "containers": [
+ "/1.0/containers/instance-00000010"
+ ]
+ },
+ "metadata": {
+ "control": "5ffecc8e6cf95e01f4bae7dcef6e87711e7c119e42ed7538e3da583ed91927da",
+ "fs": "21f09995fed96a8abae91802de4b794a35789d2a813735c9874decfe591134c4"
+ },
+ "may_cancel": false,
+ "err": ""
+ },
+ "operation": "/1.0/operations/dbd9f22c-6da5-4066-8fca-c02f09f76738"
}
@@ -381,3 +395,8 @@ def fake_container_info():
'address': "172.16.15.30",
'host_veth': "vethGMDIY9"}]},
}
+
+def fake_container_migrate():
+ return {
+
+ }
diff --git a/nova_lxd/tests/session/test_profile.py b/nova_lxd/tests/session/test_profile.py
index 3a1264f..848be25 100644
--- a/nova_lxd/tests/session/test_profile.py
+++ b/nova_lxd/tests/session/test_profile.py
@@ -80,4 +80,3 @@ def test_profile_delete(self):
self.assertEqual(None,
self.session.profile_delete(instance))
-
\ No newline at end of file
diff --git a/nova_lxd/tests/stubs.py b/nova_lxd/tests/stubs.py
index c66c061..3edfd11 100644
--- a/nova_lxd/tests/stubs.py
+++ b/nova_lxd/tests/stubs.py
@@ -108,3 +108,5 @@ def _fake_instance():
}
return fake_instance.fake_instance_obj(
ctxt, **_instance_values)
+
+
diff --git a/nova_lxd/tests/test_config.py b/nova_lxd/tests/test_config.py
index ebd5530..581e930 100644
--- a/nova_lxd/tests/test_config.py
+++ b/nova_lxd/tests/test_config.py
@@ -23,6 +23,7 @@
from nova_lxd.nova.virt.lxd import config
from nova_lxd.nova.virt.lxd import utils as container_dir
from nova_lxd.tests import stubs
+from nova_lxd.tests import fake_api
@ddt.ddt
@@ -92,3 +93,24 @@ def test_create_container_source(self):
instance = stubs._fake_instance()
config = self.config.get_container_source(instance)
self.assertEqual(config, {'type': 'image', 'alias': 'fake_image'})
+
+ def test_container_root(self):
+ instance = stubs._fake_instance()
+ config = self.config.configure_container_root(instance)
+ self.assertEqual({'root': {'path': '/',
+ 'type': 'disk',
+ 'size': '10GB'}}, config)
+
+ def test_container_nested_container(self):
+ instance = stubs._fake_instance()
+ instance.flavor.extra_specs = {'lxd_nested_allowed': True}
+ config = self.config.config_instance_options({}, instance)
+ self.assertEqual({'security.nesting': 'True',
+ 'boot.autostart': 'True'}, config)
+
+ def test_container_privileged_container(self):
+ instance = stubs._fake_instance()
+ instance.flavor.extra_specs = {'lxd_privileged_allowed': True}
+ config = self.config.config_instance_options({}, instance)
+ self.assertEqual({'security.privileged': 'True',
+ 'boot.autostart': 'True'}, config)
diff --git a/nova_lxd/tests/test_migrate.py b/nova_lxd/tests/test_migrate.py
index 3bf9ceb..18145a1 100644
--- a/nova_lxd/tests/test_migrate.py
+++ b/nova_lxd/tests/test_migrate.py
@@ -13,24 +13,77 @@
# License for the specific language governing permissions and limitations
# under the License.
+import os
+import shutil
+
import mock
from nova import test
from nova.virt import fake
+from oslo_config import cfg
+from oslo_utils import fileutils
+
+from nova_lxd.nova.virt.lxd import config
from nova_lxd.nova.virt.lxd import migrate
+from nova_lxd.nova.virt.lxd import operations
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
+CONF = cfg.CONF
+CONF.import_opt('my_ip', 'nova.netconf')
+
- at mock.patch.object(migrate, 'CONF', stubs.MockConf())
- at mock.patch.object(session, 'CONF', stubs.MockConf())
class LXDTestContainerMigrate(test.NoDBTestCase):
- @mock.patch.object(migrate, 'CONF', stubs.MockConf())
- @mock.patch.object(session, 'CONF', stubs.MockConf())
def setUp(self):
super(LXDTestContainerMigrate, self).setUp()
self.migrate = migrate.LXDContainerMigrate(
fake.FakeVirtAPI())
+
+ def test_migrate_disk_power_off_resize(self):
+ self.flags(my_ip='fakeip')
+ instance = stubs._fake_instance()
+ network_info = mock.Mock()
+ flavor = mock.Mock()
+ context = mock.Mock()
+ dest = 'fakeip'
+
+ with test.nested(
+ mock.patch.object(session.LXDAPISession, 'container_defined'),
+ mock.patch.object(config.LXDContainerConfig, 'create_profile'),
+ mock.patch.object(session.LXDAPISession, 'profile_update')
+ ) as (
+ mock_container_defined,
+ mock_create_profile,
+ mock_profile_update
+ ):
+ self.assertEqual('',
+ self.migrate.migrate_disk_and_power_off(
+ context, instance, dest, flavor, network_info))
+ mock_container_defined.assert_called_once_with(instance.name,
+ instance)
+ mock_create_profile.assert_called_once_with(instance, network_info)
+
+ def test_confirm_migration(self):
+ migration = mock.Mock()
+ instance = stubs._fake_instance()
+ network_info = mock.Mock()
+
+ with test.nested(
+ mock.patch.object(session.LXDAPISession, 'container_defined'),
+ mock.patch.object(session.LXDAPISession, 'profile_delete'),
+ mock.patch.object(session.LXDAPISession, 'container_destroy'),
+ mock.patch.object(operations.LXDContainerOperations, 'unplug_vifs'),
+ ) as (
+ mock_container_defined,
+ mock_profile_delete,
+ mock_container_destroy,
+ mock_unplug_vifs):
+ self.assertEqual(None,
+ self.migrate.confirm_migration(migration, instance, network_info))
+ mock_container_defined.assert_called_once_with(instance.name, instance)
+ mock_profile_delete.assert_called_once_with(instance)
+ mock_unplug_vifs.assert_called_once_with(instance, network_info)
From e53a7f1d62c61448269b3f8dfee4aeb8e3b51e55 Mon Sep 17 00:00:00 2001
From: Chuck Short <chuck.short at canonical.com>
Date: Mon, 8 Feb 2016 10:18:09 -0500
Subject: [PATCH 15/15] Fix pep8
Signed-off-by: Chuck Short <chuck.short at canonical.com>
---
nova_lxd/nova/virt/lxd/migrate.py | 1 -
nova_lxd/tests/fake_api.py | 13 ++++--------
nova_lxd/tests/session/test_profile.py | 3 ---
nova_lxd/tests/stubs.py | 2 --
nova_lxd/tests/test_config.py | 5 +----
nova_lxd/tests/test_migrate.py | 38 ++++++++++++++++++----------------
6 files changed, 25 insertions(+), 37 deletions(-)
diff --git a/nova_lxd/nova/virt/lxd/migrate.py b/nova_lxd/nova/virt/lxd/migrate.py
index 28c9aa3..653b64b 100644
--- a/nova_lxd/nova/virt/lxd/migrate.py
+++ b/nova_lxd/nova/virt/lxd/migrate.py
@@ -15,7 +15,6 @@
import os
import pprint
-import shutil
from nova import exception
from nova import i18n
diff --git a/nova_lxd/tests/fake_api.py b/nova_lxd/tests/fake_api.py
index b9078e6..3ead0dd 100644
--- a/nova_lxd/tests/fake_api.py
+++ b/nova_lxd/tests/fake_api.py
@@ -157,13 +157,13 @@ def fake_container_migrate():
"resources": {
"containers": [
"/1.0/containers/instance-00000010"
- ]
+ ]
},
"metadata": {
- "control": "5ffecc8e6cf95e01f4bae7dcef6e87711e7c119e42ed7538e3da583ed91927da",
- "fs": "21f09995fed96a8abae91802de4b794a35789d2a813735c9874decfe591134c4"
+ "control": "fake_control",
+ "fs": "fake_fs"
},
- "may_cancel": false,
+ "may_cancel": 'false',
"err": ""
},
"operation": "/1.0/operations/dbd9f22c-6da5-4066-8fca-c02f09f76738"
@@ -395,8 +395,3 @@ def fake_container_info():
'address': "172.16.15.30",
'host_veth': "vethGMDIY9"}]},
}
-
-def fake_container_migrate():
- return {
-
- }
diff --git a/nova_lxd/tests/session/test_profile.py b/nova_lxd/tests/session/test_profile.py
index 848be25..9698a3f 100644
--- a/nova_lxd/tests/session/test_profile.py
+++ b/nova_lxd/tests/session/test_profile.py
@@ -17,7 +17,6 @@
import ddt
import mock
-from nova.compute import power_state
from nova import exception
from nova import test
from pylxd import exceptions as lxd_exceptions
@@ -73,10 +72,8 @@ def test_profile_create(self):
def test_profile_delete(self):
instance = stubs._fake_instance()
- config = mock.Mock()
self.ml.profile_defined.return_value = True
self.ml.profile_delete.return_value = \
(200, fake_api.fake_standard_return())
self.assertEqual(None,
self.session.profile_delete(instance))
-
diff --git a/nova_lxd/tests/stubs.py b/nova_lxd/tests/stubs.py
index 3edfd11..c66c061 100644
--- a/nova_lxd/tests/stubs.py
+++ b/nova_lxd/tests/stubs.py
@@ -108,5 +108,3 @@ def _fake_instance():
}
return fake_instance.fake_instance_obj(
ctxt, **_instance_values)
-
-
diff --git a/nova_lxd/tests/test_config.py b/nova_lxd/tests/test_config.py
index 581e930..106d72c 100644
--- a/nova_lxd/tests/test_config.py
+++ b/nova_lxd/tests/test_config.py
@@ -16,14 +16,12 @@
import ddt
import mock
-from nova import objects
from nova import test
from nova.tests.unit import fake_network
from nova_lxd.nova.virt.lxd import config
from nova_lxd.nova.virt.lxd import utils as container_dir
from nova_lxd.tests import stubs
-from nova_lxd.tests import fake_api
@ddt.ddt
@@ -85,10 +83,9 @@ def test_config_instance_options(self):
instance = stubs._fake_instance()
config = {}
container_config = self.config.config_instance_options(config,
- instance)
+ instance)
self.assertEqual({'boot.autostart': 'True'}, container_config)
-
def test_create_container_source(self):
instance = stubs._fake_instance()
config = self.config.get_container_source(instance)
diff --git a/nova_lxd/tests/test_migrate.py b/nova_lxd/tests/test_migrate.py
index 18145a1..016baef 100644
--- a/nova_lxd/tests/test_migrate.py
+++ b/nova_lxd/tests/test_migrate.py
@@ -13,22 +13,17 @@
# License for the specific language governing permissions and limitations
# under the License.
-import os
-import shutil
-
import mock
from nova import test
from nova.virt import fake
from oslo_config import cfg
-from oslo_utils import fileutils
from nova_lxd.nova.virt.lxd import config
from nova_lxd.nova.virt.lxd import migrate
from nova_lxd.nova.virt.lxd import operations
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
CONF = cfg.CONF
@@ -61,11 +56,13 @@ def test_migrate_disk_power_off_resize(self):
mock_profile_update
):
self.assertEqual('',
- self.migrate.migrate_disk_and_power_off(
- context, instance, dest, flavor, network_info))
+ self.migrate.migrate_disk_and_power_off(
+ context, instance, dest, flavor,
+ network_info))
mock_container_defined.assert_called_once_with(instance.name,
instance)
- mock_create_profile.assert_called_once_with(instance, network_info)
+ mock_create_profile.assert_called_once_with(instance,
+ network_info)
def test_confirm_migration(self):
migration = mock.Mock()
@@ -76,14 +73,19 @@ def test_confirm_migration(self):
mock.patch.object(session.LXDAPISession, 'container_defined'),
mock.patch.object(session.LXDAPISession, 'profile_delete'),
mock.patch.object(session.LXDAPISession, 'container_destroy'),
- mock.patch.object(operations.LXDContainerOperations, 'unplug_vifs'),
+ mock.patch.object(operations.LXDContainerOperations,
+ 'unplug_vifs'),
) as (
- mock_container_defined,
- mock_profile_delete,
- mock_container_destroy,
- mock_unplug_vifs):
- self.assertEqual(None,
- self.migrate.confirm_migration(migration, instance, network_info))
- mock_container_defined.assert_called_once_with(instance.name, instance)
- mock_profile_delete.assert_called_once_with(instance)
- mock_unplug_vifs.assert_called_once_with(instance, network_info)
+ mock_container_defined,
+ mock_profile_delete,
+ mock_container_destroy,
+ mock_unplug_vifs):
+ self.assertEqual(None,
+ self.migrate.confirm_migration(migration,
+ instance,
+ network_info))
+ mock_container_defined.assert_called_once_with(instance.name,
+ instance)
+ mock_profile_delete.assert_called_once_with(instance)
+ mock_unplug_vifs.assert_called_once_with(instance,
+ network_info)
More information about the lxc-devel
mailing list