Skip to content

Commit 6fbc306

Browse files
committed
Increase details of Channels documentation
With a release approaching, the Channels documentation got more information about how the Channel system actually work and how to build your own channels. The internal/changes/examples JSON files were inlined to ease the readability and updated, as they contained partially outdated information. For the pkg/plugin part, some API documentation was added as this might get used by external users.
1 parent 860ea0c commit 6fbc306

File tree

6 files changed

+291
-101
lines changed

6 files changed

+291
-101
lines changed

doc/10-Channels.md

Lines changed: 266 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,88 +1,312 @@
11
# Channels
22

33
After Icinga Notifications decides to send a notification of any kind, it will be passed to a channel plugin.
4-
Such a channel plugin submits the notification event to a channel, e.g., email or a chat client.
4+
Such a plugin submits the notification event to a domain-specific channel, e.g., email or a chat client.
55

6-
Icinga Notifications comes packed with channel plugins, but also enables you to develop your own plugins.
6+
Icinga Notifications comes packed with channels, but also enables you to develop your own channels.
77

8-
To make those plugins available to Icinga Notifications, they must be placed in the
8+
To make those channels available to Icinga Notifications, they must be placed in the
99
[channels directory](03-Configuration.md#channels-directory),
1010
which is being done automatically for package installations.
11-
Afterwards they can be configured through Icinga Notifications Web.
11+
At startup, Icinga Notifications scans this directory, starts each channel once to query its configuration options
12+
and stores these options in the database.
13+
Using this information, Icinga Notifications Web allows channels to be configured,
14+
which are then started, configured, and lastly used to send notification events from Icinga Notifications.
1215

1316
## Technical Channel Description
1417

15-
Channel plugins are processes that run continuously and independently of each other. They receive many requests over
16-
their lifetime. They receive JSON-formatted requests on stdin and reply with JSON-formatted responses on stdout. The
17-
request and response structure is inspired by JSON-RPC.
18+
!!! warning
19+
20+
As this is still an early preview version, things might change.
21+
There may still be severe bugs and incompatible changes may happen without any notice.
22+
23+
Channel plugins are independent processes that run continuously, supervised by Icinga Notifications.
24+
They receive JSON-formatted requests on `stdin` and reply with JSON-formatted responses on `stdout`.
25+
For logging or debugging, channels can write to `stderr`, which will be logged by Icinga Notifications.
26+
27+
The request and response structure is inspired by JSON-RPC.
28+
The anatomy of requests and responses is described below.
29+
Note that fields with a type marked as optional must be omitted in the JSON object if they do not have a value.
30+
31+
This documentation uses beautified JSON for ease of reading.
1832

1933
### Request
2034

21-
The request must be in JSON format and should contain following keys:
35+
A channel receives a request as a JSON object with the following fields:
2236

23-
- `method`: The request method to call.
24-
- `params`: The params for request method.
25-
- `id`: Unsigned int value. Required to assign the response to its request as responses can be sent out of order.
37+
| Field | Description | Type |
38+
|----------|-------------------------------|------------------------------------------------------------------------|
39+
| `method` | Request method to call. | String |
40+
| `params` | Params for the request method | Optional JSON object, mapping parameter keys (string) to values (any). |
41+
| `id` | Unique identifier. | Unsigned integer |
2642

2743
Examples:
2844

45+
- Simple request without any `params`:
46+
```json
47+
{
48+
"method": "Simple",
49+
"id": 1000
50+
}
51+
```
52+
- Request with `params` of different types:
53+
```json
54+
{
55+
"method": "WithParams",
56+
"params": {
57+
"foo": 23,
58+
"bar": "hello"
59+
},
60+
"id": 1000
61+
}
62+
```
63+
64+
### Response
65+
66+
Each request must be answered by the channel with a response JSON object of the following fields:
67+
68+
| Field | Description | Type |
69+
|----------|-------------------------------------|---------------------------|
70+
| `result` | Output of a successful method call. | Optional JSON value (any) |
71+
| `error` | Error message. | Optional string |
72+
| `id` | Request id. | Unsigned integer |
73+
74+
The `result` field may be omitted if the method does not return a value, i.e., for setter calls.
75+
76+
In case of a present `error` value, the `result` field must be omitted.
77+
Thus, a successful responses without a `result` contains just an `id` field.
78+
79+
The `id` field in a response must match those of its request, allowing Icinga Notifications to link those two.
80+
This is necessary as responses may be created out of order.
81+
82+
Examples:
83+
84+
- Successful response without a `result` message:
85+
```json
86+
{
87+
"id": 1000
88+
}
89+
```
90+
- Successful response with a `result`:
91+
```json
92+
{
93+
"result": "hello world",
94+
"id": 1000
95+
}
96+
```
97+
- Response with an error:
98+
```json
99+
{
100+
"error": "unknown method: 'Foo'",
101+
"id": 1000
102+
}
103+
```
104+
105+
### Methods
106+
107+
The following methods must be implemented by a channel.
108+
109+
#### GetInfo
110+
111+
The parameterless `GetInfo` method returns information about the channel.
112+
113+
Its `result` is expected to be a JSON object with the `json` fields defined in the
114+
[`Info` type](https://pkg.go.dev/github.com/icinga/icinga-notifications/pkg/plugin#Info).
115+
The `config_attrs` field must be an array of JSON objects according to the
116+
[`ConfigOption` type](https://pkg.go.dev/github.com/icinga/icinga-notifications/pkg/plugin#ConfigOption).
117+
Those attributes define configuration options for the channel to be set via the `SetConfig` method.
118+
Furthermore, they are used for channel configuration in Icinga Notifications Web.
119+
120+
##### Example GetInfo Request
121+
29122
```json
30123
{
31-
"method": "Add",
32-
"params": {
33-
"num1": 5,
34-
"num2": 3
124+
"method": "GetInfo",
125+
"id": 1
126+
}
127+
```
128+
129+
##### Example GetInfo Response
130+
131+
```json
132+
{
133+
"result": {
134+
"name": "Minified Webhook",
135+
"version": "0.0.0-gf369a11-dirty",
136+
"author": "Icinga GmbH",
137+
"config_attrs": [
138+
{
139+
"name": "url_template",
140+
"type": "string",
141+
"label": {
142+
"de_DE": "URL-Template",
143+
"en_US": "URL Template"
144+
},
145+
"help": {
146+
"de_DE": "URL, optional als Go-Template über das zu verarbeitende plugin.NotificationRequest.",
147+
"en_US": "URL, optionally as a Go template over the current plugin.NotificationRequest."
148+
},
149+
"required": true,
150+
"min": null,
151+
"max": null
152+
},
153+
{
154+
"name": "response_status_codes",
155+
"type": "string",
156+
"label": {
157+
"de_DE": "Antwort-Status-Codes",
158+
"en_US": "Response Status Codes"
159+
},
160+
"help": {
161+
"de_DE": "Kommaseparierte Liste erwarteter Status-Code der HTTP-Antwort, z.B.: 200,201,202,208,418",
162+
"en_US": "Comma separated list of expected HTTP response status code, e.g., 200,201,202,208,418"
163+
},
164+
"default": "200",
165+
"min": null,
166+
"max": null
167+
}
168+
]
35169
},
36-
"id": 2020
170+
"id": 1
171+
}
172+
```
173+
174+
#### SetConfig
175+
176+
The `SetConfig` method configures the channel.
177+
178+
The Icinga Notifications daemon is going to call this method at least once before sending the first notifications
179+
to initialize the channel plugin.
180+
181+
The passed JSON object in the request's `param` field reflects the objects from `GetInfo`'s `config_attrs`.
182+
Each object within the `config_attrs` array must be configurable by using its `name` attribute as the key together with
183+
the desired configuration value, being of the specified type in the `type` field.
184+
185+
To illustrate, the URL template from the above output is configurable with the following JSON object passed in `params`:
186+
187+
```json
188+
{
189+
"url_template": "http://localhost:8000/update/{{.Incident.Id}}"
37190
}
38191
```
39192

193+
If the channel plugin successfully configured itself, a response without an `result` must be returned.
194+
Otherwise, an `error` must be returned.
195+
196+
##### Example SetConfig Request
197+
40198
```json
41199
{
42-
"method": "Foo",
200+
"method": "SetConfig",
43201
"params": {
44-
"a": "value1",
45-
"b": "value2"
202+
"url_template": "http://localhost:8000/update/{{.Incident.Id}}",
203+
"response_status_codes": "200"
46204
},
47-
"id": 3030
205+
"id": 2
48206
}
49207
```
50208

51-
### Response
209+
##### Example GetInfo Response
210+
211+
```json
212+
{
213+
"id": 2
214+
}
215+
```
52216

53-
The response is in JSON format and contains following keys:
217+
#### SendNotification
54218

55-
- `result`: The result as JSON format. Omitted when the method does not return a value (e.g. setter calls) or an error
56-
has occurred.
57-
- `error`: The error message. Omitted when no error has occurred.
58-
- `id`: The request id. When result value is empty and no error is occurred, the response will only contain the request
59-
id.
219+
The `SendNotification` method requests the channel to dispatch notifications.
60220

61-
Examples:
221+
Within the request's `params`, a JSON object representing a
222+
[`NotificationRequest`](https://pkg.go.dev/github.com/icinga/icinga-notifications/pkg/plugin#NotificationRequest)
223+
is passed.
224+
225+
If the channel cannot dispatch a notification, an `error` must be returned.
226+
This may be due to channel-specific reasons, such as an email channel where the SMTP server is unavailable.
227+
228+
##### Example SendNotification Request
62229

63230
```json
64231
{
65-
"result": 8,
66-
"id": 2020
232+
"method": "SendNotification",
233+
"params": {
234+
"contact": {
235+
"full_name": "icingaadmin",
236+
"addresses": [
237+
{
238+
"type": "email",
239+
"address": "[email protected]"
240+
}
241+
]
242+
},
243+
"object": {
244+
"name": "dummy-816!random fortune",
245+
"url": "http://localhost/icingaweb2/icingadb/service?name=random%20fortune&host.name=dummy-816",
246+
"tags": {
247+
"host": "dummy-816",
248+
"service": "random fortune"
249+
},
250+
"extra_tags": {
251+
"hostgroup/app-mobile": "",
252+
"hostgroup/department-dev": "",
253+
"hostgroup/env-prod": "",
254+
"hostgroup/location-rome": "",
255+
"servicegroup/app-storage": "",
256+
"servicegroup/department-ps": "",
257+
"servicegroup/env-prod": "",
258+
"servicegroup/location-rome": ""
259+
}
260+
},
261+
"incident": {
262+
"id": 1437,
263+
"url": "http://localhost/icingaweb2/notifications/incident?id=1437",
264+
"severity": "crit"
265+
},
266+
"event": {
267+
"time": "2024-07-12T10:47:30.445439055Z",
268+
"type": "state",
269+
"username": "",
270+
"message": "Q:\tWhat looks like a cat, flies like a bat, brays like a donkey, and\n\tplays like a monkey?\nA:\tNothing."
271+
}
272+
},
273+
"id": 3
67274
}
68275
```
69276

277+
##### Example SendNotification Response
278+
70279
```json
71280
{
72-
"error": "unknown method: 'Foo'",
73-
"id": 3030
281+
"id": 3
74282
}
75283
```
76284

77-
### Methods
285+
## Writing Channel Plugins in Go
286+
287+
!!! warning
288+
289+
As this is still an early preview version, things might change.
290+
There may still be severe bugs and incompatible changes may happen without any notice.
291+
292+
!!! tip
293+
294+
Icinga Notifications comes with a Webhook channel plugin.
295+
Consider using this channel if your transport uses HTTP instead of writing a custom channel.
296+
297+
!!! tip
298+
299+
When developing custom channels, consider naming them with a unique prefix,
300+
as additional channels will get added to Icinga Notifications in the future.
301+
For example, name your channel `x_irc` or `my_irc` instead of `irc`.
78302

79-
Currently, the channel plugin include following three methods:
303+
Since Icinga Notifications and all of its channels are written in the Go programming language,
304+
libraries already used internally can be reused.
305+
In particular, the [`Plugin`](https://pkg.go.dev/github.com/icinga/icinga-notifications/pkg/plugin#Plugin)
306+
interface must be implemented, requesting methods for all the RPC methods described above.
307+
The channel plugin's `main` function should call
308+
[`RunPlugin`](https://pkg.go.dev/github.com/icinga/icinga-notifications/pkg/plugin#RunPlugin),
309+
taking care about calling the RPC method implementations.
80310

81-
- `SetConfig`: Initialize the channel plugin with specified config as `params` key. The config is plugin specific
82-
therefore each plugin defines what is expected as config.
83-
[(example)](../internal/channel/examples/set-config.json)
84-
- `GetInfo`: Get the information about the channel e.g. Name. The `params` key has no effect and can be omitted.
85-
[(example)](../internal/channel/examples/get-info.json)
86-
- `SendNotification`: Send the notifications. The `params` key should contain the information about the contact to be
87-
notified, corresponding object, the incident and the triggered event.
88-
[(example)](../internal/channel/examples/send-notification.json)
311+
For concrete examples, there are the implemented channels in the Icinga Notifications repository under
312+
[`./cmd/channels`](https://github.com/Icinga/icinga-notifications/tree/main/cmd/channels).

doc/20-HTTP-API.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ curl -v -u 'source-2:insecureinsecure' -d '@-' 'http://localhost:5680/process-ev
3535
"type": "state",
3636
"severity": "crit",
3737
"username": "",
38-
"message": "Something went somehwere very wrong."
38+
"message": "Something went somewhere very wrong."
3939
}
4040
EOF
4141
```

internal/channel/examples/get-info.json

Lines changed: 0 additions & 4 deletions
This file was deleted.

0 commit comments

Comments
 (0)