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