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