From: François HORTA Date: Mon, 8 Nov 2021 16:35:17 +0000 (+0100) Subject: Add support for TUNE command in rrdcached X-Git-Tag: v1.8.0~13^2~5 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=2f0bc1d522c1be7bbea33da43555da6cd757a5ef;p=thirdparty%2Frrdtool-1.x.git Add support for TUNE command in rrdcached --- diff --git a/src/librrd.sym b/src/librrd.sym index ee726002..86b9a6ea 100644 --- a/src/librrd.sym +++ b/src/librrd.sym @@ -16,6 +16,8 @@ rrd_dump_r rrd_fetch rrd_fetch_cb_register rrd_fetch_r +rrd_tune +rrd_tune_r rrd_first rrd_first_r rrd_flush diff --git a/src/rrd.h b/src/rrd.h index 155cd65e..8439413c 100644 --- a/src/rrd.h +++ b/src/rrd.h @@ -303,6 +303,10 @@ extern "C" { unsigned long *ds_cnt, char ***ds_namv, rrd_value_t **data); + int rrd_tune_r( + const char *filename, + int argc, + const char **argv); int rrd_dump_opt_r( const char *filename, char *outname, diff --git a/src/rrd_client.c b/src/rrd_client.c index f00a73c6..faf462ae 100644 --- a/src/rrd_client.c +++ b/src/rrd_client.c @@ -2057,6 +2057,98 @@ int rrdc_fetch( return status; } /* }}} int rrdc_fetch */ +int rrd_client_tune( + rrd_client_t *client, + const char *filename, /* {{{ */ + int argc, + const char **argv) +{ + char buffer[RRD_CMD_MAX]; + char *buffer_ptr; + size_t buffer_free; + size_t buffer_size; + rrdc_response_t *res; + int status; + char *file_path; + int i; + + if (client == NULL) + return -1; + if (filename == NULL) { + rrd_set_error("rrdc_tune: no filename specified"); + return (-1); + } + + memset(buffer, 0, sizeof(buffer)); + buffer_ptr = &buffer[0]; + buffer_free = sizeof(buffer); + + status = buffer_add_string("tune", &buffer_ptr, &buffer_free); + if (status != 0) { + rrd_set_error("rrdc_tune: out of memory"); + return (-1); + } + + file_path = get_path(client, filename); + if (file_path == NULL) { + return (-1); + } + + status = buffer_add_string(file_path, &buffer_ptr, &buffer_free); + free(file_path); + + if (status != 0) { + rrd_set_error("rrdc_tune: out of memory"); + return (-1); + } + + status = buffer_add_ulong(argc, &buffer_ptr, &buffer_free); + if (status != 0) { + rrd_set_error("rrdc_tune: out of memory"); + return (-1); + } + + for (i = 0; i < argc; i++) { + if (argv[i]) { + status = buffer_add_string(argv[i], &buffer_ptr, &buffer_free); + if (status != 0) { + rrd_set_error("rrdc_tune: out of memory"); + return (-1); + } + } + } + + /* buffer ready to send? */ + assert(buffer_free < sizeof(buffer)); + buffer_size = sizeof(buffer) - buffer_free; + assert(buffer[buffer_size - 1] == ' '); + buffer[buffer_size - 1] = '\n'; + + res = NULL; + status = request(client, buffer, buffer_size, &res); + + if (status != 0) + return (-1); + + status = res->status; + response_free(res); + return (status); +} /* }}} int rrd_client_tune */ + +int rrdc_tune( + const char *filename, /* {{{ */ + int argc, + const char **argv) +{ + int status; + + mutex_lock(&lock); + status = + rrd_client_tune(&default_client, filename, argc, argv); + mutex_unlock(&lock); + return status; +} /* }}} int rrdc_tune */ + /* convenience function; if there is a daemon specified, or if we can * detect one from the environment, then flush the file. Otherwise, no-op */ diff --git a/src/rrd_client.h b/src/rrd_client.h index fe8f954a..1ccb7487 100644 --- a/src/rrd_client.h +++ b/src/rrd_client.h @@ -103,6 +103,10 @@ int rrd_client_fetch(rrd_client_t *client, const char *filename, char ***ret_ds_names, rrd_value_t **ret_data); +int rrd_client_tune(rrd_client_t *client, const char *filename, + int argc, + const char **argv); + int rrd_client_stats_get(rrd_client_t *client, rrdc_stats_t **ret_stats); /* @@ -144,6 +148,10 @@ int rrdc_flush_if_daemon (const char *opt_daemon, const char *filename); int rrdc_flushall (void); int rrdc_flushall_if_daemon (const char *opt_daemon); +int rrdc_tune (const char *filename, + int argc, + const char **argv); + int rrdc_fetch (const char *filename, const char *cf, time_t *ret_start, time_t *ret_end, diff --git a/src/rrd_daemon.c b/src/rrd_daemon.c index 9c36eb1e..3ad3a66f 100644 --- a/src/rrd_daemon.c +++ b/src/rrd_daemon.c @@ -1791,6 +1791,73 @@ static int handle_request_update( return rc; } /* }}} int handle_request_update */ + +static int handle_request_tune( + HANDLER_PROTO) +{ /* {{{ */ + int status; + char** argv = NULL; + int argc, argc_tmp; + char* i; + int rc; + char *file = NULL, *pbuffile; + char *tok; + + /* obtain filename */ + status = buffer_get_field(&buffer, &buffer_size, &pbuffile); + if (status != 0) { + rc = syntax_error(sock, cmd); + goto done; + } + /* get full pathname */ + file = get_abs_path(pbuffile); + if (file == NULL) { + rc = send_response(sock, RESP_ERR, "%s\n", rrd_strerror(ENOMEM)); + goto done; + } + + if (!check_file_access(file, sock)) { + rc = send_response(sock, RESP_ERR, "%s: %s\n", file, + rrd_strerror(EACCES)); + goto done; + } + RRDD_LOG(LOG_INFO, "rrdtune request for %s", file); + + status = buffer_get_field(&buffer, &buffer_size, &i); + if (status != 0) { + rc = syntax_error(sock, cmd); + goto done; + } + argc = atoi(i); + if (argc < 0) { + rc = send_response(sock, RESP_ERR, "Invalid argument count specified (%d)\n", + argc); + goto done; + } + + if ((argv = (char **) malloc(argc * sizeof(char*))) == NULL) { + rc = send_response(sock, RESP_ERR, "%s\n", rrd_strerror(ENOMEM)); + goto done; + } + argc_tmp = 0; + while ((status = buffer_get_field(&buffer, &buffer_size, &tok)) == 0 + && tok) { + argv[argc_tmp] = tok; + argc_tmp += 1; + } + + status = rrd_tune_r(file, argc, (const char **)argv); + if (status != 0) { + rc = send_response(sock, RESP_ERR, "Got error %s\n", rrd_get_error()); + goto done; + } + rc = send_response(sock, RESP_OK, "Success\n"); + done: + free(file); + free(argv); + return rc; +} + struct fetch_parsed { char *file; char *cf; @@ -2810,6 +2877,12 @@ static command_t list_of_commands[] = { /* {{{ */ CMD_CONTEXT_JOURNAL, NULL, NULL}, + { + "TUNE", + handle_request_tune, + CMD_CONTEXT_CLIENT, + "TUNE [options]", + "Tunes the given file, takes the parameters as defined in rrdtool"}, { "FLUSH", handle_request_flush, diff --git a/src/rrd_tune.c b/src/rrd_tune.c index 10fc6468..3374dd1d 100644 --- a/src/rrd_tune.c +++ b/src/rrd_tune.c @@ -73,21 +73,7 @@ int rrd_tune( int argc, char **argv) { - rrd_t rrd; - int matches; - int optcnt = 0; - long ds; - char ds_nam[DS_NAM_SIZE]; - char ds_new[DS_NAM_SIZE]; - long heartbeat; - double min = 0; - double max = 0; - char dst[DST_SIZE]; - int rc = -1; - int opt_newstep = -1; - rrd_file_t *rrd_file = NULL; char *opt_daemon = NULL; - char double_str[ 41 ] = {0}; const char *in_filename = NULL; struct optparse_long longopts[] = { {"heartbeat", 'h', OPTPARSE_REQUIRED}, @@ -115,10 +101,9 @@ int rrd_tune( }; struct optparse options; int opt; + int status = -1; rrd_thread_init(); - /* Fix CWE-457 */ - memset(&rrd, 0, sizeof(rrd_t)); /* before we open the input RRD, we should flush it from any caching daemon, because we might totally rewrite it later on */ @@ -173,6 +158,77 @@ int rrd_tune( rrd_clear_error(); } + if (rrdc_is_any_connected ()) + status = rrdc_tune (in_filename, argc, (const char **) argv); + + else + status = rrd_tune_r(in_filename, argc, (const char **) argv); + +done: + if (in_filename && rrdc_is_any_connected()) { + // save any errors.... + char *e = strdup(rrd_get_error()); + // is it a good idea to just ignore the error ???? + rrdc_forget(in_filename); + rrd_clear_error(); + + if (e) { + rrd_set_error(e); + free(e); + } else + rrd_set_error("error message was lost (out of memory)"); + } + return status; +} + +int rrd_tune_r( + const char* in_filename, + int argc, + const char **argv) +{ + rrd_t rrd; + int matches; + int optcnt = 0; + long ds; + char ds_nam[DS_NAM_SIZE]; + char ds_new[DS_NAM_SIZE]; + long heartbeat; + double min = 0; + double max = 0; + char dst[DST_SIZE]; + int rc = -1; + int opt_newstep = -1; + rrd_file_t *rrd_file = NULL; + char double_str[ 41 ] = {0}; + struct optparse_long longopts[] = { + {"heartbeat", 'h', OPTPARSE_REQUIRED}, + {"minimum", 'i', OPTPARSE_REQUIRED}, + {"maximum", 'a', OPTPARSE_REQUIRED}, + {"data-source-type", 'd', OPTPARSE_REQUIRED}, + {"data-source-rename", 'r', OPTPARSE_REQUIRED}, + /* added parameter tuning options for aberrant behavior detection */ + {"deltapos", 'p', OPTPARSE_REQUIRED}, + {"deltaneg", 'n', OPTPARSE_REQUIRED}, + {"window-length", 'w', OPTPARSE_REQUIRED}, + {"failure-threshold", 'f', OPTPARSE_REQUIRED}, + {"alpha", 'x', OPTPARSE_REQUIRED}, + {"beta", 'y', OPTPARSE_REQUIRED}, + {"gamma", 'z', OPTPARSE_REQUIRED}, + {"gamma-deviation", 'v', OPTPARSE_REQUIRED}, + {"smoothing-window", 's', OPTPARSE_REQUIRED}, + {"smoothing-window-deviation", 'S', OPTPARSE_REQUIRED}, + {"aberrant-reset", 'b', OPTPARSE_REQUIRED}, + // integration of rrd_modify functionality. + {"step", 't', OPTPARSE_REQUIRED}, + /* unfortunately, '-d' is already taken */ + {"daemon", 'D', OPTPARSE_REQUIRED}, + {0} + }; + struct optparse options; + int opt; + + /* Fix CWE-457 */ + memset(&rrd, 0, sizeof(rrd_t)); rrd_init(&rrd); rrd_file = rrd_open(in_filename, &rrd, RRD_READWRITE | RRD_LOCK | RRD_READAHEAD | RRD_READVALUES); @@ -410,19 +466,6 @@ int rrd_tune( options.optind = handle_modify(&rrd, in_filename, options.argc, options.argv, options.optind + 1, opt_newstep); rc = 0; done: - if (in_filename && rrdc_is_any_connected()) { - // save any errors.... - char *e = strdup(rrd_get_error()); - // is it a good idea to just ignore the error ???? - rrdc_forget(in_filename); - rrd_clear_error(); - - if (e) { - rrd_set_error(e); - free(e); - } else - rrd_set_error("error message was lost (out of memory)"); - } if (rrd_file) { rrd_close(rrd_file); }