API changes
[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.plc.api import *
7 from sfa.rspecs.aggregates.vini.utils import *
8 from sfa.rspecs.aggregates.vini.rspec import *
9 import sys
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
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['type'] in ['slice']:
23             slice = record
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 = site_records[0]
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['type'] in ['user']:
68                 person_record = record
69         if not person_record:
70             pass
71         person_dict = person_record
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     """
115     print >> sys.stderr, "Slice on nodes:"
116     for n in hostnames:
117         print >> sys.stderr, n
118     print >> sys.stderr, "Wants nodes:"
119     for n in nodes:
120         print >> sys.stderr, n
121     print >> sys.stderr, "Deleting nodes:"
122     for n in deleted_nodes:
123         print >> sys.stderr, n
124     print >> sys.stderr, "Adding nodes:"
125     for n in added_nodes:
126         print >> sys.stderr, n
127     """
128
129     api.plshell.AddSliceToNodes(api.plauth, slicename, added_nodes) 
130     api.plshell.DeleteSliceFromNodes(api.plauth, slicename, deleted_nodes)
131
132     return 1
133
134 def get_rspec(api, xrn, origin_hrn):
135     hrn = urn_to_hrn(xrn)[0]
136     topo = Topology(api)      
137     if (hrn):
138         slicename = hrn_to_pl_slicename(hrn)
139         slice = get_slice(api, slicename)
140         if slice:
141             slice.hrn = hrn
142             topo.nodeTopoFromSliceTags(slice)
143         else:
144             # call the default sfa.plc.nodes.get_rspec() method
145             return Nodes(api).get_rspec(hrn)     
146
147     return topo.toxml(hrn)
148
149
150
151 """
152 Hook called via 'sfi.py create'
153 """
154 def create_slice(api, xrn, xml):
155     hrn = urn_to_hrn(xrn)[0]
156     rspec = RSpec(xml)
157     topo = Topology(api)
158     
159     topo.nodeTopoFromRSpec(rspec)
160
161     # Check request against current allocations
162     topo.verifyNodeTopo(hrn, topo)
163     
164     nodes = topo.nodesInTopo()
165     hostnames = []
166     for node in nodes:
167         hostnames.append(node.hostname)
168     create_slice_vini_aggregate(api, hrn, hostnames)
169
170     slicename = hrn_to_pl_slicename(hrn)
171     slice = get_slice(api, slicename)
172     if slice:
173         topo.updateSliceTags(slice)    
174
175     # print topo.toxml(hrn)
176
177     return True
178
179 """
180 Returns the request context required by sfatables. At some point, this mechanism should be changed
181 to refer to "contexts", which is the information that sfatables is requesting. But for now, we just
182 return the basic information needed in a dict.
183 """
184 def fetch_context(slice_hrn, user_hrn, contexts):
185     base_context = {'sfa':{'user':{'hrn':user_hrn},
186                            'slice':{'hrn':slice_hrn}}}
187     return base_context
188
189 def main():
190     api = SfaAPI()
191     #rspec = get_rspec(api, "plc.princeton.iias", None)
192     #print rspec
193     f = open(sys.argv[1])
194     xml = f.read()
195     f.close()
196     create_slice(api, "plc.princeton.iias", xml)
197
198 if __name__ == "__main__":
199     main()