package Cpanel::TaskProcessors::CCSTasks;

# cpanel - Cpanel/TaskProcessors/CCSTasks.pm       Copyright 2019 cPanel, L.L.C.
#                                                           All rights Reserved.
# copyright@cpanel.net                                         http://cpanel.net
# This code is subject to the cPanel license. Unauthorized copying is prohibited

use strict;
use warnings;

=head1 NAME

Cpanel::TaskProcessors::CCSTasks

=head1 SYNOPSIS

    Cpanel::ServerTasks::queue_task( 'CCSTasks', 'rebuild_ccs_users' );

=head1 DESCRIPTION

Used internally by Cpanel::ServerTasks to queue CCS related tasks.

=cut

# Case CPANEL-39715: First time install can break if yum is setup to install
# dependencies in paralell. As such we punt the PG setup and first time
# start to the taskqueue. Most of this code used to be in
# /opt/cpanel-ccs/bin/safe_configure_postgres_for_cpanel, which itself borrowed
# heavily from scripts/installpostgres.
{

    package Cpanel::TaskProcessors::CCSTasks::safe_configure_postgres_for_cpanel;
    use parent 'Cpanel::TaskQueue::FastSpawn';

    sub is_valid_args {
        my ( $self, $task ) = @_;
        return 0 == $task->args;
    }

    sub deferral_tags {
        return qw();
    }

    sub _do_child_task {
        my ( $self, $task, $logger ) = @_;

        require Cpanel::Chkservd::Manage;
        require Cpanel::SafeRun::Simple;
        require Cpanel::PostgresUtils;
        require Cpanel::PostgresUtils::PgPass;
        require Whostmgr::Postgres;

        my $pg_user             = Cpanel::PostgresUtils::PgPass::getpostgresuser();
        my $pg_home             = Cpanel::PostgresUtils::find_pgsql_home( 'user' => $pg_user );
        my $pg_data             = Cpanel::PostgresUtils::find_pgsql_data( 'home' => $pg_home );

        # Don't rerun setup if the datastore already exists
        if ( $pg_data && !-e "$pg_data/global" ) {

            # Not all systems will have loaded a freshly installed
            # postgresql.service unit before it is required by postgresql-setup, so
            # instruct systemd to reload the unit configurations now before
            # attempting setup.
            Cpanel::SafeRun::Simple::saferunnoerror( '/usr/bin/systemctl',        'daemon-reload' ) if -x '/usr/bin/systemctl';
            Cpanel::SafeRun::Simple::saferunnoerror( '/usr/bin/postgresql-setup', 'initdb' );
        }

        Cpanel::SafeRun::Simple::saferunnoerror( '/usr/local/cpanel/scripts/setpostgresconfig', '--force' );
        Cpanel::SafeRun::Simple::saferun( '/usr/local/cpanel/scripts/cpservice', 'postgresql', 'enable', '35' );
        Whostmgr::Postgres::update_config();

        Cpanel::SafeRun::Simple::saferunnoerror('/usr/local/cpanel/scripts/restartsrv_postgres');
        my $install_ok = $? == 0 ? 1 : 0;

        # The below block should only fire if scripts/installpostgres would have worked.
        # In cases where this would fail, we would prefer haspostgres to continue
        # to report 0.
        if ($install_ok) {

            my ( $status, $message ) = Whostmgr::Postgres::create_dbowners_for_cpusers();

            $install_ok &&= $status;

            if ($install_ok) {

                Cpanel::SafeRun::Simple::saferun( '/usr/local/cpanel/bin/postgrescheck', '--check-auth', '--reset-pass-on-fail' );
                Cpanel::SafeRun::Simple::saferun('/usr/local/cpanel/bin/cpsessetup');

                # If PostgreSQL has never been listed under chkservd, enable monitoring for it.
                # (This might happen if the service was uninstalled manually but reinstalled with this script.)
                # Doing this prevents /scripts/check_unmonitored_enabled_services from complaining to the admin
                # who is installing PostgreSQL for the first time on this system.
                my %MONITORED = Cpanel::Chkservd::Manage::getmonitored();
                Cpanel::Chkservd::Manage::enable('postgresql') unless exists $MONITORED{'postgresql'};
            }
        }
        Cpanel::SafeRun::Simple::saferun('/usr/local/cpanel/bin/build_global_cache');    # reset haspostgres
        require Cpanel::ServerTasks;
        Cpanel::ServerTasks::queue_task( ['CpServicesTasks'], "restartsrv cpanel_ccs" );

        return;
    }

}

{

    package Cpanel::TaskProcessors::CCSTasks::rebuild_ccs_users;
    use parent 'Cpanel::TaskQueue::FastSpawn';

    sub is_valid_args {
        my ( $self, $task ) = @_;
        return 0 == $task->args;
    }

    sub deferral_tags {
        return qw(rebuild_email_accounts_cache);
    }

    sub _do_child_task {
        my ( $self, $task, $logger ) = @_;

        # Kinda cool since we're being loaded from /var/cpanel/perl already
        local @INC = ( '/var/cpanel/perl', @INC );
        require Cpanel::CCS::Userdata;
        local $@;
        eval { Cpanel::CCS::Userdata::output_xml( Cpanel::CCS::Userdata::create_directory() ); };
        print STDERR "CCSTasks::rebuild_ccs_users: $@" if $@;

        return;
    }

}

{

    package Cpanel::TaskProcessors::CCSTasks::rebuild_ccs_config;
    use parent 'Cpanel::TaskQueue::FastSpawn';

    sub is_valid_args {
        my ( $self, $task ) = @_;
        return 0 == $task->args;
    }

    sub deferral_tags {
        return qw(import_tls_data);
    }

    sub _do_child_task {
        my ( $self, $task, $logger ) = @_;

        # Kinda cool since we're being loaded from /var/cpanel/perl already
        local @INC = ( '/var/cpanel/perl5/lib', '/var/cpanel/perl', @INC );
        require Cpanel::CCS::Utils;
        local $@;
        eval { Cpanel::CCS::Utils::rebuild_ccs_conf(); };
        if ($@) {
            print STDERR "CCSTasks::rebuild_ccs_config: $@" if $@;
        }
        else {
            require Cpanel::ServerTasks;
            Cpanel::ServerTasks::schedule_task( ['CpServicesTasks'], 10, "restartsrv cpanel_ccs" );
        }

        return;
    }

}

{

    package Cpanel::TaskProcessors::CCSTasks::import_tls_data;
    use parent 'Cpanel::TaskQueue::FastSpawn';

    sub is_valid_args {
        my ( $self, $task ) = @_;
        return 0 == $task->args;
    }

    sub deferral_tags {
        return qw(autossl_check);
    }

    sub _do_child_task {
        my ( $self, $task, $logger ) = @_;

        # Kinda cool since we're being loaded from /var/cpanel/perl already
        require Cpanel::Domain::TLS;
        local @INC = ( '/var/cpanel/perl', @INC );
        require Cpanel::CCS::DomainTLS;

        my @domains = Cpanel::Domain::TLS->get_tls_domains();
        Cpanel::CCS::DomainTLS::real_copy_certs_for_domains(@domains) if @domains;

        return;
    }

}

{

    package Cpanel::TaskProcessors::CCSTasks::migrate_horde2ccs;
    use parent 'Cpanel::TaskQueue::FastSpawn';

    our $horde_index = '/usr/local/cpanel/base/horde/index.php';
    our $mig_script  = '/opt/cpanel-ccs/bin/migrate_horde2ccs';

    sub is_valid_args {
        my ( $self, $task ) = @_;
        return 0 == $task->args;
    }

    sub deferral_tags {
        return qw(autossl_check);
    }

    sub _do_child_task {
        my ( $self, $task, $logger ) = @_;

        # Do nothing if horde is not installed
        return if !-f $horde_index;
        local $@;
        eval {
            eval "require '$mig_script'" if !$INC{$mig_script};
            CCS::scripts::migrate_horde2ccs::script();
        };
        print STDERR "CCSTasks::migrate_horde2ccs: $@" if $@;

        return;
    }

}

{

    package Cpanel::TaskProcessors::CCSTasks::flush_memcached;
    use parent 'Cpanel::TaskQueue::FastSpawn';

    our $program = '/usr/bin/memflush';
    our @args    = qw{--servers=/opt/cpanel-ccs/data/Logs/state/memcache.sock};

    sub is_valid_args {
        my ( $self, $task ) = @_;
        return 0 == $task->args;
    }

    sub deferral_tags {
        return qw();
    }

    sub _do_child_task {
        my ( $self, $task, $logger ) = @_;

        # Do nothing if horde is not installed
        require Cpanel::SafeRun::Object;
        my $run_result = Cpanel::SafeRun::Object->new(
            'program' => $program,
            'args'    => [@args],
        );
        my $exit = $run_result->error_code() || 0;
        print STDERR "CCSTasks::flush_memcached: Nonzero exit from '$program " . join( " ", @args ) . "': " . $run_result->autopsy() . "\n" if $exit;

        return;
    }
}

=head2 to_register

The list of stuff you can actually run.

=cut

sub to_register {
    return (
        [ 'safe_configure_postgres_for_cpanel', Cpanel::TaskProcessors::CCSTasks::safe_configure_postgres_for_cpanel->new() ],
        [ 'rebuild_ccs_users',                  Cpanel::TaskProcessors::CCSTasks::rebuild_ccs_users->new() ],
        [ 'rebuild_ccs_config',                 Cpanel::TaskProcessors::CCSTasks::rebuild_ccs_config->new() ],
        [ 'import_tls_data_for_ccs',            Cpanel::TaskProcessors::CCSTasks::import_tls_data->new() ],
        [ 'migrate_horde2ccs',                  Cpanel::TaskProcessors::CCSTasks::migrate_horde2ccs->new() ],
        [ 'flush_memcached',                    Cpanel::TaskProcessors::CCSTasks::flush_memcached->new() ],
    );
}

1;
