46005ccea64542c5eda65e5dc460a59a0800143b
[sfa.git] / sfa / nitos / nitosslices.py
1 from collections import defaultdict
2
3 from sfa.util.sfatime import utcparse, datetime_to_epoch
4 from sfa.util.sfalogging import logger
5 from sfa.util.xrn import Xrn, get_leaf, get_authority, urn_to_hrn
6
7 from sfa.rspecs.rspec import RSpec
8
9 from sfa.nitos.nitosxrn import NitosXrn, hrn_to_nitos_slicename, xrn_to_hostname, xrn_to_channel
10
11 MAXINT = 2L**31 - 1
12
13
14 class NitosSlices:
15
16     def __init__(self, driver):
17         self.driver = driver
18
19     def get_sfa_peer(self, xrn):
20         hrn, type = urn_to_hrn(xrn)
21
22         # return the authority for this hrn or None if we are the authority
23         sfa_peer = None
24         slice_authority = get_authority(hrn)
25         site_authority = get_authority(slice_authority)
26
27         if site_authority != self.driver.hrn:
28             sfa_peer = site_authority
29
30         return sfa_peer
31
32     def verify_slice_leases_nodes(self, slice, rspec_requested_nodes):
33         nodes = self.driver.shell.getNodes({}, [])
34
35         requested_nodes = []
36         for node in rspec_requested_nodes:
37             requested_node = {}
38             nitos_nodes = []
39             nitos_nodes.extend(nodes)
40             slice_name = hrn_to_nitos_slicename(node['slice_id'])
41             if slice_name != slice['slice_name']:
42                 continue
43             hostname = xrn_to_hostname(node['component_id'])
44             nitos_node = self.driver.filter_nitos_results(
45                 nitos_nodes, {'hostname': hostname})
46             if not nitos_node:
47                 continue
48             nitos_node = nitos_node[0]
49             # fill the requested node with nitos ids
50             requested_node['slice_id'] = slice['slice_id']
51             requested_node['node_id'] = nitos_node['node_id']
52             requested_node['start_time'] = node['start_time']
53             requested_node['end_time'] = str(int(
54                 node['duration']) * int(self.driver.testbedInfo['grain']) + int(node['start_time']))
55             requested_nodes.append(requested_node)
56
57         # get actual nodes reservation data for the slice
58         reserved_nodes = self.driver.filter_nitos_results(
59             self.driver.shell.getReservedNodes({}, []), {'slice_id': slice['slice_id']})
60
61         reserved_nodes_by_id = {}
62         for node in reserved_nodes:
63             reserved_nodes_by_id[node['reservation_id']] = {'slice_id': node['slice_id'],
64                                                             'node_id': node['node_id'], 'start_time': node['start_time'],
65                                                             'end_time': node['end_time']}
66
67         added_nodes = []
68         kept_nodes_id = []
69         deleted_nodes_id = []
70         for reservation_id in reserved_nodes_by_id:
71             if reserved_nodes_by_id[reservation_id] not in requested_nodes:
72                 deleted_nodes_id.append(reservation_id)
73             else:
74                 kept_nodes_id.append(reservation_id)
75                 requested_nodes.remove(reserved_nodes_by_id[reservation_id])
76         added_nodes = requested_nodes
77
78         try:
79             deleted = self.driver.shell.releaseNodes(
80                 {'reservation_ids': deleted_nodes_id})
81             for node in added_nodes:
82                 added = self.driver.shell.reserveNodes({'slice_id': slice['slice_id'], 'start_time': node[
83                                                        'start_time'], 'end_time': node['end_time'], 'nodes': [node['node_id']]})
84
85         except:
86             logger.log_exc('Failed to add/remove slice leases nodes')
87
88         return added_nodes
89
90     def verify_slice_leases_channels(self, slice, rspec_requested_channels):
91         channels = self.driver.shell.getChannels({}, [])
92
93         requested_channels = []
94         for channel in rspec_requested_channels:
95             requested_channel = {}
96             nitos_channels = []
97             nitos_channels.extend(channels)
98             slice_name = hrn_to_nitos_slicename(channel['slice_id'])
99             if slice_name != slice['slice_name']:
100                 continue
101             channel_num = xrn_to_channel(channel['component_id'])
102             nitos_channel = self.driver.filter_nitos_results(
103                 nitos_channels, {'channel': channel_num})[0]
104             # fill the requested channel with nitos ids
105             requested_channel['slice_id'] = slice['slice_id']
106             requested_channel['channel_id'] = nitos_channel['channel_id']
107             requested_channel['start_time'] = channel['start_time']
108             requested_channel['end_time'] = str(int(
109                 channel['duration']) * int(self.driver.testbedInfo['grain']) + int(channel['start_time']))
110             requested_channels.append(requested_channel)
111
112         # get actual channel reservation data for the slice
113         reserved_channels = self.driver.filter_nitos_results(
114             self.driver.shell.getReservedChannels(), {'slice_id': slice['slice_id']})
115
116         reserved_channels_by_id = {}
117         for channel in reserved_channels:
118             reserved_channels_by_id[channel['reservation_id']] = {'slice_id': channel['slice_id'],
119                                                                   'channel_id': channel['channel_id'], 'start_time': channel['start_time'],
120                                                                   'end_time': channel['end_time']}
121
122         added_channels = []
123         kept_channels_id = []
124         deleted_channels_id = []
125         for reservation_id in reserved_channels_by_id:
126             if reserved_channels_by_id[reservation_id] not in requested_channels:
127                 deleted_channels_id.append(reservation_id)
128             else:
129                 kept_channels_id.append(reservation_id)
130                 requested_channels.remove(
131                     reserved_channels_by_id[reservation_id])
132         added_channels = requested_channels
133
134         try:
135             deleted = self.driver.shell.releaseChannels(
136                 {'reservation_ids': deleted_channels_id})
137             for channel in added_channels:
138                 added = self.driver.shell.reserveChannels({'slice_id': slice['slice_id'], 'start_time': channel[
139                                                           'start_time'], 'end_time': channel['end_time'], 'channels': [channel['channel_id']]})
140
141         except:
142             logger.log_exc('Failed to add/remove slice leases channels')
143
144         return added_channels
145
146     def free_egre_key(self):
147         used = set()
148         for tag in self.driver.shell.GetSliceTags({'tagname': 'egre_key'}):
149             used.add(int(tag['value']))
150
151         for i in range(1, 256):
152             if i not in used:
153                 key = i
154                 break
155         else:
156             raise KeyError("No more EGRE keys available")
157
158         return str(key)
159
160     def verify_slice(self, slice_hrn, slice_record, sfa_peer, options=None):
161         if options is None:
162             options = {}
163         slicename = hrn_to_nitos_slicename(slice_hrn)
164         slices = self.driver.shell.getSlices({}, [])
165         slices = self.driver.filter_nitos_results(
166             slices, {'slice_name': slicename})
167         if not slices:
168             slice = {'slice_name': slicename}
169             # add the slice
170             slice['slice_id'] = self.driver.shell.addSlice(slice)
171             slice['node_ids'] = []
172             slice['user_ids'] = []
173         else:
174             slice = slices[0]
175
176         return slice
177
178     def verify_users(self, slice_hrn, slice_record, users, sfa_peer, options=None):
179         if options is None:
180             options = {}
181         # get slice info
182         slicename = hrn_to_nitos_slicename(slice_hrn)
183         slices = self.driver.shell.getSlices({}, [])
184         slice = self.driver.filter_nitos_results(
185             slices, {'slice_name': slicename})[0]
186         added_users = []
187         # get users info
188         users_info = []
189         for user in users:
190             user_urn = user['urn']
191             user_hrn, type = urn_to_hrn(user_urn)
192             username = str(user_hrn).split('.')[-1]
193             email = user['email']
194             # look for the user according to his username, email...
195             nitos_users = self.driver.filter_nitos_results(
196                 self.driver.shell.getUsers(), {'username': username})
197             if not nitos_users:
198                 nitos_users = self.driver.filter_nitos_results(
199                     self.driver.shell.getUsers(), {'email': email})
200
201             if not nitos_users:
202                 # create the user
203                 user_id = self.driver.shell.addUser(
204                     {'username': email.split('@')[0], 'email': email})
205                 added_users.append(user_id)
206                 # add user keys
207                 for key in user['keys']:
208                     self.driver.shell.addUserKey(
209                         {'user_id': user_id, 'key': key, 'slice_id': slice['slice_id']})
210                 # add the user to the slice
211                 self.driver.shell.addUserToSlice(
212                     {'slice_id': slice['slice_id'], 'user_id': user_id})
213             else:
214                 # check if the users are in the slice
215                 for user in nitos_users:
216                     if not user['user_id'] in slice['user_ids']:
217                         self.driver.shell.addUserToSlice(
218                             {'slice_id': slice['slice_id'], 'user_id': user['user_id']})
219
220         return added_users
221
222     def verify_keys(self, persons, users, options=None):
223         if options is None:
224             options = {}
225         # existing keys
226         key_ids = []
227         for person in persons:
228             key_ids.extend(person['key_ids'])
229         keylist = self.driver.shell.GetKeys(key_ids, ['key_id', 'key'])
230         keydict = {}
231         for key in keylist:
232             keydict[key['key']] = key['key_id']
233         existing_keys = keydict.keys()
234         persondict = {}
235         for person in persons:
236             persondict[person['email']] = person
237
238         # add new keys
239         requested_keys = []
240         updated_persons = []
241         for user in users:
242             user_keys = user.get('keys', [])
243             updated_persons.append(user)
244             for key_string in user_keys:
245                 requested_keys.append(key_string)
246                 if key_string not in existing_keys:
247                     key = {'key': key_string, 'key_type': 'ssh'}
248                     try:
249                         if peer:
250                             person = persondict[user['email']]
251                             self.driver.shell.UnBindObjectFromPeer(
252                                 'person', person['person_id'], peer['shortname'])
253                         key['key_id'] = self.driver.shell.AddPersonKey(
254                             user['email'], key)
255                         if peer:
256                             key_index = user_keys.index(key['key'])
257                             remote_key_id = user['key_ids'][key_index]
258                             self.driver.shell.BindObjectToPeer('key', key['key_id'], peer[
259                                                                'shortname'], remote_key_id)
260
261                     finally:
262                         if peer:
263                             self.driver.shell.BindObjectToPeer('person', person['person_id'], peer[
264                                                                'shortname'], user['person_id'])
265
266         # remove old keys (only if we are not appending)
267         append = options.get('append', True)
268         if append == False:
269             removed_keys = set(existing_keys).difference(requested_keys)
270             for existing_key_id in keydict:
271                 if keydict[existing_key_id] in removed_keys:
272                     try:
273                         if peer:
274                             self.driver.shell.UnBindObjectFromPeer(
275                                 'key', existing_key_id, peer['shortname'])
276                         self.driver.shell.DeleteKey(existing_key_id)
277                     except:
278                         pass