source: fedd/fedd_client.py @ ab37086

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

Small bugfix

  • 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 = d.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(filename=opts.file, 
1107                        top="experiment")
1108            except IOError:
1109                sys.exit("Cannot read description file (%s)" % opts.file)
1110        else:
1111            sys.exit("Must specify an experiment description (--file)")
1112
1113        if not opts.master:
1114            opts.master="dummy"
1115
1116
1117        if opts.format and opts.outfile:
1118            fmt = opts.format
1119            file = opts.outfile
1120        elif not opts.format and opts.outfile:
1121            fmt = opts.outfile[-3:]
1122            if fmt not in ("png", "jpg", "dot", "svg"):
1123                sys.exit("Unexpected file type and no format specified")
1124            file = opts.outfile
1125        elif opts.format and not opts.outfile:
1126            fmt = opts.format
1127            file = None
1128        else:
1129            fmt="dot"
1130            file = None
1131
1132        self.gen_image(top, len(top.elements), file, fmt, opts.neato, 
1133                opts.labels, opts.pixels)
1134
1135class terminate(fedd_rpc):
1136    def __init__(self): 
1137        """
1138        Termination request
1139        """
1140
1141        fedd_rpc.__init__(self, "Terminate")
1142
1143    def __call__(self):
1144        """
1145        The control flow.  Compose the request and print the response.
1146        """
1147        # Process the options using the customized option parser defined above
1148        parser = fedd_terminate_opts()
1149
1150        (opts, args) = parser.parse_args()
1151
1152        (user, cert) = self.get_user_info([])
1153        if opts.trusted:
1154            if ( not os.access(opts.trusted, os.R_OK) ) :
1155                sys.exit("Cannot read trusted certificates (%s)" % opts.trusted)
1156
1157        if opts.debug > 0: opts.tracefile=sys.stderr
1158
1159        if opts.cert != None: cert = opts.cert
1160
1161        if cert == None:
1162            sys.exit("No certificate given (--cert) or found")
1163
1164        if os.access(cert, os.R_OK):
1165            fid = fedid(file=cert)
1166        else:
1167            sys.exit("Cannot read certificate (%s)" % cert)
1168
1169        if opts.exp_name and opts.exp_certfile:
1170            sys.exit("Only one of --experiment_cert and " +\
1171                    "--experiment_name permitted")
1172
1173        if opts.print_log and opts.logfile:
1174            sys.exit("Only one of --logfile and --print_log is permitted")
1175        elif opts.print_log:
1176            out = sys.stdout
1177        elif opts.logfile:
1178            try:
1179                out = open(opts.logfile, "w")
1180            except IOError,e:
1181                sys.exit("Cannot open logfile: %s" %e)
1182        else:
1183            out = None
1184
1185        exp_id = None
1186
1187        if opts.exp_certfile:
1188            exp_id = { 'fedid': fedid(file=opts.exp_certfile) }
1189
1190        if opts.exp_name:
1191            exp_id = { 'localname' : opts.exp_name }
1192
1193        if not exp_id:
1194            sys.exit("Must give one of --experiment_cert and " +\
1195                    "--experiment_name");
1196
1197        req = { 'experiment': exp_id, 'force': opts.force }
1198
1199        try:
1200            resp_dict = self.do_rpc(req,
1201                    opts.url, opts.transport, cert, opts.trusted, 
1202                    serialize_only=opts.serialize_only,
1203                    tracefile=opts.tracefile)
1204        except self.RPCException, e:
1205            exit_with_fault(\
1206                    {'desc': e.desc, 'errstr': e.errstr, 'code': e.code})
1207        except RuntimeError, e:
1208            print e
1209            sys.exit("Error processing RPC: %s" % e)
1210
1211        if out:
1212            log = resp_dict.get('deallocationLog', None)
1213            if log:
1214                print >>out, log
1215                out.close()
1216            else:
1217                out.close()
1218                sys.exit("No log returned")
1219
1220class create(fedd_rpc):
1221    def __init__(self): 
1222        fedd_rpc.__init__(self, "Create")
1223    def __call__(self):
1224        access_keys = []
1225        # Process the options using the customized option parser defined above
1226        parser = fedd_create_opts(access_keys, self.add_ssh_key,
1227                self.add_x509_cert)
1228
1229        (opts, args) = parser.parse_args()
1230
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 not opts.project :
1236            parser.error('--project is required')
1237
1238        if opts.debug > 0: opts.tracefile=sys.stderr
1239
1240        (user, cert) = self.get_user_info(access_keys)
1241
1242        if opts.user: user = opts.user
1243
1244        if opts.cert != None: cert = opts.cert
1245
1246        if cert == None:
1247            sys.exit("No certificate given (--cert) or found")
1248
1249        if os.access(cert, os.R_OK):
1250            fid = fedid(file=cert)
1251            if opts.use_fedid == True:
1252                user = fid
1253        else:
1254            sys.exit("Cannot read certificate (%s)" % cert)
1255
1256        if opts.file:
1257            exp_desc = ""
1258            try:
1259                f = open(opts.file, 'r')
1260                for line in f:
1261                    exp_desc += line
1262                f.close()
1263            except IOError:
1264                sys.exit("Cannot read description file (%s)" %opts.file)
1265        else:
1266            sys.exit("Must specify an experiment description (--file)")
1267
1268        if not opts.master:
1269            sys.exit("Must specify a master testbed (--master)")
1270
1271        out_certfile = opts.out_certfile
1272
1273        msg = {
1274                'experimentdescription': { 'ns2description': exp_desc },
1275                'master': opts.master,
1276                'exportProject': { 'localname': opts.project },
1277                'user' : [ {\
1278                        'userID': pack_id(user), \
1279                        'access': [ { a.type: a.buf } for a in access_keys]\
1280                        } ]
1281                }
1282
1283        if opts.exp_name:
1284            msg['experimentID'] = { 'localname': opts.exp_name }
1285
1286        if opts.debug > 1: print >>sys.stderr, msg
1287
1288        try:
1289            resp_dict = self.do_rpc(msg, 
1290                    opts.url, opts.transport, cert, opts.trusted, 
1291                    serialize_only=opts.serialize_only,
1292                    tracefile=opts.tracefile)
1293        except self.RPCException, e:
1294            exit_with_fault(\
1295                    {'desc': e.desc, 'errstr': e.errstr, 'code': e.code})
1296        except RuntimeError, e:
1297            sys.exit("Error processing RPC: %s" % e)
1298
1299        if opts.debug > 1: print >>sys.stderr, resp_dict
1300
1301        ea = resp_dict.get('experimentAccess', None)
1302        if out_certfile and ea and ea.has_key('X509'):
1303            try:
1304                f = open(out_certfile, "w")
1305                print >>f, ea['X509']
1306                f.close()
1307            except IOError:
1308                sys.exit('Could not write to %s' %  out_certfile)
1309        eid = resp_dict.get('experimentID', None)
1310        if eid:
1311            for id in eid:
1312                for k in id.keys():
1313                    print "%s: %s" % (k, id[k])
1314        st = resp_dict.get('experimentStatus', None)
1315        if st:
1316            print "status: %s" % st
1317
1318class split(fedd_rpc):
1319    def __init__(self): 
1320        fedd_rpc.__init__(self, "Ns2Split")
1321    def __call__(self):
1322        access_keys = []
1323        # Process the options using the customized option parser defined above
1324        parser = fedd_split_opts(access_keys, self.add_ssh_key,
1325                self.add_x509_cert)
1326
1327        (opts, args) = parser.parse_args()
1328
1329        if opts.trusted:
1330            if ( not os.access(opts.trusted, os.R_OK) ) :
1331                sys.exit("Cannot read trusted certificates (%s)" % opts.trusted)
1332
1333        if opts.debug > 0: opts.tracefile=sys.stderr
1334
1335        (user, cert) = self.get_user_info(access_keys)
1336
1337        if opts.cert != None: cert = opts.cert
1338
1339        if cert == None:
1340            sys.exit("No certificate given (--cert) or found")
1341
1342        if os.access(cert, os.R_OK):
1343            fid = fedid(file=cert)
1344            if opts.use_fedid == True:
1345                user = fid
1346        else:
1347            sys.exit("Cannot read certificate (%s)" % cert)
1348
1349        if opts.file:
1350            exp_desc = ""
1351            try:
1352                f = open(opts.file, 'r')
1353                for line in f:
1354                    exp_desc += line
1355                f.close()
1356            except IOError:
1357                sys.exit("Cannot read description file (%s)" %opts.file)
1358        else:
1359            sys.exit("Must specify an experiment description (--file)")
1360
1361        if not opts.master:
1362            sys.exit("Must specify a master testbed (--master)")
1363
1364        out_certfile = opts.out_certfile
1365
1366        msg = {
1367                'description': { 'ns2description': exp_desc },
1368                'master': opts.master,
1369                'include_fedkit': opts.fedkit,
1370                'include_gatewaykit': opts.gatewaykit,
1371                }
1372
1373        if opts.debug > 1: print >>sys.stderr, msg
1374
1375        try:
1376            resp_dict = self.do_rpc(msg, 
1377                    opts.url, opts.transport, cert, opts.trusted, 
1378                    serialize_only=opts.serialize_only,
1379                    tracefile=opts.tracefile)
1380        except self.RPCException, e:
1381            exit_with_fault(\
1382                    {'desc': e.desc, 'errstr': e.errstr, 'code': e.code})
1383        except RuntimeError, e:
1384            sys.exit("Error processing RPC: %s" % e)
1385
1386        if opts.debug > 1: print >>sys.stderr, resp_dict
1387
1388        out = resp_dict.get('output', None)
1389
1390        for line in out.splitlines():
1391            print "%s" % line
1392
1393class access(fedd_rpc):
1394    def __init__(self):
1395        fedd_rpc.__init__(self, "RequestAccess")
1396
1397    def print_response_as_testbed(self, resp, label, out=sys.stdout):
1398        """Print the response as input to the splitter script"""
1399
1400        e = resp['emulab']
1401        p = e['project']
1402        fields = { 
1403                "Boss": e['boss'],
1404                "OpsNode": e['ops'],
1405                "Domain": e['domain'],
1406                "FileServer": e['fileServer'],
1407                "EventServer": e['eventServer'],
1408                "Project": unpack_id(p['name'])
1409                }
1410        if (label != None): print >> out, "[%s]" % label
1411
1412        for l, v in fields.iteritems():
1413            print >>out, "%s: %s" % (l, v)
1414
1415        for u in p['user']:
1416            print >>out, "User: %s" % unpack_id(u['userID'])
1417
1418        for a in e['fedAttr']:
1419            print >>out, "%s: %s" % (a['attribute'], a['value'])
1420
1421    def __call__(self):
1422        access_keys = []
1423        node_descs = []
1424        proj = None
1425
1426        # Process the options using the customized option parser defined above
1427        parser = fedd_access_opts(access_keys, node_descs, self.add_ssh_key,
1428                self.add_x509_cert, self.add_node_desc)
1429
1430        (opts, args) = parser.parse_args()
1431
1432        if opts.testbed == None:
1433            parser.error("--testbed is required")
1434
1435        if opts.trusted:
1436            if ( not os.access(opts.trusted, os.R_OK) ) :
1437                sys.exit("Cannot read trusted certificates (%s)" % opts.trusted)
1438
1439        if opts.debug > 0: opts.tracefile=sys.stderr
1440
1441        (user, cert) = self.get_user_info(access_keys)
1442
1443        if opts.user: user = opts.user
1444
1445        if opts.cert != None: cert = opts.cert
1446
1447        if cert == None:
1448            sys.exit("No certificate given (--cert) or found")
1449
1450        if os.access(cert, os.R_OK):
1451            fid = fedid(file=cert)
1452            if opts.use_fedid == True:
1453                user = fid
1454        else:
1455            sys.exit("Cannot read certificate (%s)" % cert)
1456
1457        msg = {
1458                'allocID': pack_id('test alloc'),
1459                'destinationTestbed': pack_id(opts.testbed),
1460                'serviceAccess' : [ { a.type: a.buf } for a in access_keys ],
1461                'createAccess' : [ { a.type: a.buf } for a in access_keys ],
1462                }
1463
1464        if len(node_descs) > 0:
1465            msg['resources'] = { 
1466                    'node': [ 
1467                        { 
1468                            'image':  n.image ,
1469                            'hardware':  n.hardware,
1470                            'count': n.count,
1471                        } for n in node_descs],
1472                    }
1473
1474        if opts.project != None:
1475            if not opts.anonymous and user != None:
1476                msg['project'] = {
1477                        'name': pack_id(opts.project),
1478                        'user': [ { 'userID': pack_id(user) } ],
1479                        }
1480            else:
1481                msg['project'] = { 'name': pack_id(opts.project) }
1482        else:
1483            if not opts.anonymous and user != None:
1484                msg['user'] = [ { 'userID': pack_id(user) } ]
1485            else:
1486                msg['user'] = [];
1487
1488        if opts.debug > 1: print >>sys.stderr, msg
1489
1490        try:
1491            resp_dict = self.do_rpc(msg, 
1492                    opts.url, opts.transport, cert, opts.trusted, 
1493                    serialize_only=opts.serialize_only,
1494                    tracefile=opts.tracefile)
1495        except self.RPCException, e:
1496            exit_with_fault(\
1497                    {'desc': e.desc, 'errstr': e.errstr, 'code': e.code})
1498        except RuntimeError, e:
1499            sys.exit("Error processing RPC: %s" % e.message)
1500
1501        if opts.debug > 1: print >>sys.stderr, resp_dict
1502        self.print_response_as_testbed(resp_dict, opts.label)
1503
1504# Keep requesting experiment status and printing updates to the log until the
1505# experiment is done being created.
1506class spew_log(fedd_rpc):
1507    def __init__(self): 
1508        """
1509        Init the superclass
1510        """
1511
1512        fedd_rpc.__init__(self, 'Info')
1513
1514    def __call__(self):
1515        """
1516        The control flow.  Compose the request and print the response.
1517        """
1518        # Process the options using the customized option parser defined above
1519        parser = fedd_spew_opts()
1520
1521        (opts, args) = parser.parse_args()
1522
1523        if opts.trusted:
1524            if ( not os.access(opts.trusted, os.R_OK) ) :
1525                sys.exit("Cannot read trusted certificates (%s)" % opts.trusted)
1526
1527        if opts.debug > 0: opts.tracefile=sys.stderr
1528
1529        (user, cert) = self.get_user_info([])
1530
1531        if opts.cert != None: cert = opts.cert
1532
1533        if cert == None:
1534            sys.exit("No certificate given (--cert) or found")
1535
1536        if os.access(cert, os.R_OK):
1537            fid = fedid(file=cert)
1538        else:
1539            sys.exit("Cannot read certificate (%s)" % cert)
1540
1541        if opts.exp_name and opts.exp_certfile:
1542            sys.exit("Only one of --experiment_cert and " +\
1543                    "--experiment_name permitted");
1544
1545        if opts.exp_certfile:
1546            exp_id = { 'fedid': fedid(file=opts.exp_certfile) }
1547
1548        if opts.exp_name:
1549            exp_id = { 'localname' : opts.exp_name }
1550
1551        if opts.logfile:
1552            try:
1553                out = open(opts.logfile, "w")
1554            except IOError,e:
1555                sys.exit("Cannot open logfile: %s" %e)
1556        else:
1557            out = sys.stdout
1558
1559        req = { 'experiment': exp_id }
1560
1561        status = "starting"
1562        log = ""
1563        log_offset = 0
1564        update = opts.update
1565        while status == 'starting':
1566            try:
1567                resp_dict = self.do_rpc(req,
1568                        opts.url, opts.transport, cert, opts.trusted, 
1569                        serialize_only=opts.serialize_only,
1570                        tracefile=opts.tracefile)
1571            except self.RPCException, e:
1572                exit_with_fault(\
1573                        {'desc': e.desc, 'errstr': e.errstr, 'code': e.code})
1574            except RuntimeError, e:
1575                sys.exit("Error processing RPC: %s" % e)
1576
1577            status = resp_dict.get('experimentStatus', None)
1578            log = resp_dict.get('allocationLog', None)
1579            if not status:
1580                sys.exit("No status in Info response??")
1581            if log:
1582                if len(log) > log_offset:
1583                    print >>out, log[log_offset:],
1584                    out.flush()
1585                    log_offset = len(log)
1586            if status == 'starting': 
1587                time.sleep(update)
1588
1589        print >>out
1590        print >>out, status
1591        out.close()
1592
1593
1594cmds = {\
1595        'create': create(),\
1596        'split': split(),\
1597        'access': access(),\
1598        'vtopo': vtopo(),\
1599        'vis': vis(),\
1600        'info': exp_data(),\
1601        'multiinfo': multi_exp_data(),\
1602        'multistatus': multi_status(),\
1603        'image': image(),\
1604        'ns_image': ns_image(),\
1605        'status': status(),\
1606        'terminate': terminate(),\
1607        'spewlog': spew_log(),\
1608        'topdl_image': topdl_image(),\
1609    }
1610
1611operation = cmds.get(sys.argv[1], None)
1612if operation:
1613    del sys.argv[1]
1614    operation()
1615else:
1616    if sys.argv[1] == '--help':
1617        sys.exit(\
1618'''Only context sensitive help is available.  For one of the commands:
1619
1620%s
1621
1622type
1623  %s command --help
1624
1625to get help, e.g., %s create --help
1626''' % (", ".join(cmds.keys()), sys.argv[0], sys.argv[0]))
1627    else:
1628        sys.exit("Bad command: %s.  Valid ones are: %s" % \
1629                (sys.argv[1], ", ".join(cmds.keys())))
1630
Note: See TracBrowser for help on using the repository browser.