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