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