hypervisor-supplied-nics support in PowerVM
PowerVM does not allow MAC addresses to be directly set on LPARs. Instead, use the hypervisor-supplied-nics feature to generate MAC addresses we can ensure are provisioned correctly. blueprint powervm-compute-resize-migration Change-Id: Idad7f03d9fd61970912ec1a6978fc0af56309df4
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user