summaryrefslogtreecommitdiff
path: root/ironic/tests
diff options
context:
space:
mode:
Diffstat (limited to 'ironic/tests')
-rw-r--r--ironic/tests/__init__.py11
-rw-r--r--ironic/tests/api/test_acl.py9
-rw-r--r--ironic/tests/api/utils.py10
-rw-r--r--ironic/tests/api/v1/test_chassis.py22
-rw-r--r--ironic/tests/api/v1/test_nodes.py233
-rw-r--r--ironic/tests/api/v1/test_ports.py77
-rw-r--r--ironic/tests/api/v1/test_root.py4
-rw-r--r--ironic/tests/api/v1/test_utils.py111
-rw-r--r--ironic/tests/conductor/test_manager.py54
-rw-r--r--ironic/tests/db/sqlalchemy/test_migrations.py29
-rw-r--r--ironic/tests/db/test_chassis.py49
-rw-r--r--ironic/tests/db/test_conductor.py14
-rw-r--r--ironic/tests/db/test_nodes.py21
-rw-r--r--ironic/tests/db/test_ports.py4
-rw-r--r--ironic/tests/db/utils.py20
-rw-r--r--ironic/tests/dhcp/test_factory.py35
-rw-r--r--ironic/tests/dhcp/test_neutron.py33
-rw-r--r--ironic/tests/drivers/agent_pxe_config.template2
-rw-r--r--ironic/tests/drivers/amt/test_vendor.py58
-rw-r--r--ironic/tests/drivers/drac/test_client.py38
-rw-r--r--ironic/tests/drivers/drac/test_power.py17
-rw-r--r--ironic/tests/drivers/elilo_efi_pxe_config.template16
-rw-r--r--ironic/tests/drivers/ilo/test_common.py70
-rw-r--r--ironic/tests/drivers/ilo/test_deploy.py262
-rw-r--r--ironic/tests/drivers/ilo/test_inspect.py180
-rw-r--r--ironic/tests/drivers/ilo/test_power.py14
-rw-r--r--ironic/tests/drivers/ipxe_config.template21
-rw-r--r--ironic/tests/drivers/pxe_config.template2
-rw-r--r--ironic/tests/drivers/test_agent.py90
-rw-r--r--ironic/tests/drivers/test_agent_base_vendor.py111
-rw-r--r--ironic/tests/drivers/test_agent_client.py32
-rw-r--r--ironic/tests/drivers/test_deploy_utils.py114
-rw-r--r--ironic/tests/drivers/test_ipmitool.py80
-rw-r--r--ironic/tests/drivers/test_iscsi_deploy.py135
-rw-r--r--ironic/tests/drivers/test_pxe.py132
-rw-r--r--ironic/tests/drivers/test_seamicro.py3
-rw-r--r--ironic/tests/drivers/test_ssh.py2
-rw-r--r--ironic/tests/drivers/test_utils.py21
-rw-r--r--ironic/tests/objects/utils.py3
-rw-r--r--ironic/tests/stubs.py12
-rw-r--r--ironic/tests/test_disk_partitioner.py46
-rw-r--r--ironic/tests/test_driver_factory.py3
-rw-r--r--ironic/tests/test_exception.py29
-rw-r--r--ironic/tests/test_glance_service.py26
-rw-r--r--ironic/tests/test_hash_ring.py2
-rw-r--r--ironic/tests/test_image_service.py102
-rw-r--r--ironic/tests/test_images.py288
-rw-r--r--ironic/tests/test_keystone.py26
-rw-r--r--ironic/tests/test_pxe_utils.py121
-rw-r--r--ironic/tests/test_swift.py10
-rw-r--r--ironic/tests/test_utils.py68
51 files changed, 1935 insertions, 937 deletions
diff --git a/ironic/tests/__init__.py b/ironic/tests/__init__.py
index 7e8390833..918237d30 100644
--- a/ironic/tests/__init__.py
+++ b/ironic/tests/__init__.py
@@ -32,14 +32,3 @@ eventlet.monkey_patch(os=False)
# The code below enables nosetests to work with i18n _() blocks
import six.moves.builtins as __builtin__
setattr(__builtin__, '_', lambda x: x)
-
-# NOTE(viktors): Ironic unittests patches timeutils from oslo_utils. At the
-# same time oslo.db uses oslo.utils not oslo_utils till 1.5.0
-# release, so timeutils in oslo.db code at and leave not
-# patched, so time comparison fails in Ironic tests. To avoid
-# this we have oslo_db use timeutils from oslo_utils in tests.
-# TODO(viktors): Remove this workaround when Ironic will use oslo.db 1.5.0
-from oslo_db.sqlalchemy import models
-from oslo_utils import timeutils
-
-models.timeutils = timeutils
diff --git a/ironic/tests/api/test_acl.py b/ironic/tests/api/test_acl.py
index 0b60387d8..8de194ffc 100644
--- a/ironic/tests/api/test_acl.py
+++ b/ironic/tests/api/test_acl.py
@@ -88,7 +88,10 @@ class TestACL(base.FunctionalTest):
self.assertEqual(200, response.status_int)
def test_public_api_with_path_extensions(self):
- for route in ('/v1/', '/v1.json', '/v1.xml'):
- response = self.get_json(route,
+ routes = {'/v1/': 200,
+ '/v1.json': 200,
+ '/v1.xml': 404}
+ for url in routes:
+ response = self.get_json(url,
path_prefix='', expect_errors=True)
- self.assertEqual(200, response.status_int)
+ self.assertEqual(routes[url], response.status_int)
diff --git a/ironic/tests/api/utils.py b/ironic/tests/api/utils.py
index ee029717f..76d229b0a 100644
--- a/ironic/tests/api/utils.py
+++ b/ironic/tests/api/utils.py
@@ -94,3 +94,13 @@ def chassis_post_data(**kw):
chassis = utils.get_test_chassis(**kw)
internal = chassis_controller.ChassisPatchType.internal_attrs()
return remove_internal(chassis, internal)
+
+
+def post_get_test_node(**kw):
+ # NOTE(lucasagomes): When creating a node via API (POST)
+ # we have to use chassis_uuid
+ node = node_post_data(**kw)
+ chassis = utils.get_test_chassis()
+ node['chassis_id'] = None
+ node['chassis_uuid'] = kw.get('chassis_uuid', chassis['uuid'])
+ return node
diff --git a/ironic/tests/api/v1/test_chassis.py b/ironic/tests/api/v1/test_chassis.py
index 71607b270..a45e79e5a 100644
--- a/ironic/tests/api/v1/test_chassis.py
+++ b/ironic/tests/api/v1/test_chassis.py
@@ -21,6 +21,7 @@ import mock
from oslo_config import cfg
from oslo_utils import timeutils
from oslo_utils import uuidutils
+import six
from six.moves.urllib import parse as urlparse
from wsme import types as wtypes
@@ -77,16 +78,16 @@ class TestListChassis(api_base.FunctionalTest):
ch_list = []
for id_ in range(5):
chassis = obj_utils.create_test_chassis(
- self.context, id=id_, uuid=uuidutils.generate_uuid())
+ self.context, uuid=uuidutils.generate_uuid())
ch_list.append(chassis.uuid)
data = self.get_json('/chassis')
self.assertEqual(len(ch_list), len(data['chassis']))
uuids = [n['uuid'] for n in data['chassis']]
- self.assertEqual(ch_list.sort(), uuids.sort())
+ six.assertCountEqual(self, ch_list, uuids)
def test_links(self):
uuid = uuidutils.generate_uuid()
- obj_utils.create_test_chassis(self.context, id=1, uuid=uuid)
+ obj_utils.create_test_chassis(self.context, uuid=uuid)
data = self.get_json('/chassis/%s' % uuid)
self.assertIn('links', data.keys())
self.assertEqual(2, len(data['links']))
@@ -97,7 +98,7 @@ class TestListChassis(api_base.FunctionalTest):
def test_collection_links(self):
for id in range(5):
- obj_utils.create_test_chassis(self.context, id=id,
+ obj_utils.create_test_chassis(self.context,
uuid=uuidutils.generate_uuid())
data = self.get_json('/chassis/?limit=3')
self.assertEqual(3, len(data['chassis']))
@@ -108,7 +109,7 @@ class TestListChassis(api_base.FunctionalTest):
def test_collection_links_default_limit(self):
cfg.CONF.set_override('max_limit', 3, 'api')
for id_ in range(5):
- obj_utils.create_test_chassis(self.context, id=id_,
+ obj_utils.create_test_chassis(self.context,
uuid=uuidutils.generate_uuid())
data = self.get_json('/chassis')
self.assertEqual(3, len(data['chassis']))
@@ -186,8 +187,7 @@ class TestPatch(api_base.FunctionalTest):
def test_replace_multi(self):
extra = {"foo1": "bar1", "foo2": "bar2", "foo3": "bar3"}
chassis = obj_utils.create_test_chassis(self.context, extra=extra,
- uuid=uuidutils.generate_uuid(),
- id=1)
+ uuid=uuidutils.generate_uuid())
new_value = 'new value'
response = self.patch_json('/chassis/%s' % chassis.uuid,
[{'path': '/extra/foo2',
@@ -201,8 +201,7 @@ class TestPatch(api_base.FunctionalTest):
def test_remove_singular(self):
chassis = obj_utils.create_test_chassis(self.context, extra={'a': 'b'},
- uuid=uuidutils.generate_uuid(),
- id=1)
+ uuid=uuidutils.generate_uuid())
response = self.patch_json('/chassis/%s' % chassis.uuid,
[{'path': '/description', 'op': 'remove'}])
self.assertEqual('application/json', response.content_type)
@@ -218,8 +217,7 @@ class TestPatch(api_base.FunctionalTest):
extra = {"foo1": "bar1", "foo2": "bar2", "foo3": "bar3"}
chassis = obj_utils.create_test_chassis(self.context, extra=extra,
description="foobar",
- uuid=uuidutils.generate_uuid(),
- id=1)
+ uuid=uuidutils.generate_uuid())
# Removing one item from the collection
response = self.patch_json('/chassis/%s' % chassis.uuid,
@@ -343,7 +341,7 @@ class TestPost(api_base.FunctionalTest):
def test_post_nodes_subresource(self):
chassis = obj_utils.create_test_chassis(self.context)
- ndict = apiutils.node_post_data(chassis_id=None)
+ ndict = apiutils.node_post_data()
ndict['chassis_uuid'] = chassis.uuid
response = self.post_json('/chassis/nodes', ndict,
expect_errors=True)
diff --git a/ironic/tests/api/v1/test_nodes.py b/ironic/tests/api/v1/test_nodes.py
index 4f79e6aff..dbb95daaf 100644
--- a/ironic/tests/api/v1/test_nodes.py
+++ b/ironic/tests/api/v1/test_nodes.py
@@ -22,7 +22,6 @@ import mock
from oslo_config import cfg
from oslo_utils import timeutils
from oslo_utils import uuidutils
-import pecan
from six.moves.urllib import parse as urlparse
from testtools.matchers import HasLength
from wsme import types as wtypes
@@ -30,6 +29,7 @@ from wsme import types as wtypes
from ironic.api.controllers import base as api_base
from ironic.api.controllers import v1 as api_v1
from ironic.api.controllers.v1 import node as api_node
+from ironic.api.controllers.v1 import utils as api_utils
from ironic.common import boot_devices
from ironic.common import exception
from ironic.common import states
@@ -38,89 +38,13 @@ from ironic import objects
from ironic.tests.api import base as test_api_base
from ironic.tests.api import utils as test_api_utils
from ironic.tests import base
-from ironic.tests.db import utils as dbutils
from ironic.tests.objects import utils as obj_utils
-# NOTE(lucasagomes): When creating a node via API (POST)
-# we have to use chassis_uuid
-def post_get_test_node(**kw):
- node = test_api_utils.node_post_data(**kw)
- chassis = dbutils.get_test_chassis()
- node['chassis_id'] = None
- node['chassis_uuid'] = kw.get('chassis_uuid', chassis['uuid'])
- return node
-
-
-class TestTopLevelFunctions(base.TestCase):
-
- def setUp(self):
- super(TestTopLevelFunctions, self).setUp()
- self.valid_name = 'my-host'
- self.valid_uuid = uuidutils.generate_uuid()
- self.invalid_name = 'Mr Plow'
- self.invalid_uuid = '636-555-3226-'
- self.node = post_get_test_node()
-
- def test_is_valid_name(self):
- self.assertTrue(api_node.is_valid_name(self.valid_name))
- self.assertFalse(api_node.is_valid_name(self.invalid_name))
- self.assertFalse(api_node.is_valid_name(self.valid_uuid))
- self.assertFalse(api_node.is_valid_name(self.invalid_uuid))
-
- @mock.patch.object(pecan, 'request')
- @mock.patch.object(api_node, 'allow_logical_names')
- @mock.patch.object(objects.Node, 'get_by_uuid')
- @mock.patch.object(objects.Node, 'get_by_name')
- def test__get_rpc_node_expect_uuid(self, mock_gbn, mock_gbu, mock_aln,
- mock_pr):
- mock_aln.return_value = True
- self.node['uuid'] = self.valid_uuid
- mock_gbu.return_value = self.node
- self.assertEqual(self.node, api_node._get_rpc_node(self.valid_uuid))
- self.assertEqual(1, mock_gbu.call_count)
- self.assertEqual(0, mock_gbn.call_count)
-
- @mock.patch.object(pecan, 'request')
- @mock.patch.object(api_v1.node, 'allow_logical_names')
- @mock.patch.object(objects.Node, 'get_by_uuid')
- @mock.patch.object(objects.Node, 'get_by_name')
- def test__get_rpc_node_expect_name(self, mock_gbn, mock_gbu, mock_aln,
- mock_pr):
- mock_aln.return_value = True
- self.node['name'] = self.valid_name
- mock_gbn.return_value = self.node
- self.assertEqual(self.node, api_node._get_rpc_node(self.valid_name))
- self.assertEqual(0, mock_gbu.call_count)
- self.assertEqual(1, mock_gbn.call_count)
-
- @mock.patch.object(pecan, 'request')
- @mock.patch.object(api_v1.node, 'allow_logical_names')
- @mock.patch.object(objects.Node, 'get_by_uuid')
- @mock.patch.object(objects.Node, 'get_by_name')
- def test__get_rpc_node_invalid_name(self, mock_gbn, mock_gbu,
- mock_aln, mock_pr):
- mock_aln.return_value = True
- self.assertRaises(exception.InvalidUuidOrName,
- api_node._get_rpc_node,
- self.invalid_name)
-
- @mock.patch.object(pecan, 'request')
- @mock.patch.object(api_v1.node, 'allow_logical_names')
- @mock.patch.object(objects.Node, 'get_by_uuid')
- @mock.patch.object(objects.Node, 'get_by_name')
- def test__get_rpc_node_invalid_uuid(self, mock_gbn, mock_gbu,
- mock_aln, mock_pr):
- mock_aln.return_value = True
- self.assertRaises(exception.InvalidUuidOrName,
- api_node._get_rpc_node,
- self.invalid_uuid)
-
-
class TestNodeObject(base.TestCase):
def test_node_init(self):
- node_dict = test_api_utils.node_post_data(chassis_id=None)
+ node_dict = test_api_utils.node_post_data()
del node_dict['instance_uuid']
node = api_node.Node(**node_dict)
self.assertEqual(wtypes.Unset, node.instance_uuid)
@@ -159,7 +83,8 @@ class TestListNodes(test_api_base.FunctionalTest):
self.assertEqual([], data['nodes'])
def test_one(self):
- node = obj_utils.create_test_node(self.context)
+ node = obj_utils.create_test_node(self.context,
+ chassis_id=self.chassis.id)
data = self.get_json('/nodes',
headers={api_base.Version.string: str(api_v1.MAX_VER)})
self.assertIn('instance_uuid', data['nodes'][0])
@@ -184,7 +109,8 @@ class TestListNodes(test_api_base.FunctionalTest):
self.assertNotIn('chassis_id', data['nodes'][0])
def test_get_one(self):
- node = obj_utils.create_test_node(self.context)
+ node = obj_utils.create_test_node(self.context,
+ chassis_id=self.chassis.id)
data = self.get_json('/nodes/%s' % node.uuid,
headers={api_base.Version.string: str(api_v1.MAX_VER)})
self.assertEqual(node.uuid, data['uuid'])
@@ -205,7 +131,8 @@ class TestListNodes(test_api_base.FunctionalTest):
self.assertNotIn('chassis_id', data)
def test_detail(self):
- node = obj_utils.create_test_node(self.context)
+ node = obj_utils.create_test_node(self.context,
+ chassis_id=self.chassis.id)
data = self.get_json('/nodes/detail',
headers={api_base.Version.string: str(api_v1.MAX_VER)})
self.assertEqual(node.uuid, data['nodes'][0]["uuid"])
@@ -244,23 +171,7 @@ class TestListNodes(test_api_base.FunctionalTest):
headers={api_base.Version.string: "1.2"})
self.assertEqual(states.AVAILABLE, data['provision_state'])
- def test_hide_fields_in_newer_versions(self):
- some_time = datetime.datetime(2015, 3, 18, 19, 20)
- node = obj_utils.create_test_node(self.context,
- inspection_started_at=some_time)
- data = self.get_json('/nodes/%s' % node.uuid,
- headers={api_base.Version.string: str(api_v1.MIN_VER)})
- self.assertNotIn('inspection_finished_at', data)
- self.assertNotIn('inspection_started_at', data)
-
- data = self.get_json('/nodes/%s' % node.uuid,
- headers={api_base.Version.string: "1.6"})
- started = timeutils.parse_isotime(
- data['inspection_started_at']).replace(tzinfo=None)
- self.assertEqual(some_time, started)
- self.assertEqual(None, data['inspection_finished_at'])
-
- def test_hide_driver_internal_info(self):
+ def test_hide_fields_in_newer_versions_driver_internal(self):
node = obj_utils.create_test_node(self.context,
driver_internal_info={"foo": "bar"})
data = self.get_json('/nodes/%s' % node.uuid,
@@ -271,7 +182,7 @@ class TestListNodes(test_api_base.FunctionalTest):
headers={api_base.Version.string: "1.3"})
self.assertEqual({"foo": "bar"}, data['driver_internal_info'])
- def test_unset_logical_names(self):
+ def test_hide_fields_in_newer_versions_name(self):
node = obj_utils.create_test_node(self.context,
name="fish")
data = self.get_json('/nodes/%s' % node.uuid,
@@ -282,6 +193,22 @@ class TestListNodes(test_api_base.FunctionalTest):
headers={api_base.Version.string: "1.5"})
self.assertEqual('fish', data['name'])
+ def test_hide_fields_in_newer_versions_inspection(self):
+ some_time = datetime.datetime(2015, 3, 18, 19, 20)
+ node = obj_utils.create_test_node(self.context,
+ inspection_started_at=some_time)
+ data = self.get_json('/nodes/%s' % node.uuid,
+ headers={api_base.Version.string: str(api_v1.MIN_VER)})
+ self.assertNotIn('inspection_finished_at', data)
+ self.assertNotIn('inspection_started_at', data)
+
+ data = self.get_json('/nodes/%s' % node.uuid,
+ headers={api_base.Version.string: "1.6"})
+ started = timeutils.parse_isotime(
+ data['inspection_started_at']).replace(tzinfo=None)
+ self.assertEqual(some_time, started)
+ self.assertEqual(None, data['inspection_finished_at'])
+
def test_many(self):
nodes = []
for id in range(5):
@@ -530,7 +457,8 @@ class TestListNodes(test_api_base.FunctionalTest):
node = obj_utils.create_test_node(
self.context,
uuid=uuidutils.generate_uuid(),
- instance_uuid=uuidutils.generate_uuid())
+ instance_uuid=uuidutils.generate_uuid(),
+ chassis_id=self.chassis.id)
instance_uuid = node.instance_uuid
data = self.get_json('/nodes/detail?instance_uuid=%s' % instance_uuid)
@@ -734,9 +662,11 @@ class TestPatch(test_api_base.FunctionalTest):
def setUp(self):
super(TestPatch, self).setUp()
self.chassis = obj_utils.create_test_chassis(self.context)
- self.node = obj_utils.create_test_node(self.context, name='node-57')
+ self.node = obj_utils.create_test_node(self.context, name='node-57',
+ chassis_id=self.chassis.id)
self.node_no_name = obj_utils.create_test_node(self.context,
- uuid='deadbeef-0000-1111-2222-333333333333')
+ uuid='deadbeef-0000-1111-2222-333333333333',
+ chassis_id=self.chassis.id)
p = mock.patch.object(rpcapi.ConductorAPI, 'get_topic_for')
self.mock_gtf = p.start()
self.mock_gtf.return_value = 'test-topic'
@@ -777,7 +707,7 @@ class TestPatch(test_api_base.FunctionalTest):
'value': 'aaaaaaaa-1111-bbbb-2222-cccccccccccc',
'op': 'replace'}],
expect_errors=True)
- self.assertEqual(400, response.status_code)
+ self.assertEqual(404, response.status_code)
self.assertFalse(self.mock_update_node.called)
def test_update_ok_by_name(self):
@@ -945,6 +875,35 @@ class TestPatch(test_api_base.FunctionalTest):
self.assertEqual(400, response.status_code)
self.assertTrue(response.json['error_message'])
+ def test_remove_instance_uuid_cleaning(self):
+ node = obj_utils.create_test_node(
+ self.context,
+ uuid=uuidutils.generate_uuid(),
+ provision_state=states.CLEANING,
+ target_provision_state=states.AVAILABLE)
+ self.mock_update_node.return_value = node
+ response = self.patch_json('/nodes/%s' % node.uuid,
+ [{'op': 'remove',
+ 'path': '/instance_uuid'}])
+ self.assertEqual('application/json', response.content_type)
+ self.assertEqual(200, response.status_code)
+ self.mock_update_node.assert_called_once_with(
+ mock.ANY, mock.ANY, 'test-topic')
+
+ def test_add_state_in_cleaning(self):
+ node = obj_utils.create_test_node(
+ self.context,
+ uuid=uuidutils.generate_uuid(),
+ provision_state=states.CLEANING,
+ target_provision_state=states.AVAILABLE)
+ self.mock_update_node.return_value = node
+ response = self.patch_json('/nodes/%s' % node.uuid,
+ [{'path': '/extra/foo', 'value': 'bar',
+ 'op': 'add'}], expect_errors=True)
+ self.assertEqual('application/json', response.content_type)
+ self.assertEqual(409, response.status_code)
+ self.assertTrue(response.json['error_message'])
+
def test_remove_mandatory_field(self):
response = self.patch_json('/nodes/%s' % self.node.uuid,
[{'path': '/driver', 'op': 'remove'}],
@@ -1134,6 +1093,21 @@ class TestPatch(test_api_base.FunctionalTest):
self.assertEqual(409, response.status_code)
self.assertTrue(response.json['error_message'])
+ @mock.patch.object(api_utils, 'get_rpc_node')
+ def test_patch_update_drive_console_enabled(self, mock_rpc_node):
+ self.node.console_enabled = True
+ mock_rpc_node.return_value = self.node
+
+ response = self.patch_json('/nodes/%s' % self.node.uuid,
+ [{'path': '/driver',
+ 'value': 'foo',
+ 'op': 'add'}],
+ expect_errors=True)
+ mock_rpc_node.assert_called_once_with(self.node.uuid)
+ self.assertEqual('application/json', response.content_type)
+ self.assertEqual(409, response.status_code)
+ self.assertTrue(response.json['error_message'])
+
class TestPost(test_api_base.FunctionalTest):
@@ -1147,7 +1121,7 @@ class TestPost(test_api_base.FunctionalTest):
@mock.patch.object(timeutils, 'utcnow')
def test_create_node(self, mock_utcnow):
- ndict = post_get_test_node()
+ ndict = test_api_utils.post_get_test_node()
test_time = datetime.datetime(2000, 1, 1, 0, 0)
mock_utcnow.return_value = test_time
response = self.post_json('/nodes', ndict)
@@ -1172,7 +1146,7 @@ class TestPost(test_api_base.FunctionalTest):
# as Unset).
with mock.patch.object(self.dbapi, 'create_node',
wraps=self.dbapi.create_node) as cn_mock:
- ndict = post_get_test_node(extra={'foo': 123})
+ ndict = test_api_utils.post_get_test_node(extra={'foo': 123})
self.post_json('/nodes', ndict)
result = self.get_json('/nodes/%s' % ndict['uuid'])
self.assertEqual(ndict['extra'], result['extra'])
@@ -1184,7 +1158,7 @@ class TestPost(test_api_base.FunctionalTest):
kwargs = {attr_name: {'str': 'foo', 'int': 123, 'float': 0.1,
'bool': True, 'list': [1, 2], 'none': None,
'dict': {'cat': 'meow'}}}
- ndict = post_get_test_node(**kwargs)
+ ndict = test_api_utils.post_get_test_node(**kwargs)
self.post_json('/nodes', ndict)
result = self.get_json('/nodes/%s' % ndict['uuid'])
self.assertEqual(ndict[attr_name], result[attr_name])
@@ -1310,7 +1284,7 @@ class TestPost(test_api_base.FunctionalTest):
self.assertEqual(403, response.status_int)
def test_create_node_no_mandatory_field_driver(self):
- ndict = post_get_test_node()
+ ndict = test_api_utils.post_get_test_node()
del ndict['driver']
response = self.post_json('/nodes', ndict, expect_errors=True)
self.assertEqual(400, response.status_int)
@@ -1318,7 +1292,7 @@ class TestPost(test_api_base.FunctionalTest):
self.assertTrue(response.json['error_message'])
def test_create_node_invalid_driver(self):
- ndict = post_get_test_node()
+ ndict = test_api_utils.post_get_test_node()
self.mock_gtf.side_effect = exception.NoValidHost('Fake Error')
response = self.post_json('/nodes', ndict, expect_errors=True)
self.assertEqual(400, response.status_int)
@@ -1326,7 +1300,7 @@ class TestPost(test_api_base.FunctionalTest):
self.assertTrue(response.json['error_message'])
def test_create_node_no_chassis_uuid(self):
- ndict = post_get_test_node()
+ ndict = test_api_utils.post_get_test_node()
del ndict['chassis_uuid']
response = self.post_json('/nodes', ndict)
self.assertEqual('application/json', response.content_type)
@@ -1338,7 +1312,8 @@ class TestPost(test_api_base.FunctionalTest):
expected_location)
def test_create_node_with_chassis_uuid(self):
- ndict = post_get_test_node(chassis_uuid=self.chassis.uuid)
+ ndict = test_api_utils.post_get_test_node(
+ chassis_uuid=self.chassis.uuid)
response = self.post_json('/nodes', ndict)
self.assertEqual('application/json', response.content_type)
self.assertEqual(201, response.status_int)
@@ -1351,7 +1326,7 @@ class TestPost(test_api_base.FunctionalTest):
expected_location)
def test_create_node_chassis_uuid_not_found(self):
- ndict = post_get_test_node(
+ ndict = test_api_utils.post_get_test_node(
chassis_uuid='1a1a1a1a-2b2b-3c3c-4d4d-5e5e5e5e5e5e')
response = self.post_json('/nodes', ndict, expect_errors=True)
self.assertEqual('application/json', response.content_type)
@@ -1359,7 +1334,7 @@ class TestPost(test_api_base.FunctionalTest):
self.assertTrue(response.json['error_message'])
def test_create_node_with_internal_field(self):
- ndict = post_get_test_node()
+ ndict = test_api_utils.post_get_test_node()
ndict['reservation'] = 'fake'
response = self.post_json('/nodes', ndict, expect_errors=True)
self.assertEqual('application/json', response.content_type)
@@ -1392,7 +1367,6 @@ class TestDelete(test_api_base.FunctionalTest):
def setUp(self):
super(TestDelete, self).setUp()
- self.chassis = obj_utils.create_test_chassis(self.context)
p = mock.patch.object(rpcapi.ConductorAPI, 'get_topic_for')
self.mock_gtf = p.start()
self.mock_gtf.return_value = 'test-topic'
@@ -1436,7 +1410,7 @@ class TestDelete(test_api_base.FunctionalTest):
response = self.delete('/nodes/%s' % node.name,
expect_errors=True)
- self.assertEqual(400, response.status_int)
+ self.assertEqual(404, response.status_int)
self.assertFalse(mock_gbn.called)
@mock.patch.object(objects.Node, 'get_by_name')
@@ -1508,7 +1482,6 @@ class TestPut(test_api_base.FunctionalTest):
def setUp(self):
super(TestPut, self).setUp()
- self.chassis = obj_utils.create_test_chassis(self.context)
self.node = obj_utils.create_test_node(self.context,
provision_state=states.AVAILABLE, name='node-39')
p = mock.patch.object(rpcapi.ConductorAPI, 'get_topic_for')
@@ -1547,7 +1520,7 @@ class TestPut(test_api_base.FunctionalTest):
response = self.put_json('/nodes/%s/states/power' % self.node.name,
{'target': states.POWER_ON},
expect_errors=True)
- self.assertEqual(400, response.status_code)
+ self.assertEqual(404, response.status_code)
def test_power_state_by_name(self):
response = self.put_json('/nodes/%s/states/power' % self.node.name,
@@ -1570,6 +1543,13 @@ class TestPut(test_api_base.FunctionalTest):
{'target': 'not-supported'}, expect_errors=True)
self.assertEqual(400, ret.status_code)
+ def test_power_change_during_cleaning(self):
+ self.node.provision_state = states.CLEANING
+ self.node.save()
+ ret = self.put_json('/nodes/%s/states/power' % self.node.uuid,
+ {'target': states.POWER_OFF}, expect_errors=True)
+ self.assertEqual(400, ret.status_code)
+
def test_provision_invalid_state_request(self):
ret = self.put_json('/nodes/%s/states/provision' % self.node.uuid,
{'target': 'not-supported'}, expect_errors=True)
@@ -1592,7 +1572,7 @@ class TestPut(test_api_base.FunctionalTest):
ret = self.put_json('/nodes/%s/states/provision' % self.node.name,
{'target': states.ACTIVE},
expect_errors=True)
- self.assertEqual(400, ret.status_code)
+ self.assertEqual(404, ret.status_code)
def test_provision_by_name(self):
ret = self.put_json('/nodes/%s/states/provision' % self.node.name,
@@ -1775,7 +1755,7 @@ class TestPut(test_api_base.FunctionalTest):
ret = self.put_json('/nodes/%s/states/console' % self.node.name,
{'enabled': "true"},
expect_errors=True)
- self.assertEqual(400, ret.status_code)
+ self.assertEqual(404, ret.status_code)
@mock.patch.object(rpcapi.ConductorAPI, 'set_console_mode')
def test_set_console_by_name(self, mock_scm):
@@ -1833,17 +1813,14 @@ class TestPut(test_api_base.FunctionalTest):
True, 'test-topic')
def test_provision_node_in_maintenance_fail(self):
- with mock.patch.object(rpcapi.ConductorAPI, 'do_node_deploy') as dnd:
- self.node.maintenance = True
- self.node.save()
- dnd.side_effect = exception.NodeInMaintenance(op='provisioning',
- node=self.node.uuid)
+ self.node.maintenance = True
+ self.node.save()
- ret = self.put_json('/nodes/%s/states/provision' % self.node.uuid,
- {'target': states.ACTIVE},
- expect_errors=True)
- self.assertEqual(400, ret.status_code)
- self.assertTrue(ret.json['error_message'])
+ ret = self.put_json('/nodes/%s/states/provision' % self.node.uuid,
+ {'target': states.ACTIVE},
+ expect_errors=True)
+ self.assertEqual(400, ret.status_code)
+ self.assertTrue(ret.json['error_message'])
@mock.patch.object(rpcapi.ConductorAPI, 'set_boot_device')
def test_set_boot_device(self, mock_sbd):
diff --git a/ironic/tests/api/v1/test_ports.py b/ironic/tests/api/v1/test_ports.py
index 8a2c1201b..fd5a16376 100644
--- a/ironic/tests/api/v1/test_ports.py
+++ b/ironic/tests/api/v1/test_ports.py
@@ -21,11 +21,14 @@ import mock
from oslo_config import cfg
from oslo_utils import timeutils
from oslo_utils import uuidutils
+import six
from six.moves.urllib import parse as urlparse
from testtools.matchers import HasLength
from wsme import types as wtypes
+from ironic.api.controllers import base as api_controller
from ironic.api.controllers.v1 import port as api_port
+from ironic.api.controllers.v1 import utils as api_utils
from ironic.common import exception
from ironic.conductor import rpcapi
from ironic.tests.api import base as api_base
@@ -109,7 +112,7 @@ class TestListPorts(api_base.FunctionalTest):
self.assertEqual(len(ports), len(data['ports']))
uuids = [n['uuid'] for n in data['ports']]
- self.assertEqual(ports.sort(), uuids.sort())
+ six.assertCountEqual(self, ports, uuids)
def test_links(self):
uuid = uuidutils.generate_uuid()
@@ -180,6 +183,78 @@ class TestListPorts(api_base.FunctionalTest):
self.assertEqual('application/json', response.content_type)
self.assertIn(invalid_address, response.json['error_message'])
+ @mock.patch.object(api_utils, 'get_rpc_node')
+ def test_get_all_by_node_name_ok(self, mock_get_rpc_node):
+ # GET /v1/ports specifying node_name - success
+ mock_get_rpc_node.return_value = self.node
+ for i in range(5):
+ if i < 3:
+ node_id = self.node.id
+ else:
+ node_id = 100000 + i
+ obj_utils.create_test_port(self.context,
+ node_id=node_id,
+ uuid=uuidutils.generate_uuid(),
+ address='52:54:00:cf:2d:3%s' % i)
+ data = self.get_json("/ports?node=%s" % 'test-node',
+ headers={api_controller.Version.string: '1.5'})
+ self.assertEqual(3, len(data['ports']))
+
+ @mock.patch.object(api_utils, 'get_rpc_node')
+ def test_get_all_by_node_uuid_and_name(self, mock_get_rpc_node):
+ # GET /v1/ports specifying node and uuid - should only use node_uuid
+ mock_get_rpc_node.return_value = self.node
+ obj_utils.create_test_port(self.context, node_id=self.node.id)
+ self.get_json('/ports/detail?node_uuid=%s&node=%s' %
+ (self.node.uuid, 'node-name'))
+ mock_get_rpc_node.assert_called_once_with(self.node.uuid)
+
+ @mock.patch.object(api_utils, 'get_rpc_node')
+ def test_get_all_by_node_name_not_supported(self, mock_get_rpc_node):
+ # GET /v1/ports specifying node_name - name not supported
+ mock_get_rpc_node.side_effect = exception.InvalidUuidOrName(
+ name=self.node.uuid)
+ for i in range(3):
+ obj_utils.create_test_port(self.context,
+ node_id=self.node.id,
+ uuid=uuidutils.generate_uuid(),
+ address='52:54:00:cf:2d:3%s' % i)
+ data = self.get_json("/ports?node=%s" % 'test-node',
+ expect_errors=True)
+ self.assertEqual(0, mock_get_rpc_node.call_count)
+ self.assertEqual(406, data.status_int)
+
+ @mock.patch.object(api_utils, 'get_rpc_node')
+ def test_detail_by_node_name_ok(self, mock_get_rpc_node):
+ # GET /v1/ports/detail specifying node_name - success
+ mock_get_rpc_node.return_value = self.node
+ port = obj_utils.create_test_port(self.context, node_id=self.node.id)
+ data = self.get_json('/ports/detail?node=%s' % 'test-node',
+ headers={api_controller.Version.string: '1.5'})
+ self.assertEqual(port.uuid, data['ports'][0]['uuid'])
+ self.assertEqual(self.node.uuid, data['ports'][0]['node_uuid'])
+
+ @mock.patch.object(api_utils, 'get_rpc_node')
+ def test_detail_by_node_name_not_supported(self, mock_get_rpc_node):
+ # GET /v1/ports/detail specifying node_name - name not supported
+ mock_get_rpc_node.side_effect = exception.InvalidUuidOrName(
+ name=self.node.uuid)
+ obj_utils.create_test_port(self.context, node_id=self.node.id)
+ data = self.get_json('/ports/detail?node=%s' % 'test-node',
+ expect_errors=True)
+ self.assertEqual(0, mock_get_rpc_node.call_count)
+ self.assertEqual(406, data.status_int)
+
+ @mock.patch.object(api_port.PortsController, '_get_ports_collection')
+ def test_detail_with_incorrect_api_usage(self, mock_gpc):
+ # GET /v1/ports/detail specifying node and node_uuid. In this case
+ # we expect the node_uuid interface to be used.
+ self.get_json('/ports/detail?node=%s&node_uuid=%s' %
+ ('test-node', self.node.uuid))
+ mock_gpc.assert_called_once_with(self.node.uuid, mock.ANY, mock.ANY,
+ mock.ANY, mock.ANY, mock.ANY,
+ mock.ANY, mock.ANY)
+
@mock.patch.object(rpcapi.ConductorAPI, 'update_port')
class TestPatch(api_base.FunctionalTest):
diff --git a/ironic/tests/api/v1/test_root.py b/ironic/tests/api/v1/test_root.py
index 7228663f1..35913e60b 100644
--- a/ironic/tests/api/v1/test_root.py
+++ b/ironic/tests/api/v1/test_root.py
@@ -12,6 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
+import mock
from webob import exc as webob_exc
from ironic.api.controllers import v1 as v1_api
@@ -25,7 +26,8 @@ class TestV1Routing(api_base.FunctionalTest):
def test_route_checks_version(self):
self.get_json('/')
- self._check_version.assert_called_once()
+ self._check_version.assert_called_once_with(mock.ANY,
+ mock.ANY)
class TestCheckVersions(test_base.TestCase):
diff --git a/ironic/tests/api/v1/test_utils.py b/ironic/tests/api/v1/test_utils.py
index dda776b97..f55435884 100644
--- a/ironic/tests/api/v1/test_utils.py
+++ b/ironic/tests/api/v1/test_utils.py
@@ -13,13 +13,18 @@
# License for the specific language governing permissions and limitations
# under the License.
+import mock
+from oslo_config import cfg
+from oslo_utils import uuidutils
+import pecan
import wsme
from ironic.api.controllers.v1 import utils
+from ironic.common import exception
+from ironic import objects
+from ironic.tests.api import utils as test_api_utils
from ironic.tests import base
-from oslo_config import cfg
-
CONF = cfg.CONF
@@ -47,3 +52,105 @@ class TestApiUtils(base.TestCase):
self.assertRaises(wsme.exc.ClientSideError,
utils.validate_sort_dir,
'fake-sort')
+
+
+class TestNodeIdent(base.TestCase):
+
+ def setUp(self):
+ super(TestNodeIdent, self).setUp()
+ self.valid_name = 'my-host'
+ self.valid_uuid = uuidutils.generate_uuid()
+ self.invalid_name = 'Mr Plow'
+ self.invalid_uuid = '636-555-3226-'
+ self.node = test_api_utils.post_get_test_node()
+
+ @mock.patch.object(pecan, 'request')
+ def test_allow_node_logical_names_pre_name(self, mock_pecan_req):
+ mock_pecan_req.version.minor = 1
+ self.assertFalse(utils.allow_node_logical_names())
+
+ @mock.patch.object(pecan, 'request')
+ def test_allow_node_logical_names_post_name(self, mock_pecan_req):
+ mock_pecan_req.version.minor = 5
+ self.assertTrue(utils.allow_node_logical_names())
+
+ def test_is_valid_node_name(self):
+ self.assertTrue(utils.is_valid_node_name(self.valid_name))
+ self.assertFalse(utils.is_valid_node_name(self.invalid_name))
+ self.assertFalse(utils.is_valid_node_name(self.valid_uuid))
+ self.assertFalse(utils.is_valid_node_name(self.invalid_uuid))
+
+ @mock.patch.object(pecan, 'request')
+ @mock.patch.object(utils, 'allow_node_logical_names')
+ @mock.patch.object(objects.Node, 'get_by_uuid')
+ @mock.patch.object(objects.Node, 'get_by_name')
+ def test_get_rpc_node_expect_uuid(self, mock_gbn, mock_gbu, mock_anln,
+ mock_pr):
+ mock_anln.return_value = True
+ self.node['uuid'] = self.valid_uuid
+ mock_gbu.return_value = self.node
+ self.assertEqual(self.node, utils.get_rpc_node(self.valid_uuid))
+ self.assertEqual(1, mock_gbu.call_count)
+ self.assertEqual(0, mock_gbn.call_count)
+
+ @mock.patch.object(pecan, 'request')
+ @mock.patch.object(utils, 'allow_node_logical_names')
+ @mock.patch.object(objects.Node, 'get_by_uuid')
+ @mock.patch.object(objects.Node, 'get_by_name')
+ def test_get_rpc_node_expect_name(self, mock_gbn, mock_gbu, mock_anln,
+ mock_pr):
+ mock_anln.return_value = True
+ self.node['name'] = self.valid_name
+ mock_gbn.return_value = self.node
+ self.assertEqual(self.node, utils.get_rpc_node(self.valid_name))
+ self.assertEqual(0, mock_gbu.call_count)
+ self.assertEqual(1, mock_gbn.call_count)
+
+ @mock.patch.object(pecan, 'request')
+ @mock.patch.object(utils, 'allow_node_logical_names')
+ @mock.patch.object(objects.Node, 'get_by_uuid')
+ @mock.patch.object(objects.Node, 'get_by_name')
+ def test_get_rpc_node_invalid_name(self, mock_gbn, mock_gbu,
+ mock_anln, mock_pr):
+ mock_anln.return_value = True
+ self.assertRaises(exception.InvalidUuidOrName,
+ utils.get_rpc_node,
+ self.invalid_name)
+
+ @mock.patch.object(pecan, 'request')
+ @mock.patch.object(utils, 'allow_node_logical_names')
+ @mock.patch.object(objects.Node, 'get_by_uuid')
+ @mock.patch.object(objects.Node, 'get_by_name')
+ def test_get_rpc_node_invalid_uuid(self, mock_gbn, mock_gbu,
+ mock_anln, mock_pr):
+ mock_anln.return_value = True
+ self.assertRaises(exception.InvalidUuidOrName,
+ utils.get_rpc_node,
+ self.invalid_uuid)
+
+ @mock.patch.object(pecan, 'request')
+ @mock.patch.object(utils, 'allow_node_logical_names')
+ @mock.patch.object(objects.Node, 'get_by_uuid')
+ @mock.patch.object(objects.Node, 'get_by_name')
+ def test_get_rpc_node_by_uuid_no_logical_name(self, mock_gbn, mock_gbu,
+ mock_anln, mock_pr):
+ # allow_node_logical_name() should have no effect
+ mock_anln.return_value = False
+ self.node['uuid'] = self.valid_uuid
+ mock_gbu.return_value = self.node
+ self.assertEqual(self.node, utils.get_rpc_node(self.valid_uuid))
+ self.assertEqual(1, mock_gbu.call_count)
+ self.assertEqual(0, mock_gbn.call_count)
+
+ @mock.patch.object(pecan, 'request')
+ @mock.patch.object(utils, 'allow_node_logical_names')
+ @mock.patch.object(objects.Node, 'get_by_uuid')
+ @mock.patch.object(objects.Node, 'get_by_name')
+ def test_get_rpc_node_by_name_no_logical_name(self, mock_gbn, mock_gbu,
+ mock_anln, mock_pr):
+ mock_anln.return_value = False
+ self.node['name'] = self.valid_name
+ mock_gbn.return_value = self.node
+ self.assertRaises(exception.NodeNotFound,
+ utils.get_rpc_node,
+ self.valid_name)
diff --git a/ironic/tests/conductor/test_manager.py b/ironic/tests/conductor/test_manager.py
index e2dd06568..47a6e77f7 100644
--- a/ironic/tests/conductor/test_manager.py
+++ b/ironic/tests/conductor/test_manager.py
@@ -1696,7 +1696,7 @@ class DoNodeCleanTestCase(_ServiceSetUpMixin, tests_db_base.DbTestCase):
node.refresh()
# Assert that the node was moved to available without cleaning
- mock_validate.assert_not_called()
+ self.assertFalse(mock_validate.called)
self.assertEqual(states.AVAILABLE, node.provision_state)
self.assertEqual(states.NOSTATE, node.target_provision_state)
self.assertEqual({}, node.clean_step)
@@ -1725,9 +1725,9 @@ class DoNodeCleanTestCase(_ServiceSetUpMixin, tests_db_base.DbTestCase):
self.service._worker_pool.waitall()
node.refresh()
- mock_validate.assert_called_once()
+ mock_validate.assert_called_once_with(task)
mock_next_step.assert_called_once_with(mock.ANY, [], {})
- mock_steps.assert_called_once()
+ mock_steps.assert_called_once_with(task)
# Check that state didn't change
self.assertEqual(states.CLEANING, node.provision_state)
@@ -1806,7 +1806,7 @@ class DoNodeCleanTestCase(_ServiceSetUpMixin, tests_db_base.DbTestCase):
# Cleaning should be complete without calling additional steps
self.assertEqual(states.AVAILABLE, node.provision_state)
self.assertEqual({}, node.clean_step)
- mock_execute.assert_not_called()
+ self.assertFalse(mock_execute.called)
@mock.patch('ironic.drivers.modules.fake.FakePower.execute_clean_step')
@mock.patch('ironic.drivers.modules.fake.FakeDeploy.execute_clean_step')
@@ -1869,7 +1869,7 @@ class DoNodeCleanTestCase(_ServiceSetUpMixin, tests_db_base.DbTestCase):
self.assertEqual({}, node.clean_step)
self.assertIsNotNone(node.last_error)
self.assertTrue(node.maintenance)
- mock_execute.assert_not_called()
+ self.assertFalse(mock_execute.called)
@mock.patch('ironic.drivers.modules.fake.FakeDeploy.execute_clean_step')
def test__do_next_clean_step_fail(self, mock_execute):
@@ -1897,7 +1897,6 @@ class DoNodeCleanTestCase(_ServiceSetUpMixin, tests_db_base.DbTestCase):
self.assertEqual({}, node.clean_step)
self.assertIsNotNone(node.last_error)
self.assertTrue(node.maintenance)
- mock_execute.assert_not_called()
mock_execute.assert_called_once_with(mock.ANY, self.clean_steps[0])
@mock.patch('ironic.drivers.modules.fake.FakeDeploy.execute_clean_step')
@@ -1923,7 +1922,7 @@ class DoNodeCleanTestCase(_ServiceSetUpMixin, tests_db_base.DbTestCase):
# Cleaning should be complete without calling additional steps
self.assertEqual(states.AVAILABLE, node.provision_state)
self.assertEqual({}, node.clean_step)
- mock_execute.assert_not_called()
+ self.assertFalse(mock_execute.called)
@mock.patch('ironic.drivers.modules.fake.FakePower.execute_clean_step')
@mock.patch('ironic.drivers.modules.fake.FakeDeploy.execute_clean_step')
@@ -2841,7 +2840,7 @@ class ManagerSyncPowerStatesTestCase(_CommonMixIn, tests_db_base.DbTestCase):
mapped_mock.assert_called_once_with(self.node.uuid,
self.node.driver)
get_node_mock.assert_called_once_with(self.context, self.node.id)
- acquire_mock.assert_called_once_with(self.context, self.node.id)
+ acquire_mock.assert_called_once_with(self.context, self.node.uuid)
self.assertFalse(sync_mock.called)
def test_node_in_deploywait_on_acquire(self, get_nodeinfo_mock,
@@ -2853,7 +2852,7 @@ class ManagerSyncPowerStatesTestCase(_CommonMixIn, tests_db_base.DbTestCase):
task = self._create_task(
node_attrs=dict(provision_state=states.DEPLOYWAIT,
target_provision_state=states.ACTIVE,
- id=self.node.id))
+ uuid=self.node.uuid))
acquire_mock.side_effect = self._get_acquire_side_effect(task)
self.service._sync_power_states(self.context)
@@ -2863,7 +2862,7 @@ class ManagerSyncPowerStatesTestCase(_CommonMixIn, tests_db_base.DbTestCase):
mapped_mock.assert_called_once_with(self.node.uuid,
self.node.driver)
get_node_mock.assert_called_once_with(self.context, self.node.id)
- acquire_mock.assert_called_once_with(self.context, self.node.id)
+ acquire_mock.assert_called_once_with(self.context, self.node.uuid)
self.assertFalse(sync_mock.called)
def test_node_in_maintenance_on_acquire(self, get_nodeinfo_mock,
@@ -2873,7 +2872,7 @@ class ManagerSyncPowerStatesTestCase(_CommonMixIn, tests_db_base.DbTestCase):
get_node_mock.return_value = self.node
mapped_mock.return_value = True
task = self._create_task(
- node_attrs=dict(maintenance=True, id=self.node.id))
+ node_attrs=dict(maintenance=True, uuid=self.node.uuid))
acquire_mock.side_effect = self._get_acquire_side_effect(task)
self.service._sync_power_states(self.context)
@@ -2883,7 +2882,7 @@ class ManagerSyncPowerStatesTestCase(_CommonMixIn, tests_db_base.DbTestCase):
mapped_mock.assert_called_once_with(self.node.uuid,
self.node.driver)
get_node_mock.assert_called_once_with(self.context, self.node.id)
- acquire_mock.assert_called_once_with(self.context, self.node.id)
+ acquire_mock.assert_called_once_with(self.context, self.node.uuid)
self.assertFalse(sync_mock.called)
def test_node_disappears_on_acquire(self, get_nodeinfo_mock,
@@ -2902,7 +2901,7 @@ class ManagerSyncPowerStatesTestCase(_CommonMixIn, tests_db_base.DbTestCase):
mapped_mock.assert_called_once_with(self.node.uuid,
self.node.driver)
get_node_mock.assert_called_once_with(self.context, self.node.id)
- acquire_mock.assert_called_once_with(self.context, self.node.id)
+ acquire_mock.assert_called_once_with(self.context, self.node.uuid)
self.assertFalse(sync_mock.called)
def test_single_node(self, get_nodeinfo_mock, get_node_mock,
@@ -2910,7 +2909,7 @@ class ManagerSyncPowerStatesTestCase(_CommonMixIn, tests_db_base.DbTestCase):
get_nodeinfo_mock.return_value = self._get_nodeinfo_list_response()
get_node_mock.return_value = self.node
mapped_mock.return_value = True
- task = self._create_task(node_attrs=dict(id=self.node.id))
+ task = self._create_task(node_attrs=dict(uuid=self.node.uuid))
acquire_mock.side_effect = self._get_acquire_side_effect(task)
self.service._sync_power_states(self.context)
@@ -2920,7 +2919,7 @@ class ManagerSyncPowerStatesTestCase(_CommonMixIn, tests_db_base.DbTestCase):
mapped_mock.assert_called_once_with(self.node.uuid,
self.node.driver)
get_node_mock.assert_called_once_with(self.context, self.node.id)
- acquire_mock.assert_called_once_with(self.context, self.node.id)
+ acquire_mock.assert_called_once_with(self.context, self.node.uuid)
sync_mock.assert_called_once_with(task, mock.ANY)
def test__sync_power_state_multiple_nodes(self, get_nodeinfo_mock,
@@ -2957,16 +2956,16 @@ class ManagerSyncPowerStatesTestCase(_CommonMixIn, tests_db_base.DbTestCase):
mapped_map[n.uuid] = False if i == 2 else True
get_node_map[n.uuid] = n
- tasks = [self._create_task(node_attrs=dict(id=1)),
+ tasks = [self._create_task(node_attrs=dict(uuid=nodes[0].uuid)),
exception.NodeLocked(node=7, host='fake'),
exception.NodeNotFound(node=8, host='fake'),
self._create_task(
- node_attrs=dict(id=9,
+ node_attrs=dict(uuid=nodes[8].uuid,
provision_state=states.DEPLOYWAIT,
target_provision_state=states.ACTIVE)),
self._create_task(
- node_attrs=dict(id=10, maintenance=True)),
- self._create_task(node_attrs=dict(id=11))]
+ node_attrs=dict(uuid=nodes[9].uuid, maintenance=True)),
+ self._create_task(node_attrs=dict(uuid=nodes[10].uuid))]
def _get_node_side_effect(ctxt, node_id):
if node_id == 6:
@@ -2994,7 +2993,7 @@ class ManagerSyncPowerStatesTestCase(_CommonMixIn, tests_db_base.DbTestCase):
for x in nodes[:1] + nodes[2:]]
self.assertEqual(get_node_calls,
get_node_mock.call_args_list)
- acquire_calls = [mock.call(self.context, x.id)
+ acquire_calls = [mock.call(self.context, x.uuid)
for x in nodes[:1] + nodes[6:]]
self.assertEqual(acquire_calls, acquire_mock.call_args_list)
sync_calls = [mock.call(tasks[0], mock.ANY),
@@ -3339,20 +3338,19 @@ class ManagerTestProperties(tests_db_base.DbTestCase):
def test_driver_properties_fake_ilo(self):
expected = ['ilo_address', 'ilo_username', 'ilo_password',
- 'client_port', 'client_timeout', 'inspect_ports',
- 'ilo_change_password']
+ 'client_port', 'client_timeout', 'ilo_change_password']
self._check_driver_properties("fake_ilo", expected)
def test_driver_properties_ilo_iscsi(self):
expected = ['ilo_address', 'ilo_username', 'ilo_password',
'client_port', 'client_timeout', 'ilo_deploy_iso',
- 'console_port', 'inspect_ports', 'ilo_change_password']
+ 'console_port', 'ilo_change_password']
self._check_driver_properties("iscsi_ilo", expected)
def test_driver_properties_agent_ilo(self):
expected = ['ilo_address', 'ilo_username', 'ilo_password',
'client_port', 'client_timeout', 'ilo_deploy_iso',
- 'console_port', 'inspect_ports', 'ilo_change_password']
+ 'console_port', 'ilo_change_password']
self._check_driver_properties("agent_ilo", expected)
def test_driver_properties_fail(self):
@@ -3437,7 +3435,7 @@ class ManagerSyncLocalStateTestCase(_CommonMixIn, tests_db_base.DbTestCase):
self._assert_get_nodeinfo_args(get_nodeinfo_mock)
mapped_mock.assert_called_once_with(self.node.uuid, self.node.driver)
get_authtoken_mock.assert_called_once_with()
- acquire_mock.assert_called_once_with(self.context, self.node.id)
+ acquire_mock.assert_called_once_with(self.context, self.node.uuid)
# assert spawn_after has been called
self.task.spawn_after.assert_called_once_with(
self.service._spawn_worker,
@@ -3471,7 +3469,7 @@ class ManagerSyncLocalStateTestCase(_CommonMixIn, tests_db_base.DbTestCase):
# assert acquire() gets called 2 times only instead of 3. When
# NoFreeConductorWorker is raised the loop should be broken
- expected = [mock.call(self.context, self.node.id)] * 2
+ expected = [mock.call(self.context, self.node.uuid)] * 2
self.assertEqual(expected, acquire_mock.call_args_list)
# Only one auth token needed for all runs
@@ -3504,7 +3502,7 @@ class ManagerSyncLocalStateTestCase(_CommonMixIn, tests_db_base.DbTestCase):
self.assertEqual(expected, mapped_mock.call_args_list)
# assert acquire() gets called 3 times
- expected = [mock.call(self.context, self.node.id)] * 3
+ expected = [mock.call(self.context, self.node.uuid)] * 3
self.assertEqual(expected, acquire_mock.call_args_list)
# Only one auth token needed for all runs
@@ -3539,7 +3537,7 @@ class ManagerSyncLocalStateTestCase(_CommonMixIn, tests_db_base.DbTestCase):
mapped_mock.assert_called_once_with(self.node.uuid, self.node.driver)
# assert acquire() gets called only once because of the worker limit
- acquire_mock.assert_called_once_with(self.context, self.node.id)
+ acquire_mock.assert_called_once_with(self.context, self.node.uuid)
# Only one auth token needed for all runs
get_authtoken_mock.assert_called_once_with()
diff --git a/ironic/tests/db/sqlalchemy/test_migrations.py b/ironic/tests/db/sqlalchemy/test_migrations.py
index b6ba0e095..37b539e02 100644
--- a/ironic/tests/db/sqlalchemy/test_migrations.py
+++ b/ironic/tests/db/sqlalchemy/test_migrations.py
@@ -15,15 +15,9 @@
# under the License.
"""
-Tests for database migrations. This test case reads the configuration
-file test_migrations.conf for database connection settings
-to use in the tests. For each connection found in the config file,
-the test case runs a series of test cases to ensure that migrations work
-properly.
-
-There are also "opportunistic" tests for both mysql and postgresql in here,
-which allows testing against all 3 databases (sqlite in memory, mysql, pg) in
-a properly configured unit test environment.
+Tests for database migrations. There are "opportunistic" tests for both mysql
+and postgresql in here, which allows testing against these databases in a
+properly configured unit test environment.
For the opportunistic testing you need to set up a db named 'openstack_citest'
with user 'openstack_citest' and password 'openstack_citest' on localhost.
@@ -314,12 +308,8 @@ class MigrationCheckersMixin(object):
'instance_uuid': instance_uuid}
nodes.insert().values(data).execute()
data['uuid'] = uuidutils.generate_uuid()
- # TODO(viktors): Remove check on sqlalchemy.exc.IntegrityError, when
- # Ironic will use oslo_db 0.4.0 or higher.
- # See bug #1214341 for details.
- self.assertRaises(
- (sqlalchemy.exc.IntegrityError, db_exc.DBDuplicateEntry),
- nodes.insert().execute, data)
+ self.assertRaises(db_exc.DBDuplicateEntry,
+ nodes.insert().execute, data)
def _check_242cc6a923b3(self, engine, data):
nodes = db_utils.get_table(engine, 'nodes')
@@ -374,6 +364,15 @@ class MigrationCheckersMixin(object):
self.assertIsInstance(nodes.c.clean_step.type,
sqlalchemy.types.String)
+ def _check_2fb93ffd2af1(self, engine, data):
+ nodes = db_utils.get_table(engine, 'nodes')
+ bigstring = 'a' * 255
+ uuid = uuidutils.generate_uuid()
+ data = {'uuid': uuid, 'name': bigstring}
+ nodes.insert().execute(data)
+ node = nodes.select(nodes.c.uuid == uuid).execute().first()
+ self.assertEqual(bigstring, node['name'])
+
def test_upgrade_and_version(self):
with patch_with_engine(self.engine):
self.migration_api.upgrade('head')
diff --git a/ironic/tests/db/test_chassis.py b/ironic/tests/db/test_chassis.py
index de81e756e..480d4e6cd 100644
--- a/ironic/tests/db/test_chassis.py
+++ b/ironic/tests/db/test_chassis.py
@@ -25,40 +25,36 @@ from ironic.tests.db import utils
class DbChassisTestCase(base.DbTestCase):
- def _create_test_chassis(self, **kwargs):
- ch = utils.get_test_chassis(**kwargs)
- self.dbapi.create_chassis(ch)
- return ch
+ def setUp(self):
+ super(DbChassisTestCase, self).setUp()
+ self.chassis = utils.create_test_chassis()
def test_get_chassis_list(self):
- uuids = []
+ uuids = [self.chassis.uuid]
for i in range(1, 6):
- n = utils.get_test_chassis(id=i, uuid=uuidutils.generate_uuid())
- self.dbapi.create_chassis(n)
- uuids.append(six.text_type(n['uuid']))
+ ch = utils.create_test_chassis(uuid=uuidutils.generate_uuid())
+ uuids.append(six.text_type(ch.uuid))
res = self.dbapi.get_chassis_list()
res_uuids = [r.uuid for r in res]
- self.assertEqual(uuids.sort(), res_uuids.sort())
+ six.assertCountEqual(self, uuids, res_uuids)
def test_get_chassis_by_id(self):
- ch = self._create_test_chassis()
- chassis = self.dbapi.get_chassis_by_id(ch['id'])
+ chassis = self.dbapi.get_chassis_by_id(self.chassis.id)
- self.assertEqual(ch['uuid'], chassis.uuid)
+ self.assertEqual(self.chassis.uuid, chassis.uuid)
def test_get_chassis_by_uuid(self):
- ch = self._create_test_chassis()
- chassis = self.dbapi.get_chassis_by_uuid(ch['uuid'])
+ chassis = self.dbapi.get_chassis_by_uuid(self.chassis.uuid)
- self.assertEqual(ch['id'], chassis.id)
+ self.assertEqual(self.chassis.id, chassis.id)
def test_get_chassis_that_does_not_exist(self):
self.assertRaises(exception.ChassisNotFound,
self.dbapi.get_chassis_by_id, 666)
def test_update_chassis(self):
- ch = self._create_test_chassis()
- res = self.dbapi.update_chassis(ch['id'], {'description': 'hello'})
+ res = self.dbapi.update_chassis(self.chassis.id,
+ {'description': 'hello'})
self.assertEqual('hello', res.description)
@@ -67,32 +63,27 @@ class DbChassisTestCase(base.DbTestCase):
self.dbapi.update_chassis, 666, {'description': ''})
def test_update_chassis_uuid(self):
- ch = self._create_test_chassis()
self.assertRaises(exception.InvalidParameterValue,
- self.dbapi.update_chassis, ch['id'],
+ self.dbapi.update_chassis, self.chassis.id,
{'uuid': 'hello'})
def test_destroy_chassis(self):
- ch = self._create_test_chassis()
- self.dbapi.destroy_chassis(ch['id'])
+ self.dbapi.destroy_chassis(self.chassis.id)
self.assertRaises(exception.ChassisNotFound,
- self.dbapi.get_chassis_by_id, ch['id'])
+ self.dbapi.get_chassis_by_id, self.chassis.id)
def test_destroy_chassis_that_does_not_exist(self):
self.assertRaises(exception.ChassisNotFound,
self.dbapi.destroy_chassis, 666)
def test_destroy_chassis_with_nodes(self):
- ch = self._create_test_chassis()
- utils.create_test_node(chassis_id=ch['id'])
+ utils.create_test_node(chassis_id=self.chassis.id)
self.assertRaises(exception.ChassisNotEmpty,
- self.dbapi.destroy_chassis, ch['id'])
+ self.dbapi.destroy_chassis, self.chassis.id)
def test_create_chassis_already_exists(self):
- uuid = uuidutils.generate_uuid()
- self._create_test_chassis(id=1, uuid=uuid)
self.assertRaises(exception.ChassisAlreadyExists,
- self._create_test_chassis,
- id=2, uuid=uuid)
+ utils.create_test_chassis,
+ uuid=self.chassis.uuid)
diff --git a/ironic/tests/db/test_conductor.py b/ironic/tests/db/test_conductor.py
index d93aad120..1ff182615 100644
--- a/ironic/tests/db/test_conductor.py
+++ b/ironic/tests/db/test_conductor.py
@@ -64,7 +64,7 @@ class DbConductorTestCase(base.DbTestCase):
self.dbapi.unregister_conductor,
c.hostname)
- @mock.patch.object(timeutils, 'utcnow')
+ @mock.patch.object(timeutils, 'utcnow', autospec=True)
def test_touch_conductor(self, mock_utcnow):
test_time = datetime.datetime(2000, 1, 1, 0, 0)
mock_utcnow.return_value = test_time
@@ -110,7 +110,7 @@ class DbConductorTestCase(base.DbTestCase):
self.assertEqual('hostname2', node2.reservation)
self.assertIsNone(node3.reservation)
- @mock.patch.object(timeutils, 'utcnow')
+ @mock.patch.object(timeutils, 'utcnow', autospec=True)
def test_get_active_driver_dict_one_host_no_driver(self, mock_utcnow):
h = 'fake-host'
expected = {}
@@ -120,7 +120,7 @@ class DbConductorTestCase(base.DbTestCase):
result = self.dbapi.get_active_driver_dict()
self.assertEqual(expected, result)
- @mock.patch.object(timeutils, 'utcnow')
+ @mock.patch.object(timeutils, 'utcnow', autospec=True)
def test_get_active_driver_dict_one_host_one_driver(self, mock_utcnow):
h = 'fake-host'
d = 'fake-driver'
@@ -131,7 +131,7 @@ class DbConductorTestCase(base.DbTestCase):
result = self.dbapi.get_active_driver_dict()
self.assertEqual(expected, result)
- @mock.patch.object(timeutils, 'utcnow')
+ @mock.patch.object(timeutils, 'utcnow', autospec=True)
def test_get_active_driver_dict_one_host_many_drivers(self, mock_utcnow):
h = 'fake-host'
d1 = 'driver-one'
@@ -143,7 +143,7 @@ class DbConductorTestCase(base.DbTestCase):
result = self.dbapi.get_active_driver_dict()
self.assertEqual(expected, result)
- @mock.patch.object(timeutils, 'utcnow')
+ @mock.patch.object(timeutils, 'utcnow', autospec=True)
def test_get_active_driver_dict_many_hosts_one_driver(self, mock_utcnow):
h1 = 'host-one'
h2 = 'host-two'
@@ -156,7 +156,7 @@ class DbConductorTestCase(base.DbTestCase):
result = self.dbapi.get_active_driver_dict()
self.assertEqual(expected, result)
- @mock.patch.object(timeutils, 'utcnow')
+ @mock.patch.object(timeutils, 'utcnow', autospec=True)
def test_get_active_driver_dict_many_hosts_and_drivers(self, mock_utcnow):
h1 = 'host-one'
h2 = 'host-two'
@@ -172,7 +172,7 @@ class DbConductorTestCase(base.DbTestCase):
result = self.dbapi.get_active_driver_dict()
self.assertEqual(expected, result)
- @mock.patch.object(timeutils, 'utcnow')
+ @mock.patch.object(timeutils, 'utcnow', autospec=True)
def test_get_active_driver_dict_with_old_conductor(self, mock_utcnow):
past = datetime.datetime(2000, 1, 1, 0, 0)
present = past + datetime.timedelta(minutes=2)
diff --git a/ironic/tests/db/test_nodes.py b/ironic/tests/db/test_nodes.py
index 35c542e5e..be44943b4 100644
--- a/ironic/tests/db/test_nodes.py
+++ b/ironic/tests/db/test_nodes.py
@@ -33,9 +33,6 @@ class DbNodeTestCase(base.DbTestCase):
def test_create_node(self):
utils.create_test_node()
- def test_create_node_nullable_chassis_id(self):
- utils.create_test_node(chassis_id=None)
-
def test_create_node_already_exists(self):
utils.create_test_node()
self.assertRaises(exception.NodeAlreadyExists,
@@ -139,7 +136,7 @@ class DbNodeTestCase(base.DbTestCase):
res = self.dbapi.get_node_list(filters={'maintenance': False})
self.assertEqual([node1.id], [r.id for r in res])
- @mock.patch.object(timeutils, 'utcnow')
+ @mock.patch.object(timeutils, 'utcnow', autospec=True)
def test_get_nodeinfo_list_provision(self, mock_utcnow):
past = datetime.datetime(2000, 1, 1, 0, 0)
next = past + datetime.timedelta(minutes=8)
@@ -164,7 +161,7 @@ class DbNodeTestCase(base.DbTestCase):
states.DEPLOYWAIT})
self.assertEqual([node2.id], [r[0] for r in res])
- @mock.patch.object(timeutils, 'utcnow')
+ @mock.patch.object(timeutils, 'utcnow', autospec=True)
def test_get_nodeinfo_list_inspection(self, mock_utcnow):
past = datetime.datetime(2000, 1, 1, 0, 0)
next = past + datetime.timedelta(minutes=8)
@@ -197,13 +194,11 @@ class DbNodeTestCase(base.DbTestCase):
uuids.append(six.text_type(node['uuid']))
res = self.dbapi.get_node_list()
res_uuids = [r.uuid for r in res]
- self.assertEqual(uuids.sort(), res_uuids.sort())
+ six.assertCountEqual(self, uuids, res_uuids)
def test_get_node_list_with_filters(self):
- ch1 = utils.get_test_chassis(id=1, uuid=uuidutils.generate_uuid())
- ch2 = utils.get_test_chassis(id=2, uuid=uuidutils.generate_uuid())
- self.dbapi.create_chassis(ch1)
- self.dbapi.create_chassis(ch2)
+ ch1 = utils.create_test_chassis(uuid=uuidutils.generate_uuid())
+ ch2 = utils.create_test_chassis(uuid=uuidutils.generate_uuid())
node1 = utils.create_test_node(driver='driver-one',
instance_uuid=uuidutils.generate_uuid(),
@@ -359,7 +354,7 @@ class DbNodeTestCase(base.DbTestCase):
node2.id,
{'instance_uuid': new_i_uuid})
- @mock.patch.object(timeutils, 'utcnow')
+ @mock.patch.object(timeutils, 'utcnow', autospec=True)
def test_update_node_provision(self, mock_utcnow):
mocked_time = datetime.datetime(2000, 1, 1, 0, 0)
mock_utcnow.return_value = mocked_time
@@ -383,7 +378,7 @@ class DbNodeTestCase(base.DbTestCase):
self.assertIsNone(res['provision_updated_at'])
self.assertIsNone(res['inspection_started_at'])
- @mock.patch.object(timeutils, 'utcnow')
+ @mock.patch.object(timeutils, 'utcnow', autospec=True)
def test_update_node_inspection_started_at(self, mock_utcnow):
mocked_time = datetime.datetime(2000, 1, 1, 0, 0)
mock_utcnow.return_value = mocked_time
@@ -395,7 +390,7 @@ class DbNodeTestCase(base.DbTestCase):
timeutils.normalize_time(result))
self.assertIsNone(res['inspection_finished_at'])
- @mock.patch.object(timeutils, 'utcnow')
+ @mock.patch.object(timeutils, 'utcnow', autospec=True)
def test_update_node_inspection_finished_at(self, mock_utcnow):
mocked_time = datetime.datetime(2000, 1, 1, 0, 0)
mock_utcnow.return_value = mocked_time
diff --git a/ironic/tests/db/test_ports.py b/ironic/tests/db/test_ports.py
index afb1284e4..947de11a1 100644
--- a/ironic/tests/db/test_ports.py
+++ b/ironic/tests/db/test_ports.py
@@ -50,9 +50,11 @@ class DbPortTestCase(base.DbTestCase):
port = db_utils.create_test_port(uuid=uuidutils.generate_uuid(),
address='52:54:00:cf:2d:4%s' % i)
uuids.append(six.text_type(port.uuid))
+ # Also add the uuid for the port created in setUp()
+ uuids.append(six.text_type(self.port.uuid))
res = self.dbapi.get_port_list()
res_uuids = [r.uuid for r in res]
- self.assertEqual(uuids.sort(), res_uuids.sort())
+ six.assertCountEqual(self, uuids, res_uuids)
def test_get_ports_by_node_id(self):
res = self.dbapi.get_ports_by_node_id(self.node.id)
diff --git a/ironic/tests/db/utils.py b/ironic/tests/db/utils.py
index 677187e80..dbb8e8d95 100644
--- a/ironic/tests/db/utils.py
+++ b/ironic/tests/db/utils.py
@@ -149,6 +149,7 @@ def get_test_agent_driver_info():
def get_test_agent_driver_internal_info():
return {
'agent_url': 'http://127.0.0.1/foo',
+ 'is_whole_disk_image': True,
}
@@ -187,7 +188,7 @@ def get_test_node(**kw):
'id': kw.get('id', 123),
'name': kw.get('name', None),
'uuid': kw.get('uuid', '1be26c0b-03f2-4d2e-ae87-c02d7f33c123'),
- 'chassis_id': kw.get('chassis_id', 42),
+ 'chassis_id': kw.get('chassis_id', None),
'conductor_affinity': kw.get('conductor_affinity', None),
'power_state': kw.get('power_state', states.NOSTATE),
'target_power_state': kw.get('target_power_state', states.NOSTATE),
@@ -272,6 +273,23 @@ def get_test_chassis(**kw):
}
+def create_test_chassis(**kw):
+ """Create test chassis entry in DB and return Chassis DB object.
+
+ Function to be used to create test Chassis objects in the database.
+
+ :param kw: kwargs with overriding values for chassis's attributes.
+ :returns: Test Chassis DB object.
+
+ """
+ chassis = get_test_chassis(**kw)
+ # Let DB generate ID if it isn't specified explicitly
+ if 'id' not in kw:
+ del chassis['id']
+ dbapi = db_api.get_instance()
+ return dbapi.create_chassis(chassis)
+
+
def get_test_conductor(**kw):
return {
'id': kw.get('id', 6),
diff --git a/ironic/tests/dhcp/test_factory.py b/ironic/tests/dhcp/test_factory.py
index 37ce4c040..850479f8f 100644
--- a/ironic/tests/dhcp/test_factory.py
+++ b/ironic/tests/dhcp/test_factory.py
@@ -13,10 +13,13 @@
# License for the specific language governing permissions and limitations
# under the License.
+import inspect
+
import mock
from ironic.common import dhcp_factory
from ironic.common import exception
+from ironic.dhcp import base as base_class
from ironic.dhcp import neutron
from ironic.dhcp import none
from ironic.tests import base
@@ -68,3 +71,35 @@ class TestDHCPFactory(base.TestCase):
group='dhcp')
self.assertRaises(exception.DHCPNotFound, dhcp_factory.DHCPFactory)
+
+
+class CompareBasetoModules(base.TestCase):
+
+ def test_drivers_match_dhcp_base(self):
+ def _get_public_apis(inst):
+ methods = {}
+ for (name, value) in inspect.getmembers(inst, inspect.ismethod):
+ if name.startswith("_"):
+ continue
+ methods[name] = value
+ return methods
+
+ def _compare_classes(baseclass, driverclass):
+
+ basemethods = _get_public_apis(baseclass)
+ implmethods = _get_public_apis(driverclass)
+
+ for name in basemethods:
+ baseargs = inspect.getargspec(basemethods[name])
+ implargs = inspect.getargspec(implmethods[name])
+ self.assertEqual(
+ baseargs,
+ implargs,
+ "%s args of %s don't match base %s" % (
+ name,
+ driverclass,
+ baseclass)
+ )
+
+ _compare_classes(base_class.BaseDHCP, none.NoneDHCPApi)
+ _compare_classes(base_class.BaseDHCP, neutron.NeutronDHCPApi)
diff --git a/ironic/tests/dhcp/test_neutron.py b/ironic/tests/dhcp/test_neutron.py
index 4cb4402f6..11a716fa9 100644
--- a/ironic/tests/dhcp/test_neutron.py
+++ b/ironic/tests/dhcp/test_neutron.py
@@ -377,23 +377,25 @@ class TestNeutron(db_base.DbTestCase):
'network_id': '00000000-0000-0000-0000-000000000000',
'admin_state_up': True, 'mac_address': self.ports[0].address}})
- @mock.patch('ironic.conductor.manager.cleaning_error_handler')
+ @mock.patch.object(neutron.NeutronDHCPApi, '_rollback_cleaning_ports')
@mock.patch.object(client.Client, 'create_port')
- def test_create_cleaning_ports_fail(self, create_mock, error_mock):
- # Check that if creating a port fails, the node goes to cleanfail
+ def test_create_cleaning_ports_fail(self, create_mock, rollback_mock):
+ # Check that if creating a port fails, the ports are cleaned up
create_mock.side_effect = neutron_client_exc.ConnectionFailed
api = dhcp_factory.DHCPFactory().provider
with task_manager.acquire(self.context, self.node.uuid) as task:
- api.create_cleaning_ports(task)
- error_mock.assert_called_once_with(task, mock.ANY)
+ self.assertRaises(exception.NodeCleaningFailure,
+ api.create_cleaning_ports,
+ task)
create_mock.assert_called_once_with({'port': {
'network_id': '00000000-0000-0000-0000-000000000000',
'admin_state_up': True, 'mac_address': self.ports[0].address}})
+ rollback_mock.assert_called_once_with(task)
- @mock.patch('ironic.conductor.manager.cleaning_error_handler')
@mock.patch.object(client.Client, 'create_port')
- def test_create_cleaning_ports_bad_config(self, create_mock, error_mock):
+ def test_create_cleaning_ports_bad_config(self, create_mock):
+ # Check an error is raised if the cleaning network is not set
self.config(cleaning_network_uuid=None, group='neutron')
api = dhcp_factory.DHCPFactory().provider
@@ -417,32 +419,31 @@ class TestNeutron(db_base.DbTestCase):
network_id='00000000-0000-0000-0000-000000000000')
delete_mock.assert_called_once_with(self.neutron_port['id'])
- @mock.patch('ironic.conductor.manager.cleaning_error_handler')
@mock.patch.object(client.Client, 'list_ports')
- def test_delete_cleaning_ports_list_fail(self, list_mock, error_mock):
+ def test_delete_cleaning_ports_list_fail(self, list_mock):
# Check that if listing ports fails, the node goes to cleanfail
list_mock.side_effect = neutron_client_exc.ConnectionFailed
api = dhcp_factory.DHCPFactory().provider
with task_manager.acquire(self.context, self.node.uuid) as task:
- api.delete_cleaning_ports(task)
+ self.assertRaises(exception.NodeCleaningFailure,
+ api.delete_cleaning_ports,
+ task)
list_mock.assert_called_once_with(
network_id='00000000-0000-0000-0000-000000000000')
- error_mock.assert_called_once_with(task, mock.ANY)
- @mock.patch('ironic.conductor.manager.cleaning_error_handler')
@mock.patch.object(client.Client, 'delete_port')
@mock.patch.object(client.Client, 'list_ports')
- def test_delete_cleaning_ports_delete_fail(self, list_mock, delete_mock,
- error_mock):
+ def test_delete_cleaning_ports_delete_fail(self, list_mock, delete_mock):
# Check that if deleting ports fails, the node goes to cleanfail
list_mock.return_value = {'ports': [self.neutron_port]}
delete_mock.side_effect = neutron_client_exc.ConnectionFailed
api = dhcp_factory.DHCPFactory().provider
with task_manager.acquire(self.context, self.node.uuid) as task:
- api.delete_cleaning_ports(task)
+ self.assertRaises(exception.NodeCleaningFailure,
+ api.delete_cleaning_ports,
+ task)
list_mock.assert_called_once_with(
network_id='00000000-0000-0000-0000-000000000000')
delete_mock.assert_called_once_with(self.neutron_port['id'])
- error_mock.assert_called_once_with(task, mock.ANY)
diff --git a/ironic/tests/drivers/agent_pxe_config.template b/ironic/tests/drivers/agent_pxe_config.template
index 414703a1c..7b26d58cf 100644
--- a/ironic/tests/drivers/agent_pxe_config.template
+++ b/ironic/tests/drivers/agent_pxe_config.template
@@ -2,4 +2,4 @@ default deploy
label deploy
kernel /tftpboot/1be26c0b-03f2-4d2e-ae87-c02d7f33c123/deploy_kernel
-append initrd=/tftpboot/1be26c0b-03f2-4d2e-ae87-c02d7f33c123/deploy_ramdisk text test_param ipa-api-url=http://192.168.122.184:6385 ipa-driver-name=agent_ipmitool root_device=vendor=fake,size=123
+append initrd=/tftpboot/1be26c0b-03f2-4d2e-ae87-c02d7f33c123/deploy_ramdisk text test_param ipa-api-url=http://192.168.122.184:6385 ipa-driver-name=agent_ipmitool root_device=vendor=fake,size=123 coreos.configdrive=0
diff --git a/ironic/tests/drivers/amt/test_vendor.py b/ironic/tests/drivers/amt/test_vendor.py
index 1d1742918..a6ddfc769 100644
--- a/ironic/tests/drivers/amt/test_vendor.py
+++ b/ironic/tests/drivers/amt/test_vendor.py
@@ -37,7 +37,8 @@ class AMTPXEVendorPassthruTestCase(db_base.DbTestCase):
driver='pxe_amt', driver_info=INFO_DICT)
def test_vendor_routes(self):
- expected = ['heartbeat', 'pass_deploy_info']
+ expected = ['heartbeat', 'pass_deploy_info',
+ 'pass_bootloader_install_info']
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
vendor_routes = task.driver.vendor.vendor_routes
@@ -54,13 +55,64 @@ class AMTPXEVendorPassthruTestCase(db_base.DbTestCase):
@mock.patch.object(amt_mgmt.AMTManagement, 'ensure_next_boot_device')
@mock.patch.object(pxe.VendorPassthru, 'pass_deploy_info')
- def test_vendorpassthru_pass_deploy_info(self, mock_pxe_vendorpassthru,
- mock_ensure):
+ def test_vendorpassthru_pass_deploy_info_netboot(self,
+ mock_pxe_vendorpassthru,
+ mock_ensure):
kwargs = {'address': '123456'}
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
task.node.provision_state = states.DEPLOYWAIT
task.node.target_provision_state = states.ACTIVE
+ task.node.instance_info['capabilities'] = {
+ "boot_option": "netboot"
+ }
task.driver.vendor.pass_deploy_info(task, **kwargs)
mock_ensure.assert_called_with(task.node, boot_devices.PXE)
mock_pxe_vendorpassthru.assert_called_once_with(task, **kwargs)
+
+ @mock.patch.object(amt_mgmt.AMTManagement, 'ensure_next_boot_device')
+ @mock.patch.object(pxe.VendorPassthru, 'pass_deploy_info')
+ def test_vendorpassthru_pass_deploy_info_localboot(self,
+ mock_pxe_vendorpassthru,
+ mock_ensure):
+ kwargs = {'address': '123456'}
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=False) as task:
+ task.node.provision_state = states.DEPLOYWAIT
+ task.node.target_provision_state = states.ACTIVE
+ task.node.instance_info['capabilities'] = {"boot_option": "local"}
+ task.driver.vendor.pass_deploy_info(task, **kwargs)
+ self.assertFalse(mock_ensure.called)
+ mock_pxe_vendorpassthru.assert_called_once_with(task, **kwargs)
+
+ @mock.patch.object(amt_mgmt.AMTManagement, 'ensure_next_boot_device')
+ @mock.patch.object(pxe.VendorPassthru, 'continue_deploy')
+ def test_vendorpassthru_continue_deploy_netboot(self,
+ mock_pxe_vendorpassthru,
+ mock_ensure):
+ kwargs = {'address': '123456'}
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=False) as task:
+ task.node.provision_state = states.DEPLOYWAIT
+ task.node.target_provision_state = states.ACTIVE
+ task.node.instance_info['capabilities'] = {
+ "boot_option": "netboot"
+ }
+ task.driver.vendor.continue_deploy(task, **kwargs)
+ mock_ensure.assert_called_with(task.node, boot_devices.PXE)
+ mock_pxe_vendorpassthru.assert_called_once_with(task, **kwargs)
+
+ @mock.patch.object(amt_mgmt.AMTManagement, 'ensure_next_boot_device')
+ @mock.patch.object(pxe.VendorPassthru, 'continue_deploy')
+ def test_vendorpassthru_continue_deploy_localboot(self,
+ mock_pxe_vendorpassthru,
+ mock_ensure):
+ kwargs = {'address': '123456'}
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=False) as task:
+ task.node.provision_state = states.DEPLOYWAIT
+ task.node.target_provision_state = states.ACTIVE
+ task.node.instance_info['capabilities'] = {"boot_option": "local"}
+ task.driver.vendor.continue_deploy(task, **kwargs)
+ self.assertFalse(mock_ensure.called)
+ mock_pxe_vendorpassthru.assert_called_once_with(task, **kwargs)
diff --git a/ironic/tests/drivers/drac/test_client.py b/ironic/tests/drivers/drac/test_client.py
index a5df57bd6..247f34253 100644
--- a/ironic/tests/drivers/drac/test_client.py
+++ b/ironic/tests/drivers/drac/test_client.py
@@ -15,6 +15,7 @@
Test class for DRAC client wrapper.
"""
+import time
from xml.etree import ElementTree
import mock
@@ -51,6 +52,25 @@ class DracClientTestCase(base.TestCase):
None, self.resource_uri)
mock_xml.context.assert_called_once_with()
+ @mock.patch.object(time, 'sleep', lambda seconds: None)
+ def test_wsman_enumerate_retry(self, mock_client_pywsman):
+ mock_xml = test_utils.mock_wsman_root('<test></test>')
+ mock_pywsman_client = mock_client_pywsman.Client.return_value
+ mock_pywsman_client.enumerate.side_effect = [None, mock_xml]
+
+ client = drac_client.Client(**INFO_DICT)
+ client.wsman_enumerate(self.resource_uri)
+
+ mock_options = mock_client_pywsman.ClientOptions.return_value
+ mock_options.set_flags.assert_called_once_with(
+ mock_client_pywsman.FLAG_ENUMERATION_OPTIMIZATION)
+ mock_options.set_max_elements.assert_called_once_with(100)
+ mock_pywsman_client.enumerate.assert_has_calls([
+ mock.call(mock_options, None, self.resource_uri),
+ mock.call(mock_options, None, self.resource_uri)
+ ])
+ mock_xml.context.assert_called_once_with()
+
def test_wsman_enumerate_with_additional_pull(self, mock_client_pywsman):
mock_root = mock.Mock()
mock_root.string.side_effect = [test_utils.build_soap_xml(
@@ -118,6 +138,24 @@ class DracClientTestCase(base.TestCase):
mock_pywsman_client.invoke.assert_called_once_with(mock_options,
self.resource_uri, method_name, None)
+ @mock.patch.object(time, 'sleep', lambda seconds: None)
+ def test_wsman_invoke_retry(self, mock_client_pywsman):
+ result_xml = test_utils.build_soap_xml(
+ [{'ReturnValue': drac_client.RET_SUCCESS}], self.resource_uri)
+ mock_xml = test_utils.mock_wsman_root(result_xml)
+ mock_pywsman_client = mock_client_pywsman.Client.return_value
+ mock_pywsman_client.invoke.side_effect = [None, mock_xml]
+
+ method_name = 'method'
+ client = drac_client.Client(**INFO_DICT)
+ client.wsman_invoke(self.resource_uri, method_name)
+
+ mock_options = mock_client_pywsman.ClientOptions.return_value
+ mock_pywsman_client.invoke.assert_has_calls([
+ mock.call(mock_options, self.resource_uri, method_name, None),
+ mock.call(mock_options, self.resource_uri, method_name, None)
+ ])
+
def test_wsman_invoke_with_selectors(self, mock_client_pywsman):
result_xml = test_utils.build_soap_xml(
[{'ReturnValue': drac_client.RET_SUCCESS}], self.resource_uri)
diff --git a/ironic/tests/drivers/drac/test_power.py b/ironic/tests/drivers/drac/test_power.py
index a3fd5fc06..796368d24 100644
--- a/ironic/tests/drivers/drac/test_power.py
+++ b/ironic/tests/drivers/drac/test_power.py
@@ -137,7 +137,6 @@ class DracPowerTestCase(base.DbTestCase):
@mock.patch.object(drac_power, '_set_power_state')
def test_set_power_state(self, mock_set_power_state):
- mock_set_power_state.return_value = states.POWER_ON
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
task.driver.power.set_power_state(task, states.POWER_ON)
@@ -145,10 +144,22 @@ class DracPowerTestCase(base.DbTestCase):
states.POWER_ON)
@mock.patch.object(drac_power, '_set_power_state')
- def test_reboot(self, mock_set_power_state):
- mock_set_power_state.return_value = states.REBOOT
+ @mock.patch.object(drac_power, '_get_power_state')
+ def test_reboot(self, mock_get_power_state, mock_set_power_state):
+ mock_get_power_state.return_value = states.POWER_ON
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
task.driver.power.reboot(task)
mock_set_power_state.assert_called_once_with(task.node,
states.REBOOT)
+
+ @mock.patch.object(drac_power, '_set_power_state')
+ @mock.patch.object(drac_power, '_get_power_state')
+ def test_reboot_in_power_off(self, mock_get_power_state,
+ mock_set_power_state):
+ mock_get_power_state.return_value = states.POWER_OFF
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=False) as task:
+ task.driver.power.reboot(task)
+ mock_set_power_state.assert_called_once_with(task.node,
+ states.POWER_ON) \ No newline at end of file
diff --git a/ironic/tests/drivers/elilo_efi_pxe_config.template b/ironic/tests/drivers/elilo_efi_pxe_config.template
new file mode 100644
index 000000000..0dca09d8c
--- /dev/null
+++ b/ironic/tests/drivers/elilo_efi_pxe_config.template
@@ -0,0 +1,16 @@
+default=deploy
+
+image=/tftpboot/1be26c0b-03f2-4d2e-ae87-c02d7f33c123/deploy_kernel
+ label=deploy
+ initrd=/tftpboot/1be26c0b-03f2-4d2e-ae87-c02d7f33c123/deploy_ramdisk
+ append="selinux=0 disk=cciss/c0d0,sda,hda,vda iscsi_target_iqn=iqn-1be26c0b-03f2-4d2e-ae87-c02d7f33c123 deployment_id=1be26c0b-03f2-4d2e-ae87-c02d7f33c123 deployment_key=0123456789ABCDEFGHIJKLMNOPQRSTUV ironic_api_url=http://192.168.122.184:6385 troubleshoot=0 text test_param ip=%I::%G:%M:%H::on root_device=vendor=fake,size=123 ipa-api-url=http://192.168.122.184:6385 ipa-driver-name=pxe_ssh boot_option=netboot boot_mode=uefi coreos.configdrive=0"
+
+
+image=/tftpboot/1be26c0b-03f2-4d2e-ae87-c02d7f33c123/kernel
+ label=boot_partition
+ initrd=/tftpboot/1be26c0b-03f2-4d2e-ae87-c02d7f33c123/ramdisk
+ append="root={{ ROOT }} ro text test_param ip=%I::%G:%M:%H::on"
+
+image=chain.c32
+ label=boot_whole_disk
+ append="mbr:{{ DISK_IDENTIFIER }}"
diff --git a/ironic/tests/drivers/ilo/test_common.py b/ironic/tests/drivers/ilo/test_common.py
index fddd57ba7..a66b4b721 100644
--- a/ironic/tests/drivers/ilo/test_common.py
+++ b/ironic/tests/drivers/ilo/test_common.py
@@ -27,7 +27,6 @@ from ironic.common import swift
from ironic.common import utils
from ironic.conductor import task_manager
from ironic.drivers.modules.ilo import common as ilo_common
-from ironic.drivers import utils as driver_utils
from ironic.tests.conductor import utils as mgr_utils
from ironic.tests.db import base as db_base
from ironic.tests.db import utils as db_utils
@@ -300,42 +299,39 @@ class IloCommonMethodsTestCase(db_base.DbTestCase):
get_pending_boot_mode_mock.assert_called_once_with()
@mock.patch.object(ilo_common, 'set_boot_mode')
- @mock.patch.object(driver_utils, 'get_node_capability')
- def test_update_boot_mode_avbl(self,
- node_capability_mock,
- set_boot_mode_mock):
- node_capability_mock.return_value = 'uefi'
+ def test_update_boot_mode_instance_info_exists(self,
+ set_boot_mode_mock):
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
+ task.node.instance_info['deploy_boot_mode'] = 'bios'
ilo_common.update_boot_mode(task)
- node_capability_mock.assert_called_once_with(task.node,
- 'boot_mode')
- set_boot_mode_mock.assert_called_once_with(task.node, 'uefi')
+ set_boot_mode_mock.assert_called_once_with(task.node, 'bios')
+
+ @mock.patch.object(ilo_common, 'set_boot_mode')
+ def test_update_boot_mode_capabilities_exist(self,
+ set_boot_mode_mock):
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=False) as task:
+ task.node.properties['capabilities'] = 'boot_mode:bios'
+ ilo_common.update_boot_mode(task)
+ set_boot_mode_mock.assert_called_once_with(task.node, 'bios')
- @mock.patch.object(driver_utils, 'rm_node_capability')
- @mock.patch.object(driver_utils, 'add_node_capability')
@mock.patch.object(ilo_common, 'get_ilo_object')
- def test_update_boot_mode(self, get_ilo_object_mock,
- add_node_capability_mock,
- rm_node_capability_mock):
+ def test_update_boot_mode(self, get_ilo_object_mock):
ilo_mock_obj = get_ilo_object_mock.return_value
- ilo_mock_obj.get_pending_boot_mode.return_value = 'legacy'
+ ilo_mock_obj.get_pending_boot_mode.return_value = 'LEGACY'
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
ilo_common.update_boot_mode(task)
get_ilo_object_mock.assert_called_once_with(task.node)
ilo_mock_obj.get_pending_boot_mode.assert_called_once_with()
- rm_node_capability_mock.assert_called_once_with(task, 'boot_mode')
- add_node_capability_mock.assert_called_once_with(task,
- 'boot_mode',
- 'bios')
+ self.assertEqual('bios',
+ task.node.instance_info['deploy_boot_mode'])
- @mock.patch.object(driver_utils, 'add_node_capability')
@mock.patch.object(ilo_common, 'get_ilo_object')
def test_update_boot_mode_unknown(self,
- get_ilo_object_mock,
- add_node_capability_mock):
+ get_ilo_object_mock):
ilo_mock_obj = get_ilo_object_mock.return_value
ilo_mock_obj.get_pending_boot_mode.return_value = 'UNKNOWN'
set_pending_boot_mode_mock = ilo_mock_obj.set_pending_boot_mode
@@ -346,15 +342,28 @@ class IloCommonMethodsTestCase(db_base.DbTestCase):
get_ilo_object_mock.assert_called_once_with(task.node)
ilo_mock_obj.get_pending_boot_mode.assert_called_once_with()
set_pending_boot_mode_mock.assert_called_once_with('UEFI')
- add_node_capability_mock.assert_called_once_with(task,
- 'boot_mode',
- 'uefi')
+ self.assertEqual('uefi',
+ task.node.instance_info['deploy_boot_mode'])
+
+ @mock.patch.object(ilo_common, 'get_ilo_object')
+ def test_update_boot_mode_unknown_except(self,
+ get_ilo_object_mock):
+ ilo_mock_obj = get_ilo_object_mock.return_value
+ ilo_mock_obj.get_pending_boot_mode.return_value = 'UNKNOWN'
+ set_pending_boot_mode_mock = ilo_mock_obj.set_pending_boot_mode
+ exc = ilo_error.IloError('error')
+ set_pending_boot_mode_mock.side_effect = exc
+
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=False) as task:
+ self.assertRaises(exception.IloOperationError,
+ ilo_common.update_boot_mode, task)
+ get_ilo_object_mock.assert_called_once_with(task.node)
+ ilo_mock_obj.get_pending_boot_mode.assert_called_once_with()
- @mock.patch.object(driver_utils, 'add_node_capability')
@mock.patch.object(ilo_common, 'get_ilo_object')
def test_update_boot_mode_legacy(self,
- get_ilo_object_mock,
- add_node_capability_mock):
+ get_ilo_object_mock):
ilo_mock_obj = get_ilo_object_mock.return_value
exc = ilo_error.IloCommandNotSupportedError('error')
ilo_mock_obj.get_pending_boot_mode.side_effect = exc
@@ -364,9 +373,8 @@ class IloCommonMethodsTestCase(db_base.DbTestCase):
ilo_common.update_boot_mode(task)
get_ilo_object_mock.assert_called_once_with(task.node)
ilo_mock_obj.get_pending_boot_mode.assert_called_once_with()
- add_node_capability_mock.assert_called_once_with(task,
- 'boot_mode',
- 'bios')
+ self.assertEqual('bios',
+ task.node.instance_info['deploy_boot_mode'])
@mock.patch.object(ilo_common, 'set_boot_mode')
def test_update_boot_mode_prop_boot_mode_exist(self,
diff --git a/ironic/tests/drivers/ilo/test_deploy.py b/ironic/tests/drivers/ilo/test_deploy.py
index 32ea63734..f44e532b9 100644
--- a/ironic/tests/drivers/ilo/test_deploy.py
+++ b/ironic/tests/drivers/ilo/test_deploy.py
@@ -124,26 +124,29 @@ class IloDeployPrivateMethodsTestCase(db_base.DbTestCase):
boot_iso_expected = 'boot-iso-uuid'
self.assertEqual(boot_iso_expected, boot_iso_actual)
- @mock.patch.object(driver_utils, 'get_node_capability')
+ @mock.patch.object(deploy_utils, 'get_boot_mode_for_deploy')
@mock.patch.object(images, 'get_image_properties')
@mock.patch.object(ilo_deploy, '_parse_deploy_info')
- def test__get_boot_iso_uefi_no_glance_image(self, deploy_info_mock,
- image_props_mock, get_node_cap_mock):
+ def test__get_boot_iso_uefi_no_glance_image(self,
+ deploy_info_mock,
+ image_props_mock,
+ boot_mode_mock):
deploy_info_mock.return_value = {'image_source': 'image-uuid',
'ilo_deploy_iso': 'deploy_iso_uuid'}
image_props_mock.return_value = {'boot_iso': None,
'kernel_id': None,
'ramdisk_id': None}
- get_node_cap_mock.return_value = 'uefi'
+ properties = {'capabilities': 'boot_mode:uefi'}
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
+ task.node.properties = properties
boot_iso_result = ilo_deploy._get_boot_iso(task, 'root-uuid')
deploy_info_mock.assert_called_once_with(task.node)
image_props_mock.assert_called_once_with(
task.context, 'image-uuid',
['boot_iso', 'kernel_id', 'ramdisk_id'])
- get_node_cap_mock.assert_not_called(task.node, 'boot_mode')
+ self.assertFalse(boot_mode_mock.called)
self.assertIsNone(boot_iso_result)
@mock.patch.object(tempfile, 'NamedTemporaryFile')
@@ -250,8 +253,7 @@ class IloDeployPrivateMethodsTestCase(db_base.DbTestCase):
ilo_deploy._reboot_into(task, 'iso', opts)
setup_vmedia_mock.assert_called_once_with(task, 'iso', opts)
set_boot_device_mock.assert_called_once_with(task,
- boot_devices.CDROM,
- persistent=True)
+ boot_devices.CDROM)
node_power_action_mock.assert_called_once_with(task, states.REBOOT)
@mock.patch.object(ilo_deploy, '_reboot_into')
@@ -271,39 +273,26 @@ class IloDeployPrivateMethodsTestCase(db_base.DbTestCase):
@mock.patch.object(deploy_utils, 'is_secure_boot_requested')
@mock.patch.object(ilo_common, 'set_secure_boot_mode')
- def test__update_secure_boot_passed_true(self,
- func_set_secure_boot_mode,
- func_is_secure_boot_requested):
+ def test__update_secure_boot_mode_passed_true(self,
+ func_set_secure_boot_mode,
+ func_is_secure_boot_req):
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
- func_is_secure_boot_requested.return_value = True
+ func_is_secure_boot_req.return_value = True
ilo_deploy._update_secure_boot_mode(task, True)
func_set_secure_boot_mode.assert_called_once_with(task, True)
@mock.patch.object(deploy_utils, 'is_secure_boot_requested')
@mock.patch.object(ilo_common, 'set_secure_boot_mode')
- def test__update_secure_boot_passed_False(self,
- func_set_secure_boot_mode,
- func_is_secure_boot_requested):
+ def test__update_secure_boot_mode_passed_False(self,
+ func_set_secure_boot_mode,
+ func_is_secure_boot_req):
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
- func_is_secure_boot_requested.return_value = False
+ func_is_secure_boot_req.return_value = False
ilo_deploy._update_secure_boot_mode(task, False)
self.assertFalse(func_set_secure_boot_mode.called)
- @mock.patch.object(driver_utils, 'add_node_capability')
- @mock.patch.object(driver_utils, 'rm_node_capability')
- def test__enable_uefi_capability(self, func_rm_node_capability,
- func_add_node_capability):
- with task_manager.acquire(self.context, self.node.uuid,
- shared=False) as task:
- ilo_deploy._enable_uefi_capability(task)
- func_rm_node_capability.assert_called_once_with(task,
- 'boot_mode')
- func_add_node_capability.assert_called_once_with(task,
- 'boot_mode',
- 'uefi')
-
@mock.patch.object(ilo_common, 'set_secure_boot_mode')
@mock.patch.object(ilo_common, 'get_secure_boot_mode')
def test__disable_secure_boot_false(self,
@@ -330,81 +319,103 @@ class IloDeployPrivateMethodsTestCase(db_base.DbTestCase):
func_set_secure_boot_mode.assert_called_once_with(task, False)
self.assertTrue(returned_state)
+ @mock.patch.object(ilo_deploy.LOG, 'debug')
@mock.patch.object(ilo_deploy, 'exception')
@mock.patch.object(ilo_common, 'get_secure_boot_mode')
def test__disable_secure_boot_exception(self,
func_get_secure_boot_mode,
- exception_mock):
+ exception_mock,
+ mock_log):
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
exception_mock.IloOperationNotSupported = Exception
func_get_secure_boot_mode.side_effect = Exception
returned_state = ilo_deploy._disable_secure_boot(task)
func_get_secure_boot_mode.assert_called_once_with(task)
+ self.assertTrue(mock_log.called)
self.assertFalse(returned_state)
@mock.patch.object(ilo_common, 'update_boot_mode')
- @mock.patch.object(deploy_utils, 'is_secure_boot_requested')
@mock.patch.object(ilo_deploy, '_disable_secure_boot')
@mock.patch.object(manager_utils, 'node_power_action')
def test__prepare_node_for_deploy(self,
func_node_power_action,
func_disable_secure_boot,
- func_is_secure_boot_requested,
func_update_boot_mode):
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
func_disable_secure_boot.return_value = False
- func_is_secure_boot_requested.return_value = False
ilo_deploy._prepare_node_for_deploy(task)
func_node_power_action.assert_called_once_with(task,
states.POWER_OFF)
func_disable_secure_boot.assert_called_once_with(task)
- func_is_secure_boot_requested.assert_called_once_with(task.node)
func_update_boot_mode.assert_called_once_with(task)
+ bootmode = driver_utils.get_node_capability(task.node, "boot_mode")
+ self.assertIsNone(bootmode)
@mock.patch.object(ilo_common, 'update_boot_mode')
- @mock.patch.object(deploy_utils, 'is_secure_boot_requested')
@mock.patch.object(ilo_deploy, '_disable_secure_boot')
@mock.patch.object(manager_utils, 'node_power_action')
def test__prepare_node_for_deploy_sec_boot_on(self,
func_node_power_action,
func_disable_secure_boot,
- func_is_secure_boot_req,
func_update_boot_mode):
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
func_disable_secure_boot.return_value = True
- func_is_secure_boot_req.return_value = False
ilo_deploy._prepare_node_for_deploy(task)
func_node_power_action.assert_called_once_with(task,
states.POWER_OFF)
func_disable_secure_boot.assert_called_once_with(task)
- func_is_secure_boot_req.assert_called_once_with(task.node)
self.assertFalse(func_update_boot_mode.called)
+ ret_boot_mode = task.node.instance_info['deploy_boot_mode']
+ self.assertEqual('uefi', ret_boot_mode)
+ bootmode = driver_utils.get_node_capability(task.node, "boot_mode")
+ self.assertIsNone(bootmode)
@mock.patch.object(ilo_common, 'update_boot_mode')
- @mock.patch.object(ilo_deploy, '_enable_uefi_capability')
- @mock.patch.object(deploy_utils, 'is_secure_boot_requested')
@mock.patch.object(ilo_deploy, '_disable_secure_boot')
@mock.patch.object(manager_utils, 'node_power_action')
- def test__prepare_node_for_deploy_sec_boot_req(self,
- func_node_power_action,
- func_disable_secure_boot,
- func_is_secure_boot_req,
- func_enable_uefi_cap,
- func_update_boot_mode):
+ def test__prepare_node_for_deploy_inst_info(self,
+ func_node_power_action,
+ func_disable_secure_boot,
+ func_update_boot_mode):
+ instance_info = {'capabilities': '{"secure_boot": "true"}'}
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=False) as task:
+ func_disable_secure_boot.return_value = False
+ task.node.instance_info = instance_info
+ ilo_deploy._prepare_node_for_deploy(task)
+ func_node_power_action.assert_called_once_with(task,
+ states.POWER_OFF)
+ func_disable_secure_boot.assert_called_once_with(task)
+ func_update_boot_mode.assert_called_once_with(task)
+ bootmode = driver_utils.get_node_capability(task.node, "boot_mode")
+ self.assertIsNone(bootmode)
+ deploy_boot_mode = task.node.instance_info.get('deploy_boot_mode')
+ self.assertIsNone(deploy_boot_mode)
+
+ @mock.patch.object(ilo_common, 'update_boot_mode')
+ @mock.patch.object(ilo_deploy, '_disable_secure_boot')
+ @mock.patch.object(manager_utils, 'node_power_action')
+ def test__prepare_node_for_deploy_sec_boot_on_inst_info(self,
+ func_node_power_action,
+ func_disable_secure_boot,
+ func_update_boot_mode):
+ instance_info = {'capabilities': '{"secure_boot": "true"}'}
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
func_disable_secure_boot.return_value = True
- func_is_secure_boot_req.return_value = True
+ task.node.instance_info = instance_info
ilo_deploy._prepare_node_for_deploy(task)
func_node_power_action.assert_called_once_with(task,
states.POWER_OFF)
func_disable_secure_boot.assert_called_once_with(task)
- func_is_secure_boot_req.assert_called_once_with(task.node)
- func_enable_uefi_cap.assert_called_once_with(task)
self.assertFalse(func_update_boot_mode.called)
+ bootmode = driver_utils.get_node_capability(task.node, "boot_mode")
+ self.assertIsNone(bootmode)
+ deploy_boot_mode = task.node.instance_info.get('deploy_boot_mode')
+ self.assertIsNone(deploy_boot_mode)
class IloVirtualMediaIscsiDeployTestCase(db_base.DbTestCase):
@@ -739,6 +750,18 @@ class VendorPassthruTestCase(db_base.DbTestCase):
get_deploy_info_mock.assert_called_once_with(task.node,
foo='bar')
+ @mock.patch.object(iscsi_deploy, 'validate_pass_bootloader_info_input',
+ autospec=True)
+ def test_validate_pass_bootloader_install_info(self,
+ validate_mock):
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=True) as task:
+ kwargs = {'address': '1.2.3.4', 'key': 'fake-key',
+ 'status': 'SUCCEEDED', 'error': ''}
+ task.driver.vendor.validate(
+ task, method='pass_bootloader_install_info', **kwargs)
+ validate_mock.assert_called_once_with(task, kwargs)
+
@mock.patch.object(iscsi_deploy, 'get_deploy_info')
def test_validate_heartbeat(self, get_deploy_info_mock):
with task_manager.acquire(self.context, self.node.uuid,
@@ -747,7 +770,22 @@ class VendorPassthruTestCase(db_base.DbTestCase):
vendor.validate(task, method='heartbeat', foo='bar')
self.assertFalse(get_deploy_info_mock.called)
- @mock.patch.object(deploy_utils, 'notify_deploy_complete')
+ @mock.patch.object(iscsi_deploy, 'validate_bootloader_install_status',
+ autospec=True)
+ @mock.patch.object(iscsi_deploy, 'finish_deploy', autospec=True)
+ def test_pass_bootloader_install_info(self, finish_deploy_mock,
+ validate_input_mock):
+ kwargs = {'method': 'pass_deploy_info', 'address': '123456'}
+ self.node.provision_state = states.DEPLOYWAIT
+ self.node.target_provision_state = states.ACTIVE
+ self.node.save()
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=False) as task:
+ task.driver.vendor.pass_bootloader_install_info(task, **kwargs)
+ finish_deploy_mock.assert_called_once_with(task, '123456')
+ validate_input_mock.assert_called_once_with(task, kwargs)
+
+ @mock.patch.object(deploy_utils, 'notify_ramdisk_to_proceed')
@mock.patch.object(ilo_deploy, '_update_secure_boot_mode')
@mock.patch.object(ilo_common, 'update_boot_mode')
@mock.patch.object(manager_utils, 'node_set_boot_device')
@@ -760,7 +798,7 @@ class VendorPassthruTestCase(db_base.DbTestCase):
setup_vmedia_mock, set_boot_device_mock,
func_update_boot_mode,
func_update_secure_boot_mode,
- notify_deploy_complete_mock):
+ notify_ramdisk_to_proceed_mock):
kwargs = {'method': 'pass_deploy_info', 'address': '123456'}
continue_deploy_mock.return_value = {'root uuid': 'root-uuid'}
get_boot_iso_mock.return_value = 'boot-iso'
@@ -786,7 +824,7 @@ class VendorPassthruTestCase(db_base.DbTestCase):
self.assertEqual('boot-iso',
task.node.instance_info['ilo_boot_iso'])
- notify_deploy_complete_mock.assert_called_once_with('123456')
+ notify_ramdisk_to_proceed_mock.assert_called_once_with('123456')
@mock.patch.object(ilo_common, 'cleanup_vmedia_boot')
def test_pass_deploy_info_bad(self, cleanup_vmedia_boot_mock):
@@ -805,16 +843,19 @@ class VendorPassthruTestCase(db_base.DbTestCase):
self.assertEqual(states.NOSTATE, task.node.target_provision_state)
self.assertFalse(cleanup_vmedia_boot_mock.called)
+ @mock.patch.object(ilo_deploy, '_update_secure_boot_mode', autospec=True)
+ @mock.patch.object(ilo_common, 'update_boot_mode', autospec=True)
@mock.patch.object(manager_utils, 'node_power_action')
@mock.patch.object(iscsi_deploy, 'continue_deploy')
@mock.patch.object(ilo_common, 'cleanup_vmedia_boot')
@mock.patch.object(ilo_deploy, '_get_boot_iso')
def test_pass_deploy_info_create_boot_iso_fail(self, get_iso_mock,
- cleanup_vmedia_boot_mock, continue_deploy_mock, node_power_mock):
+ cleanup_vmedia_boot_mock, continue_deploy_mock, node_power_mock,
+ update_boot_mode_mock, update_secure_boot_mode_mock):
kwargs = {'address': '123456'}
continue_deploy_mock.return_value = {'root uuid': 'root-uuid'}
get_iso_mock.side_effect = exception.ImageCreationFailed(
- image_type='iso', error="error")
+ image_type='iso', error="error")
self.node.provision_state = states.DEPLOYWAIT
self.node.target_provision_state = states.ACTIVE
self.node.save()
@@ -824,6 +865,8 @@ class VendorPassthruTestCase(db_base.DbTestCase):
task.driver.vendor.pass_deploy_info(task, **kwargs)
cleanup_vmedia_boot_mock.assert_called_once_with(task)
+ update_boot_mode_mock.assert_called_once_with(task)
+ update_secure_boot_mode_mock.assert_called_once_with(task, True)
continue_deploy_mock.assert_called_once_with(task, **kwargs)
get_iso_mock.assert_called_once_with(task, 'root-uuid')
node_power_mock.assert_called_once_with(task, states.POWER_OFF)
@@ -831,22 +874,57 @@ class VendorPassthruTestCase(db_base.DbTestCase):
self.assertEqual(states.ACTIVE, task.node.target_provision_state)
self.assertIsNotNone(task.node.last_error)
- @mock.patch.object(deploy_utils, 'notify_deploy_complete')
+ @mock.patch.object(iscsi_deploy, 'finish_deploy', autospec=True)
+ @mock.patch.object(deploy_utils, 'notify_ramdisk_to_proceed',
+ autospec=True)
@mock.patch.object(manager_utils, 'node_set_boot_device')
@mock.patch.object(ilo_deploy, '_update_secure_boot_mode')
@mock.patch.object(ilo_common, 'update_boot_mode')
@mock.patch.object(iscsi_deploy, 'continue_deploy')
@mock.patch.object(ilo_common, 'cleanup_vmedia_boot')
- def _test_pass_deploy_info_localboot(self, cleanup_vmedia_boot_mock,
- continue_deploy_mock,
- func_update_boot_mode,
- func_update_secure_boot_mode,
- set_boot_device_mock,
- notify_deploy_complete_mock):
+ def test_pass_deploy_info_boot_option_local(
+ self, cleanup_vmedia_boot_mock, continue_deploy_mock,
+ func_update_boot_mode, func_update_secure_boot_mode,
+ set_boot_device_mock, notify_ramdisk_to_proceed_mock,
+ finish_deploy_mock):
+ kwargs = {'method': 'pass_deploy_info', 'address': '123456'}
+ continue_deploy_mock.return_value = {'root uuid': '<some-uuid>'}
+
+ self.node.instance_info = {'capabilities': '{"boot_option": "local"}'}
+ self.node.provision_state = states.DEPLOYWAIT
+ self.node.target_provision_state = states.ACTIVE
+ self.node.save()
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=False) as task:
+ vendor = task.driver.vendor
+ vendor.pass_deploy_info(task, **kwargs)
+ cleanup_vmedia_boot_mock.assert_called_once_with(task)
+ continue_deploy_mock.assert_called_once_with(task, **kwargs)
+ set_boot_device_mock.assert_called_once_with(task,
+ boot_devices.DISK,
+ persistent=True)
+ func_update_boot_mode.assert_called_once_with(task)
+ func_update_secure_boot_mode.assert_called_once_with(task, True)
+ notify_ramdisk_to_proceed_mock.assert_called_once_with('123456')
+ self.assertEqual(states.DEPLOYWAIT, task.node.provision_state)
+ self.assertEqual(states.ACTIVE, task.node.target_provision_state)
+ self.assertFalse(finish_deploy_mock.called)
+
+ @mock.patch.object(iscsi_deploy, 'finish_deploy', autospec=True)
+ @mock.patch.object(manager_utils, 'node_set_boot_device', autospec=True)
+ @mock.patch.object(ilo_deploy, '_update_secure_boot_mode', autospec=True)
+ @mock.patch.object(ilo_common, 'update_boot_mode', autospec=True)
+ @mock.patch.object(iscsi_deploy, 'continue_deploy', autospec=True)
+ @mock.patch.object(ilo_common, 'cleanup_vmedia_boot', autospec=True)
+ def _test_pass_deploy_info_whole_disk_image(
+ self, cleanup_vmedia_boot_mock, continue_deploy_mock,
+ func_update_boot_mode, func_update_secure_boot_mode,
+ set_boot_device_mock, notify_ramdisk_to_proceed_mock):
kwargs = {'method': 'pass_deploy_info', 'address': '123456'}
continue_deploy_mock.return_value = {'root uuid': '<some-uuid>'}
+ self.node.driver_internal_info = {'is_whole_disk_image': True}
self.node.provision_state = states.DEPLOYWAIT
self.node.target_provision_state = states.ACTIVE
self.node.save()
@@ -862,19 +940,15 @@ class VendorPassthruTestCase(db_base.DbTestCase):
persistent=True)
func_update_boot_mode.assert_called_once_with(task)
func_update_secure_boot_mode.assert_called_once_with(task, True)
- notify_deploy_complete_mock.assert_called_once_with('123456')
- self.assertEqual(states.ACTIVE, task.node.provision_state)
- self.assertEqual(states.NOSTATE, task.node.target_provision_state)
+ iscsi_deploy.finish_deploy.assert_called_once_with(task, '123456')
- def test_pass_deploy_info_boot_option_local(self):
+ def test_pass_deploy_info_whole_disk_image_local(self):
self.node.instance_info = {'capabilities': '{"boot_option": "local"}'}
self.node.save()
- self._test_pass_deploy_info_localboot()
+ self._test_pass_deploy_info_whole_disk_image()
def test_pass_deploy_info_whole_disk_image(self):
- self.node.driver_internal_info = {'is_whole_disk_image': True}
- self.node.save()
- self._test_pass_deploy_info_localboot()
+ self._test_pass_deploy_info_whole_disk_image()
@mock.patch.object(ilo_deploy, '_update_secure_boot_mode')
@mock.patch.object(ilo_common, 'update_boot_mode')
@@ -953,6 +1027,34 @@ class VendorPassthruTestCase(db_base.DbTestCase):
'configure_local_boot')
@mock.patch.object(iscsi_deploy, 'do_agent_iscsi_deploy')
@mock.patch.object(ilo_common, 'cleanup_vmedia_boot')
+ def test_continue_deploy_whole_disk_image(
+ self, cleanup_vmedia_boot_mock, do_agent_iscsi_deploy_mock,
+ configure_local_boot_mock, reboot_and_finish_deploy_mock,
+ boot_mode_cap_mock, update_secure_boot_mock):
+ self.node.provision_state = states.DEPLOYWAIT
+ self.node.target_provision_state = states.DEPLOYING
+ self.node.driver_internal_info = {'is_whole_disk_image': True}
+ self.node.save()
+ do_agent_iscsi_deploy_mock.return_value = {
+ 'disk identifier': 'some-disk-id'}
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=False) as task:
+ task.driver.vendor.continue_deploy(task)
+ cleanup_vmedia_boot_mock.assert_called_once_with(task)
+ do_agent_iscsi_deploy_mock.assert_called_once_with(task,
+ mock.ANY)
+ configure_local_boot_mock.assert_called_once_with(
+ task, root_uuid=None, efi_system_part_uuid=None)
+ reboot_and_finish_deploy_mock.assert_called_once_with(task)
+
+ @mock.patch.object(ilo_deploy, '_update_secure_boot_mode')
+ @mock.patch.object(ilo_common, 'update_boot_mode')
+ @mock.patch.object(agent_base_vendor.BaseAgentVendor,
+ 'reboot_and_finish_deploy')
+ @mock.patch.object(agent_base_vendor.BaseAgentVendor,
+ 'configure_local_boot')
+ @mock.patch.object(iscsi_deploy, 'do_agent_iscsi_deploy')
+ @mock.patch.object(ilo_common, 'cleanup_vmedia_boot')
def test_continue_deploy_localboot_uefi(self, cleanup_vmedia_boot_mock,
do_agent_iscsi_deploy_mock,
configure_local_boot_mock,
@@ -1003,10 +1105,25 @@ class IloPXEDeployTestCase(db_base.DbTestCase):
pxe_prepare_mock):
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
+ task.node.properties['capabilities'] = 'boot_mode:uefi'
task.driver.deploy.prepare(task)
update_boot_mode_mock.assert_called_once_with(task)
pxe_prepare_mock.assert_called_once_with(task)
+ @mock.patch.object(pxe.PXEDeploy, 'prepare')
+ @mock.patch.object(ilo_common, 'update_boot_mode')
+ def test_prepare_uefi_whole_disk_image_fail(self,
+ update_boot_mode_mock,
+ pxe_prepare_mock):
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=False) as task:
+ task.node.properties['capabilities'] = 'boot_mode:uefi'
+ task.node.driver_internal_info['is_whole_disk_image'] = True
+ self.assertRaises(exception.InvalidParameterValue,
+ task.driver.deploy.prepare, task)
+ update_boot_mode_mock.assert_called_once_with(task)
+ self.assertFalse(pxe_prepare_mock.called)
+
@mock.patch.object(pxe.PXEDeploy, 'deploy')
@mock.patch.object(manager_utils, 'node_set_boot_device')
def test_deploy_boot_mode_exists(self, set_persistent_mock,
@@ -1027,7 +1144,8 @@ class IloPXEVendorPassthruTestCase(db_base.DbTestCase):
driver='pxe_ilo', driver_info=INFO_DICT)
def test_vendor_routes(self):
- expected = ['heartbeat', 'pass_deploy_info']
+ expected = ['heartbeat', 'pass_deploy_info',
+ 'pass_bootloader_install_info']
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
vendor_routes = task.driver.vendor.vendor_routes
@@ -1067,8 +1185,10 @@ class IloVirtualMediaAgentVendorInterfaceTestCase(db_base.DbTestCase):
@mock.patch.object(agent.AgentVendorInterface, 'reboot_to_instance')
@mock.patch.object(agent.AgentVendorInterface, 'check_deploy_success')
+ @mock.patch.object(ilo_common, 'update_boot_mode')
@mock.patch.object(ilo_deploy, '_update_secure_boot_mode')
def test_reboot_to_instance(self, func_update_secure_boot_mode,
+ func_update_boot_mode,
check_deploy_success_mock,
agent_reboot_to_instance_mock):
kwargs = {'address': '123456'}
@@ -1077,14 +1197,17 @@ class IloVirtualMediaAgentVendorInterfaceTestCase(db_base.DbTestCase):
shared=False) as task:
task.driver.vendor.reboot_to_instance(task, **kwargs)
check_deploy_success_mock.called_once_with(task.node)
+ func_update_boot_mode.assert_called_once_with(task)
func_update_secure_boot_mode.assert_called_once_with(task, True)
agent_reboot_to_instance_mock.assert_called_once_with(task,
**kwargs)
@mock.patch.object(agent.AgentVendorInterface, 'reboot_to_instance')
@mock.patch.object(agent.AgentVendorInterface, 'check_deploy_success')
+ @mock.patch.object(ilo_common, 'update_boot_mode')
@mock.patch.object(ilo_deploy, '_update_secure_boot_mode')
def test_reboot_to_instance_deploy_fail(self, func_update_secure_boot_mode,
+ func_update_boot_mode,
check_deploy_success_mock,
agent_reboot_to_instance_mock):
kwargs = {'address': '123456'}
@@ -1093,6 +1216,7 @@ class IloVirtualMediaAgentVendorInterfaceTestCase(db_base.DbTestCase):
shared=False) as task:
task.driver.vendor.reboot_to_instance(task, **kwargs)
check_deploy_success_mock.called_once_with(task.node)
+ self.assertFalse(func_update_boot_mode.called)
self.assertFalse(func_update_secure_boot_mode.called)
agent_reboot_to_instance_mock.assert_called_once_with(task,
**kwargs)
diff --git a/ironic/tests/drivers/ilo/test_inspect.py b/ironic/tests/drivers/ilo/test_inspect.py
index 129f52b0f..9b7461a7b 100644
--- a/ironic/tests/drivers/ilo/test_inspect.py
+++ b/ironic/tests/drivers/ilo/test_inspect.py
@@ -48,78 +48,30 @@ class IloInspectTestCase(db_base.DbTestCase):
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
properties = ilo_common.REQUIRED_PROPERTIES.copy()
- properties.update(ilo_common.INSPECT_PROPERTIES)
self.assertEqual(properties,
task.driver.inspect.get_properties())
@mock.patch.object(ilo_common, 'parse_driver_info')
- def test_validate_inspect_ports_valid_with_comma(self, driver_info_mock):
+ def test_validate(self, driver_info_mock):
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
- driver_info_mock.return_value = {'inspect_ports': '1,2'}
task.driver.inspect.validate(task)
driver_info_mock.assert_called_once_with(task.node)
- @mock.patch.object(ilo_common, 'parse_driver_info')
- def test_validate_inspect_ports_valid_None(self, driver_info_mock):
- with task_manager.acquire(self.context, self.node.uuid,
- shared=False) as task:
- driver_info_mock.return_value = {'inspect_ports': 'None'}
- task.driver.inspect.validate(task)
- driver_info_mock.assert_called_once_with(task.node)
-
- @mock.patch.object(ilo_common, 'parse_driver_info')
- def test_validate_inspect_ports_valid_all(self, driver_info_mock):
- with task_manager.acquire(self.context, self.node.uuid,
- shared=False) as task:
- driver_info_mock.return_value = {'inspect_ports': 'all'}
- task.driver.inspect.validate(task)
- driver_info_mock.assert_called_once_with(task.node)
-
- @mock.patch.object(ilo_common, 'parse_driver_info')
- def test_validate_inspect_ports_valid_single(self, driver_info_mock):
- with task_manager.acquire(self.context, self.node.uuid,
- shared=False) as task:
- driver_info_mock.return_value = {'inspect_ports': '1'}
- task.driver.inspect.validate(task)
- driver_info_mock.assert_called_once_with(task.node)
-
- @mock.patch.object(ilo_common, 'parse_driver_info')
- def test_validate_inspect_ports_invalid(self, driver_info_mock):
- with task_manager.acquire(self.context, self.node.uuid,
- shared=False) as task:
- driver_info_mock.return_value = {'inspect_ports': 'abc'}
- self.assertRaises(exception.InvalidParameterValue,
- task.driver.inspect.validate, task)
- driver_info_mock.assert_called_once_with(task.node)
-
- @mock.patch.object(ilo_common, 'parse_driver_info')
- def test_validate_inspect_ports_missing(self, driver_info_mock):
- with task_manager.acquire(self.context, self.node.uuid,
- shared=False) as task:
- driver_info_mock.return_value = {'xyz': 'abc'}
- self.assertRaises(exception.MissingParameterValue,
- task.driver.inspect.validate, task)
- driver_info_mock.assert_called_once_with(task.node)
-
@mock.patch.object(ilo_inspect, '_get_capabilities')
@mock.patch.object(ilo_inspect, '_create_ports_if_not_exist')
- @mock.patch.object(ilo_inspect, '_get_macs_for_desired_ports')
@mock.patch.object(ilo_inspect, '_get_essential_properties')
@mock.patch.object(ilo_power.IloPower, 'get_power_state')
@mock.patch.object(ilo_common, 'get_ilo_object')
def test_inspect_essential_ok(self, get_ilo_object_mock,
power_mock,
get_essential_mock,
- desired_macs_mock,
create_port_mock,
get_capabilities_mock):
ilo_object_mock = get_ilo_object_mock.return_value
properties = {'memory_mb': '512', 'local_gb': '10',
'cpus': '1', 'cpu_arch': 'x86_64'}
macs = {'Port 1': 'aa:aa:aa:aa:aa:aa', 'Port 2': 'bb:bb:bb:bb:bb:bb'}
- desired_macs_mock.return_value = {'Port 1': 'aa:aa:aa:aa:aa:aa',
- 'Port 2': 'bb:bb:bb:bb:bb:bb'}
capabilities = ''
result = {'properties': properties, 'macs': macs}
get_essential_mock.return_value = result
@@ -127,7 +79,6 @@ class IloInspectTestCase(db_base.DbTestCase):
power_mock.return_value = states.POWER_ON
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
- task.node.driver_info = {'inspect_ports': 'all'}
task.driver.inspect.inspect_hardware(task)
self.assertEqual(properties, task.node.properties)
power_mock.assert_called_once_with(task)
@@ -139,7 +90,6 @@ class IloInspectTestCase(db_base.DbTestCase):
@mock.patch.object(ilo_inspect, '_get_capabilities')
@mock.patch.object(ilo_inspect, '_create_ports_if_not_exist')
- @mock.patch.object(ilo_inspect, '_get_macs_for_desired_ports')
@mock.patch.object(ilo_inspect, '_get_essential_properties')
@mock.patch.object(conductor_utils, 'node_power_action')
@mock.patch.object(ilo_power.IloPower, 'get_power_state')
@@ -148,15 +98,12 @@ class IloInspectTestCase(db_base.DbTestCase):
power_mock,
set_power_mock,
get_essential_mock,
- desired_macs_mock,
create_port_mock,
get_capabilities_mock):
ilo_object_mock = get_ilo_object_mock.return_value
properties = {'memory_mb': '512', 'local_gb': '10',
'cpus': '1', 'cpu_arch': 'x86_64'}
macs = {'Port 1': 'aa:aa:aa:aa:aa:aa', 'Port 2': 'bb:bb:bb:bb:bb:bb'}
- desired_macs_mock.return_value = {'Port 1': 'aa:aa:aa:aa:aa:aa',
- 'Port 2': 'bb:bb:bb:bb:bb:bb'}
capabilities = ''
result = {'properties': properties, 'macs': macs}
get_essential_mock.return_value = result
@@ -164,7 +111,6 @@ class IloInspectTestCase(db_base.DbTestCase):
power_mock.return_value = states.POWER_OFF
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
- task.node.driver_info = {'inspect_ports': 'all'}
task.driver.inspect.inspect_hardware(task)
self.assertEqual(properties, task.node.properties)
power_mock.assert_called_once_with(task)
@@ -177,22 +123,18 @@ class IloInspectTestCase(db_base.DbTestCase):
@mock.patch.object(ilo_inspect, '_get_capabilities')
@mock.patch.object(ilo_inspect, '_create_ports_if_not_exist')
- @mock.patch.object(ilo_inspect, '_get_macs_for_desired_ports')
@mock.patch.object(ilo_inspect, '_get_essential_properties')
@mock.patch.object(ilo_power.IloPower, 'get_power_state')
@mock.patch.object(ilo_common, 'get_ilo_object')
def test_inspect_essential_capabilities_ok(self, get_ilo_object_mock,
power_mock,
get_essential_mock,
- desired_macs_mock,
create_port_mock,
get_capabilities_mock):
ilo_object_mock = get_ilo_object_mock.return_value
properties = {'memory_mb': '512', 'local_gb': '10',
'cpus': '1', 'cpu_arch': 'x86_64'}
macs = {'Port 1': 'aa:aa:aa:aa:aa:aa', 'Port 2': 'bb:bb:bb:bb:bb:bb'}
- desired_macs_mock.return_value = {'Port 1': 'aa:aa:aa:aa:aa:aa',
- 'Port 2': 'bb:bb:bb:bb:bb:bb'}
capability_str = 'BootMode:uefi'
capabilities = {'BootMode': 'uefi'}
result = {'properties': properties, 'macs': macs}
@@ -201,7 +143,6 @@ class IloInspectTestCase(db_base.DbTestCase):
power_mock.return_value = states.POWER_ON
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
- task.node.driver_info = {'inspect_ports': 'all'}
task.driver.inspect.inspect_hardware(task)
expected_properties = {'memory_mb': '512', 'local_gb': '10',
'cpus': '1', 'cpu_arch': 'x86_64',
@@ -216,14 +157,12 @@ class IloInspectTestCase(db_base.DbTestCase):
@mock.patch.object(ilo_inspect, '_get_capabilities')
@mock.patch.object(ilo_inspect, '_create_ports_if_not_exist')
- @mock.patch.object(ilo_inspect, '_get_macs_for_desired_ports')
@mock.patch.object(ilo_inspect, '_get_essential_properties')
@mock.patch.object(ilo_power.IloPower, 'get_power_state')
@mock.patch.object(ilo_common, 'get_ilo_object')
def test_inspect_essential_capabilities_exist_ok(self, get_ilo_object_mock,
power_mock,
get_essential_mock,
- desired_macs_mock,
create_port_mock,
get_capabilities_mock):
ilo_object_mock = get_ilo_object_mock.return_value
@@ -231,8 +170,6 @@ class IloInspectTestCase(db_base.DbTestCase):
'cpus': '1', 'cpu_arch': 'x86_64',
'somekey': 'somevalue'}
macs = {'Port 1': 'aa:aa:aa:aa:aa:aa', 'Port 2': 'bb:bb:bb:bb:bb:bb'}
- desired_macs_mock.return_value = {'Port 1': 'aa:aa:aa:aa:aa:aa',
- 'Port 2': 'bb:bb:bb:bb:bb:bb'}
result = {'properties': properties, 'macs': macs}
capabilities = {'BootMode': 'uefi'}
get_essential_mock.return_value = result
@@ -240,7 +177,6 @@ class IloInspectTestCase(db_base.DbTestCase):
power_mock.return_value = states.POWER_ON
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
- task.node.driver_info = {'inspect_ports': 'all'}
task.node.properties = {'capabilities': 'foo:bar'}
expected_capabilities = ('BootMode:uefi,'
'foo:bar')
@@ -260,75 +196,6 @@ class IloInspectTestCase(db_base.DbTestCase):
ilo_object_mock)
create_port_mock.assert_called_once_with(task.node, macs)
- @mock.patch.object(ilo_inspect, '_get_capabilities')
- @mock.patch.object(ilo_inspect, '_create_ports_if_not_exist')
- @mock.patch.object(ilo_inspect, '_get_macs_for_desired_ports')
- @mock.patch.object(ilo_inspect, '_get_essential_properties')
- @mock.patch.object(ilo_power.IloPower, 'get_power_state')
- @mock.patch.object(ilo_common, 'get_ilo_object')
- def test_inspect_hardware_port_desired(self, get_ilo_object_mock,
- power_mock,
- get_essential_mock,
- desired_macs_mock,
- create_port_mock,
- get_capabilities_mock):
- ilo_object_mock = get_ilo_object_mock.return_value
- properties = {'memory_mb': '512', 'local_gb': '10',
- 'cpus': '1', 'cpu_arch': 'x86_64'}
- macs = {'Port 1': 'aa:aa:aa:aa:aa:aa', 'Port 2': 'bb:bb:bb:bb:bb:bb'}
- result = {'properties': properties, 'macs': macs}
- macs_input_given = {'Port 1': 'aa:aa:aa:aa:aa:aa'}
- desired_macs_mock.return_value = macs_input_given
- capabilities = ''
- get_essential_mock.return_value = result
- get_capabilities_mock.return_value = capabilities
- power_mock.return_value = states.POWER_ON
- with task_manager.acquire(self.context, self.node.uuid,
- shared=False) as task:
- task.node.driver_info = {'inspect_ports': '1'}
- task.driver.inspect.inspect_hardware(task)
- power_mock.assert_called_once_with(task)
- get_essential_mock.assert_called_once_with(task.node,
- ilo_object_mock)
- self.assertEqual(task.node.properties, result['properties'])
- get_capabilities_mock.assert_called_once_with(task.node,
- ilo_object_mock)
- create_port_mock.assert_called_once_with(task.node,
- macs_input_given)
-
- @mock.patch.object(ilo_inspect, '_get_capabilities')
- @mock.patch.object(ilo_inspect, '_create_ports_if_not_exist')
- @mock.patch.object(ilo_inspect, '_get_macs_for_desired_ports')
- @mock.patch.object(ilo_inspect, '_get_essential_properties')
- @mock.patch.object(ilo_power.IloPower, 'get_power_state')
- @mock.patch.object(ilo_common, 'get_ilo_object')
- def test_inspect_hardware_port_desired_none(self, get_ilo_object_mock,
- power_mock,
- get_essential_mock,
- desired_macs_mock,
- create_port_mock,
- get_capabilities_mock):
- ilo_object_mock = get_ilo_object_mock.return_value
- properties = {'memory_mb': '512', 'local_gb': '10',
- 'cpus': '1', 'cpu_arch': 'x86_64'}
- macs = {'Port 1': 'aa:aa:aa:aa:aa:aa', 'Port 2': 'bb:bb:bb:bb:bb:bb'}
- result = {'properties': properties, 'macs': macs}
- macs_input_given = {'Port 1': 'aa:aa:aa:aa:aa:aa'}
- capabilities = ''
- get_capabilities_mock.return_value = capabilities
- desired_macs_mock.return_value = macs_input_given
- get_essential_mock.return_value = result
- power_mock.return_value = states.POWER_ON
- with task_manager.acquire(self.context, self.node.uuid,
- shared=False) as task:
- task.node.driver_info = {'inspect_ports': 'none'}
- task.driver.inspect.inspect_hardware(task)
- power_mock.assert_called_once_with(task)
- get_essential_mock.assert_called_once_with(task.node,
- ilo_object_mock)
- self.assertEqual(task.node.properties, result['properties'])
- create_port_mock.assert_not_called()
-
class TestInspectPrivateMethods(db_base.DbTestCase):
@@ -347,7 +214,7 @@ class TestInspectPrivateMethods(db_base.DbTestCase):
port_dict1 = {'address': 'aa:aa:aa:aa:aa:aa', 'node_id': node_id}
port_dict2 = {'address': 'bb:bb:bb:bb:bb:bb', 'node_id': node_id}
ilo_inspect._create_ports_if_not_exist(self.node, macs)
- instance_mock.assert_called_once()
+ instance_mock.assert_called_once_with()
self.assertTrue(log_mock.called)
db_obj.create_port.assert_any_call(port_dict1)
db_obj.create_port.assert_any_call(port_dict2)
@@ -361,7 +228,7 @@ class TestInspectPrivateMethods(db_base.DbTestCase):
dbapi_mock.create_port.side_effect = exception.MACAlreadyExists('f')
macs = {'Port 1': 'aa:aa:aa:aa:aa:aa', 'Port 2': 'bb:bb:bb:bb:bb:bb'}
ilo_inspect._create_ports_if_not_exist(self.node, macs)
- instance_mock.assert_called_once()
+ instance_mock.assert_called_once_with()
self.assertTrue(log_mock.called)
def test__get_essential_properties_ok(self):
@@ -523,44 +390,3 @@ class TestInspectPrivateMethods(db_base.DbTestCase):
set2 = set(cap_returned.split(','))
self.assertEqual(set1, set2)
self.assertIsInstance(cap_returned, str)
-
- def test__get_macs_for_desired_ports(self):
- driver_info_mock = {'inspect_ports': '1,2'}
- self.node.driver_info = driver_info_mock
- macs = {'Port 1': 'aa:aa:aa:aa:aa:aa', 'Port 2': 'bb:bb:bb:bb:bb:bb'}
- expected_macs = {'Port 1': 'aa:aa:aa:aa:aa:aa',
- 'Port 2': 'bb:bb:bb:bb:bb:bb'}
- macs_out = (
- ilo_inspect._get_macs_for_desired_ports(self.node,
- macs))
- self.assertEqual(expected_macs, macs_out)
-
- def test__get_macs_for_desired_ports_few(self):
- driver_info_mock = {'inspect_ports': '1,2'}
- self.node.driver_info = driver_info_mock
- macs = {'Port 1': 'aa:aa:aa:aa:aa:aa', 'Port 2': 'bb:bb:bb:bb:bb:bb',
- 'Port 3': 'cc:cc:cc:cc:cc:cc', 'Port 4': 'dd:dd:dd:dd:dd:dd'}
- expected_macs = {'Port 1': 'aa:aa:aa:aa:aa:aa',
- 'Port 2': 'bb:bb:bb:bb:bb:bb'}
- macs_out = (
- ilo_inspect._get_macs_for_desired_ports(self.node,
- macs))
- self.assertEqual(expected_macs, macs_out)
-
- def test__get_macs_for_desired_ports_one(self):
- driver_info_mock = {'inspect_ports': '1'}
- self.node.driver_info = driver_info_mock
- macs = {'Port 1': 'aa:aa:aa:aa:aa:aa', 'Port 2': 'bb:bb:bb:bb:bb:bb'}
- expected_macs = {'Port 1': 'aa:aa:aa:aa:aa:aa'}
- macs_out = (
- ilo_inspect._get_macs_for_desired_ports(self.node,
- macs))
- self.assertEqual(expected_macs, macs_out)
-
- def test__get_macs_for_desired_ports_none(self):
- driver_info_mock = {}
- self.node.driver_info = driver_info_mock
- macs = {'Port 1': 'aa:aa:aa:aa:aa:aa', 'Port 2': 'bb:bb:bb:bb:bb:bb'}
- self.assertRaises(exception.HardwareInspectionFailure,
- ilo_inspect._get_macs_for_desired_ports,
- self.node, macs)
diff --git a/ironic/tests/drivers/ilo/test_power.py b/ironic/tests/drivers/ilo/test_power.py
index 2ed8d97fb..a7f87f450 100644
--- a/ironic/tests/drivers/ilo/test_power.py
+++ b/ironic/tests/drivers/ilo/test_power.py
@@ -137,12 +137,26 @@ class IloPowerInternalMethodsTestCase(db_base.DbTestCase):
get_ilo_object_mock):
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
+ task.node.provision_state = states.ACTIVE
task.node.instance_info['ilo_boot_iso'] = 'boot-iso'
ilo_power._attach_boot_iso(task)
setup_vmedia_mock.assert_called_once_with(task, 'boot-iso')
set_boot_device_mock.assert_called_once_with(task,
boot_devices.CDROM)
+ @mock.patch.object(manager_utils, 'node_set_boot_device')
+ @mock.patch.object(ilo_common, 'setup_vmedia_for_boot')
+ def test__attach_boot_iso_on_rebuild(self, setup_vmedia_mock,
+ set_boot_device_mock,
+ get_ilo_object_mock):
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=True) as task:
+ task.node.provision_state = states.DEPLOYING
+ task.node.instance_info['ilo_boot_iso'] = 'boot-iso'
+ ilo_power._attach_boot_iso(task)
+ self.assertFalse(setup_vmedia_mock.called)
+ self.assertFalse(set_boot_device_mock.called)
+
class IloPowerTestCase(db_base.DbTestCase):
diff --git a/ironic/tests/drivers/ipxe_config.template b/ironic/tests/drivers/ipxe_config.template
new file mode 100644
index 000000000..bc803d4a7
--- /dev/null
+++ b/ironic/tests/drivers/ipxe_config.template
@@ -0,0 +1,21 @@
+#!ipxe
+
+dhcp
+
+goto deploy
+
+:deploy
+kernel http://1.2.3.4:1234/deploy_kernel selinux=0 disk=cciss/c0d0,sda,hda,vda iscsi_target_iqn=iqn-1be26c0b-03f2-4d2e-ae87-c02d7f33c123 deployment_id=1be26c0b-03f2-4d2e-ae87-c02d7f33c123 deployment_key=0123456789ABCDEFGHIJKLMNOPQRSTUV ironic_api_url=http://192.168.122.184:6385 troubleshoot=0 text test_param boot_option=netboot ip=${ip}:${next-server}:${gateway}:${netmask} BOOTIF=${mac} root_device=vendor=fake,size=123 ipa-api-url=http://192.168.122.184:6385 ipa-driver-name=pxe_ssh coreos.configdrive=0
+
+initrd http://1.2.3.4:1234/deploy_ramdisk
+boot
+
+:boot_partition
+kernel http://1.2.3.4:1234/kernel root={{ ROOT }} ro text test_param
+initrd http://1.2.3.4:1234/ramdisk
+boot
+
+:boot_whole_disk
+kernel chain.c32
+append mbr:{{ DISK_IDENTIFIER }}
+boot
diff --git a/ironic/tests/drivers/pxe_config.template b/ironic/tests/drivers/pxe_config.template
index d77f17e6c..936a9620e 100644
--- a/ironic/tests/drivers/pxe_config.template
+++ b/ironic/tests/drivers/pxe_config.template
@@ -2,7 +2,7 @@ default deploy
label deploy
kernel /tftpboot/1be26c0b-03f2-4d2e-ae87-c02d7f33c123/deploy_kernel
-append initrd=/tftpboot/1be26c0b-03f2-4d2e-ae87-c02d7f33c123/deploy_ramdisk selinux=0 disk=cciss/c0d0,sda,hda,vda iscsi_target_iqn=iqn-1be26c0b-03f2-4d2e-ae87-c02d7f33c123 deployment_id=1be26c0b-03f2-4d2e-ae87-c02d7f33c123 deployment_key=0123456789ABCDEFGHIJKLMNOPQRSTUV ironic_api_url=http://192.168.122.184:6385 troubleshoot=0 text test_param boot_option=netboot root_device=vendor=fake,size=123 ipa-api-url=http://192.168.122.184:6385 ipa-driver-name=pxe_ssh boot_mode=bios
+append initrd=/tftpboot/1be26c0b-03f2-4d2e-ae87-c02d7f33c123/deploy_ramdisk selinux=0 disk=cciss/c0d0,sda,hda,vda iscsi_target_iqn=iqn-1be26c0b-03f2-4d2e-ae87-c02d7f33c123 deployment_id=1be26c0b-03f2-4d2e-ae87-c02d7f33c123 deployment_key=0123456789ABCDEFGHIJKLMNOPQRSTUV ironic_api_url=http://192.168.122.184:6385 troubleshoot=0 text test_param boot_option=netboot root_device=vendor=fake,size=123 ipa-api-url=http://192.168.122.184:6385 ipa-driver-name=pxe_ssh boot_mode=bios coreos.configdrive=0
ipappend 3
diff --git a/ironic/tests/drivers/test_agent.py b/ironic/tests/drivers/test_agent.py
index 7e5ed3133..bb9675f3f 100644
--- a/ironic/tests/drivers/test_agent.py
+++ b/ironic/tests/drivers/test_agent.py
@@ -48,6 +48,7 @@ class TestAgentMethods(db_base.DbTestCase):
options = agent.build_agent_options(self.node)
self.assertEqual('api-url', options['ipa-api-url'])
self.assertEqual('fake_agent', options['ipa-driver-name'])
+ self.assertEqual(0, options['coreos.configdrive'])
@mock.patch.object(keystone, 'get_service_url')
def test_build_agent_options_keystone(self, get_url_mock):
@@ -57,6 +58,7 @@ class TestAgentMethods(db_base.DbTestCase):
options = agent.build_agent_options(self.node)
self.assertEqual('api-url', options['ipa-api-url'])
self.assertEqual('fake_agent', options['ipa-driver-name'])
+ self.assertEqual(0, options['coreos.configdrive'])
def test_build_agent_options_root_device_hints(self):
self.config(api_url='api-url', group='conductor')
@@ -162,6 +164,14 @@ class TestAgentDeploy(db_base.DbTestCase):
self.assertIn('driver_info.deploy_ramdisk', str(e))
self.assertIn('driver_info.deploy_kernel', str(e))
+ def test_validate_driver_info_manage_tftp_false(self):
+ self.config(manage_tftp=False, group='agent')
+ self.node.driver_info = {}
+ self.node.save()
+ with task_manager.acquire(
+ self.context, self.node['uuid'], shared=False) as task:
+ self.driver.validate(task)
+
def test_validate_instance_info_missing_params(self):
self.node.instance_info = {}
self.node.save()
@@ -183,6 +193,13 @@ class TestAgentDeploy(db_base.DbTestCase):
self.assertRaises(exception.MissingParameterValue,
self.driver.validate, task)
+ def test_validate_agent_fail_partition_image(self):
+ with task_manager.acquire(
+ self.context, self.node['uuid'], shared=False) as task:
+ task.node.driver_internal_info['is_whole_disk_image'] = False
+ self.assertRaises(exception.InvalidParameterValue,
+ self.driver.validate, task)
+
def test_validate_invalid_root_device_hints(self):
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
@@ -190,6 +207,37 @@ class TestAgentDeploy(db_base.DbTestCase):
self.assertRaises(exception.InvalidParameterValue,
task.driver.deploy.validate, task)
+ @mock.patch.object(agent, '_cache_tftp_images')
+ @mock.patch.object(pxe_utils, 'create_pxe_config')
+ @mock.patch.object(agent, '_build_pxe_config_options')
+ @mock.patch.object(agent, '_get_tftp_image_info')
+ def test__prepare_pxe_boot(self, pxe_info_mock, options_mock,
+ create_mock, cache_mock):
+ with task_manager.acquire(
+ self.context, self.node['uuid'], shared=False) as task:
+ agent._prepare_pxe_boot(task)
+ pxe_info_mock.assert_called_once_with(task.node)
+ options_mock.assert_called_once_with(task.node, mock.ANY)
+ create_mock.assert_called_once_with(
+ task, mock.ANY, CONF.agent.agent_pxe_config_template)
+ cache_mock.assert_called_once_with(task.context, task.node,
+ mock.ANY)
+
+ @mock.patch.object(agent, '_cache_tftp_images')
+ @mock.patch.object(pxe_utils, 'create_pxe_config')
+ @mock.patch.object(agent, '_build_pxe_config_options')
+ @mock.patch.object(agent, '_get_tftp_image_info')
+ def test__prepare_pxe_boot_manage_tftp_false(
+ self, pxe_info_mock, options_mock, create_mock, cache_mock):
+ self.config(manage_tftp=False, group='agent')
+ with task_manager.acquire(
+ self.context, self.node['uuid'], shared=False) as task:
+ agent._prepare_pxe_boot(task)
+ self.assertFalse(pxe_info_mock.called)
+ self.assertFalse(options_mock.called)
+ self.assertFalse(create_mock.called)
+ self.assertFalse(cache_mock.called)
+
@mock.patch.object(dhcp_factory.DHCPFactory, 'update_dhcp')
@mock.patch('ironic.conductor.utils.node_set_boot_device')
@mock.patch('ironic.conductor.utils.node_power_action')
@@ -212,6 +260,36 @@ class TestAgentDeploy(db_base.DbTestCase):
power_mock.assert_called_once_with(task, states.POWER_OFF)
self.assertEqual(driver_return, states.DELETED)
+ @mock.patch.object(pxe_utils, 'clean_up_pxe_config')
+ @mock.patch.object(agent, 'AgentTFTPImageCache')
+ @mock.patch('ironic.common.utils.unlink_without_raise')
+ @mock.patch.object(agent, '_get_tftp_image_info')
+ def test__clean_up_pxe(self, info_mock, unlink_mock, cache_mock,
+ clean_mock):
+ info_mock.return_value = {'label': ['fake1', 'fake2']}
+ with task_manager.acquire(
+ self.context, self.node['uuid'], shared=False) as task:
+ agent._clean_up_pxe(task)
+ info_mock.assert_called_once_with(task.node)
+ unlink_mock.assert_called_once_with('fake2')
+ clean_mock.assert_called_once_with(task)
+
+ @mock.patch.object(pxe_utils, 'clean_up_pxe_config')
+ @mock.patch.object(agent.AgentTFTPImageCache, 'clean_up')
+ @mock.patch('ironic.common.utils.unlink_without_raise')
+ @mock.patch.object(agent, '_get_tftp_image_info')
+ def test__clean_up_pxe_manage_tftp_false(
+ self, info_mock, unlink_mock, cache_mock, clean_mock):
+ self.config(manage_tftp=False, group='agent')
+ info_mock.return_value = {'label': ['fake1', 'fake2']}
+ with task_manager.acquire(
+ self.context, self.node['uuid'], shared=False) as task:
+ agent._clean_up_pxe(task)
+ self.assertFalse(info_mock.called)
+ self.assertFalse(unlink_mock.called)
+ self.assertFalse(cache_mock.called)
+ self.assertFalse(clean_mock.called)
+
@mock.patch('ironic.dhcp.neutron.NeutronDHCPApi.delete_cleaning_ports')
@mock.patch('ironic.dhcp.neutron.NeutronDHCPApi.create_cleaning_ports')
@mock.patch('ironic.drivers.modules.agent._do_pxe_boot')
@@ -226,8 +304,8 @@ class TestAgentDeploy(db_base.DbTestCase):
self.driver.prepare_cleaning(task))
prepare_mock.assert_called_once_with(task)
boot_mock.assert_called_once_with(task, ports)
- create_mock.assert_called_once()
- delete_mock.assert_called_once()
+ create_mock.assert_called_once_with(task)
+ delete_mock.assert_called_once_with(task)
@mock.patch('ironic.dhcp.neutron.NeutronDHCPApi.delete_cleaning_ports')
@mock.patch('ironic.drivers.modules.agent._clean_up_pxe')
@@ -238,7 +316,7 @@ class TestAgentDeploy(db_base.DbTestCase):
self.assertIsNone(self.driver.tear_down_cleaning(task))
power_mock.assert_called_once_with(task, states.POWER_OFF)
cleanup_mock.assert_called_once_with(task)
- neutron_mock.assert_called_once()
+ neutron_mock.assert_called_once_with(task)
@mock.patch('ironic.drivers.modules.deploy_utils.agent_get_clean_steps')
def test_get_clean_steps(self, mock_get_clean_steps):
@@ -254,10 +332,11 @@ class TestAgentDeploy(db_base.DbTestCase):
@mock.patch('ironic.drivers.modules.deploy_utils.agent_get_clean_steps')
def test_get_clean_steps_config_priority(self, mock_get_clean_steps):
# Test that we can override the priority of get clean steps
- self.config(agent_erase_devices_priority=20, group='agent')
+ # Use 0 because it is an edge case (false-y) and used in devstack
+ self.config(agent_erase_devices_priority=0, group='agent')
mock_steps = [{'priority': 10, 'interface': 'deploy',
'step': 'erase_devices'}]
- expected_steps = [{'priority': 20, 'interface': 'deploy',
+ expected_steps = [{'priority': 0, 'interface': 'deploy',
'step': 'erase_devices'}]
mock_get_clean_steps.return_value = mock_steps
with task_manager.acquire(self.context, self.node.uuid) as task:
@@ -399,6 +478,7 @@ class TestAgentVendor(db_base.DbTestCase):
'deployment_ari_path': 'fake-node/deploy_ramdisk',
'ipa-api-url': 'api-url',
'ipa-driver-name': u'fake_agent',
+ 'coreos.configdrive': 0,
'pxe_append_params': 'foo bar'}
if root_device_hints:
diff --git a/ironic/tests/drivers/test_agent_base_vendor.py b/ironic/tests/drivers/test_agent_base_vendor.py
index 31596abc1..e672df85b 100644
--- a/ironic/tests/drivers/test_agent_base_vendor.py
+++ b/ironic/tests/drivers/test_agent_base_vendor.py
@@ -284,6 +284,29 @@ class TestBaseAgentVendor(db_base.DbTestCase):
'1be26c0b-03f2-4d2e-ae87-c02d7f33c123: Failed checking if deploy '
'is done. exception: LlamaException')
+ @mock.patch.object(agent_base_vendor.BaseAgentVendor, 'continue_deploy')
+ @mock.patch.object(agent_base_vendor.BaseAgentVendor, 'reboot_to_instance')
+ @mock.patch.object(agent_base_vendor.BaseAgentVendor,
+ '_notify_conductor_resume_clean')
+ def test_heartbeat_noops_maintenance_mode(self, ncrc_mock, rti_mock,
+ cd_mock):
+ """Ensures that heartbeat() no-ops for a maintenance node."""
+ kwargs = {
+ 'agent_url': 'http://127.0.0.1:9999/bar'
+ }
+ self.node.maintenance = True
+ for state in (states.AVAILABLE, states.DEPLOYWAIT, states.DEPLOYING,
+ states.CLEANING):
+ self.node.provision_state = state
+ self.node.save()
+ with task_manager.acquire(
+ self.context, self.node['uuid'], shared=True) as task:
+ self.passthru.heartbeat(task, **kwargs)
+
+ self.assertEqual(0, ncrc_mock.call_count)
+ self.assertEqual(0, rti_mock.call_count)
+ self.assertEqual(0, cd_mock.call_count)
+
def test_vendor_passthru_vendor_routes(self):
expected = ['heartbeat']
with task_manager.acquire(self.context, self.node.uuid,
@@ -336,7 +359,9 @@ class TestBaseAgentVendor(db_base.DbTestCase):
'command_status': 'SUCCESS', 'command_error': None}
with task_manager.acquire(self.context, self.node['uuid'],
shared=False) as task:
- self.passthru.configure_local_boot(task, 'some-root-uuid')
+ task.node.driver_internal_info['is_whole_disk_image'] = False
+ self.passthru.configure_local_boot(task,
+ root_uuid='some-root-uuid')
try_set_boot_device_mock.assert_called_once_with(
task, boot_devices.DISK)
install_bootloader_mock.assert_called_once_with(
@@ -351,6 +376,7 @@ class TestBaseAgentVendor(db_base.DbTestCase):
'command_status': 'SUCCESS', 'command_error': None}
with task_manager.acquire(self.context, self.node['uuid'],
shared=False) as task:
+ task.node.driver_internal_info['is_whole_disk_image'] = False
self.passthru.configure_local_boot(
task, root_uuid='some-root-uuid',
efi_system_part_uuid='efi-system-part-uuid')
@@ -360,6 +386,29 @@ class TestBaseAgentVendor(db_base.DbTestCase):
task.node, root_uuid='some-root-uuid',
efi_system_part_uuid='efi-system-part-uuid')
+ @mock.patch.object(deploy_utils, 'try_set_boot_device')
+ @mock.patch.object(agent_client.AgentClient, 'install_bootloader')
+ def test_configure_local_boot_whole_disk_image(
+ self, install_bootloader_mock, try_set_boot_device_mock):
+ with task_manager.acquire(self.context, self.node['uuid'],
+ shared=False) as task:
+ self.passthru.configure_local_boot(task)
+ self.assertFalse(install_bootloader_mock.called)
+ try_set_boot_device_mock.assert_called_once_with(
+ task, boot_devices.DISK)
+
+ @mock.patch.object(deploy_utils, 'try_set_boot_device')
+ @mock.patch.object(agent_client.AgentClient, 'install_bootloader')
+ def test_configure_local_boot_no_root_uuid(
+ self, install_bootloader_mock, try_set_boot_device_mock):
+ with task_manager.acquire(self.context, self.node['uuid'],
+ shared=False) as task:
+ task.node.driver_internal_info['is_whole_disk_image'] = False
+ self.passthru.configure_local_boot(task)
+ self.assertFalse(install_bootloader_mock.called)
+ try_set_boot_device_mock.assert_called_once_with(
+ task, boot_devices.DISK)
+
@mock.patch.object(agent_client.AgentClient, 'install_bootloader')
def test_configure_local_boot_boot_loader_install_fail(
self, install_bootloader_mock):
@@ -370,9 +419,10 @@ class TestBaseAgentVendor(db_base.DbTestCase):
self.node.save()
with task_manager.acquire(self.context, self.node['uuid'],
shared=False) as task:
+ task.node.driver_internal_info['is_whole_disk_image'] = False
self.assertRaises(exception.InstanceDeployFailure,
self.passthru.configure_local_boot,
- task, 'some-root-uuid')
+ task, root_uuid='some-root-uuid')
install_bootloader_mock.assert_called_once_with(
task.node, root_uuid='some-root-uuid',
efi_system_part_uuid=None)
@@ -391,9 +441,10 @@ class TestBaseAgentVendor(db_base.DbTestCase):
self.node.save()
with task_manager.acquire(self.context, self.node['uuid'],
shared=False) as task:
+ task.node.driver_internal_info['is_whole_disk_image'] = False
self.assertRaises(exception.InstanceDeployFailure,
self.passthru.configure_local_boot,
- task, 'some-root-uuid')
+ task, root_uuid='some-root-uuid')
install_bootloader_mock.assert_called_once_with(
task.node, root_uuid='some-root-uuid',
efi_system_part_uuid=None)
@@ -406,8 +457,20 @@ class TestBaseAgentVendor(db_base.DbTestCase):
'_notify_conductor_resume_clean')
@mock.patch.object(agent_client.AgentClient, 'get_commands_status')
def test_continue_cleaning(self, status_mock, notify_mock):
+ # Test a successful execute clean step on the agent
+ self.node.clean_step = {
+ 'priority': 10,
+ 'interface': 'deploy',
+ 'step': 'erase_devices',
+ 'reboot_requested': False
+ }
+ self.node.save()
status_mock.return_value = [{
'command_status': 'SUCCEEDED',
+ 'command_name': 'execute_clean_step',
+ 'command_result': {
+ 'clean_step': self.node.clean_step
+ }
}]
with task_manager.acquire(self.context, self.node['uuid'],
shared=False) as task:
@@ -417,20 +480,54 @@ class TestBaseAgentVendor(db_base.DbTestCase):
@mock.patch.object(agent_base_vendor.BaseAgentVendor,
'_notify_conductor_resume_clean')
@mock.patch.object(agent_client.AgentClient, 'get_commands_status')
+ def test_continue_cleaning_old_command(self, status_mock, notify_mock):
+ # Test when a second execute_clean_step happens to the agent, but
+ # the new step hasn't started yet.
+ self.node.clean_step = {
+ 'priority': 10,
+ 'interface': 'deploy',
+ 'step': 'erase_devices',
+ 'reboot_requested': False
+ }
+ self.node.save()
+ status_mock.return_value = [{
+ 'command_status': 'SUCCEEDED',
+ 'command_name': 'execute_clean_step',
+ 'command_result': {
+ 'priority': 20,
+ 'interface': 'deploy',
+ 'step': 'update_firmware',
+ 'reboot_requested': False
+ }
+ }]
+ with task_manager.acquire(self.context, self.node['uuid'],
+ shared=False) as task:
+ self.passthru.continue_cleaning(task)
+ self.assertFalse(notify_mock.called)
+
+ @mock.patch.object(agent_base_vendor.BaseAgentVendor,
+ '_notify_conductor_resume_clean')
+ @mock.patch.object(agent_client.AgentClient, 'get_commands_status')
def test_continue_cleaning_running(self, status_mock, notify_mock):
+ # Test that no action is taken while a clean step is executing
status_mock.return_value = [{
'command_status': 'RUNNING',
+ 'command_name': 'execute_clean_step',
+ 'command_result': {}
}]
with task_manager.acquire(self.context, self.node['uuid'],
shared=False) as task:
self.passthru.continue_cleaning(task)
- notify_mock.assert_not_called()
+ self.assertFalse(notify_mock.called)
@mock.patch('ironic.conductor.manager.cleaning_error_handler')
@mock.patch.object(agent_client.AgentClient, 'get_commands_status')
def test_continue_cleaning_fail(self, status_mock, error_mock):
+ # Test the a failure puts the node in CLEANFAIL
status_mock.return_value = [{
'command_status': 'FAILED',
+ 'command_name': 'execute_clean_step',
+ 'command_result': {}
}]
with task_manager.acquire(self.context, self.node['uuid'],
shared=False) as task:
@@ -443,8 +540,11 @@ class TestBaseAgentVendor(db_base.DbTestCase):
@mock.patch.object(agent_client.AgentClient, 'get_commands_status')
def test_continue_cleaning_clean_version_mismatch(
self, status_mock, notify_mock, steps_mock):
+ # Test that cleaning is restarted if there is a version mismatch
status_mock.return_value = [{
'command_status': 'CLEAN_VERSION_MISMATCH',
+ 'command_name': 'execute_clean_step',
+ 'command_result': {}
}]
with task_manager.acquire(self.context, self.node['uuid'],
shared=False) as task:
@@ -455,8 +555,11 @@ class TestBaseAgentVendor(db_base.DbTestCase):
@mock.patch('ironic.conductor.manager.cleaning_error_handler')
@mock.patch.object(agent_client.AgentClient, 'get_commands_status')
def test_continue_cleaning_unknown(self, status_mock, error_mock):
+ # Test that unknown commands are treated as failures
status_mock.return_value = [{
'command_status': 'UNKNOWN',
+ 'command_name': 'execute_clean_step',
+ 'command_result': {}
}]
with task_manager.acquire(self.context, self.node['uuid'],
shared=False) as task:
diff --git a/ironic/tests/drivers/test_agent_client.py b/ironic/tests/drivers/test_agent_client.py
index 80a0f69af..bfe91f83a 100644
--- a/ironic/tests/drivers/test_agent_client.py
+++ b/ironic/tests/drivers/test_agent_client.py
@@ -16,6 +16,7 @@ import json
import mock
import requests
+import six
from ironic.common import exception
from ironic.drivers.modules import agent_client
@@ -23,12 +24,12 @@ from ironic.tests import base
class MockResponse(object):
- def __init__(self, data):
- self.data = data
- self.text = json.dumps(data)
+ def __init__(self, text):
+ assert isinstance(text, six.string_types)
+ self.text = text
def json(self):
- return self.data
+ return json.loads(self.text)
class MockNode(object):
@@ -75,7 +76,8 @@ class TestAgentClient(base.TestCase):
def test__command(self):
response_data = {'status': 'ok'}
- self.client.session.post.return_value = MockResponse(response_data)
+ response_text = json.dumps(response_data)
+ self.client.session.post.return_value = MockResponse(response_text)
method = 'standby.run_image'
image_info = {'image_id': 'test_image'}
params = {'image_info': image_info}
@@ -92,6 +94,26 @@ class TestAgentClient(base.TestCase):
headers=headers,
params={'wait': 'false'})
+ def test__command_fail_json(self):
+ response_text = 'this be not json matey!'
+ self.client.session.post.return_value = MockResponse(response_text)
+ method = 'standby.run_image'
+ image_info = {'image_id': 'test_image'}
+ params = {'image_info': image_info}
+
+ url = self.client._get_command_url(self.node)
+ body = self.client._get_command_body(method, params)
+ headers = {'Content-Type': 'application/json'}
+
+ self.assertRaises(exception.IronicException,
+ self.client._command,
+ self.node, method, params)
+ self.client.session.post.assert_called_once_with(
+ url,
+ data=body,
+ headers=headers,
+ params={'wait': 'false'})
+
def test_get_commands_status(self):
with mock.patch.object(self.client.session, 'get') as mock_get:
res = mock.Mock()
diff --git a/ironic/tests/drivers/test_deploy_utils.py b/ironic/tests/drivers/test_deploy_utils.py
index dfbcc5532..fdb6653a3 100644
--- a/ironic/tests/drivers/test_deploy_utils.py
+++ b/ironic/tests/drivers/test_deploy_utils.py
@@ -37,6 +37,7 @@ from ironic.common import states
from ironic.common import utils as common_utils
from ironic.conductor import task_manager
from ironic.conductor import utils as manager_utils
+from ironic.drivers.modules import agent_client
from ironic.drivers.modules import deploy_utils as utils
from ironic.drivers.modules import image_cache
from ironic.tests import base as tests_base
@@ -180,7 +181,7 @@ image=kernel
image=chain.c32
label=boot_whole_disk
- append mbr:{{ DISK_IDENTIFIER }}
+ append="mbr:{{ DISK_IDENTIFIER }}"
"""
_UEFI_PXECONF_BOOT_PARTITION = """
@@ -198,7 +199,7 @@ image=kernel
image=chain.c32
label=boot_whole_disk
- append mbr:{{ DISK_IDENTIFIER }}
+ append="mbr:{{ DISK_IDENTIFIER }}"
"""
_UEFI_PXECONF_BOOT_WHOLE_DISK = """
@@ -216,7 +217,7 @@ image=kernel
image=chain.c32
label=boot_whole_disk
- append mbr:0x12345678
+ append="mbr:0x12345678"
"""
@@ -1019,13 +1020,18 @@ class WorkOnDiskTestCase(tests_base.TestCase):
self.swap_part = '/dev/fake-part1'
self.root_part = '/dev/fake-part2'
- self.mock_ibd = mock.patch.object(utils, 'is_block_device').start()
- self.mock_mp = mock.patch.object(utils, 'make_partitions').start()
- self.addCleanup(self.mock_ibd.stop)
- self.addCleanup(self.mock_mp.stop)
- self.mock_remlbl = mock.patch.object(utils,
- 'destroy_disk_metadata').start()
- self.addCleanup(self.mock_remlbl.stop)
+ self.mock_ibd_obj = mock.patch.object(
+ utils, 'is_block_device', autospec=True)
+ self.mock_ibd = self.mock_ibd_obj.start()
+ self.addCleanup(self.mock_ibd_obj.stop)
+ self.mock_mp_obj = mock.patch.object(
+ utils, 'make_partitions', autospec=True)
+ self.mock_mp = self.mock_mp_obj.start()
+ self.addCleanup(self.mock_mp_obj.stop)
+ self.mock_remlbl_obj = mock.patch.object(
+ utils, 'destroy_disk_metadata', autospec=True)
+ self.mock_remlbl = self.mock_remlbl_obj.start()
+ self.addCleanup(self.mock_remlbl_obj.stop)
self.mock_mp.return_value = {'swap': self.swap_part,
'root': self.root_part}
@@ -1043,7 +1049,7 @@ class WorkOnDiskTestCase(tests_base.TestCase):
boot_mode="bios")
def test_no_swap_partition(self):
- self.mock_ibd.side_effect = [True, False]
+ self.mock_ibd.side_effect = iter([True, False])
calls = [mock.call(self.root_part),
mock.call(self.swap_part)]
self.assertRaises(exception.InstanceDeployFailure,
@@ -1067,7 +1073,7 @@ class WorkOnDiskTestCase(tests_base.TestCase):
self.mock_mp.return_value = {'ephemeral': ephemeral_part,
'swap': swap_part,
'root': root_part}
- self.mock_ibd.side_effect = [True, True, False]
+ self.mock_ibd.side_effect = iter([True, True, False])
calls = [mock.call(root_part),
mock.call(swap_part),
mock.call(ephemeral_part)]
@@ -1095,7 +1101,7 @@ class WorkOnDiskTestCase(tests_base.TestCase):
self.mock_mp.return_value = {'swap': swap_part,
'configdrive': configdrive_part,
'root': root_part}
- self.mock_ibd.side_effect = [True, True, False]
+ self.mock_ibd.side_effect = iter([True, True, False])
calls = [mock.call(root_part),
mock.call(swap_part),
mock.call(configdrive_part)]
@@ -1453,7 +1459,7 @@ class ParseInstanceInfoCapabilitiesTestCase(tests_base.TestCase):
utils.parse_instance_info_capabilities, self.node)
def test_is_secure_boot_requested_true(self):
- self.node.instance_info = {'capabilities': {"secure_boot": "true"}}
+ self.node.instance_info = {'capabilities': {"secure_boot": "tRue"}}
self.assertTrue(utils.is_secure_boot_requested(self.node))
def test_is_secure_boot_requested_false(self):
@@ -1464,6 +1470,27 @@ class ParseInstanceInfoCapabilitiesTestCase(tests_base.TestCase):
self.node.instance_info = {'capabilities': {"secure_boot": "invalid"}}
self.assertFalse(utils.is_secure_boot_requested(self.node))
+ def test_get_boot_mode_for_deploy_using_capabilities(self):
+ properties = {'capabilities': 'boot_mode:uefi,cap2:value2'}
+ self.node.properties = properties
+
+ result = utils.get_boot_mode_for_deploy(self.node)
+ self.assertEqual('uefi', result)
+
+ def test_get_boot_mode_for_deploy_using_instance_info_cap(self):
+ instance_info = {'capabilities': {'secure_boot': 'True'}}
+ self.node.instance_info = instance_info
+
+ result = utils.get_boot_mode_for_deploy(self.node)
+ self.assertEqual('uefi', result)
+
+ def test_get_boot_mode_for_deploy_using_instance_info(self):
+ instance_info = {'deploy_boot_mode': 'bios'}
+ self.node.instance_info = instance_info
+
+ result = utils.get_boot_mode_for_deploy(self.node)
+ self.assertEqual('bios', result)
+
class TrySetBootDeviceTestCase(db_base.DbTestCase):
@@ -1526,7 +1553,9 @@ class AgentCleaningTestCase(db_base.DbTestCase):
def setUp(self):
super(AgentCleaningTestCase, self).setUp()
mgr_utils.mock_the_extension_manager(driver='fake_agent')
- n = {'driver': 'fake_agent'}
+ n = {'driver': 'fake_agent',
+ 'driver_internal_info': {'agent_url': 'http://127.0.0.1:9999'}}
+
self.node = obj_utils.create_test_node(self.context, **n)
self.ports = [obj_utils.create_test_port(self.context,
node_id=self.node.id)]
@@ -1551,39 +1580,34 @@ class AgentCleaningTestCase(db_base.DbTestCase):
}
@mock.patch('ironic.objects.Port.list_by_node_id')
- @mock.patch('ironic.drivers.modules.deploy_utils._get_agent_client')
- def test_get_clean_steps(self, get_client_mock, list_ports_mock):
- client_mock = mock.Mock()
- client_mock.get_clean_steps.return_value = {
+ @mock.patch.object(agent_client.AgentClient, 'get_clean_steps')
+ def test_get_clean_steps(self, client_mock, list_ports_mock):
+ client_mock.return_value = {
'command_result': self.clean_steps}
- get_client_mock.return_value = client_mock
list_ports_mock.return_value = self.ports
with task_manager.acquire(
self.context, self.node['uuid'], shared=False) as task:
response = utils.agent_get_clean_steps(task)
- client_mock.get_clean_steps.assert_called_once_with(task.node,
- self.ports)
+ client_mock.assert_called_once_with(task.node, self.ports)
self.assertEqual('1', task.node.driver_internal_info[
'hardware_manager_version'])
# Since steps are returned in dicts, they have non-deterministic
# ordering
self.assertEqual(2, len(response))
- self.assertTrue(self.clean_steps['clean_steps'][
- 'GenericHardwareManager'][0] in response)
- self.assertTrue(self.clean_steps['clean_steps'][
- 'SpecificHardwareManager'][0] in response)
+ self.assertIn(self.clean_steps['clean_steps'][
+ 'GenericHardwareManager'][0], response)
+ self.assertIn(self.clean_steps['clean_steps'][
+ 'SpecificHardwareManager'][0], response)
@mock.patch('ironic.objects.Port.list_by_node_id')
- @mock.patch('ironic.drivers.modules.deploy_utils._get_agent_client')
- def test_get_clean_steps_missing_steps(self, get_client_mock,
+ @mock.patch.object(agent_client.AgentClient, 'get_clean_steps')
+ def test_get_clean_steps_missing_steps(self, client_mock,
list_ports_mock):
- client_mock = mock.Mock()
del self.clean_steps['clean_steps']
- client_mock.get_clean_steps.return_value = {
+ client_mock.return_value = {
'command_result': self.clean_steps}
- get_client_mock.return_value = client_mock
list_ports_mock.return_value = self.ports
with task_manager.acquire(
@@ -1591,16 +1615,13 @@ class AgentCleaningTestCase(db_base.DbTestCase):
self.assertRaises(exception.NodeCleaningFailure,
utils.agent_get_clean_steps,
task)
- client_mock.get_clean_steps.assert_called_once_with(task.node,
- self.ports)
+ client_mock.assert_called_once_with(task.node, self.ports)
@mock.patch('ironic.objects.Port.list_by_node_id')
- @mock.patch('ironic.drivers.modules.deploy_utils._get_agent_client')
- def test_execute_clean_step(self, get_client_mock, list_ports_mock):
- client_mock = mock.Mock()
- client_mock.execute_clean_step.return_value = {
+ @mock.patch.object(agent_client.AgentClient, 'execute_clean_step')
+ def test_execute_clean_step(self, client_mock, list_ports_mock):
+ client_mock.return_value = {
'command_status': 'SUCCEEDED'}
- get_client_mock.return_value = client_mock
list_ports_mock.return_value = self.ports
with task_manager.acquire(
@@ -1611,13 +1632,10 @@ class AgentCleaningTestCase(db_base.DbTestCase):
self.assertEqual(states.CLEANING, response)
@mock.patch('ironic.objects.Port.list_by_node_id')
- @mock.patch('ironic.drivers.modules.deploy_utils._get_agent_client')
- def test_execute_clean_step_running(self, get_client_mock,
- list_ports_mock):
- client_mock = mock.Mock()
- client_mock.execute_clean_step.return_value = {
+ @mock.patch.object(agent_client.AgentClient, 'execute_clean_step')
+ def test_execute_clean_step_running(self, client_mock, list_ports_mock):
+ client_mock.return_value = {
'command_status': 'RUNNING'}
- get_client_mock.return_value = client_mock
list_ports_mock.return_value = self.ports
with task_manager.acquire(
@@ -1628,13 +1646,11 @@ class AgentCleaningTestCase(db_base.DbTestCase):
self.assertEqual(states.CLEANING, response)
@mock.patch('ironic.objects.Port.list_by_node_id')
- @mock.patch('ironic.drivers.modules.deploy_utils._get_agent_client')
- def test_execute_clean_step_version_mismatch(self, get_client_mock,
+ @mock.patch.object(agent_client.AgentClient, 'execute_clean_step')
+ def test_execute_clean_step_version_mismatch(self, client_mock,
list_ports_mock):
- client_mock = mock.Mock()
- client_mock.execute_clean_step.return_value = {
+ client_mock.return_value = {
'command_status': 'RUNNING'}
- get_client_mock.return_value = client_mock
list_ports_mock.return_value = self.ports
with task_manager.acquire(
diff --git a/ironic/tests/drivers/test_ipmitool.py b/ironic/tests/drivers/test_ipmitool.py
index a27060d0f..2e0097fba 100644
--- a/ironic/tests/drivers/test_ipmitool.py
+++ b/ironic/tests/drivers/test_ipmitool.py
@@ -840,6 +840,86 @@ class IPMIToolPrivateMethodTestCase(db_base.DbTestCase):
mock_support.assert_called_once_with('timing')
mock_pwf.assert_called_once_with(self.info['password'])
mock_exec.assert_called_once_with(*args)
+ self.assertEqual(1, mock_exec.call_count)
+
+ @mock.patch.object(ipmi, '_is_option_supported', autospec=True)
+ @mock.patch.object(utils, 'execute', autospec=True)
+ def test__exec_ipmitool_exception_retry(self,
+ mock_exec, mock_support, mock_sleep):
+
+ ipmi.LAST_CMD_TIME = {}
+ mock_support.return_value = False
+ mock_exec.side_effect = iter([
+ processutils.ProcessExecutionError(
+ stderr="insufficient resources for session"
+ ),
+ (None, None)
+ ])
+
+ # Directly set the configuration values such that
+ # the logic will cause _exec_ipmitool to retry twice.
+ self.config(min_command_interval=1, group='ipmi')
+ self.config(retry_timeout=2, group='ipmi')
+
+ ipmi._exec_ipmitool(self.info, 'A B C')
+
+ mock_support.assert_called_once_with('timing')
+ self.assertEqual(2, mock_exec.call_count)
+
+ @mock.patch.object(ipmi, '_is_option_supported', autospec=True)
+ @mock.patch.object(utils, 'execute', autospec=True)
+ def test__exec_ipmitool_exception_retries_exceeded(self,
+ mock_exec, mock_support, mock_sleep):
+
+ ipmi.LAST_CMD_TIME = {}
+ mock_support.return_value = False
+
+ mock_exec.side_effect = processutils.ProcessExecutionError(
+ stderr="insufficient resources for session"
+ )
+
+ # Directly set the configuration values such that
+ # the logic will cause _exec_ipmitool to timeout.
+ self.config(min_command_interval=1, group='ipmi')
+ self.config(retry_timeout=1, group='ipmi')
+
+ self.assertRaises(processutils.ProcessExecutionError,
+ ipmi._exec_ipmitool,
+ self.info, 'A B C')
+ mock_support.assert_called_once_with('timing')
+ self.assertEqual(1, mock_exec.call_count)
+
+ @mock.patch.object(ipmi, '_is_option_supported', autospec=True)
+ @mock.patch.object(utils, 'execute', autospec=True)
+ def test__exec_ipmitool_exception_non_retryable_failure(self,
+ mock_exec, mock_support, mock_sleep):
+
+ ipmi.LAST_CMD_TIME = {}
+ mock_support.return_value = False
+
+ # Return a retryable error, then an error that cannot
+ # be retried thus resulting in a single retry
+ # attempt by _exec_ipmitool.
+ mock_exec.side_effect = iter([
+ processutils.ProcessExecutionError(
+ stderr="insufficient resources for session"
+ ),
+ processutils.ProcessExecutionError(
+ stderr="Unknown"
+ ),
+ ])
+
+ # Directly set the configuration values such that
+ # the logic will cause _exec_ipmitool to retry up
+ # to 3 times.
+ self.config(min_command_interval=1, group='ipmi')
+ self.config(retry_timeout=3, group='ipmi')
+
+ self.assertRaises(processutils.ProcessExecutionError,
+ ipmi._exec_ipmitool,
+ self.info, 'A B C')
+ mock_support.assert_called_once_with('timing')
+ self.assertEqual(2, mock_exec.call_count)
@mock.patch.object(ipmi, '_exec_ipmitool', autospec=True)
def test__power_status_on(self, mock_exec, mock_sleep):
diff --git a/ironic/tests/drivers/test_iscsi_deploy.py b/ironic/tests/drivers/test_iscsi_deploy.py
index 01b4c853e..4d3803542 100644
--- a/ironic/tests/drivers/test_iscsi_deploy.py
+++ b/ironic/tests/drivers/test_iscsi_deploy.py
@@ -429,6 +429,7 @@ class IscsiDeployMethodsTestCase(db_base.DbTestCase):
'ironic_api_url': api_url,
'boot_option': expected_boot_option,
'boot_mode': expected_boot_mode,
+ 'coreos.configdrive': 0,
}
if expected_root_device:
@@ -486,6 +487,25 @@ class IscsiDeployMethodsTestCase(db_base.DbTestCase):
self._test_build_deploy_ramdisk_options(mock_alnum, fake_api_url,
expected_boot_option=expected)
+ @mock.patch.object(keystone, 'get_service_url', autospec=True)
+ @mock.patch.object(utils, 'random_alnum', autospec=True)
+ def test_build_deploy_ramdisk_options_whole_disk_image(self, mock_alnum,
+ mock_get_url):
+ """Tests a hack to boot_option for whole disk images.
+
+ This hack is in place to fix bug #1441556.
+ """
+ self.node.instance_info = {'capabilities': '{"boot_option": "local"}'}
+ dii = self.node.driver_internal_info
+ dii['is_whole_disk_image'] = True
+ self.node.driver_internal_info = dii
+ self.node.save()
+ expected = 'netboot'
+ fake_api_url = 'http://127.0.0.1:6385'
+ self.config(api_url=fake_api_url, group='conductor')
+ self._test_build_deploy_ramdisk_options(mock_alnum, fake_api_url,
+ expected_boot_option=expected)
+
def test_get_boot_option(self):
self.node.instance_info = {'capabilities': '{"boot_option": "local"}'}
result = iscsi_deploy.get_boot_option(self.node)
@@ -777,3 +797,118 @@ class IscsiDeployMethodsTestCase(db_base.DbTestCase):
self.assertEqual(states.DEPLOYFAIL, self.node.provision_state)
self.assertEqual(states.ACTIVE, self.node.target_provision_state)
self.assertIsNotNone(self.node.last_error)
+
+ def test_validate_pass_bootloader_info_input(self):
+ params = {'key': 'some-random-key', 'address': '1.2.3.4',
+ 'error': '', 'status': 'SUCCEEDED'}
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=False) as task:
+ task.node.instance_info['deploy_key'] = 'some-random-key'
+ # Assert that the method doesn't raise
+ iscsi_deploy.validate_pass_bootloader_info_input(task, params)
+
+ def test_validate_pass_bootloader_info_missing_status(self):
+ params = {'key': 'some-random-key', 'address': '1.2.3.4'}
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=False) as task:
+ self.assertRaises(exception.MissingParameterValue,
+ iscsi_deploy.validate_pass_bootloader_info_input,
+ task, params)
+
+ def test_validate_pass_bootloader_info_missing_key(self):
+ params = {'status': 'SUCCEEDED', 'address': '1.2.3.4'}
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=False) as task:
+ self.assertRaises(exception.MissingParameterValue,
+ iscsi_deploy.validate_pass_bootloader_info_input,
+ task, params)
+
+ def test_validate_pass_bootloader_info_missing_address(self):
+ params = {'status': 'SUCCEEDED', 'key': 'some-random-key'}
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=False) as task:
+ self.assertRaises(exception.MissingParameterValue,
+ iscsi_deploy.validate_pass_bootloader_info_input,
+ task, params)
+
+ def test_validate_pass_bootloader_info_input_invalid_key(self):
+ params = {'key': 'some-other-key', 'address': '1.2.3.4',
+ 'status': 'SUCCEEDED'}
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=False) as task:
+ task.node.instance_info['deploy_key'] = 'some-random-key'
+ self.assertRaises(exception.InvalidParameterValue,
+ iscsi_deploy.validate_pass_bootloader_info_input,
+ task, params)
+
+ def test_validate_bootloader_install_status(self):
+ kwargs = {'key': 'abcdef', 'status': 'SUCCEEDED', 'error': ''}
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=False) as task:
+ task.node.instance_info['deploy_key'] = 'abcdef'
+ # Nothing much to assert except that it shouldn't raise.
+ iscsi_deploy.validate_bootloader_install_status(task, kwargs)
+
+ @mock.patch.object(deploy_utils, 'set_failed_state', autospec=True)
+ def test_validate_bootloader_install_status_install_failed(
+ self, set_fail_state_mock):
+ kwargs = {'key': 'abcdef', 'status': 'FAILED', 'error': 'some-error'}
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=False) as task:
+ task.node.provision_state = states.DEPLOYING
+ task.node.target_provision_state = states.ACTIVE
+ task.node.instance_info['deploy_key'] = 'abcdef'
+ self.assertRaises(exception.InstanceDeployFailure,
+ iscsi_deploy.validate_bootloader_install_status,
+ task, kwargs)
+ set_fail_state_mock.assert_called_once_with(task, mock.ANY)
+
+ @mock.patch.object(deploy_utils, 'notify_ramdisk_to_proceed',
+ autospec=True)
+ def test_finish_deploy(self, notify_mock):
+ self.node.provision_state = states.DEPLOYING
+ self.node.target_provision_state = states.ACTIVE
+ self.node.save()
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=False) as task:
+ iscsi_deploy.finish_deploy(task, '1.2.3.4')
+ notify_mock.assert_called_once_with('1.2.3.4')
+ self.assertEqual(states.ACTIVE, task.node.provision_state)
+ self.assertEqual(states.NOSTATE, task.node.target_provision_state)
+
+ @mock.patch.object(deploy_utils, 'set_failed_state', autospec=True)
+ @mock.patch.object(deploy_utils, 'notify_ramdisk_to_proceed',
+ autospec=True)
+ def test_finish_deploy_notify_fails(self, notify_mock,
+ set_fail_state_mock):
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=False) as task:
+ notify_mock.side_effect = RuntimeError()
+ self.assertRaises(exception.InstanceDeployFailure,
+ iscsi_deploy.finish_deploy, task, '1.2.3.4')
+ set_fail_state_mock.assert_called_once_with(task, mock.ANY)
+
+ @mock.patch.object(manager_utils, 'node_power_action')
+ @mock.patch.object(deploy_utils, 'notify_ramdisk_to_proceed',
+ autospec=True)
+ def test_finish_deploy_ssh_with_local_boot(self, notify_mock,
+ node_power_mock):
+ instance_info = dict(INST_INFO_DICT)
+ instance_info['capabilities'] = {'boot_option': 'local'}
+ n = {
+ 'uuid': uuidutils.generate_uuid(),
+ 'driver': 'fake_ssh',
+ 'instance_info': instance_info,
+ 'provision_state': states.DEPLOYING,
+ 'target_provision_state': states.ACTIVE,
+ }
+ mgr_utils.mock_the_extension_manager(driver="fake_ssh")
+ node = obj_utils.create_test_node(self.context, **n)
+
+ with task_manager.acquire(self.context, node.uuid,
+ shared=False) as task:
+ iscsi_deploy.finish_deploy(task, '1.2.3.4')
+ notify_mock.assert_called_once_with('1.2.3.4')
+ self.assertEqual(states.ACTIVE, task.node.provision_state)
+ self.assertEqual(states.NOSTATE, task.node.target_provision_state)
+ node_power_mock.assert_called_once_with(task, states.REBOOT)
diff --git a/ironic/tests/drivers/test_pxe.py b/ironic/tests/drivers/test_pxe.py
index a7a211f75..0c6168c86 100644
--- a/ironic/tests/drivers/test_pxe.py
+++ b/ironic/tests/drivers/test_pxe.py
@@ -198,7 +198,8 @@ class PXEPrivateMethodsTestCase(db_base.DbTestCase):
@mock.patch.object(iscsi_deploy, 'build_deploy_ramdisk_options')
@mock.patch.object(pxe_utils, '_build_pxe_config')
def _test_build_pxe_config_options(self, build_pxe_mock, deploy_opts_mock,
- ipxe_enabled=False):
+ whle_dsk_img=False,
+ ipxe_enabled=False):
self.config(pxe_append_params='test_param', group='pxe')
# NOTE: right '/' should be removed from url string
self.config(api_url='http://192.168.122.184:6385', group='conductor')
@@ -212,9 +213,11 @@ class PXEPrivateMethodsTestCase(db_base.DbTestCase):
'ironic_api_url': 'fake-api-url',
'boot_option': 'netboot',
'boot_mode': 'bios',
+ 'coreos.configdrive': 0,
}
deploy_opts_mock.return_value = fake_deploy_opts
+ self.node.driver_internal_info['is_whole_disk_image'] = whle_dsk_img
tftp_server = CONF.pxe.tftp_server
@@ -241,6 +244,10 @@ class PXEPrivateMethodsTestCase(db_base.DbTestCase):
'ramdisk')
root_dir = CONF.pxe.tftp_root
+ if whle_dsk_img:
+ ramdisk = 'no_ramdisk'
+ kernel = 'no_kernel'
+
expected_options = {
'ari_path': ramdisk,
'deployment_ari_path': deploy_ramdisk,
@@ -278,30 +285,36 @@ class PXEPrivateMethodsTestCase(db_base.DbTestCase):
self.assertEqual(expected_options, options)
def test__build_pxe_config_options(self):
- self._test_build_pxe_config_options(ipxe_enabled=False)
+ self._test_build_pxe_config_options(whle_dsk_img=True,
+ ipxe_enabled=False)
def test__build_pxe_config_options_ipxe(self):
- self._test_build_pxe_config_options(ipxe_enabled=True)
+ self._test_build_pxe_config_options(whle_dsk_img=True,
+ ipxe_enabled=True)
def test__build_pxe_config_options_without_is_whole_disk_image(self):
del self.node.driver_internal_info['is_whole_disk_image']
self.node.save()
- self._test_build_pxe_config_options(ipxe_enabled=False)
+ self._test_build_pxe_config_options(whle_dsk_img=False,
+ ipxe_enabled=False)
@mock.patch.object(iscsi_deploy, 'build_deploy_ramdisk_options')
@mock.patch.object(pxe_utils, '_build_pxe_config')
- def _test_build_pxe_config_options_whole_disk_image(self, build_pxe_mock,
- deploy_opts_mock, ipxe_enabled=False):
+ def test__build_pxe_config_options_whole_disk_image(self,
+ build_pxe_mock,
+ deploy_opts_mock,
+ ipxe_enabled=False):
self.config(pxe_append_params='test_param', group='pxe')
# NOTE: right '/' should be removed from url string
- self.config(api_url='http://192.168.122.184:6385/', group='conductor')
+ self.config(api_url='http://192.168.122.184:6385', group='conductor')
self.config(disk_devices='sda', group='pxe')
fake_deploy_opts = {'iscsi_target_iqn': 'fake-iqn',
'deployment_id': 'fake-deploy-id',
'deployment_key': 'fake-deploy-key',
'disk': 'fake-disk',
- 'ironic_api_url': 'fake-api-url'}
+ 'ironic_api_url': 'fake-api-url',
+ 'coreos.configdrive': 0}
deploy_opts_mock.return_value = fake_deploy_opts
@@ -329,6 +342,10 @@ class PXEPrivateMethodsTestCase(db_base.DbTestCase):
'pxe_append_params': 'test_param',
'deployment_aki_path': deploy_kernel,
'tftp_server': tftp_server,
+ 'aki_path': 'no_kernel',
+ 'ari_path': 'no_ramdisk',
+ 'ipa-api-url': CONF.conductor.api_url,
+ 'ipa-driver-name': self.node.driver,
}
expected_options.update(fake_deploy_opts)
@@ -401,6 +418,48 @@ class PXEPrivateMethodsTestCase(db_base.DbTestCase):
fake_pxe_info.values(),
True)
+ @mock.patch.object(pxe.LOG, 'error')
+ def test_validate_boot_option_for_uefi_exc(self, mock_log):
+ properties = {'capabilities': 'boot_mode:uefi'}
+ instance_info = {"boot_option": "netboot"}
+ self.node.properties = properties
+ self.node.instance_info['capabilities'] = instance_info
+ self.node.driver_internal_info['is_whole_disk_image'] = True
+ self.assertRaises(exception.InvalidParameterValue,
+ pxe.validate_boot_option_for_uefi,
+ self.node)
+ self.assertTrue(mock_log.called)
+
+ @mock.patch.object(pxe.LOG, 'error')
+ def test_validate_boot_option_for_uefi_noexc_one(self, mock_log):
+ properties = {'capabilities': 'boot_mode:uefi'}
+ instance_info = {"boot_option": "local"}
+ self.node.properties = properties
+ self.node.instance_info['capabilities'] = instance_info
+ self.node.driver_internal_info['is_whole_disk_image'] = True
+ pxe.validate_boot_option_for_uefi(self.node)
+ self.assertFalse(mock_log.called)
+
+ @mock.patch.object(pxe.LOG, 'error')
+ def test_validate_boot_option_for_uefi_noexc_two(self, mock_log):
+ properties = {'capabilities': 'boot_mode:bios'}
+ instance_info = {"boot_option": "local"}
+ self.node.properties = properties
+ self.node.instance_info['capabilities'] = instance_info
+ self.node.driver_internal_info['is_whole_disk_image'] = True
+ pxe.validate_boot_option_for_uefi(self.node)
+ self.assertFalse(mock_log.called)
+
+ @mock.patch.object(pxe.LOG, 'error')
+ def test_validate_boot_option_for_uefi_noexc_three(self, mock_log):
+ properties = {'capabilities': 'boot_mode:uefi'}
+ instance_info = {"boot_option": "local"}
+ self.node.properties = properties
+ self.node.instance_info['capabilities'] = instance_info
+ self.node.driver_internal_info['is_whole_disk_image'] = False
+ pxe.validate_boot_option_for_uefi(self.node)
+ self.assertFalse(mock_log.called)
+
class PXEDriverTestCase(db_base.DbTestCase):
@@ -484,6 +543,17 @@ class PXEDriverTestCase(db_base.DbTestCase):
self.assertRaises(exception.InvalidParameterValue,
task.driver.deploy.validate, task)
+ def test_validate_fail_invalid_config_uefi_whole_disk_image(self):
+ properties = {'capabilities': 'boot_mode:uefi,boot_option:netboot'}
+ instance_info = {"boot_option": "netboot"}
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=True) as task:
+ task.node.properties = properties
+ task.node.instance_info['capabilities'] = instance_info
+ task.node.driver_internal_info['is_whole_disk_image'] = True
+ self.assertRaises(exception.InvalidParameterValue,
+ task.driver.deploy.validate, task)
+
@mock.patch.object(base_image_service.BaseImageService, '_show')
def test_validate_fail_invalid_boot_option(self, mock_glance):
properties = {'capabilities': 'boot_option:foo,dog:wuff'}
@@ -611,6 +681,33 @@ class PXEDriverTestCase(db_base.DbTestCase):
address='123456', iqn='aaa-bbb',
key='fake-12345')
+ @mock.patch.object(iscsi_deploy, 'validate_pass_bootloader_info_input',
+ autospec=True)
+ def test_vendor_passthru_pass_bootloader_install_info(self,
+ validate_mock):
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=True) as task:
+ kwargs = {'address': '1.2.3.4', 'key': 'fake-key',
+ 'status': 'SUCCEEDED', 'error': ''}
+ task.driver.vendor.validate(
+ task, method='pass_bootloader_install_info', **kwargs)
+ validate_mock.assert_called_once_with(task, kwargs)
+
+ @mock.patch.object(iscsi_deploy, 'validate_bootloader_install_status',
+ autospec=True)
+ @mock.patch.object(iscsi_deploy, 'finish_deploy', autospec=True)
+ def test_pass_bootloader_install_info(self, finish_deploy_mock,
+ validate_input_mock):
+ kwargs = {'method': 'pass_deploy_info', 'address': '123456'}
+ self.node.provision_state = states.DEPLOYWAIT
+ self.node.target_provision_state = states.ACTIVE
+ self.node.save()
+ with task_manager.acquire(self.context, self.node.uuid,
+ shared=False) as task:
+ task.driver.vendor.pass_bootloader_install_info(task, **kwargs)
+ finish_deploy_mock.assert_called_once_with(task, '123456')
+ validate_input_mock.assert_called_once_with(task, kwargs)
+
@mock.patch.object(pxe, '_get_image_info')
@mock.patch.object(pxe, '_cache_ramdisk_kernel')
@mock.patch.object(pxe, '_build_pxe_config_options')
@@ -831,7 +928,7 @@ class PXEDriverTestCase(db_base.DbTestCase):
@mock.patch.object(pxe_utils, 'clean_up_pxe_config')
@mock.patch.object(manager_utils, 'node_set_boot_device')
- @mock.patch.object(deploy_utils, 'notify_deploy_complete')
+ @mock.patch.object(deploy_utils, 'notify_ramdisk_to_proceed')
@mock.patch.object(deploy_utils, 'switch_pxe_config')
@mock.patch.object(iscsi_deploy, 'InstanceImageCache')
@mock.patch.object(deploy_utils, 'deploy_partition_image')
@@ -862,8 +959,6 @@ class PXEDriverTestCase(db_base.DbTestCase):
task, address='123456', iqn='aaa-bbb', key='fake-56789')
self.node.refresh()
- self.assertEqual(states.ACTIVE, self.node.provision_state)
- self.assertEqual(states.NOSTATE, self.node.target_provision_state)
self.assertEqual(states.POWER_ON, self.node.power_state)
self.assertIn('root_uuid_or_disk_id', self.node.driver_internal_info)
self.assertIsNone(self.node.last_error)
@@ -887,7 +982,7 @@ class PXEDriverTestCase(db_base.DbTestCase):
@mock.patch.object(pxe_utils, 'clean_up_pxe_config')
@mock.patch.object(manager_utils, 'node_set_boot_device')
- @mock.patch.object(deploy_utils, 'notify_deploy_complete')
+ @mock.patch.object(deploy_utils, 'notify_ramdisk_to_proceed')
@mock.patch.object(deploy_utils, 'switch_pxe_config')
@mock.patch.object(iscsi_deploy, 'InstanceImageCache')
@mock.patch.object(deploy_utils, 'deploy_disk_image')
@@ -923,8 +1018,6 @@ class PXEDriverTestCase(db_base.DbTestCase):
key='fake-56789')
self.node.refresh()
- self.assertEqual(states.ACTIVE, self.node.provision_state)
- self.assertEqual(states.NOSTATE, self.node.target_provision_state)
self.assertEqual(states.POWER_ON, self.node.power_state)
self.assertIsNone(self.node.last_error)
self.assertFalse(os.path.exists(token_path))
@@ -947,15 +1040,23 @@ class PXEDriverTestCase(db_base.DbTestCase):
def test_pass_deploy_info_deploy(self):
self._test_pass_deploy_info_deploy(False)
+ self.assertEqual(states.ACTIVE, self.node.provision_state)
+ self.assertEqual(states.NOSTATE, self.node.target_provision_state)
def test_pass_deploy_info_localboot(self):
self._test_pass_deploy_info_deploy(True)
+ self.assertEqual(states.DEPLOYWAIT, self.node.provision_state)
+ self.assertEqual(states.ACTIVE, self.node.target_provision_state)
def test_pass_deploy_info_whole_disk_image(self):
self._test_pass_deploy_info_whole_disk_image(False)
+ self.assertEqual(states.ACTIVE, self.node.provision_state)
+ self.assertEqual(states.NOSTATE, self.node.target_provision_state)
def test_pass_deploy_info_whole_disk_image_localboot(self):
self._test_pass_deploy_info_whole_disk_image(True)
+ self.assertEqual(states.ACTIVE, self.node.provision_state)
+ self.assertEqual(states.NOSTATE, self.node.target_provision_state)
def test_pass_deploy_info_invalid(self):
self.node.power_state = states.POWER_ON
@@ -986,7 +1087,8 @@ class PXEDriverTestCase(db_base.DbTestCase):
"pass_deploy_info was not called once.")
def test_vendor_routes(self):
- expected = ['heartbeat', 'pass_deploy_info']
+ expected = ['heartbeat', 'pass_deploy_info',
+ 'pass_bootloader_install_info']
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
vendor_routes = task.driver.vendor.vendor_routes
diff --git a/ironic/tests/drivers/test_seamicro.py b/ironic/tests/drivers/test_seamicro.py
index ad4586828..e477cddd4 100644
--- a/ironic/tests/drivers/test_seamicro.py
+++ b/ironic/tests/drivers/test_seamicro.py
@@ -129,6 +129,7 @@ class SeaMicroValidateParametersTestCase(db_base.DbTestCase):
node)
+@mock.patch('eventlet.greenthread.sleep', lambda n: None)
class SeaMicroPrivateMethodsTestCase(db_base.DbTestCase):
def setUp(self):
@@ -144,8 +145,6 @@ class SeaMicroPrivateMethodsTestCase(db_base.DbTestCase):
self.config(action_timeout=0, group='seamicro')
self.config(max_retry=2, group='seamicro')
- self.patcher = mock.patch('eventlet.greenthread.sleep')
- self.mock_sleep = self.patcher.start()
self.info = seamicro._parse_driver_info(self.node)
@mock.patch.object(seamicro_client, "Client")
diff --git a/ironic/tests/drivers/test_ssh.py b/ironic/tests/drivers/test_ssh.py
index f70e21309..76e023675 100644
--- a/ironic/tests/drivers/test_ssh.py
+++ b/ironic/tests/drivers/test_ssh.py
@@ -283,7 +283,7 @@ class SSHPrivateMethodsTestCase(db_base.DbTestCase):
info)
get_hosts_name_mock.assert_called_once_with(self.sshclient, info)
- exec_ssh_mock.assert_not_called()
+ self.assertFalse(exec_ssh_mock.called)
@mock.patch.object(processutils, 'ssh_execute')
def test__get_power_status_exception(self, exec_ssh_mock):
diff --git a/ironic/tests/drivers/test_utils.py b/ironic/tests/drivers/test_utils.py
index 1ca6e90d4..cd14b464f 100644
--- a/ironic/tests/drivers/test_utils.py
+++ b/ironic/tests/drivers/test_utils.py
@@ -112,27 +112,6 @@ class UtilsTestCase(db_base.DbTestCase):
self.assertEqual('a:b,c:d,a:b',
task.node.properties['capabilities'])
- def test_rm_node_capability(self):
- with task_manager.acquire(self.context, self.node.uuid,
- shared=False) as task:
- task.node.properties['capabilities'] = 'a:b'
- driver_utils.rm_node_capability(task, 'a')
- self.assertIsNone(task.node.properties['capabilities'])
-
- def test_rm_node_capability_exists(self):
- with task_manager.acquire(self.context, self.node.uuid,
- shared=False) as task:
- task.node.properties['capabilities'] = 'a:b,c:d,x:y'
- self.assertIsNone(driver_utils.rm_node_capability(task, 'c'))
- self.assertEqual('a:b,x:y', task.node.properties['capabilities'])
-
- def test_rm_node_capability_non_existent(self):
- with task_manager.acquire(self.context, self.node.uuid,
- shared=False) as task:
- task.node.properties['capabilities'] = 'a:b'
- self.assertIsNone(driver_utils.rm_node_capability(task, 'x'))
- self.assertEqual('a:b', task.node.properties['capabilities'])
-
def test_validate_capability(self):
properties = {'capabilities': 'cat:meow,cap2:value2'}
self.node.properties = properties
diff --git a/ironic/tests/objects/utils.py b/ironic/tests/objects/utils.py
index 1eead9e8b..aa21c91fd 100644
--- a/ironic/tests/objects/utils.py
+++ b/ironic/tests/objects/utils.py
@@ -79,6 +79,9 @@ def get_test_chassis(ctxt, **kw):
that a create() could be used to commit it to the DB.
"""
db_chassis = db_utils.get_test_chassis(**kw)
+ # Let DB generate ID if it isn't specified explicitly
+ if 'id' not in kw:
+ del db_chassis['id']
chassis = objects.Chassis(ctxt)
for key in db_chassis:
setattr(chassis, key, db_chassis[key])
diff --git a/ironic/tests/stubs.py b/ironic/tests/stubs.py
index 7d43d2676..d20c1fd8a 100644
--- a/ironic/tests/stubs.py
+++ b/ironic/tests/stubs.py
@@ -12,7 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
-from ironic.common import exception
+from glanceclient import exc as glance_exc
NOW_GLANCE_FORMAT = "2010-10-11T10:30:22"
@@ -40,7 +40,7 @@ class StubGlanceClient(object):
index += 1
break
else:
- raise exception.BadRequest('Marker not found')
+ raise glance_exc.BadRequest('Marker not found')
return self._images[index:index + limit]
@@ -48,7 +48,7 @@ class StubGlanceClient(object):
for image in self._images:
if image.id == str(image_id):
return image
- raise exception.ImageNotFound(image_id)
+ raise glance_exc.NotFound(image_id)
def data(self, image_id):
self.get(image_id)
@@ -76,7 +76,7 @@ class StubGlanceClient(object):
for k, v in metadata.items():
setattr(self._images[i], k, v)
return self._images[i]
- raise exception.NotFound(image_id)
+ raise glance_exc.NotFound(image_id)
def delete(self, image_id):
for i, image in enumerate(self._images):
@@ -86,10 +86,10 @@ class StubGlanceClient(object):
# HTTPForbidden.
image_data = self._images[i]
if image_data.deleted:
- raise exception.Forbidden()
+ raise glance_exc.Forbidden()
image_data.deleted = True
return
- raise exception.NotFound(image_id)
+ raise glance_exc.NotFound(image_id)
class FakeImage(object):
diff --git a/ironic/tests/test_disk_partitioner.py b/ironic/tests/test_disk_partitioner.py
index 00cbef5e4..941c92b3c 100644
--- a/ironic/tests/test_disk_partitioner.py
+++ b/ironic/tests/test_disk_partitioner.py
@@ -47,8 +47,9 @@ class DiskPartitionerTestCase(base.TestCase):
self.assertThat(partitions, HasLength(3))
self.assertEqual(expected, partitions)
- @mock.patch.object(disk_partitioner.DiskPartitioner, '_exec')
- @mock.patch.object(utils, 'execute')
+ @mock.patch.object(disk_partitioner.DiskPartitioner, '_exec',
+ autospec=True)
+ @mock.patch.object(utils, 'execute', autospec=True)
def test_commit(self, mock_utils_exc, mock_disk_partitioner_exec):
dp = disk_partitioner.DiskPartitioner('/dev/fake')
fake_parts = [(1, {'bootable': False,
@@ -59,20 +60,22 @@ class DiskPartitionerTestCase(base.TestCase):
'fs_type': 'fake-fs-type',
'type': 'fake-type',
'size': 1})]
- with mock.patch.object(dp, 'get_partitions') as mock_gp:
+ with mock.patch.object(dp, 'get_partitions', autospec=True) as mock_gp:
mock_gp.return_value = fake_parts
mock_utils_exc.return_value = (None, None)
dp.commit()
- mock_disk_partitioner_exec.assert_called_once_with('mklabel', 'msdos',
+ mock_disk_partitioner_exec.assert_called_once_with(
+ mock.ANY, 'mklabel', 'msdos',
'mkpart', 'fake-type', 'fake-fs-type', '1', '2',
'mkpart', 'fake-type', 'fake-fs-type', '2', '3',
'set', '2', 'boot', 'on')
mock_utils_exc.assert_called_once_with('fuser', '/dev/fake',
run_as_root=True, check_exit_code=[0, 1])
- @mock.patch.object(disk_partitioner.DiskPartitioner, '_exec')
- @mock.patch.object(utils, 'execute')
+ @mock.patch.object(disk_partitioner.DiskPartitioner, '_exec',
+ autospec=True)
+ @mock.patch.object(utils, 'execute', autospec=True)
def test_commit_with_device_is_busy_once(self, mock_utils_exc,
mock_disk_partitioner_exec):
dp = disk_partitioner.DiskPartitioner('/dev/fake')
@@ -84,14 +87,15 @@ class DiskPartitionerTestCase(base.TestCase):
'fs_type': 'fake-fs-type',
'type': 'fake-type',
'size': 1})]
- fuser_outputs = [("/dev/fake: 10000 10001", None), (None, None)]
+ fuser_outputs = iter([("/dev/fake: 10000 10001", None), (None, None)])
- with mock.patch.object(dp, 'get_partitions') as mock_gp:
+ with mock.patch.object(dp, 'get_partitions', autospec=True) as mock_gp:
mock_gp.return_value = fake_parts
mock_utils_exc.side_effect = fuser_outputs
dp.commit()
- mock_disk_partitioner_exec.assert_called_once_with('mklabel', 'msdos',
+ mock_disk_partitioner_exec.assert_called_once_with(
+ mock.ANY, 'mklabel', 'msdos',
'mkpart', 'fake-type', 'fake-fs-type', '1', '2',
'mkpart', 'fake-type', 'fake-fs-type', '2', '3',
'set', '2', 'boot', 'on')
@@ -99,8 +103,9 @@ class DiskPartitionerTestCase(base.TestCase):
run_as_root=True, check_exit_code=[0, 1])
self.assertEqual(2, mock_utils_exc.call_count)
- @mock.patch.object(disk_partitioner.DiskPartitioner, '_exec')
- @mock.patch.object(utils, 'execute')
+ @mock.patch.object(disk_partitioner.DiskPartitioner, '_exec',
+ autospec=True)
+ @mock.patch.object(utils, 'execute', autospec=True)
def test_commit_with_device_is_always_busy(self, mock_utils_exc,
mock_disk_partitioner_exec):
dp = disk_partitioner.DiskPartitioner('/dev/fake')
@@ -113,12 +118,13 @@ class DiskPartitionerTestCase(base.TestCase):
'type': 'fake-type',
'size': 1})]
- with mock.patch.object(dp, 'get_partitions') as mock_gp:
+ with mock.patch.object(dp, 'get_partitions', autospec=True) as mock_gp:
mock_gp.return_value = fake_parts
mock_utils_exc.return_value = ("/dev/fake: 10000 10001", None)
self.assertRaises(exception.InstanceDeployFailure, dp.commit)
- mock_disk_partitioner_exec.assert_called_once_with('mklabel', 'msdos',
+ mock_disk_partitioner_exec.assert_called_once_with(
+ mock.ANY, 'mklabel', 'msdos',
'mkpart', 'fake-type', 'fake-fs-type', '1', '2',
'mkpart', 'fake-type', 'fake-fs-type', '2', '3',
'set', '2', 'boot', 'on')
@@ -126,8 +132,9 @@ class DiskPartitionerTestCase(base.TestCase):
run_as_root=True, check_exit_code=[0, 1])
self.assertEqual(20, mock_utils_exc.call_count)
- @mock.patch.object(disk_partitioner.DiskPartitioner, '_exec')
- @mock.patch.object(utils, 'execute')
+ @mock.patch.object(disk_partitioner.DiskPartitioner, '_exec',
+ autospec=True)
+ @mock.patch.object(utils, 'execute', autospec=True)
def test_commit_with_device_disconnected(self, mock_utils_exc,
mock_disk_partitioner_exec):
dp = disk_partitioner.DiskPartitioner('/dev/fake')
@@ -140,13 +147,14 @@ class DiskPartitionerTestCase(base.TestCase):
'type': 'fake-type',
'size': 1})]
- with mock.patch.object(dp, 'get_partitions') as mock_gp:
+ with mock.patch.object(dp, 'get_partitions', autospec=True) as mock_gp:
mock_gp.return_value = fake_parts
mock_utils_exc.return_value = (None, "Specified filename /dev/fake"
" does not exist.")
self.assertRaises(exception.InstanceDeployFailure, dp.commit)
- mock_disk_partitioner_exec.assert_called_once_with('mklabel', 'msdos',
+ mock_disk_partitioner_exec.assert_called_once_with(
+ mock.ANY, 'mklabel', 'msdos',
'mkpart', 'fake-type', 'fake-fs-type', '1', '2',
'mkpart', 'fake-type', 'fake-fs-type', '2', '3',
'set', '2', 'boot', 'on')
@@ -155,7 +163,7 @@ class DiskPartitionerTestCase(base.TestCase):
self.assertEqual(20, mock_utils_exc.call_count)
-@mock.patch.object(utils, 'execute')
+@mock.patch.object(utils, 'execute', autospec=True)
class ListPartitionsTestCase(base.TestCase):
def test_correct(self, execute_mock):
@@ -178,7 +186,7 @@ BYT;
'parted', '-s', '-m', '/dev/fake', 'unit', 'MiB', 'print',
use_standard_locale=True)
- @mock.patch.object(disk_partitioner.LOG, 'warn')
+ @mock.patch.object(disk_partitioner.LOG, 'warn', autospec=True)
def test_incorrect(self, log_mock, execute_mock):
output = """
BYT;
diff --git a/ironic/tests/test_driver_factory.py b/ironic/tests/test_driver_factory.py
index 6f5be3c09..1dee9d0de 100644
--- a/ironic/tests/test_driver_factory.py
+++ b/ironic/tests/test_driver_factory.py
@@ -52,7 +52,8 @@ class DriverLoadTestCase(base.TestCase):
self.assertRaises(exception.DriverLoadError,
driver_factory.DriverFactory._init_extension_manager)
- @mock.patch.object(dispatch.NameDispatchExtensionManager, 'names')
+ @mock.patch.object(dispatch.NameDispatchExtensionManager, 'names',
+ autospec=True)
def test_no_driver_load_error_if_driver_disabled(self, mock_em):
self.config(enabled_drivers=[])
with mock.patch.object(dispatch.NameDispatchExtensionManager,
diff --git a/ironic/tests/test_exception.py b/ironic/tests/test_exception.py
new file mode 100644
index 000000000..75e8c7cfb
--- /dev/null
+++ b/ironic/tests/test_exception.py
@@ -0,0 +1,29 @@
+# Copyright (c) 2015 IBM, Corp.
+#
+# 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 six
+
+from ironic.common import exception
+from ironic.tests import base
+
+
+class TestIronicException(base.TestCase):
+ def test____init__(self):
+ expected = '\xc3\xa9\xe0\xaf\xb2\xe0\xbe\x84'
+ if six.PY3:
+ message = chr(233) + chr(0x0bf2) + chr(3972)
+ else:
+ message = unichr(233) + unichr(0x0bf2) + unichr(3972)
+ exc = exception.IronicException(message)
+ self.assertEqual(expected, exc.__str__())
diff --git a/ironic/tests/test_glance_service.py b/ironic/tests/test_glance_service.py
index dfe6d90b3..6c3276da6 100644
--- a/ironic/tests/test_glance_service.py
+++ b/ironic/tests/test_glance_service.py
@@ -18,9 +18,13 @@ import datetime
import filecmp
import os
import tempfile
+import time
+from glanceclient import exc as glance_exc
import mock
+from oslo_config import cfg
from oslo_context import context
+from oslo_serialization import jsonutils
import testtools
@@ -32,8 +36,6 @@ from ironic.tests import base
from ironic.tests import matchers
from ironic.tests import stubs
-from oslo_config import cfg
-from oslo_serialization import jsonutils
CONF = cfg.CONF
@@ -458,7 +460,8 @@ class TestGlanceImageService(base.TestCase):
self.assertEqual(self.NOW_DATETIME, image_meta['created_at'])
self.assertEqual(self.NOW_DATETIME, image_meta['updated_at'])
- def test_download_with_retries(self):
+ @mock.patch.object(time, 'sleep', autospec=True)
+ def test_download_with_retries(self, mock_sleep):
tries = [0]
class MyGlanceStubClient(stubs.StubGlanceClient):
@@ -466,7 +469,7 @@ class TestGlanceImageService(base.TestCase):
def get(self, image_id):
if tries[0] == 0:
tries[0] = 1
- raise exception.ServiceUnavailable('')
+ raise glance_exc.ServiceUnavailable('')
else:
return {}
@@ -487,6 +490,7 @@ class TestGlanceImageService(base.TestCase):
tries = [0]
self.config(glance_num_retries=1, group='glance')
stub_service.download(image_id, writer)
+ self.assertTrue(mock_sleep.called)
def test_download_file_url(self):
# NOTE: only in v2 API
@@ -533,7 +537,7 @@ class TestGlanceImageService(base.TestCase):
class MyGlanceStubClient(stubs.StubGlanceClient):
"""A client that raises a Forbidden exception."""
def get(self, image_id):
- raise exception.Forbidden(image_id)
+ raise glance_exc.Forbidden(image_id)
stub_client = MyGlanceStubClient()
stub_context = context.RequestContext(auth_token=True)
@@ -549,7 +553,7 @@ class TestGlanceImageService(base.TestCase):
class MyGlanceStubClient(stubs.StubGlanceClient):
"""A client that raises a HTTPForbidden exception."""
def get(self, image_id):
- raise exception.HTTPForbidden(image_id)
+ raise glance_exc.HTTPForbidden(image_id)
stub_client = MyGlanceStubClient()
stub_context = context.RequestContext(auth_token=True)
@@ -565,7 +569,7 @@ class TestGlanceImageService(base.TestCase):
class MyGlanceStubClient(stubs.StubGlanceClient):
"""A client that raises a NotFound exception."""
def get(self, image_id):
- raise exception.NotFound(image_id)
+ raise glance_exc.NotFound(image_id)
stub_client = MyGlanceStubClient()
stub_context = context.RequestContext(auth_token=True)
@@ -581,7 +585,7 @@ class TestGlanceImageService(base.TestCase):
class MyGlanceStubClient(stubs.StubGlanceClient):
"""A client that raises a HTTPNotFound exception."""
def get(self, image_id):
- raise exception.HTTPNotFound(image_id)
+ raise glance_exc.HTTPNotFound(image_id)
stub_client = MyGlanceStubClient()
stub_context = context.RequestContext(auth_token=True)
@@ -632,7 +636,7 @@ def _create_failing_glance_client(info):
def get(self, image_id):
info['num_calls'] += 1
if info['num_calls'] == 1:
- raise exception.ServiceUnavailable('')
+ raise glance_exc.ServiceUnavailable('')
return {}
return MyGlanceStubClient()
@@ -663,7 +667,7 @@ class TestGlanceSwiftTempURL(base.TestCase):
'id': '757274c4-2856-4bd2-bb20-9a4a231e187b'
}
- @mock.patch('swiftclient.utils.generate_temp_url')
+ @mock.patch('swiftclient.utils.generate_temp_url', autospec=True)
def test_swift_temp_url(self, tempurl_mock):
path = ('/v1/AUTH_a422b2-91f3-2f46-74b7-d7c9e8958f5d30'
@@ -686,7 +690,7 @@ class TestGlanceSwiftTempURL(base.TestCase):
key=CONF.glance.swift_temp_url_key,
method='GET')
- @mock.patch('swiftclient.utils.generate_temp_url')
+ @mock.patch('swiftclient.utils.generate_temp_url', autospec=True)
def test_swift_temp_url_multiple_containers(self, tempurl_mock):
self.config(swift_store_multiple_containers_seed=8,
diff --git a/ironic/tests/test_hash_ring.py b/ironic/tests/test_hash_ring.py
index 54a4ca0d3..8f483f774 100644
--- a/ironic/tests/test_hash_ring.py
+++ b/ironic/tests/test_hash_ring.py
@@ -36,7 +36,7 @@ class HashRingTestCase(base.TestCase):
# fake -> foo, bar, baz
# fake-again -> bar, baz, foo
- @mock.patch.object(hashlib, 'md5')
+ @mock.patch.object(hashlib, 'md5', autospec=True)
def test__hash2int_returns_int(self, mock_md5):
CONF.set_override('hash_partition_exponent', 0)
r1 = 32 * 'a'
diff --git a/ironic/tests/test_image_service.py b/ironic/tests/test_image_service.py
index c2e426f78..a5974d636 100644
--- a/ironic/tests/test_image_service.py
+++ b/ironic/tests/test_image_service.py
@@ -30,7 +30,7 @@ class HttpImageServiceTestCase(base.TestCase):
self.service = image_service.HttpImageService()
self.href = 'http://127.0.0.1:12345/fedora.qcow2'
- @mock.patch.object(requests, 'head')
+ @mock.patch.object(requests, 'head', autospec=True)
def test_validate_href(self, head_mock):
response = head_mock.return_value
response.status_code = 200
@@ -45,28 +45,28 @@ class HttpImageServiceTestCase(base.TestCase):
self.service.validate_href,
self.href)
- @mock.patch.object(requests, 'head')
+ @mock.patch.object(requests, 'head', autospec=True)
def test_validate_href_error_code(self, head_mock):
head_mock.return_value.status_code = 400
self.assertRaises(exception.ImageRefValidationFailed,
self.service.validate_href, self.href)
head_mock.assert_called_once_with(self.href)
- @mock.patch.object(requests, 'head')
+ @mock.patch.object(requests, 'head', autospec=True)
def test_validate_href_error(self, head_mock):
head_mock.side_effect = requests.ConnectionError()
self.assertRaises(exception.ImageRefValidationFailed,
self.service.validate_href, self.href)
head_mock.assert_called_once_with(self.href)
- @mock.patch.object(requests, 'head')
+ @mock.patch.object(requests, 'head', autospec=True)
def test_show(self, head_mock):
head_mock.return_value.status_code = 200
result = self.service.show(self.href)
head_mock.assert_called_with(self.href)
self.assertEqual({'size': 1, 'properties': {}}, result)
- @mock.patch.object(requests, 'head')
+ @mock.patch.object(requests, 'head', autospec=True)
def test_show_no_content_length(self, head_mock):
head_mock.return_value.status_code = 200
head_mock.return_value.headers = {}
@@ -74,8 +74,8 @@ class HttpImageServiceTestCase(base.TestCase):
self.service.show, self.href)
head_mock.assert_called_with(self.href)
- @mock.patch.object(shutil, 'copyfileobj')
- @mock.patch.object(requests, 'get')
+ @mock.patch.object(shutil, 'copyfileobj', autospec=True)
+ @mock.patch.object(requests, 'get', autospec=True)
def test_download_success(self, req_get_mock, shutil_mock):
response_mock = req_get_mock.return_value
response_mock.status_code = 200
@@ -88,15 +88,15 @@ class HttpImageServiceTestCase(base.TestCase):
)
req_get_mock.assert_called_once_with(self.href, stream=True)
- @mock.patch.object(requests, 'get',
+ @mock.patch.object(requests, 'get', autospec=True,
side_effect=requests.ConnectionError())
def test_download_fail_connerror(self, req_get_mock):
file_mock = mock.Mock(spec=file)
self.assertRaises(exception.ImageDownloadFailed,
self.service.download, self.href, file_mock)
- @mock.patch.object(shutil, 'copyfileobj')
- @mock.patch.object(requests, 'get')
+ @mock.patch.object(shutil, 'copyfileobj', autospec=True)
+ @mock.patch.object(requests, 'get', autospec=True)
def test_download_fail_ioerror(self, req_get_mock, shutil_mock):
response_mock = req_get_mock.return_value
response_mock.status_code = 200
@@ -115,31 +115,33 @@ class FileImageServiceTestCase(base.TestCase):
self.href = 'file:///home/user/image.qcow2'
self.href_path = '/home/user/image.qcow2'
- @mock.patch.object(os.path, 'isfile', return_value=True)
+ @mock.patch.object(os.path, 'isfile', return_value=True, autospec=True)
def test_validate_href(self, path_exists_mock):
self.service.validate_href(self.href)
path_exists_mock.assert_called_once_with(self.href_path)
- @mock.patch.object(os.path, 'isfile', return_value=False)
+ @mock.patch.object(os.path, 'isfile', return_value=False, autospec=True)
def test_validate_href_path_not_found_or_not_file(self, path_exists_mock):
self.assertRaises(exception.ImageRefValidationFailed,
self.service.validate_href, self.href)
path_exists_mock.assert_called_once_with(self.href_path)
- @mock.patch.object(os.path, 'getsize', return_value=42)
- @mock.patch.object(image_service.FileImageService, 'validate_href')
+ @mock.patch.object(os.path, 'getsize', return_value=42, autospec=True)
+ @mock.patch.object(image_service.FileImageService, 'validate_href',
+ autospec=True)
def test_show(self, _validate_mock, getsize_mock):
_validate_mock.return_value = self.href_path
result = self.service.show(self.href)
getsize_mock.assert_called_once_with(self.href_path)
- _validate_mock.assert_called_once_with(self.href)
+ _validate_mock.assert_called_once_with(mock.ANY, self.href)
self.assertEqual({'size': 42, 'properties': {}}, result)
- @mock.patch.object(os, 'link')
- @mock.patch.object(os, 'remove')
- @mock.patch.object(os, 'access', return_value=True)
- @mock.patch.object(os, 'stat')
- @mock.patch.object(image_service.FileImageService, 'validate_href')
+ @mock.patch.object(os, 'link', autospec=True)
+ @mock.patch.object(os, 'remove', autospec=True)
+ @mock.patch.object(os, 'access', return_value=True, autospec=True)
+ @mock.patch.object(os, 'stat', autospec=True)
+ @mock.patch.object(image_service.FileImageService, 'validate_href',
+ autospec=True)
def test_download_hard_link(self, _validate_mock, stat_mock, access_mock,
remove_mock, link_mock):
_validate_mock.return_value = self.href_path
@@ -147,18 +149,19 @@ class FileImageServiceTestCase(base.TestCase):
file_mock = mock.Mock(spec=file)
file_mock.name = 'file'
self.service.download(self.href, file_mock)
- _validate_mock.assert_called_once_with(self.href)
+ _validate_mock.assert_called_once_with(mock.ANY, self.href)
self.assertEqual(2, stat_mock.call_count)
access_mock.assert_called_once_with(self.href_path, os.R_OK | os.W_OK)
remove_mock.assert_called_once_with('file')
link_mock.assert_called_once_with(self.href_path, 'file')
- @mock.patch.object(sendfile, 'sendfile')
- @mock.patch.object(os.path, 'getsize', return_value=42)
- @mock.patch.object(__builtin__, 'open')
- @mock.patch.object(os, 'access', return_value=False)
- @mock.patch.object(os, 'stat')
- @mock.patch.object(image_service.FileImageService, 'validate_href')
+ @mock.patch.object(sendfile, 'sendfile', autospec=True)
+ @mock.patch.object(os.path, 'getsize', return_value=42, autospec=True)
+ @mock.patch.object(__builtin__, 'open', autospec=True)
+ @mock.patch.object(os, 'access', return_value=False, autospec=True)
+ @mock.patch.object(os, 'stat', autospec=True)
+ @mock.patch.object(image_service.FileImageService, 'validate_href',
+ autospec=True)
def test_download_copy(self, _validate_mock, stat_mock, access_mock,
open_mock, size_mock, copy_mock):
_validate_mock.return_value = self.href_path
@@ -167,7 +170,7 @@ class FileImageServiceTestCase(base.TestCase):
input_mock = mock.MagicMock(spec=file)
open_mock.return_value = input_mock
self.service.download(self.href, file_mock)
- _validate_mock.assert_called_once_with(self.href)
+ _validate_mock.assert_called_once_with(mock.ANY, self.href)
self.assertEqual(2, stat_mock.call_count)
access_mock.assert_called_once_with(self.href_path, os.R_OK | os.W_OK)
copy_mock.assert_called_once_with(file_mock.fileno(),
@@ -175,10 +178,11 @@ class FileImageServiceTestCase(base.TestCase):
0, 42)
size_mock.assert_called_once_with(self.href_path)
- @mock.patch.object(os, 'remove', side_effect=OSError)
- @mock.patch.object(os, 'access', return_value=True)
- @mock.patch.object(os, 'stat')
- @mock.patch.object(image_service.FileImageService, 'validate_href')
+ @mock.patch.object(os, 'remove', side_effect=OSError, autospec=True)
+ @mock.patch.object(os, 'access', return_value=True, autospec=True)
+ @mock.patch.object(os, 'stat', autospec=True)
+ @mock.patch.object(image_service.FileImageService, 'validate_href',
+ autospec=True)
def test_download_hard_link_fail(self, _validate_mock, stat_mock,
access_mock, remove_mock):
_validate_mock.return_value = self.href_path
@@ -187,16 +191,18 @@ class FileImageServiceTestCase(base.TestCase):
file_mock.name = 'file'
self.assertRaises(exception.ImageDownloadFailed,
self.service.download, self.href, file_mock)
- _validate_mock.assert_called_once_with(self.href)
+ _validate_mock.assert_called_once_with(mock.ANY, self.href)
self.assertEqual(2, stat_mock.call_count)
access_mock.assert_called_once_with(self.href_path, os.R_OK | os.W_OK)
- @mock.patch.object(sendfile, 'sendfile', side_effect=OSError)
- @mock.patch.object(os.path, 'getsize', return_value=42)
- @mock.patch.object(__builtin__, 'open')
- @mock.patch.object(os, 'access', return_value=False)
- @mock.patch.object(os, 'stat')
- @mock.patch.object(image_service.FileImageService, 'validate_href')
+ @mock.patch.object(sendfile, 'sendfile', side_effect=OSError,
+ autospec=True)
+ @mock.patch.object(os.path, 'getsize', return_value=42, autospec=True)
+ @mock.patch.object(__builtin__, 'open', autospec=True)
+ @mock.patch.object(os, 'access', return_value=False, autospec=True)
+ @mock.patch.object(os, 'stat', autospec=True)
+ @mock.patch.object(image_service.FileImageService, 'validate_href',
+ autospec=True)
def test_download_copy_fail(self, _validate_mock, stat_mock, access_mock,
open_mock, size_mock, copy_mock):
_validate_mock.return_value = self.href_path
@@ -206,7 +212,7 @@ class FileImageServiceTestCase(base.TestCase):
open_mock.return_value = input_mock
self.assertRaises(exception.ImageDownloadFailed,
self.service.download, self.href, file_mock)
- _validate_mock.assert_called_once_with(self.href)
+ _validate_mock.assert_called_once_with(mock.ANY, self.href)
self.assertEqual(2, stat_mock.call_count)
access_mock.assert_called_once_with(self.href_path, os.R_OK | os.W_OK)
size_mock.assert_called_once_with(self.href_path)
@@ -215,35 +221,37 @@ class FileImageServiceTestCase(base.TestCase):
class ServiceGetterTestCase(base.TestCase):
@mock.patch.object(glance_v1_service.GlanceImageService, '__init__',
- return_value=None)
+ return_value=None, autospec=True)
def test_get_glance_image_service(self, glance_service_mock):
image_href = 'image-uuid'
image_service.get_image_service(image_href, context=self.context)
- glance_service_mock.assert_called_once_with(None, 1, self.context)
+ glance_service_mock.assert_called_once_with(mock.ANY, None, 1,
+ self.context)
@mock.patch.object(glance_v1_service.GlanceImageService, '__init__',
- return_value=None)
+ return_value=None, autospec=True)
def test_get_glance_image_service_url(self, glance_service_mock):
image_href = 'glance://image-uuid'
image_service.get_image_service(image_href, context=self.context)
- glance_service_mock.assert_called_once_with(None, 1, self.context)
+ glance_service_mock.assert_called_once_with(mock.ANY, None, 1,
+ self.context)
@mock.patch.object(image_service.HttpImageService, '__init__',
- return_value=None)
+ return_value=None, autospec=True)
def test_get_http_image_service(self, http_service_mock):
image_href = 'http://127.0.0.1/image.qcow2'
image_service.get_image_service(image_href)
http_service_mock.assert_called_once_with()
@mock.patch.object(image_service.HttpImageService, '__init__',
- return_value=None)
+ return_value=None, autospec=True)
def test_get_https_image_service(self, http_service_mock):
image_href = 'https://127.0.0.1/image.qcow2'
image_service.get_image_service(image_href)
http_service_mock.assert_called_once_with()
@mock.patch.object(image_service.FileImageService, '__init__',
- return_value=None)
+ return_value=None, autospec=True)
def test_get_file_image_service(self, local_service_mock):
image_href = 'file:///home/user/image.qcow2'
image_service.get_image_service(image_href)
diff --git a/ironic/tests/test_images.py b/ironic/tests/test_images.py
index 9ebd2d4b8..b610d4b0a 100644
--- a/ironic/tests/test_images.py
+++ b/ironic/tests/test_images.py
@@ -40,17 +40,18 @@ class IronicImagesTestCase(base.TestCase):
class FakeImgInfo(object):
pass
- @mock.patch.object(imageutils, 'QemuImgInfo')
- @mock.patch.object(os.path, 'exists', return_value=False)
+ @mock.patch.object(imageutils, 'QemuImgInfo', autospec=True)
+ @mock.patch.object(os.path, 'exists', return_value=False, autospec=True)
def test_qemu_img_info_path_doesnt_exist(self, path_exists_mock,
qemu_img_info_mock):
images.qemu_img_info('noimg')
path_exists_mock.assert_called_once_with('noimg')
qemu_img_info_mock.assert_called_once_with()
- @mock.patch.object(utils, 'execute', return_value=('out', 'err'))
- @mock.patch.object(imageutils, 'QemuImgInfo')
- @mock.patch.object(os.path, 'exists', return_value=True)
+ @mock.patch.object(utils, 'execute', return_value=('out', 'err'),
+ autospec=True)
+ @mock.patch.object(imageutils, 'QemuImgInfo', autospec=True)
+ @mock.patch.object(os.path, 'exists', return_value=True, autospec=True)
def test_qemu_img_info_path_exists(self, path_exists_mock,
qemu_img_info_mock, execute_mock):
images.qemu_img_info('img')
@@ -59,15 +60,15 @@ class IronicImagesTestCase(base.TestCase):
'qemu-img', 'info', 'img')
qemu_img_info_mock.assert_called_once_with('out')
- @mock.patch.object(utils, 'execute')
+ @mock.patch.object(utils, 'execute', autospec=True)
def test_convert_image(self, execute_mock):
images.convert_image('source', 'dest', 'out_format')
execute_mock.assert_called_once_with('qemu-img', 'convert', '-O',
'out_format', 'source', 'dest',
run_as_root=False)
- @mock.patch.object(image_service, 'get_image_service')
- @mock.patch.object(__builtin__, 'open')
+ @mock.patch.object(image_service, 'get_image_service', autospec=True)
+ @mock.patch.object(__builtin__, 'open', autospec=True)
def test_fetch_no_image_service(self, open_mock, image_service_mock):
mock_file_handle = mock.MagicMock(spec=file)
mock_file_handle.__enter__.return_value = 'file'
@@ -81,7 +82,7 @@ class IronicImagesTestCase(base.TestCase):
image_service_mock.return_value.download.assert_called_once_with(
'image_href', 'file')
- @mock.patch.object(__builtin__, 'open')
+ @mock.patch.object(__builtin__, 'open', autospec=True)
def test_fetch_image_service(self, open_mock):
mock_file_handle = mock.MagicMock(spec=file)
mock_file_handle.__enter__.return_value = 'file'
@@ -94,8 +95,8 @@ class IronicImagesTestCase(base.TestCase):
image_service_mock.download.assert_called_once_with(
'image_href', 'file')
- @mock.patch.object(images, 'image_to_raw')
- @mock.patch.object(__builtin__, 'open')
+ @mock.patch.object(images, 'image_to_raw', autospec=True)
+ @mock.patch.object(__builtin__, 'open', autospec=True)
def test_fetch_image_service_force_raw(self, open_mock, image_to_raw_mock):
mock_file_handle = mock.MagicMock(spec=file)
mock_file_handle.__enter__.return_value = 'file'
@@ -111,7 +112,7 @@ class IronicImagesTestCase(base.TestCase):
image_to_raw_mock.assert_called_once_with(
'image_href', 'path', 'path.part')
- @mock.patch.object(images, 'qemu_img_info')
+ @mock.patch.object(images, 'qemu_img_info', autospec=True)
def test_image_to_raw_no_file_format(self, qemu_img_info_mock):
info = self.FakeImgInfo()
info.file_format = None
@@ -122,7 +123,7 @@ class IronicImagesTestCase(base.TestCase):
qemu_img_info_mock.assert_called_once_with('path_tmp')
self.assertIn("'qemu-img info' parsing failed.", str(e))
- @mock.patch.object(images, 'qemu_img_info')
+ @mock.patch.object(images, 'qemu_img_info', autospec=True)
def test_image_to_raw_backing_file_present(self, qemu_img_info_mock):
info = self.FakeImgInfo()
info.file_format = 'raw'
@@ -134,10 +135,10 @@ class IronicImagesTestCase(base.TestCase):
qemu_img_info_mock.assert_called_once_with('path_tmp')
self.assertIn("fmt=raw backed by: backing_file", str(e))
- @mock.patch.object(os, 'rename')
- @mock.patch.object(os, 'unlink')
- @mock.patch.object(images, 'convert_image')
- @mock.patch.object(images, 'qemu_img_info')
+ @mock.patch.object(os, 'rename', autospec=True)
+ @mock.patch.object(os, 'unlink', autospec=True)
+ @mock.patch.object(images, 'convert_image', autospec=True)
+ @mock.patch.object(images, 'qemu_img_info', autospec=True)
def test_image_to_raw(self, qemu_img_info_mock, convert_image_mock,
unlink_mock, rename_mock):
CONF.set_override('force_raw_images', True)
@@ -159,9 +160,9 @@ class IronicImagesTestCase(base.TestCase):
unlink_mock.assert_called_once_with('path_tmp')
rename_mock.assert_called_once_with('path.converted', 'path')
- @mock.patch.object(os, 'unlink')
- @mock.patch.object(images, 'convert_image')
- @mock.patch.object(images, 'qemu_img_info')
+ @mock.patch.object(os, 'unlink', autospec=True)
+ @mock.patch.object(images, 'convert_image', autospec=True)
+ @mock.patch.object(images, 'qemu_img_info', autospec=True)
def test_image_to_raw_not_raw_after_conversion(self, qemu_img_info_mock,
convert_image_mock,
unlink_mock):
@@ -179,8 +180,8 @@ class IronicImagesTestCase(base.TestCase):
'path.converted', 'raw')
unlink_mock.assert_called_once_with('path_tmp')
- @mock.patch.object(os, 'rename')
- @mock.patch.object(images, 'qemu_img_info')
+ @mock.patch.object(os, 'rename', autospec=True)
+ @mock.patch.object(images, 'qemu_img_info', autospec=True)
def test_image_to_raw_already_raw_format(self, qemu_img_info_mock,
rename_mock):
info = self.FakeImgInfo()
@@ -193,7 +194,7 @@ class IronicImagesTestCase(base.TestCase):
qemu_img_info_mock.assert_called_once_with('path_tmp')
rename_mock.assert_called_once_with('path_tmp', 'path')
- @mock.patch.object(image_service, 'get_image_service')
+ @mock.patch.object(image_service, 'get_image_service', autospec=True)
def test_download_size_no_image_service(self, image_service_mock):
images.download_size('context', 'image_href')
image_service_mock.assert_called_once_with('image_href',
@@ -206,7 +207,7 @@ class IronicImagesTestCase(base.TestCase):
images.download_size('context', 'image_href', image_service_mock)
image_service_mock.show.assert_called_once_with('image_href')
- @mock.patch.object(images, 'qemu_img_info')
+ @mock.patch.object(images, 'qemu_img_info', autospec=True)
def test_converted_size(self, qemu_img_info_mock):
info = self.FakeImgInfo()
info.virtual_size = 1
@@ -215,8 +216,8 @@ class IronicImagesTestCase(base.TestCase):
qemu_img_info_mock.assert_called_once_with('path')
self.assertEqual(1, size)
- @mock.patch.object(images, 'get_image_properties')
- @mock.patch.object(glance_utils, 'is_glance_image')
+ @mock.patch.object(images, 'get_image_properties', autospec=True)
+ @mock.patch.object(glance_utils, 'is_glance_image', autospec=True)
def test_is_whole_disk_image_no_img_src(self, mock_igi, mock_gip):
instance_info = {'image_source': ''}
iwdi = images.is_whole_disk_image('context', instance_info)
@@ -224,8 +225,8 @@ class IronicImagesTestCase(base.TestCase):
self.assertFalse(mock_igi.called)
self.assertFalse(mock_gip.called)
- @mock.patch.object(images, 'get_image_properties')
- @mock.patch.object(glance_utils, 'is_glance_image')
+ @mock.patch.object(images, 'get_image_properties', autospec=True)
+ @mock.patch.object(glance_utils, 'is_glance_image', autospec=True)
def test_is_whole_disk_image_partition_image(self, mock_igi, mock_gip):
mock_igi.return_value = True
mock_gip.return_value = {'kernel_id': 'kernel',
@@ -238,8 +239,8 @@ class IronicImagesTestCase(base.TestCase):
mock_igi.assert_called_once_with(image_source)
mock_gip.assert_called_once_with('context', image_source)
- @mock.patch.object(images, 'get_image_properties')
- @mock.patch.object(glance_utils, 'is_glance_image')
+ @mock.patch.object(images, 'get_image_properties', autospec=True)
+ @mock.patch.object(glance_utils, 'is_glance_image', autospec=True)
def test_is_whole_disk_image_whole_disk_image(self, mock_igi, mock_gip):
mock_igi.return_value = True
mock_gip.return_value = {}
@@ -251,8 +252,8 @@ class IronicImagesTestCase(base.TestCase):
mock_igi.assert_called_once_with(image_source)
mock_gip.assert_called_once_with('context', image_source)
- @mock.patch.object(images, 'get_image_properties')
- @mock.patch.object(glance_utils, 'is_glance_image')
+ @mock.patch.object(images, 'get_image_properties', autospec=True)
+ @mock.patch.object(glance_utils, 'is_glance_image', autospec=True)
def test_is_whole_disk_image_partition_non_glance(self, mock_igi,
mock_gip):
mock_igi.return_value = False
@@ -265,8 +266,8 @@ class IronicImagesTestCase(base.TestCase):
self.assertFalse(mock_gip.called)
mock_igi.assert_called_once_with(instance_info['image_source'])
- @mock.patch.object(images, 'get_image_properties')
- @mock.patch.object(glance_utils, 'is_glance_image')
+ @mock.patch.object(images, 'get_image_properties', autospec=True)
+ @mock.patch.object(glance_utils, 'is_glance_image', autospec=True)
def test_is_whole_disk_image_whole_disk_non_glance(self, mock_igi,
mock_gip):
mock_igi.return_value = False
@@ -280,10 +281,10 @@ class IronicImagesTestCase(base.TestCase):
class FsImageTestCase(base.TestCase):
- @mock.patch.object(shutil, 'copyfile')
- @mock.patch.object(os, 'makedirs')
- @mock.patch.object(os.path, 'dirname')
- @mock.patch.object(os.path, 'exists')
+ @mock.patch.object(shutil, 'copyfile', autospec=True)
+ @mock.patch.object(os, 'makedirs', autospec=True)
+ @mock.patch.object(os.path, 'dirname', autospec=True)
+ @mock.patch.object(os.path, 'exists', autospec=True)
def test__create_root_fs(self, path_exists_mock,
dirname_mock, mkdir_mock, cp_mock):
@@ -295,8 +296,8 @@ class FsImageTestCase(base.TestCase):
'a3': 'sub_dir/b3'}
path_exists_mock.side_effect = path_exists_mock_func
- dirname_mock.side_effect = ['root_dir', 'root_dir',
- 'root_dir/sub_dir', 'root_dir/sub_dir']
+ dirname_mock.side_effect = iter(
+ ['root_dir', 'root_dir', 'root_dir/sub_dir', 'root_dir/sub_dir'])
images._create_root_fs('root_dir', files_info)
cp_mock.assert_any_call('a1', 'root_dir/b1')
cp_mock.assert_any_call('a2', 'root_dir/b2')
@@ -308,13 +309,13 @@ class FsImageTestCase(base.TestCase):
dirname_mock.assert_any_call('root_dir/sub_dir/b3')
mkdir_mock.assert_called_once_with('root_dir/sub_dir')
- @mock.patch.object(images, '_create_root_fs')
- @mock.patch.object(utils, 'tempdir')
- @mock.patch.object(utils, 'write_to_file')
- @mock.patch.object(utils, 'dd')
- @mock.patch.object(utils, 'umount')
- @mock.patch.object(utils, 'mount')
- @mock.patch.object(utils, 'mkfs')
+ @mock.patch.object(images, '_create_root_fs', autospec=True)
+ @mock.patch.object(utils, 'tempdir', autospec=True)
+ @mock.patch.object(utils, 'write_to_file', autospec=True)
+ @mock.patch.object(utils, 'dd', autospec=True)
+ @mock.patch.object(utils, 'umount', autospec=True)
+ @mock.patch.object(utils, 'mount', autospec=True)
+ @mock.patch.object(utils, 'mkfs', autospec=True)
def test_create_vfat_image(self, mkfs_mock, mount_mock, umount_mock,
dd_mock, write_mock, tempdir_mock, create_root_fs_mock):
@@ -343,12 +344,12 @@ class FsImageTestCase(base.TestCase):
create_root_fs_mock.assert_called_once_with('tempdir', files_info)
umount_mock.assert_called_once_with('tempdir')
- @mock.patch.object(images, '_create_root_fs')
- @mock.patch.object(utils, 'tempdir')
- @mock.patch.object(utils, 'dd')
- @mock.patch.object(utils, 'umount')
- @mock.patch.object(utils, 'mount')
- @mock.patch.object(utils, 'mkfs')
+ @mock.patch.object(images, '_create_root_fs', autospec=True)
+ @mock.patch.object(utils, 'tempdir', autospec=True)
+ @mock.patch.object(utils, 'dd', autospec=True)
+ @mock.patch.object(utils, 'umount', autospec=True)
+ @mock.patch.object(utils, 'mount', autospec=True)
+ @mock.patch.object(utils, 'mkfs', autospec=True)
def test_create_vfat_image_always_umount(self, mkfs_mock, mount_mock,
umount_mock, dd_mock, tempdir_mock, create_root_fs_mock):
@@ -363,16 +364,16 @@ class FsImageTestCase(base.TestCase):
umount_mock.assert_called_once_with('tempdir')
- @mock.patch.object(utils, 'dd')
+ @mock.patch.object(utils, 'dd', autospec=True)
def test_create_vfat_image_dd_fails(self, dd_mock):
dd_mock.side_effect = processutils.ProcessExecutionError
self.assertRaises(exception.ImageCreationFailed,
images.create_vfat_image, 'tgt_file')
- @mock.patch.object(utils, 'tempdir')
- @mock.patch.object(utils, 'dd')
- @mock.patch.object(utils, 'mkfs')
+ @mock.patch.object(utils, 'tempdir', autospec=True)
+ @mock.patch.object(utils, 'dd', autospec=True)
+ @mock.patch.object(utils, 'mkfs', autospec=True)
def test_create_vfat_image_mkfs_fails(self, mkfs_mock, dd_mock,
tempdir_mock):
@@ -384,12 +385,12 @@ class FsImageTestCase(base.TestCase):
self.assertRaises(exception.ImageCreationFailed,
images.create_vfat_image, 'tgt_file')
- @mock.patch.object(images, '_create_root_fs')
- @mock.patch.object(utils, 'tempdir')
- @mock.patch.object(utils, 'dd')
- @mock.patch.object(utils, 'umount')
- @mock.patch.object(utils, 'mount')
- @mock.patch.object(utils, 'mkfs')
+ @mock.patch.object(images, '_create_root_fs', autospec=True)
+ @mock.patch.object(utils, 'tempdir', autospec=True)
+ @mock.patch.object(utils, 'dd', autospec=True)
+ @mock.patch.object(utils, 'umount', autospec=True)
+ @mock.patch.object(utils, 'mount', autospec=True)
+ @mock.patch.object(utils, 'mkfs', autospec=True)
def test_create_vfat_image_umount_fails(self, mkfs_mock, mount_mock,
umount_mock, dd_mock, tempdir_mock, create_root_fs_mock):
@@ -401,7 +402,7 @@ class FsImageTestCase(base.TestCase):
self.assertRaises(exception.ImageCreationFailed,
images.create_vfat_image, 'tgt_file')
- @mock.patch.object(utils, 'umount')
+ @mock.patch.object(utils, 'umount', autospec=True)
def test__umount_without_raise(self, umount_mock):
umount_mock.side_effect = processutils.ProcessExecutionError
@@ -423,12 +424,15 @@ class FsImageTestCase(base.TestCase):
self.assertEqual(expected_cfg, cfg)
def test__generate_grub_cfg(self):
-
kernel_params = ['key1=value1', 'key2']
options = {'linux': '/vmlinuz', 'initrd': '/initrd'}
- expected_cfg = ("menuentry \"install\" {\n"
- "linux /vmlinuz key1=value1 key2 --\n"
- "initrd /initrd\n"
+ expected_cfg = ("set default=0\n"
+ "set timeout=5\n"
+ "set hidden_timeout_quiet=false\n"
+ "\n"
+ "menuentry \"boot_partition\" {\n"
+ "linuxefi /vmlinuz key1=value1 key2 --\n"
+ "initrdefi /initrd\n"
"}")
cfg = images._generate_cfg(kernel_params,
@@ -436,34 +440,34 @@ class FsImageTestCase(base.TestCase):
options)
self.assertEqual(expected_cfg, cfg)
- @mock.patch.object(os.path, 'relpath')
- @mock.patch.object(os, 'walk')
- @mock.patch.object(utils, 'mount')
+ @mock.patch.object(os.path, 'relpath', autospec=True)
+ @mock.patch.object(os, 'walk', autospec=True)
+ @mock.patch.object(utils, 'mount', autospec=True)
def test__mount_deploy_iso(self, mount_mock,
walk_mock, relpath_mock):
walk_mock.return_value = [('/tmpdir1/EFI/ubuntu', [], ['grub.cfg']),
('/tmpdir1/isolinux', [],
['efiboot.img', 'isolinux.bin',
'isolinux.cfg'])]
- relpath_mock.side_effect = ['EFI/ubuntu/grub.cfg',
- 'isolinux/efiboot.img']
+ relpath_mock.side_effect = iter(
+ ['EFI/ubuntu/grub.cfg', 'isolinux/efiboot.img'])
images._mount_deploy_iso('path/to/deployiso', 'tmpdir1')
mount_mock.assert_called_once_with('path/to/deployiso',
'tmpdir1', '-o', 'loop')
walk_mock.assert_called_once_with('tmpdir1')
- @mock.patch.object(images, '_umount_without_raise')
- @mock.patch.object(os.path, 'relpath')
- @mock.patch.object(os, 'walk')
- @mock.patch.object(utils, 'mount')
+ @mock.patch.object(images, '_umount_without_raise', autospec=True)
+ @mock.patch.object(os.path, 'relpath', autospec=True)
+ @mock.patch.object(os, 'walk', autospec=True)
+ @mock.patch.object(utils, 'mount', autospec=True)
def test__mount_deploy_iso_fail_no_efibootimg(self, mount_mock,
walk_mock, relpath_mock,
umount_mock):
walk_mock.return_value = [('/tmpdir1/EFI/ubuntu', [], ['grub.cfg']),
('/tmpdir1/isolinux', [],
['isolinux.bin', 'isolinux.cfg'])]
- relpath_mock.side_effect = ['EFI/ubuntu/grub.cfg']
+ relpath_mock.side_effect = iter(['EFI/ubuntu/grub.cfg'])
self.assertRaises(exception.ImageCreationFailed,
images._mount_deploy_iso,
@@ -473,10 +477,10 @@ class FsImageTestCase(base.TestCase):
walk_mock.assert_called_once_with('tmpdir1')
umount_mock.assert_called_once_with('tmpdir1')
- @mock.patch.object(images, '_umount_without_raise')
- @mock.patch.object(os.path, 'relpath')
- @mock.patch.object(os, 'walk')
- @mock.patch.object(utils, 'mount')
+ @mock.patch.object(images, '_umount_without_raise', autospec=True)
+ @mock.patch.object(os.path, 'relpath', autospec=True)
+ @mock.patch.object(os, 'walk', autospec=True)
+ @mock.patch.object(utils, 'mount', autospec=True)
def test__mount_deploy_iso_fails_no_grub_cfg(self, mount_mock,
walk_mock, relpath_mock,
umount_mock):
@@ -484,7 +488,7 @@ class FsImageTestCase(base.TestCase):
('/tmpdir1/isolinux', '',
['efiboot.img', 'isolinux.bin',
'isolinux.cfg'])]
- relpath_mock.side_effect = ['isolinux/efiboot.img']
+ relpath_mock.side_effect = iter(['isolinux/efiboot.img'])
self.assertRaises(exception.ImageCreationFailed,
images._mount_deploy_iso,
@@ -494,20 +498,20 @@ class FsImageTestCase(base.TestCase):
walk_mock.assert_called_once_with('tmpdir1')
umount_mock.assert_called_once_with('tmpdir1')
- @mock.patch.object(utils, 'mount')
+ @mock.patch.object(utils, 'mount', autospec=True)
def test__mount_deploy_iso_fail_with_ExecutionError(self, mount_mock):
mount_mock.side_effect = processutils.ProcessExecutionError
self.assertRaises(exception.ImageCreationFailed,
images._mount_deploy_iso,
'path/to/deployiso', 'tmpdir1')
- @mock.patch.object(images, '_umount_without_raise')
- @mock.patch.object(images, '_create_root_fs')
- @mock.patch.object(utils, 'write_to_file')
- @mock.patch.object(utils, 'execute')
- @mock.patch.object(images, '_mount_deploy_iso')
- @mock.patch.object(utils, 'tempdir')
- @mock.patch.object(images, '_generate_cfg')
+ @mock.patch.object(images, '_umount_without_raise', autospec=True)
+ @mock.patch.object(images, '_create_root_fs', autospec=True)
+ @mock.patch.object(utils, 'write_to_file', autospec=True)
+ @mock.patch.object(utils, 'execute', autospec=True)
+ @mock.patch.object(images, '_mount_deploy_iso', autospec=True)
+ @mock.patch.object(utils, 'tempdir', autospec=True)
+ @mock.patch.object(images, '_generate_cfg', autospec=True)
def test_create_isolinux_image_for_uefi(self, gen_cfg_mock,
tempdir_mock, mount_mock, execute_mock,
write_to_file_mock,
@@ -524,7 +528,7 @@ class FsImageTestCase(base.TestCase):
cfg_file = 'tmpdir/isolinux/isolinux.cfg'
grubcfg = "grubcfg"
grub_file = 'tmpdir/relpath/to/grub.cfg'
- gen_cfg_mock.side_effect = [cfg, grubcfg]
+ gen_cfg_mock.side_effect = iter([cfg, grubcfg])
params = ['a=b', 'c']
isolinux_options = {'kernel': '/vmlinuz',
@@ -541,8 +545,8 @@ class FsImageTestCase(base.TestCase):
mock_file_handle.__enter__.return_value = 'tmpdir'
mock_file_handle1 = mock.MagicMock(spec=file)
mock_file_handle1.__enter__.return_value = 'mountdir'
- tempdir_mock.side_effect = [mock_file_handle,
- mock_file_handle1]
+ tempdir_mock.side_effect = iter(
+ [mock_file_handle, mock_file_handle1])
mount_mock.return_value = (uefi_path_info,
e_img_rel_path, grub_rel_path)
@@ -566,11 +570,11 @@ class FsImageTestCase(base.TestCase):
'-no-emul-boot', '-o', 'tgt_file', 'tmpdir')
umount_mock.assert_called_once_with('mountdir')
- @mock.patch.object(images, '_create_root_fs')
- @mock.patch.object(utils, 'write_to_file')
- @mock.patch.object(utils, 'tempdir')
- @mock.patch.object(utils, 'execute')
- @mock.patch.object(images, '_generate_cfg')
+ @mock.patch.object(images, '_create_root_fs', autospec=True)
+ @mock.patch.object(utils, 'write_to_file', autospec=True)
+ @mock.patch.object(utils, 'tempdir', autospec=True)
+ @mock.patch.object(utils, 'execute', autospec=True)
+ @mock.patch.object(images, '_generate_cfg', autospec=True)
def test_create_isolinux_image_for_bios(self, gen_cfg_mock,
execute_mock,
tempdir_mock, write_to_file_mock,
@@ -609,11 +613,11 @@ class FsImageTestCase(base.TestCase):
'4', '-boot-info-table', '-b', 'isolinux/isolinux.bin',
'-o', 'tgt_file', 'tmpdir')
- @mock.patch.object(images, '_umount_without_raise')
- @mock.patch.object(images, '_create_root_fs')
- @mock.patch.object(utils, 'tempdir')
- @mock.patch.object(utils, 'execute')
- @mock.patch.object(os, 'walk')
+ @mock.patch.object(images, '_umount_without_raise', autospec=True)
+ @mock.patch.object(images, '_create_root_fs', autospec=True)
+ @mock.patch.object(utils, 'tempdir', autospec=True)
+ @mock.patch.object(utils, 'execute', autospec=True)
+ @mock.patch.object(os, 'walk', autospec=True)
def test_create_isolinux_image_uefi_rootfs_fails(self, walk_mock,
utils_mock,
tempdir_mock,
@@ -624,8 +628,8 @@ class FsImageTestCase(base.TestCase):
mock_file_handle.__enter__.return_value = 'tmpdir'
mock_file_handle1 = mock.MagicMock(spec=file)
mock_file_handle1.__enter__.return_value = 'mountdir'
- tempdir_mock.side_effect = [mock_file_handle,
- mock_file_handle1]
+ tempdir_mock.side_effect = iter(
+ [mock_file_handle, mock_file_handle1])
create_root_fs_mock.side_effect = IOError
self.assertRaises(exception.ImageCreationFailed,
@@ -635,10 +639,10 @@ class FsImageTestCase(base.TestCase):
'path/to/ramdisk')
umount_mock.assert_called_once_with('mountdir')
- @mock.patch.object(images, '_create_root_fs')
- @mock.patch.object(utils, 'tempdir')
- @mock.patch.object(utils, 'execute')
- @mock.patch.object(os, 'walk')
+ @mock.patch.object(images, '_create_root_fs', autospec=True)
+ @mock.patch.object(utils, 'tempdir', autospec=True)
+ @mock.patch.object(utils, 'execute', autospec=True)
+ @mock.patch.object(os, 'walk', autospec=True)
def test_create_isolinux_image_bios_rootfs_fails(self, walk_mock,
utils_mock,
tempdir_mock,
@@ -650,13 +654,13 @@ class FsImageTestCase(base.TestCase):
'tgt_file', 'path/to/kernel',
'path/to/ramdisk')
- @mock.patch.object(images, '_umount_without_raise')
- @mock.patch.object(images, '_create_root_fs')
- @mock.patch.object(utils, 'write_to_file')
- @mock.patch.object(utils, 'tempdir')
- @mock.patch.object(utils, 'execute')
- @mock.patch.object(images, '_mount_deploy_iso')
- @mock.patch.object(images, '_generate_cfg')
+ @mock.patch.object(images, '_umount_without_raise', autospec=True)
+ @mock.patch.object(images, '_create_root_fs', autospec=True)
+ @mock.patch.object(utils, 'write_to_file', autospec=True)
+ @mock.patch.object(utils, 'tempdir', autospec=True)
+ @mock.patch.object(utils, 'execute', autospec=True)
+ @mock.patch.object(images, '_mount_deploy_iso', autospec=True)
+ @mock.patch.object(images, '_generate_cfg', autospec=True)
def test_create_isolinux_image_mkisofs_fails(self,
gen_cfg_mock,
mount_mock,
@@ -669,8 +673,8 @@ class FsImageTestCase(base.TestCase):
mock_file_handle.__enter__.return_value = 'tmpdir'
mock_file_handle1 = mock.MagicMock(spec=file)
mock_file_handle1.__enter__.return_value = 'mountdir'
- tempdir_mock.side_effect = [mock_file_handle,
- mock_file_handle1]
+ tempdir_mock.side_effect = iter(
+ [mock_file_handle, mock_file_handle1])
mount_mock.return_value = ({'a': 'a'}, 'b', 'c')
utils_mock.side_effect = processutils.ProcessExecutionError
@@ -679,13 +683,13 @@ class FsImageTestCase(base.TestCase):
'tgt_file', 'path/to/deployiso',
'path/to/kernel',
'path/to/ramdisk')
- umount_mock.assert_called_once_wth('mountdir')
+ umount_mock.assert_called_once_with('mountdir')
- @mock.patch.object(images, '_create_root_fs')
- @mock.patch.object(utils, 'write_to_file')
- @mock.patch.object(utils, 'tempdir')
- @mock.patch.object(utils, 'execute')
- @mock.patch.object(images, '_generate_cfg')
+ @mock.patch.object(images, '_create_root_fs', autospec=True)
+ @mock.patch.object(utils, 'write_to_file', autospec=True)
+ @mock.patch.object(utils, 'tempdir', autospec=True)
+ @mock.patch.object(utils, 'execute', autospec=True)
+ @mock.patch.object(images, '_generate_cfg', autospec=True)
def test_create_isolinux_image_bios_mkisofs_fails(self,
gen_cfg_mock,
utils_mock,
@@ -702,9 +706,9 @@ class FsImageTestCase(base.TestCase):
'tgt_file', 'path/to/kernel',
'path/to/ramdisk')
- @mock.patch.object(images, 'create_isolinux_image_for_uefi')
- @mock.patch.object(images, 'fetch')
- @mock.patch.object(utils, 'tempdir')
+ @mock.patch.object(images, 'create_isolinux_image_for_uefi', autospec=True)
+ @mock.patch.object(images, 'fetch', autospec=True)
+ @mock.patch.object(utils, 'tempdir', autospec=True)
def test_create_boot_iso_for_uefi(self, tempdir_mock, fetch_images_mock,
create_isolinux_mock):
mock_file_handle = mock.MagicMock(spec=file)
@@ -727,9 +731,9 @@ class FsImageTestCase(base.TestCase):
'tmpdir/deploy_iso-uuid', 'tmpdir/kernel-uuid',
'tmpdir/ramdisk-uuid', params)
- @mock.patch.object(images, 'create_isolinux_image_for_bios')
- @mock.patch.object(images, 'fetch')
- @mock.patch.object(utils, 'tempdir')
+ @mock.patch.object(images, 'create_isolinux_image_for_bios', autospec=True)
+ @mock.patch.object(images, 'fetch', autospec=True)
+ @mock.patch.object(utils, 'tempdir', autospec=True)
def test_create_boot_iso_for_bios(self, tempdir_mock, fetch_images_mock,
create_isolinux_mock):
mock_file_handle = mock.MagicMock(spec=file)
@@ -744,8 +748,12 @@ class FsImageTestCase(base.TestCase):
'tmpdir/kernel-uuid')
fetch_images_mock.assert_any_call('ctx', 'ramdisk-uuid',
'tmpdir/ramdisk-uuid')
- fetch_images_mock.assert_not_called_with('ctx', 'deploy_iso-uuid',
- 'tmpdir/deploy_iso-uuid')
+ # Note (NobodyCam): the orginal assert asserted that fetch_images
+ # was not called with parameters, this did not
+ # work, So I instead assert that there were only
+ # Two calls to the mock validating the above
+ # asserts.
+ self.assertEqual(2, fetch_images_mock.call_count)
params = ['root=UUID=root-uuid', 'kernel-params']
create_isolinux_mock.assert_called_once_with('output_file',
@@ -753,9 +761,9 @@ class FsImageTestCase(base.TestCase):
'tmpdir/ramdisk-uuid',
params)
- @mock.patch.object(images, 'create_isolinux_image_for_bios')
- @mock.patch.object(images, 'fetch')
- @mock.patch.object(utils, 'tempdir')
+ @mock.patch.object(images, 'create_isolinux_image_for_bios', autospec=True)
+ @mock.patch.object(images, 'fetch', autospec=True)
+ @mock.patch.object(utils, 'tempdir', autospec=True)
def test_create_boot_iso_for_bios_with_no_boot_mode(self, tempdir_mock,
fetch_images_mock,
create_isolinux_mock):
@@ -778,7 +786,7 @@ class FsImageTestCase(base.TestCase):
'tmpdir/ramdisk-uuid',
params)
- @mock.patch.object(image_service, 'get_image_service')
+ @mock.patch.object(image_service, 'get_image_service', autospec=True)
def test_get_glance_image_properties_no_such_prop(self,
image_service_mock):
@@ -796,7 +804,7 @@ class FsImageTestCase(base.TestCase):
'p2': 'v2',
'p3': None}, ret_val)
- @mock.patch.object(image_service, 'get_image_service')
+ @mock.patch.object(image_service, 'get_image_service', autospec=True)
def test_get_glance_image_properties_default_all(
self, image_service_mock):
@@ -812,7 +820,7 @@ class FsImageTestCase(base.TestCase):
self.assertEqual({'p1': 'v1',
'p2': 'v2'}, ret_val)
- @mock.patch.object(image_service, 'get_image_service')
+ @mock.patch.object(image_service, 'get_image_service', autospec=True)
def test_get_glance_image_properties_with_prop_subset(
self, image_service_mock):
@@ -830,7 +838,7 @@ class FsImageTestCase(base.TestCase):
self.assertEqual({'p1': 'v1',
'p3': 'v3'}, ret_val)
- @mock.patch.object(image_service, 'GlanceImageService')
+ @mock.patch.object(image_service, 'GlanceImageService', autospec=True)
def test_get_temp_url_for_glance_image(self, image_service_mock):
direct_url = 'swift+http://host/v1/AUTH_xx/con/obj'
diff --git a/ironic/tests/test_keystone.py b/ironic/tests/test_keystone.py
index b41a52f1b..7933ffe7e 100644
--- a/ironic/tests/test_keystone.py
+++ b/ironic/tests/test_keystone.py
@@ -46,8 +46,8 @@ class KeystoneTestCase(base.TestCase):
def test_failure_authorization(self):
self.assertRaises(exception.KeystoneFailure, keystone.get_service_url)
- @mock.patch.object(FakeCatalog, 'url_for')
- @mock.patch('keystoneclient.v2_0.client.Client')
+ @mock.patch.object(FakeCatalog, 'url_for', autospec=True)
+ @mock.patch('keystoneclient.v2_0.client.Client', autospec=True)
def test_get_url(self, mock_ks, mock_uf):
fake_url = 'http://127.0.0.1:6385'
mock_uf.return_value = fake_url
@@ -55,21 +55,21 @@ class KeystoneTestCase(base.TestCase):
res = keystone.get_service_url()
self.assertEqual(fake_url, res)
- @mock.patch.object(FakeCatalog, 'url_for')
- @mock.patch('keystoneclient.v2_0.client.Client')
+ @mock.patch.object(FakeCatalog, 'url_for', autospec=True)
+ @mock.patch('keystoneclient.v2_0.client.Client', autospec=True)
def test_url_not_found(self, mock_ks, mock_uf):
mock_uf.side_effect = ksexception.EndpointNotFound
mock_ks.return_value = FakeClient()
self.assertRaises(exception.CatalogNotFound, keystone.get_service_url)
- @mock.patch.object(FakeClient, 'has_service_catalog')
- @mock.patch('keystoneclient.v2_0.client.Client')
+ @mock.patch.object(FakeClient, 'has_service_catalog', autospec=True)
+ @mock.patch('keystoneclient.v2_0.client.Client', autospec=True)
def test_no_catalog(self, mock_ks, mock_hsc):
mock_hsc.return_value = False
mock_ks.return_value = FakeClient()
self.assertRaises(exception.KeystoneFailure, keystone.get_service_url)
- @mock.patch('keystoneclient.v2_0.client.Client')
+ @mock.patch('keystoneclient.v2_0.client.Client', autospec=True)
def test_unauthorized(self, mock_ks):
mock_ks.side_effect = ksexception.Unauthorized
self.assertRaises(exception.KeystoneUnauthorized,
@@ -80,7 +80,7 @@ class KeystoneTestCase(base.TestCase):
self.assertRaises(exception.KeystoneFailure,
keystone.get_service_url)
- @mock.patch('keystoneclient.v2_0.client.Client')
+ @mock.patch('keystoneclient.v2_0.client.Client', autospec=True)
def test_get_service_url_versionless_v2(self, mock_ks):
mock_ks.return_value = FakeClient()
self.config(group='keystone_authtoken', auth_uri='http://127.0.0.1')
@@ -91,7 +91,7 @@ class KeystoneTestCase(base.TestCase):
region_name='fake',
auth_url=expected_url)
- @mock.patch('keystoneclient.v3.client.Client')
+ @mock.patch('keystoneclient.v3.client.Client', autospec=True)
def test_get_service_url_versionless_v3(self, mock_ks):
mock_ks.return_value = FakeClient()
self.config(group='keystone_authtoken', auth_version='v3.0',
@@ -103,7 +103,7 @@ class KeystoneTestCase(base.TestCase):
region_name='fake',
auth_url=expected_url)
- @mock.patch('keystoneclient.v2_0.client.Client')
+ @mock.patch('keystoneclient.v2_0.client.Client', autospec=True)
def test_get_service_url_version_override(self, mock_ks):
mock_ks.return_value = FakeClient()
self.config(group='keystone_authtoken',
@@ -115,14 +115,14 @@ class KeystoneTestCase(base.TestCase):
region_name='fake',
auth_url=expected_url)
- @mock.patch('keystoneclient.v2_0.client.Client')
+ @mock.patch('keystoneclient.v2_0.client.Client', autospec=True)
def test_get_admin_auth_token(self, mock_ks):
fake_client = FakeClient()
fake_client.auth_token = '123456'
mock_ks.return_value = fake_client
self.assertEqual('123456', keystone.get_admin_auth_token())
- @mock.patch('keystoneclient.v2_0.client.Client')
+ @mock.patch('keystoneclient.v2_0.client.Client', autospec=True)
def test_get_region_name_v2(self, mock_ks):
mock_ks.return_value = FakeClient()
self.config(group='keystone', region_name='fake_region')
@@ -134,7 +134,7 @@ class KeystoneTestCase(base.TestCase):
region_name=expected_region,
auth_url=expected_url)
- @mock.patch('keystoneclient.v3.client.Client')
+ @mock.patch('keystoneclient.v3.client.Client', autospec=True)
def test_get_region_name_v3(self, mock_ks):
mock_ks.return_value = FakeClient()
self.config(group='keystone', region_name='fake_region')
diff --git a/ironic/tests/test_pxe_utils.py b/ironic/tests/test_pxe_utils.py
index f00a26116..1792d840a 100644
--- a/ironic/tests/test_pxe_utils.py
+++ b/ironic/tests/test_pxe_utils.py
@@ -66,6 +66,14 @@ class TestPXEUtils(db_base.DbTestCase):
}
self.agent_pxe_options.update(common_pxe_options)
+ self.ipxe_options = self.pxe_options.copy()
+ self.ipxe_options.update({
+ 'deployment_aki_path': 'http://1.2.3.4:1234/deploy_kernel',
+ 'deployment_ari_path': 'http://1.2.3.4:1234/deploy_ramdisk',
+ 'aki_path': 'http://1.2.3.4:1234/kernel',
+ 'ari_path': 'http://1.2.3.4:1234/ramdisk',
+ })
+
self.node = object_utils.create_test_node(self.context)
def test__build_pxe_config(self):
@@ -88,9 +96,39 @@ class TestPXEUtils(db_base.DbTestCase):
self.assertEqual(unicode(expected_template), rendered_template)
- @mock.patch('ironic.common.utils.create_link_without_raise')
- @mock.patch('ironic.common.utils.unlink_without_raise')
- @mock.patch('ironic.drivers.utils.get_node_mac_addresses')
+ def test__build_ipxe_config(self):
+ # NOTE(lucasagomes): iPXE is just an extension of the PXE driver,
+ # it doesn't have it's own configuration option for template.
+ # More info:
+ # http://docs.openstack.org/developer/ironic/deploy/install-guide.html
+ self.config(
+ pxe_config_template='ironic/drivers/modules/ipxe_config.template',
+ group='pxe'
+ )
+ self.config(http_url='http://1.2.3.4:1234', group='pxe')
+ rendered_template = pxe_utils._build_pxe_config(
+ self.ipxe_options, CONF.pxe.pxe_config_template)
+
+ expected_template = open(
+ 'ironic/tests/drivers/ipxe_config.template').read().rstrip()
+
+ self.assertEqual(unicode(expected_template), rendered_template)
+
+ def test__build_elilo_config(self):
+ pxe_opts = self.pxe_options
+ pxe_opts['boot_mode'] = 'uefi'
+ rendered_template = pxe_utils._build_pxe_config(
+ pxe_opts, CONF.pxe.uefi_pxe_config_template)
+
+ expected_template = open(
+ 'ironic/tests/drivers/elilo_efi_pxe_config.template'
+ ).read().rstrip()
+
+ self.assertEqual(unicode(expected_template), rendered_template)
+
+ @mock.patch('ironic.common.utils.create_link_without_raise', autospec=True)
+ @mock.patch('ironic.common.utils.unlink_without_raise', autospec=True)
+ @mock.patch('ironic.drivers.utils.get_node_mac_addresses', autospec=True)
def test__write_mac_pxe_configs(self, get_macs_mock, unlink_mock,
create_link_mock):
macs = [
@@ -106,7 +144,7 @@ class TestPXEUtils(db_base.DbTestCase):
]
unlink_calls = [
mock.call('/tftpboot/pxelinux.cfg/01-00-11-22-33-44-55-66'),
- mock.call('/tftpboot/pxelinux.cfg/01-00-11-22-33-44-55-67')
+ mock.call('/tftpboot/pxelinux.cfg/01-00-11-22-33-44-55-67'),
]
with task_manager.acquire(self.context, self.node.uuid) as task:
pxe_utils._link_mac_pxe_configs(task)
@@ -114,9 +152,43 @@ class TestPXEUtils(db_base.DbTestCase):
unlink_mock.assert_has_calls(unlink_calls)
create_link_mock.assert_has_calls(create_link_calls)
- @mock.patch('ironic.common.utils.create_link_without_raise')
- @mock.patch('ironic.common.utils.unlink_without_raise')
- @mock.patch('ironic.common.dhcp_factory.DHCPFactory.provider')
+ @mock.patch('ironic.common.utils.create_link_without_raise', autospec=True)
+ @mock.patch('ironic.common.utils.unlink_without_raise', autospec=True)
+ @mock.patch('ironic.drivers.utils.get_node_mac_addresses', autospec=True)
+ def test__write_mac_ipxe_configs(self, get_macs_mock, unlink_mock,
+ create_link_mock):
+ self.config(ipxe_enabled=True, group='pxe')
+ macs = [
+ '00:11:22:33:44:55:66',
+ '00:11:22:33:44:55:67'
+ ]
+ get_macs_mock.return_value = macs
+ create_link_calls = [
+ mock.call(u'/httpboot/1be26c0b-03f2-4d2e-ae87-c02d7f33c123/config',
+ '/httpboot/pxelinux.cfg/00-11-22-33-44-55-66'),
+ mock.call(u'/httpboot/1be26c0b-03f2-4d2e-ae87-c02d7f33c123/config',
+ '/httpboot/pxelinux.cfg/00112233445566'),
+ mock.call(u'/httpboot/1be26c0b-03f2-4d2e-ae87-c02d7f33c123/config',
+ '/httpboot/pxelinux.cfg/00-11-22-33-44-55-67'),
+ mock.call(u'/httpboot/1be26c0b-03f2-4d2e-ae87-c02d7f33c123/config',
+ '/httpboot/pxelinux.cfg/00112233445567'),
+ ]
+ unlink_calls = [
+ mock.call('/httpboot/pxelinux.cfg/00-11-22-33-44-55-66'),
+ mock.call('/httpboot/pxelinux.cfg/00112233445566'),
+ mock.call('/httpboot/pxelinux.cfg/00-11-22-33-44-55-67'),
+ mock.call('/httpboot/pxelinux.cfg/00112233445567'),
+ ]
+ with task_manager.acquire(self.context, self.node.uuid) as task:
+ pxe_utils._link_mac_pxe_configs(task)
+
+ unlink_mock.assert_has_calls(unlink_calls)
+ create_link_mock.assert_has_calls(create_link_calls)
+
+ @mock.patch('ironic.common.utils.create_link_without_raise', autospec=True)
+ @mock.patch('ironic.common.utils.unlink_without_raise', autospec=True)
+ @mock.patch('ironic.common.dhcp_factory.DHCPFactory.provider',
+ autospec=True)
def test__link_ip_address_pxe_configs(self, provider_mock, unlink_mock,
create_link_mock):
ip_address = '10.10.0.1'
@@ -135,9 +207,9 @@ class TestPXEUtils(db_base.DbTestCase):
unlink_mock.assert_called_once_with('/tftpboot/0A0A0001.conf')
create_link_mock.assert_has_calls(create_link_calls)
- @mock.patch('ironic.common.utils.write_to_file')
- @mock.patch.object(pxe_utils, '_build_pxe_config')
- @mock.patch('ironic.openstack.common.fileutils.ensure_tree')
+ @mock.patch('ironic.common.utils.write_to_file', autospec=True)
+ @mock.patch.object(pxe_utils, '_build_pxe_config', autospec=True)
+ @mock.patch('ironic.openstack.common.fileutils.ensure_tree', autospec=True)
def test_create_pxe_config(self, ensure_tree_mock, build_mock,
write_mock):
build_mock.return_value = self.pxe_options
@@ -150,7 +222,7 @@ class TestPXEUtils(db_base.DbTestCase):
mock.call(os.path.join(CONF.pxe.tftp_root, self.node.uuid)),
mock.call(os.path.join(CONF.pxe.tftp_root, 'pxelinux.cfg'))
]
- ensure_tree_mock.has_calls(ensure_calls)
+ ensure_tree_mock.assert_has_calls(ensure_calls)
pxe_cfg_file_path = pxe_utils.get_pxe_config_file_path(self.node.uuid)
write_mock.assert_called_with(pxe_cfg_file_path, self.pxe_options)
@@ -179,7 +251,7 @@ class TestPXEUtils(db_base.DbTestCase):
self.config(ipxe_enabled=True, group='pxe')
self.config(http_root='/httpboot', group='pxe')
mac = '00:11:22:33:AA:BB:CC'
- self.assertEqual('/httpboot/pxelinux.cfg/00112233aabbcc',
+ self.assertEqual('/httpboot/pxelinux.cfg/00-11-22-33-aa-bb-cc',
pxe_utils._get_pxe_mac_path(mac))
def test__get_pxe_ip_address_path(self):
@@ -308,6 +380,27 @@ class TestPXEUtils(db_base.DbTestCase):
task.node.properties = properties
pxe_utils.clean_up_pxe_config(task)
- unlink_mock.assert_called_once_with('/tftpboot/0A0A0001.conf')
- rmtree_mock.assert_called_once_with(
+ unlink_mock.assert_called_once_with('/tftpboot/0A0A0001.conf')
+ rmtree_mock.assert_called_once_with(
+ os.path.join(CONF.pxe.tftp_root, self.node.uuid))
+
+ @mock.patch('ironic.common.utils.rmtree_without_raise')
+ @mock.patch('ironic.common.utils.unlink_without_raise')
+ @mock.patch('ironic.common.dhcp_factory.DHCPFactory.provider')
+ def test_clean_up_pxe_config_uefi_instance_info(self,
+ provider_mock, unlink_mock,
+ rmtree_mock):
+ ip_address = '10.10.0.1'
+ address = "aa:aa:aa:aa:aa:aa"
+ object_utils.create_test_port(self.context, node_id=self.node.id,
+ address=address)
+
+ provider_mock.get_ip_addresses.return_value = [ip_address]
+
+ with task_manager.acquire(self.context, self.node.uuid) as task:
+ task.node.instance_info['deploy_boot_mode'] = 'uefi'
+ pxe_utils.clean_up_pxe_config(task)
+
+ unlink_mock.assert_called_once_with('/tftpboot/0A0A0001.conf')
+ rmtree_mock.assert_called_once_with(
os.path.join(CONF.pxe.tftp_root, self.node.uuid))
diff --git a/ironic/tests/test_swift.py b/ironic/tests/test_swift.py
index 07af10656..9daa06ead 100644
--- a/ironic/tests/test_swift.py
+++ b/ironic/tests/test_swift.py
@@ -28,7 +28,7 @@ from ironic.tests import base
CONF = cfg.CONF
-@mock.patch.object(swift_client, 'Connection')
+@mock.patch.object(swift_client, 'Connection', autospec=True)
class SwiftTestCase(base.TestCase):
def setUp(self):
@@ -59,7 +59,7 @@ class SwiftTestCase(base.TestCase):
'auth_version': '2'}
connection_mock.assert_called_once_with(**params)
- @mock.patch.object(__builtin__, 'open')
+ @mock.patch.object(__builtin__, 'open', autospec=True)
def test_create_object(self, open_mock, connection_mock):
swiftapi = swift.SwiftAPI()
connection_obj_mock = connection_mock.return_value
@@ -77,7 +77,7 @@ class SwiftTestCase(base.TestCase):
'object', 'file-object', headers=None)
self.assertEqual('object-uuid', object_uuid)
- @mock.patch.object(__builtin__, 'open')
+ @mock.patch.object(__builtin__, 'open', autospec=True)
def test_create_object_create_container_fails(self, open_mock,
connection_mock):
swiftapi = swift.SwiftAPI()
@@ -89,7 +89,7 @@ class SwiftTestCase(base.TestCase):
connection_obj_mock.put_container.assert_called_once_with('container')
self.assertFalse(connection_obj_mock.put_object.called)
- @mock.patch.object(__builtin__, 'open')
+ @mock.patch.object(__builtin__, 'open', autospec=True)
def test_create_object_put_object_fails(self, open_mock, connection_mock):
swiftapi = swift.SwiftAPI()
mock_file_handle = mock.MagicMock(spec=file)
@@ -105,7 +105,7 @@ class SwiftTestCase(base.TestCase):
connection_obj_mock.put_object.assert_called_once_with('container',
'object', 'file-object', headers=None)
- @mock.patch.object(swift_utils, 'generate_temp_url')
+ @mock.patch.object(swift_utils, 'generate_temp_url', autospec=True)
def test_get_temp_url(self, gen_temp_url_mock, connection_mock):
swiftapi = swift.SwiftAPI()
connection_obj_mock = connection_mock.return_value
diff --git a/ironic/tests/test_utils.py b/ironic/tests/test_utils.py
index 044f32bee..4ea1cb2af 100644
--- a/ironic/tests/test_utils.py
+++ b/ironic/tests/test_utils.py
@@ -43,25 +43,25 @@ class BareMetalUtilsTestCase(base.TestCase):
self.assertEqual(100, len(s))
def test_unlink(self):
- with mock.patch.object(os, "unlink") as unlink_mock:
+ with mock.patch.object(os, "unlink", autospec=True) as unlink_mock:
unlink_mock.return_value = None
utils.unlink_without_raise("/fake/path")
unlink_mock.assert_called_once_with("/fake/path")
def test_unlink_ENOENT(self):
- with mock.patch.object(os, "unlink") as unlink_mock:
+ with mock.patch.object(os, "unlink", autospec=True) as unlink_mock:
unlink_mock.side_effect = OSError(errno.ENOENT)
utils.unlink_without_raise("/fake/path")
unlink_mock.assert_called_once_with("/fake/path")
def test_create_link(self):
- with mock.patch.object(os, "symlink") as symlink_mock:
+ with mock.patch.object(os, "symlink", autospec=True) as symlink_mock:
symlink_mock.return_value = None
utils.create_link_without_raise("/fake/source", "/fake/link")
symlink_mock.assert_called_once_with("/fake/source", "/fake/link")
def test_create_link_EEXIST(self):
- with mock.patch.object(os, "symlink") as symlink_mock:
+ with mock.patch.object(os, "symlink", autospec=True) as symlink_mock:
symlink_mock.side_effect = OSError(errno.EEXIST)
utils.create_link_without_raise("/fake/source", "/fake/link")
symlink_mock.assert_called_once_with("/fake/source", "/fake/link")
@@ -163,15 +163,15 @@ grep foo
os.unlink(tmpfilename)
os.unlink(tmpfilename2)
- @mock.patch.object(processutils, 'execute')
- @mock.patch.object(os.environ, 'copy', return_value={})
+ @mock.patch.object(processutils, 'execute', autospec=True)
+ @mock.patch.object(os.environ, 'copy', return_value={}, autospec=True)
def test_execute_use_standard_locale_no_env_variables(self, env_mock,
execute_mock):
utils.execute('foo', use_standard_locale=True)
execute_mock.assert_called_once_with('foo',
env_variables={'LC_ALL': 'C'})
- @mock.patch.object(processutils, 'execute')
+ @mock.patch.object(processutils, 'execute', autospec=True)
def test_execute_use_standard_locale_with_env_variables(self,
execute_mock):
utils.execute('foo', use_standard_locale=True,
@@ -180,7 +180,7 @@ grep foo
env_variables={'LC_ALL': 'C',
'foo': 'bar'})
- @mock.patch.object(processutils, 'execute')
+ @mock.patch.object(processutils, 'execute', autospec=True)
def test_execute_not_use_standard_locale(self, execute_mock):
utils.execute('foo', use_standard_locale=False,
env_variables={'foo': 'bar'})
@@ -188,14 +188,16 @@ grep foo
env_variables={'foo': 'bar'})
def test_execute_get_root_helper(self):
- with mock.patch.object(processutils, 'execute') as execute_mock:
+ with mock.patch.object(
+ processutils, 'execute', autospec=True) as execute_mock:
helper = utils._get_root_helper()
utils.execute('foo', run_as_root=True)
execute_mock.assert_called_once_with('foo', run_as_root=True,
root_helper=helper)
def test_execute_without_root_helper(self):
- with mock.patch.object(processutils, 'execute') as execute_mock:
+ with mock.patch.object(
+ processutils, 'execute', autospec=True) as execute_mock:
utils.execute('foo', run_as_root=False)
execute_mock.assert_called_once_with('foo', run_as_root=False)
@@ -226,7 +228,8 @@ class GenericUtilsTestCase(base.TestCase):
self.assertEqual("hello", utils.sanitize_hostname(hostname))
def test_read_cached_file(self):
- with mock.patch.object(os.path, "getmtime") as getmtime_mock:
+ with mock.patch.object(
+ os.path, "getmtime", autospec=True) as getmtime_mock:
getmtime_mock.return_value = 1
cache_data = {"data": 1123, "mtime": 1}
@@ -235,8 +238,10 @@ class GenericUtilsTestCase(base.TestCase):
getmtime_mock.assert_called_once_with(mock.ANY)
def test_read_modified_cached_file(self):
- with mock.patch.object(os.path, "getmtime") as getmtime_mock:
- with mock.patch.object(__builtin__, 'open') as open_mock:
+ with mock.patch.object(
+ os.path, "getmtime", autospec=True) as getmtime_mock:
+ with mock.patch.object(
+ __builtin__, 'open', autospec=True) as open_mock:
getmtime_mock.return_value = 2
fake_contents = "lorem ipsum"
fake_file = mock.Mock()
@@ -342,6 +347,7 @@ class GenericUtilsTestCase(base.TestCase):
self.assertFalse(utils.is_hostname_safe('-spam'))
self.assertFalse(utils.is_hostname_safe('spam-'))
self.assertTrue(utils.is_hostname_safe('spam-eggs'))
+ self.assertFalse(utils.is_hostname_safe('spam_eggs'))
self.assertFalse(utils.is_hostname_safe('spam eggs'))
self.assertTrue(utils.is_hostname_safe('spam.eggs'))
self.assertTrue(utils.is_hostname_safe('9spam'))
@@ -360,16 +366,28 @@ class GenericUtilsTestCase(base.TestCase):
# Need to ensure a binary response for success or fail
self.assertIsNotNone(utils.is_hostname_safe('spam'))
self.assertIsNotNone(utils.is_hostname_safe('-spam'))
+ self.assertTrue(utils.is_hostname_safe('www.rackspace.com'))
+ self.assertTrue(utils.is_hostname_safe('www.rackspace.com.'))
+ self.assertTrue(utils.is_hostname_safe('http._sctp.www.example.com'))
+ self.assertTrue(utils.is_hostname_safe('mail.pets_r_us.net'))
+ self.assertTrue(utils.is_hostname_safe('mail-server-15.my_host.org'))
+ self.assertFalse(utils.is_hostname_safe('www.nothere.com_'))
+ self.assertFalse(utils.is_hostname_safe('www.nothere_.com'))
+ self.assertFalse(utils.is_hostname_safe('www..nothere.com'))
+ long_str = 'a' * 63 + '.' + 'b' * 63 + '.' + 'c' * 63 + '.' + 'd' * 63
+ self.assertTrue(utils.is_hostname_safe(long_str))
+ self.assertFalse(utils.is_hostname_safe(long_str + '.'))
+ self.assertFalse(utils.is_hostname_safe('a' * 255))
def test_validate_and_normalize_mac(self):
mac = 'AA:BB:CC:DD:EE:FF'
- with mock.patch.object(utils, 'is_valid_mac') as m_mock:
+ with mock.patch.object(utils, 'is_valid_mac', autospec=True) as m_mock:
m_mock.return_value = True
self.assertEqual(mac.lower(),
utils.validate_and_normalize_mac(mac))
def test_validate_and_normalize_mac_invalid_format(self):
- with mock.patch.object(utils, 'is_valid_mac') as m_mock:
+ with mock.patch.object(utils, 'is_valid_mac', autospec=True) as m_mock:
m_mock.return_value = False
self.assertRaises(exception.InvalidMAC,
utils.validate_and_normalize_mac, 'invalid-mac')
@@ -394,7 +412,7 @@ class GenericUtilsTestCase(base.TestCase):
class MkfsTestCase(base.TestCase):
- @mock.patch.object(utils, 'execute')
+ @mock.patch.object(utils, 'execute', autospec=True)
def test_mkfs(self, execute_mock):
utils.mkfs('ext4', '/my/block/dev')
utils.mkfs('msdos', '/my/msdos/block/dev')
@@ -411,7 +429,7 @@ class MkfsTestCase(base.TestCase):
use_standard_locale=True)]
self.assertEqual(expected, execute_mock.call_args_list)
- @mock.patch.object(utils, 'execute')
+ @mock.patch.object(utils, 'execute', autospec=True)
def test_mkfs_with_label(self, execute_mock):
utils.mkfs('ext4', '/my/block/dev', 'ext4-vol')
utils.mkfs('msdos', '/my/msdos/block/dev', 'msdos-vol')
@@ -428,14 +446,14 @@ class MkfsTestCase(base.TestCase):
use_standard_locale=True)]
self.assertEqual(expected, execute_mock.call_args_list)
- @mock.patch.object(utils, 'execute',
+ @mock.patch.object(utils, 'execute', autospec=True,
side_effect=processutils.ProcessExecutionError(
stderr=os.strerror(errno.ENOENT)))
def test_mkfs_with_unsupported_fs(self, execute_mock):
self.assertRaises(exception.FileSystemNotSupported,
utils.mkfs, 'foo', '/my/block/dev')
- @mock.patch.object(utils, 'execute',
+ @mock.patch.object(utils, 'execute', autospec=True,
side_effect=processutils.ProcessExecutionError(
stderr='fake'))
def test_mkfs_with_unexpected_error(self, execute_mock):
@@ -453,13 +471,13 @@ class TempFilesTestCase(base.TestCase):
dirname = tempdir
self.assertFalse(os.path.exists(dirname))
- @mock.patch.object(shutil, 'rmtree')
- @mock.patch.object(tempfile, 'mkdtemp')
+ @mock.patch.object(shutil, 'rmtree', autospec=True)
+ @mock.patch.object(tempfile, 'mkdtemp', autospec=True)
def test_tempdir_mocked(self, mkdtemp_mock, rmtree_mock):
self.config(tempdir='abc')
mkdtemp_mock.return_value = 'temp-dir'
- kwargs = {'a': 'b'}
+ kwargs = {'dir': 'b'}
with utils.tempdir(**kwargs) as tempdir:
self.assertEqual('temp-dir', tempdir)
@@ -468,9 +486,9 @@ class TempFilesTestCase(base.TestCase):
mkdtemp_mock.assert_called_once_with(**kwargs)
rmtree_mock.assert_called_once_with(tempdir_created)
- @mock.patch.object(utils, 'LOG')
- @mock.patch.object(shutil, 'rmtree')
- @mock.patch.object(tempfile, 'mkdtemp')
+ @mock.patch.object(utils, 'LOG', autospec=True)
+ @mock.patch.object(shutil, 'rmtree', autospec=True)
+ @mock.patch.object(tempfile, 'mkdtemp', autospec=True)
def test_tempdir_mocked_error_on_rmtree(self, mkdtemp_mock, rmtree_mock,
log_mock):