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.Sites import Site, Sites
9 from PLC.Nodes import Node, Nodes
10 from PLC.NodeNetworks import NodeNetwork, NodeNetworks
11 from PLC.NodeGroups import NodeGroup, NodeGroups
12 from PLC.ConfFiles import ConfFile, ConfFiles
13 from PLC.Slices import Slice, Slices
14 from PLC.ForeignSlices import ForeignSlice, ForeignSlices
15 from PLC.Persons import Person, Persons
16 from PLC.Keys import Key, Keys
17 from PLC.SliceAttributes import SliceAttribute, SliceAttributes
19 class GetSlivers(Method):
21 Returns an array of structs representing nodes and their slivers
22 (slices bound to nodes). If node_filter is specified, only
23 information about the specified nodes will be returned. If
24 node_filter is not specified and called by a node, only
25 information about the caller will be returned.
27 All of the information returned by this call can be gathered from
28 other calls, e.g. GetNodes, GetNodeNetworks, GetSlices, etc. This
29 function exists primarily for the benefit of Node Manager and
33 roles = ['admin', 'node']
37 Mixed([Mixed(Node.fields['node_id'],
38 Node.fields['hostname'])],
43 'timestamp': Parameter(int, "Timestamp of this call, in seconds since UNIX epoch"),
44 'node_id': Node.fields['node_id'],
45 'hostname': Node.fields['hostname'],
46 'networks': [NodeNetwork.fields],
47 'groups': [NodeGroup.fields['name']],
48 'conf_files': [ConfFile.fields],
50 'name': Slice.fields['name'],
51 'slice_id': Slice.fields['slice_id'],
52 'instantiation': Slice.fields['instantiation'],
53 'expires': Slice.fields['expires'],
55 'key_type': Key.fields['key_type'],
56 'key': Key.fields['key']
59 'name': SliceAttribute.fields['name'],
60 'value': SliceAttribute.fields['value']
65 def call(self, auth, node_filter = None):
66 timestamp = int(time.time())
68 if node_filter is None and isinstance(self.caller, Node):
69 all_nodes = {self.caller['node_id']: self.caller}
71 all_nodes = Nodes(self.api, node_filter).dict()
72 # XXX Add foreign nodes
75 default_slice_ids = set()
76 sites = Sites(self.api, [self.api.config.PLC_SLICE_PREFIX])
78 default_slice_ids.update(sites[0]['slice_ids'])
80 nodenetwork_ids = set()
82 # Thierry : need to copy here otherwise side effects
83 # on slice_ids would affect default_slice_ids,
84 # that we still need later on
85 slice_ids = set(default_slice_ids)
86 for node_id, node in all_nodes.iteritems():
87 nodenetwork_ids.update(node['nodenetwork_ids'])
88 nodegroup_ids.update(node['nodegroup_ids'])
89 slice_ids.update(node['slice_ids'])
91 # Get nodenetwork information
92 all_nodenetworks = NodeNetworks(self.api, nodenetwork_ids).dict()
94 # Get node group information
95 all_nodegroups = NodeGroups(self.api, nodegroup_ids).dict()
97 # Get (enabled) configuration files
98 all_conf_files = ConfFiles(self.api, {'enabled': True}).dict()
100 # Get slice information
101 # hacky by now - merge slices and foreign slices
102 all_slices = Slices(self.api, slice_ids).dict()
103 foreign_slices_list = ForeignSlices (self.api, slice_ids)
104 for foreign_slice in foreign_slices_list:
105 all_slices[foreign_slice['slice_id']]=foreign_slice
108 slice_attribute_ids = set()
109 for slice_id, slice in all_slices.iteritems():
110 ### still missing in foreign slices
111 if slice.get('person_ids'):
112 person_ids.update(slice['person_ids'])
113 ### still missing in foreign slices
114 if slice.get('slice_attribute_ids'):
115 slice_attribute_ids.update(slice['slice_attribute_ids'])
117 # Get user information
118 all_persons = Persons(self.api, person_ids).dict()
121 for person_id, person in all_persons.iteritems():
122 key_ids.update(person['key_ids'])
124 # Get user account keys
125 all_keys = Keys(self.api, key_ids).dict()
127 # Get slice attributes
128 all_slice_attributes = SliceAttributes(self.api, slice_attribute_ids).dict()
131 for node_id, node in all_nodes.iteritems():
132 networks = [all_nodenetworks[nodenetwork_id] for nodenetwork_id in node['nodenetwork_ids']]
133 nodegroups = [all_nodegroups[nodegroup_id] for nodegroup_id in node['nodegroup_ids']]
134 groups = [nodegroup['name'] for nodegroup in nodegroups]
136 # If multiple entries for the same global configuration
137 # file exist, it is undefined which one takes precedence.
139 for conf_file in all_conf_files.values():
140 if not conf_file['node_ids'] and not conf_file['nodegroup_ids']:
141 conf_files[conf_file['dest']] = conf_file
143 # If a node belongs to multiple node
144 # groups for which the same configuration file is defined,
145 # it is undefined which one takes precedence.
146 for nodegroup in nodegroups:
147 for conf_file_id in nodegroup['conf_file_ids']:
148 if conf_file_id in all_conf_files:
149 conf_files[conf_file['dest']] = all_conf_files[conf_file_id]
151 # Node configuration files always take precedence over
152 # node group configuration files.
153 for conf_file_id in node['conf_file_ids']:
154 if conf_file_id in all_conf_files:
155 conf_files[conf_file['dest']] = all_conf_files[conf_file_id]
157 slice_ids = node['slice_ids']
159 # If not a foreign node, add all of our default system
161 # Thierry : foreign nodes are totally out of scope
162 # we dont know how to answer GetSlivers for foreign nodes.
163 slice_ids += default_slice_ids
167 for slice in map(lambda id: all_slices[id], slice_ids):
169 ### still missing in foreign slices
171 for person in map(lambda id: all_persons[id], slice['person_ids']):
172 keys += [{'key_type': all_keys[key_id]['key_type'],
173 'key': all_keys[key_id]['key']} \
174 for key_id in person['key_ids']]
176 keys += [{'key_type':'missing',
177 'key':'key caching not implemented yet'}]
180 ### still missing in foreign slices
182 for slice_attribute in map(lambda id: all_slice_attributes[id],
183 slice['slice_attribute_ids']):
184 # Per-node sliver attributes (slice attributes
185 # with non-null node_id fields) take precedence
186 # over global slice attributes.
187 if not attributes.has_key(slice_attribute['name']) or \
188 slice_attribute['node_id'] is not None:
189 attributes[slice_attribute['name']] = {
190 'name': slice_attribute['name'],
191 'value': slice_attribute['value']
194 attributes={'ignored':{'name':'attributes caching','value':'not implemented yet'}}
197 'name': slice['name'],
198 'slice_id': slice['slice_id'],
199 'instantiation': slice['instantiation'],
200 'expires': slice['expires'],
202 'attributes': attributes.values()
206 'timestamp': timestamp,
207 'node_id': node['node_id'],
208 'hostname': node['hostname'],
209 'networks': networks,
211 'conf_files': conf_files.values(),