(most) all functions now take SessionAuth in addition to PasswordAuth
[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.Auth import Auth
7 from PLC.Nodes import Node, Nodes
8 from PLC.NodeNetworks import NodeNetwork, NodeNetworks
9 from PLC.NodeGroups import NodeGroup, NodeGroups
10 from PLC.ConfFiles import ConfFile, ConfFiles
11 from PLC.Slices import Slice, Slices
12 from PLC.Persons import Person, Persons
13 from PLC.Keys import Key, Keys
14 from PLC.SliceAttributes import SliceAttribute, SliceAttributes
15
16 class GetSlivers(Method):
17     """
18     Returns an array of structs representing slivers (slices bound to
19     nodes). If node_id_or_hostname_list is specified, only slivers
20     bound to the specified nodes are queried.
21
22     All of the information returned by this call can be gathered from
23     other calls, e.g. GetNodes, GetNodeNetworks, GetSlices, etc. This
24     function exists primarily for the benefit of Node Manager and
25     Federation Manager.
26     """
27
28     roles = ['admin']
29
30     accepts = [
31         Auth(),
32         [Mixed(Node.fields['node_id'],
33                Node.fields['hostname'])]
34         ]
35
36     returns = [{
37         'timestamp': Parameter(int, "Timestamp of this call, in seconds since UNIX epoch"),
38         'node_id': Node.fields['node_id'],
39         'hostname': Node.fields['hostname'],
40         'boot_state': Node.fields['boot_state'],
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_list = None):
61         timestamp = int(time.time())
62
63         all_nodes = Nodes(self.api, node_id_or_hostname_list)
64
65         nodenetwork_ids = set()
66         nodegroup_ids = set()
67         conf_file_ids = set()
68         slice_ids = set()
69         for node_id, node in all_nodes.iteritems():
70             nodenetwork_ids.update(node['nodenetwork_ids'])
71             nodegroup_ids.update(node['nodegroup_ids'])
72             conf_file_ids.update(node['conf_file_ids'])
73             slice_ids.update(node['slice_ids'])
74
75         # Get nodenetwork information
76         if nodenetwork_ids:
77             all_nodenetworks = NodeNetworks(self.api, nodenetwork_ids)
78         else:
79             all_nodenetworks = {}
80
81         # Get node group information
82         if nodegroup_ids:
83             all_nodegroups = NodeGroups(self.api, nodegroup_ids)
84
85             for nodegroup_id, nodegroup in all_nodegroups.iteritems():
86                 conf_file_ids.update(nodegroup['conf_file_ids'])
87         else:
88             all_nodegroups = {}
89
90         # Get configuration files
91         if conf_file_ids:
92             all_conf_files = ConfFiles(self.api, conf_file_ids)
93         else:
94             all_conf_files = {}
95
96         if slice_ids:
97             # Get slices
98             all_slices = Slices(self.api, slice_ids)
99
100             person_ids = set()
101             slice_attribute_ids = set()
102             for slice_id, slice in all_slices.iteritems():
103                 person_ids.update(slice['person_ids'])
104                 slice_attribute_ids.update(slice['slice_attribute_ids'])
105
106             # Get user accounts
107             all_persons = Persons(self.api, person_ids)
108
109             key_ids = set()
110             for person_id, person in all_persons.iteritems():
111                 key_ids.update(person['key_ids'])
112
113             # Get user account keys
114             all_keys = Keys(self.api, key_ids)
115
116             # Get slice attributes
117             all_slice_attributes = SliceAttributes(self.api, slice_attribute_ids)
118
119         nodes = []
120         for node_id, node in all_nodes.iteritems():
121             networks = [all_nodenetworks[nodenetwork_id] for nodenetwork_id in node['nodenetwork_ids']]
122             nodegroups = [all_nodegroups[nodegroup_id] for nodegroup_id in node['nodegroup_ids']]
123             groups = [nodegroup['name'] for nodegroup in nodegroups]
124
125             # If a node belongs to multiple node
126             # groups for which the same configuration file is defined,
127             # it is undefined which one takes precedence.
128             conf_files = {}
129             for nodegroup in nodegroups:
130                 for conf_file in map(lambda id: all_conf_files[id], nodegroup['conf_file_ids']):
131                     conf_files[conf_file['dest']] = conf_file
132
133             # Node configuration files always take precedence over
134             # node group configuration files.
135             for conf_file in map(lambda id: all_conf_files[id], node['conf_file_ids']):
136                 conf_files[conf_file['dest']] = conf_file
137
138             slivers = []
139             for slice in map(lambda id: all_slices[id], node['slice_ids']):
140                 keys = []
141                 for person in map(lambda id: all_persons[id], slice['person_ids']):
142                     keys += [{'key_type': all_keys[key_id]['key_type'],
143                               'key': all_keys[key_id]['key']} \
144                              for key_id in person['key_ids']]
145
146                 attributes = {}
147                 for slice_attribute in map(lambda id: all_slice_attributes[id],
148                                            slice['slice_attribute_ids']):
149                     # Per-node sliver attributes (slice attributes
150                     # with non-null node_id fields) take precedence
151                     # over global slice attributes.
152                     if not attributes.has_key(slice_attribute['name']) or \
153                        slice_attribute['node_id'] is not None:
154                         attributes[slice_attribute['name']] = {
155                             'name': slice_attribute['name'],
156                             'value': slice_attribute['value']
157                             }
158
159                 slivers.append({
160                     'name': slice['name'],
161                     'slice_id': slice['slice_id'],
162                     'instantiation': slice['instantiation'],
163                     'expires': slice['expires'],
164                     'keys': keys,
165                     'attributes': attributes.values()
166                     })
167
168             nodes.append({
169                 'timestamp': timestamp,
170                 'node_id': node['node_id'],
171                 'hostname': node['hostname'],
172                 'networks': networks,
173                 'groups': groups,
174                 'conf_files': conf_files.values(),
175                 'slivers': slivers
176                 })
177
178         return nodes