2 # This module implements the client-side of the Geni API. Stubs are provided
3 # that convert the supplied parameters to the necessary format and send them
4 # via XMLRPC to a Geni Server.
6 # TODO: Investigate ways to combine this with existing PLC API?
12 from sfa.trust.gid import *
13 from sfa.trust.credential import *
14 from sfa.util.record import *
15 from sfa.util.sfaticket import SfaTicket
18 # The GeniClient class provides stubs for executing Geni operations. A given
19 # client object connects to one server. To connect to multiple servers, create
20 # multiple GeniClient objects.
22 # The Geni protocol uses an HTTPS connection, and the client's side of the
23 # connection uses his private key. Generally, this private key must match the
24 # public key that is containing in the GID that the client is providing for
25 # those functions that take a GID.
29 # Create a new GeniClient object.
31 # @param url is the url of the server
32 # @param key_file = private key file of client
33 # @param cert_file = x.509 cert containing the client's public key. This
34 # could be a GID certificate, or any x.509 cert.
35 # @param protocol The ORPC protocol to use. Can be "soap" or "xmlrpc"
37 def __init__(self, url, key_file, cert_file, protocol="xmlrpc"):
39 self.key_file = key_file
40 self.cert_file = cert_file
42 if (protocol=="xmlrpc"):
44 self.server = xmlrpcprotocol.get_server(self.url, self.key_file, self.cert_file)
45 elif (protocol=="soap"):
47 self.server = soapprotocol.get_server(self.url, self.key_file, self.cert_file)
49 raise Exception("Attempted use of undefined protocol %s"%protocol)
52 # -------------------------------------------------------------------------
54 # -------------------------------------------------------------------------
57 # Create a new GID. For MAs and SAs that are physically located on the
58 # registry, this allows a owner/operator/PI to create a new GID and have it
59 # signed by his respective authority.
61 # @param cred credential of caller
62 # @param name hrn for new GID
63 # @param uuid unique identifier for new GID
64 # @param pkey_string public-key string (TODO: why is this a string and not a keypair object?)
66 # @return a GID object
68 def create_gid(self, cred, name, uuid, pkey_string):
69 gid_str = self.server.create_gid(cred.save_to_string(save_parents=True), name, uuid, pkey_string)
70 return GID(string=gid_str)
73 # Retrieve the GID for an object. This function looks up a record in the
74 # registry and returns the GID of the record if it exists.
75 # TODO: Is this function needed? It's a shortcut for Resolve()
77 # @param name hrn to look up
79 # @return a GID object
81 def get_gid(self, name):
82 gid_str_list = self.server.get_gid(name)
84 for str in gid_str_list:
85 gid_list.append(GID(string=str))
89 # Get_self_credential a degenerate version of get_credential used by a
90 # client to get his initial credential when he doesn't have one. This is
91 # the same as get_credential(..., cred=None,...).
93 # The registry ensures that the client is the principal that is named by
94 # (type, name) by comparing the public key in the record's GID to the
95 # private key used to encrypt the client-side of the HTTPS connection. Thus
96 # it is impossible for one principal to retrieve another principal's
97 # credential without having the appropriate private key.
99 # @param type type of object (user | slice | sa | ma | node
100 # @param name human readable name of object
102 # @return a credential object
104 def get_self_credential(self, type, name):
105 cred_str = self.server.get_self_credential(type, name)
106 return Credential(string = cred_str)
109 # Retrieve a credential for an object.
111 # If cred==None, then the behavior reverts to get_self_credential()
113 # @param cred credential object specifying rights of the caller
114 # @param type type of object (user | slice | sa | ma | node)
115 # @param name human readable name of object
117 # @return a credental object
119 def get_credential(self, cred, type, name):
121 cred = cred.save_to_string(save_parents=True)
122 cred_str = self.server.get_credential(cred, type, name)
123 return Credential(string = cred_str)
126 # List the records in an authority. The objectGID in the supplied credential
127 # should name the authority that will be listed.
129 # @param cred credential object specifying rights of the caller
131 # @return list of record objects
133 def list(self, cred, auth_hrn, caller_cred=None):
134 result_dict_list = self.server.list(cred.save_to_string(save_parents=True), auth_hrn, caller_cred)
136 for dict in result_dict_list:
137 result_rec_list.append(GeniRecord(dict=dict))
138 return result_rec_list
141 # Register an object with the registry. In addition to being stored in the
142 # Geni database, the appropriate records will also be created in the
147 # @param cred credential object specifying rights of the caller
148 # @return record to register
150 # @return GID object for the newly-registered record
152 def register(self, cred, record):
153 gid_str = self.server.register(cred.save_to_string(save_parents=True), record.as_dict())
154 return GID(string = gid_str)
157 # Remove an object from the registry. If the object represents a PLC object,
158 # then the PLC records will also be removed.
160 # @param cred credential object specifying rights of the caller
164 def remove(self, cred, type, hrn):
165 result = self.server.remove(cred.save_to_string(save_parents=True), type, hrn)
169 # Resolve an object in the registry. A given HRN may have multiple records
170 # associated with it, and therefore multiple records may be returned. The
171 # caller should check the type fields of the records to find the one that
172 # he is interested in.
174 # @param cred credential object specifying rights of the caller
175 # @param name human readable name of object
177 def resolve(self, cred, name):
178 result_dict_list = self.server.resolve(cred.save_to_string(save_parents=True), name)
180 for dict in result_dict_list:
181 if dict['type'] in ['authority']:
182 result_rec_list.append(AuthorityRecord(dict=dict))
183 elif dict['type'] in ['node']:
184 result_rec_list.append(NodeRecord(dict=dict))
185 elif dict['type'] in ['slice']:
186 result_rec_list.append(SliceRecord(dict=dict))
187 elif dict['type'] in ['user']:
188 result_rec_list.append(UserRecord(dict=dict))
190 result_rec_list.append(GeniRecord(dict=dict))
191 return result_rec_list
194 # Update an object in the registry. Currently, this only updates the
195 # PLC information associated with the record. The Geni fields (name, type,
200 # @param cred credential object specifying rights of the caller
201 # @param record a record object to be updated
203 def update(self, cred, record):
204 result = self.server.update(cred.save_to_string(save_parents=True), record.as_dict())
208 #-------------------------------------------------------------------------
209 # Aggregate Interface
210 #-------------------------------------------------------------------------
214 # @param cred a credential
215 # @param hrn slice hrn
217 def get_resources(self, cred, hrn=None, caller_cred=None):
218 result = self.server.get_resources(cred.save_to_string(save_parents=True), hrn, caller_cred)
221 def get_aggregates(self, cred, hrn=None):
222 result = self.server.get_resources(cred.save_to_string(save_parents=True), hrn)
227 # @param cred a credential
229 def get_policy(self, cred):
230 result = self.server.get_policy(cred.save_to_string(save_parents=True))
235 # @param cred a credential
236 # @param rspec resource specification defining how to instantiate the slice
238 def create_slice(self, cred, hrn, rspec, caller_cred=None):
239 result = self.server.create_slice(cred.save_to_string(save_parents=True), hrn, rspec, caller_cred)
245 # @param cred a credential
246 # @param hrn slice to delete
247 def delete_slice(self, cred, hrn, caller_cred=None):
248 result = self.server.delete_slice(cred.save_to_string(save_parents=True), hrn, caller_cred)
251 # ------------------------------------------------------------------------
253 # ------------------------------------------------------------------------
258 # @param cred a credential identifying the caller (callerGID) and the slice
261 def start_slice(self, cred, hrn):
262 result = self.server.start_slice(cred.save_to_string(save_parents=True), hrn)
268 # @param cred a credential identifying the caller (callerGID) and the slice
271 def stop_slice(self, cred, hrn):
272 result = self.server.stop_slice(cred.save_to_string(save_parents=True), hrn)
278 # @param cred a credential identifying the caller (callerGID) and the slice
281 def reset_slice(self, cred, hrn):
282 result = self.server.reset_slice(cred.save_to_string(save_parents=True), hrn)
288 # @param cred a credential identifying the caller (callerGID) and the slice
291 def delete_slice(self, cred, hrn, caller_cred=None):
292 result = self.server.delete_slice(cred.save_to_string(save_parents=True), hrn, caller_cred)
296 # List the slices on a component.
298 # @param cred credential object that authorizes the caller
300 # @return a list of slice names
302 def get_slices(self, cred):
303 result = self.server.get_slices(cred.save_to_string(save_parents=True))
307 # Retrieve a ticket. This operation is currently implemented on the
308 # registry (see SFA, engineering decisions), and is not implemented on
311 # The ticket is filled in with information from the PLC database. This
312 # information includes resources, and attributes such as user keys and
315 # @param cred credential object
316 # @param name name of the slice to retrieve a ticket for
317 # @param rspec resource specification dictionary
319 # @return a ticket object
321 def get_ticket(self, cred, name, rspec):
322 ticket_str = self.server.get_ticket(cred.save_to_string(save_parents=True), name, rspec)
323 ticket = SfaTicket(string=ticket_str)
327 # Redeem a ticket. This operation is currently implemented on the
330 # The ticket is submitted to the node manager, and the slice is instantiated
331 # or updated as appropriate.
333 # TODO: This operation should return a sliver credential and indicate
334 # whether or not the component will accept only sliver credentials, or
335 # will accept both sliver and slice credentials.
337 # @param ticket a ticket object containing the ticket
339 def redeem_ticket(self, ticket):
340 result = self.server.redeem_ticket(ticket.save_to_string(save_parents=True))