source: fedd/fedd_client.py @ df783c1

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

create images from topdl descriptions, a good sign they're coming out right.

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