|
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 | +The request and response structure is inspired by JSON-RPC. |
| 26 | + |
| 27 | +Note that this documentation uses beautified JSON for ease of reading. |
| 28 | + |
| 29 | +For logging or debugging, channels can write to `stderr`, which will be logged by Icinga Notifications. |
18 | 30 |
|
19 | 31 | ### Request
|
20 | 32 |
|
21 |
| -The request must be in JSON format and should contain following keys: |
| 33 | +A channel receives a request as a JSON object with the following fields: |
22 | 34 |
|
23 | 35 | - `method`: The request method to call.
|
24 |
| -- `params`: The params for request method. |
| 36 | +- `params`: Optional params for the request method. |
25 | 37 | - `id`: Unsigned int value. Required to assign the response to its request as responses can be sent out of order.
|
26 | 38 |
|
27 | 39 | Examples:
|
28 | 40 |
|
| 41 | +- Simple request without any `params`: |
| 42 | + ```json |
| 43 | + { |
| 44 | + "method": "Simple", |
| 45 | + "id" : 1000 |
| 46 | + } |
| 47 | + ``` |
| 48 | +- Request with `params` of different types: |
| 49 | + ```json |
| 50 | + { |
| 51 | + "method": "WithParams", |
| 52 | + "params": { |
| 53 | + "foo": 23, |
| 54 | + "bar": "hello" |
| 55 | + }, |
| 56 | + "id": 1000 |
| 57 | + } |
| 58 | + ``` |
| 59 | + |
| 60 | +### Response |
| 61 | + |
| 62 | +Each request must be answered by the channel with a response JSON object of the following fields: |
| 63 | + |
| 64 | +- `result`: The result as JSON format. Omitted when the method does not return a value, i.e., for setter calls, or an |
| 65 | + error has occurred. |
| 66 | +- `error`: The error message. Omitted when no error has occurred. |
| 67 | +- `id`: The request id. |
| 68 | + |
| 69 | +In case of a present `error` value, the `result` field should be empty. |
| 70 | +Successfully responses without a `result` do only contain the `id` field. |
| 71 | + |
| 72 | +Examples: |
| 73 | + |
| 74 | +- Successfully response without a `result` message: |
| 75 | + ```json |
| 76 | + { |
| 77 | + "id": 1000 |
| 78 | + } |
| 79 | + ``` |
| 80 | +- Successfully response with a `result`: |
| 81 | + ```json |
| 82 | + { |
| 83 | + "result": "hello world", |
| 84 | + "id": 1000 |
| 85 | + } |
| 86 | + ``` |
| 87 | +- Response with an error: |
| 88 | + ```json |
| 89 | + { |
| 90 | + "error": "unknown method: 'Foo'", |
| 91 | + "id": 1000 |
| 92 | + } |
| 93 | + ``` |
| 94 | + |
| 95 | +### Methods |
| 96 | + |
| 97 | +The following methods must be implemented by a channel. |
| 98 | + |
| 99 | +#### GetInfo |
| 100 | + |
| 101 | +The parameterless `GetInfo` method returns information about the channel. |
| 102 | + |
| 103 | +Its `result` is expected to be a JSON object with the `json` fields defined in the |
| 104 | +[`Info` type](https://pkg.go.dev/github.com/icinga/icinga-notifications/pkg/plugin#Info). |
| 105 | +The `config_attrs` field must be an array of JSON objects according to the |
| 106 | +[`ConfigOption` type](https://pkg.go.dev/github.com/icinga/icinga-notifications/pkg/plugin#ConfigOption). |
| 107 | +Those attributes define configuration options for the channel to be set via the `SetConfig` method. |
| 108 | +Furthermore, they are used to build the channel configuration UI in Icinga Notifications Web. |
| 109 | + |
| 110 | +##### Example GetInfo Request |
| 111 | + |
29 | 112 | ```json
|
30 | 113 | {
|
31 |
| - "method": "Add", |
32 |
| - "params": { |
33 |
| - "num1": 5, |
34 |
| - "num2": 3 |
| 114 | + "method": "GetInfo", |
| 115 | + "id" : 1 |
| 116 | +} |
| 117 | +``` |
| 118 | + |
| 119 | +##### Example GetInfo Response |
| 120 | + |
| 121 | +```json |
| 122 | +{ |
| 123 | + "result": { |
| 124 | + "name": "Minified Webhook", |
| 125 | + "version": "0.0.0-gf369a11-dirty", |
| 126 | + "author": "Icinga GmbH", |
| 127 | + "config_attrs": [ |
| 128 | + { |
| 129 | + "name": "url_template", |
| 130 | + "type": "string", |
| 131 | + "label": { |
| 132 | + "de_DE": "URL-Template", |
| 133 | + "en_US": "URL Template" |
| 134 | + }, |
| 135 | + "help": { |
| 136 | + "de_DE": "URL, optional als Go-Template über das zu verarbeitende plugin.NotificationRequest.", |
| 137 | + "en_US": "URL, optionally as a Go template over the current plugin.NotificationRequest." |
| 138 | + }, |
| 139 | + "required": true, |
| 140 | + "min": null, |
| 141 | + "max": null |
| 142 | + }, |
| 143 | + { |
| 144 | + "name": "response_status_codes", |
| 145 | + "type": "string", |
| 146 | + "label": { |
| 147 | + "de_DE": "Antwort-Status-Codes", |
| 148 | + "en_US": "Response Status Codes" |
| 149 | + }, |
| 150 | + "help": { |
| 151 | + "de_DE": "Kommaseparierte Liste erwarteter Status-Code der HTTP-Antwort, z.B.: 200,201,202,208,418", |
| 152 | + "en_US": "Comma separated list of expected HTTP response status code, e.g., 200,201,202,208,418" |
| 153 | + }, |
| 154 | + "default": "200", |
| 155 | + "min": null, |
| 156 | + "max": null |
| 157 | + } |
| 158 | + ] |
35 | 159 | },
|
36 |
| - "id": 2020 |
| 160 | + "id": 1 |
37 | 161 | }
|
38 | 162 | ```
|
39 | 163 |
|
| 164 | +#### SetConfig |
| 165 | + |
| 166 | +The `SetConfig` method configures the channel and |
| 167 | +should be called at least once before sending the first notifications to initialize the channel plugin. |
| 168 | + |
| 169 | +The passed JSON object in the request's `param` field reflects the objects from `GetInfo`'s `config_attrs`. |
| 170 | +Each object within the `config_attrs` array can be configured by using its `name` attribute as the key together with the |
| 171 | +desired configuration value, being of the specified type in the `type` field. |
| 172 | + |
| 173 | +To illustrate, the URL template from the above output is configurable with the following JSON object passed in `params`: |
| 174 | + |
40 | 175 | ```json
|
41 | 176 | {
|
42 |
| - "method": "Foo", |
| 177 | + "url_template": "http://localhost:8000/update/{{.Incident.Id}}" |
| 178 | +} |
| 179 | +``` |
| 180 | + |
| 181 | +The response might carry an error if the configuration is invalid. |
| 182 | + |
| 183 | +##### Example SetConfig Request |
| 184 | + |
| 185 | +```json |
| 186 | +{ |
| 187 | + "method": "SetConfig", |
43 | 188 | "params": {
|
44 |
| - "a": "value1", |
45 |
| - "b": "value2" |
| 189 | + "url_template": "http://localhost:8000/update/{{.Incident.Id}}", |
| 190 | + "response_status_codes": "200" |
46 | 191 | },
|
47 |
| - "id": 3030 |
| 192 | + "id": 2 |
48 | 193 | }
|
49 | 194 | ```
|
50 | 195 |
|
51 |
| -### Response |
| 196 | +##### Example GetInfo Response |
52 | 197 |
|
53 |
| -The response is in JSON format and contains following keys: |
| 198 | +```json |
| 199 | +{ |
| 200 | + "id": 2 |
| 201 | +} |
| 202 | +``` |
54 | 203 |
|
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. |
| 204 | +#### SendNotification |
60 | 205 |
|
61 |
| -Examples: |
| 206 | +The `SendNotification` method requests the channel to dispatch notifications. |
| 207 | + |
| 208 | +Within the request's `params`, a JSON object representing a |
| 209 | +[`NotificationRequest`](https://pkg.go.dev/github.com/icinga/icinga-notifications/pkg/plugin#NotificationRequest) |
| 210 | +is expected. |
| 211 | + |
| 212 | +The response might carry an error due to channel-specific reasons. |
| 213 | + |
| 214 | +#### Example SendNotification Request |
62 | 215 |
|
63 | 216 | ```json
|
64 | 217 | {
|
65 |
| - "result": 8, |
66 |
| - "id": 2020 |
| 218 | + "method": "SendNotification", |
| 219 | + "params": { |
| 220 | + "contact": { |
| 221 | + "full_name": "icingaadmin", |
| 222 | + "addresses": [ |
| 223 | + { |
| 224 | + "type": "email", |
| 225 | + |
| 226 | + } |
| 227 | + ] |
| 228 | + }, |
| 229 | + "object": { |
| 230 | + "name": "dummy-816!random fortune", |
| 231 | + "url": "http://localhost/icingaweb2/icingadb/service?name=random%20fortune&host.name=dummy-816", |
| 232 | + "tags": { |
| 233 | + "host": "dummy-816", |
| 234 | + "service": "random fortune" |
| 235 | + }, |
| 236 | + "extra_tags": { |
| 237 | + "hostgroup/app-mobile": "", |
| 238 | + "hostgroup/department-dev": "", |
| 239 | + "hostgroup/env-prod": "", |
| 240 | + "hostgroup/location-rome": "", |
| 241 | + "servicegroup/app-storage": "", |
| 242 | + "servicegroup/department-ps": "", |
| 243 | + "servicegroup/env-prod": "", |
| 244 | + "servicegroup/location-rome": "" |
| 245 | + } |
| 246 | + }, |
| 247 | + "incident": { |
| 248 | + "id": 1437, |
| 249 | + "url": "http://localhost/icingaweb2/notifications/incident?id=1437", |
| 250 | + "severity": "crit" |
| 251 | + }, |
| 252 | + "event": { |
| 253 | + "time": "2024-07-12T10:47:30.445439055Z", |
| 254 | + "type": "state", |
| 255 | + "username": "", |
| 256 | + "message": "Q:\tWhat looks like a cat, flies like a bat, brays like a donkey, and\n\tplays like a monkey?\nA:\tNothing." |
| 257 | + } |
| 258 | + }, |
| 259 | + "id": 3 |
67 | 260 | }
|
68 | 261 | ```
|
69 | 262 |
|
| 263 | +#### Example SendNotification Response |
| 264 | + |
70 | 265 | ```json
|
71 | 266 | {
|
72 |
| - "error": "unknown method: 'Foo'", |
73 |
| - "id": 3030 |
| 267 | + "id": 3 |
74 | 268 | }
|
75 | 269 | ```
|
76 | 270 |
|
77 |
| -### Methods |
| 271 | +## Writing Channel Plugins in Go |
| 272 | + |
| 273 | +!!! warning |
| 274 | + |
| 275 | + As this is still an early preview version, things might change. |
| 276 | + There may still be severe bugs and incompatible changes may happen without any notice. |
| 277 | + |
| 278 | +!!! tip |
| 279 | + |
| 280 | + Icinga Notifications comes with a Webhook channel plugin. |
| 281 | + Consider using this channel if your transport uses HTTP instead of writing a custom channel. |
| 282 | + |
| 283 | +!!! tip |
| 284 | + |
| 285 | + When developing custom channels, consider naming them with a unique prefix, |
| 286 | + as additional channels will get added to Icinga Notifications in the future. |
| 287 | + For example, name your channel `x_irc` or `my_irc` instead of `irc`. |
78 | 288 |
|
79 |
| -Currently, the channel plugin include following three methods: |
| 289 | +Since Icinga Notifications and all of its channels are written in the Go programming language, |
| 290 | +libraries already used internally can be reused. |
| 291 | +In particular, the [`Plugin`](https://pkg.go.dev/github.com/icinga/icinga-notifications/pkg/plugin#Plugin) |
| 292 | +interface must be implemented, requesting methods for all the RPC methods described above. |
| 293 | +The channel plugin's `main` function should call |
| 294 | +[`RunPlugin`](https://pkg.go.dev/github.com/icinga/icinga-notifications/pkg/plugin#RunPlugin), |
| 295 | +taking care about calling the RPC method implementations. |
80 | 296 |
|
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) |
| 297 | +For concrete examples, there are the implemented channels in the Icinga Notifications repository under |
| 298 | +[`./cmd/channels`](https://github.com/Icinga/icinga-notifications/tree/main/cmd/channels). |
0 commit comments