1 /*****************************************************************************\
2 * job_submit.c - driver for job_submit plugin
3 *****************************************************************************
4 * Copyright (C) 2010 Lawrence Livermore National Security.
5 * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
6 * Written by Morris Jette <jette1@llnl.gov>
7 * CODE-OCEC-09-009. All rights reserved.
8 *
9 * This file is part of Slurm, a resource management program.
10 * For details, see <https://slurm.schedmd.com/>.
11 * Please also read the included file: DISCLAIMER.
12 *
13 * Slurm is free software; you can redistribute it and/or modify it under
14 * the terms of the GNU General Public License as published by the Free
15 * Software Foundation; either version 2 of the License, or (at your option)
16 * any later version.
17 *
18 * In addition, as a special exception, the copyright holders give permission
19 * to link the code of portions of this program with the OpenSSL library under
20 * certain conditions as described in each individual source file, and
21 * distribute linked combinations including the two. You must obey the GNU
22 * General Public License in all respects for all of the code used other than
23 * OpenSSL. If you modify file(s) with this exception, you may extend this
24 * exception to your version of the file(s), but you are not obligated to do
25 * so. If you do not wish to do so, delete this exception statement from your
26 * version. If you delete this exception statement from all source files in
27 * the program, then also delete it here.
28 *
29 * Slurm is distributed in the hope that it will be useful, but WITHOUT ANY
30 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
31 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
32 * details.
33 *
34 * You should have received a copy of the GNU General Public License along
35 * with Slurm; if not, write to the Free Software Foundation, Inc.,
36 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
37 \*****************************************************************************/
38
39 #include <inttypes.h>
40 #include <stdio.h>
41 #include <string.h>
42 #include <sys/types.h>
43 #include <unistd.h>
44
45 #include "slurm/slurm.h"
46 #include "slurm/slurm_errno.h"
47
48 #include "src/common/macros.h"
49 #include "src/common/plugin.h"
50 #include "src/common/plugrack.h"
51 #include "src/common/slurm_protocol_api.h"
52 #include "src/common/xmalloc.h"
53 #include "src/common/xstring.h"
54 #include "src/slurmctld/slurmctld.h"
55 #include "src/slurmctld/job_submit.h"
56 #include "src/slurmctld/locks.h"
57
58 typedef struct slurm_submit_ops {
59 int (*submit)(job_desc_msg_t *job_desc, uint32_t submit_uid,
60 char **err_msg);
61 int (*modify)(job_desc_msg_t *job_desc, job_record_t *job_ptr,
62 uint32_t submit_uid);
63 } slurm_submit_ops_t;
64
65 /*
66 * Must be synchronized with slurm_submit_ops_t above.
67 */
68 static const char *syms[] = {
69 "job_submit",
70 "job_modify"
71 };
72
73 static int g_context_cnt = -1;
74 static slurm_submit_ops_t *ops = NULL;
75 static plugin_context_t **g_context = NULL;
76 static char *submit_plugin_list = NULL;
77 static pthread_mutex_t g_context_lock = PTHREAD_MUTEX_INITIALIZER;
78 static bool init_run = false;
79
80 /*
81 * Initialize the job submit plugin.
82 *
83 * Returns a Slurm errno.
84 */
job_submit_plugin_init(void)85 extern int job_submit_plugin_init(void)
86 {
87 int rc = SLURM_SUCCESS;
88 char *last = NULL, *tmp_plugin_list, *names;
89 char *plugin_type = "job_submit";
90 char *type;
91
92 if (init_run && (g_context_cnt >= 0))
93 return rc;
94
95 slurm_mutex_lock(&g_context_lock);
96 if (g_context_cnt >= 0)
97 goto fini;
98
99 submit_plugin_list = slurm_get_job_submit_plugins();
100 g_context_cnt = 0;
101 if ((submit_plugin_list == NULL) || (submit_plugin_list[0] == '\0'))
102 goto fini;
103
104 tmp_plugin_list = xstrdup(submit_plugin_list);
105 names = tmp_plugin_list;
106 while ((type = strtok_r(names, ",", &last))) {
107 xrecalloc(ops, g_context_cnt + 1, sizeof(slurm_submit_ops_t));
108 xrecalloc(g_context, g_context_cnt + 1,
109 sizeof(plugin_context_t *));
110 if (xstrncmp(type, "job_submit/", 11) == 0)
111 type += 11; /* backward compatibility */
112 type = xstrdup_printf("job_submit/%s", type);
113 g_context[g_context_cnt] = plugin_context_create(
114 plugin_type, type, (void **)&ops[g_context_cnt],
115 syms, sizeof(syms));
116 if (!g_context[g_context_cnt]) {
117 error("cannot create %s context for %s",
118 plugin_type, type);
119 rc = SLURM_ERROR;
120 xfree(type);
121 break;
122 }
123
124 xfree(type);
125 g_context_cnt++;
126 names = NULL; /* for next strtok_r() iteration */
127 }
128 init_run = true;
129 xfree(tmp_plugin_list);
130
131 fini:
132 slurm_mutex_unlock(&g_context_lock);
133
134 if (rc != SLURM_SUCCESS)
135 job_submit_plugin_fini();
136
137 return rc;
138 }
139
140 /*
141 * Terminate the job submit plugin. Free memory.
142 *
143 * Returns a Slurm errno.
144 */
job_submit_plugin_fini(void)145 extern int job_submit_plugin_fini(void)
146 {
147 int i, j, rc = SLURM_SUCCESS;
148
149 slurm_mutex_lock(&g_context_lock);
150 if (g_context_cnt < 0)
151 goto fini;
152
153 init_run = false;
154 for (i=0; i<g_context_cnt; i++) {
155 if (g_context[i]) {
156 j = plugin_context_destroy(g_context[i]);
157 if (j != SLURM_SUCCESS)
158 rc = j;
159 }
160 }
161 xfree(ops);
162 xfree(g_context);
163 xfree(submit_plugin_list);
164 g_context_cnt = -1;
165
166 fini: slurm_mutex_unlock(&g_context_lock);
167 return rc;
168 }
169
170 /*
171 **************************************************************************
172 * P L U G I N C A L L S *
173 **************************************************************************
174 */
175
176 /*
177 * Perform reconfig, re-read any configuration files
178 */
job_submit_plugin_reconfig(void)179 extern int job_submit_plugin_reconfig(void)
180 {
181 int rc = SLURM_SUCCESS;
182 char *plugin_names = slurm_get_job_submit_plugins();
183 bool plugin_change;
184
185 if (!plugin_names && !submit_plugin_list)
186 return rc;
187
188 slurm_mutex_lock(&g_context_lock);
189 if (xstrcmp(plugin_names, submit_plugin_list))
190 plugin_change = true;
191 else
192 plugin_change = false;
193 slurm_mutex_unlock(&g_context_lock);
194
195 if (plugin_change) {
196 info("JobSubmitPlugins changed to %s", plugin_names);
197 rc = job_submit_plugin_fini();
198 if (rc == SLURM_SUCCESS)
199 rc = job_submit_plugin_init();
200 }
201 xfree(plugin_names);
202
203 return rc;
204 }
205
206 /*
207 * Execute the job_submit() function in each job submit plugin.
208 * If any plugin function returns anything other than SLURM_SUCCESS
209 * then stop and forward it's return value.
210 * IN job_desc - Job request specification
211 * IN submit_uid - User issuing job submit request
212 * OUT err_msg - Custom error message to the user, caller to xfree results
213 */
job_submit_plugin_submit(job_desc_msg_t * job_desc,uint32_t submit_uid,char ** err_msg)214 extern int job_submit_plugin_submit(job_desc_msg_t *job_desc,
215 uint32_t submit_uid, char **err_msg)
216 {
217 DEF_TIMERS;
218 int i, rc;
219
220 xassert(verify_lock(CONF_LOCK, READ_LOCK));
221 xassert(verify_lock(JOB_LOCK, READ_LOCK));
222 xassert(verify_lock(NODE_LOCK, READ_LOCK));
223 xassert(verify_lock(PART_LOCK, READ_LOCK));
224
225 START_TIMER;
226
227 /* Set to NO_VAL so that it can only be set by the job submit plugin. */
228 job_desc->site_factor = NO_VAL;
229
230 rc = job_submit_plugin_init();
231 slurm_mutex_lock(&g_context_lock);
232 /* NOTE: On function entry read locks are set on config, job, node and
233 * partition structures. Do not attempt to unlock them and then
234 * lock again (say with a write lock) since doing so will trigger
235 * a deadlock with the g_context_lock above. */
236 for (i = 0; ((i < g_context_cnt) && (rc == SLURM_SUCCESS)); i++)
237 rc = (*(ops[i].submit))(job_desc, submit_uid, err_msg);
238 slurm_mutex_unlock(&g_context_lock);
239 END_TIMER2("job_submit_plugin_submit");
240
241 return rc;
242 }
243
244 /*
245 * Execute the job_modify() function in each job submit plugin.
246 * If any plugin function returns anything other than SLURM_SUCCESS
247 * then stop and forward it's return value.
248 */
job_submit_plugin_modify(job_desc_msg_t * job_desc,job_record_t * job_ptr,uint32_t submit_uid)249 extern int job_submit_plugin_modify(job_desc_msg_t *job_desc,
250 job_record_t *job_ptr,
251 uint32_t submit_uid)
252 {
253 DEF_TIMERS;
254 int i, rc;
255
256 xassert(verify_lock(CONF_LOCK, READ_LOCK));
257 xassert(verify_lock(JOB_LOCK, READ_LOCK));
258 xassert(verify_lock(NODE_LOCK, READ_LOCK));
259 xassert(verify_lock(PART_LOCK, READ_LOCK));
260
261 START_TIMER;
262
263 /* Set to NO_VAL so that it can only be set by the job submit plugin. */
264 job_desc->site_factor = NO_VAL;
265
266 rc = job_submit_plugin_init();
267 slurm_mutex_lock(&g_context_lock);
268 for (i = 0; ((i < g_context_cnt) && (rc == SLURM_SUCCESS)); i++)
269 rc = (*(ops[i].modify))(job_desc, job_ptr, submit_uid);
270 slurm_mutex_unlock(&g_context_lock);
271 END_TIMER2("job_submit_plugin_modify");
272
273 return rc;
274 }
275