Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
187 changes: 92 additions & 95 deletions hack/linter/.golangci.yml
Original file line number Diff line number Diff line change
@@ -1,70 +1,6 @@
# golangci configuration

linters-settings:
dupl:
threshold: 100
funlen:
lines: 100
statements: 50
goconst:
min-len: 2
min-occurrences: 2
gocritic:
enabled-tags:
- diagnostic
- experimental
- opinionated
- performance
- style
disabled-checks:
- dupImport # https://github.com/go-critic/go-critic/issues/845
- ifElseChain
- octalLiteral
- paramTypeCombine
- whyNoLint
- wrapperFunc
settings:
hugeParam:
sizeThreshold: 1024
rangeValCopy:
sizeThreshold: 1024
gocyclo:
min-complexity: 15
goimports:
local-prefixes: kubevirt.io/kubevirt
mnd:
# don't include the "operation" and "assign"
checks:
- argument
- case
- condition
- return
ignored-functions:
- '^Eventually$'
- '^EventuallyWithOffset$'
- '^ExpectWithOffset$'
- '^console\.ExpectBatch$'
- '^console\.RunCommand$'
govet:
enable:
- shadow
lll:
line-length: 140
misspell:
locale: US
nolintlint:
allow-unused: false # report any unused nolint directives
require-explanation: false # don't require an explanation for nolint directives
require-specific: false # don't require nolint directives to be specific about which linter is being skipped
stylecheck:
dot-import-whitelist:
- "github.com/onsi/ginkgo/v2"
- "github.com/onsi/gomega"
gofumpt:
extra-rules: true

version: "2"
linters:
disable-all: true
default: none
enable:
- bodyclose
- copyloopvar
Expand All @@ -77,47 +13,108 @@ linters:
- goconst
- gocritic
- gocyclo
- gofmt
- gofumpt
- goheader
- goimports
- mnd
- goprintffuncname
- gosec
- gosimple
- govet
- ineffassign
- lll
- misspell
- mnd
- nakedret
- noctx
- nolintlint
- rowserrcheck
- staticcheck
- stylecheck
- typecheck
- unconvert
- unused
- whitespace

# don't enable:
# - asciicheck
# - scopelint
# - gochecknoglobals
# - gocognit
# - godot
# - godox
# - goerr113
# - interfacer
# - maligned
# - nestif
# - prealloc
# - testpackage
# - revive
# - wsl

issues:
exclude-rules:
- text: 'SA1019: checks.SkipTestIfNoCPUManager'
linters:
- staticcheck
settings:
dupl:
threshold: 100
funlen:
lines: 100
statements: 50
goconst:
min-len: 2
min-occurrences: 2
gocritic:
disabled-checks:
- dupImport
- ifElseChain
- octalLiteral
- paramTypeCombine
- whyNoLint
- wrapperFunc
enabled-tags:
- diagnostic
- experimental
- opinionated
- performance
- style
settings:
hugeParam:
sizeThreshold: 1024
rangeValCopy:
sizeThreshold: 1024
gocyclo:
min-complexity: 15
govet:
enable:
- shadow
lll:
line-length: 140
misspell:
locale: US
mnd:
checks:
- argument
- case
- condition
- return
ignored-functions:
- ^Eventually$
- ^EventuallyWithOffset$
- ^ExpectWithOffset$
- ^console\.ExpectBatch$
- ^console\.RunCommand$
nolintlint:
require-explanation: false
require-specific: false
allow-unused: false
staticcheck:
dot-import-whitelist:
- github.com/onsi/ginkgo/v2
- github.com/onsi/gomega
exclusions:
generated: lax
presets:
- comments
- common-false-positives
- legacy
- std-error-handling
rules:
- linters:
- staticcheck
text: 'SA1019: checks.SkipTestIfNoCPUManager'
paths:
- third_party$
- builtin$
- examples$
formatters:
enable:
- gofmt
- gofumpt
- goimports
settings:
gofumpt:
extra-rules: true
goimports:
local-prefixes:
- kubevirt.io/kubevirt
exclusions:
generated: lax
paths:
- third_party$
- builtin$
- examples$
63 changes: 54 additions & 9 deletions pkg/virt-controller/watch/dra/dra.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,14 @@ const (
deleteNotifFailed = "Failed to process delete notification"
tombstoneGetObjectErrFmt = "couldn't get object from tombstone %+v"

indexByNodeName = "byNodeName"
PCIAddressDeviceAttributeKey = "resource.kubernetes.io/pcieRoot"
MDevUUIDDeviceAttributeKey = "resource.kubernetes.io/mDevUUID"
indexByNodeName = "byNodeName"
PCIAddressDeviceAttributeKey = "resource.kubernetes.io/pcieRoot"
MDevUUIDDeviceAttributeKey = "resource.kubernetes.io/mDevUUID"
DeckhouseGPUPCIAddressAttributeKey = "gpu.deckhouse.io/pciAddress"
DeckhouseGPUDeviceTypeAttributeKey = "gpu.deckhouse.io/deviceType"
DeckhouseGPUSharingStrategyAttributeKey = "gpu.deckhouse.io/sharingStrategy"
DeckhouseGPUDeviceTypePhysical = "physical"
DeckhouseGPUDeviceTypeMIG = "mig"
// USBAddressAttributeKey = "usbAddress"
// No Kubernetes resource.kubernetes.io/ prefix is used because this is a
// driver-specific attribute.
Expand Down Expand Up @@ -568,8 +573,8 @@ func (c *DRAStatusController) getGPUStatus(gpuInfo DeviceInfo, pod *k8sv1.Pod) (
if err != nil {
return gpuStatus, err
}
if info.pciAddress == "" && info.mdevUUID == "" {
return gpuStatus, fmt.Errorf("failed to get pciAddress or mdevUUID for gpu %s", gpuInfo.VMISpecClaimName)
if err := validateGPUDeviceInfo(info, gpuInfo.VMISpecClaimName); err != nil {
return gpuStatus, err
}
attrs := v1.DeviceAttribute{}
if info.pciAddress != "" {
Expand Down Expand Up @@ -636,10 +641,40 @@ type deviceInfo struct {
pciAddress string
mdevUUID string
usbAddress *v1.USBAddress
deviceType string
sharingStrategy string
allowMultipleAllocations bool
bindsToNode bool
}

func validateGPUDeviceInfo(info deviceInfo, claimName string) error {
if info.pciAddress == "" && info.mdevUUID == "" {
return fmt.Errorf("failed to get pciAddress or mdevUUID for gpu %s", claimName)
}
if info.allowMultipleAllocations {
return fmt.Errorf("gpu %s allows multiple allocations and cannot be used for VM passthrough", claimName)
}
if info.sharingStrategy != "" {
return fmt.Errorf("gpu %s uses sharing strategy %q and cannot be used for VM passthrough", claimName, info.sharingStrategy)
}
if info.deviceType == DeckhouseGPUDeviceTypeMIG && info.mdevUUID == "" {
return fmt.Errorf("gpu %s has MIG device type without mdevUUID", claimName)
}
if info.pciAddress != "" && info.deviceType != "" && info.deviceType != DeckhouseGPUDeviceTypePhysical {
return fmt.Errorf("gpu %s has device type %q and cannot be used for PCI passthrough", claimName, info.deviceType)
}
return nil
}

func normalizePCIAddress(address string) string {
parts := strings.Split(address, ":")
if len(parts) == 3 && len(parts[0]) == 8 {
parts[0] = parts[0][4:]
return strings.Join(parts, ":")
}
return address
}

// getDeviceInfo returns the pciAddress, mdevUUID, usbAddress of the device. It will return all if found, otherwise it will return empty strings or nil.
func (c *DRAStatusController) getDeviceInfo(nodeName string, deviceName, driverName string) (deviceInfo, error) {
resourceSlices, err := c.getResourceSlices(nodeName)
Expand All @@ -654,11 +689,21 @@ func (c *DRAStatusController) getDeviceInfo(nodeName string, deviceName, driverN
info := deviceInfo{}

for key, value := range device.Attributes {
if string(key) == PCIAddressDeviceAttributeKey && value.StringValue != nil {
info.pciAddress = *value.StringValue
} else if string(key) == MDevUUIDDeviceAttributeKey && value.StringValue != nil {
if value.StringValue == nil {
continue
}
switch string(key) {
case PCIAddressDeviceAttributeKey:
info.pciAddress = normalizePCIAddress(*value.StringValue)
case DeckhouseGPUPCIAddressAttributeKey:
info.pciAddress = normalizePCIAddress(*value.StringValue)
case MDevUUIDDeviceAttributeKey:
info.mdevUUID = *value.StringValue
} else if string(key) == USBAddressAttributeKey && value.StringValue != nil {
case DeckhouseGPUDeviceTypeAttributeKey:
info.deviceType = *value.StringValue
case DeckhouseGPUSharingStrategyAttributeKey:
info.sharingStrategy = *value.StringValue
case USBAddressAttributeKey:
info.usbAddress, err = resolveUSBAddress(*value.StringValue)
if err != nil {
return deviceInfo{}, err
Expand Down
Loading
Loading