package bundle import ( "context" "fmt" "os" "testing" "github.com/go-logr/logr/testr" "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/version" "k8s.io/client-go/rest" api "github.com/aws/eks-anywhere-packages/api/v1alpha1" "github.com/aws/eks-anywhere-packages/pkg/authenticator/mocks" bundleMocks "github.com/aws/eks-anywhere-packages/pkg/bundle/mocks" "github.com/aws/eks-anywhere-packages/pkg/config" ) const ( testPreviousBundleName = "v1-21-1002" testBundleName = "v1-21-1003" testNextBundleName = "v1-21-1004" testKubeMajor = "1" testKubeMinor = "21" testKubernetesVersion = "v1.21" ) func GivenBundle(state api.PackageBundleStateEnum) *api.PackageBundle { return &api.PackageBundle{ ObjectMeta: metav1.ObjectMeta{ Name: testBundleName, Namespace: api.PackageNamespace, }, Status: api.PackageBundleStatus{ State: state, }, } } func givenBundleManager(t *testing.T) (*mocks.MockTargetClusterClient, *bundleMocks.MockRegistryClient, *bundleMocks.MockClient, *bundleManager) { logger := testr.New(t) ctrl := gomock.NewController(t) tcc := mocks.NewMockTargetClusterClient(ctrl) rc := bundleMocks.NewMockRegistryClient(ctrl) bc := bundleMocks.NewMockClient(ctrl) cfg := config.GetConfig() cfg.BuildInfo.Version = "v2.2.2" bm := NewBundleManager(logger, rc, bc, tcc, cfg) return tcc, rc, bc, bm } func TestProcessBundle(t *testing.T) { ctx := context.Background() t.Run("ignore other namespaces", func(t *testing.T) { _, _, _, bm := givenBundleManager(t) bundle := GivenBundle("") bundle.Namespace = "billy" update, err := bm.ProcessBundle(ctx, bundle) assert.True(t, update) assert.Equal(t, nil, err) assert.Equal(t, api.PackageBundleStateIgnored, bundle.Status.State) }) t.Run("already ignore other namespaces", func(t *testing.T) { _, _, _, bm := givenBundleManager(t) bundle := GivenBundle(api.PackageBundleStateIgnored) bundle.Namespace = "billy" update, err := bm.ProcessBundle(ctx, bundle) assert.False(t, update) assert.Equal(t, nil, err) assert.Equal(t, api.PackageBundleStateIgnored, bundle.Status.State) }) t.Run("ignore invalid Kubernetes version", func(t *testing.T) { _, _, _, bm := givenBundleManager(t) bundle := GivenBundle(api.PackageBundleStateAvailable) bundle.Name = "v1-21-x" update, err := bm.ProcessBundle(ctx, bundle) assert.True(t, update) assert.Equal(t, nil, err) assert.Equal(t, api.PackageBundleStateInvalid, bundle.Status.State) }) t.Run("marks state available", func(t *testing.T) { _, _, _, bm := givenBundleManager(t) bundle := GivenBundle("") update, err := bm.ProcessBundle(ctx, bundle) assert.True(t, update) assert.Equal(t, nil, err) assert.Equal(t, api.PackageBundleStateAvailable, bundle.Status.State) }) t.Run("already marked state available", func(t *testing.T) { _, _, _, bm := givenBundleManager(t) bundle := GivenBundle(api.PackageBundleStateAvailable) bundle.Name = testPreviousBundleName update, err := bm.ProcessBundle(ctx, bundle) assert.False(t, update) assert.Equal(t, nil, err) assert.Equal(t, api.PackageBundleStateAvailable, bundle.Status.State) }) t.Run("newer controller version required", func(t *testing.T) { _, _, _, bm := givenBundleManager(t) bundle := GivenBundle("") bundle.Spec.MinVersion = "v4.4.4" bundle.Name = testPreviousBundleName update, err := bm.ProcessBundle(ctx, bundle) assert.True(t, update) assert.Equal(t, nil, err) assert.Equal(t, api.PackageBundleStateUpgradeRequired, bundle.Status.State) // No change results in no update needed update, err = bm.ProcessBundle(ctx, bundle) assert.False(t, update) assert.Equal(t, nil, err) assert.Equal(t, api.PackageBundleStateUpgradeRequired, bundle.Status.State) // Bundle becomes available after upgrade bm.config.BuildInfo.Version = "v4.4.5" update, err = bm.ProcessBundle(ctx, bundle) assert.True(t, update) assert.Equal(t, nil, err) assert.Equal(t, api.PackageBundleStateAvailable, bundle.Status.State) }) } func TestBundleManager_ProcessBundleController(t *testing.T) { t.Parallel() ctx := context.Background() info := version.Info{ GitVersion: testKubernetesVersion, Major: "1", Minor: "21", } allBundles := []api.PackageBundle{ { ObjectMeta: metav1.ObjectMeta{ Name: testBundleName, }, }, { ObjectMeta: metav1.ObjectMeta{ Name: "v1-21-1001", }, }, } t.Run("active to active", func(t *testing.T) { tcc, rc, bc, bm := givenBundleManager(t) pbc := givenPackageBundleController() latestBundle := givenBundle() tcc.EXPECT().GetServerVersion(ctx, pbc.Name).Return(&info, nil) tcc.EXPECT().Initialize(ctx, gomock.Any()).Return(nil) tcc.EXPECT().ToRESTConfig().Return(&rest.Config{}, nil) tcc.EXPECT().CreateClusterNamespace(ctx, pbc.Name).Return(nil) tcc.EXPECT().ApplySecret(ctx, gomock.Any()).Return(nil) rc.EXPECT().LatestBundle(ctx, testBundleRegistry+"/eks-anywhere-packages-bundles", testKubeMajor, testKubeMinor, pbc.Name).Return(latestBundle, nil) bc.EXPECT().GetBundleList(ctx).Return(allBundles, nil) bc.EXPECT().CreateClusterConfigMap(ctx, pbc.Name).Return(nil) bc.EXPECT().GetSecret(ctx, "aws-secret").Return(&corev1.Secret{}, nil) err := bm.ProcessBundleController(ctx, pbc) assert.NoError(t, err) assert.Equal(t, api.BundleControllerStateActive, pbc.Status.State) }) t.Run("active missing active bundle", func(t *testing.T) { tcc, rc, bc, bm := givenBundleManager(t) pbc := givenPackageBundleController() pbc.Spec.ActiveBundle = "v1-21-1002" latestBundle := givenBundle() tcc.EXPECT().GetServerVersion(ctx, pbc.Name).Return(&info, nil) tcc.EXPECT().Initialize(ctx, gomock.Any()).Return(nil) tcc.EXPECT().ToRESTConfig().Return(&rest.Config{}, nil) tcc.EXPECT().CreateClusterNamespace(ctx, pbc.Name).Return(nil) bc.EXPECT().GetSecret(ctx, "aws-secret").Return(&corev1.Secret{}, nil) tcc.EXPECT().ApplySecret(ctx, gomock.Any()).Return(nil) rc.EXPECT().LatestBundle(ctx, testBundleRegistry+"/eks-anywhere-packages-bundles", testKubeMajor, testKubeMinor, pbc.Name).Return(latestBundle, nil) bc.EXPECT().GetBundleList(ctx).Return(allBundles, nil) bc.EXPECT().CreateClusterConfigMap(ctx, pbc.Name).Return(nil) rc.EXPECT().DownloadBundle(ctx, "public.ecr.aws/l0g8r8j6/eks-anywhere-packages-bundles:v1-21-1002", pbc.Name).Return(&allBundles[0], nil) bc.EXPECT().CreateBundle(ctx, gomock.Any()).Return(nil) bc.EXPECT().SaveStatus(ctx, pbc).Return(nil) // update available err := bm.ProcessBundleController(ctx, pbc) assert.NoError(t, err) assert.Equal(t, api.BundleControllerStateUpgradeAvailable, pbc.Status.State) }) t.Run("active missing active bundle download error", func(t *testing.T) { tcc, rc, bc, bm := givenBundleManager(t) pbc := givenPackageBundleController() pbc.Spec.ActiveBundle = "v1-21-1002" latestBundle := givenBundle() tcc.EXPECT().GetServerVersion(ctx, pbc.Name).Return(&info, nil) tcc.EXPECT().Initialize(ctx, gomock.Any()).Return(nil) tcc.EXPECT().ToRESTConfig().Return(&rest.Config{}, nil) tcc.EXPECT().CreateClusterNamespace(ctx, pbc.Name).Return(nil) bc.EXPECT().GetSecret(ctx, "aws-secret").Return(&corev1.Secret{}, nil) tcc.EXPECT().ApplySecret(ctx, gomock.Any()).Return(nil) rc.EXPECT().LatestBundle(ctx, testBundleRegistry+"/eks-anywhere-packages-bundles", testKubeMajor, testKubeMinor, pbc.Name).Return(latestBundle, nil) bc.EXPECT().GetBundleList(ctx).Return(allBundles, nil) bc.EXPECT().CreateClusterConfigMap(ctx, pbc.Name).Return(nil) rc.EXPECT().DownloadBundle(ctx, "public.ecr.aws/l0g8r8j6/eks-anywhere-packages-bundles:v1-21-1002", pbc.Name).Return(&allBundles[0], fmt.Errorf("boom")) err := bm.ProcessBundleController(ctx, pbc) assert.NoError(t, err) assert.Equal(t, api.BundleControllerStateActive, pbc.Status.State) }) t.Run("active missing active bundle create error", func(t *testing.T) { tcc, rc, bc, bm := givenBundleManager(t) pbc := givenPackageBundleController() pbc.Spec.ActiveBundle = "v1-21-1002" latestBundle := givenBundle() tcc.EXPECT().GetServerVersion(ctx, pbc.Name).Return(&info, nil) tcc.EXPECT().Initialize(ctx, gomock.Any()).Return(nil) tcc.EXPECT().ToRESTConfig().Return(&rest.Config{}, nil) tcc.EXPECT().CreateClusterNamespace(ctx, pbc.Name).Return(nil) bc.EXPECT().GetSecret(ctx, "aws-secret").Return(&corev1.Secret{}, nil) tcc.EXPECT().ApplySecret(ctx, gomock.Any()).Return(nil) rc.EXPECT().LatestBundle(ctx, testBundleRegistry+"/eks-anywhere-packages-bundles", testKubeMajor, testKubeMinor, pbc.Name).Return(latestBundle, nil) bc.EXPECT().GetBundleList(ctx).Return(allBundles, nil) bc.EXPECT().CreateClusterConfigMap(ctx, pbc.Name).Return(nil) rc.EXPECT().DownloadBundle(ctx, "public.ecr.aws/l0g8r8j6/eks-anywhere-packages-bundles:v1-21-1002", pbc.Name).Return(&allBundles[0], nil) bc.EXPECT().CreateBundle(ctx, gomock.Any()).Return(fmt.Errorf("boom")) err := bm.ProcessBundleController(ctx, pbc) assert.NoError(t, err) assert.Equal(t, api.BundleControllerStateActive, pbc.Status.State) }) t.Run("active to active get bundles error", func(t *testing.T) { tcc, rc, bc, bm := givenBundleManager(t) pbc := givenPackageBundleController() assert.Equal(t, pbc.Spec.ActiveBundle, testBundleName) latestBundle := givenBundle() tcc.EXPECT().GetServerVersion(ctx, pbc.Name).Return(&info, nil) tcc.EXPECT().Initialize(ctx, gomock.Any()).Return(nil) tcc.EXPECT().ToRESTConfig().Return(&rest.Config{}, nil) rc.EXPECT().LatestBundle(ctx, testBundleRegistry+"/eks-anywhere-packages-bundles", testKubeMajor, testKubeMinor, pbc.Name).Return(latestBundle, nil) bc.EXPECT().GetBundleList(ctx).Return(nil, fmt.Errorf("oops")) err := bm.ProcessBundleController(ctx, pbc) assert.EqualError(t, err, "getting bundle list: oops") }) t.Run("active to disconnected", func(t *testing.T) { tcc, rc, bc, bm := givenBundleManager(t) pbc := givenPackageBundleController() assert.Equal(t, pbc.Spec.ActiveBundle, testBundleName) latestBundle := givenBundle() tcc.EXPECT().GetServerVersion(ctx, pbc.Name).Return(&info, nil) tcc.EXPECT().Initialize(ctx, gomock.Any()).Return(nil) tcc.EXPECT().ToRESTConfig().Return(&rest.Config{}, nil) rc.EXPECT().LatestBundle(ctx, testBundleRegistry+"/eks-anywhere-packages-bundles", testKubeMajor, testKubeMinor, pbc.Name).Return(latestBundle, fmt.Errorf("ooops")) bc.EXPECT().SaveStatus(ctx, pbc).Return(nil) err := bm.ProcessBundleController(ctx, pbc) assert.NoError(t, err) assert.Equal(t, api.BundleControllerStateDisconnected, pbc.Status.State) }) t.Run("disconnected to disconnected", func(t *testing.T) { tcc, rc, _, bm := givenBundleManager(t) pbc := givenPackageBundleController() pbc.Status.State = api.BundleControllerStateDisconnected assert.Equal(t, pbc.Spec.ActiveBundle, testBundleName) latestBundle := givenBundle() tcc.EXPECT().Initialize(ctx, gomock.Any()).Return(nil) tcc.EXPECT().ToRESTConfig().Return(&rest.Config{}, nil) tcc.EXPECT().GetServerVersion(ctx, pbc.Name).Return(&info, nil) rc.EXPECT().LatestBundle(ctx, testBundleRegistry+"/eks-anywhere-packages-bundles", testKubeMajor, testKubeMinor, pbc.Name).Return(latestBundle, fmt.Errorf("ooops")) err := bm.ProcessBundleController(ctx, pbc) assert.NoError(t, err) assert.Equal(t, api.BundleControllerStateDisconnected, pbc.Status.State) }) t.Run("active to disconnected error", func(t *testing.T) { tcc, rc, bc, bm := givenBundleManager(t) pbc := givenPackageBundleController() assert.Equal(t, pbc.Spec.ActiveBundle, testBundleName) latestBundle := givenBundle() tcc.EXPECT().GetServerVersion(ctx, pbc.Name).Return(&info, nil) tcc.EXPECT().Initialize(ctx, gomock.Any()).Return(nil) tcc.EXPECT().ToRESTConfig().Return(&rest.Config{}, nil) rc.EXPECT().LatestBundle(ctx, testBundleRegistry+"/eks-anywhere-packages-bundles", testKubeMajor, testKubeMinor, pbc.Name).Return(latestBundle, fmt.Errorf("ooops")) bc.EXPECT().SaveStatus(ctx, pbc).Return(fmt.Errorf("oops")) err := bm.ProcessBundleController(ctx, pbc) assert.EqualError(t, err, "updating cluster01 status to disconnected: oops") }) t.Run("active to upgradeAvailable", func(t *testing.T) { tcc, rc, bc, bm := givenBundleManager(t) pbc := givenPackageBundleController() latestBundle := givenBundle() latestBundle.Name = testNextBundleName tcc.EXPECT().GetServerVersion(ctx, pbc.Name).Return(&info, nil) tcc.EXPECT().Initialize(ctx, gomock.Any()).Return(nil) tcc.EXPECT().ToRESTConfig().Return(&rest.Config{}, nil) tcc.EXPECT().CreateClusterNamespace(ctx, pbc.GetName()).Return(nil) bc.EXPECT().GetSecret(ctx, "aws-secret").Return(&corev1.Secret{}, nil) tcc.EXPECT().ApplySecret(ctx, gomock.Any()).Return(nil) rc.EXPECT().LatestBundle(ctx, testBundleRegistry+"/eks-anywhere-packages-bundles", testKubeMajor, testKubeMinor, pbc.Name).Return(latestBundle, nil) bc.EXPECT().GetBundleList(ctx).Return(allBundles, nil) bc.EXPECT().CreateBundle(ctx, latestBundle).Return(nil) bc.EXPECT().CreateClusterConfigMap(ctx, pbc.Name).Return(nil) bc.EXPECT().SaveStatus(ctx, pbc).Return(nil) err := bm.ProcessBundleController(ctx, pbc) assert.NoError(t, err) assert.Equal(t, api.BundleControllerStateUpgradeAvailable, pbc.Status.State) }) t.Run("active to cm error", func(t *testing.T) { tcc, rc, bc, bm := givenBundleManager(t) pbc := givenPackageBundleController() latestBundle := givenBundle() latestBundle.Name = testNextBundleName tcc.EXPECT().GetServerVersion(ctx, pbc.Name).Return(&info, nil) tcc.EXPECT().Initialize(ctx, gomock.Any()).Return(nil) tcc.EXPECT().ToRESTConfig().Return(&rest.Config{}, nil) rc.EXPECT().LatestBundle(ctx, testBundleRegistry+"/eks-anywhere-packages-bundles", testKubeMajor, testKubeMinor, pbc.Name).Return(latestBundle, nil) bc.EXPECT().GetBundleList(ctx).Return(allBundles, nil) bc.EXPECT().CreateBundle(ctx, latestBundle).Return(nil) bc.EXPECT().CreateClusterConfigMap(ctx, pbc.Name).Return(fmt.Errorf("boom")) err := bm.ProcessBundleController(ctx, pbc) assert.EqualError(t, err, "creating configmap for cluster01: boom") }) t.Run("active to upgradeAvailable error", func(t *testing.T) { tcc, rc, bc, bm := givenBundleManager(t) pbc := givenPackageBundleController() latestBundle := givenBundle() latestBundle.Name = testNextBundleName tcc.EXPECT().GetServerVersion(ctx, pbc.Name).Return(&info, nil) tcc.EXPECT().Initialize(ctx, gomock.Any()).Return(nil) tcc.EXPECT().ToRESTConfig().Return(&rest.Config{}, nil) tcc.EXPECT().CreateClusterNamespace(ctx, pbc.Name).Return(nil) bc.EXPECT().GetSecret(ctx, "aws-secret").Return(&corev1.Secret{}, nil) tcc.EXPECT().ApplySecret(ctx, gomock.Any()).Return(nil) rc.EXPECT().LatestBundle(ctx, testBundleRegistry+"/eks-anywhere-packages-bundles", testKubeMajor, testKubeMinor, pbc.Name).Return(latestBundle, nil) bc.EXPECT().GetBundleList(ctx).Return(allBundles, nil) bc.EXPECT().CreateBundle(ctx, latestBundle).Return(nil) bc.EXPECT().CreateClusterConfigMap(ctx, pbc.Name).Return(nil) bc.EXPECT().SaveStatus(ctx, pbc).Return(fmt.Errorf("oops")) err := bm.ProcessBundleController(ctx, pbc) assert.EqualError(t, err, "updating cluster01 status to upgrade available: oops") }) t.Run("active to upgradeAvailable create error", func(t *testing.T) { tcc, rc, bc, bm := givenBundleManager(t) pbc := givenPackageBundleController() latestBundle := givenBundle() latestBundle.Name = testNextBundleName tcc.EXPECT().GetServerVersion(ctx, pbc.Name).Return(&info, nil) tcc.EXPECT().Initialize(ctx, gomock.Any()).Return(nil) tcc.EXPECT().ToRESTConfig().Return(&rest.Config{}, nil) rc.EXPECT().LatestBundle(ctx, testBundleRegistry+"/eks-anywhere-packages-bundles", testKubeMajor, testKubeMinor, pbc.Name).Return(latestBundle, nil) bc.EXPECT().GetBundleList(ctx).Return(allBundles, nil) bc.EXPECT().CreateBundle(ctx, latestBundle).Return(fmt.Errorf("oops")) err := bm.ProcessBundleController(ctx, pbc) assert.EqualError(t, err, "oops") }) t.Run("upgradeAvailable to upgradeAvailable", func(t *testing.T) { tcc, rc, bc, bm := givenBundleManager(t) pbc := givenPackageBundleController() pbc.Status.State = api.BundleControllerStateUpgradeAvailable pbc.Status.Detail = "v1-21-1004 available" latestBundle := givenBundle() latestBundle.Name = testNextBundleName tcc.EXPECT().GetServerVersion(ctx, pbc.Name).Return(&info, nil) tcc.EXPECT().Initialize(ctx, gomock.Any()).Return(nil) tcc.EXPECT().ToRESTConfig().Return(&rest.Config{}, nil) rc.EXPECT().LatestBundle(ctx, testBundleRegistry+"/eks-anywhere-packages-bundles", testKubeMajor, testKubeMinor, pbc.Name).Return(latestBundle, nil) bc.EXPECT().GetBundleList(ctx).Return(allBundles, nil) bc.EXPECT().CreateBundle(ctx, latestBundle).Return(nil) err := bm.ProcessBundleController(ctx, pbc) assert.NoError(t, err) assert.Equal(t, api.BundleControllerStateUpgradeAvailable, pbc.Status.State) assert.Equal(t, "v1-21-1004 available", pbc.Status.Detail) }) t.Run("upgradeAvailable to upgradeAvailable detail fix", func(t *testing.T) { tcc, rc, bc, bm := givenBundleManager(t) pbc := givenPackageBundleController() pbc.Status.State = api.BundleControllerStateUpgradeAvailable pbc.Status.Detail = "v1-21-1003 available" latestBundle := givenBundle() latestBundle.Name = testNextBundleName tcc.EXPECT().GetServerVersion(ctx, pbc.Name).Return(&info, nil) tcc.EXPECT().Initialize(ctx, gomock.Any()).Return(nil) tcc.EXPECT().ToRESTConfig().Return(&rest.Config{}, nil) rc.EXPECT().LatestBundle(ctx, testBundleRegistry+"/eks-anywhere-packages-bundles", testKubeMajor, testKubeMinor, pbc.Name).Return(latestBundle, nil) bc.EXPECT().GetBundleList(ctx).Return(allBundles, nil) bc.EXPECT().CreateBundle(ctx, latestBundle).Return(nil) bc.EXPECT().SaveStatus(ctx, pbc).Return(nil) err := bm.ProcessBundleController(ctx, pbc) assert.NoError(t, err) assert.Equal(t, api.BundleControllerStateUpgradeAvailable, pbc.Status.State) assert.Equal(t, "v1-21-1004 available", pbc.Status.Detail) }) t.Run("upgradeAvailable to upgradeAvailable detail fix", func(t *testing.T) { tcc, rc, bc, bm := givenBundleManager(t) pbc := givenPackageBundleController() pbc.Status.State = api.BundleControllerStateUpgradeAvailable pbc.Status.Detail = "v1-21-1003 available" latestBundle := givenBundle() latestBundle.Name = testNextBundleName tcc.EXPECT().GetServerVersion(ctx, pbc.Name).Return(&info, nil) tcc.EXPECT().Initialize(ctx, gomock.Any()).Return(nil) tcc.EXPECT().ToRESTConfig().Return(&rest.Config{}, nil) rc.EXPECT().LatestBundle(ctx, testBundleRegistry+"/eks-anywhere-packages-bundles", testKubeMajor, testKubeMinor, pbc.Name).Return(latestBundle, nil) bc.EXPECT().GetBundleList(ctx).Return(allBundles, nil) bc.EXPECT().CreateBundle(ctx, latestBundle).Return(nil) bc.EXPECT().SaveStatus(ctx, pbc).Return(fmt.Errorf("oops")) err := bm.ProcessBundleController(ctx, pbc) assert.EqualError(t, err, "updating cluster01 detail to v1-21-1004 available: oops") }) t.Run("upgradeAvailable to active", func(t *testing.T) { tcc, rc, bc, bm := givenBundleManager(t) pbc := givenPackageBundleController() pbc.Status.State = api.BundleControllerStateUpgradeAvailable latestBundle := givenBundle() tcc.EXPECT().GetServerVersion(ctx, pbc.Name).Return(&info, nil) tcc.EXPECT().Initialize(ctx, gomock.Any()).Return(nil) tcc.EXPECT().ToRESTConfig().Return(&rest.Config{}, nil) rc.EXPECT().LatestBundle(ctx, testBundleRegistry+"/eks-anywhere-packages-bundles", testKubeMajor, testKubeMinor, pbc.Name).Return(latestBundle, nil) bc.EXPECT().GetBundleList(ctx).Return(allBundles, nil) bc.EXPECT().SaveStatus(ctx, pbc).Return(nil) err := bm.ProcessBundleController(ctx, pbc) assert.NoError(t, err) assert.Equal(t, api.BundleControllerStateActive, pbc.Status.State) assert.Equal(t, "", pbc.Status.Detail) }) t.Run("upgradeAvailable to active error", func(t *testing.T) { tcc, rc, bc, bm := givenBundleManager(t) pbc := givenPackageBundleController() pbc.Status.State = api.BundleControllerStateUpgradeAvailable latestBundle := givenBundle() tcc.EXPECT().GetServerVersion(ctx, pbc.Name).Return(&info, nil) tcc.EXPECT().Initialize(ctx, gomock.Any()).Return(nil) tcc.EXPECT().ToRESTConfig().Return(&rest.Config{}, nil) rc.EXPECT().LatestBundle(ctx, testBundleRegistry+"/eks-anywhere-packages-bundles", testKubeMajor, testKubeMinor, pbc.Name).Return(latestBundle, nil) bc.EXPECT().GetBundleList(ctx).Return(allBundles, nil) bc.EXPECT().SaveStatus(ctx, pbc).Return(fmt.Errorf("oops")) err := bm.ProcessBundleController(ctx, pbc) assert.EqualError(t, err, "updating cluster01 status to active: oops") }) t.Run("disconnected to active", func(t *testing.T) { tcc, rc, bc, bm := givenBundleManager(t) pbc := givenPackageBundleController() pbc.Status.State = api.BundleControllerStateDisconnected latestBundle := givenBundle() tcc.EXPECT().GetServerVersion(ctx, pbc.Name).Return(&info, nil) tcc.EXPECT().Initialize(ctx, gomock.Any()).Return(nil) tcc.EXPECT().ToRESTConfig().Return(&rest.Config{}, nil) rc.EXPECT().LatestBundle(ctx, testBundleRegistry+"/eks-anywhere-packages-bundles", testKubeMajor, testKubeMinor, pbc.Name).Return(latestBundle, nil) bc.EXPECT().GetBundleList(ctx).Return(allBundles, nil) bc.EXPECT().SaveStatus(ctx, pbc).Return(nil) err := bm.ProcessBundleController(ctx, pbc) assert.NoError(t, err) assert.Equal(t, api.BundleControllerStateActive, pbc.Status.State) }) t.Run("disconnected to active error", func(t *testing.T) { tcc, rc, bc, bm := givenBundleManager(t) pbc := givenPackageBundleController() pbc.Status.State = api.BundleControllerStateDisconnected latestBundle := givenBundle() tcc.EXPECT().GetServerVersion(ctx, pbc.Name).Return(&info, nil) tcc.EXPECT().Initialize(ctx, gomock.Any()).Return(nil) tcc.EXPECT().ToRESTConfig().Return(&rest.Config{}, nil) rc.EXPECT().LatestBundle(ctx, testBundleRegistry+"/eks-anywhere-packages-bundles", testKubeMajor, testKubeMinor, pbc.Name).Return(latestBundle, nil) bc.EXPECT().GetBundleList(ctx).Return(allBundles, nil) bc.EXPECT().SaveStatus(ctx, pbc).Return(fmt.Errorf("oops")) err := bm.ProcessBundleController(ctx, pbc) assert.EqualError(t, err, "updating cluster01 status to active: oops") }) t.Run("nothing to active bundle set", func(t *testing.T) { tcc, rc, bc, bm := givenBundleManager(t) pbc := givenPackageBundleController() pbc.Status.State = "" pbc.Spec.ActiveBundle = "" latestBundle := givenBundle() latestBundle.Name = testNextBundleName tcc.EXPECT().GetServerVersion(ctx, pbc.Name).Return(&info, nil) tcc.EXPECT().Initialize(ctx, gomock.Any()).Return(nil) tcc.EXPECT().ToRESTConfig().Return(&rest.Config{}, nil) tcc.EXPECT().CreateClusterNamespace(ctx, pbc.GetName()).Return(nil).AnyTimes() rc.EXPECT().LatestBundle(ctx, testBundleRegistry+"/eks-anywhere-packages-bundles", testKubeMajor, testKubeMinor, pbc.Name).Return(latestBundle, nil) bc.EXPECT().GetBundleList(ctx).Return(allBundles, nil) bc.EXPECT().CreateBundle(ctx, latestBundle).Return(nil) bc.EXPECT().Save(ctx, pbc).Return(nil) err := bm.ProcessBundleController(ctx, pbc) assert.NoError(t, err) assert.Equal(t, api.BundleControllerStateEnum(""), pbc.Status.State) assert.Equal(t, testNextBundleName, pbc.Spec.ActiveBundle) }) t.Run("nothing to active bundle save error", func(t *testing.T) { tcc, rc, bc, bm := givenBundleManager(t) pbc := givenPackageBundleController() pbc.Status.State = "" pbc.Spec.ActiveBundle = "" latestBundle := givenBundle() latestBundle.Name = testNextBundleName tcc.EXPECT().GetServerVersion(ctx, pbc.Name).Return(&info, nil) tcc.EXPECT().Initialize(ctx, gomock.Any()).Return(nil) tcc.EXPECT().ToRESTConfig().Return(&rest.Config{}, nil) rc.EXPECT().LatestBundle(ctx, testBundleRegistry+"/eks-anywhere-packages-bundles", testKubeMajor, testKubeMinor, pbc.Name).Return(latestBundle, nil) bc.EXPECT().GetBundleList(ctx).Return(allBundles, nil) bc.EXPECT().CreateBundle(ctx, latestBundle).Return(nil) bc.EXPECT().Save(ctx, pbc).Return(fmt.Errorf("oops")) err := bm.ProcessBundleController(ctx, pbc) assert.EqualError(t, err, "updating cluster01 activeBundle to v1-21-1004: oops") }) t.Run("nothing to active state", func(t *testing.T) { tcc, rc, bc, bm := givenBundleManager(t) pbc := givenPackageBundleController() pbc.Status.State = "" latestBundle := givenBundle() tcc.EXPECT().GetServerVersion(ctx, pbc.Name).Return(&info, nil) tcc.EXPECT().Initialize(ctx, gomock.Any()).AnyTimes().Return(nil) tcc.EXPECT().ToRESTConfig().Return(&rest.Config{}, nil) rc.EXPECT().LatestBundle(ctx, testBundleRegistry+"/eks-anywhere-packages-bundles", testKubeMajor, testKubeMinor, pbc.Name).Return(latestBundle, nil) bc.EXPECT().GetBundleList(ctx).Return(allBundles, nil) bc.EXPECT().SaveStatus(ctx, pbc).Return(nil) err := bm.ProcessBundleController(ctx, pbc) assert.NoError(t, err) assert.Equal(t, api.BundleControllerStateActive, pbc.Status.State) assert.Equal(t, testBundleName, pbc.Spec.ActiveBundle) }) t.Run("nothing to active status save error", func(t *testing.T) { tcc, rc, bc, bm := givenBundleManager(t) pbc := givenPackageBundleController() pbc.Status.State = "" latestBundle := givenBundle() latestBundle.Name = testNextBundleName tcc.EXPECT().GetServerVersion(ctx, pbc.Name).Return(&info, nil) tcc.EXPECT().Initialize(ctx, gomock.Any()).AnyTimes().Return(nil) tcc.EXPECT().ToRESTConfig().Return(&rest.Config{}, nil) rc.EXPECT().LatestBundle(ctx, testBundleRegistry+"/eks-anywhere-packages-bundles", testKubeMajor, testKubeMinor, pbc.Name).Return(latestBundle, nil) bc.EXPECT().GetBundleList(ctx).Return(allBundles, nil) bc.EXPECT().CreateBundle(ctx, latestBundle).Return(nil) bc.EXPECT().SaveStatus(ctx, pbc).Return(fmt.Errorf("oops")) err := bm.ProcessBundleController(ctx, pbc) assert.EqualError(t, err, "updating cluster01 status to active: oops") }) t.Run("skip applying secret when pbc is mgmt", func(t *testing.T) { tcc, rc, bc, bm := givenBundleManager(t) pbc := givenPackageBundleController() _ = os.Setenv("CLUSTER_NAME", pbc.Name) latestBundle := givenBundle() tcc.EXPECT().GetServerVersion(ctx, pbc.Name).Return(&info, nil) tcc.EXPECT().Initialize(ctx, gomock.Any()).Return(nil) tcc.EXPECT().ToRESTConfig().Return(&rest.Config{}, nil) tcc.EXPECT().CreateClusterNamespace(ctx, pbc.Name).Return(nil) rc.EXPECT().LatestBundle(ctx, testBundleRegistry+"/eks-anywhere-packages-bundles", testKubeMajor, testKubeMinor, pbc.Name).Return(latestBundle, nil) bc.EXPECT().GetBundleList(ctx).Return(allBundles, nil) bc.EXPECT().CreateClusterConfigMap(ctx, pbc.Name).Return(nil) err := bm.ProcessBundleController(ctx, pbc) _ = os.Setenv("CLUSTER_NAME", "") assert.NoError(t, err) assert.Equal(t, api.BundleControllerStateActive, pbc.Status.State) }) t.Run("active to active skip secret when pbc", func(t *testing.T) { tcc, rc, bc, bm := givenBundleManager(t) pbc := givenPackageBundleController() _ = os.Setenv("CLUSTER_NAME", "other-cluster-name") latestBundle := givenBundle() tcc.EXPECT().GetServerVersion(ctx, pbc.Name).Return(&info, nil) tcc.EXPECT().Initialize(ctx, gomock.Any()).Return(nil) tcc.EXPECT().ToRESTConfig().Return(&rest.Config{}, nil) tcc.EXPECT().CreateClusterNamespace(ctx, pbc.Name).Return(nil) tcc.EXPECT().ApplySecret(ctx, gomock.Any()).Return(nil) rc.EXPECT().LatestBundle(ctx, testBundleRegistry+"/eks-anywhere-packages-bundles", testKubeMajor, testKubeMinor, pbc.Name).Return(latestBundle, nil) bc.EXPECT().GetBundleList(ctx).Return(allBundles, nil) bc.EXPECT().CreateClusterConfigMap(ctx, pbc.Name).Return(nil) bc.EXPECT().GetSecret(ctx, "aws-secret").Return(&corev1.Secret{}, nil) err := bm.ProcessBundleController(ctx, pbc) _ = os.Setenv("CLUSTER_NAME", "") assert.NoError(t, err) assert.Equal(t, api.BundleControllerStateActive, pbc.Status.State) }) } func TestBundleManager_isCompatible(t *testing.T) { t.Parallel() tests := map[string]struct { minVersion string curVersion string isCompatible bool }{ "same version": {minVersion: "v2.2.2", curVersion: "v2.2.2", isCompatible: true}, "development is compatible with anything": {minVersion: "v2.2.2", curVersion: "development", isCompatible: true}, "newer patch version requirement makes it incompatible": {minVersion: "v2.2.3", curVersion: "v2.2.2", isCompatible: false}, "newer minor version requirement makes it incompatible": {minVersion: "v2.3.2", curVersion: "v2.2.2", isCompatible: false}, "newer major version requirement makes it incompatible": {minVersion: "v3.2.2", curVersion: "v2.2.2", isCompatible: false}, "build info is irrelevant": {minVersion: "v2.2.2", curVersion: "v2.2.2+shasum", isCompatible: true}, "build info is irrelevant also if incompatible": {minVersion: "v2.2.3", curVersion: "v2.2.2+shasum", isCompatible: false}, "invalid pkg version is incompatible": {minVersion: "v2.2.3", curVersion: "2.2.3", isCompatible: false}, "both invalid version is compatible, I suppose?": {minVersion: "2.2.3", curVersion: "2.2.2", isCompatible: true}, "any version is compatible when no requirements imposed": {minVersion: "", curVersion: "2.2.2", isCompatible: true}, } for name, test := range tests { t.Run(name, func(t *testing.T) { _, _, _, bm := givenBundleManager(t) latestBundle := givenBundle() latestBundle.Spec.MinVersion = test.minVersion bm.config.BuildInfo.Version = test.curVersion assert.Equal(t, test.isCompatible, bm.isCompatibleWith(latestBundle)) }) } }