Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/codecov.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
comment: false

github_checks:
annotations: false
21 changes: 17 additions & 4 deletions .github/workflows/test-e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ jobs:
echo "k8s_platform=$platform" >> $GITHUB_OUTPUT
- name: Create k8s Kind Cluster
if: ${{ steps.properties.outputs.k8s_platform == 'kind' && !env.ACT }}
uses: helm/kind-action@v1.4.0
uses: helm/kind-action@v1.5.0
with:
version: v0.11.1
config: test/e2e/config/kind.yaml
Expand All @@ -193,6 +193,10 @@ jobs:
wget https://github.com/operator-framework/operator-sdk/releases/download/v1.22.0/operator-sdk_linux_amd64 -q
chmod +x operator-sdk_linux_amd64 && sudo mv operator-sdk_linux_amd64 /usr/local/bin/operator-sdk
operator-sdk version
- name: Install CRDs if needed
if: ${{ !( matrix.test == 'helm-update' || matrix.test == 'helm-wide' || matrix.test == 'bundle-test' ) }}
run: |
kubectl apply -f deploy/crds
- name: Run e2e test
env:
MCLI_PUBLIC_API_KEY: ${{ secrets.ATLAS_PUBLIC_KEY }}
Expand Down Expand Up @@ -221,17 +225,26 @@ jobs:
run: |
helm version
go version

go install github.com/onsi/ginkgo/v2/ginkgo@v2.6.1 && \
go install github.com/onsi/gomega/...

cd test/e2e

# no `long-run`, no `broken` tests. `Long-run` tests run as a separate job
[[ $TEST_NAME == 'long-run' ]] && filter='long-run && !broken' || filter="$TEST_NAME"' && !long-run && !broken' && \
echo 'Running: ginkgo --label-filter="${filter}" --timeout 120m --nodes=10 -v test/e2e/' && \
ginkgo --label-filter="${filter}" --timeout 120m --nodes=10 -v test/e2e/
echo 'Running: ginkgo --label-filter="${filter}" --timeout 120m --nodes=10 --cover --v' && \
ginkgo --label-filter="${filter}" --timeout 120m --nodes=10 --cover --v --coverpkg=github.com/mongodb/mongodb-atlas-kubernetes/pkg/...
- name: Upload operator logs
if: ${{ failure() }}
uses: actions/upload-artifact@v3
with:
name: logs
path: test/e2e/output/**
- name: Upload test results to codecov.io
if: ${{ success() }}
uses: codecov/codecov-action@v3
with:
files: test/e2e/coverprofile.out
name: ${{ matrix.test }}
verbose: true
31 changes: 27 additions & 4 deletions .github/workflows/test-int.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,36 @@ jobs:
~/.cache/go-build
~/go/pkg/mod
key: ${{ runner.os }}-build-${{ hashFiles('**/go.sum') }}

- name: Run testing
uses: ./.github/actions/int-test
- name: Setup Go
uses: actions/setup-go@v3
with:
go-version-file: "${{ github.workspace }}/go.mod"
- name: Run testing
env:
ATLAS_ORG_ID: ${{ secrets.ATLAS_ORG_ID }}
ATLAS_PUBLIC_KEY: ${{ secrets.ATLAS_PUBLIC_KEY }}
ATLAS_PRIVATE_KEY: ${{ secrets.ATLAS_PRIVATE_KEY }}
TEST_NAME: ${{ matrix.test }}
TEST_PATH: ${{ matrix.path }}
PARALLEL_NODES: ${{ matrix.nodes }}
GO111MODULE: on
GINKGO_EDITOR_INTEGRATION: "true"
run: |

# Download binaries for envtests (api-server, etcd)
sudo curl -Lo setup-envtest.sh https://raw.githubusercontent.com/kubernetes-sigs/controller-runtime/v0.8.0/hack/setup-envtest.sh && \
sudo mkdir -p /usr/local/kubebuilder/bin && \
sudo /bin/bash -c "source setup-envtest.sh && fetch_envtest_tools /usr/local/kubebuilder"

go install github.com/onsi/ginkgo/v2/ginkgo@v2.6.1 && \
go install github.com/onsi/gomega/...

cd ${{ matrix.path }}
ginkgo --label-filter="${TEST_NAME}" --timeout 80m --v --nodes="${PARALLEL_NODES}" --cover --coverpkg=github.com/mongodb/mongodb-atlas-kubernetes/pkg/...

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
with:
name: ${{ matrix.test }}
files: ${{ matrix.path }}/coverprofile.out
verbose: true

9 changes: 8 additions & 1 deletion .github/workflows/test-unit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,11 @@ jobs:
- run: go version

- name: Run testing
run: CGO_ENABLED=0 go test -v $(go list ./pkg/...)
run: CGO_ENABLED=0 go test -v $(go list ./pkg/...) -coverprofile=coverage.out

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
with:
name: unit-tests
files: coverage.out
verbose: true
21 changes: 21 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,27 @@ jobs:
steps:
- name: allowed message
run: echo "Allowed to run"
- name: check Github action bot comment
if: github.event_name == 'pull_request'
uses: peter-evans/find-comment@v2
id: find-bot-comment
with:
issue-number: ${{ github.event.pull_request.number }}
comment-author: github-actions[bot]
body-includes: 'https://app.codecov.io/github/mongodb/mongodb-atlas-kubernetes/commit'
- name: edit comment if exists
if: github.event_name == 'pull_request' && steps.find-bot-comment.outputs.comment-id != ''
uses: peter-evans/create-or-update-comment@v2
with:
edit-mode: replace
comment-id: ${{ steps.find-bot-comment.outputs.comment-id }}
body: https://app.codecov.io/github/mongodb/mongodb-atlas-kubernetes/commit/${{ github.event.pull_request.head.sha }}
- name: comment PR
if: github.event_name == 'pull_request' && steps.find-bot-comment.outputs.comment-id == ''
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh pr comment ${{ github.event.pull_request.number }} -R mongodb/mongodb-atlas-kubernetes -b "https://app.codecov.io/github/mongodb/mongodb-atlas-kubernetes/commit/${{ github.event.pull_request.head.sha }}"

unit-tests:
needs: allowed
Expand Down
182 changes: 31 additions & 151 deletions test/e2e/actions/deploy/deploy_operator.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,169 +2,46 @@
package deploy

import (
"context"
"fmt"
"os"
"path/filepath"
"strings"
"time"

"github.com/mongodb/mongodb-atlas-kubernetes/test/e2e/k8s"

"github.com/mongodb/mongodb-atlas-kubernetes/pkg/api/v1/status"

corev1 "k8s.io/api/core/v1"

"github.com/mongodb/mongodb-atlas-kubernetes/test/e2e/actions/kube"

"k8s.io/apimachinery/pkg/types"

"github.com/mongodb/mongodb-atlas-kubernetes/test/e2e/api/atlas"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"

kubecli "github.com/mongodb/mongodb-atlas-kubernetes/test/e2e/cli/kubecli"
"github.com/mongodb/mongodb-atlas-kubernetes/test/e2e/cli/kustomize"
"github.com/mongodb/mongodb-atlas-kubernetes/pkg/api/v1/status"
"github.com/mongodb/mongodb-atlas-kubernetes/test/e2e/actions/kube"
"github.com/mongodb/mongodb-atlas-kubernetes/test/e2e/config"
"github.com/mongodb/mongodb-atlas-kubernetes/test/e2e/k8s"
"github.com/mongodb/mongodb-atlas-kubernetes/test/e2e/model"
"github.com/mongodb/mongodb-atlas-kubernetes/test/e2e/utils"
)

// prepareNamespaceOperatorResources create copy of `/deploy/namespaced` folder with kustomization file for overriding namespace
func prepareNamespaceOperatorResources(input model.UserInputs) {
fullPath := input.GetOperatorFolder()
os.Mkdir(fullPath, os.ModePerm)
utils.CopyFile(config.DefaultNamespacedCRDConfig, filepath.Join(fullPath, "crds.yaml"))
utils.CopyFile(config.DefaultNamespacedOperatorConfig, filepath.Join(fullPath, "namespaced-config.yaml"))
data := []byte(
"namespace: " + input.Namespace + "\n" +
"resources:" + "\n" +
"- crds.yaml" + "\n" +
"- namespaced-config.yaml",
)
utils.SaveToFile(filepath.Join(fullPath, "kustomization.yaml"), data)
}

// CopyKustomizeNamespaceOperator create copy of `/deploy/namespaced` folder with kustomization file for overriding namespace
func prepareWideOperatorResources(input model.UserInputs) {
fullPath := input.GetOperatorFolder()
os.Mkdir(fullPath, os.ModePerm)
utils.CopyFile(config.DefaultClusterWideCRDConfig, filepath.Join(fullPath, "crds.yaml"))
utils.CopyFile(config.DefaultClusterWideOperatorConfig, filepath.Join(fullPath, "clusterwide-config.yaml"))
}

// CopyKustomizeNamespaceOperator create copy of `/deploy/namespaced` folder with kustomization file for overriding namespace
func prepareMultiNamespaceOperatorResources(input model.UserInputs, watchedNamespaces []string) {
fullPath := input.GetOperatorFolder()
err := os.Mkdir(fullPath, os.ModePerm)
Expect(err).ShouldNot(HaveOccurred())
utils.CopyFile(config.DefaultClusterWideCRDConfig, filepath.Join(fullPath, "crds.yaml"))
utils.CopyFile(config.DefaultClusterWideOperatorConfig, filepath.Join(fullPath, "multinamespace-config.yaml"))
namespaces := strings.Join(watchedNamespaces, ",")
patchWatch := []byte(
"apiVersion: apps/v1\n" +
"kind: Deployment\n" +
"metadata:\n" +
" name: mongodb-atlas-operator\n" +
"spec:\n" +
" template:\n" +
" spec:\n" +
" containers:\n" +
" - name: manager\n" +
" env:\n" +
" - name: WATCH_NAMESPACE\n" +
" value: \"" + namespaces + "\"",
)
err = utils.SaveToFile(filepath.Join(fullPath, "patch.yaml"), patchWatch)
Expect(err).ShouldNot(HaveOccurred())
kustomization := []byte(
"resources:\n" +
"- multinamespace-config.yaml\n" +
"patches:\n" +
"- path: patch.yaml\n" +
" target:\n" +
" group: apps\n" +
" version: v1\n" +
" kind: Deployment\n" +
" name: mongodb-atlas-operator",
)
err = utils.SaveToFile(filepath.Join(fullPath, "kustomization.yaml"), kustomization)
Expect(err).ShouldNot(HaveOccurred())
}

func NamespacedOperator(data *model.TestDataProvider) {
prepareNamespaceOperatorResources(data.Resources)
By("Deploy namespaced Operator\n", func() {
kubecli.Apply("-k", data.Resources.GetOperatorFolder())
CheckOperatorRunning(data, data.Resources.Namespace)
})
}

func CheckOperatorRunning(data *model.TestDataProvider, namespace string) {
By("Check Operator is running", func() {
Eventually(
func(g Gomega) string {
status, err := k8s.GetPodStatus(data.Context, data.K8SClient, namespace)
g.Expect(err).ShouldNot(HaveOccurred())
return status
},
"5m", "3s",
).Should(Equal("Running"), "The operator should successfully run")
})
}

func ClusterWideOperator(data *model.TestDataProvider) {
prepareWideOperatorResources(data.Resources)
By("Deploy clusterwide Operator \n", func() {
kubecli.Apply("-k", data.Resources.GetOperatorFolder())
CheckOperatorRunning(data, config.DefaultOperatorNS)
})
}

func MultiNamespaceOperator(data *model.TestDataProvider, watchNamespace []string) {
prepareMultiNamespaceOperatorResources(data.Resources, watchNamespace)
By("Deploy multinamespaced Operator \n", func() {
kustomOperatorPath := data.Resources.GetOperatorFolder() + "/final.yaml"
utils.SaveToFile(kustomOperatorPath, kustomize.Build(data.Resources.GetOperatorFolder()))
kubecli.Apply(kustomOperatorPath)
CheckOperatorRunning(data, config.DefaultOperatorNS)
})
}

func DeleteProject(testData *model.TestDataProvider) {
By("Delete Project", func() {
projectId := testData.Project.Status.ID
Expect(testData.K8SClient.Get(testData.Context, types.NamespacedName{Name: testData.Project.Name, Namespace: testData.Project.Namespace}, testData.Project)).Should(Succeed(), "Get project failed")
Expect(testData.K8SClient.Delete(testData.Context, testData.Project)).Should(Succeed(), "Delete project failed")
aClient := atlas.GetClientOrFail()
Eventually(func(g Gomega) bool {
return aClient.IsProjectExists(g, projectId)
}).WithTimeout(5*time.Minute).WithPolling(20*time.Second).Should(BeTrue(), "Project was not deleted in Atlas")
})
}

func DeleteUsers(testData *model.TestDataProvider) {
By("Delete Users", func() {
for _, user := range testData.Users {
Expect(testData.K8SClient.Get(testData.Context, types.NamespacedName{Name: user.Name, Namespace: user.Namespace}, user)).Should(Succeed(), "Get user failed")
Expect(testData.K8SClient.Delete(testData.Context, user)).Should(Succeed(), "Delete user failed")
}
})
}

func DeleteInitialDeployments(testData *model.TestDataProvider) {
By("Delete initial deployments", func() {
for _, deployment := range testData.InitialDeployments {
projectId := testData.Project.Status.ID
deploymentName := deployment.Spec.DeploymentSpec.Name
Expect(testData.K8SClient.Get(testData.Context, types.NamespacedName{Name: deployment.Name,
Namespace: testData.Resources.Namespace}, deployment)).Should(Succeed(), "Get deployment failed")
Expect(testData.K8SClient.Delete(testData.Context, deployment)).Should(Succeed(), "Deployment %s was not deleted", deployment.Name)
aClient := atlas.GetClientOrFail()
Eventually(func() bool {
return aClient.IsDeploymentExist(projectId, deploymentName)
}).WithTimeout(15*time.Minute).WithPolling(20*time.Second).Should(BeFalse(), "Deployment should be deleted in Atlas")
watchNamespaceMap := make(map[string]bool, len(watchNamespace))
for _, ns := range watchNamespace {
watchNamespaceMap[ns] = true
}
mgr, err := k8s.RunOperator(&k8s.Config{
Namespace: config.DefaultOperatorNS,
GlobalAPISecret: client.ObjectKey{
Namespace: config.DefaultOperatorNS,
Name: config.DefaultOperatorGlobalKey,
},
WatchedNamespaces: watchNamespaceMap,
LogDir: "logs",
})
Expect(err).Should(Succeed())
ctx := context.Background()
go func(ctx context.Context) {
err = mgr.Start(ctx)
Expect(err).Should(Succeed(), "Operator should be started")
}(ctx)
data.ManagerContext = ctx
})
}

Expand All @@ -175,8 +52,11 @@ func CreateProject(testData *model.TestDataProvider) {
By(fmt.Sprintf("Deploy Project %s", testData.Project.GetName()), func() {
err := testData.K8SClient.Create(testData.Context, testData.Project)
Expect(err).ShouldNot(HaveOccurred(), "Project %s was not created", testData.Project.GetName())
Eventually(kube.ProjectReadyCondition(testData)).WithTimeout(5*time.Minute).WithPolling(20*time.Second).
Should(Not(Equal("False")), "Project %s should be ready", testData.Project.GetName())
Eventually(func(g Gomega) {
condition, _ := k8s.GetProjectStatusCondition(testData.Context, testData.K8SClient, status.ReadyType,
testData.Resources.Namespace, testData.Project.GetName())
g.Expect(condition).Should(Equal("True"))
}).Should(Succeed(), "Project %s was not created", testData.Project.GetName())
})
By(fmt.Sprintf("Wait for Project %s", testData.Project.GetName()), func() {
Eventually(func() bool {
Expand Down
Loading