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