source: fedd/fedd_client.py @ c7910ac

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

--sshKey -> ssh_key

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