#!/usr/bin/env python # coding: utf-8 # Copyright (C) 1994-2018 Altair Engineering, Inc. # For more information, contact Altair at www.altair.com. # # This file is part of the PBS Professional ("PBS Pro") software. # # Open Source License Information: # # PBS Pro is free software. You can redistribute it and/or modify it under the # terms of the GNU Affero General Public License as published by the Free # Software Foundation, either version 3 of the License, or (at your option) any # later version. # # PBS Pro is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. # See the GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . # # Commercial License Information: # # For a copy of the commercial license terms and conditions, # go to: (http://www.pbspro.com/UserArea/agreement.html) # or contact the Altair Legal Department. # # Altair’s dual-license business model allows companies, individuals, and # organizations to create proprietary derivative works of PBS Pro and # distribute them - whether embedded or bundled with other software - # under a commercial license agreement. # # Use of Altair’s trademarks, including but not limited to "PBS™", # "PBS Professional®", and "PBS Pro™" and Altair’s logos is subject to Altair's # trademark licensing policies. import os import sys import socket import getopt import tempfile import logging import logging.config import errno import ptl import ptl.lib from ptl.utils.pbs_cliutils import CliUtils from ptl.utils.pbs_dshutils import DshUtils from ptl.lib.pbs_testlib import PtlConfig # trap SIGINT and SIGPIPE def trap_exceptions(etype, value, tb): sys.excepthook = sys.__excepthook__ if issubclass(etype, KeyboardInterrupt): pass elif issubclass(etype, IOError) and value.errno == errno.EPIPE: pass else: sys.__excepthook__(etype, value, tb) sys.excepthook = trap_exceptions # A basic SWIG interface definition to wrap PBS IFL swiginter = '''\ %module pbs_ifl %typemap(out) char ** { int len,i; len = 0; while ($1[len]) len++; $result = PyList_New(len); for (i = 0; i < len; i++) { PyList_SetItem($result,i,PyString_FromString($1[i])); } } %typemap(in) char ** { /* Check if is a list */ if (PyList_Check($input)) { int size = PyList_Size($input); int i = 0; $1 = (char **) malloc((size+1)*sizeof(char *)); for (i = 0; i < size; i++) { PyObject *o = PyList_GetItem($input,i); if (PyString_Check(o)) $1[i] = PyString_AsString(PyList_GetItem($input,i)); else { PyErr_SetString(PyExc_TypeError,"list must contain strings"); free($1); return NULL; } } $1[i] = 0; } else { PyErr_SetString(PyExc_TypeError,"not a list"); return NULL; } } %typemap(out) struct batch_status * { struct batch_status *head_bs, *bs; struct attrl *attribs; char *resource; char *str; int i, j; int len; char buf[4096]; static char *id = "id"; head_bs = $1; bs = $1; for (len=0; bs != NULL; len++) bs = bs->next; $result = PyList_New(len); bs = head_bs; for (i=0; i < len; i++) { PyObject *dict; PyObject *a, *v, *tmpv; dict = PyDict_New(); PyList_SetItem($result, i, dict); a = PyString_FromString(id); v = PyString_FromString(bs->name); PyDict_SetItem(dict, a, v); attribs = bs->attribs; while (attribs) { resource = attribs->resource; if (resource != NULL) { /* +2 to account for the '.' between name and resource */ str = malloc(strlen(attribs->name) + strlen(resource) + 2); sprintf(str, "%s.%s", attribs->name, attribs->resource); a = PyString_FromString(str); } else { a = PyString_FromString(attribs->name); } tmpv = PyDict_GetItem(dict, a); /* if the key already exists, append as comma-separated */ if (tmpv != NULL) { char *s = PyString_AsString(tmpv); /* +4 for the quotes, the comma, and a NULL byte */ str = malloc(strlen(attribs->value) + strlen(s) + 4); sprintf(str, "%s,%s", attribs->value, s); v = PyString_FromString(str); } else { v = PyString_FromString(attribs->value); } PyDict_SetItem(dict, a, v); attribs = attribs->next; } bs = bs->next; } } %{ #include "pbs_ifl.h" int pbs_py_spawn(int, char *, char **, char **); %} %include "pbs_ifl.h" int pbs_py_spawn(int, char *, char **, char **); ''' def _remove_file(workdir, filename): f = os.path.join(workdir, filename) if os.path.isfile(f): logging.debug('removing intermediary file ' + filename) os.remove(f) def usage(): msg = [] msg += ['Usage: ' + os.path.basename(sys.argv[0]) + ' [OPTION]\n\n'] msg += [' Produce Python wrappers for PBS IFL API\n\n'] msg += ['-c : path to pbs.conf\n'] msg += [ '-f: force overwrite of _pbs_ifl.so and pbs_ifl.py when present\n'] msg += ['-h: display usage information\n'] msg += ['-i : path to swig interface file\n'] msg += ['-I : path to python include directory\n'] msg += ['-l : logging level\n'] msg += ['-s : path to swig binary to use\n'] msg += ['-t : hostname to operate on\n'] msg += ['-w : path to working directory\n'] msg += ['--log-conf=: logging config file\n'] msg += ['--version: print version number and exit\n'] print "".join(msg) if __name__ == '__main__': workdir = tempfile.gettempdir() targethost = socket.gethostname() config = None interface = None pythoninc = None level = 'INFO' force = False swigbin = 'swig' logconf = None if 'PBS_CONF_FILE' in os.environ: config = os.environ['PBS_CONF_FILE'] else: config = '/etc/pbs.conf' opts, args = getopt.getopt(sys.argv[1:], "t:i:I:c:w:l:s:hf", ["log-conf=", "version"]) for o, val in opts: if o == '-t': targethost = val elif o == '-w': workdir = CliUtils.expand_abs_path(val) elif o == '-i': interface = val elif o == '-l': level = val elif o == '-c': config = val elif o == '-I': pythoninc = CliUtils.expand_abs_path(val) elif o == '-f': force = True elif o == '-s': swigbin = CliUtils.expand_abs_path(val) elif o == '--log-conf': logconf = val elif o == '--version': print ptl.__version__ sys.exit(0) elif o == '-h': usage() sys.exit(0) else: sys.stderr.write("Unrecognized option\n") usage() sys.exit(1) cu = CliUtils() if logconf: logging.config.fileConfig(logconf) else: l = cu.get_logging_level(level) logging.basicConfig(level=l) b = cu.check_bin(swigbin) if not b: logging.error("swig is missing, exiting") sys.exit(1) b = cu.check_bin("gcc") if not b: logging.error("gcc is missing, exiting") sys.exit(1) if pythoninc is None: logging.error("Path to Python include directory is mandatory") usage() sys.exit(1) if targethost != socket.gethostname(): logging.error("This command only works on localhost") sys.exit(1) PtlConfig() du = DshUtils() pbs_conf = du.parse_pbs_config(targethost, file=config) os.chdir(workdir) if interface is None: interface = os.path.join(workdir, "pbs_ifl.i") f = open(interface, 'w') f.write(swiginter) f.close() srcdir = os.getcwd() else: srcdir = os.path.dirname(interface) if 'PBS_EXEC' in pbs_conf: pbsinclude = os.path.join(pbs_conf['PBS_EXEC'], 'include') cmd = [swigbin, '-python', '-I' + pbsinclude, interface] logging.debug(du.run_cmd(targethost, cmd)) if srcdir != os.getcwd(): logging.debug(du.run_copy(targethost, os.path.join(srcdir, "pbs_ifl_wrap.c"), workdir)) logging.debug(du.run_copy(targethost, os.path.join(srcdir, "pbs_ifl.py"), workdir)) cmd = ['gcc', '-Wall', '-Wno-unused-variable', '-fPIC', '-shared', '-I' + pbsinclude] cmd += ['-I' + pythoninc] cmd += ['pbs_ifl_wrap.c'] cmd += ['-L' + os.path.join(pbs_conf['PBS_EXEC'], 'lib')] cmd += ['-lpbs'] cmd += ['-o', '_pbs_ifl.so'] cmd += ['-lcrypto', '-lssl'] logging.debug(du.run_cmd(targethost, cmd)) libdir = os.path.dirname(ptl.lib.__file__) if force or not os.path.isfile(libdir + '/_pbs_ifo.so'): du.run_copy(targethost, os.path.join(workdir, '_pbs_ifl.so'), os.path.join(libdir, '_pbs_ifl.so'), sudo=True) if force or not os.path.isfile(os.path.join(libdir, '/pbs_ifl.py')): du.run_copy(targethost, os.path.join(workdir, 'pbs_ifl.py'), os.path.join(libdir, 'pbs_ifl.py'), sudo=True) _remove_file(workdir, "pbs_ifl.py") _remove_file(workdir, "_pbs_ifl.so") _remove_file(workdir, "pbs_ifl_wrap.c") _remove_file(workdir, "pbs_ifl.i")