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