get_ticket now verifies that the required records/objects exist at the aggregate...
[sfa.git] / sfa / managers / aggregate_manager_pl.py
1 ### $Id: slices.py 15842 2009-11-22 09:56:13Z anil $
2 ### $URL: https://svn.planet-lab.org/svn/sfa/trunk/sfa/plc/slices.py $
3
4 import datetime
5 import time
6 import traceback
7 import sys
8
9 from types import StringTypes
10 from sfa.util.namespace import *
11 from sfa.util.rspec import *
12 from sfa.util.specdict import *
13 from sfa.util.faults import *
14 from sfa.util.record import SfaRecord
15 from sfa.util.policy import Policy
16 from sfa.util.record import *
17 from sfa.util.sfaticket import SfaTicket
18 from sfa.util.debug import log
19 from sfa.plc.slices import Slices
20 import sfa.plc.peers as peers
21 from sfa.plc.network import *
22 from sfa.plc.api import SfaAPI
23 from sfa.plc.slices import *
24
25 def delete_slice(api, xrn):
26     hrn, type = urn_to_hrn(xrn)
27     slicename = hrn_to_pl_slicename(hrn)
28     slices = api.plshell.GetSlices(api.plauth, {'name': slicename})
29     if not slices:
30         return 1
31     slice = slices[0]
32
33     # determine if this is a peer slice
34     peer = peers.get_peer(api, hrn)
35     if peer:
36         api.plshell.UnBindObjectFromPeer(api.plauth, 'slice', slice['slice_id'], peer)
37     api.plshell.DeleteSliceFromNodes(api.plauth, slicename, slice['node_ids'])
38     if peer:
39         api.plshell.BindObjectToPeer(api.plauth, 'slice', slice['slice_id'], peer, slice['peer_slice_id'])
40     return 1
41
42 def __get_hostnames(nodes):
43     hostnames = []
44     for node in nodes:
45         hostnames.append(node.hostname)
46     return hostnames
47     
48 def create_slice(api, xrn, xml, reg_objects=None):
49     """
50     Verify HRN and initialize the slice record in PLC if necessary.
51     """
52
53     hrn, type = urn_to_hrn(xrn)
54     peer = None
55     slices = Slices(api)
56     peer = slices.get_peer(hrn)
57     sfa_peer = slices.get_sfa_peer(hrn)
58     registry = api.registries[api.hrn]
59     credential = api.getCredential()
60     site_id, remote_site_id = slices.verify_site(registry, credential, hrn, 
61                                                  peer, sfa_peer, reg_objects)
62
63     slice = slices.verify_slice(registry, credential, hrn, site_id, 
64                                 remote_site_id, peer, sfa_peer, reg_objects)
65
66     network = Network(api)
67
68     slice = network.get_slice(api, hrn)
69     current = __get_hostnames(slice.get_nodes())
70     
71     network.addRSpec(xml, api.config.SFA_AGGREGATE_RSPEC_SCHEMA)
72     request = __get_hostnames(network.nodesWithSlivers())
73     
74     # remove nodes not in rspec
75     deleted_nodes = list(set(current).difference(request))
76
77     # add nodes from rspec
78     added_nodes = list(set(request).difference(current))
79     
80
81
82     if peer:
83         api.plshell.UnBindObjectFromPeer(api.plauth, 'slice', slice.id, peer)
84
85     api.plshell.AddSliceToNodes(api.plauth, slice.name, added_nodes) 
86     api.plshell.DeleteSliceFromNodes(api.plauth, slice.name, deleted_nodes)
87
88     network.updateSliceTags()
89
90     if peer:
91         api.plshell.BindObjectToPeer(api.plauth, 'slice', slice.id, peer, 
92                                      slice.peer_id)
93
94     # print network.toxml()
95
96     return True
97
98
99 def get_ticket(api, xrn, rspec, origin_hrn=None, reg_objects=None):
100
101     slice_hrn, type = urn_to_hrn(xrn)
102     slices = Slices(api)
103     peer = slices.get_peer(slice_hrn)
104     sfa_peer = slices.get_sfa_peer(slice_hrn)
105     
106     # get the slice record
107     registry = api.registries[api.hrn]
108     credential = api.getCredential()
109     records = registry.resolve(credential, xrn)
110
111     # similar to create_slice, we must verify that the required records exist
112     # at this aggregate before we can issue a ticket   
113     site_id, remote_site_id = slices.verify_site(registry, credential, slice_hrn,
114                                                  peer, sfa_peer, reg_objects)
115     slice = slices.verify_slice(registry, credential, slice_hrn, site_id,
116                                 remote_site_id, peer, sfa_peer, reg_objects)
117
118     # make sure we get a local slice record
119     record = None  
120     for tmp_record in records:
121         if tmp_record['type'] == 'slice' and \
122            not tmp_record['peer_authority']:
123             record = SliceRecord(dict=tmp_record)
124     if not record:
125         raise RecordNotFound(slice_hrn)
126
127     # get sliver info
128     slivers = Slices(api).get_slivers(slice_hrn)
129     if not slivers:
130         raise SliverDoesNotExist(slice_hrn)
131     
132     # get initscripts
133     initscripts = []
134     data = {
135         'timestamp': int(time.time()),
136         'initscripts': initscripts,
137         'slivers': slivers
138     }
139
140     # create the ticket
141     object_gid = record.get_gid_object()
142     new_ticket = SfaTicket(subject = object_gid.get_subject())
143     new_ticket.set_gid_caller(api.auth.client_gid)
144     new_ticket.set_gid_object(object_gid)
145     new_ticket.set_issuer(key=api.key, subject=api.hrn)
146     new_ticket.set_pubkey(object_gid.get_pubkey())
147     new_ticket.set_attributes(data)
148     new_ticket.set_rspec(rspec)
149     #new_ticket.set_parent(api.auth.hierarchy.get_auth_ticket(auth_hrn))
150     new_ticket.encode()
151     new_ticket.sign()
152     
153     return new_ticket.save_to_string(save_parents=True)
154
155 def start_slice(api, xrn):
156     hrn, type = urn_to_hrn(xrn)
157     slicename = hrn_to_pl_slicename(hrn)
158     slices = api.plshell.GetSlices(api.plauth, {'name': slicename}, ['slice_id'])
159     if not slices:
160         raise RecordNotFound(hrn)
161     slice_id = slices[0]
162     attributes = api.plshell.GetSliceTags(api.plauth, {'slice_id': slice_id, 'name': 'enabled'}, ['slice_attribute_id'])
163     attribute_id = attributes[0]['slice_attribute_id']
164     api.plshell.UpdateSliceTag(api.plauth, attribute_id, "1" )
165
166     return 1
167  
168 def stop_slice(api, xrn):
169     hrn, type = urn_to_hrn(xrn)
170     slicename = hrn_to_pl_slicename(hrn)
171     slices = api.plshell.GetSlices(api.plauth, {'name': slicename}, ['slice_id'])
172     if not slices:
173         raise RecordNotFound(hrn)
174     slice_id = slices[0]['slice_id']
175     attributes = api.plshell.GetSliceTags(api.plauth, {'slice_id': slice_id, 'name': 'enabled'}, ['slice_attribute_id'])
176     attribute_id = attributes[0]['slice_attribute_id']
177     api.plshell.UpdateSliceTag(api.plauth, attribute_id, "0")
178     return 1
179
180 def reset_slice(api, xrn):
181     # XX not implemented at this interface
182     return 1
183
184 def get_slices(api):
185     # look in cache first
186     if api.cache:
187         slices = api.cache.get('slices')
188         if slices:
189             return slices
190
191     # get data from db 
192     slices = api.plshell.GetSlices(api.plauth, {'peer_id': None}, ['name'])
193     slice_hrns = [slicename_to_hrn(api.hrn, slice['name']) for slice in slices]
194     slice_urns = [hrn_to_urn(slice_hrn, 'slice') for slice_hrn in slice_hrns]
195
196     # cache the result
197     if api.cache:
198         api.cache.add('slices', slice_urns) 
199
200     return slice_urns
201     
202 def get_rspec(api, xrn=None, origin_hrn=None):
203     # look in cache first
204     if api.cache and not xrn:
205         rspec = api.cache.get('nodes')
206         if rspec:
207             return rspec 
208
209     hrn, type = urn_to_hrn(xrn)
210     network = Network(api)
211     if (hrn):
212         if network.get_slice(api, hrn):
213             network.addSlice()
214
215     rspec = network.toxml()
216
217     # cache the result
218     if api.cache and not xrn:
219         api.cache.add('nodes', rspec)
220
221     return rspec
222
223 """
224 Returns the request context required by sfatables. At some point, this
225 mechanism should be changed to refer to "contexts", which is the
226 information that sfatables is requesting. But for now, we just return
227 the basic information needed in a dict.
228 """
229 def fetch_context(slice_xrn, user_xrn, contexts):
230     slice_hrn, type = urn_to_hrn(slice_xrn)
231     user_hrn, type = urn_to_hrn(user_xrn)
232     base_context = {'sfa':{'user':{'hrn':user_hrn}, 'slice':{'hrn':slice_hrn}}}
233     return base_context
234
235 def main():
236     api = SfaAPI()
237     """
238     rspec = get_rspec(api, "plc.princeton.sapan", None)
239     #rspec = get_rspec(api, "plc.princeton.coblitz", None)
240     #rspec = get_rspec(api, "plc.pl.sirius", None)
241     print rspec
242     """
243     f = open(sys.argv[1])
244     xml = f.read()
245     f.close()
246     create_slice(api, "plc.princeton.sapan", xml)
247
248 if __name__ == "__main__":
249     main()