/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* Fluent Bit * ========== * Copyright (C) 2015-2022 The Fluent Bit Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include #include static inline void pack_str_s(msgpack_packer *mp_pck, char *str, int size) { int len; len = strlen(str); msgpack_pack_str(mp_pck, len); if (len > 0) { msgpack_pack_str_body(mp_pck, str, len); } } static inline void pack_str(msgpack_packer *mp_pck, char *str) { int size = strlen(str); pack_str_s(mp_pck, str, size); } int pack_config_map_entry(msgpack_packer *mp_pck, struct flb_config_map *m) { int len; struct flb_mp_map_header mh; flb_mp_map_header_init(&mh, mp_pck); /* name */ flb_mp_map_header_append(&mh); pack_str(mp_pck, "name"); pack_str(mp_pck, m->name); /* description */ flb_mp_map_header_append(&mh); pack_str(mp_pck, "description"); if (m->desc) { pack_str(mp_pck, m->desc); } else { pack_str(mp_pck, ""); } /* default value */ flb_mp_map_header_append(&mh); pack_str(mp_pck, "default"); if (m->def_value) { pack_str(mp_pck, m->def_value); } else { msgpack_pack_nil(mp_pck); } /* type */ flb_mp_map_header_append(&mh); pack_str(mp_pck, "type"); if (m->type == FLB_CONFIG_MAP_STR) { pack_str(mp_pck, "string"); } else if (m->type == FLB_CONFIG_MAP_DEPRECATED) { pack_str(mp_pck, "deprecated"); } else if (m->type == FLB_CONFIG_MAP_INT) { pack_str(mp_pck, "integer"); } else if (m->type == FLB_CONFIG_MAP_BOOL) { pack_str(mp_pck, "boolean"); } else if(m->type == FLB_CONFIG_MAP_DOUBLE) { pack_str(mp_pck, "double"); } else if (m->type == FLB_CONFIG_MAP_SIZE) { pack_str(mp_pck, "size"); } else if (m->type == FLB_CONFIG_MAP_TIME) { pack_str(mp_pck, "time"); } else if (flb_config_map_mult_type(m->type) == FLB_CONFIG_MAP_CLIST) { len = flb_config_map_expected_values(m->type); if (len == -1) { pack_str(mp_pck, "multiple comma delimited strings"); } else { char tmp[64]; snprintf(tmp, sizeof(tmp) - 1, "comma delimited strings (minimum %i)", len); pack_str(mp_pck, tmp); } } else if (flb_config_map_mult_type(m->type) == FLB_CONFIG_MAP_SLIST) { len = flb_config_map_expected_values(m->type); if (len == -1) { pack_str(mp_pck, "multiple space delimited strings"); } else { char tmp[64]; snprintf(tmp, sizeof(tmp) - 1, "space delimited strings (minimum %i)", len); pack_str(mp_pck, tmp); } } else if (m->type == FLB_CONFIG_MAP_STR_PREFIX) { pack_str(mp_pck, "prefixed string"); } flb_mp_map_header_end(&mh); return 0; } int flb_help_custom(struct flb_custom_instance *ins, void **out_buf, size_t *out_size) { struct mk_list *head; struct mk_list *config_map; struct flb_mp_map_header mh; struct flb_config_map *m; msgpack_sbuffer mp_sbuf; msgpack_packer mp_pck; msgpack_sbuffer_init(&mp_sbuf); msgpack_packer_init(&mp_pck, &mp_sbuf, msgpack_sbuffer_write); msgpack_pack_map(&mp_pck, 4); /* plugin type */ pack_str(&mp_pck, "type"); pack_str(&mp_pck, "custom"); /* plugin name */ pack_str(&mp_pck, "name"); pack_str(&mp_pck, ins->p->name); /* description */ pack_str(&mp_pck, "description"); pack_str(&mp_pck, ins->p->description); /* list of properties */ pack_str(&mp_pck, "properties"); flb_mp_map_header_init(&mh, &mp_pck); /* properties['options']: options exposed by the plugin */ if (ins->p->config_map) { flb_mp_map_header_append(&mh); pack_str(&mp_pck, "options"); config_map = flb_config_map_create(ins->config, ins->p->config_map); msgpack_pack_array(&mp_pck, mk_list_size(config_map)); mk_list_foreach(head, config_map) { m = mk_list_entry(head, struct flb_config_map, _head); pack_config_map_entry(&mp_pck, m); } flb_config_map_destroy(config_map); } flb_mp_map_header_end(&mh); *out_buf = mp_sbuf.data; *out_size = mp_sbuf.size; return 0; } int flb_help_input(struct flb_input_instance *ins, void **out_buf, size_t *out_size) { struct mk_list *head; struct mk_list *config_map; struct flb_mp_map_header mh; struct flb_config_map *m; msgpack_sbuffer mp_sbuf; msgpack_packer mp_pck; int options_size = 0; struct mk_list *tls_config; struct flb_config_map m_input_net_listen = { .type = FLB_CONFIG_MAP_STR, .name = "host", .def_value = "0.0.0.0", .desc = "Listen Address", }; struct flb_config_map m_input_net_port = { .type = FLB_CONFIG_MAP_INT, .name = "port", .def_value = "0", .desc = "Listen Port", }; msgpack_sbuffer_init(&mp_sbuf); msgpack_packer_init(&mp_pck, &mp_sbuf, msgpack_sbuffer_write); msgpack_pack_map(&mp_pck, 4); /* plugin type */ pack_str(&mp_pck, "type"); pack_str(&mp_pck, "input"); /* plugin name */ pack_str(&mp_pck, "name"); pack_str(&mp_pck, ins->p->name); /* description */ pack_str(&mp_pck, "description"); pack_str(&mp_pck, ins->p->description); /* list of properties */ pack_str(&mp_pck, "properties"); flb_mp_map_header_init(&mh, &mp_pck); /* properties['options']: options exposed by the plugin */ if (ins->p->config_map) { flb_mp_map_header_append(&mh); pack_str(&mp_pck, "options"); config_map = flb_config_map_create(ins->config, ins->p->config_map); options_size = mk_list_size(config_map); if ((ins->flags & (FLB_INPUT_NET | FLB_INPUT_NET_SERVER)) != 0) { options_size += 2; } if (ins->flags & FLB_IO_OPT_TLS) { tls_config = flb_tls_get_config_map(ins->config); options_size += mk_list_size(tls_config); } msgpack_pack_array(&mp_pck, options_size); if ((ins->flags & (FLB_INPUT_NET | FLB_INPUT_NET_SERVER)) != 0) { pack_config_map_entry(&mp_pck, &m_input_net_listen); pack_config_map_entry(&mp_pck, &m_input_net_port); } if (ins->flags & FLB_IO_OPT_TLS) { mk_list_foreach(head, tls_config) { m = mk_list_entry(head, struct flb_config_map, _head); pack_config_map_entry(&mp_pck, m); } flb_config_map_destroy(tls_config); } mk_list_foreach(head, config_map) { m = mk_list_entry(head, struct flb_config_map, _head); pack_config_map_entry(&mp_pck, m); } flb_config_map_destroy(config_map); } flb_mp_map_header_end(&mh); *out_buf = mp_sbuf.data; *out_size = mp_sbuf.size; return 0; } int flb_help_filter(struct flb_filter_instance *ins, void **out_buf, size_t *out_size) { struct mk_list *head; struct mk_list *config_map; struct flb_mp_map_header mh; struct flb_config_map *m; msgpack_sbuffer mp_sbuf; msgpack_packer mp_pck; msgpack_sbuffer_init(&mp_sbuf); msgpack_packer_init(&mp_pck, &mp_sbuf, msgpack_sbuffer_write); msgpack_pack_map(&mp_pck, 4); /* plugin type */ pack_str(&mp_pck, "type"); pack_str(&mp_pck, "filter"); /* plugin name */ pack_str(&mp_pck, "name"); pack_str(&mp_pck, ins->p->name); /* description */ pack_str(&mp_pck, "description"); pack_str(&mp_pck, ins->p->description); /* list of properties */ pack_str(&mp_pck, "properties"); flb_mp_map_header_init(&mh, &mp_pck); /* properties['options']: options exposed by the plugin */ if (ins->p->config_map) { flb_mp_map_header_append(&mh); pack_str(&mp_pck, "options"); config_map = flb_config_map_create(ins->config, ins->p->config_map); msgpack_pack_array(&mp_pck, mk_list_size(config_map)); mk_list_foreach(head, config_map) { m = mk_list_entry(head, struct flb_config_map, _head); pack_config_map_entry(&mp_pck, m); } flb_config_map_destroy(config_map); } flb_mp_map_header_end(&mh); *out_buf = mp_sbuf.data; *out_size = mp_sbuf.size; return 0; } int flb_help_output(struct flb_output_instance *ins, void **out_buf, size_t *out_size) { struct mk_list *head; struct mk_list *config_map; struct flb_mp_map_header mh; struct flb_config_map *m; msgpack_sbuffer mp_sbuf; msgpack_packer mp_pck; int options_size = 0; struct mk_list *tls_config; struct flb_config_map m_output_net_host = { .type = FLB_CONFIG_MAP_STR, .name = "host", .def_value = "", .flags = 0, .desc = "Host Address", }; struct flb_config_map m_output_net_port = { .type = FLB_CONFIG_MAP_INT, .name = "port", .def_value = "0", .flags = 0, .desc = "host Port", }; msgpack_sbuffer_init(&mp_sbuf); msgpack_packer_init(&mp_pck, &mp_sbuf, msgpack_sbuffer_write); msgpack_pack_map(&mp_pck, 4); /* plugin type */ pack_str(&mp_pck, "type"); pack_str(&mp_pck, "output"); /* plugin name */ pack_str(&mp_pck, "name"); pack_str(&mp_pck, ins->p->name); /* description */ pack_str(&mp_pck, "description"); pack_str(&mp_pck, ins->p->description); /* list of properties */ pack_str(&mp_pck, "properties"); flb_mp_map_header_init(&mh, &mp_pck); /* properties['options']: options exposed by the plugin */ if (ins->p->config_map) { flb_mp_map_header_append(&mh); pack_str(&mp_pck, "options"); config_map = flb_config_map_create(ins->config, ins->p->config_map); options_size = mk_list_size(config_map); options_size = mk_list_size(config_map); if (ins->flags & FLB_OUTPUT_NET) { options_size += 2; } if (ins->flags & FLB_IO_OPT_TLS) { tls_config = flb_tls_get_config_map(ins->config); options_size += mk_list_size(tls_config); } msgpack_pack_array(&mp_pck, options_size); if (ins->flags & FLB_OUTPUT_NET) { pack_config_map_entry(&mp_pck, &m_output_net_host); pack_config_map_entry(&mp_pck, &m_output_net_port); } if (ins->flags & FLB_IO_OPT_TLS) { mk_list_foreach(head, tls_config) { m = mk_list_entry(head, struct flb_config_map, _head); pack_config_map_entry(&mp_pck, m); } flb_config_map_destroy(tls_config); } mk_list_foreach(head, config_map) { m = mk_list_entry(head, struct flb_config_map, _head); pack_config_map_entry(&mp_pck, m); } flb_config_map_destroy(config_map); } if (ins->p->flags & FLB_OUTPUT_NET) { flb_mp_map_header_append(&mh); pack_str(&mp_pck, "networking"); config_map = flb_upstream_get_config_map(ins->config); msgpack_pack_array(&mp_pck, mk_list_size(config_map)); mk_list_foreach(head, config_map) { m = mk_list_entry(head, struct flb_config_map, _head); pack_config_map_entry(&mp_pck, m); } flb_config_map_destroy(config_map); } if (ins->p->flags & (FLB_IO_TLS | FLB_IO_OPT_TLS)) { flb_mp_map_header_append(&mh); pack_str(&mp_pck, "network_tls"); config_map = flb_tls_get_config_map(ins->config); msgpack_pack_array(&mp_pck, mk_list_size(config_map)); /* Adjust 'tls' default value based on plugin type" */ m = mk_list_entry_first(config_map, struct flb_config_map, _head); if (ins->p->flags & FLB_IO_TLS) { m->value.val.boolean = FLB_TRUE; } else if (ins->p->flags & FLB_IO_OPT_TLS) { m->value.val.boolean = FLB_FALSE; } mk_list_foreach(head, config_map) { m = mk_list_entry(head, struct flb_config_map, _head); pack_config_map_entry(&mp_pck, m); } flb_config_map_destroy(config_map); } flb_mp_map_header_end(&mh); *out_buf = mp_sbuf.data; *out_size = mp_sbuf.size; return 0; } static int build_plugin_help(struct flb_config *config, int type, char *name, char **out_buf, size_t *out_size) { void *help_buf = NULL; size_t help_size = 0; struct flb_custom_instance *c = NULL; struct flb_input_instance *i = NULL; struct flb_filter_instance *f = NULL; struct flb_output_instance *o = NULL; if (type == FLB_HELP_PLUGIN_CUSTOM) { c = flb_custom_new(config, name, NULL); if (!c) { fprintf(stderr, "invalid custom plugin '%s'", name); return -1; } flb_help_custom(c, &help_buf, &help_size); flb_custom_instance_destroy(c); } else if (type == FLB_HELP_PLUGIN_INPUT) { i = flb_input_new(config, name, 0, FLB_TRUE); if (!i) { fprintf(stderr, "invalid input plugin '%s'", name); return -1; } flb_help_input(i, &help_buf, &help_size); flb_input_instance_destroy(i); } else if (type == FLB_HELP_PLUGIN_FILTER) { f = flb_filter_new(config, name, 0); if (!f) { fprintf(stderr, "invalid filter plugin '%s'", name); return -1; } flb_help_filter(f, &help_buf, &help_size); flb_filter_instance_destroy(f); } else if (type == FLB_HELP_PLUGIN_OUTPUT) { o = flb_output_new(config, name, 0, FLB_TRUE); if (!o) { fprintf(stderr, "invalid output plugin '%s'", name); return -1; } flb_help_output(o, &help_buf, &help_size); flb_output_instance_destroy(o); } *out_buf = help_buf; *out_size = help_size; return 0; } static void pack_map_kv(msgpack_packer *mp_pck, char *key, char *val) { int k_len; int v_len; k_len = strlen(key); v_len = strlen(val); msgpack_pack_str(mp_pck, k_len); msgpack_pack_str_body(mp_pck, key, k_len); msgpack_pack_str(mp_pck, v_len); msgpack_pack_str_body(mp_pck, val, v_len); } flb_sds_t flb_help_build_json_schema(struct flb_config *config) { int ret; char *out_buf; flb_sds_t json; size_t out_size; struct mk_list *head; struct flb_custom_plugin *c; struct flb_input_plugin *i; struct flb_filter_plugin *f; struct flb_output_plugin *o; msgpack_sbuffer mp_sbuf; msgpack_packer mp_pck; struct flb_mp_map_header mh; /* initialize buffer */ msgpack_sbuffer_init(&mp_sbuf); msgpack_packer_init(&mp_pck, &mp_sbuf, msgpack_sbuffer_write); /* * Root map for entries: * * - fluent-bit * - customs * - inputs * - filters * - outputs */ msgpack_pack_map(&mp_pck, 5); /* Fluent Bit */ msgpack_pack_str(&mp_pck, 10); msgpack_pack_str_body(&mp_pck, "fluent-bit", 10); /* fluent-bit['version'], fluent-bit['help_version'] and fluent-bit['os'] */ msgpack_pack_map(&mp_pck, 3); pack_map_kv(&mp_pck, "version", FLB_VERSION_STR); pack_map_kv(&mp_pck, "schema_version", FLB_HELP_SCHEMA_VERSION); pack_map_kv(&mp_pck, "os", (char *) flb_utils_get_os_name()); /* customs */ msgpack_pack_str(&mp_pck, 7); msgpack_pack_str_body(&mp_pck, "customs", 7); flb_mp_array_header_init(&mh, &mp_pck); mk_list_foreach(head, &config->custom_plugins) { c = mk_list_entry(head, struct flb_custom_plugin, _head); ret = build_plugin_help(config, FLB_HELP_PLUGIN_CUSTOM, c->name, &out_buf, &out_size); if (ret == -1) { continue; } flb_mp_array_header_append(&mh); msgpack_sbuffer_write(&mp_sbuf, out_buf, out_size); flb_free(out_buf); } flb_mp_array_header_end(&mh); /* inputs */ msgpack_pack_str(&mp_pck, 6); msgpack_pack_str_body(&mp_pck, "inputs", 6); flb_mp_array_header_init(&mh, &mp_pck); mk_list_foreach(head, &config->in_plugins) { i = mk_list_entry(head, struct flb_input_plugin, _head); if (i->flags & FLB_INPUT_PRIVATE){ continue; } ret = build_plugin_help(config, FLB_HELP_PLUGIN_INPUT, i->name, &out_buf, &out_size); if (ret == -1) { continue; } flb_mp_array_header_append(&mh); msgpack_sbuffer_write(&mp_sbuf, out_buf, out_size); flb_free(out_buf); } flb_mp_array_header_end(&mh); /* filters */ msgpack_pack_str(&mp_pck, 7); msgpack_pack_str_body(&mp_pck, "filters", 7); flb_mp_array_header_init(&mh, &mp_pck); mk_list_foreach(head, &config->filter_plugins) { f = mk_list_entry(head, struct flb_filter_plugin, _head); ret = build_plugin_help(config, FLB_HELP_PLUGIN_FILTER, f->name, &out_buf, &out_size); if (ret == -1) { continue; } flb_mp_array_header_append(&mh); msgpack_sbuffer_write(&mp_sbuf, out_buf, out_size); flb_free(out_buf); } flb_mp_array_header_end(&mh); /* outputs */ msgpack_pack_str(&mp_pck, 7); msgpack_pack_str_body(&mp_pck, "outputs", 7); flb_mp_array_header_init(&mh, &mp_pck); mk_list_foreach(head, &config->out_plugins) { o = mk_list_entry(head, struct flb_output_plugin, _head); if (o->flags & FLB_OUTPUT_PRIVATE){ continue; } ret = build_plugin_help(config, FLB_HELP_PLUGIN_OUTPUT, o->name, &out_buf, &out_size); if (ret == -1) { continue; } flb_mp_array_header_append(&mh); msgpack_sbuffer_write(&mp_sbuf, out_buf, out_size); flb_free(out_buf); } flb_mp_array_header_end(&mh); json = flb_msgpack_raw_to_json_sds(mp_sbuf.data, mp_sbuf.size); msgpack_sbuffer_destroy(&mp_sbuf); return json; }