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