зеркало из https://github.com/Azure/ARO-RP.git
Merge pull request #951 from asalkeld/apply-system-reserve
Add workaround controller and systemreserved fix
This commit is contained in:
Коммит
01f13f2565
|
@ -8,7 +8,9 @@ import (
|
|||
"flag"
|
||||
"fmt"
|
||||
|
||||
configclient "github.com/openshift/client-go/config/clientset/versioned"
|
||||
securityclient "github.com/openshift/client-go/security/clientset/versioned"
|
||||
mcoclient "github.com/openshift/machine-config-operator/pkg/generated/clientset/versioned"
|
||||
"github.com/sirupsen/logrus"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
|
@ -20,6 +22,7 @@ import (
|
|||
"github.com/Azure/ARO-RP/pkg/operator/controllers/genevalogging"
|
||||
"github.com/Azure/ARO-RP/pkg/operator/controllers/internetchecker"
|
||||
"github.com/Azure/ARO-RP/pkg/operator/controllers/pullsecret"
|
||||
"github.com/Azure/ARO-RP/pkg/operator/controllers/workaround"
|
||||
utillog "github.com/Azure/ARO-RP/pkg/util/log"
|
||||
// +kubebuilder:scaffold:imports
|
||||
)
|
||||
|
@ -55,6 +58,14 @@ func operator(ctx context.Context, log *logrus.Entry) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
configcli, err := configclient.NewForConfig(restConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
mcocli, err := mcoclient.NewForConfig(restConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
arocli, err := aroclient.NewForConfig(restConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -77,6 +88,11 @@ func operator(ctx context.Context, log *logrus.Entry) error {
|
|||
kubernetescli)).SetupWithManager(mgr); err != nil {
|
||||
return fmt.Errorf("unable to create controller AlertWebhook: %v", err)
|
||||
}
|
||||
if err = (workaround.NewReconciler(
|
||||
log.WithField("controller", controllers.WorkaroundControllerName),
|
||||
kubernetescli, configcli, mcocli, arocli, restConfig)).SetupWithManager(mgr); err != nil {
|
||||
return fmt.Errorf("unable to create controller Workaround: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if err = (internetchecker.NewReconciler(
|
||||
|
|
|
@ -8,4 +8,5 @@ const (
|
|||
GenevaLoggingControllerName = "GenevaLogging"
|
||||
PullSecretControllerName = "PullSecret"
|
||||
InternetCheckerControllerName = "InternetChecker"
|
||||
WorkaroundControllerName = "Workaround"
|
||||
)
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
package workaround
|
||||
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the Apache License 2.0.
|
||||
|
||||
//go:generate go run ../../../../vendor/github.com/golang/mock/mockgen -destination=../../../util/mocks/operator/controllers/$GOPACKAGE/$GOPACKAGE.go github.com/Azure/ARO-RP/pkg/operator/controllers/$GOPACKAGE Workaround
|
||||
//go:generate go run ../../../../vendor/golang.org/x/tools/cmd/goimports -local=github.com/Azure/ARO-RP -e -w ../../../util/mocks/operator/controllers/$GOPACKAGE/$GOPACKAGE.go
|
|
@ -0,0 +1,145 @@
|
|||
package workaround
|
||||
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the Apache License 2.0.
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
mcv1 "github.com/openshift/machine-config-operator/pkg/apis/machineconfiguration.openshift.io/v1"
|
||||
mcoclient "github.com/openshift/machine-config-operator/pkg/generated/clientset/versioned"
|
||||
"github.com/sirupsen/logrus"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
"k8s.io/client-go/util/retry"
|
||||
|
||||
"github.com/Azure/ARO-RP/pkg/util/dynamichelper"
|
||||
"github.com/Azure/ARO-RP/pkg/util/version"
|
||||
)
|
||||
|
||||
type systemreserved struct {
|
||||
mcocli mcoclient.Interface
|
||||
dh dynamichelper.DynamicHelper
|
||||
log *logrus.Entry
|
||||
versionFixed *version.Version
|
||||
}
|
||||
|
||||
const (
|
||||
labelName = "aro.openshift.io/limits"
|
||||
labelValue = ""
|
||||
kubeletConfigName = "aro-limits"
|
||||
workerMachineConfigPoolName = "worker"
|
||||
memReserved = "2000Mi"
|
||||
)
|
||||
|
||||
var (
|
||||
_ Workaround = &systemreserved{}
|
||||
)
|
||||
|
||||
func NewSystemReserved(log *logrus.Entry, mcocli mcoclient.Interface, dh dynamichelper.DynamicHelper) *systemreserved {
|
||||
verFixed, err := version.ParseVersion("4.99.0") // TODO set this correctly when known.
|
||||
utilruntime.Must(err)
|
||||
|
||||
return &systemreserved{
|
||||
mcocli: mcocli,
|
||||
dh: dh,
|
||||
log: log,
|
||||
versionFixed: verFixed,
|
||||
}
|
||||
}
|
||||
|
||||
func (sr *systemreserved) Name() string {
|
||||
return "SystemReserved fix for bz-1857446"
|
||||
}
|
||||
|
||||
func (sr *systemreserved) IsRequired(clusterVersion *version.Version) bool {
|
||||
return clusterVersion.Lt(sr.versionFixed)
|
||||
}
|
||||
|
||||
func (sr *systemreserved) kubeletConfig() (*unstructured.Unstructured, error) {
|
||||
kubeletConfig := map[string]map[string]string{
|
||||
"systemReserved": {
|
||||
"memory": memReserved,
|
||||
},
|
||||
}
|
||||
cfgJSON, err := json.Marshal(kubeletConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
kc := &mcv1.KubeletConfig{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: kubeletConfigName,
|
||||
Labels: map[string]string{labelName: labelValue},
|
||||
},
|
||||
Spec: mcv1.KubeletConfigSpec{
|
||||
MachineConfigPoolSelector: &metav1.LabelSelector{
|
||||
MatchLabels: map[string]string{labelName: labelValue},
|
||||
},
|
||||
KubeletConfig: &runtime.RawExtension{Raw: cfgJSON},
|
||||
},
|
||||
}
|
||||
un := &unstructured.Unstructured{}
|
||||
err = scheme.Scheme.Convert(kc, un, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return un, nil
|
||||
}
|
||||
|
||||
func (sr *systemreserved) Ensure() error {
|
||||
// Step 1. Add label to worker MachineConfigPool.
|
||||
// Get the worker MachineConfigPool, modify it to add a label bz-1857446: hotfixed, and apply the modified config.
|
||||
err := retry.RetryOnConflict(retry.DefaultRetry, func() error {
|
||||
mcp, err := sr.mcocli.MachineconfigurationV1().MachineConfigPools().Get(workerMachineConfigPoolName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, ok := mcp.Labels[labelName]; ok {
|
||||
// don't update if we don't need to.
|
||||
return nil
|
||||
}
|
||||
if mcp.Labels == nil {
|
||||
mcp.Labels = map[string]string{}
|
||||
}
|
||||
mcp.Labels[labelName] = labelValue
|
||||
|
||||
_, err = sr.mcocli.MachineconfigurationV1().MachineConfigPools().Update(mcp)
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Step 2. Create KubeletConfig CRD with appropriate limits.
|
||||
un, err := sr.kubeletConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return sr.dh.Ensure(un)
|
||||
}
|
||||
|
||||
func (sr *systemreserved) Remove() error {
|
||||
err := retry.RetryOnConflict(retry.DefaultRetry, func() error {
|
||||
mcp, err := sr.mcocli.MachineconfigurationV1().MachineConfigPools().Get(workerMachineConfigPoolName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, ok := mcp.Labels[labelName]; !ok {
|
||||
// don't update if we don't need to.
|
||||
return nil
|
||||
}
|
||||
delete(mcp.Labels, labelName)
|
||||
|
||||
_, err = sr.mcocli.MachineconfigurationV1().MachineConfigPools().Update(mcp)
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return sr.dh.Delete("KubeletConfig.machineconfiguration.openshift.io/v1", "", kubeletConfigName)
|
||||
}
|
|
@ -0,0 +1,164 @@
|
|||
package workaround
|
||||
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the Apache License 2.0.
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
machinev1beta1 "github.com/openshift/cluster-api/pkg/apis/machine/v1beta1"
|
||||
mcv1 "github.com/openshift/machine-config-operator/pkg/apis/machineconfiguration.openshift.io/v1"
|
||||
fakemcoclient "github.com/openshift/machine-config-operator/pkg/generated/clientset/versioned/fake"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
ktesting "k8s.io/client-go/testing"
|
||||
|
||||
"github.com/Azure/ARO-RP/pkg/util/cmp"
|
||||
utillog "github.com/Azure/ARO-RP/pkg/util/log"
|
||||
mock_dynamichelper "github.com/Azure/ARO-RP/pkg/util/mocks/dynamichelper"
|
||||
_ "github.com/Azure/ARO-RP/pkg/util/scheme"
|
||||
)
|
||||
|
||||
func machineset(vmSize string) *machinev1beta1.MachineSet {
|
||||
return &machinev1beta1.MachineSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "fake-worker-profile-1",
|
||||
Namespace: "openshift-machine-api",
|
||||
},
|
||||
Spec: machinev1beta1.MachineSetSpec{
|
||||
Template: machinev1beta1.MachineTemplateSpec{
|
||||
Spec: machinev1beta1.MachineSpec{
|
||||
ProviderSpec: machinev1beta1.ProviderSpec{
|
||||
Value: &runtime.RawExtension{
|
||||
Raw: []byte(fmt.Sprintf(`{
|
||||
"apiVersion": "azureproviderconfig.openshift.io/v1beta1",
|
||||
"kind": "AzureMachineProviderSpec",
|
||||
"osDisk": {
|
||||
"diskSizeGB": 512
|
||||
},
|
||||
"vmSize": "%s"
|
||||
}`, vmSize)),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestSystemreservedEnsure(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
mcocli *fakemcoclient.Clientset
|
||||
mocker func(mdh *mock_dynamichelper.MockDynamicHelper)
|
||||
machineConfigPoolNeedsUpdate bool
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "first time create",
|
||||
mcocli: fakemcoclient.NewSimpleClientset(&mcv1.MachineConfigPool{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "worker",
|
||||
},
|
||||
}),
|
||||
machineConfigPoolNeedsUpdate: true,
|
||||
mocker: func(mdh *mock_dynamichelper.MockDynamicHelper) {
|
||||
mdh.EXPECT().Ensure(gomock.Any()).Return(nil)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "nothing to be done",
|
||||
mcocli: fakemcoclient.NewSimpleClientset(&mcv1.MachineConfigPool{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "worker",
|
||||
Labels: map[string]string{labelName: labelValue},
|
||||
},
|
||||
}),
|
||||
mocker: func(mdh *mock_dynamichelper.MockDynamicHelper) {
|
||||
mdh.EXPECT().Ensure(gomock.Any()).Return(nil)
|
||||
},
|
||||
},
|
||||
}
|
||||
err := mcv1.AddToScheme(scheme.Scheme)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
controller := gomock.NewController(t)
|
||||
defer controller.Finish()
|
||||
|
||||
mdh := mock_dynamichelper.NewMockDynamicHelper(controller)
|
||||
sr := &systemreserved{
|
||||
mcocli: tt.mcocli,
|
||||
dh: mdh,
|
||||
log: utillog.GetLogger(),
|
||||
}
|
||||
|
||||
var updated bool
|
||||
tt.mcocli.PrependReactor("update", "machineconfigpools", func(action ktesting.Action) (handled bool, ret runtime.Object, err error) {
|
||||
updated = true
|
||||
return false, nil, nil
|
||||
})
|
||||
|
||||
tt.mocker(mdh)
|
||||
if err := sr.Ensure(); (err != nil) != tt.wantErr {
|
||||
t.Errorf("systemreserved.Ensure() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
if tt.machineConfigPoolNeedsUpdate != updated {
|
||||
t.Errorf("systemreserved.Ensure() updated %v, machineConfigPoolNeedsUpdate = %v", updated, tt.machineConfigPoolNeedsUpdate)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSystemreservedKubeletConfig(t *testing.T) {
|
||||
err := mcv1.AddToScheme(scheme.Scheme)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
sr := &systemreserved{}
|
||||
got, err := sr.kubeletConfig()
|
||||
if err != nil {
|
||||
t.Errorf("systemreserved.kubeletConfig() error = %v", err)
|
||||
return
|
||||
}
|
||||
want := &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"apiVersion": "machineconfiguration.openshift.io/v1",
|
||||
"kind": "KubeletConfig",
|
||||
"metadata": map[string]interface{}{
|
||||
"creationTimestamp": nil,
|
||||
"labels": map[string]interface{}{
|
||||
"aro.openshift.io/limits": "",
|
||||
},
|
||||
"name": kubeletConfigName,
|
||||
},
|
||||
"spec": map[string]interface{}{
|
||||
"kubeletConfig": map[string]interface{}{
|
||||
"systemReserved": map[string]interface{}{
|
||||
"memory": "2000Mi",
|
||||
},
|
||||
},
|
||||
"machineConfigPoolSelector": map[string]interface{}{
|
||||
"matchLabels": map[string]interface{}{
|
||||
"aro.openshift.io/limits": "",
|
||||
},
|
||||
},
|
||||
},
|
||||
"status": map[string]interface{}{
|
||||
"conditions": nil,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Errorf("systemreserved.kubeletConfig() = %v, want %v", got, want)
|
||||
t.Error(cmp.Diff(got, want))
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package workaround
|
||||
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the Apache License 2.0.
|
||||
|
||||
import (
|
||||
"github.com/Azure/ARO-RP/pkg/util/version"
|
||||
)
|
||||
|
||||
// Workaround is the interface for each Workaround
|
||||
type Workaround interface {
|
||||
Name() string
|
||||
// IsRequired returns true when the clusterversion is indicates that the cluster
|
||||
// is effected by the bug that the workaround fixes.
|
||||
IsRequired(clusterVersion *version.Version) bool
|
||||
// Ensure will apply the workaround to the cluster.
|
||||
Ensure() error
|
||||
// Remove will remove the workaround from the cluster
|
||||
// (in the case when IsRequired returns false).
|
||||
Remove() error
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
package workaround
|
||||
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the Apache License 2.0.
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
configv1 "github.com/openshift/api/config/v1"
|
||||
configclient "github.com/openshift/client-go/config/clientset/versioned"
|
||||
mcoclient "github.com/openshift/machine-config-operator/pkg/generated/clientset/versioned"
|
||||
"github.com/sirupsen/logrus"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
|
||||
arov1alpha1 "github.com/Azure/ARO-RP/pkg/operator/apis/aro.openshift.io/v1alpha1"
|
||||
aroclient "github.com/Azure/ARO-RP/pkg/operator/clientset/versioned/typed/aro.openshift.io/v1alpha1"
|
||||
"github.com/Azure/ARO-RP/pkg/operator/controllers"
|
||||
"github.com/Azure/ARO-RP/pkg/util/dynamichelper"
|
||||
"github.com/Azure/ARO-RP/pkg/util/version"
|
||||
)
|
||||
|
||||
// WorkaroundReconciler the point of the workaround controller is to apply
|
||||
// workarounds that we have unitl upstream fixes are available.
|
||||
type WorkaroundReconciler struct {
|
||||
kubernetescli kubernetes.Interface
|
||||
configcli configclient.Interface
|
||||
arocli aroclient.AroV1alpha1Interface
|
||||
restConfig *rest.Config
|
||||
workarounds []Workaround
|
||||
log *logrus.Entry
|
||||
}
|
||||
|
||||
func NewReconciler(log *logrus.Entry, kubernetescli kubernetes.Interface, configcli configclient.Interface, mcocli mcoclient.Interface, arocli aroclient.AroV1alpha1Interface, restConfig *rest.Config) *WorkaroundReconciler {
|
||||
dh, err := dynamichelper.New(log, restConfig)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return &WorkaroundReconciler{
|
||||
kubernetescli: kubernetescli,
|
||||
configcli: configcli,
|
||||
arocli: arocli,
|
||||
restConfig: restConfig,
|
||||
workarounds: []Workaround{NewSystemReserved(log, mcocli, dh)},
|
||||
log: log,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *WorkaroundReconciler) actualClusterVersion() (*version.Version, error) {
|
||||
cv, err := r.configcli.ConfigV1().ClusterVersions().Get("version", metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, history := range cv.Status.History {
|
||||
if history.State == configv1.CompletedUpdate {
|
||||
return version.ParseVersion(history.Version)
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("unknown cluster version")
|
||||
}
|
||||
|
||||
// Reconcile makes sure that the workarounds are applied or removed as per the OpenShift version.
|
||||
func (r *WorkaroundReconciler) Reconcile(request ctrl.Request) (ctrl.Result, error) {
|
||||
clusterVersion, err := r.actualClusterVersion()
|
||||
if err != nil {
|
||||
r.log.Errorf("error getting the OpenShift version: %v", err)
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
|
||||
for _, wa := range r.workarounds {
|
||||
if wa.IsRequired(clusterVersion) {
|
||||
err = wa.Ensure()
|
||||
} else {
|
||||
err = wa.Remove()
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
r.log.Errorf("workaround %s returned error %v", wa.Name(), err)
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
}
|
||||
return reconcile.Result{RequeueAfter: time.Hour, Requeue: true}, nil
|
||||
}
|
||||
|
||||
// SetupWithManager setup our mananger
|
||||
func (r *WorkaroundReconciler) SetupWithManager(mgr ctrl.Manager) error {
|
||||
return ctrl.NewControllerManagedBy(mgr).
|
||||
For(&arov1alpha1.Cluster{}).
|
||||
Named(controllers.WorkaroundControllerName).
|
||||
Complete(r)
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
package workaround
|
||||
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the Apache License 2.0.
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
configv1 "github.com/openshift/api/config/v1"
|
||||
fakeconfigclient "github.com/openshift/client-go/config/clientset/versioned/fake"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
|
||||
utillog "github.com/Azure/ARO-RP/pkg/util/log"
|
||||
mock_workaround "github.com/Azure/ARO-RP/pkg/util/mocks/operator/controllers/workaround"
|
||||
)
|
||||
|
||||
func clusterVersion(ver string) *configv1.ClusterVersion {
|
||||
return &configv1.ClusterVersion{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "version",
|
||||
},
|
||||
Status: configv1.ClusterVersionStatus{
|
||||
Desired: configv1.Update{
|
||||
Version: ver,
|
||||
},
|
||||
History: []configv1.UpdateHistory{
|
||||
{
|
||||
State: configv1.CompletedUpdate,
|
||||
Version: ver,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestWorkaroundReconciler(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
want ctrl.Result
|
||||
mocker func(mw *mock_workaround.MockWorkaround)
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "is required",
|
||||
mocker: func(mw *mock_workaround.MockWorkaround) {
|
||||
c := mw.EXPECT().IsRequired(gomock.Any()).Return(true)
|
||||
mw.EXPECT().Ensure().After(c).Return(nil)
|
||||
},
|
||||
want: ctrl.Result{Requeue: true, RequeueAfter: time.Hour},
|
||||
},
|
||||
{
|
||||
name: "is not required",
|
||||
mocker: func(mw *mock_workaround.MockWorkaround) {
|
||||
c := mw.EXPECT().IsRequired(gomock.Any()).Return(false)
|
||||
mw.EXPECT().Remove().After(c).Return(nil)
|
||||
},
|
||||
want: ctrl.Result{Requeue: true, RequeueAfter: time.Hour},
|
||||
},
|
||||
{
|
||||
name: "has error",
|
||||
mocker: func(mw *mock_workaround.MockWorkaround) {
|
||||
mw.EXPECT().IsRequired(gomock.Any()).Return(true)
|
||||
mw.EXPECT().Name().Return("test").AnyTimes()
|
||||
mw.EXPECT().Ensure().Return(fmt.Errorf("oops"))
|
||||
},
|
||||
want: ctrl.Result{},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
controller := gomock.NewController(t)
|
||||
defer controller.Finish()
|
||||
|
||||
mwa := mock_workaround.NewMockWorkaround(controller)
|
||||
r := &WorkaroundReconciler{
|
||||
configcli: fakeconfigclient.NewSimpleClientset(clusterVersion("4.4.10")),
|
||||
workarounds: []Workaround{mwa},
|
||||
log: utillog.GetLogger(),
|
||||
}
|
||||
tt.mocker(mwa)
|
||||
got, err := r.Reconcile(reconcile.Request{})
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("WorkaroundReconciler.Reconcile() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("WorkaroundReconciler.Reconcile() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package dynamichelper
|
||||
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the Apache License 2.0.
|
||||
|
||||
//go:generate go run ../../../vendor/github.com/golang/mock/mockgen -destination=../mocks/$GOPACKAGE/$GOPACKAGE.go github.com/Azure/ARO-RP/pkg/util/$GOPACKAGE DynamicHelper
|
||||
//go:generate go run ../../../vendor/golang.org/x/tools/cmd/goimports -local=github.com/Azure/ARO-RP -e -w ../mocks/$GOPACKAGE/$GOPACKAGE.go
|
|
@ -0,0 +1,92 @@
|
|||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: github.com/Azure/ARO-RP/pkg/operator/controllers/workaround (interfaces: Workaround)
|
||||
|
||||
// Package mock_workaround is a generated GoMock package.
|
||||
package mock_workaround
|
||||
|
||||
import (
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
|
||||
version "github.com/Azure/ARO-RP/pkg/util/version"
|
||||
)
|
||||
|
||||
// MockWorkaround is a mock of Workaround interface
|
||||
type MockWorkaround struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockWorkaroundMockRecorder
|
||||
}
|
||||
|
||||
// MockWorkaroundMockRecorder is the mock recorder for MockWorkaround
|
||||
type MockWorkaroundMockRecorder struct {
|
||||
mock *MockWorkaround
|
||||
}
|
||||
|
||||
// NewMockWorkaround creates a new mock instance
|
||||
func NewMockWorkaround(ctrl *gomock.Controller) *MockWorkaround {
|
||||
mock := &MockWorkaround{ctrl: ctrl}
|
||||
mock.recorder = &MockWorkaroundMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use
|
||||
func (m *MockWorkaround) EXPECT() *MockWorkaroundMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// Ensure mocks base method
|
||||
func (m *MockWorkaround) Ensure() error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Ensure")
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Ensure indicates an expected call of Ensure
|
||||
func (mr *MockWorkaroundMockRecorder) Ensure() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Ensure", reflect.TypeOf((*MockWorkaround)(nil).Ensure))
|
||||
}
|
||||
|
||||
// IsRequired mocks base method
|
||||
func (m *MockWorkaround) IsRequired(arg0 *version.Version) bool {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "IsRequired", arg0)
|
||||
ret0, _ := ret[0].(bool)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// IsRequired indicates an expected call of IsRequired
|
||||
func (mr *MockWorkaroundMockRecorder) IsRequired(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsRequired", reflect.TypeOf((*MockWorkaround)(nil).IsRequired), arg0)
|
||||
}
|
||||
|
||||
// Name mocks base method
|
||||
func (m *MockWorkaround) Name() string {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Name")
|
||||
ret0, _ := ret[0].(string)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Name indicates an expected call of Name
|
||||
func (mr *MockWorkaroundMockRecorder) Name() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Name", reflect.TypeOf((*MockWorkaround)(nil).Name))
|
||||
}
|
||||
|
||||
// Remove mocks base method
|
||||
func (m *MockWorkaround) Remove() error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Remove")
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Remove indicates an expected call of Remove
|
||||
func (mr *MockWorkaroundMockRecorder) Remove() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Remove", reflect.TypeOf((*MockWorkaround)(nil).Remove))
|
||||
}
|
|
@ -0,0 +1,121 @@
|
|||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: github.com/Azure/ARO-RP/pkg/util/dynamichelper (interfaces: DynamicHelper)
|
||||
|
||||
// Package mock_dynamichelper is a generated GoMock package.
|
||||
package mock_dynamichelper
|
||||
|
||||
import (
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
unstructured "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
)
|
||||
|
||||
// MockDynamicHelper is a mock of DynamicHelper interface
|
||||
type MockDynamicHelper struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockDynamicHelperMockRecorder
|
||||
}
|
||||
|
||||
// MockDynamicHelperMockRecorder is the mock recorder for MockDynamicHelper
|
||||
type MockDynamicHelperMockRecorder struct {
|
||||
mock *MockDynamicHelper
|
||||
}
|
||||
|
||||
// NewMockDynamicHelper creates a new mock instance
|
||||
func NewMockDynamicHelper(ctrl *gomock.Controller) *MockDynamicHelper {
|
||||
mock := &MockDynamicHelper{ctrl: ctrl}
|
||||
mock.recorder = &MockDynamicHelperMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use
|
||||
func (m *MockDynamicHelper) EXPECT() *MockDynamicHelperMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// CreateOrUpdate mocks base method
|
||||
func (m *MockDynamicHelper) CreateOrUpdate(arg0 *unstructured.Unstructured) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "CreateOrUpdate", arg0)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// CreateOrUpdate indicates an expected call of CreateOrUpdate
|
||||
func (mr *MockDynamicHelperMockRecorder) CreateOrUpdate(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateOrUpdate", reflect.TypeOf((*MockDynamicHelper)(nil).CreateOrUpdate), arg0)
|
||||
}
|
||||
|
||||
// Delete mocks base method
|
||||
func (m *MockDynamicHelper) Delete(arg0, arg1, arg2 string) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Delete", arg0, arg1, arg2)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Delete indicates an expected call of Delete
|
||||
func (mr *MockDynamicHelperMockRecorder) Delete(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockDynamicHelper)(nil).Delete), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// Ensure mocks base method
|
||||
func (m *MockDynamicHelper) Ensure(arg0 *unstructured.Unstructured) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Ensure", arg0)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Ensure indicates an expected call of Ensure
|
||||
func (mr *MockDynamicHelperMockRecorder) Ensure(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Ensure", reflect.TypeOf((*MockDynamicHelper)(nil).Ensure), arg0)
|
||||
}
|
||||
|
||||
// Get mocks base method
|
||||
func (m *MockDynamicHelper) Get(arg0, arg1, arg2 string) (*unstructured.Unstructured, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Get", arg0, arg1, arg2)
|
||||
ret0, _ := ret[0].(*unstructured.Unstructured)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// Get indicates an expected call of Get
|
||||
func (mr *MockDynamicHelperMockRecorder) Get(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockDynamicHelper)(nil).Get), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// List mocks base method
|
||||
func (m *MockDynamicHelper) List(arg0, arg1 string) (*unstructured.UnstructuredList, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "List", arg0, arg1)
|
||||
ret0, _ := ret[0].(*unstructured.UnstructuredList)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// List indicates an expected call of List
|
||||
func (mr *MockDynamicHelperMockRecorder) List(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "List", reflect.TypeOf((*MockDynamicHelper)(nil).List), arg0, arg1)
|
||||
}
|
||||
|
||||
// RefreshAPIResources mocks base method
|
||||
func (m *MockDynamicHelper) RefreshAPIResources() error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "RefreshAPIResources")
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// RefreshAPIResources indicates an expected call of RefreshAPIResources
|
||||
func (mr *MockDynamicHelperMockRecorder) RefreshAPIResources() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RefreshAPIResources", reflect.TypeOf((*MockDynamicHelper)(nil).RefreshAPIResources))
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: github.com/Azure/ARO-RP/pkg/operator/controllers/workaround (interfaces: Workaround)
|
||||
|
||||
// Package mock_workaround is a generated GoMock package.
|
||||
package mock_workaround
|
||||
|
||||
import (
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
|
||||
version "github.com/Azure/ARO-RP/pkg/util/version"
|
||||
)
|
||||
|
||||
// MockWorkaround is a mock of Workaround interface
|
||||
type MockWorkaround struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockWorkaroundMockRecorder
|
||||
}
|
||||
|
||||
// MockWorkaroundMockRecorder is the mock recorder for MockWorkaround
|
||||
type MockWorkaroundMockRecorder struct {
|
||||
mock *MockWorkaround
|
||||
}
|
||||
|
||||
// NewMockWorkaround creates a new mock instance
|
||||
func NewMockWorkaround(ctrl *gomock.Controller) *MockWorkaround {
|
||||
mock := &MockWorkaround{ctrl: ctrl}
|
||||
mock.recorder = &MockWorkaroundMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use
|
||||
func (m *MockWorkaround) EXPECT() *MockWorkaroundMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// Ensure mocks base method
|
||||
func (m *MockWorkaround) Ensure() error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Ensure")
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Ensure indicates an expected call of Ensure
|
||||
func (mr *MockWorkaroundMockRecorder) Ensure() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Ensure", reflect.TypeOf((*MockWorkaround)(nil).Ensure))
|
||||
}
|
||||
|
||||
// IsRequired mocks base method
|
||||
func (m *MockWorkaround) IsRequired(arg0 *version.Version) bool {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "IsRequired", arg0)
|
||||
ret0, _ := ret[0].(bool)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// IsRequired indicates an expected call of IsRequired
|
||||
func (mr *MockWorkaroundMockRecorder) IsRequired(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsRequired", reflect.TypeOf((*MockWorkaround)(nil).IsRequired), arg0)
|
||||
}
|
||||
|
||||
// Name mocks base method
|
||||
func (m *MockWorkaround) Name() string {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Name")
|
||||
ret0, _ := ret[0].(string)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Name indicates an expected call of Name
|
||||
func (mr *MockWorkaroundMockRecorder) Name() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Name", reflect.TypeOf((*MockWorkaround)(nil).Name))
|
||||
}
|
||||
|
||||
// Remove mocks base method
|
||||
func (m *MockWorkaround) Remove() error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Remove")
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Remove indicates an expected call of Remove
|
||||
func (mr *MockWorkaroundMockRecorder) Remove() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Remove", reflect.TypeOf((*MockWorkaround)(nil).Remove))
|
||||
}
|
|
@ -6,6 +6,7 @@ package scheme
|
|||
import (
|
||||
securityv1 "github.com/openshift/api/security/v1"
|
||||
azureproviderv1beta1 "github.com/openshift/cluster-api-provider-azure/pkg/apis/azureprovider/v1beta1"
|
||||
mcv1 "github.com/openshift/machine-config-operator/pkg/apis/machineconfiguration.openshift.io/v1"
|
||||
apiextensions "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
|
||||
"k8s.io/apimachinery/pkg/util/runtime"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
|
@ -18,4 +19,5 @@ func init() {
|
|||
runtime.Must(securityv1.AddToScheme(scheme.Scheme))
|
||||
runtime.Must(arov1alpha1.AddToScheme(scheme.Scheme))
|
||||
runtime.Must(azureproviderv1beta1.SchemeBuilder.AddToScheme(scheme.Scheme))
|
||||
runtime.Must(mcv1.AddToScheme(scheme.Scheme))
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче