sfi.py resources outputs rspec only if no file specified
[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         if opts.file is None:
802             display_rspec(result, format)
803         else:
804             file = opts.file
805             if not file.startswith(os.sep):
806                 file = os.path.join(self.options.sfi_dir, file)
807             save_rspec_to_file(result, file)
808         return
809     
810     # created named slice with given rspec
811     def create(self, opts, args):
812         slice_hrn = args[0]
813         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
814         user_cred = self.get_user_cred()
815         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
816         creds = [slice_cred]
817         if opts.delegate:
818             delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
819             creds.append(delegated_cred)
820         rspec_file = self.get_rspec_file(args[1])
821         rspec = open(rspec_file).read()
822         server = self.get_server_from_opts(opts)
823         result =  server.CreateSliver(slice_urn, creds, rspec, [])
824         print result
825         return result
826
827     # get a ticket for the specified slice
828     def get_ticket(self, opts, args):
829         slice_hrn, rspec_path = args[0], args[1]
830         slice_urn = hrn_to_urn(slice_hrn, 'slice')
831         user_cred = self.get_user_cred()
832         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
833         creds = [slice_cred]
834         if opts.delegate:
835             delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
836             creds.append(delegated_cred)
837         rspec_file = self.get_rspec_file(rspec_path) 
838         rspec = open(rspec_file).read()
839         server = self.get_server_from_opts(opts)
840         ticket_string = server.GetTicket(slice_urn, creds, rspec, [])
841         file = os.path.join(self.options.sfi_dir, get_leaf(slice_hrn) + ".ticket")
842         self.logger.info("writing ticket to %s"%file)
843         ticket = SfaTicket(string=ticket_string)
844         ticket.save_to_file(filename=file, save_parents=True)
845
846     def redeem_ticket(self, opts, args):
847         ticket_file = args[0]
848         
849         # get slice hrn from the ticket
850         # use this to get the right slice credential 
851         ticket = SfaTicket(filename=ticket_file)
852         ticket.decode()
853         slice_hrn = ticket.gidObject.get_hrn()
854         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
855         #slice_hrn = ticket.attributes['slivers'][0]['hrn']
856         user_cred = self.get_user_cred()
857         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
858         
859         # get a list of node hostnames from the RSpec 
860         tree = etree.parse(StringIO(ticket.rspec))
861         root = tree.getroot()
862         hostnames = root.xpath("./network/site/node/hostname/text()")
863         
864         # create an xmlrpc connection to the component manager at each of these
865         # components and gall redeem_ticket
866         connections = {}
867         for hostname in hostnames:
868             try:
869                 self.logger.info("Calling redeem_ticket at %(hostname)s " % locals())
870                 server = self.get_server(hostname, CM_PORT, self.key_file, \
871                                          self.cert_file, self.options.debug)
872                 server.RedeemTicket(ticket.save_to_string(save_parents=True), slice_cred)
873                 self.logger.info("Success")
874             except socket.gaierror:
875                 self.logger.error("redeem_ticket failed: Component Manager not accepting requests")
876             except Exception, e:
877                 self.logger.log_exc(e.message)
878         return
879  
880     # delete named slice
881     def delete(self, opts, args):
882         slice_hrn = args[0]
883         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
884         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
885         creds = [slice_cred]
886         if opts.delegate:
887             delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
888             creds.append(delegated_cred)
889         server = self.get_server_from_opts(opts)
890         return server.DeleteSliver(slice_urn, creds)
891     
892     # start named slice
893     def start(self, opts, args):
894         slice_hrn = args[0]
895         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
896         slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
897         creds = [slice_cred]
898         if opts.delegate:
899             delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
900             creds.append(delegated_cred)
901         server = self.get_server_from_opts(opts)
902         return server.Start(slice_urn, creds)
903     
904     # stop named slice
905     def stop(self, opts, args):
906         slice_hrn = args[0]
907         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
908         slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
909         creds = [slice_cred]
910         if opts.delegate:
911             delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
912             creds.append(delegated_cred)
913         server = self.get_server_from_opts(opts)
914         return server.Stop(slice_urn, creds)
915     
916     # reset named slice
917     def reset(self, opts, args):
918         slice_hrn = args[0]
919         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
920         server = self.get_server_from_opts(opts)
921         slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
922         creds = [slice_cred]
923         if opts.delegate:
924             delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
925             creds.append(delegated_cred)
926         return server.reset_slice(creds, slice_urn)
927
928     def renew(self, opts, args):
929         slice_hrn = args[0]
930         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
931         server = self.get_server_from_opts(opts)
932         slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
933         creds = [slice_cred]
934         if opts.delegate:
935             delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
936             creds.append(delegated_cred)
937         time = args[1]
938         return server.RenewSliver(slice_urn, creds, time)
939
940
941     def status(self, opts, args):
942         slice_hrn = args[0]
943         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
944         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
945         creds = [slice_cred]
946         if opts.delegate:
947             delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
948             creds.append(delegated_cred)
949         server = self.get_server_from_opts(opts)
950         print server.SliverStatus(slice_urn, creds)
951
952
953     def shutdown(self, opts, args):
954         slice_hrn = args[0]
955         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
956         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
957         creds = [slice_cred]
958         if opts.delegate:
959             delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
960             creds.append(delegated_cred)
961         server = self.get_server_from_opts(opts)
962         return server.Shutdown(slice_urn, creds)         
963     
964
965     #
966     # Main: parse arguments and dispatch to command
967     #
968     def main(self):
969         parser = self.create_parser()
970         (options, args) = parser.parse_args()
971         self.options = options
972
973         self.logger.setLevelFromOptVerbose(self.options.verbose)
974         if options.hashrequest:
975             self.hashrequest = True
976  
977         if len(args) <= 0:
978             self.logger.critical("No command given. Use -h for help.")
979             return -1
980     
981         command = args[0]
982         self.parser = self.create_cmd_parser(command)
983         (cmd_opts, cmd_args) = self.parser.parse_args(args[1:])
984
985         self.set_servers()
986     
987         self.logger.info("Command=%s" % command)
988         if command in ("resources"):
989             self.logger.debug("resources cmd_opts %s" % cmd_opts.format)
990         elif command in ("list", "show", "remove"):
991             self.logger.debug("cmd_opts.type %s" % cmd_opts.type)
992         self.logger.debug('cmd_args %s',cmd_args)
993
994         try:
995             self.dispatch(command, cmd_opts, cmd_args)
996         except KeyError:
997             self.logger.critical ("Unknown command %s"%command)
998             sys.exit(1)
999     
1000         return
1001     
1002 if __name__ == "__main__":
1003     Sfi().main()