From 3c591a03b048cc3fd00ad75e467797f9448f3fa5 Mon Sep 17 00:00:00 2001 From: Michael Friedrich Date: Thu, 17 Jan 2019 18:20:23 +0100 Subject: [PATCH] Add technical concept docs for our internal JSON-RPC message API --- doc/19-technical-concepts.md | 794 ++++++++++++++++++++++++++++++++++- 1 file changed, 786 insertions(+), 8 deletions(-) diff --git a/doc/19-technical-concepts.md b/doc/19-technical-concepts.md index 7c040ae36..945119e16 100644 --- a/doc/19-technical-concepts.md +++ b/doc/19-technical-concepts.md @@ -735,14 +735,6 @@ Icinga 2 v2.9+ adds more performance metrics for these values: * `sum_bytes_sent_per_second` and `sum_bytes_received_per_second` - - - ## TLS Network IO ### TLS Connection Handling @@ -936,3 +928,789 @@ into the Icinga 2 binary. * cpp-netlib: https://github.com/cpp-netlib/cpp-netlib * evpp: https://github.com/Qihoo360/evpp + + + + +## JSON-RPC Message API + +**The JSON-RPC message API is not a public API for end users.** In case you want +to interact with Icinga, use the [REST API](12-icinga2-api.md#icinga2-api). + +This section describes the internal cluster messages exchanged between endpoints. + +> **Tip** +> +> Debug builds with `icinga2 daemon -DDebugJsonRpc=1` unveils the JSON-RPC messages. + +### Registered Handler Functions + +Functions by example: + +Event Sender: `Checkable::OnNewCheckResult` + +``` +On.connect(&xyzHandler) +``` + +Event Receiver (Client): `CheckResultAPIHandler` in `REGISTER_APIFUNCTION` + +``` +APIHandler() +``` + +### Messages + +#### icinga::Hello + +> Location: `apilistener.cpp` + +##### Message Body + +Key | Value +----------|--------- +jsonrpc | 2.0 +method | icinga::Hello +params | Dictionary + +##### Params + +Currently empty. + +##### Functions + +Event Sender: When a new client connects in `NewClientHandlerInternal()`. +Event Receiver: `HelloAPIHandler` + +##### Permissions + +None, this is a required message. + +#### event::Heartbeat + +> Location: `jsonrpcconnection-heartbeat.cpp` + +##### Message Body + +Key | Value +----------|--------- +jsonrpc | 2.0 +method | event::Heartbeat +params | Dictionary + +##### Params + +Key | Type | Description +----------|---------------|------------------ +timeout | Number | Heartbeat timeout, sender sets 120s. + + +##### Functions + +Event Sender: `JsonRpcConnection::HeartbeatTimerHandler` +Event Receiver: `HeartbeatAPIHandler` + +Both sender and receiver exchange this heartbeat message. If the sender detects +that a client endpoint hasn't sent anything in the updated timeout span, it disconnects +the client. This is to avoid stale connections with no message processing. + +##### Permissions + +None, this is a required message. + +#### event::CheckResult + +> Location: `clusterevents.cpp` + +##### Message Body + +Key | Value +----------|--------- +jsonrpc | 2.0 +method | event::CheckResult +params | Dictionary + +##### Params + +Key | Type | Description +----------|---------------|------------------ +host | String | Host name +service | String | Service name +cr | Serialized CR | Check result + +##### Functions + +Event Sender: `Checkable::OnNewCheckResult` +Event Receiver: `CheckResultAPIHandler` + +##### Permissions + +The receiver will not process messages from not configured endpoints. + +Message updates will be dropped when: + +* Hosts/services do not exist +* Origin is a remote command endpoint different to the configured, and whose zone is not allowed to access this checkable. + +#### event::SetNextCheck + +> Location: `clusterevents.cpp` + +##### Message Body + +Key | Value +----------|--------- +jsonrpc | 2.0 +method | event::SetNextCheck +params | Dictionary + +##### Params + +Key | Type | Description +------------|---------------|------------------ +host | String | Host name +service | String | Service name +next\_check | Timestamp | Next scheduled time as UNIX timestamp. + +##### Functions + +Event Sender: `Checkable::OnNextCheckChanged` +Event Receiver: `NextCheckChangedAPIHandler` + +##### Permissions + +The receiver will not process messages from not configured endpoints. + +Message updates will be dropped when: + +* Checkable does not exist. +* Origin endpoint's zone is not allowed to access this checkable. + +#### event::SetNextNotification + +> Location: `clusterevents.cpp` + +##### Message Body + +Key | Value +----------|--------- +jsonrpc | 2.0 +method | event::SetNextNotification +params | Dictionary + +##### Params + +Key | Type | Description +-------------------|---------------|------------------ +host | String | Host name +service | String | Service name +notification | String | Notification name +next\_notification | Timestamp | Next scheduled notification time as UNIX timestamp. + +##### Functions + +Event Sender: `Notification::OnNextNotificationChanged` +Event Receiver: `NextNotificationChangedAPIHandler` + +##### Permissions + +The receiver will not process messages from not configured endpoints. + +Message updates will be dropped when: + +* Notification does not exist. +* Origin endpoint's zone is not allowed to access this checkable. + +#### event::SetForceNextCheck + +> Location: `clusterevents.cpp` + +##### Message Body + +Key | Value +----------|--------- +jsonrpc | 2.0 +method | event::SetForceNextCheck +params | Dictionary + +##### Params + +Key | Type | Description +----------|---------------|------------------ +host | String | Host name +service | String | Service name +forced | Boolean | Forced next check (execute now) + +##### Functions + +Event Sender: `Checkable::OnForceNextCheckChanged` +Event Receiver: `ForceNextCheckChangedAPIHandler` + +##### Permissions + +The receiver will not process messages from not configured endpoints. + +Message updates will be dropped when: + +* Checkable does not exist. +* Origin endpoint's zone is not allowed to access this checkable. + +#### event::SetForceNextNotification + +> Location: `clusterevents.cpp` + +##### Message Body + +Key | Value +----------|--------- +jsonrpc | 2.0 +method | event::SetForceNextNotification +params | Dictionary + +##### Params + +Key | Type | Description +----------|---------------|------------------ +host | String | Host name +service | String | Service name +forced | Boolean | Forced next check (execute now) + +##### Functions + +Event Sender: `Checkable::SetForceNextNotification` +Event Receiver: `ForceNextNotificationChangedAPIHandler` + +##### Permissions + +The receiver will not process messages from not configured endpoints. + +Message updates will be dropped when: + +* Checkable does not exist. +* Origin endpoint's zone is not allowed to access this checkable. + +#### event::SetAcknowledgement + +> Location: `clusterevents.cpp` + +##### Message Body + +Key | Value +----------|--------- +jsonrpc | 2.0 +method | event::SetAcknowledgement +params | Dictionary + +##### Params + +Key | Type | Description +-----------|---------------|------------------ +host | String | Host name +service | String | Service name +author | String | Acknowledgement author name. +comment | String | Acknowledgement comment content. +acktype | Number | Acknowledgement type (0=None, 1=Normal, 2=Sticky) +notify | Boolean | Notification should be sent. +persistent | Boolean | Whether the comment is persistent. +expiry | Timestamp | Optional expire time as UNIX timestamp. + +##### Functions + +Event Sender: `Checkable::OnForceNextCheckChanged` +Event Receiver: `ForceNextCheckChangedAPIHandler` + +##### Permissions + +The receiver will not process messages from not configured endpoints. + +Message updates will be dropped when: + +* Checkable does not exist. +* Origin endpoint's zone is not allowed to access this checkable. + +#### event::ClearAcknowledgement + +> Location: `clusterevents.cpp` + +##### Message Body + +Key | Value +----------|--------- +jsonrpc | 2.0 +method | event::ClearAcknowledgement +params | Dictionary + +##### Params + +Key | Type | Description +----------|---------------|------------------ +host | String | Host name +service | String | Service name + +##### Functions + +Event Sender: `Checkable::OnAcknowledgementCleared` +Event Receiver: `AcknowledgementClearedAPIHandler` + +##### Permissions + +The receiver will not process messages from not configured endpoints. + +Message updates will be dropped when: + +* Checkable does not exist. +* Origin endpoint's zone is not allowed to access this checkable. + +#### event::SendNotifications + +> Location: `clusterevents.cpp` + +##### Message Body + +Key | Value +----------|--------- +jsonrpc | 2.0 +method | event::SendNotifications +params | Dictionary + +##### Params + +Key | Type | Description +----------|---------------|------------------ +host | String | Host name +service | String | Service name +cr | Serialized CR | Check result +type | Number | enum NotificationType, same as `types` for notification objects. +author | String | Author name +text | String | Notification text + +##### Functions + +Event Sender: `Checkable::OnNotificationsRequested` +Event Receiver: `SendNotificationsAPIHandler` + +##### Permissions + +The receiver will not process messages from not configured endpoints. + +Message updates will be dropped when: + +* Checkable does not exist. +* Origin endpoint's zone the same as the receiver. This binds notification messages to the HA zone. + +#### event::NotificationSentUser + +> Location: `clusterevents.cpp` + +##### Message Body + +Key | Value +----------|--------- +jsonrpc | 2.0 +method | event::NotificationSentUser +params | Dictionary + +##### Params + +Key | Type | Description +--------------|-----------------|------------------ +host | String | Host name +service | String | Service name +notification | String | Notification name. +user | String | Notified user name. +type | Number | enum NotificationType, same as `types` in Notification objects. +cr | Serialized CR | Check result. +author | String | Notification author (for specific types) +text | String | Notification text (for specific types) +command | String | Notification command name. + +##### Functions + +Event Sender: `Checkable::OnNotificationSentToUser` +Event Receiver: `NotificationSentUserAPIHandler` + +##### Permissions + +The receiver will not process messages from not configured endpoints. + +Message updates will be dropped when: + +* Checkable does not exist. +* Origin endpoint's zone the same as the receiver. This binds notification messages to the HA zone. + +#### event::NotificationSentToAllUsers + +> Location: `clusterevents.cpp` + +##### Message Body + +Key | Value +----------|--------- +jsonrpc | 2.0 +method | event::NotificationSentToAllUsers +params | Dictionary + +##### Params + +Key | Type | Description +----------------------------|-----------------|------------------ +host | String | Host name +service | String | Service name +notification | String | Notification name. +users | Array of String | Notified user names. +type | Number | enum NotificationType, same as `types` in Notification objects. +cr | Serialized CR | Check result. +author | String | Notification author (for specific types) +text | String | Notification text (for specific types) +last\_notification | Timestamp | Last notification time as UNIX timestamp. +next\_notification | Timestamp | Next scheduled notification time as UNIX timestamp. +notification\_number | Number | Current notification number in problem state. +last\_problem\_notification | Timestamp | Last problem notification time as UNIX timestamp. +no\_more\_notifications | Boolean | Whether to send future notifications when this notification becomes active on this HA node. + +##### Functions + +Event Sender: `Checkable::OnNotificationSentToAllUsers` +Event Receiver: `NotificationSentToAllUsersAPIHandler` + +##### Permissions + +The receiver will not process messages from not configured endpoints. + +Message updates will be dropped when: + +* Checkable does not exist. +* Origin endpoint's zone the same as the receiver. This binds notification messages to the HA zone. + +#### event::ExecuteCommand + +> Location: `clusterevents-check.cpp` and `checkable-check.cpp` + +##### Message Body + +Key | Value +----------|--------- +jsonrpc | 2.0 +method | event::ExecuteCommand +params | Dictionary + +##### Params + +Key | Type | Description +--------------|---------------|------------------ +host | String | Host name. +service | String | Service name. +command\_type | String | `check_command` or `event_command`. +command | String | CheckCommand or EventCommand name. +macros | Dictionary | Command arguments as key/value pairs for remote execution. + + +##### Functions + +**Event Sender:** This gets constructed directly in `Checkable::ExecuteCheck()` or `Checkable::ExecuteEventHandler()` when a remote command endpoint is configured. + +* `Get{CheckCommand,EventCommand}()->Execute()` simulates an execution and extracts all command arguments into the `macro` dictionary (inside lib/methods tasks). +* When the endpoint is connected, the message is constructed and sent directly. +* When the endpoint is not connected and not syncing replay logs and 5m after application start, generate an UNKNOWN check result for the user ("not connected"). + +**Event Receiver:** `ExecuteCommandAPIHandler` + +Special handling, calls `ClusterEvents::EnqueueCheck()` for command endpoint checks. +This function enqueues check tasks into a queue which is controlled in `RemoteCheckThreadProc()`. + +##### Permissions + +The receiver will not process messages from not configured endpoints. + +Message updates will be dropped when: + +* Origin endpoint's zone is not a parent zone of the receiver endpoint. +* `accept_commands = false` in the `api` feature configuration sends back an UNKNOWN check result to the sender. + +The receiver constructs a virtual host object and looks for the local CheckCommand object. + +Returns UNKNWON as check result to the sender + +* when the CheckCommand object does not exist. +* when there was an exception triggered from check execution, e.g. the plugin binary could not be executed or similar. + +The returned messages are synced directly to the sender's endpoint, no cluster broadcast. + +> **Note**: EventCommand errors are just logged on the remote endpoint. + +#### config::Update + +> Location: `apilistener-filesync.cpp` + +##### Message Body + +Key | Value +----------|--------- +jsonrpc | 2.0 +method | config::Update +params | Dictionary + +##### Params + +Key | Type | Description +-----------|---------------|------------------ +update | Dictionary | Config file paths and their content. +update\_v2 | Dictionary | Additional meta config files introduced in 2.4+ for compatibility reasons. + +##### Functions + +**Event Sender:** `SendConfigUpdate()` called in `ApiListener::SyncClient()` when a new client endpoint connects. +**Event Receiver:** `ConfigUpdateHandler` reads the config update content and stores them in `/var/lib/icinga2/api`. +When it detects a configuration change, the function requests and application restart. + +##### Permissions + +The receiver will not process messages from not configured endpoints. + +Message updates will be dropped when: + +* The origin sender is not in a parent zone of the receiver. +* `api` feature does not accept config. + +Config updates will be ignored when: + +* The zone is not configured on the receiver endpoint. +* The zone is authoritative on this instance (this only happens on a master which has `/etc/icinga2/zones.d` populated, and prevents sync loops) + +#### config::UpdateObject + +> Location: `apilistener-configsync.cpp` + +##### Message Body + +Key | Value +----------|--------- +jsonrpc | 2.0 +method | config::UpdateObject +params | Dictionary + +##### Params + +Key | Type | Description +---------------------|-------------|------------------ +name | String | Object name. +type | String | Object type name. +version | Number | Object version. +config | String | Config file content for `_api` packages. +modified\_attributes | Dictionary | Modified attributes at runtime as key value pairs. +original\_attributes | Array | Original attributes as array of keys. + + +##### Functions + +**Event Sender:** Either on client connect (full sync), or runtime created/updated object + +`ApiListener::SendRuntimeConfigObjects()` gets called when a new endpoint is connected +and runtime created config objects need to be synced. This invokes a call to `UpdateConfigObject()` +to only sync this JsonRpcConnection client. + +`ConfigObject::OnActiveChanged` (created or deleted) or `ConfigObject::OnVersionChanged` (updated) +also call `UpdateConfigObject()`. + +**Event Receiver:** `ConfigUpdateObjectAPIHandler` calls `ConfigObjectUtility::CreateObject()` in order +to create the object if it is not already existing. Afterwards, all modified attributes are applied +and in case, original attributes are restored. The object version is set as well, keeping it in sync +with the sender. + +##### Permissions + +###### Sender + +Client receiver connects: + +The sender only syncs config object updates to a client which can access +the config object, in `ApiListener::SendRuntimeConfigObjects()`. + +In addition to that, the client endpoint's zone is checked whether this zone may access +the config object. + +Runtime updated object: + +Only if the config object belongs to the `_api` package. + + +###### Receiver + +The receiver will not process messages from not configured endpoints. + +Message updates will be dropped when: + +* Origin sender endpoint's zone is in a child zone. +* `api` feature does not accept config +* The received config object type does not exist (this is to prevent failures with older nodes and new object types). + +Error handling: + +* Log an error if `CreateObject` fails (only if the object does not already exist) +* Local object version is newer than the received version, object will not be updated. +* Compare modified and original attributes and restore any type of change here. + + +#### config::DeleteObject + +> Location: `apilistener-configsync.cpp` + +##### Message Body + +Key | Value +----------|--------- +jsonrpc | 2.0 +method | config::DeleteObject +params | Dictionary + +##### Params + +Key | Type | Description +--------------------|-------------|------------------ +name | String | Object name. +type | String | Object type name. +version | Number | Object version. + +##### Functions + +**Event Sender:** + +`ConfigObject::OnActiveChanged` (created or deleted) or `ConfigObject::OnVersionChanged` (updated) +call `DeleteConfigObject()`. + +**Event Receiver:** `ConfigDeleteObjectAPIHandler` + +##### Permissions + +###### Sender + +Runtime deleted object: + +Only if the config object belongs to the `_api` package. + +###### Receiver + +The receiver will not process messages from not configured endpoints. + +Message updates will be dropped when: + +* Origin sender endpoint's zone is in a child zone. +* `api` feature does not accept config +* The received config object type does not exist (this is to prevent failures with older nodes and new object types). +* The object in question was not created at runtime, it does not belong to the `_api` package. + +Error handling: + +* Log an error if `DeleteObject` fails (only if the object does not already exist) + +#### pki::RequestCertificate + +> Location: `jsonrpcconnection-pki.cpp` + +##### Message Body + +Key | Value +----------|--------- +jsonrpc | 2.0 +method | pki::RequestCertificate +params | Dictionary + +##### Params + +Key | Type | Description +--------------|---------------|------------------ +ticket | String | Own ticket, or as satellite in CA proxy from local store. +cert\_request | String | Certificate request content from local store, optional. + +##### Functions + +Event Sender: `RequestCertificateHandler` +Event Receiver: `RequestCertificateHandler` + +##### Permissions + +This is an anonymous request, and the number of anonymous clients can be configured +in the `api` feature. + +Only valid certificate request messages are processed, and valid signed certificates +won't be signed again. + +#### pki::UpdateCertificate + +> Location: `jsonrpcconnection-pki.cpp` + +##### Message Body + +Key | Value +----------|--------- +jsonrpc | 2.0 +method | pki::UpdateCertificate +params | Dictionary + +##### Params + +Key | Type | Description +---------------------|---------------|------------------ +status\_code | Number | Status code, 0=ok. +cert | String | Signed certificate content. +ca | String | Public CA certificate content. +fingerprint\_request | String | Certificate fingerprint from the CSR. + + +##### Functions + +**Event Sender:** + +* When a client requests a certificate in `RequestCertificateHandler` and the satellite +already has a signed certificate, the `pki::UpdateCertificate` message is constructed and sent back. +* When the endpoint holding the master's CA private key (and TicketSalt private key) is able to sign +the request, the `pki::UpdateCertificate` message is constructed and sent back. + +**Event Receiver:** `UpdateCertificateHandler` + +##### Permissions + +Message updates are dropped when + +* The origin sender is not in a parent zone of the receiver. +* The certificate fingerprint is in an invalid format. + +#### log::SetLogPosition + +> Location: `apilistener.cpp` and `jsonrpcconnection.cpp` + +##### Message Body + +Key | Value +----------|--------- +jsonrpc | 2.0 +method | log::SetLogPosition +params | Dictionary + +##### Params + +Key | Type | Description +--------------------|---------------|------------------ +log\_position | Timestamp | The endpoint's log position as UNIX timestamp. + + +##### Functions + +**Event Sender:** + +During log replay to a client endpoint in `ApiListener::ReplayLog()`, each processed +file generates a message which updates the log position timestamp. + +`ApiListener::ApiTimerHandler()` invokes a check to keep all connected endpoints and +their log position in sync during replay log. + +**Event Receiver:** `SetLogPositionHandler` + +##### Permissions + +The receiver will not process messages from not configured endpoints.