Merge "Update settings during deploying an IBMi VM."
This commit is contained in:
commit
f2d4c27d27
@ -187,6 +187,7 @@ class TestPowerVMDriver(test.TestCase):
|
||||
"""
|
||||
# Set up the mocks to the tasks.
|
||||
inst = objects.Instance(**powervm.TEST_INSTANCE)
|
||||
inst.system_metadata = {'image_os_distro': 'rhel'}
|
||||
my_flavor = inst.get_flavor()
|
||||
mock_get_flv.return_value = my_flavor
|
||||
mock_cfg_drv.return_value = False
|
||||
@ -222,6 +223,7 @@ class TestPowerVMDriver(test.TestCase):
|
||||
"""Validates the PowerVM spawn w/ config drive operations."""
|
||||
# Set up the mocks to the tasks.
|
||||
inst = objects.Instance(**powervm.TEST_INSTANCE)
|
||||
inst.system_metadata = {'image_os_distro': 'rhel'}
|
||||
my_flavor = inst.get_flavor()
|
||||
mock_get_flv.return_value = my_flavor
|
||||
mock_cfg_drv.return_value = True
|
||||
@ -263,6 +265,7 @@ class TestPowerVMDriver(test.TestCase):
|
||||
"""
|
||||
# Set up the mocks to the tasks.
|
||||
inst = objects.Instance(**powervm.TEST_INSTANCE)
|
||||
inst.system_metadata = {'image_os_distro': 'rhel'}
|
||||
my_flavor = inst.get_flavor()
|
||||
mock_get_flv.return_value = my_flavor
|
||||
mock_cfg_drv.return_value = False
|
||||
@ -325,6 +328,7 @@ class TestPowerVMDriver(test.TestCase):
|
||||
"""
|
||||
# Set up the mocks to the tasks.
|
||||
inst = objects.Instance(**powervm.TEST_INSTANCE)
|
||||
inst.system_metadata = {'image_os_distro': 'rhel'}
|
||||
my_flavor = inst.get_flavor()
|
||||
mock_get_flv.return_value = my_flavor
|
||||
mock_cfg_drv.return_value = False
|
||||
@ -374,6 +378,7 @@ class TestPowerVMDriver(test.TestCase):
|
||||
"""
|
||||
# Set up the mocks to the tasks.
|
||||
inst = objects.Instance(**powervm.TEST_INSTANCE)
|
||||
inst.system_metadata = {'image_os_distro': 'rhel'}
|
||||
my_flavor = inst.get_flavor()
|
||||
mock_get_flv.return_value = my_flavor
|
||||
mock_cfg_drv.return_value = False
|
||||
@ -420,6 +425,7 @@ class TestPowerVMDriver(test.TestCase):
|
||||
"""Validates the PowerVM driver operations. Will do a rollback."""
|
||||
# Set up the mocks to the tasks.
|
||||
inst = objects.Instance(**powervm.TEST_INSTANCE)
|
||||
inst.system_metadata = {'image_os_distro': 'rhel'}
|
||||
my_flavor = inst.get_flavor()
|
||||
mock_get_flv.return_value = my_flavor
|
||||
mock_cfg_drv.return_value = False
|
||||
@ -444,6 +450,114 @@ class TestPowerVMDriver(test.TestCase):
|
||||
# Validate the rollbacks were called
|
||||
self.assertEqual(2, self.vol_drv.disconnect_volume.call_count)
|
||||
|
||||
@mock.patch('nova.virt.block_device.DriverVolumeBlockDevice.save')
|
||||
@mock.patch('nova_powervm.virt.powervm.tasks.storage.CreateDiskForImg'
|
||||
'.execute')
|
||||
@mock.patch('nova_powervm.virt.powervm.driver.PowerVMDriver.'
|
||||
'_is_booted_from_volume')
|
||||
@mock.patch('nova_powervm.virt.powervm.tasks.network.PlugMgmtVif.execute')
|
||||
@mock.patch('nova_powervm.virt.powervm.tasks.network.PlugVifs.execute')
|
||||
@mock.patch('nova.virt.configdrive.required_by')
|
||||
@mock.patch('nova.objects.flavor.Flavor.get_by_id')
|
||||
@mock.patch('nova_powervm.virt.powervm.tasks.vm.UpdateIBMiSettings'
|
||||
'.execute')
|
||||
@mock.patch('nova_powervm.virt.powervm.driver.PowerVMDriver.'
|
||||
'_get_boot_connectivity_type')
|
||||
@mock.patch('pypowervm.tasks.power.power_on')
|
||||
def test_spawn_ibmi(
|
||||
self, mock_pwron, mock_boot_conn_type,
|
||||
mock_update_lod_src, mock_get_flv, mock_cfg_drv,
|
||||
mock_plug_vifs, mock_plug_mgmt_vif, mock_boot_from_vol,
|
||||
mock_crt_img, mock_save):
|
||||
"""Validates the PowerVM spawn to create an IBMi server.
|
||||
"""
|
||||
# Set up the mocks to the tasks.
|
||||
inst = objects.Instance(**powervm.TEST_INSTANCE)
|
||||
inst.system_metadata = {'image_os_distro': 'ibmi'}
|
||||
my_flavor = inst.get_flavor()
|
||||
mock_get_flv.return_value = my_flavor
|
||||
mock_cfg_drv.return_value = False
|
||||
mock_boot_from_vol.return_value = True
|
||||
mock_boot_conn_type.return_value = 'vscsi'
|
||||
# Create some fake BDMs
|
||||
block_device_info = self._fake_bdms()
|
||||
image_meta = {}
|
||||
# Invoke the method.
|
||||
self.drv.spawn('context', inst, image_meta,
|
||||
'injected_files', 'admin_password',
|
||||
block_device_info=block_device_info)
|
||||
|
||||
self.assertTrue(mock_boot_from_vol.called)
|
||||
# Since the root device is in the BDMs we do not expect the image disk
|
||||
# to be created.
|
||||
self.assertFalse(mock_crt_img.called)
|
||||
|
||||
# Create LPAR was called
|
||||
self.crt_lpar.assert_called_with(self.apt, self.drv.host_wrapper,
|
||||
inst, my_flavor)
|
||||
|
||||
self.assertTrue(mock_boot_conn_type.called)
|
||||
self.assertTrue(mock_update_lod_src.called)
|
||||
|
||||
# Power on was called
|
||||
self.assertTrue(mock_pwron.called)
|
||||
|
||||
# Check that the connect volume was called
|
||||
self.assertEqual(2, self.vol_drv.connect_volume.call_count)
|
||||
|
||||
# Make sure the BDM save was invoked twice.
|
||||
self.assertEqual(2, mock_save.call_count)
|
||||
|
||||
@mock.patch('nova_powervm.virt.powervm.tasks.storage.'
|
||||
'CreateAndConnectCfgDrive.execute')
|
||||
@mock.patch('nova_powervm.virt.powervm.tasks.storage.ConnectVolume'
|
||||
'.execute')
|
||||
@mock.patch('nova_powervm.virt.powervm.tasks.storage.CreateDiskForImg'
|
||||
'.execute')
|
||||
@mock.patch('nova_powervm.virt.powervm.driver.PowerVMDriver.'
|
||||
'_is_booted_from_volume')
|
||||
@mock.patch('nova_powervm.virt.powervm.tasks.network.PlugMgmtVif.execute')
|
||||
@mock.patch('nova_powervm.virt.powervm.tasks.network.PlugVifs.execute')
|
||||
@mock.patch('nova.virt.configdrive.required_by')
|
||||
@mock.patch('nova.objects.flavor.Flavor.get_by_id')
|
||||
@mock.patch('nova_powervm.virt.powervm.tasks.vm.UpdateIBMiSettings'
|
||||
'.execute')
|
||||
@mock.patch('nova_powervm.virt.powervm.driver.PowerVMDriver.'
|
||||
'_get_boot_connectivity_type')
|
||||
@mock.patch('pypowervm.tasks.power.power_on')
|
||||
def test_spawn_ibmi_without_bdms(
|
||||
self, mock_pwron, mock_boot_conn_type, mock_update_lod_src,
|
||||
mock_get_flv, mock_cfg_drv, mock_plug_vifs,
|
||||
mock_plug_mgmt_vif, mock_boot_from_vol, mock_crt_disk_img,
|
||||
mock_conn_vol, mock_crt_cfg_drv):
|
||||
"""Validates the 'typical' spawn flow for IBMi
|
||||
Perform an UT using an image with local disk, attaching networks
|
||||
and powering on.
|
||||
"""
|
||||
# Set up the mocks to the tasks.
|
||||
inst = objects.Instance(**powervm.TEST_INSTANCE)
|
||||
inst.system_metadata = {'image_os_distro': 'ibmi'}
|
||||
my_flavor = inst.get_flavor()
|
||||
mock_get_flv.return_value = my_flavor
|
||||
mock_cfg_drv.return_value = False
|
||||
mock_boot_from_vol.return_value = False
|
||||
mock_boot_conn_type.return_value = 'vscsi'
|
||||
# Invoke the method.
|
||||
self.drv.spawn('context', inst, mock.Mock(),
|
||||
'injected_files', 'admin_password')
|
||||
|
||||
# Assert the correct tasks were called
|
||||
self.assertTrue(mock_plug_vifs.called)
|
||||
self.assertTrue(mock_plug_mgmt_vif.called)
|
||||
self.assertTrue(mock_crt_disk_img.called)
|
||||
self.crt_lpar.assert_called_with(
|
||||
self.apt, self.drv.host_wrapper, inst, my_flavor)
|
||||
self.assertTrue(mock_update_lod_src.called)
|
||||
self.assertTrue(mock_pwron.called)
|
||||
# Assert that tasks that are not supposed to be called are not called
|
||||
self.assertFalse(mock_conn_vol.called)
|
||||
self.assertFalse(mock_crt_cfg_drv.called)
|
||||
|
||||
@mock.patch('nova_powervm.virt.powervm.disk.localdisk.LocalStorage.'
|
||||
'delete_disks')
|
||||
@mock.patch('nova_powervm.virt.powervm.tasks.storage.CreateDiskForImg.'
|
||||
@ -459,6 +573,7 @@ class TestPowerVMDriver(test.TestCase):
|
||||
"""Validates the rollback if failure occurs on disk create."""
|
||||
# Set up the mocks to the tasks.
|
||||
inst = objects.Instance(**powervm.TEST_INSTANCE)
|
||||
inst.system_metadata = {'image_os_distro': 'rhel'}
|
||||
my_flavor = inst.get_flavor()
|
||||
mock_get_flv.return_value = my_flavor
|
||||
mock_cfg_drv.return_value = False
|
||||
@ -493,6 +608,7 @@ class TestPowerVMDriver(test.TestCase):
|
||||
"""Validates the rollbacks on a volume connect failure."""
|
||||
# Set up the mocks to the tasks.
|
||||
inst = objects.Instance(**powervm.TEST_INSTANCE)
|
||||
inst.system_metadata = {'image_os_distro': 'rhel'}
|
||||
my_flavor = inst.get_flavor()
|
||||
mock_get_flv.return_value = my_flavor
|
||||
mock_cfg_drv.return_value = False
|
||||
|
@ -444,3 +444,21 @@ class TestVM(test.TestCase):
|
||||
self.assertEqual(EXPECTED, vm.norm_mac("1234567890ab"))
|
||||
self.assertEqual(EXPECTED, vm.norm_mac("12:34:56:78:90:AB"))
|
||||
self.assertEqual(EXPECTED, vm.norm_mac("1234567890AB"))
|
||||
|
||||
@mock.patch('pypowervm.tasks.ibmi.update_ibmi_settings')
|
||||
@mock.patch('nova_powervm.virt.powervm.vm.get_instance_wrapper')
|
||||
def test_update_ibmi_settings(self, mock_lparw, mock_ibmi):
|
||||
instance = mock.MagicMock()
|
||||
# Test update load source with vscsi boot
|
||||
boot_type = 'vscsi'
|
||||
vm.update_ibmi_settings(
|
||||
self.apt, instance, 'host-uuid', boot_type)
|
||||
mock_ibmi.assert_called_once_with(
|
||||
self.apt, mock.ANY, 'vscsi')
|
||||
mock_ibmi.reset_mock()
|
||||
# Test update load source with npiv boot
|
||||
boot_type = 'npiv'
|
||||
vm.update_ibmi_settings(
|
||||
self.apt, instance, 'host-uuid', boot_type)
|
||||
mock_ibmi.assert_called_once_with(
|
||||
self.apt, mock.ANY, 'npiv')
|
||||
|
@ -49,6 +49,7 @@ from pypowervm.wrappers import virtual_io_server as pvm_vios
|
||||
|
||||
from nova_powervm.virt.powervm.disk import driver as disk_dvr
|
||||
from nova_powervm.virt.powervm import host as pvm_host
|
||||
from nova_powervm.virt.powervm import image as img
|
||||
from nova_powervm.virt.powervm import live_migration as lpm
|
||||
from nova_powervm.virt.powervm import mgmt
|
||||
from nova_powervm.virt.powervm.tasks import image as tf_img
|
||||
@ -270,6 +271,14 @@ class PowerVMDriver(driver.ComputeDriver):
|
||||
# connection' tasks. This will run all the connections in parallel.
|
||||
flow_spawn.add(stg_ftsk)
|
||||
|
||||
# Update load source of IBMi VM
|
||||
distro = instance.system_metadata.get('image_os_distro', '')
|
||||
if distro.lower() == img.OSDistro.OS400:
|
||||
boot_type = self._get_boot_connectivity_type(
|
||||
context, bdms, block_device_info)
|
||||
flow_spawn.add(tf_vm.UpdateIBMiSettings(
|
||||
self.adapter, instance, self.host_uuid, boot_type))
|
||||
|
||||
# Last step is to power on the system.
|
||||
flow_spawn.add(tf_vm.PowerOn(self.adapter, self.host_uuid, instance))
|
||||
|
||||
@ -1321,6 +1330,30 @@ class PowerVMDriver(driver.ComputeDriver):
|
||||
return vol_cls(self.adapter, self.host_uuid,
|
||||
instance, conn_info, stg_ftsk=stg_ftsk)
|
||||
|
||||
def _get_boot_connectivity_type(self, context, bdms, block_device_info):
|
||||
"""Get connectivity information for the instance.
|
||||
|
||||
:param context: security context
|
||||
:param bdms: The BDMs for the operation. If boot volume of
|
||||
the instance is ssp lu or local disk, the bdms is None.
|
||||
:param block_device_info: Instance volume block device info.
|
||||
:return: Returns the boot connectivity type,
|
||||
If boot volume is a npiv volume, returns 'npiv'
|
||||
Otherwise, return 'vscsi'.
|
||||
"""
|
||||
# Set default boot_conn_type as 'vscsi'
|
||||
boot_conn_type = 'vscsi'
|
||||
if self._is_booted_from_volume(block_device_info) and bdms is not None:
|
||||
for bdm in bdms:
|
||||
if bdm.get('boot_index') == 0:
|
||||
conn_info = bdm.get('connection_info')
|
||||
connectivity_type = conn_info['data']['connection-type']
|
||||
boot_conn_type = ('vscsi' if connectivity_type ==
|
||||
'pv_vscsi' else connectivity_type)
|
||||
return boot_conn_type
|
||||
else:
|
||||
return boot_conn_type
|
||||
|
||||
|
||||
def _inst_dict(input_dict):
|
||||
"""Builds a dictionary with instances as values based on the input classes.
|
||||
|
@ -19,6 +19,17 @@
|
||||
from nova import utils
|
||||
|
||||
|
||||
class OSDistro(object):
|
||||
"""Mirror of image os distro.Enum."""
|
||||
AIX = 'aix'
|
||||
RHEL = 'rhel'
|
||||
OS400 = 'ibmi'
|
||||
SLES = 'sles'
|
||||
UBUNTU = 'ubuntu'
|
||||
UNKNOWN = 'Unknown'
|
||||
ALL_VALUES = (AIX, RHEL, OS400, SLES, UBUNTU, UNKNOWN)
|
||||
|
||||
|
||||
def stream_blockdev_to_glance(context, image_api, image_id, metadata, devpath):
|
||||
"""Stream the entire contents of a block device to a glance image.
|
||||
|
||||
|
@ -165,3 +165,28 @@ class Delete(task.Task):
|
||||
def execute(self):
|
||||
LOG.info(_LI('Deleting instance %s from system.'), self.instance.name)
|
||||
vm.dlt_lpar(self.adapter, self.lpar_uuid)
|
||||
|
||||
|
||||
class UpdateIBMiSettings(task.Task):
|
||||
"""The task to update settings of an ibmi instance."""
|
||||
|
||||
def __init__(self, adapter, instance, host_uuid, boot_type):
|
||||
"""Create the Task to update settings of the IBMi VM.
|
||||
|
||||
:param adapter: The adapter for the pypowervm API.
|
||||
:param instance: The nova instance.
|
||||
:param host_uuid: The host's PowerVM UUID.
|
||||
:param boot_type: The boot type of the instance.
|
||||
"""
|
||||
super(UpdateIBMiSettings, self).__init__(
|
||||
name='update_ibmi_settings')
|
||||
self.adapter = adapter
|
||||
self.instance = instance
|
||||
self.host_uuid = host_uuid
|
||||
self.boot_type = boot_type
|
||||
|
||||
def execute(self):
|
||||
LOG.info(_LI('Update settings of instance %s.'),
|
||||
self.instance.name)
|
||||
vm.update_ibmi_settings(
|
||||
self.adapter, self.instance, self.host_uuid, self.boot_type)
|
||||
|
@ -27,6 +27,7 @@ from nova.virt import hardware
|
||||
from pypowervm import exceptions as pvm_exc
|
||||
from pypowervm.helpers import log_helper as pvm_log
|
||||
from pypowervm.tasks import cna
|
||||
from pypowervm.tasks import ibmi
|
||||
from pypowervm.tasks import power
|
||||
from pypowervm.tasks import vterm
|
||||
from pypowervm.utils import lpar_builder as lpar_bldr
|
||||
@ -644,3 +645,16 @@ def norm_mac(mac):
|
||||
"""
|
||||
mac = mac.lower().replace(':', '')
|
||||
return ':'.join(mac[i:i + 2] for i in range(0, len(mac), 2))
|
||||
|
||||
|
||||
def update_ibmi_settings(adapter, instance, host_uuid, boot_type):
|
||||
"""Update settings of IBMi VMs on the instance.
|
||||
|
||||
:param adapter: The pypowervm adapter.
|
||||
:param instance: The nova instance.
|
||||
:param host_uuid: The host system UUID.
|
||||
:param boot_type: The boot connectivity type of the instance.
|
||||
"""
|
||||
lpar_wrap = get_instance_wrapper(adapter, instance, host_uuid)
|
||||
entry = ibmi.update_ibmi_settings(adapter, lpar_wrap, boot_type)
|
||||
entry.update()
|
||||
|
Loading…
Reference in New Issue
Block a user