(no commit message)
[sfa.git] / sfa / rspecs / aggregates / rspec_manager_max.py
1 #!/usr/bin/python
2
3 from sfa.util.rspec import Rspec
4 import sys
5 import pdb
6
7 SFA_MAX_CONF_FILE = '/etc/sfa/max_allocations'
8
9 # Topology 
10
11 topology = {'pl23':('planetlab2.dragon.maxgigapop.net','planetlab3.dragon.maxgigapop.net'),
12             'pl24':('planetlab2.dragon.maxgigapop.net','planetlab4.dragon.maxgigapop.net'),
13             'pl25':('planetlab2.dragon.maxgigapop.net','planetlab5.dragon.maxgigapop.net'),
14             'pl34':('planetlab3.dragon.maxgigapop.net','planetlab4.dragon.maxgigapop.net'),
15             'pl35':('planetlab3.dragon.maxgigapop.net','planetlab5.dragon.maxgigapop.net'),
16             'pl45':('planetlab4.dragon.maxgigapop.net','planetlab5.dragon.maxgigapop.net')
17             }
18
19 def link_endpoints(links):
20     nodes=[]
21     for l in links:
22         nodes.extend(topology[l])
23     return nodes
24
25 def lock_state_file():
26     # Noop for demo
27     return True
28
29 def unlock_state_file():
30     return True
31     # Noop for demo
32
33 def read_alloc_dict():
34     alloc_dict={}
35     rows = open(SFA_MAX_CONF_FILE).read().split('\n')
36     for r in rows:
37         columns = r.split(' ')
38         if (len(columns)>2):
39             hrn = columns[0]
40             allocs = columns[1].split(',')
41             alloc_dict[hrn]=allocs
42     return alloc_dict
43
44 def commit_alloc_dict(d):
45     f = open(SFA_MAX_CONF_FILE, 'w')
46     for hrn in d.keys():
47         columns = d[hrn]
48         row = hrn+' '+','.join(columns)+'\n'
49         f.write(row)
50     f.close()
51
52 def collapse_alloc_dict(d):
53     ret = []
54     for k in d.keys():
55         ret.extend(d[k])
56     return ret
57
58
59 def alloc_links(api, links_to_add, links_to_drop, foo):
60     return True
61
62 def alloc_nodes(api,hrn, requested_links):
63     
64     requested_nodes = link_endpoints(requested_links)
65
66     pdb.set_trace()
67     create_slice_max_aggregate(api, hrn, requested_nodes)
68
69 # Taken from slices.py
70
71 def create_slice_max_aggregate(api, hrn, nodes):
72     # Get the slice record from geni
73     slice = {}
74     registries = Registries(api)
75     registry = registries[api.hrn]
76     credential = api.getCredential()
77     records = registry.resolve(credential, hrn)
78     for record in records:
79         if record.get_type() in ['slice']:
80             slice = record.as_dict()
81     if not slice:
82         raise RecordNotFound(hrn)   
83
84     # Make sure slice exists at plc, if it doesnt add it
85     slicename = hrn_to_pl_slicename(hrn)
86     slices = api.plshell.GetSlices(api.plauth, [slicename], ['node_ids'])
87     if not slices:
88         parts = slicename.split("_")
89         login_base = parts[0]
90         # if site doesnt exist add it
91         sites = api.plshell.GetSites(api.plauth, [login_base])
92         if not sites:
93             authority = get_authority(hrn)
94             site_records = registry.resolve(credential, authority)
95             site_record = {}
96             if not site_records:
97                 raise RecordNotFound(authority)
98             site_record = site_records[0]
99             site = site_record.as_dict()
100                 
101             # add the site
102             site.pop('site_id')
103             site_id = api.plshell.AddSite(api.plauth, site)
104         else:
105             site = sites[0]
106             
107         slice_fields = {}
108         slice_keys = ['name', 'url', 'description']
109         for key in slice_keys:
110             if key in slice and slice[key]:
111                 slice_fields[key] = slice[key]  
112         api.plshell.AddSlice(api.plauth, slice_fields)
113         slice = slice_fields
114         slice['node_ids'] = 0
115     else:
116         slice = slices[0]    
117
118     # get the list of valid slice users from the registry and make 
119     # they are added to the slice 
120     researchers = record.get('researcher', [])
121     for researcher in researchers:
122         person_record = {}
123         person_records = registry.resolve(credential, researcher)
124         for record in person_records:
125             if record.get_type() in ['user']:
126                 person_record = record
127         if not person_record:
128             pass
129         person_dict = person_record.as_dict()
130         persons = api.plshell.GetPersons(api.plauth, [person_dict['email']],
131                                          ['person_id', 'key_ids'])
132
133         # Create the person record 
134         if not persons:
135             person_id=api.plshell.AddPerson(api.plauth, person_dict)
136
137             # The line below enables the user account on the remote aggregate
138             # soon after it is created.
139             # without this the user key is not transfered to the slice
140             # (as GetSlivers returns key of only enabled users),
141             # which prevents the user from login to the slice.
142             # We may do additional checks before enabling the user.
143
144             api.plshell.UpdatePerson(api.plauth, person_id, {'enabled' : True})
145             key_ids = []
146         else:
147             key_ids = persons[0]['key_ids']
148
149         api.plshell.AddPersonToSlice(api.plauth, person_dict['email'],
150                                      slicename)        
151
152         # Get this users local keys
153         keylist = api.plshell.GetKeys(api.plauth, key_ids, ['key'])
154         keys = [key['key'] for key in keylist]
155
156         # add keys that arent already there 
157         for personkey in person_dict['keys']:
158             if personkey not in keys:
159                 key = {'key_type': 'ssh', 'key': personkey}
160                 api.plshell.AddPersonKey(api.plauth, person_dict['email'], key)
161
162     # find out where this slice is currently running
163     nodelist = api.plshell.GetNodes(api.plauth, slice['node_ids'],
164                                     ['hostname'])
165     hostnames = [node['hostname'] for node in nodelist]
166
167     # remove nodes not in rspec
168     deleted_nodes = list(set(hostnames).difference(nodes))
169     # add nodes from rspec
170     added_nodes = list(set(nodes).difference(hostnames))
171
172     api.plshell.AddSliceToNodes(api.plauth, slicename, added_nodes) 
173     api.plshell.DeleteSliceFromNodes(api.plauth, slicename, deleted_nodes)
174
175     return 1
176
177
178 def get_rspec(hrn):
179     # Eg. config line:
180     # plc.princeton.sapan vlan23,vlan45
181
182     allocations = read_alloc_dict()
183     if (hrn):
184         current_allocations = allocations[hrn]
185     else:
186         current_allocations = collapse_alloc_dict(allocations)
187
188     return (allocations_to_rspec_dict(current_allocations))
189
190
191 def create_slice(api, hrn, rspec_xml):
192     # Check if everything in rspec is either allocated by hrn
193     # or not allocated at all.
194
195     r = Rspec()
196     r.parseString(rspec_xml)
197     rspec = r.toDict()
198
199     lock_state_file()
200
201     allocations = read_alloc_dict()
202     requested_allocations = rspec_to_allocations (rspec)
203     current_allocations = collapse_alloc_dict(allocations)
204     try:
205         current_hrn_allocations=allocations[hrn]
206     except KeyError:
207         current_hrn_allocations=[]
208
209     # Check request against current allocations
210     for a in requested_allocations:
211         if (a not in current_hrn_allocations and a in current_allocations):
212             return False
213     # Request OK
214
215     # Allocations to delete
216     allocations_to_delete = []
217     for a in current_hrn_allocations:
218         if (a not in requested_allocations):
219             allocations_to_delete.extend([a])
220
221     # Ok, let's do our thing
222     alloc_nodes(api, hrn, requested_allocations)
223     alloc_links(api, hrn, requested_allocations, allocations_to_delete)
224     allocations[hrn] = requested_allocations
225     commit_alloc_dict(allocations)
226
227     unlock_state_file()
228
229     return True
230
231 def rspec_to_allocations(rspec):
232     links = []
233     try:
234         linkspecs = rspec['rspec']['request'][0]['netspec'][0]['linkspec']
235         for l in linkspecs:
236             links.extend([l['name'].replace('tns:','')])
237         
238     except KeyError:
239         # Bad Rspec
240         pass
241     return links
242
243 def main():
244     r = Rspec()
245     rspec_xml = open(sys.argv[1]).read()
246     r.parseString(rspec_xml)
247     rspec = r.toDict()
248     create_slice(None,'plc',rspec)
249     
250 if __name__ == "__main__":
251     main()