trailing spaces in sql schema
[plcapi.git] / PLC / Nodes.py
index 9cf0edf..6af9ee9 100644 (file)
@@ -4,11 +4,7 @@
 # Mark Huang <mlhuang@cs.princeton.edu>
 # Copyright (C) 2006 The Trustees of Princeton University
 #
-# $Id$
-# $URL$
-#
 
-from types import StringTypes
 import re
 
 from PLC.Faults import *
@@ -19,6 +15,7 @@ from PLC.Table import Row, Table
 from PLC.NodeTypes import NodeTypes
 from PLC.BootStates import BootStates
 from PLC.Interfaces import Interface, Interfaces
+from PLC.TagTypes import TagType, TagTypes
 
 def valid_hostname(hostname):
     # 1. Each part begins and ends with a letter or number.
@@ -57,6 +54,12 @@ 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),
+        'last_boot': Parameter(int, "Date and time when node last booted", ro = True),
+        'last_download': Parameter(int, "Date and time when node boot image was created", ro = True),
+        'last_pcu_reboot': Parameter(int, "Date and time when PCU reboot was attempted", ro = True),
+        'last_pcu_confirmation': Parameter(int, "Date and time when PCU reboot was confirmed", ro = True),
+        'last_time_spent_online': Parameter(int, "Length of time the node was last online before shutdown/failure", ro = True),
+        'last_time_spent_offline': Parameter(int, "Length of time the node was last offline after failure and before reboot", 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),
@@ -88,67 +91,82 @@ class Node(Row):
     tags = { }
 
     def validate_hostname(self, hostname):
+        hostname = hostname.lower()
         if not valid_hostname(hostname):
-            raise PLCInvalidArgument, "Invalid hostname"
+            raise PLCInvalidArgument("Invalid hostname")
 
         conflicts = Nodes(self.api, [hostname])
         for node in conflicts:
             if 'node_id' not in self or self['node_id'] != node['node_id']:
-                raise PLCInvalidArgument, "Hostname already in use"
+                raise PLCInvalidArgument("Hostname already in use")
 
         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
+            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 %r"%boot_state
+            raise PLCInvalidArgument("Invalid boot state %r"%boot_state)
         return boot_state
 
     validate_date_created = Row.validate_timestamp
     validate_last_updated = Row.validate_timestamp
     validate_last_contact = Row.validate_timestamp
+    validate_last_boot = Row.validate_timestamp
+    validate_last_download = Row.validate_timestamp
+    validate_last_pcu_reboot = Row.validate_timestamp
+    validate_last_pcu_confirmation = Row.validate_timestamp
 
-    def update_last_contact(self, commit = True):
-        """
-        Update last_contact field with current time
-        """
+    def update_readonly_int(self, col_name, commit = True):
 
         assert 'node_id' in self
         assert self.table_name
 
-        self.api.db.do("UPDATE %s SET last_contact = CURRENT_TIMESTAMP " % (self.table_name) + \
-                       " where node_id = %d" % ( self['node_id']) )
+        self.api.db.do("UPDATE %s SET %s = %s" % (self.table_name, col_name, self[col_name]) + \
+                        " where node_id = %d" % (self['node_id']) )
         self.sync(commit)
 
-
-    def update_last_updated(self, commit = True):
+    def update_timestamp(self, col_name, commit = True):
         """
-        Update last_updated field with current time
+        Update col_name field with current time
         """
 
         assert 'node_id' in self
         assert self.table_name
 
-        self.api.db.do("UPDATE %s SET last_updated = CURRENT_TIMESTAMP " % (self.table_name) + \
+        self.api.db.do("UPDATE %s SET %s = CURRENT_TIMESTAMP " % (self.table_name, col_name) + \
                        " where node_id = %d" % (self['node_id']) )
         self.sync(commit)
 
+    def update_last_boot(self, commit = True):
+        self.update_timestamp('last_boot', commit)
+    def update_last_download(self, commit = True):
+        self.update_timestamp('last_download', commit)
+    def update_last_pcu_reboot(self, commit = True):
+        self.update_timestamp('last_pcu_reboot', commit)
+    def update_last_pcu_confirmation(self, commit = True):
+        self.update_timestamp('last_pcu_confirmation', commit)
+
+    def update_last_contact(self, commit = True):
+        self.update_timestamp('last_contact', commit)
+    def update_last_updated(self, commit = True):
+        self.update_timestamp('last_updated', commit)
+
     def update_tags(self, tags):
         from PLC.Shell import Shell
         from PLC.NodeTags import NodeTags
         from PLC.Methods.AddNodeTag import AddNodeTag
         from PLC.Methods.UpdateNodeTag import UpdateNodeTag
         shell = Shell()
-        for (tagname,value) in tags.iteritems():
+        for (tagname,value) in tags.items():
             # the tagtype instance is assumed to exist, just check that
             if not TagTypes(self.api,{'tagname':tagname}):
-                raise PLCInvalidArgument,"No such TagType %s"%tagname
+                raise PLCInvalidArgument("No such TagType %s"%tagname)
             node_tags=NodeTags(self.api,{'tagname':tagname,'node_id':node['node_id']})
             if not node_tags:
                 AddNodeTag(self.api).__call__(shell.auth,node['node_id'],tagname,value)
@@ -215,7 +233,7 @@ class Node(Row):
 
         if slice_names:
             slices = Slices(self.api, slice_names, ['slice_id']).dict('slice_id')
-            slice_ids += slices.keys()
+            slice_ids += list(slices.keys())
 
         if self['slice_ids'] != slice_ids:
             from PLC.Methods.AddSliceToNodes import AddSliceToNodes
@@ -244,7 +262,7 @@ class Node(Row):
 
         if slice_names:
             slices = Slices(self.api, slice_names, ['slice_id']).dict('slice_id')
-            slice_ids += slices.keys()
+            slice_ids += list(slices.keys())
 
         if self['slice_ids_whitelist'] != slice_ids:
             from PLC.Methods.AddSliceToNodesWhitelist import AddSliceToNodesWhitelist
@@ -283,7 +301,6 @@ class Node(Row):
         self['deleted'] = True
         self.sync(commit)
 
-
 class Nodes(Table):
     """
     Representation of row(s) from the nodes table in the
@@ -301,26 +318,26 @@ class Nodes(Table):
                                                 Node.primary_key)
 
         sql = "SELECT %s FROM %s WHERE deleted IS False" % \
-              (", ".join(self.columns.keys()+self.tag_columns.keys()),view)
+              (", ".join(list(self.columns.keys())+list(self.tag_columns.keys())),view)
 
         if node_filter is not None:
             if isinstance(node_filter, (list, tuple, set)):
                 # Separate the list into integers and strings
-                ints = filter(lambda x: isinstance(x, (int, long)), node_filter)
-                strs = filter(lambda x: isinstance(x, StringTypes), node_filter)
+                ints = [x for x in node_filter if isinstance(x, int)]
+                strs = [x for x in node_filter if isinstance(x, str)]
                 node_filter = Filter(Node.fields, {'node_id': ints, 'hostname': strs})
                 sql += " AND (%s) %s" % node_filter.sql(api, "OR")
             elif isinstance(node_filter, dict):
-                allowed_fields=dict(Node.fields.items()+Node.tags.items())
+                allowed_fields=dict(list(Node.fields.items())+list(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]})
+            elif isinstance (node_filter, str):
+                node_filter = Filter(Node.fields, {'hostname':node_filter})
                 sql += " AND (%s) %s" % node_filter.sql(api, "AND")
             elif isinstance (node_filter, int):
-                node_filter = Filter(Node.fields, {'node_id':[node_filter]})
+                node_filter = Filter(Node.fields, {'node_id':node_filter})
                 sql += " AND (%s) %s" % node_filter.sql(api, "AND")
             else:
-                raise PLCInvalidArgument, "Wrong node filter %r"%node_filter
+                raise PLCInvalidArgument("Wrong node filter %r"%node_filter)
 
         self.selectall(sql)