Skip to content

Commit

Permalink
Migrate agent_mqtt to SSC and ruleset APIs
Browse files Browse the repository at this point in the history
CMK-17394

Change-Id: I34a8dee05a8728d94e21518cc906fe432be24867
  • Loading branch information
racicLuka committed Oct 14, 2024
1 parent 0bd422e commit c0ceffb
Show file tree
Hide file tree
Showing 8 changed files with 277 additions and 211 deletions.
29 changes: 0 additions & 29 deletions cmk/base/legacy_checks/agent_mqtt.py

This file was deleted.

110 changes: 0 additions & 110 deletions cmk/gui/plugins/wato/special_agents/mqtt.py

This file was deleted.

160 changes: 160 additions & 0 deletions cmk/plugins/mqtt/rulesets/special_agent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
#!/usr/bin/env python3
# Copyright (C) 2019 Checkmk GmbH - License: GNU General Public License v2
# This file is part of Checkmk (https://checkmk.com). It is subject to the terms and
# conditions defined in the file COPYING, which is part of this source code package.


from cmk.utils.hostaddress import HostAddress

from cmk.rulesets.v1 import Help, Message, Title
from cmk.rulesets.v1.form_specs import (
DefaultValue,
DictElement,
Dictionary,
Integer,
migrate_to_password,
Password,
SingleChoice,
String,
validators,
)
from cmk.rulesets.v1.form_specs._basic import FieldSize, SingleChoiceElement
from cmk.rulesets.v1.rule_specs import SpecialAgent, Topic


def parameter_form() -> Dictionary:
return Dictionary(
title=Title("MQTT broker statistics"),
help_text=Help(
"Connect to an MQTT broker to get statistics out of your instance. "
"The information is fetched from the <tt>$SYS</tt> topic of the broker. The "
"different brokers implement different topics as they are not standardized, "
"means that not every service available with every broker. "
"In multi-tentant, enterprise level cluster this agent may not be useful or "
"probably only when directly connecting to single nodes, because the "
"<tt>$SYS</tt> topic is node-specific."
),
elements={
"username": DictElement(
required=False,
parameter_form=String(
title=Title("Username"),
help_text=Help("The username used for broker authentication."),
field_size=FieldSize.MEDIUM,
custom_validate=(validators.LengthInRange(min_value=1),),
),
),
"password": DictElement(
required=False,
parameter_form=Password(
title=Title("Password of the user"),
custom_validate=(validators.LengthInRange(min_value=1),),
migrate=migrate_to_password,
),
),
"address": DictElement(
required=False,
parameter_form=String(
title=Title("Custom address"),
help_text=Help(
"When set, this address is used for connecting to the MQTT "
"broker. If not set, the special agent will use the primary "
"address of the host to connect to the MQTT broker."
),
field_size=FieldSize.MEDIUM,
custom_validate=(
validators.LengthInRange(min_value=1),
_validate_hostname,
),
),
),
"port": DictElement(
required=False,
parameter_form=Integer(
title=Title("Port"),
prefill=DefaultValue(1883),
help_text=Help("The port that is used for the api call."),
custom_validate=(validators.NetworkPort(),),
),
),
"client_id": DictElement(
required=False,
parameter_form=String(
title=Title("Client ID"),
help_text=Help(
"Unique client ID used for the broker. Will be randomly "
"generated when not set."
),
field_size=FieldSize.MEDIUM,
custom_validate=(validators.LengthInRange(min_value=1),),
),
),
"protocol": DictElement(
required=False,
parameter_form=SingleChoice(
title=Title("Protocol"),
elements=[
SingleChoiceElement(name="MQTTv31", title=Title("MQTTv31")),
SingleChoiceElement(name="MQTTv311", title=Title("MQTTv311")),
SingleChoiceElement(name="MQTTv5", title=Title("MQTTv5")),
],
prefill=DefaultValue("MQTTv311"),
),
),
"instance_id": DictElement(
required=False,
parameter_form=String(
title=Title("Instance ID"),
help_text=Help(
"Unique ID used to identify the instance on the host within Checkmk."
),
field_size=FieldSize.MEDIUM,
custom_validate=(validators.LengthInRange(min_value=1),),
prefill=DefaultValue("broker"),
),
),
},
)


def _validate_hostname(value: str) -> None:
try:
HostAddress(value)
except ValueError as exception:
raise validators.ValidationError(
message=Message(
"Please enter a valid host name or IPv4 address. "
"Only letters, digits, dash, underscore and dot are allowed."
)
) from exception


def _migrate_instance_and_client_id(params: object) -> dict[str, object]:
match params:
case {"client-id": client_value, **rest}:
return {
"client_id": client_value,
**{str(k): v for k, v in rest.items()},
}
case {"instance-id": instance_value, **rest}:
return {
"instance_id": instance_value,
**{str(k): v for k, v in rest.items()},
}
case {"instance-id": instance_value, "client-id": client_value, **rest}:
return {
"instance_id": instance_value,
"client_id": client_value,
**{str(k): v for k, v in rest.items()},
}
case dict():
return {**params}
raise ValueError(f"Invalid parameters: {params!r}")


rule_spec_special_agent_mqtt = SpecialAgent(
name="mqtt",
title=Title("MQTT broker statistics"),
topic=Topic.APPLICATIONS,
parameter_form=parameter_form,
)
43 changes: 43 additions & 0 deletions cmk/plugins/mqtt/server_side_calls/special_agent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#!/usr/bin/env python3
# Copyright (C) 2024 Checkmk GmbH - License: GNU General Public License v2
# This file is part of Checkmk (https://checkmk.com). It is subject to the terms and
# conditions defined in the file COPYING, which is part of this source code package.


from collections.abc import Iterable

from pydantic import BaseModel

from cmk.server_side_calls.v1 import HostConfig, SpecialAgentCommand, SpecialAgentConfig
from cmk.server_side_calls.v1._utils import Secret


class Params(BaseModel):
username: str | None = None
password: Secret | None = None
address: str | None = None
port: int | None = None
client_id: str | None = None
protocol: str | None = None
instance_id: str | None = None


def commands_function(params: Params, host_config: HostConfig) -> Iterable[SpecialAgentCommand]:
command_arguments: list[str | Secret] = []

command_arguments += ["--client-id", params.client_id] if params.client_id else []
command_arguments += ["--password", params.password.unsafe()] if params.password else []
command_arguments += ["--port", f"{params.port}"] if params.port else []
command_arguments += ["--protocol", params.protocol] if params.protocol else []
command_arguments += ["--username", params.username] if params.username else []

command_arguments += [params.address or host_config.primary_ip_config.address]

yield SpecialAgentCommand(command_arguments=command_arguments)


special_agent_mqtt = SpecialAgentConfig(
name="mqtt",
parameter_parser=Params.model_validate,
commands_function=commands_function,
)
1 change: 1 addition & 0 deletions cmk/utils/password_store/hack.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
"vsphere": True,
"jolokia": True,
"random": False, # needs no secret
"mqtt": True,
}


Expand Down
Loading

0 comments on commit c0ceffb

Please sign in to comment.