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