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