7faa4d548e82ddf8e0b912eeea538452bd779d69
[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(user_cred, hrn)
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(user_cred, hrn)
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(user_cred, hrn)
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(user_cred.save_to_string(save_parents=True), args[0])
562        records = filter_records("user", records)
563     
564        if not records:
565            print "Error: Didn't find a user record for", args[0]
566            return
567     
568        # the gid of the user who will be delegated to
569        delegee_gid = GID(string=records[0]['gid'])
570        delegee_hrn = delegee_gid.get_hrn()
571    
572        # the key and hrn of the user who will be delegating
573        user_key = Keypair(filename=self.get_key_file())
574        user_hrn = user_cred.get_gid_caller().get_hrn()
575        subject_string = "%s delegated to %s" % (object_hrn, delegee_hrn)
576        dcred = Credential(subject=subject_string)
577        dcred.set_gid_caller(delegee_gid)
578        dcred.set_gid_object(object_gid)
579        privs = object_cred.get_privileges()
580        dcred.set_privileges(object_cred.get_privileges())
581        dcred.get_privileges().delegate_all_privileges(True)
582        dcred.set_pubkey(object_gid.get_pubkey())
583        dcred.set_issuer(user_key, user_hrn)
584        dcred.set_parent(object_cred)
585        dcred.encode()
586        dcred.sign()
587     
588        if opts.delegate_user:
589            dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_" 
590                                   + get_leaf(object_hrn) + ".cred")
591        elif opts.delegate_slice:
592            dest_fn = os.path_join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_slice_" 
593                                   + get_leaf(object_hrn) + ".cred")
594     
595        dcred.save_to_file(dest_fn, save_parents=True)
596     
597        print "delegated credential for", object_hrn, "to", delegee_hrn, "and wrote to", dest_fn
598     
599     # removed named registry record
600     #   - have to first retrieve the record to be removed
601     def remove(self, opts, args):
602         auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
603         hrn = args[0]
604         type = opts.type 
605         if type in ['all']:
606             type = '*'
607         return self.registry.remove(auth_cred, type, hrn)
608     
609     # add named registry record
610     def add(self, opts, args):
611         auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
612         record_filepath = args[0]
613         rec_file = self.get_record_file(record_filepath)
614         record = load_record_from_file(rec_file).as_dict()
615         return self.registry.register(auth_cred, record)
616     
617     # update named registry entry
618     def update(self, opts, args):
619         user_cred = self.get_user_cred()
620         rec_file = self.get_record_file(args[0])
621         record = load_record_from_file(rec_file)
622         if record['type'] == "user":
623             if record.get_name() == user_cred.get_gid_object().get_hrn():
624                 cred = user_cred.save_to_string(save_parents=True)
625             else:
626                 cred = self.get_auth_cred().save_to_string(save_parents=True)
627         elif record['type'] in ["slice"]:
628             try:
629                 cred = self.get_slice_cred(record.get_name()).save_to_string(save_parents=True)
630             except ServerException, e:
631                # XXX smbaker -- once we have better error return codes, update this
632                # to do something better than a string compare
633                if "Permission error" in e.args[0]:
634                    cred = self.get_auth_cred().save_to_string(save_parents=True)
635                else:
636                    raise
637         elif record.get_type() in ["authority"]:
638             cred = self.get_auth_cred().save_to_string(save_parents=True)
639         elif record.get_type() == 'node':
640             cred = self.get_auth_cred().save_to_string(save_parents=True)
641         else:
642             raise "unknown record type" + record.get_type()
643         record = record.as_dict()
644         return self.registry.update(cred, record)
645   
646     def get_trusted_certs(self, opts, args):
647         """
648         return the trusted certs at this interface 
649         """ 
650         trusted_certs = self.registry.get_trusted_certs()
651         for trusted_cert in trusted_certs:
652             cert = Certificate(string=trusted_cert)
653             print cert.get_subject()
654         return 
655
656     def aggregates(self, opts, args):
657         """
658         return a list of details about known aggregates
659         """
660         user_cred = self.get_user_cred().save_to_string(save_parents=True)
661         hrn = None
662         if args:
663             hrn = args[0]
664
665         result = self.registry.get_aggregates(user_cred, hrn)
666         display_list(result)
667         return 
668
669     def registries(self, opts, args):
670         """
671         return a list of details about known registries
672         """
673         user_cred = self.get_user_cred().save_to_string(save_parents=True)
674         hrn = None
675         if args:
676             hrn = args[0]
677         result = self.registry.get_registries(user_cred, hrn)
678         display_list(result)
679         return
680
681  
682     # ==================================================================
683     # Slice-related commands
684     # ==================================================================
685     
686
687     def version(self, opts, args):
688         server = self.get_server_from_opts(opts)
689         
690         print server.GetVersion()
691
692     # list instantiated slices
693     def slices(self, opts, args):
694         """
695         list instantiated slices
696         """
697         user_cred = self.get_user_cred().save_to_string(save_parents=True)
698         server = self.get_server_from_opts(opts)
699         results = server.ListSlices([user_cred])
700         display_list(results)
701         return
702     
703     # show rspec for named slice
704     def resources(self, opts, args):
705         user_cred = self.get_user_cred().save_to_string(save_parents=True)
706         server = self.slicemgr
707         call_options = {}
708         server = self.get_server_from_opts(opts)
709         
710         if args:
711             cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
712             hrn = args[0]
713             call_options = {'geni_slice_urn': hrn_to_urn(hrn, 'slice')}
714         else:
715             cred = user_cred
716             hrn = None
717         
718         result = server.ListResources([cred], call_options)
719         format = opts.format
720         display_rspec(result, format)
721         if (opts.file is not None):
722             file = opts.file
723             if not file.startswith(os.sep):
724                 file = os.path.join(self.options.sfi_dir, file)
725             save_rspec_to_file(result, file)
726         return
727     
728     # created named slice with given rspec
729     def create(self, opts, args):
730         slice_hrn = args[0]
731         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
732         user_cred = self.get_user_cred()
733         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
734         rspec_file = self.get_rspec_file(args[1])
735         rspec = open(rspec_file).read()
736         server = self.get_server_from_opts(opts)
737         result =  server.CreateSliver(slice_urn, [slice_cred], rspec, [])
738         print result
739         return result
740
741     # get a ticket for the specified slice
742     def get_ticket(self, opts, args):
743         slice_hrn, rspec_path = args[0], args[1]
744         slice_urn = hrn_to_urn(slice_hrn, 'slice')
745         user_cred = self.get_user_cred()
746         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
747         rspec_file = self.get_rspec_file(rspec_path) 
748         rspec = open(rspec_file).read()
749         server = self.get_server_from_opts(opts)
750         ticket_string = server.GetTicket(slice_urn, [slice_cred], rspec, [])
751         file = os.path.join(self.options.sfi_dir, get_leaf(slice_hrn) + ".ticket")
752         print "writing ticket to ", file        
753         ticket = SfaTicket(string=ticket_string)
754         ticket.save_to_file(filename=file, save_parents=True)
755
756     def redeem_ticket(self, opts, args):
757         ticket_file = args[0]
758         
759         # get slice hrn from the ticket
760         # use this to get the right slice credential 
761         ticket = SfaTicket(filename=ticket_file)
762         ticket.decode()
763         slice_hrn = ticket.gidObject.get_hrn()
764         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
765         #slice_hrn = ticket.attributes['slivers'][0]['hrn']
766         user_cred = self.get_user_cred()
767         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
768         
769         # get a list of node hostnames from the RSpec 
770         tree = etree.parse(StringIO(ticket.rspec))
771         root = tree.getroot()
772         hostnames = root.xpath("./network/site/node/hostname/text()")
773         
774         # create an xmlrpc connection to the component manager at each of these
775         # components and gall redeem_ticket
776         connections = {}
777         for hostname in hostnames:
778             try:
779                 print "Calling redeem_ticket at %(hostname)s " % locals(),
780                 server = self.get_server(hostname, CM_PORT, self.key_file, \
781                                          self.cert_file, self.options.debug)
782                 server.RedeemTicket(ticket.save_to_string(save_parents=True), slice_cred)
783                 print "Success"
784             except socket.gaierror:
785                 print "Failed:",
786                 print "Componet Manager not accepting requests" 
787             except Exception, e:
788                 print "Failed:", e.message
789         return
790  
791     # delete named slice
792     def delete(self, opts, args):
793         slice_hrn = args[0]
794         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
795         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
796         server = self.get_server_from_opts(opts)
797         return server.DeleteSliver(slice_urn, [slice_cred])
798     
799     # start named slice
800     def start(self, opts, args):
801         slice_hrn = args[0]
802         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
803         slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
804         server = self.get_server_from_opts(opts)
805         return server.Start(slice_urn, [slice_cred])
806     
807     # stop named slice
808     def stop(self, opts, args):
809         slice_hrn = args[0]
810         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
811         slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
812         server = self.get_server_from_opts(opts)
813         return server.Stop(slice_urn, [slice_cred])
814     
815     # reset named slice
816     def reset(self, opts, args):
817         slice_hrn = args[0]
818         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
819         server = self.get_server_from_opts(opts)
820         slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
821         return server.reset_slice(slice_cred, slice_urn)
822
823     def renew(self, opts, args):
824         slice_hrn = args[0]
825         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
826         server = self.get_server_from_opts(opts)
827         slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
828         time = args[1]
829         return server.RenewSliver(slice_urn, [slice_cred], time)
830
831
832     def status(self, opts, args):
833         slice_hrn = args[0]
834         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
835         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
836         server = self.get_server_from_opts(opts)
837         print server.SliverStatus(slice_urn, [slice_cred])
838
839
840     def shutdown(self, opts, args):
841         slice_hrn = args[0]
842         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
843         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
844         server = self.get_server_from_opts(opts)
845         return server.Shutdown(slice_urn, [slice_cred])         
846     
847     #
848     # Main: parse arguments and dispatch to command
849     #
850     def main(self):
851         parser = self.create_parser()
852         (options, args) = parser.parse_args()
853         self.options = options
854    
855         if options.hashrequest:
856             self.hashrequest = True
857  
858         if len(args) <= 0:
859             print "No command given. Use -h for help."
860             return - 1
861     
862         command = args[0]
863         (cmd_opts, cmd_args) = self.create_cmd_parser(command).parse_args(args[1:])
864         if self.options.verbose :
865             print "Registry %s, sm %s, dir %s, user %s, auth %s" % (options.registry, options.sm,
866                                                                    options.sfi_dir, options.user,
867                                                                    options.auth)
868             print "Command %s" % command
869             if command in ("resources"):
870                 print "resources cmd_opts %s" % cmd_opts.format
871             elif command in ("list", "show", "remove"):
872                 print "cmd_opts.type %s" % cmd_opts.type
873             print "cmd_args %s" % cmd_args
874     
875         self.set_servers()
876     
877         try:
878             self.dispatch(command, cmd_opts, cmd_args)
879         except KeyError:
880             raise 
881             print "Command not found:", command
882             sys.exit(1)
883     
884         return
885     
886 if __name__ == "__main__":
887    Sfi().main()