redeem_ticket() calls redeem_ticket on all nodes specified in the rspec
[sfa.git] / sfa / client / sfi.py
1 #! /usr/bin/env python
2
3 # sfi -- slice-based facility interface
4
5 import sys
6 import os, os.path
7 import tempfile
8 import traceback
9 import socket
10 from types import StringTypes, ListType
11 from optparse import OptionParser
12 from sfa.trust.certificate import Keypair, Certificate
13 from sfa.trust.credential import Credential
14 from sfa.util.geniclient import GeniClient
15 from sfa.util.sfaticket import SfaTicket
16 from sfa.util.record import *
17 from sfa.util.misc import *
18 from sfa.util.rspec import RSpec
19 from sfa.util.xmlrpcprotocol import ServerException
20 import sfa.util.xmlrpcprotocol as xmlrpcprotocol
21 from sfa.util.config import Config
22
23 # utility methods here
24 # display methods
25 def display_rspec(rspec, format = 'rspec'):
26     if format in ['dns']:
27         spec = RSpec()
28         spec.parseString(rspec)
29         hostnames = []
30         nodespecs = spec.getDictsByTagName('NodeSpec')
31         for nodespec in nodespecs:
32             if nodespec.has_key('name') and nodespec['name']:
33                 if isinstance(nodespec['name'], ListType):
34                     hostnames.extend(nodespec['name'])
35                 elif isinstance(nodespec['name'], StringTypes):
36                      hostnames.append(nodespec['name'])
37         result = hostnames
38     elif format in ['ip']:
39         spec = RSpec()
40         spec.parseString(rspec)
41         ips = []
42         ifspecs = spec.getDictsByTagName('IfSpec')
43         for ifspec in ifspecs:
44             if ifspec.has_key('addr') and ifspec['addr']:
45                 ips.append(ifspec['addr'])
46         result = ips
47     else:
48         result = rspec
49
50     print result
51     return
52
53 def display_list(results):
54     for result in results:
55         print result
56
57
58 def display_records(recordList, dump = False):
59     ''' Print all fields in the record'''
60     for record in recordList:
61         display_record(record, dump)
62
63 def display_record(record, dump = False):
64     if dump:
65         record.dump()
66     else:
67         info = record.getdict()
68         print "%s (%s)" % (info['hrn'], info['type'])
69     return
70
71
72 def filter_records(type, records):
73     filtered_records = []
74     for record in records:
75         if (record['type'] == type) or (type == "all"):
76             filtered_records.append(record)
77     return filtered_records
78
79
80 # save methods
81 def save_rspec_to_file(rspec, filename):
82     if not filename.endswith(".rspec"):
83         filename = filename + ".rspec"
84
85     f = open(filename, 'w')
86     f.write(rspec)
87     f.close()
88     return
89
90 def save_records_to_file(filename, recordList):
91     index = 0
92     for record in recordList:
93         if index>0:
94             save_record_to_file(filename + "." + str(index), record)
95         else:
96             save_record_to_file(filename, record)
97         index = index + 1
98
99 def save_record_to_file(filename, record):
100     if record['type'] in ['user']:
101         record = UserRecord(dict = record)
102     elif record['type'] in ['slice']:
103         record = SliceRecord(dict = record)
104     elif record['type'] in ['node']:
105         record = NodeRecord(dict = record)
106     elif record['type'] in ['authority', 'ma', 'sa']:
107         record = AuthorityRecord(dict = record)
108     else:
109         record = GeniRecord(dict = record)
110     str = record.save_to_string()
111     file(filename, "w").write(str)
112     return
113
114
115 # load methods
116 def load_record_from_file(filename):
117     str = file(filename, "r").read()
118     record = GeniRecord(string=str)
119     return record
120
121
122
123 class Sfi:
124     
125     slicemgr = None
126     registry = None
127     user = None
128     authority = None
129     options = None
130     hashrequest = False
131    
132     def create_cmd_parser(self,command, additional_cmdargs = None):
133         cmdargs = {"gid": "",
134                   "list": "name",
135                   "show": "name",
136                   "remove": "name",
137                   "add": "record",
138                   "update": "record",
139                   "aggregates": "[name]",
140                   "registries": "[name]",
141                   "slices": "",
142                   "resources": "[name]",
143                   "create": "name rspec",
144                   "get_ticket": "name rspec",
145                   "redeem_ticket": "ticket rspec",  
146                   "delete": "name",
147                   "reset": "name",
148                   "start": "name",
149                   "stop": "name",
150                   "delegate": "name"
151                  }
152
153         if additional_cmdargs:
154             cmdargs.update(additional_cmdargs)
155
156         if command not in cmdargs:
157             print "Invalid command\n"
158             print "Commands: ",
159             for key in cmdargs.keys():
160                 print key+",",
161             print ""
162             sys.exit(2)
163
164         parser = OptionParser(usage="sfi [sfi_options] %s [options] %s" \
165                                      % (command, cmdargs[command]))
166
167         if command in ("resources"):
168             parser.add_option("-f", "--format", dest="format",type="choice",
169                              help="display format ([xml]|dns|ip)",default="xml",
170                              choices=("xml","dns","ip"))
171             parser.add_option("-a", "--aggregate", dest="aggregate",
172                              default=None, help="aggregate hrn")
173
174         if command in ("create", "get_ticket"):
175             parser.add_option("-a", "--aggregate", dest="aggregate",default=None,
176                              help="aggregate hrn")
177
178         if command in ("list", "show", "remove"):
179             parser.add_option("-t", "--type", dest="type",type="choice",
180                             help="type filter ([all]|user|slice|sa|ma|node|aggregate)",
181                             choices=("all","user","slice","sa","ma","node","aggregate"),
182                             default="all")
183
184         if command in ("resources", "show", "list"):
185            parser.add_option("-o", "--output", dest="file",
186                             help="output XML to file", metavar="FILE", default=None)
187         
188         if command in ("show", "list"):
189            parser.add_option("-f", "--format", dest="format", type="choice",
190                              help="display format ([text]|xml)",default="text",
191                              choices=("text","xml"))
192
193         if command in ("delegate"):
194            parser.add_option("-u", "--user",
195                             action="store_true", dest="delegate_user", default=False,
196                             help="delegate user credential")
197            parser.add_option("-s", "--slice", dest="delegate_slice",
198                             help="delegate slice credential", metavar="HRN", default=None)
199         return parser
200
201         
202     def create_parser(self):
203
204         # Generate command line parser
205         parser = OptionParser(usage="sfi [options] command [command_options] [command_args]",
206                              description="Commands: gid,list,show,remove,add,update,nodes,slices,resources,create,delete,start,stop,reset")
207         parser.add_option("-r", "--registry", dest="registry",
208                          help="root registry", metavar="URL", default=None)
209         parser.add_option("-s", "--slicemgr", dest="sm",
210                          help="slice manager", metavar="URL", default=None)
211         default_sfi_dir=os.path.expanduser("~/.sfi/")
212         parser.add_option("-d", "--dir", dest="sfi_dir",
213                          help="config & working directory - default is " + default_sfi_dir,
214                          metavar="PATH", default = default_sfi_dir)
215         parser.add_option("-u", "--user", dest="user",
216                          help="user name", metavar="HRN", default=None)
217         parser.add_option("-a", "--auth", dest="auth",
218                          help="authority name", metavar="HRN", default=None)
219         parser.add_option("-v", "--verbose",
220                          action="store_true", dest="verbose", default=False,
221                          help="verbose mode")
222         parser.add_option("-p", "--protocol",
223                          dest="protocol", default="xmlrpc",
224                          help="RPC protocol (xmlrpc or soap)")
225         parser.add_option("-k", "--hashrequest",
226                          action="store_true", dest="hashrequest", default=False,
227                          help="Create a hash of the request that will be authenticated on the server")
228         parser.disable_interspersed_args()
229
230         return parser
231         
232  
233     #
234     # Establish Connection to SliceMgr and Registry Servers
235     #
236     def set_servers(self):
237        config_file = self.options.sfi_dir + os.sep + "sfi_config"
238        try:
239           config = Config (config_file)
240        except:
241           print "Failed to read configuration file",config_file
242           print "Make sure to remove the export clauses and to add quotes"
243           if not self.options.verbose:
244              print "Re-run with -v for more details"
245           else:
246              traceback.print_exc()
247           sys.exit(1)
248     
249        errors=0
250        # Set SliceMgr URL
251        if (self.options.sm is not None):
252           sm_url = self.options.sm
253        elif hasattr(config,"SFI_SM"):
254           sm_url = config.SFI_SM
255        else:
256           print "You need to set e.g. SFI_SM='http://your.slicemanager.url:12347/' in %s"%config_file
257           errors +=1 
258     
259        # Set Registry URL
260        if (self.options.registry is not None):
261           reg_url = self.options.registry
262        elif hasattr(config,"SFI_REGISTRY"):
263           reg_url = config.SFI_REGISTRY
264        else:
265           print "You need to set e.g. SFI_REGISTRY='http://your.registry.url:12345/' in %s"%config_file
266           errors +=1 
267     
268        # Set user HRN
269        if (self.options.user is not None):
270           self.user = self.options.user
271        elif hasattr(config,"SFI_USER"):
272           self.user = config.SFI_USER
273        else:
274           print "You need to set e.g. SFI_USER='plc.princeton.username' in %s"%config_file
275           errors +=1 
276     
277        # Set authority HRN
278        if (self.options.auth is not None):
279           self.authority = self.options.auth
280        elif hasattr(config,"SFI_AUTH"):
281           self.authority = config.SFI_AUTH
282        else:
283           print "You need to set e.g. SFI_AUTH='plc.princeton' in %s"%config_file
284           errors +=1 
285     
286        if errors:
287           sys.exit(1)
288     
289        if self.options.verbose :
290           print "Contacting Slice Manager at:", sm_url
291           print "Contacting Registry at:", reg_url
292     
293        # Get key and certificate
294        key_file = self.get_key_file()
295        cert_file = self.get_cert_file(key_file)
296        self.key = Keypair(filename=key_file) 
297        self.key_file = key_file
298        self.cert_file = cert_file
299        self.cert = Certificate(filename=cert_file) 
300        # Establish connection to server(s)
301        #self.slicemgr = GeniClient(sm_url, key_file, cert_file, self.options.protocol)
302        #self.registry = GeniClient(reg_url, key_file, cert_file, self.options.protocol)
303        self.registry = xmlrpcprotocol.get_server(reg_url, key_file, cert_file)  
304        self.slicemgr = xmlrpcprotocol.get_server(sm_url, key_file, cert_file)  
305        return
306     
307     #
308     # Get various credential and spec files
309     #
310     # Establishes limiting conventions
311     #   - conflates MAs and SAs
312     #   - assumes last token in slice name is unique
313     #
314     # Bootstraps credentials
315     #   - bootstrap user credential from self-signed certificate
316     #   - bootstrap authority credential from user credential
317     #   - bootstrap slice credential from user credential
318     #
319     
320     
321     def get_key_file(self):
322        file = os.path.join(self.options.sfi_dir, get_leaf(self.user) + ".pkey")
323        if (os.path.isfile(file)):
324           return file
325        else:
326           print "Key file", file, "does not exist"
327           sys.exit(-1)
328        return
329     
330     def get_cert_file(self,key_file):
331     
332        file = os.path.join(self.options.sfi_dir, get_leaf(self.user) + ".cert")
333        if (os.path.isfile(file)):
334           return file
335        else:
336           k = Keypair(filename = key_file)
337           cert = Certificate(subject=self.user)
338           cert.set_pubkey(k)
339           cert.set_issuer(k, self.user)
340           cert.sign()
341           if self.options.verbose :
342              print "Writing self-signed certificate to", file
343           cert.save_to_file(file)
344           return file
345    
346     def get_gid(self):
347         file = os.path.join(self.options.sfi_dir, get_leaf(self.user) + ".gid")
348         if (os.path.isfile(file)):
349             gid = GID(filename=file)
350             return gid
351         else:
352             cert_str = self.cert.save_to_string(save_parents=True)
353             request_hash=None
354             if self.hashrequest:
355                 request_hash = self.key.compute_hash([cert_str, self.user, "user"])
356             gid_str = self.registry.get_gid(cert_str, self.user, "user", request_hash)
357             gid = GID(string=gid_str)
358             if self.options.verbose:
359                 print "Writing user gid to", file
360             gid.save_to_file(file, save_parents=True)
361             return gid       
362  
363     def get_user_cred(self):
364         file = os.path.join(self.options.sfi_dir, get_leaf(self.user) + ".cred")
365         if (os.path.isfile(file)):
366             user_cred = Credential(filename=file)
367             return user_cred
368         else:
369             # bootstrap user credential
370             cert_string = self.cert.save_to_string(save_parents=True)
371             request_hash=None
372             if self.hashrequest:
373                 request_hash = self.key.compute_hash([cert_string, "user", self.user])
374             user_cred = self.registry.get_self_credential(cert_string, "user", self.user, request_hash)
375             if user_cred:
376                cred = Credential(string=user_cred)
377                cred.save_to_file(file, save_parents=True)
378                if self.options.verbose:
379                     print "Writing user credential to", file
380                return cred
381             else:
382                print "Failed to get user credential"
383                sys.exit(-1)
384   
385     def get_auth_cred(self):
386         if not self.authority:
387             print "no authority specified. Use -a or set SF_AUTH"
388             sys.exit(-1)
389     
390         file = os.path.join(self.options.sfi_dir, get_leaf("authority") +".cred")
391         if (os.path.isfile(file)):
392             auth_cred = Credential(filename=file)
393             return auth_cred
394         else:
395             # bootstrap authority credential from user credential
396             user_cred = self.get_user_cred().save_to_string(save_parents=True)
397             request_hash = None
398             if self.hashrequest:
399                 request_hash = self.key.compute_hash([user_cred, "authority", self.authority])
400             auth_cred = self.registry.get_credential(user_cred, "authority", self.authority, request_hash)
401             if auth_cred:
402                 cred = Credential(string=auth_cred)
403                 cred.save_to_file(file, save_parents=True)
404                 if self.options.verbose:
405                     print "Writing authority credential to", file
406                 return cred
407             else:
408                 print "Failed to get authority credential"
409                 sys.exit(-1)
410     
411     def get_slice_cred(self,name):
412         file = os.path.join(self.options.sfi_dir, "slice_" + get_leaf(name) + ".cred")
413         if (os.path.isfile(file)):
414             slice_cred = Credential(filename=file)
415             return slice_cred
416         else:
417             # bootstrap slice credential from user credential
418             user_cred = self.get_user_cred().save_to_string(save_parents=True)
419             arg_list = [user_cred, "slice", name]
420             request_hash=None
421             if self.hashrequest:
422                 request_hash = self.key.compute_hash(arg_list)  
423             slice_cred_str = self.registry.get_credential(user_cred, "slice", name, request_hash)
424             if slice_cred_str:
425                 slice_cred = Credential(string=slice_cred_str)
426                 slice_cred.save_to_file(file, save_parents=True)
427                 if self.options.verbose:
428                     print "Writing slice credential to", file
429                 return slice_cred
430             else:
431                 print "Failed to get slice credential"
432                 sys.exit(-1)
433     
434     def delegate_cred(self,cred, hrn, type = 'authority'):
435         # the gid and hrn of the object we are delegating
436         object_gid = cred.get_gid_object()
437         object_hrn = object_gid.get_hrn()
438         cred.set_delegate(True)
439         if not cred.get_delegate():
440             raise Exception, "Error: Object credential %(object_hrn)s does not have delegate bit set" % locals()
441            
442     
443         records = self.registry.resolve(cred, hrn)
444         records = filter_records(type, records)
445         
446         if not records:
447             raise Exception, "Error: Didn't find a %(type)s record for %(hrn)s" % locals()
448     
449         # the gid of the user who will be delegated too
450         delegee_gid = records[0].get_gid_object()
451         delegee_hrn = delegee_gid.get_hrn()
452         
453         # the key and hrn of the user who will be delegating
454         user_key = Keypair(filename = self.get_key_file())
455         user_hrn = cred.get_gid_caller().get_hrn()
456     
457         dcred = Credential(subject=object_hrn + " delegated to " + delegee_hrn)
458         dcred.set_gid_caller(delegee_gid)
459         dcred.set_gid_object(object_gid)
460         dcred.set_privileges(cred.get_privileges())
461         dcred.set_delegate(True)
462         dcred.set_pubkey(object_gid.get_pubkey())
463         dcred.set_issuer(user_key, user_hrn)
464         dcred.set_parent(cred)
465         dcred.encode()
466         dcred.sign()
467     
468         return dcred
469     
470     def get_rspec_file(self,rspec):
471        if (os.path.isabs(rspec)):
472           file = rspec
473        else:
474           file = os.path.join(self.options.sfi_dir, rspec)
475        if (os.path.isfile(file)):
476           return file
477        else:
478           print "No such rspec file", rspec
479           sys.exit(1)
480     
481     def get_record_file(self,record):
482        if (os.path.isabs(record)):
483           file = record
484        else:
485           file = os.path.join(self.options.sfi_dir, record)
486        if (os.path.isfile(file)):
487           return file
488        else:
489           print "No such registry record file", record
490           sys.exit(1)
491     
492     def load_publickey_string(self,fn):
493        f = file(fn,"r")
494        key_string = f.read()
495     
496        # if the filename is a private key file, then extract the public key
497        if "PRIVATE KEY" in key_string:
498            outfn = tempfile.mktemp()
499            cmd = "openssl rsa -in " + fn + " -pubout -outform PEM -out " + outfn
500            os.system(cmd)
501            f = file(outfn, "r")
502            key_string = f.read()
503            os.remove(outfn)
504     
505        return key_string
506     
507     #
508     # Following functions implement the commands
509     #
510     # Registry-related commands
511     #
512   
513     def dispatch(self,command, cmd_opts, cmd_args):
514         getattr(self,command)(cmd_opts, cmd_args)
515  
516     def gid(self, opts, args):
517         gid = self.get_gid()
518         print "GID: %s" % (gid.save_to_string(save_parents=True))
519         return   
520  
521     # list entires in named authority registry
522     def list(self,opts, args):
523         user_cred = self.get_user_cred().save_to_string(save_parents=True)
524         hrn = args[0]
525         request_hash=None
526         if self.hashrequest:
527             request_hash = self.key.compute_hash([user_cred, hrn])    
528         try:
529             list = self.registry.list(user_cred, hrn, request_hash)
530         except IndexError:
531             raise Exception, "Not enough parameters for the 'list' command"
532           
533         # filter on person, slice, site, node, etc.  
534         # THis really should be in the self.filter_records funct def comment...
535         list = filter_records(opts.type, list)
536         for record in list:
537             print "%s (%s)" % (record['hrn'], record['type'])     
538         if opts.file:
539             file = opts.file
540             if not file.startswith(os.sep):
541                 file = os.path.join(self.options.sfi_dir, get_leaf(self.user) + ".gid")
542             save_records_to_file(file, list)
543         return
544     
545     # show named registry record
546     def show(self,opts, args):
547         user_cred = self.get_user_cred().save_to_string(save_parents=True)
548         hrn = args[0]
549         request_hash=None
550         if self.hashrequest:
551             request_hash = self.key.compute_hash([user_cred, hrn])    
552         records = self.registry.resolve(user_cred, hrn, request_hash)
553         records = filter_records(opts.type, records)
554         if not records:
555             print "No record of type", opts.type
556         for record in records:
557             if record['type'] in ['user']:
558                 record = UserRecord(dict = record)
559             elif record['type'] in ['slice']:
560                 record = SliceRecord(dict = record)
561             elif record['type'] in ['node']:
562                 record = NodeRecord(dict = record)
563             elif record['type'] in ['authority', 'ma', 'sa']:
564                 record = AuthorityRecord(dict = record)
565             else:
566                 record = GeniRecord(dict = record)
567             if (opts.format=="text"): 
568                 record.dump()  
569             else: 
570                 print record.save_to_string() 
571        
572         if opts.file:
573             file = opts.file
574             if not file.startswith(os.sep):
575                 file = os.path.join(self.options.sfi_dir, file)
576             save_records_to_file(file, records)
577         return
578     
579     def delegate(self,opts, args):
580        user_cred = self.get_user_cred()
581        if opts.delegate_user:
582            object_cred = user_cred
583        elif opts.delegate_slice:
584            object_cred = self.get_slice_cred(opts.delegate_slice)
585        else:
586            print "Must specify either --user or --slice <hrn>"
587            return
588     
589        # the gid and hrn of the object we are delegating
590        object_gid = object_cred.get_gid_object()
591        object_hrn = object_gid.get_hrn()
592     
593        if not object_cred.get_delegate():
594            print "Error: Object credential", object_hrn, "does not have delegate bit set"
595            return
596     
597        records = self.registry.resolve(user_cred, args[0])
598        records = filter_records("user", records)
599     
600        if not records:
601            print "Error: Didn't find a user record for", args[0]
602            return
603     
604        # the gid of the user who will be delegated too
605        delegee_gid = records[0].get_gid_object()
606        delegee_hrn = delegee_gid.get_hrn()
607     
608        # the key and hrn of the user who will be delegating
609        user_key = Keypair(filename = self.get_key_file())
610        user_hrn = user_cred.get_gid_caller().get_hrn()
611     
612        dcred = Credential(subject=object_hrn + " delegated to " + delegee_hrn)
613        dcred.set_gid_caller(delegee_gid)
614        dcred.set_gid_object(object_gid)
615        dcred.set_privileges(object_cred.get_privileges())
616        dcred.set_delegate(True)
617        dcred.set_pubkey(object_gid.get_pubkey())
618        dcred.set_issuer(user_key, user_hrn)
619        dcred.set_parent(object_cred)
620        dcred.encode()
621        dcred.sign()
622     
623        if opts.delegate_user:
624            dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_" 
625                                   + get_leaf(object_hrn) + ".cred")
626        elif opts.delegate_slice:
627            dest_fn = os.path_join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_slice_" 
628                                   + get_leaf(object_hrn) + ".cred")
629     
630        dcred.save_to_file(dest_fn, save_parents = True)
631     
632        print "delegated credential for", object_hrn, "to", delegee_hrn, "and wrote to", dest_fn
633     
634     # removed named registry record
635     #   - have to first retrieve the record to be removed
636     def remove(self,opts, args):
637         auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
638         hrn = args[0]
639         type = opts.type 
640         if type in ['all']:
641             type = '*'
642         request_hash=None
643         if self.hashrequest: 
644             arg_list = [auth_cred, type, hrn]
645             request_hash = self.key.compute_hash(arg_list)                   
646         return self.registry.remove(auth_cred, type, hrn, request_hash)
647     
648     # add named registry record
649     def add(self,opts, args):
650         auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
651         record_filepath = args[0]
652         rec_file = self.get_record_file(record_filepath)
653         record = load_record_from_file(rec_file).as_dict()
654         request_hash=None
655         if self.hashrequest:
656             arg_list = [auth_cred]
657             request_hash = self.key.compute_hash(arg_list)
658         return self.registry.register(auth_cred, record, request_hash)
659     
660     # update named registry entry
661     def update(self,opts, args):
662         user_cred = self.get_user_cred()
663         rec_file = self.get_record_file(args[0])
664         record = load_record_from_file(rec_file)
665         if record['type'] == "user":
666             if record.get_name() == user_cred.get_gid_object().get_hrn():
667                 cred = user_cred.save_to_string(save_parents=True)
668             else:
669                 cred = self.get_auth_cred().save_to_string(save_parents=True)
670         elif record['type'] in ["slice"]:
671             try:
672                 cred = self.get_slice_cred(record.get_name()).save_to_string(save_parents=True)
673             except ServerException, e:
674                # XXX smbaker -- once we have better error return codes, update this
675                # to do something better than a string compare
676                if "Permission error" in e.args[0]:
677                    cred = self.get_auth_cred().save_to_string(save_parents=True)
678                else:
679                    raise
680         elif record.get_type() in ["authority"]:
681             cred = self.get_auth_cred().save_to_string(save_parents=True)
682         elif record.get_type() == 'node':
683             cred = self.get_auth_cred().save_to_string(save_parents=True)
684         else:
685             raise "unknown record type" + record.get_type()
686         record = record.as_dict()
687         request_hash=None
688         if self.hashrequest:
689             arg_list = [cred]  
690             request_hash = self.key.compute_hash(arg_list)
691         return self.registry.update(cred, record, request_hash)
692    
693     
694     def aggregates(self, opts, args):
695         """
696         return a list of details about known aggregates
697         """
698         user_cred = self.get_user_cred().save_to_string(save_parents=True)
699         hrn = None
700         if args: 
701             hrn = args[0]
702         request_hash=None
703         if self.hashrequest:
704             arg_list = [user_cred, hrn]  
705             request_hash = self.key.compute_hash(arg_list)
706         result = self.registry.get_aggregates(user_cred, hrn, request_hash)
707         display_list(result)
708         return 
709
710     def registries(self, opts, args):
711         """
712         return a list of details about known registries
713         """
714         user_cred = self.get_user_cred().save_to_string(save_parents=True)
715         hrn = None
716         if args:
717             hrn = args[0]
718         request_hash=None
719         if self.hashrequest:
720             arg_list = [user_cred, hrn]  
721             request_hash = self.key.compute_hash(arg_list)
722         result = self.registry.get_registries(user_cred, hrn, request_hash)
723         display_list(result)
724         return
725
726  
727     #
728     # Slice-related commands
729     #
730     
731     # list available nodes -- use 'resources' w/ no argument instead
732
733     # list instantiated slices
734     def slices(self,opts, args):
735         user_cred = self.get_user_cred().save_to_string(save_parents=True)
736         request_hash=None
737         if self.hashrequest:
738             arg_list = [user_cred]
739             request_hash = self.key.compute_hash(arg_list)
740         results = self.slicemgr.get_slices(user_cred, request_hash)
741         display_list(results)
742         return
743     
744     # show rspec for named slice
745     def resources(self,opts, args):
746         user_cred = self.get_user_cred().save_to_string(save_parents=True)
747         server = self.slicemgr
748         if opts.aggregate:
749             agg_hrn = opts.aggregate
750             arg_list = [user_cred, arg_hrn]
751             request_hash = self.key.compute_hash(arg_list)
752             aggregates = self.registry.get_aggregates(user_cred, agg_hrn, request_hash)
753             if not aggregates:
754                 raise Exception, "No such aggregate %s" % agg_hrn
755             aggregate = aggregates[0]
756             url = "http://%s:%s" % (aggregate['addr'], aggregate['port'])     
757             server = xmlrpcprotocol.get_server(url, self.key_file, self.cert_file)
758         if args:
759             cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
760             hrn = args[0]
761         else:
762             cred = user_cred
763             hrn = None
764
765         request_hash=None
766         if self.hashrequest:
767             arg_list = [cred, hrn]
768             request_hash = self.key.compute_hash(arg_list)  
769         result = server.get_resources(cred, hrn, request_hash)
770         format = opts.format
771        
772         display_rspec(result, format)
773         if (opts.file is not None):
774             file = opts.file
775             if not file.startswith(os.sep):
776                 file = os.path.join(self.options.sfi_dir, file)
777             save_rspec_to_file(result, file)
778         return
779     
780     # created named slice with given rspec
781     def create(self,opts, args):
782         slice_hrn = args[0]
783         user_cred = self.get_user_cred()
784         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
785         rspec_file = self.get_rspec_file(args[1])
786         rspec=open(rspec_file).read()
787         server = self.slicemgr
788         if opts.aggregate:
789             aggregates = self.registry.get_aggregates(user_cred, opts.aggregate)
790             if not aggregates:
791                 raise Exception, "No such aggregate %s" % opts.aggregate
792             aggregate = aggregates[0]
793             url = "http://%s:%s" % (aggregate['addr'], aggregate['port'])
794             server = GeniClient(url, self.key_file, self.cert_file, self.options.protocol)
795         request_hash=None
796         if self.hashrequest:
797             arg_list = [slice_cred, slice_hrn, rspec]
798             request_hash = self.key.compute_hash(arg_list) 
799         return server.create_slice(slice_cred, slice_hrn, rspec, request_hash)
800
801     # get a ticket for the specified slice
802     def get_ticket(self, opts, args):
803         slice_hrn, rspec_path = args[0], args[1]
804         user_cred = self.get_user_cred()
805         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
806         rspec_file = self.get_rspec_file(rspec_path) 
807         rspec=open(rspec_file).read()
808         server = self.slicemgr
809         if opts.aggregate:
810             aggregates = self.registry.get_aggregates(user_cred, opts.aggregate)
811             if not aggregates:
812                 raise Exception, "No such aggregate %s" % opts.aggregate
813             aggregate = aggregates[0]
814             url = "http://%s:%s" % (aggregate['addr'], aggregate['port'])
815             server = GeniClient(url, self.key_file, self.cert_file, self.options.protocol)
816         request_hash=None
817         if self.hashrequest:
818             arg_list = [slice_cred, slice_hrn, rspec]
819             request_hash = self.key.compute_hash(arg_list)
820         ticket_string = server.get_ticket(slice_cred, slice_hrn, rspec, request_hash)
821         file = os.path.join(self.options.sfi_dir, get_leaf(slice_hrn) + ".ticket")
822         print "writing ticket to ", file        
823         ticket = SfaTicket(string=ticket_string)
824         ticket.save_to_file(filename=file, save_parents=True)
825
826     def redeem_ticket(self, opts, args):
827         ticket, rspec = args[0], args[1]
828         # get a list node hostnames from the nodespecs in the rspec 
829         resource_spec = RSpec()
830         resource_spec.parseFile(rspec)
831         nodespecs = resource_spec.getDictsByTagName('NodeSpec')
832         hostnames = [nodespec['name'] for nodespec in nodespecs]
833         
834         # create an xmlrpc connection to the component manager at each of these
835         # components and gall redeem_ticket
836         connections = {}
837         for hostname in hostnames:
838             try:
839                 cm_port = "12346" 
840                 url = "https://%(hostname)s:%(cm_port)s" % locals() 
841                 print "Calling get_ticket at %(url)s " % locals(),  
842                 cm = xmlrpcprotocol.get_server(url, self.key_file, self.cert_file)
843                 cm.redeem_ticket(ticket)
844                 print "Success"
845             except socket.gaierror:
846                 print "Failed:",
847                 print "Componet Manager not accepting requests" 
848             except Exception, e:
849                 print "Failed:", e.message
850              
851         return
852  
853     # delete named slice
854     def delete(self,opts, args):
855         slice_hrn = args[0]
856         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
857         request_hash=None
858         if self.hashrequest:
859             arg_list = [slice_cred, slice_hrn]
860             request_hash = self.key.compute_hash(arg_list) 
861         return self.slicemgr.delete_slice(slice_cred, slice_hrn, request_hash)
862     
863     # start named slice
864     def start(self,opts, args):
865         slice_hrn = args[0]
866         slice_cred = self.get_slice_cred(args[0])
867         request_hash=None
868         if self.hashrequest:
869             arg_list = [slice_cred, slice_hrn]
870             request_hash = self.key.compute_hash(arg_list)
871         return self.slicemgr.start_slice(slice_cred, slice_hrn, request_hash)
872     
873     # stop named slice
874     def stop(self,opts, args):
875         slice_hrn = args[0]
876         slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
877         request_hash=None
878         if self.hashrequest:
879             arg_list = [slice_cred, slice_hrn]
880             request_hash = self.key.compute_hash(arg_list)
881         return self.slicemgr.stop_slice(slice_cred, slice_hrn, request_hash)
882     
883     # reset named slice
884     def reset(self,opts, args):
885         slice_hrn = args[0]
886         slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
887         request_hash=None
888         if self.hashrequest:
889             arg_list = [slice_cred, slice_hrn]
890             request_hash = self.key.compute_hash(arg_list)
891         return self.slicemgr.reset_slice(slice_cred, slice_hrn, request_hash)
892     
893     #
894     # Main: parse arguments and dispatch to command
895     #
896     def main(self):
897         parser = self.create_parser()
898         (options, args) = parser.parse_args()
899         self.options = options
900    
901         if options.hashrequest:
902             self.hashrequest=True
903  
904         if len(args) <= 0:
905             print "No command given. Use -h for help."
906             return -1
907     
908         command = args[0]
909         (cmd_opts, cmd_args) = self.create_cmd_parser(command).parse_args(args[1:])
910         if self.options.verbose :
911             print "Registry %s, sm %s, dir %s, user %s, auth %s" % (options.registry, options.sm,
912                                                                    options.sfi_dir, options.user,
913                                                                    options.auth)
914             print "Command %s" %command
915             if command in ("resources"):
916                 print "resources cmd_opts %s" %cmd_opts.format
917             elif command in ("list","show","remove"):
918                 print "cmd_opts.type %s" %cmd_opts.type
919             print "cmd_args %s" %cmd_args
920     
921         self.set_servers()
922     
923         try:
924             self.dispatch(command, cmd_opts, cmd_args)
925         except KeyError:
926             raise 
927             print "Command not found:", command
928             sys.exit(1)
929     
930         return
931     
932 if __name__=="__main__":
933    Sfi().main()