4 from PLC.Faults import *
5 from PLC.Method import Method
6 from PLC.Parameter import Parameter, Mixed
7 from PLC.Filter import Filter
8 from PLC.Auth import Auth
9 from PLC.Nodes import Node, Nodes
10 from PLC.Interfaces import Interface, Interfaces
11 from PLC.NodeGroups import NodeGroup, NodeGroups
12 from PLC.ConfFiles import ConfFile, ConfFiles
13 from PLC.Slices import Slice, Slices
14 from PLC.Persons import Person, Persons
15 from PLC.Sites import Sites
16 from PLC.Roles import Roles
17 from PLC.Keys import Key, Keys
18 from PLC.SliceTags import SliceTag, SliceTags
19 from PLC.InitScripts import InitScript, InitScripts
20 from PLC.Config import Config
22 # XXX we don't really know whether this PLC is loaded from /etc/planetlab/plc_config or elsewhere
25 # XXX used to check if slice expiration time is sane
28 def get_slivers(api, slice_filter, node = None):
29 # Get slice information
30 slices = Slices(api, slice_filter, ['slice_id', 'name', 'instantiation', 'expires', 'person_ids', 'slice_tag_ids'])
32 # Build up list of users and slice attributes
36 person_ids.update(slice['person_ids'])
37 slice_tag_ids.update(slice['slice_tag_ids'])
39 # Get user information
40 all_persons = Persons(api, {'person_id':person_ids,'enabled':True}, ['person_id', 'enabled', 'key_ids']).dict()
42 # Build up list of keys
44 for person in all_persons.values():
45 key_ids.update(person['key_ids'])
47 # Get user account keys
48 all_keys = Keys(api, key_ids, ['key_id', 'key', 'key_type']).dict()
50 # Get slice attributes
51 all_slice_tags = SliceTags(api, slice_tag_ids).dict()
56 for person_id in slice['person_ids']:
57 if person_id in all_persons:
58 person = all_persons[person_id]
59 if not person['enabled']:
61 for key_id in person['key_ids']:
62 if key_id in all_keys:
63 key = all_keys[key_id]
64 keys += [{'key_type': key['key_type'],
69 # All (per-node and global) attributes for this slice
71 for slice_tag_id in slice['slice_tag_ids']:
72 if slice_tag_id in all_slice_tags:
73 slice_tags.append(all_slice_tags[slice_tag_id])
75 # Per-node sliver attributes take precedence over global
76 # slice attributes, so set them first.
77 # Then comes nodegroup slice attributes
78 # Followed by global slice attributes
79 sliver_attributes = []
82 for sliver_attribute in filter(lambda a: a['node_id'] == node['node_id'], slice_tags):
83 sliver_attributes.append(sliver_attribute['tagname'])
84 attributes.append({'tagname': sliver_attribute['tagname'],
85 'value': sliver_attribute['value']})
87 # set nodegroup slice attributes
88 for slice_tag in filter(lambda a: a['nodegroup_id'] in node['nodegroup_ids'], slice_tags):
89 # Do not set any nodegroup slice attributes for
90 # which there is at least one sliver attribute
92 if slice_tag not in slice_tags:
93 attributes.append({'tagname': slice_tag['tagname'],
94 'value': slice_tag['value']})
96 for slice_tag in filter(lambda a: a['node_id'] is None, slice_tags):
97 # Do not set any global slice attributes for
98 # which there is at least one sliver attribute
100 if slice_tag['tagname'] not in sliver_attributes:
101 attributes.append({'tagname': slice_tag['tagname'],
102 'value': slice_tag['value']})
104 # XXX Sanity check; though technically this should be a system invariant
105 # checked with an assertion
106 if slice['expires'] > MAXINT: slice['expires']= MAXINT
109 'name': slice['name'],
110 'slice_id': slice['slice_id'],
111 'instantiation': slice['instantiation'],
112 'expires': slice['expires'],
114 'attributes': attributes
119 class v43GetSlivers(Method):
121 Returns a struct containing information about the specified node
122 (or calling node, if called by a node and node_id_or_hostname is
123 not specified), including the current set of slivers bound to the
126 All of the information returned by this call can be gathered from
127 other calls, e.g. GetNodes, GetInterfaces, GetSlices, etc. This
128 function exists almost solely for the benefit of Node Manager.
131 roles = ['admin', 'node']
135 Mixed(Node.fields['node_id'],
136 Node.fields['hostname']),
140 'timestamp': Parameter(int, "Timestamp of this call, in seconds since UNIX epoch"),
141 'node_id': Node.fields['node_id'],
142 'hostname': Node.fields['hostname'],
143 'networks': [Interface.fields],
144 'groups': [NodeGroup.fields['groupname']],
145 'conf_files': [ConfFile.fields],
146 'initscripts': [InitScript.fields],
148 'name': Parameter(str, "unix style account name", max = 254),
150 'key_type': Key.fields['key_type'],
151 'key': Key.fields['key']
155 'name': Slice.fields['name'],
156 'slice_id': Slice.fields['slice_id'],
157 'instantiation': Slice.fields['instantiation'],
158 'expires': Slice.fields['expires'],
160 'key_type': Key.fields['key_type'],
161 'key': Key.fields['key']
164 'tagname': SliceTag.fields['tagname'],
165 'value': SliceTag.fields['value']
170 def call(self, auth, node_id_or_hostname = None):
173 timestamp = int(time.time())
176 if node_id_or_hostname is None:
177 if isinstance(self.caller, Node):
180 raise PLCInvalidArgument, "'node_id_or_hostname' not specified"
182 nodes = Nodes(self.api, [node_id_or_hostname])
184 raise PLCInvalidArgument, "No such node"
187 if node['peer_id'] is not None:
188 raise PLCInvalidArgument, "Not a local node"
190 # Get interface information
191 networks = Interfaces(self.api, node['interface_ids'])
193 # Get node group information
194 nodegroups = NodeGroups(self.api, node['nodegroup_ids']).dict('groupname')
195 groups = nodegroups.keys()
197 # Get all (enabled) configuration files
198 all_conf_files = ConfFiles(self.api, {'enabled': True}).dict()
201 # Global configuration files are the default. If multiple
202 # entries for the same global configuration file exist, it is
203 # undefined which one takes precedence.
204 for conf_file in all_conf_files.values():
205 if not conf_file['node_ids'] and not conf_file['nodegroup_ids']:
206 conf_files[conf_file['dest']] = conf_file
208 # Node group configuration files take precedence over global
209 # ones. If a node belongs to multiple node groups for which
210 # the same configuration file is defined, it is undefined
211 # which one takes precedence.
212 for nodegroup in nodegroups.values():
213 for conf_file_id in nodegroup['conf_file_ids']:
214 if conf_file_id in all_conf_files:
215 conf_file = all_conf_files[conf_file_id]
216 conf_files[conf_file['dest']] = conf_file
218 # Node configuration files take precedence over node group
219 # configuration files.
220 for conf_file_id in node['conf_file_ids']:
221 if conf_file_id in all_conf_files:
222 conf_file = all_conf_files[conf_file_id]
223 conf_files[conf_file['dest']] = conf_file
225 # Get all (enabled) initscripts
226 initscripts = InitScripts(self.api, {'enabled': True})
229 system_slice_tags = SliceTags(self.api, {'tagname': 'system', 'value': '1'}).dict('slice_id')
230 system_slice_ids = system_slice_tags.keys()
232 # Get nm-controller slices
233 controller_and_delegated_slices = Slices(self.api, {'instantiation': ['nm-controller', 'delegated']}, ['slice_id']).dict('slice_id')
234 controller_and_delegated_slice_ids = controller_and_delegated_slices.keys()
235 slice_ids = system_slice_ids + controller_and_delegated_slice_ids + node['slice_ids']
237 slivers = get_slivers(self.api, slice_ids, node)
239 # get the special accounts and keys needed for the node
243 if False and 'site_id' not in node:
244 nodes = Nodes(self.api, node['node_id'])
247 def getpersonsitekeys(site_id_or_name,theroles):
248 site_filter = site_id_or_name
249 site_return_filter = ['person_ids']
250 sites = Sites(self.api, site_filter, site_return_filter)
252 person_filter = {'person_id':site['person_ids'],'enabled':True}
253 person_return_filter = ['person_id', 'enabled', 'key_ids','role_ids']
254 site_persons = Persons(self.api, person_filter, person_return_filter)
256 # XXX This snippet below maps role names to role_ids,
257 # which is really DUMB. Why can't one just pass 'roles'
258 # as a return_filter to Persons() above.
260 dbroles = Roles(self.api)
261 for dbrole in dbroles:
262 __roles[dbrole['name']]=dbrole['role_id']
264 for role in theroles:
265 __theroles.append(__roles[role])
268 # collect the keys into a table to weed out duplicates
270 for site_person in site_persons:
271 if site_person['enabled'] is False: continue
273 for role in theroles:
274 if role in site_person['role_ids']:
275 keys_filter = site_person['key_ids']
276 keys_return_filter = ['key_id', 'key', 'key_type']
277 keys = Keys(self.api, keys_filter, keys_return_filter)
279 if key['key_type'] == 'ssh':
280 site_keys[key['key']]=None
281 return site_keys.keys()
283 # 'site_admin' account setup
284 personsitekeys=getpersonsitekeys(node['site_id'],['pi','tech'])
285 accounts.append({'name':'site_admin','keys':personsitekeys})
287 # 'root' account setup on nodes from all 'admin' users
288 # registered with the PLC main site
289 personsitekeys=getpersonsitekeys(plc_config.PLC_SLICE_PREFIX,['admin'])
290 accounts.append({'name':'root','keys':personsitekeys})
292 node.update_last_contact()
295 'timestamp': timestamp,
296 'node_id': node['node_id'],
297 'hostname': node['hostname'],
298 'networks': networks,
300 'conf_files': conf_files.values(),
301 'initscripts': initscripts,
306 class v42GetSlivers(v43GetSlivers):
308 Legacy wrapper for v43GetSlivers.
311 def call(self, auth, node_id_or_hostname = None):
312 result = v43GetSlivers.call(self,auth,node_id_or_hostname)
313 networks = result['networks']
315 for i in range(0,len(networks)):
316 network = networks[i]
317 if network.has_key("interface_id"):
318 network['nodenetwork_id']=network['interface_id']
319 if network.has_key("interface_tag_ids"):
320 network['nodenetwork_setting_ids']=network['interface_tag_ids']
323 result['networks']=networks
326 class GetSlivers(v42GetSlivers):
328 Returns a struct containing information about the specified node
329 (or calling node, if called by a node and node_id_or_hostname is
330 not specified), including the current set of slivers bound to the
333 All of the information returned by this call can be gathered from
334 other calls, e.g. GetNodes, GetInterfaces, GetSlices, etc. This
335 function exists almost solely for the benefit of Node Manager.