#!/usr/bin/perl

#
# Perl Core Modules
#
use Exception::Class;
use Getopt::Long;
use strict;

#
# VMware Lookup and SSO libraries
#
use VMware::SSOConnection;
use VMware::LookupService;
use VMware::VIRuntime;

#
# vApi runtime libraries
#
use Com::Vmware::Vapi::Protocol::ProtocolConnectionFactory;
use Com::Vmware::Vapi::Bindings::StubConfiguration;
use Com::Vmware::Vapi::Bindings::StubFactory;
use Com::Vmware::Vapi::Dsig::SecurityContextFactory;
use Com::Vmware::Vapi::Util::Logger
  qw(log_info log_dumper log_framework log_warning set_verbosity);

#
# Generated SDK's
#
use Com::Vmware::Cis::Session;
use Com::Vmware::Vcenter::Vm::GuestOS;
use Com::Vmware::Vcenter::VM;
use Com::Vmware::Vcenter::Vm::Power;
use Com::Vmware::Vcenter::Vm::Hardware;
use Com::Vmware::Vcenter::Vm::Hardware::Adapter::Scsi;
use Com::Vmware::Vcenter::Vm::Hardware::Disk;
use Com::Vmware::Vcenter::Vm::Hardware::ScsiAddressSpec;
use Com::Vmware::Vcenter::Vm::Hardware::Ethernet;
use Com::Vmware::Vcenter::Vm::Hardware::Boot;
use Com::Vmware::Vcenter::Vm::Hardware::Boot::Device;
use Com::Vmware::Vcenter::Vm::Hardware::Cdrom;
use Com::Vmware::Vcenter::Vm::Hardware::Cpu;
use Com::Vmware::Vcenter::Vm::Hardware::Memory;
use Com::Vmware::Vcenter::Vm::Hardware::Serial;
use Com::Vmware::Vcenter::Vm::Hardware::Parallel;
use Com::Vmware::Vcenter::Vm::Hardware::Floppy;

#
# Sample helper modules
#
use Vcenter::Helpers::PlacementHelper;
use Vcenter::Helpers::NetworkHelper;

#
# Demonstrates how to create a VM with system provided defaults
#
# Sample Prerequisites:
# The sample needs a datacenter and the following resources:
# - vm folder
# - datastore
# - cluster
# - A standard switch network
#

# Call main
&main();

sub main() {

	#
	# User inputs
	#
	my %params;
	GetOptions(
		\%params,       "server=s",       "lsurl=s",      "username=s",
		"password=s",   "privatekey:s",   "servercert:s", "cert:s",
		"vmfolder:s",   "datastore:s",  "clustername:s",
		"datacenter:s", "cleanup:s",      "help:s"
	  )
	  or die
"\nValid options are --server <server> --username <user> --password <password> --lsurl <lookup service url>
                         --privatekey <private key> --servercert <server cert> --cert <cert> --vmfolder <vmfolder name> --datastore <datastore name> --clustername <cluster name> --datacenter <datacenter name> --cleanup <value should be true or false> or --help\n";

	if ( defined( $params{'help'} ) ) {
		print "\nCommand to execute sample:\n";
		print
"default_vm.pl --server <server> --username <user> --password <password> --lsurl <lookup service url> \n";
		print
"               --privatekey <private key> --servercert <server cert> --cert <cert> --vmfolder <vmfolder name> --datastore <datastore name> --clustername <cluster name> --datacenter <datacenter name> --cleanup <value should be true or false> \n";
		exit;
	}

	if (
		   !defined( $params{'username'} )
		|| !defined( $params{'password'} )
		|| !defined( $params{'lsurl'} )
		|| !defined( $params{'server'} )
		|| !defined( $params{'vmfolder'} )
		|| !defined( $params{'datastore'} )
		|| !defined( $params{'clustername'} )
		|| !defined( $params{'datacenter'} )
		|| !defined( $params{'cleanup'} )

	  )
	{
		print
"\nMissing mandatory parameter(s) i.e. --server <server> --lsurl <lookup service url> --username <user> --password <password> --vmfolder <vmfolder name> --datastore <datastore name> --clustername <cluster name> --datacenter <datacenter name> --cleanup <value should be true or false> \n";
		exit;
	}

	my $ip              = $params{'server'};
	my $ls_url          = $params{'lsurl'};
	my $sso_url         = undef;
	my $username        = $params{'username'};
	my $password        = $params{'password'};
	my $private_key     = $params{'privatekey'};
	my $cert            = $params{'cert'};
	my $server_cert     = $params{'servercert'};
	my $vmfolder_name   = $params{'vmfolder'};
	my $datastore_name  = $params{'datastore'};
	my $cluster_name    = $params{'clustername'};
	my $datacenter_name = $params{'datacenter'};
	our $cleanup         = $params{'cleanup'};
	our $DEFAULT_VM_NAME = "Sample-Default-VM";
	our $vmGuestOS       = Com::Vmware::Vcenter::Vm::GuestOS::WINDOWS_9_64;
	our $defaultVMId;

	set_verbosity( 'level' => 3 );

	#
	# Get the SSO url
	#
	log_info( MSG => "Getting the SSO URL via Lookup Service..." );
	my $lookup_service = new LookupService( 'lookup_url' => $ls_url );
	$sso_url = $lookup_service->find_sso_url();

	#
	# Get the SSO token
	#
	log_info( MSG => $sso_url );

	log_info( MSG => "Getting the SSO token..." );
	my $ssoConnection = new SSOConnection( 'sso_url' => $sso_url );
	$ssoConnection->login(
		'user_name'   => $username,
		'password'    => $password,
		'public_key'  => $cert,
		'private_key' => $private_key
	);
	my $token = $ssoConnection->get_token();

	#
	# Create a VAPI transport connection
	#
	my $protocolConn =
	  new Com::Vmware::Vapi::Protocol::ProtocolConnectionFactory();
	my $config = $protocolConn->get_connection(
		'protocol_type' => 'https',
		'uri'           => "$ip/api"
	);

	#
	# Create a VAPI security context
	#
	my $scFactory = new Com::Vmware::Vapi::Dsig::SecurityContextFactory();
	my $samlTokenSecurityContext = $scFactory->create_saml_security_context(
		'token'       => $token,
		'private_key' => $private_key
	);
	my $stubConfig = new Com::Vmware::Vapi::Bindings::StubConfiguration();
	$stubConfig->set_security_context(
		security_context => $samlTokenSecurityContext );

	#
	# Get the instance of stub factory
	#
	my $stubFactory = new Com::Vmware::Vapi::Bindings::StubFactory(
		'api_provider' => $config->get_api_provider() );

	#
	# Get the Session Service
	#
	my $session = $stubFactory->create_stub(
		'service_name' => 'Com::Vmware::Cis::Session',
		'stub_config'  => $stubConfig
	);

	log_info( MSG => "Login in to VAPI server using token..." );
	my $sessionId = $session->create();
	log_info( MSG => "Got the Session Id" );

	#
	# Update the VAPI security context with session id
	#
	my $ssContext =
	  $scFactory->create_session_security_context( 'session_id' => $sessionId );

	$stubConfig->set_security_context( security_context => $ssContext );

	#
	# Get the VM Service
	#
	our $vm_service = $stubFactory->create_stub(
		'service_name' => 'Com::Vmware::Vcenter::VM',
		'stub_config'  => $stubConfig
	);

	#
	# Creates a VM on a cluster with selected Guest OS and name which
	# uses all the system provided defaults.
	#
	sub createDefaultVM() {
		my (%args)          = @_;
		my $vmPlacementSpec = $args{'vmPlacementSpec'};
		my $vm_createspec   = new Com::Vmware::Vcenter::VM::CreateSpec();
		$vm_createspec->set_guest_OS( 'guest_OS' => $vmGuestOS );
		$vm_createspec->set_name( 'name' => $DEFAULT_VM_NAME );
		$vm_createspec->set_placement( 'placement' => $vmPlacementSpec );
		log_info( MSG => "#### Example: Creating default VM with spec: '"
			  . $vm_createspec
			  . "'" );
		$defaultVMId = $vm_service->create( 'spec' => $vm_createspec );
		log_info( MSG => "Created default VM : '"
			  . $DEFAULT_VM_NAME
			  . "' with id: '"
			  . $defaultVMId
			  . "'" );
		my $vmInfo = $vm_service->get( 'vm' => $defaultVMId );

		#print Dumper($vmInfo);
		log_info( MSG => "Default VM Info:" );
		log_info( MSG => "   VM name:'" . $vmInfo->get_name() . "'" );
		log_info( MSG => "   VM Guest OS:'" . $vmInfo->get_guest_OS() . "'" );
	}

	#
	# Cleanup any data created by the sample run, if cleanup=true
	#
	sub cleanup() {
		log_info( MSG => "#### Deleting the Default VM" );
		if ( defined($defaultVMId) ) {
			$vm_service->delete( 'vm' => $defaultVMId );
		}
	}

	#Get a placement spec
	my $vmPlacementSpec =
	  Vcenter::Helpers::PlacementHelper::getPlacementSpecForCluster(
		'stubFactory'       => $stubFactory,
		'sessionStubConfig' => $stubConfig,
		'datacenterName'    => $datacenter_name,
		'clusterName'       => $cluster_name,
		'vmFolderName'      => $vmfolder_name,
		'datastoreName'     => $datastore_name
	  );

	# Create the VM
	&createDefaultVM( 'vmPlacementSpec' => $vmPlacementSpec );
	if ( $cleanup eq 'true' ) {
		&cleanup();
	}
    log_info( MSG => "#### Done!" );
}

# END
