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