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