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