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