updated calls to accept/support urn format where necessary
[sfa.git] / sfa / managers / aggregate_manager_vini.py
1 from sfa.util.faults import *
2 from sfa.util.namespace 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
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['type'] in ['slice']:
24             slice = record
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 = site_records[0]
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['type'] in ['user']:
69                 person_record = record
70         if not person_record:
71             pass
72         person_dict = person_record
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     """
116     print >> sys.stderr, "Slice on nodes:"
117     for n in hostnames:
118         print >> sys.stderr, n
119     print >> sys.stderr, "Wants nodes:"
120     for n in nodes:
121         print >> sys.stderr, n
122     print >> sys.stderr, "Deleting nodes:"
123     for n in deleted_nodes:
124         print >> sys.stderr, n
125     print >> sys.stderr, "Adding nodes:"
126     for n in added_nodes:
127         print >> sys.stderr, n
128     """
129
130     api.plshell.AddSliceToNodes(api.plauth, slicename, added_nodes) 
131     api.plshell.DeleteSliceFromNodes(api.plauth, slicename, deleted_nodes)
132
133     return 1
134
135 def get_rspec(api, xrn):
136     hrn = urn_to_hrn(xrn)[0]
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, xrn, xml):
156     hrn = urn_to_hrn(xrn)[0]
157     ### Check the whitelist
158     ### It consists of lines of the form: <slice hrn> <bw>
159     whitelist = {}
160     f = open(SFA_VINI_WHITELIST)
161     for line in f.readlines():
162         (slice, maxbw) = line.split()
163         whitelist[slice] = maxbw
164         
165     if hrn in whitelist:
166         maxbw = whitelist[hrn]
167     else:
168         raise PermissionError("%s not in VINI whitelist" % hrn)
169         
170     rspec = RSpec(xml)
171     topo = Topology(api)
172     
173     topo.nodeTopoFromRSpec(rspec)
174
175     # Check request against current allocations
176     topo.verifyNodeTopo(hrn, topo, maxbw)
177     
178     nodes = topo.nodesInTopo()
179     hostnames = []
180     for node in nodes:
181         hostnames.append(node.hostname)
182     create_slice_vini_aggregate(api, hrn, hostnames)
183
184     slicename = hrn_to_pl_slicename(hrn)
185     slice = get_slice(api, slicename)
186     if slice:
187         topo.updateSliceTags(slice)    
188
189     return True
190
191 """
192 Returns the request context required by sfatables. At some point, this mechanism should be changed
193 to refer to "contexts", which is the information that sfatables is requesting. But for now, we just
194 return the basic information needed in a dict.
195 """
196 def fetch_context(slice_hrn, user_hrn, contexts):
197     base_context = {'sfa':{'user':{'hrn':user_hrn},
198                            'slice':{'hrn':slice_hrn}}}
199     return base_context
200
201 def main():
202     r = RSpec()
203     r.parseFile(sys.argv[1])
204     rspec = r.toDict()
205     create_slice(None,'plc',rspec)
206
207 if __name__ == "__main__":
208     main()