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
21 # XXX used to check if slice expiration time is sane
24 def get_slivers(api, slice_filter, node = None):
25 # Get slice information
26 slices = Slices(api, slice_filter, ['slice_id', 'name', 'instantiation', 'expires', 'person_ids', 'slice_tag_ids'])
28 # Build up list of users and slice attributes
32 person_ids.update(slice['person_ids'])
33 slice_tag_ids.update(slice['slice_tag_ids'])
35 # Get user information
36 all_persons = Persons(api, {'person_id':person_ids,'enabled':True}, ['person_id', 'enabled', 'key_ids']).dict()
38 # Build up list of keys
40 for person in all_persons.values():
41 key_ids.update(person['key_ids'])
43 # Get user account keys
44 all_keys = Keys(api, key_ids, ['key_id', 'key', 'key_type']).dict()
46 # Get slice attributes
47 all_slice_tags = SliceTags(api, slice_tag_ids).dict()
52 for person_id in slice['person_ids']:
53 if person_id in all_persons:
54 person = all_persons[person_id]
55 if not person['enabled']:
57 for key_id in person['key_ids']:
58 if key_id in all_keys:
59 key = all_keys[key_id]
60 keys += [{'key_type': key['key_type'],
65 # All (per-node and global) attributes for this slice
67 for slice_tag_id in slice['slice_tag_ids']:
68 if slice_tag_id in all_slice_tags:
69 slice_tags.append(all_slice_tags[slice_tag_id])
71 # Per-node sliver attributes take precedence over global
72 # slice attributes, so set them first.
73 # Then comes nodegroup slice attributes
74 # Followed by global slice attributes
75 sliver_attributes = []
78 for sliver_attribute in filter(lambda a: a['node_id'] == node['node_id'], slice_tags):
79 sliver_attributes.append(sliver_attribute['tagname'])
80 attributes.append({'tagname': sliver_attribute['tagname'],
81 'value': sliver_attribute['value']})
83 # set nodegroup slice attributes
84 for slice_tag in filter(lambda a: a['nodegroup_id'] in node['nodegroup_ids'], slice_tags):
85 # Do not set any nodegroup slice attributes for
86 # which there is at least one sliver attribute
88 if slice_tag not in slice_tags:
89 attributes.append({'tagname': slice_tag['tagname'],
90 'value': slice_tag['value']})
92 for slice_tag in filter(lambda a: a['node_id'] is None, slice_tags):
93 # Do not set any global slice attributes for
94 # which there is at least one sliver attribute
96 if slice_tag['tagname'] not in sliver_attributes:
97 attributes.append({'tagname': slice_tag['tagname'],
98 'value': slice_tag['value']})
100 # XXX Sanity check; though technically this should be a system invariant
101 # checked with an assertion
102 if slice['expires'] > MAXINT: slice['expires']= MAXINT
105 'name': slice['name'],
106 'slice_id': slice['slice_id'],
107 'instantiation': slice['instantiation'],
108 'expires': slice['expires'],
110 'attributes': attributes
115 class v43GetSlivers(Method):
117 Returns a struct containing information about the specified node
118 (or calling node, if called by a node and node_id_or_hostname is
119 not specified), including the current set of slivers bound to the
122 All of the information returned by this call can be gathered from
123 other calls, e.g. GetNodes, GetInterfaces, GetSlices, etc. This
124 function exists almost solely for the benefit of Node Manager.
127 roles = ['admin', 'node']
131 Mixed(Node.fields['node_id'],
132 Node.fields['hostname']),
136 'timestamp': Parameter(int, "Timestamp of this call, in seconds since UNIX epoch"),
137 'node_id': Node.fields['node_id'],
138 'hostname': Node.fields['hostname'],
139 'networks': [Interface.fields],
140 'groups': [NodeGroup.fields['groupname']],
141 'conf_files': [ConfFile.fields],
142 'initscripts': [InitScript.fields],
144 'name': Parameter(str, "unix style account name", max = 254),
146 'key_type': Key.fields['key_type'],
147 'key': Key.fields['key']
151 'name': Slice.fields['name'],
152 'slice_id': Slice.fields['slice_id'],
153 'instantiation': Slice.fields['instantiation'],
154 'expires': Slice.fields['expires'],
156 'key_type': Key.fields['key_type'],
157 'key': Key.fields['key']
160 'tagname': SliceTag.fields['tagname'],
161 'value': SliceTag.fields['value']
166 def call(self, auth, node_id_or_hostname = None):
167 timestamp = int(time.time())
170 if node_id_or_hostname is None:
171 if isinstance(self.caller, Node):
174 raise PLCInvalidArgument, "'node_id_or_hostname' not specified"
176 nodes = Nodes(self.api, [node_id_or_hostname])
178 raise PLCInvalidArgument, "No such node"
181 if node['peer_id'] is not None:
182 raise PLCInvalidArgument, "Not a local node"
184 # Get interface information
185 networks = Interfaces(self.api, node['interface_ids'])
187 # Get node group information
188 nodegroups = NodeGroups(self.api, node['nodegroup_ids']).dict('groupname')
189 groups = nodegroups.keys()
191 # Get all (enabled) configuration files
192 all_conf_files = ConfFiles(self.api, {'enabled': True}).dict()
195 # Global configuration files are the default. If multiple
196 # entries for the same global configuration file exist, it is
197 # undefined which one takes precedence.
198 for conf_file in all_conf_files.values():
199 if not conf_file['node_ids'] and not conf_file['nodegroup_ids']:
200 conf_files[conf_file['dest']] = conf_file
202 # Node group configuration files take precedence over global
203 # ones. If a node belongs to multiple node groups for which
204 # the same configuration file is defined, it is undefined
205 # which one takes precedence.
206 for nodegroup in nodegroups.values():
207 for conf_file_id in nodegroup['conf_file_ids']:
208 if conf_file_id in all_conf_files:
209 conf_file = all_conf_files[conf_file_id]
210 conf_files[conf_file['dest']] = conf_file
212 # Node configuration files take precedence over node group
213 # configuration files.
214 for conf_file_id in node['conf_file_ids']:
215 if conf_file_id in all_conf_files:
216 conf_file = all_conf_files[conf_file_id]
217 conf_files[conf_file['dest']] = conf_file
219 # Get all (enabled) initscripts
220 initscripts = InitScripts(self.api, {'enabled': True})
223 system_slice_tags = SliceTags(self.api, {'tagname': 'system', 'value': '1'}).dict('slice_id')
224 system_slice_ids = system_slice_tags.keys()
226 # Get nm-controller slices
227 controller_and_delegated_slices = Slices(self.api, {'instantiation': ['nm-controller', 'delegated']}, ['slice_id']).dict('slice_id')
228 controller_and_delegated_slice_ids = controller_and_delegated_slices.keys()
229 slice_ids = system_slice_ids + controller_and_delegated_slice_ids + node['slice_ids']
231 slivers = get_slivers(self.api, slice_ids, node)
233 # get the special accounts and keys needed for the node
237 if False and 'site_id' not in node:
238 nodes = Nodes(self.api, node['node_id'])
241 def getpersonsitekeys(site_id_or_name,theroles):
242 site_filter = site_id_or_name
243 site_return_filter = ['person_ids']
244 sites = Sites(self.api, site_filter, site_return_filter)
246 person_filter = {'person_id':site['person_ids'],'enabled':True}
247 person_return_filter = ['person_id', 'enabled', 'key_ids','role_ids','roles']
248 site_persons = Persons(self.api, person_filter, person_return_filter)
250 # collect the keys into a table to weed out duplicates
252 for site_person in site_persons:
253 if site_person['enabled'] is False: continue
255 for role in theroles:
256 if role in site_person['role_ids']:
257 keys_filter = site_person['key_ids']
258 keys_return_filter = ['key_id', 'key', 'key_type']
259 keys = Keys(self.api, keys_filter, keys_return_filter)
261 if key['key_type'] == 'ssh':
262 site_keys[key['key']]=None
263 return site_keys.keys()
265 # 'site_admin' account setup
266 personsitekeys=getpersonsitekeys(node['site_id'],['pi','tech'])
267 accounts.append({'name':'site_admin','keys':personsitekeys})
269 # 'root' account setup on nodes from all 'admin' users
270 # registered with the PLC main site
271 personsitekeys=getpersonsitekeys(self.api.config.PLC_SLICE_PREFIX,['admin'])
272 accounts.append({'name':'root','keys':personsitekeys})
274 node.update_last_contact()
277 'timestamp': timestamp,
278 'node_id': node['node_id'],
279 'hostname': node['hostname'],
280 'networks': networks,
282 'conf_files': conf_files.values(),
283 'initscripts': initscripts,
288 class v42GetSlivers(v43GetSlivers):
290 Legacy wrapper for v43GetSlivers.
293 def call(self, auth, node_id_or_hostname = None):
294 result = v43GetSlivers.call(self,auth,node_id_or_hostname)
295 networks = result['networks']
297 for i in range(0,len(networks)):
298 network = networks[i]
299 if network.has_key("interface_id"):
300 network['nodenetwork_id']=network['interface_id']
301 if network.has_key("interface_tag_ids"):
302 network['nodenetwork_setting_ids']=network['interface_tag_ids']
305 result['networks']=networks
308 class GetSlivers(v42GetSlivers):
310 Returns a struct containing information about the specified node
311 (or calling node, if called by a node and node_id_or_hostname is
312 not specified), including the current set of slivers bound to the
315 All of the information returned by this call can be gathered from
316 other calls, e.g. GetNodes, GetInterfaces, GetSlices, etc. This
317 function exists almost solely for the benefit of Node Manager.