Merge "Update settings during deploying an IBMi VM."

This commit is contained in:
Jenkins 2015-10-12 14:11:55 +00:00 committed by Gerrit Code Review
commit f2d4c27d27
6 changed files with 217 additions and 0 deletions

View File

@ -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

View File

@ -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')

View File

@ -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.

View File

@ -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.

View File

@ -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)

View File

@ -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()