From: Peter Stamfest Date: Tue, 2 Sep 2014 20:44:18 +0000 (+0200) Subject: Implement --template option to rrdtool create X-Git-Tag: v1.5.0-rc1~42^2~10 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b4bb4e0c6f7fecf885abb5d514658760e0acac6f;p=thirdparty%2Frrdtool-1.x.git Implement --template option to rrdtool create --- diff --git a/src/rrd.h b/src/rrd.h index 5eb52355..c69659e7 100644 --- a/src/rrd.h +++ b/src/rrd.h @@ -245,6 +245,7 @@ struct rrd_t; time_t last_up, int no_overwrite, const char **sources, + const char *template, int argc, const char **argv); rrd_info_t *rrd_info_r( diff --git a/src/rrd_client.c b/src/rrd_client.c index 9c1ae3d3..58a3d5b8 100644 --- a/src/rrd_client.c +++ b/src/rrd_client.c @@ -1203,7 +1203,7 @@ int rrdc_create (const char *filename, /* {{{ */ int argc, const char **argv) { - return rrdc_create_r2(filename, pdp_step, last_up, no_overwrite, NULL, argc, argv); + return rrdc_create_r2(filename, pdp_step, last_up, no_overwrite, NULL, NULL, argc, argv); } int rrdc_create_r2(const char *filename, /* {{{ */ @@ -1211,6 +1211,7 @@ int rrdc_create_r2(const char *filename, /* {{{ */ time_t last_up, int no_overwrite, const char **sources, + const char *template, int argc, const char **argv) { @@ -1262,6 +1263,11 @@ int rrdc_create_r2(const char *filename, /* {{{ */ } } + if (template != NULL) { + buffer_add_string ("-t", &buffer_ptr, &buffer_free); + buffer_add_string (template, &buffer_ptr, &buffer_free); + } + if (status != 0) { mutex_unlock (&lock); diff --git a/src/rrd_client.h b/src/rrd_client.h index 4984bc59..18b36e72 100644 --- a/src/rrd_client.h +++ b/src/rrd_client.h @@ -65,6 +65,7 @@ int rrdc_create_r2 (const char *filename, time_t last_up, int no_overwrite, const char **sources, + const char *template, int argc, const char **argv); diff --git a/src/rrd_create.c b/src/rrd_create.c index cfd03e0d..5510b173 100644 --- a/src/rrd_create.c +++ b/src/rrd_create.c @@ -56,13 +56,14 @@ int rrd_create( {"step", required_argument, 0, 's'}, {"daemon", required_argument, 0, 'd'}, {"source", required_argument, 0, 'r'}, + {"template", required_argument, 0, 't'}, {"no-overwrite", no_argument, 0, 'O'}, {0, 0, 0, 0} }; int option_index = 0; int opt; time_t last_up = -1; - unsigned long pdp_step = 300; + unsigned long pdp_step = 0; rrd_time_value_t last_up_tv; const char *parsetime_error = NULL; int rc = -1; @@ -70,6 +71,7 @@ int rrd_create( int opt_no_overwrite = 0; GList * sources = NULL; const char **sources_array = NULL; + const char *template = NULL; optind = 0; opterr = 0; /* initialize getopt */ @@ -162,6 +164,22 @@ int rrd_create( break; } + case 't': { + if (template != NULL) { + rrd_set_error("template already set"); + rc = -1; + goto done; + } + char * optcpy = strdup(optarg); + if (optcpy == NULL) { + rrd_set_error("Cannot allocate string"); + rc = -1; + goto done; + } + + template = optcpy; + break; + } case '?': if (optopt != 0) rrd_set_error("unknown option '%c'", optopt); @@ -194,14 +212,14 @@ int rrd_create( if (rrdc_is_connected (opt_daemon)) { rc = rrdc_create_r2(argv[optind], pdp_step, last_up, opt_no_overwrite, - sources_array, + sources_array, template, argc - optind - 1, (const char **) (argv + optind + 1)); - } else { + } else { rc = rrd_create_r2(argv[optind], pdp_step, last_up, opt_no_overwrite, - sources_array, + sources_array, template, argc - optind - 1, (const char **) (argv + optind + 1)); - } + } done: if (sources_array != NULL) { free(sources_array); @@ -212,6 +230,10 @@ done: g_list_free_full(sources, free); sources = NULL; } + if (template != NULL) { + free(template); + template = NULL; + } return rc; } @@ -646,7 +668,7 @@ int rrd_create_r( int argc, const char **argv) { - return rrd_create_r2(filename,pdp_step,last_up,0, NULL, argc,argv); + return rrd_create_r2(filename,pdp_step,last_up,0, NULL, NULL, argc,argv); } @@ -668,6 +690,7 @@ int rrd_create_r2( time_t last_up, int no_overwrite, const char **sources, + const char *template, int argc, const char **argv) { @@ -716,6 +739,49 @@ int rrd_create_r2( rrd.rra_def = NULL; rrd.live_head->last_up = last_up > 0 ? last_up : time(NULL) - 10; + int last_up_set = last_up > 0; + + time_t template_latest_last_up = 0; + + if (template) { + rrd_t trrd; + + rrd_init(&trrd); + rrd_file_t *tf = rrd_open(template, &trrd, RRD_READONLY | RRD_READAHEAD | RRD_READVALUES); + if (tf == NULL) { + rrd_set_error("Cannot open template RRD %s", template); + goto done; + } + + /* copy step time if not yet set */ + + if (rrd.stat_head->pdp_step == 0) { + rrd.stat_head->pdp_step = trrd.stat_head->pdp_step; + } + + /* copy DS and RRA definitions from template... */ + + rrd.stat_head->ds_cnt = trrd.stat_head->ds_cnt; + rrd.ds_def = malloc(sizeof(ds_def_t) * trrd.stat_head->ds_cnt); + rrd.stat_head->rra_cnt = trrd.stat_head->rra_cnt; + rrd.rra_def = malloc(sizeof(rra_def_t) * trrd.stat_head->rra_cnt); + + if (rrd.ds_def == NULL || rrd.rra_def == NULL) { + rrd_set_error("cannot allocate memory"); + goto done; + } + + template_latest_last_up = trrd.live_head->last_up; + + memcpy(rrd.ds_def, trrd.ds_def, sizeof(ds_def_t) * trrd.stat_head->ds_cnt); + memcpy(rrd.rra_def, trrd.rra_def, sizeof(rra_def_t) * trrd.stat_head->rra_cnt); + + rrd_close(tf); + } + + if (rrd.stat_head->pdp_step == 0) { + rrd.stat_head->pdp_step = 300; + } /* optind points to the first non-option command line arg, * in this case, the file name. */ @@ -800,7 +866,13 @@ int rrd_create_r2( rrd_set_error("you must define at least one Data Source"); goto done; } - + + /* set last update time from template if not set explicitly and there + * are no sources given */ + if (!last_up_set && template_latest_last_up > 0 && sources == NULL) { + rrd.live_head->last_up = template_latest_last_up; + } + rc = rrd_init_data(&rrd); if (rc != 0) goto done; @@ -832,11 +904,12 @@ int rrd_create_r2( if (last_up == -1) { rrd.live_head->last_up = sources_latest_last_up; + last_up_set = 1; reset_pdp_prep(&rrd); } rrd_prefill_data(&rrd, sources_rrd_files, mappings, mappings_cnt); } - + rc = write_rrd(filename, &rrd); done: diff --git a/src/rrd_daemon.c b/src/rrd_daemon.c index 3fefd406..81535ef5 100644 --- a/src/rrd_daemon.c +++ b/src/rrd_daemon.c @@ -1915,6 +1915,7 @@ static int handle_request_create (HANDLER_PROTO) /* {{{ */ char *av[128]; char **sources = NULL; int sources_length = 0; + char *template = NULL; int status; unsigned long step = 300; time_t last_up = time(NULL)-10; @@ -1991,6 +1992,15 @@ static int handle_request_create (HANDLER_PROTO) /* {{{ */ sources[sources_length + 1] = NULL; continue; } + if( ! strncmp(tok,"-t",2) ) { + status = buffer_get_field(&buffer, &buffer_size, &tok ); + if (status != 0) { + rc = syntax_error(sock,cmd); + goto done; + } + template = tok; + continue; + } if( ! strncmp(tok,"-O",2) ) { no_overwrite = 1; continue; @@ -2011,7 +2021,7 @@ static int handle_request_create (HANDLER_PROTO) /* {{{ */ rrd_clear_error (); pthread_mutex_lock(&rrdfilecreate_lock); - status = rrd_create_r2(file,step,last_up,no_overwrite, (const char**) sources, ac,(const char **)av); + status = rrd_create_r2(file,step,last_up,no_overwrite, (const char**) sources, template, ac,(const char **)av); pthread_mutex_unlock(&rrdfilecreate_lock); if(!status) { diff --git a/tests/Makefile.am b/tests/Makefile.am index 1d8136bd..d6717f23 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -3,7 +3,8 @@ TESTS = modify1 modify2 modify3 modify4 modify5 \ rrdcreate \ dump-restore \ create-with-source-1 create-with-source-2 create-with-source-3 \ - create-with-source-4 create-with-source-and-mapping-1 + create-with-source-4 create-with-source-and-mapping-1 \ + create-from-template-1 EXTRA_DIST = Makefile.am \ alltests functions \ modify1 modify-test1.create.dump modify-test1.mod1.dump \ diff --git a/tests/create-from-template-1 b/tests/create-from-template-1 new file mode 100755 index 00000000..a2475104 --- /dev/null +++ b/tests/create-from-template-1 @@ -0,0 +1,75 @@ +#!/bin/bash + +. $(dirname $0)/functions + +BASE=$BASEDIR/$(basename $0)-test +PREFIX=$BUILDDIR/$(basename $0)-test + +# currently, we do not properly copy cdp and pdp information, so for +# comparison of RRD dumps, we just filter out those parts we do not +# expect to match anyway... +function cdp_prep_filter { + perl -n -e '$a=join("",<>); $a=~s,<(cdp_prep).*?,,msg ; print $a' +} + +function pdp_prep_filter { + perl -n -e '$a=join("",<>); $a=~s,<(last_ds|value|unknown_sec).*?,,msg ; print $a' +} + +function data_filter_by_time { + START="$1" + END="$2" +# 7.9666666667e+02 + + perl -n -e 'print unless (m,/ (\d+) -->.*, && $1 >= '$START' && $1 <= '$END')' +} + +FIRST=1300000000 +ST=$FIRST + +RRA="RRA:AVERAGE:0.5:1:100 RRA:AVERAGE:0.5:5:2 RRA:MIN:0.5:5:2 RRA:MAX:0.5:5:2 RRA:LAST:0.5:5:2" + +rm -f ${PREFIX}*.rrd ${PREFIX}*.xml +$RRDTOOL create ${PREFIX}ax1.rrd --start $(($ST-1)) --step 60 DS:a:GAUGE:120:0:U DS:b:COUNTER:120:0:U $RRA +report createax1 + +cp ${PREFIX}ax1.rrd ${PREFIX}ax1-copy.rrd + +UPDATEAx1= +V=10 +for A in $(seq $ST 60 $(($ST + 3000)) ) ; do + UPDATEAx1="$UPDATEAx1 $A:$V" + V=$(($V + 20)) + ST=$A +done + +$RRDTOOL create ${PREFIX}ay1.rrd --start $ST --step 60 DS:a:GAUGE:120:0:U DS:b:COUNTER:120:0:U $RRA +report createay1 + +$RRDTOOL update ${PREFIX}ax1.rrd --template a $UPDATEAx1 +report update ax1 + +$RRDTOOL create ${PREFIX}ax2.rrd --template ${PREFIX}ax1.rrd || fail "create ax2" + +$RRDTOOL dump ${PREFIX}ay1.rrd > ${PREFIX}ay1.xml +$RRDTOOL dump ${PREFIX}ax2.rrd > ${PREFIX}ax2.xml +$DIFF ${PREFIX}ay1.xml ${PREFIX}ax2.xml + +report "created from template matches empty RRD with same start time" + +$RRDTOOL create ${PREFIX}b1.rrd --step 60 DS:b:GAUGE:120:0:U $RRA +report createb1 + +! $RRDTOOL create ${PREFIX}b2.rrd --template ${PREFIX}b1.rrd DS:b:COUNTER:120:0:U 2>/dev/null +report "create with template and name-clashing DS fails" + +$RRDTOOL create ${PREFIX}ax3.rrd --template ${PREFIX}ax1-copy.rrd \ + --source ${PREFIX}ax1.rrd || fail "create ax3" + +$RRDTOOL dump ${PREFIX}ax1.rrd > ${PREFIX}ax1.xml +$RRDTOOL dump ${PREFIX}ax3.rrd > ${PREFIX}ax3.xml +$DIFF ${PREFIX}ax1.xml ${PREFIX}ax3.xml + +report "create from old source as template using source for prefilling equals source" + +rm -f ${PREFIX}*.rrd ${PREFIX}*.xml