Make sure people using xmlrpc don't need to install soap libraries
[sfa.git] / sfa / util / newgeniclient.py
1 ##
2 # This is a rehash of geniclient.py, changed to be agnostic to the messaging protocol,
3 # i.e., SOAP or XMLRPC. Please use this file if you want to support the SOAP protocol.
4
5 # If all you need is XMLRPC, use geniclient (not newgeniclient)
6 ##
7
8
9
10 from sfa.trust.gid import *
11 from sfa.trust.credential import *
12 from sfa.util.record import *
13 from sfa.util.geniticket import *
14
15 ##
16 # The GeniClient class provides stubs for executing Geni operations. A given
17 # client object connects to one server. To connect to multiple servers, create
18 # multiple GeniClient objects.
19 #
20 # The Geni protocol uses an HTTPS connection, and the client's side of the
21 # connection uses his private key. Generally, this private key must match the
22 # public key that is containing in the GID that the client is providing for
23 # those functions that take a GID.
24
25 class GeniClient:
26     ##
27     # Create a new GeniClient object.
28     #
29     # @param url is the url of the server
30     # @param key_file = private key file of client
31     # @param cert_file = x.509 cert containing the client's public key. This
32     #      could be a GID certificate, or any x.509 cert.
33     # @param protocol The ORPC protocol to use. Can be "soap" or "xmlrpc"
34
35     def __init__(self, url, key_file, cert_file, protocol="xmlrpc"):
36        self.url = url
37        self.key_file = key_file
38        self.cert_file = cert_file
39
40        if (protocol=="xmlrpc"):
41            import xmlrpcprotocol  
42            self.server = xmlrpcprotocol.get_server(self.url, self.key_file, self.cert_file)
43        elif (protocol=="soap"):
44            import soapprotocol
45            self.server = soapprotocol.get_server(self.url, self.key_file, self.cert_file)
46        else:
47            raise Exception("Attempted use of undefined protocol %s"%protocol)
48
49
50     # -------------------------------------------------------------------------
51     # Registry Interface
52     # -------------------------------------------------------------------------
53
54     ##
55     # Create a new GID. For MAs and SAs that are physically located on the
56     # registry, this allows a owner/operator/PI to create a new GID and have it
57     # signed by his respective authority.
58     #
59     # @param cred credential of caller
60     # @param name hrn for new GID
61     # @param uuid unique identifier for new GID
62     # @param pkey_string public-key string (TODO: why is this a string and not a keypair object?)
63     #
64     # @return a GID object
65
66     def create_gid(self, cred, name, uuid, pkey_string):
67         gid_str = self.server.create_gid(cred.save_to_string(save_parents=True), name, uuid, pkey_string)
68         return GID(string=gid_str)
69
70     ##
71     # Retrieve the GID for an object. This function looks up a record in the
72     # registry and returns the GID of the record if it exists.
73     # TODO: Is this function needed? It's a shortcut for Resolve()
74     #
75     # @param name hrn to look up
76     #
77     # @return a GID object
78
79     def get_gid(self, name):
80        gid_str_list = self.server.get_gid(name)
81        gid_list = []
82        for str in gid_str_list:
83            gid_list.append(GID(string=str))
84        return gid_list
85
86     ##
87     # Get_self_credential a degenerate version of get_credential used by a
88     # client to get his initial credential when he doesn't have one. This is
89     # the same as get_credential(..., cred=None,...).
90     #
91     # The registry ensures that the client is the principal that is named by
92     # (type, name) by comparing the public key in the record's GID to the
93     # private key used to encrypt the client-side of the HTTPS connection. Thus
94     # it is impossible for one principal to retrieve another principal's
95     # credential without having the appropriate private key.
96     #
97     # @param type type of object (user | slice | sa | ma | node
98     # @param name human readable name of object
99     #
100     # @return a credential object
101
102     def get_self_credential(self, type, name):
103         cred_str = self.server.get_self_credential(type, name)
104         return Credential(string = cred_str)
105
106     ##
107     # Retrieve a credential for an object.
108     #
109     # If cred==None, then the behavior reverts to get_self_credential()
110     #
111     # @param cred credential object specifying rights of the caller
112     # @param type type of object (user | slice | sa | ma | node)
113     # @param name human readable name of object
114     #
115     # @return a credental object
116
117     def get_credential(self, cred, type, name):
118         if cred:
119             cred = cred.save_to_string(save_parents=True) 
120         cred_str = self.server.get_credential(cred, type, name)
121         return Credential(string = cred_str)
122
123     ##
124     # List the records in an authority. The objectGID in the supplied credential
125     # should name the authority that will be listed.
126     #
127     # @param cred credential object specifying rights of the caller
128     #
129     # @return list of record objects
130
131     def list(self, cred, auth_hrn):
132         result_dict_list = self.server.list(cred.save_to_string(save_parents=True), auth_hrn)
133         result_rec_list = []
134         for dict in result_dict_list:
135              result_rec_list.append(GeniRecord(dict=dict))
136         return result_rec_list
137
138     ##
139     # Register an object with the registry. In addition to being stored in the
140     # Geni database, the appropriate records will also be created in the
141     # PLC databases.
142     #
143     #
144     #
145     # @param cred credential object specifying rights of the caller
146     # @return record to register
147     #
148     # @return GID object for the newly-registered record
149
150     def register(self, cred, record):
151         gid_str = self.server.register(cred.save_to_string(save_parents=True), record.as_dict())
152         return GID(string = gid_str)
153
154     ##
155     # Remove an object from the registry. If the object represents a PLC object,
156     # then the PLC records will also be removed.
157     #
158     # @param cred credential object specifying rights of the caller
159     # @param type
160     # @param hrn
161
162     def remove(self, cred, type, hrn):
163         result = self.server.remove(cred.save_to_string(save_parents=True), type, hrn)
164         return result
165
166     ##
167     # Resolve an object in the registry. A given HRN may have multiple records
168     # associated with it, and therefore multiple records may be returned. The
169     # caller should check the type fields of the records to find the one that
170     # he is interested in.
171     #
172     # @param cred credential object specifying rights of the caller
173     # @param name human readable name of object
174
175     def resolve(self, cred, name):
176         result_dict_list = self.server.resolve(cred.save_to_string(save_parents=True), name)
177         result_rec_list = []
178         for dict in result_dict_list:
179             if dict['type'] in ['authority']:
180                 result_rec_list.append(AuthorityRecord(dict=dict))
181             elif dict['type'] in ['node']:
182                 result_rec_list.append(NodeRecord(dict=dict))
183             elif dict['type'] in ['slice']:
184                 result_rec_list.append(SliceRecord(dict=dict))
185             elif dict['type'] in ['user']:
186                 result_rec_list.append(UserRecord(dict=dict))
187             else:
188                 result_rec_list.append(GeniRecord(dict=dict))
189         return result_rec_list
190
191     ##
192     # Update an object in the registry. Currently, this only updates the
193     # PLC information associated with the record. The Geni fields (name, type,
194     # GID) are fixed.
195     #
196     #
197     #
198     # @param cred credential object specifying rights of the caller
199     # @param record a record object to be updated
200
201     def update(self, cred, record):
202         result = self.server.update(cred.save_to_string(save_parents=True), record.as_dict())
203         return result
204
205
206     #-------------------------------------------------------------------------
207     # Aggregate Interface
208     #-------------------------------------------------------------------------
209     
210     ## list resources
211     #
212     # @param cred a credential
213     # @param hrn slice hrn
214
215     def get_resources(self, cred, hrn=None):
216         result = self.server.get_resources(cred.save_to_string(save_parents=True), hrn)
217         return result
218
219     def get_aggregates(self, cred, hrn=None):
220         result = self.server.get_resources(cred.save_to_string(save_parents=True), hrn)
221         return result
222
223     ## get policy
224     #
225     # @param cred a credential
226
227     def get_policy(self, cred):
228         result = self.server.get_policy(cred.save_to_string(save_parents=True))
229         return result
230
231     ## create slice
232     #
233     # @param cred a credential
234     # @param rspec resource specification defining how to instantiate the slice
235     
236     def create_slice(self, cred, hrn, rspec):
237         result = self.server.create_slice(cred.save_to_string(save_parents=True), hrn, rspec)
238         return result
239
240
241     ## delete slice
242     #
243     # @param cred a credential
244     # @param hrn slice to delete
245     def delete_slice(self, cred, hrn):
246         result = self.server.delete_slice(cred.save_to_string(save_parents=True), hrn)
247         return result    
248
249     # ------------------------------------------------------------------------
250     # Slice Interface
251     # ------------------------------------------------------------------------
252
253     ##
254     # Start a slice.
255     #
256     # @param cred a credential identifying the caller (callerGID) and the slice
257     #     (objectGID)
258
259     def start_slice(self, cred, hrn):
260         result = self.server.start_slice(cred.save_to_string(save_parents=True), hrn)
261         return result
262
263     ##
264     # Stop a slice.
265     #
266     # @param cred a credential identifying the caller (callerGID) and the slice
267     #     (objectGID)
268
269     def stop_slice(self, cred, hrn):
270         result = self.server.stop_slice(cred.save_to_string(save_parents=True), hrn)
271         return result
272
273     ##
274     # Reset a slice.
275     #
276     # @param cred a credential identifying the caller (callerGID) and the slice
277     #     (objectGID)
278
279     def reset_slice(self, cred, hrn):
280         result = self.server.reset_slice(cred.save_to_string(save_parents=True), hrn)
281         return result
282
283     ##
284     # Delete a slice.
285     #
286     # @param cred a credential identifying the caller (callerGID) and the slice
287     #     (objectGID)
288
289     def delete_slice(self, cred, hrn):
290         result = self.server.delete_slice(cred.save_to_string(save_parents=True), hrn)
291         return result
292
293     ##
294     # List the slices on a component.
295     #
296     # @param cred credential object that authorizes the caller
297     #
298     # @return a list of slice names
299
300     def get_slices(self, cred):
301         result = self.server.get_slices(cred.save_to_string(save_parents=True))
302         return result
303
304     ##
305     # Retrieve a ticket. This operation is currently implemented on the
306     # registry (see SFA, engineering decisions), and is not implemented on
307     # components.
308     #
309     # The ticket is filled in with information from the PLC database. This
310     # information includes resources, and attributes such as user keys and
311     # initscripts.
312     #
313     # @param cred credential object
314     # @param name name of the slice to retrieve a ticket for
315     # @param rspec resource specification dictionary
316     #
317     # @return a ticket object
318
319     def get_ticket(self, cred, name, rspec):
320         ticket_str = self.server.get_ticket(cred.save_to_string(save_parents=True), name, rspec)
321         ticket = Ticket(string=ticket_str)
322         return ticket
323
324     ##
325     # Redeem a ticket. This operation is currently implemented on the
326     # component.
327     #
328     # The ticket is submitted to the node manager, and the slice is instantiated
329     # or updated as appropriate.
330     #
331     # TODO: This operation should return a sliver credential and indicate
332     # whether or not the component will accept only sliver credentials, or
333     # will accept both sliver and slice credentials.
334     #
335     # @param ticket a ticket object containing the ticket
336
337     def redeem_ticket(self, ticket):
338         result = self.server.redeem_ticket(ticket.save_to_string(save_parents=True))
339         return result
340
341