Merge "Allow ramdisk to specify PXE boot interface"

This commit is contained in:
Jenkins 2015-02-09 12:34:34 +00:00 committed by Gerrit Code Review
commit 2fbe520ba8
5 changed files with 74 additions and 4 deletions

View File

@ -324,6 +324,14 @@ See `1.1.0 release tracking page`_ for details.
**Major Features**
* Default to only creating a port for the NIC that the ramdisk was PXE booted
from, if such information is provided by ramdisk as ``boot_interface`` field.
Adjustable by ``only_pxe_booting_port`` option.
See `better-boot-interface-detection blueprint
<https://blueprints.launchpad.net/ironic-discoverd/+spec/better-boot-interface-detection>`_
for details.
**Other Changes**
* Experimental plugin ``edeploy`` to use with

View File

@ -32,8 +32,13 @@
; If set to false, discoverd will create ports only for those interfaces, that
; received IP address during ramdisk boot. Otherwise ports will be created
; for all interfaces. You should leave it as false, unless you encounter any
; bugs with this behavior.
; bugs with this behavior. Has limited effect if only_pxe_booting_port is true.
;ports_for_inactive_interfaces = false
; If set to true, discoverd will try to detect the interface that node
; PXE booted from and will create a port only for it.
; If it cannot be detected, all ports will be created
; (regulated by ports_for_inactive_interfaces option).
;only_pxe_booting_port = true
; Timeout after which introspection is considered failed, set to 0 to disable.
;timeout = 3600
; For how much time (in seconds) to keep status information about nodes after

View File

@ -29,6 +29,7 @@ DEFAULTS = {
'firewall_update_period': '15',
# Introspection process settings
'ports_for_inactive_interfaces': 'false',
'only_pxe_booting_port': 'true',
'timeout': '3600',
'node_status_keep_time': '604800',
'clean_up_period': '60',

View File

@ -66,7 +66,17 @@ class ValidateInterfacesHook(base.ProcessingHook):
ports_for_inactive = conf.getboolean('discoverd',
'ports_for_inactive_interfaces')
if not ports_for_inactive:
only_pxe = conf.getboolean('discoverd', 'only_pxe_booting_port')
pxe_mac = node_info.get('boot_interface')
if only_pxe and pxe_mac:
LOG.info('PXE boot interface was %s', pxe_mac)
pxe_mac = pxe_mac.replace('-', ':').lower()
valid_interfaces = {
n: iface for n, iface in valid_interfaces.items()
if iface['mac'].lower() == pxe_mac
}
elif not ports_for_inactive:
valid_interfaces = {
n: iface for n, iface in valid_interfaces.items()
if iface.get('ip')

View File

@ -34,6 +34,7 @@ class BaseTest(test_base.NodeTest):
'ramdisk_error,scheduler,validate_interfaces')
self.started_at = time.time()
self.all_macs = self.macs + ['DE:AD:BE:EF:DE:AD']
self.pxe_mac = self.macs[1]
self.data = {
'ipmi_address': self.bmc_address,
'cpus': 2,
@ -44,12 +45,14 @@ class BaseTest(test_base.NodeTest):
'em1': {'mac': self.macs[0], 'ip': '1.2.0.1'},
'em2': {'mac': self.macs[1], 'ip': '1.2.0.2'},
'em3': {'mac': self.all_macs[2]},
}
},
'boot_interface': self.pxe_mac,
}
self.ports = [
self.all_ports = [
mock.Mock(uuid='port_uuid%d' % i, address=mac)
for i, mac in enumerate(self.macs)
]
self.ports = [self.all_ports[1]]
@mock.patch.object(process, '_process_node', autospec=True)
@ -81,6 +84,46 @@ class TestProcess(BaseTest):
self.assertEqual(self.fake_result_json, res)
# Only boot interface is added by default
self.assertEqual(['em2'], sorted(self.data['interfaces']))
self.assertEqual(['em1', 'em2', 'em3'],
sorted(self.data['all_interfaces']))
self.assertEqual([self.pxe_mac], self.data['macs'])
pop_mock.assert_called_once_with(bmc_address=self.bmc_address,
mac=self.data['macs'])
cli.node.get.assert_called_once_with(self.uuid)
process_mock.assert_called_once_with(cli, cli.node.get.return_value,
self.data, pop_mock.return_value)
@prepare_mocks
def test_no_boot_interface(self, cli, pop_mock, process_mock):
del self.data['boot_interface']
res = process.process(self.data)
self.assertEqual(self.fake_result_json, res)
# By default interfaces w/o IP are dropped
self.assertEqual(['em1', 'em2'], sorted(self.data['interfaces']))
self.assertEqual(['em1', 'em2', 'em3'],
sorted(self.data['all_interfaces']))
self.assertEqual(self.macs, sorted(self.data['macs']))
pop_mock.assert_called_once_with(bmc_address=self.bmc_address,
mac=self.data['macs'])
cli.node.get.assert_called_once_with(self.uuid)
process_mock.assert_called_once_with(cli, cli.node.get.return_value,
self.data, pop_mock.return_value)
@prepare_mocks
def test_non_pxe_interfaces(self, cli, pop_mock, process_mock):
conf.CONF.set('discoverd', 'only_pxe_booting_port', 'false')
res = process.process(self.data)
self.assertEqual(self.fake_result_json, res)
# By default interfaces w/o IP are dropped
self.assertEqual(['em1', 'em2'], sorted(self.data['interfaces']))
self.assertEqual(['em1', 'em2', 'em3'],
@ -112,6 +155,8 @@ class TestProcess(BaseTest):
@prepare_mocks
def test_ports_for_inactive(self, cli, pop_mock, process_mock):
conf.CONF.set('discoverd', 'ports_for_inactive_interfaces', 'true')
del self.data['boot_interface']
process.process(self.data)
self.assertEqual(['em1', 'em2', 'em3'],
@ -234,6 +279,7 @@ class TestProcessNode(BaseTest):
self.validate_attempts = 5
self.power_off_attempts = 2
self.data['macs'] = self.macs # validate_interfaces hook
self.ports = self.all_ports
self.cached_node = node_cache.NodeInfo(uuid=self.uuid,
started_at=self.started_at)
self.patch_before = [