From a438ff180dca08d5e6981aea63eb072333116216 Mon Sep 17 00:00:00 2001 From: Tim Lapawa Date: Fri, 13 Oct 2017 16:05:14 +0200 Subject: [PATCH 1/3] Added health report wich print missing VLANs from dvSwitch Health Check --- perl/getdvSwitchInfo.pl | 124 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 118 insertions(+), 6 deletions(-) diff --git a/perl/getdvSwitchInfo.pl b/perl/getdvSwitchInfo.pl index 13b4383..b4f19e2 100755 --- a/perl/getdvSwitchInfo.pl +++ b/perl/getdvSwitchInfo.pl @@ -1,5 +1,5 @@ #!/usr/bin/perl -w -# Author: William Lam +# Author: William Lam; Tim Lapawa # Website: www.virtuallyghetto.com # Reference: http://www.virtuallyghetto.com/2011/12/retrieving-information-from-distributed.html @@ -12,7 +12,7 @@ my %opts = ( 'list' => { type => "=s", - help => "Operation [all|summary|config|networkpool|portgroup|host|vm]", + help => "Operation [all|summary|config|networkpool|portgroup|host|vm|health]", required => 1, }, 'dvswitch' => { @@ -27,15 +27,25 @@ # validate options, and connect to the server Opts::parse(); Opts::validate(); -Util::connect(); +my $vim = Util::connect(); my $list = Opts::get_option('list'); my $dvswitch = Opts::get_option('dvswitch'); my $dvSwitches; -my $apiVersion = Vim::get_service_content()->about->version; +my $apiVersion = $vim->get_service_content()->about->version; if($dvswitch) { - $dvSwitches = Vim::find_entity_views(view_type => 'DistributedVirtualSwitch', filter => {'name' => $dvswitch}); + if ( $list eq 'health' ) { + $dvSwitches = Vim::find_entity_views(view_type => 'DistributedVirtualSwitch' + , filter => {'name' => $dvswitch} + , properties => [ 'name', 'runtime', 'config.host' ] + ); + } else { + $dvSwitches = Vim::find_entity_views(view_type => 'DistributedVirtualSwitch' + , filter => {'name' => $dvswitch} + , properties => { } + ); + } } else { $dvSwitches = Vim::find_entity_views(view_type => 'DistributedVirtualSwitch'); } @@ -289,9 +299,111 @@ } }; if($@) { - print "ERROR: Unable to query for entites connected to dvSwitch " . $@ . "\n"; + print "ERROR: Unable to query for entities connected to dvSwitch " . $@ . "\n"; } } + if($list eq "all" || $list eq "health") { + # * dvSwitch->runtime->hostMemberRuntime[] + # - lists all hosts of dvSwitch + # * + my $hostMemberRuntimeInfo = $dvs->{runtime}->{hostMemberRuntime}; + my %r = (); +# print " Check NIC Infos for host: \t'".$host->name."'\n\n"; + format STDOUT = + @<<<<<<<<<<<<<<<<<<<<<<<<<<< |@<<<<<< |@<<<<<<<<<<<<<<<<<<<<<<<<< |@<<<<<<<<<< |@<<<<<<<<<<<<<<<<<< |@<<<<<<<<<<<<<<<<<<<<< + $r{host}, $r{pnic}, $r{switch}, $r{address}, $r{port}, $r{missingvlans} +. + my $foundHealthCheckResults = undef; + foreach my $hostMember (@{$hostMemberRuntimeInfo}) { + if ( exists $hostMember->{healthCheckResult}) { + + my $hostRef = $hostMember->{host}; + my $hostView = Vim::get_view( mo_ref => $hostRef, properties => [ 'name', 'configManager'] ); + + if ($hostMember->status ne 'up') { + print ("\n".$hostView->name.color("red") . 'DOWN'.color('reset')); + next; + } + + my $netMgr = undef; + my $checkResults = $hostMember->{healthCheckResult}; + foreach my $checkResult (@{$checkResults}){ + if ( ref($checkResult) eq 'VMwareDVSVlanHealthCheckResult') { + %r = ( + host => $hostView->name, + pnic => '', + switch => '', + address => '', + port => '', + missingvlans => '', + ); + + # find physical uplink for DVS uplinkPort + # dvs-83&doPath=config.host + # + my $dvsHostMembers = $dvs->{'config.host'}; + $netMgr = Vim::get_view(mo_ref => $hostView->configManager->networkSystem) if not $netMgr; + foreach my $member (@{$dvsHostMembers}){ + my $dvsConfigHostrefValue = $member->{config}->{host}->{value}; + if ($hostRef->{value} eq $dvsConfigHostrefValue) { + my $pnicSpecs = $member->{config}->{backing}->{pnicSpec}; + foreach my $pnic (@{$pnicSpecs}){ + if ($pnic->{uplinkPortKey} eq $checkResult->{uplinkPortKey}) { + $r{pnic} = $pnic->{pnicDevice}; + } + } + } + } + + # + # find CDP infos for pnic and host + # + my @physicalNicHintInfo = $netMgr->QueryNetworkHint(); + foreach (@physicalNicHintInfo) { + foreach ( @{$_} ) { + next if ($r{pnic} ne $_->device); # skip wrong device + if(defined($_->connectedSwitchPort)) { + $r{switch} = $_->connectedSwitchPort->devId; + $r{address} = $_->connectedSwitchPort->address; + $r{port} = $_->connectedSwitchPort->portId; + } + } + } + my $untrunkedVlans = $checkResult->{untrunkedVlan}; + my %missingVlans = (); + foreach my $untrunkedVlan (@{$untrunkedVlans}){ + my $start = int($untrunkedVlan->{start}); + my $end = int($untrunkedVlan->{end}); + if ( $start eq $end ) { + $missingVlans{$start} = 1; + } else { + for (my $i = $start; $i <= $end; $i++){ + $missingVlans{$i} = 1; + } + } + } + my @sorted = keys %missingVlans; + @sorted = sort {$a <=> $b} @sorted; + $r{missingvlans} = join (',', @sorted); + if (!$foundHealthCheckResults) { + print " Host | pnic | switch | address | port | missing VLANs \n"; + print " -----------------------------+--------+---------------------------+------------+--------------------+------------------------\n"; + } + $foundHealthCheckResults ||= $hostMember; + write; + } # foreach VMwareDVSVlanHealthCheckResult + } # foreach healthCheckResult + } # if healthCheckResult + } # foreach $hostMemberRuntimeInfo + if ( ! $foundHealthCheckResults) { + print 'Could not find any DVSwitch Health check results.'; + } + print "\n"; + } +} +if (!scalar @{ $dvSwitches}) { + print "WARN: Could not find dvSwitch: '".$dvswitch."' with service url '".$vim->{service_url}."'. DONE!"; } + Util::disconnect(); From d5da21a2373d7540d9cc97a9a08e5857e814d07b Mon Sep 17 00:00:00 2001 From: Tim Lapawa Date: Mon, 16 Oct 2017 15:04:25 +0200 Subject: [PATCH 2/3] Changed formatting output of dvswitch health report. --- perl/getdvSwitchInfo.pl | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/perl/getdvSwitchInfo.pl b/perl/getdvSwitchInfo.pl index b4f19e2..4899e72 100755 --- a/perl/getdvSwitchInfo.pl +++ b/perl/getdvSwitchInfo.pl @@ -32,7 +32,10 @@ my $list = Opts::get_option('list'); my $dvswitch = Opts::get_option('dvswitch'); my $dvSwitches; -my $apiVersion = $vim->get_service_content()->about->version; +my $sc = $vim->get_service_content(); +my $apiVersion = $sc->about->version; + +print ("vCenterServer: ".color("yellow"). $vim->{service_url}. color('reset').' - '. color('yellow'). $sc->about->fullName . color("reset"). "\n"); if($dvswitch) { if ( $list eq 'health' ) { @@ -51,7 +54,7 @@ } foreach my $dvs (sort{$a->name cmp $b->name} @$dvSwitches) { - print color("yellow") . $dvs->name . "\n" . color("reset"); + print 'dvSwitch: '.color("yellow") . $dvs->name . "\n" . color("reset"); if($list eq "all" || $list eq "summary") { print "UUID: " . color("cyan") . $dvs->summary->uuid . "\n" . color("reset"); print "Description: " . color("cyan") . ($dvs->summary->description ? $dvs->summary->description : "N/A") . "\n" . color("reset"); @@ -310,8 +313,8 @@ my %r = (); # print " Check NIC Infos for host: \t'".$host->name."'\n\n"; format STDOUT = - @<<<<<<<<<<<<<<<<<<<<<<<<<<< |@<<<<<< |@<<<<<<<<<<<<<<<<<<<<<<<<< |@<<<<<<<<<< |@<<<<<<<<<<<<<<<<<< |@<<<<<<<<<<<<<<<<<<<<< - $r{host}, $r{pnic}, $r{switch}, $r{address}, $r{port}, $r{missingvlans} + @<<<<<<<<<<<<<<<<<<<<<<<<<<< |@<<<<<< |@<<<<<<<<<<<<<<<<<<<<<<<<<... |@<<<<<<<<<<<<<<< |@<<<<<<<<<<<<<<<<<< |@* + $r{host}, $r{pnic}, $r{switch}, $r{address}, $r{port}, $r{missingvlans} . my $foundHealthCheckResults = undef; foreach my $hostMember (@{$hostMemberRuntimeInfo}) { @@ -342,7 +345,7 @@ # dvs-83&doPath=config.host # my $dvsHostMembers = $dvs->{'config.host'}; - $netMgr = Vim::get_view(mo_ref => $hostView->configManager->networkSystem) if not $netMgr; + $netMgr ||= Vim::get_view(mo_ref => $hostView->configManager->networkSystem); foreach my $member (@{$dvsHostMembers}){ my $dvsConfigHostrefValue = $member->{config}->{host}->{value}; if ($hostRef->{value} eq $dvsConfigHostrefValue) { @@ -382,12 +385,12 @@ } } } - my @sorted = keys %missingVlans; - @sorted = sort {$a <=> $b} @sorted; + my @sorted = sort {$a <=> $b} keys %missingVlans;; $r{missingvlans} = join (',', @sorted); if (!$foundHealthCheckResults) { - print " Host | pnic | switch | address | port | missing VLANs \n"; - print " -----------------------------+--------+---------------------------+------------+--------------------+------------------------\n"; + + print " Host | pnic | switch | address | port | missing VLANs \n"; + print " -----------------------------+--------+------------------------------+-----------------+--------------------+------------------------\n"; } $foundHealthCheckResults ||= $hostMember; write; @@ -399,8 +402,8 @@ print 'Could not find any DVSwitch Health check results.'; } print "\n"; - } -} + } # if --list all|health +} # foreach @$dvSwitches if (!scalar @{ $dvSwitches}) { print "WARN: Could not find dvSwitch: '".$dvswitch."' with service url '".$vim->{service_url}."'. DONE!"; } From c8d7d99a1c106f4ac3637923542a13f91c8ac053 Mon Sep 17 00:00:00 2001 From: Tim Lapawa Date: Mon, 14 Jan 2019 14:17:47 +0100 Subject: [PATCH 3/3] Added DVSwitch health check status page to getdvSwitchInfo.pl --- perl/getdvSwitchInfo.pl | 35 +++++++++++++++++++---------- perl/sessionManagement.pl | 46 +++++++++++++++++++++++++++++++++++---- 2 files changed, 65 insertions(+), 16 deletions(-) diff --git a/perl/getdvSwitchInfo.pl b/perl/getdvSwitchInfo.pl index 4899e72..a6a0893 100755 --- a/perl/getdvSwitchInfo.pl +++ b/perl/getdvSwitchInfo.pl @@ -37,20 +37,20 @@ print ("vCenterServer: ".color("yellow"). $vim->{service_url}. color('reset').' - '. color('yellow'). $sc->about->fullName . color("reset"). "\n"); +my $dvSwitchProperties = {}; +if ($list eq 'health') { + $dvSwitchProperties = [ 'name', 'runtime', 'config.host', 'config.healthCheckConfig' ]; +} + if($dvswitch) { - if ( $list eq 'health' ) { - $dvSwitches = Vim::find_entity_views(view_type => 'DistributedVirtualSwitch' - , filter => {'name' => $dvswitch} - , properties => [ 'name', 'runtime', 'config.host' ] - ); - } else { - $dvSwitches = Vim::find_entity_views(view_type => 'DistributedVirtualSwitch' + $dvSwitches = Vim::find_entity_views(view_type => 'DistributedVirtualSwitch' , filter => {'name' => $dvswitch} - , properties => { } + , properties => $dvSwitchProperties ); - } } else { - $dvSwitches = Vim::find_entity_views(view_type => 'DistributedVirtualSwitch'); + $dvSwitches = Vim::find_entity_views(view_type => 'DistributedVirtualSwitch' + , properties => $dvSwitchProperties + ); } foreach my $dvs (sort{$a->name cmp $b->name} @$dvSwitches) { @@ -328,6 +328,11 @@ next; } + if ($hostView->name eq 'ffm30vmwzst0112.mhs.msys.net') { + print 'found it'; + } + + my $netMgr = undef; my $checkResults = $hostMember->{healthCheckResult}; foreach my $checkResult (@{$checkResults}){ @@ -398,8 +403,14 @@ } # foreach healthCheckResult } # if healthCheckResult } # foreach $hostMemberRuntimeInfo - if ( ! $foundHealthCheckResults) { - print 'Could not find any DVSwitch Health check results.'; + + if ( ! $foundHealthCheckResults ) { + my $checkConfigs = $dvs->{'config.healthCheckConfig'}; + if ( lc ($checkConfigs->[0]->{'enable'}) ) { + print '** Could not find any DVSwitch Health check results.'.color('red').' Please reconfigure health check to get new results.'.color('reset'); + } else { + print '** DVSwitch Health check is deactivated. '.color('red').'Please enable and rerun script to collect results.'.color('reset'); + } } print "\n"; } # if --list all|health diff --git a/perl/sessionManagement.pl b/perl/sessionManagement.pl index e421f97..cc98946 100755 --- a/perl/sessionManagement.pl +++ b/perl/sessionManagement.pl @@ -12,14 +12,24 @@ my %opts = ( 'operation' => { type => "=s", - help => "Operation [list|disconnect]", + help => "Operation [list|disconnect|terminateidle]", required => 1, }, - 'sessionkey' => { + 'sessionkey' => { type => "=s", help => "Session key to disconnect", required => 0, }, + 'idle_hours' =>{ + type => "=i", + help => "Select session to terminate if they are idle for N hours. Defaults to 36.", + required => 0, + }, + 'dry' => { + type => "", + help => "Enable dry run. Inspect but skip real actions.", + required => 0, + }, ); # validate options, and connect to the server Opts::add_options(%opts); @@ -31,11 +41,17 @@ my $operation = Opts::get_option ('operation'); my $sessionkey = Opts::get_option ('sessionkey'); +my $opt_idle_hours = Opts::get_option( 'idle_hours'); +my $opt_dry = Opts::get_option('dry'); -my $sessionMgr = Vim::get_view(mo_ref => Vim::get_service_content()->sessionManager); +my $sc = Vim::get_service_content(); +my $sessionMgr = Vim::get_view(mo_ref => $sc->sessionManager); my $sessionList = eval {$sessionMgr->sessionList || []}; my $currentSessionkey = $sessionMgr->currentSession->key; +print 'Connected to vCenter Server: '. $sessionMgr->{vim}->{service_url}."\n"; +print 'Checking #'. scalar @$sessionList . " user sessions.\n"; + if($operation eq "list") { foreach my $session (@$sessionList) { if($session->key eq $currentSessionkey) { @@ -50,13 +66,35 @@ print "Sessionkey : " . $session->key . "\n\n"; } } elsif($operation eq "disconnect") { + Opts::assert_usage( defined $sessionkey ,"Operation 'disconnect' expects option '--sessionkey '." ); print "Disconnecting sessionkey: " . $sessionkey . " ...\n"; eval { - $sessionMgr->TerminateSession(sessionId => [$sessionkey]); + unless ($opt_dry) {$sessionMgr->TerminateSession(sessionId => [$sessionkey]);} }; if($@) { print "Error: " . $@ . "\n"; } +} elsif ( $operation eq 'terminateidle' ){ + my $max_idletime = abs ($opt_idle_hours || 36); + + my $now = time; + foreach my $session (@$sessionList) { + if($session->key eq $currentSessionkey) { + print "Username: " . $session->userName . " (CURRENT SESSION) SKIP!\n"; + next; + } + + my $idletime = (time - str2time($session->lastActiveTime))/3600; + if ( $idletime > $max_idletime) { + print "Terminating user Session ". $session->userName; + eval { + unless ($opt_dry) {$sessionMgr->TerminateSession(sessionId => [$session->key]);} + }; + if($@) { + print "Error: " . $@ . "\n"; + } + } # if limit reached + } # foreach session } else { print "Invalid operation!\n"; }