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