Log look up attributes at INFO level

Without this it's hard to debug look up issues.
This change required NodeInfo to expose attributes.

Change-Id: Ieba14ab14dd356cc2c099656201c24fa46cbff6d
This commit is contained in:
Dmitry Tantsur 2015-08-03 18:01:21 +02:00
parent b383c87dfc
commit 7d32c57936
3 changed files with 41 additions and 0 deletions

View File

@ -131,6 +131,10 @@ def _background_introspect(ironic, node_info):
{'macs': macs, 'node': node_info.uuid}) {'macs': macs, 'node': node_info.uuid})
firewall.update_filters(ironic) firewall.update_filters(ironic)
LOG.info(_LI('The following attributes will be used for looking up '
'node %(uuid)s: %(attrs)s'),
{'attrs': node_info.attributes, 'uuid': node_info.uuid})
if not node_info.options.get('new_ipmi_credentials'): if not node_info.options.get('new_ipmi_credentials'):
try: try:
ironic.node.set_boot_device(node_info.uuid, 'pxe', ironic.node.set_boot_device(node_info.uuid, 'pxe',

View File

@ -49,6 +49,7 @@ class NodeInfo(object):
if ports is not None and not isinstance(ports, dict): if ports is not None and not isinstance(ports, dict):
ports = {p.address: p for p in ports} ports = {p.address: p for p in ports}
self._ports = ports self._ports = ports
self._attributes = None
@property @property
def options(self): def options(self):
@ -60,6 +61,17 @@ class NodeInfo(object):
for row in rows} for row in rows}
return self._options return self._options
@property
def attributes(self):
"""Node look up attributes as a dict."""
if self._attributes is None:
self._attributes = {}
rows = db.model_query(db.Attribute).filter_by(
uuid=self.uuid)
for row in rows:
self._attributes.setdefault(row.name, []).append(row.value)
return self._attributes
def set_option(self, name, value): def set_option(self, name, value):
"""Set an option for a node.""" """Set an option for a node."""
encoded = json.dumps(value) encoded = json.dumps(value)
@ -111,6 +123,8 @@ class NodeInfo(object):
raise utils.Error(_( raise utils.Error(_(
'Some or all of %(name)s\'s %(value)s are already ' 'Some or all of %(name)s\'s %(value)s are already '
'on introspection') % {'name': name, 'value': value}) 'on introspection') % {'name': name, 'value': value})
# Invalidate attributes so they're loaded on next usage
self._attributes = None
@classmethod @classmethod
def from_row(cls, row): def from_row(cls, row):
@ -124,6 +138,7 @@ class NodeInfo(object):
self._options = None self._options = None
self._node = None self._node = None
self._ports = None self._ports = None
self._attributes = None
def node(self, ironic=None): def node(self, ironic=None):
"""Get Ironic node object associated with the cached node record.""" """Get Ironic node object associated with the cached node record."""

View File

@ -93,6 +93,28 @@ class TestNodeCache(test_base.NodeTest):
[tuple(row) for row in res]) [tuple(row) for row in res])
self.assertRaises(utils.Error, node_info.add_attribute, self.assertRaises(utils.Error, node_info.add_attribute,
'key', 'value') 'key', 'value')
# check that .attributes got invalidated and reloaded
self.assertEqual({'key': ['value']}, node_info.attributes)
def test_attributes(self):
node_info = node_cache.add_node(self.uuid,
bmc_address='1.2.3.4',
mac=self.macs)
self.assertEqual({'bmc_address': ['1.2.3.4'],
'mac': self.macs},
node_info.attributes)
# check invalidation
session = db.get_session()
with session.begin():
db.Attribute(name='foo', value='bar', uuid=self.uuid).save(session)
# still cached
self.assertEqual({'bmc_address': ['1.2.3.4'],
'mac': self.macs},
node_info.attributes)
node_info.invalidate_cache()
self.assertEqual({'bmc_address': ['1.2.3.4'],
'mac': self.macs, 'foo': ['bar']},
node_info.attributes)
class TestNodeCacheFind(test_base.NodeTest): class TestNodeCacheFind(test_base.NodeTest):