aded get_gid() and get_cached_gid() helper methods.
[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_gid(self, file):
356         """
357         Return a cached gid    
358         """
359         gid = None 
360         if (os.path.isfile(file)):
361             gid = GID(filename=file)
362         return gid
363
364     def get_gid(self, hrn):
365         gidfile = os.path.join(self.options.sfi_dir, hrn + ".gid")
366         gid = self.get_cached_gid(gidfile)
367         if not gid:
368             user_cred = self.get_user_cred()
369             records = self.registry.Resolve(hrn, user_cred.save_to_string(save_parents=True))
370             if not records:
371                 raise RecordNotFound(args[0])
372             gid = GID(string=records[0]['gid'])
373             if self.options.verbose:
374                 print "Writing gid to ", gidfile 
375             gid.save_to_file(filename=gidfile)
376         return gid   
377                 
378      
379     def get_cached_credential(self, file):
380         """
381         Return a cached credential only if it hasn't expired.
382         """
383         if (os.path.isfile(file)):
384             credential = Credential(filename=file)
385             # make sure it isnt expired 
386             if not credential.get_lifetime or \
387                datetime.datetime.today() < credential.get_lifetime():
388                 return credential
389         return None 
390  
391     def get_user_cred(self):
392         #file = os.path.join(self.options.sfi_dir, get_leaf(self.user) + ".cred")
393         file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cred")
394         return self.get_cred(file, 'user', self.user)
395
396     def get_auth_cred(self):
397         if not self.authority:
398             print "no authority specified. Use -a or set SF_AUTH"
399             sys.exit(-1)
400         file = os.path.join(self.options.sfi_dir, get_leaf("authority") + ".cred")
401         return self.get_cred(file, 'authority', self.authority)
402
403     def get_slice_cred(self, name):
404         file = os.path.join(self.options.sfi_dir, "slice_" + get_leaf(name) + ".cred")
405         return self.get_cred(file, 'slice', name)
406  
407     def get_cred(self, file, type, hrn):
408         # attempt to load a cached credential 
409         cred = self.get_cached_credential(file)    
410         if not cred:
411             if type in ['user']:
412                 cert_string = self.cert.save_to_string(save_parents=True)
413                 user_name = self.user.replace(self.authority + ".", '')
414                 if user_name.count(".") > 0:
415                     user_name = user_name.replace(".", '_')
416                     self.user = self.authority + "." + user_name
417                 cred_str = self.registry.get_self_credential(cert_string, "user", hrn)
418             else:
419                 # bootstrap slice credential from user credential
420                 user_cred = self.get_user_cred().save_to_string(save_parents=True)
421                 cred_str = self.registry.get_credential(user_cred, type, hrn)
422             
423             if not cred_str:
424                 print "Failed to get %s credential" % (type)
425                 sys.exit(-1)
426                 
427             cred = Credential(string=cred_str)
428             cred.save_to_file(file, save_parents=True)
429             if self.options.verbose:
430                 print "Writing %s credential to %s" %(type, file)
431
432         return cred
433  
434     
435     def get_rspec_file(self, rspec):
436        if (os.path.isabs(rspec)):
437           file = rspec
438        else:
439           file = os.path.join(self.options.sfi_dir, rspec)
440        if (os.path.isfile(file)):
441           return file
442        else:
443           print "No such rspec file", rspec
444           sys.exit(1)
445     
446     def get_record_file(self, record):
447        if (os.path.isabs(record)):
448           file = record
449        else:
450           file = os.path.join(self.options.sfi_dir, record)
451        if (os.path.isfile(file)):
452           return file
453        else:
454           print "No such registry record file", record
455           sys.exit(1)
456     
457     def load_publickey_string(self, fn):
458        f = file(fn, "r")
459        key_string = f.read()
460     
461        # if the filename is a private key file, then extract the public key
462        if "PRIVATE KEY" in key_string:
463            outfn = tempfile.mktemp()
464            cmd = "openssl rsa -in " + fn + " -pubout -outform PEM -out " + outfn
465            os.system(cmd)
466            f = file(outfn, "r")
467            key_string = f.read()
468            os.remove(outfn)
469     
470        return key_string
471
472     def get_component_server_from_hrn(self, hrn):
473         # direct connection to the nodes component manager interface
474         user_cred = self.get_user_cred().save_to_string(save_parents=True)
475         records = self.registry.Resolve(hrn, user_cred)
476         records = filter_records('node', records)
477         if not records:
478             print "No such component:", opts.component
479         record = records[0]
480   
481         return self.get_server(record['hostname'], CM_PORT, self.key_file, \
482                                self.cert_file, self.options.debug)
483  
484     def get_server(self, host, port, keyfile, certfile, debug):
485         """
486         Return an instnace of an xmlrpc server connection    
487         """
488         url = "http://%s:%s" % (host, port)
489         return xmlrpcprotocol.get_server(url, keyfile, certfile, debug)
490
491     def get_server_from_opts(self, opts):
492         """
493         Return instance of an xmlrpc connection to a slice manager, aggregate
494         or component server depending on the specified opts
495         """
496         server = self.slicemgr
497         # direct connection to an aggregate
498         if hasattr(opts, 'aggregate') and opts.aggregate:
499             server = self.get_server(opts.aggregate, opts.port, self.key_file, \
500                                      self.cert_file, self.options.debug)
501         # direct connection to the nodes component manager interface
502         if hasattr(opts, 'component') and opts.component:
503             server = self.get_component_server_from_hrn(opts.component)    
504  
505         return server
506     #==========================================================================
507     # Following functions implement the commands
508     #
509     # Registry-related commands
510     #==========================================================================
511   
512     def dispatch(self, command, cmd_opts, cmd_args):
513         getattr(self, command)(cmd_opts, cmd_args)
514  
515     # list entires in named authority registry
516     def list(self, opts, args):
517         user_cred = self.get_user_cred().save_to_string(save_parents=True)
518         hrn = args[0]
519         try:
520             list = self.registry.List(hrn, user_cred)
521         except IndexError:
522             raise Exception, "Not enough parameters for the 'list' command"
523           
524         # filter on person, slice, site, node, etc.  
525         # THis really should be in the self.filter_records funct def comment...
526         list = filter_records(opts.type, list)
527         for record in list:
528             print "%s (%s)" % (record['hrn'], record['type'])     
529         if opts.file:
530             file = opts.file
531             if not file.startswith(os.sep):
532                 file = os.path.join(self.options.sfi_dir, file)
533             save_records_to_file(file, list)
534         return
535     
536     # show named registry record
537     def show(self, opts, args):
538         user_cred = self.get_user_cred().save_to_string(save_parents=True)
539         hrn = args[0]
540         records = self.registry.Resolve(hrn, user_cred)
541         records = filter_records(opts.type, records)
542         if not records:
543             print "No record of type", opts.type
544         for record in records:
545             if record['type'] in ['user']:
546                 record = UserRecord(dict=record)
547             elif record['type'] in ['slice']:
548                 record = SliceRecord(dict=record)
549             elif record['type'] in ['node']:
550                 record = NodeRecord(dict=record)
551             elif record['type'] in ['authority', 'ma', 'sa']:
552                 record = AuthorityRecord(dict=record)
553             else:
554                 record = SfaRecord(dict=record)
555             if (opts.format == "text"): 
556                 record.dump()  
557             else:
558                 print record.save_to_string() 
559        
560         if opts.file:
561             file = opts.file
562             if not file.startswith(os.sep):
563                 file = os.path.join(self.options.sfi_dir, file)
564             save_records_to_file(file, records)
565         return
566     
567     def delegate(self, opts, args):
568         user_cred = self.get_user_cred()
569         if opts.delegate_user:
570             object_cred = user_cred
571         elif opts.delegate_slice:
572             object_cred = self.get_slice_cred(opts.delegate_slice)
573         else:
574             print "Must specify either --user or --slice <hrn>"
575             return
576     
577         # the gid and hrn of the object we are delegating
578         object_gid = object_cred.get_gid_object()
579         object_hrn = object_gid.get_hrn()
580     
581         if not object_cred.get_privileges().get_all_delegate():
582             print "Error: Object credential", object_hrn, "does not have delegate bit set"
583             return
584     
585         # the gid of the user who will be delegated to
586         delegee_gid = self.get_gid(args[0])
587         delegee_hrn = delegee_gid.get_hrn()
588         delegee_gidfile = os.path.join(self.options.sfi_dir, delegee_hrn + ".gid")
589         delegee_gid.save_to_file(filename=delegee_gidfile)
590         dcred = object_cred.delegate(delegee_gidfile, self.get_key_file())
591     
592         if opts.delegate_user:
593             dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_" 
594                                   + get_leaf(object_hrn) + ".cred")
595         elif opts.delegate_slice:
596             dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_slice_" 
597                                   + get_leaf(object_hrn) + ".cred")
598     
599         dcred.save_to_file(dest_fn, save_parents=True)
600     
601         print "delegated credential for", object_hrn, "to", delegee_hrn, "and wrote to", dest_fn
602     
603     # removed named registry record
604     #   - have to first retrieve the record to be removed
605     def remove(self, opts, args):
606         auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
607         hrn = args[0]
608         type = opts.type 
609         if type in ['all']:
610             type = '*'
611         return self.registry.Remove(hrn, auth_cred, type)
612     
613     # add named registry record
614     def add(self, opts, args):
615         auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
616         record_filepath = args[0]
617         rec_file = self.get_record_file(record_filepath)
618         record = load_record_from_file(rec_file).as_dict()
619         return self.registry.Register(record, auth_cred)
620     
621     # update named registry entry
622     def update(self, opts, args):
623         user_cred = self.get_user_cred()
624         rec_file = self.get_record_file(args[0])
625         record = load_record_from_file(rec_file)
626         if record['type'] == "user":
627             if record.get_name() == user_cred.get_gid_object().get_hrn():
628                 cred = user_cred.save_to_string(save_parents=True)
629             else:
630                 cred = self.get_auth_cred().save_to_string(save_parents=True)
631         elif record['type'] in ["slice"]:
632             try:
633                 cred = self.get_slice_cred(record.get_name()).save_to_string(save_parents=True)
634             except ServerException, e:
635                # XXX smbaker -- once we have better error return codes, update this
636                # to do something better than a string compare
637                if "Permission error" in e.args[0]:
638                    cred = self.get_auth_cred().save_to_string(save_parents=True)
639                else:
640                    raise
641         elif record.get_type() in ["authority"]:
642             cred = self.get_auth_cred().save_to_string(save_parents=True)
643         elif record.get_type() == 'node':
644             cred = self.get_auth_cred().save_to_string(save_parents=True)
645         else:
646             raise "unknown record type" + record.get_type()
647         record = record.as_dict()
648         return self.registry.Update(record, cred)
649   
650     def get_trusted_certs(self, opts, args):
651         """
652         return uhe trusted certs at this interface 
653         """ 
654         trusted_certs = self.registry.get_trusted_certs()
655         for trusted_cert in trusted_certs:
656             cert = Certificate(string=trusted_cert)
657             print cert.get_subject()
658         return 
659
660     def aggregates(self, opts, args):
661         """
662         return a list of details about known aggregates
663         """
664         user_cred = self.get_user_cred().save_to_string(save_parents=True)
665         hrn = None
666         if args:
667             hrn = args[0]
668
669         result = self.registry.get_aggregates(user_cred, hrn)
670         display_list(result)
671         return 
672
673     def registries(self, opts, args):
674         """
675         return a list of details about known registries
676         """
677         user_cred = self.get_user_cred().save_to_string(save_parents=True)
678         hrn = None
679         if args:
680             hrn = args[0]
681         result = self.registry.get_registries(user_cred, hrn)
682         display_list(result)
683         return
684
685  
686     # ==================================================================
687     # Slice-related commands
688     # ==================================================================
689     
690
691     def version(self, opts, args):
692         server = self.get_server_from_opts(opts)
693         
694         print server.GetVersion()
695
696     # list instantiated slices
697     def slices(self, opts, args):
698         """
699         list instantiated slices
700         """
701         user_cred = self.get_user_cred().save_to_string(save_parents=True)
702         server = self.get_server_from_opts(opts)
703         results = server.ListSlices([user_cred])
704         display_list(results)
705         return
706     
707     # show rspec for named slice
708     def resources(self, opts, args):
709         user_cred = self.get_user_cred().save_to_string(save_parents=True)
710         server = self.slicemgr
711         call_options = {}
712         server = self.get_server_from_opts(opts)
713         
714         if args:
715             cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
716             hrn = args[0]
717             call_options = {'geni_slice_urn': hrn_to_urn(hrn, 'slice')}
718         else:
719             cred = user_cred
720             hrn = None
721         
722         result = server.ListResources([cred], call_options)
723         format = opts.format
724         display_rspec(result, format)
725         if (opts.file is not None):
726             file = opts.file
727             if not file.startswith(os.sep):
728                 file = os.path.join(self.options.sfi_dir, file)
729             save_rspec_to_file(result, file)
730         return
731     
732     # created named slice with given rspec
733     def create(self, opts, args):
734         slice_hrn = args[0]
735         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
736         user_cred = self.get_user_cred()
737         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
738         rspec_file = self.get_rspec_file(args[1])
739         rspec = open(rspec_file).read()
740         server = self.get_server_from_opts(opts)
741         result =  server.CreateSliver(slice_urn, [slice_cred], rspec, [])
742         print result
743         return result
744
745     # get a ticket for the specified slice
746     def get_ticket(self, opts, args):
747         slice_hrn, rspec_path = args[0], args[1]
748         slice_urn = hrn_to_urn(slice_hrn, 'slice')
749         user_cred = self.get_user_cred()
750         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
751         rspec_file = self.get_rspec_file(rspec_path) 
752         rspec = open(rspec_file).read()
753         server = self.get_server_from_opts(opts)
754         ticket_string = server.GetTicket(slice_urn, [slice_cred], rspec, [])
755         file = os.path.join(self.options.sfi_dir, get_leaf(slice_hrn) + ".ticket")
756         print "writing ticket to ", file        
757         ticket = SfaTicket(string=ticket_string)
758         ticket.save_to_file(filename=file, save_parents=True)
759
760     def redeem_ticket(self, opts, args):
761         ticket_file = args[0]
762         
763         # get slice hrn from the ticket
764         # use this to get the right slice credential 
765         ticket = SfaTicket(filename=ticket_file)
766         ticket.decode()
767         slice_hrn = ticket.gidObject.get_hrn()
768         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
769         #slice_hrn = ticket.attributes['slivers'][0]['hrn']
770         user_cred = self.get_user_cred()
771         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
772         
773         # get a list of node hostnames from the RSpec 
774         tree = etree.parse(StringIO(ticket.rspec))
775         root = tree.getroot()
776         hostnames = root.xpath("./network/site/node/hostname/text()")
777         
778         # create an xmlrpc connection to the component manager at each of these
779         # components and gall redeem_ticket
780         connections = {}
781         for hostname in hostnames:
782             try:
783                 print "Calling redeem_ticket at %(hostname)s " % locals(),
784                 server = self.get_server(hostname, CM_PORT, self.key_file, \
785                                          self.cert_file, self.options.debug)
786                 server.RedeemTicket(ticket.save_to_string(save_parents=True), slice_cred)
787                 print "Success"
788             except socket.gaierror:
789                 print "Failed:",
790                 print "Componet Manager not accepting requests" 
791             except Exception, e:
792                 print "Failed:", e.message
793         return
794  
795     # delete named slice
796     def delete(self, opts, args):
797         slice_hrn = args[0]
798         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
799         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
800         server = self.get_server_from_opts(opts)
801         return server.DeleteSliver(slice_urn, [slice_cred])
802     
803     # start named slice
804     def start(self, opts, args):
805         slice_hrn = args[0]
806         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
807         slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
808         server = self.get_server_from_opts(opts)
809         return server.Start(slice_urn, [slice_cred])
810     
811     # stop named slice
812     def stop(self, opts, args):
813         slice_hrn = args[0]
814         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
815         slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
816         server = self.get_server_from_opts(opts)
817         return server.Stop(slice_urn, [slice_cred])
818     
819     # reset named slice
820     def reset(self, opts, args):
821         slice_hrn = args[0]
822         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
823         server = self.get_server_from_opts(opts)
824         slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
825         return server.reset_slice(slice_cred, slice_urn)
826
827     def renew(self, opts, args):
828         slice_hrn = args[0]
829         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
830         server = self.get_server_from_opts(opts)
831         slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
832         time = args[1]
833         return server.RenewSliver(slice_urn, [slice_cred], time)
834
835
836     def status(self, opts, args):
837         slice_hrn = args[0]
838         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
839         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
840         server = self.get_server_from_opts(opts)
841         print server.SliverStatus(slice_urn, [slice_cred])
842
843
844     def shutdown(self, opts, args):
845         slice_hrn = args[0]
846         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
847         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
848         server = self.get_server_from_opts(opts)
849         return server.Shutdown(slice_urn, [slice_cred])         
850     
851     #
852     # Main: parse arguments and dispatch to command
853     #
854     def main(self):
855         parser = self.create_parser()
856         (options, args) = parser.parse_args()
857         self.options = options
858    
859         if options.hashrequest:
860             self.hashrequest = True
861  
862         if len(args) <= 0:
863             print "No command given. Use -h for help."
864             return - 1
865     
866         command = args[0]
867         (cmd_opts, cmd_args) = self.create_cmd_parser(command).parse_args(args[1:])
868         if self.options.verbose :
869             print "Registry %s, sm %s, dir %s, user %s, auth %s" % (options.registry, options.sm,
870                                                                    options.sfi_dir, options.user,
871                                                                    options.auth)
872             print "Command %s" % command
873             if command in ("resources"):
874                 print "resources cmd_opts %s" % cmd_opts.format
875             elif command in ("list", "show", "remove"):
876                 print "cmd_opts.type %s" % cmd_opts.type
877             print "cmd_args %s" % cmd_args
878     
879         self.set_servers()
880     
881         try:
882             self.dispatch(command, cmd_opts, cmd_args)
883         except KeyError:
884             raise 
885             print "Command not found:", command
886             sys.exit(1)
887     
888         return
889     
890 if __name__ == "__main__":
891    Sfi().main()