source: fedd/fedd_client.py @ b4b19c7

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

Get topology information into the info operation, as annotations of a topology description. This required adding such information to the start segment replies as well

  • Property mode set to 100755
File size: 61.3 KB
Line 
1#!/usr/local/bin/python
2
3import sys
4import os
5import pwd
6import tempfile
7import subprocess
8import re
9import xml.parsers.expat
10import time
11
12from federation import fedid, service_error
13from federation.util import fedd_ssl_context, pack_id, unpack_id
14from federation.remote_service import service_caller
15from federation import topdl
16
17from optparse import OptionParser, OptionValueError
18
19
20class IDFormatException(RuntimeError): pass
21
22class access_method:
23    """Encapsulates an access method generically."""
24    (type_ssh, type_x509, type_pgp) = ('sshPubkey', 'X509', 'pgpPubkey')
25    default_type = type_ssh
26    def __init__(self, buf=None, type=None, file=None):
27        self.buf = buf
28
29        if type != None: self.type = type
30        else: self.type = access_method.default_type
31
32        if file != None:
33            self.readfile(file)
34   
35    def readfile(self, file, type=None):
36        f = open(file, "r")
37        self.buf = f.read();
38        f.close()
39        if type == None:
40            if self.type == None:
41                self.type = access_method.default_type
42        else:
43            self.type = type;
44   
45class node_desc:
46    def __init__(self, image, hardware, count=1):
47        if getattr(image, "__iter__", None) == None:
48            if image == None: self.image = [ ]
49            else: self.image = [ image ]
50        else:
51            self.image = image
52
53        if getattr(hardware, "__iter__", None) == None: 
54            if hardware == None: self.hardware = [ ]
55            else: self.hardware = [ hardware ]
56        else:
57            self.hardware = hardware
58        if count != None: self.count = int(count)
59        else: self.count = 1
60
61class fedd_client_opts(OptionParser):
62    """Encapsulate option processing in this class, rather than in main"""
63    def __init__(self):
64        OptionParser.__init__(self, usage="%prog [opts] (--help for details)",
65                version="0.1")
66
67        self.add_option("--cert", action="store", dest="cert",
68                type="string", help="my certificate file")
69        self.add_option( "--debug", action="count", dest="debug", 
70                default=0, help="Set debug.  Repeat for more information")
71        self.add_option("--serializeOnly", action="store_true", 
72                dest="serialize_only", default=False,
73                help="Print the SOAP request that would be sent and exit")
74        self.add_option("--trusted", action="store", dest="trusted",
75                type="string", help="Trusted certificates (required)")
76        self.add_option("--url", action="store", dest="url",
77                type="string",default="https://localhost:23235", 
78                help="URL to connect to (default %default)")
79        self.add_option("--transport", action="store", type="choice",
80                choices=("xmlrpc", "soap"), default="soap",
81                help="Transport for request (xmlrpc|soap) (Default: %default)")
82        self.add_option("--trace", action="store_const", dest="tracefile", 
83                const=sys.stderr, help="Print SOAP exchange to stderr")
84class fedd_new_opts(fedd_client_opts):
85    def __init__(self):
86        fedd_client_opts.__init__(self)
87        self.add_option("--experiment_cert", dest="out_certfile",
88                type="string", help="output certificate file")
89        self.add_option("--experiment_name", dest="exp_name",
90                type="string", help="Suggested experiment name")
91
92class fedd_create_opts(fedd_new_opts):
93    def __init__(self):
94        fedd_new_opts.__init__(self)
95        self.add_option("--file", dest="file", 
96                help="experiment description file")
97        self.add_option("--project", action="store", dest="project", 
98                type="string",
99                help="Project to export from master")
100        self.add_option("--master", dest="master",
101                help="Master testbed in the federation")
102
103class fedd_split_opts(fedd_create_opts):
104    def __init__(self ):
105        fedd_create_opts.__init__(self)
106        self.add_option('--fedkit', action='store_true', dest='fedkit',
107                default=False,
108                help="get output suitable for federation kit install")
109        self.add_option('--gatewaykit', action='store_true',
110                dest='gatewaykit', default=False,
111                help="get output suitable for federation gateway kit install")
112
113
114class fedd_access_opts(fedd_create_opts):
115    def __init__(self):
116        fedd_create_opts.__init__(self)
117        self.add_option("--label", action="store", dest="label",
118                type="string", help="Label for output")
119        if add_node_callback:
120            self.add_option("--node", action="callback", type="string", 
121                    callback=add_node_callback, callback_args=(node_descs,),
122                    help="Node description: image:hardware[:count]")
123        self.add_option("--testbed", action="store", dest="testbed",
124                type="string",
125                help="Testbed identifier (URI) to contact (required)")
126
127class fedd_exp_data_opts(fedd_client_opts):
128    def __init__(self):
129        fedd_client_opts.__init__(self)
130        self.add_option("--experiment_cert", dest="exp_certfile",
131                type="string", help="experiment certificate file")
132        self.add_option("--experiment_name", dest="exp_name",
133                type="string", help="human readable experiment name")
134        self.add_option("--data", dest="data", default=[],
135                action="append", type="choice",
136                choices=("id", "experimentdescription", "federant", "vtopo", 
137                    "vis", "log", "status"),
138                help="data to extract")
139
140class fedd_terminate_opts(fedd_exp_data_opts):
141    def __init__(self):
142        fedd_exp_data_opts.__init__(self)
143        self.add_option("--force", dest="force",
144                action="store_true", default=False,
145                help="Force termination if experiment is in strange state")
146        self.add_option("--logfile", dest="logfile", default=None,
147                help="File to write log to")
148        self.add_option("--print_log", dest="print_log", default=False,
149                action="store_true",
150                help="Print deallocation log to standard output")
151
152class fedd_multi_exp_data_opts(fedd_client_opts):
153    def __init__(self):
154        fedd_client_opts.__init__(self)
155        self.add_option("--data", dest="data", default=[],
156                action="append", type="choice",
157                choices=("id", "federant", "vtopo", "vis", "log", "status"),
158                help="data to extract")
159
160class fedd_spew_opts(fedd_client_opts):
161    def __init__(self):
162        fedd_client_opts.__init__(self)
163        self.add_option("--experiment_cert", dest="exp_certfile",
164                type="string", help="experiment name certificate file")
165        self.add_option("--experiment_name", dest="exp_name",
166                type="string", help="human readable experiment name")
167        self.add_option("--logfile", dest="logfile", default=None,
168                help="File to write log to")
169        self.add_option('--update_time', dest='update', type='int', default=10,
170                help='how often to update the printed log')
171
172class fedd_image_opts(fedd_exp_data_opts):
173    def __init__(self):
174        fedd_exp_data_opts.__init__(self)
175        self.add_option("--output", dest="outfile", type="string",
176                help="output image file")
177        self.add_option("--format", dest="format", type="choice", 
178                choices=("jpg", "png", "dot", "svg"),
179                help="Output file format override")
180        self.add_option("--program", dest="neato", default=None,
181                type="string",
182                help="Program compatible with dot (from graphviz) used to " + \
183                        "render image")
184        self.add_option("--labels", dest='labels', action='store_true',
185                default=True, help='Label nodes and edges')
186        self.add_option("--no_labels", dest='labels',
187                default=True, action='store_false',
188                help='Label nodes and edges')
189        self.add_option('--pixels', dest="pixels", default=None,
190                type="int",
191                help="Size of output in pixels (diagrams are square")
192
193class fedd_ns_image_opts(fedd_split_opts):
194    def __init__(self):
195        fedd_split_opts.__init__(self)
196        self.add_option("--output", dest="outfile", type="string",
197                help="output image file")
198        self.add_option("--format", dest="format", type="choice", 
199                choices=("jpg", "png", "dot", "svg"),
200                help="Output file format override")
201        self.add_option("--program", dest="neato", default=None,
202                type="string",
203                help="Program compatible with dot (from graphviz) used to " + \
204                        "render image")
205        self.add_option("--labels", dest='labels', action='store_true',
206                default=True, help='Label nodes and edges')
207        self.add_option("--no_labels", dest='labels',
208                default=True, action='store_false',
209                help='Label nodes and edges')
210        self.add_option('--pixels', dest="pixels", default=None,
211                type="int",
212                help="Size of output in pixels (diagrams are square")
213
214class fedd_start_opts(fedd_client_opts):
215    def __init__(self):
216        fedd_client_opts.__init__(self)
217        self.add_option("--file", dest="file", 
218                help="experiment description file")
219
220def exit_with_fault(dict, out=sys.stderr):
221    """ Print an error message and exit.
222
223    The dictionary contains the FeddFaultBody elements."""
224    codestr = ""
225
226    if dict.has_key('errstr'):
227        codestr = "Error: %s" % dict['errstr']
228
229    if dict.has_key('code'):
230        if len(codestr) > 0 : 
231            codestr += " (%d)" % dict['code']
232        else:
233            codestr = "Error Code: %d" % dict['code']
234
235    print>>out, codestr
236    print>>out, "Description: %s" % dict['desc']
237    sys.exit(dict.get('code', 20))
238# Base class for the various client operations.  It includes some commonly used
239# functions and classes the most important of which are the exception classes
240# and the service calling classes.
241class fedd_rpc:
242
243    class RPCException:
244        """
245        An error during the RPC exchange.  It unifies errors from both SOAP and
246        XMLPRC calls.
247        """
248        def __init__(self, fb):
249            self.desc = fb.get('desc', None)
250            self.code = fb.get('code', -1)
251            self.errstr = fb.get('errstr', None)
252
253    class caller(service_caller):
254        """
255        The caller is used by fedd_rpc.do_rpc to make the rpc call.  The extra
256        stashed information is used to parse responses a little.
257        """
258        def __init__(self, pre):
259            self.ResponseBody="%sResponseBody" % pre
260            self.method = pre
261            service_caller.__init__(self, self.method)
262
263    def __init__(self): 
264        """
265        Specialize the class for the pre method
266        """
267        self.caller = fedd_rpc.caller
268        self.RPCException = fedd_rpc.RPCException
269
270
271    def add_node_desc(self, option, opt_str, value, parser, node_descs):
272        def none_if_zero(x):
273            if len(x) > 0: return x
274            else: return None
275
276        params = map(none_if_zero, value.split(":"));
277       
278        if len(params) < 4 and len(params) > 1:
279            node_descs.append(node_desc(*params))
280        else:
281            raise OptionValueError("Bad node description: %s" % value)
282
283    def get_user_info(self):
284        pw = pwd.getpwuid(os.getuid());
285        try_cert=None
286        user = None
287
288        if pw != None:
289            user = pw[0]
290            try_cert = "%s/.ssl/emulab.pem" % pw[5];
291            if not os.access(try_cert, os.R_OK):
292                try_cert = None
293        return (user, try_cert)
294
295    def do_rpc(self, req_dict, url, transport, cert, trusted, tracefile=None,
296            serialize_only=False, caller=None):
297        """
298        The work of sending and parsing the RPC as either XMLRPC or SOAP
299        """
300
301        if caller is None: 
302            raise RuntimeError("Must provide caller to do_rpc")
303
304        context = None
305        while context == None:
306            try:
307                context = fedd_ssl_context(cert, trusted)
308            except Exception, e:
309                # Yes, doing this on message type is not ideal.  The string
310                # comes from OpenSSL, so check there is this stops working.
311                if str(e) == "bad decrypt": 
312                    print >>sys.stderr, "Bad Passphrase given."
313                else: raise
314
315        if transport == "soap":
316            if serialize_only:
317                print self.caller.serialize_soap(req_dict) 
318                sys.exit(0)
319            else:
320                try:
321                    resp = caller.call_soap_service(url, req_dict, 
322                            context=context, tracefile=tracefile)
323                except service_error, e:
324                    raise self.RPCException( {\
325                            'code': e.code, 
326                            'desc': e.desc, 
327                            'errstr': e.code_string()\
328                        })
329        elif transport == "xmlrpc":
330            if serialize_only:
331                ser = dumps((req_dict,))
332                print ser
333                sys.exit(0)
334            else:
335                try:
336                    resp = caller.call_xmlrpc_service(url, req_dict, 
337                            context=context, tracefile=tracefile)
338                except service_error, e:
339                    raise self.RPCException( {\
340                            'code': e.code, 
341                            'desc': e.desc, 
342                            'errstr': e.code_string()\
343                        })
344
345        else:
346            raise RuntimeError("Unknown RPC transport: %s" % transport)
347
348        if resp.has_key(caller.ResponseBody):
349            return resp[caller.ResponseBody]
350        else:
351            raise RuntimeError("No body in response??")
352
353class exp_data_base(fedd_rpc):
354    def __init__(self):
355        """
356        Init the various conversions
357        """
358
359        fedd_rpc.__init__(self)
360        # List of things one could ask for and what formatting routine is
361        # called.
362        self.params = {
363                'vis': ('vis', self.print_vis_or_vtopo('vis')),
364                'vtopo': ('vtopo', self.print_vis_or_vtopo('vtopo')),
365                'federant': ('federant', self.print_xml),
366                'experimentdescription': \
367                        ('experimentdescription', self.print_xml),
368                'id': ('experimentID', self.print_id),
369                'status': ('experimentStatus', self.print_string),
370                'log': ('allocationLog', self.print_string),
371                'access': ('experimentAccess', self.print_string),
372            }
373
374    # Utility functions
375    def print_string(self, d, out=sys.stdout):
376        print >>out, d
377
378    def print_id(self, d, out=sys.stdout):
379        if d:
380            for id in d:
381                for k in id.keys():
382                    print >>out, "%s: %s" % (k, id[k])
383
384    def print_xml(self, d, out=sys.stdout):
385        """
386        Very simple ugly xml formatter of the kinds of dicts that come back
387        from services.
388        """
389        if isinstance(d, dict):
390            for k, v in d.items():
391                print >>out, "<%s>" % k
392                self.print_xml(v, out)
393                print >>out, "</%s>" % k
394        elif isinstance(d, list):
395            for x in d:
396                self.print_xml(x, out)
397        else:
398            print >>out, d
399
400
401    class print_vis_or_vtopo:
402        """
403        Print the retrieved data is a simple xml representation of the dict.
404        """
405        def __init__(self, top):
406            self.xml = top
407
408        def __call__(self, d, out=sys.stdout):
409            str = "<%s>\n" % self.xml
410            for t in ('node', 'lan'):
411                if d.has_key(t): 
412                    for x in d[t]:
413                        str += "<%s>" % t
414                        for k in x.keys():
415                            str += "<%s>%s</%s>" % (k, x[k],k)
416                        str += "</%s>\n" % t
417            str+= "</%s>" % self.xml
418            print >>out, str
419
420       
421
422# Querying experiment data follows the same control flow regardless of the
423# specific data retrieved.  This class encapsulates that control flow.
424class exp_data(exp_data_base):
425    def __init__(self): 
426        exp_data_base.__init__(self)
427
428    def __call__(self):
429        """
430        The control flow.  Compose the request and print the response.
431        """
432        # Process the options using the customized option parser defined above
433        parser = fedd_exp_data_opts()
434
435        (opts, args) = parser.parse_args()
436
437        if opts.trusted:
438            if ( not os.access(opts.trusted, os.R_OK) ) :
439                sys.exit("Cannot read trusted certificates (%s)" % opts.trusted)
440
441        if opts.debug > 0: opts.tracefile=sys.stderr
442
443        (user, cert) = self.get_user_info()
444
445        if opts.cert != None: cert = opts.cert
446
447        if cert == None:
448            sys.exit("No certificate given (--cert) or found")
449
450        if os.access(cert, os.R_OK):
451            fid = fedid(file=cert)
452        else:
453            sys.exit("Cannot read certificate (%s)" % cert)
454
455        if opts.exp_name and opts.exp_certfile:
456            sys.exit("Only one of --experiment_cert and " +\
457                    "--experiment_name permitted");
458
459        exp_id = None
460        if opts.exp_certfile:
461            exp_id = { 'fedid': fedid(file=opts.exp_certfile) }
462
463        if opts.exp_name:
464            exp_id = { 'localname' : opts.exp_name }
465
466        if not exp_id:
467            sys.exit("specify one of --experiment_cert and --experiment_name")
468
469
470        req = { 'experiment': exp_id }
471
472        try:
473            resp_dict = self.do_rpc(req,
474                    opts.url, opts.transport, cert, opts.trusted, 
475                    serialize_only=opts.serialize_only,
476                    tracefile=opts.tracefile,
477                    caller=self.caller('Info'))
478        except self.RPCException, e:
479            exit_with_fault(\
480                    {'desc': e.desc, 'errstr': e.errstr, 'code': e.code})
481        except RuntimeError, e:
482            sys.exit("Error processing RPC: %s" % e)
483
484        for d in opts.data:
485            key, output = self.params[d]
486            try:
487                if resp_dict.has_key(key):
488                    output(resp_dict[key])
489            except RuntimeError, e:
490                sys.exit("Bad response. %s" % e.message)
491
492class vtopo(exp_data):
493    """
494    vtopo is just an info --data=vtopo request, so this adds that parameter to
495    the arguments and executes exp_info when called.
496    """
497    def __init__(self):
498        exp_data.__init__(self)
499    def __call__(self):
500        sys.argv.append('--data=vtopo')
501        exp_data.__call__(self)
502
503
504class vis(exp_data):
505    """
506    vis is just an info --data=vis request, so this adds that parameter to
507    the arguments and executes exp_info when called.
508    """
509    def __init__(self):
510        exp_data.__init__(self)
511    def __call__(self):
512        sys.argv.append('--data=vis')
513        exp_data.__call__(self)
514
515class status(exp_data):
516    """
517    status is just an info --data=status request, so this adds that parameter
518    to the arguments and executes exp_info when called.
519    """
520    def __init__(self):
521        exp_data.__init__(self)
522    def __call__(self):
523        sys.argv.append('--data=status')
524        exp_data.__call__(self)
525
526class multi_exp_data(exp_data_base):
527    def __init__(self): 
528        exp_data_base.__init__(self)
529
530
531    def __call__(self):
532        """
533        The control flow.  Compose the request and print the response.
534        """
535        # Process the options using the customized option parser defined above
536        parser = fedd_multi_exp_data_opts()
537
538        (opts, args) = parser.parse_args()
539
540        if opts.trusted:
541            if ( not os.access(opts.trusted, os.R_OK) ) :
542                sys.exit("Cannot read trusted certificates (%s)" % opts.trusted)
543
544        if opts.debug > 0: opts.tracefile=sys.stderr
545
546        (user, cert) = self.get_user_info()
547
548        if opts.cert != None: cert = opts.cert
549
550        if cert == None:
551            sys.exit("No certificate given (--cert) or found")
552
553        if os.access(cert, os.R_OK):
554            fid = fedid(file=cert)
555        else:
556            sys.exit("Cannot read certificate (%s)" % cert)
557
558        req = { }
559
560        try:
561            resp_dict = self.do_rpc(req,
562                    opts.url, opts.transport, cert, opts.trusted, 
563                    serialize_only=opts.serialize_only,
564                    tracefile=opts.tracefile,
565                    caller=self.caller('MultiInfo'))
566        except self.RPCException, e:
567            exit_with_fault(\
568                    {'desc': e.desc, 'errstr': e.errstr, 'code': e.code})
569        except RuntimeError, e:
570            sys.exit("Error processing RPC: %s" % e)
571
572        exps = resp_dict.get('info', [])
573        if exps:
574            print '---'
575            for exp in exps:
576                for d in opts.data:
577                    key, output = self.params[d]
578                    try:
579                        if exp.has_key(key):
580                            output(exp[key])
581                    except RuntimeError, e:
582                        sys.exit("Bad response. %s" % e.message)
583                print '---'
584
585
586class multi_status(exp_data_base):
587    def __init__(self): 
588        exp_data_base.__init__(self)
589
590
591    def __call__(self):
592        """
593        The control flow.  Compose the request and print the response.
594        """
595        # Process the options using the customized option parser defined above
596        parser = fedd_client_opts()
597
598        (opts, args) = parser.parse_args()
599
600        if opts.trusted:
601            if ( not os.access(opts.trusted, os.R_OK) ) :
602                sys.exit("Cannot read trusted certificates (%s)" % opts.trusted)
603
604        if opts.debug > 0: opts.tracefile=sys.stderr
605
606        (user, cert) = self.get_user_info()
607
608        if opts.cert != None: cert = opts.cert
609
610        if cert == None:
611            sys.exit("No certificate given (--cert) or found")
612
613        if os.access(cert, os.R_OK):
614            fid = fedid(file=cert)
615        else:
616            sys.exit("Cannot read certificate (%s)" % cert)
617
618        req = { }
619
620        try:
621            resp_dict = self.do_rpc(req,
622                    opts.url, opts.transport, cert, opts.trusted, 
623                    serialize_only=opts.serialize_only,
624                    tracefile=opts.tracefile,
625                    caller=self.caller('MultiInfo'))
626        except self.RPCException, e:
627            exit_with_fault(\
628                    {'desc': e.desc, 'errstr': e.errstr, 'code': e.code})
629        except RuntimeError, e:
630            sys.exit("Error processing RPC: %s" % e)
631
632        for exp in resp_dict.get('info', []):
633            out = []
634            for eid in exp.get('experimentID', []):
635                if eid.has_key('localname'):
636                    out.append(eid['localname'])
637                    break
638            else:
639                out.append("")
640            for eid in exp.get('experimentID', []):
641                if eid.has_key('fedid'):
642                    out.append("%s" % eid['fedid'])
643                    break
644            else:
645                out.append("")
646
647            out.append(exp.get('experimentStatus', ""))
648
649            for f in exp.get('federant', []):
650                if f.get('master', False):
651                    em = f.get('emulab', None)
652                    if em:
653                        project = em.get('project', None)
654                        if project:
655                            tb = project.get('testbed', None)
656                            if tb and tb.has_key('localname'):
657                                out.append(tb['localname'])
658                            else:
659                                out.append("")
660                            pn = project.get('name', None)
661                            if pn and pn.has_key('localname'):
662                                out.append(pn['localname'])
663                            else:
664                                out.append("")
665                        else:
666                            out.extend(("", ""))
667                    else:
668                        out.extend(("", ""))
669                    break
670            else:
671                out.extend(("",""))
672
673            print ":".join(out)
674
675class image(fedd_rpc):
676    def __init__(self): 
677        """
678        Null constructor
679        """
680
681        fedd_rpc.__init__(self)
682
683    @staticmethod
684    def gen_dot_topo(d, labels, dotfile):
685        lans = { }
686        links = { }
687
688        for n in d.get('node', []):
689            print >>dotfile, '\t"%s" [shape=box,style=filled,\\' % n['vname']
690            print >>dotfile, '\t\tcolor=black,fillcolor="#60f8c0",regular=1]'
691
692        # Collect lan members (we have to draw extra stuff for these)
693        for n in d.get('lan', []):
694            v = n['vname']
695            m = n['member']
696            i = n['ip']
697            if m.find(':') != -1:
698                m = m[0:m.find(':')]
699            if lans.has_key(v):
700                lans[v].append((m, i))
701            elif links.has_key(v):
702                links[v].append((m, i))
703                if len(links[v]) > 2:
704                    lans[v] = links[v]
705                    del links[v]
706            else:
707                links[v] = [(m, i)]
708
709        # Encode the lans and the links
710        for l in lans.keys():
711            print >>dotfile, '\t"%s" [shape=ellipse, style=filled,\\' % l
712            print >>dotfile,'\t\tcolor=black,fillcolor="#80c0f8",regular=1]'
713            for n in lans[l]:
714                if labels:
715                    print >>dotfile, '\t"%s" -- "%s" [headlabel="%s"]' % \
716                            (l, n[0], n[1])
717                else:
718                    print >>dotfile, '\t"%s" -- "%s"' % (l, n[0])
719
720        for k, l in links.items():
721            if len(l) == 2:
722                if labels:
723                    print >>dotfile, \
724                            ('\t"%s" -- "%s" [label="%s",taillabel="%s",' + \
725                            'headlabel="%s"]') % \
726                            (l[0][0], l[1][0], k, l[0][1], l[1][1])
727                else:
728                    print >>dotfile, '\t"%s" -- "%s" ' % (l[0][0], l[1][0])
729
730
731    def gen_image(self, d, nodes, file, fmt, neato, labels, pix=None):
732
733        # Open up a temporary file for dot to turn into a visualization
734        try:
735            df, dotname = tempfile.mkstemp(prefix='fedd_client', suffix=".dot")
736            dotfile = os.fdopen(df, 'w')
737        except IOError:
738            raise service_error(service_error.internal,
739                    "Failed to open file in genviz")
740
741        if not neato:
742            for f in ['/usr/bin/neato', '/usr/local/bin/neato', 
743                    '/usr/bin/dot', '/usr/local/bin/dot']:
744                if os.access(f, os.X_OK):
745                    neato = f
746                    break
747            else:
748                sys.exit("Cannot find graph rendering program")
749
750        cmd = [neato, '-Gsplines=true']
751        if fmt != 'dot': cmd.append('-T%s' % fmt)
752        if file:
753            cmd.append('-o')
754            cmd.append(file)
755        cmd.append(dotname)
756
757        #nodes = d.get('node',[])
758
759        if nodes < 10: size = 5
760        elif nodes < 50: size = 10
761        else: size = 18
762
763        if pix:
764            dpi = pix / size
765        else:
766            dpi = None
767
768
769        print >>dotfile, "graph G {"
770        if dpi:
771            print >>dotfile, '\tgraph [size="%i,%i", dpi="%i", ratio=fill];' \
772                    % (size, size, dpi)
773        else:
774            print >>dotfile, '\tgraph [size="%i,%i", ratio=fill];' \
775                    % (size, size)
776
777        if labels:
778            print >>dotfile, '\tnode [fontname=arial,fontsize=9,label="\N"];'
779            print >>dotfile, '\tedge [fontname=arial,fontsize=9];\n'
780        else:
781            print >>dotfile, '\tnode [label=""];'
782
783
784        self.gen_dot_topo(d, labels, dotfile)
785        print >>dotfile, "}"
786        dotfile.close()
787
788        # Redirect the drawing program stderr
789        dev_null = open("/dev/null", "w")
790        rv = subprocess.call(cmd, stderr=dev_null)
791        os.remove(dotname)
792        dev_null.close()
793        if rv != 0:
794            sys.exit("Error creating graph")
795
796
797
798    def __call__(self):
799        """
800        The control flow.  Compose the request and print the response.
801        """
802        # Process the options using the customized option parser defined above
803        parser = fedd_image_opts()
804
805        (opts, args) = parser.parse_args()
806
807        if opts.trusted:
808            if ( not os.access(opts.trusted, os.R_OK) ) :
809                sys.exit("Cannot read trusted certificates (%s)" % opts.trusted)
810
811        if opts.debug > 0: opts.tracefile=sys.stderr
812
813        (user, cert) = self.get_user_info()
814
815        if opts.cert != None: cert = opts.cert
816
817        if cert == None:
818            sys.exit("No certificate given (--cert) or found")
819
820        if os.access(cert, os.R_OK):
821            fid = fedid(file=cert)
822        else:
823            sys.exit("Cannot read certificate (%s)" % cert)
824
825        if opts.exp_name and opts.exp_certfile:
826            sys.exit("Only one of --experiment_cert and " +\
827                    "--experiment_name permitted");
828
829        if opts.exp_certfile:
830            exp_id = { 'fedid': fedid(file=opts.exp_certfile) }
831
832        if opts.exp_name:
833            exp_id = { 'localname' : opts.exp_name }
834
835        if opts.format and opts.outfile:
836            fmt = opts.format
837            file = opts.outfile
838        elif not opts.format and opts.outfile:
839            fmt = opts.outfile[-3:]
840            if fmt not in ("png", "jpg", "dot", "svg"):
841                sys.exit("Unexpected file type and no format specified")
842            file = opts.outfile
843        elif opts.format and not opts.outfile:
844            fmt = opts.format
845            file = None
846        else:
847            fmt="dot"
848            file = None
849
850
851        req = { 'experiment': exp_id }
852
853        try:
854            resp_dict = self.do_rpc(req,
855                    opts.url, opts.transport, cert, opts.trusted, 
856                    serialize_only=opts.serialize_only,
857                    tracefile=opts.tracefile,
858                    caller=self.caller('Vtopo'))
859        except self.RPCException, e:
860            exit_with_fault(\
861                    {'desc': e.desc, 'errstr': e.errstr, 'code': e.code})
862        except RuntimeError, e:
863            sys.exit("Error processing RPC: %s" % e)
864
865
866        if resp_dict.has_key('vtopo'):
867            self.gen_image(resp_dict['vtopo'], 
868                    len(resp_dict['vtopo'].get('node', [])),
869                    file, fmt, opts.neato, opts.labels, opts.pixels)
870        else:
871            sys.exit("Bad response. %s" % e.message)
872
873class ns_image(image):
874    def __init__(self): 
875        """
876        Null constructor
877        """
878
879        image.__init__(self)
880
881    def generate_topo_dict(self, splitout):
882        class topo_parse:
883            """
884            Parse the topology XML and create the dats structure.  This class
885            is copied from federation.experiment_control.
886            """
887            def __init__(self):
888                # Typing of the subelements for data conversion
889                self.str_subelements = ('vname', 'vnode', 'ips', 'ip', 'member')
890                self.int_subelements = ( 'bandwidth',)
891                self.float_subelements = ( 'delay',)
892                # The final data structure
893                self.nodes = [ ]
894                self.lans =  [ ]
895                self.topo = { \
896                        'node': self.nodes,\
897                        'lan' : self.lans,\
898                    }
899                self.element = { }  # Current element being created
900                self.chars = ""     # Last text seen
901
902            def end_element(self, name):
903                # After each sub element the contents is added to the current
904                # element or to the appropriate list.
905                if name == 'node':
906                    self.nodes.append(self.element)
907                    self.element = { }
908                elif name == 'lan':
909                    self.lans.append(self.element)
910                    self.element = { }
911                elif name in self.str_subelements:
912                    self.element[name] = self.chars
913                    self.chars = ""
914                elif name in self.int_subelements:
915                    self.element[name] = int(self.chars)
916                    self.chars = ""
917                elif name in self.float_subelements:
918                    self.element[name] = float(self.chars)
919                    self.chars = ""
920
921            def found_chars(self, data):
922                self.chars += data.rstrip()
923
924
925        tp = topo_parse();
926        parser = xml.parsers.expat.ParserCreate()
927        parser.EndElementHandler = tp.end_element
928        parser.CharacterDataHandler = tp.found_chars
929
930        m = re.search('^#\s+Begin\s+Vtopo\s*$(.*)^#\s+End\s+Vtopo', splitout, 
931                re.MULTILINE | re.DOTALL)
932        if m:
933            str = m.group(1)
934        else:
935            sys.exit("Badly formatted split")
936
937        parser.Parse(str)
938
939        return tp.topo
940
941    def __call__(self):
942        """
943        The control flow.  Compose the request and print the response.
944        """
945        # Process the options using the customized option parser defined above
946        parser = fedd_ns_image_opts()
947
948        (opts, args) = parser.parse_args()
949
950        if opts.trusted:
951            if ( not os.access(opts.trusted, os.R_OK) ) :
952                sys.exit("Cannot read trusted certificates (%s)" % opts.trusted)
953
954        if opts.debug > 0: opts.tracefile=sys.stderr
955
956        (user, cert) = self.get_user_info()
957
958        if opts.cert != None: cert = opts.cert
959
960        if cert == None:
961            sys.exit("No certificate given (--cert) or found")
962
963        if os.access(cert, os.R_OK):
964            fid = fedid(file=cert)
965        else:
966            sys.exit("Cannot read certificate (%s)" % cert)
967
968        if opts.file:
969            exp_desc = ""
970            try:
971                f = open(opts.file, 'r')
972                for line in f:
973                    exp_desc += line
974                f.close()
975            except IOError:
976                sys.exit("Cannot read description file (%s)" %opts.file)
977        else:
978            sys.exit("Must specify an experiment description (--file)")
979
980        if not opts.master:
981            opts.master="dummy"
982
983
984        req = {
985                'description': { 'ns2description': exp_desc },
986                'master': opts.master,
987                'include_fedkit': opts.fedkit,
988                'include_gatewaykit': opts.gatewaykit,
989                }
990
991
992        if opts.format and opts.outfile:
993            fmt = opts.format
994            file = opts.outfile
995        elif not opts.format and opts.outfile:
996            fmt = opts.outfile[-3:]
997            if fmt not in ("png", "jpg", "dot", "svg"):
998                sys.exit("Unexpected file type and no format specified")
999            file = opts.outfile
1000        elif opts.format and not opts.outfile:
1001            fmt = opts.format
1002            file = None
1003        else:
1004            fmt="dot"
1005            file = None
1006
1007        try:
1008            resp_dict = self.do_rpc(req,
1009                    opts.url, opts.transport, cert, opts.trusted, 
1010                    serialize_only=opts.serialize_only,
1011                    tracefile=opts.tracefile,
1012                    caller=self.caller('Ns2Split'))
1013        except self.RPCException, e:
1014            exit_with_fault(\
1015                    {'desc': e.desc, 'errstr': e.errstr, 'code': e.code})
1016        except RuntimeError, e:
1017            sys.exit("Error processing RPC: %s" % e)
1018
1019
1020        if resp_dict.has_key('output'):
1021            if len(resp_dict['output']) < 1:
1022                sys.exit("Bad response: could not split")
1023            topo = self.generate_topo_dict(resp_dict['output'])
1024            self.gen_image(topo, len(topo.get('node', [])), file, fmt,
1025                    opts.neato, opts.labels, opts.pixels)
1026        else:
1027            sys.exit("Bad response. %s" % e.message)
1028
1029class topdl_image(image):
1030    def __init__(self): 
1031        """
1032        Null constructor
1033        """
1034
1035        image.__init__(self)
1036
1037    @staticmethod
1038    def gen_dot_topo(t, labels, dotfile):
1039        lans = [ s for s in t.substrates if len(s.interfaces) != 2]
1040        links = [ s for s in t.substrates if len(s.interfaces) == 2]
1041
1042        i = 0
1043        for n in t.elements:
1044            if n.name:
1045                print >>dotfile, '\t"%s" [shape=box,style=filled,\\' % n.name[0]
1046            else:
1047                print >>dotfile, \
1048                        '\t"unnamed_node%d" [shape=box,style=filled,\\' % i
1049                i += 1
1050            print >>dotfile, '\t\tcolor=black,fillcolor="#60f8c0",regular=1]'
1051
1052        # Encode the lans and the links
1053        for l in lans:
1054            print >>dotfile, '\t"%s" [shape=ellipse, style=filled,\\' % l.name
1055            print >>dotfile,'\t\tcolor=black,fillcolor="#80c0f8",regular=1]'
1056            for i in l.interfaces:
1057                ip = i.get_attribute('ip4_address')
1058                if labels and ip:
1059                    print >>dotfile, '\t"%s" -- "%s" [headlabel="%s"]' % \
1060                            (l.name, i.element.name[0], ip)
1061                else:
1062                    print >>dotfile, '\t"%s" -- "%s"' % \
1063                            (l.name, i.element.name[0])
1064
1065        for l in links:
1066            s, d = l.interfaces[0:2] 
1067            sip = s.get_attribute('ip4_address')
1068            dip = d.get_attribute('ip4_address')
1069            if labels and sip and dip:
1070                print >>dotfile, \
1071                        ('\t"%s" -- "%s" [label="%s",taillabel="%s",' + \
1072                        'headlabel="%s"]') % \
1073                        (s.element.name[0], d.element.name[0], l.name,
1074                            sip, dip)
1075            else:
1076                print >>dotfile, '\t"%s" -- "%s" ' % \
1077                        (s.element.name[0], d.element.name[0])
1078    def __call__(self):
1079        """
1080        The control flow.  Compose the request and print the response.
1081        """
1082        # Process the options using the customized option parser defined above
1083        parser = fedd_ns_image_opts()
1084
1085        (opts, args) = parser.parse_args()
1086
1087        if opts.trusted:
1088            if ( not os.access(opts.trusted, os.R_OK) ) :
1089                sys.exit("Cannot read trusted certificates (%s)" % opts.trusted)
1090
1091        if opts.debug > 0: opts.tracefile=sys.stderr
1092
1093        (user, cert) = self.get_user_info()
1094
1095        if opts.cert != None: cert = opts.cert
1096
1097        if cert == None:
1098            sys.exit("No certificate given (--cert) or found")
1099
1100        if os.access(cert, os.R_OK):
1101            fid = fedid(file=cert)
1102        else:
1103            sys.exit("Cannot read certificate (%s)" % cert)
1104
1105        if opts.file:
1106            exp_desc = ""
1107            try:
1108                top = topdl.topology_from_xml(filename=opts.file, 
1109                        top="experiment")
1110            except IOError:
1111                sys.exit("Cannot read description file (%s)" % opts.file)
1112        else:
1113            sys.exit("Must specify an experiment description (--file)")
1114
1115        if not opts.master:
1116            opts.master="dummy"
1117
1118
1119        if opts.format and opts.outfile:
1120            fmt = opts.format
1121            file = opts.outfile
1122        elif not opts.format and opts.outfile:
1123            fmt = opts.outfile[-3:]
1124            if fmt not in ("png", "jpg", "dot", "svg"):
1125                sys.exit("Unexpected file type and no format specified")
1126            file = opts.outfile
1127        elif opts.format and not opts.outfile:
1128            fmt = opts.format
1129            file = None
1130        else:
1131            fmt="dot"
1132            file = None
1133
1134        self.gen_image(top, len(top.elements), file, fmt, opts.neato, 
1135                opts.labels, opts.pixels)
1136
1137class terminate(fedd_rpc):
1138    def __init__(self): 
1139        """
1140        Termination request
1141        """
1142
1143        fedd_rpc.__init__(self)
1144
1145    def __call__(self):
1146        """
1147        The control flow.  Compose the request and print the response.
1148        """
1149        # Process the options using the customized option parser defined above
1150        parser = fedd_terminate_opts()
1151
1152        (opts, args) = parser.parse_args()
1153
1154        (user, cert) = self.get_user_info()
1155        if opts.trusted:
1156            if ( not os.access(opts.trusted, os.R_OK) ) :
1157                sys.exit("Cannot read trusted certificates (%s)" % opts.trusted)
1158
1159        if opts.debug > 0: opts.tracefile=sys.stderr
1160
1161        if opts.cert != None: cert = opts.cert
1162
1163        if cert == None:
1164            sys.exit("No certificate given (--cert) or found")
1165
1166        if os.access(cert, os.R_OK):
1167            fid = fedid(file=cert)
1168        else:
1169            sys.exit("Cannot read certificate (%s)" % cert)
1170
1171        if opts.exp_name and opts.exp_certfile:
1172            sys.exit("Only one of --experiment_cert and " +\
1173                    "--experiment_name permitted")
1174
1175        if opts.print_log and opts.logfile:
1176            sys.exit("Only one of --logfile and --print_log is permitted")
1177        elif opts.print_log:
1178            out = sys.stdout
1179        elif opts.logfile:
1180            try:
1181                out = open(opts.logfile, "w")
1182            except IOError,e:
1183                sys.exit("Cannot open logfile: %s" %e)
1184        else:
1185            out = None
1186
1187        exp_id = None
1188
1189        if opts.exp_certfile:
1190            exp_id = { 'fedid': fedid(file=opts.exp_certfile) }
1191
1192        if opts.exp_name:
1193            exp_id = { 'localname' : opts.exp_name }
1194
1195        if not exp_id:
1196            sys.exit("Must give one of --experiment_cert and " +\
1197                    "--experiment_name");
1198
1199        req = { 'experiment': exp_id, 'force': opts.force }
1200
1201        try:
1202            resp_dict = self.do_rpc(req,
1203                    opts.url, opts.transport, cert, opts.trusted, 
1204                    serialize_only=opts.serialize_only,
1205                    tracefile=opts.tracefile,
1206                    caller=self.caller('Terminate'))
1207        except self.RPCException, e:
1208            exit_with_fault(\
1209                    {'desc': e.desc, 'errstr': e.errstr, 'code': e.code})
1210        except RuntimeError, e:
1211            print e
1212            sys.exit("Error processing RPC: %s" % e)
1213
1214        if out:
1215            log = resp_dict.get('deallocationLog', None)
1216            if log:
1217                print >>out, log
1218                out.close()
1219            else:
1220                out.close()
1221                sys.exit("No log returned")
1222
1223class terminate_segment(fedd_rpc):
1224    def __init__(self): 
1225        """
1226        Termination request
1227        """
1228
1229        fedd_rpc.__init__(self)
1230
1231    def __call__(self):
1232        """
1233        The control flow.  Compose the request and print the response.
1234        """
1235        # Process the options using the customized option parser defined above
1236        parser = fedd_terminate_opts()
1237
1238        (opts, args) = parser.parse_args()
1239
1240        (user, cert) = self.get_user_info()
1241        if opts.trusted:
1242            if ( not os.access(opts.trusted, os.R_OK) ) :
1243                sys.exit("Cannot read trusted certificates (%s)" % opts.trusted)
1244
1245        if opts.debug > 0: opts.tracefile=sys.stderr
1246
1247        if opts.cert != None: cert = opts.cert
1248
1249        if cert == None:
1250            sys.exit("No certificate given (--cert) or found")
1251
1252        if os.access(cert, os.R_OK):
1253            fid = fedid(file=cert)
1254        else:
1255            sys.exit("Cannot read certificate (%s)" % cert)
1256
1257        if opts.exp_name and opts.exp_certfile:
1258            sys.exit("Only one of --experiment_cert and " +\
1259                    "--experiment_name permitted")
1260
1261        if opts.print_log and opts.logfile:
1262            sys.exit("Only one of --logfile and --print_log is permitted")
1263        elif opts.print_log:
1264            out = sys.stdout
1265        elif opts.logfile:
1266            try:
1267                out = open(opts.logfile, "w")
1268            except IOError,e:
1269                sys.exit("Cannot open logfile: %s" %e)
1270        else:
1271            out = None
1272
1273        exp_id = None
1274
1275        if opts.exp_certfile:
1276            exp_id = { 'fedid': fedid(file=opts.exp_certfile) }
1277
1278        if opts.exp_name:
1279            exp_id = { 'localname' : opts.exp_name }
1280
1281        if not exp_id:
1282            sys.exit("Must give one of --experiment_cert and " +\
1283                    "--experiment_name");
1284
1285        req = { 'allocID': exp_id, 'force': opts.force }
1286
1287        try:
1288            resp_dict = self.do_rpc(req,
1289                    opts.url, opts.transport, cert, opts.trusted, 
1290                    serialize_only=opts.serialize_only,
1291                    tracefile=opts.tracefile,
1292                    caller=self.caller('TerminateSegment'))
1293        except self.RPCException, e:
1294            exit_with_fault(\
1295                    {'desc': e.desc, 'errstr': e.errstr, 'code': e.code})
1296        except RuntimeError, e:
1297            print e
1298            sys.exit("Error processing RPC: %s" % e)
1299
1300        if out:
1301            log = resp_dict.get('deallocationLog', None)
1302            if log:
1303                print >>out, log
1304                out.close()
1305            else:
1306                out.close()
1307                sys.exit("No log returned")
1308
1309class new(fedd_rpc):
1310    def __init__(self): 
1311        fedd_rpc.__init__(self)
1312    def __call__(self):
1313        # Process the options using the customized option parser defined above
1314        parser = fedd_new_opts()
1315
1316        (opts, args) = parser.parse_args()
1317
1318        if opts.trusted:
1319            if ( not os.access(opts.trusted, os.R_OK) ) :
1320                sys.exit("Cannot read trusted certificates (%s)" % opts.trusted)
1321
1322        if opts.debug > 0: opts.tracefile=sys.stderr
1323
1324        (user, cert) = self.get_user_info()
1325
1326        if opts.cert != None: cert = opts.cert
1327
1328        if cert == None:
1329            sys.exit("No certificate given (--cert) or found")
1330
1331        if os.access(cert, os.R_OK):
1332            fid = fedid(file=cert)
1333        else:
1334            sys.exit("Cannot read certificate (%s)" % cert)
1335
1336        out_certfile = opts.out_certfile
1337
1338        msg = { }
1339
1340        if opts.exp_name:
1341            msg['experimentID'] = { 'localname': opts.exp_name }
1342
1343        if opts.debug > 1: print >>sys.stderr, msg
1344
1345        try:
1346            resp_dict = self.do_rpc(msg, 
1347                    opts.url, opts.transport, cert, opts.trusted, 
1348                    serialize_only=opts.serialize_only,
1349                    tracefile=opts.tracefile, 
1350                    caller=self.caller("New"))
1351        except self.RPCException, e:
1352            exit_with_fault(\
1353                    {'desc': e.desc, 'errstr': e.errstr, 'code': e.code})
1354        except RuntimeError, e:
1355            sys.exit("Error processing RPC: %s" % e)
1356
1357        if opts.debug > 1: print >>sys.stderr, resp_dict
1358
1359        ea = resp_dict.get('experimentAccess', None)
1360        if out_certfile and ea and ea.has_key('X509'):
1361            try:
1362                f = open(out_certfile, "w")
1363                print >>f, ea['X509']
1364                f.close()
1365            except IOError:
1366                sys.exit('Could not write to %s' %  out_certfile)
1367        eid = resp_dict.get('experimentID', None)
1368        if eid:
1369            for id in eid:
1370                for k in id.keys():
1371                    print "%s: %s" % (k, id[k])
1372        st = resp_dict.get('experimentStatus', None)
1373        if st:
1374            print "status: %s" % st
1375
1376
1377class create(fedd_rpc):
1378    def __init__(self): 
1379        fedd_rpc.__init__(self)
1380    def __call__(self):
1381        parser = fedd_create_opts()
1382
1383        (opts, args) = parser.parse_args()
1384
1385        if opts.trusted:
1386            if ( not os.access(opts.trusted, os.R_OK) ) :
1387                sys.exit("Cannot read trusted certificates (%s)" % opts.trusted)
1388
1389        if not opts.project :
1390            parser.error('--project is required')
1391
1392        if opts.debug > 0: opts.tracefile=sys.stderr
1393
1394        (user, cert) = self.get_user_info()
1395
1396        if opts.cert != None: cert = opts.cert
1397
1398        if cert == None:
1399            sys.exit("No certificate given (--cert) or found")
1400
1401        if os.access(cert, os.R_OK):
1402            fid = fedid(file=cert)
1403        else:
1404            sys.exit("Cannot read certificate (%s)" % cert)
1405
1406        if opts.file:
1407            exp_desc = ""
1408            try:
1409                f = open(opts.file, 'r')
1410                for line in f:
1411                    exp_desc += line
1412                f.close()
1413            except IOError:
1414                sys.exit("Cannot read description file (%s)" %opts.file)
1415        else:
1416            sys.exit("Must specify an experiment description (--file)")
1417
1418        if not opts.master:
1419            sys.exit("Must specify a master testbed (--master)")
1420
1421        out_certfile = opts.out_certfile
1422
1423        msg = { }
1424
1425        if opts.exp_name:
1426            msg['experimentID'] = { 'localname': opts.exp_name }
1427
1428        if opts.debug > 1: print >>sys.stderr, msg
1429
1430        try:
1431            resp_dict = self.do_rpc(msg, 
1432                    opts.url, opts.transport, cert, opts.trusted, 
1433                    serialize_only=opts.serialize_only,
1434                    tracefile=opts.tracefile,
1435                    caller=self.caller('New'))
1436        except self.RPCException, e:
1437            exit_with_fault(\
1438                    {'desc': e.desc, 'errstr': e.errstr, 'code': e.code})
1439        except RuntimeError, e:
1440            sys.exit("Error processing RPC: %s" % e)
1441
1442        if opts.debug > 1: print >>sys.stderr, resp_dict
1443
1444        ea = resp_dict.get('experimentAccess', None)
1445        if out_certfile and ea and ea.has_key('X509'):
1446            try:
1447                f = open(out_certfile, "w")
1448                print >>f, ea['X509']
1449                f.close()
1450            except IOError:
1451                sys.exit('Could not write to %s' %  out_certfile)
1452        eid = resp_dict.get('experimentID', None)
1453        e_fedid = None
1454        e_local = None
1455        if eid:
1456            for id in eid:
1457                for k in id.keys():
1458                    if k =='fedid':
1459                        e_fedid = id[k]
1460                    elif k =='localname':
1461                        e_local = id[k]
1462
1463        msg = {
1464                'experimentdescription': { 'ns2description': exp_desc },
1465                'service': [ {
1466                    'name': 'project_export', 
1467                    'export': [opts.master], 
1468                    'fedAttr': [ 
1469                        { 'attribute': 'project', 'value': opts.project },
1470                        ],
1471                    }, ]
1472            }
1473
1474        if e_fedid:
1475            msg['experimentID'] = { 'fedid': e_fedid }
1476        elif e_local:
1477            msg['experimentID'] = { 'localname': e_local }
1478        else:
1479            sys.exit("New did not return an experiment ID??")
1480
1481        if opts.debug > 1: print >>sys.stderr, msg
1482
1483        try:
1484            resp_dict = self.do_rpc(msg, 
1485                    opts.url, opts.transport, cert, opts.trusted, 
1486                    serialize_only=opts.serialize_only,
1487                    tracefile=opts.tracefile,
1488                    caller=self.caller('Create'))
1489        except self.RPCException, e:
1490            exit_with_fault(\
1491                    {'desc': e.desc, 'errstr': e.errstr, 'code': e.code})
1492        except RuntimeError, e:
1493            sys.exit("Error processing RPC: %s" % e)
1494
1495        if opts.debug > 1: print >>sys.stderr, resp_dict
1496
1497        ea = resp_dict.get('experimentAccess', None)
1498        if out_certfile and ea and ea.has_key('X509'):
1499            try:
1500                f = open(out_certfile, "w")
1501                print >>f, ea['X509']
1502                f.close()
1503            except IOError:
1504                sys.exit('Could not write to %s' %  out_certfile)
1505        eid = resp_dict.get('experimentID', None)
1506        if eid:
1507            for id in eid:
1508                for k in id.keys():
1509                    print "%s: %s" % (k, id[k])
1510        st = resp_dict.get('experimentStatus', None)
1511        if st:
1512            print "status: %s" % st
1513
1514class split(fedd_rpc):
1515    def __init__(self): 
1516        fedd_rpc.__init__(self)
1517    def __call__(self):
1518        # Process the options using the customized option parser defined above
1519        parser = fedd_split_opts()
1520
1521        (opts, args) = parser.parse_args()
1522
1523        if opts.trusted:
1524            if ( not os.access(opts.trusted, os.R_OK) ) :
1525                sys.exit("Cannot read trusted certificates (%s)" % opts.trusted)
1526
1527        if opts.debug > 0: opts.tracefile=sys.stderr
1528
1529        (user, cert) = self.get_user_info()
1530
1531        if opts.cert != None: cert = opts.cert
1532
1533        if cert == None:
1534            sys.exit("No certificate given (--cert) or found")
1535
1536        if os.access(cert, os.R_OK):
1537            fid = fedid(file=cert)
1538        else:
1539            sys.exit("Cannot read certificate (%s)" % cert)
1540
1541        if opts.file:
1542            exp_desc = ""
1543            try:
1544                f = open(opts.file, 'r')
1545                for line in f:
1546                    exp_desc += line
1547                f.close()
1548            except IOError:
1549                sys.exit("Cannot read description file (%s)" %opts.file)
1550        else:
1551            sys.exit("Must specify an experiment description (--file)")
1552
1553        if not opts.master:
1554            sys.exit("Must specify a master testbed (--master)")
1555
1556        out_certfile = opts.out_certfile
1557
1558        msg = {
1559                'description': { 'ns2description': exp_desc },
1560                'master': opts.master,
1561                'include_fedkit': opts.fedkit,
1562                'include_gatewaykit': opts.gatewaykit,
1563                }
1564
1565        if opts.debug > 1: print >>sys.stderr, msg
1566
1567        try:
1568            resp_dict = self.do_rpc(msg, 
1569                    opts.url, opts.transport, cert, opts.trusted, 
1570                    serialize_only=opts.serialize_only,
1571                    tracefile=opts.tracefile,
1572                    caller=self.caller('Ns2Split'))
1573        except self.RPCException, e:
1574            exit_with_fault(\
1575                    {'desc': e.desc, 'errstr': e.errstr, 'code': e.code})
1576        except RuntimeError, e:
1577            sys.exit("Error processing RPC: %s" % e)
1578
1579        if opts.debug > 1: print >>sys.stderr, resp_dict
1580
1581        ed = resp_dict.get('experimentdescription', None)
1582        if ed:
1583            if ed.has_key('topdldescription'):
1584                topo = topdl.Topology(**ed['topdldescription'])
1585                print topdl.topology_to_xml(topo, 'experiment')
1586
1587class access(fedd_rpc):
1588    def __init__(self):
1589        fedd_rpc.__init__(self)
1590
1591    def print_response_as_testbed(self, resp, label, out=sys.stdout):
1592        """Print the response as input to the splitter script"""
1593
1594        e = resp.get('emulab', None)
1595        if e:
1596            p = e['project']
1597            fields = { 
1598                    "Boss": e['boss'],
1599                    "OpsNode": e['ops'],
1600                    "Domain": e['domain'],
1601                    "FileServer": e['fileServer'],
1602                    "EventServer": e['eventServer'],
1603                    "Project": unpack_id(p['name'])
1604                    }
1605            if (label != None): print >> out, "[%s]" % label
1606
1607            for l, v in fields.iteritems():
1608                print >>out, "%s: %s" % (l, v)
1609
1610            for u in p['user']:
1611                print >>out, "User: %s" % unpack_id(u['userID'])
1612
1613            for a in e['fedAttr']:
1614                print >>out, "%s: %s" % (a['attribute'], a['value'])
1615
1616    def __call__(self):
1617        node_descs = []
1618        proj = None
1619
1620        # Process the options using the customized option parser defined above
1621        parser = fedd_access_opts()
1622
1623        (opts, args) = parser.parse_args()
1624
1625        if opts.testbed == None:
1626            parser.error("--testbed is required")
1627
1628        if opts.trusted:
1629            if ( not os.access(opts.trusted, os.R_OK) ) :
1630                sys.exit("Cannot read trusted certificates (%s)" % opts.trusted)
1631
1632        if opts.debug > 0: opts.tracefile=sys.stderr
1633
1634        (user, cert) = self.get_user_info()
1635
1636        if opts.cert != None: cert = opts.cert
1637
1638        if cert == None:
1639            sys.exit("No certificate given (--cert) or found")
1640
1641        if os.access(cert, os.R_OK):
1642            fid = fedid(file=cert)
1643            if opts.use_fedid == True:
1644                user = fid
1645        else:
1646            sys.exit("Cannot read certificate (%s)" % cert)
1647
1648        msg = {
1649                'allocID': pack_id('test alloc'),
1650                'destinationTestbed': pack_id(opts.testbed),
1651                }
1652
1653        if len(node_descs) > 0:
1654            msg['resources'] = { 
1655                    'node': [ 
1656                        { 
1657                            'image':  n.image ,
1658                            'hardware':  n.hardware,
1659                            'count': n.count,
1660                        } for n in node_descs],
1661                    }
1662
1663        if opts.debug > 1: print >>sys.stderr, msg
1664
1665        try:
1666            resp_dict = self.do_rpc(msg, 
1667                    opts.url, opts.transport, cert, opts.trusted, 
1668                    serialize_only=opts.serialize_only,
1669                    tracefile=opts.tracefile,
1670                    caller=self.caller('RequestAccess'))
1671        except self.RPCException, e:
1672            exit_with_fault(\
1673                    {'desc': e.desc, 'errstr': e.errstr, 'code': e.code})
1674        except RuntimeError, e:
1675            sys.exit("Error processing RPC: %s" % e.message)
1676
1677        if opts.debug > 1: print >>sys.stderr, resp_dict
1678        self.print_response_as_testbed(resp_dict, opts.label)
1679
1680# Keep requesting experiment status and printing updates to the log until the
1681# experiment is done being created.
1682class spew_log(fedd_rpc):
1683    def __init__(self): 
1684        """
1685        Init the superclass
1686        """
1687
1688        fedd_rpc.__init__(self)
1689
1690    def __call__(self):
1691        """
1692        The control flow.  Compose the request and print the response.
1693        """
1694        # Process the options using the customized option parser defined above
1695        parser = fedd_spew_opts()
1696
1697        (opts, args) = parser.parse_args()
1698
1699        if opts.trusted:
1700            if ( not os.access(opts.trusted, os.R_OK) ) :
1701                sys.exit("Cannot read trusted certificates (%s)" % opts.trusted)
1702
1703        if opts.debug > 0: opts.tracefile=sys.stderr
1704
1705        (user, cert) = self.get_user_info()
1706
1707        if opts.cert != None: cert = opts.cert
1708
1709        if cert == None:
1710            sys.exit("No certificate given (--cert) or found")
1711
1712        if os.access(cert, os.R_OK):
1713            fid = fedid(file=cert)
1714        else:
1715            sys.exit("Cannot read certificate (%s)" % cert)
1716
1717        if opts.exp_name and opts.exp_certfile:
1718            sys.exit("Only one of --experiment_cert and " +\
1719                    "--experiment_name permitted");
1720
1721        if opts.exp_certfile:
1722            exp_id = { 'fedid': fedid(file=opts.exp_certfile) }
1723
1724        if opts.exp_name:
1725            exp_id = { 'localname' : opts.exp_name }
1726
1727        if opts.logfile:
1728            try:
1729                out = open(opts.logfile, "w")
1730            except IOError,e:
1731                sys.exit("Cannot open logfile: %s" %e)
1732        else:
1733            out = sys.stdout
1734
1735        req = { 'experiment': exp_id }
1736
1737        status = "starting"
1738        log = ""
1739        log_offset = 0
1740        update = opts.update
1741        while status == 'starting':
1742            try:
1743                resp_dict = self.do_rpc(req,
1744                        opts.url, opts.transport, cert, opts.trusted, 
1745                        serialize_only=opts.serialize_only,
1746                        tracefile=opts.tracefile,
1747                        caller=self.caller('Info'))
1748            except self.RPCException, e:
1749                exit_with_fault(\
1750                        {'desc': e.desc, 'errstr': e.errstr, 'code': e.code})
1751            except RuntimeError, e:
1752                sys.exit("Error processing RPC: %s" % e)
1753
1754            status = resp_dict.get('experimentStatus', None)
1755            log = resp_dict.get('allocationLog', None)
1756            if not status:
1757                sys.exit("No status in Info response??")
1758            if log:
1759                if len(log) > log_offset:
1760                    print >>out, log[log_offset:],
1761                    out.flush()
1762                    log_offset = len(log)
1763            if status == 'starting': 
1764                time.sleep(update)
1765
1766        print >>out
1767        print >>out, status
1768        out.close()
1769
1770class start_segment(fedd_rpc):
1771    def __init__(self): 
1772        fedd_rpc.__init__(self)
1773    def __call__(self):
1774        # Process the options using the customized option parser defined above
1775        parser = fedd_start_opts()
1776
1777        (opts, args) = parser.parse_args()
1778
1779        if opts.trusted:
1780            if ( not os.access(opts.trusted, os.R_OK) ) :
1781                sys.exit("Cannot read trusted certificates (%s)" % opts.trusted)
1782
1783        if opts.debug > 0: opts.tracefile=sys.stderr
1784
1785        (user, cert) = self.get_user_info()
1786
1787        if opts.cert != None: cert = opts.cert
1788
1789        if cert == None:
1790            sys.exit("No certificate given (--cert) or found")
1791
1792        if os.access(cert, os.R_OK):
1793            fid = fedid(file=cert)
1794        else:
1795            sys.exit("Cannot read certificate (%s)" % cert)
1796
1797        if opts.file:
1798            try:
1799                top = topdl.topology_from_xml(filename=opts.file, 
1800                        top='experiment')
1801            except IOError:
1802                sys.exit("Cannot read description file (%s)" %opts.file)
1803        else:
1804            sys.exit("Must specify an experiment description (--file)")
1805
1806        msg = {
1807                'segmentdescription': { 'topdldescription': top.to_dict() },
1808                'allocID': pack_id(fid),
1809                'master': False,
1810                }
1811
1812        if opts.debug > 1: print >>sys.stderr, msg
1813
1814        try:
1815            resp_dict = self.do_rpc(msg, 
1816                    opts.url, opts.transport, cert, opts.trusted, 
1817                    serialize_only=opts.serialize_only,
1818                    tracefile=opts.tracefile,
1819                    caller=self.caller('StartSegment'))
1820        except self.RPCException, e:
1821            exit_with_fault(\
1822                    {'desc': e.desc, 'errstr': e.errstr, 'code': e.code})
1823        except RuntimeError, e:
1824            sys.exit("Error processing RPC: %s" % e)
1825
1826        if opts.debug > 1: print >>sys.stderr, resp_dict
1827        print resp_dict
1828
1829
1830
1831cmds = {\
1832        'new': new(),\
1833        'create': create(),\
1834        'split': split(),\
1835        'access': access(),\
1836        'vtopo': vtopo(),\
1837        'vis': vis(),\
1838        'info': exp_data(),\
1839        'multiinfo': multi_exp_data(),\
1840        'multistatus': multi_status(),\
1841        'image': image(),\
1842        'ns_image': ns_image(),\
1843        'status': status(),\
1844        'terminate': terminate(),\
1845        'spewlog': spew_log(),\
1846        'topdl_image': topdl_image(),\
1847        'start_segment': start_segment(),\
1848        'terminate_segment': terminate_segment(),\
1849    }
1850if len(sys.argv) > 1:
1851    operation = cmds.get(sys.argv[1], None)
1852else:
1853    sys.exit("first argument must be one of " + ",".join(cmds.keys()))
1854
1855if operation:
1856    del sys.argv[1]
1857    operation()
1858else:
1859    if sys.argv[1] == '--help':
1860        sys.exit(\
1861'''Only context sensitive help is available.  For one of the commands:
1862
1863%s
1864
1865type
1866  %s command --help
1867
1868to get help, e.g., %s create --help
1869''' % (", ".join(cmds.keys()), sys.argv[0], sys.argv[0]))
1870    else:
1871        sys.exit("Bad command: %s.  Valid ones are: %s" % \
1872                (sys.argv[1], ", ".join(cmds.keys())))
1873
Note: See TracBrowser for help on using the repository browser.