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