Skip to content

Commit 38f3cf7

Browse files
committed
Watch VolumeSnapshot object is ready
When the VolumeSnapshot object is ready, notify to the Pod that it belongs to. Signed-off-by: JenTing Hsiao <[email protected]>
1 parent 01c7c26 commit 38f3cf7

File tree

1 file changed

+59
-38
lines changed

1 file changed

+59
-38
lines changed

components/ws-manager/pkg/manager/monitor.go

Lines changed: 59 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ import (
2626
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2727
"k8s.io/apimachinery/pkg/labels"
2828
"k8s.io/apimachinery/pkg/types"
29-
"k8s.io/apimachinery/pkg/util/wait"
3029
"k8s.io/apimachinery/pkg/watch"
3130
"sigs.k8s.io/controller-runtime/pkg/client"
3231

@@ -83,6 +82,8 @@ type Monitor struct {
8382
act actingManager
8483

8584
OnError func(error)
85+
86+
notifyPod map[string]chan string
8687
}
8788

8889
// CreateMonitor creates a new monitor
@@ -103,6 +104,8 @@ func (m *Manager) CreateMonitor() (*Monitor, error) {
103104
OnError: func(err error) {
104105
log.WithError(err).Error("workspace monitor error")
105106
},
107+
108+
notifyPod: make(map[string]chan string),
106109
}
107110
res.eventpool = workpool.NewEventWorkerPool(res.handleEvent)
108111
res.act = struct {
@@ -145,13 +148,47 @@ func (m *Monitor) handleEvent(evt watch.Event) {
145148
switch evt.Object.(type) {
146149
case *corev1.Pod:
147150
err = m.onPodEvent(evt)
151+
case *volumesnapshotv1.VolumeSnapshot:
152+
err = m.onVolumesnapshotEvent(evt)
148153
}
149154

150155
if err != nil {
151156
m.OnError(err)
152157
}
153158
}
154159

160+
func (m *Monitor) onVolumesnapshotEvent(evt watch.Event) error {
161+
vs, ok := evt.Object.(*volumesnapshotv1.VolumeSnapshot)
162+
if !ok {
163+
return xerrors.Errorf("received non-volume-snapshot event")
164+
}
165+
166+
log := log.WithField("volumesnapshot", vs.Name)
167+
168+
if vs.Spec.Source.PersistentVolumeClaimName == nil {
169+
// there is no pvc name within the VolumeSnapshot object
170+
log.Warn("the spec.source.persistentVolumeClaimName is empty")
171+
return nil
172+
}
173+
174+
// the pod name is 1:1 mapping to pvc name
175+
podName := *vs.Spec.Source.PersistentVolumeClaimName
176+
log = log.WithField("pod", podName)
177+
178+
if vs.Status == nil || vs.Status.ReadyToUse == nil || !*vs.Status.ReadyToUse || vs.Status.BoundVolumeSnapshotContentName == nil {
179+
return nil
180+
}
181+
182+
vsc := *vs.Status.BoundVolumeSnapshotContentName
183+
log.Infof("the vsc %s is ready", vsc)
184+
if m.notifyPod[podName] == nil {
185+
m.notifyPod[podName] = make(chan string)
186+
}
187+
m.notifyPod[podName] <- vsc
188+
189+
return nil
190+
}
191+
155192
// onPodEvent interpretes Kubernetes events, translates and broadcasts them, and acts based on them
156193
func (m *Monitor) onPodEvent(evt watch.Event) error {
157194
// Beware: we patch running pods to add annotations. At the moment this is not a problem as do not attach
@@ -987,47 +1024,31 @@ func (m *Monitor) finalizeWorkspaceContent(ctx context.Context, wso *workspaceOb
9871024
volumeSnapshotTime = time.Now()
9881025
}
9891026
if createdVolumeSnapshot {
990-
backoff := wait.Backoff{
991-
Steps: 30,
992-
Duration: 100 * time.Millisecond,
993-
Factor: 1.5,
994-
Jitter: 0.1,
995-
Cap: 10 * time.Minute,
1027+
if m.notifyPod[wso.Pod.Name] == nil {
1028+
m.notifyPod[wso.Pod.Name] = make(chan string)
9961029
}
997-
log = log.WithField("VolumeSnapshot.Name", pvcVolumeSnapshotName)
998-
err = wait.ExponentialBackoff(backoff, func() (bool, error) {
999-
var volumeSnapshot volumesnapshotv1.VolumeSnapshot
1000-
err := m.manager.Clientset.Get(ctx, types.NamespacedName{Namespace: m.manager.Config.Namespace, Name: pvcVolumeSnapshotName}, &volumeSnapshot)
1001-
if err != nil {
1002-
if k8serr.IsNotFound(err) {
1003-
// volumesnapshot doesn't exist yet, retry again
1004-
return false, nil
1005-
}
1006-
log.WithError(err).Error("was unable to get volume snapshot")
1007-
return false, err
1008-
}
1009-
if volumeSnapshot.Status != nil {
1010-
if volumeSnapshot.Status.ReadyToUse != nil && *(volumeSnapshot.Status.ReadyToUse) && volumeSnapshot.Status.BoundVolumeSnapshotContentName != nil {
1011-
pvcVolumeSnapshotContentName = *volumeSnapshot.Status.BoundVolumeSnapshotContentName
1012-
return true, nil
1013-
}
1014-
if volumeSnapshot.Status.Error != nil {
1015-
if volumeSnapshot.Status.Error.Message != nil {
1016-
err = xerrors.Errorf("error during volume snapshot creation: %s", *volumeSnapshot.Status.Error.Message)
1017-
log.WithError(err).Error("unable to create volume snapshot")
1018-
return false, err
1019-
}
1020-
log.Error("unknown error during volume snapshot creation")
1021-
return false, xerrors.Errorf("unknown error during volume snapshot creation")
1022-
}
1030+
1031+
select {
1032+
case pvcVolumeSnapshotContentName = <-m.notifyPod[wso.Pod.Name]:
1033+
readyVolumeSnapshot = true
1034+
case <-ctx.Done():
1035+
// There might be a chance that the VolumeSnapshot is ready but somehow
1036+
// we did not receive the notification.
1037+
// For example, the ws-manager restarts before the VolumeSnapshot becomes ready.
1038+
// Let's give it the last chance to check the VolumeSnapshot is ready.
1039+
var vs volumesnapshotv1.VolumeSnapshot
1040+
err := m.manager.Clientset.Get(ctx, types.NamespacedName{Namespace: m.manager.Config.Namespace, Name: pvcVolumeSnapshotName}, &vs)
1041+
if err == nil && vs.Status != nil && vs.Status.ReadyToUse != nil && *vs.Status.ReadyToUse && vs.Status.BoundVolumeSnapshotContentName != nil {
1042+
pvcVolumeSnapshotContentName = *vs.Status.BoundVolumeSnapshotContentName
1043+
readyVolumeSnapshot = true
1044+
break
10231045
}
1024-
return false, nil
1025-
})
1026-
if err != nil {
1027-
log.WithError(err).Errorf("failed while waiting for volume snapshot to get ready")
1046+
1047+
err = xerrors.Errorf("%s timed out while waiting for volume snapshot to get ready", m.manager.Config.Timeouts.ContentFinalization.String())
1048+
log.Error(err.Error())
10281049
return true, nil, err
10291050
}
1030-
readyVolumeSnapshot = true
1051+
10311052
hist, err := m.manager.metrics.volumeSnapshotTimeHistVec.GetMetricWithLabelValues(wsType, wso.Pod.Labels[workspaceClassLabel])
10321053
if err != nil {
10331054
log.WithError(err).WithField("type", wsType).Warn("cannot get volume snapshot time histogram metric")

0 commit comments

Comments
 (0)