From b123580ca38d1223f3b56f9dff4cbdae4653565c Mon Sep 17 00:00:00 2001 From: Daniel Salinas Date: Tue, 28 May 2013 14:20:27 -0500 Subject: [PATCH] merged in migration code Change-Id: Id526ba721ba3c531f75768f2d5552189d7e1e3c5 --- debian/changelog | 4 +- debian/rules | 4 +- etc/nova/rootwrap.d/openvz.filters | 13 + nova/tests/openvz/__init__.py | 16 + nova/tests/openvz/fakes.py | 892 ++++++++ nova/tests/openvz/test_driver.py | 1987 +++++++++++++++++ nova/tests/openvz/test_ext_storage.py | 107 + nova/tests/openvz/test_file.py | 126 ++ nova/tests/openvz/test_network.py | 214 ++ nova/tests/openvz/test_utils.py | 302 +++ nova/virt/openvz/driver.py | 462 +++- nova/virt/openvz/file.py | 6 +- nova/virt/openvz/file_ext/__init__.py | 16 + nova/virt/openvz/file_ext/ext_storage.py | 31 +- nova/virt/openvz/migration.py | 369 +++ .../virt/openvz/migration_drivers/__init__.py | 16 + nova/virt/openvz/migration_drivers/rsync.py | 62 + .../openvz/migration_drivers/transport.py | 72 + nova/virt/openvz/network_drivers/__init__.py | 16 + nova/virt/openvz/network_drivers/tc.py | 2 +- nova/virt/openvz/utils.py | 3 +- nova/virt/openvz/volume.py | 27 +- nova/virt/openvz/volume_drivers/__init__.py | 16 + nova/virt/openvz/volume_drivers/iscsi.py | 9 +- 24 files changed, 4689 insertions(+), 83 deletions(-) create mode 100644 nova/tests/openvz/__init__.py create mode 100644 nova/tests/openvz/fakes.py create mode 100644 nova/tests/openvz/test_driver.py create mode 100644 nova/tests/openvz/test_ext_storage.py create mode 100644 nova/tests/openvz/test_file.py create mode 100644 nova/tests/openvz/test_network.py create mode 100644 nova/tests/openvz/test_utils.py create mode 100644 nova/virt/openvz/migration.py create mode 100644 nova/virt/openvz/migration_drivers/__init__.py create mode 100644 nova/virt/openvz/migration_drivers/rsync.py create mode 100644 nova/virt/openvz/migration_drivers/transport.py diff --git a/debian/changelog b/debian/changelog index 91c89ef..2bfc953 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,6 +1,8 @@ -openvz-nova-driver (1.0-3) precise; urgency=low +openvz-nova-driver (1.1-02) precise; urgency=low * Released for known working distributions. (Closes: #XXXXXX) * Releasing as noarch + * Released Migrations + * Fixed broken copyright headers -- Daniel Salinas Mon, 07 May 2013 15:51:03 -0500 diff --git a/debian/rules b/debian/rules index 5ec278d..61e34f0 100755 --- a/debian/rules +++ b/debian/rules @@ -16,9 +16,11 @@ clean: binary-arch: binary-indep binary-indep: - dh_installdirs /usr/lib/python$(PYVERS)/dist-packages/nova/virt /etc/nova/rootwrap.d + dh_installdirs /usr/lib/python$(PYVERS)/dist-packages/nova/virt /usr/lib/python$(PYVERS)/dist-packages/nova/tests /etc/nova/rootwrap.d cp -R $(CURDIR)/nova/virt/openvz $(CURDIR)/debian/openvz-nova-driver/usr/lib/python$(PYVERS)/dist-packages/nova/virt + cp -R $(CURDIR)/nova/tests/openvz $(CURDIR)/debian/openvz-nova-driver/usr/lib/python$(PYVERS)/dist-packages/nova/tests install -d -m 755 $(CURDIR)/debian/openvz-nova-driver/usr/lib/python$(PYVERS)/dist-packages/nova/virt + install -d -m 755 $(CURDIR)/debian/openvz-nova-driver/usr/lib/python$(PYVERS)/dist-packages/nova/tests install -D -m 0400 $(CURDIR)/etc/nova/rootwrap.d/openvz.filters $(CURDIR)/debian/openvz-nova-driver/etc/nova/rootwrap.d/ dh_testdir dh_testroot diff --git a/etc/nova/rootwrap.d/openvz.filters b/etc/nova/rootwrap.d/openvz.filters index 73de16f..0b9766c 100644 --- a/etc/nova/rootwrap.d/openvz.filters +++ b/etc/nova/rootwrap.d/openvz.filters @@ -1,6 +1,7 @@ # nova-rootwrap command filters for openvz nodes # This file should be owned by (and only-writeable by) the root user +[Filters] # nova/virt/openvz/utils.py: 'mount', '-o', 'defaults' ... mount: CommandFilter, /bin/mount, root @@ -70,3 +71,15 @@ sfdisk: CommandFilter, /sbin/sfdisk, root # nova/virt/openvz/volume.py mknod: CommandFilter, /bin/mknod, root + +# nova/virt/openvz/driver.py +vzmigrate: CommandFilter, /usr/sbin/vzmigrate, root + +# nova/virt/openvz/migrate.py +cp: CommandFilter, /bin/cp, root + +# nova/virt/openvz/utils.py +tar: CommandFilter, /bin/tar, root + +# nova/virt/openvz/migration_drivers/rsync.py +rsync: CommandFilter, /usr/bin/rsync, root diff --git a/nova/tests/openvz/__init__.py b/nova/tests/openvz/__init__.py new file mode 100644 index 0000000..3e1c627 --- /dev/null +++ b/nova/tests/openvz/__init__.py @@ -0,0 +1,16 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2013 Rackspace +# 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. diff --git a/nova/tests/openvz/fakes.py b/nova/tests/openvz/fakes.py new file mode 100644 index 0000000..323f952 --- /dev/null +++ b/nova/tests/openvz/fakes.py @@ -0,0 +1,892 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2013 Rackspace +# 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 Cheetah import Template +import json +from nova.compute import power_state +from nova import exception +from nova.virt.openvz import utils as ovz_utils +import os +from oslo.config import cfg +import random +import socket + +CONF = cfg.CONF + +global _ovz_tc_available_ids +global _ovz_tc_inflight_ids +_ovz_tc_available_ids = None +_ovz_tc_inflight_ids = None + + +class FakeOVZExtStorage(object): + def __init__(self, instance_id): + self.instance_id = instance_id + self._volumes = {} + + def add_volume(self, mount_point, connection_info): + self._volumes[mount_point] = connection_info + + def remove_volume(self, mount_point): + self._volumes.pop(mount_point) + + +class FakeOVZTcRules(object): + if not _ovz_tc_available_ids: + _ovz_tc_available_ids = list() + + if not _ovz_tc_inflight_ids: + _ovz_tc_inflight_ids = list() + + def __init__(self): + if not len(FakeOVZTcRules._ovz_tc_available_ids): + FakeOVZTcRules._ovz_tc_available_ids = [ + i for i in range(1, CONF.ovz_tc_id_max) + ] + self.instance_type = {'memory_mb': 512} + self._remove_used_ids() + + def instance_info(self, instance_id, address, vz_iface): + if not instance_id: + self.instance_type = dict() + self.instance_type['memory_mb'] = 2048 + + self.address = address + self.vz_iface = vz_iface + self.bandwidth = int( + round(self.instance_type['memory_mb'] / + CONF.ovz_memory_unit_size)) * CONF.ovz_tc_mbit_per_unit + self.tc_id = self._get_instance_tc_id() + if not self.tc_id: + self.tc_id = self.get_id() + + self._save_instance_tc_id() + + def get_id(self): + self._remove_used_ids() + tc_id = self._pull_id() + while tc_id in FakeOVZTcRules._ovz_tc_inflight_ids: + tc_id = self._pull_id() + self._reserve_id(tc_id) + return id + + def container_start(self): + template = self._load_template('tc_container_start.template') + search_list = { + 'prio': self.tc_id, + 'host_iface': CONF.ovz_tc_host_slave_device, + 'vz_iface': self.vz_iface, + 'bandwidth': self.bandwidth, + 'vz_address': self.address, + 'line_speed': CONF.ovz_tc_max_line_speed + } + return self._fill_template(template, search_list).splitlines() + + def container_stop(self): + template = self._load_template('tc_container_stop.template') + search_list = { + 'prio': self.tc_id, + 'host_iface': CONF.ovz_tc_host_slave_device, + 'vz_iface': self.vz_iface, + 'bandwidth': self.bandwidth, + 'vz_address': self.address + } + return self._fill_template(template, search_list).splitlines() + + def host_start(self): + template = self._load_template('tc_host_start.template') + search_list = { + 'host_iface': CONF.ovz_tc_host_slave_device, + 'line_speed': CONF.ovz_tc_max_line_speed + } + return self._fill_template(template, search_list).splitlines() + + def host_stop(self): + template = self._load_template('tc_host_stop.template') + search_list = { + 'host_iface': CONF.ovz_tc_host_slave_device + } + return self._fill_template(template, search_list).splitlines() + + def _load_template(self, template_name): + full_template_path = '%s/%s' % ( + CONF.ovz_tc_template_dir, template_name) + full_template_path = os.path.abspath(full_template_path) + try: + template_file = open(full_template_path).read() + return template_file + except Exception as err: + raise exception.FileNotFound(err) + + def _fill_template(self, template, search_list): + return str(Template.Template(template, searchList=[search_list])) + + def _pull_id(self): + return _ovz_tc_available_ids[random.randint( + 0, len(_ovz_tc_available_ids) - 1)] + + def _list_existing_ids(self): + return [1, 3, 6] + + def _reserve_id(self, tc_id): + FakeOVZTcRules._ovz_tc_inflight_ids.append(tc_id) + FakeOVZTcRules._ovz_tc_available_ids.remove(tc_id) + + def _remove_used_ids(self): + used_ids = self._list_existing_ids() + for tc_id in used_ids: + if tc_id in FakeOVZTcRules._ovz_tc_available_ids: + FakeOVZTcRules._ovz_tc_available_ids.remove(tc_id) + + def _save_instance_tc_id(self): + return + + def _get_instance_tc_id(self): + return 1 + + +class Context(object): + def __init__(self): + self.is_admin = False + self.read_deleted = "yes" + + +class AdminContext(Context): + def __init__(self): + super(AdminContext, self).__init__() + self.is_admin = True + + +# Stubs for faked file operations to allow unittests to test code paths +# without actually leaving file turds around the test box. +class FakeOvzFile(object): + def __init__(self, filename, perms): + self.filename = filename + self.permissions = perms + self.contents = [] + + def __enter__(self): + """ + This may feel dirty but we need to be able to read and write files + as a non priviledged user so we need to change the permissions to + be more open for our file operations and then secure them once we + are done. + """ + if not self.exists(): + self.make_path() + self.touch() + + self.set_permissions(666) + + def __exit__(self, _type, value, tb): + if self.exists(): + self.set_permissions(self.permissions) + + def exists(self): + return True + + def make_path(self, path=None): + return + + def touch(self): + return + + def set_permissions(self, perms): + return + + def read(self): + return + + def run_contents(self, raise_on_error=True): + return + + def set_contents(self, contents): + self.contents = contents + + def make_proper_script(self): + return + + def append(self, contents): + if not isinstance(contents, list): + contents = [str(contents)] + self.contents = self.contents + contents + + def prepend(self, contents): + if not isinstance(contents, list): + contents = [str(contents)] + self.contents = contents + self.contents + + def write(self): + return + + +class FakeOVZShutdownFile(FakeOvzFile): + def __init__(self, instance_id, permissions): + filename = "%s/%s.shutdown" % (CONF.ovz_config_dir, instance_id) + filename = os.path.abspath(filename) + super(FakeOVZShutdownFile, self).__init__(filename, permissions) + + +class FakeOVZBootFile(FakeOvzFile): + def __init__(self, instance_id, permissions): + filename = "%s/%s.shutdown" % (CONF.ovz_config_dir, instance_id) + filename = os.path.abspath(filename) + super(FakeOVZBootFile, self).__init__(filename, permissions) + + +class FakeOVZNetworkFile(FakeOvzFile): + def __init__(self, filename): + self.filename = filename + super(FakeOVZNetworkFile, self).__init__(filename, 644) + + +class FakeOVZInstanceVolumeOps(object): + def __init__(self, instance): + self.instance = instance + + def attach_all_volumes(self): + return + + def detach_all_volumes(self): + return + + +class FakeOVZISCSIStorageDriver(object): + def init_iscsi_device(self): + return + + def disconnect_iscsi_volume(self): + return + + def discover_volume(self): + return + + def setup(self): + return + + def prepare_filesystem(self): + return + + def attach(self): + return + + def detach(self, container_is_running=True): + return + + def write_and_close(self): + return + + +class FakeAggregate(object): + def __init__(self): + self.id = 1 + + +class FakePosixStatVFSResult(object): + def __init__(self): + self.f_frsize = 4096 + self.f_blocks = 61005206 + self.f_bavail = 58342965 + self.f_bfree = 58342965 + + +METAKEY = 'tc_id' +METAVALUE = '1002' +METADATA = {METAKEY: METAVALUE} + +STATVFSRESULT = FakePosixStatVFSResult() + +AGGREGATE = FakeAggregate() + +ROOTPASS = '2s3cUr3' + +USER = {'user': 'admin', 'role': 'admin', 'id': 1} + +PROJECT = {'name': 'test', 'id': 2} + +ADMINCONTEXT = AdminContext() + +CONTEXT = Context() + +DESTINATION = '127.0.7.1' + +BDM = { + 'block_device_mapping': [ + { + 'connection_info': { + 'data': { + 'volume_id': 'c49a7247-731e-4135-8420-7a3c67002582' + }, + 'driver_volume_type': 'iscsi', + 'mount_device': '/dev/sdgg' + }, + 'mount_device': '/dev/sdgg' + } + ] +} + +INSTANCETYPE = { + 'id': 1, + 'vcpus': 1, + 'name': 'm1.small', + 'memory_mb': 2048, + 'swap': 0, + 'root_gb': 20 +} + +INSTANCE = { + "image_ref": 1, + "name": "instance-00001002", + "instance_type_id": 1, + "id": 1002, + "uuid": "07fd1fc9-eb75-4375-88d5-6247ce2fb7e4", + "hostname": "test.foo.com", + "power_state": power_state.RUNNING, + "admin_pass": ROOTPASS, + "user_id": USER['id'], + "project_id": PROJECT['id'], + "memory_mb": INSTANCETYPE['memory_mb'], + "block_device_mapping": BDM, + "system_metadata": [ + {'key': METAKEY, 'value': METAVALUE}, + {'key': 'instance_type_name', 'value': INSTANCETYPE['name']}, + {'key': 'instance_type_root_gb', 'value': INSTANCETYPE['root_gb']}, + {'key': 'instance_type_memory_mb', 'value': INSTANCETYPE['memory_mb']}, + {'key': 'instance_type_vcpus', 'value': INSTANCETYPE['vcpus']} + ] +} + +BLKID = '0670a412-bba5-4ef4-a954-7fec8f2a06aa\n' + +IMAGEPATH = '%s/%s.tar.gz' % \ + (CONF.ovz_image_template_dir, INSTANCE['image_ref']) + +INSTANCES = [INSTANCE, INSTANCE] + +RES_PERCENT = .50 + +RES_OVER_PERCENT = 1.50 + +VZLIST = "\t1001\n\t%d\n\t1003\n\t1004\n" % (INSTANCE['id'],) + +VZLISTDETAIL = " %d running %s" \ + % (INSTANCE['id'], INSTANCE['hostname']) + +FINDBYNAME = VZLISTDETAIL.split() +FINDBYNAME = {'name': FINDBYNAME[2], 'id': int(FINDBYNAME[0]), + 'state': FINDBYNAME[1]} +FINDBYNAMENOSTATE = VZLISTDETAIL.split() +FINDBYNAMENOSTATE = { + 'name': FINDBYNAMENOSTATE[2], 'id': int(FINDBYNAMENOSTATE[0]), + 'state': '-'} +FINDBYNAMESHUTDOWN = VZLISTDETAIL.split() +FINDBYNAMESHUTDOWN = { + 'name': FINDBYNAMESHUTDOWN[2], 'id': int(FINDBYNAMESHUTDOWN[0]), + 'state': 'stopped'} + +VZNAME = """\tinstance-00001001\n""" + +VZNAMES = """\tinstance-00001001\n\t%s + \tinstance-00001003\n\tinstance-00001004\n""" % ( + INSTANCE['name'],) + +GOODSTATUS = { + 'state': power_state.RUNNING, + 'max_mem': 0, + 'mem': 0, + 'num_cpu': 0, + 'cpu_time': 0 +} + +NOSTATUS = { + 'state': power_state.NOSTATE, + 'max_mem': 0, + 'mem': 0, + 'num_cpu': 0, + 'cpu_time': 0 +} + +SHUTDOWNSTATUS = { + 'state': power_state.SHUTDOWN, + 'max_mem': 0, + 'mem': 0, + 'num_cpu': 0, + 'cpu_time': 0 +} + +ERRORMSG = "vz command ran but output something to stderr" + +MEMINFO = """MemTotal: 506128 kB +MemFree: 291992 kB +Buffers: 44512 kB +Cached: 64708 kB +SwapCached: 0 kB +Active: 106496 kB +Inactive: 62948 kB +Active(anon): 62108 kB +Inactive(anon): 496 kB +Active(file): 44388 kB +Inactive(file): 62452 kB +Unevictable: 2648 kB +Mlocked: 2648 kB +SwapTotal: 1477624 kB +SwapFree: 1477624 kB +Dirty: 0 kB +Writeback: 0 kB +AnonPages: 62908 kB +Mapped: 14832 kB +Shmem: 552 kB +Slab: 27988 kB +SReclaimable: 17280 kB +SUnreclaim: 10708 kB +KernelStack: 1448 kB +PageTables: 3092 kB +NFS_Unstable: 0 kB +Bounce: 0 kB +WritebackTmp: 0 kB +CommitLimit: 1730688 kB +Committed_AS: 654760 kB +VmallocTotal: 34359738367 kB +VmallocUsed: 24124 kB +VmallocChunk: 34359711220 kB +HardwareCorrupted: 0 kB +HugePages_Total: 0 +HugePages_Free: 0 +HugePages_Rsvd: 0 +HugePages_Surp: 0 +Hugepagesize: 2048 kB +DirectMap4k: 8128 kB +DirectMap2M: 516096 kB +""" + +PROCINFO = """ +processor : 0 +vendor_id : GenuineIntel +cpu family : 6 +model : 58 +model name : Intel(R) Core(TM) i7-3610QM CPU @ 2.30GHz +stepping : 9 +microcode : 0x13 +cpu MHz : 1200.000 +cache size : 6144 KB +physical id : 0 +siblings : 8 +core id : 0 +cpu cores : 4 +apicid : 0 +initial apicid : 0 +fpu : yes +fpu_exception : yes +cpuid level : 13 +wp : yes +flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca +bogomips : 4589.55 +clflush size : 64 +cache_alignment : 64 +address sizes : 36 bits physical, 48 bits virtual +power management: + +processor : 1 +vendor_id : GenuineIntel +cpu family : 6 +model : 58 +model name : Intel(R) Core(TM) i7-3610QM CPU @ 2.30GHz +stepping : 9 +microcode : 0x13 +cpu MHz : 1200.000 +cache size : 6144 KB +physical id : 0 +siblings : 8 +core id : 0 +cpu cores : 4 +apicid : 1 +initial apicid : 1 +fpu : yes +fpu_exception : yes +cpuid level : 13 +wp : yes +flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca +bogomips : 4589.36 +clflush size : 64 +cache_alignment : 64 +address sizes : 36 bits physical, 48 bits virtual +power management: + +processor : 2 +vendor_id : GenuineIntel +cpu family : 6 +model : 58 +model name : Intel(R) Core(TM) i7-3610QM CPU @ 2.30GHz +stepping : 9 +microcode : 0x13 +cpu MHz : 1200.000 +cache size : 6144 KB +physical id : 0 +siblings : 8 +core id : 1 +cpu cores : 4 +apicid : 2 +initial apicid : 2 +fpu : yes +fpu_exception : yes +cpuid level : 13 +wp : yes +flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca +bogomips : 4589.36 +clflush size : 64 +cache_alignment : 64 +address sizes : 36 bits physical, 48 bits virtual +power management: + +processor : 3 +vendor_id : GenuineIntel +cpu family : 6 +model : 58 +model name : Intel(R) Core(TM) i7-3610QM CPU @ 2.30GHz +stepping : 9 +microcode : 0x13 +cpu MHz : 1200.000 +cache size : 6144 KB +physical id : 0 +siblings : 8 +core id : 1 +cpu cores : 4 +apicid : 3 +initial apicid : 3 +fpu : yes +fpu_exception : yes +cpuid level : 13 +wp : yes +flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca +bogomips : 4589.36 +clflush size : 64 +cache_alignment : 64 +address sizes : 36 bits physical, 48 bits virtual +power management: + +processor : 4 +vendor_id : GenuineIntel +cpu family : 6 +model : 58 +model name : Intel(R) Core(TM) i7-3610QM CPU @ 2.30GHz +stepping : 9 +microcode : 0x13 +cpu MHz : 1200.000 +cache size : 6144 KB +physical id : 0 +siblings : 8 +core id : 2 +cpu cores : 4 +apicid : 4 +initial apicid : 4 +fpu : yes +fpu_exception : yes +cpuid level : 13 +wp : yes +flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca +bogomips : 4589.37 +clflush size : 64 +cache_alignment : 64 +address sizes : 36 bits physical, 48 bits virtual +power management: + +processor : 5 +vendor_id : GenuineIntel +cpu family : 6 +model : 58 +model name : Intel(R) Core(TM) i7-3610QM CPU @ 2.30GHz +stepping : 9 +microcode : 0x13 +cpu MHz : 1200.000 +cache size : 6144 KB +physical id : 0 +siblings : 8 +core id : 2 +cpu cores : 4 +apicid : 5 +initial apicid : 5 +fpu : yes +fpu_exception : yes +cpuid level : 13 +wp : yes +flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca +bogomips : 4589.36 +clflush size : 64 +cache_alignment : 64 +address sizes : 36 bits physical, 48 bits virtual +power management: + +processor : 6 +vendor_id : GenuineIntel +cpu family : 6 +model : 58 +model name : Intel(R) Core(TM) i7-3610QM CPU @ 2.30GHz +stepping : 9 +microcode : 0x13 +cpu MHz : 1200.000 +cache size : 6144 KB +physical id : 0 +siblings : 8 +core id : 3 +cpu cores : 4 +apicid : 6 +initial apicid : 6 +fpu : yes +fpu_exception : yes +cpuid level : 13 +wp : yes +flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca +bogomips : 4589.37 +clflush size : 64 +cache_alignment : 64 +address sizes : 36 bits physical, 48 bits virtual +power management: + +processor : 7 +vendor_id : GenuineIntel +cpu family : 6 +model : 58 +model name : Intel(R) Core(TM) i7-3610QM CPU @ 2.30GHz +stepping : 9 +microcode : 0x13 +cpu MHz : 1200.000 +cache size : 6144 KB +physical id : 0 +siblings : 8 +core id : 3 +cpu cores : 4 +apicid : 7 +initial apicid : 7 +fpu : yes +fpu_exception : yes +cpuid level : 13 +wp : yes +flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca +bogomips : 4589.37 +clflush size : 64 +cache_alignment : 64 +address sizes : 36 bits physical, 48 bits virtual +power management: +""" + +UTILITY = { + 'CTIDS': { + 1: { + + } + }, + 'UTILITY': 10000, + 'TOTAL': 1000, + 'UNITS': 100000, + 'MEMORY_MB': 512000, + 'CPULIMIT': 2400 +} + +CPUUNITSCAPA = { + 'total': 500000, + 'subscribed': 1000 +} + +CPUCHECKCONT = """VEID CPUUNITS +------------------------- +0 1000 +26 25000 +27 25000 +Current CPU utilization: 51000 +Power of the node: 758432 +""" + +CPUCHECKNOCONT = """Current CPU utilization: 51000 +Power of the node: 758432 +""" + +FILECONTENTS = """mount UUID=FEE52433-F693-448E-B6F6-AA6D0124118B /mnt/foo + mount --bind /mnt/foo /vz/private/1/mnt/foo + """ + +NETWORKINFO = [ + [ + { + u'bridge': u'br100', + u'multi_host': False, + u'bridge_interface': u'eth0', + u'vlan': None, + u'id': 1, + u'injected': True, + u'cidr': u'10.0.2.0/24', + u'cidr_v6': None + }, + { + u'should_create_bridge': True, + u'dns': [ + u'192.168.2.1' + ], + u'label': u'usernet', + u'broadcast': u'10.0.2.255', + u'ips': [ + { + u'ip': u'10.0.2.16', + u'netmask': u'255.255.255.0', + u'enabled': u'1' + } + ], + u'mac': u'02:16:3e:0c:2c:08', + u'rxtx_cap': 0, + u'should_create_vlan': True, + u'dhcp_server': u'10.0.2.2', + u'gateway': u'10.0.2.2' + } + ], + [ + { + u'bridge': u'br200', + u'multi_host': False, + u'bridge_interface': u'eth1', + u'vlan': None, + u'id': 2, + u'injected': True, + u'cidr': u'10.0.4.0/24', + u'cidr_v6': None + }, + { + u'should_create_bridge': False, + u'dns': [ + u'192.168.2.1' + ], + u'label': u'infranet', + u'broadcast': u'10.0.4.255', + u'ips': [ + { + u'ip': u'10.0.4.16', + u'netmask': u'255.255.255.0', + u'enabled': u'1' + } + ], + u'mac': u'02:16:3e:40:5e:1b', + u'rxtx_cap': 0, + u'should_create_vlan': False, + u'dhcp_server': u'10.0.2.2', + u'gateway': u'10.0.2.2' + } + ] +] + +INTERFACEINFO = [ + { + 'id': 1002, + 'interface_number': 0, + 'bridge': 'br100', + 'name': 'eth0', + 'vz_host_if': 'veth1002.eth0', + 'mac': '02:16:3e:0c:2c:08', + 'address': '10.0.2.16', + 'netmask': '255.255.255.0', + 'gateway': '10.0.2.2', + 'broadcast': '10.0.2.255', + 'dns': '192.168.2.1', + 'address_v6': None, + 'gateway_v6': None, + 'netmask_v6': None + }, + { + 'id': 1002, + 'interface_number': 1, + 'bridge': 'br200', + 'name': 'eth1', + 'vz_host_if': 'veth1002.eth1', + 'mac': '02:16:3e:40:5e:1b', + 'address': '10.0.4.16', + 'netmask': '255.255.255.0', + 'gateway': '10.0.2.2', + 'broadcast': '10.0.4.255', + 'dns': '192.168.2.1', + 'address_v6': None, + 'gateway_v6': None, + 'netmask_v6': None + } +] + +TEMPFILE = '/tmp/foo/file' + +NETTEMPLATE = """ + # This file describes the network interfaces available on your system + # and how to activate them. For more information, see interfaces(5). + + # The loopback network interface + auto lo + iface lo inet loopback + + #for $ifc in $interfaces + auto ${ifc.name} + iface ${ifc.name} inet static + address ${ifc.address} + netmask ${ifc.netmask} + broadcast ${ifc.broadcast} + gateway ${ifc.gateway} + dns-nameservers ${ifc.dns} + + #if $use_ipv6 + iface ${ifc.name} inet6 static + address ${ifc.address_v6} + netmask ${ifc.netmask_v6} + gateway ${ifc.gateway_v6} + #end if + + #end for + """ + +HOSTSTATS = { + 'vcpus': 12, + 'vcpus_used': 2, + 'cpu_info': json.dumps(PROCINFO), + 'memory_mb': 36864, + 'memory_mb_used': 2048, + 'host_memory_total': 36864, + 'host_memory_free': 34816, + 'disk_total': 232, + 'disk_used': 10, + 'disk_available': 222, + 'local_gb': 232, + 'local_gb_used': 10, + 'hypervisor_type': ovz_utils.get_hypervisor_type(), + 'hypervisor_version': '3.2.0-31-generic', + 'hypervisor_hostname': socket.gethostname() +} + +FILESTOINJECT = [ + ['/tmp/testfile1', FILECONTENTS], + ['/tmp/testfile2', FILECONTENTS] +] + +OSLISTDIR = ['1002.start', '1002.stop'] + +INITIATORNAME = 'iqn.1993-08.org.debian:01:f424a54e43' + +ISCSIINITIATOR = """## DO NOT EDIT OR REMOVE THIS FILE! +## If you remove this file, the iSCSI daemon will not start. +## If you change the InitiatorName, existing access control lists +## may reject this initiator. The InitiatorName must be unique +## for each iSCSI initiator. Do NOT duplicate iSCSI InitiatorNames. +InitiatorName=%s +""" % INITIATORNAME + +PRIVVMPAGES_2048 = "%s 524288\n" % INSTANCE['id'] +PRIVVMPAGES_1024 = "1003 262144\n" +PRIVVMPAGES = PRIVVMPAGES_2048 + PRIVVMPAGES_1024 + +UNAME = ('Linux', 'imsplitbit-M17xR4', '3.2.0-31-generic', + '#50-Ubuntu SMP Fri Sep 7 16:16:45 UTC 2012', 'x86_64', 'x86_64') diff --git a/nova/tests/openvz/test_driver.py b/nova/tests/openvz/test_driver.py new file mode 100644 index 0000000..63a5bc4 --- /dev/null +++ b/nova/tests/openvz/test_driver.py @@ -0,0 +1,1987 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2013 Rackspace +# 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 base64 +import mox +from nova.compute import manager +from nova.compute import power_state +from nova import exception +from nova.openstack.common import processutils +from nova import test +from nova.tests.openvz import fakes +from nova.virt.openvz import driver as openvz_conn +from nova.virt.openvz.file_ext import ext_storage +from nova.virt.openvz import migration +from nova.virt.openvz import utils as ovz_utils +import os +from oslo.config import cfg + +CONF = cfg.CONF + + +class OpenVzDriverTestCase(test.TestCase): + def setUp(self): + super(OpenVzDriverTestCase, self).setUp() + try: + CONF.injected_network_template + except AttributeError: + CONF.register_opt( + cfg.StrOpt('injected_network_template', + default='nova/virt/interfaces.template', + help='Stub for network template ' + 'for testing purposes')) + CONF.use_ipv6 = False + self.ext_str_filename = '%s/%s.ext_storage' % (CONF.ovz_config_dir, + fakes.INSTANCE['id']) + self.ext_str_filename = os.path.abspath(self.ext_str_filename) + self.ext_str_permissions = 600 + + def test_legacy_nwinfo(self): + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + self.assertTrue(ovz_conn.legacy_nwinfo()) + + def test_start_success(self): + # Testing happy path :-D + # Mock the objects needed for this test to succeed. + self.mox.StubOutWithMock(openvz_conn.ovzboot, 'OVZBootFile') + openvz_conn.ovzboot.OVZBootFile( + fakes.INSTANCE['id'], mox.IgnoreArg()).AndReturn( + fakes.FakeOVZBootFile(fakes.INSTANCE['id'], 700)) + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'vzctl', 'start', fakes.INSTANCE['id'], + run_as_root=True).AndReturn( + ('', fakes.ERRORMSG)) + conn = openvz_conn.OpenVzDriver(manager.ComputeVirtAPI(None), False) + self.mox.StubOutWithMock(conn.virtapi, 'instance_update') + conn.virtapi.instance_update( + mox.IgnoreArg(), fakes.INSTANCE['uuid'], + {'power_state': power_state.RUNNING}) + # Start the tests + self.mox.ReplayAll() + # Create our connection object. For all intents and purposes this is + # a real OpenVzDriver object. + conn._start(fakes.INSTANCE) + + def test_start_fail(self): + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'vzctl', 'start', fakes.INSTANCE['id'], + run_as_root=True).AndRaise( + exception.InstanceUnacceptable(fakes.ERRORMSG)) + self.mox.ReplayAll() + + conn = openvz_conn.OpenVzDriver(manager.ComputeVirtAPI(None), False) + self.assertRaises( + exception.InstanceUnacceptable, conn._start, fakes.INSTANCE) + + def test_list_instances_success(self): + # Testing happy path of OpenVzDriver.list_instances() + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'vzlist', '--all', '--no-header', '--output', 'ctid', + run_as_root=True).AndReturn( + (fakes.VZLIST, fakes.ERRORMSG)) + # Start test + self.mox.ReplayAll() + conn = openvz_conn.OpenVzDriver(manager.ComputeVirtAPI(None), False) + vzs = conn.list_instances() + self.assertEqual(vzs.__class__, list) + + def test_list_instances_fail(self): + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'vzlist', '--all', '--no-header', '--output', 'ctid', + run_as_root=True).AndRaise( + exception.InstanceUnacceptable(fakes.ERRORMSG)) + # Start test + self.mox.ReplayAll() + conn = openvz_conn.OpenVzDriver(manager.ComputeVirtAPI(None), False) + self.assertRaises(exception.InstanceUnacceptable, conn.list_instances) + + def test_create_vz_success(self): + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'vzctl', 'create', fakes.INSTANCE['id'], '--ostemplate', + fakes.INSTANCE['image_ref'], run_as_root=True).AndReturn( + ('', fakes.ERRORMSG)) + self.mox.ReplayAll() + conn = openvz_conn.OpenVzDriver(manager.ComputeVirtAPI(None), False) + conn._create_vz(fakes.INSTANCE) + + def test_create_vz_fail(self): + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'vzctl', 'create', fakes.INSTANCE['id'], '--ostemplate', + fakes.INSTANCE['image_ref'], run_as_root=True).AndRaise( + exception.InstanceUnacceptable(fakes.ERRORMSG)) + self.mox.ReplayAll() + conn = openvz_conn.OpenVzDriver(manager.ComputeVirtAPI(None), False) + self.assertRaises( + exception.InstanceUnacceptable, conn._create_vz, fakes.INSTANCE) + + def test_set_vz_os_hint_success(self): + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'vzctl', 'set', fakes.INSTANCE['id'], '--save', '--ostemplate', + 'ubuntu', run_as_root=True).AndReturn( + ('', fakes.ERRORMSG)) + self.mox.ReplayAll() + conn = openvz_conn.OpenVzDriver(manager.ComputeVirtAPI(None), False) + conn._set_vz_os_hint(fakes.INSTANCE) + + def test_set_vz_os_hint_failure(self): + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'vzctl', 'set', fakes.INSTANCE['id'], '--save', '--ostemplate', + 'ubuntu', run_as_root=True).AndRaise( + exception.InstanceUnacceptable(fakes.ERRORMSG)) + self.mox.ReplayAll() + conn = openvz_conn.OpenVzDriver(manager.ComputeVirtAPI(None), False) + self.assertRaises( + exception.InstanceUnacceptable, conn._set_vz_os_hint, + fakes.INSTANCE) + + def test_configure_vz_success(self): + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'vzctl', 'set', fakes.INSTANCE['id'], '--save', '--applyconfig', + 'basic', run_as_root=True).AndReturn( + ('', fakes.ERRORMSG)) + self.mox.ReplayAll() + conn = openvz_conn.OpenVzDriver(manager.ComputeVirtAPI(None), False) + conn._configure_vz(fakes.INSTANCE) + + def test_configure_vz_failure(self): + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'vzctl', 'set', fakes.INSTANCE['id'], '--save', '--applyconfig', + 'basic', run_as_root=True).AndRaise( + exception.InstanceUnacceptable(fakes.ERRORMSG)) + self.mox.ReplayAll() + conn = openvz_conn.OpenVzDriver(manager.ComputeVirtAPI(None), False) + self.assertRaises( + exception.InstanceUnacceptable, conn._configure_vz, fakes.INSTANCE) + + def test_stop_success(self): + self.mox.StubOutWithMock(openvz_conn.ovzshutdown, 'OVZShutdownFile') + openvz_conn.ovzshutdown.OVZShutdownFile( + fakes.INSTANCE['id'], mox.IgnoreArg()).AndReturn( + fakes.FakeOVZShutdownFile(fakes.INSTANCE['id'], 700)) + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'vzctl', 'stop', fakes.INSTANCE['id'], + run_as_root=True).AndReturn( + ('', fakes.ERRORMSG)) + conn = openvz_conn.OpenVzDriver(manager.ComputeVirtAPI(None), False) + self.mox.StubOutWithMock(conn.virtapi, 'instance_update') + conn.virtapi.instance_update( + mox.IgnoreArg(), fakes.INSTANCE['uuid'], + {'power_state': power_state.SHUTDOWN}) + self.mox.ReplayAll() + conn._stop(fakes.INSTANCE) + + def test_stop_failure_on_exec(self): + self.mox.StubOutWithMock(openvz_conn.ovzshutdown, 'OVZShutdownFile') + openvz_conn.ovzshutdown.OVZShutdownFile( + fakes.INSTANCE['id'], mox.IgnoreArg()).AndReturn( + fakes.FakeOVZShutdownFile(fakes.INSTANCE['id'], 700)) + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'vzctl', 'stop', fakes.INSTANCE['id'], run_as_root=True).AndRaise( + exception.InstanceUnacceptable(fakes.ERRORMSG)) + self.mox.ReplayAll() + conn = openvz_conn.OpenVzDriver(manager.ComputeVirtAPI(None), False) + self.assertRaises( + exception.InstanceUnacceptable, conn._stop, fakes.INSTANCE) + + def test_stop_failure_on_db_access(self): + self.mox.StubOutWithMock(openvz_conn.ovzshutdown, 'OVZShutdownFile') + openvz_conn.ovzshutdown.OVZShutdownFile( + fakes.INSTANCE['id'], mox.IgnoreArg()).AndReturn( + fakes.FakeOVZShutdownFile(fakes.INSTANCE['id'], 700)) + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'vzctl', 'stop', fakes.INSTANCE['id'], + run_as_root=True).AndReturn(('', fakes.ERRORMSG)) + conn = openvz_conn.OpenVzDriver(manager.ComputeVirtAPI(None), False) + self.mox.StubOutWithMock(conn.virtapi, 'instance_update') + conn.virtapi.instance_update( + mox.IgnoreArg(), fakes.INSTANCE['uuid'], + {'power_state': power_state.SHUTDOWN}).AndRaise( + exception.InstanceNotFound('FAIL')) + self.mox.ReplayAll() + self.assertRaises( + exception.InstanceNotFound, conn._stop, fakes.INSTANCE) + + def test_set_vmguarpages_success(self): + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'vzctl', 'set', fakes.INSTANCE['id'], '--save', '--vmguarpages', + mox.IgnoreArg(), run_as_root=True).AndReturn(('', fakes.ERRORMSG)) + self.mox.ReplayAll() + conn = openvz_conn.OpenVzDriver(manager.ComputeVirtAPI(None), False) + conn._set_vmguarpages( + fakes.INSTANCE, conn._calc_pages(fakes.INSTANCE['memory_mb'])) + + def test_set_vmguarpages_failure(self): + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'vzctl', 'set', fakes.INSTANCE['id'], '--save', '--vmguarpages', + mox.IgnoreArg(), run_as_root=True).AndRaise( + exception.InstanceUnacceptable(fakes.ERRORMSG)) + self.mox.ReplayAll() + conn = openvz_conn.OpenVzDriver(manager.ComputeVirtAPI(None), False) + self.assertRaises( + exception.InstanceUnacceptable, conn._set_vmguarpages, + fakes.INSTANCE, conn._calc_pages(fakes.INSTANCE['memory_mb'])) + + def test_set_privvmpages_success(self): + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'vzctl', 'set', fakes.INSTANCE['id'], '--save', '--privvmpages', + mox.IgnoreArg(), run_as_root=True).AndReturn(('', fakes.ERRORMSG)) + self.mox.ReplayAll() + conn = openvz_conn.OpenVzDriver(manager.ComputeVirtAPI(None), False) + conn._set_privvmpages( + fakes.INSTANCE, conn._calc_pages(fakes.INSTANCE['memory_mb'])) + + def test_set_privvmpages_failure(self): + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'vzctl', 'set', fakes.INSTANCE['id'], '--save', '--privvmpages', + mox.IgnoreArg(), run_as_root=True).AndRaise( + exception.InstanceUnacceptable(fakes.ERRORMSG)) + self.mox.ReplayAll() + conn = openvz_conn.OpenVzDriver(manager.ComputeVirtAPI(None), False) + self.assertRaises( + exception.InstanceUnacceptable, conn._set_privvmpages, + fakes.INSTANCE, conn._calc_pages(fakes.INSTANCE['memory_mb'])) + + def test_set_kmemsize_success(self): + kmemsize = ((fakes.INSTANCE['memory_mb'] * 1024) * 1024) + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'vzctl', 'set', fakes.INSTANCE['id'], '--save', '--kmemsize', + mox.IgnoreArg(), run_as_root=True).AndReturn(('', '')) + self.mox.ReplayAll() + conn = openvz_conn.OpenVzDriver(manager.ComputeVirtAPI(None), False) + conn._set_kmemsize(fakes.INSTANCE, kmemsize) + + def test_set_kmemsize_failure(self): + kmemsize = ((fakes.INSTANCE['memory_mb'] * 1024) * 1024) + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'vzctl', 'set', fakes.INSTANCE['id'], '--save', '--kmemsize', + mox.IgnoreArg(), run_as_root=True).AndRaise( + exception.InstanceUnacceptable(fakes.ERRORMSG)) + self.mox.ReplayAll() + conn = openvz_conn.OpenVzDriver(manager.ComputeVirtAPI(None), False) + self.assertRaises( + exception.InstanceUnacceptable, conn._set_kmemsize, fakes.INSTANCE, + kmemsize) + + def test_cache_image_path_doesnt_exist(self): + self.mox.StubOutWithMock(openvz_conn.os.path, 'exists') + openvz_conn.os.path.exists(mox.IgnoreArg()).AndReturn(False) + self.mox.StubOutWithMock(openvz_conn.images, 'fetch') + openvz_conn.images.fetch( + fakes.ADMINCONTEXT, fakes.INSTANCE['image_ref'], fakes.IMAGEPATH, + fakes.INSTANCE['user_id'], fakes.INSTANCE['project_id']) + self.mox.ReplayAll() + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + self.assertTrue( + ovz_conn._cache_image(fakes.ADMINCONTEXT, fakes.INSTANCE)) + + def test_cache_image_path_exists(self): + self.mox.StubOutWithMock(openvz_conn.os.path, 'exists') + openvz_conn.os.path.exists(mox.IgnoreArg()).AndReturn(True) + self.mox.ReplayAll() + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + self.assertFalse( + ovz_conn._cache_image(fakes.ADMINCONTEXT, fakes.INSTANCE)) + + def test_access_control_allow(self): + self.mox.StubOutWithMock( + openvz_conn.linux_net.iptables_manager, 'apply') + openvz_conn.linux_net.iptables_manager.apply().MultipleTimes() + self.mox.ReplayAll() + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + ovz_conn._initial_secure_host(fakes.INSTANCE) + ovz_conn._access_control(fakes.INSTANCE, '1.1.1.1') + + def test_access_control_deny_and_port(self): + self.mox.StubOutWithMock( + openvz_conn.linux_net.iptables_manager, 'apply') + openvz_conn.linux_net.iptables_manager.apply().MultipleTimes() + self.mox.ReplayAll() + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + ovz_conn._initial_secure_host(fakes.INSTANCE) + ovz_conn._access_control( + fakes.INSTANCE, '1.1.1.1', port=22, access_type='deny') + + def test_access_control_invalid_access_type(self): + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + self.assertRaises( + exception.InvalidInput, ovz_conn._access_control, fakes.INSTANCE, + '1.1.1.1', port=22, access_type='invalid') + + def test_reset_instance_size_success(self): + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + self.mox.StubOutWithMock(ovz_conn, '_set_instance_size') + ovz_conn._set_instance_size(fakes.INSTANCE) + self.mox.StubOutWithMock(ovz_conn, 'reboot') + ovz_conn.reboot(fakes.INSTANCE, None, None, None, None) + self.mox.ReplayAll() + self.assertTrue(ovz_conn.reset_instance_size(fakes.INSTANCE, True)) + + def test_reset_instance_size_failure(self): + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + self.mox.StubOutWithMock(ovz_conn, '_set_instance_size') + ovz_conn._set_instance_size(fakes.INSTANCE).AndRaise( + exception.InstanceUnacceptable(fakes.ERRORMSG)) + self.mox.ReplayAll() + self.assertRaises( + exception.InstanceUnacceptable, ovz_conn.reset_instance_size, + fakes.INSTANCE, True) + + def test_set_numflock(self): + instance_memory_mb = int(fakes.INSTANCETYPE['memory_mb']) + memory_unit_size = int(CONF.ovz_memory_unit_size) + max_fd_per_unit = int(CONF.ovz_file_descriptors_per_unit) + max_fd = int(instance_memory_mb / memory_unit_size) * max_fd_per_unit + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'vzctl', 'set', fakes.INSTANCE['id'], '--save', '--numflock', + max_fd, run_as_root=True).AndReturn(('', '')) + self.mox.ReplayAll() + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + ovz_conn._set_numflock(fakes.INSTANCE, max_fd) + + def test_sum_numfiles(self): + instance_memory_mb = int(fakes.INSTANCETYPE['memory_mb']) + memory_unit_size = int(CONF.ovz_memory_unit_size) + max_fd_per_unit = int(CONF.ovz_file_descriptors_per_unit) + max_fd = int(instance_memory_mb / memory_unit_size) * max_fd_per_unit + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'vzctl', 'set', fakes.INSTANCE['id'], '--save', '--numfile', + max_fd, run_as_root=True).AndReturn(('', '')) + self.mox.ReplayAll() + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + ovz_conn._set_numfiles(fakes.INSTANCE, max_fd) + + def test_set_instance_size_with_instance_type_id(self): + instance_memory_bytes = ((int(fakes.INSTANCETYPE['memory_mb']) + * 1024) * 1024) + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + pages = ovz_conn._calc_pages(fakes.INSTANCE['memory_mb']) + memory_unit_size = int(CONF.ovz_memory_unit_size) + max_fd_per_unit = int(CONF.ovz_file_descriptors_per_unit) + max_fd = int( + fakes.INSTANCE['memory_mb'] / memory_unit_size) * max_fd_per_unit + self.mox.StubOutWithMock(ovz_conn, '_percent_of_resource') + ovz_conn._percent_of_resource( + fakes.INSTANCETYPE['memory_mb']).AndReturn( + float(fakes.INSTANCE['memory_mb']) / + float(fakes.HOSTSTATS['memory_mb'])) + self.mox.StubOutWithMock(ovz_conn, '_set_vmguarpages') + ovz_conn._set_vmguarpages( + fakes.INSTANCE, pages) + self.mox.StubOutWithMock(ovz_conn, '_set_privvmpages') + ovz_conn._set_privvmpages(fakes.INSTANCE, pages) + self.mox.StubOutWithMock(ovz_conn, '_set_kmemsize') + ovz_conn._set_kmemsize(fakes.INSTANCE, instance_memory_bytes) + self.mox.StubOutWithMock(ovz_conn, '_set_numfiles') + ovz_conn._set_numfiles(fakes.INSTANCE, max_fd) + self.mox.StubOutWithMock(ovz_conn, '_set_numflock') + ovz_conn._set_numflock(fakes.INSTANCE, max_fd) + self.mox.StubOutWithMock(ovz_conn, '_set_cpuunits') + ovz_conn._set_cpuunits(fakes.INSTANCE, mox.IgnoreArg()) + self.mox.StubOutWithMock(ovz_conn, '_set_cpulimit') + ovz_conn._set_cpulimit(fakes.INSTANCE, mox.IgnoreArg()) + self.mox.StubOutWithMock(ovz_conn, '_set_cpus') + ovz_conn._set_cpus(fakes.INSTANCE, fakes.INSTANCETYPE['vcpus']) + self.mox.StubOutWithMock(ovz_conn, '_set_ioprio') + ovz_conn._set_ioprio( + fakes.INSTANCE, int(fakes.INSTANCETYPE['memory_mb'])) + self.mox.StubOutWithMock(ovz_conn, '_set_diskspace') + ovz_conn._set_diskspace(fakes.INSTANCE, fakes.INSTANCETYPE['root_gb']) + self.mox.StubOutWithMock(ovz_conn, '_generate_tc_rules') + ovz_conn._generate_tc_rules(fakes.INSTANCE, fakes.NETWORKINFO, False) + self.mox.ReplayAll() + ovz_conn._set_instance_size( + fakes.INSTANCE, fakes.NETWORKINFO) + + def test_set_instance_size_without_instance_type_id(self): + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + instance_memory_bytes = ((int(fakes.INSTANCETYPE['memory_mb']) + * 1024) * 1024) + pages = ovz_conn._calc_pages(fakes.INSTANCE['memory_mb']) + memory_unit_size = int(CONF.ovz_memory_unit_size) + max_fd_per_unit = int(CONF.ovz_file_descriptors_per_unit) + max_fd = int( + fakes.INSTANCE['memory_mb'] / memory_unit_size) * max_fd_per_unit + self.mox.StubOutWithMock(ovz_conn, '_percent_of_resource') + ovz_conn._percent_of_resource( + fakes.INSTANCETYPE['memory_mb']).AndReturn( + float(fakes.INSTANCE['memory_mb']) / + float(fakes.HOSTSTATS['memory_mb'])) + self.mox.StubOutWithMock(ovz_conn, '_set_vmguarpages') + ovz_conn._set_vmguarpages( + fakes.INSTANCE, pages) + self.mox.StubOutWithMock(ovz_conn, '_set_privvmpages') + ovz_conn._set_privvmpages(fakes.INSTANCE, pages) + self.mox.StubOutWithMock(ovz_conn, '_set_kmemsize') + ovz_conn._set_kmemsize(fakes.INSTANCE, instance_memory_bytes) + self.mox.StubOutWithMock(ovz_conn, '_set_numfiles') + ovz_conn._set_numfiles(fakes.INSTANCE, max_fd) + self.mox.StubOutWithMock(ovz_conn, '_set_numflock') + ovz_conn._set_numflock(fakes.INSTANCE, max_fd) + self.mox.StubOutWithMock(ovz_conn, '_set_cpuunits') + ovz_conn._set_cpuunits(fakes.INSTANCE, mox.IgnoreArg()) + self.mox.StubOutWithMock(ovz_conn, '_set_cpulimit') + ovz_conn._set_cpulimit(fakes.INSTANCE, mox.IgnoreArg()) + self.mox.StubOutWithMock(ovz_conn, '_set_cpus') + ovz_conn._set_cpus(fakes.INSTANCE, fakes.INSTANCETYPE['vcpus']) + self.mox.StubOutWithMock(ovz_conn, '_set_ioprio') + ovz_conn._set_ioprio( + fakes.INSTANCE, int(fakes.INSTANCETYPE['memory_mb'])) + self.mox.StubOutWithMock(ovz_conn, '_set_diskspace') + ovz_conn._set_diskspace( + fakes.INSTANCE, + ovz_utils.format_system_metadata( + fakes.INSTANCE['system_metadata'])['instance_type_root_gb']) + self.mox.StubOutWithMock(ovz_conn, '_generate_tc_rules') + ovz_conn._generate_tc_rules(fakes.INSTANCE, fakes.NETWORKINFO, False) + self.mox.ReplayAll() + ovz_conn._set_instance_size( + fakes.INSTANCE, fakes.NETWORKINFO) + + def test_generate_tc_rules(self): + self.mox.StubOutWithMock(openvz_conn.ovzboot, 'OVZBootFile') + openvz_conn.ovzboot.OVZBootFile( + mox.IgnoreArg(), mox.IgnoreArg()).AndReturn( + fakes.FakeOVZBootFile(0, 700)) + self.mox.StubOutWithMock(ovz_utils, 'read_instance_metadata') + ovz_utils.read_instance_metadata( + fakes.INSTANCE['id']).AndReturn(fakes.METADATA) + self.mox.StubOutWithMock(ovz_utils, 'remove_instance_metadata_key') + ovz_utils.remove_instance_metadata_key( + fakes.INSTANCE['id'], fakes.METAKEY) + self.mox.StubOutWithMock(openvz_conn.ovzshutdown, 'OVZShutdownFile') + openvz_conn.ovzshutdown.OVZShutdownFile( + mox.IgnoreArg(), mox.IgnoreArg()).AndReturn( + fakes.FakeOVZShutdownFile(0, 700)) + self.mox.StubOutWithMock(openvz_conn.ovztc, 'OVZTcRules') + openvz_conn.ovztc.OVZTcRules().MultipleTimes().AndReturn( + fakes.FakeOVZTcRules()) + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + self.mox.ReplayAll() + ovz_conn._generate_tc_rules(fakes.INSTANCE, fakes.NETWORKINFO) + + def test_set_onboot_success(self): + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'vzctl', 'set', fakes.INSTANCE['id'], '--onboot', 'no', '--save', + run_as_root=True).AndReturn(('', '')) + self.mox.ReplayAll() + conn = openvz_conn.OpenVzDriver(manager.ComputeVirtAPI(None), False) + conn._set_onboot(fakes.INSTANCE) + + def test_set_onboot_failure(self): + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'vzctl', 'set', fakes.INSTANCE['id'], '--onboot', 'no', '--save', + run_as_root=True).AndRaise( + exception.InstanceUnacceptable( + fakes.ERRORMSG)) + self.mox.ReplayAll() + conn = openvz_conn.OpenVzDriver(manager.ComputeVirtAPI(None), False) + self.assertRaises( + exception.InstanceUnacceptable, conn._set_onboot, fakes.INSTANCE) + + def test_set_cpuunits_success(self): + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'vzctl', 'set', fakes.INSTANCE['id'], '--save', '--cpuunits', + mox.IgnoreArg(), run_as_root=True).AndReturn(('', '')) + conn = openvz_conn.OpenVzDriver(manager.ComputeVirtAPI(None), False) + self.mox.StubOutWithMock(conn, '_percent_of_resource') + conn._percent_of_resource(mox.IgnoreArg()).AndReturn(fakes.RES_PERCENT) + self.mox.ReplayAll() + conn._set_cpuunits( + fakes.INSTANCE, conn._percent_of_resource( + fakes.INSTANCETYPE['memory_mb']) + ) + + def test_set_cpuunits_over_subscribe(self): + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'vzctl', 'set', fakes.INSTANCE['id'], '--save', '--cpuunits', + mox.IgnoreArg(), run_as_root=True).AndReturn(('', '')) + conn = openvz_conn.OpenVzDriver(manager.ComputeVirtAPI(None), False) + self.mox.StubOutWithMock(conn, '_percent_of_resource') + conn._percent_of_resource( + mox.IgnoreArg()).AndReturn(fakes.RES_OVER_PERCENT) + self.mox.ReplayAll() + conn._set_cpuunits( + fakes.INSTANCE, conn._percent_of_resource( + fakes.INSTANCETYPE['memory_mb']) + ) + + def test_set_cpuunits_failure(self): + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'vzctl', 'set', fakes.INSTANCE['id'], '--save', '--cpuunits', + mox.IgnoreArg(), run_as_root=True).AndRaise( + processutils.ProcessExecutionError(fakes.ERRORMSG)) + conn = openvz_conn.OpenVzDriver(manager.ComputeVirtAPI(None), False) + self.mox.StubOutWithMock(conn, '_percent_of_resource') + conn._percent_of_resource(mox.IgnoreArg()).AndReturn(fakes.RES_PERCENT) + self.mox.ReplayAll() + self.assertRaises( + exception.InstanceUnacceptable, conn._set_cpuunits, fakes.INSTANCE, + conn._percent_of_resource(fakes.INSTANCETYPE['memory_mb'])) + + def test_set_cpulimit_success(self): + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'vzctl', 'set', fakes.INSTANCE['id'], '--save', '--cpulimit', + fakes.UTILITY['CPULIMIT'] * fakes.RES_PERCENT, + run_as_root=True).AndReturn( + ('', fakes.ERRORMSG)) + conn = openvz_conn.OpenVzDriver(manager.ComputeVirtAPI(None), False) + self.mox.StubOutWithMock(conn, '_percent_of_resource') + conn._percent_of_resource(mox.IgnoreArg()).AndReturn( + fakes.RES_PERCENT + ) + self.mox.StubOutWithMock(conn, 'utility') + conn.utility = fakes.UTILITY + self.mox.ReplayAll() + conn._set_cpulimit( + fakes.INSTANCE, conn._percent_of_resource( + fakes.INSTANCETYPE['memory_mb']) + ) + + def test_set_cpulimit_over_subscribe(self): + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'vzctl', 'set', fakes.INSTANCE['id'], '--save', '--cpulimit', + fakes.UTILITY['CPULIMIT'], run_as_root=True).AndReturn( + ('', fakes.ERRORMSG)) + conn = openvz_conn.OpenVzDriver(manager.ComputeVirtAPI(None), False) + self.mox.StubOutWithMock(conn, '_percent_of_resource') + conn._percent_of_resource( + mox.IgnoreArg()).AndReturn(fakes.RES_OVER_PERCENT) + self.mox.StubOutWithMock(conn, 'utility') + conn.utility = fakes.UTILITY + self.mox.ReplayAll() + conn._set_cpulimit( + fakes.INSTANCE, conn._percent_of_resource( + fakes.INSTANCETYPE['memory_mb']) + ) + + def test_set_cpulimit_failure(self): + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'vzctl', 'set', fakes.INSTANCE['id'], '--save', '--cpulimit', + fakes.UTILITY['CPULIMIT'] * fakes.RES_PERCENT, + run_as_root=True).AndRaise( + exception.InstanceUnacceptable(fakes.ERRORMSG)) + conn = openvz_conn.OpenVzDriver(manager.ComputeVirtAPI(None), False) + self.mox.StubOutWithMock(conn, '_percent_of_resource') + conn._percent_of_resource(mox.IgnoreArg()).AndReturn(fakes.RES_PERCENT) + self.mox.StubOutWithMock(conn, 'utility') + conn.utility = fakes.UTILITY + self.mox.ReplayAll() + self.assertRaises( + exception.InstanceUnacceptable, conn._set_cpulimit, fakes.INSTANCE, + conn._percent_of_resource(fakes.INSTANCETYPE['memory_mb'])) + + def test_set_cpus_too_many_vcpus_success(self): + conn = openvz_conn.OpenVzDriver(manager.ComputeVirtAPI(None), False) + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'vzctl', 'set', fakes.INSTANCE['id'], '--save', '--cpus', + fakes.UTILITY['CPULIMIT'] / 100, + run_as_root=True).AndReturn( + ('', fakes.ERRORMSG)) + self.mox.StubOutWithMock(conn, 'utility') + conn.utility = fakes.UTILITY + self.mox.ReplayAll() + conn._set_cpus(fakes.INSTANCE, fakes.HOSTSTATS['vcpus'] * 200) + + def test_set_cpus_success(self): + conn = openvz_conn.OpenVzDriver(manager.ComputeVirtAPI(None), False) + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'vzctl', 'set', fakes.INSTANCE['id'], '--save', '--cpus', + mox.IgnoreArg(), run_as_root=True).AndReturn(('', fakes.ERRORMSG)) + self.mox.StubOutWithMock(conn, 'utility') + conn.utility = fakes.UTILITY + self.mox.ReplayAll() + conn._set_cpus(fakes.INSTANCE, fakes.INSTANCETYPE['vcpus']) + + def test_set_cpus_failure(self): + conn = openvz_conn.OpenVzDriver(manager.ComputeVirtAPI(None), False) + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'vzctl', 'set', fakes.INSTANCE['id'], '--save', '--cpus', + mox.IgnoreArg(), run_as_root=True).AndRaise( + exception.InstanceUnacceptable(fakes.ERRORMSG)) + self.mox.ReplayAll() + self.mox.StubOutWithMock(conn, 'utility') + conn.utility = fakes.UTILITY + self.assertRaises( + exception.InstanceUnacceptable, conn._set_cpus, fakes.INSTANCE, + fakes.INSTANCETYPE['vcpus']) + + def test_calc_pages_success(self): + # this test is a little sketchy because it is testing the default + # values of memory for instance type id 1. if this value changes then + # we will have a mismatch. + + # TODO(imsplitbit): make this work better. This test is very brittle + # because it relies on the default memory size for flavor 1 never + # changing. Need to fix this. + conn = openvz_conn.OpenVzDriver(manager.ComputeVirtAPI(None), False) + self.assertEqual( + conn._calc_pages(fakes.INSTANCE['memory_mb']), 524288) + + def test_get_cpuunits_capability_success(self): + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'vzcpucheck', run_as_root=True).AndReturn( + (fakes.CPUCHECKNOCONT, fakes.ERRORMSG)) + self.mox.ReplayAll() + ovz_utils.get_cpuunits_capability() + + def test_get_cpuunits_capability_failure(self): + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'vzcpucheck', run_as_root=True).AndRaise( + exception.InstanceUnacceptable(fakes.ERRORMSG)) + self.mox.ReplayAll() + self.assertRaises( + exception.InstanceUnacceptable, ovz_utils.get_cpuunits_capability) + + def test_get_cpuunits_usage_success(self): + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'vzcpucheck', '-v', run_as_root=True).AndReturn( + (fakes.CPUCHECKCONT, fakes.ERRORMSG)) + self.mox.ReplayAll() + conn = openvz_conn.OpenVzDriver(manager.ComputeVirtAPI(None), False) + conn._get_cpuunits_usage() + + def test_get_cpuunits_usage_failure(self): + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'vzcpucheck', '-v', run_as_root=True).AndRaise( + exception.InstanceUnacceptable(fakes.ERRORMSG)) + self.mox.ReplayAll() + conn = openvz_conn.OpenVzDriver(manager.ComputeVirtAPI(None), False) + self.assertRaises( + exception.InstanceUnacceptable, conn._get_cpuunits_usage) + + def test_percent_of_resource(self): + conn = openvz_conn.OpenVzDriver(manager.ComputeVirtAPI(None), False) + self.mox.StubOutWithMock(conn, 'utility') + conn.utility = fakes.UTILITY + self.mox.ReplayAll() + self.assertEqual( + float, type(conn._percent_of_resource(fakes.INSTANCE['memory_mb'])) + ) + + def test_set_ioprio_success(self): + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'vzctl', 'set', fakes.INSTANCE['id'], '--save', '--ioprio', + mox.IgnoreArg(), run_as_root=True).AndReturn(('', fakes.ERRORMSG)) + conn = openvz_conn.OpenVzDriver(manager.ComputeVirtAPI(None), False) + self.mox.ReplayAll() + conn._set_ioprio( + fakes.INSTANCE, fakes.INSTANCE['memory_mb']) + + def test_set_ioprio_too_high_success(self): + # Artificially inflate the memory for the instance to test the case + # where the logarithm would result in a value higher than 7, the + # code should set 7 as the cap. + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'vzctl', 'set', fakes.INSTANCE['id'], '--save', '--ioprio', + 7, run_as_root=True).AndReturn( + ('', fakes.ERRORMSG)) + conn = openvz_conn.OpenVzDriver(manager.ComputeVirtAPI(None), False) + self.mox.ReplayAll() + conn._set_ioprio( + fakes.INSTANCE, fakes.INSTANCE['memory_mb'] * 100) + + def test_set_ioprio_failure(self): + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'vzctl', 'set', fakes.INSTANCE['id'], '--save', '--ioprio', + mox.IgnoreArg(), run_as_root=True).AndRaise( + exception.InstanceUnacceptable(fakes.ERRORMSG)) + conn = openvz_conn.OpenVzDriver(manager.ComputeVirtAPI(None), False) + self.mox.ReplayAll() + self.assertRaises( + exception.InstanceUnacceptable, conn._set_ioprio, fakes.INSTANCE, + fakes.INSTANCE['memory_mb']) + + def test_set_diskspace_success(self): + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'vzctl', 'set', fakes.INSTANCE['id'], '--save', '--diskspace', + mox.IgnoreArg(), run_as_root=True).AndReturn(('', fakes.ERRORMSG)) + self.mox.ReplayAll() + conn = openvz_conn.OpenVzDriver(manager.ComputeVirtAPI(None), False) + conn._set_diskspace(fakes.INSTANCE, fakes.INSTANCETYPE['root_gb']) + + def test_set_diskspace_failure(self): + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'vzctl', 'set', fakes.INSTANCE['id'], '--save', '--diskspace', + mox.IgnoreArg(), run_as_root=True).AndRaise( + exception.InstanceUnacceptable(fakes.ERRORMSG)) + self.mox.ReplayAll() + conn = openvz_conn.OpenVzDriver(manager.ComputeVirtAPI(None), False) + self.assertRaises( + exception.InstanceUnacceptable, conn._set_diskspace, + fakes.INSTANCE, fakes.INSTANCETYPE['root_gb']) + + def test_attach_volumes_success(self): + conn = openvz_conn.OpenVzDriver(manager.ComputeVirtAPI(None), False) + self.mox.StubOutWithMock(conn, 'attach_volume') + conn.attach_volume( + fakes.BDM['block_device_mapping'][0]['connection_info'], + fakes.INSTANCE['name'], + (fakes.BDM['block_device_mapping'][0] + ['connection_info']['mount_device'])) + self.mox.ReplayAll() + conn._attach_volumes(fakes.INSTANCE['name'], fakes.BDM) + + def test_attach_volume(self): + self.mox.StubOutWithMock(ext_storage.ovzfile, 'OVZFile') + ext_storage.ovzfile.OVZFile( + self.ext_str_filename, self.ext_str_permissions).AndReturn( + fakes.FakeOvzFile( + self.ext_str_filename, self.ext_str_permissions)) + self.mox.StubOutWithMock(openvz_conn.ovziscsi, 'OVZISCSIStorageDriver') + openvz_conn.ovziscsi.OVZISCSIStorageDriver( + fakes.INSTANCE['id'], + fakes.BDM['block_device_mapping'][0]['mount_device'], + fakes.BDM['block_device_mapping'][0]['connection_info']).AndReturn( + fakes.FakeOVZISCSIStorageDriver()) + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + self.mox.ReplayAll() + ovz_conn.attach_volume( + fakes.BDM['block_device_mapping'][0]['connection_info'], + fakes.INSTANCE, + fakes.BDM['block_device_mapping'][0]['mount_device']) + + def test_detach_volume(self): + self.mox.StubOutWithMock(ext_storage.ovzfile, 'OVZFile') + ext_storage.ovzfile.OVZFile( + self.ext_str_filename, self.ext_str_permissions).AndReturn( + fakes.FakeOvzFile( + self.ext_str_filename, self.ext_str_permissions)) + self.mox.StubOutWithMock(openvz_conn.ovziscsi, 'OVZISCSIStorageDriver') + openvz_conn.ovziscsi.OVZISCSIStorageDriver( + fakes.INSTANCE['id'], + fakes.BDM['block_device_mapping'][0]['mount_device'], + fakes.BDM['block_device_mapping'][0]['connection_info']).AndReturn( + fakes.FakeOVZISCSIStorageDriver()) + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + self.mox.ReplayAll() + ovz_conn.detach_volume( + fakes.BDM['block_device_mapping'][0]['connection_info'], + fakes.INSTANCE) + + def test_get_available_resource(self): + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + self.mox.StubOutWithMock(ovz_conn, 'get_host_stats') + ovz_conn.get_host_stats(refresh=True).AndReturn(fakes.HOSTSTATS) + self.mox.ReplayAll() + ovz_conn.get_available_resource(None) + + def test_get_volume_connector(self): + self.mox.StubOutWithMock(openvz_conn.ovz_utils, 'get_iscsi_initiator') + openvz_conn.ovz_utils.get_iscsi_initiator().AndReturn( + fakes.ISCSIINITIATOR) + self.mox.ReplayAll() + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + iscsi_initiator = ovz_conn.get_volume_connector(fakes.INSTANCE) + self.assertTrue(isinstance(iscsi_initiator, dict)) + self.assertEqual(CONF.my_ip, iscsi_initiator['ip']) + self.assertEqual(fakes.ISCSIINITIATOR, iscsi_initiator['initiator']) + self.assertEqual(CONF.host, iscsi_initiator['host']) + + def test_gratuitous_arp_all_addresses(self): + conn = openvz_conn.OpenVzDriver(manager.ComputeVirtAPI(None), False) + self.mox.StubOutWithMock(conn, '_send_garp') + conn._send_garp( + fakes.INSTANCE['id'], mox.IgnoreArg(), + mox.IgnoreArg()).MultipleTimes() + self.mox.ReplayAll() + conn._gratuitous_arp_all_addresses(fakes.INSTANCE, fakes.NETWORKINFO) + + def test_send_garp_success(self): + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'vzctl', 'exec2', fakes.INSTANCE['id'], 'arping', '-q', '-c', '5', + '-A', '-I', fakes.NETWORKINFO[0][0]['bridge_interface'], + fakes.NETWORKINFO[0][1]['ips'][0]['ip'], + run_as_root=True).AndReturn( + ('', fakes.ERRORMSG)) + self.mox.ReplayAll() + conn = openvz_conn.OpenVzDriver(manager.ComputeVirtAPI(None), False) + conn._send_garp( + fakes.INSTANCE['id'], fakes.NETWORKINFO[0][1]['ips'][0]['ip'], + fakes.NETWORKINFO[0][0]['bridge_interface']) + + def test_send_garp_faiure(self): + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'vzctl', 'exec2', fakes.INSTANCE['id'], 'arping', '-q', '-c', '5', + '-A', '-I', fakes.NETWORKINFO[0][0]['bridge_interface'], + fakes.NETWORKINFO[0][1]['ips'][0]['ip'], + run_as_root=True).AndRaise( + exception.InstanceUnacceptable(fakes.ERRORMSG)) + self.mox.ReplayAll() + conn = openvz_conn.OpenVzDriver(manager.ComputeVirtAPI(None), False) + self.assertRaises( + exception.InstanceUnacceptable, conn._send_garp, + fakes.INSTANCE['id'], fakes.NETWORKINFO[0][1]['ips'][0]['ip'], + fakes.NETWORKINFO[0][0]['bridge_interface']) + + def test_init_host_success(self): + self.mox.StubOutWithMock(openvz_conn.ovzboot, 'OVZBootFile') + openvz_conn.ovzboot.OVZBootFile( + mox.IgnoreArg(), mox.IgnoreArg()).AndReturn( + fakes.FakeOVZBootFile(0, 700)) + self.mox.StubOutWithMock(openvz_conn.ovzshutdown, 'OVZShutdownFile') + openvz_conn.ovzshutdown.OVZShutdownFile( + mox.IgnoreArg(), mox.IgnoreArg()).AndReturn( + fakes.FakeOVZShutdownFile(0, 700)) + self.mox.StubOutWithMock(openvz_conn.ovztc, 'OVZTcRules') + openvz_conn.ovztc.OVZTcRules().AndReturn(fakes.FakeOVZTcRules()) + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + self.mox.StubOutWithMock(ovz_conn, '_refresh_host_stats') + ovz_conn._refresh_host_stats() + self.mox.StubOutWithMock(ovz_conn, '_get_cpulimit') + ovz_conn._get_cpulimit() + self.mox.ReplayAll() + ovz_conn.init_host() + + def test_get_host_stats(self): + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + self.mox.StubOutWithMock(ovz_conn, '_refresh_host_stats') + ovz_conn._refresh_host_stats() + self.mox.ReplayAll() + result = ovz_conn.get_host_stats(True) + self.assertTrue(isinstance(result, dict)) + + def test_refresh_host_stats(self): + self.mox.StubOutWithMock(openvz_conn.ovz_utils, 'get_vcpu_total') + openvz_conn.ovz_utils.get_vcpu_total().AndReturn( + fakes.HOSTSTATS['vcpus']) + self.mox.StubOutWithMock(openvz_conn.ovz_utils, 'get_vcpu_used') + openvz_conn.ovz_utils.get_vcpu_used().AndReturn( + fakes.HOSTSTATS['vcpus_used']) + self.mox.StubOutWithMock(openvz_conn.ovz_utils, 'get_cpuinfo') + openvz_conn.ovz_utils.get_cpuinfo().AndReturn( + fakes.PROCINFO) + self.mox.StubOutWithMock(openvz_conn.ovz_utils, 'get_memory_mb_total') + openvz_conn.ovz_utils.get_memory_mb_total().AndReturn( + fakes.HOSTSTATS['memory_mb']) + self.mox.StubOutWithMock(openvz_conn.ovz_utils, 'get_memory_mb_used') + openvz_conn.ovz_utils.get_memory_mb_used().AndReturn( + fakes.HOSTSTATS['memory_mb_used']) + self.mox.StubOutWithMock(openvz_conn.ovz_utils, 'get_local_gb_total') + openvz_conn.ovz_utils.get_local_gb_total().AndReturn( + fakes.HOSTSTATS['disk_total']) + self.mox.StubOutWithMock(openvz_conn.ovz_utils, 'get_local_gb_used') + openvz_conn.ovz_utils.get_local_gb_used().AndReturn( + fakes.HOSTSTATS['disk_used']) + self.mox.StubOutWithMock( + openvz_conn.ovz_utils, 'get_hypervisor_version') + openvz_conn.ovz_utils.get_hypervisor_version().AndReturn( + fakes.HOSTSTATS['hypervisor_version']) + self.mox.ReplayAll() + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + ovz_conn._refresh_host_stats() + + def test_set_hostname_success(self): + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'vzctl', 'set', fakes.INSTANCE['id'], '--save', '--hostname', + fakes.INSTANCE['hostname'], run_as_root=True).AndReturn( + ('', fakes.ERRORMSG)) + self.mox.ReplayAll() + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + ovz_conn._set_hostname(fakes.INSTANCE) + + def test_set_hostname_failure(self): + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'vzctl', 'set', fakes.INSTANCE['id'], '--save', '--hostname', + fakes.INSTANCE['hostname'], run_as_root=True).AndRaise( + exception.InstanceUnacceptable(fakes.ERRORMSG)) + self.mox.ReplayAll() + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + self.assertRaises( + exception.InstanceUnacceptable, ovz_conn._set_hostname, + fakes.INSTANCE) + + def test_set_name_success(self): + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'vzctl', 'set', fakes.INSTANCE['id'], '--save', '--name', + fakes.INSTANCE['name'], run_as_root=True).AndReturn( + ('', fakes.ERRORMSG)) + self.mox.ReplayAll() + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + ovz_conn._set_name(fakes.INSTANCE) + + def test_set_name_failure(self): + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'vzctl', 'set', fakes.INSTANCE['id'], '--save', '--name', + fakes.INSTANCE['name'], run_as_root=True).AndRaise( + exception.InstanceUnacceptable(fakes.ERRORMSG)) + self.mox.ReplayAll() + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + self.assertRaises( + exception.InstanceUnacceptable, ovz_conn._set_name, fakes.INSTANCE) + + def test_find_by_name_success(self): + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'vzlist', '-H', '-o', 'ctid,status,name', '--all', '--name_filter', + fakes.INSTANCE['name'], run_as_root=True).AndReturn( + (fakes.VZLISTDETAIL, fakes.ERRORMSG)) + self.mox.ReplayAll() + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + meta = ovz_conn._find_by_name(fakes.INSTANCE['name']) + self.assertEqual(fakes.INSTANCE['hostname'], meta['name']) + self.assertEqual(str(fakes.INSTANCE['id']), meta['id']) + self.assertEqual('running', meta['state']) + + def test_find_by_name_not_found(self): + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'vzlist', '-H', '-o', 'ctid,status,name', '--all', '--name_filter', + fakes.INSTANCE['name'], run_as_root=True).AndReturn( + ('', fakes.ERRORMSG)) + self.mox.ReplayAll() + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + self.assertRaises( + exception.NotFound, ovz_conn._find_by_name, fakes.INSTANCE['name']) + + def test_find_by_name_failure(self): + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'vzlist', '-H', '-o', 'ctid,status,name', '--all', '--name_filter', + fakes.INSTANCE['name'], run_as_root=True).AndRaise( + exception.InstanceUnacceptable(fakes.ERRORMSG)) + self.mox.ReplayAll() + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + self.assertRaises( + exception.InstanceUnacceptable, ovz_conn._find_by_name, + fakes.INSTANCE['name']) + + def test_plug_vifs(self): + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + ovz_conn.vif_driver = mox.MockAnything() + ovz_conn.vif_driver.plug( + fakes.INSTANCE, mox.IgnoreArg(), mox.IgnoreArg()) + self.mox.ReplayAll() + ovz_conn.plug_vifs(fakes.INSTANCE, fakes.NETWORKINFO) + + def test_reboot_success(self): + self.mox.StubOutWithMock(openvz_conn.ovzshutdown, 'OVZShutdownFile') + openvz_conn.ovzshutdown.OVZShutdownFile( + fakes.INSTANCE['id'], mox.IgnoreArg()).AndReturn( + fakes.FakeOVZShutdownFile(fakes.INSTANCE['id'], 700)) + self.mox.StubOutWithMock(openvz_conn.ovzboot, 'OVZBootFile') + openvz_conn.ovzboot.OVZBootFile( + fakes.INSTANCE['id'], mox.IgnoreArg()).AndReturn( + fakes.FakeOVZBootFile(fakes.INSTANCE['id'], 700)) + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + self.mox.StubOutWithMock(ovz_conn.virtapi, 'instance_update') + ovz_conn.virtapi.instance_update( + fakes.ADMINCONTEXT, fakes.INSTANCE['uuid'], + mox.IgnoreArg()).MultipleTimes() + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'vzctl', 'restart', fakes.INSTANCE['id'], + run_as_root=True).AndReturn(('', '')) + self.mox.StubOutWithMock(ovz_conn, 'get_info') + ovz_conn.get_info( + fakes.INSTANCE).MultipleTimes().AndReturn(fakes.GOODSTATUS) + self.mox.ReplayAll() + timer = ovz_conn.reboot( + fakes.ADMINCONTEXT, fakes.INSTANCE, fakes.NETWORKINFO, None) + timer.wait() + + def test_reboot_fail_in_get_info(self): + self.mox.StubOutWithMock(openvz_conn.ovzshutdown, 'OVZShutdownFile') + openvz_conn.ovzshutdown.OVZShutdownFile( + fakes.INSTANCE['id'], mox.IgnoreArg()).AndReturn( + fakes.FakeOVZShutdownFile(fakes.INSTANCE['id'], 700)) + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + self.mox.StubOutWithMock(ovz_conn.virtapi, 'instance_update') + ovz_conn.virtapi.instance_update( + fakes.ADMINCONTEXT, fakes.INSTANCE['uuid'], + mox.IgnoreArg()).MultipleTimes() + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'vzctl', 'restart', fakes.INSTANCE['id'], + run_as_root=True).AndReturn( + ('', fakes.ERRORMSG)) + self.mox.StubOutWithMock(ovz_conn, 'get_info') + ovz_conn.get_info(fakes.INSTANCE).AndRaise(exception.NotFound) + self.mox.ReplayAll() + timer = ovz_conn.reboot( + fakes.ADMINCONTEXT, fakes.INSTANCE, fakes.NETWORKINFO, None) + self.assertRaises(exception.NotFound, timer.wait) + + def test_reboot_fail_because_not_found(self): + self.mox.StubOutWithMock(openvz_conn.ovzshutdown, 'OVZShutdownFile') + openvz_conn.ovzshutdown.OVZShutdownFile( + fakes.INSTANCE['id'], mox.IgnoreArg()).AndReturn( + fakes.FakeOVZShutdownFile(fakes.INSTANCE['id'], 700)) + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + self.mox.StubOutWithMock(ovz_conn.virtapi, 'instance_update') + ovz_conn.virtapi.instance_update( + fakes.ADMINCONTEXT, fakes.INSTANCE['uuid'], + mox.IgnoreArg()).MultipleTimes() + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'vzctl', 'restart', fakes.INSTANCE['id'], + run_as_root=True).AndReturn( + ('', fakes.ERRORMSG)) + self.mox.StubOutWithMock(ovz_conn, 'get_info') + ovz_conn.get_info(fakes.INSTANCE).AndReturn(fakes.NOSTATUS) + self.mox.ReplayAll() + timer = ovz_conn.reboot( + fakes.ADMINCONTEXT, fakes.INSTANCE, fakes.NETWORKINFO, None) + timer.wait() + + def test_reboot_failure(self): + self.mox.StubOutWithMock(openvz_conn.ovzshutdown, 'OVZShutdownFile') + openvz_conn.ovzshutdown.OVZShutdownFile( + fakes.INSTANCE['id'], mox.IgnoreArg()).AndReturn( + fakes.FakeOVZShutdownFile(fakes.INSTANCE['id'], 700)) + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + self.mox.StubOutWithMock(ovz_conn.virtapi, 'instance_update') + ovz_conn.virtapi.instance_update( + fakes.ADMINCONTEXT, fakes.INSTANCE['uuid'], + {'power_state': power_state.PAUSED}) + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'vzctl', 'restart', fakes.INSTANCE['id'], + run_as_root=True).AndRaise( + exception.InstanceUnacceptable(fakes.ERRORMSG)) + self.mox.ReplayAll() + self.assertRaises( + exception.InstanceUnacceptable, ovz_conn.reboot, + fakes.ADMINCONTEXT, fakes.INSTANCE, fakes.NETWORKINFO, None) + + def test_inject_files(self): + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + self.mox.StubOutWithMock(ovz_conn, 'inject_file') + ovz_conn.inject_file( + fakes.INSTANCE, mox.IgnoreArg(), + base64.b64encode(fakes.FILECONTENTS)).MultipleTimes() + self.mox.ReplayAll() + ovz_conn._inject_files(fakes.INSTANCE, fakes.FILESTOINJECT) + + def test_inject_file(self): + full_path = '%s/%s/%s' % (CONF.ovz_ve_private_dir, + fakes.INSTANCE['id'], + fakes.FILESTOINJECT[0][0]) + self.mox.StubOutWithMock(openvz_conn.ovzfile, 'OVZFile') + openvz_conn.ovzfile.OVZFile( + full_path, 644).AndReturn(fakes.FakeOvzFile(full_path, 644)) + self.mox.ReplayAll() + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + ovz_conn.inject_file( + fakes.INSTANCE, base64.b64encode(fakes.FILESTOINJECT[0][0]), + base64.b64encode(fakes.FILESTOINJECT[0][1])) + + def test_set_admin_password_success(self): + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'vzctl', 'exec2', fakes.INSTANCE['id'], 'echo', + 'root:%s' % fakes.ROOTPASS, '|', 'chpasswd', + run_as_root=True).AndReturn( + ('', fakes.ERRORMSG)) + self.mox.ReplayAll() + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + ovz_conn.set_admin_password( + fakes.ADMINCONTEXT, fakes.INSTANCE['id'], fakes.ROOTPASS) + + def test_set_admin_password_failure(self): + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'vzctl', 'exec2', fakes.INSTANCE['id'], 'echo', + 'root:%s' % fakes.ROOTPASS, '|', 'chpasswd', + run_as_root=True).AndRaise( + exception.InstanceUnacceptable(fakes.ERRORMSG)) + self.mox.ReplayAll() + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + self.assertRaises( + exception.InstanceUnacceptable, ovz_conn.set_admin_password, + fakes.ADMINCONTEXT, fakes.INSTANCE['id'], fakes.ROOTPASS) + + def test_pause_success(self): + self.mox.StubOutWithMock(openvz_conn.ovzshutdown, 'OVZShutdownFile') + openvz_conn.ovzshutdown.OVZShutdownFile( + fakes.INSTANCE['id'], mox.IgnoreArg()).AndReturn( + fakes.FakeOVZShutdownFile(fakes.INSTANCE['id'], 700)) + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'vzctl', 'stop', fakes.INSTANCE['id'], run_as_root=True).AndReturn( + ('', fakes.ERRORMSG)) + conn = openvz_conn.OpenVzDriver(manager.ComputeVirtAPI(None), False) + self.mox.StubOutWithMock(conn.virtapi, 'instance_update') + conn.virtapi.instance_update( + mox.IgnoreArg(), fakes.INSTANCE['uuid'], + {'power_state': power_state.SHUTDOWN}) + self.mox.ReplayAll() + conn.pause(fakes.INSTANCE) + + def test_pause_failure(self): + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'vzctl', 'stop', fakes.INSTANCE['id'], run_as_root=True).AndRaise( + exception.InstanceUnacceptable(fakes.ERRORMSG)) + self.mox.StubOutWithMock(openvz_conn.ovzshutdown, 'OVZShutdownFile') + openvz_conn.ovzshutdown.OVZShutdownFile( + fakes.INSTANCE['id'], mox.IgnoreArg()).AndReturn( + fakes.FakeOVZShutdownFile(fakes.INSTANCE['id'], 700)) + self.mox.ReplayAll() + conn = openvz_conn.OpenVzDriver(manager.ComputeVirtAPI(None), False) + self.assertRaises( + exception.InstanceUnacceptable, conn.pause, fakes.INSTANCE) + + def test_suspend_success(self): + self.mox.StubOutWithMock(openvz_conn.context, 'get_admin_context') + openvz_conn.context.get_admin_context().AndReturn(fakes.ADMINCONTEXT) + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'vzctl', 'chkpnt', fakes.INSTANCE['id'], '--suspend', + run_as_root=True).AndReturn( + ('', fakes.ERRORMSG)) + conn = openvz_conn.OpenVzDriver(manager.ComputeVirtAPI(None), False) + self.mox.StubOutWithMock(conn.virtapi, 'instance_update') + conn.virtapi.instance_update( + fakes.ADMINCONTEXT, fakes.INSTANCE['uuid'], + {'power_state': power_state.SUSPENDED}) + self.mox.ReplayAll() + conn.suspend(fakes.INSTANCE) + + def test_suspend_failure(self): + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'vzctl', 'chkpnt', fakes.INSTANCE['id'], '--suspend', + run_as_root=True).AndRaise( + exception.InstanceUnacceptable( + fakes.ERRORMSG)) + self.mox.ReplayAll() + conn = openvz_conn.OpenVzDriver(manager.ComputeVirtAPI(None), False) + self.assertRaises( + exception.InstanceUnacceptable, conn.suspend, fakes.INSTANCE) + + def test_suspend_dberror(self): + self.mox.StubOutWithMock(openvz_conn.context, 'get_admin_context') + openvz_conn.context.get_admin_context().AndReturn(fakes.ADMINCONTEXT) + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'vzctl', 'chkpnt', fakes.INSTANCE['id'], '--suspend', + run_as_root=True).AndReturn( + ('', fakes.ERRORMSG)) + conn = openvz_conn.OpenVzDriver(manager.ComputeVirtAPI(None), False) + self.mox.StubOutWithMock(conn.virtapi, 'instance_update') + conn.virtapi.instance_update( + fakes.ADMINCONTEXT, fakes.INSTANCE['uuid'], + {'power_state': power_state.SUSPENDED}).AndRaise( + exception.InstanceNotFound(fakes.ERRORMSG)) + self.mox.ReplayAll() + conn.suspend(fakes.INSTANCE) + + def test_unpause_success(self): + self.mox.StubOutWithMock(openvz_conn.ovzboot, 'OVZBootFile') + openvz_conn.ovzboot.OVZBootFile( + fakes.INSTANCE['id'], mox.IgnoreArg()).AndReturn( + fakes.FakeOVZBootFile(fakes.INSTANCE['id'], 700)) + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'vzctl', 'start', fakes.INSTANCE['id'], + run_as_root=True).AndReturn( + ('', fakes.ERRORMSG)) + conn = openvz_conn.OpenVzDriver(manager.ComputeVirtAPI(None), True) + self.mox.StubOutWithMock(conn.virtapi, 'instance_update') + conn.virtapi.instance_update( + mox.IgnoreArg(), fakes.INSTANCE['uuid'], + {'power_state': power_state.RUNNING}) + + self.mox.ReplayAll() + conn.unpause(fakes.INSTANCE) + + def test_unpause_failure(self): + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'vzctl', 'start', fakes.INSTANCE['id'], run_as_root=True).AndRaise( + exception.InstanceUnacceptable(fakes.ERRORMSG)) + self.mox.ReplayAll() + conn = openvz_conn.OpenVzDriver(manager.ComputeVirtAPI(None), False) + self.assertRaises( + exception.InstanceUnacceptable, conn.unpause, fakes.INSTANCE) + + def test_resume_success(self): + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'vzctl', 'chkpnt', fakes.INSTANCE['id'], '--resume', + run_as_root=True).AndReturn( + ('', fakes.ERRORMSG)) + conn = openvz_conn.OpenVzDriver(manager.ComputeVirtAPI(None), True) + self.mox.StubOutWithMock(conn.virtapi, 'instance_update') + conn.virtapi.instance_update( + mox.IgnoreArg(), fakes.INSTANCE['uuid'], + {'power_state': power_state.RUNNING}) + + self.mox.ReplayAll() + conn.resume(fakes.INSTANCE, fakes.NETWORKINFO) + + def test_resume_db_not_found(self): + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'vzctl', 'chkpnt', fakes.INSTANCE['id'], '--resume', + run_as_root=True).AndReturn( + ('', fakes.ERRORMSG)) + conn = openvz_conn.OpenVzDriver(manager.ComputeVirtAPI(None), True) + self.mox.StubOutWithMock(conn.virtapi, 'instance_update') + conn.virtapi.instance_update( + mox.IgnoreArg(), fakes.INSTANCE['uuid'], + {'power_state': power_state.RUNNING}).AndRaise( + exception.InstanceNotFound(fakes.ERRORMSG)) + self.mox.ReplayAll() + conn.resume(fakes.INSTANCE, fakes.NETWORKINFO) + + def test_resume_failure(self): + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'vzctl', 'chkpnt', fakes.INSTANCE['id'], '--resume', + run_as_root=True).AndRaise( + exception.InstanceUnacceptable(fakes.ERRORMSG)) + self.mox.ReplayAll() + conn = openvz_conn.OpenVzDriver(manager.ComputeVirtAPI(None), False) + self.assertRaises( + exception.InstanceUnacceptable, conn.resume, fakes.INSTANCE, None, + None) + + def test_clean_orphaned_files(self): + self.mox.StubOutWithMock(openvz_conn.os, 'listdir') + openvz_conn.os.listdir(mox.IgnoreArg()).MultipleTimes().AndReturn( + fakes.OSLISTDIR) + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'rm', '-f', mox.IgnoreArg(), + run_as_root=True).MultipleTimes().AndReturn(('', '')) + self.mox.ReplayAll() + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + ovz_conn._clean_orphaned_files(fakes.INSTANCE['id']) + + def test_destroy_fail_on_exec(self): + self.mox.StubOutWithMock( + openvz_conn.ovz_utils, 'remove_instance_metadata') + openvz_conn.ovz_utils.remove_instance_metadata(fakes.INSTANCE['id']) + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + ovz_conn.vif_driver = mox.MockAnything() + ovz_conn.vif_driver.unplug( + fakes.INSTANCE, mox.IgnoreArg(), mox.IgnoreArg()) + self.mox.StubOutWithMock(ovz_conn, '_stop') + ovz_conn._stop(fakes.INSTANCE) + self.mox.StubOutWithMock(ovz_conn, 'get_info') + ovz_conn.get_info(fakes.INSTANCE).AndReturn(fakes.GOODSTATUS) + self.mox.StubOutWithMock(ovz_conn, '_destroy') + ovz_conn._destroy(fakes.INSTANCE['id']).AndRaise( + exception.InstanceUnacceptable(fakes.ERRORMSG)) + self.mox.ReplayAll() + self.assertRaises( + exception.InstanceTerminationFailure, ovz_conn.destroy, + fakes.INSTANCE, fakes.NETWORKINFO) + + def test_destroy_success(self): + self.mox.StubOutWithMock( + openvz_conn.ovz_utils, 'remove_instance_metadata') + openvz_conn.ovz_utils.remove_instance_metadata(fakes.INSTANCE['id']) + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + ovz_conn.vif_driver = mox.MockAnything() + ovz_conn.vif_driver.unplug( + fakes.INSTANCE, mox.IgnoreArg(), mox.IgnoreArg()) + self.mox.StubOutWithMock(ovz_conn, 'get_info') + dir(ovz_conn.get_info) + ovz_conn.get_info(fakes.INSTANCE).AndReturn( + fakes.GOODSTATUS) + ovz_conn.get_info(fakes.INSTANCE).AndRaise(exception.InstanceNotFound( + fakes.ERRORMSG)) + self.mox.StubOutWithMock(ovz_conn, '_stop') + ovz_conn._stop(fakes.INSTANCE) + self.mox.StubOutWithMock(ovz_conn, '_destroy') + ovz_conn._destroy(fakes.INSTANCE['id']) + self.mox.StubOutWithMock(ovz_conn, '_clean_orphaned_files') + ovz_conn._clean_orphaned_files(fakes.INSTANCE['id']) + self.mox.StubOutWithMock(ovz_conn, '_detach_volumes') + ovz_conn._detach_volumes(fakes.INSTANCE, fakes.BDM) + self.mox.ReplayAll() + ovz_conn.destroy(fakes.INSTANCE, fakes.NETWORKINFO, fakes.BDM) + + def test_get_info_running_state(self): + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + self.mox.StubOutWithMock(ovz_conn, '_find_by_name') + ovz_conn._find_by_name(fakes.INSTANCE['name']).AndReturn( + fakes.FINDBYNAME) + self.mox.ReplayAll() + meta = ovz_conn.get_info(fakes.INSTANCE) + self.assertTrue(isinstance(meta, dict)) + self.assertEqual(meta['state'], power_state.RUNNING) + + def test_get_info_shutdown_state(self): + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + self.mox.StubOutWithMock(ovz_conn, '_find_by_name') + ovz_conn._find_by_name(fakes.INSTANCE['name']).AndReturn( + fakes.FINDBYNAMESHUTDOWN) + self.mox.ReplayAll() + meta = ovz_conn.get_info(fakes.INSTANCE) + self.assertTrue(isinstance(meta, dict)) + self.assertEqual(meta['state'], power_state.SHUTDOWN) + + def test_get_info_no_state(self): + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + self.mox.StubOutWithMock(ovz_conn, '_find_by_name') + ovz_conn._find_by_name(fakes.INSTANCE['name']).AndReturn( + fakes.FINDBYNAMENOSTATE) + self.mox.ReplayAll() + meta = ovz_conn.get_info(fakes.INSTANCE) + self.assertTrue(isinstance(meta, dict)) + self.assertEqual(meta['state'], power_state.NOSTATE) + + def test_get_info_state_is_None(self): + BADFINDBYNAME = fakes.FINDBYNAME.copy() + BADFINDBYNAME['state'] = None + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + self.mox.StubOutWithMock(ovz_conn, '_find_by_name') + ovz_conn._find_by_name(fakes.INSTANCE['name']).AndReturn(BADFINDBYNAME) + self.mox.ReplayAll() + meta = ovz_conn.get_info(fakes.INSTANCE) + self.assertTrue(isinstance(meta, dict)) + self.assertEqual(meta['state'], power_state.NOSTATE) + + def test_get_info_state_is_shutdown(self): + BADFINDBYNAME = fakes.FINDBYNAME.copy() + BADFINDBYNAME['state'] = 'shutdown' + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + self.mox.StubOutWithMock(ovz_conn, '_find_by_name') + ovz_conn._find_by_name(fakes.INSTANCE['name']).AndReturn(BADFINDBYNAME) + self.mox.ReplayAll() + meta = ovz_conn.get_info(fakes.INSTANCE) + self.assertTrue(isinstance(meta, dict)) + self.assertEqual(meta['state'], power_state.SHUTDOWN) + + def test_get_info_notfound(self): + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + self.mox.StubOutWithMock(ovz_conn, '_find_by_name') + ovz_conn._find_by_name(fakes.INSTANCE['name']).AndRaise( + exception.NotFound) + self.mox.ReplayAll() + self.assertRaises( + exception.NotFound, ovz_conn.get_info, fakes.INSTANCE) + + def test_percent_of_memory_over_subscribe(self): + # Force the utility storage to have really low memory so as to test the + # code that doesn't allow more than a 1.x multiplier. + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + ovz_conn.utility['MEMORY_MB'] = 16 + self.mox.StubOutWithMock(ovz_utils, 'get_memory_mb_total') + ovz_utils.get_memory_mb_total().AndReturn(1024) + self.mox.ReplayAll() + self.assertEqual( + 1, ovz_conn._percent_of_resource(fakes.INSTANCE['memory_mb'])) + + def test_percent_of_memory_normal_subscribe(self): + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + ovz_conn.utility['MEMORY_MB'] = 16384 + self.mox.ReplayAll() + self.assertTrue( + ovz_conn._percent_of_resource(fakes.INSTANCE['memory_mb']) < 1) + + def test_get_cpulimit_success(self): + self.mox.StubOutWithMock(ovz_utils.multiprocessing, 'cpu_count') + ovz_utils.multiprocessing.cpu_count().AndReturn(2) + self.mox.ReplayAll() + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + ovz_conn._get_cpulimit() + self.assertEqual(ovz_conn.utility['CPULIMIT'], 200) + + def test_spawn_success(self): + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + self.mox.StubOutWithMock(ovz_conn.virtapi, 'instance_update') + ovz_conn.virtapi.instance_update( + fakes.ADMINCONTEXT, fakes.INSTANCE['uuid'], mox.IgnoreArg()) + self.mox.StubOutWithMock(ovz_conn, '_get_cpuunits_usage') + ovz_conn._get_cpuunits_usage() + self.mox.StubOutWithMock(ovz_conn, '_cache_image') + ovz_conn._cache_image(fakes.ADMINCONTEXT, fakes.INSTANCE) + self.mox.StubOutWithMock(ovz_conn, '_create_vz') + ovz_conn._create_vz(fakes.INSTANCE) + self.mox.StubOutWithMock(ovz_conn, '_set_vz_os_hint') + ovz_conn._set_vz_os_hint(fakes.INSTANCE) + self.mox.StubOutWithMock(ovz_conn, '_configure_vz') + ovz_conn._configure_vz(fakes.INSTANCE) + self.mox.StubOutWithMock(ovz_conn, '_set_description') + ovz_conn._set_description(fakes.INSTANCE) + self.mox.StubOutWithMock(ovz_conn, '_setup_networking') + ovz_conn._setup_networking(fakes.INSTANCE, fakes.NETWORKINFO) + self.mox.StubOutWithMock(ovz_conn, '_set_onboot') + ovz_conn._set_onboot(fakes.INSTANCE) + self.mox.StubOutWithMock(ovz_conn, '_set_name') + ovz_conn._set_name(fakes.INSTANCE) + self.mox.StubOutWithMock(ovz_conn, 'plug_vifs') + ovz_conn.plug_vifs(fakes.INSTANCE, fakes.NETWORKINFO) + self.mox.StubOutWithMock(ovz_conn, '_set_hostname') + ovz_conn._set_hostname(fakes.INSTANCE) + self.mox.StubOutWithMock(ovz_conn, '_set_instance_size') + ovz_conn._set_instance_size(fakes.INSTANCE) + self.mox.StubOutWithMock(ovz_conn, '_attach_volumes') + ovz_conn._attach_volumes(fakes.INSTANCE, fakes.BDM) + self.mox.StubOutWithMock(ovz_conn, '_inject_files') + ovz_conn._inject_files(fakes.INSTANCE, fakes.FILESTOINJECT) + self.mox.StubOutWithMock(ovz_conn, '_start') + ovz_conn._start(fakes.INSTANCE) + self.mox.StubOutWithMock(ovz_conn, '_gratuitous_arp_all_addresses') + ovz_conn._gratuitous_arp_all_addresses( + fakes.INSTANCE, fakes.NETWORKINFO) + self.mox.StubOutWithMock(ovz_conn, 'set_admin_password') + ovz_conn.set_admin_password( + fakes.ADMINCONTEXT, fakes.INSTANCE['id'], + fakes.INSTANCE['admin_pass']) + self.mox.StubOutWithMock(ovz_conn, 'get_info') + ovz_conn.get_info(fakes.INSTANCE).AndReturn(fakes.GOODSTATUS) + self.mox.ReplayAll() + timer = ovz_conn.spawn( + fakes.ADMINCONTEXT, fakes.INSTANCE, None, fakes.FILESTOINJECT, + fakes.ROOTPASS, fakes.NETWORKINFO, fakes.BDM) + timer.wait() + + def test_spawn_failure(self): + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + self.mox.StubOutWithMock(ovz_conn.virtapi, 'instance_update') + ovz_conn.virtapi.instance_update( + fakes.ADMINCONTEXT, fakes.INSTANCE['uuid'], mox.IgnoreArg()) + self.mox.StubOutWithMock(ovz_conn, '_get_cpuunits_usage') + ovz_conn._get_cpuunits_usage() + self.mox.StubOutWithMock(ovz_conn, '_cache_image') + ovz_conn._cache_image(fakes.ADMINCONTEXT, fakes.INSTANCE) + self.mox.StubOutWithMock(ovz_conn, '_create_vz') + ovz_conn._create_vz(fakes.INSTANCE) + self.mox.StubOutWithMock(ovz_conn, '_set_vz_os_hint') + ovz_conn._set_vz_os_hint(fakes.INSTANCE) + self.mox.StubOutWithMock(ovz_conn, '_configure_vz') + ovz_conn._configure_vz(fakes.INSTANCE) + self.mox.StubOutWithMock(ovz_conn, '_set_description') + ovz_conn._set_description(fakes.INSTANCE) + self.mox.StubOutWithMock(ovz_conn, '_setup_networking') + ovz_conn._setup_networking(fakes.INSTANCE, fakes.NETWORKINFO) + self.mox.StubOutWithMock(ovz_conn, '_set_onboot') + ovz_conn._set_onboot(fakes.INSTANCE) + self.mox.StubOutWithMock(ovz_conn, '_set_name') + ovz_conn._set_name(fakes.INSTANCE) + self.mox.StubOutWithMock(ovz_conn, 'plug_vifs') + ovz_conn.plug_vifs(fakes.INSTANCE, fakes.NETWORKINFO) + self.mox.StubOutWithMock(ovz_conn, '_set_hostname') + ovz_conn._set_hostname(fakes.INSTANCE) + self.mox.StubOutWithMock(ovz_conn, '_set_instance_size') + ovz_conn._set_instance_size(fakes.INSTANCE) + self.mox.StubOutWithMock(ovz_conn, '_attach_volumes') + ovz_conn._attach_volumes(fakes.INSTANCE, fakes.BDM) + self.mox.StubOutWithMock(ovz_conn, '_inject_files') + ovz_conn._inject_files(fakes.INSTANCE, fakes.FILESTOINJECT) + self.mox.StubOutWithMock(ovz_conn, '_start') + ovz_conn._start(fakes.INSTANCE) + self.mox.StubOutWithMock(ovz_conn, '_gratuitous_arp_all_addresses') + ovz_conn._gratuitous_arp_all_addresses( + fakes.INSTANCE, fakes.NETWORKINFO) + self.mox.StubOutWithMock(ovz_conn, 'set_admin_password') + ovz_conn.set_admin_password( + fakes.ADMINCONTEXT, fakes.INSTANCE['id'], + fakes.INSTANCE['admin_pass']) + self.mox.StubOutWithMock(ovz_conn, 'get_info') + ovz_conn.get_info(fakes.INSTANCE).AndRaise(exception.NotFound) + self.mox.ReplayAll() + timer = ovz_conn.spawn( + fakes.ADMINCONTEXT, fakes.INSTANCE, None, fakes.FILESTOINJECT, + fakes.ROOTPASS, fakes.NETWORKINFO, fakes.BDM) + timer.wait() + + def test_snapshot(self): + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + ovz_conn.snapshot( + fakes.ADMINCONTEXT, fakes.INSTANCE, fakes.INSTANCE['image_ref'], + True) + + def test_rescue(self): + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + ovz_conn.rescue( + fakes.ADMINCONTEXT, fakes.INSTANCE, fakes.NETWORKINFO, + fakes.INSTANCE['image_ref'], fakes.ROOTPASS) + + def test_unrescue(self): + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + ovz_conn.unrescue(fakes.INSTANCE, fakes.NETWORKINFO) + + def test_get_diagnostics(self): + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + ovz_conn.get_diagnostics(fakes.INSTANCE['name']) + + def test_list_disks(self): + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + result = ovz_conn.list_disks(fakes.INSTANCE['name']) + self.assertTrue(isinstance(result, list)) + self.assertEqual(result[0], 'A_DISK') + + def test_list_interfaces(self): + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + result = ovz_conn.list_interfaces(fakes.INSTANCE['name']) + self.assertTrue(isinstance(result, list)) + self.assertEqual(result[0], 'A_VIF') + + def test_block_stats(self): + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + result = ovz_conn.block_stats( + fakes.INSTANCE['name'], 'c49a7247-731e-4135-8420-7a3c67002582') + self.assertTrue(isinstance(result, list)) + self.assertEqual(result[0], 0L) + self.assertEqual(result[1], 0L) + self.assertEqual(result[2], 0L) + self.assertEqual(result[3], 0L) + self.assertEqual(result[4], None) + + def test_interface_stats(self): + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + result = ovz_conn.interface_stats(fakes.INSTANCE['name'], 'eth0') + self.assertTrue(isinstance(result, list)) + self.assertEqual(result[0], 0L) + self.assertEqual(result[1], 0L) + self.assertEqual(result[2], 0L) + self.assertEqual(result[3], 0L) + self.assertEqual(result[4], 0L) + self.assertEqual(result[5], 0L) + self.assertEqual(result[6], 0L) + self.assertEqual(result[7], 0L) + + def test_get_console_output(self): + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + result = ovz_conn.get_console_output(fakes.INSTANCE) + self.assertTrue(isinstance(result, str)) + self.assertEqual(result, 'FAKE CONSOLE OUTPUT') + + def test_get_ajax_console(self): + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + result = ovz_conn.get_ajax_console(fakes.INSTANCE) + self.assertTrue(isinstance(result, str)) + self.assertEqual(result, 'http://fakeajaxconsole.com/?token=FAKETOKEN') + + def test_get_console_pool_info(self): + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + result = ovz_conn.get_console_pool_info(None) + self.assertTrue(isinstance(result, dict)) + self.assertEqual(result['address'], '127.0.0.1') + self.assertEqual(result['username'], 'fakeuser') + self.assertEqual(result['password'], 'fakepassword') + + def test_refresh_security_group_rules(self): + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + result = ovz_conn.refresh_security_group_rules(None) + self.assertTrue(result) + + def test_refresh_security_group_members(self): + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + result = ovz_conn.refresh_security_group_members(None) + self.assertTrue(result) + + def test_poll_rebooting_instances(self): + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + result = ovz_conn.poll_rebooting_instances(5, fakes.INSTANCES) + + def test_poll_rescued_instances(self): + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + result = ovz_conn.poll_rescued_instances(5) + + def test_power_off(self): + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + result = ovz_conn.power_off(fakes.INSTANCE) + + def test_power_on(self): + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + result = ovz_conn.power_on(fakes.INSTANCE) + + def test_compare_cpu(self): + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + result = ovz_conn.compare_cpu(fakes.PROCINFO) + + def test_poll_unconfirmed_resizes(self): + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + result = ovz_conn.poll_unconfirmed_resizes(None) + + def test_host_power_action(self): + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + result = ovz_conn.host_power_action(CONF.host, 'reboot') + + def test_set_host_enabled(self): + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + result = ovz_conn.set_host_enabled(CONF.host, True) + + def test_ensure_filtering_rules_for_instance(self): + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + result = ovz_conn.ensure_filtering_rules_for_instance( + fakes.INSTANCE, fakes.NETWORKINFO) + + def test_unfilter_instance(self): + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + result = ovz_conn.unfilter_instance(fakes.INSTANCE, fakes.NETWORKINFO) + + def test_refresh_provider_fw_rules(self): + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + result = ovz_conn.refresh_provider_fw_rules() + + def test_agent_update(self): + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + result = ovz_conn.agent_update(fakes.INSTANCE, None, None) + + def test_update_host_status(self): + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + result = ovz_conn.update_host_status() + + def test_get_all_bw_usage(self): + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + result = ovz_conn.get_all_bw_usage(fakes.INSTANCES, 'now') + self.assertTrue(isinstance(result, list)) + self.assertTrue(len(result) == 0) + + def test_snapshot_instance(self): + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + result = ovz_conn.snapshot_instance( + fakes.ADMINCONTEXT, fakes.INSTANCE['id'], + fakes.INSTANCE['image_ref']) + + def test_resize(self): + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + ovz_conn.resize(fakes.INSTANCE, None) + + def test_get_host_ip_addr(self): + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + ovz_conn.get_host_ip_addr() + + def test_migrate_disk_and_power_off_success_with_storage(self): + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + self.mox.StubOutWithMock(ovz_conn, '_stop') + ovz_conn._stop(fakes.INSTANCE) + self.mox.StubOutWithMock(ovz_conn, '_pymigration_send_to_host') + ovz_conn._pymigration_send_to_host( + fakes.INSTANCE, ovz_utils.generate_network_dict( + fakes.INSTANCE['id'], fakes.NETWORKINFO), + fakes.BDM, fakes.DESTINATION, False) + self.mox.StubOutWithMock(ovz_conn, '_detach_volumes') + ovz_conn._detach_volumes(fakes.INSTANCE, fakes.BDM, True, False) + self.mox.ReplayAll() + ovz_conn.migrate_disk_and_power_off( + fakes.ADMINCONTEXT, fakes.INSTANCE, fakes.DESTINATION, + fakes.INSTANCETYPE, fakes.NETWORKINFO, fakes.BDM) + + def test_migrate_disk_and_power_off_success_without_storage(self): + INSTANCE = fakes.INSTANCE.copy() + INSTANCE['block_device_mapping'] = {} + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + self.mox.StubOutWithMock(ovz_conn, 'suspend') + ovz_conn.suspend(INSTANCE) + self.mox.StubOutWithMock(ovz_conn, '_pymigration_send_to_host') + ovz_conn._pymigration_send_to_host( + INSTANCE, ovz_utils.generate_network_dict( + INSTANCE['id'], fakes.NETWORKINFO), + None, fakes.DESTINATION, True) + self.mox.ReplayAll() + ovz_conn.migrate_disk_and_power_off( + fakes.ADMINCONTEXT, INSTANCE, fakes.DESTINATION, + fakes.INSTANCETYPE, fakes.NETWORKINFO) + + def test_migrate_disk_and_power_off_no_dest(self): + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + self.assertRaises( + exception.MigrationError, ovz_conn.migrate_disk_and_power_off, + fakes.ADMINCONTEXT, fakes.INSTANCE, None, fakes.INSTANCETYPE, + fakes.NETWORKINFO) + + def test_migrate_disk_and_power_off_same_host(self): + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + self.mox.StubOutWithMock(ovz_utils, 'save_instance_metadata') + ovz_utils.save_instance_metadata( + fakes.INSTANCE['id'], 'migration_type', 'resize_in_place') + self.mox.ReplayAll() + ovz_conn.migrate_disk_and_power_off( + fakes.ADMINCONTEXT, fakes.INSTANCE, CONF.host, + fakes.INSTANCETYPE, fakes.NETWORKINFO) + + def test_pymigration_send_to_host(self): + self.mox.StubOutWithMock( + migration.OVZMigration, 'dump_and_transfer_instance') + migration.OVZMigration.dump_and_transfer_instance() + self.mox.StubOutWithMock(migration.OVZMigration, 'send') + migration.OVZMigration.send() + self.mox.ReplayAll() + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + ovz_conn._pymigration_send_to_host( + fakes.INSTANCE, fakes.NETWORKINFO, fakes.BDM, + fakes.DESTINATION, False) + + def test_vzmigration_send_to_host(self): + self.mox.StubOutWithMock(ovz_utils, 'execute') + ovz_utils.execute( + 'vzmigrate', '--online', '-r', 'yes', '-v', fakes.DESTINATION, + fakes.INSTANCE['id'], run_as_root=True) + self.mox.ReplayAll() + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + ovz_conn._vzmigration_send_to_host(fakes.INSTANCE, fakes.DESTINATION) + + def test_finish_migration_resize_in_place(self): + self.mox.StubOutWithMock(ovz_utils, 'read_instance_metadata') + ovz_utils.read_instance_metadata(fakes.INSTANCE['id']).AndReturn( + {'migration_type': 'resize_in_place'}) + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + self.mox.StubOutWithMock(ovz_conn, '_set_instance_size') + ovz_conn._set_instance_size(fakes.INSTANCE, fakes.NETWORKINFO, False) + self.mox.ReplayAll() + ovz_conn.finish_migration( + fakes.ADMINCONTEXT, None, fakes.INSTANCE, None, fakes.NETWORKINFO, + None, None, fakes.BDM) + + def test_finish_migration_no_resize(self): + self.mox.StubOutWithMock(ovz_utils, 'read_instance_metadata') + ovz_utils.read_instance_metadata(fakes.INSTANCE['id']).AndReturn({}) + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + self.mox.StubOutWithMock(ovz_conn, '_attach_volumes') + ovz_conn._attach_volumes(fakes.INSTANCE, fakes.BDM) + self.mox.StubOutWithMock(ovz_conn, '_pymigrate_finish_migration') + ovz_conn._pymigrate_finish_migration( + fakes.INSTANCE, fakes.NETWORKINFO, False) + self.mox.StubOutWithMock(ovz_conn, '_set_name') + ovz_conn._set_name(fakes.INSTANCE) + self.mox.StubOutWithMock(ovz_conn, '_set_description') + ovz_conn._set_description(fakes.INSTANCE) + self.mox.StubOutWithMock(ovz_conn, '_generate_tc_rules') + ovz_conn._generate_tc_rules(fakes.INSTANCE, fakes.NETWORKINFO, True) + self.mox.StubOutWithMock(ovz_conn, '_start') + ovz_conn._start(fakes.INSTANCE) + self.mox.ReplayAll() + ovz_conn.finish_migration( + fakes.ADMINCONTEXT, None, fakes.INSTANCE, None, fakes.NETWORKINFO, + None, False, fakes.BDM) + + def test_finish_migration_resize(self): + self.mox.StubOutWithMock(ovz_utils, 'read_instance_metadata') + ovz_utils.read_instance_metadata(fakes.INSTANCE['id']).AndReturn({}) + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + self.mox.StubOutWithMock(ovz_conn, '_attach_volumes') + ovz_conn._attach_volumes(fakes.INSTANCE, fakes.BDM) + self.mox.StubOutWithMock(ovz_conn, '_pymigrate_finish_migration') + ovz_conn._pymigrate_finish_migration( + fakes.INSTANCE, fakes.NETWORKINFO, False) + self.mox.StubOutWithMock(ovz_conn, '_set_name') + ovz_conn._set_name(fakes.INSTANCE) + self.mox.StubOutWithMock(ovz_conn, '_set_instance_size') + ovz_conn._set_instance_size(fakes.INSTANCE, fakes.NETWORKINFO, True) + self.mox.StubOutWithMock(ovz_conn, '_set_description') + ovz_conn._set_description(fakes.INSTANCE) + self.mox.StubOutWithMock(ovz_conn, '_start') + ovz_conn._start(fakes.INSTANCE) + self.mox.ReplayAll() + ovz_conn.finish_migration( + fakes.ADMINCONTEXT, None, fakes.INSTANCE, None, fakes.NETWORKINFO, + None, True, fakes.BDM) + + def test_pymigrate_finish_migration(self): + self.mox.StubOutWithMock(migration.OVZMigration, 'undump_instance') + migration.OVZMigration.undump_instance() + self.mox.StubOutWithMock(migration.OVZMigration, 'cleanup_destination') + migration.OVZMigration.cleanup_destination() + self.mox.ReplayAll() + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + ovz_conn._pymigrate_finish_migration( + fakes.INSTANCE, fakes.NETWORKINFO, False) + + def test_vzmigrate_setup_dest_host(self): + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + self.mox.StubOutWithMock(ovz_conn, '_stop') + ovz_conn._stop(fakes.INSTANCE) + self.mox.StubOutWithMock(ovz_conn, 'plug_vifs') + ovz_conn.plug_vifs(fakes.INSTANCE, fakes.NETWORKINFO) + self.mox.StubOutWithMock(ovz_conn, '_start') + ovz_conn._start(fakes.INSTANCE) + self.mox.ReplayAll() + ovz_conn._vzmigrate_setup_dest_host(fakes.INSTANCE, fakes.NETWORKINFO) + + def test_confirm_migration_resize_in_place(self): + self.mox.StubOutWithMock(ovz_utils, 'read_instance_metadata') + ovz_utils.read_instance_metadata(fakes.INSTANCE['id']).AndReturn( + {'migration_type': 'resize_in_place'}) + self.mox.StubOutWithMock(ovz_utils, 'remove_instance_metadata_key') + ovz_utils.remove_instance_metadata_key( + fakes.INSTANCE['id'], 'migration_type') + self.mox.StubOutWithMock(openvz_conn.ext_storage, 'OVZExtStorage') + openvz_conn.ext_storage.OVZExtStorage(fakes.INSTANCE['id']).AndReturn( + fakes.FakeOVZExtStorage(fakes.INSTANCE['id'])) + self.mox.ReplayAll() + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + ovz_conn.confirm_migration(None, fakes.INSTANCE, fakes.NETWORKINFO) + + def test_confirm_migration(self): + self.mox.StubOutWithMock(migration.OVZMigration, 'cleanup_source') + migration.OVZMigration.cleanup_source() + self.mox.StubOutWithMock(ovz_utils, 'read_instance_metadata') + ovz_utils.read_instance_metadata(fakes.INSTANCE['id']).AndReturn({}) + self.mox.StubOutWithMock(openvz_conn.ext_storage, 'OVZExtStorage') + openvz_conn.ext_storage.OVZExtStorage(fakes.INSTANCE['id']).AndReturn( + fakes.FakeOVZExtStorage(fakes.INSTANCE['id'])) + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + self.mox.StubOutWithMock(ovz_conn, 'get_info') + ovz_conn.get_info(fakes.INSTANCE).AndReturn(fakes.SHUTDOWNSTATUS) + self.mox.StubOutWithMock(ovz_conn, '_destroy') + ovz_conn._destroy(fakes.INSTANCE['id']) + self.mox.StubOutWithMock(ovz_conn, '_clean_orphaned_files') + ovz_conn._clean_orphaned_files(fakes.INSTANCE['id']) + self.mox.ReplayAll() + ovz_conn.confirm_migration(None, fakes.INSTANCE, fakes.NETWORKINFO) + + def test_finish_revert_migration(self): + self.mox.StubOutWithMock(ovz_utils, 'read_instance_metadata') + ovz_utils.read_instance_metadata(fakes.INSTANCE['id']).AndReturn({}) + self.mox.StubOutWithMock(migration.OVZMigration, 'cleanup_files') + migration.OVZMigration.cleanup_files() + ovz_conn = openvz_conn.OpenVzDriver( + manager.ComputeVirtAPI(None), False) + self.mox.StubOutWithMock(ovz_conn, 'resume') + ovz_conn.resume(fakes.INSTANCE, fakes.NETWORKINFO) + self.mox.ReplayAll() + ovz_conn.finish_revert_migration( + fakes.INSTANCE, fakes.NETWORKINFO, None) diff --git a/nova/tests/openvz/test_ext_storage.py b/nova/tests/openvz/test_ext_storage.py new file mode 100644 index 0000000..1688064 --- /dev/null +++ b/nova/tests/openvz/test_ext_storage.py @@ -0,0 +1,107 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2013 Rackspace +# 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 json +from nova import test +from nova.tests.openvz import fakes +from nova.virt.openvz.file_ext import ext_storage +import os +from oslo.config import cfg + +CONF = cfg.CONF + + +class OpenVzExtStorageTestCase(test.TestCase): + def setUp(self): + super(OpenVzExtStorageTestCase, self).setUp() + self.filename = '%s/%s.ext_storage' % (CONF.ovz_config_dir, + fakes.INSTANCE['id']) + self.filename = os.path.abspath(self.filename) + self.permissions = 600 + + def test_new_object(self): + self.mox.StubOutWithMock(ext_storage.ovzfile, 'OVZFile') + ext_storage.ovzfile.OVZFile(self.filename, self.permissions).AndReturn( + fakes.FakeOvzFile(self.filename, self.permissions)) + self.mox.ReplayAll() + ext_str = ext_storage.OVZExtStorage(fakes.INSTANCE['id']) + self.assertEqual(ext_str.instance_id, fakes.INSTANCE['id']) + self.assertEqual(ext_str.local_store.filename, self.filename) + self.assertEqual(ext_str.local_store.permissions, self.permissions) + + def test_load_volumes(self): + self.mox.StubOutWithMock(ext_storage.ovzfile, 'OVZFile') + ext_storage.ovzfile.OVZFile(self.filename, self.permissions).AndReturn( + fakes.FakeOvzFile(self.filename, self.permissions)) + self.mox.ReplayAll() + ext_str = ext_storage.OVZExtStorage(fakes.INSTANCE['id']) + self.assertTrue(isinstance(ext_str._volumes, dict)) + + def test_add_volume_success(self): + BDM = fakes.BDM['block_device_mapping'][0] + self.mox.StubOutWithMock(ext_storage.ovzfile, 'OVZFile') + ext_storage.ovzfile.OVZFile(self.filename, self.permissions).AndReturn( + fakes.FakeOvzFile(self.filename, self.permissions)) + self.mox.ReplayAll() + ext_str = ext_storage.OVZExtStorage(fakes.INSTANCE['id']) + for bdm in fakes.BDM['block_device_mapping']: + ext_str.add_volume(bdm['mount_device'], bdm['connection_info']) + + self.assertTrue(BDM['mount_device'] in ext_str._volumes) + self.assertEqual( + ext_str._volumes[BDM['mount_device']], BDM['connection_info']) + + def test_remove_volume_success(self): + BDM = fakes.BDM['block_device_mapping'][0] + self.mox.StubOutWithMock(ext_storage.ovzfile, 'OVZFile') + ext_storage.ovzfile.OVZFile(self.filename, self.permissions).AndReturn( + fakes.FakeOvzFile(self.filename, self.permissions)) + self.mox.ReplayAll() + ext_str = ext_storage.OVZExtStorage(fakes.INSTANCE['id']) + for bdm in fakes.BDM['block_device_mapping']: + ext_str.add_volume(bdm['mount_device'], bdm['connection_info']) + + self.assertTrue(BDM['mount_device'] in ext_str._volumes) + self.assertEqual( + ext_str._volumes[BDM['mount_device']], BDM['connection_info']) + + ext_str.remove_volume(BDM['mount_device']) + + self.assertFalse(BDM['mount_device'] in ext_str._volumes) + + def test_remove_volume_failure(self): + BDM = fakes.BDM['block_device_mapping'][0] + self.mox.StubOutWithMock(ext_storage.ovzfile, 'OVZFile') + ext_storage.ovzfile.OVZFile(self.filename, self.permissions).AndReturn( + fakes.FakeOvzFile(self.filename, self.permissions)) + self.mox.ReplayAll() + ext_str = ext_storage.OVZExtStorage(fakes.INSTANCE['id']) + ext_str.remove_volume(BDM['mount_device']) + + def test_save(self): + BDM = fakes.BDM['block_device_mapping'][0] + self.mox.StubOutWithMock(ext_storage.ovzfile, 'OVZFile') + ext_storage.ovzfile.OVZFile(self.filename, self.permissions).AndReturn( + fakes.FakeOvzFile(self.filename, self.permissions)) + self.mox.ReplayAll() + ext_str = ext_storage.OVZExtStorage(fakes.INSTANCE['id']) + for bdm in fakes.BDM['block_device_mapping']: + ext_str.add_volume(bdm['mount_device'], bdm['connection_info']) + + ext_str.save() + self.assertEqual( + json.dumps(ext_str._volumes), ext_str.local_store.contents) diff --git a/nova/tests/openvz/test_file.py b/nova/tests/openvz/test_file.py new file mode 100644 index 0000000..2ce96d2 --- /dev/null +++ b/nova/tests/openvz/test_file.py @@ -0,0 +1,126 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2013 Rackspace +# 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 __builtin__ +import mox +from nova import exception +from nova import test +from nova.tests.openvz import fakes +from nova.virt.openvz import driver as openvz_conn +from nova.virt.openvz import file as ovzfile +from nova.virt.openvz import utils as ovz_utils +from oslo.config import cfg + +CONF = cfg.CONF + + +class OpenVzFileTestCase(test.TestCase): + def setUp(self): + super(OpenVzFileTestCase, self).setUp() + self.fake_file = mox.MockAnything() + self.fake_file.readlines().AndReturn(fakes.FILECONTENTS.split()) + self.fake_file.writelines(mox.IgnoreArg()) + self.fake_file.read().AndReturn(fakes.FILECONTENTS) + + def test_touch_file_success(self): + fh = ovzfile.OVZFile(fakes.TEMPFILE, 755) + self.mox.StubOutWithMock(fh, 'make_path') + fh.make_path() + self.mox.StubOutWithMock(ovz_utils, 'execute') + ovz_utils.execute( + 'touch', fakes.TEMPFILE, run_as_root=True).AndReturn( + ('', fakes.ERRORMSG)) + self.mox.ReplayAll() + fh.touch() + + def test_touch_file_failure(self): + fh = ovzfile.OVZFile(fakes.TEMPFILE, 755) + self.mox.StubOutWithMock(fh, 'make_path') + fh.make_path() + self.mox.StubOutWithMock(ovz_utils, 'execute') + ovz_utils.execute( + 'touch', fakes.TEMPFILE, run_as_root=True).AndRaise( + exception.InstanceUnacceptable(fakes.ERRORMSG)) + self.mox.ReplayAll() + self.assertRaises(exception.InstanceUnacceptable, fh.touch) + + def test_read_file_success(self): + self.mox.StubOutWithMock(__builtin__, 'open') + __builtin__.open(mox.IgnoreArg(), 'r').AndReturn(self.fake_file) + self.mox.ReplayAll() + fh = ovzfile.OVZFile(fakes.TEMPFILE, 755) + fh.read() + + def test_read_file_failure(self): + self.mox.StubOutWithMock(__builtin__, 'open') + __builtin__.open(mox.IgnoreArg(), 'r').AndRaise( + exception.FileNotFound(fakes.ERRORMSG)) + self.mox.ReplayAll() + fh = ovzfile.OVZFile(fakes.TEMPFILE, 755) + self.assertRaises(exception.FileNotFound, fh.read) + + def test_write_to_file_success(self): + self.mox.StubOutWithMock(__builtin__, 'open') + __builtin__.open(mox.IgnoreArg(), 'w').AndReturn(self.fake_file) + self.mox.ReplayAll() + fh = ovzfile.OVZFile(fakes.TEMPFILE, 755) + fh.write() + + def test_write_to_file_failure(self): + self.mox.StubOutWithMock(__builtin__, 'open') + __builtin__.open(mox.IgnoreArg(), 'w').AndRaise( + exception.FileNotFound(fakes.ERRORMSG)) + self.mox.ReplayAll() + fh = ovzfile.OVZFile(fakes.TEMPFILE, 755) + self.assertRaises(exception.FileNotFound, fh.write) + + def test_set_perms_success(self): + self.mox.StubOutWithMock(ovz_utils, 'execute') + ovz_utils.execute( + 'chmod', 755, fakes.TEMPFILE, run_as_root=True).AndReturn( + ('', fakes.ERRORMSG)) + self.mox.ReplayAll() + fh = ovzfile.OVZFile(fakes.TEMPFILE, 755) + fh.set_permissions(755) + + def test_set_perms_failure(self): + self.mox.StubOutWithMock(ovz_utils, 'execute') + ovz_utils.execute( + 'chmod', 755, fakes.TEMPFILE, run_as_root=True).AndRaise( + exception.InstanceUnacceptable(fakes.ERRORMSG)) + self.mox.ReplayAll() + fh = ovzfile.OVZFile(fakes.TEMPFILE, 755) + self.assertRaises( + exception.InstanceUnacceptable, fh.set_permissions, 755) + + def test_make_path_and_dir_success(self): + self.mox.StubOutWithMock(ovz_utils, 'execute') + ovz_utils.execute( + 'mkdir', '-p', mox.IgnoreArg(), run_as_root=True).AndReturn( + ('', fakes.ERRORMSG)) + self.mox.StubOutWithMock(openvz_conn.os.path, 'exists') + openvz_conn.os.path.exists(mox.IgnoreArg()).AndReturn(False) + self.mox.ReplayAll() + fh = ovzfile.OVZFile(fakes.TEMPFILE, 755) + fh.make_path() + + def test_make_path_and_dir_exists(self): + self.mox.StubOutWithMock(openvz_conn.os.path, 'exists') + openvz_conn.os.path.exists(mox.IgnoreArg()).AndReturn(True) + self.mox.ReplayAll() + fh = ovzfile.OVZFile(fakes.TEMPFILE, 755) + fh.make_path() diff --git a/nova/tests/openvz/test_network.py b/nova/tests/openvz/test_network.py new file mode 100644 index 0000000..e096bf7 --- /dev/null +++ b/nova/tests/openvz/test_network.py @@ -0,0 +1,214 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2013 Rackspace +# 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 mox +from nova import exception +from nova import test +from nova.tests.openvz import fakes +from nova.virt.openvz import driver as openvz_conn +from nova.virt.openvz import network as openvz_net +from nova.virt.openvz.network_drivers import network_bridge +from oslo.config import cfg + +CONF = cfg.CONF + + +class OpenVzNetworkTestCase(test.TestCase): + def setUp(self): + super(OpenVzNetworkTestCase, self).setUp() + try: + CONF.injected_network_template + except AttributeError as err: + CONF.register_opt( + cfg.StrOpt( + 'injected_network_template', + default='nova/virt/interfaces.template', + help='Stub for network template for testing purposes') + ) + CONF.use_ipv6 = False + self.fake_file = mox.MockAnything() + self.fake_file.readlines().AndReturn(fakes.FILECONTENTS.split()) + self.fake_file.writelines(mox.IgnoreArg()) + self.fake_file.read().AndReturn(fakes.FILECONTENTS) + + def test_ovz_network_interfaces_add_success(self): + self.mox.StubOutWithMock(openvz_net.ovzshutdown, 'OVZShutdownFile') + openvz_net.ovzshutdown.OVZShutdownFile( + fakes.INSTANCE['id'], mox.IgnoreArg()).AndReturn( + fakes.FakeOVZShutdownFile(fakes.INSTANCE['id'], 700)) + self.mox.StubOutWithMock(openvz_net.ovzboot, 'OVZBootFile') + openvz_net.ovzboot.OVZBootFile( + fakes.INSTANCE['id'], mox.IgnoreArg()).AndReturn( + fakes.FakeOVZBootFile(fakes.INSTANCE['id'], 700)) + self.mox.StubOutWithMock(openvz_net.ovztc, 'OVZTcRules') + openvz_net.ovztc.OVZTcRules().MultipleTimes().AndReturn( + fakes.FakeOVZTcRules()) + self.mox.StubOutWithMock(openvz_net.OVZNetworkInterfaces, '_add_netif') + openvz_net.OVZNetworkInterfaces._add_netif( + fakes.INTERFACEINFO[0]['id'], + mox.IgnoreArg(), + mox.IgnoreArg(), + mox.IgnoreArg()).MultipleTimes() + self.mox.StubOutWithMock( + openvz_net.OVZNetworkInterfaces, '_set_nameserver') + self.mox.StubOutWithMock(openvz_net, 'OVZNetworkFile') + openvz_net.OVZNetworkFile( + ('/var/lib/vz/private/%s/etc/network/interfaces' % + fakes.INSTANCE['id'])).AndReturn( + fakes.FakeOVZNetworkFile('/etc/network/interfaces')) + openvz_net.OVZNetworkInterfaces._set_nameserver( + fakes.INTERFACEINFO[0]['id'], fakes.INTERFACEINFO[0]['dns']) + self.mox.ReplayAll() + ifaces = openvz_net.OVZNetworkInterfaces( + fakes.INTERFACEINFO) + ifaces.add() + + def test_ovz_network_interfaces_add_ip_success(self): + self.mox.StubOutWithMock(openvz_net.ovzshutdown, 'OVZShutdownFile') + openvz_net.ovzshutdown.OVZShutdownFile( + fakes.INSTANCE['id'], mox.IgnoreArg()).AndReturn( + fakes.FakeOVZShutdownFile(fakes.INSTANCE['id'], 700)) + self.mox.StubOutWithMock(openvz_net.ovzboot, 'OVZBootFile') + openvz_net.ovzboot.OVZBootFile( + fakes.INSTANCE['id'], mox.IgnoreArg()).AndReturn( + fakes.FakeOVZBootFile(fakes.INSTANCE['id'], 700)) + self.mox.StubOutWithMock(openvz_conn.ovz_utils, 'execute') + openvz_conn.ovz_utils.execute( + 'vzctl', 'set', fakes.INTERFACEINFO[0]['id'], '--save', '--ipadd', + fakes.INTERFACEINFO[0]['address'], run_as_root=True).AndReturn( + ('', fakes.ERRORMSG)) + self.mox.ReplayAll() + ifaces = openvz_net.OVZNetworkInterfaces(fakes.INTERFACEINFO) + ifaces._add_ip( + fakes.INTERFACEINFO[0]['id'], fakes.INTERFACEINFO[0]['address']) + + def test_ovz_network_interfaces_add_ip_failure(self): + self.mox.StubOutWithMock(openvz_net.ovzshutdown, 'OVZShutdownFile') + openvz_net.ovzshutdown.OVZShutdownFile( + fakes.INSTANCE['id'], mox.IgnoreArg()).AndReturn( + fakes.FakeOVZShutdownFile(fakes.INSTANCE['id'], 700)) + self.mox.StubOutWithMock(openvz_net.ovzboot, 'OVZBootFile') + openvz_net.ovzboot.OVZBootFile( + fakes.INSTANCE['id'], mox.IgnoreArg()).AndReturn( + fakes.FakeOVZBootFile(fakes.INSTANCE['id'], 700)) + self.mox.StubOutWithMock(openvz_conn.ovz_utils, 'execute') + openvz_conn.ovz_utils.execute( + 'vzctl', 'set', fakes.INTERFACEINFO[0]['id'], '--save', + '--ipadd', fakes.INTERFACEINFO[0]['address'], + run_as_root=True).AndRaise( + exception.InstanceUnacceptable(fakes.ERRORMSG)) + self.mox.ReplayAll() + ifaces = openvz_net.OVZNetworkInterfaces(fakes.INTERFACEINFO) + self.assertRaises( + exception.InstanceUnacceptable, ifaces._add_ip, + fakes.INTERFACEINFO[0]['id'], fakes.INTERFACEINFO[0]['address']) + + def test_ovz_network_interfaces_add_netif(self): + self.mox.StubOutWithMock(openvz_net.ovzshutdown, 'OVZShutdownFile') + openvz_net.ovzshutdown.OVZShutdownFile( + fakes.INSTANCE['id'], mox.IgnoreArg()).AndReturn( + fakes.FakeOVZShutdownFile(fakes.INSTANCE['id'], 700)) + self.mox.StubOutWithMock(openvz_net.ovzboot, 'OVZBootFile') + openvz_net.ovzboot.OVZBootFile( + fakes.INSTANCE['id'], mox.IgnoreArg()).AndReturn( + fakes.FakeOVZBootFile(fakes.INSTANCE['id'], 700)) + self.mox.StubOutWithMock(openvz_conn.ovz_utils, 'execute') + openvz_conn.ovz_utils.execute( + 'vzctl', 'set', fakes.INTERFACEINFO[0]['id'], '--save', + '--netif_add', + '%s,,veth%s.%s,%s,%s' % ( + fakes.INTERFACEINFO[0]['name'], + fakes.INTERFACEINFO[0]['id'], + fakes.INTERFACEINFO[0]['name'], + fakes.INTERFACEINFO[0]['mac'], + fakes.INTERFACEINFO[0]['bridge']), + run_as_root=True).AndReturn(('', fakes.ERRORMSG)) + self.mox.ReplayAll() + ifaces = openvz_net.OVZNetworkInterfaces(fakes.INTERFACEINFO) + ifaces._add_netif( + fakes.INTERFACEINFO[0]['id'], + fakes.INTERFACEINFO[0]['name'], + fakes.INTERFACEINFO[0]['bridge'], + fakes.INTERFACEINFO[0]['mac'] + ) + + def test_filename_factory_debian_variant(self): + self.mox.StubOutWithMock(openvz_net.ovzshutdown, 'OVZShutdownFile') + openvz_net.ovzshutdown.OVZShutdownFile( + fakes.INSTANCE['id'], mox.IgnoreArg()).AndReturn( + fakes.FakeOVZShutdownFile(fakes.INSTANCE['id'], 700)) + self.mox.StubOutWithMock(openvz_net.ovzboot, 'OVZBootFile') + openvz_net.ovzboot.OVZBootFile( + fakes.INSTANCE['id'], mox.IgnoreArg()).AndReturn( + fakes.FakeOVZBootFile(fakes.INSTANCE['id'], 700)) + self.mox.ReplayAll() + ifaces = openvz_net.OVZNetworkInterfaces(fakes.INTERFACEINFO) + for filename in ifaces._filename_factory(): + self.assertFalse('//' in filename) + + def test_set_nameserver_success(self): + self.mox.StubOutWithMock(openvz_net.ovzshutdown, 'OVZShutdownFile') + openvz_net.ovzshutdown.OVZShutdownFile( + fakes.INSTANCE['id'], mox.IgnoreArg()).AndReturn( + fakes.FakeOVZShutdownFile(fakes.INSTANCE['id'], 700)) + self.mox.StubOutWithMock(openvz_net.ovzboot, 'OVZBootFile') + openvz_net.ovzboot.OVZBootFile( + fakes.INSTANCE['id'], mox.IgnoreArg()).AndReturn( + fakes.FakeOVZBootFile(fakes.INSTANCE['id'], 700)) + self.mox.StubOutWithMock(openvz_net.ovz_utils, 'execute') + openvz_net.ovz_utils.execute( + 'vzctl', 'set', fakes.INTERFACEINFO[0]['id'], '--save', + '--nameserver', fakes.INTERFACEINFO[0]['dns'], + run_as_root=True).AndReturn(('', fakes.ERRORMSG)) + self.mox.ReplayAll() + ifaces = openvz_net.OVZNetworkInterfaces(fakes.INTERFACEINFO) + ifaces._set_nameserver( + fakes.INTERFACEINFO[0]['id'], fakes.INTERFACEINFO[0]['dns']) + + def test_set_nameserver_failure(self): + self.mox.StubOutWithMock(openvz_net.ovzshutdown, 'OVZShutdownFile') + openvz_net.ovzshutdown.OVZShutdownFile( + fakes.INSTANCE['id'], mox.IgnoreArg()).AndReturn( + fakes.FakeOVZShutdownFile(fakes.INSTANCE['id'], 700)) + self.mox.StubOutWithMock(openvz_net.ovzboot, 'OVZBootFile') + openvz_net.ovzboot.OVZBootFile( + fakes.INSTANCE['id'], mox.IgnoreArg()).AndReturn( + fakes.FakeOVZBootFile(fakes.INSTANCE['id'], 700)) + self.mox.StubOutWithMock(openvz_conn.ovz_utils, 'execute') + openvz_conn.ovz_utils.execute( + 'vzctl', 'set', fakes.INTERFACEINFO[0]['id'], '--save', + '--nameserver', fakes.INTERFACEINFO[0]['dns'], + run_as_root=True).AndRaise(exception.InstanceUnacceptable( + fakes.ERRORMSG)) + self.mox.ReplayAll() + ifaces = openvz_net.OVZNetworkInterfaces(fakes.INTERFACEINFO) + self.assertRaises( + exception.InstanceUnacceptable, ifaces._set_nameserver, + fakes.INTERFACEINFO[0]['id'], fakes.INTERFACEINFO[0]['dns']) + + def test_ovz_network_bridge_driver_plug(self): + self.mox.StubOutWithMock( + openvz_conn.linux_net.LinuxBridgeInterfaceDriver, + 'ensure_vlan_bridge' + ) + openvz_conn.linux_net.LinuxBridgeInterfaceDriver.ensure_vlan_bridge( + mox.IgnoreArg(), mox.IgnoreArg(), mox.IgnoreArg() + ) + self.mox.ReplayAll() + driver = network_bridge.OVZNetworkBridgeDriver() + for network, mapping in fakes.NETWORKINFO: + driver.plug(fakes.INSTANCE, network, mapping) diff --git a/nova/tests/openvz/test_utils.py b/nova/tests/openvz/test_utils.py new file mode 100644 index 0000000..1737537 --- /dev/null +++ b/nova/tests/openvz/test_utils.py @@ -0,0 +1,302 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2013 Rackspace +# 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 mox +from nova import exception +from nova.openstack.common import processutils +from nova import test +from nova.tests.openvz import fakes +from nova.virt.openvz import utils as ovz_utils +from oslo.config import cfg +import uuid + +CONF = cfg.CONF + + +class OpenVzUtilsTestCase(test.TestCase): + def setUp(self): + super(OpenVzUtilsTestCase, self).setUp() + + def test_execute_process_execution_error(self): + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'cat', '/proc/cpuinfo', run_as_root=False).AndRaise( + processutils.ProcessExecutionError(fakes.ERRORMSG)) + self.mox.ReplayAll() + self.assertRaises( + exception.InstanceUnacceptable, ovz_utils.execute, 'cat', + '/proc/cpuinfo', run_as_root=False) + + def test_execute_process_execution_error_no_raise_on_error(self): + self.mox.StubOutWithMock(ovz_utils.utils, 'execute') + ovz_utils.utils.execute( + 'cat', '/proc/cpuinfo', run_as_root=False).AndRaise( + processutils.ProcessExecutionError) + self.mox.ReplayAll() + ovz_utils.execute( + 'cat', '/proc/cpuinfo', run_as_root=False, raise_on_error=False) + + def test_mkfs_uuid(self): + fs_uuid = uuid.uuid4() + path = '/dev/sdgg' + self.mox.StubOutWithMock(ovz_utils, 'execute') + ovz_utils.execute( + 'mkfs', '-F', '-t', 'ext3', '-U', fs_uuid, path, run_as_root=True) + self.mox.ReplayAll() + ovz_utils.mkfs(path, 'ext3', fs_uuid) + + def test_mkfs_label(self): + path = '/dev/sdgg' + fs_label = 'STORAGE' + self.mox.StubOutWithMock(ovz_utils, 'execute') + ovz_utils.execute( + 'mkfs', '-F', '-t', 'ext3', '-U', mox.IgnoreArg(), '-L', fs_label, + path, run_as_root=True) + self.mox.ReplayAll() + ovz_utils.mkfs(path, 'ext3', None, fs_label) + + def test_get_fs_uuid_success(self): + dev = '/dev/sdgg' + self.mox.StubOutWithMock(ovz_utils, 'execute') + ovz_utils.execute( + 'blkid', '-o', 'value', '-s', 'UUID', dev, + raise_on_error=False, run_as_root=True).AndReturn(fakes.BLKID) + self.mox.ReplayAll() + fs_uuid = ovz_utils.get_fs_uuid(dev) + self.assertEqual(fs_uuid, fakes.BLKID.strip()) + + def test_get_fs_uuid_failure(self): + dev = '/dev/sdgg' + self.mox.StubOutWithMock(ovz_utils, 'execute') + ovz_utils.execute( + 'blkid', '-o', 'value', '-s', 'UUID', dev, + raise_on_error=False, run_as_root=True).AndReturn('\n') + self.mox.ReplayAll() + fs_uuid = ovz_utils.get_fs_uuid(dev) + self.assertFalse(fs_uuid) + + def test_get_vcpu_total_success(self): + self.mox.StubOutWithMock( + ovz_utils.multiprocessing, 'cpu_count') + ovz_utils.multiprocessing.cpu_count().AndReturn( + fakes.HOSTSTATS['vcpus']) + self.mox.ReplayAll() + result = ovz_utils.get_vcpu_total() + self.assertEqual(result, fakes.HOSTSTATS['vcpus']) + + def test_get_vcpu_total_failure(self): + self.mox.StubOutWithMock( + ovz_utils.multiprocessing, 'cpu_count') + ovz_utils.multiprocessing.cpu_count().AndRaise(NotImplementedError) + self.mox.ReplayAll() + result = ovz_utils.get_vcpu_total() + self.assertEqual(result, 0) + + def test_get_cpuinfo_not_running_on_linux(self): + self.mox.StubOutWithMock(ovz_utils, 'sys') + self.mox.StubOutWithMock(ovz_utils.sys, 'platform') + self.mox.StubOutWithMock(ovz_utils.sys.platform, 'upper') + ovz_utils.sys.platform.upper().AndReturn('DARWIN') + self.mox.ReplayAll() + result = ovz_utils.get_cpuinfo() + self.assertEqual(result, 0) + + def test_iscsi_initiator(self): + self.mox.StubOutWithMock(ovz_utils.utils, 'read_file_as_root') + ovz_utils.utils.read_file_as_root( + '/etc/iscsi/initiatorname.iscsi').AndReturn(fakes.ISCSIINITIATOR) + self.mox.ReplayAll() + iscsi_initiator = ovz_utils.get_iscsi_initiator() + self.assertEqual(fakes.INITIATORNAME, iscsi_initiator) + + def test_get_cpuunits_capability(self): + self.mox.StubOutWithMock(ovz_utils, 'execute') + ovz_utils.execute( + 'vzcpucheck', run_as_root=True).AndReturn('') + self.mox.ReplayAll() + self.assertRaises( + exception.InvalidCPUInfo, ovz_utils.get_cpuunits_capability) + + def test_get_vcpu_used(self): + self.mox.StubOutWithMock(ovz_utils, 'get_cpuunits_capability') + ovz_utils.get_cpuunits_capability().AndReturn(fakes.CPUUNITSCAPA) + self.mox.StubOutWithMock(ovz_utils, 'get_vcpu_total') + ovz_utils.get_vcpu_total().AndReturn(fakes.HOSTSTATS['vcpus']) + self.mox.ReplayAll() + used = int(fakes.HOSTSTATS['vcpus'] * + (float(fakes.CPUUNITSCAPA['subscribed']) / + fakes.CPUUNITSCAPA['total'])) + result = ovz_utils.get_vcpu_used() + self.assertEqual(result, used) + + def test_get_memory_mb_total_not_running_on_linux(self): + self.mox.StubOutWithMock(ovz_utils, 'sys') + self.mox.StubOutWithMock(ovz_utils.sys, 'platform') + self.mox.StubOutWithMock(ovz_utils.sys.platform, 'upper') + ovz_utils.sys.platform.upper().AndReturn('DARWIN') + self.mox.ReplayAll() + result = ovz_utils.get_memory_mb_total() + self.assertEqual(result, 1) + + def test_get_memory_mb_used(self): + self.mox.StubOutWithMock(ovz_utils, 'execute') + ovz_utils.execute( + 'vzlist', '--all', '-H', '-o', 'ctid,privvmpages.l', + raise_on_error=False, run_as_root=True).AndReturn( + fakes.PRIVVMPAGES) + self.mox.ReplayAll() + memory_used = (((int( + fakes.PRIVVMPAGES_1024.strip().split()[1]) * 4096) / 1024 ** 2) + + ((int( + fakes.PRIVVMPAGES_2048.strip().split()[1]) * + 4096) / 1024 ** 2)) + result = ovz_utils.get_memory_mb_used() + self.assertEqual(memory_used, result) + + def test_get_memory_mb_used_instance(self): + self.mox.StubOutWithMock(ovz_utils, 'execute') + ovz_utils.execute( + 'vzlist', '-H', '-o', 'ctid,privvmpages.l', + str(fakes.INSTANCE['id']), + raise_on_error=False, run_as_root=True).AndReturn( + fakes.PRIVVMPAGES_2048) + self.mox.ReplayAll() + memory_used = ((int( + fakes.PRIVVMPAGES_2048.strip().split()[1]) * 4096) / 1024 ** 2) + result = ovz_utils.get_memory_mb_used(fakes.INSTANCE['id']) + self.assertEqual(memory_used, result) + + def test_get_local_gb_total(self): + self.mox.StubOutWithMock(ovz_utils.os, 'statvfs') + ovz_utils.os.statvfs( + CONF.ovz_ve_private_dir).AndReturn(fakes.STATVFSRESULT) + self.mox.ReplayAll() + total = ((fakes.STATVFSRESULT.f_frsize * fakes.STATVFSRESULT.f_blocks) + / 1024 ** 3) + result = ovz_utils.get_local_gb_total() + self.assertEqual(total, result) + + def test_get_local_gb_used(self): + self.mox.StubOutWithMock(ovz_utils.os, 'statvfs') + ovz_utils.os.statvfs( + CONF.ovz_ve_private_dir).AndReturn(fakes.STATVFSRESULT) + self.mox.ReplayAll() + used = ((fakes.STATVFSRESULT.f_frsize * + (fakes.STATVFSRESULT.f_blocks - fakes.STATVFSRESULT.f_bfree) + ) / (1024 ** 3)) + result = ovz_utils.get_local_gb_used() + self.assertEqual(used, result) + + def test_get_hypervisor_version(self): + self.mox.StubOutWithMock(ovz_utils.platform, 'uname') + ovz_utils.platform.uname().AndReturn(fakes.UNAME) + self.mox.ReplayAll() + result = ovz_utils.get_hypervisor_version() + self.assertEqual(result, fakes.UNAME[2]) + + def test_delete_path_good(self): + self.mox.StubOutWithMock(ovz_utils, 'execute') + ovz_utils.execute( + 'rmdir', CONF.ovz_ve_private_dir, + run_as_root=True).AndReturn(('', '')) + self.mox.ReplayAll() + self.assertTrue(ovz_utils.delete_path(CONF.ovz_ve_private_dir)) + + def test_delete_path_bad(self): + self.mox.StubOutWithMock(ovz_utils, 'execute') + ovz_utils.execute( + 'rmdir', CONF.ovz_ve_private_dir, + run_as_root=True).AndRaise(exception.InstanceUnacceptable( + fakes.ERRORMSG)) + self.mox.ReplayAll() + self.assertFalse(ovz_utils.delete_path(CONF.ovz_ve_private_dir)) + + def test_set_permissions(self): + perms = 755 + filename = '/tmp/testfile' + self.mox.StubOutWithMock(ovz_utils, 'execute') + ovz_utils.execute('chmod', perms, filename, run_as_root=True) + self.mox.ReplayAll() + ovz_utils.set_permissions(filename, perms) + + def test_save_instance_metadata_success(self): + self.mox.StubOutWithMock(ovz_utils.context, 'get_admin_context') + ovz_utils.context.get_admin_context().AndReturn(fakes.ADMINCONTEXT) + self.mox.StubOutWithMock(ovz_utils.conductor, 'instance_get') + ovz_utils.conductor.instance_get( + fakes.ADMINCONTEXT, fakes.INSTANCE['id']).AndReturn(fakes.INSTANCE) + self.mox.StubOutWithMock( + ovz_utils.conductor, 'instance_update') + ovz_utils.conductor.instance_update( + fakes.ADMINCONTEXT, fakes.INSTANCE['uuid'], + system_metadata=ovz_utils.format_system_metadata( + fakes.INSTANCE['system_metadata'])) + self.mox.ReplayAll() + ovz_utils.save_instance_metadata( + fakes.INSTANCE['id'], fakes.METAKEY, fakes.METAVALUE) + + def test_save_instance_metadata_not_found(self): + self.mox.StubOutWithMock(ovz_utils.context, 'get_admin_context') + ovz_utils.context.get_admin_context().AndReturn(fakes.ADMINCONTEXT) + self.mox.StubOutWithMock(ovz_utils.conductor, 'instance_get') + ovz_utils.conductor.instance_get( + fakes.ADMINCONTEXT, fakes.INSTANCE['id']).AndReturn(fakes.INSTANCE) + self.mox.StubOutWithMock( + ovz_utils.conductor, 'instance_update') + ovz_utils.conductor.instance_update( + fakes.ADMINCONTEXT, fakes.INSTANCE['uuid'], + system_metadata=ovz_utils.format_system_metadata( + fakes.INSTANCE['system_metadata'])).AndRaise( + exception.InstanceNotFound(fakes.ERRORMSG)) + self.mox.ReplayAll() + ovz_utils.save_instance_metadata( + fakes.INSTANCE['id'], fakes.METAKEY, fakes.METAVALUE) + + def test_read_instance_metadata_success(self): + self.mox.StubOutWithMock(ovz_utils.context, 'get_admin_context') + ovz_utils.context.get_admin_context().AndReturn(fakes.ADMINCONTEXT) + self.mox.StubOutWithMock(ovz_utils.conductor, 'instance_get') + ovz_utils.conductor.instance_get( + fakes.ADMINCONTEXT, fakes.INSTANCE['id']).AndReturn(fakes.INSTANCE) + self.mox.ReplayAll() + meta = ovz_utils.read_instance_metadata(fakes.INSTANCE['id']) + self.assertTrue(isinstance(meta, dict)) + self.assertEqual(meta[fakes.METAKEY], fakes.METAVALUE) + + def test_read_instance_metadata_not_found(self): + self.mox.StubOutWithMock(ovz_utils.context, 'get_admin_context') + ovz_utils.context.get_admin_context().AndReturn(fakes.ADMINCONTEXT) + self.mox.StubOutWithMock(ovz_utils.conductor, 'instance_get') + ovz_utils.conductor.instance_get( + fakes.ADMINCONTEXT, fakes.INSTANCE['id']).AndRaise( + exception.InstanceNotFound(fakes.ERRORMSG)) + self.mox.ReplayAll() + meta = ovz_utils.read_instance_metadata(fakes.INSTANCE['id']) + self.assertTrue(isinstance(meta, dict)) + self.assertTrue(len(meta) == 0) + + def test_read_instance_metadata_dberror(self): + self.mox.StubOutWithMock(ovz_utils.context, 'get_admin_context') + ovz_utils.context.get_admin_context().AndReturn(fakes.ADMINCONTEXT) + self.mox.StubOutWithMock(ovz_utils.conductor, 'instance_get') + ovz_utils.conductor.instance_get( + fakes.ADMINCONTEXT, fakes.INSTANCE['id']).AndRaise( + exception.InstanceNotFound(fakes.ERRORMSG)) + self.mox.ReplayAll() + meta = ovz_utils.read_instance_metadata(fakes.INSTANCE['id']) + self.assertTrue(isinstance(meta, dict)) + self.assertTrue(len(meta) == 0) diff --git a/nova/virt/openvz/driver.py b/nova/virt/openvz/driver.py index c73d0d9..8eb009a 100644 --- a/nova/virt/openvz/driver.py +++ b/nova/virt/openvz/driver.py @@ -29,13 +29,14 @@ from nova import exception from nova.network import linux_net from nova.openstack.common import importutils from nova.openstack.common import log as logging -from nova import utils +from nova.openstack.common import loopingcall from nova.virt import driver from nova.virt import images from nova.virt.openvz import file as ovzfile from nova.virt.openvz.file_ext import boot as ovzboot from nova.virt.openvz.file_ext import ext_storage from nova.virt.openvz.file_ext import shutdown as ovzshutdown +from nova.virt.openvz import migration as ovz_migration from nova.virt.openvz import network as ovznetwork from nova.virt.openvz.network_drivers import tc as ovztc from nova.virt.openvz import utils as ovz_utils @@ -43,6 +44,7 @@ from nova.virt.openvz.volume_drivers import iscsi as ovziscsi import os from oslo.config import cfg import socket +import time openvz_conn_opts = [ cfg.StrOpt('ovz_template_path', @@ -85,6 +87,28 @@ openvz_conn_opts = [ cfg.StrOpt('ovz_tmp_dir', default='/var/tmp', help='Directory to use as temporary storage'), + cfg.StrOpt('ovz_migration_method', + default='python', + help='Method to use for migrations'), + cfg.StrOpt('ovz_migration_user', + default='nova', + help='User to use for running migrations'), + cfg.StrOpt('ovz_migration_transport', + default='rsync', + help='Method to use to transport migrations'), + cfg.StrOpt('ovz_vzmigrate_opts', + default=None, + help='Optional arguments to pass to vzmigrate'), + cfg.BoolOpt('ovz_vzmigrate_online_migration', + default=True, + help='Perform an online migration of a container'), + cfg.BoolOpt('ovz_vzmigrate_destroy_source_container_on_migrate', + default=True, + help='If a migration is successful do we delete the ' + 'container on the old host'), + cfg.BoolOpt('ovz_vzmigrate_verbose_migration_logging', + default=True, + help='Log verbose messages from vzmigrate command'), cfg.BoolOpt('ovz_use_cpuunit', default=True, help='Use OpenVz cpuunits for guaranteed minimums'), @@ -341,7 +365,7 @@ class OpenVzDriver(driver.ComputeDriver): for network, mapping in network_info: if mapping['ips']: has_networking = True - except Exception: + except ValueError: has_networking = False if has_networking: self.plug_vifs(instance, network_info) @@ -366,7 +390,7 @@ class OpenVzDriver(driver.ComputeDriver): admin_password) # Begin making our looping async call - timer = utils.FixedIntervalLoopingCall() + timer = loopingcall.FixedIntervalLoopingCall() # I stole this from the libvirt driver but it is appropriate to # have this looping timer call so that if a VE doesn't start right @@ -789,7 +813,8 @@ class OpenVzDriver(driver.ComputeDriver): '--numfile', max_file_descriptors, run_as_root=True) - def _set_instance_size(self, instance, network_info=None): + def _set_instance_size(self, instance, network_info=None, + is_migration=False): """ Given that these parameters make up and instance's 'size' we are bundling them together to make resizing an instance on the host @@ -800,14 +825,32 @@ class OpenVzDriver(driver.ComputeDriver): LOG.debug(_('Instance system metadata: %s') % instance_size) - instance_memory_bytes = ((int(instance_size['instance_type_memory_mb']) - * 1024) * 1024) - instance_memory_pages = self._calc_pages( - instance_size['instance_type_memory_mb']) - percent_of_resource = self._percent_of_resource( - instance_size['instance_type_memory_mb']) + if is_migration: + instance_memory_mb = instance_size.get( + 'new_instance_type_memory_mb', None) + if not instance_memory_mb: + instance_memory_mb = instance_size.get( + 'instance_type_memory_mb') + instance_vcpus = instance_size.get('new_instance_type_vcpus', None) + if not instance_vcpus: + instance_vcpus = instance_size.get('instance_type_vcpus') + instance_root_gb = instance_size.get( + 'new_instance_type_root_gb', None) + if not instance_root_gb: + instance_root_gb = instance_size.get('instance_type_root_gb') + else: + instance_memory_mb = instance_size.get('instance_type_memory_mb') + instance_vcpus = instance_size.get('instance_type_vcpus') + instance_root_gb = instance_size.get('instance_type_root_gb') + + instance_memory_mb = int(instance_memory_mb) + instance_vcpus = int(instance_vcpus) + instance_root_gb = int(instance_root_gb) + + instance_memory_bytes = ((instance_memory_mb * 1024) * 1024) + instance_memory_pages = self._calc_pages(instance_memory_mb) + percent_of_resource = self._percent_of_resource(instance_memory_mb) - instance_memory_mb = int(instance_size['instance_type_memory_mb']) memory_unit_size = int(CONF.ovz_memory_unit_size) max_fd_per_unit = int(CONF.ovz_file_descriptors_per_unit) max_fd = int(instance_memory_mb / memory_unit_size) * max_fd_per_unit @@ -821,18 +864,16 @@ class OpenVzDriver(driver.ComputeDriver): if CONF.ovz_use_cpulimit: self._set_cpulimit(instance, percent_of_resource) if CONF.ovz_use_cpus: - self._set_cpus(instance, instance_size['instance_type_vcpus']) + self._set_cpus(instance, instance_vcpus) if CONF.ovz_use_ioprio: - self._set_ioprio( - instance, int(instance_size['instance_type_memory_mb'])) + self._set_ioprio(instance, instance_memory_mb) if CONF.ovz_use_disk_quotas: - self._set_diskspace( - instance, instance_size['instance_type_root_gb']) + self._set_diskspace(instance, instance_root_gb) if network_info: - self._generate_tc_rules(instance, network_info) + self._generate_tc_rules(instance, network_info, is_migration) - def _generate_tc_rules(self, instance, network_info): + def _generate_tc_rules(self, instance, network_info, is_migration=False): """ Utility method to generate tc info for instances that have been resized and/or migrated @@ -840,10 +881,22 @@ class OpenVzDriver(driver.ComputeDriver): LOG.debug(_('Setting network sizing')) bf = ovzboot.OVZBootFile(instance['id'], 755) sf = ovzshutdown.OVZShutdownFile(instance['id'], 755) + + if not is_migration: + with sf: + LOG.debug(_('Cleaning TC rules for %s') % instance['id']) + sf.read() + sf.run_contents(raise_on_error=False) + + # On resize we throw away existing tc_id and make a new one + # because the resize *could* have taken place on a different host + # where the tc_id is already in use. + meta = ovz_utils.read_instance_metadata(instance['id']) + tc_id = meta.get('tc_id', None) + if tc_id: + ovz_utils.remove_instance_metadata_key(instance['id'], 'tc_id') + with sf: - LOG.debug(_('Cleaning TC rules for %s') % instance['id']) - sf.read() - sf.run_contents() sf.set_contents(list()) with bf: @@ -1148,7 +1201,7 @@ class OpenVzDriver(driver.ComputeDriver): context, instance['uuid'], {'power_state': power_state.NOSTATE}) LOG.error(_('During reboot %s disappeared') % instance['name']) - raise utils.LoopingCallDone + raise loopingcall.LoopingCallDone if state == power_state.RUNNING: self.virtapi.instance_update( @@ -1160,12 +1213,12 @@ class OpenVzDriver(driver.ComputeDriver): with bf: bf.read() bf.run_contents() - raise utils.LoopingCallDone + raise loopingcall.LoopingCallDone elif state == power_state.NOSTATE: LOG.error(_('Error rebooting %s') % instance['name']) - raise utils.LoopingCallDone + raise loopingcall.LoopingCallDone - timer = utils.FixedIntervalLoopingCall(_wait_for_reboot) + timer = loopingcall.FixedIntervalLoopingCall(_wait_for_reboot) return timer.start(interval=0.5) def _inject_files(self, instance, files_to_inject): @@ -1339,7 +1392,7 @@ class OpenVzDriver(driver.ComputeDriver): self._detach_volumes( instance, block_device_info) - timer = utils.FixedIntervalLoopingCall() + timer = loopingcall.FixedIntervalLoopingCall() def _wait_for_destroy(): try: @@ -1427,7 +1480,28 @@ class OpenVzDriver(driver.ComputeDriver): ext_str.add_volume(mountpoint, connection_info) ext_str.save() - def _detach_volumes(self, instance, block_device_mapping): + def _disconnect_volume(self, connection_info, instance, mountpoint, + container_is_running=True): + """ + Necessary for migrations to disconnect but not permanently remove + volumes. + + :param connection_info: + :param instance: + :param mountpoint: + :return: + """ + if connection_info['driver_volume_type'] == 'iscsi': + volume = ovziscsi.OVZISCSIStorageDriver( + instance['id'], mountpoint, connection_info) + else: + raise NotImplementedError( + _('There are no suitable storage drivers')) + + volume.detach(container_is_running) + + def _detach_volumes(self, instance, block_device_mapping, + disconnect_only=False, container_is_running=True): """ Move bulk operations of volume connections back into the driver as they are relevant here and no longer need to be in their own module. @@ -1436,9 +1510,14 @@ class OpenVzDriver(driver.ComputeDriver): :return: None """ for volume in block_device_mapping['block_device_mapping']: - self.detach_volume( - volume['connection_info'], instance, - volume['mount_device']) + if disconnect_only: + self._disconnect_volume(volume['connection_info'], instance, + volume['mount_device'], + container_is_running) + else: + self.detach_volume( + volume['connection_info'], instance, + volume['mount_device']) def detach_volume(self, connection_info, instance, mountpoint=None): """ @@ -1448,14 +1527,7 @@ class OpenVzDriver(driver.ComputeDriver): if not mountpoint: mountpoint = connection_info['mount_device'] - if connection_info['driver_volume_type'] == 'iscsi': - volume = ovziscsi.OVZISCSIStorageDriver( - instance['id'], mountpoint, connection_info) - else: - raise NotImplementedError( - _('There are no suitable storage drivers')) - - volume.detach() + self._disconnect_volume(connection_info, instance, mountpoint) # Remove storage connection info from the storage repo for the # instance. @@ -1505,10 +1577,6 @@ class OpenVzDriver(driver.ComputeDriver): if state != new_state: state = new_state - # Set the new instance power_state - self.virtapi.instance_update( - context.get_admin_context(), instance['uuid'], - {'power_state': state}) LOG.debug( _('OpenVz says instance %(id)s is in state %(state)s') % @@ -1612,6 +1680,309 @@ class OpenVzDriver(driver.ComputeDriver): 'host': CONF.host } + def migrate_disk_and_power_off(self, context, instance, dest, + instance_type, network_info, + block_device_info=None): + """ + Transfers the disk of a running instance in multiple phases, turning + off the instance before the end. + """ + LOG.debug(_('Migration context: %s') % context) + LOG.debug(_('Migration instance: %s') % instance) + LOG.debug(_('Migration dest: %s') % dest) + LOG.debug(_('Migration instance_type: %s') % instance_type) + LOG.debug(_('Migration network_info: %s') % network_info) + + if not dest: + LOG.error(_('No destination given to migration')) + raise exception.MigrationError( + _('Migration destination is: %s') % dest) + + if dest == CONF.host: + # if this is an inplace resize we don't need to do any of this + LOG.debug(_('This is an inplace migration')) + ovz_utils.save_instance_metadata(instance['id'], 'migration_type', + 'resize_in_place') + return + + # Validate the ovz_migration_method flag + if CONF.ovz_migration_method not in ['vzmigrate', 'python']: + raise exception.MigrationError( + _('I do not understand your migration method')) + + # Find out if we have external volumes, this will determine + # if we will freeze the instance and attempt to preserve state of if + # we will stop the instance completely to preserve the integrity + # of the attached filesystems. + if block_device_info: + live_migration = False + self._stop(instance) + self._detach_volumes( + instance, block_device_info, True, live_migration) + else: + live_migration = True + self.suspend(instance) + + LOG.debug(_('ovz_migration_method is: %s') % + CONF.ovz_migration_method) + if CONF.ovz_migration_method == 'vzmigrate': + self._vzmigration_send_to_host(instance, dest) + elif CONF.ovz_migration_method == 'python': + self._pymigration_send_to_host( + instance, ovz_utils.generate_network_dict(instance['id'], + network_info), + block_device_info, dest, live_migration) + + def _pymigration_send_to_host(self, instance, network_info, + block_device_info, dest, live_migration): + """ + This performs a more complex but more secure migration using a pure + python implemented vz migration driver. + """ + LOG.debug(_('Beginning pure python based migration')) + mobj = ovz_migration.OVZMigration( + instance, network_info, block_device_info, dest, live_migration) + mobj.dump_and_transfer_instance() + mobj.send() + + def _vzmigration_send_to_host(self, instance, dest): + """ + This performs a simple migration using openvz's supplied vzmigrate + script. It requires shared keys for root across all hosts and + does not support containers with externally attached volumes. And + currently TC rules aren't preserved. + """ + LOG.debug(_('Beginning vzmigrate based migration')) + cmd = ['vzmigrate'] + if CONF.ovz_vzmigrate_opts: + if isinstance(CONF.ovz_vzmigrate_opts, str): + cmd += CONF.ovz_vzmigrate_opts.split() + elif isinstance(CONF.ovz_vzmigrate_opts, list): + cmd += CONF.ovz_vzmigrate_opts + if CONF.ovz_vzmigrate_online_migration: + cmd.append('--online') + if CONF.ovz_vzmigrate_destroy_source_container_on_migrate: + cmd += ['-r', 'yes'] + if CONF.ovz_vzmigrate_verbose_migration_logging: + cmd.append('-v') + cmd.append(dest) + cmd.append(instance['id']) + LOG.debug( + _('Beginning the migration of %(instance_id)s to %(dest)s') % + {'instance_id': instance['id'], 'dest': dest}) + out = ovz_utils.execute(*cmd, run_as_root=True) + LOG.debug(_('Output from migration process: %s') % out) + + def finish_migration(self, context, migration, instance, disk_info, + network_info, image_meta, resize_instance, + block_device_info=None): + """Completes a resize, turning on the migrated instance + + :param network_info: + :py:meth:`~nova.network.manager.NetworkManager.get_instance_nw_info` + :param image_meta: image object returned by nova.image.glance that + defines the image from which this instance + was created + """ + # Get the instance metadata to see what we need to do + meta = ovz_utils.read_instance_metadata(instance['id']) + migration_type = meta.get('migration_type') + + if migration_type == 'resize_in_place': + # This is a resize on the same host so its simple, resize + # in place and then exit the method + self._set_instance_size(instance, network_info, False) + return + + if block_device_info: + # It is assumed that if there are externally attached volumes + # then this is not a live migration. + live_migration = False + else: + live_migration = True + + if CONF.ovz_migration_method == 'vzmigrate': + self._vzmigrate_setup_dest_host(instance, network_info) + elif CONF.ovz_migration_method == 'python': + self._pymigrate_finish_migration(instance, + network_info, + live_migration) + + if block_device_info: + # Once the files have been moved into place we need to attach + # volumes. + self._attach_volumes(instance, block_device_info) + + # Somehow the name of the instance is lost in migration so + # set it here. + self._set_name(instance) + + # The uuid is lost from the description field in the migration + # so set it here. + self._set_description(instance) + + if resize_instance: + LOG.debug(_('A resize after migration was requested: %s') % + instance['id']) + self._set_instance_size(instance, network_info, True) + LOG.debug(_('Resized instance after migration: %s') % + instance['id']) + else: + LOG.debug(_('Regenerating TC rules for instance %s') % + instance['id']) + self._generate_tc_rules(instance, network_info, True) + LOG.debug(_('Regenerated TC rules for instance %s') % + instance['id']) + + if not live_migration: + self._start(instance) + + def _pymigrate_finish_migration(self, instance, network_info, + live_migration): + """ + Take all transferred files and put them back into place to create a + working instance. + """ + LOG.debug(_('Beginning python based finish_migration')) + interfaces = ovz_utils.generate_network_dict(instance['id'], + network_info) + mobj = ovz_migration.OVZMigration( + instance, interfaces, None, live_migration) + mobj.undump_instance() + + # Crude but we just need to give things time to settle before cleaning + # up all the dumped stuff + # TODO(imsplitbit): maybe a wait_for_start method with a looping + # timer is better here, will check into it soon + time.sleep(5) + mobj.cleanup_destination() + LOG.debug(_('Finished python based finish_migration')) + + def _vzmigrate_setup_dest_host(self, instance, network_info): + """ + Sequence to run on destination host should the migration be done + by the vzmigrate tools. + """ + LOG.debug(_('Stopping instance: %s') % instance['id']) + self._stop(instance) + LOG.debug(_('Stopped instance: %s') % instance['id']) + + self.plug_vifs(instance, network_info) + + LOG.debug(_('Starting instance: %s') % instance['id']) + self._start(instance) + LOG.debug(_('Started instance: %s') % instance['id']) + + def confirm_migration(self, migration, instance, network_info): + """ + Run on the source host to confirm the migration and cleans up the + the files from the source host. + """ + LOG.debug(_('Beginning confirm migration for %s') % instance['id']) + + # Get the instance metadata to see what we need to do + meta = ovz_utils.read_instance_metadata(instance['id']) + migration_type = meta.get('migration_type') + + live_migration = True + ext_str = ext_storage.OVZExtStorage(instance['id']) + if ext_str._volumes: + live_migration = False + + if migration_type == 'resize_in_place': + # This is a resize on the same host so its simple, resize + # in place and then exit the method + if ovz_utils.remove_instance_metadata_key(instance['id'], + 'migration_type'): + LOG.debug(_('Removed migration_type metadata')) + else: + LOG.debug(_('Failed to remove migration_type metadata')) + return + + try: + status = self.get_info(instance)['state'] + LOG.debug(_('State in confirm_migration: %s') % status) + if status == power_state.RUNNING: + LOG.warn( + _('Instance %s is running on source after migration') % + instance['uuid']) + self._stop(instance) + status = self.get_info(instance)['state'] + + if status == power_state.SHUTDOWN: + LOG.debug(_('Cleaning up migration on source host')) + mobj = ovz_migration.OVZMigration( + instance, ovz_utils.generate_network_dict( + instance['id'], network_info), None, live_migration) + mobj.cleanup_source() + self._destroy(instance['id']) + self._clean_orphaned_files(instance['id']) + else: + LOG.warn( + _('Check instance: %(instance_id)s, it may be broken. ' + 'power_state: %(ps)s') % + {'instance_id': instance['id'], + 'ps': status}) + except exception.InstanceNotFound: + LOG.warn( + _('Instance %s not found, migration cleaned itself up?') % + instance['id']) + except exception.InstanceUnacceptable: + LOG.error(_('Failed to stop and destroy the instance')) + LOG.debug(_('Finished confirm migration for %s') % instance['id']) + + def finish_revert_migration(self, instance, network_info, + block_device_info=None): + """Finish reverting a resize, powering back on the instance.""" + # Get the instance metadata to see what we need to do + LOG.debug(_('Beginning finish_revert_migration')) + meta = ovz_utils.read_instance_metadata(instance['id']) + migration_type = meta.get('migration_type') + + if migration_type == 'resize_in_place': + # This is a resize on the same host so its simple, resize + # in place and then exit the method + LOG.debug(_('Reverting in-place migration for %s') % + instance['id']) + self._set_instance_size(instance, network_info) + if ovz_utils.remove_instance_metadata_key(instance['id'], + 'migration_type'): + LOG.debug(_('Removed migration_type metadata')) + LOG.debug(_('Done reverting in-place migration for %s') % + instance['id']) + else: + LOG.debug(_('Failed to remove migration_type metadata')) + return + + if block_device_info: + LOG.debug(_('Instance %s has volumes') % instance['id']) + # the instance has external volumes and was not a live migration + # so we need to reattach external volumes + live_migration = False + LOG.debug(_('Starting instance %s, after revert') % instance['id']) + ext_str = ext_storage.OVZExtStorage(instance['id']) + + for mountpoint, connection_info in ext_str.volumes(): + self.attach_volume(connection_info, instance, mountpoint) + + self._start(instance) + else: + LOG.debug(_('Instance %s has no volumes') % instance['id']) + live_migration = True + LOG.debug(_('Resuming live migration for %s') % instance['id']) + self.resume(instance, network_info) + + mobj = ovz_migration.OVZMigration( + instance, ovz_utils.generate_network_dict( + instance['id'], network_info), None, live_migration) + mobj.cleanup_files() + + def get_host_ip_addr(self): + """ + Retrieves the IP address of the host + """ + return CONF.my_ip + # TODO(imsplitbit): finish the outstanding software contract with nova # All methods in the driver below this need to be worked out. def snapshot(self, context, instance, image_id, update_task_state): @@ -1886,13 +2257,6 @@ class OpenVzDriver(driver.ComputeDriver): running VM""" return [] - def get_host_ip_addr(self): - """ - Retrieves the IP address of the dom0. - """ - # TODO(Vek): Need to pass context in for access to auth_token - return - def snapshot_instance(self, context, instance_id, image_id): return diff --git a/nova/virt/openvz/file.py b/nova/virt/openvz/file.py index dbbdb85..bf59d1e 100644 --- a/nova/virt/openvz/file.py +++ b/nova/virt/openvz/file.py @@ -197,7 +197,7 @@ class OVZFile(object): raise TypeError(_("I don't know what to do with this type: %s") % type(new_contents)) - def run_contents(self): + def run_contents(self, raise_on_error=True): # Because only approved commands in rootwrap can be executed we # don't need to worry about unwanted command injection for line in self.contents: @@ -209,7 +209,9 @@ class OVZFile(object): _('Running line from %(filename)s: %(line)s') % {'filename': self.filename, 'line': line}) line = line.split() - ovz_utils.execute(*line, run_as_root=True) + ovz_utils.execute( + *line, run_as_root=True, + raise_on_error=raise_on_error) except exception.InstanceUnacceptable as err: LOG.error(_('Cannot execute: %s') % line) LOG.error(err) diff --git a/nova/virt/openvz/file_ext/__init__.py b/nova/virt/openvz/file_ext/__init__.py index e69de29..3e1c627 100644 --- a/nova/virt/openvz/file_ext/__init__.py +++ b/nova/virt/openvz/file_ext/__init__.py @@ -0,0 +1,16 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2013 Rackspace +# 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. diff --git a/nova/virt/openvz/file_ext/ext_storage.py b/nova/virt/openvz/file_ext/ext_storage.py index 5a22b9a..8702ea0 100644 --- a/nova/virt/openvz/file_ext/ext_storage.py +++ b/nova/virt/openvz/file_ext/ext_storage.py @@ -63,11 +63,11 @@ class OVZExtStorage(object): :return: list """ try: - self.volumes = json.loads(self.local_store.contents[0]) + self._volumes = json.loads(self.local_store.contents[0]) except (ValueError, IndexError): - self.volumes = dict() + self._volumes = dict() - def add_volume(self, device, volume_info, overwrite=True): + def add_volume(self, device, volume_info): """ Add a volume to local storage so volumes can be reconnected to in emergencies without nova services if need be. @@ -76,14 +76,7 @@ class OVZExtStorage(object): :param volume_info: Nova volume information from block_device_map :return: None """ - if device in self.volumes and not overwrite: - msg = (_('You told me not to overwrite volume info for device: ' - '%(device)s on instance: %(instnace_id)s') % - {'device': device, 'instance_id': self.instance_id}) - LOG.error(msg) - raise KeyError(msg) - - self.volumes[device] = volume_info + self._volumes[device] = volume_info def remove_volume(self, device): """ @@ -93,7 +86,7 @@ class OVZExtStorage(object): :return: None """ try: - self.volumes.pop(device) + self._volumes.pop(device) LOG.debug( _('Removed volume %(device)s from instance %(instance_id)s') % {'device': device, 'instance_id': self.instance_id}) @@ -105,10 +98,20 @@ class OVZExtStorage(object): def save(self): """ - Flushes contents of self.volumes to disk for persistance + Flushes contents of self._volumes to disk for persistance :return: None """ - self.local_store.set_contents(json.dumps(self.volumes)) + self.local_store.set_contents(json.dumps(self._volumes)) with self.local_store: self.local_store.write() + + def volumes(self): + """ + Simple generator to give back the volumes in an iterable and + adventurous way. + + :return: device name, connection info + """ + for key in self._volumes.keys(): + yield key, self._volumes[key] diff --git a/nova/virt/openvz/migration.py b/nova/virt/openvz/migration.py new file mode 100644 index 0000000..cac88b7 --- /dev/null +++ b/nova/virt/openvz/migration.py @@ -0,0 +1,369 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2013 Rackspace +# 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. + +""" +A driver specific to OpenVz as the support for Ovz in libvirt +is sketchy at best. +""" +from nova import exception +from nova.openstack.common import log as logging +from nova.virt.openvz import utils as ovz_utils +import os +from oslo.config import cfg + +CONF = cfg.CONF +LOG = logging.getLogger('nova.virt.openvz.volume') + + +class OVZMigration(object): + def __init__(self, instance, interfaces, block_device_info=None, + dest=None, live=False): + self.instance = instance + self.interfaces = interfaces + self.block_device_info = block_device_info + self.destination_host = dest + self.live_migration = live + + # Hook in archives if migrations aren't done with the root user + # because we need to preserve ownerships on the files inside + # the container's root. + if CONF.ovz_migration_user == 'root': + self.unprivileged_user = False + self.instance_tarfile = None + else: + self.unprivileged_user = True + self.instance_tarfile = os.path.abspath('%s/%s.tar' % + (CONF.ovz_tmp_dir, + self.instance['id'])) + + self.instance_parent = CONF.ovz_ve_private_dir + self.instance_source = os.path.abspath( + '%s/%s' % (self.instance_parent, self.instance['id'])) + self.dumpdir_name = '%s-dumpdir' % instance['id'] + self.dumpdir_parent = CONF.ovz_tmp_dir + self.dumpdir = os.path.abspath('%s/%s' % (self.dumpdir_parent, + self.dumpdir_name)) + self.i_dumpdir = os.path.abspath('%s/instance' % self.dumpdir) + self.dumpfile = os.path.abspath( + '%s/dump.%s' % (self.i_dumpdir, self.instance['id'])) + self.q_dumpdir = os.path.abspath('%s/quotas' % self.dumpdir) + self.qdumpfile = os.path.abspath( + '%s/qdump.%s' % (self.q_dumpdir, self.instance['id'])) + self.as_dumpdir = os.path.abspath('%s/ascripts' % self.dumpdir) + self.actionscripts = ['start', 'stop', 'mount', 'umount', 'premount', + 'postumount', 'boot', 'shutdown', 'conf', + 'ext_storage'] + self.dumpdir_tarfile = '%s.tar' % self.dumpdir + + def dump_and_transfer_instance(self): + """ + Put all the pieces together to dump the instance and make the dump + ready for transfer to the destination host. + """ + self.make_dump_dir() + + # Begin the dumping process + if self.live_migration: + # this is a live migration so dump current memory and network + # state. + LOG.debug(_('Making container backup for %s') % + self.instance['id']) + self.dump() + + if self.unprivileged_user: + # we are transferring the instance by using an unprivileged user + # so we need to tar the instance to preserve ownerships and + # permissions + LOG.debug(_('self.unprivileged_user is True')) + self.tar_instance() + + # Take all instance scripts from /etc/vz/conf and put them in a + # tarball for transfer. + LOG.debug(_('Making action script backups for %s') % + self.instance['id']) + self.backup_action_scripts() + LOG.debug(_('Archiving misc files: %s') % self.instance['id']) + self.tar_dumpdir() + LOG.debug(_('Migration image created')) + + def undump_instance(self): + """ + Take the pieces of a dump archive and put them back in place. + """ + # If a non-root user was used to transfer the files then we + # need to move everything to where it is expected to be. + LOG.debug(_('Restoring action scripts from archive: %s') % + self.dumpdir_tarfile) + self.untar_dumpdir() + LOG.debug(_('Restoring action scripts for %s') % self.instance['id']) + self.restore_action_scripts() + + if self.unprivileged_user: + LOG.debug(_('Restoring container from tar: %s') % + self.instance['id']) + self.untar_instance() + + if self.live_migration: + LOG.debug(_('Restoring container state from dump for %s') % + self.instance['id']) + self.undump() + LOG.debug(_('Resuming container: %s') % self.instance['id']) + self.resume() + + LOG.debug(_('Done restoring instance %s') % self.instance['id']) + + def make_dump_dir(self): + """ + Make our dump locations + """ + LOG.debug(_('Making dump location for %s') % self.instance['id']) + ovz_utils.make_dir(self.dumpdir) + ovz_utils.make_dir(self.i_dumpdir) + ovz_utils.make_dir(self.q_dumpdir) + ovz_utils.make_dir(self.as_dumpdir) + LOG.debug(_('Done making location for %s') % self.instance['id']) + + def cleanup_source(self): + """ + Helper method to wrap up all methods required to clean up a + migration. + """ + if self.live_migration: + self.kill() + + self.cleanup_files() + + def cleanup_destination(self): + """ + Do anything you need to do on the destination host to clean it up + """ + self.cleanup_files() + + def dump(self): + """ + Create a vz dump file from a container. This is the file that we + transfer to do a full migration + """ + LOG.debug(_('Dumping instance %s') % self.instance['id']) + ovz_utils.execute('vzctl', 'chkpnt', self.instance['id'], + '--dump', '--dumpfile', self.dumpfile, + run_as_root=True) + LOG.debug(_('Dumped instance %(instance_id)s to %(dumpfile)s') % + {'instance_id': self.instance['id'], + 'dumpfile': self.dumpfile}) + + def undump(self): + """ + Restore a VZ from a dump file + """ + LOG.debug(_('Undumping instance %s') % self.instance['id']) + ovz_utils.execute('vzctl', 'restore', self.instance['id'], '--undump', + '--dumpfile', self.dumpfile, '--skip_arpdetect', + run_as_root=True) + LOG.debug(_('Undumped instance %(instance_id)s from %(dumpfile)s') % + {'instance_id': self.instance['id'], + 'dumpfile': self.dumpfile}) + + def resume(self): + """ + Resume a container from an undumped migration + """ + LOG.debug(_('Resuming instance %s') % self.instance['id']) + ovz_utils.execute('vzctl', 'restore', self.instance['id'], + '--resume', run_as_root=True) + LOG.debug(_('Resumed instance %s') % self.instance['id']) + + def kill(self): + """ + This is used to stop a container once it's suspended without having to + resume it to properly destroy it + """ + LOG.debug(_('Killing instance %s') % self.instance['id']) + ovz_utils.execute('vzctl', 'chkpnt', self.instance['id'], + '--kill', run_as_root=True) + LOG.debug(_('Killed instance %s') % self.instance['id']) + + def quotadump(self): + """ + Dump the quotas for containers + """ + LOG.debug(_('Dumping quotas for %s') % self.instance['id']) + ovz_utils.execute('vzdqdump', self.instance['id'], '-U', '-G', + '-T', '>', self.qdumpfile, run_as_root=True) + LOG.debug(_('Dumped quotas for %s') % self.instance['id']) + + def quotaload(self): + """ + Load quotas from quota file + """ + LOG.debug(_('Loading quotas for %s') % self.instance['id']) + ovz_utils.execute('vzdqload', self.instance['id'], '-U', '-G', '-T', + '<', self.qdumpfile, run_as_root=True) + LOG.debug(_('Loaded quotas for %s') % self.instance['id']) + + def quotaenable(self): + """ + enable quotas for a given container + """ + LOG.debug(_('Enabling quotas for %s') % self.instance['id']) + ovz_utils.execute('vzquota', 'reload2', + self.instance['id'], run_as_root=True) + LOG.debug(_('Enabled quotas for %s') % self.instance['id']) + + def quota_init(self): + """ + Initialize quotas for instance + """ + LOG.debug(_('Initializing quotas for %s') % self.instance['id']) + ovz_utils.execute('vzctl', 'quotainit', self.instance['id']) + LOG.debug(_('Initialized quotas for %s') % self.instance['id']) + + def quota_on(self): + """ + Turn on quotas for instance + """ + LOG.debug(_('Turning on quotas for %s') % self.instance['id']) + ovz_utils.execute('vzctl', 'quotaon', self.instance['id'], + run_as_root=True) + LOG.debug(_('Turned on quotas for %s') % self.instance['id']) + + def backup_action_scripts(self): + """ + Take the action scripts with us in the backup/migration + """ + LOG.debug(_('Copying actionscripts into place')) + for a_script in self.actionscripts: + a_script = os.path.abspath( + '%s/%s.%s' % (CONF.ovz_config_dir, self.instance['id'], + a_script)) + if os.path.exists(a_script): + LOG.debug(_('Copying actionscript: %s') % a_script) + ovz_utils.copy(a_script, self.as_dumpdir) + LOG.debug(_('Copied actionscript: %s') % a_script) + LOG.debug(_('Copied actionscripts into place')) + + def restore_action_scripts(self): + """ + Put the action scripts back into place + """ + LOG.debug(_('Restoring actionscripts into place')) + for a_script in self.actionscripts: + a_script = os.path.abspath('%s/%s.%s' % (self.as_dumpdir, + self.instance['id'], + a_script)) + if os.path.exists(a_script): + LOG.debug(_('Restoring actionscript: %s') % a_script) + ovz_utils.copy(a_script, CONF.ovz_config_dir) + LOG.debug(_('Restored actionscript: %s') % a_script) + LOG.debug(_('Restored actionscripts into place')) + + def send(self): + """ + Use the configured transport to transfer the image from the src to + the dest host. This will run on the source host. + """ + # Set the destination and source for the instance transfer + if self.unprivileged_user: + # Since we tarred up the instance we don't need to skip rsync'ing + # any paths. + src_path = self.instance_tarfile + dest_path = CONF.ovz_tmp_dir + else: + src_path = self.instance_source + dest_path = self.instance_parent + + transport_instance = self._setup_transport(src_path, dest_path) + transport_instance.send() + + # Set the destination and source for the dumpdir transfer + src_path = self.dumpdir_tarfile + dest_path = self.dumpdir_parent + + transport_instance_scripts = self._setup_transport(src_path, dest_path) + transport_instance_scripts.send() + + def receive(self): + """ + Use the configured transport to transfer the image form the src to + dest host. This will run on the destination host + """ + # Right now we don't have a transport that needs this. + raise NotImplementedError() + + def cleanup_files(self): + """ + Remove the files in the OpenVz temp dir + """ + LOG.debug(_('Cleaning migration files for %s') % self.instance['id']) + ovz_utils.execute('rm', '-rf', self.dumpdir, run_as_root=True) + ovz_utils.execute('rm', '-f', self.dumpdir_tarfile, run_as_root=True) + if self.instance_tarfile: + ovz_utils.execute('rm', '-f', self.instance_tarfile, + run_as_root=True) + LOG.debug( + _('Cleaned up migration files for %s') % self.instance['id']) + + def tar_instance(self): + """ + Not an optimal way to do this but if you aren't using the root user + to rsync the files from host to host you need to preserve the + permissions and ownerships thus tar is your only hope. + """ + # Create our batch volume operations object + LOG.debug(_('Tarring up instance: %s') % self.instance['id']) + ovz_utils.tar(self.instance['id'], self.instance_tarfile, + self.instance_parent) + LOG.debug(_('Tarred up instance: %s') % self.instance['id']) + + def tar_dumpdir(self): + """ + Archive the instance action scripts + """ + LOG.debug(_('Tarring up instance dumpdir: %s') % self.dumpdir) + ovz_utils.tar(self.dumpdir_name, self.dumpdir_tarfile, + self.dumpdir_parent) + LOG.debug(_('Tarred up instance dumpdir: %s') % self.dumpdir) + + def untar_instance(self): + """ + Expand the tarball from the instance and expand it into place + """ + LOG.debug(_('Untarring instance: %s') % self.instance_source) + ovz_utils.untar(self.instance_tarfile, self.instance_parent) + LOG.debug(_('Untarred instance: %s') % self.instance_source) + + def untar_dumpdir(self): + """ + Expand the dumpdir into place on the destination machine + """ + LOG.debug(_('Untarring instance dumpdir: %s') % self.dumpdir) + ovz_utils.untar(self.dumpdir_tarfile, self.dumpdir_parent) + LOG.debug(_('Untarred instance dumpdir: %s') % self.dumpdir) + + def _setup_transport(self, src_path, dest_path, skip_list=None): + if CONF.ovz_migration_transport == 'rsync': + from nova.virt.openvz.migration_drivers import rsync + return rsync.OVZMigrationRsyncTransport( + src_path, dest_path, self.instance['id'], + self.destination_host, skip_list) + else: + LOG.error( + _('I do not understand your migration transport: %s') % + CONF.ovz_migration_transport) + raise exception.MigrationError( + _('No valid migration transport: %s') % + CONF.ovz_migration_transport) diff --git a/nova/virt/openvz/migration_drivers/__init__.py b/nova/virt/openvz/migration_drivers/__init__.py new file mode 100644 index 0000000..3e1c627 --- /dev/null +++ b/nova/virt/openvz/migration_drivers/__init__.py @@ -0,0 +1,16 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2013 Rackspace +# 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. diff --git a/nova/virt/openvz/migration_drivers/rsync.py b/nova/virt/openvz/migration_drivers/rsync.py new file mode 100644 index 0000000..013c88d --- /dev/null +++ b/nova/virt/openvz/migration_drivers/rsync.py @@ -0,0 +1,62 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2013 Rackspace +# 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. + +""" +Driver for OVZ Migrations. Uses rsync as a backend. +""" +from nova.openstack.common import log as logging +from nova.virt.openvz.migration_drivers import transport +from nova.virt.openvz import utils as ovz_utils +import os +from oslo.config import cfg + +CONF = cfg.CONF +LOG = logging.getLogger('nova.virt.openvz.migration_drivers.rsync') + + +class OVZMigrationRsyncTransport(transport.OVZMigrationTransport): + def __init__(self, src_path, dest_path, instance_id, + dest_host, skip_list=None): + super(OVZMigrationRsyncTransport, self).__init__(src_path, + dest_path, + instance_id, + dest_host, + skip_list) + + def send(self): + """ + Send image/files to a destination. This should be run on the source + host. + """ + LOG.debug(_('Running _rsync()')) + self._rsync(self.src_path, self.dest_path) + LOG.debug(_('Ran _rsync()')) + super(OVZMigrationRsyncTransport, self).send() + + def _rsync(self, src_path, dest_path): + """ + Copy a path from one place to another using rsync + """ + dest = '%s@%s:%s' % (self.user, self.dest_host, + os.path.abspath(dest_path)) + counter = 1 + while counter <= CONF.ovz_rsync_iterations: + LOG.debug(_('RSyncing %(src_path)s, attempt: %(counter)s') % + locals()) + ovz_utils.execute('rsync', '-qavz', src_path, + dest, run_as_root=True) + counter += 1 diff --git a/nova/virt/openvz/migration_drivers/transport.py b/nova/virt/openvz/migration_drivers/transport.py new file mode 100644 index 0000000..c0f84dc --- /dev/null +++ b/nova/virt/openvz/migration_drivers/transport.py @@ -0,0 +1,72 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2013 Rackspace +# 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. + +""" +Generic transport class for OVZ Migrations. Common methods will be placed +in this file for reuse. +""" +from nova.openstack.common import log as logging +import os +from oslo.config import cfg + +CONF = cfg.CONF +LOG = logging.getLogger('nova.virt.openvz.migration_drivers.transport') + + +class OVZMigrationTransport(object): + def __init__(self, src_path, dest_path, instance_id, + dest_host, skip_list=None): + self.src_path = src_path + self.dest_path = dest_path + self.instance_id = instance_id + self.dest_host = dest_host + self.skip_list = skip_list + self.user = CONF.ovz_migration_user + self.container_path = os.path.abspath('%s/%s' % + (CONF.ovz_ve_private_dir, + self.instance_id)) + + def send(self): + """ + Code should go here to support what needs to be done upon sending a + container to another host. This should be called from all transport + drivers after their work is done on the source host. + """ + LOG.debug(_('Beginning send() for %s') % self.instance_id) + # Generic use case transport code goes here, this code is run + # after any code in a custom transport + LOG.debug(_('Finished send() for %s') % self.instance_id) + + def receive(self): + """ + Code should go here to support what needs to be done upon receiving a + container from another host. This should be called from all transport + drivers after their work is done on the destination host. + """ + LOG.debug(_('Beginning receive() for %s') % self.instance_id) + # Generic use case transport code goes here, this code is run + # after any code in a custom transport + LOG.debug(_('Finished receive() for %s') % self.instance_id) + + def verify(self): + """ + Check things on the destination host to make sure that the migration + went well. + """ + LOG.debug(_('Beginning verify() for %s') % self.instance_id) + # Generic use case transport code goes here + LOG.debug(_('Finished verify() for %s') % self.instance_id) diff --git a/nova/virt/openvz/network_drivers/__init__.py b/nova/virt/openvz/network_drivers/__init__.py index e69de29..3e1c627 100644 --- a/nova/virt/openvz/network_drivers/__init__.py +++ b/nova/virt/openvz/network_drivers/__init__.py @@ -0,0 +1,16 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2013 Rackspace +# 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. diff --git a/nova/virt/openvz/network_drivers/tc.py b/nova/virt/openvz/network_drivers/tc.py index 7521c14..3e8e9a0 100644 --- a/nova/virt/openvz/network_drivers/tc.py +++ b/nova/virt/openvz/network_drivers/tc.py @@ -115,7 +115,7 @@ class OVZTcRules(object): LOG.debug(_('TC id %s inflight already, pulling another') % tc_id) tc_id = self._pull_id() LOG.debug(_('TC id %s pulled, testing for dupe') % tc_id) - LOG.debug(_('TC id %s pulled, verified unique')) + LOG.debug(_('TC id %s pulled, verified unique') % tc_id) self._reserve_id(tc_id) return tc_id diff --git a/nova/virt/openvz/utils.py b/nova/virt/openvz/utils.py index 113748f..15fb22d 100644 --- a/nova/virt/openvz/utils.py +++ b/nova/virt/openvz/utils.py @@ -25,6 +25,7 @@ from nova.conductor import api from nova import context from nova import exception from nova.openstack.common import log as logging +from nova.openstack.common import processutils from nova import utils import os from oslo.config import cfg @@ -57,7 +58,7 @@ def execute(*cmd, **kwargs): LOG.debug(_('Stderr from %(command)s: %(out)s') % {'command': cmd[0], 'out': err}) return out - except exception.ProcessExecutionError as err: + except processutils.ProcessExecutionError as err: msg = (_('Stderr from %(command)s: %(out)s') % {'command': cmd[0], 'out': err}) if raise_on_error: diff --git a/nova/virt/openvz/volume.py b/nova/virt/openvz/volume.py index 6d02b3b..d0b57b6 100644 --- a/nova/virt/openvz/volume.py +++ b/nova/virt/openvz/volume.py @@ -23,6 +23,7 @@ is sketchy at best. import glob from nova import exception from nova.openstack.common import log as logging +from nova.openstack.common import processutils from nova.virt.openvz import file as ovzfile from nova.virt.openvz import utils as ovz_utils import os @@ -68,11 +69,11 @@ class OVZVolume(object): """ self._attach_raw_devices() - def detach(self): + def detach(self, container_is_running=True): """ Public method for detaching volumes from an instance. """ - self._detach_raw_devices() + self._detach_raw_devices(container_is_running) def device_name(self): """ @@ -92,7 +93,7 @@ class OVZVolume(object): ovz_utils.execute('blockdev', '--getsize64', device_path, attempts=CONF.ovz_system_num_tries, run_as_root=True) - except exception.ProcessExecutionError: + except processutils.ProcessExecutionError: raise exception.InvalidDevicePath(path=device_path) def _find_device(self): @@ -312,7 +313,7 @@ class OVZVolume(object): self._set_block_devices(devices) - def _del_block_devices(self, new_devices): + def _del_block_devices(self, new_devices, container_is_running=True): """ New devices should be a list that looks like this: @@ -327,7 +328,7 @@ class OVZVolume(object): if dev in devices: devices.remove(dev) - self._set_block_devices(devices) + self._set_block_devices(devices, container_is_running) def _detach_remaining_block_devices(self): """ @@ -349,7 +350,7 @@ class OVZVolume(object): ovz_utils.execute(*cmd, run_as_root=True) - def _set_block_devices(self, devices): + def _set_block_devices(self, devices, container_is_running=True): """ Run the command necessary to save the block device permissions to the container config file so that they persist on reboot. @@ -368,7 +369,9 @@ class OVZVolume(object): # if the device list is empty this means that it's the last device # attached to the container and we need to run some special case # code to remove that device. - self._detach_remaining_block_devices() + if container_is_running: + self._detach_remaining_block_devices() + self._remove_all_device_entries() def _remove_all_device_entries(self): @@ -389,7 +392,7 @@ class OVZVolume(object): ct_conf.contents.remove(line) ct_conf.write() - def _detach_raw_devices(self): + def _detach_raw_devices(self, container_is_running=True): """ Remove the associated devices from the container. @@ -409,7 +412,11 @@ class OVZVolume(object): # TODO(imsplitbit): research to see if running this remove command # adhoc is necessary or if just removing the device from the config # file is adequate. - self._detach_raw_device(maj_min['major'], maj_min['minor']) + if container_is_running: + # If the container isn't running this command makes things + # unhappy. Very very unhappy. + self._detach_raw_device(maj_min['major'], maj_min['minor']) + m = re.match('^(?P/[a-z]+/[a-z]+)(?P\\d*)$', dev) device_name = self.mountpoint @@ -419,7 +426,7 @@ class OVZVolume(object): self._delete_device(device_name) if bdevs_conf: - self._del_block_devices(bdevs_conf) + self._del_block_devices(bdevs_conf, container_is_running) def _detach_raw_device(self, major, minor): """ diff --git a/nova/virt/openvz/volume_drivers/__init__.py b/nova/virt/openvz/volume_drivers/__init__.py index e69de29..3e1c627 100644 --- a/nova/virt/openvz/volume_drivers/__init__.py +++ b/nova/virt/openvz/volume_drivers/__init__.py @@ -0,0 +1,16 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2013 Rackspace +# 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. diff --git a/nova/virt/openvz/volume_drivers/iscsi.py b/nova/virt/openvz/volume_drivers/iscsi.py index 70c7428..2471cf0 100644 --- a/nova/virt/openvz/volume_drivers/iscsi.py +++ b/nova/virt/openvz/volume_drivers/iscsi.py @@ -22,6 +22,7 @@ is sketchy at best. from nova import exception from nova.openstack.common import lockutils from nova.openstack.common import log as logging +from nova.openstack.common import processutils from nova.virt.openvz import utils as ovz_utils from nova.virt.openvz import volume as ovzvolume from oslo.config import cfg @@ -122,16 +123,16 @@ class OVZISCSIStorageDriver(ovzvolume.OVZVolume): self._run_iscsiadm(("--login",)) LOG.debug(_('iSCSI session for %s connected') % self.iscsi_properties['target_iqn']) - except exception.ProcessExecutionError as err: + except processutils.ProcessExecutionError as err: if "15 - already exists" in err.message: raise exception.VolumeUnattached() LOG.error(err) raise exception.VolumeNotFound(_("iSCSI device %s not found") % self.iscsi_properties['target_iqn']) - def detach(self, raise_on_error=True): + def detach(self, container_is_running=True): """Detach the volume from instance_name.""" - super(OVZISCSIStorageDriver, self).detach() + super(OVZISCSIStorageDriver, self).detach(container_is_running) self._detach_iscsi() @lockutils.synchronized('iscsiadm_lock', 'openvz-') @@ -157,7 +158,7 @@ class OVZISCSIStorageDriver(ovzvolume.OVZVolume): (self.iscsi_properties['target_portal'], self.iscsi_properties['target_iqn'], self.iscsi_properties['target_lun'])) - except exception.ProcessExecutionError as err: + except processutils.ProcessExecutionError as err: LOG.error(err) raise exception.ISCSITargetNotFoundForVolume( _("Error rescanning iscsi device: %s") %