diff options
author | Dmitry Tantsur <divius.inside@gmail.com> | 2019-03-04 14:52:14 +0100 |
---|---|---|
committer | Dmitry Tantsur <divius.inside@gmail.com> | 2019-03-04 14:52:14 +0100 |
commit | 885bfbda969f2cceeb6f5ac2c05461c86c6b5dbf (patch) | |
tree | 20b6d0754d37edf2a78d114a559dcbe23f0eeb4a /ironic/db | |
parent | 3f6d4c6a789b12512d6cc67cdbc93ba5fbf29848 (diff) | |
download | ironic-885bfbda969f2cceeb6f5ac2c05461c86c6b5dbf.tar.gz |
Allocation API: optimize check on candidate nodes
Currently we fetch all nodes one by one when validating the provided
candidate_nodes. This is not overly efficient, so this change introduces
a new database API to specifically validate a list of names/uuids and
convert it to uuids. As a nice side effect, no database query is done
for identities that cannot be a valid node name or uuid.
Change-Id: I7adfe897200b1b05d9e632c68d0d3d046c06a921
Story: #2004341
Diffstat (limited to 'ironic/db')
-rw-r--r-- | ironic/db/api.py | 14 | ||||
-rw-r--r-- | ironic/db/sqlalchemy/api.py | 34 |
2 files changed, 48 insertions, 0 deletions
diff --git a/ironic/db/api.py b/ironic/db/api.py index 35d299737..73e47dae8 100644 --- a/ironic/db/api.py +++ b/ironic/db/api.py @@ -98,6 +98,20 @@ class Connection(object): """ @abc.abstractmethod + def check_node_list(self, idents): + """Check a list of node identities and map it to UUIDs. + + This call takes a list of node names and/or UUIDs and tries to convert + them to UUIDs. It fails early if any identities cannot possible be used + as names or UUIDs. + + :param idents: List of identities. + :returns: A mapping from requests identities to node UUIDs. + :raises: NodeNotFound if some identities were not found or cannot be + valid names or UUIDs. + """ + + @abc.abstractmethod def reserve_node(self, tag, node_id): """Reserve a node. diff --git a/ironic/db/sqlalchemy/api.py b/ironic/db/sqlalchemy/api.py index af403cc56..6ca3f1504 100644 --- a/ironic/db/sqlalchemy/api.py +++ b/ironic/db/sqlalchemy/api.py @@ -39,6 +39,7 @@ from ironic.common.i18n import _ from ironic.common import profiler from ironic.common import release_mappings from ironic.common import states +from ironic.common import utils from ironic.conf import CONF from ironic.db import api from ironic.db.sqlalchemy import models @@ -398,6 +399,39 @@ class Connection(api.Connection): return _paginate_query(models.Node, limit, marker, sort_key, sort_dir, query) + def check_node_list(self, idents): + mapping = {} + if idents: + idents = set(idents) + else: + return mapping + + uuids = {i for i in idents if uuidutils.is_uuid_like(i)} + names = {i for i in idents if not uuidutils.is_uuid_like(i) + and utils.is_valid_logical_name(i)} + missing = idents - set(uuids) - set(names) + if missing: + # Such nodes cannot exist, bailing out early + raise exception.NodeNotFound( + _("Nodes cannot be found: %s") % ', '.join(missing)) + + query = model_query(models.Node.uuid, models.Node.name).filter( + sql.or_(models.Node.uuid.in_(uuids), + models.Node.name.in_(names)) + ) + for row in query: + if row[0] in idents: + mapping[row[0]] = row[0] + if row[1] and row[1] in idents: + mapping[row[1]] = row[0] + + missing = idents - set(mapping) + if missing: + raise exception.NodeNotFound( + _("Nodes cannot be found: %s") % ', '.join(missing)) + + return mapping + @oslo_db_api.retry_on_deadlock def reserve_node(self, tag, node_id): with _session_for_write(): |