add -c option for slices call
[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", "slices"):
180             parser.add_option("-c", "--component", dest="component",default=None,
181                              help="component hrn")
182             
183         if command in ("list", "show", "remove"):
184             parser.add_option("-t", "--type", dest="type",type="choice",
185                             help="type filter ([all]|user|slice|sa|ma|node|aggregate)",
186                             choices=("all","user","slice","sa","ma","node","aggregate"),
187                             default="all")
188
189         if command in ("resources", "show", "list"):
190            parser.add_option("-o", "--output", dest="file",
191                             help="output XML to file", metavar="FILE", default=None)
192         
193         if command in ("show", "list"):
194            parser.add_option("-f", "--format", dest="format", type="choice",
195                              help="display format ([text]|xml)",default="text",
196                              choices=("text","xml"))
197
198         if command in ("delegate"):
199            parser.add_option("-u", "--user",
200                             action="store_true", dest="delegate_user", default=False,
201                             help="delegate user credential")
202            parser.add_option("-s", "--slice", dest="delegate_slice",
203                             help="delegate slice credential", metavar="HRN", default=None)
204         return parser
205
206         
207     def create_parser(self):
208
209         # Generate command line parser
210         parser = OptionParser(usage="sfi [options] command [command_options] [command_args]",
211                              description="Commands: gid,list,show,remove,add,update,nodes,slices,resources,create,delete,start,stop,reset")
212         parser.add_option("-r", "--registry", dest="registry",
213                          help="root registry", metavar="URL", default=None)
214         parser.add_option("-s", "--slicemgr", dest="sm",
215                          help="slice manager", metavar="URL", default=None)
216         default_sfi_dir=os.path.expanduser("~/.sfi/")
217         parser.add_option("-d", "--dir", dest="sfi_dir",
218                          help="config & working directory - default is " + default_sfi_dir,
219                          metavar="PATH", default = default_sfi_dir)
220         parser.add_option("-u", "--user", dest="user",
221                          help="user name", metavar="HRN", default=None)
222         parser.add_option("-a", "--auth", dest="auth",
223                          help="authority name", metavar="HRN", default=None)
224         parser.add_option("-v", "--verbose",
225                          action="store_true", dest="verbose", default=False,
226                          help="verbose mode")
227         parser.add_option("-p", "--protocol",
228                          dest="protocol", default="xmlrpc",
229                          help="RPC protocol (xmlrpc or soap)")
230         parser.add_option("-k", "--hashrequest",
231                          action="store_true", dest="hashrequest", default=False,
232                          help="Create a hash of the request that will be authenticated on the server")
233         parser.disable_interspersed_args()
234
235         return parser
236         
237  
238     #
239     # Establish Connection to SliceMgr and Registry Servers
240     #
241     def set_servers(self):
242        config_file = self.options.sfi_dir + os.sep + "sfi_config"
243        try:
244           config = Config (config_file)
245        except:
246           print "Failed to read configuration file",config_file
247           print "Make sure to remove the export clauses and to add quotes"
248           if not self.options.verbose:
249              print "Re-run with -v for more details"
250           else:
251              traceback.print_exc()
252           sys.exit(1)
253     
254        errors=0
255        # Set SliceMgr URL
256        if (self.options.sm is not None):
257           sm_url = self.options.sm
258        elif hasattr(config,"SFI_SM"):
259           sm_url = config.SFI_SM
260        else:
261           print "You need to set e.g. SFI_SM='http://your.slicemanager.url:12347/' in %s"%config_file
262           errors +=1 
263     
264        # Set Registry URL
265        if (self.options.registry is not None):
266           reg_url = self.options.registry
267        elif hasattr(config,"SFI_REGISTRY"):
268           reg_url = config.SFI_REGISTRY
269        else:
270           print "You need to set e.g. SFI_REGISTRY='http://your.registry.url:12345/' in %s"%config_file
271           errors +=1 
272     
273        # Set user HRN
274        if (self.options.user is not None):
275           self.user = self.options.user
276        elif hasattr(config,"SFI_USER"):
277           self.user = config.SFI_USER
278        else:
279           print "You need to set e.g. SFI_USER='plc.princeton.username' in %s"%config_file
280           errors +=1 
281     
282        # Set authority HRN
283        if (self.options.auth is not None):
284           self.authority = self.options.auth
285        elif hasattr(config,"SFI_AUTH"):
286           self.authority = config.SFI_AUTH
287        else:
288           print "You need to set e.g. SFI_AUTH='plc.princeton' in %s"%config_file
289           errors +=1 
290     
291        if errors:
292           sys.exit(1)
293     
294        if self.options.verbose :
295           print "Contacting Slice Manager at:", sm_url
296           print "Contacting Registry at:", reg_url
297     
298        # Get key and certificate
299        key_file = self.get_key_file()
300        cert_file = self.get_cert_file(key_file)
301        self.key = Keypair(filename=key_file) 
302        self.key_file = key_file
303        self.cert_file = cert_file
304        self.cert = Certificate(filename=cert_file) 
305        # Establish connection to server(s)
306        #self.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
776         server = self.slicemgr
777         # direct connection to the nodes component manager interface
778         if opts.component:
779             server = self.get_component_server_from_hrn(opts.component)
780         results = server.get_slices(user_cred, request_hash)
781         display_list(results)
782         return
783     
784     # show rspec for named slice
785     def resources(self,opts, args):
786         user_cred = self.get_user_cred().save_to_string(save_parents=True)
787         server = self.slicemgr
788         if opts.aggregate:
789             agg_hrn = opts.aggregate
790             arg_list = [user_cred, agg_hrn]
791             request_hash = self.key.compute_hash(arg_list)
792             aggregates = self.registry.get_aggregates(user_cred, agg_hrn, request_hash)
793             if not aggregates:
794                 raise Exception, "No such aggregate %s" % agg_hrn
795             aggregate = aggregates[0]
796             url = "http://%s:%s" % (aggregate['addr'], aggregate['port'])     
797             server = xmlrpcprotocol.get_server(url, self.key_file, self.cert_file)
798         if args:
799             cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
800             hrn = args[0]
801         else:
802             cred = user_cred
803             hrn = None
804
805         request_hash=None
806         if self.hashrequest:
807             arg_list = [cred, hrn]
808             request_hash = self.key.compute_hash(arg_list)  
809         result = server.get_resources(cred, hrn, request_hash)
810         format = opts.format
811        
812         display_rspec(result, format)
813         if (opts.file is not None):
814             file = opts.file
815             if not file.startswith(os.sep):
816                 file = os.path.join(self.options.sfi_dir, file)
817             save_rspec_to_file(result, file)
818         return
819     
820     # created named slice with given rspec
821     def create(self,opts, args):
822         slice_hrn = args[0]
823         user_cred = self.get_user_cred()
824         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
825         rspec_file = self.get_rspec_file(args[1])
826         rspec=open(rspec_file).read()
827         server = self.slicemgr
828         if opts.aggregate:
829             aggregates = self.registry.get_aggregates(user_cred, opts.aggregate)
830             if not aggregates:
831                 raise Exception, "No such aggregate %s" % opts.aggregate
832             aggregate = aggregates[0]
833             url = "http://%s:%s" % (aggregate['addr'], aggregate['port'])
834             server = GeniClient(url, self.key_file, self.cert_file, self.options.protocol)
835         request_hash=None
836         if self.hashrequest:
837             arg_list = [slice_cred, slice_hrn, rspec]
838             request_hash = self.key.compute_hash(arg_list) 
839         return server.create_slice(slice_cred, slice_hrn, rspec, request_hash)
840
841     # get a ticket for the specified slice
842     def get_ticket(self, opts, args):
843         slice_hrn, rspec_path = args[0], args[1]
844         user_cred = self.get_user_cred()
845         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
846         rspec_file = self.get_rspec_file(rspec_path) 
847         rspec=open(rspec_file).read()
848         server = self.slicemgr
849         if opts.aggregate:
850             aggregates = self.registry.get_aggregates(user_cred, opts.aggregate)
851             if not aggregates:
852                 raise Exception, "No such aggregate %s" % opts.aggregate
853             aggregate = aggregates[0]
854             url = "http://%s:%s" % (aggregate['addr'], aggregate['port'])
855             server = GeniClient(url, self.key_file, self.cert_file, self.options.protocol)
856         request_hash=None
857         if self.hashrequest:
858             arg_list = [slice_cred, slice_hrn, rspec]
859             request_hash = self.key.compute_hash(arg_list)
860         ticket_string = server.get_ticket(slice_cred, slice_hrn, rspec, request_hash)
861         file = os.path.join(self.options.sfi_dir, get_leaf(slice_hrn) + ".ticket")
862         print "writing ticket to ", file        
863         ticket = SfaTicket(string=ticket_string)
864         ticket.save_to_file(filename=file, save_parents=True)
865
866     def redeem_ticket(self, opts, args):
867         ticket_file = args[0]
868         
869         # get slice hrn from the ticket
870         # use this to get the right slice credential 
871         ticket = SfaTicket(filename=ticket_file)
872         ticket.decode()
873         slice_hrn = ticket.attributes['slivers'][0]['hrn']
874         user_cred = self.get_user_cred()
875         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
876         
877         # get a list node hostnames from the nodespecs in the rspec 
878         rspec = RSpec()
879         rspec.parseString(ticket.rspec)
880         nodespecs = rspec.getDictsByTagName('NodeSpec')
881         hostnames = [nodespec['name'] for nodespec in nodespecs]
882         
883         # create an xmlrpc connection to the component manager at each of these
884         # components and gall redeem_ticket
885         connections = {}
886         for hostname in hostnames:
887             try:
888                 cm_port = "12346" 
889                 url = "https://%(hostname)s:%(cm_port)s" % locals() 
890                 print "Calling get_ticket at %(url)s " % locals(),  
891                 cm = xmlrpcprotocol.get_server(url, self.key_file, self.cert_file)
892                 cm.redeem_ticket(slice_cred, ticket.save_to_string(save_parents=True))
893                 print "Success"
894             except socket.gaierror:
895                 print "Failed:",
896                 print "Componet Manager not accepting requests" 
897             except Exception, e:
898                 print "Failed:", e.message
899              
900         return
901  
902     # delete named slice
903     def delete(self,opts, args):
904         slice_hrn = args[0]
905         server = self.slicemgr
906         # direct connection to the nodes component manager interface
907         if opts.component:
908             server = self.get_component_server_from_hrn(opts.component)
909  
910         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
911         request_hash=None
912         if self.hashrequest:
913             arg_list = [slice_cred, slice_hrn]
914             request_hash = self.key.compute_hash(arg_list) 
915         return server.delete_slice(slice_cred, slice_hrn, request_hash)
916     
917     # start named slice
918     def start(self,opts, args):
919         slice_hrn = args[0]
920         server = self.slicemgr
921         # direct connection to the nodes component manager interface
922         if opts.component:
923             server = self.get_component_server_from_hrn(opts.component)
924  
925         slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
926         request_hash=None
927         if self.hashrequest:
928             arg_list = [slice_cred, slice_hrn]
929             request_hash = self.key.compute_hash(arg_list)
930         return server.start_slice(slice_cred, slice_hrn, request_hash)
931     
932     # stop named slice
933     def stop(self,opts, args):
934         slice_hrn = args[0]
935         server = self.slicemgr
936         # direct connection to the nodes component manager interface
937         if opts.component:
938             server = self.get_component_server_from_hrn(opts.component)
939
940         slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
941         request_hash=None
942         if self.hashrequest:
943             arg_list = [slice_cred, slice_hrn]
944             request_hash = self.key.compute_hash(arg_list)
945         return server.stop_slice(slice_cred, slice_hrn, request_hash)
946     
947     # reset named slice
948     def reset(self,opts, args):
949         slice_hrn = args[0]
950         server = self.slicemgr
951         # direct connection to the nodes component manager interface
952         if opts.component:
953             server = self.get_component_server_from_hrn(opts.component)
954         slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
955         request_hash=None
956         if self.hashrequest:
957             arg_list = [slice_cred, slice_hrn]
958             request_hash = self.key.compute_hash(arg_list)
959         return server.reset_slice(slice_cred, slice_hrn, request_hash)
960     
961     #
962     # Main: parse arguments and dispatch to command
963     #
964     def main(self):
965         parser = self.create_parser()
966         (options, args) = parser.parse_args()
967         self.options = options
968    
969         if options.hashrequest:
970             self.hashrequest=True
971  
972         if len(args) <= 0:
973             print "No command given. Use -h for help."
974             return -1
975     
976         command = args[0]
977         (cmd_opts, cmd_args) = self.create_cmd_parser(command).parse_args(args[1:])
978         if self.options.verbose :
979             print "Registry %s, sm %s, dir %s, user %s, auth %s" % (options.registry, options.sm,
980                                                                    options.sfi_dir, options.user,
981                                                                    options.auth)
982             print "Command %s" %command
983             if command in ("resources"):
984                 print "resources cmd_opts %s" %cmd_opts.format
985             elif command in ("list","show","remove"):
986                 print "cmd_opts.type %s" %cmd_opts.type
987             print "cmd_args %s" %cmd_args
988     
989         self.set_servers()
990     
991         try:
992             self.dispatch(command, cmd_opts, cmd_args)
993         except KeyError:
994             raise 
995             print "Command not found:", command
996             sys.exit(1)
997     
998         return
999     
1000 if __name__=="__main__":
1001    Sfi().main()