#!/usr/bin/env perl
use JSON qw(decode_json);
use Sys::Hostname;
use Getopt::Long;
use strict;
use warnings;

my @services;
my $verbose;
my $num_pgs;
my $service;
my $clusterid;
my $adminsock;
my @alarms;
my @checked;

GetOptions (
    "service=s{1}"  => \@services,
    "verbose"       => \$verbose,
    "num_pgs=i"     => \$num_pgs,
    "clusterid=s"   => \$clusterid,
);
help() if not @services;


# This bit of magic makes this script 'discover' running OSDs.
if (scalar(@services) == 1 and $services[0] eq "osd_discover") {
    if (not opendir(DIR, "/var/run/ceph/")) {
        push @alarms, "Can't readdir() /var/run/ceph: $!";
    } else {
        @services = ();
        foreach my $dent (readdir(DIR)) {
            next if $dent !~ m#ceph\-(osd\.\d+)\.asok#;
            push @services, $1;
        }
        closedir(DIR);
        push @alarms, "No OSDs were discovered!" if (not scalar(@services));
    }
}

$num_pgs ||= 200;

foreach $service (@services) {
  if($verbose) { print "running loop service $service\n"; }

    push @checked, "$service";

    my $command = 'status';
    if ($service =~ m/^mon\./ ) {
      $command = 'mon_status';
    }


    if($clusterid) {
        $adminsock = "/var/run/ceph/$clusterid/ceph-$service.asok";
    } else {
        $adminsock = $service;
    }

    # mgr contains a container tag in the RBD cluster, we are using an 'autodetect'
    # together with the required clusterid that is mandatory in @ new RBD cluster

    if ($service =~ m#^mgr\..+# and $clusterid){
        if (not opendir(DIR, "/var/run/ceph/$clusterid/")) {
            push @alarms, "Can't readdir() /var/run/ceph/$clusterid: $!";
        } else {
            foreach my $dent (readdir(DIR)) {
                next if $dent !~ m#ceph\-mgr\..+\.asok#;
                $adminsock = "/var/run/ceph/$clusterid/$dent";
            }
        }
    }

    if($verbose) { print "running command: /usr/bin/ceph daemon $adminsock $command 2>&1\n"; }
    my $json = `/usr/bin/ceph daemon $adminsock $command 2>&1`;
    my $json_out = eval { decode_json($json) };

    # If not valid JSON, then set alarm
    if ($@) {
      push @alarms, "NOT-RUNNING: $service";
      next;
    }

    if ( (defined $json_out->{num_pgs}) and ($json_out->{num_pgs} > $num_pgs)) {
      push @alarms, "PG-OVERBOOKED: $service";
    }

# Active only works on OSD, but MON, etc ...
#    if ( (defined $json_out->{state}) and ($json_out->{state} ne 'active') ) {
#      push @alarms, "INACTIVE: $service";
#    }

}

if (@alarms) {
  my $brokenServices = join(' ', @alarms);
  print "CRITICAL - $brokenServices\n";
  exit 2;
} 

my $checkedServices = join(' ', @checked);
print "OK - Checked: $checkedServices \n";
exit 0;

#
##
#

sub help {
  print "Usage: $0 --service=\$SERVICE.\$ID --service=\$SERVICE.\$ID --num_pgs=XYZ --verbose\n";
  exit 1;
}
