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