From 13bd661f67332b74e30beb870020a792cd05cd22 Mon Sep 17 00:00:00 2001 From: Nathan Scott Date: Fri, 27 Jun 2025 10:20:57 +1000 Subject: [PATCH] Update to pcp-6.3.7-5 with recent important fixes Resolves: RHEL-93182 --- big-endian-timestamps.patch | 93 ---- pcp-xsos-fixes.patch | 269 ---------- pcp.spec | 31 +- pcp_openmetrics.patch | 278 ----------- pmapi-header-multilib-fix.patch | 202 ++++++++ pmda-openmetrics-rollup.patch | 465 ++++++++++++++++++ ...exact.patch => pmwebapi-filter-exact.patch | 0 python-pmda-wrapper-list-fix.patch | 17 + selinux-pcp_pmie_t.patch | 21 + selinux-pmie-and-pmlogger.patch | 24 - systemd-tmpfiles.d-directories.patch | 40 ++ 11 files changed, 769 insertions(+), 671 deletions(-) delete mode 100644 big-endian-timestamps.patch delete mode 100644 pcp-xsos-fixes.patch delete mode 100644 pcp_openmetrics.patch create mode 100644 pmapi-header-multilib-fix.patch create mode 100644 pmda-openmetrics-rollup.patch rename pcp-filter-exact.patch => pmwebapi-filter-exact.patch (100%) create mode 100644 python-pmda-wrapper-list-fix.patch create mode 100644 selinux-pcp_pmie_t.patch delete mode 100644 selinux-pmie-and-pmlogger.patch create mode 100644 systemd-tmpfiles.d-directories.patch diff --git a/big-endian-timestamps.patch b/big-endian-timestamps.patch deleted file mode 100644 index 854afe1..0000000 --- a/big-endian-timestamps.patch +++ /dev/null @@ -1,93 +0,0 @@ -commit 4df35d2b5070f289bf3856f035551cde8ca22e06 -Author: Nathan Scott -Date: Thu Jan 30 12:11:26 2025 +1100 - - libpcp: fix endian issue in big-endian __pmTimestamp writing - - Mirror an earlier endian fix in the reading code for big-endian - platforms for writing __pmTimestamp structures. Affects v3 log - writing only, and big endian platforms only. - - Some minor code cleanup also; fix an unused-function warning on - big endian build machines and keep the various timestamp get/put - routines together in logmeta.c for easier cross-referencing. - - Resolves Red Hat bug RHEL-69722 - Resolves github issue #2110 - -diff --git a/src/libpcp/src/endian.c b/src/libpcp/src/endian.c -index fc6d931f99..f700fc9c56 100644 ---- a/src/libpcp/src/endian.c -+++ b/src/libpcp/src/endian.c -@@ -77,6 +77,7 @@ __ntohpmLabel(pmLabel * const label) - } - #endif - -+#ifndef __htonpmValueBlock - static void - __htonpmTimespec(pmTimespec * const tsp) - { -@@ -84,7 +85,6 @@ __htonpmTimespec(pmTimespec * const tsp) - __htonll((char *)&tsp->tv_nsec); - } - --#ifndef __htonpmValueBlock - static void - htonEventArray(pmValueBlock * const vb, int highres) - { -diff --git a/src/libpcp/src/logmeta.c b/src/libpcp/src/logmeta.c -index 9db81af860..e04545d425 100644 ---- a/src/libpcp/src/logmeta.c -+++ b/src/libpcp/src/logmeta.c -@@ -1823,17 +1823,6 @@ __pmLoadTimestamp(const __int32_t *buf, __pmTimestamp *tsp) - } - } - --void --__pmLoadTimeval(const __int32_t *buf, __pmTimestamp *tsp) --{ -- tsp->sec = (__int32_t)ntohl(buf[0]); -- tsp->nsec = ntohl(buf[1]) * 1000; -- if (pmDebugOptions.logmeta && pmDebugOptions.desperate) { -- fprintf(stderr, "__pmLoadTimeval: network(%08x %08x usec)", buf[0], buf[1]); -- fprintf(stderr, " -> %" FMT_INT64 ".%09d (%llx %x nsec)\n", tsp->sec, tsp->nsec, (long long)tsp->sec, tsp->nsec); -- } --} -- - void - __pmPutTimestamp(const __pmTimestamp *tsp, __int32_t *buf) - { -@@ -1845,8 +1834,13 @@ __pmPutTimestamp(const __pmTimestamp *tsp, __int32_t *buf) - * need to dodge endian issues here ... want the MSB 32-bits of sec - * in buf[0] and the LSB 32 bits of sec in buf[1] - */ -- buf[0] = (stamp.sec >> 32) & 0xffffffff; -- buf[1] = stamp.sec & 0xffffffff; -+#if __BYTE_ORDER == __LITTLE_ENDIAN -+ buf[0] = (__int32_t)((__int64_t)(stamp.sec >> 32)); -+ buf[1] = (__int32_t)((__int64_t)(stamp.sec & 0x00000000ffffffffLL)); -+#else -+ buf[1] = (__int32_t)((__int64_t)(stamp.sec >> 32)); -+ buf[0] = (__int32_t)((__int64_t)(stamp.sec & 0x00000000ffffffffLL)); -+#endif - buf[2] = stamp.nsec; - if (pmDebugOptions.logmeta && pmDebugOptions.desperate) { - fprintf(stderr, "__pmPutTimestamp: %" FMT_INT64 ".%09d (%llx %x nsec)", tsp->sec, tsp->nsec, (long long)tsp->sec, tsp->nsec); -@@ -1854,6 +1848,17 @@ __pmPutTimestamp(const __pmTimestamp *tsp, __int32_t *buf) - } - } - -+void -+__pmLoadTimeval(const __int32_t *buf, __pmTimestamp *tsp) -+{ -+ tsp->sec = (__int32_t)ntohl(buf[0]); -+ tsp->nsec = ntohl(buf[1]) * 1000; -+ if (pmDebugOptions.logmeta && pmDebugOptions.desperate) { -+ fprintf(stderr, "__pmLoadTimeval: network(%08x %08x usec)", buf[0], buf[1]); -+ fprintf(stderr, " -> %" FMT_INT64 ".%09d (%llx %x nsec)\n", tsp->sec, tsp->nsec, (long long)tsp->sec, tsp->nsec); -+ } -+} -+ - void - __pmPutTimeval(const __pmTimestamp *tsp, __int32_t *buf) - { diff --git a/pcp-xsos-fixes.patch b/pcp-xsos-fixes.patch deleted file mode 100644 index cbe1038..0000000 --- a/pcp-xsos-fixes.patch +++ /dev/null @@ -1,269 +0,0 @@ -commit d2852e19e77e25d628399d51fcf199233547f8c4 -Author: Nathan Scott -Date: Wed Nov 13 17:17:28 2024 +1100 - - libpcp, pcp-xsos: finer grained string output control in pmPrintValue - - Implement a mechanism in pmPrintValue for producing single-line value - output, giving shell scripts a chance to operate sensibly with whacky - command lines. - - Resolves Red Hat bugs RHEL-67164 and RHEL-67148. - -diff --git a/man/man3/pmprintvalue.3 b/man/man3/pmprintvalue.3 -index 067b2aee2b..656c05849d 100644 ---- a/man/man3/pmprintvalue.3 -+++ b/man/man3/pmprintvalue.3 -@@ -80,6 +80,15 @@ and - pairs for each requested metric), based upon the - metrics type as returned from - .BR pmLookupDesc (3). -+.SH ENVIRONMENT -+Output of string metric values can be further controlled using -+.BR PCP_SQUASH_NEWLINES . -+When set in the environment of the calling process, and the -+.I type -+is set to PM_TYPE_STRING or PM_TYPE_AGGREGATE, then the output -+value is guaranteed to be free of embedded newline characters. -+If the given value contained such characters, they will have been -+replaced by a space before being printed. - .SH SEE ALSO - .BR PMAPI (3), - .BR pmAtomStr (3), -diff --git a/qa/1564 b/qa/1564 -index cbb976cfe4..714955223e 100755 ---- a/qa/1564 -+++ b/qa/1564 -@@ -117,5 +117,33 @@ pcp -a $archive xsos -x -n | _filter_net - echo === Archive pcp xsos -N - pcp -a $archive xsos -x -N | _filter_netstat - -+echo === Special case: eval command issues | tee -a $seq.full -+test -f /eperm && $sudo rm -f /eperm -+(./src/args \$\(touch /eperm\) )& -+argspid=$! -+$PCP_BINADM_DIR/pmsleep 0.25 # start args -+$sudo pcp xsos -x --ps >> $seq.full -+echo $? exit status -+test -f /eperm && echo file exists && $sudo rm -f /eperm -+$PCP_BINADM_DIR/pmsignal $argspid -+wait $argspid -+ -+echo === Special case: multiline ps issues | tee -a $seq.full -+(./src/args ' -+multi -+line -+args -+')& -+argspid=$! -+$PCP_BINADM_DIR/pmsleep 0.25 # start args -+pcp xsos -x --ps >> $seq.full -+echo $? exit status -+$PCP_BINADM_DIR/pmsignal $argspid -+wait $argspid -+ -+echo === Special case: command line errors | tee -a $seq.full -+pcp xsos unknown_arg >> $seq.full 2>&1 -+echo $? exit status -+ - # success, all done - exit -diff --git a/qa/1564.out b/qa/1564.out -index 57de00c30a..11321e342a 100644 ---- a/qa/1564.out -+++ b/qa/1564.out -@@ -111,3 +111,9 @@ NET STATS - Ip.InAddrErrors: XXX - Ip6.InAddrErrors: XXX - -+=== Special case: eval command issues -+0 exit status -+=== Special case: multiline ps issues -+0 exit status -+=== Special case: command line errors -+1 exit status -diff --git a/qa/src/.gitignore b/qa/src/.gitignore -index 7e9b0fe08a..3399d24a4e 100644 ---- a/qa/src/.gitignore -+++ b/qa/src/.gitignore -@@ -13,6 +13,7 @@ archend - archfetch - archinst - arch_maxfd -+args - atomstr - badUnitsStr_r - badloglabel -diff --git a/qa/src/GNUlocaldefs b/qa/src/GNUlocaldefs -index ae647278f2..ac0920d136 100644 ---- a/qa/src/GNUlocaldefs -+++ b/qa/src/GNUlocaldefs -@@ -48,7 +48,7 @@ CFILES = disk_test.c exercise.c context_test.c chkoptfetch.c \ - archctl_segfault.c debug.c int2pmid.c int2indom.c exectest.c \ - unpickargs.c hanoi.c progname.c countmark.c check_attribute.c \ - indom2int.c pmid2int.c scanmeta.c traverse_return_codes.c \ -- timeshift.c checkstructs.c bcc_profile.c sha1int2ext.c \ -+ timeshift.c checkstructs.c bcc_profile.c args.c sha1int2ext.c \ - getdomainname.c profilecrash.c store_and_fetch.c test_service_notify.c \ - ctx_derive.c pmstrn.c pmfstring.c pmfg-derived.c mmv_help.c sizeof.c \ - stampconv.c time_stamp.c archend.c scandata.c wait_for_values.c \ -diff --git a/qa/src/args.c b/qa/src/args.c -new file mode 100644 -index 0000000000..06d9b9b6cc ---- /dev/null -+++ b/qa/src/args.c -@@ -0,0 +1,18 @@ -+/* -+ * Copyright (c) 2024 Red Hat. -+ * -+ * QA helper that waits for stdin input then exits, useful for -+ * shell escape testing as it allows arbitrary args (ignored). -+ */ -+ -+#include -+#include -+#include -+ -+int -+main(int argc, char **argv) -+{ -+ while (1) -+ sleep(1); -+ exit(EXIT_SUCCESS); -+} -diff --git a/src/libpcp/src/check-statics b/src/libpcp/src/check-statics -index 29dcb868ad..b9f21edc32 100755 ---- a/src/libpcp/src/check-statics -+++ b/src/libpcp/src/check-statics -@@ -581,6 +581,8 @@ util.o - msgbuf # guarded by util_lock mutex - msgbuflen # guarded by util_lock mutex - msgsize # guarded by util_lock mutex -+ squashed # guarded by __pmLock_extcall mutex when set -+ # in a one-trip initialization - filename # guarded by __pmLock_extcall mutex when set - # in a one-trip initialization - ?base # no unsafe side-effects, see notes in util.c -diff --git a/src/libpcp/src/util.c b/src/libpcp/src/util.c -index d4f79ca40d..84a7df6329 100644 ---- a/src/libpcp/src/util.c -+++ b/src/libpcp/src/util.c -@@ -984,6 +984,18 @@ print_event_summary(FILE *f, const pmValue *val, int highres) - fputc(']', f); - } - -+static void -+squash_string(char *s, unsigned int len) -+{ -+ unsigned int i; -+ -+ /* replace end-of-line characters */ -+ for (i = 0; i < len; i++) { -+ if (isspace(s[i])) -+ s[i] = ' '; -+ } -+} -+ - /* Print single pmValue. */ - void - pmPrintValue(FILE *f, /* output stream */ -@@ -997,6 +1009,16 @@ pmPrintValue(FILE *f, /* output stream */ - int n; - char *p; - int sts; -+ static int squashed = -1; -+ -+ if (squashed == -1) { -+ /* one-trip initialization */ -+ PM_LOCK(__pmLock_extcall); -+ squashed = 0; -+ if (getenv("PCP_SQUASH_NEWLINES") != NULL) /* THREADSAFE */ -+ squashed = 1; -+ PM_UNLOCK(__pmLock_extcall); -+ } - - if (type != PM_TYPE_UNKNOWN && - type != PM_TYPE_EVENT && -@@ -1032,7 +1054,10 @@ pmPrintValue(FILE *f, /* output stream */ - break; - - case PM_TYPE_STRING: -- n = (int)strlen(a.cp) + 2; -+ n = (int)strlen(a.cp); -+ if (squashed) -+ squash_string(a.cp, n); -+ n += 2; - while (n < minwidth) { - fputc(' ', f); - n++; -@@ -1123,6 +1148,8 @@ pmPrintValue(FILE *f, /* output stream */ - n++; - } - n = (int)val->value.pval->vlen - PM_VAL_HDR_SIZE; -+ if (squashed) -+ squash_string(val->value.pval->vbuf, n); - fprintf(f, "\"%*.*s\"", n, n, val->value.pval->vbuf); - done = 1; - } - -commit a55c5de05836ca0e71b052a4579b34f8e6577c23 -Merge: 3bcaee943a b147af9c8e -Author: Nathan Scott -Date: Wed Nov 13 16:49:57 2024 +1100 - - Merge commit 'b147af9c8e71423be9bb62699534d3fea4d86b8a' into xsos - - -commit b147af9c8e71423be9bb62699534d3fea4d86b8a -Author: Nathan Scott -Date: Wed Nov 13 16:49:57 2024 +1100 - - Squashed 'vendor/github.com/performancecopilot/xsos-pcp/' changes from deb8740f2f..de2b314859 - - de2b314859 pcp-xsos: fine-tune error handling on bad command line options - 35f2cefa3a pcp-xsos: single-line pmPrintValue/pminfo values, escape shell chars - - git-subtree-dir: vendor/github.com/performancecopilot/xsos-pcp - git-subtree-split: de2b314859d01dec9387e06da39af6920018d219 - -diff --git a/pcp-xsos b/pcp-xsos -index e8c60f1e0c..388712752d 100755 ---- a/vendor/github.com/performancecopilot/xsos-pcp/pcp-xsos -+++ b/vendor/github.com/performancecopilot/xsos-pcp/pcp-xsos -@@ -112,7 +112,6 @@ _usage() - { - [ ! -z "$@" ] && echo $@ 1>&2 - pmgetopt --progname=$progname --usage --config=$tmp/usage -- sts=0 - exit - } - -@@ -206,9 +205,11 @@ do - color=false - ;; - -\?) -+ sts=0 - _usage "" - ;; - --) # end of options, start of arguments -+ sts=1 - _usage "Unknown argument: $2" - ;; - esac -@@ -304,6 +305,7 @@ fi - # kernel_all_load_value[15]=0.06 - # kernel_cpu_util_user_error="No value(s) available!" - -+export PCP_SQUASH_NEWLINES=1 - if ! pminfo $batch --fetch ${metrics[*]} > $tmp/metrics 2>$tmp/error - then - if grep "^pminfo:" $tmp/error > /dev/null 2>&1 -@@ -320,6 +322,8 @@ gawk < $tmp/metrics > $tmp/variables ' - function filter(string) { - gsub(/"/, "\\\"", string) # escape double quotes - gsub(/\\u/, "\\\\u", string) # escape backslash-u -+ # replace any characters with special shell meaning -+ gsub("/\\(|\\$|\\*|)|\\{|\\}\\?|`|;|!/", "-", string) - gsub(/%/, "%%", string) # percent sign in printf - gsub(/^\\"|\\"$/, "\"", string) # except on ends - return string diff --git a/pcp.spec b/pcp.spec index 5dcbc43..86f806c 100644 --- a/pcp.spec +++ b/pcp.spec @@ -1,16 +1,20 @@ Name: pcp Version: 6.3.7 -Release: 4%{?dist} +Release: 5%{?dist} Summary: System-level performance monitoring and performance management License: GPL-2.0-or-later AND LGPL-2.1-or-later AND CC-BY-3.0 URL: https://pcp.io Source0: https://github.com/performancecopilot/pcp/releases/pcp-%{version}.src.tar.gz -Patch0: fix-pmdabpf-noarch-man-page-build-failure.patch -Patch1: selinux-proc_psi_t.patch -Patch2: pcp-filter-exact.patch -Patch3: pcp_openmetrics.patch +Patch0: selinux-proc_psi_t.patch +Patch1: selinux-pcp_pmie_t.patch +Patch2: pmwebapi-filter-exact.patch +Patch3: pmda-openmetrics-rollup.patch +Patch4: pmapi-header-multilib-fix.patch +Patch5: python-pmda-wrapper-list-fix.patch +Patch6: systemd-tmpfiles.d-directories.patch +Patch7: fix-pmdabpf-noarch-man-page-build-failure.patch %if 0%{?fedora} >= 40 || 0%{?rhel} >= 10 ExcludeArch: %{ix86} @@ -366,6 +370,8 @@ Requires: pcp-selinux = %{version}-%{release} %global _ieconfdir %{_localstatedir}/lib/pcp/config/pmieconf %global _selinuxdir %{_datadir}/selinux/packages/targeted +%global _with_multilib --enable-multilib=true + %if 0%{?fedora} >= 20 || 0%{?rhel} >= 8 %global _with_doc --with-docdir=%{_docdir}/%{name} %endif @@ -2501,7 +2507,7 @@ sed -i "/PACKAGE_BUILD/s/=[0-9]*/=$_build/" VERSION.pcp %if !%{disable_python2} && 0%{?default_python} != 3 export PYTHON=python%{?default_python} %endif -%configure %{?_with_initd} %{?_with_doc} %{?_with_dstat} %{?_with_ib} %{?_with_gfs2} %{?_with_statsd} %{?_with_perfevent} %{?_with_bcc} %{?_with_bpf} %{?_with_bpftrace} %{?_with_json} %{?_with_mongodb} %{?_with_mysql} %{?_with_snmp} %{?_with_nutcracker} %{?_with_python2} +%configure %{?_with_multilib} %{?_with_initd} %{?_with_doc} %{?_with_dstat} %{?_with_ib} %{?_with_gfs2} %{?_with_statsd} %{?_with_perfevent} %{?_with_bcc} %{?_with_bpf} %{?_with_bpftrace} %{?_with_json} %{?_with_mongodb} %{?_with_mysql} %{?_with_snmp} %{?_with_nutcracker} %{?_with_python2} make %{?_smp_mflags} default_pcp %install @@ -3244,7 +3250,11 @@ for PMDA in dm nfsclient openmetrics ; do fi done # managed via /usr/lib/systemd/system-preset/90-default.preset nowadays: -%if 0%{?rhel} > 0 && 0%{?rhel} < 10 +%if 0%{?fedora} > 40 || 0%{?rhel} > 9 + for s in pmcd pmlogger pmie; do + systemctl --quiet is-enabled $s && systemctl restart $s >/dev/null 2>&1 + done +%else # old-school methods follow %if !%{disable_systemd} systemctl restart pmcd pmlogger pmie >/dev/null 2>&1 systemctl enable pmcd pmlogger pmie >/dev/null 2>&1 @@ -3615,6 +3625,13 @@ fi %files zeroconf -f pcp-zeroconf-files.rpm %changelog +* Fri Jun 27 2025 Nathan Scott - 6.3.7-5 +- Make pcp-zeroconf start enabled services once again (RHEL-93182) +- Fix python PMDA wrapper handling of list objects +- Improve tmpfiles.d handling of empty directories +- Backport some more fixes to the OpenMetrics PMDA +- Fix a multilib regression in PCP header files + * Wed Apr 30 2025 Lauren Chilton - 6.3.7-4 - Backport metric removal for pmdaopenmetrics diff --git a/pcp_openmetrics.patch b/pcp_openmetrics.patch deleted file mode 100644 index d2b55dd..0000000 --- a/pcp_openmetrics.patch +++ /dev/null @@ -1,278 +0,0 @@ -commit 26e7f6e58be9237c2fd37ae8a98b7941f0ff1345 -Author: lmchilton -Date: Mon Apr 14 10:46:11 2025 -0400 - - added logic to support metric removal in pmdaopenmetrics. - A bug was discovered during development: the PMDA - did not support metric re-addition. So, logic was - added to address that scenario. Additionally, QA test - 1976 was added to the testsuite. - - Addressed changes from PR review. Tested with a script and found/fixed a bug. - -diff --git a/qa/1976 b/qa/1976 -new file mode 100755 -index 000000000..1427ef119 ---- /dev/null -+++ b/qa/1976 -@@ -0,0 +1,90 @@ -+#!/bin/sh -+# PCP QA Test No. 1976 -+# test pmdaopenmetrics metric removal -+# -+# Copyright (c) 2017, 2025 Red Hat. All Rights Reserved. -+# -+# Note: if anything gets added or changed in qa/openmetrics/samples directory, -+# then this test (and all tests in group pmda.openmetrics) will need to be remade. -+ -+seq=`basename $0` -+echo "QA output created by $seq" -+ -+# get standard environment, filters and checks -+. ./common.openmetrics -+ -+_pmdaopenmetrics_check || _notrun "openmetrics pmda not installed" -+ -+status=1 # failure is the default! -+ -+_cleanup() -+{ -+ cd $here -+ _pmdaopenmetrics_cleanup -+ $sudo rm -rf $tmp $tmp.* -+} -+ -+_prepare_pmda openmetrics -+trap "_cleanup; exit \$status" 0 1 2 3 15 -+_stop_auto_restart pmcd -+ -+_pmdaopenmetrics_save_config -+ -+# add all the sample text files as urls. -+# need to be a place the user $PCP_USER (pmcd) can read -+# -+( cd $here/openmetrics/samples; ls -1 *.txt ) | sort | while read file -+do -+ cp $here/openmetrics/samples/$file $tmp.$file -+ urlbase=`basename "$file" .txt | tr .- _` -+ echo 'file://'$tmp.$file >$tmp.tmp -+ $sudo cp $tmp.tmp $PCP_PMDAS_DIR/openmetrics/config.d/$urlbase.url -+done -+ls -l $PCP_PMDAS_DIR/openmetrics/config.d >>$seq_full -+ -+# add all the sample scripts -+cp -a $here/openmetrics/scripts/* $PCP_PMDAS_DIR/openmetrics/config.d -+find $PCP_PMDAS_DIR/openmetrics/config.d -name GNU\* -exec rm -f {} ";" -+ -+_pmdaopenmetrics_install -+ -+if ! _pmdaopenmetrics_wait_for_metric openmetrics.thermostat -+then -+ status=1 -+ exit -+fi -+ -+echo "-- metric removal of new source/metric --" -+$sudo rm $PCP_PMDAS_DIR/openmetrics/config.d/simple_metric.url -+if pminfo openmetrics | grep openmetrics.simple_metric -+then -+ echo "metric removal failed..exiting" -+ status=1 -+ exit -+else -+ echo "metric removal success" -+fi -+echo -+ -+echo "-- source re-addition --" -+path=$here/openmetrics/samples/simple_metric.txt -+echo 'file:///'$path > $PCP_PMDAS_DIR/openmetrics/config.d/simple_metric.url -+pminfo openmetrics.simple_metric -+echo -+ -+echo "-- metric removal of recognized source/metric --" -+$sudo rm $PCP_PMDAS_DIR/openmetrics/config.d/simple_metric.url -+if pminfo openmetrics | grep openmetrics.simple_metric -+then -+ echo "metric removal failed..exiting" -+ status=1 -+ exit -+else -+ echo "metric removal success" -+fi -+ -+_pmdaopenmetrics_remove >/dev/null 2>&1 -+ -+# success, all done -+status=0 -+exit -diff --git a/qa/1976.out b/qa/1976.out -new file mode 100644 -index 000000000..bcfe03f8d ---- /dev/null -+++ b/qa/1976.out -@@ -0,0 +1,11 @@ -+QA output created by 1976 -+ -+=== openmetrics agent installation === -+-- metric removal of new source/metric -- -+metric removal success -+ -+-- source re-addition -- -+openmetrics.simple_metric.metric1 -+ -+-- metric removal of recognized source/metric -- -+metric removal success -diff --git a/qa/group b/qa/group -index 55828846a..83c8f2e8a 100644 ---- a/qa/group -+++ b/qa/group -@@ -2216,6 +2216,7 @@ pmcd.pdu - 1963 pmda.linux local - 1970 pmda.bpf local - 1973 pcp zoneinfo python local -+1976 pmdaopenmetrics python local - 1978 atop local pmlogrewrite - 1984 pmlogconf pmda.redis local - 1985 pmfind local valgrind -diff --git a/src/pmdas/openmetrics/pmdaopenmetrics.python b/src/pmdas/openmetrics/pmdaopenmetrics.python -index c33a56400..a9e65af93 100755 ---- a/src/pmdas/openmetrics/pmdaopenmetrics.python -+++ b/src/pmdas/openmetrics/pmdaopenmetrics.python -@@ -127,15 +127,9 @@ class Metric(object): - (name, pmContext.pmIDStr(self.pmid), self.mtype, self.msem, self.singular, self.mindom, self.labels)) - - self.obj = pmdaMetric(self.pmid, self.mtype, self.mindom, self.msem, self.munits) -+ self.source.pmda.all_metrics[self.mname] = self.obj - -- if helpline: # it could be None! -- unescaped = helpline.replace('\\\\', '\\').replace('\\n', '\n') -- split = unescaped.split('\n') -- help_oneline = split[0] # must have at least one entry -- help_text = '\n'.join(split[1:]) # may have other entries -- else: -- help_oneline = '' -- help_text = '' -+ help_text, help_oneline = self.source.helptext(helpline) - - try: - self.source.pmda.add_metric(self.mname, self.obj, help_oneline, help_text) -@@ -588,6 +582,16 @@ class Source(object): - self.metrics_by_name = {} # name -> Metric - self.metrics_by_num = {} # number (last component of pmid) -> Metric - -+ def helptext(self, helpline): -+ if helpline: # it could be None! -+ unescaped = helpline.replace('\\\\', '\\').replace('\\n', '\n') -+ split = unescaped.split('\n') -+ help_oneline = split[0] # must have at least one entry -+ help_text = '\n'.join(split[1:]) # may have other entries -+ else: -+ help_oneline = '' -+ help_text = '' -+ return help_text, help_oneline - - def old_enough_for_refresh(self): - '''But what is "old"? If it is empty (no metrics), then it -@@ -685,6 +689,23 @@ class Source(object): - self.pmda.debug("included_labels '%s'" % (included_labels)) if self.pmda.dbg else None - self.pmda.debug("optional_labels '%s'" % (optional_labels)) if self.pmda.dbg else None - if sp.name in self.metrics_by_name: -+ if ("openmetrics.%s.%s" % (self.name, sp.name)) not in self.pmda.all_metrics and self.name in self.pmda.re_add_list: -+ # re-add metric to namespace -+ if pcpline: -+ split = pcpline.split(" ") -+ fullname = "openmetrics.%s.%s" % (self.name, split[1]) -+ else: -+ fullname = "openmetrics.%s.%s" % (self.name, sp.name.replace(":", ".")) -+ help_oneline, help_text = self.helptext(helpline) -+ try: -+ obj = self.pmda.removed_metrics[fullname] -+ self.pmda.add_metric(fullname, obj, help_oneline, help_text) -+ self.pmda.debug("re-adding metric: %s to namespace" % fullname) if self.pmda.dbg else None -+ self.pmda.all_metrics[fullname] = obj -+ del self.pmda.removed_metrics[fullname] -+ self.pmda.set_need_refresh() -+ except Exception as e: -+ self.pmda.debug("Can't re-add metric: %s, see error: %s" % (fullname, e)) if self.pmda.dbg else None - m = self.metrics_by_name[sp.name] - assert self.metrics_by_num[m.metricnum] == m - if m.singular: -@@ -693,6 +714,7 @@ class Source(object): - else: - m.store_inst(naming_labels, sp.value) - self.pmda.debug("naming_labels '%s'" % (naming_labels)) if self.pmda.dbg else None -+ # new metric case - else: - # check metric is not excluded by filters - fullname = "openmetrics.%s.%s" % (self.name, sp.name) -@@ -1014,6 +1036,10 @@ class OpenMetricsPMDA(PMDA): - reserved_cluster = self.cluster_table.intern_lookup_value("control") - assert reserved_cluster == 0 - self.source_by_cluster = {} -+ # all metrics added, to be used for removal -+ self.all_metrics = {} -+ # keep track of removed metrics, in case of re-addition -+ self.removed_metrics = {} - - # compiled regex cache - self.regex_cache = {} -@@ -1148,8 +1174,40 @@ class OpenMetricsPMDA(PMDA): - - self.log("Config change detected, traversed %d config entries in %.04fs, rescanning ..." % (len(conf_filelist), traverse_time)) - nickname_regexp = self.lookup_regex(r"^[A-Za-z][A-Za-z0-9_.]*$") -+ self.re_add_list = [] -+ -+ # calculate config entry nicknames -+ nicknames = [] -+ for file in conf_filelist: -+ file_split = os.path.splitext(file) -+ name = file_split[0].replace(self.config_dir + "/", "").replace("/", ".") -+ nicknames.append(name) -+ -+ # check if config change adds a previously removed source -+ for key in self.removed_metrics: -+ split_name = key.split(".") -+ if split_name[1] in nicknames: -+ self.re_add_list.append(split_name[1]) -+ -+ # if source is not in config directory, remove the metric -+ for key, value in self.all_metrics.items(): -+ split_name = key.split(".") -+ if split_name[1] in nicknames: -+ continue -+ try: -+ remove_name = key -+ remove_obj = value -+ self.remove_metric(remove_name, remove_obj) -+ self.removed_metrics[remove_name] = remove_obj -+ self.debug("removed metric name: %s" % remove_name) if self.dbg else None -+ self.set_need_refresh() -+ except Exception as e: -+ self.debug("can't remove metric: %s, see error: %s" % (key, e)) if self.dbg else None -+ -+ for key in self.removed_metrics: -+ if key in self.all_metrics: -+ del self.all_metrics[key] - -- # TODO: maybe nuke sources related to removed files - save_cluster_table = False - if sort_conf_list: - # sorted for indom cluster consistency -@@ -1177,6 +1235,16 @@ class OpenMetricsPMDA(PMDA): - if name in self.source_by_name: - # this source is already known - self.assert_source_invariants(name=name) -+ s = self.source_by_name[name] -+ cluster_for_refresh = [] -+ cluster_for_refresh_names = [] -+ if name in self.re_add_list: -+ for key,value in self.source_by_cluster.items(): -+ if value == s: -+ cluster_for_refresh.append(key) -+ cluster_for_refresh_names.append(name) -+ self.debug("refreshing cluster list: %s" % cluster_for_refresh_names) if self.dbg else None -+ self.refresh_some_clusters_for_fetch(cluster_for_refresh) - else: - try: - path = file diff --git a/pmapi-header-multilib-fix.patch b/pmapi-header-multilib-fix.patch new file mode 100644 index 0000000..b26db21 --- /dev/null +++ b/pmapi-header-multilib-fix.patch @@ -0,0 +1,202 @@ +diff -Naurp pcp-6.3.7.orig/configure pcp-6.3.7/configure +--- pcp-6.3.7.orig/configure 2025-03-31 12:41:26.000000000 +1100 ++++ pcp-6.3.7/configure 2025-06-26 19:38:57.864414825 +1000 +@@ -932,6 +932,7 @@ sed + SED + awk + AWK ++enable_multilib + enable_shared + cxx + ac_ct_CXX +@@ -1055,6 +1056,7 @@ enable_ssp + enable_pie + enable_visibility + enable_shared ++enable_multilib + with_perl_installdirs + with_perl_install_base + with_python_prefix +@@ -1748,7 +1750,8 @@ Optional Features: + --disable-ssp disable gcc stack-protector + --disable-pie disable position-independent-executable + --disable-visibility disable gcc symbol visibility +- --disable-shared disable core shared libary generation ++ --disable-shared disable core shared library generation ++ --enable-multilib enable multilib installations + + Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] +@@ -5696,6 +5699,21 @@ else case e in #( + esac + fi + ++ ++ ++# Check whether --enable-multilib was given. ++if test ${enable_multilib+y} ++then : ++ enableval=$enable_multilib; PACKAGE_CONFIGURE="$PACKAGE_CONFIGURE --enable-multilib=$withval" ++ ++printf "%s\n" "#define HAVE_MULTILIB 1" >>confdefs.h ++ ++ enable_multilib=true ++else case e in #( ++ e) enable_multilib=false ;; ++esac ++fi ++ + + + +diff -Naurp pcp-6.3.7.orig/configure.ac pcp-6.3.7/configure.ac +--- pcp-6.3.7.orig/configure.ac 2025-03-31 12:41:26.000000000 +1100 ++++ pcp-6.3.7/configure.ac 2025-06-26 19:38:57.867577540 +1000 +@@ -655,11 +655,20 @@ AC_LANG_POP([C++]) + + dnl Prevent shared libraries from being built for libpcp and other core libraries + AC_ARG_ENABLE([shared], +- [AS_HELP_STRING([--disable-shared], [disable core shared libary generation])], ++ [AS_HELP_STRING([--disable-shared], [disable core shared library generation])], + [PACKAGE_CONFIGURE="$PACKAGE_CONFIGURE --disable-shared=$withval"], + [enable_shared=false]) + AC_SUBST(enable_shared) + ++dnl Support installing both devel package variants on either 32/64 bit platform ++AC_ARG_ENABLE([multilib], ++ [AS_HELP_STRING([--enable-multilib], [enable multilib installations])], ++ [PACKAGE_CONFIGURE="$PACKAGE_CONFIGURE --enable-multilib=$withval" ++ AC_DEFINE(HAVE_MULTILIB, [1], [multilib defined]) ++ enable_multilib=true], ++ [enable_multilib=false]) ++AC_SUBST(enable_multilib) ++ + dnl check if user wants to use any of their own commands; + dnl ordering is important: some tests use earlier results + +diff -Naurp pcp-6.3.7.orig/src/include/builddefs.in pcp-6.3.7/src/include/builddefs.in +--- pcp-6.3.7.orig/src/include/builddefs.in 2025-03-27 17:01:59.000000000 +1100 ++++ pcp-6.3.7/src/include/builddefs.in 2025-06-26 19:38:57.869743878 +1000 +@@ -259,6 +259,7 @@ QT_VERSION = @qt_version@ + CLANG_MAJOR_VERSION = @CLANG_MAJOR_VERSION@ + + # configuration state affecting the entire build ++ENABLE_MULTILIB = @enable_multilib@ + ENABLE_SHARED = @enable_shared@ + ENABLE_SECURE = @enable_secure@ + ENABLE_PROBES = @enable_probes@ +diff -Naurp pcp-6.3.7.orig/src/include/pcp/config32.h pcp-6.3.7/src/include/pcp/config32.h +--- pcp-6.3.7.orig/src/include/pcp/config32.h 2024-07-30 16:43:55.000000000 +1000 ++++ pcp-6.3.7/src/include/pcp/config32.h 2025-06-26 19:38:57.871096964 +1000 +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2014,2016 Red Hat. ++ * Copyright (c) 2014,2016,2025 Red Hat. + * Headers for "multilib" support (32-bit and 64-bit packages co-existing) + * + * This library is free software; you can redistribute it and/or modify it +@@ -19,5 +19,7 @@ + #define HAVE_32BIT_LONG 1 + #define HAVE_32BIT_PTR 1 + /* #undef HAVE_64BIT_PTR */ ++#define PM_PAD_RESULT 4 ++#define PM_PAD_TIMESPEC 4 + + #endif /* PCP_CONFIG32_H */ +diff -Naurp pcp-6.3.7.orig/src/include/pcp/config64.h pcp-6.3.7/src/include/pcp/config64.h +--- pcp-6.3.7.orig/src/include/pcp/config64.h 2024-07-30 16:43:55.000000000 +1000 ++++ pcp-6.3.7/src/include/pcp/config64.h 2025-06-26 19:38:57.871276548 +1000 +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2014,2016 Red Hat. ++ * Copyright (c) 2014,2016,2025 Red Hat. + * Headers for "multilib" support (32-bit and 64-bit packages co-existing) + * + * This library is free software; you can redistribute it and/or modify it +@@ -19,5 +19,7 @@ + /* #undef HAVE_32BIT_LONG */ + /* #undef HAVE_32BIT_PTR */ + #define HAVE_64BIT_PTR 1 ++/* #undef PM_PAD_RESULT */ ++/* #undef PM_PAD_TIMESPEC */ + + #endif /* PCP_CONFIG64_H */ +diff -Naurp pcp-6.3.7.orig/src/include/pcp/config.h.in pcp-6.3.7/src/include/pcp/config.h.in +--- pcp-6.3.7.orig/src/include/pcp/config.h.in 2025-03-14 14:41:06.000000000 +1100 ++++ pcp-6.3.7/src/include/pcp/config.h.in 2025-06-26 19:38:57.871702924 +1000 +@@ -792,6 +792,9 @@ + #undef HAVE__ETEXT + #undef HAVE_ETEXT + ++/* multilib headers */ ++#undef HAVE_MULTILIB ++ + /* sizeof suseconds_t ... only ever going to exist on linux-like systems */ + #undef PM_SIZEOF_SUSECONDS_T + +@@ -801,9 +804,3 @@ + #ifndef PM_SIZEOF_TIME_T + #error Unknown time_t size + #endif +- +-/* __pmResult padding */ +-#undef PM_PAD_RESULT +- +-/* timespec padding */ +-#undef PM_PAD_TIMESPEC +diff -Naurp pcp-6.3.7.orig/src/include/pcp/configsz.h.in pcp-6.3.7/src/include/pcp/configsz.h.in +--- pcp-6.3.7.orig/src/include/pcp/configsz.h.in 2024-07-30 16:43:55.000000000 +1000 ++++ pcp-6.3.7/src/include/pcp/configsz.h.in 2025-06-26 19:38:57.872742426 +1000 +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2014-2017 Red Hat. ++ * Copyright (c) 2014-2017,2025 Red Hat. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published +@@ -26,4 +26,10 @@ + /* pointer size */ + #undef HAVE_64BIT_PTR + ++/* __pmResult padding */ ++#undef PM_PAD_RESULT ++ ++/* timespec padding */ ++#undef PM_PAD_TIMESPEC ++ + #endif /* PCP_CONFIGSZ_H */ +diff -Naurp pcp-6.3.7.orig/src/include/pcp/GNUmakefile pcp-6.3.7/src/include/pcp/GNUmakefile +--- pcp-6.3.7.orig/src/include/pcp/GNUmakefile 2024-07-30 16:43:55.000000000 +1000 ++++ pcp-6.3.7/src/include/pcp/GNUmakefile 2025-06-26 19:38:57.873157593 +1000 +@@ -22,11 +22,16 @@ SDSH_HFILES = sds.h sdsalloc.h + EXTERNAL_HFILES = dict.h + HFILES = pmapi.h impl.h pmda.h pmtime.h pmdaroot.h pmafm.h \ + trace.h trace_dev.h mmv_stats.h mmv_dev.h import.h \ +- config32.h config64.h platform32.h platform64.h \ + pmjson.h pmhttp.h pmdbg.h pmwebapi.h deprecated.h \ + ini.h sds.h dict.h archive.h +-INFILES = config.h.in configsz.h.in platform_defs.h.in platformsz.h.in +-CONFFILES = config.h configsz.h platform_defs.h platformsz.h ++INFILES = config.h.in platform_defs.h.in ++CONFFILES = config.h platform_defs.h ++ifeq "$(ENABLE_MULTILIB)" "true" ++HFILES += config32.h config64.h platform32.h platform64.h ++else ++INFILES += configsz.h.in platformsz.h.in ++CONFFILES += configsz.h platformsz.h ++endif + GENERATED_HFILES = $(CONFFILES) + NOSHIP_HFILES = libpcp.h sdsalloc.h + +diff -Naurp pcp-6.3.7.orig/src/include/pcp/platform_defs.h.in pcp-6.3.7/src/include/pcp/platform_defs.h.in +--- pcp-6.3.7.orig/src/include/pcp/platform_defs.h.in 2025-03-31 12:41:26.000000000 +1100 ++++ pcp-6.3.7/src/include/pcp/platform_defs.h.in 2025-06-26 19:38:57.873423552 +1000 +@@ -36,7 +36,7 @@ extern "C" { + #define FMT_PID "@fmt_pid@" + #define FMT_PTHREAD "@fmt_pthread@" + +-#ifdef HAVE_BITS_WORDSIZE_H ++#if defined(HAVE_MULTILIB) && defined(HAVE_BITS_WORDSIZE_H) + #include + #if __WORDSIZE == 32 + #include "config32.h" diff --git a/pmda-openmetrics-rollup.patch b/pmda-openmetrics-rollup.patch new file mode 100644 index 0000000..e63f800 --- /dev/null +++ b/pmda-openmetrics-rollup.patch @@ -0,0 +1,465 @@ +diff -Naurp pcp-6.3.7.orig/qa/1976 pcp-6.3.7/qa/1976 +--- pcp-6.3.7.orig/qa/1976 1970-01-01 10:00:00.000000000 +1000 ++++ pcp-6.3.7/qa/1976 2025-06-26 18:02:39.313416612 +1000 +@@ -0,0 +1,85 @@ ++#!/bin/sh ++# PCP QA Test No. 1976 ++# Test pmdaopenmetrics metric removal ++# ++# Copyright (c) 2017, 2025 Red Hat. All Rights Reserved. ++# ++seq=`basename $0` ++echo "QA output created by $seq" ++ ++# get standard environment, filters and checks ++. ./common.openmetrics ++ ++_pmdaopenmetrics_check || _notrun "openmetrics pmda not installed" ++ ++status=1 # failure is the default! ++ ++_cleanup() ++{ ++ cd $here ++ _pmdaopenmetrics_cleanup ++ $sudo rm -rf $tmp $tmp.* ++} ++ ++_prepare_pmda openmetrics ++trap "_cleanup; exit \$status" 0 1 2 3 15 ++_stop_auto_restart pmcd ++ ++_pmdaopenmetrics_save_config ++ ++# add all the sample text files as urls. ++# need to be a place the user $PCP_USER (pmcd) can read ++# ++( cd $here/openmetrics/samples; ls -1 *.txt ) | sort | while read file ++do ++ cp $here/openmetrics/samples/$file $tmp.$file ++ urlbase=`basename "$file" .txt | tr .- _` ++ echo 'file://'$tmp.$file >$tmp.tmp ++ $sudo cp $tmp.tmp $PCP_PMDAS_DIR/openmetrics/config.d/$urlbase.url ++done ++ls -l $PCP_PMDAS_DIR/openmetrics/config.d >>$seq_full ++ ++# add all the sample scripts ++cp -a $here/openmetrics/scripts/* $PCP_PMDAS_DIR/openmetrics/config.d ++find $PCP_PMDAS_DIR/openmetrics/config.d -name GNU\* -exec rm -f {} ";" ++ ++_pmdaopenmetrics_install ++ ++if ! _pmdaopenmetrics_wait_for_metric openmetrics.thermostat ++then ++ status=1 ++ exit ++fi ++ ++echo "-- metric removal of new source/metric --" ++$sudo rm $PCP_PMDAS_DIR/openmetrics/config.d/simple_metric.url ++pminfo openmetrics.simple_metric ++echo ++ ++echo "-- source re-addition --" ++# same access controls logic as above, user $PCP_USER needs to be ++# able to read the file at the end of the URL ++# ++cp $here/openmetrics/samples/simple_metric.txt $tmp.simple_metric.txt ++echo 'file:///'$tmp.simple_metric.txt >$PCP_PMDAS_DIR/openmetrics/config.d/simple_metric.url ++pminfo openmetrics.simple_metric ++echo ++ ++echo "-- metric removal of recognized source/metric --" ++$sudo rm $PCP_PMDAS_DIR/openmetrics/config.d/simple_metric.url ++pminfo openmetrics.simple_metric ++echo ++ ++echo "-- source re-addition with epoch timestamp --" ++txtpath=$here/openmetrics/samples/simple_metric.txt ++urlfile=$PCP_PMDAS_DIR/openmetrics/config.d/simple_metric.url ++echo 'file:///'$txtpath > $urlfile ++$sudo touch -t 197001010000 $urlfile ++pminfo openmetrics.simple_metric ++echo ++ ++_pmdaopenmetrics_remove >/dev/null 2>&1 ++ ++# success, all done ++status=0 ++exit +diff -Naurp pcp-6.3.7.orig/qa/1976.out pcp-6.3.7/qa/1976.out +--- pcp-6.3.7.orig/qa/1976.out 1970-01-01 10:00:00.000000000 +1000 ++++ pcp-6.3.7/qa/1976.out 2025-06-26 18:02:01.879861640 +1000 +@@ -0,0 +1,17 @@ ++QA output created by 1976 ++ ++=== openmetrics agent installation === ++-- metric removal of new source/metric -- ++Error: openmetrics.simple_metric: Unknown metric name ++ ++-- source re-addition -- ++openmetrics.simple_metric.metric2 ++openmetrics.simple_metric.metric1 ++ ++-- metric removal of recognized source/metric -- ++Error: openmetrics.simple_metric: Unknown metric name ++ ++-- source re-addition with epoch timestamp -- ++openmetrics.simple_metric.metric2 ++openmetrics.simple_metric.metric1 ++ +diff -Naurp pcp-6.3.7.orig/qa/group pcp-6.3.7/qa/group +--- pcp-6.3.7.orig/qa/group 2025-06-26 17:55:37.790462638 +1000 ++++ pcp-6.3.7/qa/group 2025-06-26 17:58:18.996389423 +1000 +@@ -2205,6 +2205,7 @@ pmcd.pdu + 1963 pmda.linux local + 1970 pmda.bpf local + 1973 pcp zoneinfo python local ++1976 pmdaopenmetrics python local + 1978 atop local pmlogrewrite + 1984 pmlogconf pmda.redis local + 1985 pmfind local valgrind +diff -Naurp pcp-6.3.7.orig/qa/openmetrics/scripts/curl/script.sh pcp-6.3.7/qa/openmetrics/scripts/curl/script.sh +--- pcp-6.3.7.orig/qa/openmetrics/scripts/curl/script.sh 2023-11-16 17:51:39.000000000 +1100 ++++ pcp-6.3.7/qa/openmetrics/scripts/curl/script.sh 2025-06-26 18:02:50.155355973 +1000 +@@ -1,4 +1,4 @@ + #! /bin/sh + + . /etc/pcp.conf +-curl -Gq file://$PCP_PMDAS_DIR/openmetrics/config.d/some_metric.txt ++curl -Gqs file://$PCP_PMDAS_DIR/openmetrics/config.d/some_metric.txt +diff -Naurp pcp-6.3.7.orig/qa/openmetrics/scripts/curl_filtered.sh pcp-6.3.7/qa/openmetrics/scripts/curl_filtered.sh +--- pcp-6.3.7.orig/qa/openmetrics/scripts/curl_filtered.sh 2023-11-16 17:51:39.000000000 +1100 ++++ pcp-6.3.7/qa/openmetrics/scripts/curl_filtered.sh 2025-06-26 18:02:50.155694515 +1000 +@@ -7,6 +7,6 @@ + + . /etc/pcp.conf + +-( curl -Gq file://$PCP_PMDAS_DIR/openmetrics/config.d/some_metric.txt ; \ +-curl -Gq file://$PCP_PMDAS_DIR/openmetrics/config.d/some_other_metric.txt) \ ++( curl -Gqs file://$PCP_PMDAS_DIR/openmetrics/config.d/some_metric.txt ; \ ++curl -Gqs file://$PCP_PMDAS_DIR/openmetrics/config.d/some_other_metric.txt) \ + | sed -e '/metric2/d' +diff -Naurp pcp-6.3.7.orig/qa/openmetrics/scripts/curl_hostname_label.sh pcp-6.3.7/qa/openmetrics/scripts/curl_hostname_label.sh +--- pcp-6.3.7.orig/qa/openmetrics/scripts/curl_hostname_label.sh 2023-11-16 17:51:39.000000000 +1100 ++++ pcp-6.3.7/qa/openmetrics/scripts/curl_hostname_label.sh 2025-06-26 18:02:50.155942641 +1000 +@@ -12,5 +12,5 @@ + + # here for QA purposes we're fetching from a local file + # and just pretending it came from a remote host. +-curl -q -G file://$PCP_PMDAS_DIR/openmetrics/config.d/some_metric.txt 2>/dev/null | \ ++curl -Gqs file://$PCP_PMDAS_DIR/openmetrics/config.d/some_metric.txt 2>/dev/null | \ + sed -e 's/[a-z0-9]*=/hostname="remotehost",&/' +diff -Naurp pcp-6.3.7.orig/qa/openmetrics/scripts/curl_scripted.sh pcp-6.3.7/qa/openmetrics/scripts/curl_scripted.sh +--- pcp-6.3.7.orig/qa/openmetrics/scripts/curl_scripted.sh 2023-11-16 17:51:39.000000000 +1100 ++++ pcp-6.3.7/qa/openmetrics/scripts/curl_scripted.sh 2025-06-26 18:02:50.156229975 +1000 +@@ -1,5 +1,5 @@ + #! /bin/sh + + . /etc/pcp.conf +-curl -Gq file://$PCP_PMDAS_DIR/openmetrics/config.d/some_metric.txt +-curl -Gq file://$PCP_PMDAS_DIR/openmetrics/config.d/some_other_metric.txt ++curl -Gqs file://$PCP_PMDAS_DIR/openmetrics/config.d/some_metric.txt ++curl -Gqs file://$PCP_PMDAS_DIR/openmetrics/config.d/some_other_metric.txt +diff -Naurp pcp-6.3.7.orig/src/pmdas/openmetrics/pmdaopenmetrics.python pcp-6.3.7/src/pmdas/openmetrics/pmdaopenmetrics.python +--- pcp-6.3.7.orig/src/pmdas/openmetrics/pmdaopenmetrics.python 2025-06-26 17:55:37.790973098 +1000 ++++ pcp-6.3.7/src/pmdas/openmetrics/pmdaopenmetrics.python 2025-06-26 18:02:26.571388227 +1000 +@@ -32,7 +32,8 @@ import subprocess + import sys + from ctypes import c_int + from socket import gethostname +-from stat import ST_MODE, S_IXUSR, ST_CTIME ++from urllib.parse import urlparse ++from stat import ST_MODE, S_IXUSR + import requests + + from pcp.pmapi import pmUnits, pmContext +@@ -127,15 +128,9 @@ class Metric(object): + (name, pmContext.pmIDStr(self.pmid), self.mtype, self.msem, self.singular, self.mindom, self.labels)) + + self.obj = pmdaMetric(self.pmid, self.mtype, self.mindom, self.msem, self.munits) ++ self.source.pmda.all_metrics[self.mname] = self.obj + +- if helpline: # it could be None! +- unescaped = helpline.replace('\\\\', '\\').replace('\\n', '\n') +- split = unescaped.split('\n') +- help_oneline = split[0] # must have at least one entry +- help_text = '\n'.join(split[1:]) # may have other entries +- else: +- help_oneline = '' +- help_text = '' ++ help_text, help_oneline = self.source.helptext(helpline) + + try: + self.source.pmda.add_metric(self.mname, self.obj, help_oneline, help_text) +@@ -565,7 +560,7 @@ class Source(object): + self.path = path # pathname to .url or executable file + self.url = None + self.parse_error = False +- self.parse_url_time = 0 # timestamp of config file when it was last parsed ++ self.parse_time = None # last time config file was parsed + self.is_scripted = is_scripted + self.pmda = thispmda # the shared pmda + self.requests = None +@@ -588,6 +583,16 @@ class Source(object): + self.metrics_by_name = {} # name -> Metric + self.metrics_by_num = {} # number (last component of pmid) -> Metric + ++ def helptext(self, helpline): ++ if helpline: # it could be None! ++ unescaped = helpline.replace('\\\\', '\\').replace('\\n', '\n') ++ split = unescaped.split('\n') ++ help_oneline = split[0] # must have at least one entry ++ help_text = '\n'.join(split[1:]) # may have other entries ++ else: ++ help_oneline = '' ++ help_text = '' ++ return help_text, help_oneline + + def old_enough_for_refresh(self): + '''But what is "old"? If it is empty (no metrics), then it +@@ -685,6 +690,23 @@ class Source(object): + self.pmda.debug("included_labels '%s'" % (included_labels)) if self.pmda.dbg else None + self.pmda.debug("optional_labels '%s'" % (optional_labels)) if self.pmda.dbg else None + if sp.name in self.metrics_by_name: ++ if ("openmetrics.%s.%s" % (self.name, sp.name)) not in self.pmda.all_metrics and self.name in self.pmda.re_add_list: ++ # re-add metric to namespace ++ if pcpline: ++ split = pcpline.split(" ") ++ fullname = "openmetrics.%s.%s" % (self.name, split[1]) ++ else: ++ fullname = "openmetrics.%s.%s" % (self.name, sp.name.replace(":", ".")) ++ help_oneline, help_text = self.helptext(helpline) ++ try: ++ obj = self.pmda.removed_metrics[fullname] ++ self.pmda.add_metric(fullname, obj, help_oneline, help_text) ++ self.pmda.debug("re-adding metric: %s to namespace" % fullname) if self.pmda.dbg else None ++ self.pmda.all_metrics[fullname] = obj ++ del self.pmda.removed_metrics[fullname] ++ self.pmda.set_need_refresh() ++ except Exception as e: ++ self.pmda.debug("Can't re-add metric: %s, see error: %s" % (fullname, e)) if self.pmda.dbg else None + m = self.metrics_by_name[sp.name] + assert self.metrics_by_num[m.metricnum] == m + if m.singular: +@@ -693,6 +715,7 @@ class Source(object): + else: + m.store_inst(naming_labels, sp.value) + self.pmda.debug("naming_labels '%s'" % (naming_labels)) if self.pmda.dbg else None ++ # new metric case + else: + # check metric is not excluded by filters + fullname = "openmetrics.%s.%s" % (self.name, sp.name) +@@ -800,9 +823,9 @@ class Source(object): + + return num_metrics + +- def parse_url_config(self, filepath): ++ def parse_config(self, filepath): + ''' +- Parse a URL config file. The first line is always the URL. ++ Parse a configuration file. The first line is always the URL. + Remaining lines are prefixed with a keyword. Supported keywords + include '#' for a comment, 'HEADER:' to add to the header passed + to the headers dict parameter to the get() call. Note the ':' are +@@ -900,12 +923,12 @@ class Source(object): + if not s[ST_MODE] & S_IXUSR: + self.pmda.err("cannot execute script '%s'" % self.path) + return +- elif self.parse_url_time < s[ST_CTIME]: ++ elif self.parse_time is None or self.parse_time < s.st_mtime_ns: + # (re)parse the URL from given file +- self.parse_url_config(self.path) +- self.parse_url_time = s[ST_CTIME] ++ self.parse_config(self.path) ++ self.parse_time = s.st_mtime_ns + except Exception as e: +- self.pmda.err("cannot read %s: %s" % (self.path, e)) ++ self.pmda.err("cannot stat %s: %s" % (self.path, e)) + return + + # fetch the document +@@ -1001,7 +1024,7 @@ class OpenMetricsPMDA(PMDA): + # now everything else may take time + self.pmda_name = pmda_name + self.config_dir = os.path.normpath(config) +- self.config_dir_ctime = None ++ self.config_dir_mtime = 0.0 + self.timeout = timeout + + # a single central Session that all our sources can concurrently reuse +@@ -1014,6 +1037,11 @@ class OpenMetricsPMDA(PMDA): + reserved_cluster = self.cluster_table.intern_lookup_value("control") + assert reserved_cluster == 0 + self.source_by_cluster = {} ++ # all metrics added, to be used for removal ++ self.all_metrics = {} ++ # keep track of removed metrics, in case of re-addition ++ self.removed_metrics = {} ++ self.controls = {0:0} + + # compiled regex cache + self.regex_cache = {} +@@ -1106,26 +1134,53 @@ class OpenMetricsPMDA(PMDA): + assert s == self.source_by_name[s.name] + + +- def traverse(self, directory, ctime): ++ def traverse(self, directory, mtime): + ''' Return list of files below dir, recursively ''' + ret = [] +- m = os.path.getctime(directory) +- if ctime is None or m > ctime: +- ctime = m ++ m = os.path.getmtime(directory) ++ if mtime is None or m > mtime: ++ mtime = m + + for path, subdirs, files in os.walk(directory): + for f in files: + if not f.startswith("."): + fname = os.path.join(path, f) +- m = os.path.getctime(fname) +- if ctime is None or m > ctime: +- ctime = m ++ m = os.path.getmtime(fname) ++ if mtime is None or m > mtime: ++ mtime = m + ret.append(fname) ++ fname = os.path.join(path, f) ++ with open(fname, 'r') as name: ++ f_path = name.readline().strip() ++ if f_path.startswith("file:///"): ++ parsed = urlparse(f_path) ++ m = os.path.getmtime(parsed.path) ++ if mtime is None or m > mtime: ++ mtime = m + for d in subdirs: +- m, _ = self.traverse(os.path.join(path, d), ctime) +- if ctime is None or m > ctime: +- ctime = m +- return ctime, ret ++ m, _ = self.traverse(os.path.join(path, d), mtime) ++ if mtime is None or m > mtime: ++ mtime = m ++ return mtime, ret ++ ++ def initialize_controls(self, cluster): ++ # initialize statistics ++ self.stats_fetch_calls[cluster] = 0 ++ self.stats_fetch_time[cluster] = 0 ++ self.stats_parse_time[cluster] = 0 ++ self.stats_status[cluster] = "unknown" ++ self.stats_status_code[cluster] = 0 ++ ++ self.controls[cluster] = 1 ++ ++ def delete_controls(self, cluster): ++ del self.stats_fetch_calls[cluster] ++ del self.stats_fetch_time[cluster] ++ del self.stats_parse_time[cluster] ++ del self.stats_status[cluster] ++ del self.stats_status_code[cluster] ++ ++ self.controls[cluster] = 0 + + def rescan_confdir(self): + '''Scan the configuration directories for any new .url files +@@ -1138,19 +1193,56 @@ class OpenMetricsPMDA(PMDA): + ''' + + traverse_time = time.time() +- dir_ctime, conf_filelist = self.traverse(self.config_dir, self.config_dir_ctime) ++ dir_mtime, conf_filelist = self.traverse(self.config_dir, self.config_dir_mtime) + traverse_time = time.time() - traverse_time + +- if self.config_dir_ctime is None or self.config_dir_ctime < dir_ctime: +- self.config_dir_ctime = dir_ctime ++ if self.config_dir_mtime < dir_mtime: ++ self.config_dir_mtime = dir_mtime + else: # no new or changed conf files, don't rescan directory + return + + self.log("Config change detected, traversed %d config entries in %.04fs, rescanning ..." % (len(conf_filelist), traverse_time)) + nickname_regexp = self.lookup_regex(r"^[A-Za-z][A-Za-z0-9_.]*$") ++ self.re_add_list = [] ++ ++ # calculate config entry nicknames ++ nicknames = [] ++ for file in conf_filelist: ++ file_split = os.path.splitext(file) ++ name = file_split[0].replace(self.config_dir + "/", "").replace("/", ".") ++ nicknames.append(name) ++ ++ # check if config change adds a previously removed source ++ for key in self.removed_metrics: ++ split_name = key.split(".") ++ if split_name[1] in nicknames: ++ self.re_add_list.append(split_name[1]) ++ ++ # if source is not in config directory, remove the metric ++ for key, value in self.all_metrics.items(): ++ split_name = key.split(".") ++ if split_name[1] in nicknames: ++ continue ++ try: ++ remove_name = key ++ remove_obj = value ++ cluster = self.cluster_table.intern_lookup_value(split_name[1]) ++ if self.controls[cluster] == 1: ++ self.delete_controls(cluster) ++ self.remove_metric(remove_name, remove_obj) ++ self.removed_metrics[remove_name] = remove_obj ++ self.debug("removed metric name: %s" % remove_name) if self.dbg else None ++ self.set_need_refresh() ++ except Exception as e: ++ self.debug("can't remove metric: %s, see error: %s" % (key, e)) if self.dbg else None ++ ++ for key in self.removed_metrics: ++ if key in self.all_metrics: ++ del self.all_metrics[key] + +- # TODO: maybe nuke sources related to removed files + save_cluster_table = False ++ cluster_for_refresh_names = [] ++ cluster_for_refresh = [] + if sort_conf_list: + # sorted for indom cluster consistency + conf_filelist = sorted(conf_filelist) +@@ -1177,6 +1269,13 @@ class OpenMetricsPMDA(PMDA): + if name in self.source_by_name: + # this source is already known + self.assert_source_invariants(name=name) ++ s = self.source_by_name[name] ++ for key, value in self.source_by_cluster.items(): ++ if value == s: ++ cluster_for_refresh.append(key) ++ cluster_for_refresh_names.append(name) ++ if name in self.re_add_list: ++ self.initialize_controls(key) + else: + try: + path = file +@@ -1185,17 +1284,16 @@ class OpenMetricsPMDA(PMDA): + self.source_by_name[source.name] = source + self.source_by_cluster[source.cluster] = source + +- # initialize statistics +- self.stats_fetch_calls[cluster] = 0 +- self.stats_fetch_time[cluster] = 0 +- self.stats_parse_time[cluster] = 0 +- self.stats_status[cluster] = "unknown" +- self.stats_status_code[cluster] = 0 ++ self.initialize_controls(cluster) + + save_cluster_table = True + self.log("Found source %s cluster %d" % (name, cluster)) + except Exception as e: + self.err("Error allocating new cluster/source %s (%s)" % (name, e)) ++ ++ self.debug("refreshing cluster list: %s" % cluster_for_refresh_names) if self.dbg else None ++ self.refresh_some_clusters_for_fetch(cluster_for_refresh) ++ + if save_cluster_table: + self.cluster_table.save() + self.set_notify_change() diff --git a/pcp-filter-exact.patch b/pmwebapi-filter-exact.patch similarity index 100% rename from pcp-filter-exact.patch rename to pmwebapi-filter-exact.patch diff --git a/python-pmda-wrapper-list-fix.patch b/python-pmda-wrapper-list-fix.patch new file mode 100644 index 0000000..b26daa7 --- /dev/null +++ b/python-pmda-wrapper-list-fix.patch @@ -0,0 +1,17 @@ +diff -Naurp pcp-6.3.7.orig/src/python/pmda.c pcp-6.3.7/src/python/pmda.c +--- pcp-6.3.7.orig/src/python/pmda.c 2025-06-26 19:39:47.002695985 +1000 ++++ pcp-6.3.7/src/python/pmda.c 2025-06-26 19:40:16.426718001 +1000 +@@ -417,11 +417,11 @@ refresh_all_clusters(int numclusters, in + PyList_SET_ITEM(list, i, num); + } + +- arglist = Py_BuildValue("(N)", list); ++ arglist = Py_BuildValue("(O)", list); ++ Py_DECREF(list); + if (arglist == NULL) + return -ENOMEM; + result = PyObject_Call(refresh_all_func, arglist, NULL); +- Py_DECREF(list); + Py_DECREF(arglist); + if (result == NULL) + return callback_error("refresh_all_clusters"); diff --git a/selinux-pcp_pmie_t.patch b/selinux-pcp_pmie_t.patch new file mode 100644 index 0000000..383094f --- /dev/null +++ b/selinux-pcp_pmie_t.patch @@ -0,0 +1,21 @@ +commit 081aa84d3809b64f3e7765abf13a9a90f1072ec8 +Author: Nathan Scott +Date: Tue May 6 11:46:14 2025 +1000 + + selinux: additional policy needed for pcp_pmie_t using ps(1) + + Resolves Fedora BZ 2363903. + +diff --git a/src/selinux/pcp.te b/src/selinux/pcp.te +index a30144950..9cbd59bd2 100644 +--- a/src/selinux/pcp.te ++++ b/src/selinux/pcp.te +@@ -247,7 +247,7 @@ optional_policy(` + # + # pcp_pmie local policy + # +-allow pcp_pmie_t self:capability { chown fsetid sys_ptrace }; ++allow pcp_pmie_t self:capability { chown fsetid sys_admin sys_ptrace }; + allow pcp_pmie_t self:cap_userns sys_ptrace; + allow pcp_pmie_t self:netlink_route_socket { create_socket_perms nlmsg_read }; + allow pcp_pmie_t self:unix_dgram_socket { create_socket_perms sendto }; diff --git a/selinux-pmie-and-pmlogger.patch b/selinux-pmie-and-pmlogger.patch deleted file mode 100644 index 21cfc2b..0000000 --- a/selinux-pmie-and-pmlogger.patch +++ /dev/null @@ -1,24 +0,0 @@ -diff --git a/src/selinux/pcp.te b/src/selinux/pcp.te -index 46d921b5c..c03d03674 100644 ---- a/src/selinux/pcp.te -+++ b/src/selinux/pcp.te -@@ -906,6 +906,9 @@ allow pcp_pmlogger_t etc_t:dir { add_name read remove_name write }; - allow pcp_pmlogger_t etc_t:file { create unlink write }; - allow pcp_pmlogger_t cgroup_t:file { getattr read open append write }; - -+allow pcp_pmlogger_t fixed_disk_device_t:blk_file getattr; -+allow pcp_pmlogger_t sysfs_t:lnk_file read; -+ - #============= pcp_pmie_t ============== - # type=AVC msg=audit(N): avc: denied { execute execute_no_trans getattr open read } for pid=PID comm="pmdaX" name="/" dev="tracefs" ino=INO scontext=system_u:system_r:pcp_pmie_t:s0 tcontext=system_u:object_r:hostname_exec_t:s0 tclass=file permissive=0 - allow pcp_pmie_t hostname_exec_t:file { execute execute_no_trans getattr open read }; -@@ -940,6 +943,9 @@ allow pcp_pmie_t etc_t:dir { add_name read remove_name write }; - allow pcp_pmie_t etc_t:file { create unlink write }; - allow pcp_pmie_t cgroup_t:file { getattr read open append write }; - -+allow pcp_pmie_t fixed_disk_device_t:blk_file getattr; -+allow pcp_pmie_t sysfs_t:lnk_file read; -+ - #============= pmda-lio ============== - # type=AVC msg=audit(N): avc: denied { open read search write } for pid=PID comm="pmdaX" name="/" dev="tracefs" ino=INO scontext=system_u:system_r:pcp_pmcd_t:s0 tcontext=system_u:object_r:configfs_t:s0 tclass=dir permissive=0 - allow pcp_pmcd_t configfs_t:dir { open read search write }; diff --git a/systemd-tmpfiles.d-directories.patch b/systemd-tmpfiles.d-directories.patch new file mode 100644 index 0000000..6accc0a --- /dev/null +++ b/systemd-tmpfiles.d-directories.patch @@ -0,0 +1,40 @@ +diff -Naurp pcp-6.3.7.orig/GNUmakefile pcp-6.3.7/GNUmakefile +--- pcp-6.3.7.orig/GNUmakefile 2025-03-27 17:01:59.000000000 +1100 ++++ pcp-6.3.7/GNUmakefile 2025-06-26 19:23:24.874469186 +1000 +@@ -135,6 +135,8 @@ pcp.lsm src/include/builddefs src/includ + + tmpfiles.init.setup: tmpfiles.init.setup.in + sed < $< > $@ \ ++ -e "s@PCP_VAR_DIR@$(PCP_VAR_DIR)@" \ ++ -e "s@PCP_TMP_DIR@$(PCP_TMP_DIR)@" \ + -e "s@PCP_RUN_DIR@$(PCP_RUN_DIR)@" \ + -e "s@PCP_LOG_DIR@$(PCP_LOG_DIR)@" \ + -e "s/PCP_GROUP/$(PCP_GROUP)/" \ +diff -Naurp pcp-6.3.7.orig/tmpfiles.init.setup.in pcp-6.3.7/tmpfiles.init.setup.in +--- pcp-6.3.7.orig/tmpfiles.init.setup.in 2024-07-30 16:43:55.000000000 +1000 ++++ pcp-6.3.7/tmpfiles.init.setup.in 2025-06-26 19:23:24.875070062 +1000 +@@ -1,10 +1,16 @@ + # tmpfiles.d(5) config for Performance Co-Pilot startup components + # +-# Type Path Mode User Group Age Argument +-D PCP_RUN_DIR 0775 PCP_USER PCP_GROUP - - +-d PCP_LOG_DIR 0775 PCP_USER PCP_GROUP - - +-d PCP_LOG_DIR/pmcd 0755 root root - - +-d PCP_LOG_DIR/pmfind 0775 PCP_USER PCP_GROUP - - +-d PCP_LOG_DIR/pmie 0775 PCP_USER PCP_GROUP - - +-d PCP_LOG_DIR/pmlogger 0775 PCP_USER PCP_GROUP - - +-d PCP_LOG_DIR/pmproxy 0775 PCP_USER PCP_GROUP - - ++# Path Mode User Group Age Argument ++D PCP_RUN_DIR 0775 PCP_USER PCP_GROUP - - ++d PCP_VAR_DIR 0755 root root - - ++d PCP_VAR_DIR/config 0755 root root - - ++d PCP_VAR_DIR/config/pmda 0775 PCP_USER PCP_GROUP - - ++d PCP_VAR_DIR/config/pmie 0775 PCP_USER PCP_GROUP - - ++d PCP_VAR_DIR/config/pmlogger 0775 PCP_USER PCP_GROUP - - ++d PCP_TMP_DIR 0775 PCP_USER PCP_GROUP - - ++d PCP_LOG_DIR 0775 PCP_USER PCP_GROUP - - ++d PCP_LOG_DIR/pmcd 0755 root root - - ++d PCP_LOG_DIR/pmfind 0775 PCP_USER PCP_GROUP - - ++d PCP_LOG_DIR/pmie 0775 PCP_USER PCP_GROUP - - ++d PCP_LOG_DIR/pmlogger 0775 PCP_USER PCP_GROUP - - ++d PCP_LOG_DIR/pmproxy 0775 PCP_USER PCP_GROUP - -