diff --git a/doc/13-distributed-monitoring-ha.md b/doc/13-distributed-monitoring-ha.md index 6022ec090..8a8348dd1 100644 --- a/doc/13-distributed-monitoring-ha.md +++ b/doc/13-distributed-monitoring-ha.md @@ -416,7 +416,7 @@ The configuration synchronisation works with multiple hierarchies. The following illustrate a quite common setup where the master is reponsible for configuration deployment: * [High-Availability master zone](13-distributed-monitoring-ha.md#distributed-monitoring-high-availability) -* [Distributed satellites](12-distributed-monitoring-ha.md#) +* [Distributed satellites](13-distributed-monitoring-ha.md#cluster-scenarios-distributed-zones) * [Remote clients](11-icinga2-client.md#icinga2-client-scenarios) connected to the satellite While you could use the clients with local configuration and service discovery on the satellite/master diff --git a/doc/5-advanced-topics.md b/doc/5-advanced-topics.md index 95c9a5635..eefa3fad4 100644 --- a/doc/5-advanced-topics.md +++ b/doc/5-advanced-topics.md @@ -508,18 +508,3 @@ It may be reasonable to have a volatile service which stays in a `HARD` state type if the service stays in a `NOT-OK` state. That way each service recheck will automatically trigger a notification unless the service is acknowledged or in a scheduled downtime. - -## Icinga 2 API - -The Icinga 2 API allows you to manage configuration objects -and resources in a simple, programmatic way using HTTP requests. - -More details can be found in [this chapter](9-icinga2-api.md#icinga2-api). - -## Icinga 2 Feature Configuration - -Icinga 2 provides several features which can be enabled using [CLI commands](8-cli-commands.md#cli-command-feature). - -More details can be found in [this chapter](15-features.md#icinga2-features). - - diff --git a/doc/6-object-types.md b/doc/6-object-types.md index 03732b019..4ee2814b6 100644 --- a/doc/6-object-types.md +++ b/doc/6-object-types.md @@ -1471,7 +1471,7 @@ Configuration Attributes: In addition to [expressions](18-language-reference.md#expressions) used in object attribute assignments such as -* [Numeric](18-language-reference.md#numeric-literals), [duration](8-language-reference.md#duration-literals), [string](18-language-reference.md#string-literals) and [boolean](18-language-reference.md#boolean-literals) literals +* [Numeric](18-language-reference.md#numeric-literals), [duration](18-language-reference.md#duration-literals), [string](18-language-reference.md#string-literals) and [boolean](18-language-reference.md#boolean-literals) literals * [Array](18-language-reference.md#array) * [Dictionary](18-language-reference.md#dictionary) diff --git a/doc/8-cli-commands.md b/doc/8-cli-commands.md index b23057e2b..1683b81a8 100644 --- a/doc/8-cli-commands.md +++ b/doc/8-cli-commands.md @@ -138,10 +138,10 @@ added. ## CLI command: Console The CLI command `console` can be used to evaluate Icinga config expressions, e.g. to test -`assign where` rules. +[functions](18-language-reference.md#functions). $ icinga2 console - Icinga (version: v2.2.0-435-gc95d2f1) + Icinga 2 (version: v2.4.0) <1> => function test(name) { <1> .. log("Hello " + name) <1> .. } @@ -149,12 +149,93 @@ The CLI command `console` can be used to evaluate Icinga config expressions, e.g <2> => test("World") information/config: Hello World null + <3> => -The `console` command does not support line-editing or a command history. However you can + +On operating systems without the `libedit` library installed there is no +support line-editing or a command history. However you can use the `rlwrap` program if you require those features: $ rlwrap icinga2 console +The `console` can be used to connect to a running Icinga 2 instance using +the [REST API](9-icinga2-api.md#icinga2-api). [API permissions](9-icinga2-api.md#icinga2-api-permissions) +are required for executing config expressions and auto-completion. + +The `--connect` parameter expects the API URL as string, optionally with basic auth credentials: + + $ icinga2 console --connect 'https://root:icinga@localhost:5665/' + Icinga 2 (version: v2.4.0) + <1> => + +Example using [object accessor functions](19-library-reference.md#object-accessor-functions) +to fetch the host object for the local node and print its `last_check_result` attribute: + + <1> => NodeName + "icinga2-node1.localdomain" + <2> => get_host(NodeName).last_check_result + { + active = true + check_source = "icinga2-node1.localdomain" + command = [ "/usr/local/sbin/check_ping", "-H", "127.0.0.1", "-c", "5000,100%", "-w", "3000,80%" ] + execution_end = 1446716536.250887 + execution_start = 1446716532.222686 + exit_status = 0.000000 + output = "PING OK - Packet loss = 0%, RTA = 0.08 ms" + performance_data = [ "rta=0.076000ms;3000.000000;5000.000000;0.000000", "pl=0%;80;100;0" ] + schedule_end = 1446716536.250992 + schedule_start = 1446716592.210000 + state = 0.000000 + type = "CheckResult" + vars_after = { + attempt = 1.000000 + reachable = true + state = 0.000000 + state_type = 1.000000 + } + vars_before = { + attempt = 1.000000 + reachable = true + state = 0.000000 + state_type = 1.000000 + } + } + <3> => + +In order to evaluate a single config expression use the `--eval` +parameter. The following example prints the command line from +the local node's last check result: + + $ icinga2 console --connect 'https://root:icinga@localhost:5665/' --eval "get_host(NodeName).last_check_result.command" | python -m json.tool + [ + "/usr/local/sbin/check_ping", + "-H", + "127.0.0.1", + "-c", + "5000,100%", + "-w", + "3000,80%" + ] + + +The following environment variables can be exported to the +user's environment instead of adding them to the `--connect` parameter: + + Environment Variable | Description + ----------------------|-------------------------- + ICINGA2_API_USERNAME | Basic auth username. + ICINGA2_API_PASSWORD | Basic auth password. + ICINGA2_API_URL | URL with or without basic auth credentials. + +Example: + + $ export ICINGA2_API_USERNAME=root + $ export ICINGA2_API_PASSWORD=icinga + + $ icinga2 console --connect 'https://localhost:5665/' + Icinga 2 (version: v2.4.0) + <1> => + ## CLI command: Daemon The CLI command `daemon` provides the functionality to start/stop Icinga 2. diff --git a/doc/9-icinga2-api.md b/doc/9-icinga2-api.md index 349f27991..5d45f2dbb 100644 --- a/doc/9-icinga2-api.md +++ b/doc/9-icinga2-api.md @@ -140,10 +140,23 @@ Once the API user is configured make sure to restart Icinga 2: You can test authentication by sending a GET request to the API: - $ curl -u root:icinga -k -s 'https://localhost:5665/v1' + $ curl -k -s -u root:icinga 'https://localhost:5665/v1' In case you get an error message make sure to check the API user credentials. +The curl parameter `-k` disables the master certificate verification. In order +to securely check each connection you'll need to pass the trusted CA certificate +using the curl parameter`--cacert`: + + $ curl -u root:icinga --cacert ca.crt 'icinga2.node1.localdomain:5665/v1' + +Using client certificates you'll need to pass your client certificate +and the trusted CA certificate from your Icinga 2 instance to the curl call: + + $ curl --cert icinga2-node1.localdomain.crt --key icinga2-node1.localdomain.key --cacert ca.crt 'https://icinga2-node1.localdomain:5665/v1/status' + +In case of an error make sure to verify the client certificate and CA. + Read the next chapter on [API permissions](9-icinga2-api.md#icinga2-api-permissions) in order to authorize the newly created API user. @@ -196,6 +209,7 @@ Available permissions for specific URL endpoints: objects/delete/<type> | /v1/objects status/query | /v1/status events/<type> | /v1/events + console/* | /v1/console The required actions or types can be replaced by using a wildcard match ("*"). @@ -213,11 +227,11 @@ as query string, e.g. a space becomes `%20`. Example for an URL-encoded query string: - /v1/objects/hosts?filter=match(%22nbmif*%22,host.name)&attrs=host.name&attrs=host.state + /v1/objects/hosts?filter=match(%22icinga2-node1.localdomain*%22,host.name)&attrs=host.name&attrs=host.state Example for a JSON body: - { "attrs": { "address": "8.8.4.4", "vars.os" : "Windows" } } + { "templates": [ "generic-host" ], "attrs": { "address": "8.8.8.8", "check_command": "hostalive", "vars.os" : "Linux" } } Selecting a single object as URL parameter: @@ -248,7 +262,7 @@ Example matching all services in NOT-OK state: Example matching all hosts by name: - https://localhost:5665/v1/objects/hosts?filter=match("nbmif*",host.name) + https://localhost:5665/v1/objects/hosts?filter=match("icinga2-node1.localdomain*",host.name) Example for all hosts being a member of the host group `linux-servers`: @@ -275,8 +289,9 @@ The Icinga 2 API provides multiple URL endpoints: /v1/events | Endpoint for subscribing to [API events](9-icinga2-api.md#icinga2-api-actions). /v1/status | Endpoint for receiving the global Icinga 2 [status and statistics](9-icinga2-api.md#icinga2-api-status). /v1/objects | Endpoint for querying, creating, modifying and deleting [config objects](9-icinga2-api.md#icinga2-api-config-objects). - /v1/types | Endpoint for listing Icinga 2 configuration object types and their attributes. /v1/config | Endpoint for [managing configuration modules](9-icinga2-api.md#icinga2-api-config-management). + /v1/types | Endpoint for listing Icinga 2 configuration object types and their attributes. + /v1/console | Endpoint for connecting the [Icinga 2 console](9-icinga2-api.md#icinga2-api-clients-cli-console) Please check the respective sections for detailed URL information and parameters. @@ -931,7 +946,7 @@ configuration can be found [here](13-distributed-monitoring-ha.md#distributed-mo Send a `GET` request to `/v1/objects/hosts` to list all host objects and their attributes. - $ curl -u root:icinga -k -s 'https://localhost:5665/v1/objects/hosts' + $ curl -k -s -u root:icinga 'https://localhost:5665/v1/objects/hosts' This works in a similar fashion for other [config objects](9-icinga2-api.md#icinga2-api-config-objects). @@ -954,7 +969,7 @@ If attributes are of the Dictionary type, you can also use the indexer format: Example for creating the new host object `google.com`: - $ curl -u root:icinga -k -s 'https://localhost:5665/v1/objects/hosts/google.com' \ + $ curl -k -s -u root:icinga 'https://localhost:5665/v1/objects/hosts/google.com' \ -X PUT \ -d '{ "templates": [ "generic-host" ], "attrs": { "address": "8.8.8.8", "check_command": "hostalive", "vars.os" : "Linux" } }' \ | python -m json.tool @@ -973,7 +988,7 @@ If the configuration validation fails, the new object will not be created and th contains a detailed error message. The following example omits the `check_command` attribute required by the host object. - $ curl -u root:icinga -k -s 'https://localhost:5665/v1/objects/hosts/google.com' \ + $ curl -k -s -u root:icinga 'https://localhost:5665/v1/objects/hosts/google.com' \ -X PUT \ -d '{ "attrs": { "address": "8.8.8.8", "vars.os" : "Linux" } }' \ | python -m json.tool @@ -996,12 +1011,12 @@ Send a `GET` request including the object name inside the URL. Example for the host `google.com`: - $ curl -u root:icinga -k -s 'https://localhost:5665/v1/objects/hosts/google.com' + $ curl -k -s -u root:icinga 'https://localhost:5665/v1/objects/hosts/google.com' You can select specific attributes by adding them as url parameters using `?attrs=...`. Multiple attributes must be added one by one, e.g. `?attrs=host.address&attrs=host.name`. - $ curl -u root:icinga -k -s 'https://localhost:5665/v1/objects/hosts/google.com?attrs=host.name&attrs=host.address' | python -m json.tool + $ curl -k -s -u root:icinga 'https://localhost:5665/v1/objects/hosts/google.com?attrs=host.name&attrs=host.address' | python -m json.tool { "results": [ { @@ -1033,7 +1048,7 @@ If attributes are of the Dictionary type, you can also use the indexer format: Example for existing object `google.com`: - $ curl -u root:icinga -k -s 'https://localhost:5665/v1/objects/hosts/google.com' \ + $ curl -k -s -u root:icinga 'https://localhost:5665/v1/objects/hosts/google.com' \ -X POST \ -d '{ "attrs": { "address": "8.8.4.4", "vars.os" : "Windows" } }' \ | python -m json.tool @@ -1063,7 +1078,7 @@ to pass the `cascade` parameter on host object deletion. Example for deleting the host object `google.com`: - $ curl -u root:icinga -k -s 'https://localhost:5665/v1/objects/hosts/google.com?cascade=1' -X DELETE | python -m json.tool + $ curl -k -s -u root:icinga 'https://localhost:5665/v1/objects/hosts/google.com?cascade=1' -X DELETE | python -m json.tool { "results": [ { @@ -1089,15 +1104,15 @@ can be fetched in a separated request. ### Create Config Package -Send a `POST` request to a new config package called `puppet` in this example. This +Send a `POST` request to a new config package called `example-cmdb` in this example. This will create a new empty configuration package. - $ curl -k -s -u root:icinga -X POST https://localhost:5665/v1/config/packages/puppet | python -m json.tool + $ curl -k -s -u root:icinga -X POST https://localhost:5665/v1/config/packages/example-cmdb | python -m json.tool { "results": [ { "code": 200.0, - "package": "puppet", + "package": "example-cmdb", "status": "Created package." } ] @@ -1107,7 +1122,7 @@ will create a new empty configuration package. ### Create Configuration to Package Stage Send a `POST` request to the URL endpoint `/v1/config/stages` including an existing -configuration package, e.g. `puppet`. +configuration package, e.g. `example-cmdb`. The request body must contain the `files` attribute with the value being a dictionary of file targets and their content. @@ -1118,13 +1133,13 @@ generates a unique name for the `package` attribute you'll need for later reques Note: This example contains an error (`chec_command`), do not blindly copy paste it. - $ curl -k -s -u root:icinga -X POST -d '{ "files": { "conf.d/test.conf": "object Host \"cfg-mgmt\" { chec_command = \"dummy\" }" } }' https://localhost:5665/v1/config/stages/puppet | python -m json.tool + $ curl -k -s -u root:icinga -X POST -d '{ "files": { "conf.d/test.conf": "object Host \"cfg-mgmt\" { chec_command = \"dummy\" }" } }' https://localhost:5665/v1/config/stages/example-cmdb | python -m json.tool { "results": [ { "code": 200.0, - "package": "puppet", - "stage": "nbmif-1441625839-0", + "package": "example-cmdb", + "stage": "icinga2-node1.localdomain-1441625839-0", "status": "Created stage." } ] @@ -1153,7 +1168,7 @@ List all config packages, their active stage and other stages. That way you may iterate of all of them programmatically for older revisions and their requests. -The following example contains one configuration package `puppet`. +The following example contains one configuration package `example-cmdb`. The latter already has a stage created, but it is not active. $ curl -k -s -u root:icinga https://localhost:5665/v1/config/packages | python -m json.tool @@ -1161,9 +1176,9 @@ The latter already has a stage created, but it is not active. "results": [ { "active-stage": "", - "name": "puppet", + "name": "example-cmdb", "stages": [ - "nbmif-1441625839-0" + "icinga2-node1.localdomain-1441625839-0" ] } ] @@ -1173,9 +1188,9 @@ The latter already has a stage created, but it is not active. ### List Configuration Packages and their Stages Sent a `GET` request to the URL endpoint `/v1/config/stages` including the package -(`puppet`) and stage (`nbmif-1441625839-0`) name. +(`example-cmdb`) and stage (`icinga2-node1.localdomain-1441625839-0`) name. - $ curl -k -s -u root:icinga https://localhost:5665/v1/config/stages/puppet/nbmif-1441625839-0 | python -m json.tool + $ curl -k -s -u root:icinga https://localhost:5665/v1/config/stages/example-cmdb/icinga2-node1.localdomain-1441625839-0 | python -m json.tool { "results": [ ... @@ -1212,10 +1227,10 @@ Note: You cannot use dots in paths. You can fetch a [list of existing files](9-icinga2-api.md#icinga2-api-config-management-list-config-package-stage-files) in a configuration stage and then specifically request their content. -The following example fetches the faulty configuration inside `conf.d/test.conf` +The following example fetches the **erroneous** configuration inside `conf.d/test.conf` for further analysis. - $ curl -k -s -u root:icinga https://localhost:5665/v1/config/files/puppet/nbmif-1441625839-0/conf.d/test.conf + $ curl -k -s -u root:icinga https://localhost:5665/v1/config/files/example-cmdb/icinga2-node1.localdomain-1441625839-0/conf.d/test.conf object Host "cfg-mgmt" { chec_command = "dummy" } Note: The returned files are plain-text instead of JSON-encoded. @@ -1223,20 +1238,232 @@ Note: The returned files are plain-text instead of JSON-encoded. ### Configuration Package Stage Errors -Now that we don't have an active stage for `puppet` yet seen [here](9-icinga2-api.md#icinga2-api-config-management-list-config-packages), +Now that we don't have an active stage for `example-cmdb` yet seen [here](9-icinga2-api.md#icinga2-api-config-management-list-config-packages), there must have been an error. Fetch the `startup.log` file and check the config validation errors: - $ curl -k -s -u root:icinga https://localhost:5665/v1/config/files/puppet/imagine-1441133065-1/startup.log + $ curl -k -s -u root:icinga https://localhost:5665/v1/config/files/example-cmdb/imagine-1441133065-1/startup.log ... critical/config: Error: Attribute 'chec_command' does not exist. Location: - /var/lib/icinga2/api/packages/puppet/imagine-1441133065-1/conf.d/test.conf(1): object Host "cfg-mgmt" { chec_command = "dummy" } + /var/lib/icinga2/api/packages/example-cmdb/imagine-1441133065-1/conf.d/test.conf(1): object Host "cfg-mgmt" { chec_command = "dummy" } ^^^^^^^^^^^^^^^^^^^^^^ critical/config: 1 error The output is similar to the manual [configuration validation](8-cli-commands.md#config-validation). + +## API Clients + +There's a couple of existing clients using the Icinga 2 API +for various use cases: + +* [curl](http://curl.haxx.se) +* [console cli command](9-icinga2-api.md#icinga2-api-clients-cli-console) +* [Icinga Studio](9-icinga2-api.md#icinga2-api-clients-icinga-studio) +* [Icinga Web 2 Director](https://dev.icinga.org/projects/icingaweb2-modules) + +Demo cases: + +* [Dashing](https://github.com/Icinga/dashing-icinga2) +* [AWS host creation/update/deletion](https://github.com/Icinga/aws-icinga2) + +Additional [programmatic examples](9-icinga2-api.md#icinga2-api-clients-programmatic-examples) +will help you getting started using the Icinga 2 API in your environment. + +### Icinga Studio + +Icinga Studio is a graphical application to query configuration objects provided by the API. + +![Icinga Studio Connection](images/icinga2-api/icinga2_api_icinga_studio_connect.png) + +![Icinga Studio Overview](images/icinga2-api/icinga2_api_icinga_studio_overview.png) + +Please check the package repository of your distribution for available +packages. + +The Windows installer includes Icinga Studio already. You must additionally +install the [WxWidgets library](https://www.wxwidgets.org/downloads/). + +### Console Command using the API + +The [console cli command](8-cli-commands.md#cli-command-console) accepts the API URL as `--connect` parameter. Note: You can omit the +username and/or password string and use the environment variables `ICINGA2_API_USERNAME` +and `ICINGA2_API_PASSWORD` instead. + + $ icinga2 console --connect 'https://root:icinga@localhost:5665/' + Icinga 2 (version: v2.3.11-762-g1d327ac) + <1> => + +Once connected fetch the host object and print its attribute `last_check_result`. +Tip: On systems with enabled auto-completion press . + + <1> => h = get_host("mbmif.int.netways.de") + null + <2> => h.last_check_result + { + active = true + check_source = "mbmif.int.netways.de" + command = [ "/usr/local/sbin/check_ping", "-H", "127.0.0.1", "-c", "5000,100%", "-w", "3000,80%" ] + execution_end = 1446653527.174983 + execution_start = 1446653523.152673 + exit_status = 0.000000 + output = "PING OK - Packet loss = 0%, RTA = 0.11 ms" + performance_data = [ "rta=0.114000ms;3000.000000;5000.000000;0.000000", "pl=0%;80;100;0" ] + schedule_end = 1446653527.175133 + schedule_start = 1446653583.150000 + state = 0.000000 + type = "CheckResult" + vars_after = { + attempt = 1.000000 + reachable = true + state = 0.000000 + state_type = 1.000000 + } + vars_before = { + attempt = 1.000000 + reachable = true + state = 0.000000 + state_type = 1.000000 + } + } + <3> => + + +Use the `--eval` parameter to evaluate a single expression in batch mode. The +following example fetches the local node object and its check result: + + $ icinga2 console --connect 'https://root:icinga@localhost:5665/' --eval "get_host(NodeName).last_check_result.command" | python -m json.tool + [ + "/usr/local/sbin/check_ping", + "-H", + "127.0.0.1", + "-c", + "5000,100%", + "-w", + "3000,80%" + ] + +### API Clients Programmatic Examples + +#### Example API Client using Python + +Example for **Python** using the `requests` and `json` module: + + # pip install requests + # pip install json + + $ vim icinga2-api-example.py + + #!/usr/bin/env python + + import requests, json + + request_url = "https://localhost:5665/v1/status" + headers = {"Content-Type": "application/json", "Accept": "application/json"} + r = requests.get(request_url, headers=headers, auth=('root', 'icinga'), verify=False) + + print "Status code: " + str(r.status_code) + print "Result: " + json.dumps(r.json()) + + $ python icinga2-api-example.py + + +#### Example API Client using Ruby + +Example for **Ruby** using the `rest_client` gem: + + # gem install rest_client + + $ vim icinga2-api-example.rb + + #!/usr/bin/ruby + + require 'rest_client' + + request_url = "https://localhost:5665/v1/status" + options = { :user => "root", :password => "icinga", :verify_ssl => OpenSSL::SSL::VERIFY_NONE } + headers = {"Content-Type" => "application/json", "Accept" => "application/json"} + r = RestClient::Resource.new(URI.encode(request_url), options) + response = r.get(headers) + + puts "Status: " + response.code.to_s + puts "Result: " + (JSON.pretty_generate JSON.parse(response.body)) + + $ ruby icinga2-api-example.rb + +A more detailed example can be found in the [Dashing demo](https://github.com/Icinga/dashing-icinga2). + +#### Example API Client using PHP + +Example for **PHP** using `curl`: + + $ vim icinga2-api-example.php + + #!/usr/bin/env php + + + $ php icinga2-api-example.php + +#### Example API Client using Perl + +Example for **Perl** using the `Rest::Client` module: + + # perl -MCPAN -e 'install REST::Client' + # perl -MCPAN -e 'install JSON' + # perl -MCPAN -e 'install MIME::Base64' + + $ vim icinga2-api-example.pl + + #!/usr/bin/env perl + + use REST::Client; + use MIME::Base64; + use JSON; + + $ENV{PERL_LWP_SSL_VERIFY_HOSTNAME}=0; + + $userpass = "root:icinga"; + my $client = REST::Client->new(); + $client->setHost("https://127.0.0.1:5665"); + $client->addHeader("Content-Type", "application/json"); + $client->addHeader("Accept", "application/json"); + $client->addHeader("Authorization", "Basic ".encode_base64($userpass)); + $client->GET("/v1/status"); + + print "Status: " . $client->responseCode() . "\n"; + print "Result: " . $client->responseContent() . "\n"; + + $ perl icinga2-api-example.pl + + diff --git a/doc/images/icinga2-api/icinga2_api_icinga_studio_connect.png b/doc/images/icinga2-api/icinga2_api_icinga_studio_connect.png new file mode 100644 index 000000000..dadfd4560 Binary files /dev/null and b/doc/images/icinga2-api/icinga2_api_icinga_studio_connect.png differ diff --git a/doc/images/icinga2-api/icinga2_api_icinga_studio_overview.png b/doc/images/icinga2-api/icinga2_api_icinga_studio_overview.png new file mode 100644 index 000000000..5af1b5678 Binary files /dev/null and b/doc/images/icinga2-api/icinga2_api_icinga_studio_overview.png differ