--- /dev/null
+
+=pod
+/******************************************************************************
+ * Icinga 2 *
+ * Copyright (C) 2012 Icinga Development Team (http://www.icinga.org/) *
+ * *
+ * This program is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU General Public License *
+ * as published by the Free Software Foundation; either version 2 *
+ * of the License, or (at your option) any later version. *
+ * *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ******************************************************************************/
+=cut
+
+
+package Icinga2::Convert;
+
+use strict;
+#use Icinga2;
+use Data::Dumper;
+use File::Find;
+use Storable qw(dclone);
+
+use feature 'say';
+our $dbg_lvl = 1;
+
+################################################################################
+## Validation
+#################################################################################
+
+sub obj_1x_is_template {
+ my $obj_1x = shift;
+
+ if (defined($obj_1x->{'register'})) {
+ if ($obj_1x->{'register'} == 0) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+sub obj_1x_uses_template {
+ my $obj_1x = shift;
+
+ if (defined($obj_1x->{'use'})) {
+ return 1;
+ }
+
+ return 0;
+}
+
+# check if notification object exists (2.x only)
+sub obj_2x_notification_exists {
+ my $objs = shift;
+ my $obj_type = 'notification';
+ my $obj_attr = '__I2CONVERT_NOTIFICATION_NAME';
+ my $obj_val = shift;
+
+ #debug("My objects hive: ".Dumper($objs));
+
+ #debug("Checking for type=$obj_type attr=$obj_attr val=$obj_val ");
+ foreach my $obj_key (keys %{@$objs{$obj_type}}) {
+ my $obj = @$objs{$obj_type}->{$obj_key};
+ next if !defined($obj->{$obj_attr});
+ #debug("Getting attr $obj_attr and val $obj_val");
+ if ($obj->{$obj_attr} eq $obj_val) {
+ #debug("Found object: ".Dumper($obj));
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+# check if command object exists (2.x only)
+sub obj_2x_command_exists {
+ my $objs = shift;
+ my $obj_type = 'command';
+ my $obj_attr = '__I2CONVERT_COMMAND_NAME';
+ my $obj_val = shift;
+
+ #debug("My objects hive: ".Dumper($objs));
+
+ #debug("Checking for type=$obj_type attr=$obj_attr val=$obj_val ");
+ foreach my $obj_key (keys %{@$objs{$obj_type}}) {
+ my $obj = @$objs{$obj_type}->{$obj_key};
+ next if !defined($obj->{$obj_attr});
+ #debug("Getting attr $obj_attr and val $obj_val");
+ if ($obj->{$obj_attr} eq $obj_val) {
+ #debug("Found object: ".Dumper($obj));
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+
+################################################################################
+# Migration
+#################################################################################
+
+
+#################################################################################
+# Get Object Helpers
+#################################################################################
+
+# get host object by attr 'host_name'
+sub obj_get_host_obj_by_host_name {
+ my $objs = shift;
+ my $obj_type = 'host';
+ my $obj_attr = 'host_name';
+ my $obj_val = shift;
+
+ #debug("My objects hive: ".Dumper($objs));
+
+ #debug("Checking for type=$obj_type attr=$obj_attr val=$obj_val ");
+ foreach my $obj_key (keys %{@$objs{$obj_type}}) {
+ my $obj = @$objs{$obj_type}->{$obj_key};
+ next if !defined($obj->{$obj_attr});
+ #debug("Getting attr $obj_attr and val $obj_val");
+ if ($obj->{$obj_attr} eq $obj_val) {
+ #debug("Found object: ".Dumper($obj));
+ return $obj;
+ }
+ }
+
+ return undef;
+}
+
+# get service object by attr 'host_name' and 'service_description'
+sub obj_get_service_obj_by_host_name_service_description {
+ my $objs = shift;
+ my $obj_type = 'service';
+ my $obj_attr_host = shift;
+ my $obj_attr_service = shift;
+ my $obj_val_host = shift;
+ my $obj_val_service = shift;
+
+ #debug("My objects hive: ".Dumper($objs));
+
+ #Icinga2::Utils::debug("Checking for service with host_name=$obj_val_host service_description=$obj_val_service ");
+ foreach my $obj_key (keys %{@$objs{$obj_type}}) {
+ my $obj = @$objs{$obj_type}->{$obj_key};
+ next if !defined($obj->{$obj_attr_host});
+ next if !defined($obj->{$obj_attr_service});
+ #Icinga2::Utils::debug("Getting attr $obj_attr_host/$obj_attr_service and val $obj_val_host/$obj_val_service");
+ if (($obj->{$obj_attr_host} eq $obj_val_host) && ($obj->{$obj_attr_service} eq $obj_val_service)) {
+ #Icinga2::Utils::debug("Found object: ".Dumper($obj));
+ return $obj;
+ }
+ }
+
+ return undef;
+}
+
+# get contact object by attr 'contact_name'
+sub obj_get_contact_obj_by_contact_name {
+ my $objs = shift;
+ my $obj_type = shift;
+ my $obj_attr = shift;
+ my $obj_val = shift;
+
+ #debug("My objects hive: ".Dumper($objs));
+
+ #debug("Checking for type=$obj_type attr=$obj_attr val=$obj_val ");
+ foreach my $obj_key (keys %{@$objs{$obj_type}}) {
+ my $obj = @$objs{$obj_type}->{$obj_key};
+ next if !defined($obj->{$obj_attr});
+ #debug("Getting attr $obj_attr and val $obj_val");
+ if ($obj->{$obj_attr} eq $obj_val) {
+ #debug("Found object: ".Dumper($obj));
+ return $obj;
+ }
+ }
+
+ return undef;
+}
+
+# get user object by attr 'user_name'
+sub obj_get_user_obj_by_user_name {
+ my $objs = shift;
+ my $obj_type = 'user';
+ my $obj_attr = 'user_name';
+ my $obj_val = shift;
+
+ #debug("My objects hive: ".Dumper($objs));
+
+ #debug("Checking for type=$obj_type attr=$obj_attr val=$obj_val ");
+ foreach my $obj_key (keys %{@$objs{$obj_type}}) {
+ my $obj = @$objs{$obj_type}->{$obj_key};
+ next if !defined($obj->{$obj_attr});
+ #debug("Getting attr $obj_attr and val $obj_val");
+ if ($obj->{$obj_attr} eq $obj_val) {
+ #debug("Found object: ".Dumper($obj));
+ return $obj;
+ }
+ }
+
+ return undef;
+}
+
+# get template object by attr 'name'
+sub obj_get_tmpl_obj_by_tmpl_name {
+ my $objs = shift;
+ my $obj_tmpl_type = shift;
+ my $obj_attr_tmpl_name = shift;
+
+ #debug("My objects hive: ".Dumper($objs));
+
+ #Icinga2::Utils::debug("Checking for template name with $obj_attr_tmpl_name");
+ foreach my $obj_key (keys %{@$objs{$obj_tmpl_type}}) {
+ my $obj = @$objs{$obj_tmpl_type}->{$obj_key};
+ next if !defined($obj->{'name'});
+ # XXX it would be safe, but we cannot garantuee it here, so better check before if we want a template or not
+ if ($obj->{'name'} eq $obj_attr_tmpl_name) {
+ #Icinga2::Utils::debug("Found object: ".Dumper($obj));
+ return $obj;
+ }
+ }
+
+ return undef;
+}
+
+
+# get hostgroup object by attr 'hostgroup_name'
+sub obj_get_hostgroup_obj_by_hostgroup_name {
+ my $objs = shift;
+ my $obj_type = 'hostgroup';
+ my $obj_attr = 'hostgroup_name';
+ my $obj_val = shift;
+
+ #debug("My objects hive: ".Dumper($objs));
+
+ #debug("Checking for type=$obj_type attr=$obj_attr val=$obj_val ");
+ foreach my $obj_key (keys %{@$objs{$obj_type}}) {
+ my $obj = @$objs{$obj_type}->{$obj_key};
+ next if !defined($obj->{$obj_attr});
+ #debug("Getting attr $obj_attr and val $obj_val");
+ if ($obj->{$obj_attr} eq $obj_val) {
+ #debug("Found object: ".Dumper($obj));
+ return $obj;
+ }
+ }
+
+ return undef;
+}
+
+#################################################################################
+# Get Object Attribute Helpers
+#################################################################################
+
+
+# get host_names by attr 'hostgroup_name'
+sub obj_get_hostnames_arr_by_hostgroup_name {
+ my $objs = shift;
+ my $obj_type = 'host';
+ my $obj_attr = 'hostgroups';
+ my $obj_val = shift;
+ my @host_names = ();
+
+ #debug("My objects hive: ".Dumper($objs));
+
+ #debug("Checking for type=$obj_type attr=$obj_attr val=$obj_val ");
+ foreach my $obj_key (keys %{@$objs{$obj_type}}) {
+ my $obj = @$objs{$obj_type}->{$obj_key};
+ next if !defined($obj->{$obj_attr});
+ #debug("Getting attr $obj_attr and val $obj_val");
+
+ foreach my $hg (@{$obj->{$obj_attr}}) {
+ if ($hg eq $obj_val) {
+ #debug("Found object: ".Dumper($obj));
+ push @host_names, $obj->{'host_name'};
+ }
+ }
+ }
+
+ return @host_names;
+}
+
+sub obj_get_usernames_arr_by_usergroup_name {
+ my $objs = shift;
+ my $obj_type = 'user';
+ my $obj_attr = 'usergroups';
+ my $obj_val = shift;
+ my @user_names = ();
+
+ #debug("My objects hive: ".Dumper($objs));
+
+ #debug("Checking for type=$obj_type attr=$obj_attr val=$obj_val ");
+ foreach my $obj_key (keys %{@$objs{$obj_type}}) {
+ my $obj = @$objs{$obj_type}->{$obj_key};
+ next if !defined($obj->{$obj_attr});
+ #debug("Getting attr $obj_attr and val $obj_val");
+
+ foreach my $user (@{$obj->{$obj_attr}}) {
+ if ($user eq $obj_val) {
+ #debug("Found object: ".Dumper($obj));
+ push @user_names, $obj->{'user_name'};
+ }
+ }
+ }
+
+ return @user_names;
+}
+
+sub obj_1x_get_all_hostnames_arr {
+ my $objs = shift;
+ my $obj_type = 'host';
+ my $obj_attr = 'host_name';
+ my $obj_val = '*';
+ my @host_names = ();
+
+ #debug("My objects hive: ".Dumper($objs));
+
+ #debug("Checking for type=$obj_type attr=$obj_attr val=$obj_val ");
+ foreach my $obj_key (keys %{@$objs{$obj_type}}) {
+ my $obj = @$objs{$obj_type}->{$obj_key};
+ next if !defined($obj->{$obj_attr});
+ #debug("Getting attr $obj_attr and val $obj_val");
+
+ push @host_names, $obj->{$obj_attr};
+ }
+
+ return @host_names;
+}
+
+
+
+# get host_name from object
+sub obj_1x_get_host_host_name {
+ my $objs_1x = shift;
+ my $obj_1x = shift;
+ my $host_name = "";
+
+ # if this object is invalid, bail early
+ return undef if !defined($obj_1x);
+
+ # first, check if we already got a host_name here in our struct (recursion safety)
+ return $obj_1x->{'__I2CONVERT_HOSTNAME'} if defined($obj_1x->{'__I2CONVERT_HOSTNAME'});
+ delete $obj_1x->{'__I2CONVERT_HOSTNAME'};
+
+ # if this object got what we want, return (it can be recursion and a template!)
+ if(defined($obj_1x->{'host_name'})) {
+ $obj_1x->{'__I2CONVERT_HOSTNAME'} = $obj_1x->{'host_name'};
+ return $obj_1x->{'__I2CONVERT_HOSTNAME'};
+ }
+
+ # we don't have a host name, should we look into a template?
+ # make sure _not_ to use
+ if (defined($obj_1x->{'__I2CONVERT_USES_TEMPLATE'}) && $obj_1x->{'__I2CONVERT_USES_TEMPLATE'} == 1) {
+ # get the object referenced as template - this is an array of templates, loop (funny recursion here)
+ foreach my $obj_1x_template (@{$obj_1x->{'__I2CONVERT_TEMPLATE_NAMES'}}) {
+
+ # get the template object associated with by its unique 'name' attr
+ my $obj_1x_tmpl = obj_get_tmpl_obj_by_tmpl_name($objs_1x, 'host', $obj_1x_template);
+
+ # now recurse into ourselves and look for a possible service_description
+ $host_name = obj_1x_get_host_host_name($objs_1x,$obj_1x_tmpl);
+ # bail here if search did not unveil anything
+ next if(!defined($host_name));
+
+ # get the host_name and return - first template wins
+ $obj_1x->{'__I2CONVERT_HOSTNAME'} = $host_name;
+ return $obj_1x->{'__I2CONVERT_HOSTNAME'};
+ }
+ }
+ # no template used, and no host name - broken object, ignore it
+ else {
+ return undef;
+ }
+
+ # we should never hit here
+ return undef;
+}
+
+# get host_name(s) from service object
+sub obj_1x_get_service_host_name_arr {
+# service objects may contain comma seperated host lists (ugly as ...)
+ my $objs_1x = shift;
+ my $obj_1x = shift;
+ my @host_name = ();
+
+ # if this object is invalid, bail early
+ return undef if !defined($obj_1x);
+
+ # first, check if we already got a host_name here in our struct (recursion safety)
+ return $obj_1x->{'__I2CONVERT_HOSTNAMES'} if defined($obj_1x->{'__I2CONVERT_HOSTNAMES'});
+ delete $obj_1x->{'__I2CONVERT_HOSTNAMES'};
+
+ # if this object got what we want, return (it can be recursion and a template!)
+ if(defined($obj_1x->{'host_name'})) {
+
+ #print "DEBUG: found $obj_1x->{'host_name'}\n";
+
+ # convert to array
+ delete($obj_1x->{'__I2CONVERT_HOSTNAMES'});
+
+ # check if host_name is a wildcard, or a possible comma seperated list
+ # using object tricks - http://docs.icinga.org/latest/en/objecttricks.html#objecttricks-service
+ if ($obj_1x->{'host_name'} =~ /^\*$/) {
+ @host_name = obj_1x_get_all_hostnames_arr($objs_1x);
+ } else {
+ @host_name = Icinga2::Utils::str2arr_by_delim_without_excludes($obj_1x->{'host_name'}, ',', 1);
+ }
+ push @{$obj_1x->{'__I2CONVERT_HOSTNAMES'}}, @host_name;
+
+ #print "DEBUG: @{$obj_1x->{'__I2CONVERT_HOSTNAMES'}}";
+ return @host_name;
+ }
+
+ # we don't have a host name, should we look into a template?
+ # make sure _not_ to use
+ if (defined($obj_1x->{'__I2CONVERT_USES_TEMPLATE'}) && $obj_1x->{'__I2CONVERT_USES_TEMPLATE'} == 1) {
+ # get the object referenced as template - this is an array of templates, loop (funny recursion here)
+ foreach my $obj_1x_template (@{$obj_1x->{'__I2CONVERT_TEMPLATE_NAMES'}}) {
+
+ #say Dumper($obj_1x_template);
+
+ # get the template object associated with by its unique 'name' attr
+ my $obj_1x_tmpl = obj_get_tmpl_obj_by_tmpl_name($objs_1x, 'service', $obj_1x_template);
+
+ # now recurse into ourselves and look for all possible hostnames in array
+ @host_name = obj_1x_get_service_host_name_arr($objs_1x,$obj_1x_tmpl);
+ #print "DEBUG: from tmpl $obj_1x_template: " . join(" ", @host_name) . "\n";
+
+ # bail here if search did not unveil anything
+ next if(!@host_name);
+
+ # get the host_name and return - first template wins
+ # convert to array
+ delete($obj_1x->{'__I2CONVERT_HOSTNAMES'});
+ push @{$obj_1x->{'__I2CONVERT_HOSTNAMES'}}, @host_name;
+ return @host_name;
+ }
+ }
+ # no template used, and no host name - broken object, ignore it
+ else {
+ return undef;
+ }
+
+ # we should never hit here
+ return undef;
+}
+
+# get service_description from object
+sub obj_1x_get_service_service_description {
+ my $objs_1x = shift;
+ my $obj_1x = shift;
+ my $host_name = shift;
+ my $service_description = "";
+
+ # if this object is invalid, bail early
+ return undef if !defined($obj_1x);
+
+ # first, check if we already got a service_description here in our struct (recursion safety)
+ return $obj_1x->{'__I2CONVERT_SERVICEDESCRIPTION'} if defined($obj_1x->{'__I2CONVERT_SERVICEDESCRIPTION'});
+ delete $obj_1x->{'__I2CONVERT_SERVICEDESCRIPTION'};
+
+ # if this object got what we want, return (it can be recursion and a template!)
+ if(defined($obj_1x->{'service_description'})) {
+ $obj_1x->{'__I2CONVERT_SERVICEDESCRIPTION'} = $obj_1x->{'service_description'};
+ return $obj_1x->{'__I2CONVERT_SERVICEDESCRIPTION'};
+ }
+
+ # we don't have a service description, should we look into a template?
+ # make sure _not_ to use
+ if (defined($obj_1x->{'__I2CONVERT_USES_TEMPLATE'}) && $obj_1x->{'__I2CONVERT_USES_TEMPLATE'} == 1) {
+ # get the object referenced as template - this is an array of templates, loop (funny recursion here)
+ foreach my $obj_1x_template (@{$obj_1x->{'__I2CONVERT_TEMPLATE_NAMES'}}) {
+
+ # get the template object associated with by its unique 'name' attr
+ my $obj_1x_tmpl = obj_get_tmpl_obj_by_tmpl_name($objs_1x, 'service', $obj_1x_template);
+
+ # now recurse into ourselves and look for a possible service_description
+ $service_description = obj_1x_get_service_service_description($objs_1x,$obj_1x_tmpl,$host_name); # we must pass the host_name
+ # bail here if search did not unveil anything
+ next if(!defined($service_description));
+
+ # get the service description and return - first template wins
+ $obj_1x->{'__I2CONVERT_SERVICEDESCRIPTION'} = $service_description;
+ return $obj_1x->{'__I2CONVERT_SERVICEDESCRIPTION'};
+ }
+ }
+ # no template used, and not service description - broken object, ignore it
+ else {
+ return undef;
+ }
+
+ # we should never hit here
+ return undef;
+}
+
+################################################################################
+# Conversion
+#################################################################################
+
+# host|service_notification_commands are a comma seperated list w/o arguments
+sub convert_notificationcommand {
+ my $commands_1x = shift;
+ my $obj_1x = shift;
+ my $user_macros_1x = shift;
+ my $command_name_1x;
+ my @commands = ();
+ my $notification_commands_2x = ();
+
+ # bail early if this is not a valid contact object
+ return if (!defined($obj_1x->{'contact_name'}));
+ # bail early if required commands not available (not a valid 1.x object either)
+ return if (!defined($obj_1x->{'host_notification_commands'}) && !defined($obj_1x->{'service_notification_commands'}));
+
+ # a contact has a comma seperated list of notification commands by host and service
+ my $all_notification_commands = {};
+ push @{$all_notification_commands->{'host'}}, split /,\s+/, $obj_1x->{'host_notification_commands'};
+ push @{$all_notification_commands->{'service'}}, split /,\s+/, $obj_1x->{'service_notification_commands'};
+
+
+ foreach my $obj_notification_command_key ( keys %{$all_notification_commands}) {
+
+ # fetch all command names in array via type key
+ my @notification_commands = @{$all_notification_commands->{$obj_notification_command_key}};
+ my $notification_command_type = $obj_notification_command_key;
+
+ foreach my $notification_command (@notification_commands) {
+
+ # now back in all command objects of 1.x
+ foreach my $command_1x_key (keys %{$commands_1x}) {
+ chomp $notification_command; # remove trailing spaces
+
+ if ($commands_1x->{$command_1x_key}->{'command_name'} eq $notification_command) {
+ # save the type (host, service) and then by command name
+ $notification_commands_2x->{$notification_command_type}->{$notification_command} = Icinga2::Utils::escape_str($commands_1x->{$command_1x_key}->{'command_line'});
+ }
+ }
+
+ }
+ }
+
+ return $notification_commands_2x;
+
+}
+
+# event_handler
+sub convert_eventhandler {
+ my $commands_1x = shift;
+ my $obj_1x = shift;
+ my $user_macros_1x = shift;
+ my $command_name_1x;
+ my @commands = ();
+ my $event_commands_2x = ();
+
+ # bail early if required commands not available (not a valid 1.x object either)
+ return if (!defined($obj_1x->{'event_handler'}));
+
+ my $event_command = $obj_1x->{'event_handler'};
+ #say Dumper($event_command);
+
+ # now back in all command objects of 1.x
+ foreach my $command_1x_key (keys %{$commands_1x}) {
+ chomp $event_command; # remove trailing spaces
+
+ if ($commands_1x->{$command_1x_key}->{'command_name'} eq $event_command) {
+ # save the command line and command name
+ $event_commands_2x->{'command_name'} = $event_command;
+ $event_commands_2x->{'command_line'} = Icinga2::Utils::escape_str($commands_1x->{$command_1x_key}->{'command_line'});
+ }
+ }
+
+ return $event_commands_2x;
+
+}
+
+
+# check_command accepts argument parameters, special treatment
+sub convert_checkcommand {
+ my $commands_1x = shift;
+ my $obj_1x = shift; #host or service
+ my $user_macros_1x = shift;
+
+ my $command_1x;
+ my $command_2x = {};
+ #say Dumper($commands_1x);
+ #say Dumper($obj_1x);
+
+ # ignore objects without check_command (may defined in template!)
+ return if (!defined($obj_1x->{'check_command'}));
+
+ #debug("check_command: $obj_1x->{'check_command'}" );
+ # split by ! and take only the check command
+ my ($real_command_name_1x, @command_args_1x) = split /!/, $obj_1x->{'check_command'};
+
+ # ignore objects with empty check_command attribute
+ #return if (!defined($real_command_name_1x));
+
+ #debug("1x Command Name: $real_command_name_1x");
+ if (@command_args_1x) {
+ #debug("1x Command Args: @command_args_1x");
+ }
+
+ foreach my $command_1x_key (keys %{$commands_1x}) {
+
+ #say Dumper($commands_1x->{$command_1x_key}->{'command_name'});
+ if ($commands_1x->{$command_1x_key}->{'command_name'} eq $real_command_name_1x) {
+ #debug("Found: $real_command_name_1x");
+
+ # save the command_line and the $ARGn$ macros
+ $command_2x->{'check_command'} = Icinga2::Utils::escape_str($commands_1x->{$command_1x_key}->{'command_line'});
+ $command_2x->{'check_command_name_1x'} = $real_command_name_1x;
+ #Icinga2::Utils::debug("2x Command: $command_2x->{'check_command'}");
+
+ # detect $USERn$ macros and replace them too XXX - this should be a global macro?
+ if ($commands_1x->{$command_1x_key}->{'command_line'} =~/\$(USER\d)\$/) {
+ $command_2x->{'command_macros'}->{$1} = Icinga2::Utils::escape_str($user_macros_1x->{$1});
+ #debug("\$$1\$=$command_2x->{'macros'}->{$1}");
+ }
+
+ # save all command args as macros (we'll deal later with them in service definitions)
+ my $arg_cnt = 1;
+ foreach my $command_arg_1x (@command_args_1x) {
+ my $macro_name_2x = "ARG" . $arg_cnt;
+ $command_2x->{'command_macros'}->{$macro_name_2x} = Icinga2::Utils::escape_str($command_arg_1x);
+ #debug("\$$macro_name_2x\$=$command_2x->{'macros'}->{$macro_name_2x}");
+ $arg_cnt++;
+ }
+ }
+ }
+
+ return $command_2x;
+}
+
+
+# convert existing 1x objects into the 2x objects hive
+sub convert_2x {
+# v1 -> v2
+# register 0 == template
+# use == inherits template
+# dependency == ...
+# escalation == ...
+
+ # hashref is selectable by type first
+ my $icinga2_cfg = shift;
+ my $cfg_obj_1x = shift;
+ my $cfg_obj_cache_1x = shift;
+ my $user_macros_1x = shift;
+
+ # build a new hashref with the actual 2.x config inside
+ my $cfg_obj_2x = {};
+
+ my $command_obj_cnt = 0;
+
+ $cfg_obj_2x->{'command'}->{$command_obj_cnt}->{'__I2CONVERT_COMMAND_NAME'} = '__I2CONVERT_COMMAND_DUMMY';
+
+ ######################################
+ # SERVICE
+ # do the magic lookup for host_name/
+ # service_description for each object
+ # only once
+ ######################################
+ my $service_cnt = 0;
+
+ foreach my $service_obj_1x_key (keys %{@$cfg_obj_1x{'service'}}) {
+
+ #say Dumper(@$cfg_obj_1x{'service'}->{$service_obj_1x_key});
+ my $obj_1x_service = @$cfg_obj_1x{'service'}->{$service_obj_1x_key};
+
+ ####################################################
+ # verify template is/use
+ ####################################################
+ $obj_1x_service->{'__I2CONVERT_IS_TEMPLATE'} = obj_1x_is_template($obj_1x_service);
+ $obj_1x_service->{'__I2CONVERT_USES_TEMPLATE'} = obj_1x_uses_template($obj_1x_service);
+ $obj_1x_service->{'__I2CONVERT_TEMPLATE_NAME'} = $obj_1x_service->{'name'};
+
+ # this can be a comma seperated list of templates
+ my @service_templates = ();
+ if(defined($obj_1x_service->{'use'})) {
+ @service_templates = Icinga2::Utils::str2arr_by_delim_without_excludes($obj_1x_service->{'use'}, ',', 1);
+ }
+
+ push @{$obj_1x_service->{'__I2CONVERT_TEMPLATE_NAMES'}}, @service_templates;
+
+ # add dependency to ITL template to objects
+ if ($obj_1x_service->{'__I2CONVERT_IS_TEMPLATE'} == 0) {
+ if(defined($icinga2_cfg->{'itl'}->{'service-template'}) && $icinga2_cfg->{'itl'}->{'service-template'} ne "") {
+ push @{$obj_1x_service->{'__I2CONVERT_TEMPLATE_NAMES'}}, $icinga2_cfg->{'itl'}->{'service-template'};
+ $obj_1x_service->{'__I2CONVERT_USES_TEMPLATE'} = 1;
+ }
+ }
+
+ ####################################################
+ # get related host_name/service_description
+ # used later in host->service resolval
+ ####################################################
+ # XXX even if the service object uses templates, we need to figure out its host_name/service_description in order to safely link hosts towards it
+ my @host_names = obj_1x_get_service_host_name_arr($cfg_obj_1x, $obj_1x_service);
+
+ #print "DEBUG: service @host_names\n";
+
+ delete($obj_1x_service->{'__I2CONVERT_HOSTNAMES'});
+ if(@host_names == 0) {
+ # set a dummy value for postprocessing - we need the prepared 2.x service for later object tricks
+ push @host_names, "__I2CONVERT_DUMMY";
+ }
+ push @{$obj_1x_service->{'__I2CONVERT_HOSTNAMES'}}, @host_names;
+
+
+ # if there is more than one host_name involved on the service object, clone it in a loop
+ foreach my $service_host_name (@{$obj_1x_service->{'__I2CONVERT_HOSTNAMES'}}) {
+
+ # we can only look up services with their uniqueness to the host_name
+ $obj_1x_service->{'__I2CONVERT_SERVICEDESCRIPTION'} = obj_1x_get_service_service_description($cfg_obj_1x, $obj_1x_service, $service_host_name);
+ #say Dumper($obj_1x_service);
+
+ # skip non-template objects without a valid service description (we cannot tolerate 'name' here!)
+ # XXX find a better way - we actually need all services in the list, even if __I2CONVERT_SERVICEDESCRIPTION is undef
+ if (!defined($obj_1x_service->{'__I2CONVERT_SERVICEDESCRIPTION'}) && $obj_1x_service->{'__I2CONVERT_IS_TEMPLATE'} == 0) {
+ #Icinga2::Utils::debug("Skipping invalid service object without service_description ".Dumper($obj_1x_service));
+ next;
+ }
+
+ ####################################################
+ # clone service object into 2.x
+ ####################################################
+ $cfg_obj_2x->{'service'}->{$service_cnt} = dclone(@$cfg_obj_1x{'service'}->{$service_obj_1x_key});
+
+ # immediately overwrite the correct host_name - if there's no dummy value set for further processing
+ if ($service_host_name !~ /__I2CONVERT_DUMMY/) {
+ $cfg_obj_2x->{'service'}->{$service_cnt}->{__I2CONVERT_SERVICE_HOSTNAME} = $service_host_name;
+ }
+
+ #say Dumper($cfg_obj_2x->{'service'}->{$service_cnt});
+ ####################################################
+ # map existing service attributes
+ # same:
+ # - display_name
+ # - max_check_attempts
+ # - action_url
+ # - notes_url
+ # - notes
+ # - icon_image
+ # - notes
+ # change:
+ # - servicegroups (commaseperated strings to array)
+ # - check_command
+ # - check_interval (X min -> Xm) + normal_check_interval
+ # - retry_interval (X min -> Xm) + retry_check_interval
+ # - notification_interval (X min -> Xm)
+ # - check_period - XXX TODO
+ # - notification_period - XXX TODO
+ # - contacts => users XXX DO NOT DELETE contacts and contactgroups, they will be assembled later for notifications!
+ # -
+ ####################################################
+
+ ##########################################
+ # escape strings in attributes
+ ##########################################
+ if(defined($cfg_obj_2x->{'service'}->{$service_cnt}->{'action_url'})) {
+ $cfg_obj_2x->{'service'}->{$service_cnt}->{'action_url'} = Icinga2::Utils::escape_str($cfg_obj_2x->{'service'}->{$service_cnt}->{'action_url'});
+ }
+ if(defined($cfg_obj_2x->{'service'}->{$service_cnt}->{'notes_url'})) {
+ $cfg_obj_2x->{'service'}->{$service_cnt}->{'notes_url'} = Icinga2::Utils::escape_str($cfg_obj_2x->{'service'}->{$service_cnt}->{'notes_url'});
+ }
+ if(defined($cfg_obj_2x->{'service'}->{$service_cnt}->{'notes'})) {
+ $cfg_obj_2x->{'service'}->{$service_cnt}->{'notes'} = Icinga2::Utils::escape_str($cfg_obj_2x->{'service'}->{$service_cnt}->{'notes'});
+ }
+ if(defined($cfg_obj_2x->{'service'}->{$service_cnt}->{'icon_image'})) {
+ $cfg_obj_2x->{'service'}->{$service_cnt}->{'icon_image'} = Icinga2::Utils::escape_str($cfg_obj_2x->{'service'}->{$service_cnt}->{'icon_image'});
+ }
+ if(defined($cfg_obj_2x->{'service'}->{$service_cnt}->{'icon_image_alt'})) {
+ $cfg_obj_2x->{'service'}->{$service_cnt}->{'icon_image_alt'} = Icinga2::Utils::escape_str($cfg_obj_2x->{'service'}->{$service_cnt}->{'icon_image_alt'});
+ }
+
+ ##########################################
+ # servicegroups
+ ##########################################
+ delete($cfg_obj_2x->{'service'}->{$service_cnt}->{'servicegroups'});
+ # debug # @{$cfg_obj_2x->{'service'}->{$service_cnt}->{'servicegroups'}} = ();
+
+ if(defined($obj_1x_service->{'servicegroups'})) {
+ # check if there's additive inheritance required, and save a flag
+ if ($obj_1x_service->{'servicegroups'} =~ /^\+/) {
+ $cfg_obj_2x->{'service'}->{$service_cnt}->{'__I2_CONVERT_SG_ADD'} = 1;
+ $obj_1x_service->{'servicegroups'} =~ s/^\+//;
+ }
+ # convert comma seperated list to array
+ push @{$cfg_obj_2x->{'service'}->{$service_cnt}->{'servicegroups'}}, Icinga2::Utils::str2arr_by_delim_without_excludes($obj_1x_service->{'servicegroups'}, ',', 1);
+ #print "DEBUG: servicegroups " . join (" ", @{$cfg_obj_2x->{'service'}->{$service_cnt}->{'servicegroups'}});
+ }
+
+ ##########################################
+ # check_interval
+ ##########################################
+ my $service_check_interval = undef;
+ if(defined($obj_1x_service->{'normal_check_interval'})) {
+ $service_check_interval = $obj_1x_service->{'normal_check_interval'};
+ }
+ if(defined($obj_1x_service->{'check_interval'})) {
+ $service_check_interval = $obj_1x_service->{'check_interval'};
+ }
+ # we assume that 1.x kept 1m default interval, and map it
+ if (defined($service_check_interval)) {
+ $cfg_obj_2x->{'service'}->{$service_cnt}->{'check_interval'} = $service_check_interval."m";
+ }
+
+ ##########################################
+ # retry_interval
+ ##########################################
+ my $service_retry_interval = undef;
+ if(defined($obj_1x_service->{'retry_check_interval'})) {
+ $service_retry_interval = $obj_1x_service->{'retry_check_interval'};
+ }
+ if(defined($obj_1x_service->{'retry_interval'})) {
+ $service_retry_interval = $obj_1x_service->{'retry_interval'};
+ }
+ # we assume that 1.x kept 1m default interval, and map it
+ if (defined($service_retry_interval)) {
+ $cfg_obj_2x->{'service'}->{$service_cnt}->{'retry_interval'} = $service_retry_interval."m";
+ }
+
+ ##########################################
+ # notification_interval
+ ##########################################
+ my $service_notification_interval = undef;
+ if(defined($obj_1x_service->{'notification_interval'})) {
+ $service_notification_interval = $obj_1x_service->{'notification_interval'};
+ }
+ # we assume that 1.x kept 1m default interval, and map it
+ if (defined($service_notification_interval)) {
+ $cfg_obj_2x->{'service'}->{$service_cnt}->{'notification_interval'} = $service_notification_interval."m";
+ }
+
+ ##########################################
+ # eventhandler
+ ##########################################
+ if (defined($obj_1x_service->{'event_handler'})) {
+
+ my $service_event_command_2x = Icinga2::Convert::convert_eventhandler(@$cfg_obj_1x{'command'}, $obj_1x_service, $user_macros_1x);
+ #say Dumper($service_event_command_2x);
+
+ # XXX do not add duplicate event commands, they must remain unique by their check_command origin!
+ if ((obj_2x_command_exists($cfg_obj_2x, $obj_1x_service->{'event_handler'}) != 1)) {
+
+ # create a new EventCommand 2x object with the original name
+ $cfg_obj_2x->{'command'}->{$command_obj_cnt}->{'__I2CONVERT_COMMAND_TYPE'} = 'Event';
+ $cfg_obj_2x->{'command'}->{$command_obj_cnt}->{'__I2CONVERT_COMMAND_NAME'} = $service_event_command_2x->{'command_name'};
+ $cfg_obj_2x->{'command'}->{$command_obj_cnt}->{'__I2CONVERT_COMMAND_LINE'} = $service_event_command_2x->{'command_line'};
+
+ # use the ITL plugin check command template
+ if(defined($icinga2_cfg->{'itl'}->{'eventcommand-template'}) && $icinga2_cfg->{'itl'}->{'eventcommand-template'} ne "") {
+ push @{$cfg_obj_2x->{'command'}->{$command_obj_cnt}->{'__I2CONVERT_TEMPLATE_NAMES'}}, $icinga2_cfg->{'itl'}->{'eventcommand-template'};
+ $cfg_obj_2x->{'command'}->{$command_obj_cnt}->{'__I2CONVERT_USES_TEMPLATE'} = 1;
+ }
+
+ # our PK
+ $command_obj_cnt++;
+ }
+
+ # the event_handler name of 1.x is still the unique command object name, so we just keep
+ # in __I2_CONVERT_EVENTCOMMAND_NAME in our service object
+ $cfg_obj_2x->{'service'}->{$service_cnt}->{'__I2_CONVERT_EVENTCOMMAND_NAME'} = $service_event_command_2x->{'command_name'};
+
+ }
+
+
+ ##########################################
+ # volatile is bool only
+ ##########################################
+ if (defined($obj_1x_service->{'is_volatile'})) {
+ $cfg_obj_2x->{'service'}->{$service_cnt}->{'volatile'} = ($obj_1x_service->{'is_volatile'} > 0) ? 1 : 0;
+ }
+
+ ##########################################
+ # map the service check_command to 2.x
+ ##########################################
+ my $service_check_command_2x = Icinga2::Convert::convert_checkcommand(@$cfg_obj_1x{'command'}, $obj_1x_service, $user_macros_1x);
+
+ #say Dumper($service_check_command_2x);
+
+ if (defined($service_check_command_2x->{'check_command_name_1x'})) {
+
+ # XXX do not add duplicate check commands, they must remain unique by their check_command origin!
+ if (obj_2x_command_exists($cfg_obj_2x, $service_check_command_2x->{'check_command_name_1x'}) != 1) {
+
+ # create a new CheckCommand 2x object with the original name
+ $cfg_obj_2x->{'command'}->{$command_obj_cnt}->{'__I2CONVERT_COMMAND_TYPE'} = 'Check';
+ $cfg_obj_2x->{'command'}->{$command_obj_cnt}->{'__I2CONVERT_COMMAND_NAME'} = $service_check_command_2x->{'check_command_name_1x'};
+ $cfg_obj_2x->{'command'}->{$command_obj_cnt}->{'__I2CONVERT_COMMAND_LINE'} = $service_check_command_2x->{'check_command'};
+
+ # use the ITL plugin check command template
+ if(defined($icinga2_cfg->{'itl'}->{'checkcommand-template'}) && $icinga2_cfg->{'itl'}->{'checkcommand-template'} ne "") {
+ push @{$cfg_obj_2x->{'command'}->{$command_obj_cnt}->{'__I2CONVERT_TEMPLATE_NAMES'}}, $icinga2_cfg->{'itl'}->{'checkcommand-template'};
+ $cfg_obj_2x->{'command'}->{$command_obj_cnt}->{'__I2CONVERT_USES_TEMPLATE'} = 1;
+ }
+
+ # add the command macros to the command 2x object
+ if(defined($service_check_command_2x->{'command_macros'})) {
+ $cfg_obj_2x->{'command'}->{$command_obj_cnt}->{'__I2CONVERT_COMMAND_MACROS'} = dclone($service_check_command_2x->{'command_macros'});
+ }
+
+ # our PK
+ $command_obj_cnt++;
+ }
+
+ # make sure service object still got the checkcommand assigned
+ # the check command name of 1.x is still the unique command object name, so we just keep
+ # in $service_check_command_2x->{'check_command'} the cut real check_command_name_1x
+ delete($service_check_command_2x->{'check_command'});
+ $cfg_obj_2x->{'service'}->{$service_cnt}->{'__I2_CONVERT_CHECKCOMMAND_NAME'} = $service_check_command_2x->{'check_command_name_1x'};
+
+ }
+
+ # XXX make sure to always add the service specific command arguments, since we have a n .. 1 relation here
+ # add the command macros to the command 2x object
+ if(defined($service_check_command_2x->{'command_macros'})) {
+ @$cfg_obj_2x{'service'}->{$service_cnt}->{command_macros} = dclone($service_check_command_2x->{'command_macros'});
+ }
+
+ # our PK
+ $service_cnt++;
+ }
+
+ }
+ ######################################
+ # HOST
+ # use => inherit template
+ # register 0 => template
+ # check_command => create a new service?
+ ######################################
+
+ # "get all 'host' hashref as array in hashmap, and their keys to access it"
+ foreach my $host_obj_1x_key (keys %{@$cfg_obj_1x{'host'}}) {
+
+ #say Dumper(@$cfg_obj_1x{'host'}->{$host_obj_1x_key});
+ my $obj_1x_host = @$cfg_obj_1x{'host'}->{$host_obj_1x_key};
+
+ ####################################################
+ # verify template is/use
+ ####################################################
+ $obj_1x_host->{'__I2CONVERT_IS_TEMPLATE'} = obj_1x_is_template($obj_1x_host);
+ $obj_1x_host->{'__I2CONVERT_USES_TEMPLATE'} = obj_1x_uses_template($obj_1x_host);
+ $obj_1x_host->{'__I2CONVERT_TEMPLATE_NAME'} = $obj_1x_host->{'name'};
+
+ # this can be a comma seperated list of templates
+ my @host_templates = ();
+ if(defined($obj_1x_host->{'use'})) {
+ @host_templates = Icinga2::Utils::str2arr_by_delim_without_excludes($obj_1x_host->{'use'}, ',', 1);
+ }
+
+ push @{$obj_1x_host->{'__I2CONVERT_TEMPLATE_NAMES'}}, @host_templates;
+
+ ####################################################
+ # get the related host_name
+ ####################################################
+ # XXX even if the host object uses templates, we need to figure out its host_name in order to safely link services towards it
+ $obj_1x_host->{'__I2CONVERT_HOSTNAME'} = obj_1x_get_host_host_name($cfg_obj_1x, $obj_1x_host);
+
+ ####################################################
+ # skip objects without a valid hostname
+ ####################################################
+ if (!defined($obj_1x_host->{'__I2CONVERT_HOSTNAME'}) && $obj_1x_host->{'__I2CONVERT_IS_TEMPLATE'} == 0) {
+ #Icinga2::Utils::debug("Skipping invalid host object without host_name ".Dumper($obj_1x_host));
+ next;
+ }
+ #say Dumper($obj_1x_host);
+ #
+
+ # FIXME do that later on
+ # primary host->service relation resolval
+
+ ####################################################
+ # Clone the existing object into 2.x
+ ####################################################
+ # save a copy with the valid ones
+ $cfg_obj_2x->{'host'}->{$host_obj_1x_key} = dclone(@$cfg_obj_1x{'host'}->{$host_obj_1x_key});
+
+ ####################################################
+ # map existing host attributes
+ # same:
+ # - max_check_attempts
+ # - action_url
+ # - notes_url
+ # - notes
+ # - icon_image
+ # - statusmap_image
+ # - notes
+ # change:
+ # - display_name (if alias is set, overwrites it)
+ # - hostgroups (commaseperated strings to array)
+ # - check_interval (X min -> Xm) + normal_check_interval
+ # - retry_interval (X min -> Xm) + retry_check_interval
+ # - notification_interval (X min -> Xm)
+ # - check_period - XXX TODO
+ # - notification_period - XXX TODO
+ # - contacts => users XXX DO NOT DELETE contacts and contactgroups - they will be assembled later for notifications!
+ # -
+ # remove:
+ # - check_command
+ ####################################################
+
+ ##########################################
+ # escape strings in attributes
+ ##########################################
+ if(defined($cfg_obj_2x->{'host'}->{$host_obj_1x_key}->{'action_url'})) {
+ $cfg_obj_2x->{'host'}->{$host_obj_1x_key}->{'action_url'} = Icinga2::Utils::escape_str($cfg_obj_2x->{'host'}->{$host_obj_1x_key}->{'action_url'});
+ }
+ if(defined($cfg_obj_2x->{'host'}->{$host_obj_1x_key}->{'notes_url'})) {
+ $cfg_obj_2x->{'host'}->{$host_obj_1x_key}->{'notes_url'} = Icinga2::Utils::escape_str($cfg_obj_2x->{'host'}->{$host_obj_1x_key}->{'notes_url'});
+ }
+ if(defined($cfg_obj_2x->{'host'}->{$host_obj_1x_key}->{'notes'})) {
+ $cfg_obj_2x->{'host'}->{$host_obj_1x_key}->{'notes'} = Icinga2::Utils::escape_str($cfg_obj_2x->{'host'}->{$host_obj_1x_key}->{'notes'});
+ }
+ if(defined($cfg_obj_2x->{'host'}->{$host_obj_1x_key}->{'icon_image'})) {
+ $cfg_obj_2x->{'host'}->{$host_obj_1x_key}->{'icon_image'} = Icinga2::Utils::escape_str($cfg_obj_2x->{'host'}->{$host_obj_1x_key}->{'icon_image'});
+ }
+ if(defined($cfg_obj_2x->{'host'}->{$host_obj_1x_key}->{'icon_image_alt'})) {
+ $cfg_obj_2x->{'host'}->{$host_obj_1x_key}->{'icon_image_alt'} = Icinga2::Utils::escape_str($cfg_obj_2x->{'host'}->{$host_obj_1x_key}->{'icon_image_alt'});
+ }
+
+ ####################################################
+ # display_name -> alias mapping
+ ####################################################
+ # if there was an host alias defined, make this the primary display_name for 2x
+ if(defined($obj_1x_host->{'alias'})) {
+ $cfg_obj_2x->{'host'}->{$host_obj_1x_key}->{'display_name'} = Icinga2::Utils::escape_str($obj_1x_host->{'alias'});
+ }
+
+ ##########################################
+ # hostgroups
+ ##########################################
+ delete($cfg_obj_2x->{'host'}->{$host_obj_1x_key}->{'hostgroups'});
+
+ if(defined($obj_1x_host->{'hostgroups'})) {
+ # check if there's additive inheritance required, and save a flag
+ if ($obj_1x_host->{'hostgroups'} =~ /^\+/) {
+ $cfg_obj_2x->{'host'}->{$host_obj_1x_key}->{'__I2_CONVERT_HG_ADD'} = 1;
+ $obj_1x_host->{'hostgroups'} =~ s/^\+//;
+ }
+
+ # convert comma seperated list to array
+ push @{$cfg_obj_2x->{'host'}->{$host_obj_1x_key}->{'hostgroups'}}, Icinga2::Utils::str2arr_by_delim_without_excludes($obj_1x_host->{'hostgroups'}, ',', 1);
+ #print "DEBUG: hostgroups " . join (" ", @{$cfg_obj_2x->{'host'}->{$host_obj_1x_key}->{'hostgroups'}});
+ }
+
+ ##########################################
+ # check_interval
+ ##########################################
+ my $host_check_interval = undef;
+ if(defined($obj_1x_host->{'normal_check_interval'})) {
+ $host_check_interval = $obj_1x_host->{'normal_check_interval'};
+ }
+ if(defined($obj_1x_host->{'check_interval'})) {
+ $host_check_interval = $obj_1x_host->{'check_interval'};
+ }
+ # we assume that 1.x kept 1m default interval, and map it
+ if (defined($host_check_interval)) {
+ $cfg_obj_2x->{'host'}->{$host_obj_1x_key}->{'check_interval'} = $host_check_interval."m";
+ }
+
+ ##########################################
+ # retry_interval
+ ##########################################
+ my $host_retry_interval = undef;
+ if(defined($obj_1x_host->{'retry_check_interval'})) {
+ $host_retry_interval = $obj_1x_host->{'retry_check_interval'};
+ }
+ if(defined($obj_1x_host->{'retry_interval'})) {
+ $host_retry_interval = $obj_1x_host->{'retry_interval'};
+ }
+ # we assume that 1.x kept 1m default interval, and map it
+ if (defined($host_retry_interval)) {
+ $cfg_obj_2x->{'host'}->{$host_obj_1x_key}->{'retry_interval'} = $host_retry_interval."m";
+ }
+
+ ##########################################
+ # notification_interval
+ ##########################################
+ my $host_notification_interval = undef;
+ if(defined($obj_1x_host->{'notification_interval'})) {
+ $host_notification_interval = $obj_1x_host->{'notification_interval'};
+ }
+ # we assume that 1.x kept 1m default interval, and map it
+ if (defined($host_notification_interval)) {
+ $cfg_obj_2x->{'host'}->{$host_obj_1x_key}->{'notification_interval'} = $host_notification_interval."m";
+ }
+
+ if(defined($obj_1x_host->{'parents'})) {
+ my @host_parents = Icinga2::Utils::str2arr_by_delim_without_excludes($obj_1x_host->{'parents'}, ',', 1);
+ push @{$cfg_obj_2x->{'host'}->{$host_obj_1x_key}->{'__I2CONVERT_PARENT_HOSTNAMES'}}, @host_parents;
+ }
+ ####################################################
+ # Icinga 2 Hosts don't have a check_command anymore
+ # - get a similar service with command_name lookup
+ # and link that service
+ ####################################################
+
+ my $host_check_command_2x = Icinga2::Convert::convert_checkcommand(@$cfg_obj_1x{'command'}, $obj_1x_host, $user_macros_1x);
+ #say Dumper($host_check_command_2x);
+
+ delete($cfg_obj_2x->{'host'}->{$host_obj_1x_key}->{'check_command'});
+
+ if(defined($host_check_command_2x->{'check_command_name_1x'})) {
+ # XXX TODO match on the command_name in available services for _this_ host later on. right on, just save it
+ $cfg_obj_2x->{'host'}->{$host_obj_1x_key}->{'__I2CONVERT_HOSTCHECK_NAME'} = $host_check_command_2x->{'check_command_name_1x'};
+ }
+
+ # XXX skip all host templates, they do not need to be linked with services!
+ #if ($cfg_obj_2x->{'host'}->{$host_obj_1x_key}->{'__I2CONVERT_IS_TEMPLATE'} == 1) {
+ # Icinga2::Utils::debug("Skipping host template for linking against service.");
+ # next;
+ #}
+
+ # NOTE: the relation between host and services for 2x will be done later
+ # this is due to the reason we may manipulate service objects later
+ # e.g. when relinking the servicegroup members, etc
+ # otherwise we would have to make sure to update 2 locations everytime
+ }
+
+ ######################################
+ # CONTACT => USER
+ ######################################
+ my $user_cnt = 0;
+
+ if (!@$cfg_obj_1x{'contact'}) {
+ goto SKIP_CONTACTS;
+ }
+
+ foreach my $contact_obj_1x_key (keys %{@$cfg_obj_1x{'contact'}}) {
+ my $obj_1x_contact = @$cfg_obj_1x{'contact'}->{$contact_obj_1x_key};
+
+ ####################################################
+ # verify template is/use
+ ####################################################
+ $obj_1x_contact->{'__I2CONVERT_IS_TEMPLATE'} = obj_1x_is_template($obj_1x_contact);
+ $obj_1x_contact->{'__I2CONVERT_USES_TEMPLATE'} = obj_1x_uses_template($obj_1x_contact);
+ $obj_1x_contact->{'__I2CONVERT_TEMPLATE_NAME'} = $obj_1x_contact->{'name'}; # XXX makes sense when IS_TEMPLATE is set
+
+ # this can be a comma seperated list of templates
+ my @contact_templates = ();
+ if(defined($obj_1x_contact->{'use'})) {
+ @contact_templates = Icinga2::Utils::str2arr_by_delim_without_excludes($obj_1x_contact->{'use'}, ',', 1);
+ }
+
+ push @{$obj_1x_contact->{'__I2CONVERT_TEMPLATE_NAMES'}}, @contact_templates;
+
+ ####################################################
+ # get all notification commands
+ ####################################################
+ my $notification_commands_2x = Icinga2::Convert::convert_notificationcommand(@$cfg_obj_1x{'command'}, $obj_1x_contact, $user_macros_1x);
+
+ # clone it into our users hash
+ $cfg_obj_2x->{'user'}->{$contact_obj_1x_key} = dclone(@$cfg_obj_1x{'contact'}->{$contact_obj_1x_key});
+
+ # set our own __I2CONVERT_TYPE
+ $cfg_obj_2x->{'user'}->{$contact_obj_1x_key}->{'__I2CONVERT_TYPE'} = "user";
+
+ ####################################################
+ # migrate renamed attributes
+ ####################################################
+ $cfg_obj_2x->{'user'}->{$contact_obj_1x_key}->{'user_name'} = $obj_1x_contact->{'contact_name'};
+
+ if(defined($obj_1x_contact->{'alias'})) {
+ $cfg_obj_2x->{'user'}->{$contact_obj_1x_key}->{'display_name'} = Icinga2::Utils::escape_str($obj_1x_contact->{'alias'});
+ }
+
+ delete($cfg_obj_2x->{'user'}->{$contact_obj_1x_key}->{'usergroups'});
+ if(defined($obj_1x_contact->{'contactgroups'})) {
+
+ # check if there's additive inheritance required, and save a flag
+ if ($obj_1x_contact->{'contactgroups'} =~ /^\+/) {
+ $cfg_obj_2x->{'user'}->{$contact_obj_1x_key}->{'__I2_CONVERT_UG_ADD'} = 1;
+ $obj_1x_contact->{'contactgroups'} =~ s/^\+//;
+ }
+
+ push @{$cfg_obj_2x->{'user'}->{$contact_obj_1x_key}->{'usergroups'}}, Icinga2::Utils::str2arr_by_delim_without_excludes($obj_1x_contact->{'contactgroups'}, ',', 1);
+ #print "DEBUG: usergroups " . join (" ", @{$cfg_obj_2x->{'user'}->{$contact_obj_1x_key}->{'usergroups'}});
+ }
+
+ # we need to rebuild that notification logic entirely for 2.x
+ # do that later when all objects are processed and prepared (all relations?)
+ #say Dumper($notification_commands_2x);
+ $cfg_obj_2x->{'user'}->{$contact_obj_1x_key}->{'__I2CONVERT_NOTIFICATION_COMMANDS'} = $notification_commands_2x;
+ }
+
+ SKIP_CONTACTS:
+
+ ######################################
+ # GROUPS
+ ######################################
+
+ if (!@$cfg_obj_1x{'hostgroup'}) {
+ goto SKIP_HOSTGROUPS;
+ }
+
+ # host->hostgroups and hostgroup-members relinked together
+ foreach my $hostgroup_obj_1x_key (keys %{@$cfg_obj_1x{'hostgroup'}}) {
+ my $obj_1x_hostgroup = @$cfg_obj_1x{'hostgroup'}->{$hostgroup_obj_1x_key};
+ # clone it into our hash
+ $cfg_obj_2x->{'hostgroup'}->{$hostgroup_obj_1x_key} = dclone(@$cfg_obj_1x{'hostgroup'}->{$hostgroup_obj_1x_key});
+
+ if(defined($obj_1x_hostgroup->{'alias'})) {
+ $cfg_obj_2x->{'hostgroup'}->{$hostgroup_obj_1x_key}->{'display_name'} = Icinga2::Utils::escape_str($obj_1x_hostgroup->{'alias'});
+ }
+
+ ####################################################
+ # check if host_groupname exists, if not, try to copy it from 'name' (no template inheritance possible in groups!)
+ ####################################################
+ if(!defined($obj_1x_hostgroup->{'hostgroup_name'})) {
+ if(defined($obj_1x_hostgroup->{'name'})) {
+ $cfg_obj_2x->{'hostgroup'}->{$hostgroup_obj_1x_key}->{'hostgroup_name'} = $obj_1x_hostgroup->{'name'};
+ }
+ }
+
+ ####################################################
+ # check if there are members defined, we must re-link them in their host object again
+ ####################################################
+ if(defined($obj_1x_hostgroup->{'members'})) {
+
+ my @hg_members = ();
+ # check if members is a wildcard, or a possible comma seperated list
+ # using object tricks - http://docs.icinga.org/latest/en/objecttricks.html#objecttricks-service
+ # XXX better create a master template where all hosts inherit from, and use additive hostgroups attribute
+ if ($obj_1x_hostgroup->{'members'} =~ /^\*$/) {
+ @hg_members = obj_1x_get_all_hostnames_arr($cfg_obj_2x);
+ } else {
+ @hg_members = Icinga2::Utils::str2arr_by_delim_without_excludes($obj_1x_hostgroup->{'members'}, ',', 1);
+ }
+
+ foreach my $hg_member (@hg_members) {
+ my $obj_2x_hg_member = obj_get_host_obj_by_host_name($cfg_obj_2x, $hg_member);
+ #print "DEBUG: $hg_member found.\n";
+ push @{$obj_2x_hg_member->{'hostgroups'}}, $obj_1x_hostgroup->{'hostgroup_name'};
+ }
+ }
+ }
+
+ SKIP_HOSTGROUPS:
+
+ if (!@$cfg_obj_1x{'servicegroup'}) {
+ goto SKIP_SERVICEGROUPS;
+ }
+
+ # service->servicegroups and servicegroup->members relinked together
+ foreach my $servicegroup_obj_1x_key (keys %{@$cfg_obj_1x{'servicegroup'}}) {
+ my $obj_1x_servicegroup = @$cfg_obj_1x{'servicegroup'}->{$servicegroup_obj_1x_key};
+ # clone it into our hash
+ $cfg_obj_2x->{'servicegroup'}->{$servicegroup_obj_1x_key} = dclone(@$cfg_obj_1x{'servicegroup'}->{$servicegroup_obj_1x_key});
+
+ if(defined($obj_1x_servicegroup->{'alias'})) {
+ $cfg_obj_2x->{'servicegroup'}->{$servicegroup_obj_1x_key}->{'display_name'} = Icinga2::Utils::escape_str($obj_1x_servicegroup->{'alias'});
+ }
+
+ ####################################################
+ # check if service_groupname exists, if not, try to copy it from 'name' (no template inheritance possible in groups!)
+ ####################################################
+ if(!defined($obj_1x_servicegroup->{'servicegroup_name'})) {
+ if(defined($obj_1x_servicegroup->{'name'})) {
+ $cfg_obj_2x->{'servicegroup'}->{$servicegroup_obj_1x_key}->{'servicegroup_name'} = $obj_1x_servicegroup->{'name'};
+ }
+ }
+
+ ####################################################
+ # check if there are members defined, we must re-link them in their service object again
+ ####################################################
+ if(defined($obj_1x_servicegroup->{'members'})) {
+
+ # host1,svc1,host2,svc2 is just an insane way of parsing stuff - do NOT sort here.
+ my @sg_members = Icinga2::Utils::str2arr_by_delim_without_excludes($obj_1x_servicegroup->{'members'}, ',', 0);
+ # just some safety for debugging
+ if(@sg_members % 2 != 0) {
+ Icinga2::Utils::debug("servicegroup $obj_1x_servicegroup->{'servicegroup_name'} members list not even: $obj_1x_servicegroup->{'members'}");
+ }
+ #print "DEBUG: $obj_1x_servicegroup->{'servicegroup_name'}: @sg_members\n";
+ my $obj_2x_sg_member;
+ while (scalar(@sg_members) > 0) {
+ my $sg_member_host = shift(@sg_members);
+ my $sg_member_service = shift(@sg_members);
+ #print "DEBUG: Looking for $obj_1x_servicegroup->{'servicegroup_name'}: $sg_member_host/$sg_member_service\n";
+ # since we require the previously looked up unique hostname/service_description, we use the new values in 2x objects (__I2CONVERT_...)
+ my $obj_2x_sg_member = obj_get_service_obj_by_host_name_service_description($cfg_obj_2x, "__I2CONVERT_SERVICE_HOSTNAME", "__I2CONVERT_SERVICEDESCRIPTION", $sg_member_host, $sg_member_service);
+ #print "DEBUG: $sg_member_host,$sg_member_service found.\n";
+ push @{$obj_2x_sg_member->{'servicegroups'}}, $obj_1x_servicegroup->{'servicegroup_name'};
+ }
+ #say Dumper($cfg_obj_2x->{'service'});
+ }
+ }
+
+ SKIP_SERVICEGROUPS:
+
+ if (!@$cfg_obj_1x{'contactgroup'}) {
+ goto SKIP_CONTACTGROUPS;
+ }
+
+ # contact->contactgroups and contactgroup->members relinked together
+ foreach my $contactgroup_obj_1x_key (keys %{@$cfg_obj_1x{'contactgroup'}}) {
+ my $obj_1x_contactgroup = @$cfg_obj_1x{'contactgroup'}->{$contactgroup_obj_1x_key};
+ # clone it into our hash
+ $cfg_obj_2x->{'usergroup'}->{$contactgroup_obj_1x_key} = dclone(@$cfg_obj_1x{'contactgroup'}->{$contactgroup_obj_1x_key});
+ $cfg_obj_2x->{'usergroup'}->{$contactgroup_obj_1x_key}->{'__I2CONVERT_TYPE'} = "usergroup";
+
+ ####################################################
+ # migrate renamed attributes
+ ####################################################
+ $cfg_obj_2x->{'usergroup'}->{$contactgroup_obj_1x_key}->{'usergroup_name'} = $obj_1x_contactgroup->{'contactgroup_name'};
+
+ if(defined($obj_1x_contactgroup->{'alias'})) {
+ $cfg_obj_2x->{'usergroup'}->{$contactgroup_obj_1x_key}->{'display_name'} = Icinga2::Utils::escape_str($obj_1x_contactgroup->{'alias'});
+ }
+
+ ####################################################
+ # check if contact_groupname exists, if not, try to copy it from 'name' (no template inheritance possible in groups!)
+ ####################################################
+ if(!defined($obj_1x_contactgroup->{'contactgroup_name'})) {
+ if(defined($obj_1x_contactgroup->{'name'})) {
+ $cfg_obj_2x->{'usergroup'}->{$contactgroup_obj_1x_key}->{'usergroup_name'} = $obj_1x_contactgroup->{'name'};
+ }
+ }
+
+ ####################################################
+ # check if there are members defined, we must re-link them in their host object again
+ ####################################################
+ if(defined($obj_1x_contactgroup->{'members'})) {
+ my @cg_members = Icinga2::Utils::str2arr_by_delim_without_excludes($obj_1x_contactgroup->{'members'}, ',', 1);
+ foreach my $cg_member (@cg_members) {
+ my $obj_2x_cg_member = obj_get_contact_obj_by_contact_name($cfg_obj_2x, "user", "user_name", $cg_member);
+ #print "DEBUG: $cg_member found.\n";
+ push @{$obj_2x_cg_member->{'usergroups'}}, $obj_1x_contactgroup->{'contactgroup_name'};
+ }
+ }
+ }
+
+ SKIP_CONTACTGROUPS:
+
+ ######################################
+ # TIMEPERIODS
+ ######################################
+
+ if (!@$cfg_obj_1x{'timeperiod'}) {
+ goto SKIP_TIMEPERIODS;
+ }
+
+ foreach my $timeperiod_obj_1x_key (keys %{@$cfg_obj_1x{'timeperiod'}}) {
+ my $obj_1x_timeperiod = @$cfg_obj_1x{'timeperiod'}->{$timeperiod_obj_1x_key};
+ # clone it into our hash
+ $cfg_obj_2x->{'timeperiod'}->{$timeperiod_obj_1x_key} = dclone(@$cfg_obj_1x{'timeperiod'}->{$timeperiod_obj_1x_key});
+
+ ####################################################
+ # add dependency to ITL template to objects
+ ####################################################
+ if(defined($icinga2_cfg->{'itl'}->{'timeperiod-template'}) && $icinga2_cfg->{'itl'}->{'timeperiod-template'} ne "") {
+ push @{$cfg_obj_2x->{'timeperiod'}->{$timeperiod_obj_1x_key}->{'__I2CONVERT_TEMPLATE_NAMES'}}, $icinga2_cfg->{'itl'}->{'timeperiod-template'};
+ $cfg_obj_2x->{'timeperiod'}->{$timeperiod_obj_1x_key}->{'__I2CONVERT_USES_TEMPLATE'} = 1;
+ }
+
+ ####################################################
+ # display_name -> alias mapping
+ ####################################################
+ # if there was a timeperiod alias defined, make this the primary display_name for 2x
+ if(defined($obj_1x_timeperiod->{'alias'})) {
+ $cfg_obj_2x->{'timeperiod'}->{$timeperiod_obj_1x_key}->{'display_name'} = Icinga2::Utils::escape_str($obj_1x_timeperiod->{'alias'});
+ delete($cfg_obj_2x->{'timeperiod'}->{$timeperiod_obj_1x_key}->{'alias'});
+ }
+
+ }
+
+ SKIP_TIMEPERIODS:
+
+ ######################################
+ # DEPENDENCIES
+ ######################################
+
+ if (!@$cfg_obj_1x{'hostdependency'}) {
+ goto SKIP_HOSTDEPS;
+ }
+
+ foreach my $hostdependency_obj_1x_key (keys %{@$cfg_obj_1x{'hostdependency'}}) {
+ my $obj_1x_hostdependency = @$cfg_obj_1x{'hostdependency'}->{$hostdependency_obj_1x_key};
+ # clone it into our hash
+ $cfg_obj_2x->{'hostdependency'}->{$hostdependency_obj_1x_key} = dclone(@$cfg_obj_1x{'hostdependency'}->{$hostdependency_obj_1x_key});
+
+ # 1. the single host_name entries
+ # host_name is the master host (comma seperated list)
+ # dependent_host_name is the child host (comma seperated list)
+ my @master_host_names = Icinga2::Utils::str2arr_by_delim_without_excludes($obj_1x_hostdependency->{'host_name'}, ',', 1);
+ my @child_host_names = Icinga2::Utils::str2arr_by_delim_without_excludes($obj_1x_hostdependency->{'dependent_host_name'}, ',', 1);
+
+ # go through all child hosts, and push to the parents array
+ foreach my $child_host_name (@child_host_names) {
+ my $child_host_obj = obj_get_host_obj_by_host_name($cfg_obj_2x, $child_host_name);
+
+ push @{$child_host_obj->{'__I2CONVERT_PARENT_HOSTNAMES'}}, @master_host_names;
+ }
+
+ # 2. the infamous group logic - let's loop because we're cool
+ my @master_hostgroup_names = Icinga2::Utils::str2arr_by_delim_without_excludes($obj_1x_hostdependency->{'hostgroup_name'}, ',', 1);
+ my @child_hostgroup_names = Icinga2::Utils::str2arr_by_delim_without_excludes($obj_1x_hostdependency->{'dependent_hostgroup_name'}, ',', 1);
+
+ my @all_master_hostgroup_hostnames = ();
+
+ # get all hosts as array for the master host groups
+ foreach my $master_hostgroup_name (@master_hostgroup_names) {
+ my @host_master_hostgroup_hostnames = obj_get_hostnames_arr_by_hostgroup_name($cfg_obj_2x, $master_hostgroup_name);
+ push @all_master_hostgroup_hostnames, @host_master_hostgroup_hostnames;
+ }
+
+ # go through all child hostgroups and fetch their host objects, setting
+ foreach my $child_hostgroup_name (@child_hostgroup_names) {
+ my @host_child_hostgroup_hostnames = obj_get_hostnames_arr_by_hostgroup_name($cfg_obj_2x, $child_hostgroup_name);
+ foreach my $host_child_hostgroup_hostname (@host_child_hostgroup_hostnames) {
+ my $child_host_obj = obj_get_host_obj_by_host_name($cfg_obj_2x, $host_child_hostgroup_hostname);
+ push @{$child_host_obj->{'__I2CONVERT_PARENT_HOSTNAMES'}}, @all_master_hostgroup_hostnames;
+ }
+ }
+ }
+
+ # XXX ugly but works
+ SKIP_HOSTDEPS:
+
+ if (!@$cfg_obj_1x{'servicedependency'}) {
+ goto SKIP_SVCDEPS;
+ }
+
+ foreach my $servicedependency_obj_1x_key (keys %{@$cfg_obj_1x{'servicedependency'}}) {
+ my $obj_1x_servicedependency = @$cfg_obj_1x{'servicedependency'}->{$servicedependency_obj_1x_key};
+ # clone it into our hash
+ $cfg_obj_2x->{'servicedependency'}->{$servicedependency_obj_1x_key} = dclone(@$cfg_obj_1x{'servicedependency'}->{$servicedependency_obj_1x_key});
+
+ # 1. the single host_name / service_description entries
+ # service_description is a string, while the host_name directive is still a comma seperated list
+ my @master_host_names = Icinga2::Utils::str2arr_by_delim_without_excludes($obj_1x_servicedependency->{'host_name'}, ',', 1);
+ my @child_host_names = Icinga2::Utils::str2arr_by_delim_without_excludes($obj_1x_servicedependency->{'dependent_host_name'}, ',', 1);
+
+ my $master_service_description = $obj_1x_servicedependency->{'service_description'};
+ my $child_service_description = $obj_1x_servicedependency->{'dependent_service_description'};
+
+ # XXX object tricks allow more here
+ # - comma seperated list of service descriptions on a single *host_name
+ # - wildcard * for all services on a single *host_name
+
+ # go through all child hosts, and get the service object by host_name and our single service_description
+ foreach my $child_host_name (@child_host_names) {
+ my $child_service_obj = obj_get_service_obj_by_host_name_service_description($cfg_obj_2x, "__I2CONVERT_SERVICE_HOSTNAME", "__I2CONVERT_SERVICEDESCRIPTION", $child_host_name, $child_service_description);
+ # stash all master dependencies onto the child service
+ foreach my $master_host_name (@master_host_names) {
+ # use some calculated unique key here (no, i will not split the string later! we are perl, we can do hashes)
+ my $master_key = $master_host_name."-".$master_service_description;
+ $child_service_obj->{'__I2CONVERT_PARENT_SERVICES'}->{$master_key}->{'host'} = $master_host_name;
+ $child_service_obj->{'__I2CONVERT_PARENT_SERVICES'}->{$master_key}->{'service'} = $master_service_description;
+ }
+ }
+
+ # 2. the infamous group logic - but only for hostgroups here
+ my @master_hostgroup_names = Icinga2::Utils::str2arr_by_delim_without_excludes($obj_1x_servicedependency->{'hostgroup_name'}, ',', 1);
+ my @child_hostgroup_names = Icinga2::Utils::str2arr_by_delim_without_excludes($obj_1x_servicedependency->{'dependent_hostgroup_name'}, ',', 1);
+
+ my @all_master_hostgroup_hostnames = ();
+
+ # get all hosts as array for the master host groups
+ foreach my $master_hostgroup_name (@master_hostgroup_names) {
+ my @host_master_hostgroup_hostnames = obj_get_hostnames_arr_by_hostgroup_name($cfg_obj_2x, $master_hostgroup_name);
+ push @all_master_hostgroup_hostnames, @host_master_hostgroup_hostnames;
+ }
+
+ #say Dumper($obj_1x_servicedependency);
+ #say " DEBUG: all master hg hostnames: ".Dumper(@all_master_hostgroup_hostnames);
+
+ # go through all child hostgroups and fetch their host objects, setting
+ foreach my $child_hostgroup_name (@child_hostgroup_names) {
+ my @host_child_hostgroup_hostnames = obj_get_hostnames_arr_by_hostgroup_name($cfg_obj_2x, $child_hostgroup_name); # child hostgroup members
+ #say " DEBUG: child hg hostnames: ".Dumper(@host_child_hostgroup_hostnames);
+
+ foreach my $host_child_hostgroup_hostname (@host_child_hostgroup_hostnames) {
+ my $child_service_obj = obj_get_service_obj_by_host_name_service_description($cfg_obj_2x, "__I2CONVERT_SERVICE_HOSTNAME", "__I2CONVERT_SERVICEDESCRIPTION", $host_child_hostgroup_hostname, $child_service_description);
+
+ # now loop through all master hostgroups and get their hosts
+ foreach my $master_hostgroup_name (@master_hostgroup_names) {
+ my @host_master_hostgroup_names = obj_get_hostnames_arr_by_hostgroup_name($cfg_obj_2x, $master_hostgroup_name); # master hostgroup members
+ foreach my $host_master_hostgroup_hostname (@host_master_hostgroup_names) {
+
+ # use some calculated unique key here (no, i will not split the string later! we are perl, we can do hashes)
+ my $master_key = $host_master_hostgroup_hostname."-".$master_service_description;
+ $child_service_obj->{'__I2CONVERT_PARENT_SERVICES'}->{$master_key}->{'host'} = $host_master_hostgroup_hostname; # XXX 5th foreach. awesome!
+ $child_service_obj->{'__I2CONVERT_PARENT_SERVICES'}->{$master_key}->{'service'} = $master_service_description;
+ }
+ }
+
+ }
+ }
+ }
+
+ # XXX ugly but works
+ SKIP_SVCDEPS:
+
+ ######################################
+ # ESCALATIONS - XXX handled differently
+ ######################################
+ #foreach my $hostescalation_obj_1x_key (keys %{@$cfg_obj_1x{'hostescalation'}}) {
+ #my $obj_1x_hostescalation = @$cfg_obj_1x{'hostescalation'}->{$hostescalation_obj_1x_key};
+ # clone it into our hash
+ # $cfg_obj_2x->{'hostescalation'}->{$hostescalation_obj_1x_key} = dclone(@$cfg_obj_1x{'hostescalation'}->{$hostescalation_obj_1x_key});
+ #}
+
+ if (!@$cfg_obj_1x{'serviceescalation'}) {
+ goto SKIP_SVCESCAL;
+ }
+ foreach my $serviceescalation_obj_1x_key (keys %{@$cfg_obj_1x{'serviceescalation'}}) {
+ my $obj_1x_serviceescalation = @$cfg_obj_1x{'serviceescalation'}->{$serviceescalation_obj_1x_key};
+ # clone it into our hash
+ $cfg_obj_2x->{'serviceescalation'}->{$serviceescalation_obj_1x_key} = dclone(@$cfg_obj_1x{'serviceescalation'}->{$serviceescalation_obj_1x_key});
+ }
+
+ SKIP_SVCESCAL:
+
+
+ ######################################
+ # SERVICE->HG<-HOSTMEMBERS MAGIC
+ # we've skipped services without
+ # host_name before, now deal with them
+ # hostgroups have been prepared with
+ # all their members too (!!)
+ # we're working on 2.x objects now
+ ######################################
+
+ # get the max key for hosts (required for adding more)
+ my $obj_2x_hosts_cnt = (reverse sort {$a <=> $b} (keys %{@$cfg_obj_2x{'host'}}))[0];
+ #print "FOO: $obj_2x_hosts_cnt\n";
+
+ my $obj_2x_services_hg = {};
+
+ # filter all services with a hostgroup_name into smaller list
+ foreach my $service_obj_2x_key (keys %{@$cfg_obj_2x{'service'}}) {
+
+ my $obj_2x_service = @$cfg_obj_2x{'service'}->{$service_obj_2x_key};
+
+ #print "DEBUG: now checking $obj_2x_service->{'service_description'}...\n";
+ # skip all services which already got a host_name? which one wins here? XXX
+
+ # skip all services without hostgroup_name
+ next if(!defined($obj_2x_service->{'hostgroup_name'}));
+
+ # XXX object tricks allow to use a comma seperated list of hostgroup_names!
+ # http://docs.icinga.org/latest/en/objecttricks.html
+ my @hostgroup_names = Icinga2::Utils::str2arr_by_delim_without_excludes($obj_2x_service->{'hostgroup_name'}, ',', 1);
+
+ foreach my $hostgroup_name (@hostgroup_names) {
+ # we need to save all services first, but our new key is the hostgroupname
+ # so that we can create multiple services for a single hosthg template later on
+ push @{$obj_2x_services_hg->{$hostgroup_name}}, $service_obj_2x_key;
+ }
+ }
+
+ # now loop over all hostgroups with service relations
+ foreach my $service_hg_obj_2x_key (keys %{$obj_2x_services_hg}) {
+
+ #say Dumper($obj_2x_services_hg);
+
+ # get the stored unique key to our services
+ my $hg_name = $service_hg_obj_2x_key;
+ my @service_keys = @{$obj_2x_services_hg->{$hg_name}};
+
+ #print "DEBUG: Looking for $hg_name ...\n";
+
+ my $obj_2x_hostgroup = obj_get_hostgroup_obj_by_hostgroup_name($cfg_obj_2x, $hg_name);
+
+ if(!defined($obj_2x_hostgroup)) {
+ # no hostgroup defined?
+ }
+
+ # we now need all host names for this hostgroup name, as an array
+
+ my @service_hostgroup_hostnames = obj_get_hostnames_arr_by_hostgroup_name($cfg_obj_2x, $hg_name);
+
+ if(@service_hostgroup_hostnames == 0) {
+ # no members, so service cannot be linked. log a warning XXX
+ #print " DEBUG: no members found, skipping $hg_name\n";
+ next;
+ }
+
+ # we've got:
+ # * n services linked to hostgroups,
+ # * a hostgroup
+ # * an array of hosts as hostgroup members
+ # we'll create:
+ # * n service templates,
+ # * a hg-host template referencing the service templates,
+ # * host objects inheriting from it
+ #
+ my $svc_count = 0;
+
+ # create a host template with hgname-group
+ my $obj_2x_host_template;
+ $obj_2x_host_template->{'__I2CONVERT_IS_TEMPLATE'} = 1;
+ $obj_2x_host_template->{'__I2CONVERT_TEMPLATE_NAME'} = $obj_2x_hostgroup->{'hostgroup_name'}."-group"; # XXX hardcode it for now
+
+ # loop through all services and attach them to the host template
+ foreach my $service_obj_2x_key_val (@service_keys) {
+
+ #print "DEBUG: Working on $service_obj_2x_key_val ...\n";
+ # get the service object by key
+ my $obj_2x_service = @$cfg_obj_2x{'service'}->{$service_obj_2x_key_val};
+
+ # set the service as template.
+ $obj_2x_service->{'__I2CONVERT_IS_TEMPLATE'} = 1;
+ $obj_2x_service->{'__I2CONVERT_TEMPLATE_NAME'} = $obj_2x_service->{'service_description'}."-group-".$svc_count; # XXX hardcode it for now
+
+ # create a dummy service inheriting the service template
+ my $obj_2x_service_inherit;
+ $obj_2x_service_inherit->{__I2CONVERT_USES_TEMPLATE} = 1;
+ push @{$obj_2x_service_inherit->{'__I2CONVERT_TEMPLATE_NAMES'}}, $obj_2x_service->{'__I2CONVERT_TEMPLATE_NAME'};
+ $obj_2x_service_inherit->{'service_description'} = $obj_2x_service->{'service_description'};
+ $obj_2x_service_inherit->{'__I2CONVERT_SERVICEDESCRIPTION'} = $obj_2x_service->{'service_description'};
+
+ # link the service inherit to the host template
+ $obj_2x_host_template->{'SERVICE'}->{$svc_count} = $obj_2x_service_inherit;
+
+ $svc_count++;
+ }
+
+ # all host objects on the hostgroup members will get the host hg template name pushed into their array
+ foreach my $hostgroup_member_host_name (@service_hostgroup_hostnames) {
+ # get the host obj
+ my $obj_2x_host = obj_get_host_obj_by_host_name($cfg_obj_2x, $hostgroup_member_host_name); # this is a reference in memory, not a copy!
+
+ # push the template used
+ # (override __I2CONVERT_USES_TEMPLATE too)
+ $obj_2x_host->{__I2CONVERT_USES_TEMPLATE} = 1;
+ push @{$obj_2x_host->{'__I2CONVERT_TEMPLATE_NAMES'}}, $obj_2x_host_template->{'__I2CONVERT_TEMPLATE_NAME'};
+
+ }
+
+ # push back the newly created host template (incl the service inherit below SERVICE) to the objects 2.x hive
+ #say Dumper($obj_2x_host_template);
+
+ $obj_2x_hosts_cnt++;
+ #print "adding new host at key " . $obj_2x_hosts_cnt . "\n";
+ $cfg_obj_2x->{'host'}->{$obj_2x_hosts_cnt} = $obj_2x_host_template;
+
+ }
+
+ ######################################
+ # NEW: NOTIFICATION MAPPING
+ # old: contact->notification_commands->commands
+ # contact->email/etc
+ # host/service -> contact
+ # new: notification->notification_command
+ # user->mail/etc
+ # host/service->notifications[type]->notification_templates,users
+ ######################################
+ my $notification_obj_cnt = 0;
+ my $obj_notification_cnt = 0;
+ # add a dummy value so that we can check against it
+ $cfg_obj_2x->{'notification'}->{$notification_obj_cnt}->{'__I2CONVERT_NOTIFICATION_NAME'} = '__I2CONVERT_NOTIFICATION_DUMMY';
+
+ # go through all users and build notifications based on the notification_command
+ foreach my $user_obj_2x_key (keys %{@$cfg_obj_2x{'user'}}) {
+
+ my $obj_2x_user = @$cfg_obj_2x{'user'}->{$user_obj_2x_key};
+
+ my $user_notification;
+ ####################################################
+ # get all notification_commands, and create new notification templates
+ ####################################################
+ my $notification_commands = $obj_2x_user->{'__I2CONVERT_NOTIFICATION_COMMANDS'};
+ #say Dumper($notification_commands);
+
+ foreach my $notification_command_type (keys %{$notification_commands}) {
+ foreach my $notification_command_name (keys %{$notification_commands->{$notification_command_type}}) {
+ my $notification_command_line = $notification_commands->{$notification_command_type}->{$notification_command_name};
+ #print "type: $notification_command_type name: $notification_command_name line: $notification_command_line\n";
+
+ my $notification_command_name_2x = $notification_command_type."-".$notification_command_name;
+
+ my $notification_name_2x = $notification_command_name_2x.$obj_notification_cnt;
+ $obj_notification_cnt++;
+
+ # save a relation to this user and which notification templates are now linked ( ["name"] = { templates = "template" } )
+ # we'll use that later on when processing hosts/services and linking to users and notifications
+ $user_notification->{$notification_name_2x}->{'name'} = $notification_name_2x;
+
+ push @{$user_notification->{$notification_name_2x}->{'templates'}}, $notification_command_name_2x;
+ push @{$user_notification->{$notification_name_2x}->{'users'}}, $obj_2x_user->{'user_name'};
+
+ # save the type for later objects (host or service)
+ $user_notification->{$notification_name_2x}->{'type'} = $notification_command_type;
+
+ # XXX do not add duplicate notifications, they must remain unique by their notification_command origin!
+ next if (obj_2x_notification_exists($cfg_obj_2x, $notification_command_name_2x) == 1);
+
+ # create a new NotificationCommand 2x object with the original name
+ $cfg_obj_2x->{'command'}->{$command_obj_cnt}->{'__I2CONVERT_COMMAND_TYPE'} = 'Notification';
+ $cfg_obj_2x->{'command'}->{$command_obj_cnt}->{'__I2CONVERT_COMMAND_NAME'} = $notification_command_name;
+ $cfg_obj_2x->{'command'}->{$command_obj_cnt}->{'__I2CONVERT_COMMAND_LINE'} = $notification_command_line;
+
+ # use the ITL plugin notification command template
+ if(defined($icinga2_cfg->{'itl'}->{'notificationcommand-template'}) && $icinga2_cfg->{'itl'}->{'notificationcommand-template'} ne "") {
+ push @{$cfg_obj_2x->{'command'}->{$command_obj_cnt}->{'__I2CONVERT_TEMPLATE_NAMES'}}, $icinga2_cfg->{'itl'}->{'notificationcommand-template'};
+ $cfg_obj_2x->{'command'}->{$command_obj_cnt}->{'__I2CONVERT_USES_TEMPLATE'} = 1;
+ }
+
+ # the check command name of 1.x is still the unique command object name, so we just keep it
+ # in __I2CONVERT_NOTIFICATION_COMMAND
+
+ # our global PK
+ $command_obj_cnt++;
+
+ # create a new notification template object
+ $cfg_obj_2x->{'notification'}->{$notification_obj_cnt}->{'__I2CONVERT_NOTIFICATION_TEMPLATE_NAME'} = $notification_command_name_2x;
+ $cfg_obj_2x->{'notification'}->{$notification_obj_cnt}->{'__I2CONVERT_NOTIFICATION_COMMAND'} = $notification_command_name;
+ $cfg_obj_2x->{'notification'}->{$notification_obj_cnt}->{'__I2CONVERT_IS_TEMPLATE'} = 1; # this is a template, used in hosts/services then
+
+ # add dependency to ITL template to objects
+ if(defined($icinga2_cfg->{'itl'}->{'notification-template'}) && $icinga2_cfg->{'itl'}->{'notification-template'} ne "") {
+ @{$cfg_obj_2x->{'notification'}->{$notification_obj_cnt}->{'__I2CONVERT_TEMPLATE_NAMES'}} = ();
+ push @{$cfg_obj_2x->{'notification'}->{$notification_obj_cnt}->{'__I2CONVERT_TEMPLATE_NAMES'}}, $icinga2_cfg->{'itl'}->{'notification-template'};
+ $cfg_obj_2x->{'notification'}->{$notification_obj_cnt}->{'__I2CONVERT_USES_TEMPLATE'} = 1; # we now use a template, otherwise it won't be dumped
+ }
+
+ $notification_obj_cnt++;
+ }
+ }
+ $cfg_obj_2x->{'user'}->{$user_obj_2x_key}->{'__I2CONVERT_NOTIFICATIONS'} = $user_notification;
+
+ #say Dumper($cfg_obj_2x->{'user'}->{$user_obj_2x_key});
+ }
+
+ # go through all hosts/services, and add notifications based on the users
+ # XXX hosts - do we notify on hosts?
+ foreach my $host_obj_2x_key (keys %{@$cfg_obj_2x{'host'}}) {
+
+ my $obj_2x_host = @$cfg_obj_2x{'host'}->{$host_obj_2x_key};
+ # make sure there are none
+ delete($cfg_obj_2x->{'host'}->{$host_obj_2x_key}->{'__I2CONVERT_NOTIFICATIONS'});
+ @{$cfg_obj_2x->{'host'}->{$host_obj_2x_key}->{'__I2CONVERT_NOTIFICATIONS'}} = ();
+
+ # convert users and usergroupmembers into a unique list of users
+ my @users = Icinga2::Utils::str2arr_by_delim_without_excludes($obj_2x_host->{'contacts'}, ',', 1);
+ my @usergroups = Icinga2::Utils::str2arr_by_delim_without_excludes($obj_2x_host->{'contacts'}, ',', 1);
+
+ # get all members of the usergroups
+ foreach my $usergroup (@usergroups) {
+ my @users_ug = obj_get_usernames_arr_by_usergroup_name($cfg_obj_2x, $usergroup);
+ push @users, @users_ug;
+ }
+ # create a unique array of users (XXX important! XXX)
+ my @uniq_users = Icinga2::Utils::uniq(@users);
+
+ # now loop and fetch objects, and their needed notification values as array
+ # (prepared above - look for $user_notification->{$notification_command_name_2x}...)
+ foreach my $uniq_user (@uniq_users) {
+ my $obj_2x_user = obj_get_user_obj_by_user_name($cfg_obj_2x, $uniq_user);
+ push @{$cfg_obj_2x->{'host'}->{$host_obj_2x_key}->{'__I2CONVERT_NOTIFICATIONS'}}, $obj_2x_user->{'__I2CONVERT_NOTIFICATIONS'};
+ # we'll add a reference to all notifications here. decide on dump which object type is given, and dump only those notifications!
+ }
+ #say Dumper($obj_2x_service);
+
+ }
+
+ # XXX services
+ foreach my $service_obj_2x_key (keys %{@$cfg_obj_2x{'service'}}) {
+
+ my $obj_2x_service = @$cfg_obj_2x{'service'}->{$service_obj_2x_key};
+ # make sure there are none
+ delete($cfg_obj_2x->{'service'}->{$service_obj_2x_key}->{'__I2CONVERT_NOTIFICATIONS'});
+ @{$cfg_obj_2x->{'service'}->{$service_obj_2x_key}->{'__I2CONVERT_NOTIFICATIONS'}} = ();
+
+ # convert users and usergroupmembers into a unique list of users
+ my @users = Icinga2::Utils::str2arr_by_delim_without_excludes($obj_2x_service->{'contacts'}, ',', 1);
+ my @usergroups = Icinga2::Utils::str2arr_by_delim_without_excludes($obj_2x_service->{'contacts'}, ',', 1);
+
+ # get all members of the usergroups
+ foreach my $usergroup (@usergroups) {
+ my @users_ug = obj_get_usernames_arr_by_usergroup_name($cfg_obj_2x, $usergroup);
+ push @users, @users_ug;
+ }
+ # create a unique array of users (XXX important! XXX)
+ my @uniq_users = Icinga2::Utils::uniq(@users);
+
+ # now loop and fetch objects, and their needed notification values as array
+ # (prepared above - look for $user_notification->{$notification_command_name_2x}...)
+ foreach my $uniq_user (@uniq_users) {
+ my $obj_2x_user = obj_get_user_obj_by_user_name($cfg_obj_2x, $uniq_user);
+ push @{$cfg_obj_2x->{'service'}->{$service_obj_2x_key}->{'__I2CONVERT_NOTIFICATIONS'}}, $obj_2x_user->{'__I2CONVERT_NOTIFICATIONS'};
+ # we'll add a reference to all notifications here. decide on dump which object type is given, and dump only those notifications!
+ }
+ #say Dumper($obj_2x_service);
+
+ }
+ #exit(0);
+
+ ######################################
+ # HOST->SERVICE MAGIC
+ # we need to do it _after_ we've
+ # manipulated all service objects!
+ ######################################
+
+ # "get all 'host' hashref as array in hashmap, and their keys to access it"
+ foreach my $host_obj_2x_key (keys %{@$cfg_obj_2x{'host'}}) {
+
+ #say Dumper(@$cfg_obj_2x{'host'}->{$host_obj_2x_key});
+ my $obj_2x_host = @$cfg_obj_2x{'host'}->{$host_obj_2x_key};
+
+ ####################################################
+ # Create Host->Service Relation for later dumping
+ # we use the prep'ed 2x service hashref already
+ # all attributes _must_have been resolved already!
+ ####################################################
+ my $obj_2x_host_service_cnt = 0;
+
+ # find all services for this host
+ foreach my $service_obj_2x_key (keys %{@$cfg_obj_2x{'service'}}) {
+
+ my $obj_2x_service = @$cfg_obj_2x{'service'}->{$service_obj_2x_key};
+
+ ######################################
+ # get host_name/service_desc for obj
+ # (prepared in service loop already)
+ ######################################
+ my $obj_2x_service_host_name = $obj_2x_service->{'__I2CONVERT_SERVICE_HOSTNAME'};
+ my $obj_2x_service_service_description = $obj_2x_service->{'__I2CONVERT_SERVICEDESCRIPTION'};
+
+ ######################################
+ # skip service templates
+ ######################################
+ if ($obj_2x_service->{'__I2CONVERT_IS_TEMPLATE'} == 1) {
+ #Icinga2::Utils::debug("WARNING: Skipping service template '$obj_2x_service->{'__I2CONVERT_TEMPLATE_NAMES'}' for linking to host '$obj_2x_host->{'__I2CONVERT_HOSTNAME'}'.");
+ next;
+ }
+
+ # save it for later
+ # XXX if host_name can't be located in the service template tree, check if hostgroup is set somewhere
+ # we then need to check if the service -> hostgroup <- hostmember applies (ugly) FIXME
+
+ # XXX if host_name can't be determined, log an error XXX templates MUST be skipped before (they cannot look down, only up in use tree)
+ if (!defined($obj_2x_service_host_name)) {
+ #print "ERROR: No host_name for service given " . Dumper($obj_2x_service);
+ next;
+ }
+
+ ######################################
+ # found a host->service relation?
+ ######################################
+ if ($obj_2x_service_host_name eq $obj_2x_host->{'__I2CONVERT_HOSTNAME'}) {
+ #debug("service_description: $obj_2x_service_service_description host_name: $obj_2x_service_host_name");
+
+ # 1. generate template name "host-service"
+ my $service_template_name = $obj_2x_service_host_name."-".$obj_2x_service_service_description;
+
+ # 2. make the service object a template with a special unique name
+ $cfg_obj_2x->{'service'}->{$service_obj_2x_key}->{'__I2CONVERT_IS_TEMPLATE'} = 1;
+ $cfg_obj_2x->{'service'}->{$service_obj_2x_key}->{'__I2CONVERT_TEMPLATE_NAME'} = $service_template_name;
+
+ # 3. use the template name as reference for the host->service
+ $cfg_obj_2x->{'host'}->{$host_obj_2x_key}->{'SERVICE'}->{$obj_2x_host_service_cnt}->{'__I2CONVERT_USES_TEMPLATE'} = 1;
+ push @{$cfg_obj_2x->{'host'}->{$host_obj_2x_key}->{'SERVICE'}->{$obj_2x_host_service_cnt}->{'__I2CONVERT_TEMPLATE_NAMES'}}, $service_template_name;
+
+ # 4. define the service description for the service
+ $cfg_obj_2x->{'host'}->{$host_obj_2x_key}->{'SERVICE'}->{$obj_2x_host_service_cnt}->{'__I2CONVERT_SERVICEDESCRIPTION'} = $obj_2x_service_service_description;
+
+ ######################################
+ # LINK HOST COMMAND WITH SERVICE CHECK
+ ######################################
+ my $service_check_command_2x = Icinga2::Convert::convert_checkcommand(@$cfg_obj_1x{'command'}, $obj_2x_service, $user_macros_1x);
+
+ # check if this service check is a possible match for __I2CONVERT_HOST_CHECK?
+ if (defined($service_check_command_2x->{'check_command_name_1x'})) {
+ if ($cfg_obj_2x->{'host'}->{$host_obj_2x_key}->{'__I2CONVERT_HOSTCHECK_NAME'} eq $service_check_command_2x->{'check_command_name_1x'}) {
+ # set service as hostcheck
+ $cfg_obj_2x->{'host'}->{$host_obj_2x_key}->{'__I2CONVERT_HOSTCHECK'} = $obj_2x_service_service_description;
+ }
+ }
+
+ # primary key
+ $obj_2x_host_service_cnt++;
+ }
+ else {
+ # no match
+ #say "ERROR: No Match with ". Dumper($obj_1x_host);
+ }
+ }
+ }
+
+ ############################################################################
+ ############################################################################
+ # export takes place outside again
+
+ return $cfg_obj_2x;
+}
+
+
+
+1;
+
+__END__
+# vi: sw=4 ts=4 expandtab :
--- /dev/null
+
+=pod
+/******************************************************************************
+ * Icinga 2 *
+ * Copyright (C) 2012 Icinga Development Team (http://www.icinga.org/) *
+ * *
+ * This program is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU General Public License *
+ * as published by the Free Software Foundation; either version 2 *
+ * of the License, or (at your option) any later version. *
+ * *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ******************************************************************************/
+=cut
+
+
+package Icinga2::ExportIcinga2Cfg;
+
+use strict;
+
+use Data::Dumper;
+use File::Find;
+use Storable qw(dclone);
+
+use feature 'say';
+
+#use Icinga2;
+use Icinga2::Utils;
+
+#our $dbg_lvl = 1;
+
+# XXX figure a better way for \t count printing, making dumps more modular
+# XXX sort macros and linked hostservices by name
+
+################################################################################
+# Helpers
+################################################################################
+
+sub open_cfg_file {
+ my $file = shift;
+ my $FH;
+
+ say "opening file '$file'...\n";
+ open($FH, ">".$file);
+
+ return $FH;
+}
+
+sub close_cfg_file {
+ my $FH = shift;
+
+ close($FH);
+}
+
+sub add_header {
+ my $icinga2_cfg = shift;
+
+ dump_config_line($icinga2_cfg, "/******************************************************************************");
+ dump_config_line($icinga2_cfg, " * GENERATED BY ICINGA2 CONVERSION SCRIPT");
+ dump_config_line($icinga2_cfg, " * (C) 2013 Icinga Development Team");
+ dump_config_line($icinga2_cfg, " * http://www.icinga.org");
+ dump_config_line($icinga2_cfg, " ******************************************************************************/");
+}
+
+sub dump_config_line {
+ my $icinga2_cfg = shift;
+ my $line = shift;
+ my $dbg_lvl = $icinga2_cfg->{'__I2EXPORT_DEBUG'};
+
+ if ($dbg_lvl) {
+ print $line. "\n";
+ }
+
+ print { $icinga2_cfg->{'__I2EXPORT_FH'} } "$line\n";
+}
+
+sub start_object_type_config_dump {
+ my $icinga2_cfg = shift;
+ my $cfg_type = shift;
+
+ $icinga2_cfg->{'__I2EXPORT_FH'} = open_cfg_file($icinga2_cfg->{$cfg_type});
+ add_header($icinga2_cfg);
+}
+
+sub end_object_type_config_dump {
+ my $icinga2_cfg = shift;
+
+ close_cfg_file($icinga2_cfg->{'__I2EXPORT_FH'});
+}
+
+################################################################################
+# DUMP ALL OBJECTS 2.x
+################################################################################
+
+
+sub dump_cfg_obj_2x {
+ my $icinga2_cfg = shift;
+ my $cfg_obj_2x = shift;
+
+ dump_hosts_2x($icinga2_cfg, $cfg_obj_2x);
+ dump_services_2x($icinga2_cfg, $cfg_obj_2x);
+ dump_users_2x($icinga2_cfg, $cfg_obj_2x);
+ dump_notifications_2x($icinga2_cfg, $cfg_obj_2x);
+ dump_timeperiods_2x($icinga2_cfg, $cfg_obj_2x);
+ dump_groups_2x($icinga2_cfg, $cfg_obj_2x);
+ dump_commands_2x($icinga2_cfg, $cfg_obj_2x);
+
+}
+sub dump_hosts_2x {
+ my $icinga2_cfg = shift;
+ my $cfg_obj_2x = shift;
+
+ start_object_type_config_dump($icinga2_cfg, 'hosts');
+ #say Dumper($icinga2_cfg);
+
+ foreach my $host_2x_key (keys %{@$cfg_obj_2x{'host'}}) {
+ my $host_2x = @$cfg_obj_2x{'host'}->{$host_2x_key};
+ #say Dumper($host_2x);
+ #say "==============\n";
+ # function decides itsself if object or template
+ Icinga2::ExportIcinga2Cfg::dump_host_2x($icinga2_cfg, $host_2x);
+ }
+
+ end_object_type_config_dump($icinga2_cfg);
+}
+
+sub dump_services_2x {
+ my $icinga2_cfg = shift;
+ my $cfg_obj_2x = shift;
+
+ start_object_type_config_dump($icinga2_cfg, 'services');
+
+ foreach my $service_2x_key (keys %{@$cfg_obj_2x{'service'}}) {
+ my $service_2x = @$cfg_obj_2x{'service'}->{$service_2x_key};
+
+ Icinga2::ExportIcinga2Cfg::dump_service_2x($icinga2_cfg, $service_2x);
+ }
+
+ end_object_type_config_dump($icinga2_cfg);
+}
+
+sub dump_users_2x {
+ my $icinga2_cfg = shift;
+ my $cfg_obj_2x = shift;
+
+ start_object_type_config_dump($icinga2_cfg, 'users');
+
+ foreach my $user_2x_key (keys %{@$cfg_obj_2x{'user'}}) {
+ my $user_2x = @$cfg_obj_2x{'user'}->{$user_2x_key};
+
+ Icinga2::ExportIcinga2Cfg::dump_user_2x($icinga2_cfg, $user_2x);
+ }
+
+ end_object_type_config_dump($icinga2_cfg);
+}
+
+sub dump_notifications_2x {
+ my $icinga2_cfg = shift;
+ my $cfg_obj_2x = shift;
+
+ start_object_type_config_dump($icinga2_cfg, 'notifications');
+
+ foreach my $notification_2x_key (keys %{@$cfg_obj_2x{'notification'}}) {
+ my $notification_2x = @$cfg_obj_2x{'notification'}->{$notification_2x_key};
+
+ Icinga2::ExportIcinga2Cfg::dump_notification_2x($icinga2_cfg, $notification_2x);
+ }
+
+ end_object_type_config_dump($icinga2_cfg);
+}
+
+
+sub dump_timeperiods_2x {
+ my $icinga2_cfg = shift;
+ my $cfg_obj_2x = shift;
+
+ start_object_type_config_dump($icinga2_cfg, 'timeperiods');
+
+ foreach my $timeperiod_2x_key (keys %{@$cfg_obj_2x{'timeperiod'}}) {
+ my $timeperiod_2x = @$cfg_obj_2x{'timeperiod'}->{$timeperiod_2x_key};
+
+ Icinga2::ExportIcinga2Cfg::dump_timeperiod_2x($icinga2_cfg, $timeperiod_2x);
+ }
+
+ end_object_type_config_dump($icinga2_cfg);
+}
+
+# XXX maybe split later
+sub dump_groups_2x {
+ my $icinga2_cfg = shift;
+ my $cfg_obj_2x = shift;
+
+ start_object_type_config_dump($icinga2_cfg, 'groups');
+
+ foreach my $hostgroup_2x_key (keys %{@$cfg_obj_2x{'hostgroup'}}) {
+ my $hostgroup_2x = @$cfg_obj_2x{'hostgroup'}->{$hostgroup_2x_key};
+
+ Icinga2::ExportIcinga2Cfg::dump_group_2x($icinga2_cfg, $hostgroup_2x);
+ }
+
+ foreach my $servicegroup_2x_key (keys %{@$cfg_obj_2x{'servicegroup'}}) {
+ my $servicegroup_2x = @$cfg_obj_2x{'servicegroup'}->{$servicegroup_2x_key};
+
+ Icinga2::ExportIcinga2Cfg::dump_group_2x($icinga2_cfg, $servicegroup_2x);
+ }
+
+ foreach my $usergroup_2x_key (keys %{@$cfg_obj_2x{'usergroup'}}) {
+ my $usergroup_2x = @$cfg_obj_2x{'usergroup'}->{$usergroup_2x_key};
+
+ Icinga2::ExportIcinga2Cfg::dump_group_2x($icinga2_cfg, $usergroup_2x);
+ }
+
+ end_object_type_config_dump($icinga2_cfg);
+}
+
+sub dump_commands_2x {
+ my $icinga2_cfg = shift;
+ my $cfg_obj_2x = shift;
+
+ start_object_type_config_dump($icinga2_cfg, 'commands');
+
+ foreach my $command_2x_key (keys %{@$cfg_obj_2x{'command'}}) {
+ my $command_2x = @$cfg_obj_2x{'command'}->{$command_2x_key};
+
+ Icinga2::ExportIcinga2Cfg::dump_command_2x($icinga2_cfg, $command_2x);
+ }
+
+ end_object_type_config_dump($icinga2_cfg);
+}
+
+################################################################################
+# DUMP OBJECT 2.x
+################################################################################
+
+
+sub dump_service_2x {
+ my $icinga2_cfg = shift;
+ my $service_2x = shift;
+ my $object_type = "object"; # object or template
+ my $service_description = $service_2x->{__I2CONVERT_SERVICEDESCRIPTION};
+
+ # only dump templates, the objects will be directly created in host objects
+ if ($service_2x->{__I2CONVERT_IS_TEMPLATE} == 0) {
+ return;
+ }
+ #say Dumper($host_2x);
+ if ($service_2x->{__I2CONVERT_IS_TEMPLATE} == 1) {
+ $object_type = "template";
+ $service_description = $service_2x->{'__I2CONVERT_TEMPLATE_NAME'};
+ }
+
+ ####################################################
+ # start, inherit from template?
+ ####################################################
+ if (defined($service_2x->{'__I2CONVERT_USES_TEMPLATE'}) && $service_2x->{'__I2CONVERT_USES_TEMPLATE'} == 1) {
+ my $service_2x_templates = join '", "', @{$service_2x->{'__I2CONVERT_TEMPLATE_NAMES'}};
+ dump_config_line($icinga2_cfg, "$object_type Service \"$service_description\" inherits \"$service_2x_templates\" {");
+ } else {
+ dump_config_line($icinga2_cfg, "$object_type Service \"$service_description\" {");
+ }
+
+ ####################################################
+ # display_name
+ ####################################################
+ if(defined($service_2x->{'display_name'})) {
+ dump_config_line($icinga2_cfg, "\tdisplay_name = \"$service_2x->{'display_name'}\",");
+ }
+
+ ####################################################
+ # macros
+ ####################################################
+
+ if(defined($service_2x->{'command_macros'}) && $service_2x->{'command_macros'} != 0) {
+ dump_config_line($icinga2_cfg, "\tmacros = {");
+ foreach my $cmd_arg (keys %{$service_2x->{'command_macros'}}) {
+ dump_config_line($icinga2_cfg, "\t\t$cmd_arg = \"$service_2x->{'command_macros'}->{$cmd_arg}\",");
+ }
+ dump_config_line($icinga2_cfg, "\t},");
+ }
+
+ dump_config_line($icinga2_cfg, "");
+
+ ####################################################
+ # check command
+ ####################################################
+ if(defined($service_2x->{'__I2_CONVERT_CHECKCOMMAND_NAME'})) {
+ dump_config_line($icinga2_cfg, "\tcheck_command = \"$service_2x->{'__I2_CONVERT_CHECKCOMMAND_NAME'}\",");
+ }
+
+ ####################################################
+ # event command
+ ####################################################
+ if(defined($service_2x->{'__I2_CONVERT_EVENTCOMMAND_NAME'})) {
+ dump_config_line($icinga2_cfg, "\tevent_command = \"$service_2x->{'__I2_CONVERT_EVENTCOMMAND_NAME'}\",");
+ }
+
+ ####################################################
+ # servicegroups
+ ####################################################
+ if(defined($service_2x->{'servicegroups'})) {
+ my $servicegroups = join '", "', @{$service_2x->{'servicegroups'}};
+ if ($service_2x->{'__I2_CONVERT_SG_ADD'} == 1) {
+ dump_config_line($icinga2_cfg, "\tservicegroups += [ \"$servicegroups\" ],");
+ } else {
+ dump_config_line($icinga2_cfg, "\tservicegroups = [ \"$servicegroups\" ],");
+ }
+ }
+
+ ####################################################
+ # servicedependencies (1.x deps)
+ ####################################################
+ if(defined($service_2x->{'__I2CONVERT_PARENT_SERVICES'})) {
+ dump_config_line($icinga2_cfg, "\tservicedependencies = [");
+
+ #say Dumper($service_2x);
+ # this is a hash with keys
+ foreach my $servicedep_key (keys %{$service_2x->{'__I2CONVERT_PARENT_SERVICES'}}) {
+ my $servicedep = $service_2x->{'__I2CONVERT_PARENT_SERVICES'}->{$servicedep_key};
+ dump_config_line($icinga2_cfg, "\t\t{ host = \"$servicedep->{'host'}\", service = \"$servicedep->{'service'}\" },");
+ }
+ dump_config_line($icinga2_cfg, "\t],");
+ }
+
+ ####################################################
+ # notifications
+ ####################################################
+ if(defined($service_2x->{'__I2CONVERT_NOTIFICATIONS'})) {
+ #say Dumper ($service_2x->{'__I2CONVERT_NOTIFICATIONS'});
+ # this is an array of notification objects
+ foreach my $service_notification_hash (@{$service_2x->{'__I2CONVERT_NOTIFICATIONS'}}) {
+
+ #say Dumper($service_notification_hash);
+
+ # this is a hash by unique key of the notification template, but all further attributes are seperatedly available too
+ foreach my $service_notification_key (keys %{$service_notification_hash}) {
+ my $service_notification = $service_notification_hash->{$service_notification_key};
+ #say Dumper($service_notification);
+
+ # skip everything not related to service notifications
+ next if ($service_notification->{'type'} ne 'service');
+
+ dump_config_line($icinga2_cfg, "\t\tnotifications[\"$service_notification->{'name'}\"] = {");
+
+ if (defined ($service_notification->{'templates'}) && @{$service_notification->{'templates'}} > 0) {
+ my $service_notification_templates = join '", "', @{$service_notification->{'templates'}};
+ dump_config_line($icinga2_cfg, "\t\t\ttemplates = [ \"$service_notification_templates\" ],");
+ }
+
+ if(defined($service_notification->{'users'}) && @{$service_notification->{'users'}} > 0) {
+ my $service_users = join '", "', @{$service_notification->{'users'}};
+ dump_config_line($icinga2_cfg, "\t\t\tusers = [ \"$service_users\" ],");
+ }
+
+ dump_config_line($icinga2_cfg, "\t\t},");
+ }
+ }
+ }
+
+ if(defined($service_2x->{'notification_period'})) {
+ dump_config_line($icinga2_cfg, "\tnotification_period = \"$service_2x->{'notification_period'}\",");
+ }
+ if(defined($service_2x->{'notification_interval'})) {
+ dump_config_line($icinga2_cfg, "\tnotification_interval = $service_2x->{'notification_interval'},");
+ }
+
+ ####################################################
+ # other service attributes, if set
+ ####################################################
+ if(defined($service_2x->{'check_interval'})) {
+ dump_config_line($icinga2_cfg, "\tcheck_interval = $service_2x->{'check_interval'},");
+ }
+ if(defined($service_2x->{'retry_interval'})) {
+ dump_config_line($icinga2_cfg, "\tretry_interval = $service_2x->{'retry_interval'},");
+ }
+ if(defined($service_2x->{'max_check_attempts'})) {
+ dump_config_line($icinga2_cfg, "\tmax_check_attempts = $service_2x->{'max_check_attempts'},");
+ }
+
+ if(defined($service_2x->{'check_period'})) {
+ dump_config_line($icinga2_cfg, "\tcheck_period = \"$service_2x->{'check_period'}\",");
+ }
+
+ if(defined($service_2x->{'action_url'})) {
+ dump_config_line($icinga2_cfg, "\taction_url = \"$service_2x->{'action_url'}\",");
+ }
+
+ if(defined($service_2x->{'notes_url'})) {
+ dump_config_line($icinga2_cfg, "\tnotes_url = \"$service_2x->{'notes_url'}\",");
+ }
+
+ if(defined($service_2x->{'notes'})) {
+ dump_config_line($icinga2_cfg, "\tnotes = \"$service_2x->{'notes'}\",");
+ }
+
+ if(defined($service_2x->{'icon_image'})) {
+ dump_config_line($icinga2_cfg, "\ticon_image = \"$service_2x->{'icon_image'}\",");
+ }
+
+ if(defined($service_2x->{'volatile'})) {
+ dump_config_line($icinga2_cfg, "\tvolatile = $service_2x->{'volatile'},");
+ }
+
+
+ dump_config_line($icinga2_cfg, "}");
+ dump_config_line($icinga2_cfg, "\n");
+}
+
+sub dump_host_2x {
+ my $icinga2_cfg = shift;
+ my $host_2x = shift;
+ my $object_type = "object"; # object or template
+ my $host_name = $host_2x->{'host_name'}; # default, may be changed for templates
+
+ #say Dumper($host_2x);
+ if ($host_2x->{__I2CONVERT_IS_TEMPLATE} == 1) {
+ $object_type = "template";
+ $host_name = $host_2x->{'__I2CONVERT_TEMPLATE_NAME'};
+ }
+
+ ####################################################
+ # start, inherit from template?
+ ####################################################
+ if (defined($host_2x->{'__I2CONVERT_USES_TEMPLATE'}) && $host_2x->{'__I2CONVERT_USES_TEMPLATE'} == 1) {
+ my $host_2x_templates = join '", "', @{$host_2x->{'__I2CONVERT_TEMPLATE_NAMES'}};
+ dump_config_line($icinga2_cfg, "$object_type Host \"$host_name\" inherits \"$host_2x_templates\" {");
+ } else {
+ dump_config_line($icinga2_cfg, "$object_type Host \"$host_name\" {");
+ }
+
+ ####################################################
+ # display_name
+ ####################################################
+ if(defined($host_2x->{'display_name'})) {
+ dump_config_line($icinga2_cfg, "\tdisplay_name = \"$host_2x->{'display_name'}\",");
+ }
+
+ ####################################################
+ # macros
+ ####################################################
+ if(defined($host_2x->{'address'})) {
+ dump_config_line($icinga2_cfg, "\tmacros = {");
+ dump_config_line($icinga2_cfg, "\t\taddress = \"$host_2x->{'address'}\",");
+ dump_config_line($icinga2_cfg, "\t},");
+ }
+ dump_config_line($icinga2_cfg, "");
+
+ ####################################################
+ # hostcheck
+ ####################################################
+ # this is magic, and must be set during conversion
+ if(defined($host_2x->{'__I2CONVERT_HOSTCHECK'})) {
+ dump_config_line($icinga2_cfg, "\thostcheck = \"$host_2x->{'__I2CONVERT_HOSTCHECK'}\",");
+ }
+
+ ####################################################
+ # hostgroups
+ ####################################################
+ if(defined($host_2x->{'hostgroups'})) {
+ my $hostgroups = join '", "', @{$host_2x->{'hostgroups'}};
+ if ($host_2x->{'__I2_CONVERT_HG_ADD'} == 1) {
+ dump_config_line($icinga2_cfg, "\thostgroups += [ \"$hostgroups\" ],");
+ } else {
+ dump_config_line($icinga2_cfg, "\thostgroups = [ \"$hostgroups\" ],");
+ }
+ }
+
+ ####################################################
+ # hostdependencies (1.x deps and parents combined)
+ ####################################################
+ if(defined($host_2x->{'__I2CONVERT_PARENT_HOSTNAMES'})) {
+ my $hostdependency_hosts = join '", "', @{$host_2x->{'__I2CONVERT_PARENT_HOSTNAMES'}};
+ dump_config_line($icinga2_cfg, "\thostdependencies = [ \"$hostdependency_hosts\" ],");
+ }
+
+ ####################################################
+ # notifications
+ ####################################################
+ if(defined($host_2x->{'__I2CONVERT_NOTIFICATIONS'})) {
+ #say Dumper ($host_2x->{'__I2CONVERT_NOTIFICATIONS'});
+ # this is an array of notification objects
+ foreach my $host_notification_hash (@{$host_2x->{'__I2CONVERT_NOTIFICATIONS'}}) {
+
+ #say Dumper($host_notification_hash);
+
+ # this is a hash by unique key of the notification template, but all further attributes are seperatedly available too
+ foreach my $host_notification_key (keys %{$host_notification_hash}) {
+ my $host_notification = $host_notification_hash->{$host_notification_key};
+ #say Dumper($host_notification);
+
+ # skip everything not related to host notifications
+ next if ($host_notification->{'type'} ne 'host');
+
+ dump_config_line($icinga2_cfg, "\t\tnotifications[\"$host_notification->{'name'}\"] = {");
+
+ if (defined ($host_notification->{'templates'}) && @{$host_notification->{'templates'}} > 0) {
+ my $host_notification_templates = join '", "', @{$host_notification->{'templates'}};
+ dump_config_line($icinga2_cfg, "\t\t\ttemplates = [ \"$host_notification_templates\" ],");
+ }
+
+ if(defined($host_notification->{'users'}) && @{$host_notification->{'users'}} > 0) {
+ my $host_users = join '", "', @{$host_notification->{'users'}};
+ dump_config_line($icinga2_cfg, "\t\t\tusers = [ \"$host_users\" ],");
+ }
+
+ dump_config_line($icinga2_cfg, "\t\t},");
+ }
+ }
+ }
+
+
+ if(defined($host_2x->{'notification_period'})) {
+ dump_config_line($icinga2_cfg, "\tnotification_period = \"$host_2x->{'notification_period'}\",");
+ }
+ if(defined($host_2x->{'notification_interval'})) {
+ dump_config_line($icinga2_cfg, "\tnotification_interval = $host_2x->{'notification_interval'},");
+ }
+
+ ####################################################
+ # other host attributes, if set
+ ####################################################
+ if(defined($host_2x->{'check_interval'})) {
+ dump_config_line($icinga2_cfg, "\tcheck_interval = $host_2x->{'check_interval'},");
+ }
+ if(defined($host_2x->{'retry_interval'})) {
+ dump_config_line($icinga2_cfg, "\tretry_interval = $host_2x->{'retry_interval'},");
+ }
+ if(defined($host_2x->{'max_check_attempts'})) {
+ dump_config_line($icinga2_cfg, "\tmax_check_attempts = $host_2x->{'max_check_attempts'},");
+ }
+
+ if(defined($host_2x->{'check_period'})) {
+ dump_config_line($icinga2_cfg, "\tcheck_period = \"$host_2x->{'check_period'}\",");
+ }
+
+ if(defined($host_2x->{'action_url'})) {
+ dump_config_line($icinga2_cfg, "\taction_url = \"$host_2x->{'action_url'}\",");
+ }
+
+ if(defined($host_2x->{'notes_url'})) {
+ dump_config_line($icinga2_cfg, "\tnotes_url = \"$host_2x->{'notes_url'}\",");
+ }
+
+ if(defined($host_2x->{'notes'})) {
+ dump_config_line($icinga2_cfg, "\tnotes = \"$host_2x->{'notes'}\",");
+ }
+
+ if(defined($host_2x->{'icon_image'})) {
+ dump_config_line($icinga2_cfg, "\ticon_image = \"$host_2x->{'icon_image'}\",");
+ }
+
+ if(defined($host_2x->{'statusmap_image'})) {
+ dump_config_line($icinga2_cfg, "\tstatusmap_image = $host_2x->{'statusmap_image'},");
+ }
+
+ # host with no services - valid configuration
+ if (!defined($host_2x->{'SERVICE'})) {
+ dump_config_line($icinga2_cfg, "}");
+ dump_config_line($icinga2_cfg, "\n");
+ return;
+ }
+
+ #say Dumper($host_2x->{'SERVICE'});
+
+ ####################################################
+ # now all services with templates
+ ####################################################
+ foreach my $service_2x_key (keys %{$host_2x->{'SERVICE'}}) {
+ my $service_2x = $host_2x->{'SERVICE'}->{$service_2x_key};
+
+ dump_config_line($icinga2_cfg, "\tservices[\"$service_2x->{__I2CONVERT_SERVICEDESCRIPTION}\"] = {");
+
+ ####################################################
+ # templates
+ ####################################################
+ if (defined($service_2x->{'__I2CONVERT_USES_TEMPLATE'}) && $service_2x->{'__I2CONVERT_USES_TEMPLATE'} == 1) {
+ my $service_2x_templates = join '", "', @{$service_2x->{'__I2CONVERT_TEMPLATE_NAMES'}};
+ dump_config_line($icinga2_cfg, "\t\ttemplates = [ \"$service_2x_templates\" ],")
+ }
+ ####################################################
+ # display_name
+ ####################################################
+ if(defined($service_2x->{'display_name'})) {
+ dump_config_line($icinga2_cfg, "\t\tdisplay_name = \"$service_2x->{'display_name'}\",");
+ }
+
+ dump_config_line($icinga2_cfg, "");
+ ####################################################
+ # macros
+ ####################################################
+ if(defined($service_2x->{'command_macros'}) && $service_2x->{'command_macros'} != 0) {
+ dump_config_line($icinga2_cfg, "\t\tmacros = {");
+ foreach my $cmd_arg (keys %{$service_2x->{'command_macros'}}) {
+ dump_config_line($icinga2_cfg, "\t\t\t$cmd_arg = \"$service_2x->{'command_macros'}->{$cmd_arg}\",");
+ }
+ dump_config_line($icinga2_cfg, "\t\t},");
+ }
+
+ ####################################################
+ # check_command
+ ####################################################
+ if(defined($service_2x->{'check_command'})) {
+ dump_config_line($icinga2_cfg, "\t\tcheck_command = \"$service_2x->{'check_command'}\",");
+ }
+
+ ####################################################
+ # servicegroups
+ ####################################################
+ if(defined($service_2x->{'servicegroups'})) {
+ #say Dumper($service_2x->{'servicegroups'});
+ my $servicegroups = join '", "', @{$service_2x->{'servicegroups'}};
+ if ($service_2x->{'__I2_CONVERT_SG_ADD'} == 1) {
+ dump_config_line($icinga2_cfg, "\t\tservicegroups += [ \"$servicegroups\" ],");
+ } else {
+ dump_config_line($icinga2_cfg, "\t\tservicegroups = [ \"$servicegroups\" ],");
+ }
+ }
+
+ ####################################################
+ # notifications
+ ####################################################
+ if(defined($service_2x->{'__I2CONVERT_NOTIFICATIONS'})) {
+ #say Dumper ($service_2x->{'__I2CONVERT_NOTIFICATIONS'});
+ # this is an array of notification objects
+ foreach my $service_notification_hash (@{$service_2x->{'__I2CONVERT_NOTIFICATIONS'}}) {
+
+ #say Dumper($service_notification_hash);
+
+ # this is a hash by unique key of the notification template, but all further attributes are seperatedly available too
+ foreach my $service_notification_key (keys %{$service_notification_hash}) {
+ my $service_notification = $service_notification_hash->{$service_notification_key};
+ #say Dumper($service_notification);
+
+ # skip everything not related to service notifications
+ next if ($service_notification->{'type'} ne 'service');
+
+ dump_config_line($icinga2_cfg, "\t\tnotifications[\"$service_notification->{'name'}\"] = {");
+
+ if (defined ($service_notification->{'templates'}) && @{$service_notification->{'templates'}} > 0) {
+ my $service_notification_templates = join '", "', @{$service_notification->{'templates'}};
+ dump_config_line($icinga2_cfg, "\t\t\ttemplates = [ \"$service_notification_templates\" ],");
+ }
+
+ if(defined($service_notification->{'users'}) && @{$service_notification->{'users'}} > 0) {
+ my $service_users = join '", "', @{$service_notification->{'users'}};
+ dump_config_line($icinga2_cfg, "\t\t\tusers = [ \"$service_users\" ],");
+ }
+
+ dump_config_line($icinga2_cfg, "\t\t},");
+ }
+ }
+ }
+
+ if(defined($service_2x->{'notification_period'})) {
+ dump_config_line($icinga2_cfg, "\t\tnotification_period = \"$service_2x->{'notification_period'}\",");
+ }
+ if(defined($service_2x->{'notification_interval'})) {
+ dump_config_line($icinga2_cfg, "\t\tnotification_interval = $service_2x->{'notification_interval'},");
+ }
+
+ ####################################################
+ # other service attributes, if set
+ ####################################################
+ if(defined($service_2x->{'check_interval'})) {
+ dump_config_line($icinga2_cfg, "\t\tcheck_interval = $service_2x->{'check_interval'},");
+ }
+ if(defined($service_2x->{'retry_interval'})) {
+ dump_config_line($icinga2_cfg, "\t\tretry_interval = $service_2x->{'retry_interval'},");
+ }
+ if(defined($service_2x->{'max_check_attempts'})) {
+ dump_config_line($icinga2_cfg, "\t\tmax_check_attempts = $service_2x->{'max_check_attempts'},");
+ }
+
+ if(defined($service_2x->{'check_period'})) {
+ dump_config_line($icinga2_cfg, "\tcheck_period = \"$service_2x->{'check_period'}\",");
+ }
+
+ if(defined($service_2x->{'action_url'})) {
+ dump_config_line($icinga2_cfg, "\t\taction_url = \"$service_2x->{'action_url'}\",");
+ }
+
+ if(defined($service_2x->{'notes_url'})) {
+ dump_config_line($icinga2_cfg, "\t\tnotes_url = \"$service_2x->{'notes_url'}\",");
+ }
+
+ if(defined($service_2x->{'notes'})) {
+ dump_config_line($icinga2_cfg, "\t\tnotes = \"$service_2x->{'notes'}\",");
+ }
+
+ if(defined($service_2x->{'icon_image'})) {
+ dump_config_line($icinga2_cfg, "\t\ticon_image = \"$service_2x->{'icon_image'}\",");
+ }
+
+
+ dump_config_line($icinga2_cfg, "\t},");
+ dump_config_line($icinga2_cfg, "");
+ }
+ dump_config_line($icinga2_cfg, "}");
+ dump_config_line($icinga2_cfg, "\n");
+}
+
+sub dump_user_2x {
+ my $icinga2_cfg = shift;
+ my $user_2x = shift;
+ my $object_type = "object"; # object or template
+ my $user_name = $user_2x->{'contact_name'}; # default, may be changed for templates
+
+ #say Dumper($user_2x);
+ if ($user_2x->{__I2CONVERT_IS_TEMPLATE} == 1) {
+ $object_type = "template";
+ $user_name = $user_2x->{'__I2CONVERT_TEMPLATE_NAME'};
+ }
+
+ ####################################################
+ # start, inherit from template?
+ ####################################################
+ if (defined($user_2x->{'__I2CONVERT_USES_TEMPLATE'}) && $user_2x->{'__I2CONVERT_USES_TEMPLATE'} == 1) {
+ my $user_2x_templates = join '", "', @{$user_2x->{'__I2CONVERT_TEMPLATE_NAMES'}};
+ dump_config_line($icinga2_cfg, "$object_type User \"$user_name\" inherits \"$user_2x_templates\" {");
+ } else {
+ dump_config_line($icinga2_cfg, "$object_type User \"$user_name\" {");
+ }
+
+ if(defined($user_2x->{'display_name'})) {
+ dump_config_line($icinga2_cfg, "\tdisplay_name = \"$user_2x->{'display_name'}\",");
+ }
+
+ ####################################################
+ # usergroups
+ ####################################################
+ if(defined($user_2x->{'usergroups'})) {
+ #say Dumper($user_2x->{'usergroups'});
+ my $usergroups = join '", "', @{$user_2x->{'usergroups'}};
+ if ($user_2x->{'__I2_CONVERT_UG_ADD'} == 1) {
+ dump_config_line($icinga2_cfg, "\tgroups += [ \"$usergroups\" ],");
+ } else {
+ dump_config_line($icinga2_cfg, "\tgroups = [ \"$usergroups\" ],");
+ }
+ }
+
+ dump_config_line($icinga2_cfg, "");
+ dump_config_line($icinga2_cfg, "}");
+ dump_config_line($icinga2_cfg, "\n");
+}
+
+sub dump_notification_2x {
+ my $icinga2_cfg = shift;
+ my $notification_2x = shift;
+ my $object_type = "object"; # object or template
+ my $notification_name = $notification_2x->{'__I2CONVERT_NOTIFICATION_NAME'}; # default, may be changed for templates
+
+ #say Dumper($notification_2x);
+ if ($notification_2x->{__I2CONVERT_IS_TEMPLATE} == 1) {
+ $object_type = "template";
+ $notification_name = $notification_2x->{'__I2CONVERT_NOTIFICATION_TEMPLATE_NAME'};
+ }
+
+ ####################################################
+ # start, inherit from template?
+ ####################################################
+ if (defined($notification_2x->{'__I2CONVERT_USES_TEMPLATE'}) && $notification_2x->{'__I2CONVERT_USES_TEMPLATE'} == 1) {
+ my $notification_2x_templates = join '", "', @{$notification_2x->{'__I2CONVERT_TEMPLATE_NAMES'}};
+ dump_config_line($icinga2_cfg, "$object_type Notification \"$notification_name\" inherits \"$notification_2x_templates\" {");
+ } else {
+ dump_config_line($icinga2_cfg, "$object_type Notification \"$notification_name\" {");
+ }
+
+ if(defined($notification_2x->{'display_name'})) {
+ dump_config_line($icinga2_cfg, "\tdisplay_name = \"$notification_2x->{'display_name'}\",");
+ }
+
+ if(defined($notification_2x->{'__I2CONVERT_NOTIFICATION_COMMAND'})) {
+ #say Dumper($notifications_2x->{'notification_command'});
+ dump_config_line($icinga2_cfg, "\tnotification_command = \"$notification_2x->{'__I2CONVERT_NOTIFICATION_COMMAND'}\",");
+ }
+
+ if(defined($notification_2x->{'export_macros'})) {
+ #say Dumper($notification_2x->{'export_macros'});
+ my $export_macros = join '",\n"', @{$notification_2x->{'export_macros'}};
+ dump_config_line($icinga2_cfg, "\texport_macros = [ \"$export_macros\" ],");
+ }
+
+ dump_config_line($icinga2_cfg, "");
+ dump_config_line($icinga2_cfg, "}");
+ dump_config_line($icinga2_cfg, "\n");
+}
+
+
+sub dump_timeperiod_2x {
+ my $icinga2_cfg = shift;
+ my $object_type = "object"; # object or template
+ my $timeperiod_2x = shift;
+ my $timeperiod_name = $timeperiod_2x->{'timeperiod_name'};
+
+ #say Dumper($timeperiod_2x);
+ if ($timeperiod_2x->{__I2CONVERT_IS_TEMPLATE} == 1) {
+ $object_type = "template";
+ $timeperiod_name = $timeperiod_2x->{'__I2CONVERT_TEMPLATE_NAME'};
+ }
+
+ ####################################################
+ # start, inherit from template?
+ ####################################################
+ if (defined($timeperiod_2x->{'__I2CONVERT_USES_TEMPLATE'}) && $timeperiod_2x->{'__I2CONVERT_USES_TEMPLATE'} == 1) {
+ my $timeperiod_2x_templates = join '", "', @{$timeperiod_2x->{'__I2CONVERT_TEMPLATE_NAMES'}};
+ dump_config_line($icinga2_cfg, "$object_type TimePeriod \"$timeperiod_name\" inherits \"$timeperiod_2x_templates\" {");
+ } else {
+ dump_config_line($icinga2_cfg, "$object_type TimePeriod \"$timeperiod_name\" {");
+ }
+
+ # display_name is seperated at first position
+ if(defined($timeperiod_2x->{'display_name'})) {
+ dump_config_line($icinga2_cfg, "\tdisplay_name = \"$timeperiod_2x->{'display_name'}\",");
+ }
+
+ dump_config_line($icinga2_cfg, "\tranges = {");
+
+ # dump all possible keys (there's no fixed string attr here)
+ foreach my $key (sort (keys %{$timeperiod_2x})) {
+ if ($key !~ /__I2CONVERT/ &&
+ $key ne 'alias' &&
+ $key ne 'name' &&
+ $key ne 'timeperiod_name' &&
+ $key ne 'display_name' &&
+ $key ne 'use'
+ ) {
+ dump_config_line($icinga2_cfg, "\t\t\"$key\" \t= \"$timeperiod_2x->{$key}\",");
+ }
+ }
+
+ dump_config_line($icinga2_cfg, "\t},");
+ dump_config_line($icinga2_cfg, "");
+ dump_config_line($icinga2_cfg, "}");
+ dump_config_line($icinga2_cfg, "\n");
+}
+
+sub dump_group_2x {
+ my $icinga2_cfg = shift;
+ my $group_2x = shift;
+ my $group_name_attr = $group_2x->{__I2CONVERT_TYPE} . "_name";
+ my $group_name = $group_2x->{$group_name_attr};
+ my $group_type = ucfirst("$group_2x->{__I2CONVERT_TYPE}");
+ $group_type =~ s/group/Group/;
+
+ #say Dumper($group_2x);
+
+ dump_config_line($icinga2_cfg, "object $group_type \"$group_name\" {");
+ if(defined($group_2x->{'display_name'})) {
+ dump_config_line($icinga2_cfg, "\tdisplay_name = \"$group_2x->{'display_name'}\",");
+ }
+ dump_config_line($icinga2_cfg, "");
+ dump_config_line($icinga2_cfg, "}");
+ dump_config_line($icinga2_cfg, "\n");
+}
+
+sub dump_command_2x {
+ my $icinga2_cfg = shift;
+ my $command_2x = shift;
+ my $command_name = $command_2x->{'__I2CONVERT_COMMAND_NAME'};
+ my $command_line = $command_2x->{'__I2CONVERT_COMMAND_LINE'};
+ my $command_type = ucfirst("$command_2x->{__I2CONVERT_COMMAND_TYPE}Command");
+ my $object_type = "object";
+
+ #say Dumper($command_2x);
+
+ if ($command_2x->{__I2CONVERT_IS_TEMPLATE} == 1) {
+ $object_type = "template";
+ $command_name = $command_2x->{'__I2CONVERT_TEMPLATE_NAME'};
+ }
+
+ ####################################################
+ # start, inherit from template?
+ ####################################################
+ if (defined($command_2x->{'__I2CONVERT_USES_TEMPLATE'}) && $command_2x->{'__I2CONVERT_USES_TEMPLATE'} == 1) {
+ my $command_2x_templates = join '", "', @{$command_2x->{'__I2CONVERT_TEMPLATE_NAMES'}};
+ dump_config_line($icinga2_cfg, "$object_type $command_type \"$command_name\" inherits \"$command_2x_templates\" {");
+ } else {
+ dump_config_line($icinga2_cfg, "$object_type $command_type \"$command_name\" {");
+ }
+
+ ####################################################
+ # attributes
+ ####################################################
+ if(defined($command_2x->{'display_name'})) {
+ dump_config_line($icinga2_cfg, "\tdisplay_name = \"$command_2x->{'display_name'}\",");
+ }
+
+ if(defined($command_line)) {
+ dump_config_line($icinga2_cfg, "\tcommand = \"$command_line\",");
+ }
+
+ ####################################################
+ # macros
+ ####################################################
+
+ if(defined($command_2x->{'__I2CONVERT_COMMAND_MACROS'}) && $command_2x->{'__I2CONVERT_COMMAND_MACROS'} != 0) {
+ dump_config_line($icinga2_cfg, "\tmacros = {");
+ foreach my $cmd_arg (keys %{$command_2x->{'__I2CONVERT_COMMAND_MACROS'}}) {
+ dump_config_line($icinga2_cfg, "\t\t$cmd_arg = \"$command_2x->{'__I2CONVERT_COMMAND_MACROS'}->{$cmd_arg}\",");
+ }
+ dump_config_line($icinga2_cfg, "\t},");
+ }
+
+ dump_config_line($icinga2_cfg, "");
+
+ dump_config_line($icinga2_cfg, "");
+
+ dump_config_line($icinga2_cfg, "}");
+ dump_config_line($icinga2_cfg, "\n");
+}
+
+
+
+1;
+
+__END__
+# vi: sw=4 ts=4 expandtab :