diff --git a/.github/workflows/e2e.yaml b/.github/workflows/e2e.yaml index 3dadbc35..be988156 100644 --- a/.github/workflows/e2e.yaml +++ b/.github/workflows/e2e.yaml @@ -29,14 +29,20 @@ jobs: version: v0.11.1 image: kindest/node:v1.21.1@sha256:69860bda5563ac81e3c0057d654b5253219618a22ec3a346306239bba8cfa1a6 config: .github/kind/config.yaml # disable KIND-net + - name: Setup envtest + uses: fluxcd/pkg/actions/envtest@main + with: + version: "1.21.x" - name: Setup Calico for network policy run: | kubectl apply -f https://docs.projectcalico.org/v3.16/manifests/calico.yaml kubectl -n kube-system set env daemonset/calico-node FELIX_IGNORELOOSERPF=true - name: Setup Kustomize uses: fluxcd/pkg//actions/kustomize@main - - name: Run test + - name: Run tests run: make test + - name: Run e2e tests + run: TEST_KUBECONFIG=$HOME/.kube/config make e2e - name: Check if working tree is dirty run: | if [[ $(git diff --stat) != '' ]]; then diff --git a/Makefile b/Makefile index 7a674fff..fa499d5d 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,6 @@ VERSION?=$(shell grep 'VERSION' cmd/flux/main.go | awk '{ print $$4 }' | tr -d '"') EMBEDDED_MANIFESTS_TARGET=cmd/flux/manifests +TEST_KUBECONFIG?=/tmp/flux-e2e-test-kubeconfig rwildcard=$(foreach d,$(wildcard $(addsuffix *,$(1))),$(call rwildcard,$(d)/,$(2)) $(filter $(subst *,%,$(2)),$(d))) @@ -14,9 +15,41 @@ fmt: vet: go vet ./... +setup-envtest: +ifeq (, $(shell which setup-envtest)) + @{ \ + set -e ;\ + SETUP_ENVTEST_TMP_DIR=$$(mktemp -d) ;\ + cd $$SETUP_ENVTEST_TMP_DIR ;\ + go mod init tmp ;\ + go get sigs.k8s.io/controller-runtime/tools/setup-envtest@latest ;\ + rm -rf $$SETUP_ENVTEST_TMP_DIR ;\ + } +SETUP_ENVTEST=$(GOBIN)/setup-envtest +else +SETUP_ENVTEST=$(shell which setup-envtest) +endif + +setup-kind: + kind create cluster --name=flux-e2e-test --kubeconfig=$(TEST_KUBECONFIG) --config=.github/kind/config.yaml + kubectl --kubeconfig=$(TEST_KUBECONFIG) apply -f https://docs.projectcalico.org/v3.16/manifests/calico.yaml + kubectl --kubeconfig=$(TEST_KUBECONFIG) -n kube-system set env daemonset/calico-node FELIX_IGNORELOOSERPF=true + +cleanup-kind: + kind delete cluster --name=flux-e2e-test + rm $(TEST_KUBECONFIG) + test: $(EMBEDDED_MANIFESTS_TARGET) tidy fmt vet go test ./... -coverprofile cover.out +e2e: $(EMBEDDED_MANIFESTS_TARGET) tidy fmt vet + TEST_KUBECONFIG=$(TEST_KUBECONFIG) go test ./cmd/flux/... -coverprofile cover.out --tags=e2e -parallel=1 + +test-with-kind: setup-envtest + make setup-kind + make e2e + make cleanup-kind + $(EMBEDDED_MANIFESTS_TARGET): $(call rwildcard,manifests/,*.yaml *.json) ./manifests/scripts/bundle.sh diff --git a/cmd/flux/install_test.go b/cmd/flux/install_test.go new file mode 100644 index 00000000..35d532f3 --- /dev/null +++ b/cmd/flux/install_test.go @@ -0,0 +1,54 @@ +// +build e2e + +package main + +import ( + "testing" + "time" +) + +func TestInstallNoArgs(t *testing.T) { + cmd := cmdTestCase{ + args: "install", + wantError: false, + testClusterMode: ExistingClusterMode, + goldenFile: "testdata/install/install_no_args.golden", + } + cmd.runTestCmd(t) + + testUninstallSilent(t) + time.Sleep(30 * time.Second) +} + +func TestInstallExtraComponents(t *testing.T) { + cmd := cmdTestCase{ + args: "install --components-extra=image-reflector-controller,image-automation-controller", + wantError: false, + testClusterMode: ExistingClusterMode, + goldenFile: "testdata/install/install_extra_components.golden", + } + cmd.runTestCmd(t) + + testUninstallSilentForExtraComponents(t) + time.Sleep(30 * time.Second) +} + +func testUninstallSilent(t *testing.T) { + cmd := cmdTestCase{ + args: "uninstall -s", + wantError: false, + testClusterMode: ExistingClusterMode, + goldenFile: "testdata/uninstall/uninstall.golden", + } + cmd.runTestCmd(t) +} + +func testUninstallSilentForExtraComponents(t *testing.T) { + cmd := cmdTestCase{ + args: "uninstall -s", + wantError: false, + testClusterMode: ExistingClusterMode, + goldenFile: "testdata/uninstall/uninstall_extra_components.golden", + } + cmd.runTestCmd(t) +} diff --git a/cmd/flux/main_test.go b/cmd/flux/main_test.go index 832fb84b..3a4b9762 100644 --- a/cmd/flux/main_test.go +++ b/cmd/flux/main_test.go @@ -4,17 +4,23 @@ import ( "bufio" "bytes" "context" + "fmt" "io" + "io/ioutil" "os" + "path/filepath" "testing" + "time" "github.com/fluxcd/flux2/internal/utils" "github.com/google/go-cmp/cmp" "github.com/mattn/go-shellwords" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" k8syaml "k8s.io/apimachinery/pkg/util/yaml" + "k8s.io/client-go/tools/clientcmd" "sigs.k8s.io/controller-runtime/pkg/client" fakeclient "sigs.k8s.io/controller-runtime/pkg/client/fake" + "sigs.k8s.io/controller-runtime/pkg/envtest" ) func TestMain(m *testing.M) { @@ -49,17 +55,18 @@ func readYamlObjects(objectFile string) ([]client.Object, error) { } // A KubeManager that can create objects that are subject to a test. -type fakeKubeManager struct { - fakeClient client.WithWatch +type testEnvKubeManager struct { + client client.WithWatch + testEnv *envtest.Environment } -func (m *fakeKubeManager) NewClient(kubeconfig string, kubecontext string) (client.WithWatch, error) { - return m.fakeClient, nil +func (m *testEnvKubeManager) NewClient(kubeconfig string, kubecontext string) (client.WithWatch, error) { + return m.client, nil } -func (m *fakeKubeManager) CreateObjects(clientObjects []client.Object) error { +func (m *testEnvKubeManager) CreateObjects(clientObjects []client.Object) error { for _, obj := range clientObjects { - err := m.fakeClient.Create(context.Background(), obj) + err := m.client.Create(context.Background(), obj) if err != nil { return err } @@ -67,32 +74,92 @@ func (m *fakeKubeManager) CreateObjects(clientObjects []client.Object) error { return nil } -func NewFakeKubeManager() *fakeKubeManager { - c := fakeclient.NewClientBuilder().WithScheme(utils.NewScheme()).Build() - return &fakeKubeManager{ - fakeClient: c, +func (m *testEnvKubeManager) Stop() error { + if m.testEnv == nil { + return fmt.Errorf("do nothing because testEnv is nil") } + return m.testEnv.Stop() } -// Run the command and return the captured output. -func executeCommand(cmd string) (string, error) { - args, err := shellwords.Parse(cmd) - if err != nil { - return "", err - } +func NewTestEnvKubeManager(testClusterMode TestClusterMode) (*testEnvKubeManager, error) { + switch testClusterMode { + case FakeClusterMode: + c := fakeclient.NewClientBuilder().WithScheme(utils.NewScheme()).Build() + return &testEnvKubeManager{ + client: c, + }, nil + case TestEnvClusterMode: + useExistingCluster := false + testEnv := &envtest.Environment{ + UseExistingCluster: &useExistingCluster, + } + cfg, err := testEnv.Start() + if err != nil { + return nil, err + } + user, err := testEnv.ControlPlane.AddUser(envtest.User{ + Name: "envtest-admin", + Groups: []string{"system:masters"}, + }, nil) + if err != nil { + return nil, err + } - buf := new(bytes.Buffer) + kubeConfig, err := user.KubeConfig() + if err != nil { + return nil, err + } - rootCmd.SetOut(buf) - rootCmd.SetErr(buf) - rootCmd.SetArgs(args) + tmpFilename := filepath.Join("/tmp", "kubeconfig-"+time.Nanosecond.String()) + ioutil.WriteFile(tmpFilename, kubeConfig, 0644) + rootArgs.kubeconfig = tmpFilename + k8sClient, err := client.NewWithWatch(cfg, client.Options{}) + if err != nil { + return nil, err + } + return &testEnvKubeManager{ + testEnv: testEnv, + client: k8sClient, + }, nil + case ExistingClusterMode: + // TEST_KUBECONFIG is mandatory to prevent destroying a current cluster accidentally. + testKubeConfig := os.Getenv("TEST_KUBECONFIG") + if testKubeConfig == "" { + return nil, fmt.Errorf("environment variable TEST_KUBECONFIG is required to run tests against an existing cluster") + } + rootArgs.kubeconfig = testKubeConfig - _, err = rootCmd.ExecuteC() - result := buf.String() + useExistingCluster := true + config, err := clientcmd.BuildConfigFromFlags("", testKubeConfig) + testEnv := &envtest.Environment{ + UseExistingCluster: &useExistingCluster, + Config: config, + } + cfg, err := testEnv.Start() + if err != nil { + return nil, err + } + k8sClient, err := client.NewWithWatch(cfg, client.Options{}) + if err != nil { + return nil, err + } + return &testEnvKubeManager{ + testEnv: testEnv, + client: k8sClient, + }, nil + } - return result, err + return nil, nil } +type TestClusterMode int + +const ( + FakeClusterMode = TestClusterMode(iota + 1) + TestEnvClusterMode + ExistingClusterMode +) + // Structure used for each test to load objects into kubernetes, run // commands and assert on the expected output. type cmdTestCase struct { @@ -106,11 +173,20 @@ type cmdTestCase struct { goldenFile string // Filename that contains yaml objects to load into Kubernetes objectFile string + // TestClusterMode to bootstrap and testing, default to Fake + testClusterMode TestClusterMode } func (cmd *cmdTestCase) runTestCmd(t *testing.T) { - km := NewFakeKubeManager() - rootCtx.kubeManager = km + km, err := NewTestEnvKubeManager(cmd.testClusterMode) + if err != nil { + t.Fatalf("Error creating kube manager: '%v'", err) + } + + if km != nil { + rootCtx.kubeManager = km + defer km.Stop() + } if cmd.objectFile != "" { clientObjects, err := readYamlObjects(cmd.objectFile) @@ -149,6 +225,27 @@ func (cmd *cmdTestCase) runTestCmd(t *testing.T) { } } +// Run the command and return the captured output. +func executeCommand(cmd string) (string, error) { + args, err := shellwords.Parse(cmd) + if err != nil { + return "", err + } + + buf := new(bytes.Buffer) + + rootCmd.SetOut(buf) + rootCmd.SetErr(buf) + rootCmd.SetArgs(args) + + logger.stderr = rootCmd.ErrOrStderr() + + _, err = rootCmd.ExecuteC() + result := buf.String() + + return result, err +} + func TestVersion(t *testing.T) { cmd := cmdTestCase{ args: "--version", diff --git a/cmd/flux/testdata/install/install_extra_components.golden b/cmd/flux/testdata/install/install_extra_components.golden new file mode 100644 index 00000000..c11f58d3 --- /dev/null +++ b/cmd/flux/testdata/install/install_extra_components.golden @@ -0,0 +1,11 @@ +✚ generating manifests +✔ manifests build completed +► installing components in flux-system namespace +◎ verifying installation +✔ helm-controller: deployment ready +✔ image-automation-controller: deployment ready +✔ image-reflector-controller: deployment ready +✔ kustomize-controller: deployment ready +✔ notification-controller: deployment ready +✔ source-controller: deployment ready +✔ install finished diff --git a/cmd/flux/testdata/install/install_no_args.golden b/cmd/flux/testdata/install/install_no_args.golden new file mode 100644 index 00000000..8958465f --- /dev/null +++ b/cmd/flux/testdata/install/install_no_args.golden @@ -0,0 +1,9 @@ +✚ generating manifests +✔ manifests build completed +► installing components in flux-system namespace +◎ verifying installation +✔ helm-controller: deployment ready +✔ kustomize-controller: deployment ready +✔ notification-controller: deployment ready +✔ source-controller: deployment ready +✔ install finished diff --git a/cmd/flux/testdata/uninstall/uninstall.golden b/cmd/flux/testdata/uninstall/uninstall.golden new file mode 100644 index 00000000..e75944ed --- /dev/null +++ b/cmd/flux/testdata/uninstall/uninstall.golden @@ -0,0 +1,31 @@ +► deleting components in flux-system namespace +✔ Deployment/flux-system/helm-controller deleted +✔ Deployment/flux-system/kustomize-controller deleted +✔ Deployment/flux-system/notification-controller deleted +✔ Deployment/flux-system/source-controller deleted +✔ Service/flux-system/notification-controller deleted +✔ Service/flux-system/source-controller deleted +✔ Service/flux-system/webhook-receiver deleted +✔ NetworkPolicy/flux-system/allow-egress deleted +✔ NetworkPolicy/flux-system/allow-scraping deleted +✔ NetworkPolicy/flux-system/allow-webhooks deleted +✔ ServiceAccount/flux-system/helm-controller deleted +✔ ServiceAccount/flux-system/kustomize-controller deleted +✔ ServiceAccount/flux-system/notification-controller deleted +✔ ServiceAccount/flux-system/source-controller deleted +✔ ClusterRole/crd-controller-flux-system deleted +✔ ClusterRoleBinding/cluster-reconciler-flux-system deleted +✔ ClusterRoleBinding/crd-controller-flux-system deleted +► deleting toolkit.fluxcd.io finalizers in all namespaces +► deleting toolkit.fluxcd.io custom resource definitions +✔ CustomResourceDefinition/alerts.notification.toolkit.fluxcd.io deleted +✔ CustomResourceDefinition/buckets.source.toolkit.fluxcd.io deleted +✔ CustomResourceDefinition/gitrepositories.source.toolkit.fluxcd.io deleted +✔ CustomResourceDefinition/helmcharts.source.toolkit.fluxcd.io deleted +✔ CustomResourceDefinition/helmreleases.helm.toolkit.fluxcd.io deleted +✔ CustomResourceDefinition/helmrepositories.source.toolkit.fluxcd.io deleted +✔ CustomResourceDefinition/kustomizations.kustomize.toolkit.fluxcd.io deleted +✔ CustomResourceDefinition/providers.notification.toolkit.fluxcd.io deleted +✔ CustomResourceDefinition/receivers.notification.toolkit.fluxcd.io deleted +✔ Namespace/flux-system deleted +✔ uninstall finished diff --git a/cmd/flux/testdata/uninstall/uninstall_extra_components.golden b/cmd/flux/testdata/uninstall/uninstall_extra_components.golden new file mode 100644 index 00000000..f81c6cf8 --- /dev/null +++ b/cmd/flux/testdata/uninstall/uninstall_extra_components.golden @@ -0,0 +1,38 @@ +► deleting components in flux-system namespace +✔ Deployment/flux-system/helm-controller deleted +✔ Deployment/flux-system/image-automation-controller deleted +✔ Deployment/flux-system/image-reflector-controller deleted +✔ Deployment/flux-system/kustomize-controller deleted +✔ Deployment/flux-system/notification-controller deleted +✔ Deployment/flux-system/source-controller deleted +✔ Service/flux-system/notification-controller deleted +✔ Service/flux-system/source-controller deleted +✔ Service/flux-system/webhook-receiver deleted +✔ NetworkPolicy/flux-system/allow-egress deleted +✔ NetworkPolicy/flux-system/allow-scraping deleted +✔ NetworkPolicy/flux-system/allow-webhooks deleted +✔ ServiceAccount/flux-system/helm-controller deleted +✔ ServiceAccount/flux-system/image-automation-controller deleted +✔ ServiceAccount/flux-system/image-reflector-controller deleted +✔ ServiceAccount/flux-system/kustomize-controller deleted +✔ ServiceAccount/flux-system/notification-controller deleted +✔ ServiceAccount/flux-system/source-controller deleted +✔ ClusterRole/crd-controller-flux-system deleted +✔ ClusterRoleBinding/cluster-reconciler-flux-system deleted +✔ ClusterRoleBinding/crd-controller-flux-system deleted +► deleting toolkit.fluxcd.io finalizers in all namespaces +► deleting toolkit.fluxcd.io custom resource definitions +✔ CustomResourceDefinition/alerts.notification.toolkit.fluxcd.io deleted +✔ CustomResourceDefinition/buckets.source.toolkit.fluxcd.io deleted +✔ CustomResourceDefinition/gitrepositories.source.toolkit.fluxcd.io deleted +✔ CustomResourceDefinition/helmcharts.source.toolkit.fluxcd.io deleted +✔ CustomResourceDefinition/helmreleases.helm.toolkit.fluxcd.io deleted +✔ CustomResourceDefinition/helmrepositories.source.toolkit.fluxcd.io deleted +✔ CustomResourceDefinition/imagepolicies.image.toolkit.fluxcd.io deleted +✔ CustomResourceDefinition/imagerepositories.image.toolkit.fluxcd.io deleted +✔ CustomResourceDefinition/imageupdateautomations.image.toolkit.fluxcd.io deleted +✔ CustomResourceDefinition/kustomizations.kustomize.toolkit.fluxcd.io deleted +✔ CustomResourceDefinition/providers.notification.toolkit.fluxcd.io deleted +✔ CustomResourceDefinition/receivers.notification.toolkit.fluxcd.io deleted +✔ Namespace/flux-system deleted +✔ uninstall finished diff --git a/cmd/flux/trace_test.go b/cmd/flux/trace_test.go index d66a51aa..83847d23 100644 --- a/cmd/flux/trace_test.go +++ b/cmd/flux/trace_test.go @@ -1,3 +1,5 @@ +// +build !e2e + package main import ( @@ -6,39 +8,43 @@ import ( func TestTraceNoArgs(t *testing.T) { cmd := cmdTestCase{ - args: "trace", - wantError: true, - goldenValue: "object name is required", + args: "trace", + testClusterMode: FakeClusterMode, + wantError: true, + goldenValue: "object name is required", } cmd.runTestCmd(t) } func TestTraceDeployment(t *testing.T) { cmd := cmdTestCase{ - args: "trace podinfo -n podinfo --kind deployment --api-version=apps/v1", - wantError: false, - goldenFile: "testdata/trace/deployment.txt", - objectFile: "testdata/trace/deployment.yaml", + args: "trace podinfo -n podinfo --kind deployment --api-version=apps/v1", + testClusterMode: FakeClusterMode, + wantError: false, + goldenFile: "testdata/trace/deployment.txt", + objectFile: "testdata/trace/deployment.yaml", } cmd.runTestCmd(t) } func TestTraceHelmRelease(t *testing.T) { cmd := cmdTestCase{ - args: "trace podinfo -n podinfo --kind HelmRelease --api-version=helm.toolkit.fluxcd.io/v2beta1", - wantError: false, - goldenFile: "testdata/trace/helmrelease.txt", - objectFile: "testdata/trace/helmrelease.yaml", + args: "trace podinfo -n podinfo --kind HelmRelease --api-version=helm.toolkit.fluxcd.io/v2beta1", + testClusterMode: FakeClusterMode, + wantError: false, + goldenFile: "testdata/trace/helmrelease.txt", + objectFile: "testdata/trace/helmrelease.yaml", } cmd.runTestCmd(t) } func TestTraceHelmReleaseMissingGitRef(t *testing.T) { cmd := cmdTestCase{ - args: "trace podinfo -n podinfo --kind HelmRelease --api-version=helm.toolkit.fluxcd.io/v2beta1", - wantError: false, - goldenFile: "testdata/trace/helmrelease-missing-git-ref.txt", - objectFile: "testdata/trace/helmrelease-missing-git-ref.yaml", + args: "trace podinfo -n podinfo --kind HelmRelease --api-version=helm.toolkit.fluxcd.io/v2beta1", + testClusterMode: FakeClusterMode, + wantError: false, + goldenFile: "testdata/trace/helmrelease-missing-git-ref.txt", + objectFile: "testdata/trace/helmrelease-missing-git-ref.yaml", } cmd.runTestCmd(t) } diff --git a/go.sum b/go.sum index 994c9974..b6cf5b58 100644 --- a/go.sum +++ b/go.sum @@ -115,6 +115,7 @@ github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZw github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= @@ -123,7 +124,9 @@ github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnweb github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw= github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE= @@ -543,6 +546,7 @@ github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m github.com/mattn/go-shellwords v1.0.12 h1:M2zGm7EW6UQJvDeQxo4T51eKPurbeFbe8WtebGE2xrk= github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= @@ -650,12 +654,14 @@ github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5Fsn github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.10.0/go.mod h1:WJM3cc3yu7XKBKa/I8WeZm+V3eltZnBwfENSU7mdogU= +github.com/prometheus/client_golang v1.11.0 h1:HNkLOAEQMIDv/K+04rukrLx6ch7msSRwf3/SASFAGtQ= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= @@ -664,6 +670,7 @@ github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8 github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.18.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= +github.com/prometheus/common v0.26.0 h1:iMAkS2TDoNWnKM+Kopnx/8tnEStIfpYA0ur0xQzzhMQ= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= @@ -672,6 +679,7 @@ github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsT github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= @@ -1051,6 +1059,7 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gomodules.xyz/jsonpatch/v2 v2.2.0 h1:4pT439QV83L+G9FkcCriY6EkpcK6r6bK+A5FBUMI7qY= gomodules.xyz/jsonpatch/v2 v2.2.0/go.mod h1:WXp+iVDkoLQqPudfQ9GBlwB2eZ5DKOnjQZCYdOS8GPY= gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0= gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= @@ -1204,6 +1213,7 @@ k8s.io/code-generator v0.21.1/go.mod h1:hUlps5+9QaTrKx+jiM4rmq7YmH8wPOIko64uZCHD k8s.io/code-generator v0.21.3/go.mod h1:K3y0Bv9Cz2cOW2vXUrNZlFbflhuPvuadW6JdnN6gGKo= k8s.io/component-base v0.18.8/go.mod h1:00frPRDas29rx58pPCxNkhUfPbwajlyyvu8ruNgSErU= k8s.io/component-base v0.21.1/go.mod h1:NgzFZ2qu4m1juby4TnrmpR8adRk6ka62YdH5DkIIyKA= +k8s.io/component-base v0.21.3 h1:4WuuXY3Npa+iFfi2aDRiOz+anhNvRfye0859ZgfC5Og= k8s.io/component-base v0.21.3/go.mod h1:kkuhtfEHeZM6LkX0saqSK8PbdO7A0HigUngmhhrwfGQ= k8s.io/component-helpers v0.21.1/go.mod h1:FtC1flbiQlosHQrLrRUulnKxE4ajgWCGy/67fT2GRlQ= k8s.io/csi-translation-lib v0.18.8/go.mod h1:6cA6Btlzxy9s3QrS4BCZzQqclIWnTLr6Jx3H2ctAzY4= diff --git a/internal/flags/crds_test.go b/internal/flags/crds_test.go index be53a461..9d20b095 100644 --- a/internal/flags/crds_test.go +++ b/internal/flags/crds_test.go @@ -1,3 +1,5 @@ +// +build !e2e + /* Copyright 2021 The Flux authors diff --git a/internal/flags/decryption_provider_test.go b/internal/flags/decryption_provider_test.go index cc1b2f07..86a0deba 100644 --- a/internal/flags/decryption_provider_test.go +++ b/internal/flags/decryption_provider_test.go @@ -1,3 +1,5 @@ +// +build !e2e + /* Copyright 2020 The Flux authors diff --git a/internal/flags/ecdsa_curve_test.go b/internal/flags/ecdsa_curve_test.go index d1b1f05e..e58c8b8b 100644 --- a/internal/flags/ecdsa_curve_test.go +++ b/internal/flags/ecdsa_curve_test.go @@ -1,3 +1,5 @@ +// +build !e2e + /* Copyright 2020 The Flux authors diff --git a/internal/flags/git_implementation_test.go b/internal/flags/git_implementation_test.go index 6372d4bf..e555dd27 100644 --- a/internal/flags/git_implementation_test.go +++ b/internal/flags/git_implementation_test.go @@ -1,3 +1,5 @@ +// +build !e2e + /* Copyright 2021 The Flux authors diff --git a/internal/flags/helm_chart_source_test.go b/internal/flags/helm_chart_source_test.go index b484c983..62b34ea6 100644 --- a/internal/flags/helm_chart_source_test.go +++ b/internal/flags/helm_chart_source_test.go @@ -1,3 +1,5 @@ +// +build !e2e + /* Copyright 2020 The Flux authors diff --git a/internal/flags/helm_release_values_test.go b/internal/flags/helm_release_values_test.go index f6fc28e4..8e392049 100644 --- a/internal/flags/helm_release_values_test.go +++ b/internal/flags/helm_release_values_test.go @@ -1,3 +1,5 @@ +// +build !e2e + /* Copyright 2020 The Flux authors diff --git a/internal/flags/kustomization_source_test.go b/internal/flags/kustomization_source_test.go index b2950218..db5062d9 100644 --- a/internal/flags/kustomization_source_test.go +++ b/internal/flags/kustomization_source_test.go @@ -1,3 +1,5 @@ +// +build !e2e + /* Copyright 2020 The Flux authors diff --git a/internal/flags/log_level_test.go b/internal/flags/log_level_test.go index bccf1ac1..a8ef1cae 100644 --- a/internal/flags/log_level_test.go +++ b/internal/flags/log_level_test.go @@ -1,3 +1,5 @@ +// +build !e2e + /* Copyright 2020 The Flux authors diff --git a/internal/flags/public_key_algorithm_test.go b/internal/flags/public_key_algorithm_test.go index 84e19c22..e2b69230 100644 --- a/internal/flags/public_key_algorithm_test.go +++ b/internal/flags/public_key_algorithm_test.go @@ -1,3 +1,5 @@ +// +build !e2e + /* Copyright 2020 The Flux authors diff --git a/internal/flags/rsa_key_bits_test.go b/internal/flags/rsa_key_bits_test.go index f9805270..e0b15e7c 100644 --- a/internal/flags/rsa_key_bits_test.go +++ b/internal/flags/rsa_key_bits_test.go @@ -1,3 +1,5 @@ +// +build !e2e + /* Copyright 2020 The Flux authors diff --git a/internal/flags/safe_relative_path_test.go b/internal/flags/safe_relative_path_test.go index 872085ad..8651436f 100644 --- a/internal/flags/safe_relative_path_test.go +++ b/internal/flags/safe_relative_path_test.go @@ -1,3 +1,5 @@ +// +build !e2e + /* Copyright 2020 The Flux authors diff --git a/internal/flags/source_bucket_provider_test.go b/internal/flags/source_bucket_provider_test.go index 05b4f7ce..5ec82e35 100644 --- a/internal/flags/source_bucket_provider_test.go +++ b/internal/flags/source_bucket_provider_test.go @@ -1,3 +1,5 @@ +// +build !e2e + /* Copyright 2020 The Flux authors diff --git a/internal/utils/utils_test.go b/internal/utils/utils_test.go index 59ec97ae..2e5d6542 100644 --- a/internal/utils/utils_test.go +++ b/internal/utils/utils_test.go @@ -1,3 +1,5 @@ +// +build !e2e + /* Copyright 2021 The Flux authors diff --git a/pkg/manifestgen/sourcesecret/sourcesecret_test.go b/pkg/manifestgen/sourcesecret/sourcesecret_test.go index 24ab8057..b7e4e2c1 100644 --- a/pkg/manifestgen/sourcesecret/sourcesecret_test.go +++ b/pkg/manifestgen/sourcesecret/sourcesecret_test.go @@ -1,3 +1,5 @@ +// +build !e2e + /* Copyright 2021 The Flux authors diff --git a/pkg/manifestgen/sync/sync_test.go b/pkg/manifestgen/sync/sync_test.go index a39d09d9..732442af 100644 --- a/pkg/manifestgen/sync/sync_test.go +++ b/pkg/manifestgen/sync/sync_test.go @@ -1,3 +1,5 @@ +// +build !e2e + /* Copyright 2020 The Flux CD contributors. diff --git a/pkg/status/status.go b/pkg/status/status.go index 1a5abc37..b2894052 100644 --- a/pkg/status/status.go +++ b/pkg/status/status.go @@ -19,6 +19,7 @@ package status import ( "context" "fmt" + "sort" "strings" "time" @@ -74,7 +75,13 @@ func (sc *StatusChecker) Assess(identifiers ...object.ObjMetadata) error { <-done - for _, rs := range coll.ResourceStatuses { + // we use sorted identifiers to loop over the resource statuses because a Go's map is unordered. + // sorting identifiers by object's name makes sure that the logs look stable for every run + sort.SliceStable(identifiers, func(i, j int) bool { + return strings.Compare(identifiers[i].Name, identifiers[j].Name) < 0 + }) + for _, id := range identifiers { + rs := coll.ResourceStatuses[id] switch rs.Status { case status.CurrentStatus: sc.logger.Successf("%s: %s ready", rs.Identifier.Name, strings.ToLower(rs.Identifier.GroupKind.Kind))