From 57047c4aa723e961ba744329567fdf23d2a8bf48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Radek=20Ma=C5=88=C3=A1k?= Date: Wed, 6 May 2026 15:35:54 +0200 Subject: [PATCH 1/2] Fix nil pointer dereference in IsVirtualMachine Add nil receiver guards to IsVirtualMachine() and IsVirtualMachineScaleSetVM() methods to prevent panic when the receiver is nil. This addresses the issue where EnsureHostInPool calls GetInstanceViewStatus which calls IsVirtualMachine without checking for nil receiver first. Fixes OCPBUGS-62712 --- pkg/provider/virtualmachine/virtualmachine.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pkg/provider/virtualmachine/virtualmachine.go b/pkg/provider/virtualmachine/virtualmachine.go index 924f08c8eb..b15768ae27 100644 --- a/pkg/provider/virtualmachine/virtualmachine.go +++ b/pkg/provider/virtualmachine/virtualmachine.go @@ -129,10 +129,16 @@ func FromVirtualMachineScaleSetVM(vm *compute.VirtualMachineScaleSetVM, opt Mana } func (vm *VirtualMachine) IsVirtualMachine() bool { + if vm == nil { + return false + } return vm.Variant == VariantVirtualMachine } func (vm *VirtualMachine) IsVirtualMachineScaleSetVM() bool { + if vm == nil { + return false + } return vm.Variant == VariantVirtualMachineScaleSetVM } From bdf1e64f00b9628acf222cf8fb903522e7b372f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Radek=20Ma=C5=88=C3=A1k?= Date: Wed, 6 May 2026 15:40:10 +0200 Subject: [PATCH 2/2] UPSTREAM: : Fix EnsureHostInPool nil VM panic on non-VMSS nodes When getVmssVM returns ErrorNotVmssInstance, EnsureHostInPool fell through to vm.GetInstanceViewStatus() with vm == nil, causing a nil pointer dereference panic. Fix the error handling to skip the node (matching the pattern used in GetInstanceIDByNodeName), and add a nil receiver guard to ManagedByVMSS for defensive consistency. Fixes OCPBUGS-62712 --- pkg/provider/azure_vmss.go | 6 ++- pkg/provider/virtualmachine/virtualmachine.go | 2 +- .../virtualmachine/virtualmachine_test.go | 43 +++++++++++++++++++ 3 files changed, 48 insertions(+), 3 deletions(-) create mode 100644 pkg/provider/virtualmachine/virtualmachine_test.go diff --git a/pkg/provider/azure_vmss.go b/pkg/provider/azure_vmss.go index 3a9c3d4556..7197a43f28 100644 --- a/pkg/provider/azure_vmss.go +++ b/pkg/provider/azure_vmss.go @@ -1036,9 +1036,11 @@ func (ss *ScaleSet) EnsureHostInPool(_ *v1.Service, nodeName types.NodeName, bac } logger.Error(err, "failed to get vmss vm", "vmName", vmName) - if !errors.Is(err, ErrorNotVmssInstance) { - return "", "", "", nil, err + if errors.Is(err, ErrorNotVmssInstance) { + klog.Infof("EnsureHostInPool: skipping node %s because it is not a VMSS instance", vmName) + return "", "", "", nil, nil } + return "", "", "", nil, err } statuses := vm.GetInstanceViewStatus() vmPowerState := vmutil.GetVMPowerState(vm.Name, statuses) diff --git a/pkg/provider/virtualmachine/virtualmachine.go b/pkg/provider/virtualmachine/virtualmachine.go index b15768ae27..9cc507aa87 100644 --- a/pkg/provider/virtualmachine/virtualmachine.go +++ b/pkg/provider/virtualmachine/virtualmachine.go @@ -143,7 +143,7 @@ func (vm *VirtualMachine) IsVirtualMachineScaleSetVM() bool { } func (vm *VirtualMachine) ManagedByVMSS() bool { - return vm.Manage == VMSS + return vm != nil && vm.Manage == VMSS } func (vm *VirtualMachine) AsVirtualMachine() *compute.VirtualMachine { diff --git a/pkg/provider/virtualmachine/virtualmachine_test.go b/pkg/provider/virtualmachine/virtualmachine_test.go new file mode 100644 index 0000000000..fa21ebc4aa --- /dev/null +++ b/pkg/provider/virtualmachine/virtualmachine_test.go @@ -0,0 +1,43 @@ +/* +Copyright 2024 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package virtualmachine + +import ( + "testing" + + "sigs.k8s.io/cloud-provider-azure/pkg/consts" +) + +func TestNilVirtualMachine(t *testing.T) { + var vm *VirtualMachine + + if vm.IsVirtualMachine() { + t.Error("nil VirtualMachine should return false for IsVirtualMachine()") + } + if vm.IsVirtualMachineScaleSetVM() { + t.Error("nil VirtualMachine should return false for IsVirtualMachineScaleSetVM()") + } + if vm.ManagedByVMSS() { + t.Error("nil VirtualMachine should return false for ManagedByVMSS()") + } + if vm.GetInstanceViewStatus() != nil { + t.Error("nil VirtualMachine should return nil for GetInstanceViewStatus()") + } + if vm.GetProvisioningState() != consts.ProvisioningStateUnknown { + t.Errorf("nil VirtualMachine should return %q for GetProvisioningState(), got %q", consts.ProvisioningStateUnknown, vm.GetProvisioningState()) + } +}