initial upload of version 2.1.0 which uses the new plugin API

This commit is contained in:
2025-04-05 11:47:59 +02:00
parent 358f84307c
commit cc2aaee908
34 changed files with 1204 additions and 1238 deletions

View File

@@ -0,0 +1,219 @@
#!/usr/bin/env python3
# pylint: disable=too-many-locals, line-too-long, too-many-statements
"""Mailcow check for domains"""
# import necessary elements from API version 2
from cmk.agent_based.v2 import (
AgentSection,
CheckPlugin,
Service,
Result,
State,
Metric,
render,
)
def get_state_upper(
levels: tuple[int | float, int | float], value: int | float
) -> State:
"""returns OK/WARN/CRIT depending on the given parameters"""
warn, crit = levels
if value >= crit:
return State.CRIT
if value >= warn:
return State.WARN
return State.OK
def parse_mailcow_domains(string_table):
"""the parse function"""
parsed_data = {}
# convert the raw output of the agent section to an meaningful structure
# do type conversions and so on
for line in string_table:
domainname = line[0]
value_active = int(line[1])
if value_active == 1:
active = "yes"
else:
active = "no"
# calculate creation and last modification date in human readable format
create_time_value = line[2]
if create_time_value == "None":
create_time_data = "Not available"
else:
create_time_data = create_time_value
modify_time_value = line[3]
if modify_time_value == "None":
modify_time_data = "Never"
else:
modify_time_data = modify_time_value
# calculate percentage of used mailboxes
max_number_of_mailboxes = int(line[4])
number_of_mailboxes = int(line[5])
percent_used_mailboxes = number_of_mailboxes * 100 / max_number_of_mailboxes
# calculate percentage of used aliases
max_number_of_aliases = int(line[6])
number_of_aliases = int(line[7])
percent_used_aliases = number_of_aliases * 100 / max_number_of_aliases
# number of messages within domain
total_number_of_messages = int(line[8])
# calculate storage used for all messages in domain
total_number_of_bytes_used = int(line[9])
quota = int(line[10])
percent_storage_used_for_messages = total_number_of_bytes_used * 100 / quota
# store all (calculated) data
parsed_data[f"{domainname}"] = [
active,
create_time_data,
modify_time_data,
max_number_of_mailboxes,
number_of_mailboxes,
percent_used_mailboxes,
max_number_of_aliases,
number_of_aliases,
percent_used_aliases,
total_number_of_messages,
total_number_of_bytes_used,
quota,
percent_storage_used_for_messages,
]
return parsed_data
def discover_mailcow_domains(section):
"""the discover function"""
# since we have a service with item here we must create one service per item
for key in section:
yield Service(item=key)
def check_mailcow_domains(item, params, section):
"""the check function"""
domain = section.get(item)
if not domain:
# if a previously found domain does not exist anymore, create a meaningful result
yield Result(
state=State.UNKNOWN,
summary="Domain not found anymore, maybe it was deleted?",
)
return
# get all infos regarding the domain
active = domain[0]
create_time = domain[1]
modify_time = domain[2]
max_number_of_mailboxes = domain[3]
number_of_mailboxes = domain[4]
percent_used_mailboxes = domain[5]
max_number_of_aliases = domain[6]
number_of_aliases = domain[7]
percent_used_aliases = domain[8]
total_number_of_messages = domain[9]
total_number_of_bytes_used = domain[10]
quota = domain[11]
percent_storage_used_for_messages = domain[12]
# create (main) service for used storage (domain quota)
_type, levels = params["levels_mailcow_domains_quota_used"]
state_quota = get_state_upper(levels, percent_storage_used_for_messages)
# create graph for used quota
yield Metric(
"mailcow_domains_used_quota", percent_storage_used_for_messages, levels=levels
)
summary_quota = (
f"Storage quota used is {render.percent(percent_storage_used_for_messages)}"
)
details_quota = f"Storage quota: {render.bytes(total_number_of_bytes_used)} of {render.bytes(quota)} used"
# create service
yield Result(state=state_quota, summary=summary_quota, details=details_quota)
# create some additional services and information only in service details
notice = f"Active: {active}"
yield Result(state=State.OK, notice=notice)
notice = f"Creation date: {create_time}"
yield Result(state=State.OK, notice=notice)
notice = f"Last modified: {modify_time}"
yield Result(state=State.OK, notice=notice)
# create service for number of configured mailboxes (percent)
_type, levels = params["levels_mailcow_domains_mailboxes_used"]
state_mailboxes = get_state_upper(levels, percent_used_mailboxes)
yield Metric("mailcow_domains_mailboxes", percent_used_mailboxes, levels=levels)
notice = f"Used mailboxes: {render.percent(percent_used_mailboxes)}, {number_of_mailboxes} of {max_number_of_mailboxes} in use"
yield Result(state=state_mailboxes, notice=notice)
# create service for number of configured aliases (percent)
_type, levels = params["levels_mailcow_domains_aliases_used"]
state_aliases = get_state_upper(levels, percent_used_aliases)
yield Metric("mailcow_domains_aliases", percent_used_aliases, levels=levels)
notice = f"Used aliases: {render.percent(percent_used_aliases)}, {number_of_aliases} of {max_number_of_aliases} in use"
yield Result(state=state_aliases, notice=notice)
# create service for number of messages
_type, levels = params["levels_mailcow_domains_num_messages"]
state_messages = get_state_upper(levels, total_number_of_messages)
yield Metric("mailcow_domains_messages", total_number_of_messages, levels=levels)
notice = f"Number of messages: {total_number_of_messages}"
yield Result(state=state_messages, notice=notice)
# create service for number of configured aliases (absolute)
_type, levels = params["levels_mailcow_domains_num_aliases"]
state_aliases = get_state_upper(levels, number_of_aliases)
yield Metric("mailcow_domains_configured_aliases", number_of_aliases, levels=levels)
notice = (
f"Number of aliases: {number_of_aliases}, max {max_number_of_aliases} allowed"
)
yield Result(state=state_aliases, notice=notice)
# create service for number of configured mailboxes (absolute)
_type, levels = params["levels_mailcow_domains_num_mailboxes"]
state_mailboxes = get_state_upper(levels, number_of_mailboxes)
yield Metric(
"mailcow_domains_configured_mailboxes", number_of_mailboxes, levels=levels
)
notice = f"Number of mailboxes: {number_of_mailboxes}, max {max_number_of_mailboxes} allowed"
yield Result(state=state_mailboxes, notice=notice)
# create the new agent section, must begin with "agent_section_"
# and must be an instance of "AgentSection"
agent_section_mailcow_domains = AgentSection(
# "name" must exactly match the section name within the agent output
name="mailcow_domains",
# define the parse function, name is arbitrary, a good choice is to choose
# "parse_" as prefix and append the section name
parse_function=parse_mailcow_domains,
)
# create the new check plugin, must begin with "check_plugin_"
# and must be an instance of "CheckPlugin"
check_plugin_mailcow_domains = CheckPlugin(
# "name" should be the same as the corresponding section within the agent output
name="mailcow_domains",
# this is a service with item, so you have to include a place holder for the item id
service_name="Mailcow domain %s",
# define the discovery function, name is arbitrary, a good choice is to choose
# "discover_" as prefix and append the section name
discovery_function=discover_mailcow_domains,
# define the check function, name is arbitrary, a good choice is to choose
# "check_" as prefix and append the section name
check_function=check_mailcow_domains,
# define the default parameters
check_default_parameters={
"levels_mailcow_domains_quota_used": ("fixed", (65.0, 85.0)),
"levels_mailcow_domains_mailboxes_used": ("fixed", (65.0, 85.0)),
"levels_mailcow_domains_aliases_used": ("fixed", (65.0, 85.0)),
"levels_mailcow_domains_num_messages": ("fixed", (10_000, 25_000)),
"levels_mailcow_domains_num_aliases": ("fixed", (100, 250)),
"levels_mailcow_domains_num_mailboxes": ("fixed", (100, 250)),
},
# connect to the ruleset where parameters can be defined
# must match the name of the ruleset exactly
check_ruleset_name="mailcow_domains",
)

View File

@@ -0,0 +1,155 @@
#!/usr/bin/env python3
# pylint: disable=line-too-long, simplifiable-if-statement, missing-module-docstring, too-many-locals
# import necessary elements from API version 2
from cmk.agent_based.v2 import (
AgentSection,
CheckPlugin,
Service,
Result,
State,
Metric,
)
def get_state_upper(
levels: tuple[int | float, int | float], value: int | float
) -> State:
"""returns OK/WARN/CRIT depending on the given parameters"""
warn, crit = levels
if value >= crit:
return State.CRIT
if value >= warn:
return State.WARN
return State.OK
def parse_mailcow_info(string_table) -> dict:
"""the parse function"""
parsed_data = {}
# we only expect one line with 7 entries
line = string_table[0]
version = line[0]
num_domains = int(line[1])
num_mailboxes = int(line[2])
num_global_messages = int(line[3])
git_version = line[4]
update_available = line[5]
if update_available == "True":
update_available = True
else:
update_available = False
check_version_enabled = line[6]
if check_version_enabled == "True":
check_version_enabled = True
else:
check_version_enabled = False
parsed_data["version"] = version
parsed_data["num_domains"] = num_domains
parsed_data["num_mailboxes"] = num_mailboxes
parsed_data["num_global_messages"] = num_global_messages
parsed_data["git_version"] = git_version
parsed_data["update_available"] = update_available
parsed_data["check_version_enabled"] = check_version_enabled
return parsed_data
def discover_mailcow_info(section):
"""the discover function"""
yield Service()
def check_mailcow_info(params, section):
"""the check function"""
# get thresholds
_type, levels_num_domains = params["levels_num_domains"]
_type, levels_num_mailboxes = params["levels_num_mailboxes"]
_type, levels_num_global_messages = params["levels_num_global_messages"]
# get all section data
version: str = section["version"]
git_version: str = section["git_version"]
check_version_enabled: bool = section["check_version_enabled"]
update_available: bool = section["update_available"]
num_domains: int = section["num_domains"]
num_mailboxes: int = section["num_mailboxes"]
num_global_messages: int = section["num_global_messages"]
# create graphs for number of domains, mailboxes and messages
yield Metric(name="mc_num_domains", value=num_domains, levels=levels_num_domains)
yield Metric(
name="mc_num_mailboxes", value=num_mailboxes, levels=levels_num_mailboxes
)
yield Metric(
name="mc_num_global_messages",
value=num_global_messages,
levels=levels_num_global_messages,
)
# create overall result
if check_version_enabled:
if update_available:
summary = f"Update available: Running version is {version}, Github version is: {git_version}"
state = State.WARN
else:
summary = f"No update available: Running version is {version}, Github version is: {git_version}"
state = State.OK
else:
summary = f"Version is {version}, Update check is disabled"
state = State.OK
details = f"Mailcow version: {version}\nNumber of domains: {num_domains}\nNumber of mailboxes: {num_mailboxes}\nNumber of messages: {num_global_messages}"
yield Result(state=state, summary=summary, details=details)
# Create result for number of domains
warn, crit = levels_num_domains
state = get_state_upper((warn, crit), num_domains)
notice = f"Number of domains: {num_domains}"
if state != State.OK:
yield Result(state=state, notice=notice)
# Create result for number of mailboxes
warn, crit = levels_num_mailboxes
state = get_state_upper((warn, crit), num_mailboxes)
notice = f"Number of mailboxes: {num_mailboxes}"
if state != State.OK:
yield Result(state=state, notice=notice)
# Create result for number of global messages
warn, crit = levels_num_global_messages
state = get_state_upper((warn, crit), num_global_messages)
notice = f"Number of messages: {num_global_messages}"
if state != State.OK:
yield Result(state=state, notice=notice)
# create the new agent section, must begin with "agent_section_"
# and must be an instance of "AgentSection"
agent_section_mailcow_info = AgentSection(
# "name" must exactly match the section name within the agent output
name="mailcow_info",
# define the parse function, name is arbitrary, a good choice is to choose
# "parse_" as prefix and append the section name
parse_function=parse_mailcow_info,
)
# create the new check plugin, must begin with "check_plugin_"
# and must be an instance of "CheckPlugin"
check_plugin_mailcow_info = CheckPlugin(
# "name" should be the same as the corresponding section within the agent output
name="mailcow_info",
service_name="Mailcow info",
# define the discovery function, name is arbitrary, a good choice is to choose
# "discover_" as prefix and append the section name
discovery_function=discover_mailcow_info,
# define the check function, name is arbitrary, a good choice is to choose
# "check_" as prefix and append the section name
check_function=check_mailcow_info,
# define the default parameters
check_default_parameters={
"levels_num_domains": ("fixed", (100, 200)),
"levels_num_mailboxes": ("fixed", (500, 1000)),
"levels_num_global_messages": ("fixed", (100_000, 250_000)),
},
# connect to the ruleset where parameters can be defined
# must match the name of the ruleset exactly
check_ruleset_name="mailcow_info",
)

View File

@@ -0,0 +1,211 @@
#!/usr/bin/env python3
# pylint: disable=too-many-locals, line-too-long, too-many-statements, too-many-branches
"""Mailcow check for mailboxes"""
import time
# import necessary elements from API version 2
from cmk.agent_based.v2 import (
AgentSection,
CheckPlugin,
Service,
Result,
State,
Metric,
render,
)
def get_state_upper(
levels: tuple[int | float, int | float], value: int | float
) -> State:
"""returns OK/WARN/CRIT depending on the given parameters"""
warn, crit = levels
if value >= crit:
return State.CRIT
if value >= warn:
return State.WARN
return State.OK
def parse_mailcow_mailboxes(string_table):
"""the parse function"""
parsed_data = {}
# convert the raw output of the agent section to an meaningful structure
# do type conversions and so on
for line in string_table:
mailboxname = line[0]
value_active = int(line[1])
if value_active == 1:
active = "yes"
else:
active = "no"
# calculate creation and last modification date in human readable format
create_time_value = line[2]
if create_time_value == "None":
create_time_data = "Not available"
else:
create_time_data = create_time_value
modify_time_value = line[3]
if modify_time_value == "None":
modify_time_data = "Never"
else:
modify_time_data = modify_time_value
# get display name
display_name = line[4]
# number of messages within mailbox
number_of_messages = int(line[5])
# calculate storage used for all messages in mailbox
quota = int(line[7])
total_number_of_bytes_used = int(line[8])
if quota == 0:
# quota is not set, if this is the case, line[6] contains no numeric value, but the char "-"
# so set all usage counters to zero
percent_in_use = 0
percent_storage_used_for_messages = 0
else:
# percent in use, rounded to full percent (calculated by Mailcow)
percent_in_use = int(line[6])
# let's calculate our own value
percent_storage_used_for_messages = total_number_of_bytes_used * 100 / quota
# get time of last login for IMAP/POP3/SMTP (seconds since epoch)
last_imap_login = int(line[9])
last_pop3_login = int(line[10])
last_smtp_login = int(line[11])
# transfer these times into a human friendly format
if last_imap_login == 0:
last_imap_login_data = "Never"
else:
curr_time = int(time.time())
diff_time = curr_time - last_imap_login
last_imap_login_data = render.timespan(diff_time)
if last_pop3_login == 0:
last_pop3_login_data = "Never"
else:
curr_time = int(time.time())
diff_time = curr_time - last_pop3_login
last_pop3_login_data = render.timespan(diff_time)
if last_smtp_login == 0:
last_smtp_login_data = "Never"
else:
curr_time = int(time.time())
diff_time = curr_time - last_smtp_login
last_smtp_login_data = render.timespan(diff_time)
# store all (calculated) data
parsed_data[f"{mailboxname}"] = [
active,
create_time_data,
modify_time_data,
display_name,
number_of_messages,
percent_in_use,
quota,
total_number_of_bytes_used,
percent_storage_used_for_messages,
last_imap_login_data,
last_pop3_login_data,
last_smtp_login_data,
]
return parsed_data
def discover_mailcow_mailboxes(section):
"""the discover function"""
# since we have a service with item here we must create one service per item
for key in section:
yield Service(item=key)
def check_mailcow_mailboxes(item, params, section):
"""the check function"""
mailbox = section.get(item)
if not mailbox:
# if a previously found domain does not exist anymore, create a meaningful result
yield Result(
state=State.UNKNOWN,
summary="Mailbox not found anymore, maybe it was deleted?",
)
return
# get all infos regarding the mailbox
active = mailbox[0]
create_time = mailbox[1]
modify_time = mailbox[2]
display_name = mailbox[3]
number_of_messages = mailbox[4]
_percent_in_use = mailbox[5]
quota = mailbox[6]
total_number_of_bytes_used = mailbox[7]
percent_storage_used_for_messages = mailbox[8]
last_imap_login_data = mailbox[9]
last_pop3_login_data = mailbox[10]
last_smtp_login_data = mailbox[11]
# create (main) service for used storage (mailbox quota)
_type, levels = params["levels_mailcow_mailboxes_quota_used"]
state_quota = get_state_upper(levels, percent_storage_used_for_messages)
# create graph for used quota
yield Metric(
"mailcow_mailboxes_used_quota", percent_storage_used_for_messages, levels=levels
)
summary_quota = f"Storage quota for mailbox of '{display_name}' is {render.percent(percent_storage_used_for_messages)}"
details_quota = f"Quota: {render.bytes(total_number_of_bytes_used)} of {render.bytes(quota)} used"
# create service
yield Result(state=state_quota, summary=summary_quota, details=details_quota)
# create some additional services and information only details
notice = f"Active: {active}"
yield Result(state=State.OK, notice=notice)
notice = f"Creation date: {create_time}"
yield Result(state=State.OK, notice=notice)
notice = f"Last modified: {modify_time}"
yield Result(state=State.OK, notice=notice)
notice = f"Last IMAP login: {last_imap_login_data} ago"
yield Result(state=State.OK, notice=notice)
notice = f"Last POP3 login: {last_pop3_login_data} ago"
yield Result(state=State.OK, notice=notice)
notice = f"Last SMTP login: {last_smtp_login_data} ago"
yield Result(state=State.OK, notice=notice)
# create service for number of messages
_type, levels = params["levels_mailcow_mailboxes_num_messages"]
state_messages = get_state_upper(levels, number_of_messages)
yield Metric("mailcow_mailboxes_messages", number_of_messages, levels=levels)
notice = f"Number of messages: {number_of_messages}"
yield Result(state=state_messages, notice=notice)
# create the new agent section, must begin with "agent_section_"
# and must be an instance of "AgentSection"
agent_section_mailcow_mailboxes = AgentSection(
# "name" must exactly match the section name within the agent output
name="mailcow_mailboxes",
# define the parse function, name is arbitrary, a good choice is to choose
# "parse_" as prefix and append the section name
parse_function=parse_mailcow_mailboxes,
)
# create the new check plugin, must begin with "check_plugin_"
# and must be an instance of "CheckPlugin"
check_plugin_mailcow_mailboxes = CheckPlugin(
# "name" should be the same as the corresponding section within the agent output
name="mailcow_mailboxes",
# this is a service with item, so you have to include a place holder for the item id
service_name="Mailcow mailbox %s",
# define the discovery function, name is arbitrary, a good choice is to choose
# "discover_" as prefix and append the section name
discovery_function=discover_mailcow_mailboxes,
# define the check function, name is arbitrary, a good choice is to choose
# "check_" as prefix and append the section name
check_function=check_mailcow_mailboxes,
# define the default parameters
check_default_parameters={
"levels_mailcow_mailboxes_quota_used": ("fixed", (65.0, 85.0)),
"levels_mailcow_mailboxes_num_messages": ("fixed", (1000, 2500)),
},
# connect to the ruleset where parameters can be defined
# must match the name of the ruleset exactly
check_ruleset_name="mailcow_mailboxes",
)

View File

@@ -0,0 +1,20 @@
title: Mailcow: Mailboxes, Aliases and Storage used by Email Domain
agents: linux
catalog: unsorted
license: GPL
distribution: check_mk
description:
Tested with Mailcow versions 2022-07a and higher (use at your own risk with lower versions).
Tested only with fully dockerized Mailcow instances.
You have to provide at least the hostname/IP of your Mailcow server and an API key.
Got to configuration settings and create a new API key (read-only access is sufficient).
Allow API access to at least your CheckMK server IP address.
Shows several information about a Mailcow email domain, e.g. number of configured mailboxes/aliases, used space for all messages etc.
The check will raise WARN/CRIT if quota usage is above the configurable levels.
The check will raise WARN/CRIT if number of configured mailboxes is above the configurable levels.
The check will raise WARN/CRIT if number of configured aliases is above the configurable levels.
The check will raise WARN/CRIT if number of total messages is above the configurable levels.
item:
domainname
inventory:
one service is created for each email domain

View File

@@ -0,0 +1,18 @@
title: Mailcow: Various information
agents: linux
catalog: unsorted
license: GPL
distribution: check_mk
description:
Tested with Mailcow versions 2022-07a and higher (use at your own risk with lower versions).
Tested only with fully dockerized Mailcow instances.
You have to provide at least the hostname/IP of your Mailcow server and an API key.
Got to configuration settings and create a new API key (read-only access is sufficient).
Allow API access to at least your CheckMK server IP address.
Shows several information about a Mailcow instance, e.g. number of domains/mailboxes/messages.
The check will raise WARN if an update is available (and if this check is enabled)
The check will raise WARN/CRIT if the number of domains is above the configurable levels.
The check will raise WARN/CRIT if the number of mailboxes is above the configurable levels.
The check will raise WARN/CRIT if the number of messages is above the configurable levels.
inventory:
one service is created (with several details)

View File

@@ -0,0 +1,18 @@
title: Mailcow: Usage per Mailbox, Quota and Number of Messages
agents: linux
catalog: unsorted
license: GPL
distribution: check_mk
description:
Tested with Mailcow versions 2022-07a and higher (use at your own risk with lower versions).
Tested only with fully dockerized Mailcow instances.
You have to provide at least the hostname/IP of your Mailcow server and an API key.
Got to configuration settings and create a new API key (read-only access is sufficient).
Allow API access to at least your CheckMK server IP address.
Shows several information about a Mailcow mailbox, e.g. number of messages and quota.
The check will raise WARN/CRIT if quota usage is above the configurable levels.
The check will raise WARN/CRIT if number of messages is above the configurable levels.
item:
mailboxname
inventory:
one service is created for each mailbox

View File

@@ -0,0 +1,112 @@
#!/usr/bin/env python3
# pylint: disable=unused-import
"""graphing and metrics definitions"""
from cmk.graphing.v1 import Title
from cmk.graphing.v1.graphs import Graph, MinimalRange
from cmk.graphing.v1.metrics import Color, DecimalNotation, Metric, Unit
from cmk.graphing.v1.perfometers import Closed, FocusRange, Perfometer
## Metrics
# metrics must begin with "metric_" and be an instance of "Metric"
# Global metrics
metric_mc_num_domains = Metric(
# "name" must be exactly the "metric_name" within the check function
name="mc_num_domains",
title=Title("Number of email domains"),
unit=Unit(DecimalNotation("")),
color=Color.DARK_ORANGE,
)
metric_mc_num_global_messages = Metric(
# "name" must be exactly the "metric_name" within the check function
name="mc_num_global_messages",
title=Title("Global number of messages"),
unit=Unit(DecimalNotation("")),
color=Color.DARK_CYAN,
)
metric_mc_num_mailboxes = Metric(
# "name" must be exactly the "metric_name" within the check function
name="mc_num_mailboxes",
title=Title("Number of mailboxes"),
unit=Unit(DecimalNotation("")),
color=Color.DARK_GREEN,
)
# Mailbox Metrics
metric_mc_mailboxes_used_quota = Metric(
# "name" must be exactly the "metric_name" within the check function
name="mailcow_mailboxes_used_quota",
title=Title("Percentage of mailbox quota used"),
unit=Unit(DecimalNotation("%")),
color=Color.DARK_ORANGE,
)
metric_mc_mailboxes_messages = Metric(
# "name" must be exactly the "metric_name" within the check function
name="mailcow_mailboxes_messages",
title=Title("Number of messages in mailbox"),
unit=Unit(DecimalNotation("")),
color=Color.DARK_RED,
)
# Domain metrics
metric_mc_domains_used_quota = Metric(
# "name" must be exactly the "metric_name" within the check function
name="mailcow_domains_used_quota",
title=Title("Percentage of domain quota used"),
unit=Unit(DecimalNotation("%")),
color=Color.DARK_ORANGE,
)
metric_mc_domains_mailboxes = Metric(
# "name" must be exactly the "metric_name" within the check function
name="mailcow_domains_mailboxes",
title=Title("Percentage of maximum mailboxes used"),
unit=Unit(DecimalNotation("%")),
color=Color.DARK_GREEN,
)
metric_mc_domains_aliases = Metric(
# "name" must be exactly the "metric_name" within the check function
name="mailcow_domains_aliases",
title=Title("Percentage of maximum aliases used"),
unit=Unit(DecimalNotation("%")),
color=Color.DARK_BLUE,
)
metric_mc_domains_messages = Metric(
# "name" must be exactly the "metric_name" within the check function
name="mailcow_domains_messages",
title=Title("Number of messages"),
unit=Unit(DecimalNotation("")),
color=Color.DARK_RED,
)
metric_mc_domains_configured_aliases = Metric(
# "name" must be exactly the "metric_name" within the check function
name="mailcow_domains_configured_aliases",
title=Title("Number of configured aliases"),
unit=Unit(DecimalNotation("")),
color=Color.DARK_CYAN,
)
metric_mc_domains_configured_mailboxes = Metric(
# "name" must be exactly the "metric_name" within the check function
name="mailcow_domains_configured_mailboxes",
title=Title("Number of configured mailboxes"),
unit=Unit(DecimalNotation("")),
color=Color.DARK_PINK,
)
## Perfometers
# perfometers must begin with "perfometer_" and be an instance of "Perfometer"
perfometer_mc_domains_used_quota = Perfometer(
name="mailcow_domains_used_quota",
focus_range=FocusRange(Closed(0), Closed(100)),
# "segments" must be exactly the name of the metric
segments=["mailcow_domains_used_quota"],
)
perfometer_mc_mailboxes_used_quota = Perfometer(
name="mailcow_mailboxes_used_quota",
focus_range=FocusRange(Closed(0), Closed(100)),
# "segments" must be exactly the name of the metric
segments=["mailcow_mailboxes_used_quota"],
)

447
mailcow/libexec/agent_mailcow Executable file
View File

@@ -0,0 +1,447 @@
#!/usr/bin/env python3
# pylint: disable=line-too-long, too-many-branches, too-many-locals
# pylint: disable=bare-except, pointless-string-statement, consider-using-dict-items
# pylint: disable=too-many-arguments, too-many-statements, simplifiable-if-statement, too-many-positional-arguments
# pylint: disable=possibly-used-before-assignment, used-before-assignment
# pylint: disable=missing-class-docstring, missing-module-docstring, missing-function-docstring
"""CheckMK special agent for Mailcow systems"""
import json
import argparse
import sys
import requests
import urllib3
from requests.structures import CaseInsensitiveDict
def get_args() -> argparse.Namespace:
parser: argparse.ArgumentParser = argparse.ArgumentParser(
description="Mailcow server parameters"
)
parser.add_argument(
"--hostname", required=True, type=str, help="Hostname or IP of mailcow server"
)
parser.add_argument("--apikey", required=True, type=str, help="API key")
parser.add_argument(
"--port",
required=False,
type=int,
help="Port where the server is listening on",
)
parser.add_argument(
"--no-https",
required=False,
default=False,
help="Disable HTTPS",
action="store_true",
)
parser.add_argument(
"--no-cert-check",
required=False,
default=False,
help="Disable certificate checks",
action="store_true",
)
parser.add_argument(
"--check-version",
required=False,
default=False,
help="Enable version check",
action="store_true",
)
args = parser.parse_args()
return args
MC_API_BASE: str = "api/v1/get"
TIMEOUT: int = 30
domain_data: dict = {}
mailbox_data: dict = {}
def get_domain_info(headers: str, verify: bool, base_url: str) -> int:
"""retrieves info about all configured domains"""
url: str = f"{base_url}/domain/all"
response = requests.get(url=url, headers=headers, verify=verify, timeout=TIMEOUT)
if response.status_code == 200:
jsdata = response.text
data = json.loads(jsdata) # returns a list of dictionaries
i = 0
while i < len(data):
# pprint(data[i])
# get domain name and status (active (1) or not (0))
domain_name = data[i].get("domain_name")
active = data[i].get("active")
# get creation and last modification date
created = data[i].get("created")
modified = data[i].get("modified") # returns "None" or date
# get maximum and current number of mailboxes in this domain
max_num_mboxes_for_domain = data[i].get("max_num_mboxes_for_domain")
mboxes_in_domain = data[i].get("mboxes_in_domain")
# get maximum and current number of aliases in this domain
max_num_aliases_for_domain = data[i].get("max_num_aliases_for_domain")
aliases_in_domain = data[i].get("aliases_in_domain")
# get total messages in this domain
msgs_total = data[i].get("msgs_total")
# get total bytes used in this domain
bytes_total = data[i].get("bytes_total")
# get maximum quota for this domain
max_quota_for_domain = data[i].get("max_quota_for_domain")
# store all domain data in global dictionary
dom = {
"active": active,
"created": created,
"modified": modified,
"max_num_mboxes_for_domain": max_num_mboxes_for_domain,
"mboxes_in_domain": mboxes_in_domain,
"max_num_aliases_for_domain": max_num_aliases_for_domain,
"aliases_in_domain": aliases_in_domain,
"msgs_total": msgs_total,
"bytes_total": bytes_total,
"max_quota_for_domain": max_quota_for_domain,
}
domain_data[domain_name] = {}
domain_data[domain_name] = dom
i += 1
# return number of email domains
return i
sys.stderr.write(
f"Request response code is {response.status_code} with URL {url}\n"
)
sys.exit(1)
def get_mailbox_info(headers: str, verify: bool, base_url: str) -> tuple:
"""retrieves info about all configured mailboxes"""
url: str = f"{base_url}/mailbox/all"
response = requests.get(url=url, headers=headers, verify=verify, timeout=TIMEOUT)
if response.status_code == 200:
jsdata = response.text
data = json.loads(jsdata) # returns a list of dictionaries
i: int = 0
global_num_messages: int = 0
while i < len(data):
# get status of mailbox (0-->inactive or 1-->active)
active = data[i].get("active")
# get username of mailbox
username = data[i].get("username")
# get friendly name of user
name = data[i].get("name")
# get number of messages in mailbox
num_messages = data[i].get("messages")
# get quota used in percent (rounded to full percent)
percent_in_use = data[i].get("percent_in_use")
# get quota and quota used in bytes
quota = data[i].get("quota")
quota_used = data[i].get("quota_used")
# get creation and last modification date
created = data[i].get("created")
modified = data[i].get("modified")
# get number of messages
messages = data[i].get("messages")
# get last login dates
last_imap_login = data[i].get("last_imap_login")
last_pop3_login = data[i].get("last_pop3_login")
last_smtp_login = data[i].get("last_smtp_login")
mailbox = {
"active": active,
"created": created,
"modified": modified,
"name": name,
"num_messages": num_messages,
"percent_in_use": percent_in_use,
"quota": quota,
"quota_used": quota_used,
"messages": messages,
"last_imap_login": last_imap_login,
"last_pop3_login": last_pop3_login,
"last_smtp_login": last_smtp_login,
}
mailbox_data[username] = {}
mailbox_data[username] = mailbox
i += 1
global_num_messages += num_messages
# return number of mailboxes and global number of messages
return i, global_num_messages
sys.stderr.write(
f"Request response code is {response.status_code} with URL {url}\n"
)
sys.exit(1)
def get_git_version() -> str:
"""gets the actual version of Mailcow from Github"""
url: str = "https://api.github.com/repos/mailcow/mailcow-dockerized/releases/latest"
git_version: str = ""
response = requests.get(url=url, timeout=TIMEOUT)
if response.status_code == 200:
jsdata = response.text
data = json.loads(jsdata) # returns a dictionary
git_version = data["tag_name"]
else:
sys.stderr.write(
f"Request response code is {response.status_code} with URL {url}\n"
)
sys.exit(1)
return git_version
def compare_versions(mc_ver: str, git_ver: str) -> bool:
"""compares the actual Github version with the version of the running Mailcow system"""
update_available: bool = False
try:
mc_year, mc_month = mc_ver.split("-")
git_year, git_month = git_ver.split("-")
# print(mc_year, mc_month, git_year, git_month)
mc_year_int = int(mc_year)
git_year_int = int(git_year)
if git_year_int > mc_year_int:
update_available = True
else:
len_mc_month = len(mc_month)
len_git_month = len(git_month)
if len_mc_month == 2:
mc_month_int = int(mc_month)
elif len_mc_month == 3:
mc_month_int = int(mc_month[0:2])
mc_month_ver = mc_month[-1]
else:
pass
if len_git_month == 2:
git_month_int = int(git_month)
elif len_git_month == 3:
git_month_int = int(git_month[0:2])
git_month_ver = git_month[-1]
else:
pass
if git_month_int > mc_month_int:
update_available = True
elif len_mc_month == 2 and len_git_month == 3:
update_available = True
elif git_month_ver > mc_month_ver:
update_available = True
except:
# TBD
pass
return update_available
def get_mailcow_info(
headers: str, verify: bool, base_url: str, check_version: bool
) -> dict:
"""retrieves several global information about the mailcow system"""
info_data = {}
url = f"{base_url}/status/version"
response = requests.get(url=url, headers=headers, verify=verify, timeout=TIMEOUT)
if response.status_code == 200:
jsdata = response.text
data = json.loads(jsdata) # returns a dictionary
# pprint(data)
# get Mailcow version
mc_version = data["version"]
# if enabled, check this version against the official Mailcow repo on Github
if check_version:
git_version = get_git_version()
update_available = compare_versions(mc_version, git_version)
info_data["git_version"] = git_version
info_data["update_available"] = update_available
else:
info_data["git_version"] = "Version check disabled"
info_data["update_available"] = False
info_data["mc_version"] = mc_version
info_data["check_version_enabled"] = check_version
return info_data
sys.stderr.write(
f"Request response code is {response.status_code} with URL {url}\n"
)
sys.exit(1)
"""
Output is as follows:
0 mailbox name email address used for login
1 active 1 --> active, 0 --> not active
2 creation date "None" if ???
3 last modified date "None" if never modified
4 name display name
5 number of messages
6 percent in use quota used, rounded to full percents
7 quota max quota in bytes
8 quota used quota used in bytes
9 last imap login seconds since epoch, 0 if never logged in
10 last pop3 login seconds since epoch, 0 if never logged in
11 last smtp login seconds since epoch, 0 if never logged in
Example:
user1@dom1.de;1;2022-04-29 14:29:34;2022-04-29 14:29:34;Sarah;2433;2;21474836480;495481374;1692520168;0;1692281537
user2@dom1.de;1;2022-04-29 14:38:33;2022-04-29 14:38:33;Tom;271;0;21474836480;25895752;1657394782;1692519758;1681065713
user1@dom2.de;1;2022-04-30 09:55:37;2022-04-30 09:55:37;Melissa;53460;33;19964887040;6677677548;1692520066;0;1692510822
"""
def do_cmk_output_mailboxes() -> None:
"""prints out agent section for mailboxes"""
print("<<<mailcow_mailboxes:sep(59)>>>")
for mb in mailbox_data:
active = mailbox_data[mb]["active"]
created = mailbox_data[mb]["created"]
modified = mailbox_data[mb]["modified"]
name = mailbox_data[mb]["name"]
# strip semicolons, if present, since we use it as delimiter
name = name.replace(";", "")
num_messages = mailbox_data[mb]["num_messages"]
percent_in_use = mailbox_data[mb]["percent_in_use"]
quota = mailbox_data[mb]["quota"]
quota_used = mailbox_data[mb]["quota_used"]
last_imap_login = mailbox_data[mb]["last_imap_login"]
last_pop3_login = mailbox_data[mb]["last_pop3_login"]
last_smtp_login = mailbox_data[mb]["last_smtp_login"]
print(
f"{mb};{active};{created};{modified};{name};{num_messages};{percent_in_use};{quota};{quota_used};{last_imap_login};{last_pop3_login};{last_smtp_login}"
)
def do_cmk_output_mailcow(
version: str,
num_domains: int,
num_mailboxes: int,
num_global_messages: int,
git_version: str,
update_available: bool,
check_version_enabled: bool,
) -> None:
"""prints out agent section for global mailcow info"""
print("<<<mailcow_info:sep(59)>>>")
# strip semicolons, if present, since we use it as delimiter
version = version.replace(";", "")
print(
f"{version};{num_domains};{num_mailboxes};{num_global_messages};{git_version};{update_available};{check_version_enabled}"
)
"""
Output is as follows:
0 domain name
1 active 1 --> active, 0 --> not active
2 creation date "None" if ???
3 last modified date "None" if never modified
4 max number of mailboxes
5 number of mailboxes
6 max number of aliases
7 number of aliases
8 total number of messages
9 total number of bytes used in bytes
10 max quota in bytes
Example:
dom1.de;1;2022-04-23 22:54:57;None;10;0;400;6;0;0;10737418240
dom2.de;1;2022-04-29 13:38:42;2023-08-19 17:21:04;10;0;400;2;0;0;10737418240
dom3.de;1;2022-04-29 13:36:08;2022-04-29 21:26:19;10;1;100;3;28132;12852485367;21474836480
"""
def do_cmk_output_domains() -> None:
"""print out agent section for domains"""
print("<<<mailcow_domains:sep(59)>>>")
for dom in domain_data:
active = domain_data[dom]["active"]
created = domain_data[dom]["created"]
modified = domain_data[dom]["modified"]
max_num_mboxes_for_domain = domain_data[dom]["max_num_mboxes_for_domain"]
mboxes_in_domain = domain_data[dom]["mboxes_in_domain"]
max_num_aliases_for_domain = domain_data[dom]["max_num_aliases_for_domain"]
aliases_in_domain = domain_data[dom]["aliases_in_domain"]
msgs_total = domain_data[dom]["msgs_total"]
bytes_total = domain_data[dom]["bytes_total"]
max_quota_for_domain = domain_data[dom]["max_quota_for_domain"]
print(
f"{dom};{active};{created};{modified};{max_num_mboxes_for_domain};{mboxes_in_domain};{max_num_aliases_for_domain};{aliases_in_domain};{msgs_total};{bytes_total};{max_quota_for_domain}"
)
def main():
"""main function"""
# get and check parameters
params: argparse.Namespace = get_args()
# do some parameter checks
if params.hostname is None:
sys.stderr.write("No hostname given.\n")
sys.exit(1)
else:
hostname = params.hostname
if params.apikey is None:
sys.stderr.write("No API key given.\n")
sys.exit(1)
else:
apikey = params.apikey
if params.no_cert_check:
# disable certificate warnings
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
verify = False
else:
verify = True
if params.check_version:
check_version = True
else:
check_version = False
if params.port is None:
if params.no_https:
protocol = "http"
port = "80"
else:
protocol = "https"
port = "443"
else:
if params.no_https:
protocol = "http"
else:
protocol = "https"
port = params.port
if protocol == "http" and port == "443":
sys.stderr.write("Combining HTTP with port 443 is not supported.\n")
sys.exit(1)
if protocol == "https" and port == "80":
sys.stderr.write("Combining HTTPS with port 80 is not supported.\n")
sys.exit(1)
headers = CaseInsensitiveDict()
headers["Accept"] = "application/json"
headers["X-API-Key"] = apikey
# now "hostname" contains the FQDN of the host running Mailcow
# now "protocol" is http or https
# now "port" contains the port number to use
# now "verify" signals whether certificate checking will be done (True) or not (False)
# now "check_version" signals whether the Mailcow version will be checked against the Github version
# now "headers" contains the accepted format (JSON) and the API key to use
base_url = f"{protocol}://{hostname}:{port}/{MC_API_BASE}"
# get domain data
num_domains = get_domain_info(headers=headers, verify=verify, base_url=base_url)
# get mailbox data
num_mailboxes, num_global_messages = get_mailbox_info(
headers=headers, verify=verify, base_url=base_url
)
# get global Mailcow info
mailcow_info = get_mailcow_info(
headers=headers, verify=verify, base_url=base_url, check_version=check_version
)
mailcow_version = mailcow_info["mc_version"]
github_version = mailcow_info["git_version"]
update_available = mailcow_info["update_available"]
check_version_enabled = mailcow_info["check_version_enabled"]
# create agent output
do_cmk_output_domains()
do_cmk_output_mailboxes()
do_cmk_output_mailcow(
mailcow_version,
num_domains,
num_mailboxes,
num_global_messages,
github_version,
update_available,
check_version_enabled,
)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,93 @@
#!/user/bin/env python3
"""parameter form ruleset for mailcow domains"""
from cmk.rulesets.v1 import Title
from cmk.rulesets.v1.form_specs import (
DefaultValue,
DictElement,
Dictionary,
LevelDirection,
SimpleLevels,
Percentage,
Integer,
)
from cmk.rulesets.v1.rule_specs import CheckParameters, HostAndItemCondition, Topic
# function name should begin with an underscore to limit it's visibility
def _parameter_form():
return Dictionary(
elements={
"levels_mailcow_domains_quota_used": DictElement(
parameter_form=SimpleLevels(
title=Title("Mailcow domains quota usage for storage"),
form_spec_template=Percentage(),
level_direction=LevelDirection.UPPER,
prefill_fixed_levels=DefaultValue(value=(65.0, 85.0)),
),
required=True,
),
"levels_mailcow_domains_mailboxes_used": DictElement(
parameter_form=SimpleLevels(
title=Title("Mailcow domains mailboxes usage"),
form_spec_template=Percentage(),
level_direction=LevelDirection.UPPER,
prefill_fixed_levels=DefaultValue(value=(65.0, 85.0)),
),
required=True,
),
"levels_mailcow_domains_aliases_used": DictElement(
parameter_form=SimpleLevels(
title=Title("Mailcow domains aliases usage"),
form_spec_template=Percentage(),
level_direction=LevelDirection.UPPER,
prefill_fixed_levels=DefaultValue(value=(65.0, 85.0)),
),
required=True,
),
"levels_mailcow_domains_num_messages": DictElement(
parameter_form=SimpleLevels(
title=Title("Number of messages"),
form_spec_template=Integer(),
level_direction=LevelDirection.UPPER,
prefill_fixed_levels=DefaultValue(value=(10_000, 25_000)),
),
required=True,
),
"levels_mailcow_domains_num_aliases": DictElement(
parameter_form=SimpleLevels(
title=Title("Number of configured aliases"),
form_spec_template=Integer(),
level_direction=LevelDirection.UPPER,
prefill_fixed_levels=DefaultValue(value=(100, 250)),
),
required=True,
),
"levels_mailcow_domains_num_mailboxes": DictElement(
parameter_form=SimpleLevels(
title=Title("Number of configured mailboxes"),
form_spec_template=Integer(),
level_direction=LevelDirection.UPPER,
prefill_fixed_levels=DefaultValue(value=(100, 250)),
),
required=True,
),
}
)
# name must begin with "rule_spec_", should refer to the used check plugin
# must be an instance of "CheckParameters"
rule_spec_mailcow_domains = CheckParameters(
# "name" should be the same as the check plugin
name="mailcow_domains",
# the title is shown in the GUI
title=Title("Mailcow domain levels"),
# this ruleset can be found under Setup|Service monitoring rules|Various
topic=Topic.APPLICATIONS,
# define the name of the function which creates the GUI elements
parameter_form=_parameter_form,
# define the label in the GUI where you can restrict the
# settings to one or mor specific users (item)
condition=HostAndItemCondition(item_title=Title("Domain")),
)

View File

@@ -0,0 +1,65 @@
#!/usr/bin/env python3
"""
defines the form for typing in all needed levels
regarding number of domains, mailboxes and global message count
"""
from cmk.rulesets.v1 import Help, Title
from cmk.rulesets.v1.form_specs import (
DictElement,
Dictionary,
SimpleLevels,
LevelDirection,
DefaultValue,
Integer,
)
from cmk.rulesets.v1.rule_specs import (
CheckParameters,
Topic,
HostCondition,
)
def _parameter_form() -> Dictionary:
return Dictionary(
title=Title("Levels for global Mailcow information"),
help_text=Help("Checking Mailcow systems via API"),
elements={
"levels_num_domains": DictElement(
parameter_form=SimpleLevels(
title=Title("Levels for number of email domains"),
form_spec_template=Integer(),
level_direction=LevelDirection.UPPER,
prefill_fixed_levels=DefaultValue(value=(100, 200)),
),
required=True,
),
"levels_num_mailboxes": DictElement(
parameter_form=SimpleLevels(
title=Title("Levels for number of mailboxes"),
form_spec_template=Integer(),
level_direction=LevelDirection.UPPER,
prefill_fixed_levels=DefaultValue(value=(500, 1000)),
),
required=True,
),
"levels_num_global_messages": DictElement(
parameter_form=SimpleLevels(
title=Title("Levels for number of messages"),
form_spec_template=Integer(),
level_direction=LevelDirection.UPPER,
prefill_fixed_levels=DefaultValue(value=(100_000, 250_000)),
),
required=True,
),
},
)
rule_spec_mailcow_info = CheckParameters(
name="mailcow_info",
title=Title("Mailcow global levels"),
topic=Topic.APPLICATIONS,
parameter_form=_parameter_form,
condition=HostCondition(),
)

View File

@@ -0,0 +1,57 @@
#!/user/bin/env python3
"""parameter form ruleset for mailcow domains"""
from cmk.rulesets.v1 import Title
from cmk.rulesets.v1.form_specs import (
DefaultValue,
DictElement,
Dictionary,
LevelDirection,
SimpleLevels,
Percentage,
Integer,
)
from cmk.rulesets.v1.rule_specs import CheckParameters, HostAndItemCondition, Topic
# function name should begin with an underscore to limit it's visibility
def _parameter_form():
return Dictionary(
elements={
"levels_mailcow_mailboxes_quota_used": DictElement(
parameter_form=SimpleLevels(
title=Title("Mailcow mailbox quota usage for storage"),
form_spec_template=Percentage(),
level_direction=LevelDirection.UPPER,
prefill_fixed_levels=DefaultValue(value=(65.0, 85.0)),
),
required=True,
),
"levels_mailcow_mailboxes_num_messages": DictElement(
parameter_form=SimpleLevels(
title=Title("Number of messages in mailbox"),
form_spec_template=Integer(),
level_direction=LevelDirection.UPPER,
prefill_fixed_levels=DefaultValue(value=(1000, 2500)),
),
required=True,
),
}
)
# name must begin with "rule_spec_", should refer to the used check plugin
# must be an instance of "CheckParameters"
rule_spec_mailcow_mailboxes = CheckParameters(
# "name" should be the same as the check plugin
name="mailcow_mailboxes",
# the title is shown in the GUI
title=Title("Mailcow mailbox levels"),
# this ruleset can be found under Setup|Service monitoring rules|Various
topic=Topic.APPLICATIONS,
# define the name of the function which creates the GUI elements
parameter_form=_parameter_form,
# define the label in the GUI where you can restrict the
# settings to one or mor specific users (item)
condition=HostAndItemCondition(item_title=Title("Mailbox")),
)

View File

@@ -0,0 +1,98 @@
#!/usr/bin/env python3
# pylint: disable=line-too-long
"""defines the form for typing in all needed HAL9002 parameters"""
from cmk.rulesets.v1 import Help, Title, Label
from cmk.rulesets.v1.form_specs import (
DictElement,
Dictionary,
String,
validators,
BooleanChoice,
Integer,
Password,
migrate_to_password,
InputHint,
DefaultValue,
)
from cmk.rulesets.v1.rule_specs import SpecialAgent, Topic
def _form_spec_special_agent_mailcow() -> Dictionary:
return Dictionary(
title=Title("Mailcow Server Information"),
help_text=Help("Checking Mailcow systems via API"),
elements={
"hostname": DictElement(
required=True,
parameter_form=String(
title=Title("Hostname"),
help_text=Help(
"Hostname of Mailcow server (bare FQDN or IP), mandatory, eg. mailcow.yourdomain.tld"
),
custom_validate=(validators.LengthInRange(min_value=1),),
prefill=InputHint("mailcow.yourdomain.tld"),
),
),
"apikey": DictElement(
required=True,
parameter_form=Password(
title=Title("API key"),
help_text=Help("Specify API key, mandatory"),
custom_validate=(validators.LengthInRange(min_value=1),),
migrate=migrate_to_password,
),
),
"port": DictElement(
required=False,
parameter_form=Integer(
title=Title("Port"),
help_text=Help(
"Specify port the Mailcow system ist listening on, mandatory"
),
prefill=DefaultValue(443),
custom_validate=(validators.NetworkPort(),),
),
),
"check_version": DictElement(
required=False,
parameter_form=BooleanChoice(
title=Title("Check Mailcow version"),
help_text=Help(
"Activate to check version of running Mailcow against actual Github version, optional"
),
label=Label(
"Enable version check (requires access to Github internet site)"
),
),
),
"no_https": DictElement(
required=False,
parameter_form=BooleanChoice(
title=Title("Disable HTTPS"),
help_text=Help(
"Activate to disable encryption (not recommended), optional"
),
label=Label("Disable HTTPS"),
),
),
"no_cert_check": DictElement(
required=False,
parameter_form=BooleanChoice(
title=Title("Disable certificate validation"),
help_text=Help(
"Activate to disable certificate validation (not recommended), optional"
),
label=Label("Disable certificate validation"),
),
),
},
)
rule_spec_mailcow = SpecialAgent(
name="mailcow",
title=Title("Mailcow connection parameters"),
topic=Topic.APPLICATIONS,
parameter_form=_form_spec_special_agent_mailcow,
)

View File

@@ -0,0 +1,48 @@
#!/usr/bin/env python3
# pylint: disable=missing-class-docstring, missing-module-docstring, missing-function-docstring
from collections.abc import Iterable
from pydantic import BaseModel
from cmk.server_side_calls.v1 import (
HostConfig,
Secret,
SpecialAgentCommand,
SpecialAgentConfig,
)
class MailcowParams(BaseModel):
hostname: str | None = None
apikey: Secret | None = None
port: int | None = None
no_https: bool = False
no_cert_check: bool = False
check_version: bool = False
def agent_mailcow_arguments(
params: MailcowParams, _host_config: HostConfig
) -> Iterable[SpecialAgentCommand]:
command_arguments: list[str | Secret] = []
if params.hostname is not None:
command_arguments += ["--hostname", params.hostname]
if params.apikey is not None:
command_arguments += ["--apikey", params.apikey.unsafe()]
if params.port is not None:
command_arguments += ["--port", str(params.port)]
if params.no_https:
command_arguments.append("--no-https")
if params.no_cert_check:
command_arguments.append("--no-cert-check")
if params.check_version:
command_arguments.append("--check-version")
yield SpecialAgentCommand(command_arguments=command_arguments)
special_agent_mailcow = SpecialAgentConfig(
name="mailcow",
parameter_parser=MailcowParams.model_validate,
commands_function=agent_mailcow_arguments,
)