#!/usr/bin/perl -w ################################################################## # Author: William Lam # Email: william2003[at]gmail[dot]com # 03/05/2009 # http://www.engineering.ucsb.edu/~duonglt/vmware/ ################################################################## use strict; use warnings; use Math::BigInt; use Tie::File; use POSIX qw/mktime/; use Getopt::Long; use VMware::VIRuntime; use VMware::VILib; ########### DO NOT MODIFY PAST HERE ########### ################################ # VERSION ################################ my $version = "0.1"; $Util::script_version = $version; ################################ # DEMO MODE # 0 = no, 1 = yes ################################ my $enable_demo_mode = 0; ################ #GLOBAL VARS ################ my $opt_type; my $host_type; my $host_view; my $cluster_count = 0; my $cluster_view; my $cluster_views; my $datacenter_view; my $datacenter_name; my $start_time; my $end_time; my $run_time; my $my_time; my @jump_tags = (); my $randomHostName; my $content; my $report_name; my %opts = ( datacenter => { type => "=s", help => "The name of a vCenter datacenter", required => 0, }, cluster => { type => "=s", help => "The name of a vCenter cluster", required => 0, }, type => { type => "=s", help => "Type: [vcenter|datacenter|cluster|host]\n", required => 1, }, report => { type => "=s", help => "The name of the report to output. Please add \".html\" extension", required => 0, }, ); # validate options, and connect to the server Opts::add_options(%opts); # validate options, and connect to the server Opts::parse(); Opts::validate(); Util::connect(); ############################ # PARSE COMMANDLINE OPTIONS ############################# if (Opts::option_is_set ('type')) { # get ServiceContent $content = Vim::get_service_content(); $host_type = $content->about->apiType; $opt_type = Opts::get_option('type'); #################### # SINGLE ESX HOST #################### if( ($opt_type eq 'host') && (!Opts::option_is_set('cluster')) && ($host_type eq 'HostAgent') ) { $host_view = Vim::find_entity_views(view_type => 'HostSystem'); if (!$host_view) { die "ESX/ESXi host was not found\n"; } } ##################### # vCENTER + CLUSTER ##################### elsif( ($opt_type eq 'cluster') && ($host_type eq 'VirtualCenter') ) { if ( Opts::option_is_set('cluster') ) { my $cluster_name = Opts::get_option('cluster'); $cluster_view = Vim::find_entity_view(view_type => 'ClusterComputeResource',filter => { name => $cluster_name }); if(!$cluster_view) { die "Cluster: \"$cluster_name\" was not found\n"; } } else { Fail("\n--cluster parameter required with the name of a valid vCenter Cluster\n\n"); } } ######################## # vCENTER + DATACENTER ######################## elsif( ($opt_type eq 'datacenter') && ($host_type eq 'VirtualCenter') ) { if ( Opts::option_is_set('datacenter') ) { $datacenter_name = Opts::get_option('datacenter'); my $datacenter_view = Vim::find_entity_view(view_type => 'Datacenter',filter => { name => $datacenter_name}); if(!$datacenter_view) { die "Datacenter: \"$datacenter_name\" was not found\n"; } $cluster_views = Vim::find_entity_views(view_type => 'ClusterComputeResource',begin_entity => $datacenter_view); if(!$cluster_views) { die "No clusters were found in this datacenter\n"; } } else { Fail("\n--datacenter parameter required with the name of a valid vCenter Datacenter\n\n"); } } ################## # vCENTER ALL ################## elsif( ($opt_type eq 'vcenter') && (!Opts::option_is_set('cluster')) && ($host_type eq 'VirtualCenter') ) { $cluster_views = Vim::find_entity_views(view_type => 'ClusterComputeResource'); Fail ("No clusters found.\n") unless (@$cluster_views); } else { die "Invalid Input, ensure your selection is one of the supported use cases \n\n\tServer: vCenter => [vcenter|datacenter|cluster]\n\tServer: ESX/ESXi Host => [host]\n"; } #if report name is not specified, default output if (Opts::option_is_set ('report')) { $report_name = Opts::get_option('report'); } else { $report_name = "cdp.html"; } } ### CODE START ### ################################# # PRINT HTML HEADER/CSS ################################# printStartHeader(); ######################################### # PRINT vCENTER or HOST BUILD/SUMMARY ######################################### printBuildSummary(); ######################################### # PRINT vCENTER INFO ######################################### if ($opt_type eq 'vcenter') { foreach my $cluster (@$cluster_views) { $cluster_count += 1; my $hosts = Vim::get_views (mo_ref_array => $cluster->host); if(@$hosts) { getVswitchInfo($hosts); } } } ######################################### # PRINT SPECIFIC DATACENTER INFO ######################################### elsif ($opt_type eq 'datacenter') { printDatacenterName($datacenter_name); foreach my $cluster (@$cluster_views) { $cluster_count += 1; printClusterSummary($cluster); my $hosts = Vim::get_views (mo_ref_array => $cluster->host); if(@$hosts) { getVswitchInfo($hosts); } } } ######################################### # PRINT SPECIFIC CLUSTER INFO ######################################### elsif ($opt_type eq 'cluster') { $cluster_count += 1; printClusterSummary($cluster_view); foreach my $cluster (@$cluster_views) { $cluster_count += 1; printClusterSummary($cluster); my $hosts = Vim::get_views (mo_ref_array => $cluster->host); if(@$hosts) { getVswitchInfo($hosts); } } } elsif ($opt_type eq 'host' ) { getVswitchInfo($host_view); } ################################# # CLOSE HTML REPORT ################################# printCloseHeader(); Util::disconnect(); ### CODE END ### ########################### # # HELPER FUNCTIONS # ########################### sub getVswitchInfo { my ($hosts) = @_; my %cdp_enabled = (); my %cdp_blob = (); foreach my $host(@$hosts) { my $netMgr = Vim::get_view(mo_ref => $host->configManager->networkSystem); my @physicalNicHintInfo = $netMgr->QueryNetworkHint(); foreach (@physicalNicHintInfo){ foreach ( @{$_} ){ if(defined($_->connectedSwitchPort)) { my $device = $_->device; my $port = $_->connectedSwitchPort->portId; my $address = defined $_->connectedSwitchPort->address ? $_->connectedSwitchPort->address : "N/A"; my $cdp_ver = defined $_->connectedSwitchPort->cdpVersion ? $_->connectedSwitchPort->cdpVersion : "N/A"; my $devid = defined $_->connectedSwitchPort->devId ? $_->connectedSwitchPort->devId : "N/A"; my $duplex = defined $_->connectedSwitchPort->fullDuplex ? ($_->connectedSwitchPort->fullDuplex ? "YES" : "NO") : "N/A"; my $platform = defined $_->connectedSwitchPort->hardwarePlatform ? $_->connectedSwitchPort->hardwarePlatform : "N/A"; my $prefix = defined $_->connectedSwitchPort->ipPrefix ? $_->connectedSwitchPort->ipPrefix : "N/A"; my $location = defined $_->connectedSwitchPort->location ? $_->connectedSwitchPort->location : "N/A"; my $mgmt_addr = defined $_->connectedSwitchPort->mgmtAddr ? $_->connectedSwitchPort->mgmtAddr : "N/A"; my $d_mtu = defined $_->connectedSwitchPort->mtu ? $_->connectedSwitchPort->mtu : "N/A"; my $samples = defined $_->connectedSwitchPort->samples ? $_->connectedSwitchPort->samples : "N/A"; my $sys_ver = defined $_->connectedSwitchPort->softwareVersion ? $_->connectedSwitchPort->softwareVersion : "N/A"; my $sys_name = defined $_->connectedSwitchPort->systemName ? $_->connectedSwitchPort->systemName : "N/A"; my $sys_oid = defined $_->connectedSwitchPort->systemOID ? $_->connectedSwitchPort->systemOID : "N/A"; my $timeout = defined $_->connectedSwitchPort->timeout ? $_->connectedSwitchPort->timeout : "N/A"; my $ttl = defined $_->connectedSwitchPort->ttl ? $_->connectedSwitchPort->ttl : "N/A"; my $vlan = defined $_->connectedSwitchPort->vlan ? $_->connectedSwitchPort->vlan : "N/A"; my $blob .= "".$device."".$mgmt_addr."".$address."".$prefix."".$location."".$sys_name."".$sys_ver."".$sys_oid."".$platform."".$devid."".$cdp_ver."".$duplex."".$d_mtu."".$timeout."".$ttl."".$vlan."".$samples."\n"; $cdp_blob{$device} = $blob; $cdp_enabled{$device} = $port; } } } my $vswitches = $host->config->network->vswitch; my $vswitch_string = ""; foreach my $vSwitch (@$vswitches) { my $pNicName = ""; my $mtu = ""; my $cdp_vswitch = ""; my $found = 0; my $device_name = ""; my $pNics = $vSwitch->pnic; my $pNicKey = ""; foreach (@$pNics) { $pNicKey = $_; if ($pNicKey ne "") { $pNics = $netMgr->networkInfo->pnic; foreach my $pNic (@$pNics) { if ($pNic->key eq $pNicKey) { $pNicName = $pNicName ? ("$pNicName," . $pNic->device) : $pNic->device; if($cdp_enabled{$pNic->device}) { $cdp_vswitch = $cdp_enabled{$pNic->device}; } else { $cdp_vswitch = ""; } } } } } $mtu = $vSwitch->{mtu} if defined($vSwitch->{mtu}); $vswitch_string .= "VSWITCH NAMENUM OF PORTSUSED PORTSMTUUPLINKSCDP ENABLED".$vSwitch->name."".$vSwitch->numPorts."".($vSwitch->numPorts - $vSwitch->numPortsAvailable)."".$vSwitch->{mtu}."".$pNicName."".$cdp_vswitch.""; $vswitch_string .= "PORTGROUP NAMEVLAN IDUSED PORTSUPLINKS"; my $portGroups = $vSwitch->portgroup; foreach my $port (@$portGroups) { my $pg = FindPortGroupbyKey ($netMgr, $vSwitch->key, $port); next unless (defined $pg); my $usedPorts = (defined $pg->port) ? $#{$pg->port} + 1 : 0; if($enable_demo_mode eq 1) { $vswitch_string .= "HIDE MY PGHIDE MY VLAN ID".$usedPorts."".$pNicName.""; } else { $vswitch_string .= "".$pg->spec->name."".$pg->spec->vlanId."".$usedPorts."".$pNicName.""; } } } print REPORT_OUTPUT "
VSWITCH(s)",$vswitch_string,"
\n"; my $cdp_string = ""; for my $key ( keys %cdp_blob ) { my $value = $cdp_blob{$key}; $cdp_string .= $value; } print REPORT_OUTPUT "
CDP SUMMARY\n",$cdp_string,"
DEVICEMGMT ADDRESSDEVICE ADDRESSIP PREFIXLOCATIONSYSTEM NAMESYSTEM VERSIONSYSTEM OIDPLATFORMDEVICE IDCDP VERFULL DUPLEXMTUTIMEOUTTTLVLAN IDSAMPLES
\n"; } } sub FindPortGroupbyKey { my ($network, $vSwitch, $key) = @_; my $portGroups = $network->networkInfo->portgroup; foreach my $pg (@$portGroups) { return $pg if (($pg->vswitch eq $vSwitch) && ($key eq $pg->key)); } return undef; } sub printBuildSummary { my $print_type; if ($content->about->apiType eq 'VirtualCenter') { $print_type = "VMware vCenter"; } else { $print_type = "ESX/ESXi"; } print REPORT_OUTPUT "

$print_type:

\n"; print REPORT_OUTPUT "\n"; print REPORT_OUTPUT "\n"; print REPORT_OUTPUT ""; print REPORT_OUTPUT "\n"; print REPORT_OUTPUT ""; print REPORT_OUTPUT "
BUILDVERSIONFULL NAME
",$content->about->build,"",$content->about->version,"",$content->about->fullName,"
\n"; #please do not touch this, else the jump tags will break print REPORT_OUTPUT "
\n"; print REPORT_OUTPUT "\n//\n"; } sub printStartHeader { print "Generating VMware vSwitch Report $version \"$report_name\" ...\n\n"; print "This can take a few minutes depending on environment size. \nGet a cup of coffee/tea and check out http://www.engineering.ucsb.edu/~duonglt/vmware/\n"; $my_time = "Date: ".giveMeDate('MDYHMS'); $start_time = time(); open(REPORT_OUTPUT, ">$report_name"); print REPORT_OUTPUT "\n"; print REPORT_OUTPUT "VMware vSwitch Report $version - $my_time\n"; print REPORT_OUTPUT "\n"; print REPORT_OUTPUT "\n"; print REPORT_OUTPUT "\n

VMware vSwitch Report $version

\n"; print REPORT_OUTPUT "$my_time\n"; } sub giveMeDate { my ($date_format) = @_; my %dttime = (); my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); ### begin_: initialize DateTime number formats $dttime{year } = sprintf "%04d",($year + 1900); ## four digits to specify the year $dttime{mon } = sprintf "%02d",($mon + 1); ## zeropad months $dttime{mday } = sprintf "%02d",$mday; ## zeropad day of the month $dttime{wday } = sprintf "%02d",$wday + 1; ## zeropad day of week; sunday = 1; $dttime{yday } = sprintf "%02d",$yday; ## zeropad nth day of the year $dttime{hour } = sprintf "%02d",$hour; ## zeropad hour $dttime{min } = sprintf "%02d",$min; ## zeropad minutes $dttime{sec } = sprintf "%02d",$sec; ## zeropad seconds $dttime{isdst} = $isdst; if($date_format eq 'MDYHMS') { $my_time = "$dttime{mon}-$dttime{mday}-$dttime{year} $dttime{hour}:$dttime{min}:$dttime{sec}"; } elsif ($date_format eq 'YMD') { $my_time = "$dttime{year}-$dttime{mon}-$dttime{mday}"; } return $my_time; } sub printCloseHeader { print REPORT_OUTPUT "

\n"; print REPORT_OUTPUT "
Author: William Lam
\n"; print REPORT_OUTPUT "
Generated using: cdp.pl
\n"; print REPORT_OUTPUT "
™Primp Industries
\n"; close(REPORT_OUTPUT); my @lines; my $jump_string = ""; tie @lines, 'Tie::File', $report_name or die; for (@lines) { if (//) { foreach (@jump_tags) { if( ($_ =~ /^CL/) ) { my $tmp_string = substr($_,2); $jump_string .= $tmp_string; } else { $jump_string .= $_; } } $_ = "\n$jump_string"; last; } } untie @lines; $end_time = time(); $run_time = $end_time - $start_time; print "\nStart Time: ",&formatTime(str => scalar localtime($start_time)),"\n"; print "End Time: ",&formatTime(str => scalar localtime($end_time)),"\n"; if ($run_time < 60) { print "Duration : ",$run_time," Seconds\n\n"; } else { print "Duration : ",&restrict_num_decimal_digits($run_time/60,2)," Minutes\n\n"; } } sub Fail { my ($msg) = @_; Util::disconnect(); die ($msg); exit (); } #http://www.infocopter.com/perl/format-time.html sub formatTime(%) { my %args = @_; $args{'str'} ||= ''; # e.g. Mon Jul 3 12:59:28 2006 my @elems = (); foreach (split / /, $args{'str'}) { next unless $_; push(@elems, $_); } my ($weekday, $month, $mday, $time, $yyyy) = split / /, join(' ', @elems); my %months = ( Jan => 1, Feb => 2, Mar => 3, Apr => 4, May => 5, Jun => 6, Jul => 7, Aug => 8, Sep => 9, Oct => 10, Nov => 11, Dec => 12 ); my $s = substr($time, 6,2); my $m = substr($time, 3,2); my $h = substr($time, 0, 2); my $dd = sprintf('%02d', $mday); my $mm_num = sprintf('%02d', $months{$month}); my $formatted = "$mm_num\-$dd\-$yyyy $h:$m:$s"; #my $formatted = "$yyyy$mm_num$dd$h$m$s"; $formatted; }