#!/usr/bin/perl
#
# lml-maintenance.pl Lab Manager Light maintenance script
#
# * Remove obsolete machines from lab.conf
#
# IMPORTANT: If an ESX server is disconnected from the vCenter server, the VM data
#            is still accessible. Therefore this script won't delete VMs from that
#            disconnected ESX server!

use strict;
use warnings;

# place DLLs and PMs with the required subdirectory structure into lib/ next to this script
use FindBin;
use lib "$FindBin::RealBin/../lib";

use CGI ':standard';
use LML::Common;
use LML::VMware;
use LML::DHCP;
use LML::Lab;
use LML::VM;
use Data::Dumper;
use Carp;

sub maintain_labfile($$$$$$) {
    # initialize needed variables
    my ($C, $VM_ALL, $HOSTS, $NETWORKS, $DATASTORES, $FOLDERS)  = @_;
    carp( "1st argument must be LML::Config object and not " . ref($C) ) unless ( ref($C) eq "LML::Config" );
    carp( "2nd argument must be VM Hash and not " . ref($VM_ALL) ) unless ( ref($VM_ALL) eq "HASH" );
    carp( "3rd argument must be HOSTS Hash object and not " . ref($HOSTS) ) unless ( ref($HOSTS) eq "HASH" );
    carp( "4th argument must be NETWORKS Hash object and not " . ref($NETWORKS) ) unless ( ref($NETWORKS) eq "HASH" );
    carp( "5th argument must be DATASTORES Hash object and not " . ref($DATASTORES) ) unless ( ref($DATASTORES) eq "HASH" );
    carp( "6th argument must be FOLDERS Hash object and not " . ref($FOLDERS) ) unless ( ref($FOLDERS) eq "HASH" );
    my $labfile = $C->labfile;
    my @error   = ();

    my $LAB = new LML::Lab($labfile, 1);
    # go through our known VM list and delete host from that list
    # if they are not in the actual VM list we got previously
    my $hosts_removed = 0;
    foreach my $LAB_VM ($LAB->get_vms) {
        my $uuid = $LAB_VM->uuid;
        if ( exists( $VM_ALL->{$uuid} ) ) {
            my $VM = new LML::VM( $VM_ALL->{$uuid} );
            # Set dns domain of VM from first network card
            $VM->set_dns_domain($C->appenddomain(($VM->networks())[0]));            
            $VM->set_networks_filter( $C->get_array("vsphere","networks") );    # set network filter
            $LAB->update_vm($VM);
        } else {
            # remember that we deleted a host
            $hosts_removed++;
            # delete the host from the lab hash
            $LAB->remove($uuid);
        }
    }

    # first update the info about Hosts, Networks and Datastores
    $LAB->update_hosts($HOSTS);
    $LAB->update_networks($NETWORKS);
    $LAB->update_datastores($DATASTORES);
    $LAB->update_folders($FOLDERS);
    
    # always write LAB file, also creates new one if it did not exist before
    $LAB->write_file( "by " . __FILE__ );

    if ( $LAB->vms_to_update ) {
        # rewrite the DHCP configuration with the new data
        push( @error, LML::DHCP::UpdateDHCP( $C, $LAB ) );
    }

    # Return the error array
    return @error;
}

# main() code when running as stand-alone program
unless (caller) {
    my $C = new LML::Config;

    # initialize needed variables
    my $vm_name = "";
    my @error   = ();

    # get info about all ESX hosts
    my $HOSTS = get_hosts();
    my $NETWORKS = get_networks();
    my $DATASTORES = get_datastores();
    my $FOLDERS = get_folders();
    # get a complete dump from vSphere - this is expensive and takes some time
    my $VM = get_all_vm_data();
    
    # $LAB describes our internal view of the lab that lml manages
    # used mainly to react to renamed VMs or VMs with changed MAC adresses
    push( @error, maintain_labfile( $C, $VM, $HOSTS, $NETWORKS, $DATASTORES, $FOLDERS ) );

    # if errors occured, print them out
    if ( scalar(@error) ) {
        print STDERR "ERROR: " . join( "\nERROR: ", @error ) . "\n";
        exit 1;
    }
}
