Fix bug with application id allocation for IOU nodes. Fixes #3079

This commit is contained in:
grossmj 2020-10-27 19:41:24 +10:30
parent 362701f5aa
commit 5d1fdceb98
2 changed files with 24 additions and 9 deletions

View File

@ -174,6 +174,7 @@ class Project:
self._links = {} self._links = {}
self._drawings = {} self._drawings = {}
self._snapshots = {} self._snapshots = {}
self._computes = []
# List the available snapshots # List the available snapshots
snapshot_dir = os.path.join(self.path, "snapshots") snapshot_dir = os.path.join(self.path, "snapshots")
@ -564,6 +565,9 @@ class Project:
if node_id in self._nodes: if node_id in self._nodes:
return self._nodes[node_id] return self._nodes[node_id]
if compute.id not in self._computes:
self._computes.append(compute.id)
if node_type == "iou": if node_type == "iou":
async with self._iou_id_lock: async with self._iou_id_lock:
# wait for a IOU node to be completely created before adding a new one # wait for a IOU node to be completely created before adding a new one
@ -571,10 +575,10 @@ class Project:
# to generate MAC addresses) when creating multiple IOU node at the same time # to generate MAC addresses) when creating multiple IOU node at the same time
if "properties" in kwargs.keys(): if "properties" in kwargs.keys():
# allocate a new application id for nodes loaded from the project # allocate a new application id for nodes loaded from the project
kwargs.get("properties")["application_id"] = get_next_application_id(self._controller.projects, compute) kwargs.get("properties")["application_id"] = get_next_application_id(self._controller.projects, self._computes)
elif "application_id" not in kwargs.keys() and not kwargs.get("properties"): elif "application_id" not in kwargs.keys() and not kwargs.get("properties"):
# allocate a new application id for nodes added to the project # allocate a new application id for nodes added to the project
kwargs["application_id"] = get_next_application_id(self._controller.projects, compute) kwargs["application_id"] = get_next_application_id(self._controller.projects, self._computes)
node = await self._create_node(compute, name, node_id, node_type, **kwargs) node = await self._create_node(compute, name, node_id, node_type, **kwargs)
else: else:
node = await self._create_node(compute, name, node_id, node_type, **kwargs) node = await self._create_node(compute, name, node_id, node_type, **kwargs)
@ -604,6 +608,8 @@ class Project:
self.remove_allocated_node_name(node.name) self.remove_allocated_node_name(node.name)
del self._nodes[node.id] del self._nodes[node.id]
await node.destroy() await node.destroy()
# refresh the compute IDs list
self._computes = [n.compute.id for n in self.nodes.values()]
self.dump() self.dump()
self.emit_notification("node.deleted", node.__json__()) self.emit_notification("node.deleted", node.__json__())
@ -931,6 +937,14 @@ class Project:
topology = project_data["topology"] topology = project_data["topology"]
for compute in topology.get("computes", []): for compute in topology.get("computes", []):
await self.controller.add_compute(**compute) await self.controller.add_compute(**compute)
# Get all compute used in the project
# used to allocate application IDs for IOU nodes.
for node in topology.get("nodes", []):
compute_id = node.get("compute_id")
if compute_id not in self._computes:
self._computes.append(compute_id)
for node in topology.get("nodes", []): for node in topology.get("nodes", []):
compute = self.controller.get_compute(node.pop("compute_id")) compute = self.controller.get_compute(node.pop("compute_id"))
name = node.pop("name") name = node.pop("name")

View File

@ -21,26 +21,27 @@ import logging
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
def get_next_application_id(projects, compute): def get_next_application_id(projects, computes):
""" """
Calculates free application_id from given nodes Calculates free application_id from given nodes
:param projects: all projects managed by controller :param projects: all projects managed by controller
:param compute: Compute instance :param computes: all computes used by the project
:raises HTTPConflict when exceeds number :raises HTTPConflict when exceeds number
:return: integer first free id :return: integer first free id
""" """
nodes = [] nodes = []
# look for application id for in all nodes across all opened projects that share the same compute # look for application id for in all nodes across all opened projects that share the same computes
for project in projects.values(): for project in projects.values():
if project.status == "opened" and compute in project.computes: if project.status == "opened":
nodes.extend(list(project.nodes.values())) nodes.extend(list(project.nodes.values()))
used = set([n.properties["application_id"] for n in nodes if n.node_type == "iou"]) used = set([n.properties["application_id"] for n in nodes if n.node_type == "iou" and n.compute.id in computes])
pool = set(range(1, 512)) pool = set(range(1, 512))
try: try:
return (pool - used).pop() application_id = (pool - used).pop()
return application_id
except KeyError: except KeyError:
raise aiohttp.web.HTTPConflict(text="Cannot create a new IOU node (limit of 512 nodes across all opened projects using compute {} reached".format(compute.name)) raise aiohttp.web.HTTPConflict(text="Cannot create a new IOU node (limit of 512 nodes across all opened projects using the same computes)")