Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1500 from vrutkovs/sno-SendRetryAfterWhileNotRead…
…yOnce OCPBUGS-14008: Enable "send-retry-after-while-not-ready-once" on SNO
- Loading branch information
Showing
3 changed files
with
178 additions
and
0 deletions.
There are no files selected for viewing
58 changes: 58 additions & 0 deletions
58
pkg/operator/configobservation/apiserver/observe_send_retry_after_while_not_ready_once.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
package apiserver | ||
|
||
import ( | ||
"fmt" | ||
"reflect" | ||
"strconv" | ||
|
||
apierrors "k8s.io/apimachinery/pkg/api/errors" | ||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" | ||
|
||
configv1 "github.com/openshift/api/config/v1" | ||
"github.com/openshift/cluster-kube-apiserver-operator/pkg/operator/configobservation" | ||
"github.com/openshift/library-go/pkg/operator/configobserver" | ||
"github.com/openshift/library-go/pkg/operator/events" | ||
) | ||
|
||
var sendRetryAfterWhileNotReadyOncePath = []string{"apiServerArguments", "send-retry-after-while-not-ready-once"} | ||
|
||
// ObserveSendRetryAfterWhileNotReadyOnce ensures that send-retry-after-while-not-ready-once is set for SNO clusters. | ||
func ObserveSendRetryAfterWhileNotReadyOnce(genericListers configobserver.Listers, _ events.Recorder, existingConfig map[string]interface{}) (ret map[string]interface{}, errs []error) { | ||
defer func() { | ||
// Prune the observed config so that it only contains apiServerArguments field. | ||
ret = configobserver.Pruned(ret, sendRetryAfterWhileNotReadyOncePath) | ||
}() | ||
|
||
// read the observed value | ||
listers := genericListers.(configobservation.Listers) | ||
infra, err := listers.InfrastructureLister().Get("cluster") | ||
if err != nil && !apierrors.IsNotFound(err) { | ||
// we got an error so without the infrastructure object we are not able to determine the type of platform we are running on | ||
return existingConfig, append(errs, err) | ||
} | ||
|
||
observedSendRetryAfterWhileNotReadyOnce := strconv.FormatBool(infra.Status.ControlPlaneTopology == configv1.SingleReplicaTopologyMode) | ||
|
||
// read the current value | ||
var currentSendRetryAfterWhileNotReadyOnce string | ||
currentSendRetryAfterWhileNotReadyOnceSlice, _, err := unstructured.NestedStringSlice(existingConfig, sendRetryAfterWhileNotReadyOncePath...) | ||
if err != nil { | ||
errs = append(errs, fmt.Errorf("unable to extract send retry after while not ready setting from the existing config: %v", err)) | ||
// keep going, we are only interested in the observed value which will overwrite the current configuration anyway | ||
} | ||
if len(currentSendRetryAfterWhileNotReadyOnceSlice) > 0 { | ||
currentSendRetryAfterWhileNotReadyOnce = currentSendRetryAfterWhileNotReadyOnceSlice[0] | ||
} | ||
|
||
// see if the current and the observed value differ | ||
observedConfig := map[string]interface{}{} | ||
if !reflect.DeepEqual(observedSendRetryAfterWhileNotReadyOnce, currentSendRetryAfterWhileNotReadyOnce) { | ||
if err = unstructured.SetNestedStringSlice(observedConfig, []string{observedSendRetryAfterWhileNotReadyOnce}, sendRetryAfterWhileNotReadyOncePath...); err != nil { | ||
return existingConfig, append(errs, err) | ||
} | ||
return observedConfig, errs | ||
} | ||
|
||
// nothing has changed return the original configuration | ||
return existingConfig, errs | ||
} |
119 changes: 119 additions & 0 deletions
119
...perator/configobservation/apiserver/observe_send_retry_after_while_not_ready_once_test.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
package apiserver | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/google/go-cmp/cmp" | ||
|
||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
"k8s.io/client-go/tools/cache" | ||
|
||
configv1 "github.com/openshift/api/config/v1" | ||
kubecontrolplanev1 "github.com/openshift/api/kubecontrolplane/v1" | ||
configlistersv1 "github.com/openshift/client-go/config/listers/config/v1" | ||
"github.com/openshift/cluster-kube-apiserver-operator/pkg/operator/configobservation" | ||
"github.com/openshift/library-go/pkg/operator/events" | ||
) | ||
|
||
func TestObserveSendRetryAfterWhileNotReadyOnce(t *testing.T) { | ||
scenarios := []struct { | ||
name string | ||
validateKubeAPIConfigFn func(kubecontrolplanev1.KubeAPIServerConfig) error | ||
existingKubeAPIConfig map[string]interface{} | ||
expectedKubeAPIConfig map[string]interface{} | ||
controlPlaneTopology configv1.TopologyMode | ||
}{ | ||
|
||
// scenario 1 - HA unset | ||
{ | ||
name: "ha: defaults to false", | ||
controlPlaneTopology: configv1.HighlyAvailableTopologyMode, | ||
expectedKubeAPIConfig: map[string]interface{}{"apiServerArguments": map[string]interface{}{ | ||
"send-retry-after-while-not-ready-once": []interface{}{"false"}, | ||
}}, | ||
}, | ||
|
||
// scenario 3 - HA, update not required | ||
{ | ||
name: "ha: update not required", | ||
controlPlaneTopology: configv1.HighlyAvailableTopologyMode, | ||
existingKubeAPIConfig: map[string]interface{}{"apiServerArguments": map[string]interface{}{ | ||
"send-retry-after-while-not-ready-once": []interface{}{"false"}, | ||
}}, | ||
expectedKubeAPIConfig: map[string]interface{}{"apiServerArguments": map[string]interface{}{ | ||
"send-retry-after-while-not-ready-once": []interface{}{"false"}, | ||
}}, | ||
}, | ||
|
||
// scenario 4 - HA, update required | ||
{ | ||
name: "ha: update required", | ||
controlPlaneTopology: configv1.HighlyAvailableTopologyMode, | ||
existingKubeAPIConfig: map[string]interface{}{"apiServerArguments": map[string]interface{}{ | ||
"send-retry-after-while-not-ready-once": []interface{}{"true"}, | ||
}}, | ||
expectedKubeAPIConfig: map[string]interface{}{"apiServerArguments": map[string]interface{}{ | ||
"send-retry-after-while-not-ready-once": []interface{}{"false"}, | ||
}}, | ||
}, | ||
|
||
// scenario 5 - SNO | ||
{ | ||
name: "ha: defaults to true", | ||
controlPlaneTopology: configv1.SingleReplicaTopologyMode, | ||
expectedKubeAPIConfig: map[string]interface{}{"apiServerArguments": map[string]interface{}{ | ||
"send-retry-after-while-not-ready-once": []interface{}{"true"}, | ||
}}, | ||
}, | ||
|
||
// scenario 6 - SNO, update required | ||
{ | ||
name: "sno: update required", | ||
controlPlaneTopology: configv1.SingleReplicaTopologyMode, | ||
existingKubeAPIConfig: map[string]interface{}{"apiServerArguments": map[string]interface{}{ | ||
"send-retry-after-while-not-ready-once": []interface{}{"false"}, | ||
}}, | ||
expectedKubeAPIConfig: map[string]interface{}{"apiServerArguments": map[string]interface{}{ | ||
"send-retry-after-while-not-ready-once": []interface{}{"true"}, | ||
}}, | ||
}, | ||
|
||
// scenario 7 - SNO, update not required | ||
{ | ||
name: "sno: update not required", | ||
controlPlaneTopology: configv1.SingleReplicaTopologyMode, | ||
existingKubeAPIConfig: map[string]interface{}{"apiServerArguments": map[string]interface{}{ | ||
"send-retry-after-while-not-ready-once": []interface{}{"true"}, | ||
}}, | ||
expectedKubeAPIConfig: map[string]interface{}{"apiServerArguments": map[string]interface{}{ | ||
"send-retry-after-while-not-ready-once": []interface{}{"true"}, | ||
}}, | ||
}, | ||
} | ||
|
||
for _, scenario := range scenarios { | ||
t.Run(scenario.name, func(t *testing.T) { | ||
// test data | ||
eventRecorder := events.NewInMemoryRecorder("") | ||
infrastructureIndexer := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{}) | ||
infrastructureIndexer.Add(&configv1.Infrastructure{ | ||
ObjectMeta: metav1.ObjectMeta{Name: "cluster"}, | ||
Status: configv1.InfrastructureStatus{ControlPlaneTopology: scenario.controlPlaneTopology}, | ||
}) | ||
listers := configobservation.Listers{ | ||
InfrastructureLister_: configlistersv1.NewInfrastructureLister(infrastructureIndexer), | ||
} | ||
|
||
// act | ||
observedKubeAPIConfig, err := ObserveSendRetryAfterWhileNotReadyOnce(listers, eventRecorder, scenario.existingKubeAPIConfig) | ||
|
||
// validate | ||
if len(err) > 0 { | ||
t.Fatal(err) | ||
} | ||
if !cmp.Equal(scenario.expectedKubeAPIConfig, observedKubeAPIConfig) { | ||
t.Fatalf("unexpected configuration, diff = %v", cmp.Diff(scenario.expectedKubeAPIConfig, observedKubeAPIConfig)) | ||
} | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters