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