Compare commits

...

No commits in common. "imports/c8s/pcp-5.3.1-3.el8" and "c8" have entirely different histories.

19 changed files with 65562 additions and 11356 deletions

2
.gitignore vendored
View File

@ -1 +1 @@
SOURCES/pcp-5.3.1.src.tar.gz
SOURCES/pcp-5.3.7.src.tar.gz

View File

@ -1 +1 @@
5b693868cb11c09b87880ca2d57e672a3bfd63e6 SOURCES/pcp-5.3.1.src.tar.gz
a0a05bf501b016cb859fb211ae60ce18be2bbd99 SOURCES/pcp-5.3.7.src.tar.gz

File diff suppressed because it is too large Load Diff

View File

@ -1,849 +0,0 @@
commit 2bad6aef10339f000f7cb578108db5ee80bd640c
Author: Mark Goodwin <mgoodwin@redhat.com>
Date: Wed Jun 9 17:04:33 2021 +1000
pmproxy: add mutex for client req lists, fix https/tls support, QA
Add a new mutext to struct proxy and use it to protect parallel
multithreaded updates to the proxy->first client list.
Also use the same mutext to protect updates to the pending_writes
client list and avoid the doubly linked list corruption that was
causing parallel https/tls requests to get stuck spinning in
flush_secure_module(), as reported in BZ#1947989.
qa/1457 is extensively updated to test parallel http, https/tls
(and combinations of http and https/tls) RESTAPI calls. Previously
it only tested a single https/tls call.
With these changes, parallel https/tls RESTAPI requests from the
grafana-pcp datasource to pmproxy now work correctly whereas previously
pmproxy would hang/spin.
Resolves: RHBZ#1947989 - pmproxy hangs and consume 100% cpu if the
redis datasource is configured with TLS.
Related: https://github.com/performancecopilot/pcp/issues/1311
diff --git a/qa/1457 b/qa/1457
index 94969f6e0..8bf395944 100755
--- a/qa/1457
+++ b/qa/1457
@@ -2,7 +2,7 @@
# PCP QA Test No. 1457
# Exercise HTTPS access to the PMWEBAPI(3).
#
-# Copyright (c) 2019 Red Hat.
+# Copyright (c) 2019,2021 Red Hat.
#
seq=`basename $0`
@@ -138,14 +138,59 @@ else
fi
date >>$seq.full
-echo "=== checking TLS operation ===" | tee -a $seq.full
-# (-k) allows us to use self-signed (insecure) certificates, so for testing only
-# (-v) provides very detailed TLS connection information, for debugging only
-curl -k --get 2>$tmp.err \
- "https://localhost:$port/pmapi/metric?name=sample.long.ten" \
- | _filter_json
-cat $tmp.err >>$seq.full
+echo "=== checking serial http operation ===" | tee -a $seq.full
+for i in 1 2 3 4; do
+ curl -Gs "http://localhost:$port/pmapi/metric?name=sample.long.ten" 2>$tmp.err$i >$tmp.out$i
+done
+for i in 1 2 3 4; do
+echo === out$i === | tee -a $seq.full
+_filter_json < $tmp.out$i
+done
+
+date >>$seq.full
+echo "=== checking parallel http operation ===" | tee -a $seq.full
+for i in 1 2 3 4; do
+ curl -Gs "http://localhost:$port/pmapi/metric?name=sample.long.ten" 2>$tmp.err$i >$tmp.out$i & 2>/dev/null eval pid$i=$!
+done
+wait $pid1 $pid2 $pid3 $pid4
+for i in 1 2 3 4; do
+echo === out$i === | tee -a $seq.full
+_filter_json < $tmp.out$i
+done
+
+date >>$seq.full
+echo "=== checking serial https/TLS operation ===" | tee -a $seq.full
+for i in 1 2 3 4; do
+ curl -k -Gs "https://localhost:$port/pmapi/metric?name=sample.long.ten" 2>$tmp.err$i >$tmp.out$i
+done
+for i in 1 2 3 4; do
+echo === out$i === | tee -a $seq.full
+_filter_json < $tmp.out$i
+done
+
date >>$seq.full
+echo "=== checking parallel https/TLS operation ===" | tee -a $seq.full
+for i in 1 2 3 4; do
+ curl -k -Gs "https://localhost:$port/pmapi/metric?name=sample.long.ten" 2>$tmp.err$i >$tmp.out$i & 2>/dev/null eval pid$i=$!
+done
+wait $pid1 $pid2 $pid3 $pid4
+for i in 1 2 3 4; do
+echo === out$i === | tee -a $seq.full
+_filter_json < $tmp.out$i
+done
+
+date >>$seq.full
+echo "=== checking parallel mixed http and https/TLS operations ===" | tee -a $seq.full
+for i in 1 3 5 7; do
+ j=`expr $i + 1`
+ curl -k -Gs "http://localhost:$port/pmapi/metric?name=sample.long.ten" 2>$tmp.err$i >$tmp.out$i & 2>/dev/null eval pid$i=$!
+ curl -k -Gs "https://localhost:$port/pmapi/metric?name=sample.long.ten" 2>$tmp.err$j >$tmp.out$j & 2>/dev/null eval pid$j=$!
+done
+wait $pid1 $pid2 $pid3 $pid4 $pid5 $pid6 $pid7 $pid8
+for i in 1 2 3 4 5 6 7 8; do
+echo === out$i === | tee -a $seq.full
+_filter_json < $tmp.out$i
+done
echo "=== check pmproxy is running ==="
pminfo -v -h localhost@localhost:$port hinv.ncpu
@@ -156,7 +201,7 @@ else
fi
# valgrind takes awhile to shutdown too
-pmsignal $pid
+pmsignal $pid >/dev/null 2>&1
pmsleep 3.5
echo "=== valgrind stdout ===" | tee -a $seq.full
cat $tmp.valout | _filter_valgrind
@@ -164,6 +209,9 @@ cat $tmp.valout | _filter_valgrind
echo "=== valgrind stderr ===" | tee -a $seq.full
cat $tmp.valerr | _filter_pmproxy_log | _filter_port
+# final kill if it's spinning
+$sudo kill -9 $pid >/dev/null 2>&1
+
# success, all done
status=0
exit
diff --git a/qa/1457.out b/qa/1457.out
index a7b64cdc5..422176db2 100644
--- a/qa/1457.out
+++ b/qa/1457.out
@@ -1,5 +1,539 @@
QA output created by 1457
-=== checking TLS operation ===
+=== checking serial http operation ===
+=== out1 ===
+{
+ "context": "CONTEXT"
+ "metrics": [
+ {
+ "name": "sample.long.ten",
+ "series": "SERIES"
+ "pmid": "29.0.11",
+ "type": "32",
+ "sem": "instant",
+ "units": "none",
+ "labels": {
+ "agent": "sample",
+ "cluster": "zero",
+ "domainname": "DOMAINNAME"
+ "hostname": "HOSTNAME"
+ "role": "testing"
+ },
+ "text-oneline": "10 as a 32-bit integer",
+ "text-help": "10 as a 32-bit integer"
+ }
+ ]
+}
+=== out2 ===
+{
+ "context": "CONTEXT"
+ "metrics": [
+ {
+ "name": "sample.long.ten",
+ "series": "SERIES"
+ "pmid": "29.0.11",
+ "type": "32",
+ "sem": "instant",
+ "units": "none",
+ "labels": {
+ "agent": "sample",
+ "cluster": "zero",
+ "domainname": "DOMAINNAME"
+ "hostname": "HOSTNAME"
+ "role": "testing"
+ },
+ "text-oneline": "10 as a 32-bit integer",
+ "text-help": "10 as a 32-bit integer"
+ }
+ ]
+}
+=== out3 ===
+{
+ "context": "CONTEXT"
+ "metrics": [
+ {
+ "name": "sample.long.ten",
+ "series": "SERIES"
+ "pmid": "29.0.11",
+ "type": "32",
+ "sem": "instant",
+ "units": "none",
+ "labels": {
+ "agent": "sample",
+ "cluster": "zero",
+ "domainname": "DOMAINNAME"
+ "hostname": "HOSTNAME"
+ "role": "testing"
+ },
+ "text-oneline": "10 as a 32-bit integer",
+ "text-help": "10 as a 32-bit integer"
+ }
+ ]
+}
+=== out4 ===
+{
+ "context": "CONTEXT"
+ "metrics": [
+ {
+ "name": "sample.long.ten",
+ "series": "SERIES"
+ "pmid": "29.0.11",
+ "type": "32",
+ "sem": "instant",
+ "units": "none",
+ "labels": {
+ "agent": "sample",
+ "cluster": "zero",
+ "domainname": "DOMAINNAME"
+ "hostname": "HOSTNAME"
+ "role": "testing"
+ },
+ "text-oneline": "10 as a 32-bit integer",
+ "text-help": "10 as a 32-bit integer"
+ }
+ ]
+}
+=== checking parallel http operation ===
+=== out1 ===
+{
+ "context": "CONTEXT"
+ "metrics": [
+ {
+ "name": "sample.long.ten",
+ "series": "SERIES"
+ "pmid": "29.0.11",
+ "type": "32",
+ "sem": "instant",
+ "units": "none",
+ "labels": {
+ "agent": "sample",
+ "cluster": "zero",
+ "domainname": "DOMAINNAME"
+ "hostname": "HOSTNAME"
+ "role": "testing"
+ },
+ "text-oneline": "10 as a 32-bit integer",
+ "text-help": "10 as a 32-bit integer"
+ }
+ ]
+}
+=== out2 ===
+{
+ "context": "CONTEXT"
+ "metrics": [
+ {
+ "name": "sample.long.ten",
+ "series": "SERIES"
+ "pmid": "29.0.11",
+ "type": "32",
+ "sem": "instant",
+ "units": "none",
+ "labels": {
+ "agent": "sample",
+ "cluster": "zero",
+ "domainname": "DOMAINNAME"
+ "hostname": "HOSTNAME"
+ "role": "testing"
+ },
+ "text-oneline": "10 as a 32-bit integer",
+ "text-help": "10 as a 32-bit integer"
+ }
+ ]
+}
+=== out3 ===
+{
+ "context": "CONTEXT"
+ "metrics": [
+ {
+ "name": "sample.long.ten",
+ "series": "SERIES"
+ "pmid": "29.0.11",
+ "type": "32",
+ "sem": "instant",
+ "units": "none",
+ "labels": {
+ "agent": "sample",
+ "cluster": "zero",
+ "domainname": "DOMAINNAME"
+ "hostname": "HOSTNAME"
+ "role": "testing"
+ },
+ "text-oneline": "10 as a 32-bit integer",
+ "text-help": "10 as a 32-bit integer"
+ }
+ ]
+}
+=== out4 ===
+{
+ "context": "CONTEXT"
+ "metrics": [
+ {
+ "name": "sample.long.ten",
+ "series": "SERIES"
+ "pmid": "29.0.11",
+ "type": "32",
+ "sem": "instant",
+ "units": "none",
+ "labels": {
+ "agent": "sample",
+ "cluster": "zero",
+ "domainname": "DOMAINNAME"
+ "hostname": "HOSTNAME"
+ "role": "testing"
+ },
+ "text-oneline": "10 as a 32-bit integer",
+ "text-help": "10 as a 32-bit integer"
+ }
+ ]
+}
+=== checking serial https/TLS operation ===
+=== out1 ===
+{
+ "context": "CONTEXT"
+ "metrics": [
+ {
+ "name": "sample.long.ten",
+ "series": "SERIES"
+ "pmid": "29.0.11",
+ "type": "32",
+ "sem": "instant",
+ "units": "none",
+ "labels": {
+ "agent": "sample",
+ "cluster": "zero",
+ "domainname": "DOMAINNAME"
+ "hostname": "HOSTNAME"
+ "role": "testing"
+ },
+ "text-oneline": "10 as a 32-bit integer",
+ "text-help": "10 as a 32-bit integer"
+ }
+ ]
+}
+=== out2 ===
+{
+ "context": "CONTEXT"
+ "metrics": [
+ {
+ "name": "sample.long.ten",
+ "series": "SERIES"
+ "pmid": "29.0.11",
+ "type": "32",
+ "sem": "instant",
+ "units": "none",
+ "labels": {
+ "agent": "sample",
+ "cluster": "zero",
+ "domainname": "DOMAINNAME"
+ "hostname": "HOSTNAME"
+ "role": "testing"
+ },
+ "text-oneline": "10 as a 32-bit integer",
+ "text-help": "10 as a 32-bit integer"
+ }
+ ]
+}
+=== out3 ===
+{
+ "context": "CONTEXT"
+ "metrics": [
+ {
+ "name": "sample.long.ten",
+ "series": "SERIES"
+ "pmid": "29.0.11",
+ "type": "32",
+ "sem": "instant",
+ "units": "none",
+ "labels": {
+ "agent": "sample",
+ "cluster": "zero",
+ "domainname": "DOMAINNAME"
+ "hostname": "HOSTNAME"
+ "role": "testing"
+ },
+ "text-oneline": "10 as a 32-bit integer",
+ "text-help": "10 as a 32-bit integer"
+ }
+ ]
+}
+=== out4 ===
+{
+ "context": "CONTEXT"
+ "metrics": [
+ {
+ "name": "sample.long.ten",
+ "series": "SERIES"
+ "pmid": "29.0.11",
+ "type": "32",
+ "sem": "instant",
+ "units": "none",
+ "labels": {
+ "agent": "sample",
+ "cluster": "zero",
+ "domainname": "DOMAINNAME"
+ "hostname": "HOSTNAME"
+ "role": "testing"
+ },
+ "text-oneline": "10 as a 32-bit integer",
+ "text-help": "10 as a 32-bit integer"
+ }
+ ]
+}
+=== checking parallel https/TLS operation ===
+=== out1 ===
+{
+ "context": "CONTEXT"
+ "metrics": [
+ {
+ "name": "sample.long.ten",
+ "series": "SERIES"
+ "pmid": "29.0.11",
+ "type": "32",
+ "sem": "instant",
+ "units": "none",
+ "labels": {
+ "agent": "sample",
+ "cluster": "zero",
+ "domainname": "DOMAINNAME"
+ "hostname": "HOSTNAME"
+ "role": "testing"
+ },
+ "text-oneline": "10 as a 32-bit integer",
+ "text-help": "10 as a 32-bit integer"
+ }
+ ]
+}
+=== out2 ===
+{
+ "context": "CONTEXT"
+ "metrics": [
+ {
+ "name": "sample.long.ten",
+ "series": "SERIES"
+ "pmid": "29.0.11",
+ "type": "32",
+ "sem": "instant",
+ "units": "none",
+ "labels": {
+ "agent": "sample",
+ "cluster": "zero",
+ "domainname": "DOMAINNAME"
+ "hostname": "HOSTNAME"
+ "role": "testing"
+ },
+ "text-oneline": "10 as a 32-bit integer",
+ "text-help": "10 as a 32-bit integer"
+ }
+ ]
+}
+=== out3 ===
+{
+ "context": "CONTEXT"
+ "metrics": [
+ {
+ "name": "sample.long.ten",
+ "series": "SERIES"
+ "pmid": "29.0.11",
+ "type": "32",
+ "sem": "instant",
+ "units": "none",
+ "labels": {
+ "agent": "sample",
+ "cluster": "zero",
+ "domainname": "DOMAINNAME"
+ "hostname": "HOSTNAME"
+ "role": "testing"
+ },
+ "text-oneline": "10 as a 32-bit integer",
+ "text-help": "10 as a 32-bit integer"
+ }
+ ]
+}
+=== out4 ===
+{
+ "context": "CONTEXT"
+ "metrics": [
+ {
+ "name": "sample.long.ten",
+ "series": "SERIES"
+ "pmid": "29.0.11",
+ "type": "32",
+ "sem": "instant",
+ "units": "none",
+ "labels": {
+ "agent": "sample",
+ "cluster": "zero",
+ "domainname": "DOMAINNAME"
+ "hostname": "HOSTNAME"
+ "role": "testing"
+ },
+ "text-oneline": "10 as a 32-bit integer",
+ "text-help": "10 as a 32-bit integer"
+ }
+ ]
+}
+=== checking parallel mixed http and https/TLS operations ===
+=== out1 ===
+{
+ "context": "CONTEXT"
+ "metrics": [
+ {
+ "name": "sample.long.ten",
+ "series": "SERIES"
+ "pmid": "29.0.11",
+ "type": "32",
+ "sem": "instant",
+ "units": "none",
+ "labels": {
+ "agent": "sample",
+ "cluster": "zero",
+ "domainname": "DOMAINNAME"
+ "hostname": "HOSTNAME"
+ "role": "testing"
+ },
+ "text-oneline": "10 as a 32-bit integer",
+ "text-help": "10 as a 32-bit integer"
+ }
+ ]
+}
+=== out2 ===
+{
+ "context": "CONTEXT"
+ "metrics": [
+ {
+ "name": "sample.long.ten",
+ "series": "SERIES"
+ "pmid": "29.0.11",
+ "type": "32",
+ "sem": "instant",
+ "units": "none",
+ "labels": {
+ "agent": "sample",
+ "cluster": "zero",
+ "domainname": "DOMAINNAME"
+ "hostname": "HOSTNAME"
+ "role": "testing"
+ },
+ "text-oneline": "10 as a 32-bit integer",
+ "text-help": "10 as a 32-bit integer"
+ }
+ ]
+}
+=== out3 ===
+{
+ "context": "CONTEXT"
+ "metrics": [
+ {
+ "name": "sample.long.ten",
+ "series": "SERIES"
+ "pmid": "29.0.11",
+ "type": "32",
+ "sem": "instant",
+ "units": "none",
+ "labels": {
+ "agent": "sample",
+ "cluster": "zero",
+ "domainname": "DOMAINNAME"
+ "hostname": "HOSTNAME"
+ "role": "testing"
+ },
+ "text-oneline": "10 as a 32-bit integer",
+ "text-help": "10 as a 32-bit integer"
+ }
+ ]
+}
+=== out4 ===
+{
+ "context": "CONTEXT"
+ "metrics": [
+ {
+ "name": "sample.long.ten",
+ "series": "SERIES"
+ "pmid": "29.0.11",
+ "type": "32",
+ "sem": "instant",
+ "units": "none",
+ "labels": {
+ "agent": "sample",
+ "cluster": "zero",
+ "domainname": "DOMAINNAME"
+ "hostname": "HOSTNAME"
+ "role": "testing"
+ },
+ "text-oneline": "10 as a 32-bit integer",
+ "text-help": "10 as a 32-bit integer"
+ }
+ ]
+}
+=== out5 ===
+{
+ "context": "CONTEXT"
+ "metrics": [
+ {
+ "name": "sample.long.ten",
+ "series": "SERIES"
+ "pmid": "29.0.11",
+ "type": "32",
+ "sem": "instant",
+ "units": "none",
+ "labels": {
+ "agent": "sample",
+ "cluster": "zero",
+ "domainname": "DOMAINNAME"
+ "hostname": "HOSTNAME"
+ "role": "testing"
+ },
+ "text-oneline": "10 as a 32-bit integer",
+ "text-help": "10 as a 32-bit integer"
+ }
+ ]
+}
+=== out6 ===
+{
+ "context": "CONTEXT"
+ "metrics": [
+ {
+ "name": "sample.long.ten",
+ "series": "SERIES"
+ "pmid": "29.0.11",
+ "type": "32",
+ "sem": "instant",
+ "units": "none",
+ "labels": {
+ "agent": "sample",
+ "cluster": "zero",
+ "domainname": "DOMAINNAME"
+ "hostname": "HOSTNAME"
+ "role": "testing"
+ },
+ "text-oneline": "10 as a 32-bit integer",
+ "text-help": "10 as a 32-bit integer"
+ }
+ ]
+}
+=== out7 ===
+{
+ "context": "CONTEXT"
+ "metrics": [
+ {
+ "name": "sample.long.ten",
+ "series": "SERIES"
+ "pmid": "29.0.11",
+ "type": "32",
+ "sem": "instant",
+ "units": "none",
+ "labels": {
+ "agent": "sample",
+ "cluster": "zero",
+ "domainname": "DOMAINNAME"
+ "hostname": "HOSTNAME"
+ "role": "testing"
+ },
+ "text-oneline": "10 as a 32-bit integer",
+ "text-help": "10 as a 32-bit integer"
+ }
+ ]
+}
+=== out8 ===
{
"context": "CONTEXT"
"metrics": [
diff --git a/qa/group b/qa/group
index 462dffaaa..77cac788d 100644
--- a/qa/group
+++ b/qa/group
@@ -1818,7 +1818,7 @@ x11
1436 pmda.postgresql local
1437 pmda.kvm local
1455 pmlogrewrite labels pmdumplog local
-1457 pmproxy local
+1457 pmproxy libpcp_web threads secure local
1480 pmda.lmsensors local
1489 python pmrep pmimport local
1490 python local labels
diff --git a/src/pmproxy/src/secure.c b/src/pmproxy/src/secure.c
index 77265894c..072e2a085 100644
--- a/src/pmproxy/src/secure.c
+++ b/src/pmproxy/src/secure.c
@@ -16,13 +16,25 @@
#include <openssl/opensslv.h>
#include <openssl/ssl.h>
+/* called with proxy->mutex locked */
static void
remove_connection_from_queue(struct client *client)
{
+ struct proxy *proxy = client->proxy;
+
if (client->secure.pending.writes_buffer != NULL)
free(client->secure.pending.writes_buffer);
- if (client->secure.pending.prev != NULL)
- *client->secure.pending.prev = client->secure.pending.next;
+ if (client->secure.pending.prev == NULL) {
+ /* next (if any) becomes first in pending_writes list */
+ proxy->pending_writes = client->secure.pending.next;
+ if (proxy->pending_writes)
+ proxy->pending_writes->secure.pending.prev = NULL;
+ }
+ else {
+ /* link next and prev */
+ client->secure.pending.prev->secure.pending.next = client->secure.pending.next;
+ client->secure.pending.next->secure.pending.prev = client->secure.pending.prev;
+ }
memset(&client->secure.pending, 0, sizeof(client->secure.pending));
}
@@ -32,7 +44,9 @@ on_secure_client_close(struct client *client)
if (pmDebugOptions.auth || pmDebugOptions.http)
fprintf(stderr, "%s: client %p\n", "on_secure_client_close", client);
+ uv_mutex_lock(&client->proxy->mutex);
remove_connection_from_queue(client);
+ uv_mutex_unlock(&client->proxy->mutex);
/* client->read and client->write freed by SSL_free */
SSL_free(client->secure.ssl);
}
@@ -40,6 +54,8 @@ on_secure_client_close(struct client *client)
static void
maybe_flush_ssl(struct proxy *proxy, struct client *client)
{
+ struct client *c;
+
if (client->secure.pending.queued)
return;
@@ -47,13 +63,19 @@ maybe_flush_ssl(struct proxy *proxy, struct client *client)
client->secure.pending.writes_count > 0)
return;
- client->secure.pending.next = proxy->pending_writes;
- if (client->secure.pending.next != NULL)
- client->secure.pending.next->secure.pending.prev = &client->secure.pending.next;
- client->secure.pending.prev = &proxy->pending_writes;
+ uv_mutex_lock(&proxy->mutex);
+ if (proxy->pending_writes == NULL) {
+ proxy->pending_writes = client;
+ client->secure.pending.prev = client->secure.pending.next = NULL;
+ }
+ else {
+ for (c=proxy->pending_writes; c->secure.pending.next; c = c->secure.pending.next)
+ ; /**/
+ c->secure.pending.next = client;
+ client->secure.pending.prev = c;
+ }
client->secure.pending.queued = 1;
-
- proxy->pending_writes = client;
+ uv_mutex_unlock(&proxy->mutex);
}
static void
@@ -135,10 +157,12 @@ flush_ssl_buffer(struct client *client)
void
flush_secure_module(struct proxy *proxy)
{
- struct client *client, **head = &proxy->pending_writes;
+ struct client *client, **head;
size_t i, used;
int sts;
+ uv_mutex_lock(&proxy->mutex);
+ head = &proxy->pending_writes;
while ((client = *head) != NULL) {
flush_ssl_buffer(client);
@@ -188,6 +212,7 @@ flush_secure_module(struct proxy *proxy)
sizeof(uv_buf_t) * client->secure.pending.writes_count);
}
}
+ uv_mutex_unlock(&proxy->mutex);
}
void
diff --git a/src/pmproxy/src/server.c b/src/pmproxy/src/server.c
index 612d3613b..b5c5d84de 100644
--- a/src/pmproxy/src/server.c
+++ b/src/pmproxy/src/server.c
@@ -149,6 +149,7 @@ server_init(int portcount, const char *localpath)
pmGetProgname());
return NULL;
}
+ uv_mutex_init(&proxy->mutex);
count = portcount + (*localpath ? 1 : 0);
if (count) {
@@ -251,6 +252,7 @@ void
client_put(struct client *client)
{
unsigned int refcount;
+ struct proxy *proxy = client->proxy;
uv_mutex_lock(&client->mutex);
assert(client->refcount);
@@ -259,9 +261,11 @@ client_put(struct client *client)
if (refcount == 0) {
/* remove client from the doubly-linked list */
+ uv_mutex_lock(&proxy->mutex);
if (client->next != NULL)
client->next->prev = client->prev;
*client->prev = client->next;
+ uv_mutex_unlock(&proxy->mutex);
if (client->protocol & STREAM_PCP)
on_pcp_client_close(client);
@@ -514,10 +518,12 @@ on_client_connection(uv_stream_t *stream, int status)
client->proxy = proxy;
/* insert client into doubly-linked list at the head */
+ uv_mutex_lock(&proxy->mutex);
if ((client->next = proxy->first) != NULL)
proxy->first->prev = &client->next;
proxy->first = client;
client->prev = &proxy->first;
+ uv_mutex_unlock(&proxy->mutex);
status = uv_read_start((uv_stream_t *)&client->stream.u.tcp,
on_buffer_alloc, on_client_read);
diff --git a/src/pmproxy/src/server.h b/src/pmproxy/src/server.h
index f0b7a5f68..f93daeff4 100644
--- a/src/pmproxy/src/server.h
+++ b/src/pmproxy/src/server.h
@@ -118,7 +118,7 @@ typedef struct secure_client {
BIO *write;
struct {
struct client *next;
- struct client **prev;
+ struct client *prev;
unsigned int queued;
size_t writes_count;
uv_buf_t *writes_buffer;
@@ -166,6 +166,7 @@ typedef struct proxy {
struct dict *config; /* configuration dictionary */
uv_loop_t *events; /* global, async event loop */
uv_callback_t write_callbacks;
+ uv_mutex_t mutex; /* protects client lists and pending writes */
} proxy;
extern void proxylog(pmLogLevel, sds, void *);

File diff suppressed because it is too large Load Diff

View File

@ -1,922 +0,0 @@
3f5ba2218 libpcp_web: add mutex to struct webgroup protecting the context dict
107633192 src/libpcp: be more careful when calling __pmLogChangeVol()
49bdfdfff libpcp: redefine __pmLogSetTime()
5e3b792d3 libpcp_web: plug mem leak in redisMapInsert during daily log-rolling
2a00a90b0 libpcp_web/discovery: improve lock handling and scalability
commit 3f5ba221842e6a02e9fb22e23c754854271c3c9a
Author: Mark Goodwin <mgoodwin@redhat.com>
Date: Wed Jun 9 16:44:30 2021 +1000
libpcp_web: add mutex to struct webgroup protecting the context dict
Add a mutex to the local webgroups structure in libpcp_web and
use it to protect multithreaded parallel updates (dictAdd,
dictDelete) to the groups->contexts dict and the dict traversal
in the timer driven garbage collector.
Tested by qa/297 and related tests and also an updated version
of qa/1457 (which now stress tests parallel http and https/tls
pmproxy RESTAPI calls .. in a later commit).
Related: RHBZ#1947989
Resolves: https://github.com/performancecopilot/pcp/issues/1311
diff --git a/src/libpcp_web/src/webgroup.c b/src/libpcp_web/src/webgroup.c
index 08c2518ed..35f05441b 100644
--- a/src/libpcp_web/src/webgroup.c
+++ b/src/libpcp_web/src/webgroup.c
@@ -51,14 +51,20 @@ typedef struct webgroups {
uv_loop_t *events;
unsigned int active;
uv_timer_t timer;
+ uv_mutex_t mutex;
} webgroups;
static struct webgroups *
webgroups_lookup(pmWebGroupModule *module)
{
- if (module->privdata == NULL)
+ struct webgroups *groups = module->privdata;
+
+ if (module->privdata == NULL) {
module->privdata = calloc(1, sizeof(struct webgroups));
- return (struct webgroups *)module->privdata;
+ groups = (struct webgroups *)module->privdata;
+ uv_mutex_init(&groups->mutex);
+ }
+ return groups;
}
static int
@@ -94,8 +100,11 @@ webgroup_drop_context(struct context *context, struct webgroups *groups)
context->garbage = 1;
uv_timer_stop(&context->timer);
}
- if (groups)
+ if (groups) {
+ uv_mutex_lock(&groups->mutex);
dictDelete(groups->contexts, &context->randomid);
+ uv_mutex_unlock(&groups->mutex);
+ }
uv_close((uv_handle_t *)&context->timer, webgroup_release_context);
}
}
@@ -207,13 +216,16 @@ webgroup_new_context(pmWebGroupSettings *sp, dict *params,
cp->context = -1;
cp->timeout = polltime;
+ uv_mutex_lock(&groups->mutex);
if ((cp->randomid = random()) < 0 ||
dictFind(groups->contexts, &cp->randomid) != NULL) {
infofmt(*message, "random number failure on new web context");
pmwebapi_free_context(cp);
*status = -ESRCH;
+ uv_mutex_unlock(&groups->mutex);
return NULL;
}
+ uv_mutex_unlock(&groups->mutex);
cp->origin = sdscatfmt(sdsempty(), "%i", cp->randomid);
cp->name.sds = sdsdup(hostspec ? hostspec : LOCALHOST);
cp->realm = sdscatfmt(sdsempty(), "pmapi/%i", cp->randomid);
@@ -242,7 +254,9 @@ webgroup_new_context(pmWebGroupSettings *sp, dict *params,
pmwebapi_free_context(cp);
return NULL;
}
+ uv_mutex_lock(&groups->mutex);
dictAdd(groups->contexts, &cp->randomid, cp);
+ uv_mutex_unlock(&groups->mutex);
/* leave until the end because uv_timer_init makes this visible in uv_run */
handle = (uv_handle_t *)&cp->timer;
@@ -261,25 +275,34 @@ webgroup_new_context(pmWebGroupSettings *sp, dict *params,
static void
webgroup_garbage_collect(struct webgroups *groups)
{
- dictIterator *iterator = dictGetSafeIterator(groups->contexts);
+ dictIterator *iterator;
dictEntry *entry;
context_t *cp;
if (pmDebugOptions.http || pmDebugOptions.libweb)
fprintf(stderr, "%s: started\n", "webgroup_garbage_collect");
- while ((entry = dictNext(iterator)) != NULL) {
- cp = (context_t *)dictGetVal(entry);
- if (cp->garbage && cp->privdata == groups) {
- if (pmDebugOptions.http || pmDebugOptions.libweb)
- fprintf(stderr, "GC context %u (%p)\n", cp->randomid, cp);
- webgroup_drop_context(cp, groups);
+ /* do context GC if we get the lock (else don't block here) */
+ if (uv_mutex_trylock(&groups->mutex) == 0) {
+ iterator = dictGetSafeIterator(groups->contexts);
+ for (entry = dictNext(iterator); entry;) {
+ cp = (context_t *)dictGetVal(entry);
+ entry = dictNext(iterator);
+ if (cp->garbage && cp->privdata == groups) {
+ if (pmDebugOptions.http || pmDebugOptions.libweb)
+ fprintf(stderr, "GC context %u (%p)\n", cp->randomid, cp);
+ uv_mutex_unlock(&groups->mutex);
+ webgroup_drop_context(cp, groups);
+ uv_mutex_lock(&groups->mutex);
+ }
}
+ dictReleaseIterator(iterator);
+ uv_mutex_unlock(&groups->mutex);
}
- dictReleaseIterator(iterator);
/* TODO - trim maps, particularly instmap if proc metrics are not excluded */
+ /* TODO move the following to a new stats timer */
if (groups->metrics_handle) {
mmv_stats_set(groups->metrics_handle, "contextmap.size",
NULL, dictSize(contextmap));
commit 107633192326b27ae571d4d4955052b8d86222c2
Author: Ken McDonell <kenj@kenj.id.au>
Date: Fri Jul 2 16:52:48 2021 +1000
src/libpcp: be more careful when calling __pmLogChangeVol()
Mark observed a SEGV which looks like __pmLogFetch() died because
ctxp->c_archctl->ac_mfp was (unexpectedly) NULL.
See: https://github.com/performancecopilot/pcp/issues/1338
Initial guess is that a physical file was removed by concurrent
activity (like pmlogger_check or pmlogger_daily), causing
__pmLogChangeVol() to fail ... and this was not being checked for
on the __pmLogFetch() path and in a couple of other places.
modified: interp.c
modified: logutil.c
diff --git a/src/libpcp/src/interp.c b/src/libpcp/src/interp.c
index d7effbc1e..c8f6fe382 100644
--- a/src/libpcp/src/interp.c
+++ b/src/libpcp/src/interp.c
@@ -1312,7 +1312,9 @@ __pmLogFetchInterp(__pmContext *ctxp, int numpmid, pmID pmidlist[], pmResult **r
}
/* get to the last remembered place */
- __pmLogChangeVol(ctxp->c_archctl, ctxp->c_archctl->ac_vol);
+ sts = __pmLogChangeVol(ctxp->c_archctl, ctxp->c_archctl->ac_vol);
+ if (sts < 0)
+ goto all_done;
__pmFseek(ctxp->c_archctl->ac_mfp, ctxp->c_archctl->ac_offset, SEEK_SET);
seen_mark = 0; /* interested in <mark> records seen from here on */
@@ -1397,7 +1399,9 @@ __pmLogFetchInterp(__pmContext *ctxp, int numpmid, pmID pmidlist[], pmResult **r
* at least one metric requires a bound from earlier in the log ...
* position ourselves, ... and search
*/
- __pmLogChangeVol(ctxp->c_archctl, ctxp->c_archctl->ac_vol);
+ sts = __pmLogChangeVol(ctxp->c_archctl, ctxp->c_archctl->ac_vol);
+ if (sts < 0)
+ goto all_done;
__pmFseek(ctxp->c_archctl->ac_mfp, ctxp->c_archctl->ac_offset, SEEK_SET);
done = 0;
@@ -1542,7 +1546,9 @@ __pmLogFetchInterp(__pmContext *ctxp, int numpmid, pmID pmidlist[], pmResult **r
* at least one metric requires a bound from later in the log ...
* position ourselves ... and search
*/
- __pmLogChangeVol(ctxp->c_archctl, ctxp->c_archctl->ac_vol);
+ sts = __pmLogChangeVol(ctxp->c_archctl, ctxp->c_archctl->ac_vol);
+ if (sts < 0)
+ goto all_done;
__pmFseek(ctxp->c_archctl->ac_mfp, ctxp->c_archctl->ac_offset, SEEK_SET);
done = 0;
diff --git a/src/libpcp/src/logutil.c b/src/libpcp/src/logutil.c
index fe35ed422..0ef76de25 100644
--- a/src/libpcp/src/logutil.c
+++ b/src/libpcp/src/logutil.c
@@ -1992,7 +1992,10 @@ __pmLogFetch(__pmContext *ctxp, int numpmid, pmID pmidlist[], pmResult **result)
all_derived = check_all_derived(numpmid, pmidlist);
/* re-establish position */
- __pmLogChangeVol(ctxp->c_archctl, ctxp->c_archctl->ac_vol);
+ sts = __pmLogChangeVol(ctxp->c_archctl, ctxp->c_archctl->ac_vol);
+ if (sts < 0)
+ goto func_return;
+ assert(ctxp->c_archctl->ac_mfp != NULL);
__pmFseek(ctxp->c_archctl->ac_mfp,
(long)ctxp->c_archctl->ac_offset, SEEK_SET);
@@ -2489,10 +2492,12 @@ __pmLogSetTime(__pmContext *ctxp)
/* index either not available, or not useful */
if (mode == PM_MODE_FORW) {
__pmLogChangeVol(acp, lcp->l_minvol);
+ assert(acp->ac_mfp != NULL);
__pmFseek(acp->ac_mfp, (long)(sizeof(__pmLogLabel) + 2*sizeof(int)), SEEK_SET);
}
else if (mode == PM_MODE_BACK) {
__pmLogChangeVol(acp, lcp->l_maxvol);
+ assert(acp->ac_mfp != NULL);
__pmFseek(acp->ac_mfp, (long)0, SEEK_END);
}
@@ -3141,6 +3146,7 @@ LogChangeToPreviousArchive(__pmContext *ctxp)
/* Set up to scan backwards from the end of the archive. */
__pmLogChangeVol(acp, lcp->l_maxvol);
+ assert(acp->ac_mfp != NULL);
__pmFseek(acp->ac_mfp, (long)0, SEEK_END);
ctxp->c_archctl->ac_offset = __pmFtell(acp->ac_mfp);
assert(ctxp->c_archctl->ac_offset >= 0);
commit 49bdfdfff83ac165de2bdc9a40e61a56512585d8
Author: Ken McDonell <kenj@kenj.id.au>
Date: Sun Jul 4 10:07:09 2021 +1000
libpcp: redefine __pmLogSetTime()
The problem is that if physical files for the data volumes of an
archive are removed (asynchronously by someone else) while we're
trying to switch volumes then we don't handle this safely.
The previous commit 10763319 was as stop-gap to address Mark's SEGV
issue at https://github.com/performancecopilot/pcp/issues/1338 and
simply handled direct calls to __pmLogChangeVol() and ensured the
return status was checked.
I was aware, then Coverity made a lot more people aware, that this
"fix" was incomplete, specifically the calls to __pmLogChangeVol()
from within __pmLogSetTime() were not checked.
To fix the latter we have to change the type of __pmLogSetTime() from
void to int so we can return status to indicate that __pmLogChangeVol()
has failed. And then make sure all the callers of __pmLogSetTime()
check the status returned from that function.
modified: src/libpcp/src/fetch.c
modified: src/libpcp/src/internal.h
modified: src/libpcp/src/logutil.c
Because this introduces some new -Dlog diagnostics, qa/251 needed
a bit of a make-over.
diff --git a/qa/251 b/qa/251
index 2b8a07917..f9b293e98 100755
--- a/qa/251
+++ b/qa/251
@@ -37,7 +37,7 @@ _filter()
status=1 # failure is the default!
$sudo rm -rf $tmp.* $seq.full
-trap "cd $here; rm -rf $tmp; exit \$status" 0 1 2 3 15
+trap "cd $here; rm -rf $tmp $tmp.*; exit \$status" 0 1 2 3 15
# real QA test starts here
mkdir $tmp
@@ -50,56 +50,62 @@ cd $tmp
for inst in "bin-100" "bin-100,bin-500,bin-900"
do
echo
- echo "All volumes present ... $inst ..."
- pmval -z -O $offset -D128 -t2 -a ok-mv-bar -i $inst sampledso.bin 2>err >out
- egrep 'Skip|Change' err
- _filter <out
+ echo "All volumes present ... $inst ..." | tee -a $here/$seq.full
+ pmval -z -O $offset -Dlog -t2 -a ok-mv-bar -i $inst sampledso.bin 2>$tmp.err >$tmp.out
+ cat $tmp.err >>$here/$seq.full
+ grep '^__pmLogChangeVol:' $tmp.err
+ _filter <$tmp.out
[ -f die ] && exit
echo
- echo "First volume missing ... $inst ..."
+ echo "First volume missing ... $inst ..." | tee -a $here/$seq.full
mv ok-mv-bar.0 foo.0
- pmval -z -O $offset -D128 -t2 -a ok-mv-bar -i $inst sampledso.bin 2>err >out
- egrep 'Skip|Change' err
- _filter <out
+ pmval -z -O $offset -Dlog -t2 -a ok-mv-bar -i $inst sampledso.bin 2>$tmp.err >$tmp.out
+ cat $tmp.err >>$here/$seq.full
+ grep '^__pmLogChangeVol:' $tmp.err
+ _filter <$tmp.out
[ -f die ] && exit
mv foo.0 ok-mv-bar.0
echo
- echo "Last volume missing ... $inst ..."
+ echo "Last volume missing ... $inst ..." | tee -a $here/$seq.full
mv ok-mv-bar.3 foo.3
- pmval -z -O $offset -D128 -t2 -a ok-mv-bar -i $inst sampledso.bin 2>err >out
- egrep 'Skip|Change' err
- _filter <out
+ pmval -z -O $offset -Dlog -t2 -a ok-mv-bar -i $inst sampledso.bin 2>$tmp.err >$tmp.out
+ cat $tmp.err >>$here/$seq.full
+ grep '^__pmLogChangeVol:' $tmp.err
+ _filter <$tmp.out
[ -f die ] && exit
mv foo.3 ok-mv-bar.3
echo
- echo "Second volume missing ... $inst ..."
+ echo "Second volume missing ... $inst ..." | tee -a $here/$seq.full
mv ok-mv-bar.1 foo.1
- pmval -z -O $offset -D128 -t2 -a ok-mv-bar -i $inst sampledso.bin 2>err >out
- egrep 'Skip|Change' err
- _filter <out
+ pmval -z -O $offset -Dlog -t2 -a ok-mv-bar -i $inst sampledso.bin 2>$tmp.err >$tmp.out
+ cat $tmp.err >>$here/$seq.full
+ grep '^__pmLogChangeVol:' $tmp.err
+ _filter <$tmp.out
[ -f die ] && exit
mv foo.1 ok-mv-bar.1
echo
- echo "Second last volume missing ... $inst ..."
+ echo "Second last volume missing ... $inst ..." | tee -a $here/$seq.full
mv ok-mv-bar.2 foo.2
- pmval -z -O $offset -D128 -t2 -a ok-mv-bar -i $inst sampledso.bin 2>err >out
- egrep 'Skip|Change' err
- _filter <out
+ pmval -z -O $offset -Dlog -t2 -a ok-mv-bar -i $inst sampledso.bin 2>$tmp.err >$tmp.out
+ cat $tmp.err >>$here/$seq.full
+ grep '^__pmLogChangeVol:' $tmp.err
+ _filter <$tmp.out
[ -f die ] && exit
mv foo.2 ok-mv-bar.2
echo
- echo "All volumes but second missing ... $inst ..."
+ echo "All volumes but second missing ... $inst ..." | tee -a $here/$seq.full
mv ok-mv-bar.0 foo.0
mv ok-mv-bar.2 foo.2
mv ok-mv-bar.3 foo.3
- pmval -z -O $offset -D128 -t2 -a ok-mv-bar -i $inst sampledso.bin 2>err >out
- egrep 'Skip|Change' err
- _filter <out
+ pmval -z -O $offset -Dlog -t2 -a ok-mv-bar -i $inst sampledso.bin 2>$tmp.err >$tmp.out
+ cat $tmp.err >>$here/$seq.full
+ grep '^__pmLogChangeVol:' $tmp.err
+ _filter <$tmp.out
[ -f die ] && exit
mv foo.0 ok-mv-bar.0
mv foo.2 ok-mv-bar.2
diff --git a/src/libpcp/src/fetch.c b/src/libpcp/src/fetch.c
index 5328a2807..01d5bf7fc 100644
--- a/src/libpcp/src/fetch.c
+++ b/src/libpcp/src/fetch.c
@@ -458,6 +458,7 @@ pmSetMode(int mode, const struct timeval *when, int delta)
/* assume PM_CONTEXT_ARCHIVE */
if (l_mode == PM_MODE_INTERP ||
l_mode == PM_MODE_FORW || l_mode == PM_MODE_BACK) {
+ int lsts;
if (when != NULL) {
/*
* special case of NULL for timestamp
@@ -468,7 +469,18 @@ pmSetMode(int mode, const struct timeval *when, int delta)
}
ctxp->c_mode = mode;
ctxp->c_delta = delta;
- __pmLogSetTime(ctxp);
+ lsts = __pmLogSetTime(ctxp);
+ if (lsts < 0) {
+ /*
+ * most unlikely; not much we can do here but expect
+ * PMAPI error to be returned once pmFetch's start
+ */
+ if (pmDebugOptions.log) {
+ char errmsg[PM_MAXERRMSGLEN];
+ fprintf(stderr, "pmSetMode: __pmLogSetTime failed: %s\n",
+ pmErrStr_r(lsts, errmsg, sizeof(errmsg)));
+ }
+ }
__pmLogResetInterp(ctxp);
sts = 0;
}
diff --git a/src/libpcp/src/internal.h b/src/libpcp/src/internal.h
index 977efdcf6..fd8d6e740 100644
--- a/src/libpcp/src/internal.h
+++ b/src/libpcp/src/internal.h
@@ -407,7 +407,7 @@ extern int __pmLogGenerateMark(__pmLogCtl *, int, pmResult **) _PCP_HIDDEN;
extern int __pmLogFetchInterp(__pmContext *, int, pmID *, pmResult **) _PCP_HIDDEN;
extern int __pmGetArchiveLabel(__pmLogCtl *, pmLogLabel *) _PCP_HIDDEN;
extern pmTimeval *__pmLogStartTime(__pmArchCtl *) _PCP_HIDDEN;
-extern void __pmLogSetTime(__pmContext *) _PCP_HIDDEN;
+extern int __pmLogSetTime(__pmContext *) _PCP_HIDDEN;
extern void __pmLogResetInterp(__pmContext *) _PCP_HIDDEN;
extern void __pmArchCtlFree(__pmArchCtl *) _PCP_HIDDEN;
extern int __pmLogChangeArchive(__pmContext *, int) _PCP_HIDDEN;
diff --git a/src/libpcp/src/logutil.c b/src/libpcp/src/logutil.c
index 0ef76de25..2ea559bfe 100644
--- a/src/libpcp/src/logutil.c
+++ b/src/libpcp/src/logutil.c
@@ -1995,7 +1995,6 @@ __pmLogFetch(__pmContext *ctxp, int numpmid, pmID pmidlist[], pmResult **result)
sts = __pmLogChangeVol(ctxp->c_archctl, ctxp->c_archctl->ac_vol);
if (sts < 0)
goto func_return;
- assert(ctxp->c_archctl->ac_mfp != NULL);
__pmFseek(ctxp->c_archctl->ac_mfp,
(long)ctxp->c_archctl->ac_offset, SEEK_SET);
@@ -2010,7 +2009,9 @@ more:
* no serial access, so need to make sure we are
* starting in the correct place
*/
- __pmLogSetTime(ctxp);
+ sts = __pmLogSetTime(ctxp);
+ if (sts < 0)
+ goto func_return;
ctxp->c_archctl->ac_offset = __pmFtell(ctxp->c_archctl->ac_mfp);
ctxp->c_archctl->ac_vol = ctxp->c_archctl->ac_curvol;
/*
@@ -2299,7 +2300,7 @@ VolSkip(__pmArchCtl *acp, int mode, int j)
return PM_ERR_EOL;
}
-void
+int
__pmLogSetTime(__pmContext *ctxp)
{
__pmArchCtl *acp = ctxp->c_archctl;
@@ -2356,6 +2357,7 @@ __pmLogSetTime(__pmContext *ctxp)
if (lcp->l_numti) {
/* we have a temporal index, use it! */
int j = -1;
+ int try;
int toobig = 0;
int match = 0;
int vol;
@@ -2406,9 +2408,13 @@ __pmLogSetTime(__pmContext *ctxp)
acp->ac_serial = 1;
if (match) {
+ try = j;
j = VolSkip(acp, mode, j);
- if (j < 0)
- return;
+ if (j < 0) {
+ if (pmDebugOptions.log)
+ fprintf(stderr, "__pmLogSetTime: VolSkip mode=%d vol=%d failed #1\n", mode, try);
+ return PM_ERR_LOGFILE;
+ }
__pmFseek(acp->ac_mfp, (long)lcp->l_ti[j].ti_log, SEEK_SET);
if (mode == PM_MODE_BACK)
acp->ac_serial = 0;
@@ -2418,9 +2424,13 @@ __pmLogSetTime(__pmContext *ctxp)
}
}
else if (j < 1) {
+ try = 0;
j = VolSkip(acp, PM_MODE_FORW, 0);
- if (j < 0)
- return;
+ if (j < 0) {
+ if (pmDebugOptions.log)
+ fprintf(stderr, "__pmLogSetTime: VolSkip mode=%d vol=%d failed #2\n", PM_MODE_FORW, try);
+ return PM_ERR_LOGFILE;
+ }
__pmFseek(acp->ac_mfp, (long)lcp->l_ti[j].ti_log, SEEK_SET);
if (pmDebugOptions.log) {
fprintf(stderr, " before start ti@");
@@ -2428,9 +2438,13 @@ __pmLogSetTime(__pmContext *ctxp)
}
}
else if (j == numti) {
+ try = numti-1;
j = VolSkip(acp, PM_MODE_BACK, numti-1);
- if (j < 0)
- return;
+ if (j < 0) {
+ if (pmDebugOptions.log)
+ fprintf(stderr, "__pmLogSetTime: VolSkip mode=%d vol=%d failed #3\n", PM_MODE_BACK, try);
+ return PM_ERR_LOGFILE;
+ }
__pmFseek(acp->ac_mfp, (long)lcp->l_ti[j].ti_log, SEEK_SET);
if (mode == PM_MODE_BACK)
acp->ac_serial = 0;
@@ -2450,9 +2464,13 @@ __pmLogSetTime(__pmContext *ctxp)
t_hi = __pmTimevalSub(&lcp->l_ti[j].ti_stamp, &ctxp->c_origin);
t_lo = __pmTimevalSub(&ctxp->c_origin, &lcp->l_ti[j-1].ti_stamp);
if (t_hi <= t_lo && !toobig) {
+ try = j;
j = VolSkip(acp, mode, j);
- if (j < 0)
- return;
+ if (j < 0) {
+ if (pmDebugOptions.log)
+ fprintf(stderr, "__pmLogSetTime: VolSkip mode=%d vol=%d failed #4\n", mode, try);
+ return PM_ERR_LOGFILE;
+ }
__pmFseek(acp->ac_mfp, (long)lcp->l_ti[j].ti_log, SEEK_SET);
if (mode == PM_MODE_FORW)
acp->ac_serial = 0;
@@ -2462,9 +2480,13 @@ __pmLogSetTime(__pmContext *ctxp)
}
}
else {
+ try = j-1;
j = VolSkip(acp, mode, j-1);
- if (j < 0)
- return;
+ if (j < 0) {
+ if (pmDebugOptions.log)
+ fprintf(stderr, "__pmLogSetTime: VolSkip mode=%d vol=%d failed #5\n", mode, try);
+ return PM_ERR_LOGFILE;
+ }
__pmFseek(acp->ac_mfp, (long)lcp->l_ti[j].ti_log, SEEK_SET);
if (mode == PM_MODE_BACK)
acp->ac_serial = 0;
@@ -2490,14 +2512,37 @@ __pmLogSetTime(__pmContext *ctxp)
}
else {
/* index either not available, or not useful */
+ int j;
if (mode == PM_MODE_FORW) {
- __pmLogChangeVol(acp, lcp->l_minvol);
- assert(acp->ac_mfp != NULL);
+ for (j = lcp->l_minvol; j <= lcp->l_maxvol; j++) {
+ if (__pmLogChangeVol(acp, j) >= 0)
+ break;
+ }
+ if (j > lcp->l_maxvol) {
+ /* no volume found */
+ if (pmDebugOptions.log)
+ fprintf(stderr, " index not useful, no volume between %d...%d\n",
+ lcp->l_minvol, lcp->l_maxvol);
+ acp->ac_curvol = -1;
+ acp->ac_mfp = NULL;
+ return PM_ERR_LOGFILE;
+ }
__pmFseek(acp->ac_mfp, (long)(sizeof(__pmLogLabel) + 2*sizeof(int)), SEEK_SET);
}
else if (mode == PM_MODE_BACK) {
- __pmLogChangeVol(acp, lcp->l_maxvol);
- assert(acp->ac_mfp != NULL);
+ for (j = lcp->l_maxvol; j >= lcp->l_minvol; j--) {
+ if (__pmLogChangeVol(acp, j) >= 0)
+ break;
+ }
+ if (j < lcp->l_minvol) {
+ /* no volume found */
+ if (pmDebugOptions.log)
+ fprintf(stderr, " index not useful, no volume between %d...%d\n",
+ lcp->l_maxvol, lcp->l_minvol);
+ acp->ac_curvol = -1;
+ acp->ac_mfp = NULL;
+ return PM_ERR_LOGFILE;
+ }
__pmFseek(acp->ac_mfp, (long)0, SEEK_END);
}
@@ -2513,6 +2558,8 @@ __pmLogSetTime(__pmContext *ctxp)
acp->ac_offset = __pmFtell(acp->ac_mfp);
assert(acp->ac_offset >= 0);
acp->ac_vol = acp->ac_curvol;
+
+ return 0;
}
/* Read the label of the current archive. */
@@ -3100,6 +3147,7 @@ LogChangeToPreviousArchive(__pmContext *ctxp)
pmTimeval save_origin;
int save_mode;
int sts;
+ int j;
/*
* Check whether there is a previous archive to switch to.
@@ -3145,12 +3193,23 @@ LogChangeToPreviousArchive(__pmContext *ctxp)
}
/* Set up to scan backwards from the end of the archive. */
- __pmLogChangeVol(acp, lcp->l_maxvol);
- assert(acp->ac_mfp != NULL);
+ for (j = lcp->l_maxvol; j >= lcp->l_minvol; j--) {
+ if (__pmLogChangeVol(acp, j) >= 0)
+ break;
+ }
+ if (j < lcp->l_minvol) {
+ /* no volume found */
+ if (pmDebugOptions.log)
+ fprintf(stderr, "LogChangeToPreviousArchive: no volume between %d...%d\n",
+ lcp->l_maxvol, lcp->l_minvol);
+ acp->ac_curvol = -1;
+ acp->ac_mfp = NULL;
+ return PM_ERR_LOGFILE;
+ }
__pmFseek(acp->ac_mfp, (long)0, SEEK_END);
- ctxp->c_archctl->ac_offset = __pmFtell(acp->ac_mfp);
- assert(ctxp->c_archctl->ac_offset >= 0);
- ctxp->c_archctl->ac_vol = ctxp->c_archctl->ac_curvol;
+ acp->ac_offset = __pmFtell(acp->ac_mfp);
+ assert(acp->ac_offset >= 0);
+ acp->ac_vol = acp->ac_curvol;
/*
* Check for temporal overlap here. Do this last in case the API client
commit 5e3b792d3d8ae60f2cebbd51c37b9b0722c3b26e
Author: Mark Goodwin <mgoodwin@redhat.com>
Date: Tue Jul 6 20:09:28 2021 +1000
libpcp_web: plug mem leak in redisMapInsert during daily log-rolling
When pmlogger_daily processes daily archives, the resulting
merged archive(s) are discovered and processed by pmproxy
(if the discovery module is enabled). Since the metadata and
logvol data in each merged archive is likely to have already
been previously processed (but discovery doesn't know this),
we see a lot of dict updates for existing keys and values that
are already mapped.
Static analysis by Coverity (CID323605 Resource Leak) shows
when redisMapInsert calls dictAdd for an existing key, the
new value field is assigned but the old value is not free'd,
and so it leaks.
Related: RHBZ1975069 and https://github.com/performancecopilot/pcp/issues/1318
diff --git a/src/libpcp_web/src/maps.c b/src/libpcp_web/src/maps.c
index 013ef02d3..ce20476c9 100644
--- a/src/libpcp_web/src/maps.c
+++ b/src/libpcp_web/src/maps.c
@@ -160,6 +160,12 @@ redisMapLookup(redisMap *map, sds key)
void
redisMapInsert(redisMap *map, sds key, sds value)
{
+ redisMapEntry *entry = redisMapLookup(map, key);
+
+ if (entry) {
+ /* fix for Coverity CID323605 Resource Leak */
+ dictDelete(map, key);
+ }
dictAdd(map, key, value);
}
commit 2a00a90b0bc3aecb8465fd32aef1ddbe745b2c91
Author: Mark Goodwin <mgoodwin@redhat.com>
Date: Tue Jul 6 20:43:01 2021 +1000
libpcp_web/discovery: improve lock handling and scalability
Rework the global log-rolling lock detection with finer grain
(per-pmlogger directory) detection, and break early in
process_meta() and process_logvol() if a lock file is found
in the same directory as a monitored archive. This is much
more scalable since archive directories that are not locked
can continue to be processed and ingested whilst log-rolling
progresses elsewhere. Also uses much less CPU time since we
don't need a traversal of all monitored archives looking for
locks on every fs change event.
Also improve process_logvol/meta handling for archives that
are deleted whilst being processed by the discovery module.
In conjunction with Kenj's changes in libpcp - stop processing
metadata and logvols if pmFetchArchive returns -ENOENT .. the
archive has been deleted so there is no point further ingesting
it's data.
Related: RHBZ1975069
Related: https://github.com/performancecopilot/pcp/issues/1338
diff --git a/src/libpcp_web/src/discover.c b/src/libpcp_web/src/discover.c
index 991055ce5..964813f66 100644
--- a/src/libpcp_web/src/discover.c
+++ b/src/libpcp_web/src/discover.c
@@ -33,9 +33,6 @@ static char *pmDiscoverFlagsStr(pmDiscover *);
#define PM_DISCOVER_HASHTAB_SIZE 32
static pmDiscover *discover_hashtable[PM_DISCOVER_HASHTAB_SIZE];
-/* pmlogger_daily log-roll lock count */
-static int logrolling = 0;
-
/* number of archives or directories currently being monitored */
static int n_monitored = 0;
@@ -426,28 +423,6 @@ is_deleted(pmDiscover *p, struct stat *sbuf)
return ret;
}
-static int
-check_for_locks()
-{
- int i;
- pmDiscover *p;
- char sep = pmPathSeparator();
- char path[MAXNAMELEN];
-
- for (i=0; i < PM_DISCOVER_HASHTAB_SIZE; i++) {
- for (p = discover_hashtable[i]; p; p = p->next) {
- if (p->flags & PM_DISCOVER_FLAGS_DIRECTORY) {
- pmsprintf(path, sizeof(path), "%s%c%s", p->context.name, sep, "lock");
- if (access(path, F_OK) == 0)
- return 1;
- }
- }
- }
-
- /* no locks */
- return 0;
-}
-
static void
check_deleted(pmDiscover *p)
{
@@ -465,37 +440,8 @@ fs_change_callBack(uv_fs_event_t *handle, const char *filename, int events, int
pmDiscover *p;
char *s;
sds path;
- int locksfound = 0;
struct stat statbuf;
- /*
- * check if logs are currently being rolled by pmlogger_daily et al
- * in any of the directories we are tracking. For mutex, the log control
- * scripts use a 'lock' file in each directory as it is processed.
- */
- locksfound = check_for_locks();
-
- if (!logrolling && locksfound) {
- /* log-rolling has started */
- if (pmDebugOptions.discovery)
- fprintf(stderr, "%s discovery callback: log-rolling in progress\n", stamp());
- logrolling = locksfound;
- return;
- }
-
- if (logrolling && locksfound) {
- logrolling = locksfound;
- return; /* still in progress */
- }
-
- if (logrolling && !locksfound) {
- /* log-rolling is finished: check what got deleted, and then purge */
- if (pmDebugOptions.discovery)
- fprintf(stderr, "%s discovery callback: finished log-rolling\n", stamp());
- pmDiscoverTraverse(PM_DISCOVER_FLAGS_META|PM_DISCOVER_FLAGS_DATAVOL, check_deleted);
- }
- logrolling = locksfound;
-
uv_fs_event_getpath(handle, buffer, &bytes);
path = sdsnewlen(buffer, bytes);
@@ -1037,6 +983,17 @@ pmDiscoverNewSource(pmDiscover *p, int context)
pmDiscoverInvokeSourceCallBacks(p, &timestamp);
}
+static char *
+archive_dir_lock_path(pmDiscover *p)
+{
+ char path[MAXNAMELEN], lockpath[MAXNAMELEN];
+ int sep = pmPathSeparator();
+
+ strncpy(path, p->context.name, sizeof(path)-1);
+ pmsprintf(lockpath, sizeof(lockpath), "%s%c%s", dirname(path), sep, "lock");
+ return strndup(lockpath, sizeof(lockpath));
+}
+
/*
* Process metadata records until EOF. That can span multiple
* callbacks if we get a partial record read.
@@ -1059,6 +1016,7 @@ process_metadata(pmDiscover *p)
__pmLogHdr hdr;
sds msg, source;
static uint32_t *buf = NULL;
+ char *lock_path;
int deleted;
struct stat sbuf;
static int buflen = 0;
@@ -1073,7 +1031,10 @@ process_metadata(pmDiscover *p)
fprintf(stderr, "process_metadata: %s in progress %s\n",
p->context.name, pmDiscoverFlagsStr(p));
pmDiscoverStatsAdd(p->module, "metadata.callbacks", NULL, 1);
+ lock_path = archive_dir_lock_path(p);
for (;;) {
+ if (lock_path && access(lock_path, F_OK) == 0)
+ break;
pmDiscoverStatsAdd(p->module, "metadata.loops", NULL, 1);
off = lseek(p->fd, 0, SEEK_CUR);
nb = read(p->fd, &hdr, sizeof(__pmLogHdr));
@@ -1240,6 +1201,9 @@ process_metadata(pmDiscover *p)
/* flag that all available metadata has now been read */
p->flags &= ~PM_DISCOVER_FLAGS_META_IN_PROGRESS;
+ if (lock_path)
+ free(lock_path);
+
if (pmDebugOptions.discovery)
fprintf(stderr, "%s: completed, partial=%d %s %s\n",
"process_metadata", partial, p->context.name, pmDiscoverFlagsStr(p));
@@ -1266,14 +1230,18 @@ static void
process_logvol(pmDiscover *p)
{
int sts;
- pmResult *r;
+ pmResult *r = NULL;
pmTimespec ts;
int oldcurvol;
__pmContext *ctxp;
__pmArchCtl *acp;
+ char *lock_path;
pmDiscoverStatsAdd(p->module, "logvol.callbacks", NULL, 1);
+ lock_path = archive_dir_lock_path(p);
for (;;) {
+ if (lock_path && access(lock_path, F_OK) == 0)
+ break;
pmDiscoverStatsAdd(p->module, "logvol.loops", NULL, 1);
pmUseContext(p->ctx);
ctxp = __pmHandleToPtr(p->ctx);
@@ -1312,6 +1280,7 @@ process_logvol(pmDiscover *p)
}
/* we are done - return and wait for another callback */
+ r = NULL;
break;
}
@@ -1328,14 +1297,15 @@ process_logvol(pmDiscover *p)
}
/*
- * TODO: persistently save current timestamp, so after being restarted,
- * pmproxy can resume where it left off for each archive.
+ * TODO (perhaps): persistently save current timestamp, so after being
+ * restarted, pmproxy can resume where it left off for each archive.
*/
ts.tv_sec = r->timestamp.tv_sec;
ts.tv_nsec = r->timestamp.tv_usec * 1000;
bump_logvol_decode_stats(p, r);
pmDiscoverInvokeValuesCallBack(p, &ts, r);
pmFreeResult(r);
+ r = NULL;
}
if (r) {
@@ -1348,6 +1318,9 @@ process_logvol(pmDiscover *p)
/* datavol is now up-to-date and at EOF */
p->flags &= ~PM_DISCOVER_FLAGS_DATAVOL_READY;
+
+ if (lock_path)
+ free(lock_path);
}
static void
@@ -1357,6 +1330,10 @@ pmDiscoverInvokeCallBacks(pmDiscover *p)
sds msg;
sds metaname;
+ check_deleted(p);
+ if (p->flags & PM_DISCOVER_FLAGS_DELETED)
+ return; /* ignore deleted archive */
+
if (p->ctx < 0) {
/*
* once off initialization on the first event
@@ -1366,16 +1343,23 @@ pmDiscoverInvokeCallBacks(pmDiscover *p)
/* create the PMAPI context (once off) */
if ((sts = pmNewContext(p->context.type, p->context.name)) < 0) {
- /*
- * Likely an early callback on a new (still empty) archive.
- * If so, just ignore the callback and don't log any scary
- * looking messages. We'll get another CB soon.
- */
- if (sts != PM_ERR_NODATA || pmDebugOptions.desperate) {
- infofmt(msg, "pmNewContext failed for %s: %s\n",
- p->context.name, pmErrStr(sts));
- moduleinfo(p->module, PMLOG_ERROR, msg, p->data);
+ if (sts == -ENOENT) {
+ /* newly deleted archive */
+ p->flags |= PM_DISCOVER_FLAGS_DELETED;
}
+ else {
+ /*
+ * Likely an early callback on a new (still empty) archive.
+ * If so, just ignore the callback and don't log any scary
+ * looking messages. We'll get another CB soon.
+ */
+ if (sts != PM_ERR_NODATA || pmDebugOptions.desperate) {
+ infofmt(msg, "pmNewContext failed for %s: %s\n",
+ p->context.name, pmErrStr(sts));
+ moduleinfo(p->module, PMLOG_ERROR, msg, p->data);
+ }
+ }
+ /* no further processing for this archive */
return;
}
pmDiscoverStatsAdd(p->module, "logvol.new_contexts", NULL, 1);
@@ -1410,8 +1394,12 @@ pmDiscoverInvokeCallBacks(pmDiscover *p)
metaname = sdsnew(p->context.name);
metaname = sdscat(metaname, ".meta");
if ((p->fd = open(metaname, O_RDONLY)) < 0) {
- infofmt(msg, "open failed for %s: %s\n", metaname, osstrerror());
- moduleinfo(p->module, PMLOG_ERROR, msg, p->data);
+ if (p->fd == -ENOENT)
+ p->flags |= PM_DISCOVER_FLAGS_DELETED;
+ else {
+ infofmt(msg, "open failed for %s: %s\n", metaname, osstrerror());
+ moduleinfo(p->module, PMLOG_ERROR, msg, p->data);
+ }
sdsfree(metaname);
return;
}

View File

@ -0,0 +1,374 @@
diff --git a/qa/1927 b/qa/1927
new file mode 100755
index 000000000..46afa9509
--- /dev/null
+++ b/qa/1927
@@ -0,0 +1,88 @@
+#!/bin/sh
+# PCP QA Test No. 1927
+# Exercise the sockets PMDA Install/Remove and string metric bug.
+#
+# Copyright (c) 2022 Red Hat. All Rights Reserved.
+#
+
+seq=`basename $0`
+echo "QA output created by $seq"
+
+# get standard environment, filters and checks
+. ./common.product
+. ./common.filter
+. ./common.check
+
+[ -f $PCP_PMDAS_DIR/sockets/pmdasockets ] || _notrun "sockets pmda not installed"
+
+_cleanup()
+{
+ cd $here
+ $sudo rm -rf $tmp $tmp.*
+}
+
+status=0 # success is the default!
+$sudo rm -rf $tmp $tmp.* $seq.full
+
+_filter_sockets()
+{
+ grep -v 'No value(s) available'
+}
+
+pmdasockets_remove()
+{
+ echo
+ echo "=== remove sockets agent ==="
+ $sudo ./Remove >$tmp.out 2>&1
+ _filter_pmda_remove <$tmp.out
+}
+
+pmdasockets_install()
+{
+ # start from known starting points
+ cd $PCP_PMDAS_DIR/sockets
+ $sudo ./Remove >/dev/null 2>&1
+
+ echo
+ echo "=== sockets agent installation ==="
+ $sudo ./Install </dev/null >$tmp.out 2>&1
+ cat $tmp.out >>$here/$seq.full
+ # Check sockets metrics have appeared ... X metrics and Y values
+ _filter_pmda_install <$tmp.out \
+ | sed \
+ -e 's/[0-9][0-9]* warnings, //' \
+ | $PCP_AWK_PROG '
+/Check network.persocket metrics have appeared/ {
+ if ($7 >= 50 && $7 <= 99) $7 = "X"
+ if ($10 >= 0) $10 = "Y"
+ }
+ { print }'
+}
+
+_prepare_pmda sockets
+# note: _restore_auto_restart pmcd done in _cleanup_pmda()
+trap "_cleanup_pmda sockets; exit \$status" 0 1 2 3 15
+
+_stop_auto_restart pmcd
+
+# real QA test starts here
+pmdasockets_install
+
+# pmcd should have been started by the Install process - check
+if pminfo -v network.persocket > $tmp.info 2> $tmp.err
+then
+ :
+else
+ echo "... failed! ... here is the Install log ..."
+ cat $tmp.out
+fi
+cat $tmp.info $tmp.err | _filter_sockets
+
+echo "Check the values for v6only metric are 0 or 1 ..."
+pminfo -f network.persocket.v6only | egrep -v 'value [01]$' | sed -e '/^$/d'
+
+pmdasockets_remove
+status=0
+
+# success, all done
+exit
diff --git a/qa/1927.out b/qa/1927.out
new file mode 100644
index 000000000..2ae4385fd
--- /dev/null
+++ b/qa/1927.out
@@ -0,0 +1,17 @@
+QA output created by 1927
+
+=== sockets agent installation ===
+Updating the Performance Metrics Name Space (PMNS) ...
+Terminate PMDA if already installed ...
+[...install files, make output...]
+Updating the PMCD control file, and notifying PMCD ...
+Check network.persocket metrics have appeared ... X metrics and Y values
+Check the values for v6only metric are 0 or 1 ...
+network.persocket.v6only
+
+=== remove sockets agent ===
+Culling the Performance Metrics Name Space ...
+network.persocket ... done
+Updating the PMCD control file, and notifying PMCD ...
+[...removing files...]
+Check network.persocket metrics have gone away ... OK
diff --git a/qa/group b/qa/group
index acfc5d208..846c0c4bd 100644
--- a/qa/group
+++ b/qa/group
@@ -1967,6 +1967,7 @@ x11
1901 pmlogger local
1902 help local
1914 atop local
+1927 pmda.sockets local
1937 pmlogrewrite pmda.xfs local
1955 libpcp pmda pmda.pmcd local
1956 pmda.linux pmcd local
diff --git a/src/pmdas/linux_sockets/pmda.c b/src/pmdas/linux_sockets/pmda.c
index d10eacf29..5a3018d8a 100644
--- a/src/pmdas/linux_sockets/pmda.c
+++ b/src/pmdas/linux_sockets/pmda.c
@@ -1,7 +1,7 @@
/*
* Sockets PMDA
*
- * Copyright (c) 2021 Red Hat.
+ * Copyright (c) 2021-2022 Red Hat.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -14,6 +14,7 @@
* for more details.
*/
+#include <ctype.h>
#include "pmapi.h"
#include "pmda.h"
@@ -147,6 +148,31 @@ sockets_fetchCallBack(pmdaMetric *metric, unsigned int inst, pmAtomValue *atom)
return PMDA_FETCH_STATIC;
}
+/*
+ * Restrict the allowed filter strings to only limited special
+ * characters (open and close brackets - everthing else can be
+ * done with alphanumerics) to limit any attack surface here.
+ * The ss filtering language is more complex than we ever want
+ * to be attempting to parse ourself, so we leave that side of
+ * things to the ss command itself.
+ */
+int
+sockets_check_filter(const char *string)
+{
+ const char *p;
+
+ for (p = string; *p; p++) {
+ if (isspace(*p))
+ continue;
+ if (isalnum(*p))
+ continue;
+ if (*p == '(' || *p == ')')
+ continue;
+ return 0; /* disallow */
+ }
+ return 1;
+}
+
static int
sockets_store(pmResult *result, pmdaExt *pmda)
{
@@ -165,9 +191,14 @@ sockets_store(pmResult *result, pmdaExt *pmda)
case 0: /* network.persocket.filter */
if ((sts = pmExtractValue(vsp->valfmt, &vsp->vlist[0],
PM_TYPE_STRING, &av, PM_TYPE_STRING)) >= 0) {
+ if (sockets_check_filter(av.cp)) {
+ sts = PM_ERR_BADSTORE;
+ free(av.cp);
+ break;
+ }
if (ss_filter)
free(ss_filter);
- ss_filter = av.cp; /* TODO filter syntax check */
+ ss_filter = av.cp;
}
break;
default:
diff --git a/src/pmdas/linux_sockets/ss_parse.c b/src/pmdas/linux_sockets/ss_parse.c
index 94c5e16e9..9f3afc691 100644
--- a/src/pmdas/linux_sockets/ss_parse.c
+++ b/src/pmdas/linux_sockets/ss_parse.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 Red Hat.
+ * Copyright (c) 2021-2022 Red Hat.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -21,65 +21,70 @@ static ss_stats_t ss_p;
/* boolean value with no separate value, default 0 */
#define PM_TYPE_BOOL (PM_TYPE_UNKNOWN-1)
+/* helper macros to extract field address and size */
+#define SSFIELD(str,type,f) {(str), (sizeof(str)-1), type, (&(f)), (sizeof(f))}
+#define SSNULLFIELD(str) {(str), (sizeof(str)-1), PM_TYPE_UNKNOWN, NULL}
+
static struct {
char *field;
int len;
int type;
void *addr;
+ int size;
int found;
} parse_table[] = {
- { "timer:", 6, PM_TYPE_STRING, &ss_p.timer_str },
- { "uid:", 4, PM_TYPE_U32, &ss_p.uid },
- { "ino:", 4, PM_TYPE_64, &ss_p.inode },
- { "sk:", 3, PM_TYPE_U64, &ss_p.sk },
- { "cgroup:", 7, PM_TYPE_STRING, &ss_p.cgroup },
- { "v6only:", 7, PM_TYPE_32, &ss_p.v6only },
- { "--- ", 4, PM_TYPE_UNKNOWN, NULL },
- { "<-> ", 4, PM_TYPE_UNKNOWN, NULL },
- { "--> ", 4, PM_TYPE_UNKNOWN, NULL },
- { "skmem:", 6, PM_TYPE_STRING, &ss_p.skmem_str, },
- { "ts ", 3, PM_TYPE_BOOL, &ss_p.ts },
- { "sack ", 5, PM_TYPE_BOOL, &ss_p.sack },
- { "cubic ", 6, PM_TYPE_BOOL, &ss_p.cubic },
- { "wscale:", 7, PM_TYPE_STRING, &ss_p.wscale_str },
- { "rto:", 4, PM_TYPE_DOUBLE, &ss_p.rto },
- { "rtt:", 4, PM_TYPE_STRING, &ss_p.round_trip_str },
- { "ato:", 4, PM_TYPE_DOUBLE, &ss_p.ato },
- { "backoff:", 8, PM_TYPE_32, &ss_p.backoff },
- { "mss:", 4, PM_TYPE_U32, &ss_p.mss },
- { "pmtu:", 5, PM_TYPE_U32, &ss_p.pmtu },
- { "rcvmss:", 7, PM_TYPE_U32, &ss_p.rcvmss },
- { "advmss:", 7, PM_TYPE_U32, &ss_p.advmss },
- { "cwnd:", 5, PM_TYPE_U32, &ss_p.cwnd },
- { "lost:", 5, PM_TYPE_32, &ss_p.lost },
- { "ssthresh:", 9, PM_TYPE_U32, &ss_p.ssthresh },
- { "bytes_sent:", 11, PM_TYPE_U64, &ss_p.bytes_sent },
- { "bytes_retrans:", 14, PM_TYPE_U64, &ss_p.bytes_retrans },
- { "bytes_acked:", 12, PM_TYPE_U64, &ss_p.bytes_acked },
- { "bytes_received:", 15, PM_TYPE_U64, &ss_p.bytes_received },
- { "segs_out:", 9, PM_TYPE_U32, &ss_p.segs_out },
- { "segs_in:", 8, PM_TYPE_U32, &ss_p.segs_in },
- { "data_segs_out:", 14, PM_TYPE_U32, &ss_p.data_segs_out },
- { "data_segs_in:", 13, PM_TYPE_U32, &ss_p.data_segs_in },
- { "send ", 5, PM_TYPE_DOUBLE, &ss_p.send }, /* no ':' */
- { "lastsnd:", 8, PM_TYPE_U32, &ss_p.lastsnd },
- { "lastrcv:", 8, PM_TYPE_U32, &ss_p.lastrcv },
- { "lastack:", 8, PM_TYPE_U32, &ss_p.lastack },
- { "pacing_rate ", 12, PM_TYPE_DOUBLE, &ss_p.pacing_rate }, /* no ':' */
- { "delivery_rate ", 14, PM_TYPE_DOUBLE, &ss_p.delivery_rate }, /* no ':' */
- { "delivered:", 10, PM_TYPE_U32, &ss_p.delivered },
- { "app_limited ", 12, PM_TYPE_BOOL, &ss_p.app_limited },
- { "reord_seen:", 11, PM_TYPE_32, &ss_p.reord_seen },
- { "busy:", 5, PM_TYPE_U64, &ss_p.busy },
- { "unacked:", 8, PM_TYPE_32, &ss_p.unacked },
- { "rwnd_limited:", 13, PM_TYPE_U64, &ss_p.rwnd_limited },
- { "retrans:", 8, PM_TYPE_STRING, &ss_p.retrans_str },
- { "dsack_dups:", 11, PM_TYPE_U32, &ss_p.dsack_dups },
- { "rcv_rtt:", 8, PM_TYPE_DOUBLE, &ss_p.rcv_rtt },
- { "rcv_space:", 10, PM_TYPE_32, &ss_p.rcv_space },
- { "rcv_ssthresh:", 13, PM_TYPE_32, &ss_p.rcv_ssthresh },
- { "minrtt:", 7, PM_TYPE_DOUBLE, &ss_p.minrtt },
- { "notsent:", 8, PM_TYPE_U32, &ss_p.notsent },
+ SSFIELD("timer:", PM_TYPE_STRING, ss_p.timer_str),
+ SSFIELD("uid:", PM_TYPE_U32, ss_p.uid),
+ SSFIELD("ino:", PM_TYPE_64, ss_p.inode),
+ SSFIELD("sk:", PM_TYPE_U64, ss_p.sk),
+ SSFIELD("cgroup:", PM_TYPE_STRING, ss_p.cgroup),
+ SSFIELD("v6only:", PM_TYPE_32, ss_p.v6only),
+ SSNULLFIELD("--- "),
+ SSNULLFIELD("<-> "),
+ SSNULLFIELD("--> "),
+ SSFIELD("skmem:", PM_TYPE_STRING, ss_p.skmem_str),
+ SSFIELD("ts ", PM_TYPE_BOOL, ss_p.ts),
+ SSFIELD("sack ", PM_TYPE_BOOL, ss_p.sack),
+ SSFIELD("cubic ", PM_TYPE_BOOL, ss_p.cubic),
+ SSFIELD("wscale:", PM_TYPE_STRING, ss_p.wscale_str),
+ SSFIELD("rto:", PM_TYPE_DOUBLE, ss_p.rto),
+ SSFIELD("rtt:", PM_TYPE_STRING, ss_p.round_trip_str),
+ SSFIELD("ato:", PM_TYPE_DOUBLE, ss_p.ato),
+ SSFIELD("backoff:", PM_TYPE_32, ss_p.backoff),
+ SSFIELD("mss:", PM_TYPE_U32, ss_p.mss),
+ SSFIELD("pmtu:", PM_TYPE_U32, ss_p.pmtu),
+ SSFIELD("rcvmss:", PM_TYPE_U32, ss_p.rcvmss),
+ SSFIELD("advmss:", PM_TYPE_U32, ss_p.advmss),
+ SSFIELD("cwnd:", PM_TYPE_U32, ss_p.cwnd),
+ SSFIELD("lost:", PM_TYPE_32, ss_p.lost),
+ SSFIELD("ssthresh:", PM_TYPE_U32, ss_p.ssthresh),
+ SSFIELD("bytes_sent:", PM_TYPE_U64, ss_p.bytes_sent),
+ SSFIELD("bytes_retrans:", PM_TYPE_U64, ss_p.bytes_retrans),
+ SSFIELD("bytes_acked:", PM_TYPE_U64, ss_p.bytes_acked),
+ SSFIELD("bytes_received:", PM_TYPE_U64, ss_p.bytes_received),
+ SSFIELD("segs_out:", PM_TYPE_U32, ss_p.segs_out),
+ SSFIELD("segs_in:", PM_TYPE_U32, ss_p.segs_in),
+ SSFIELD("data_segs_out:", PM_TYPE_U32, ss_p.data_segs_out),
+ SSFIELD("data_segs_in:", PM_TYPE_U32, ss_p.data_segs_in),
+ SSFIELD("send ", PM_TYPE_DOUBLE, ss_p.send), /* no ':' */
+ SSFIELD("lastsnd:", PM_TYPE_U32, ss_p.lastsnd),
+ SSFIELD("lastrcv:", PM_TYPE_U32, ss_p.lastrcv),
+ SSFIELD("lastack:", PM_TYPE_U32, ss_p.lastack),
+ SSFIELD("pacing_rate ", PM_TYPE_DOUBLE, ss_p.pacing_rate), /* no ':' */
+ SSFIELD("delivery_rate ", PM_TYPE_DOUBLE, ss_p.delivery_rate), /* no ':' */
+ SSFIELD("delivered:", PM_TYPE_U32, ss_p.delivered),
+ SSFIELD("app_limited ", PM_TYPE_BOOL, ss_p.app_limited),
+ SSFIELD("reord_seen:", PM_TYPE_32, ss_p.reord_seen),
+ SSFIELD("busy:", PM_TYPE_U64, ss_p.busy),
+ SSFIELD("unacked:", PM_TYPE_32, ss_p.unacked),
+ SSFIELD("rwnd_limited:", PM_TYPE_U64, ss_p.rwnd_limited),
+ SSFIELD("retrans:", PM_TYPE_STRING, ss_p.retrans_str),
+ SSFIELD("dsack_dups:", PM_TYPE_U32, ss_p.dsack_dups),
+ SSFIELD("rcv_rtt:", PM_TYPE_DOUBLE, ss_p.rcv_rtt),
+ SSFIELD("rcv_space:", PM_TYPE_32, ss_p.rcv_space),
+ SSFIELD("rcv_ssthresh:", PM_TYPE_32, ss_p.rcv_ssthresh),
+ SSFIELD("minrtt:", PM_TYPE_DOUBLE, ss_p.minrtt),
+ SSFIELD("notsent:", PM_TYPE_U32, ss_p.notsent),
{ NULL }
};
@@ -225,8 +230,11 @@ ss_parse(char *line, int has_state_field, ss_stats_t *ss)
if (*p == '(')
p++;
r = (char *)parse_table[i].addr;
- for (s=p; *s && *s != ' ' && *s != '\n' && *s != ')'; s++)
- *r++ = *s; /* TODO check r len */
+ for (s=p; *s && *s != ' ' && *s != '\n' && *s != ')'; s++) {
+ *r++ = *s;
+ if (r - (char *)parse_table[i].addr >= parse_table[i].size - 1)
+ break;
+ }
*r = '\0';
break;
case PM_TYPE_32:
diff --git a/src/pmdas/linux_sockets/ss_stats.h b/src/pmdas/linux_sockets/ss_stats.h
index 183db5afa..009a00cd9 100644
--- a/src/pmdas/linux_sockets/ss_stats.h
+++ b/src/pmdas/linux_sockets/ss_stats.h
@@ -1,11 +1,11 @@
/*
- * Copyright (c) 2021 Red Hat.
- *
+ * Copyright (c) 2021-2022 Red Hat.
+ *
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
- *
+ *
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
@@ -26,7 +26,7 @@ typedef struct ss_stats {
__int32_t timer_retrans;
__uint32_t uid;
__uint64_t sk;
- char cgroup[64];
+ char cgroup[128];
__int32_t v6only;
char skmem_str[64];
__int32_t skmem_rmem_alloc;

View File

@ -0,0 +1,20 @@
bcc included in RHEL 8.6 doesn't support the kernel_struct_has_field function.
The 4.18.x kernel in RHEL 8.6 did backport the `state` to `__state` rename (upstream:
change was in kernel v5.14+), and now we're in a situation where we can't test for
the existence of this kernel struct member and also can't rely on a kernel version check.
Therefore, let's patch it here for RHEL 8.x only:
diff --git a/src/pmdas/bcc/modules/runqlat.python b/src/pmdas/bcc/modules/runqlat.python
index 1c6c6b4b0..efc30e958 100644
--- a/src/pmdas/bcc/modules/runqlat.python
+++ b/src/pmdas/bcc/modules/runqlat.python
@@ -100,7 +100,7 @@ class PCPBCCModule(PCPBCCBase):
if (
hasattr(BPF, "kernel_struct_has_field")
and BPF.kernel_struct_has_field(b"task_struct", b"__state") == 1
- ) or self.kernel_version() >= (5, 14, 0):
+ ) or self.kernel_version() >= (4, 18, 0):
self.bpf_text = self.bpf_text.replace('STATE_FIELD', '__state')
else:
self.bpf_text = self.bpf_text.replace('STATE_FIELD', 'state')

View File

@ -0,0 +1,11 @@
diff -Naurp pcp-5.3.7.orig/src/pmie/GNUmakefile pcp-5.3.7/src/pmie/GNUmakefile
--- pcp-5.3.7.orig/src/pmie/GNUmakefile 2022-02-02 11:53:05.000000000 +1100
+++ pcp-5.3.7/src/pmie/GNUmakefile 2022-05-03 11:45:12.108743480 +1000
@@ -80,6 +80,7 @@ pmie.service : pmie.service.in
$(SED) <$< >$@ \
-e 's;@PCP_RC_DIR@;'$(PCP_RC_DIR)';' \
-e 's;@PCP_RUN_DIR@;'$(PCP_RUN_DIR)';' \
+ -e 's;@PCP_SYSCONFIG_DIR@;'$(PCP_SYSCONFIG_DIR)';' \
# END
pmie_farm.service : pmie_farm.service.in

View File

@ -0,0 +1,146 @@
commit f54eddf494e474531e5af609bcc376037a918977
Author: Nathan Scott <nathans@redhat.com>
Date: Tue Apr 26 14:32:59 2022 +1000
pmdapostfix: harden against a not-yet-running postfix
Ensure the postfix PMDA can start and service requests even
if postfix is not yet started.
diff --git a/src/perl/PMDA/local.c b/src/perl/PMDA/local.c
index e223bde7a..33130bc5d 100644
--- a/src/perl/PMDA/local.c
+++ b/src/perl/PMDA/local.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2017 Red Hat.
+ * Copyright (c) 2012-2017,2022 Red Hat.
* Copyright (c) 2008-2011 Aconex. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify it
@@ -139,18 +139,15 @@ int
local_tail(char *file, scalar_t *callback, int cookie)
{
int fd = open(file, O_RDONLY | O_NDELAY);
- struct stat stats;
+ struct stat stats = {0};
int me;
- if (fd < 0) {
- pmNotifyErr(LOG_ERR, "open failed (%s): %s", file, osstrerror());
- exit(1);
- }
- if (fstat(fd, &stats) < 0) {
- pmNotifyErr(LOG_ERR, "fstat failed (%s): %s", file, osstrerror());
- exit(1);
- }
- lseek(fd, 0L, SEEK_END);
+ if (fd < 0)
+ pmNotifyErr(LOG_INFO, "open failed (%s): %s", file, osstrerror());
+ else if (fstat(fd, &stats) < 0)
+ pmNotifyErr(LOG_INFO, "fstat failed (%s): %s", file, osstrerror());
+ else
+ lseek(fd, 0L, SEEK_END);
me = local_file(FILE_TAIL, fd, callback, cookie);
files[me].me.tail.path = strdup(file);
files[me].me.tail.dev = stats.st_dev;
@@ -416,10 +413,11 @@ local_pmdaMain(pmdaInterface *self)
}
for (i = 0; i < nfiles; i++) {
- fd = files[i].fd;
/* check for log rotation or host reconnection needed */
if ((count % 10) == 0) /* but only once every 10 */
local_connection(&files[i]);
+ if ((fd = files[i].fd) < 0)
+ continue;
if (files[i].type != FILE_TAIL && !(__pmFD_ISSET(fd, &readyfds)))
continue;
offset = 0;
@@ -431,21 +429,16 @@ multiread:
(oserror() == EAGAIN) ||
(oserror() == EWOULDBLOCK)))
continue;
- if (files[i].type == FILE_SOCK) {
- close(files[i].fd);
- files[i].fd = -1;
- continue;
- }
- pmNotifyErr(LOG_ERR, "Data read error on %s: %s\n",
- local_filetype(files[i].type), osstrerror());
- exit(1);
+ close(files[i].fd);
+ files[i].fd = -1;
+ continue;
}
if (bytes == 0) {
if (files[i].type == FILE_TAIL)
continue;
- pmNotifyErr(LOG_ERR, "No data to read - %s may be closed\n",
- local_filetype(files[i].type));
- exit(1);
+ close(files[i].fd);
+ files[i].fd = -1;
+ continue;
}
/*
* good read ... data up to buffer + offset + bytes is all OK
diff --git a/src/pmdas/postfix/pmdapostfix.pl b/src/pmdas/postfix/pmdapostfix.pl
index ac46816bc..d6d3f4d3a 100644
--- a/src/pmdas/postfix/pmdapostfix.pl
+++ b/src/pmdas/postfix/pmdapostfix.pl
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2012-2015 Red Hat.
+# Copyright (c) 2012-2015,2022 Red Hat.
# Copyright (c) 2009-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
#
# This program is free software; you can redistribute it and/or modify it
@@ -56,8 +56,6 @@ my @postfix_received_dom = (
1 => 'smtp',
);
-my $setup = defined($ENV{'PCP_PERL_PMNS'}) || defined($ENV{'PCP_PERL_DOMAIN'});
-
sub postfix_do_refresh
{
QUEUE:
@@ -212,7 +210,7 @@ $logstats{"received"}{1} = 0;
# Note:
# Environment variables.
-# $PMDA_POSTFIX_QSHAPE: alternative executable qshape scrpipt (for QA)
+# $PMDA_POSTFIX_QSHAPE: alternative executable qshape script (for QA)
# ... over-rides default and command line argument.
# ... over-rides default arguments -b 10 -t $refresh
# $PMDA_POSTFIX_REFRESH: alternative refresh rate (for QA)
@@ -228,7 +226,7 @@ if (defined($ENV{'PMDA_POSTFIX_QSHAPE'})) {
$qshape = $ENV{'PMDA_POSTFIX_QSHAPE'};
$qshape_args = '';
}
-if (!$setup) { $pmda->log("qshape cmd: $qshape $qshape_args <qname>"); }
+unless (pmda_install()) { $pmda->log("qshape cmd: $qshape $qshape_args <qname>"); }
if (defined($ENV{'PMDA_POSTFIX_REFRESH'})) { $refresh = $ENV{'PMDA_POSTFIX_REFRESH'}; }
@@ -238,12 +236,15 @@ foreach my $file ( @logfiles ) {
}
}
if (defined($ENV{'PMDA_POSTFIX_LOG'})) { $logfile = $ENV{'PMDA_POSTFIX_LOG'}; }
-unless(defined($logfile))
-{
- $pmda->log("Fatal: No Postfix log file found in: @logfiles");
- die 'No Postfix log file found';
+unless (pmda_install()) {
+ if (defined($logfile)) {
+ $pmda->log("logfile: $logfile");
+ } else {
+ $pmda->log("Warning: assuming logfile: $logfiles[0] as no Postfix log found yet from: @logfiles");
+ }
}
-if (!$setup) { $pmda->log("logfile: $logfile"); }
+# set a good default if none found, before continuing
+unless (defined($logfile)) { $logfile = $logfiles[0]; }
$pmda->add_indom($postfix_queues_indom, \@postfix_queues_dom, '', '');
$pmda->add_indom($postfix_sent_indom, \@postfix_sent_dom, '', '');

View File

@ -0,0 +1,44 @@
commit d874d2e486c8a64fa9945ed7aa0048cccbd46f77
Author: Nathan Scott <nathans@redhat.com>
Date: Wed May 4 17:11:19 2022 +1000
pmdaproc: fix cgroup cpu metrics refresh structures
Jan Kurik encountered this issue when running the regression
testsuite (especially qa/359) on non-x86_64 architectures.
Something must've changed in the toolchain recently on these
platforms since we've not seen this before, but this bug has
been in our code for some time. It works everywhere else by
good fortune, when there just happen to be NULLs after these
cgroups CPU parsing data structures.
Resolves Red Hat BZ #2081262.
diff --git a/src/pmdas/linux_proc/cgroups.c b/src/pmdas/linux_proc/cgroups.c
index 413a72343..26d59863a 100644
--- a/src/pmdas/linux_proc/cgroups.c
+++ b/src/pmdas/linux_proc/cgroups.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2019 Red Hat.
+ * Copyright (c) 2012-2019,2022 Red Hat.
* Copyright (c) 2010 Aconex. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify it
@@ -863,6 +863,7 @@ read_cpu_time(const char *file, cgroup_cputime_t *ccp)
{ "usage_usec", &cputime.usage },
{ "user_usec", &cputime.user },
{ "system_usec", &cputime.system },
+ { NULL, NULL }
};
char buffer[4096], name[64];
unsigned long long value;
@@ -903,6 +904,7 @@ read_cpu_stats(const char *file, cgroup_cpustat_t *ccp)
{ "nr_periods", &cpustat.nr_periods },
{ "nr_throttled", &cpustat.nr_throttled },
{ "throttled_time", &cpustat.throttled_time },
+ { NULL, NULL }
};
char buffer[4096], name[64];
unsigned long long value;

View File

@ -0,0 +1,74 @@
diff -Naurp pcp-5.3.7.orig/src/pcp/dstat/pcp-dstat.1 pcp-5.3.7/src/pcp/dstat/pcp-dstat.1
--- pcp-5.3.7.orig/src/pcp/dstat/pcp-dstat.1 2021-05-26 17:43:26.000000000 +1000
+++ pcp-5.3.7/src/pcp/dstat/pcp-dstat.1 2022-10-20 08:57:02.176922290 +1100
@@ -1,6 +1,6 @@
'\"macro stdmacro
.\"
-.\" Copyright (c) 2018-2020 Red Hat.
+.\" Copyright (c) 2018-2022 Red Hat.
.\"
.\" This program is free software; you can redistribute it and/or modify it
.\" under the terms of the GNU General Public License as published by the
@@ -34,6 +34,7 @@
[\f3\-\-integer\f1]
[\f3\-\-nocolor\f1]
[\f3\-\-noheaders\f1]
+[\f3\-\-nomissed\f1]
[\f3\-\-noupdate\f1]
[\f3\-\-list\f1]
[\f3\-\-pidfile\f1 \f2pid-file\f1]
@@ -404,6 +405,9 @@ disable colors
\fB\-\-noheaders\fR
disable repetitive headers
.TP
+\fB\-\-nomissed\fR
+disable missed ticks warnings for intermediate samples.
+.TP
\fB\-\-noupdate\fR
disable intermediate updates when \fIdelay\fR greater than 1.
.TP
diff -Naurp pcp-5.3.7.orig/src/pcp/dstat/pcp-dstat.py pcp-5.3.7/src/pcp/dstat/pcp-dstat.py
--- pcp-5.3.7.orig/src/pcp/dstat/pcp-dstat.py 2022-04-05 09:05:43.000000000 +1000
+++ pcp-5.3.7/src/pcp/dstat/pcp-dstat.py 2022-10-20 08:57:02.176922290 +1100
@@ -455,6 +455,7 @@ class DstatTool(object):
# Internal
self.missed = 0
+ self.nomissed = False # report missed ticks by default
self.runtime = -1
self.plugins = [] # list of requested plugin names
self.allplugins = [] # list of all known plugin names
@@ -783,7 +784,8 @@ class DstatTool(object):
opts.pmSetLongOption('color', 0, '', '', 'force colors')
opts.pmSetLongOption('nocolor', 0, '', '', 'disable colors')
opts.pmSetLongOption('noheaders', 0, '', '', 'disable repetitive headers')
- opts.pmSetLongOption('noupdate', 0, '', '', 'disable intermediate headers')
+ opts.pmSetLongOption('noupdate', 0, '', '', 'disable intermediate updates')
+ opts.pmSetLongOption('nomissed', 0, '', '', 'disable missed ticks warnings')
opts.pmSetLongOption('output', 1, 'o', 'file', 'write CSV output to file')
opts.pmSetLongOption('version', 0, 'V', '', '')
opts.pmSetLongOption('debug', 1, None, '', '')
@@ -920,6 +922,8 @@ class DstatTool(object):
self.header = False
elif opt in ['noupdate']:
self.update = False
+ elif opt in ['nomissed']:
+ self.nomissed = True
elif opt in ['o', 'output']:
self.output = arg
elif opt in ['pidfile']:
@@ -1773,12 +1777,12 @@ class DstatTool(object):
outputfile = open(self.output, omode)
outputfile.write(oline)
- if self.missed > 0:
+ if self.missed > 0 and self.nomissed is False:
line = 'missed ' + str(self.missed + 1) + ' ticks'
sys.stdout.write(' ' + THEME['error'] + line + THEME['input'])
if self.output and step == self.delay:
outputfile.write(',"' + line + '"')
- self.missed = 0
+ self.missed = 0
# Finish the line
if not op.update and self.novalues is False:
sys.stdout.write('\n')

View File

@ -0,0 +1,135 @@
commit 55e8c83ee5920ab30644f54f7a525255b1de4b84
Author: Nathan Scott <nathans@redhat.com>
Date: Mon Aug 29 14:25:03 2022 +1000
docs: describe working sudoers configuration with requiretty
When /etc/sudoers is configured with 'Defaults requiretty',
pmlogctl cannot invoke pmlogger_check in the normal fashion.
Symptoms of the problem are the following system log message:
pmlogctl[PID]: sudo: sorry, you must have a tty to run sudo
pmiectl and pmie_check are similarly affected. The simplest
solution is to add an additional configuration line excluding
these commands from requiring a tty; this is the approach now
documented.
Note these PCP commands are not interactive (require no tty)
and the unprivileged 'pcp' account uses nologin(8) as a shell
anyway, so requiretty offers no advantages here. Note also
there's debate about whether requiretty is a useful security
measure in general as it can be trivially bypassed; further
details: https://bugzilla.redhat.com/show_bug.cgi?id=1020147
Resolves Red Hat BZ #2093751
diff -Naurp pcp-5.3.7.orig/man/man1/pmie_check.1 pcp-5.3.7/man/man1/pmie_check.1
--- pcp-5.3.7.orig/man/man1/pmie_check.1 2021-11-04 08:26:15.000000000 +1100
+++ pcp-5.3.7/man/man1/pmie_check.1 2022-08-31 11:17:52.362276530 +1000
@@ -406,6 +406,42 @@ no
entries are needed as the timer mechanism provided by
.B systemd
is used instead.
+.PP
+The
+.BR pmiectl (1)
+utility may invoke
+.B pmie_check
+using the
+.BR sudo (1)
+command to run it under the $PCP_USER ``pcp'' account.
+If
+.B sudo
+is configured with the non-default
+.I requiretty
+option (see below),
+.B pmie_check
+may fail to run due to not having a tty configured.
+This issue can be resolved by adding a second line
+(expand $PCP_BINADM_DIR according to your platform)
+to the
+.I /etc/sudoers
+configuration file as follows:
+.P
+.ft CW
+.nf
+.in +0.5i
+Defaults requiretty
+Defaults!$PCP_BINADM_DIR/pmie_check !requiretty
+.in
+.fi
+.ft 1
+.P
+Note that the unprivileged PCP account under which these
+commands run uses
+.I /sbin/nologin
+as the shell, so the
+.I requiretty
+option is ineffective here and safe to disable in this way.
.SH FILES
.TP 5
.I $PCP_PMIECONTROL_PATH
diff -Naurp pcp-5.3.7.orig/man/man1/pmlogger_check.1 pcp-5.3.7/man/man1/pmlogger_check.1
--- pcp-5.3.7.orig/man/man1/pmlogger_check.1 2022-04-05 09:05:43.000000000 +1000
+++ pcp-5.3.7/man/man1/pmlogger_check.1 2022-08-31 11:20:52.470086724 +1000
@@ -830,6 +830,42 @@ no
entries are needed as the timer mechanism provided by
.B systemd
is used instead.
+.PP
+The
+.BR pmlogctl (1)
+utility may invoke
+.B pmlogger_check
+using the
+.BR sudo (1)
+command to run it under the $PCP_USER ``pcp'' account.
+If
+.B sudo
+is configured with the non-default
+.I requiretty
+option (see below),
+.B pmlogger_check
+may fail to run due to not having a tty configured.
+This issue can be resolved by adding a second line
+(expand $PCP_BINADM_DIR according to your platform)
+to the
+.I /etc/sudoers
+configuration file as follows:
+.P
+.ft CW
+.nf
+.in +0.5i
+Defaults requiretty
+Defaults!$PCP_BINADM_DIR/pmlogger_check !requiretty
+.in
+.fi
+.ft 1
+.P
+Note that the unprivileged PCP account under which these
+commands run uses
+.I /sbin/nologin
+as the shell, so the
+.I requiretty
+option is ineffective here and safe to disable in this way.
.SH FILES
.TP 5
.I $PCP_PMLOGGERCONTROL_PATH
@@ -926,7 +962,7 @@ instances for
.I hostname
have been launched in the interim.
Because the cron-driven PCP archive management scripts run under
-the uid of the user ``pcp'',
+the $PCP_USER account ``pcp'',
.BI $PCP_ARCHIVE_DIR/ hostname /SaveLogs
typically needs to be owned by the user ``pcp''.
.TP
@@ -994,6 +1030,7 @@ platforms.
.BR pmlogmv (1),
.BR pmlogrewrite (1),
.BR pmsocks (1),
+.BR sudo (1),
.BR systemd (1),
.BR xz (1)
and

View File

@ -0,0 +1,103 @@
From 73c024c64f7db68fdcd224c27c1711fa6dd1d254 Mon Sep 17 00:00:00 2001
From: Nathan Scott <nathans@redhat.com>
Date: Tue, 28 Jun 2022 10:06:06 +1000
Subject: [PATCH] pmlogger_farm: add default configuration file for farm
loggers
Provide a mechanism whereby the farm loggers can be configured.
There has been reluctance in the past to sharing configuration
of the local primary logger, so these are now done separately.
Makes sense to me as the primary pmlogger may need to use more
frequent sampling, may not want to allow remote pmlc, etc.
Resolves Red Hat BZ #2101574
---
src/pmlogger/GNUmakefile | 1 +
src/pmlogger/pmlogger.defaults | 2 ++
src/pmlogger/pmlogger_check.sh | 5 +++--
src/pmlogger/pmlogger_farm.defaults | 27 +++++++++++++++++++++++++++
4 files changed, 33 insertions(+), 2 deletions(-)
create mode 100644 src/pmlogger/pmlogger_farm.defaults
diff -Naurp pcp-5.3.7.orig/src/pmlogger/GNUmakefile pcp-5.3.7/src/pmlogger/GNUmakefile
--- pcp-5.3.7.orig/src/pmlogger/GNUmakefile 2022-02-02 11:53:05.000000000 +1100
+++ pcp-5.3.7/src/pmlogger/GNUmakefile 2022-08-31 11:23:08.758672970 +1000
@@ -45,6 +45,7 @@ install:: $(SUBDIRS)
install:: default
$(INSTALL) -m 775 -o $(PCP_USER) -g $(PCP_GROUP) -d $(PCP_VAR_DIR)/config/pmlogger
+ $(INSTALL) -m 644 pmlogger_farm.defaults $(PCP_SYSCONFIG_DIR)/pmlogger_farm
$(INSTALL) -m 644 pmlogger.defaults $(PCP_SYSCONFIG_DIR)/pmlogger
$(INSTALL) -m 755 -d $(PCP_SHARE_DIR)/zeroconf
$(INSTALL) -m 644 pmlogger.zeroconf $(PCP_SHARE_DIR)/zeroconf/pmlogger
diff -Naurp pcp-5.3.7.orig/src/pmlogger/pmlogger_check.sh pcp-5.3.7/src/pmlogger/pmlogger_check.sh
--- pcp-5.3.7.orig/src/pmlogger/pmlogger_check.sh 2022-04-05 09:05:43.000000000 +1000
+++ pcp-5.3.7/src/pmlogger/pmlogger_check.sh 2022-08-31 11:23:08.758672970 +1000
@@ -1,6 +1,6 @@
#! /bin/sh
#
-# Copyright (c) 2013-2016,2018,2020-2021 Red Hat.
+# Copyright (c) 2013-2016,2018,2020-2022 Red Hat.
# Copyright (c) 1995-2000,2003 Silicon Graphics, Inc. All Rights Reserved.
#
# This program is free software; you can redistribute it and/or modify it
@@ -24,6 +24,7 @@
PMLOGGER="$PCP_BINADM_DIR/pmlogger"
PMLOGCONF="$PCP_BINADM_DIR/pmlogconf"
PMLOGGERENVS="$PCP_SYSCONFIG_DIR/pmlogger"
+PMLOGGERFARMENVS="$PCP_SYSCONFIG_DIR/pmlogger_farm"
PMLOGGERZEROCONFENVS="$PCP_SHARE_DIR/zeroconf/pmlogger"
# error messages should go to stderr, not the GUI notifiers
@@ -972,8 +973,8 @@ END { print m }'`
continue
fi
else
+ envs=`grep -h ^PMLOGGER "$PMLOGGERFARMENVS" 2>/dev/null`
args="-h $host $args"
- envs=""
iam=""
fi
diff -Naurp pcp-5.3.7.orig/src/pmlogger/pmlogger.defaults pcp-5.3.7/src/pmlogger/pmlogger.defaults
--- pcp-5.3.7.orig/src/pmlogger/pmlogger.defaults 2022-02-03 16:11:40.000000000 +1100
+++ pcp-5.3.7/src/pmlogger/pmlogger.defaults 2022-08-31 11:23:08.758672970 +1000
@@ -1,5 +1,7 @@
# Environment variables for the primary pmlogger daemon. See also
# the pmlogger control file and pmlogconf(1) for additional details.
+# Also see separate pmlogger_farm configuration for the non-primary
+# logger configuration settings, separate to this file.
# Settings defined in this file will override any settings in the
# pmlogger zeroconf file (if present).
diff -Naurp pcp-5.3.7.orig/src/pmlogger/pmlogger_farm.defaults pcp-5.3.7/src/pmlogger/pmlogger_farm.defaults
--- pcp-5.3.7.orig/src/pmlogger/pmlogger_farm.defaults 1970-01-01 10:00:00.000000000 +1000
+++ pcp-5.3.7/src/pmlogger/pmlogger_farm.defaults 2022-08-31 11:23:08.758672970 +1000
@@ -0,0 +1,27 @@
+# Environment variables for the pmlogger farm daemons. See also
+# pmlogger control file(s) and pmlogconf(1) for additional details.
+# Also see separate pmlogger configuration for the primary logger
+# configuration settings, separate to this file.
+
+# Behaviour regarding listening on external-facing interfaces;
+# unset PMLOGGER_LOCAL to allow connections from remote hosts.
+# A value of 0 permits remote connections, 1 permits local only.
+# PMLOGGER_LOCAL=1
+
+# Max length to which the queue of pending connections may grow
+# A value of 5 is the default.
+# PMLOGGER_MAXPENDING=5
+
+# Default sampling interval pmlogger uses when no more specific
+# interval is requested. A value of 60 seconds is the default.
+# Both pmlogger command line (via control file) and also pmlogger
+# configuration file directives will override this value.
+# PMLOGGER_INTERVAL=60
+
+# The default behaviour, when pmlogger configuration comes from
+# pmlogconf(1), is to regenerate the configuration file and check for
+# changes whenever pmlogger is started from pmlogger_check(1).
+# If the PMDA configuration is stable, this is not necessary, and
+# setting PMLOGGER_CHECK_SKIP_LOGCONF to yes disables the regeneration
+# and checking.
+# PMLOGGER_CHECK_SKIP_LOGCONF=yes

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,534 @@
diff -Naurp pcp-5.3.7.orig/qa/1985 pcp-5.3.7/qa/1985
--- pcp-5.3.7.orig/qa/1985 1970-01-01 10:00:00.000000000 +1000
+++ pcp-5.3.7/qa/1985 2022-10-19 21:32:03.971832371 +1100
@@ -0,0 +1,38 @@
+#!/bin/sh
+# PCP QA Test No. 1985
+# Exercise a pmfind fix - valgrind-enabled variant.
+#
+# Copyright (c) 2022 Red Hat. All Rights Reserved.
+#
+
+seq=`basename $0`
+echo "QA output created by $seq"
+
+# get standard environment, filters and checks
+. ./common.product
+. ./common.filter
+. ./common.check
+
+_check_valgrind
+
+_cleanup()
+{
+ cd $here
+ $sudo rm -rf $tmp $tmp.*
+}
+
+status=0 # success is the default!
+$sudo rm -rf $tmp $tmp.* $seq.full
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# real QA test starts here
+export seq
+./1986 --valgrind \
+| $PCP_AWK_PROG '
+skip == 1 && $1 == "===" { skip = 0 }
+/^=== std err ===/ { skip = 1 }
+skip == 0 { print }
+skip == 1 { print >>"'$here/$seq.full'" }'
+
+# success, all done
+exit
diff -Naurp pcp-5.3.7.orig/qa/1985.out pcp-5.3.7/qa/1985.out
--- pcp-5.3.7.orig/qa/1985.out 1970-01-01 10:00:00.000000000 +1000
+++ pcp-5.3.7/qa/1985.out 2022-10-19 21:32:03.971832371 +1100
@@ -0,0 +1,11 @@
+QA output created by 1985
+QA output created by 1986 --valgrind
+=== std out ===
+SOURCE HOSTNAME
+=== filtered valgrind report ===
+Memcheck, a memory error detector
+Command: pmfind -S -m probe=127.0.0.1/32
+LEAK SUMMARY:
+definitely lost: 0 bytes in 0 blocks
+indirectly lost: 0 bytes in 0 blocks
+ERROR SUMMARY: 0 errors from 0 contexts ...
diff -Naurp pcp-5.3.7.orig/qa/1986 pcp-5.3.7/qa/1986
--- pcp-5.3.7.orig/qa/1986 1970-01-01 10:00:00.000000000 +1000
+++ pcp-5.3.7/qa/1986 2022-10-19 21:32:03.971832371 +1100
@@ -0,0 +1,62 @@
+#!/bin/sh
+# PCP QA Test No. 1986
+# Exercise libpcp_web timers pmfind regression fix.
+#
+# Copyright (c) 2022 Red Hat. All Rights Reserved.
+#
+
+if [ $# -eq 0 ]
+then
+ seq=`basename $0`
+ echo "QA output created by $seq"
+else
+ # use $seq from caller, unless not set
+ [ -n "$seq" ] || seq=`basename $0`
+ echo "QA output created by `basename $0` $*"
+fi
+
+# get standard environment, filters and checks
+. ./common.product
+. ./common.filter
+. ./common.check
+
+do_valgrind=false
+if [ "$1" = "--valgrind" ]
+then
+ _check_valgrind
+ do_valgrind=true
+fi
+
+test -x $PCP_BIN_DIR/pmfind || _notrun No support for pmfind
+
+_cleanup()
+{
+ cd $here
+ $sudo rm -rf $tmp $tmp.*
+}
+
+status=0 # success is the default!
+hostname=`hostname || echo localhost`
+$sudo rm -rf $tmp $tmp.* $seq.full
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+_filter()
+{
+ sed \
+ -e "s@$tmp@TMP@g" \
+ -e "s/ $hostname/ HOSTNAME/" \
+ -e 's/^[a-f0-9][a-f0-9]* /SOURCE /' \
+ # end
+}
+
+# real QA test starts here
+if $do_valgrind
+then
+ _run_valgrind pmfind -S -m probe=127.0.0.1/32
+else
+ pmfind -S -m probe=127.0.0.1/32
+fi \
+| _filter
+
+# success, all done
+exit
diff -Naurp pcp-5.3.7.orig/qa/1986.out pcp-5.3.7/qa/1986.out
--- pcp-5.3.7.orig/qa/1986.out 1970-01-01 10:00:00.000000000 +1000
+++ pcp-5.3.7/qa/1986.out 2022-10-19 21:32:03.971832371 +1100
@@ -0,0 +1,2 @@
+QA output created by 1986
+SOURCE HOSTNAME
diff -Naurp pcp-5.3.7.orig/qa/group pcp-5.3.7/qa/group
--- pcp-5.3.7.orig/qa/group 2022-10-19 20:49:42.638708707 +1100
+++ pcp-5.3.7/qa/group 2022-10-19 21:32:03.972832359 +1100
@@ -1974,4 +1974,6 @@ x11
1957 libpcp local valgrind
1978 atop local
1984 pmlogconf pmda.redis local
+1985 pmfind local valgrind
+1986 pmfind local
4751 libpcp threads valgrind local pcp helgrind
diff -Naurp pcp-5.3.7.orig/src/libpcp_web/src/webgroup.c pcp-5.3.7/src/libpcp_web/src/webgroup.c
--- pcp-5.3.7.orig/src/libpcp_web/src/webgroup.c 2021-11-01 13:02:26.000000000 +1100
+++ pcp-5.3.7/src/libpcp_web/src/webgroup.c 2022-10-19 21:32:03.973832346 +1100
@@ -287,11 +287,24 @@ webgroup_new_context(pmWebGroupSettings
}
static void
+webgroup_timers_stop(struct webgroups *groups)
+{
+ if (groups->active) {
+ uv_timer_stop(&groups->timer);
+ uv_close((uv_handle_t *)&groups->timer, NULL);
+ pmWebTimerRelease(groups->timerid);
+ groups->timerid = -1;
+ groups->active = 0;
+ }
+}
+
+static void
webgroup_garbage_collect(struct webgroups *groups)
{
dictIterator *iterator;
dictEntry *entry;
context_t *cp;
+ unsigned int count = 0, drops = 0;
if (pmDebugOptions.http || pmDebugOptions.libweb)
fprintf(stderr, "%s: started\n", "webgroup_garbage_collect");
@@ -308,33 +321,40 @@ webgroup_garbage_collect(struct webgroup
uv_mutex_unlock(&groups->mutex);
webgroup_drop_context(cp, groups);
uv_mutex_lock(&groups->mutex);
+ drops++;
}
+ count++;
}
dictReleaseIterator(iterator);
+
+ /* if dropping the last remaining context, do cleanup */
+ if (groups->active && drops == count) {
+ if (pmDebugOptions.http || pmDebugOptions.libweb)
+ fprintf(stderr, "%s: freezing\n", "webgroup_garbage_collect");
+ webgroup_timers_stop(groups);
+ }
uv_mutex_unlock(&groups->mutex);
}
if (pmDebugOptions.http || pmDebugOptions.libweb)
- fprintf(stderr, "%s: finished\n", "webgroup_garbage_collect");
+ fprintf(stderr, "%s: finished [%u drops from %u entries]\n",
+ "webgroup_garbage_collect", drops, count);
}
static void
refresh_maps_metrics(void *data)
{
struct webgroups *groups = (struct webgroups *)data;
+ unsigned int value;
- if (groups->metrics) {
- unsigned int value;
-
- value = dictSize(contextmap);
- mmv_set(groups->map, groups->metrics[CONTEXT_MAP_SIZE], &value);
- value = dictSize(namesmap);
- mmv_set(groups->map, groups->metrics[NAMES_MAP_SIZE], &value);
- value = dictSize(labelsmap);
- mmv_set(groups->map, groups->metrics[LABELS_MAP_SIZE], &value);
- value = dictSize(instmap);
- mmv_set(groups->map, groups->metrics[INST_MAP_SIZE], &value);
- }
+ value = contextmap? dictSize(contextmap) : 0;
+ mmv_set(groups->map, groups->metrics[CONTEXT_MAP_SIZE], &value);
+ value = namesmap? dictSize(namesmap) : 0;
+ mmv_set(groups->map, groups->metrics[NAMES_MAP_SIZE], &value);
+ value = labelsmap? dictSize(labelsmap) : 0;
+ mmv_set(groups->map, groups->metrics[LABELS_MAP_SIZE], &value);
+ value = instmap? dictSize(instmap) : 0;
+ mmv_set(groups->map, groups->metrics[INST_MAP_SIZE], &value);
}
static void
@@ -487,6 +507,7 @@ pmWebGroupDestroy(pmWebGroupSettings *se
if (pmDebugOptions.libweb)
fprintf(stderr, "%s: destroy context %p gp=%p\n", "pmWebGroupDestroy", cp, gp);
+ webgroup_deref_context(cp);
webgroup_drop_context(cp, gp);
}
sdsfree(msg);
@@ -2394,17 +2415,12 @@ pmWebGroupClose(pmWebGroupModule *module
if (groups) {
/* walk the contexts, stop timers and free resources */
- if (groups->active) {
- groups->active = 0;
- uv_timer_stop(&groups->timer);
- pmWebTimerRelease(groups->timerid);
- groups->timerid = -1;
- }
iterator = dictGetIterator(groups->contexts);
while ((entry = dictNext(iterator)) != NULL)
webgroup_drop_context((context_t *)dictGetVal(entry), NULL);
dictReleaseIterator(iterator);
dictRelease(groups->contexts);
+ webgroup_timers_stop(groups);
memset(groups, 0, sizeof(struct webgroups));
free(groups);
}
diff -Naurp pcp-5.3.7.orig/src/pmfind/source.c pcp-5.3.7/src/pmfind/source.c
--- pcp-5.3.7.orig/src/pmfind/source.c 2021-02-17 15:27:41.000000000 +1100
+++ pcp-5.3.7/src/pmfind/source.c 2022-10-19 21:32:03.973832346 +1100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 Red Hat.
+ * Copyright (c) 2020,2022 Red Hat.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -25,6 +25,7 @@ static pmWebGroupSettings settings;
typedef struct {
sds source;
sds hostspec;
+ unsigned int refcount;
} context_t;
typedef struct {
@@ -38,22 +39,34 @@ typedef struct {
} sources_t;
static void
+source_release(sources_t *sp, context_t *cp, sds ctx)
+{
+ pmWebGroupDestroy(&settings, ctx, sp);
+ sdsfree(cp->hostspec);
+ sdsfree(cp->source);
+ free(cp);
+}
+
+static void
sources_release(void *arg, const struct dictEntry *entry)
{
sources_t *sp = (sources_t *)arg;
context_t *cp = (context_t *)dictGetVal(entry);
sds ctx = (sds)entry->key;
- pmWebGroupDestroy(&settings, ctx, sp);
- sdsfree(cp->hostspec);
- sdsfree(cp->source);
+ if (pmDebugOptions.discovery)
+ fprintf(stderr, "releasing context %s\n", ctx);
+
+ source_release(sp, cp, ctx);
}
static void
-sources_containers(sources_t *sp, sds id, dictEntry *uniq)
+sources_containers(sources_t *sp, context_t *cp, sds id, dictEntry *uniq)
{
uv_mutex_lock(&sp->mutex);
- sp->count++; /* issuing another PMWEBAPI request */
+ /* issuing another PMWEBAPI request */
+ sp->count++;
+ cp->refcount++;
uv_mutex_unlock(&sp->mutex);
pmWebGroupScrape(&settings, id, sp->params, sp);
@@ -75,6 +88,7 @@ on_source_context(sds id, pmWebSource *s
cp->source = sdsdup(src->source);
cp->hostspec = sdsdup(src->hostspec);
+ cp->refcount = 1;
uv_mutex_lock(&sp->mutex);
dictAdd(sp->contexts, id, cp);
@@ -84,7 +98,7 @@ on_source_context(sds id, pmWebSource *s
if (entry) { /* source just discovered */
printf("%s %s\n", src->source, src->hostspec);
if (containers)
- sources_containers(sp, id, entry);
+ sources_containers(sp, cp, id, entry);
}
}
@@ -116,7 +130,9 @@ static void
on_source_done(sds context, int status, sds message, void *arg)
{
sources_t *sp = (sources_t *)arg;
- int count = 0, release = 0;
+ context_t *cp;
+ dictEntry *he;
+ int remove = 0, count = 0, release = 0;
if (pmDebugOptions.discovery)
fprintf(stderr, "done on context %s (sts=%d)\n", context, status);
@@ -127,19 +143,26 @@ on_source_done(sds context, int status,
uv_mutex_lock(&sp->mutex);
if ((count = --sp->count) <= 0)
release = 1;
+ if ((he = dictFind(sp->contexts, context)) != NULL &&
+ (cp = (context_t *)dictGetVal(he)) != NULL &&
+ (--cp->refcount <= 0))
+ remove = 1;
uv_mutex_unlock(&sp->mutex);
+ if (remove) {
+ if (pmDebugOptions.discovery)
+ fprintf(stderr, "remove context %s\n", context);
+ source_release(sp, cp, context);
+ dictDelete(sp->contexts, context);
+ }
+
if (release) {
unsigned long cursor = 0;
-
- if (pmDebugOptions.discovery)
- fprintf(stderr, "release context %s (sts=%d)\n", context, status);
do {
cursor = dictScan(sp->contexts, cursor, sources_release, NULL, sp);
} while (cursor);
- } else {
- if (pmDebugOptions.discovery)
- fprintf(stderr, "not yet releasing (count=%d)\n", count);
+ } else if (pmDebugOptions.discovery) {
+ fprintf(stderr, "not yet releasing (count=%d)\n", count);
}
}
@@ -190,6 +213,7 @@ sources_discovery_start(uv_timer_t *arg)
}
dictRelease(dp);
+ pmWebTimerClose();
}
/*
@@ -214,8 +238,8 @@ source_discovery(int count, char **urls)
uv_mutex_init(&find.mutex);
find.urls = urls;
find.count = count; /* at least one PMWEBAPI request for each url */
- find.uniq = dictCreate(&sdsDictCallBacks, NULL);
- find.params = dictCreate(&sdsDictCallBacks, NULL);
+ find.uniq = dictCreate(&sdsKeyDictCallBacks, NULL);
+ find.params = dictCreate(&sdsOwnDictCallBacks, NULL);
dictAdd(find.params, sdsnew("name"), sdsnew("containers.state.running"));
find.contexts = dictCreate(&sdsKeyDictCallBacks, NULL);
@@ -230,6 +254,7 @@ source_discovery(int count, char **urls)
pmWebGroupSetup(&settings.module);
pmWebGroupSetEventLoop(&settings.module, loop);
+ pmWebTimerSetEventLoop(loop);
/*
* Start a one-shot timer to add a start function into the loop
@@ -244,7 +269,9 @@ source_discovery(int count, char **urls)
/*
* Finished, release all resources acquired so far
*/
+ pmWebGroupClose(&settings.module);
uv_mutex_destroy(&find.mutex);
+ dictRelease(find.uniq);
dictRelease(find.params);
dictRelease(find.contexts);
return find.status;
diff -Naurp pcp-5.3.7.orig/src/pmproxy/src/server.c pcp-5.3.7/src/pmproxy/src/server.c
--- pcp-5.3.7.orig/src/pmproxy/src/server.c 2022-04-05 09:05:43.000000000 +1000
+++ pcp-5.3.7/src/pmproxy/src/server.c 2022-10-19 21:31:43.831093354 +1100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018-2019,2021 Red Hat.
+ * Copyright (c) 2018-2019,2021-2022 Red Hat.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
@@ -310,17 +310,21 @@ on_write_callback(uv_callback_t *handle,
struct client *client = (struct client *)request->writer.data;
int sts;
+ (void)handle;
if (pmDebugOptions.af)
fprintf(stderr, "%s: client=%p\n", "on_write_callback", client);
if (client->stream.secure == 0) {
sts = uv_write(&request->writer, (uv_stream_t *)&client->stream,
&request->buffer[0], request->nbuffers, request->callback);
- if (sts != 0)
- fprintf(stderr, "%s: ERROR uv_write failed\n", "on_write_callback");
+ if (sts != 0) {
+ pmNotifyErr(LOG_ERR, "%s: %s - uv_write failed [%s]: %s\n",
+ pmGetProgname(), "on_write_callback",
+ uv_err_name(sts), uv_strerror(sts));
+ client_close(client);
+ }
} else
secure_client_write(client, request);
- (void)handle;
return 0;
}
@@ -455,14 +459,16 @@ on_client_connection(uv_stream_t *stream
uv_handle_t *handle;
if (status != 0) {
- fprintf(stderr, "%s: client connection failed: %s\n",
- pmGetProgname(), uv_strerror(status));
+ pmNotifyErr(LOG_ERR, "%s: %s - %s failed [%s]: %s\n",
+ pmGetProgname(), "on_client_connection", "connection",
+ uv_err_name(status), uv_strerror(status));
return;
}
if ((client = calloc(1, sizeof(*client))) == NULL) {
- fprintf(stderr, "%s: out-of-memory for new client\n",
- pmGetProgname());
+ pmNotifyErr(LOG_ERR, "%s: %s - %s failed [%s]: %s\n",
+ pmGetProgname(), "on_client_connection", "calloc",
+ "ENOMEM", strerror(ENOMEM));
return;
}
if (pmDebugOptions.context | pmDebugOptions.af)
@@ -476,16 +482,18 @@ on_client_connection(uv_stream_t *stream
status = uv_tcp_init(proxy->events, &client->stream.u.tcp);
if (status != 0) {
- fprintf(stderr, "%s: client tcp init failed: %s\n",
- pmGetProgname(), uv_strerror(status));
+ pmNotifyErr(LOG_ERR, "%s: %s - %s failed [%s]: %s\n",
+ pmGetProgname(), "on_client_connection", "uv_tcp_init",
+ uv_err_name(status), uv_strerror(status));
client_put(client);
return;
}
status = uv_accept(stream, (uv_stream_t *)&client->stream.u.tcp);
if (status != 0) {
- fprintf(stderr, "%s: client tcp init failed: %s\n",
- pmGetProgname(), uv_strerror(status));
+ pmNotifyErr(LOG_ERR, "%s: %s - %s failed [%s]: %s\n",
+ pmGetProgname(), "on_client_connection", "uv_accept",
+ uv_err_name(status), uv_strerror(status));
client_put(client);
return;
}
@@ -496,8 +504,9 @@ on_client_connection(uv_stream_t *stream
status = uv_read_start((uv_stream_t *)&client->stream.u.tcp,
on_buffer_alloc, on_client_read);
if (status != 0) {
- fprintf(stderr, "%s: client read start failed: %s\n",
- pmGetProgname(), uv_strerror(status));
+ pmNotifyErr(LOG_ERR, "%s: %s - %s failed [%s]: %s\n",
+ pmGetProgname(), "on_client_connection", "uv_read_start",
+ uv_err_name(status), uv_strerror(status));
client_close(client);
}
}
@@ -530,8 +539,9 @@ open_request_port(struct proxy *proxy, s
sts = uv_listen((uv_stream_t *)&stream->u.tcp, maxpending, on_client_connection);
if (sts != 0) {
- fprintf(stderr, "%s: socket listen error %s\n",
- pmGetProgname(), uv_strerror(sts));
+ pmNotifyErr(LOG_ERR, "%s: %s - uv_listen failed [%s]: %s\n",
+ pmGetProgname(), "open_request_port",
+ uv_err_name(sts), uv_strerror(sts));
uv_close(handle, NULL);
return -ENOTCONN;
}
@@ -554,15 +564,23 @@ open_request_local(struct proxy *proxy,
uv_pipe_init(proxy->events, &stream->u.local, 0);
handle = (uv_handle_t *)&stream->u.local;
handle->data = (void *)proxy;
- uv_pipe_bind(&stream->u.local, name);
+ sts = uv_pipe_bind(&stream->u.local, name);
+ if (sts != 0) {
+ pmNotifyErr(LOG_ERR, "%s: %s - uv_pipe_bind %s failed [%s]: %s\n",
+ pmGetProgname(), "open_request_local", name,
+ uv_err_name(sts), uv_strerror(sts));
+ uv_close(handle, NULL);
+ return -ENOTCONN;
+ }
#ifdef HAVE_UV_PIPE_CHMOD
uv_pipe_chmod(&stream->u.local, UV_READABLE | UV_WRITABLE);
#endif
sts = uv_listen((uv_stream_t *)&stream->u.local, maxpending, on_client_connection);
if (sts != 0) {
- fprintf(stderr, "%s: local listen error %s\n",
- pmGetProgname(), uv_strerror(sts));
+ pmNotifyErr(LOG_ERR, "%s: %s - %s failed [%s]: %s\n",
+ pmGetProgname(), "open_request_local", "uv_listen",
+ uv_err_name(sts), uv_strerror(sts));
uv_close(handle, NULL);
return -ENOTCONN;
}

View File

@ -0,0 +1,32 @@
commit 4014e295f7b5f541439774bd3c88924d3c061325
Author: Masatake YAMATO <yamato@redhat.com>
Date: Thu Oct 20 13:55:43 2022 +0900
pmdas/snmp: install the agent specific configuration file to PMDATMPDIR
When running ./Install of the agent, the following line is printed in
/var/log/pcp/pmcd/snmp.log.
Log for pmdasnmp on pcp-netsnmp started Tue Oct 18 22:45:23 2022
opening /var/lib/pcp/pmdas/snmp/snmp.conf No such file or directory at /var/lib/pcp/pmdas/snmp/pmdasnmp.pl line 90.
As a result, pmdasnmp.pl cannot read its configuration file though it
is "./Install"ed.
Signed-off-by: Masatake YAMATO <yamato@redhat.com>
diff --git a/src/pmdas/snmp/GNUmakefile b/src/pmdas/snmp/GNUmakefile
index ce0e3e8036..7bf5471a76 100644
--- a/src/pmdas/snmp/GNUmakefile
+++ b/src/pmdas/snmp/GNUmakefile
@@ -44,7 +44,7 @@ install_pcp install: default
$(INSTALL) -m 755 -t $(PMDATMPDIR) Install Remove $(PMDAADMDIR)
$(INSTALL) -m 644 -t $(PMDATMPDIR)/pmda$(IAM).pl pmda$(IAM).pl $(PMDAADMDIR)/pmda$(IAM).pl
$(INSTALL) -m 755 -d $(PMDACONFIG)
- $(INSTALL) -m 644 snmp.conf $(PMDACONFIG)/snmp.conf
+ $(INSTALL) -m 644 -t $(PMDATMPDIR)/$(IAM).conf $(IAM).conf $(PMDACONFIG)/$(IAM).conf
@$(INSTALL_MAN)
else
build-me:

View File

@ -0,0 +1,50 @@
diff --git a/src/pmdas/podman/.gitignore b/src/pmdas/podman/.gitignore
index a4f35e0f43..aea2c4052e 100644
--- a/src/pmdas/podman/.gitignore
+++ b/src/pmdas/podman/.gitignore
@@ -2,8 +2,6 @@ deps/
domain.h
pmdapodman
pmda_podman.so
-jsonsl.c
-jsonsl.h
help.dir
help.pag
exports
diff --git a/src/pmdas/podman/GNUmakefile b/src/pmdas/podman/GNUmakefile
index d6e58cfca5..1117a7a4e4 100644
--- a/src/pmdas/podman/GNUmakefile
+++ b/src/pmdas/podman/GNUmakefile
@@ -83,6 +83,7 @@ domain.h: ../../pmns/stdpmid
$(OBJECTS): domain.h
pmda.o: $(VERSION_SCRIPT)
pmda.o: $(TOPDIR)/src/include/pcp/libpcp.h
+podman.o: $(JSONSL_HFILES)
check:: $(CFILES) $(HFILES)
$(CLINT) $^
diff --git a/src/pmdas/root/.gitignore b/src/pmdas/root/.gitignore
index 21f507f0dd..b78b1fd28a 100644
--- a/src/pmdas/root/.gitignore
+++ b/src/pmdas/root/.gitignore
@@ -1,8 +1,6 @@
deps/
domain.h
pmdaroot
-jsonsl.c
-jsonsl.h
help.dir
help.pag
pmns
diff --git a/src/pmdas/root/GNUmakefile b/src/pmdas/root/GNUmakefile
index ed01a18fb8..b02d4ea834 100644
--- a/src/pmdas/root/GNUmakefile
+++ b/src/pmdas/root/GNUmakefile
@@ -83,6 +83,7 @@ pmns :
$(LN_S) -f root_root pmns
lxc.o root.o: $(TOPDIR)/src/include/pcp/libpcp.h
+podman.o: $(JSONSL_HFILES)
check:: $(CFILES) $(HFILES)
$(CLINT) $^

View File

@ -1,17 +1,28 @@
Name: pcp
Version: 5.3.1
Release: 3%{?dist}
Version: 5.3.7
Release: 16%{?dist}
Summary: System-level performance monitoring and performance management
License: GPLv2+ and LGPLv2+ and CC-BY
URL: https://pcp.io
%global artifactory https://performancecopilot.jfrog.io/artifactory
Source0: %{artifactory}/pcp-source-release/pcp-%{version}.src.tar.gz
Patch0: redhat-bugzilla-2003956-pmdabcc-update-kernel-version-check-due-to-backporting.patch
Patch1: redhat-bugzilla-1981886-pmdasockets-backporting.patch
Patch2: redhat-bugzilla-2059461-pmie-systemd-fixup.patch
Patch3: redhat-bugzilla-2081262-pmdaproc-cgroups-fix.patch
Patch4: redhat-bugzilla-2059463-pmdapostfix-harden.patch
Patch5: redhat-bugzilla-2083897-dstat-missed-ticks.patch
Patch6: redhat-bugzilla-2111742-selinux-policy.patch
Patch7: redhat-bugzilla-2093751-sudoers-docs.patch
Patch8: redhat-bugzilla-2101574-farm-config.patch
Patch9: redhat-bugzilla-2135314-pmfind-fix.patch
Patch10: redhat-bugzilla-2139012-pmdasnmp-config.patch
Patch11: redhat-build-jsonsl.patch
Patch000: redhat-bugzilla-1947989.patch
Patch001: redhat-bugzilla-1974266.patch
Patch002: redhat-bugzilla-1975069.patch
Patch003: redhat-bugzilla-1879350.patch
# The additional linker flags break out-of-tree PMDAs.
# https://bugzilla.redhat.com/show_bug.cgi?id=2043092
%undefine _package_note_flags
%if 0%{?fedora} >= 26 || 0%{?rhel} > 7
%global __python2 python2
@ -95,6 +106,17 @@ Patch003: redhat-bugzilla-1879350.patch
%global disable_bcc 1
%endif
# support for pmdabpf, check bpf.spec for supported architectures of bpf
%if 0%{?fedora} >= 33 || 0%{?rhel} > 8
%ifarch x86_64 %{power64} aarch64 s390x
%global disable_bpf 0
%else
%global disable_bpf 1
%endif
%else
%global disable_bpf 1
%endif
# support for pmdabpftrace, check bpftrace.spec for supported architectures of bpftrace
%if 0%{?fedora} >= 30 || 0%{?rhel} > 7
%ifarch x86_64 %{power64} aarch64 s390x
@ -279,27 +301,27 @@ BuildRequires: qt5-qtsvg-devel
Requires: bash xz gawk sed grep findutils which %{_hostname_executable}
Requires: pcp-libs = %{version}-%{release}
%if !%{disable_selinux}
# rpm boolean dependencies are supported since RHEL 8
%if 0%{?fedora} >= 35 || 0%{?rhel} >= 8
# This ensures that the pcp-selinux package and all its dependencies are
# not pulled into containers and other systems that do not use SELinux
Requires: (pcp-selinux = %{version}-%{release} if selinux-policy-targeted)
%else
Requires: pcp-selinux = %{version}-%{release}
%endif
%endif
%global _confdir %{_sysconfdir}/pcp
%global _logsdir %{_localstatedir}/log/pcp
%global _pmnsdir %{_localstatedir}/lib/pcp/pmns
%global _pmnsexecdir %{_libexecdir}/pcp/pmns
%global _tempsdir %{_localstatedir}/lib/pcp/tmp
%global _pmdasdir %{_localstatedir}/lib/pcp/pmdas
%global _pmdasexecdir %{_libexecdir}/pcp/pmdas
%global _testsdir %{_localstatedir}/lib/pcp/testsuite
%global _selinuxdir %{_localstatedir}/lib/pcp/selinux
%global _selinuxexecdir %{_libexecdir}/pcp/selinux
%global _logconfdir %{_localstatedir}/lib/pcp/config/pmlogconf
%global _ieconfigdir %{_localstatedir}/lib/pcp/config/pmie
%global _ieconfdir %{_localstatedir}/lib/pcp/config/pmieconf
%global _tapsetdir %{_datadir}/systemtap/tapset
%global _bashcompdir %{_datadir}/bash-completion/completions
%global _pixmapdir %{_datadir}/pcp-gui/pixmaps
%global _hicolordir %{_datadir}/icons/hicolor
%global _booksdir %{_datadir}/doc/pcp-doc
%global _selinuxdir %{_datadir}/selinux/packages/targeted
%if 0%{?fedora} >= 20 || 0%{?rhel} >= 8
%global _with_doc --with-docdir=%{_docdir}/%{name}
@ -360,6 +382,12 @@ Requires: pcp-selinux = %{version}-%{release}
%global _with_bcc --with-pmdabcc=yes
%endif
%if %{disable_bpf}
%global _with_bpf --with-pmdabpf=no
%else
%global _with_bpf --with-pmdabpf=yes
%endif
%if %{disable_bpftrace}
%global _with_bpftrace --with-pmdabpftrace=no
%else
@ -414,14 +442,13 @@ else
fi
}
%global selinux_handle_policy() %{expand:
if [ %1 -ge 1 ]
%global run_pmieconf() %{expand:
if [ -w "%1" ]
then
%{_libexecdir}/pcp/bin/selinux-setup %{_selinuxdir} install %2
elif [ %1 -eq 0 ]
then
%{_libexecdir}/pcp/bin/selinux-setup %{_selinuxdir} remove %2
fi
pmieconf -c enable "%2"
else
echo "WARNING: Cannot write to %1, skipping pmieconf enable of %2." >&2
fi
}
%description
@ -502,11 +529,11 @@ Requires: pcp-pmda-activemq pcp-pmda-bonding pcp-pmda-dbping pcp-pmda-ds389 pcp-
Requires: pcp-pmda-elasticsearch pcp-pmda-gpfs pcp-pmda-gpsd pcp-pmda-lustre
Requires: pcp-pmda-memcache pcp-pmda-mysql pcp-pmda-named pcp-pmda-netfilter pcp-pmda-news
Requires: pcp-pmda-nginx pcp-pmda-nfsclient pcp-pmda-pdns pcp-pmda-postfix pcp-pmda-postgresql pcp-pmda-oracle
Requires: pcp-pmda-samba pcp-pmda-slurm pcp-pmda-vmware pcp-pmda-zimbra
Requires: pcp-pmda-samba pcp-pmda-slurm pcp-pmda-zimbra
Requires: pcp-pmda-dm pcp-pmda-apache
Requires: pcp-pmda-bash pcp-pmda-cisco pcp-pmda-gfs2 pcp-pmda-mailq pcp-pmda-mounts
Requires: pcp-pmda-nvidia-gpu pcp-pmda-roomtemp pcp-pmda-sendmail pcp-pmda-shping pcp-pmda-smart
Requires: pcp-pmda-hacluster pcp-pmda-lustrecomm pcp-pmda-logger pcp-pmda-docker pcp-pmda-bind2
Requires: pcp-pmda-hacluster pcp-pmda-lustrecomm pcp-pmda-logger pcp-pmda-denki pcp-pmda-docker pcp-pmda-bind2
Requires: pcp-pmda-sockets
%if !%{disable_podman}
Requires: pcp-pmda-podman
@ -520,6 +547,9 @@ Requires: pcp-pmda-nutcracker
%if !%{disable_bcc}
Requires: pcp-pmda-bcc
%endif
%if !%{disable_bpf}
Requires: pcp-pmda-bpf
%endif
%if !%{disable_bpftrace}
Requires: pcp-pmda-bpftrace
%endif
@ -527,7 +557,7 @@ Requires: pcp-pmda-bpftrace
Requires: pcp-pmda-gluster pcp-pmda-zswap pcp-pmda-unbound pcp-pmda-mic
Requires: pcp-pmda-libvirt pcp-pmda-lio pcp-pmda-openmetrics pcp-pmda-haproxy
Requires: pcp-pmda-lmsensors pcp-pmda-netcheck pcp-pmda-rabbitmq
Requires: pcp-pmda-openvswitch
Requires: pcp-pmda-openvswitch pcp-pmda-mongodb
%endif
%if !%{disable_mssql}
Requires: pcp-pmda-mssql
@ -539,9 +569,7 @@ Requires: pcp-pmda-snmp
Requires: pcp-pmda-json
%endif
Requires: pcp-pmda-summary pcp-pmda-trace pcp-pmda-weblog
%if !%{disable_python2} || !%{disable_python3}
Requires: pcp-system-tools
%endif
%if !%{disable_qt}
Requires: pcp-gui
%endif
@ -1109,6 +1137,20 @@ This package contains the PCP Performance Metrics Domain Agent (PMDA) for
collecting metrics about a GPS Daemon.
#end pcp-pmda-gpsd
#
# pcp-pmda-denki
#
%package pmda-denki
License: GPLv2+
Summary: Performance Co-Pilot (PCP) metrics dealing with electrical power
URL: https://pcp.io
Requires: pcp = %{version}-%{release} pcp-libs = %{version}-%{release}
%description pmda-denki
This package contains the PCP Performance Metrics Domain Agent (PMDA) for
collecting metrics related to the electrical power consumed by and inside
the system.
# end pcp-pmda-denki
#
# pcp-pmda-docker
#
@ -1372,21 +1414,6 @@ collecting metrics about SNMP.
#end pcp-pmda-snmp
%endif
#
# pcp-pmda-vmware
#
%package pmda-vmware
License: GPLv2+
Summary: Performance Co-Pilot (PCP) metrics for VMware
URL: https://pcp.io
Requires: pcp = %{version}-%{release} pcp-libs = %{version}-%{release}
Requires: perl-PCP-PMDA = %{version}-%{release}
%description pmda-vmware
This package contains the PCP Performance Metrics Domain Agent (PMDA) for
collecting metrics for VMware.
#end pcp-pmda-vmware
#
# pcp-pmda-zimbra
#
@ -1434,6 +1461,23 @@ extracting performance metrics from eBPF/BCC Python modules.
# end pcp-pmda-bcc
%endif
%if !%{disable_bpf}
#
# pcp-pmda-bpf
#
%package pmda-bpf
License: ASL 2.0 and GPLv2+
Summary: Performance Co-Pilot (PCP) metrics from eBPF ELF modules
URL: https://pcp.io
Requires: pcp = %{version}-%{release} pcp-libs = %{version}-%{release}
Requires: libbpf
BuildRequires: libbpf-devel clang llvm bpftool
%description pmda-bpf
This package contains the PCP Performance Metrics Domain Agent (PMDA) for
extracting performance metrics from eBPF ELF modules.
# end pcp-pmda-bpf
%endif
%if !%{disable_bpftrace}
#
# pcp-pmda-bpftrace
@ -1711,6 +1755,7 @@ BuildRequires: %{__python2}-requests
%endif
Obsoletes: pcp-pmda-prometheus < 5.0.0
Provides: pcp-pmda-prometheus < 5.0.0
Obsoletes: pcp-pmda-vmware < 5.3.5
%description pmda-openmetrics
This package contains the PCP Performance Metrics Domain Agent (PMDA) for
@ -1756,6 +1801,29 @@ This package contains the PCP Performance Metrics Domain Agent (PMDA) for
collecting metrics from simple network checks.
# end pcp-pmda-netcheck
#
# pcp-pmda-mongodb
#
%package pmda-mongodb
License: GPLv2+
Summary: Performance Co-Pilot (PCP) metrics for MongoDB
URL: https://pcp.io
Requires: pcp = %{version}-%{release} pcp-libs = %{version}-%{release}
%if !%{disable_python3}
Requires: python3-pcp
%if 0%{?rhel} == 0
Requires: python3-pymongo
%endif
%else
Requires: %{__python2}-pcp
%if 0%{?rhel} == 0
Requires: %{__python2}-pymongo
%endif
%endif
%description pmda-mongodb
This package contains the PCP Performance Metrics Domain Agent (PMDA) for
collecting metrics from MongoDB.
# end pcp-pmda-mongodb
%endif
%if !%{disable_mssql}
@ -2123,7 +2191,6 @@ Performance Metric API (PMAPI) monitor tools and Performance
Metric Domain Agent (PMDA) collector tools written in Python3.
%endif
%if !%{disable_python2} || !%{disable_python3}
#
# pcp-system-tools
#
@ -2131,23 +2198,24 @@ Metric Domain Agent (PMDA) collector tools written in Python3.
License: GPLv2+
Summary: Performance Co-Pilot (PCP) System and Monitoring Tools
URL: https://pcp.io
Requires: pcp = %{version}-%{release} pcp-libs = %{version}-%{release}
%if !%{disable_python2} || !%{disable_python3}
%if !%{disable_python3}
Requires: python3-pcp = %{version}-%{release}
%else
Requires: %{__python2}-pcp = %{version}-%{release}
%endif
Requires: pcp = %{version}-%{release} pcp-libs = %{version}-%{release}
%if !%{disable_dstat}
# https://fedoraproject.org/wiki/Packaging:Guidelines "Renaming/Replacing Existing Packages"
Provides: dstat = %{version}-%{release}
Provides: /usr/bin/dstat
Obsoletes: dstat <= 0.8
%endif
%endif
%description system-tools
This PCP module contains additional system monitoring tools written
in the Python language.
%endif
%if !%{disable_qt}
#
@ -2216,14 +2284,26 @@ interface rules, type enforcement and file context adjustments for an
updated policy package.
%endif
%prep
%setup -q
%patch000 -p1
%patch001 -p1
%patch002 -p1
%patch003 -p1
%patch0 -p1
%patch1 -p1
%patch2 -p1
%patch3 -p1
%patch4 -p1
%patch5 -p1
%patch6 -p1
%patch7 -p1
%patch8 -p1
%patch9 -p1
%patch10 -p1
%patch11 -p1
%build
# the buildsubdir macro gets defined in %setup and is apparently only available in the next step (i.e. the %build step)
%global __strip %{_builddir}/%{?buildsubdir}/build/rpm/custom-strip
# fix up build version
_build=`echo %{release} | sed -e 's/\..*$//'`
sed -i "/PACKAGE_BUILD/s/=[0-9]*/=$_build/" VERSION.pcp
@ -2231,7 +2311,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_podman} %{?_with_statsd} %{?_with_perfevent} %{?_with_bcc} %{?_with_bpftrace} %{?_with_json} %{?_with_snmp} %{?_with_nutcracker} %{?_with_python2}
%configure %{?_with_initd} %{?_with_doc} %{?_with_dstat} %{?_with_ib} %{?_with_podman} %{?_with_statsd} %{?_with_perfevent} %{?_with_bcc} %{?_with_bpf} %{?_with_bpftrace} %{?_with_json} %{?_with_snmp} %{?_with_nutcracker} %{?_with_python2}
make %{?_smp_mflags} default_pcp
%install
@ -2363,12 +2443,12 @@ basic_manifest() {
# Likewise, for the pcp-pmda and pcp-testsuite subpackages.
#
total_manifest | keep 'tutorials|/html/|pcp-doc|man.*\.[1-9].*' | cull 'out' >pcp-doc-files
total_manifest | keep 'testsuite|etc/systemd/system' >pcp-testsuite-files
total_manifest | keep 'testsuite|etc/systemd/system|libpcp_fault|pcp/fault.h' >pcp-testsuite-files
basic_manifest | keep "$PCP_GUI|pcp-gui|applications|pixmaps|hicolor" | cull 'pmtime.h' >pcp-gui-files
basic_manifest | keep 'selinux' | cull 'tmp|GNUselinuxdefs' >pcp-selinux-files
basic_manifest | keep 'selinux' | cull 'tmp|testsuite' >pcp-selinux-files
basic_manifest | keep 'zeroconf|daily[-_]report|/sa$' >pcp-zeroconf-files
basic_manifest | grep -E -e 'pmiostat|pmrep|dstat|pcp2csv' \
basic_manifest | grep -E -e 'pmiostat|pmrep|dstat|htop|pcp2csv' \
-e 'pcp-atop|pcp-dmcache|pcp-dstat|pcp-free|pcp-htop' \
-e 'pcp-ipcs|pcp-iostat|pcp-lvmcache|pcp-mpstat' \
-e 'pcp-numastat|pcp-pidstat|pcp-shping|pcp-tapestat' \
@ -2396,11 +2476,13 @@ basic_manifest | keep '(etc/pcp|pmdas)/bash(/|$)' >pcp-pmda-bash-files
basic_manifest | keep '(etc/pcp|pmdas)/bcc(/|$)' >pcp-pmda-bcc-files
basic_manifest | keep '(etc/pcp|pmdas)/bind2(/|$)' >pcp-pmda-bind2-files
basic_manifest | keep '(etc/pcp|pmdas)/bonding(/|$)' >pcp-pmda-bonding-files
basic_manifest | keep '(etc/pcp|pmdas)/bpf(/|$)' >pcp-pmda-bpf-files
basic_manifest | keep '(etc/pcp|pmdas)/bpftrace(/|$)' >pcp-pmda-bpftrace-files
basic_manifest | keep '(etc/pcp|pmdas)/cifs(/|$)' >pcp-pmda-cifs-files
basic_manifest | keep '(etc/pcp|pmdas)/cisco(/|$)' >pcp-pmda-cisco-files
basic_manifest | keep '(etc/pcp|pmdas)/dbping(/|$)' >pcp-pmda-dbping-files
basic_manifest | keep '(etc/pcp|pmdas|pmieconf)/dm(/|$)' >pcp-pmda-dm-files
basic_manifest | keep '(etc/pcp|pmdas)/denki(/|$)' >pcp-pmda-denki-files
basic_manifest | keep '(etc/pcp|pmdas)/docker(/|$)' >pcp-pmda-docker-files
basic_manifest | keep '(etc/pcp|pmdas)/ds389log(/|$)' >pcp-pmda-ds389log-files
basic_manifest | keep '(etc/pcp|pmdas)/ds389(/|$)' >pcp-pmda-ds389-files
@ -2423,6 +2505,7 @@ basic_manifest | keep '(etc/pcp|pmdas)/memcache(/|$)' >pcp-pmda-memcache-files
basic_manifest | keep '(etc/pcp|pmdas)/mailq(/|$)' >pcp-pmda-mailq-files
basic_manifest | keep '(etc/pcp|pmdas)/mic(/|$)' >pcp-pmda-mic-files
basic_manifest | keep '(etc/pcp|pmdas)/mounts(/|$)' >pcp-pmda-mounts-files
basic_manifest | keep '(etc/pcp|pmdas)/mongodb(/|$)' >pcp-pmda-mongodb-files
basic_manifest | keep '(etc/pcp|pmdas|pmieconf)/mssql(/|$)' >pcp-pmda-mssql-files
basic_manifest | keep '(etc/pcp|pmdas)/mysql(/|$)' >pcp-pmda-mysql-files
basic_manifest | keep '(etc/pcp|pmdas)/named(/|$)' >pcp-pmda-named-files
@ -2459,23 +2542,22 @@ basic_manifest | keep '(etc/pcp|pmdas)/systemd(/|$)' >pcp-pmda-systemd-files
basic_manifest | keep '(etc/pcp|pmdas)/trace(/|$)' >pcp-pmda-trace-files
basic_manifest | keep '(etc/pcp|pmdas)/unbound(/|$)' >pcp-pmda-unbound-files
basic_manifest | keep '(etc/pcp|pmdas)/weblog(/|$)' >pcp-pmda-weblog-files
basic_manifest | keep '(etc/pcp|pmdas)/vmware(/|$)' >pcp-pmda-vmware-files
basic_manifest | keep '(etc/pcp|pmdas)/zimbra(/|$)' >pcp-pmda-zimbra-files
basic_manifest | keep '(etc/pcp|pmdas)/zswap(/|$)' >pcp-pmda-zswap-files
rm -f packages.list
for pmda_package in \
activemq apache \
bash bcc bind2 bonding bpftrace \
bash bcc bind2 bonding bpf bpftrace \
cifs cisco \
dbping docker dm ds389 ds389log \
dbping denki docker dm ds389 ds389log \
elasticsearch \
gfs2 gluster gpfs gpsd \
hacluster haproxy \
infiniband \
json \
libvirt lio lmsensors logger lustre lustrecomm \
mailq memcache mic mounts mssql mysql \
mailq memcache mic mounts mongodb mssql mysql \
named netcheck netfilter news nfsclient nginx \
nutcracker nvidia \
openmetrics openvswitch oracle \
@ -2485,7 +2567,6 @@ for pmda_package in \
sockets statsd summary systemd \
unbound \
trace \
vmware \
weblog \
zimbra zswap ; \
do \
@ -2609,6 +2690,9 @@ done
%endif
%pre testsuite
%if !%{disable_selinux}
%selinux_relabel_pre -s targeted
%endif
test -d %{_testsdir} || mkdir -p -m 755 %{_testsdir}
getent group pcpqa >/dev/null || groupadd -r pcpqa
getent passwd pcpqa >/dev/null || \
@ -2617,13 +2701,16 @@ chown -R pcpqa:pcpqa %{_testsdir} 2>/dev/null
exit 0
%post testsuite
%if !%{disable_selinux}
semodule -r pcpqa >/dev/null 2>&1 || true
%selinux_modules_install -s targeted %{_selinuxdir}/pcp-testsuite.pp.bz2
%selinux_relabel_post -s targeted
%endif
chown -R pcpqa:pcpqa %{_testsdir} 2>/dev/null
%if 0%{?rhel}
%if !%{disable_systemd}
systemctl restart pmcd >/dev/null 2>&1
systemctl restart pmlogger >/dev/null 2>&1
systemctl enable pmcd >/dev/null 2>&1
systemctl enable pmlogger >/dev/null 2>&1
systemctl restart pmcd pmlogger >/dev/null 2>&1
systemctl enable pmcd pmlogger >/dev/null 2>&1
%else
/sbin/chkconfig --add pmcd >/dev/null 2>&1
/sbin/chkconfig --add pmlogger >/dev/null 2>&1
@ -2633,6 +2720,14 @@ chown -R pcpqa:pcpqa %{_testsdir} 2>/dev/null
%endif
exit 0
%if !%{disable_selinux}
%postun testsuite
if [ $1 -eq 0 ]; then
%selinux_modules_uninstall -s targeted pcp-testsuite
%selinux_relabel_post -s targeted
fi
%endif
%pre
getent group pcp >/dev/null || groupadd -r pcp
getent passwd pcp >/dev/null || \
@ -2710,6 +2805,9 @@ exit 0
%preun pmda-dbping
%{pmda_remove "$1" "dbping"}
%preun pmda-denki
%{pmda_remove "$1" "denki"}
%preun pmda-docker
%{pmda_remove "$1" "docker"}
@ -2769,9 +2867,6 @@ exit 0
%preun pmda-samba
%{pmda_remove "$1" "samba"}
%preun pmda-vmware
%{pmda_remove "$1" "vmware"}
%preun pmda-zimbra
%{pmda_remove "$1" "zimbra"}
@ -2783,6 +2878,11 @@ exit 0
%{pmda_remove "$1" "bcc"}
%endif
%if !%{disable_bpf}
%preun pmda-bpf
%{pmda_remove "$1" "bpf"}
%endif
%if !%{disable_bpftrace}
%preun pmda-bpftrace
%{pmda_remove "$1" "bpftrace"}
@ -2810,6 +2910,9 @@ exit 0
%preun pmda-lmsensors
%{pmda_remove "$1" "lmsensors"}
%preun pmda-mongodb
%{pmda_remove "$1" "mongodb"}
%if !%{disable_mssql}
%preun pmda-mssql
%{pmda_remove "$1" "mssql"}
@ -2878,10 +2981,7 @@ exit 0
%preun zeroconf
if [ "$1" -eq 0 ]
then
%systemd_preun pmlogger_daily_report.timer
%systemd_preun pmlogger_daily_report.service
%systemd_preun pmlogger_daily_report-poll.timer
%systemd_preun pmlogger_daily_report-poll.service
%systemd_preun pmlogger_daily_report.timer pmlogger_daily_report.service
fi
%endif
@ -2890,19 +2990,9 @@ if [ "$1" -eq 0 ]
then
# stop daemons before erasing the package
%if !%{disable_systemd}
%systemd_preun pmlogger.service
%systemd_preun pmie.service
%systemd_preun pmproxy.service
%systemd_preun pmcd.service
%systemd_preun pmie_daily.timer
%systemd_preun pmlogger_daily.timer
%systemd_preun pmlogger_daily-poll.timer
%systemd_preun pmlogger_check.timer
%systemd_preun pmlogger_check.timer pmlogger_daily.timer pmlogger_farm_check.timer pmlogger_farm_check.service pmlogger_farm.service pmlogger.service pmie_check.timer pmie_daily.timer pmie_farm_check.timer pmie_farm_check.service pmie_farm.service pmie.service pmproxy.service pmfind.service pmcd.service
systemctl stop pmlogger.service >/dev/null 2>&1
systemctl stop pmie.service >/dev/null 2>&1
systemctl stop pmproxy.service >/dev/null 2>&1
systemctl stop pmcd.service >/dev/null 2>&1
systemctl stop pmlogger.service pmie.service pmproxy.service pmfind.service pmcd.service >/dev/null 2>&1
%else
/sbin/service pmlogger stop >/dev/null 2>&1
/sbin/service pmie stop >/dev/null 2>&1
@ -2924,6 +3014,7 @@ fi
PCP_PMDAS_DIR=%{_pmdasdir}
PCP_SYSCONFIG_DIR=%{_sysconfdir}/sysconfig
PCP_PMCDCONF_PATH=%{_confdir}/pmcd/pmcd.conf
PCP_PMIECONFIG_DIR=%{_ieconfigdir}
# auto-install important PMDAs for RH Support (if not present already)
for PMDA in dm nfsclient openmetrics ; do
if ! grep -q "$PMDA/pmda$PMDA" "$PCP_PMCDCONF_PATH"
@ -2931,18 +3022,12 @@ for PMDA in dm nfsclient openmetrics ; do
%{install_file "$PCP_PMDAS_DIR/$PMDA" .NeedInstall}
fi
done
# increase default pmlogger recording frequency
sed -i 's/^\#\ PMLOGGER_INTERVAL.*/PMLOGGER_INTERVAL=10/g' "$PCP_SYSCONFIG_DIR/pmlogger"
# auto-enable these usually optional pmie rules
pmieconf -c enable dmthin
%{run_pmieconf "$PCP_PMIECONFIG_DIR" dmthin}
%if 0%{?rhel}
%if !%{disable_systemd}
systemctl restart pmcd >/dev/null 2>&1
systemctl restart pmlogger >/dev/null 2>&1
systemctl restart pmie >/dev/null 2>&1
systemctl enable pmcd >/dev/null 2>&1
systemctl enable pmlogger >/dev/null 2>&1
systemctl enable pmie >/dev/null 2>&1
systemctl restart pmcd pmlogger pmie >/dev/null 2>&1
systemctl enable pmcd pmlogger pmie >/dev/null 2>&1
%else
/sbin/chkconfig --add pmcd >/dev/null 2>&1
/sbin/chkconfig --add pmlogger >/dev/null 2>&1
@ -2953,30 +3038,24 @@ pmieconf -c enable dmthin
%endif
%endif
%if !%{disable_selinux}
%post selinux
%{selinux_handle_policy "$1" "pcpupstream"}
%triggerin selinux -- docker-selinux
%{selinux_handle_policy "$1" "pcpupstream-docker"}
%triggerin selinux -- container-selinux
%{selinux_handle_policy "$1" "pcpupstream-container"}
%endif
%post
PCP_PMNS_DIR=%{_pmnsdir}
PCP_LOG_DIR=%{_logsdir}
%{install_file "$PCP_PMNS_DIR" .NeedRebuild}
%{install_file "$PCP_LOG_DIR/pmlogger" .NeedRewrite}
%if !%{disable_systemd}
# clean up any stale symlinks for deprecated pm*-poll services
rm -f %{_sysconfdir}/systemd/system/pm*.requires/pm*-poll.* >/dev/null 2>&1 || true
%systemd_postun_with_restart pmcd.service
%systemd_post pmcd.service
%systemd_postun_with_restart pmlogger.service
%systemd_post pmlogger.service
%systemd_postun_with_restart pmie.service
%systemd_post pmie.service
systemctl condrestart pmproxy.service >/dev/null 2>&1
%systemd_postun_with_restart pmproxy.service
%systemd_post pmproxy.service
%systemd_post pmfind.service
%else
/sbin/chkconfig --add pmcd >/dev/null 2>&1
/sbin/service pmcd condrestart
@ -2997,14 +3076,21 @@ PCP_LOG_DIR=%{_logsdir}
%endif
%if !%{disable_selinux}
%preun selinux
%{selinux_handle_policy "$1" "pcpupstream"}
%pre selinux
%selinux_relabel_pre -s targeted
%triggerun selinux -- docker-selinux
%{selinux_handle_policy "$1" "pcpupstream-docker"}
%post selinux
semodule -r pcpupstream-container >/dev/null 2>&1 || true
semodule -r pcpupstream-docker >/dev/null 2>&1 || true
semodule -r pcpupstream >/dev/null 2>&1 || true
%selinux_modules_install -s targeted %{_selinuxdir}/pcp.pp.bz2
%selinux_relabel_post -s targeted
%triggerun selinux -- container-selinux
%{selinux_handle_policy "$1" "pcpupstream-container"}
%postun selinux
if [ $1 -eq 0 ]; then
%selinux_modules_uninstall -s targeted pcp
%selinux_relabel_post -s targeted
fi
%endif
%files -f pcp-files.rpm
@ -3023,6 +3109,7 @@ PCP_LOG_DIR=%{_logsdir}
%if !%{disable_selinux}
%files selinux -f pcp-selinux-files.rpm
%ghost %verify(not md5 size mode mtime) %{_sharedstatedir}/selinux/targeted/active/modules/200/pcp
%endif
%if !%{disable_qt}
@ -3096,11 +3183,11 @@ PCP_LOG_DIR=%{_logsdir}
%files pmda-slurm -f pcp-pmda-slurm-files.rpm
%files pmda-vmware -f pcp-pmda-vmware-files.rpm
%files pmda-zimbra -f pcp-pmda-zimbra-files.rpm
%endif
%files pmda-denki -f pcp-pmda-denki-files.rpm
%files pmda-docker -f pcp-pmda-docker-files.rpm
%files pmda-lustrecomm -f pcp-pmda-lustrecomm-files.rpm
@ -3133,6 +3220,10 @@ PCP_LOG_DIR=%{_logsdir}
%files pmda-bcc -f pcp-pmda-bcc-files.rpm
%endif
%if !%{disable_bpf}
%files pmda-bpf -f pcp-pmda-bpf-files.rpm
%endif
%if !%{disable_bpftrace}
%files pmda-bpftrace -f pcp-pmda-bpftrace-files.rpm
%endif
@ -3150,6 +3241,8 @@ PCP_LOG_DIR=%{_logsdir}
%files pmda-lmsensors -f pcp-pmda-lmsensors-files.rpm
%files pmda-mongodb -f pcp-pmda-mongodb-files.rpm
%if !%{disable_mssql}
%files pmda-mssql -f pcp-pmda-mssql-files.rpm
%endif
@ -3272,13 +3365,102 @@ PCP_LOG_DIR=%{_logsdir}
%files -n python3-pcp -f python3-pcp.list.rpm
%endif
%if !%{disable_python2} || !%{disable_python3}
%files system-tools -f pcp-system-tools-files.rpm
%endif
%files zeroconf -f pcp-zeroconf-files.rpm
%changelog
* Thu Nov 17 2022 Nathan Scott <nathans@redhat.com> - 5.3.7-16
- Ensure SNMP metrics config symlink installed (BZ 2139012)
* Thu Oct 27 2022 Nathan Scott <nathans@redhat.com> - 5.3.7-15
- Backport independent selinux policy rework (BZ 2111742)
- Fix invalid memory access in pmfind utility (BZ 2135314)
- Allow pcp-dstat(1) missed ticks suppression (BZ 2083897)
* Mon Sep 05 2022 Nathan Scott <nathans@redhat.com> - 5.3.7-9
- Additional selinux policy rules for pmdabcc (BZ 2050094)
- Describe working sudoers requiretty configuration (BZ 2093751)
- Separate pmlogger_farm configuration mechanism (BZ 2101574)
* Mon May 09 2022 Nathan Scott <nathans@redhat.com> - 5.3.7-7
- Additional selinux policy rules for pmdasockets (BZ 1981886)
* Thu May 05 2022 Nathan Scott <nathans@redhat.com> - 5.3.7-5
- Harden pmdapostfix(1) against missing Postfix (BZ 2059463)
- Fix cgroups failure on non-x86_64 platforms (BZ 2081262)
* Tue May 03 2022 Nathan Scott <nathans@redhat.com> - 5.3.7-3
- Fix remaining issues in the pcp-ss(1) utility (BZ 1981886)
- Remove benign warning message from pmie systemd unit file.
* Tue Apr 05 2022 Nathan Scott <nathans@redhat.com> - 5.3.7-1
- Fix several issues in the pcp-ss(1) utility (BZ 1981886)
- Document pmproxy archive discovery further (BZ 2026726)
- Improve SQL Server PMDA secure settings (BZ 2057615)
- Rebase to latest stable version of PCP (BZ 2059461)
* Wed Feb 02 2022 Nathan Scott <nathans@redhat.com> - 5.3.5-8
- Fix pcp-zeroconf logger interval override regression (BZ 1991763)
- Remove warnings from spec setup of PCP systemd units (BZ 2048024)
* Thu Dec 16 2021 Andreas Gerstmayr <agerstmayr@redhat.com> - 5.3.5-6
- pmdabcc: update qa/1118 testcase to match new output (BZ 2003956)
* Wed Dec 15 2021 Nathan Scott <nathans@redhat.com> - 5.3.5-4
- pmdabcc: resolve compilation issues of some bcc PMDA modules on
aarch64, ppc64le and s390x (BZ 2003956)
- Further improve pmlogger service startup latency (BZ 1973833)
- Additional improvements to farm systemd services (BZ 2027753)
* Thu Dec 09 2021 Nathan Scott <nathans@redhat.com> - 5.3.5-3
- Resolve failure in the Nvidia metrics agent (BZ 2029301)
- PMDA indom cache loading performance improvements (BZ 2030121)
- Consistent user experience for new farm services (BZ 2027753)
- Resilience improvements for the pmproxy service (BZ 2030140)
* Fri Nov 26 2021 Nathan Scott <nathans@redhat.com> - 5.3.5-2
- Updates to pmlogconf persistence changes (BZ 2017632)
* Wed Nov 10 2021 Nathan Scott <nathans@redhat.com> - 5.3.5-1
- Extend pmlogger(1) man page --interval option (BZ 2018083)
- Disable Avahi service advertisement by default (BZ 1899625)
- Use separate localhost and farm service cgroups (BZ 1991896)
- Update and extend the Nvidia GPU metric coverage (BZ 1690590)
- Assessment API and pmdamssql(1) share credentials (BZ 1951342)
- Improve remote pmlogger over slow network connections (BZ 1973833)
- Implement pcp-atop(1) support for Nvidia GPU reports (BZ 1984273)
- Drop DMA[32] zones when the zone is not in node 0 (BZ 1985519)
- Support kernel changes to /proc/zoneinfo metrics (BZ 1985523)
- Ensure pmlogconf persists configuration changes (BZ 2017632)
- Auto-reconnect lost redis connection in pmproxy (BZ 1989287)
- Rebase to a more recent upstream version of PCP (BZ 1991763)
* Fri Oct 15 2021 Mark Goodwin <mgoodwin@redhat.com> - 5.3.4-2
- Fix pmlogger manual start with service disabled (BZ 2018011)
* Fri Oct 08 2021 Nathan Scott <nathans@redhat.com> - 5.3.4-1
- Add pcp-atop(1) support for 'curscal' values (BZ 1984271)
- Fix pcp-atop(1) reporting perfevent 'ipc' values (BZ 1986264)
- Fix pmlogger(1) exiting on receipt of SIGALRM (BZ 2004771)
- Fix values of some hacluster metrics on s390x (BZ 2008298)
- Add new pmdads389(1) metrics for replication (BZ 1966122)
- Rebase to a more recent upstream version of PCP (BZ 1991763)
* Wed Sep 15 2021 Nathan Scott <nathans@redhat.com> - 5.3.3-1
- Add new pmdads389(1) metrics for replication (BZ 1966122)
- Add label support to pmdahacluster(1) metrics (BZ 1972277)
- Improve pmieconf rules for saturated processors (BZ 1994680)
- Auto-upgrade pmcd.conf for python2 to python3 (BZ 1988403)
- Document unloading pmdakvm(1) for kernel module (BZ 1977740)
- Add option to pmdalinux(1) for slabinfo metrics (BZ 1962902)
- Fix for OpenMetrics scripting generating AVCs (BZ 1985818)
- Resolve some pcp-testsuite failures (BZ 1980459, 1981686)
- Rebase to a more recent upstream version of PCP (BZ 1991763)
* Sat Aug 28 2021 Nathan Scott <nathans@redhat.com> - 5.3.1-5
- Fix pmdapodman initialization and selinux policy (BZ 1962019)
* Fri Jul 09 2021 Mark Goodwin <mgoodwin@redhat.com> - 5.3.1-3
- Improve pmproxy and libpcp_web scalability (BZ 1975069)
- Provide a pcp-ss(1) tool in pcp-system-tools (BZ 1879350)