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