Merge "Complete move of baremetal machine tests"
This commit is contained in:
@@ -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',
|
||||
|
||||
170
openstack/tests/unit/cloud/test_operator.py
Normal file
170
openstack/tests/unit/cloud/test_operator.py
Normal file
@@ -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()
|
||||
Reference in New Issue
Block a user