diff --git a/api/v1alpha1/agent/spec.gen.go b/api/v1alpha1/agent/spec.gen.go index 4817e0c8c..731bf4674 100644 --- a/api/v1alpha1/agent/spec.gen.go +++ b/api/v1alpha1/agent/spec.gen.go @@ -19,53 +19,56 @@ import ( // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "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", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/api/v1alpha1/openapi.yaml b/api/v1alpha1/openapi.yaml index 609a408b1..bf854786e 100644 --- a/api/v1alpha1/openapi.yaml +++ b/api/v1alpha1/openapi.yaml @@ -2494,6 +2494,29 @@ components: type: string description: Identifier of the host where this datastore is attached nullable: true + storageIoConfiguration: + $ref: "#/components/schemas/StorageIoConfiguration" + + StorageIoConfiguration: + type: object + properties: + enabled: + type: boolean + default: false + description: "Whether Storage I/O Control is enabled for this datastore" + congestionThreshold: + type: integer + default: 30 + description: "Congestion threshold percentage" + congestionThresholdMode: + type: string + enum: ["automatic", "manual"] + default: "automatic" + description: "Mode for congestion threshold calculation" + percentOfPeakThroughput: + type: integer + default: 90 + description: "Percent of peak throughput" VMResourceBreakdown: type: object diff --git a/api/v1alpha1/spec.gen.go b/api/v1alpha1/spec.gen.go index d62fe3227..b29a1788e 100644 --- a/api/v1alpha1/spec.gen.go +++ b/api/v1alpha1/spec.gen.go @@ -18,166 +18,169 @@ import ( // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "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", - "jvP45fH/BwAA//9KRYHliycBAA==", + "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", + "zvEpAQA=", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/api/v1alpha1/types.gen.go b/api/v1alpha1/types.gen.go index 7fdaa23ff..ae7b1955b 100644 --- a/api/v1alpha1/types.gen.go +++ b/api/v1alpha1/types.gen.go @@ -133,6 +133,12 @@ const ( SourceUpdateNetworkConfigTypeStatic SourceUpdateNetworkConfigType = "static" ) +// Defines values for StorageIoConfigurationCongestionThresholdMode. +const ( + Automatic StorageIoConfigurationCongestionThresholdMode = "automatic" + Manual StorageIoConfigurationCongestionThresholdMode = "manual" +) + // Defines values for ListGroupsParamsKind. const ( ListGroupsParamsKindAdmin ListGroupsParamsKind = "admin" @@ -397,12 +403,13 @@ type Datastore struct { HardwareAcceleratedMove bool `json:"hardwareAcceleratedMove"` // HostId Identifier of the host where this datastore is attached - HostId *string `json:"hostId"` - Model string `json:"model"` - ProtocolType string `json:"protocolType"` - TotalCapacityGB int `json:"totalCapacityGB"` - Type string `json:"type"` - Vendor string `json:"vendor"` + HostId *string `json:"hostId"` + Model string `json:"model"` + ProtocolType string `json:"protocolType"` + StorageIoConfiguration *StorageIoConfiguration `json:"storageIoConfiguration,omitempty"` + TotalCapacityGB int `json:"totalCapacityGB"` + Type string `json:"type"` + Vendor string `json:"vendor"` } // Error defines model for Error. @@ -915,6 +922,24 @@ type Status struct { Status *string `json:"status,omitempty"` } +// StorageIoConfiguration defines model for StorageIoConfiguration. +type StorageIoConfiguration struct { + // CongestionThreshold Congestion threshold percentage + CongestionThreshold *int `json:"congestionThreshold,omitempty"` + + // CongestionThresholdMode Mode for congestion threshold calculation + CongestionThresholdMode *StorageIoConfigurationCongestionThresholdMode `json:"congestionThresholdMode,omitempty"` + + // Enabled Whether Storage I/O Control is enabled for this datastore + Enabled *bool `json:"enabled,omitempty"` + + // PercentOfPeakThroughput Percent of peak throughput + PercentOfPeakThroughput *int `json:"percentOfPeakThroughput,omitempty"` +} + +// StorageIoConfigurationCongestionThresholdMode Mode for congestion threshold calculation +type StorageIoConfigurationCongestionThresholdMode string + // UpdateInventory defines model for UpdateInventory. type UpdateInventory struct { AgentId openapi_types.UUID `json:"agentId"` diff --git a/pkg/duckdb_parser/inventory_builder.go b/pkg/duckdb_parser/inventory_builder.go index 04c571d5e..898cf8a1e 100644 --- a/pkg/duckdb_parser/inventory_builder.go +++ b/pkg/duckdb_parser/inventory_builder.go @@ -318,6 +318,12 @@ func (p *Parser) buildInfraData(ctx context.Context, filters Filters) (*inventor Model: d.Model, ProtocolType: d.ProtocolType, Vendor: d.Vendor, + StorageIoConfiguration: &inventory.StorageIoConfiguration{ + Enabled: d.SiocEnabled, + CongestionThreshold: d.SiocCongestionThreshold, + CongestionThresholdMode: d.SiocCongestionThresholdMode, + PercentOfPeakThroughput: d.SiocPercentOfPeakThroughput, + }, }) } infraData.Datastores = datastores diff --git a/pkg/duckdb_parser/inventory_builder_test.go b/pkg/duckdb_parser/inventory_builder_test.go index 731df2af6..bcc904487 100644 --- a/pkg/duckdb_parser/inventory_builder_test.go +++ b/pkg/duckdb_parser/inventory_builder_test.go @@ -15,6 +15,7 @@ import ( "github.com/xuri/excelize/v2" "github.com/kubev2v/migration-planner/pkg/duckdb_parser/models" + "github.com/kubev2v/migration-planner/pkg/inventory" ) // testValidator returns no concerns for all VMs. @@ -91,8 +92,9 @@ var ( "VM UUID", "Total disk capacity MiB", "migration_excluded", } vHostHeaders = []string{"Datacenter", "Cluster", "# Cores", "# CPU", "Object ID", "# Memory", "Model", "Vendor", "Host", "Config status"} - vDatastoreHeaders = []string{"Hosts", "Address", "Name", "Object ID", "Free MiB", "MHA", "Capacity MiB", "Type"} - vClusterHeaders = []string{"Name", "Object ID"} + vDatastoreHeaders = []string{"Hosts", "Address", "Name", "Object ID", "Free MiB", "MHA", "Capacity MiB", "Type", + "SIOC Enabled", "SIOC Congestion Threshold", "SIOC Congestion Threshold Mode", "SIOC Percent Of Peak Throughput"} + vClusterHeaders = []string{"Name", "Object ID"} ) // defaultStandardSheets returns vInfo, vHost, default vDatastore, and vCluster from hosts for createTestExcel. @@ -110,14 +112,18 @@ func defaultStandardSheets(vms, hosts []map[string]string) []ExcelSheet { vDatastoreRows := []map[string]string{ { - "Hosts": "esxi-host-1", - "Address": "10.0.0.1", - "Name": "datastore1", - "Object ID": "datastore-001", - "Free MiB": "524288", - "MHA": "false", - "Capacity MiB": "1048576", - "Type": "VMFS", + "Hosts": "esxi-host-1", + "Address": "10.0.0.1", + "Name": "datastore1", + "Object ID": "datastore-001", + "Free MiB": "524288", + "MHA": "false", + "Capacity MiB": "1048576", + "Type": "VMFS", + "SIOC Enabled": "false", + "SIOC Congestion Threshold": "30", + "SIOC Congestion Threshold Mode": "automatic", + "SIOC Percent Of Peak Throughput": "90", }, } @@ -1475,6 +1481,148 @@ func TestBuildInventory_VMListFilter(t *testing.T) { assert.Equal(t, 0, invNone.VCenter.VMs.Total, "Non-existent VMs should result in 0 count") } +// TestBuildInventory_StorageIoConfiguration verifies that SIOC fields are correctly +// populated in the inventory datastores, both when explicit SIOC values are provided +// and when SIOC columns are missing (defaults should apply). +func TestBuildInventory_StorageIoConfiguration(t *testing.T) { + t.Run("explicit SIOC values", func(t *testing.T) { + parser, _, cleanup := setupTestParser(t, &testValidator{}) + defer cleanup() + + vms := []map[string]string{ + {"VM": "vm-1", "VM ID": "vm-001", "VI SDK UUID": "uuid-1", "Host": "esxi-host-1", "CPUs": "4", "Memory": "8192", "Powerstate": "poweredOn", "Cluster": "cluster1", "Datacenter": "dc1"}, + } + hosts := []map[string]string{ + {"Datacenter": "dc1", "Cluster": "cluster1", "# Cores": "8", "# CPU": "2", "Object ID": "host-001", "# Memory": "32768", "Model": "ESXi", "Vendor": "VMware", "Host": "esxi-host-1", "Config status": "green"}, + } + clustersRows := []map[string]string{{"Name": "cluster1", "Object ID": "domain-c1"}} + + datastoreRows := []map[string]string{ + { + "Hosts": "esxi-host-1", + "Address": "10.0.0.1", + "Name": "ds-sioc-on", + "Object ID": "datastore-001", + "Free MiB": "524288", + "MHA": "false", + "Capacity MiB": "1048576", + "Type": "VMFS", + "SIOC Enabled": "true", + "SIOC Congestion Threshold": "50", + "SIOC Congestion Threshold Mode": "manual", + "SIOC Percent Of Peak Throughput": "80", + }, + { + "Hosts": "esxi-host-1", + "Address": "10.0.0.1", + "Name": "ds-sioc-off", + "Object ID": "datastore-002", + "Free MiB": "262144", + "MHA": "false", + "Capacity MiB": "524288", + "Type": "NFS", + "SIOC Enabled": "false", + "SIOC Congestion Threshold": "30", + "SIOC Congestion Threshold Mode": "automatic", + "SIOC Percent Of Peak Throughput": "90", + }, + } + + sheets := []ExcelSheet{ + NewExcelSheet("vInfo", vInfoHeaders, vms), + NewExcelSheet("vHost", vHostHeaders, hosts), + NewExcelSheet("vDatastore", vDatastoreHeaders, datastoreRows), + NewExcelSheet("vCluster", vClusterHeaders, clustersRows), + } + tmpFile := createTestExcel(t, sheets...) + + ctx := context.Background() + _, err := parser.IngestRvTools(ctx, tmpFile) + require.NoError(t, err) + + inv, err := parser.BuildInventory(ctx, nil) + require.NoError(t, err) + + require.Len(t, inv.VCenter.Infra.Datastores, 2, "should have 2 datastores") + + // Build a map by datastore ID for easier assertion + dsMap := make(map[string]inventory.Datastore) + for _, ds := range inv.VCenter.Infra.Datastores { + dsMap[ds.DiskId] = ds + } + + // Datastore with SIOC enabled (diskId is the datastore Name) + dsOn, ok := dsMap["ds-sioc-on"] + require.True(t, ok, "ds-sioc-on should exist") + require.NotNil(t, dsOn.StorageIoConfiguration, "StorageIoConfiguration should be populated") + assert.True(t, dsOn.StorageIoConfiguration.Enabled, "SIOC should be enabled") + assert.Equal(t, 50, dsOn.StorageIoConfiguration.CongestionThreshold, "Congestion threshold should be 50") + assert.Equal(t, "manual", dsOn.StorageIoConfiguration.CongestionThresholdMode, "Congestion threshold mode should be manual") + assert.Equal(t, 80, dsOn.StorageIoConfiguration.PercentOfPeakThroughput, "Percent of peak throughput should be 80") + + // Datastore with SIOC disabled (diskId is the datastore Name) + dsOff, ok := dsMap["ds-sioc-off"] + require.True(t, ok, "ds-sioc-off should exist") + require.NotNil(t, dsOff.StorageIoConfiguration, "StorageIoConfiguration should be populated") + assert.False(t, dsOff.StorageIoConfiguration.Enabled, "SIOC should be disabled") + assert.Equal(t, 30, dsOff.StorageIoConfiguration.CongestionThreshold, "Congestion threshold should be 30") + assert.Equal(t, "automatic", dsOff.StorageIoConfiguration.CongestionThresholdMode, "Congestion threshold mode should be automatic") + assert.Equal(t, 90, dsOff.StorageIoConfiguration.PercentOfPeakThroughput, "Percent of peak throughput should be 90") + }) + + t.Run("missing SIOC columns default gracefully", func(t *testing.T) { + parser, _, cleanup := setupTestParser(t, &testValidator{}) + defer cleanup() + + vms := []map[string]string{ + {"VM": "vm-1", "VM ID": "vm-001", "VI SDK UUID": "uuid-1", "Host": "esxi-host-1", "CPUs": "4", "Memory": "8192", "Powerstate": "poweredOn", "Cluster": "cluster1", "Datacenter": "dc1"}, + } + hosts := []map[string]string{ + {"Datacenter": "dc1", "Cluster": "cluster1", "# Cores": "8", "# CPU": "2", "Object ID": "host-001", "# Memory": "32768", "Model": "ESXi", "Vendor": "VMware", "Host": "esxi-host-1", "Config status": "green"}, + } + clustersRows := []map[string]string{{"Name": "cluster1", "Object ID": "domain-c1"}} + + // vDatastore headers WITHOUT any SIOC columns + noSiocHeaders := []string{"Hosts", "Address", "Name", "Object ID", "Free MiB", "MHA", "Capacity MiB", "Type"} + datastoreRows := []map[string]string{ + { + "Hosts": "esxi-host-1", + "Address": "10.0.0.1", + "Name": "ds-no-sioc", + "Object ID": "datastore-010", + "Free MiB": "524288", + "MHA": "false", + "Capacity MiB": "1048576", + "Type": "VMFS", + }, + } + + sheets := []ExcelSheet{ + NewExcelSheet("vInfo", vInfoHeaders, vms), + NewExcelSheet("vHost", vHostHeaders, hosts), + NewExcelSheet("vDatastore", noSiocHeaders, datastoreRows), + NewExcelSheet("vCluster", vClusterHeaders, clustersRows), + } + tmpFile := createTestExcel(t, sheets...) + + ctx := context.Background() + _, err := parser.IngestRvTools(ctx, tmpFile) + require.NoError(t, err) + + inv, err := parser.BuildInventory(ctx, nil) + require.NoError(t, err) + + require.Len(t, inv.VCenter.Infra.Datastores, 1, "should have 1 datastore") + ds := inv.VCenter.Infra.Datastores[0] + + require.NotNil(t, ds.StorageIoConfiguration, "StorageIoConfiguration should be populated even without SIOC columns") + assert.False(t, ds.StorageIoConfiguration.Enabled, "SIOC should default to disabled") + assert.Equal(t, 30, ds.StorageIoConfiguration.CongestionThreshold, "Congestion threshold should default to 30") + assert.Equal(t, "automatic", ds.StorageIoConfiguration.CongestionThresholdMode, "Congestion threshold mode should default to automatic") + assert.Equal(t, 90, ds.StorageIoConfiguration.PercentOfPeakThroughput, "Percent of peak throughput should default to 90") + }) +} + func TestVCenterVersion(t *testing.T) { tests := []struct { name string diff --git a/pkg/duckdb_parser/models/inventory.go b/pkg/duckdb_parser/models/inventory.go index 5655bcb7a..cddfc674f 100644 --- a/pkg/duckdb_parser/models/inventory.go +++ b/pkg/duckdb_parser/models/inventory.go @@ -2,16 +2,20 @@ package models // Datastore represents a VMware datastore. type Datastore struct { - Cluster string `db:"cluster" json:"-"` - DiskId string `db:"diskId" json:"diskId"` - FreeCapacityGB float64 `db:"freeCapacityGB" json:"freeCapacityGB"` - HardwareAcceleratedMove bool `db:"hardwareAcceleratedMove" json:"hardwareAcceleratedMove"` - HostId string `db:"hostId" json:"hostId"` - Model string `db:"model" json:"model"` - ProtocolType string `db:"protocolType" json:"protocolType"` - TotalCapacityGB float64 `db:"totalCapacityGB" json:"totalCapacityGB"` - Type string `db:"type" json:"type"` - Vendor string `db:"vendor" json:"vendor"` + Cluster string `db:"cluster" json:"-"` + DiskId string `db:"diskId" json:"diskId"` + FreeCapacityGB float64 `db:"freeCapacityGB" json:"freeCapacityGB"` + HardwareAcceleratedMove bool `db:"hardwareAcceleratedMove" json:"hardwareAcceleratedMove"` + HostId string `db:"hostId" json:"hostId"` + Model string `db:"model" json:"model"` + ProtocolType string `db:"protocolType" json:"protocolType"` + TotalCapacityGB float64 `db:"totalCapacityGB" json:"totalCapacityGB"` + Type string `db:"type" json:"type"` + Vendor string `db:"vendor" json:"vendor"` + SiocEnabled bool `db:"siocEnabled" json:"siocEnabled"` + SiocCongestionThreshold int `db:"siocCongestionThreshold" json:"siocCongestionThreshold"` + SiocCongestionThresholdMode string `db:"siocCongestionThresholdMode" json:"siocCongestionThresholdMode"` + SiocPercentOfPeakThroughput int `db:"siocPercentOfPeakThroughput" json:"siocPercentOfPeakThroughput"` } // Os represents an operating system summary. diff --git a/pkg/duckdb_parser/templates/create_schema.go.tmpl b/pkg/duckdb_parser/templates/create_schema.go.tmpl index bce2f7107..01e3b47bc 100644 --- a/pkg/duckdb_parser/templates/create_schema.go.tmpl +++ b/pkg/duckdb_parser/templates/create_schema.go.tmpl @@ -125,7 +125,11 @@ CREATE TABLE IF NOT EXISTS vdatastore ( "MHA" BOOLEAN DEFAULT false, "Capacity MiB" DOUBLE DEFAULT 0.0, "Type" VARCHAR, - "Backing Devices" VARCHAR DEFAULT '[]' + "Backing Devices" VARCHAR DEFAULT '[]', + "SIOC Enabled" BOOLEAN DEFAULT false, + "SIOC Congestion Threshold" INTEGER DEFAULT 30, + "SIOC Congestion Threshold Mode" VARCHAR DEFAULT 'automatic', + "SIOC Percent Of Peak Throughput" INTEGER DEFAULT 90 ); CREATE TABLE IF NOT EXISTS vhba ( diff --git a/pkg/duckdb_parser/templates/datastore_query.go.tmpl b/pkg/duckdb_parser/templates/datastore_query.go.tmpl index 802a41bb7..176d44b2d 100644 --- a/pkg/duckdb_parser/templates/datastore_query.go.tmpl +++ b/pkg/duckdb_parser/templates/datastore_query.go.tmpl @@ -33,7 +33,11 @@ with_host AS ( e."Type", e.ip, vh."Object ID", - e.hba_device + e.hba_device, + e."SIOC Enabled", + e."SIOC Congestion Threshold", + e."SIOC Congestion Threshold Mode", + e."SIOC Percent Of Peak Throughput" FROM expanded e JOIN vhost vh ON vh.Host = e.ip WHERE vh."Cluster" = '{{.ClusterFilter}}' @@ -49,7 +53,11 @@ with_hba AS ( w."Type", w.ip, w."Object ID", - FIRST(hba."Type") OVER (PARTITION BY w."Name") as hba_type + FIRST(hba."Type") OVER (PARTITION BY w."Name") as hba_type, + w."SIOC Enabled", + w."SIOC Congestion Threshold", + w."SIOC Congestion Threshold Mode", + w."SIOC Percent Of Peak Throughput" FROM with_host w LEFT JOIN vhba hba ON hba."Device" = w.hba_device ) @@ -68,9 +76,14 @@ SELECT END as "protocolType", ROUND(w."Capacity MiB"::double / 1024)::integer as "totalCapacityGB", COALESCE(w."Type", 'N/A') as "type", - 'N/A' as "vendor" + 'N/A' as "vendor", + COALESCE(w."SIOC Enabled", false) as "siocEnabled", + COALESCE(w."SIOC Congestion Threshold", 30) as "siocCongestionThreshold", + COALESCE(w."SIOC Congestion Threshold Mode", 'automatic') as "siocCongestionThresholdMode", + COALESCE(w."SIOC Percent Of Peak Throughput", 90) as "siocPercentOfPeakThroughput" FROM with_hba w -GROUP BY w."Cluster", w."Address", w."Name", w."Free MiB", w."MHA", w."Capacity MiB", w."Type", w.hba_type +GROUP BY w."Cluster", w."Address", w."Name", w."Free MiB", w."MHA", w."Capacity MiB", w."Type", w.hba_type, + w."SIOC Enabled", w."SIOC Congestion Threshold", w."SIOC Congestion Threshold Mode", w."SIOC Percent Of Peak Throughput" {{- if and .Limit (gt .Limit 0) }} LIMIT {{.Limit}}{{end}} {{- if and .Offset (gt .Offset 0) }} OFFSET {{.Offset}}{{end}}; {{- else }} @@ -103,7 +116,11 @@ SELECT END as "protocolType", COALESCE(ROUND(d."Capacity MiB"::double / 1024)::integer, 0) as "totalCapacityGB", COALESCE(d."Type", 'N/A') as "type", - 'N/A' as "vendor" + 'N/A' as "vendor", + COALESCE(d."SIOC Enabled", false) as "siocEnabled", + COALESCE(d."SIOC Congestion Threshold", 30) as "siocCongestionThreshold", + COALESCE(d."SIOC Congestion Threshold Mode", 'automatic') as "siocCongestionThresholdMode", + COALESCE(d."SIOC Percent Of Peak Throughput", 90) as "siocPercentOfPeakThroughput" FROM vdatastore d LEFT JOIN host_ids h ON h.ds_name = d."Name" {{- if and .Limit (gt .Limit 0) }} LIMIT {{.Limit}}{{end}} diff --git a/pkg/duckdb_parser/templates/ingest_rvtools.go.tmpl b/pkg/duckdb_parser/templates/ingest_rvtools.go.tmpl index 8c41c26c9..bf30a8e19 100644 --- a/pkg/duckdb_parser/templates/ingest_rvtools.go.tmpl +++ b/pkg/duckdb_parser/templates/ingest_rvtools.go.tmpl @@ -216,6 +216,10 @@ ALTER TABLE vdatastore_raw ADD COLUMN IF NOT EXISTS "Free MB" VARCHAR; ALTER TABLE vdatastore_raw ADD COLUMN IF NOT EXISTS "Capacity MB" VARCHAR; ALTER TABLE vdatastore_raw ADD COLUMN IF NOT EXISTS "Free MiB" VARCHAR; ALTER TABLE vdatastore_raw ADD COLUMN IF NOT EXISTS "Capacity MiB" VARCHAR; +ALTER TABLE vdatastore_raw ADD COLUMN IF NOT EXISTS "SIOC Enabled" VARCHAR; +ALTER TABLE vdatastore_raw ADD COLUMN IF NOT EXISTS "SIOC Congestion Threshold" VARCHAR; +ALTER TABLE vdatastore_raw ADD COLUMN IF NOT EXISTS "SIOC Congestion Threshold Mode" VARCHAR; +ALTER TABLE vdatastore_raw ADD COLUMN IF NOT EXISTS "SIOC Percent Of Peak Throughput" VARCHAR; UPDATE vdatastore_raw SET "Free MiB" = COALESCE( @@ -227,7 +231,8 @@ UPDATE vdatastore_raw SET NULLIF(TRIM("Capacity MB"), '') ); -INSERT INTO vdatastore ("Hosts", "Address", "Name", "Object ID", "Free MiB", "MHA", "Capacity MiB", "Type") +INSERT INTO vdatastore ("Hosts", "Address", "Name", "Object ID", "Free MiB", "MHA", "Capacity MiB", "Type", + "SIOC Enabled", "SIOC Congestion Threshold", "SIOC Congestion Threshold Mode", "SIOC Percent Of Peak Throughput") SELECT "Hosts", "Address", @@ -236,7 +241,11 @@ SELECT TRY_CAST("Free MiB" AS DOUBLE), CASE WHEN LOWER("MHA") IN ('true', '1', 'yes') THEN TRUE WHEN LOWER("MHA") IN ('false', '0', 'no') THEN FALSE ELSE NULL END, TRY_CAST("Capacity MiB" AS DOUBLE), - "Type" + "Type", + CASE WHEN LOWER(TRIM(COALESCE("SIOC Enabled", ''))) IN ('true', '1', 'yes') THEN true ELSE false END, + COALESCE(TRY_CAST("SIOC Congestion Threshold" AS INTEGER), 30), + COALESCE(NULLIF(TRIM("SIOC Congestion Threshold Mode"), ''), 'automatic'), + COALESCE(TRY_CAST("SIOC Percent Of Peak Throughput" AS INTEGER), 90) FROM vdatastore_raw; DROP TABLE vdatastore_raw; diff --git a/pkg/duckdb_parser/templates/ingest_sqlite.go.tmpl b/pkg/duckdb_parser/templates/ingest_sqlite.go.tmpl index f54f0cc38..aeb507263 100644 --- a/pkg/duckdb_parser/templates/ingest_sqlite.go.tmpl +++ b/pkg/duckdb_parser/templates/ingest_sqlite.go.tmpl @@ -155,7 +155,8 @@ SELECT FROM src.Host h LEFT JOIN src.Cluster c ON h.Cluster = c.ID; -INSERT INTO vdatastore ("Hosts", "Address", "Name", "Object ID", "Free MiB", "MHA", "Capacity MiB", "Type", "Backing Devices") +INSERT INTO vdatastore ("Hosts", "Address", "Name", "Object ID", "Free MiB", "MHA", "Capacity MiB", "Type", "Backing Devices", + "SIOC Enabled", "SIOC Congestion Threshold", "SIOC Congestion Threshold Mode", "SIOC Percent Of Peak Throughput") SELECT string_agg(DISTINCT h.ID, ','), ds.Name, @@ -165,7 +166,11 @@ SELECT ds.MaintenanceMode = 'True', ds.Capacity / 1048576, ds.Type, - COALESCE(ds.BackingDevicesNames, '[]') + COALESCE(ds.BackingDevicesNames, '[]'), + false, + 30, + 'automatic', + 90 FROM src.Datastore ds LEFT JOIN ( SELECT h.ID, h.Cluster, dsref->>'id' AS datastore_id diff --git a/pkg/inventory/converters/to_api.go b/pkg/inventory/converters/to_api.go index a453f4dc4..825818f20 100644 --- a/pkg/inventory/converters/to_api.go +++ b/pkg/inventory/converters/to_api.go @@ -202,7 +202,15 @@ func toAPIInfra(i *inventory.InfraData) api.Infra { hostId := d.HostId ds.HostId = &hostId } - // Anonymize NFS datastores + if d.StorageIoConfiguration != nil { + mode := api.StorageIoConfigurationCongestionThresholdMode(d.StorageIoConfiguration.CongestionThresholdMode) + ds.StorageIoConfiguration = &api.StorageIoConfiguration{ + Enabled: &d.StorageIoConfiguration.Enabled, + CongestionThreshold: &d.StorageIoConfiguration.CongestionThreshold, + CongestionThresholdMode: &mode, + PercentOfPeakThroughput: &d.StorageIoConfiguration.PercentOfPeakThroughput, + } + } anonymizeNFSDatastore(&ds) datastores = append(datastores, ds) } diff --git a/pkg/inventory/model.go b/pkg/inventory/model.go index e4fae1dbe..c4436c9fb 100644 --- a/pkg/inventory/model.go +++ b/pkg/inventory/model.go @@ -100,16 +100,25 @@ type Host struct { MemoryMB int } +// StorageIoConfiguration represents VMware Storage I/O Control settings for a datastore. +type StorageIoConfiguration struct { + Enabled bool + CongestionThreshold int + CongestionThresholdMode string + PercentOfPeakThroughput int +} + // Datastore represents a VMware datastore. type Datastore struct { - DiskId string - FreeCapacityGB float64 - TotalCapacityGB float64 - Type string - HostId string - Model string - ProtocolType string - Vendor string + DiskId string + FreeCapacityGB float64 + TotalCapacityGB float64 + Type string + HostId string + Model string + ProtocolType string + Vendor string + StorageIoConfiguration *StorageIoConfiguration } // Network represents a VMware network.