source: fedd/fedd_client.py @ cc58813

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

Allow image generation when not swapped in, using a fedd to do the split. Also added dynamic image sizing and ip addresses to links.

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