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:
parent
59d3676bca
commit
399ffda676
|
@ -174,11 +174,20 @@ def periodic_clean_up(period): # pragma: no cover
|
||||||
try:
|
try:
|
||||||
if node_cache.clean_up():
|
if node_cache.clean_up():
|
||||||
firewall.update_filters()
|
firewall.update_filters()
|
||||||
|
sync_with_ironic()
|
||||||
except Exception:
|
except Exception:
|
||||||
LOG.exception(_LE('Periodic clean up of node cache failed'))
|
LOG.exception(_LE('Periodic clean up of node cache failed'))
|
||||||
eventlet.greenthread.sleep(period)
|
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():
|
def init():
|
||||||
if utils.get_auth_strategy() != 'noauth':
|
if utils.get_auth_strategy() != 'noauth':
|
||||||
utils.add_auth_middleware(app)
|
utils.add_auth_middleware(app)
|
||||||
|
|
|
@ -183,13 +183,7 @@ def add_node(uuid, **attributes):
|
||||||
"""
|
"""
|
||||||
started_at = time.time()
|
started_at = time.time()
|
||||||
with db.ensure_transaction() as session:
|
with db.ensure_transaction() as session:
|
||||||
(db.model_query(db.Node, session=session).filter_by(uuid=uuid).
|
_delete_node(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())
|
|
||||||
|
|
||||||
db.Node(uuid=uuid, started_at=started_at).save(session)
|
db.Node(uuid=uuid, started_at=started_at).save(session)
|
||||||
|
|
||||||
node_info = NodeInfo(uuid=uuid, started_at=started_at)
|
node_info = NodeInfo(uuid=uuid, started_at=started_at)
|
||||||
|
@ -201,12 +195,46 @@ def add_node(uuid, **attributes):
|
||||||
return node_info
|
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():
|
def active_macs():
|
||||||
"""List all MAC's that are on introspection right now."""
|
"""List all MAC's that are on introspection right now."""
|
||||||
return ({x.value for x in db.model_query(db.Attribute.value).
|
return ({x.value for x in db.model_query(db.Attribute.value).
|
||||||
filter_by(name=MACS_ATTRIBUTE)})
|
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):
|
def get_node(uuid):
|
||||||
"""Get node from cache by it's UUID.
|
"""Get node from cache by it's UUID.
|
||||||
|
|
||||||
|
|
|
@ -57,6 +57,7 @@ class Base(base.NodeTest):
|
||||||
self.cli.reset_mock()
|
self.cli.reset_mock()
|
||||||
self.cli.node.get.return_value = self.node
|
self.cli.node.get.return_value = self.node
|
||||||
self.cli.node.update.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
|
# https://github.com/openstack/ironic-inspector/blob/master/HTTP-API.rst # noqa
|
||||||
self.data = {
|
self.data = {
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
|
import json
|
||||||
import time
|
import time
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
|
@ -56,6 +57,41 @@ class TestNodeCache(test_base.NodeTest):
|
||||||
('mac', self.macs[1], self.uuid)],
|
('mac', self.macs[1], self.uuid)],
|
||||||
[(row.name, row.value, row.uuid) for row in res])
|
[(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):
|
def test_add_node_duplicate_mac(self):
|
||||||
session = db.get_session()
|
session = db.get_session()
|
||||||
with session.begin():
|
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'},
|
self.assertEqual({'11:22:11:22:11:22', '22:11:22:11:22:11'},
|
||||||
node_cache.active_macs())
|
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):
|
def test_add_attribute(self):
|
||||||
session = db.get_session()
|
session = db.get_session()
|
||||||
with session.begin():
|
with session.begin():
|
||||||
|
|
Loading…
Reference in New Issue