#!/usr/bin/env perl
use strict;
use warnings;

use Data::Dumper qw( Dumper );
use English qw( -no_match_vars );
use Getopt::Long;
use Pod::Usage;

use lib "lib";
use Provision::Unix;
use Provision::Unix::Utility;
use Provision::Unix::VirtualOS;

my $prov = Provision::Unix->new( debug => 0 );
my $util = Provision::Unix::Utility->new( prov => $prov, debug => 0);

Getopt::Long::GetOptions(
    'action=s'        => \my $action,
    'name=s'          => \my $name,
    'ip=s'            => \my $ip,

    'template=s'      => \my $template,
    'config=s'        => \my $config,
    'disk_root=s'     => \my $disk_root,
    'disk_size=s'     => \my $disk_size,
    'hostname=s'      => \my $hostname,
    'password=s'      => \my $password,
    'nameservers=s'   => \my $nameservers,
    'searchdomain=s'  => \my $searchdomain,

    'new_node=s'      => \my $new_node,
    'connection_test' => \my $connection_test,
    'verbose'         => \my $debug,
    'version'         => \my $version,
    'help'            => \my $help,
) or die 'error parsing command line options';

pod2usage( { -verbose => 3 } ) if $help;
$prov->get_version() and exit if $version;
$EUID == 0 or die 'Virtual OS functions require root privileges.';
my $vos  = Provision::Unix::VirtualOS->new( prov => $prov );

my %actions = map { $_ => 1 } qw/ create destroy start stop restart disable
     enable modify probe mount unmount console set_password migrate /;

my $questions = {
    action    => "the action to perform: \n\tcreate, destroy\n\tstart, stop, restart\n\tdisable, enable, mount, unmount, modify, console, probe",
    name      => "the virtual environment name/ID",
    ip        => "the IP address[es] (space delimited)",

    template  => "the OS template/tarball to use",
    config    => "the configuration file",
    disk_root => "the path to the virtual OS root",
    disk_size => "the disk size (limit) ",
    hostname  => "the virtual hostname",
    password  => "the root password",
    nameservers  => "the nameservers (for /etc/resolv.conf)",
    searchdomain  => "the search domain (for /etc/resolv.conf)",
};

$action ||= $util->ask( $questions->{action}, default=>'create' );
$action = lc($action);

pod2usage( { -verbose => 1 } ) if !$actions{$action};

$name ||= $util->ask( $questions->{name} );
$debug = defined $debug ? $debug : 0;

my %request = ( debug => $debug, fatal => 0, name => lc($name) );

  $action eq 'create'   ? create()
: $action eq 'destroy'  ? destroy()
: $action eq 'start'    ? start()
: $action eq 'stop'     ? stop()
: $action eq 'restart'  ? restart()
: $action eq 'disable'  ? disable()
: $action eq 'enable'   ? enable()
: $action eq 'modify'   ? modify()
: $action eq 'probe'    ? probe()
: $action eq 'mount'    ? mount()
: $action eq 'unmount'  ? unmount()
: $action eq 'console'  ? console()
: $action eq 'set_password' ? set_password()
: $action eq 'migrate'  ? migrate()
: die "oops, the action ($action) is invalid\n";

$prov->error( fatal => 0 ) if $debug;
print "done.\n";
exit;

sub create {

    $request{ip}       = $ip       || $util->ask( $questions->{ip} );
    $request{hostname} = $hostname || $util->ask( $questions->{hostname} );
    $request{template} = $template || $util->ask( $questions->{template}, 
        default => 'centos-5-i386-default' );
    $request{config}   = $config   || $util->ask( $questions->{config} );
    $request{password} = $password || $util->ask( $questions->{password} );
    $request{nameservers} = $nameservers || $util->ask( $questions->{nameservers} );
    $request{searchdomain} = $searchdomain || $util->ask( $questions->{searchdomain} );

    warn "creating!\n";
    $prov->audit("dispatching creation request");

    foreach ( keys %request ) { delete $request{$_} if ! defined $request{$_}; };
    print Dumper( $vos->create( %request ) );
}

sub destroy {
    foreach ( keys %request ) { delete $request{$_} if ! defined $request{$_}; };
    print Dumper( $vos->destroy( %request ) );
}
sub start {
    foreach ( keys %request ) { delete $request{$_} if ! defined $request{$_}; };
    print Dumper( $vos->start( %request ) );
}
sub stop {
    foreach ( keys %request ) { delete $request{$_} if ! defined $request{$_}; };
    print Dumper( $vos->stop( %request ) );
}
sub restart {
    foreach ( keys %request ) { delete $request{$_} if ! defined $request{$_}; };
    print Dumper( $vos->restart( %request ) );
}
sub disable {
    foreach ( keys %request ) { delete $request{$_} if ! defined $request{$_}; };
    print Dumper( $vos->disable( %request ) );
}
sub enable {
    foreach ( keys %request ) { delete $request{$_} if ! defined $request{$_}; };
    print Dumper( $vos->enable( %request ) );
}
sub modify {
    $request{hostname} = $hostname || $util->ask( $questions->{hostname} );
    $request{password} = $password || $util->ask( $questions->{password} );
    $request{ip}       = $ip       || $util->ask( $questions->{ip} );
    foreach ( keys %request ) { delete $request{$_} if ! defined $request{$_}; };
    print Dumper( $vos->modify( %request ) );
}
sub probe {
    foreach ( keys %request ) { delete $request{$_} if ! defined $request{$_}; };
    print Dumper( $vos->get_status( %request ) );
}
sub mount {
    foreach ( keys %request ) { delete $request{$_} if ! defined $request{$_}; };
    print Dumper( $vos->mount_disk_image( %request ) );
}
sub unmount {
    foreach ( keys %request ) { delete $request{$_} if ! defined $request{$_}; };
    print Dumper( $vos->unmount_disk_image( %request ) );
}
sub console {
    foreach ( keys %request ) { delete $request{$_} if ! defined $request{$_}; };
    print Dumper( $vos->get_console( %request ) );
}
sub set_password {
    $request{password} = $password || $util->ask( $questions->{password} );
    foreach ( keys %request ) { delete $request{$_} if ! defined $request{$_}; };
    print Dumper( $vos->set_password( %request ) );
}
sub migrate {
    $request{new_node} = $new_node || $util->ask( "the destination HW node hostname or IP" );
    $request{connection_test} = $connection_test || $util->ask( "only test the connection", default => 0 );
    foreach ( keys %request ) { delete $request{$_} if ! defined $request{$_}; };
    print Dumper( $vos->migrate( %request ) );
}

__END__

=head1 NAME 

prov_virtual - a command line interface for provisioning virtual machines

=head1 SYNOPSIS

    prov_virtual --action= [--name example.com]

Action is one of the following:

  create   - creates a new virtual environment/machine/server
  destroy  - remove a VE from the system
  start    - start up a VE
  stop     - shut down a VE
  restart  - restart a VE
  enable   - enable/restore a VE
  disable  - disable/suspend a VE
  modify   - make changes to an existing VE
  probe    - get status of a VE (returns a hash)

  --help     - display this help document

required arguments: action, name

optional arguments: ip, hostname, template, config, password, nameservers, searchdomain

=head1 USAGE
 
 prov_virtual --action=create  --name=8675309
 prov_virtual --action=destroy --name=9001
 prov_virtual --action=modify  --name=example.ve


=head1 DESCRIPTION
 
prov_virtual is a consistent command line interface for provisioning virtual environments on various virtualization platforms. Support is included for OpenVZ, Xen, and FreeBSD jails.

 
=head1 CONFIGURATION AND ENVIRONMENT

See the [VirtualOS] section in provision.conf

=head1 DEPENDENCIES
 
  Config::Tiny
  Getopt::Long
  Params::Validate
  Digest::MD5 
  LWP::UserAgent

=head1 AUTHOR
 
Matt Simerson, C<< <matt at tnpi.net> >>
 
 
=head1 LICENCE AND COPYRIGHT
 
Copyright (c) 2009 The Network People, Inc. (info@tnpi.net)

This module is free software; you can redistribute it and/or
modify it under the same terms as Perl itself. See L<perlartistic>.
 
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
