package RackMan::Format::Nagios;

use strict;
use warnings;

use Carp;
use List::MoreUtils qw< uniq >;
use RackMan::File;


use constant {
    CONFIG_SECTION  => "format:nagios",
    DEFAULT_PATH    => "/etc/nagios/hosts",
};


my %type2group = (
    PDU     => "pdus",
    Server  => "servers",
    Switch  => "switches",
);


#
# write()
# -----
sub write {
    my ($class, $args) = @_;

    my $rackdev = $args->{rackdev};
    my $rackman = $args->{rackman};
    my $config  = RackMan::File->new;
    my $type    = $rackdev->object_type;

    # fetch the common name and FQDN of the host
    my $name    = $rackdev->object_name;
    my $fqdn    = $rackdev->attributes->{FQDN};
    RackMan->error("RackObject '$name' lacks a FQDN") unless $fqdn;

    # find the first IP address of the device, excluding the iLO
    my @ip_addrs = ( $rackdev->regular_ipv4addrs, $rackdev->regular_ipv6addrs );
    RackMan->error("RackObject '$name' lacks an IPv4 address") unless @ip_addrs;
    my $address = $ip_addrs[0]{addr} || $name;

    # determine the parents of this device
    my $parents = join ", ", uniq map {
        defined $_->{peer_object_name} && $_->{name} !~ /^(?:PWR\d|ilo)$/i
            ? $_->{peer_object_name} : ()
    } @{ $rackdev->ports };

    # construct the RackTables url for this device
    my $rto_url = "";
    if (my $base_url = $rackman->config->val(general => "racktables_url")) {
        $base_url =~ s:/$::;
        $rto_url = sprintf "$base_url/index.php?page=object&object_id=%d",
                $rackdev->object_id;
    }

    # store the generic config
    $config->add_content(
        "define host {\n",
        "    use                     tmpl-generic-host\n",
        "    host_name               $name\n",
        "    alias                   $fqdn\n",
        "    address                 $address\n",
        "    parents                 $parents\n",
        "    hostgroups              $type2group{$type}\n",
        "    check_command           check-host-alive\n",
        "    notes                   RackTables object\n",
        "    notes_url               $rto_url\n",
        "}\n\n",
    );

    # call the appropriate function for generating the specific config
    # corresponding to the type of the device
    my $config_maker = "config_for_\L$type";
    $class->$config_maker({ config => $config, rackdev => $rackdev });

    # write the configuration on disk
    $config->name("$name.conf");
    $config->path($rackman->config->val(CONFIG_SECTION, "path", DEFAULT_PATH));
    print "  + writing ", $config->fullpath, $/ if $args->{verbose};
    my $scm = $rackman->get_scm({ path => $config->path });
    $scm->update;
    $config->write;
    $scm->add($config->name);
    $scm->commit($config->name, "generated by $class / $::PROGRAM v$::VERSION");
}


#
# config_for_server()
# -----------------
sub config_for_server {
    my ($class, $args) = @_;

    my $rackdev = $args->{rackdev};
    my $config  = $args->{config};
    my $name    = $rackdev->object_name;
    my $fqdn    = $rackdev->attributes->{FQDN};

    $config->add_content(
        "define service {\n",
        "    use                     tmpl-server-service\n",
        "    host_name               $name\n",
        "    service_description     check_disk\n",
        "    check_command           check_disk\n",
        "}\n\n",
    );

    $config->add_content(
        "define service {\n",
        "    use                     tmpl-server-service\n",
        "    host_name               $name\n",
        "    service_description     check_proc\n",
        "    check_command           check_proc\n",
        "}\n\n",
    );

    $config->add_content(
        "define service {\n",
        "    use                     tmpl-server-service\n",
        "    host_name               $name\n",
        "    service_description     check_raid_bsd\n",
        "    check_command           check_raid_bsd\n",
        "}\n\n",
    );

    $config->add_content(
        "define service {\n",
        "    use                     tmpl-server-service\n",
        "    host_name               $name\n",
        "    service_description     check_snmp_volume\n",
        "    check_command           check_snmp_volume\n",
        "}\n\n",
    );

    if ($rackdev->has_ilo) {
        my $ilo_name = $rackdev->ilo_fqdn;
        my $ilo_addr = $rackdev->ilo_ipv4addr->{addr};

        $config->add_content(
            "define host {\n",
            "    use                     tmpl-generic-host\n",
            "    host_name               $ilo_name\n",
            "    address                 $ilo_addr\n",
            "    check_command           check-host-alive\n",
            "    notes                   iLO subsystem of $name\n",
            "}\n\n",
        );
    }

}


#
# config_for_switch()
# -----------------
sub config_for_switch {
    my ($class, $args) = @_;

    my $rackdev = $args->{rackdev};
    my $config  = $args->{config};
    my $name    = $rackdev->object_name;

    $config->add_content(
        "define service {\n",
        "    use                     tmpl-switch-service\n",
        "    host_name               $name\n",
        "    service_description     check_media_switch\n",
        "    check_command           check_media_switch\n",
        "}\n\n",
    );
}


#
# config_for_pdu()
# --------------
sub config_for_pdu {
    my ($class, $args) = @_;

    my $rackdev = $args->{rackdev};
    my $config  = $args->{config};
    my $name    = $rackdev->object_name;

    $config->add_content(
        "define service {\n",
        "    use                     tmpl-pdu-service\n",
        "    host_name               $name\n",
        "    service_description     check_pdu\n",
        "    check_command           check_pdu\n",
        "}\n\n",
    );
}


__PACKAGE__

__END__

=pod

=head1 NAME

RackMan::Format::Nagios - Generate the Nagios config for a given RackObject

=head1 SYNOPSIS

    use RackMan::Format::Nagios;

    RackMan::Format::Nagios->write({
        rackdev => $rackdev,  # a RackMan::Device instance
        rackman => $rackman,  # a RackMan instance
    });


=head1 DESCRIPTION

This module generates the Nagios configuration file for a given RackObject.


=head1 METHODS

=head2 write

Generate the file.

B<Arguments>

Arguments are expected as a hashref with the following keys:

=over

=item *

C<rackdev> - I<(mandatory)> a RackMan::Device instance

=item *

C<rackman> - I<(mandatory)> a RackMan instance

=item *

C<verbose> - I<(optional)> boolean, set to true to be verbose

=back


=head1 CONFIGURATION

This module gets its configuration from the C<[format:nagios]> section
of the main F<rack.conf>, with the following parameters:

=head2 path

Path of the directory to store the generated files.


=head2 scm

Specify the SCM tool to use for versionning generated files.


=head1 AUTHOR

Sebastien Aperghis-Tramoni

=cut

