Skip to main content

Hi,

There is a docker connector, can make a connector for podman (which looks a lot like Docker).

Best regards,

NewIn Backlog

Updated idea statusIn BacklogNeeds Votes

Hello :)

This idea had been released in the February release.

Kind regards.


Needs VotesReleased

This plugin is nice, but I see one slight issue that makes it unusable in some situations. The check to monitor the state of specific containers doesn’t return a critical status if the container is not running at all or doesn’t exist (it just skips and return OK). In some cases, the container needs to be destroyed before it is recreated (ex. to update its image), or is setup to run with the --rm parameter meaning it will be deleted if it exits. This is a valid scenario and I would like to be able to get alerted if one one the containers supposed to run (ex. via a systemd service) has failed, even if it’s no longer running at all.

There should be an optional parameter to exit as critical if the requested container returns no data (empty array) because it doesn’t exist.


Hello :)

Could you provided us with a debug output to understand exactly your needs?
Have you already try using this options to rise a warning: 

=item B<--warning-container-state>

Define the conditions to match for the state to be WARNING (default: C<'%{state} =~ /Paused/'>).
You can use the following variables: C<%{state}>

=item B<--critical-container-state>

Define the conditions to match for the state to be CRITICAL (default: C<'%{state} =~ /Exited/'>).
You can use the following variables: C<%{state}>

Also it may be possible to use this option (available for all plugins):

=item B<--change-output-adv>

Replace short output and exit code based on a "if" condition using the following variables:
short_output, exit_code.
Variables must be written either %{variable} or %(variable).
Example: adding --change-output-adv='%(short_ouput) =~ /UNKNOWN: No daemon/,OK: No daemon,OK' will
change the following specific UNKNOWN result to an OK result.


Kind regards.


I have tried using the different state parameters and they are simply not considered if the container is not running at all (if the returned info doesn’t contain the container as part of the data array), it just skips and returns OK anyway.

For example, say I have two containers running, one named “patate” and the other “tomate”, and I want to check “patate” with Centreon. Here is the debug output when it is running (don’t worry about IPs, it’s a local test VM, there’s nothing sensitive):
 

rygirouard@centreon ~]$ /usr/lib/centreon/plugins//centreon_podman_restapi.pl --plugin=apps::podman::restapi::plugin --mode=container-usage --custommode=api --hostname='192.168.0.201' --port='8889' --proto='http'  --container-name='bitch' --warning-cpu-usage='' --critical-cpu-usage='' --warning-memory-usage='' --critical-memory-usage='' --warning-read-io='' --critical-read-io='' --warning-write-io='' --critical-write-io='' --warning-network-in='' --critical-network-in='' --warning-network-out='' --critical-network-out='' --warning-state='%{state} =~ /Paused/' --critical-state='%{state} =~ /Exited/' --verbose --debug
OK: CPU: 0.02%, Memory: 212.00KB, Read : 0.00B, Write : 0.00B, network-in : skipped (no value(s)), network-out : skipped (no value(s)), state : skipped (no value(s)) | 'podman.container.cpu.usage.percent'=0.02%;;;0;100 'podman.container.memory.usage.bytes'=217088B;;;0; 'podman.container.io.read'=0B;;;0; 'podman.container.io.write'=0B;;;0;
== Info: Trying 192.168.0.201:8889...
== Info: Connected to 192.168.0.201 (192.168.0.201) port 8889 (#0)
=> Send header: GET /v5.0.0/libpod/containers/stats?stream=false&amp;containers=bitch HTTP/1.1
Host: 192.168.0.201:8889
Accept:application/json

== Info: Mark bundle as not supporting multiuse
=> Recv header: HTTP/1.1 200 OK
=> Recv header: Api-Version: 1.41
=> Recv header: Libpod-Api-Version: 5.2.2
=> Recv header: Server: Libpod/5.2.2 (linux)
=> Recv header: X-Reference-Id: 0xc0005d6008
=> Recv header: Date: Fri, 11 Apr 2025 13:46:13 GMT
=> Recv header: Content-Type: text/plain; charset=utf-8
=> Recv header: Transfer-Encoding: chunked
=> Recv header:
=> Recv data: 427
{"Error":null,"Stats":"{"AvgCPU":0.02290531978149026,"ContainerID":"87c479d9c02ccc3dc6fbb19055ccd469c3f536fcc2bac8bf48dc7ca215446e92","Name":"patate","PerCPU":null,"CPU":0.02290531978149026,"CPUNano":11960000,"CPUSystemNano":11960,"SystemNano":1744379173859676056,"MemUsage":217088,"MemLimit":1341464576,"MemPerc":0.016182909626083184,"Network":{"eth0":{"RxBytes":0,"RxDropped":0,"RxErrors":0,"RxPackets":0,"TxBytes":726,"TxDropped":0,"TxErrors":0,"TxPackets":9}},"BlockInput":0,"BlockOutput":0,"PIDs":1,"UpTime":11960000,"Duration":11960000},{"AvgCPU":0.022736757313467273,"ContainerID":"f7793ebade74cf8af83b99a0551c26d6df0a9840e8c46e356cf223f06635cf51","Name":"tomate","PerCPU":null,"CPU":0.022736757313467273,"CPUNano":9304000,"CPUSystemNano":9304,"SystemNano":1744379173860253772,"MemUsage":217088,"MemLimit":1341464576,"MemPerc":0.016182909626083184,"Network":{"eth0":{"RxBytes":0,"RxDropped":0,"RxErrors":0,"RxPackets":0,"TxBytes":726,"TxDropped":0,"TxErrors":0,"TxPackets":9}},"BlockInput":0,"BlockOutput":0,"PIDs":1,"UpTime":9304000,"Duration":9304000}]}

0

== Info: Connection #0 to host 192.168.0.201 left intact
== Info: Found bundle for host 192.168.0.201: 0x55e729973e50 .serially]
== Info: Can not multiplex, even if we wanted to!
== Info: Re-using existing connection! (#0) with host 192.168.0.201
== Info: Connected to 192.168.0.201 (192.168.0.201) port 8889 (#0)
=> Send header: GET /v5.0.0/libpod/containers/json HTTP/1.1
Host: 192.168.0.201:8889
Accept:application/json

== Info: Mark bundle as not supporting multiuse
=> Recv header: HTTP/1.1 200 OK
=> Recv header: Api-Version: 1.41
=> Recv header: Content-Type: application/json
=> Recv header: Libpod-Api-Version: 5.2.2
=> Recv header: Server: Libpod/5.2.2 (linux)
=> Recv header: X-Reference-Id: 0xc0005d6008
=> Recv header: Date: Fri, 11 Apr 2025 13:46:13 GMT
=> Recv header: Transfer-Encoding: chunked
=> Recv header:
=> Recv data: 800
{"AutoRemove":true,"Command":m"sleep","9000"],"Created":"2025-04-11T09:45:21.547599055-04:00","CreatedAt":"","CIDFile":"","Exited":false,"ExitedAt":-62135596800,"ExitCode":0,"ExposedPorts":null,"Id":"87c479d9c02ccc3dc6fbb19055ccd469c3f536fcc2bac8bf48dc7ca215446e92","Image":"registry.access.redhat.com/ubi8:latest","ImageID":"b7cd93e154b49774a2110c33695b6c235ca6d6dfd401857c5accf47c6be21311","IsInfra":false,"Labels":{"architecture":"x86_64","build-date":"2025-03-13T10:59:43","com.redhat.component":"ubi8-container","com.redhat.license_terms":"https://www.redhat.com/en/about/red-hat-end-user-license-agreements#UBI","description":"The Universal Base Image is designed and engineered to be the base layer for all of your containerized applications, middleware and utilities. This base image is freely redistributable, but Red Hat only supports Red Hat technologies through subscriptions for Red Hat products. This image is maintained by Red Hat and updated regularly.","distribution-scope":"public","io.buildah.version":"1.33.12","io.k8s.description":"The Universal Base Image is designed and engineered to be the base layer for all of your containerized applications, middleware and utilities. This base image is freely redistributable, but Red Hat only supports Red Hat technologies through subscriptions for Red Hat products. This image is maintained by Red Hat and updated regularly.","io.k8s.display-name":"Red Hat Universal Base Image 8","io.openshift.expose-services":"","io.openshift.tags":"base rhel8","maintainer":"Red Hat, Inc.","name":"ubi8","release":"1184.1741863532","summary":"Provides the latest release of Red Hat Universal Base Image 8.","url":"https://access.redhat.com/containers/#/registry.access.redhat.com/ubi8/images/8.10-1184.1741863532","vcs-ref":"967861a8dbbb288b8cec9f1fee7ccbf6c7ee9a20","vcs-type":"git","vendor":"Red Hat, Inc.","version":"8.10"},"Mounts":o],"Names":,"patate"],"Namespaces":{},"Networks":p],"Pid":1404,"Pod":"","PodName":"","Ports":null,"Restarts":0,"Size":null,"StartedAt":1744379121,"State":"runni
800
ng","Status":""},{"AutoRemove":true,"Command":m"sleep","9000"],"Created":"2025-04-11T09:45:32.86580644-04:00","CreatedAt":"","CIDFile":"","Exited":false,"ExitedAt":-62135596800,"ExitCode":0,"ExposedPorts":null,"Id":"f7793ebade74cf8af83b99a0551c26d6df0a9840e8c46e356cf223f06635cf51","Image":"registry.access.redhat.com/ubi8:latest","ImageID":"b7cd93e154b49774a2110c33695b6c235ca6d6dfd401857c5accf47c6be21311","IsInfra":false,"Labels":{"architecture":"x86_64","build-date":"2025-03-13T10:59:43","com.redhat.component":"ubi8-container","com.redhat.license_terms":"https://www.redhat.com/en/about/red-hat-end-user-license-agreements#UBI","description":"The Universal Base Image is designed and engineered to be the base layer for all of your containerized applications, middleware and utilities. This base image is freely redistributable, but Red Hat only supports Red Hat technologies through subscriptions for Red Hat products. This image is maintained by Red Hat and updated regularly.","distribution-scope":"public","io.buildah.version":"1.33.12","io.k8s.description":"The Universal Base Image is designed and engineered to be the base layer for all of your containerized applications, middleware and utilities. This base image is freely redistributable, but Red Hat only supports Red Hat technologies through subscriptions for Red Hat products. This image is maintained by Red Hat and updated regularly.","io.k8s.display-name":"Red Hat Universal Base Image 8","io.openshift.expose-services":"","io.openshift.tags":"base rhel8","maintainer":"Red Hat, Inc.","name":"ubi8","release":"1184.1741863532","summary":"Provides the latest release of Red Hat Universal Base Image 8.","url":"https://access.redhat.com/containers/#/registry.access.redhat.com/ubi8/images/8.10-1184.1741863532","vcs-ref":"967861a8dbbb288b8cec9f
=> Recv data: 1fee7ccbf6c7ee9a20","vcs-type":"git","vendor":"Red Hat, Inc.","version":"8.10"},"Mounts":o],"Names":,"tomate"],"Namespaces":{},"Networks":p],"Pid":1429,"Pod":"","PodName":"","Ports":null,"Restarts":0,"Size":null,"StartedAt":1744379132
21
,"State":"running","Status":""}]

0

== Info: Connection #0 to host 192.168.0.201 left intact

On the podman server, both containers are running:
 

bpoduser1@rhel9 ~]$ podman ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
02a05621ac8e registry.access.redhat.com/ubi8:latest sleep 9000 7 seconds ago Up 8 seconds tomate
795b14b3c86b registry.access.redhat.com/ubi8:latest sleep 9000 4 seconds ago Up 4 seconds patate

Now, if I destroy the container patate (podman rm -f -t0 patate), and run the check again:

 ygirouard@centreon ~]$ /usr/lib/centreon/plugins//centreon_podman_restapi.pl --plugin=apps::podman::restapi::plugin --mode=container-usage --custommode=api --hostname='192.168.0.201' --port='8889' --proto='http'  --container-name='bitch' --warning-cpu-usage='' --critical-cpu-usage='' --warning-memory-usage='' --critical-memory-usage='' --warning-read-io='' --critical-read-io='' --warning-write-io='' --critical-write-io='' --warning-network-in='' --critical-network-in='' --warning-network-out='' --critical-network-out='' --warning-state='%{state} =~ /Paused/' --critical-state='%{state} =~ /Exited/' --verbose --debug
OK: CPU: 0.01%, Memory: 212.00KB, Read : 0.00B, Write : 0.00B, network-in : skipped (no value(s)), network-out : skipped (no value(s)), state : skipped (no value(s)) | 'podman.container.cpu.usage.percent'=0.01%;;;0;100 'podman.container.memory.usage.bytes'=217088B;;;0; 'podman.container.io.read'=0B;;;0; 'podman.container.io.write'=0B;;;0;
== Info: Trying 192.168.0.201:8889...
== Info: Connected to 192.168.0.201 (192.168.0.201) port 8889 (#0)
=> Send header: GET /v5.0.0/libpod/containers/stats?stream=false&amp;containers=bitch HTTP/1.1
Host: 192.168.0.201:8889
Accept:application/json

== Info: Mark bundle as not supporting multiuse
=> Recv header: HTTP/1.1 200 OK
=> Recv header: Api-Version: 1.41
=> Recv header: Libpod-Api-Version: 5.2.2
=> Recv header: Server: Libpod/5.2.2 (linux)
=> Recv header: X-Reference-Id: 0xc000076000
=> Recv header: Date: Fri, 11 Apr 2025 14:21:39 GMT
=> Recv header: Content-Type: text/plain; charset=utf-8
=> Recv header: Transfer-Encoding: chunked
=> Recv header:
=> Recv data: 21e
{"Error":null,"Stats":{{"AvgCPU":0.01305606896751601,"ContainerID":"02a05621ac8e8e5b4964e510ea93c2799bb84783ab52009b35c8d7c8578dfb4a","Name":"tomate","PerCPU":null,"CPU":0.01305606896751601,"CPUNano":9479000,"CPUSystemNano":9479,"SystemNano":1744381299546103076,"MemUsage":217088,"MemLimit":1389699072,"MemPerc":0.015621223642869355,"Network":{"eth0":{"RxBytes":0,"RxDropped":0,"RxErrors":0,"RxPackets":0,"TxBytes":796,"TxDropped":0,"TxErrors":0,"TxPackets":10}},"BlockInput":0,"BlockOutput":0,"PIDs":1,"UpTime":9479000,"Duration":9479000}]}

=> Recv data: 0

== Info: Connection #0 to host 192.168.0.201 left intact
== Info: Found bundle for host 192.168.0.201: 0x55914f55aec0 0serially]
== Info: Can not multiplex, even if we wanted to!
== Info: Re-using existing connection! (#0) with host 192.168.0.201
== Info: Connected to 192.168.0.201 (192.168.0.201) port 8889 (#0)
=> Send header: GET /v5.0.0/libpod/containers/json HTTP/1.1
Host: 192.168.0.201:8889
Accept:application/json

== Info: Mark bundle as not supporting multiuse
=> Recv header: HTTP/1.1 200 OK
=> Recv header: Api-Version: 1.41
=> Recv header: Content-Type: application/json
=> Recv header: Libpod-Api-Version: 5.2.2
=> Recv header: Server: Libpod/5.2.2 (linux)
=> Recv header: X-Reference-Id: 0xc000076000
=> Recv header: Date: Fri, 11 Apr 2025 14:21:39 GMT
=> Recv header: Transfer-Encoding: chunked
=> Recv header:
=> Recv data: 800
;{"AutoRemove":true,"Command":e"sleep","9000"],"Created":"2025-04-11T10:20:26.870961993-04:00","CreatedAt":"","CIDFile":"","Exited":false,"ExitedAt":-62135596800,"ExitCode":0,"ExposedPorts":null,"Id":"02a05621ac8e8e5b4964e510ea93c2799bb84783ab52009b35c8d7c8578dfb4a","Image":"registry.access.redhat.com/ubi8:latest","ImageID":"b7cd93e154b49774a2110c33695b6c235ca6d6dfd401857c5accf47c6be21311","IsInfra":false,"Labels":{"architecture":"x86_64","build-date":"2025-03-13T10:59:43","com.redhat.component":"ubi8-container","com.redhat.license_terms":"https://www.redhat.com/en/about/red-hat-end-user-license-agreements#UBI","description":"The Universal Base Image is designed and engineered to be the base layer for all of your containerized applications, middleware and utilities. This base image is freely redistributable, but Red Hat only supports Red Hat technologies through subscriptions for Red Hat products. This image is maintained by Red Hat and updated regularly.","distribution-scope":"public","io.buildah.version":"1.33.12","io.k8s.description":"The Universal Base Image is designed and engineered to be the base layer for all of your containerized applications, middleware and utilities. This base image is freely redistributable, but Red Hat only supports Red Hat technologies through subscriptions for Red Hat products. This image is maintained by Red Hat and updated regularly.","io.k8s.display-name":"Red Hat Universal Base Image 8","io.openshift.expose-services":"","io.openshift.tags":"base rhel8","maintainer":"Red Hat, Inc.","name":"ubi8","release":"1184.1741863532","summary":"Provides the latest release of Red Hat Universal Base Image 8.","url":"https://access.redhat.com/containers/#/registry.access.redhat.com/ubi8/images/8.10-1184.1741863532","vcs-ref":"967861a8dbbb288b8cec9f1fee7ccbf6c7ee9a20","vcs-type":"git","vendor":"Red Hat, Inc.","version":"8.10"},"Mounts":i],"Names":}"tomate"],"Namespaces":{},"Networks":s],"Pid":1656,"Pod":"","PodName":"","Ports":null,"Restarts":0,"Size":null,"StartedAt":1744381226,"State":"runni
12
ng","Status":""}]

0

== Info: Connection #0 to host 192.168.0.201 left intact

It still returns OK even though the container is not present at all, and just says “skipped” for network-in, network-out and state because the values were not set. Instead, it should exit with at least an UNKNOWN or a CRITICAL because it is not running at all.

Is that clearer?


I’ve tried replying with debug info and it says the post is pending moderator approval… I might have pasted the wrong console output from a previous test by accident and it contained a word that might be filtered (I had used other names for test containers...). If it’s the case, let me know, it wasn’t intentional. Still I have responded further below in case it may help.


FYI, if it may help, I have made this change in the plugin to get what I wanted:

[centreon-engine@centreon tmp]$ diff /usr/lib/centreon/plugins/centreon_podman_restapi.pl ./centreon_podman_restapi.pl
262a263
> my $found = 0;
265a267,268
> $found = 1;
> last;
266a270,274
> }
>
> if (!$found) {
> $self->{output}->add_option_msg(short_msg => "Container '$options{container_name}' not found.");
> $self->{output}->option_exit();

If I just run the command with a container name that is not running, I then get this:
 

>centreon-engine@centreon tmp]$ ./centreon_podman_restapi.pl --plugin=apps::podman::restapi::plugin --mode=container-usage --custommode=api --hostname='192.168.0.201' --port='8889' --proto='http'  --container-name='patate' --warning-cpu-usage='' --critical-cpu-usage='' --warning-memory-usage='' --critical-memory-usage='' --warning-read-io='' --critical-read-io='' --warning-write-io='' --critical-write-io='' --warning-network-in='' --critical-network-in='' --warning-network-out='' --critical-network-out='' --warning-state='%{state} =~ /Paused/' --critical-state='%{state} =~ /Exited/' --verbose; echo $?
UNKNOWN: Container 'patate' not found.

To make it critical, I can add the --opt-exit=critical parameter and it works:
 

ecentreon-engine@centreon tmp]$ ./centreon_podman_restapi.pl --plugin=apps::podman::restapi::plugin --mode=container-usage --custommode=api --hostname='192.168.0.201' --port='8889' --proto='http'  --container-name='patate' --warning-cpu-usage='' --critical-cpu-usage='' --warning-memory-usage='' --critical-memory-usage='' --warning-read-io='' --critical-read-io='' --warning-write-io='' --critical-write-io='' --warning-network-in='' --critical-network-in='' --warning-network-out='' --critical-network-out='' --warning-state='%{state} =~ /Paused/' --critical-state='%{state} =~ /Exited/' --verbose --opt-exit=critical; echo $?
CRITICAL: Container 'patate' not found.

Does that help?


Found some more issues… With the current plugin script, if the containers are either paused or exited (podman stop, or podman pause), they won’t be found either because the Rest API’s /containers/json will not return pods that are not running unless you add the query parameter all=true. Also, the current defaults for warning-state and critical-state need to be case insensitive (/i) or it won’t work at least not with Podman on RHEL9. So, I have made some additional modifications to the script and it seems to work.

Here is the final diff:

 

ucentreon-engine@centreon tmp]$ diff /usr/lib/centreon/plugins/centreon_podman_restapi.pl ./centreon_podman_restapi.pl                                                                                                      176c176,177
< method => 'GET'
---
> method => 'GET',
> get_param => a'all=true']
262a264
> my $found = 0;
265a268,269
> $found = 1;
> last;
267a272,276
>
> if (!$found) {
> $self->{output}->add_option_msg(short_msg => "Container '$options{container_name}' not found.");
> $self->{output}->option_exit();
> }
461,462c470,471
< warning_default => '%{state} =~ /Paused/',
< critical_default => '%{state} =~ /Exited/',
---
> warning_default => '%{state} =~ /Paused/i',
> critical_default => '%{state} =~ /Exited/i',
568c577
< Define the conditions to match for the state to be WARNING (default: C<'%{state} =~ /Paused/'>).
---
> Define the conditions to match for the state to be WARNING (default: C<'%{state} =~ /Paused/i'>).
573c582
< Define the conditions to match for the state to be CRITICAL (default: C<'%{state} =~ /Exited/'>).
---
> Define the conditions to match for the state to be CRITICAL (default: C<'%{state} =~ /Exited/i'>).