#! /usr/bin/env perl
# vim: set filetype=perl ts=4 sw=4 sts=4 et:
#
# DESC: Check that the bastion code works (healtheck)

use strict;
use warnings;
use File::Basename;
use Getopt::Long;

my $PROBE_NAME = basename($0);
my $debug;

## no critic (Subroutines::RequireFinalReturn)

sub _out {
    my ($criticity, $msg) = @_;
    printf "%s %4s - %s\n", $PROBE_NAME, $criticity, $msg;
}

sub _dbg  { _out('dbg',  $_[0]) if $debug; }
sub _info { _out('info', $_[0]); }
sub _warn { _out('WARN', $_[0]); }
sub _err  { _out('ERR!', $_[0]); }

sub success { my $msg = shift; _info($msg) if $msg; _info("status=OK");      exit(0); }
sub warning { my $msg = shift; _warn($msg) if $msg; _info("status=WARN");    exit(1); }
sub failure { my $msg = shift; _err($msg)  if $msg; _info("status=FAILURE"); exit(2); }
sub unknown { my $msg = shift; _err($msg)  if $msg; _info("status=UNKNOWN"); exit(3); }

# OPTIONS

my $host           = "127.0.0.1";
my $port           = 22;
my $account        = 'healthcheck';
my $keyfile        = '/home/healthcheck/.ssh/id_healthcheck';
my $kbdinteractive = 0;

GetOptions(
    "help"            => \my $help,
    "debug!"          => \$debug,
    "host=s"          => \$host,
    "port=i"          => \$port,
    "account=s"       => \$account,
    "keyfile=s"       => \$keyfile,
    "kbd-interactive" => \$kbdinteractive,
) or unknown("Failed parsing command-line");

# HELP

if ($help) {
    print <<"EOF";

$PROBE_NAME [options]

        --help              This help message
        --debug             Increase verbosity of logs
        --host HOST         Host to connect to. Default: $host
        --port PORT         Port to connect to. Default: $port
        --account ACCOUNT   Account name to use to authenticate. Default: $account
        --keyfile PATH      Path to the private SSH key file to authenticate. Default: $keyfile
        --kbd-interactive   Allow keyboard-interactive authentication. Default: $kbdinteractive

        Note: don't specify an other option than --help to get the proper default values.

EOF
    unknown();
}

# CODE

if ($account !~ /^[a-zA-Z0-9._-]+$/) {
    unknown("Specified account is invalid ($account)");
}

if ($host !~ /^[a-zA-Z0-9._-]+$/) {
    unknown("Specified host is invalid ($host)");
}

if ($port <= 0 || $port > 65535) {
    unknown("Specified port is invalid ($port)");
}

if (!-f -r $keyfile) {
    unknown("Specified keyfile '$keyfile' is not readable or not a file");
}

# first; check that sudo is healthy
_dbg("Checking sudo viability...");
my $sysret = system(qw{ sudo -n -v });
if ($sysret != 0) {
    critical("sudo is broken!");
}

my @cmd = ('ssh', '-l', $account, '-i', $keyfile, '-p', $port);
if ($kbdinteractive) {
    push @cmd,
      ('-o', 'KbdInteractiveAuthentication=yes', '-o', 'PreferredAuthentications=publickey,keyboard-interactive');
}
push @cmd, ($host, '--', '-q', '--osh', 'info');
_dbg("Executing: " . join(" ", @cmd));

$sysret = system(@cmd);
if ($sysret == 0) {
    success("Connection worked and ended successfully");
}
failure("Connection failed (SSH return code = " . ($sysret >> 8) . ")");
