1 /*****************************************************************************\
2 * prep.c - driver for PrEpPlugins ('Pr'olog and 'Ep'ilog)
3 *****************************************************************************
4 * Copyright (C) 2019 SchedMD LLC.
5 * Written by Tim Wickberg <tim@schedmd.com>
6 *
7 * This file is part of Slurm, a resource management program.
8 * For details, see <https://slurm.schedmd.com/>.
9 * Please also read the included file: DISCLAIMER.
10 *
11 * Slurm is free software; you can redistribute it and/or modify it under
12 * the terms of the GNU General Public License as published by the Free
13 * Software Foundation; either version 2 of the License, or (at your option)
14 * any later version.
15 *
16 * In addition, as a special exception, the copyright holders give permission
17 * to link the code of portions of this program with the OpenSSL library under
18 * certain conditions as described in each individual source file, and
19 * distribute linked combinations including the two. You must obey the GNU
20 * General Public License in all respects for all of the code used other than
21 * OpenSSL. If you modify file(s) with this exception, you may extend this
22 * exception to your version of the file(s), but you are not obligated to do
23 * so. If you do not wish to do so, delete this exception statement from your
24 * version. If you delete this exception statement from all source files in
25 * the program, then also delete it here.
26 *
27 * Slurm is distributed in the hope that it will be useful, but WITHOUT ANY
28 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
29 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
30 * details.
31 *
32 * You should have received a copy of the GNU General Public License along
33 * with Slurm; if not, write to the Free Software Foundation, Inc.,
34 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
35 \*****************************************************************************/
36
37 #include "src/common/plugin.h"
38 #include "src/common/plugrack.h"
39 #include "src/common/slurm_protocol_api.h"
40 #include "src/common/timers.h"
41 #include "src/common/xmalloc.h"
42 #include "src/common/xstring.h"
43
44 #include "src/common/prep.h"
45
46 typedef struct {
47 int (*register_callbacks)(prep_callbacks_t *callbacks);
48 int (*prolog)(job_env_t *job_env, slurm_cred_t *cred);
49 int (*epilog)(job_env_t *job_env, slurm_cred_t *cred);
50 int (*prolog_slurmctld)(job_record_t *job_ptr, bool *async);
51 int (*epilog_slurmctld)(job_record_t *job_ptr, bool *async);
52 } prep_ops_t;
53
54 /*
55 * Must be synchronized with prep_ops_t above.
56 */
57 static const char *syms[] = {
58 "prep_p_register_callbacks",
59 "prep_p_prolog",
60 "prep_p_epilog",
61 "prep_p_prolog_slurmctld",
62 "prep_p_epilog_slurmctld",
63 };
64
65 static int g_context_cnt = -1;
66 static prep_ops_t *ops = NULL;
67 static plugin_context_t **g_context = NULL;
68 static char *prep_plugin_list = NULL;
69 static pthread_mutex_t g_context_lock = PTHREAD_MUTEX_INITIALIZER;
70 static bool init_run = false;
71
72 /*
73 * Initialize the PrEpPlugins.
74 *
75 * Returns a Slurm errno.
76 */
prep_plugin_init(prep_callbacks_t * callbacks)77 extern int prep_plugin_init(prep_callbacks_t *callbacks)
78 {
79 int rc = SLURM_SUCCESS;
80 char *last = NULL, *tmp_plugin_list, *names;
81 char *plugin_type = "prep";
82 char *type;
83
84 if (init_run && (g_context_cnt >= 0))
85 return rc;
86
87 slurm_mutex_lock(&g_context_lock);
88 if (g_context_cnt >= 0)
89 goto fini;
90
91 prep_plugin_list = slurm_get_prep_plugins();
92 g_context_cnt = 0;
93 if ((prep_plugin_list == NULL) || (prep_plugin_list[0] == '\0'))
94 goto fini;
95
96 tmp_plugin_list = xstrdup(prep_plugin_list);
97 names = tmp_plugin_list;
98 while ((type = strtok_r(names, ",", &last))) {
99 xrecalloc(ops, g_context_cnt + 1, sizeof(prep_ops_t));
100 xrecalloc(g_context, g_context_cnt + 1,
101 sizeof(plugin_context_t *));
102
103 if (xstrncmp(type, "prep/", 5) == 0)
104 type += 5; /* backward compatibility */
105 type = xstrdup_printf("prep/%s", type);
106
107 g_context[g_context_cnt] = plugin_context_create(
108 plugin_type, type, (void **)&ops[g_context_cnt],
109 syms, sizeof(syms));
110 if (!g_context[g_context_cnt]) {
111 error("%s: cannot create %s context for %s",
112 __func__, plugin_type, type);
113 rc = SLURM_ERROR;
114 xfree(type);
115 break;
116 }
117
118 if (callbacks)
119 (*(ops[g_context_cnt].register_callbacks))(callbacks);
120
121 xfree(type);
122 g_context_cnt++;
123 names = NULL; /* for next strtok_r() iteration */
124 }
125 init_run = true;
126 xfree(tmp_plugin_list);
127
128 fini:
129 slurm_mutex_unlock(&g_context_lock);
130
131 if (rc != SLURM_SUCCESS)
132 prep_plugin_fini();
133
134 return rc;
135 }
136
137 /*
138 * Terminate the PrEpPlugins and free associated memory.
139 *
140 * Returns a Slurm errno.
141 */
prep_plugin_fini(void)142 extern int prep_plugin_fini(void)
143 {
144 int rc = SLURM_SUCCESS;
145
146 slurm_mutex_lock(&g_context_lock);
147 if (g_context_cnt < 0)
148 goto fini;
149
150 init_run = false;
151 for (int i = 0; i < g_context_cnt; i++) {
152 if (g_context[i]) {
153 int j = plugin_context_destroy(g_context[i]);
154 if (j != SLURM_SUCCESS)
155 rc = j;
156 }
157 }
158 xfree(ops);
159 xfree(g_context);
160 xfree(prep_plugin_list);
161 g_context_cnt = -1;
162
163 fini:
164 slurm_mutex_unlock(&g_context_lock);
165 return rc;
166 }
167
168 /*
169 * Perform reconfig, re-read any configuration files
170 */
prep_plugin_reconfig(void)171 extern int prep_plugin_reconfig(void)
172 {
173 int rc = SLURM_SUCCESS;
174 char *plugin_names = slurm_get_prep_plugins();
175 bool plugin_change = false;
176
177 if (!plugin_names && !prep_plugin_list)
178 return rc;
179
180 slurm_mutex_lock(&g_context_lock);
181 if (xstrcmp(plugin_names, prep_plugin_list))
182 plugin_change = true;
183 slurm_mutex_unlock(&g_context_lock);
184
185 if (plugin_change) {
186 info("%s: PrEpPlugins changed to %s", __func__, plugin_names);
187 rc = prep_plugin_fini();
188 if (rc == SLURM_SUCCESS)
189 rc = prep_plugin_init(NULL);
190 }
191 xfree(plugin_names);
192
193 return rc;
194 }
195
196 /*
197 **************************************************************************
198 * P L U G I N C A L L S *
199 **************************************************************************
200 */
201
prep_prolog(job_env_t * job_env,slurm_cred_t * cred)202 extern int prep_prolog(job_env_t *job_env, slurm_cred_t *cred)
203 {
204 DEF_TIMERS;
205 int rc;
206
207 START_TIMER;
208
209 rc = prep_plugin_init(NULL);
210 slurm_mutex_lock(&g_context_lock);
211 for (int i = 0; ((i < g_context_cnt) && (rc == SLURM_SUCCESS)); i++)
212 rc = (*(ops[i].prolog))(job_env, cred);
213 slurm_mutex_unlock(&g_context_lock);
214 END_TIMER2(__func__);
215
216 return rc;
217 }
218
prep_epilog(job_env_t * job_env,slurm_cred_t * cred)219 extern int prep_epilog(job_env_t *job_env, slurm_cred_t *cred)
220 {
221 DEF_TIMERS;
222 int rc;
223
224 START_TIMER;
225
226 rc = prep_plugin_init(NULL);
227 slurm_mutex_lock(&g_context_lock);
228 for (int i = 0; ((i < g_context_cnt) && (rc == SLURM_SUCCESS)); i++)
229 rc = (*(ops[i].epilog))(job_env, cred);
230 slurm_mutex_unlock(&g_context_lock);
231 END_TIMER2(__func__);
232
233 return rc;
234 }
235
prep_prolog_slurmctld(job_record_t * job_ptr)236 extern void prep_prolog_slurmctld(job_record_t *job_ptr)
237 {
238 DEF_TIMERS;
239 int rc;
240
241 START_TIMER;
242
243 rc = prep_plugin_init(NULL);
244 slurm_mutex_lock(&g_context_lock);
245 for (int i = 0; ((i < g_context_cnt) && (rc == SLURM_SUCCESS)); i++) {
246 bool async = false;
247
248 rc = (*(ops[i].prolog_slurmctld))(job_ptr, &async);
249
250 if (async)
251 job_ptr->prep_prolog_cnt++;
252 }
253 slurm_mutex_unlock(&g_context_lock);
254 END_TIMER2(__func__);
255 }
256
prep_epilog_slurmctld(job_record_t * job_ptr)257 extern void prep_epilog_slurmctld(job_record_t *job_ptr)
258 {
259 DEF_TIMERS;
260 int rc;
261
262 START_TIMER;
263
264 rc = prep_plugin_init(NULL);
265 slurm_mutex_lock(&g_context_lock);
266 for (int i = 0; ((i < g_context_cnt) && (rc == SLURM_SUCCESS)); i++) {
267 bool async = false;
268
269 rc = (*(ops[i].epilog_slurmctld))(job_ptr, &async);
270
271 if (async)
272 job_ptr->prep_epilog_cnt++;
273 }
274
275 if (job_ptr->prep_epilog_cnt)
276 job_ptr->epilog_running = true;
277
278 slurm_mutex_unlock(&g_context_lock);
279 END_TIMER2(__func__);
280 }
281