Bug: REST API acknowledgement adds trailing ";" to comment with Nagios core (2.5.0p14)

CMK version: 2.5.0p14 Community, monitoring core: Nagios (CONFIG_CORE='nagios')

OS version: Linux

Error message: none. The acknowledgement works, but the stored comment gets an extra ; at the end.

Description

When a host problem is acknowledged via the REST API without an expiry, the comment stored by the Nagios core ends with a trailing ;.

Request (POST /domain-types/acknowledge/collections/host):

{
  "acknowledge_type": "host",
  "sticky": false,
  "persistent": false,
  "notify": false,
  "host_name": "example-host",
  "comment": "TEST ABC"
}

Command written to var/nagios/nagios.log:

EXTERNAL COMMAND: ACKNOWLEDGE_HOST_PROBLEM;example-host;1;0;0;api-user;TEST ABC;

Comment shown in the GUI: TEST ABC;

Root cause

  • cmk/livestatus_client/_api/commands.py: AcknowledgeHostProblem.args() (same for AcknowledgeServiceProblem) always returns expire_on as the last argument, after comment.
  • cmk/livestatus_client/_api/client.py, _serialize_command(): None is serialized as "", and the arguments are joined with ";".join(...). So the command always ends in comment;.
  • The trailing field is the CMC acknowledgement-expiry extension. The Nagios core does not know it. Nagios treats everything after the author as the comment, so the ; becomes part of the comment text. If expire_on is set, the timestamp ends up in the comment instead (TEST ABC;1791972000).

Reproduction

Serializing with the site’s own code (no command sent):

from datetime import datetime
from cmk.livestatus_client._api.client import LivestatusClient
from cmk.livestatus_client._api.commands import AcknowledgeHostProblem, Acknowledgement
from cmk.ccc.user import UserId
from cmk.ccc.hostaddress import HostName

kw = dict(host_name=HostName("example-host"), acknowledgement=Acknowledgement.NORMAL,
          notify=False, persistent=False, user=UserId("api-user"), comment="TEST ABC")
print(LivestatusClient._serialize_command(AcknowledgeHostProblem(**kw)))
# ACKNOWLEDGE_HOST_PROBLEM;example-host;1;0;0;api-user;TEST ABC;
print(LivestatusClient._serialize_command(AcknowledgeHostProblem(**kw, expire_on=datetime(2026,10,14,12,0))))
# ACKNOWLEDGE_HOST_PROBLEM;example-host;1;0;0;api-user;TEST ABC;1791972000

Confirming how the Nagios core stores the comment, by sending directly via lq:

ADD_HOST_COMMENT;example-host;0;test;RC TEST no-semicolon     -> stored: "RC TEST no-semicolon"
ADD_HOST_COMMENT;example-host;0;test;RC TEST trailing-semicolon;  -> stored: "RC TEST trailing-semicolon;"

Expected behaviour

Only append the expire_on field when it is set (and/or not for the Nagios core), so the command ends with the comment:

ACKNOWLEDGE_HOST_PROBLEM;example-host;1;0;0;api-user;TEST ABC

This looks like a regression of Werk #2580 (1.2.7i3), “Remove bogus ;0 in comment of problem acknowledgements” for Nagios/Icinga cores, where the GUI was changed to append the expiry only when set.