|
1 | 1 | # Channels
|
2 | 2 |
|
3 | 3 | 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. |
5 | 5 |
|
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. |
7 | 7 |
|
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 |
9 | 9 | [channels directory](03-Configuration.md#channels-directory),
|
10 | 10 | 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. |
12 | 15 |
|
13 | 16 | ## Technical Channel Description
|
14 | 17 |
|
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. |
18 | 32 |
|
19 | 33 | ### Request
|
20 | 34 |
|
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: |
22 | 36 |
|
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 | |
26 | 42 |
|
27 | 43 | Examples:
|
28 | 44 |
|
| 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 | + |
29 | 122 | ```json
|
30 | 123 | {
|
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 | + ] |
35 | 169 | },
|
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}}" |
37 | 190 | }
|
38 | 191 | ```
|
39 | 192 |
|
| 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 | + |
40 | 198 | ```json
|
41 | 199 | {
|
42 |
| - "method": "Foo", |
| 200 | + "method": "SetConfig", |
43 | 201 | "params": {
|
44 |
| - "a": "value1", |
45 |
| - "b": "value2" |
| 202 | + "url_template": "http://localhost:8000/update/{{.Incident.Id}}", |
| 203 | + "response_status_codes": "200" |
46 | 204 | },
|
47 |
| - "id": 3030 |
| 205 | + "id": 2 |
48 | 206 | }
|
49 | 207 | ```
|
50 | 208 |
|
51 |
| -### Response |
| 209 | +##### Example GetInfo Response |
| 210 | + |
| 211 | +```json |
| 212 | +{ |
| 213 | + "id": 2 |
| 214 | +} |
| 215 | +``` |
52 | 216 |
|
53 |
| -The response is in JSON format and contains following keys: |
| 217 | +#### SendNotification |
54 | 218 |
|
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. |
60 | 220 |
|
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 |
62 | 229 |
|
63 | 230 | ```json
|
64 | 231 | {
|
65 |
| - "result": 8, |
66 |
| - "id": 2020 |
| 232 | + "method": "SendNotification", |
| 233 | + "params": { |
| 234 | + "contact": { |
| 235 | + "full_name": "icingaadmin", |
| 236 | + "addresses": [ |
| 237 | + { |
| 238 | + "type": "email", |
| 239 | + |
| 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 |
67 | 274 | }
|
68 | 275 | ```
|
69 | 276 |
|
| 277 | +##### Example SendNotification Response |
| 278 | + |
70 | 279 | ```json
|
71 | 280 | {
|
72 |
| - "error": "unknown method: 'Foo'", |
73 |
| - "id": 3030 |
| 281 | + "id": 3 |
74 | 282 | }
|
75 | 283 | ```
|
76 | 284 |
|
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`. |
78 | 302 |
|
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. |
80 | 310 |
|
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). |
0 commit comments