icinga1_objects_upgrader

Icinga1 configuration objects upgrader

This tool permits the conversion of Icinga1 configuration objects to a format compatible with Icinga2.

There is no one-to-one conversion method, so this tool attempts to make it as best as possible.

Installation

Using Debian package

The simple way is to retrieve and install the latest Debian package produced automatically for each release. See release page.

After downloading the latest Debian package, you can install it using the following command:

dpkg -i icinga1-objects-upgrader_1.0_all.deb

Using Python wheel package

On non-Debian based OS, you could also install the latest Python wheel package produced automatically for each release. See release page.

After downloading the latest Python wheel package, you can install it using the following command:

python3 -m pip install icinga1_objects_upgrader-1.0-py3-none-any.whl

From source

You could also manually install it from the source using Git:

git clone https://gitlab.easter-eggs.com/brenard/icinga1_objects_upgrader.git \
  /usr/local/src/icinga1_objects_upgrader
python3 -m pip install /usr/local/bin/icinga1_objects_upgrader

Usage

usage: icinga1_objects_upgrader [-h] [-v] [-d] [-l LOGFILE] [-i INPUT] [-e INPUT_ENCODING]
                                [-o OUTPUT] [-E OUTPUT_ENCODING] [-m MAP_OBJECTS] [-D]
                                [--map-custom-macro MAP_CUSTOM_MACROS]
                                [--map-custom-user-macro-value MAP_CUSTOM_USER_MACRO_VALUES]
                                [--host-parents-mapping-policy {individual-dependency,variable}]
                                [--objects-mappers OBJECTS_MAPPERS] [--var-name-lowercase]
                                [-I IGNORE_UNSUPPORTED_PROPERTIES] [-x EXCLUDED_OBJECTS]

optional arguments:
  -h, --help            show this help message and exit
  -v, --verbose         Enable verbose mode
  -d, --debug           Enable debug mode
  -l LOGFILE, --log-file LOGFILE
                        Log file path
  -i INPUT, --input INPUT
                        Icinga object config directory path to parse
  -e INPUT_ENCODING, --input-encoding INPUT_ENCODING
                        Encoding of Icinga1 object config files (default: utf-8)
  -o OUTPUT, --output OUTPUT
                        Icinga object config directory path to parse
  -E OUTPUT_ENCODING, --output-encoding OUTPUT_ENCODING
                        Encoding of Icinga2 object config files (default: utf-8)
  -m MAP_OBJECTS, --map-object MAP_OBJECTS
                        Icinga1 objects name mapping for Icinga2. Could be use to map for
                        instance 'generic-debian' Icinga1 host template to Icinga2 'generic-
                        debian-pa2' Host template. For this example, you have to specify
                        --map-object host:generic-debian=generic-debian-pa2
  -D, --map-object-display-name
                        Also map objects display name in Icinga2.
  --map-custom-macro MAP_CUSTOM_MACROS
                        Icinga1 custom macro name mapping for Icinga2. Could be use to map
                        for instance '_NRPEPORT' Icinga1 host custom macro to Icinga2
                        'nrpe_port' host variable. For this example, you have to specify
                        --map-custom-macro NRPEPORT=nrpe_port
  --map-custom-user-macro-value MAP_CUSTOM_USER_MACRO_VALUES
                        Icinga1 custom user macro value mapping for Icinga2. Could be use to
                        map for instance '$USER1$' Icinga1 custom user macro to
                        '/usr/lib/nagios/plugins' in Icinga2 configuration. For this
                        example, you have to specify --map-custom-user-macro-value
                        USER1=/usr/lib/nagios/plugins
  --host-parents-mapping-policy {individual-dependency,variable}
                        Mapping policy for Icinga1 host parents: in Icinga2, host parents
                        have to be converted in host-to-host dependency. To do that, we
                        could simply create on host-to-parents dependency by host with
                        parents. Another way to do that, is to create an host variable that
                        will store the host's parents and apply host-to-parents by looping
                        on its variable values. This parameter permit to control the mapping
                        method you prefer: possible values are individual-dependency or
                        variable (default: individual-dependency). Note: with the variable
                        policy, only the hosts variable parents will be converted and you
                        have to manually add the apply Dependency rule (see
                        https://icinga.com/docs/icinga-2/latest/doc/23-migrating-from-
                        icinga-1x/#manual-config-migration-hints-for-host-parents).
  --objects-mappers OBJECTS_MAPPERS
                        Icinga1 objects mappers: you could specify name of a python function
                        that will be call for each objects to permit custom adjustment on it
                        (for example, add some variables). For example, you could specify
                        'myicinga2.add_my_vars_to_host' to call the add_my_vars_to_host of
                        the python module myicinga2. This method will take the object
                        reference as unique parameter, could detect the object type using
                        the type object attribute and add some variables to the object
                        attribute variables (dict). Multiple objects mappers could be
                        specify by repeating this parameter.
  --var-name-lowercase  Put Icinga1 custom macro names in lowercase in Icinga2 configuration
  -I IGNORE_UNSUPPORTED_PROPERTIES, --ignore-unsupported-property IGNORE_UNSUPPORTED_PROPERTIES
                        You could use this option to inhibate warnings about specified
                        unsupported properties. Multiple properties could be specified by
                        repeating this parameter.
  -x EXCLUDED_OBJECTS, --exclude-object EXCLUDED_OBJECTS
                        This parameter could be use to exclude some Icinga1 objects that
                        will not be retrieved in Icinga2 configuration. For example, to
                        exclude the check_ipv6_ping command, you have to specify --exclude-
                        object command:check_ipv6_ping. Note: only the matching object will
                        be not exported, all references to this object will be keeped and
                        optionally map to another object if combine with -m/--map-object
                        parameter.

Example:

icinga1_objects_upgrader -v \
    -i /etc/icinga1/objects -o /etc/icing2/conf.d \
  --map-object command:check_ipv4_ping=ping4 \
  --exclude-object command:check_ipv4_ping \
  --map-object command:check_ipv4_host-alive=ping4 \
  --exclude-object command:check_ipv4_host-alive \
  --map-object command:check_smtp=smtp \
  --map-object command:check_ssh=ssh \
  --map-custom-macro SSHPORT=ssh_port \
  --map-object command:check_http=http \
  --map-object command:check_https=https \
  --map-object command:check_simap=simap \
  --map-object command:check_imap=imap \
  --map-object command:check_spop=spop \
  --map-object command:check_pop=pop \
  --map-object command:check_ftp=ftp \
  --map-object command:check_ssmtp=ssmtp \
  --map-object command:check_ipv6_ping=ping6 \
  --exclude-object command:check_ipv6_ping \
  --map-object command:check_ipv6_host-alive=hostalive6 \
  --exclude-object command:check_ipv6_host-alive \
  --map-custom-user-macro-value USER1=/usr/lib/nagios/plugins \
  --var-name-lowercase \
  --map-object-display-name \
  --ignore-unsupported-property host_notification_commands \
  --ignore-unsupported-property service_notification_commands \
  --ignore-unsupported-property inherits_parent \
  --ignore-unsupported-property notification_failure_criteria \
  --host-parents-mapping-policy variable

Define notifications

More than any other concept, notifications have been completely redesigned in Icinga2, and it's really not possible to convert them one-to-one:

  • contact and contactgroup are now User and UserGroup objects.
  • There are no notification parameters in Host and Service definitions (except for the _enablenotifications parameter).
  • User's notification parameters have changed significantly:
    • _host_notificationsenabled and _service_notificationsenabled parameters are replaced by a single _enablenotifications parameter.
    • _host_notificationperiod and _service_notificationperiod parameters are replaced by a single period parameter.
    • _host_notificationoptions and _service_notificationoptions parameters are replaced by similar states and types parameters.
    • _host_notificationcommands and _service_notificationcommands parameters are removed, and notification commands are now defined in the Notification object.
  • Notification objects now group parameters about notifications sent to users.

To make migration easier, I am trying to implement a solution for migrating configurations. I've placed old contacts, _contactgroups, _notificationinterval, _notificationperiod, _notificationsoptions, and _first_notificationdelay of Host and Service objects into a notifications variable. This allows us to dynamically configure Notification objects. The following example demonstrates how to send email notifications to users:

template Notification "generic-notification" {
  period = "24x7"
  interval = 1h

  types = [ Problem, Acknowledgement, Recovery, Custom, FlappingStart,
            FlappingEnd, DowntimeStart, DowntimeEnd, DowntimeRemoved ]

  users = [ "icingaadmin" ]
}

template Notification "generic-host-notification" {
  import "generic-notification"

  command = "mail-host-notification"

  if (host.vars.notifications.users || host.vars.notifications.groups) {
    if (host.vars.notifications.users) {
      users = host.vars.notifications.users
    } else {
      users = []
    }
    if (host.vars.notifications.groups) {
      user_groups = host.vars.notifications.groups
    } else {
      user_groups = []
    }
  }

  if (host.vars.notifications.states) {
    states = host.vars.notifications.states
  } else {
    states = [ Up, Down ]
  }

  if (host.vars.notifications.types) {
    types = host.vars.notifications.types
  }

  if (host.vars.notifications.period) {
    period = host.vars.notifications.period
  }

  if (host.vars.notifications.interval) {
    interval = host.vars.notifications.interval
  }

  if (host.vars.notifications.delay) {
    times.begin = host.vars.notifications.delay
  }
}

template Notification "generic-service-notification" {
  import "generic-notification"

  command = "mail-service-notification"

  if (service.vars.notifications.users || service.vars.notifications.groups) {
    if (service.vars.notifications.users) {
      users = service.vars.notifications.users
    } else {
      users = []
    }
    if (service.vars.notifications.groups) {
      user_groups = service.vars.notifications.groups
    } else {
      user_groups = []
    }
  }

  if (service.vars.notifications.states) {
    states = service.vars.notifications.states
  } else {
    states = [ Warning, Critical, Unknown ]
  }

  if (service.vars.notifications.types) {
    types = service.vars.notifications.types
  }

  if (service.vars.notifications.period) {
    period = service.vars.notifications.period
  }

  if (service.vars.notifications.interval) {
    interval = service.vars.notifications.interval
  }

  if (service.vars.notifications.delay) {
    times.begin = service.vars.notifications.delay
  }
}

apply Notification "notify-by-mail" to Host {
  import "generic-host-notification"

  assign where match("*", host.name) && host.enable_notifications
}

apply Notification "notify-by-mail" to Service {
  import "generic-service-notification"

  assign where match("*", service.name) && service.enable_notifications
}

Note:

Copyright

Copyright (c) 2020-2022 Benjamin Renard / Easter-eggs

License

This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 3 as published by the Free Software Foundation.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.