diff options
-rw-r--r-- | nova/tests/test_powervm.py | 12 | ||||
-rw-r--r-- | nova/virt/powervm/driver.py | 5 | ||||
-rw-r--r-- | nova/virt/powervm/operator.py | 56 |
3 files changed, 67 insertions, 6 deletions
diff --git a/nova/tests/test_powervm.py b/nova/tests/test_powervm.py index 68795e22f..ad0e4539c 100644 --- a/nova/tests/test_powervm.py +++ b/nova/tests/test_powervm.py @@ -23,7 +23,9 @@ from nova import db from nova import test from nova.compute import power_state +from nova.network import model as network_model from nova.openstack.common import log as logging +from nova.tests import fake_network_cache_model from nova.virt import images from nova.virt.powervm import blockdev as powervm_blockdev from nova.virt.powervm import common @@ -156,8 +158,11 @@ class PowerVMDriverTestCase(test.TestCase): self.stubs.Set(images, 'fetch_to_raw', fake_image_fetch_to_raw) image_meta = {} image_meta['id'] = '666' + fake_net_info = network_model.NetworkInfo([ + fake_network_cache_model.new_vif()]) self.powervm_connection.spawn(context.get_admin_context(), - self.instance, image_meta, 's3cr3t', []) + self.instance, image_meta, [], 's3cr3t', + fake_net_info) state = self.powervm_connection.get_info(self.instance)['state'] self.assertEqual(state, power_state.RUNNING) @@ -176,12 +181,13 @@ class PowerVMDriverTestCase(test.TestCase): self.stubs.Set( self.powervm_connection._powervm, '_cleanup', lambda *x, **y: raise_(Exception('This should be logged.'))) - + fake_net_info = network_model.NetworkInfo([ + fake_network_cache_model.new_vif()]) self.assertRaises(exception.PowerVMImageCreationFailed, self.powervm_connection.spawn, context.get_admin_context(), self.instance, - {'id': 'ANY_ID'}, 's3cr3t', []) + {'id': 'ANY_ID'}, [], 's3cr3t', fake_net_info) def test_destroy(self): self.powervm_connection.destroy(self.instance, None) diff --git a/nova/virt/powervm/driver.py b/nova/virt/powervm/driver.py index 6679c38f9..baf9bf12d 100644 --- a/nova/virt/powervm/driver.py +++ b/nova/virt/powervm/driver.py @@ -88,10 +88,13 @@ class PowerVMDriver(driver.ComputeDriver): def plug_vifs(self, instance, network_info): pass + def macs_for_instance(self, instance): + return self._powervm.macs_for_instance(instance) + def spawn(self, context, instance, image_meta, injected_files, admin_password, network_info=None, block_device_info=None): """Create a new instance/VM/domain on powerVM.""" - self._powervm.spawn(context, instance, image_meta['id']) + self._powervm.spawn(context, instance, image_meta['id'], network_info) def destroy(self, instance, network_info, block_device_info=None, destroy_disks=True): diff --git a/nova/virt/powervm/operator.py b/nova/virt/powervm/operator.py index 87da30a14..c5c2b5f04 100644 --- a/nova/virt/powervm/operator.py +++ b/nova/virt/powervm/operator.py @@ -15,6 +15,7 @@ # under the License. import decimal +import random import re import time @@ -170,7 +171,7 @@ class PowerVMOperator(object): self._host_stats = data - def spawn(self, context, instance, image_id): + def spawn(self, context, instance, image_id, network_info): def _create_lpar_instance(instance): host_stats = self.get_host_stats(refresh=True) inst_name = instance['name'] @@ -201,9 +202,21 @@ class PowerVMOperator(object): try: # Network + # To ensure the MAC address on the guest matches the + # generated value, pull the first 10 characters off the + # MAC address for the mac_base_value parameter and then + # get the integer value of the final 2 characters as the + # slot_id parameter + mac = network_info[0]['address'] + mac_base_value = (mac[:-2]).replace(':', '') eth_id = self._operator.get_virtual_eth_adapter_id() + slot_id = int(mac[-2:], 16) + virtual_eth_adapters = ('%(slot_id)s/0/%(eth_id)s//0/0' % + locals()) # LPAR configuration data + # max_virtual_slots is hardcoded to 64 since we generate a MAC + # address that must be placed in slots 32 - 64 lpar_inst = LPAR.LPAR( name=inst_name, lpar_env='aixlinux', min_mem=mem_min, desired_mem=mem, @@ -213,10 +226,14 @@ class PowerVMOperator(object): min_proc_units=cpus_units_min, desired_proc_units=cpus_units, max_proc_units=cpus_max, - virtual_eth_adapters='4/0/%s//0/0' % eth_id) + virtual_eth_mac_base_value=mac_base_value, + max_virtual_slots=64, + virtual_eth_adapters=virtual_eth_adapters) LOG.debug(_("Creating LPAR instance '%s'") % instance['name']) self._operator.create_lpar(lpar_inst) + #TODO(mjfork) capture the error and handle the error when the MAC + # prefix already exists on the system (1 in 2^28) except nova_exception.ProcessExecutionError: LOG.exception(_("LPAR instance '%s' creation failed") % instance['name']) @@ -345,6 +362,9 @@ class PowerVMOperator(object): def power_on(self, instance_name): self._operator.start_lpar(instance_name) + def macs_for_instance(self, instance): + return self._operator.macs_for_instance(instance) + class BaseOperator(object): """Base operator for IVM and HMC managed systems.""" @@ -573,6 +593,9 @@ class BaseOperator(object): self._connection, command, check_exit_code=check_exit_code) return stdout.read().splitlines() + def macs_for_instance(self, instance): + pass + class IVMOperator(BaseOperator): """Integrated Virtualization Manager (IVM) Operator. @@ -583,3 +606,32 @@ class IVMOperator(BaseOperator): def __init__(self, ivm_connection): self.command = command.IVMCommand() BaseOperator.__init__(self, ivm_connection) + + def macs_for_instance(self, instance): + """Generates set of valid MAC addresses for an IVM instance.""" + # NOTE(vish): We would prefer to use 0xfe here to ensure that linux + # bridge mac addresses don't change, but it appears to + # conflict with libvirt, so we use the next highest octet + # that has the unicast and locally administered bits set + # properly: 0xfa. + # Discussion: https://bugs.launchpad.net/nova/+bug/921838 + # NOTE(mjfork): For IVM-based PowerVM, we cannot directly set a MAC + # address on an LPAR, but rather need to construct one + # that can be used. Retain the 0xfe as noted above, + # but ensure the final 3 hex values represent a value + # between 32 and 64 so we can assign as the slot id on + # the system. + # FA:xx:xx:xx:x0:[32-64] + + macs = set() + mac_base = [0xfa, + random.randint(0x00, 0xff), + random.randint(0x00, 0xff), + random.randint(0x00, 0xff), + random.randint(0x00, 0xff) & 0xf0, + random.randint(0x00, 0x00)] + for n in range(32, 64): + mac_base[5] = n + macs.add(':'.join(map(lambda x: "%02x" % x, mac_base))) + + return macs |