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. # Set up the mocks to the tasks.
inst = objects.Instance(**powervm.TEST_INSTANCE) inst = objects.Instance(**powervm.TEST_INSTANCE)
inst.system_metadata = {'image_os_distro': 'rhel'}
my_flavor = inst.get_flavor() my_flavor = inst.get_flavor()
mock_get_flv.return_value = my_flavor mock_get_flv.return_value = my_flavor
mock_cfg_drv.return_value = False mock_cfg_drv.return_value = False
@ -222,6 +223,7 @@ class TestPowerVMDriver(test.TestCase):
"""Validates the PowerVM spawn w/ config drive operations.""" """Validates the PowerVM spawn w/ config drive operations."""
# Set up the mocks to the tasks. # Set up the mocks to the tasks.
inst = objects.Instance(**powervm.TEST_INSTANCE) inst = objects.Instance(**powervm.TEST_INSTANCE)
inst.system_metadata = {'image_os_distro': 'rhel'}
my_flavor = inst.get_flavor() my_flavor = inst.get_flavor()
mock_get_flv.return_value = my_flavor mock_get_flv.return_value = my_flavor
mock_cfg_drv.return_value = True mock_cfg_drv.return_value = True
@ -263,6 +265,7 @@ class TestPowerVMDriver(test.TestCase):
""" """
# Set up the mocks to the tasks. # Set up the mocks to the tasks.
inst = objects.Instance(**powervm.TEST_INSTANCE) inst = objects.Instance(**powervm.TEST_INSTANCE)
inst.system_metadata = {'image_os_distro': 'rhel'}
my_flavor = inst.get_flavor() my_flavor = inst.get_flavor()
mock_get_flv.return_value = my_flavor mock_get_flv.return_value = my_flavor
mock_cfg_drv.return_value = False mock_cfg_drv.return_value = False
@ -325,6 +328,7 @@ class TestPowerVMDriver(test.TestCase):
""" """
# Set up the mocks to the tasks. # Set up the mocks to the tasks.
inst = objects.Instance(**powervm.TEST_INSTANCE) inst = objects.Instance(**powervm.TEST_INSTANCE)
inst.system_metadata = {'image_os_distro': 'rhel'}
my_flavor = inst.get_flavor() my_flavor = inst.get_flavor()
mock_get_flv.return_value = my_flavor mock_get_flv.return_value = my_flavor
mock_cfg_drv.return_value = False mock_cfg_drv.return_value = False
@ -374,6 +378,7 @@ class TestPowerVMDriver(test.TestCase):
""" """
# Set up the mocks to the tasks. # Set up the mocks to the tasks.
inst = objects.Instance(**powervm.TEST_INSTANCE) inst = objects.Instance(**powervm.TEST_INSTANCE)
inst.system_metadata = {'image_os_distro': 'rhel'}
my_flavor = inst.get_flavor() my_flavor = inst.get_flavor()
mock_get_flv.return_value = my_flavor mock_get_flv.return_value = my_flavor
mock_cfg_drv.return_value = False mock_cfg_drv.return_value = False
@ -420,6 +425,7 @@ class TestPowerVMDriver(test.TestCase):
"""Validates the PowerVM driver operations. Will do a rollback.""" """Validates the PowerVM driver operations. Will do a rollback."""
# Set up the mocks to the tasks. # Set up the mocks to the tasks.
inst = objects.Instance(**powervm.TEST_INSTANCE) inst = objects.Instance(**powervm.TEST_INSTANCE)
inst.system_metadata = {'image_os_distro': 'rhel'}
my_flavor = inst.get_flavor() my_flavor = inst.get_flavor()
mock_get_flv.return_value = my_flavor mock_get_flv.return_value = my_flavor
mock_cfg_drv.return_value = False mock_cfg_drv.return_value = False
@ -444,6 +450,114 @@ class TestPowerVMDriver(test.TestCase):
# Validate the rollbacks were called # Validate the rollbacks were called
self.assertEqual(2, self.vol_drv.disconnect_volume.call_count) 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.' @mock.patch('nova_powervm.virt.powervm.disk.localdisk.LocalStorage.'
'delete_disks') 'delete_disks')
@mock.patch('nova_powervm.virt.powervm.tasks.storage.CreateDiskForImg.' @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.""" """Validates the rollback if failure occurs on disk create."""
# Set up the mocks to the tasks. # Set up the mocks to the tasks.
inst = objects.Instance(**powervm.TEST_INSTANCE) inst = objects.Instance(**powervm.TEST_INSTANCE)
inst.system_metadata = {'image_os_distro': 'rhel'}
my_flavor = inst.get_flavor() my_flavor = inst.get_flavor()
mock_get_flv.return_value = my_flavor mock_get_flv.return_value = my_flavor
mock_cfg_drv.return_value = False mock_cfg_drv.return_value = False
@ -493,6 +608,7 @@ class TestPowerVMDriver(test.TestCase):
"""Validates the rollbacks on a volume connect failure.""" """Validates the rollbacks on a volume connect failure."""
# Set up the mocks to the tasks. # Set up the mocks to the tasks.
inst = objects.Instance(**powervm.TEST_INSTANCE) inst = objects.Instance(**powervm.TEST_INSTANCE)
inst.system_metadata = {'image_os_distro': 'rhel'}
my_flavor = inst.get_flavor() my_flavor = inst.get_flavor()
mock_get_flv.return_value = my_flavor mock_get_flv.return_value = my_flavor
mock_cfg_drv.return_value = False 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("1234567890ab"))
self.assertEqual(EXPECTED, vm.norm_mac("12:34:56:78:90:AB")) self.assertEqual(EXPECTED, vm.norm_mac("12:34:56:78:90:AB"))
self.assertEqual(EXPECTED, vm.norm_mac("1234567890AB")) 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.disk import driver as disk_dvr
from nova_powervm.virt.powervm import host as pvm_host 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 live_migration as lpm
from nova_powervm.virt.powervm import mgmt from nova_powervm.virt.powervm import mgmt
from nova_powervm.virt.powervm.tasks import image as tf_img 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. # connection' tasks. This will run all the connections in parallel.
flow_spawn.add(stg_ftsk) 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. # Last step is to power on the system.
flow_spawn.add(tf_vm.PowerOn(self.adapter, self.host_uuid, instance)) 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, return vol_cls(self.adapter, self.host_uuid,
instance, conn_info, stg_ftsk=stg_ftsk) 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): def _inst_dict(input_dict):
"""Builds a dictionary with instances as values based on the input classes. """Builds a dictionary with instances as values based on the input classes.

View File

@ -19,6 +19,17 @@
from nova import utils 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): def stream_blockdev_to_glance(context, image_api, image_id, metadata, devpath):
"""Stream the entire contents of a block device to a glance image. """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): def execute(self):
LOG.info(_LI('Deleting instance %s from system.'), self.instance.name) LOG.info(_LI('Deleting instance %s from system.'), self.instance.name)
vm.dlt_lpar(self.adapter, self.lpar_uuid) 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 import exceptions as pvm_exc
from pypowervm.helpers import log_helper as pvm_log from pypowervm.helpers import log_helper as pvm_log
from pypowervm.tasks import cna from pypowervm.tasks import cna
from pypowervm.tasks import ibmi
from pypowervm.tasks import power from pypowervm.tasks import power
from pypowervm.tasks import vterm from pypowervm.tasks import vterm
from pypowervm.utils import lpar_builder as lpar_bldr from pypowervm.utils import lpar_builder as lpar_bldr
@ -644,3 +645,16 @@ def norm_mac(mac):
""" """
mac = mac.lower().replace(':', '') mac = mac.lower().replace(':', '')
return ':'.join(mac[i:i + 2] for i in range(0, len(mac), 2)) 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()