Merge branch 'master' of ssh://git.onelab.eu/git/plcapi
authorThierry Parmentelat <thierry.parmentelat@sophia.inria.fr>
Tue, 7 Jun 2011 12:00:53 +0000 (14:00 +0200)
committerThierry Parmentelat <thierry.parmentelat@sophia.inria.fr>
Tue, 7 Jun 2011 12:00:53 +0000 (14:00 +0200)
PLC/Methods/BootUpdateNode.py
PLC/Methods/GetPersons.py
PLC/Methods/GetSliceTags.py
PLC/Methods/GetSlices.py
PLC/Methods/UpdateNode.py
PLC/Nodes.py
PLC/Persons.py
migrations/105-down-timespent.sql [new file with mode: 0644]
migrations/105-up-timespent.sql [new file with mode: 0644]

index 4e81845..06bdd78 100644 (file)
@@ -83,14 +83,30 @@ class BootUpdateNode(Method):
             interface.update(interface_fields)
             interface.sync(commit = False)
 
-        # indicate that node has booted & contacted PLC.
-        node.update_last_contact()
-        node.update_last_boot()
-
         current_time = int(time.time())
-        # if last_pcu_reboot is within 20 minutes of current_time, accept that the PCU is responsible
-        if node['last_pcu_reboot'] and Timestamp.cast_long(node['last_pcu_reboot']) >= current_time - 60*20:
-            node.update_last_pcu_confirmation(commit=False)
+
+        # ONLY UPDATE ONCE when the boot_state flag and ssh_rsa_key flag are NOT passed
+        if not node_fields.has_key('boot_state') and not node_fields.has_key('ssh_rsa_key'):
+
+            # record times spent on and off line by comparing last_contact with previous value of last_boot
+            if node['last_boot'] and node['last_contact']:
+                # last_boot is when the machine last called this API function.
+                # last_contact is the last time NM or RLA pinged the API.
+                node['last_time_spent_online'] = node['last_contact'] - node['last_boot']
+                node['last_time_spent_offline'] = current_time - Timestamp.cast_long(node['last_contact'])
+
+                node.update_readonly_int('last_time_spent_online')
+                node.update_readonly_int('last_time_spent_offline')
+                changed_fields.append('last_time_spent_online')
+                changed_fields.append('last_time_spent_offline')
+
+            # indicate that node has booted & contacted PLC.
+            node.update_last_contact()
+            node.update_last_boot()
+
+            # if last_pcu_reboot is within 20 minutes of current_time, accept that the PCU is responsible
+            if node['last_pcu_reboot'] and Timestamp.cast_long(node['last_pcu_reboot']) >= current_time - 60*20:
+                node.update_last_pcu_confirmation(commit=False)
 
         node.sync(commit = True)
 
index 9439420..06da9f5 100644 (file)
@@ -44,11 +44,11 @@ class GetPersons(Method):
            'admin' not in self.caller['roles']:
             # Get accounts that we are able to view
             valid_person_ids = [self.caller['person_id']]
-            if 'pi' in self.caller['roles'] and self.caller['site_ids']:
+            if ('pi' in self.caller['roles'] or 'tech' in self.caller['roles']) \
+               and self.caller['site_ids']:
                 sites = Sites(self.api, self.caller['site_ids'])
                 for site in sites:
                     valid_person_ids += site['person_ids']
-
             if not valid_person_ids:
                 return []
 
index 45a445f..bed5b6e 100644 (file)
@@ -7,6 +7,7 @@ from PLC.Filter import Filter
 from PLC.SliceTags import SliceTag, SliceTags
 from PLC.Persons import Person, Persons
 from PLC.Sites import Site, Sites
+from PLC.Nodes import Nodes
 from PLC.Slices import Slice, Slices
 from PLC.Auth import Auth
 
@@ -49,6 +50,11 @@ class GetSliceTags(Method):
                 sites = Sites(self.api, self.caller['site_ids'])
                 for site in sites:
                     valid_slice_ids += site['slice_ids']
+            # techs can view all slices on the nodes at their site
+            if 'tech' in self.caller['roles'] and self.caller['site_ids']:
+                nodes = Nodes(self.api, {'site_id': self.caller['site_ids']}, ['site_id', 'slice_ids'])
+                for node in nodes:
+                    valid_slice_ids.extend(node['slice_ids'])
 
             if not valid_slice_ids:
                 return []
index 22e5e1e..15ebd5c 100644 (file)
@@ -5,6 +5,7 @@ from PLC.Parameter import Parameter, Mixed
 from PLC.Filter import Filter
 from PLC.Auth import Auth
 from PLC.Persons import Person, Persons
+from PLC.Nodes import Nodes
 from PLC.Sites import Site, Sites
 from PLC.Slices import Slice, Slices
 
@@ -43,10 +44,16 @@ class GetSlices(Method):
            'admin' not in self.caller['roles']:
             # Get slices that we are able to view
             valid_slice_ids = self.caller['slice_ids']
+            # pis can view all slices at their site
             if 'pi' in self.caller['roles'] and self.caller['site_ids']:
                 sites = Sites(self.api, self.caller['site_ids'])
                 for site in sites:
                     valid_slice_ids += site['slice_ids']
+            # techs can view all slices on the nodes at their site
+            if 'tech' in self.caller['roles'] and self.caller['site_ids']:
+                nodes = Nodes(self.api, {'site_id': self.caller['site_ids']}, ['site_id', 'slice_ids'])
+                for node in nodes:
+                    valid_slice_ids.extend(node['slice_ids'])
 
             if not valid_slice_ids:
                 return []
index 2927f73..9f94d0a 100644 (file)
@@ -98,8 +98,10 @@ class UpdateNode(Method):
 
         for (tagname,value) in tags.iteritems():
             # the tagtype instance is assumed to exist, just check that
-            if not TagTypes(self.api,{'tagname':tagname}):
+            tag_types = TagTypes(self.api,{'tagname':tagname})
+            if not tag_types:
                 raise PLCInvalidArgument,"No such TagType %s"%tagname
+            tag_type = tag_types[0]
             node_tags=NodeTags(self.api,{'tagname':tagname,'node_id':node['node_id']})
             if not node_tags:
                 node_tag = NodeTag(self.api)
index a7e2988..87789ea 100644 (file)
@@ -58,6 +58,8 @@ class Node(Row):
         '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),
@@ -120,6 +122,15 @@ class Node(Row):
     validate_last_pcu_reboot = Row.validate_timestamp
     validate_last_pcu_confirmation = Row.validate_timestamp
 
+    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 %s = %s" % (self.table_name, col_name, self[col_name]) + \
+                        " where node_id = %d" % (self['node_id']) )
+        self.sync(commit)
+
     def update_timestamp(self, col_name, commit = True):
         """
         Update col_name field with current time
index 060a46f..d5f1533 100644 (file)
@@ -155,7 +155,7 @@ class Person(Row):
 
         1. We are the person.
         2. We are an admin.
-        3. We are a PI and the person is at one of our sites.
+        3. We are a PI or Tech and the person is at one of our sites.
         """
 
         assert isinstance(person, Person)
@@ -163,7 +163,7 @@ class Person(Row):
         if self.can_update(person):
             return True
 
-        if 'pi' in self['roles']:
+        if 'pi' in self['roles'] or 'tech' in self['roles']:
             if set(self['site_ids']).intersection(person['site_ids']):
                 # Can view people with equal or higher role IDs
                 return 'admin' not in person['roles']
diff --git a/migrations/105-down-timespent.sql b/migrations/105-down-timespent.sql
new file mode 100644 (file)
index 0000000..d2d1f2c
--- /dev/null
@@ -0,0 +1,60 @@
+ALTER TABLE nodes DROP COLUMN last_time_spent_online CASCADE;
+ALTER TABLE nodes DROP COLUMN last_time_spent_offline CASCADE;
+
+DROP VIEW view_nodes;
+CREATE OR REPLACE VIEW view_nodes AS
+SELECT
+nodes.node_id,
+nodes.node_type,
+nodes.hostname,
+nodes.site_id,
+nodes.boot_state,
+nodes.run_level,
+nodes.deleted,
+nodes.model,
+nodes.boot_nonce,
+nodes.version,
+nodes.verified,
+nodes.ssh_rsa_key,
+nodes.key,
+CAST(date_part('epoch', nodes.date_created) AS bigint) AS date_created,
+CAST(date_part('epoch', nodes.last_updated) AS bigint) AS last_updated,
+CAST(date_part('epoch', nodes.last_contact) AS bigint) AS last_contact,  
+CAST(date_part('epoch', nodes.last_boot) AS bigint) AS last_boot,  
+CAST(date_part('epoch', nodes.last_download) AS bigint) AS last_download,  
+CAST(date_part('epoch', nodes.last_pcu_reboot) AS bigint) AS last_pcu_reboot,  
+CAST(date_part('epoch', nodes.last_pcu_confirmation) AS bigint) AS last_pcu_confirmation,  
+peer_node.peer_id,
+peer_node.peer_node_id,
+COALESCE((SELECT interface_ids FROM node_interfaces 
+                WHERE node_interfaces.node_id = nodes.node_id), '{}') 
+AS interface_ids,
+COALESCE((SELECT nodegroup_ids FROM node_nodegroups 
+                WHERE node_nodegroups.node_id = nodes.node_id), '{}') 
+AS nodegroup_ids,
+COALESCE((SELECT slice_ids FROM node_slices 
+                WHERE node_slices.node_id = nodes.node_id), '{}') 
+AS slice_ids,
+COALESCE((SELECT slice_ids_whitelist FROM node_slices_whitelist 
+                WHERE node_slices_whitelist.node_id = nodes.node_id), '{}') 
+AS slice_ids_whitelist,
+COALESCE((SELECT pcu_ids FROM node_pcus 
+                WHERE node_pcus.node_id = nodes.node_id), '{}') 
+AS pcu_ids,
+COALESCE((SELECT ports FROM node_pcus
+                WHERE node_pcus.node_id = nodes.node_id), '{}') 
+AS ports,
+COALESCE((SELECT conf_file_ids FROM node_conf_files
+                WHERE node_conf_files.node_id = nodes.node_id), '{}') 
+AS conf_file_ids,
+COALESCE((SELECT node_tag_ids FROM node_tags 
+                WHERE node_tags.node_id = nodes.node_id), '{}') 
+AS node_tag_ids,
+node_session.session_id AS session
+FROM nodes
+LEFT JOIN peer_node USING (node_id)
+LEFT JOIN node_session USING (node_id);
+
+--------------------------------------------------------------------------------
+
+UPDATE plc_db_version SET subversion = 104;
diff --git a/migrations/105-up-timespent.sql b/migrations/105-up-timespent.sql
new file mode 100644 (file)
index 0000000..2dbdfb9
--- /dev/null
@@ -0,0 +1,62 @@
+ALTER TABLE nodes ADD COLUMN last_time_spent_online integer;
+ALTER TABLE nodes ADD COLUMN last_time_spent_offline integer;
+
+DROP VIEW view_nodes;
+CREATE OR REPLACE VIEW view_nodes AS
+SELECT
+nodes.node_id,
+nodes.node_type,
+nodes.hostname,
+nodes.site_id,
+nodes.boot_state,
+nodes.run_level,
+nodes.deleted,
+nodes.model,
+nodes.boot_nonce,
+nodes.version,
+nodes.verified,
+nodes.ssh_rsa_key,
+nodes.key,
+CAST(date_part('epoch', nodes.date_created) AS bigint) AS date_created,
+CAST(date_part('epoch', nodes.last_updated) AS bigint) AS last_updated,
+CAST(date_part('epoch', nodes.last_contact) AS bigint) AS last_contact,  
+CAST(date_part('epoch', nodes.last_boot) AS bigint) AS last_boot,  
+CAST(date_part('epoch', nodes.last_download) AS bigint) AS last_download,  
+CAST(date_part('epoch', nodes.last_pcu_reboot) AS bigint) AS last_pcu_reboot,  
+CAST(date_part('epoch', nodes.last_pcu_confirmation) AS bigint) AS last_pcu_confirmation,  
+nodes.last_time_spent_online,
+nodes.last_time_spent_offline,
+peer_node.peer_id,
+peer_node.peer_node_id,
+COALESCE((SELECT interface_ids FROM node_interfaces 
+                WHERE node_interfaces.node_id = nodes.node_id), '{}') 
+AS interface_ids,
+COALESCE((SELECT nodegroup_ids FROM node_nodegroups 
+                WHERE node_nodegroups.node_id = nodes.node_id), '{}') 
+AS nodegroup_ids,
+COALESCE((SELECT slice_ids FROM node_slices 
+                WHERE node_slices.node_id = nodes.node_id), '{}') 
+AS slice_ids,
+COALESCE((SELECT slice_ids_whitelist FROM node_slices_whitelist 
+                WHERE node_slices_whitelist.node_id = nodes.node_id), '{}') 
+AS slice_ids_whitelist,
+COALESCE((SELECT pcu_ids FROM node_pcus 
+                WHERE node_pcus.node_id = nodes.node_id), '{}') 
+AS pcu_ids,
+COALESCE((SELECT ports FROM node_pcus
+                WHERE node_pcus.node_id = nodes.node_id), '{}') 
+AS ports,
+COALESCE((SELECT conf_file_ids FROM node_conf_files
+                WHERE node_conf_files.node_id = nodes.node_id), '{}') 
+AS conf_file_ids,
+COALESCE((SELECT node_tag_ids FROM node_tags 
+                WHERE node_tags.node_id = nodes.node_id), '{}') 
+AS node_tag_ids,
+node_session.session_id AS session
+FROM nodes
+LEFT JOIN peer_node USING (node_id)
+LEFT JOIN node_session USING (node_id);
+
+--------------------------------------------------------------------------------
+
+UPDATE plc_db_version SET subversion = 105;