Changed Rspec --> RSpec throughout.
[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 from sfa.rspecs.aggregates.vini.utils import *
7 from sfa.rspecs.aggregates.vini.rspec import *
8 import sys
9
10 SFA_VINI_WHITELIST = '/etc/sfa/vini.whitelist'
11
12 """
13 Copied from create_slice_aggregate() in sfa.plc.slices
14 """
15 def create_slice_vini_aggregate(api, hrn, nodes):
16     # Get the slice record from geni
17     slice = {}
18     registries = Registries(api)
19     registry = registries[api.hrn]
20     credential = api.getCredential()
21     records = registry.resolve(credential, hrn)
22     for record in records:
23         if record.get_type() in ['slice']:
24             slice = record.as_dict()
25     if not slice:
26         raise RecordNotFound(hrn)   
27
28     # Make sure slice exists at plc, if it doesnt add it
29     slicename = hrn_to_pl_slicename(hrn)
30     slices = api.plshell.GetSlices(api.plauth, [slicename], ['node_ids'])
31     if not slices:
32         parts = slicename.split("_")
33         login_base = parts[0]
34         # if site doesnt exist add it
35         sites = api.plshell.GetSites(api.plauth, [login_base])
36         if not sites:
37             authority = get_authority(hrn)
38             site_records = registry.resolve(credential, authority)
39             site_record = {}
40             if not site_records:
41                 raise RecordNotFound(authority)
42             site_record = site_records[0]
43             site = site_record.as_dict()
44                 
45             # add the site
46             site.pop('site_id')
47             site_id = api.plshell.AddSite(api.plauth, site)
48         else:
49             site = sites[0]
50             
51         slice_fields = {}
52         slice_keys = ['name', 'url', 'description']
53         for key in slice_keys:
54             if key in slice and slice[key]:
55                 slice_fields[key] = slice[key]  
56         api.plshell.AddSlice(api.plauth, slice_fields)
57         slice = slice_fields
58         slice['node_ids'] = 0
59     else:
60         slice = slices[0]    
61
62     # get the list of valid slice users from the registry and make 
63     # they are added to the slice 
64     researchers = record.get('researcher', [])
65     for researcher in researchers:
66         person_record = {}
67         person_records = registry.resolve(credential, researcher)
68         for record in person_records:
69             if record.get_type() in ['user']:
70                 person_record = record
71         if not person_record:
72             pass
73         person_dict = person_record.as_dict()
74         persons = api.plshell.GetPersons(api.plauth, [person_dict['email']],
75                                          ['person_id', 'key_ids'])
76
77         # Create the person record 
78         if not persons:
79             person_id=api.plshell.AddPerson(api.plauth, person_dict)
80
81             # The line below enables the user account on the remote aggregate
82             # soon after it is created.
83             # without this the user key is not transfered to the slice
84             # (as GetSlivers returns key of only enabled users),
85             # which prevents the user from login to the slice.
86             # We may do additional checks before enabling the user.
87
88             api.plshell.UpdatePerson(api.plauth, person_id, {'enabled' : True})
89             key_ids = []
90         else:
91             key_ids = persons[0]['key_ids']
92
93         api.plshell.AddPersonToSlice(api.plauth, person_dict['email'],
94                                      slicename)        
95
96         # Get this users local keys
97         keylist = api.plshell.GetKeys(api.plauth, key_ids, ['key'])
98         keys = [key['key'] for key in keylist]
99
100         # add keys that arent already there 
101         for personkey in person_dict['keys']:
102             if personkey not in keys:
103                 key = {'key_type': 'ssh', 'key': personkey}
104                 api.plshell.AddPersonKey(api.plauth, person_dict['email'], key)
105
106     # find out where this slice is currently running
107     nodelist = api.plshell.GetNodes(api.plauth, slice['node_ids'],
108                                     ['hostname'])
109     hostnames = [node['hostname'] for node in nodelist]
110
111     # remove nodes not in rspec
112     deleted_nodes = list(set(hostnames).difference(nodes))
113     # add nodes from rspec
114     added_nodes = list(set(nodes).difference(hostnames))
115
116     """
117     print >> sys.stderr, "Slice on nodes:"
118     for n in hostnames:
119         print >> sys.stderr, n
120     print >> sys.stderr, "Wants nodes:"
121     for n in nodes:
122         print >> sys.stderr, n
123     print >> sys.stderr, "Deleting nodes:"
124     for n in deleted_nodes:
125         print >> sys.stderr, n
126     print >> sys.stderr, "Adding nodes:"
127     for n in added_nodes:
128         print >> sys.stderr, n
129     """
130
131     api.plshell.AddSliceToNodes(api.plauth, slicename, added_nodes) 
132     api.plshell.DeleteSliceFromNodes(api.plauth, slicename, deleted_nodes)
133
134     return 1
135
136 def get_rspec(api, hrn):
137     topo = Topology(api)      
138     if (hrn):
139         slicename = hrn_to_pl_slicename(hrn)
140         slice = get_slice(api, slicename)
141         if slice:
142             slice.hrn = hrn
143             topo.nodeTopoFromSliceTags(slice)
144         else:
145             # call the default sfa.plc.nodes.get_rspec() method
146             return Nodes(api).get_rspec(hrn)     
147
148     return topo.toxml(hrn)
149
150
151
152 """
153 Hook called via 'sfi.py create'
154 """
155 def create_slice(api, hrn, xml):
156     ### Check the whitelist
157     ### It consists of lines of the form: <slice hrn> <bw>
158     whitelist = {}
159     f = open(SFA_VINI_WHITELIST)
160     for line in f.readlines():
161         (slice, maxbw) = line.split()
162         whitelist[slice] = maxbw
163         
164     if hrn in whitelist:
165         maxbw = whitelist[hrn]
166     else:
167         raise PermissionError("%s not in VINI whitelist" % hrn)
168         
169     rspec = RSpec(xml)
170     topo = Topology(api)
171     
172     topo.nodeTopoFromRSpec(rspec)
173
174     # Check request against current allocations
175     topo.verifyNodeTopo(hrn, topo, maxbw)
176     
177     nodes = topo.nodesInTopo()
178     hostnames = []
179     for node in nodes:
180         hostnames.append(node.hostname)
181     create_slice_vini_aggregate(api, hrn, hostnames)
182
183     slicename = hrn_to_pl_slicename(hrn)
184     slice = get_slice(api, slicename)
185     if slice:
186         topo.updateSliceTags(slice)    
187
188     return True
189
190 """
191 Returns the request context required by sfatables. At some point, this mechanism should be changed
192 to refer to "contexts", which is the information that sfatables is requesting. But for now, we just
193 return the basic information needed in a dict.
194 """
195 def fetch_context(slice_hrn, user_hrn, contexts):
196     base_context = {'sfa':{'user':{'hrn':user_hrn}}}
197     return base_context
198
199 def main():
200     r = RSpec()
201     r.parseFile(sys.argv[1])
202     rspec = r.toDict()
203     create_slice(None,'plc',rspec)
204
205 if __name__ == "__main__":
206     main()