This commit was manufactured by cvs2svn to create branch
[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         # set nodegroup slice attributes
76         for slice_attribute in filter(lambda a: a['nodegroup_id'] in node['nodegroup_ids'], slice_attributes):
77             # Do not set any nodegroup slice attributes for
78             # which there is at least one sliver attribute
79             # already set.
80             if slice_attribute['name'] not in slice_attributes:
81                 attributes.append({'name': slice_attribute['name'],
82                                    'value': slice_attribute['value']})
83
84         for slice_attribute in filter(lambda a: a['node_id'] is None, slice_attributes):
85             # Do not set any global slice attributes for
86             # which there is at least one sliver attribute
87             # already set.
88             if slice_attribute['name'] not in sliver_attributes:
89                 attributes.append({'name': slice_attribute['name'],
90                                    'value': slice_attribute['value']})
91
92         slivers.append({
93             'name': slice['name'],
94             'slice_id': slice['slice_id'],
95             'instantiation': slice['instantiation'],
96             'expires': slice['expires'],
97             'keys': keys,
98             'attributes': attributes
99             })
100
101     return slivers
102
103 class GetSlivers(Method):
104     """
105     Returns a struct containing information about the specified node
106     (or calling node, if called by a node and node_id_or_hostname is
107     not specified), including the current set of slivers bound to the
108     node.
109
110     All of the information returned by this call can be gathered from
111     other calls, e.g. GetNodes, GetNodeNetworks, GetSlices, etc. This
112     function exists almost solely for the benefit of Node Manager.
113     """
114
115     roles = ['admin', 'node']
116
117     accepts = [
118         Auth(),
119         Mixed(Node.fields['node_id'],
120               Node.fields['hostname']),
121         ]
122
123     returns = {
124         'timestamp': Parameter(int, "Timestamp of this call, in seconds since UNIX epoch"),
125         'node_id': Node.fields['node_id'],
126         'hostname': Node.fields['hostname'],
127         'networks': [NodeNetwork.fields],
128         'groups': [NodeGroup.fields['name']],
129         'conf_files': [ConfFile.fields],
130         'initscripts': [InitScript.fields],
131         'slivers': [{
132             'name': Slice.fields['name'],
133             'slice_id': Slice.fields['slice_id'],
134             'instantiation': Slice.fields['instantiation'],
135             'expires': Slice.fields['expires'],
136             'keys': [{
137                 'key_type': Key.fields['key_type'],
138                 'key': Key.fields['key']
139             }],
140             'attributes': [{
141                 'name': SliceAttribute.fields['name'],
142                 'value': SliceAttribute.fields['value']
143             }]
144         }]
145     }
146
147     def call(self, auth, node_id_or_hostname = None):
148         timestamp = int(time.time())
149
150         # Get node
151         if node_id_or_hostname is None:
152             if isinstance(self.caller, Node):
153                 node = self.caller
154             else:
155                 raise PLCInvalidArgument, "'node_id_or_hostname' not specified"
156         else:
157             nodes = Nodes(self.api, [node_id_or_hostname])
158             if not nodes:
159                 raise PLCInvalidArgument, "No such node"
160             node = nodes[0]
161
162             if node['peer_id'] is not None:
163                 raise PLCInvalidArgument, "Not a local node"
164
165         # Get nodenetwork information
166         networks = NodeNetworks(self.api, node['nodenetwork_ids'])
167
168         # Get node group information
169         nodegroups = NodeGroups(self.api, node['nodegroup_ids']).dict('name')
170         groups = nodegroups.keys()
171
172         # Get all (enabled) configuration files
173         all_conf_files = ConfFiles(self.api, {'enabled': True}).dict()
174         conf_files = {}
175
176         # Global configuration files are the default. If multiple
177         # entries for the same global configuration file exist, it is
178         # undefined which one takes precedence.
179         for conf_file in all_conf_files.values():
180             if not conf_file['node_ids'] and not conf_file['nodegroup_ids']:
181                 conf_files[conf_file['dest']] = conf_file
182         
183         # Node group configuration files take precedence over global
184         # ones. If a node belongs to multiple node groups for which
185         # the same configuration file is defined, it is undefined
186         # which one takes precedence.
187         for nodegroup in nodegroups.values():
188             for conf_file_id in nodegroup['conf_file_ids']:
189                 if conf_file_id in all_conf_files:
190                     conf_files[conf_file['dest']] = all_conf_files[conf_file_id]
191         
192         # Node configuration files take precedence over node group
193         # configuration files.
194         for conf_file_id in node['conf_file_ids']:
195             if conf_file_id in all_conf_files:
196                 conf_files[conf_file['dest']] = all_conf_files[conf_file_id]
197             
198
199         # Get all (enabled) initscripts
200         initscripts = InitScripts(self.api, {'enabled': True})  
201
202         # Get system slices
203         system_slice_attributes = SliceAttributes(self.api, {'name': 'system', 'value': '1'}).dict('slice_id')
204         system_slice_ids = system_slice_attributes.keys()
205
206         slivers = get_slivers(self.api, system_slice_ids + node['slice_ids'], node)
207
208         node.update_last_contact()
209
210         return {
211             'timestamp': timestamp,
212             'node_id': node['node_id'],
213             'hostname': node['hostname'],
214             'networks': networks,
215             'groups': groups,
216             'conf_files': conf_files.values(),
217             'initscripts': initscripts,
218             'slivers': slivers
219             }