#!/usr/bin/perl -w
### BEGIN INIT INFO
# Provides:          octopussy
# Required-Start:    $local_fs $remote_fs $network $syslog
# Required-Stop:     $local_fs $remote_fs $network $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Start/Stop Octopussy programs
### END INIT INFO

### BEGIN CHKCONFIG INFO
# chkconfig: 2345 90 50
# description: Start/Stop Octopussy programs
### END CHKCONFIG INFO

=head1 NAME

octopussy - Octopussy Main program

=head1 SYNOPSIS

octopussy {start|stop|restart|force-reload|status}
octopussy dispatcher{-start|-stop|-restart|-reload}
octopussy parser{-start|-stop|-restart} <device>
octopussy pusher{-start|-stop|-restart} 
octopussy scheduler{-start|-stop|-restart} 
octopussy web{-start|-stop}

=head1 DESCRIPTION

octopussy is the main program used by the Octopussy Project 
to launch all other Octopussy programs

=cut

use strict;
use warnings;
use Readonly;

use Octopussy;
use Octopussy::Device;
use Octopussy::FS;
use Octopussy::System;

Readonly my $PROG_NAME       => 'octopussy';
Readonly my $USER            => 'octopussy';
Readonly my $APACHE2_CONF    => '/etc/octopussy/apache2.conf';
Readonly my $COMMANDER       => 'octo_commander';
Readonly my $DISPATCHER      => 'octo_dispatcher';
Readonly my $PARSER          => 'octo_parser';
Readonly my $PUSHER          => 'octo_pusher';
Readonly my $RRD             => 'octo_rrd';
Readonly my $SCHEDULER       => 'octo_scheduler';
Readonly my $SENDER          => 'octo_sender';
Readonly my $NICE_PUSHER     => 'nice -n 10';
Readonly my $NICE_RRD        => 'nice -n 15';
Readonly my $NICE_SCHEDULER  => 'nice -n 10';
Readonly my $KILLALL         => '/usr/bin/killall';
Readonly my $INITD_SYSLOG_NG => '/etc/init.d/syslog-ng';

Readonly my $base    => Octopussy::FS::Directory('programs');
Readonly my $dir_pid => Octopussy::FS::Directory('running');

my $MSG_STATUS         = "$PROG_NAME %s %s.\n";
my $MSG_PARSING_STATUS = "$PROG_NAME Parsing '%s' %s.\n";

=head1 FUNCTIONS

=head2 Usage()

Prints usage for Octopussy program

=cut

sub Usage
{
    my $version = Octopussy::Version();
    my $usage   = <<'EOF';
Usage: 
	octopussy {start|stop|restart}
	octopussy {dispatcher-start|dispatcher-stop|dispatcher-restart|dispatcher-reload}
	octopussy {parser-start|parser-stop|parser-restart} <device>
	octopussy {pusher-start|pusher-stop|pusher-restart}
	octopussy {scheduler-start|scheduler-stop|scheduler-restart}
	octopussy {sender-start|sender-stop|sender-restart}
	octopussy {web-start|web-stop}\n";
EOF

    print "\nOctopussy $version\n\n$usage\n";

    return (1);
}

=head2 Commander_Start

Starts octo_commander

=cut

sub Commander_Start
{
    system "sudo -u $USER $base$COMMANDER &";
    printf $MSG_STATUS, 'Commander', 'Started';

    return (1);
}

=head2 Commander_Stop

Stops octo_commander

=cut

sub Commander_Stop
{
    `$KILLALL $COMMANDER`;
    printf $MSG_STATUS, 'Commander', 'Stopped';

    return (1);
}

=head2 Dispatcher_Start()

Starts syslog-ng that launchs octo_dispatcher

=cut

sub Dispatcher_Start
{

    #`$INITD_SYSLOG_NG start`;
    system "sudo -u $USER $base$DISPATCHER &";
    printf $MSG_STATUS, 'Dispatcher', 'Started';

    return (1);
}

=head2 Dispatcher_Stop()

Stops syslog-ng that stops octo_dispatcher

=cut

sub Dispatcher_Stop
{
    my $file_pid = "$dir_pid/octo_dispatcher.pid";
    if (-f $file_pid)
    {
        my $pid = Octopussy::PID_Value($file_pid);
        kill USR1 => $pid;
    }

    #`$INITD_SYSLOG_NG stop`;
    printf $MSG_STATUS, 'Dispatcher', 'Stopped';

    return (1);
}

=head2 Dispatcher_Reload()

Restarts syslog-ng and octo_dispatcher

=cut

sub Dispatcher_Reload
{

    #`$INITD_SYSLOG_NG restart`;
    printf $MSG_STATUS, 'Dispatcher', 'Reloaded';

    return (1);
}

=head2 Parser_Start($device)

Starts octo_parser for device '$device' (all devices if no device specified)

=cut

sub Parser_Start
{
    my $device  = shift;
    my @devices = ();

    if (defined $device) { push @devices, $device; }
    else                 { @devices = Octopussy::Device::List(); }

    foreach my $d (@devices)
    {
        my $parse_status = Octopussy::Device::Parse_Status($d);
        if (defined $parse_status)
        {
            if (Octopussy::Device::Parse_Status($d) >= 1)
            {    # Device Status "Started/Paused"
                system "sudo -u $USER $base$PARSER '$d' &";
                printf $MSG_PARSING_STATUS, $d, 'Started';
            }
            else
            {
                print
"$PROG_NAME Parsing status of '$d' is 'Stopped', set status to 'Paused' or 'Started' first !\n";
            }
        }
        else
        {
            print "Device $d Unknown !\n";
        }
    }

    return (scalar @devices);
}

=head2 Parser_Stop($device)

Stops octo_parser for device '$device' (all devices if no device specified)

=cut

sub Parser_Stop
{
    my $device  = shift;
    my @devices = ();

    if (defined $device) { push @devices, $device; }
    else                 { @devices = Octopussy::Device::List(); }

    foreach my $d (@devices)
    {
        if (Octopussy::Device::Parse_Status($d) >= 1)
        {
            Octopussy::Device::Parse_Pause($d);
            printf $MSG_PARSING_STATUS, $d, 'Paused';
        }
        else
        {
            Octopussy::Device::Parse_Stop($d);
            printf $MSG_PARSING_STATUS, $d, 'Stopped';
        }
    }

    return (scalar @devices);
}

=head2 Pusher_Start

Starts octo_pusher

=cut

sub Pusher_Start
{
    system "sudo -u $USER $NICE_PUSHER $base$PUSHER &";
    printf $MSG_STATUS, 'Pusher', 'Started';

    return (1);
}

=head2 Pusher_Stop

Stops octo_pusher

=cut

sub Pusher_Stop
{
    `$KILLALL $PUSHER`;
    printf $MSG_STATUS, 'Pusher', 'Stopped';

    return (1);
}

=head2 RRD_Start

Starts octo_rrd

=cut

sub RRD_Start
{
    system "sudo -u $USER $NICE_RRD $base$RRD &";
    printf $MSG_STATUS, 'RRD', 'Started';

    return (1);
}

=head2 RRD_Stop

Stops octo_rrd

=cut

sub RRD_Stop
{
    `$KILLALL $RRD`;
    printf $MSG_STATUS, 'RRD', 'Stopped';

    return (1);
}

=head2 Scheduler_Start

Starts octo_scheduler

=cut

sub Scheduler_Start
{
    system "sudo -u $USER $NICE_SCHEDULER $base$SCHEDULER &";
    printf $MSG_STATUS, 'Scheduler', 'Started';

    return (1);
}

=head2 Scheduler_Stop

Stops octo_scheduler

=cut

sub Scheduler_Stop
{
    `$KILLALL $SCHEDULER`;
    printf $MSG_STATUS, 'Scheduler', 'Stopped';

    return (1);
}

=head2 Sender_Start

Starts octo_sender

=cut

sub Sender_Start
{
    system "sudo -u $USER $NICE_SCHEDULER $base$SENDER &";
    printf $MSG_STATUS, 'Sender', 'Started';

    return (1);
}

=head2 Sender_Stop

Stops octo_sender

=cut

sub Sender_Stop
{
    `$KILLALL $SENDER`;
    printf $MSG_STATUS, 'Sender', 'Stopped';

    return (1);
}

=head2 Web_Start

Starts Web Octopussy (Launches Apache2 with Octopussy Apache2 configuration file)

=cut

sub Web_Start
{
    my $APACHE2_BIN = Octopussy::System::Apache2_Binary();

    system
"export APACHE_RUN_DIR=$dir_pid && $APACHE2_BIN -f $APACHE2_CONF -k start";
    printf $MSG_STATUS, 'Web', 'Started';

    return (1);
}

=head2 Web_Stop

Stops Web Octopussy (Stops Apache2 with Octopussy Apache2 configuration file)

=cut

sub Web_Stop
{
    my $APACHE2_BIN = Octopussy::System::Apache2_Binary();

    system "$APACHE2_BIN -f $APACHE2_CONF -k stop";
    printf $MSG_STATUS, 'Web', 'Stopped';

    return (1);
}

=head2 Start()

Starts all Octopussy programs (dispatcher, mysql, parsers, scheduler & pusher)

=cut

sub Start
{

    # recreate /var/run/octopussy/ for systems that mount it on tmpfs
    Octopussy::FS::Create_Directory($dir_pid);
    Octopussy::FS::Chown(Octopussy::FS::File('fifo'));
    Dispatcher_Start();
    my $mysql =
        (-x '/etc/init.d/mysqld' ? '/etc/init.d/mysqld' : '/etc/init.d/mysql');
    `$mysql restart`;
    Parser_Start();
    RRD_Start();
    Scheduler_Start();
    Sender_Start();
    Pusher_Start();
    Commander_Start();
    Web_Start();

    return (1);
}

=head2 Stop()

Stops all Octopussy programs (parsers, scheduler, pusher & dispatcher)

=cut

sub Stop
{
    Web_Stop();
    Commander_Stop();
    Parser_Stop();
    RRD_Stop();
    Scheduler_Stop();
    Sender_Stop();
    Pusher_Stop();
    Dispatcher_Stop();

    #`rm -f $dir_pid/*.err`;
    #`rm -f $dir_pid/*.pid`;

    return (1);
}

=head2 Status()

Returns Octopussy programs (dispatcher, rsyslog, scheduler) status

=cut

sub Status
{
    my %proc = Octopussy::Process_Status();
    foreach my $k (sort keys %proc)
    {
        my $status = ($proc{$k} != 0 ? 'Started' : 'Stopped');
        print "  $k: $status\n";
    }

    return (1);
}

my $arg    = $ARGV[0] || '';
my $device = $ARGV[1] || undef;

my %action = (
    'start'              => \&Start,
    'stop'               => \&Stop,
    'status'             => \&Status,
    'reload'             => sub { Stop(); Start(); },
    'restart'            => sub { Stop(); Start(); },
    'dispatcher-start'   => \&Dispatcher_Start,
    'dispatcher-stop'    => \&Dispatcher_Stop,
    'dispatcher-reload'  => \&Dispatcher_Reload,
    'dispatcher-restart' => sub { Dispatcher_Stop(); Dispatcher_Start(); },
    'parser-start'       => \&Parser_Start,
    'parser-stop'        => \&Parser_Stop,
    'parser-restart' =>
        sub { my $d = shift; Parser_Stop($d); Parser_Start($d); },
    'pusher-start'      => \&Pusher_Start,
    'pusher-stop'       => \&Pusher_Stop,
    'pusher-restart'    => sub { Pusher_Stop(); Pusher_Start(); },
    'scheduler-start'   => \&Scheduler_Start,
    'scheduler-stop'    => \&Scheduler_Stop,
    'scheduler-restart' => sub { Scheduler_Stop(); Scheduler_Start(); },
    'sender-start'      => \&Sender_Start,
    'sender-stop'       => \&Sender_Stop,
    'sender-restart'    => sub { Sender_Stop(); Sender_Start(); },
    'web-start'         => \&Web_Start,
    'web-stop'          => \&Web_Stop,

    #'web-restart' => sub { Web_Stop(); Web_Start(); }, # too fast
);

if (defined $action{$arg})
{
    $action{$arg}->($device);
}
else { Usage(); }

exit 0;

=head1 AUTHOR

Sebastien Thebert <octo.devel@gmail.com>

=head1 SEE ALSO

octo_dispatcher, octo_extractor, octo_parser, octo_uparser, octo_reporter, octo_rrd, octo_scheduler

=cut
