debug_adm 5.07 KB
#!/usr/bin/env perl

use strict;
use warnings;

use Carp 'verbose';

use FindBin;

use File::Slurp;
use File::Glob qw(:glob);
use File::Copy;
use File::Copy::Recursive qw(dircopy);
use File::Path qw(make_path remove_tree);
use File::Temp;
use File::Spec;
use File::Basename qw(dirname);

use Cwd qw(abs_path);

use IPC::Cmd qw(run);

use List::MoreUtils qw(uniq);

use Cache::Memcached::Fast;
use ExtUtils::Installed;

our $VERSION = '1.0001';

my $self = $0 = ( -f $0 && -l $0 ) ? abs_path( readlink( $0 ) ) : abs_path( $0 );

use Pod::Usage;
use Getopt::Long;

use Data::Dumper qw(Dumper);

my %options = ();
my $arg_line = join ' ', $0, @ARGV; # survive GetOptions

GetOptions (\%options,
    'webmin=s',
    'action=s',
    'object=s',
    'level=s',
    'name=s',
    'log=s',
    'debug',
    'help|?'
);

pod2usage(1) if $options{help};

my $self_path = dirname( $self );
my $webmin_conf_path = $options{webmin} || "/etc/webmin/miniserv.conf";

my $log_file = $options{'log'} || "/var/log/thirdlane/debug_adm.log";

our @possible_objects = qw(debug pbxconf pbxlogs);

our $cache;

$SIG{__WARN__} = sub {
    my $strace = Carp::longmess();
    &write_log(@_, $strace);
    print "Warn:" . $_[0] . "\n" if $options{debug};
};

$SIG{__DIE__} = sub {
    my $strace = Carp::longmess();
    &write_log(@_, $strace);
    print "Die:" . $_[0] . "\n" if $options{debug};
};

sub data_dump {
    return Data::Dumper->new([@_])
        ->Purity(0)
        ->Useqq(0)
        ->Terse(1)
        ->Deepcopy(1)
        ->Quotekeys(0)
        ->Maxdepth(32)
        ->Dump;
}

sub get_cache_handle {
    my $cache = new Cache::Memcached::Fast {
	servers => [ "127.0.0.1:11211" ],
	serialize_methods => [ \&Storable::freeze, \&Storable::thaw ],
	utf8 => 1,
	compress_threshold => 10_000
    };

    die "cache inaccessible" unless defined $cache;

    return $cache;
}

sub write_log {
    my ( @args ) = @_;

    my $date_string = localtime();

    $_ = ( ref $_ ? data_dump($_) : $_ ) for @args;

    foreach my $log_line ( split /\n/, join "\n", @args ) {
	$log_line = "$date_string [v$VERSION]: " . $log_line;
	$log_line .= "\n" unless $log_line =~ m/\n$/sg;

	print "LOG:", $log_line if $options{debug};
	write_file($log_file, { append => 1 }, $log_line);
    }
}

sub get_webmin_port {
    my $webmin_conf = read_file($webmin_conf_path);
    my ($port) = $webmin_conf =~ m/port\=(\d+)/sg;

    return $port;
}

sub set_webmin_port {
    my $port = shift;

    my $webmin_conf = read_file($webmin_conf_path);
    $webmin_conf =~ s/port\=(\d+)/port\=$port/sg;
    write_file($webmin_conf_path, $webmin_conf);

    system("/usr/bin/systemctl", "restart", "webmin");

    return $port;
}

sub usage {
    pod2usage(1);
}

sub action_status_all {
    no strict 'refs';

    foreach my $object_name ( @possible_objects ) {
	my $action_name_sub = sprintf( "action_status_%s", $object_name );
	if ( defined *$action_name_sub{CODE} ) {
	    $action_name_sub->();
	}
    }
}

sub action_status_debug {
    if ( $cache->get("thirdlane::debug::core") ) {
	print "Core debug is enabled.\n";
    } else {
	print "Core debug is disabled.\n";
    }
}

sub action_enable_debug {
    $options{level} ||= "debug";
    $cache->set("thirdlane::debug::core", 1);
    $cache->set("thirdlane::debug::core::level", $options{level});
}

sub action_disable_debug {
    $cache->delete("thirdlane::debug::core");
    $cache->delete("thirdlane::debug::core::level");
}

sub action_modules_perl {
    my $installed = ExtUtils::Installed->new( skip_cwd => 1 );
    for my $module ($installed->modules()) {
	printf("%s %s\n", $module, $installed->version($module));
    }
}

write_log("Started with arguments:", $arg_line);
write_log("Used options:", \%options);

$options{action} = "enable" if ( lc $options{action} eq "on" );
$options{action} = "disable" if ( lc $options{action} eq "off" );

my $action_sub = $options{action} && $options{object} ? "action_" . $options{action} . "_" . $options{object} : "usage";

$cache = &get_cache_handle();

{
    no strict 'refs';

    if ( defined *$action_sub{CODE} ) {
	write_log("Calling function:", $action_sub);
	&action_status_all() if $action_sub eq "usage";
	$action_sub->();
	my $action_status_sub = "action_status_" . $options{object};
	if ( defined *$action_status_sub{CODE} ) {
	    $action_status_sub->();
	}
    } else {
	write_log("Unknown function:", $action_sub);
	&action_status_all();
	&usage();
	die("unknown operation!\n");
    }
}

__END__

=head1 NAME

debug_adm - Debug configuration manager for Thirdlane PBX distribution

=head1 SYNOPSIS

debug_adm --action=[action] --object=[object] [options ...]

 Options:
   --help               help message
   --action             manager action
   --object             manager object
   --level              debug level

=head1 OPTIONS

=over 4

=item B<--help>

Print a brief help message and exits.

=item B<--action>

Configuration action. Possible actions [ "enable", "disable", "status" ]

=item B<--object>

Configuration object. Possible objects [ "debug", "pbxconf", "pbxlogs" ]

=head1 DESCRIPTION

B<This program> will read the given input configuration and do something
useful with the debug behavior.

=cut