- since this will no longer be used for passing information to peers, it
[plcapi.git] / PLC / Methods / GetSlivers.py
1 import time
2
3 from PLC.Faults import *
4 from PLC.Method import Method
5 from PLC.Parameter import Parameter, Mixed
6 from PLC.Filter import Filter
7 from PLC.Auth import Auth
8 from PLC.Nodes import Node, Nodes
9 from PLC.NodeNetworks import NodeNetwork, NodeNetworks
10 from PLC.NodeGroups import NodeGroup, NodeGroups
11 from PLC.ConfFiles import ConfFile, ConfFiles
12 from PLC.Slices import Slice, Slices
13 from PLC.Persons import Person, Persons
14 from PLC.Keys import Key, Keys
15 from PLC.SliceAttributes import SliceAttribute, SliceAttributes
16
17 class GetSlivers(Method):
18     """
19     Returns a struct containing information about the specified node
20     (or calling node, if called by a node and node_id_or_hostname is
21     not specified), including the current set of slivers bound to the
22     node.
23
24     All of the information returned by this call can be gathered from
25     other calls, e.g. GetNodes, GetNodeNetworks, GetSlices, etc. This
26     function exists almost solely for the benefit of Node Manager.
27     """
28
29     roles = ['admin', 'node']
30
31     accepts = [
32         Auth(),
33         Mixed(Node.fields['node_id'],
34               Node.fields['hostname']),
35         ]
36
37     returns = {
38         'timestamp': Parameter(int, "Timestamp of this call, in seconds since UNIX epoch"),
39         'node_id': Node.fields['node_id'],
40         'hostname': Node.fields['hostname'],
41         'networks': [NodeNetwork.fields],
42         'groups': [NodeGroup.fields['name']],
43         'conf_files': [ConfFile.fields],
44         'slivers': [{
45             'name': Slice.fields['name'],
46             'slice_id': Slice.fields['slice_id'],
47             'instantiation': Slice.fields['instantiation'],
48             'expires': Slice.fields['expires'],
49             'keys': [{
50                 'key_type': Key.fields['key_type'],
51                 'key': Key.fields['key']
52             }],
53             'attributes': [{
54                 'name': SliceAttribute.fields['name'],
55                 'value': SliceAttribute.fields['value']
56             }]
57         }]
58     }
59
60     def call(self, auth, node_id_or_hostname = None):
61         timestamp = int(time.time())
62
63         # Get node
64         if node_id_or_hostname is None:
65             if isinstance(self.caller, Node):
66                 node = self.caller
67             else:
68                 raise PLCInvalidArgument, "'node_id_or_hostname' not specified"
69         else:
70             nodes = Nodes(self.api, [node_id_or_hostname])
71             if not nodes:
72                 raise PLCInvalidArgument, "No such node"
73             node = nodes[0]
74
75             if node['peer_id'] is not None:
76                 raise PLCInvalidArgument, "Not a local node"
77
78         # Get nodenetwork information
79         networks = NodeNetworks(self.api, node['nodenetwork_ids'])
80
81         # Get node group information
82         nodegroups = NodeGroups(self.api, node['nodegroup_ids']).dict('name')
83         groups = nodegroups.keys()
84
85         # Get system slices
86         system_slice_attributes = SliceAttributes(self.api, {'name': 'system', 'value': '1'}).dict('slice_id')
87         system_slice_ids = system_slice_attributes.keys()
88
89         # Get slice information
90         slices = Slices(self.api, system_slice_ids + node['slice_ids'])
91
92         # Build up list of users and slice attributes
93         person_ids = set()
94         slice_attribute_ids = set()
95         for slice in slices:
96             person_ids.update(slice['person_ids'])
97             slice_attribute_ids.update(slice['slice_attribute_ids'])
98
99         # Get user information
100         all_persons = Persons(self.api, person_ids).dict()
101
102         # Build up list of keys
103         key_ids = set()
104         for person in all_persons.values():
105             key_ids.update(person['key_ids'])
106
107         # Get user account keys
108         all_keys = Keys(self.api, key_ids).dict()
109
110         # Get slice attributes
111         all_slice_attributes = SliceAttributes(self.api, slice_attribute_ids).dict()
112         
113         # Get all (enabled) configuration files
114         all_conf_files = ConfFiles(self.api, {'enabled': True}).dict()
115         conf_files = {}
116
117         # Global configuration files are the default. If multiple
118         # entries for the same global configuration file exist, it is
119         # undefined which one takes precedence.
120         for conf_file in all_conf_files.values():
121             if not conf_file['node_ids'] and not conf_file['nodegroup_ids']:
122                 conf_files[conf_file['dest']] = conf_file
123         
124         # Node group configuration files take precedence over global
125         # ones. If a node belongs to multiple node groups for which
126         # the same configuration file is defined, it is undefined
127         # which one takes precedence.
128         for nodegroup in nodegroups.values():
129             for conf_file_id in nodegroup['conf_file_ids']:
130                 if conf_file_id in all_conf_files:
131                     conf_files[conf_file['dest']] = all_conf_files[conf_file_id]
132         
133         # Node configuration files take precedence over node group
134         # configuration files.
135         for conf_file_id in node['conf_file_ids']:
136             if conf_file_id in all_conf_files:
137                 conf_files[conf_file['dest']] = all_conf_files[conf_file_id]
138             
139         slivers = [] 
140         for slice in slices:
141             keys = []
142             for person_id in slice['person_ids']:
143                 if person_id in all_persons:
144                     person = all_persons[person_id]
145                     if not person['enabled']:
146                         continue
147                     for key_id in person['key_ids']:
148                         if key_id in all_keys:
149                             key = all_keys[key_id]
150                             keys += [{'key_type': key['key_type'],
151                                       'key': key['key']}]
152
153             attributes = []
154
155             # All (per-node and global) attributes for this slice
156             slice_attributes = []
157             for slice_attribute_id in slice['slice_attribute_ids']:
158                 if slice_attribute_id in all_slice_attributes:
159                     slice_attributes.append(all_slice_attributes[slice_attribute_id])
160
161             # Per-node sliver attributes take precedence over global
162             # slice attributes, so set them first.
163             sliver_attributes = []
164             for sliver_attribute in filter(lambda a: a['node_id'] == node['node_id'], slice_attributes):
165                 sliver_attributes.append(sliver_attribute['name'])
166                 attributes.append({'name': sliver_attribute['name'],
167                                    'value': sliver_attribute['value']})
168
169             for slice_attribute in filter(lambda a: a['node_id'] is None, slice_attributes):
170                 # Do not set any global slice attributes for
171                 # which there is at least one sliver attribute
172                 # already set.
173                 if slice_attribute['name'] not in sliver_attributes:
174                     attributes.append({'name': slice_attribute['name'],
175                                        'value': slice_attribute['value']})
176
177             slivers.append({
178                 'name': slice['name'],
179                 'slice_id': slice['slice_id'],
180                 'instantiation': slice['instantiation'],
181                 'expires': slice['expires'],
182                 'keys': keys,
183                 'attributes': attributes
184                 })
185             
186         return {
187             'timestamp': timestamp,
188             'node_id': node['node_id'],
189             'hostname': node['hostname'],
190             'networks': networks,
191             'groups': groups,
192             'conf_files': conf_files.values(),
193             'slivers': slivers
194             }