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