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