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