development, package builds and tests.
* [Debug Icinga 2](21-development.md#development-debug)
+ * [GDB Backtrace](21-development.md#development-debug-gdb-backtrace)
+ * [Core Dump](21-development.md#development-debug-core-dump)
* [Develop Icinga 2](21-development.md#development-develop)
- * [Linux Dev Environment](21-development.md#development-linux-dev-env)
- * [macOS Dev Environment](21-development.md#development-macos-dev-env)
- * [Windows Dev Environment](21-development.md#development-windows-dev-env)
+ * [Linux Dev Environment](21-development.md#development-linux-dev-env)
+ * [macOS Dev Environment](21-development.md#development-macos-dev-env)
+ * [Windows Dev Environment](21-development.md#development-windows-dev-env)
* [Package Builds](21-development.md#development-package-builds)
+ * [RPM](21-development.md#development-package-builds-rpms)
+ * [DEB](21-development.md#development-package-builds-deb)
+ * [Windows](21-development.md#development-package-builds-windows)
* [Advanced Tips](21-development.md#development-advanced)
* [Tests](21-development.md#development-tests)
for developers working with different debuggers.
> **Note:**
+>
> This is intentionally mentioned before any development insights
> as debugging is a more frequent and commonly asked question.
installed separately for all involved binaries, like `icinga2-bin`
or `icinga2-ido-mysql`.
-Debian/Ubuntu:
-
-```
-apt-get install icinga2-dbg
-```
-
-RHEL/CentOS:
-
-```
-yum install icinga2-debuginfo
-```
-
-Fedora:
-
-```
-dnf install icinga2-debuginfo icinga2-bin-debuginfo icinga2-ido-mysql-debuginfo
-```
-
-SLES/openSUSE:
-
-```
-zypper install icinga2-bin-debuginfo icinga2-ido-mysql-debuginfo
-```
+Distribution | Command
+-------------------|------------------------------------------
+Debian/Ubuntu | `apt-get install icinga2-dbg`
+RHEL/CentOS | `yum install icinga2-debuginfo`
+Fedora | `dnf install icinga2-debuginfo icinga2-bin-debuginfo icinga2-ido-mysql-debuginfo`
+SLES/openSUSE | `zypper install icinga2-bin-debuginfo icinga2-ido-mysql-debuginfo`
Furthermore, you may also have to install debug symbols for Boost and your C++ library.
Install GDB in your development environment.
-Debian/Ubuntu:
-
-```
-apt-get install gdb
-```
-
-RHEL/CentOS/Fedora:
-
-```
-yum install gdb
-```
-
-SLES/openSUSE:
-
-```
-zypper install gdb
-```
+Distribution | Command
+-------------------|------------------------------------------
+Debian/Ubuntu | `apt-get install gdb`
+RHEL/CentOS | `yum install gdb`
+Fedora | `dnf install gdb`
+SLES/openSUSE | `zypper install gdb`
#### GDB Run <a id="development-debug-gdb-run"></a>
#### GDB Backtrace <a id="development-debug-gdb-backtrace"></a>
If Icinga 2 aborted its operation abnormally, generate a backtrace.
+
+> **Note**
+>
+> Please install the [required debug symbols](21-development.md#debug-requirements)
+> prior to generating a backtrace.
+
`thread apply all` is important here since this includes all running threads.
We need this information when e.g. debugging dead locks and hanging features.
If Icinga 2 is still running, generate a full backtrace from the running
process and store it into a new file (e.g. for debugging dead locks).
+> **Note**
+>
+> Please install the [required debug symbols](21-development.md#debug-requirements)
+> prior to generating a backtrace.
+
Icinga 2 runs with 2 processes: main and command executor, therefore generate two backtrace logs
and add them to the GitHub issue.
Breakpoint Example:
- (gdb) b __cxa_throw
- (gdb) r
- (gdb) up
- ....
- (gdb) up
- #11 0x00007ffff7cbf9ff in icinga::Utility::GlobRecursive(icinga::String const&, icinga::String const&, boost::function<void (icinga::String const&)> const&, int) (path=..., pattern=..., callback=..., type=1)
- at /home/michi/coding/icinga/icinga2/lib/base/utility.cpp:609
- 609 callback(cpath);
- (gdb) l
- 604
- 605 #endif /* _WIN32 */
- 606
- 607 std::sort(files.begin(), files.end());
- 608 BOOST_FOREACH(const String& cpath, files) {
- 609 callback(cpath);
- 610 }
- 611
- 612 std::sort(dirs.begin(), dirs.end());
- 613 BOOST_FOREACH(const String& cpath, dirs) {
- (gdb) p files
- $3 = std::vector of length 11, capacity 16 = {{static NPos = 18446744073709551615, m_Data = "/etc/icinga2/conf.d/agent.conf"}, {static NPos = 18446744073709551615,
- m_Data = "/etc/icinga2/conf.d/commands.conf"}, {static NPos = 18446744073709551615, m_Data = "/etc/icinga2/conf.d/downtimes.conf"}, {static NPos = 18446744073709551615,
- m_Data = "/etc/icinga2/conf.d/groups.conf"}, {static NPos = 18446744073709551615, m_Data = "/etc/icinga2/conf.d/notifications.conf"}, {static NPos = 18446744073709551615,
- m_Data = "/etc/icinga2/conf.d/satellite.conf"}, {static NPos = 18446744073709551615, m_Data = "/etc/icinga2/conf.d/services.conf"}, {static NPos = 18446744073709551615,
- m_Data = "/etc/icinga2/conf.d/templates.conf"}, {static NPos = 18446744073709551615, m_Data = "/etc/icinga2/conf.d/test.conf"}, {static NPos = 18446744073709551615,
- m_Data = "/etc/icinga2/conf.d/timeperiods.conf"}, {static NPos = 18446744073709551615, m_Data = "/etc/icinga2/conf.d/users.conf"}}
+```
+(gdb) b __cxa_throw
+(gdb) r
+(gdb) up
+....
+(gdb) up
+#11 0x00007ffff7cbf9ff in icinga::Utility::GlobRecursive(icinga::String const&, icinga::String const&, boost::function<void (icinga::String const&)> const&, int) (path=..., pattern=..., callback=..., type=1)
+ at /home/michi/coding/icinga/icinga2/lib/base/utility.cpp:609
+609 callback(cpath);
+(gdb) l
+604
+605 #endif /* _WIN32 */
+606
+607 std::sort(files.begin(), files.end());
+608 BOOST_FOREACH(const String& cpath, files) {
+609 callback(cpath);
+610 }
+611
+612 std::sort(dirs.begin(), dirs.end());
+613 BOOST_FOREACH(const String& cpath, dirs) {
+(gdb) p files
+$3 = std::vector of length 11, capacity 16 = {{static NPos = 18446744073709551615, m_Data = "/etc/icinga2/conf.d/agent.conf"}, {static NPos = 18446744073709551615,
+ m_Data = "/etc/icinga2/conf.d/commands.conf"}, {static NPos = 18446744073709551615, m_Data = "/etc/icinga2/conf.d/downtimes.conf"}, {static NPos = 18446744073709551615,
+ m_Data = "/etc/icinga2/conf.d/groups.conf"}, {static NPos = 18446744073709551615, m_Data = "/etc/icinga2/conf.d/notifications.conf"}, {static NPos = 18446744073709551615,
+ m_Data = "/etc/icinga2/conf.d/satellite.conf"}, {static NPos = 18446744073709551615, m_Data = "/etc/icinga2/conf.d/services.conf"}, {static NPos = 18446744073709551615,
+ m_Data = "/etc/icinga2/conf.d/templates.conf"}, {static NPos = 18446744073709551615, m_Data = "/etc/icinga2/conf.d/test.conf"}, {static NPos = 18446744073709551615,
+ m_Data = "/etc/icinga2/conf.d/timeperiods.conf"}, {static NPos = 18446744073709551615, m_Data = "/etc/icinga2/conf.d/users.conf"}}
+```
### Core Dump <a id="development-debug-core-dump"></a>
This requires setting the core dump file size to `unlimited`.
-Example for Systemd:
+
+##### Systemd
```
-vim /usr/lib/systemd/system/icinga2.service
+systemctl edit icinga2.service
[Service]
...
systemctl restart icinga2
```
-Example for init script:
+##### Init Script
```
vim /etc/init.d/icinga2
service icinga2 restart
```
+##### Verify
+
Verify that the Icinga 2 process core file size limit is set to `unlimited`.
```
-cat /proc/`pidof icinga2`/limits
+for pid in $(pidof icinga2); do cat /proc/$pid/limits; done
+
...
Max core file size unlimited unlimited bytes
```
to explicitly enable core dumps for SUID on Linux.
```
-sysctl -w fs.suid_dumpable=1
+sysctl -w fs.suid_dumpable=2
```
Adjust the coredump kernel format and file location on Linux:
gdb --args /usr/local/icinga2/lib/icinga2/sbin/icinga2 daemon
```
-##### Debian 9 <a id="development-linux-dev-env-debian"></a>
+#### Debian 9 <a id="development-linux-dev-env-debian"></a>
```
-apt-get -y install gdb vim git cmake make ccache build-essential libssl-dev libboost-all-dev bison flex default-libmysqlclient-dev libpq-dev libyajl-dev libedit-dev monitoring-plugins
+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
ln -s /usr/bin/ccache /usr/local/bin/gcc
ln -s /usr/bin/ccache /usr/local/bin/g++
OpenSSL 1.0.x doesn't build anymore, so we're explicitly using 1.1.x here.
```
-brew install ccache boost cmake bison flex yajl openssl@1.1 mysql-connector-c++ postgresql libpq
+brew install ccache boost cmake bison flex openssl@1.1 mysql-connector-c++ postgresql libpq
```
##### ccache
After a while, Visual Studio will be ready.
+#### .NET Framework 3.5
+
+Windows 10 only have .NET Framework >= 4.6 installed by default, the Icinga Agent Wizard is built on .NET Framework 2.0 which is not included in .NET Framework 4.6. Thankfully Windows 10 have .NET Framework 3.5 (which includes .NET Framework 2.0) as a component on board, you just need to activate it.
+
+Go to `Control Panel` -> `Programs` -> `Turn Windows features on or off`. Tick `.NET Framework 3.5 (includes .NET 2.0 and 3.0)` and wait until the installation process succseded.
+
#### Flex and Bison
Install it using [chocolatey](https://www.wireshark.org/docs/wsdg_html_chunked/ChSetupWin32.html):
Variable | Value | Description
----------------------|----------------------------------------------------------------------|-------------------------------------------------------
-BOOST_ROOT | `C:\boost_1_65_1` | Root path where you've extracted and compiled Boost.
-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.
-ICINGA2_WITH_PGSQL | OFF | Requires extra setup for PgSQL if set to `ON`. Not supported for client setups.
-ICINGA2_UNITY_BUILD | OFF | Disable unity builds for development environments.
+`BOOST_ROOT` | `C:\boost_1_65_1` | Root path where you've extracted and compiled Boost.
+`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.
+`ICINGA2_WITH_PGSQL` | OFF | Requires extra setup for PgSQL if set to `ON`. Not supported for client setups.
+`ICINGA2_UNITY_BUILD` | OFF | Disable unity builds for development environments.
Tip: If you have previously opened a terminal, run `refreshenv` to re-read updated PATH variables.
- SUSE: libopenssl-devel (for SLES 11: libopenssl1-devel)
- Debian/Ubuntu: libssl-dev
- Alpine: libressl-dev
-* Boost library and header files >= 1.48.0
- - RHEL/Fedora: boost148-devel
+* Boost library and header files >= 1.66.0
+ - RHEL/Fedora: boost166-devel
- Debian/Ubuntu: libboost-all-dev
- Alpine: boost-dev
* GNU bison (bison)
* GNU flex (flex) >= 2.5.35
-* Systemd headers
- - Only required when using Systemd
+* systemd headers
+ - Only required when using systemd
- Debian/Ubuntu: libsystemd-dev
- RHEL/Fedora: systemd-devel
- RHEL/Fedora: postgresql-devel
- Debian/Ubuntu: libpq-dev
- postgresql-dev on Alpine
-* YAJL (Faster JSON library)
- - RHEL/Fedora: yajl-devel
- - Debian: libyajl-dev
- - Alpine: yajl-dev
* libedit (CLI console)
- RHEL/Fedora: libedit-devel on CentOS (RHEL requires rhel-7-server-optional-rpms)
- Debian/Ubuntu/Alpine: libedit-dev
**FreeBSD**: libexecinfo (automatically used when Icinga 2 is installed via port or package)
-**RHEL6**: Requires a newer boost version which is available on packages.icinga.com
+**RHEL6** and **SLES11**: Requires a newer boost version which is available on packages.icinga.com
with a version suffixed name.
### Runtime user environment <a id="development-package-builds-runtime-user-env"></a>
into your source tree and run the following command:
```
-$ dpkg-buildpackage -uc -us
+dpkg-buildpackage -uc -us
```
### Build Alpine Linux packages <a id="development-package-builds-alpine"></a>
Icinga 2 can be started as a daemon using the provided init script:
```
-# /etc/init.d/icinga2
+/etc/init.d/icinga2
Usage: /etc/init.d/icinga2 {start|stop|restart|reload|checkconfig|status}
```
-### Systemd <a id="development-package-builds-systemd"></a>
+#### Systemd <a id="development-package-builds-systemd"></a>
-If your distribution uses Systemd:
+If your distribution uses systemd:
```
-# systemctl {start|stop|reload|status|enable|disable} icinga2
+systemctl {start|stop|reload|status|enable|disable} icinga2
```
-In case the distribution is running Systemd >227, you'll also
+In case the distribution is running systemd >227, you'll also
need to package and install the `etc/initsystem/icinga2.service.limits.conf`
file into `/etc/systemd/system/icinga2.service.d`.
-### openrc <a id="development-package-builds-openrc"></a>
+#### openrc <a id="development-package-builds-openrc"></a>
Or if your distribution uses openrc (like Alpine):
```
-# rc-service icinga2
+rc-service icinga2
Usage: /etc/init.d/icinga2 {start|stop|restart|reload|checkconfig|status}
- ```
+```
Note: the openrc's init.d is not shipped by default.
A working init.d with openrc can be found here: (https://git.alpinelinux.org/cgit/aports/plain/community/icinga2/icinga2.initd). If you have customized some path, edit the file and adjust it according with your setup.
Those few steps can be followed:
```
-# wget https://git.alpinelinux.org/cgit/aports/plain/community/icinga2/icinga2.initd
-# mv icinga2.initd /etc/init.d/icinga2
-# chmod +x /etc/init.d/icinga2
+wget https://git.alpinelinux.org/cgit/aports/plain/community/icinga2/icinga2.initd
+mv icinga2.initd /etc/init.d/icinga2
+chmod +x /etc/init.d/icinga2
```
Icinga 2 reads a single configuration file which is used to specify all
Install the `boost`, `python` and `icinga2` pretty printers. Absolute paths are required,
so please make sure to update the installation paths accordingly (`pwd`).
- $ mkdir -p ~/.gdb_printers && cd ~/.gdb_printers
+```
+$ mkdir -p ~/.gdb_printers && cd ~/.gdb_printers
+```
Boost Pretty Printers compatible with Python 3:
- $ git clone https://github.com/mateidavid/Boost-Pretty-Printer.git && cd Boost-Pretty-Printer
- $ git checkout python-3
- $ pwd
- /home/michi/.gdb_printers/Boost-Pretty-Printer
+```
+$ git clone https://github.com/mateidavid/Boost-Pretty-Printer.git && cd Boost-Pretty-Printer
+$ git checkout python-3
+$ pwd
+/home/michi/.gdb_printers/Boost-Pretty-Printer
+```
Python Pretty Printers:
- $ cd ~/.gdb_printers
- $ svn co svn://gcc.gnu.org/svn/gcc/trunk/libstdc++-v3/python
+```
+$ cd ~/.gdb_printers
+$ svn co svn://gcc.gnu.org/svn/gcc/trunk/libstdc++-v3/python
+```
Icinga 2 Pretty Printers:
- $ mkdir -p ~/.gdb_printers/icinga2 && cd ~/.gdb_printers/icinga2
- $ wget https://raw.githubusercontent.com/Icinga/icinga2/master/tools/debug/gdb/icingadbg.py
+```
+$ mkdir -p ~/.gdb_printers/icinga2 && cd ~/.gdb_printers/icinga2
+$ wget https://raw.githubusercontent.com/Icinga/icinga2/master/tools/debug/gdb/icingadbg.py
+```
Now you'll need to modify/setup your `~/.gdbinit` configuration file.
You can download the one from Icinga 2 and modify all paths.
Example on Fedora 22:
- $ wget https://raw.githubusercontent.com/Icinga/icinga2/master/tools/debug/gdb/gdbinit -O ~/.gdbinit
- $ vim ~/.gdbinit
-
- set print pretty on
-
- python
- import sys
- sys.path.insert(0, '/home/michi/.gdb_printers/icinga2')
- from icingadbg import register_icinga_printers
- register_icinga_printers()
- end
-
- python
- import sys
- sys.path.insert(0, '/home/michi/.gdb_printers/python')
- from libstdcxx.v6.printers import register_libstdcxx_printers
- try:
- register_libstdcxx_printers(None)
- except:
- pass
- end
-
- python
- import sys
- sys.path.insert(0, '/home/michi/.gdb_printers/Boost-Pretty-Printer')
- import boost_print
- boost_print.register_printers()
- end
+```
+$ wget https://raw.githubusercontent.com/Icinga/icinga2/master/tools/debug/gdb/gdbinit -O ~/.gdbinit
+$ vim ~/.gdbinit
+set print pretty on
+
+python
+import sys
+sys.path.insert(0, '/home/michi/.gdb_printers/icinga2')
+from icingadbg import register_icinga_printers
+register_icinga_printers()
+end
+
+python
+import sys
+sys.path.insert(0, '/home/michi/.gdb_printers/python')
+from libstdcxx.v6.printers import register_libstdcxx_printers
+try:
+ register_libstdcxx_printers(None)
+except:
+ pass
+end
+
+python
+import sys
+sys.path.insert(0, '/home/michi/.gdb_printers/Boost-Pretty-Printer')
+import boost_print
+boost_print.register_printers()
+end
+```
If you are getting the following error when running gdb, the `libstdcxx`
printers are already preloaded in your environment and you can remove
the duplicate import in your `~/.gdbinit` file.
- RuntimeError: pretty-printer already registered: libstdc++-v6
-
+```
+RuntimeError: pretty-printer already registered: libstdc++-v6
+```
## Development Tests <a id="development-tests"></a>