Pbs_ifl access from python

I’m trying to use pbs_ifl routines from python, but keep running into deadends.

I started with a git clone of 18, configured it (with a private --prefix), built it (with some hacking involved due to missing RPMs), and installed the pieces that built.

Now running pbs_python via:

env PYTHONPATH=$HOME/PBS_18/lib/python/altair \
LD_LIBRARY_PATH=$HOME/PBS_18/lib \
$HOME/PBS_18/bin/pbs_python --hook -i hook.input

I get:
pbs_python: No such file or directory (2) in pbs_python_ext_alloc_python_script, failed to stat <>
Python 2.7.13 (default, Jan 11 2017, 10:56:06) [GCC] on linux2
>>> import pbs
>>> conn = pbs.pbs_connect(‘testpbs’)
>>> print conn
1
>>> svr = pbs.pbs_statserver(conn, None, None)
>>> print svr
<Swig Object of type ‘batch_status *’ at 0x7fffec1b8960>
>>>

How do I convert the batch_status * to something useful to python?

Also, several of the files in $HOME/PBS_18/lib/python/altair/pbs/v1, contain:

from _pbs_v1 import *

Where does _pbs_v1 come from?

The top level goal is to write a daemon that monitors certain queues and performs some reservation manipulations that cannot be done via the command line. We already do some of this using pbs_tclsh, but want to use a language more people would understand.

@dtalcott Try this:

  1. Ensure swig, python-devel and gcc is installed
  2. create pbs_ifl.i file with below content in it (let’s say file is /tmp/pbsapi/pbs_ifl.i)
%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 ** {
  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) {
                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 (tmpv != NULL) {
                char *s = PyString_AsString(tmpv);
                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"
%}
%include "pbs_ifl.h"
  1. cd /tmp/pbsapi
  2. source /etc/pbs.conf (Change /etc/pbs.conf according to location of pbs.conf in your system)
  3. swig -python -I${PBS_EXEC}/include ./pbs_ifl.i (This command should generate pbs_ifl.py and pbs_ifl_wrap.c in current directory)
  4. gcc -Wall -Wno-unused-variable -fPIC -shared -I${PBS_EXEC}/include -I/usr/include/python2.7 -L${PBS_EXEC}/lib -lpbs -o _pbs_ifl.so ./pbs_ifl_wrap.c (This should generate _pbs_ifl.so in current directory)
  5. export LD_LIBRARY_PATH=${PBS_EXEC}/lib:${LD_LIBRARY_PATH}
  6. export PYTHONPATH=/tmp/pbsapi:${PYTHONPATH} (This is required only when PWD is not /tmp/pbsapi)
  7. (Optional) Run ldd /tmp/pbsapi/_pbs_ifl.so and check output and ensure that no missing lib is reported
    Now you can use PBS IFL API from python
    for example:
python -c "from pbs_ifl import *;import json;c=pbs_connect(None);print json.dumps(pbs_statserver(c, None, None), indent=2)"
[
  {
    "eligible_time_enable": "False", 
    "default_chunk.ncpus": "1", 
    "license_count": "Avail_Global:10000000 Avail_Local:10000000 Used:0 High_Use:0", 
    "pbs_license_min": "0", 
    "scheduling": "True", 
    "id": "testdev", 
    "total_jobs": "0", 
    "server_host": "testdev.pbspro.com", 
    "FLicenses": "20000000", 
    "node_fail_requeue": "310", 
    "resv_enable": "True", 
    "power_provisioning": "False", 
    "query_other_jobs": "True", 
    "state_count": "Transit:0 Queued:0 Held:0 Waiting:0 Running:0 Exiting:0 Begun:0 ", 
    "default_queue": "workq", 
    "server_state": "Active", 
    "max_concurrent_provision": "5", 
    "scheduler_iteration": "600", 
    "pbs_license_linger_time": "31536000", 
    "mail_from": "adm", 
    "log_events": "511", 
    "pbs_version": "18.1.0", 
    "resources_default.ncpus": "1", 
    "pbs_license_max": "2147483647", 
    "max_array_size": "10000"
  }
]

@ hirenvadalia

That works great!

Thank you.

@hirenvadalia Hey, this method is feasible. i have a question, i find a API named pbs_manager, I want use python call it, the fifth param is a structure, How should I pass in this parameter? In torque python package, it has new_attropl, but in pbspro , It was deleted, please help me , thanks.

@zhimingzhang123 In pbspro it is attropl(), for more information you can look into structure declaration in pbs_ifl.h.

And this is a minimal example on how to use attropl() in python:

[root@testdev pbsapi]# pbsnodes -av
testdev
     Mom = testdev.pbspro.com
     Port = 15002
     pbs_version = 19.0.0
     ntype = PBS
     state = free
     pcpus = 8
     resources_available.arch = linux
     resources_available.host = testdev
     resources_available.mem = 32832820kb
     resources_available.ncpus = 8
     resources_available.vnode = testdev
     resources_assigned.accelerator_memory = 0kb
     resources_assigned.hbmem = 0kb
     resources_assigned.mem = 0kb
     resources_assigned.naccelerators = 0
     resources_assigned.ncpus = 0
     resources_assigned.vmem = 0kb
     resv_enable = True
     sharing = default_shared
     last_state_change_time = Mon May  6 05:25:37 2019

[root@testdev pbsapi]# python
Python 2.7.5 (default, Apr  9 2019, 14:30:50) 
[GCC 4.8.5 20150623 (Red Hat 4.8.5-36)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from pbs_ifl import *
>>> a = attropl()
>>> a.name = "resources_available"
>>> a.resource = "ncpus"
>>> a.value = "10"
>>> a.op = EQ
>>> a.next = None
>>> c = pbs_connect(None)
>>> pbs_manager(c, MGR_CMD_SET, MGR_OBJ_NODE, "testdev", a, None)
0
>>> exit()
[root@testdev pbsapi]# pbsnodes -av
testdev
     Mom = testdev.pbspro.com
     Port = 15002
     pbs_version = 19.0.0
     ntype = PBS
     state = free
     pcpus = 8
     resources_available.arch = linux
     resources_available.host = testdev
     resources_available.mem = 32832820kb
     resources_available.ncpus = 10
     resources_available.vnode = testdev
     resources_assigned.accelerator_memory = 0kb
     resources_assigned.hbmem = 0kb
     resources_assigned.mem = 0kb
     resources_assigned.naccelerators = 0
     resources_assigned.ncpus = 0
     resources_assigned.vmem = 0kb
     resv_enable = True
     sharing = default_shared
     last_state_change_time = Mon May  6 05:25:37 2019

[root@testdev pbsapi]# 
1 Like

@hirenvadalia Thank you for your help. you’ve really been a big help.

1 Like