From c3c1429dbd1be9c30aab885a49bbcc455ccec557 Mon Sep 17 00:00:00 2001 From: Salah Aldeen Al Saleh Date: Wed, 6 Nov 2024 11:13:57 -0800 Subject: [PATCH 1/6] Add test for introducing a required config item in EC updates --- pkg/pull/interface.go | 21 ++++++++++++ pkg/pull/pull.go | 6 +++- pkg/upgradeservice/bootstrap_test.go | 38 ++++++++++++++++++++++ pkg/upgradeservice/testassets/license.yaml | 36 ++++++++++++++++++++ 4 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 pkg/pull/interface.go create mode 100644 pkg/upgradeservice/bootstrap_test.go create mode 100644 pkg/upgradeservice/testassets/license.yaml diff --git a/pkg/pull/interface.go b/pkg/pull/interface.go new file mode 100644 index 0000000000..4f84f70e8c --- /dev/null +++ b/pkg/pull/interface.go @@ -0,0 +1,21 @@ +package pull + +var p PullerInterface + +func init() { + SetPuller(&Puller{}) +} + +func SetPuller(_p PullerInterface) { + p = _p +} + +type PullerInterface interface { + Pull(upstreamURI string, pullOptions PullOptions) (string, error) +} + +// Convenience functions + +func Pull(upstreamURI string, pullOptions PullOptions) (string, error) { + return p.Pull(upstreamURI, pullOptions) +} diff --git a/pkg/pull/pull.go b/pkg/pull/pull.go index 0962bee32b..a3e6a0f457 100644 --- a/pkg/pull/pull.go +++ b/pkg/pull/pull.go @@ -39,6 +39,10 @@ import ( "k8s.io/client-go/kubernetes/scheme" ) +type Puller struct{} + +var _ PullerInterface = (*Puller)(nil) + type PullOptions struct { RootDir string Namespace string @@ -107,7 +111,7 @@ func PullApplicationMetadata(upstreamURI string, versionLabel string) (*replicat // Pull will download the application specified in upstreamURI using the options // specified in pullOptions. It returns the directory that the app was pulled to -func Pull(upstreamURI string, pullOptions PullOptions) (string, error) { +func (p *Puller) Pull(upstreamURI string, pullOptions PullOptions) (string, error) { log := logger.NewCLILogger(os.Stdout) if pullOptions.Silent { diff --git a/pkg/upgradeservice/bootstrap_test.go b/pkg/upgradeservice/bootstrap_test.go new file mode 100644 index 0000000000..eea9a7d5b2 --- /dev/null +++ b/pkg/upgradeservice/bootstrap_test.go @@ -0,0 +1,38 @@ +package upgradeservice + +import ( + _ "embed" + "testing" + + "github.com/replicatedhq/kots/pkg/pull" + "github.com/replicatedhq/kots/pkg/upgradeservice/types" +) + +//go:embed testassets/license.yaml +var testLicense string + +func Test_bootstrap(t *testing.T) { + pull.SetPuller(&MockPuller{ + PullFunc: func(upstreamURI string, pullOptions pull.PullOptions) (string, error) { + return "", pull.ErrConfigNeeded + }, + }) + + params := types.UpgradeServiceParams{ + AppLicense: testLicense, + AppArchive: t.TempDir(), + } + + err := bootstrap(params) + if err != nil { + t.Errorf("expected no error when ErrConfigNeeded is returned, got %v", err) + } +} + +type MockPuller struct { + PullFunc func(upstreamURI string, pullOptions pull.PullOptions) (string, error) +} + +func (m *MockPuller) Pull(upstreamURI string, pullOptions pull.PullOptions) (string, error) { + return m.PullFunc(upstreamURI, pullOptions) +} diff --git a/pkg/upgradeservice/testassets/license.yaml b/pkg/upgradeservice/testassets/license.yaml new file mode 100644 index 0000000000..8b799958db --- /dev/null +++ b/pkg/upgradeservice/testassets/license.yaml @@ -0,0 +1,36 @@ +apiVersion: kots.io/v1beta1 +kind: License +metadata: + name: test-license +spec: + appSlug: fake-app-slug + channelID: fake-channel-id + channelName: fake-channel-name + channels: + - channelID: fake-channel-id + channelName: fake-channel-name + channelSlug: fake-channel-slug + endpoint: https://fake-endpoint.com + isDefault: true + replicatedProxyDomain: fake-replicated-proxy.test.net + customerEmail: salah@replicated.com + customerName: Salah EC Dev + endpoint: https://fake-endpoint.com + entitlements: + expires_at: + description: License Expiration + signature: {} + title: Expiration + value: "" + valueType: String + isDisasterRecoverySupported: true + isEmbeddedClusterDownloadEnabled: true + isKotsInstallEnabled: true + isNewKotsUiEnabled: true + isSnapshotSupported: true + isSupportBundleUploadSupported: true + licenseID: fake-license-id + licenseSequence: 4 + licenseType: dev + replicatedProxyDomain: fake-replicated-proxy.test.net + signature: ZmFrZS1zaWduYXR1cmU= From b4e583d0dd49ef05575a93002750e24a2670a58c Mon Sep 17 00:00:00 2001 From: Salah Aldeen Al Saleh Date: Wed, 6 Nov 2024 11:18:01 -0800 Subject: [PATCH 2/6] update test license --- pkg/upgradeservice/testassets/license.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/upgradeservice/testassets/license.yaml b/pkg/upgradeservice/testassets/license.yaml index 8b799958db..814c209cd1 100644 --- a/pkg/upgradeservice/testassets/license.yaml +++ b/pkg/upgradeservice/testassets/license.yaml @@ -13,8 +13,8 @@ spec: endpoint: https://fake-endpoint.com isDefault: true replicatedProxyDomain: fake-replicated-proxy.test.net - customerEmail: salah@replicated.com - customerName: Salah EC Dev + customerEmail: test-customer@replicated.com + customerName: test customer endpoint: https://fake-endpoint.com entitlements: expires_at: From 0b59d26014ec82fe4fa849f9e87aa4d6a49c1526 Mon Sep 17 00:00:00 2001 From: Salah Aldeen Al Saleh Date: Wed, 6 Nov 2024 11:30:51 -0800 Subject: [PATCH 3/6] test cases --- pkg/upgradeservice/bootstrap_test.go | 35 +++++++++++++++++++--------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/pkg/upgradeservice/bootstrap_test.go b/pkg/upgradeservice/bootstrap_test.go index eea9a7d5b2..4ae8d5417c 100644 --- a/pkg/upgradeservice/bootstrap_test.go +++ b/pkg/upgradeservice/bootstrap_test.go @@ -6,26 +6,39 @@ import ( "github.com/replicatedhq/kots/pkg/pull" "github.com/replicatedhq/kots/pkg/upgradeservice/types" + "github.com/stretchr/testify/require" ) //go:embed testassets/license.yaml var testLicense string func Test_bootstrap(t *testing.T) { - pull.SetPuller(&MockPuller{ - PullFunc: func(upstreamURI string, pullOptions pull.PullOptions) (string, error) { - return "", pull.ErrConfigNeeded + tests := []struct { + name string + mockPullFunc func(upstreamURI string, pullOptions pull.PullOptions) (string, error) + }{ + { + name: "does not error when version needs config", + mockPullFunc: func(upstreamURI string, pullOptions pull.PullOptions) (string, error) { + return "", pull.ErrConfigNeeded + }, }, - }) - - params := types.UpgradeServiceParams{ - AppLicense: testLicense, - AppArchive: t.TempDir(), } - err := bootstrap(params) - if err != nil { - t.Errorf("expected no error when ErrConfigNeeded is returned, got %v", err) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + pull.SetPuller(&MockPuller{ + PullFunc: tt.mockPullFunc, + }) + + params := types.UpgradeServiceParams{ + AppLicense: testLicense, + AppArchive: t.TempDir(), + } + + err := bootstrap(params) + require.NoError(t, err) + }) } } From 3c265f2ce9d4103e159b6b0e4d11fa3f17d67397 Mon Sep 17 00:00:00 2001 From: Salah Aldeen Al Saleh Date: Wed, 6 Nov 2024 11:33:13 -0800 Subject: [PATCH 4/6] address feedback --- pkg/pull/interface.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/pull/interface.go b/pkg/pull/interface.go index 4f84f70e8c..61cc0dc901 100644 --- a/pkg/pull/interface.go +++ b/pkg/pull/interface.go @@ -1,13 +1,13 @@ package pull -var p PullerInterface +var _p PullerInterface func init() { SetPuller(&Puller{}) } -func SetPuller(_p PullerInterface) { - p = _p +func SetPuller(p PullerInterface) { + _p = p } type PullerInterface interface { @@ -17,5 +17,5 @@ type PullerInterface interface { // Convenience functions func Pull(upstreamURI string, pullOptions PullOptions) (string, error) { - return p.Pull(upstreamURI, pullOptions) + return _p.Pull(upstreamURI, pullOptions) } From 5925afbef92f328ee4ff6ae5f9cc7871dfe98e5a Mon Sep 17 00:00:00 2001 From: Salah Aldeen Al Saleh Date: Wed, 6 Nov 2024 12:19:30 -0800 Subject: [PATCH 5/6] mock clientset --- pkg/automation/automation.go | 2 +- pkg/docker/registry/registry.go | 2 +- pkg/k8sutil/clientset.go | 6 +++++- pkg/k8sutil/config.go | 2 +- pkg/k8sutil/helm.go | 4 ++-- pkg/k8sutil/interface.go | 23 +++++++++++++++++++++ pkg/k8sutil/kotsadm.go | 30 ++++++++++++++-------------- pkg/k8sutil/portforward.go | 4 ++-- pkg/kotsadm/api.go | 6 +++--- pkg/kotsadm/application_metadata.go | 2 +- pkg/kotsadm/configmaps.go | 8 ++++---- pkg/kotsadm/configvalues.go | 4 ++-- pkg/kotsadm/ingress.go | 4 ++-- pkg/kotsadm/kotsadm.go | 18 ++++++++--------- pkg/kotsadm/license.go | 4 ++-- pkg/kotsadm/limitrange.go | 2 +- pkg/kotsadm/main.go | 18 ++++++++--------- pkg/kotsadm/namespaces.go | 2 +- pkg/kotsadm/rqlite.go | 8 ++++---- pkg/kotsadm/secrets.go | 20 +++++++++---------- pkg/kotsadm/updates.go | 4 ++-- pkg/password/password.go | 2 +- pkg/pull/interface.go | 4 ++-- pkg/snapshot/velero.go | 8 ++++---- pkg/supportbundle/spec.go | 2 +- pkg/upgradeservice/bootstrap_test.go | 24 +++++++++++++++++++--- 26 files changed, 129 insertions(+), 84 deletions(-) create mode 100644 pkg/k8sutil/interface.go diff --git a/pkg/automation/automation.go b/pkg/automation/automation.go index 04b1e9f30b..1be54c89f0 100644 --- a/pkg/automation/automation.go +++ b/pkg/automation/automation.go @@ -124,7 +124,7 @@ func AutomateInstall(opts AutomateInstallOptions) error { return nil } -func installLicenseSecret(clientset *kubernetes.Clientset, licenseSecret corev1.Secret, additionalFiles map[string][]byte) (finalError error) { +func installLicenseSecret(clientset kubernetes.Interface, licenseSecret corev1.Secret, additionalFiles map[string][]byte) (finalError error) { license, ok := licenseSecret.Data["license"] if !ok { return fmt.Errorf("license secret %q does not contain a license field", licenseSecret.Name) diff --git a/pkg/docker/registry/registry.go b/pkg/docker/registry/registry.go index 3d84de17fb..8fb320c306 100644 --- a/pkg/docker/registry/registry.go +++ b/pkg/docker/registry/registry.go @@ -245,7 +245,7 @@ func applicationPullSecretLabels() map[string]string { return secretLabels } -func EnsureDockerHubSecret(username string, password string, namespace string, clientset *kubernetes.Clientset) error { +func EnsureDockerHubSecret(username string, password string, namespace string, clientset kubernetes.Interface) error { dockerHubSecretMutex.Lock() defer dockerHubSecretMutex.Unlock() diff --git a/pkg/k8sutil/clientset.go b/pkg/k8sutil/clientset.go index 4e690adf45..abd6616453 100644 --- a/pkg/k8sutil/clientset.go +++ b/pkg/k8sutil/clientset.go @@ -25,6 +25,10 @@ import ( "sigs.k8s.io/controller-runtime/pkg/log/zap" ) +type K8sutil struct{} + +var _ K8sutilInterface = (*K8sutil)(nil) + const ( DEFAULT_K8S_CLIENT_QPS = 100 DEFAULT_K8S_CLIENT_BURST = 100 @@ -41,7 +45,7 @@ func AddFlags(flags *flag.FlagSet) { kubernetesConfigFlags.AddFlags(flags) } -func GetClientset() (*kubernetes.Clientset, error) { +func (k *K8sutil) GetClientset() (kubernetes.Interface, error) { cfg, err := GetClusterConfig() if err != nil { return nil, errors.Wrap(err, "failed to get cluster config") diff --git a/pkg/k8sutil/config.go b/pkg/k8sutil/config.go index 00bc087913..29498b33d3 100644 --- a/pkg/k8sutil/config.go +++ b/pkg/k8sutil/config.go @@ -11,7 +11,7 @@ import ( "k8s.io/client-go/kubernetes" ) -func GetCurrentRules(deployOptions kotsadmtypes.DeployOptions, clientset *kubernetes.Clientset) ([]rbacv1.PolicyRule, error) { +func GetCurrentRules(deployOptions kotsadmtypes.DeployOptions, clientset kubernetes.Interface) ([]rbacv1.PolicyRule, error) { sar := &authorizationv1.SelfSubjectRulesReview{ Spec: authorizationv1.SelfSubjectRulesReviewSpec{ Namespace: deployOptions.Namespace, diff --git a/pkg/k8sutil/helm.go b/pkg/k8sutil/helm.go index c097684ecd..bdf4d423af 100644 --- a/pkg/k8sutil/helm.go +++ b/pkg/k8sutil/helm.go @@ -14,12 +14,12 @@ func InitHelmCapabilities() error { return errors.Wrap(err, "failed to create kubernetes clientset") } - serverGroups, err := clientset.ServerGroups() + serverGroups, err := clientset.Discovery().ServerGroups() if err != nil { return errors.Wrap(err, "failed to get server groups") } - serverVersion, err := clientset.ServerVersion() + serverVersion, err := clientset.Discovery().ServerVersion() if err != nil { return errors.Wrap(err, "failed to get server version") } diff --git a/pkg/k8sutil/interface.go b/pkg/k8sutil/interface.go new file mode 100644 index 0000000000..dd81cd6873 --- /dev/null +++ b/pkg/k8sutil/interface.go @@ -0,0 +1,23 @@ +package k8sutil + +import "k8s.io/client-go/kubernetes" + +var _k8s K8sutilInterface + +func init() { + Set(&K8sutil{}) +} + +func Set(k8s K8sutilInterface) { + _k8s = k8s +} + +type K8sutilInterface interface { + GetClientset() (kubernetes.Interface, error) +} + +// Convenience functions + +func GetClientset() (kubernetes.Interface, error) { + return _k8s.GetClientset() +} diff --git a/pkg/k8sutil/kotsadm.go b/pkg/k8sutil/kotsadm.go index a3b625bf50..7b639f8405 100644 --- a/pkg/k8sutil/kotsadm.go +++ b/pkg/k8sutil/kotsadm.go @@ -165,7 +165,7 @@ func UpdateKotsadmIDConfigMap(clientset kubernetes.Interface, kotsadmID string) return nil } -func FindKotsadm(clientset *kubernetes.Clientset, namespace string) (string, error) { +func FindKotsadm(clientset kubernetes.Interface, namespace string) (string, error) { pods, err := clientset.CoreV1().Pods(namespace).List(context.TODO(), metav1.ListOptions{LabelSelector: "app=kotsadm"}) if err != nil { return "", errors.Wrap(err, "failed to list pods") @@ -214,7 +214,7 @@ func WaitForKotsadm(clientset kubernetes.Interface, namespace string, timeoutWai } } -func RestartKotsadm(ctx context.Context, clientset *kubernetes.Clientset, namespace string, timeout time.Duration) error { +func RestartKotsadm(ctx context.Context, clientset kubernetes.Interface, namespace string, timeout time.Duration) error { pods, err := clientset.CoreV1().Pods(namespace).List(ctx, metav1.ListOptions{LabelSelector: "app=kotsadm"}) if err != nil { return errors.Wrap(err, "failed to list pods for termination") @@ -261,7 +261,7 @@ func RestartKotsadm(ctx context.Context, clientset *kubernetes.Clientset, namesp } } -func DeleteKotsadm(ctx context.Context, clientset *kubernetes.Clientset, namespace string, isKurl bool) error { +func DeleteKotsadm(ctx context.Context, clientset kubernetes.Interface, namespace string, isKurl bool) error { selectorLabels := map[string]string{ kotsadmtypes.KotsadmKey: kotsadmtypes.KotsadmLabelValue, } @@ -417,7 +417,7 @@ func DeleteKotsadm(ctx context.Context, clientset *kubernetes.Clientset, namespa return nil } -func waitForDeleteServices(ctx context.Context, clientset *kubernetes.Clientset, namespace string, listOptions metav1.ListOptions) error { +func waitForDeleteServices(ctx context.Context, clientset kubernetes.Interface, namespace string, listOptions metav1.ListOptions) error { for { services, err := clientset.CoreV1().Services(namespace).List(ctx, listOptions) if err != nil { @@ -430,7 +430,7 @@ func waitForDeleteServices(ctx context.Context, clientset *kubernetes.Clientset, } } -func waitForDeleteDeployments(ctx context.Context, clientset *kubernetes.Clientset, namespace string, listOptions metav1.ListOptions) error { +func waitForDeleteDeployments(ctx context.Context, clientset kubernetes.Interface, namespace string, listOptions metav1.ListOptions) error { for { deployments, err := clientset.AppsV1().Deployments(namespace).List(context.TODO(), listOptions) if err != nil { @@ -443,7 +443,7 @@ func waitForDeleteDeployments(ctx context.Context, clientset *kubernetes.Clients } } -func waitForDeleteStatefulSets(ctx context.Context, clientset *kubernetes.Clientset, namespace string, listOptions metav1.ListOptions) error { +func waitForDeleteStatefulSets(ctx context.Context, clientset kubernetes.Interface, namespace string, listOptions metav1.ListOptions) error { for { statefulsets, err := clientset.AppsV1().StatefulSets(namespace).List(context.TODO(), listOptions) if err != nil { @@ -456,7 +456,7 @@ func waitForDeleteStatefulSets(ctx context.Context, clientset *kubernetes.Client } } -func waitForDeletePods(ctx context.Context, clientset *kubernetes.Clientset, namespace string, listOptions metav1.ListOptions) error { +func waitForDeletePods(ctx context.Context, clientset kubernetes.Interface, namespace string, listOptions metav1.ListOptions) error { for { pods, err := clientset.CoreV1().Pods(namespace).List(context.TODO(), listOptions) if err != nil { @@ -469,7 +469,7 @@ func waitForDeletePods(ctx context.Context, clientset *kubernetes.Clientset, nam } } -func waitForDeletePVCs(ctx context.Context, clientset *kubernetes.Clientset, namespace string, listOptions metav1.ListOptions) error { +func waitForDeletePVCs(ctx context.Context, clientset kubernetes.Interface, namespace string, listOptions metav1.ListOptions) error { for { pvcs, err := clientset.CoreV1().PersistentVolumeClaims(namespace).List(context.TODO(), listOptions) if err != nil { @@ -482,7 +482,7 @@ func waitForDeletePVCs(ctx context.Context, clientset *kubernetes.Clientset, nam } } -func waitForDeleteSecrets(ctx context.Context, clientset *kubernetes.Clientset, namespace string, listOptions metav1.ListOptions) error { +func waitForDeleteSecrets(ctx context.Context, clientset kubernetes.Interface, namespace string, listOptions metav1.ListOptions) error { for { secrets, err := clientset.CoreV1().Secrets(namespace).List(context.TODO(), listOptions) if err != nil { @@ -495,7 +495,7 @@ func waitForDeleteSecrets(ctx context.Context, clientset *kubernetes.Clientset, } } -func waitForDeleteConfigmaps(ctx context.Context, clientset *kubernetes.Clientset, namespace string, listOptions metav1.ListOptions) error { +func waitForDeleteConfigmaps(ctx context.Context, clientset kubernetes.Interface, namespace string, listOptions metav1.ListOptions) error { for { configmaps, err := clientset.CoreV1().ConfigMaps(namespace).List(context.TODO(), listOptions) if err != nil { @@ -508,7 +508,7 @@ func waitForDeleteConfigmaps(ctx context.Context, clientset *kubernetes.Clientse } } -func waitForDeleteClusterRoleBindings(ctx context.Context, clientset *kubernetes.Clientset, listOptions metav1.ListOptions) error { +func waitForDeleteClusterRoleBindings(ctx context.Context, clientset kubernetes.Interface, listOptions metav1.ListOptions) error { for { crbs, err := clientset.RbacV1().ClusterRoleBindings().List(context.TODO(), listOptions) if err != nil { @@ -521,7 +521,7 @@ func waitForDeleteClusterRoleBindings(ctx context.Context, clientset *kubernetes } } -func waitForDeleteRoleBindings(ctx context.Context, clientset *kubernetes.Clientset, namespace string, listOptions metav1.ListOptions) error { +func waitForDeleteRoleBindings(ctx context.Context, clientset kubernetes.Interface, namespace string, listOptions metav1.ListOptions) error { for { rbs, err := clientset.RbacV1().RoleBindings(namespace).List(context.TODO(), listOptions) if err != nil { @@ -534,7 +534,7 @@ func waitForDeleteRoleBindings(ctx context.Context, clientset *kubernetes.Client } } -func waitForDeleteClusterRoles(ctx context.Context, clientset *kubernetes.Clientset, listOptions metav1.ListOptions) error { +func waitForDeleteClusterRoles(ctx context.Context, clientset kubernetes.Interface, listOptions metav1.ListOptions) error { for { crs, err := clientset.RbacV1().ClusterRoles().List(context.TODO(), listOptions) if err != nil { @@ -547,7 +547,7 @@ func waitForDeleteClusterRoles(ctx context.Context, clientset *kubernetes.Client } } -func waitForDeleteRoles(ctx context.Context, clientset *kubernetes.Clientset, namespace string, listOptions metav1.ListOptions) error { +func waitForDeleteRoles(ctx context.Context, clientset kubernetes.Interface, namespace string, listOptions metav1.ListOptions) error { for { roles, err := clientset.RbacV1().Roles(namespace).List(context.TODO(), listOptions) if err != nil { @@ -560,7 +560,7 @@ func waitForDeleteRoles(ctx context.Context, clientset *kubernetes.Clientset, na } } -func waitForDeleteServiceAccounts(ctx context.Context, clientset *kubernetes.Clientset, namespace string, listOptions metav1.ListOptions) error { +func waitForDeleteServiceAccounts(ctx context.Context, clientset kubernetes.Interface, namespace string, listOptions metav1.ListOptions) error { for { serviceAccounts, err := clientset.CoreV1().ServiceAccounts(namespace).List(context.TODO(), listOptions) if err != nil { diff --git a/pkg/k8sutil/portforward.go b/pkg/k8sutil/portforward.go index dfc8030082..6fac901d2f 100644 --- a/pkg/k8sutil/portforward.go +++ b/pkg/k8sutil/portforward.go @@ -378,7 +378,7 @@ func createDialer(cfg *rest.Config, namespace string, podName string) (httpstrea return spdy.NewDialer(upgrader, &http.Client{Transport: roundTripper}, http.MethodPost, &serverURL), nil } -func ServiceForward(clientset *kubernetes.Clientset, cfg *rest.Config, localPort int, remotePort int, namespace string, serviceName string) (chan struct{}, error) { +func ServiceForward(clientset kubernetes.Interface, cfg *rest.Config, localPort int, remotePort int, namespace string, serviceName string) (chan struct{}, error) { isPortAvailable, err := IsPortAvailable(clientset, localPort) if err != nil { return nil, errors.Wrap(err, "failed to check if port is available") @@ -454,7 +454,7 @@ func ServiceForward(clientset *kubernetes.Clientset, cfg *rest.Config, localPort return stopChan, nil } -func getFirstPod(clientset *kubernetes.Clientset, namespace string, selector string) (string, error) { +func getFirstPod(clientset kubernetes.Interface, namespace string, selector string) (string, error) { options := metav1.ListOptions{LabelSelector: selector} podList, err := clientset.CoreV1().Pods(namespace).List(context.TODO(), options) diff --git a/pkg/kotsadm/api.go b/pkg/kotsadm/api.go index 142b98ac15..3b31d82bf3 100644 --- a/pkg/kotsadm/api.go +++ b/pkg/kotsadm/api.go @@ -12,7 +12,7 @@ import ( ) // removeNodeAPI should be removable when we don't need to support direct upgrade paths from 1.19.6 and before -func removeNodeAPI(deployOptions *types.DeployOptions, clientset *kubernetes.Clientset) error { +func removeNodeAPI(deployOptions *types.DeployOptions, clientset kubernetes.Interface) error { ns := deployOptions.Namespace err := clientset.AppsV1().Deployments(ns).Delete(context.TODO(), "kotsadm-api", metav1.DeleteOptions{}) @@ -35,7 +35,7 @@ func removeNodeAPI(deployOptions *types.DeployOptions, clientset *kubernetes.Cli } // removeNodeAPIRBAC should be removable when we don't need to support direct upgrade paths from 1.19.6 and before -func removeNodeAPIRBAC(deployOptions *types.DeployOptions, clientset *kubernetes.Clientset) error { +func removeNodeAPIRBAC(deployOptions *types.DeployOptions, clientset kubernetes.Interface) error { isClusterScoped, err := isKotsadmClusterScoped(deployOptions) if err != nil { return errors.Wrap(err, "failed to check if kotsadm api is cluster scoped") @@ -60,7 +60,7 @@ func removeNodeAPIRBAC(deployOptions *types.DeployOptions, clientset *kubernetes } // removeNodeAPIClusterRBAC should be removable when we don't need to support direct upgrade paths from 1.19.6 and before -func removeNodeAPIClusterRBAC(deployOptions *types.DeployOptions, clientset *kubernetes.Clientset) error { +func removeNodeAPIClusterRBAC(deployOptions *types.DeployOptions, clientset kubernetes.Interface) error { err := clientset.CoreV1().ServiceAccounts(deployOptions.Namespace).Delete(context.TODO(), "kotsadm-api", metav1.DeleteOptions{}) if err != nil && !kuberneteserrors.IsNotFound(err) { return errors.Wrap(err, "failed to delete api service account") diff --git a/pkg/kotsadm/application_metadata.go b/pkg/kotsadm/application_metadata.go index d660fe5c70..ae21e4ad41 100644 --- a/pkg/kotsadm/application_metadata.go +++ b/pkg/kotsadm/application_metadata.go @@ -27,7 +27,7 @@ func getApplicationMetadataYAML(data []byte, namespace string, upstreamURI strin return docs, nil } -func ensureApplicationMetadata(deployOptions types.DeployOptions, clientset *kubernetes.Clientset) error { +func ensureApplicationMetadata(deployOptions types.DeployOptions, clientset kubernetes.Interface) error { _, err := clientset.CoreV1().ConfigMaps(deployOptions.Namespace).Get(context.TODO(), "kotsadm-application-metadata", metav1.GetOptions{}) if err != nil { if !kuberneteserrors.IsNotFound(err) { diff --git a/pkg/kotsadm/configmaps.go b/pkg/kotsadm/configmaps.go index 71759bb46d..a4c3a3aa89 100644 --- a/pkg/kotsadm/configmaps.go +++ b/pkg/kotsadm/configmaps.go @@ -33,7 +33,7 @@ func getConfigMapsYAML(deployOptions types.DeployOptions) (map[string][]byte, er return docs, nil } -func ensureKotsadmConfig(deployOptions types.DeployOptions, clientset *kubernetes.Clientset) error { +func ensureKotsadmConfig(deployOptions types.DeployOptions, clientset kubernetes.Interface) error { if err := kotsadmresources.EnsurePrivateKotsadmRegistrySecret(deployOptions.Namespace, deployOptions.RegistryConfig, clientset); err != nil { return errors.Wrap(err, "failed to ensure private kotsadm registry secret") } @@ -45,7 +45,7 @@ func ensureKotsadmConfig(deployOptions types.DeployOptions, clientset *kubernete return nil } -func EnsureConfigMaps(deployOptions types.DeployOptions, clientset *kubernetes.Clientset) error { +func EnsureConfigMaps(deployOptions types.DeployOptions, clientset kubernetes.Interface) error { desiredConfigMap := kotsadmobjects.KotsadmConfigMap(deployOptions) existingConfigMap, err := clientset.CoreV1().ConfigMaps(deployOptions.Namespace).Get(context.TODO(), types.KotsadmConfigMap, metav1.GetOptions{}) @@ -77,7 +77,7 @@ func updateConfigMap(existingConfigMap, desiredConfigMap *corev1.ConfigMap) *cor return existingConfigMap } -func ensureWaitForAirgapConfig(deployOptions types.DeployOptions, clientset *kubernetes.Clientset, configMapName string) error { +func ensureWaitForAirgapConfig(deployOptions types.DeployOptions, clientset kubernetes.Interface, configMapName string) error { additionalLabels := map[string]string{ "kots.io/automation": "airgap", } @@ -117,7 +117,7 @@ func ensureWaitForAirgapConfig(deployOptions types.DeployOptions, clientset *kub return nil } -func ensureConfigMapWithData(deployOptions types.DeployOptions, clientset *kubernetes.Clientset, configMapName string, data map[string]string) error { +func ensureConfigMapWithData(deployOptions types.DeployOptions, clientset kubernetes.Interface, configMapName string, data map[string]string) error { configMap, err := configMapWithData(deployOptions, configMapName, data) if err != nil { return errors.Wrap(err, "failed to build config map") diff --git a/pkg/kotsadm/configvalues.go b/pkg/kotsadm/configvalues.go index bba218d3bb..a4cb16f8b9 100644 --- a/pkg/kotsadm/configvalues.go +++ b/pkg/kotsadm/configvalues.go @@ -15,7 +15,7 @@ import ( "k8s.io/client-go/kubernetes/scheme" ) -func ensureConfigValuesSecret(deployOptions *types.DeployOptions, clientset *kubernetes.Clientset) (bool, error) { +func ensureConfigValuesSecret(deployOptions *types.DeployOptions, clientset kubernetes.Interface) (bool, error) { existingSecret, err := getConfigValuesSecret(deployOptions.Namespace, clientset) if err != nil { return false, errors.Wrap(err, "failed to check for existing config values secret") @@ -39,7 +39,7 @@ func ensureConfigValuesSecret(deployOptions *types.DeployOptions, clientset *kub return true, nil } -func getConfigValuesSecret(namespace string, clientset *kubernetes.Clientset) (*corev1.Secret, error) { +func getConfigValuesSecret(namespace string, clientset kubernetes.Interface) (*corev1.Secret, error) { configValuesSecret, err := clientset.CoreV1().Secrets(namespace).Get(context.TODO(), "kotsadm-default-configvalues", metav1.GetOptions{}) if err != nil { if kuberneteserrors.IsNotFound(err) { diff --git a/pkg/kotsadm/ingress.go b/pkg/kotsadm/ingress.go index e63c753ff6..1d6b9fa240 100644 --- a/pkg/kotsadm/ingress.go +++ b/pkg/kotsadm/ingress.go @@ -12,7 +12,7 @@ import ( "k8s.io/client-go/kubernetes" ) -func EnsureIngress(ctx context.Context, namespace string, clientset *kubernetes.Clientset, ingressSpec kotsv1beta1.IngressConfigSpec) error { +func EnsureIngress(ctx context.Context, namespace string, clientset kubernetes.Interface, ingressSpec kotsv1beta1.IngressConfigSpec) error { if !ingressSpec.Enabled || ingressSpec.Ingress == nil { return DeleteIngress(ctx, namespace, clientset) } @@ -20,7 +20,7 @@ func EnsureIngress(ctx context.Context, namespace string, clientset *kubernetes. return ingress.EnsureIngress(ctx, clientset, namespace, kotsadmIngress) } -func DeleteIngress(ctx context.Context, namespace string, clientset *kubernetes.Clientset) error { +func DeleteIngress(ctx context.Context, namespace string, clientset kubernetes.Interface) error { err := clientset.NetworkingV1().Ingresses(namespace).Delete(ctx, "kotsadm", metav1.DeleteOptions{}) if kuberneteserrors.IsNotFound(err) { err = nil diff --git a/pkg/kotsadm/kotsadm.go b/pkg/kotsadm/kotsadm.go index 7095a13e24..457cb63b94 100644 --- a/pkg/kotsadm/kotsadm.go +++ b/pkg/kotsadm/kotsadm.go @@ -116,7 +116,7 @@ func getKotsadmNamespacedRBAC(s *json.Serializer, additionalNamespace string, ko return nil } -func ensureKotsadmComponent(deployOptions *types.DeployOptions, clientset *kubernetes.Clientset) error { +func ensureKotsadmComponent(deployOptions *types.DeployOptions, clientset kubernetes.Interface) error { if deployOptions.EnsureRBAC { if err := ensureKotsadmRBAC(*deployOptions, clientset); err != nil { return errors.Wrap(err, "failed to ensure kotsadm rbac") @@ -153,7 +153,7 @@ func ensureKotsadmComponent(deployOptions *types.DeployOptions, clientset *kuber return nil } -func ensureKotsadmRBAC(deployOptions types.DeployOptions, clientset *kubernetes.Clientset) error { +func ensureKotsadmRBAC(deployOptions types.DeployOptions, clientset kubernetes.Interface) error { isClusterScoped, err := isKotsadmClusterScoped(&deployOptions) if err != nil { return errors.Wrap(err, "failed to check if kotsadm is cluster scoped") @@ -207,7 +207,7 @@ func ensureKotsadmRBAC(deployOptions types.DeployOptions, clientset *kubernetes. } // ensureKotsadmClusterRBAC will ensure that the cluster role and cluster role bindings exists -func ensureKotsadmClusterRBAC(deployOptions types.DeployOptions, clientset *kubernetes.Clientset) error { +func ensureKotsadmClusterRBAC(deployOptions types.DeployOptions, clientset kubernetes.Interface) error { err := ensureKotsadmClusterRole(clientset) if err != nil { return errors.Wrap(err, "failed to ensure kotsadm cluster role") @@ -224,7 +224,7 @@ func ensureKotsadmClusterRBAC(deployOptions types.DeployOptions, clientset *kube return nil } -func ensureKotsadmClusterRole(clientset *kubernetes.Clientset) error { +func ensureKotsadmClusterRole(clientset kubernetes.Interface) error { _, err := clientset.RbacV1().ClusterRoles().Create(context.TODO(), kotsadmobjects.KotsadmClusterRole(), metav1.CreateOptions{}) if err == nil || kuberneteserrors.IsAlreadyExists(err) { return nil @@ -233,7 +233,7 @@ func ensureKotsadmClusterRole(clientset *kubernetes.Clientset) error { return errors.Wrap(err, "failed to create cluster role") } -func ensureKotsadmClusterRoleBinding(serviceAccountNamespace string, clientset *kubernetes.Clientset) error { +func ensureKotsadmClusterRoleBinding(serviceAccountNamespace string, clientset kubernetes.Interface) error { clusterRoleBinding, err := clientset.RbacV1().ClusterRoleBindings().Get(context.TODO(), "kotsadm-rolebinding", metav1.GetOptions{}) if kuberneteserrors.IsNotFound(err) { _, err := clientset.RbacV1().ClusterRoleBindings().Create(context.TODO(), kotsadmobjects.KotsadmClusterRoleBinding(serviceAccountNamespace), metav1.CreateOptions{}) @@ -265,7 +265,7 @@ func ensureKotsadmClusterRoleBinding(serviceAccountNamespace string, clientset * return nil } -func ensureKotsadmServiceAccount(namespace string, clientset *kubernetes.Clientset) error { +func ensureKotsadmServiceAccount(namespace string, clientset kubernetes.Interface) error { _, err := clientset.CoreV1().ServiceAccounts(namespace).Get(context.TODO(), "kotsadm", metav1.GetOptions{}) if err != nil { if !kuberneteserrors.IsNotFound(err) { @@ -281,7 +281,7 @@ func ensureKotsadmServiceAccount(namespace string, clientset *kubernetes.Clients return nil } -func ensureKotsadmDeployment(deployOptions types.DeployOptions, clientset *kubernetes.Clientset) error { +func ensureKotsadmDeployment(deployOptions types.DeployOptions, clientset kubernetes.Interface) error { desiredDeployment, err := kotsadmobjects.KotsadmDeployment(deployOptions) if err != nil { return errors.Wrap(err, "failed to get desired kotsadm deployment definition") @@ -312,7 +312,7 @@ func ensureKotsadmDeployment(deployOptions types.DeployOptions, clientset *kuber return nil } -func ensureKotsadmStatefulSet(deployOptions types.DeployOptions, clientset *kubernetes.Clientset, size resource.Quantity) error { +func ensureKotsadmStatefulSet(deployOptions types.DeployOptions, clientset kubernetes.Interface, size resource.Quantity) error { desiredStatefulSet, err := kotsadmobjects.KotsadmStatefulSet(deployOptions, size) if err != nil { return errors.Wrap(err, "failed to get desired kotsadm statefulset definition") @@ -344,7 +344,7 @@ func ensureKotsadmStatefulSet(deployOptions types.DeployOptions, clientset *kube return nil } -func ensureKotsadmService(namespace string, clientset *kubernetes.Clientset, nodePort int32) error { +func ensureKotsadmService(namespace string, clientset kubernetes.Interface, nodePort int32) error { service := kotsadmobjects.KotsadmService(namespace, nodePort) existing, err := clientset.CoreV1().Services(namespace).Get(context.TODO(), "kotsadm", metav1.GetOptions{}) diff --git a/pkg/kotsadm/license.go b/pkg/kotsadm/license.go index 1bb3491ecd..6fc45dd7ae 100644 --- a/pkg/kotsadm/license.go +++ b/pkg/kotsadm/license.go @@ -33,7 +33,7 @@ func getLicenseSecretYAML(deployOptions *types.DeployOptions) (map[string][]byte return docs, nil } -func ensureLicenseSecret(deployOptions *types.DeployOptions, clientset *kubernetes.Clientset) (bool, error) { +func ensureLicenseSecret(deployOptions *types.DeployOptions, clientset kubernetes.Interface) (bool, error) { existingSecret, err := getLicenseSecret(deployOptions.Namespace, clientset) if err != nil { return false, errors.Wrap(err, "failed to check for existing license secret") @@ -57,7 +57,7 @@ func ensureLicenseSecret(deployOptions *types.DeployOptions, clientset *kubernet return true, nil } -func getLicenseSecret(namespace string, clientset *kubernetes.Clientset) (*corev1.Secret, error) { +func getLicenseSecret(namespace string, clientset kubernetes.Interface) (*corev1.Secret, error) { licenseSecret, err := clientset.CoreV1().Secrets(namespace).Get(context.TODO(), "kotsadm-default-license", metav1.GetOptions{}) if err != nil { if kuberneteserrors.IsNotFound(err) { diff --git a/pkg/kotsadm/limitrange.go b/pkg/kotsadm/limitrange.go index 5cef0ead4e..1d9cbbcb08 100644 --- a/pkg/kotsadm/limitrange.go +++ b/pkg/kotsadm/limitrange.go @@ -14,7 +14,7 @@ import ( "k8s.io/client-go/kubernetes" ) -func maybeGetNamespaceLimitRanges(clientset *kubernetes.Clientset, namespace string) (*corev1.LimitRange, error) { +func maybeGetNamespaceLimitRanges(clientset kubernetes.Interface, namespace string) (*corev1.LimitRange, error) { limitRanges, err := clientset.CoreV1().LimitRanges(namespace).List(context.TODO(), metav1.ListOptions{}) if err != nil { return nil, errors.Wrap(err, "failed to list limit ranges") diff --git a/pkg/kotsadm/main.go b/pkg/kotsadm/main.go index b9b2cdacad..69c9ad759f 100644 --- a/pkg/kotsadm/main.go +++ b/pkg/kotsadm/main.go @@ -99,7 +99,7 @@ func YAML(deployOptions types.DeployOptions) (map[string][]byte, error) { return docs, nil } -func Upgrade(clientset *kubernetes.Clientset, upgradeOptions types.UpgradeOptions) error { +func Upgrade(clientset kubernetes.Interface, upgradeOptions types.UpgradeOptions) error { log := logger.NewCLILogger(os.Stdout) if err := canUpgrade(upgradeOptions, clientset, log); err != nil { @@ -245,7 +245,7 @@ func IsAirgap() bool { return os.Getenv("DISABLE_OUTBOUND_CONNECTIONS") == "true" } -func canUpgrade(upgradeOptions types.UpgradeOptions, clientset *kubernetes.Clientset, log *logger.CLILogger) error { +func canUpgrade(upgradeOptions types.UpgradeOptions, clientset kubernetes.Interface, log *logger.CLILogger) error { _, err := clientset.CoreV1().Namespaces().Get(context.TODO(), upgradeOptions.Namespace, metav1.GetOptions{}) if kuberneteserrors.IsNotFound(err) { err := errors.New("The namespace cannot be found or accessed") @@ -273,7 +273,7 @@ func canUpgrade(upgradeOptions types.UpgradeOptions, clientset *kubernetes.Clien return nil } -func removeUnusedKotsadmComponents(deployOptions types.DeployOptions, clientset *kubernetes.Clientset, log *logger.CLILogger) error { +func removeUnusedKotsadmComponents(deployOptions types.DeployOptions, clientset kubernetes.Interface, log *logger.CLILogger) error { // if there's a kotsadm web deployment, remove (pre 1.11.0) _, err := clientset.AppsV1().Deployments(deployOptions.Namespace).Get(context.TODO(), "kotsadm-web", metav1.GetOptions{}) if err == nil { @@ -309,7 +309,7 @@ func removeUnusedKotsadmComponents(deployOptions types.DeployOptions, clientset return nil } -func removeKotsadmOperator(deployOptions types.DeployOptions, clientset *kubernetes.Clientset, log *logger.CLILogger) error { +func removeKotsadmOperator(deployOptions types.DeployOptions, clientset kubernetes.Interface, log *logger.CLILogger) error { err := clientset.AppsV1().Deployments(deployOptions.Namespace).Delete(context.TODO(), "kotsadm-operator", metav1.DeleteOptions{}) if err != nil && !kuberneteserrors.IsNotFound(err) { return errors.Wrap(err, "failed to delete kotsadm-operator deployment") @@ -369,7 +369,7 @@ func removeKotsadmOperator(deployOptions types.DeployOptions, clientset *kuberne return nil } -func removeKotsadmMinio(deployOptions types.DeployOptions, clientset *kubernetes.Clientset) error { +func removeKotsadmMinio(deployOptions types.DeployOptions, clientset kubernetes.Interface) error { // if there's a deployment named "kotsadm", remove (pre 1.47.0) // only delete the deployment if minio is not included because that will mean that it's been replaced with a statefulset err := clientset.AppsV1().Deployments(deployOptions.Namespace).Delete(context.TODO(), "kotsadm", metav1.DeleteOptions{}) @@ -415,7 +415,7 @@ func removeKotsadmMinio(deployOptions types.DeployOptions, clientset *kubernetes return nil } -func removeKotsadmPostgres(deployOptions types.DeployOptions, clientset *kubernetes.Clientset) error { +func removeKotsadmPostgres(deployOptions types.DeployOptions, clientset kubernetes.Interface) error { // if there's a service named "kotsadm-postgres", remove (pre 1.89.0) err := clientset.CoreV1().Services(deployOptions.Namespace).Delete(context.TODO(), "kotsadm-postgres", metav1.DeleteOptions{}) if err != nil && !kuberneteserrors.IsNotFound(err) { @@ -460,7 +460,7 @@ func removeKotsadmPostgres(deployOptions types.DeployOptions, clientset *kuberne return nil } -func ensureKotsadm(deployOptions types.DeployOptions, clientset *kubernetes.Clientset, log *logger.CLILogger) error { +func ensureKotsadm(deployOptions types.DeployOptions, clientset kubernetes.Interface, log *logger.CLILogger) error { restartKotsadmAPI := false ingressConfig := deployOptions.IngressConfig @@ -652,7 +652,7 @@ func ensureKotsadm(deployOptions types.DeployOptions, clientset *kubernetes.Clie return nil } -func ensureDisasterRecoveryLabels(deployOptions *types.DeployOptions, clientset *kubernetes.Clientset) error { +func ensureDisasterRecoveryLabels(deployOptions *types.DeployOptions, clientset kubernetes.Interface) error { selectorLabels := map[string]string{ types.KotsadmKey: types.KotsadmLabelValue, } @@ -971,7 +971,7 @@ func ensureDisasterRecoveryLabels(deployOptions *types.DeployOptions, clientset return nil } -func ReadDeployOptionsFromCluster(namespace string, clientset *kubernetes.Clientset) (*types.DeployOptions, error) { +func ReadDeployOptionsFromCluster(namespace string, clientset kubernetes.Interface) (*types.DeployOptions, error) { deployOptions := types.DeployOptions{ Namespace: namespace, ServiceType: "ClusterIP", diff --git a/pkg/kotsadm/namespaces.go b/pkg/kotsadm/namespaces.go index 50f384598d..cc79436fb3 100644 --- a/pkg/kotsadm/namespaces.go +++ b/pkg/kotsadm/namespaces.go @@ -14,7 +14,7 @@ import ( "k8s.io/client-go/kubernetes" ) -func ensureAdditionalNamespaces(deployOptions *types.DeployOptions, clientset *kubernetes.Clientset, log *logger.CLILogger) error { +func ensureAdditionalNamespaces(deployOptions *types.DeployOptions, clientset kubernetes.Interface, log *logger.CLILogger) error { // try to parse if deployOptions.ApplicationMetadata == nil { return nil diff --git a/pkg/kotsadm/rqlite.go b/pkg/kotsadm/rqlite.go index a306c7f7a8..d490246d24 100644 --- a/pkg/kotsadm/rqlite.go +++ b/pkg/kotsadm/rqlite.go @@ -54,7 +54,7 @@ func getRqliteYAML(deployOptions types.DeployOptions) (map[string][]byte, error) return docs, nil } -func ensureRqlite(deployOptions types.DeployOptions, clientset *kubernetes.Clientset) error { +func ensureRqlite(deployOptions types.DeployOptions, clientset kubernetes.Interface) error { if err := ensureRqliteSecret(deployOptions, clientset); err != nil { return errors.Wrap(err, "failed to ensure rqlite secret") } @@ -79,7 +79,7 @@ func ensureRqlite(deployOptions types.DeployOptions, clientset *kubernetes.Clien return nil } -func ensureRqliteStatefulset(deployOptions types.DeployOptions, clientset *kubernetes.Clientset, size resource.Quantity) error { +func ensureRqliteStatefulset(deployOptions types.DeployOptions, clientset kubernetes.Interface, size resource.Quantity) error { desiredRqlite, err := kotsadmobjects.RqliteStatefulset(deployOptions, size) if err != nil { return errors.Wrap(err, "failed to get desired rqlite statefulset definition") @@ -129,7 +129,7 @@ func ensureRqliteStatefulset(deployOptions types.DeployOptions, clientset *kuber return nil } -func ensureRqliteService(namespace string, clientset *kubernetes.Clientset) error { +func ensureRqliteService(namespace string, clientset kubernetes.Interface) error { _, err := clientset.CoreV1().Services(namespace).Get(context.TODO(), "kotsadm-rqlite", metav1.GetOptions{}) if err != nil { if !kuberneteserrors.IsNotFound(err) { @@ -145,7 +145,7 @@ func ensureRqliteService(namespace string, clientset *kubernetes.Clientset) erro return nil } -func ensureRqliteHeadlessService(namespace string, clientset *kubernetes.Clientset) error { +func ensureRqliteHeadlessService(namespace string, clientset kubernetes.Interface) error { _, err := clientset.CoreV1().Services(namespace).Get(context.TODO(), "kotsadm-rqlite-headless", metav1.GetOptions{}) if err != nil { if !kuberneteserrors.IsNotFound(err) { diff --git a/pkg/kotsadm/secrets.go b/pkg/kotsadm/secrets.go index c0080d1885..08af87db73 100644 --- a/pkg/kotsadm/secrets.go +++ b/pkg/kotsadm/secrets.go @@ -93,7 +93,7 @@ func getSecretsYAML(deployOptions *types.DeployOptions) (map[string][]byte, erro return docs, nil } -func ensureSecrets(deployOptions *types.DeployOptions, clientset *kubernetes.Clientset) error { +func ensureSecrets(deployOptions *types.DeployOptions, clientset kubernetes.Interface) error { if err := ensureJWTSessionSecret(deployOptions.Namespace, clientset); err != nil { return errors.Wrap(err, "failed to ensure jwt session secret") } @@ -154,7 +154,7 @@ func ensureS3Secret(namespace string, clientset kubernetes.Interface) error { return nil } -func getJWTSessionSecret(namespace string, clientset *kubernetes.Clientset) (*corev1.Secret, error) { +func getJWTSessionSecret(namespace string, clientset kubernetes.Interface) (*corev1.Secret, error) { jwtSecret, err := clientset.CoreV1().Secrets(namespace).Get(context.TODO(), "kotsadm-session", metav1.GetOptions{}) if err != nil { if kuberneteserrors.IsNotFound(err) { @@ -167,7 +167,7 @@ func getJWTSessionSecret(namespace string, clientset *kubernetes.Clientset) (*co return jwtSecret, nil } -func ensureJWTSessionSecret(namespace string, clientset *kubernetes.Clientset) error { +func ensureJWTSessionSecret(namespace string, clientset kubernetes.Interface) error { existingJWTSessionSecret, err := getJWTSessionSecret(namespace, clientset) if err != nil { return errors.Wrap(err, "failed to check for existing jwt sesssion secret") @@ -183,7 +183,7 @@ func ensureJWTSessionSecret(namespace string, clientset *kubernetes.Clientset) e return nil } -func getRqliteSecret(namespace string, clientset *kubernetes.Clientset) (*corev1.Secret, error) { +func getRqliteSecret(namespace string, clientset kubernetes.Interface) (*corev1.Secret, error) { rqliteSecret, err := clientset.CoreV1().Secrets(namespace).Get(context.TODO(), "kotsadm-rqlite", metav1.GetOptions{}) if err != nil { if kuberneteserrors.IsNotFound(err) { @@ -195,7 +195,7 @@ func getRqliteSecret(namespace string, clientset *kubernetes.Clientset) (*corev1 return rqliteSecret, nil } -func ensureRqliteSecret(deployOptions types.DeployOptions, clientset *kubernetes.Clientset) error { +func ensureRqliteSecret(deployOptions types.DeployOptions, clientset kubernetes.Interface) error { existingRqliteSecret, err := getRqliteSecret(deployOptions.Namespace, clientset) if err != nil { return errors.Wrap(err, "failed to check for existing rqlite secret") @@ -211,7 +211,7 @@ func ensureRqliteSecret(deployOptions types.DeployOptions, clientset *kubernetes return nil } -func getSharedPasswordSecret(namespace string, clientset *kubernetes.Clientset) (*corev1.Secret, error) { +func getSharedPasswordSecret(namespace string, clientset kubernetes.Interface) (*corev1.Secret, error) { sharedPasswordSecret, err := clientset.CoreV1().Secrets(namespace).Get(context.TODO(), "kotsadm-password", metav1.GetOptions{}) if err != nil { if kuberneteserrors.IsNotFound(err) { @@ -224,7 +224,7 @@ func getSharedPasswordSecret(namespace string, clientset *kubernetes.Clientset) return sharedPasswordSecret, nil } -func ensureSharedPasswordSecret(deployOptions *types.DeployOptions, clientset *kubernetes.Clientset) error { +func ensureSharedPasswordSecret(deployOptions *types.DeployOptions, clientset kubernetes.Interface) error { if deployOptions.SharedPassword == "" { sharedPassword, err := util.PromptForNewPassword() if err != nil { @@ -255,7 +255,7 @@ func ensureSharedPasswordSecret(deployOptions *types.DeployOptions, clientset *k return nil } -func ensureAPIEncryptionSecret(deployOptions *types.DeployOptions, clientset *kubernetes.Clientset) error { +func ensureAPIEncryptionSecret(deployOptions *types.DeployOptions, clientset kubernetes.Interface) error { secret, err := getAPIEncryptionSecret(deployOptions.Namespace, clientset) if err != nil { return errors.Wrap(err, "failed to check for existing api encryption secret") @@ -283,7 +283,7 @@ func ensureAPIEncryptionSecret(deployOptions *types.DeployOptions, clientset *ku return nil } -func getAPIEncryptionSecret(namespace string, clientset *kubernetes.Clientset) (*corev1.Secret, error) { +func getAPIEncryptionSecret(namespace string, clientset kubernetes.Interface) (*corev1.Secret, error) { apiSecret, err := clientset.CoreV1().Secrets(namespace).Get(context.TODO(), "kotsadm-encryption", metav1.GetOptions{}) if err != nil { if kuberneteserrors.IsNotFound(err) { @@ -296,7 +296,7 @@ func getAPIEncryptionSecret(namespace string, clientset *kubernetes.Clientset) ( return apiSecret, nil } -func ensureAPIClusterTokenSecret(deployOptions types.DeployOptions, clientset *kubernetes.Clientset) error { +func ensureAPIClusterTokenSecret(deployOptions types.DeployOptions, clientset kubernetes.Interface) error { _, err := clientset.CoreV1().Secrets(deployOptions.Namespace).Get(context.TODO(), types.ClusterTokenSecret, metav1.GetOptions{}) if err != nil { if !kuberneteserrors.IsNotFound(err) { diff --git a/pkg/kotsadm/updates.go b/pkg/kotsadm/updates.go index f61e82374e..ea425d3e25 100644 --- a/pkg/kotsadm/updates.go +++ b/pkg/kotsadm/updates.go @@ -171,7 +171,7 @@ func UpdateToVersion(newVersion string) error { return nil } -func findUpdatePod(ctx context.Context, clientset *kubernetes.Clientset) (*corev1.Pod, error) { +func findUpdatePod(ctx context.Context, clientset kubernetes.Interface) (*corev1.Pod, error) { selectorLabels := map[string]string{ "app": "kotsadm-updater", } @@ -199,7 +199,7 @@ func findUpdatePod(ctx context.Context, clientset *kubernetes.Clientset) (*corev return pod, nil } -func getLastLogLineFromPod(ctx context.Context, clientset *kubernetes.Clientset, pod *corev1.Pod) (string, error) { +func getLastLogLineFromPod(ctx context.Context, clientset kubernetes.Interface, pod *corev1.Pod) (string, error) { if len(pod.Spec.Containers) == 0 { return "", nil } diff --git a/pkg/password/password.go b/pkg/password/password.go index 350c499e0c..8fdca0cec6 100644 --- a/pkg/password/password.go +++ b/pkg/password/password.go @@ -60,7 +60,7 @@ func ValidateCurrentPassword(kotsStore store.Store, currentPassword string) erro } // ChangePassword - will change the password in the kotsadm secret -func ChangePassword(clientset *kubernetes.Clientset, namespace string, newPassword string) error { +func ChangePassword(clientset kubernetes.Interface, namespace string, newPassword string) error { passwordLock.Lock() defer passwordLock.Unlock() diff --git a/pkg/pull/interface.go b/pkg/pull/interface.go index 61cc0dc901..0bad1c26be 100644 --- a/pkg/pull/interface.go +++ b/pkg/pull/interface.go @@ -3,10 +3,10 @@ package pull var _p PullerInterface func init() { - SetPuller(&Puller{}) + Set(&Puller{}) } -func SetPuller(p PullerInterface) { +func Set(p PullerInterface) { _p = p } diff --git a/pkg/snapshot/velero.go b/pkg/snapshot/velero.go index 4af14711b0..12c109e9f8 100644 --- a/pkg/snapshot/velero.go +++ b/pkg/snapshot/velero.go @@ -384,7 +384,7 @@ func getVersion(ctx context.Context, namespace string) (string, error) { return serverStatus.Status.ServerVersion, nil } -func getVeleroPod(ctx context.Context, clientset *kubernetes.Clientset, namespace string) (string, error) { +func getVeleroPod(ctx context.Context, clientset kubernetes.Interface, namespace string) (string, error) { veleroLabels := map[string]string{ "component": "velero", "deploy": "velero", @@ -415,7 +415,7 @@ func getVeleroPod(ctx context.Context, clientset *kubernetes.Clientset, namespac return "", nil } -func getNodeAgentPods(ctx context.Context, clientset *kubernetes.Clientset, namespace string) ([]string, error) { +func getNodeAgentPods(ctx context.Context, clientset kubernetes.Interface, namespace string) ([]string, error) { componentReq, err := labels.NewRequirement("component", selection.Equals, []string{"velero"}) if err != nil { return nil, errors.Wrap(err, "failed to create component requirement") @@ -456,7 +456,7 @@ func getNodeAgentPods(ctx context.Context, clientset *kubernetes.Clientset, name // listPossibleVeleroDeployments filters with a label selector based on how we've found velero deployed // using the CLI or the Helm Chart. -func listPossibleVeleroDeployments(ctx context.Context, clientset *kubernetes.Clientset, namespace string) ([]v1.Deployment, error) { +func listPossibleVeleroDeployments(ctx context.Context, clientset kubernetes.Interface, namespace string) ([]v1.Deployment, error) { deployments, err := clientset.AppsV1().Deployments(namespace).List(ctx, metav1.ListOptions{ LabelSelector: "component=velero", }) @@ -476,7 +476,7 @@ func listPossibleVeleroDeployments(ctx context.Context, clientset *kubernetes.Cl // listPossibleNodeAgentDaemonsets filters with a label selector based on how we've found node-agent deployed // using the CLI or the Helm Chart. -func listPossibleNodeAgentDaemonsets(ctx context.Context, clientset *kubernetes.Clientset, namespace string) ([]v1.DaemonSet, error) { +func listPossibleNodeAgentDaemonsets(ctx context.Context, clientset kubernetes.Interface, namespace string) ([]v1.DaemonSet, error) { daemonsets, err := clientset.AppsV1().DaemonSets(namespace).List(ctx, metav1.ListOptions{ LabelSelector: "component=velero", }) diff --git a/pkg/supportbundle/spec.go b/pkg/supportbundle/spec.go index 17a2782343..72be088aed 100644 --- a/pkg/supportbundle/spec.go +++ b/pkg/supportbundle/spec.go @@ -398,7 +398,7 @@ func createClusterSpecificSpec(app *apptypes.App, b *troubleshootv1beta2.Support } // createDefaultSpec creates a default support bundle spec that includes the default collectors and analyzers and add kurl specific collectors and analyzers if the cluster is a kurl cluster -func createDefaultSpec(app *apptypes.App, b *troubleshootv1beta2.SupportBundle, opts types.TroubleshootOptions, namespacesToCollect []string, namespacesToAnalyze []string, clientset *kubernetes.Clientset) (*troubleshootv1beta2.SupportBundle, error) { +func createDefaultSpec(app *apptypes.App, b *troubleshootv1beta2.SupportBundle, opts types.TroubleshootOptions, namespacesToCollect []string, namespacesToAnalyze []string, clientset kubernetes.Interface) (*troubleshootv1beta2.SupportBundle, error) { supportBundle, err := staticspecs.GetDefaultSpec(app) if err != nil { logger.Errorf("Failed to load default support bundle spec: %v", err) diff --git a/pkg/upgradeservice/bootstrap_test.go b/pkg/upgradeservice/bootstrap_test.go index 4ae8d5417c..c8ebe5cfb5 100644 --- a/pkg/upgradeservice/bootstrap_test.go +++ b/pkg/upgradeservice/bootstrap_test.go @@ -4,9 +4,12 @@ import ( _ "embed" "testing" + "github.com/replicatedhq/kots/pkg/k8sutil" "github.com/replicatedhq/kots/pkg/pull" "github.com/replicatedhq/kots/pkg/upgradeservice/types" "github.com/stretchr/testify/require" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/kubernetes/fake" ) //go:embed testassets/license.yaml @@ -14,11 +17,15 @@ var testLicense string func Test_bootstrap(t *testing.T) { tests := []struct { - name string - mockPullFunc func(upstreamURI string, pullOptions pull.PullOptions) (string, error) + name string + mockClientset func() kubernetes.Interface + mockPullFunc func(upstreamURI string, pullOptions pull.PullOptions) (string, error) }{ { name: "does not error when version needs config", + mockClientset: func() kubernetes.Interface { + return fake.NewSimpleClientset() + }, mockPullFunc: func(upstreamURI string, pullOptions pull.PullOptions) (string, error) { return "", pull.ErrConfigNeeded }, @@ -27,7 +34,10 @@ func Test_bootstrap(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - pull.SetPuller(&MockPuller{ + k8sutil.Set(&MockK8sutil{ + ClientFunc: tt.mockClientset, + }) + pull.Set(&MockPuller{ PullFunc: tt.mockPullFunc, }) @@ -42,6 +52,14 @@ func Test_bootstrap(t *testing.T) { } } +type MockK8sutil struct { + ClientFunc func() kubernetes.Interface +} + +func (m *MockK8sutil) GetClientset() (kubernetes.Interface, error) { + return m.ClientFunc(), nil +} + type MockPuller struct { PullFunc func(upstreamURI string, pullOptions pull.PullOptions) (string, error) } From dce742cf9aa58c10abe3cbb6eaaf0d17f218aa9b Mon Sep 17 00:00:00 2001 From: Salah Aldeen Al Saleh Date: Wed, 6 Nov 2024 12:55:54 -0800 Subject: [PATCH 6/6] use mocks --- Makefile | 2 ++ pkg/k8sutil/clientset.go | 6 ++-- pkg/k8sutil/interface.go | 8 ++--- pkg/k8sutil/mock/mock.go | 50 ++++++++++++++++++++++++++ pkg/pull/interface.go | 8 ++--- pkg/pull/mock/mock.go | 50 ++++++++++++++++++++++++++ pkg/pull/pull.go | 6 ++-- pkg/upgradeservice/bootstrap_test.go | 54 ++++++++++++---------------- 8 files changed, 139 insertions(+), 45 deletions(-) create mode 100644 pkg/k8sutil/mock/mock.go create mode 100644 pkg/pull/mock/mock.go diff --git a/Makefile b/Makefile index a8b1ea573b..f5cabc24a5 100644 --- a/Makefile +++ b/Makefile @@ -89,6 +89,8 @@ mock: mockgen -source=pkg/store/store_interface.go -destination=pkg/store/mock/mock.go mockgen -source=pkg/handlers/interface.go -destination=pkg/handlers/mock/mock.go mockgen -source=pkg/operator/client/client_interface.go -destination=pkg/operator/client/mock/mock.go + mockgen -source=pkg/k8sutil/interface.go -destination=pkg/k8sutil/mock/mock.go + mockgen -source=pkg/pull/interface.go -destination=pkg/pull/mock/mock.go .PHONY: dev dev: diff --git a/pkg/k8sutil/clientset.go b/pkg/k8sutil/clientset.go index abd6616453..99dbcbbe74 100644 --- a/pkg/k8sutil/clientset.go +++ b/pkg/k8sutil/clientset.go @@ -25,9 +25,9 @@ import ( "sigs.k8s.io/controller-runtime/pkg/log/zap" ) -type K8sutil struct{} +type k8sutil struct{} -var _ K8sutilInterface = (*K8sutil)(nil) +var _ K8sutil = (*k8sutil)(nil) const ( DEFAULT_K8S_CLIENT_QPS = 100 @@ -45,7 +45,7 @@ func AddFlags(flags *flag.FlagSet) { kubernetesConfigFlags.AddFlags(flags) } -func (k *K8sutil) GetClientset() (kubernetes.Interface, error) { +func (k *k8sutil) GetClientset() (kubernetes.Interface, error) { cfg, err := GetClusterConfig() if err != nil { return nil, errors.Wrap(err, "failed to get cluster config") diff --git a/pkg/k8sutil/interface.go b/pkg/k8sutil/interface.go index dd81cd6873..e4a1507870 100644 --- a/pkg/k8sutil/interface.go +++ b/pkg/k8sutil/interface.go @@ -2,17 +2,17 @@ package k8sutil import "k8s.io/client-go/kubernetes" -var _k8s K8sutilInterface +var _k8s K8sutil func init() { - Set(&K8sutil{}) + _k8s = &k8sutil{} } -func Set(k8s K8sutilInterface) { +func Mock(k8s K8sutil) { _k8s = k8s } -type K8sutilInterface interface { +type K8sutil interface { GetClientset() (kubernetes.Interface, error) } diff --git a/pkg/k8sutil/mock/mock.go b/pkg/k8sutil/mock/mock.go new file mode 100644 index 0000000000..22621f9c3b --- /dev/null +++ b/pkg/k8sutil/mock/mock.go @@ -0,0 +1,50 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: pkg/k8sutil/interface.go + +// Package mock_k8sutil is a generated GoMock package. +package mock_k8sutil + +import ( + reflect "reflect" + + gomock "github.com/golang/mock/gomock" + kubernetes "k8s.io/client-go/kubernetes" +) + +// MockK8sutil is a mock of K8sutil interface. +type MockK8sutil struct { + ctrl *gomock.Controller + recorder *MockK8sutilMockRecorder +} + +// MockK8sutilMockRecorder is the mock recorder for MockK8sutil. +type MockK8sutilMockRecorder struct { + mock *MockK8sutil +} + +// NewMockK8sutil creates a new mock instance. +func NewMockK8sutil(ctrl *gomock.Controller) *MockK8sutil { + mock := &MockK8sutil{ctrl: ctrl} + mock.recorder = &MockK8sutilMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockK8sutil) EXPECT() *MockK8sutilMockRecorder { + return m.recorder +} + +// GetClientset mocks base method. +func (m *MockK8sutil) GetClientset() (kubernetes.Interface, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetClientset") + ret0, _ := ret[0].(kubernetes.Interface) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetClientset indicates an expected call of GetClientset. +func (mr *MockK8sutilMockRecorder) GetClientset() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetClientset", reflect.TypeOf((*MockK8sutil)(nil).GetClientset)) +} diff --git a/pkg/pull/interface.go b/pkg/pull/interface.go index 0bad1c26be..468d14d37c 100644 --- a/pkg/pull/interface.go +++ b/pkg/pull/interface.go @@ -1,16 +1,16 @@ package pull -var _p PullerInterface +var _p Puller func init() { - Set(&Puller{}) + _p = &puller{} } -func Set(p PullerInterface) { +func Mock(p Puller) { _p = p } -type PullerInterface interface { +type Puller interface { Pull(upstreamURI string, pullOptions PullOptions) (string, error) } diff --git a/pkg/pull/mock/mock.go b/pkg/pull/mock/mock.go new file mode 100644 index 0000000000..7be5a3f0ab --- /dev/null +++ b/pkg/pull/mock/mock.go @@ -0,0 +1,50 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: pkg/pull/interface.go + +// Package mock_pull is a generated GoMock package. +package mock_pull + +import ( + reflect "reflect" + + gomock "github.com/golang/mock/gomock" + pull "github.com/replicatedhq/kots/pkg/pull" +) + +// MockPuller is a mock of Puller interface. +type MockPuller struct { + ctrl *gomock.Controller + recorder *MockPullerMockRecorder +} + +// MockPullerMockRecorder is the mock recorder for MockPuller. +type MockPullerMockRecorder struct { + mock *MockPuller +} + +// NewMockPuller creates a new mock instance. +func NewMockPuller(ctrl *gomock.Controller) *MockPuller { + mock := &MockPuller{ctrl: ctrl} + mock.recorder = &MockPullerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockPuller) EXPECT() *MockPullerMockRecorder { + return m.recorder +} + +// Pull mocks base method. +func (m *MockPuller) Pull(upstreamURI string, pullOptions pull.PullOptions) (string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Pull", upstreamURI, pullOptions) + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Pull indicates an expected call of Pull. +func (mr *MockPullerMockRecorder) Pull(upstreamURI, pullOptions interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Pull", reflect.TypeOf((*MockPuller)(nil).Pull), upstreamURI, pullOptions) +} diff --git a/pkg/pull/pull.go b/pkg/pull/pull.go index a3e6a0f457..203384ca95 100644 --- a/pkg/pull/pull.go +++ b/pkg/pull/pull.go @@ -39,9 +39,9 @@ import ( "k8s.io/client-go/kubernetes/scheme" ) -type Puller struct{} +type puller struct{} -var _ PullerInterface = (*Puller)(nil) +var _ Puller = (*puller)(nil) type PullOptions struct { RootDir string @@ -111,7 +111,7 @@ func PullApplicationMetadata(upstreamURI string, versionLabel string) (*replicat // Pull will download the application specified in upstreamURI using the options // specified in pullOptions. It returns the directory that the app was pulled to -func (p *Puller) Pull(upstreamURI string, pullOptions PullOptions) (string, error) { +func (p *puller) Pull(upstreamURI string, pullOptions PullOptions) (string, error) { log := logger.NewCLILogger(os.Stdout) if pullOptions.Silent { diff --git a/pkg/upgradeservice/bootstrap_test.go b/pkg/upgradeservice/bootstrap_test.go index c8ebe5cfb5..20dabeb0c1 100644 --- a/pkg/upgradeservice/bootstrap_test.go +++ b/pkg/upgradeservice/bootstrap_test.go @@ -4,11 +4,13 @@ import ( _ "embed" "testing" + "github.com/golang/mock/gomock" "github.com/replicatedhq/kots/pkg/k8sutil" + mock_k8sutil "github.com/replicatedhq/kots/pkg/k8sutil/mock" "github.com/replicatedhq/kots/pkg/pull" + mock_pull "github.com/replicatedhq/kots/pkg/pull/mock" "github.com/replicatedhq/kots/pkg/upgradeservice/types" "github.com/stretchr/testify/require" - "k8s.io/client-go/kubernetes" "k8s.io/client-go/kubernetes/fake" ) @@ -17,29 +19,35 @@ var testLicense string func Test_bootstrap(t *testing.T) { tests := []struct { - name string - mockClientset func() kubernetes.Interface - mockPullFunc func(upstreamURI string, pullOptions pull.PullOptions) (string, error) + name string + setup func(t *testing.T, mockK8sutil *mock_k8sutil.MockK8sutil, mockPuller *mock_pull.MockPuller) }{ { name: "does not error when version needs config", - mockClientset: func() kubernetes.Interface { - return fake.NewSimpleClientset() - }, - mockPullFunc: func(upstreamURI string, pullOptions pull.PullOptions) (string, error) { - return "", pull.ErrConfigNeeded + setup: func(t *testing.T, mockK8sutil *mock_k8sutil.MockK8sutil, mockPuller *mock_pull.MockPuller) { + mockK8sutil.EXPECT().GetClientset().Return(fake.NewSimpleClientset(), nil) + mockPuller.EXPECT().Pull(gomock.Any(), gomock.Any()).Return("", pull.ErrConfigNeeded) }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - k8sutil.Set(&MockK8sutil{ - ClientFunc: tt.mockClientset, - }) - pull.Set(&MockPuller{ - PullFunc: tt.mockPullFunc, - }) + // mock k8sutil + k8sutil_ctrl := gomock.NewController(t) + defer k8sutil_ctrl.Finish() + mockK8sutil := mock_k8sutil.NewMockK8sutil(k8sutil_ctrl) + k8sutil.Mock(mockK8sutil) + + // mock puller + puller_ctrl := gomock.NewController(t) + defer puller_ctrl.Finish() + mockPuller := mock_pull.NewMockPuller(puller_ctrl) + pull.Mock(mockPuller) + + if tt.setup != nil { + tt.setup(t, mockK8sutil, mockPuller) + } params := types.UpgradeServiceParams{ AppLicense: testLicense, @@ -51,19 +59,3 @@ func Test_bootstrap(t *testing.T) { }) } } - -type MockK8sutil struct { - ClientFunc func() kubernetes.Interface -} - -func (m *MockK8sutil) GetClientset() (kubernetes.Interface, error) { - return m.ClientFunc(), nil -} - -type MockPuller struct { - PullFunc func(upstreamURI string, pullOptions pull.PullOptions) (string, error) -} - -func (m *MockPuller) Pull(upstreamURI string, pullOptions pull.PullOptions) (string, error) { - return m.PullFunc(upstreamURI, pullOptions) -}