(*) Peer has new fields person_ids and site_ids
[plcapi.git] / PLC / Methods / GetSlivers.py
index 11db475..060169f 100644 (file)
@@ -3,21 +3,25 @@ import time
 from PLC.Faults import *
 from PLC.Method import Method
 from PLC.Parameter import Parameter, Mixed
+from PLC.Filter import Filter
 from PLC.Auth import Auth
 from PLC.Nodes import Node, Nodes
 from PLC.NodeNetworks import NodeNetwork, NodeNetworks
 from PLC.NodeGroups import NodeGroup, NodeGroups
 from PLC.ConfFiles import ConfFile, ConfFiles
 from PLC.Slices import Slice, Slices
+#from PLC.ForeignSlices import ForeignSlice, ForeignSlices
 from PLC.Persons import Person, Persons
 from PLC.Keys import Key, Keys
 from PLC.SliceAttributes import SliceAttribute, SliceAttributes
 
 class GetSlivers(Method):
     """
-    Returns an array of structs representing slivers (slices bound to
-    nodes). If node_id_or_hostname_list is specified, only slivers
-    bound to the specified nodes are queried.
+    Returns an array of structs representing nodes and their slivers
+    (slices bound to nodes). If node_filter is specified, only
+    information about the specified nodes will be returned. If
+    node_filter is not specified and called by a node, only
+    information about the caller will be returned.
 
     All of the information returned by this call can be gathered from
     other calls, e.g. GetNodes, GetNodeNetworks, GetSlices, etc. This
@@ -25,19 +29,19 @@ class GetSlivers(Method):
     Federation Manager.
     """
 
-    roles = ['admin']
+    roles = ['admin', 'node']
 
     accepts = [
         Auth(),
-        [Mixed(Node.fields['node_id'],
-               Node.fields['hostname'])]
+        Mixed([Mixed(Node.fields['node_id'],
+                     Node.fields['hostname'])],
+              Filter(Node.fields)),
         ]
 
     returns = [{
         'timestamp': Parameter(int, "Timestamp of this call, in seconds since UNIX epoch"),
         'node_id': Node.fields['node_id'],
         'hostname': Node.fields['hostname'],
-        'boot_state': Node.fields['boot_state'],
         'networks': [NodeNetwork.fields],
         'groups': [NodeGroup.fields['name']],
         'conf_files': [ConfFile.fields],
@@ -57,104 +61,136 @@ class GetSlivers(Method):
         }]
     }]
 
-    def call(self, auth, node_id_or_hostname_list = None):
-        timestamp = int(time.time())
 
-        all_nodes = Nodes(self.api, node_id_or_hostname_list)
+    def call(self, auth, node_filter = None):
+        timestamp = int(time.time())
 
-        nodenetwork_ids = set()
-        nodegroup_ids = set()
-        conf_file_ids = set()
-        slice_ids = set()
+        if node_filter is None and isinstance(self.caller, Node):
+            all_nodes = {self.caller['node_id']: self.caller}
+        else:
+            all_nodes = Nodes(self.api, node_filter).dict()
+
+        # Get local default slices
+        system_slice_attributes = SliceAttributes(self.api, {'name': 'system', 'value': '1', 'peer_id': None}).dict()
+        system_slice_ids = [slice_attribute['slice_id'] for slice_attribute in system_slice_attributes.values()]
+        system_slice_ids = dict.fromkeys(system_slice_ids)
+       
+        all_nodenetwork_ids = set()
+        all_nodegroup_ids = set()
+        all_slice_ids = set(system_slice_ids.keys())
         for node_id, node in all_nodes.iteritems():
-            nodenetwork_ids.update(node['nodenetwork_ids'])
-            nodegroup_ids.update(node['nodegroup_ids'])
-            conf_file_ids.update(node['conf_file_ids'])
-            slice_ids.update(node['slice_ids'])
-
+            all_nodenetwork_ids.update(node['nodenetwork_ids'])
+            all_nodegroup_ids.update(node['nodegroup_ids'])
+            all_slice_ids.update(node['slice_ids'])
+       
         # Get nodenetwork information
-        if nodenetwork_ids:
-            all_nodenetworks = NodeNetworks(self.api, nodenetwork_ids)
-        else:
-            all_nodenetworks = {}
+        all_nodenetworks = NodeNetworks(self.api, all_nodenetwork_ids).dict()
 
         # Get node group information
-        if nodegroup_ids:
-            all_nodegroups = NodeGroups(self.api, nodegroup_ids)
-
-            for nodegroup_id, nodegroup in all_nodegroups.iteritems():
-                conf_file_ids.update(nodegroup['conf_file_ids'])
-        else:
-            all_nodegroups = {}
+        all_nodegroups = NodeGroups(self.api, all_nodegroup_ids).dict()
 
-        # Get configuration files
-        if conf_file_ids:
-            all_conf_files = ConfFiles(self.api, conf_file_ids)
-        else:
-            all_conf_files = {}
+        # Get (enabled) configuration files
+        all_conf_files = ConfFiles(self.api, {'enabled': True}).dict()
 
-        if slice_ids:
-            # Get slices
-            all_slices = Slices(self.api, slice_ids)
+        # Get slice information
+        all_slices = Slices(self.api, all_slice_ids).dict()
 
-            person_ids = set()
-            slice_attribute_ids = set()
-            for slice_id, slice in all_slices.iteritems():
+        person_ids = set()
+        slice_attribute_ids = set()
+        for slice_id, slice in all_slices.iteritems():
+            ### still missing in foreign slices
+            if slice.get('person_ids'):
                 person_ids.update(slice['person_ids'])
+            ### still missing in foreign slices
+            if slice.get('slice_attribute_ids'):
                 slice_attribute_ids.update(slice['slice_attribute_ids'])
 
-            # Get user accounts
-            all_persons = Persons(self.api, person_ids)
+       # Get user information
+        all_persons = Persons(self.api, person_ids).dict()
 
-            key_ids = set()
-            for person_id, person in all_persons.iteritems():
-                key_ids.update(person['key_ids'])
+        key_ids = set()
+        for person_id, person in all_persons.iteritems():
+            key_ids.update(person['key_ids'])
 
-            # Get user account keys
-            all_keys = Keys(self.api, key_ids)
+        # Get user account keys
+        all_keys = Keys(self.api, key_ids).dict()
 
-            # Get slice attributes
-            all_slice_attributes = SliceAttributes(self.api, slice_attribute_ids)
-
-        nodes = []
+        # Get slice attributes
+        all_slice_attributes = SliceAttributes(self.api, slice_attribute_ids).dict()
+        
+       nodes = []
         for node_id, node in all_nodes.iteritems():
-            networks = [all_nodenetworks[nodenetwork_id] for nodenetwork_id in node['nodenetwork_ids']]
+           networks = [all_nodenetworks[nodenetwork_id] for nodenetwork_id in node['nodenetwork_ids']]
             nodegroups = [all_nodegroups[nodegroup_id] for nodegroup_id in node['nodegroup_ids']]
             groups = [nodegroup['name'] for nodegroup in nodegroups]
 
-            # If a node belongs to multiple node
+            # If multiple entries for the same global configuration
+            # file exist, it is undefined which one takes precedence.
+            conf_files = {}
+            for conf_file in all_conf_files.values():
+                if not conf_file['node_ids'] and not conf_file['nodegroup_ids']:
+                    conf_files[conf_file['dest']] = conf_file
+            
+           # If a node belongs to multiple node
             # groups for which the same configuration file is defined,
             # it is undefined which one takes precedence.
-            conf_files = {}
             for nodegroup in nodegroups:
-                for conf_file in map(lambda id: all_conf_files[id], nodegroup['conf_file_ids']):
-                    conf_files[conf_file['dest']] = conf_file
-
-            # Node configuration files always take precedence over
+                for conf_file_id in nodegroup['conf_file_ids']:
+                    if conf_file_id in all_conf_files:
+                        conf_files[conf_file['dest']] = all_conf_files[conf_file_id]
+            
+           # Node configuration files always take precedence over
             # node group configuration files.
-            for conf_file in map(lambda id: all_conf_files[id], node['conf_file_ids']):
-                conf_files[conf_file['dest']] = conf_file
-
-            slivers = []
-            for slice in map(lambda id: all_slices[id], node['slice_ids']):
+            for conf_file_id in node['conf_file_ids']:
+                if conf_file_id in all_conf_files:
+                    conf_files[conf_file['dest']] = all_conf_files[conf_file_id]
+            
+           # filter out any slices in this nodes slice_id list that may be invalid
+            # (i.e. expired slices)
+            slice_ids = dict.fromkeys(filter(lambda slice_id: slice_id in all_slice_ids, node['slice_ids']))
+           
+           # If not a foreign node, add all of our default system
+            # slices to it.
+            if node['peer_id'] is None:
+               slice_ids.update(system_slice_ids)
+
+            slivers = [] 
+           
+           for slice in map(lambda id: all_slices[id], slice_ids.keys()):
                 keys = []
-                for person in map(lambda id: all_persons[id], slice['person_ids']):
-                    keys += [{'key_type': all_keys[key_id]['key_type'],
-                              'key': all_keys[key_id]['key']} \
-                             for key_id in person['key_ids']]
-
-                attributes = {}
-                for slice_attribute in map(lambda id: all_slice_attributes[id],
-                                           slice['slice_attribute_ids']):
-                    # Per-node sliver attributes (slice attributes
-                    # with non-null node_id fields) take precedence
-                    # over global slice attributes.
-                    if not attributes.has_key(slice_attribute['name']) or \
-                       slice_attribute['node_id'] is not None:
-                        attributes[slice_attribute['name']] = {
-                            'name': slice_attribute['name'],
-                            'value': slice_attribute['value']
-                            }
+                ### still missing in foreign slices
+                try:
+                    for person in map(lambda id: all_persons[id], slice['person_ids']):
+                        keys += [{'key_type': all_keys[key_id]['key_type'],
+                                  'key': all_keys[key_id]['key']} \
+                                 for key_id in person['key_ids']]
+                except:
+                    keys += [{'key_type':'missing',
+                              'key':'key caching not implemented yet'}]
+
+                sliver_attributes = []
+                attributes = []
+                ### still missing in foreign slices
+                try:
+                    slice_attributes = map(lambda id: all_slice_attributes[id],
+                                           slice['slice_attribute_ids'])
+
+                    # Per-node sliver attributes take precedence over
+                    # global slice attributes, so set them first.
+                    for sliver_attribute in filter(lambda a: a['node_id'] == node_id, slice_attributes):
+                        sliver_attributes.append(sliver_attribute['name'])
+                        attributes.append({'name': sliver_attribute['name'],
+                                           'value': sliver_attribute['value']})
+
+                    for slice_attribute in filter(lambda a: a['node_id'] is None, slice_attributes):
+                        # Do not set any global slice attributes for
+                        # which there is at least one sliver attribute
+                        # already set.
+                        if slice_attribute['name'] not in sliver_attributes:
+                            attributes.append({'name': slice_attribute['name'],
+                                               'value': slice_attribute['value']})
+                except Exception, err:
+                    attributes=[{'name':'attributes caching','value':'not implemented yet'}]
 
                 slivers.append({
                     'name': slice['name'],
@@ -162,9 +198,9 @@ class GetSlivers(Method):
                     'instantiation': slice['instantiation'],
                     'expires': slice['expires'],
                     'keys': keys,
-                    'attributes': attributes.values()
+                    'attributes': attributes
                     })
-
+           
             nodes.append({
                 'timestamp': timestamp,
                 'node_id': node['node_id'],