diff --git a/nova_zvm/tests/unit/virt/zvm/test_configdrive.py b/nova_zvm/tests/unit/virt/zvm/test_configdrive.py index bc4826e..4511f48 100644 --- a/nova_zvm/tests/unit/virt/zvm/test_configdrive.py +++ b/nova_zvm/tests/unit/virt/zvm/test_configdrive.py @@ -17,6 +17,7 @@ import os +from nova import exception from nova import test from oslo_utils import fileutils @@ -38,14 +39,13 @@ class ZVMConfigDriveTestCase(test.NoDBTestCase): super(ZVMConfigDriveTestCase, self).setUp() self.flags(config_drive_format='iso9660', tempdir='/tmp/os') - + self._file_path = CONF.tempdir + self._file_name = self._file_path + '/cfgdrive.tgz' self.inst_md = FakeInstMeta() def test_create_configdrive_tgz(self): self._file_path = CONF.tempdir fileutils.ensure_tree(self._file_path) - self._file_name = self._file_path + '/cfgdrive.tgz' - try: with zvmconfigdrive.ZVMConfigDriveBuilder( instance_md=self.inst_md) as c: @@ -55,3 +55,13 @@ class ZVMConfigDriveTestCase(test.NoDBTestCase): finally: fileutils.remove_path_on_error(self._file_path) + + def test_make_drive_unknown_format(self): + self.flags(config_drive_format='vfat') + try: + with zvmconfigdrive.ZVMConfigDriveBuilder( + instance_md=self.inst_md) as c: + self.assertRaises(exception.ConfigDriveUnknownFormat, + c.make_drive, self._file_name) + finally: + fileutils.remove_path_on_error(self._file_path) diff --git a/nova_zvm/tests/unit/virt/zvm/test_driver.py b/nova_zvm/tests/unit/virt/zvm/test_driver.py index 8eac431..ff19416 100644 --- a/nova_zvm/tests/unit/virt/zvm/test_driver.py +++ b/nova_zvm/tests/unit/virt/zvm/test_driver.py @@ -12,67 +12,37 @@ # License for the specific language governing permissions and limitations # under the License. - -"""Test suite for ZVMDriver.""" - +import copy import eventlet import mock from nova.compute import power_state from nova import context -from nova import exception as nova_exception -from nova.image import api as image_api +from nova import exception from nova.network import model as network_model from nova import objects -from nova.objects import fields as obj_fields from nova import test from nova.tests.unit import fake_instance from nova.tests import uuidsentinel -from nova.virt import fake -from nova.virt import hardware -from zvmsdk import api as sdkapi -from zvmsdk import dist -from zvmsdk import exception as sdkexception -from nova_zvm.virt.zvm import conf -from nova_zvm.virt.zvm import const -from nova_zvm.virt.zvm import driver +from nova_zvm.virt.zvm import driver as zvmdriver from nova_zvm.virt.zvm import utils as zvmutils -CONF = conf.CONF -CONF.import_opt('host', 'nova.conf') -CONF.import_opt('my_ip', 'nova.conf') +class TestZVMDriver(test.NoDBTestCase): - -class ZVMDriverTestCases(test.NoDBTestCase): - """Unit tests for z/VM driver methods.""" - - @mock.patch.object(driver.ZVMDriver, 'update_host_status') - def setUp(self, update_host_status): - super(ZVMDriverTestCases, self).setUp() - - self.flags(host='fakehost', - my_ip='10.1.1.10', - instance_name_template = 'test%04x') - update_host_status.return_value = [{ - 'host': 'fakehost', - 'allowed_vm_type': 'zLinux', - 'vcpus': 10, - 'vcpus_used': 10, - 'cpu_info': {'Architecture': 's390x', 'CEC model': '2097'}, - 'disk_total': 406105, - 'disk_used': 367263, - 'disk_available': 38842, - 'host_memory_total': 16384, - 'host_memory_free': 8096, - 'hypervisor_type': 'zvm', - 'hypervisor_version': '630', - 'hypervisor_hostname': 'fakenode', - 'supported_instances': [('s390x', 'zvm', 'hvm')], - 'ipl_time': 'IPL at 03/13/14 21:43:12 EDT', - }] - self.driver = driver.ZVMDriver(fake.FakeVirtAPI()) + def setUp(self): + super(TestZVMDriver, self).setUp() + self.flags(zvm_cloud_connector_url='https://1.1.1.1:1111', + zvm_image_tmp_path='/test/image', + zvm_reachable_timeout=300) + self.flags(my_ip='192.168.1.1', + instance_name_template='test%04x') + with mock.patch('nova_zvm.virt.zvm.utils.' + 'zVMConnectorRequestHandler.call') as mcall: + mcall.return_value = {'hypervisor_hostname': 'TESTHOST', + 'ipl_time': 'TESTTIME'} + self.driver = zvmdriver.ZVMDriver('virtapi') self._context = context.RequestContext('fake_user', 'fake_project') self._uuid = uuidsentinel.foo self._image_id = uuidsentinel.foo @@ -82,7 +52,7 @@ class ZVMDriverTestCases(test.NoDBTestCase): 'vcpus': 1, 'memory_mb': 1024, 'image_ref': self._image_id, - 'root_gb': 3, + 'root_gb': 0, } self._instance = fake_instance.fake_instance_obj( self._context, **self._instance_values) @@ -91,7 +61,7 @@ class ZVMDriverTestCases(test.NoDBTestCase): swap=0, extra_specs={}) self._instance.flavor = self._flavor - eph_disks = [{'guest_format': u'ext3', + self._eph_disks = [{'guest_format': u'ext3', 'device_name': u'/dev/sdb', 'disk_bus': None, 'device_type': None, @@ -103,9 +73,8 @@ class ZVMDriverTestCases(test.NoDBTestCase): 'size': 2}] self._block_device_info = {'swap': None, 'root_device_name': u'/dev/sda', - 'ephemerals': eph_disks, + 'ephemerals': self._eph_disks, 'block_device_mapping': []} - fake_image_meta = {'status': 'active', 'properties': {'os_distro': 'rhel7.2'}, 'name': 'rhel72eckdimage', @@ -148,226 +117,321 @@ class ZVMDriverTestCases(test.NoDBTestCase): network_model.VIF(**self._network_values) ]) - def test_init_driver(self): - self.assertIsInstance(self.driver._sdk_api, sdkapi.SDKAPI) + def test_driver_init(self): + self.assertEqual(self.driver._hypervisor_hostname, 'TESTHOST') + self.assertIsInstance(self.driver._reqh, + zvmutils.zVMConnectorRequestHandler) self.assertIsInstance(self.driver._vmutils, zvmutils.VMUtils) - self.assertIsInstance(self.driver._image_api, image_api.API) - self.assertIsInstance(self.driver._pathutils, zvmutils.PathUtils) - self.assertIsInstance(self.driver._imageutils, zvmutils.ImageUtils) - self.assertIsInstance(self.driver._networkutils, - zvmutils.NetworkUtils) self.assertIsInstance(self.driver._imageop_semaphore, eventlet.semaphore.Semaphore) - self.assertEqual(self.driver._host_stats[0]['host'], "fakehost") - self.assertEqual(self.driver._host_stats[0]['disk_available'], 38842) - @mock.patch.object(sdkapi.SDKAPI, 'host_get_info') - def test_update_host_status(self, host_get_info): - host_get_info.return_value = { - 'vcpus': 10, - 'vcpus_used': 10, - 'cpu_info': {'Architecture': 's390x', 'CEC model': '2097'}, - 'disk_total': 406105, - 'disk_used': 367263, - 'disk_available': 38842, - 'memory_mb': 876543, - 'memory_mb_used': 111111, - 'hypervisor_type': 'zvm', - 'hypervisor_version': '630', - 'hypervisor_hostname': 'fakenode', - 'ipl_time': 'IPL at 03/13/14 21:43:12 EDT', - } - info = self.driver.update_host_status() - host_get_info.assert_called_with() - self.assertEqual(info[0]['host'], CONF.host) - self.assertEqual(info[0]['hypervisor_hostname'], 'fakenode') - self.assertEqual(info[0]['host_memory_free'], 765432) + @mock.patch('nova_zvm.virt.zvm.utils.zVMConnectorRequestHandler.call') + def test_list_instance(self, call): + call.return_value = ['vm1', 'vm2'] + inst_list = self.driver.list_instances() + self.assertEqual(['vm1', 'vm2'], inst_list) - @mock.patch.object(driver.ZVMDriver, 'update_host_status') - def test_get_available_resource(self, update_host_status): - update_host_status.return_value = [{ - 'host': CONF.host, - 'allowed_vm_type': const.ALLOWED_VM_TYPE, - 'vcpus': 10, - 'vcpus_used': 10, - 'cpu_info': {'Architecture': 's390x', 'CEC model': '2097'}, - 'disk_total': 406105, - 'disk_used': 367263, - 'disk_available': 38842, - 'host_memory_total': 876543, - 'host_memory_free': 111111, - 'hypervisor_type': 'zvm', - 'hypervisor_version': '630', - 'hypervisor_hostname': 'fakenode', - 'supported_instances': [(const.ARCHITECTURE, - const.HYPERVISOR_TYPE, - obj_fields.VMMode.HVM)], - 'ipl_time': 'IPL at 03/13/14 21:43:12 EDT', - }] - res = self.driver.get_available_resource('fakenode') - self.assertEqual(res['vcpus'], 10) - self.assertEqual(res['memory_mb_used'], 765432) - self.assertEqual(res['disk_available_least'], 38842) + @mock.patch('nova_zvm.virt.zvm.utils.zVMConnectorRequestHandler.call') + def test_get_available_resource(self, call): + host_info = {'disk_available': 1144, + 'ipl_time': u'IPL at 11/14/17 10:47:44 EST', + 'vcpus_used': 4, + 'hypervisor_type': u'zvm', + 'disk_total': 2000, + 'zvm_host': u'TESTHOST', + 'memory_mb': 78192.0, + 'cpu_info': {u'cec_model': u'2827', + u'architecture': u's390x'}, + 'vcpus': 84, + 'hypervisor_hostname': u'TESTHOST', + 'hypervisor_version': 640, + 'disk_used': 856, + 'memory_mb_used': 8192.0} + call.return_value = host_info + results = self.driver.get_available_resource() + self.assertEqual(84, results['vcpus']) + self.assertEqual(8192.0, results['memory_mb_used']) + self.assertEqual(1144, results['disk_available_least']) + self.assertEqual('TESTHOST', results['hypervisor_hostname']) - @mock.patch.object(sdkapi.SDKAPI, 'guest_list') - def test_list_instances(self, guest_list): - self.driver.list_instances() - guest_list.assert_called_once_with() - - @mock.patch.object(sdkapi.SDKAPI, 'guest_get_power_state') - @mock.patch.object(zvmutils, 'mapping_power_stat') - def test_get_instance_info_off(self, mapping_power_stat, get_power_state): - get_power_state.return_value = 'off' - mapping_power_stat.return_value = power_state.SHUTDOWN - fake_inst = fake_instance.fake_instance_obj(self._context, - name='fake', power_state=power_state.SHUTDOWN, - memory_mb='1024', - vcpus='4') - inst_info = self.driver._get_instance_info(fake_inst) - mapping_power_stat.assert_called_once_with('off') - self.assertEqual(inst_info.state, power_state.SHUTDOWN) - - @mock.patch.object(driver.ZVMDriver, '_get_instance_info') - def test_get_info(self, _get_instance_info): - _fake_inst_info = hardware.InstanceInfo(state=0x01) - _get_instance_info.return_value = _fake_inst_info - fake_inst = fake_instance.fake_instance_obj(self._context, - name='fake', power_state=power_state.RUNNING, - memory_mb='1024', - vcpus='4') - inst_info = self.driver.get_info(fake_inst) - self.assertEqual(0x01, inst_info.state) - - @mock.patch.object(driver.ZVMDriver, '_get_instance_info') - def test_get_info_instance_not_exist_error(self, _get_instance_info): - _get_instance_info.side_effect = sdkexception.ZVMVirtualMachineNotExist - fake_inst = fake_instance.fake_instance_obj(self._context, - name='fake', power_state=power_state.RUNNING, - memory_mb='1024', - vcpus='4') - self.assertRaises(nova_exception.InstanceNotFound, - self.driver.get_info, - fake_inst) + @mock.patch('nova_zvm.virt.zvm.utils.zVMConnectorRequestHandler.call') + def test_get_available_resource_err_case(self, call): + call.side_effect = exception.NovaException + results = self.driver.get_available_resource() + self.assertEqual(0, results['vcpus']) + self.assertEqual(0, results['memory_mb_used']) + self.assertEqual(0, results['disk_available_least']) + self.assertEqual('', results['hypervisor_hostname']) def test_get_available_nodes(self): nodes = self.driver.get_available_nodes() - self.assertEqual(nodes[0], 'fakenode') + self.assertEqual(['TESTHOST'], nodes) - @mock.patch.object(sdkapi.SDKAPI, 'guest_get_console_output') - def test_get_console_output(self, gco): - self.driver.get_console_output({}, self._instance) - gco.assert_called_with('test0001') + def test_private_mapping_power_stat(self): + status = self.driver._mapping_power_stat('on') + self.assertEqual(power_state.RUNNING, status) + status = self.driver._mapping_power_stat('off') + self.assertEqual(power_state.SHUTDOWN, status) + status = self.driver._mapping_power_stat('bad') + self.assertEqual(power_state.NOSTATE, status) - @mock.patch.object(sdkapi.SDKAPI, 'guest_start') - @mock.patch.object(driver.ZVMDriver, '_wait_network_ready') - @mock.patch.object(sdkapi.SDKAPI, 'guest_config_minidisks') - @mock.patch.object(sdkapi.SDKAPI, 'guest_deploy') - @mock.patch.object(driver.ZVMDriver, '_setup_network') - @mock.patch.object(sdkapi.SDKAPI, 'guest_create') - @mock.patch.object(zvmutils.ImageUtils, 'import_spawn_image') - @mock.patch.object(sdkapi.SDKAPI, 'image_query') - @mock.patch.object(zvmutils.VMUtils, 'generate_configdrive') - @mock.patch.object(dist.LinuxDistManager, 'get_linux_dist') - def _test_spawn(self, mock_linux_dist, - generate_configdrive, image_query, import_spawn_image, - guest_create, setup_network, guest_deploy, - guest_config_minidisks, wait_network_ready, - guest_start, image_query_result, eph_disks): - generate_configdrive.return_value = '/tmp/fakecfg.tgz' - image_query.side_effect = image_query_result + @mock.patch('nova_zvm.virt.zvm.utils.zVMConnectorRequestHandler.call') + def test_get_info_err_InstanceNotFound(self, call): + call.side_effect = exception.NovaException(results={'overallRC': 404}) + self.assertRaises(exception.InstanceNotFound, self.driver.get_info, + self._instance) - self._block_device_info['ephemerals'] = eph_disks - root_disk = {'size': '3g', 'is_boot_disk': True} - disk_list = [root_disk] - eph_list = [] - for eph in eph_disks: - eph_dict = {'size': '%ig' % eph['size'], - 'format': (eph['guest_format'] or - CONF.default_ephemeral_format or - const.DEFAULT_EPH_DISK_FMT)} - eph_list.append(eph_dict) - if eph_list: - disk_list.extend(eph_list) + @mock.patch('nova_zvm.virt.zvm.utils.zVMConnectorRequestHandler.call') + def test_get_info_err_general(self, call): + call.side_effect = exception.NovaException(results={'overallRC': 500}) + self.assertRaises(exception.NovaException, self.driver.get_info, + self._instance) - os_distro = self._image_meta.properties.os_distro + @mock.patch('nova.virt.hardware.InstanceInfo') + @mock.patch('nova_zvm.virt.zvm.utils.zVMConnectorRequestHandler.call') + def test_get_info(self, call, InstanceInfo): + call.return_value = 'on' + self.driver.get_info(self._instance) + call.assert_called_once_with('guest_get_power_state', + self._instance['name']) + InstanceInfo.assert_called_once_with(power_state.RUNNING) - self.driver.spawn(self._context, self._instance, self._image_meta, - injected_files=None, admin_password=None, - allocations=None, - network_info=self._network_info, - block_device_info=self._block_device_info, - flavor=self._flavor) - generate_configdrive.assert_called_once_with(self._context, - self._instance, - os_distro, - self._network_info, - None, None) - image_query.assert_called_with(self._image_meta.id) - if not image_query_result[0]: - import_spawn_image.assert_called_once_with(self._context, - self._image_meta.id, - os_distro) + @mock.patch('nova_zvm.virt.zvm.driver.ZVMDriver.list_instances') + def test_private_instance_exists_True(self, list_instances): + list_instances.return_value = ['vm1', 'vm2'] + res = self.driver._instance_exists('vm1') + self.assertTrue(res) - guest_create.assert_called_once_with('test0001', 1, 1024, disk_list) - setup_network.assert_called_once_with('test0001', self._network_info) - guest_deploy.assert_called_once_with('test0001', - 'rhel7.2-s390x-netboot-0a0c576a_157f_42c8_bde5_2a254d8b77fc', - '/tmp/fakecfg.tgz', zvmutils.get_host()) + @mock.patch('nova_zvm.virt.zvm.driver.ZVMDriver.list_instances') + def test_private_instance_exists_False(self, list_instances): + list_instances.return_value = ['vm1', 'vm2'] + res = self.driver._instance_exists('vm3') + self.assertFalse(res) - if eph_disks: - guest_config_minidisks.assert_called_once_with('test0001', - eph_list) + @mock.patch('nova_zvm.virt.zvm.driver.ZVMDriver._instance_exists') + def test_instance_exists(self, is_exists): + is_exists_response = [] + is_exists_response.append(True) + is_exists_response.append(False) + is_exists.side_effect = is_exists_response + res = self.driver.instance_exists(self._instance) + is_exists.assert_any_call(self._instance.name) + self.assertTrue(res) - wait_network_ready.assert_called_once_with('test0001', - self._instance) - guest_start.assert_called_once_with('test0001') + res = self.driver.instance_exists(self._instance) + is_exists.assert_any_call(self._instance.name) + self.assertFalse(res) - def test_spawn_simple_path(self): - self._test_spawn(image_query_result=( - ["rhel7.2-s390x-netboot-0a0c576a_157f_42c8_bde5_2a254d8b77fc"], - ["rhel7.2-s390x-netboot-0a0c576a_157f_42c8_bde5_2a254d8b77fc"]), - eph_disks=[]) + @mock.patch('nova_zvm.virt.zvm.utils.zVMConnectorRequestHandler.call') + def test_private_get_image_info_err(self, call): + call.side_effect = exception.NovaException(results={'overallRC': 500}) + self.assertRaises(exception.NovaException, self.driver._get_image_info, + 'context', 'image_meta_id', 'os_distro') - def test_spawn_image_not_in_backend(self): - self._test_spawn(image_query_result=( - [], - ["rhel7.2-s390x-netboot-0a0c576a_157f_42c8_bde5_2a254d8b77fc"]), - eph_disks=[]) + @mock.patch('nova_zvm.virt.zvm.utils.zVMConnectorRequestHandler.call') + @mock.patch('nova_zvm.virt.zvm.driver.ZVMDriver._import_spawn_image') + def test_private_get_image_info(self, image_import, call): + call_response = [] + call_response.append(exception.NovaException(results= + {'overallRC': 404})) + call_response.append('Query_Result') + call.side_effect = call_response + self.driver._get_image_info('context', 'image_meta_id', 'os_distro') + call.assert_any_call('image_query', imagename='image_meta_id') + image_import.assert_called_once_with('context', 'image_meta_id', + 'os_distro') + call.assert_any_call('image_query', imagename='image_meta_id') - def test_spawn_with_ephemeral_disks(self): - self._test_spawn(image_query_result=( - ["rhel7.2-s390x-netboot-0a0c576a_157f_42c8_bde5_2a254d8b77fc"], - ["rhel7.2-s390x-netboot-0a0c576a_157f_42c8_bde5_2a254d8b77fc"]), - eph_disks=[{'guest_format': u'ext3', - 'device_name': u'/dev/sdb', - 'disk_bus': None, - 'device_type': None, - 'size': 1}, - {'guest_format': u'ext4', - 'device_name': u'/dev/sdc', - 'disk_bus': None, - 'device_type': None, - 'size': 2}]) + @mock.patch('nova_zvm.virt.zvm.utils.zVMConnectorRequestHandler.call') + def test_private_get_image_info_exist(self, call): + call.return_value = 'image-info' + res = self.driver._get_image_info('context', 'image_meta_id', + 'os_distro') + call.assert_any_call('image_query', imagename='image_meta_id') + self.assertEqual('image-info', res) - @mock.patch.object(driver.ZVMDriver, '_instance_exists') - @mock.patch.object(sdkapi.SDKAPI, 'guest_delete') - def test_destroy(self, guest_delete, instance_exists): + @mock.patch('nova_zvm.virt.zvm.utils.zVMConnectorRequestHandler.call') + def _test_set_disk_list(self, call, has_get_root_units=False, + has_eph_disks=False): + disk_list = [{'is_boot_disk': True, 'size': '3g'}] + eph_disk_list = [{'format': u'ext3', 'size': '1g'}, + {'format': u'ext4', 'size': '2g'}] + _inst = copy.copy(self._instance) + _bdi = copy.copy(self._block_device_info) + + if has_get_root_units: + # overwrite + disk_list = [{'is_boot_disk': True, 'size': '3338'}] + call.return_value = '3338' + _inst['root_gb'] = 0 + else: + _inst['root_gb'] = 3 + + if has_eph_disks: + disk_list += eph_disk_list + else: + _bdi['ephemerals'] = [] + eph_disk_list = [] + + res1, res2 = self.driver._set_disk_list(_inst, self._image_meta.id, + _bdi) + + if has_get_root_units: + call.assert_called_once_with('image_get_root_disk_size', + self._image_meta.id) + self.assertEqual(disk_list, res1) + self.assertEqual(eph_disk_list, res2) + + def test_private_set_disk_list_simple(self): + self._test_set_disk_list() + + def test_private_set_disk_list_with_eph_disks(self): + self._test_set_disk_list(has_eph_disks=True) + + def test_private_set_disk_list_with_get_root_units(self): + self._test_set_disk_list(has_get_root_units=True) + + @mock.patch('nova_zvm.virt.zvm.utils.zVMConnectorRequestHandler.call') + def test_private_setup_network(self, call): + inst_nets = [] + _net = {'ip_addr': '192.168.0.100', + 'gateway_addr': '192.168.0.1', + 'cidr': '192.168.0.1/24', + 'mac_addr': 'DE:AD:BE:EF:00:00', + 'nic_id': None} + inst_nets.append(_net) + self.driver._setup_network('vm_name', 'os_distro', self._network_info, + self._instance) + call.assert_any_call('guest_create_network_interface', + 'vm_name', 'os_distro', inst_nets) + + def test_private_nic_coupled(self): + user_direct = {'user_direct': + ['User TEST', + "NICDEF 1000 TYPE QDIO LAN SYSTEM TESTVS"]} + res = self.driver._nic_coupled(user_direct, '1000', 'TESTVS') + self.assertTrue(res) + + res = self.driver._nic_coupled(user_direct, '2000', 'TESTVS') + self.assertFalse(res) + + res = self.driver._nic_coupled(user_direct, '1000', None) + self.assertFalse(res) + + @mock.patch('pwd.getpwuid') + def test_private_get_host(self, getpwuid): + class FakePwuid(object): + def __init__(self): + self.pw_name = 'test' + getpwuid.return_value = FakePwuid() + res = self.driver._get_host() + self.assertEqual('test@192.168.1.1', res) + + @mock.patch('nova.virt.images.fetch') + @mock.patch('os.path.exists') + @mock.patch('nova_zvm.virt.zvm.driver.ZVMDriver._get_host') + @mock.patch('nova_zvm.virt.zvm.utils.zVMConnectorRequestHandler.call') + def test_private_import_spawn_image(self, call, get_host, exists, fetch): + get_host.return_value = 'test@192.168.1.1' + exists.return_value = False + + image_url = "file:///test/image/image_name" + image_meta = {'os_version': 'os_version'} + self.driver._import_spawn_image(self._context, 'image_name', + 'os_version') + fetch.assert_called_once_with(self._context, 'image_name', + "/test/image/image_name") + get_host.assert_called_once_with() + call.assert_called_once_with('image_import', 'image_name', image_url, + image_meta, remote_host='test@192.168.1.1') + + @mock.patch('nova_zvm.virt.zvm.driver.ZVMDriver._instance_exists') + @mock.patch('nova_zvm.virt.zvm.utils.zVMConnectorRequestHandler.call') + def test_destroy(self, call, instance_exists): instance_exists.return_value = True self.driver.destroy(self._context, self._instance, network_info=self._network_info) - guest_delete.assert_called_once_with(self._instance['name']) + call.assert_called_once_with('guest_delete', self._instance['name']) - @mock.patch.object(driver.ZVMDriver, '_instance_exists') - @mock.patch.object(sdkapi.SDKAPI, 'guest_stop') - def test_power_off(self, guest_stop, instance_exists): - instance_exists.return_value = True - self.driver.power_off(self._instance) - guest_stop.assert_called_once_with(self._instance['name'], 0, 0) + def test_get_host_uptime(self): + with mock.patch('nova_zvm.virt.zvm.utils.' + 'zVMConnectorRequestHandler.call') as mcall: + mcall.return_value = {'hypervisor_hostname': 'TESTHOST', + 'ipl_time': 'TESTTIME'} + time = self.driver.get_host_uptime() + self.assertEqual('TESTTIME', time) - @mock.patch.object(driver.ZVMDriver, '_instance_exists') - @mock.patch.object(sdkapi.SDKAPI, 'guest_start') - def test_power_on(self, guest_start, instance_exists): - instance_exists.return_value = True - self.driver.power_on(self._context, self._instance, - network_info=self._network_info) - guest_start.assert_called_once_with(self._instance['name']) + def test_spawn_invalid_userid(self): + self.flags(instance_name_template='test%05x') + self.addCleanup(self.flags, instance_name_template='test%04x') + invalid_inst = fake_instance.fake_instance_obj(self._context, + name='123456789') + self.assertRaises(exception.InvalidInput, self.driver.spawn, + self._context, invalid_inst, self._image_meta, + injected_files=None, admin_password=None, + allocations=None, network_info=self._network_info, + block_device_info=self._block_device_info, + flavor=self._flavor) + + @mock.patch('nova_zvm.virt.zvm.driver.ZVMDriver._wait_network_ready') + @mock.patch('nova_zvm.virt.zvm.driver.ZVMDriver._setup_network') + @mock.patch('nova_zvm.virt.zvm.driver.ZVMDriver._get_host') + @mock.patch('nova_zvm.virt.zvm.driver.ZVMDriver._set_disk_list') + @mock.patch.object(zvmutils.VMUtils, 'generate_configdrive') + @mock.patch('nova_zvm.virt.zvm.driver.ZVMDriver._get_image_info') + @mock.patch('nova_zvm.virt.zvm.utils.zVMConnectorRequestHandler.call') + def test_spawn(self, call, get_image_info, gen_conf_file, set_disk_list, + get_host, setup_network, wait_ready): + _inst = copy.copy(self._instance) + _bdi = copy.copy(self._block_device_info) + get_image_info.return_value = [['image_name']] + gen_conf_file.return_value = 'transportfiles' + set_disk_list.return_value = 'disk_list', 'eph_list' + get_host.return_value = 'test@192.168.1.1' + setup_network.return_value = '' + wait_ready.return_value = '' + call_resp = ['', '', '', ''] + call.side_effect = call_resp + + self.driver.spawn(self._context, _inst, self._image_meta, + injected_files=None, admin_password=None, + allocations=None, network_info=self._network_info, + block_device_info=_bdi, flavor=self._flavor) + gen_conf_file.assert_called_once_with(self._context, _inst, + None, None) + get_image_info.assert_called_once_with(self._context, + self._image_meta.id, + self._image_meta.properties.os_distro) + set_disk_list.assert_called_once_with(_inst, 'image_name', _bdi) + call.assert_any_call('guest_create', _inst['name'], + 1, 1024, disk_list='disk_list') + get_host.assert_called_once_with() + call.assert_any_call('guest_deploy', _inst['name'], 'image_name', + transportfiles='transportfiles', + remotehost='test@192.168.1.1') + setup_network.assert_called_once_with(_inst['name'], + self._image_meta.properties.os_distro, + self._network_info, _inst) + call.assert_any_call('guest_config_minidisks', _inst['name'], + 'eph_list') + wait_ready.assert_called_once_with(_inst) + call.assert_any_call('guest_start', _inst['name']) + + @mock.patch('nova_zvm.virt.zvm.driver.ZVMDriver._nic_coupled') + @mock.patch('nova_zvm.virt.zvm.utils.zVMConnectorRequestHandler.call') + def test_private_wait_network_ready(self, call, nic_coupled): + call_resp = [] + switch_dict = {'1000': 'TESTVM'} + user_direct = {'user_direct': + ['User TEST', + "NICDEF 1000 TYPE QDIO LAN SYSTEM TESTVS"]} + call_resp.append(switch_dict) + call_resp.append(user_direct) + call.side_effect = call_resp + nic_coupled.return_value = True + self.driver._wait_network_ready(self._instance) + call.assert_any_call('guest_get_nic_vswitch_info', + self._instance['name']) + + call.assert_any_call('guest_get_definition_info', + self._instance['name']) diff --git a/nova_zvm/virt/zvm/conf.py b/nova_zvm/virt/zvm/conf.py index 17c14e3..9449a6c 100644 --- a/nova_zvm/virt/zvm/conf.py +++ b/nova_zvm/virt/zvm/conf.py @@ -15,6 +15,11 @@ from oslo_config import cfg zvm_opts = [ + cfg.StrOpt('zvm_cloud_connector_url', + help=""" +URL to be used to communicate with z/VM Cloud Connector. +Example: https://10.10.10.1:8080. +"""), cfg.StrOpt('zvm_image_tmp_path', default='/var/lib/nova/images', help=""" diff --git a/nova_zvm/virt/zvm/configdrive.py b/nova_zvm/virt/zvm/configdrive.py index bc8a9e2..5824f02 100644 --- a/nova_zvm/virt/zvm/configdrive.py +++ b/nova_zvm/virt/zvm/configdrive.py @@ -25,8 +25,6 @@ from oslo_log import log as logging LOG = logging.getLogger(__name__) - - CONF = cfg.CONF diff --git a/nova_zvm/virt/zvm/driver.py b/nova_zvm/virt/zvm/driver.py index 6f1e1ec..4988f01 100644 --- a/nova_zvm/virt/zvm/driver.py +++ b/nova_zvm/virt/zvm/driver.py @@ -15,35 +15,31 @@ import datetime import eventlet -import six +import os +import pwd import time -from nova import exception as nova_exception +from nova.compute import power_state +from nova import exception from nova.i18n import _ -from nova.image import api as image_api from nova.objects import fields as obj_fields from nova.virt import driver from nova.virt import hardware +from nova.virt import images from oslo_log import log as logging from oslo_serialization import jsonutils from oslo_service import loopingcall from oslo_utils import excutils from oslo_utils import timeutils -from zvmsdk import api as sdkapi -from zvmsdk import exception as sdkexception from nova_zvm.virt.zvm import conf from nova_zvm.virt.zvm import const -from nova_zvm.virt.zvm import exception from nova_zvm.virt.zvm import utils as zvmutils LOG = logging.getLogger(__name__) CONF = conf.CONF -CONF.import_opt('default_ephemeral_format', 'nova.conf') -CONF.import_opt('host', 'nova.conf') -CONF.import_opt('my_ip', 'nova.conf') class ZVMDriver(driver.ComputeDriver): @@ -58,34 +54,14 @@ class ZVMDriver(driver.ComputeDriver): def __init__(self, virtapi): super(ZVMDriver, self).__init__(virtapi) - self._sdk_api = sdkapi.SDKAPI() + self._reqh = zvmutils.zVMConnectorRequestHandler() self._vmutils = zvmutils.VMUtils() - - self._image_api = image_api.API() - self._pathutils = zvmutils.PathUtils() - self._imageutils = zvmutils.ImageUtils() - self._networkutils = zvmutils.NetworkUtils() self._imageop_semaphore = eventlet.semaphore.Semaphore(1) - # incremental sleep interval list - _inc_slp = [5, 10, 20, 30, 60] - _slp = 5 - - self._host_stats = [] - _slp = 5 - - while (self._host_stats == []): - try: - self._host_stats = self.update_host_status() - except Exception as e: - # Ignore any exceptions and log as warning - _slp = len(_inc_slp) != 0 and _inc_slp.pop(0) or _slp - msg = _("Failed to get host stats while initializing zVM " - "driver due to reason %(reason)s, will re-try in " - "%(slp)d seconds") - LOG.warning(msg, {'reason': six.text_type(e), - 'slp': _slp}) - time.sleep(_slp) + # get hypervisor host name + res = self._reqh.call('host_get_info') + self._hypervisor_hostname = res['hypervisor_hostname'] + LOG.info("The zVM compute driver has been initialized.") def init_host(self, host): """Initialize anything that is necessary for the driver to function, @@ -93,35 +69,92 @@ class ZVMDriver(driver.ComputeDriver): """ pass - def _get_instance_info(self, instance): - power_stat = self._sdk_api.guest_get_power_state(instance['name']) - power_stat = zvmutils.mapping_power_stat(power_stat) - - _instance_info = hardware.InstanceInfo(power_stat) - - return _instance_info - - def get_info(self, instance): - """Get the current status of an instance.""" - inst_name = instance['name'] - - try: - return self._get_instance_info(instance) - except sdkexception.ZVMVirtualMachineNotExist: - LOG.warning(_("z/VM instance %s does not exist") % inst_name, - instance=instance) - raise nova_exception.InstanceNotFound(instance_id=inst_name) - except Exception as err: - # TODO(YDY): raise nova_exception.InstanceNotFound - LOG.warning(_("Failed to get the info of z/VM instance %s") % - inst_name, instance=instance) - raise err - def list_instances(self): """Return the names of all the instances known to the virtualization layer, as a list. """ - return self._sdk_api.guest_list() + return self._reqh.call('guest_list') + + def _get_host_status(self): + LOG.debug("Getting host status for %s", CONF.host) + + info = self._reqh.call('host_get_info') + + host_status = {'host': CONF.host, + 'allowed_vm_type': const.ALLOWED_VM_TYPE} + host_status['vcpus'] = info['vcpus'] + host_status['vcpus_used'] = info['vcpus_used'] + host_status['cpu_info'] = info['cpu_info'] + host_status['disk_total'] = info['disk_total'] + host_status['disk_used'] = info['disk_used'] + host_status['disk_available'] = info['disk_available'] + host_status['host_memory_total'] = info['memory_mb'] + host_status['host_memory_free'] = (info['memory_mb'] - + info['memory_mb_used']) + host_status['hypervisor_type'] = info['hypervisor_type'] + host_status['hypervisor_version'] = info['hypervisor_version'] + host_status['hypervisor_hostname'] = info['hypervisor_hostname'] + host_status['supported_instances'] = [(const.ARCHITECTURE, + const.HYPERVISOR_TYPE, + obj_fields.VMMode.HVM)] + host_status['ipl_time'] = info['ipl_time'] + + return host_status + + def get_available_resource(self, nodename=None): + LOG.debug("Getting available resource for %s", CONF.host) + + try: + host_stats = self._reqh.call('host_get_info') + except exception.NovaException: + host_stats = {} + + res = { + 'vcpus': host_stats.get('vcpus', 0), + 'memory_mb': host_stats.get('memory_mb', 0), + 'local_gb': host_stats.get('disk_total', 0), + 'vcpus_used': 0, + 'memory_mb_used': host_stats.get('memory_mb_used', 0), + 'local_gb_used': host_stats.get('disk_used', 0), + 'hypervisor_type': host_stats.get('hypervisor_type', 'zvm'), + 'hypervisor_version': host_stats.get('hypervisor_version', ''), + 'hypervisor_hostname': host_stats.get('hypervisor_hostname', ''), + 'cpu_info': jsonutils.dumps(host_stats.get('cpu_info', {})), + 'disk_available_least': host_stats.get('disk_available', 0), + 'supported_instances': [(const.ARCHITECTURE, + const.HYPERVISOR_TYPE, + obj_fields.VMMode.HVM)], + 'numa_topology': None, + } + + return res + + def get_available_nodes(self, refresh=False): + return [self._hypervisor_hostname] + + def _mapping_power_stat(self, power_stat): + """Translate power state to OpenStack defined constants.""" + return const.ZVM_POWER_STAT.get(power_stat, power_state.NOSTATE) + + def get_info(self, instance): + """Get the current status of an instance.""" + power_stat = '' + try: + power_stat = self._reqh.call('guest_get_power_state', + instance['name']) + except exception.NovaException as err: + if err.kwargs['results']['overallRC'] == 404: + # instance not exists + LOG.warning("Get power state of non-exist instance: %s", + instance['name']) + raise exception.InstanceNotFound(instance_id=instance['name']) + else: + raise + + power_stat = self._mapping_power_stat(power_stat) + _instance_info = hardware.InstanceInfo(power_stat) + + return _instance_info def _instance_exists(self, instance_name): """Overwrite this to using instance name as input parameter.""" @@ -134,7 +167,7 @@ class ZVMDriver(driver.ComputeDriver): def spawn(self, context, instance, image_meta, injected_files, admin_password, allocations, network_info=None, block_device_info=None, flavor=None): - LOG.info(_("Spawning new instance %s on zVM hypervisor") % + LOG.info(_("Spawning new instance %s on zVM hypervisor"), instance['name'], instance=instance) # For zVM instance, limit the maximum length of instance name to \ 8 if len(instance['name']) > 8: @@ -142,114 +175,141 @@ class ZVMDriver(driver.ComputeDriver): "name: %s, please change your instance_name_template to make " "sure the length of instance name is not longer than 8 " "characters") % instance['name']) - raise nova_exception.InvalidInput(reason=msg) + raise exception.InvalidInput(reason=msg) try: spawn_start = time.time() os_distro = image_meta.properties.os_distro - - # TODO(YaLian) will remove network files from this transportfiles = self._vmutils.generate_configdrive( - context, instance, os_distro, network_info, - injected_files, admin_password) + context, instance, injected_files, admin_password) - with self._imageop_semaphore: - spawn_image_exist = self._sdk_api.image_query( - image_meta.id) - if not spawn_image_exist: - self._imageutils.import_spawn_image( - context, image_meta.id, os_distro) + resp = self._get_image_info(context, image_meta.id, os_distro) + spawn_image_name = resp[0][0] + disk_list, eph_list = self._set_disk_list(instance, + spawn_image_name, + block_device_info) - spawn_image_name = self._sdk_api.image_query( - image_meta.id)[0] - if instance['root_gb'] == 0: - root_disk_size = self._sdk_api.image_get_root_disk_size( - spawn_image_name) - else: - root_disk_size = '%ig' % instance['root_gb'] + # Create the guest vm + self._reqh.call('guest_create', instance['name'], + instance['vcpus'], instance['memory_mb'], + disk_list=disk_list) - disk_list = [] - root_disk = {'size': root_disk_size, - 'is_boot_disk': True - } - disk_list.append(root_disk) - ephemeral_disks_info = block_device_info.get('ephemerals', []) - eph_list = [] - for eph in ephemeral_disks_info: - eph_dict = {'size': '%ig' % eph['size'], - 'format': (eph['guest_format'] or - CONF.default_ephemeral_format or - const.DEFAULT_EPH_DISK_FMT)} - eph_list.append(eph_dict) - - if eph_list: - disk_list.extend(eph_list) - self._sdk_api.guest_create(instance['name'], instance['vcpus'], - instance['memory_mb'], disk_list) + # Deploy image to the guest vm + remotehost = self._get_host() + self._reqh.call('guest_deploy', instance['name'], + spawn_image_name, transportfiles=transportfiles, + remotehost=remotehost) # Setup network for z/VM instance - self._setup_network(instance['name'], network_info) - self._sdk_api.guest_deploy(instance['name'], spawn_image_name, - transportfiles, zvmutils.get_host()) + self._setup_network(instance['name'], os_distro, network_info, + instance) # Handle ephemeral disks if eph_list: - self._sdk_api.guest_config_minidisks(instance['name'], - eph_list) + self._reqh.call('guest_config_minidisks', + instance['name'], eph_list) - self._wait_network_ready(instance['name'], instance) + self._wait_network_ready(instance) - self._sdk_api.guest_start(instance['name']) + self._reqh.call('guest_start', instance['name']) spawn_time = time.time() - spawn_start - LOG.info(_("Instance spawned succeeded in %s seconds") % + LOG.info(_("Instance spawned succeeded in %s seconds"), spawn_time, instance=instance) except Exception as err: with excutils.save_and_reraise_exception(): LOG.error(_("Deploy image to instance %(instance)s " - "failed with reason: %(err)s") % + "failed with reason: %(err)s"), {'instance': instance['name'], 'err': err}, instance=instance) self.destroy(context, instance, network_info, block_device_info) - def _setup_network(self, vm_name, network_info): - LOG.debug("Creating NICs for vm %s", vm_name) - manage_IP_set = False - for vif in network_info: - if not manage_IP_set: - network = vif['network'] - ip_addr = network['subnets'][0]['ips'][0]['address'] - self._sdk_api.guest_create_nic(vm_name, nic_id=vif['id'], - mac_addr=vif['address'], - ip_addr=ip_addr) - manage_IP_set = True + def _get_image_info(self, context, image_meta_id, os_distro): + spawn_image_exist = False + try: + spawn_image_exist = self._reqh.call('image_query', + imagename=image_meta_id) + except exception.NovaException as err: + if err.kwargs['results']['overallRC'] == 404: + # image not exist, nothing to do + pass else: - self._sdk_api.guest_create_nic(vm_name, nic_id=vif['id'], - mac_addr=vif['address']) + raise err - def _wait_network_ready(self, inst_name, instance): + if not spawn_image_exist: + with self._imageop_semaphore: + self._import_spawn_image(context, image_meta_id, os_distro) + return self._reqh.call('image_query', imagename=image_meta_id) + else: + return spawn_image_exist + + def _set_disk_list(self, instance, image_name, block_device_info): + if instance['root_gb'] == 0: + root_disk_size = self._reqh.call('image_get_root_disk_size', + image_name) + else: + root_disk_size = '%ig' % instance['root_gb'] + + disk_list = [] + root_disk = {'size': root_disk_size, + 'is_boot_disk': True + } + disk_list.append(root_disk) + ephemeral_disks_info = block_device_info.get('ephemerals', []) + eph_list = [] + for eph in ephemeral_disks_info: + eph_dict = {'size': '%ig' % eph['size'], + 'format': (eph['guest_format'] or + CONF.default_ephemeral_format or + const.DEFAULT_EPH_DISK_FMT)} + eph_list.append(eph_dict) + + if eph_list: + disk_list.extend(eph_list) + return disk_list, eph_list + + def _setup_network(self, vm_name, os_distro, network_info, instance): + LOG.debug("Creating NICs for vm %s", vm_name) + inst_nets = [] + for vif in network_info: + subnet = vif['network']['subnets'][0] + _net = {'ip_addr': subnet['ips'][0]['address'], + 'gateway_addr': subnet['gateway']['address'], + 'cidr': subnet['cidr'], + 'mac_addr': vif['address'], + 'nic_id': vif['id']} + inst_nets.append(_net) + + if inst_nets: + self._reqh.call('guest_create_network_interface', + vm_name, os_distro, inst_nets) + + def _wait_network_ready(self, instance): """Wait until neutron zvm-agent add all NICs to vm""" + inst_name = instance['name'] + def _wait_for_nics_add_in_vm(inst_name, expiration): if (CONF.zvm_reachable_timeout and timeutils.utcnow() > expiration): msg = _("NIC update check failed " "on instance:%s") % instance.uuid - raise exception.ZVMNetworkError(msg=msg) + raise exception.NovaException(message=msg) try: - switch_dict = self._sdk_api.guest_get_nic_vswitch_info( - inst_name) - if switch_dict and '' not in switch_dict.values(): - for key in switch_dict: - result = self._sdk_api.guest_get_definition_info( - inst_name, nic_coupled=key) - if not result['nic_coupled']: + switch_dict = self._reqh.call('guest_get_nic_vswitch_info', + inst_name) + if switch_dict and None not in switch_dict.values(): + for key, value in switch_dict.items(): + user_direct = self._reqh.call( + 'guest_get_definition_info', + inst_name) + if not self._nic_coupled(user_direct, key, value): return else: # In this case, the nic switch info is not ready yet # need another loop to check until time out or find it return - except exception.ZVMBaseException as e: + except Exception as e: # Ignore any zvm driver exceptions LOG.info(_('encounter error %s during get vswitch info'), e.format_message(), instance=instance) @@ -268,136 +328,44 @@ class ZVMDriver(driver.ComputeDriver): _wait_for_nics_add_in_vm, inst_name, expiration) timer.start(interval=10).wait() - @property - def need_legacy_block_device_info(self): + def _nic_coupled(self, user_direct, vdev, vswitch): + if vswitch is None: + return False + direct_info = user_direct['user_direct'] + nic_str = ("NICDEF %s TYPE QDIO LAN SYSTEM %s" % + (vdev.upper(), vswitch.upper())) + for info in direct_info: + if nic_str in info: + return True return False + def _get_host(self): + return ''.join([pwd.getpwuid(os.geteuid()).pw_name, '@', CONF.my_ip]) + + def _import_spawn_image(self, context, image_href, image_os_version): + LOG.debug("Downloading the image %s from glance to nova compute " + "server", image_href) + image_path = os.path.join(os.path.normpath(CONF.zvm_image_tmp_path), + image_href) + if not os.path.exists(image_path): + images.fetch(context, image_href, image_path) + image_url = "file://" + image_path + image_meta = {'os_version': image_os_version} + remote_host = self._get_host() + self._reqh.call('image_import', image_href, image_url, + image_meta, remote_host=remote_host) + def destroy(self, context, instance, network_info=None, block_device_info=None, destroy_disks=False): - inst_name = instance['name'] if self._instance_exists(inst_name): LOG.info(_("Destroying instance %s"), inst_name, instance=instance) - self._sdk_api.guest_delete(inst_name) + self._reqh.call('guest_delete', inst_name) else: LOG.warning(_('Instance %s does not exist'), inst_name, instance=instance) - def attach_volume(self, context, connection_info, instance, mountpoint, - disk_bus=None, device_type=None, encryption=None): - """Attach the disk to the instance at mountpoint using info.""" - pass - - def detach_volume(self, connection_info, instance, mountpoint=None, - encryption=None): - """Detach the disk attached to the instance.""" - pass - - def power_off(self, instance, timeout=0, retry_interval=0): - """Power off the specified instance.""" - inst_name = instance['name'] - if self._instance_exists(inst_name): - LOG.info(_("Powering OFF instance %s"), inst_name, - instance=instance) - self._sdk_api.guest_stop(inst_name, timeout, retry_interval) - else: - LOG.warning(_('Instance %s does not exist'), inst_name, - instance=instance) - - def power_on(self, context, instance, network_info, - block_device_info=None): - """Power on the specified instance.""" - inst_name = instance['name'] - if self._instance_exists(inst_name): - LOG.info(_("Powering ON instance %s"), inst_name, - instance=instance) - self._sdk_api.guest_start(inst_name) - else: - LOG.warning(_('Instance %s does not exist'), inst_name, - instance=instance) - - def get_available_resource(self, nodename=None): - """Retrieve resource information. - - This method is called when nova-compute launches, and - as part of a periodic task - - :param nodename: - node which the caller want to get resources from - a driver that manages only one node can safely ignore this - :returns: Dictionary describing resources - - """ - LOG.debug("Getting available resource for %s" % CONF.host) - stats = self.update_host_status()[0] - - mem_used = stats['host_memory_total'] - stats['host_memory_free'] - supported_instances = stats['supported_instances'] - dic = { - 'vcpus': stats['vcpus'], - 'memory_mb': stats['host_memory_total'], - 'local_gb': stats['disk_total'], - 'vcpus_used': stats['vcpus_used'], - 'memory_mb_used': mem_used, - 'local_gb_used': stats['disk_used'], - 'hypervisor_type': stats['hypervisor_type'], - 'hypervisor_version': stats['hypervisor_version'], - 'hypervisor_hostname': stats['hypervisor_hostname'], - 'cpu_info': jsonutils.dumps(stats['cpu_info']), - 'disk_available_least': stats['disk_available'], - 'supported_instances': supported_instances, - 'numa_topology': None, - } - - return dic - - def ensure_filtering_rules_for_instance(self, instance_ref, network_info): - # It enforces security groups on host initialization and live - # migration. In z/VM we do not assume instances running upon host - # initialization - return - - def update_host_status(self): - """Refresh host stats. One compute service entry possibly - manages several hypervisors, so will return a list of host - status information. - """ - LOG.debug("Updating host status for %s" % CONF.host) - - caps = [] - - info = self._sdk_api.host_get_info() - - data = {'host': CONF.host, - 'allowed_vm_type': const.ALLOWED_VM_TYPE} - data['vcpus'] = info['vcpus'] - data['vcpus_used'] = info['vcpus_used'] - data['cpu_info'] = info['cpu_info'] - data['disk_total'] = info['disk_total'] - data['disk_used'] = info['disk_used'] - data['disk_available'] = info['disk_available'] - data['host_memory_total'] = info['memory_mb'] - data['host_memory_free'] = (info['memory_mb'] - - info['memory_mb_used']) - data['hypervisor_type'] = info['hypervisor_type'] - data['hypervisor_version'] = info['hypervisor_version'] - data['hypervisor_hostname'] = info['hypervisor_hostname'] - data['supported_instances'] = [(const.ARCHITECTURE, - const.HYPERVISOR_TYPE, - obj_fields.VMMode.HVM)] - data['ipl_time'] = info['ipl_time'] - - caps.append(data) - - return caps - - def get_console_output(self, context, instance): - return self._sdk_api.guest_get_console_output(instance.name) - def get_host_uptime(self): - return self._host_stats[0]['ipl_time'] - - def get_available_nodes(self, refresh=False): - return [d['hypervisor_hostname'] for d in self._host_stats - if (d.get('hypervisor_hostname') is not None)] + res = self._reqh.call('host_get_info') + return res['ipl_time'] diff --git a/nova_zvm/virt/zvm/exception.py b/nova_zvm/virt/zvm/exception.py deleted file mode 100644 index e59a51d..0000000 --- a/nova_zvm/virt/zvm/exception.py +++ /dev/null @@ -1,46 +0,0 @@ -# Copyright 2013 IBM Corp. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - - -from nova import exception -from nova.i18n import _ - - -class ZVMBaseException(exception.NovaException): - """Base z/VM exception.""" - pass - - -class ZVMDriverError(ZVMBaseException): - msg_fmt = _('z/VM driver error: %(msg)s') - - -class ZVMVolumeError(ZVMBaseException): - msg_fmt = _('Volume error: %(msg)s') - - -class ZVMImageError(ZVMBaseException): - msg_fmt = _("Image error: %(msg)s") - - -class ZVMNetworkError(ZVMBaseException): - msg_fmt = _("z/VM network error: %(msg)s") - - -class ZVMConfigDriveError(ZVMBaseException): - msg_fmt = _('Create configure drive failed: %(msg)s') - - -class ZVMRetryException(ZVMBaseException): - pass diff --git a/nova_zvm/virt/zvm/utils.py b/nova_zvm/virt/zvm/utils.py index d45fb27..079751b 100644 --- a/nova_zvm/virt/zvm/utils.py +++ b/nova_zvm/virt/zvm/utils.py @@ -14,31 +14,25 @@ import os -import pwd from nova.api.metadata import base as instance_metadata -from nova import block_device from nova.compute import power_state +from nova import exception from nova.i18n import _ from nova.virt import configdrive -from nova.virt import driver -from nova.virt import images -from oslo_config import cfg from oslo_log import log as logging -from zvmsdk import api as zvm_api -from zvmsdk import dist +import six.moves.urllib.parse as urlparse +from zvmconnector import connector +from nova_zvm.virt.zvm import conf from nova_zvm.virt.zvm import configdrive as zvmconfigdrive from nova_zvm.virt.zvm import const -from nova_zvm.virt.zvm import exception LOG = logging.getLogger(__name__) -CONF = cfg.CONF +CONF = conf.CONF -CONF.import_opt('host', 'nova.conf') CONF.import_opt('instances_path', 'nova.compute.manager') -CONF.import_opt('my_ip', 'nova.conf') def mapping_power_stat(power_stat): @@ -46,30 +40,23 @@ def mapping_power_stat(power_stat): return const.ZVM_POWER_STAT.get(power_stat, power_state.NOSTATE) -def _volume_in_mapping(mount_device, block_device_info): - block_device_list = [block_device.strip_dev(vol['mount_device']) - for vol in - driver.block_device_info_get_mapping( - block_device_info)] - LOG.debug("block_device_list %s", block_device_list) - return block_device.strip_dev(mount_device) in block_device_list +class zVMConnectorRequestHandler(object): + def __init__(self): + _url = urlparse.urlparse(CONF.zvm_cloud_connector_url) + self._conn = connector.ZVMConnector(_url.hostname, _url.port) -def is_volume_root(root_device, mountpoint): - """This judges if the moutpoint equals the root_device.""" - return block_device.strip_dev(mountpoint) == block_device.strip_dev( - root_device) - - -def is_boot_from_volume(block_device_info): - root_mount_device = driver.block_device_info_get_root(block_device_info) - boot_from_volume = _volume_in_mapping(root_mount_device, - block_device_info) - return root_mount_device, boot_from_volume - - -def get_host(): - return ''.join([pwd.getpwuid(os.geteuid()).pw_name, '@', CONF.my_ip]) + def call(self, func_name, *args, **kwargs): + results = self._conn.send_request(func_name, *args, **kwargs) + if results['overallRC'] == 0: + return results['output'] + else: + msg = ("SDK request %(api)s failed with parameters: %(args)s " + "%(kwargs)s . Results: %(results)s" % + {'api': func_name, 'args': str(args), 'kwargs': str(kwargs), + 'results': str(results)}) + LOG.debug(msg) + raise exception.NovaException(message=msg, results=results) class PathUtils(object): @@ -80,61 +67,40 @@ class PathUtils(object): instance_folder = os.path.join(self._get_instances_path(), instance_uuid) if not os.path.exists(instance_folder): - LOG.debug("Creating the instance path %s" % instance_folder) + LOG.debug("Creating the instance path %s", instance_folder) os.makedirs(instance_folder) return instance_folder - def get_console_log_path(self, os_node, instance_name): - return os.path.join(self.get_instance_path(os_node, instance_name), - "console.log") - - -class NetworkUtils(object): - """Utilities for z/VM network operator.""" - pass - class VMUtils(object): def __init__(self): - self._sdk_api = zvm_api.SDKAPI() - self._dist_manager = dist.LinuxDistManager() self._pathutils = PathUtils() - self._imageutils = ImageUtils() # Prepare and create configdrive for instance - def generate_configdrive(self, context, instance, os_version, - network_info, injected_files, admin_password): + def generate_configdrive(self, context, instance, injected_files, + admin_password): # Create network configuration files LOG.debug('Creating network configuration files ' - 'for instance: %s' % instance['name'], instance=instance) + 'for instance: %s', instance['name'], instance=instance) - linuxdist = self._dist_manager.get_linux_dist(os_version)() instance_path = self._pathutils.get_instance_path(instance['uuid']) - files_and_cmds = linuxdist.create_network_configuration_files( - instance_path, network_info) - (net_conf_files, net_conf_cmds) = files_and_cmds - # Add network configure files to inject_files - if len(net_conf_files) > 0: - injected_files.extend(net_conf_files) - transportfiles = None if configdrive.required_by(instance): transportfiles = self._create_config_drive(context, instance_path, instance, injected_files, - admin_password, - net_conf_cmds, - linuxdist) + admin_password) return transportfiles def _create_config_drive(self, context, instance_path, instance, - injected_files, admin_password, commands, - linuxdist): + injected_files, admin_password): if CONF.config_drive_format not in ['tgz', 'iso9660']: msg = (_("Invalid config drive format %s") % CONF.config_drive_format) - raise exception.ZVMConfigDriveError(msg=msg) + LOG.debug(msg) + raise exception.ConfigDriveUnsupportedFormat( + format=CONF.config_drive_format) LOG.debug('Using config drive', instance=instance) @@ -142,19 +108,6 @@ class VMUtils(object): if admin_password: extra_md['admin_pass'] = admin_password - udev_settle = linuxdist.get_znetconfig_contents() - if udev_settle: - if len(commands) == 0: - znetconfig = '\n'.join(('#!/bin/bash', udev_settle)) - else: - znetconfig = '\n'.join(('#!/bin/bash', commands, udev_settle)) - znetconfig += '\nrm -rf /tmp/znetconfig.sh\n' - # Create a temp file in instance to execute above commands - net_cmd_file = [] - net_cmd_file.append(('/tmp/znetconfig.sh', znetconfig)) # nosec - injected_files.extend(net_cmd_file) - # injected_files.extend(('/tmp/znetconfig.sh', znetconfig)) - inst_md = instance_metadata.InstanceMetadata(instance, content=injected_files, extra_md=extra_md, @@ -165,30 +118,9 @@ class VMUtils(object): configdrive_tgz = os.path.join(instance_path, 'cfgdrive.tgz') - LOG.debug('Creating config drive at %s' % configdrive_tgz, + LOG.debug('Creating config drive at %s', configdrive_tgz, instance=instance) with zvmconfigdrive.ZVMConfigDriveBuilder(instance_md=inst_md) as cdb: cdb.make_drive(configdrive_tgz) return configdrive_tgz - - -class ImageUtils(object): - - def __init__(self): - self._pathutils = PathUtils() - self._sdk_api = zvm_api.SDKAPI() - - def import_spawn_image(self, context, image_href, image_os_version): - LOG.debug("Downloading the image %s from glance to nova compute " - "server" % image_href) - - image_path = os.path.join(os.path.normpath(CONF.zvm_image_tmp_path), - image_href) - if not os.path.exists(image_path): - images.fetch(context, image_href, image_path) - image_url = "file://" + image_path - image_meta = {'os_version': image_os_version} - remote_host = get_host() - self._sdk_api.image_import(image_url, image_meta=image_meta, - remote_host=remote_host) diff --git a/requirements.txt b/requirements.txt index 423d29f..061886f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,4 +9,4 @@ oslo.service>=1.10.0 # Apache-2.0 oslo.utils>=3.20.0 # Apache-2.0 six>=1.9.0 -CloudLib4zvm>=0.2.2 +zVMCloudConnector>=0.3.2 # Apache 2.0 License diff --git a/test-requirements.txt b/test-requirements.txt index a7b9821..9f2dea9 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -19,3 +19,4 @@ vine wsgi-intercept>=1.4.1 # MIT License eventlet!=0.18.3,!=0.20.1,<0.21.0,>=0.18.2 # MIT sphinxcontrib-actdiag # BSD +python-memcached>=1.56