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