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