Plug tenant networks once provision is completed
Change-Id: I34f56f6e42b2b8e70dcaa7576b8d0106e6dffae8
This commit is contained in:
parent
8a28fc7881
commit
774898ed84
|
@ -73,6 +73,25 @@ class PXEBoot(pxe.PXEBoot):
|
|||
new_port.create()
|
||||
return port['port']['fixed_ips'][0]['ip_address']
|
||||
|
||||
def _plug_tenant_networks(self, task, **kwargs):
|
||||
ports = objects.Port.list_by_node_id(task.context, task.node.id)
|
||||
for port in ports:
|
||||
pargs = port['extra']
|
||||
if pargs.get('type') == "tenant" and pargs['state'] == "DOWN":
|
||||
try:
|
||||
common.add_vnic(
|
||||
task, pargs['vif_port_id'], port['address'],
|
||||
pargs['seg_id'], pargs['pxe'])
|
||||
except imcsdk.ImcException:
|
||||
port.extra = {x: pargs[x] for x in pargs}
|
||||
port.extra['state'] = "ERROR"
|
||||
LOG.error("ADDING VNIC FAILED")
|
||||
else:
|
||||
port.extra = {x: pargs[x] for x in pargs}
|
||||
port.extra['state'] = "UP"
|
||||
LOG.info("ADDING VNIC SUCCESSFUL")
|
||||
port.save()
|
||||
|
||||
def _unplug_provisioning(self, task, **kwargs):
|
||||
LOG.debug("Unplugging the provisioning!")
|
||||
if task.node.power_state != states.POWER_ON:
|
||||
|
@ -87,6 +106,17 @@ class PXEBoot(pxe.PXEBoot):
|
|||
client.delete_port(port['extra']['vif_port_id'])
|
||||
port.destroy()
|
||||
|
||||
def _unplug_tenant_networks(self, task, **kwargs):
|
||||
ports = objects.Port.list_by_node_id(task.context, task.node.id)
|
||||
for port in ports:
|
||||
pargs = port['extra']
|
||||
if pargs.get('type') == "tenant" and pargs['state'] == "UP":
|
||||
common.delete_vnic(task, port['extra']['vif_port_id'])
|
||||
port.extra = {x: pargs[x] for x in pargs}
|
||||
port.extra['state'] = "DOWN"
|
||||
port.save()
|
||||
LOG.info("DELETEING VNIC SUCCESSFUL")
|
||||
|
||||
def validate(self, task):
|
||||
pass
|
||||
|
||||
|
@ -133,8 +163,14 @@ class PXEBoot(pxe.PXEBoot):
|
|||
super(PXEBoot, self).prepare_instance(task)
|
||||
if deploy_utils.get_boot_option(task.node) == "local":
|
||||
self._unplug_provisioning(task)
|
||||
self._plug_tenant_networks(task)
|
||||
|
||||
def clean_up_ramdisk(self, task):
|
||||
super(PXEBoot, self).clean_up_ramdisk(task)
|
||||
self._unplug_provisioning(task)
|
||||
task.ports = objects.Port.list_by_node_id(task.context, task.node.id)
|
||||
|
||||
def clean_up_instance(self, task):
|
||||
super(PXEBoot, self).clean_up_instance(task)
|
||||
self._unplug_tenant_networks(task)
|
||||
task.ports = objects.Port.list_by_node_id(task.context, task.node.id)
|
||||
|
|
|
@ -17,15 +17,11 @@ from oslo_log import log as logging
|
|||
from oslo_utils import importutils
|
||||
|
||||
from ironic.common import exception
|
||||
from ironic.common import states
|
||||
from ironic.conductor import task_manager
|
||||
from ironic.conductor import utils as manager_utils
|
||||
from ironic.drivers import base
|
||||
from ironic.drivers.modules import iscsi_deploy
|
||||
from ironic import objects
|
||||
|
||||
from cisco_ironic_contrib.ironic.cimc import common
|
||||
|
||||
imcsdk = importutils.try_import('ImcSdk')
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
@ -37,53 +33,28 @@ class CIMCPXEVendorPassthru(iscsi_deploy.VendorPassthru):
|
|||
@base.passthru(['POST'], async=True)
|
||||
@task_manager.require_exclusive_lock
|
||||
def add_vnic(self, task, **kwargs):
|
||||
|
||||
LOG.info("ENSURING NODE ON FOR VNIC ADDITION!")
|
||||
if task.node.power_state != states.POWER_ON:
|
||||
manager_utils.node_power_action(task, states.REBOOT)
|
||||
|
||||
LOG.info("ADDING PORT TO IRONIC DB")
|
||||
new_port = objects.Port(
|
||||
task.context, node_id=task.node.id, address=kwargs['mac'],
|
||||
extra={"vif_port_id": kwargs['uuid'],
|
||||
"type": "tenant", "state": "DOWN"})
|
||||
extra={"vif_port_id": kwargs['uuid'], "seg_id": kwargs['vlan'],
|
||||
"pxe": kwargs['pxe'], "type": "tenant", "state": "DOWN"})
|
||||
|
||||
new_port.create()
|
||||
|
||||
try:
|
||||
LOG.info("ADDING VNIC TO CIMC")
|
||||
common.add_vnic(
|
||||
task, kwargs['uuid'], kwargs['mac'],
|
||||
kwargs['vlan'], kwargs['pxe'])
|
||||
except imcsdk.ImcException:
|
||||
new_port.extra = {"vif_port_id": kwargs['uuid'], "type": "tenant",
|
||||
"state": "ERROR"}
|
||||
LOG.error("ADDING VNIC FAILED")
|
||||
else:
|
||||
new_port.extra = {"vif_port_id": kwargs['uuid'], "type": "tenant",
|
||||
"state": "UP"}
|
||||
LOG.info("ADDING VNIC SUCCESSFUL")
|
||||
new_port.save()
|
||||
|
||||
@base.passthru(['POST'], async=True)
|
||||
@task_manager.require_exclusive_lock
|
||||
def delete_vnic(self, task, **kwargs):
|
||||
|
||||
# Ensure Node is powered on before changing VNIC settings
|
||||
if task.node.power_state != states.POWER_ON:
|
||||
manager_utils.node_power_action(task, states.REBOOT)
|
||||
|
||||
# Use neutron UUID to get port from ironic DB
|
||||
ports = objects.Port.list_by_node_id(task.context, task.node.id)
|
||||
todelete = None
|
||||
for port in ports:
|
||||
if port['extra']['vif_port_id'] == kwargs['uuid']:
|
||||
if (port['extra']['vif_port_id'] == kwargs['uuid'] and
|
||||
port['extra']['state'] == "DOWN"):
|
||||
todelete = port
|
||||
break
|
||||
|
||||
if todelete is None:
|
||||
raise exception.NotFound("No port matched uuid provided")
|
||||
# Delete vnic from server
|
||||
common.delete_vnic(task, kwargs['uuid'])
|
||||
# Delete port from ironic port DB
|
||||
|
||||
# Delete from DB
|
||||
todelete.destroy()
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
from oslo_service import loopingcall
|
||||
|
||||
from nova.network.neutronv2 import api as neutron
|
||||
from nova.virt.ironic import driver as ironic_driver
|
||||
|
@ -28,11 +27,6 @@ CONF = cfg.CONF
|
|||
class CiscoIronicDriver(ironic_driver.IronicDriver):
|
||||
"""Hypervisor driver for Ironic - bare metal provisioning."""
|
||||
|
||||
def _check_for_vnic_creation(self, ironicclient, address):
|
||||
port = self.ironicclient.call("port.get_by_address", address)
|
||||
if port.extra['state'] == "UP":
|
||||
raise loopingcall.LoopingCallDone()
|
||||
|
||||
def macs_for_instance(self, instance):
|
||||
return None
|
||||
|
||||
|
@ -50,11 +44,6 @@ class CiscoIronicDriver(ironic_driver.IronicDriver):
|
|||
}
|
||||
self.ironicclient.call("node.vendor_passthru", node_uuid,
|
||||
"add_vnic", args=net_info)
|
||||
|
||||
timer = loopingcall.FixedIntervalLoopingCall(
|
||||
self._check_for_vnic_creation,
|
||||
self.ironicclient, vif['address'])
|
||||
timer.start(interval=5).wait()
|
||||
LOG.debug('Plug VIFs successful for instance', instance=instance)
|
||||
|
||||
def _unplug_vifs(self, node, instance, network_info):
|
||||
|
|
|
@ -17,14 +17,10 @@ import mock
|
|||
from oslo_utils import importutils
|
||||
|
||||
from ironic.common import exception
|
||||
from ironic.common import states
|
||||
from ironic.conductor import task_manager
|
||||
from ironic.conductor import utils as manager_utils
|
||||
from ironic import objects
|
||||
from ironic.tests.unit.drivers.modules.cimc import test_common
|
||||
|
||||
from cisco_ironic_contrib.ironic.cimc import common
|
||||
|
||||
imcsdk = importutils.try_import('ImcSdk')
|
||||
|
||||
TEST_DATA = {
|
||||
|
@ -37,105 +33,47 @@ TEST_DATA = {
|
|||
|
||||
class CIMCPXEVendorPassthruTestCase(test_common.CIMCBaseTestCase):
|
||||
|
||||
@mock.patch.object(common, 'add_vnic', autospec=True)
|
||||
@mock.patch.object(manager_utils, 'node_power_action', autospec=True)
|
||||
@mock.patch.object(objects, 'Port', autospec=True)
|
||||
def _test_add_vnic(self, mock_port, mock_power_action,
|
||||
mock_add_vnic, initial_state=states.POWER_OFF):
|
||||
def test_add_vnic(self, mock_port):
|
||||
with task_manager.acquire(self.context, self.node.uuid,
|
||||
shared=False) as task:
|
||||
task.node.power_state = initial_state
|
||||
mock_port.return_value.extra = {}
|
||||
|
||||
task.driver.vendor.add_vnic(task, **TEST_DATA)
|
||||
|
||||
if initial_state != states.POWER_ON:
|
||||
mock_power_action.assert_called_once_with(task, states.REBOOT)
|
||||
else:
|
||||
self.assertFalse(mock_power_action.called)
|
||||
|
||||
mock_port.assert_called_once_with(
|
||||
task.context, node_id=task.node.id, address=TEST_DATA['mac'],
|
||||
extra={"type": "tenant", "state": "DOWN",
|
||||
"vif_port_id": TEST_DATA['uuid']})
|
||||
extra={"type": "tenant", "state": "DOWN", 'seg_id': 600,
|
||||
'pxe': False, "vif_port_id": TEST_DATA['uuid']})
|
||||
|
||||
mock_port.return_value.create.assert_called_once_with()
|
||||
|
||||
mock_add_vnic.assert_called_once_with(
|
||||
task, TEST_DATA['uuid'], TEST_DATA['mac'],
|
||||
TEST_DATA['vlan'], TEST_DATA['pxe'])
|
||||
|
||||
self.assertEqual(mock_port.return_value.extra['state'],
|
||||
"UP")
|
||||
|
||||
mock_port.return_value.save.assert_called_once_with()
|
||||
|
||||
def test_add_vnic_node_off(self):
|
||||
self._test_add_vnic()
|
||||
|
||||
def test_add_vnic_node_already_on(self):
|
||||
self._test_add_vnic(initial_state=states.POWER_ON)
|
||||
|
||||
@mock.patch.object(common, 'add_vnic', autospec=True)
|
||||
@mock.patch.object(objects, 'Port', autospec=True)
|
||||
def test_add_vnic_fail(self, mock_port, mock_add_vnic):
|
||||
def test_delete_vnic(self, mock_port):
|
||||
with task_manager.acquire(self.context, self.node.uuid,
|
||||
shared=False) as task:
|
||||
task.node.power_state = states.POWER_ON
|
||||
mock_port.return_value.extra = {}
|
||||
|
||||
mock_add_vnic.side_effect = imcsdk.ImcException("Boom")
|
||||
|
||||
task.driver.vendor.add_vnic(task, **TEST_DATA)
|
||||
|
||||
self.assertEqual(mock_port.return_value.extra['state'],
|
||||
"ERROR")
|
||||
|
||||
mock_port.return_value.save.assert_called_once_with()
|
||||
|
||||
@mock.patch.object(common, 'delete_vnic', autospec=True)
|
||||
@mock.patch.object(manager_utils, 'node_power_action', autospec=True)
|
||||
@mock.patch.object(objects, 'Port', autospec=True)
|
||||
def _test_delete_vnic(self, mock_port, mock_power_action, mock_delete_vnic,
|
||||
initial_state=states.POWER_OFF):
|
||||
with task_manager.acquire(self.context, self.node.uuid,
|
||||
shared=False) as task:
|
||||
task.node.power_state = initial_state
|
||||
|
||||
port1 = mock.MagicMock()
|
||||
port1.__getitem__.return_value = {'vif_port_id': "1"}
|
||||
port1.__getitem__.return_value = {'vif_port_id': "1",
|
||||
'state': 'DOWN'}
|
||||
|
||||
port2 = mock.MagicMock()
|
||||
port2.__getitem__.return_value = {'vif_port_id': "2"}
|
||||
port2.__getitem__.return_value = {'vif_port_id': "2",
|
||||
'state': 'DOWN'}
|
||||
|
||||
port3 = mock.MagicMock()
|
||||
port3.__getitem__.return_value = {'vif_port_id': "3"}
|
||||
port3.__getitem__.return_value = {'vif_port_id': "3",
|
||||
'state': 'DOWN'}
|
||||
|
||||
mock_port.list_by_node_id.return_value = [port1, port2, port3]
|
||||
|
||||
task.driver.vendor.delete_vnic(task, uuid="1")
|
||||
|
||||
if initial_state != states.POWER_ON:
|
||||
mock_power_action.assert_called_once_with(task, states.REBOOT)
|
||||
else:
|
||||
self.assertFalse(mock_power_action.called)
|
||||
|
||||
mock_port.list_by_node_id.assert_called_with(
|
||||
task.context, task.node.id)
|
||||
|
||||
mock_delete_vnic.assert_called_once_with(task, "1")
|
||||
|
||||
def test_delete_vnic_node_off(self):
|
||||
self._test_delete_vnic()
|
||||
|
||||
def test_delete_vnic_node_already_on(self):
|
||||
self._test_delete_vnic(initial_state=states.POWER_ON)
|
||||
port1.destroy.assert_called_once_with()
|
||||
|
||||
@mock.patch.object(objects, 'Port', autospec=True)
|
||||
def test_delete_vnic_port_not_found(self, mock_port):
|
||||
with task_manager.acquire(self.context, self.node.uuid,
|
||||
shared=False) as task:
|
||||
task.node.power_state = states.POWER_ON
|
||||
mock_port.list_by_node_id.return_value = []
|
||||
|
||||
self.assertRaises(exception.NotFound,
|
||||
|
|
|
@ -70,8 +70,7 @@ class CiscoIronicDriverTestCase(test.NoDBTestCase):
|
|||
|
||||
@mock.patch.object(neutron, 'get_client')
|
||||
@mock.patch.object(FAKE_CLIENT.node, 'vendor_passthru')
|
||||
@mock.patch.object(FAKE_CLIENT.port, 'get_by_address')
|
||||
def test_plug_vifs_with_port(self, mock_address, mock_vp, mock_neutron):
|
||||
def test_plug_vifs_with_port(self, mock_vp, mock_neutron):
|
||||
node = ironic_utils.get_test_node()
|
||||
instance = fake_instance.fake_instance_obj(self.ctx,
|
||||
node=node.uuid)
|
||||
|
@ -79,8 +78,6 @@ class CiscoIronicDriverTestCase(test.NoDBTestCase):
|
|||
mock_neutron.return_value.show_network.return_value = {
|
||||
'network': {
|
||||
'provider:segmentation_id': 600}}
|
||||
mock_address.return_value = ironic_utils.get_test_port(
|
||||
extra={'state': 'UP'})
|
||||
|
||||
self.driver._plug_vifs(node, instance, network_info)
|
||||
expected_info = {
|
||||
|
@ -91,20 +88,16 @@ class CiscoIronicDriverTestCase(test.NoDBTestCase):
|
|||
}
|
||||
mock_vp.assert_called_once_with(node.uuid, 'add_vnic',
|
||||
args=expected_info)
|
||||
mock_address.assert_called_once_with(network_info[0]['address'])
|
||||
|
||||
@mock.patch.object(neutron, 'get_client')
|
||||
@mock.patch.object(FAKE_CLIENT.node, 'vendor_passthru')
|
||||
@mock.patch.object(FAKE_CLIENT.port, 'get_by_address')
|
||||
def test_plug_vifs_no_network_info(self, mock_address, mock_vp,
|
||||
mock_neutron):
|
||||
def test_plug_vifs_no_network_info(self, mock_vp, mock_neutron):
|
||||
node = ironic_utils.get_test_node()
|
||||
instance = fake_instance.fake_instance_obj(self.ctx,
|
||||
node=node.uuid)
|
||||
network_info = []
|
||||
self.driver._plug_vifs(node, instance, network_info)
|
||||
self.assertFalse(mock_vp.called)
|
||||
self.assertFalse(mock_address.called)
|
||||
|
||||
@mock.patch.object(FAKE_CLIENT.node, 'vendor_passthru')
|
||||
def test_unplug_vifs(self, mock_vp):
|
||||
|
|
Loading…
Reference in New Issue