extend GetVersion to expose:
[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         if command in ("version"):
215             parser.add_option("-R","--registry-version",
216                               action="store_true", dest="probe_registry", default=False,
217                               help="probe registry version instead of slicemgr")
218
219         return parser
220
221         
222     def create_parser(self):
223
224         # Generate command line parser
225         parser = OptionParser(usage="sfi [options] command [command_options] [command_args]",
226                              description="Commands: gid,list,show,remove,add,update,nodes,slices,resources,create,delete,start,stop,reset")
227         parser.add_option("-r", "--registry", dest="registry",
228                          help="root registry", metavar="URL", default=None)
229         parser.add_option("-s", "--slicemgr", dest="sm",
230                          help="slice manager", metavar="URL", default=None)
231         default_sfi_dir = os.path.expanduser("~/.sfi/")
232         parser.add_option("-d", "--dir", dest="sfi_dir",
233                          help="config & working directory - default is " + default_sfi_dir,
234                          metavar="PATH", default=default_sfi_dir)
235         parser.add_option("-u", "--user", dest="user",
236                          help="user name", metavar="HRN", default=None)
237         parser.add_option("-a", "--auth", dest="auth",
238                          help="authority name", metavar="HRN", default=None)
239         parser.add_option("-v", "--verbose", action="count", dest="verbose", default=0,
240                          help="verbose mode - cumulative")
241         parser.add_option("-D", "--debug",
242                           action="store_true", dest="debug", default=False,
243                           help="Debug (xml-rpc) protocol messages")
244         parser.add_option("-p", "--protocol", dest="protocol", default="xmlrpc",
245                          help="RPC protocol (xmlrpc or soap)")
246         parser.add_option("-k", "--hashrequest",
247                          action="store_true", dest="hashrequest", default=False,
248                          help="Create a hash of the request that will be authenticated on the server")
249         parser.disable_interspersed_args()
250
251         return parser
252         
253  
254     #
255     # Establish Connection to SliceMgr and Registry Servers
256     #
257     def set_servers(self):
258        config_file = self.options.sfi_dir + os.sep + "sfi_config"
259        try:
260           config = Config (config_file)
261        except:
262           self.logger.critical("Failed to read configuration file %s"%config_file)
263           self.logger.info("Make sure to remove the export clauses and to add quotes")
264           if self.options.verbose==0:
265               self.logger.info("Re-run with -v for more details")
266           else:
267               self.logger.log_exc("Could not read config file %s"%config_file)
268           sys.exit(1)
269     
270        errors = 0
271        # Set SliceMgr URL
272        if (self.options.sm is not None):
273           sm_url = self.options.sm
274        elif hasattr(config, "SFI_SM"):
275           sm_url = config.SFI_SM
276        else:
277           self.logger.error("You need to set e.g. SFI_SM='http://your.slicemanager.url:12347/' in %s" % config_file)
278           errors += 1 
279     
280        # Set Registry URL
281        if (self.options.registry is not None):
282           reg_url = self.options.registry
283        elif hasattr(config, "SFI_REGISTRY"):
284           reg_url = config.SFI_REGISTRY
285        else:
286           self.logger.errors("You need to set e.g. SFI_REGISTRY='http://your.registry.url:12345/' in %s" % config_file)
287           errors += 1 
288           
289
290        # Set user HRN
291        if (self.options.user is not None):
292           self.user = self.options.user
293        elif hasattr(config, "SFI_USER"):
294           self.user = config.SFI_USER
295        else:
296           self.logger.errors("You need to set e.g. SFI_USER='plc.princeton.username' in %s" % config_file)
297           errors += 1 
298     
299        # Set authority HRN
300        if (self.options.auth is not None):
301           self.authority = self.options.auth
302        elif hasattr(config, "SFI_AUTH"):
303           self.authority = config.SFI_AUTH
304        else:
305           self.logger.error("You need to set e.g. SFI_AUTH='plc.princeton' in %s" % config_file)
306           errors += 1 
307     
308        if errors:
309           sys.exit(1)
310     
311     
312        # Get key and certificate
313        key_file = self.get_key_file()
314        cert_file = self.get_cert_file(key_file)
315        self.key = Keypair(filename=key_file) 
316        self.key_file = key_file
317        self.cert_file = cert_file
318        self.cert = Certificate(filename=cert_file) 
319        # Establish connection to server(s)
320        self.logger.info("Contacting Registry at: %s"%reg_url)
321        self.registry = xmlrpcprotocol.get_server(reg_url, key_file, cert_file, self.options)  
322        self.logger.info("Contacting Slice Manager at: %s"%sm_url)
323        self.slicemgr = xmlrpcprotocol.get_server(sm_url, key_file, cert_file, self.options)
324
325        return
326     
327     #
328     # Get various credential and spec files
329     #
330     # Establishes limiting conventions
331     #   - conflates MAs and SAs
332     #   - assumes last token in slice name is unique
333     #
334     # Bootstraps credentials
335     #   - bootstrap user credential from self-signed certificate
336     #   - bootstrap authority credential from user credential
337     #   - bootstrap slice credential from user credential
338     #
339     
340     
341     def get_key_file(self):
342        file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".pkey")
343        if (os.path.isfile(file)):
344           return file
345        else:
346           self.logger.error("Key file %s does not exist"%file)
347           sys.exit(-1)
348        return
349     
350     def get_cert_file(self, key_file):
351     
352         file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cert")
353         if (os.path.isfile(file)):
354             # use existing cert if it exists                     
355             return file
356         else:
357             try:
358                 # attempt to use gid as the cert.  
359                 gid = self._get_gid()
360                 self.logger.info("Writing certificate to %s"%file)
361                 gid.save_to_file(file) 
362             except:
363                 # generate self signed certificate
364                 k = Keypair(filename=key_file)
365                 cert = Certificate(subject=self.user)
366                 cert.set_pubkey(k)
367                 cert.set_issuer(k, self.user)
368                 cert.sign()
369                 self.logger.info("Writing self-signed certificate to %s"%file)
370                 cert.save_to_file(file)
371             
372             return file
373
374     def get_cached_gid(self, file):
375         """
376         Return a cached gid    
377         """
378         gid = None 
379         if (os.path.isfile(file)):
380             gid = GID(filename=file)
381         return gid
382
383     # xxx opts unused
384     def get_gid(self, opts, args):
385         """
386         Get the specify gid and save it to file
387         """
388         hrn = None
389         if args:
390             hrn = args[0]
391         gid = self._get_gid(hrn)
392         self.logger.debug("Sfi.get_gid-> %s",gid.save_to_string(save_parents=True))
393         return gid
394
395     def _get_gid(self, hrn=None):
396         """
397         git_gid helper. Retrive the gid from the registry and save it to file.
398         """
399         
400         if not hrn:
401             hrn = self.user
402  
403         gidfile = os.path.join(self.options.sfi_dir, hrn + ".gid")
404         gid = self.get_cached_gid(gidfile)
405         if not gid:
406             user_cred = self.get_user_cred()
407             records = self.registry.Resolve(hrn, user_cred.save_to_string(save_parents=True))
408             if not records:
409                 raise RecordNotFound(args[0])
410             gid = GID(string=records[0]['gid'])
411             self.logger.info("Writing gid to %s"%gidfile)
412             gid.save_to_file(filename=gidfile)
413         return gid   
414                 
415      
416     def get_cached_credential(self, file):
417         """
418         Return a cached credential only if it hasn't expired.
419         """
420         if (os.path.isfile(file)):
421             credential = Credential(filename=file)
422             # make sure it isnt expired 
423             if not credential.get_expiration or \
424                datetime.datetime.today() < credential.get_expiration():
425                 return credential
426         return None 
427  
428     def get_user_cred(self):
429         file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cred")
430         return self.get_cred(file, 'user', self.user)
431
432     def get_auth_cred(self):
433         if not self.authority:
434             self.logger.critical("no authority specified. Use -a or set SF_AUTH")
435             sys.exit(-1)
436         file = os.path.join(self.options.sfi_dir, self.authority + ".cred")
437         return self.get_cred(file, 'authority', self.authority)
438
439     def get_slice_cred(self, name):
440         file = os.path.join(self.options.sfi_dir, "slice_" + get_leaf(name) + ".cred")
441         return self.get_cred(file, 'slice', name)
442  
443     def get_cred(self, file, type, hrn):
444         # attempt to load a cached credential 
445         cred = self.get_cached_credential(file)    
446         if not cred:
447             if type in ['user']:
448                 cert_string = self.cert.save_to_string(save_parents=True)
449                 user_name = self.user.replace(self.authority + ".", '')
450                 if user_name.count(".") > 0:
451                     user_name = user_name.replace(".", '_')
452                     self.user = self.authority + "." + user_name
453                 cred_str = self.registry.GetSelfCredential(cert_string, hrn, "user")
454             else:
455                 # bootstrap slice credential from user credential
456                 user_cred = self.get_user_cred().save_to_string(save_parents=True)
457                 cred_str = self.registry.GetCredential(user_cred, hrn, type)
458             
459             if not cred_str:
460                 self.logger.critical("Failed to get %s credential" % type)
461                 sys.exit(-1)
462                 
463             cred = Credential(string=cred_str)
464             cred.save_to_file(file, save_parents=True)
465             self.logger.info("Writing %s credential to %s" %(type, file))
466
467         return cred
468  
469     
470     def get_rspec_file(self, rspec):
471        if (os.path.isabs(rspec)):
472           file = rspec
473        else:
474           file = os.path.join(self.options.sfi_dir, rspec)
475        if (os.path.isfile(file)):
476           return file
477        else:
478           self.logger.critical("No such rspec file"%rspec)
479           sys.exit(1)
480     
481     def get_record_file(self, record):
482        if (os.path.isabs(record)):
483           file = record
484        else:
485           file = os.path.join(self.options.sfi_dir, record)
486        if (os.path.isfile(file)):
487           return file
488        else:
489           self.logger.critical("No such registry record file %s"%record)
490           sys.exit(1)
491     
492     def load_publickey_string(self, fn):
493        f = file(fn, "r")
494        key_string = f.read()
495     
496        # if the filename is a private key file, then extract the public key
497        if "PRIVATE KEY" in key_string:
498            outfn = tempfile.mktemp()
499            cmd = "openssl rsa -in " + fn + " -pubout -outform PEM -out " + outfn
500            os.system(cmd)
501            f = file(outfn, "r")
502            key_string = f.read()
503            os.remove(outfn)
504     
505        return key_string
506
507     # xxx opts undefined
508     def get_component_server_from_hrn(self, hrn):
509         # direct connection to the nodes component manager interface
510         user_cred = self.get_user_cred().save_to_string(save_parents=True)
511         records = self.registry.Resolve(hrn, user_cred)
512         records = filter_records('node', records)
513         if not records:
514             self.logger.warning("No such component:%r"% opts.component)
515         record = records[0]
516   
517         return self.get_server(record['hostname'], CM_PORT, self.key_file, self.cert_file)
518  
519     def get_server(self, host, port, keyfile, certfile):
520         """
521         Return an instance of an xmlrpc server connection    
522         """
523         # port is appended onto the domain, before the path. Should look like:
524         # http://domain:port/path
525         host_parts = host.split('/')
526         host_parts[0] = host_parts[0] + ":" + str(port)
527         url =  "http://%s" %  "/".join(host_parts)    
528         return xmlrpcprotocol.get_server(url, keyfile, certfile, self.options)
529
530     # xxx opts could be retrieved in self.options
531     def get_server_from_opts(self, opts):
532         """
533         Return instance of an xmlrpc connection to a slice manager, aggregate
534         or component server depending on the specified opts
535         """
536         server = self.slicemgr
537         # direct connection to an aggregate
538         if hasattr(opts, 'aggregate') and opts.aggregate:
539             server = self.get_server(opts.aggregate, opts.port, self.key_file, self.cert_file)
540         # direct connection to the nodes component manager interface
541         if hasattr(opts, 'component') and opts.component:
542             server = self.get_component_server_from_hrn(opts.component)    
543  
544         return server
545     #==========================================================================
546     # Following functions implement the commands
547     #
548     # Registry-related commands
549     #==========================================================================
550   
551     def dispatch(self, command, cmd_opts, cmd_args):
552         return getattr(self, command)(cmd_opts, cmd_args)
553  
554     # list entires in named authority registry
555     def list(self, opts, args):
556         if len(args)!= 1:
557             self.parser.print_help()
558             sys.exit(1)
559         hrn = args[0]
560         user_cred = self.get_user_cred().save_to_string(save_parents=True)
561         try:
562             list = self.registry.List(hrn, user_cred)
563         except IndexError:
564             raise Exception, "Not enough parameters for the 'list' command"
565           
566         # filter on person, slice, site, node, etc.  
567         # THis really should be in the self.filter_records funct def comment...
568         list = filter_records(opts.type, list)
569         for record in list:
570             print "%s (%s)" % (record['hrn'], record['type'])     
571         if opts.file:
572             file = opts.file
573             if not file.startswith(os.sep):
574                 file = os.path.join(self.options.sfi_dir, file)
575             save_records_to_file(file, list)
576         return
577     
578     # show named registry record
579     def show(self, opts, args):
580         if len(args)!= 1:
581             self.parser.print_help()
582             sys.exit(1)
583         hrn = args[0]
584         user_cred = self.get_user_cred().save_to_string(save_parents=True)
585         records = self.registry.Resolve(hrn, user_cred)
586         records = filter_records(opts.type, records)
587         if not records:
588             print "No record of type", opts.type
589         for record in records:
590             if record['type'] in ['user']:
591                 record = UserRecord(dict=record)
592             elif record['type'] in ['slice']:
593                 record = SliceRecord(dict=record)
594             elif record['type'] in ['node']:
595                 record = NodeRecord(dict=record)
596             elif record['type'] in ['authority', 'ma', 'sa']:
597                 record = AuthorityRecord(dict=record)
598             else:
599                 record = SfaRecord(dict=record)
600             if (opts.format == "text"): 
601                 record.dump()  
602             else:
603                 print record.save_to_string() 
604        
605         if opts.file:
606             file = opts.file
607             if not file.startswith(os.sep):
608                 file = os.path.join(self.options.sfi_dir, file)
609             save_records_to_file(file, records)
610         return
611     
612     def delegate(self, opts, args):
613
614         delegee_hrn = args[0]
615         if opts.delegate_user:
616             user_cred = self.get_user_cred()
617             cred = self.delegate_cred(user_cred, delegee_hrn)
618         elif opts.delegate_slice:
619             slice_cred = self.get_slice_cred(opts.delegate_slice)
620             cred = self.delegate_cred(slice_cred, delegee_hrn)
621         else:
622             self.logger.warning("Must specify either --user or --slice <hrn>")
623             return
624         delegated_cred = Credential(string=cred)
625         object_hrn = delegated_cred.get_gid_object().get_hrn()
626         if opts.delegate_user:
627             dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_"
628                                   + get_leaf(object_hrn) + ".cred")
629         elif opts.delegate_slice:
630             dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_slice_"
631                                   + get_leaf(object_hrn) + ".cred")
632
633         delegated_cred.save_to_file(dest_fn, save_parents=True)
634
635         self.logger.info("delegated credential for %s to %s and wrote to %s"%(object_hrn, delegee_hrn,dest_fn))
636     
637     def delegate_cred(self, object_cred, hrn):
638         # the gid and hrn of the object we are delegating
639         if isinstance(object_cred, str):
640             object_cred = Credential(string=object_cred) 
641         object_gid = object_cred.get_gid_object()
642         object_hrn = object_gid.get_hrn()
643     
644         if not object_cred.get_privileges().get_all_delegate():
645             self.logger.error("Object credential %s does not have delegate bit set"%object_hrn)
646             return
647
648         # the delegating user's gid
649         caller_gid = self._get_gid(self.user)
650         caller_gidfile = os.path.join(self.options.sfi_dir, self.user + ".gid")
651   
652         # the gid of the user who will be delegated to
653         delegee_gid = self._get_gid(hrn)
654         delegee_hrn = delegee_gid.get_hrn()
655         delegee_gidfile = os.path.join(self.options.sfi_dir, delegee_hrn + ".gid")
656         delegee_gid.save_to_file(filename=delegee_gidfile)
657         dcred = object_cred.delegate(delegee_gidfile, self.get_key_file(), caller_gidfile)
658         return dcred.save_to_string(save_parents=True)
659      
660     # removed named registry record
661     #   - have to first retrieve the record to be removed
662     def remove(self, opts, args):
663         auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
664         if len(args)!=1:
665             self.parser.print_help()
666             sys.exit(1)
667         hrn = args[0]
668         type = opts.type 
669         if type in ['all']:
670             type = '*'
671         return self.registry.Remove(hrn, auth_cred, type)
672     
673     # add named registry record
674     def add(self, opts, args):
675         auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
676         if len(args)!=1:
677             self.parser.print_help()
678             sys.exit(1)
679         record_filepath = args[0]
680         rec_file = self.get_record_file(record_filepath)
681         record = load_record_from_file(rec_file).as_dict()
682         return self.registry.Register(record, auth_cred)
683     
684     # update named registry entry
685     def update(self, opts, args):
686         user_cred = self.get_user_cred()
687         if len(args)!=1:
688             self.parser.print_help()
689             sys.exit(1)
690         rec_file = self.get_record_file(args[0])
691         record = load_record_from_file(rec_file)
692         if record['type'] == "user":
693             if record.get_name() == user_cred.get_gid_object().get_hrn():
694                 cred = user_cred.save_to_string(save_parents=True)
695             else:
696                 cred = self.get_auth_cred().save_to_string(save_parents=True)
697         elif record['type'] in ["slice"]:
698             try:
699                 cred = self.get_slice_cred(record.get_name()).save_to_string(save_parents=True)
700             except ServerException, e:
701                # XXX smbaker -- once we have better error return codes, update this
702                # to do something better than a string compare
703                if "Permission error" in e.args[0]:
704                    cred = self.get_auth_cred().save_to_string(save_parents=True)
705                else:
706                    raise
707         elif record.get_type() in ["authority"]:
708             cred = self.get_auth_cred().save_to_string(save_parents=True)
709         elif record.get_type() == 'node':
710             cred = self.get_auth_cred().save_to_string(save_parents=True)
711         else:
712             raise "unknown record type" + record.get_type()
713         record = record.as_dict()
714         return self.registry.Update(record, cred)
715   
716     def get_trusted_certs(self, opts, args):
717         """
718         return uhe trusted certs at this interface 
719         """ 
720         trusted_certs = self.registry.get_trusted_certs()
721         for trusted_cert in trusted_certs:
722             cert = Certificate(string=trusted_cert)
723             self.logger.debug('Sfi.get_trusted_certs -> %r'%cert.get_subject())
724         return 
725
726     def aggregates(self, opts, args):
727         """
728         return a list of details about known aggregates
729         """
730         user_cred = self.get_user_cred().save_to_string(save_parents=True)
731         hrn = None
732         if args:
733             hrn = args[0]
734
735         result = self.registry.get_aggregates(user_cred, hrn)
736         display_list(result)
737         return 
738
739     def registries(self, opts, args):
740         """
741         return a list of details about known registries
742         """
743         user_cred = self.get_user_cred().save_to_string(save_parents=True)
744         hrn = None
745         if args:
746             hrn = args[0]
747         result = self.registry.get_registries(user_cred, hrn)
748         display_list(result)
749         return
750
751  
752     # ==================================================================
753     # Slice-related commands
754     # ==================================================================
755     
756
757     def version(self, opts, args):
758         if opts.probe_registry:
759             server=self.registry
760         else:
761             server = self.get_server_from_opts(opts)
762         for (k,v) in server.GetVersion().items():
763             print "%-20s: %s"%(k,v)
764
765     # list instantiated slices
766     def slices(self, opts, args):
767         """
768         list instantiated slices
769         """
770         user_cred = self.get_user_cred().save_to_string(save_parents=True)
771         creds = [user_cred]
772         if opts.delegate:
773             delegated_cred = self.delegate_cred(user_cred, get_authority(self.authority))
774             creds.append(delegated_cred)  
775         server = self.get_server_from_opts(opts)
776         results = server.ListSlices(creds)
777         display_list(results)
778         return
779     
780     # show rspec for named slice
781     def resources(self, opts, args):
782         user_cred = self.get_user_cred().save_to_string(save_parents=True)
783         server = self.slicemgr
784         call_options = {}
785         server = self.get_server_from_opts(opts)
786         
787         if args:
788             cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
789             hrn = args[0]
790             call_options = {'geni_slice_urn': hrn_to_urn(hrn, 'slice')}
791         else:
792             cred = user_cred
793             hrn = None
794      
795         creds = [cred]
796         if opts.delegate:
797             delegated_cred = self.delegate_cred(cred, get_authority(self.authority))
798             creds.append(delegated_cred) 
799         result = server.ListResources(creds, call_options)
800         format = opts.format
801         display_rspec(result, format)
802         if (opts.file is not None):
803             file = opts.file
804             if not file.startswith(os.sep):
805                 file = os.path.join(self.options.sfi_dir, file)
806             save_rspec_to_file(result, file)
807         return
808     
809     # created named slice with given rspec
810     def create(self, opts, args):
811         slice_hrn = args[0]
812         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
813         user_cred = self.get_user_cred()
814         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
815         creds = [slice_cred]
816         if opts.delegate:
817             delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
818             creds.append(delegated_cred)
819         rspec_file = self.get_rspec_file(args[1])
820         rspec = open(rspec_file).read()
821         server = self.get_server_from_opts(opts)
822         result =  server.CreateSliver(slice_urn, creds, rspec, [])
823         print result
824         return result
825
826     # get a ticket for the specified slice
827     def get_ticket(self, opts, args):
828         slice_hrn, rspec_path = args[0], args[1]
829         slice_urn = hrn_to_urn(slice_hrn, 'slice')
830         user_cred = self.get_user_cred()
831         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
832         creds = [slice_cred]
833         if opts.delegate:
834             delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
835             creds.append(delegated_cred)
836         rspec_file = self.get_rspec_file(rspec_path) 
837         rspec = open(rspec_file).read()
838         server = self.get_server_from_opts(opts)
839         ticket_string = server.GetTicket(slice_urn, creds, rspec, [])
840         file = os.path.join(self.options.sfi_dir, get_leaf(slice_hrn) + ".ticket")
841         self.logger.info("writing ticket to %s"%file)
842         ticket = SfaTicket(string=ticket_string)
843         ticket.save_to_file(filename=file, save_parents=True)
844
845     def redeem_ticket(self, opts, args):
846         ticket_file = args[0]
847         
848         # get slice hrn from the ticket
849         # use this to get the right slice credential 
850         ticket = SfaTicket(filename=ticket_file)
851         ticket.decode()
852         slice_hrn = ticket.gidObject.get_hrn()
853         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
854         #slice_hrn = ticket.attributes['slivers'][0]['hrn']
855         user_cred = self.get_user_cred()
856         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
857         
858         # get a list of node hostnames from the RSpec 
859         tree = etree.parse(StringIO(ticket.rspec))
860         root = tree.getroot()
861         hostnames = root.xpath("./network/site/node/hostname/text()")
862         
863         # create an xmlrpc connection to the component manager at each of these
864         # components and gall redeem_ticket
865         connections = {}
866         for hostname in hostnames:
867             try:
868                 self.logger.info("Calling redeem_ticket at %(hostname)s " % locals())
869                 server = self.get_server(hostname, CM_PORT, self.key_file, \
870                                          self.cert_file, self.options.debug)
871                 server.RedeemTicket(ticket.save_to_string(save_parents=True), slice_cred)
872                 self.logger.info("Success")
873             except socket.gaierror:
874                 self.logger.error("redeem_ticket failed: Component Manager not accepting requests")
875             except Exception, e:
876                 self.logger.log_exc(e.message)
877         return
878  
879     # delete named slice
880     def delete(self, opts, args):
881         slice_hrn = args[0]
882         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
883         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
884         creds = [slice_cred]
885         if opts.delegate:
886             delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
887             creds.append(delegated_cred)
888         server = self.get_server_from_opts(opts)
889         return server.DeleteSliver(slice_urn, creds)
890     
891     # start named slice
892     def start(self, opts, args):
893         slice_hrn = args[0]
894         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
895         slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
896         creds = [slice_cred]
897         if opts.delegate:
898             delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
899             creds.append(delegated_cred)
900         server = self.get_server_from_opts(opts)
901         return server.Start(slice_urn, creds)
902     
903     # stop named slice
904     def stop(self, opts, args):
905         slice_hrn = args[0]
906         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
907         slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
908         creds = [slice_cred]
909         if opts.delegate:
910             delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
911             creds.append(delegated_cred)
912         server = self.get_server_from_opts(opts)
913         return server.Stop(slice_urn, creds)
914     
915     # reset named slice
916     def reset(self, opts, args):
917         slice_hrn = args[0]
918         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
919         server = self.get_server_from_opts(opts)
920         slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
921         creds = [slice_cred]
922         if opts.delegate:
923             delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
924             creds.append(delegated_cred)
925         return server.reset_slice(creds, slice_urn)
926
927     def renew(self, opts, args):
928         slice_hrn = args[0]
929         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
930         server = self.get_server_from_opts(opts)
931         slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
932         creds = [slice_cred]
933         if opts.delegate:
934             delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
935             creds.append(delegated_cred)
936         time = args[1]
937         return server.RenewSliver(slice_urn, creds, time)
938
939
940     def status(self, opts, args):
941         slice_hrn = args[0]
942         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
943         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
944         creds = [slice_cred]
945         if opts.delegate:
946             delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
947             creds.append(delegated_cred)
948         server = self.get_server_from_opts(opts)
949         print server.SliverStatus(slice_urn, creds)
950
951
952     def shutdown(self, opts, args):
953         slice_hrn = args[0]
954         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
955         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
956         creds = [slice_cred]
957         if opts.delegate:
958             delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
959             creds.append(delegated_cred)
960         server = self.get_server_from_opts(opts)
961         return server.Shutdown(slice_urn, creds)         
962     
963
964     #
965     # Main: parse arguments and dispatch to command
966     #
967     def main(self):
968         parser = self.create_parser()
969         (options, args) = parser.parse_args()
970         self.options = options
971
972         self.logger.setLevelFromOptVerbose(self.options.verbose)
973         if options.hashrequest:
974             self.hashrequest = True
975  
976         if len(args) <= 0:
977             self.logger.critical("No command given. Use -h for help.")
978             return -1
979     
980         command = args[0]
981         self.parser = self.create_cmd_parser(command)
982         (cmd_opts, cmd_args) = self.parser.parse_args(args[1:])
983
984         self.set_servers()
985     
986         self.logger.info("Command=%s" % command)
987         if command in ("resources"):
988             self.logger.debug("resources cmd_opts %s" % cmd_opts.format)
989         elif command in ("list", "show", "remove"):
990             self.logger.debug("cmd_opts.type %s" % cmd_opts.type)
991         self.logger.debug('cmd_args %s',cmd_args)
992
993         try:
994             self.dispatch(command, cmd_opts, cmd_args)
995         except KeyError:
996             self.logger.critical ("Unknown command %s"%command)
997             sys.exit(1)
998     
999         return
1000     
1001 if __name__ == "__main__":
1002     Sfi().main()