diff --git a/src/common/args.h b/src/common/args.h index d73d437cc16060c7f64215926dfeae906acb44a7..d9562ea312485d73ab793c56afb69c8faf59d492 100644 --- a/src/common/args.h +++ b/src/common/args.h @@ -14,7 +14,7 @@ ******************************************************************************/ #ifndef __GOPHER_ARGS_H__ #define __GOPHER_ARGS_H__ - +#include "../lib/base.h" #pragma once #define DEFAULT_PERIOD 60 @@ -57,6 +57,11 @@ copy struct probe_params code to python.probe/ipc.py. if modify struct probe_params, please sync change to the class ProbeParams in ipc.py */ +struct custom_params { + char label[MAX_CUSTOM_PARAMS_LEN]; + char value[MAX_CUSTOM_PARAMS_LEN]; +}; + struct probe_params { unsigned int period; // Report period, unit second, default is 5 seconds unsigned int sample_period; // Sampling period, unit milliseconds, default is 100 milliseconds @@ -96,6 +101,8 @@ struct probe_params { char svg_dir[PATH_LEN]; char flame_dir[PATH_LEN]; unsigned int cadvisor_port; // the port which cadvisor start. + struct custom_params custom_param[MAX_CUSTOM_NUM]; + unsigned int params_num; }; diff --git a/src/common/ipc.c b/src/common/ipc.c index 946c9ecf0c6a9bd66e7ae24290fa4348c791a2d5..e62dd9c0319ed24dadfc4df7651d9e2055f6ea3e 100644 --- a/src/common/ipc.c +++ b/src/common/ipc.c @@ -708,7 +708,7 @@ int send_ipc_msg(int msqid, long msg_type, struct ipc_body_s* ipc_body) return -1; } - if (msg_type < PROBE_BASEINFO || msg_type >= PROBE_TYPE_MAX) { + if (msg_type < PROBE_BASEINFO || msg_type == PROBE_TYPE_MAX || msg_type > (MAX_CUSTOM_NUM + PROBE_TYPE_MAX)) { return -1; } diff --git a/src/common/ipc.h b/src/common/ipc.h index 889791c043c04d8c6cae342edc9a45f59a517643..75474610254effd5fb143cd714ac1c87dffe3b1b 100644 --- a/src/common/ipc.h +++ b/src/common/ipc.h @@ -198,7 +198,7 @@ enum probe_type_e { PROBE_FLOWTRACER, // If you want to add a probe, add the probe type. - + PROBE_EXTERN, PROBE_TYPE_MAX }; @@ -224,12 +224,18 @@ struct snooper_obj_s { } obj; }; +struct custom_subprobes { + char subprobe[MAX_SUBPEOBE_NUM][MAX_CUSTOM_NAME_LEN]; + u32 subprobe_num; +}; + #define IPC_FLAGS_SNOOPER_CHG 0x00000001 #define IPC_FLAGS_PARAMS_CHG 0x00000002 struct ipc_body_s { u32 probe_range_flags; // Refer to flags defined [PROBE_RANGE_XX_XX] u32 snooper_obj_num; u32 probe_flags; + struct custom_subprobes *custom; struct probe_params probe_param; struct snooper_obj_s snooper_objs[SNOOPER_MAX]; }; diff --git a/src/lib/base.h b/src/lib/base.h index fcf56e63f95690144da973277ebe5f078683eb11..c9af979005bbd4d5475c721663c2c82c6eb4d214 100644 --- a/src/lib/base.h +++ b/src/lib/base.h @@ -60,6 +60,17 @@ // probe config #define MAX_PROBE_NAME_LEN 32 +// custom config +#define MAX_CUSTOM_NAME_LEN 64 +#define MAX_BIN_LEN 100 +#define MAX_SUBPEOBE_NUM 8 +#define MAX_CUSTOM_NUM (8 + 1) //The subscript of custom starts from 1. +#define MAX_CUSTOM_PARAMS_LEN 64 +#define MAX_CUSTOM_PARAMS_NUM 8 +#define MAX_PRIVILEGE_LEN 8 +#define MAX_CUSTOM_CONFIG (2048 * 2048 * 10) +#define MAX_RESTART_TIMES 10 + // extend probe config #define MAX_EXTEND_PROBE_COMMAND_LEN 128 #define MAX_PARAM_LEN 128 @@ -99,6 +110,8 @@ typedef enum { #define GALA_GOPHER_RUN_DIR "/var/run/gala_gopher/" #define GALA_GOPHER_CMD_SOCK_PATH "/var/run/gala_gopher/gala_gopher_cmd.sock" #define GALA_GOPHER_RUN_DIR_MODE 0750 +/* custom probe json path */ +#define GALA_GOPHER_CUSTOM_PATH "/opt/gala-gopher/custom/custom.json" #endif diff --git a/src/lib/http_server/http_server.c b/src/lib/http_server/http_server.c index 29afa779cd01f15dd16603409a1cb67dda548426..70c2d5758489c5421ea6b95456188a3bccb5db5d 100644 --- a/src/lib/http_server/http_server.c +++ b/src/lib/http_server/http_server.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "http_server.h" @@ -44,6 +45,17 @@ static struct bufferevent* http_server_bevcb_nossl(struct event_base *evbase, vo return bufferevent_socket_new(evbase, -1, BEV_OPT_CLOSE_ON_FREE); } +static void get_current_time(char *buffer) +{ + time_t rawtime; + struct tm * timeinfo; + + time(&rawtime); + timeinfo = localtime(&rawtime); + strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", timeinfo); + return; +} + void http_server_reply_code(struct evhttp_request *req, int errorno) { evhttp_send_reply(req, errorno, NULL, NULL); @@ -51,12 +63,15 @@ void http_server_reply_code(struct evhttp_request *req, int errorno) void http_server_reply_message(struct evhttp_request *req, int resp_code, const char* message) { + char buffer[20] = {0}; struct evbuffer *evbuffer; char buf[HTTP_REPLY_MSG_LEN] = {0}; if (resp_code == HTTP_OK) { (void)snprintf(buf, sizeof(buf), "{ \"result\": \"success\", \"message\":\"%s\" }\n", message); + get_current_time(buffer); + INFO("Probe start time is %s.", buffer); } else { (void)snprintf(buf, sizeof(buf), "{ \"result\": \"failed\", \"message\":\"%s\" }\n", message); } diff --git a/src/lib/probe/extend_probe.c b/src/lib/probe/extend_probe.c index a51832b62d903b92da7ce931135a9428698f96bd..51fab0a64ce90debadb5d058b47b52e1cf443bb9 100644 --- a/src/lib/probe/extend_probe.c +++ b/src/lib/probe/extend_probe.c @@ -31,7 +31,11 @@ static FILE* __DoRunExtProbe(const struct probe_s *probe) FILE *f = NULL; command[0] = 0; - (void)snprintf(command, MAX_COMMAND_LEN - 1, "%s", probe->bin); + if (probe->probe_type == PROBE_EXTERN && strcmp(probe->custom.privilege, "True") == 0) { + (void)snprintf(command, MAX_COMMAND_LEN - 1, "sudo %s", probe->bin); + } else { + (void)snprintf(command, MAX_COMMAND_LEN - 1, "%s", probe->bin); + } repeat: f = popen(command, "r"); if (feof(f) != 0 || ferror(f) != 0) { diff --git a/src/lib/probe/probe_mng.c b/src/lib/probe/probe_mng.c index c3ef88e5ff4f7961b9e0ba2ff437fba6aa8211c2..5b556f51be4e34b7f3e88e6985d855afa415f40d 100644 --- a/src/lib/probe/probe_mng.c +++ b/src/lib/probe/probe_mng.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "ipc.h" #include "pod_mng.h" @@ -62,6 +63,13 @@ struct probe_define_s probe_define[] = { // If you want to add a probe, add the probe define. }; +struct probe_threshold_verify verify[] = { + {"name", MAX_CUSTOM_NAME_LEN}, + {"bin", MAX_BIN_LEN}, + {"probe_num", MAX_SUBPEOBE_NUM}, + {"param", MAX_CUSTOM_PARAMS_LEN} +}; + struct probe_range_define_s { enum probe_type_e probe_type; char *desc; @@ -184,6 +192,21 @@ static int check_probe_range(struct probe_s *probe) return 0; } +int check_custom_range(const char *key, const char *comp) +{ + int size = sizeof(verify) / sizeof(struct probe_threshold_verify); + + for (int i = 0; i < size; i++) { + if (strcmp(verify[i].name, comp) != 0) { + continue; + } + if (strlen(key) > verify[i].max) { + return -1; + } + } + return 0; +} + static int check_probe_snooper_conf_num(struct probe_s *probe) { if (probe->snooper_conf_num == 0 && (!strcmp(probe->name, "tcp") || @@ -195,6 +218,7 @@ static int check_probe_snooper_conf_num(struct probe_s *probe) } static struct probe_mng_s *g_probe_mng; +static struct custom_ini *g_custom_ini; char g_parse_json_err[PARSE_JSON_ERR_STR_LEN]; @@ -281,6 +305,10 @@ static int attach_probe_fd(struct probe_mng_s *probe_mng, struct probe_s *probe) static void detach_probe_fd(struct probe_mng_s *probe_mng, struct probe_s *probe) { struct epoll_event event; + if (probe_mng == NULL || probe == NULL) { + return; + } + if (probe_mng->ingress_epoll_fd < 0 || probe->fifo == NULL) { return; } @@ -434,7 +462,11 @@ static void init_probe_bin(struct probe_s *probe, enum probe_type_e probe_type) return; } - probe->bin = strdup(probe_define[probe_type - 1].bin); + if (probe_type != PROBE_EXTERN) { + probe->bin = strdup(probe_define[probe_type - 1].bin); + } else { + probe->bin = strdup("/extern"); + } if (is_extend_probe(probe)) { probe->is_extend_probe = 1; @@ -527,7 +559,7 @@ static int try_start_probe(struct probe_s *probe) probe->probe_status.status_flags |= PROBE_FLAGS_RUNNING; probe->probe_status.status_flags &= ~(PROBE_FLAGS_STOPPED); (void)pthread_rwlock_unlock(&probe->rwlock); - probe->resnd_snooper_for_restart = 1; // must be reset when start ends + probe->resnd_snooper_for_restart += 1; // must be reset when start ends return 0; } @@ -612,37 +644,117 @@ static enum probe_type_e get_probe_type_by_name(const char *probe_name) return probe_define[i].type; } } + + for (size_t i = 1; i <= g_custom_ini->custom_num; i++) { + if (!strcmp(g_custom_ini->custom[i]->name, probe_name)) { + INFO("External probe name.\r\n"); + return PROBE_EXTERN; + } + } + PARSE_ERR("invalid probe name"); return PROBE_TYPE_MAX; } +/* Pass the parameters of the init custom probe record to the currently probe. */ +static int information_transfer(struct probe_s *custom, struct probe_s *probe) +{ + char *bin; + int size; + + /* Transfer the bin, privilege, subprobe, params information in the JSON file. */ + bin = custom->bin; + probe->bin = strdup(bin); + + strcpy(probe->custom.privilege, custom->custom.privilege); + + size = custom->custom.custom_subprobe.subprobe_num; + for (int i = 0; i < size; i++) { + strcpy(probe->custom.custom_subprobe.subprobe[i], custom->custom.custom_subprobe.subprobe[i]); + } + probe->custom.custom_subprobe.subprobe_num = size; + + size = custom->custom.params_num; + for (int i = 0; i < size; i++) { + strcpy(probe->probe_param.custom_param[i].label, custom->custom.custom_params[i]); + } + probe->probe_param.params_num = size; + probe->custom.index = custom->custom.index; + + return 0; +} + +static int find_custom_ini(struct probe_s *probe) { + u32 num = g_custom_ini->custom_num; + int ret; + + for (int i = 0; i <= num; i++) { + if ((g_custom_ini->custom[i] != NULL) && (strcmp(g_custom_ini->custom[i]->name, probe->name)) == 0) { + ret = information_transfer(g_custom_ini->custom[i], probe); + return ret; + } + } + return -1; +} + static struct probe_s *get_probe_by_name(const char *probe_name) { enum probe_type_e probe_type = get_probe_type_by_name(probe_name); + u32 custom_index = g_probe_mng->custom_index; + if (probe_type >= PROBE_TYPE_MAX) { return NULL; } - if (g_probe_mng->probes[probe_type]) { + if (probe_type == PROBE_EXTERN) { + for (size_t i = 1; i <= custom_index; i++) { + if (strcmp(probe_name, g_probe_mng->custom[i]->name) == 0) { + return g_probe_mng->custom[i]; + } + } + custom_index++; + if (custom_index >= MAX_CUSTOM_NUM) { + PARSE_ERR("The number of external probes has over the threshold."); + return NULL; + } + g_probe_mng->custom[custom_index] = new_probe(probe_name, PROBE_EXTERN); + if (g_probe_mng->custom[custom_index] != NULL && !find_custom_ini(g_probe_mng->custom[custom_index])) { + g_probe_mng->custom_index = custom_index; + } + return g_probe_mng->custom[custom_index]; + } else { + if (g_probe_mng->probes[probe_type]) { + return g_probe_mng->probes[probe_type]; + } + + g_probe_mng->probes[probe_type] = new_probe(probe_name, probe_type); return g_probe_mng->probes[probe_type]; } - - g_probe_mng->probes[probe_type] = new_probe(probe_name, probe_type); - return g_probe_mng->probes[probe_type]; } static void probe_printer_cmd(struct probe_s *probe, void *json) { void *range; Json_AddStringToObject(json, "bin", probe->bin ? :""); - - size_t size = sizeof(probe_range_define) / sizeof(struct probe_range_define_s); + size_t size = 0; range = Json_CreateArray(); - for (size_t i = 0; i < size; i++) { - if (probe->probe_type == probe_range_define[i].probe_type) { - if (probe->probe_range_flags & probe_range_define[i].flags) { - Json_AddStringItemToArray(range, probe_range_define[i].desc); + if (probe->probe_type == PROBE_EXTERN) { + size = probe->custom.custom_subprobe.subprobe_num; + + for (size_t i = 0; i < size; i++) { + if (probe->custom.custom_subprobe.subprobe[i] != NULL) { + Json_AddStringItemToArray(range, probe->custom.custom_subprobe.subprobe[i]); + } + } + } else { + size = sizeof(probe_range_define) / sizeof(struct probe_range_define_s); + + for (size_t i = 0; i < size; i++) { + if (probe->probe_type == probe_range_define[i].probe_type) { + if (probe->probe_range_flags & probe_range_define[i].flags) { + Json_AddStringItemToArray(range, probe_range_define[i].desc); + } } } } @@ -653,7 +765,7 @@ static void probe_printer_cmd(struct probe_s *probe, void *json) /* {"probe":["XX","YY"]} , XX must be string and must be in supported probe range*/ static int probe_parser_range(struct probe_s *probe, void *probe_item) { - int range; + int range = 0; void *object; probe->probe_range_flags = 0; @@ -664,26 +776,136 @@ static int probe_parser_range(struct probe_s *probe, void *probe_item) PARSE_ERR("invalid probe range: must be string"); return -1; } - - range = get_probe_range(probe->probe_type, (const char*)Json_GetValueString(object)); - if (!range) { - PARSE_ERR("unsupported probe range: %s", (const char*)Json_GetValueString(object)); + if (check_custom_range((char *)Json_GetValueString(object), "name")) { + ERROR("The lengh of probe name must less than 64.\r\n"); return -1; } + + if (strcmp(probe->bin, "/extern") == 0) { + if (size > MAX_SUBPEOBE_NUM) { + ERROR("[CUSTOM INI]The number of subprobe must less than 8.\r\n"); + return -1; + } + strcpy(probe->custom.custom_subprobe.subprobe[i], (char *)Json_GetValueString(object)); + INFO("The %d subprobe name is %s\r\n", i, probe->custom.custom_subprobe.subprobe[i]); + (probe->custom.custom_subprobe.subprobe_num)++; + } else if (probe->probe_type == PROBE_EXTERN) { + for (int j = 0; j < probe->custom.custom_subprobe.subprobe_num; j++) { + if (strcmp((char *)Json_GetValueString(object), probe->custom.custom_subprobe.subprobe[j]) == 0) { + break; + } + if (j == probe->custom.custom_subprobe.subprobe_num - 1) { + PARSE_ERR("[Custom]invalid external probe range: subprobe name error.\r\n"); + return -1; + } + } + } else { + range = get_probe_range(probe->probe_type, (const char*)Json_GetValueString(object)); + if (!range) { + PARSE_ERR("unsupported probe range: %s.\r\n", (const char*)Json_GetValueString(object)); + return -1; + } + } probe->probe_range_flags |= (u32)range; } return check_probe_range(probe); } +static int is_privalige_valid(char *privalige) { + if (privalige == NULL || strlen(privalige) == 0) { + ERROR("[Custom ini]:Privalige must not be NULL.\r\n"); + return -1; + } + + if (strcmp(privalige, "True") != 0 && strcmp(privalige, "False") != 0) { + ERROR("[Custom ini]:Privalige must be True or False.\r\n"); + return -1; + } + + return 0; +} + +static char *probe_extern_cmd_param(const char *key, const void *item) +{ + void *probe_object; + + probe_object = Json_GetObjectItem(item, key); + if (probe_object == NULL && !Json_IsString(probe_object)) { + PARSE_ERR("invalid probe range: must be string and not null.\r\n"); + return NULL; + } + return (char *)Json_GetValueString(probe_object); +} + +static int custom_params_ini(struct probe_s *probe, char *param) { + char *ptr = NULL; + int count = 0; + + if (param == NULL) { + return -1; + } + ptr = strtok(param, ","); + while (ptr != NULL) { + if (count == MAX_CUSTOM_PARAMS_NUM) { + ERROR("[CUSTOM INI]The number of custom params must less than 8.\r\n"); + return -1; + } + if (check_custom_range(ptr, "param")) { + ERROR("[CUSTOM INI]The length of custom params must less than 64.\r\n"); + return -1; + } + strcpy(probe->custom.custom_params[count], ptr); + INFO("The NO.%d param is %s.\r\n", count, ptr); + count++; + ptr = strtok(NULL, ","); + } + probe->custom.params_num = count; + return 0; +} + static int probe_parser_cmd(struct probe_s *probe, const void *item) { int ret = 0; void *probe_object; probe_object = Json_GetObjectItem(item, "probe"); - if (probe_object != NULL) { - ret = probe_parser_range(probe, probe_object); + if (probe_object == NULL) { + ERROR("[Custom ini]:Faild get probe params from json.\r\n"); + return -1; + } + ret = probe_parser_range(probe, probe_object); + if (ret) { + PARSE_ERR("invalid range type."); + return ret; + } + + /* Custom probe dedicated, there are tow scenarios.*/ + if (strcmp(probe->bin, "/extern") == 0) { + free(probe->bin); + probe->bin = NULL; + probe->bin = strdup(probe_extern_cmd_param("bin", item)); + INFO("Custom path is : %s\r\n", probe->bin); + if (check_custom_range(probe->bin, "bin")) { + ERROR("[Custom ini]:The length of bin must be less than 100.\r\n"); + return -1; + } + + strcpy(probe->custom.privilege, probe_extern_cmd_param("privalige", item)); + ret = is_privalige_valid(probe->custom.privilege); + INFO("The privalige of custom is %s.\r\n", probe->custom.privilege); + ret |= custom_params_ini(probe, probe_extern_cmd_param("custom_param", item)); + if (probe->bin == NULL || ret) { + ERROR("[Custom ini]invalid json type, check privalige and custom params.\r\n"); + return -1; + } + } else if (probe->probe_type == PROBE_EXTERN) { + ret = strcmp(probe->bin, probe_extern_cmd_param("bin", item)); + ret += abs(strcmp(probe->custom.privilege, probe_extern_cmd_param("privalige", item))); + if (ret > 0) { + PARSE_ERR("invalid probe range: parms transferred by curl has error.\r\n"); + return -1; + } } return ret; @@ -969,11 +1191,10 @@ int parse_probe_json(const char *probe_name, const char *probe_content) goto end; } - probe_backup = (struct probe_s *)malloc(sizeof(struct probe_s)); + probe_backup = (struct probe_s *)calloc(1, sizeof(struct probe_s)); if (probe_backup == NULL) { goto end; } - (void)memset(probe_backup, 0, sizeof(struct probe_s)); size_t size = sizeof(probe_parsers) / sizeof(struct probe_parser_s); for (size_t i = 0; i < size; i++) { @@ -1023,7 +1244,7 @@ char *get_probe_json(const char *probe_name) { void *res = NULL, *item; char *buf = NULL; - struct probe_s *probe; + struct probe_s *probe = NULL; struct probe_parser_s *parser; get_probemng_lock(); @@ -1034,7 +1255,19 @@ char *get_probe_json(const char *probe_name) } res = Json_CreateObject(); - probe = g_probe_mng->probes[probe_type]; + if (probe_type == PROBE_EXTERN) { + for (int i = 1; i <= g_probe_mng->custom_index; i++) { + if (strcmp(g_probe_mng->custom[i]->name, probe_name) == 0) { + probe = g_probe_mng->custom[i]; + break; + } + if (i == (g_probe_mng->custom_index) - 1) { + goto end; + } + } + } else { + probe = g_probe_mng->probes[probe_type]; + } if (probe == NULL) { goto end; } @@ -1073,7 +1306,7 @@ void destroy_probe_threads(void) struct probe_s *probe = g_probe_mng->probes[i]; if (probe != NULL) { stop_probe(probe); - INFO("[PROBE_MNG] Probe %s is stopped\n", probe->name); + INFO("[PROBE_MNG] Probe %s is stopped.\r\n", probe->name); } } } @@ -1100,6 +1333,233 @@ void destroy_probe_mng(void) del_pods(); } +void destroy_custom_ini(void) +{ + struct probe_s *probe; + + if (g_custom_ini == NULL) { + return; + } + for (int i = 0; i < g_custom_ini->custom_num; i++) { + probe = g_custom_ini->custom[i]; + if (probe == NULL) { + continue; + } + stop_probe(probe); + INFO("[CUSTOM INI]Probe %s is stopped\r\n", probe->name); + destroy_probe(g_custom_ini->custom[i]); + g_custom_ini->custom[i] = NULL; + } + free(g_custom_ini); + g_custom_ini = NULL; +} + +static struct probe_s* new_costom(const char* name, const u32 custom_index) +{ + struct probe_s *probe = NULL; + + probe = (struct probe_s *)calloc(1, sizeof(struct probe_s)); + if (probe == NULL) { + ERROR("Probe memory allocation failure.\r\n"); + return NULL; + } + + probe->name = strdup(name); + probe->probe_type = PROBE_EXTERN; + probe->custom.index = custom_index; + probe->bin = strdup("/extern"); + set_default_params(probe); + + return probe; +} + +static struct probe_s *creare_custom_by_name(char *name) +{ + u32 custom_index = g_custom_ini->custom_num; + + if (check_custom_range(name, "name")) { + ERROR("[CUSTOM INIT]The length of custom name has out of range, it must less than 100.\r\n"); + return NULL; + } + custom_index++; + if (custom_index >= MAX_CUSTOM_NUM) { + ERROR("[CUSTOM INIT]The number of custom probes has over the threshold.\r\n"); + return NULL; + } + g_custom_ini->custom[custom_index] = new_costom(name, custom_index); + if (g_custom_ini->custom[custom_index] != NULL) { + g_custom_ini->custom_num = custom_index; + } + return g_custom_ini->custom[custom_index]; +} +/* Read data from a file*/ +static int file_handle(const char *file, char *data) +{ + FILE *fp; + u32 fsize; + + fp = fopen(file, "r"); + if (fp == NULL) { + ERROR("[CUSTOM INI]Unable to open file.\r\n"); + return -1; + } + fseek(fp, 0, SEEK_END); + fsize = ftell(fp); + fseek(fp, 0, SEEK_SET); + fread(data, 1, fsize, fp); + fclose(fp); + data[fsize] = '\0'; + return 0; +} + +static int init_custom_probe(const char* data) +{ + void *json_obj = NULL; + void *item_obj = NULL; + struct key_value_pairs *kv_pairs; + struct key_value *kv; + struct probe_s *probe; + struct probe_parser_s *parser; + + json_obj = Json_Parse(data); + if (json_obj == NULL) { + ERROR("[CUSTOM INI]invalid json format.\r\n"); + return -1; + } + + kv_pairs = Json_GetKeyValuePairs(json_obj); + if (!kv_pairs) { + ERROR("[CUSTOM INI]invalid json param pairs.\r\n"); + return -1; + } + Json_ArrayForEach(kv, kv_pairs) { + probe = creare_custom_by_name(kv->key); + if (probe == NULL) { + ERROR("[CUSTOM INI]Failed to initialize the custom with name.\r\n"); + return -1; + } + + item_obj = Json_GetObjectItem(kv->valuePtr, "cmd"); + if (item_obj == NULL) { + continue; + } + parser = &(probe_parsers[0]); + if (parser->parser(probe, item_obj)) { + return -1; + } + } + return 0; +} + +static int init_custom(const char *custom_path) +{ + char *json_data; + int ret; + + json_data = calloc(1, MAX_CUSTOM_CONFIG + 1); + if (json_data == NULL) { + ERROR("[CUSTOM INI]Custom memory allocation error\r\n"); + return -1; + } + ret = file_handle(custom_path, json_data); + if (ret) { + free(json_data); + return ret; + } + + ret = init_custom_probe(json_data); + free(json_data); + if (ret) { + return ret; + } + + return 0; +} + +static int get_dir_from_bin(char *bin) { + char *ptr = strrchr(bin, '/'); + + if (ptr != NULL) { + *ptr = '\0'; + INFO("meta path is %s.\r\n", bin); + return 0; + } + ERROR("bin type from Json ERROR, please check!\r\n"); + return -1; +} + +static int copy_single_meta(const char *sourcedir, const char *desdir) +{ + DIR *dir; + struct dirent *entry; + char sourcefile[MAX_BIN_LEN], desfile[MAX_BIN_LEN], buff[MAX_BIN_LEN]; + FILE *source_file, *dest_file; + + dir = opendir(sourcedir); + if (dir == NULL) { + ERROR("Unable to open meta source directory."); + return -1; + } + while ((entry = readdir(dir)) != NULL) { + if (strstr(entry->d_name, ".meta") == NULL) { + continue; + } + sprintf(sourcefile, "%s/%s", sourcedir, entry->d_name); + sprintf(desfile, "%s/%s", desdir, entry->d_name); + source_file = fopen(sourcefile, "r"); + dest_file = fopen(desfile, "w"); + + while (fgets(buff, MAX_BIN_LEN, source_file) != NULL) { + fputs(buff, dest_file); + } + fclose(source_file); + fclose(dest_file); + } + closedir(dir); + return 0; +} + +static int init_meta() +{ + char source_dir[MAX_BIN_LEN]; + + size_t size = g_custom_ini->custom_num; + int ret; + + for (size_t i = 1; i <= size; i++) { + if (g_custom_ini->custom[i]->bin == NULL) { + continue; + } + strcpy(source_dir, g_custom_ini->custom[i]->bin); + ret = get_dir_from_bin(source_dir); + ret |= copy_single_meta(source_dir, GALA_META_DIR_PATH); + if (ret) { + return ret; + } + } + return 0; +} + +static int verify_permissions() +{ + struct stat st; + int size = g_custom_ini->custom_num; + + for (int i = 1; i <= size; i++) { + if (stat(g_custom_ini->custom[i]->bin, &st)) { + return -1; + } + + if (((st.st_mode & S_IRWXU) == (S_IRUSR | S_IXUSR)) && ((st.st_mode & S_IRWXG) == (S_IRGRP | S_IXGRP)) && ((st.st_mode & S_IRWXO) == 0)) { + continue; + } else { + ERROR("%s has permission error.\r\n", g_custom_ini->custom[i]->bin); + return -1; + } + } + return 0; +} + struct probe_mng_s *create_probe_mng(void) { int msq_id; @@ -1135,13 +1595,51 @@ struct probe_mng_s *create_probe_mng(void) g_probe_mng->keeplive_ts = (time_t)time(NULL); + g_custom_ini = (struct custom_ini *)calloc(1, sizeof(struct custom_ini)); + if (g_custom_ini == NULL) { + return NULL; + } + ret = init_custom(GALA_GOPHER_CUSTOM_PATH); + if (ret) { + goto err; + } + ret = init_meta(); + if (ret) { + goto err; + } + ret = verify_permissions(); + if (ret) { + goto err; + } return g_probe_mng; err: destroy_probe_mng(); + destroy_custom_ini(); return NULL; } +#define __PROBE_KEEPLIVE_TIMEOUT (60) // 60 Seconds +static int is_start_today(const struct probe_mng_s *probe_mng, char *restart) +{ + time_t time = probe_mng->keeplive_ts; + struct tm *tm_now, *tm_before; + + tm_now = localtime(&time); + time -= __PROBE_KEEPLIVE_TIMEOUT; + tm_before = localtime(&time); + if (*restart <= MAX_RESTART_TIMES) { + return 1; + } + + if (tm_now->tm_mday == tm_before->tm_mday) { + return 0; + } else { + *restart = 0; + return 1; + } +} + static void keeplive_probes(struct probe_mng_s *probe_mng) { struct probe_s *probe; @@ -1159,9 +1657,21 @@ static void keeplive_probes(struct probe_mng_s *probe_mng) probe->resnd_snooper_for_restart = 0; } } + + for (int i = 1; i <= probe_mng->custom_index; i++) { + probe = probe_mng->custom[i]; + if (probe == NULL) { + continue; + } + + if (try_start_probe(probe) == 0 && is_start_today(probe_mng, &probe->resnd_snooper_for_restart) ) { + probe->is_params_chg = 0; + probe->is_snooper_chg = 0; + (void)send_snooper_obj(probe); + } + } } -#define __PROBE_KEEPLIVE_TIMEOUT (60) // 60 Seconds static char is_keeplive_tmout(struct probe_mng_s *probe_mng) { time_t current = (time_t)time(NULL); diff --git a/src/lib/probe/probe_mng.h b/src/lib/probe/probe_mng.h index b95e99f22d93fc890512a763215a4c5f7e466e6c..6a507f5fe7c4a553b4b90e73cfe082c244d5bbe9 100644 --- a/src/lib/probe/probe_mng.h +++ b/src/lib/probe/probe_mng.h @@ -45,6 +45,11 @@ struct probe_define_s { char enable; }; +struct probe_threshold_verify { + char *name; + u32 max; +}; + typedef int (*ParseParam)(const char*, struct probe_params *); struct param_define_s { char *desc; @@ -55,6 +60,19 @@ struct probe_status_s { u32 status_flags; // Refer to flags defined [PROBE_FLAGS_XXX] }; +struct custom { + u32 index; + char privilege[MAX_PRIVILEGE_LEN]; + char custom_params[MAX_CUSTOM_PARAMS_NUM][MAX_CUSTOM_PARAMS_LEN]; + u32 params_num; + struct custom_subprobes custom_subprobe; +}; + +struct custom_ini { + struct probe_s *custom[MAX_CUSTOM_NUM]; //The probe number starts from subscript 1. + u32 custom_num; +}; + struct probe_s; typedef int (*ProbeMain)(struct probe_s *); typedef void *(*ProbeCB)(void *); @@ -67,6 +85,7 @@ struct probe_s { char resnd_snooper_for_restart; // Need to resend snooper obj after probe is restarted u8 snooper_type; // Specify the type of snoopers that one probe really concern */ enum probe_type_e probe_type; + struct custom custom; // User-defined probe u32 probe_range_flags; // Refer to flags defined [PROBE_RANGE_XX_XX] ProbeMain probe_entry; // Main function for native probe ProbeCB cb; // Thread cb for probe @@ -88,6 +107,8 @@ struct probe_s { struct probe_mng_s { int msq_id; // ipc control msg channel struct probe_s *probes[PROBE_TYPE_MAX]; + struct probe_s *custom[MAX_CUSTOM_NUM]; //Used to manage external probes. + u32 custom_index; //Used to define external probes index. void *snooper_skel; const char *btf_custom_path; void *snooper_proc_pb; // context in perf event @@ -112,10 +133,12 @@ int parse_probe_json(const char *probe_name, const char *probe_content); char *get_probe_json(const char *probe_name); struct probe_mng_s *create_probe_mng(void); void destroy_probe_mng(void); +void destroy_custom_ini(void); void destroy_probe_threads(void); u32 get_probe_status_flags(struct probe_s* probe); void set_probe_status_stopped(struct probe_s* probe); void set_probe_pid(struct probe_s *probe, int pid); +int check_custom_range(const char *key, const char *comp); #define IS_STOPPED_PROBE(probe) (get_probe_status_flags(probe) & PROBE_FLAGS_STOPPED) #define IS_STARTED_PROBE(probe) (get_probe_status_flags(probe) & PROBE_FLAGS_STARTED) diff --git a/src/lib/probe/probe_params_parser.c b/src/lib/probe/probe_params_parser.c index 3c3efdfeaed6e70a894292d5c3eee334da388b2c..7399cdcd50d60770e2dc72a08bddbe6b1aa72a71 100644 --- a/src/lib/probe/probe_params_parser.c +++ b/src/lib/probe/probe_params_parser.c @@ -419,6 +419,41 @@ static int parser_cadvisor_port(struct probe_s *probe, const struct param_key_s return 0; } +static int parser_custom_param(struct probe_s *probe, const struct param_key_s *param_key, const void *key_item) +{ + void *obj = NULL; + int size = Json_GetArraySize(key_item); + int custom_size = probe->probe_param.params_num; + struct key_value_pairs *kv; + + for (int i = 0; i < size; i++) { + obj = Json_GetArrayItem(key_item, i); + if (obj == NULL) { + PARSE_ERR("Get custom params from json error"); + return -1; + } + kv = Json_GetKeyValuePairs(obj); + if (kv == NULL) { + PARSE_ERR("Custom params parsed error"); + return -1; + } + for (int j = 0; j < custom_size; j++) { + if (strcmp(probe->probe_param.custom_param[j].label, kv->kv_pairs->key) == 0) { + if (!Json_IsString(kv->kv_pairs->valuePtr)) { + PARSE_ERR("Curl params parsed error"); + return -1; + } + if (check_custom_range((char *)Json_GetValueString(kv->kv_pairs->valuePtr), "param")) { + PARSE_ERR("param value must less than 64."); + return -1; + } + strcpy(probe->probe_param.custom_param[j].value, (char *)Json_GetValueString(kv->kv_pairs->valuePtr)); + } + } + } + return 0; +} + #define SET_DEFAULT_PARAMS_INTER(field) \ static void set_default_params_inter_##field(struct probe_params *params, const struct param_val_s *value) \ { \ @@ -484,6 +519,7 @@ SET_DEFAULT_PARAMS_STR(flame_dir); #define ELF_PATH "elf_path" #define KAFKA_PORT "kafka_port" #define CADVISOR_PORT "cadvisor_port" +#define CUSTOM_PARAMS "custom_param" struct param_key_s param_keys[] = { {SAMPLE_PERIOD, {DEFAULT_SAMPLE_PERIOD, 100, 10000, ""}, parser_sample_peirod, set_default_params_inter_sample_period, JSON_NUMBER}, @@ -511,7 +547,8 @@ struct param_key_s param_keys[] = { {CONTINUOUS_SAMPLING, {0, 0, 1, ""}, parser_continuous_sampling, set_default_params_char_continuous_sampling_flag, JSON_NUMBER}, {ELF_PATH, {0, 0, 0, ""}, parser_elf_path, NULL, JSON_STRING}, {KAFKA_PORT, {DEFAULT_KAFKA_PORT, 1, 65535, ""}, parser_kafka_port, set_default_params_inter_kafka_port, JSON_NUMBER}, - {CADVISOR_PORT, {DEFAULT_CADVISOR_PORT, 1, 65535, ""}, parser_cadvisor_port, set_default_params_inter_cadvisor_port, JSON_NUMBER} + {CADVISOR_PORT, {DEFAULT_CADVISOR_PORT, 1, 65535, ""}, parser_cadvisor_port, set_default_params_inter_cadvisor_port, JSON_NUMBER}, + {CUSTOM_PARAMS, {0, 0, 0, ""}, parser_custom_param, NULL,JSON_ARRAY} }; void set_default_params(struct probe_s *probe) @@ -572,15 +609,28 @@ static void *param_flags_to_json(unsigned int flags, struct param_flags_s param_ return arr; } +static void *param_custom_to_json(struct custom_params *custom_param, size_t size) +{ + void *item = Json_CreateObject(); + + for (size_t i = 0; i < size; i++) { + if (custom_param[i].label == NULL || custom_param[i].value == NULL) { + continue; + } + Json_AddStringToObject(item, custom_param[i].label, custom_param[i].value); + } + return item; +} + void probe_params_to_json(struct probe_s *probe, void *params) { struct probe_params *probe_param = &probe->probe_param; enum probe_type_e probe_type = probe->probe_type; - void *flags_arr; - size_t flags_size; + void *arr; + size_t size; Json_AddUIntItemToObject(params, REPORT_PERIOD, probe_param->period); - if (probe_type == PROBE_IO || probe_type == PROBE_TCP) { + if (probe_type == PROBE_IO || probe_type == PROBE_EXTERN || probe_type == PROBE_TCP) { Json_AddUIntItemToObject(params, SAMPLE_PERIOD, probe_param->sample_period); } #ifdef ENABLE_REPORT_EVENT @@ -601,20 +651,20 @@ void probe_params_to_json(struct probe_s *probe, void *params) } #endif - if (probe_type == PROBE_L7) { - flags_size = sizeof(param_l7pro_flags) / sizeof(param_l7pro_flags[0]); - flags_arr = param_flags_to_json(probe_param->l7_probe_proto_flags, param_l7pro_flags, flags_size); - Json_AddItemToObject(params, L7_PROTOCOL, flags_arr); - Json_Delete(flags_arr); + if (probe_type == PROBE_EXTERN || probe_type == PROBE_L7 ) { + size = sizeof(param_l7pro_flags) / sizeof(param_l7pro_flags[0]); + arr = param_flags_to_json(probe_param->l7_probe_proto_flags, param_l7pro_flags, size); + Json_AddItemToObject(params, L7_PROTOCOL, arr); + Json_Delete(arr); Json_AddCharItemToObject(params, SUPPORT_SSL, probe_param->support_ssl); } - if (probe_type == PROBE_L7 || probe_type == PROBE_TCP) { + if (probe_type == PROBE_EXTERN || probe_type == PROBE_L7 || probe_type == PROBE_TCP) { Json_AddCharItemToObject(params, CLUSTER_IP_BACKEND, probe_param->cluster_ip_backend); } - if (probe_type == PROBE_BASEINFO) { + if (probe_type == PROBE_BASEINFO || probe_type == PROBE_EXTERN) { Json_AddStringToObject(params, ELF_PATH, probe_param->elf_path); } - if (probe_type == PROBE_FG) { + if (probe_type == PROBE_FG || probe_type == PROBE_EXTERN) { Json_AddStringToObject(params, PYROSCOPE_SERVER, probe_param->pyroscope_server); Json_AddUIntItemToObject(params, SVG_PERIOD,probe_param->svg_period); Json_AddUIntItemToObject(params, PERF_SAMPLE_PERIOD, probe_param->perf_sample_period); @@ -624,19 +674,24 @@ void probe_params_to_json(struct probe_s *probe, void *params) Json_AddStringToObject(params, FLAME_DIR, probe_param->flame_dir); } if (probe_type == PROBE_IO || probe_type == PROBE_KAFKA || probe_type == PROBE_KSLI || - probe_type == PROBE_POSTGRE_SLI || probe_type == PROBE_BASEINFO || probe_type == PROBE_TCP) { + probe_type == PROBE_POSTGRE_SLI || probe_type == PROBE_BASEINFO || probe_type == PROBE_EXTERN || probe_type == PROBE_TCP) { Json_AddStringToObject(params, DEV_NAME_KEY, probe_param->target_dev); } - if (probe_type == PROBE_KSLI) { + if (probe_type == PROBE_KSLI || probe_type == PROBE_EXTERN) { Json_AddCharItemToObject(params, CONTINUOUS_SAMPLING, probe_param->continuous_sampling_flag); } - if (probe_type == PROBE_NGINX) { + if (probe_type == PROBE_NGINX || probe_type == PROBE_EXTERN) { Json_AddStringToObject(params, ELF_PATH, probe_param->elf_path); } - if (probe_type == PROBE_KAFKA) { + if (probe_type == PROBE_KAFKA || probe_type == PROBE_EXTERN) { Json_AddUIntItemToObject(params, KAFKA_PORT, probe_param->kafka_port); } - if (probe_type == PROBE_CONTAINER) { + if (probe_type == PROBE_CONTAINER || probe_type == PROBE_EXTERN) { Json_AddUIntItemToObject(params, CADVISOR_PORT, probe_param->cadvisor_port); } + if (probe_type == PROBE_EXTERN) { + size = probe->probe_param.params_num; + arr = param_custom_to_json(probe->probe_param.custom_param, size); + Json_AddItemToObject(params, CUSTOM_PARAMS, arr); + } } diff --git a/src/lib/probe/snooper.c b/src/lib/probe/snooper.c index b5947551729b99058e6fc77789b3c08b09b76d98..0b71aa61217823bac4ffe41c9dcd825f9296b648 100644 --- a/src/lib/probe/snooper.c +++ b/src/lib/probe/snooper.c @@ -574,6 +574,7 @@ static void __build_ipc_body(struct probe_s *probe, struct ipc_body_s* ipc_body) if (probe->is_snooper_chg) { ipc_body->probe_flags |= IPC_FLAGS_SNOOPER_CHG; } + ipc_body->custom = &probe->custom.custom_subprobe; memcpy(&(ipc_body->probe_param), &probe->probe_param, sizeof(struct probe_params)); return; } @@ -594,13 +595,19 @@ static inline int need_send_snooper_obj(struct probe_s *probe) int send_snooper_obj(struct probe_s *probe) { struct ipc_body_s ipc_body; // Initialized at '__build_ipc_body' function + long probetype = 0; if (need_send_snooper_obj(probe) == 0) { return 0; } __build_ipc_body(probe, &ipc_body); - return send_ipc_msg(__probe_mng_snooper->msq_id, (long)probe->probe_type, &ipc_body); + if (probe->probe_type == PROBE_EXTERN) { + probetype = (long)(PROBE_EXTERN + 1 + probe->custom.index); + } else { + probetype = (long)probe->probe_type; + } + return send_ipc_msg(__probe_mng_snooper->msq_id, probetype, &ipc_body); } int parse_snooper(struct probe_s *probe, const void *json) diff --git a/src/resource/resource.c b/src/resource/resource.c index 9866141e482b9ae66be580bf06debb21301e3619..229b6e5c2d95cbcb32a82ad03a4481b9df539cb5 100644 --- a/src/resource/resource.c +++ b/src/resource/resource.c @@ -185,6 +185,7 @@ static int ProbeMngInit(ResourceMgr *resourceMgr) static void ProbeMngDeinit(ResourceMgr *resourceMgr) { destroy_probe_mng(); + destroy_custom_ini(); resourceMgr->probe_mng = NULL; }