source: fedd/fedd_client.py @ 139e2e2

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

Add a call to a ns2 -> topdl converter

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