From 32ed8ac14d6673307ace81c452271d3e8f552d2f Mon Sep 17 00:00:00 2001 From: Mark Huang Date: Mon, 25 Sep 2006 15:00:55 +0000 Subject: [PATCH] - support new schema - use new table views instead of defining join_fields, extra_fields, and all_fields - rename flush() to sync() to be like shelve - remove support for returning primary node_network information --- PLC/Nodes.py | 142 ++++++++++----------------------------------------- 1 file changed, 27 insertions(+), 115 deletions(-) diff --git a/PLC/Nodes.py b/PLC/Nodes.py index 2fbda71..fd20c2d 100644 --- a/PLC/Nodes.py +++ b/PLC/Nodes.py @@ -4,7 +4,7 @@ # Mark Huang # Copyright (C) 2006 The Trustees of Princeton University # -# $Id: Nodes.py,v 1.2 2006/09/08 19:44:51 mlhuang Exp $ +# $Id: Nodes.py,v 1.3 2006/09/19 19:28:39 mlhuang Exp $ # from types import StringTypes @@ -21,51 +21,31 @@ class Node(Row): """ Representation of a row in the nodes table. To use, optionally instantiate with a dict of values. Update as you would a - dict. Commit to the database with flush(). + dict. Commit to the database with sync(). """ fields = { 'node_id': Parameter(int, "Node identifier"), 'hostname': Parameter(str, "Fully qualified hostname", max = 255), + 'site_id': Parameter(int, "Site at which this node is located"), 'boot_state': Parameter(str, "Boot state", max = 20), 'model': Parameter(str, "Make and model of the actual machine", max = 255), 'boot_nonce': Parameter(str, "(Admin only) Random value generated by the node at last boot", max = 128), 'version': Parameter(str, "Apparent Boot CD version", max = 64), 'ssh_rsa_key': Parameter(str, "Last known SSH host key", max = 1024), 'date_created': Parameter(str, "Date and time when node entry was created"), + 'last_updated': Parameter(str, "Date and time when node entry was created"), 'deleted': Parameter(bool, "Has been deleted"), 'key': Parameter(str, "(Admin only) Node key", max = 256), 'session': Parameter(str, "(Admin only) Node session value", max = 256), - } - - # These fields are derived from join tables and are not actually - # in the nodes table. - join_fields = { 'nodenetwork_ids': Parameter([int], "List of network interfaces that this node has"), - } - - # These fields are derived from join tables and are not returned - # by default unless specified. - extra_fields = { 'nodegroup_ids': Parameter([int], "List of node groups that this node is in"), - 'conf_file_ids': Parameter([int], "List of configuration files specific to this node"), - 'root_person_ids': Parameter([int], "(Admin only) List of people who have root access to this node"), - # XXX Too inefficient + # 'conf_file_ids': Parameter([int], "List of configuration files specific to this node"), + # 'root_person_ids': Parameter([int], "(Admin only) List of people who have root access to this node"), # 'slice_ids': Parameter([int], "List of slices on this node"), - 'pcu_ids': Parameter([int], "List of PCUs that control this node"), - 'site_id': Parameter([int], "Site at which this node is located"), + # 'pcu_ids': Parameter([int], "List of PCUs that control this node"), } - # Primary interface values - primary_nodenetwork_fields = dict(filter(lambda (key, value): \ - key not in ['node_id', 'is_primary', 'hostname'], - NodeNetwork.fields.items())) - - extra_fields.update(primary_nodenetwork_fields) - - default_fields = dict(fields.items() + join_fields.items()) - all_fields = dict(default_fields.items() + extra_fields.items()) - def __init__(self, api, fields): Row.__init__(self, fields) self.api = api @@ -113,7 +93,7 @@ class Node(Row): nodenetwork_id = nodenetwork['nodenetwork_id'] nodenetwork['node_id'] = self['node_id'] - self.api.db.do("INSERT INTO node_nodenetworks (node_id, nodenetwork_id, is_primary)" \ + self.api.db.do("INSERT INTO node_nodenetwork (node_id, nodenetwork_id, is_primary)" \ " VALUES(%(node_id)d, %(nodenetwork_id)d, False)", nodenetwork) @@ -135,11 +115,11 @@ class Node(Row): node_id = self['node_id'] nodenetwork_id = nodenetwork['nodenetwork_id'] - self.api.db.do("UPDATE node_nodenetworks SET is_primary = False" \ + self.api.db.do("UPDATE node_nodenetwork SET is_primary = False" \ " WHERE node_id = %(node_id)d", locals()) - self.api.db.do("UPDATE node_nodenetworks SET is_primary = True" \ + self.api.db.do("UPDATE node_nodenetwork SET is_primary = True" \ " WHERE node_id = %(node_id)d" \ " AND nodenetwork_id = %(nodenetwork_id)d", locals()) @@ -149,7 +129,7 @@ class Node(Row): nodenetwork['is_primary'] = True - def flush(self, commit = True): + def sync(self, commit = True): """ Flush changes back to the database. """ @@ -167,7 +147,8 @@ class Node(Row): insert = False # Filter out fields that cannot be set or updated directly - fields = dict(filter(lambda (key, value): key in self.fields, + nodes_fields = self.api.db.fields('nodes') + fields = dict(filter(lambda (key, value): key in nodes_fields, self.items())) # Parameterize for safety @@ -203,16 +184,14 @@ class Node(Row): nodenetwork.delete(commit = False) # Clean up miscellaneous join tables - for table in ['nodegroup_nodes', 'pod_hash', 'conf_assoc', - 'node_root_access', 'dslice03_slicenode', - 'pcu_ports']: + for table in ['nodegroup_node']: self.api.db.do("DELETE FROM %s" \ " WHERE node_id = %d" % \ (table, self['node_id'])) # Mark as deleted self['deleted'] = True - self.flush(commit) + self.sync(commit) class Nodes(Table): """ @@ -220,43 +199,11 @@ class Nodes(Table): database. """ - def __init__(self, api, node_id_or_hostname_list = None, extra_fields = []): + def __init__(self, api, node_id_or_hostname_list = None, fields = Node.fields.keys()): self.api = api - sql = "SELECT nodes.*, node_nodenetworks.nodenetwork_id" - - # For compatibility and convenience, support returning primary - # interface values directly in the Node structure. - extra_nodenetwork_fields = set(extra_fields).intersection(Node.primary_nodenetwork_fields) - - # N.B.: Joined IDs may be marked as deleted in their primary tables - join_tables = { - # extra_field: (extra_table, extra_column, join_using) - 'nodegroup_ids': ('nodegroup_nodes', 'nodegroup_id', 'node_id'), - 'conf_file_ids': ('conf_assoc', 'conf_file_id', 'node_id'), - 'root_person_ids': ('node_root_access', 'person_id AS root_person_id', 'node_id'), - 'slice_ids': ('dslice03_slicenode', 'slice_id', 'node_id'), - 'pcu_ids': ('pcu_ports', 'pcu_id', 'node_id'), - } - - extra_fields = filter(join_tables.has_key, extra_fields) - extra_tables = ["%s USING (%s)" % \ - (join_tables[field][0], join_tables[field][2]) \ - for field in extra_fields] - extra_columns = ["%s.%s" % \ - (join_tables[field][0], join_tables[field][1]) \ - for field in extra_fields] - - if extra_columns: - sql += ", " + ", ".join(extra_columns) - - sql += " FROM nodes" \ - " LEFT JOIN node_nodenetworks USING (node_id)" - - if extra_tables: - sql += " LEFT JOIN " + " LEFT JOIN ".join(extra_tables) - - sql += " WHERE deleted IS False" + sql = "SELECT %s FROM view_nodes WHERE deleted IS False" % \ + ", ".join(fields) if node_id_or_hostname_list: # Separate the list into integers and strings @@ -271,49 +218,14 @@ class Nodes(Table): sql += " OR hostname IN (%s)" % ", ".join(api.db.quote(hostnames)).lower() sql += ")" - # So that if the node has a primary interface, it is listed - # first. - if 'nodenetwork_ids' in extra_fields: - sql += " ORDER BY node_nodenetworks.is_primary DESC" - rows = self.api.db.selectall(sql) + for row in rows: - if self.has_key(row['node_id']): - node = self[row['node_id']] - node.update(row) - else: - self[row['node_id']] = Node(api, row) - - # XXX Should instead have a site_node join table that is - # magically taken care of above. - if rows: - sql = "SELECT node_id, sites.site_id FROM nodegroup_nodes" \ - " INNER JOIN sites USING (nodegroup_id)" \ - " WHERE node_id IN (%s)" % ", ".join(map(str, self.keys())) - - rows = self.api.db.selectall(sql, self) - for row in rows: - assert self.has_key(row['node_id']) - node = self[row['node_id']] - node.update(row) - - # Fill in optional primary interface fields for each node - if extra_nodenetwork_fields: - # More efficient to get all the nodenetworks at once - nodenetwork_ids = [] - for node in self.values(): - nodenetwork_ids += node['nodenetwork_ids'] - - # Remove duplicates - nodenetwork_ids = set(nodenetwork_ids) - - # Get all nodenetwork information - nodenetworks = NodeNetworks(self.api, nodenetwork_ids) - - for node in self.values(): - for nodenetwork_id in node['nodenetwork_ids']: - nodenetwork = nodenetworks[nodenetwork_id] - if nodenetwork['is_primary']: - for field in extra_nodenetwork_fields: - node[field] = nodenetwork[field] - break + self[row['node_id']] = node = Node(api, row) + for aggregate in ['nodenetwork_ids', 'nodegroup_ids', + 'conf_file_ids', 'root_person_ids', 'slice_ids', + 'pcu_ids']: + if not node.has_key(aggregate) or node[aggregate] is None: + node[aggregate] = [] + else: + node[aggregate] = map(int, node[aggregate].split(',')) -- 2.43.0