| /*****************************************************************************\ |
| * data_t parser plugin interface |
| ****************************************************************************** |
| * Copyright (C) SchedMD LLC. |
| * |
| * This file is part of Slurm, a resource management program. |
| * For details, see <https://slurm.schedmd.com/>. |
| * 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. |
| \*****************************************************************************/ |
| |
| #include "config.h" |
| |
| #include "src/common/data.h" |
| #include "src/common/fd.h" |
| #include "src/common/list.h" |
| #include "src/common/log.h" |
| #include "src/common/openapi.h" |
| #include "src/common/read_config.h" |
| #include "src/common/timers.h" |
| #include "src/common/xassert.h" |
| #include "src/common/xmalloc.h" |
| #include "src/common/xstring.h" |
| |
| #include "src/interfaces/data_parser.h" |
| #include "src/interfaces/serializer.h" |
| |
| #define PARSE_MAJOR_TYPE "data_parser" |
| #define PARSE_MAGIC 0x0ea0b1be |
| #define LATEST_PLUGIN_NAME "latest" |
| |
| struct data_parser_s { |
| int magic; |
| int plugin_offset; |
| /* arg returned by plugin init() */ |
| void *arg; |
| const char *plugin_type; /* ptr to plugin plugin_type - do not xfree */ |
| char *params; /* parameters from _new - must xfree */ |
| char *plugin_string; /* plugin_type+params - must xfree */ |
| }; |
| |
| typedef struct { |
| int (*parse)(void *arg, data_parser_type_t type, void *dst, |
| ssize_t dst_bytes, data_t *src, data_t *parent_path); |
| int (*dump)(void *arg, data_parser_type_t type, void *src, |
| ssize_t src_bytes, data_t *dst); |
| /* ptr returned to be handed to commands as arg */ |
| void *(*new)(data_parser_on_error_t on_parse_error, |
| data_parser_on_error_t on_dump_error, |
| data_parser_on_error_t on_query_error, void *error_arg, |
| data_parser_on_warn_t on_parse_warn, |
| data_parser_on_warn_t on_dump_warn, |
| data_parser_on_warn_t on_query_warn, void *warn, |
| char *params); |
| void (*free)(void *arg); |
| int (*assign)(void *arg, data_parser_attr_type_t type, void *obj); |
| openapi_type_t (*resolve_openapi_type)(void *arg, |
| data_parser_type_t type, |
| const char *field); |
| const char *(*resolve_type_str)(void *arg, data_parser_type_t type); |
| int (*inc_ref)(void *arg, data_parser_type_t type, |
| void **references_ptr); |
| int (*populate_schema)(void *arg, data_parser_type_t type, |
| void **references_ptr, data_t *dst, data_t *schemas); |
| int (*populate_parameters)(void *arg, data_parser_type_t parameter_type, |
| data_parser_type_t query_type, |
| void **references_ptr, data_t *dst, |
| data_t *schemas); |
| void (*release_refs)(void *arg, void **references_ptr); |
| bool (*is_complex)(void *arg); |
| bool (*is_deprecated)(void *arg); |
| int (*dump_flags)(void *arg, data_t *dst); |
| } parse_funcs_t; |
| |
| typedef struct { |
| char *plugin_type; |
| char *params; |
| } plugin_param_t; |
| |
| /* |
| * Must be synchronized with parse_funcs_t above. |
| */ |
| static const char *parse_syms[] = { |
| "data_parser_p_parse", |
| "data_parser_p_dump", |
| "data_parser_p_new", |
| "data_parser_p_free", |
| "data_parser_p_assign", |
| "data_parser_p_resolve_openapi_type", |
| "data_parser_p_resolve_type_string", |
| "data_parser_p_increment_reference", |
| "data_parser_p_populate_schema", |
| "data_parser_p_populate_parameters", |
| "data_parser_p_release_references", |
| "data_parser_p_is_complex", |
| "data_parser_p_is_deprecated", |
| "data_parser_p_dump_flags", |
| }; |
| |
| static plugins_t *plugins = NULL; |
| static pthread_mutex_t init_mutex = PTHREAD_MUTEX_INITIALIZER; |
| static int active_parsers = 0; |
| |
| static const char *_get_plugin_version(const char *plugin_type); |
| |
| extern int data_parser_g_parse(data_parser_t *parser, data_parser_type_t type, |
| void *dst, ssize_t dst_bytes, data_t *src, |
| data_t *parent_path) |
| { |
| const parse_funcs_t *funcs; |
| DEF_TIMERS; |
| int rc; |
| |
| if (!parser) |
| return ESLURM_DATA_INVALID_PARSER; |
| |
| funcs = plugins->functions[parser->plugin_offset]; |
| |
| if (!src || (data_get_type(src) == DATA_TYPE_NONE)) |
| return ESLURM_DATA_PARSE_NOTHING; |
| |
| xassert(type > DATA_PARSER_TYPE_INVALID); |
| xassert(type < DATA_PARSER_TYPE_MAX); |
| xassert(parser->magic == PARSE_MAGIC); |
| xassert(data_get_type(parent_path) == DATA_TYPE_LIST); |
| xassert(plugins && (plugins->magic == PLUGINS_MAGIC)); |
| xassert(parser->plugin_offset < plugins->count); |
| xassert(plugins->functions[parser->plugin_offset]); |
| |
| START_TIMER; |
| rc = funcs->parse(parser->arg, type, dst, dst_bytes, src, parent_path); |
| END_TIMER2(__func__); |
| |
| return rc; |
| } |
| |
| extern int data_parser_g_dump(data_parser_t *parser, data_parser_type_t type, |
| void *src, ssize_t src_bytes, data_t *dst) |
| { |
| DEF_TIMERS; |
| int rc; |
| const parse_funcs_t *funcs; |
| |
| if (!parser) |
| return ESLURM_DATA_INVALID_PARSER; |
| |
| funcs = plugins->functions[parser->plugin_offset]; |
| |
| xassert(data_get_type(dst)); |
| xassert(type > DATA_PARSER_TYPE_INVALID); |
| xassert(type < DATA_PARSER_TYPE_MAX); |
| xassert(parser->magic == PARSE_MAGIC); |
| xassert(plugins && (plugins->magic == PLUGINS_MAGIC)); |
| xassert(parser->plugin_offset < plugins->count); |
| xassert(plugins->functions[parser->plugin_offset]); |
| |
| START_TIMER; |
| rc = funcs->dump(parser->arg, type, src, src_bytes, dst); |
| END_TIMER2(__func__); |
| |
| return rc; |
| } |
| |
| /* takes ownership of params */ |
| static data_parser_t *_new_parser(data_parser_on_error_t on_parse_error, |
| data_parser_on_error_t on_dump_error, |
| data_parser_on_error_t on_query_error, |
| void *error_arg, |
| data_parser_on_warn_t on_parse_warn, |
| data_parser_on_warn_t on_dump_warn, |
| data_parser_on_warn_t on_query_warn, |
| void *warn_arg, int plugin_index, |
| char *params) |
| { |
| DEF_TIMERS; |
| const parse_funcs_t *funcs; |
| data_parser_t *parser = xmalloc(sizeof(*parser)); |
| |
| parser->magic = PARSE_MAGIC; |
| |
| parser->plugin_offset = plugin_index; |
| parser->plugin_type = plugins->types[plugin_index]; |
| parser->params = params; |
| |
| START_TIMER; |
| funcs = plugins->functions[plugin_index]; |
| parser->arg = funcs->new(on_parse_error, on_dump_error, on_query_error, |
| error_arg, on_parse_warn, on_dump_warn, |
| on_query_warn, warn_arg, params); |
| xstrfmtcat(parser->plugin_string, "%s%s", parser->plugin_type, |
| (parser->params ? parser->params : "")); |
| END_TIMER2(__func__); |
| |
| slurm_mutex_lock(&init_mutex); |
| xassert(active_parsers >= 0); |
| active_parsers++; |
| slurm_mutex_unlock(&init_mutex); |
| |
| return parser; |
| } |
| |
| static plugin_param_t *_parse_plugin_type(const char *plugin_type) |
| { |
| char *type, *last = NULL, *pl; |
| plugin_param_t *pparams = NULL; |
| int count = 0; |
| |
| if (!plugin_type) |
| return NULL; |
| |
| pl = xstrdup(plugin_type); |
| type = strtok_r(pl, ",", &last); |
| while (type) { |
| char *pl; |
| plugin_param_t *p; |
| |
| xrecalloc(pparams, (count + 2), sizeof(*pparams)); |
| |
| p = &pparams[count]; |
| |
| if ((pl = xstrstr(type, |
| SLURM_DATA_PARSER_PLUGIN_PARAMS_CHAR))) { |
| p->plugin_type = xstrndup(type, (pl - type)); |
| p->params = xstrdup(pl); |
| } else { |
| p->plugin_type = xstrdup(type); |
| } |
| |
| if (!xstrcasecmp(p->plugin_type, LATEST_PLUGIN_NAME)) { |
| xfree(p->plugin_type); |
| p->plugin_type = xstrdup(SLURM_DATA_PARSER_VERSION); |
| } |
| |
| log_flag(DATA, "%s: plugin=%s params=%s", |
| __func__, p->plugin_type, p->params); |
| |
| count++; |
| |
| type = strtok_r(NULL, ",", &last); |
| } |
| |
| xfree(pl); |
| return pparams; |
| } |
| |
| static int _load_plugins(plugin_param_t *pparams, plugrack_foreach_t listf, |
| bool skip_loading) |
| { |
| int rc = SLURM_SUCCESS; |
| |
| if (skip_loading) |
| return rc; |
| |
| slurm_mutex_lock(&init_mutex); |
| |
| serializer_required(MIME_TYPE_JSON); |
| |
| xassert(sizeof(parse_funcs_t) == |
| (sizeof(void *) * ARRAY_SIZE(parse_syms))); |
| |
| if (!pparams) { |
| rc = load_plugins(&plugins, PARSE_MAJOR_TYPE, NULL, listf, |
| parse_syms, ARRAY_SIZE(parse_syms)); |
| } else { |
| for (int i = 0; !rc && pparams[i].plugin_type; i++) |
| rc = load_plugins(&plugins, PARSE_MAJOR_TYPE, |
| pparams[i].plugin_type, listf, |
| parse_syms, ARRAY_SIZE(parse_syms)); |
| } |
| |
| xassert(rc || plugins); |
| |
| slurm_mutex_unlock(&init_mutex); |
| |
| return rc; |
| } |
| |
| static int _find_plugin_by_type(const char *plugin_type) |
| { |
| if (!plugin_type || !plugins) |
| return -1; |
| |
| /* quick match by pointer address */ |
| for (int i = 0; i < plugins->count; i++) { |
| if (plugin_type == plugins->types[i]) |
| return i; |
| } |
| |
| /* match by full string */ |
| for (int i = 0; i < plugins->count; i++) { |
| if (!xstrcasecmp(plugin_type, plugins->types[i])) |
| return i; |
| } |
| |
| /* match by string without "data_parser/" */ |
| for (int i = 0; i < plugins->count; i++) { |
| if (!xstrcasecmp(plugin_type, |
| _get_plugin_version(plugins->types[i]))) |
| return i; |
| } |
| |
| return -1; |
| } |
| |
| extern data_parser_t *data_parser_g_new(data_parser_on_error_t on_parse_error, |
| data_parser_on_error_t on_dump_error, |
| data_parser_on_error_t on_query_error, |
| void *error_arg, |
| data_parser_on_warn_t on_parse_warn, |
| data_parser_on_warn_t on_dump_warn, |
| data_parser_on_warn_t on_query_warn, |
| void *warn_arg, const char *plugin_type, |
| plugrack_foreach_t listf, |
| bool skip_loading) |
| { |
| int rc, index; |
| char *params = NULL; |
| data_parser_t *parser = NULL; |
| plugin_param_t *pparams; |
| |
| if (!xstrcasecmp(plugin_type, "list")) { |
| xassert(listf); |
| load_plugins(&plugins, PARSE_MAJOR_TYPE, plugin_type, listf, |
| parse_syms, ARRAY_SIZE(parse_syms)); |
| return NULL; |
| } |
| |
| pparams = _parse_plugin_type(plugin_type); |
| |
| if (!pparams || !pparams[0].plugin_type) { |
| error("%s: invalid plugin %s", __func__, plugin_type); |
| goto cleanup; |
| } |
| |
| if (pparams[1].plugin_type) { |
| error("%s: rejecting ambiguous plugin %s", |
| __func__, plugin_type); |
| goto cleanup; |
| } |
| |
| if ((rc = _load_plugins(pparams, listf, skip_loading))) { |
| error("%s: failure loading plugins: %s", |
| __func__, slurm_strerror(rc)); |
| goto cleanup; |
| } |
| |
| if ((index = _find_plugin_by_type(pparams[0].plugin_type)) < 0) { |
| error("%s: unable to find plugin %s", __func__, |
| pparams[0].plugin_type); |
| goto cleanup; |
| } |
| |
| SWAP(params, pparams[0].params); |
| |
| parser = _new_parser(on_parse_error, on_dump_error, on_query_error, |
| error_arg, on_parse_warn, on_dump_warn, |
| on_query_warn, warn_arg, index, params); |
| cleanup: |
| if (pparams) { |
| for (int i = 0; pparams[i].plugin_type; i++) { |
| xfree(pparams[i].plugin_type); |
| xfree(pparams[i].params); |
| } |
| xfree(pparams); |
| } |
| |
| return parser; |
| } |
| |
| extern data_parser_t **data_parser_g_new_array( |
| data_parser_on_error_t on_parse_error, |
| data_parser_on_error_t on_dump_error, |
| data_parser_on_error_t on_query_error, |
| void *error_arg, |
| data_parser_on_warn_t on_parse_warn, |
| data_parser_on_warn_t on_dump_warn, |
| data_parser_on_warn_t on_query_warn, |
| void *warn_arg, |
| const char *plugin_type, |
| plugrack_foreach_t listf, |
| bool skip_loading) |
| { |
| int rc, i = 0; |
| data_parser_t **parsers = NULL; |
| plugin_param_t *pparams; |
| |
| if (!xstrcasecmp(plugin_type, "list")) { |
| xassert(listf); |
| load_plugins(&plugins, PARSE_MAJOR_TYPE, plugin_type, listf, |
| parse_syms, ARRAY_SIZE(parse_syms)); |
| return NULL; |
| } |
| |
| pparams = _parse_plugin_type(plugin_type); |
| |
| if ((rc = _load_plugins(pparams, listf, skip_loading))) { |
| error("%s: failure loading plugins: %s", |
| __func__, slurm_strerror(rc)); |
| goto cleanup; |
| } |
| |
| /* always allocate for all possible plugins */ |
| parsers = xcalloc((plugins->count + 1), sizeof(*parsers)); |
| |
| if (pparams) { |
| for (; pparams[i].plugin_type; i++) { |
| int index = |
| _find_plugin_by_type(pparams[i].plugin_type); |
| |
| if (index < 0) { |
| error("%s: unable to find plugin %s", |
| __func__, pparams[i].plugin_type); |
| goto cleanup; |
| } |
| |
| parsers[i] = _new_parser(on_parse_error, on_dump_error, |
| on_query_error, error_arg, |
| on_parse_warn, on_dump_warn, |
| on_query_warn, warn_arg, index, |
| pparams[i].params); |
| |
| pparams[i].params = NULL; |
| xfree(pparams[i].plugin_type); |
| } |
| } else { |
| for (; i < plugins->count; i++) { |
| parsers[i] = _new_parser(on_parse_error, on_dump_error, |
| on_query_error, error_arg, |
| on_parse_warn, on_dump_warn, |
| on_query_warn, warn_arg, i, |
| NULL); |
| } |
| } |
| |
| xfree(pparams); |
| |
| return parsers; |
| cleanup: |
| if (pparams) { |
| for (; pparams[i].plugin_type; i++) { |
| xfree(pparams[i].plugin_type); |
| xfree(pparams[i].params); |
| } |
| xfree(pparams); |
| } |
| |
| if (plugins && parsers) |
| for (int j = 0; j < plugins->count; j++) |
| FREE_NULL_DATA_PARSER(parsers[j]); |
| xfree(parsers); |
| |
| return NULL; |
| } |
| |
| extern const char *data_parser_get_plugin(data_parser_t *parser) |
| { |
| if (!parser) |
| return NULL; |
| |
| xassert(parser->magic == PARSE_MAGIC); |
| |
| return parser->plugin_string; |
| } |
| |
| static const char *_get_plugin_version(const char *plugin_type) |
| { |
| static const char prefix[] = PARSE_MAJOR_TYPE "/"; |
| |
| #ifndef NDEBUG |
| /* catch if the prefix ever changes in an unexpected way */ |
| const char *match; |
| xassert(plugin_type); |
| match = xstrstr(plugin_type, prefix); |
| xassert(match); |
| #endif |
| |
| return plugin_type + strlen(prefix); |
| } |
| |
| extern const char *data_parser_get_plugin_version(data_parser_t *parser) |
| { |
| xassert(!parser || parser->magic == PARSE_MAGIC); |
| |
| if (!parser) |
| return NULL; |
| |
| return _get_plugin_version(parser->plugin_type); |
| } |
| |
| extern const char *data_parser_get_plugin_params(data_parser_t *parser) |
| { |
| xassert(!parser || parser->magic == PARSE_MAGIC); |
| |
| if (!parser) |
| return NULL; |
| |
| return parser->params; |
| } |
| |
| extern void data_parser_g_free(data_parser_t *parser, bool skip_unloading) |
| { |
| DEF_TIMERS; |
| const parse_funcs_t *funcs; |
| |
| if (!parser) |
| return; |
| |
| funcs = plugins->functions[parser->plugin_offset]; |
| |
| if (plugins) { |
| xassert(plugins->magic == PLUGINS_MAGIC); |
| xassert(plugins->functions[parser->plugin_offset]); |
| xassert(parser->magic == PARSE_MAGIC); |
| xassert(parser->plugin_offset < plugins->count); |
| } |
| |
| START_TIMER; |
| if (plugins) |
| funcs->free(parser->arg); |
| END_TIMER2(__func__); |
| |
| xfree(parser->params); |
| xfree(parser->plugin_string); |
| parser->arg = NULL; |
| parser->plugin_offset = -1; |
| parser->magic = ~PARSE_MAGIC; |
| xfree(parser); |
| |
| slurm_mutex_lock(&init_mutex); |
| xassert(active_parsers >= 0); |
| active_parsers--; |
| xassert(active_parsers >= 0); |
| |
| if (!skip_unloading && !active_parsers) |
| FREE_NULL_PLUGINS(plugins); |
| slurm_mutex_unlock(&init_mutex); |
| } |
| |
| extern void data_parser_g_array_free(data_parser_t **ptr, bool skip_unloading) |
| { |
| if (!ptr) |
| return; |
| |
| for (int i = 0; ptr[i]; i++) |
| data_parser_g_free(ptr[i], skip_unloading); |
| |
| xfree(ptr); |
| } |
| |
| extern int data_parser_g_assign(data_parser_t *parser, |
| data_parser_attr_type_t type, void *obj) |
| { |
| int rc; |
| DEF_TIMERS; |
| const parse_funcs_t *funcs; |
| |
| if (!parser) |
| return ESLURM_DATA_INVALID_PARSER; |
| |
| funcs = plugins->functions[parser->plugin_offset]; |
| |
| xassert(parser); |
| xassert(plugins); |
| xassert(parser->magic == PARSE_MAGIC); |
| xassert(parser->plugin_offset < plugins->count); |
| xassert(type > DATA_PARSER_ATTR_INVALID); |
| xassert(type < DATA_PARSER_ATTR_MAX); |
| |
| START_TIMER; |
| rc = funcs->assign(parser->arg, type, obj); |
| END_TIMER2(__func__); |
| |
| return rc; |
| } |
| |
| extern openapi_resp_meta_t *data_parser_cli_meta(int argc, char **argv, |
| const char *mime_type) |
| { |
| openapi_resp_meta_t *meta = xmalloc_nz(sizeof(*meta)); |
| int tty; |
| char **argvnt = NULL; |
| |
| /* need a new array with a NULL terminator */ |
| if (argc > 0) { |
| argvnt = xcalloc(argc, sizeof(*argv)); |
| memcpy(argvnt, argv, (sizeof(*argv) * (argc - 1))); |
| } |
| |
| if (isatty(STDIN_FILENO)) |
| tty = STDIN_FILENO; |
| else if (isatty(STDOUT_FILENO)) |
| tty = STDOUT_FILENO; |
| else if (isatty(STDERR_FILENO)) |
| tty = STDERR_FILENO; |
| else |
| tty = -1; |
| |
| *meta = (openapi_resp_meta_t) { |
| .plugin = { |
| .data_parser = NULL, |
| .accounting_storage = |
| slurm_conf.accounting_storage_type, |
| }, |
| .command = argvnt, |
| .client = { |
| .source = ((tty != -1) ? fd_resolve_path(tty) : |
| NULL), |
| .uid = getuid(), |
| .gid = getgid(), |
| }, |
| .slurm = { |
| .version = { |
| .major = xstrdup(SLURM_MAJOR), |
| .micro = xstrdup(SLURM_MICRO), |
| .minor = xstrdup(SLURM_MINOR), |
| }, |
| .release = xstrdup(SLURM_VERSION_STRING), |
| .cluster = xstrdup(slurm_conf.cluster_name), |
| } |
| }; |
| |
| return meta; |
| } |
| |
| static void _plugrack_foreach_list(const char *full_type, const char *fq_path, |
| const plugin_handle_t id, void *arg) |
| { |
| dprintf(STDOUT_FILENO, "%s\n", full_type); |
| } |
| |
| static bool _on_error(void *arg, data_parser_type_t type, int error_code, |
| const char *source, const char *why, ...) |
| { |
| va_list ap; |
| char *str; |
| data_parser_dump_cli_ctxt_t *ctxt = arg; |
| openapi_resp_error_t *e = NULL; |
| |
| if (ctxt) { |
| xassert(ctxt->magic == DATA_PARSER_DUMP_CLI_CTXT_MAGIC); |
| xassert(ctxt->errors); |
| |
| if (!ctxt->errors) |
| return false; |
| |
| e = xmalloc(sizeof(*e)); |
| } |
| |
| va_start(ap, why); |
| str = vxstrfmt(why, ap); |
| va_end(ap); |
| |
| if (str) { |
| error("%s: parser=%s rc[%d]=%s -> %s", |
| (source ? source : __func__), |
| (!ctxt ? "DEFAULT" : ctxt->data_parser), |
| error_code, slurm_strerror(error_code), str); |
| |
| if (e) |
| e->description = str; |
| else |
| xfree(str); |
| } |
| |
| if (error_code) { |
| if (e) |
| e->num = error_code; |
| |
| if (ctxt && !ctxt->rc) |
| ctxt->rc = error_code; |
| } |
| |
| /* |
| * e is always non-NULL is ctxt is non-NULL, but check if e != NULL to |
| * silence a coverity warning. |
| */ |
| if (source && ctxt && e) |
| e->source = xstrdup(source); |
| |
| if (ctxt) |
| list_append(ctxt->errors, e); |
| |
| return false; |
| } |
| |
| static void _on_warn(void *arg, data_parser_type_t type, const char *source, |
| const char *why, ...) |
| { |
| va_list ap; |
| char *str; |
| data_parser_dump_cli_ctxt_t *ctxt = arg; |
| openapi_resp_warning_t *w = NULL; |
| |
| if (ctxt) { |
| xassert(ctxt->magic == DATA_PARSER_DUMP_CLI_CTXT_MAGIC); |
| xassert(ctxt->warnings); |
| |
| if (!ctxt->warnings) |
| return; |
| |
| w = xmalloc(sizeof(*w)); |
| } |
| |
| va_start(ap, why); |
| str = vxstrfmt(why, ap); |
| va_end(ap); |
| |
| if (str) { |
| debug("%s: parser=%s WARNING: %s", |
| (source ? source : __func__), |
| (!ctxt ? "DEFAULT" : ctxt->data_parser), str); |
| |
| if (ctxt) |
| w->description = str; |
| else |
| xfree(str); |
| } |
| |
| if (source && ctxt) |
| w->source = xstrdup(source); |
| |
| if (ctxt) |
| list_append(ctxt->warnings, w); |
| } |
| |
| extern int data_parser_dump_cli_stdout(data_parser_type_t type, void *obj, |
| int obj_bytes, void *acct_db_conn, |
| const char *mime_type, |
| const char *data_parser, |
| data_parser_dump_cli_ctxt_t *ctxt, |
| openapi_resp_meta_t *meta) |
| { |
| int rc = SLURM_SUCCESS; |
| data_t *dresp = NULL; |
| data_parser_t *parser; |
| char *out = NULL; |
| |
| if (!xstrcasecmp(data_parser, "list")) { |
| dprintf(STDERR_FILENO, "Possible data_parser plugins:\n"); |
| parser = data_parser_g_new(NULL, NULL, NULL, NULL, NULL, NULL, |
| NULL, NULL, "list", |
| _plugrack_foreach_list, false); |
| FREE_NULL_DATA_PARSER(parser); |
| return SLURM_SUCCESS; |
| } |
| |
| if (!(parser = data_parser_cli_parser(data_parser, ctxt))) { |
| rc = ESLURM_DATA_INVALID_PARSER; |
| error("%s output not supported by %s", |
| mime_type, SLURM_DATA_PARSER_VERSION); |
| goto cleanup; |
| } |
| |
| if (acct_db_conn) |
| data_parser_g_assign(parser, DATA_PARSER_ATTR_DBCONN_PTR, |
| acct_db_conn); |
| |
| xassert(!meta->plugin.data_parser); |
| meta->plugin.data_parser = xstrdup(data_parser_get_plugin(parser)); |
| |
| dresp = data_new(); |
| |
| if (!data_parser_g_dump(parser, type, obj, obj_bytes, dresp) && |
| (data_get_type(dresp) != DATA_TYPE_NULL)) { |
| serializer_flags_t sflags = SER_FLAGS_NONE; |
| |
| if (data_parser_g_is_complex(parser)) |
| sflags |= SER_FLAGS_COMPLEX; |
| |
| serialize_g_data_to_string(&out, NULL, dresp, mime_type, |
| sflags); |
| } |
| |
| if (out && out[0]) |
| printf("%s\n", out); |
| else |
| debug("No output generated"); |
| |
| cleanup: |
| /* |
| * This is only called from the CLI just before exiting. |
| * Skip the explicit free here to improve responsiveness. |
| */ |
| #ifdef MEMORY_LEAK_DEBUG |
| xfree(out); |
| FREE_NULL_DATA(dresp); |
| FREE_NULL_DATA_PARSER(parser); |
| #endif |
| |
| return rc; |
| } |
| |
| extern data_parser_t *data_parser_cli_parser(const char *data_parser, void *arg) |
| { |
| char *default_data_parser = (slurm_conf.data_parser_parameters ? |
| slurm_conf.data_parser_parameters : |
| SLURM_DATA_PARSER_VERSION); |
| return data_parser_g_new(_on_error, _on_error, _on_error, arg, _on_warn, |
| _on_warn, _on_warn, arg, |
| (data_parser ? data_parser : |
| default_data_parser), NULL, false); |
| } |
| |
| extern openapi_type_t data_parser_g_resolve_openapi_type( |
| data_parser_t *parser, |
| data_parser_type_t type, |
| const char *field) |
| { |
| const parse_funcs_t *funcs; |
| |
| if (!parser) |
| return OPENAPI_TYPE_INVALID; |
| |
| funcs = plugins->functions[parser->plugin_offset]; |
| |
| xassert(parser); |
| xassert(plugins); |
| xassert(parser->magic == PARSE_MAGIC); |
| xassert(parser->plugin_offset < plugins->count); |
| |
| return funcs->resolve_openapi_type(parser->arg, type, field); |
| } |
| |
| extern const char *data_parser_g_resolve_type_string(data_parser_t *parser, |
| data_parser_type_t type) |
| { |
| const parse_funcs_t *funcs; |
| |
| if (!parser) |
| return NULL; |
| |
| funcs = plugins->functions[parser->plugin_offset]; |
| |
| xassert(plugins); |
| xassert(parser->magic == PARSE_MAGIC); |
| xassert(parser->plugin_offset < plugins->count); |
| |
| return funcs->resolve_type_str(parser->arg, type); |
| } |
| |
| extern int data_parser_g_increment_reference(data_parser_t *parser, |
| data_parser_type_t type, |
| void **references_ptr) |
| { |
| const parse_funcs_t *funcs; |
| |
| if (!parser) |
| return EINVAL; |
| |
| funcs = plugins->functions[parser->plugin_offset]; |
| |
| xassert(parser->magic == PARSE_MAGIC); |
| xassert(parser->plugin_offset < plugins->count); |
| |
| return funcs->inc_ref(parser->arg, type, references_ptr); |
| } |
| |
| extern int data_parser_g_populate_schema(data_parser_t *parser, |
| data_parser_type_t type, |
| void **references_ptr, data_t *dst, |
| data_t *schemas) |
| { |
| const parse_funcs_t *funcs; |
| |
| if (!parser) |
| return EINVAL; |
| |
| funcs = plugins->functions[parser->plugin_offset]; |
| |
| xassert(parser->magic == PARSE_MAGIC); |
| xassert(parser->plugin_offset < plugins->count); |
| |
| return funcs->populate_schema(parser->arg, type, references_ptr, dst, |
| schemas); |
| } |
| |
| extern int data_parser_g_populate_parameters(data_parser_t *parser, |
| data_parser_type_t parameter_type, |
| data_parser_type_t query_type, |
| void **references_ptr, data_t *dst, |
| data_t *schemas) |
| { |
| const parse_funcs_t *funcs; |
| |
| if (!parser) |
| return EINVAL; |
| |
| funcs = plugins->functions[parser->plugin_offset]; |
| |
| xassert(parser->magic == PARSE_MAGIC); |
| xassert(parser->plugin_offset < plugins->count); |
| |
| return funcs->populate_parameters(parser->arg, parameter_type, |
| query_type, references_ptr, dst, |
| schemas); |
| } |
| |
| extern void data_parser_g_release_references(data_parser_t *parser, |
| void **references_ptr) |
| { |
| const parse_funcs_t *funcs; |
| |
| if (!parser) |
| return; |
| |
| funcs = plugins->functions[parser->plugin_offset]; |
| |
| xassert(parser->magic == PARSE_MAGIC); |
| xassert(parser->plugin_offset < plugins->count); |
| |
| return funcs->release_refs(parser->arg, references_ptr); |
| } |
| |
| extern bool data_parser_g_is_complex(data_parser_t *parser) |
| { |
| const parse_funcs_t *funcs; |
| |
| if (!parser) |
| return false; |
| |
| funcs = plugins->functions[parser->plugin_offset]; |
| |
| xassert(parser->magic == PARSE_MAGIC); |
| xassert(parser->plugin_offset < plugins->count); |
| |
| return funcs->is_complex(parser->arg); |
| } |
| |
| extern bool data_parser_g_is_deprecated(data_parser_t *parser) |
| { |
| const parse_funcs_t *funcs; |
| |
| if (!parser) |
| return true; |
| |
| funcs = plugins->functions[parser->plugin_offset]; |
| |
| xassert(parser->magic == PARSE_MAGIC); |
| xassert(parser->plugin_offset < plugins->count); |
| |
| return funcs->is_deprecated(parser->arg); |
| } |
| |
| extern int data_parser_g_dump_flags(data_parser_t *parser, data_t *dst) |
| { |
| const parse_funcs_t *funcs; |
| |
| if (!parser) |
| return EINVAL; |
| |
| xassert(data_get_type(dst)); |
| xassert(parser->magic == PARSE_MAGIC); |
| xassert(plugins && (plugins->magic == PLUGINS_MAGIC)); |
| xassert(parser->plugin_offset < plugins->count); |
| xassert(plugins->functions[parser->plugin_offset]); |
| |
| funcs = plugins->functions[parser->plugin_offset]; |
| |
| return funcs->dump_flags(parser->arg, dst); |
| } |