Merge branch 'master' into support/2.11

This commit is contained in:
Michael Friedrich 2019-09-18 12:28:40 +02:00
commit 316d2dc762
120 changed files with 4363 additions and 1168 deletions

View File

@ -8,11 +8,13 @@ assignees: ''
---
## Describe the bug
A clear and concise description of what the bug is.
Please ensure to read https://github.com/Icinga/icinga2/blob/master/doc/15-troubleshooting.md first. Formatting tips: GitHub supports Markdown: https://guides.github.com/features/mastering-markdown/
Please ensure to read https://github.com/Icinga/icinga2/blob/master/doc/15-troubleshooting.md first. Formatting tips: GitHub supports Markdown: https://guides.github.com/features/mastering-markdown/
## To Reproduce
Provide a link to a live example, or an unambiguous set of steps to reproduce this bug. Include configuration, logs, etc. to reproduce, if relevant.
1.
@ -21,12 +23,15 @@ Provide a link to a live example, or an unambiguous set of steps to reproduce th
4.
## Expected behavior
A clear and concise description of what you expected to happen.
## Screenshots
If applicable, add screenshots to help explain your problem.
## Your Environment
Include as many relevant details about the environment you experienced the problem in
* Version used (`icinga2 --version`):
@ -37,4 +42,5 @@ Include as many relevant details about the environment you experienced the probl
* If you run multiple Icinga 2 instances, the `zones.conf` file (or `icinga2 object list --type Endpoint` and `icinga2 object list --type Zone`) from all affected nodes.
## Additional context
Add any other context about the problem here.

View File

@ -8,13 +8,17 @@ assignees: ''
---
## Is your feature request related to a problem? Please describe.
A clear and concise description of what the problem is. Ex. I'm always using this feature but am missing [...]
## Describe the solution you'd like
A clear and concise description of what you want to happen.
A clear and concise description of what you want to happen.
## Describe alternatives you've considered
A clear and concise description of any alternative solutions or features you've considered.
## Additional context
Add any other context or screenshots about the feature request here.

View File

@ -240,7 +240,7 @@ endif()
if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
if(CMAKE_SYSTEM_NAME MATCHES AIX)
set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -g -lpthread")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -lpthread")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -lpthread")
elseif(CMAKE_SYSTEM_NAME MATCHES "kOpenBSD.*|OpenBSD.*")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -pthread")
@ -314,7 +314,7 @@ if(ICINGA2_LTO_BUILD)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -flto")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -flto")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -flto")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -flto")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -flto")
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND NOT (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9.0) AND NOT OPENBSD)
set(CMAKE_AR "gcc-ar")
@ -390,12 +390,12 @@ if(NOT MSVC)
)
if (RESULT)
message(FATAL_ERROR "Failed to detect target architecture: ${RESULT}")
message(STATUS "Failed to detect target architecture with compiler ${CMAKE_C_COMPILER}: ${RESULT}")
endif()
string(REGEX MATCH "([^-]+).*" ARCH_MATCH ${ARCH})
string(REGEX MATCH "([^-]+).*" ARCH_MATCH "${ARCH}")
if (NOT CMAKE_MATCH_1 OR NOT ARCH_MATCH)
message(FATAL_ERROR "Failed to match the target architecture: ${ARCH}")
message(STATUS "Failed to match the target architecture: ${ARCH}")
endif()
set(ARCH ${CMAKE_MATCH_1})

View File

@ -16,25 +16,33 @@
## About
[Icinga 2](https://icinga.com/products/icinga-2/) is a monitoring system which checks
[Icinga](https://icinga.com/products/) is a monitoring system which checks
the availability of your network resources, notifies users of outages, and generates
performance data for reporting.
Scalable and extensible, Icinga 2 can monitor large, complex environments across
Scalable and extensible, Icinga can monitor large, complex environments across
multiple locations.
Icinga 2 as core requires [Icinga Web 2](https://icinga.com/products/icinga-web-2/)
on top in your Icinga Stack.
Icinga 2 is the monitoring server and requires [Icinga Web 2](https://icinga.com/products/)
on top in your Icinga Stack. The [configuration](https://icinga.com/products/configuration/)
can be easily managed with either the [Icinga Director](https://icinga.com/docs/director/latest/),
config management tools or plain text within the [Icinga DSL](https://icinga.com/docs/icinga2/latest/doc/17-language-reference/).
![Icinga Dashboard](https://icinga.com/wp-content/uploads/2017/12/icingaweb2-2.5.0-dashboard.png)
## Installation
For installing Icinga please check the [installation chapter](https://icinga.com/docs/icinga2/latest/doc/02-getting-started/)
in the documentation.
* [Installation](https://icinga.com/docs/icinga2/latest/doc/02-installation/)
* [Monitoring Basics](https://icinga.com/docs/icinga2/latest/doc/03-monitoring-basics/)
* [Configuration](https://icinga.com/docs/icinga2/latest/doc/04-configuration/)
* [Distributed Monitoring](https://icinga.com/docs/icinga2/latest/doc/06-distributed-monitoring/)
* [Addons, Integrations and Features](https://icinga.com/docs/icinga2/latest/doc/13-addons/)
* [Troubleshooting](https://icinga.com/docs/icinga2/latest/doc/15-troubleshooting/)
* [Upgrading](https://icinga.com/docs/icinga2/latest/doc/16-upgrading-icinga-2/)
If you are a packager, please read the [development chapter](https://icinga.com/docs/icinga2/latest/doc/21-development/)
for more details.
Once Icinga Server and Web are running in your distributed environment,
make sure to check out the many [Icinga modules](https://icinga.com/docs/)
for even better monitoring.
## Documentation
@ -74,6 +82,9 @@ contribution is appreciated!
Please continue reading in the [contributing chapter](CONTRIBUTING.md).
If you are a packager, please read the [development chapter](https://icinga.com/docs/icinga2/latest/doc/21-development/)
for more details.
### Security Issues
For reporting security issues please visit [this page](https://icinga.com/contact/security/).

View File

@ -10,7 +10,7 @@ using System.Runtime.InteropServices;
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Icinga GmbH")]
[assembly: AssemblyProduct("Icinga 2")]
[assembly: AssemblyCopyright("Copyright © 2014 Icinga GmbH")]
[assembly: AssemblyCopyright("Copyright © 2019 Icinga GmbH")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

View File

@ -65,7 +65,7 @@ namespace Icinga.Properties {
/// </summary>
internal static System.Drawing.Bitmap icinga_banner {
get {
object obj = ResourceManager.GetObject("icinga-banner", resourceCulture);
object obj = ResourceManager.GetObject("icinga_banner", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}

View File

@ -118,7 +118,7 @@
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="icinga-banner" type="System.Resources.ResXFileRef, System.Windows.Forms">
<data name="icinga_banner" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\icinga-banner.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
</root>

View File

@ -28,95 +28,95 @@
/// </summary>
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ServiceStatus));
this.picBanner = new System.Windows.Forms.PictureBox();
this.lblStatus = new System.Windows.Forms.Label();
this.txtStatus = new System.Windows.Forms.TextBox();
this.btnReconfigure = new System.Windows.Forms.Button();
this.btnOK = new System.Windows.Forms.Button();
this.btnOpenConfigDir = new System.Windows.Forms.Button();
((System.ComponentModel.ISupportInitialize)(this.picBanner)).BeginInit();
this.SuspendLayout();
//
// picBanner
//
this.picBanner.Image = global::Icinga.Properties.Resources.icinga_banner;
this.picBanner.Location = new System.Drawing.Point(0, 0);
this.picBanner.Name = "picBanner";
this.picBanner.Size = new System.Drawing.Size(625, 77);
this.picBanner.TabIndex = 2;
this.picBanner.TabStop = false;
//
// lblStatus
//
this.lblStatus.AutoSize = true;
this.lblStatus.Location = new System.Drawing.Point(12, 105);
this.lblStatus.Name = "lblStatus";
this.lblStatus.Size = new System.Drawing.Size(79, 13);
this.lblStatus.TabIndex = 3;
this.lblStatus.Text = "Service Status:";
//
// txtStatus
//
this.txtStatus.Location = new System.Drawing.Point(97, 102);
this.txtStatus.Name = "txtStatus";
this.txtStatus.ReadOnly = true;
this.txtStatus.Size = new System.Drawing.Size(278, 20);
this.txtStatus.TabIndex = 3;
//
// btnReconfigure
//
this.btnReconfigure.Location = new System.Drawing.Point(195, 143);
this.btnReconfigure.Name = "btnReconfigure";
this.btnReconfigure.Size = new System.Drawing.Size(89, 23);
this.btnReconfigure.TabIndex = 1;
this.btnReconfigure.Text = "Reconfigure";
this.btnReconfigure.UseVisualStyleBackColor = true;
this.btnReconfigure.Click += new System.EventHandler(this.btnReconfigure_Click);
//
// btnOK
//
this.btnOK.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.btnOK.Location = new System.Drawing.Point(290, 143);
this.btnOK.Name = "btnOK";
this.btnOK.Size = new System.Drawing.Size(89, 23);
this.btnOK.TabIndex = 0;
this.btnOK.Text = "OK";
this.btnOK.UseVisualStyleBackColor = true;
this.btnOK.Click += new System.EventHandler(this.btnOK_Click);
//
// btnOpenConfigDir
//
this.btnOpenConfigDir.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.btnOpenConfigDir.Location = new System.Drawing.Point(100, 143);
this.btnOpenConfigDir.Name = "btnOpenConfigDir";
this.btnOpenConfigDir.Size = new System.Drawing.Size(89, 23);
this.btnOpenConfigDir.TabIndex = 2;
this.btnOpenConfigDir.Text = "Examine Config";
this.btnOpenConfigDir.UseVisualStyleBackColor = true;
this.btnOpenConfigDir.Click += new System.EventHandler(this.btnOpenConfigDir_Click);
//
// ServiceStatus
//
this.AcceptButton = this.btnOK;
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.CancelButton = this.btnOK;
this.ClientSize = new System.Drawing.Size(391, 186);
this.Controls.Add(this.btnOpenConfigDir);
this.Controls.Add(this.btnOK);
this.Controls.Add(this.btnReconfigure);
this.Controls.Add(this.txtStatus);
this.Controls.Add(this.lblStatus);
this.Controls.Add(this.picBanner);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.MaximizeBox = false;
this.Name = "ServiceStatus";
this.Text = "Icinga 2 Service Status";
((System.ComponentModel.ISupportInitialize)(this.picBanner)).EndInit();
this.ResumeLayout(false);
this.PerformLayout();
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ServiceStatus));
this.picBanner = new System.Windows.Forms.PictureBox();
this.lblStatus = new System.Windows.Forms.Label();
this.txtStatus = new System.Windows.Forms.TextBox();
this.btnReconfigure = new System.Windows.Forms.Button();
this.btnOK = new System.Windows.Forms.Button();
this.btnOpenConfigDir = new System.Windows.Forms.Button();
((System.ComponentModel.ISupportInitialize)(this.picBanner)).BeginInit();
this.SuspendLayout();
//
// picBanner
//
this.picBanner.Image = global::Icinga.Properties.Resources.icinga_banner;
this.picBanner.Location = new System.Drawing.Point(0, 0);
this.picBanner.Name = "picBanner";
this.picBanner.Size = new System.Drawing.Size(625, 77);
this.picBanner.TabIndex = 2;
this.picBanner.TabStop = false;
//
// lblStatus
//
this.lblStatus.AutoSize = true;
this.lblStatus.Location = new System.Drawing.Point(12, 105);
this.lblStatus.Name = "lblStatus";
this.lblStatus.Size = new System.Drawing.Size(79, 13);
this.lblStatus.TabIndex = 3;
this.lblStatus.Text = "Service Status:";
//
// txtStatus
//
this.txtStatus.Location = new System.Drawing.Point(97, 102);
this.txtStatus.Name = "txtStatus";
this.txtStatus.ReadOnly = true;
this.txtStatus.Size = new System.Drawing.Size(278, 20);
this.txtStatus.TabIndex = 3;
//
// btnReconfigure
//
this.btnReconfigure.Location = new System.Drawing.Point(195, 143);
this.btnReconfigure.Name = "btnReconfigure";
this.btnReconfigure.Size = new System.Drawing.Size(89, 23);
this.btnReconfigure.TabIndex = 1;
this.btnReconfigure.Text = "Reconfigure";
this.btnReconfigure.UseVisualStyleBackColor = true;
this.btnReconfigure.Click += new System.EventHandler(this.btnReconfigure_Click);
//
// btnOK
//
this.btnOK.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.btnOK.Location = new System.Drawing.Point(290, 143);
this.btnOK.Name = "btnOK";
this.btnOK.Size = new System.Drawing.Size(89, 23);
this.btnOK.TabIndex = 0;
this.btnOK.Text = "OK";
this.btnOK.UseVisualStyleBackColor = true;
this.btnOK.Click += new System.EventHandler(this.btnOK_Click);
//
// btnOpenConfigDir
//
this.btnOpenConfigDir.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.btnOpenConfigDir.Location = new System.Drawing.Point(100, 143);
this.btnOpenConfigDir.Name = "btnOpenConfigDir";
this.btnOpenConfigDir.Size = new System.Drawing.Size(89, 23);
this.btnOpenConfigDir.TabIndex = 2;
this.btnOpenConfigDir.Text = "Examine Config";
this.btnOpenConfigDir.UseVisualStyleBackColor = true;
this.btnOpenConfigDir.Click += new System.EventHandler(this.btnOpenConfigDir_Click);
//
// ServiceStatus
//
this.AcceptButton = this.btnOK;
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.CancelButton = this.btnOK;
this.ClientSize = new System.Drawing.Size(391, 186);
this.Controls.Add(this.btnOpenConfigDir);
this.Controls.Add(this.btnOK);
this.Controls.Add(this.btnReconfigure);
this.Controls.Add(this.txtStatus);
this.Controls.Add(this.lblStatus);
this.Controls.Add(this.picBanner);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.MaximizeBox = false;
this.Name = "ServiceStatus";
this.Text = "Icinga Windows Agent Service Status";
((System.ComponentModel.ISupportInitialize)(this.picBanner)).EndInit();
this.ResumeLayout(false);
this.PerformLayout();
}

View File

@ -1,9 +1,4 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.ServiceProcess;
using System.Diagnostics;

View File

@ -112,27 +112,469 @@
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Drawing" name="System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
AAABAAEAICAQAAAABADoAgAAFgAAACgAAAAgAAAAQAAAAAEABAAAAAAAAAIAAAAAAAAAAAAAEAAAABAA
AAAAAAAAAACAAACAAAAAgIAAgAAAAIAAgACAgAAAgICAAMDAwAAAAP8AAP8AAAD//wD/AAAA/wD/AP//
AAD///8AAAAAAAAAAAAAAAAAAAAAAAAHAAAAAAAAAAAAAAAAcAAAcAB3AAAAAAAAAAAAAAcABwB///cA
AAAAAAAAAAAAcAAA////AAAAAAAAAAAAAAAAAP///3AAAAAAAAAAAAAAAAD///9wAAAAAAAAAAAAAAAA
j//4AAAAB3AAAAAAAAAAAAj/jwAAAA/4AAAAAAAAAAAAAAiAAAAP9wAAAAAAAAAAAAAH9wAAf3AAAAAA
AAAAAAAAAH93d/cAAAAAAAAAAAAAAAB////3AAAAAAAAAAAAAAAA/////wAAAAAAAAAAAAAAB/////9w
AAAAAAAAAAAAAAf/////gAAAAAAAAAAAAAAH//////h3AAAAAAAAAAAAB/////+I//h3eHAAAAAAAAD/
////AAB3j//3AAAAAAB4////9wAAAAf/+AAAAAf/+AB4iPAAAAAAj/cAAAAH//AAAAD3AAAAAAcAAAAA
B/+AAAAAjwAAAAAAAAAAAAB3AAAAAA9wAAAAAAAAAAAAAAAAAAAIh3AAAAAAAAAAAAAAAAAAD//wAAAA
AAAAAAAAAAAAAH//9wAAAAAAAAAAAAAAAAB///cAAAAAAAcAAAAAAAAACP+AAAAAAHAAcAAAAAAAAAB3
AAAAAAcAAAcAAAAAAAAAAAAAAABwAAAAAAAAAAAAAAAAAAAAAAD/////4AAAB8AAAAOAAAABgAAAAYAA
AAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAA
AAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAcAAAAPgAAAH/////w==
AAABAAUAEBAAAAEAIABoBAAAVgAAABgYAAABACAAiAkAAL4EAAAgIAAAAQAgAKgQAABGDgAAMDAAAAEA
IACoJQAA7h4AAAAAAAABACAA6iUAAJZEAAAoAAAAEAAAACAAAAABACAAAAAAAAAEAADDDgAAww4AAAAA
AAAAAAAAv5UA/7+VAP+/lQD/v5UB/7+WAv+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+UAf++kwD/v5YB/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/76TAP/Alwv/xZ8Z/72SAP+/lQD/v5UA/7+WAf+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAf++kwD/7eG3///////Orj3/vJAA/8CWA/+9kgD/v5QA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAf+/lQD/v5QA//Hoyf//////0rVQ/7yQAP/AlwX/yKMj/8CX
Bf+/lAD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UB/76TAP/DnBb/zaw2/8WfHP+7jgD/vJAB/9a7
Xf/BmQn/vpQA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/vpQD/7qMAP/LqTT/7N+y/+na
p//EnSD/vZEA/8CWAv/AlgL/wJYD/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/8CXBP+9kgD/7N+z////
////////5dSX/7uPAP+/lQP/vJAA/7uOAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lAL/uYsA/+3h
uP///////////+fYov/EnRX/xqEd/82tOv/Vulr/vpQA/7+VAP+/lQD/v5UA/7+VAf++kwD/xJ0S/8+v
Qf/NrTr/696v/+zgtP/Fnxv/v5UA/72SAP/cxXP/9e7X/76TAP+/lQD/v5UB/7+VAP+/lgL/vJEA/8uo
L//j0ZD/u48A/7uOAP/Algv/wZgQ/7uOAP+/lQD/vpMB/7+VBP+/lAD/v5UA/7+VAP+/lQD/v5UA/7+V
AP++kwD/vI8A/8CWA//AlgL/wJYE/+nbqf/awWr/vJEA/8CWA/+/lQH/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UB/8CWAv+/lQH/vpQA/8GYCf/7+fD/696w/7uPAP/AlgP/v5UB/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP++kwD/w5sS/8GYC/++lAD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/76TAP++lAH/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lgH/v5UB/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAoAAAAGAAAADAAAAABACAAAAAAAAAJAADDDgAAww4AAAAAAAAAAAAAv5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP/AlgP/wJcE/8CWAv+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
Af+7jwD/uo0A/7yRAP+/lgD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/72SAP/Yv2j/6t2s/82tPf+8kQD/wJYC/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP/AlgP/u48A/9K0S/////////////n16P/DnBL/vpMA/7+WAf+/lQD/v5YC/7+WAf+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP/AlwT/u44A/9W6Wf////////////v5
8f/Fnxn/vpMA/7+VAf+/lgD/vZEA/72SAP+/lgD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQH/v5UA/7+VBP/k05b/9e/Z/9/Kgv++kwH/wJYE/8GYCP+7jwD/3cd6/9W6
Wf+7jgD/wJYD/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/76U
AP+8kAH/vJEA/8KaFv/Mqjb/uowA/7uOAf+7jgD/17xh/8ikJP+9kgD/v5YB/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAf/AlgP/wJYD/72RAP/JpS3/3sl9/+PR
kf/bxHD/wpoc/7yPAP/AlgH/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5YB/72SAP/o2qb///////79+v//////3cd7/7yQAP/AlwT/v5YB/7+V
AP+/lQH/v5YC/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP/AlgL/vJEA/8uo
L////////v37//38+f//////+PTl/8KZDP+9kQD/vpMB/76UAP+/lAH/vZIA/7+VAf+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP/AlgP/vZIA/8upMP///////v37//79+f//////+vbr/86u
Pf/Kpiz/x6Ig/8KZC//Alwr/x6Mj/76TAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP++kwH/uo0A/7+VBf/x58b///////79+v//////4MuF/7yQAP/EnRL/yKMk/8ejI//q3Kv//////9K0
TP+7jwD/wJYD/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UB/76TAP/Fnhf/2L5k/86tPP/EnRb/3MZ2/+jZ
pP/fyoH/v5UJ/7+VAP++lAD/vpMD/7qNAP/eyHz//Pr1/82sOf+8kAD/wJYD/7+VAP+/lQD/v5UA/7+V
AP+/lQD/wJYD/7uPAP/StEv//////8mlKf+7jwD/vI8D/7mLAP/EnR7/yKUp/7yQAP/AlwP/v5UB/7+V
Af+9kgL/wJYH/72SAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP/AlgT/xJ4Y/7+U
Af+/lgH/wJcE/8CXBP+/lAL/zKo3/8SdFv+9kQD/v5UA/7+VAP+/lQH/v5QB/7+WAf+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/vZIA/7+VAP+/lQD/v5UB/7+VAP+/lAD/696x////
///VuVf/vJAA/8CWA/+/lQD/v5UB/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5YC/7+VAP+/lQD/v5YB/76TAP/EnhX/+vfs///////l1Jn/u44A/8CXBP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+W
Av+9kQD/1rtd/+japv/GoR//vZIA/7+WAf+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/vJAA/7qNAP+9kgD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/wJYD/8CXBP+/lgL/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAACAA
AABAAAAAAQAgAAAAAAAAEAAAww4AAMMOAAAAAAAAAAAAAL+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQH/wJYD/7+VAf+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/wJYC/76TAf+8kAD/vpQB/8CWAv+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+WAf+8kAD/w5wV/86tOv/CmhH/vJEA/7+W
Af+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP/AlgL/vJEA/86tPv/69+3///////j0
5f/KqDH/vZEA/8CWAv+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+WAf+9kgD/7+XC////
///9/Pj//////+vfsv+8kAD/wJYC/7+VAP+/lQD/v5UA/7+WAf/AlgP/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/76U
AP/z69H///////z79f//////7+XC/72RAP+/lgL/v5UA/7+VAP+/lQD/vZIA/7yPAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP/AlgP/u48A/9m/af///////v37///////Wu2H/u44A/8CXA/+/lQD/v5UB/76TAP/HoyL/0LJG/76U
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQH/vZEA/8+wQ//dyHr/0LFF/8+vQf++lAT/wJYC/8CXBP/BmAj/uo0A/9zF
eP/38uD/vpMA/7+VAP+/lQH/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lgL/vJAA/7qOAf+6jAD/yqcv/86uP/+6jQD/u44C/7uO
AP+9kQD/0rVP/8SeF/++kwD/v5UB/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP/AlgP/wJcE/8CXBP+9kQD/zKo3/9Cy
R//awm7/17xf/8+wQv/Ioyj/vJAA/8CWAv+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/wJYC/7yQ
AP/eyX////////7+/P///////v37/9CySf+8kAD/wJYC/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/8CW
A/+8kAD/0LFF///////+/vz//v37//79+v//////+PTm/8OcFP++lAD/wJYD/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/wJcE/7uOAP/k0pP///////79+/////////////79+///////0rRP/7mLAP++kwP/vpQA/7+V
Af/AlgL/wJYD/7+VAf/AlgL/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP/AlwT/u44A/+XTl////////v37/////////////v78///////fyYD/yqcu/8il
J//Cmw7/vpQA/72RAP+8kAD/vpQB/7yRAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UB/8GYB/+8kAD/z7BI///////+/vz//v36//79+v//////+vbq/8Wg
HP/EnRT/y6ky/8+vQf/Qskf/y6gx/93GeP/48+L/171g/7yRAP/AlgL/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP++kwD/uo0A/7yQAP/LqC//6Nqn/////////v7///////37
9v/Tt1X/u48A/76UAv+9kQD/vZIA/7+WAv/HoiH/+PTm///////z69D/vpQA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lgH/vpMA/8ahHf/gy4P/1rte/8qnL/+7jwD/zq8+/+DL
g//cxnX/1rth/7yRA/+/lgD/v5UB/7+WAv+/lgL/v5UC/7uPAP/eyX7//Pr0/9rDb/+8kQD/wJYC/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/8CXBP+7jgD/2cFr///////hzoz/uYsA/8GY
Bv+8kAD/u44C/7iJAP/JpjL/y6gy/72SAP/AlwT/v5UA/7+VAP+/lQD/v5UB/72RAf/Alwj/vZEA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UB/76TAP/EnRX/3MV2/8ah
H/++kwD/v5YB/8CWA//AlwX/wJYC/8CXCf/Rs0z/u44A/7yQAP+/lgH/v5UA/7+VAP+/lQD/v5YC/7+U
AP/AlgL/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/76T
AP+6jQD/vpMA/7+VAP+/lQD/v5UA/7+VAP/AlgL/u48A/8yrQP/eyX3/zKo2/72RAP+/lgH/v5UA/7+V
AP+/lQD/v5UB/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UB/8CXBP+/lgH/v5UA/7+VAP+/lQD/v5UB/7+VAP+/lQL/7uO+////////////0LJG/7yQ
AP/AlgP/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lgL/vZIA/8agHP/9+/b//v35////
///fy4L/uo0A/8CXBP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lgH/vZIA/+fX
of//////+vfr/8qnLv+9kQD/wJYC/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP++lAD/vpQF/8yrNf/Fnhr/vZEA/7+WAf+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQL/vJAA/76TAf/AlgH/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP/AlgP/v5YB/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP8AAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgA
AAAwAAAAYAAAAAEAIAAAAAAAACQAAMMOAADDDgAAAAAAAAAAAAC/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+WAv/AlgT/wJYD/7+VAf+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/wJYD/72SAP+7jgD/vJAA/7+V
Av+/lgL/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQL/vI8A/8ij
JP/Tt1T/zq49/76UBf+9kgD/wJYB/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+W
Af+9kQD/38uE///+/f///v7///////HoyP/Fnx3/vZIA/7+WAf+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/wJYD/7uPAP/Wu1////////7+/P/+/vz//v37///////t4rv/vZIA/7+VAf+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/wJYC/7yRAP/u4rv///////79+//////////+///+/f/+/v3/yaYs/72R
AP/AlgL/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UB/72SAP/x6Mj///////7+/f/////////////+
/v//////zKs4/7yQAP/AlgP/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/wJcE/8CWA/+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/wJcE/7uOAP/izoz///////38
+P/+/vz//v36///////48+P/wpoO/76UAP+/lQH/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lAD/uo4A/7yQ
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5YB/76T
AP/DnBb/9O3W/////////v3//v78///////XvWj/uo0A/8CXA/+/lQD/v5UA/7+VAP+/lQD/v5UB/7+U
AP/AlwX/3MV1/9GzSf+9kgD/v5YC/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/8CWAf+9kgD/wpoT/9/Jf//s4LX/5tWc/9GySf/XvWT/v5UH/7+VAP+/lQD/v5UA/7+V
AP+/lQD/wJYD/7yQAP/NrDr///////Pr0f++lAD/v5UA/7+VAf+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP/AlgH/vpQB/7qOAP+8jwD/u48C/7mLAP/OrkH/1blc/7uO
AP/AlwP/v5UB/8CWAv/AlgL/wJYC/72SAP/FnyD/7eG5/9O2Uf+9kgD/v5YC/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UB/8CXBP/AlgP/wJYE/8CX
Bf+7jwD/2L5m/8qoM/+8kQD/vpQC/7yQAP+9kQD/v5YC/7yQAP/XvGP/xqAl/7mMAP/AlgH/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAf++lAD/wZgP/9rCcP++lAf/w5wT/8yqNP/Kpy3/vZIA/8ijLP/WvGH/vJAA/8CX
Bf+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP/AlwP/uo0A/86tSP/y6cv/+vbq////////////9e7X/+nb
qv/Alxb/vpMA/7+WAf+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/8CWAv+9kgD/x6Il//fy4P/////////+////
//////////7+///////l05j/vZEA/7+WAf+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAf+9kgD/7eK8////
///+/fr///7+/////////////v79//79+///////1bpe/7uPAP/AlgP/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/wJYD/7yQ
AP/Nqzj///////7+/f////////////////////////////7+/P//////8ObD/76TAP/AlgP/v5UB/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/wJcE/7uOAP/ZwGj///////79+//////////////////////////////+/v//////+fbq/8CX
Ef+8jwD/v5QB/7+WAv/AlgP/v5YB/7+VAP+/lQD/v5UA/7+VAf/AlgT/wJYC/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/wJcE/7uOAP/ZwWr///////79+///////////////////////////////
/v///////Pr0/9W5WP/IpCb/wpkL/72RAP+8jwD/vZEA/76UAP+/lgH/wJcD/76UAf+7jgD/vZEA/8CW
Av+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/wJYD/7yQAP/Orj7///////7+/f//////////////
//////////////7+/f//////8unM/8qnLv/Ut1T/2L5l/9e8Yv/Rs0v/yaYr/8KaDP+9kgD/u44A/8Kb
E//UuFP/yqcu/7yRAP+/lgH/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UB/7+WAf++kwD/7uS/////
///+/fn////+///////////////+//79+v//////2L9q/7iKAP+9kQT/vpMA/8OcEv/LqTL/07ZS/9i+
Zf/XvWH/0rVP//Tt1P///////////9W5WP+8kAD/wJYD/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/8CWAv+/lQH/wJcD/76U
Av+8kQD/3cd5//z79v/////////+//7+/P///v3//v79///////q3K3/vZIA/8CWAv/AlgP/v5UB/76T
AP+8kAD/vI8A/76UA/+/lgL/4MyH///////8+vT///////Dnxf+9kgD/v5YB/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5YA/72R
AP++kwH/u48A/8KaEv/cxnf/yaYt/8eiJP/u5L7//v79///////+/v3//v38/+TSk/+9kgL/v5QB/7+W
Af+/lQD/v5UA/7+VAf+/lgL/wJYD/8CXBP+6jQD/0bNP///////+/fr//////+rcrf+8kAD/wJYC/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP/AlgL/vZEA/8yqNf/z69D/6duq/9vDcP/GoCD/vJAA/72SAf+8kQH/yKUm/9GzSv/OrTv/yKQk/9W5
Xf+9kgD/wJYC/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQH/vpMA/+DMiP/59en/7+S//8ah
Iv+9kgD/v5YC/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP/AlgP/vI8A/+rdrv///////////9S4XP+5iwD/wZgF/7+WAv/AlgL/vZEA/7uP
AP+9kQP/uo0A/9W6Xv/KqDT/vJEA/7+WAv+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UB/7yQ
AP/BmAf/vZIC/72SAP+/lgD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP/AlgP/vI8A/9zEdP//////+/jv/8qnLf+9kgD/v5YC/7+V
AP+/lQD/v5YC/8CWA//AlgT/vpMA/8SdGv/Zv23/vZEA/8CXA/+/lQH/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UB/8CWA/+/lAD/v5YC/7+WAv+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/72SAf/NrDn/x6Mk/72R
AP+/lgH/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/wJYC/7uPAP/Wu2H/yaYv/7qNAP+/lQL/wJYC/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQH/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
Af+8kAD/vZIB/7+WAf+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UB/76TAP/Cmxn/171k/8ah
Hf/CmQ//vJAA/7+WAf+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP/AlgP/v5YC/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/wJYC/72R
AP/LqDP/+PPj///////59ef/0rVS/7yQAP/AlgL/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQH/v5UA/8CWBf/07NP///////7+/P//////+/jv/8agHP+9kgD/v5YC/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lgL/vZEA/8ilKP/9/Pn///79/////v/+/fn//////9K0TP+7jwD/wJYD/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQH/vpQA/8KbD//48+T///////79+v///////v38/8mm
K/+9kQD/wJYC/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/wJYD/7yQAP/VuVz//v37////
/v//////3sh9/7yQAP/AlgL/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+W
Af+8kAD/x6Ij/9S4Vv/Kpy7/vJAA/7+VAf+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP/AlgL/vZIA/7uOAP+9kQD/wJYC/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5YC/8CWBP/AlgL/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+VAP+/lQD/v5UA/7+V
AP+/lQD/v5UA/7+VAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
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
oeb/A5fj85sn5OS0AAAAAElFTkSuQmCC
</value>
</data>
</root>

View File

@ -46,6 +46,7 @@
this.colGlobalZoneName = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.introduction1 = new System.Windows.Forms.Label();
this.groupBox3 = new System.Windows.Forms.GroupBox();
this.chkDisableConf = new System.Windows.Forms.CheckBox();
this.txtUser = new System.Windows.Forms.TextBox();
this.chkRunServiceAsThisUser = new System.Windows.Forms.CheckBox();
this.chkInstallNSCP = new System.Windows.Forms.CheckBox();
@ -87,7 +88,7 @@
this.txtError = new System.Windows.Forms.TextBox();
this.lblError = new System.Windows.Forms.Label();
this.picBanner = new System.Windows.Forms.PictureBox();
this.chkDisableConf = new System.Windows.Forms.CheckBox();
this.linkLabelDocs = new System.Windows.Forms.LinkLabel();
this.tabFinish.SuspendLayout();
this.tabConfigure.SuspendLayout();
this.tabParameters.SuspendLayout();
@ -141,7 +142,7 @@
this.tabFinish.Location = new System.Drawing.Point(4, 5);
this.tabFinish.Name = "tabFinish";
this.tabFinish.Padding = new System.Windows.Forms.Padding(3);
this.tabFinish.Size = new System.Drawing.Size(617, 471);
this.tabFinish.Size = new System.Drawing.Size(617, 495);
this.tabFinish.TabIndex = 5;
this.tabFinish.Text = "Finish";
this.tabFinish.UseVisualStyleBackColor = true;
@ -151,7 +152,7 @@
this.lblSetupCompleted.AutoSize = true;
this.lblSetupCompleted.Location = new System.Drawing.Point(34, 35);
this.lblSetupCompleted.Name = "lblSetupCompleted";
this.lblSetupCompleted.Size = new System.Drawing.Size(259, 13);
this.lblSetupCompleted.Size = new System.Drawing.Size(252, 13);
this.lblSetupCompleted.TabIndex = 0;
this.lblSetupCompleted.Text = "The Icinga Windows agent was set up successfully.";
//
@ -162,7 +163,7 @@
this.tabConfigure.Location = new System.Drawing.Point(4, 5);
this.tabConfigure.Name = "tabConfigure";
this.tabConfigure.Padding = new System.Windows.Forms.Padding(3);
this.tabConfigure.Size = new System.Drawing.Size(617, 471);
this.tabConfigure.Size = new System.Drawing.Size(617, 495);
this.tabConfigure.TabIndex = 4;
this.tabConfigure.Text = "Configure Icinga 2";
this.tabConfigure.UseVisualStyleBackColor = true;
@ -185,6 +186,7 @@
//
// tabParameters
//
this.tabParameters.Controls.Add(this.linkLabelDocs);
this.tabParameters.Controls.Add(this.groupBox4);
this.tabParameters.Controls.Add(this.introduction1);
this.tabParameters.Controls.Add(this.groupBox3);
@ -270,7 +272,7 @@
this.introduction1.AutoSize = true;
this.introduction1.Location = new System.Drawing.Point(11, 3);
this.introduction1.Name = "introduction1";
this.introduction1.Size = new System.Drawing.Size(269, 13);
this.introduction1.Size = new System.Drawing.Size(262, 13);
this.introduction1.TabIndex = 6;
this.introduction1.Text = "Welcome to the Icinga Windows Agent Setup Wizard!";
//
@ -289,6 +291,18 @@
this.groupBox3.TabStop = false;
this.groupBox3.Text = "Advanced Options";
//
// chkDisableConf
//
this.chkDisableConf.AutoSize = true;
this.chkDisableConf.Checked = true;
this.chkDisableConf.CheckState = System.Windows.Forms.CheckState.Checked;
this.chkDisableConf.Location = new System.Drawing.Point(9, 137);
this.chkDisableConf.Name = "chkDisableConf";
this.chkDisableConf.Size = new System.Drawing.Size(211, 17);
this.chkDisableConf.TabIndex = 9;
this.chkDisableConf.Text = "Disable including local \'conf.d\' directory";
this.chkDisableConf.UseVisualStyleBackColor = true;
//
// txtUser
//
this.txtUser.Enabled = false;
@ -341,9 +355,9 @@
//
// txtTicket
//
this.txtTicket.Location = new System.Drawing.Point(136, 56);
this.txtTicket.Location = new System.Drawing.Point(164, 56);
this.txtTicket.Name = "txtTicket";
this.txtTicket.Size = new System.Drawing.Size(378, 20);
this.txtTicket.Size = new System.Drawing.Size(350, 20);
this.txtTicket.TabIndex = 1;
//
// lblTicket
@ -351,15 +365,15 @@
this.lblTicket.AutoSize = true;
this.lblTicket.Location = new System.Drawing.Point(9, 59);
this.lblTicket.Name = "lblTicket";
this.lblTicket.Size = new System.Drawing.Size(117, 13);
this.lblTicket.Size = new System.Drawing.Size(149, 13);
this.lblTicket.TabIndex = 4;
this.lblTicket.Text = "Setup Ticket (optional):";
this.lblTicket.Text = "CSR Signing Ticket (optional):";
//
// txtInstanceName
//
this.txtInstanceName.Location = new System.Drawing.Point(136, 27);
this.txtInstanceName.Location = new System.Drawing.Point(164, 27);
this.txtInstanceName.Name = "txtInstanceName";
this.txtInstanceName.Size = new System.Drawing.Size(378, 20);
this.txtInstanceName.Size = new System.Drawing.Size(350, 20);
this.txtInstanceName.TabIndex = 0;
//
// lblInstanceName
@ -527,7 +541,7 @@
this.tabRetrieveCertificate.Location = new System.Drawing.Point(4, 5);
this.tabRetrieveCertificate.Name = "tabRetrieveCertificate";
this.tabRetrieveCertificate.Padding = new System.Windows.Forms.Padding(3);
this.tabRetrieveCertificate.Size = new System.Drawing.Size(617, 471);
this.tabRetrieveCertificate.Size = new System.Drawing.Size(617, 495);
this.tabRetrieveCertificate.TabIndex = 7;
this.tabRetrieveCertificate.Text = "Checking Certificate";
this.tabRetrieveCertificate.UseVisualStyleBackColor = true;
@ -559,7 +573,7 @@
this.tabVerifyCertificate.Location = new System.Drawing.Point(4, 5);
this.tabVerifyCertificate.Name = "tabVerifyCertificate";
this.tabVerifyCertificate.Padding = new System.Windows.Forms.Padding(3);
this.tabVerifyCertificate.Size = new System.Drawing.Size(617, 471);
this.tabVerifyCertificate.Size = new System.Drawing.Size(617, 495);
this.tabVerifyCertificate.TabIndex = 6;
this.tabVerifyCertificate.Text = "Verify Certificate";
this.tabVerifyCertificate.UseVisualStyleBackColor = true;
@ -659,7 +673,7 @@
this.tabError.Location = new System.Drawing.Point(4, 5);
this.tabError.Name = "tabError";
this.tabError.Padding = new System.Windows.Forms.Padding(3);
this.tabError.Size = new System.Drawing.Size(617, 471);
this.tabError.Size = new System.Drawing.Size(617, 495);
this.tabError.TabIndex = 8;
this.tabError.Text = "Error";
this.tabError.UseVisualStyleBackColor = true;
@ -686,25 +700,25 @@
//
// picBanner
//
this.picBanner.Image = global::Icinga.Properties.Resources.icinga_banner;
this.picBanner.Image = ((System.Drawing.Image)(resources.GetObject("picBanner.Image")));
this.picBanner.Location = new System.Drawing.Point(0, 0);
this.picBanner.Name = "picBanner";
this.picBanner.Size = new System.Drawing.Size(625, 77);
this.picBanner.TabIndex = 1;
this.picBanner.TabStop = false;
//
// chkDisableConf
// linkLabelDocs
//
this.chkDisableConf.AutoSize = true;
this.chkDisableConf.Checked = true;
this.chkDisableConf.CheckState = System.Windows.Forms.CheckState.Checked;
this.chkDisableConf.Location = new System.Drawing.Point(9, 137);
this.chkDisableConf.Name = "chkDisableConf";
this.chkDisableConf.Size = new System.Drawing.Size(138, 17);
this.chkDisableConf.TabIndex = 9;
this.chkDisableConf.Text = "Disable conf.d inclusion";
this.chkDisableConf.UseVisualStyleBackColor = true;
this.chkDisableConf.CheckedChanged += new System.EventHandler(this.checkBox1_CheckedChanged);
this.linkLabelDocs.AutoSize = true;
this.linkLabelDocs.LinkColor = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(149)))), ((int)(((byte)(191)))));
this.linkLabelDocs.Location = new System.Drawing.Point(525, 3);
this.linkLabelDocs.Name = "linkLabelDocs";
this.linkLabelDocs.Size = new System.Drawing.Size(79, 13);
this.linkLabelDocs.TabIndex = 10;
this.linkLabelDocs.TabStop = true;
this.linkLabelDocs.Text = "Documentation";
this.linkLabelDocs.VisitedLinkColor = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(149)))), ((int)(((byte)(191)))));
this.linkLabelDocs.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkLabelDocs_LinkClicked);
//
// SetupWizard
//
@ -722,7 +736,8 @@
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.MaximizeBox = false;
this.Name = "SetupWizard";
this.Text = "Icinga 2 Setup Wizard";
this.Text = "Icinga Windows Agent Setup Wizard";
this.Load += new System.EventHandler(this.SetupWizard_Load);
this.tabFinish.ResumeLayout(false);
this.tabFinish.PerformLayout();
this.tabConfigure.ResumeLayout(false);
@ -746,7 +761,7 @@
this.tabError.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.picBanner)).EndInit();
this.ResumeLayout(false);
this.Load += new System.EventHandler(this.SetupWizard_Load);
}
#endregion
@ -810,6 +825,7 @@
private System.Windows.Forms.ListView lvwGlobalZones;
private System.Windows.Forms.ColumnHeader colGlobalZoneName;
private System.Windows.Forms.CheckBox chkDisableConf;
private System.Windows.Forms.LinkLabel linkLabelDocs;
}
}

View File

@ -1,16 +1,11 @@
using System;
using System.IO;
using System.Text;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Security.Cryptography.X509Certificates;
using System.Threading;
using System.Net.NetworkInformation;
using System.IO.Compression;
using System.Diagnostics;
using System.ServiceProcess;
using System.Security.AccessControl;
namespace Icinga
@ -572,16 +567,18 @@ namespace Icinga
lvwGlobalZones.Items.Add(lvi2);
}
private void checkBox1_CheckedChanged(object sender, EventArgs e)
{
}
private void SetupWizard_Load(object sender, EventArgs e)
{
this.MinimumSize = this.Size;
this.MaximumSize = this.Size;
}
private void linkLabelDocs_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
linkLabelDocs.LinkVisited = true;
Process.Start("https://icinga.com/docs/icinga2/latest/");
}
}
}

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 766 B

After

Width:  |  Height:  |  Size: 27 KiB

View File

@ -2,15 +2,17 @@
## What is Icinga 2? <a id="what-is-icinga2"></a>
[Icinga 2](https://icinga.com/products/icinga-2/) is a monitoring system which checks
[Icinga](https://icinga.com/products/) is a monitoring system which checks
the availability of your network resources, notifies users of outages, and generates
performance data for reporting.
Scalable and extensible, Icinga 2 can monitor large, complex environments across
Scalable and extensible, Icinga can monitor large, complex environments across
multiple locations.
Icinga 2 as core requires [Icinga Web 2](https://icinga.com/products/icinga-web-2/)
on top in your Icinga Stack.
Icinga 2 is the monitoring server and requires [Icinga Web 2](https://icinga.com/products/)
on top in your Icinga Stack. The [configuration](https://icinga.com/products/configuration/)
can be easily managed with either the [Icinga Director](https://icinga.com/docs/director/latest/),
config management tools or plain text within the [Icinga DSL](04-configuration.md#configuration).
![Icinga 2 Distributed Master and Satellites with Agents](images/distributed-monitoring/icinga2_distributed_monitoring_scenarios_master_satellites_agents.png)
@ -25,7 +27,7 @@ on top in your Icinga Stack.
* [Troubleshooting](15-troubleshooting.md#troubleshooting)
* [Upgrading](16-upgrading-icinga-2.md#upgrading-icinga-2)
Once Icinga Core and Web are running in your distributed environment,
Once Icinga Server and Web are running in your distributed environment,
make sure to check out the many [Icinga modules](https://icinga.com/docs/)
for even better monitoring.

View File

@ -13,7 +13,7 @@ First off you have to install Icinga 2. The preferred way of doing this
is to use the official package repositories depending on which operating system
and distribution you are running.
Official repositories ([support matrix](https://icinga.com/support/details/)):
Official repositories ([support matrix](https://icinga.com/subscription/support-details/)):
Distribution | Repository
------------------------|---------------------------
@ -549,7 +549,7 @@ Test it:
# vim /etc/icinga2/conf.d/templates.conf
```
![Vim with syntax highlighting](images/getting-started/vim-syntax.png "Vim with Icinga 2 syntax highlighting")
![Vim with syntax highlighting](images/installation/vim-syntax.png "Vim with Icinga 2 syntax highlighting")
### Configuration Syntax Highlighting using Nano <a id="configuration-syntax-highlighting-nano"></a>
@ -593,7 +593,7 @@ Test it:
$ nano /etc/icinga2/conf.d/templates.conf
```
![Nano with syntax highlighting](images/getting-started/nano-syntax.png "Nano with Icinga 2 syntax highlighting")
![Nano with syntax highlighting](images/installation/nano-syntax.png "Nano with Icinga 2 syntax highlighting")
## Setting up Icinga Web 2 <a id="setting-up-icingaweb2"></a>
@ -704,7 +704,7 @@ GRANT SELECT, INSERT, UPDATE, DELETE, DROP, CREATE VIEW, INDEX, EXECUTE ON icing
quit
```
![setting up the database on CentOS 7](images/getting-started/mariadb-centos7.png "Setting up the database on CentOS 7")
![setting up the database on CentOS 7](images/installation/mariadb-centos7.png "Setting up the database on CentOS 7")
After creating the database you can import the Icinga 2 IDO schema using the
following command. Enter the root password into the prompt when asked.
@ -876,7 +876,7 @@ export PGPASSWORD=icinga
psql -U icinga -d icinga < /usr/share/icinga2-ido-pgsql/schema/pgsql.sql
```
![importing the Icinga 2 IDO schema](images/getting-started/postgr-import-ido.png "Importing the Icinga 2 IDO schema on Debian Jessie")
![importing the Icinga 2 IDO schema](images/installation/postgr-import-ido.png "Importing the Icinga 2 IDO schema on Debian Jessie")
#### Enabling the IDO PostgreSQL module <a id="enabling-ido-postgresql"></a>

View File

@ -1688,7 +1688,7 @@ notification users and groups are inherited from the service and if not set,
from the host object. A default user is set too.
```
apply Notification "mail-host-notification" to Service {
apply Notification "mail-service-notification" to Service {
[...]
if (service.vars.notification.mail.users) {
@ -1702,11 +1702,11 @@ apply Notification "mail-host-notification" to Service {
if (service.vars.notification.mail.groups) {
user_groups = service.vars.notification.mail.groups
} else (host.vars.notification.mail.groups) {
} else if (host.vars.notification.mail.groups) {
user_groups = host.vars.notification.mail.groups
}
assign where host.vars.notification.mail && typeof(host.vars.notification.mail) == Dictionary
assign where ( host.vars.notification.mail && typeof(host.vars.notification.mail) == Dictionary ) || ( service.vars.notification.mail && typeof(service.vars.notification.mail) == Dictionary )
}
```
@ -2803,55 +2803,40 @@ will detect their reachability immediately when executing checks.
### Dependencies for Agent Checks <a id="dependencies-agent-checks"></a>
Another classic example are agent based checks. You would define a health check
Another good example are agent based checks. You would define a health check
for the agent daemon responding to your requests, and make all other services
querying that daemon depend on that health check.
The following configuration defines two nrpe based service checks `nrpe-load`
and `nrpe-disk` applied to the host `nrpe-server` [matched](18-library-reference.md#global-functions-match)
by its name. The health check is defined as `nrpe-health` service.
```
apply Service "agent-health" {
check_command = "cluster-zone"
display_name = "cluster-health-" + host.name
/* This follows the convention that the agent zone name is the FQDN which is the same as the host object name. */
vars.cluster_zone = host.name
assign where host.vars.agent_endpoint
}
```
Now, make all other agent based checks dependent on the OK state of the `agent-health`
service.
```
apply Service "nrpe-health" {
import "generic-service"
check_command = "nrpe"
assign where match("nrpe-*", host.name)
}
apply Dependency "agent-health-check" to Service {
parent_service_name = "agent-health"
apply Service "nrpe-load" {
import "generic-service"
check_command = "nrpe"
vars.nrpe_command = "check_load"
assign where match("nrpe-*", host.name)
}
apply Service "nrpe-disk" {
import "generic-service"
check_command = "nrpe"
vars.nrpe_command = "check_disk"
assign where match("nrpe-*", host.name)
}
object Host "nrpe-server" {
import "generic-host"
address = "192.168.1.5"
}
apply Dependency "disable-nrpe-checks" to Service {
parent_service_name = "nrpe-health"
states = [ OK ]
disable_checks = true
states = [ OK ] // Fail if the parent service state switches to NOT-OK
disable_notifications = true
assign where service.check_command == "nrpe"
ignore where service.name == "nrpe-health"
assign where host.vars.agent_endpoint // Automatically assigns all agent endpoint checks as child services on the matched host
ignore where service.name == "agent-health" // Avoid a self reference from child to parent
}
```
The `disable-nrpe-checks` dependency is applied to all services
on the `nrpe-service` host using the `nrpe` check_command attribute
but not the `nrpe-health` service itself.
This is described in detail in [this chapter](06-distributed-monitoring.md#distributed-monitoring-health-checks).
### Event Commands <a id="event-commands"></a>

View File

@ -1,8 +1,18 @@
# Configuration: First Steps <a id="configuration"></a>
# Configuration <a id="configuration"></a>
This chapter provides an introduction into best practices for your Icinga 2 configuration.
The configuration files which are automatically created when installing the Icinga 2 packages
are a good way to start with Icinga 2.
The Icinga [configuration](https://icinga.com/products/configuration/)
can be easily managed with either the [Icinga Director](https://icinga.com/docs/director/latest/),
config management tools or plain text within the [Icinga DSL](04-configuration.md#configuration).
Before looking into web based configuration or any sort of automation,
we recommend to start with the configuration files and fully understand
the possibilities of the Icinga DSL (Domain Specific Language).
The package installation provides example configuration which already
monitors the local Icinga server. You can view the monitoring details
in Icinga Web.
![Icinga Web Local Server](images/configuration/icinga_web_local_server.png)
The [Language Reference](17-language-reference.md#language-reference) chapter explains details
on value types (string, number, dictionaries, etc.) and the general configuration syntax.
@ -15,8 +25,9 @@ decide for a possible strategy.
There are many ways of creating Icinga 2 configuration objects:
* The [Icinga Director](https://icinga.com/docs/director/latest/) as web based and/or automation configuration interface
* [Monitoring Automation with Icinga - The Director](https://icinga.com/2019/04/23/monitoring-automation-with-icinga-the-director/)
* Manually with your preferred editor, for example vi(m), nano, notepad, etc.
* A configuration tool for Icinga 2 e.g. the [Icinga Director](https://github.com/Icinga/icingaweb2-module-director)
* Generated by a [configuration management tool](13-addons.md#configuration-tools) such as Puppet, Chef, Ansible, etc.
* A custom exporter script from your CMDB or inventory tool
* etc.
@ -66,7 +77,7 @@ There is a detailed chapter on [distributed monitoring scenarios](06-distributed
Please ensure to have read the [introduction](06-distributed-monitoring.md#distributed-monitoring) at first glance.
If you happen to have further questions, do not hesitate to join the
[community support channels](https://icinga.com/community/)
[community forum](https://community.icinga.com)
and ask community members for their experience and best practices.
## Your Configuration <a id="your-configuration"></a>
@ -86,7 +97,7 @@ in your icinga2.conf file.
include_recursive "objects.d"
```
This approach is used by the [Icinga 2 Puppet module](https://github.com/Icinga/puppet-icinga2).
This approach is used by the [Icinga 2 Puppet module](https://icinga.com/products/integrations/puppet/).
If you plan to setup a distributed setup with HA clusters and clients, please refer to [this chapter](#06-distributed-monitoring.md#distributed-monitoring-top-down)
for examples with `zones.d` as configuration directory.
@ -216,7 +227,8 @@ const TicketSalt = ""
```
The `ZoneName` and `TicketSalt` constants are required for remote client
and distributed setups only.
and distributed setups. The `node setup/wizard` CLI tools take care of
populating these values.
### zones.conf <a id="zones-conf"></a>

View File

@ -910,6 +910,8 @@ Instead, choose a plugin and configure its parameters and thresholds. The follow
* [kdc](10-icinga-template-library.md#plugin-contrib-command-kdc)
* [rbl](10-icinga-template-library.md#plugin-contrib-command-rbl)
* [Icinga Certificate Monitoring](https://icinga.com/products/icinga-certificate-monitoring/)
### Java Monitoring <a id="service-monitoring-java"></a>
* [jmx4perl](10-icinga-template-library.md#plugin-contrib-command-jmx4perl)
@ -934,6 +936,7 @@ Instead, choose a plugin and configure its parameters and thresholds. The follow
### VMware Monitoring <a id="service-monitoring-virtualization-vmware"></a>
* [Icinga Module for vSphere](https://icinga.com/products/icinga-module-for-vsphere/)
* [esxi_hardware](10-icinga-template-library.md#plugin-contrib-command-esxi-hardware)
* [VMware](10-icinga-template-library.md#plugin-contrib-vmware)

View File

@ -360,6 +360,17 @@ Disadvantages:
* Tickets need to be generated on the master and copied to client setup wizards.
* No central signing management.
#### CSR Auto-Signing: Preparation <a id="distributed-monitoring-setup-csr-auto-signing-preparation"></a>
Prior to using this mode, ensure that the following steps are taken on
the signing master:
* The [master setup](06-distributed-monitoring.md#distributed-monitoring-setup-master) was run successfully. This includes:
* Generated a CA key pair
* Generated a private ticket salt stored in the `TicketSalt` constant, set as `ticket_salt` attribute inside the [api](09-object-types.md#objecttype-apilistener) feature.
* Restart of the master instance.
#### CSR Auto-Signing: On the master <a id="distributed-monitoring-setup-csr-auto-signing-master"></a>
Setup wizards for agent/satellite nodes will ask you for this specific client ticket.
@ -368,6 +379,7 @@ There are two possible ways to retrieve the ticket:
* [CLI command](11-cli-commands.md#cli-command-pki) executed on the master node.
* [REST API](12-icinga2-api.md#icinga2-api) request against the master node.
Required information:
Parameter | Description
@ -399,7 +411,7 @@ Retrieve the ticket on the master node `icinga2-master1.localdomain` with `curl`
-X POST 'https://localhost:5665/v1/actions/generate-ticket' -d '{ "cn": "icinga2-agent1.localdomain" }'
```
Store that ticket number for the agent/satellite setup below.
Store that ticket number for the [agent/satellite setup](06-distributed-monitoring.md#distributed-monitoring-setup-agent-satellite) below.
> **Note**
>
@ -408,6 +420,7 @@ Store that ticket number for the agent/satellite setup below.
> to the authorized Puppet agent node which will invoke the
> [automated setup steps](06-distributed-monitoring.md#distributed-monitoring-automation-cli-node-setup).
### On-Demand CSR Signing <a id="distributed-monitoring-setup-on-demand-csr-signing"></a>
The client can be a secondary master, satellite or agent.
@ -428,6 +441,16 @@ Disadvantages:
* Asynchronous step for automated deployments.
* Needs client verification on the master.
#### On-Demand CSR Signing: Preparation <a id="distributed-monitoring-setup-on-demand-csr-signing-preparation"></a>
Prior to using this mode, ensure that the following steps are taken on
the signing master:
* The [master setup](06-distributed-monitoring.md#distributed-monitoring-setup-master) was run successfully. This includes:
* Generated a CA key pair
* Restart of the master instance.
#### On-Demand CSR Signing: On the master <a id="distributed-monitoring-setup-on-demand-csr-signing-master"></a>
You can list pending certificate signing requests with the `ca list` CLI command.
@ -727,27 +750,29 @@ the [configuration modes](06-distributed-monitoring.md#distributed-monitoring-co
### Agent Setup on Windows <a id="distributed-monitoring-setup-agent-windows"></a>
Download the MSI-Installer package from [https://packages.icinga.com/windows/](https://packages.icinga.com/windows/).
The supported Windows agent versions are listed [here](https://icinga.com/subscription/support-details/).
Requirements:
* Windows Vista/Server 2008 or higher
* Versions older than Windows 10/Server 2016 require the [Universal C Runtime for Windows](https://support.microsoft.com/en-us/help/2999226/update-for-universal-c-runtime-in-windows)
* [Microsoft .NET Framework 4.6] or higher (https://www.microsoft.com/en-US/download/details.aspx?id=53344) for the setup wizard
* [Microsoft .NET Framework 4.6](https://www.microsoft.com/en-US/download/details.aspx?id=53344) or higher. This is the default on Windows Server 2016 or later.
* [Universal C Runtime for Windows](https://support.microsoft.com/en-us/help/2999226/update-for-universal-c-runtime-in-windows) for Windows Server 2012 and older.
The installer package includes the [NSClient++](https://www.nsclient.org/) package
so that Icinga 2 can use its built-in plugins. You can find more details in
[this chapter](06-distributed-monitoring.md#distributed-monitoring-windows-nscp).
The Windows package also installs native [monitoring plugin binaries](06-distributed-monitoring.md#distributed-monitoring-windows-plugins)
#### Agent Setup on Windows: Installer <a id="distributed-monitoring-setup-agent-windows-installer"></a>
Download the MSI-Installer package from [https://packages.icinga.com/windows/](https://packages.icinga.com/windows/).
The preferred flavor is `x86_64` for modern Windows systems.
The Windows package provides native [monitoring plugin binaries](06-distributed-monitoring.md#distributed-monitoring-windows-plugins)
to get you started more easily.
The installer package also includes the [NSClient++](https://www.nsclient.org/) package
to allow using its built-in plugins. You can find more details in
[this chapter](06-distributed-monitoring.md#distributed-monitoring-windows-nscp).
> **Note**
>
> Please note that Icinga 2 was designed to run as light-weight agent on Windows.
> There is no support for satellite instances.
#### Windows Agent Setup Start <a id="distributed-monitoring-setup-agent-windows-start"></a>
Run the MSI-Installer package and follow the instructions shown in the screenshots.
![Icinga 2 Windows Setup](images/distributed-monitoring/icinga2_windows_setup_installer_01.png)
@ -756,12 +781,14 @@ Run the MSI-Installer package and follow the instructions shown in the screensho
![Icinga 2 Windows Setup](images/distributed-monitoring/icinga2_windows_setup_installer_04.png)
![Icinga 2 Windows Setup](images/distributed-monitoring/icinga2_windows_setup_installer_05.png)
The graphical installer offers to run the Icinga 2 setup wizard after the installation. Select
the check box to proceed.
The graphical installer offers to run the [Icinga Agent setup wizard](06-distributed-monitoring.md#distributed-monitoring-setup-agent-windows-configuration-wizard)
after the installation. Select the check box to proceed.
> **Tip**
>
> You can also run the Icinga 2 setup wizard from the Start menu later.
> You can also run the Icinga agent setup wizard from the Start menu later.
#### Agent Setup on Windows: Configuration Wizard <a id="distributed-monitoring-setup-agent-windows-configuration-wizard"></a>
On a fresh installation the setup wizard guides you through the initial configuration.
It also provides a mechanism to send a certificate request to the [CSR signing master](distributed-monitoring-setup-sign-certificates-master).
@ -793,13 +820,13 @@ When needed you can add an additional global zone (the zones `global-templates`
Optionally enable the following settings:
Parameter | Description
----------------------------------|----------------------------------
Accept config | **Optional.** Whether this node accepts configuration sync from the master node (required for [config sync mode](06-distributed-monitoring.md#distributed-monitoring-top-down-config-sync)). For [security reasons](06-distributed-monitoring.md#distributed-monitoring-security) this is disabled by default.
Accept commands | **Optional.** Whether this node accepts command execution messages from the master node (required for [command endpoint mode](06-distributed-monitoring.md#distributed-monitoring-top-down-command-endpoint)). For [security reasons](06-distributed-monitoring.md#distributed-monitoring-security) this is disabled by default.
Run Icinga 2 service as this user | **Optional.** Specify a different Windows user. This defaults to `NT AUTHORITY\Network Service` and is required for more privileged service checks.
Install NSClient++ | **Optional.** The Windows installer bundles the NSClient++ installer for additional [plugin checks](06-distributed-monitoring.md#distributed-monitoring-windows-nscp).
Disable conf.d | **Optional.** Allows to disable the `include_recursive "conf.d"` directive except for the `api-users.conf` file in the `icinga2.conf` file. Defaults to `true`.
Parameter | Description
--------------------------------------------------------|----------------------------------
Accept commands from master/satellite instance(s) | **Optional.** Whether this node accepts command execution messages from the master node (required for [command endpoint mode](06-distributed-monitoring.md#distributed-monitoring-top-down-command-endpoint)). For [security reasons](06-distributed-monitoring.md#distributed-monitoring-security) this is disabled by default.
Accept config updates from master/satellite instance(s) | **Optional.** Whether this node accepts configuration sync from the master node (required for [config sync mode](06-distributed-monitoring.md#distributed-monitoring-top-down-config-sync)). For [security reasons](06-distributed-monitoring.md#distributed-monitoring-security) this is disabled by default.
Run Icinga 2 service as this user | **Optional.** Specify a different Windows user. This defaults to `NT AUTHORITY\Network Service` and is required for more privileged service checks.
Install/Update bundled NSClient++ | **Optional.** The Windows installer bundles the NSClient++ installer for additional [plugin checks](06-distributed-monitoring.md#distributed-monitoring-windows-nscp).
Disable including local 'conf.d' directory | **Optional.** Allows to disable the `include_recursive "conf.d"` directive except for the `api-users.conf` file in the `icinga2.conf` file. Defaults to `true`.
![Icinga 2 Windows Setup](images/distributed-monitoring/icinga2_windows_setup_wizard_03.png)
@ -891,20 +918,26 @@ the following line:
> Packages >= 2.9 provide an option in the setup wizard to disable this.
> Defaults to disabled.
Validate the configuration on Windows open an administrator terminal
Validate the configuration on Windows open an administrative Powershell
and run the following command:
```
C:\WINDOWS\system32>cd "C:\Program Files\ICINGA2\sbin"
C:\Program Files\ICINGA2\sbin>icinga2.exe daemon -C
C:\> cd C:\Program Files\ICINGA2\sbin
C:\Program Files\ICINGA2\sbin> .\icinga2.exe daemon -C
```
**Note**: You have to run this command in a shell with `administrator` privileges.
Now you need to restart the Icinga 2 service. Run `services.msc` from the start menu
and restart the `icinga2` service. Alternatively, you can use the `net {start,stop}` CLI commands.
Now you need to restart the Icinga 2 service. Run `services.msc` from the start menu and restart the `icinga2` service.
Alternatively open an administrative Powershell and run the following commands:
```
C:\> Restart-Service icinga2
C:\> Get-Service icinga2
```
![Icinga 2 Windows Service Start/Stop](images/distributed-monitoring/icinga2_windows_cmd_admin_net_start_stop.png)
Now that you've successfully installed a Windows agent, please proceed to
the [detailed configuration modes](06-distributed-monitoring.md#distributed-monitoring-configuration-modes).
@ -926,9 +959,9 @@ can start with additional integrations to manage and deploy your
configuration:
* [Icinga Director](https://icinga.com/docs/director/latest/) provides a web interface to manage configuration and also allows to sync imported resources (CMDB, PuppetDB, etc.)
* [Ansible Roles](https://github.com/Icinga/icinga2-ansible)
* [Puppet Module](https://github.com/Icinga/puppet-icinga2)
* [Chef Cookbook](https://github.com/Icinga/chef-icinga2)
* [Ansible Roles](https://icinga.com/products/integrations/)
* [Puppet Module](https://icinga.com/products/integrations/puppet/)
* [Chef Cookbook](https://icinga.com/products/integrations/chef/)
More details can be found [here](13-addons.md#configuration-tools).
@ -1154,6 +1187,17 @@ Disadvantages:
* Additional zone and endpoint configuration needed.
* Replay log is replicated on reconnect after connection loss. This might increase the data transfer and create an overload on the connection.
> **Note**
>
> This mode only supports **configuration text files** for Icinga. Do not abuse
> this for syncing binaries, this is not supported and may harm your production
> environment. The config sync uses checksums to detect changes, binaries may
> trigger reload loops.
>
> This is a fair warning. If you want to deploy plugin binaries, create
> packages for dependency management and use infrastructure lifecycle tools
> such as Foreman, Puppet, Ansible, etc.
To make sure that all involved nodes accept configuration and/or
commands, you need to configure the `Zone` and `Endpoint` hierarchy
on all nodes.
@ -2643,7 +2687,7 @@ By default ICMP requests are disabled in the Windows firewall. You can
change that by [adding a new rule](https://support.microsoft.com/en-us/kb/947709).
```
C:\WINDOWS\system32>netsh advfirewall firewall add rule name="ICMP Allow incoming V4 echo request" protocol=icmpv4:8,any dir=in action=allow
C:\> netsh advfirewall firewall add rule name="ICMP Allow incoming V4 echo request" protocol=icmpv4:8,any dir=in action=allow
```
#### Icinga 2 <a id="distributed-monitoring-windows-firewall-icinga2"></a>
@ -2652,7 +2696,7 @@ If your master/satellite nodes should actively connect to the Windows agent
you'll also need to ensure that port `5665` is enabled.
```
C:\WINDOWS\system32>netsh advfirewall firewall add rule name="Open port 5665 (Icinga 2)" dir=in action=allow protocol=TCP localport=5665
C:\> netsh advfirewall firewall add rule name="Open port 5665 (Icinga 2)" dir=in action=allow protocol=TCP localport=5665
```
#### NSClient++ API <a id="distributed-monitoring-windows-firewall-nsclient-api"></a>
@ -2661,7 +2705,7 @@ If the [check_nscp_api](06-distributed-monitoring.md#distributed-monitoring-wind
plugin is used to query NSClient++, you need to ensure that its port is enabled.
```
C:\WINDOWS\system32>netsh advfirewall firewall add rule name="Open port 8443 (NSClient++ API)" dir=in action=allow protocol=TCP localport=8443
C:\> netsh advfirewall firewall add rule name="Open port 8443 (NSClient++ API)" dir=in action=allow protocol=TCP localport=8443
```
For security reasons, it is advised to enable the NSClient++ HTTP API for local
@ -2673,14 +2717,6 @@ are not recommended with using the legacy HTTP API.
The Icinga 2 package on Windows already provides several plugins.
Detailed [documentation](10-icinga-template-library.md#windows-plugins) is available for all check command definitions.
Add the following `include` statement on all your nodes (master, satellite, agent):
```
vim /etc/icinga2/icinga2.conf
include <windows-plugins>
```
Based on the [master with agents](06-distributed-monitoring.md#distributed-monitoring-master-agents)
scenario we'll now add a local disk check.

View File

@ -1,20 +1,198 @@
# Additional Agent-based Checks <a id="agent-based-checks-addon"></a>
# Agent-based Checks <a id="agent-based-checks-addon"></a>
If the remote services are not directly accessible through the network, a
local agent installation exposing the results to check queries can
become handy.
Prior to installing and configuration an agent service, evaluate possible
options based on these requirements:
* Security (authentication, TLS certificates, secure connection handling, etc.)
* Connection direction
* Master/satellite can execute commands directly or
* Agent sends back passive/external check results
* Availability on specific OS types and versions
* Packages available
* Configuration and initial setup
* Updates and maintenance, compatibility
Available agent types:
* [Icinga Agent](07-agent-based-monitoring.md#agent-based-checks-icinga) on Linux/Unix and Windows
* [SSH](07-agent-based-monitoring.md#agent-based-checks-ssh) on Linux/Unix
* [SNMP](07-agent-based-monitoring.md#agent-based-checks-snmp) on Linux/Unix and hardware
* [SNMP Traps](07-agent-based-monitoring.md#agent-based-checks-snmp-traps) as passive check results
* [REST API](07-agent-based-monitoring.md#agent-based-checks-rest-api) for passive external check results
* [NSClient++](07-agent-based-monitoring.md#agent-based-checks-nsclient) and [WMI](07-agent-based-monitoring.md#agent-based-checks-wmi) on Windows
## Icinga Agent <a id="agent-based-checks-icinga"></a>
For the most common setups on Linux/Unix and Windows, we recommend
to setup the Icinga agent in a [distributed environment](06-distributed-monitoring.md#distributed-monitoring).
![Icinga 2 Distributed Master with Agents](images/distributed-monitoring/icinga2_distributed_monitoring_scenarios_master_with_agents.png)
Key benefits:
* Directly integrated into the distributed monitoring stack of Icinga
* Works on Linux/Unix and Windows
* Secure communication with TLS
* Connection can be established from both sides. Once connected, command execution and check results are exchanged.
* Master/satellite connects to agent
* Agent connects to parent satellite/master
* Same configuration language and binaries
* Troubleshooting docs and community best practices
Follow the setup and configuration instructions [here](06-distributed-monitoring.md#distributed-monitoring-setup-agent-satellite).
On Windows hosts, the Icinga agent can query a local NSClient++ service
for additional checks in case there are no plugins available. The NSCP
installer is bundled with Icinga and can be installed with the setup wizard.
![Icinga 2 Windows Setup](images/distributed-monitoring/icinga2_windows_setup_wizard_01.png)
## SSH <a id="agent-based-checks-ssh"></a>
> **Tip**
>
> This is the recommended way for systems where the Icinga agent is not available
> Be it specific hardware architectures, old systems or forbidden to install an additional software.
This method uses the SSH service on the remote host to execute
an arbitrary plugin command line. The output and exit code is
returned and used by the core.
The `check_by_ssh` plugin takes care of this. It is available in the
[Monitoring Plugins package](02-installation.md#setting-up-check-plugins).
For your convenience, the Icinga template library provides the [by_ssh](10-icinga-template-library.md#plugin-check-command-by-ssh)
CheckCommand already.
### SSH: Preparations <a id="agent-based-checks-ssh-preparations"></a>
SSH key pair for the Icinga daemon user. In case the user has no shell, temporarily enable this.
When asked for a passphrase, **do not set it** and press enter.
```
sudo su - icinga
ssh-keygen -b 4096 -t rsa -C "icinga@$(hostname) user for check_by_ssh" -f $HOME/.ssh/id_rsa
```
On the remote agent, create the icinga user and generate a temporary password.
```
useradd -m icinga
passwd icinga
```
Copy the public key from the Icinga server to the remote agent, e.g. with `ssh-copy-id`
or manually into `/home/icinga/.ssh/authorized_keys`.
This will ask for the password once.
```
sudo su - icinga
ssh-copy-id -i $HOME/.ssh/id_rsa icinga@ssh-agent1.localdomain
```
After the SSH key is copied, test at the connection **at least once** and
accept the host key verification. If you forget about this step, checks will
become UNKNOWN later.
```
ssh -i $HOME/.ssh/id_rsa icinga@ssh-agent1.localdomain
```
After the SSH key login works, disable the previously enabled logins.
* Remote agent user's password with `passwd -l icinga`
* Local icinga user terminal
Also, ensure that the permissions are correct for the `.ssh` directory
as otherwise logins will fail.
* `.ssh` directory: 700
* `.ssh/id_rsa.pub` public key file: 644
* `.ssh/id_rsa` private key file: 600
### SSH: Configuration <a id="agent-based-checks-ssh-config"></a>
First, create a host object which has SSH configured and enabled.
Mark this e.g. with the custom variable `agent_type` to later
use this for service apply rule matches. Best practice is to
store that in a specific template, either in the static configuration
or inside the Director.
```
template Host "ssh-agent" {
check_command = "hostalive"
vars.agent_type = "ssh"
vars.os_type = "linux"
}
object Host "ssh-agent1.localdomain" {
import "ssh-agent"
address = "192.168.56.115"
}
```
Example for monitoring the remote users:
```
apply Service "users" {
check_command = "by_ssh"
vars.by_ssh_command = [ "/usr/lib/nagios/plugins/check_users" ]
// Follows the same principle as with command arguments, e.g. for ordering
vars.by_ssh_arguments = {
"-w" = {
value = "$users_wgreater$" // Can reference an existing custom variable defined on the host or service, evaluated at runtime
}
"-c" = {
value = "$users_cgreater$"
}
}
vars.users_wgreater = 3
vars.users_cgreater = 5
assign where host.vars.os_type == "linux" && host.vars.agent_type == "ssh"
}
```
A more advanced example with better arguments is shown in [this blogpost](https://www.netways.de/blog/2016/03/21/check_by_ssh-mit-icinga-2/).
## SNMP <a id="agent-based-checks-snmp"></a>
The SNMP daemon runs on the remote system and answers SNMP queries by plugin
binaries. The [Monitoring Plugins package](02-installation.md#setting-up-check-plugins) ships
The SNMP daemon runs on the remote system and answers SNMP queries by plugin scripts.
The [Monitoring Plugins package](02-installation.md#setting-up-check-plugins) provides
the `check_snmp` plugin binary, but there are plenty of [existing plugins](05-service-monitoring.md#service-monitoring-plugins)
for specific use cases already around, for example monitoring Cisco routers.
The following example uses the [SNMP ITL](10-icinga-template-library.md#plugin-check-command-snmp) `CheckCommand` and just
overrides the `snmp_oid` custom variable. A service is created for all hosts which
The following example uses the [SNMP ITL](10-icinga-template-library.md#plugin-check-command-snmp)
CheckCommand and sets the `snmp_oid` custom variable. A service is created for all hosts which
have the `snmp-community` custom variable.
```
template Host "snmp-agent" {
check_command = "hostalive"
vars.agent_type = "snmp"
vars.snmp_community = "public-icinga"
}
object Host "snmp-agent1.localdomain" {
import "snmp-agent"
}
```
```
apply Service "uptime" {
import "generic-service"
@ -23,177 +201,21 @@ apply Service "uptime" {
vars.snmp_oid = "1.3.6.1.2.1.1.3.0"
vars.snmp_miblist = "DISMAN-EVENT-MIB"
assign where host.vars.snmp_community != ""
assign where host.vars.agent_type == "snmp" && host.vars.snmp_community != ""
}
```
Additional SNMP plugins are available using the [Manubulon SNMP Plugins](10-icinga-template-library.md#snmp-manubulon-plugin-check-commands).
If no `snmp_miblist` is specified, the plugin will default to `ALL`. As the number of available MIB files
on the system increases so will the load generated by this plugin if no `MIB` is specified.
As such, it is recommended to always specify at least one `MIB`.
## SSH <a id="agent-based-checks-ssh"></a>
Additional SNMP plugins are available using the [Manubulon SNMP Plugins](10-icinga-template-library.md#snmp-manubulon-plugin-check-commands).
Calling a plugin using the SSH protocol to execute a plugin on the remote server fetching
its return code and output. The `by_ssh` command object is part of the built-in templates and
requires the `check_by_ssh` check plugin which is available in the [Monitoring Plugins package](02-installation.md#setting-up-check-plugins).
```
object CheckCommand "by_ssh_swap" {
import "by_ssh"
vars.by_ssh_command = "/usr/lib/nagios/plugins/check_swap -w $by_ssh_swap_warn$ -c $by_ssh_swap_crit$"
vars.by_ssh_swap_warn = "75%"
vars.by_ssh_swap_crit = "50%"
}
object Service "swap" {
import "generic-service"
host_name = "remote-ssh-host"
check_command = "by_ssh_swap"
vars.by_ssh_logname = "icinga"
}
```
## NSClient++ <a id="agent-based-checks-nsclient"></a>
[NSClient++](https://nsclient.org/) works on both Windows and Linux platforms and is well
known for its magnificent Windows support. There are alternatives like the WMI interface,
but using `NSClient++` will allow you to run local scripts similar to check plugins fetching
the required output and performance counters.
You can use the `check_nt` plugin from the Monitoring Plugins project to query NSClient++.
Icinga 2 provides the [nscp check command](10-icinga-template-library.md#plugin-check-command-nscp) for this:
Example:
```
object Service "disk" {
import "generic-service"
host_name = "remote-windows-host"
check_command = "nscp"
vars.nscp_variable = "USEDDISKSPACE"
vars.nscp_params = "c"
vars.nscp_warn = 70
vars.nscp_crit = 80
}
```
For details on the `NSClient++` configuration please refer to the [official documentation](https://docs.nsclient.org/).
## NSCA-NG <a id="agent-based-checks-nsca-ng"></a>
[NSCA-ng](http://www.nsca-ng.org) provides a client-server pair that allows the
remote sender to push check results into the Icinga 2 `ExternalCommandListener`
feature.
> **Note**
>
> This addon works in a similar fashion like the Icinga 1.x distributed model. If you
> are looking for a real distributed architecture with Icinga 2, scroll down.
## NRPE <a id="agent-based-checks-nrpe"></a>
[NRPE](https://docs.icinga.com/latest/en/nrpe.html) runs as daemon on the remote client including
the required plugins and command definitions.
Icinga 2 calls the `check_nrpe` plugin binary in order to query the configured command on the
remote client.
> **Note**
>
> The NRPE protocol is considered insecure and has multiple flaws in its
> design. Upstream is not willing to fix these issues.
>
> In order to stay safe, please use the native [Icinga 2 client](06-distributed-monitoring.md#distributed-monitoring)
> instead.
The NRPE daemon uses its own configuration format in nrpe.cfg while `check_nrpe`
can be embedded into the Icinga 2 `CheckCommand` configuration syntax.
You can use the `check_nrpe` plugin from the NRPE project to query the NRPE daemon.
Icinga 2 provides the [nrpe check command](10-icinga-template-library.md#plugin-check-command-nrpe) for this:
Example:
```
object Service "users" {
import "generic-service"
host_name = "remote-nrpe-host"
check_command = "nrpe"
vars.nrpe_command = "check_users"
}
```
nrpe.cfg:
```
command[check_users]=/usr/local/icinga/libexec/check_users -w 5 -c 10
```
If you are planning to pass arguments to NRPE using the `-a`
command line parameter, make sure that your NRPE daemon has them
supported and enabled.
> **Note**
>
> Enabling command arguments in NRPE is considered harmful
> and exposes a security risk allowing attackers to execute
> commands remotely. Details at [seclists.org](http://seclists.org/fulldisclosure/2014/Apr/240).
The plugin check command `nrpe` provides the `nrpe_arguments` custom
attribute which expects either a single value or an array of values.
Example:
```
object Service "nrpe-disk-/" {
import "generic-service"
host_name = "remote-nrpe-host"
check_command = "nrpe"
vars.nrpe_command = "check_disk"
vars.nrpe_arguments = [ "20%", "10%", "/" ]
}
```
Icinga 2 will execute the nrpe plugin like this:
```
/usr/lib/nagios/plugins/check_nrpe -H <remote-nrpe-host> -c 'check_disk' -a '20%' '10%' '/'
```
NRPE expects all additional arguments in an ordered fashion
and interprets the first value as `$ARG1$` macro, the second
value as `$ARG2$`, and so on.
nrpe.cfg:
```
command[check_disk]=/usr/local/icinga/libexec/check_disk -w $ARG1$ -c $ARG2$ -p $ARG3$
```
Using the above example with `nrpe_arguments` the command
executed by the NRPE daemon looks similar to that:
```
/usr/local/icinga/libexec/check_disk -w 20% -c 10% -p /
```
You can pass arguments in a similar manner to [NSClient++](07-agent-based-monitoring.md#agent-based-checks-nsclient)
when using its NRPE supported check method.
For network monitoring, community members advise to use [nwc_health](05-service-monitoring.md#service-monitoring-network)
for example.
## Passive Check Results and SNMP Traps <a id="agent-based-checks-snmp-traps"></a>
## SNMP Traps and Passive Check Results <a id="agent-based-checks-snmp-traps"></a>
SNMP Traps can be received and filtered by using [SNMPTT](http://snmptt.sourceforge.net/)
and specific trap handlers passing the check results to Icinga 2.
@ -228,6 +250,11 @@ applied to your _n_ hosts. The host address inferred by SNMPTT will be the
correlating factor. You can have snmptt provide host names or ip addresses to
match your Icinga convention.
> **Note**
>
> Replace the deprecated command pipe EXEC statement with a curl call
> to the REST API action [process-check-result](12-icinga2-api.md#icinga2-api-actions-process-check-result).
Add an `EventCommand` configuration object for the passive service auto reset event.
```
@ -311,6 +338,11 @@ if [ "$SERVICE_STATE_ID" -gt 0 ]; then
fi
```
> **Note**
>
> Replace the deprecated command pipe EXEC statement with a curl call
> to the REST API action [process-check-result](12-icinga2-api.md#icinga2-api-actions-process-check-result).
Finally create the `Service` and assign it:
```
@ -361,6 +393,11 @@ EDESC
2. The service name, state and text are extracted from the first three varbinds.
This has the advantage of accommodating an unlimited set of use cases.
> **Note**
>
> Replace the deprecated command pipe EXEC statement with a curl call
> to the REST API action [process-check-result](12-icinga2-api.md#icinga2-api-actions-process-check-result).
Create a `Service` for the specific use case associated to the host. If the host
matches and the first varbind value is `Backup`, SNMPTT will submit the corresponding
passive update with the state and text from the second and third varbind:
@ -385,4 +422,66 @@ object Service "Backup" {
vars.dummy_state = 2
vars.dummy_text = "No passive check result received."
}
```
```
## Agents sending Check Results via REST API <a id="agent-based-checks-rest-api"></a>
Whenever the remote agent cannot run the Icinga agent, or a backup script
should just send its current state after finishing, you can use the [REST API](12-icinga2-api.md#icinga2-api)
as secure transport and send [passive external check results](08-advanced-topics.md#external-check-results).
Use the [process-check-result](12-icinga2-api.md#icinga2-api-actions-process-check-result) API action to send the external passive check result.
You can either use `curl` or implement the HTTP requests in your preferred programming
language. Examples for API clients are available in [this chapter](12-icinga2-api.md#icinga2-api-clients).
Feeding check results from remote hosts requires the host/service
objects configured on the master/satellite instance.
## NSClient++ on Windows <a id="agent-based-checks-nsclient"></a>
[NSClient++](https://nsclient.org/) works on both Windows and Linux platforms and is well
known for its magnificent Windows support. There are alternatives like the WMI interface,
but using `NSClient++` will allow you to run local scripts similar to check plugins fetching
the required output and performance counters.
> **Tip**
>
> Best practice is to use the Icinga agent as secure execution
> bridge (`check_nt` and `check_nrpe` are considered insecure)
> and query the NSClient++ service [locally](06-distributed-monitoring.md#distributed-monitoring-windows-nscp).
You can use the `check_nt` plugin from the Monitoring Plugins project to query NSClient++.
Icinga 2 provides the [nscp check command](10-icinga-template-library.md#plugin-check-command-nscp) for this:
Example:
```
object Service "disk" {
import "generic-service"
host_name = "remote-windows-host"
check_command = "nscp"
vars.nscp_variable = "USEDDISKSPACE"
vars.nscp_params = "c"
vars.nscp_warn = 70
vars.nscp_crit = 80
}
```
For details on the `NSClient++` configuration please refer to the [official documentation](https://docs.nsclient.org/).
## WMI on Windows <a id="agent-based-checks-wmi"></a>
The most popular plugin is [check_wmi_plus](http://edcint.co.nz/checkwmiplus/).
> Check WMI Plus uses the Windows Management Interface (WMI) to check for common services (cpu, disk, sevices, eventlog…) on Windows machines. It requires the open source wmi client for Linux.
Community examples:
* [Icinga 2 check_wmi_plus example by 18pct](http://18pct.com/icinga2-check_wmi_plus-example/)
* [Agent-less monitoring with WMI](https://www.devlink.de/linux/icinga2-nagios-agentless-monitoring-von-windows/)

View File

@ -376,7 +376,7 @@ object TimePeriod "prod-notification" {
}
```
## External Check Results <a id="external-check-results"></a>
## External Passive Check Results <a id="external-check-results"></a>
Hosts or services which do not actively execute a check plugin to receive
the state and output are called "passive checks" or "external check results".
@ -529,7 +529,7 @@ System | Memory, Swap | [mem](10-icinga-template-library.md#plugin-contrib-co
System | Hardware | [hpasm](10-icinga-template-library.md#plugin-contrib-command-hpasm), [ipmi-sensor](10-icinga-template-library.md#plugin-contrib-command-ipmi-sensor)
System | Virtualization | [VMware](10-icinga-template-library.md#plugin-contrib-vmware), [esxi_hardware](10-icinga-template-library.md#plugin-contrib-command-esxi-hardware)
System | Processes | [procs](10-icinga-template-library.md#plugin-check-command-processes), [service-windows](10-icinga-template-library.md#windows-plugins) (Windows Client)
System | System Activity Reports | [check_sar_perf](https://github.com/dnsmichi/icinga-plugins/blob/master/scripts/check_sar_perf.py)
System | System Activity Reports | [sar-perf](10-icinga-template-library.md#plugin-contrib-command-sar-perf)
System | I/O | [iostat](10-icinga-template-library.md#plugin-contrib-command-iostat)
System | Network interfaces | [nwc_health](10-icinga-template-library.md#plugin-contrib-command-nwc_health), [interfaces](10-icinga-template-library.md#plugin-contrib-command-interfaces)
System | Users | [users](10-icinga-template-library.md#plugin-check-command-users), [users-windows](10-icinga-template-library.md#windows-plugins) (Windows Client)
@ -543,7 +543,7 @@ Database | PostgreSQL | [postgres](10-icinga-template-library.md#plugin-contri
Database | Housekeeping | Check the database size and growth and analyse metrics to examine trends.
Database | DB IDO | [ido](10-icinga-template-library.md#itl-icinga-ido) (more below)
Webserver | Apache2, Nginx, etc. | [http](10-icinga-template-library.md#plugin-check-command-http), [apache-status](10-icinga-template-library.md#plugin-contrib-command-apache-status), [nginx_status](10-icinga-template-library.md#plugin-contrib-command-nginx_status)
Webserver | Certificates | [http](10-icinga-template-library.md#plugin-check-command-http)
Webserver | Certificates | [http](10-icinga-template-library.md#plugin-check-command-http), [Icinga certificate monitoring](https://icinga.com/products/icinga-certificate-monitoring/)
Webserver | Authorization | [http](10-icinga-template-library.md#plugin-check-command-http)
Notifications | Mail (queue) | [smtp](10-icinga-template-library.md#plugin-check-command-smtp), [mailq](10-icinga-template-library.md#plugin-check-command-mailq)
Notifications | SMS (GSM modem) | [check_sms3_status](https://exchange.icinga.com/netways/check_sms3status)
@ -578,7 +578,10 @@ apply Service "ido-mysql" {
More specific database queries can be found in the [DB IDO](14-features.md#db-ido) chapter.
Distributed setups should include specific [health checks](06-distributed-monitoring.md#distributed-monitoring-health-checks).
You might also want to add additional checks for SSL certificate expiration.
You might also want to add additional checks for TLS certificate expiration.
This can be done using the [Icinga certificate monitoring](https://icinga.com/products/icinga-certificate-monitoring/) module.
## Advanced Configuration Hints <a id="advanced-configuration-hints"></a>

View File

@ -1091,7 +1091,7 @@ Configuration Attributes:
accept\_config | Boolean | **Optional.** Accept zone configuration. Defaults to `false`.
accept\_commands | Boolean | **Optional.** Accept remote commands. Defaults to `false`.
max\_anonymous\_clients | Number | **Optional.** Limit the number of anonymous client connections (not configured endpoints and signing requests).
cipher\_list | String | **Optional.** Cipher list that is allowed. For a list of available ciphers run `openssl ciphers`. Defaults to `ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256`.
cipher\_list | String | **Optional.** Cipher list that is allowed. For a list of available ciphers run `openssl ciphers`. Defaults to `ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:AES256-GCM-SHA384:AES128-GCM-SHA256`.
tls\_protocolmin | String | **Optional.** Minimum TLS protocol version. Since v2.11, only `TLSv1.2` is supported. Defaults to `TLSv1.2`.
tls\_handshake\_timeout | Number | **Optional.** TLS Handshake timeout. Defaults to `10s`.
access\_control\_allow\_origin | Array | **Optional.** Specifies an array of origin URLs that may access the API. [(MDN docs)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Access-Control-Allow-Origin)

View File

@ -76,7 +76,7 @@ plugin scripts.
### icinga <a id="itl-icinga"></a>
Check command for the built-in `icinga` check. This check returns performance
data for the current Icinga instance and optionally allows for minimum version checks.
data for the current Icinga instance, reports as warning if the last reload failed and optionally allows for minimum version checks.
Custom variables passed as [command parameters](03-monitoring-basics.md#command-passing-parameters):
@ -1485,6 +1485,21 @@ users_wgreater | **Optional.** The user count warning threshold. Defaults to 20
users_cgreater | **Optional.** The user count critical threshold. Defaults to 50.
### uptime <a id="plugin-check-command-uptime"></a>
The [check_uptime](https://www.monitoring-plugins.org/doc/man/check_uptime.html) plugin
checks the uptime of the system using /proc/uptime.
Custom variables passed as [command parameters](03-monitoring-basics.md#command-passing-parameters):
Name | Description
----------------|--------------
uptime_warning | **Required.** Min. number of uptime to generate warning (-w 30m). Defaults to 30m.
uptime_critical | **Required.** Min. number of uptime to generate critical alert (-c 15m). Defaults to 15m.
uptime_for | **Optional.** Show uptime in a pretty format (Running for x weeks, x days, ...). Defaults to false.
uptime_since | **Optional.** Show last boot in yyyy-mm-dd HH:MM:SS format (output from 'uptime -s'). Defaults to false.
## Windows Plugins for Icinga 2 <a id="windows-plugins"></a>
@ -3145,6 +3160,7 @@ nwc_health_privpassword | **Optional.** The password for authPriv security le
nwc_health_privprotocol | **Optional.** The private protocol for SNMPv3 (des\|aes\|aes128\|3des\|3desde).
nwc_health_contextengineid | **Optional.** The context engine id for SNMPv3 (10 to 64 hex characters).
nwc_health_contextname | **Optional.** The context name for SNMPv3 (empty represents the default context).
nwc_health_community2 | **Optional.** SNMP community which can be used to switch the context during runtime.
nwc_health_name | **Optional.** The name of an interface (ifDescr).
nwc_health_drecksptkdb | **Optional.** This parameter must be used instead of --name, because Devel::ptkdb is stealing the latter from the command line.
nwc_health_alias | **Optional.** The alias name of a 64bit-interface (ifAlias)
@ -3154,6 +3170,7 @@ nwc_health_ifspeedout | **Optional.** Override the ifspeed oid of an interface
nwc_health_ifspeed | **Optional.** Override the ifspeed oid of an interface
nwc_health_units | **Optional.** One of %, B, KB, MB, GB, Bit, KBi, MBi, GBi. (used for e.g. mode interface-usage)
nwc_health_name2 | **Optional.** The secondary name of a component.
nwc_health_name3 | **Optional.** The tertiary name of a component.
nwc_health_role | **Optional.** The role of this device in a hsrp group (active/standby/listen).
nwc_health_report | **Optional.** Can be used to shorten the output. Possible values are: 'long' (default), 'short' (to shorten if available), or 'html' (to produce some html outputs if available)
nwc_health_lookback | **Optional.** The amount of time you want to look back when calculating average rates. Use it for mode interface-errors or interface-usage. Without --lookback the time between two runs of check_nwc_health is the base for calculations. If you want your checkresult to be based for example on the past hour, use --lookback 3600.
@ -3291,6 +3308,19 @@ mem_cache | **Optional.** If set to true, plugin will count cache as free mem
mem_warning | **Required.** Specify the warning threshold as number interpreted as percent.
mem_critical | **Required.** Specify the critical threshold as number interpreted as percent.
#### sar-perf <a id="plugin-contrib-command-sar-perf"></a>
The [check_sar_perf.py](https://github.com/dnsmichi/check-sar-perf)
plugin collects performance metrics from Linux hosts using the `sar` binary available in the `sysstat` package.
Custom variables passed as [command parameters](03-monitoring-basics.md#command-passing-parameters):
Name | Description
-----------------|-----------------------------------------------------------------------------------------------------------------------
sar_perf_profile | **Required.** Define the run profile: `pagestat`, `cpu`, `memory_util`, `memory_stat`, `io_transfer`, `queueln_load`, `swap_util`, `swap_stat`, `task`, `kernel`, `disk <disk>`. Can be a string or an array of multiple profiles.
sar_perf_disk | **Optional.** Disk name for the 'disk' profile.
#### running_kernel <a id="plugin-contrib-command-running_kernel"></a>
The [check_running_kernel](https://packages.debian.org/stretch/nagios-plugins-contrib) plugin

View File

@ -2400,7 +2400,7 @@ $ vim icinga.py
import requests, json
# Replace 'localhost' with your FQDN and certificate CN
# for SSL verification
# for TLS verification
request_url = "https://localhost:5665/v1/objects/services"
headers = {
'Accept': 'application/json',
@ -2444,7 +2444,7 @@ $ vim icinga.rb
require 'rest_client'
# Replace 'localhost' with your FQDN and certificate CN
# for SSL verification
# for TLS verification
request_url = "https://localhost:5665/v1/objects/services"
headers = {
"Accept" => "application/json",
@ -2491,7 +2491,7 @@ $ vim icinga.php
#!/usr/bin/env php
<?php
# Replace 'localhost' with your FQDN and certificate CN
# for SSL verification
# for TLS verification
$request_url = "https://localhost:5665/v1/objects/services";
$username = "root";
$password = "icinga";
@ -2556,7 +2556,7 @@ use JSON;
use Data::Dumper;
# Replace 'localhost' with your FQDN and certificate CN
# for SSL verification
# for TLS verification
my $request_host = "https://localhost:5665";
my $userpass = "root:icinga";

View File

@ -1,6 +1,27 @@
# Icinga 2 Addons <a id="addons"></a>
# Icinga 2 Addons and Integrations <a id="addons"></a>
## Graphing <a id="addons-graphing"></a>
For an uptodate overview of all integrations and modules,
please visit [https://icinga.com/products/](https://icinga.com/products/).
## Icinga Reporting <a id="addons-reporting"></a>
The [Icinga Reporting Module](https://icinga.com/docs/reporting/latest/)
is the framework and foundation we created to handle data collected
by Icinga 2 and other data providers. By definition Icinga Reporting does not collect
or calculate any data. The framework processes usable data from data providers such as
Icingas IDO or Icinga Web 2 modules and makes them available in different formats.
It can display the data directly within the Icinga web interface or export it to PDF,
JSON or CSV format. With scheduled reports you can receive the prepared data periodically
via email.
![Icinga Reporting](images/addons/icinga_reporting.png)
Follow along in this [hands-on blog post](https://icinga.com/2019/06/17/icinga-reporting-hands-on/).
## Graphs and Metrics <a id="addons-graphs-metrics"></a>
### Graphite <a id="addons-graphing-graphite"></a>
@ -80,10 +101,6 @@ Set `perfdata_spool_dir = /var/spool/icinga2/perfdata` and restart the `npcd` da
There's also an Icinga Web 2 module for direct PNP graph integration
available at [Icinga Exchange](https://exchange.icinga.com/icinga/PNP).
More information on [action_url as attribute](13-addons.md#addons-graphing-pnp-action-url)
and [graph template names](13-addons.md#addons-graphing-pnp-custom-templates).
## Visualization <a id="addons-visualization"></a>
### Maps <a id="addons-visualization-maps"></a>
@ -99,6 +116,27 @@ installation, configuration and integration.
![Icinga Web 2 Maps](images/addons/icingaweb2_maps.png)
### Business Process <a id="addons-business-process"></a>
Create top-level views of your applications in a graphical editor.
Rules express dependencies between existing hosts and services and
let you alert on application level. Business processes are displayed
in a tree or list overview and can be added to any dashboard.
![Icinga Web 2 Business Process](images/addons/icingaweb2_businessprocess.png)
Read more [here](https://icinga.com/products/icinga-business-process-modelling/).
### Certificate Monitoring <a id="addons-visualization-certificate-monitoring"></a>
Monitor your certificates in an efficient and comfortable way. Be aware of required
actions and view all details at a glance.
![Icinga Certificate Monitoring](images/addons/icinga_certificate_monitoring.png)
Read more [here](https://icinga.com/products/icinga-certificate-monitoring/)
and [here](https://icinga.com/2019/06/03/monitoring-automation-with-icinga-certificate-monitoring/).
### Dashing Dashboard <a id="addons-visualization-dashing-dashboard"></a>
The [Icinga 2 dashboard](https://github.com/dnsmichi/dashing-icinga2) is built
@ -111,40 +149,6 @@ host and service problem lists as Iframe.
![Dashing dashboard](images/addons/dashing_icinga2.png)
### Business Process <a id="addons-business-process"></a>
Create top-level views of your applications in a graphical editor.
Rules express dependencies between existing hosts and services and
let you alert on application level. Business processes are displayed
in a tree or list overview and can be added to any dashboard.
![Icinga Web 2 Business Process](images/addons/icingaweb2_businessprocess.png)
### NagVis <a id="addons-visualization-nagvis"></a>
By using the [DB IDO](14-features.md#db-ido) feature
you can create your own network maps
based on your monitoring configuration and status data using [NagVis](https://www.nagvis.org).
The configuration in nagvis.ini.php should look like this for Livestatus for example:
```
[backend_live_1]
backendtype="mklivestatus"
socket="unix:/var/run/icinga2/cmd/livestatus"
```
If you are planning an integration into Icinga Web 2, look at [this module](https://github.com/Icinga/icingaweb2-module-nagvis).
### Icinga Reporting <a id="addons-visualization-reporting"></a>
By enabling the [DB IDO](14-features.md#db-ido) feature you can use the
[Icinga Reporting package](https://icinga.com/docs/icinga1/latest/en/reporting.html).
### Thruk <a id="addons-visualization-thruk"></a>
[Thruk](https://www.thruk.org) is an alternative web interface which can be used with Icinga 2
and the [Livestatus](14-features.md#setting-up-livestatus) feature.
## Log Monitoring <a id="log-monitoring"></a>
@ -170,6 +174,10 @@ There's a variety of resources available, for example different notification scr
* Ticket systems
* etc.
Blog posts and howtos:
* [Environmental Monitoring and Alerting](https://icinga.com/2019/09/02/environmental-monitoring-and-alerting-via-text-message/)
Additionally external services can be [integrated with Icinga 2](https://icinga.com/products/integrations/):
* [Pagerduty](https://icinga.com/products/integrations/pagerduty/)
@ -180,73 +188,13 @@ More information can be found on the [Icinga Website](https://icinga.com/).
## Configuration Management Tools <a id="configuration-tools"></a>
If you require your favourite configuration tool to export the Icinga 2 configuration, please get in
touch with their developers. The Icinga project does not provide a configuration web interface
yet. Follow the [Icinga Blog](https://icinga.com/blog/) for updates on this topic.
Checkout these specific integrations:
If you're looking for puppet manifests, chef cookbooks, ansible recipes, etc. -- we're happy
to integrate them upstream, so please get in touch with the [Icinga team](https://icinga.com/community/).
* [Ansible Roles](https://icinga.com/products/integrations/)
* [Puppet Module](https://icinga.com/products/integrations/puppet/)
* [Chef Cookbook](https://icinga.com/products/integrations/chef/)
These tools are currently in development and require feedback and tests:
If you're looking for different config management integrations -- we're happy
to add them upstream, so please get in touch with the [Icinga team](https://icinga.com/community/).
* [Ansible Roles](https://github.com/Icinga/icinga2-ansible)
* [Puppet Module](https://github.com/Icinga/puppet-icinga2)
* [Chef Cookbook](https://github.com/Icinga/chef-icinga2)
## More Addon Integration Hints <a id="addon-integration-hints"></a>
### PNP Action Url <a id="addons-graphing-pnp-action-url"></a>
They work in a similar fashion for Icinga 2 and are used for 1.x web interfaces (Icinga Web 2 doesn't require
the action url attribute in its own module).
```
template Host "pnp-hst" {
action_url = "/pnp4nagios/graph?host=$HOSTNAME$"
}
template Service "pnp-svc" {
action_url = "/pnp4nagios/graph?host=$HOSTNAME$&srv=$SERVICEDESC$"
}
```
### PNP Custom Templates with Icinga 2 <a id="addons-graphing-pnp-custom-templates"></a>
PNP automatically determines the graph template from the check command name (or the argument's name).
This behavior changed in Icinga 2 compared to Icinga 1.x. Though there are certain possibilities to
fix this:
* Create a symlink for example from the `templates.dist/check_ping.php` template to the actual check name in Icinga 2 (`templates/ping4.php`)
* Pass the check command name inside the [format template configuration](14-features.md#writing-performance-data-files)
The latter becomes difficult with agent based checks like NRPE or SSH where the first command argument acts as
graph template identifier. There is the possibility to define the pnp template name as custom variable
and use that inside the formatting templates as `SERVICECHECKCOMMAND` for instance.
Example for services:
```
# vim /etc/icinga2/features-enabled/perfdata.conf
service_format_template = "DATATYPE::SERVICEPERFDATA\tTIMET::$icinga.timet$\tHOSTNAME::$host.name$\tSERVICEDESC::$service.name$\tSERVICEPERFDATA::$service.perfdata$\tSERVICECHECKCOMMAND::$service.check_command$$pnp_check_arg1$\tHOSTSTATE::$host.state$\tHOSTSTATETYPE::$host.state_type$\tSERVICESTATE::$service.state$\tSERVICESTATETYPE::$service.state_type$"
# vim /etc/icinga2/conf.d/services.conf
template Service "pnp-svc" {
action_url = "/pnp4nagios/graph?host=$HOSTNAME$&srv=$SERVICEDESC$"
vars.pnp_check_arg1 = ""
}
apply Service "nrpe-check" {
import "pnp-svc"
check_command = nrpe
vars.nrpe_command = "check_disk"
vars.pnp_check_arg1 = "!$nrpe_command$"
}
```
If there are warnings about unresolved macros, make sure to specify a default value for `vars.pnp_check_arg1` inside the
In PNP, the custom template for nrpe is then defined in `/etc/pnp4nagios/custom/nrpe.cfg`
and the additional command arg string will be seen in the xml too for other templates.

View File

@ -225,7 +225,7 @@ expects the Graphite Carbon Cache to listen at `127.0.0.1` on TCP port `2003`.
#### Graphite Schema <a id="graphite-carbon-cache-writer-schema"></a>
The current naming schema is defined as follows. The [Icinga Web 2 Graphite module](https://github.com/icinga/icingaweb2-module-graphite)
The current naming schema is defined as follows. The [Icinga Web 2 Graphite module](https://icinga.com/products/integrations/graphite/)
depends on this schema.
The default prefix for hosts and services is configured using
@ -386,7 +386,7 @@ apply Service "disk" for (disk => attributes in host.vars.disks) {
}
```
This is a typical pattern for checking individual disks, NICs, SSL certificates etc associated
This is a typical pattern for checking individual disks, NICs, TLS certificates etc associated
with a host. What would be useful is to have the data points tagged with the specific instance
for that check. This would allow you to query time series data for a check on a host and for a
specific instance e.g. /dev/sda. To do this quite simply add the instance to the service variables:
@ -438,14 +438,14 @@ where the InfluxDB HTTP API or Telegraf as Proxy are running.
### Elastic Stack Integration <a id="elastic-stack-integration"></a>
[Icingabeat](https://github.com/icinga/icingabeat) is an Elastic Beat that fetches data
[Icingabeat](https://icinga.com/products/integrations/elastic/) is an Elastic Beat that fetches data
from the Icinga 2 API and sends it either directly to [Elasticsearch](https://www.elastic.co/products/elasticsearch)
or [Logstash](https://www.elastic.co/products/logstash).
More integrations:
* [Logstash output](https://github.com/Icinga/logstash-output-icinga) for the Icinga 2 API.
* [Logstash Grok Pattern](https://github.com/Icinga/logstash-grok-pattern) for Icinga 2 logs.
* [Logstash output](https://icinga.com/products/integrations/elastic/) for the Icinga 2 API.
* [Logstash Grok Pattern](https://icinga.com/products/integrations/elastic/) for Icinga 2 logs.
#### Elasticsearch Writer <a id="elasticsearch-writer"></a>

View File

@ -3,7 +3,8 @@
## Required Information <a id="troubleshooting-information-required"></a>
Please ensure to provide any detail which may help reproduce and understand your issue.
Whether you ask on the community channels or you create an issue at [GitHub](https://github.com/Icinga), make sure
Whether you ask on the [community channels](https://community.icinga.com) or you
create an issue at [GitHub](https://github.com/Icinga), make sure
that others can follow your explanations. If necessary, draw a picture and attach it for
better illustration. This is especially helpful if you are troubleshooting a distributed
setup.
@ -44,7 +45,7 @@ is also key to identify bottlenecks and issues.
* Analyze the system's performance and dentify bottlenecks and issues.
* Collect details about all applications (e.g. Icinga 2, MySQL, Apache, Graphite, Elastic, etc.).
* If data is exchanged via network (e.g. central MySQL cluster) ensure to monitor the bandwidth capabilities too.
* Add graphs and screenshots to your issue description
* Add graphs from Grafana or Graphite as screenshots to your issue description
Install tools which help you to do so. Opinions differ, let us know if you have any additions here!
@ -107,6 +108,16 @@ You can also start `perfmon` and analyze specific performance counters.
Keep notes which could be important for your monitoring, and add service
checks later on.
> **Tip**
>
> Use an administrative Powershell to gain more insights.
```
cd C:\ProgramData\icinga2\var\log\icinga2
Get-Content .\icinga2.log -tail 10 -wait
```
## Enable Debug Output <a id="troubleshooting-enable-debug-output"></a>
### Enable Debug Output on Linux/Unix <a id="troubleshooting-enable-debug-output-linux"></a>
@ -120,6 +131,13 @@ Enable the `debuglog` feature:
The debug log file can be found in `/var/log/icinga2/debug.log`.
You can tail the log files with an administrative shell:
```
cd /var/log/icinga2
tail -f debug.log
```
Alternatively you may run Icinga 2 in the foreground with debugging enabled. Specify the console
log severity as an additional parameter argument to `-x`.
@ -132,18 +150,29 @@ and `debug`.
### Enable Debug Output on Windows <a id="troubleshooting-enable-debug-output-windows"></a>
Open a command prompt with administrative privileges and enable the debug log feature.
Open a Powershell with administrative privileges and enable the debug log feature.
```
C:> icinga2.exe feature enable debuglog
C:\> cd C:\Program Files\ICINGA2\sbin
C:\Program Files\ICINGA2\sbin> .\icinga2.exe feature enable debuglog
```
Ensure that the Icinga 2 service already writes the main log into `C:\ProgramData\icinga2\var\log\icinga2`.
Restart the Icinga 2 service and open the newly created `debug.log` file.
Restart the Icinga 2 service in an administrative Powershell and open the newly created `debug.log` file.
```
C:> net stop icinga2
C:> net start icinga2
C:\> Restart-Service icinga2
C:\> Get-Service icinga2
```
You can tail the log files with an administrative Powershell:
```
C:\> cd C:\ProgramData\icinga2\var\log\icinga2
C:\ProgramData\icinga2\var\log\icinga2> Get-Content .\debug.log -tail 10 -wait
```
## Configuration Troubleshooting <a id="troubleshooting-configuration"></a>
@ -187,6 +216,14 @@ Object 'localhost!ssh' of type 'Service':
[...]
```
On Windows, use an administrative Powershell:
```
C:\> cd C:\Program Files\ICINGA2\sbin
C:\Program Files\ICINGA2\sbin> .\icinga2.exe object list
```
You can also filter by name and type:
```
@ -326,6 +363,9 @@ $ curl -k -s -u root:icinga -H 'Accept: application/json' -H 'X-HTTP-Method-Over
}
```
Alternatively when using the Director, navigate into the Service Detail View
in Icinga Web and pick `Inspect` to query the details.
Example for using the `icinga2 console` CLI command evaluation functionality:
```
@ -351,17 +391,34 @@ Example for searching the debug log:
### Checks are not executed <a id="checks-not-executed"></a>
* First off, decide whether the checks are executed locally, or remote in a distributed setup.
If the master does not receive check results from the satellite, move your analysis to the satellite
and verify why the checks are not executed there.
* Check the [debug log](15-troubleshooting.md#troubleshooting-enable-debug-output) to see if the check command gets executed.
* Verify that failed depedencies do not prevent command execution.
* Verify that failed dependencies do not prevent command execution.
* Make sure that the plugin is executable by the Icinga 2 user (run a manual test).
* Make sure the [checker](11-cli-commands.md#enable-features) feature is enabled.
* Use the Icinga 2 API [event streams](12-icinga2-api.md#icinga2-api-event-streams) to receive live check result streams.
Examples:
Test a plugin as icinga user.
```
# sudo -u icinga /usr/lib/nagios/plugins/check_ping -4 -H 127.0.0.1 -c 5000,100% -w 3000,80%
```
> **Note**
>
> **Never test plugins as root, but the icinga daemon user.** The environment and permissions differ.
>
> Also, the daemon user **does not** spawn a terminal shell (Bash, etc.) so it won't read anything from .bashrc
> and variants. The Icinga daemon only relies on sysconfig environment variables being set.
Enable the checker feature.
```
# icinga2 feature enable checker
The feature 'checker' is already enabled.
```
@ -369,7 +426,8 @@ The feature 'checker' is already enabled.
Fetch all check result events matching the `event.service` name `random`:
```
$ curl -k -s -u root:icinga -H 'Accept: application/json' -X POST 'https://localhost:5665/v1/events?queue=debugchecks&types=CheckResult&filter=match%28%22random*%22,event.service%29'
$ curl -k -s -u root:icinga -H 'Accept: application/json' -X POST \
'https://localhost:5665/v1/events?queue=debugchecks&types=CheckResult&filter=match%28%22random*%22,event.service%29'
```
@ -411,7 +469,10 @@ $ curl -k -s -u root:icinga -H 'Accept: application/json' -H 'X-HTTP-Method-Over
}
```
Example for using the `icinga2 console` CLI command evaluation functionality:
Alternatively when using the Director, navigate into the Service Detail View
in Icinga Web and pick `Inspect` to query the details.
Example with the debug console:
```
$ ICINGA2_API_PASSWORD=icinga icinga2 console --connect 'https://root@localhost:5665/' \
@ -663,7 +724,7 @@ but you can adjust this by omitting the `len()` call inside the for loop.
## Notifications Troubleshooting <a id="troubleshooting-notifications"></a>
### Notifications are not sent <a id="notifications-not-sent"></a>
### Notifications are not sent <a id="troubleshooting-notifications-not-sent"></a>
* Check the [debug log](15-troubleshooting.md#troubleshooting-enable-debug-output) to see if a notification is triggered.
* If yes, verify that all conditions are satisfied.
@ -707,6 +768,96 @@ You can use the Icinga 2 API [event streams](12-icinga2-api.md#icinga2-api-event
$ curl -k -s -u root:icinga -H 'Accept: application/json' -X POST 'https://localhost:5665/v1/events?queue=debugnotifications&types=Notification'
```
### Analyze Notification Result <a id="troubleshooting-notifications-result"></a>
> **Note**
>
> This feature is available since v2.11 and requires all endpoints
> being updated.
Notifications inside a HA enabled zone are balanced between the endpoints,
just like checks.
Sometimes notifications may fail, and with looking into the (debug) logs
for both masters, you cannot correlate this correctly.
The `last_notification_result` runtime attribute is stored and synced for Notification
objects and can be queried via REST API.
Example for retrieving the notification object and result from all `disk` services using a
[regex match](18-library-reference.md#global-functions-regex) on the name:
```
$ curl -k -s -u root:icinga -H 'Accept: application/json' -H 'X-HTTP-Method-Override: GET' -X POST 'https://localhost:5665/v1/objects/notifications' \
-d '{ "filter": "regex(pattern, service.name)", "filter_vars": { "pattern": "^disk" }, "attrs": [ "__name", "last_notification_result" ], "pretty": true }'
{
"results": [
{
"attrs": {
"last_notification_result": {
"active": true,
"command": [
"/etc/icinga2/scripts/mail-service-notification.sh",
"-4",
"",
"-6",
"",
"-b",
"",
"-c",
"",
"-d",
"2019-08-02 10:54:16 +0200",
"-e",
"disk",
"-l",
"icinga2-agent1.localdomain",
"-n",
"icinga2-agent1.localdomain",
"-o",
"DISK OK - free space: / 38108 MB (90.84% inode=100%);",
"-r",
"user@localdomain",
"-s",
"OK",
"-t",
"RECOVERY",
"-u",
"disk"
],
"execution_end": 1564736056.186217,
"execution_endpoint": "icinga2-master1.localdomain",
"execution_start": 1564736056.132323,
"exit_status": 0.0,
"output": "",
"type": "NotificationResult"
}
},
"joins": {},
"meta": {},
"name": "icinga2-agent1.localdomain!disk!mail-service-notification",
"type": "Notification"
}
...
]
}
```
Example with the debug console:
```
$ ICINGA2_API_PASSWORD=icinga icinga2 console --connect 'https://root@localhost:5665/' --eval 'get_object(Notification, "icinga2-agent1.localdomain!disk!mail-service-notification").last_notification_result.execution_endpoint' | jq
"icinga2-agent1.localdomain"
```
Whenever a notification command failed to execute, you can fetch the output as well.
## Feature Troubleshooting <a id="troubleshooting-features"></a>
### Feature is not working <a id="feature-not-working"></a>
@ -858,30 +1009,40 @@ systemctl restart icinga2
## Certificate Troubleshooting <a id="troubleshooting-certificate"></a>
Tools for analysing certificates and TLS connections:
- `openssl` binary on Linux/Unix, `openssl.exe` on Windows ([download](https://slproweb.com/products/Win32OpenSSL.html))
- `sslscan` tool, available [here](https://github.com/rbsec/sslscan) (Linux/Windows)
Note: You can also execute sslscan on Windows using Powershell.
### Certificate Verification <a id="troubleshooting-certificate-verification"></a>
If the TLS handshake fails when a client connects to the cluster or the REST API,
Whenever the TLS handshake fails when a client connects to the cluster or the REST API,
ensure to verify the used certificates.
Print the CA and client certificate and ensure that the following attributes are set:
* Version must be 3.
* Serial number is a hex-encoded string.
* Issuer should be your certificate authority (defaults to `Icinga CA` for all CLI commands).
* Validity, meaning to say the certificate is not expired.
* Issuer should be your certificate authority (defaults to `Icinga CA` for all certificates generated by CLI commands and automated signing requests).
* Validity: The certificate must not be expired.
* Subject with the common name (CN) matches the client endpoint name and its FQDN.
* v3 extensions must set the basic constraint for `CA:TRUE` (ca.crt) or `CA:FALSE` (client certificate).
* Subject Alternative Name is set to a proper DNS name (required for REST API and browsers).
* Subject Alternative Name is set to the resolvable DNS name (required for REST API and browsers).
Navigate into the local certificate store:
```
# cd /var/lib/icinga2/certs/
$ cd /var/lib/icinga2/certs/
```
CA certificate:
Print the CA certificate:
```
# openssl x509 -in ca.crt -text
$ openssl x509 -in ca.crt -text
Certificate:
Data:
@ -906,10 +1067,10 @@ Certificate:
...
```
Client public certificate:
Print the client public certificate:
```
# openssl x509 -in icinga2-agent1.localdomain.crt -text
$ openssl x509 -in icinga2-agent1.localdomain.crt -text
Certificate:
Data:
@ -941,23 +1102,46 @@ Make sure to verify the client's certificate and its received `ca.crt` in `/var/
both instances are signed by the **same CA**.
```
# openssl verify -verbose -CAfile /var/lib/icinga2/certs/ca.crt /var/lib/icinga2/certs/icinga2-master1.localdomain.crt
icinga2-master1.localdomain.crt: OK
$ openssl verify -verbose -CAfile /var/lib/icinga2/certs/ca.crt /var/lib/icinga2/certs/icinga2-master1.localdomain.crt
icinga2-master1.localdomain.crt: OK
```
```
$ openssl verify -verbose -CAfile /var/lib/icinga2/certs/ca.crt /var/lib/icinga2/certs/icinga2-agent1.localdomain.crt
# openssl verify -verbose -CAfile /var/lib/icinga2/certs/ca.crt /var/lib/icinga2/certs/icinga2-agent1.localdomain.crt
icinga2-agent1.localdomain.crt: OK
```
Fetch the `ca.crt` file from the client node and compare it to your master's `ca.crt` file:
```
# scp icinga2-agent1:/var/lib/icinga2/certs/ca.crt test-client-ca.crt
# diff -ur /var/lib/icinga2/certs/ca.crt test-client-ca.crt
$ scp icinga2-agent1:/var/lib/icinga2/certs/ca.crt test-client-ca.crt
$ diff -ur /var/lib/icinga2/certs/ca.crt test-client-ca.crt
```
<!--
### Certificate Signing <a id="troubleshooting-certificate-signing"></a>
-->
Icinga offers two methods:
* [CSR Auto-Signing](06-distributed-monitoring.md#distributed-monitoring-setup-csr-auto-signing) which uses a client (an agent or a satellite) ticket generated on the master as trust identifier.
* [On-Demand CSR Signing](06-distributed-monitoring.md#distributed-monitoring-setup-on-demand-csr-signing) which allows to sign pending certificate requests on the master.
Whenever a signed certificate is not received on the requesting clients, ensure to check the following:
* The ticket was valid and the master's log shows nothing different (CSR Auto-Signing only)
* If the agent/satellite is directly connected to the CA master, check whether the master actually has performance problems to process the request. If the connection is closed without certificate response, analyse the master's health. It is also advised to upgrade to v2.11 where network stack problems have been fixed.
* If you're using a 3+ level cluster, check whether the satellite really forwarded the CSR signing request and the master processed it.
Other common errors:
* The generated ticket is invalid. The client receives this error message, as well as the master logs a warning message.
* The [api](09-object-types.md#objecttype-apilistener) feature does not have the `ticket_salt` attribute set to the generated `TicketSalt` constant by the CLI wizards.
In case you are using On-Demand CSR Signing, `icinga2 ca list` on the master only lists
pending requests since v2.11. Add `--all` to also see signed requests. Keep in mind that
old requests are purged after 1 week automatically.
### TLS Handshake: Ciphers <a id="troubleshooting-certificate-handshake-ciphers"></a>
@ -967,6 +1151,8 @@ standards. This includes TLS v1.2 as minimum protocol version too.
In case the TLS handshake fails with `no shared cipher`, first analyse whether both
instances support the same ciphers.
#### Client connects to Server <a id="troubleshooting-certificate-handshake-ciphers-client"></a>
Connect using `openssl s_client` and try to reproduce the connection problem.
> **Important**
@ -979,7 +1165,7 @@ Connect using `openssl s_client` and try to reproduce the connection problem.
`openssl s_client` tells you about the supported and shared cipher suites
on the remove server. `openssl ciphers` lists locally available ciphers.
on the remote server. `openssl ciphers` lists locally available ciphers.
```
$ openssl s_client -connect 192.168.33.5:5665
@ -1022,8 +1208,24 @@ in the `api` feature configuration accordingly.
Beware of using insecure ciphers, this may become a
security risk in your organisation.
#### Server Accepts Client <a id="troubleshooting-certificate-handshake-ciphers-server"></a>
#### Cipher Scan Tools
If the master node does not actively connect to the satellite/agent node(s), but instead
the child node actively connectsm, you can still simulate a TLS handshake.
Use `openssl s_server` instead of `openssl s_client` on the master during the connection
attempt.
```
$ openssl s_server -connect 192.168.56.101:5665
```
Since the server role chooses the preferred cipher suite in Icinga,
you can test-drive the "agent connects to master" mode here, granted that
the TCP connection is not blocked by the firewall.
#### Cipher Scan Tools <a id="troubleshooting-certificate-handshake-ciphers-scantools"></a>
You can also use different tools to test the available cipher suites, this is what SSL Labs, etc.
provide for TLS enabled websites as well. [This post](https://superuser.com/questions/109213/how-do-i-list-the-ssl-tls-cipher-suites-a-particular-website-offers)
@ -1075,26 +1277,7 @@ Not valid before: Jul 12 07:39:55 2019 GMT
Not valid after: Jul 8 07:39:55 2034 GMT
```
### Certificate Problems with OpenSSL 1.1.0 <a id="troubleshooting-certificate-openssl-1-1-0"></a>
Users have reported problems with SSL certificates inside a distributed monitoring setup when they
* updated their Icinga 2 package to 2.7.0 on Windows or
* upgraded their distribution which included an update to OpenSSL 1.1.0.
Example during startup on a Windows client:
```
critical/SSL: Error loading and verifying locations in ca key file 'C:\ProgramData\icinga2\etc/icinga2/pki/ca.crt': 219029726, "error:0D0E20DE:asn1 encoding routines:c2i_ibuf:illegal zero content"
critical/config: Error: Cannot make SSL context for cert path: 'C:\ProgramData\icinga2\etc/icinga2/pki/client.crt' key path: 'C:\ProgramData\icinga2\etc/icinga2/pki/client.key' ca path: 'C:\ProgramData\icinga2\etc/icinga2/pki/ca.crt'.
```
A technical analysis and solution for re-creating the public CA certificate is
available in [this advisory](https://icinga.com/2017/08/30/advisory-for-ssl-problems-with-leading-zeros-on-openssl-1-1-0/).
## Cluster and Clients Troubleshooting <a id="troubleshooting-cluster"></a>
## Distributed Troubleshooting <a id="troubleshooting-cluster"></a>
This applies to any Icinga 2 node in a [distributed monitoring setup](06-distributed-monitoring.md#distributed-monitoring-scenarios).
@ -1125,12 +1308,12 @@ works (default port is `5665`).
# nmap icinga2-agent1.localdomain
```
### Cluster Troubleshooting SSL Errors <a id="troubleshooting-cluster-ssl-errors"></a>
### Cluster Troubleshooting TLS Errors <a id="troubleshooting-cluster-tls-errors"></a>
If the cluster communication fails with SSL error messages, make sure to check
If the cluster communication fails with TLS/SSL error messages, make sure to check
the following
* File permissions on the SSL certificate files
* File permissions on the TLS certificate files
* Does the used CA match for all cluster endpoints?
* Verify the `Issuer` being your trusted CA
* Verify the `Subject` containing your endpoint's common name (CN)
@ -1139,7 +1322,7 @@ the following
Try to manually connect from `icinga2-agent1.localdomain` to the master node `icinga2-master1.localdomain`:
```
# openssl s_client -CAfile /var/lib/icinga2/certs/ca.crt -cert /var/lib/icinga2/certs/icinga2-agent1.localdomain.crt -key /var/lib/icinga2/certs/icinga2-agent1.localdomain.key -connect icinga2-master1.localdomain:5665
$ openssl s_client -CAfile /var/lib/icinga2/certs/ca.crt -cert /var/lib/icinga2/certs/icinga2-agent1.localdomain.crt -key /var/lib/icinga2/certs/icinga2-agent1.localdomain.key -connect icinga2-master1.localdomain:5665
CONNECTED(00000003)
---
@ -1151,7 +1334,7 @@ If the connection attempt fails or your CA does not match, [verify the certifica
#### Cluster Troubleshooting Unauthenticated Clients <a id="troubleshooting-cluster-unauthenticated-clients"></a>
Unauthenticated nodes are able to connect. This is required for client setups.
Unauthenticated nodes are able to connect. This is required for agent/satellite setups.
Master:
@ -1159,13 +1342,14 @@ Master:
[2015-07-13 18:29:25 +0200] information/ApiListener: New client connection for identity 'icinga2-agent1.localdomain' (unauthenticated)
```
Client as command execution bridge:
Agent as command execution bridge:
```
[2015-07-13 18:29:26 +1000] notice/ClusterEvents: Discarding 'execute command' message from 'icinga2-master1.localdomain': Invalid endpoint origin (client not allowed).
```
If these messages do not go away, make sure to [verify the master and client certificates](15-troubleshooting.md#troubleshooting-certificate-verification).
If these messages do not go away, make sure to [verify the master and agent certificates](15-troubleshooting.md#troubleshooting-certificate-verification).
### Cluster Troubleshooting Message Errors <a id="troubleshooting-cluster-message-errors"></a>
@ -1179,21 +1363,25 @@ for later synchronisation, you should make sure to check why the network connect
Ensure to setup [cluster health checks](06-distributed-monitoring.md#distributed-monitoring-health-checks)
to monitor all endpoints and zones connectivity.
### Cluster Troubleshooting Command Endpoint Errors <a id="troubleshooting-cluster-command-endpoint-errors"></a>
Command endpoints can be used [for clients](06-distributed-monitoring.md#distributed-monitoring-top-down-command-endpoint)
Command endpoints can be used [for agents](06-distributed-monitoring.md#distributed-monitoring-top-down-command-endpoint)
as well as inside an [High-Availability cluster](06-distributed-monitoring.md#distributed-monitoring-scenarios).
There is no cli command for manually executing the check, but you can verify
There is no CLI command for manually executing the check, but you can verify
the following (e.g. by invoking a forced check from the web interface):
* `/var/log/icinga2/icinga2.log` contains connection and execution errors.
* The ApiListener is not enabled to [accept commands](06-distributed-monitoring.md#distributed-monitoring-top-down-command-endpoint).
* `CheckCommand` definition not found on the remote client.
* Referenced check plugin not found on the remote client.
* `/var/log/icinga2/icinga2.log` shows connection and execution errors.
* The ApiListener is not enabled to [accept commands](06-distributed-monitoring.md#distributed-monitoring-top-down-command-endpoint). This is visible as `UNKNOWN` check result output.
* `CheckCommand` definition not found on the remote client. This is visible as `UNKNWON` check result output.
* Referenced check plugin not found on the remote agent.
* Runtime warnings and errors, e.g. unresolved runtime macros or configuration problems.
* Specific error messages are also populated into `UNKNOWN` check results including a detailed error message in their output.
* Verify the `check_source` object attribute. This is populated by the node executing the check.
* Verify the [check source](15-troubleshooting.md#checks-check-source). This is populated by the node executing the check. You can see that in Icinga Web's detail view or by querying the REST API for this checkable object.
Additional tasks:
* More verbose logs are found inside the [debug log](15-troubleshooting.md#troubleshooting-enable-debug-output).
* Use the Icinga 2 API [event streams](12-icinga2-api.md#icinga2-api-event-streams) to receive live check result streams.
@ -1208,16 +1396,93 @@ $ curl -k -s -u root:icinga -H 'Accept: application/json' -X POST 'https://local
### Cluster Troubleshooting Config Sync <a id="troubleshooting-cluster-config-sync"></a>
If the cluster zones do not sync their configuration, make sure to check the following:
In order to troubleshoot this, remember the key things with the config sync:
* Within a config master zone, only one configuration master is allowed to have its config in `/etc/icinga2/zones.d`.
** The master syncs the configuration to `/var/lib/icinga2/api/zones/` during startup and only syncs valid configuration to the other nodes.
** The other nodes receive the configuration into `/var/lib/icinga2/api/zones/`.
* The `icinga2.log` log file in `/var/log/icinga2` will indicate whether this ApiListener
[accepts config](06-distributed-monitoring.md#distributed-monitoring-top-down-config-sync), or not.
* The config master copies the zone configuration from `/etc/icinga2/zones.d` to `/var/lib/icinga2/api/zones`. This storage is the same for all cluster endpoints, and the source for all config syncs.
* The config master puts the `.authoritative` marker on these zone files locally. This is to ensure that it doesn't receive config updates from other endpoints. If you have copied the content from `/var/lib/icinga2/api/zones` to another node, ensure to remove them.
* During startup, the master validates the entire configuration and only syncs valid configuration to other zone endpoints.
Verify the object's [version](09-object-types.md#object-types) attribute on all nodes to
check whether the config update and reload was successful or not.
Satellites/Agents < 2.11 store the received configuration directly in `/var/lib/icinga2/api/zones`, validating it and reloading the daemon.
Satellites/Agents >= 2.11 put the received configuration into the staging directory `/var/lib/icinga2/api/zones-stage` first, and will only copy this to the production directory `/var/lib/icinga2/api/zones` once the validation was successful.
The configuration sync logs the operations during startup with the `information` severity level. Received zone configuration is also logged.
Typical errors are:
* The api feature doesn't [accept config](06-distributed-monitoring.md#distributed-monitoring-top-down-config-sync). This is logged into `/var/lib/icinga2/icinga2.log`.
* The received configuration zone is not configured in [zones.conf](04-configuration.md#zones-conf) and Icinga denies it. This is logged into `/var/lib/icinga2/icinga2.log`.
* The satellite/agent has local configuration in `/etc/icinga2/zones.d` and thinks it is authoritive for this zone. It then denies the received update. Purge the content from `/etc/icinga2/zones.d`, `/var/lib/icinga2/api/zones/*` and restart Icinga to fix this.
#### New configuration does not trigger a reload <a id="troubleshooting-cluster-config-sync-no-reload"></a>
The debug/notice log dumps the calculated checksums for all files and the comparison. Analyse this to troubleshoot further.
A complete sync for the `director-global` global zone can look like this:
```
[2019-08-01 09:20:25 +0200] notice/JsonRpcConnection: Received 'config::Update' message from 'icinga2-master1.localdomain'
[2019-08-01 09:20:25 +0200] information/ApiListener: Applying config update from endpoint 'icinga2-master1.localdomain' of zone 'master'.
[2019-08-01 09:20:25 +0200] notice/ApiListener: Creating config update for file '/var/lib/icinga2/api/zones/director-global/.checksums'.
[2019-08-01 09:20:25 +0200] notice/ApiListener: Creating config update for file '/var/lib/icinga2/api/zones/director-global/.timestamp'.
[2019-08-01 09:20:25 +0200] notice/ApiListener: Creating config update for file '/var/lib/icinga2/api/zones/director-global/director/001-director-basics.conf'.
[2019-08-01 09:20:25 +0200] notice/ApiListener: Creating config update for file '/var/lib/icinga2/api/zones/director-global/director/host_templates.conf'.
[2019-08-01 09:20:25 +0200] information/ApiListener: Received configuration for zone 'director-global' from endpoint 'icinga2-master1.localdomain'. Comparing the checksums.
[2019-08-01 09:20:25 +0200] debug/ApiListener: Checking for config change between stage and production. Old (4): '{"/.checksums":"c4dd1237e36dcad9142f4d9a81324a7cae7d01543a672299
b8c1bb08b629b7d1","/.timestamp":"f21c0e6551328812d9f5176e5e31f390de0d431d09800a85385630727b404d83","/director/001-director-basics.conf":"f86583eec81c9bf3a1823a761991fb53d640bd0dc
6cd12bf8c5e6a275359970f","/director/host_templates.conf":"831e9b7e3ec1e33288e56a51e63c688da1d6316155349382a101f7fce6229ecc"}' vs. new (4): '{"/.checksums":"c4dd1237e36dcad9142f4d
9a81324a7cae7d01543a672299b8c1bb08b629b7d1","/.timestamp":"f21c0e6551328812d9f5176e5e31f390de0d431d09800a85385630727b404d83","/director/001-director-basics.conf":"f86583eec81c9bf
3a1823a761991fb53d640bd0dc6cd12bf8c5e6a275359970f","/director/host_templates.conf":"831e9b7e3ec1e33288e56a51e63c688da1d6316155349382a101f7fce6229ecc"}'.
[2019-08-01 09:20:25 +0200] debug/ApiListener: Ignoring old internal file '/.checksums'.
[2019-08-01 09:20:25 +0200] debug/ApiListener: Ignoring old internal file '/.timestamp'.
[2019-08-01 09:20:25 +0200] debug/ApiListener: Checking /director/001-director-basics.conf for old checksum: f86583eec81c9bf3a1823a761991fb53d640bd0dc6cd12bf8c5e6a275359970f.
[2019-08-01 09:20:25 +0200] debug/ApiListener: Checking /director/host_templates.conf for old checksum: 831e9b7e3ec1e33288e56a51e63c688da1d6316155349382a101f7fce6229ecc.
[2019-08-01 09:20:25 +0200] debug/ApiListener: Ignoring new internal file '/.checksums'.
[2019-08-01 09:20:25 +0200] debug/ApiListener: Ignoring new internal file '/.timestamp'.
[2019-08-01 09:20:25 +0200] debug/ApiListener: Checking /director/001-director-basics.conf for new checksum: f86583eec81c9bf3a1823a761991fb53d640bd0dc6cd12bf8c5e6a275359970f.
[2019-08-01 09:20:25 +0200] debug/ApiListener: Checking /director/host_templates.conf for new checksum: 831e9b7e3ec1e33288e56a51e63c688da1d6316155349382a101f7fce6229ecc.
[2019-08-01 09:20:25 +0200] information/ApiListener: Stage: Updating received configuration file '/var/lib/icinga2/api/zones-stage/director-global//director/001-director-basics.c
onf' for zone 'director-global'.
[2019-08-01 09:20:25 +0200] information/ApiListener: Stage: Updating received configuration file '/var/lib/icinga2/api/zones-stage/director-global//director/host_templates.conf'
for zone 'director-global'.
[2019-08-01 09:20:25 +0200] information/ApiListener: Applying configuration file update for path '/var/lib/icinga2/api/zones-stage/director-global' (2209 Bytes).
...
[2019-08-01 09:20:25 +0200] information/ApiListener: Received configuration updates (4) from endpoint 'icinga2-master1.localdomain' are different to production, triggering validation and reload.
[2019-08-01 09:20:25 +0200] notice/Process: Running command '/usr/lib/x86_64-linux-gnu/icinga2/sbin/icinga2' '--no-stack-rlimit' 'daemon' '--close-stdio' '-e' '/var/log/icinga2/e
rror.log' '--validate' '--define' 'System.ZonesStageVarDir=/var/lib/icinga2/api/zones-stage/': PID 4532
[2019-08-01 09:20:25 +0200] notice/Process: PID 4532 ('/usr/lib/x86_64-linux-gnu/icinga2/sbin/icinga2' '--no-stack-rlimit' 'daemon' '--close-stdio' '-e' '/var/log/icinga2/error.l
og' '--validate' '--define' 'System.ZonesStageVarDir=/var/lib/icinga2/api/zones-stage/') terminated with exit code 0
[2019-08-01 09:20:25 +0200] information/ApiListener: Config validation for stage '/var/lib/icinga2/api/zones-stage/' was OK, replacing into '/var/lib/icinga2/api/zones/' and trig
gering reload.
[2019-08-01 09:20:26 +0200] information/ApiListener: Copying file 'director-global//.checksums' from config sync staging to production zones directory.
[2019-08-01 09:20:26 +0200] information/ApiListener: Copying file 'director-global//.timestamp' from config sync staging to production zones directory.
[2019-08-01 09:20:26 +0200] information/ApiListener: Copying file 'director-global//director/001-director-basics.conf' from config sync staging to production zones directory.
[2019-08-01 09:20:26 +0200] information/ApiListener: Copying file 'director-global//director/host_templates.conf' from config sync staging to production zones directory.
...
[2019-08-01 09:20:26 +0200] notice/Application: Got reload command, forwarding to umbrella process (PID 4236)
```
#### Syncing Binary Files is Denied <a id="troubleshooting-cluster-config-sync-binary-denied"></a>
The config sync is built for syncing text configuration files, wrapped into JSON-RPC messages.
Some users have started to use this as binary file sync instead of using tools built for this:
rsync, git, Puppet, Ansible, etc.
Starting with 2.11, this attempt is now prohibited and logged.
```
[2019-08-02 16:03:19 +0200] critical/ApiListener: Ignoring file '/etc/icinga2/zones.d/global-templates/forbidden.exe' for cluster config sync: Does not contain valid UTF8. Binary files are not supported.
Context:
(0) Creating config update for file '/etc/icinga2/zones.d/global-templates/forbidden.exe'
(1) Activating object 'api' of type 'ApiListener'
```
In order to solve this problem, remove the mentioned files from `zones.d` and use an alternate way
of syncing plugin binaries to your satellites and agents.
### Cluster Troubleshooting Overdue Check Results <a id="troubleshooting-cluster-check-results"></a>
@ -1271,12 +1536,45 @@ Check the following:
* Does the log replay work, e.g. are all events processed and the directory gets cleared up over time?
* Decrease the `log_duration` attribute value for that specific [endpoint](09-object-types.md#objecttype-endpoint).
The cluster health checks also measure the `slave_lag` metric. Use this data to correlate
graphs with other events (e.g. disk I/O, network problems, etc).
### Cluster Troubleshooting: Windows Agents <a id="troubleshooting-cluster-windows-agents"></a>
#### Windows Service Exe Path <a id="troubleshooting-cluster-windows-agents-service-exe-path"></a>
Icinga agents can be installed either as x86 or x64 package. If you enable features, or wonder why
logs are not written, the first step is to analyse which path the Windows service `icinga2` is using.
Start a new administrative Powershell and ensure that the `icinga2` service is running.
```
C:\Program Files\ICINGA2\sbin> net start icinga2
```
Use the `Get-WmiObject` function to extract the windows service and its path name.
```
C:\Program Files\ICINGA2\sbin> Get-WmiObject win32_service | ?{$_.Name -like '*icinga*'} | select Name, DisplayName, State, PathName
Name DisplayName State PathName
---- ----------- ----- --------
icinga2 Icinga 2 Running "C:\Program Files\ICINGA2\sbin\icinga2.exe" --scm "daemon"
```
If you have used the `icinga2.exe` from a different path to enable e.g. the `debuglog` feature,
navigate into `C:\Program Files\ICINGA2\sbin\` and use the correct exe to control the feature set.
#### Windows Agents consuming 100% CPU <a id="troubleshooting-cluster-windows-agents-cpu"></a>
> **Note**
>
> The network stack was rewritten in 2.11. This fixes several hanging connections and threads
> on older Windows agents and master/satellite nodes. Prior to testing the below, plan an upgrade.
Icinga 2 requires the `NodeName` [constant](17-language-reference.md#constants) in various places to run.
This includes loading the TLS certificates, setting the proper check source,
and so on.

View File

@ -133,7 +133,7 @@ other than explicitly setting the allowed ciphers.
The new default sets this to:
```
ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256
ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:AES256-GCM-SHA384:AES128-GCM-SHA256
```
You can override this setting in the [api](09-object-types.md#objecttype-apilistener)
@ -168,6 +168,25 @@ prior to installing new clients/agents.
Technical details are available in the [technical concepts](19-technical-concepts.md#technical-concepts-cluster-config-sync) chapter.
Since the config sync change detection now uses checksums, this may fail
with anything else than syncing configuration text files. Syncing binary
files were never supported, but rumors say that some users do so.
This is now prohibited and logged.
```
[2019-08-02 16:03:19 +0200] critical/ApiListener: Ignoring file '/etc/icinga2/zones.d/global-templates/forbidden.exe' for cluster config sync: Does not contain valid UTF8. Binary files are not supported.
Context:
(0) Creating config update for file '/etc/icinga2/zones.d/global-templates/forbidden.exe'
(1) Activating object 'api' of type 'ApiListener'
```
Such binaries wrapped into JSON-RPC cluster messages may always cause changes
and trigger reload loops. In order to prevent such harm in production,
use infrastructure tools such as Foreman, Puppet, Ansible, etc. to install
plugins on the masters, satellites and agents.
#### HA-aware Features <a id="upgrading-to-2-11-cluster-ha-aware-features"></a>
v2.11 introduces additional HA functionality similar to the DB IDO feature.
@ -279,6 +298,12 @@ It will also attempt to fix them, the following log entry is perfectly fine.
If you still encounter problems, please follow [this troubleshooting entry](15-troubleshooting.md#troubleshooting-api-missing-runtime-objects).
### DB IDO MySQL Schema <a id="upgrading-to-2-11-db-ido"></a>
The schema for MySQL contains an optional update which
drops unneeded indexes. You don't necessarily need to apply
this update.
### Documentation <a id="upgrading-to-2-11-documentation"></a>
* `Custom attributes` have been renamed to `Custom variables` following the name `vars` and their usage in backends and web interfaces.

View File

@ -540,11 +540,11 @@ Each node certificate must be signed by the private CA key.
Note: The following description uses `parent node` and `child node`.
This also applies to nodes in the same cluster zone.
During the connection attempt, an SSL handshake is performed.
During the connection attempt, a TLS handshake is performed.
If the public certificate of a child node is not signed by the same
CA, the child node is not trusted and the connection will be closed.
If the SSL handshake succeeds, the parent node reads the
If the TLS handshake succeeds, the parent node reads the
certificate's common name (CN) of the child node and looks for
a local Endpoint object name configuration.
@ -754,7 +754,7 @@ that by grepping the log file for `resumed` and `paused`.
Specific features with HA capabilities are explained below.
### High Availability: Checker <a id="technical-concepts-cluster-ha-checker"></a>
#### High Availability: Checker <a id="technical-concepts-cluster-ha-checker"></a>
The `checker` feature only executes checks for `Checkable` objects (Host, Service)
where it is authoritative.
@ -765,7 +765,7 @@ The cluster message routing ensures that all check results are synchronized
to nodes which are not authoritative for this configuration object.
### High Availability: Notifications <a id="technical-concepts-cluster-notifications"></a>
#### High Availability: Notifications <a id="technical-concepts-cluster-notifications"></a>
The `notification` feature only sends notifications for `Notification` objects
where it is authoritative.
@ -775,7 +775,7 @@ That way each node only executes notifications for a segment of all notification
Notified users and other event details are synchronized throughout the cluster.
This is required if for example the DB IDO feature is active on the other node.
### High Availability: DB IDO <a id="technical-concepts-cluster-ha-ido"></a>
#### High Availability: DB IDO <a id="technical-concepts-cluster-ha-ido"></a>
If you don't have HA enabled for the IDO feature, both nodes will
write their status and historical data to their own separate database
@ -1052,6 +1052,68 @@ when e.g. hostgroup membership is used for assign where expressions, but the gro
available on the master.
### Cluster: Message Routing <a id="technical-concepts-cluster-message-routing"></a>
One fundamental part of the cluster message routing is the MessageOrigin object.
This is created when a new JSON-RPC message is received in `JsonRpcConnection::MessageHandler()`.
It contains
- FromZone being extracted from the endpoint object which owns the JsonRpcConnection
- FromClient being the JsonRpcConnection bound to the endpoint object
These attributes are checked in message receive api handlers for security access. E.g. whether a
message origin is from a child zone which is not allowed, etc.
This is explained in the [JSON-RPC messages](19-technical-concepts.md#technical-concepts-json-rpc-messages) chapter.
Whenever such a message is processed on the client, it may trigger additional cluster events
which are sent back to other endpoints. Therefore it is key to always pass the MessageOrigin
`origin` when processing these messages locally.
Example:
- Client receives a CheckResult from another endpoint in the same zone, call it `sender` for now
- Calls ProcessCheckResult() to store the CR and calculcate states, notifications, etc.
- Calls the OnNewCheckResult() signal to trigger IDO updates
OnNewCheckResult() also calls a registered cluster handler which forwards the CheckResult to other cluster members.
Without any origin details, this CheckResult would be relayed to the `sender` endpoint again.
Which processes the message, ProcessCheckResult(), OnNewCheckResult(), sends back and so on.
That creates a loop which our cluster protocol needs to prevent at all cost.
RelayMessageOne() takes care of the routing. This involves fetching the targetZone for this message and its endpoints.
- Don't relay messages to ourselves.
- Don't relay messages to disconnected endpoints.
- Don't relay the message to the zone through more than one endpoint unless this is our own zone.
- Don't relay messages back to the endpoint which we got the message from. **THIS**
- Don't relay messages back to the zone which we got the message from.
- Only relay message to the zone master if we're not currently the zone master.
```
e1 is zone master, e2 and e3 are zone members.
Message is sent from e2 or e3:
!isMaster == true
targetEndpoint e1 is zone master -> send the message
targetEndpoint e3 is not zone master -> skip it, avoid routing loops
Message is sent from e1:
!isMaster == false -> send the messages to e2 and e3 being the zone routing master.
```
With passing the `origin` the following condition prevents sending a message back to sender:
```
if (origin && origin->FromClient && targetEndpoint == origin->FromClient->GetEndpoint()) {
```
This message then simply gets skipped for this specific Endpoint and is never sent.
This analysis originates from a long-lasting [downtime loop bug](https://github.com/Icinga/icinga2/issues/7198).
## TLS Network IO <a id="technical-concepts-tls-network-io"></a>
### TLS Connection Handling <a id="technical-concepts-tls-network-io-connection-handling"></a>
@ -1085,7 +1147,7 @@ benchmark this when TCP connections are broken and timeouts are encountered.
#### Master Processes Incoming Connection <a id="technical-concepts-tls-network-io-connection-handling-incoming"></a>
* The node starts a new ApiListener, this invokes `AddListener()`
* Setup SSL Context
* Setup TLS Context (SslContext)
* Initialize global I/O engine and create a TCP acceptor
* Resolve bind host/port (optional)
* Listen on IPv4 and IPv6
@ -1101,7 +1163,7 @@ benchmark this when TCP connections are broken and timeouts are encountered.
* Loop over all configured zones, exclude global zones and not direct parent/child zones
* Get the endpoints configured in the zones, exclude: local endpoint, no 'host' attribute, already connected or in progress
* Call `AddConnection()`
* Spawn a new Coroutine after making the SSL context
* Spawn a new Coroutine after making the TLS context
* Use the global I/O engine for socket I/O
* Create TLS stream
* Connect to endpoint host/port details
@ -1713,7 +1775,7 @@ Message updates will be dropped when:
The receiver constructs a virtual host object and looks for the local CheckCommand object.
Returns UNKNWON as check result to the sender
Returns UNKNOWN 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.

View File

@ -9,7 +9,7 @@ development, package builds and tests.
* [Test Icinga 2](21-development.md#development-tests)
* [Snapshot Packages (Nightly Builds)](21-development.md#development-tests-snapshot-packages)
* [Develop Icinga 2](21-development.md#development-develop)
* [Preparations](21-development.md#development-develop-styleguide)
* [Preparations](21-development.md#development-develop-prepare)
* [Design Patterns](21-development.md#development-develop-design-patterns)
* [Build Tools](21-development.md#development-develop-builds-tools)
* [Unit Tests](21-development.md#development-develop-tests)
@ -22,6 +22,7 @@ development, package builds and tests.
* [RPM](21-development.md#development-package-builds-rpms)
* [DEB](21-development.md#development-package-builds-deb)
* [Windows](21-development.md#development-package-builds-windows)
* [Continuous Integration](21-development.md#development-ci)
* [Advanced Tips](21-development.md#development-advanced)
<!-- mkdocs requires 4 spaces indent for nested lists: https://github.com/Python-Markdown/markdown/issues/3 -->
@ -70,16 +71,15 @@ SLES/openSUSE | `zypper install gdb`
#### GDB Run <a id="development-debug-gdb-run"></a>
Call GDB with the binary (`/usr/sbin/icinga2` is a wrapper script calling
`/usr/lib64/icinga2/sbin/icinga2` since 2.4) and all arguments and run it in foreground.
Since v2.11 we would attach to the umbrella process spawned with `/usr/lib/icinga2/sbin/icinga2`,
therefore rather attach to a running process.
```
gdb --args /usr/lib64/icinga2/sbin/icinga2 daemon -x debug
```
# Typically the order of PIDs is: 1) umbrella 2) spawn helper 3) main process
pidof icinga2
The exact path to the Icinga 2 binary differs on each distribution. On Ubuntu
it is installed into `/usr/lib/x86_64-linux-gnu/icinga2/sbin/icinga2` on 64-bit systems
for example.
gdb -p $(pidof icinga2 | cut -d ' ' -f3)
```
> **Note**
>
@ -356,9 +356,14 @@ $ xcode-select --install
```
In order to run Icinga 2 with LLDB you need to pass the binary as argument.
Since v2.11 we would attach to the umbrella process, therefore rather
attach to a running process.
```
lldb -- /usr/local/icinga2/lib/icinga2/sbin/icinga2 daemon
# Typically the order of PIDs is: 1) umbrella 2) spawn helper 3) main process
pidof icinga2
lldb -p $(pidof icinga2 | cut -d ' ' -f3)
```
Breakpoint:
@ -405,6 +410,76 @@ Up/down in stacktrace:
> down
```
### Debug on Windows <a id="development-debug-windows"></a>
Whenever the application crashes, the Windows error reporting (WER) can be [configured](https://docs.microsoft.com/en-gb/windows/win32/wer/collecting-user-mode-dumps)
to create user-mode dumps.
Tail the log file with Powershell:
```
Get-Content .\icinga2.log -tail 10 -wait
```
#### Debug on Windows: Dependencies <a id="development-debug-windows-dependencies"></a>
Similar to `ldd` or `nm` on Linux/Unix.
Extract the dependent DLLs from a binary with Visual Studio's `dumpbin` tool
in Powershell:
```
C:> &'C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.22.27905\bin\Hostx64\x64\dumpbin.exe' /dependents .\debug\Bin\Debug\Debug\boosttest-test-base.exe
DEBUG: 1+ >>>> &'C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.22.27905\bin\Hostx64\x64\dumpbin.exe' /dependents .\debug\Bin\Debug\Debug\boosttest-test-base.exe
Microsoft (R) COFF/PE Dumper Version 14.22.27905.0
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file .\debug\Bin\Debug\Debug\boosttest-test-base.exe
File Type: EXECUTABLE IMAGE
Image has the following dependencies:
boost_coroutine-vc142-mt-gd-x64-1_71.dll
boost_date_time-vc142-mt-gd-x64-1_71.dll
boost_filesystem-vc142-mt-gd-x64-1_71.dll
boost_thread-vc142-mt-gd-x64-1_71.dll
boost_regex-vc142-mt-gd-x64-1_71.dll
libssl-1_1-x64.dll
libcrypto-1_1-x64.dll
WS2_32.dll
dbghelp.dll
SHLWAPI.dll
msi.dll
boost_unit_test_framework-vc142-mt-gd-x64-1_71.dll
KERNEL32.dll
SHELL32.dll
ADVAPI32.dll
MSVCP140D.dll
MSWSOCK.dll
bcrypt.dll
VCRUNTIME140D.dll
ucrtbased.dll
Summary
1000 .00cfg
68000 .data
B000 .idata
148000 .pdata
69C000 .rdata
25000 .reloc
1000 .rsrc
E7A000 .text
1000 .tls
```
## Test Icinga 2 <a id="development-tests"></a>
### Snapshot Packages (Nightly Builds) <a id="development-tests-snapshot-packages"></a>
@ -749,6 +824,9 @@ Depending on the file type, this must be a comment.
#### Code Formatting <a id="development-develop-code-formatting"></a>
**Tabs instead of spaces.** Inside Visual Studio, choose to keep tabs instead of
spaces. Tabs should use 4 spaces indent by default, depending on your likings.
We follow the clang format, with some exceptions.
- Curly braces for functions and classes always start at a new line.
@ -1241,19 +1319,24 @@ Create two build directories for different binary builds.
mkdir -p release debug
```
Proceed with the specific distribution examples below.
Proceed with the specific distribution examples below. Keep in mind that these instructions
are best effort and sometimes out-of-date. Git Master may contain updates.
* [CentOS 7](21-development.md#development-linux-dev-env-centos)
* [Debian 9](21-development.md#development-linux-dev-env-debian)
* [Debian 10 Buster](21-development.md#development-linux-dev-env-debian)
* [Ubuntu 18 Bionic](21-development.md#development-linux-dev-env-ubuntu)
#### CentOS 7 <a id="development-linux-dev-env-centos"></a>
```
yum -y install gdb git bash-completion htop rpmdevtools \
ccache cmake make gcc-c++ flex bison \
openssl-devel boost-devel systemd-devel mysql-devel \
postgresql-devel libedit-devel libstdc++-devel
yum -y install gdb vim git bash-completion htop
yum -y install rpmdevtools ccache \
cmake make gcc-c++ flex bison \
openssl-devel boost169-devel systemd-devel \
mysql-devel postgresql-devel libedit-devel \
libstdc++-devel
groupadd icinga
groupadd icingacmd
@ -1263,14 +1346,46 @@ ln -s /bin/ccache /usr/local/bin/gcc
ln -s /bin/ccache /usr/local/bin/g++
git clone https://github.com/icinga/icinga2.git && cd icinga2
mkdir debug release
cd debug
cmake .. -DCMAKE_BUILD_TYPE=Debug -DICINGA2_UNITY_BUILD=OFF -DCMAKE_INSTALL_PREFIX=/usr/local/icinga2 -DICINGA2_PLUGINDIR=/usr/local/sbin
cd ..
make -j2 install -C debug
```
The debug build binaries contain specific code which runs
slower but allows for better debugging insights.
For benchmarks, change `CMAKE_BUILD_TYPE` to `RelWithDebInfo` and
build inside the `release` directory.
First, off export some generics for Boost.
```
export I2_BOOST="-DBoost_NO_BOOST_CMAKE=TRUE -DBoost_NO_SYSTEM_PATHS=TRUE -DBOOST_LIBRARYDIR=/usr/lib64/boost169 -DBOOST_INCLUDEDIR=/usr/include/boost169 -DBoost_ADDITIONAL_VERSIONS='1.69;1.69.0'"
```
Second, add the prefix path to it.
```
export I2_GENERIC="$I2_BOOST -DCMAKE_INSTALL_PREFIX=/usr/local/icinga2"
```
Third, define the two build types with their specific CMake variables.
```
export I2_DEBUG="-DCMAKE_BUILD_TYPE=Debug -DICINGA2_UNITY_BUILD=OFF $I2_GENERIC"
export I2_RELEASE="-DCMAKE_BUILD_TYPE=RelWithDebInfo -DICINGA2_WITH_TESTS=ON -DICINGA2_UNITY_BUILD=ON $I2_GENERIC"
```
Fourth, depending on your likings, you may add a bash alias for building,
or invoke the commands inside:
```
alias i2_debug="cd /root/icinga2; mkdir -p debug; cd debug; cmake $I2_DEBUG ..; make -j2; sudo make -j2 install; cd .."
alias i2_release="cd /root/icinga2; mkdir -p release; cd release; cmake $I2_RELEASE ..; make -j2; sudo make -j2 install; cd .."
```
This is taken from the [centos7-dev](https://github.com/Icinga/icinga-vagrant/tree/master/centos7-dev) Vagrant box.
The source installation doesn't set proper permissions, this is
handled in the package builds which are officially supported.
```
chown -R icinga:icinga /usr/local/icinga2/var/
@ -1279,14 +1394,26 @@ chown -R icinga:icinga /usr/local/icinga2/var/
/usr/local/icinga2/sbin/icinga2 api setup
vim /usr/local/icinga2/etc/icinga2/conf.d/api-users.conf
gdb --args /usr/local/icinga2/lib/icinga2/sbin/icinga2 daemon
/usr/local/icinga2/lib/icinga2/sbin/icinga2 daemon
```
#### Debian 9 <a id="development-linux-dev-env-debian"></a>
#### Debian 10 <a id="development-linux-dev-env-debian"></a>
Debian Buster doesn't need updated Boost packages from packages.icinga.com,
the distribution already provides 1.66+. For older versions such as Stretch,
include the release repository for packages.icinga.com as shown in the [setup instructions](02-installation.md#package-repositories-debian-ubuntu-raspbian).
```
apt-get -y install gdb vim git cmake make ccache build-essential libssl-dev libboost-all-dev bison flex default-libmysqlclient-dev libpq-dev libedit-dev monitoring-plugins
$ docker run -ti ubuntu:bionic bash
apt-get update
apt-get -y install apt-transport-https wget gnupg
apt-get -y install gdb vim git cmake make ccache build-essential libssl-dev bison flex default-libmysqlclient-dev libpq-dev libedit-dev monitoring-plugins
apt-get -y install libboost-all-dev
```
```
ln -s /usr/bin/ccache /usr/local/bin/gcc
ln -s /usr/bin/ccache /usr/local/bin/g++
@ -1297,13 +1424,22 @@ useradd -c "icinga" -s /sbin/nologin -G icingacmd -g icinga icinga
git clone https://github.com/icinga/icinga2.git && cd icinga2
mkdir debug release
export I2_DEB="-DBoost_NO_BOOST_CMAKE=TRUE -DBoost_NO_SYSTEM_PATHS=TRUE -DBOOST_LIBRARYDIR=/usr/lib/x86_64-linux-gnu -DBOOST_INCLUDEDIR=/usr/include -DCMAKE_INSTALL_RPATH=/usr/lib/x86_64-linux-gnu"
export I2_GENERIC="-DCMAKE_INSTALL_PREFIX=/usr/local/icinga2 -DICINGA2_PLUGINDIR=/usr/local/sbin"
export I2_DEBUG="$I2_DEB $I2_GENERIC -DCMAKE_BUILD_TYPE=Debug -DICINGA2_UNITY_BUILD=OFF"
cd debug
cmake .. -DCMAKE_BUILD_TYPE=Debug -DICINGA2_UNITY_BUILD=OFF -DCMAKE_INSTALL_PREFIX=/usr/local/icinga2 -DICINGA2_PLUGINDIR=/usr/local/sbin
cmake .. $I2_DEBUG
cd ..
make -j2 install -C debug
```
The source installation doesn't set proper permissions, this is
handled in the package builds which are officially supported.
```
chown -R icinga:icinga /usr/local/icinga2/var/
@ -1311,7 +1447,7 @@ chown -R icinga:icinga /usr/local/icinga2/var/
/usr/local/icinga2/sbin/icinga2 api setup
vim /usr/local/icinga2/etc/icinga2/conf.d/api-users.conf
gdb --args /usr/local/icinga2/lib/icinga2/sbin/icinga2 daemon
/usr/local/icinga2/lib/icinga2/sbin/icinga2 daemon
```
@ -1365,6 +1501,8 @@ cd ..
make -j2 install -C debug
```
The source installation doesn't set proper permissions, this is
handled in the package builds which are officially supported.
```
chown -R icinga:icinga /usr/local/icinga2/var/
@ -1373,7 +1511,7 @@ chown -R icinga:icinga /usr/local/icinga2/var/
/usr/local/icinga2/sbin/icinga2 api setup
vim /usr/local/icinga2/etc/icinga2/conf.d/api-users.conf
gdb --args /usr/local/icinga2/lib/icinga2/sbin/icinga2 daemon
/usr/local/icinga2/lib/icinga2/sbin/icinga2 daemon
```
### macOS Dev Environment <a id="development-macos-dev-env"></a>
@ -1397,7 +1535,7 @@ This requires at least v2.11.
#### Requirements
OpenSSL 1.0.x doesn't build anymore, so we're explicitly using 1.1.x here.
Explicitly use OpenSSL 1.1.x, older versions are out of support.
```
brew install ccache boost cmake bison flex openssl@1.1 mysql-connector-c++ postgresql libpq
@ -1555,6 +1693,8 @@ While it is recommended to use Docker or the Icinga Web 2 development VM pointin
The required steps are described in [this script](https://github.com/dnsmichi/dotfiles/blob/master/icingaweb2.sh).
### Windows Dev Environment <a id="development-windows-dev-env"></a>
The following sections explain how to setup the required build tools
@ -1568,52 +1708,119 @@ Open an administrative command prompt (Win key, type “cmd”, right-click and
@powershell -NoProfile -ExecutionPolicy Bypass -Command "iex ((new-object net.webclient).DownloadString('https://chocolatey.org/install.ps1'))" && SET PATH=%PATH%;%ALLUSERSPROFILE%\chocolatey\bin
```
In case you are used to `vim`, start a new administrative Powershell and run `choco install -y vim`.
#### Git, Posh and Vim
In case you are used to `vim`, start a new administrative Powershell:
```
choco install -y vim
```
The same applies for Git integration in Powershell:
```
choco install -y poshgit
```
![Powershell Posh Git](images/development/windows_powershell_posh_git.png)
In order to fix the colors for commands like `git status` or `git diff`,
edit `$HOME/.gitconfig` in your Powershell and add the following lines:
```
vim $HOME/.gitconfig
[color "status"]
changed = cyan bold
untracked = yellow bold
added = green bold
branch = cyan bold
unmerged = red bold
[color "diff"]
frag = cyan
new = green bold
commit = yellow
old = red white
[color "branch"]
current = yellow reverse
local = yellow
remote = green bold
remote = red bold
```
#### Visual Studio
Thanks to Microsoft theyll now provide their Professional Edition of Visual Studio 2017
Thanks to Microsoft theyll now provide their Professional Edition of Visual Studio
as community version, free for use for open source projects such as Icinga.
The installation requires ~9GB disk space. [Download](https://www.visualstudio.com/downloads/)
the web installer and start the installation.
Note: Both Visual Studio 2017 and 2019 are covered here. Older versions
are not supported.
You need a free Microsoft account to download and also store your preferences.
Install the following Workloads:
Install the following complete workloads:
* C++ Desktop
* .NET Desktop
* C++ Desktop Development
* .NET Desktop Development
In addition also choose these individual components on Visual Studio 2017:
In addition also choose these individual components on Visual Studio:
* .NET
* .NET Framework 4.6 targeting pack
* .NET Framework 4.6.1 SDK
* .NET Framework 4.6.1 targeting pack
* .NET Framework 4.x targeting packs
* .NET Framework 4.x.y SDKs
* Code tools
* Git for Windows
* Static analysis tools
* GitHub Extension for Visual Studio
* NuGet package manager
* Compilers, build tools and runtimes
* C# and Visual Basic Roslyn compilers
* C++/CLI Support
* VC++ 2017 v141 toolset (x86_64)
* C++ 2019 Redistributable Update
* C++ CMake tools for Windows
* C++/CLI Support for v142 build tools (14.22)
* MSBuild
* MSVC v142 - VS 2019 C++ x64/x86 build tools (v14.22)
* Debugging and testing
* .NET profiling tools
* C++ profiling tools
* Just-in-Time debugger
* Development activities
* Visual Studio C++ core features
* C# and Visual Basic
* C++ core features
* IntelliCode
* Live Share
* Games and Graphics
* Graphics debugger and GPU profiler for DirectX (required by C++ profiling tools)
* SDKs, libraries and frameworks
* Graphics Tools Windows 8.1 SDK (required by C++ profiling tools)
* Windows 10 SDK **10.0.10240.0 - exactly this version**
* Windows 8.1 SDK
* Windows 10 SDK (10.0.18362.0 or later)
* Windows Universal C Runtime
![Visual Studio Installer](images/development/windows_visual_studio_installer_01.png)
![Visual Studio Installer](images/development/windows_visual_studio_installer_02.png)
![Visual Studio Installer](images/development/windows_visual_studio_installer_03.png)
After a while, Visual Studio will be ready.
##### Style Guide for Visual Studio
Navigate into `Tools > Options > Text Editor` and repeat the following for
- C++
- C#
Navigate into `Tabs` and set:
- Indenting: Smart (default)
- Tab size: 4
- Indent size: 4
- Keep tabs (instead of spaces)
![Visual Studio Tabs](images/development/windows_visual_studio_tabs_c++.png)
#### Flex and Bison
Install it using [chocolatey](https://www.wireshark.org/docs/wsdg_html_chunked/ChSetupWin32.html):
@ -1626,10 +1833,8 @@ Chocolatey installs these tools into the hidden directory `C:\ProgramData\chocol
#### OpenSSL
Icinga 2 requires the OpenSSL library. [Download](http://slproweb.com/products/Win32OpenSSL.html)
and install it into the default path.
Install both, 32 and 64 bit variants.
Icinga 2 requires the OpenSSL library. [Download](http://slproweb.com/products/Win32OpenSSL.html) the Win64 package
and install it into `c:\local\OpenSSL-Win64`.
Once asked for `Copy OpenSSLs DLLs to` select `The Windows system directory`. That way CMake/Visual Studio
will automatically detect them for builds and packaging.
@ -1642,21 +1847,46 @@ will automatically detect them for builds and packaging.
#### Boost
Icinga needs the development header and library files from the Boost library.
Visual Studio translates into the following compiler versions:
- `msvc-14.1` = Visual Studio 2017
- `msvc-14.2` = Visual Studio 2019
##### Pre-built Binaries
Prefer the pre-built package over self-compiling, if the newest version already exists.
Download the [boost-binaries](https://sourceforge.net/projects/boost/files/boost-binaries/) for
- msvc-14.2 is Visual Studio 2019
- 64 for 64 bit builds
```
https://sourceforge.net/projects/boost/files/boost-binaries/1.71.0/boost_1_71_0-msvc-14.2-64.exe/download
```
Run the installer and leave the default installation path in `C:\local\boost_1_71_0`.
##### Source & Compile
In order to use the boost development header and library files you need to [download](http://www.boost.org/users/download/)
Boost and then extract it to e.g. `C:\boost_1_69_0`.
Boost and then extract it to e.g. `C:\local\boost_1_71_0`.
> **Note**
>
> Just use `C:`, the zip file already contains the sub folder. Extraction takes a while,
> Just use `C:\local`, the zip file already contains the sub folder. Extraction takes a while,
> the archive contains more than 70k files.
In order to integrate Boost into Visual Studio 2017, open the `Developer Command Prompt` from the start menu,
and navigate to `C:\boost_1_69_0`.
In order to integrate Boost into Visual Studio, open the `Developer Command Prompt` from the start menu,
and navigate to `C:\local\boost_1_71_0`.
Execute `bootstrap.bat` first.
```
cd C:\boost_1_69_0
cd C:\local\boost_1_71_0
bootstrap.bat
```
@ -1666,10 +1896,10 @@ which isn't treated as exception safe by the VS compiler. Therefore set the
additional compilation flag according to [this entry](https://lists.boost.org/Archives/boost/2015/08/224570.php).
```
b2 --toolset=msvc-14.1 asmflags=\safeseh
b2 --toolset=msvc-14.2 link=static threading=multi runtime-link=static address-model=64 asmflags=\safeseh
```
![Windows Boost Build in VS2017 Development Console](images/development/windows_boost_build_dev_cmd.png)
![Windows Boost Build in VS Development Console](images/development/windows_boost_build_dev_cmd.png)
#### TortoiseGit
@ -1715,7 +1945,11 @@ when asked.
> **Note**
>
> In order to properly detect the Boost libraries, install the CMake 3.14+.
> In order to properly detect the Boost libraries and VS 2019, install CMake 3.15.2+.
>
> **Tip**
>
> Cheatsheet: http://www.brianlheim.com/2018/04/09/cmake-cheat-sheet.html
Once setup is completed, open a command prompt and navigate to
@ -1725,12 +1959,17 @@ cd %HOMEPATH%\source\repos
Build Icinga with specific CMake variables. This generates a new Visual Studio project file called `icinga2.sln`.
You need to specify the previously installed component paths:
Visual Studio translates into the following:
- `msvc-14.1` = Visual Studio 2017
- `msvc-14.2` = Visual Studio 2019
You need to specify the previously installed component paths.
Variable | Value | Description
----------------------|----------------------------------------------------------------------|-------------------------------------------------------
`BOOST_ROOT` | `C:\boost_1_69_0` | Root path where you've extracted and compiled Boost.
`BOOST_LIBRARYDIR` | `C:\boost_1_69_0\stage` | Path to the static compiled Boost libraries, directory must contain `lib`.
`BOOST_ROOT` | `C:\local\boost_1_71_0` | Root path where you've extracted and compiled Boost.
`BOOST_LIBRARYDIR` | Binary: `C:\local\boost_1_71_0\lib64-msvc-14.1`, Source: `C:\local\boost_1_71_0\stage` | Path to the static compiled Boost libraries, directory must contain `lib`.
`BISON_EXECUTABLE` | `C:\ProgramData\chocolatey\lib\winflexbison\tools\win_bison.exe` | Path to the Bison executable.
`FLEX_EXECUTABLE` | `C:\ProgramData\chocolatey\lib\winflexbison\tools\win_flex.exe` | Path to the Flex executable.
`ICINGA2_WITH_MYSQL` | OFF | Requires extra setup for MySQL if set to `ON`. Not supported for client setups.
@ -1747,31 +1986,39 @@ Open a new Powershell and navigate into the cloned Git repository. Set
specific environment variables and run the build scripts.
```
cd %HOMEPATH%\source\repos
cd %HOMEPATH%\source\repos\icinga2
$env:ICINGA2_BUILDPATH='debug'
$env:CMAKE_BUILD_TYPE='Debug'
$env:OPENSSL_ROOT_DIR='C:\OpenSSL-Win64'
$env:BOOST_ROOT='C:\boost_1_69_0'
$env:BOOST_LIBRARYDIR='C:\boost_1_69_0\stage'
.\tools\win32\configure.ps1
.\tools\win32\configure-dev.ps1
.\tools\win32\build.ps1
.\tools\win32\test.ps1
```
> **Note**
>
> You may need to modify `configure.ps1` and
> add a changed CMake variable for the installation
> prefix: `-DCMAKE_INSTALL_PREFIX="C:\Program Files\Icinga2-build"`.
The debug MSI package is located in the `debug` directory.
If you did not follow the above steps with Boost binaries
and OpenSSL paths, or using VS 2017, you can still modify
the environment variables.
```
$env:CMAKE_GENERATOR='Visual Studio 16 2019'
$env:CMAKE_GENERATOR_PLATFORM='x64'
$env:ICINGA2_INSTALLPATH = 'C:\Program Files\Icinga2-debug'
$env:ICINGA2_BUILDPATH='debug'
$env:CMAKE_BUILD_TYPE='Debug'
$env:OPENSSL_ROOT_DIR='C:\OpenSSL-Win64'
$env:BOOST_ROOT='C:\local\boost_1_71_0'
$env:BOOST_LIBRARYDIR='C:\local\boost_1_71_0\lib64-msvc-14.2'
```
#### Icinga 2 in Visual Studio
This requires running the configure script once.
Navigate to
```
cd %HOMEPATH%\source\repos\icinga2
cd %HOMEPATH%\source\repos\icinga2\debug
```
Open `icinga2.sln`. Log into Visual Studio when asked.
@ -1791,28 +2038,21 @@ icinga2.exe --version
#### Release Package
This is part of the build process script already.
> **Note**
>
> You may need to modify `configure.ps1` and
> add a changed CMake variable for the installation
> prefix: `-DCMAKE_INSTALL_PREFIX="C:\Program Files\Icinga2-build"`.
This is part of the build process script. Override the build type and pick a different
build directory.
```
cd %HOMEPATH%\source\repos
cd %HOMEPATH%\source\repos\icinga2
$env:ICINGA2_BUILDPATH='debug'
$env:CMAKE_BUILD_TYPE='Debug'
$env:OPENSSL_ROOT_DIR='C:\OpenSSL-Win64'
$env:BOOST_ROOT='C:\boost_1_69_0'
$env:BOOST_LIBRARYDIR='C:\boost_1_69_0\stage'
$env:ICINGA2_BUILDPATH='release'
$env:CMAKE_BUILD_TYPE='RelWithDebInfo'
.\tools\win32\configure.ps1
.\tools\win32\configure-dev.ps1
.\tools\win32\build.ps1
.\tools\win32\test.ps1
```
The release MSI package is located in the `release` directory.
### Embedded Dev Env: Pi <a id="development-embedded-dev-env"></a>
@ -2134,6 +2374,7 @@ The following packages are required to build the SELinux policy module:
The RedHat Developer Toolset is required for building Icinga 2 beforehand.
This contains a modern version of flex and a C++ compiler which supports
C++11 features.
```
cat >/etc/yum.repos.d/devtools-2.repo <<REPO
[testing-devtools-2-centos-\$releasever]
@ -2186,7 +2427,7 @@ After building Icinga 2 yourself, your package build system should at least run
install requirements:
* enable the `checker`, `notification` and `mainlog` feature by default
* run 'icinga2 api setup' in order to enable the `api` feature and generate SSL certificates for the node
* run 'icinga2 api setup' in order to enable the `api` feature and generate TLS certificates for the node
### Run Icinga 2 <a id="development-package-builds-run-icinga"></a>
@ -2255,99 +2496,53 @@ sysconfdir.
The Windows MSI packages are located at https://packages.icinga.com/windows/
#### Requirements <a id="development-package-builds-windows-requirements"></a>
The build infrastructure is based on GitLab CI and an Ansible provisioned
Windows VM running in OpenStack.
* 32 or 64-bit system
* Visual Studio >= 14 2015
* CMake >= 2.6
* OpenSSL >= 1.0.1
* Flex and Bison
The runner uses the scripts located in `tools/win32` to configure, build
and test the packages. Uploading them to the package repository is a
separate step. For manual package creation, please refer to [this chapter](21-development.md#development-windows-dev-env).
##### Visual Studio
Download the community edition from [visualstudio.com](https://www.visualstudio.com/en/downloads/)
Workloads to install:
* C++ Desktop
* .NET Desktop
##### OpenSSL for Icinga
Download custom OpenSSL builds from [openssl-windows GitHub project](https://github.com/Icinga/openssl-windows/releases).
You need to install a binary dist version to 'C:\\Program Files\\OpenSSL'.
The Powershell script `.\tools\win32\download-openssl.ps1` can be used for automated downloads.
##### Chocolatey
A simple package manager for Windows, please see [install instructions](https://chocolatey.org/install).
##### Git
Use Chocolatey, see [package details](https://chocolatey.org/packages/git).
```
choco install git
```
##### Flex / Bison
Use Chocolatey, see [package details](https://chocolatey.org/packages/winflexbison3).
```
choco install winflexbison3
```
##### CMake
Use Chocolatey, see [package details](https://chocolatey.org/packages/cmake)
or download from: [cmake.org](https://cmake.org/download/)
```
choco install cmake
```
##### WIX
Use Chocolatey, see [package details](https://chocolatey.org/packages/wixtoolset).
```
choco install wixtoolset
```
##### Boost
Download third party Windows binaries from: [boost.org](http://www.boost.org/users/download/)
For example: `https://dl.bintray.com/boostorg/release/1.65.1/binaries/boost_1_65_1-msvc-14.1-64.exe`
*Warning:*
* Must match your Visual Studio version!
* CMake might not support the latest Boost version (we used CMake 3.10 and Boost 1_65_1)
Run the installer exe.
![Windows build pipeline in GitLab](images/development/windows_builds_gitlab_pipeline.png)
#### Build Icinga 2
## Continuous Integration <a id="development-ci"></a>
Run with VC Native x64 Command Prompt:
Icinga uses the integrated CI capabilities on GitHub in the development workflow.
This ensures that incoming pull requests and branches are built on create/push events.
Contributors and developers can immediately see whether builds fail or succeed and
help the final reviews.
```
powershell .\tools\win32\configure.ps1
powershell .\tools\win32\build.ps1
powershell .\tools\win32\test.ps1
```
* For Linux, we are currently using Travis CI.
* For Windows, AppVeyor has been integrated.
See these scripts for details.
Future plans involve making use of GitHub Actions.
#### CI: AppVeyor
In addition to our development platform on GitHub,
we are using GitLab's CI platform to build binary packages for
all supported operating systems and distributions.
These CI pipelines provide even more detailed insights into
specific platform failures and developers can react faster.
We are building [Icinga 2 with AppVeyor](https://ci.appveyor.com/project/icinga/icinga2) for testing and CI integration.
### CI: Travis CI
Please check `appveyor.yml` for instructions.
[Travis CI](https://travis-ci.org/Icinga/icinga2) provides Ubuntu as base
distribution where Icinga is compiled from sources followed by running the
unit tests and a config validation check.
For details, please refer to the [.travis.yml](https://github.com/Icinga/icinga2/blob/master/.travis.yml)
configuration file.
### CI: AppVeyor
[AppVeyor](https://ci.appveyor.com/project/icinga/icinga2) provides Windows
as platform where Visual Studio and Boost libraries come pre-installed.
Icinga is built using the Powershell scripts located in `tools/win32`.
In addition to that, the unit tests are run.
Please check the [appveyor.yml](https://github.com/Icinga/icinga2/blob/master/appveyor.yml) configuration
file for details.
## Advanced Development Tips <a id="development-advanced"></a>

View File

@ -6,6 +6,33 @@ The Icinga 2 configuration format introduces plenty of behavioural changes. In
order to ease migration from Icinga 1.x, this section provides hints and tips
on your migration requirements.
### Automated Config Migration <a id="automated-config-migration"></a>
Depending on your previous setup, you may have already used different sources
for generating the 1.x configuration files. If this is the case,
we strongly recommend to use these sources in combination with
the [Icinga Director](https://icinga.com/docs/director/latest/doc/01-Introduction/).
This can be for example:
* A CMDB or RDBMS which provides host details and facts
* PuppetDB
* CSV/XSL/JSON files
* Cloud resources (AWS, etc.)
In case you have been using Icinga Web 1.x or an addon requiring
the underlying IDO database, you can use this as database resource
to import the host details.
Talks:
* [This talk from OSMC 2016](https://www.youtube.com/watch?v=T6GBsfeXIZI) shares more insights (German).
* [Automated Monitoring in heterogeneous environments](https://www.youtube.com/watch?v=bkUlS5rlHzM&list=PLeoxx10paaAn_xHJ5wBhnBJyW_d5G7-Bl&index=8)
Continue reading more about [Import Sources](https://icinga.com/docs/director/latest/doc/70-Import-and-Sync/)
for the Icinga Director.
### Manual Config Migration <a id="manual-config-migration"></a>
For a long-term migration of your configuration you should consider re-creating
@ -1553,6 +1580,6 @@ and configuration distribution problems Icinga 1.x distributed monitoring curren
Icinga 2 implements a new built-in
[distributed monitoring architecture](06-distributed-monitoring.md#distributed-monitoring-scenarios),
including config and check distribution, IPv4/IPv6 support, SSL certificates and zone support for DMZ.
including config and check distribution, IPv4/IPv6 support, TLS certificates and zone support for DMZ.
High Availability and load balancing are also part of the Icinga 2 Cluster feature, next to local replay
logs on connection loss ensuring that the event history is kept in sync.

View File

@ -611,7 +611,7 @@ Not supported: `neb_callbacks`, `neb_callbacks_rate`, `requests`, `requests_rate
host_ | join | Prefix for attributes from implicit join with hosts table.
#### Livestatus Timeperiod Table Attributes <a id="schema-livestatus-timeperiod-table-attributes"></a>
#### Livestatus Timeperiods Table Attributes <a id="schema-livestatus-timeperiods-table-attributes"></a>
Key | Type | Note
----------------------|-----------|-------------------------

Binary file not shown.

After

Width:  |  Height:  |  Size: 246 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 306 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 296 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 73 KiB

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 KiB

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 81 KiB

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 75 KiB

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 115 KiB

After

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 44 KiB

View File

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 50 KiB

View File

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 48 KiB

View File

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 32 KiB

View File

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 766 B

After

Width:  |  Height:  |  Size: 27 KiB

View File

@ -1,7 +1,7 @@
/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
if (!globals.contains("NscpPath")) {
NscpPath = dirname(msi_get_component_path("{5C45463A-4AE9-4325-96DB-6E239C034F93}"))
globals.NscpPath = dirname(msi_get_component_path("{5C45463A-4AE9-4325-96DB-6E239C034F93}"))
}
object CheckCommand "nscp-local" {

View File

@ -3140,3 +3140,32 @@ object CheckCommand "rpc" {
vars.rpc_address = "$check_address$"
}
object CheckCommand "uptime" {
command = [ PluginDir + "/check_uptime" ]
arguments = {
"--warning" = {
value = "$uptime_warning$"
description = "Min. number of uptime to generate warning"
required = true
}
"--critical" = {
value = "$uptime_critical$"
description = "Min. number of uptime to generate critical alert ( w < c )"
required = true
}
"--for" = {
set_if = "$uptime_for$"
description = "Show uptime in a pretty format (Running for x weeks, x days, ...)"
}
"--since" = {
set_if = "$uptime_since$"
description = "Show last boot in yyyy-mm-dd HH:MM:SS format (output from 'uptime -s')"
}
}
vars.uptime_warning = "30m"
vars.uptime_critical = "15m"
}

View File

@ -550,6 +550,10 @@ object CheckCommand "nwc_health" {
value = "$nwc_health_contextname$"
description = "The context name for SNMPv3 (empty represents the default context)"
}
"--community2" = {
value = "$nwc_health_community2$"
description = "SNMP community which can be used to switch the context during runtime"
}
"--mode" = {
value = "$nwc_health_mode$"
description = "Which mode should be executed. A list of all available modes can be found in the plugin documentation"
@ -590,6 +594,10 @@ object CheckCommand "nwc_health" {
value = "$nwc_health_name2$"
description = "The secondary name of a component"
}
"--name3" = {
value = "$nwc_health_name3$"
description = "The tertiary name of a component"
}
"--role" = {
value = "$nwc_health_role$"
description = "The role of this device in a hsrp group (active/standby/listen)"

View File

@ -31,6 +31,26 @@ object CheckCommand "mem" {
vars.mem_cache = false
}
object CheckCommand "sar-perf" {
command = [ PluginContribDir + "/check_sar_perf.py" ]
arguments = {
"sar_perf_profile" = {
value = "$sar_perf_profile$"
description = "Define the run profile: pagestat, cpu, memory_util, memory_stat, io_transfer, queueln_load, swap_util, swap_stat, task, kernel, disk <disk>. Can be a string or an array of multiple profiles."
skip_key = true
repeat_key = false
required = true
}
"sar_perf_disk" = {
value = "$sar_perf_disk$"
set_if = {{ macro("$sar_perf_profile$") == "disk" }}
description = "Disk name for the 'disk' profile"
skip_key = true
}
}
}
object CheckCommand "running_kernel" {
command = {{
var use_sudo = macro("$running_kernel_use_sudo$")

View File

@ -357,7 +357,7 @@ void ConfigObject::PreActivate()
SetActive(true, true);
}
void ConfigObject::Activate(bool runtimeCreated)
void ConfigObject::Activate(bool runtimeCreated, const Value& cookie)
{
CONTEXT("Activating object '" + GetName() + "' of type '" + GetReflectionType()->GetName() + "'");
@ -372,7 +372,7 @@ void ConfigObject::Activate(bool runtimeCreated)
SetAuthority(true);
}
NotifyActive();
NotifyActive(cookie);
}
void ConfigObject::Stop(bool runtimeRemoved)
@ -384,7 +384,7 @@ void ConfigObject::Stop(bool runtimeRemoved)
SetStopCalled(true);
}
void ConfigObject::Deactivate(bool runtimeRemoved)
void ConfigObject::Deactivate(bool runtimeRemoved, const Value& cookie)
{
CONTEXT("Deactivating object '" + GetName() + "' of type '" + GetReflectionType()->GetName() + "'");
@ -403,7 +403,7 @@ void ConfigObject::Deactivate(bool runtimeRemoved)
ASSERT(GetStopCalled());
NotifyActive();
NotifyActive(cookie);
}
void ConfigObject::OnConfigLoaded()

View File

@ -44,8 +44,8 @@ public:
void Unregister();
void PreActivate();
void Activate(bool runtimeCreated = false);
void Deactivate(bool runtimeRemoved = false);
void Activate(bool runtimeCreated = false, const Value& cookie = Empty);
void Deactivate(bool runtimeRemoved = false, const Value& cookie = Empty);
void SetAuthority(bool authority);
void Start(bool runtimeCreated = false) override;

View File

@ -7,8 +7,9 @@
#include <exception>
#include <memory>
#include <thread>
#include <boost/asio/io_service.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/asio/spawn.hpp>
#include <boost/asio/post.hpp>
#include <boost/date_time/posix_time/ptime.hpp>
#include <boost/system/error_code.hpp>
@ -78,12 +79,12 @@ IoEngine& IoEngine::Get()
return *m_Instance.Get();
}
boost::asio::io_service& IoEngine::GetIoService()
boost::asio::io_context& IoEngine::GetIoContext()
{
return m_IoService;
return m_IoContext;
}
IoEngine::IoEngine() : m_IoService(), m_KeepAlive(m_IoService), m_Threads(decltype(m_Threads)::size_type(std::thread::hardware_concurrency() * 2u)), m_AlreadyExpiredTimer(m_IoService)
IoEngine::IoEngine() : m_IoContext(), m_KeepAlive(boost::asio::make_work_guard(m_IoContext)), m_Threads(decltype(m_Threads)::size_type(std::thread::hardware_concurrency() * 2u)), m_AlreadyExpiredTimer(m_IoContext)
{
m_AlreadyExpiredTimer.expires_at(boost::posix_time::neg_infin);
m_CpuBoundSemaphore.store(std::thread::hardware_concurrency() * 3u / 2u);
@ -96,7 +97,7 @@ IoEngine::IoEngine() : m_IoService(), m_KeepAlive(m_IoService), m_Threads(declty
IoEngine::~IoEngine()
{
for (auto& thread : m_Threads) {
m_IoService.post([]() {
boost::asio::post(m_IoContext, []() {
throw TerminateIoThread();
});
}
@ -110,7 +111,7 @@ void IoEngine::RunEventLoop()
{
for (;;) {
try {
m_IoService.run();
m_IoContext.run();
break;
} catch (const TerminateIoThread&) {
@ -122,7 +123,7 @@ void IoEngine::RunEventLoop()
}
}
AsioConditionVariable::AsioConditionVariable(boost::asio::io_service& io, bool init)
AsioConditionVariable::AsioConditionVariable(boost::asio::io_context& io, bool init)
: m_Timer(io)
{
m_Timer.expires_at(init ? boost::posix_time::neg_infin : boost::posix_time::pos_infin);

View File

@ -9,8 +9,10 @@
#include <memory>
#include <thread>
#include <vector>
#include <stdexcept>
#include <boost/exception/all.hpp>
#include <boost/asio/deadline_timer.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/asio/spawn.hpp>
namespace icinga
@ -75,7 +77,83 @@ public:
static IoEngine& Get();
boost::asio::io_service& GetIoService();
boost::asio::io_context& GetIoContext();
/*
* Custom exceptions thrown in a Boost.Coroutine may cause stack corruption.
* Ensure that these are wrapped correctly.
*
* Inspired by https://github.com/niekbouman/commelec-api/blob/master/commelec-api/coroutine-exception.hpp
* Source: http://boost.2283326.n4.nabble.com/coroutine-only-std-exceptions-are-caught-from-coroutines-td4683671.html
*/
static inline boost::exception_ptr convertExceptionPtr(std::exception_ptr ex) {
try {
throw boost::enable_current_exception(ex);
} catch (...) {
return boost::current_exception();
}
}
static inline void rethrowBoostExceptionPointer() {
std::exception_ptr sep;
sep = std::current_exception();
boost::exception_ptr bep = convertExceptionPtr(sep);
boost::rethrow_exception(bep);
}
static inline size_t GetCoroutineStackSize() {
#ifdef _WIN32
// Increase the stack size for Windows coroutines to prevent exception corruption.
// Rationale: Low cost Windows agent only & https://github.com/Icinga/icinga2/issues/7431
return 8 * 1024 * 1024;
#else /* _WIN32 */
return boost::coroutines::stack_allocator::traits_type::default_size(); // Default 64 KB
#endif /* _WIN32 */
}
/* With dedicated strand in *Connection classes. */
template <typename Handler, typename Function>
static void SpawnCoroutine(Handler h, Function f) {
boost::asio::spawn(std::forward<Handler>(h),
[f](boost::asio::yield_context yc) {
try {
f(yc);
} catch (const boost::coroutines::detail::forced_unwind &) {
// Required for proper stack unwinding when coroutines are destroyed.
// https://github.com/boostorg/coroutine/issues/39
throw;
} catch (...) {
// Handle uncaught exceptions outside of the coroutine.
rethrowBoostExceptionPointer();
}
},
boost::coroutines::attributes(GetCoroutineStackSize()) // Set a pre-defined stack size.
);
}
/* Without strand in the IO executor's context. */
template <typename Function>
static void SpawnCoroutine(boost::asio::io_context& io, Function f) {
boost::asio::spawn(io,
[f](boost::asio::yield_context yc) {
try {
f(yc);
} catch (const boost::coroutines::detail::forced_unwind &) {
// Required for proper stack unwinding when coroutines are destroyed.
// https://github.com/boostorg/coroutine/issues/39
throw;
} catch (...) {
// Handle uncaught exceptions outside of the coroutine.
rethrowBoostExceptionPointer();
}
},
boost::coroutines::attributes(GetCoroutineStackSize()) // Set a pre-defined stack size.
);
}
private:
IoEngine();
@ -84,8 +162,8 @@ private:
static LazyInit<std::unique_ptr<IoEngine>> m_Instance;
boost::asio::io_service m_IoService;
boost::asio::io_service::work m_KeepAlive;
boost::asio::io_context m_IoContext;
boost::asio::executor_work_guard<boost::asio::io_context::executor_type> m_KeepAlive;
std::vector<std::thread> m_Threads;
boost::asio::deadline_timer m_AlreadyExpiredTimer;
std::atomic_int_fast32_t m_CpuBoundSemaphore;
@ -103,7 +181,7 @@ class TerminateIoThread : public std::exception
class AsioConditionVariable
{
public:
AsioConditionVariable(boost::asio::io_service& io, bool init = false);
AsioConditionVariable(boost::asio::io_context& io, bool init = false);
void Set();
void Clear();

View File

@ -223,7 +223,7 @@ Log::~Log()
logger->ProcessLogEntry(entry);
#ifdef I2_DEBUG /* I2_DEBUG */
/* Always flush, don't depend on the timer. Enable this for development sprints. */
/* Always flush, don't depend on the timer. Enable this for development sprints on Linux/macOS only. Windows crashes. */
//logger->Flush();
#endif /* I2_DEBUG */
}

View File

@ -38,7 +38,7 @@ void Connect(Socket& socket, const String& node, const String& service)
{
using boost::asio::ip::tcp;
tcp::resolver resolver (IoEngine::Get().GetIoService());
tcp::resolver resolver (IoEngine::Get().GetIoContext());
tcp::resolver::query query (node, service);
auto result (resolver.resolve(query));
auto current (result.begin());
@ -67,7 +67,7 @@ void Connect(Socket& socket, const String& node, const String& service, boost::a
{
using boost::asio::ip::tcp;
tcp::resolver resolver (IoEngine::Get().GetIoService());
tcp::resolver resolver (IoEngine::Get().GetIoContext());
tcp::resolver::query query (node, service);
auto result (resolver.async_resolve(query, yc));
auto current (result.begin());

View File

@ -6,7 +6,7 @@
using namespace icinga;
ThreadPool::ThreadPool(size_t threads)
: m_Threads(threads)
: m_Threads(threads), m_Pending(0)
{
Start();
}

View File

@ -3,6 +3,7 @@
#ifndef THREADPOOL_H
#define THREADPOOL_H
#include "base/atomic.hpp"
#include "base/exception.hpp"
#include "base/logger.hpp"
#include <cstddef>
@ -14,6 +15,7 @@
#include <boost/asio/thread_pool.hpp>
#include <boost/thread/locks.hpp>
#include <boost/thread/shared_mutex.hpp>
#include <cstdint>
namespace icinga
{
@ -52,7 +54,11 @@ public:
boost::shared_lock<decltype(m_Mutex)> lock (m_Mutex);
if (m_Pool) {
boost::asio::post(*m_Pool, [callback]() {
m_Pending.fetch_add(1);
boost::asio::post(*m_Pool, [this, callback]() {
m_Pending.fetch_sub(1);
try {
callback();
} catch (const std::exception& ex) {
@ -70,10 +76,21 @@ public:
}
}
/**
* Returns the amount of queued tasks not started yet.
*
* @returns amount of queued tasks.
*/
inline uint_fast64_t GetPending()
{
return m_Pending.load();
}
private:
boost::shared_mutex m_Mutex;
std::unique_ptr<boost::asio::thread_pool> m_Pool;
size_t m_Threads;
Atomic<uint_fast64_t> m_Pending;
};
}

View File

@ -11,7 +11,7 @@
#include <memory>
#include <utility>
#include <boost/asio/buffered_stream.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/ssl/context.hpp>
#include <boost/asio/ssl/stream.hpp>
@ -21,7 +21,7 @@ namespace icinga
struct UnbufferedAsioTlsStreamParams
{
boost::asio::io_service& IoService;
boost::asio::io_context& IoContext;
boost::asio::ssl::context& SslContext;
const String& Hostname;
};
@ -33,7 +33,7 @@ class UnbufferedAsioTlsStream : public AsioTcpTlsStream
public:
inline
UnbufferedAsioTlsStream(UnbufferedAsioTlsStreamParams& init)
: stream(init.IoService, init.SslContext), m_VerifyOK(true), m_Hostname(init.Hostname)
: stream(init.IoContext, init.SslContext), m_VerifyOK(true), m_Hostname(init.Hostname)
{
}
@ -71,8 +71,8 @@ class AsioTlsStream : public boost::asio::buffered_stream<UnbufferedAsioTlsStrea
{
public:
inline
AsioTlsStream(boost::asio::io_service& ioService, boost::asio::ssl::context& sslContext, const String& hostname = String())
: AsioTlsStream(UnbufferedAsioTlsStreamParams{ioService, sslContext, hostname})
AsioTlsStream(boost::asio::io_context& ioContext, boost::asio::ssl::context& sslContext, const String& hostname = String())
: AsioTlsStream(UnbufferedAsioTlsStreamParams{ioContext, sslContext, hostname})
{
}

View File

@ -20,6 +20,7 @@
#include <boost/algorithm/string/replace.hpp>
#include <boost/uuid/uuid_io.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/regex.hpp>
#include <ios>
#include <fstream>
#include <iostream>
@ -1172,6 +1173,26 @@ unsigned long Utility::SDBM(const String& str, size_t len)
return hash;
}
String Utility::ParseVersion(const String& v)
{
/*
* 2.11.0-0.rc1.1
* v2.10.5
* r2.10.3
* v2.11.0-rc1-58-g7c1f716da
*/
boost::regex pattern("^[vr]?(2\\.\\d+\\.\\d+).*$");
boost::smatch result;
if (boost::regex_search(v.GetData(), result, pattern)) {
String res(result[1].first, result[1].second);
return res;
}
// Couldn't not extract anything, return unparsed version
return v;
}
int Utility::CompareVersion(const String& v1, const String& v2)
{
std::vector<String> tokensv1 = v1.Split(".");

View File

@ -100,6 +100,7 @@ public:
static unsigned long SDBM(const String& str, size_t len = String::NPos);
static String ParseVersion(const String& v);
static int CompareVersion(const String& v1, const String& v2);
static int Random();

View File

@ -537,7 +537,7 @@ std::shared_ptr<AsioTlsStream> ConsoleCommand::Connect()
String host = l_Url->GetHost();
String port = l_Url->GetPort();
std::shared_ptr<AsioTlsStream> stream = std::make_shared<AsioTlsStream>(IoEngine::Get().GetIoService(), *sslContext, host);
std::shared_ptr<AsioTlsStream> stream = std::make_shared<AsioTlsStream>(IoEngine::Get().GetIoContext(), *sslContext, host);
try {
icinga::Connect(stream->lowest_layer(), host, port);

View File

@ -24,7 +24,9 @@
#include <iostream>
#include <fstream>
#ifndef _WIN32
#ifdef _WIN32
#include <windows.h>
#else /* _WIN32 */
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
@ -193,19 +195,23 @@ static Atomic<bool> l_AllowedToWork (false);
* Do the actual work (config loading, ...)
*
* @param configs Files to read config from
* @param closeConsoleLog Whether to close the console log after config loading
* @param stderrFile Where to log errors
*
* @return Exit code
*/
static inline
int RunWorker(const std::vector<std::string>& configs)
int RunWorker(const std::vector<std::string>& configs, bool closeConsoleLog = false, const String& stderrFile = String())
{
Log(LogInformation, "cli", "Loading configuration file(s).");
{
std::vector<ConfigItem::Ptr> newItems;
if (!DaemonUtility::LoadConfigFiles(configs, newItems, Configuration::ObjectsPath, Configuration::VarsPath))
if (!DaemonUtility::LoadConfigFiles(configs, newItems, Configuration::ObjectsPath, Configuration::VarsPath)) {
Log(LogCritical, "cli", "Config validation failed. Re-run with 'icinga2 daemon -C' after fixing the config.");
return EXIT_FAILURE;
}
#ifndef _WIN32
Log(LogNotice, "cli")
@ -216,6 +222,11 @@ int RunWorker(const std::vector<std::string>& configs)
Log(LogNotice, "cli")
<< "Waiting for the umbrella process to let us doing the actual work";
if (closeConsoleLog) {
CloseStdIO(stderrFile);
Logger::DisableConsoleLog();
}
while (!l_AllowedToWork.load()) {
Utility::Sleep(0.2);
}
@ -397,10 +408,12 @@ static void NotifyWatchdog()
* Starts seemless worker process doing the actual work (config loading, ...)
*
* @param configs Files to read config from
* @param closeConsoleLog Whether to close the console log after config loading
* @param stderrFile Where to log errors
*
* @return The worker's PID on success, -1 on failure (if the worker couldn't load its config)
*/
static pid_t StartUnixWorker(const std::vector<std::string>& configs)
static pid_t StartUnixWorker(const std::vector<std::string>& configs, bool closeConsoleLog = false, const String& stderrFile = String())
{
Log(LogNotice, "cli")
<< "Spawning seemless worker process doing the actual work";
@ -461,7 +474,7 @@ static pid_t StartUnixWorker(const std::vector<std::string>& configs)
_exit(EXIT_FAILURE);
}
_exit(RunWorker(configs));
_exit(RunWorker(configs, closeConsoleLog, stderrFile));
} catch (...) {
_exit(EXIT_FAILURE);
}
@ -539,6 +552,10 @@ public:
*/
int DaemonCommand::Run(const po::variables_map& vm, const std::vector<std::string>& ap) const
{
#ifdef _WIN32
SetConsoleOutputCP(65001);
#endif /* _WIN32 */
Logger::EnableTimestamp();
Log(LogInformation, "cli")
@ -562,8 +579,10 @@ int DaemonCommand::Run(const po::variables_map& vm, const std::vector<std::strin
std::vector<ConfigItem::Ptr> newItems;
if (!DaemonUtility::LoadConfigFiles(configs, newItems, Configuration::ObjectsPath, Configuration::VarsPath))
if (!DaemonUtility::LoadConfigFiles(configs, newItems, Configuration::ObjectsPath, Configuration::VarsPath)) {
Log(LogCritical, "cli", "Config validation failed. Re-run with 'icinga2 daemon -C' after fixing the config.");
return EXIT_FAILURE;
}
Log(LogInformation, "cli", "Finished validating the configuration file(s).");
return EXIT_SUCCESS;
@ -604,7 +623,7 @@ int DaemonCommand::Run(const po::variables_map& vm, const std::vector<std::strin
});
#endif /* _WIN32 */
if (vm.count("daemonize") || vm.count("close-stdio")) {
if (vm.count("daemonize")) {
// After disabling the console log, any further errors will go to the configured log only.
// Let's try to make this clear and say good bye.
Log(LogInformation, "cli", "Closing console log.");
@ -638,13 +657,28 @@ int DaemonCommand::Run(const po::variables_map& vm, const std::vector<std::strin
(void)sigaction(SIGHUP, &sa, nullptr);
}
bool closeConsoleLog = !vm.count("daemonize") && vm.count("close-stdio");
String errorLog;
if (vm.count("errorlog"))
errorLog = vm["errorlog"].as<std::string>();
// The PID of the current seemless worker
pid_t currentWorker = StartUnixWorker(configs);
pid_t currentWorker = StartUnixWorker(configs, closeConsoleLog, errorLog);
if (currentWorker == -1) {
return EXIT_FAILURE;
}
if (closeConsoleLog) {
// After disabling the console log, any further errors will go to the configured log only.
// Let's try to make this clear and say good bye.
Log(LogInformation, "cli", "Closing console log.");
CloseStdIO(errorLog);
Logger::DisableConsoleLog();
}
// Immediately allow the first (non-reload) worker to continue working beyond config validation
(void)kill(currentWorker, SIGUSR2);

View File

@ -624,7 +624,8 @@ bool ConfigItem::CommitItems(const ActivationContext::Ptr& context, WorkQueue& u
return true;
}
bool ConfigItem::ActivateItems(WorkQueue& upq, const std::vector<ConfigItem::Ptr>& newItems, bool runtimeCreated, bool silent, bool withModAttrs)
bool ConfigItem::ActivateItems(WorkQueue& upq, const std::vector<ConfigItem::Ptr>& newItems, bool runtimeCreated,
bool silent, bool withModAttrs, const Value& cookie)
{
static boost::mutex mtx;
boost::mutex::scoped_lock lock(mtx);
@ -692,7 +693,7 @@ bool ConfigItem::ActivateItems(WorkQueue& upq, const std::vector<ConfigItem::Ptr
<< objectType->GetActivationPriority();
#endif /* I2_DEBUG */
object->Activate(runtimeCreated);
object->Activate(runtimeCreated, cookie);
}
}

View File

@ -53,7 +53,8 @@ public:
const String& name);
static bool CommitItems(const ActivationContext::Ptr& context, WorkQueue& upq, std::vector<ConfigItem::Ptr>& newItems, bool silent = false);
static bool ActivateItems(WorkQueue& upq, const std::vector<ConfigItem::Ptr>& newItems, bool runtimeCreated = false, bool silent = false, bool withModAttrs = false);
static bool ActivateItems(WorkQueue& upq, const std::vector<ConfigItem::Ptr>& newItems, bool runtimeCreated = false,
bool silent = false, bool withModAttrs = false, const Value& cookie = Empty);
static bool RunWithActivationContext(const Function::Ptr& function);

View File

@ -552,6 +552,58 @@ ExpressionResult GetScopeExpression::DoEvaluate(ScriptFrame& frame, DebugHint *d
VERIFY(!"Invalid scope.");
}
static inline
void WarnOnImplicitlySetGlobalVar(const std::unique_ptr<Expression>& setLhs, const Value& setLhsParent, CombinedSetOp setOp, const DebugInfo& debug)
{
auto var (dynamic_cast<VariableExpression*>(setLhs.get()));
if (var && setLhsParent.IsObject()) {
auto ns (dynamic_pointer_cast<Namespace>(setLhsParent.Get<Object::Ptr>()));
if (ns && ns == ScriptGlobal::GetGlobals()) {
const char *opStr = nullptr;
switch (setOp) {
case OpSetLiteral:
opStr = "=";
break;
case OpSetAdd:
opStr = "+=";
break;
case OpSetSubtract:
opStr = "-=";
break;
case OpSetMultiply:
opStr = "*=";
break;
case OpSetDivide:
opStr = "/=";
break;
case OpSetModulo:
opStr = "%=";
break;
case OpSetXor:
opStr = "^=";
break;
case OpSetBinaryAnd:
opStr = "&=";
break;
case OpSetBinaryOr:
opStr = "|=";
break;
default:
VERIFY(!"Invalid opcode.");
}
auto varName (var->GetVariable());
Log(LogWarning, "config")
<< "Global variable '" << varName << "' has been set implicitly via '" << varName << ' ' << opStr << " ...' " << debug << "."
" Please set it explicitly via 'globals." << varName << ' ' << opStr << " ...' instead.";
}
}
}
ExpressionResult SetExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
{
if (frame.Sandboxed)
@ -610,6 +662,8 @@ ExpressionResult SetExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint)
delete psdhint;
}
WarnOnImplicitlySetGlobalVar(m_Operand1, parent, m_Op, m_DebugInfo);
return Empty;
}

View File

@ -316,7 +316,7 @@ void IdoMysqlConnection::Reconnect()
Log(LogCritical, "IdoMysqlConnection")
<< "Schema version '" << version << "' does not match the required version '"
<< IDO_COMPAT_SCHEMA_VERSION << "' (or newer)! Please check the upgrade documentation at "
<< "https://docs.icinga.com/icinga2/latest/doc/module/icinga2/chapter/upgrading-icinga-2#upgrading-mysql-db";
<< "https://icinga.com/docs/icinga2/latest/doc/16-upgrading-icinga-2/#upgrading-mysql-db";
BOOST_THROW_EXCEPTION(std::runtime_error("Schema version mismatch."));
}

View File

@ -2,37 +2,86 @@
-- upgrade path for Icinga 2.11.0
--
-- -----------------------------------------
-- Copyright (c) 2018 Icinga Development Team (https://icinga.com/)
-- Copyright (c) 2019 Icinga Development Team (https://icinga.com/)
--
-- Please check https://docs.icinga.com for upgrading information!
-- -----------------------------------------
ALTER TABLE `icinga_commands` DROP INDEX `commands_i_id_idx`;
ALTER TABLE `icinga_comments` DROP INDEX `idx_comments_object_id`;
ALTER TABLE `icinga_comments` DROP INDEX `comments_i_id_idx`;
ALTER TABLE `icinga_configfiles` DROP INDEX `configfiles_i_id_idx`;
ALTER TABLE `icinga_contactgroups` DROP INDEX `contactgroups_i_id_idx`;
ALTER TABLE `icinga_contacts` DROP INDEX `contacts_i_id_idx`;
ALTER TABLE `icinga_customvariables` DROP INDEX `idx_customvariables_object_id`;
ALTER TABLE `icinga_eventhandlers` DROP INDEX `eventhandlers_i_id_idx`;
ALTER TABLE `icinga_hostdependencies` DROP INDEX `hostdependencies_i_id_idx`;
ALTER TABLE `icinga_hostescalations` DROP INDEX `hostesc_i_id_idx`;
ALTER TABLE `icinga_hostescalation_contacts` DROP INDEX `hostesc_contacts_i_id_idx`;
ALTER TABLE `icinga_hostgroups` DROP INDEX `hostgroups_i_id_idx`;
ALTER TABLE `icinga_hosts` DROP INDEX `host_object_id`;
ALTER TABLE `icinga_hosts` DROP INDEX `hosts_i_id_idx`;
ALTER TABLE `icinga_objects` DROP INDEX `objects_objtype_id_idx`;
ALTER TABLE `icinga_programstatus` DROP INDEX `programstatus_i_id_idx`;
ALTER TABLE `icinga_runtimevariables` DROP INDEX `runtimevariables_i_id_idx`;
ALTER TABLE `icinga_scheduleddowntime` DROP INDEX `scheduleddowntime_i_id_idx`;
ALTER TABLE `icinga_scheduleddowntime` DROP INDEX `idx_scheduleddowntime_object_id`;
ALTER TABLE `icinga_serviceescalations` DROP INDEX `serviceesc_i_id_idx`;
ALTER TABLE `icinga_serviceescalation_contacts` DROP INDEX `serviceesc_contacts_i_id_idx`;
ALTER TABLE `icinga_servicegroups` DROP INDEX `servicegroups_i_id_idx`;
ALTER TABLE `icinga_services` DROP INDEX `services_i_id_idx`;
ALTER TABLE `icinga_services` DROP INDEX `service_object_id`;
ALTER TABLE `icinga_systemcommands` DROP INDEX `systemcommands_i_id_idx`;
ALTER TABLE `icinga_timeperiods` DROP INDEX `timeperiods_i_id_idx`;
SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";
-- --------------------------------------------------------
-- Helper functions and procedures for DROP INDEX IF EXISTS
-- --------------------------------------------------------
DELIMITER //
DROP FUNCTION IF EXISTS ido_index_exists //
CREATE FUNCTION ido_index_exists(
f_table_name varchar(64),
f_index_name varchar(64)
)
RETURNS BOOL
DETERMINISTIC
READS SQL DATA
BEGIN
DECLARE index_exists BOOL DEFAULT FALSE;
SELECT EXISTS (
SELECT 1
FROM information_schema.statistics
WHERE table_schema = SCHEMA()
AND table_name = f_table_name
AND index_name = f_index_name
) INTO index_exists;
RETURN index_exists;
END //
DROP PROCEDURE IF EXISTS ido_drop_index_if_exists //
CREATE PROCEDURE ido_drop_index_if_exists (
IN p_table_name varchar(64),
IN p_index_name varchar(64)
)
DETERMINISTIC
MODIFIES SQL DATA
BEGIN
IF ido_index_exists(p_table_name, p_index_name)
THEN
SET @ido_drop_index_sql = CONCAT('ALTER TABLE `', SCHEMA(), '`.`', p_table_name, '` DROP INDEX `', p_index_name, '`');
PREPARE stmt FROM @ido_drop_index_sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET @ido_drop_index_sql = NULL;
END IF;
END //
DELIMITER ;
CALL ido_drop_index_if_exists('icinga_commands', 'commands_i_id_idx');
CALL ido_drop_index_if_exists('icinga_comments', 'idx_comments_object_id');
CALL ido_drop_index_if_exists('icinga_comments', 'comments_i_id_idx');
CALL ido_drop_index_if_exists('icinga_configfiles', 'configfiles_i_id_idx');
CALL ido_drop_index_if_exists('icinga_contactgroups', 'contactgroups_i_id_idx');
CALL ido_drop_index_if_exists('icinga_contacts', 'contacts_i_id_idx');
CALL ido_drop_index_if_exists('icinga_customvariables', 'idx_customvariables_object_id');
CALL ido_drop_index_if_exists('icinga_eventhandlers', 'eventhandlers_i_id_idx');
CALL ido_drop_index_if_exists('icinga_hostdependencies', 'hostdependencies_i_id_idx');
CALL ido_drop_index_if_exists('icinga_hostescalations', 'hostesc_i_id_idx');
CALL ido_drop_index_if_exists('icinga_hostescalation_contacts', 'hostesc_contacts_i_id_idx');
CALL ido_drop_index_if_exists('icinga_hostgroups', 'hostgroups_i_id_idx');
CALL ido_drop_index_if_exists('icinga_hosts', 'host_object_id');
CALL ido_drop_index_if_exists('icinga_hosts', 'hosts_i_id_idx');
CALL ido_drop_index_if_exists('icinga_objects', 'objects_objtype_id_idx');
CALL ido_drop_index_if_exists('icinga_programstatus', 'programstatus_i_id_idx');
CALL ido_drop_index_if_exists('icinga_runtimevariables', 'runtimevariables_i_id_idx');
CALL ido_drop_index_if_exists('icinga_scheduleddowntime', 'scheduleddowntime_i_id_idx');
CALL ido_drop_index_if_exists('icinga_scheduleddowntime', 'idx_scheduleddowntime_object_id');
CALL ido_drop_index_if_exists('icinga_serviceescalations', 'serviceesc_i_id_idx');
CALL ido_drop_index_if_exists('icinga_serviceescalation_contacts', 'serviceesc_contacts_i_id_idx');
CALL ido_drop_index_if_exists('icinga_servicegroups', 'servicegroups_i_id_idx');
CALL ido_drop_index_if_exists('icinga_services', 'services_i_id_idx');
CALL ido_drop_index_if_exists('icinga_services', 'service_object_id');
CALL ido_drop_index_if_exists('icinga_systemcommands', 'systemcommands_i_id_idx');
CALL ido_drop_index_if_exists('icinga_timeperiods', 'timeperiods_i_id_idx');
DROP FUNCTION ido_index_exists;
DROP PROCEDURE ido_drop_index_if_exists;
-- -----------------------------------------
-- set dbversion (same as 2.11.0)

View File

@ -288,7 +288,7 @@ void IdoPgsqlConnection::Reconnect()
Log(LogCritical, "IdoPgsqlConnection")
<< "Schema version '" << version << "' does not match the required version '"
<< IDO_COMPAT_SCHEMA_VERSION << "' (or newer)! Please check the upgrade documentation at "
<< "https://docs.icinga.com/icinga2/latest/doc/module/icinga2/chapter/upgrading-icinga-2#upgrading-postgresql-db";
<< "https://icinga.com/docs/icinga2/latest/doc/16-upgrading-icinga-2/#upgrading-postgresql-db";
BOOST_THROW_EXCEPTION(std::runtime_error("Schema version mismatch."));
}

View File

@ -337,16 +337,6 @@ Dictionary::Ptr ApiActions::ScheduleDowntime(const ConfigObject::Ptr& object,
String comment = HttpUtility::GetLastParameter(params, "comment");
double startTime = HttpUtility::GetLastParameter(params, "start_time");
double endTime = HttpUtility::GetLastParameter(params, "end_time");
double now = Utility::GetTime() - 10; //Take a request delay into account.
if (author.IsEmpty() || comment.IsEmpty())
return ApiActions::CreateResult(400, "Options 'author' and 'comment' must not be empty");
if (startTime < now || endTime < now)
return ApiActions::CreateResult(400, "Options 'start_time' and 'end_time' must be greater than current timestamp");
if (endTime < startTime)
return ApiActions::CreateResult(400, "Option 'end_time' must be greater than 'start_time'");
Host::Ptr host;
Service::Ptr service;

View File

@ -23,6 +23,8 @@ boost::signals2::signal<void (const Checkable::Ptr&, const CheckResult::Ptr&, st
boost::signals2::signal<void (const Checkable::Ptr&, NotificationType, const CheckResult::Ptr&, const String&, const String&, const MessageOrigin::Ptr&)> Checkable::OnNotificationsRequested;
boost::signals2::signal<void (const Checkable::Ptr&)> Checkable::OnNextCheckUpdated;
Atomic<uint_fast64_t> Checkable::CurrentConcurrentChecks (0);
boost::mutex Checkable::m_StatsMutex;
int Checkable::m_PendingChecks = 0;
boost::condition_variable Checkable::m_PendingChecksCV;

View File

@ -130,6 +130,9 @@ void Checkable::AcknowledgeProblem(const String& author, const String& comment,
if (notify && !IsPaused())
OnNotificationsRequested(this, NotificationAcknowledgement, GetLastCheckResult(), author, comment, nullptr);
Log(LogInformation, "Checkable")
<< "Acknowledgement set for checkable '" << GetName() << "'.";
OnAcknowledgementSet(this, author, comment, type, notify, persistent, expiry, origin);
}
@ -138,6 +141,9 @@ void Checkable::ClearAcknowledgement(const MessageOrigin::Ptr& origin)
SetAcknowledgementRaw(AcknowledgementNone);
SetAcknowledgementExpiry(0);
Log(LogInformation, "Checkable")
<< "Acknowledgement cleared for checkable '" << GetName() << "'.";
OnAcknowledgementCleared(this, origin);
}

View File

@ -3,6 +3,7 @@
#ifndef CHECKABLE_H
#define CHECKABLE_H
#include "base/atomic.hpp"
#include "base/timer.hpp"
#include "icinga/i2-icinga.hpp"
#include "icinga/checkable-ti.hpp"
@ -12,6 +13,7 @@
#include "icinga/downtime.hpp"
#include "remote/endpoint.hpp"
#include "remote/messageorigin.hpp"
#include <cstdint>
namespace icinga
{
@ -131,6 +133,8 @@ public:
static boost::signals2::signal<void (const Checkable::Ptr&)> OnNextCheckUpdated;
static boost::signals2::signal<void (const Checkable::Ptr&)> OnEventCommandExecuted;
static Atomic<uint_fast64_t> CurrentConcurrentChecks;
/* Downtimes */
int GetDowntimeDepth() const final;

View File

@ -4,6 +4,7 @@
#include "icinga/host.hpp"
#include "icinga/service.hpp"
#include "icinga/clusterevents.hpp"
#include "base/application.hpp"
#include "base/objectlock.hpp"
#include "base/utility.hpp"
#include "base/perfdatavalue.hpp"
@ -186,8 +187,6 @@ ServiceStatistics CIB::CalculateServiceStats()
for (const Service::Ptr& service : ConfigType::GetObjectsByType<Service>()) {
ObjectLock olock(service);
CheckResult::Ptr cr = service->GetLastCheckResult();
if (service->GetState() == ServiceOK)
ss.services_ok++;
if (service->GetState() == ServiceWarning)
@ -197,8 +196,11 @@ ServiceStatistics CIB::CalculateServiceStats()
if (service->GetState() == ServiceUnknown)
ss.services_unknown++;
CheckResult::Ptr cr = service->GetLastCheckResult();
if (!cr)
ss.services_pending++;
if (!service->IsReachable())
ss.services_unreachable++;
@ -208,6 +210,11 @@ ServiceStatistics CIB::CalculateServiceStats()
ss.services_in_downtime++;
if (service->IsAcknowledged())
ss.services_acknowledged++;
if (service->GetHandled())
ss.services_handled++;
if (service->GetProblem())
ss.services_problem++;
}
return ss;
@ -237,6 +244,11 @@ HostStatistics CIB::CalculateHostStats()
hs.hosts_in_downtime++;
if (host->IsAcknowledged())
hs.hosts_acknowledged++;
if (host->GetHandled())
hs.hosts_handled++;
if (host->GetProblem())
hs.hosts_problem++;
}
return hs;
@ -289,7 +301,10 @@ void CIB::StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata) {
status->Set("active_service_checks_15min", GetActiveServiceChecksStatistics(60 * 15));
status->Set("passive_service_checks_15min", GetPassiveServiceChecksStatistics(60 * 15));
// Checker related stats
status->Set("remote_check_queue", ClusterEvents::GetCheckRequestQueueSize());
status->Set("current_pending_callbacks", Application::GetTP().GetPending());
status->Set("current_concurrent_checks", Checkable::CurrentConcurrentChecks.load());
CheckableCheckStatistics scs = CalculateServiceCheckStats();
@ -311,6 +326,8 @@ void CIB::StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata) {
status->Set("num_services_flapping", ss.services_flapping);
status->Set("num_services_in_downtime", ss.services_in_downtime);
status->Set("num_services_acknowledged", ss.services_acknowledged);
status->Set("num_services_handled", ss.services_handled);
status->Set("num_services_problem", ss.services_problem);
double uptime = Utility::GetTime() - Application::GetStartTime();
status->Set("uptime", uptime);
@ -324,4 +341,6 @@ void CIB::StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata) {
status->Set("num_hosts_flapping", hs.hosts_flapping);
status->Set("num_hosts_in_downtime", hs.hosts_in_downtime);
status->Set("num_hosts_acknowledged", hs.hosts_acknowledged);
status->Set("num_hosts_handled", hs.hosts_handled);
status->Set("num_hosts_problem", hs.hosts_problem);
}

View File

@ -30,6 +30,8 @@ struct ServiceStatistics {
double services_flapping;
double services_in_downtime;
double services_acknowledged;
double services_handled;
double services_problem;
};
struct HostStatistics {
@ -40,6 +42,8 @@ struct HostStatistics {
double hosts_flapping;
double hosts_in_downtime;
double hosts_acknowledged;
double hosts_handled;
double hosts_problem;
};
/**

View File

@ -298,10 +298,11 @@ String Downtime::AddDowntime(const Checkable::Ptr& checkable, const String& auth
if (!downtime)
BOOST_THROW_EXCEPTION(std::runtime_error("Could not create downtime object."));
Log(LogNotice, "Downtime")
Log(LogInformation, "Downtime")
<< "Added downtime '" << downtime->GetName()
<< "' between '" << Utility::FormatDateTime("%Y-%m-%d %H:%M:%S", startTime)
<< "' and '" << Utility::FormatDateTime("%Y-%m-%d %H:%M:%S", endTime) << "'.";
<< "' and '" << Utility::FormatDateTime("%Y-%m-%d %H:%M:%S", endTime) << "', author: '"
<< author << "', " << (fixed ? "fixed" : "flexible with " + Convert::ToString(duration) + "s duration");
return fullName;
}
@ -323,9 +324,6 @@ void Downtime::RemoveDowntime(const String& id, bool cancelled, bool expired, co
downtime->SetWasCancelled(cancelled);
Log(LogNotice, "Downtime")
<< "Removed downtime '" << downtime->GetName() << "' from object '" << downtime->GetCheckable()->GetName() << "'.";
Array::Ptr errors = new Array();
if (!ConfigObjectUtility::DeleteObject(downtime, false, errors, nullptr)) {
@ -336,6 +334,21 @@ void Downtime::RemoveDowntime(const String& id, bool cancelled, bool expired, co
BOOST_THROW_EXCEPTION(std::runtime_error("Could not remove downtime."));
}
String reason;
if (expired) {
reason = "expired at " + Utility::FormatDateTime("%Y-%m-%d %H:%M:%S %z", downtime->GetEndTime());
} else if (cancelled) {
reason = "cancelled by user";
} else {
reason = "<unknown>";
}
Log(LogInformation, "Downtime")
<< "Removed downtime '" << downtime->GetName() << "' from checkable '"
<< downtime->GetCheckable()->GetName() << "' (Reason: " << reason << ").";
}
bool Downtime::CanBeTriggered()
@ -359,8 +372,10 @@ void Downtime::TriggerDowntime()
if (!CanBeTriggered())
return;
Log(LogNotice, "Downtime")
<< "Triggering downtime '" << GetName() << "'.";
Checkable::Ptr checkable = GetCheckable();
Log(LogInformation, "Downtime")
<< "Triggering downtime '" << GetName() << "' for checkable '" << checkable->GetName() << "'.";
if (GetTriggerTime() == 0)
SetTriggerTime(Utility::GetTime());

View File

@ -247,6 +247,12 @@ bool IcingaApplication::ResolveMacro(const String& macro, const CheckResult::Ptr
} else if (macro == "num_services_acknowledged") {
*result = ss.services_acknowledged;
return true;
} else if (macro == "num_services_handled") {
*result = ss.services_handled;
return true;
} else if (macro == "num_services_problem") {
*result = ss.services_problem;
return true;
}
}
else if (macro.Contains("num_hosts")) {
@ -273,6 +279,12 @@ bool IcingaApplication::ResolveMacro(const String& macro, const CheckResult::Ptr
} else if (macro == "num_hosts_acknowledged") {
*result = hs.hosts_acknowledged;
return true;
} else if (macro == "num_hosts_handled") {
*result = hs.hosts_handled;
return true;
} else if (macro == "num_hosts_problem") {
*result = hs.hosts_problem;
return true;
}
}

View File

@ -771,7 +771,7 @@ Value HostsTable::CheckIntervalAccessor(const Value& row)
if (!host)
return Empty;
return host->GetCheckInterval() / 60.0;
return host->GetCheckInterval() / LIVESTATUS_INTERVAL_LENGTH;
}
Value HostsTable::RetryIntervalAccessor(const Value& row)
@ -781,7 +781,7 @@ Value HostsTable::RetryIntervalAccessor(const Value& row)
if (!host)
return Empty;
return host->GetRetryInterval() / 60.0;
return host->GetRetryInterval() / LIVESTATUS_INTERVAL_LENGTH;
}
Value HostsTable::NotificationIntervalAccessor(const Value& row)

View File

@ -792,7 +792,7 @@ Value ServicesTable::CheckIntervalAccessor(const Value& row)
if (!service)
return Empty;
return service->GetCheckInterval() / 60.0;
return service->GetCheckInterval() / LIVESTATUS_INTERVAL_LENGTH;
}
Value ServicesTable::RetryIntervalAccessor(const Value& row)
@ -802,7 +802,7 @@ Value ServicesTable::RetryIntervalAccessor(const Value& row)
if (!service)
return Empty;
return service->GetRetryInterval() / 60.0;
return service->GetRetryInterval() / LIVESTATUS_INTERVAL_LENGTH;
}
Value ServicesTable::NotificationIntervalAccessor(const Value& row)

View File

@ -67,7 +67,7 @@ void StatusTable::AddColumns(Table *table, const String& prefix,
table->AddColumn(prefix + "program_start", Column(&StatusTable::ProgramStartAccessor, objectAccessor));
table->AddColumn(prefix + "last_command_check", Column(&Table::ZeroAccessor, objectAccessor));
table->AddColumn(prefix + "last_log_rotation", Column(&Table::ZeroAccessor, objectAccessor));
table->AddColumn(prefix + "interval_length", Column(&Table::ZeroAccessor, objectAccessor));
table->AddColumn(prefix + "interval_length", Column(&StatusTable::IntervalLengthAccessor, objectAccessor));
table->AddColumn(prefix + "num_hosts", Column(&StatusTable::NumHostsAccessor, objectAccessor));
table->AddColumn(prefix + "num_services", Column(&StatusTable::NumServicesAccessor, objectAccessor));
table->AddColumn(prefix + "program_version", Column(&StatusTable::ProgramVersionAccessor, objectAccessor));
@ -187,6 +187,11 @@ Value StatusTable::ProgramStartAccessor(const Value&)
return static_cast<long>(Application::GetStartTime());
}
Value StatusTable::IntervalLengthAccessor(const Value&)
{
return LIVESTATUS_INTERVAL_LENGTH;
}
Value StatusTable::NumHostsAccessor(const Value&)
{
return ConfigType::Get<Host>()->GetObjectCount();

View File

@ -45,6 +45,7 @@ protected:
static Value EnableFlapDetectionAccessor(const Value& row);
static Value ProcessPerformanceDataAccessor(const Value& row);
static Value ProgramStartAccessor(const Value& row);
static Value IntervalLengthAccessor(const Value& row);
static Value NumHostsAccessor(const Value& row);
static Value NumServicesAccessor(const Value& row);
static Value ProgramVersionAccessor(const Value& row);

View File

@ -12,6 +12,9 @@
namespace icinga
{
// Well, don't ask.
#define LIVESTATUS_INTERVAL_LENGTH 60.0
struct LivestatusRowValue {
Value Row;
LivestatusGroupByType GroupByType;

View File

@ -75,7 +75,8 @@ void IcingaCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckRes
perfdata->Add(new PerfdataValue("active_service_checks_15min", CIB::GetActiveServiceChecksStatistics(60 * 15)));
perfdata->Add(new PerfdataValue("passive_service_checks_15min", CIB::GetPassiveServiceChecksStatistics(60 * 15)));
perfdata->Add(new PerfdataValue("current_concurrent_checks", Checkable::GetPendingChecks()));
perfdata->Add(new PerfdataValue("current_pending_callbacks", Application::GetTP().GetPending()));
perfdata->Add(new PerfdataValue("current_concurrent_checks", Checkable::CurrentConcurrentChecks.load()));
perfdata->Add(new PerfdataValue("remote_check_queue", ClusterEvents::GetCheckRequestQueueSize()));
CheckableCheckStatistics scs = CIB::CalculateServiceCheckStats();
@ -98,6 +99,8 @@ void IcingaCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckRes
perfdata->Add(new PerfdataValue("num_services_flapping", ss.services_flapping));
perfdata->Add(new PerfdataValue("num_services_in_downtime", ss.services_in_downtime));
perfdata->Add(new PerfdataValue("num_services_acknowledged", ss.services_acknowledged));
perfdata->Add(new PerfdataValue("num_services_handled", ss.services_handled));
perfdata->Add(new PerfdataValue("num_services_problem", ss.services_problem));
double uptime = Utility::GetTime() - Application::GetStartTime();
perfdata->Add(new PerfdataValue("uptime", uptime));
@ -111,6 +114,8 @@ void IcingaCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckRes
perfdata->Add(new PerfdataValue("num_hosts_flapping", hs.hosts_flapping));
perfdata->Add(new PerfdataValue("num_hosts_in_downtime", hs.hosts_in_downtime));
perfdata->Add(new PerfdataValue("num_hosts_acknowledged", hs.hosts_acknowledged));
perfdata->Add(new PerfdataValue("num_hosts_handled", hs.hosts_handled));
perfdata->Add(new PerfdataValue("num_hosts_problem", hs.hosts_problem));
std::vector<Endpoint::Ptr> endpoints = ConfigType::GetObjectsByType<Endpoint>();
@ -172,11 +177,7 @@ void IcingaCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckRes
}
}
/* Extract the version number of the running Icinga2 instance.
* We assume that appVersion will allways be something like 'v2.10.1-8-gaebe6da' and we want to extract '2.10.1'.
*/
int endOfVersionNumber = appVersion.FindFirstOf("-") - 1;
String parsedAppVersion = appVersion.SubStr(1, endOfVersionNumber);
String parsedAppVersion = Utility::ParseVersion(appVersion);
/* Return an error if the version is less than specified (optional). */
if (missingIcingaMinVersion.IsEmpty() && !icingaMinVersion.IsEmpty() && Utility::CompareVersion(icingaMinVersion, parsedAppVersion) < 0) {

View File

@ -44,12 +44,15 @@ void PluginCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckRes
resolvers, resolvedMacros, useResolvedMacros, timeout,
std::bind(&PluginCheckTask::ProcessFinishedHandler, checkable, cr, _1, _2));
if (!resolvedMacros || useResolvedMacros)
if (!resolvedMacros || useResolvedMacros) {
Checkable::CurrentConcurrentChecks.fetch_add(1);
Checkable::IncreasePendingChecks();
}
}
void PluginCheckTask::ProcessFinishedHandler(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, const Value& commandLine, const ProcessResult& pr)
{
Checkable::CurrentConcurrentChecks.fetch_sub(1);
Checkable::DecreasePendingChecks();
if (pr.ExitStatus > 3) {

View File

@ -598,9 +598,9 @@ OptionalTlsStream ElasticsearchWriter::Connect()
throw;
}
stream.first = std::make_shared<AsioTlsStream>(IoEngine::Get().GetIoService(), *sslContext, GetHost());
stream.first = std::make_shared<AsioTlsStream>(IoEngine::Get().GetIoContext(), *sslContext, GetHost());
} else {
stream.second = std::make_shared<AsioTcpStream>(IoEngine::Get().GetIoService());
stream.second = std::make_shared<AsioTcpStream>(IoEngine::Get().GetIoContext());
}
try {

View File

@ -173,9 +173,9 @@ void GelfWriter::ReconnectInternal()
throw;
}
m_Stream.first = std::make_shared<AsioTlsStream>(IoEngine::Get().GetIoService(), *sslContext, GetHost());
m_Stream.first = std::make_shared<AsioTlsStream>(IoEngine::Get().GetIoContext(), *sslContext, GetHost());
} else {
m_Stream.second = std::make_shared<AsioTcpStream>(IoEngine::Get().GetIoService());
m_Stream.second = std::make_shared<AsioTcpStream>(IoEngine::Get().GetIoContext());
}
try {

View File

@ -187,7 +187,7 @@ void GraphiteWriter::ReconnectInternal()
Log(LogNotice, "GraphiteWriter")
<< "Reconnecting to Graphite on host '" << GetHost() << "' port '" << GetPort() << "'.";
m_Stream = std::make_shared<AsioTcpStream>(IoEngine::Get().GetIoService());
m_Stream = std::make_shared<AsioTcpStream>(IoEngine::Get().GetIoContext());
try {
icinga::Connect(m_Stream->lowest_layer(), GetHost(), GetPort());

View File

@ -187,9 +187,9 @@ OptionalTlsStream InfluxdbWriter::Connect()
throw;
}
stream.first = std::make_shared<AsioTlsStream>(IoEngine::Get().GetIoService(), *sslContext, GetHost());
stream.first = std::make_shared<AsioTlsStream>(IoEngine::Get().GetIoContext(), *sslContext, GetHost());
} else {
stream.second = std::make_shared<AsioTcpStream>(IoEngine::Get().GetIoService());
stream.second = std::make_shared<AsioTcpStream>(IoEngine::Get().GetIoContext());
}
try {
@ -248,21 +248,26 @@ void InfluxdbWriter::CheckResultHandlerWQ(const Checkable::Ptr& checkable, const
// Clone the template and perform an in-place macro expansion of measurement and tag values
Dictionary::Ptr tmpl_clean = service ? GetServiceTemplate() : GetHostTemplate();
Dictionary::Ptr tmpl = static_pointer_cast<Dictionary>(tmpl_clean->Clone());
Dictionary::Ptr tmpl = static_pointer_cast<Dictionary>(tmpl_clean->ShallowClone());
tmpl->Set("measurement", MacroProcessor::ResolveMacros(tmpl->Get("measurement"), resolvers, cr));
Dictionary::Ptr tags = tmpl->Get("tags");
if (tags) {
ObjectLock olock(tags);
for (const Dictionary::Pair& pair : tags) {
String missing_macro;
Value value = MacroProcessor::ResolveMacros(pair.second, resolvers, cr, &missing_macro);
Dictionary::Ptr tagsClean = tmpl->Get("tags");
if (tagsClean) {
Dictionary::Ptr tags = new Dictionary();
if (!missing_macro.IsEmpty())
continue;
{
ObjectLock olock(tagsClean);
for (const Dictionary::Pair& pair : tagsClean) {
String missing_macro;
Value value = MacroProcessor::ResolveMacros(pair.second, resolvers, cr, &missing_macro);
tags->Set(pair.first, value);
if (missing_macro.IsEmpty()) {
tags->Set(pair.first, value);
}
}
}
tmpl->Set("tags", tags);
}
CheckCommand::Ptr checkCommand = checkable->GetCheckCommand();

View File

@ -121,7 +121,7 @@ void OpenTsdbWriter::ReconnectTimerHandler()
* http://opentsdb.net/docs/build/html/user_guide/writing/index.html#telnet
*/
m_Stream = std::make_shared<AsioTcpStream>(IoEngine::Get().GetIoService());
m_Stream = std::make_shared<AsioTcpStream>(IoEngine::Get().GetIoContext());
try {
icinga::Connect(m_Stream->lowest_layer(), GetHost(), GetPort());
@ -338,4 +338,4 @@ String OpenTsdbWriter::EscapeMetric(const String& str)
boost::replace_all(result, ":", "_");
return result;
}
}

Some files were not shown because too many files have changed in this diff Show More