Merge "Add option to delete ports after introspection"
This commit is contained in:
commit
16cc7323a5
|
@ -49,6 +49,13 @@
|
||||||
# Allowed values: all, active, pxe
|
# Allowed values: all, active, pxe
|
||||||
#add_ports = pxe
|
#add_ports = pxe
|
||||||
|
|
||||||
|
# Which ports (already present on a node) to keep after introspection.
|
||||||
|
# Possible values: all (do not delete anything), present (keep ports
|
||||||
|
# which MACs were present in introspection data), added (keep only
|
||||||
|
# MACs that we added during introspection). (string value)
|
||||||
|
# Allowed values: all, present, added
|
||||||
|
#keep_ports = all
|
||||||
|
|
||||||
# Timeout after which introspection is considered failed, set to 0 to
|
# Timeout after which introspection is considered failed, set to 0 to
|
||||||
# disable. (integer value)
|
# disable. (integer value)
|
||||||
#timeout = 3600
|
#timeout = 3600
|
||||||
|
|
|
@ -15,6 +15,7 @@ from oslo_config import cfg
|
||||||
|
|
||||||
|
|
||||||
VALID_ADD_PORTS_VALUES = ('all', 'active', 'pxe')
|
VALID_ADD_PORTS_VALUES = ('all', 'active', 'pxe')
|
||||||
|
VALID_KEEP_PORTS_VALUES = ('all', 'present', 'added')
|
||||||
|
|
||||||
SERVICE_OPTS = [
|
SERVICE_OPTS = [
|
||||||
cfg.StrOpt('os_auth_url',
|
cfg.StrOpt('os_auth_url',
|
||||||
|
@ -61,6 +62,14 @@ SERVICE_OPTS = [
|
||||||
'from, falls back to "active" if PXE MAC is not supplied '
|
'from, falls back to "active" if PXE MAC is not supplied '
|
||||||
'by the ramdisk).',
|
'by the ramdisk).',
|
||||||
choices=VALID_ADD_PORTS_VALUES),
|
choices=VALID_ADD_PORTS_VALUES),
|
||||||
|
cfg.StrOpt('keep_ports',
|
||||||
|
default='all',
|
||||||
|
help='Which ports (already present on a node) to keep after '
|
||||||
|
'introspection. Possible values: '
|
||||||
|
'all (do not delete anything), present (keep ports which MACs '
|
||||||
|
'were present in introspection data), added (keep only MACs '
|
||||||
|
'that we added during introspection).',
|
||||||
|
choices=VALID_KEEP_PORTS_VALUES),
|
||||||
cfg.IntOpt('timeout',
|
cfg.IntOpt('timeout',
|
||||||
default=3600,
|
default=3600,
|
||||||
help='Timeout after which introspection is considered failed, '
|
help='Timeout after which introspection is considered failed, '
|
||||||
|
|
|
@ -67,6 +67,13 @@ class ValidateInterfacesHook(base.ProcessingHook):
|
||||||
'actual': CONF.discoverd.add_ports})
|
'actual': CONF.discoverd.add_ports})
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
if CONF.discoverd.keep_ports not in conf.VALID_KEEP_PORTS_VALUES:
|
||||||
|
LOG.critical(_LC('Accepted values for [discoverd]keep_ports are '
|
||||||
|
'%(valid)s, got %(actual)s'),
|
||||||
|
{'valid': conf.VALID_KEEP_PORTS_VALUES,
|
||||||
|
'actual': CONF.discoverd.keep_ports})
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
def _ports_to_add(self):
|
def _ports_to_add(self):
|
||||||
if CONF.discoverd.ports_for_inactive_interfaces:
|
if CONF.discoverd.ports_for_inactive_interfaces:
|
||||||
LOG.warning(_LW('Using deprecated option '
|
LOG.warning(_LW('Using deprecated option '
|
||||||
|
@ -127,6 +134,28 @@ class ValidateInterfacesHook(base.ProcessingHook):
|
||||||
valid_macs = [iface['mac'] for iface in valid_interfaces.values()]
|
valid_macs = [iface['mac'] for iface in valid_interfaces.values()]
|
||||||
node_info['macs'] = valid_macs
|
node_info['macs'] = valid_macs
|
||||||
|
|
||||||
|
def before_update(self, node, ports, node_info):
|
||||||
|
"""Drop ports that are not present in the data."""
|
||||||
|
if CONF.discoverd.keep_ports == 'present':
|
||||||
|
expected_macs = {iface['mac']
|
||||||
|
for iface in node_info['all_interfaces'].values()}
|
||||||
|
elif CONF.discoverd.keep_ports == 'added':
|
||||||
|
expected_macs = set(node_info['macs'])
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
|
||||||
|
ironic = utils.get_client()
|
||||||
|
for port in ironic.node.list_ports(node.uuid, limit=0):
|
||||||
|
if port.address not in expected_macs:
|
||||||
|
LOG.info(_LI("Deleting port %(port)s as its MAC %(mac)s is "
|
||||||
|
"not in expected MAC list %(expected)s for node "
|
||||||
|
"%(node)s"),
|
||||||
|
{'port': port.uuid,
|
||||||
|
'mac': port.address,
|
||||||
|
'expected': list(sorted(expected_macs)),
|
||||||
|
'node': node.uuid})
|
||||||
|
ironic.port.delete(port.uuid)
|
||||||
|
|
||||||
|
|
||||||
class RamdiskErrorHook(base.ProcessingHook):
|
class RamdiskErrorHook(base.ProcessingHook):
|
||||||
"""Hook to process error send from the ramdisk."""
|
"""Hook to process error send from the ramdisk."""
|
||||||
|
|
|
@ -325,6 +325,7 @@ class TestProcessNode(BaseTest):
|
||||||
'discoverd')
|
'discoverd')
|
||||||
self.validate_attempts = 5
|
self.validate_attempts = 5
|
||||||
self.data['macs'] = self.macs # validate_interfaces hook
|
self.data['macs'] = self.macs # validate_interfaces hook
|
||||||
|
self.data['all_interfaces'] = self.data['interfaces']
|
||||||
self.ports = self.all_ports
|
self.ports = self.all_ports
|
||||||
self.cached_node = node_cache.NodeInfo(uuid=self.uuid,
|
self.cached_node = node_cache.NodeInfo(uuid=self.uuid,
|
||||||
started_at=self.started_at)
|
started_at=self.started_at)
|
||||||
|
@ -509,8 +510,53 @@ class TestProcessNode(BaseTest):
|
||||||
error='Failed to power off node %s, check it\'s power management'
|
error='Failed to power off node %s, check it\'s power management'
|
||||||
' configuration: boom' % self.uuid)
|
' configuration: boom' % self.uuid)
|
||||||
|
|
||||||
|
@mock.patch.object(utils, 'get_client')
|
||||||
|
def test_keep_ports_present(self, client_mock, filters_mock,
|
||||||
|
post_hook_mock):
|
||||||
|
CONF.set_override('keep_ports', 'present', 'discoverd')
|
||||||
|
|
||||||
|
# 2 MACs valid, one invalid, one not present in data
|
||||||
|
all_macs = self.all_macs + ['01:09:02:08:03:07']
|
||||||
|
all_ports = [
|
||||||
|
mock.Mock(uuid='port_uuid%d' % i, address=mac)
|
||||||
|
for i, mac in enumerate(all_macs)
|
||||||
|
]
|
||||||
|
|
||||||
|
client_mock.return_value = self.cli
|
||||||
|
self.cli.node.list_ports.return_value = all_ports
|
||||||
|
|
||||||
|
self.call()
|
||||||
|
|
||||||
|
self.cli.node.list_ports.assert_called_once_with(self.uuid, limit=0)
|
||||||
|
self.cli.port.delete.assert_called_once_with(all_ports[-1].uuid)
|
||||||
|
|
||||||
|
@mock.patch.object(utils, 'get_client')
|
||||||
|
def test_keep_ports_added(self, client_mock, filters_mock, post_hook_mock):
|
||||||
|
CONF.set_override('keep_ports', 'added', 'discoverd')
|
||||||
|
|
||||||
|
# 2 MACs valid, one invalid, one not present in data
|
||||||
|
all_macs = self.all_macs + ['01:09:02:08:03:07']
|
||||||
|
all_ports = [
|
||||||
|
mock.Mock(uuid='port_uuid%d' % i, address=mac)
|
||||||
|
for i, mac in enumerate(all_macs)
|
||||||
|
]
|
||||||
|
|
||||||
|
client_mock.return_value = self.cli
|
||||||
|
self.cli.node.list_ports.return_value = all_ports
|
||||||
|
|
||||||
|
self.call()
|
||||||
|
|
||||||
|
self.cli.node.list_ports.assert_called_once_with(self.uuid, limit=0)
|
||||||
|
for port in all_ports[2:]:
|
||||||
|
self.cli.port.delete.assert_any_call(port.uuid)
|
||||||
|
self.assertEqual(2, self.cli.port.delete.call_count)
|
||||||
|
|
||||||
|
|
||||||
class TestValidateInterfacesHook(test_base.BaseTest):
|
class TestValidateInterfacesHook(test_base.BaseTest):
|
||||||
def test_wrong_add_ports(self):
|
def test_wrong_add_ports(self):
|
||||||
CONF.set_override('add_ports', 'foobar', 'discoverd')
|
CONF.set_override('add_ports', 'foobar', 'discoverd')
|
||||||
self.assertRaises(SystemExit, std_plugins.ValidateInterfacesHook)
|
self.assertRaises(SystemExit, std_plugins.ValidateInterfacesHook)
|
||||||
|
|
||||||
|
def test_wrong_keep_ports(self):
|
||||||
|
CONF.set_override('keep_ports', 'foobar', 'discoverd')
|
||||||
|
self.assertRaises(SystemExit, std_plugins.ValidateInterfacesHook)
|
||||||
|
|
Loading…
Reference in New Issue