@@ -30,9 +30,12 @@ import (
30
30
k8serr "k8s.io/apimachinery/pkg/api/errors"
31
31
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
32
32
"k8s.io/apimachinery/pkg/labels"
33
+ "k8s.io/apimachinery/pkg/runtime"
33
34
"k8s.io/apimachinery/pkg/types"
34
35
"k8s.io/apimachinery/pkg/util/wait"
35
36
"k8s.io/client-go/kubernetes"
37
+ covev1client "k8s.io/client-go/kubernetes/typed/core/v1"
38
+ "k8s.io/client-go/tools/record"
36
39
"k8s.io/client-go/util/retry"
37
40
"sigs.k8s.io/controller-runtime/pkg/client"
38
41
@@ -69,6 +72,8 @@ type Manager struct {
69
72
70
73
metrics * metrics
71
74
75
+ eventRecorder record.EventRecorder
76
+
72
77
api.UnimplementedWorkspaceManagerServer
73
78
regapi.UnimplementedSpecProviderServer
74
79
}
@@ -127,14 +132,19 @@ func New(config config.Configuration, client client.Client, rawClient kubernetes
127
132
return nil , err
128
133
}
129
134
135
+ broadcaster := record .NewBroadcaster ()
136
+ broadcaster .StartRecordingToSink (& covev1client.EventSinkImpl {Interface : rawClient .CoreV1 ().Events ("" )})
137
+ eventRecorder := broadcaster .NewRecorder (runtime .NewScheme (), corev1.EventSource {Component : "ws-manager" })
138
+
130
139
m := & Manager {
131
- Config : config ,
132
- Clientset : client ,
133
- RawClient : rawClient ,
134
- Content : cp ,
135
- clock : clock .System (),
136
- subscribers : make (map [string ]chan * api.SubscribeResponse ),
137
- wsdaemonPool : grpcpool .New (wsdaemonConnfactory , checkWSDaemonEndpoint (config .Namespace , client )),
140
+ Config : config ,
141
+ Clientset : client ,
142
+ RawClient : rawClient ,
143
+ Content : cp ,
144
+ clock : clock .System (),
145
+ subscribers : make (map [string ]chan * api.SubscribeResponse ),
146
+ wsdaemonPool : grpcpool .New (wsdaemonConnfactory , checkWSDaemonEndpoint (config .Namespace , client )),
147
+ eventRecorder : eventRecorder ,
138
148
}
139
149
m .metrics = newMetrics (m )
140
150
m .OnChange = m .onChange
@@ -310,20 +320,37 @@ func (m *Manager) StartWorkspace(ctx context.Context, req *api.StartWorkspaceReq
310
320
}
311
321
312
322
// we only calculate the time that PVC restoring from VolumeSnapshot
313
- if createPVC && startContext .VolumeSnapshot != nil && startContext .VolumeSnapshot .VolumeSnapshotName != "" {
314
- err := wait .PollWithContext (ctx , 100 * time .Millisecond , 5 * time .Minute , pvcRunning (m .Clientset , pvc .Name , pvc .Namespace ))
315
- if err == nil {
316
- wsType := api .WorkspaceType_name [int32 (req .Type )]
317
- hist , err := m .metrics .volumeRestoreTimeHistVec .GetMetricWithLabelValues (wsType , req .Spec .Class )
318
- if err != nil {
319
- log .WithError (err ).WithField ("type" , wsType ).Warn ("cannot get volume restore time histogram metric" )
320
- } else if endTime .IsZero () {
321
- endTime = time .Now ()
322
- hist .Observe (endTime .Sub (startTime ).Seconds ())
323
- }
323
+ if createPVC {
324
+ err = m .Clientset .Get (ctx , types.NamespacedName {Namespace : pod .Namespace , Name : pod .Name }, pod )
325
+ if err != nil {
326
+ return nil , xerrors .Errorf ("unable to get workspace pod %s: %w" , pod .Name , err )
324
327
}
325
328
326
- log .WithError (err ).Warn ("unexpected error waiting for PVC" )
329
+ err = wait .PollWithContext (ctx , 100 * time .Millisecond , 5 * time .Minute , pvcRunning (m .Clientset , pvc .Name , pvc .Namespace ))
330
+ if err != nil {
331
+ if startContext .VolumeSnapshot != nil && startContext .VolumeSnapshot .VolumeSnapshotName != "" {
332
+ m .eventRecorder .Eventf (pod , corev1 .EventTypeWarning , "PVC" , "PVC %q restored from volume snapshot %s failed %v" , pvc .Name , startContext .VolumeSnapshot .VolumeSnapshotName , err )
333
+ log .WithError (err ).Warnf ("unexpected error waiting for PVC %s volume snapshot %s/%s" , pvc .Name , startContext .VolumeSnapshot .VolumeSnapshotName )
334
+ } else {
335
+ m .eventRecorder .Eventf (pod , corev1 .EventTypeWarning , "PVC" , "PVC %q created failed %v" , pvc .Name , err )
336
+ log .WithError (err ).Warnf ("unexpected error waiting for PVC %s" , pvc .Name )
337
+ }
338
+ } else {
339
+ if startContext .VolumeSnapshot != nil && startContext .VolumeSnapshot .VolumeSnapshotName != "" {
340
+ m .eventRecorder .Eventf (pod , corev1 .EventTypeNormal , "PVC" , "PVC %q restored from volume snapshot %s successfully" , pvc .Name , startContext .VolumeSnapshot .VolumeSnapshotName )
341
+
342
+ wsType := api .WorkspaceType_name [int32 (req .Type )]
343
+ hist , err := m .metrics .volumeRestoreTimeHistVec .GetMetricWithLabelValues (wsType , req .Spec .Class )
344
+ if err != nil {
345
+ log .WithError (err ).WithField ("type" , wsType ).Warn ("cannot get volume restore time histogram metric" )
346
+ } else if endTime .IsZero () {
347
+ endTime = time .Now ()
348
+ hist .Observe (endTime .Sub (startTime ).Seconds ())
349
+ }
350
+ } else {
351
+ m .eventRecorder .Eventf (pod , corev1 .EventTypeNormal , "PVC" , "PVC %q created successfully" , pvc .Name )
352
+ }
353
+ }
327
354
}
328
355
329
356
// remove annotation to signal that workspace pod was indeed created and scheduled on the node
0 commit comments