Periodically check nodes' existance

Add below procedure to periodic_clean_up() in order to sync data
with Ironic.
* Get Ironic's node list by executing python-ironicclient's node.list()
* Compare above Ironic-node-list and cache
* If node in cache is not exist in Ironic-node-list,
  delete data from cache.

Change-Id: I606b0a76559b8bd2845d58146086b1019712dc34
Implements: blueprint delete-db-api
This commit is contained in:
Yuiko Takada 2015-06-29 23:58:50 +09:00 committed by Yuiko Takada
parent 59d3676bca
commit 399ffda676
4 changed files with 90 additions and 7 deletions

View File

@ -174,11 +174,20 @@ def periodic_clean_up(period): # pragma: no cover
try:
if node_cache.clean_up():
firewall.update_filters()
sync_with_ironic()
except Exception:
LOG.exception(_LE('Periodic clean up of node cache failed'))
eventlet.greenthread.sleep(period)
def sync_with_ironic():
ironic = utils.get_client()
# TODO(yuikotakada): pagination
ironic_nodes = ironic.node.list(limit=0)
ironic_node_uuids = {node.uuid for node in ironic_nodes}
node_cache.delete_nodes_not_in_list(ironic_node_uuids)
def init():
if utils.get_auth_strategy() != 'noauth':
utils.add_auth_middleware(app)

View File

@ -183,13 +183,7 @@ def add_node(uuid, **attributes):
"""
started_at = time.time()
with db.ensure_transaction() as session:
(db.model_query(db.Node, session=session).filter_by(uuid=uuid).
delete())
(db.model_query(db.Attribute, session=session).filter_by(uuid=uuid).
delete(synchronize_session=False))
(db.model_query(db.Option, session=session).filter_by(uuid=uuid).
delete())
_delete_node(uuid)
db.Node(uuid=uuid, started_at=started_at).save(session)
node_info = NodeInfo(uuid=uuid, started_at=started_at)
@ -201,12 +195,46 @@ def add_node(uuid, **attributes):
return node_info
def delete_nodes_not_in_list(uuids):
"""Delete nodes which don't exist in Ironic node UUIDs.
:param uuids: Ironic node UUIDs
"""
inspector_uuids = _list_node_uuids()
for uuid in inspector_uuids - uuids:
LOG.warn(_LW('Node %s was deleted from Ironic, dropping from Ironic '
'Inspector database'), uuid)
_delete_node(uuid)
def _delete_node(uuid, session=None):
"""Delete information about a node.
:param uuid: Ironic node UUID
"""
with db.ensure_transaction(session) as session:
(db.model_query(db.Node, session=session).filter_by(uuid=uuid).
delete())
(db.model_query(db.Attribute, session=session).filter_by(uuid=uuid).
delete(synchronize_session=False))
(db.model_query(db.Option, session=session).filter_by(uuid=uuid).
delete())
def active_macs():
"""List all MAC's that are on introspection right now."""
return ({x.value for x in db.model_query(db.Attribute.value).
filter_by(name=MACS_ATTRIBUTE)})
def _list_node_uuids():
"""Get all nodes' uuid from cache.
:returns: Set of nodes' uuid.
"""
return {x.uuid for x in db.model_query(db.Node.uuid)}
def get_node(uuid):
"""Get node from cache by it's UUID.

View File

@ -57,6 +57,7 @@ class Base(base.NodeTest):
self.cli.reset_mock()
self.cli.node.get.return_value = self.node
self.cli.node.update.return_value = self.node
self.cli.node.list.return_value = [self.node]
# https://github.com/openstack/ironic-inspector/blob/master/HTTP-API.rst # noqa
self.data = {

View File

@ -11,6 +11,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import json
import time
import unittest
@ -56,6 +57,41 @@ class TestNodeCache(test_base.NodeTest):
('mac', self.macs[1], self.uuid)],
[(row.name, row.value, row.uuid) for row in res])
def test__delete_node(self):
session = db.get_session()
with session.begin():
db.Node(uuid=self.node.uuid).save(session)
db.Attribute(name='mac', value='11:22:11:22:11:22',
uuid=self.uuid).save(session)
data = {'s': 'value', 'b': True, 'i': 42}
encoded = json.dumps(data)
db.Option(uuid=self.uuid, name='name', value=encoded).save(
session)
node_cache._delete_node(self.uuid)
session = db.get_session()
row_node = db.model_query(db.Node).filter_by(
uuid=self.uuid).first()
self.assertIsNone(row_node)
row_attribute = db.model_query(db.Attribute).filter_by(
uuid=self.uuid).first()
self.assertIsNone(row_attribute)
row_option = db.model_query(db.Option).filter_by(
uuid=self.uuid).first()
self.assertIsNone(row_option)
@mock.patch.object(node_cache, '_list_node_uuids')
@mock.patch.object(node_cache, '_delete_node')
def test_delete_nodes_not_in_list(self, mock__delete_node,
mock__list_node_uuids):
uuid2 = 'uuid2'
uuids = {self.uuid}
mock__list_node_uuids.return_value = {self.uuid, uuid2}
session = db.get_session()
with session.begin():
node_cache.delete_nodes_not_in_list(uuids)
mock__delete_node.assert_called_once_with(uuid2)
def test_add_node_duplicate_mac(self):
session = db.get_session()
with session.begin():
@ -78,6 +114,15 @@ class TestNodeCache(test_base.NodeTest):
self.assertEqual({'11:22:11:22:11:22', '22:11:22:11:22:11'},
node_cache.active_macs())
def test__list_node_uuids(self):
session = db.get_session()
with session.begin():
db.Node(uuid=self.node.uuid).save(session)
db.Node(uuid='uuid2').save(session)
node_uuid_list = node_cache._list_node_uuids()
self.assertEqual({self.uuid, 'uuid2'}, node_uuid_list)
def test_add_attribute(self):
session = db.get_session()
with session.begin():