Complete move of baremetal machine tests
Migrating tests to wrap up machine actions. Ports will be migrated separately as there will also need to be portgroups, which could be wrapped into the same file/class depending on how that ends up being implemented. Change-Id: I239bbc134f42a47e8df75531dbd50916a97a6068
This commit is contained in:
parent
dd431c3a22
commit
910fc10427
|
@ -17,81 +17,94 @@
|
|||
from openstack import task_manager
|
||||
|
||||
|
||||
class MachineCreate(task_manager.Task):
|
||||
def main(self, client):
|
||||
return client.ironic_client.node.create(**self.args)
|
||||
class IronicTask(task_manager.Task):
|
||||
|
||||
def __init__(self, client, **kwargs):
|
||||
super(IronicTask, self).__init__(**kwargs)
|
||||
self.client = client
|
||||
|
||||
|
||||
class MachineDelete(task_manager.Task):
|
||||
def main(self, client):
|
||||
return client.ironic_client.node.delete(**self.args)
|
||||
class MachineCreate(IronicTask):
|
||||
def main(self):
|
||||
return self.client.ironic_client.node.create(*self.args, **self.kwargs)
|
||||
|
||||
|
||||
class MachinePatch(task_manager.Task):
|
||||
def main(self, client):
|
||||
return client.ironic_client.node.update(**self.args)
|
||||
class MachineDelete(IronicTask):
|
||||
def main(self):
|
||||
return self.client.ironic_client.node.delete(*self.args, **self.kwargs)
|
||||
|
||||
|
||||
class MachinePortGet(task_manager.Task):
|
||||
def main(self, client):
|
||||
return client.ironic_client.port.get(**self.args)
|
||||
class MachinePatch(IronicTask):
|
||||
def main(self):
|
||||
return self.client.ironic_client.node.update(*self.args, **self.kwargs)
|
||||
|
||||
|
||||
class MachinePortGetByAddress(task_manager.Task):
|
||||
def main(self, client):
|
||||
return client.ironic_client.port.get_by_address(**self.args)
|
||||
class MachinePortGet(IronicTask):
|
||||
def main(self):
|
||||
return self.client.ironic_client.port.get(*self.args, **self.kwargs)
|
||||
|
||||
|
||||
class MachinePortCreate(task_manager.Task):
|
||||
def main(self, client):
|
||||
return client.ironic_client.port.create(**self.args)
|
||||
class MachinePortGetByAddress(IronicTask):
|
||||
def main(self):
|
||||
return self.client.ironic_client.port.get_by_address(
|
||||
*self.args, **self.kwargs)
|
||||
|
||||
|
||||
class MachinePortDelete(task_manager.Task):
|
||||
def main(self, client):
|
||||
return client.ironic_client.port.delete(**self.args)
|
||||
class MachinePortCreate(IronicTask):
|
||||
def main(self):
|
||||
return self.client.ironic_client.port.create(*self.args, **self.kwargs)
|
||||
|
||||
|
||||
class MachinePortList(task_manager.Task):
|
||||
def main(self, client):
|
||||
return client.ironic_client.port.list()
|
||||
class MachinePortDelete(IronicTask):
|
||||
def main(self):
|
||||
return self.client.ironic_client.port.delete(*self.args, **self.kwargs)
|
||||
|
||||
|
||||
class MachineNodeGet(task_manager.Task):
|
||||
def main(self, client):
|
||||
return client.ironic_client.node.get(**self.args)
|
||||
class MachinePortList(IronicTask):
|
||||
def main(self):
|
||||
return self.client.ironic_client.port.list()
|
||||
|
||||
|
||||
class MachineNodeList(task_manager.Task):
|
||||
def main(self, client):
|
||||
return client.ironic_client.node.list(**self.args)
|
||||
class MachineNodeGet(IronicTask):
|
||||
def main(self):
|
||||
return self.client.ironic_client.node.get(*self.args, **self.kwargs)
|
||||
|
||||
|
||||
class MachineNodePortList(task_manager.Task):
|
||||
def main(self, client):
|
||||
return client.ironic_client.node.list_ports(**self.args)
|
||||
class MachineNodeList(IronicTask):
|
||||
def main(self):
|
||||
return self.client.ironic_client.node.list(*self.args, **self.kwargs)
|
||||
|
||||
|
||||
class MachineNodeUpdate(task_manager.Task):
|
||||
def main(self, client):
|
||||
return client.ironic_client.node.update(**self.args)
|
||||
class MachineNodePortList(IronicTask):
|
||||
def main(self):
|
||||
return self.client.ironic_client.node.list_ports(
|
||||
*self.args, **self.kwargs)
|
||||
|
||||
|
||||
class MachineNodeValidate(task_manager.Task):
|
||||
def main(self, client):
|
||||
return client.ironic_client.node.validate(**self.args)
|
||||
class MachineNodeUpdate(IronicTask):
|
||||
def main(self):
|
||||
return self.client.ironic_client.node.update(*self.args, **self.kwargs)
|
||||
|
||||
|
||||
class MachineSetMaintenance(task_manager.Task):
|
||||
def main(self, client):
|
||||
return client.ironic_client.node.set_maintenance(**self.args)
|
||||
class MachineNodeValidate(IronicTask):
|
||||
def main(self):
|
||||
return self.client.ironic_client.node.validate(
|
||||
*self.args, **self.kwargs)
|
||||
|
||||
|
||||
class MachineSetPower(task_manager.Task):
|
||||
def main(self, client):
|
||||
return client.ironic_client.node.set_power_state(**self.args)
|
||||
class MachineSetMaintenance(IronicTask):
|
||||
def main(self):
|
||||
return self.client.ironic_client.node.set_maintenance(
|
||||
*self.args, **self.kwargs)
|
||||
|
||||
|
||||
class MachineSetProvision(task_manager.Task):
|
||||
def main(self, client):
|
||||
return client.ironic_client.node.set_provision_state(**self.args)
|
||||
class MachineSetPower(IronicTask):
|
||||
def main(self):
|
||||
return self.client.ironic_client.node.set_power_state(
|
||||
*self.args, **self.kwargs)
|
||||
|
||||
|
||||
class MachineSetProvision(IronicTask):
|
||||
def main(self):
|
||||
return self.client.ironic_client.node.set_provision_state(
|
||||
*self.args, **self.kwargs)
|
||||
|
|
|
@ -16,6 +16,7 @@ import jsonpatch
|
|||
import munch
|
||||
|
||||
from openstack.cloud.exc import * # noqa
|
||||
from openstack.cloud import meta
|
||||
from openstack.cloud import openstackcloud
|
||||
from openstack.cloud import _tasks
|
||||
from openstack.cloud import _utils
|
||||
|
@ -35,27 +36,28 @@ class OperatorCloud(openstackcloud.OpenStackCloud):
|
|||
|
||||
def list_nics(self):
|
||||
with _utils.shade_exceptions("Error fetching machine port list"):
|
||||
return self.manager.submit_task(_tasks.MachinePortList())
|
||||
return meta.obj_list_to_munch(
|
||||
self.manager.submit_task(_tasks.MachinePortList(self)))
|
||||
|
||||
def list_nics_for_machine(self, uuid):
|
||||
with _utils.shade_exceptions(
|
||||
"Error fetching port list for node {node_id}".format(
|
||||
node_id=uuid)):
|
||||
return self.manager.submit_task(
|
||||
_tasks.MachineNodePortList(node_id=uuid))
|
||||
return meta.obj_list_to_munch(self.manager.submit_task(
|
||||
_tasks.MachineNodePortList(self, node_id=uuid)))
|
||||
|
||||
def get_nic_by_mac(self, mac):
|
||||
"""Get Machine by MAC address"""
|
||||
# TODO(shade) Finish porting ironic to REST/sdk
|
||||
# try:
|
||||
# return self.manager.submit_task(
|
||||
# _tasks.MachineNodePortGet(port_id=mac))
|
||||
# _tasks.MachineNodePortGet(self, port_id=mac))
|
||||
# except ironic_exceptions.ClientException:
|
||||
# return None
|
||||
|
||||
def list_machines(self):
|
||||
return self._normalize_machines(
|
||||
self.manager.submit_task(_tasks.MachineNodeList()))
|
||||
self.manager.submit_task(_tasks.MachineNodeList(self)))
|
||||
|
||||
def get_machine(self, name_or_id):
|
||||
"""Get Machine by name or uuid
|
||||
|
@ -211,7 +213,7 @@ class OperatorCloud(openstackcloud.OpenStackCloud):
|
|||
nic = self.manager.submit_task(
|
||||
_tasks.MachinePortCreate(address=row['mac'],
|
||||
node_uuid=machine['uuid']))
|
||||
created_nics.append(nic.uuid)
|
||||
created_nics.append(nic['uuid'])
|
||||
|
||||
except Exception as e:
|
||||
self.log.debug("ironic NIC registration failed", exc_info=True)
|
||||
|
@ -277,7 +279,10 @@ class OperatorCloud(openstackcloud.OpenStackCloud):
|
|||
machine = self.get_machine(machine['uuid'])
|
||||
if (machine['reservation'] is None and
|
||||
machine['provision_state'] is not 'enroll'):
|
||||
|
||||
# NOTE(TheJulia): In this case, the node has
|
||||
# has moved on from the previous state and is
|
||||
# likely not being verified, as no lock is
|
||||
# present on the node.
|
||||
self.node_set_provision_state(
|
||||
machine['uuid'], 'provide')
|
||||
machine = self.get_machine(machine['uuid'])
|
||||
|
@ -292,8 +297,10 @@ class OperatorCloud(openstackcloud.OpenStackCloud):
|
|||
raise OpenStackCloudException(
|
||||
"Machine encountered a failure: %s"
|
||||
% machine['last_error'])
|
||||
|
||||
return machine
|
||||
if not isinstance(machine, str):
|
||||
return self._normalize_machine(machine)
|
||||
else:
|
||||
return machine
|
||||
|
||||
def unregister_machine(self, nics, uuid, wait=False, timeout=600):
|
||||
"""Unregister Baremetal from Ironic
|
||||
|
|
|
@ -248,6 +248,16 @@ def make_fake_machine(machine_name, machine_id=None):
|
|||
id=machine_id,
|
||||
name=machine_name))
|
||||
|
||||
def make_fake_port(address, node_id=None, port_id=None):
|
||||
if not node_id:
|
||||
node_id = uuid.uuid4().hex
|
||||
if not port_id:
|
||||
port_id = uuid.uuid4().hex
|
||||
return meta.obj_to_munch(FakeMachinePort(
|
||||
id=port_id,
|
||||
address=address,
|
||||
node_id=node_id))
|
||||
|
||||
|
||||
class FakeFloatingIP(object):
|
||||
def __init__(self, id, pool, ip, fixed_ip, instance_id):
|
||||
|
@ -346,7 +356,7 @@ class FakeVolumeSnapshot(object):
|
|||
class FakeMachine(object):
|
||||
def __init__(self, id, name=None, driver=None, driver_info=None,
|
||||
chassis_uuid=None, instance_info=None, instance_uuid=None,
|
||||
properties=None):
|
||||
properties=None, reservation=None, last_error=None):
|
||||
self.uuid = id
|
||||
self.name = name
|
||||
self.driver = driver
|
||||
|
@ -355,6 +365,8 @@ class FakeMachine(object):
|
|||
self.instance_info = instance_info
|
||||
self.instance_uuid = instance_uuid
|
||||
self.properties = properties
|
||||
self.reservation = reservation
|
||||
self.last_error = last_error
|
||||
|
||||
|
||||
class FakeMachinePort(object):
|
||||
|
|
|
@ -34,6 +34,12 @@ class TestBaremetalNode(base.IronicTestCase):
|
|||
self.skipTest("Ironic operations not supported yet")
|
||||
self.fake_baremetal_node = fakes.make_fake_machine(
|
||||
self.name, self.uuid)
|
||||
# TODO(TheJulia): Some tests below have fake ports,
|
||||
# since they are required in some processes. Lets refactor
|
||||
# them at some point to use self.fake_baremetal_port.
|
||||
self.fake_baremetal_port = fakes.make_fake_port(
|
||||
'00:01:02:03:04:05',
|
||||
node_id=self.uuid)
|
||||
|
||||
def test_list_machines(self):
|
||||
fake_baremetal_two = fakes.make_fake_machine('two', str(uuid.uuid4()))
|
||||
|
@ -822,6 +828,542 @@ class TestBaremetalNode(base.IronicTestCase):
|
|||
self.assertIsNone(return_value)
|
||||
self.assert_calls()
|
||||
|
||||
def test_register_machine(self):
|
||||
mac_address = '00:01:02:03:04:05'
|
||||
nics = [{'mac': mac_address}]
|
||||
node_uuid = self.fake_baremetal_node['uuid']
|
||||
# TODO(TheJulia): There is a lot of duplication
|
||||
# in testing creation. Surely this hsould be a helper
|
||||
# or something. We should fix this, after we have
|
||||
# ironicclient removed, as in the mean time visibility
|
||||
# will be helpful.
|
||||
node_to_post = {
|
||||
'chassis_uuid': None,
|
||||
'driver': None,
|
||||
'driver_info': None,
|
||||
'name': self.fake_baremetal_node['name'],
|
||||
'properties': None,
|
||||
'uuid': node_uuid}
|
||||
self.fake_baremetal_node['provision_state'] = 'available'
|
||||
if 'provision_state' in node_to_post:
|
||||
node_to_post.pop('provision_state')
|
||||
self.register_uris([
|
||||
dict(
|
||||
method='POST',
|
||||
uri=self.get_mock_url(
|
||||
resource='nodes'),
|
||||
json=self.fake_baremetal_node,
|
||||
validate=dict(json=node_to_post)),
|
||||
dict(
|
||||
method='POST',
|
||||
uri=self.get_mock_url(
|
||||
resource='ports'),
|
||||
validate=dict(json={'address': mac_address,
|
||||
'node_uuid': node_uuid}),
|
||||
json=self.fake_baremetal_port),
|
||||
])
|
||||
return_value = self.op_cloud.register_machine(nics, **node_to_post)
|
||||
|
||||
self.assertDictEqual(self.fake_baremetal_node, return_value)
|
||||
self.assert_calls()
|
||||
|
||||
# TODO(TheJulia): After we remove ironicclient,
|
||||
# we need to de-duplicate these tests. Possibly
|
||||
# a dedicated class, although we should do it then
|
||||
# as we may find differences that need to be accounted
|
||||
# for newer microversions.
|
||||
def test_register_machine_enroll(self):
|
||||
mac_address = '00:01:02:03:04:05'
|
||||
nics = [{'mac': mac_address}]
|
||||
node_uuid = self.fake_baremetal_node['uuid']
|
||||
node_to_post = {
|
||||
'chassis_uuid': None,
|
||||
'driver': None,
|
||||
'driver_info': None,
|
||||
'name': self.fake_baremetal_node['name'],
|
||||
'properties': None,
|
||||
'uuid': node_uuid}
|
||||
self.fake_baremetal_node['provision_state'] = 'enroll'
|
||||
manageable_node = self.fake_baremetal_node.copy()
|
||||
manageable_node['provision_state'] = 'manageable'
|
||||
available_node = self.fake_baremetal_node.copy()
|
||||
available_node['provision_state'] = 'available'
|
||||
self.register_uris([
|
||||
dict(
|
||||
method='POST',
|
||||
uri=self.get_mock_url(
|
||||
resource='nodes'),
|
||||
validate=dict(json=node_to_post),
|
||||
json=self.fake_baremetal_node),
|
||||
dict(
|
||||
method='POST',
|
||||
uri=self.get_mock_url(
|
||||
resource='ports'),
|
||||
validate=dict(json={'address': mac_address,
|
||||
'node_uuid': node_uuid}),
|
||||
json=self.fake_baremetal_port),
|
||||
dict(
|
||||
method='PUT',
|
||||
uri=self.get_mock_url(
|
||||
resource='nodes',
|
||||
append=[self.fake_baremetal_node['uuid'],
|
||||
'states', 'provision']),
|
||||
validate=dict(json={'target': 'manage'})),
|
||||
dict(
|
||||
method='GET',
|
||||
uri=self.get_mock_url(
|
||||
resource='nodes',
|
||||
append=[self.fake_baremetal_node['uuid']]),
|
||||
json=manageable_node),
|
||||
dict(
|
||||
method='GET',
|
||||
uri=self.get_mock_url(
|
||||
resource='nodes',
|
||||
append=[self.fake_baremetal_node['uuid']]),
|
||||
json=manageable_node),
|
||||
dict(
|
||||
method='PUT',
|
||||
uri=self.get_mock_url(
|
||||
resource='nodes',
|
||||
append=[self.fake_baremetal_node['uuid'],
|
||||
'states', 'provision']),
|
||||
validate=dict(json={'target': 'provide'})),
|
||||
dict(
|
||||
method='GET',
|
||||
uri=self.get_mock_url(
|
||||
resource='nodes',
|
||||
append=[self.fake_baremetal_node['uuid']]),
|
||||
json=available_node),
|
||||
dict(
|
||||
method='GET',
|
||||
uri=self.get_mock_url(
|
||||
resource='nodes',
|
||||
append=[self.fake_baremetal_node['uuid']]),
|
||||
json=available_node),
|
||||
])
|
||||
# NOTE(When we migrate to a newer microversion, this test
|
||||
# may require revision. It was written for microversion
|
||||
# ?1.13?, which accidently got reverted to 1.6 at one
|
||||
# point during code being refactored soon after the
|
||||
# change landed. Presently, with the lock at 1.6,
|
||||
# this code is never used in the current code path.
|
||||
return_value = self.op_cloud.register_machine(nics, **node_to_post)
|
||||
|
||||
self.assertDictEqual(available_node, return_value)
|
||||
self.assert_calls()
|
||||
|
||||
def test_register_machine_enroll_wait(self):
|
||||
mac_address = self.fake_baremetal_port
|
||||
nics = [{'mac': mac_address}]
|
||||
node_uuid = self.fake_baremetal_node['uuid']
|
||||
node_to_post = {
|
||||
'chassis_uuid': None,
|
||||
'driver': None,
|
||||
'driver_info': None,
|
||||
'name': self.fake_baremetal_node['name'],
|
||||
'properties': None,
|
||||
'uuid': node_uuid}
|
||||
self.fake_baremetal_node['provision_state'] = 'enroll'
|
||||
manageable_node = self.fake_baremetal_node.copy()
|
||||
manageable_node['provision_state'] = 'manageable'
|
||||
available_node = self.fake_baremetal_node.copy()
|
||||
available_node['provision_state'] = 'available'
|
||||
self.register_uris([
|
||||
dict(
|
||||
method='POST',
|
||||
uri=self.get_mock_url(
|
||||
resource='nodes'),
|
||||
validate=dict(json=node_to_post),
|
||||
json=self.fake_baremetal_node),
|
||||
dict(
|
||||
method='POST',
|
||||
uri=self.get_mock_url(
|
||||
resource='ports'),
|
||||
validate=dict(json={'address': mac_address,
|
||||
'node_uuid': node_uuid}),
|
||||
json=self.fake_baremetal_port),
|
||||
dict(
|
||||
method='GET',
|
||||
uri=self.get_mock_url(
|
||||
resource='nodes',
|
||||
append=[self.fake_baremetal_node['uuid']]),
|
||||
json=self.fake_baremetal_node),
|
||||
dict(
|
||||
method='PUT',
|
||||
uri=self.get_mock_url(
|
||||
resource='nodes',
|
||||
append=[self.fake_baremetal_node['uuid'],
|
||||
'states', 'provision']),
|
||||
validate=dict(json={'target': 'manage'})),
|
||||
dict(
|
||||
method='GET',
|
||||
uri=self.get_mock_url(
|
||||
resource='nodes',
|
||||
append=[self.fake_baremetal_node['uuid']]),
|
||||
json=self.fake_baremetal_node),
|
||||
dict(
|
||||
method='GET',
|
||||
uri=self.get_mock_url(
|
||||
resource='nodes',
|
||||
append=[self.fake_baremetal_node['uuid']]),
|
||||
json=manageable_node),
|
||||
dict(
|
||||
method='PUT',
|
||||
uri=self.get_mock_url(
|
||||
resource='nodes',
|
||||
append=[self.fake_baremetal_node['uuid'],
|
||||
'states', 'provision']),
|
||||
validate=dict(json={'target': 'provide'})),
|
||||
dict(
|
||||
method='GET',
|
||||
uri=self.get_mock_url(
|
||||
resource='nodes',
|
||||
append=[self.fake_baremetal_node['uuid']]),
|
||||
json=available_node),
|
||||
dict(
|
||||
method='GET',
|
||||
uri=self.get_mock_url(
|
||||
resource='nodes',
|
||||
append=[self.fake_baremetal_node['uuid']]),
|
||||
json=available_node),
|
||||
])
|
||||
return_value = self.op_cloud.register_machine(nics, wait=True,
|
||||
**node_to_post)
|
||||
|
||||
self.assertDictEqual(available_node, return_value)
|
||||
self.assert_calls()
|
||||
|
||||
def test_register_machine_enroll_failure(self):
|
||||
mac_address = '00:01:02:03:04:05'
|
||||
nics = [{'mac': mac_address}]
|
||||
node_uuid = self.fake_baremetal_node['uuid']
|
||||
node_to_post = {
|
||||
'chassis_uuid': None,
|
||||
'driver': None,
|
||||
'driver_info': None,
|
||||
'name': self.fake_baremetal_node['name'],
|
||||
'properties': None,
|
||||
'uuid': node_uuid}
|
||||
self.fake_baremetal_node['provision_state'] = 'enroll'
|
||||
failed_node = self.fake_baremetal_node.copy()
|
||||
failed_node['reservation'] = 'conductor0'
|
||||
failed_node['provision_state'] = 'verifying'
|
||||
failed_node['last_error'] = 'kaboom!'
|
||||
self.register_uris([
|
||||
dict(
|
||||
method='POST',
|
||||
uri=self.get_mock_url(
|
||||
resource='nodes'),
|
||||
json=self.fake_baremetal_node,
|
||||
validate=dict(json=node_to_post)),
|
||||
dict(
|
||||
method='POST',
|
||||
uri=self.get_mock_url(
|
||||
resource='ports'),
|
||||
validate=dict(json={'address': mac_address,
|
||||
'node_uuid': node_uuid}),
|
||||
json=self.fake_baremetal_port),
|
||||
dict(
|
||||
method='PUT',
|
||||
uri=self.get_mock_url(
|
||||
resource='nodes',
|
||||
append=[self.fake_baremetal_node['uuid'],
|
||||
'states', 'provision']),
|
||||
validate=dict(json={'target': 'manage'})),
|
||||
dict(
|
||||
method='GET',
|
||||
uri=self.get_mock_url(
|
||||
resource='nodes',
|
||||
append=[self.fake_baremetal_node['uuid']]),
|
||||
json=failed_node),
|
||||
dict(
|
||||
method='GET',
|
||||
uri=self.get_mock_url(
|
||||
resource='nodes',
|
||||
append=[self.fake_baremetal_node['uuid']]),
|
||||
json=failed_node),
|
||||
])
|
||||
|
||||
self.assertRaises(
|
||||
exc.OpenStackCloudException,
|
||||
self.op_cloud.register_machine,
|
||||
nics,
|
||||
**node_to_post)
|
||||
self.assert_calls()
|
||||
|
||||
def test_register_machine_enroll_timeout(self):
|
||||
mac_address = '00:01:02:03:04:05'
|
||||
nics = [{'mac': mac_address}]
|
||||
node_uuid = self.fake_baremetal_node['uuid']
|
||||
node_to_post = {
|
||||
'chassis_uuid': None,
|
||||
'driver': None,
|
||||
'driver_info': None,
|
||||
'name': self.fake_baremetal_node['name'],
|
||||
'properties': None,
|
||||
'uuid': node_uuid}
|
||||
self.fake_baremetal_node['provision_state'] = 'enroll'
|
||||
busy_node = self.fake_baremetal_node.copy()
|
||||
busy_node['reservation'] = 'conductor0'
|
||||
busy_node['provision_state'] = 'verifying'
|
||||
self.register_uris([
|
||||
dict(
|
||||
method='POST',
|
||||
uri=self.get_mock_url(
|
||||
resource='nodes'),
|
||||
json=self.fake_baremetal_node,
|
||||
validate=dict(json=node_to_post)),
|
||||
dict(
|
||||
method='POST',
|
||||
uri=self.get_mock_url(
|
||||
resource='ports'),
|
||||
validate=dict(json={'address': mac_address,
|
||||
'node_uuid': node_uuid}),
|
||||
json=self.fake_baremetal_port),
|
||||
dict(
|
||||
method='PUT',
|
||||
uri=self.get_mock_url(
|
||||
resource='nodes',
|
||||
append=[self.fake_baremetal_node['uuid'],
|
||||
'states', 'provision']),
|
||||
validate=dict(json={'target': 'manage'})),
|
||||
dict(
|
||||
method='GET',
|
||||
uri=self.get_mock_url(
|
||||
resource='nodes',
|
||||
append=[self.fake_baremetal_node['uuid']]),
|
||||
json=self.fake_baremetal_node),
|
||||
dict(
|
||||
method='GET',
|
||||
uri=self.get_mock_url(
|
||||
resource='nodes',
|
||||
append=[self.fake_baremetal_node['uuid']]),
|
||||
json=busy_node),
|
||||
])
|
||||
# NOTE(TheJulia): This test shortcircuits the timeout loop
|
||||
# such that it executes only once. The very last returned
|
||||
# state to the API is essentially a busy state that we
|
||||
# want to block on until it has cleared.
|
||||
self.assertRaises(
|
||||
exc.OpenStackCloudException,
|
||||
self.op_cloud.register_machine,
|
||||
nics,
|
||||
timeout=0.001,
|
||||
lock_timeout=0.001,
|
||||
**node_to_post)
|
||||
self.assert_calls()
|
||||
|
||||
def test_register_machine_enroll_timeout_wait(self):
|
||||
mac_address = '00:01:02:03:04:05'
|
||||
nics = [{'mac': mac_address}]
|
||||
node_uuid = self.fake_baremetal_node['uuid']
|
||||
node_to_post = {
|
||||
'chassis_uuid': None,
|
||||
'driver': None,
|
||||
'driver_info': None,
|
||||
'name': self.fake_baremetal_node['name'],
|
||||
'properties': None,
|
||||
'uuid': node_uuid}
|
||||
self.fake_baremetal_node['provision_state'] = 'enroll'
|
||||
self.register_uris([
|
||||
dict(
|
||||
method='POST',
|
||||
uri=self.get_mock_url(
|
||||
resource='nodes'),
|
||||
json=self.fake_baremetal_node,
|
||||
validate=dict(json=node_to_post)),
|
||||
dict(
|
||||
method='POST',
|
||||
uri=self.get_mock_url(
|
||||
resource='ports'),
|
||||
validate=dict(json={'address': mac_address,
|
||||
'node_uuid': node_uuid}),
|
||||
json=self.fake_baremetal_port),
|
||||
dict(
|
||||
method='GET',
|
||||
uri=self.get_mock_url(
|
||||
resource='nodes',
|
||||
append=[self.fake_baremetal_node['uuid']]),
|
||||
json=self.fake_baremetal_node),
|
||||
dict(
|
||||
method='PUT',
|
||||
uri=self.get_mock_url(
|
||||
resource='nodes',
|
||||
append=[self.fake_baremetal_node['uuid'],
|
||||
'states', 'provision']),
|
||||
validate=dict(json={'target': 'manage'})),
|
||||
dict(
|
||||
method='GET',
|
||||
uri=self.get_mock_url(
|
||||
resource='nodes',
|
||||
append=[self.fake_baremetal_node['uuid']]),
|
||||
json=self.fake_baremetal_node),
|
||||
])
|
||||
self.assertRaises(
|
||||
exc.OpenStackCloudException,
|
||||
self.op_cloud.register_machine,
|
||||
nics,
|
||||
wait=True,
|
||||
timeout=0.001,
|
||||
**node_to_post)
|
||||
self.assert_calls()
|
||||
|
||||
def test_register_machine_port_create_failed(self):
|
||||
mac_address = '00:01:02:03:04:05'
|
||||
nics = [{'mac': mac_address}]
|
||||
node_uuid = self.fake_baremetal_node['uuid']
|
||||
node_to_post = {
|
||||
'chassis_uuid': None,
|
||||
'driver': None,
|
||||
'driver_info': None,
|
||||
'name': self.fake_baremetal_node['name'],
|
||||
'properties': None,
|
||||
'uuid': node_uuid}
|
||||
self.fake_baremetal_node['provision_state'] = 'available'
|
||||
self.register_uris([
|
||||
dict(
|
||||
method='POST',
|
||||
uri=self.get_mock_url(
|
||||
resource='nodes'),
|
||||
json=self.fake_baremetal_node,
|
||||
validate=dict(json=node_to_post)),
|
||||
dict(
|
||||
method='POST',
|
||||
uri=self.get_mock_url(
|
||||
resource='ports'),
|
||||
status_code=400,
|
||||
json={'error': 'invalid'},
|
||||
validate=dict(json={'address': mac_address,
|
||||
'node_uuid': node_uuid})),
|
||||
dict(
|
||||
method='DELETE',
|
||||
uri=self.get_mock_url(
|
||||
resource='nodes',
|
||||
append=[self.fake_baremetal_node['uuid']])),
|
||||
])
|
||||
self.assertRaises(exc.OpenStackCloudException,
|
||||
self.op_cloud.register_machine,
|
||||
nics, **node_to_post)
|
||||
|
||||
self.assert_calls()
|
||||
|
||||
def test_unregister_machine(self):
|
||||
mac_address = self.fake_baremetal_port['address']
|
||||
nics = [{'mac': mac_address}]
|
||||
port_uuid = self.fake_baremetal_port['uuid']
|
||||
# NOTE(TheJulia): The two values below should be the same.
|
||||
port_node_uuid = self.fake_baremetal_port['node_uuid']
|
||||
port_url_address = 'detail?address=%s' % mac_address
|
||||
self.fake_baremetal_node['provision_state'] = 'available'
|
||||
self.register_uris([
|
||||
dict(
|
||||
method='GET',
|
||||
uri=self.get_mock_url(
|
||||
resource='nodes',
|
||||
append=[self.fake_baremetal_node['uuid']]),
|
||||
json=self.fake_baremetal_node),
|
||||
dict(
|
||||
method='GET',
|
||||
uri=self.get_mock_url(
|
||||
resource='ports',
|
||||
append=[port_url_address]),
|
||||
json={'ports': [{'address': mac_address,
|
||||
'node_uuid': port_node_uuid,
|
||||
'uuid': port_uuid}]}),
|
||||
dict(
|
||||
method='DELETE',
|
||||
uri=self.get_mock_url(
|
||||
resource='ports',
|
||||
append=[self.fake_baremetal_port['uuid']])),
|
||||
dict(
|
||||
method='DELETE',
|
||||
uri=self.get_mock_url(
|
||||
resource='nodes',
|
||||
append=[self.fake_baremetal_node['uuid']])),
|
||||
])
|
||||
|
||||
self.op_cloud.unregister_machine(nics,
|
||||
self.fake_baremetal_node['uuid'])
|
||||
|
||||
self.assert_calls()
|
||||
|
||||
def test_unregister_machine_timeout(self):
|
||||
mac_address = self.fake_baremetal_port['address']
|
||||
nics = [{'mac': mac_address}]
|
||||
port_uuid = self.fake_baremetal_port['uuid']
|
||||
port_node_uuid = self.fake_baremetal_port['node_uuid']
|
||||
port_url_address = 'detail?address=%s' % mac_address
|
||||
self.fake_baremetal_node['provision_state'] = 'available'
|
||||
self.register_uris([
|
||||
dict(
|
||||
method='GET',
|
||||
uri=self.get_mock_url(
|
||||
resource='nodes',
|
||||
append=[self.fake_baremetal_node['uuid']]),
|
||||
json=self.fake_baremetal_node),
|
||||
dict(
|
||||
method='GET',
|
||||
uri=self.get_mock_url(
|
||||
resource='ports',
|
||||
append=[port_url_address]),
|
||||
json={'ports': [{'address': mac_address,
|
||||
'node_uuid': port_node_uuid,
|
||||
'uuid': port_uuid}]}),
|
||||
dict(
|
||||
method='DELETE',
|
||||
uri=self.get_mock_url(
|
||||
resource='ports',
|
||||
append=[self.fake_baremetal_port['uuid']])),
|
||||
dict(
|
||||
method='DELETE',
|
||||
uri=self.get_mock_url(
|
||||
resource='nodes',
|
||||
append=[self.fake_baremetal_node['uuid']])),
|
||||
dict(
|
||||
method='GET',
|
||||
uri=self.get_mock_url(
|
||||
resource='nodes',
|
||||
append=[self.fake_baremetal_node['uuid']]),
|
||||
json=self.fake_baremetal_node),
|
||||
])
|
||||
self.assertRaises(
|
||||
exc.OpenStackCloudException,
|
||||
self.op_cloud.unregister_machine,
|
||||
nics,
|
||||
self.fake_baremetal_node['uuid'],
|
||||
wait=True,
|
||||
timeout=0.001)
|
||||
|
||||
self.assert_calls()
|
||||
|
||||
def test_unregister_machine_unavailable(self):
|
||||
# This is a list of invalid states that the method
|
||||
# should fail on.
|
||||
invalid_states = ['active', 'cleaning', 'clean wait', 'clean failed']
|
||||
mac_address = self.fake_baremetal_port['address']
|
||||
nics = [{'mac': mac_address}]
|
||||
url_list = []
|
||||
for state in invalid_states:
|
||||
self.fake_baremetal_node['provision_state'] = state
|
||||
url_list.append(
|
||||
dict(
|
||||
method='GET',
|
||||
uri=self.get_mock_url(
|
||||
resource='nodes',
|
||||
append=[self.fake_baremetal_node['uuid']]),
|
||||
json=self.fake_baremetal_node))
|
||||
|
||||
self.register_uris(url_list)
|
||||
|
||||
for state in invalid_states:
|
||||
self.assertRaises(
|
||||
exc.OpenStackCloudException,
|
||||
self.op_cloud.unregister_machine,
|
||||
nics,
|
||||
self.fake_baremetal_node['uuid'])
|
||||
|
||||
self.assert_calls()
|
||||
|
||||
def test_update_machine_patch_no_action(self):
|
||||
self.register_uris([dict(
|
||||
method='GET',
|
||||
|
|
|
@ -374,8 +374,8 @@ class TestImage(BaseTestImage):
|
|||
'X-Trans-Id': 'txbbb825960a3243b49a36f-005a0dadaedfw1',
|
||||
'Content-Length': '1290170880',
|
||||
'Last-Modified': 'Tue, 14 Apr 2015 18:29:01 GMT',
|
||||
'X-Object-Meta-X-Shade-Sha256': fakes.NO_SHA256,
|
||||
'X-Object-Meta-X-Shade-Md5': fakes.NO_MD5,
|
||||
'X-Object-Meta-X-Sdk-Sha256': fakes.NO_SHA256,
|
||||
'X-Object-Meta-X-Sdk-Md5': fakes.NO_MD5,
|
||||
'Date': 'Thu, 16 Nov 2017 15:24:30 GMT',
|
||||
'Accept-Ranges': 'bytes',
|
||||
'Content-Type': 'application/octet-stream',
|
||||
|
|
|
@ -0,0 +1,170 @@
|
|||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import mock
|
||||
import munch
|
||||
import testtools
|
||||
|
||||
import openstack
|
||||
from openstack.cloud import exc
|
||||
from openstack.cloud import meta
|
||||
from openstack.config import cloud_config
|
||||
from openstack.tests import fakes
|
||||
from openstack.tests.unit import base
|
||||
|
||||
|
||||
class TestOperatorCloud(base.RequestsMockTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestOperatorCloud, self).setUp()
|
||||
|
||||
def test_operator_cloud(self):
|
||||
self.assertIsInstance(self.op_cloud, openstack.OperatorCloud)
|
||||
|
||||
@mock.patch.object(openstack.OperatorCloud, 'ironic_client')
|
||||
def test_list_nics(self, mock_client):
|
||||
port1 = fakes.FakeMachinePort(1, "aa:bb:cc:dd", "node1")
|
||||
port2 = fakes.FakeMachinePort(2, "dd:cc:bb:aa", "node2")
|
||||
port_list = [port1, port2]
|
||||
port_dict_list = meta.obj_list_to_munch(port_list)
|
||||
|
||||
mock_client.port.list.return_value = port_list
|
||||
nics = self.op_cloud.list_nics()
|
||||
|
||||
self.assertTrue(mock_client.port.list.called)
|
||||
self.assertEqual(port_dict_list, nics)
|
||||
|
||||
@mock.patch.object(openstack.OperatorCloud, 'ironic_client')
|
||||
def test_list_nics_failure(self, mock_client):
|
||||
mock_client.port.list.side_effect = Exception()
|
||||
self.assertRaises(exc.OpenStackCloudException,
|
||||
self.op_cloud.list_nics)
|
||||
|
||||
@mock.patch.object(openstack.OperatorCloud, 'ironic_client')
|
||||
def test_list_nics_for_machine(self, mock_client):
|
||||
mock_client.node.list_ports.return_value = []
|
||||
self.op_cloud.list_nics_for_machine("123")
|
||||
mock_client.node.list_ports.assert_called_with(node_id="123")
|
||||
|
||||
@mock.patch.object(openstack.OperatorCloud, 'ironic_client')
|
||||
def test_list_nics_for_machine_failure(self, mock_client):
|
||||
mock_client.node.list_ports.side_effect = Exception()
|
||||
self.assertRaises(exc.OpenStackCloudException,
|
||||
self.op_cloud.list_nics_for_machine, None)
|
||||
|
||||
@mock.patch.object(openstack.OpenStackCloud, '_image_client')
|
||||
def test_get_image_name(self, mock_client):
|
||||
|
||||
fake_image = munch.Munch(
|
||||
id='22',
|
||||
name='22 name',
|
||||
status='success')
|
||||
mock_client.get.return_value = [fake_image]
|
||||
self.assertEqual('22 name', self.op_cloud.get_image_name('22'))
|
||||
self.assertEqual('22 name', self.op_cloud.get_image_name('22 name'))
|
||||
|
||||
@mock.patch.object(openstack.OpenStackCloud, '_image_client')
|
||||
def test_get_image_id(self, mock_client):
|
||||
|
||||
fake_image = munch.Munch(
|
||||
id='22',
|
||||
name='22 name',
|
||||
status='success')
|
||||
mock_client.get.return_value = [fake_image]
|
||||
self.assertEqual('22', self.op_cloud.get_image_id('22'))
|
||||
self.assertEqual('22', self.op_cloud.get_image_id('22 name'))
|
||||
|
||||
@mock.patch.object(cloud_config.CloudConfig, 'get_endpoint')
|
||||
def test_get_session_endpoint_provided(self, fake_get_endpoint):
|
||||
fake_get_endpoint.return_value = 'http://fake.url'
|
||||
self.assertEqual(
|
||||
'http://fake.url', self.op_cloud.get_session_endpoint('image'))
|
||||
|
||||
@mock.patch.object(cloud_config.CloudConfig, 'get_session')
|
||||
def test_get_session_endpoint_session(self, get_session_mock):
|
||||
session_mock = mock.Mock()
|
||||
session_mock.get_endpoint.return_value = 'http://fake.url'
|
||||
get_session_mock.return_value = session_mock
|
||||
self.assertEqual(
|
||||
'http://fake.url', self.op_cloud.get_session_endpoint('image'))
|
||||
|
||||
@mock.patch.object(cloud_config.CloudConfig, 'get_session')
|
||||
def test_get_session_endpoint_exception(self, get_session_mock):
|
||||
class FakeException(Exception):
|
||||
pass
|
||||
|
||||
def side_effect(*args, **kwargs):
|
||||
raise FakeException("No service")
|
||||
session_mock = mock.Mock()
|
||||
session_mock.get_endpoint.side_effect = side_effect
|
||||
get_session_mock.return_value = session_mock
|
||||
self.op_cloud.name = 'testcloud'
|
||||
self.op_cloud.region_name = 'testregion'
|
||||
with testtools.ExpectedException(
|
||||
exc.OpenStackCloudException,
|
||||
"Error getting image endpoint on testcloud:testregion:"
|
||||
" No service"):
|
||||
self.op_cloud.get_session_endpoint("image")
|
||||
|
||||
@mock.patch.object(cloud_config.CloudConfig, 'get_session')
|
||||
def test_get_session_endpoint_unavailable(self, get_session_mock):
|
||||
session_mock = mock.Mock()
|
||||
session_mock.get_endpoint.return_value = None
|
||||
get_session_mock.return_value = session_mock
|
||||
image_endpoint = self.op_cloud.get_session_endpoint("image")
|
||||
self.assertIsNone(image_endpoint)
|
||||
|
||||
@mock.patch.object(cloud_config.CloudConfig, 'get_session')
|
||||
def test_get_session_endpoint_identity(self, get_session_mock):
|
||||
session_mock = mock.Mock()
|
||||
get_session_mock.return_value = session_mock
|
||||
self.op_cloud.get_session_endpoint('identity')
|
||||
kwargs = dict(
|
||||
interface='public', region_name='RegionOne',
|
||||
service_name=None, service_type='identity')
|
||||
|
||||
session_mock.get_endpoint.assert_called_with(**kwargs)
|
||||
|
||||
@mock.patch.object(cloud_config.CloudConfig, 'get_session')
|
||||
def test_has_service_no(self, get_session_mock):
|
||||
session_mock = mock.Mock()
|
||||
session_mock.get_endpoint.return_value = None
|
||||
get_session_mock.return_value = session_mock
|
||||
self.assertFalse(self.op_cloud.has_service("image"))
|
||||
|
||||
@mock.patch.object(cloud_config.CloudConfig, 'get_session')
|
||||
def test_has_service_yes(self, get_session_mock):
|
||||
session_mock = mock.Mock()
|
||||
session_mock.get_endpoint.return_value = 'http://fake.url'
|
||||
get_session_mock.return_value = session_mock
|
||||
self.assertTrue(self.op_cloud.has_service("image"))
|
||||
|
||||
def test_list_hypervisors(self):
|
||||
'''This test verifies that calling list_hypervisors results in a call
|
||||
to nova client.'''
|
||||
self.register_uris([
|
||||
dict(method='GET',
|
||||
uri=self.get_mock_url(
|
||||
'compute', 'public', append=['os-hypervisors', 'detail']),
|
||||
json={'hypervisors': [
|
||||
fakes.make_fake_hypervisor('1', 'testserver1'),
|
||||
fakes.make_fake_hypervisor('2', 'testserver2'),
|
||||
]}),
|
||||
])
|
||||
|
||||
r = self.op_cloud.list_hypervisors()
|
||||
|
||||
self.assertEqual(2, len(r))
|
||||
self.assertEqual('testserver1', r[0]['hypervisor_hostname'])
|
||||
self.assertEqual('testserver2', r[1]['hypervisor_hostname'])
|
||||
|
||||
self.assert_calls()
|
Loading…
Reference in New Issue