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