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