Merge "Implements SeaMicro VendorPassThru functionality"
This commit is contained in:
@@ -344,3 +344,8 @@ class NodeLocked(TemporaryFailure):
|
||||
class NoFreeConductorWorker(TemporaryFailure):
|
||||
message = _('Requested action cannot be performed due to lack of free '
|
||||
'conductor workers.')
|
||||
code = 503 # Service Unavailable (temporary).
|
||||
|
||||
|
||||
class VendorPassthruException(IronicException):
|
||||
pass
|
||||
|
@@ -82,6 +82,7 @@ class FakeSeaMicroDriver(base.BaseDriver):
|
||||
self.power = seamicro.Power()
|
||||
self.deploy = fake.FakeDeploy()
|
||||
self.rescue = self.deploy
|
||||
a = fake.FakeVendorA()
|
||||
b = fake.FakeVendorB()
|
||||
self.vendor = fake.MultipleVendorInterface(a, b)
|
||||
self.seamicro_vendor = seamicro.VendorPassthru()
|
||||
self.pxe_vendor = pxe.VendorPassthru()
|
||||
self.vendor = seamicro.SeaMicroPXEMultipleVendorInterface(
|
||||
self.seamicro_vendor, self.pxe_vendor)
|
||||
|
@@ -16,6 +16,8 @@ Ironic SeaMicro interfaces.
|
||||
|
||||
Provides basic power control of servers in SeaMicro chassis via
|
||||
python-seamicroclient.
|
||||
|
||||
Provides vendor passthru methods for SeaMicro specific functionality.
|
||||
"""
|
||||
|
||||
from oslo.config import cfg
|
||||
@@ -47,6 +49,11 @@ CONF.register_opts(opts, opt_group)
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
VENDOR_PASSTHRU_METHODS = ['attach_volume', 'set_boot_device',
|
||||
'set_node_vlan_id']
|
||||
|
||||
VALID_BOOT_DEVICES = ['pxe', 'disk']
|
||||
|
||||
|
||||
def _get_client(*args, **kwargs):
|
||||
"""Creates the python-seamicro_client
|
||||
@@ -106,6 +113,13 @@ def _get_server(driver_info):
|
||||
return s_client.servers.get(driver_info['server_id'])
|
||||
|
||||
|
||||
def _get_volume(driver_info, volume_id):
|
||||
"""Get volume from volume_id."""
|
||||
|
||||
s_client = _get_client(**driver_info)
|
||||
return s_client.volumes.get(volume_id)
|
||||
|
||||
|
||||
def _get_power_status(node):
|
||||
"""Get current power state of this node
|
||||
|
||||
@@ -243,6 +257,46 @@ def _reboot(node, timeout=None):
|
||||
return state[0]
|
||||
|
||||
|
||||
def _validate_volume(driver_info, volume_id):
|
||||
"""Validates if volume is in Storage pools designated for ironic."""
|
||||
|
||||
volume = _get_volume(driver_info, volume_id)
|
||||
|
||||
# Check if the ironic <scard>/ironic-<pool_id>/<volume_id> naming scheme
|
||||
# is present in volume id
|
||||
try:
|
||||
pool_id = volume.id.split('/')[1].lower()
|
||||
except IndexError:
|
||||
pool_id = ""
|
||||
|
||||
if "ironic-" in pool_id:
|
||||
return True
|
||||
else:
|
||||
raise exception.InvalidParameterValue(_(
|
||||
"Invalid volume id specified"))
|
||||
|
||||
|
||||
def _get_pools(driver_info, filters=None):
|
||||
"""Get SeaMicro storage pools matching given filters."""
|
||||
|
||||
s_client = _get_client(**driver_info)
|
||||
return s_client.pools.list(filters=filters)
|
||||
|
||||
|
||||
def _create_volume(driver_info, volume_size):
|
||||
"""Create volume in the SeaMicro storage pools designated for ironic."""
|
||||
|
||||
ironic_pools = _get_pools(driver_info, filters={'id': 'ironic-'})
|
||||
if ironic_pools is None:
|
||||
raise exception.VendorPassthruException(_(
|
||||
"No storage pools found for ironic"))
|
||||
|
||||
least_used_pool = sorted(ironic_pools,
|
||||
key=lambda x: x.freeSize)[0]
|
||||
return _get_client(**driver_info).volumes.create(volume_size,
|
||||
least_used_pool)
|
||||
|
||||
|
||||
class Power(base.PowerInterface):
|
||||
"""SeaMicro Power Interface.
|
||||
|
||||
@@ -307,3 +361,141 @@ class Power(base.PowerInterface):
|
||||
|
||||
if state != states.POWER_ON:
|
||||
raise exception.PowerStateFailure(pstate=states.POWER_ON)
|
||||
|
||||
|
||||
class VendorPassthru(base.VendorInterface):
|
||||
"""SeaMicro vendor-specific methods."""
|
||||
|
||||
def validate(self, node, **kwargs):
|
||||
method = kwargs['method']
|
||||
if method in VENDOR_PASSTHRU_METHODS:
|
||||
return True
|
||||
else:
|
||||
raise exception.InvalidParameterValue(_(
|
||||
"Unsupported method (%s) passed to SeaMicro driver.")
|
||||
% method)
|
||||
|
||||
def vendor_passthru(self, task, node, **kwargs):
|
||||
"""Dispatch vendor specific method calls."""
|
||||
method = kwargs['method']
|
||||
if method in VENDOR_PASSTHRU_METHODS:
|
||||
return getattr(self, "_" + method)(task, node, **kwargs)
|
||||
|
||||
def _set_node_vlan_id(self, task, node, **kwargs):
|
||||
"""Sets a untagged vlan id for NIC 0 of node.
|
||||
|
||||
@kwargs vlan_id: id of untagged vlan for NIC 0 of node
|
||||
"""
|
||||
|
||||
vlan_id = kwargs.get('vlan_id')
|
||||
if not vlan_id:
|
||||
raise exception.InvalidParameterValue(_("No vlan id provided"))
|
||||
|
||||
seamicro_info = _parse_driver_info(node)
|
||||
try:
|
||||
server = _get_server(seamicro_info)
|
||||
|
||||
# remove current vlan for server
|
||||
if len(server.nic['0']['untaggedVlan']) > 0:
|
||||
server.unset_untagged_vlan(server.nic['0']['untaggedVlan'])
|
||||
server = server.refresh(5)
|
||||
server.set_untagged_vlan(vlan_id)
|
||||
except seamicro_client_exception.ClientException as ex:
|
||||
LOG.error(_("SeaMicro client exception: %s"), ex.message)
|
||||
raise exception.VendorPassthruException(message=ex.message)
|
||||
|
||||
properties = node.properties
|
||||
properties['seamicro_vlan_id'] = vlan_id
|
||||
node.properties = properties
|
||||
node.save(task.context)
|
||||
|
||||
def _attach_volume(self, task, node, **kwargs):
|
||||
"""Attach volume from SeaMicro storage pools for ironic to node.
|
||||
If kwargs['volume_id'] not given, Create volume in SeaMicro
|
||||
storage pool and attach to node.
|
||||
|
||||
@kwargs volume_id: id of pre-provisioned volume that is to be attached
|
||||
as root volume of node
|
||||
@kwargs volume_size: size of new volume to be created and attached
|
||||
as root volume of node
|
||||
"""
|
||||
seamicro_info = _parse_driver_info(node)
|
||||
volume_id = kwargs.get('volume_id')
|
||||
|
||||
if volume_id is None:
|
||||
volume_size = kwargs.get('volume_size')
|
||||
if volume_size is None:
|
||||
raise exception.InvalidParameterValue(
|
||||
_("No volume size provided for creating volume"))
|
||||
volume_id = _create_volume(seamicro_info, volume_size)
|
||||
|
||||
if _validate_volume(seamicro_info, volume_id):
|
||||
try:
|
||||
server = _get_server(seamicro_info)
|
||||
server.detach_volume()
|
||||
server = server.refresh(5)
|
||||
server.attach_volume(volume_id)
|
||||
except seamicro_client_exception.ClientException as ex:
|
||||
LOG.error(_("SeaMicro client exception: %s"), ex.message)
|
||||
raise exception.VendorPassthruException(message=ex.message)
|
||||
|
||||
properties = node.properties
|
||||
properties['seamicro_volume_id'] = volume_id
|
||||
node.properties = properties
|
||||
node.save(task.context)
|
||||
|
||||
def _set_boot_device(self, task, node, **kwargs):
|
||||
"""Set the boot device of the node.
|
||||
|
||||
@kwargs boot_device: Boot device. One of [pxe, disk]
|
||||
"""
|
||||
boot_device = kwargs.get('boot_device')
|
||||
|
||||
if boot_device is None:
|
||||
raise exception.InvalidParameterValue(_("No boot device provided"))
|
||||
|
||||
if boot_device not in VALID_BOOT_DEVICES:
|
||||
raise exception.InvalidParameterValue(_("Boot device is invalid"))
|
||||
|
||||
seamicro_info = _parse_driver_info(node)
|
||||
try:
|
||||
server = _get_server(seamicro_info)
|
||||
if boot_device == "disk":
|
||||
boot_device = "hd0"
|
||||
|
||||
server.set_boot_order(boot_device)
|
||||
except seamicro_client_exception.ClientException as ex:
|
||||
LOG.error(_("set_boot_device error: %s"), ex.message)
|
||||
raise exception.VendorPassthruException(message=ex.message)
|
||||
|
||||
|
||||
class SeaMicroPXEMultipleVendorInterface(base.VendorInterface):
|
||||
"""Wrapper around SeaMicro and PXE VendorInterfaces."""
|
||||
|
||||
def __init__(self, seamicro_vendor, pxe_vendor):
|
||||
self.seamicro_vendor = seamicro_vendor
|
||||
self.pxe_vendor = pxe_vendor
|
||||
self.mapping = dict((method, self.seamicro_vendor)
|
||||
for method in VENDOR_PASSTHRU_METHODS)
|
||||
|
||||
def _map(self, **kwargs):
|
||||
"""Use SeaMicro interface if method is supported by SeaMicro,
|
||||
else use PXE.
|
||||
|
||||
:returns: an instance of a VendorInterface
|
||||
:raises: InvalidParameterValue if **kwargs does not contain 'method'
|
||||
or if the method can not be mapped to an interface.
|
||||
|
||||
"""
|
||||
method = kwargs.get('method')
|
||||
return self.mapping.get(method) or self.pxe_vendor
|
||||
|
||||
def validate(self, *args, **kwargs):
|
||||
"""Call validate on the appropriate interface only."""
|
||||
route = self._map(**kwargs)
|
||||
route.validate(*args, **kwargs)
|
||||
|
||||
def vendor_passthru(self, task, node, **kwargs):
|
||||
"""Call vendor_passthru on the appropriate interface only."""
|
||||
route = self._map(**kwargs)
|
||||
return route.vendor_passthru(task, node, **kwargs)
|
||||
|
@@ -93,4 +93,7 @@ class PXEAndSeaMicroDriver(base.BaseDriver):
|
||||
self.power = seamicro.Power()
|
||||
self.deploy = pxe.PXEDeploy()
|
||||
self.rescue = self.deploy
|
||||
self.vendor = pxe.VendorPassthru()
|
||||
self.seamicro_vendor = seamicro.VendorPassthru()
|
||||
self.pxe_vendor = pxe.VendorPassthru()
|
||||
self.vendor = seamicro.SeaMicroPXEMultipleVendorInterface(
|
||||
self.seamicro_vendor, self.pxe_vendor)
|
||||
|
@@ -12,7 +12,10 @@
|
||||
|
||||
"""Test class for Ironic SeaMicro driver."""
|
||||
|
||||
import uuid
|
||||
|
||||
import mock
|
||||
from seamicroclient import exceptions as seamicro_client_exception
|
||||
|
||||
from ironic.common import driver_factory
|
||||
from ironic.common import exception
|
||||
@@ -31,6 +34,7 @@ INFO_DICT = db_utils.get_test_seamicro_info()
|
||||
class Fake_Server():
|
||||
def __init__(self, active=False, *args, **kwargs):
|
||||
self.active = active
|
||||
self.nic = {'0': {'untaggedVlan': ''}}
|
||||
|
||||
def power_on(self):
|
||||
self.active = True
|
||||
@@ -41,6 +45,34 @@ class Fake_Server():
|
||||
def reset(self):
|
||||
self.active = True
|
||||
|
||||
def set_untagged_vlan(self, vlan_id):
|
||||
return
|
||||
|
||||
def attach_volume(self, volume_id):
|
||||
return
|
||||
|
||||
def detach_volume(self):
|
||||
return
|
||||
|
||||
def set_boot_order(self, boot_order):
|
||||
return
|
||||
|
||||
def refresh(self, wait=0):
|
||||
return self
|
||||
|
||||
|
||||
class Fake_Volume():
|
||||
def __init__(self, id=None, *args, **kwargs):
|
||||
if id is None:
|
||||
self.id = "%s/%s/%s" % ("0", "ironic-p6-6", str(uuid.uuid4()))
|
||||
else:
|
||||
self.id = id
|
||||
|
||||
|
||||
class Fake_Pool():
|
||||
def __init__(self, freeSize=None, *args, **kwargs):
|
||||
self.freeSize = freeSize
|
||||
|
||||
|
||||
class SeaMicroValidateParametersTestCase(base.TestCase):
|
||||
|
||||
@@ -96,10 +128,19 @@ class SeaMicroPrivateMethodsTestCase(base.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(SeaMicroPrivateMethodsTestCase, self).setUp()
|
||||
self.node = db_utils.get_test_node(driver='fake_seamicro',
|
||||
driver_info=INFO_DICT)
|
||||
|
||||
n = {
|
||||
'driver': 'fake_seamicro',
|
||||
'driver_info': INFO_DICT
|
||||
}
|
||||
self.dbapi = dbapi.get_instance()
|
||||
self.node = self._create_test_node(**n)
|
||||
self.Server = Fake_Server
|
||||
self.Volume = Fake_Volume
|
||||
self.Pool = Fake_Pool
|
||||
|
||||
def _create_test_node(self, **kwargs):
|
||||
n = db_utils.get_test_node(**kwargs)
|
||||
return self.dbapi.create_node(n)
|
||||
|
||||
@mock.patch.object(seamicro, "_get_server")
|
||||
def test__get_power_status_on(self, mock_get_server):
|
||||
@@ -168,6 +209,43 @@ class SeaMicroPrivateMethodsTestCase(base.TestCase):
|
||||
pstate = seamicro._reboot(self.node, timeout=2)
|
||||
self.assertEqual(states.ERROR, pstate)
|
||||
|
||||
@mock.patch.object(seamicro, "_get_volume")
|
||||
def test__validate_fail(self, mock_get_volume):
|
||||
info = seamicro._parse_driver_info(self.node)
|
||||
volume_id = "0/p6-6/vol1"
|
||||
volume = self.Volume()
|
||||
volume.id = volume_id
|
||||
mock_get_volume.return_value = volume
|
||||
self.assertRaises(exception.InvalidParameterValue,
|
||||
seamicro._validate_volume, info, volume_id)
|
||||
|
||||
@mock.patch.object(seamicro, "_get_volume")
|
||||
def test__validate_good(self, mock_get_volume):
|
||||
info = seamicro._parse_driver_info(self.node)
|
||||
volume = self.Volume()
|
||||
mock_get_volume.return_value = volume
|
||||
valid = seamicro._validate_volume(info, volume.id)
|
||||
self.assertEqual(valid, True)
|
||||
|
||||
@mock.patch.object(seamicro, "_get_pools")
|
||||
def test__create_volume_fail(self, mock_get_pools):
|
||||
info = seamicro._parse_driver_info(self.node)
|
||||
mock_get_pools.return_value = None
|
||||
self.assertRaises(exception.IronicException,
|
||||
seamicro._create_volume,
|
||||
info, 2)
|
||||
|
||||
@mock.patch.object(seamicro, "_get_pools")
|
||||
@mock.patch.object(seamicro, "_get_client")
|
||||
def test__create_volume_good(self, mock_get_client, mock_get_pools):
|
||||
info = seamicro._parse_driver_info(self.node)
|
||||
pools = [self.Pool(1), self.Pool(6), self.Pool(5)]
|
||||
get_pools_patcher = mock.patch.object(mock_get_client, "volume.create")
|
||||
get_pools_patcher.start()
|
||||
mock_get_pools.return_value = pools
|
||||
seamicro._create_volume(info, 2)
|
||||
get_pools_patcher.stop()
|
||||
|
||||
|
||||
class SeaMicroPowerDriverTestCase(db_base.DbTestCase):
|
||||
|
||||
@@ -178,7 +256,7 @@ class SeaMicroPowerDriverTestCase(db_base.DbTestCase):
|
||||
self.node = db_utils.get_test_node(driver='fake_seamicro',
|
||||
driver_info=INFO_DICT)
|
||||
self.dbapi = dbapi.get_instance()
|
||||
self.dbapi.create_node(self.node)
|
||||
self.node = self.dbapi.create_node(self.node)
|
||||
self.parse_drv_info_patcher = mock.patch.object(seamicro,
|
||||
'_parse_driver_info')
|
||||
self.parse_drv_info_mock = None
|
||||
@@ -186,6 +264,7 @@ class SeaMicroPowerDriverTestCase(db_base.DbTestCase):
|
||||
|
||||
self.get_server_mock = None
|
||||
self.Server = Fake_Server
|
||||
self.Volume = Fake_Volume
|
||||
|
||||
@mock.patch.object(seamicro, '_reboot')
|
||||
def test_reboot(self, mock_reboot):
|
||||
@@ -267,3 +346,192 @@ class SeaMicroPowerDriverTestCase(db_base.DbTestCase):
|
||||
task, self.node, states.POWER_OFF)
|
||||
|
||||
mock_power_off.assert_called_once_with(self.node)
|
||||
|
||||
def test_vendor_passthru_validate_good(self):
|
||||
with task_manager.acquire(self.context, [self.node['uuid']],
|
||||
shared=True) as task:
|
||||
for method in seamicro.VENDOR_PASSTHRU_METHODS:
|
||||
task.resources[0].driver.vendor.validate(self.node,
|
||||
**{'method': method})
|
||||
|
||||
def test_vendor_passthru_validate_fail(self):
|
||||
with task_manager.acquire(self.context, [self.node['uuid']],
|
||||
shared=True) as task:
|
||||
self.assertRaises(exception.InvalidParameterValue,
|
||||
task.resources[0].driver.vendor.validate,
|
||||
task, self.node, **{'method': 'invalid_method'})
|
||||
|
||||
@mock.patch.object(seamicro, '_get_server')
|
||||
def test_set_node_vlan_id_good(self, mock_get_server):
|
||||
info = seamicro._parse_driver_info(self.node)
|
||||
vlan_id = "12"
|
||||
mock_get_server.return_value = self.Server(active="true")
|
||||
with task_manager.acquire(self.context, [info['uuid']],
|
||||
shared=False) as task:
|
||||
kwargs = {'vlan_id': vlan_id, 'method': 'set_node_vlan_id'}
|
||||
task.resources[0].driver.vendor.\
|
||||
vendor_passthru(task, self.node, **kwargs)
|
||||
mock_get_server.assert_called_once_with(info)
|
||||
|
||||
def test_set_node_vlan_id_no_input(self):
|
||||
info = seamicro._parse_driver_info(self.node)
|
||||
with task_manager.acquire(self.context, [info['uuid']],
|
||||
shared=False) as task:
|
||||
self.assertRaises(exception.InvalidParameterValue,
|
||||
task.resources[0].driver.vendor.
|
||||
vendor_passthru, task, self.node,
|
||||
**{'method': 'set_node_vlan_id'})
|
||||
|
||||
@mock.patch.object(seamicro, '_get_server')
|
||||
def test_set_node_vlan_id_fail(self, mock_get_server):
|
||||
def fake_set_untagged_vlan(self, **kwargs):
|
||||
raise seamicro_client_exception.ClientException(500)
|
||||
|
||||
info = seamicro._parse_driver_info(self.node)
|
||||
vlan_id = "12"
|
||||
server = self.Server(active="true")
|
||||
server.set_untagged_vlan = fake_set_untagged_vlan
|
||||
mock_get_server.return_value = server
|
||||
with task_manager.acquire(self.context, [info['uuid']],
|
||||
shared=False) as task:
|
||||
kwargs = {'vlan_id': vlan_id, 'method': 'set_node_vlan_id'}
|
||||
self.assertRaises(exception.IronicException,
|
||||
task.resources[0].driver.vendor.
|
||||
vendor_passthru, task, self.node, **kwargs)
|
||||
|
||||
mock_get_server.assert_called_once_with(info)
|
||||
|
||||
@mock.patch.object(seamicro, '_get_server')
|
||||
@mock.patch.object(seamicro, '_validate_volume')
|
||||
def test_attach_volume_with_volume_id_good(self, mock_validate_volume,
|
||||
mock_get_server):
|
||||
info = seamicro._parse_driver_info(self.node)
|
||||
volume_id = '0/ironic-p6-1/vol1'
|
||||
mock_validate_volume.return_value = True
|
||||
mock_get_server.return_value = self.Server(active="true")
|
||||
with task_manager.acquire(self.context, [info['uuid']],
|
||||
shared=False) as task:
|
||||
kwargs = {'volume_id': volume_id, 'method': 'attach_volume'}
|
||||
task.resources[0].driver.vendor.\
|
||||
vendor_passthru(task, self.node, **kwargs)
|
||||
mock_get_server.assert_called_once_with(info)
|
||||
|
||||
@mock.patch.object(seamicro, '_get_server')
|
||||
@mock.patch.object(seamicro, '_get_volume')
|
||||
def test_attach_volume_with_invalid_volume_id_fail(self,
|
||||
mock_get_volume,
|
||||
mock_get_server):
|
||||
info = seamicro._parse_driver_info(self.node)
|
||||
volume_id = '0/p6-1/vol1'
|
||||
mock_get_volume.return_value = self.Volume(volume_id)
|
||||
mock_get_server.return_value = self.Server(active="true")
|
||||
with task_manager.acquire(self.context, [info['uuid']],
|
||||
shared=False) as task:
|
||||
kwargs = {'volume_id': volume_id, 'method': 'attach_volume'}
|
||||
self.assertRaises(exception.InvalidParameterValue,
|
||||
task.resources[0].driver.vendor.
|
||||
vendor_passthru, task, self.node,
|
||||
**kwargs)
|
||||
|
||||
@mock.patch.object(seamicro, '_get_server')
|
||||
@mock.patch.object(seamicro, '_validate_volume')
|
||||
def test_attach_volume_fail(self, mock_validate_volume,
|
||||
mock_get_server):
|
||||
def fake_attach_volume(self, **kwargs):
|
||||
raise seamicro_client_exception.ClientException(500)
|
||||
|
||||
info = seamicro._parse_driver_info(self.node)
|
||||
volume_id = '0/p6-1/vol1'
|
||||
mock_validate_volume.return_value = True
|
||||
server = self.Server(active="true")
|
||||
server.attach_volume = fake_attach_volume
|
||||
mock_get_server.return_value = server
|
||||
with task_manager.acquire(self.context, [info['uuid']],
|
||||
shared=False) as task:
|
||||
kwargs = {'volume_id': volume_id, 'method': 'attach_volume'}
|
||||
self.assertRaises(exception.IronicException,
|
||||
task.resources[0].driver.vendor.
|
||||
vendor_passthru, task, self.node, **kwargs)
|
||||
|
||||
mock_get_server.assert_called_once_with(info)
|
||||
|
||||
@mock.patch.object(seamicro, '_get_server')
|
||||
@mock.patch.object(seamicro, '_validate_volume')
|
||||
@mock.patch.object(seamicro, '_create_volume')
|
||||
def test_attach_volume_with_volume_size_good(self, mock_create_volume,
|
||||
mock_validate_volume,
|
||||
mock_get_server):
|
||||
info = seamicro._parse_driver_info(self.node)
|
||||
volume_id = '0/ironic-p6-1/vol1'
|
||||
volume_size = 2
|
||||
mock_create_volume.return_value = volume_id
|
||||
mock_validate_volume.return_value = True
|
||||
mock_get_server.return_value = self.Server(active="true")
|
||||
with task_manager.acquire(self.context, [info['uuid']],
|
||||
shared=False) as task:
|
||||
kwargs = {'volume_size': volume_size, 'method': "attach_volume"}
|
||||
task.resources[0].driver.vendor.\
|
||||
vendor_passthru(task, self.node, **kwargs)
|
||||
mock_get_server.assert_called_once_with(info)
|
||||
mock_create_volume.assert_called_once_with(info, volume_size)
|
||||
|
||||
def test_attach_volume_with_no_input_fail(self):
|
||||
info = seamicro._parse_driver_info(self.node)
|
||||
with task_manager.acquire(self.context, [info['uuid']],
|
||||
shared=False) as task:
|
||||
self.assertRaises(exception.InvalidParameterValue,
|
||||
task.resources[0].driver.vendor.
|
||||
vendor_passthru, task, self.node,
|
||||
**{'method': 'attach_volume'})
|
||||
|
||||
@mock.patch.object(seamicro, '_get_server')
|
||||
def test_set_boot_device_good(self, mock_get_server):
|
||||
info = seamicro._parse_driver_info(self.node)
|
||||
boot_device = "disk"
|
||||
mock_get_server.return_value = self.Server(active="true")
|
||||
with task_manager.acquire(self.context, [info['uuid']],
|
||||
shared=False) as task:
|
||||
kwargs = {'boot_device': boot_device, 'method': 'set_boot_device'}
|
||||
task.resources[0].driver.vendor.\
|
||||
vendor_passthru(task, self.node, **kwargs)
|
||||
mock_get_server.assert_called_once_with(info)
|
||||
|
||||
def test_set_boot_device_no_input(self):
|
||||
info = seamicro._parse_driver_info(self.node)
|
||||
with task_manager.acquire(self.context, [info['uuid']],
|
||||
shared=False) as task:
|
||||
self.assertRaises(exception.InvalidParameterValue,
|
||||
task.resources[0].driver.vendor.
|
||||
vendor_passthru, task, self.node,
|
||||
**{'method': 'set_boot_device'})
|
||||
|
||||
@mock.patch.object(seamicro, '_get_server')
|
||||
def test_set_boot_device_invalid_device_fail(self, mock_get_server):
|
||||
info = seamicro._parse_driver_info(self.node)
|
||||
boot_device = "invalid_device"
|
||||
mock_get_server.return_value = self.Server(active="true")
|
||||
with task_manager.acquire(self.context, [info['uuid']],
|
||||
shared=False) as task:
|
||||
kwargs = {'boot_device': boot_device, 'method': 'set_boot_device'}
|
||||
self.assertRaises(exception.InvalidParameterValue,
|
||||
task.resources[0].driver.vendor.
|
||||
vendor_passthru, task, self.node, **kwargs)
|
||||
|
||||
@mock.patch.object(seamicro, '_get_server')
|
||||
def test_set_boot_device_fail(self, mock_get_server):
|
||||
def fake_set_boot_order(self, **kwargs):
|
||||
raise seamicro_client_exception.ClientException(500)
|
||||
|
||||
info = seamicro._parse_driver_info(self.node)
|
||||
boot_device = "pxe"
|
||||
server = self.Server(active="true")
|
||||
server.set_boot_order = fake_set_boot_order
|
||||
mock_get_server.return_value = server
|
||||
with task_manager.acquire(self.context, [info['uuid']],
|
||||
shared=False) as task:
|
||||
kwargs = {'boot_device': boot_device, 'method': 'set_boot_device'}
|
||||
self.assertRaises(exception.IronicException,
|
||||
task.resources[0].driver.vendor.
|
||||
vendor_passthru, task, self.node, **kwargs)
|
||||
|
||||
mock_get_server.assert_called_once_with(info)
|
||||
|
Reference in New Issue
Block a user