Merge "Handle duplicate node inventory entries per node"
This commit is contained in:
commit
ce1abd4007
@ -2651,12 +2651,13 @@ class Connection(api.Connection):
|
|||||||
inventory = models.NodeInventory()
|
inventory = models.NodeInventory()
|
||||||
inventory.update(values)
|
inventory.update(values)
|
||||||
with _session_for_write() as session:
|
with _session_for_write() as session:
|
||||||
try:
|
session.query(
|
||||||
session.add(inventory)
|
models.NodeInventory
|
||||||
session.flush()
|
).filter(
|
||||||
except db_exc.DBDuplicateEntry:
|
models.NodeInventory.node_id == values['node_id']
|
||||||
raise exception.NodeInventoryAlreadyExists(
|
).delete()
|
||||||
id=values['id'])
|
session.add(inventory)
|
||||||
|
session.flush()
|
||||||
return inventory
|
return inventory
|
||||||
|
|
||||||
@oslo_db_api.retry_on_deadlock
|
@oslo_db_api.retry_on_deadlock
|
||||||
@ -2670,12 +2671,26 @@ class Connection(api.Connection):
|
|||||||
node=node_id)
|
node=node_id)
|
||||||
|
|
||||||
def get_node_inventory_by_node_id(self, node_id):
|
def get_node_inventory_by_node_id(self, node_id):
|
||||||
try:
|
with _session_for_read() as session:
|
||||||
with _session_for_read() as session:
|
# Note(masghar): The most recent node inventory is extracted
|
||||||
query = session.query(models.NodeInventory).filter_by(
|
# (as per the created_at field). This is because previously, it was
|
||||||
node_id=node_id)
|
# possible to add more than one inventory per node into the
|
||||||
res = query.one()
|
# database, due to there being no unique constraint on the node_id
|
||||||
except NoResultFound:
|
# column in the node_inventory table. Now, all previous node
|
||||||
|
# inventories are deleted before a new one is added using
|
||||||
|
# create_node_inventory. However, some databases would already
|
||||||
|
# contain multiple node inventories due to the prior
|
||||||
|
# implementation. Hence the most recent one is being retrieved.
|
||||||
|
query = session.query(
|
||||||
|
models.NodeInventory
|
||||||
|
).filter_by(
|
||||||
|
node_id=node_id
|
||||||
|
).order_by(
|
||||||
|
models.NodeInventory.created_at.desc()
|
||||||
|
)
|
||||||
|
res = query.first()
|
||||||
|
|
||||||
|
if res is None:
|
||||||
raise exception.NodeInventoryNotFound(node=node_id)
|
raise exception.NodeInventoryNotFound(node=node_id)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
@ -8025,7 +8025,9 @@ class TestNodeHistory(test_api_base.BaseApiTest):
|
|||||||
|
|
||||||
|
|
||||||
class TestNodeInventory(test_api_base.BaseApiTest):
|
class TestNodeInventory(test_api_base.BaseApiTest):
|
||||||
fake_inventory_data = {"cpu": "amd"}
|
fake_inventory_data = {'cpu': {'count': 1,
|
||||||
|
'model_name': 'qemu64',
|
||||||
|
'architecture': 'x86_64'}}
|
||||||
fake_plugin_data = {"disks": [{"name": "/dev/vda"}]}
|
fake_plugin_data = {"disks": [{"name": "/dev/vda"}]}
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
@ -24,6 +24,7 @@ from sqlalchemy.orm import exc as sa_exc
|
|||||||
|
|
||||||
from ironic.common import exception
|
from ironic.common import exception
|
||||||
from ironic.common import states
|
from ironic.common import states
|
||||||
|
from ironic.db.sqlalchemy.models import NodeInventory
|
||||||
from ironic.tests.unit.db import base
|
from ironic.tests.unit.db import base
|
||||||
from ironic.tests.unit.db import utils
|
from ironic.tests.unit.db import utils
|
||||||
|
|
||||||
@ -763,6 +764,31 @@ class DbNodeTestCase(base.DbTestCase):
|
|||||||
self.assertRaises(exception.NodeHistoryNotFound,
|
self.assertRaises(exception.NodeHistoryNotFound,
|
||||||
self.dbapi.get_node_history_by_id, history.id)
|
self.dbapi.get_node_history_by_id, history.id)
|
||||||
|
|
||||||
|
def test_inventory_updated_for_node(self):
|
||||||
|
node = utils.create_test_node()
|
||||||
|
|
||||||
|
first_timestamp = datetime.datetime(2000, 1, 1, 0, 0)
|
||||||
|
second_timestamp = first_timestamp + datetime.timedelta(minutes=8)
|
||||||
|
utils.create_test_inventory(node_id=node.id,
|
||||||
|
id=1,
|
||||||
|
created_at=first_timestamp)
|
||||||
|
utils.create_test_inventory(node_id=node.id,
|
||||||
|
id=2,
|
||||||
|
inventory={"inventory": "test2"},
|
||||||
|
created_at=second_timestamp)
|
||||||
|
|
||||||
|
node_inventory = self.dbapi.get_node_inventory_by_node_id(
|
||||||
|
node_id=node.id)
|
||||||
|
expected_inventory = NodeInventory(node_id=node.id,
|
||||||
|
id=2,
|
||||||
|
inventory_data={"inventory":
|
||||||
|
"test2"},
|
||||||
|
created_at=second_timestamp,
|
||||||
|
plugin_data={"pdata":
|
||||||
|
{"plugin": "data"}},
|
||||||
|
version='1.0')
|
||||||
|
self.assertJsonEqual(expected_inventory, node_inventory)
|
||||||
|
|
||||||
def test_inventory_get_destroyed_after_destroying_a_node_by_uuid(self):
|
def test_inventory_get_destroyed_after_destroying_a_node_by_uuid(self):
|
||||||
node = utils.create_test_node()
|
node = utils.create_test_node()
|
||||||
|
|
||||||
|
@ -743,7 +743,7 @@ def get_test_inventory(**kw):
|
|||||||
def create_test_inventory(**kw):
|
def create_test_inventory(**kw):
|
||||||
"""Create test inventory entry in DB and return NodeInventory DB object.
|
"""Create test inventory entry in DB and return NodeInventory DB object.
|
||||||
|
|
||||||
:param kw: kwargs with overriding values for port's attributes.
|
:param kw: kwargs with overriding values for inventory attributes.
|
||||||
:returns: Test NodeInventory DB object.
|
:returns: Test NodeInventory DB object.
|
||||||
"""
|
"""
|
||||||
inventory = get_test_inventory(**kw)
|
inventory = get_test_inventory(**kw)
|
||||||
|
@ -0,0 +1,15 @@
|
|||||||
|
---
|
||||||
|
fixes:
|
||||||
|
- |
|
||||||
|
Fixes a bug that occurs when a node is inspected more than once and the
|
||||||
|
database is configured as a storage backend: a new node inventory entry
|
||||||
|
is added in the database for each inspection result, causing more than one
|
||||||
|
inventory to exist for the node in the node_inventory table.
|
||||||
|
|
||||||
|
This is handled by:
|
||||||
|
|
||||||
|
* Deleting any previous inventory entries for a node before adding a new
|
||||||
|
entry in the database.
|
||||||
|
* Retrieving the most recent node inventory from the database when the
|
||||||
|
database is queried. (To cater for databases that already contain
|
||||||
|
duplicate node inventories due to the bug.)
|
Loading…
Reference in New Issue
Block a user