#!/usr/local/bin/python import os,sys import subprocess import tempfile import logging import topdl import os.path from util import * from fedid import fedid from remote_service import xmlrpc_handler, soap_handler from service_error import * from authorizer import authorizer, abac_authorizer class nullHandler(logging.Handler): def emit(self, record): pass fl = logging.getLogger("fedd.splitter") fl.addHandler(nullHandler()) class ns2topdl_local: def __init__(self, config=None, auth=None): """ Intialize the various attributes, most from the config object """ self.debug = config.getboolean("ns2topdl", "debug") self.muxmax = config.getint("ns2topdl", "muxmax", 3) self.tclsh = config.get("ns2topdl", "tclsh", "/usr/local/bin/otclsh") self.tcl_splitter = config.get("ns2topdl", "tcl_splitter", "/usr/testbed/lib/ns2ir/parse.tcl") self.auth_type = config.get('ns2topdl', 'auth_type') or 'legacy' access_db = config.get("ns2topdl", "accessdb", None) self.allow_any = config.getboolean("ns2topdl", "allow_any", False) auth_dir = config.get('ns2topdl', 'auth_dir') self.log = logging.getLogger("fedd.ns2topdl") set_log_level(config, "ns2topdl", self.log) self.trace_file = sys.stderr set_log_level(config, "ns2topdl", self.log) if auth: self.auth= auth else: self.auth = authorizer() self.log.warning("[ns2topdl] No authorizer passed in, " +\ "using local one") if self.auth_type == 'legacy': if access_db and self.allow_any: raise service_error(service_error.internal, "Cannot specify both an access database and " + "allow_any for ns2topdl") if access_db: try: read_simple_accessdb(access_db, self.auth, 'ns2topdl') except EnvironmentError, e: raise service_error(service_error.internal, "Error reading accessDB %s: %s" % (access_db, e)) except ValueError: raise service_error(service_error.internal, "%s" % e) elif self.allow_any: auth.set_global_attribute("ns2topdl") elif self.auth_type == 'abac': self.auth = abac_authorizer(load=auth_dir) else: raise service_error(service_error.internal, "Unknown auth_type: %s" % self.auth_type) # Dispatch tables self.soap_services = {\ 'Ns2Topdl': soap_handler("Ns2Topdl", self.run_ns2topdl), } self.xmlrpc_services = {\ 'Ns2Topdl': xmlrpc_handler('Ns2Topdl', self.run_ns2topdl), } def run_ns2topdl(self, req, fid): """ The external interface to tcl to topdl translation. Creates a working directory, translates the incoming description using the tcl script. """ if self.allow_any: self.auth.set_attribute(fid, 'ns2topdl') access_ok, proof = self.auth.check_attribute(fid, 'ns2topdl', with_proof=True) if not access_ok: raise service_error(service_error.access, "Access Denied", proof=proof) try: tmpdir = tempfile.mkdtemp(prefix="ns2topdl-") except EnvironmentError: raise service_error(service_error.internal, "Cannot create tmp dir") tclfile = os.path.join(tmpdir, "experiment.tcl") # save error output in case the parse fails. errfile = os.path.join(tmpdir, "errfile") pid = "dummy" gid = "dummy" eid = "dummy" master = "dummy" req = req.get('Ns2TopdlRequestBody', None) if not req: raise service_error(service_error.req, "Bad request format (no Ns2TopdlRequestBody)") # The tcl parser needs to read a file so put the content into that file descr=req.get('description', None) if descr: file_content=descr.get('ns2description', None) if file_content: try: f = open(tclfile, 'w') f.write(file_content) f.close() ef = open(errfile, 'w') except EnvironmentError: raise service_error(service_error.internal, "Cannot write temp experiment description") else: raise service_error(service_error.req, "Only ns2descriptions supported") else: raise service_error(service_error.req, "No description") tclcmd = [self.tclsh, self.tcl_splitter, '-t', '-x', str(self.muxmax), '-m', master] tclcmd.extend([pid, gid, eid, tclfile]) self.log.debug("Calling splitter %s" % " ".join(tclcmd)) tclparser = subprocess.Popen(tclcmd, stdout=subprocess.PIPE, stderr=ef) try: top = topdl.topology_from_xml(file=tclparser.stdout, top="experiment") except: top = None if top is None: # There was an ns parsing error, gather up the error from the # errfile and raise a service_error containing the error text try: ef = open(errfile, 'r') parse_err = ef.read() ef.close() except EnvironmentError: raise service_error(service_error.internal, "Cannot read error string") raise service_error(service_error.req, "Cannot parse ns file: %s" % parse_err) # Walk up tmpdir, deleting as we go for path, dirs, files in os.walk(tmpdir, topdown=False): for f in files: os.remove(os.path.join(path, f)) for d in dirs: os.rmdir(os.path.join(path, d)) os.rmdir(tmpdir) resp = { 'experimentdescription': { 'topdldescription': top.to_dict(), }, 'proof': proof.to_dict(), } return resp