88f0a22eb3d76822b6c93baa3004e455342d15fd
[sfa.git] / sfa / client / sfi.py
1 #! /usr/bin/env python
2
3 # sfi -- slice-based facility interface
4
5 import sys
6 import os, os.path
7 import tempfile
8 import traceback
9 import socket
10 from types import StringTypes, ListType
11 from optparse import OptionParser
12 from sfa.trust.certificate import Keypair, Certificate
13 from sfa.trust.credential import Credential
14 from sfa.util.geniclient import GeniClient
15 from sfa.util.sfaticket import SfaTicket
16 from sfa.util.record import *
17 from sfa.util.misc 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 = GeniRecord(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 = GeniRecord(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 ("list", "show", "remove"):
180             parser.add_option("-t", "--type", dest="type",type="choice",
181                             help="type filter ([all]|user|slice|sa|ma|node|aggregate)",
182                             choices=("all","user","slice","sa","ma","node","aggregate"),
183                             default="all")
184
185         if command in ("resources", "show", "list"):
186            parser.add_option("-o", "--output", dest="file",
187                             help="output XML to file", metavar="FILE", default=None)
188         
189         if command in ("show", "list"):
190            parser.add_option("-f", "--format", dest="format", type="choice",
191                              help="display format ([text]|xml)",default="text",
192                              choices=("text","xml"))
193
194         if command in ("delegate"):
195            parser.add_option("-u", "--user",
196                             action="store_true", dest="delegate_user", default=False,
197                             help="delegate user credential")
198            parser.add_option("-s", "--slice", dest="delegate_slice",
199                             help="delegate slice credential", metavar="HRN", default=None)
200         return parser
201
202         
203     def create_parser(self):
204
205         # Generate command line parser
206         parser = OptionParser(usage="sfi [options] command [command_options] [command_args]",
207                              description="Commands: gid,list,show,remove,add,update,nodes,slices,resources,create,delete,start,stop,reset")
208         parser.add_option("-r", "--registry", dest="registry",
209                          help="root registry", metavar="URL", default=None)
210         parser.add_option("-s", "--slicemgr", dest="sm",
211                          help="slice manager", metavar="URL", default=None)
212         default_sfi_dir=os.path.expanduser("~/.sfi/")
213         parser.add_option("-d", "--dir", dest="sfi_dir",
214                          help="config & working directory - default is " + default_sfi_dir,
215                          metavar="PATH", default = default_sfi_dir)
216         parser.add_option("-u", "--user", dest="user",
217                          help="user name", metavar="HRN", default=None)
218         parser.add_option("-a", "--auth", dest="auth",
219                          help="authority name", metavar="HRN", default=None)
220         parser.add_option("-v", "--verbose",
221                          action="store_true", dest="verbose", default=False,
222                          help="verbose mode")
223         parser.add_option("-p", "--protocol",
224                          dest="protocol", default="xmlrpc",
225                          help="RPC protocol (xmlrpc or soap)")
226         parser.add_option("-k", "--hashrequest",
227                          action="store_true", dest="hashrequest", default=False,
228                          help="Create a hash of the request that will be authenticated on the server")
229         parser.disable_interspersed_args()
230
231         return parser
232         
233  
234     #
235     # Establish Connection to SliceMgr and Registry Servers
236     #
237     def set_servers(self):
238        config_file = self.options.sfi_dir + os.sep + "sfi_config"
239        try:
240           config = Config (config_file)
241        except:
242           print "Failed to read configuration file",config_file
243           print "Make sure to remove the export clauses and to add quotes"
244           if not self.options.verbose:
245              print "Re-run with -v for more details"
246           else:
247              traceback.print_exc()
248           sys.exit(1)
249     
250        errors=0
251        # Set SliceMgr URL
252        if (self.options.sm is not None):
253           sm_url = self.options.sm
254        elif hasattr(config,"SFI_SM"):
255           sm_url = config.SFI_SM
256        else:
257           print "You need to set e.g. SFI_SM='http://your.slicemanager.url:12347/' in %s"%config_file
258           errors +=1 
259     
260        # Set Registry URL
261        if (self.options.registry is not None):
262           reg_url = self.options.registry
263        elif hasattr(config,"SFI_REGISTRY"):
264           reg_url = config.SFI_REGISTRY
265        else:
266           print "You need to set e.g. SFI_REGISTRY='http://your.registry.url:12345/' in %s"%config_file
267           errors +=1 
268     
269        # Set user HRN
270        if (self.options.user is not None):
271           self.user = self.options.user
272        elif hasattr(config,"SFI_USER"):
273           self.user = config.SFI_USER
274        else:
275           print "You need to set e.g. SFI_USER='plc.princeton.username' in %s"%config_file
276           errors +=1 
277     
278        # Set authority HRN
279        if (self.options.auth is not None):
280           self.authority = self.options.auth
281        elif hasattr(config,"SFI_AUTH"):
282           self.authority = config.SFI_AUTH
283        else:
284           print "You need to set e.g. SFI_AUTH='plc.princeton' in %s"%config_file
285           errors +=1 
286     
287        if errors:
288           sys.exit(1)
289     
290        if self.options.verbose :
291           print "Contacting Slice Manager at:", sm_url
292           print "Contacting Registry at:", reg_url
293     
294        # Get key and certificate
295        key_file = self.get_key_file()
296        cert_file = self.get_cert_file(key_file)
297        self.key = Keypair(filename=key_file) 
298        self.key_file = key_file
299        self.cert_file = cert_file
300        self.cert = Certificate(filename=cert_file) 
301        # Establish connection to server(s)
302        #self.slicemgr = GeniClient(sm_url, key_file, cert_file, self.options.protocol)
303        #self.registry = GeniClient(reg_url, key_file, cert_file, self.options.protocol)
304        self.registry = xmlrpcprotocol.get_server(reg_url, key_file, cert_file)  
305        self.slicemgr = xmlrpcprotocol.get_server(sm_url, key_file, cert_file)  
306        return
307     
308     #
309     # Get various credential and spec files
310     #
311     # Establishes limiting conventions
312     #   - conflates MAs and SAs
313     #   - assumes last token in slice name is unique
314     #
315     # Bootstraps credentials
316     #   - bootstrap user credential from self-signed certificate
317     #   - bootstrap authority credential from user credential
318     #   - bootstrap slice credential from user credential
319     #
320     
321     
322     def get_key_file(self):
323        file=os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".pkey")
324        #file = os.path.join(self.options.sfi_dir, get_leaf(self.user) + ".pkey")
325        if (os.path.isfile(file)):
326           return file
327        else:
328           print "Key file", file, "does not exist"
329           sys.exit(-1)
330        return
331     
332     def get_cert_file(self,key_file):
333     
334        #file = os.path.join(self.options.sfi_dir, get_leaf(self.user) + ".cert")
335        file=os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cert")
336        if (os.path.isfile(file)):
337           return file
338        else:
339           k = Keypair(filename = key_file)
340           cert = Certificate(subject=self.user)
341           cert.set_pubkey(k)
342           cert.set_issuer(k, self.user)
343           cert.sign()
344           if self.options.verbose :
345              print "Writing self-signed certificate to", file
346           cert.save_to_file(file)
347           return file
348    
349     def get_gid(self):
350         #file = os.path.join(self.options.sfi_dir, get_leaf(self.user) + ".gid")
351         file=os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".gid")
352         if (os.path.isfile(file)):
353             gid = GID(filename=file)
354             return gid
355         else:
356             cert_str = self.cert.save_to_string(save_parents=True)
357             request_hash=None
358             if self.hashrequest:
359                 request_hash = self.key.compute_hash([cert_str, self.user, "user"])
360             gid_str = self.registry.get_gid(cert_str, self.user, "user", request_hash)
361             gid = GID(string=gid_str)
362             if self.options.verbose:
363                 print "Writing user gid to", file
364             gid.save_to_file(file, save_parents=True)
365             return gid       
366  
367     def get_user_cred(self):
368         #file = os.path.join(self.options.sfi_dir, get_leaf(self.user) + ".cred")
369         file=os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cred")
370         if (os.path.isfile(file)):
371             user_cred = Credential(filename=file)
372             return user_cred
373         else:
374             # bootstrap user credential
375             cert_string = self.cert.save_to_string(save_parents=True)
376             request_hash=None
377             if self.hashrequest:
378                 request_hash = self.key.compute_hash([cert_string, "user", self.user])
379             user_name=self.user.replace(self.authority+".", '')
380             if user_name.count(".") > 0:
381                user_name = user_name.replace(".", '_')
382                self.user=self.authority + "." + user_name
383             user_cred = self.registry.get_self_credential(cert_string, "user", self.user, request_hash)
384             if user_cred:
385                cred = Credential(string=user_cred)
386                cred.save_to_file(file, save_parents=True)
387                if self.options.verbose:
388                     print "Writing user credential to", file
389                return cred
390             else:
391                print "Failed to get user credential"
392                sys.exit(-1)
393   
394     def get_auth_cred(self):
395         if not self.authority:
396             print "no authority specified. Use -a or set SF_AUTH"
397             sys.exit(-1)
398     
399         file = os.path.join(self.options.sfi_dir, get_leaf("authority") +".cred")
400         if (os.path.isfile(file)):
401             auth_cred = Credential(filename=file)
402             return auth_cred
403         else:
404             # bootstrap authority credential from user credential
405             user_cred = self.get_user_cred().save_to_string(save_parents=True)
406             request_hash = None
407             if self.hashrequest:
408                 request_hash = self.key.compute_hash([user_cred, "authority", self.authority])
409             auth_cred = self.registry.get_credential(user_cred, "authority", self.authority, request_hash)
410             if auth_cred:
411                 cred = Credential(string=auth_cred)
412                 cred.save_to_file(file, save_parents=True)
413                 if self.options.verbose:
414                     print "Writing authority credential to", file
415                 return cred
416             else:
417                 print "Failed to get authority credential"
418                 sys.exit(-1)
419     
420     def get_slice_cred(self,name):
421         file = os.path.join(self.options.sfi_dir, "slice_" + get_leaf(name) + ".cred")
422         if (os.path.isfile(file)):
423             slice_cred = Credential(filename=file)
424             return slice_cred
425         else:
426             # bootstrap slice credential from user credential
427             user_cred = self.get_user_cred().save_to_string(save_parents=True)
428             arg_list = [user_cred, "slice", name]
429             request_hash=None
430             if self.hashrequest:
431                 request_hash = self.key.compute_hash(arg_list)  
432             slice_cred_str = self.registry.get_credential(user_cred, "slice", name, request_hash)
433             if slice_cred_str:
434                 slice_cred = Credential(string=slice_cred_str)
435                 slice_cred.save_to_file(file, save_parents=True)
436                 if self.options.verbose:
437                     print "Writing slice credential to", file
438                 return slice_cred
439             else:
440                 print "Failed to get slice credential"
441                 sys.exit(-1)
442     
443     def delegate_cred(self,cred, hrn, type = 'authority'):
444         # the gid and hrn of the object we are delegating
445         object_gid = cred.get_gid_object()
446         object_hrn = object_gid.get_hrn()
447         cred.set_delegate(True)
448         if not cred.get_delegate():
449             raise Exception, "Error: Object credential %(object_hrn)s does not have delegate bit set" % locals()
450            
451     
452         records = self.registry.resolve(cred, hrn)
453         records = filter_records(type, records)
454         
455         if not records:
456             raise Exception, "Error: Didn't find a %(type)s record for %(hrn)s" % locals()
457     
458         # the gid of the user who will be delegated too
459         delegee_gid = records[0].get_gid_object()
460         delegee_hrn = delegee_gid.get_hrn()
461         
462         # the key and hrn of the user who will be delegating
463         user_key = Keypair(filename = self.get_key_file())
464         user_hrn = cred.get_gid_caller().get_hrn()
465     
466         dcred = Credential(subject=object_hrn + " delegated to " + delegee_hrn)
467         dcred.set_gid_caller(delegee_gid)
468         dcred.set_gid_object(object_gid)
469         dcred.set_privileges(cred.get_privileges())
470         dcred.set_delegate(True)
471         dcred.set_pubkey(object_gid.get_pubkey())
472         dcred.set_issuer(user_key, user_hrn)
473         dcred.set_parent(cred)
474         dcred.encode()
475         dcred.sign()
476     
477         return dcred
478     
479     def get_rspec_file(self,rspec):
480        if (os.path.isabs(rspec)):
481           file = rspec
482        else:
483           file = os.path.join(self.options.sfi_dir, rspec)
484        if (os.path.isfile(file)):
485           return file
486        else:
487           print "No such rspec file", rspec
488           sys.exit(1)
489     
490     def get_record_file(self,record):
491        if (os.path.isabs(record)):
492           file = record
493        else:
494           file = os.path.join(self.options.sfi_dir, record)
495        if (os.path.isfile(file)):
496           return file
497        else:
498           print "No such registry record file", record
499           sys.exit(1)
500     
501     def load_publickey_string(self,fn):
502        f = file(fn,"r")
503        key_string = f.read()
504     
505        # if the filename is a private key file, then extract the public key
506        if "PRIVATE KEY" in key_string:
507            outfn = tempfile.mktemp()
508            cmd = "openssl rsa -in " + fn + " -pubout -outform PEM -out " + outfn
509            os.system(cmd)
510            f = file(outfn, "r")
511            key_string = f.read()
512            os.remove(outfn)
513     
514        return key_string
515     
516     #
517     # Following functions implement the commands
518     #
519     # Registry-related commands
520     #
521   
522     def dispatch(self,command, cmd_opts, cmd_args):
523         getattr(self,command)(cmd_opts, cmd_args)
524  
525     def gid(self, opts, args):
526         gid = self.get_gid()
527         print "GID: %s" % (gid.save_to_string(save_parents=True))
528         return   
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         request_hash=None
535         if self.hashrequest:
536             request_hash = self.key.compute_hash([user_cred, hrn])    
537         try:
538             list = self.registry.list(user_cred, hrn, request_hash)
539         except IndexError:
540             raise Exception, "Not enough parameters for the 'list' command"
541           
542         # filter on person, slice, site, node, etc.  
543         # THis really should be in the self.filter_records funct def comment...
544         list = filter_records(opts.type, list)
545         for record in list:
546             print "%s (%s)" % (record['hrn'], record['type'])     
547         if opts.file:
548             file = opts.file
549             if not file.startswith(os.sep):
550                 file = os.path.join(self.options.sfi_dir, get_leaf(self.user) + ".gid")
551             save_records_to_file(file, list)
552         return
553     
554     # show named registry record
555     def show(self,opts, args):
556         user_cred = self.get_user_cred().save_to_string(save_parents=True)
557         hrn = args[0]
558         request_hash=None
559         if self.hashrequest:
560             request_hash = self.key.compute_hash([user_cred, hrn])    
561         records = self.registry.resolve(user_cred, hrn, request_hash)
562         records = filter_records(opts.type, records)
563         if not records:
564             print "No record of type", opts.type
565         for record in records:
566             if record['type'] in ['user']:
567                 record = UserRecord(dict = record)
568             elif record['type'] in ['slice']:
569                 record = SliceRecord(dict = record)
570             elif record['type'] in ['node']:
571                 record = NodeRecord(dict = record)
572             elif record['type'] in ['authority', 'ma', 'sa']:
573                 record = AuthorityRecord(dict = record)
574             else:
575                 record = GeniRecord(dict = record)
576             if (opts.format=="text"): 
577                 record.dump()  
578             else: 
579                 print record.save_to_string() 
580        
581         if opts.file:
582             file = opts.file
583             if not file.startswith(os.sep):
584                 file = os.path.join(self.options.sfi_dir, file)
585             save_records_to_file(file, records)
586         return
587     
588     def delegate(self,opts, args):
589        user_cred = self.get_user_cred()
590        if opts.delegate_user:
591            object_cred = user_cred
592        elif opts.delegate_slice:
593            object_cred = self.get_slice_cred(opts.delegate_slice)
594        else:
595            print "Must specify either --user or --slice <hrn>"
596            return
597     
598        # the gid and hrn of the object we are delegating
599        object_gid = object_cred.get_gid_object()
600        object_hrn = object_gid.get_hrn()
601     
602        if not object_cred.get_delegate():
603            print "Error: Object credential", object_hrn, "does not have delegate bit set"
604            return
605     
606        records = self.registry.resolve(user_cred, args[0])
607        records = filter_records("user", records)
608     
609        if not records:
610            print "Error: Didn't find a user record for", args[0]
611            return
612     
613        # the gid of the user who will be delegated too
614        delegee_gid = records[0].get_gid_object()
615        delegee_hrn = delegee_gid.get_hrn()
616     
617        # the key and hrn of the user who will be delegating
618        user_key = Keypair(filename = self.get_key_file())
619        user_hrn = user_cred.get_gid_caller().get_hrn()
620     
621        dcred = Credential(subject=object_hrn + " delegated to " + delegee_hrn)
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         request_hash=None
652         if self.hashrequest: 
653             arg_list = [auth_cred, type, hrn]
654             request_hash = self.key.compute_hash(arg_list)                   
655         return self.registry.remove(auth_cred, type, hrn, request_hash)
656     
657     # add named registry record
658     def add(self,opts, args):
659         auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
660         record_filepath = args[0]
661         rec_file = self.get_record_file(record_filepath)
662         record = load_record_from_file(rec_file).as_dict()
663         request_hash=None
664         if self.hashrequest:
665             arg_list = [auth_cred]
666             request_hash = self.key.compute_hash(arg_list)
667         return self.registry.register(auth_cred, record, request_hash)
668     
669     # update named registry entry
670     def update(self,opts, args):
671         user_cred = self.get_user_cred()
672         rec_file = self.get_record_file(args[0])
673         record = load_record_from_file(rec_file)
674         if record['type'] == "user":
675             if record.get_name() == user_cred.get_gid_object().get_hrn():
676                 cred = user_cred.save_to_string(save_parents=True)
677             else:
678                 cred = self.get_auth_cred().save_to_string(save_parents=True)
679         elif record['type'] in ["slice"]:
680             try:
681                 cred = self.get_slice_cred(record.get_name()).save_to_string(save_parents=True)
682             except ServerException, e:
683                # XXX smbaker -- once we have better error return codes, update this
684                # to do something better than a string compare
685                if "Permission error" in e.args[0]:
686                    cred = self.get_auth_cred().save_to_string(save_parents=True)
687                else:
688                    raise
689         elif record.get_type() in ["authority"]:
690             cred = self.get_auth_cred().save_to_string(save_parents=True)
691         elif record.get_type() == 'node':
692             cred = self.get_auth_cred().save_to_string(save_parents=True)
693         else:
694             raise "unknown record type" + record.get_type()
695         record = record.as_dict()
696         request_hash=None
697         if self.hashrequest:
698             arg_list = [cred]  
699             request_hash = self.key.compute_hash(arg_list)
700         return self.registry.update(cred, record, request_hash)
701   
702     def get_trusted_certs(self, opts, args):
703         """
704         return the trusted certs at this interface 
705         """ 
706         trusted_certs = self.registry.get_trusted_certs()
707         for trusted_cert in trusted_certs:
708             cert = Certificate(string=trusted_cert)
709             print cert.get_subject()
710         return 
711
712     def aggregates(self, opts, args):
713         """
714         return a list of details about known aggregates
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         request_hash=None
721         if self.hashrequest:
722             arg_list = [user_cred, hrn]  
723             request_hash = self.key.compute_hash(arg_list)
724         result = self.registry.get_aggregates(user_cred, hrn, request_hash)
725         display_list(result)
726         return 
727
728     def registries(self, opts, args):
729         """
730         return a list of details about known registries
731         """
732         user_cred = self.get_user_cred().save_to_string(save_parents=True)
733         hrn = None
734         if args:
735             hrn = args[0]
736         request_hash=None
737         if self.hashrequest:
738             arg_list = [user_cred, hrn]  
739             request_hash = self.key.compute_hash(arg_list)
740         result = self.registry.get_registries(user_cred, hrn, request_hash)
741         display_list(result)
742         return
743
744  
745     #
746     # Slice-related commands
747     #
748     
749     # list available nodes -- use 'resources' w/ no argument instead
750
751     # list instantiated slices
752     def slices(self,opts, args):
753         user_cred = self.get_user_cred().save_to_string(save_parents=True)
754         request_hash=None
755         if self.hashrequest:
756             arg_list = [user_cred]
757             request_hash = self.key.compute_hash(arg_list)
758         results = self.slicemgr.get_slices(user_cred, request_hash)
759         display_list(results)
760         return
761     
762     # show rspec for named slice
763     def resources(self,opts, args):
764         user_cred = self.get_user_cred().save_to_string(save_parents=True)
765         server = self.slicemgr
766         if opts.aggregate:
767             agg_hrn = opts.aggregate
768             arg_list = [user_cred, agg_hrn]
769             request_hash = self.key.compute_hash(arg_list)
770             aggregates = self.registry.get_aggregates(user_cred, agg_hrn, request_hash)
771             if not aggregates:
772                 raise Exception, "No such aggregate %s" % agg_hrn
773             aggregate = aggregates[0]
774             url = "http://%s:%s" % (aggregate['addr'], aggregate['port'])     
775             server = xmlrpcprotocol.get_server(url, self.key_file, self.cert_file)
776         if args:
777             cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
778             hrn = args[0]
779         else:
780             cred = user_cred
781             hrn = None
782
783         request_hash=None
784         if self.hashrequest:
785             arg_list = [cred, hrn]
786             request_hash = self.key.compute_hash(arg_list)  
787         result = server.get_resources(cred, hrn, request_hash)
788         format = opts.format
789        
790         display_rspec(result, format)
791         if (opts.file is not None):
792             file = opts.file
793             if not file.startswith(os.sep):
794                 file = os.path.join(self.options.sfi_dir, file)
795             save_rspec_to_file(result, file)
796         return
797     
798     # created named slice with given rspec
799     def create(self,opts, args):
800         slice_hrn = args[0]
801         user_cred = self.get_user_cred()
802         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
803         rspec_file = self.get_rspec_file(args[1])
804         rspec=open(rspec_file).read()
805         server = self.slicemgr
806         if opts.aggregate:
807             aggregates = self.registry.get_aggregates(user_cred, opts.aggregate)
808             if not aggregates:
809                 raise Exception, "No such aggregate %s" % opts.aggregate
810             aggregate = aggregates[0]
811             url = "http://%s:%s" % (aggregate['addr'], aggregate['port'])
812             server = GeniClient(url, self.key_file, self.cert_file, self.options.protocol)
813         request_hash=None
814         if self.hashrequest:
815             arg_list = [slice_cred, slice_hrn, rspec]
816             request_hash = self.key.compute_hash(arg_list) 
817         return server.create_slice(slice_cred, slice_hrn, rspec, request_hash)
818
819     # get a ticket for the specified slice
820     def get_ticket(self, opts, args):
821         slice_hrn, rspec_path = args[0], args[1]
822         user_cred = self.get_user_cred()
823         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
824         rspec_file = self.get_rspec_file(rspec_path) 
825         rspec=open(rspec_file).read()
826         server = self.slicemgr
827         if opts.aggregate:
828             aggregates = self.registry.get_aggregates(user_cred, opts.aggregate)
829             if not aggregates:
830                 raise Exception, "No such aggregate %s" % opts.aggregate
831             aggregate = aggregates[0]
832             url = "http://%s:%s" % (aggregate['addr'], aggregate['port'])
833             server = GeniClient(url, self.key_file, self.cert_file, self.options.protocol)
834         request_hash=None
835         if self.hashrequest:
836             arg_list = [slice_cred, slice_hrn, rspec]
837             request_hash = self.key.compute_hash(arg_list)
838         ticket_string = server.get_ticket(slice_cred, slice_hrn, rspec, request_hash)
839         file = os.path.join(self.options.sfi_dir, get_leaf(slice_hrn) + ".ticket")
840         print "writing ticket to ", file        
841         ticket = SfaTicket(string=ticket_string)
842         ticket.save_to_file(filename=file, save_parents=True)
843
844     def redeem_ticket(self, opts, args):
845         ticket_file = args[0]
846         
847         # get slice hrn from the ticket
848         # use this to get the right slice credential 
849         ticket = SfaTicket(filename=ticket_file)
850         ticket.decode()
851         slice_hrn = ticket.attributes['slivers'][0]['hrn']
852         user_cred = self.get_user_cred()
853         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
854         
855         # get a list node hostnames from the nodespecs in the rspec 
856         rspec = RSpec()
857         rspec.parseString(ticket.rspec)
858         nodespecs = rspec.getDictsByTagName('NodeSpec')
859         hostnames = [nodespec['name'] for nodespec in nodespecs]
860         
861         # create an xmlrpc connection to the component manager at each of these
862         # components and gall redeem_ticket
863         connections = {}
864         for hostname in hostnames:
865             try:
866                 cm_port = "12346" 
867                 url = "https://%(hostname)s:%(cm_port)s" % locals() 
868                 print "Calling get_ticket at %(url)s " % locals(),  
869                 cm = xmlrpcprotocol.get_server(url, self.key_file, self.cert_file)
870                 cm.redeem_ticket(slice_cred, ticket.save_to_string(save_parents=True))
871                 print "Success"
872             except socket.gaierror:
873                 print "Failed:",
874                 print "Componet Manager not accepting requests" 
875             except Exception, e:
876                 print "Failed:", e.message
877              
878         return
879  
880     # delete named slice
881     def delete(self,opts, args):
882         slice_hrn = args[0]
883         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
884         request_hash=None
885         if self.hashrequest:
886             arg_list = [slice_cred, slice_hrn]
887             request_hash = self.key.compute_hash(arg_list) 
888         return self.slicemgr.delete_slice(slice_cred, slice_hrn, request_hash)
889     
890     # start named slice
891     def start(self,opts, args):
892         slice_hrn = args[0]
893         slice_cred = self.get_slice_cred(args[0])
894         request_hash=None
895         if self.hashrequest:
896             arg_list = [slice_cred, slice_hrn]
897             request_hash = self.key.compute_hash(arg_list)
898         return self.slicemgr.start_slice(slice_cred, slice_hrn, request_hash)
899     
900     # stop named slice
901     def stop(self,opts, args):
902         slice_hrn = args[0]
903         slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
904         request_hash=None
905         if self.hashrequest:
906             arg_list = [slice_cred, slice_hrn]
907             request_hash = self.key.compute_hash(arg_list)
908         return self.slicemgr.stop_slice(slice_cred, slice_hrn, request_hash)
909     
910     # reset named slice
911     def reset(self,opts, args):
912         slice_hrn = args[0]
913         slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
914         request_hash=None
915         if self.hashrequest:
916             arg_list = [slice_cred, slice_hrn]
917             request_hash = self.key.compute_hash(arg_list)
918         return self.slicemgr.reset_slice(slice_cred, slice_hrn, request_hash)
919     
920     #
921     # Main: parse arguments and dispatch to command
922     #
923     def main(self):
924         parser = self.create_parser()
925         (options, args) = parser.parse_args()
926         self.options = options
927    
928         if options.hashrequest:
929             self.hashrequest=True
930  
931         if len(args) <= 0:
932             print "No command given. Use -h for help."
933             return -1
934     
935         command = args[0]
936         (cmd_opts, cmd_args) = self.create_cmd_parser(command).parse_args(args[1:])
937         if self.options.verbose :
938             print "Registry %s, sm %s, dir %s, user %s, auth %s" % (options.registry, options.sm,
939                                                                    options.sfi_dir, options.user,
940                                                                    options.auth)
941             print "Command %s" %command
942             if command in ("resources"):
943                 print "resources cmd_opts %s" %cmd_opts.format
944             elif command in ("list","show","remove"):
945                 print "cmd_opts.type %s" %cmd_opts.type
946             print "cmd_args %s" %cmd_args
947     
948         self.set_servers()
949     
950         try:
951             self.dispatch(command, cmd_opts, cmd_args)
952         except KeyError:
953             raise 
954             print "Command not found:", command
955             sys.exit(1)
956     
957         return
958     
959 if __name__=="__main__":
960    Sfi().main()