source: fedd/fedd_client.py @ 70cdf59

axis_examplecompt_changesinfo-opsversion-1.30version-2.00version-3.01version-3.02
Last change on this file since 70cdf59 was 70cdf59, checked in by Ted Faber <faber@…>, 15 years ago

Require an experiment name for terminate

  • Property mode set to 100755
File size: 21.0 KB
Line 
1#!/usr/local/bin/python
2
3import sys
4import os
5import pwd
6
7from federation import fedid, service_error
8from federation.util import fedd_ssl_context, pack_id, unpack_id
9from federation.remote_service import service_caller
10
11from optparse import OptionParser, OptionValueError
12
13
14class IDFormatException(RuntimeError): pass
15
16class access_method:
17    """Encapsulates an access method generically."""
18    (type_ssh, type_x509, type_pgp) = ('sshPubkey', 'X509', 'pgpPubkey')
19    default_type = type_ssh
20    def __init__(self, buf=None, type=None, file=None):
21        self.buf = buf
22
23        if type != None: self.type = type
24        else: self.type = access_method.default_type
25
26        if file != None:
27            self.readfile(file)
28   
29    def readfile(self, file, type=None):
30        f = open(file, "r")
31        self.buf = f.read();
32        f.close()
33        if type == None:
34            if self.type == None:
35                self.type = access_method.default_type
36        else:
37            self.type = type;
38   
39class node_desc:
40    def __init__(self, image, hardware, count=1):
41        if getattr(image, "__iter__", None) == None:
42            if image == None: self.image = [ ]
43            else: self.image = [ image ]
44        else:
45            self.image = image
46
47        if getattr(hardware, "__iter__", None) == None: 
48            if hardware == None: self.hardware = [ ]
49            else: self.hardware = [ hardware ]
50        else:
51            self.hardware = hardware
52        if count != None: self.count = int(count)
53        else: self.count = 1
54
55class fedd_client_opts(OptionParser):
56    """Encapsulate option processing in this class, rather than in main"""
57    def __init__(self):
58        OptionParser.__init__(self, usage="%prog [opts] (--help for details)",
59                version="0.1")
60
61        self.add_option("-c","--cert", action="store", dest="cert",
62                type="string", help="my certificate file")
63        self.add_option("-d", "--debug", action="count", dest="debug", 
64                default=0, help="Set debug.  Repeat for more information")
65        self.add_option("-s", "--serializeOnly", action="store_true", 
66                dest="serialize_only", default=False,
67                help="Print the SOAP request that would be sent and exit")
68        self.add_option("-T","--trusted", action="store", dest="trusted",
69                type="string", help="Trusted certificates (required)")
70        self.add_option("-u", "--url", action="store", dest="url",
71                type="string",default="https://localhost:23235", 
72                help="URL to connect to (default %default)")
73        self.add_option("-x","--transport", action="store", type="choice",
74                choices=("xmlrpc", "soap"), default="soap",
75                help="Transport for request (xmlrpc|soap) (Default: %default)")
76        self.add_option("--trace", action="store_const", dest="tracefile", 
77                const=sys.stderr, help="Print SOAP exchange to stderr")
78
79class fedd_create_opts(fedd_client_opts):
80    def __init__(self, access_keys, add_key_callback=None, 
81            add_cert_callback=None):
82        fedd_client_opts.__init__(self)
83        self.add_option("-e", "--experiment_cert", dest="out_certfile",
84                type="string", help="output certificate file")
85        self.add_option("-E", "--experiment_name", dest="exp_name",
86                type="string", help="output certificate file")
87        self.add_option("-F","--useFedid", action="store_true",
88                dest="use_fedid", default=False,
89                help="Use a fedid derived from my certificate as user identity")
90        self.add_option("-f", "--file", dest="file", 
91                help="experiment description file")
92        self.add_option("-p", "--project", action="store", dest="project", 
93                type="string",
94                help="Project to export from master")
95        if add_key_callback:
96            self.add_option("-k", "--sshKey", action="callback", type="string", 
97                    callback=add_key_callback, callback_args=(access_keys,),
98                    help="ssh key for access (can be supplied more than once")
99        if add_cert_callback:
100            self.add_option("-K", "--x509Key", action="callback",
101                    type="string", callback=add_cert_callback,
102                    callback_args=(access_keys,),
103                    help="X509 certificate for access " + \
104                        "(can be supplied more than once")
105        self.add_option("-m", "--master", dest="master",
106                help="Master testbed in the federation")
107        self.add_option("-U", "--username", action="store", dest="user",
108                type="string", help="Use this username instead of the uid")
109
110class fedd_split_opts(fedd_create_opts):
111    def __init__(self, access_keys, add_key_callback=None, 
112            add_cert_callback=None):
113        fedd_create_opts.__init__(self, access_keys, add_key_callback,
114                add_cert_callback)
115        self.add_option('-t','--fedkit', action='store_true', dest='fedkit',
116                default=False,
117                help="get output suitable for federation kit install")
118
119
120class fedd_access_opts(fedd_create_opts):
121    def __init__(self, access_keys, node_descs, add_key_callback=None, 
122            add_cert_callback=None, add_node_callback=None):
123        fedd_create_opts.__init__(self, access_keys, add_key_callback,
124                add_cert_callback)
125        self.add_option("-a","--anonymous", action="store_true",
126                dest="anonymous", default=False,
127                help="Do not include a user in the request")
128        self.add_option("-l","--label", action="store", dest="label",
129                type="string", help="Label for output")
130        if add_node_callback:
131            self.add_option("-n", "--node", action="callback", type="string", 
132                    callback=add_node_callback, callback_args=(node_descs,),
133                    help="Node description: image:hardware[:count]")
134        self.add_option("-t", "--testbed", action="store", dest="testbed",
135                type="string",
136                help="Testbed identifier (URI) to contact (required)")
137
138class fedd_exp_data_opts(fedd_client_opts):
139    def __init__(self):
140        fedd_client_opts.__init__(self)
141        self.add_option("-e", "--experiment_cert", dest="exp_certfile",
142                type="string", help="output certificate file")
143        self.add_option("-E", "--experiment_name", dest="exp_name",
144                type="string", help="output certificate file")
145
146def exit_with_fault(dict, out=sys.stderr):
147    """ Print an error message and exit.
148
149    The dictionary contains the FeddFaultBody elements."""
150    codestr = ""
151
152    if dict.has_key('errstr'):
153        codestr = "Error: %s" % dict['errstr']
154
155    if dict.has_key('code'):
156        if len(codestr) > 0 : 
157            codestr += " (%d)" % dict['code']
158        else:
159            codestr = "Error Code: %d" % dict['code']
160
161    print>>out, codestr
162    print>>out, "Description: %s" % dict['desc']
163    sys.exit(dict.get('code', 20))
164# Base class that will do a the SOAP/XMLRPC exchange for a request.
165class fedd_rpc:
166    class RPCException:
167        def __init__(self, fb):
168            self.desc = fb.get('desc', None)
169            self.code = fb.get('code', -1)
170            self.errstr = fb.get('errstr', None)
171
172    def __init__(self, pre): 
173        """
174        Specialize the class for the pre method
175        """
176        self.RequestBody="%sRequestBody" % pre
177        self.ResponseBody="%sResponseBody" % pre
178        self.method = pre
179
180        self.caller = service_caller(self.method)
181        self.RPCException = fedd_rpc.RPCException
182
183
184    def add_ssh_key(self, option, opt_str, value, parser, access_keys):
185        try:
186            access_keys.append(access_method(file=value,
187                type=access_method.type_ssh))
188        except IOError, (errno, strerror):
189            raise OptionValueError("Cannot generate sshPubkey from %s: "\
190                    "%s (%d)" % (value,strerror,errno))
191
192    def add_x509_cert(self, option, opt_str, value, parser, access_keys):
193        try:
194            access_keys.append(access_method(file=value,
195                type=access_method.type_x509))
196        except IOError, (errno, strerror):
197            raise OptionValueError("Cannot read x509 cert from %s: %s (%d)" %
198                    (value,strerror,errno))
199    def add_node_desc(self, option, opt_str, value, parser, node_descs):
200        def none_if_zero(x):
201            if len(x) > 0: return x
202            else: return None
203
204        params = map(none_if_zero, value.split(":"));
205       
206        if len(params) < 4 and len(params) > 1:
207            node_descs.append(node_desc(*params))
208        else:
209            raise OptionValueError("Bad node description: %s" % value)
210
211    def get_user_info(self, access_keys):
212        pw = pwd.getpwuid(os.getuid());
213        try_cert=None
214        user = None
215
216        if pw != None:
217            user = pw[0]
218            try_cert = "%s/.ssl/emulab.pem" % pw[5];
219            if not os.access(try_cert, os.R_OK):
220                try_cert = None
221            if len(access_keys) == 0:
222                for k in ["%s/.ssh/id_rsa.pub", "%s/.ssh/id_dsa.pub", 
223                        "%s/.ssh/identity.pub"]:
224                    try_key = k % pw[5];
225                    if os.access(try_key, os.R_OK):
226                        access_keys.append(access_method(file=try_key,
227                            type=access_method.type_ssh))
228                        break
229        return (user, try_cert)
230
231    def do_rpc(self, req_dict, url, transport, cert, trusted, tracefile=None,
232            serialize_only=False):
233        """
234        The work of sending and parsing the RPC as either XMLRPC or SOAP
235        """
236
237        context = None
238        while context == None:
239            try:
240                context = fedd_ssl_context(cert, trusted)
241            except Exception, e:
242                # Yes, doing this on message type is not ideal.  The string
243                # comes from OpenSSL, so check there is this stops working.
244                if str(e) == "bad decrypt": 
245                    print >>sys.stderr, "Bad Passphrase given."
246                else: raise
247
248        if transport == "soap":
249            if serialize_only:
250                print self.caller.serialize_soap(req_dict) 
251                sys.exit(0)
252            else:
253                try:
254                    resp = self.caller.call_soap_service(url, req_dict, 
255                            context=context, tracefile=tracefile)
256                except service_error, e:
257                    raise self.RPCException( {\
258                            'code': e.code, 
259                            'desc': e.desc, 
260                            'errstr': e.code_string()\
261                        })
262        elif transport == "xmlrpc":
263            if serialize_only:
264                ser = dumps((req_dict,))
265                print ser
266                sys.exit(0)
267            else:
268                try:
269                    resp = self.caller.call_xmlrpc_service(url, req_dict, 
270                            context=context, tracefile=tracefile)
271                except service_error, e:
272                    raise self.RPCException( {\
273                            'code': e.code, 
274                            'desc': e.desc, 
275                            'errstr': e.code_string()\
276                        })
277
278        else:
279            raise RuntimeError("Unknown RPC transport: %s" % transport)
280
281        if resp.has_key(self.ResponseBody):
282            return resp[self.ResponseBody]
283        else:
284            raise RuntimeError("No body in response??")
285
286# Querying experiment data follows the same control flow regardless of the
287# specific data retrieved.  This class encapsulates that control flow.
288class exp_data(fedd_rpc):
289    def __init__(self, op): 
290        """
291        Specialize the class for the type of data requested (op)
292        """
293
294        fedd_rpc.__init__(self, op)
295        if op =='Vtopo':
296            self.key="vtopo"
297            self.xml='experiment'
298        elif op == 'Vis':
299            self.key="vis"
300            self.xml='vis'
301        elif op == 'Info': pass
302        else:
303            raise TypeError("Bad op: %s" % op)
304
305    def print_xml(self, d, out=sys.stdout):
306        """
307        Print the retrieved data is a simple xml representation of the dict.
308        """
309        str = "<%s>\n" % self.xml
310        for t in ('node', 'lan'):
311            if d.has_key(t): 
312                for x in d[t]:
313                    str += "<%s>" % t
314                    for k in x.keys():
315                        str += "<%s>%s</%s>" % (k, x[k],k)
316                    str += "</%s>\n" % t
317        str+= "</%s>" % self.xml
318        print >>out, str
319
320    def __call__(self):
321        """
322        The control flow.  Compose the request and print the response.
323        """
324        # Process the options using the customized option parser defined above
325        parser = fedd_exp_data_opts()
326
327        (opts, args) = parser.parse_args()
328
329        if opts.trusted:
330            if ( not os.access(opts.trusted, os.R_OK) ) :
331                sys.exit("Cannot read trusted certificates (%s)" % opts.trusted)
332
333        if opts.debug > 0: opts.tracefile=sys.stderr
334
335        (user, cert) = self.get_user_info([])
336
337        if opts.cert != None: cert = opts.cert
338
339        if cert == None:
340            sys.exit("No certificate given (--cert) or found")
341
342        if os.access(cert, os.R_OK):
343            fid = fedid(file=cert)
344        else:
345            sys.exit("Cannot read certificate (%s)" % cert)
346
347        if opts.exp_name and opts.exp_certfile:
348            sys.exit("Only one of --experiment_cert and " +\
349                    "--experiment_name permitted");
350
351        if opts.exp_certfile:
352            exp_id = { 'fedid': fedid(file=opts.exp_certfile) }
353
354        if opts.exp_name:
355            exp_id = { 'localname' : opts.exp_name }
356
357        req = { 'experiment': exp_id }
358
359        try:
360            resp_dict = self.do_rpc(req,
361                    opts.url, opts.transport, cert, opts.trusted, 
362                    serialize_only=opts.serialize_only,
363                    tracefile=opts.tracefile)
364        except self.RPCException, e:
365            exit_with_fault(\
366                    {'desc': e.desc, 'errstr': e.errstr, 'code': e.code})
367        except RuntimeError, e:
368            print e
369            sys.exit("Error processing RPC: %s" % e)
370
371        if getattr(self, 'key', None):
372            try:
373                if resp_dict.has_key(self.key):
374                    self.print_xml(resp_dict[self.key])
375            except RuntimeError, e:
376                sys.exit("Bad response. %s" % e.message)
377        else:
378            print resp_dict
379
380class terminate(fedd_rpc):
381    def __init__(self): 
382        """
383        Termination request
384        """
385
386        fedd_rpc.__init__(self, "Terminate")
387
388    def __call__(self):
389        """
390        The control flow.  Compose the request and print the response.
391        """
392        # Process the options using the customized option parser defined above
393        parser = fedd_exp_data_opts()
394
395        (opts, args) = parser.parse_args()
396
397        (user, cert) = self.get_user_info([])
398        if opts.trusted:
399            if ( not os.access(opts.trusted, os.R_OK) ) :
400                sys.exit("Cannot read trusted certificates (%s)" % opts.trusted)
401
402        if opts.debug > 0: opts.tracefile=sys.stderr
403
404        if opts.cert != None: cert = opts.cert
405
406        if cert == None:
407            sys.exit("No certificate given (--cert) or found")
408
409        if os.access(cert, os.R_OK):
410            fid = fedid(file=cert)
411        else:
412            sys.exit("Cannot read certificate (%s)" % cert)
413
414        if opts.exp_name and opts.exp_certfile:
415            sys.exit("Only one of --experiment_cert and " +\
416                    "--experiment_name permitted");
417
418        exp_id = None
419
420        if opts.exp_certfile:
421            exp_id = { 'fedid': fedid(file=opts.exp_certfile) }
422
423        if opts.exp_name:
424            exp_id = { 'localname' : opts.exp_name }
425
426        if not exp_id:
427            sys.exit("Must give one of --experiment_cert and " +\
428                    "--experiment_name");
429
430        req = { 'experiment': exp_id }
431
432        try:
433            resp_dict = self.do_rpc(req,
434                    opts.url, opts.transport, cert, opts.trusted, 
435                    serialize_only=opts.serialize_only,
436                    tracefile=opts.tracefile)
437        except self.RPCException, e:
438            exit_with_fault(\
439                    {'desc': e.desc, 'errstr': e.errstr, 'code': e.code})
440        except RuntimeError, e:
441            print e
442            sys.exit("Error processing RPC: %s" % e)
443
444        eid = resp_dict.get('experimentID', None)
445        if eid:
446            for id in eid:
447                for k in id.keys():
448                    if k == 'fedid': print "%s: %s" % (k,fedid(bits=id[k]))
449                    else: print "%s: %s" % (k, id[k])
450
451class create(fedd_rpc):
452    def __init__(self): 
453        fedd_rpc.__init__(self, "Create")
454    def __call__(self):
455        access_keys = []
456        # Process the options using the customized option parser defined above
457        parser = fedd_create_opts(access_keys, self.add_ssh_key,
458                self.add_x509_cert)
459
460        (opts, args) = parser.parse_args()
461
462        if opts.trusted:
463            if ( not os.access(opts.trusted, os.R_OK) ) :
464                sys.exit("Cannot read trusted certificates (%s)" % opts.trusted)
465
466        if not opts.project :
467            parser.error('--project is required')
468
469        if opts.debug > 0: opts.tracefile=sys.stderr
470
471        (user, cert) = self.get_user_info(access_keys)
472
473        if opts.user: user = opts.user
474
475        if opts.cert != None: cert = opts.cert
476
477        if cert == None:
478            sys.exit("No certificate given (--cert) or found")
479
480        if os.access(cert, os.R_OK):
481            fid = fedid(file=cert)
482            if opts.use_fedid == True:
483                user = fid
484        else:
485            sys.exit("Cannot read certificate (%s)" % cert)
486
487        if opts.file:
488            exp_desc = ""
489            try:
490                f = open(opts.file, 'r')
491                for line in f:
492                    exp_desc += line
493                f.close()
494            except IOError:
495                sys.exit("Cannot read description file (%s)" %opts.file)
496        else:
497            sys.exit("Must specify an experiment description (--file)")
498
499        if not opts.master:
500            sys.exit("Must specify a master testbed (--master)")
501
502        out_certfile = opts.out_certfile
503
504        msg = {
505                'experimentdescription': { 'ns2description': exp_desc },
506                'master': opts.master,
507                'exportProject': { 'localname': opts.project },
508                'user' : [ {\
509                        'userID': pack_id(user), \
510                        'access': [ { a.type: a.buf } for a in access_keys]\
511                        } ]
512                }
513
514        if opts.exp_name:
515            msg['experimentID'] = { 'localname': opts.exp_name }
516
517        if opts.debug > 1: print >>sys.stderr, msg
518
519        try:
520            resp_dict = self.do_rpc(msg, 
521                    opts.url, opts.transport, cert, opts.trusted, 
522                    serialize_only=opts.serialize_only,
523                    tracefile=opts.tracefile)
524        except self.RPCException, e:
525            exit_with_fault(\
526                    {'desc': e.desc, 'errstr': e.errstr, 'code': e.code})
527        except RuntimeError, e:
528            sys.exit("Error processing RPC: %s" % e)
529
530        if opts.debug > 1: print >>sys.stderr, resp_dict
531
532        ea = resp_dict.get('experimentAccess', None)
533        if out_certfile and ea and ea.has_key('X509'):
534            try:
535                f = open(out_certfile, "w")
536                print >>f, ea['X509']
537                f.close()
538            except IOError:
539                sys.exit('Could not write to %s' %  out_certfile)
540        eid = resp_dict.get('experimentID', None)
541        if eid:
542            for id in eid:
543                for k in id.keys():
544                    print "%s: %s" % (k, id[k])
545
546class split(fedd_rpc):
547    def __init__(self): 
548        fedd_rpc.__init__(self, "Ns2Split")
549    def __call__(self):
550        access_keys = []
551        # Process the options using the customized option parser defined above
552        parser = fedd_split_opts(access_keys, self.add_ssh_key,
553                self.add_x509_cert)
554
555        (opts, args) = parser.parse_args()
556
557        if opts.trusted:
558            if ( not os.access(opts.trusted, os.R_OK) ) :
559                sys.exit("Cannot read trusted certificates (%s)" % opts.trusted)
560
561        if opts.debug > 0: opts.tracefile=sys.stderr
562
563        if opts.cert != None: cert = opts.cert
564        else: cert = None
565
566        if cert == None:
567            sys.exit("No certificate given (--cert) or found")
568
569        if os.access(cert, os.R_OK):
570            fid = fedid(file=cert)
571            if opts.use_fedid == True:
572                user = fid
573        else:
574            sys.exit("Cannot read certificate (%s)" % cert)
575
576        if opts.file:
577            exp_desc = ""
578            try:
579                f = open(opts.file, 'r')
580                for line in f:
581                    exp_desc += line
582                f.close()
583            except IOError:
584                sys.exit("Cannot read description file (%s)" %opts.file)
585        else:
586            sys.exit("Must specify an experiment description (--file)")
587
588        if not opts.master:
589            sys.exit("Must specify a master testbed (--master)")
590
591        out_certfile = opts.out_certfile
592
593        msg = {
594                'description': { 'ns2description': exp_desc },
595                'master': opts.master,
596                'include_fedkit': opts.fedkit,
597                }
598
599        if opts.debug > 1: print >>sys.stderr, msg
600
601        try:
602            resp_dict = self.do_rpc(msg, 
603                    opts.url, opts.transport, cert, opts.trusted, 
604                    serialize_only=opts.serialize_only,
605                    tracefile=opts.tracefile)
606        except self.RPCException, e:
607            exit_with_fault(\
608                    {'desc': e.desc, 'errstr': e.errstr, 'code': e.code})
609        except RuntimeError, e:
610            sys.exit("Error processing RPC: %s" % e)
611
612        if opts.debug > 1: print >>sys.stderr, resp_dict
613
614        out = resp_dict.get('output', None)
615
616        for line in out.splitlines():
617            print "%s" % line
618
619class access(fedd_rpc):
620    def __init__(self):
621        fedd_rpc.__init__(self, "RequestAccess")
622
623    def print_response_as_testbed(self, resp, label, out=sys.stdout):
624        """Print the response as input to the splitter script"""
625
626        e = resp['emulab']
627        p = e['project']
628        fields = { 
629                "Boss": e['boss'],
630                "OpsNode": e['ops'],
631                "Domain": e['domain'],
632                "FileServer": e['fileServer'],
633                "EventServer": e['eventServer'],
634                "Project": unpack_id(p['name'])
635                }
636        if (label != None): print >> out, "[%s]" % label
637
638        for l, v in fields.iteritems():
639            print >>out, "%s: %s" % (l, v)
640
641        for u in p['user']:
642            print >>out, "User: %s" % unpack_id(u['userID'])
643
644        for a in e['fedAttr']:
645            print >>out, "%s: %s" % (a['attribute'], a['value'])
646
647    def __call__(self):
648        access_keys = []
649        node_descs = []
650        proj = None
651
652        # Process the options using the customized option parser defined above
653        parser = fedd_access_opts(access_keys, node_descs, self.add_ssh_key,
654                self.add_x509_cert, self.add_node_desc)
655
656        (opts, args) = parser.parse_args()
657
658        if opts.testbed == None:
659            parser.error("--testbed is required")
660
661        if opts.trusted:
662            if ( not os.access(opts.trusted, os.R_OK) ) :
663                sys.exit("Cannot read trusted certificates (%s)" % opts.trusted)
664
665        if opts.debug > 0: opts.tracefile=sys.stderr
666
667        (user, cert) = self.get_user_info(access_keys)
668
669        if opts.user: user = opts.user
670
671        if opts.cert != None: cert = opts.cert
672
673        if cert == None:
674            sys.exit("No certificate given (--cert) or found")
675
676        if os.access(cert, os.R_OK):
677            fid = fedid(file=cert)
678            if opts.use_fedid == True:
679                user = fid
680        else:
681            sys.exit("Cannot read certificate (%s)" % cert)
682
683        msg = {
684                'allocID': pack_id('test alloc'),
685                'destinationTestbed': pack_id(opts.testbed),
686                'serviceAccess' : [ { a.type: a.buf } for a in access_keys ],
687                'createAccess' : [ { a.type: a.buf } for a in access_keys ],
688                }
689
690        if len(node_descs) > 0:
691            msg['resources'] = { 
692                    'node': [ 
693                        { 
694                            'image':  n.image ,
695                            'hardware':  n.hardware,
696                            'count': n.count,
697                        } for n in node_descs],
698                    }
699
700        if opts.project != None:
701            if not opts.anonymous and user != None:
702                msg['project'] = {
703                        'name': pack_id(opts.project),
704                        'user': [ { 'userID': pack_id(user) } ],
705                        }
706            else:
707                msg['project'] = { 'name': pack_id(opts.project) }
708        else:
709            if not opts.anonymous and user != None:
710                msg['user'] = [ { 'userID': pack_id(user) } ]
711            else:
712                msg['user'] = [];
713
714        if opts.debug > 1: print >>sys.stderr, msg
715
716        try:
717            resp_dict = self.do_rpc(msg, 
718                    opts.url, opts.transport, cert, opts.trusted, 
719                    serialize_only=opts.serialize_only,
720                    tracefile=opts.tracefile)
721        except self.RPCException, e:
722            exit_with_fault(\
723                    {'desc': e.desc, 'errstr': e.errstr, 'code': e.code})
724        except RuntimeError, e:
725            sys.exit("Error processing RPC: %s" % e.message)
726
727        if opts.debug > 1: print >>sys.stderr, resp_dict
728        self.print_response_as_testbed(resp_dict, opts.label)
729
730cmds = {\
731        'create': create(),\
732        'split': split(),\
733        'access': access(),\
734        'vtopo': exp_data('Vtopo'),\
735        'vis': exp_data('Vis'),\
736        'info': exp_data('Info'),\
737        'terminate': terminate(),\
738    }
739
740operation = cmds.get(sys.argv[1], None)
741if operation:
742    del sys.argv[1]
743    operation()
744else:
745    sys.exit("Bad command: %s.  Valid ones are: %s" % \
746            (sys.argv[1], ", ".join(cmds.keys())))
747
Note: See TracBrowser for help on using the repository browser.