2 # This module implements the client-side of the SFA API. Stubs are provided
3 # that convert the supplied parameters to the necessary format and send them
4 # via XMLRPC to an SFA Server.
6 # TODO: Investigate ways to combine this with existing PLC API?
9 ### $Id: client.py 16477 2010-01-05 16:31:37Z thierry $
10 ### $URL: http://svn.planet-lab.org/svn/sfa/trunk/sfa/util/client.py $
12 from sfa.trust.certificate import *
13 from sfa.trust.gid import *
14 from sfa.trust.credential import *
15 from sfa.util.record import *
16 from sfa.util.sfaticket import SfaTicket
19 # The GeniClient class provides stubs for executing SFA operations. A given
20 # client object connects to one server. To connect to multiple servers, create
21 # multiple GeniClient objects.
23 # The SFA protocol uses an HTTPS connection, and the client's side of the
24 # connection uses his private key. Generally, this private key must match the
25 # public key that is containing in the GID that the client is providing for
26 # those functions that take a GID.
30 # Create a new GeniClient object.
32 # @param url is the url of the server
33 # @param key_file = private key file of client
34 # @param cert_file = x.509 cert containing the client's public key. This
35 # could be a GID certificate, or any x.509 cert.
36 # @param protocol The ORPC protocol to use. Can be "soap" or "xmlrpc"
38 def __init__(self, url, key_file, cert_file, protocol="xmlrpc"):
40 self.key_file = key_file
41 self.cert_file = cert_file
42 self.key = Keypair(filename = self.key_file)
45 if (protocol=="xmlrpc"):
47 self.server = xmlrpcprotocol.get_server(self.url, self.key_file, self.cert_file)
48 elif (protocol=="soap"):
50 self.server = soapprotocol.get_server(self.url, self.key_file, self.cert_file)
52 raise Exception("Attempted use of undefined protocol %s"%protocol)
55 # -------------------------------------------------------------------------
57 # -------------------------------------------------------------------------
60 # Create a new GID. For MAs and SAs that are physically located on the
61 # registry, this allows a owner/operator/PI to create a new GID and have it
62 # signed by his respective authority.
64 # @param cred credential of caller
65 # @param name hrn for new GID
66 # @param uuid unique identifier for new GID
67 # @param pkey_string public-key string (TODO: why is this a string and not a keypair object?)
69 # @return a GID object
71 def create_gid(self, cred, name, uuid, pkey_string):
72 gid_str = self.server.create_gid(cred.save_to_string(save_parents=True), name, uuid, pkey_string)
73 return GID(string=gid_str)
76 # Retrieve the GID for an object. This function looks up a record in the
77 # registry and returns the GID of the record if it exists.
78 # TODO: Is this function needed? It's a shortcut for Resolve()
80 # @param name hrn to look up
82 # @return a GID object
84 #def get_gid(self, name):
85 # gid_str_list = self.server.get_gid(name)
87 # for str in gid_str_list:
88 # gid_list.append(GID(string=str))
92 def get_gid(self, cert, hrn, type, request_hash):
93 cert_string = cert.save_to_string(save_parents=True)
94 gid_str = self.server.get_gid(cert_string, hrn, type, request_hash)
95 return GID(string=gid_str)
97 # Get_self_credential a degenerate version of get_credential used by a
98 # client to get his initial credential when he doesn't have one. This is
99 # the same as get_credential(..., cred=None,...).
101 # The registry ensures that the client is the principal that is named by
102 # (type, name) by comparing the public key in the record's GID to the
103 # private key used to encrypt the client-side of the HTTPS connection. Thus
104 # it is impossible for one principal to retrieve another principal's
105 # credential without having the appropriate private key.
107 # @param type type of object (user | slice | sa | ma | node
108 # @param name human readable name of object
110 # @return a credential object
112 def get_self_credential(self, type, name):
113 cred_str = self.server.get_self_credential(type, name)
114 return Credential(string = cred_str)
117 # Retrieve a credential for an object.
119 # If cred==None, then the behavior reverts to get_self_credential()
121 # @param cred credential object specifying rights of the caller
122 # @param type type of object (user | slice | sa | ma | node)
123 # @param name human readable name of object
125 # @return a credental object
127 def get_credential(self, cred, type, name):
129 cred = cred.save_to_string(save_parents=True)
130 cred_str = self.server.get_credential(cred, type, name)
131 return Credential(string = cred_str)
134 # List the records in an authority. The objectGID in the supplied credential
135 # should name the authority that will be listed.
137 # @param cred credential object specifying rights of the caller
139 # @return list of record objects
141 def list(self, cred, auth_hrn, caller_cred=None):
142 result_dict_list = self.server.list(cred.save_to_string(save_parents=True), auth_hrn, caller_cred)
144 for dict in result_dict_list:
145 result_rec_list.append(SfaRecord(dict=dict))
146 return result_rec_list
149 # Register an object with the registry. In addition to being stored in the
150 # SFA database, the appropriate records will also be created in the
155 # @param cred credential object specifying rights of the caller
156 # @param record to register
158 # @return GID object for the newly-registered record
160 def register(self, cred, record, caller_cred=None):
161 gid_str = self.server.register(cred.save_to_string(save_parents=True), record.as_dict(), caller_cred)
162 return GID(string = gid_str)
166 # Register a peer object with the registry.
169 # @param cred credential object specifying rights of the caller
170 # @param record to register
172 # @return GID object for the newly-registered record
174 def register_peer_object(self, cred, record, caller_cred=None):
175 return self.server.register_peer_object(cred.save_to_string(save_parents=True), record, caller_cred)
178 # Remove an object from the registry. If the object represents a PLC object,
179 # then the PLC records will also be removed.
181 # @param cred credential object specifying rights of the caller
185 def remove(self, cred, type, hrn, caller_cred=None):
186 return self.server.remove(cred.save_to_string(save_parents=True), type, hrn, caller_cred)
189 # Remove a peer object from the registry. If the object represents a PLC object,
190 # then the PLC records will also be removed.
192 # @param cred credential object specifying rights of the caller
196 def remove_peer_object(self, cred, record, caller_cred=None):
197 result = self.server.remove_peer_object(cred.save_to_string(save_parents=True), record, caller_cred)
201 # Resolve an object in the registry. A given HRN may have multiple records
202 # associated with it, and therefore multiple records may be returned. The
203 # caller should check the type fields of the records to find the one that
204 # he is interested in.
206 # @param cred credential object specifying rights of the caller
207 # @param name human readable name of object
209 def resolve(self, cred, name, caller_cred=None):
210 result_dict_list = self.server.resolve(cred.save_to_string(save_parents=True), name, caller_cred)
212 for dict in result_dict_list:
213 if dict['type'] in ['authority']:
214 result_rec_list.append(AuthorityRecord(dict=dict))
215 elif dict['type'] in ['node']:
216 result_rec_list.append(NodeRecord(dict=dict))
217 elif dict['type'] in ['slice']:
218 result_rec_list.append(SliceRecord(dict=dict))
219 elif dict['type'] in ['user']:
220 result_rec_list.append(UserRecord(dict=dict))
222 result_rec_list.append(SfaRecord(dict=dict))
223 return result_rec_list
226 # Update an object in the registry. Currently, this only updates the
227 # PLC information associated with the record. The SFA fields (name, type,
232 # @param cred credential object specifying rights of the caller
233 # @param record a record object to be updated
235 def update(self, cred, record, caller_cred=None):
236 result = self.server.update(cred.save_to_string(save_parents=True), record.as_dict(), caller_cred)
240 #-------------------------------------------------------------------------
241 # Aggregate Interface
242 #-------------------------------------------------------------------------
246 # @param cred a credential
247 # @param hrn slice hrn
249 def get_resources(self, cred, hrn=None, caller_cred=None):
250 result = self.server.get_resources(cred.save_to_string(save_parents=True), hrn, caller_cred)
253 def get_aggregates(self, cred, hrn=None):
254 result = self.server.get_aggregates(cred.save_to_string(save_parents=True), hrn)
257 def get_registries(self, cred, hrn=None):
258 result = self.server.get_registries(cred.save_to_string(save_parents=True), hrn)
263 # @param cred a credential
265 def get_policy(self, cred):
266 result = self.server.get_policy(cred.save_to_string(save_parents=True))
271 # @param cred a credential
272 # @param rspec resource specification defining how to instantiate the slice
274 def create_slice(self, cred, hrn, rspec, caller_cred=None):
275 result = self.server.create_slice(cred.save_to_string(save_parents=True), hrn, rspec, caller_cred)
281 # @param cred a credential
282 # @param hrn slice to delete
283 def delete_slice(self, cred, hrn, caller_cred=None):
284 result = self.server.delete_slice(cred.save_to_string(save_parents=True), hrn, caller_cred)
287 # ------------------------------------------------------------------------
289 # ------------------------------------------------------------------------
294 # @param cred a credential identifying the caller (callerGID) and the slice
297 def start_slice(self, cred, hrn):
298 result = self.server.start_slice(cred.save_to_string(save_parents=True), hrn)
304 # @param cred a credential identifying the caller (callerGID) and the slice
307 def stop_slice(self, cred, hrn):
308 result = self.server.stop_slice(cred.save_to_string(save_parents=True), hrn)
314 # @param cred a credential identifying the caller (callerGID) and the slice
317 def reset_slice(self, cred, hrn):
318 result = self.server.reset_slice(cred.save_to_string(save_parents=True), hrn)
324 # @param cred a credential identifying the caller (callerGID) and the slice
327 def delete_slice(self, cred, hrn, caller_cred=None):
328 result = self.server.delete_slice(cred.save_to_string(save_parents=True), hrn, caller_cred)
332 # List the slices on a component.
334 # @param cred credential object that authorizes the caller
336 # @return a list of slice names
338 def get_slices(self, cred):
339 result = self.server.get_slices(cred.save_to_string(save_parents=True))
343 # Retrieve a ticket. This operation is currently implemented on the
344 # registry (see SFA, engineering decisions), and is not implemented on
347 # The ticket is filled in with information from the PLC database. This
348 # information includes resources, and attributes such as user keys and
351 # @param cred credential object
352 # @param name name of the slice to retrieve a ticket for
353 # @param rspec resource specification dictionary
355 # @return a ticket object
357 def get_ticket(self, cred, name, rspec):
358 ticket_str = self.server.get_ticket(cred.save_to_string(save_parents=True), name, rspec)
359 ticket = SfaTicket(string=ticket_str)
363 # Redeem a ticket. This operation is currently implemented on the
366 # The ticket is submitted to the node manager, and the slice is instantiated
367 # or updated as appropriate.
369 # TODO: This operation should return a sliver credential and indicate
370 # whether or not the component will accept only sliver credentials, or
371 # will accept both sliver and slice credentials.
373 # @param ticket a ticket object containing the ticket
375 def redeem_ticket(self, ticket):
376 result = self.server.redeem_ticket(ticket.save_to_string(save_parents=True))
380 def remove_remote_object(self, cred, hrn, record):
381 result = self.server.remove_remote_object(cred.save_to_string(save_parents=True), hrn, record)