2018-09-12 05:53:46 +08:00
package vsphere
import (
"context"
"crypto/tls"
2023-03-13 19:19:49 +08:00
"net/url"
2020-08-27 00:58:28 +08:00
"os"
"strings"
2018-09-12 05:53:46 +08:00
"testing"
"time"
"github.com/stretchr/testify/require"
2018-11-07 06:22:43 +08:00
"github.com/vmware/govmomi/object"
2018-09-12 05:53:46 +08:00
"github.com/vmware/govmomi/simulator"
2019-02-13 06:05:14 +08:00
"github.com/vmware/govmomi/vim25/mo"
2018-11-07 06:22:43 +08:00
"github.com/vmware/govmomi/vim25/types"
2021-11-18 22:22:43 +08:00
"github.com/influxdata/telegraf/config"
2024-10-02 02:49:53 +08:00
common_tls "github.com/influxdata/telegraf/plugins/common/tls"
2021-11-18 22:22:43 +08:00
"github.com/influxdata/telegraf/testutil"
2018-09-12 05:53:46 +08:00
)
func defaultVSphere ( ) * VSphere {
return & VSphere {
2019-09-24 06:39:50 +08:00
Log : testutil . Logger { } ,
2018-09-12 05:53:46 +08:00
ClusterMetricInclude : [ ] string {
"cpu.usage.*" ,
"cpu.usagemhz.*" ,
"mem.usage.*" ,
"mem.active.*" } ,
ClusterMetricExclude : nil ,
2019-02-13 06:05:14 +08:00
ClusterInclude : [ ] string { "/**" } ,
2018-09-12 05:53:46 +08:00
HostMetricInclude : [ ] string {
2019-02-13 06:05:14 +08:00
"cpu.coreUtilization.average" ,
"cpu.costop.summation" ,
"cpu.demand.average" ,
"cpu.idle.summation" ,
"cpu.latency.average" ,
"cpu.readiness.average" ,
"cpu.ready.summation" ,
"cpu.swapwait.summation" ,
"cpu.usage.average" ,
"cpu.usagemhz.average" ,
"cpu.used.summation" ,
"cpu.utilization.average" ,
"cpu.wait.summation" ,
"disk.deviceReadLatency.average" ,
"disk.deviceWriteLatency.average" ,
"disk.kernelReadLatency.average" ,
"disk.kernelWriteLatency.average" ,
"disk.numberReadAveraged.average" ,
"disk.numberWriteAveraged.average" ,
"disk.read.average" ,
"disk.totalReadLatency.average" ,
"disk.totalWriteLatency.average" ,
"disk.write.average" ,
"mem.active.average" ,
"mem.latency.average" ,
"mem.state.latest" ,
"mem.swapin.average" ,
"mem.swapinRate.average" ,
"mem.swapout.average" ,
"mem.swapoutRate.average" ,
"mem.totalCapacity.average" ,
"mem.usage.average" ,
"mem.vmmemctl.average" ,
"net.bytesRx.average" ,
"net.bytesTx.average" ,
"net.droppedRx.summation" ,
"net.droppedTx.summation" ,
"net.errorsRx.summation" ,
"net.errorsTx.summation" ,
"net.usage.average" ,
"power.power.average" ,
"storageAdapter.numberReadAveraged.average" ,
"storageAdapter.numberWriteAveraged.average" ,
"storageAdapter.read.average" ,
"storageAdapter.write.average" ,
"sys.uptime.latest" } ,
2018-09-12 05:53:46 +08:00
HostMetricExclude : nil ,
2019-02-13 06:05:14 +08:00
HostInclude : [ ] string { "/**" } ,
2018-09-12 05:53:46 +08:00
VMMetricInclude : [ ] string {
2019-02-13 06:05:14 +08:00
"cpu.demand.average" ,
"cpu.idle.summation" ,
"cpu.latency.average" ,
"cpu.readiness.average" ,
"cpu.ready.summation" ,
"cpu.run.summation" ,
"cpu.usagemhz.average" ,
"cpu.used.summation" ,
"cpu.wait.summation" ,
"mem.active.average" ,
"mem.granted.average" ,
"mem.latency.average" ,
"mem.swapin.average" ,
"mem.swapinRate.average" ,
"mem.swapout.average" ,
"mem.swapoutRate.average" ,
"mem.usage.average" ,
"mem.vmmemctl.average" ,
"net.bytesRx.average" ,
"net.bytesTx.average" ,
"net.droppedRx.summation" ,
"net.droppedTx.summation" ,
"net.usage.average" ,
"power.power.average" ,
"virtualDisk.numberReadAveraged.average" ,
"virtualDisk.numberWriteAveraged.average" ,
"virtualDisk.read.average" ,
"virtualDisk.readOIO.latest" ,
"virtualDisk.throughput.usage.average" ,
"virtualDisk.totalReadLatency.average" ,
"virtualDisk.totalWriteLatency.average" ,
"virtualDisk.write.average" ,
"virtualDisk.writeOIO.latest" ,
"sys.uptime.latest" } ,
2018-09-12 05:53:46 +08:00
VMMetricExclude : nil ,
2019-02-13 06:05:14 +08:00
VMInclude : [ ] string { "/**" } ,
2018-09-12 05:53:46 +08:00
DatastoreMetricInclude : [ ] string {
"disk.used.*" ,
2020-05-16 06:43:32 +08:00
"disk.provisioned.*" } ,
2022-05-13 04:36:56 +08:00
DatastoreMetricExclude : nil ,
DatastoreInclude : [ ] string { "/**" } ,
ResourcePoolMetricInclude : [ ] string {
"cpu.capacity.*" ,
"mem.capacity.*" } ,
ResourcePoolMetricExclude : nil ,
ResourcePoolInclude : [ ] string { "/**" } ,
DatacenterMetricInclude : nil ,
DatacenterMetricExclude : nil ,
DatacenterInclude : [ ] string { "/**" } ,
2024-10-02 02:49:53 +08:00
ClientConfig : common_tls . ClientConfig { InsecureSkipVerify : true } ,
2018-09-12 05:53:46 +08:00
2023-04-19 01:03:28 +08:00
MaxQueryObjects : 256 ,
MaxQueryMetrics : 256 ,
ObjectDiscoveryInterval : config . Duration ( time . Second * 300 ) ,
Timeout : config . Duration ( time . Second * 20 ) ,
ForceDiscoverOnInit : true ,
DiscoverConcurrency : 1 ,
CollectConcurrency : 1 ,
Separator : "." ,
HistoricalInterval : config . Duration ( time . Second * 300 ) ,
2018-09-12 05:53:46 +08:00
}
}
2019-08-20 09:17:27 +08:00
func createSim ( folders int ) ( * simulator . Model , * simulator . Server , error ) {
2018-09-12 05:53:46 +08:00
model := simulator . VPX ( )
2019-08-20 09:17:27 +08:00
model . Folder = folders
model . Datacenter = 2
2024-09-19 17:03:28 +08:00
// model.App = 1
2019-08-20 09:17:27 +08:00
2018-09-12 05:53:46 +08:00
err := model . Create ( )
if err != nil {
return nil , nil , err
}
model . Service . TLS = new ( tls . Config )
s := model . Service . NewServer ( )
return model , s , nil
}
2019-02-13 06:05:14 +08:00
func testAlignUniform ( t * testing . T , n int ) {
now := time . Now ( ) . Truncate ( 60 * time . Second )
2022-12-12 22:05:33 +08:00
info := make ( [ ] types . PerfSampleInfo , 0 , n )
values := make ( [ ] int64 , 0 , n )
2019-02-13 06:05:14 +08:00
for i := 0 ; i < n ; i ++ {
2022-12-12 22:05:33 +08:00
info = append ( info , types . PerfSampleInfo {
2019-02-13 06:05:14 +08:00
Timestamp : now . Add ( time . Duration ( 20 * i ) * time . Second ) ,
Interval : 20 ,
2022-12-12 22:05:33 +08:00
} )
values = append ( values , 1 )
2019-02-13 06:05:14 +08:00
}
2025-01-21 23:17:01 +08:00
e := endpoint { log : testutil . Logger { } }
2020-04-22 02:30:29 +08:00
newInfo , newValues := e . alignSamples ( info , values , 60 * time . Second )
2023-10-31 17:29:53 +08:00
require . Len ( t , newInfo , n / 3 , "Aligned infos have wrong size" )
require . Len ( t , newValues , n / 3 , "Aligned values have wrong size" )
2019-02-13 06:05:14 +08:00
for _ , v := range newValues {
2024-07-01 21:00:13 +08:00
require . InDelta ( t , 1.0 , v , testutil . DefaultDelta , "Aligned value should be 1" )
2019-02-13 06:05:14 +08:00
}
}
func TestAlignMetrics ( t * testing . T ) {
testAlignUniform ( t , 3 )
testAlignUniform ( t , 30 )
testAlignUniform ( t , 333 )
// 20s to 60s of 1,2,3,1,2,3... (should average to 2)
n := 30
now := time . Now ( ) . Truncate ( 60 * time . Second )
2022-12-12 22:05:33 +08:00
info := make ( [ ] types . PerfSampleInfo , 0 , n )
values := make ( [ ] int64 , 0 , n )
2019-02-13 06:05:14 +08:00
for i := 0 ; i < n ; i ++ {
2022-12-12 22:05:33 +08:00
info = append ( info , types . PerfSampleInfo {
2019-02-13 06:05:14 +08:00
Timestamp : now . Add ( time . Duration ( 20 * i ) * time . Second ) ,
Interval : 20 ,
2022-12-12 22:05:33 +08:00
} )
values = append ( values , int64 ( i % 3 + 1 ) )
2019-02-13 06:05:14 +08:00
}
2025-01-21 23:17:01 +08:00
e := endpoint { log : testutil . Logger { } }
2020-04-22 02:30:29 +08:00
newInfo , newValues := e . alignSamples ( info , values , 60 * time . Second )
2023-10-31 17:29:53 +08:00
require . Len ( t , newInfo , n / 3 , "Aligned infos have wrong size" )
require . Len ( t , newValues , n / 3 , "Aligned values have wrong size" )
2019-02-13 06:05:14 +08:00
for _ , v := range newValues {
2024-07-01 21:00:13 +08:00
require . InDelta ( t , 2.0 , v , testutil . DefaultDelta , "Aligned value should be 2" )
2019-02-13 06:05:14 +08:00
}
}
2021-05-21 04:50:40 +08:00
func TestConfigDurationParsing ( t * testing . T ) {
v := defaultVSphere ( )
require . Equal ( t , int32 ( 300 ) , int32 ( time . Duration ( v . HistoricalInterval ) . Seconds ( ) ) , "HistoricalInterval.Seconds() with default duration should resolve 300" )
2018-09-12 05:53:46 +08:00
}
2018-11-07 06:22:43 +08:00
func TestMaxQuery ( t * testing . T ) {
2022-03-25 01:55:36 +08:00
if testing . Short ( ) {
t . Skip ( "Skipping long test in short mode" )
}
2019-08-20 09:17:27 +08:00
m , s , err := createSim ( 0 )
2023-01-10 00:17:23 +08:00
require . NoError ( t , err )
2018-11-07 06:22:43 +08:00
defer m . Remove ( )
defer s . Close ( )
v := defaultVSphere ( )
v . MaxQueryMetrics = 256
2025-03-10 15:12:42 +08:00
c , err := newClient ( t . Context ( ) , s . URL , v )
2023-01-10 00:17:23 +08:00
require . NoError ( t , err )
2018-11-07 06:22:43 +08:00
require . Equal ( t , 256 , v . MaxQueryMetrics )
2025-01-21 23:17:01 +08:00
om := object . NewOptionManager ( c . client . Client , * c . client . Client . ServiceContent . Setting )
2025-03-10 15:12:42 +08:00
err = om . Update ( t . Context ( ) , [ ] types . BaseOptionValue { & types . OptionValue {
2018-11-07 06:22:43 +08:00
Key : "config.vpxd.stats.maxQueryMetrics" ,
Value : "42" ,
} } )
2023-01-10 00:17:23 +08:00
require . NoError ( t , err )
2018-11-07 06:22:43 +08:00
v . MaxQueryMetrics = 256
2025-03-10 15:12:42 +08:00
c2 , err := newClient ( t . Context ( ) , s . URL , v )
2023-01-10 00:17:23 +08:00
require . NoError ( t , err )
2018-11-07 06:22:43 +08:00
require . Equal ( t , 42 , v . MaxQueryMetrics )
c . close ( )
c2 . close ( )
}
2025-01-21 23:17:01 +08:00
func testLookupVM ( ctx context . Context , t * testing . T , f * finder , path string , expected int , expectedName string ) {
2019-08-20 09:17:27 +08:00
poweredOn := types . VirtualMachinePowerState ( "poweredOn" )
var vm [ ] mo . VirtualMachine
2025-01-21 23:17:01 +08:00
err := f . find ( ctx , "VirtualMachine" , path , & vm )
2019-08-20 09:17:27 +08:00
require . NoError ( t , err )
2023-10-31 17:29:53 +08:00
require . Len ( t , vm , expected )
2019-08-20 09:17:27 +08:00
if expectedName != "" {
require . Equal ( t , expectedName , vm [ 0 ] . Name )
}
2023-12-15 22:36:34 +08:00
for i := range vm {
v := & vm [ i ]
2019-08-20 09:17:27 +08:00
require . Equal ( t , poweredOn , v . Runtime . PowerState )
}
}
2019-02-13 06:05:14 +08:00
func TestFinder ( t * testing . T ) {
2022-03-25 01:55:36 +08:00
if testing . Short ( ) {
t . Skip ( "Skipping long test in short mode" )
}
2019-08-20 09:17:27 +08:00
m , s , err := createSim ( 0 )
2023-01-10 00:17:23 +08:00
require . NoError ( t , err )
2019-02-13 06:05:14 +08:00
defer m . Remove ( )
defer s . Close ( )
v := defaultVSphere ( )
2025-03-10 15:12:42 +08:00
c , err := newClient ( t . Context ( ) , s . URL , v )
2021-11-18 22:22:43 +08:00
require . NoError ( t , err )
2019-02-13 06:05:14 +08:00
2025-01-21 23:17:01 +08:00
f := finder { c }
2019-02-13 06:05:14 +08:00
2019-08-20 09:17:27 +08:00
var dc [ ] mo . Datacenter
2025-03-10 15:12:42 +08:00
err = f . find ( t . Context ( ) , "Datacenter" , "/DC0" , & dc )
2019-02-13 06:05:14 +08:00
require . NoError ( t , err )
2023-10-31 17:29:53 +08:00
require . Len ( t , dc , 1 )
2019-02-13 06:05:14 +08:00
require . Equal ( t , "DC0" , dc [ 0 ] . Name )
2019-08-20 09:17:27 +08:00
var host [ ] mo . HostSystem
2025-03-10 15:12:42 +08:00
err = f . find ( t . Context ( ) , "HostSystem" , "/DC0/host/DC0_H0/DC0_H0" , & host )
2019-02-13 06:05:14 +08:00
require . NoError ( t , err )
2023-10-31 17:29:53 +08:00
require . Len ( t , host , 1 )
2019-02-13 06:05:14 +08:00
require . Equal ( t , "DC0_H0" , host [ 0 ] . Name )
2024-10-24 17:03:31 +08:00
host = make ( [ ] mo . HostSystem , 0 )
2025-03-10 15:12:42 +08:00
err = f . find ( t . Context ( ) , "HostSystem" , "/DC0/host/DC0_C0/DC0_C0_H0" , & host )
2019-02-13 06:05:14 +08:00
require . NoError ( t , err )
2023-10-31 17:29:53 +08:00
require . Len ( t , host , 1 )
2019-02-13 06:05:14 +08:00
require . Equal ( t , "DC0_C0_H0" , host [ 0 ] . Name )
2024-10-24 17:03:31 +08:00
resourcepool := make ( [ ] mo . ResourcePool , 0 )
2025-03-10 15:12:42 +08:00
err = f . find ( t . Context ( ) , "ResourcePool" , "/DC0/host/DC0_C0/Resources/DC0_C0_RP0" , & resourcepool )
2022-05-13 04:36:56 +08:00
require . NoError ( t , err )
2023-10-31 17:29:53 +08:00
require . Len ( t , host , 1 )
2022-05-13 04:36:56 +08:00
require . Equal ( t , "DC0_C0_H0" , host [ 0 ] . Name )
2024-10-24 17:03:31 +08:00
host = make ( [ ] mo . HostSystem , 0 )
2025-03-10 15:12:42 +08:00
err = f . find ( t . Context ( ) , "HostSystem" , "/DC0/host/DC0_C0/*" , & host )
2019-02-13 06:05:14 +08:00
require . NoError ( t , err )
2023-10-31 17:29:53 +08:00
require . Len ( t , host , 3 )
2019-02-13 06:05:14 +08:00
2019-08-20 09:17:27 +08:00
var vm [ ] mo . VirtualMachine
2025-03-10 15:12:42 +08:00
testLookupVM ( t . Context ( ) , t , & f , "/DC0/vm/DC0_H0_VM0" , 1 , "" )
testLookupVM ( t . Context ( ) , t , & f , "/DC0/vm/DC0_C0*" , 2 , "" )
testLookupVM ( t . Context ( ) , t , & f , "/DC0/*/DC0_H0_VM0" , 1 , "DC0_H0_VM0" )
testLookupVM ( t . Context ( ) , t , & f , "/DC0/*/DC0_H0_*" , 2 , "" )
testLookupVM ( t . Context ( ) , t , & f , "/DC0/**/DC0_H0_VM*" , 2 , "" )
testLookupVM ( t . Context ( ) , t , & f , "/DC0/**" , 4 , "" )
testLookupVM ( t . Context ( ) , t , & f , "/DC1/**" , 4 , "" )
testLookupVM ( t . Context ( ) , t , & f , "/**" , 8 , "" )
testLookupVM ( t . Context ( ) , t , & f , "/**/vm/**" , 8 , "" )
testLookupVM ( t . Context ( ) , t , & f , "/*/host/**/*DC*" , 8 , "" )
testLookupVM ( t . Context ( ) , t , & f , "/*/host/**/*DC*VM*" , 8 , "" )
testLookupVM ( t . Context ( ) , t , & f , "/*/host/**/*DC*/*/*DC*" , 4 , "" )
2019-02-13 06:05:14 +08:00
2024-10-24 17:03:31 +08:00
vm = make ( [ ] mo . VirtualMachine , 0 )
2025-03-10 15:12:42 +08:00
err = f . findAll ( t . Context ( ) , "VirtualMachine" , [ ] string { "/DC0/vm/DC0_H0*" , "/DC0/vm/DC0_C0*" } , nil , & vm )
2019-02-13 06:05:14 +08:00
require . NoError ( t , err )
2023-10-31 17:29:53 +08:00
require . Len ( t , vm , 4 )
2019-02-13 06:05:14 +08:00
2025-01-21 23:17:01 +08:00
rf := resourceFilter {
2020-01-17 04:14:00 +08:00
finder : & f ,
paths : [ ] string { "/DC0/vm/DC0_H0*" , "/DC0/vm/DC0_C0*" } ,
excludePaths : [ ] string { "/DC0/vm/DC0_H0_VM0" } ,
resType : "VirtualMachine" ,
}
2024-10-24 17:03:31 +08:00
vm = make ( [ ] mo . VirtualMachine , 0 )
2025-03-10 15:12:42 +08:00
require . NoError ( t , rf . findAll ( t . Context ( ) , & vm ) )
2023-10-31 17:29:53 +08:00
require . Len ( t , vm , 3 )
2020-01-17 04:14:00 +08:00
2025-01-21 23:17:01 +08:00
rf = resourceFilter {
2020-01-17 04:14:00 +08:00
finder : & f ,
paths : [ ] string { "/DC0/vm/DC0_H0*" , "/DC0/vm/DC0_C0*" } ,
excludePaths : [ ] string { "/**" } ,
resType : "VirtualMachine" ,
}
2024-10-24 17:03:31 +08:00
vm = make ( [ ] mo . VirtualMachine , 0 )
2025-03-10 15:12:42 +08:00
require . NoError ( t , rf . findAll ( t . Context ( ) , & vm ) )
2023-10-26 05:09:13 +08:00
require . Empty ( t , vm )
2020-01-17 04:14:00 +08:00
2025-01-21 23:17:01 +08:00
rf = resourceFilter {
2020-01-17 04:14:00 +08:00
finder : & f ,
paths : [ ] string { "/**" } ,
excludePaths : [ ] string { "/**" } ,
resType : "VirtualMachine" ,
}
2024-10-24 17:03:31 +08:00
vm = make ( [ ] mo . VirtualMachine , 0 )
2025-03-10 15:12:42 +08:00
require . NoError ( t , rf . findAll ( t . Context ( ) , & vm ) )
2023-10-26 05:09:13 +08:00
require . Empty ( t , vm )
2020-01-17 04:14:00 +08:00
2025-01-21 23:17:01 +08:00
rf = resourceFilter {
2020-01-17 04:14:00 +08:00
finder : & f ,
paths : [ ] string { "/**" } ,
excludePaths : [ ] string { "/this won't match anything" } ,
resType : "VirtualMachine" ,
}
2024-10-24 17:03:31 +08:00
vm = make ( [ ] mo . VirtualMachine , 0 )
2025-03-10 15:12:42 +08:00
require . NoError ( t , rf . findAll ( t . Context ( ) , & vm ) )
2023-10-31 17:29:53 +08:00
require . Len ( t , vm , 8 )
2020-01-17 04:14:00 +08:00
2025-01-21 23:17:01 +08:00
rf = resourceFilter {
2020-01-17 04:14:00 +08:00
finder : & f ,
paths : [ ] string { "/**" } ,
excludePaths : [ ] string { "/**/*VM0" } ,
resType : "VirtualMachine" ,
}
2024-10-24 17:03:31 +08:00
vm = make ( [ ] mo . VirtualMachine , 0 )
2025-03-10 15:12:42 +08:00
require . NoError ( t , rf . findAll ( t . Context ( ) , & vm ) )
2023-10-31 17:29:53 +08:00
require . Len ( t , vm , 4 )
2019-08-20 09:17:27 +08:00
}
2019-02-13 06:05:14 +08:00
2019-08-20 09:17:27 +08:00
func TestFolders ( t * testing . T ) {
2022-03-25 01:55:36 +08:00
if testing . Short ( ) {
t . Skip ( "Skipping long test in short mode" )
}
2019-08-20 09:17:27 +08:00
m , s , err := createSim ( 1 )
2023-01-10 00:17:23 +08:00
require . NoError ( t , err )
2019-08-20 09:17:27 +08:00
defer m . Remove ( )
defer s . Close ( )
2019-02-13 06:05:14 +08:00
2020-08-27 00:58:28 +08:00
v := defaultVSphere ( )
2025-03-10 15:12:42 +08:00
c , err := newClient ( t . Context ( ) , s . URL , v )
2021-11-18 22:22:43 +08:00
require . NoError ( t , err )
2019-02-13 06:05:14 +08:00
2025-01-21 23:17:01 +08:00
f := finder { c }
2019-08-15 08:03:33 +08:00
2019-08-20 09:17:27 +08:00
var folder [ ] mo . Folder
2025-03-10 15:12:42 +08:00
err = f . find ( t . Context ( ) , "Folder" , "/F0" , & folder )
2019-02-13 06:05:14 +08:00
require . NoError ( t , err )
2023-10-31 17:29:53 +08:00
require . Len ( t , folder , 1 )
2019-08-20 09:17:27 +08:00
require . Equal ( t , "F0" , folder [ 0 ] . Name )
2019-02-13 06:05:14 +08:00
2019-08-20 09:17:27 +08:00
var dc [ ] mo . Datacenter
2025-03-10 15:12:42 +08:00
err = f . find ( t . Context ( ) , "Datacenter" , "/F0/DC1" , & dc )
2019-02-13 06:05:14 +08:00
require . NoError ( t , err )
2023-10-31 17:29:53 +08:00
require . Len ( t , dc , 1 )
2019-08-20 09:17:27 +08:00
require . Equal ( t , "DC1" , dc [ 0 ] . Name )
2019-02-13 06:05:14 +08:00
2025-03-10 15:12:42 +08:00
testLookupVM ( t . Context ( ) , t , & f , "/F0/DC0/vm/**/F*" , 0 , "" )
testLookupVM ( t . Context ( ) , t , & f , "/F0/DC1/vm/**/F*/*VM*" , 4 , "" )
testLookupVM ( t . Context ( ) , t , & f , "/F0/DC1/vm/**/F*/**" , 4 , "" )
2019-02-13 06:05:14 +08:00
}
2023-04-19 01:03:28 +08:00
func TestVsanCmmds ( t * testing . T ) {
m , s , err := createSim ( 0 )
require . NoError ( t , err )
defer m . Remove ( )
defer s . Close ( )
v := defaultVSphere ( )
2025-03-10 15:12:42 +08:00
c , err := newClient ( t . Context ( ) , s . URL , v )
2023-04-19 01:03:28 +08:00
require . NoError ( t , err )
2025-01-21 23:17:01 +08:00
f := finder { c }
2023-04-19 01:03:28 +08:00
var clusters [ ] mo . ClusterComputeResource
2025-03-10 15:12:42 +08:00
err = f . findAll ( t . Context ( ) , "ClusterComputeResource" , [ ] string { "/**" } , nil , & clusters )
2023-04-19 01:03:28 +08:00
require . NoError ( t , err )
2025-01-21 23:17:01 +08:00
clusterObj := object . NewClusterComputeResource ( c . client . Client , clusters [ 0 ] . Reference ( ) )
2025-03-10 15:12:42 +08:00
_ , err = getCmmdsMap ( t . Context ( ) , c . client . Client , clusterObj )
2023-04-19 01:03:28 +08:00
require . Error ( t , err )
}
func TestVsanTags ( t * testing . T ) {
host := "5b860329-3bc4-a76c-48b6-246e963cfcc0"
disk := "52ee3be1-47cc-b50d-ecab-01af0f706381"
ssdDisk := "52f26fc8-0b9b-56d8-3a32-a9c3bfbc6148"
2024-10-02 23:19:57 +08:00
nvmeDisk := "5291e74f-74d3-fca2-6ffa-3655657dd3be"
2023-04-19 01:03:28 +08:00
ssd := "52173131-3384-bb63-4ef8-c00b0ce7e3e7"
hostname := "sc2-hs1-b2801.eng.vmware.com"
devName := "naa.55cd2e414d82c815:2"
2025-01-21 23:17:01 +08:00
var cmmds = map [ string ] cmmdsEntity {
nvmeDisk : { UUID : nvmeDisk , Type : "DISK_CAPACITY_TIER" , Owner : host , Content : cmmdsContent { DevName : devName } } ,
disk : { UUID : disk , Type : "DISK" , Owner : host , Content : cmmdsContent { DevName : devName , IsSsd : 1. } } ,
ssdDisk : { UUID : ssdDisk , Type : "DISK" , Owner : host , Content : cmmdsContent { DevName : devName , IsSsd : 0. , SsdUUID : ssd } } ,
host : { UUID : host , Type : "HOSTNAME" , Owner : host , Content : cmmdsContent { Hostname : hostname } } ,
2023-04-19 01:03:28 +08:00
}
tags := populateCMMDSTags ( make ( map [ string ] string ) , "capacity-disk" , disk , cmmds )
2023-10-31 17:29:53 +08:00
require . Len ( t , tags , 2 )
2023-04-19 01:03:28 +08:00
tags = populateCMMDSTags ( make ( map [ string ] string ) , "cache-disk" , ssdDisk , cmmds )
2023-10-31 17:29:53 +08:00
require . Len ( t , tags , 3 )
2023-04-19 01:03:28 +08:00
tags = populateCMMDSTags ( make ( map [ string ] string ) , "host-domclient" , host , cmmds )
2023-10-31 17:29:53 +08:00
require . Len ( t , tags , 1 )
2024-10-02 23:19:57 +08:00
tags = populateCMMDSTags ( make ( map [ string ] string ) , "vsan-esa-disk-layer" , nvmeDisk , cmmds )
require . Len ( t , tags , 2 )
2020-08-27 00:58:28 +08:00
}
func TestCollectionNoClusterMetrics ( t * testing . T ) {
2022-03-25 01:55:36 +08:00
if testing . Short ( ) {
t . Skip ( "Skipping long test in short mode" )
}
2020-08-27 00:58:28 +08:00
testCollection ( t , true )
}
2023-03-13 19:19:49 +08:00
func TestDisconnectedServerBehavior ( t * testing . T ) {
u , err := url . Parse ( "https://definitely.not.a.valid.host" )
require . NoError ( t , err )
v := defaultVSphere ( )
v . DisconnectedServersBehavior = "error"
2025-03-10 15:12:42 +08:00
_ , err = newEndpoint ( t . Context ( ) , v , u , v . Log )
2023-03-13 19:19:49 +08:00
require . Error ( t , err )
v . DisconnectedServersBehavior = "ignore"
2025-03-10 15:12:42 +08:00
_ , err = newEndpoint ( t . Context ( ) , v , u , v . Log )
2023-03-13 19:19:49 +08:00
require . NoError ( t , err )
v . DisconnectedServersBehavior = "something else"
2025-03-10 15:12:42 +08:00
_ , err = newEndpoint ( t . Context ( ) , v , u , v . Log )
2023-03-13 19:19:49 +08:00
require . Error ( t , err )
2023-11-02 04:09:55 +08:00
require . Equal ( t , ` "something else" is not a valid value for disconnected_servers_behavior ` , err . Error ( ) )
2023-03-13 19:19:49 +08:00
}
2020-08-27 00:58:28 +08:00
func testCollection ( t * testing . T , excludeClusters bool ) {
mustHaveMetrics := map [ string ] struct { } {
"vsphere.vm.cpu" : { } ,
"vsphere.vm.mem" : { } ,
"vsphere.vm.net" : { } ,
"vsphere.host.cpu" : { } ,
"vsphere.host.mem" : { } ,
"vsphere.host.net" : { } ,
"vsphere.datastore.disk" : { } ,
2018-12-29 05:24:43 +08:00
}
2020-08-27 00:58:28 +08:00
vCenter := os . Getenv ( "VCENTER_URL" )
username := os . Getenv ( "VCENTER_USER" )
password := os . Getenv ( "VCENTER_PASSWORD" )
v := defaultVSphere ( )
if vCenter != "" {
v . Vcenters = [ ] string { vCenter }
2023-01-10 00:17:23 +08:00
v . Username = config . NewSecret ( [ ] byte ( username ) )
v . Password = config . NewSecret ( [ ] byte ( password ) )
2020-08-27 00:58:28 +08:00
} else {
m , s , err := createSim ( 0 )
2023-01-10 00:17:23 +08:00
require . NoError ( t , err )
2020-08-27 00:58:28 +08:00
defer m . Remove ( )
defer s . Close ( )
v . Vcenters = [ ] string { s . URL . String ( ) }
}
if excludeClusters {
v . ClusterMetricExclude = [ ] string { "*" }
2018-09-12 05:53:46 +08:00
}
var acc testutil . Accumulator
2020-08-27 00:58:28 +08:00
require . NoError ( t , v . Start ( & acc ) )
2018-09-12 05:53:46 +08:00
defer v . Stop ( )
require . NoError ( t , v . Gather ( & acc ) )
2024-11-13 05:49:39 +08:00
require . Emptyf ( t , acc . Errors , "Errors found: %s" , acc . Errors )
2023-10-26 05:09:13 +08:00
require . NotEmpty ( t , acc . Metrics , "No metrics were collected" )
2020-08-27 00:58:28 +08:00
cache := make ( map [ string ] string )
2025-03-10 15:12:42 +08:00
client , err := v . endpoints [ 0 ] . clientFactory . getClient ( t . Context ( ) )
2020-08-27 00:58:28 +08:00
require . NoError ( t , err )
hostCache := make ( map [ string ] string )
for _ , m := range acc . Metrics {
delete ( mustHaveMetrics , m . Measurement )
if strings . HasPrefix ( m . Measurement , "vsphere.vm." ) {
mustContainAll ( t , m . Tags , [ ] string { "esxhostname" , "moid" , "vmname" , "guest" , "dcname" , "uuid" , "vmname" } )
hostName := m . Tags [ "esxhostname" ]
hostMoid , ok := hostCache [ hostName ]
if ! ok {
// We have to follow the host parent path to locate a cluster. Look up the host!
2025-01-21 23:17:01 +08:00
finder := finder { client }
2020-08-27 00:58:28 +08:00
var hosts [ ] mo . HostSystem
2025-03-10 15:12:42 +08:00
err := finder . find ( t . Context ( ) , "HostSystem" , "/**/" + hostName , & hosts )
2021-04-09 00:43:39 +08:00
require . NoError ( t , err )
2020-08-27 00:58:28 +08:00
require . NotEmpty ( t , hosts )
hostMoid = hosts [ 0 ] . Reference ( ) . Value
hostCache [ hostName ] = hostMoid
}
2025-03-10 15:12:42 +08:00
if isInCluster ( t , v , client , cache , "HostSystem" , hostMoid ) { // If the VM lives in a cluster
2020-08-27 00:58:28 +08:00
mustContainAll ( t , m . Tags , [ ] string { "clustername" } )
}
} else if strings . HasPrefix ( m . Measurement , "vsphere.host." ) {
2025-03-10 15:12:42 +08:00
if isInCluster ( t , v , client , cache , "HostSystem" , m . Tags [ "moid" ] ) { // If the host lives in a cluster
2020-08-27 00:58:28 +08:00
mustContainAll ( t , m . Tags , [ ] string { "esxhostname" , "clustername" , "moid" , "dcname" } )
} else {
mustContainAll ( t , m . Tags , [ ] string { "esxhostname" , "moid" , "dcname" } )
}
} else if strings . HasPrefix ( m . Measurement , "vsphere.cluster." ) {
mustContainAll ( t , m . Tags , [ ] string { "clustername" , "moid" , "dcname" } )
} else {
mustContainAll ( t , m . Tags , [ ] string { "moid" , "dcname" } )
}
}
require . Empty ( t , mustHaveMetrics , "Some metrics were not found" )
}
2025-03-10 15:12:42 +08:00
func isInCluster ( t * testing . T , v * VSphere , client * client , cache map [ string ] string , resourceKind , moid string ) bool {
2020-08-27 00:58:28 +08:00
ref := types . ManagedObjectReference {
Type : resourceKind ,
Value : moid ,
}
2025-03-10 15:12:42 +08:00
_ , ok := v . endpoints [ 0 ] . getAncestorName ( t . Context ( ) , client , "ClusterComputeResource" , cache , ref )
2020-08-27 00:58:28 +08:00
return ok
}
func mustContainAll ( t * testing . T , tagMap map [ string ] string , mustHave [ ] string ) {
for _ , tag := range mustHave {
require . Contains ( t , tagMap , tag )
}
2018-09-12 05:53:46 +08:00
}
2023-07-06 22:13:12 +08:00
func TestVersionLowerThan ( t * testing . T ) {
tests := [ ] struct {
current string
major int
minor int
result bool
} {
{
current : "7" ,
major : 6 ,
minor : 3 ,
result : false ,
} ,
{
current : "5" ,
major : 6 ,
minor : 3 ,
result : true ,
} ,
{
current : "6.0" ,
major : 6 ,
minor : 3 ,
result : true ,
} ,
{
current : "6.3" ,
major : 6 ,
minor : 3 ,
result : false ,
} ,
{
current : "6.2" ,
major : 6 ,
minor : 3 ,
result : true ,
} ,
{
current : "7.0.3.0" ,
major : 6 ,
minor : 7 ,
result : false ,
} ,
}
for _ , tc := range tests {
result := versionLowerThan ( tc . current , tc . major , tc . minor )
2024-11-13 05:49:39 +08:00
require . Equalf ( t , tc . result , result , "%s < %d.%d" , tc . current , tc . major , tc . minor )
2023-07-06 22:13:12 +08:00
}
}