source: fedd/fedd_client.py @ 63f3746

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

Add image rendering functionality to fedd_client

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