source: fedd/fedd_client.py @ 3925b50

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

add placeholder for other experiment descriptions

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