Add option power_off_after_discovery
Option controls whether to shut down node after the discovery. Change-Id: I447a640a963eafac820c94db3dcd005268ae6bef Implements: blueprint returning-to-ramdisk
This commit is contained in:
parent
2f63aaba24
commit
9b1a164cfa
@ -189,6 +189,10 @@ HTTP API consist of 2 endpoints:
|
|||||||
* 403 - node is not on discovery
|
* 403 - node is not on discovery
|
||||||
* 404 - node cannot be found or multiple nodes found
|
* 404 - node cannot be found or multiple nodes found
|
||||||
|
|
||||||
|
Successful response body is a JSON dictionary with keys:
|
||||||
|
|
||||||
|
* ``node`` node as returned by Ironic
|
||||||
|
|
||||||
.. _bug #1391866: https://bugs.launchpad.net/ironic-discoverd/+bug/1391866
|
.. _bug #1391866: https://bugs.launchpad.net/ironic-discoverd/+bug/1391866
|
||||||
|
|
||||||
Change Log
|
Change Log
|
||||||
@ -198,6 +202,8 @@ v1.0.0
|
|||||||
~~~~~~
|
~~~~~~
|
||||||
|
|
||||||
* ``/v1/continue`` is now sync and errors are returned.
|
* ``/v1/continue`` is now sync and errors are returned.
|
||||||
|
* Option ``power_off_after_discovery`` controls whether to force power off
|
||||||
|
after the successful discovery, and is ``False`` by default.
|
||||||
* Discovery now times out by default.
|
* Discovery now times out by default.
|
||||||
* Add support for plugins that hook into data processing pipeline, see
|
* Add support for plugins that hook into data processing pipeline, see
|
||||||
`plugin-architecture blueprint`_ for details.
|
`plugin-architecture blueprint`_ for details.
|
||||||
|
@ -28,6 +28,8 @@
|
|||||||
;timeout = 3600
|
;timeout = 3600
|
||||||
; Amount of time in seconds, after which repeat clean up of timed out nodes.
|
; Amount of time in seconds, after which repeat clean up of timed out nodes.
|
||||||
;firewall_update_period = 60
|
;firewall_update_period = 60
|
||||||
|
; Whether to power off the ramdisk immediately after the successful discovery.
|
||||||
|
;power_off_after_discovery = false
|
||||||
|
|
||||||
; IP to listen on.
|
; IP to listen on.
|
||||||
;listen_address = 0.0.0.0
|
;listen_address = 0.0.0.0
|
||||||
|
@ -28,6 +28,7 @@ DEFAULTS = {
|
|||||||
'processing_hooks': 'scheduler',
|
'processing_hooks': 'scheduler',
|
||||||
'timeout': '3600',
|
'timeout': '3600',
|
||||||
'clean_up_period': '60',
|
'clean_up_period': '60',
|
||||||
|
'power_off_after_discovery': 'false',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -97,9 +97,6 @@ def _process_node(ironic, node, node_info, valid_macs):
|
|||||||
'database - skipping',
|
'database - skipping',
|
||||||
{'mac': mac, 'node': node.uuid})
|
{'mac': mac, 'node': node.uuid})
|
||||||
|
|
||||||
patch = [{'op': 'add', 'path': '/extra/newly_discovered', 'value': 'true'},
|
|
||||||
{'op': 'remove', 'path': '/extra/on_discovery'}]
|
|
||||||
|
|
||||||
node_patches = []
|
node_patches = []
|
||||||
port_patches = {}
|
port_patches = {}
|
||||||
for hook_ext in hooks:
|
for hook_ext in hooks:
|
||||||
@ -114,22 +111,28 @@ def _process_node(ironic, node, node_info, valid_macs):
|
|||||||
port_patches = {mac: patch for (mac, patch) in port_patches.items()
|
port_patches = {mac: patch for (mac, patch) in port_patches.items()
|
||||||
if mac in ports and patch}
|
if mac in ports and patch}
|
||||||
|
|
||||||
ironic.node.update(node.uuid, patch + node_patches)
|
ironic.node.update(node.uuid, node_patches)
|
||||||
|
|
||||||
for mac, patches in port_patches.items():
|
for mac, patches in port_patches.items():
|
||||||
ironic.port.update(ports[mac].uuid, patches)
|
ironic.port.update(ports[mac].uuid, patches)
|
||||||
|
|
||||||
LOG.info('Node %s was updated with data from discovery process, forcing '
|
LOG.info('Node %s was updated with data from discovery process', node.uuid)
|
||||||
'power off', node.uuid)
|
|
||||||
|
|
||||||
firewall.update_filters(ironic)
|
firewall.update_filters(ironic)
|
||||||
|
|
||||||
|
if conf.getboolean('discoverd', 'power_off_after_discovery'):
|
||||||
|
LOG.info('Forcing power off of node %s', node.uuid)
|
||||||
try:
|
try:
|
||||||
ironic.node.set_power_state(node.uuid, 'off')
|
ironic.node.set_power_state(node.uuid, 'off')
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
LOG.error('Failed to power off node %s, check it\'s power '
|
LOG.error('Failed to power off node %s, check it\'s power '
|
||||||
'management configuration:\n%s', node.uuid, exc)
|
'management configuration:\n%s', node.uuid, exc)
|
||||||
raise utils.DiscoveryFailed('Failed to power off node %s' % node.uuid)
|
raise utils.DiscoveryFailed('Failed to power off node %s' %
|
||||||
|
node.uuid)
|
||||||
|
|
||||||
|
patch = [{'op': 'add', 'path': '/extra/newly_discovered', 'value': 'true'},
|
||||||
|
{'op': 'remove', 'path': '/extra/on_discovery'}]
|
||||||
|
ironic.node.update(node.uuid, patch)
|
||||||
|
|
||||||
|
|
||||||
def discover(uuids):
|
def discover(uuids):
|
||||||
|
@ -51,16 +51,19 @@ class BaseTest(unittest.TestCase):
|
|||||||
@patch.object(utils, 'get_client', autospec=True)
|
@patch.object(utils, 'get_client', autospec=True)
|
||||||
class TestProcess(BaseTest):
|
class TestProcess(BaseTest):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
super(TestProcess, self).setUp()
|
||||||
self.node = Mock(driver_info={'ipmi_address': '1.2.3.4'},
|
self.node = Mock(driver_info={'ipmi_address': '1.2.3.4'},
|
||||||
properties={'cpu_arch': 'i386', 'local_gb': 40},
|
properties={'cpu_arch': 'i386', 'local_gb': 40},
|
||||||
uuid='uuid',
|
uuid='uuid',
|
||||||
extra={'on_discovery': 'true'})
|
extra={'on_discovery': 'true'})
|
||||||
self.patch = [
|
self.patch1 = [
|
||||||
{'op': 'add', 'path': '/extra/newly_discovered', 'value': 'true'},
|
|
||||||
{'op': 'remove', 'path': '/extra/on_discovery'},
|
|
||||||
{'op': 'add', 'path': '/properties/cpus', 'value': '2'},
|
{'op': 'add', 'path': '/properties/cpus', 'value': '2'},
|
||||||
{'op': 'add', 'path': '/properties/memory_mb', 'value': '1024'},
|
{'op': 'add', 'path': '/properties/memory_mb', 'value': '1024'},
|
||||||
]
|
]
|
||||||
|
self.patch2 = [
|
||||||
|
{'op': 'add', 'path': '/extra/newly_discovered', 'value': 'true'},
|
||||||
|
{'op': 'remove', 'path': '/extra/on_discovery'},
|
||||||
|
]
|
||||||
self.data = {
|
self.data = {
|
||||||
'ipmi_address': '1.2.3.4',
|
'ipmi_address': '1.2.3.4',
|
||||||
'cpus': 2,
|
'cpus': 2,
|
||||||
@ -105,16 +108,17 @@ class TestProcess(BaseTest):
|
|||||||
self.assertEqual(['11:22:33:44:55:66', '66:55:44:33:22:11'],
|
self.assertEqual(['11:22:33:44:55:66', '66:55:44:33:22:11'],
|
||||||
sorted(pop_mock.call_args[1]['mac']))
|
sorted(pop_mock.call_args[1]['mac']))
|
||||||
|
|
||||||
cli.node.update.assert_called_once_with(self.node.uuid,
|
cli.node.update.assert_any_call(self.node.uuid,
|
||||||
self.patch + ['fake patch',
|
self.patch1 + ['fake patch',
|
||||||
'fake patch 2'])
|
'fake patch 2'])
|
||||||
|
cli.node.update.assert_any_call(self.node.uuid, self.patch2)
|
||||||
|
self.assertEqual(2, cli.node.update.call_count)
|
||||||
cli.port.create.assert_any_call(node_uuid=self.node.uuid,
|
cli.port.create.assert_any_call(node_uuid=self.node.uuid,
|
||||||
address='11:22:33:44:55:66')
|
address='11:22:33:44:55:66')
|
||||||
cli.port.create.assert_any_call(node_uuid=self.node.uuid,
|
cli.port.create.assert_any_call(node_uuid=self.node.uuid,
|
||||||
address='66:55:44:33:22:11')
|
address='66:55:44:33:22:11')
|
||||||
self.assertEqual(2, cli.port.create.call_count)
|
self.assertEqual(2, cli.port.create.call_count)
|
||||||
filters_mock.assert_called_once_with(cli)
|
filters_mock.assert_called_once_with(cli)
|
||||||
cli.node.set_power_state.assert_called_once_with(self.node.uuid, 'off')
|
|
||||||
cli.port.update.assert_called_once_with(self.port.uuid, ['port patch'])
|
cli.port.update.assert_called_once_with(self.port.uuid, ['port patch'])
|
||||||
|
|
||||||
pre_mock.assert_called_once_with(self.data)
|
pre_mock.assert_called_once_with(self.data)
|
||||||
@ -123,6 +127,14 @@ class TestProcess(BaseTest):
|
|||||||
def test_ok(self, client_mock, pop_mock, filters_mock, pre_mock,
|
def test_ok(self, client_mock, pop_mock, filters_mock, pre_mock,
|
||||||
post_mock):
|
post_mock):
|
||||||
self._do_test(client_mock, pop_mock, filters_mock, pre_mock, post_mock)
|
self._do_test(client_mock, pop_mock, filters_mock, pre_mock, post_mock)
|
||||||
|
self.assertFalse(client_mock.return_value.node.set_power_state.called)
|
||||||
|
|
||||||
|
def test_force_off(self, client_mock, pop_mock, filters_mock, pre_mock,
|
||||||
|
post_mock):
|
||||||
|
conf.CONF.set('discoverd', 'power_off_after_discovery', 'true')
|
||||||
|
self._do_test(client_mock, pop_mock, filters_mock, pre_mock, post_mock)
|
||||||
|
client_mock.return_value.node.set_power_state.assert_called_once_with(
|
||||||
|
self.node.uuid, 'off')
|
||||||
|
|
||||||
def test_deprecated_macs(self, client_mock, pop_mock, filters_mock,
|
def test_deprecated_macs(self, client_mock, pop_mock, filters_mock,
|
||||||
pre_mock, post_mock):
|
pre_mock, post_mock):
|
||||||
|
Loading…
Reference in New Issue
Block a user