(no commit message)
[sfa.git] / sfa / rspecs / aggregates / rspec_manager_vini.py
1 from sfa.util.faults import *
2 from sfa.util.misc import *
3 from sfa.util.rspec import Rspec
4 from sfa.server.registry import Registries
5 import sys
6 import pdb
7
8 SFA_VINI_DEFAULT_RSPEC = '/etc/sfa/vini.rspec'
9
10 """
11 Copied from create_slice_aggregate() in sfa.plc.slices
12 """
13 def create_slice_vini_aggregate(api, hrn, nodes):
14     # Get the slice record from geni
15     slice = {}
16     registries = Registries(api)
17     registry = registries[api.hrn]
18     credential = api.getCredential()
19     records = registry.resolve(credential, hrn)
20     for record in records:
21         if record.get_type() in ['slice']:
22             slice = record.as_dict()
23     if not slice:
24         raise RecordNotFound(hrn)   
25
26     # Make sure slice exists at plc, if it doesnt add it
27     slicename = hrn_to_pl_slicename(hrn)
28     slices = api.plshell.GetSlices(api.plauth, [slicename], ['node_ids'])
29     if not slices:
30         parts = slicename.split("_")
31         login_base = parts[0]
32         # if site doesnt exist add it
33         sites = api.plshell.GetSites(api.plauth, [login_base])
34         if not sites:
35             authority = get_authority(hrn)
36             site_records = registry.resolve(credential, authority)
37             site_record = {}
38             if not site_records:
39                 raise RecordNotFound(authority)
40             site_record = site_records[0]
41             site = site_record.as_dict()
42                 
43             # add the site
44             site.pop('site_id')
45             site_id = api.plshell.AddSite(api.plauth, site)
46         else:
47             site = sites[0]
48             
49         slice_fields = {}
50         slice_keys = ['name', 'url', 'description']
51         for key in slice_keys:
52             if key in slice and slice[key]:
53                 slice_fields[key] = slice[key]  
54         api.plshell.AddSlice(api.plauth, slice_fields)
55         slice = slice_fields
56         slice['node_ids'] = 0
57     else:
58         slice = slices[0]    
59
60     # get the list of valid slice users from the registry and make 
61     # they are added to the slice 
62     researchers = record.get('researcher', [])
63     for researcher in researchers:
64         person_record = {}
65         person_records = registry.resolve(credential, researcher)
66         for record in person_records:
67             if record.get_type() in ['user']:
68                 person_record = record
69         if not person_record:
70             pass
71         person_dict = person_record.as_dict()
72         persons = api.plshell.GetPersons(api.plauth, [person_dict['email']],
73                                          ['person_id', 'key_ids'])
74
75         # Create the person record 
76         if not persons:
77             person_id=api.plshell.AddPerson(api.plauth, person_dict)
78
79             # The line below enables the user account on the remote aggregate
80             # soon after it is created.
81             # without this the user key is not transfered to the slice
82             # (as GetSlivers returns key of only enabled users),
83             # which prevents the user from login to the slice.
84             # We may do additional checks before enabling the user.
85
86             api.plshell.UpdatePerson(api.plauth, person_id, {'enabled' : True})
87             key_ids = []
88         else:
89             key_ids = persons[0]['key_ids']
90
91         api.plshell.AddPersonToSlice(api.plauth, person_dict['email'],
92                                      slicename)        
93
94         # Get this users local keys
95         keylist = api.plshell.GetKeys(api.plauth, key_ids, ['key'])
96         keys = [key['key'] for key in keylist]
97
98         # add keys that arent already there 
99         for personkey in person_dict['keys']:
100             if personkey not in keys:
101                 key = {'key_type': 'ssh', 'key': personkey}
102                 api.plshell.AddPersonKey(api.plauth, person_dict['email'], key)
103
104     # find out where this slice is currently running
105     nodelist = api.plshell.GetNodes(api.plauth, slice['node_ids'],
106                                     ['hostname'])
107     hostnames = [node['hostname'] for node in nodelist]
108
109     # remove nodes not in rspec
110     deleted_nodes = list(set(hostnames).difference(nodes))
111     # add nodes from rspec
112     added_nodes = list(set(nodes).difference(hostnames))
113
114     api.plshell.AddSliceToNodes(api.plauth, slicename, added_nodes) 
115     api.plshell.DeleteSliceFromNodes(api.plauth, slicename, deleted_nodes)
116
117     return 1
118
119 def get_rspec(api, hrn):
120     rspec = None
121     
122     if (hrn):
123         # Convert HRN to slice name
124         # Get SliceTags for the slice
125
126         # Construct LinkSpecs from the topo_rspec SliceTags
127         # The first field is the NodeId of the remote node.
128         # So the endpoints are the SliceTag node and the remote node.
129
130         # How to:
131         # - avoid duplicates?
132         # - verify both ends of the link?
133         pass
134     else:
135         # Return canned response for now...
136         r = Rspec()
137         r.parseFile(SFA_VINI_DEFAULT_RSPEC)
138         rspec = r.toxml()
139
140     return rspec
141
142
143 def create_slice(api, hrn, xml):
144     r = Rspec()
145     r.parseString(xml)
146     rspec = r.toGenDict()
147
148     # Check request against current allocations
149     # Request OK
150
151     nodes = rspec_to_nodeset(rspec)
152     create_slice_vini_aggregate(api, hrn, nodes)
153
154     # Add VINI-specific topology attributes to slice here
155
156     return True
157
158 def rspec_to_nodeset(rspec):
159     nodedict = {}
160     nodes = set()
161     try:
162         sitespecs = rspec['Rspec'][0]['Capacity'][0]['NetSpec'][0]['SiteSpec']
163         for s in sitespecs:
164             for node in s['NodeSpec']:
165                 nodedict[node['name'][0]] = node['hostname'][0]
166
167         linkspecs = rspec['Rspec'][0]['Request'][0]['NetSpec'][0]['LinkSpec']
168         for l in linkspecs:
169             for e in l['endpoint']:
170                 nodes.add(nodedict[e])
171         
172     except KeyError:
173         # Bad Rspec
174         pass
175     
176     return nodes
177
178 def main():
179     r = Rspec()
180     r.parseFile(sys.argv[1])
181     rspec = r.toGenDict()
182     create_slice(None,'plc',rspec)
183     
184 if __name__ == "__main__":
185     main()