概述

LSF API Python 包装器允许用户从 Python 调用 LSF API。该包装器使用 SWIG(Simplified Wrapper and Interface Generator)工具将 LSF C API 与 Python 进行接口对接。

开源项目

您可以在 GitHub 上贡献自己的 Python 包装器:

https://github.com/PlatformLSF/platform-python-lsf-api

基本用法

字符串数组映射

在 Python 包装器中,需要使用特定的方法创建和设置字符串数组:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from pythonlsf import lsf

strArr = lsf.new_stringArray(1);              # Create a new stringArray, length 1
lsf.stringArray_setitem(strArr, 0, "normal"); # Set its value
intp_num_queues = lsf.new_intp();             # Create an int ptr
lsf.intp_assign(intp_num_queues, 1);          # Set the int value, which is the queue number

if lsf.lsb_init("test") > 0:                  # LSB initialization
    exit(-1);

queueInfo = lsf.lsb_queueinfo(strArr,intp_num_queues,None,None,0); # Query queue info
if queueInfo == None:
    exit(0);

print 'queue name = %s' % queueInfo.queue;
print 'queue description = %s' % queueInfo.description;
1
2
3
$ python test1.py
queue name = normal
queue description = For normal low priority jobs, running only if hosts are lightly loaded.

扩展 Python 包装器

查询多个实体

要返回多个结果(如多个队列信息),需要扩展 Python 接口。

步骤一:添加 SWIG 接口代码

<python-wrapper-install-dir>/pythonlsf/lsf.i 中添加:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
PyObject * get_queue_info_by_name(char** name, int num) {
    struct queueInfoEnt* queueinfo;
    int numqueues = num;
    int options = 0;

    queueinfo = lsb_queueinfo(name,               // Return queries as C queueInfoEnt*
                  &numqueues, NULL, 0, options);  

    PyObject *result = PyList_New(numqueues);     // Create PyObject * to get C returns
    int i;
    for (i = 0; i < numqueues; i++) {             // Save queries in a loop to result
        PyObject *o = SWIG_NewPointerObj(SWIG_as_voidptr(&queueinfo[i]),
        SWIGTYPE_p_queueInfoEnt, 0 | 0 );
        PyList_SetItem(result,i,o);
    }

    return result;
}

步骤二:重新构建和安装

1
2
$ python setup.py build
$ sudo python setup.py install

步骤三:测试新 API

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from pythonlsf import lsf

strArr = lsf.new_stringArray(2)                             # Create a new stringArray, length 2
lsf.stringArray_setitem(strArr, 0, "normal")                # Set the 1st queue name
lsf.stringArray_setitem(strArr, 1, "public")                # Set the 2nd queue name

if lsf.lsb_init("test") > 0:                                # LSB initialization
  exit(-1);
                                       
for queueInfoEnt in lsf.get_queue_info_by_name(strArr, 2):  # Query the queue info in batch
  if queueInfo == None:
    exit(0);
  print 'queue name = %s' % queueInfoEnt.queue;
  print 'queue description = %s\n' % queueInfoEnt.description;
1
2
3
4
5
6
$ python test2.py
queue name = normal
queue description = For normal low priority jobs, running only if hosts are lightly loaded.

queue name = public
queue description = public queue

不存在的队列名

当查询包含不存在的队列名时,API 返回 [None]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ cat test4.py
from pythonlsf import lsf

strArr = lsf.new_stringArray(2)
lsf.stringArray_setitem(strArr, 0, "normal")
lsf.stringArray_setitem(strArr, 1, "doesnotexist")

if lsf.lsb_init("test") > 0:
  exit(-1);

print lsf.get_queue_info_by_name(strArr, 2)

$ python test4.py
[None]

这与 LSF bqueues 命令行为一致:

1
2
$ bqueues normal doesnotexist
doesnotexist: No such queue

查询所有实体

添加 SWIG 接口代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
PyObject * get_queue_info_all() {
    struct queueInfoEnt *queueinfo;
    char *resreq;
    int numqueues = 0;
    int options = 0;

    resreq="";

    queueinfo = lsb_queueinfo(resreq,             // Return queries as C queueInfoEnt*
                  &numqueues, NULL, 0, options);

    PyObject *result = PyList_New(numqueues);     // Create PyObject * to get C returns
    int i;
    for (i = 0; i < numqueues; i++) {             // Save queries in a loop to result
        PyObject *o = SWIG_NewPointerObj(SWIG_as_voidptr(&queueinfo[i]),
                                         SWIGTYPE_p_queueInfoEnt, 0 | 0 );
        PyList_SetItem(result,i,o);
    }

    return result;
}

测试查询所有队列

1
2
3
4
5
6
7
8
9
10
11
from pythonlsf import lsf

if lsf.lsb_init("test") > 0:
    exit(-1)

# 查询所有队列信息
for queueInfoEnt in lsf.get_queue_info_all():
    if queueInfoEnt == None:
        exit(0)
    print('queue name = %s' % queueInfoEnt.queue)
    print('queue description = %s\n' % queueInfoEnt.description)
1
2
3
4
5
6
7
8
9
10
11
$ python test3.py
queue name = owners
queue description = For owners of some machines. Only users listed in the HOSTSsection can submit jobs to this queue.

...        ...       ...

queue name = interactive
queue description = For interactive jobs only

queue name = idle
queue description = Running only if the machine is idle and very lightly loaded.

常用 API 函数

Python 函数 说明
lsf.lsb_init("name") 初始化 LSB 库
lsf.new_stringArray(n) 创建长度为 n 的字符串数组
lsf.stringArray_setitem(arr, i, val) 设置数组元素值
lsf.new_intp() 创建整数指针
lsf.intp_assign(ptr, val) 设置整数指针值
lsf.lsb_queueinfo(...) 查询队列信息

参考资料

  1. IBM Documentation - Using the LSF API Python wrapper
  2. GitHub - Platform Python LSF API
  3. IBM Documentation - Best practices and tips for LSF