Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 117 additions & 0 deletions qa/1744
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
#!/bin/sh
# PCP QA Test No. 1744
# Test pmproxy / pmseries label storing mechanism
#
# Copyright (c) 2026 Red Hat. All Rights Reserved.
#
seq=`basename $0`
echo "QA output created by $seq"

# get standard environment, filters and checks
. ./common.python
. ./common.keys

_check_series

status=1 # failure is the default!

_cleanup()
{
cd $here
[ -n "$pmloggerpid" ] && $sudo kill -TERM $pmloggerpid 2>/dev/null
if [ -n "$key_server_port" ]; then
echo "Shutting down key server on port $key_server_port..." >>$here/$seq.full
$keys_cli -p $key_server_port shutdown >>$here/$seq.full 2>&1
sleep 1
# Verify it's actually dead
if $keys_cli -p $key_server_port PING >>$here/$seq.full 2>&1; then
echo "WARNING: Key server still running after shutdown!" >>$here/$seq.full
else
echo "Key server shutdown confirmed" >>$here/$seq.full
fi
fi
_sighup_pmcd
_restore_config $PCP_SYSCONF_DIR/pmseries
$sudo rm -rf $tmp $tmp.*
}
Comment thread
lmchilton marked this conversation as resolved.

trap "_cleanup; exit \$status" 0 1 2 3 15
_stop_auto_restart pmcd

Comment on lines +33 to +40
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot May 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Restore pmcd auto-restart policy in cleanup.

Line 39 disables pmcd auto-restart via _stop_auto_restart pmcd, but _cleanup() never calls _restore_auto_restart pmcd. This can leak modified service state into later QA tests.

Suggested fix
 _cleanup()
 {
     cd $here
     [ -n "$pmloggerpid" ] && $sudo kill -TERM $pmloggerpid 2>/dev/null
@@
     fi
     _sighup_pmcd
+    _restore_auto_restart pmcd
     _restore_config $PCP_SYSCONF_DIR/pmseries
     $sudo rm -rf $tmp $tmp.*
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
_sighup_pmcd
_restore_config $PCP_SYSCONF_DIR/pmseries
$sudo rm -rf $tmp $tmp.*
}
trap "_cleanup; exit \$status" 0 1 2 3 15
_stop_auto_restart pmcd
_sighup_pmcd
_restore_auto_restart pmcd
_restore_config $PCP_SYSCONF_DIR/pmseries
$sudo rm -rf $tmp $tmp.*
}
trap "_cleanup; exit \$status" 0 1 2 3 15
_stop_auto_restart pmcd
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@qa/1744` around lines 33 - 40, The cleanup routine omits restoring the pmcd
auto-restart policy after it was disabled by the call to _stop_auto_restart
pmcd; update the _cleanup function to call _restore_auto_restart pmcd (using the
same service name "pmcd") before exiting/returning so the service auto-restart
state is reverted, and ensure this new call is invoked in the trap path that
references _cleanup so later QA tests do not inherit the modified service state.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it looks like there should be a _restore_auto_restart pmcd in the cleanup like many other of the qa tests.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@wcohen, agreed — the fix is to add _restore_auto_restart pmcd inside _cleanup, consistent with the pattern used in other QA tests:

     _sighup_pmcd
+    _restore_auto_restart pmcd
     _restore_config $PCP_SYSCONF_DIR/pmseries
     $sudo rm -rf $tmp $tmp.*
 }

A="$here/archives/pcp-atop-nvidia"

_filter()
{
# Replace machine-specific label values with placeholders
sed \
-e "s/\"hostname\":\"[a-z]*\"/\"hostname\":\"HOSTNAME\"/g" \
-e 's/"uuid":"GPU-[0-9a-f-]*"/"uuid":"UUID"/g'
}

_filter_series()
{
sed \
-e 's/[0-9a-z]\{40\}/TIMESERIES/g' \
#end
}

# real QA test starts here
key_server_port=`_find_free_port`
_save_config $PCP_SYSCONF_DIR/pmseries
$sudo rm -f $PCP_SYSCONF_DIR/pmseries/*

# Create pmseries config pointing to our test key server
$sudo tee $PCP_SYSCONF_DIR/pmseries/pmseries.conf > /dev/null <<EOF
[pmseries]
servers = localhost:$key_server_port
EOF

echo "Start test key server on port $key_server_port..." >>$seq.full
$key_server --port $key_server_port --save "" > $tmp.keys 2>&1 &
_check_key_server_ping $key_server_port
_check_key_server $key_server_port
echo

_check_key_server_version $key_server_port


# Check key server port and flush
echo "Using key server on port $key_server_port" >>$seq_full
echo "Flushing key server on port $key_server_port ..."
flush_result=`echo "FLUSHALL" | $keys_cli -p $key_server_port 2>&1`
echo "Flush result: $flush_result" >>$seq_full
if [ "$flush_result" != "OK" ]; then
echo "ERROR: Failed to flush key server, got: $flush_result"
status=1
exit
fi
echo "Key server flushed successfully"

# Load the archive into pmseries
echo "Loading test archive into pmseries ..."
pmseries $options --load "{source.path: \"$A\"}" 2>&1 | \
sed "s|$A|ARCHIVE|g" | tee -a $seq_full

# Wait for metrics to be indexed
echo "Waiting for metrics to be indexed ..."
pmsleep 2

# Query for the first metric (identifying labels only)
echo
echo "=== nvidia.gpuactive (optional labels "gpu" & "uuid") ==="
series1=`pmseries $options 'nvidia.gpuactive'`
if [ -z "$series1" ]; then
echo "ERROR: No series found for nvidia.gpuactive"
status=1
exit
else
pmseries $series1 | _filter_series | _filter
fi

echo == Note: check $seq.full for details
echo == pmlogger LOG == >>$seq_full
cat $tmp.pmlogger.log >>$seq_full 2>&1

# success, all done
status=0
exit
21 changes: 21 additions & 0 deletions qa/1744.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
QA output created by 1744
PING
PONG

Flushing key server on port 54321 ...
Key server flushed successfully
Loading test archive into pmseries ...
pmseries: [Info] processed 11 archive records from ARCHIVE
Waiting for metrics to be indexed ...

=== nvidia.gpuactive (optional labels gpu & uuid) ===

TIMESERIES
PMID: 120.0.7
Data Type: 32-bit unsigned int InDom: 120.0 0x1e000000
Semantics: instant Units: none
Source: TIMESERIES
Metric: nvidia.gpuactive
inst [0 or "gpu0"] series TIMESERIES
inst [0 or "gpu0"] labels {"agent":"nvidia","device_type":"gpu","gpu":0,"hostname":"HOSTNAME","indom_name":"per gpu","uuid":"UUID"}
== Note: check 1744.full for details
4 changes: 2 additions & 2 deletions qa/common.check
Original file line number Diff line number Diff line change
Expand Up @@ -1560,11 +1560,11 @@ _check_key_server_version()
fi


if which valkey-cli >/dev/null 2>&1 && test -n `_get_pids_by_name valkey-server`
if which valkey-cli >/dev/null 2>&1 && test -n "`_get_pids_by_name valkey-server`"
then
keys_cli=valkey-cli
keys_ver=valkey_version
elif which redis-cli >/dev/null 2>&1 && test -n _get_pids_by_name redis-server
elif which redis-cli >/dev/null 2>&1 && test -n "`_get_pids_by_name redis-server`"
then
keys_cli=redis-cli
keys_ver=redis_version
Expand Down
1 change: 1 addition & 0 deletions qa/group
Original file line number Diff line number Diff line change
Expand Up @@ -2252,6 +2252,7 @@ suse
1727 pmproxy libpcp_web pmda.openmetrics local
1735 python pmimport local
1740 pmda.proc local
1744 pmseries local
1745 pmlogger libpcp pmval local pmda.sample pmda.simple pmlogdump
1747 pmlogger labels local
1748 atop local
Expand Down
42 changes: 33 additions & 9 deletions src/libpcp_web/src/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,13 @@ instance_labelsets(indom_t *indom, instance_t *inst, char *buffer, int length,
return pmMergeLabelSets(sets, nsets, buffer, length, filter, arg);
}

/* extract all labels (both identifying and optional) */
static int
all_labels(const pmLabel *label, const char *json, void *arg)
{
return 1;
}

/* extract only the identifying labels (not optional) */
static int
labels(const pmLabel *label, const char *json, void *arg)
Expand Down Expand Up @@ -276,7 +283,13 @@ pmwebapi_source_meta(context_t *c, char *buffer, int length)
static int
context_labels_str(context_t *c, char *buffer, int length)
{
return pmMergeLabelSets(&c->labelset, 1, buffer, length, NULL, NULL);
return pmMergeLabelSets(&c->labelset, 1, buffer, length, all_labels, NULL);
}

static int
context_labels_str_identifying(context_t *c, char *buffer, int length)
{
return pmMergeLabelSets(&c->labelset, 1, buffer, length, labels, NULL);
}

int
Expand Down Expand Up @@ -447,14 +460,17 @@ int
pmwebapi_context_hash(context_t *context)
{
char labels[PM_MAXLABELJSONLEN];
char idlabels[PM_MAXLABELJSONLEN];
int sts;

if (context->labels == NULL) {
if ((sts = context_labels_str(context, labels, sizeof(labels))) < 0)
return sts;
context->labels = sdsnewlen(labels, sts);
}
return pmwebapi_source_hash(context->name.hash, context->labels, sdslen(context->labels));
if ((sts = context_labels_str_identifying(context, idlabels, sizeof(idlabels))) < 0)
return sts;
return pmwebapi_source_hash(context->name.hash, idlabels, sts);
}

void
Expand All @@ -464,22 +480,26 @@ pmwebapi_metric_hash(metric_t *metric)
pmDesc *desc = &metric->desc;
sds identifier;
char buf[PM_MAXLABELJSONLEN];
char idbuf[PM_MAXLABELJSONLEN];
char sem[32], type[32], units[64];
int len, i;

if (metric->labels == NULL) {
len = metric_labelsets(metric, buf, sizeof(buf), labels, NULL);
len = metric_labelsets(metric, buf, sizeof(buf), all_labels, NULL);
if (len <= 0)
len = pmsprintf(buf, sizeof(buf), "null");
metric->labels = sdsnewlen(buf, len);
}

if (metric_labelsets(metric, idbuf, sizeof(idbuf), labels, NULL) <= 0)
pmsprintf(idbuf, sizeof(idbuf), "null");

identifier = sdsempty();
for (i = 0; i < metric->numnames; i++) {
identifier = sdscatfmt(identifier,
"{\"series\":\"metric\",\"name\":\"%S\",\"labels\":%S,"
"{\"series\":\"metric\",\"name\":\"%S\",\"labels\":%s,"
"\"semantics\":\"%s\",\"type\":\"%s\",\"units\":\"%s\"}",
metric->names[i].sds, metric->labels,
metric->names[i].sds, idbuf,
pmSemStr_r(desc->sem, sem, sizeof(sem)),
pmTypeStr_r(desc->type, type, sizeof(type)),
pmUnitsStr_r(&desc->units, units, sizeof(units)));
Expand All @@ -501,7 +521,7 @@ pmwebapi_add_indom_labels(indom_t *indom)
int len;

if (indom->labels == NULL) {
len = instance_labelsets(indom, NULL, buf, sizeof(buf), labels, NULL);
len = instance_labelsets(indom, NULL, buf, sizeof(buf), all_labels, NULL);
if (len <= 0)
len = pmsprintf(buf, sizeof(buf), "null");
indom->labels = sdsnewlen(buf, len);
Expand All @@ -514,18 +534,22 @@ pmwebapi_instance_hash(indom_t *ip, instance_t *instance)
SHA1_CTX shactx;
sds identifier;
char buf[PM_MAXLABELJSONLEN];
char idbuf[PM_MAXLABELJSONLEN];
int len;

if (instance->labels == NULL) {
len = instance_labelsets(ip, instance, buf, sizeof(buf), labels, NULL);
len = instance_labelsets(ip, instance, buf, sizeof(buf), all_labels, NULL);
if (len <= 0)
len = pmsprintf(buf, sizeof(buf), "null");
instance->labels = sdsnewlen(buf, len);
}

if (instance_labelsets(ip, instance, idbuf, sizeof(idbuf), labels, NULL) <= 0)
pmsprintf(idbuf, sizeof(idbuf), "null");

identifier = sdscatfmt(sdsempty(),
"{\"series\":\"instance\",\"name\":\"%S\",\"labels\":%S}",
instance->name.sds, instance->labels);
"{\"series\":\"instance\",\"name\":\"%S\",\"labels\":%s}",
instance->name.sds, idbuf);
/* Calculate unique instance identifier 20-byte SHA1 hash */
SHA1Init(&shactx);
SHA1Update(&shactx, (unsigned char *)identifier, sdslen(identifier));
Expand Down
Loading