Skip to content

Commit c8abe58

Browse files
author
Gregory Kopels
committed
network-operator: update setmultinetpolicy
1 parent f8269e5 commit c8abe58

1 file changed

Lines changed: 107 additions & 10 deletions

File tree

pkg/network/operator.go

Lines changed: 107 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package network
22

33
import (
44
"context"
5+
"errors"
56
"fmt"
67
"time"
78

@@ -203,7 +204,13 @@ func (builder *OperatorBuilder) SetIPForwarding(
203204
return builder, err
204205
}
205206

206-
// SetMultiNetworkPolicy enables network.operator multinetworkpolicy feature.
207+
// SetMultiNetworkPolicy enables or disables the network.operator multinetworkpolicy feature.
208+
// When disabling, the Cluster Network Operator often does not set Progressing=True; the initial
209+
// wait for Progressing=True is skipped in that case only. Enabling keeps the original sequence.
210+
// On disable, we wait until status.observedGeneration catches metadata.generation from the update
211+
// so condition polling is not satisfied from stale status from before this change.
212+
// The wait for Progressing=False uses a disable-specific path: CNO may omit the Progressing
213+
// condition when idle, which would otherwise never match WaitUntilInCondition(..., False).
207214
func (builder *OperatorBuilder) SetMultiNetworkPolicy(state bool, timeout time.Duration) (*OperatorBuilder, error) {
208215
if valid, err := builder.validate(); !valid {
209216
return builder, err
@@ -221,20 +228,34 @@ func (builder *OperatorBuilder) SetMultiNetworkPolicy(state bool, timeout time.D
221228
return nil, err
222229
}
223230

224-
err = builder.WaitUntilInCondition(
225-
operatorv1.OperatorStatusTypeProgressing, 60*time.Second, operatorv1.ConditionTrue)
226-
if err != nil {
227-
return nil, err
231+
targetGeneration := builder.Definition.Generation
232+
233+
if state {
234+
err = builder.WaitUntilInCondition(
235+
operatorv1.OperatorStatusTypeProgressing, 60*time.Second, operatorv1.ConditionTrue)
236+
if err != nil {
237+
return nil, err
238+
}
239+
} else {
240+
err = builder.waitUntilObservedGeneration(targetGeneration, timeout)
241+
if err != nil {
242+
return nil, err
243+
}
244+
}
245+
246+
if state {
247+
err = builder.WaitUntilInCondition(
248+
operatorv1.OperatorStatusTypeProgressing, timeout, operatorv1.ConditionFalse)
249+
} else {
250+
err = builder.waitUntilProgressingSettledOnDisable(timeout)
228251
}
229252

230-
err = builder.WaitUntilInCondition(
231-
operatorv1.OperatorStatusTypeProgressing, timeout, operatorv1.ConditionFalse)
232253
if err != nil {
233254
return nil, err
234255
}
235256

236257
return builder, builder.WaitUntilInCondition(
237-
operatorv1.OperatorStatusTypeAvailable, 60*time.Second, operatorv1.ConditionTrue)
258+
operatorv1.OperatorStatusTypeAvailable, timeout, operatorv1.ConditionTrue)
238259
}
239260

240261
return builder, err
@@ -288,8 +309,8 @@ func (builder *OperatorBuilder) WaitUntilInCondition(
288309
return err
289310
}
290311

291-
klog.V(100).Infof("Wait until network.operator object %s is in condition %v",
292-
builder.Definition.Name, condition)
312+
klog.V(100).Infof("Wait until network.operator object %s has condition %s=%s",
313+
builder.Definition.Name, condition, status)
293314

294315
err := wait.PollUntilContextTimeout(
295316
context.TODO(), 3*time.Second, timeout, true, func(ctx context.Context) (bool, error) {
@@ -306,9 +327,85 @@ func (builder *OperatorBuilder) WaitUntilInCondition(
306327
return false, nil
307328
})
308329

330+
if err != nil && errors.Is(err, context.DeadlineExceeded) && builder.Exists() {
331+
klog.V(100).Infof("timeout waiting for network.operator %s condition %s=%s; last status conditions: %#v",
332+
builder.Definition.Name, condition, status, builder.Object.Status.Conditions)
333+
}
334+
309335
return err
310336
}
311337

338+
// waitUntilObservedGeneration waits until status.observedGeneration reflects the given metadata.generation,
339+
// indicating the operator has reconciled that spec revision.
340+
func (builder *OperatorBuilder) waitUntilObservedGeneration(targetGeneration int64, timeout time.Duration) error {
341+
if valid, err := builder.validate(); !valid {
342+
return err
343+
}
344+
345+
klog.V(100).Infof("Wait until network.operator %s observedGeneration >= %d",
346+
builder.Definition.Name, targetGeneration)
347+
348+
return wait.PollUntilContextTimeout(
349+
context.TODO(), 3*time.Second, timeout, true, func(ctx context.Context) (bool, error) {
350+
if !builder.Exists() {
351+
return false, fmt.Errorf("network.operator object %s does not exist", builder.Definition.Name)
352+
}
353+
354+
return builder.Object.Status.ObservedGeneration >= targetGeneration, nil
355+
})
356+
}
357+
358+
// waitUntilProgressingSettledOnDisable waits until Progressing is False, or until the operator
359+
// reports available and not degraded while Progressing is absent (CNO may omit Progressing when idle).
360+
func (builder *OperatorBuilder) waitUntilProgressingSettledOnDisable(timeout time.Duration) error {
361+
if valid, err := builder.validate(); !valid {
362+
return err
363+
}
364+
365+
klog.V(100).Infof("Wait until network.operator %s is settled after disabling MultiNetworkPolicy",
366+
builder.Definition.Name)
367+
368+
return wait.PollUntilContextTimeout(
369+
context.TODO(), 3*time.Second, timeout, true, func(ctx context.Context) (bool, error) {
370+
if !builder.Exists() {
371+
return false, fmt.Errorf("network.operator object %s does not exist", builder.Definition.Name)
372+
}
373+
374+
for _, c := range builder.Object.Status.Conditions {
375+
if c.Type != operatorv1.OperatorStatusTypeProgressing {
376+
continue
377+
}
378+
379+
return c.Status == operatorv1.ConditionFalse, nil
380+
}
381+
382+
return operatorAvailableAndNotDegraded(builder.Object.Status.Conditions), nil
383+
})
384+
}
385+
386+
func operatorAvailableAndNotDegraded(conditions []operatorv1.OperatorCondition) bool {
387+
var available, degraded *operatorv1.OperatorCondition
388+
389+
for i := range conditions {
390+
switch conditions[i].Type {
391+
case operatorv1.OperatorStatusTypeAvailable:
392+
available = &conditions[i]
393+
case operatorv1.OperatorStatusTypeDegraded:
394+
degraded = &conditions[i]
395+
}
396+
}
397+
398+
if available == nil || available.Status != operatorv1.ConditionTrue {
399+
return false
400+
}
401+
402+
if degraded != nil && degraded.Status == operatorv1.ConditionTrue {
403+
return false
404+
}
405+
406+
return len(conditions) > 0
407+
}
408+
312409
// validate will check that the builder and builder definition are properly initialized before
313410
// accessing any member fields.
314411
func (builder *OperatorBuilder) validate() (bool, error) {

0 commit comments

Comments
 (0)