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