@@ -53,19 +53,19 @@ func NewWithClient(dynamicClient dynamic.Interface, logger logr.Logger) *Resourc
5353 }
5454}
5555
56- // WaitForResourceToBeReady waits for the resource identified by the given GVK
57- // and NamespacedName. It blocks until the resource is ready, an error occurs, or a context
56+ // WaitForResourceToBeReadyOrDeleted waits for the resource identified by the given GVK
57+ // and NamespacedName. It blocks until the resource is ready or deleted , an error occurs, or a context
5858// cancellation occurs. Note that a nil return value signifies that the resource is ready and
5959// no errors have occurred.
60- func (r * ResourceWatcher ) WaitForResourceToBeReady (ctx context.Context , nn types.NamespacedName , gvk schema.GroupVersionKind ) error {
60+ func (r * ResourceWatcher ) WaitForResourceToBeReadyOrDeleted (ctx context.Context , nn types.NamespacedName , gvk schema.GroupVersionKind ) error {
6161 logger := r .logger .WithValues ("resource" , nn , "resourceGVK" , gvk )
6262 watch , err := r .WatchResource (ctx , nn , gvk )
6363 if err != nil {
6464 return err
6565 }
6666 defer watch .Stop ()
6767 logger .Info ("successfully created watch on resource" )
68- return WaitForResourceToBeReadyViaWatch (ctx , watch , logger )
68+ return WaitForResourceToBeReadyOrDeletedViaWatch (ctx , watch , logger )
6969}
7070
7171// WatchResource creates a watch on a resource identified by the given GVK and NamespacedName.
@@ -79,25 +79,41 @@ func (r *ResourceWatcher) WatchResource(ctx context.Context, nn types.Namespaced
7979 return watch , nil
8080}
8181
82- // WaitForResourceToBeReadyViaWatch monitors a given 'Watch' for any
82+ // WaitForResourceToBeReadyOrDeletedViaWatch monitors a given 'Watch' for any
8383// updates to the resource that the given 'Watch' is targeting. Note that
8484// an error is returned to signify a failure during the 'Watch' process,
85- // while nil is returned to signify the watched resource is ready.
86- func WaitForResourceToBeReadyViaWatch (ctx context.Context , watch watch.Interface , logger logr.Logger ) error {
85+ // while nil is returned to signify the watched resource is ready or deleted .
86+ func WaitForResourceToBeReadyOrDeletedViaWatch (ctx context.Context , w watch.Interface , logger logr.Logger ) error {
8787 for {
8888 select {
8989 case <- ctx .Done ():
9090 return fmt .Errorf ("context was cancelled: %w" , ctx .Err ())
91- case event , ok := <- watch .ResultChan ():
91+ case event , ok := <- w .ResultChan ():
9292 if ! ok {
9393 return fmt .Errorf ("watch channel was closed" )
9494 }
95- ok , reason , err := isResourceReady (event )
95+ if event .Type == watch .Bookmark {
96+ continue // ignore
97+ }
98+ if event .Type == watch .Deleted {
99+ logger .Info ("resource has been deleted; triggering watch completion" )
100+ return nil
101+ }
102+ if event .Type != watch .Modified && event .Type != watch .Added {
103+ return fmt .Errorf ("unexpected watch event type %v" , event .Type )
104+ }
105+
106+ u , ok := event .Object .(* unstructured.Unstructured )
107+ if ! ok {
108+ return fmt .Errorf ("error casting event object '%v' of kind '%v' to unstructured" , event .Object , event .Object .GetObjectKind ())
109+ }
110+
111+ isReady , err := isResourceReady (u )
96112 if err != nil {
97113 return fmt .Errorf ("error checking if resource is ready: %w" , err )
98114 }
99- if ! ok {
100- logger .Info ("resource not ready" , "reason" , reason )
115+ if ! isReady {
116+ logger .Info ("resource not ready" )
101117 continue
102118 }
103119 logger .Info ("resource is ready" )
@@ -107,27 +123,19 @@ func WaitForResourceToBeReadyViaWatch(ctx context.Context, watch watch.Interface
107123}
108124
109125// isResourceReady returns whether a resource identified by the given GVK
110- // and NamespacedName is ready. Note that a 'reason' for failure is returned only
111- // when the resource is not ready and no fatal error has occurred.
112- func isResourceReady (event watch.Event ) (ok bool , reason string , err error ) {
113- if event .Type != watch .Modified && event .Type != watch .Added {
114- return false , fmt .Sprintf ("got watch event of type '%v', want event type '%v' or '%v'" , event .Type , watch .Modified , watch .Added ), nil
115- }
116- u , ok := event .Object .(* unstructured.Unstructured )
117- if ! ok {
118- return false , "" , fmt .Errorf ("error casting event object '%v' of kind '%v' to unstructured" , event .Object , event .Object .GetObjectKind ())
119- }
126+ // and NamespacedName is ready.
127+ func isResourceReady (u * unstructured.Unstructured ) (isReady bool , err error ) {
120128 resource , err := k8s .NewResource (u )
121129 if err != nil {
122- return false , "" , fmt .Errorf ("error converting unstructured to resource: %w" , err )
130+ return false , fmt .Errorf ("error converting unstructured to resource: %w" , err )
123131 }
124132 // Secrets don't have a 'ready' condition. As long as they can be
125133 // found on the API server, we consider them ready as resources.
126134 if resource .Kind == "Secret" {
127- return true , "" , nil
135+ return true , nil
128136 }
129137 if ! k8s .IsResourceReady (resource ) {
130- return false , "resource not ready" , nil
138+ return false , nil
131139 }
132- return true , "" , nil
140+ return true , nil
133141}
0 commit comments