Newer
Older
/*****************************************************************************\
* job_submit_lua.c - Set defaults in job submit request specifications.
*****************************************************************************
* Copyright (C) 2010 Lawrence Livermore National Security.
* Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
* Written by Danny Auble <da@llnl.gov>
* CODE-OCEC-09-009. All rights reserved.
*
* This file is part of SLURM, a resource management program.
* For details, see <http://www.schedmd.com/slurmdocs/>.
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
* Please also read the included file: DISCLAIMER.
*
* SLURM is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* In addition, as a special exception, the copyright holders give permission
* to link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two. You must obey the GNU
* General Public License in all respects for all of the code used other than
* OpenSSL. If you modify file(s) with this exception, you may extend this
* exception to your version of the file(s), but you are not obligated to do
* so. If you do not wish to do so, delete this exception statement from your
* version. If you delete this exception statement from all source files in
* the program, then also delete it here.
*
* SLURM 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 General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along
* with SLURM; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
\*****************************************************************************/
#if HAVE_CONFIG_H
# include "config.h"
#endif
#if HAVE_STDINT_H
# include <stdint.h>
#endif
#if HAVE_INTTYPES_H
# include <inttypes.h>
#endif
#include <stdio.h>
#include <sys/types.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <dlfcn.h>
#include <pthread.h>
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
#include "slurm/slurm.h"
#include "slurm/slurm_errno.h"
#include "src/common/slurm_xlator.h"
#include "src/slurmctld/slurmctld.h"
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#define MIN_ACCTG_FREQUENCY 30
/*
* These variables are required by the generic plugin interface. If they
* are not found in the plugin, the plugin loader will ignore it.
*
* plugin_name - a string giving a human-readable description of the
* plugin. There is no maximum length, but the symbol must refer to
* a valid string.
*
* plugin_type - a string suggesting the type of the plugin or its
* applicability to a particular form of data or method of data handling.
* If the low-level plugin API is used, the contents of this string are
* unimportant and may be anything. SLURM uses the higher-level plugin
* interface which requires this string to be of the form
*
* <application>/<method>
*
* where <application> is a description of the intended application of
* the plugin (e.g., "auth" for SLURM authentication) and <method> is a
* description of how this plugin satisfies that application. SLURM will
* only load authentication plugins if the plugin_type string has a prefix
* of "auth/".
*
* plugin_version - specifies the version number of the plugin.
* min_plug_version - specifies the minumum version number of incoming
* messages that this plugin can accept
*/
const char plugin_name[] = "Job submit lua plugin";
const char plugin_type[] = "job_submit/lua";
const uint32_t plugin_version = 100;
const uint32_t min_plug_version = 100;
static const char lua_script_path[] = DEFAULT_SCRIPT_DIR "/job_submit.lua";
static lua_State *L = NULL;
/*
* Mutex for protecting multi-threaded access to this plugin.
* (Only 1 thread at a time should be in here)
*/
#ifdef WITH_PTHREADS
static pthread_mutex_t lua_lock = PTHREAD_MUTEX_INITIALIZER;
#endif
/*****************************************************************************\
* We've provided a simple example of the type of things you can do with this
* plugin. If you develop another plugin that may be of interest to others
* please post it to slurm-dev@lists.llnl.gov Thanks!
\*****************************************************************************/
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
/* Generic stack dump function for debugging purposes */
static void _stack_dump (char *header, lua_State *L)
{
#if _DEBUG
int i;
int top = lua_gettop(L);
info("%s: dumping job_submit/lua stack, %d elements", header, top);
for (i = 1; i <= top; i++) { /* repeat for each level */
int type = lua_type(L, i);
switch (type) {
case LUA_TSTRING:
info("string[%d]:%s", i, lua_tostring(L, i));
break;
case LUA_TBOOLEAN:
info("boolean[%d]:%s", i,
lua_toboolean(L, i) ? "true" : "false");
break;
case LUA_TNUMBER:
info("number[%d]:%d", i,
(int) lua_tonumber(L, i));
break;
default:
info("other[%d]:%s", i, lua_typename(L, type));
break;
}
}
#endif
}
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
/*
* Lua interface to SLURM log facility:
*/
static int _log_lua_msg (lua_State *L)
{
const char *prefix = "job_submit.lua";
int level = 0;
const char *msg;
/*
* Optional numeric prefix indicating the log level
* of the message.
*/
/*
* Pop message off the lua stack
*/
msg = lua_tostring(L, -1);
lua_pop (L, 1);
/*
* Pop level off stack:
*/
level = (int)lua_tonumber (L, -1);
lua_pop (L, 1);
/*
* Call appropriate slurm log function based on log-level argument
*/
if (level > 4)
debug4 ("%s: %s", prefix, msg);
else if (level == 4)
debug3 ("%s: %s", prefix, msg);
else if (level == 3)
debug2 ("%s: %s", prefix, msg);
else if (level == 2)
debug ("%s: %s", prefix, msg);
else if (level == 1)
verbose ("%s: %s", prefix, msg);
else if (level == 0)
info ("%s: %s", prefix, msg);
return (0);
}
static int _log_lua_error (lua_State *L)
{
const char *prefix = "job_submit.lua";
const char *msg = lua_tostring (L, -1);
error ("%s: %s", prefix, msg);
return (0);
}
static const struct luaL_Reg slurm_functions [] = {
{ "log", _log_lua_msg },
{ "error", _log_lua_error },
{ NULL, NULL }
};
static void _register_lua_slurm_output_functions (void)
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
{
/*
* Register slurm output functions in a global "slurm" table
*/
lua_newtable (L);
luaL_register (L, NULL, slurm_functions);
/*
* Create more user-friendly lua versions of SLURM log functions.
*/
luaL_loadstring (L, "slurm.error (string.format(unpack({...})))");
lua_setfield (L, -2, "log_error");
luaL_loadstring (L, "slurm.log (0, string.format(unpack({...})))");
lua_setfield (L, -2, "log_info");
luaL_loadstring (L, "slurm.log (1, string.format(unpack({...})))");
lua_setfield (L, -2, "log_verbose");
luaL_loadstring (L, "slurm.log (2, string.format(unpack({...})))");
lua_setfield (L, -2, "log_debug");
luaL_loadstring (L, "slurm.log (3, string.format(unpack({...})))");
lua_setfield (L, -2, "log_debug2");
luaL_loadstring (L, "slurm.log (4, string.format(unpack({...})))");
lua_setfield (L, -2, "log_debug3");
luaL_loadstring (L, "slurm.log (5, string.format(unpack({...})))");
lua_setfield (L, -2, "log_debug4");
/*
* slurm.SUCCESS, slurm.FAILURE and slurm.ERROR
*/
lua_pushnumber (L, SLURM_FAILURE);
lua_setfield (L, -2, "FAILURE");
lua_pushnumber (L, SLURM_ERROR);
lua_setfield (L, -2, "ERROR");
lua_pushnumber (L, SLURM_SUCCESS);
lua_setfield (L, -2, "SUCCESS");
lua_setglobal (L, "slurm");
/* Get fields in an existing slurmctld job record
* NOTE: This is an incomplete list of job record fields.
* Add more as needed and send patches to slurm-dev@llnl.gov */
static int _get_job_rec_field (lua_State *L)
{

Moe Jette
committed
const struct job_record *job_ptr = lua_touserdata(L, 1);
const char *name = luaL_checkstring(L, 2);

Moe Jette
committed
if (job_ptr == NULL) {
error("_get_job_field: job_ptr is NULL");
lua_pushnil (L);
} else if (!strcmp(name, "account")) {

Moe Jette
committed
lua_pushstring (L, job_ptr->account);
} else if (!strcmp(name, "comment")) {

Moe Jette
committed
lua_pushstring (L, job_ptr->comment);
} else if (!strcmp(name, "direct_set_prio")) {
lua_pushnumber (L, job_ptr->direct_set_prio);
} else if (!strcmp(name, "gres")) {

Moe Jette
committed
lua_pushstring (L, job_ptr->gres);
} else if (!strcmp(name, "job_id")) {

Moe Jette
committed
lua_pushnumber (L, job_ptr->job_id);
} else if (!strcmp(name, "job_state")) {

Moe Jette
committed
lua_pushnumber (L, job_ptr->job_state);
} else if (!strcmp(name, "licenses")) {

Moe Jette
committed
lua_pushstring (L, job_ptr->licenses);
} else if (!strcmp(name, "max_cpus")) {

Moe Jette
committed
if (job_ptr->details)
lua_pushnumber (L, job_ptr->details->max_cpus);
else
lua_pushnumber (L, 0);
} else if (!strcmp(name, "max_nodes")) {

Moe Jette
committed
if (job_ptr->details)
lua_pushnumber (L, job_ptr->details->max_nodes);
else
lua_pushnumber (L, 0);
} else if (!strcmp(name, "min_cpus")) {

Moe Jette
committed
if (job_ptr->details)
lua_pushnumber (L, job_ptr->details->min_cpus);
else
lua_pushnumber (L, 0);
} else if (!strcmp(name, "min_nodes")) {

Moe Jette
committed
if (job_ptr->details)
lua_pushnumber (L, job_ptr->details->min_nodes);
else
lua_pushnumber (L, 0);
} else if (!strcmp(name, "nice")) {
if (job_ptr->details)
lua_pushnumber (L, job_ptr->details->nice);
else
lua_pushnumber (L, (uint16_t)NO_VAL);
} else if (!strcmp(name, "partition")) {

Moe Jette
committed
lua_pushstring (L, job_ptr->partition);
} else if (!strcmp(name, "priority")) {
lua_pushnumber (L, job_ptr->priority);
} else if (!strcmp(name, "time_limit")) {

Moe Jette
committed
lua_pushnumber (L, job_ptr->time_limit);
} else if (!strcmp(name, "time_min")) {

Moe Jette
committed
lua_pushnumber (L, job_ptr->time_min);
} else if (!strcmp(name, "wckey")) {

Moe Jette
committed
lua_pushstring (L, job_ptr->wckey);
} else {
lua_pushnil (L);
}
return 1;
}
/* Get fields in the job request record on job submit or modify */
static int _get_job_req_field (lua_State *L)

Moe Jette
committed
const struct job_descriptor *job_desc = lua_touserdata(L, 1);
const char *name = luaL_checkstring(L, 2);

Moe Jette
committed
if (job_desc == NULL) {
error("_get_job_req_field: job_desc is NULL");
lua_pushnil (L);
} else if (!strcmp(name, "account")) {

Moe Jette
committed
lua_pushstring (L, job_desc->account);
} else if (!strcmp(name, "acctg_freq")) {

Moe Jette
committed
lua_pushnumber (L, job_desc->acctg_freq);
} else if (!strcmp(name, "begin_time")) {

Moe Jette
committed
lua_pushnumber (L, job_desc->begin_time);
} else if (!strcmp(name, "comment")) {

Moe Jette
committed
lua_pushstring (L, job_desc->comment);
} else if (!strcmp(name, "contiguous")) {

Moe Jette
committed
lua_pushnumber (L, job_desc->contiguous);
} else if (!strcmp(name, "cores_per_socket")) {

Moe Jette
committed
lua_pushnumber (L, job_desc->cores_per_socket);
} else if (!strcmp(name, "dependency")) {

Moe Jette
committed
lua_pushstring (L, job_desc->dependency);
} else if (!strcmp(name, "end_time")) {

Moe Jette
committed
lua_pushnumber (L, job_desc->end_time);
} else if (!strcmp(name, "exc_nodes")) {

Moe Jette
committed
lua_pushstring (L, job_desc->exc_nodes);
} else if (!strcmp(name, "features")) {

Moe Jette
committed
lua_pushstring (L, job_desc->features);
} else if (!strcmp(name, "gres")) {

Moe Jette
committed
lua_pushstring (L, job_desc->gres);
} else if (!strcmp(name, "group_id")) {

Moe Jette
committed
lua_pushnumber (L, job_desc->group_id);
} else if (!strcmp(name, "licenses")) {

Moe Jette
committed
lua_pushstring (L, job_desc->licenses);
} else if (!strcmp(name, "max_cpus")) {

Moe Jette
committed
lua_pushnumber (L, job_desc->max_cpus);
} else if (!strcmp(name, "max_nodes")) {

Moe Jette
committed
lua_pushnumber (L, job_desc->max_nodes);
} else if (!strcmp(name, "min_cpus")) {

Moe Jette
committed
lua_pushnumber (L, job_desc->min_cpus);
} else if (!strcmp(name, "min_nodes")) {

Moe Jette
committed
lua_pushnumber (L, job_desc->min_nodes);
} else if (!strcmp(name, "name")) {

Moe Jette
committed
lua_pushstring (L, job_desc->name);
} else if (!strcmp(name, "nice")) {

Moe Jette
committed
lua_pushnumber (L, job_desc->nice);
} else if (!strcmp(name, "ntasks_per_node")) {

Moe Jette
committed
lua_pushnumber (L, job_desc->ntasks_per_node);
} else if (!strcmp(name, "num_tasks")) {

Moe Jette
committed
lua_pushnumber (L, job_desc->num_tasks);
} else if (!strcmp(name, "partition")) {

Moe Jette
committed
lua_pushstring (L, job_desc->partition);
} else if (!strcmp(name, "pn_min_cpus")) {

Moe Jette
committed
lua_pushnumber (L, job_desc->pn_min_cpus);
} else if (!strcmp(name, "pn_min_memory")) {

Moe Jette
committed
lua_pushnumber (L, job_desc->pn_min_memory);
} else if (!strcmp(name, "pn_min_tmp_disk")) {

Moe Jette
committed
lua_pushnumber (L, job_desc->pn_min_tmp_disk);
} else if (!strcmp(name, "priority")) {

Moe Jette
committed
lua_pushnumber (L, job_desc->priority);
} else if (!strcmp(name, "qos")) {

Moe Jette
committed
lua_pushstring (L, job_desc->qos);
} else if (!strcmp(name, "req_nodes")) {

Moe Jette
committed
lua_pushstring (L, job_desc->req_nodes);
} else if (!strcmp(name, "requeue")) {

Moe Jette
committed
lua_pushnumber (L, job_desc->requeue);
} else if (!strcmp(name, "reservation")) {

Moe Jette
committed
lua_pushstring (L, job_desc->reservation);
} else if (!strcmp(name, "shared")) {

Moe Jette
committed
lua_pushnumber (L, job_desc->shared);
} else if (!strcmp(name, "sockets_per_node")) {

Moe Jette
committed
lua_pushnumber (L, job_desc->sockets_per_node);
} else if (!strcmp(name, "threads_per_core")) {

Moe Jette
committed
lua_pushnumber (L, job_desc->threads_per_core);
} else if (!strcmp(name, "time_limit")) {

Moe Jette
committed
lua_pushnumber (L, job_desc->time_limit);
} else if (!strcmp(name, "time_min")) {

Moe Jette
committed
lua_pushnumber (L, job_desc->time_min);
} else if (!strcmp(name, "user_id")) {

Moe Jette
committed
lua_pushnumber (L, job_desc->user_id);
} else if (!strcmp(name, "wckey")) {

Moe Jette
committed
lua_pushstring (L, job_desc->wckey);
} else {
lua_pushnil (L);
}
return 1;
}
/* Set fields in the job request structure on job submit or modify */
static int _set_job_req_field (lua_State *L)

Moe Jette
committed
struct job_descriptor *job_desc = lua_touserdata(L, 1);
const char *name, *value_str;

Moe Jette
committed
name = luaL_checkstring(L, 2);
if (job_desc == NULL) {
error("_set_job_req_field: job_desc is NULL");
} else if (!strcmp(name, "account")) {

Moe Jette
committed
value_str = luaL_checkstring(L, 3);
xfree(job_desc->account);
if (strlen(value_str))

Moe Jette
committed
job_desc->account = xstrdup(value_str);
} else if (!strcmp(name, "acctg_freq")) {

Moe Jette
committed
job_desc->acctg_freq = luaL_checknumber(L, 3);
} else if (!strcmp(name, "begin_time")) {

Moe Jette
committed
job_desc->begin_time = luaL_checknumber(L, 3);
} else if (!strcmp(name, "comment")) {

Moe Jette
committed
value_str = luaL_checkstring(L, 3);
xfree(job_desc->comment);
if (strlen(value_str))

Moe Jette
committed
job_desc->comment = xstrdup(value_str);
} else if (!strcmp(name, "contiguous")) {

Moe Jette
committed
job_desc->contiguous = luaL_checknumber(L, 3);
} else if (!strcmp(name, "cores_per_socket")) {

Moe Jette
committed
job_desc->cores_per_socket = luaL_checknumber(L, 3);
} else if (!strcmp(name, "dependency")) {

Moe Jette
committed
value_str = luaL_checkstring(L, 3);
xfree(job_desc->dependency);
if (strlen(value_str))

Moe Jette
committed
job_desc->dependency = xstrdup(value_str);
} else if (!strcmp(name, "end_time")) {

Moe Jette
committed
job_desc->end_time = luaL_checknumber(L, 3);
} else if (!strcmp(name, "exc_nodes")) {

Moe Jette
committed
value_str = luaL_checkstring(L, 3);
xfree(job_desc->exc_nodes);
if (strlen(value_str))

Moe Jette
committed
job_desc->exc_nodes = xstrdup(value_str);
} else if (!strcmp(name, "features")) {

Moe Jette
committed
value_str = luaL_checkstring(L, 3);
xfree(job_desc->features);
if (strlen(value_str))

Moe Jette
committed
job_desc->features = xstrdup(value_str);
} else if (!strcmp(name, "gres")) {

Moe Jette
committed
value_str = luaL_checkstring(L, 3);
xfree(job_desc->gres);
if (strlen(value_str))

Moe Jette
committed
job_desc->gres = xstrdup(value_str);
} else if (!strcmp(name, "licenses")) {

Moe Jette
committed
value_str = luaL_checkstring(L, 3);
xfree(job_desc->licenses);
if (strlen(value_str))

Moe Jette
committed
job_desc->licenses = xstrdup(value_str);
} else if (!strcmp(name, "max_cpus")) {

Moe Jette
committed
job_desc->max_cpus = luaL_checknumber(L, 3);
} else if (!strcmp(name, "max_nodes")) {

Moe Jette
committed
job_desc->max_nodes = luaL_checknumber(L, 3);
} else if (!strcmp(name, "min_cpus")) {

Moe Jette
committed
job_desc->min_cpus = luaL_checknumber(L, 3);
} else if (!strcmp(name, "min_nodes")) {

Moe Jette
committed
job_desc->min_nodes = luaL_checknumber(L, 3);
} else if (!strcmp(name, "name")) {

Moe Jette
committed
value_str = luaL_checkstring(L, 3);
xfree(job_desc->name);
if (strlen(value_str))

Moe Jette
committed
job_desc->name = xstrdup(value_str);
} else if (!strcmp(name, "nice")) {

Moe Jette
committed
job_desc->nice = luaL_checknumber(L, 3);
} else if (!strcmp(name, "ntasks_per_node")) {

Moe Jette
committed
job_desc->ntasks_per_node = luaL_checknumber(L, 3);
} else if (!strcmp(name, "num_tasks")) {

Moe Jette
committed
job_desc->num_tasks = luaL_checknumber(L, 3);
} else if (!strcmp(name, "partition")) {

Moe Jette
committed
value_str = luaL_checkstring(L, 3);
xfree(job_desc->partition);
if (strlen(value_str))

Moe Jette
committed
job_desc->partition = xstrdup(value_str);
} else if (!strcmp(name, "pn_min_cpus")) {

Moe Jette
committed
job_desc->pn_min_cpus = luaL_checknumber(L, 3);
} else if (!strcmp(name, "pn_min_memory")) {

Moe Jette
committed
job_desc->pn_min_memory = luaL_checknumber(L, 3);
} else if (!strcmp(name, "pn_min_tmp_disk")) {

Moe Jette
committed
job_desc->pn_min_tmp_disk = luaL_checknumber(L, 3);
} else if (!strcmp(name, "priority")) {

Moe Jette
committed
job_desc->priority = luaL_checknumber(L, 3);
} else if (!strcmp(name, "qos")) {

Moe Jette
committed
value_str = luaL_checkstring(L, 3);
xfree(job_desc->qos);
if (strlen(value_str))

Moe Jette
committed
job_desc->qos = xstrdup(value_str);
} else if (!strcmp(name, "req_nodes")) {

Moe Jette
committed
value_str = luaL_checkstring(L, 3);
xfree(job_desc->req_nodes);
if (strlen(value_str))

Moe Jette
committed
job_desc->req_nodes = xstrdup(value_str);
} else if (!strcmp(name, "requeue")) {

Moe Jette
committed
job_desc->requeue = luaL_checknumber(L, 3);
} else if (!strcmp(name, "reservation")) {

Moe Jette
committed
value_str = luaL_checkstring(L, 3);
xfree(job_desc->reservation);
if (strlen(value_str))

Moe Jette
committed
job_desc->reservation = xstrdup(value_str);
} else if (!strcmp(name, "shared")) {

Moe Jette
committed
job_desc->shared = luaL_checknumber(L, 3);
} else if (!strcmp(name, "sockets_per_node")) {

Moe Jette
committed
job_desc->sockets_per_node = luaL_checknumber(L, 3);
} else if (!strcmp(name, "threads_per_core")) {

Moe Jette
committed
job_desc->threads_per_core = luaL_checknumber(L, 3);
} else if (!strcmp(name, "time_limit")) {

Moe Jette
committed
job_desc->time_limit = luaL_checknumber(L, 3);
} else if (!strcmp(name, "time_min")) {

Moe Jette
committed
job_desc->time_min = luaL_checknumber(L, 3);
} else if (!strcmp(name, "wckey")) {

Moe Jette
committed
value_str = luaL_checkstring(L, 3);
xfree(job_desc->wckey);
if (strlen(value_str))

Moe Jette
committed
job_desc->wckey = xstrdup(value_str);
} else {
error("_set_job_field: unrecognized field: %s", name);
}
/* Get fields in an existing slurmctld partition record
* NOTE: This is an incomplete list of partition record fields.
* Add more as needed and send patches to slurm-dev@llnl.gov */
static int _get_part_rec_field (lua_State *L)
{
const struct part_record *part_ptr = lua_touserdata(L, 1);
const char *name = luaL_checkstring(L, 2);
if (part_ptr == NULL) {
error("_get_part_field: part_ptr is NULL");
lua_pushnil (L);
} else if (!strcmp(name, "flag_default")) {
int is_default = 0;
if (part_ptr->flags & PART_FLAG_DEFAULT)
is_default = 1;
lua_pushnumber (L, is_default);
} else if (!strcmp(name, "flags")) {
lua_pushnumber (L, part_ptr->flags);
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
} else if (!strcmp(name, "max_nodes")) {
lua_pushnumber (L, part_ptr->max_nodes);
} else if (!strcmp(name, "max_nodes_orig")) {
lua_pushnumber (L, part_ptr->max_nodes_orig);
} else if (!strcmp(name, "max_time")) {
lua_pushnumber (L, part_ptr->max_time);
} else if (!strcmp(name, "min_nodes")) {
lua_pushnumber (L, part_ptr->min_nodes);
} else if (!strcmp(name, "min_nodes_orig")) {
lua_pushnumber (L, part_ptr->min_nodes_orig);
} else if (!strcmp(name, "name")) {
lua_pushstring (L, part_ptr->name);
} else if (!strcmp(name, "nodes")) {
lua_pushstring (L, part_ptr->nodes);
} else if (!strcmp(name, "priority")) {
lua_pushnumber (L, part_ptr->priority);
} else if (!strcmp(name, "state_up")) {
lua_pushnumber (L, part_ptr->state_up);
} else {
lua_pushnil (L);
}
return 1;
}
#if 0
/* Filter before packing list of partitions */
char *allow_groups; /* comma delimited list of groups */
uid_t *allow_uids; /* zero terminated list of allowed users */
#endif
static void _register_lua_slurm_struct_functions (void)
lua_pushcfunction(L, _get_job_rec_field);
lua_setglobal(L, "_get_job_rec_field");
lua_pushcfunction(L, _get_job_req_field);
lua_setglobal(L, "_get_job_req_field");
lua_pushcfunction(L, _set_job_req_field);
lua_setglobal(L, "_set_job_req_field");
lua_pushcfunction(L, _get_part_rec_field);
lua_setglobal(L, "_get_part_rec_field");
/*
* check that global symbol [name] in lua script is a function
*/
static int _check_lua_script_function(const char *name)
{
int rc = 0;
lua_getglobal(L, name);
if (!lua_isfunction(L, -1))
rc = -1;
lua_pop(L, -1);
return (rc);
}
/*
* Verify all required functions are defined in the job_submit/lua script
*/
static int _check_lua_script_functions()
{
int rc = 0;
int i;
const char *fns[] = {
"slurm_job_submit",
"slurm_job_modify",
NULL
};
i = 0;
do {
if (_check_lua_script_function(fns[i]) < 0) {
error("job_submit/lua: %s: "
"missing required function %s",
lua_script_path, fns[i]);
rc = -1;
}
} while (fns[++i]);
static bool _user_can_use_part(uint32_t user_id, uint32_t submit_uid,
struct part_record *part_ptr)
{
int i;
if (user_id == 0) {
if (part_ptr->flags & PART_FLAG_NO_ROOT)
return false;
return true;
}
if ((part_ptr->flags & PART_FLAG_ROOT_ONLY) && (submit_uid != 0))
return false;
if (part_ptr->allow_uids == NULL)
return true; /* No user ID filters */
for (i=0; part_ptr->allow_uids[i]; i++) {
if (user_id == part_ptr->allow_uids[i])
return true;
}
return false;
}
static void _push_partition_list(uint32_t user_id, uint32_t submit_uid)
{
int i = 1;
ListIterator part_iterator;
struct part_record *part_ptr;
lua_newtable(L);
part_iterator = list_iterator_create(part_list);
if (!part_iterator)
fatal("list_iterator_create malloc");
while ((part_ptr = (struct part_record *) list_next(part_iterator))) {
if (!_user_can_use_part(user_id, submit_uid, part_ptr))
continue;
lua_pushlightuserdata (L, part_ptr);
lua_rawseti(L, -2, i++);
}
list_iterator_destroy(part_iterator);
}
static void _push_job_desc(struct job_descriptor *job_desc)
{
lua_newtable(L);
lua_pushlightuserdata(L, job_desc);
lua_setfield(L, -2, "job_desc_ptr");
}
static void _push_job_rec(struct job_record *job_ptr)
{
lua_newtable(L);
lua_pushlightuserdata (L, job_ptr);
lua_setfield(L, -2, "job_rec_ptr");
}
/*
* NOTE: The init callback should never be called multiple times,
* let alone called from multiple threads. Therefore, locking
* is unnecessary here.
*/
int init (void)
{
int rc = SLURM_SUCCESS;
/*
* Need to dlopen() liblua.so with RTLD_GLOBAL in order to
* ensure symbols from liblua are available to libs opened
* by any lua scripts.
*/
if (!dlopen("liblua.so", RTLD_NOW | RTLD_GLOBAL)) {
if (!dlopen ("liblua5.1.so", RTLD_NOW | RTLD_GLOBAL) &&
!dlopen ("liblua5.1.so.0", RTLD_NOW | RTLD_GLOBAL))
return (error("Failed to open liblua.so: %s",
dlerror()));
/*
* Initilize lua
*/
L = luaL_newstate();
luaL_openlibs(L);
if (luaL_loadfile(L, lua_script_path)) {
return error("lua: %s: %s", lua_script_path,
lua_tostring(L, -1));
* Register SLURM functions in lua state:
* logging and slurm structure read/write functions
*/
_register_lua_slurm_output_functions();
_register_lua_slurm_struct_functions();
if (lua_pcall(L, 0, 1, 0) != 0) {
return error("job_submit/lua: %s: %s",
lua_script_path, lua_tostring (L, -1));
/*
* Get any return code from the lua script
*/
rc = (int) lua_tonumber(L, -1);
lua_pop (L, 1);
if (rc != SLURM_SUCCESS)
return rc;
/*
* Check for required lua script functions:
*/
return (_check_lua_script_functions());
}
int fini (void)
{
lua_close (L);
return SLURM_SUCCESS;
}
/* Lua script hook called for "submit job" event. */
extern int job_submit(struct job_descriptor *job_desc, uint32_t submit_uid)
{
int rc = SLURM_ERROR;
slurm_mutex_lock (&lua_lock);
/*
* All lua script functions should have been verified during
* initialization:
*/
lua_getglobal(L, "slurm_job_submit");
if (lua_isnil(L, -1))
goto out;
_push_job_desc(job_desc);
_push_partition_list(job_desc->user_id, submit_uid);
_stack_dump("job_submit, before lua_pcall", L);
if (lua_pcall (L, 2, 1, 0) != 0) {
error("%s/lua: %s: %s",
__func__, lua_script_path, lua_tostring (L, -1));
} else {
if (lua_isnumber(L, -1)) {
rc = lua_tonumber(L, -1);
} else {
info("%s/lua: %s: non-numeric return code",
__func__, lua_script_path);
rc = SLURM_SUCCESS;
}
lua_pop(L, 1);
}
_stack_dump("job_submit, after lua_pcall", L);
out: slurm_mutex_unlock (&lua_lock);
/* Lua script hook called for "modify job" event. */
extern int job_modify(struct job_descriptor *job_desc,
struct job_record *job_ptr, uint32_t submit_uid)
{
int rc = SLURM_ERROR;
slurm_mutex_lock (&lua_lock);
/*
* All lua script functions should have been verified during
* initialization:
*/
lua_getglobal(L, "slurm_job_modify");
if (lua_isnil(L, -1))
goto out;
_push_job_desc(job_desc);
_push_job_rec(job_ptr);
_push_partition_list(job_ptr->user_id, submit_uid);
_stack_dump("job_modify, before lua_pcall", L);
if (lua_pcall (L, 3, 1, 0) != 0) {
error("%s/lua: %s: %s",
__func__, lua_script_path, lua_tostring (L, -1));
} else {
if (lua_isnumber(L, -1)) {
rc = lua_tonumber(L, -1);
} else {
info("%s/lua: %s: non-numeric return code",
__func__, lua_script_path);
rc = SLURM_SUCCESS;
}
lua_pop(L, 1);
}
_stack_dump("job_modify, after lua_pcall", L);
out: slurm_mutex_unlock (&lua_lock);