From 13d8d762e12b09bebbcaf7a44a1c543190c953ec Mon Sep 17 00:00:00 2001 From: Philipp Pixel Date: Wed, 25 Oct 2023 14:48:24 +0200 Subject: [PATCH 01/32] #36 add option to allow insecure TLS traffic to Helm registry --- pkg/config/config.go | 3 ++- pkg/helm/client.go | 3 ++- pkg/helm/client/client.go | 8 ++++++++ pkg/helm/client/types.go | 4 +++- 4 files changed, 15 insertions(+), 3 deletions(-) diff --git a/pkg/config/config.go b/pkg/config/config.go index 7929a89..38b9dd4 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -60,7 +60,8 @@ type HelmRepositoryData struct { // Schema describes the way how clients communicate with the Helm registry endpoint. Schema EndpointSchema `json:"schema" yaml:"schema"` // PlainHttp indicates that the repository endpoint should be accessed using plain http - PlainHttp bool `json:"plainHttp,omitempty" yaml:"plainHttp,omitempty"` + PlainHttp bool `json:"plainHttp,omitempty" yaml:"plainHttp,omitempty"` + InsecureTLS bool `json:"insecureTls" yaml:"insecureTls"` } // URL returns the full URL Helm repository endpoint including schema. diff --git a/pkg/helm/client.go b/pkg/helm/client.go index 9e8f572..2c9078e 100644 --- a/pkg/helm/client.go +++ b/pkg/helm/client.go @@ -119,7 +119,8 @@ func (c *Client) getChart(ctx context.Context, chartSpec *client.ChartSpec) (*ch logger.Info("Trying to get chart with options", "chart", chartSpec.ChartName, "version", chartSpec.Version, - "plain http", c.helmRepoData.PlainHttp) + "plain HTTP", c.helmRepoData.PlainHttp, + "insecure TLS", c.helmRepoData.InsecureTLS) componentChart, _, err := c.helmClient.GetChart(chartSpec) if err != nil { diff --git a/pkg/helm/client/client.go b/pkg/helm/client/client.go index d93caff..b10ed9a 100644 --- a/pkg/helm/client/client.go +++ b/pkg/helm/client/client.go @@ -2,8 +2,10 @@ package client import ( "context" + "crypto/tls" "fmt" "log" + "net/http" "os" "github.com/spf13/pflag" @@ -76,6 +78,12 @@ func newClient(options *Options, clientGetter genericclioptions.RESTClientGetter clientOpts = append(clientOpts, registry.ClientOptPlainHTTP()) } + if !options.PlainHttp && options.InsecureTls { + insecureHttpsClient := &http.Client{Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}} + httpClientOpt := registry.ClientOptHTTPClient(insecureHttpsClient) + clientOpts = append(clientOpts, httpClientOpt) + } + registryClient, err := registry.NewClient(clientOpts...) if err != nil { return nil, err diff --git a/pkg/helm/client/types.go b/pkg/helm/client/types.go index 29e3776..daa9200 100644 --- a/pkg/helm/client/types.go +++ b/pkg/helm/client/types.go @@ -37,8 +37,10 @@ type Options struct { DebugLog action.DebugLog RegistryConfig string Output io.Writer - // PlainHttp forces the registry client to establish plain http connections. + // PlainHttp forces the registry client to establish plain http connections. This option will override by InsecureTls by using HTTP traffic. PlainHttp bool + // InsecureTls allows invalid or selfsigned certificates to be used. This option may be overridden by PlainHttp which forces HTTP traffic. + InsecureTls bool } // RESTClientOption is a function that can be used to set the RESTClientOptions of a HelmClient. From 6a2f0d6f234438d966960266cfea0f3aa065c4d2 Mon Sep 17 00:00:00 2001 From: Philipp Pixel Date: Wed, 25 Oct 2023 14:49:34 +0200 Subject: [PATCH 02/32] #35 WIP: fix missing component upgrade for different deployNamespace --- .../bases/k8s.cloudogu.com_components.yaml | 4 +- config/manager/kustomization.yaml | 14 +++---- config/samples/k8s-longhorn.yaml | 9 +++++ pkg/api/v1/k8s.cloudogu.com_components.yaml | 4 +- pkg/controllers/componentController.go | 39 ++++++++++++++++--- pkg/controllers/componentController_test.go | 12 +++--- 6 files changed, 61 insertions(+), 21 deletions(-) create mode 100644 config/samples/k8s-longhorn.yaml diff --git a/config/crd/bases/k8s.cloudogu.com_components.yaml b/config/crd/bases/k8s.cloudogu.com_components.yaml index ffa20d5..1dd9888 100644 --- a/config/crd/bases/k8s.cloudogu.com_components.yaml +++ b/config/crd/bases/k8s.cloudogu.com_components.yaml @@ -40,7 +40,9 @@ spec: properties: deployNamespace: description: DeployNamespace is the namespace where the helm chart - should be deployed in. + should be deployed in. This value is optional. If it is empty the + operator deploys the helm chart in the namespace where the operator + is deployed. type: string name: description: Name of the component (e.g. k8s-dogu-operator) diff --git a/config/manager/kustomization.yaml b/config/manager/kustomization.yaml index 255600f..b03d9cb 100644 --- a/config/manager/kustomization.yaml +++ b/config/manager/kustomization.yaml @@ -1,14 +1,14 @@ resources: - - manager.yaml +- manager.yaml generatorOptions: disableNameSuffixHash: true configMapGenerator: - - files: - - controller_manager_config.yaml - name: manager-config +- files: + - controller_manager_config.yaml + name: manager-config apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization images: - - name: controller - newName: cloudogu/k8s-component-operator - newTag: 0.5.1 +- name: controller + newName: cloudogu/k8s-component-operator + newTag: 0.5.1 diff --git a/config/samples/k8s-longhorn.yaml b/config/samples/k8s-longhorn.yaml new file mode 100644 index 0000000..d014fb6 --- /dev/null +++ b/config/samples/k8s-longhorn.yaml @@ -0,0 +1,9 @@ +apiVersion: k8s.cloudogu.com/v1 +kind: Component +metadata: + name: k8s-longhorn +spec: + name: k8s-longhorn + deployNamespace: longhorn-system + namespace: k8s + version: 1.5.1-1 \ No newline at end of file diff --git a/pkg/api/v1/k8s.cloudogu.com_components.yaml b/pkg/api/v1/k8s.cloudogu.com_components.yaml index ffa20d5..1dd9888 100644 --- a/pkg/api/v1/k8s.cloudogu.com_components.yaml +++ b/pkg/api/v1/k8s.cloudogu.com_components.yaml @@ -40,7 +40,9 @@ spec: properties: deployNamespace: description: DeployNamespace is the namespace where the helm chart - should be deployed in. + should be deployed in. This value is optional. If it is empty the + operator deploys the helm chart in the namespace where the operator + is deployed. type: string name: description: Name of the component (e.g. k8s-dogu-operator) diff --git a/pkg/controllers/componentController.go b/pkg/controllers/componentController.go index 66c4d76..0b5dda3 100644 --- a/pkg/controllers/componentController.go +++ b/pkg/controllers/componentController.go @@ -211,11 +211,13 @@ func (r *componentReconciler) evaluateRequiredOperation(ctx context.Context, com return Delete, nil } + logger.Info("===== current state", component.Status.Status) + switch component.Status.Status { case k8sv1.ComponentStatusNotInstalled: return Install, nil case k8sv1.ComponentStatusInstalled: - operation, err := r.getChangeOperation(component) + operation, err := r.getChangeOperation(ctx, component) if err != nil { return "", err } @@ -233,42 +235,67 @@ func (r *componentReconciler) evaluateRequiredOperation(ctx context.Context, com } } -func (r *componentReconciler) getChangeOperation(component *k8sv1.Component) (operation, error) { +func (r *componentReconciler) getChangeOperation(ctx context.Context, component *k8sv1.Component) (operation, error) { + logger := log.FromContext(ctx) + deployedReleases, err := r.helmClient.ListDeployedReleases() if err != nil { return "", fmt.Errorf("failed to get deployed helm releases: %w", err) } + logger.Info("==== getChangeOperation 1") + for _, deployedRelease := range deployedReleases { - // This will allow a namespace switch e. g. k8s/dogu-operator -> k8s-testing/dogu-operator. - if deployedRelease.Name == component.Spec.Name && deployedRelease.Namespace == component.Namespace { - return getChangeOperationForRelease(component, deployedRelease) + logger.Info("==== getChangeOperation for", deployedRelease) + + isComponentToBeChanged := deployedRelease.Name == component.Spec.Name + compareNamespace := component.Spec.DeployNamespace + + if compareNamespace == "" { + compareNamespace = component.Namespace + } + + logger.Info("==== getChangeOperation compare existing release with target namespace", compareNamespace, deployedRelease.Namespace) + existsReleaseInCompareNamespace := deployedRelease.Namespace == compareNamespace + + if isComponentToBeChanged && existsReleaseInCompareNamespace { + logger.Info("==== getChangeOperation component hit", compareNamespace) + return getChangeOperationForRelease(ctx, component, deployedRelease) } } + logger.Info("==== getChangeOperation exit") + return Ignore, nil } -func getChangeOperationForRelease(component *k8sv1.Component, release *release.Release) (operation, error) { +func getChangeOperationForRelease(ctx context.Context, component *k8sv1.Component, release *release.Release) (operation, error) { + logger := log.FromContext(ctx) chart := release.Chart deployedAppVersion, err := semver.NewVersion(chart.AppVersion()) if err != nil { return "", fmt.Errorf("failed to parse app version %s from helm chart %s: %w", chart.AppVersion(), chart.Name(), err) } + logger.Info("Found deployed app version", "appversion", deployedAppVersion) + componentVersion, err := semver.NewVersion(component.Spec.Version) if err != nil { return "", fmt.Errorf("failed to parse component version %s from %s: %w", component.Spec.Version, component.Spec.Name, err) } if deployedAppVersion.LessThan(componentVersion) { + logger.Info("Yay deployed is greater than component: up", "appversion", deployedAppVersion, "componentversion", componentVersion) return Upgrade, nil } if deployedAppVersion.GreaterThan(componentVersion) { + logger.Info("oops deployed is less than component: down", "appversion", deployedAppVersion, "componentversion", componentVersion) return Downgrade, nil } + logger.Info("oh noez deployed is ??? than component: ignore", "appversion", deployedAppVersion, "componentversion", componentVersion) + return Ignore, nil } diff --git a/pkg/controllers/componentController_test.go b/pkg/controllers/componentController_test.go index 12785a3..073623a 100644 --- a/pkg/controllers/componentController_test.go +++ b/pkg/controllers/componentController_test.go @@ -362,7 +362,7 @@ func Test_componentReconciler_getChangeOperation(t *testing.T) { } // when - _, err := sut.getChangeOperation(component) + _, err := sut.getChangeOperation(testCtx, component) // then require.Error(t, err) @@ -382,7 +382,7 @@ func Test_componentReconciler_getChangeOperation(t *testing.T) { } // when - _, err := sut.getChangeOperation(component) + _, err := sut.getChangeOperation(testCtx, component) // then require.Error(t, err) @@ -401,7 +401,7 @@ func Test_componentReconciler_getChangeOperation(t *testing.T) { } // when - op, err := sut.getChangeOperation(component) + op, err := sut.getChangeOperation(testCtx, component) // then require.NoError(t, err) @@ -420,7 +420,7 @@ func Test_componentReconciler_getChangeOperation(t *testing.T) { } // when - op, err := sut.getChangeOperation(component) + op, err := sut.getChangeOperation(testCtx, component) // then require.NoError(t, err) @@ -439,7 +439,7 @@ func Test_componentReconciler_getChangeOperation(t *testing.T) { } // when - op, err := sut.getChangeOperation(component) + op, err := sut.getChangeOperation(testCtx, component) // then require.NoError(t, err) @@ -458,7 +458,7 @@ func Test_componentReconciler_getChangeOperation(t *testing.T) { } // when - op, err := sut.getChangeOperation(component) + op, err := sut.getChangeOperation(testCtx, component) // then require.NoError(t, err) From a2266e408b992443b0a27db9e72f236bb1238d0f Mon Sep 17 00:00:00 2001 From: Philipp Pixel Date: Wed, 25 Oct 2023 15:04:30 +0200 Subject: [PATCH 03/32] Boyscouting: set default log level to INFO --- pkg/logging/logger.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/pkg/logging/logger.go b/pkg/logging/logger.go index 9781d74..11e2b34 100644 --- a/pkg/logging/logger.go +++ b/pkg/logging/logger.go @@ -25,7 +25,10 @@ const ( // CurrentLogLevel is the currently configured logLevel // The default logLevel is "ERROR" -var CurrentLogLevel = logrus.ErrorLevel +var ( + defaultLogLevel = logrus.InfoLevel + CurrentLogLevel = defaultLogLevel +) type libraryLogger struct { logger logr.LogSink @@ -83,12 +86,12 @@ func (ll *libraryLogger) Errorf(format string, args ...interface{}) { func getLogLevelFromEnv() (logrus.Level, error) { logLevel, found := os.LookupEnv(logLevelEnvVar) if !found || strings.TrimSpace(logLevel) == "" { - return logrus.ErrorLevel, nil + return defaultLogLevel, nil } level, err := logrus.ParseLevel(logLevel) if err != nil { - return logrus.ErrorLevel, fmt.Errorf("value of log environment variable [%s] is not a valid log level: %w", logLevelEnvVar, err) + return defaultLogLevel, fmt.Errorf("value of log environment variable [%s] is not a valid log level: %w", logLevelEnvVar, err) } return level, nil From 9588742863f422d7c3d5ff084ce97b83e6d8a959 Mon Sep 17 00:00:00 2001 From: meiserloh Date: Wed, 25 Oct 2023 15:24:50 +0200 Subject: [PATCH 04/32] #35 cleanup logs and test components with deploy namespace Co-authored-by: Philipp Pixel --- pkg/controllers/componentController.go | 34 +++------ pkg/controllers/componentController_test.go | 72 ++++++++++++++----- .../componentInstallManager_test.go | 12 ++-- pkg/controllers/component_manager_test.go | 15 ++-- 4 files changed, 80 insertions(+), 53 deletions(-) diff --git a/pkg/controllers/componentController.go b/pkg/controllers/componentController.go index 0b5dda3..2425696 100644 --- a/pkg/controllers/componentController.go +++ b/pkg/controllers/componentController.go @@ -211,8 +211,6 @@ func (r *componentReconciler) evaluateRequiredOperation(ctx context.Context, com return Delete, nil } - logger.Info("===== current state", component.Status.Status) - switch component.Status.Status { case k8sv1.ComponentStatusNotInstalled: return Install, nil @@ -243,59 +241,49 @@ func (r *componentReconciler) getChangeOperation(ctx context.Context, component return "", fmt.Errorf("failed to get deployed helm releases: %w", err) } - logger.Info("==== getChangeOperation 1") - for _, deployedRelease := range deployedReleases { - logger.Info("==== getChangeOperation for", deployedRelease) isComponentToBeChanged := deployedRelease.Name == component.Spec.Name - compareNamespace := component.Spec.DeployNamespace + targetNamespace := component.Spec.DeployNamespace - if compareNamespace == "" { - compareNamespace = component.Namespace + if targetNamespace == "" { + targetNamespace = component.Namespace } - logger.Info("==== getChangeOperation compare existing release with target namespace", compareNamespace, deployedRelease.Namespace) - existsReleaseInCompareNamespace := deployedRelease.Namespace == compareNamespace + existsReleaseInTargetNamespace := deployedRelease.Namespace == targetNamespace - if isComponentToBeChanged && existsReleaseInCompareNamespace { - logger.Info("==== getChangeOperation component hit", compareNamespace) - return getChangeOperationForRelease(ctx, component, deployedRelease) + if isComponentToBeChanged { + logger.Info("Found existing release for reconciled component", + "releaseNamespace", deployedRelease.Namespace, "targetNamespace", targetNamespace) + if existsReleaseInTargetNamespace { + return getChangeOperationForRelease(component, deployedRelease) + } } } - logger.Info("==== getChangeOperation exit") - return Ignore, nil } -func getChangeOperationForRelease(ctx context.Context, component *k8sv1.Component, release *release.Release) (operation, error) { - logger := log.FromContext(ctx) +func getChangeOperationForRelease(component *k8sv1.Component, release *release.Release) (operation, error) { chart := release.Chart deployedAppVersion, err := semver.NewVersion(chart.AppVersion()) if err != nil { return "", fmt.Errorf("failed to parse app version %s from helm chart %s: %w", chart.AppVersion(), chart.Name(), err) } - logger.Info("Found deployed app version", "appversion", deployedAppVersion) - componentVersion, err := semver.NewVersion(component.Spec.Version) if err != nil { return "", fmt.Errorf("failed to parse component version %s from %s: %w", component.Spec.Version, component.Spec.Name, err) } if deployedAppVersion.LessThan(componentVersion) { - logger.Info("Yay deployed is greater than component: up", "appversion", deployedAppVersion, "componentversion", componentVersion) return Upgrade, nil } if deployedAppVersion.GreaterThan(componentVersion) { - logger.Info("oops deployed is less than component: down", "appversion", deployedAppVersion, "componentversion", componentVersion) return Downgrade, nil } - logger.Info("oh noez deployed is ??? than component: ignore", "appversion", deployedAppVersion, "componentversion", componentVersion) - return Ignore, nil } diff --git a/pkg/controllers/componentController_test.go b/pkg/controllers/componentController_test.go index 073623a..95f3edb 100644 --- a/pkg/controllers/componentController_test.go +++ b/pkg/controllers/componentController_test.go @@ -45,7 +45,7 @@ func Test_componentReconciler_Reconcile(t *testing.T) { helmNamespace := "k8s" t.Run("success install", func(t *testing.T) { // given - component := getComponent(testNamespace, helmNamespace, "dogu-op", "0.1.0") + component := getComponent(testNamespace, helmNamespace, "", "dogu-op", "0.1.0") componentInterfaceMock := newMockComponentInterface(t) componentInterfaceMock.EXPECT().Get(testCtx, "dogu-op", v1.GetOptions{}).Return(component, nil) @@ -83,7 +83,7 @@ func Test_componentReconciler_Reconcile(t *testing.T) { t.Run("success delete", func(t *testing.T) { // given - component := getComponent(testNamespace, helmNamespace, "dogu-op", "0.1.0") + component := getComponent(testNamespace, helmNamespace, "", "dogu-op", "0.1.0") component.DeletionTimestamp = &v1.Time{Time: time.Now()} componentInterfaceMock := newMockComponentInterface(t) @@ -122,7 +122,7 @@ func Test_componentReconciler_Reconcile(t *testing.T) { t.Run("success upgrade", func(t *testing.T) { // given - component := getComponent(testNamespace, helmNamespace, "dogu-op", "0.1.0") + component := getComponent(testNamespace, helmNamespace, "", "dogu-op", "0.1.0") component.Status.Status = "installed" componentInterfaceMock := newMockComponentInterface(t) @@ -164,7 +164,7 @@ func Test_componentReconciler_Reconcile(t *testing.T) { t.Run("should fail on downgrade", func(t *testing.T) { // given - component := getComponent(testNamespace, helmNamespace, "dogu-op", "0.1.0") + component := getComponent(testNamespace, helmNamespace, "", "dogu-op", "0.1.0") component.Status.Status = "installed" componentInterfaceMock := newMockComponentInterface(t) @@ -200,7 +200,7 @@ func Test_componentReconciler_Reconcile(t *testing.T) { t.Run("should ignore equal installed component", func(t *testing.T) { // given - component := getComponent(testNamespace, helmNamespace, "dogu-op", "0.1.0") + component := getComponent(testNamespace, helmNamespace, "", "dogu-op", "0.1.0") component.Status.Status = "installed" componentInterfaceMock := newMockComponentInterface(t) @@ -278,7 +278,7 @@ func Test_componentReconciler_Reconcile(t *testing.T) { t.Run("should fail on getting operation with invalid versions", func(t *testing.T) { // given - component := getComponent(testNamespace, helmNamespace, "dogu-op", "0.1.0") + component := getComponent(testNamespace, helmNamespace, "", "dogu-op", "0.1.0") component.Status.Status = "installed" componentInterfaceMock := newMockComponentInterface(t) @@ -308,7 +308,7 @@ func Test_componentReconciler_Reconcile(t *testing.T) { t.Run("should fail on error in operation", func(t *testing.T) { // given - component := getComponent(testNamespace, helmNamespace, "dogu-op", "0.1.0") + component := getComponent(testNamespace, helmNamespace, "", "dogu-op", "0.1.0") component.DeletionTimestamp = &v1.Time{Time: time.Now()} componentInterfaceMock := newMockComponentInterface(t) @@ -353,7 +353,7 @@ func Test_componentReconciler_Reconcile(t *testing.T) { func Test_componentReconciler_getChangeOperation(t *testing.T) { t.Run("should fail on error getting helm releases", func(t *testing.T) { // given - component := getComponent("ecosystem", "k8s", "dogu-op", "0.1.0") + component := getComponent("ecosystem", "k8s", "", "dogu-op", "0.1.0") mockHelmClient := newMockHelmClient(t) mockHelmClient.EXPECT().ListDeployedReleases().Return(nil, assert.AnError) @@ -372,7 +372,7 @@ func Test_componentReconciler_getChangeOperation(t *testing.T) { t.Run("should fail on error parsing component version", func(t *testing.T) { // given - component := getComponent("ecosystem", "k8s", "dogu-op", "notvalidsemver") + component := getComponent("ecosystem", "k8s", "", "dogu-op", "notvalidsemver") mockHelmClient := newMockHelmClient(t) helmReleases := []*release.Release{{Name: "dogu-op", Namespace: "ecosystem", Chart: &chart.Chart{Metadata: &chart.Metadata{AppVersion: "0.0.1"}}}} mockHelmClient.EXPECT().ListDeployedReleases().Return(helmReleases, nil) @@ -391,7 +391,7 @@ func Test_componentReconciler_getChangeOperation(t *testing.T) { t.Run("should return downgrade-operation on downgrade", func(t *testing.T) { // given - component := getComponent("ecosystem", "k8s", "dogu-op", "0.0.0") + component := getComponent("ecosystem", "k8s", "", "dogu-op", "0.0.0") mockHelmClient := newMockHelmClient(t) helmReleases := []*release.Release{{Name: "dogu-op", Namespace: "ecosystem", Chart: &chart.Chart{Metadata: &chart.Metadata{AppVersion: "0.0.1"}}}} mockHelmClient.EXPECT().ListDeployedReleases().Return(helmReleases, nil) @@ -408,9 +408,47 @@ func Test_componentReconciler_getChangeOperation(t *testing.T) { assert.Equal(t, Downgrade, op) }) + t.Run("should return upgrade-operation on upgrade if deploy namespace is set", func(t *testing.T) { + // given + component := getComponent("ecosystem", "k8s", "deploy-namespace", "dogu-op", "0.0.1-2") + mockHelmClient := newMockHelmClient(t) + helmReleases := []*release.Release{{Name: "dogu-op", Namespace: "deploy-namespace", Chart: &chart.Chart{Metadata: &chart.Metadata{AppVersion: "0.0.1-1"}}}} + mockHelmClient.EXPECT().ListDeployedReleases().Return(helmReleases, nil) + + sut := componentReconciler{ + helmClient: mockHelmClient, + } + + // when + op, err := sut.getChangeOperation(testCtx, component) + + // then + require.NoError(t, err) + assert.Equal(t, Upgrade, op) + }) + + t.Run("should return ignore-operation on downgrade if deploy namespace is not equal release namespace", func(t *testing.T) { + // given + component := getComponent("ecosystem", "k8s", "deploy-namespace", "dogu-op", "0.0.1-2") + mockHelmClient := newMockHelmClient(t) + helmReleases := []*release.Release{{Name: "dogu-op", Namespace: "ecosystem", Chart: &chart.Chart{Metadata: &chart.Metadata{AppVersion: "0.0.1-1"}}}} + mockHelmClient.EXPECT().ListDeployedReleases().Return(helmReleases, nil) + + sut := componentReconciler{ + helmClient: mockHelmClient, + } + + // when + op, err := sut.getChangeOperation(testCtx, component) + + // then + require.NoError(t, err) + assert.Equal(t, Ignore, op) + }) + t.Run("should return upgrade-operation on upgrade", func(t *testing.T) { // given - component := getComponent("ecosystem", "k8s", "dogu-op", "0.0.2") + component := getComponent("ecosystem", "k8s", "", "dogu-op", "0.0.2") mockHelmClient := newMockHelmClient(t) helmReleases := []*release.Release{{Name: "dogu-op", Namespace: "ecosystem", Chart: &chart.Chart{Metadata: &chart.Metadata{AppVersion: "0.0.1"}}}} mockHelmClient.EXPECT().ListDeployedReleases().Return(helmReleases, nil) @@ -429,7 +467,7 @@ func Test_componentReconciler_getChangeOperation(t *testing.T) { t.Run("should return ignore-operation on same version", func(t *testing.T) { // given - component := getComponent("ecosystem", "k8s", "dogu-op", "0.0.1") + component := getComponent("ecosystem", "k8s", "", "dogu-op", "0.0.1") mockHelmClient := newMockHelmClient(t) helmReleases := []*release.Release{{Name: "dogu-op", Namespace: "ecosystem", Chart: &chart.Chart{Metadata: &chart.Metadata{AppVersion: "0.0.1"}}}} mockHelmClient.EXPECT().ListDeployedReleases().Return(helmReleases, nil) @@ -448,7 +486,7 @@ func Test_componentReconciler_getChangeOperation(t *testing.T) { t.Run("should return ignore-operation when no release is found", func(t *testing.T) { // given - component := getComponent("ecosystem", "k8s", "dogu-op", "0.0.1") + component := getComponent("ecosystem", "k8s", "", "dogu-op", "0.0.1") mockHelmClient := newMockHelmClient(t) var helmReleases []*release.Release mockHelmClient.EXPECT().ListDeployedReleases().Return(helmReleases, nil) @@ -469,7 +507,7 @@ func Test_componentReconciler_getChangeOperation(t *testing.T) { func Test_componentReconciler_evaluateRequiredOperation(t *testing.T) { t.Run("should return ignore on status installing", func(t *testing.T) { // given - component := getComponent("ecosystem", "k8s", "dogu-op", "0.0.0") + component := getComponent("ecosystem", "k8s", "", "dogu-op", "0.0.0") component.Status.Status = "installing" sut := componentReconciler{} @@ -483,7 +521,7 @@ func Test_componentReconciler_evaluateRequiredOperation(t *testing.T) { t.Run("should return ignore on status deleting", func(t *testing.T) { // given - component := getComponent("ecosystem", "k8s", "dogu-op", "0.0.0") + component := getComponent("ecosystem", "k8s", "", "dogu-op", "0.0.0") component.Status.Status = "deleting" sut := componentReconciler{} @@ -497,7 +535,7 @@ func Test_componentReconciler_evaluateRequiredOperation(t *testing.T) { t.Run("should return ignore on status upgrading", func(t *testing.T) { // given - component := getComponent("ecosystem", "k8s", "dogu-op", "0.0.0") + component := getComponent("ecosystem", "k8s", "", "dogu-op", "0.0.0") component.Status.Status = "upgrading" sut := componentReconciler{} @@ -511,7 +549,7 @@ func Test_componentReconciler_evaluateRequiredOperation(t *testing.T) { t.Run("should return ignore on unrecognized status", func(t *testing.T) { // given - component := getComponent("ecosystem", "k8s", "dogu-op", "0.0.0") + component := getComponent("ecosystem", "k8s", "", "dogu-op", "0.0.0") component.Status.Status = "foobar" sut := componentReconciler{} diff --git a/pkg/controllers/componentInstallManager_test.go b/pkg/controllers/componentInstallManager_test.go index ec5c4ab..256f06a 100644 --- a/pkg/controllers/componentInstallManager_test.go +++ b/pkg/controllers/componentInstallManager_test.go @@ -20,7 +20,7 @@ func TestNewComponentInstallManager(t *testing.T) { func Test_componentInstallManager_Install(t *testing.T) { namespace := "ecosystem" - component := getComponent(namespace, "k8s", "dogu-op", "0.1.0") + component := getComponent(namespace, "k8s", "", "dogu-op", "0.1.0") t.Run("should install component", func(t *testing.T) { // given @@ -166,13 +166,13 @@ func Test_componentInstallManager_Install(t *testing.T) { t.Run("should update version of component", func(t *testing.T) { // given - componentWithoutVersion := getComponent(namespace, "k8s", "dogu-op", "") + componentWithoutVersion := getComponent(namespace, "k8s", "", "dogu-op", "") mockComponentClient := newMockComponentInterface(t) mockComponentClient.EXPECT().UpdateStatusInstalling(testCtx, componentWithoutVersion).Return(componentWithoutVersion, nil) mockComponentClient.EXPECT().UpdateStatusInstalled(testCtx, componentWithoutVersion).Return(componentWithoutVersion, nil) mockComponentClient.EXPECT().AddFinalizer(testCtx, componentWithoutVersion, "component-finalizer").Return(componentWithoutVersion, nil) - componentWithVersion := getComponent(namespace, "k8s", "dogu-op", "4.8.3") + componentWithVersion := getComponent(namespace, "k8s", "", "dogu-op", "4.8.3") mockComponentClient.EXPECT().Update(testCtx, componentWithVersion, metav1.UpdateOptions{}).Return(componentWithoutVersion, nil) mockHelmClient := newMockHelmClient(t) @@ -198,7 +198,7 @@ func Test_componentInstallManager_Install(t *testing.T) { t.Run("should fail to update version of component on error while listing releases", func(t *testing.T) { // given - componentWithoutVersion := getComponent(namespace, "k8s", "dogu-op", "") + componentWithoutVersion := getComponent(namespace, "k8s", "", "dogu-op", "") mockComponentClient := newMockComponentInterface(t) mockComponentClient.EXPECT().UpdateStatusInstalling(testCtx, componentWithoutVersion).Return(componentWithoutVersion, nil) mockComponentClient.EXPECT().AddFinalizer(testCtx, componentWithoutVersion, "component-finalizer").Return(componentWithoutVersion, nil) @@ -224,12 +224,12 @@ func Test_componentInstallManager_Install(t *testing.T) { t.Run("should fail to update version of component on error while updating", func(t *testing.T) { // given - componentWithoutVersion := getComponent(namespace, "k8s", "dogu-op", "") + componentWithoutVersion := getComponent(namespace, "k8s", "", "dogu-op", "") mockComponentClient := newMockComponentInterface(t) mockComponentClient.EXPECT().UpdateStatusInstalling(testCtx, componentWithoutVersion).Return(componentWithoutVersion, nil) mockComponentClient.EXPECT().AddFinalizer(testCtx, componentWithoutVersion, "component-finalizer").Return(componentWithoutVersion, nil) - componentWithVersion := getComponent(namespace, "k8s", "dogu-op", "4.8.3") + componentWithVersion := getComponent(namespace, "k8s", "", "dogu-op", "4.8.3") mockComponentClient.EXPECT().Update(testCtx, componentWithVersion, metav1.UpdateOptions{}).Return(nil, assert.AnError) mockHelmClient := newMockHelmClient(t) diff --git a/pkg/controllers/component_manager_test.go b/pkg/controllers/component_manager_test.go index d5659f2..d287ed4 100644 --- a/pkg/controllers/component_manager_test.go +++ b/pkg/controllers/component_manager_test.go @@ -21,7 +21,7 @@ func TestNewComponentManager(t *testing.T) { func Test_componentManager_Install(t *testing.T) { t.Run("success", func(t *testing.T) { // given - component := getComponent("ecosystem", "k8s", "dogu-op", "0.1.0") + component := getComponent("ecosystem", "k8s", "", "dogu-op", "0.1.0") installManagerMock := newMockInstallManager(t) installManagerMock.EXPECT().Install(context.TODO(), component).Return(nil) eventRecorderMock := newMockEventRecorder(t) @@ -43,7 +43,7 @@ func Test_componentManager_Install(t *testing.T) { func Test_componentManager_Upgrade(t *testing.T) { t.Run("success", func(t *testing.T) { // given - component := getComponent("ecosystem", "k8s", "dogu-op", "0.1.0") + component := getComponent("ecosystem", "k8s", "", "dogu-op", "0.1.0") upgradeManagerMock := newMockUpgradeManager(t) upgradeManagerMock.EXPECT().Upgrade(context.TODO(), component).Return(nil) eventRecorderMock := newMockEventRecorder(t) @@ -64,7 +64,7 @@ func Test_componentManager_Upgrade(t *testing.T) { func Test_componentManager_Delete(t *testing.T) { t.Run("success", func(t *testing.T) { // given - component := getComponent("ecosystem", "k8s", "dogu-op", "0.1.0") + component := getComponent("ecosystem", "k8s", "", "dogu-op", "0.1.0") deleteManagerMock := newMockDeleteManager(t) deleteManagerMock.EXPECT().Delete(context.TODO(), component).Return(nil) eventRecorderMock := newMockEventRecorder(t) @@ -82,12 +82,13 @@ func Test_componentManager_Delete(t *testing.T) { }) } -func getComponent(namespace string, helmNamespace string, name string, version string) *v1.Component { +func getComponent(namespace string, helmNamespace string, deployNamespace string, name string, version string) *v1.Component { return &v1.Component{ ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: namespace}, Spec: v1.ComponentSpec{ - Namespace: helmNamespace, - Name: name, - Version: version, + Namespace: helmNamespace, + DeployNamespace: deployNamespace, + Name: name, + Version: version, }} } From 683a7f15044f2dba56fbe4bcde501793dfef5f04 Mon Sep 17 00:00:00 2001 From: Philipp Pixel Date: Wed, 25 Oct 2023 16:00:57 +0200 Subject: [PATCH 05/32] #36 add option to allow insecure TLS traffic to Helm registry --- pkg/config/config.go | 19 ++++++++++++++----- pkg/helm/client.go | 1 + pkg/helm/client/action.go | 6 +++++- pkg/helm/client/client.go | 1 + 4 files changed, 21 insertions(+), 6 deletions(-) diff --git a/pkg/config/config.go b/pkg/config/config.go index 38b9dd4..9f40166 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -41,8 +41,9 @@ var ( ) const ( - configMapSchema = "schema" - configMapPlainHttp = "plainHttp" + configMapSchema = "schema" + configMapPlainHttp = "plainHttp" + configMapInsecureTls = "insecureTls" ) type EndpointSchema string @@ -155,6 +156,13 @@ func NewHelmRepoDataFromCluster(ctx context.Context, configMapClient configMapIn return nil, fmt.Errorf("failed to parse field %s from configMap %s", configMapPlainHttp, helmRepositoryConfigMapName) } } + insecureTls := false + if insecureTlsStr, exists := configMap.Data[configMapInsecureTls]; exists { + insecureTls, err = strconv.ParseBool(insecureTlsStr) + if err != nil { + return nil, fmt.Errorf("failed to parse field %s from configMap %s", configMapInsecureTls, helmRepositoryConfigMapName) + } + } var schema string var schemaExists bool if schema, schemaExists = configMap.Data[configMapSchema]; schemaExists { @@ -164,9 +172,10 @@ func NewHelmRepoDataFromCluster(ctx context.Context, configMapClient configMapIn } repoData := &HelmRepositoryData{ - Endpoint: configMap.Data["endpoint"], - Schema: EndpointSchema(schema), - PlainHttp: plainHttp, + Endpoint: configMap.Data["endpoint"], + Schema: EndpointSchema(schema), + PlainHttp: plainHttp, + InsecureTLS: insecureTls, } err = repoData.validate() diff --git a/pkg/helm/client.go b/pkg/helm/client.go index 2c9078e..6724ede 100644 --- a/pkg/helm/client.go +++ b/pkg/helm/client.go @@ -48,6 +48,7 @@ func NewClient(namespace string, helmRepoData *config.HelmRepositoryData, debug Debug: debug, DebugLog: debugLog, PlainHttp: helmRepoData.PlainHttp, + InsecureTls: helmRepoData.InsecureTLS, }, RestConfig: ctrl.GetConfigOrDie(), } diff --git a/pkg/helm/client/action.go b/pkg/helm/client/action.go index 3d7dd20..c8874f8 100644 --- a/pkg/helm/client/action.go +++ b/pkg/helm/client/action.go @@ -11,18 +11,21 @@ import ( type provider struct { *action.Configuration - plainHttp bool + plainHttp bool + insecureTls bool } func (p *provider) newInstall() installAction { installAction := action.NewInstall(p.Configuration) installAction.PlainHTTP = p.plainHttp + installAction.InsecureSkipTLSverify = p.insecureTls return &install{Install: installAction} } func (p *provider) newUpgrade() upgradeAction { upgradeAction := action.NewUpgrade(p.Configuration) upgradeAction.PlainHTTP = p.plainHttp + upgradeAction.InsecureSkipTLSverify = p.insecureTls return &upgrade{Upgrade: upgradeAction} } @@ -34,6 +37,7 @@ func (p *provider) newUninstall() uninstallAction { func (p *provider) newLocateChart() locateChartAction { dummyAction := action.NewInstall(p.Configuration) dummyAction.PlainHTTP = p.plainHttp + dummyAction.InsecureSkipTLSverify = p.insecureTls return &locateChart{dummyAction: dummyAction} } diff --git a/pkg/helm/client/client.go b/pkg/helm/client/client.go index b10ed9a..1bc35b9 100644 --- a/pkg/helm/client/client.go +++ b/pkg/helm/client/client.go @@ -93,6 +93,7 @@ func newClient(options *Options, clientGetter genericclioptions.RESTClientGetter actionProvider := &provider{ Configuration: actionConfig, plainHttp: options.PlainHttp, + insecureTls: options.InsecureTls, } return &HelmClient{ From 6a742e52ed7afe766a6a69e3a95c8027197c0846 Mon Sep 17 00:00:00 2001 From: Philipp Pixel Date: Wed, 25 Oct 2023 16:02:11 +0200 Subject: [PATCH 06/32] Boyscouting: remove whitespace from structured log keys --- pkg/helm/client.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/helm/client.go b/pkg/helm/client.go index 6724ede..9ed01e6 100644 --- a/pkg/helm/client.go +++ b/pkg/helm/client.go @@ -120,8 +120,8 @@ func (c *Client) getChart(ctx context.Context, chartSpec *client.ChartSpec) (*ch logger.Info("Trying to get chart with options", "chart", chartSpec.ChartName, "version", chartSpec.Version, - "plain HTTP", c.helmRepoData.PlainHttp, - "insecure TLS", c.helmRepoData.InsecureTLS) + "plainHTTP", c.helmRepoData.PlainHttp, + "insecureTLS", c.helmRepoData.InsecureTLS) componentChart, _, err := c.helmClient.GetChart(chartSpec) if err != nil { From 8d985112d09f1a289ceb3ddaad4fbca46d48aa1b Mon Sep 17 00:00:00 2001 From: meiserloh Date: Thu, 26 Oct 2023 09:14:15 +0200 Subject: [PATCH 07/32] #35 Fix Test that broke due to Log-Level change --- pkg/logging/logger_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/logging/logger_test.go b/pkg/logging/logger_test.go index c21ddf8..c220db1 100644 --- a/pkg/logging/logger_test.go +++ b/pkg/logging/logger_test.go @@ -24,7 +24,7 @@ func TestConfigureLogger(t *testing.T) { // then assert.NoError(t, err) }) - t.Run("should not fail with empty string log level and return error level", func(t *testing.T) { + t.Run("should not fail with empty string log level and return info level", func(t *testing.T) { // given t.Setenv(logLevelEnvVar, "") @@ -33,7 +33,7 @@ func TestConfigureLogger(t *testing.T) { // then assert.NoError(t, err) - assert.Equal(t, logrus.ErrorLevel, CurrentLogLevel) + assert.Equal(t, logrus.InfoLevel, CurrentLogLevel) }) t.Run("create logger with invalid log level TEST_LEVEL", func(t *testing.T) { From cbfbe92652556ff7f427808968dd8f093bbd562a Mon Sep 17 00:00:00 2001 From: meiserloh Date: Thu, 26 Oct 2023 14:45:57 +0200 Subject: [PATCH 08/32] #36 add tests for insecureTls --- pkg/config/config_test.go | 47 ++++++++++++++++-------- pkg/config/testdata/helm-repository.yaml | 3 +- pkg/helm/client/action_test.go | 32 ++++++++++++++++ pkg/helm/client_test.go | 7 ++-- 4 files changed, 70 insertions(+), 19 deletions(-) diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go index 8b78cd7..b2ea5b7 100644 --- a/pkg/config/config_test.go +++ b/pkg/config/config_test.go @@ -48,9 +48,10 @@ func TestGetHelmRepositoryData(t *testing.T) { t.Setenv("RUNTIME", "local") devHelmRepoDataPath = "testdata/helm-repository.yaml" expected := &HelmRepositoryData{ - Endpoint: "192.168.56.3:30100", - Schema: EndpointSchemaOCI, - PlainHttp: true, + Endpoint: "192.168.56.3:30100", + Schema: EndpointSchemaOCI, + PlainHttp: true, + InsecureTLS: true, } // when @@ -66,13 +67,14 @@ func TestGetHelmRepositoryData(t *testing.T) { mockConfigMapInterface := newMockConfigMapInterface(t) configMap := &v1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{Name: "component-operator-helm-repository"}, - Data: map[string]string{"endpoint": "endpoint", "schema": "oci", "plainHttp": "false"}, + Data: map[string]string{"endpoint": "endpoint", "schema": "oci", "plainHttp": "false", "insecureTls": "true"}, } mockConfigMapInterface.On("Get", mock.Anything, "component-operator-helm-repository", mock.Anything).Return(configMap, nil) expected := &HelmRepositoryData{ - Endpoint: "endpoint", - Schema: EndpointSchemaOCI, - PlainHttp: false, + Endpoint: "endpoint", + Schema: EndpointSchemaOCI, + PlainHttp: false, + InsecureTLS: true, } // when @@ -112,6 +114,19 @@ func TestNewHelmRepoDataFromCluster(t *testing.T) { require.Error(t, err) assert.ErrorContains(t, err, "failed to parse field plainHttp from configMap component-operator-helm-repository") }) + t.Run("should fail to parse insecureTls", func(t *testing.T) { + // given + configMap := &v1.ConfigMap{Data: map[string]string{"insecureTls": "invalid"}} + configMapClient := newMockConfigMapInterface(t) + configMapClient.EXPECT().Get(testCtx, "component-operator-helm-repository", getOpts).Return(configMap, nil) + + // when + _, err := NewHelmRepoDataFromCluster(testCtx, configMapClient) + + // then + require.Error(t, err) + assert.ErrorContains(t, err, "failed to parse field insecureTls from configMap component-operator-helm-repository") + }) t.Run("should fail because endpoint has empty URL", func(t *testing.T) { // given configMap := &v1.ConfigMap{Data: map[string]string{"endpoint": ""}} @@ -151,9 +166,9 @@ func TestNewHelmRepoDataFromCluster(t *testing.T) { require.Error(t, err) assert.ErrorContains(t, err, "config map 'component-operator-helm-repository' failed validation: endpoint uses an unsupported schema 'https': valid schemas are: oci") }) - t.Run("should succeed to parse plainHttp and validate endpoint", func(t *testing.T) { + t.Run("should succeed to parse plainHttp and insecureTls and validate endpoint", func(t *testing.T) { // given - configMap := &v1.ConfigMap{Data: map[string]string{"endpoint": "myEndpoint", "schema": "oci", "plainHttp": "true"}} + configMap := &v1.ConfigMap{Data: map[string]string{"endpoint": "myEndpoint", "schema": "oci", "plainHttp": "true", "insecureTls": "true"}} configMapClient := newMockConfigMapInterface(t) configMapClient.EXPECT().Get(testCtx, "component-operator-helm-repository", getOpts).Return(configMap, nil) @@ -162,9 +177,10 @@ func TestNewHelmRepoDataFromCluster(t *testing.T) { // then expected := &HelmRepositoryData{ - Endpoint: "myEndpoint", - Schema: EndpointSchemaOCI, - PlainHttp: true, + Endpoint: "myEndpoint", + Schema: EndpointSchemaOCI, + PlainHttp: true, + InsecureTLS: true, } require.NoError(t, err) assert.Equal(t, expected, actual) @@ -199,9 +215,10 @@ func TestNewHelmRepoDataFromFile(t *testing.T) { name: "should succeed", filepath: "testdata/helm-repository.yaml", want: &HelmRepositoryData{ - Endpoint: "192.168.56.3:30100", - Schema: EndpointSchemaOCI, - PlainHttp: true, + Endpoint: "192.168.56.3:30100", + Schema: EndpointSchemaOCI, + PlainHttp: true, + InsecureTLS: true, }, wantErr: assert.NoError, }, diff --git a/pkg/config/testdata/helm-repository.yaml b/pkg/config/testdata/helm-repository.yaml index 907b0a4..153356b 100644 --- a/pkg/config/testdata/helm-repository.yaml +++ b/pkg/config/testdata/helm-repository.yaml @@ -1,3 +1,4 @@ endpoint: 192.168.56.3:30100 schema: oci -plainHttp: true \ No newline at end of file +plainHttp: true +insecureTls: true \ No newline at end of file diff --git a/pkg/helm/client/action_test.go b/pkg/helm/client/action_test.go index a89ae45..90151ec 100644 --- a/pkg/helm/client/action_test.go +++ b/pkg/helm/client/action_test.go @@ -11,6 +11,7 @@ func Test_provider_newInstall(t *testing.T) { sut := &provider{ Configuration: &action.Configuration{}, plainHttp: true, + insecureTls: true, } // when @@ -19,9 +20,39 @@ func Test_provider_newInstall(t *testing.T) { // then assert.NotEmpty(t, result.raw()) assert.True(t, result.raw().PlainHTTP) + assert.True(t, result.raw().InsecureSkipTLSverify) +} + +func Test_provider_newInstall_providerOptionsNotSet(t *testing.T) { + // given + sut := &provider{Configuration: &action.Configuration{}} + + // when + result := sut.newInstall() + + // then + assert.NotEmpty(t, result.raw()) + assert.False(t, result.raw().PlainHTTP) + assert.False(t, result.raw().InsecureSkipTLSverify) } func Test_provider_newUpgrade(t *testing.T) { + // given + sut := &provider{ + Configuration: &action.Configuration{}, + plainHttp: true, + insecureTls: true, + } + + // when + result := sut.newUpgrade() + + // then + assert.NotEmpty(t, result.raw()) + assert.True(t, result.raw().PlainHTTP) + assert.True(t, result.raw().InsecureSkipTLSverify) +} +func Test_provider_newUpgrade_providerOptionsNotSet(t *testing.T) { // given sut := &provider{Configuration: &action.Configuration{}} @@ -31,6 +62,7 @@ func Test_provider_newUpgrade(t *testing.T) { // then assert.NotEmpty(t, result.raw()) assert.False(t, result.raw().PlainHTTP) + assert.False(t, result.raw().InsecureSkipTLSverify) } func Test_provider_newUninstall(t *testing.T) { diff --git a/pkg/helm/client_test.go b/pkg/helm/client_test.go index 1bcb259..267418a 100644 --- a/pkg/helm/client_test.go +++ b/pkg/helm/client_test.go @@ -347,9 +347,10 @@ func TestClient_SatisfiesDependencies(t *testing.T) { t.Run("should succeed", func(t *testing.T) { // given repoConfigData := &config.HelmRepositoryData{ - Endpoint: "some.where/testing", - Schema: config.EndpointSchemaOCI, - PlainHttp: true, + Endpoint: "some.where/testing", + Schema: config.EndpointSchemaOCI, + PlainHttp: true, + InsecureTLS: true, } dependencies := []Dependency{createDependency("k8s-etcd", "3.2.1")} From fdb9a77e219c2d761022a8f70865fb985685dd86 Mon Sep 17 00:00:00 2001 From: meiserloh Date: Thu, 26 Oct 2023 14:46:30 +0200 Subject: [PATCH 09/32] #36 refactor new function to make newClient more readable --- pkg/helm/client/client.go | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/pkg/helm/client/client.go b/pkg/helm/client/client.go index 1bc35b9..110a738 100644 --- a/pkg/helm/client/client.go +++ b/pkg/helm/client/client.go @@ -69,22 +69,7 @@ func newClient(options *Options, clientGetter genericclioptions.RESTClientGetter return nil, err } - clientOpts := []registry.ClientOption{ - registry.ClientOptDebug(settings.Debug), - registry.ClientOptCredentialsFile(settings.RegistryConfig), - } - - if options.PlainHttp { - clientOpts = append(clientOpts, registry.ClientOptPlainHTTP()) - } - - if !options.PlainHttp && options.InsecureTls { - insecureHttpsClient := &http.Client{Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}} - httpClientOpt := registry.ClientOptHTTPClient(insecureHttpsClient) - clientOpts = append(clientOpts, httpClientOpt) - } - - registryClient, err := registry.NewClient(clientOpts...) + registryClient, err := createRegistryClient(options, settings) if err != nil { return nil, err } @@ -105,6 +90,24 @@ func newClient(options *Options, clientGetter genericclioptions.RESTClientGetter }, nil } +func createRegistryClient(options *Options, settings *cli.EnvSettings) (*registry.Client, error) { + clientOpts := []registry.ClientOption{ + registry.ClientOptDebug(settings.Debug), + registry.ClientOptCredentialsFile(settings.RegistryConfig), + } + + if options.PlainHttp { + clientOpts = append(clientOpts, registry.ClientOptPlainHTTP()) + } + + if !options.PlainHttp && options.InsecureTls { + insecureHttpsClient := &http.Client{Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}} + httpClientOpt := registry.ClientOptHTTPClient(insecureHttpsClient) + clientOpts = append(clientOpts, httpClientOpt) + } + return registry.NewClient(clientOpts...) +} + // setEnvSettings sets the client's environment settings based on the provided client configuration. func setEnvSettings(ppOptions **Options, settings *cli.EnvSettings) error { if *ppOptions == nil { From edf756494ef6e5290107ee53433e92621c9790d2 Mon Sep 17 00:00:00 2001 From: Philipp Pixel Date: Thu, 26 Oct 2023 15:52:07 +0200 Subject: [PATCH 10/32] Boyscouting: remove double pointer on helm options --- pkg/helm/client/client.go | 10 +++---- pkg/helm/client/client_test.go | 49 ++++++++++++++++++++++++++-------- 2 files changed, 42 insertions(+), 17 deletions(-) diff --git a/pkg/helm/client/client.go b/pkg/helm/client/client.go index 110a738..172bd7e 100644 --- a/pkg/helm/client/client.go +++ b/pkg/helm/client/client.go @@ -44,7 +44,7 @@ func NewClientFromRestConf(options *RestConfClientOptions) (Client, error) { // newClient is used by both NewClientFromKubeConf and NewClientFromRestConf // and returns a new Helm client via the provided options and REST config. func newClient(options *Options, clientGetter genericclioptions.RESTClientGetter, settings *cli.EnvSettings) (Client, error) { - err := setEnvSettings(&options, settings) + err := setEnvSettings(options, settings) if err != nil { return nil, err } @@ -109,16 +109,14 @@ func createRegistryClient(options *Options, settings *cli.EnvSettings) (*registr } // setEnvSettings sets the client's environment settings based on the provided client configuration. -func setEnvSettings(ppOptions **Options, settings *cli.EnvSettings) error { - if *ppOptions == nil { - *ppOptions = &Options{ +func setEnvSettings(options *Options, settings *cli.EnvSettings) error { + if options == nil { + options = &Options{ RepositoryConfig: defaultRepositoryConfigPath, RepositoryCache: defaultCachePath, } } - options := *ppOptions - // set the namespace with this ugly workaround because cli.EnvSettings.namespace is private // thank you helm! if options.Namespace != "" { diff --git a/pkg/helm/client/client_test.go b/pkg/helm/client/client_test.go index ded8bfe..154b8ff 100644 --- a/pkg/helm/client/client_test.go +++ b/pkg/helm/client/client_test.go @@ -56,19 +56,46 @@ func TestNewClientFromRestConf(t *testing.T) { } func Test_setEnvSettings(t *testing.T) { - // given - settings := &cli.EnvSettings{} - options := new(*Options) + t.Run("should lazy initialize options object with two field", func(t *testing.T) { + // given + settings := &cli.EnvSettings{} + options := new(Options) - // when - err := setEnvSettings(options, settings) + // when + err := setEnvSettings(options, settings) - // then - require.NoError(t, err) - assert.Equal(t, defaultRepositoryConfigPath, settings.RepositoryConfig) - assert.Equal(t, defaultCachePath, settings.RepositoryCache) - assert.Equal(t, defaultRepositoryConfigPath, (*options).RepositoryConfig) - assert.Equal(t, defaultCachePath, (*options).RepositoryCache) + // then + require.NoError(t, err) + assert.Equal(t, defaultRepositoryConfigPath, settings.RepositoryConfig) + assert.Equal(t, defaultCachePath, settings.RepositoryCache) + assert.Equal(t, defaultRepositoryConfigPath, (*options).RepositoryConfig) + assert.Equal(t, defaultCachePath, (*options).RepositoryCache) + }) + t.Run("should not initialize existing options object", func(t *testing.T) { + // given + settings := &cli.EnvSettings{} + options := &Options{ + Namespace: "asdf", + RepositoryConfig: "asdf", + RepositoryCache: "asdf", + Debug: true, + DebugLog: func(format string, v ...interface{}) {}, + RegistryConfig: "asdf", + Output: nil, + PlainHttp: true, + InsecureTls: true, + } + + // when + err := setEnvSettings(options, settings) + + // then + require.NoError(t, err) + assert.Equal(t, "asdf", settings.RepositoryConfig) + assert.Equal(t, "asdf", settings.RepositoryCache) + assert.Equal(t, true, settings.Debug) + assert.Equal(t, "asdf", settings.RegistryConfig) + }) } func TestHelmClient_UninstallReleaseByName(t *testing.T) { From 725359daa95f1ff8d3f2a9389ecd5e2cb5d7a291 Mon Sep 17 00:00:00 2001 From: Benjamin Ernst Date: Mon, 6 Nov 2023 08:14:11 +0100 Subject: [PATCH 11/32] #38 add documentation for creating components --- docs/operations/creating_components_de.md | 131 ++++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 docs/operations/creating_components_de.md diff --git a/docs/operations/creating_components_de.md b/docs/operations/creating_components_de.md new file mode 100644 index 0000000..f4452e1 --- /dev/null +++ b/docs/operations/creating_components_de.md @@ -0,0 +1,131 @@ +# Erstellung von K8s-CES-Komponenten + +K8s-CES-Komponenten stellen erforderliche Dienste für das Cloudogu EcoSystem bereit. +Dabei handelt es sich um Helm-Charts, die in einer OCI-Registry verfügbar sind. + +## Eine neue Komponente erstellen + +- neues Github-Repo anlegen + - Schema `k8s-NAME` + - Readme kann mit angelegt werden, alles andere machen wir händisch danach +- "develop"-Branch anlegen und zum Default machen (in den Github-Einstellungen des Repos) +- Vom develop einen neuen Branch abzweigen, auf dem gleich der ganze initiale code landen wird +- Grundsätzliche Dateien importieren bzw. an anderen Komponenten (bspw. k8s-velero oder k8s-etcd) orientieren: + - README.md + - Jenkinsfile + - LICENSE + - CHANGELOG.md + - Makefiles + - .gitignore +- "manifests"-Ordner mit dummy-yaml anlegen + - bspw. "promtail.yaml"; Inhalt siehe promtail-Repo + - Wird nur noch so lange benötigt, bis der Chart-Generierungsprozess in den Makefiles komplett umgestellt ist (?) +- K8S_PRE_GENERATE_TARGETS-Target in Makefile mit eigenem Target überschreiben + - Bspw. "K8S_PRE_GENERATE_TARGETS=generate-release-resource" + - In diesem Target die dummy-yaml nach "K8S_RESOURCE_TEMP_YAML" verschieben +- k8s-ordner: helm/Chart.yaml erzeugen + - mit "make helm-init-chart" erzeugen +- Eigenes Target "helm-NAME-apply" (bspw. "helm-promtail-apply") im Makefile erstellen + - bspw. aus k8s-etcd kopieren und anpassen + - `${K8S_HELM_RESSOURCES}/charts` als Voraussetzung (s.u.) + - Funktioniert analog zu "k8s-apply" aus k8s.mk, aber ohne das "image-import"-Target +- Offizielles Chart des Produkts (bspw. promtail) suchen und in `Chart.yaml` einfügen +```yaml +dependencies: + - name: promtail + version: 6.15.2 + repository: https://grafana.github.io/helm-charts +``` +- Make-Target schreiben, was den `k8s/helm/charts`-Ordner aus dem `dependencies`-Eintrag erzeugt +```make +.PHONY: ${K8S_HELM_RESSOURCES}/charts +${K8S_HELM_RESSOURCES}/charts: ${BINARY_HELM} + @cd ${K8S_HELM_RESSOURCES} && ${BINARY_HELM} repo add grafana https://grafana.github.io/helm-charts && ${BINARY_HELM} dependency build +``` +- Danach können folgende Make-Targets eingesetzt werden: + - helm-generate: Baut im targets-Ordner das fertige Helm-Chart aus den Ressourcen unter k8s/helm und der dummy-yaml zusammen + - helm-NAME-apply (bspw. "helm-promtail-apply"): Anwenden des Charts im Cluster +- Falls man das Helm-Chart später über den Komponenten-Operator installieren will: + - eigenes target helm-NAME-chart-import-Target schreiben (wie production-Fall im "helm-chart-import"-Target aus k8s-component.mk, aber ohne image-import, aber mit `${K8S_HELM_RESSOURCES}/charts` als Voraussetzung) + - "make component-apply" + +### Component-Dependencies + +> TODO + +### Component-Patch-Template +Damit eine K8s-CES-Komponente von `ces-mirror` gespiegelt werden kann, muss sie ein `Component-Patch-Template`enthalten. +Diese muss in einer Datei mit dem Namen `component-patch-tpl.yaml` im Root-Verzeichnis eines Helm-Charts abgelegt werden. +Das `Component-Patch-Template` enthält eine Liste aller nötigen Container-Images und Template-Anweisungen, um Image-Referenzen in Helm-Values-Dateien während der Spiegelung umzuschreiben. + +Der Aufbau sieht wie folgt aus: +```yaml +apiVersion: v1 + +values: + images: + : "" + : "" + +patches: + : + foo: + bar: + registry: "{{ registryFrom .images.imageKey1 }}" + repository: "{{ repositoryFrom .images.imageKey1 }}" + tag: "{{ tagFrom .images.imageKey1 }}" +``` + +#### apiVersion +Die `apiVersion` gibt die im Template verwendete Version der Patch-API an. +Derzeit wird von `ces-mirror` die Version `v1` unterstützt. +Die zugehörigen Template-Funktionen werden unter [patches](#patches) beschrieben. + +#### values +`values` enthält eine Map von beliebigen Werten, die für das Templating der in den [patches](#patches) angegebenen Dateien verwendet werden können. +Die `values` müssen mindestens eine Map `images` enthalten, die alle zu spiegelnden Container-Images enthält. +Der Key eines Eintrags in der `images`-Map kann beliebig gewählt werden. +Der Value eines Eintrags in der `images`-Map entspricht einer Container-Image-Referenz (z.B. `registry.cloudogu.com/k8s/k8s-dogu-operator:0.35.1`). + +#### patches +`patches` enthalten einzelne Templates für beliebige YAML-Dateien des Helm-Charts (z.B. die `values.yaml`). +Jedes Template ist unter dem Dateinamen der zu patchenden Datei abgelegt. +Ein Template kann eine beliebige YAML-Struktur enthalten. +Es wird die [Go template language](https://godoc.org/text/template) verwendet. +Die [`values`-map](#values) ist als Daten im Templating verfügbar. + +Zusätzlich stehe folgende Template-Funktionen zum Parsen von Container-Image-Referenzen bereit: + - **registryFrom **: liefert die Registry einer Container-Image-Referenz (z.B. `registry.cloudogu.com`) + - **repositoryFrom **: liefert das Repository einer Container-Image-Referenz (z.B. `k8s/k8s-dogu-operator`) + - **tagFrom **: liefert den Tag einer Container-Image-Referenz (z.B. `0.35.1`) + +Nachdem ein Template gerendert wurde, wird es in die "originale" YAML-Datei des Helm-Charts gemerged. +So bleiben Werte in der "originalen" YAML-Datei erhalten, die _nicht_ im Template enthalten sind. +Bereit vorhandene Werte werden vom gerenderten Template überschrieben. + +##### Beispiel `component-patch-tpl.yaml` + +```yaml +apiVersion: v1 + +values: + images: + engine: longhornio/longhorn-engine:v1.5.1 + manager: longhornio/longhorn-manager:v1.5.1 + ui: longhornio/longhorn-ui:v1.5.1 + +patches: + values.yaml: + longhorn: + image: + longhorn: + engine: + repository: "{{ registryFrom .images.engine }}/{{ repositoryFrom .images.engine }}" + tag: "{{ tagFrom .images.engine }}" + manager: + repository: "{{ registryFrom .images.manager }}/{{ repositoryFrom .images.manager }}" + tag: "{{ tagFrom .images.manager }}" + ui: + repository: "{{ registryFrom .images.ui }}/{{ repositoryFrom .images.ui }}" + tag: "{{ tagFrom .images.ui }}" +``` From c7a9987c4b8fc3137120a597d718d24e952858c8 Mon Sep 17 00:00:00 2001 From: Benjamin Ernst Date: Mon, 6 Nov 2023 10:29:20 +0100 Subject: [PATCH 12/32] #38 update documentation for creating new components and wrapping third-party components --- docs/operations/creating_components_de.md | 84 +++++++++++++++-------- 1 file changed, 54 insertions(+), 30 deletions(-) diff --git a/docs/operations/creating_components_de.md b/docs/operations/creating_components_de.md index f4452e1..8c8cf93 100644 --- a/docs/operations/creating_components_de.md +++ b/docs/operations/creating_components_de.md @@ -4,50 +4,74 @@ K8s-CES-Komponenten stellen erforderliche Dienste für das Cloudogu EcoSystem be Dabei handelt es sich um Helm-Charts, die in einer OCI-Registry verfügbar sind. ## Eine neue Komponente erstellen +Die folgenden Schritte beschreiben die Erstellung einer allgemeinen K8s-CES-Komponente, die im Cloudogu EcoSystem betrieben werden kann: - neues Github-Repo anlegen - Schema `k8s-NAME` - Readme kann mit angelegt werden, alles andere machen wir händisch danach - "develop"-Branch anlegen und zum Default machen (in den Github-Einstellungen des Repos) -- Vom develop einen neuen Branch abzweigen, auf dem gleich der ganze initiale code landen wird -- Grundsätzliche Dateien importieren bzw. an anderen Komponenten (bspw. k8s-velero oder k8s-etcd) orientieren: +- Vom develop einen neuen Branch für den initialen Sourcecode abzweigen +- Grundsätzliche Dateien importieren bzw. erstellen - README.md - Jenkinsfile - LICENSE - CHANGELOG.md - Makefiles - .gitignore -- "manifests"-Ordner mit dummy-yaml anlegen - - bspw. "promtail.yaml"; Inhalt siehe promtail-Repo - - Wird nur noch so lange benötigt, bis der Chart-Generierungsprozess in den Makefiles komplett umgestellt ist (?) -- K8S_PRE_GENERATE_TARGETS-Target in Makefile mit eigenem Target überschreiben - - Bspw. "K8S_PRE_GENERATE_TARGETS=generate-release-resource" - - In diesem Target die dummy-yaml nach "K8S_RESOURCE_TEMP_YAML" verschieben -- k8s-ordner: helm/Chart.yaml erzeugen +- Die K8s-Ressourcen der Komponente bestimmen: + - K8s-Controller: Einbindung des `k8s-controller.mk` Makefiles zur Generierung der K8s-Ressourcen + - Das Make-Target `k8s-create-temporary-resource` erstellen, das für die Erstellung der K8s-Ressourcen zuständig ist +- Im `k8s`-Ordner Helm-Chart `helm/Chart.yaml` erzeugen - mit "make helm-init-chart" erzeugen -- Eigenes Target "helm-NAME-apply" (bspw. "helm-promtail-apply") im Makefile erstellen - - bspw. aus k8s-etcd kopieren und anpassen - - `${K8S_HELM_RESSOURCES}/charts` als Voraussetzung (s.u.) - - Funktioniert analog zu "k8s-apply" aus k8s.mk, aber ohne das "image-import"-Target +- Ggf. [Component Dependencies](#component-dependencies) in der `Chart.yaml` eintragen +- Ein [Component Patch Template](#component-patch-template) erstellen + +Anschließend können die folgenden Make-Targets eingesetzt werden: + - `helm-generate`: Baut im target-Ordner das fertige Helm-Chart aus den Ressourcen unter k8s/helm und den generierten K8s-Ressourcen zusammen + - `helm-apply`: Anwenden des Charts im lokalen DEV-Cluster + - `component-apply`: Anwenden des Charts im lokalen DEV-Cluster als Installation/Upgrade über den Komponenten-Operator + - `helm-package-release`: Baut und packt das Helm-Chart als `.tgz` um es in ein Helm-Repository zu releasen + + +### Komponente für Fremd-Anwendungen erstellen +Um Fremd-Anwendungen als K8s-CES-Komponente zu erstellen sind einige extra Schritte nötig. +Hier am Beispiel für `promtail` beschrieben: + +- "manifests"-Ordner mit dummy-yaml anlegen + - bspw. "promtail.yaml" + ```yaml + # This is a dummy file, required for the makefile's yaml file generation process for the dogu-controller. + apiVersion: v1 + kind: ConfigMap + metadata: + name: promtail-dummy + data: {} + ``` - Offizielles Chart des Produkts (bspw. promtail) suchen und in `Chart.yaml` einfügen -```yaml -dependencies: - - name: promtail - version: 6.15.2 - repository: https://grafana.github.io/helm-charts -``` + ```yaml + dependencies: + - name: promtail + version: 6.15.2 + repository: https://grafana.github.io/helm-charts + ``` - Make-Target schreiben, was den `k8s/helm/charts`-Ordner aus dem `dependencies`-Eintrag erzeugt -```make -.PHONY: ${K8S_HELM_RESSOURCES}/charts -${K8S_HELM_RESSOURCES}/charts: ${BINARY_HELM} - @cd ${K8S_HELM_RESSOURCES} && ${BINARY_HELM} repo add grafana https://grafana.github.io/helm-charts && ${BINARY_HELM} dependency build -``` -- Danach können folgende Make-Targets eingesetzt werden: - - helm-generate: Baut im targets-Ordner das fertige Helm-Chart aus den Ressourcen unter k8s/helm und der dummy-yaml zusammen - - helm-NAME-apply (bspw. "helm-promtail-apply"): Anwenden des Charts im Cluster -- Falls man das Helm-Chart später über den Komponenten-Operator installieren will: - - eigenes target helm-NAME-chart-import-Target schreiben (wie production-Fall im "helm-chart-import"-Target aus k8s-component.mk, aber ohne image-import, aber mit `${K8S_HELM_RESSOURCES}/charts` als Voraussetzung) - - "make component-apply" + ```makefile + .PHONY: ${K8S_HELM_RESSOURCES}/charts + ${K8S_HELM_RESSOURCES}/charts: ${BINARY_HELM} + @cd ${K8S_HELM_RESSOURCES} && ${BINARY_HELM} repo add grafana https://grafana.github.io/helm-charts && ${BINARY_HELM} dependency build + ``` +- `K8S_PRE_GENERATE_TARGETS`-Target in Makefile mit eigenem Target überschreiben + - Bspw. `K8S_PRE_GENERATE_TARGETS=generate-release-resource` + - In diesem Target die dummy-yaml nach `K8S_RESOURCE_TEMP_YAML` verschieben +- Eigenes Target `helm-NAME-apply` (bspw. `helm-promtail-apply`) im Makefile erstellen + - Funktioniert analog zu "k8s-apply" aus k8s.mk, aber ohne das "image-import"-Target + ```makefile + .PHONY: helm-promtail-apply + helm-promtail-apply: ${BINARY_HELM} ${K8S_HELM_RESSOURCES}/charts helm-generate $(K8S_POST_GENERATE_TARGETS) ## Generates and installs the helm chart. + @echo "Apply generated helm chart" + @${BINARY_HELM} upgrade -i ${ARTIFACT_ID} ${K8S_HELM_TARGET} --namespace ${NAMESPACE} + ``` + ### Component-Dependencies From 73232dc2d13552bea43c54bd9cafbbc006e255e7 Mon Sep 17 00:00:00 2001 From: kahoona77 Date: Mon, 6 Nov 2023 10:31:32 +0100 Subject: [PATCH 13/32] Apply suggestions from code review Co-authored-by: Philipp Pixel --- docs/operations/creating_components_de.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/operations/creating_components_de.md b/docs/operations/creating_components_de.md index 8c8cf93..20febe4 100644 --- a/docs/operations/creating_components_de.md +++ b/docs/operations/creating_components_de.md @@ -1,7 +1,6 @@ -# Erstellung von K8s-CES-Komponenten +# Erstellung von K8s-Komponenten -K8s-CES-Komponenten stellen erforderliche Dienste für das Cloudogu EcoSystem bereit. -Dabei handelt es sich um Helm-Charts, die in einer OCI-Registry verfügbar sind. +K8s-CES-Komponenten stellen erforderliche Dienste für das Cloudogu EcoSystem (CES) bereit. ## Eine neue Komponente erstellen Die folgenden Schritte beschreiben die Erstellung einer allgemeinen K8s-CES-Komponente, die im Cloudogu EcoSystem betrieben werden kann: @@ -78,7 +77,7 @@ Hier am Beispiel für `promtail` beschrieben: > TODO ### Component-Patch-Template -Damit eine K8s-CES-Komponente von `ces-mirror` gespiegelt werden kann, muss sie ein `Component-Patch-Template`enthalten. +Damit eine K8s-CES-Komponente mit einer Cloudogu-eigenen Applikation in abgeschottete Umgebungen importiert werden kann, muss sie ein `Component-Patch-Template`enthalten. Diese muss in einer Datei mit dem Namen `component-patch-tpl.yaml` im Root-Verzeichnis eines Helm-Charts abgelegt werden. Das `Component-Patch-Template` enthält eine Liste aller nötigen Container-Images und Template-Anweisungen, um Image-Referenzen in Helm-Values-Dateien während der Spiegelung umzuschreiben. @@ -118,14 +117,15 @@ Ein Template kann eine beliebige YAML-Struktur enthalten. Es wird die [Go template language](https://godoc.org/text/template) verwendet. Die [`values`-map](#values) ist als Daten im Templating verfügbar. -Zusätzlich stehe folgende Template-Funktionen zum Parsen von Container-Image-Referenzen bereit: - - **registryFrom **: liefert die Registry einer Container-Image-Referenz (z.B. `registry.cloudogu.com`) - - **repositoryFrom **: liefert das Repository einer Container-Image-Referenz (z.B. `k8s/k8s-dogu-operator`) - - **tagFrom **: liefert den Tag einer Container-Image-Referenz (z.B. `0.35.1`) +Zusätzlich stehen folgende Template-Funktionen zum Parsen von Container-Image-Referenzen bereit. Dabei sollten die [Schlüssel](#values) für Container-Images verwendet werden, die bereits unter `.values.images` aufgeführt wurden, z. B. in Form `.images.yourContainerImageKey`: + +- **registryFrom **: liefert die Registry einer Container-Image-Referenz (z. B. `registry.cloudogu.com`) +- **repositoryFrom **: liefert das Repository einer Container-Image-Referenz (z. B. `k8s/k8s-dogu-operator`) +- **tagFrom **: liefert den Tag einer Container-Image-Referenz (z. B. `0.35.1`) Nachdem ein Template gerendert wurde, wird es in die "originale" YAML-Datei des Helm-Charts gemerged. So bleiben Werte in der "originalen" YAML-Datei erhalten, die _nicht_ im Template enthalten sind. -Bereit vorhandene Werte werden vom gerenderten Template überschrieben. +Bereits vorhandene Werte werden vom gerenderten Template überschrieben. ##### Beispiel `component-patch-tpl.yaml` From 777070514007a2e99ccde0082e0cc4f6e1bc96c4 Mon Sep 17 00:00:00 2001 From: Benjamin Ernst Date: Mon, 6 Nov 2023 10:54:13 +0100 Subject: [PATCH 14/32] #38 apply suggestions from review --- docs/operations/creating_components_de.md | 26 ++++++++++++++--------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/docs/operations/creating_components_de.md b/docs/operations/creating_components_de.md index 20febe4..8ef167f 100644 --- a/docs/operations/creating_components_de.md +++ b/docs/operations/creating_components_de.md @@ -72,11 +72,11 @@ Hier am Beispiel für `promtail` beschrieben: ``` -### Component-Dependencies +## Component-Dependencies > TODO -### Component-Patch-Template +## Component-Patch-Template Damit eine K8s-CES-Komponente mit einer Cloudogu-eigenen Applikation in abgeschottete Umgebungen importiert werden kann, muss sie ein `Component-Patch-Template`enthalten. Diese muss in einer Datei mit dem Namen `component-patch-tpl.yaml` im Root-Verzeichnis eines Helm-Charts abgelegt werden. Das `Component-Patch-Template` enthält eine Liste aller nötigen Container-Images und Template-Anweisungen, um Image-Referenzen in Helm-Values-Dateien während der Spiegelung umzuschreiben. @@ -99,24 +99,30 @@ patches: tag: "{{ tagFrom .images.imageKey1 }}" ``` -#### apiVersion +### apiVersion Die `apiVersion` gibt die im Template verwendete Version der Patch-API an. -Derzeit wird von `ces-mirror` die Version `v1` unterstützt. +Derzeit wird die Version `v1` unterstützt. Die zugehörigen Template-Funktionen werden unter [patches](#patches) beschrieben. -#### values +### values `values` enthält eine Map von beliebigen Werten, die für das Templating der in den [patches](#patches) angegebenen Dateien verwendet werden können. Die `values` müssen mindestens eine Map `images` enthalten, die alle zu spiegelnden Container-Images enthält. Der Key eines Eintrags in der `images`-Map kann beliebig gewählt werden. Der Value eines Eintrags in der `images`-Map entspricht einer Container-Image-Referenz (z.B. `registry.cloudogu.com/k8s/k8s-dogu-operator:0.35.1`). -#### patches +> **Wichtig:** +> - Der Key eines Eintrags in der `images`-Map darf keine Bindestriche "-" enthalten, damit die Verarbeitung in [Go-Templates](https://pkg.go.dev/text/template) möglich ist. +> - Der Value eines Eintrags in der `images`-Map sollte immer als String in doppelten Anführungsstrichen angegeben werden, um Probleme beim Parsen als YAML zu vermeiden. + +### patches `patches` enthalten einzelne Templates für beliebige YAML-Dateien des Helm-Charts (z.B. die `values.yaml`). Jedes Template ist unter dem Dateinamen der zu patchenden Datei abgelegt. Ein Template kann eine beliebige YAML-Struktur enthalten. Es wird die [Go template language](https://godoc.org/text/template) verwendet. Die [`values`-map](#values) ist als Daten im Templating verfügbar. +> **Wichtig:** Die Angaben der Go-Template-Functions (z.B. "{{ .Foo }}") muss als String in doppelten Anführungsstrichen, um Probleme beim Parsen als YAML zu verhindern. + Zusätzlich stehen folgende Template-Funktionen zum Parsen von Container-Image-Referenzen bereit. Dabei sollten die [Schlüssel](#values) für Container-Images verwendet werden, die bereits unter `.values.images` aufgeführt wurden, z. B. in Form `.images.yourContainerImageKey`: - **registryFrom **: liefert die Registry einer Container-Image-Referenz (z. B. `registry.cloudogu.com`) @@ -127,16 +133,16 @@ Nachdem ein Template gerendert wurde, wird es in die "originale" YAML-Datei des So bleiben Werte in der "originalen" YAML-Datei erhalten, die _nicht_ im Template enthalten sind. Bereits vorhandene Werte werden vom gerenderten Template überschrieben. -##### Beispiel `component-patch-tpl.yaml` +#### Beispiel `component-patch-tpl.yaml` ```yaml apiVersion: v1 values: images: - engine: longhornio/longhorn-engine:v1.5.1 - manager: longhornio/longhorn-manager:v1.5.1 - ui: longhornio/longhorn-ui:v1.5.1 + engine: "longhornio/longhorn-engine:v1.5.1" + manager: "longhornio/longhorn-manager:v1.5.1" + ui: "longhornio/longhorn-ui:v1.5.1" patches: values.yaml: From 66fe734f1dac24e0e30209d09c790578ea2a971a Mon Sep 17 00:00:00 2001 From: Benjamin Ernst Date: Mon, 6 Nov 2023 11:07:14 +0100 Subject: [PATCH 15/32] #38 add documentation for component-dependencies --- docs/operations/creating_components_de.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/docs/operations/creating_components_de.md b/docs/operations/creating_components_de.md index 8ef167f..a0d4bcc 100644 --- a/docs/operations/creating_components_de.md +++ b/docs/operations/creating_components_de.md @@ -73,8 +73,21 @@ Hier am Beispiel für `promtail` beschrieben: ## Component-Dependencies +K8s-CES-Komponenten können abhängig von anderen K8s-CES-Komponenten sein. +Damit der Komponenten-Operator diese Abhängigkeiten bei der Installation oder dem Upgrade von Komponenten überprüfen kann, müssen diese im Helm-Chart als `anntotaion` angegeben sein. -> TODO +Der Key der `annotataion` einer Component-Dependency muss immer in der Form `k8s.cloudogu.com/ces-dependency/` angeben sein. +Der `` ist der Name der K8s-CES-Komponenten, auf die die Abhängigkeit besteht. + +Der Value der `annotataion` einer Component-Dependency enthält die Version, in der die abhängige Komponente benötigt wird. +Hierbei wird [Semantic Versioning](https://semver.org/) verwendet, sodass auch Versionsbereiche angegeben werden können. + +### Beispiel Component-Dependency in der `Chart.yaml` +```yaml +annotations: + # Dependency for the Component-CRD. + "k8s.cloudogu.com/ces-dependency/k8s-component-operator-crd": "1.x.x-0" +``` ## Component-Patch-Template Damit eine K8s-CES-Komponente mit einer Cloudogu-eigenen Applikation in abgeschottete Umgebungen importiert werden kann, muss sie ein `Component-Patch-Template`enthalten. From 7257efa19e16ee4e2edb94a8be09e20fb48654cc Mon Sep 17 00:00:00 2001 From: Benjamin Ernst Date: Mon, 6 Nov 2023 11:40:16 +0100 Subject: [PATCH 16/32] #38 add suggestions from review Co-authored-by: Philipp Pixel --- docs/operations/creating_components_de.md | 61 ++++++++++++----------- 1 file changed, 31 insertions(+), 30 deletions(-) diff --git a/docs/operations/creating_components_de.md b/docs/operations/creating_components_de.md index a0d4bcc..3946b78 100644 --- a/docs/operations/creating_components_de.md +++ b/docs/operations/creating_components_de.md @@ -5,23 +5,19 @@ K8s-CES-Komponenten stellen erforderliche Dienste für das Cloudogu EcoSystem (C ## Eine neue Komponente erstellen Die folgenden Schritte beschreiben die Erstellung einer allgemeinen K8s-CES-Komponente, die im Cloudogu EcoSystem betrieben werden kann: -- neues Github-Repo anlegen +- neues Repo anlegen - Schema `k8s-NAME` - - Readme kann mit angelegt werden, alles andere machen wir händisch danach -- "develop"-Branch anlegen und zum Default machen (in den Github-Einstellungen des Repos) -- Vom develop einen neuen Branch für den initialen Sourcecode abzweigen - Grundsätzliche Dateien importieren bzw. erstellen - README.md - Jenkinsfile - LICENSE - CHANGELOG.md - - Makefiles + - [Makefiles](https://github.com/cloudogu/makefiles) - .gitignore - Die K8s-Ressourcen der Komponente bestimmen: - - K8s-Controller: Einbindung des `k8s-controller.mk` Makefiles zur Generierung der K8s-Ressourcen - - Das Make-Target `k8s-create-temporary-resource` erstellen, das für die Erstellung der K8s-Ressourcen zuständig ist -- Im `k8s`-Ordner Helm-Chart `helm/Chart.yaml` erzeugen - - mit "make helm-init-chart" erzeugen + - Als K8s-Controller: Einbindung des `k8s-controller.mk` Makefiles zur Generierung der K8s-Ressourcen + - Andernfalls: Das Make-Target `k8s-create-temporary-resource` erstellen, das für die Erstellung der K8s-Ressourcen zuständig ist +- Helm-Chart `Chart.yaml` in `k8s/helm/` mit `make helm-init-chart` erzeugen - Ggf. [Component Dependencies](#component-dependencies) in der `Chart.yaml` eintragen - Ein [Component Patch Template](#component-patch-template) erstellen @@ -32,38 +28,41 @@ Anschließend können die folgenden Make-Targets eingesetzt werden: - `helm-package-release`: Baut und packt das Helm-Chart als `.tgz` um es in ein Helm-Repository zu releasen -### Komponente für Fremd-Anwendungen erstellen -Um Fremd-Anwendungen als K8s-CES-Komponente zu erstellen sind einige extra Schritte nötig. +### Komponente für Fremdanwendungen erstellen +Um fremde Helm-Chart als K8s-CES-Komponente zu erstellen, sind zusätzliche Schritte nötig. Hier am Beispiel für `promtail` beschrieben: -- "manifests"-Ordner mit dummy-yaml anlegen - - bspw. "promtail.yaml" - ```yaml - # This is a dummy file, required for the makefile's yaml file generation process for the dogu-controller. - apiVersion: v1 - kind: ConfigMap - metadata: - name: promtail-dummy - data: {} - ``` -- Offizielles Chart des Produkts (bspw. promtail) suchen und in `Chart.yaml` einfügen +- Offizielles Chart des Produkts (bspw. promtail) suchen und in eigenes `Chart.yaml` als `dependency` einfügen ```yaml + name: k8s-promtail + ... dependencies: - name: promtail version: 6.15.2 repository: https://grafana.github.io/helm-charts ``` -- Make-Target schreiben, was den `k8s/helm/charts`-Ordner aus dem `dependencies`-Eintrag erzeugt +- Make-Target schreiben, das den `k8s/helm/charts`-Ordner aus dem `dependencies`-Eintrag erzeugt ```makefile .PHONY: ${K8S_HELM_RESSOURCES}/charts ${K8S_HELM_RESSOURCES}/charts: ${BINARY_HELM} @cd ${K8S_HELM_RESSOURCES} && ${BINARY_HELM} repo add grafana https://grafana.github.io/helm-charts && ${BINARY_HELM} dependency build ``` -- `K8S_PRE_GENERATE_TARGETS`-Target in Makefile mit eigenem Target überschreiben +- "manifests"-Ordner mit dummy-yaml anlegen + - Wird benötigt, da die Makefiles derzeit K8s-Ressourcen (yaml) benötigen um das Helm-chart zu erstellen + - bspw. "promtail.yaml" + ```yaml + # This is a dummy file, required for the makefile's yaml file generation process. + apiVersion: v1 + kind: ConfigMap + metadata: + name: promtail-dummy + data: {} + ``` +- `K8S_PRE_GENERATE_TARGETS`-Target im Makefile mit eigenem Target überschreiben - Bspw. `K8S_PRE_GENERATE_TARGETS=generate-release-resource` - In diesem Target die dummy-yaml nach `K8S_RESOURCE_TEMP_YAML` verschieben - Eigenes Target `helm-NAME-apply` (bspw. `helm-promtail-apply`) im Makefile erstellen - - Funktioniert analog zu "k8s-apply" aus k8s.mk, aber ohne das "image-import"-Target + - Funktioniert analog zu "k8s-apply" aus `k8s.mk`, aber ohne das "image-import"-Target ```makefile .PHONY: helm-promtail-apply helm-promtail-apply: ${BINARY_HELM} ${K8S_HELM_RESSOURCES}/charts helm-generate $(K8S_POST_GENERATE_TARGETS) ## Generates and installs the helm chart. @@ -74,12 +73,13 @@ Hier am Beispiel für `promtail` beschrieben: ## Component-Dependencies K8s-CES-Komponenten können abhängig von anderen K8s-CES-Komponenten sein. -Damit der Komponenten-Operator diese Abhängigkeiten bei der Installation oder dem Upgrade von Komponenten überprüfen kann, müssen diese im Helm-Chart als `anntotaion` angegeben sein. +Damit der Komponenten-Operator diese Abhängigkeiten bei der Installation oder dem Upgrade von Komponenten überprüfen kann, müssen diese im Helm-Chart als `annotation` angegeben sein. +Es können mehrere Abhängigkeiten angegeben werden. -Der Key der `annotataion` einer Component-Dependency muss immer in der Form `k8s.cloudogu.com/ces-dependency/` angeben sein. -Der `` ist der Name der K8s-CES-Komponenten, auf die die Abhängigkeit besteht. +Der Key der `annotation` einer Component-Dependency muss immer in der Form `k8s.cloudogu.com/ces-dependency/` angeben sein. +Der `` ist der Name der K8s-CES-Komponente, auf die die Abhängigkeit besteht. -Der Value der `annotataion` einer Component-Dependency enthält die Version, in der die abhängige Komponente benötigt wird. +Der Value der `annotation` einer Component-Dependency enthält die Version der abhängigen Komponente. Hierbei wird [Semantic Versioning](https://semver.org/) verwendet, sodass auch Versionsbereiche angegeben werden können. ### Beispiel Component-Dependency in der `Chart.yaml` @@ -134,7 +134,8 @@ Ein Template kann eine beliebige YAML-Struktur enthalten. Es wird die [Go template language](https://godoc.org/text/template) verwendet. Die [`values`-map](#values) ist als Daten im Templating verfügbar. -> **Wichtig:** Die Angaben der Go-Template-Functions (z.B. "{{ .Foo }}") muss als String in doppelten Anführungsstrichen, um Probleme beim Parsen als YAML zu verhindern. +> **Wichtig:** +> - Go-Template-Functions (z. B. "{{ .Foo }}") müssen als String in doppelten Anführungsstrichen angegeben werden, um Probleme beim Parsen als YAML zu verhindern. Zusätzlich stehen folgende Template-Funktionen zum Parsen von Container-Image-Referenzen bereit. Dabei sollten die [Schlüssel](#values) für Container-Images verwendet werden, die bereits unter `.values.images` aufgeführt wurden, z. B. in Form `.images.yourContainerImageKey`: From 089d21791c4fdb4f7b68759e01dfb8d237111003 Mon Sep 17 00:00:00 2001 From: Benjamin Ernst Date: Mon, 6 Nov 2023 11:42:07 +0100 Subject: [PATCH 17/32] #38 add changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3fb230d..24a3874 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Added +- [#38] Add documentation for creating components and component-patch-templates ## [v0.5.1] - 2023-10-11 ### Changed From ac31a7ad607df1b47d50fad98f6f6f9905b5e88e Mon Sep 17 00:00:00 2001 From: Philipp Pixel Date: Mon, 6 Nov 2023 13:08:37 +0100 Subject: [PATCH 18/32] Apply suggestions from code review Co-authored-by: kahoona77 --- pkg/config/config.go | 1 + pkg/logging/logger.go | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/config/config.go b/pkg/config/config.go index 9f40166..f09da0c 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -62,6 +62,7 @@ type HelmRepositoryData struct { Schema EndpointSchema `json:"schema" yaml:"schema"` // PlainHttp indicates that the repository endpoint should be accessed using plain http PlainHttp bool `json:"plainHttp,omitempty" yaml:"plainHttp,omitempty"` + // InsecureTls allows invalid or selfsigned certificates to be used. This option may be overridden by PlainHttp which forces HTTP traffic. InsecureTLS bool `json:"insecureTls" yaml:"insecureTls"` } diff --git a/pkg/logging/logger.go b/pkg/logging/logger.go index 11e2b34..7eb0f4e 100644 --- a/pkg/logging/logger.go +++ b/pkg/logging/logger.go @@ -24,7 +24,6 @@ const ( ) // CurrentLogLevel is the currently configured logLevel -// The default logLevel is "ERROR" var ( defaultLogLevel = logrus.InfoLevel CurrentLogLevel = defaultLogLevel From 97e6215bb28902b123d63a195a71d69d9475febf Mon Sep 17 00:00:00 2001 From: Philipp Pixel Date: Mon, 6 Nov 2023 13:10:31 +0100 Subject: [PATCH 19/32] Apply suggestions from code review Co-authored-by: kahoona77 --- pkg/helm/client/client_test.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/pkg/helm/client/client_test.go b/pkg/helm/client/client_test.go index 154b8ff..4453285 100644 --- a/pkg/helm/client/client_test.go +++ b/pkg/helm/client/client_test.go @@ -75,12 +75,12 @@ func Test_setEnvSettings(t *testing.T) { // given settings := &cli.EnvSettings{} options := &Options{ - Namespace: "asdf", - RepositoryConfig: "asdf", - RepositoryCache: "asdf", + Namespace: "anamespace", + RepositoryConfig: "arepoconfig", + RepositoryCache: "arepocache", Debug: true, DebugLog: func(format string, v ...interface{}) {}, - RegistryConfig: "asdf", + RegistryConfig: "aregconfig", Output: nil, PlainHttp: true, InsecureTls: true, @@ -91,10 +91,10 @@ func Test_setEnvSettings(t *testing.T) { // then require.NoError(t, err) - assert.Equal(t, "asdf", settings.RepositoryConfig) - assert.Equal(t, "asdf", settings.RepositoryCache) + assert.Equal(t, "arepoconfig", settings.RepositoryConfig) + assert.Equal(t, "arepocache", settings.RepositoryCache) assert.Equal(t, true, settings.Debug) - assert.Equal(t, "asdf", settings.RegistryConfig) + assert.Equal(t, "aregconfig", settings.RegistryConfig) }) } From 7f4303fb561f63531d86fcbf7b0798cd8d466448 Mon Sep 17 00:00:00 2001 From: Benjamin Ernst Date: Fri, 3 Nov 2023 16:07:56 +0100 Subject: [PATCH 20/32] add documentation for creating components and component-patch-templates --- docs/operations/creating_components_de.md | 131 ++++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 docs/operations/creating_components_de.md diff --git a/docs/operations/creating_components_de.md b/docs/operations/creating_components_de.md new file mode 100644 index 0000000..f4452e1 --- /dev/null +++ b/docs/operations/creating_components_de.md @@ -0,0 +1,131 @@ +# Erstellung von K8s-CES-Komponenten + +K8s-CES-Komponenten stellen erforderliche Dienste für das Cloudogu EcoSystem bereit. +Dabei handelt es sich um Helm-Charts, die in einer OCI-Registry verfügbar sind. + +## Eine neue Komponente erstellen + +- neues Github-Repo anlegen + - Schema `k8s-NAME` + - Readme kann mit angelegt werden, alles andere machen wir händisch danach +- "develop"-Branch anlegen und zum Default machen (in den Github-Einstellungen des Repos) +- Vom develop einen neuen Branch abzweigen, auf dem gleich der ganze initiale code landen wird +- Grundsätzliche Dateien importieren bzw. an anderen Komponenten (bspw. k8s-velero oder k8s-etcd) orientieren: + - README.md + - Jenkinsfile + - LICENSE + - CHANGELOG.md + - Makefiles + - .gitignore +- "manifests"-Ordner mit dummy-yaml anlegen + - bspw. "promtail.yaml"; Inhalt siehe promtail-Repo + - Wird nur noch so lange benötigt, bis der Chart-Generierungsprozess in den Makefiles komplett umgestellt ist (?) +- K8S_PRE_GENERATE_TARGETS-Target in Makefile mit eigenem Target überschreiben + - Bspw. "K8S_PRE_GENERATE_TARGETS=generate-release-resource" + - In diesem Target die dummy-yaml nach "K8S_RESOURCE_TEMP_YAML" verschieben +- k8s-ordner: helm/Chart.yaml erzeugen + - mit "make helm-init-chart" erzeugen +- Eigenes Target "helm-NAME-apply" (bspw. "helm-promtail-apply") im Makefile erstellen + - bspw. aus k8s-etcd kopieren und anpassen + - `${K8S_HELM_RESSOURCES}/charts` als Voraussetzung (s.u.) + - Funktioniert analog zu "k8s-apply" aus k8s.mk, aber ohne das "image-import"-Target +- Offizielles Chart des Produkts (bspw. promtail) suchen und in `Chart.yaml` einfügen +```yaml +dependencies: + - name: promtail + version: 6.15.2 + repository: https://grafana.github.io/helm-charts +``` +- Make-Target schreiben, was den `k8s/helm/charts`-Ordner aus dem `dependencies`-Eintrag erzeugt +```make +.PHONY: ${K8S_HELM_RESSOURCES}/charts +${K8S_HELM_RESSOURCES}/charts: ${BINARY_HELM} + @cd ${K8S_HELM_RESSOURCES} && ${BINARY_HELM} repo add grafana https://grafana.github.io/helm-charts && ${BINARY_HELM} dependency build +``` +- Danach können folgende Make-Targets eingesetzt werden: + - helm-generate: Baut im targets-Ordner das fertige Helm-Chart aus den Ressourcen unter k8s/helm und der dummy-yaml zusammen + - helm-NAME-apply (bspw. "helm-promtail-apply"): Anwenden des Charts im Cluster +- Falls man das Helm-Chart später über den Komponenten-Operator installieren will: + - eigenes target helm-NAME-chart-import-Target schreiben (wie production-Fall im "helm-chart-import"-Target aus k8s-component.mk, aber ohne image-import, aber mit `${K8S_HELM_RESSOURCES}/charts` als Voraussetzung) + - "make component-apply" + +### Component-Dependencies + +> TODO + +### Component-Patch-Template +Damit eine K8s-CES-Komponente von `ces-mirror` gespiegelt werden kann, muss sie ein `Component-Patch-Template`enthalten. +Diese muss in einer Datei mit dem Namen `component-patch-tpl.yaml` im Root-Verzeichnis eines Helm-Charts abgelegt werden. +Das `Component-Patch-Template` enthält eine Liste aller nötigen Container-Images und Template-Anweisungen, um Image-Referenzen in Helm-Values-Dateien während der Spiegelung umzuschreiben. + +Der Aufbau sieht wie folgt aus: +```yaml +apiVersion: v1 + +values: + images: + : "" + : "" + +patches: + : + foo: + bar: + registry: "{{ registryFrom .images.imageKey1 }}" + repository: "{{ repositoryFrom .images.imageKey1 }}" + tag: "{{ tagFrom .images.imageKey1 }}" +``` + +#### apiVersion +Die `apiVersion` gibt die im Template verwendete Version der Patch-API an. +Derzeit wird von `ces-mirror` die Version `v1` unterstützt. +Die zugehörigen Template-Funktionen werden unter [patches](#patches) beschrieben. + +#### values +`values` enthält eine Map von beliebigen Werten, die für das Templating der in den [patches](#patches) angegebenen Dateien verwendet werden können. +Die `values` müssen mindestens eine Map `images` enthalten, die alle zu spiegelnden Container-Images enthält. +Der Key eines Eintrags in der `images`-Map kann beliebig gewählt werden. +Der Value eines Eintrags in der `images`-Map entspricht einer Container-Image-Referenz (z.B. `registry.cloudogu.com/k8s/k8s-dogu-operator:0.35.1`). + +#### patches +`patches` enthalten einzelne Templates für beliebige YAML-Dateien des Helm-Charts (z.B. die `values.yaml`). +Jedes Template ist unter dem Dateinamen der zu patchenden Datei abgelegt. +Ein Template kann eine beliebige YAML-Struktur enthalten. +Es wird die [Go template language](https://godoc.org/text/template) verwendet. +Die [`values`-map](#values) ist als Daten im Templating verfügbar. + +Zusätzlich stehe folgende Template-Funktionen zum Parsen von Container-Image-Referenzen bereit: + - **registryFrom **: liefert die Registry einer Container-Image-Referenz (z.B. `registry.cloudogu.com`) + - **repositoryFrom **: liefert das Repository einer Container-Image-Referenz (z.B. `k8s/k8s-dogu-operator`) + - **tagFrom **: liefert den Tag einer Container-Image-Referenz (z.B. `0.35.1`) + +Nachdem ein Template gerendert wurde, wird es in die "originale" YAML-Datei des Helm-Charts gemerged. +So bleiben Werte in der "originalen" YAML-Datei erhalten, die _nicht_ im Template enthalten sind. +Bereit vorhandene Werte werden vom gerenderten Template überschrieben. + +##### Beispiel `component-patch-tpl.yaml` + +```yaml +apiVersion: v1 + +values: + images: + engine: longhornio/longhorn-engine:v1.5.1 + manager: longhornio/longhorn-manager:v1.5.1 + ui: longhornio/longhorn-ui:v1.5.1 + +patches: + values.yaml: + longhorn: + image: + longhorn: + engine: + repository: "{{ registryFrom .images.engine }}/{{ repositoryFrom .images.engine }}" + tag: "{{ tagFrom .images.engine }}" + manager: + repository: "{{ registryFrom .images.manager }}/{{ repositoryFrom .images.manager }}" + tag: "{{ tagFrom .images.manager }}" + ui: + repository: "{{ registryFrom .images.ui }}/{{ repositoryFrom .images.ui }}" + tag: "{{ tagFrom .images.ui }}" +``` From 8fbb202e37066df090b174766ba3bf193b1c0e99 Mon Sep 17 00:00:00 2001 From: Philipp Pixel Date: Mon, 6 Nov 2023 14:15:45 +0100 Subject: [PATCH 21/32] Revert "add documentation for creating components and component-patch-templates" This reverts commit 7f4303fb561f63531d86fcbf7b0798cd8d466448. --- docs/operations/creating_components_de.md | 131 ---------------------- 1 file changed, 131 deletions(-) delete mode 100644 docs/operations/creating_components_de.md diff --git a/docs/operations/creating_components_de.md b/docs/operations/creating_components_de.md deleted file mode 100644 index f4452e1..0000000 --- a/docs/operations/creating_components_de.md +++ /dev/null @@ -1,131 +0,0 @@ -# Erstellung von K8s-CES-Komponenten - -K8s-CES-Komponenten stellen erforderliche Dienste für das Cloudogu EcoSystem bereit. -Dabei handelt es sich um Helm-Charts, die in einer OCI-Registry verfügbar sind. - -## Eine neue Komponente erstellen - -- neues Github-Repo anlegen - - Schema `k8s-NAME` - - Readme kann mit angelegt werden, alles andere machen wir händisch danach -- "develop"-Branch anlegen und zum Default machen (in den Github-Einstellungen des Repos) -- Vom develop einen neuen Branch abzweigen, auf dem gleich der ganze initiale code landen wird -- Grundsätzliche Dateien importieren bzw. an anderen Komponenten (bspw. k8s-velero oder k8s-etcd) orientieren: - - README.md - - Jenkinsfile - - LICENSE - - CHANGELOG.md - - Makefiles - - .gitignore -- "manifests"-Ordner mit dummy-yaml anlegen - - bspw. "promtail.yaml"; Inhalt siehe promtail-Repo - - Wird nur noch so lange benötigt, bis der Chart-Generierungsprozess in den Makefiles komplett umgestellt ist (?) -- K8S_PRE_GENERATE_TARGETS-Target in Makefile mit eigenem Target überschreiben - - Bspw. "K8S_PRE_GENERATE_TARGETS=generate-release-resource" - - In diesem Target die dummy-yaml nach "K8S_RESOURCE_TEMP_YAML" verschieben -- k8s-ordner: helm/Chart.yaml erzeugen - - mit "make helm-init-chart" erzeugen -- Eigenes Target "helm-NAME-apply" (bspw. "helm-promtail-apply") im Makefile erstellen - - bspw. aus k8s-etcd kopieren und anpassen - - `${K8S_HELM_RESSOURCES}/charts` als Voraussetzung (s.u.) - - Funktioniert analog zu "k8s-apply" aus k8s.mk, aber ohne das "image-import"-Target -- Offizielles Chart des Produkts (bspw. promtail) suchen und in `Chart.yaml` einfügen -```yaml -dependencies: - - name: promtail - version: 6.15.2 - repository: https://grafana.github.io/helm-charts -``` -- Make-Target schreiben, was den `k8s/helm/charts`-Ordner aus dem `dependencies`-Eintrag erzeugt -```make -.PHONY: ${K8S_HELM_RESSOURCES}/charts -${K8S_HELM_RESSOURCES}/charts: ${BINARY_HELM} - @cd ${K8S_HELM_RESSOURCES} && ${BINARY_HELM} repo add grafana https://grafana.github.io/helm-charts && ${BINARY_HELM} dependency build -``` -- Danach können folgende Make-Targets eingesetzt werden: - - helm-generate: Baut im targets-Ordner das fertige Helm-Chart aus den Ressourcen unter k8s/helm und der dummy-yaml zusammen - - helm-NAME-apply (bspw. "helm-promtail-apply"): Anwenden des Charts im Cluster -- Falls man das Helm-Chart später über den Komponenten-Operator installieren will: - - eigenes target helm-NAME-chart-import-Target schreiben (wie production-Fall im "helm-chart-import"-Target aus k8s-component.mk, aber ohne image-import, aber mit `${K8S_HELM_RESSOURCES}/charts` als Voraussetzung) - - "make component-apply" - -### Component-Dependencies - -> TODO - -### Component-Patch-Template -Damit eine K8s-CES-Komponente von `ces-mirror` gespiegelt werden kann, muss sie ein `Component-Patch-Template`enthalten. -Diese muss in einer Datei mit dem Namen `component-patch-tpl.yaml` im Root-Verzeichnis eines Helm-Charts abgelegt werden. -Das `Component-Patch-Template` enthält eine Liste aller nötigen Container-Images und Template-Anweisungen, um Image-Referenzen in Helm-Values-Dateien während der Spiegelung umzuschreiben. - -Der Aufbau sieht wie folgt aus: -```yaml -apiVersion: v1 - -values: - images: - : "" - : "" - -patches: - : - foo: - bar: - registry: "{{ registryFrom .images.imageKey1 }}" - repository: "{{ repositoryFrom .images.imageKey1 }}" - tag: "{{ tagFrom .images.imageKey1 }}" -``` - -#### apiVersion -Die `apiVersion` gibt die im Template verwendete Version der Patch-API an. -Derzeit wird von `ces-mirror` die Version `v1` unterstützt. -Die zugehörigen Template-Funktionen werden unter [patches](#patches) beschrieben. - -#### values -`values` enthält eine Map von beliebigen Werten, die für das Templating der in den [patches](#patches) angegebenen Dateien verwendet werden können. -Die `values` müssen mindestens eine Map `images` enthalten, die alle zu spiegelnden Container-Images enthält. -Der Key eines Eintrags in der `images`-Map kann beliebig gewählt werden. -Der Value eines Eintrags in der `images`-Map entspricht einer Container-Image-Referenz (z.B. `registry.cloudogu.com/k8s/k8s-dogu-operator:0.35.1`). - -#### patches -`patches` enthalten einzelne Templates für beliebige YAML-Dateien des Helm-Charts (z.B. die `values.yaml`). -Jedes Template ist unter dem Dateinamen der zu patchenden Datei abgelegt. -Ein Template kann eine beliebige YAML-Struktur enthalten. -Es wird die [Go template language](https://godoc.org/text/template) verwendet. -Die [`values`-map](#values) ist als Daten im Templating verfügbar. - -Zusätzlich stehe folgende Template-Funktionen zum Parsen von Container-Image-Referenzen bereit: - - **registryFrom **: liefert die Registry einer Container-Image-Referenz (z.B. `registry.cloudogu.com`) - - **repositoryFrom **: liefert das Repository einer Container-Image-Referenz (z.B. `k8s/k8s-dogu-operator`) - - **tagFrom **: liefert den Tag einer Container-Image-Referenz (z.B. `0.35.1`) - -Nachdem ein Template gerendert wurde, wird es in die "originale" YAML-Datei des Helm-Charts gemerged. -So bleiben Werte in der "originalen" YAML-Datei erhalten, die _nicht_ im Template enthalten sind. -Bereit vorhandene Werte werden vom gerenderten Template überschrieben. - -##### Beispiel `component-patch-tpl.yaml` - -```yaml -apiVersion: v1 - -values: - images: - engine: longhornio/longhorn-engine:v1.5.1 - manager: longhornio/longhorn-manager:v1.5.1 - ui: longhornio/longhorn-ui:v1.5.1 - -patches: - values.yaml: - longhorn: - image: - longhorn: - engine: - repository: "{{ registryFrom .images.engine }}/{{ repositoryFrom .images.engine }}" - tag: "{{ tagFrom .images.engine }}" - manager: - repository: "{{ registryFrom .images.manager }}/{{ repositoryFrom .images.manager }}" - tag: "{{ tagFrom .images.manager }}" - ui: - repository: "{{ registryFrom .images.ui }}/{{ repositoryFrom .images.ui }}" - tag: "{{ tagFrom .images.ui }}" -``` From 33678b069b40656add8528b80935406e24148a0b Mon Sep 17 00:00:00 2001 From: Benjamin Ernst Date: Mon, 6 Nov 2023 14:22:02 +0100 Subject: [PATCH 22/32] #38 translate documentation for creating components to english Co-authored-by: Philipp Pixel --- CHANGELOG.md | 5 +- docs/operations/creating_components_de.md | 7 +- docs/operations/creating_components_en.md | 174 ++++++++++++++++++++++ 3 files changed, 181 insertions(+), 5 deletions(-) create mode 100644 docs/operations/creating_components_en.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 24a3874..02484cd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Added -- [#38] Add documentation for creating components and component-patch-templates +- [#38] Add [documentation](docs/operations/creating_components_en.md) for creating components and component-patch-templates + +### Changed +- [#36] Allow insecure TLS certificates with configuration options ## [v0.5.1] - 2023-10-11 ### Changed diff --git a/docs/operations/creating_components_de.md b/docs/operations/creating_components_de.md index 3946b78..76c972d 100644 --- a/docs/operations/creating_components_de.md +++ b/docs/operations/creating_components_de.md @@ -3,7 +3,7 @@ K8s-CES-Komponenten stellen erforderliche Dienste für das Cloudogu EcoSystem (CES) bereit. ## Eine neue Komponente erstellen -Die folgenden Schritte beschreiben die Erstellung einer allgemeinen K8s-CES-Komponente, die im Cloudogu EcoSystem betrieben werden kann: +Die folgenden Schritte beschreiben die Erstellung einer allgemeinen K8s-CES-Komponente, die im Multinode CES betrieben werden kann: - neues Repo anlegen - Schema `k8s-NAME` @@ -29,8 +29,7 @@ Anschließend können die folgenden Make-Targets eingesetzt werden: ### Komponente für Fremdanwendungen erstellen -Um fremde Helm-Chart als K8s-CES-Komponente zu erstellen, sind zusätzliche Schritte nötig. -Hier am Beispiel für `promtail` beschrieben: +Um fremde Helm-Chart als K8s-CES-Komponente zu erstellen, sind zusätzliche Schritte nötig, hier am Beispiel für `promtail` beschrieben: - Offizielles Chart des Produkts (bspw. promtail) suchen und in eigenes `Chart.yaml` als `dependency` einfügen ```yaml @@ -90,7 +89,7 @@ annotations: ``` ## Component-Patch-Template -Damit eine K8s-CES-Komponente mit einer Cloudogu-eigenen Applikation in abgeschottete Umgebungen importiert werden kann, muss sie ein `Component-Patch-Template`enthalten. +Damit eine K8s-CES-Komponente mit einer Cloudogu-eigenen Applikation in abgeschottete Umgebungen gespiegelt werden kann, muss sie ein `Component-Patch-Template`enthalten. Diese muss in einer Datei mit dem Namen `component-patch-tpl.yaml` im Root-Verzeichnis eines Helm-Charts abgelegt werden. Das `Component-Patch-Template` enthält eine Liste aller nötigen Container-Images und Template-Anweisungen, um Image-Referenzen in Helm-Values-Dateien während der Spiegelung umzuschreiben. diff --git a/docs/operations/creating_components_en.md b/docs/operations/creating_components_en.md new file mode 100644 index 0000000..dc07052 --- /dev/null +++ b/docs/operations/creating_components_en.md @@ -0,0 +1,174 @@ +# Creation of K8s components + +K8s CES components provide required services for the Cloudogu EcoSystem (CES). + +## Creating a new component +The following steps describe the creation of a general K8s CES component that can be operated in the Multinode CES: + +- Create a new repo + - Schema `k8s-NAME` +- Import or create basic files + - README.md + - Jenkinsfile + - LICENSE + - CHANGELOG.md + - [Makefiles](https://github.com/cloudogu/makefiles) + - .gitignore +- Determine the K8s resources of the component: + - As K8s controller: Include the `k8s-controller.mk` Makefile to generate the K8s resources + - Otherwise: Create the Make target `k8s-create-temporary-resource`, which is responsible for creating the K8s resources +- Create Helm chart `Chart.yaml` in `k8s/helm/` with `make helm-init-chart` +- If necessary, enter [Component Dependencies](#component-dependencies) in the `Chart.yaml`. +- Create a [Component Patch Template](#component-patch-template) + +The following make targets can then be used: +- `helm-generate`: Assembles the finished Helm chart in the target folder from the resources under k8s/helm and the generated K8s resources +- `helm-apply`: Applies the chart in the local DEV cluster +- `component-apply`: Applying the chart in the local DEV cluster as an installation/upgrade via the component operator +- `helm-package-release`: Builds and packs the Helm chart as `.tgz` to release it into a Helm repository + + +### Create component for third-party applications +Additional steps are required to create third-party Helm charts as K8s CES components, described here using the example of `promtail`: + +- Search for the official chart of the product (e.g. promtail) and insert it into your own `Chart.yaml` as `dependency`. + ```yaml + name: k8s-promtail + ... + dependencies: + - name: promtail + version: 6.15.2 + repository: https://grafana.github.io/helm-charts + ``` +- Write a make target that creates the `k8s/helm/charts` folder from the `dependencies` entry + ```makefile + .PHONY: ${K8S_HELM_RESSOURCES}/charts + ${K8S_HELM_RESSOURCES}/charts: ${BINARY_HELM} + @cd ${K8S_HELM_RESSOURCES} && ${BINARY_HELM} repo add grafana https://grafana.github.io/helm-charts && ${BINARY_HELM} dependency build + ``` +- Create "manifests" folder with dummy-yaml + - Necessary because the Makefiles currently require K8s resources (yaml) to create the Helm chart + - e.g. "promtail.yaml" + ```yaml + # This is a dummy file, required for the makefile's yaml file generation process. + apiVersion: v1 + kind: ConfigMap + metadata: + name: promtail-dummy + data: {} + ``` +- Overwrite `K8S_PRE_GENERATE_TARGETS` target in the Makefile with your own target + - E.g. `K8S_PRE_GENERATE_TARGETS=generate-release-resource`. + - Move the dummy-yaml to `K8S_RESOURCE_TEMP_YAML` in this target +- Create your own target `helm-NAME-apply` (e.g. `helm-promtail-apply`) in the Makefile + - This works similar to "k8s-apply" from `k8s.mk`, but without the "image-import" target + ```makefile + .PHONY: helm-promtail-apply + helm-promtail-apply: ${BINARY_HELM} ${K8S_HELM_RESSOURCES}/charts helm-generate $(K8S_POST_GENERATE_TARGETS) ## Generates and installs the helm chart. + @echo "Apply generated helm chart" + @${BINARY_HELM} upgrade -i ${ARTIFACT_ID} ${K8S_HELM_TARGET} --namespace ${NAMESPACE} + ``` + + +## Component dependencies +K8s CES components may depend on other K8s CES components. +So that the component operator can check these dependencies when installing or upgrading components, they must be specified in the Helm chart as `annotation`. +Several dependencies can be specified. + +The component dependency's `annotation` key must always be specified in the form `k8s.cloudogu.com/ces-dependency/`. +The `` is the name of the K8s CES component on which the dependency exists. + +The component dependency's `annotation` value contains the version of the dependent component. +[Semantic versioning](https://semver.org/) is used here so that version ranges can also be specified. + +### Example component dependency in the `Chart.yaml` +```yaml +annotations: + # Dependency for the Component-CRD. + "k8s.cloudogu.com/ces-dependency/k8s-component-operator-crd": "1.x.x-0" +``` + +## Component patch template +In order for a K8s CES component to be mirrored into air-gapped environments with a Cloudogu application, it must contain a 'component patch template'. +This must be stored in a file with the name `component-patch-tpl.yaml` in the root directory of a Helm chart. +The `component-patch-template` contains a list of all necessary container images and template instructions to rewrite image references in Helm Values files during mirroring. + +The structure is as follows: +```yaml +apiVersion: v1 + +values: + images: + : "" + : "" + +patches: + : + foo: + bar: + registry: "{{ registryFrom .images.imageKey1 }}" + repository: "{{ repositoryFrom .images.imageKey1 }}" + tag: "{{ tagFrom .images.imageKey1 }}" +``` + +### apiVersion +The `apiVersion` specifies the version of the patch API used in the template. +Version `v1` is currently supported. +The associated template functions are described under [patches](#patches). + +### values +`values` contains a map of arbitrary values that can be used for templating the files specified in the [patches](#patches). +The `values` must contain at least one map `images`, which contains all container images to be mirrored. +The key of an entry in the `images` map can be chosen arbitrarily. +The value of an entry in the `images` map corresponds to a container image reference (e.g. `registry.cloudogu.com/k8s/k8s-dogu-operator:0.35.1`). + +> **Important:** +> - The key of an entry in the `images` map must not contain any hyphens "-" so that processing in [Go-Templates](https://pkg.go.dev/text/template) is possible. +> - The value of an entry in the `images` map should always be specified as a string in double quotes to avoid problems when parsing as YAML. + +### patches +`patches` contain individual templates for any YAML files of the Helm chart (e.g. the `values.yaml`). +Each template is stored under the file name of the file to be patched. +A template can contain any YAML structure. +The [Go template language](https://godoc.org/text/template) is used. +The [`values`-map](#values) is available as data in the templating. + +> **Important:** +> Go template functions (e.g. "{{ .Foo }}") must be specified as a string in double quotes to prevent problems when parsing as YAML. + +In addition, the following template functions are available for parsing container image references. The [keys](#values) for container images already listed under `.values.images` should be used, e.g. in the form `.images.yourContainerImageKey`: + +- **registryFrom **: returns the registry of a container image reference (e.g. `registry.cloudogu.com`) +- **repositoryFrom **: returns the repository of a container image reference (e.g. `k8s/k8s-dogu-operator`) +- **tagFrom **: returns the tag of a container image reference (e.g. `0.35.1`) + +After a template has been rendered, it is merged into the "original" YAML file of the Helm chart. +This preserves values in the "original" YAML file that are _not_ contained in the template. +Existing values are overwritten by the rendered template. + +#### Example `component-patch-tpl.yaml` + +```yaml +apiVersion: v1 + +values: + images: + engine: "longhornio/longhorn-engine:v1.5.1" + manager: "longhornio/longhorn-manager:v1.5.1" + ui: "longhornio/longhorn-ui:v1.5.1" + +patches: + values.yaml: + longhorn: + image: + longhorn: + engine: + repository: "{{ registryFrom .images.engine }}/{{ repositoryFrom .images.engine }}" + tag: "{{ tagFrom .images.engine }}" + manager: + repository: "{{ registryFrom .images.manager }}/{{ repositoryFrom .images.manager }}" + tag: "{{ tagFrom .images.manager }}" + ui: + repository: "{{ registryFrom .images.ui }}/{{ repositoryFrom .images.ui }}" + tag: "{{ tagFrom .images.ui }}" +``` From 0d6eb24e2ae56095be391cba6c589e79295191e1 Mon Sep 17 00:00:00 2001 From: meiserloh Date: Tue, 14 Nov 2023 13:56:21 +0100 Subject: [PATCH 23/32] #40 add additional values yaml option to component --- .../mock_ComponentEcosystemInterface_test.go | 2417 +++++++++++++++++ .../mock_ComponentV1Alpha1Interface_test.go | 77 + pkg/api/v1/ces_component_types.go | 5 + pkg/controllers/componentController.go | 35 +- pkg/controllers/interfaces.go | 4 + pkg/controllers/mock_helmClient_test.go | 109 + pkg/helm/client.go | 10 + pkg/helm/client/client.go | 14 +- pkg/helm/client/interface.go | 1 + pkg/helm/client/mock_Client_test.go | 718 +++++ pkg/helm/client/mock_RESTClientOption_test.go | 69 + pkg/helm/client/mock_RollBack_test.go | 75 + pkg/helm/client/mock_TagResolver_test.go | 87 + pkg/helm/mock_HelmClient_test.go | 54 + 14 files changed, 3671 insertions(+), 4 deletions(-) create mode 100644 pkg/api/ecosystem/mock_ComponentEcosystemInterface_test.go create mode 100644 pkg/api/ecosystem/mock_ComponentV1Alpha1Interface_test.go create mode 100644 pkg/helm/client/mock_Client_test.go create mode 100644 pkg/helm/client/mock_RESTClientOption_test.go create mode 100644 pkg/helm/client/mock_RollBack_test.go create mode 100644 pkg/helm/client/mock_TagResolver_test.go diff --git a/pkg/api/ecosystem/mock_ComponentEcosystemInterface_test.go b/pkg/api/ecosystem/mock_ComponentEcosystemInterface_test.go new file mode 100644 index 0000000..7f25cc3 --- /dev/null +++ b/pkg/api/ecosystem/mock_ComponentEcosystemInterface_test.go @@ -0,0 +1,2417 @@ +// Code generated by mockery v2.20.0. DO NOT EDIT. + +package ecosystem + +import ( + apiserverinternalv1alpha1 "k8s.io/client-go/kubernetes/typed/apiserverinternal/v1alpha1" + appsv1 "k8s.io/client-go/kubernetes/typed/apps/v1" + + appsv1beta1 "k8s.io/client-go/kubernetes/typed/apps/v1beta1" + + authenticationv1 "k8s.io/client-go/kubernetes/typed/authentication/v1" + + authenticationv1alpha1 "k8s.io/client-go/kubernetes/typed/authentication/v1alpha1" + + authenticationv1beta1 "k8s.io/client-go/kubernetes/typed/authentication/v1beta1" + + authorizationv1 "k8s.io/client-go/kubernetes/typed/authorization/v1" + + authorizationv1beta1 "k8s.io/client-go/kubernetes/typed/authorization/v1beta1" + + autoscalingv1 "k8s.io/client-go/kubernetes/typed/autoscaling/v1" + + batchv1 "k8s.io/client-go/kubernetes/typed/batch/v1" + + batchv1beta1 "k8s.io/client-go/kubernetes/typed/batch/v1beta1" + + certificatesv1 "k8s.io/client-go/kubernetes/typed/certificates/v1" + + certificatesv1alpha1 "k8s.io/client-go/kubernetes/typed/certificates/v1alpha1" + + certificatesv1beta1 "k8s.io/client-go/kubernetes/typed/certificates/v1beta1" + + coordinationv1 "k8s.io/client-go/kubernetes/typed/coordination/v1" + + coordinationv1beta1 "k8s.io/client-go/kubernetes/typed/coordination/v1beta1" + + corev1 "k8s.io/client-go/kubernetes/typed/core/v1" + + discovery "k8s.io/client-go/discovery" + + discoveryv1 "k8s.io/client-go/kubernetes/typed/discovery/v1" + + discoveryv1beta1 "k8s.io/client-go/kubernetes/typed/discovery/v1beta1" + + eventsv1 "k8s.io/client-go/kubernetes/typed/events/v1" + + eventsv1beta1 "k8s.io/client-go/kubernetes/typed/events/v1beta1" + + extensionsv1beta1 "k8s.io/client-go/kubernetes/typed/extensions/v1beta1" + + flowcontrolv1alpha1 "k8s.io/client-go/kubernetes/typed/flowcontrol/v1alpha1" + + flowcontrolv1beta1 "k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta1" + + flowcontrolv1beta2 "k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta2" + + mock "github.com/stretchr/testify/mock" + + networkingv1 "k8s.io/client-go/kubernetes/typed/networking/v1" + + networkingv1alpha1 "k8s.io/client-go/kubernetes/typed/networking/v1alpha1" + + networkingv1beta1 "k8s.io/client-go/kubernetes/typed/networking/v1beta1" + + nodev1 "k8s.io/client-go/kubernetes/typed/node/v1" + + nodev1alpha1 "k8s.io/client-go/kubernetes/typed/node/v1alpha1" + + nodev1beta1 "k8s.io/client-go/kubernetes/typed/node/v1beta1" + + policyv1 "k8s.io/client-go/kubernetes/typed/policy/v1" + + policyv1beta1 "k8s.io/client-go/kubernetes/typed/policy/v1beta1" + + rbacv1 "k8s.io/client-go/kubernetes/typed/rbac/v1" + + rbacv1alpha1 "k8s.io/client-go/kubernetes/typed/rbac/v1alpha1" + + rbacv1beta1 "k8s.io/client-go/kubernetes/typed/rbac/v1beta1" + + schedulingv1 "k8s.io/client-go/kubernetes/typed/scheduling/v1" + + schedulingv1alpha1 "k8s.io/client-go/kubernetes/typed/scheduling/v1alpha1" + + schedulingv1beta1 "k8s.io/client-go/kubernetes/typed/scheduling/v1beta1" + + storagev1 "k8s.io/client-go/kubernetes/typed/storage/v1" + + storagev1alpha1 "k8s.io/client-go/kubernetes/typed/storage/v1alpha1" + + storagev1beta1 "k8s.io/client-go/kubernetes/typed/storage/v1beta1" + + v1 "k8s.io/client-go/kubernetes/typed/admissionregistration/v1" + + v1alpha1 "k8s.io/client-go/kubernetes/typed/admissionregistration/v1alpha1" + + v1alpha2 "k8s.io/client-go/kubernetes/typed/resource/v1alpha2" + + v1beta1 "k8s.io/client-go/kubernetes/typed/admissionregistration/v1beta1" + + v1beta2 "k8s.io/client-go/kubernetes/typed/apps/v1beta2" + + v1beta3 "k8s.io/client-go/kubernetes/typed/flowcontrol/v1beta3" + + v2 "k8s.io/client-go/kubernetes/typed/autoscaling/v2" + + v2beta1 "k8s.io/client-go/kubernetes/typed/autoscaling/v2beta1" + + v2beta2 "k8s.io/client-go/kubernetes/typed/autoscaling/v2beta2" +) + +// MockComponentEcosystemInterface is an autogenerated mock type for the ComponentEcosystemInterface type +type MockComponentEcosystemInterface struct { + mock.Mock +} + +type MockComponentEcosystemInterface_Expecter struct { + mock *mock.Mock +} + +func (_m *MockComponentEcosystemInterface) EXPECT() *MockComponentEcosystemInterface_Expecter { + return &MockComponentEcosystemInterface_Expecter{mock: &_m.Mock} +} + +// AdmissionregistrationV1 provides a mock function with given fields: +func (_m *MockComponentEcosystemInterface) AdmissionregistrationV1() v1.AdmissionregistrationV1Interface { + ret := _m.Called() + + var r0 v1.AdmissionregistrationV1Interface + if rf, ok := ret.Get(0).(func() v1.AdmissionregistrationV1Interface); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(v1.AdmissionregistrationV1Interface) + } + } + + return r0 +} + +// MockComponentEcosystemInterface_AdmissionregistrationV1_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AdmissionregistrationV1' +type MockComponentEcosystemInterface_AdmissionregistrationV1_Call struct { + *mock.Call +} + +// AdmissionregistrationV1 is a helper method to define mock.On call +func (_e *MockComponentEcosystemInterface_Expecter) AdmissionregistrationV1() *MockComponentEcosystemInterface_AdmissionregistrationV1_Call { + return &MockComponentEcosystemInterface_AdmissionregistrationV1_Call{Call: _e.mock.On("AdmissionregistrationV1")} +} + +func (_c *MockComponentEcosystemInterface_AdmissionregistrationV1_Call) Run(run func()) *MockComponentEcosystemInterface_AdmissionregistrationV1_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockComponentEcosystemInterface_AdmissionregistrationV1_Call) Return(_a0 v1.AdmissionregistrationV1Interface) *MockComponentEcosystemInterface_AdmissionregistrationV1_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockComponentEcosystemInterface_AdmissionregistrationV1_Call) RunAndReturn(run func() v1.AdmissionregistrationV1Interface) *MockComponentEcosystemInterface_AdmissionregistrationV1_Call { + _c.Call.Return(run) + return _c +} + +// AdmissionregistrationV1alpha1 provides a mock function with given fields: +func (_m *MockComponentEcosystemInterface) AdmissionregistrationV1alpha1() v1alpha1.AdmissionregistrationV1alpha1Interface { + ret := _m.Called() + + var r0 v1alpha1.AdmissionregistrationV1alpha1Interface + if rf, ok := ret.Get(0).(func() v1alpha1.AdmissionregistrationV1alpha1Interface); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(v1alpha1.AdmissionregistrationV1alpha1Interface) + } + } + + return r0 +} + +// MockComponentEcosystemInterface_AdmissionregistrationV1alpha1_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AdmissionregistrationV1alpha1' +type MockComponentEcosystemInterface_AdmissionregistrationV1alpha1_Call struct { + *mock.Call +} + +// AdmissionregistrationV1alpha1 is a helper method to define mock.On call +func (_e *MockComponentEcosystemInterface_Expecter) AdmissionregistrationV1alpha1() *MockComponentEcosystemInterface_AdmissionregistrationV1alpha1_Call { + return &MockComponentEcosystemInterface_AdmissionregistrationV1alpha1_Call{Call: _e.mock.On("AdmissionregistrationV1alpha1")} +} + +func (_c *MockComponentEcosystemInterface_AdmissionregistrationV1alpha1_Call) Run(run func()) *MockComponentEcosystemInterface_AdmissionregistrationV1alpha1_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockComponentEcosystemInterface_AdmissionregistrationV1alpha1_Call) Return(_a0 v1alpha1.AdmissionregistrationV1alpha1Interface) *MockComponentEcosystemInterface_AdmissionregistrationV1alpha1_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockComponentEcosystemInterface_AdmissionregistrationV1alpha1_Call) RunAndReturn(run func() v1alpha1.AdmissionregistrationV1alpha1Interface) *MockComponentEcosystemInterface_AdmissionregistrationV1alpha1_Call { + _c.Call.Return(run) + return _c +} + +// AdmissionregistrationV1beta1 provides a mock function with given fields: +func (_m *MockComponentEcosystemInterface) AdmissionregistrationV1beta1() v1beta1.AdmissionregistrationV1beta1Interface { + ret := _m.Called() + + var r0 v1beta1.AdmissionregistrationV1beta1Interface + if rf, ok := ret.Get(0).(func() v1beta1.AdmissionregistrationV1beta1Interface); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(v1beta1.AdmissionregistrationV1beta1Interface) + } + } + + return r0 +} + +// MockComponentEcosystemInterface_AdmissionregistrationV1beta1_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AdmissionregistrationV1beta1' +type MockComponentEcosystemInterface_AdmissionregistrationV1beta1_Call struct { + *mock.Call +} + +// AdmissionregistrationV1beta1 is a helper method to define mock.On call +func (_e *MockComponentEcosystemInterface_Expecter) AdmissionregistrationV1beta1() *MockComponentEcosystemInterface_AdmissionregistrationV1beta1_Call { + return &MockComponentEcosystemInterface_AdmissionregistrationV1beta1_Call{Call: _e.mock.On("AdmissionregistrationV1beta1")} +} + +func (_c *MockComponentEcosystemInterface_AdmissionregistrationV1beta1_Call) Run(run func()) *MockComponentEcosystemInterface_AdmissionregistrationV1beta1_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockComponentEcosystemInterface_AdmissionregistrationV1beta1_Call) Return(_a0 v1beta1.AdmissionregistrationV1beta1Interface) *MockComponentEcosystemInterface_AdmissionregistrationV1beta1_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockComponentEcosystemInterface_AdmissionregistrationV1beta1_Call) RunAndReturn(run func() v1beta1.AdmissionregistrationV1beta1Interface) *MockComponentEcosystemInterface_AdmissionregistrationV1beta1_Call { + _c.Call.Return(run) + return _c +} + +// AppsV1 provides a mock function with given fields: +func (_m *MockComponentEcosystemInterface) AppsV1() appsv1.AppsV1Interface { + ret := _m.Called() + + var r0 appsv1.AppsV1Interface + if rf, ok := ret.Get(0).(func() appsv1.AppsV1Interface); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(appsv1.AppsV1Interface) + } + } + + return r0 +} + +// MockComponentEcosystemInterface_AppsV1_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AppsV1' +type MockComponentEcosystemInterface_AppsV1_Call struct { + *mock.Call +} + +// AppsV1 is a helper method to define mock.On call +func (_e *MockComponentEcosystemInterface_Expecter) AppsV1() *MockComponentEcosystemInterface_AppsV1_Call { + return &MockComponentEcosystemInterface_AppsV1_Call{Call: _e.mock.On("AppsV1")} +} + +func (_c *MockComponentEcosystemInterface_AppsV1_Call) Run(run func()) *MockComponentEcosystemInterface_AppsV1_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockComponentEcosystemInterface_AppsV1_Call) Return(_a0 appsv1.AppsV1Interface) *MockComponentEcosystemInterface_AppsV1_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockComponentEcosystemInterface_AppsV1_Call) RunAndReturn(run func() appsv1.AppsV1Interface) *MockComponentEcosystemInterface_AppsV1_Call { + _c.Call.Return(run) + return _c +} + +// AppsV1beta1 provides a mock function with given fields: +func (_m *MockComponentEcosystemInterface) AppsV1beta1() appsv1beta1.AppsV1beta1Interface { + ret := _m.Called() + + var r0 appsv1beta1.AppsV1beta1Interface + if rf, ok := ret.Get(0).(func() appsv1beta1.AppsV1beta1Interface); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(appsv1beta1.AppsV1beta1Interface) + } + } + + return r0 +} + +// MockComponentEcosystemInterface_AppsV1beta1_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AppsV1beta1' +type MockComponentEcosystemInterface_AppsV1beta1_Call struct { + *mock.Call +} + +// AppsV1beta1 is a helper method to define mock.On call +func (_e *MockComponentEcosystemInterface_Expecter) AppsV1beta1() *MockComponentEcosystemInterface_AppsV1beta1_Call { + return &MockComponentEcosystemInterface_AppsV1beta1_Call{Call: _e.mock.On("AppsV1beta1")} +} + +func (_c *MockComponentEcosystemInterface_AppsV1beta1_Call) Run(run func()) *MockComponentEcosystemInterface_AppsV1beta1_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockComponentEcosystemInterface_AppsV1beta1_Call) Return(_a0 appsv1beta1.AppsV1beta1Interface) *MockComponentEcosystemInterface_AppsV1beta1_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockComponentEcosystemInterface_AppsV1beta1_Call) RunAndReturn(run func() appsv1beta1.AppsV1beta1Interface) *MockComponentEcosystemInterface_AppsV1beta1_Call { + _c.Call.Return(run) + return _c +} + +// AppsV1beta2 provides a mock function with given fields: +func (_m *MockComponentEcosystemInterface) AppsV1beta2() v1beta2.AppsV1beta2Interface { + ret := _m.Called() + + var r0 v1beta2.AppsV1beta2Interface + if rf, ok := ret.Get(0).(func() v1beta2.AppsV1beta2Interface); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(v1beta2.AppsV1beta2Interface) + } + } + + return r0 +} + +// MockComponentEcosystemInterface_AppsV1beta2_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AppsV1beta2' +type MockComponentEcosystemInterface_AppsV1beta2_Call struct { + *mock.Call +} + +// AppsV1beta2 is a helper method to define mock.On call +func (_e *MockComponentEcosystemInterface_Expecter) AppsV1beta2() *MockComponentEcosystemInterface_AppsV1beta2_Call { + return &MockComponentEcosystemInterface_AppsV1beta2_Call{Call: _e.mock.On("AppsV1beta2")} +} + +func (_c *MockComponentEcosystemInterface_AppsV1beta2_Call) Run(run func()) *MockComponentEcosystemInterface_AppsV1beta2_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockComponentEcosystemInterface_AppsV1beta2_Call) Return(_a0 v1beta2.AppsV1beta2Interface) *MockComponentEcosystemInterface_AppsV1beta2_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockComponentEcosystemInterface_AppsV1beta2_Call) RunAndReturn(run func() v1beta2.AppsV1beta2Interface) *MockComponentEcosystemInterface_AppsV1beta2_Call { + _c.Call.Return(run) + return _c +} + +// AuthenticationV1 provides a mock function with given fields: +func (_m *MockComponentEcosystemInterface) AuthenticationV1() authenticationv1.AuthenticationV1Interface { + ret := _m.Called() + + var r0 authenticationv1.AuthenticationV1Interface + if rf, ok := ret.Get(0).(func() authenticationv1.AuthenticationV1Interface); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(authenticationv1.AuthenticationV1Interface) + } + } + + return r0 +} + +// MockComponentEcosystemInterface_AuthenticationV1_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AuthenticationV1' +type MockComponentEcosystemInterface_AuthenticationV1_Call struct { + *mock.Call +} + +// AuthenticationV1 is a helper method to define mock.On call +func (_e *MockComponentEcosystemInterface_Expecter) AuthenticationV1() *MockComponentEcosystemInterface_AuthenticationV1_Call { + return &MockComponentEcosystemInterface_AuthenticationV1_Call{Call: _e.mock.On("AuthenticationV1")} +} + +func (_c *MockComponentEcosystemInterface_AuthenticationV1_Call) Run(run func()) *MockComponentEcosystemInterface_AuthenticationV1_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockComponentEcosystemInterface_AuthenticationV1_Call) Return(_a0 authenticationv1.AuthenticationV1Interface) *MockComponentEcosystemInterface_AuthenticationV1_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockComponentEcosystemInterface_AuthenticationV1_Call) RunAndReturn(run func() authenticationv1.AuthenticationV1Interface) *MockComponentEcosystemInterface_AuthenticationV1_Call { + _c.Call.Return(run) + return _c +} + +// AuthenticationV1alpha1 provides a mock function with given fields: +func (_m *MockComponentEcosystemInterface) AuthenticationV1alpha1() authenticationv1alpha1.AuthenticationV1alpha1Interface { + ret := _m.Called() + + var r0 authenticationv1alpha1.AuthenticationV1alpha1Interface + if rf, ok := ret.Get(0).(func() authenticationv1alpha1.AuthenticationV1alpha1Interface); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(authenticationv1alpha1.AuthenticationV1alpha1Interface) + } + } + + return r0 +} + +// MockComponentEcosystemInterface_AuthenticationV1alpha1_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AuthenticationV1alpha1' +type MockComponentEcosystemInterface_AuthenticationV1alpha1_Call struct { + *mock.Call +} + +// AuthenticationV1alpha1 is a helper method to define mock.On call +func (_e *MockComponentEcosystemInterface_Expecter) AuthenticationV1alpha1() *MockComponentEcosystemInterface_AuthenticationV1alpha1_Call { + return &MockComponentEcosystemInterface_AuthenticationV1alpha1_Call{Call: _e.mock.On("AuthenticationV1alpha1")} +} + +func (_c *MockComponentEcosystemInterface_AuthenticationV1alpha1_Call) Run(run func()) *MockComponentEcosystemInterface_AuthenticationV1alpha1_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockComponentEcosystemInterface_AuthenticationV1alpha1_Call) Return(_a0 authenticationv1alpha1.AuthenticationV1alpha1Interface) *MockComponentEcosystemInterface_AuthenticationV1alpha1_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockComponentEcosystemInterface_AuthenticationV1alpha1_Call) RunAndReturn(run func() authenticationv1alpha1.AuthenticationV1alpha1Interface) *MockComponentEcosystemInterface_AuthenticationV1alpha1_Call { + _c.Call.Return(run) + return _c +} + +// AuthenticationV1beta1 provides a mock function with given fields: +func (_m *MockComponentEcosystemInterface) AuthenticationV1beta1() authenticationv1beta1.AuthenticationV1beta1Interface { + ret := _m.Called() + + var r0 authenticationv1beta1.AuthenticationV1beta1Interface + if rf, ok := ret.Get(0).(func() authenticationv1beta1.AuthenticationV1beta1Interface); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(authenticationv1beta1.AuthenticationV1beta1Interface) + } + } + + return r0 +} + +// MockComponentEcosystemInterface_AuthenticationV1beta1_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AuthenticationV1beta1' +type MockComponentEcosystemInterface_AuthenticationV1beta1_Call struct { + *mock.Call +} + +// AuthenticationV1beta1 is a helper method to define mock.On call +func (_e *MockComponentEcosystemInterface_Expecter) AuthenticationV1beta1() *MockComponentEcosystemInterface_AuthenticationV1beta1_Call { + return &MockComponentEcosystemInterface_AuthenticationV1beta1_Call{Call: _e.mock.On("AuthenticationV1beta1")} +} + +func (_c *MockComponentEcosystemInterface_AuthenticationV1beta1_Call) Run(run func()) *MockComponentEcosystemInterface_AuthenticationV1beta1_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockComponentEcosystemInterface_AuthenticationV1beta1_Call) Return(_a0 authenticationv1beta1.AuthenticationV1beta1Interface) *MockComponentEcosystemInterface_AuthenticationV1beta1_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockComponentEcosystemInterface_AuthenticationV1beta1_Call) RunAndReturn(run func() authenticationv1beta1.AuthenticationV1beta1Interface) *MockComponentEcosystemInterface_AuthenticationV1beta1_Call { + _c.Call.Return(run) + return _c +} + +// AuthorizationV1 provides a mock function with given fields: +func (_m *MockComponentEcosystemInterface) AuthorizationV1() authorizationv1.AuthorizationV1Interface { + ret := _m.Called() + + var r0 authorizationv1.AuthorizationV1Interface + if rf, ok := ret.Get(0).(func() authorizationv1.AuthorizationV1Interface); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(authorizationv1.AuthorizationV1Interface) + } + } + + return r0 +} + +// MockComponentEcosystemInterface_AuthorizationV1_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AuthorizationV1' +type MockComponentEcosystemInterface_AuthorizationV1_Call struct { + *mock.Call +} + +// AuthorizationV1 is a helper method to define mock.On call +func (_e *MockComponentEcosystemInterface_Expecter) AuthorizationV1() *MockComponentEcosystemInterface_AuthorizationV1_Call { + return &MockComponentEcosystemInterface_AuthorizationV1_Call{Call: _e.mock.On("AuthorizationV1")} +} + +func (_c *MockComponentEcosystemInterface_AuthorizationV1_Call) Run(run func()) *MockComponentEcosystemInterface_AuthorizationV1_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockComponentEcosystemInterface_AuthorizationV1_Call) Return(_a0 authorizationv1.AuthorizationV1Interface) *MockComponentEcosystemInterface_AuthorizationV1_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockComponentEcosystemInterface_AuthorizationV1_Call) RunAndReturn(run func() authorizationv1.AuthorizationV1Interface) *MockComponentEcosystemInterface_AuthorizationV1_Call { + _c.Call.Return(run) + return _c +} + +// AuthorizationV1beta1 provides a mock function with given fields: +func (_m *MockComponentEcosystemInterface) AuthorizationV1beta1() authorizationv1beta1.AuthorizationV1beta1Interface { + ret := _m.Called() + + var r0 authorizationv1beta1.AuthorizationV1beta1Interface + if rf, ok := ret.Get(0).(func() authorizationv1beta1.AuthorizationV1beta1Interface); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(authorizationv1beta1.AuthorizationV1beta1Interface) + } + } + + return r0 +} + +// MockComponentEcosystemInterface_AuthorizationV1beta1_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AuthorizationV1beta1' +type MockComponentEcosystemInterface_AuthorizationV1beta1_Call struct { + *mock.Call +} + +// AuthorizationV1beta1 is a helper method to define mock.On call +func (_e *MockComponentEcosystemInterface_Expecter) AuthorizationV1beta1() *MockComponentEcosystemInterface_AuthorizationV1beta1_Call { + return &MockComponentEcosystemInterface_AuthorizationV1beta1_Call{Call: _e.mock.On("AuthorizationV1beta1")} +} + +func (_c *MockComponentEcosystemInterface_AuthorizationV1beta1_Call) Run(run func()) *MockComponentEcosystemInterface_AuthorizationV1beta1_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockComponentEcosystemInterface_AuthorizationV1beta1_Call) Return(_a0 authorizationv1beta1.AuthorizationV1beta1Interface) *MockComponentEcosystemInterface_AuthorizationV1beta1_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockComponentEcosystemInterface_AuthorizationV1beta1_Call) RunAndReturn(run func() authorizationv1beta1.AuthorizationV1beta1Interface) *MockComponentEcosystemInterface_AuthorizationV1beta1_Call { + _c.Call.Return(run) + return _c +} + +// AutoscalingV1 provides a mock function with given fields: +func (_m *MockComponentEcosystemInterface) AutoscalingV1() autoscalingv1.AutoscalingV1Interface { + ret := _m.Called() + + var r0 autoscalingv1.AutoscalingV1Interface + if rf, ok := ret.Get(0).(func() autoscalingv1.AutoscalingV1Interface); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(autoscalingv1.AutoscalingV1Interface) + } + } + + return r0 +} + +// MockComponentEcosystemInterface_AutoscalingV1_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AutoscalingV1' +type MockComponentEcosystemInterface_AutoscalingV1_Call struct { + *mock.Call +} + +// AutoscalingV1 is a helper method to define mock.On call +func (_e *MockComponentEcosystemInterface_Expecter) AutoscalingV1() *MockComponentEcosystemInterface_AutoscalingV1_Call { + return &MockComponentEcosystemInterface_AutoscalingV1_Call{Call: _e.mock.On("AutoscalingV1")} +} + +func (_c *MockComponentEcosystemInterface_AutoscalingV1_Call) Run(run func()) *MockComponentEcosystemInterface_AutoscalingV1_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockComponentEcosystemInterface_AutoscalingV1_Call) Return(_a0 autoscalingv1.AutoscalingV1Interface) *MockComponentEcosystemInterface_AutoscalingV1_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockComponentEcosystemInterface_AutoscalingV1_Call) RunAndReturn(run func() autoscalingv1.AutoscalingV1Interface) *MockComponentEcosystemInterface_AutoscalingV1_Call { + _c.Call.Return(run) + return _c +} + +// AutoscalingV2 provides a mock function with given fields: +func (_m *MockComponentEcosystemInterface) AutoscalingV2() v2.AutoscalingV2Interface { + ret := _m.Called() + + var r0 v2.AutoscalingV2Interface + if rf, ok := ret.Get(0).(func() v2.AutoscalingV2Interface); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(v2.AutoscalingV2Interface) + } + } + + return r0 +} + +// MockComponentEcosystemInterface_AutoscalingV2_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AutoscalingV2' +type MockComponentEcosystemInterface_AutoscalingV2_Call struct { + *mock.Call +} + +// AutoscalingV2 is a helper method to define mock.On call +func (_e *MockComponentEcosystemInterface_Expecter) AutoscalingV2() *MockComponentEcosystemInterface_AutoscalingV2_Call { + return &MockComponentEcosystemInterface_AutoscalingV2_Call{Call: _e.mock.On("AutoscalingV2")} +} + +func (_c *MockComponentEcosystemInterface_AutoscalingV2_Call) Run(run func()) *MockComponentEcosystemInterface_AutoscalingV2_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockComponentEcosystemInterface_AutoscalingV2_Call) Return(_a0 v2.AutoscalingV2Interface) *MockComponentEcosystemInterface_AutoscalingV2_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockComponentEcosystemInterface_AutoscalingV2_Call) RunAndReturn(run func() v2.AutoscalingV2Interface) *MockComponentEcosystemInterface_AutoscalingV2_Call { + _c.Call.Return(run) + return _c +} + +// AutoscalingV2beta1 provides a mock function with given fields: +func (_m *MockComponentEcosystemInterface) AutoscalingV2beta1() v2beta1.AutoscalingV2beta1Interface { + ret := _m.Called() + + var r0 v2beta1.AutoscalingV2beta1Interface + if rf, ok := ret.Get(0).(func() v2beta1.AutoscalingV2beta1Interface); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(v2beta1.AutoscalingV2beta1Interface) + } + } + + return r0 +} + +// MockComponentEcosystemInterface_AutoscalingV2beta1_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AutoscalingV2beta1' +type MockComponentEcosystemInterface_AutoscalingV2beta1_Call struct { + *mock.Call +} + +// AutoscalingV2beta1 is a helper method to define mock.On call +func (_e *MockComponentEcosystemInterface_Expecter) AutoscalingV2beta1() *MockComponentEcosystemInterface_AutoscalingV2beta1_Call { + return &MockComponentEcosystemInterface_AutoscalingV2beta1_Call{Call: _e.mock.On("AutoscalingV2beta1")} +} + +func (_c *MockComponentEcosystemInterface_AutoscalingV2beta1_Call) Run(run func()) *MockComponentEcosystemInterface_AutoscalingV2beta1_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockComponentEcosystemInterface_AutoscalingV2beta1_Call) Return(_a0 v2beta1.AutoscalingV2beta1Interface) *MockComponentEcosystemInterface_AutoscalingV2beta1_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockComponentEcosystemInterface_AutoscalingV2beta1_Call) RunAndReturn(run func() v2beta1.AutoscalingV2beta1Interface) *MockComponentEcosystemInterface_AutoscalingV2beta1_Call { + _c.Call.Return(run) + return _c +} + +// AutoscalingV2beta2 provides a mock function with given fields: +func (_m *MockComponentEcosystemInterface) AutoscalingV2beta2() v2beta2.AutoscalingV2beta2Interface { + ret := _m.Called() + + var r0 v2beta2.AutoscalingV2beta2Interface + if rf, ok := ret.Get(0).(func() v2beta2.AutoscalingV2beta2Interface); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(v2beta2.AutoscalingV2beta2Interface) + } + } + + return r0 +} + +// MockComponentEcosystemInterface_AutoscalingV2beta2_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AutoscalingV2beta2' +type MockComponentEcosystemInterface_AutoscalingV2beta2_Call struct { + *mock.Call +} + +// AutoscalingV2beta2 is a helper method to define mock.On call +func (_e *MockComponentEcosystemInterface_Expecter) AutoscalingV2beta2() *MockComponentEcosystemInterface_AutoscalingV2beta2_Call { + return &MockComponentEcosystemInterface_AutoscalingV2beta2_Call{Call: _e.mock.On("AutoscalingV2beta2")} +} + +func (_c *MockComponentEcosystemInterface_AutoscalingV2beta2_Call) Run(run func()) *MockComponentEcosystemInterface_AutoscalingV2beta2_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockComponentEcosystemInterface_AutoscalingV2beta2_Call) Return(_a0 v2beta2.AutoscalingV2beta2Interface) *MockComponentEcosystemInterface_AutoscalingV2beta2_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockComponentEcosystemInterface_AutoscalingV2beta2_Call) RunAndReturn(run func() v2beta2.AutoscalingV2beta2Interface) *MockComponentEcosystemInterface_AutoscalingV2beta2_Call { + _c.Call.Return(run) + return _c +} + +// BatchV1 provides a mock function with given fields: +func (_m *MockComponentEcosystemInterface) BatchV1() batchv1.BatchV1Interface { + ret := _m.Called() + + var r0 batchv1.BatchV1Interface + if rf, ok := ret.Get(0).(func() batchv1.BatchV1Interface); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(batchv1.BatchV1Interface) + } + } + + return r0 +} + +// MockComponentEcosystemInterface_BatchV1_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'BatchV1' +type MockComponentEcosystemInterface_BatchV1_Call struct { + *mock.Call +} + +// BatchV1 is a helper method to define mock.On call +func (_e *MockComponentEcosystemInterface_Expecter) BatchV1() *MockComponentEcosystemInterface_BatchV1_Call { + return &MockComponentEcosystemInterface_BatchV1_Call{Call: _e.mock.On("BatchV1")} +} + +func (_c *MockComponentEcosystemInterface_BatchV1_Call) Run(run func()) *MockComponentEcosystemInterface_BatchV1_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockComponentEcosystemInterface_BatchV1_Call) Return(_a0 batchv1.BatchV1Interface) *MockComponentEcosystemInterface_BatchV1_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockComponentEcosystemInterface_BatchV1_Call) RunAndReturn(run func() batchv1.BatchV1Interface) *MockComponentEcosystemInterface_BatchV1_Call { + _c.Call.Return(run) + return _c +} + +// BatchV1beta1 provides a mock function with given fields: +func (_m *MockComponentEcosystemInterface) BatchV1beta1() batchv1beta1.BatchV1beta1Interface { + ret := _m.Called() + + var r0 batchv1beta1.BatchV1beta1Interface + if rf, ok := ret.Get(0).(func() batchv1beta1.BatchV1beta1Interface); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(batchv1beta1.BatchV1beta1Interface) + } + } + + return r0 +} + +// MockComponentEcosystemInterface_BatchV1beta1_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'BatchV1beta1' +type MockComponentEcosystemInterface_BatchV1beta1_Call struct { + *mock.Call +} + +// BatchV1beta1 is a helper method to define mock.On call +func (_e *MockComponentEcosystemInterface_Expecter) BatchV1beta1() *MockComponentEcosystemInterface_BatchV1beta1_Call { + return &MockComponentEcosystemInterface_BatchV1beta1_Call{Call: _e.mock.On("BatchV1beta1")} +} + +func (_c *MockComponentEcosystemInterface_BatchV1beta1_Call) Run(run func()) *MockComponentEcosystemInterface_BatchV1beta1_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockComponentEcosystemInterface_BatchV1beta1_Call) Return(_a0 batchv1beta1.BatchV1beta1Interface) *MockComponentEcosystemInterface_BatchV1beta1_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockComponentEcosystemInterface_BatchV1beta1_Call) RunAndReturn(run func() batchv1beta1.BatchV1beta1Interface) *MockComponentEcosystemInterface_BatchV1beta1_Call { + _c.Call.Return(run) + return _c +} + +// CertificatesV1 provides a mock function with given fields: +func (_m *MockComponentEcosystemInterface) CertificatesV1() certificatesv1.CertificatesV1Interface { + ret := _m.Called() + + var r0 certificatesv1.CertificatesV1Interface + if rf, ok := ret.Get(0).(func() certificatesv1.CertificatesV1Interface); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(certificatesv1.CertificatesV1Interface) + } + } + + return r0 +} + +// MockComponentEcosystemInterface_CertificatesV1_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CertificatesV1' +type MockComponentEcosystemInterface_CertificatesV1_Call struct { + *mock.Call +} + +// CertificatesV1 is a helper method to define mock.On call +func (_e *MockComponentEcosystemInterface_Expecter) CertificatesV1() *MockComponentEcosystemInterface_CertificatesV1_Call { + return &MockComponentEcosystemInterface_CertificatesV1_Call{Call: _e.mock.On("CertificatesV1")} +} + +func (_c *MockComponentEcosystemInterface_CertificatesV1_Call) Run(run func()) *MockComponentEcosystemInterface_CertificatesV1_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockComponentEcosystemInterface_CertificatesV1_Call) Return(_a0 certificatesv1.CertificatesV1Interface) *MockComponentEcosystemInterface_CertificatesV1_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockComponentEcosystemInterface_CertificatesV1_Call) RunAndReturn(run func() certificatesv1.CertificatesV1Interface) *MockComponentEcosystemInterface_CertificatesV1_Call { + _c.Call.Return(run) + return _c +} + +// CertificatesV1alpha1 provides a mock function with given fields: +func (_m *MockComponentEcosystemInterface) CertificatesV1alpha1() certificatesv1alpha1.CertificatesV1alpha1Interface { + ret := _m.Called() + + var r0 certificatesv1alpha1.CertificatesV1alpha1Interface + if rf, ok := ret.Get(0).(func() certificatesv1alpha1.CertificatesV1alpha1Interface); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(certificatesv1alpha1.CertificatesV1alpha1Interface) + } + } + + return r0 +} + +// MockComponentEcosystemInterface_CertificatesV1alpha1_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CertificatesV1alpha1' +type MockComponentEcosystemInterface_CertificatesV1alpha1_Call struct { + *mock.Call +} + +// CertificatesV1alpha1 is a helper method to define mock.On call +func (_e *MockComponentEcosystemInterface_Expecter) CertificatesV1alpha1() *MockComponentEcosystemInterface_CertificatesV1alpha1_Call { + return &MockComponentEcosystemInterface_CertificatesV1alpha1_Call{Call: _e.mock.On("CertificatesV1alpha1")} +} + +func (_c *MockComponentEcosystemInterface_CertificatesV1alpha1_Call) Run(run func()) *MockComponentEcosystemInterface_CertificatesV1alpha1_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockComponentEcosystemInterface_CertificatesV1alpha1_Call) Return(_a0 certificatesv1alpha1.CertificatesV1alpha1Interface) *MockComponentEcosystemInterface_CertificatesV1alpha1_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockComponentEcosystemInterface_CertificatesV1alpha1_Call) RunAndReturn(run func() certificatesv1alpha1.CertificatesV1alpha1Interface) *MockComponentEcosystemInterface_CertificatesV1alpha1_Call { + _c.Call.Return(run) + return _c +} + +// CertificatesV1beta1 provides a mock function with given fields: +func (_m *MockComponentEcosystemInterface) CertificatesV1beta1() certificatesv1beta1.CertificatesV1beta1Interface { + ret := _m.Called() + + var r0 certificatesv1beta1.CertificatesV1beta1Interface + if rf, ok := ret.Get(0).(func() certificatesv1beta1.CertificatesV1beta1Interface); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(certificatesv1beta1.CertificatesV1beta1Interface) + } + } + + return r0 +} + +// MockComponentEcosystemInterface_CertificatesV1beta1_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CertificatesV1beta1' +type MockComponentEcosystemInterface_CertificatesV1beta1_Call struct { + *mock.Call +} + +// CertificatesV1beta1 is a helper method to define mock.On call +func (_e *MockComponentEcosystemInterface_Expecter) CertificatesV1beta1() *MockComponentEcosystemInterface_CertificatesV1beta1_Call { + return &MockComponentEcosystemInterface_CertificatesV1beta1_Call{Call: _e.mock.On("CertificatesV1beta1")} +} + +func (_c *MockComponentEcosystemInterface_CertificatesV1beta1_Call) Run(run func()) *MockComponentEcosystemInterface_CertificatesV1beta1_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockComponentEcosystemInterface_CertificatesV1beta1_Call) Return(_a0 certificatesv1beta1.CertificatesV1beta1Interface) *MockComponentEcosystemInterface_CertificatesV1beta1_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockComponentEcosystemInterface_CertificatesV1beta1_Call) RunAndReturn(run func() certificatesv1beta1.CertificatesV1beta1Interface) *MockComponentEcosystemInterface_CertificatesV1beta1_Call { + _c.Call.Return(run) + return _c +} + +// ComponentV1Alpha1 provides a mock function with given fields: +func (_m *MockComponentEcosystemInterface) ComponentV1Alpha1() ComponentV1Alpha1Interface { + ret := _m.Called() + + var r0 ComponentV1Alpha1Interface + if rf, ok := ret.Get(0).(func() ComponentV1Alpha1Interface); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(ComponentV1Alpha1Interface) + } + } + + return r0 +} + +// MockComponentEcosystemInterface_ComponentV1Alpha1_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ComponentV1Alpha1' +type MockComponentEcosystemInterface_ComponentV1Alpha1_Call struct { + *mock.Call +} + +// ComponentV1Alpha1 is a helper method to define mock.On call +func (_e *MockComponentEcosystemInterface_Expecter) ComponentV1Alpha1() *MockComponentEcosystemInterface_ComponentV1Alpha1_Call { + return &MockComponentEcosystemInterface_ComponentV1Alpha1_Call{Call: _e.mock.On("ComponentV1Alpha1")} +} + +func (_c *MockComponentEcosystemInterface_ComponentV1Alpha1_Call) Run(run func()) *MockComponentEcosystemInterface_ComponentV1Alpha1_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockComponentEcosystemInterface_ComponentV1Alpha1_Call) Return(_a0 ComponentV1Alpha1Interface) *MockComponentEcosystemInterface_ComponentV1Alpha1_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockComponentEcosystemInterface_ComponentV1Alpha1_Call) RunAndReturn(run func() ComponentV1Alpha1Interface) *MockComponentEcosystemInterface_ComponentV1Alpha1_Call { + _c.Call.Return(run) + return _c +} + +// CoordinationV1 provides a mock function with given fields: +func (_m *MockComponentEcosystemInterface) CoordinationV1() coordinationv1.CoordinationV1Interface { + ret := _m.Called() + + var r0 coordinationv1.CoordinationV1Interface + if rf, ok := ret.Get(0).(func() coordinationv1.CoordinationV1Interface); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(coordinationv1.CoordinationV1Interface) + } + } + + return r0 +} + +// MockComponentEcosystemInterface_CoordinationV1_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CoordinationV1' +type MockComponentEcosystemInterface_CoordinationV1_Call struct { + *mock.Call +} + +// CoordinationV1 is a helper method to define mock.On call +func (_e *MockComponentEcosystemInterface_Expecter) CoordinationV1() *MockComponentEcosystemInterface_CoordinationV1_Call { + return &MockComponentEcosystemInterface_CoordinationV1_Call{Call: _e.mock.On("CoordinationV1")} +} + +func (_c *MockComponentEcosystemInterface_CoordinationV1_Call) Run(run func()) *MockComponentEcosystemInterface_CoordinationV1_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockComponentEcosystemInterface_CoordinationV1_Call) Return(_a0 coordinationv1.CoordinationV1Interface) *MockComponentEcosystemInterface_CoordinationV1_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockComponentEcosystemInterface_CoordinationV1_Call) RunAndReturn(run func() coordinationv1.CoordinationV1Interface) *MockComponentEcosystemInterface_CoordinationV1_Call { + _c.Call.Return(run) + return _c +} + +// CoordinationV1beta1 provides a mock function with given fields: +func (_m *MockComponentEcosystemInterface) CoordinationV1beta1() coordinationv1beta1.CoordinationV1beta1Interface { + ret := _m.Called() + + var r0 coordinationv1beta1.CoordinationV1beta1Interface + if rf, ok := ret.Get(0).(func() coordinationv1beta1.CoordinationV1beta1Interface); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(coordinationv1beta1.CoordinationV1beta1Interface) + } + } + + return r0 +} + +// MockComponentEcosystemInterface_CoordinationV1beta1_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CoordinationV1beta1' +type MockComponentEcosystemInterface_CoordinationV1beta1_Call struct { + *mock.Call +} + +// CoordinationV1beta1 is a helper method to define mock.On call +func (_e *MockComponentEcosystemInterface_Expecter) CoordinationV1beta1() *MockComponentEcosystemInterface_CoordinationV1beta1_Call { + return &MockComponentEcosystemInterface_CoordinationV1beta1_Call{Call: _e.mock.On("CoordinationV1beta1")} +} + +func (_c *MockComponentEcosystemInterface_CoordinationV1beta1_Call) Run(run func()) *MockComponentEcosystemInterface_CoordinationV1beta1_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockComponentEcosystemInterface_CoordinationV1beta1_Call) Return(_a0 coordinationv1beta1.CoordinationV1beta1Interface) *MockComponentEcosystemInterface_CoordinationV1beta1_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockComponentEcosystemInterface_CoordinationV1beta1_Call) RunAndReturn(run func() coordinationv1beta1.CoordinationV1beta1Interface) *MockComponentEcosystemInterface_CoordinationV1beta1_Call { + _c.Call.Return(run) + return _c +} + +// CoreV1 provides a mock function with given fields: +func (_m *MockComponentEcosystemInterface) CoreV1() corev1.CoreV1Interface { + ret := _m.Called() + + var r0 corev1.CoreV1Interface + if rf, ok := ret.Get(0).(func() corev1.CoreV1Interface); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(corev1.CoreV1Interface) + } + } + + return r0 +} + +// MockComponentEcosystemInterface_CoreV1_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CoreV1' +type MockComponentEcosystemInterface_CoreV1_Call struct { + *mock.Call +} + +// CoreV1 is a helper method to define mock.On call +func (_e *MockComponentEcosystemInterface_Expecter) CoreV1() *MockComponentEcosystemInterface_CoreV1_Call { + return &MockComponentEcosystemInterface_CoreV1_Call{Call: _e.mock.On("CoreV1")} +} + +func (_c *MockComponentEcosystemInterface_CoreV1_Call) Run(run func()) *MockComponentEcosystemInterface_CoreV1_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockComponentEcosystemInterface_CoreV1_Call) Return(_a0 corev1.CoreV1Interface) *MockComponentEcosystemInterface_CoreV1_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockComponentEcosystemInterface_CoreV1_Call) RunAndReturn(run func() corev1.CoreV1Interface) *MockComponentEcosystemInterface_CoreV1_Call { + _c.Call.Return(run) + return _c +} + +// Discovery provides a mock function with given fields: +func (_m *MockComponentEcosystemInterface) Discovery() discovery.DiscoveryInterface { + ret := _m.Called() + + var r0 discovery.DiscoveryInterface + if rf, ok := ret.Get(0).(func() discovery.DiscoveryInterface); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(discovery.DiscoveryInterface) + } + } + + return r0 +} + +// MockComponentEcosystemInterface_Discovery_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Discovery' +type MockComponentEcosystemInterface_Discovery_Call struct { + *mock.Call +} + +// Discovery is a helper method to define mock.On call +func (_e *MockComponentEcosystemInterface_Expecter) Discovery() *MockComponentEcosystemInterface_Discovery_Call { + return &MockComponentEcosystemInterface_Discovery_Call{Call: _e.mock.On("Discovery")} +} + +func (_c *MockComponentEcosystemInterface_Discovery_Call) Run(run func()) *MockComponentEcosystemInterface_Discovery_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockComponentEcosystemInterface_Discovery_Call) Return(_a0 discovery.DiscoveryInterface) *MockComponentEcosystemInterface_Discovery_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockComponentEcosystemInterface_Discovery_Call) RunAndReturn(run func() discovery.DiscoveryInterface) *MockComponentEcosystemInterface_Discovery_Call { + _c.Call.Return(run) + return _c +} + +// DiscoveryV1 provides a mock function with given fields: +func (_m *MockComponentEcosystemInterface) DiscoveryV1() discoveryv1.DiscoveryV1Interface { + ret := _m.Called() + + var r0 discoveryv1.DiscoveryV1Interface + if rf, ok := ret.Get(0).(func() discoveryv1.DiscoveryV1Interface); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(discoveryv1.DiscoveryV1Interface) + } + } + + return r0 +} + +// MockComponentEcosystemInterface_DiscoveryV1_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DiscoveryV1' +type MockComponentEcosystemInterface_DiscoveryV1_Call struct { + *mock.Call +} + +// DiscoveryV1 is a helper method to define mock.On call +func (_e *MockComponentEcosystemInterface_Expecter) DiscoveryV1() *MockComponentEcosystemInterface_DiscoveryV1_Call { + return &MockComponentEcosystemInterface_DiscoveryV1_Call{Call: _e.mock.On("DiscoveryV1")} +} + +func (_c *MockComponentEcosystemInterface_DiscoveryV1_Call) Run(run func()) *MockComponentEcosystemInterface_DiscoveryV1_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockComponentEcosystemInterface_DiscoveryV1_Call) Return(_a0 discoveryv1.DiscoveryV1Interface) *MockComponentEcosystemInterface_DiscoveryV1_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockComponentEcosystemInterface_DiscoveryV1_Call) RunAndReturn(run func() discoveryv1.DiscoveryV1Interface) *MockComponentEcosystemInterface_DiscoveryV1_Call { + _c.Call.Return(run) + return _c +} + +// DiscoveryV1beta1 provides a mock function with given fields: +func (_m *MockComponentEcosystemInterface) DiscoveryV1beta1() discoveryv1beta1.DiscoveryV1beta1Interface { + ret := _m.Called() + + var r0 discoveryv1beta1.DiscoveryV1beta1Interface + if rf, ok := ret.Get(0).(func() discoveryv1beta1.DiscoveryV1beta1Interface); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(discoveryv1beta1.DiscoveryV1beta1Interface) + } + } + + return r0 +} + +// MockComponentEcosystemInterface_DiscoveryV1beta1_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DiscoveryV1beta1' +type MockComponentEcosystemInterface_DiscoveryV1beta1_Call struct { + *mock.Call +} + +// DiscoveryV1beta1 is a helper method to define mock.On call +func (_e *MockComponentEcosystemInterface_Expecter) DiscoveryV1beta1() *MockComponentEcosystemInterface_DiscoveryV1beta1_Call { + return &MockComponentEcosystemInterface_DiscoveryV1beta1_Call{Call: _e.mock.On("DiscoveryV1beta1")} +} + +func (_c *MockComponentEcosystemInterface_DiscoveryV1beta1_Call) Run(run func()) *MockComponentEcosystemInterface_DiscoveryV1beta1_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockComponentEcosystemInterface_DiscoveryV1beta1_Call) Return(_a0 discoveryv1beta1.DiscoveryV1beta1Interface) *MockComponentEcosystemInterface_DiscoveryV1beta1_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockComponentEcosystemInterface_DiscoveryV1beta1_Call) RunAndReturn(run func() discoveryv1beta1.DiscoveryV1beta1Interface) *MockComponentEcosystemInterface_DiscoveryV1beta1_Call { + _c.Call.Return(run) + return _c +} + +// EventsV1 provides a mock function with given fields: +func (_m *MockComponentEcosystemInterface) EventsV1() eventsv1.EventsV1Interface { + ret := _m.Called() + + var r0 eventsv1.EventsV1Interface + if rf, ok := ret.Get(0).(func() eventsv1.EventsV1Interface); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(eventsv1.EventsV1Interface) + } + } + + return r0 +} + +// MockComponentEcosystemInterface_EventsV1_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'EventsV1' +type MockComponentEcosystemInterface_EventsV1_Call struct { + *mock.Call +} + +// EventsV1 is a helper method to define mock.On call +func (_e *MockComponentEcosystemInterface_Expecter) EventsV1() *MockComponentEcosystemInterface_EventsV1_Call { + return &MockComponentEcosystemInterface_EventsV1_Call{Call: _e.mock.On("EventsV1")} +} + +func (_c *MockComponentEcosystemInterface_EventsV1_Call) Run(run func()) *MockComponentEcosystemInterface_EventsV1_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockComponentEcosystemInterface_EventsV1_Call) Return(_a0 eventsv1.EventsV1Interface) *MockComponentEcosystemInterface_EventsV1_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockComponentEcosystemInterface_EventsV1_Call) RunAndReturn(run func() eventsv1.EventsV1Interface) *MockComponentEcosystemInterface_EventsV1_Call { + _c.Call.Return(run) + return _c +} + +// EventsV1beta1 provides a mock function with given fields: +func (_m *MockComponentEcosystemInterface) EventsV1beta1() eventsv1beta1.EventsV1beta1Interface { + ret := _m.Called() + + var r0 eventsv1beta1.EventsV1beta1Interface + if rf, ok := ret.Get(0).(func() eventsv1beta1.EventsV1beta1Interface); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(eventsv1beta1.EventsV1beta1Interface) + } + } + + return r0 +} + +// MockComponentEcosystemInterface_EventsV1beta1_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'EventsV1beta1' +type MockComponentEcosystemInterface_EventsV1beta1_Call struct { + *mock.Call +} + +// EventsV1beta1 is a helper method to define mock.On call +func (_e *MockComponentEcosystemInterface_Expecter) EventsV1beta1() *MockComponentEcosystemInterface_EventsV1beta1_Call { + return &MockComponentEcosystemInterface_EventsV1beta1_Call{Call: _e.mock.On("EventsV1beta1")} +} + +func (_c *MockComponentEcosystemInterface_EventsV1beta1_Call) Run(run func()) *MockComponentEcosystemInterface_EventsV1beta1_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockComponentEcosystemInterface_EventsV1beta1_Call) Return(_a0 eventsv1beta1.EventsV1beta1Interface) *MockComponentEcosystemInterface_EventsV1beta1_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockComponentEcosystemInterface_EventsV1beta1_Call) RunAndReturn(run func() eventsv1beta1.EventsV1beta1Interface) *MockComponentEcosystemInterface_EventsV1beta1_Call { + _c.Call.Return(run) + return _c +} + +// ExtensionsV1beta1 provides a mock function with given fields: +func (_m *MockComponentEcosystemInterface) ExtensionsV1beta1() extensionsv1beta1.ExtensionsV1beta1Interface { + ret := _m.Called() + + var r0 extensionsv1beta1.ExtensionsV1beta1Interface + if rf, ok := ret.Get(0).(func() extensionsv1beta1.ExtensionsV1beta1Interface); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(extensionsv1beta1.ExtensionsV1beta1Interface) + } + } + + return r0 +} + +// MockComponentEcosystemInterface_ExtensionsV1beta1_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ExtensionsV1beta1' +type MockComponentEcosystemInterface_ExtensionsV1beta1_Call struct { + *mock.Call +} + +// ExtensionsV1beta1 is a helper method to define mock.On call +func (_e *MockComponentEcosystemInterface_Expecter) ExtensionsV1beta1() *MockComponentEcosystemInterface_ExtensionsV1beta1_Call { + return &MockComponentEcosystemInterface_ExtensionsV1beta1_Call{Call: _e.mock.On("ExtensionsV1beta1")} +} + +func (_c *MockComponentEcosystemInterface_ExtensionsV1beta1_Call) Run(run func()) *MockComponentEcosystemInterface_ExtensionsV1beta1_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockComponentEcosystemInterface_ExtensionsV1beta1_Call) Return(_a0 extensionsv1beta1.ExtensionsV1beta1Interface) *MockComponentEcosystemInterface_ExtensionsV1beta1_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockComponentEcosystemInterface_ExtensionsV1beta1_Call) RunAndReturn(run func() extensionsv1beta1.ExtensionsV1beta1Interface) *MockComponentEcosystemInterface_ExtensionsV1beta1_Call { + _c.Call.Return(run) + return _c +} + +// FlowcontrolV1alpha1 provides a mock function with given fields: +func (_m *MockComponentEcosystemInterface) FlowcontrolV1alpha1() flowcontrolv1alpha1.FlowcontrolV1alpha1Interface { + ret := _m.Called() + + var r0 flowcontrolv1alpha1.FlowcontrolV1alpha1Interface + if rf, ok := ret.Get(0).(func() flowcontrolv1alpha1.FlowcontrolV1alpha1Interface); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(flowcontrolv1alpha1.FlowcontrolV1alpha1Interface) + } + } + + return r0 +} + +// MockComponentEcosystemInterface_FlowcontrolV1alpha1_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FlowcontrolV1alpha1' +type MockComponentEcosystemInterface_FlowcontrolV1alpha1_Call struct { + *mock.Call +} + +// FlowcontrolV1alpha1 is a helper method to define mock.On call +func (_e *MockComponentEcosystemInterface_Expecter) FlowcontrolV1alpha1() *MockComponentEcosystemInterface_FlowcontrolV1alpha1_Call { + return &MockComponentEcosystemInterface_FlowcontrolV1alpha1_Call{Call: _e.mock.On("FlowcontrolV1alpha1")} +} + +func (_c *MockComponentEcosystemInterface_FlowcontrolV1alpha1_Call) Run(run func()) *MockComponentEcosystemInterface_FlowcontrolV1alpha1_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockComponentEcosystemInterface_FlowcontrolV1alpha1_Call) Return(_a0 flowcontrolv1alpha1.FlowcontrolV1alpha1Interface) *MockComponentEcosystemInterface_FlowcontrolV1alpha1_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockComponentEcosystemInterface_FlowcontrolV1alpha1_Call) RunAndReturn(run func() flowcontrolv1alpha1.FlowcontrolV1alpha1Interface) *MockComponentEcosystemInterface_FlowcontrolV1alpha1_Call { + _c.Call.Return(run) + return _c +} + +// FlowcontrolV1beta1 provides a mock function with given fields: +func (_m *MockComponentEcosystemInterface) FlowcontrolV1beta1() flowcontrolv1beta1.FlowcontrolV1beta1Interface { + ret := _m.Called() + + var r0 flowcontrolv1beta1.FlowcontrolV1beta1Interface + if rf, ok := ret.Get(0).(func() flowcontrolv1beta1.FlowcontrolV1beta1Interface); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(flowcontrolv1beta1.FlowcontrolV1beta1Interface) + } + } + + return r0 +} + +// MockComponentEcosystemInterface_FlowcontrolV1beta1_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FlowcontrolV1beta1' +type MockComponentEcosystemInterface_FlowcontrolV1beta1_Call struct { + *mock.Call +} + +// FlowcontrolV1beta1 is a helper method to define mock.On call +func (_e *MockComponentEcosystemInterface_Expecter) FlowcontrolV1beta1() *MockComponentEcosystemInterface_FlowcontrolV1beta1_Call { + return &MockComponentEcosystemInterface_FlowcontrolV1beta1_Call{Call: _e.mock.On("FlowcontrolV1beta1")} +} + +func (_c *MockComponentEcosystemInterface_FlowcontrolV1beta1_Call) Run(run func()) *MockComponentEcosystemInterface_FlowcontrolV1beta1_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockComponentEcosystemInterface_FlowcontrolV1beta1_Call) Return(_a0 flowcontrolv1beta1.FlowcontrolV1beta1Interface) *MockComponentEcosystemInterface_FlowcontrolV1beta1_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockComponentEcosystemInterface_FlowcontrolV1beta1_Call) RunAndReturn(run func() flowcontrolv1beta1.FlowcontrolV1beta1Interface) *MockComponentEcosystemInterface_FlowcontrolV1beta1_Call { + _c.Call.Return(run) + return _c +} + +// FlowcontrolV1beta2 provides a mock function with given fields: +func (_m *MockComponentEcosystemInterface) FlowcontrolV1beta2() flowcontrolv1beta2.FlowcontrolV1beta2Interface { + ret := _m.Called() + + var r0 flowcontrolv1beta2.FlowcontrolV1beta2Interface + if rf, ok := ret.Get(0).(func() flowcontrolv1beta2.FlowcontrolV1beta2Interface); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(flowcontrolv1beta2.FlowcontrolV1beta2Interface) + } + } + + return r0 +} + +// MockComponentEcosystemInterface_FlowcontrolV1beta2_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FlowcontrolV1beta2' +type MockComponentEcosystemInterface_FlowcontrolV1beta2_Call struct { + *mock.Call +} + +// FlowcontrolV1beta2 is a helper method to define mock.On call +func (_e *MockComponentEcosystemInterface_Expecter) FlowcontrolV1beta2() *MockComponentEcosystemInterface_FlowcontrolV1beta2_Call { + return &MockComponentEcosystemInterface_FlowcontrolV1beta2_Call{Call: _e.mock.On("FlowcontrolV1beta2")} +} + +func (_c *MockComponentEcosystemInterface_FlowcontrolV1beta2_Call) Run(run func()) *MockComponentEcosystemInterface_FlowcontrolV1beta2_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockComponentEcosystemInterface_FlowcontrolV1beta2_Call) Return(_a0 flowcontrolv1beta2.FlowcontrolV1beta2Interface) *MockComponentEcosystemInterface_FlowcontrolV1beta2_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockComponentEcosystemInterface_FlowcontrolV1beta2_Call) RunAndReturn(run func() flowcontrolv1beta2.FlowcontrolV1beta2Interface) *MockComponentEcosystemInterface_FlowcontrolV1beta2_Call { + _c.Call.Return(run) + return _c +} + +// FlowcontrolV1beta3 provides a mock function with given fields: +func (_m *MockComponentEcosystemInterface) FlowcontrolV1beta3() v1beta3.FlowcontrolV1beta3Interface { + ret := _m.Called() + + var r0 v1beta3.FlowcontrolV1beta3Interface + if rf, ok := ret.Get(0).(func() v1beta3.FlowcontrolV1beta3Interface); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(v1beta3.FlowcontrolV1beta3Interface) + } + } + + return r0 +} + +// MockComponentEcosystemInterface_FlowcontrolV1beta3_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FlowcontrolV1beta3' +type MockComponentEcosystemInterface_FlowcontrolV1beta3_Call struct { + *mock.Call +} + +// FlowcontrolV1beta3 is a helper method to define mock.On call +func (_e *MockComponentEcosystemInterface_Expecter) FlowcontrolV1beta3() *MockComponentEcosystemInterface_FlowcontrolV1beta3_Call { + return &MockComponentEcosystemInterface_FlowcontrolV1beta3_Call{Call: _e.mock.On("FlowcontrolV1beta3")} +} + +func (_c *MockComponentEcosystemInterface_FlowcontrolV1beta3_Call) Run(run func()) *MockComponentEcosystemInterface_FlowcontrolV1beta3_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockComponentEcosystemInterface_FlowcontrolV1beta3_Call) Return(_a0 v1beta3.FlowcontrolV1beta3Interface) *MockComponentEcosystemInterface_FlowcontrolV1beta3_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockComponentEcosystemInterface_FlowcontrolV1beta3_Call) RunAndReturn(run func() v1beta3.FlowcontrolV1beta3Interface) *MockComponentEcosystemInterface_FlowcontrolV1beta3_Call { + _c.Call.Return(run) + return _c +} + +// InternalV1alpha1 provides a mock function with given fields: +func (_m *MockComponentEcosystemInterface) InternalV1alpha1() apiserverinternalv1alpha1.InternalV1alpha1Interface { + ret := _m.Called() + + var r0 apiserverinternalv1alpha1.InternalV1alpha1Interface + if rf, ok := ret.Get(0).(func() apiserverinternalv1alpha1.InternalV1alpha1Interface); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(apiserverinternalv1alpha1.InternalV1alpha1Interface) + } + } + + return r0 +} + +// MockComponentEcosystemInterface_InternalV1alpha1_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'InternalV1alpha1' +type MockComponentEcosystemInterface_InternalV1alpha1_Call struct { + *mock.Call +} + +// InternalV1alpha1 is a helper method to define mock.On call +func (_e *MockComponentEcosystemInterface_Expecter) InternalV1alpha1() *MockComponentEcosystemInterface_InternalV1alpha1_Call { + return &MockComponentEcosystemInterface_InternalV1alpha1_Call{Call: _e.mock.On("InternalV1alpha1")} +} + +func (_c *MockComponentEcosystemInterface_InternalV1alpha1_Call) Run(run func()) *MockComponentEcosystemInterface_InternalV1alpha1_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockComponentEcosystemInterface_InternalV1alpha1_Call) Return(_a0 apiserverinternalv1alpha1.InternalV1alpha1Interface) *MockComponentEcosystemInterface_InternalV1alpha1_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockComponentEcosystemInterface_InternalV1alpha1_Call) RunAndReturn(run func() apiserverinternalv1alpha1.InternalV1alpha1Interface) *MockComponentEcosystemInterface_InternalV1alpha1_Call { + _c.Call.Return(run) + return _c +} + +// NetworkingV1 provides a mock function with given fields: +func (_m *MockComponentEcosystemInterface) NetworkingV1() networkingv1.NetworkingV1Interface { + ret := _m.Called() + + var r0 networkingv1.NetworkingV1Interface + if rf, ok := ret.Get(0).(func() networkingv1.NetworkingV1Interface); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(networkingv1.NetworkingV1Interface) + } + } + + return r0 +} + +// MockComponentEcosystemInterface_NetworkingV1_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NetworkingV1' +type MockComponentEcosystemInterface_NetworkingV1_Call struct { + *mock.Call +} + +// NetworkingV1 is a helper method to define mock.On call +func (_e *MockComponentEcosystemInterface_Expecter) NetworkingV1() *MockComponentEcosystemInterface_NetworkingV1_Call { + return &MockComponentEcosystemInterface_NetworkingV1_Call{Call: _e.mock.On("NetworkingV1")} +} + +func (_c *MockComponentEcosystemInterface_NetworkingV1_Call) Run(run func()) *MockComponentEcosystemInterface_NetworkingV1_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockComponentEcosystemInterface_NetworkingV1_Call) Return(_a0 networkingv1.NetworkingV1Interface) *MockComponentEcosystemInterface_NetworkingV1_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockComponentEcosystemInterface_NetworkingV1_Call) RunAndReturn(run func() networkingv1.NetworkingV1Interface) *MockComponentEcosystemInterface_NetworkingV1_Call { + _c.Call.Return(run) + return _c +} + +// NetworkingV1alpha1 provides a mock function with given fields: +func (_m *MockComponentEcosystemInterface) NetworkingV1alpha1() networkingv1alpha1.NetworkingV1alpha1Interface { + ret := _m.Called() + + var r0 networkingv1alpha1.NetworkingV1alpha1Interface + if rf, ok := ret.Get(0).(func() networkingv1alpha1.NetworkingV1alpha1Interface); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(networkingv1alpha1.NetworkingV1alpha1Interface) + } + } + + return r0 +} + +// MockComponentEcosystemInterface_NetworkingV1alpha1_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NetworkingV1alpha1' +type MockComponentEcosystemInterface_NetworkingV1alpha1_Call struct { + *mock.Call +} + +// NetworkingV1alpha1 is a helper method to define mock.On call +func (_e *MockComponentEcosystemInterface_Expecter) NetworkingV1alpha1() *MockComponentEcosystemInterface_NetworkingV1alpha1_Call { + return &MockComponentEcosystemInterface_NetworkingV1alpha1_Call{Call: _e.mock.On("NetworkingV1alpha1")} +} + +func (_c *MockComponentEcosystemInterface_NetworkingV1alpha1_Call) Run(run func()) *MockComponentEcosystemInterface_NetworkingV1alpha1_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockComponentEcosystemInterface_NetworkingV1alpha1_Call) Return(_a0 networkingv1alpha1.NetworkingV1alpha1Interface) *MockComponentEcosystemInterface_NetworkingV1alpha1_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockComponentEcosystemInterface_NetworkingV1alpha1_Call) RunAndReturn(run func() networkingv1alpha1.NetworkingV1alpha1Interface) *MockComponentEcosystemInterface_NetworkingV1alpha1_Call { + _c.Call.Return(run) + return _c +} + +// NetworkingV1beta1 provides a mock function with given fields: +func (_m *MockComponentEcosystemInterface) NetworkingV1beta1() networkingv1beta1.NetworkingV1beta1Interface { + ret := _m.Called() + + var r0 networkingv1beta1.NetworkingV1beta1Interface + if rf, ok := ret.Get(0).(func() networkingv1beta1.NetworkingV1beta1Interface); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(networkingv1beta1.NetworkingV1beta1Interface) + } + } + + return r0 +} + +// MockComponentEcosystemInterface_NetworkingV1beta1_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NetworkingV1beta1' +type MockComponentEcosystemInterface_NetworkingV1beta1_Call struct { + *mock.Call +} + +// NetworkingV1beta1 is a helper method to define mock.On call +func (_e *MockComponentEcosystemInterface_Expecter) NetworkingV1beta1() *MockComponentEcosystemInterface_NetworkingV1beta1_Call { + return &MockComponentEcosystemInterface_NetworkingV1beta1_Call{Call: _e.mock.On("NetworkingV1beta1")} +} + +func (_c *MockComponentEcosystemInterface_NetworkingV1beta1_Call) Run(run func()) *MockComponentEcosystemInterface_NetworkingV1beta1_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockComponentEcosystemInterface_NetworkingV1beta1_Call) Return(_a0 networkingv1beta1.NetworkingV1beta1Interface) *MockComponentEcosystemInterface_NetworkingV1beta1_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockComponentEcosystemInterface_NetworkingV1beta1_Call) RunAndReturn(run func() networkingv1beta1.NetworkingV1beta1Interface) *MockComponentEcosystemInterface_NetworkingV1beta1_Call { + _c.Call.Return(run) + return _c +} + +// NodeV1 provides a mock function with given fields: +func (_m *MockComponentEcosystemInterface) NodeV1() nodev1.NodeV1Interface { + ret := _m.Called() + + var r0 nodev1.NodeV1Interface + if rf, ok := ret.Get(0).(func() nodev1.NodeV1Interface); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(nodev1.NodeV1Interface) + } + } + + return r0 +} + +// MockComponentEcosystemInterface_NodeV1_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NodeV1' +type MockComponentEcosystemInterface_NodeV1_Call struct { + *mock.Call +} + +// NodeV1 is a helper method to define mock.On call +func (_e *MockComponentEcosystemInterface_Expecter) NodeV1() *MockComponentEcosystemInterface_NodeV1_Call { + return &MockComponentEcosystemInterface_NodeV1_Call{Call: _e.mock.On("NodeV1")} +} + +func (_c *MockComponentEcosystemInterface_NodeV1_Call) Run(run func()) *MockComponentEcosystemInterface_NodeV1_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockComponentEcosystemInterface_NodeV1_Call) Return(_a0 nodev1.NodeV1Interface) *MockComponentEcosystemInterface_NodeV1_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockComponentEcosystemInterface_NodeV1_Call) RunAndReturn(run func() nodev1.NodeV1Interface) *MockComponentEcosystemInterface_NodeV1_Call { + _c.Call.Return(run) + return _c +} + +// NodeV1alpha1 provides a mock function with given fields: +func (_m *MockComponentEcosystemInterface) NodeV1alpha1() nodev1alpha1.NodeV1alpha1Interface { + ret := _m.Called() + + var r0 nodev1alpha1.NodeV1alpha1Interface + if rf, ok := ret.Get(0).(func() nodev1alpha1.NodeV1alpha1Interface); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(nodev1alpha1.NodeV1alpha1Interface) + } + } + + return r0 +} + +// MockComponentEcosystemInterface_NodeV1alpha1_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NodeV1alpha1' +type MockComponentEcosystemInterface_NodeV1alpha1_Call struct { + *mock.Call +} + +// NodeV1alpha1 is a helper method to define mock.On call +func (_e *MockComponentEcosystemInterface_Expecter) NodeV1alpha1() *MockComponentEcosystemInterface_NodeV1alpha1_Call { + return &MockComponentEcosystemInterface_NodeV1alpha1_Call{Call: _e.mock.On("NodeV1alpha1")} +} + +func (_c *MockComponentEcosystemInterface_NodeV1alpha1_Call) Run(run func()) *MockComponentEcosystemInterface_NodeV1alpha1_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockComponentEcosystemInterface_NodeV1alpha1_Call) Return(_a0 nodev1alpha1.NodeV1alpha1Interface) *MockComponentEcosystemInterface_NodeV1alpha1_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockComponentEcosystemInterface_NodeV1alpha1_Call) RunAndReturn(run func() nodev1alpha1.NodeV1alpha1Interface) *MockComponentEcosystemInterface_NodeV1alpha1_Call { + _c.Call.Return(run) + return _c +} + +// NodeV1beta1 provides a mock function with given fields: +func (_m *MockComponentEcosystemInterface) NodeV1beta1() nodev1beta1.NodeV1beta1Interface { + ret := _m.Called() + + var r0 nodev1beta1.NodeV1beta1Interface + if rf, ok := ret.Get(0).(func() nodev1beta1.NodeV1beta1Interface); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(nodev1beta1.NodeV1beta1Interface) + } + } + + return r0 +} + +// MockComponentEcosystemInterface_NodeV1beta1_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NodeV1beta1' +type MockComponentEcosystemInterface_NodeV1beta1_Call struct { + *mock.Call +} + +// NodeV1beta1 is a helper method to define mock.On call +func (_e *MockComponentEcosystemInterface_Expecter) NodeV1beta1() *MockComponentEcosystemInterface_NodeV1beta1_Call { + return &MockComponentEcosystemInterface_NodeV1beta1_Call{Call: _e.mock.On("NodeV1beta1")} +} + +func (_c *MockComponentEcosystemInterface_NodeV1beta1_Call) Run(run func()) *MockComponentEcosystemInterface_NodeV1beta1_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockComponentEcosystemInterface_NodeV1beta1_Call) Return(_a0 nodev1beta1.NodeV1beta1Interface) *MockComponentEcosystemInterface_NodeV1beta1_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockComponentEcosystemInterface_NodeV1beta1_Call) RunAndReturn(run func() nodev1beta1.NodeV1beta1Interface) *MockComponentEcosystemInterface_NodeV1beta1_Call { + _c.Call.Return(run) + return _c +} + +// PolicyV1 provides a mock function with given fields: +func (_m *MockComponentEcosystemInterface) PolicyV1() policyv1.PolicyV1Interface { + ret := _m.Called() + + var r0 policyv1.PolicyV1Interface + if rf, ok := ret.Get(0).(func() policyv1.PolicyV1Interface); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(policyv1.PolicyV1Interface) + } + } + + return r0 +} + +// MockComponentEcosystemInterface_PolicyV1_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'PolicyV1' +type MockComponentEcosystemInterface_PolicyV1_Call struct { + *mock.Call +} + +// PolicyV1 is a helper method to define mock.On call +func (_e *MockComponentEcosystemInterface_Expecter) PolicyV1() *MockComponentEcosystemInterface_PolicyV1_Call { + return &MockComponentEcosystemInterface_PolicyV1_Call{Call: _e.mock.On("PolicyV1")} +} + +func (_c *MockComponentEcosystemInterface_PolicyV1_Call) Run(run func()) *MockComponentEcosystemInterface_PolicyV1_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockComponentEcosystemInterface_PolicyV1_Call) Return(_a0 policyv1.PolicyV1Interface) *MockComponentEcosystemInterface_PolicyV1_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockComponentEcosystemInterface_PolicyV1_Call) RunAndReturn(run func() policyv1.PolicyV1Interface) *MockComponentEcosystemInterface_PolicyV1_Call { + _c.Call.Return(run) + return _c +} + +// PolicyV1beta1 provides a mock function with given fields: +func (_m *MockComponentEcosystemInterface) PolicyV1beta1() policyv1beta1.PolicyV1beta1Interface { + ret := _m.Called() + + var r0 policyv1beta1.PolicyV1beta1Interface + if rf, ok := ret.Get(0).(func() policyv1beta1.PolicyV1beta1Interface); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(policyv1beta1.PolicyV1beta1Interface) + } + } + + return r0 +} + +// MockComponentEcosystemInterface_PolicyV1beta1_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'PolicyV1beta1' +type MockComponentEcosystemInterface_PolicyV1beta1_Call struct { + *mock.Call +} + +// PolicyV1beta1 is a helper method to define mock.On call +func (_e *MockComponentEcosystemInterface_Expecter) PolicyV1beta1() *MockComponentEcosystemInterface_PolicyV1beta1_Call { + return &MockComponentEcosystemInterface_PolicyV1beta1_Call{Call: _e.mock.On("PolicyV1beta1")} +} + +func (_c *MockComponentEcosystemInterface_PolicyV1beta1_Call) Run(run func()) *MockComponentEcosystemInterface_PolicyV1beta1_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockComponentEcosystemInterface_PolicyV1beta1_Call) Return(_a0 policyv1beta1.PolicyV1beta1Interface) *MockComponentEcosystemInterface_PolicyV1beta1_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockComponentEcosystemInterface_PolicyV1beta1_Call) RunAndReturn(run func() policyv1beta1.PolicyV1beta1Interface) *MockComponentEcosystemInterface_PolicyV1beta1_Call { + _c.Call.Return(run) + return _c +} + +// RbacV1 provides a mock function with given fields: +func (_m *MockComponentEcosystemInterface) RbacV1() rbacv1.RbacV1Interface { + ret := _m.Called() + + var r0 rbacv1.RbacV1Interface + if rf, ok := ret.Get(0).(func() rbacv1.RbacV1Interface); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(rbacv1.RbacV1Interface) + } + } + + return r0 +} + +// MockComponentEcosystemInterface_RbacV1_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RbacV1' +type MockComponentEcosystemInterface_RbacV1_Call struct { + *mock.Call +} + +// RbacV1 is a helper method to define mock.On call +func (_e *MockComponentEcosystemInterface_Expecter) RbacV1() *MockComponentEcosystemInterface_RbacV1_Call { + return &MockComponentEcosystemInterface_RbacV1_Call{Call: _e.mock.On("RbacV1")} +} + +func (_c *MockComponentEcosystemInterface_RbacV1_Call) Run(run func()) *MockComponentEcosystemInterface_RbacV1_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockComponentEcosystemInterface_RbacV1_Call) Return(_a0 rbacv1.RbacV1Interface) *MockComponentEcosystemInterface_RbacV1_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockComponentEcosystemInterface_RbacV1_Call) RunAndReturn(run func() rbacv1.RbacV1Interface) *MockComponentEcosystemInterface_RbacV1_Call { + _c.Call.Return(run) + return _c +} + +// RbacV1alpha1 provides a mock function with given fields: +func (_m *MockComponentEcosystemInterface) RbacV1alpha1() rbacv1alpha1.RbacV1alpha1Interface { + ret := _m.Called() + + var r0 rbacv1alpha1.RbacV1alpha1Interface + if rf, ok := ret.Get(0).(func() rbacv1alpha1.RbacV1alpha1Interface); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(rbacv1alpha1.RbacV1alpha1Interface) + } + } + + return r0 +} + +// MockComponentEcosystemInterface_RbacV1alpha1_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RbacV1alpha1' +type MockComponentEcosystemInterface_RbacV1alpha1_Call struct { + *mock.Call +} + +// RbacV1alpha1 is a helper method to define mock.On call +func (_e *MockComponentEcosystemInterface_Expecter) RbacV1alpha1() *MockComponentEcosystemInterface_RbacV1alpha1_Call { + return &MockComponentEcosystemInterface_RbacV1alpha1_Call{Call: _e.mock.On("RbacV1alpha1")} +} + +func (_c *MockComponentEcosystemInterface_RbacV1alpha1_Call) Run(run func()) *MockComponentEcosystemInterface_RbacV1alpha1_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockComponentEcosystemInterface_RbacV1alpha1_Call) Return(_a0 rbacv1alpha1.RbacV1alpha1Interface) *MockComponentEcosystemInterface_RbacV1alpha1_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockComponentEcosystemInterface_RbacV1alpha1_Call) RunAndReturn(run func() rbacv1alpha1.RbacV1alpha1Interface) *MockComponentEcosystemInterface_RbacV1alpha1_Call { + _c.Call.Return(run) + return _c +} + +// RbacV1beta1 provides a mock function with given fields: +func (_m *MockComponentEcosystemInterface) RbacV1beta1() rbacv1beta1.RbacV1beta1Interface { + ret := _m.Called() + + var r0 rbacv1beta1.RbacV1beta1Interface + if rf, ok := ret.Get(0).(func() rbacv1beta1.RbacV1beta1Interface); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(rbacv1beta1.RbacV1beta1Interface) + } + } + + return r0 +} + +// MockComponentEcosystemInterface_RbacV1beta1_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RbacV1beta1' +type MockComponentEcosystemInterface_RbacV1beta1_Call struct { + *mock.Call +} + +// RbacV1beta1 is a helper method to define mock.On call +func (_e *MockComponentEcosystemInterface_Expecter) RbacV1beta1() *MockComponentEcosystemInterface_RbacV1beta1_Call { + return &MockComponentEcosystemInterface_RbacV1beta1_Call{Call: _e.mock.On("RbacV1beta1")} +} + +func (_c *MockComponentEcosystemInterface_RbacV1beta1_Call) Run(run func()) *MockComponentEcosystemInterface_RbacV1beta1_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockComponentEcosystemInterface_RbacV1beta1_Call) Return(_a0 rbacv1beta1.RbacV1beta1Interface) *MockComponentEcosystemInterface_RbacV1beta1_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockComponentEcosystemInterface_RbacV1beta1_Call) RunAndReturn(run func() rbacv1beta1.RbacV1beta1Interface) *MockComponentEcosystemInterface_RbacV1beta1_Call { + _c.Call.Return(run) + return _c +} + +// ResourceV1alpha2 provides a mock function with given fields: +func (_m *MockComponentEcosystemInterface) ResourceV1alpha2() v1alpha2.ResourceV1alpha2Interface { + ret := _m.Called() + + var r0 v1alpha2.ResourceV1alpha2Interface + if rf, ok := ret.Get(0).(func() v1alpha2.ResourceV1alpha2Interface); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(v1alpha2.ResourceV1alpha2Interface) + } + } + + return r0 +} + +// MockComponentEcosystemInterface_ResourceV1alpha2_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ResourceV1alpha2' +type MockComponentEcosystemInterface_ResourceV1alpha2_Call struct { + *mock.Call +} + +// ResourceV1alpha2 is a helper method to define mock.On call +func (_e *MockComponentEcosystemInterface_Expecter) ResourceV1alpha2() *MockComponentEcosystemInterface_ResourceV1alpha2_Call { + return &MockComponentEcosystemInterface_ResourceV1alpha2_Call{Call: _e.mock.On("ResourceV1alpha2")} +} + +func (_c *MockComponentEcosystemInterface_ResourceV1alpha2_Call) Run(run func()) *MockComponentEcosystemInterface_ResourceV1alpha2_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockComponentEcosystemInterface_ResourceV1alpha2_Call) Return(_a0 v1alpha2.ResourceV1alpha2Interface) *MockComponentEcosystemInterface_ResourceV1alpha2_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockComponentEcosystemInterface_ResourceV1alpha2_Call) RunAndReturn(run func() v1alpha2.ResourceV1alpha2Interface) *MockComponentEcosystemInterface_ResourceV1alpha2_Call { + _c.Call.Return(run) + return _c +} + +// SchedulingV1 provides a mock function with given fields: +func (_m *MockComponentEcosystemInterface) SchedulingV1() schedulingv1.SchedulingV1Interface { + ret := _m.Called() + + var r0 schedulingv1.SchedulingV1Interface + if rf, ok := ret.Get(0).(func() schedulingv1.SchedulingV1Interface); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(schedulingv1.SchedulingV1Interface) + } + } + + return r0 +} + +// MockComponentEcosystemInterface_SchedulingV1_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SchedulingV1' +type MockComponentEcosystemInterface_SchedulingV1_Call struct { + *mock.Call +} + +// SchedulingV1 is a helper method to define mock.On call +func (_e *MockComponentEcosystemInterface_Expecter) SchedulingV1() *MockComponentEcosystemInterface_SchedulingV1_Call { + return &MockComponentEcosystemInterface_SchedulingV1_Call{Call: _e.mock.On("SchedulingV1")} +} + +func (_c *MockComponentEcosystemInterface_SchedulingV1_Call) Run(run func()) *MockComponentEcosystemInterface_SchedulingV1_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockComponentEcosystemInterface_SchedulingV1_Call) Return(_a0 schedulingv1.SchedulingV1Interface) *MockComponentEcosystemInterface_SchedulingV1_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockComponentEcosystemInterface_SchedulingV1_Call) RunAndReturn(run func() schedulingv1.SchedulingV1Interface) *MockComponentEcosystemInterface_SchedulingV1_Call { + _c.Call.Return(run) + return _c +} + +// SchedulingV1alpha1 provides a mock function with given fields: +func (_m *MockComponentEcosystemInterface) SchedulingV1alpha1() schedulingv1alpha1.SchedulingV1alpha1Interface { + ret := _m.Called() + + var r0 schedulingv1alpha1.SchedulingV1alpha1Interface + if rf, ok := ret.Get(0).(func() schedulingv1alpha1.SchedulingV1alpha1Interface); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(schedulingv1alpha1.SchedulingV1alpha1Interface) + } + } + + return r0 +} + +// MockComponentEcosystemInterface_SchedulingV1alpha1_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SchedulingV1alpha1' +type MockComponentEcosystemInterface_SchedulingV1alpha1_Call struct { + *mock.Call +} + +// SchedulingV1alpha1 is a helper method to define mock.On call +func (_e *MockComponentEcosystemInterface_Expecter) SchedulingV1alpha1() *MockComponentEcosystemInterface_SchedulingV1alpha1_Call { + return &MockComponentEcosystemInterface_SchedulingV1alpha1_Call{Call: _e.mock.On("SchedulingV1alpha1")} +} + +func (_c *MockComponentEcosystemInterface_SchedulingV1alpha1_Call) Run(run func()) *MockComponentEcosystemInterface_SchedulingV1alpha1_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockComponentEcosystemInterface_SchedulingV1alpha1_Call) Return(_a0 schedulingv1alpha1.SchedulingV1alpha1Interface) *MockComponentEcosystemInterface_SchedulingV1alpha1_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockComponentEcosystemInterface_SchedulingV1alpha1_Call) RunAndReturn(run func() schedulingv1alpha1.SchedulingV1alpha1Interface) *MockComponentEcosystemInterface_SchedulingV1alpha1_Call { + _c.Call.Return(run) + return _c +} + +// SchedulingV1beta1 provides a mock function with given fields: +func (_m *MockComponentEcosystemInterface) SchedulingV1beta1() schedulingv1beta1.SchedulingV1beta1Interface { + ret := _m.Called() + + var r0 schedulingv1beta1.SchedulingV1beta1Interface + if rf, ok := ret.Get(0).(func() schedulingv1beta1.SchedulingV1beta1Interface); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(schedulingv1beta1.SchedulingV1beta1Interface) + } + } + + return r0 +} + +// MockComponentEcosystemInterface_SchedulingV1beta1_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SchedulingV1beta1' +type MockComponentEcosystemInterface_SchedulingV1beta1_Call struct { + *mock.Call +} + +// SchedulingV1beta1 is a helper method to define mock.On call +func (_e *MockComponentEcosystemInterface_Expecter) SchedulingV1beta1() *MockComponentEcosystemInterface_SchedulingV1beta1_Call { + return &MockComponentEcosystemInterface_SchedulingV1beta1_Call{Call: _e.mock.On("SchedulingV1beta1")} +} + +func (_c *MockComponentEcosystemInterface_SchedulingV1beta1_Call) Run(run func()) *MockComponentEcosystemInterface_SchedulingV1beta1_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockComponentEcosystemInterface_SchedulingV1beta1_Call) Return(_a0 schedulingv1beta1.SchedulingV1beta1Interface) *MockComponentEcosystemInterface_SchedulingV1beta1_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockComponentEcosystemInterface_SchedulingV1beta1_Call) RunAndReturn(run func() schedulingv1beta1.SchedulingV1beta1Interface) *MockComponentEcosystemInterface_SchedulingV1beta1_Call { + _c.Call.Return(run) + return _c +} + +// StorageV1 provides a mock function with given fields: +func (_m *MockComponentEcosystemInterface) StorageV1() storagev1.StorageV1Interface { + ret := _m.Called() + + var r0 storagev1.StorageV1Interface + if rf, ok := ret.Get(0).(func() storagev1.StorageV1Interface); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(storagev1.StorageV1Interface) + } + } + + return r0 +} + +// MockComponentEcosystemInterface_StorageV1_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'StorageV1' +type MockComponentEcosystemInterface_StorageV1_Call struct { + *mock.Call +} + +// StorageV1 is a helper method to define mock.On call +func (_e *MockComponentEcosystemInterface_Expecter) StorageV1() *MockComponentEcosystemInterface_StorageV1_Call { + return &MockComponentEcosystemInterface_StorageV1_Call{Call: _e.mock.On("StorageV1")} +} + +func (_c *MockComponentEcosystemInterface_StorageV1_Call) Run(run func()) *MockComponentEcosystemInterface_StorageV1_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockComponentEcosystemInterface_StorageV1_Call) Return(_a0 storagev1.StorageV1Interface) *MockComponentEcosystemInterface_StorageV1_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockComponentEcosystemInterface_StorageV1_Call) RunAndReturn(run func() storagev1.StorageV1Interface) *MockComponentEcosystemInterface_StorageV1_Call { + _c.Call.Return(run) + return _c +} + +// StorageV1alpha1 provides a mock function with given fields: +func (_m *MockComponentEcosystemInterface) StorageV1alpha1() storagev1alpha1.StorageV1alpha1Interface { + ret := _m.Called() + + var r0 storagev1alpha1.StorageV1alpha1Interface + if rf, ok := ret.Get(0).(func() storagev1alpha1.StorageV1alpha1Interface); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(storagev1alpha1.StorageV1alpha1Interface) + } + } + + return r0 +} + +// MockComponentEcosystemInterface_StorageV1alpha1_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'StorageV1alpha1' +type MockComponentEcosystemInterface_StorageV1alpha1_Call struct { + *mock.Call +} + +// StorageV1alpha1 is a helper method to define mock.On call +func (_e *MockComponentEcosystemInterface_Expecter) StorageV1alpha1() *MockComponentEcosystemInterface_StorageV1alpha1_Call { + return &MockComponentEcosystemInterface_StorageV1alpha1_Call{Call: _e.mock.On("StorageV1alpha1")} +} + +func (_c *MockComponentEcosystemInterface_StorageV1alpha1_Call) Run(run func()) *MockComponentEcosystemInterface_StorageV1alpha1_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockComponentEcosystemInterface_StorageV1alpha1_Call) Return(_a0 storagev1alpha1.StorageV1alpha1Interface) *MockComponentEcosystemInterface_StorageV1alpha1_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockComponentEcosystemInterface_StorageV1alpha1_Call) RunAndReturn(run func() storagev1alpha1.StorageV1alpha1Interface) *MockComponentEcosystemInterface_StorageV1alpha1_Call { + _c.Call.Return(run) + return _c +} + +// StorageV1beta1 provides a mock function with given fields: +func (_m *MockComponentEcosystemInterface) StorageV1beta1() storagev1beta1.StorageV1beta1Interface { + ret := _m.Called() + + var r0 storagev1beta1.StorageV1beta1Interface + if rf, ok := ret.Get(0).(func() storagev1beta1.StorageV1beta1Interface); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(storagev1beta1.StorageV1beta1Interface) + } + } + + return r0 +} + +// MockComponentEcosystemInterface_StorageV1beta1_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'StorageV1beta1' +type MockComponentEcosystemInterface_StorageV1beta1_Call struct { + *mock.Call +} + +// StorageV1beta1 is a helper method to define mock.On call +func (_e *MockComponentEcosystemInterface_Expecter) StorageV1beta1() *MockComponentEcosystemInterface_StorageV1beta1_Call { + return &MockComponentEcosystemInterface_StorageV1beta1_Call{Call: _e.mock.On("StorageV1beta1")} +} + +func (_c *MockComponentEcosystemInterface_StorageV1beta1_Call) Run(run func()) *MockComponentEcosystemInterface_StorageV1beta1_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockComponentEcosystemInterface_StorageV1beta1_Call) Return(_a0 storagev1beta1.StorageV1beta1Interface) *MockComponentEcosystemInterface_StorageV1beta1_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockComponentEcosystemInterface_StorageV1beta1_Call) RunAndReturn(run func() storagev1beta1.StorageV1beta1Interface) *MockComponentEcosystemInterface_StorageV1beta1_Call { + _c.Call.Return(run) + return _c +} + +type mockConstructorTestingTNewMockComponentEcosystemInterface interface { + mock.TestingT + Cleanup(func()) +} + +// NewMockComponentEcosystemInterface creates a new instance of MockComponentEcosystemInterface. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewMockComponentEcosystemInterface(t mockConstructorTestingTNewMockComponentEcosystemInterface) *MockComponentEcosystemInterface { + mock := &MockComponentEcosystemInterface{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/api/ecosystem/mock_ComponentV1Alpha1Interface_test.go b/pkg/api/ecosystem/mock_ComponentV1Alpha1Interface_test.go new file mode 100644 index 0000000..dd3bdc9 --- /dev/null +++ b/pkg/api/ecosystem/mock_ComponentV1Alpha1Interface_test.go @@ -0,0 +1,77 @@ +// Code generated by mockery v2.20.0. DO NOT EDIT. + +package ecosystem + +import mock "github.com/stretchr/testify/mock" + +// MockComponentV1Alpha1Interface is an autogenerated mock type for the ComponentV1Alpha1Interface type +type MockComponentV1Alpha1Interface struct { + mock.Mock +} + +type MockComponentV1Alpha1Interface_Expecter struct { + mock *mock.Mock +} + +func (_m *MockComponentV1Alpha1Interface) EXPECT() *MockComponentV1Alpha1Interface_Expecter { + return &MockComponentV1Alpha1Interface_Expecter{mock: &_m.Mock} +} + +// Components provides a mock function with given fields: namespace +func (_m *MockComponentV1Alpha1Interface) Components(namespace string) ComponentInterface { + ret := _m.Called(namespace) + + var r0 ComponentInterface + if rf, ok := ret.Get(0).(func(string) ComponentInterface); ok { + r0 = rf(namespace) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(ComponentInterface) + } + } + + return r0 +} + +// MockComponentV1Alpha1Interface_Components_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Components' +type MockComponentV1Alpha1Interface_Components_Call struct { + *mock.Call +} + +// Components is a helper method to define mock.On call +// - namespace string +func (_e *MockComponentV1Alpha1Interface_Expecter) Components(namespace interface{}) *MockComponentV1Alpha1Interface_Components_Call { + return &MockComponentV1Alpha1Interface_Components_Call{Call: _e.mock.On("Components", namespace)} +} + +func (_c *MockComponentV1Alpha1Interface_Components_Call) Run(run func(namespace string)) *MockComponentV1Alpha1Interface_Components_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *MockComponentV1Alpha1Interface_Components_Call) Return(_a0 ComponentInterface) *MockComponentV1Alpha1Interface_Components_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockComponentV1Alpha1Interface_Components_Call) RunAndReturn(run func(string) ComponentInterface) *MockComponentV1Alpha1Interface_Components_Call { + _c.Call.Return(run) + return _c +} + +type mockConstructorTestingTNewMockComponentV1Alpha1Interface interface { + mock.TestingT + Cleanup(func()) +} + +// NewMockComponentV1Alpha1Interface creates a new instance of MockComponentV1Alpha1Interface. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewMockComponentV1Alpha1Interface(t mockConstructorTestingTNewMockComponentV1Alpha1Interface) *MockComponentV1Alpha1Interface { + mock := &MockComponentV1Alpha1Interface{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/api/v1/ces_component_types.go b/pkg/api/v1/ces_component_types.go index 4a1f226..78c66d7 100644 --- a/pkg/api/v1/ces_component_types.go +++ b/pkg/api/v1/ces_component_types.go @@ -46,6 +46,10 @@ type ComponentSpec struct { // DeployNamespace is the namespace where the helm chart should be deployed in. // This value is optional. If it is empty the operator deploys the helm chart in the namespace where the operator is deployed. DeployNamespace string `json:"deployNamespace,omitempty"` + // ValuesYamlOverwrite is a multiline-yaml string that is applied alongside the original values.yaml-file of the component. + // It can be used to overwrite specific configurations. Lists are overwritten, maps are merged. + // +optional + ValuesYamlOverwrite string `json:"valuesYamlOverwrite,omitempty"` } // ComponentStatus defines the observed state of a Component. @@ -89,6 +93,7 @@ func (c *Component) GetHelmChartSpec() *client.ChartSpec { ChartName: fmt.Sprintf("%s/%s", c.Spec.Namespace, c.Spec.Name), Namespace: deployNamespace, Version: c.Spec.Version, + ValuesYaml: c.Spec.ValuesYamlOverwrite, // Rollback to previous release on failure. Atomic: true, // This timeout prevents context exceeded errors from the used k8s client from the helm library. diff --git a/pkg/controllers/componentController.go b/pkg/controllers/componentController.go index 2425696..2887f7c 100644 --- a/pkg/controllers/componentController.go +++ b/pkg/controllers/componentController.go @@ -3,6 +3,7 @@ package controllers import ( "context" "fmt" + "reflect" "strings" k8sv1 "github.com/cloudogu/k8s-component-operator/pkg/api/v1" @@ -256,7 +257,7 @@ func (r *componentReconciler) getChangeOperation(ctx context.Context, component logger.Info("Found existing release for reconciled component", "releaseNamespace", deployedRelease.Namespace, "targetNamespace", targetNamespace) if existsReleaseInTargetNamespace { - return getChangeOperationForRelease(component, deployedRelease) + return r.getChangeOperationForRelease(component, deployedRelease) } } } @@ -264,7 +265,29 @@ func (r *componentReconciler) getChangeOperation(ctx context.Context, component return Ignore, nil } -func getChangeOperationForRelease(component *k8sv1.Component, release *release.Release) (operation, error) { +func (r *componentReconciler) isValuesChanged(deployedRelease *release.Release, component *k8sv1.Component) (bool, error) { + deployedValues, err := r.helmClient.GetReleaseValues(deployedRelease.Name, false) + if err != nil { + return false, fmt.Errorf("failed to get values.yaml from release %s: %w", deployedRelease.Name, err) + } + + chartSpecValues, err := r.helmClient.GetChartSpecValues(component.GetHelmChartSpec()) + if err != nil { + return false, fmt.Errorf("failed to get values.yaml from chart spec %s: %w", component.GetHelmChartSpec().ChartName, err) + } + + // if no additional values are set, the maps will look like this: + // deployedValues=map[string]interface {}(nil) │ + // chartSpecValues=map[string]interface {}{} + // this is treated as a difference by DeepEqual, so we have to handle this edge case manually + if len(deployedValues) == 0 && len(chartSpecValues) == 0 { + return false, nil + } + + return !reflect.DeepEqual(deployedValues, chartSpecValues), nil +} + +func (r *componentReconciler) getChangeOperationForRelease(component *k8sv1.Component, release *release.Release) (operation, error) { chart := release.Chart deployedAppVersion, err := semver.NewVersion(chart.AppVersion()) if err != nil { @@ -284,6 +307,14 @@ func getChangeOperationForRelease(component *k8sv1.Component, release *release.R return Downgrade, nil } + isValuesChanged, err := r.isValuesChanged(release, component) + if err != nil { + return "", fmt.Errorf("failed to compare Values.yaml files of component %s: %w", component.Name, err) + } + if isValuesChanged { + return Upgrade, nil + } + return Ignore, nil } diff --git a/pkg/controllers/interfaces.go b/pkg/controllers/interfaces.go index 75a97c9..4e7341c 100644 --- a/pkg/controllers/interfaces.go +++ b/pkg/controllers/interfaces.go @@ -39,6 +39,10 @@ type helmClient interface { Uninstall(releaseName string) error // ListDeployedReleases returns all deployed helm releases ListDeployedReleases() ([]*release.Release, error) + // GetReleaseValues returns the (optionally, all computed) values for the specified release. + GetReleaseValues(name string, allValues bool) (map[string]interface{}, error) + // GetChartSpecValues returns the additional values for the specified ChartSpec. + GetChartSpecValues(chart *client.ChartSpec) (map[string]interface{}, error) // SatisfiesDependencies validates that all dependencies are installed in the required version. A nil error // indicates that all dependencies (if any) meet the requirements, so that the client may conduct an installation or // upgrade. diff --git a/pkg/controllers/mock_helmClient_test.go b/pkg/controllers/mock_helmClient_test.go index b94f101..73ffe07 100644 --- a/pkg/controllers/mock_helmClient_test.go +++ b/pkg/controllers/mock_helmClient_test.go @@ -25,6 +25,115 @@ func (_m *mockHelmClient) EXPECT() *mockHelmClient_Expecter { return &mockHelmClient_Expecter{mock: &_m.Mock} } +// GetChartSpecValues provides a mock function with given fields: chart +func (_m *mockHelmClient) GetChartSpecValues(chart *client.ChartSpec) (map[string]interface{}, error) { + ret := _m.Called(chart) + + var r0 map[string]interface{} + var r1 error + if rf, ok := ret.Get(0).(func(*client.ChartSpec) (map[string]interface{}, error)); ok { + return rf(chart) + } + if rf, ok := ret.Get(0).(func(*client.ChartSpec) map[string]interface{}); ok { + r0 = rf(chart) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(map[string]interface{}) + } + } + + if rf, ok := ret.Get(1).(func(*client.ChartSpec) error); ok { + r1 = rf(chart) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// mockHelmClient_GetChartSpecValues_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetChartSpecValues' +type mockHelmClient_GetChartSpecValues_Call struct { + *mock.Call +} + +// GetChartSpecValues is a helper method to define mock.On call +// - chart *client.ChartSpec +func (_e *mockHelmClient_Expecter) GetChartSpecValues(chart interface{}) *mockHelmClient_GetChartSpecValues_Call { + return &mockHelmClient_GetChartSpecValues_Call{Call: _e.mock.On("GetChartSpecValues", chart)} +} + +func (_c *mockHelmClient_GetChartSpecValues_Call) Run(run func(chart *client.ChartSpec)) *mockHelmClient_GetChartSpecValues_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*client.ChartSpec)) + }) + return _c +} + +func (_c *mockHelmClient_GetChartSpecValues_Call) Return(_a0 map[string]interface{}, _a1 error) *mockHelmClient_GetChartSpecValues_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *mockHelmClient_GetChartSpecValues_Call) RunAndReturn(run func(*client.ChartSpec) (map[string]interface{}, error)) *mockHelmClient_GetChartSpecValues_Call { + _c.Call.Return(run) + return _c +} + +// GetReleaseValues provides a mock function with given fields: name, allValues +func (_m *mockHelmClient) GetReleaseValues(name string, allValues bool) (map[string]interface{}, error) { + ret := _m.Called(name, allValues) + + var r0 map[string]interface{} + var r1 error + if rf, ok := ret.Get(0).(func(string, bool) (map[string]interface{}, error)); ok { + return rf(name, allValues) + } + if rf, ok := ret.Get(0).(func(string, bool) map[string]interface{}); ok { + r0 = rf(name, allValues) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(map[string]interface{}) + } + } + + if rf, ok := ret.Get(1).(func(string, bool) error); ok { + r1 = rf(name, allValues) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// mockHelmClient_GetReleaseValues_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetReleaseValues' +type mockHelmClient_GetReleaseValues_Call struct { + *mock.Call +} + +// GetReleaseValues is a helper method to define mock.On call +// - name string +// - allValues bool +func (_e *mockHelmClient_Expecter) GetReleaseValues(name interface{}, allValues interface{}) *mockHelmClient_GetReleaseValues_Call { + return &mockHelmClient_GetReleaseValues_Call{Call: _e.mock.On("GetReleaseValues", name, allValues)} +} + +func (_c *mockHelmClient_GetReleaseValues_Call) Run(run func(name string, allValues bool)) *mockHelmClient_GetReleaseValues_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string), args[1].(bool)) + }) + return _c +} + +func (_c *mockHelmClient_GetReleaseValues_Call) Return(_a0 map[string]interface{}, _a1 error) *mockHelmClient_GetReleaseValues_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *mockHelmClient_GetReleaseValues_Call) RunAndReturn(run func(string, bool) (map[string]interface{}, error)) *mockHelmClient_GetReleaseValues_Call { + _c.Call.Return(run) + return _c +} + // InstallOrUpgrade provides a mock function with given fields: ctx, chart func (_m *mockHelmClient) InstallOrUpgrade(ctx context.Context, chart *client.ChartSpec) error { ret := _m.Called(ctx, chart) diff --git a/pkg/helm/client.go b/pkg/helm/client.go index 9ed01e6..0b1c546 100644 --- a/pkg/helm/client.go +++ b/pkg/helm/client.go @@ -144,6 +144,16 @@ func (c *Client) ListDeployedReleases() ([]*release.Release, error) { return c.helmClient.ListDeployedReleases() } +// GetReleaseValues returns the (optionally, all computed) values for the specified release. +func (c *Client) GetReleaseValues(name string, allValues bool) (map[string]interface{}, error) { + return c.helmClient.GetReleaseValues(name, allValues) +} + +// GetChartSpecValues returns the additional values for the specified ChartSpec. +func (c *Client) GetChartSpecValues(spec *client.ChartSpec) (map[string]interface{}, error) { + return c.helmClient.GetChartSpecValues(spec) +} + func (c *Client) patchOciEndpoint(chart *client.ChartSpec) { if strings.HasPrefix(chart.ChartName, ociSchemePrefix) { return diff --git a/pkg/helm/client/client.go b/pkg/helm/client/client.go index 110a738..7bd4657 100644 --- a/pkg/helm/client/client.go +++ b/pkg/helm/client/client.go @@ -4,12 +4,11 @@ import ( "context" "crypto/tls" "fmt" + "github.com/spf13/pflag" "log" "net/http" "os" - "github.com/spf13/pflag" - "k8s.io/cli-runtime/pkg/genericclioptions" "helm.sh/helm/v3/pkg/action" @@ -193,6 +192,17 @@ func (c *HelmClient) GetReleaseValues(name string, allValues bool) (map[string]i return c.getReleaseValues(name, allValues) } +// GetChartSpecValues returns the additional values for the specified ChartSpec. +func (c *HelmClient) GetChartSpecValues(spec *ChartSpec) (map[string]interface{}, error) { + p := getter.All(c.Settings) + additionalValuesYaml, err := spec.GetValuesMap(p) + if err != nil { + return nil, fmt.Errorf("failed to get additional values.yaml-values from %s: %w", spec.ChartName, err) + } + + return additionalValuesYaml, nil +} + // GetRelease returns a release specified by name. func (c *HelmClient) GetRelease(name string) (*release.Release, error) { return c.getRelease(name) diff --git a/pkg/helm/client/interface.go b/pkg/helm/client/interface.go index 662a301..742104f 100644 --- a/pkg/helm/client/interface.go +++ b/pkg/helm/client/interface.go @@ -21,6 +21,7 @@ type Client interface { // RollBack is an interface to abstract a rollback action. RollBack GetReleaseValues(name string, allValues bool) (map[string]interface{}, error) + GetChartSpecValues(spec *ChartSpec) (map[string]interface{}, error) UninstallRelease(spec *ChartSpec) error UninstallReleaseByName(name string) error GetChart(spec *ChartSpec) (*chart.Chart, string, error) diff --git a/pkg/helm/client/mock_Client_test.go b/pkg/helm/client/mock_Client_test.go new file mode 100644 index 0000000..c1254e4 --- /dev/null +++ b/pkg/helm/client/mock_Client_test.go @@ -0,0 +1,718 @@ +// Code generated by mockery v2.20.0. DO NOT EDIT. + +package client + +import ( + action "helm.sh/helm/v3/pkg/action" + chart "helm.sh/helm/v3/pkg/chart" + + context "context" + + mock "github.com/stretchr/testify/mock" + + release "helm.sh/helm/v3/pkg/release" +) + +// MockClient is an autogenerated mock type for the Client type +type MockClient struct { + mock.Mock +} + +type MockClient_Expecter struct { + mock *mock.Mock +} + +func (_m *MockClient) EXPECT() *MockClient_Expecter { + return &MockClient_Expecter{mock: &_m.Mock} +} + +// GetChart provides a mock function with given fields: spec +func (_m *MockClient) GetChart(spec *ChartSpec) (*chart.Chart, string, error) { + ret := _m.Called(spec) + + var r0 *chart.Chart + var r1 string + var r2 error + if rf, ok := ret.Get(0).(func(*ChartSpec) (*chart.Chart, string, error)); ok { + return rf(spec) + } + if rf, ok := ret.Get(0).(func(*ChartSpec) *chart.Chart); ok { + r0 = rf(spec) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*chart.Chart) + } + } + + if rf, ok := ret.Get(1).(func(*ChartSpec) string); ok { + r1 = rf(spec) + } else { + r1 = ret.Get(1).(string) + } + + if rf, ok := ret.Get(2).(func(*ChartSpec) error); ok { + r2 = rf(spec) + } else { + r2 = ret.Error(2) + } + + return r0, r1, r2 +} + +// MockClient_GetChart_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetChart' +type MockClient_GetChart_Call struct { + *mock.Call +} + +// GetChart is a helper method to define mock.On call +// - spec *ChartSpec +func (_e *MockClient_Expecter) GetChart(spec interface{}) *MockClient_GetChart_Call { + return &MockClient_GetChart_Call{Call: _e.mock.On("GetChart", spec)} +} + +func (_c *MockClient_GetChart_Call) Run(run func(spec *ChartSpec)) *MockClient_GetChart_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*ChartSpec)) + }) + return _c +} + +func (_c *MockClient_GetChart_Call) Return(_a0 *chart.Chart, _a1 string, _a2 error) *MockClient_GetChart_Call { + _c.Call.Return(_a0, _a1, _a2) + return _c +} + +func (_c *MockClient_GetChart_Call) RunAndReturn(run func(*ChartSpec) (*chart.Chart, string, error)) *MockClient_GetChart_Call { + _c.Call.Return(run) + return _c +} + +// GetChartSpecValues provides a mock function with given fields: spec +func (_m *MockClient) GetChartSpecValues(spec *ChartSpec) (map[string]interface{}, error) { + ret := _m.Called(spec) + + var r0 map[string]interface{} + var r1 error + if rf, ok := ret.Get(0).(func(*ChartSpec) (map[string]interface{}, error)); ok { + return rf(spec) + } + if rf, ok := ret.Get(0).(func(*ChartSpec) map[string]interface{}); ok { + r0 = rf(spec) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(map[string]interface{}) + } + } + + if rf, ok := ret.Get(1).(func(*ChartSpec) error); ok { + r1 = rf(spec) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockClient_GetChartSpecValues_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetChartSpecValues' +type MockClient_GetChartSpecValues_Call struct { + *mock.Call +} + +// GetChartSpecValues is a helper method to define mock.On call +// - spec *ChartSpec +func (_e *MockClient_Expecter) GetChartSpecValues(spec interface{}) *MockClient_GetChartSpecValues_Call { + return &MockClient_GetChartSpecValues_Call{Call: _e.mock.On("GetChartSpecValues", spec)} +} + +func (_c *MockClient_GetChartSpecValues_Call) Run(run func(spec *ChartSpec)) *MockClient_GetChartSpecValues_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*ChartSpec)) + }) + return _c +} + +func (_c *MockClient_GetChartSpecValues_Call) Return(_a0 map[string]interface{}, _a1 error) *MockClient_GetChartSpecValues_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockClient_GetChartSpecValues_Call) RunAndReturn(run func(*ChartSpec) (map[string]interface{}, error)) *MockClient_GetChartSpecValues_Call { + _c.Call.Return(run) + return _c +} + +// GetRelease provides a mock function with given fields: name +func (_m *MockClient) GetRelease(name string) (*release.Release, error) { + ret := _m.Called(name) + + var r0 *release.Release + var r1 error + if rf, ok := ret.Get(0).(func(string) (*release.Release, error)); ok { + return rf(name) + } + if rf, ok := ret.Get(0).(func(string) *release.Release); ok { + r0 = rf(name) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*release.Release) + } + } + + if rf, ok := ret.Get(1).(func(string) error); ok { + r1 = rf(name) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockClient_GetRelease_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetRelease' +type MockClient_GetRelease_Call struct { + *mock.Call +} + +// GetRelease is a helper method to define mock.On call +// - name string +func (_e *MockClient_Expecter) GetRelease(name interface{}) *MockClient_GetRelease_Call { + return &MockClient_GetRelease_Call{Call: _e.mock.On("GetRelease", name)} +} + +func (_c *MockClient_GetRelease_Call) Run(run func(name string)) *MockClient_GetRelease_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *MockClient_GetRelease_Call) Return(_a0 *release.Release, _a1 error) *MockClient_GetRelease_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockClient_GetRelease_Call) RunAndReturn(run func(string) (*release.Release, error)) *MockClient_GetRelease_Call { + _c.Call.Return(run) + return _c +} + +// GetReleaseValues provides a mock function with given fields: name, allValues +func (_m *MockClient) GetReleaseValues(name string, allValues bool) (map[string]interface{}, error) { + ret := _m.Called(name, allValues) + + var r0 map[string]interface{} + var r1 error + if rf, ok := ret.Get(0).(func(string, bool) (map[string]interface{}, error)); ok { + return rf(name, allValues) + } + if rf, ok := ret.Get(0).(func(string, bool) map[string]interface{}); ok { + r0 = rf(name, allValues) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(map[string]interface{}) + } + } + + if rf, ok := ret.Get(1).(func(string, bool) error); ok { + r1 = rf(name, allValues) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockClient_GetReleaseValues_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetReleaseValues' +type MockClient_GetReleaseValues_Call struct { + *mock.Call +} + +// GetReleaseValues is a helper method to define mock.On call +// - name string +// - allValues bool +func (_e *MockClient_Expecter) GetReleaseValues(name interface{}, allValues interface{}) *MockClient_GetReleaseValues_Call { + return &MockClient_GetReleaseValues_Call{Call: _e.mock.On("GetReleaseValues", name, allValues)} +} + +func (_c *MockClient_GetReleaseValues_Call) Run(run func(name string, allValues bool)) *MockClient_GetReleaseValues_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string), args[1].(bool)) + }) + return _c +} + +func (_c *MockClient_GetReleaseValues_Call) Return(_a0 map[string]interface{}, _a1 error) *MockClient_GetReleaseValues_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockClient_GetReleaseValues_Call) RunAndReturn(run func(string, bool) (map[string]interface{}, error)) *MockClient_GetReleaseValues_Call { + _c.Call.Return(run) + return _c +} + +// InstallChart provides a mock function with given fields: ctx, spec +func (_m *MockClient) InstallChart(ctx context.Context, spec *ChartSpec) (*release.Release, error) { + ret := _m.Called(ctx, spec) + + var r0 *release.Release + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *ChartSpec) (*release.Release, error)); ok { + return rf(ctx, spec) + } + if rf, ok := ret.Get(0).(func(context.Context, *ChartSpec) *release.Release); ok { + r0 = rf(ctx, spec) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*release.Release) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *ChartSpec) error); ok { + r1 = rf(ctx, spec) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockClient_InstallChart_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'InstallChart' +type MockClient_InstallChart_Call struct { + *mock.Call +} + +// InstallChart is a helper method to define mock.On call +// - ctx context.Context +// - spec *ChartSpec +func (_e *MockClient_Expecter) InstallChart(ctx interface{}, spec interface{}) *MockClient_InstallChart_Call { + return &MockClient_InstallChart_Call{Call: _e.mock.On("InstallChart", ctx, spec)} +} + +func (_c *MockClient_InstallChart_Call) Run(run func(ctx context.Context, spec *ChartSpec)) *MockClient_InstallChart_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*ChartSpec)) + }) + return _c +} + +func (_c *MockClient_InstallChart_Call) Return(_a0 *release.Release, _a1 error) *MockClient_InstallChart_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockClient_InstallChart_Call) RunAndReturn(run func(context.Context, *ChartSpec) (*release.Release, error)) *MockClient_InstallChart_Call { + _c.Call.Return(run) + return _c +} + +// InstallOrUpgradeChart provides a mock function with given fields: ctx, spec +func (_m *MockClient) InstallOrUpgradeChart(ctx context.Context, spec *ChartSpec) (*release.Release, error) { + ret := _m.Called(ctx, spec) + + var r0 *release.Release + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *ChartSpec) (*release.Release, error)); ok { + return rf(ctx, spec) + } + if rf, ok := ret.Get(0).(func(context.Context, *ChartSpec) *release.Release); ok { + r0 = rf(ctx, spec) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*release.Release) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *ChartSpec) error); ok { + r1 = rf(ctx, spec) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockClient_InstallOrUpgradeChart_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'InstallOrUpgradeChart' +type MockClient_InstallOrUpgradeChart_Call struct { + *mock.Call +} + +// InstallOrUpgradeChart is a helper method to define mock.On call +// - ctx context.Context +// - spec *ChartSpec +func (_e *MockClient_Expecter) InstallOrUpgradeChart(ctx interface{}, spec interface{}) *MockClient_InstallOrUpgradeChart_Call { + return &MockClient_InstallOrUpgradeChart_Call{Call: _e.mock.On("InstallOrUpgradeChart", ctx, spec)} +} + +func (_c *MockClient_InstallOrUpgradeChart_Call) Run(run func(ctx context.Context, spec *ChartSpec)) *MockClient_InstallOrUpgradeChart_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*ChartSpec)) + }) + return _c +} + +func (_c *MockClient_InstallOrUpgradeChart_Call) Return(_a0 *release.Release, _a1 error) *MockClient_InstallOrUpgradeChart_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockClient_InstallOrUpgradeChart_Call) RunAndReturn(run func(context.Context, *ChartSpec) (*release.Release, error)) *MockClient_InstallOrUpgradeChart_Call { + _c.Call.Return(run) + return _c +} + +// ListDeployedReleases provides a mock function with given fields: +func (_m *MockClient) ListDeployedReleases() ([]*release.Release, error) { + ret := _m.Called() + + var r0 []*release.Release + var r1 error + if rf, ok := ret.Get(0).(func() ([]*release.Release, error)); ok { + return rf() + } + if rf, ok := ret.Get(0).(func() []*release.Release); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*release.Release) + } + } + + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockClient_ListDeployedReleases_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListDeployedReleases' +type MockClient_ListDeployedReleases_Call struct { + *mock.Call +} + +// ListDeployedReleases is a helper method to define mock.On call +func (_e *MockClient_Expecter) ListDeployedReleases() *MockClient_ListDeployedReleases_Call { + return &MockClient_ListDeployedReleases_Call{Call: _e.mock.On("ListDeployedReleases")} +} + +func (_c *MockClient_ListDeployedReleases_Call) Run(run func()) *MockClient_ListDeployedReleases_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockClient_ListDeployedReleases_Call) Return(_a0 []*release.Release, _a1 error) *MockClient_ListDeployedReleases_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockClient_ListDeployedReleases_Call) RunAndReturn(run func() ([]*release.Release, error)) *MockClient_ListDeployedReleases_Call { + _c.Call.Return(run) + return _c +} + +// ListReleasesByStateMask provides a mock function with given fields: _a0 +func (_m *MockClient) ListReleasesByStateMask(_a0 action.ListStates) ([]*release.Release, error) { + ret := _m.Called(_a0) + + var r0 []*release.Release + var r1 error + if rf, ok := ret.Get(0).(func(action.ListStates) ([]*release.Release, error)); ok { + return rf(_a0) + } + if rf, ok := ret.Get(0).(func(action.ListStates) []*release.Release); ok { + r0 = rf(_a0) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*release.Release) + } + } + + if rf, ok := ret.Get(1).(func(action.ListStates) error); ok { + r1 = rf(_a0) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockClient_ListReleasesByStateMask_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListReleasesByStateMask' +type MockClient_ListReleasesByStateMask_Call struct { + *mock.Call +} + +// ListReleasesByStateMask is a helper method to define mock.On call +// - _a0 action.ListStates +func (_e *MockClient_Expecter) ListReleasesByStateMask(_a0 interface{}) *MockClient_ListReleasesByStateMask_Call { + return &MockClient_ListReleasesByStateMask_Call{Call: _e.mock.On("ListReleasesByStateMask", _a0)} +} + +func (_c *MockClient_ListReleasesByStateMask_Call) Run(run func(_a0 action.ListStates)) *MockClient_ListReleasesByStateMask_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(action.ListStates)) + }) + return _c +} + +func (_c *MockClient_ListReleasesByStateMask_Call) Return(_a0 []*release.Release, _a1 error) *MockClient_ListReleasesByStateMask_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockClient_ListReleasesByStateMask_Call) RunAndReturn(run func(action.ListStates) ([]*release.Release, error)) *MockClient_ListReleasesByStateMask_Call { + _c.Call.Return(run) + return _c +} + +// RollbackRelease provides a mock function with given fields: spec +func (_m *MockClient) RollbackRelease(spec *ChartSpec) error { + ret := _m.Called(spec) + + var r0 error + if rf, ok := ret.Get(0).(func(*ChartSpec) error); ok { + r0 = rf(spec) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockClient_RollbackRelease_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RollbackRelease' +type MockClient_RollbackRelease_Call struct { + *mock.Call +} + +// RollbackRelease is a helper method to define mock.On call +// - spec *ChartSpec +func (_e *MockClient_Expecter) RollbackRelease(spec interface{}) *MockClient_RollbackRelease_Call { + return &MockClient_RollbackRelease_Call{Call: _e.mock.On("RollbackRelease", spec)} +} + +func (_c *MockClient_RollbackRelease_Call) Run(run func(spec *ChartSpec)) *MockClient_RollbackRelease_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*ChartSpec)) + }) + return _c +} + +func (_c *MockClient_RollbackRelease_Call) Return(_a0 error) *MockClient_RollbackRelease_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockClient_RollbackRelease_Call) RunAndReturn(run func(*ChartSpec) error) *MockClient_RollbackRelease_Call { + _c.Call.Return(run) + return _c +} + +// Tags provides a mock function with given fields: ref +func (_m *MockClient) Tags(ref string) ([]string, error) { + ret := _m.Called(ref) + + var r0 []string + var r1 error + if rf, ok := ret.Get(0).(func(string) ([]string, error)); ok { + return rf(ref) + } + if rf, ok := ret.Get(0).(func(string) []string); ok { + r0 = rf(ref) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]string) + } + } + + if rf, ok := ret.Get(1).(func(string) error); ok { + r1 = rf(ref) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockClient_Tags_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Tags' +type MockClient_Tags_Call struct { + *mock.Call +} + +// Tags is a helper method to define mock.On call +// - ref string +func (_e *MockClient_Expecter) Tags(ref interface{}) *MockClient_Tags_Call { + return &MockClient_Tags_Call{Call: _e.mock.On("Tags", ref)} +} + +func (_c *MockClient_Tags_Call) Run(run func(ref string)) *MockClient_Tags_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *MockClient_Tags_Call) Return(_a0 []string, _a1 error) *MockClient_Tags_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockClient_Tags_Call) RunAndReturn(run func(string) ([]string, error)) *MockClient_Tags_Call { + _c.Call.Return(run) + return _c +} + +// UninstallRelease provides a mock function with given fields: spec +func (_m *MockClient) UninstallRelease(spec *ChartSpec) error { + ret := _m.Called(spec) + + var r0 error + if rf, ok := ret.Get(0).(func(*ChartSpec) error); ok { + r0 = rf(spec) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockClient_UninstallRelease_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UninstallRelease' +type MockClient_UninstallRelease_Call struct { + *mock.Call +} + +// UninstallRelease is a helper method to define mock.On call +// - spec *ChartSpec +func (_e *MockClient_Expecter) UninstallRelease(spec interface{}) *MockClient_UninstallRelease_Call { + return &MockClient_UninstallRelease_Call{Call: _e.mock.On("UninstallRelease", spec)} +} + +func (_c *MockClient_UninstallRelease_Call) Run(run func(spec *ChartSpec)) *MockClient_UninstallRelease_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*ChartSpec)) + }) + return _c +} + +func (_c *MockClient_UninstallRelease_Call) Return(_a0 error) *MockClient_UninstallRelease_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockClient_UninstallRelease_Call) RunAndReturn(run func(*ChartSpec) error) *MockClient_UninstallRelease_Call { + _c.Call.Return(run) + return _c +} + +// UninstallReleaseByName provides a mock function with given fields: name +func (_m *MockClient) UninstallReleaseByName(name string) error { + ret := _m.Called(name) + + var r0 error + if rf, ok := ret.Get(0).(func(string) error); ok { + r0 = rf(name) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockClient_UninstallReleaseByName_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UninstallReleaseByName' +type MockClient_UninstallReleaseByName_Call struct { + *mock.Call +} + +// UninstallReleaseByName is a helper method to define mock.On call +// - name string +func (_e *MockClient_Expecter) UninstallReleaseByName(name interface{}) *MockClient_UninstallReleaseByName_Call { + return &MockClient_UninstallReleaseByName_Call{Call: _e.mock.On("UninstallReleaseByName", name)} +} + +func (_c *MockClient_UninstallReleaseByName_Call) Run(run func(name string)) *MockClient_UninstallReleaseByName_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *MockClient_UninstallReleaseByName_Call) Return(_a0 error) *MockClient_UninstallReleaseByName_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockClient_UninstallReleaseByName_Call) RunAndReturn(run func(string) error) *MockClient_UninstallReleaseByName_Call { + _c.Call.Return(run) + return _c +} + +// UpgradeChart provides a mock function with given fields: ctx, spec +func (_m *MockClient) UpgradeChart(ctx context.Context, spec *ChartSpec) (*release.Release, error) { + ret := _m.Called(ctx, spec) + + var r0 *release.Release + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *ChartSpec) (*release.Release, error)); ok { + return rf(ctx, spec) + } + if rf, ok := ret.Get(0).(func(context.Context, *ChartSpec) *release.Release); ok { + r0 = rf(ctx, spec) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*release.Release) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *ChartSpec) error); ok { + r1 = rf(ctx, spec) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockClient_UpgradeChart_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UpgradeChart' +type MockClient_UpgradeChart_Call struct { + *mock.Call +} + +// UpgradeChart is a helper method to define mock.On call +// - ctx context.Context +// - spec *ChartSpec +func (_e *MockClient_Expecter) UpgradeChart(ctx interface{}, spec interface{}) *MockClient_UpgradeChart_Call { + return &MockClient_UpgradeChart_Call{Call: _e.mock.On("UpgradeChart", ctx, spec)} +} + +func (_c *MockClient_UpgradeChart_Call) Run(run func(ctx context.Context, spec *ChartSpec)) *MockClient_UpgradeChart_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*ChartSpec)) + }) + return _c +} + +func (_c *MockClient_UpgradeChart_Call) Return(_a0 *release.Release, _a1 error) *MockClient_UpgradeChart_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockClient_UpgradeChart_Call) RunAndReturn(run func(context.Context, *ChartSpec) (*release.Release, error)) *MockClient_UpgradeChart_Call { + _c.Call.Return(run) + return _c +} + +type mockConstructorTestingTNewMockClient interface { + mock.TestingT + Cleanup(func()) +} + +// NewMockClient creates a new instance of MockClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewMockClient(t mockConstructorTestingTNewMockClient) *MockClient { + mock := &MockClient{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/helm/client/mock_RESTClientOption_test.go b/pkg/helm/client/mock_RESTClientOption_test.go new file mode 100644 index 0000000..48b9cd8 --- /dev/null +++ b/pkg/helm/client/mock_RESTClientOption_test.go @@ -0,0 +1,69 @@ +// Code generated by mockery v2.20.0. DO NOT EDIT. + +package client + +import ( + mock "github.com/stretchr/testify/mock" + rest "k8s.io/client-go/rest" +) + +// MockRESTClientOption is an autogenerated mock type for the RESTClientOption type +type MockRESTClientOption struct { + mock.Mock +} + +type MockRESTClientOption_Expecter struct { + mock *mock.Mock +} + +func (_m *MockRESTClientOption) EXPECT() *MockRESTClientOption_Expecter { + return &MockRESTClientOption_Expecter{mock: &_m.Mock} +} + +// Execute provides a mock function with given fields: _a0 +func (_m *MockRESTClientOption) Execute(_a0 *rest.Config) { + _m.Called(_a0) +} + +// MockRESTClientOption_Execute_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Execute' +type MockRESTClientOption_Execute_Call struct { + *mock.Call +} + +// Execute is a helper method to define mock.On call +// - _a0 *rest.Config +func (_e *MockRESTClientOption_Expecter) Execute(_a0 interface{}) *MockRESTClientOption_Execute_Call { + return &MockRESTClientOption_Execute_Call{Call: _e.mock.On("Execute", _a0)} +} + +func (_c *MockRESTClientOption_Execute_Call) Run(run func(_a0 *rest.Config)) *MockRESTClientOption_Execute_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*rest.Config)) + }) + return _c +} + +func (_c *MockRESTClientOption_Execute_Call) Return() *MockRESTClientOption_Execute_Call { + _c.Call.Return() + return _c +} + +func (_c *MockRESTClientOption_Execute_Call) RunAndReturn(run func(*rest.Config)) *MockRESTClientOption_Execute_Call { + _c.Call.Return(run) + return _c +} + +type mockConstructorTestingTNewMockRESTClientOption interface { + mock.TestingT + Cleanup(func()) +} + +// NewMockRESTClientOption creates a new instance of MockRESTClientOption. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewMockRESTClientOption(t mockConstructorTestingTNewMockRESTClientOption) *MockRESTClientOption { + mock := &MockRESTClientOption{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/helm/client/mock_RollBack_test.go b/pkg/helm/client/mock_RollBack_test.go new file mode 100644 index 0000000..9fa4005 --- /dev/null +++ b/pkg/helm/client/mock_RollBack_test.go @@ -0,0 +1,75 @@ +// Code generated by mockery v2.20.0. DO NOT EDIT. + +package client + +import mock "github.com/stretchr/testify/mock" + +// MockRollBack is an autogenerated mock type for the RollBack type +type MockRollBack struct { + mock.Mock +} + +type MockRollBack_Expecter struct { + mock *mock.Mock +} + +func (_m *MockRollBack) EXPECT() *MockRollBack_Expecter { + return &MockRollBack_Expecter{mock: &_m.Mock} +} + +// RollbackRelease provides a mock function with given fields: spec +func (_m *MockRollBack) RollbackRelease(spec *ChartSpec) error { + ret := _m.Called(spec) + + var r0 error + if rf, ok := ret.Get(0).(func(*ChartSpec) error); ok { + r0 = rf(spec) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockRollBack_RollbackRelease_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RollbackRelease' +type MockRollBack_RollbackRelease_Call struct { + *mock.Call +} + +// RollbackRelease is a helper method to define mock.On call +// - spec *ChartSpec +func (_e *MockRollBack_Expecter) RollbackRelease(spec interface{}) *MockRollBack_RollbackRelease_Call { + return &MockRollBack_RollbackRelease_Call{Call: _e.mock.On("RollbackRelease", spec)} +} + +func (_c *MockRollBack_RollbackRelease_Call) Run(run func(spec *ChartSpec)) *MockRollBack_RollbackRelease_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*ChartSpec)) + }) + return _c +} + +func (_c *MockRollBack_RollbackRelease_Call) Return(_a0 error) *MockRollBack_RollbackRelease_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockRollBack_RollbackRelease_Call) RunAndReturn(run func(*ChartSpec) error) *MockRollBack_RollbackRelease_Call { + _c.Call.Return(run) + return _c +} + +type mockConstructorTestingTNewMockRollBack interface { + mock.TestingT + Cleanup(func()) +} + +// NewMockRollBack creates a new instance of MockRollBack. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewMockRollBack(t mockConstructorTestingTNewMockRollBack) *MockRollBack { + mock := &MockRollBack{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/helm/client/mock_TagResolver_test.go b/pkg/helm/client/mock_TagResolver_test.go new file mode 100644 index 0000000..cc4b4a8 --- /dev/null +++ b/pkg/helm/client/mock_TagResolver_test.go @@ -0,0 +1,87 @@ +// Code generated by mockery v2.20.0. DO NOT EDIT. + +package client + +import mock "github.com/stretchr/testify/mock" + +// MockTagResolver is an autogenerated mock type for the TagResolver type +type MockTagResolver struct { + mock.Mock +} + +type MockTagResolver_Expecter struct { + mock *mock.Mock +} + +func (_m *MockTagResolver) EXPECT() *MockTagResolver_Expecter { + return &MockTagResolver_Expecter{mock: &_m.Mock} +} + +// Tags provides a mock function with given fields: ref +func (_m *MockTagResolver) Tags(ref string) ([]string, error) { + ret := _m.Called(ref) + + var r0 []string + var r1 error + if rf, ok := ret.Get(0).(func(string) ([]string, error)); ok { + return rf(ref) + } + if rf, ok := ret.Get(0).(func(string) []string); ok { + r0 = rf(ref) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]string) + } + } + + if rf, ok := ret.Get(1).(func(string) error); ok { + r1 = rf(ref) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockTagResolver_Tags_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Tags' +type MockTagResolver_Tags_Call struct { + *mock.Call +} + +// Tags is a helper method to define mock.On call +// - ref string +func (_e *MockTagResolver_Expecter) Tags(ref interface{}) *MockTagResolver_Tags_Call { + return &MockTagResolver_Tags_Call{Call: _e.mock.On("Tags", ref)} +} + +func (_c *MockTagResolver_Tags_Call) Run(run func(ref string)) *MockTagResolver_Tags_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *MockTagResolver_Tags_Call) Return(_a0 []string, _a1 error) *MockTagResolver_Tags_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockTagResolver_Tags_Call) RunAndReturn(run func(string) ([]string, error)) *MockTagResolver_Tags_Call { + _c.Call.Return(run) + return _c +} + +type mockConstructorTestingTNewMockTagResolver interface { + mock.TestingT + Cleanup(func()) +} + +// NewMockTagResolver creates a new instance of MockTagResolver. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewMockTagResolver(t mockConstructorTestingTNewMockTagResolver) *MockTagResolver { + mock := &MockTagResolver{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/helm/mock_HelmClient_test.go b/pkg/helm/mock_HelmClient_test.go index e7e2424..b406b52 100644 --- a/pkg/helm/mock_HelmClient_test.go +++ b/pkg/helm/mock_HelmClient_test.go @@ -89,6 +89,60 @@ func (_c *MockHelmClient_GetChart_Call) RunAndReturn(run func(*client.ChartSpec) return _c } +// GetChartSpecValues provides a mock function with given fields: spec +func (_m *MockHelmClient) GetChartSpecValues(spec *client.ChartSpec) (map[string]interface{}, error) { + ret := _m.Called(spec) + + var r0 map[string]interface{} + var r1 error + if rf, ok := ret.Get(0).(func(*client.ChartSpec) (map[string]interface{}, error)); ok { + return rf(spec) + } + if rf, ok := ret.Get(0).(func(*client.ChartSpec) map[string]interface{}); ok { + r0 = rf(spec) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(map[string]interface{}) + } + } + + if rf, ok := ret.Get(1).(func(*client.ChartSpec) error); ok { + r1 = rf(spec) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockHelmClient_GetChartSpecValues_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetChartSpecValues' +type MockHelmClient_GetChartSpecValues_Call struct { + *mock.Call +} + +// GetChartSpecValues is a helper method to define mock.On call +// - spec *client.ChartSpec +func (_e *MockHelmClient_Expecter) GetChartSpecValues(spec interface{}) *MockHelmClient_GetChartSpecValues_Call { + return &MockHelmClient_GetChartSpecValues_Call{Call: _e.mock.On("GetChartSpecValues", spec)} +} + +func (_c *MockHelmClient_GetChartSpecValues_Call) Run(run func(spec *client.ChartSpec)) *MockHelmClient_GetChartSpecValues_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*client.ChartSpec)) + }) + return _c +} + +func (_c *MockHelmClient_GetChartSpecValues_Call) Return(_a0 map[string]interface{}, _a1 error) *MockHelmClient_GetChartSpecValues_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockHelmClient_GetChartSpecValues_Call) RunAndReturn(run func(*client.ChartSpec) (map[string]interface{}, error)) *MockHelmClient_GetChartSpecValues_Call { + _c.Call.Return(run) + return _c +} + // GetRelease provides a mock function with given fields: name func (_m *MockHelmClient) GetRelease(name string) (*release.Release, error) { ret := _m.Called(name) From 49757a3fab4940dd11c7ac1ee0dfa31269b23327 Mon Sep 17 00:00:00 2001 From: meiserloh Date: Tue, 14 Nov 2023 14:57:15 +0100 Subject: [PATCH 24/32] #40 fix failing tests --- pkg/controllers/componentController_test.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pkg/controllers/componentController_test.go b/pkg/controllers/componentController_test.go index 95f3edb..71d023f 100644 --- a/pkg/controllers/componentController_test.go +++ b/pkg/controllers/componentController_test.go @@ -215,6 +215,8 @@ func Test_componentReconciler_Reconcile(t *testing.T) { helmClient := newMockHelmClient(t) helmReleases := []*release.Release{{Name: "dogu-op", Namespace: testNamespace, Chart: &chart.Chart{Metadata: &chart.Metadata{AppVersion: "0.1.0"}}}} helmClient.EXPECT().ListDeployedReleases().Return(helmReleases, nil) + helmClient.EXPECT().GetReleaseValues("dogu-op", false).Return(map[string]interface{}{}, nil) + helmClient.EXPECT().GetChartSpecValues(component.GetHelmChartSpec()).Return(map[string]interface{}{}, nil) sut := componentReconciler{ clientSet: clientSetMock, @@ -471,6 +473,8 @@ func Test_componentReconciler_getChangeOperation(t *testing.T) { mockHelmClient := newMockHelmClient(t) helmReleases := []*release.Release{{Name: "dogu-op", Namespace: "ecosystem", Chart: &chart.Chart{Metadata: &chart.Metadata{AppVersion: "0.0.1"}}}} mockHelmClient.EXPECT().ListDeployedReleases().Return(helmReleases, nil) + mockHelmClient.EXPECT().GetReleaseValues("dogu-op", false).Return(map[string]interface{}{}, nil) + mockHelmClient.EXPECT().GetChartSpecValues(component.GetHelmChartSpec()).Return(map[string]interface{}{}, nil) sut := componentReconciler{ helmClient: mockHelmClient, From 64165e29b7a4bca3a0c476f6f5020f6893721a52 Mon Sep 17 00:00:00 2001 From: meiserloh Date: Tue, 14 Nov 2023 15:10:55 +0100 Subject: [PATCH 25/32] #40 add unit tests for componentController --- pkg/controllers/componentController.go | 2 +- pkg/controllers/componentController_test.go | 108 ++++++++++++++++++++ 2 files changed, 109 insertions(+), 1 deletion(-) diff --git a/pkg/controllers/componentController.go b/pkg/controllers/componentController.go index 2887f7c..10136e7 100644 --- a/pkg/controllers/componentController.go +++ b/pkg/controllers/componentController.go @@ -273,7 +273,7 @@ func (r *componentReconciler) isValuesChanged(deployedRelease *release.Release, chartSpecValues, err := r.helmClient.GetChartSpecValues(component.GetHelmChartSpec()) if err != nil { - return false, fmt.Errorf("failed to get values.yaml from chart spec %s: %w", component.GetHelmChartSpec().ChartName, err) + return false, fmt.Errorf("failed to get values.yaml from component %s: %w", component.GetHelmChartSpec().ChartName, err) } // if no additional values are set, the maps will look like this: diff --git a/pkg/controllers/componentController_test.go b/pkg/controllers/componentController_test.go index 71d023f..7664399 100644 --- a/pkg/controllers/componentController_test.go +++ b/pkg/controllers/componentController_test.go @@ -391,6 +391,51 @@ func Test_componentReconciler_getChangeOperation(t *testing.T) { assert.ErrorContains(t, err, "failed to parse component version") }) + t.Run("should fail on error getting release values", func(t *testing.T) { + // given + component := getComponent("ecosystem", "k8s", "", "dogu-op", "0.0.1") + mockHelmClient := newMockHelmClient(t) + helmReleases := []*release.Release{{Name: "dogu-op", Namespace: "ecosystem", Chart: &chart.Chart{Metadata: &chart.Metadata{AppVersion: "0.0.1"}}}} + mockHelmClient.EXPECT().ListDeployedReleases().Return(helmReleases, nil) + mockHelmClient.EXPECT().GetReleaseValues("dogu-op", false).Return(nil, assert.AnError) + + sut := componentReconciler{ + helmClient: mockHelmClient, + } + + // when + _, err := sut.getChangeOperation(testCtx, component) + + // then + require.Error(t, err) + assert.ErrorIs(t, err, assert.AnError) + assert.ErrorContains(t, err, "failed to compare Values.yaml files of component") + assert.ErrorContains(t, err, "failed to get values.yaml from release") + }) + + t.Run("should fail on error getting component values", func(t *testing.T) { + // given + component := getComponent("ecosystem", "k8s", "", "dogu-op", "0.0.1") + mockHelmClient := newMockHelmClient(t) + helmReleases := []*release.Release{{Name: "dogu-op", Namespace: "ecosystem", Chart: &chart.Chart{Metadata: &chart.Metadata{AppVersion: "0.0.1"}}}} + mockHelmClient.EXPECT().ListDeployedReleases().Return(helmReleases, nil) + mockHelmClient.EXPECT().GetReleaseValues("dogu-op", false).Return(map[string]interface{}{}, nil) + mockHelmClient.EXPECT().GetChartSpecValues(component.GetHelmChartSpec()).Return(nil, assert.AnError) + + sut := componentReconciler{ + helmClient: mockHelmClient, + } + + // when + _, err := sut.getChangeOperation(testCtx, component) + + // then + require.Error(t, err) + assert.ErrorIs(t, err, assert.AnError) + assert.ErrorContains(t, err, "failed to compare Values.yaml files of component") + assert.ErrorContains(t, err, "failed to get values.yaml from component") + }) + t.Run("should return downgrade-operation on downgrade", func(t *testing.T) { // given component := getComponent("ecosystem", "k8s", "", "dogu-op", "0.0.0") @@ -467,6 +512,69 @@ func Test_componentReconciler_getChangeOperation(t *testing.T) { assert.Equal(t, Upgrade, op) }) + t.Run("should return upgrade-operation on same version, but values-yaml difference", func(t *testing.T) { + // given + component := getComponent("ecosystem", "k8s", "", "dogu-op", "0.0.2") + mockHelmClient := newMockHelmClient(t) + helmReleases := []*release.Release{{Name: "dogu-op", Namespace: "ecosystem", Chart: &chart.Chart{Metadata: &chart.Metadata{AppVersion: "0.0.2"}}}} + mockHelmClient.EXPECT().ListDeployedReleases().Return(helmReleases, nil) + mockHelmClient.EXPECT().GetReleaseValues("dogu-op", false).Return(map[string]interface{}{"foo": "bar", "baz": "buz"}, nil) + mockHelmClient.EXPECT().GetChartSpecValues(component.GetHelmChartSpec()).Return(map[string]interface{}{"foo": "bar", "baz": "xyz"}, nil) + + sut := componentReconciler{ + helmClient: mockHelmClient, + } + + // when + op, err := sut.getChangeOperation(testCtx, component) + + // then + require.NoError(t, err) + assert.Equal(t, Upgrade, op) + }) + + t.Run("should return ignore-operation on same version and same values-yaml values", func(t *testing.T) { + // given + component := getComponent("ecosystem", "k8s", "", "dogu-op", "0.0.2") + mockHelmClient := newMockHelmClient(t) + helmReleases := []*release.Release{{Name: "dogu-op", Namespace: "ecosystem", Chart: &chart.Chart{Metadata: &chart.Metadata{AppVersion: "0.0.2"}}}} + mockHelmClient.EXPECT().ListDeployedReleases().Return(helmReleases, nil) + mockHelmClient.EXPECT().GetReleaseValues("dogu-op", false).Return(map[string]interface{}{"foo": "bar", "baz": "buz"}, nil) + mockHelmClient.EXPECT().GetChartSpecValues(component.GetHelmChartSpec()).Return(map[string]interface{}{"foo": "bar", "baz": "buz"}, nil) + + sut := componentReconciler{ + helmClient: mockHelmClient, + } + + // when + op, err := sut.getChangeOperation(testCtx, component) + + // then + require.NoError(t, err) + assert.Equal(t, Ignore, op) + }) + + t.Run("should return ignore-operation on same version and different zero-length maps", func(t *testing.T) { + // given + component := getComponent("ecosystem", "k8s", "", "dogu-op", "0.0.2") + mockHelmClient := newMockHelmClient(t) + helmReleases := []*release.Release{{Name: "dogu-op", Namespace: "ecosystem", Chart: &chart.Chart{Metadata: &chart.Metadata{AppVersion: "0.0.2"}}}} + mockHelmClient.EXPECT().ListDeployedReleases().Return(helmReleases, nil) + mockHelmClient.EXPECT().GetReleaseValues("dogu-op", false).Return(map[string]interface{}(nil), nil) + mockHelmClient.EXPECT().GetChartSpecValues(component.GetHelmChartSpec()).Return(map[string]interface{}{}, nil) + + sut := componentReconciler{ + helmClient: mockHelmClient, + } + + // when + op, err := sut.getChangeOperation(testCtx, component) + + // then + require.NoError(t, err) + assert.Equal(t, Ignore, op) + }) + t.Run("should return ignore-operation on same version", func(t *testing.T) { // given component := getComponent("ecosystem", "k8s", "", "dogu-op", "0.0.1") From 65d6ecacb89995ed2048aabd8abfe0d2ac224a41 Mon Sep 17 00:00:00 2001 From: meiserloh Date: Tue, 14 Nov 2023 16:08:12 +0100 Subject: [PATCH 26/32] #40 add unit tests for helm client --- pkg/helm/client/client.go | 2 +- pkg/helm/client/client_test.go | 163 +++++++++++++++++++++++++++++++++ pkg/helm/client_test.go | 45 +++++++++ 3 files changed, 209 insertions(+), 1 deletion(-) diff --git a/pkg/helm/client/client.go b/pkg/helm/client/client.go index 7bd4657..bab0116 100644 --- a/pkg/helm/client/client.go +++ b/pkg/helm/client/client.go @@ -197,7 +197,7 @@ func (c *HelmClient) GetChartSpecValues(spec *ChartSpec) (map[string]interface{} p := getter.All(c.Settings) additionalValuesYaml, err := spec.GetValuesMap(p) if err != nil { - return nil, fmt.Errorf("failed to get additional values.yaml-values from %s: %w", spec.ChartName, err) + return nil, fmt.Errorf("failed to get additional values.yaml-values from %s: %w", spec.ChartName, err) } return additionalValuesYaml, nil diff --git a/pkg/helm/client/client_test.go b/pkg/helm/client/client_test.go index ded8bfe..cec661b 100644 --- a/pkg/helm/client/client_test.go +++ b/pkg/helm/client/client_test.go @@ -2,6 +2,7 @@ package client import ( "context" + "github.com/cloudogu/k8s-component-operator/pkg/helm/client/values" "github.com/stretchr/testify/mock" "helm.sh/helm/v3/pkg/chart" "log" @@ -338,6 +339,168 @@ func TestHelmClient_GetReleaseValues(t *testing.T) { }) } +func TestHelmClient_GetChartSpecValues(t *testing.T) { + t.Run("should use ValuesYaml when no ValuesOptions are set", func(t *testing.T) { + // given + spec := &ChartSpec{ + ReleaseName: "test-release", + ChartName: "test-chart", + ValuesYaml: ` +testYaml: + key1: val1 + key2: val2 +`, + } + + sut := &HelmClient{ + Settings: &cli.EnvSettings{}, + } + + // when + actual, err := sut.GetChartSpecValues(spec) + + // then + expected := map[string]interface{}{ + "testYaml": map[string]interface{}{ + "key1": "val1", + "key2": "val2", + }, + } + require.NoError(t, err) + assert.Equal(t, actual, expected) + }) + + t.Run("should use ValuesOptions when no ValuesYaml are set", func(t *testing.T) { + // given + spec := &ChartSpec{ + ReleaseName: "test-release", + ChartName: "test-chart", + ValuesOptions: values.Options{ + StringValues: []string{"testYaml.key3=val3", "testYaml.key4=val4"}, + }, + } + + sut := &HelmClient{ + Settings: &cli.EnvSettings{}, + } + + // when + actual, err := sut.GetChartSpecValues(spec) + + // then + expected := map[string]interface{}{ + "testYaml": map[string]interface{}{ + "key3": "val3", + "key4": "val4", + }, + } + require.NoError(t, err) + assert.Equal(t, actual, expected) + }) + + t.Run("should merge ValuesOptions and ValuesYaml when both are set with Options having priority", func(t *testing.T) { + // given + spec := &ChartSpec{ + ReleaseName: "test-release", + ChartName: "test-chart", + ValuesOptions: values.Options{ + StringValues: []string{"testYaml.key2=val3", "testYaml.key3=val4"}, + }, + ValuesYaml: ` +testYaml: + key1: val1 + key2: val2 +`, + } + + sut := &HelmClient{ + Settings: &cli.EnvSettings{}, + } + + // when + actual, err := sut.GetChartSpecValues(spec) + + // then + expected := map[string]interface{}{ + "testYaml": map[string]interface{}{ + "key1": "val1", + "key2": "val3", + "key3": "val4", + }, + } + require.NoError(t, err) + assert.Equal(t, actual, expected) + }) + + t.Run("should return empty map when nothing set", func(t *testing.T) { + // given + spec := &ChartSpec{ + ReleaseName: "test-release", + ChartName: "test-chart", + } + + sut := &HelmClient{ + Settings: &cli.EnvSettings{}, + } + + // when + actual, err := sut.GetChartSpecValues(spec) + + // then + expected := map[string]interface{}{} + require.NoError(t, err) + assert.Equal(t, actual, expected) + }) + + t.Run("should fail if yaml is not parsable", func(t *testing.T) { + // given + spec := &ChartSpec{ + ReleaseName: "test-release", + ChartName: "test-chart", + ValuesYaml: ` +NoYaml{} +`, + } + + sut := &HelmClient{ + Settings: &cli.EnvSettings{}, + } + + // when + actual, err := sut.GetChartSpecValues(spec) + + // then + require.Error(t, err) + assert.Nil(t, actual) + assert.ErrorContains(t, err, "Failed to Parse ValuesYaml") + assert.ErrorContains(t, err, "failed to get additional values.yaml-values from") + }) + + t.Run("should fail if values options are not parsable", func(t *testing.T) { + // given + spec := &ChartSpec{ + ReleaseName: "test-release", + ChartName: "test-chart", + ValuesOptions: values.Options{ + StringValues: []string{"noKeyValue{}"}, + }, + } + + sut := &HelmClient{ + Settings: &cli.EnvSettings{}, + } + + // when + actual, err := sut.GetChartSpecValues(spec) + + // then + require.Error(t, err) + assert.Nil(t, actual) + assert.ErrorContains(t, err, "Failed to Parse ValuesOptions") + assert.ErrorContains(t, err, "failed to get additional values.yaml-values from") + }) +} + func TestHelmClient_ListDeployedReleases(t *testing.T) { t.Run("should fail to list deployed releases", func(t *testing.T) { // given diff --git a/pkg/helm/client_test.go b/pkg/helm/client_test.go index 267418a..03ed452 100644 --- a/pkg/helm/client_test.go +++ b/pkg/helm/client_test.go @@ -583,3 +583,48 @@ func Test_sortByVersionDescending(t *testing.T) { }) } } + +func TestClient_GetChartSpecValues(t *testing.T) { + t.Run("should call HelmClient", func(t *testing.T) { + // given + chartSpec := &client.ChartSpec{ + ReleaseName: "k8s-etcd", + ChartName: "oci://some.endpoint/testing/myChart", + } + + mockedHelmClient := NewMockHelmClient(t) + mockedHelmClient.EXPECT().GetChartSpecValues(chartSpec).Return(map[string]interface{}{"key": "val"}, assert.AnError) + + sut := &Client{ + helmClient: mockedHelmClient, + } + + // when + values, err := sut.GetChartSpecValues(chartSpec) + + require.Error(t, err) + require.ErrorIs(t, err, assert.AnError) + assert.Equal(t, 1, len(values)) + assert.Equal(t, "val", values["key"]) + }) +} + +func TestClient_GetReleaseValues(t *testing.T) { + t.Run("should call HelmClient", func(t *testing.T) { + // given + mockedHelmClient := NewMockHelmClient(t) + mockedHelmClient.EXPECT().GetReleaseValues("name", false).Return(map[string]interface{}{"key": "val"}, assert.AnError) + + sut := &Client{ + helmClient: mockedHelmClient, + } + + // when + values, err := sut.GetReleaseValues("name", false) + + require.Error(t, err) + require.ErrorIs(t, err, assert.AnError) + assert.Equal(t, 1, len(values)) + assert.Equal(t, "val", values["key"]) + }) +} From d3a8dd5538b9e1454323c0061ab945470649192f Mon Sep 17 00:00:00 2001 From: meiserloh Date: Thu, 16 Nov 2023 13:59:15 +0100 Subject: [PATCH 27/32] #40 add documentation --- docs/operations/managing_components_de.md | 17 ++++++++++++----- docs/operations/managing_components_en.md | 17 ++++++++++++----- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/docs/operations/managing_components_de.md b/docs/operations/managing_components_de.md index 15df73d..f9ddffd 100644 --- a/docs/operations/managing_components_de.md +++ b/docs/operations/managing_components_de.md @@ -48,17 +48,22 @@ $ helm uninstall -n ecosystem k8s-component-operator Um Komponenten zu installieren oder zu aktualisieren, muss jeweils eine _Custom Resource_ (CR) für die gewünschte Komponente auf den Cluster im korrekten Cluster-Namespace angewendet werden. -Beispiel einer Komponenten-Ressource (z. B. als `k8s-dogu-operator.yaml` und aus dem Helm-Registry-Namespace `k8s`): +Beispiel einer Komponenten-Ressource (z. B. als `k8s-longhorn.yaml` und aus dem Helm-Registry-Namespace `k8s`): ```yaml apiVersion: k8s.cloudogu.com/v1 kind: Component metadata: - name: k8s-dogu-operator + name: k8s-longhorn spec: - name: k8s-dogu-operator + name: k8s-longhorn namespace: k8s - version: 0.35.0 + version: 1.5.1-1 + deployNamespace: longhorn-system + valuesYamlOverwrite: | + longhorn: + defaultSettings: + backupTargetCredentialSecret: my-longhorn-backup-target ``` > [!IMPORTANT] @@ -68,7 +73,7 @@ spec: Diese CR kann dann auf den Cluster angewendet werden: ```bash -kubectl -n ecosystem apply -f k8s-dogu-operator.yaml +kubectl -n ecosystem apply -f k8s-longhorn.yaml ``` Der Komponenten-Operator beginnt nun mit der Installation der Komponente. Abhängigkeiten zu anderen k8s-CES-Komponenten und deren Versionen müssen erfüllt sein (dies überprüft der Komponenten-Operator). Weitere Informationen zu diesem Thema befinden sich im Abschnitt [Abhängigkeiten zu anderen Komponenten](#Abhängigkeiten-zu-anderen-Komponenten). @@ -85,6 +90,8 @@ Ein Komponenten-CR besteht aus unterschiedlichen Feldern. Dieser Abschnitt erlä - Mittels unterschiedlicher Komponenten-Namespaces können unterschiedliche Versionen ausgebracht werden (z. B. zu Debugging-Zwecken). - Es handelt sich hierbei _nicht_ um den Cluster-Namespace. - `.spec.version`: Die Version der Komponente in der Helm-Registry. +- `.spec.deployNamespace`: (optional) Der k8s-Namespace, in dem alle Ressourcen der Komponente deployed werden sollen. Wenn dieser leer ist, wird der Namespace des Komponenten-Operators verwendet. +- `.spec.valuesYamlOverwrite`: (optional) Helm-Werte zum Überschreiben von Konfigurationen aus der Helm-Datei values.yaml. Sollte aus Gründen der Lesbarkeit als [multiline-yaml](https://yaml-multiline.info/) geschrieben werden. ## Komponenten deinstallieren diff --git a/docs/operations/managing_components_en.md b/docs/operations/managing_components_en.md index 217e740..d337d73 100644 --- a/docs/operations/managing_components_en.md +++ b/docs/operations/managing_components_en.md @@ -48,17 +48,22 @@ $ helm uninstall -n ecosystem k8s-component-operator To install or upgrade components, a _Custom Resource_ (CR) for each desired component must be applied to the cluster in the correct cluster namespace. -Example of a component resource (e.g. as `k8s-dogu-operator.yaml` and from the Helm registry namespace `k8s`): +Example of a component resource (e.g. as `k8s-longhorn.yaml` and from the Helm registry namespace `k8s`): ```yaml apiVersion: k8s.cloudogu.com/v1 kind: Component metadata: - name: k8s-dogu-operator + name: k8s-longhorn spec: - name: k8s-dogu-operator + name: k8s-longhorn namespace: k8s - version: 0.35.0 + version: 1.5.1-1 + deployNamespace: longhorn-system + valuesYamlOverwrite: | + longhorn: + defaultSettings: + backupTargetCredentialSecret: my-longhorn-backup-target ``` > [!IMPORTANT] @@ -68,7 +73,7 @@ spec: CRs like this can then be applied to the cluster: ```bash -kubectl -n ecosystem apply -f k8s-dogu-operator.yaml +kubectl -n ecosystem apply -f k8s-longhorn.yaml ``` The component operator now starts installing the component. Dependencies to other k8s-CES components and their versions must be fulfilled (this is checked by the component operator). For more information on this topic can be found in the section [Dependencies to other components](#Dependencies-to-other-components). @@ -85,6 +90,8 @@ A component CR consists of various fields. This section describes these: - Using different component namespaces, different versions could be deployed (e.g. for debugging purposes). - This is _not_ the cluster namespace. - `.spec.version`: The version of the component in the helm registry. +- `.spec.deployNamespace`: (optional) The k8s-namespace, where all resources of the component should be deployed. If this is empty the namespace of the component-operator will be used. +- `.spec.valuesYamlOverwrite`: (optional) Helm-Values to overwrite configurations of the default values.yaml file. Should be writte as a [multiline-yaml](https://yaml-multiline.info/) string for readability. ## Uninstall components From 27011928eb698f1b475aa1f0b1d9e47c0336901e Mon Sep 17 00:00:00 2001 From: meiserloh Date: Thu, 16 Nov 2023 14:22:41 +0100 Subject: [PATCH 28/32] #40 add changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3fb230d..8baff5b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Added +- [#40] Components default values.yaml can be overwritten (with the field valuesYamlOverwrite) ## [v0.5.1] - 2023-10-11 ### Changed From 0c22e62834aa017976799f77365021f28c39430a Mon Sep 17 00:00:00 2001 From: kahoona77 Date: Thu, 16 Nov 2023 16:22:44 +0100 Subject: [PATCH 29/32] Update docs/operations/managing_components_en.md --- docs/operations/managing_components_en.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/operations/managing_components_en.md b/docs/operations/managing_components_en.md index d337d73..97bddee 100644 --- a/docs/operations/managing_components_en.md +++ b/docs/operations/managing_components_en.md @@ -91,7 +91,7 @@ A component CR consists of various fields. This section describes these: - This is _not_ the cluster namespace. - `.spec.version`: The version of the component in the helm registry. - `.spec.deployNamespace`: (optional) The k8s-namespace, where all resources of the component should be deployed. If this is empty the namespace of the component-operator will be used. -- `.spec.valuesYamlOverwrite`: (optional) Helm-Values to overwrite configurations of the default values.yaml file. Should be writte as a [multiline-yaml](https://yaml-multiline.info/) string for readability. +- `.spec.valuesYamlOverwrite`: (optional) Helm-Values to overwrite configurations of the default values.yaml file. Should be written as a [multiline-yaml](https://yaml-multiline.info/) string for readability. ## Uninstall components From 3fe4be369ff51eca8b48922cf5c75c5be28932ff Mon Sep 17 00:00:00 2001 From: Benjamin Ernst Date: Thu, 16 Nov 2023 16:26:06 +0100 Subject: [PATCH 30/32] #40 update component-yamls --- config/crd/bases/k8s.cloudogu.com_components.yaml | 6 ++++++ pkg/api/v1/k8s.cloudogu.com_components.yaml | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/config/crd/bases/k8s.cloudogu.com_components.yaml b/config/crd/bases/k8s.cloudogu.com_components.yaml index 1dd9888..155b6b5 100644 --- a/config/crd/bases/k8s.cloudogu.com_components.yaml +++ b/config/crd/bases/k8s.cloudogu.com_components.yaml @@ -50,6 +50,12 @@ spec: namespace: description: Namespace of the component (e.g. k8s) type: string + valuesYamlOverwrite: + description: ValuesYamlOverwrite is a multiline-yaml string that is + applied alongside the original values.yaml-file of the component. + It can be used to overwrite specific configurations. Lists are overwritten, + maps are merged. + type: string version: description: Version of the component (e.g. 2.4.48-3) type: string diff --git a/pkg/api/v1/k8s.cloudogu.com_components.yaml b/pkg/api/v1/k8s.cloudogu.com_components.yaml index 1dd9888..155b6b5 100644 --- a/pkg/api/v1/k8s.cloudogu.com_components.yaml +++ b/pkg/api/v1/k8s.cloudogu.com_components.yaml @@ -50,6 +50,12 @@ spec: namespace: description: Namespace of the component (e.g. k8s) type: string + valuesYamlOverwrite: + description: ValuesYamlOverwrite is a multiline-yaml string that is + applied alongside the original values.yaml-file of the component. + It can be used to overwrite specific configurations. Lists are overwritten, + maps are merged. + type: string version: description: Version of the component (e.g. 2.4.48-3) type: string From 47ea29356f4577902d6ae5372bbeb42ede6626b6 Mon Sep 17 00:00:00 2001 From: Benjamin Ernst Date: Thu, 16 Nov 2023 16:32:23 +0100 Subject: [PATCH 31/32] Bump version --- Dockerfile | 2 +- Makefile | 2 +- config/manager/kustomization.yaml | 14 +++++++------- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Dockerfile b/Dockerfile index 7a49340..664e0cb 100644 --- a/Dockerfile +++ b/Dockerfile @@ -35,7 +35,7 @@ RUN make compile-generic FROM gcr.io/distroless/static:nonroot LABEL maintainer="hello@cloudogu.com" \ NAME="k8s-component-operator" \ - VERSION="0.5.1" + VERSION="0.6.0" WORKDIR / COPY --from=builder /workspace/target/k8s-component-operator . diff --git a/Makefile b/Makefile index 3d4afb2..9c8afe2 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ # Set these to the desired values ARTIFACT_ID=k8s-component-operator -VERSION=0.5.1 +VERSION=0.6.0 ## Image URL to use all building/pushing image targets IMAGE_DEV=${K3CES_REGISTRY_URL_PREFIX}/${ARTIFACT_ID}:${VERSION} IMAGE=cloudogu/${ARTIFACT_ID}:${VERSION} diff --git a/config/manager/kustomization.yaml b/config/manager/kustomization.yaml index b03d9cb..89dbe0e 100644 --- a/config/manager/kustomization.yaml +++ b/config/manager/kustomization.yaml @@ -1,14 +1,14 @@ resources: -- manager.yaml + - manager.yaml generatorOptions: disableNameSuffixHash: true configMapGenerator: -- files: - - controller_manager_config.yaml - name: manager-config + - files: + - controller_manager_config.yaml + name: manager-config apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization images: -- name: controller - newName: cloudogu/k8s-component-operator - newTag: 0.5.1 + - name: controller + newName: cloudogu/k8s-component-operator + newTag: 0.6.0 From 213bd0b5da6db5d327b94ead87b5319d2cf09122 Mon Sep 17 00:00:00 2001 From: Benjamin Ernst Date: Thu, 16 Nov 2023 16:32:35 +0100 Subject: [PATCH 32/32] Update changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 112e319..8b583ee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] + +## [v0.6.0] - 2023-11-16 ### Added - [#40] Components default values.yaml can be overwritten (with the field valuesYamlOverwrite) - [#38] Add [documentation](docs/operations/creating_components_en.md) for creating components and component-patch-templates