Skip to content

Commit 05f2dfa

Browse files
author
Valeriy Khorunzhin
committed
resolve
Signed-off-by: Valeriy Khorunzhin <valeriy.khorunzhin@flant.com>
1 parent ed1f0cf commit 05f2dfa

9 files changed

Lines changed: 60 additions & 450 deletions

File tree

api/core/v1alpha2/vmbdacondition/condition.go

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,6 @@ const (
6565
Conflict AttachedReason = "Conflict"
6666
// DeviceNotAvailableOnNode indicates that the block device's PersistentVolume is not available on the node where the virtual machine is running.
6767
DeviceNotAvailableOnNode AttachedReason = "DeviceNotAvailableOnNode"
68-
// HotPlugPodNotScheduled indicates that the hotplug pod cannot be scheduled on any node.
69-
HotPlugPodNotScheduled AttachedReason = "HotPlugPodNotScheduled"
70-
// FailedAttachVolume indicates that the hotplug pod failed to attach a volume.
71-
FailedAttachVolume AttachedReason = "FailedAttachVolume"
7268

7369
// CapacityAvailable signifies that the capacity not reached and attaching available.
7470
CapacityAvailable DiskAttachmentCapacityAvailableReason = "CapacityAvailable"

api/core/v1alpha2/vmcondition/condition.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,6 @@ const (
169169
ReasonVirtualMachineRunning RunningReason = "Running"
170170
ReasonInternalVirtualMachineError RunningReason = "InternalVirtualMachineError"
171171
ReasonPodNotStarted RunningReason = "PodNotStarted"
172-
ReasonPodVolumeErrors RunningReason = "PodVolumeErrors"
173172
ReasonPodTerminating RunningReason = "PodTerminating"
174173
ReasonPodNotFound RunningReason = "PodNotFound"
175174
ReasonPodConditionMissing RunningReason = "PodConditionMissing"

images/virtualization-artifact/pkg/common/pod/pod.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,14 @@ limitations under the License.
1717
package pod
1818

1919
import (
20+
"context"
21+
"slices"
22+
2023
corev1 "k8s.io/api/core/v1"
2124
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
25+
"k8s.io/apimachinery/pkg/fields"
2226
"k8s.io/utils/ptr"
27+
"sigs.k8s.io/controller-runtime/pkg/client"
2328
)
2429

2530
// MakeOwnerReference makes owner reference from a Pod
@@ -108,6 +113,46 @@ func IsPodComplete(pod *corev1.Pod) bool {
108113
return pod != nil && pod.Status.Phase == corev1.PodSucceeded
109114
}
110115

116+
func GetLastPodEvent(ctx context.Context, clientObject client.Client, pod *corev1.Pod) (*corev1.Event, error) {
117+
if pod == nil {
118+
return nil, nil
119+
}
120+
121+
eventList := &corev1.EventList{}
122+
err := clientObject.List(ctx, eventList, &client.ListOptions{
123+
Namespace: pod.Namespace,
124+
FieldSelector: fields.SelectorFromSet(fields.Set{
125+
"involvedObject.name": pod.Name,
126+
"involvedObject.kind": "Pod",
127+
}),
128+
})
129+
if err != nil {
130+
return nil, err
131+
}
132+
133+
if len(eventList.Items) == 0 {
134+
return nil, nil
135+
}
136+
137+
last := slices.MaxFunc(eventList.Items, func(a, b corev1.Event) int {
138+
return a.LastTimestamp.Compare(b.LastTimestamp.Time)
139+
})
140+
141+
return &last, nil
142+
}
143+
144+
func IsContainerCreating(pod *corev1.Pod) bool {
145+
if pod.Status.Phase != corev1.PodPending {
146+
return false
147+
}
148+
for _, cs := range pod.Status.ContainerStatuses {
149+
if cs.State.Waiting != nil && cs.State.Waiting.Reason == "ContainerCreating" {
150+
return true
151+
}
152+
}
153+
return false
154+
}
155+
111156
// QemuSubGID is the gid used as the qemu group in fsGroup
112157
const QemuSubGID = int64(107)
113158

images/virtualization-artifact/pkg/controller/vm/internal/lifecycle.go

Lines changed: 15 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,16 @@ import (
2020
"context"
2121
"fmt"
2222
"log/slog"
23-
"slices"
2423

2524
corev1 "k8s.io/api/core/v1"
2625
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
27-
"k8s.io/apimachinery/pkg/fields"
2826
"k8s.io/apimachinery/pkg/labels"
2927
virtv1 "kubevirt.io/api/core/v1"
3028
"sigs.k8s.io/controller-runtime/pkg/client"
3129
"sigs.k8s.io/controller-runtime/pkg/reconcile"
3230

3331
"github.com/deckhouse/virtualization-controller/pkg/common/annotations"
32+
ccpod "github.com/deckhouse/virtualization-controller/pkg/common/pod"
3433
"github.com/deckhouse/virtualization-controller/pkg/controller/conditions"
3534
"github.com/deckhouse/virtualization-controller/pkg/controller/service"
3635
"github.com/deckhouse/virtualization-controller/pkg/controller/vm/internal/state"
@@ -55,11 +54,6 @@ type LifeCycleHandler struct {
5554
recorder eventrecord.EventRecorderLogger
5655
}
5756

58-
type podVolumeErrorEvent struct {
59-
Reason string
60-
Message string
61-
}
62-
6357
func (h *LifeCycleHandler) Handle(ctx context.Context, s state.VirtualMachineState) (reconcile.Result, error) {
6458
if s.VirtualMachine().IsEmpty() {
6559
return reconcile.Result{}, nil
@@ -109,19 +103,6 @@ func (h *LifeCycleHandler) Handle(ctx context.Context, s state.VirtualMachineSta
109103
}
110104

111105
log := logger.FromContext(ctx).With(logger.SlogHandler(nameLifeCycleHandler))
112-
// While the pod is not running, the VMI does not set the node and the method returns nil, so it is necessary to check if there are any issues with the pod
113-
if pod == nil {
114-
cb := conditions.NewConditionBuilder(vmcondition.TypeRunning).Generation(changed.GetGeneration())
115-
116-
if volumeErr := h.checkPodVolumeErrors(ctx, changed, log); volumeErr != nil {
117-
cb.Status(metav1.ConditionFalse).
118-
Reason(vmcondition.ReasonPodVolumeErrors).
119-
Message(fmt.Sprintf("Error attaching block devices to virtual machine: %s: %s", volumeErr.Reason, volumeErr.Message))
120-
conditions.SetCondition(cb, &changed.Status.Conditions)
121-
return reconcile.Result{}, nil
122-
}
123-
}
124-
125106
h.syncRunning(ctx, changed, kvvm, kvvmi, pod, log)
126107
return reconcile.Result{}, nil
127108
}
@@ -141,10 +122,10 @@ func (h *LifeCycleHandler) syncRunning(ctx context.Context, vm *v1alpha2.Virtual
141122
return
142123
}
143124

144-
if volumeError := h.checkPodVolumeErrors(ctx, vm, log); volumeError != nil {
125+
if volumeError := h.checkVMPodVolumeErrors(ctx, vm, log); volumeError != nil {
145126
cb.Status(metav1.ConditionFalse).
146-
Reason(vmcondition.ReasonPodVolumeErrors).
147-
Message(fmt.Sprintf("Error attaching block devices to virtual machine: %s: %s", volumeError.Reason, volumeError.Message))
127+
Reason(vmcondition.ReasonPodNotStarted).
128+
Message(fmt.Sprintf("Error attaching block devices to virtual machine: %s", volumeError.Error()))
148129
conditions.SetCondition(cb, &vm.Status.Conditions)
149130
return
150131
}
@@ -233,7 +214,7 @@ func (h *LifeCycleHandler) syncRunning(ctx context.Context, vm *v1alpha2.Virtual
233214
conditions.SetCondition(cb, &vm.Status.Conditions)
234215
}
235216

236-
func (h *LifeCycleHandler) checkPodVolumeErrors(ctx context.Context, vm *v1alpha2.VirtualMachine, log *slog.Logger) *podVolumeErrorEvent {
217+
func (h *LifeCycleHandler) checkVMPodVolumeErrors(ctx context.Context, vm *v1alpha2.VirtualMachine, log *slog.Logger) error {
237218
var podList corev1.PodList
238219
err := h.client.List(ctx, &podList, &client.ListOptions{
239220
Namespace: vm.Namespace,
@@ -243,62 +224,20 @@ func (h *LifeCycleHandler) checkPodVolumeErrors(ctx context.Context, vm *v1alpha
243224
})
244225
if err != nil {
245226
log.Error("Failed to list pods", "error", err)
246-
return nil
227+
return err
247228
}
248229

249-
for i := range podList.Items {
250-
if volumeErr := h.getPodVolumeError(ctx, &podList.Items[i], log); volumeErr != nil {
251-
return volumeErr
230+
for _, pod := range podList.Items {
231+
if !ccpod.IsContainerCreating(&pod) {
232+
continue
252233
}
253-
}
254-
255-
return nil
256-
}
257-
258-
func isContainerCreating(pod *corev1.Pod) bool {
259-
if pod == nil {
260-
return false
261-
}
262-
if pod.Status.Phase != corev1.PodPending {
263-
return false
264-
}
265-
for _, cs := range pod.Status.ContainerStatuses {
266-
if cs.State.Waiting != nil && cs.State.Waiting.Reason == "ContainerCreating" {
267-
return true
234+
lastEvent, err := ccpod.GetLastPodEvent(ctx, h.client, &pod)
235+
if err != nil {
236+
log.Error("Failed to get last pod event", "error", err)
237+
return err
268238
}
269-
}
270-
return false
271-
}
272-
273-
func (h *LifeCycleHandler) getPodVolumeError(ctx context.Context, pod *corev1.Pod, log *slog.Logger) *podVolumeErrorEvent {
274-
if !isContainerCreating(pod) {
275-
return nil
276-
}
277-
278-
eventList := &corev1.EventList{}
279-
err := h.client.List(ctx, eventList, &client.ListOptions{
280-
Namespace: pod.Namespace,
281-
FieldSelector: fields.SelectorFromSet(fields.Set{
282-
"involvedObject.name": pod.Name,
283-
"involvedObject.kind": "Pod",
284-
}),
285-
})
286-
if err != nil {
287-
log.Error("Failed to list pod events", "error", err)
288-
return nil
289-
}
290-
291-
if len(eventList.Items) == 0 {
292-
return nil
293-
}
294-
295-
last := slices.MaxFunc(eventList.Items, func(a, b corev1.Event) int {
296-
return a.LastTimestamp.Compare(b.LastTimestamp.Time)
297-
})
298-
if last.Reason == watcher.ReasonFailedAttachVolume || last.Reason == watcher.ReasonFailedMount {
299-
return &podVolumeErrorEvent{
300-
Reason: last.Reason,
301-
Message: last.Message,
239+
if lastEvent != nil && (lastEvent.Reason == watcher.ReasonFailedAttachVolume || lastEvent.Reason == watcher.ReasonFailedMount) {
240+
return fmt.Errorf("failed to attach volume: %s: %s", lastEvent.Reason, lastEvent.Message)
302241
}
303242
}
304243

images/virtualization-artifact/pkg/controller/vmbda/internal/life_cycle.go

Lines changed: 0 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,13 @@ import (
2222
"fmt"
2323
"time"
2424

25-
corev1 "k8s.io/api/core/v1"
2625
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2726
virtv1 "kubevirt.io/api/core/v1"
2827
"sigs.k8s.io/controller-runtime/pkg/reconcile"
2928

3029
"github.com/deckhouse/virtualization-controller/pkg/controller/conditions"
3130
"github.com/deckhouse/virtualization-controller/pkg/controller/service"
3231
intsvc "github.com/deckhouse/virtualization-controller/pkg/controller/vmbda/internal/service"
33-
"github.com/deckhouse/virtualization-controller/pkg/controller/vmbda/internal/watcher"
3432
"github.com/deckhouse/virtualization-controller/pkg/logger"
3533
"github.com/deckhouse/virtualization/api/core/v1alpha2"
3634
"github.com/deckhouse/virtualization/api/core/v1alpha2/vmbdacondition"
@@ -202,10 +200,6 @@ func (h LifeCycleHandler) Handle(ctx context.Context, vmbda *v1alpha2.VirtualMac
202200
if errors.Is(err, intsvc.ErrVolumeStatusNotReady) {
203201
vmbda.Status.Phase = v1alpha2.BlockDeviceAttachmentPhaseInProgress
204202

205-
if handled, podErr := h.handleHotPlugPodIssues(ctx, ad, kvvmi, vmbda, cb); podErr != nil || handled {
206-
return reconcile.Result{}, podErr
207-
}
208-
209203
cb.
210204
Status(metav1.ConditionFalse).
211205
Reason(vmbdacondition.AttachmentRequestSent).
@@ -307,58 +301,3 @@ func (h LifeCycleHandler) Handle(ctx context.Context, vmbda *v1alpha2.VirtualMac
307301
return reconcile.Result{}, err
308302
}
309303
}
310-
311-
func (h LifeCycleHandler) handleHotPlugPodIssues(
312-
ctx context.Context,
313-
ad *intsvc.AttachmentDisk,
314-
kvvmi *virtv1.VirtualMachineInstance,
315-
vmbda *v1alpha2.VirtualMachineBlockDeviceAttachment,
316-
cb *conditions.ConditionBuilder,
317-
) (bool, error) {
318-
hotPlugPod, err := h.attacher.GetHotPlugPod(ctx, ad, kvvmi)
319-
if err != nil {
320-
return false, err
321-
}
322-
if hotPlugPod == nil {
323-
return false, nil
324-
}
325-
326-
for _, c := range hotPlugPod.Status.Conditions {
327-
if c.Type == corev1.PodScheduled && c.Status == corev1.ConditionFalse && c.Message != "" {
328-
vmbda.Status.Phase = v1alpha2.BlockDeviceAttachmentPhasePending
329-
cb.
330-
Status(metav1.ConditionFalse).
331-
Reason(vmbdacondition.HotPlugPodNotScheduled).
332-
Message(fmt.Sprintf("Error attaching block device to virtual machine: %s: %s", c.Reason, c.Message))
333-
return true, nil
334-
}
335-
}
336-
337-
if isContainerCreating(hotPlugPod) {
338-
lastEvent, err := h.attacher.GetLastPodEvent(ctx, hotPlugPod)
339-
if err != nil {
340-
return false, err
341-
}
342-
if lastEvent != nil && (lastEvent.Reason == watcher.ReasonFailedAttachVolume || lastEvent.Reason == watcher.ReasonFailedMount) {
343-
cb.
344-
Status(metav1.ConditionFalse).
345-
Reason(vmbdacondition.FailedAttachVolume).
346-
Message(fmt.Sprintf("Error attaching block device to virtual machine: %s: %s", lastEvent.Reason, lastEvent.Message))
347-
return true, nil
348-
}
349-
}
350-
351-
return false, nil
352-
}
353-
354-
func isContainerCreating(pod *corev1.Pod) bool {
355-
if pod.Status.Phase != corev1.PodPending {
356-
return false
357-
}
358-
for _, cs := range pod.Status.ContainerStatuses {
359-
if cs.State.Waiting != nil && cs.State.Waiting.Reason == "ContainerCreating" {
360-
return true
361-
}
362-
}
363-
return false
364-
}

images/virtualization-artifact/pkg/controller/vmbda/internal/service/attachment_service.go

Lines changed: 0 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,9 @@ import (
2020
"context"
2121
"errors"
2222
"fmt"
23-
"slices"
2423
"strings"
2524

2625
corev1 "k8s.io/api/core/v1"
27-
"k8s.io/apimachinery/pkg/fields"
2826
"k8s.io/apimachinery/pkg/types"
2927
"k8s.io/component-helpers/scheduling/corev1/nodeaffinity"
3028
virtv1 "kubevirt.io/api/core/v1"
@@ -316,69 +314,6 @@ func (s AttachmentService) IsPVAvailableOnVMNode(ctx context.Context, pvc *corev
316314
return true, nil
317315
}
318316

319-
func (s AttachmentService) GetHotPlugPod(ctx context.Context, ad *AttachmentDisk, kvvmi *virtv1.VirtualMachineInstance) (*corev1.Pod, error) {
320-
if ad == nil || kvvmi == nil {
321-
return nil, nil
322-
}
323-
324-
for _, vs := range kvvmi.Status.VolumeStatus {
325-
if vs.HotplugVolume == nil || vs.Name != ad.GenerateName {
326-
continue
327-
}
328-
if vs.HotplugVolume.AttachPodName == "" {
329-
return nil, nil
330-
}
331-
332-
return object.FetchObject(ctx, types.NamespacedName{
333-
Namespace: kvvmi.Namespace,
334-
Name: vs.HotplugVolume.AttachPodName,
335-
}, s.client, &corev1.Pod{})
336-
}
337-
return nil, nil
338-
}
339-
340-
func (s AttachmentService) GetHotPlugPodCondition(ctx context.Context, ad *AttachmentDisk, kvvmi *virtv1.VirtualMachineInstance, condType corev1.PodConditionType) (*corev1.PodCondition, error) {
341-
pod, err := s.GetHotPlugPod(ctx, ad, kvvmi)
342-
if err != nil || pod == nil {
343-
return nil, err
344-
}
345-
346-
for i, c := range pod.Status.Conditions {
347-
if c.Type == condType {
348-
return &pod.Status.Conditions[i], nil
349-
}
350-
}
351-
return nil, nil
352-
}
353-
354-
func (s AttachmentService) GetLastPodEvent(ctx context.Context, pod *corev1.Pod) (*corev1.Event, error) {
355-
if pod == nil {
356-
return nil, nil
357-
}
358-
359-
eventList := &corev1.EventList{}
360-
err := s.client.List(ctx, eventList, &client.ListOptions{
361-
Namespace: pod.Namespace,
362-
FieldSelector: fields.SelectorFromSet(fields.Set{
363-
"involvedObject.name": pod.Name,
364-
"involvedObject.kind": "Pod",
365-
}),
366-
})
367-
if err != nil {
368-
return nil, err
369-
}
370-
371-
if len(eventList.Items) == 0 {
372-
return nil, nil
373-
}
374-
375-
last := slices.MaxFunc(eventList.Items, func(a, b corev1.Event) int {
376-
return a.LastTimestamp.Compare(b.LastTimestamp.Time)
377-
})
378-
379-
return &last, nil
380-
}
381-
382317
func isSameBlockDeviceRefs(a, b v1alpha2.VMBDAObjectRef) bool {
383318
return a.Kind == b.Kind && a.Name == b.Name
384319
}

0 commit comments

Comments
 (0)