Skip to content

Commit da549ee

Browse files
committed
integrate notification support both in the guide and in the mkp builder
1 parent 5574afe commit da549ee

File tree

9 files changed

+891
-40
lines changed

9 files changed

+891
-40
lines changed

CHANGES.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
88
## [Unreleased]
99

1010
### New
11+
- Add notification plugin support to mkp-builder (collects from `local/share/check_mk/notifications/`, creates `notifications.tar`)
12+
- Add notification plugin development guide (14-notifications.md) covering Discord/webhook examples, environment variables, testing
1113

1214
### Changed
1315

README.md

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -165,8 +165,11 @@ repository/
165165
│ │ │ └── your_plugin_bakery.py
166166
│ │ └── cmk/base/cee/plugins/bakery/
167167
│ │ └── your_plugin.py
168-
│ └── share/check_mk/agents/plugins/
169-
│ └── your_plugin
168+
│ └── share/check_mk/
169+
│ ├── agents/plugins/
170+
│ │ └── your_plugin
171+
│ └── notifications/
172+
│ └── your_notification.py
170173
├── .mkp-builder.ini # Optional config file
171174
└── .github/workflows/
172175
└── build.yml
@@ -271,8 +274,9 @@ package.mkp (tar file, gzip compressed)
271274
├── info # Python dict with package metadata
272275
├── info.json # JSON version of metadata
273276
├── agents.tar # Agent plugins and scripts
274-
├── cmk_addons_plugins.tar # Checkmk addon plugins
275-
└── lib.tar # Library files (bakery plugins)
277+
├── cmk_addons_plugins.tar # CheckMK addon plugins
278+
├── lib.tar # Library files (bakery plugins)
279+
└── notifications.tar # Notification scripts
276280
```
277281

278282
## Supported Checkmk Versions
@@ -295,6 +299,10 @@ The action automatically maps files from your local directory structure:
295299
- Source: `local/lib/python3/cmk/base/cee/plugins/bakery/PACKAGE_NAME.py`
296300
- Target: `cmk/base/cee/plugins/bakery/PACKAGE_NAME.py` in lib.tar
297301

302+
### Notification Scripts
303+
- Source: `local/share/check_mk/notifications/*`
304+
- Target: notification files in notifications.tar
305+
298306
## Troubleshooting
299307

300308
### Common Issues

cmk-mkp-format.md

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,9 @@ package.mkp (gzip compressed)
2020
├── info # Python dict with package metadata
2121
├── info.json # JSON version of metadata
2222
├── agents.tar # Agent plugins and scripts
23-
├── cmk_addons_plugins.tar # Checkmk addon plugins
24-
└── lib.tar # Library files (bakery plugins)
23+
├── cmk_addons_plugins.tar # CheckMK addon plugins
24+
├── lib.tar # Library files (bakery plugins)
25+
└── notifications.tar # Notification scripts
2526
```
2627

2728
## Component Details
@@ -43,7 +44,8 @@ package.mkp (gzip compressed)
4344
'rulesets/plugin_name.py',
4445
'rulesets/plugin_name_bakery.py'
4546
],
46-
'lib': ['check_mk/base/cee/plugins/bakery/plugin_name.py']
47+
'lib': ['check_mk/base/cee/plugins/bakery/plugin_name.py'],
48+
'notifications': ['notification_script.py']
4749
},
4850
'name': 'plugin_name',
4951
'title': 'Human Readable Title',
@@ -108,6 +110,16 @@ check_mk/base/cee/plugins/bakery/
108110

109111
**Installation Path**: `~SITE/local/lib/python3/`
110112

113+
### 5. Notification Scripts (`notifications.tar`)
114+
115+
Contains notification scripts for alerting integrations:
116+
117+
```
118+
notification_script.py # Notification plugin script
119+
```
120+
121+
**Installation Path**: `~SITE/local/share/check_mk/notifications/`
122+
111123
## Directory Structure Requirements
112124

113125
Your source project should follow this structure:
@@ -126,8 +138,11 @@ project_root/
126138
│ │ ├── checkman/
127139
│ │ ├── graphing/
128140
│ │ └── rulesets/
129-
│ └── share/check_mk/agents/plugins/
130-
│ └── plugin_name
141+
│ └── share/check_mk/
142+
│ ├── agents/plugins/
143+
│ │ └── plugin_name
144+
│ └── notifications/
145+
│ └── notification_script.py
131146
├── .mkp-builder.ini # Package configuration
132147
```
133148

@@ -151,16 +166,19 @@ a symlink to `python3/cmk`.
151166
# Create agents.tar
152167
tar -cf agents.tar -C local/share/check_mk/agents plugins/
153168

154-
# Create cmk_addons_plugins.tar
169+
# Create cmk_addons_plugins.tar
155170
tar -cf cmk_addons_plugins.tar -C local/lib/python3/cmk_addons/plugins .
156171

157172
# Create lib.tar
158173
tar -cf lib.tar -C local/lib/python3 check_mk/
174+
175+
# Create notifications.tar
176+
tar -cf notifications.tar -C local/share/check_mk/notifications .
159177
```
160178

161179
3. **Package final MKP**:
162180
```bash
163-
tar -czf package_name-version.mkp info info.json agents.tar cmk_addons_plugins.tar lib.tar
181+
tar -czf package_name-version.mkp info info.json agents.tar cmk_addons_plugins.tar lib.tar notifications.tar
164182
```
165183

166184
### 2. Automated Build Script
@@ -208,11 +226,16 @@ The build process automatically maps files from your local directory structure:
208226
- Target: `PACKAGE_NAME/*` and flat structure in cmk_addons_plugins.tar
209227
- Pattern: Recursive inclusion of all Python files and documentation
210228

211-
### Library Mapping
229+
### Library Mapping
212230
- Source: `local/lib/python3/cmk/base/cee/plugins/bakery/PACKAGE_NAME.py`
213231
- Target: `check_mk/base/cee/plugins/bakery/PACKAGE_NAME.py` in lib.tar
214232
- Pattern: Bakery plugin files only
215233

234+
### Notification Mapping
235+
- Source: `local/share/check_mk/notifications/*`
236+
- Target: notification files in notifications.tar
237+
- Pattern: All notification script files
238+
216239
## Version Management
217240

218241
### Semantic Versioning
@@ -332,8 +355,9 @@ tar -tzf package.mkp
332355

333356
# Validate tar files
334357
tar -tf agents.tar
335-
tar -tf cmk_addons_plugins.tar
358+
tar -tf cmk_addons_plugins.tar
336359
tar -tf lib.tar
360+
tar -tf notifications.tar
337361

338362
# Check Python syntax
339363
python3 -m py_compile file.py

cmk-plugin-guide/00-index.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
| **Rename metrics while preserving history** | [13-metric-migration.md](13-metric-migration.md) | [05-metrics-graphing.md](05-metrics-graphing.md) |
1919
| **Configure thresholds in the GUI** | [06-rulesets.md](06-rulesets.md) | - |
2020
| **Deploy plugins automatically** | [07-bakery.md](07-bakery.md) | [06-rulesets.md](06-rulesets.md) |
21+
| **Send alerts to external systems** | [14-notifications.md](14-notifications.md) | - |
2122
| **Debug a non-working plugin** | [08-testing-debugging.md](08-testing-debugging.md) | - |
2223
| **Handle cluster environments** | [09-advanced-patterns.md](09-advanced-patterns.md) | - |
2324
| **See a complete example** | [10-examples.md](10-examples.md) | - |
@@ -39,6 +40,7 @@ START: What type of monitoring?
3940
Need to rename metrics? → 13-metric-migration.md
4041
Need GUI configuration? → 06-rulesets.md
4142
Need automatic deployment? → 07-bakery.md
43+
Need custom alerts? → 14-notifications.md
4244
Having problems? → 08-testing-debugging.md
4345
```
4446

@@ -63,6 +65,7 @@ Having problems? → 08-testing-debugging.md
6365
#### Configuration & Deployment
6466
- **[06-rulesets.md](06-rulesets.md)** - GUI configuration forms
6567
- **[07-bakery.md](07-bakery.md)** - Automatic agent deployment
68+
- **[14-notifications.md](14-notifications.md)** - Custom alert integrations (Slack, Discord, etc.)
6669

6770
#### Advanced Topics
6871
- **[08-testing-debugging.md](08-testing-debugging.md)** - Troubleshooting and validation

cmk-plugin-guide/08-testing-debugging.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,43 @@ def test_snmp_detection():
158158
assert oid_responses.get(".1.3.6.1.4.1.318.1.1.1.1.1.1.0") is not None
159159
```
160160

161+
### Using Checkmk Debug Mode
162+
163+
```python
164+
from cmk.ccc import debug
165+
166+
def parse_my_service(string_table):
167+
"""Parse with conditional debug output"""
168+
if debug.enabled():
169+
print(f"DEBUG: Parsing {len(string_table)} lines")
170+
print(f"DEBUG: Data: {string_table}")
171+
172+
parsed = {}
173+
for line in string_table:
174+
# Parse logic here
175+
pass
176+
177+
if debug.enabled():
178+
print(f"DEBUG: Parsed result: {parsed}")
179+
180+
return parsed
181+
182+
def check_my_service(item, section):
183+
"""Check with conditional debug output"""
184+
if debug.enabled():
185+
print(f"DEBUG: Checking item: {item}")
186+
print(f"DEBUG: Section data: {section}")
187+
188+
# Check logic here
189+
yield Result(state=State.OK, summary="Status OK")
190+
```
191+
192+
**Important Notes:**
193+
- In Checkmk 2.4.0+, the debug module moved from `cmk.utils.debug` to `cmk.ccc.debug`
194+
- Debug output is only shown when running with `--debug` flag (e.g., `cmk -II --debug hostname`)
195+
- Debug statements are automatically filtered out in production
196+
- Use `debug.enabled()` to check if debug mode is active before printing
197+
161198
### Debugging with Logging
162199

163200
```python

cmk-plugin-guide/12-special-agents.md

Lines changed: 33 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,13 @@ A complete special agent plugin consists of four parts:
3838

3939
```
4040
~/local/lib/python3/cmk_addons/plugins/my_plugin/
41+
├── __init__.py # Package marker
4142
├── libexec/
4243
│ └── agent_my_plugin # 1. Executable data collector
4344
├── server_side_calls/
44-
│ └── special_agent.py # 2. Command builder
45+
│ └── my_plugin.py # 2. Command builder
4546
├── rulesets/
46-
│ └── special_agent.py # 3. GUI configuration
47+
│ └── my_plugin.py # 3. GUI configuration
4748
└── agent_based/
4849
└── my_plugin.py # 4. Check plugin (data processor)
4950
```
@@ -114,20 +115,27 @@ if __name__ == "__main__":
114115
chmod 755 agent_my_plugin
115116
```
116117

117-
2. **Password Handling**: Always call `replace_passwords()` first
118+
2. **Entry Point**: Must include `if __name__ == "__main__":` block
119+
```python
120+
if __name__ == "__main__":
121+
sys.exit(main())
122+
```
123+
**Without this, the script will not execute when called from the command line!**
124+
125+
3. **Password Handling**: Always call `replace_passwords()` first
118126
```python
119127
from cmk.utils.password_store import replace_passwords
120128
replace_passwords() # Must be FIRST thing in main()
121129
```
122130

123-
3. **Output Format**: Standard CheckMK agent output
131+
4. **Output Format**: Standard CheckMK agent output
124132
```python
125133
print("<<<section_name>>>")
126134
print("key1 value1")
127135
print("key2 value2")
128136
```
129137

130-
4. **Error Handling**: Write errors to stderr, return non-zero on failure
138+
5. **Error Handling**: Write errors to stderr, return non-zero on failure
131139

132140
### JSON Output Pattern
133141

@@ -164,20 +172,21 @@ Converts GUI ruleset parameters into command-line arguments for the special agen
164172
### Basic Implementation
165173

166174
```python
167-
# File: ~/local/lib/python3/cmk_addons/plugins/my_plugin/server_side_calls/special_agent.py
175+
# File: ~/local/lib/python3/cmk_addons/plugins/my_plugin/server_side_calls/my_plugin.py
168176

169177
from collections.abc import Iterator
170178
from pydantic import BaseModel
171179
from cmk.server_side_calls.v1 import (
172180
HostConfig,
181+
Secret,
173182
SpecialAgentCommand,
174183
SpecialAgentConfig,
175184
)
176185

177186
class Params(BaseModel):
178187
"""Type-safe parameter model"""
179188
username: str
180-
password: tuple[str, str] # ("password", "stored_password_id") or ("store", "id")
189+
password: Secret
181190
port: int | None = None
182191
protocol: str = "https"
183192

@@ -188,9 +197,9 @@ def commands_function(
188197
"""Build command-line arguments"""
189198

190199
# Build argument list
191-
args: list[str | tuple[str, str, str]] = [
200+
args = [
192201
"-u", params.username,
193-
"-p", params.password, # Tuple for password store
202+
"-p", params.password.unsafe(), # Extract password from Secret
194203
]
195204

196205
# Optional parameters
@@ -257,7 +266,7 @@ host_config.macros # Custom macros
257266
### Basic Ruleset
258267

259268
```python
260-
# File: ~/local/lib/python3/cmk_addons/plugins/my_plugin/rulesets/special_agent.py
269+
# File: ~/local/lib/python3/cmk_addons/plugins/my_plugin/rulesets/my_plugin.py
261270

262271
from cmk.rulesets.v1 import Title, Help, Label
263272
from cmk.rulesets.v1.form_specs import (
@@ -518,19 +527,20 @@ if __name__ == "__main__":
518527
sys.exit(main())
519528
```
520529

521-
### 2. Server-Side Calls (server_side_calls/special_agent.py)
530+
### 2. Server-Side Calls (server_side_calls/my_plugin.py)
522531

523532
```python
524533
from collections.abc import Iterator
525534
from pydantic import BaseModel
526535
from cmk.server_side_calls.v1 import (
527536
HostConfig,
537+
Secret,
528538
SpecialAgentCommand,
529539
SpecialAgentConfig,
530540
)
531541

532542
class Params(BaseModel):
533-
api_key: tuple[str, str]
543+
api_key: Secret
534544
location: str
535545
units: str = "metric"
536546

@@ -539,7 +549,7 @@ def commands_function(
539549
host_config: HostConfig,
540550
) -> Iterator[SpecialAgentCommand]:
541551
yield SpecialAgentCommand(command_arguments=[
542-
"-k", params.api_key,
552+
"-k", params.api_key.unsafe(),
543553
"-l", params.location,
544554
"--units", params.units,
545555
host_config.primary_ip_config.address or "api.weather.com",
@@ -554,7 +564,7 @@ special_agent_acme_weather = SpecialAgentConfig(
554564
)
555565
```
556566

557-
### 3. Ruleset (rulesets/special_agent.py)
567+
### 3. Ruleset (rulesets/my_plugin.py)
558568

559569
```python
560570
from cmk.rulesets.v1 import Title, Help
@@ -818,18 +828,20 @@ local/share/check_mk/web/plugins/wato/my_plugin.py # GUI
818828
### New Structure (CheckMK 2.3+)
819829
```
820830
local/lib/python3/cmk_addons/plugins/my_plugin/
831+
├── __init__.py
821832
├── libexec/agent_my_plugin
822-
├── server_side_calls/special_agent.py
823-
├── rulesets/special_agent.py
833+
├── server_side_calls/my_plugin.py
834+
├── rulesets/my_plugin.py
824835
└── agent_based/my_plugin.py
825836
```
826837

827838
### Migration Steps
828-
1. Move agent to `libexec/agent_<name>`
829-
2. Create `server_side_calls/special_agent.py` from old `special_agent_info`
830-
3. Convert WATO ruleset to `rulesets/special_agent.py`
831-
4. Update check plugin imports (v1 → v2)
832-
5. Test thoroughly
839+
1. Create `__init__.py` package marker
840+
2. Move agent to `libexec/agent_<name>`
841+
3. Create `server_side_calls/<name>.py` from old `special_agent_info`
842+
4. Convert WATO ruleset to `rulesets/<name>.py`
843+
5. Update check plugin imports (v1 → v2)
844+
6. Test thoroughly
833845

834846
---
835847

0 commit comments

Comments
 (0)