X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=PLC%2FNodes.py;h=28ff8c1780f566d6a2896283155310b7204e662d;hb=8750a51bb3597aa0687e06221f21412b18004c58;hp=7a164c76cdb31b2b14d81073021bff409c43a9e0;hpb=a12987e598653f7fb2b8000d1826dab0f8e154a1;p=plcapi.git diff --git a/PLC/Nodes.py b/PLC/Nodes.py index 7a164c7..28ff8c1 100644 --- a/PLC/Nodes.py +++ b/PLC/Nodes.py @@ -5,6 +5,7 @@ # Copyright (C) 2006 The Trustees of Princeton University # # $Id$ +# $URL$ # from types import StringTypes @@ -15,8 +16,9 @@ from PLC.Parameter import Parameter, Mixed from PLC.Filter import Filter from PLC.Debug import profile from PLC.Table import Row, Table -from PLC.Interfaces import Interface, Interfaces +from PLC.NodeTypes import NodeTypes from PLC.BootStates import BootStates +from PLC.Interfaces import Interface, Interfaces def valid_hostname(hostname): # 1. Each part begins and ends with a letter or number. @@ -47,6 +49,7 @@ class Node(Row): '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), + 'run_level': Parameter(str, "Run level", max = 20), 'model': Parameter(str, "Make and model of the actual machine", max = 255, nullok = True), '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), @@ -54,6 +57,7 @@ class Node(Row): 'date_created': Parameter(int, "Date and time when node entry was created", ro = True), 'last_updated': Parameter(int, "Date and time when node entry was created", ro = True), 'last_contact': Parameter(int, "Date and time when node last contacted plc", ro = True), + 'verified': Parameter(bool, "Whether the node configuration is verified correct", ro=False), 'key': Parameter(str, "(Admin only) Node key", max = 256), 'session': Parameter(str, "(Admin only) Node session value", max = 256, ro = True), 'interface_ids': Parameter([int], "List of network interfaces that this node has"), @@ -65,30 +69,26 @@ class Node(Row): 'ports': Parameter([int], "List of PCU ports that this node is connected to"), 'peer_id': Parameter(int, "Peer to which this node belongs", nullok = True), 'peer_node_id': Parameter(int, "Foreign node identifier at peer", nullok = True), - 'tag_ids' : Parameter ([int], "List of tags attached to this node"), + 'node_tag_ids' : Parameter ([int], "List of tags attached to this node"), 'nodegroup_ids': Parameter([int], "List of node groups that this node is in"), } related_fields = { 'interfaces': [Mixed(Parameter(int, "Interface identifier"), Filter(Interface.fields))], - 'nodegroups': [Mixed(Parameter(int, "NodeGroup identifier"), - Parameter(str, "NodeGroup name"))], 'conf_files': [Parameter(int, "ConfFile identifier")], 'slices': [Mixed(Parameter(int, "Slice identifier"), Parameter(str, "Slice name"))], 'slices_whitelist': [Mixed(Parameter(int, "Slice identifier"), Parameter(str, "Slice name"))] } - view_name = "view_nodes" + view_tags_name = "view_node_tags" - tags = { - # regular - 'arch': Parameter(str, "node/config", ro=True), - 'deployment': Parameter(str, "node/operation"), - # dummynet - } + # tags are used by the Add/Get/Update methods to expose tags + # this is initialized here and updated by the accessors factory + tags = { } def validate_hostname(self, hostname): + hostname = hostname.lower() if not valid_hostname(hostname): raise PLCInvalidArgument, "Invalid hostname" @@ -99,11 +99,16 @@ class Node(Row): return hostname + def validate_node_type(self, node_type): + node_types = [row['node_type'] for row in NodeTypes(self.api)] + if node_type not in node_types: + raise PLCInvalidArgument, "Invalid node type %r"%node_type + return node_type + def validate_boot_state(self, boot_state): boot_states = [row['boot_state'] for row in BootStates(self.api)] if boot_state not in boot_states: - raise PLCInvalidArgument, "Invalid boot state" - + raise PLCInvalidArgument, "Invalid boot state %r"%boot_state return boot_state validate_date_created = Row.validate_timestamp @@ -244,11 +249,15 @@ class Node(Row): """ assert 'node_id' in self - assert 'interface_ids' in self # we need to clean up InterfaceTags, so handling interfaces as part of join_tables does not work - for interface in Interfaces(self.api,self['interface_ids']): - interface.delete() + # federated nodes don't have interfaces though so for smooth transition from 4.2 to 4.3 + if 'peer_id' in self and self['peer_id']: + pass + else: + assert 'interface_ids' in self + for interface in Interfaces(self.api,self['interface_ids']): + interface.delete() # Clean up miscellaneous join tables for table in self.join_tables: @@ -273,7 +282,8 @@ class Nodes(Table): view = "view_nodes" # as many left joins as requested tags for tagname in self.tag_columns: - view= "%s left join %s using (%s)"%(view,Node.tagvalue_view_name(tagname),Node.primary_key) + view= "%s left join %s using (%s)"%(view,Node.tagvalue_view_name(tagname), + Node.primary_key) sql = "SELECT %s FROM %s WHERE deleted IS False" % \ (", ".join(self.columns.keys()+self.tag_columns.keys()),view) @@ -286,7 +296,8 @@ class Nodes(Table): node_filter = Filter(Node.fields, {'node_id': ints, 'hostname': strs}) sql += " AND (%s) %s" % node_filter.sql(api, "OR") elif isinstance(node_filter, dict): - node_filter = Filter(Node.fields, node_filter) + allowed_fields=dict(Node.fields.items()+Node.tags.items()) + node_filter = Filter(allowed_fields, node_filter) sql += " AND (%s) %s" % node_filter.sql(api, "AND") elif isinstance (node_filter, StringTypes): node_filter = Filter(Node.fields, {'hostname':[node_filter]})