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