source: fedd/fedd_client.py @ 2c6128f

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

Add support for a real fedkit tar file rather than the ad hoc script stuff.

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