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