{"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;
int opt_no_overwrite = 0;
GList * sources = NULL;
const char **sources_array = NULL;
+ const char *template = NULL;
optind = 0;
opterr = 0; /* initialize getopt */
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);
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);
g_list_free_full(sources, free);
sources = NULL;
}
+ if (template != NULL) {
+ free(template);
+ template = NULL;
+ }
return rc;
}
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);
}
time_t last_up,
int no_overwrite,
const char **sources,
+ const char *template,
int argc,
const char **argv)
{
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. */
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;
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:
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;
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;
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) {
--- /dev/null
+#!/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).*?</\1>,,msg ; print $a'
+}
+
+function pdp_prep_filter {
+ perl -n -e '$a=join("",<>); $a=~s,<(last_ds|value|unknown_sec).*?</\1>,,msg ; print $a'
+}
+
+function data_filter_by_time {
+ START="$1"
+ END="$2"
+# <!-- 2011-03-13 08:46:00 CET / 1300002360 --> <row><v>7.9666666667e+02</v>
+
+ perl -n -e 'print unless (m,/ (\d+) -->.*<row>, && $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