From 1d6732a44c119455c23d8647ac4497059cba714c Mon Sep 17 00:00:00 2001 From: Saswata Mukherjee Date: Tue, 17 Oct 2023 19:16:33 +0530 Subject: [PATCH] *: Refactor codebase with linters/formatters and upstream patterns (#1253) * Add formatters/linters and init bingo Signed-off-by: Saswata Mukherjee * Run formatter + bump some prom libs Signed-off-by: Saswata Mukherjee * Deprecate ioutil Signed-off-by: Saswata Mukherjee * Follow promauto registry pattern in collector + remove unused code Signed-off-by: Saswata Mukherjee * Make all errors consistent, replace errors, github.com/pkg/errors with github.com/efficientgo/core/errors Signed-off-by: Saswata Mukherjee * Try to address initial lint errors Signed-off-by: Saswata Mukherjee * Address even more lint issues Signed-off-by: Saswata Mukherjee * Remove deprecated logger Signed-off-by: Saswata Mukherjee * Remove deprecated fake.NewFakeClient Signed-off-by: Saswata Mukherjee * Use exp/slices to fix test Signed-off-by: Saswata Mukherjee * Make lint fully green Signed-off-by: Saswata Mukherjee * Add copyright script and enable go vet Signed-off-by: Saswata Mukherjee * Add lint as a workflow to CI Signed-off-by: Saswata Mukherjee * Fix Makefile and forwarder metrics/tests Signed-off-by: Saswata Mukherjee * Fix build_info collector metric Signed-off-by: Saswata Mukherjee * Revert move to github.com/efficientgo/core/errors for stdlib Signed-off-by: Saswata Mukherjee * Address comments Signed-off-by: Saswata Mukherjee --------- Signed-off-by: Saswata Mukherjee --- .bingo/.gitignore | 13 + .bingo/README.md | 14 + .bingo/Variables.mk | 49 + .bingo/faillint.mod | 5 + .bingo/faillint.sum | 30 + .bingo/go.mod | 1 + .bingo/goimports.mod | 5 + .bingo/goimports.sum | 6 + .bingo/golangci-lint.mod | 5 + .bingo/golangci-lint.sum | 953 ++++++++++++++++++ .bingo/misspell.mod | 5 + .bingo/misspell.sum | 2 + .bingo/shfmt.mod | 5 + .bingo/shfmt.sum | 12 + .bingo/variables.env | 20 + .errcheck_excludes.txt | 3 + .github/workflows/lint.yaml | 36 + .golangci.yml | 67 ++ Makefile | 93 +- README.md | 2 +- cicd-scripts/build.sh | 4 +- cicd-scripts/copyright-check.sh | 45 +- cicd-scripts/customize-mco.sh | 309 +++--- cicd-scripts/deploy-to-cluster.sh | 2 +- cicd-scripts/install-dependencies.sh | 14 +- cicd-scripts/run-e2e-in-kind-via-prow.sh | 26 +- cicd-scripts/run-e2e-tests.sh | 123 +-- cicd-scripts/run-unit-tests.sh | 2 +- cicd-scripts/setup-e2e-tests.sh | 356 +++---- cicd-scripts/update-check-mco-csv.sh | 22 +- .../metrics/cmd/metrics-collector/main.go | 51 +- .../cmd/metrics-collector/main_test.go | 8 +- .../metrics/pkg/collectrule/evaluator.go | 15 +- collectors/metrics/pkg/forwarder/forwarder.go | 127 ++- .../metrics/pkg/forwarder/forwarder_test.go | 20 +- collectors/metrics/pkg/http/client.go | 101 -- collectors/metrics/pkg/http/roundtripper.go | 5 +- collectors/metrics/pkg/http/routes.go | 5 +- collectors/metrics/pkg/logger/logger.go | 8 +- .../metricfamily/hypershift_transformer.go | 9 +- .../hypershift_transformer_test.go | 2 +- .../metrics/pkg/metricfamily/invalid.go | 7 +- collectors/metrics/pkg/metricfamily/label.go | 12 +- .../metrics/pkg/metricfamily/overwrite.go | 51 - .../metrics/pkg/metricfamily/required.go | 3 +- collectors/metrics/pkg/metricfamily/sort.go | 2 +- .../metrics/pkg/metricfamily/unsorted.go | 8 +- .../pkg/metricsclient/metricsclient.go | 105 +- .../pkg/metricsclient/metricsclient_test.go | 2 +- collectors/metrics/pkg/reader/reader.go | 4 +- collectors/metrics/pkg/simulator/simulator.go | 5 +- collectors/metrics/pkg/status/status.go | 17 +- collectors/metrics/pkg/status/status_test.go | 18 +- collectors/metrics/test/integration/clean.sh | 24 +- collectors/metrics/test/integration/prereq.sh | 79 +- collectors/metrics/test/integration/setup.sh | 293 +++--- docs/scale-perf.md | 2 +- examples/ceph/operator.yaml | 2 +- examples/gen.go | 7 +- go.mod | 8 +- go.sum | 4 +- .../pkg/controller/dashboard_controller.go | 23 +- .../controller/dashboard_controller_test.go | 6 +- loaders/dashboards/pkg/util/grafana_util.go | 7 +- .../dashboards/pkg/util/grafana_util_test.go | 3 +- .../observabilityendpoint/match_evaluator.go | 7 +- .../metrics_collector.go | 4 +- .../observabilityaddon_controller.go | 18 +- .../observabilityaddon_controller_test.go | 9 +- .../ocp_monitoring_config.go | 67 +- .../ocp_monitoring_config_test.go | 52 +- .../ocp_resource_test.go | 10 +- .../controllers/status/status_controller.go | 2 +- .../status/status_controller_test.go | 4 +- operators/endpointmetrics/main.go | 8 +- .../endpointmetrics/pkg/rendering/renderer.go | 2 +- .../pkg/rendering/renderer_test.go | 3 +- .../pkg/rendering/templates/templates.go | 2 +- operators/endpointmetrics/pkg/util/client.go | 4 +- .../endpointmetrics/pkg/util/client_test.go | 4 +- operators/endpointmetrics/pkg/util/status.go | 8 +- .../endpointmetrics/pkg/util/status_test.go | 2 +- .../multiclusterobservability_shared.go | 2 +- .../api/v1beta1/groupversion_info.go | 4 +- .../multiclusterobservability_types.go | 8 +- .../api/v1beta2/groupversion_info.go | 4 +- .../multiclusterobservability_types.go | 14 +- .../multiclusterobservability_webhook.go | 8 +- .../multiclusterobservability/grafana.go | 2 +- .../multiclusterobservability_controller.go | 53 +- ...lticlusterobservability_controller_test.go | 55 +- .../multiclusterobservability_status.go | 29 +- .../multiclusterobservability_status_test.go | 2 +- .../observatorium.go | 71 +- .../observatorium_test.go | 15 +- .../storageversionmigration_test.go | 4 +- .../placementrule/customize_img.go | 4 +- .../placementrule/customize_img_test.go | 11 +- .../endpoint_metrics_operator.go | 7 +- .../placementrule/hub_info_secret.go | 2 +- .../controllers/placementrule/manifestwork.go | 22 +- .../placementrule/manifestwork_test.go | 11 +- .../placementrule/mco_predicate.go | 6 +- .../controllers/placementrule/obsaddon.go | 3 +- .../placementrule/placementrule_controller.go | 87 +- .../placementrule_controller_test.go | 5 +- operators/multiclusterobservability/main.go | 22 +- .../pkg/certificates/cert_controller.go | 8 +- .../pkg/certificates/cert_controller_test.go | 12 +- .../pkg/certificates/certificates.go | 7 +- .../pkg/certificates/certificates_test.go | 4 +- .../pkg/certificates/signer.go | 2 +- .../pkg/config/azure_conf.go | 2 +- .../pkg/config/config.go | 81 +- .../pkg/config/config_test.go | 24 +- .../pkg/config/gcs_conf.go | 2 +- .../pkg/config/obj_storage_conf.go | 4 +- .../pkg/config/s3_conf.go | 2 +- .../pkg/rendering/renderer.go | 21 - .../pkg/rendering/templates/templates.go | 18 +- .../pkg/util/clustermanagementaddon.go | 6 +- .../pkg/util/clustermanagementaddon_test.go | 6 +- .../pkg/util/managedclusteraddon.go | 2 + .../pkg/util/managedclusteraddon_test.go | 2 +- .../pkg/util/remotewriteendpoint.go | 6 +- .../pkg/util/remotewriteendpoint_test.go | 15 +- .../pkg/webhook/webhook_controller_test.go | 2 +- .../multiclusterobservability/prestop.sh | 1 - operators/pkg/config/config.go | 2 +- operators/pkg/config/types.go | 2 +- operators/pkg/deploying/deployer.go | 6 +- operators/pkg/deploying/deployer_test.go | 3 +- operators/pkg/rendering/renderer.go | 14 +- operators/pkg/util/allowlist_test.go | 9 +- operators/pkg/util/client.go | 12 +- operators/pkg/util/client_test.go | 4 +- operators/pkg/util/obj_compare.go | 2 +- operators/pkg/util/util.go | 10 - operators/pkg/util/util_test.go | 29 +- proxy/pkg/config/config.go | 16 +- proxy/pkg/config/types.go | 2 +- proxy/pkg/proxy/proxy.go | 16 +- proxy/pkg/proxy/proxy_test.go | 47 +- proxy/pkg/proxy/tls.go | 4 +- proxy/pkg/rewrite/rewrite.go | 2 +- proxy/pkg/util/user_project_test.go | 8 +- proxy/pkg/util/util.go | 64 +- proxy/pkg/util/util_test.go | 34 +- scripts/copyright/copyright.go | 76 ++ tests/benchmark/clean-metrics-collector.sh | 26 +- tests/benchmark/setup-metrics-collector.sh | 83 +- tests/format-results.sh | 4 +- tests/grafana-dev-test.sh | 74 +- tests/pkg/kustomize/render.go | 6 +- .../observability-e2e-test_suite_test.go | 3 +- tests/pkg/tests/observability_addon_test.go | 8 +- tests/pkg/tests/observability_alert_test.go | 12 +- tests/pkg/tests/observability_config_test.go | 6 +- .../observability_endpoint_preserve_test.go | 4 +- tests/pkg/tests/observability_export_test.go | 7 +- tests/pkg/tests/observability_install_test.go | 11 +- tests/pkg/tests/observability_route_test.go | 22 +- .../pkg/tests/observability_uninstall_test.go | 8 +- tests/pkg/utils/cluster_deploy.go | 12 +- tests/pkg/utils/install_config.go | 12 +- tests/pkg/utils/mco_dashboard.go | 9 +- tests/pkg/utils/mco_deploy.go | 24 +- tests/pkg/utils/mco_managedcluster.go | 4 +- tests/pkg/utils/mco_metric.go | 11 +- tests/pkg/utils/utils.go | 34 +- tests/run-in-kind/run-e2e-in-kind.sh | 79 +- tools/generate-dashboard-configmap-yaml.sh | 92 +- tools/setup-grafana-dev.sh | 113 +-- .../alert-forward/clean-alert-forwarder.sh | 14 +- tools/simulator/alert-forward/main.go | 23 +- .../alert-forward/setup-alert-forwarder.sh | 24 +- .../managed-cluster/clean-managedcluster.sh | 21 +- .../managed-cluster/setup-managedcluster.sh | 34 +- .../clean-metrics-collector.sh | 88 +- .../generate-metrics-data.sh | 168 +-- .../metrics-extractor/extract-metrics-data.sh | 79 +- .../setup-metrics-collector.sh | 233 ++--- tools/switch-to-grafana-admin.sh | 94 +- 183 files changed, 3500 insertions(+), 2460 deletions(-) create mode 100644 .bingo/.gitignore create mode 100644 .bingo/README.md create mode 100644 .bingo/Variables.mk create mode 100644 .bingo/faillint.mod create mode 100644 .bingo/faillint.sum create mode 100644 .bingo/go.mod create mode 100644 .bingo/goimports.mod create mode 100644 .bingo/goimports.sum create mode 100644 .bingo/golangci-lint.mod create mode 100644 .bingo/golangci-lint.sum create mode 100644 .bingo/misspell.mod create mode 100644 .bingo/misspell.sum create mode 100644 .bingo/shfmt.mod create mode 100644 .bingo/shfmt.sum create mode 100644 .bingo/variables.env create mode 100644 .errcheck_excludes.txt create mode 100644 .github/workflows/lint.yaml create mode 100644 .golangci.yml delete mode 100644 collectors/metrics/pkg/http/client.go delete mode 100644 collectors/metrics/pkg/metricfamily/overwrite.go create mode 100644 scripts/copyright/copyright.go diff --git a/.bingo/.gitignore b/.bingo/.gitignore new file mode 100644 index 000000000..9efccf683 --- /dev/null +++ b/.bingo/.gitignore @@ -0,0 +1,13 @@ + +# Ignore everything +* + +# But not these files: +!.gitignore +!*.mod +!*.sum +!README.md +!Variables.mk +!variables.env + +*tmp.mod diff --git a/.bingo/README.md b/.bingo/README.md new file mode 100644 index 000000000..7a5c2d4f6 --- /dev/null +++ b/.bingo/README.md @@ -0,0 +1,14 @@ +# Project Development Dependencies. + +This is directory which stores Go modules with pinned buildable package that is used within this repository, managed by https://github.com/bwplotka/bingo. + +* Run `bingo get` to install all tools having each own module file in this directory. +* Run `bingo get ` to install that have own module file in this directory. +* For Makefile: Make sure to put `include .bingo/Variables.mk` in your Makefile, then use $() variable where is the .bingo/.mod. +* For shell: Run `source .bingo/variables.env` to source all environment variable for each tool. +* For go: Import `.bingo/variables.go` to for variable names. +* See https://github.com/bwplotka/bingo or -h on how to add, remove or change binaries dependencies. + +## Requirements + +* Go 1.14+ diff --git a/.bingo/Variables.mk b/.bingo/Variables.mk new file mode 100644 index 000000000..76b8cd2aa --- /dev/null +++ b/.bingo/Variables.mk @@ -0,0 +1,49 @@ +# Auto generated binary variables helper managed by https://github.com/bwplotka/bingo v0.8. DO NOT EDIT. +# All tools are designed to be build inside $GOBIN. +BINGO_DIR := $(dir $(lastword $(MAKEFILE_LIST))) +GOPATH ?= $(shell go env GOPATH) +GOBIN ?= $(firstword $(subst :, ,${GOPATH}))/bin +GO ?= $(shell which go) + +# Below generated variables ensure that every time a tool under each variable is invoked, the correct version +# will be used; reinstalling only if needed. +# For example for faillint variable: +# +# In your main Makefile (for non array binaries): +# +#include .bingo/Variables.mk # Assuming -dir was set to .bingo . +# +#command: $(FAILLINT) +# @echo "Running faillint" +# @$(FAILLINT) +# +FAILLINT := $(GOBIN)/faillint-v1.11.0 +$(FAILLINT): $(BINGO_DIR)/faillint.mod + @# Install binary/ries using Go 1.14+ build command. This is using bwplotka/bingo-controlled, separate go module with pinned dependencies. + @echo "(re)installing $(GOBIN)/faillint-v1.11.0" + @cd $(BINGO_DIR) && GOWORK=off $(GO) build -mod=mod -modfile=faillint.mod -o=$(GOBIN)/faillint-v1.11.0 "github.com/fatih/faillint" + +GOIMPORTS := $(GOBIN)/goimports-v0.14.0 +$(GOIMPORTS): $(BINGO_DIR)/goimports.mod + @# Install binary/ries using Go 1.14+ build command. This is using bwplotka/bingo-controlled, separate go module with pinned dependencies. + @echo "(re)installing $(GOBIN)/goimports-v0.14.0" + @cd $(BINGO_DIR) && GOWORK=off $(GO) build -mod=mod -modfile=goimports.mod -o=$(GOBIN)/goimports-v0.14.0 "golang.org/x/tools/cmd/goimports" + +GOLANGCI_LINT := $(GOBIN)/golangci-lint-v1.54.2 +$(GOLANGCI_LINT): $(BINGO_DIR)/golangci-lint.mod + @# Install binary/ries using Go 1.14+ build command. This is using bwplotka/bingo-controlled, separate go module with pinned dependencies. + @echo "(re)installing $(GOBIN)/golangci-lint-v1.54.2" + @cd $(BINGO_DIR) && GOWORK=off $(GO) build -mod=mod -modfile=golangci-lint.mod -o=$(GOBIN)/golangci-lint-v1.54.2 "github.com/golangci/golangci-lint/cmd/golangci-lint" + +MISSPELL := $(GOBIN)/misspell-v0.3.4 +$(MISSPELL): $(BINGO_DIR)/misspell.mod + @# Install binary/ries using Go 1.14+ build command. This is using bwplotka/bingo-controlled, separate go module with pinned dependencies. + @echo "(re)installing $(GOBIN)/misspell-v0.3.4" + @cd $(BINGO_DIR) && GOWORK=off $(GO) build -mod=mod -modfile=misspell.mod -o=$(GOBIN)/misspell-v0.3.4 "github.com/client9/misspell/cmd/misspell" + +SHFMT := $(GOBIN)/shfmt-v3.7.0 +$(SHFMT): $(BINGO_DIR)/shfmt.mod + @# Install binary/ries using Go 1.14+ build command. This is using bwplotka/bingo-controlled, separate go module with pinned dependencies. + @echo "(re)installing $(GOBIN)/shfmt-v3.7.0" + @cd $(BINGO_DIR) && GOWORK=off $(GO) build -mod=mod -modfile=shfmt.mod -o=$(GOBIN)/shfmt-v3.7.0 "mvdan.cc/sh/v3/cmd/shfmt" + diff --git a/.bingo/faillint.mod b/.bingo/faillint.mod new file mode 100644 index 000000000..f1d4dd37d --- /dev/null +++ b/.bingo/faillint.mod @@ -0,0 +1,5 @@ +module _ // Auto generated by https://github.com/bwplotka/bingo. DO NOT EDIT + +go 1.21.0 + +require github.com/fatih/faillint v1.11.0 diff --git a/.bingo/faillint.sum b/.bingo/faillint.sum new file mode 100644 index 000000000..763a40558 --- /dev/null +++ b/.bingo/faillint.sum @@ -0,0 +1,30 @@ +dmitri.shuralyov.com/go/generated v0.0.0-20170818220700-b1254a446363 h1:o4lAkfETerCnr1kF9/qwkwjICnU+YLHNDCM8h2xj7as= +dmitri.shuralyov.com/go/generated v0.0.0-20170818220700-b1254a446363/go.mod h1:WG7q7swWsS2f9PYpt5DoEP/EBYWx8We5UoRltn9vJl8= +github.com/fatih/faillint v1.11.0 h1:EhmAKe8k0Cx2gnf+/JiX/IAeeKjwsQao5dY8oG6cQB4= +github.com/fatih/faillint v1.11.0/go.mod h1:d9kdQwFcr+wD4cLXOdjTw1ENUUvv5+z0ctJ5Wm0dTvA= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/.bingo/go.mod b/.bingo/go.mod new file mode 100644 index 000000000..610249af0 --- /dev/null +++ b/.bingo/go.mod @@ -0,0 +1 @@ +module _ // Fake go.mod auto-created by 'bingo' for go -moddir compatibility with non-Go projects. Commit this file, together with other .mod files. \ No newline at end of file diff --git a/.bingo/goimports.mod b/.bingo/goimports.mod new file mode 100644 index 000000000..b29540e5a --- /dev/null +++ b/.bingo/goimports.mod @@ -0,0 +1,5 @@ +module _ // Auto generated by https://github.com/bwplotka/bingo. DO NOT EDIT + +go 1.21.0 + +require golang.org/x/tools v0.14.0 // cmd/goimports diff --git a/.bingo/goimports.sum b/.bingo/goimports.sum new file mode 100644 index 000000000..b8511a3dd --- /dev/null +++ b/.bingo/goimports.sum @@ -0,0 +1,6 @@ +golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= +golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc= +golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= diff --git a/.bingo/golangci-lint.mod b/.bingo/golangci-lint.mod new file mode 100644 index 000000000..d043fc82f --- /dev/null +++ b/.bingo/golangci-lint.mod @@ -0,0 +1,5 @@ +module _ // Auto generated by https://github.com/bwplotka/bingo. DO NOT EDIT + +go 1.21.0 + +require github.com/golangci/golangci-lint v1.54.2 // cmd/golangci-lint diff --git a/.bingo/golangci-lint.sum b/.bingo/golangci-lint.sum new file mode 100644 index 000000000..ecbc7817f --- /dev/null +++ b/.bingo/golangci-lint.sum @@ -0,0 +1,953 @@ +4d63.com/gocheckcompilerdirectives v1.2.1 h1:AHcMYuw56NPjq/2y615IGg2kYkBdTvOaojYCBcRE7MA= +4d63.com/gocheckcompilerdirectives v1.2.1/go.mod h1:yjDJSxmDTtIHHCqX0ufRYZDL6vQtMG7tJdKVeWwsqvs= +4d63.com/gochecknoglobals v0.2.1 h1:1eiorGsgHOFOuoOiJDy2psSrQbRdIHrlge0IJIkUgDc= +4d63.com/gochecknoglobals v0.2.1/go.mod h1:KRE8wtJB3CXCsb1xy421JfTHIIbmT3U5ruxw2Qu8fSU= +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/4meepo/tagalign v1.3.2 h1:1idD3yxlRGV18VjqtDbqYvQ5pXqQS0wO2dn6M3XstvI= +github.com/4meepo/tagalign v1.3.2/go.mod h1:Q9c1rYMZJc9dPRkbQPpcBNCLEmY2njbAsXhQOZFE2dE= +github.com/Abirdcfly/dupword v0.0.12 h1:56NnOyrXzChj07BDFjeRA+IUzSz01jmzEq+G4kEgFhc= +github.com/Abirdcfly/dupword v0.0.12/go.mod h1:+us/TGct/nI9Ndcbcp3rgNcQzctTj68pq7TcgNpLfdI= +github.com/Antonboom/errname v0.1.12 h1:oh9ak2zUtsLp5oaEd/erjB4GPu9w19NyoIskZClDcQY= +github.com/Antonboom/errname v0.1.12/go.mod h1:bK7todrzvlaZoQagP1orKzWXv59X/x0W0Io2XT1Ssro= +github.com/Antonboom/nilnil v0.1.7 h1:ofgL+BA7vlA1K2wNQOsHzLJ2Pw5B5DpWRLdDAVvvTow= +github.com/Antonboom/nilnil v0.1.7/go.mod h1:TP+ScQWVEq0eSIxqU8CbdT5DFWoHp0MbP+KMUO1BKYQ= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= +github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 h1:sHglBQTwgx+rWPdisA5ynNEsoARbiCBOyGcJM4/OzsM= +github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24/go.mod h1:4UJr5HIiMZrwgkSPdsjy2uOQExX/WEILpIrO9UPGuXs= +github.com/GaijinEntertainment/go-exhaustruct/v3 v3.1.0 h1:3ZBs7LAezy8gh0uECsA6CGU43FF3zsx5f4eah5FxTMA= +github.com/GaijinEntertainment/go-exhaustruct/v3 v3.1.0/go.mod h1:rZLTje5A9kFBe0pzhpe2TdhRniBF++PRHQuRpR8esVc= +github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= +github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= +github.com/OpenPeeDeeP/depguard/v2 v2.1.0 h1:aQl70G173h/GZYhWf36aE5H0KaujXfVMnn/f1kSDVYY= +github.com/OpenPeeDeeP/depguard/v2 v2.1.0/go.mod h1:PUBgk35fX4i7JDmwzlJwJ+GMe6NfO1723wmJMgPThNQ= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/alexkohler/nakedret/v2 v2.0.2 h1:qnXuZNvv3/AxkAb22q/sEsEpcA99YxLFACDtEw9TPxE= +github.com/alexkohler/nakedret/v2 v2.0.2/go.mod h1:2b8Gkk0GsOrqQv/gPWjNLDSKwG8I5moSXG1K4VIBcTQ= +github.com/alexkohler/prealloc v1.0.0 h1:Hbq0/3fJPQhNkN0dR95AVrr6R7tou91y0uHG5pOcUuw= +github.com/alexkohler/prealloc v1.0.0/go.mod h1:VetnK3dIgFBBKmg0YnD9F9x6Icjd+9cvfHR56wJVlKE= +github.com/alingse/asasalint v0.0.11 h1:SFwnQXJ49Kx/1GghOFz1XGqHYKp21Kq1nHad/0WQRnw= +github.com/alingse/asasalint v0.0.11/go.mod h1:nCaoMhw7a9kSJObvQyVzNTPBDbNpdocqrSP7t/cW5+I= +github.com/ashanbrown/forbidigo v1.6.0 h1:D3aewfM37Yb3pxHujIPSpTf6oQk9sc9WZi8gerOIVIY= +github.com/ashanbrown/forbidigo v1.6.0/go.mod h1:Y8j9jy9ZYAEHXdu723cUlraTqbzjKF1MUyfOKL+AjcU= +github.com/ashanbrown/makezero v1.1.1 h1:iCQ87C0V0vSyO+M9E/FZYbu65auqH0lnsOkf5FcB28s= +github.com/ashanbrown/makezero v1.1.1/go.mod h1:i1bJLCRSCHOcOa9Y6MyF2FTfMZMFdHvxKHxgO5Z1axI= +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/bkielbasa/cyclop v1.2.1 h1:AeF71HZDob1P2/pRm1so9cd1alZnrpyc4q2uP2l0gJY= +github.com/bkielbasa/cyclop v1.2.1/go.mod h1:K/dT/M0FPAiYjBgQGau7tz+3TMh4FWAEqlMhzFWCrgM= +github.com/blizzy78/varnamelen v0.8.0 h1:oqSblyuQvFsW1hbBHh1zfwrKe3kcSj0rnXkKzsQ089M= +github.com/blizzy78/varnamelen v0.8.0/go.mod h1:V9TzQZ4fLJ1DSrjVDfl89H7aMnTvKkApdHeyESmyR7k= +github.com/bombsimon/wsl/v3 v3.4.0 h1:RkSxjT3tmlptwfgEgTgU+KYKLI35p/tviNXNXiL2aNU= +github.com/bombsimon/wsl/v3 v3.4.0/go.mod h1:KkIB+TXkqy6MvK9BDZVbZxKNYsE1/oLRJbIFtf14qqo= +github.com/breml/bidichk v0.2.4 h1:i3yedFWWQ7YzjdZJHnPo9d/xURinSq3OM+gyM43K4/8= +github.com/breml/bidichk v0.2.4/go.mod h1:7Zk0kRFt1LIZxtQdl9W9JwGAcLTTkOs+tN7wuEYGJ3s= +github.com/breml/errchkjson v0.3.1 h1:hlIeXuspTyt8Y/UmP5qy1JocGNR00KQHgfaNtRAjoxQ= +github.com/breml/errchkjson v0.3.1/go.mod h1:XroxrzKjdiutFyW3nWhw34VGg7kiMsDQox73yWCGI2U= +github.com/butuzov/ireturn v0.2.0 h1:kCHi+YzC150GE98WFuZQu9yrTn6GEydO2AuPLbTgnO4= +github.com/butuzov/ireturn v0.2.0/go.mod h1:Wh6Zl3IMtTpaIKbmwzqi6olnM9ptYQxxVacMsOEFPoc= +github.com/butuzov/mirror v1.1.0 h1:ZqX54gBVMXu78QLoiqdwpl2mgmoOJTk7s4p4o+0avZI= +github.com/butuzov/mirror v1.1.0/go.mod h1:8Q0BdQU6rC6WILDiBM60DBfvV78OLJmMmixe7GF45AE= +github.com/ccojocar/zxcvbn-go v1.0.1 h1:+sxrANSCj6CdadkcMnvde/GWU1vZiiXRbqYSCalV4/4= +github.com/ccojocar/zxcvbn-go v1.0.1/go.mod h1:g1qkXtUSvHP8lhHp5GrSmTz6uWALGRMQdw6Qnz/hi60= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/charithe/durationcheck v0.0.10 h1:wgw73BiocdBDQPik+zcEoBG/ob8uyBHf2iyoHGPf5w4= +github.com/charithe/durationcheck v0.0.10/go.mod h1:bCWXb7gYRysD1CU3C+u4ceO49LoGOY1C1L6uouGNreQ= +github.com/chavacava/garif v0.0.0-20230227094218-b8c73b2037b8 h1:W9o46d2kbNL06lq7UNDPV0zYLzkrde/bjIqO02eoll0= +github.com/chavacava/garif v0.0.0-20230227094218-b8c73b2037b8/go.mod h1:gakxgyXaaPkxvLw1XQxNGK4I37ys9iBRzNUx/B7pUCo= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/curioswitch/go-reassign v0.2.0 h1:G9UZyOcpk/d7Gd6mqYgd8XYWFMw/znxwGDUstnC9DIo= +github.com/curioswitch/go-reassign v0.2.0/go.mod h1:x6OpXuWvgfQaMGks2BZybTngWjT84hqJfKoO8Tt/Roc= +github.com/daixiang0/gci v0.11.0 h1:XeQbFKkCRxvVyn06EOuNY6LPGBLVuB/W130c8FrnX6A= +github.com/daixiang0/gci v0.11.0/go.mod h1:xtHP9N7AHdNvtRNfcx9gwTDfw7FRJx4bZUsiEfiNNAI= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/denis-tingaikin/go-header v0.4.3 h1:tEaZKAlqql6SKCY++utLmkPLd6K8IBM20Ha7UVm+mtU= +github.com/denis-tingaikin/go-header v0.4.3/go.mod h1:0wOCWuN71D5qIgE2nz9KrKmuYBAC2Mra5RassOIQ2/c= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/esimonov/ifshort v1.0.4 h1:6SID4yGWfRae/M7hkVDVVyppy8q/v9OuxNdmjLQStBA= +github.com/esimonov/ifshort v1.0.4/go.mod h1:Pe8zjlRrJ80+q2CxHLfEOfTwxCZ4O+MuhcHcfgNWTk0= +github.com/ettle/strcase v0.1.1 h1:htFueZyVeE1XNnMEfbqp5r67qAN/4r6ya1ysq8Q+Zcw= +github.com/ettle/strcase v0.1.1/go.mod h1:hzDLsPC7/lwKyBOywSHEP89nt2pDgdy+No1NBA9o9VY= +github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= +github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= +github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4= +github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= +github.com/firefart/nonamedreturns v1.0.4 h1:abzI1p7mAEPYuR4A+VLKn4eNDOycjYo2phmY9sfv40Y= +github.com/firefart/nonamedreturns v1.0.4/go.mod h1:TDhe/tjI1BXo48CmYbUduTV7BdIga8MAO/xbKdcVsGI= +github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= +github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= +github.com/fzipp/gocyclo v0.6.0 h1:lsblElZG7d3ALtGMx9fmxeTKZaLLpU8mET09yN4BBLo= +github.com/fzipp/gocyclo v0.6.0/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA= +github.com/go-critic/go-critic v0.9.0 h1:Pmys9qvU3pSML/3GEQ2Xd9RZ/ip+aXHKILuxczKGV/U= +github.com/go-critic/go-critic v0.9.0/go.mod h1:5P8tdXL7m/6qnyG6oRAlYLORvoXH0WDypYgAEmagT40= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-toolsmith/astcast v1.1.0 h1:+JN9xZV1A+Re+95pgnMgDboWNVnIMMQXwfBwLRPgSC8= +github.com/go-toolsmith/astcast v1.1.0/go.mod h1:qdcuFWeGGS2xX5bLM/c3U9lewg7+Zu4mr+xPwZIB4ZU= +github.com/go-toolsmith/astcopy v1.1.0 h1:YGwBN0WM+ekI/6SS6+52zLDEf8Yvp3n2seZITCUBt5s= +github.com/go-toolsmith/astcopy v1.1.0/go.mod h1:hXM6gan18VA1T/daUEHCFcYiW8Ai1tIwIzHY6srfEAw= +github.com/go-toolsmith/astequal v1.0.3/go.mod h1:9Ai4UglvtR+4up+bAD4+hCj7iTo4m/OXVTSLnCyTAx4= +github.com/go-toolsmith/astequal v1.1.0 h1:kHKm1AWqClYn15R0K1KKE4RG614D46n+nqUQ06E1dTw= +github.com/go-toolsmith/astequal v1.1.0/go.mod h1:sedf7VIdCL22LD8qIvv7Nn9MuWJruQA/ysswh64lffQ= +github.com/go-toolsmith/astfmt v1.1.0 h1:iJVPDPp6/7AaeLJEruMsBUlOYCmvg0MoCfJprsOmcco= +github.com/go-toolsmith/astfmt v1.1.0/go.mod h1:OrcLlRwu0CuiIBp/8b5PYF9ktGVZUjlNMV634mhwuQ4= +github.com/go-toolsmith/astp v1.1.0 h1:dXPuCl6u2llURjdPLLDxJeZInAeZ0/eZwFJmqZMnpQA= +github.com/go-toolsmith/astp v1.1.0/go.mod h1:0T1xFGz9hicKs8Z5MfAqSUitoUYS30pDMsRVIDHs8CA= +github.com/go-toolsmith/strparse v1.0.0/go.mod h1:YI2nUKP9YGZnL/L1/DLFBfixrcjslWct4wyljWhSRy8= +github.com/go-toolsmith/strparse v1.1.0 h1:GAioeZUK9TGxnLS+qfdqNbA4z0SSm5zVNtCQiyP2Bvw= +github.com/go-toolsmith/strparse v1.1.0/go.mod h1:7ksGy58fsaQkGQlY8WVoBFNyEPMGuJin1rfoPS4lBSQ= +github.com/go-toolsmith/typep v1.1.0 h1:fIRYDyF+JywLfqzyhdiHzRop/GQDxxNhLGQ6gFUNHus= +github.com/go-toolsmith/typep v1.1.0/go.mod h1:fVIw+7zjdsMxDA3ITWnH1yOiw1rnTQKCsF/sk2H/qig= +github.com/go-xmlfmt/xmlfmt v1.1.2 h1:Nea7b4icn8s57fTx1M5AI4qQT5HEM3rVUO8MuE6g80U= +github.com/go-xmlfmt/xmlfmt v1.1.2/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM= +github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= +github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= +github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2 h1:23T5iq8rbUYlhpt5DB4XJkc6BU31uODLD1o1gKvZmD0= +github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2/go.mod h1:k9Qvh+8juN+UKMCS/3jFtGICgW8O96FVaZsaxdzDkR4= +github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a h1:w8hkcTqaFpzKqonE9uMCefW1WDie15eSP/4MssdenaM= +github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a/go.mod h1:ryS0uhF+x9jgbj/N71xsEqODy9BN81/GonCZiOzirOk= +github.com/golangci/go-misc v0.0.0-20220329215616-d24fe342adfe h1:6RGUuS7EGotKx6J5HIP8ZtyMdiDscjMLfRBSPuzVVeo= +github.com/golangci/go-misc v0.0.0-20220329215616-d24fe342adfe/go.mod h1:gjqyPShc/m8pEMpk0a3SeagVb0kaqvhscv+i9jI5ZhQ= +github.com/golangci/gofmt v0.0.0-20220901101216-f2edd75033f2 h1:amWTbTGqOZ71ruzrdA+Nx5WA3tV1N0goTspwmKCQvBY= +github.com/golangci/gofmt v0.0.0-20220901101216-f2edd75033f2/go.mod h1:9wOXstvyDRshQ9LggQuzBCGysxs3b6Uo/1MvYCR2NMs= +github.com/golangci/golangci-lint v1.54.2 h1:oR9zxfWYxt7hFqk6+fw6Enr+E7F0SN2nqHhJYyIb0yo= +github.com/golangci/golangci-lint v1.54.2/go.mod h1:vnsaCTPKCI2wreL9tv7RkHDwUrz3htLjed6+6UsvcwU= +github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0 h1:MfyDlzVjl1hoaPzPD4Gpb/QgoRfSBR0jdhwGyAWwMSA= +github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0/go.mod h1:66R6K6P6VWk9I95jvqGxkqJxVWGFy9XlDwLwVz1RCFg= +github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca h1:kNY3/svz5T29MYHubXix4aDDuE3RWHkPvopM/EDv/MA= +github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca/go.mod h1:tvlJhZqDe4LMs4ZHD0oMUlt9G2LWuDGoisJTBzLMV9o= +github.com/golangci/misspell v0.4.1 h1:+y73iSicVy2PqyX7kmUefHusENlrP9YwuHZHPLGQj/g= +github.com/golangci/misspell v0.4.1/go.mod h1:9mAN1quEo3DlpbaIKKyEvRxK1pwqR9s/Sea1bJCtlNI= +github.com/golangci/revgrep v0.0.0-20220804021717-745bb2f7c2e6 h1:DIPQnGy2Gv2FSA4B/hh8Q7xx3B7AIDk3DAMeHclH1vQ= +github.com/golangci/revgrep v0.0.0-20220804021717-745bb2f7c2e6/go.mod h1:0AKcRCkMoKvUvlf89F6O7H2LYdhr1zBh736mBItOdRs= +github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4 h1:zwtduBRr5SSWhqsYNgcuWO2kFlpdOZbP0+yRjmvPGys= +github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4/go.mod h1:Izgrg8RkN3rCIMLGE9CyYmU9pY2Jer6DgANEnZ/L/cQ= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= +github.com/gordonklaus/ineffassign v0.0.0-20230610083614-0e73809eb601 h1:mrEEilTAUmaAORhssPPkxj84TsHrPMLBGW2Z4SoTxm8= +github.com/gordonklaus/ineffassign v0.0.0-20230610083614-0e73809eb601/go.mod h1:Qcp2HIAYhR7mNUVSIxZww3Guk4it82ghYcEXIAk+QT0= +github.com/gostaticanalysis/analysisutil v0.7.1 h1:ZMCjoue3DtDWQ5WyU16YbjbQEQ3VuzwxALrpYd+HeKk= +github.com/gostaticanalysis/analysisutil v0.7.1/go.mod h1:v21E3hY37WKMGSnbsw2S/ojApNWb6C1//mXO48CXbVc= +github.com/gostaticanalysis/comment v1.4.1/go.mod h1:ih6ZxzTHLdadaiSnF5WY3dxUoXfXAlTaRzuaNDlSado= +github.com/gostaticanalysis/comment v1.4.2 h1:hlnx5+S2fY9Zo9ePo4AhgYsYHbM2+eAv8m/s1JiCd6Q= +github.com/gostaticanalysis/comment v1.4.2/go.mod h1:KLUTGDv6HOCotCH8h2erHKmpci2ZoR8VPu34YA2uzdM= +github.com/gostaticanalysis/forcetypeassert v0.1.0 h1:6eUflI3DiGusXGK6X7cCcIgVCpZ2CiZ1Q7jl6ZxNV70= +github.com/gostaticanalysis/forcetypeassert v0.1.0/go.mod h1:qZEedyP/sY1lTGV1uJ3VhWZ2mqag3IkWsDHVbplHXak= +github.com/gostaticanalysis/nilerr v0.1.1 h1:ThE+hJP0fEp4zWLkWHWcRyI2Od0p7DlgYG3Uqrmrcpk= +github.com/gostaticanalysis/nilerr v0.1.1/go.mod h1:wZYb6YI5YAxxq0i1+VJbY0s2YONW0HU0GPE3+5PWN4A= +github.com/gostaticanalysis/testutil v0.3.1-0.20210208050101-bfb5c8eec0e4/go.mod h1:D+FIZ+7OahH3ePw/izIEeH5I06eKs1IKI4Xr64/Am3M= +github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= +github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/jgautheron/goconst v1.5.1 h1:HxVbL1MhydKs8R8n/HE5NPvzfaYmQJA3o879lE4+WcM= +github.com/jgautheron/goconst v1.5.1/go.mod h1:aAosetZ5zaeC/2EfMeRswtxUFBpe2Hr7HzkgX4fanO4= +github.com/jingyugao/rowserrcheck v1.1.1 h1:zibz55j/MJtLsjP1OF4bSdgXxwL1b+Vn7Tjzq7gFzUs= +github.com/jingyugao/rowserrcheck v1.1.1/go.mod h1:4yvlZSDb3IyDTUZJUmpZfm2Hwok+Dtp+nu2qOq+er9c= +github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af h1:KA9BjwUk7KlCh6S9EAGWBt1oExIUv9WyNCiRz5amv48= +github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af/go.mod h1:HEWGJkRDzjJY2sqdDwxccsGicWEf9BQOZsq2tV+xzM0= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/julz/importas v0.1.0 h1:F78HnrsjY3cR7j0etXy5+TU1Zuy7Xt08X/1aJnH5xXY= +github.com/julz/importas v0.1.0/go.mod h1:oSFU2R4XK/P7kNBrnL/FEQlDGN1/6WoxXEjSSXO0DV0= +github.com/kisielk/errcheck v1.6.3 h1:dEKh+GLHcWm2oN34nMvDzn1sqI0i0WxPvrgiJA5JuM8= +github.com/kisielk/errcheck v1.6.3/go.mod h1:nXw/i/MfnvRHqXa7XXmQMUB0oNFGuBrNI8d8NLy0LPw= +github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kkHAIKE/contextcheck v1.1.4 h1:B6zAaLhOEEcjvUgIYEqystmnFk1Oemn8bvJhbt0GMb8= +github.com/kkHAIKE/contextcheck v1.1.4/go.mod h1:1+i/gWqokIa+dm31mqGLZhZJ7Uh44DJGZVmr6QRBNJg= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kulti/thelper v0.6.3 h1:ElhKf+AlItIu+xGnI990no4cE2+XaSu1ULymV2Yulxs= +github.com/kulti/thelper v0.6.3/go.mod h1:DsqKShOvP40epevkFrvIwkCMNYxMeTNjdWL4dqWHZ6I= +github.com/kunwardeep/paralleltest v1.0.8 h1:Ul2KsqtzFxTlSU7IP0JusWlLiNqQaloB9vguyjbE558= +github.com/kunwardeep/paralleltest v1.0.8/go.mod h1:2C7s65hONVqY7Q5Efj5aLzRCNLjw2h4eMc9EcypGjcY= +github.com/kyoh86/exportloopref v0.1.11 h1:1Z0bcmTypkL3Q4k+IDHMWTcnCliEZcaPiIe0/ymEyhQ= +github.com/kyoh86/exportloopref v0.1.11/go.mod h1:qkV4UF1zGl6EkF1ox8L5t9SwyeBAZ3qLMd6up458uqA= +github.com/ldez/gomoddirectives v0.2.3 h1:y7MBaisZVDYmKvt9/l1mjNCiSA1BVn34U0ObUcJwlhA= +github.com/ldez/gomoddirectives v0.2.3/go.mod h1:cpgBogWITnCfRq2qGoDkKMEVSaarhdBr6g8G04uz6d0= +github.com/ldez/tagliatelle v0.5.0 h1:epgfuYt9v0CG3fms0pEgIMNPuFf/LpPIfjk4kyqSioo= +github.com/ldez/tagliatelle v0.5.0/go.mod h1:rj1HmWiL1MiKQuOONhd09iySTEkUuE/8+5jtPYz9xa4= +github.com/leonklingele/grouper v1.1.1 h1:suWXRU57D4/Enn6pXR0QVqqWWrnJ9Osrz+5rjt8ivzU= +github.com/leonklingele/grouper v1.1.1/go.mod h1:uk3I3uDfi9B6PeUjsCKi6ndcf63Uy7snXgR4yDYQVDY= +github.com/lufeee/execinquery v1.2.1 h1:hf0Ems4SHcUGBxpGN7Jz78z1ppVkP/837ZlETPCEtOM= +github.com/lufeee/execinquery v1.2.1/go.mod h1:EC7DrEKView09ocscGHC+apXMIaorh4xqSxS/dy8SbM= +github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= +github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/maratori/testableexamples v1.0.0 h1:dU5alXRrD8WKSjOUnmJZuzdxWOEQ57+7s93SLMxb2vI= +github.com/maratori/testableexamples v1.0.0/go.mod h1:4rhjL1n20TUTT4vdh3RDqSizKLyXp7K2u6HgraZCGzE= +github.com/maratori/testpackage v1.1.1 h1:S58XVV5AD7HADMmD0fNnziNHqKvSdDuEKdPD1rNTU04= +github.com/maratori/testpackage v1.1.1/go.mod h1:s4gRK/ym6AMrqpOa/kEbQTV4Q4jb7WeLZzVhVVVOQMc= +github.com/matoous/godox v0.0.0-20230222163458-006bad1f9d26 h1:gWg6ZQ4JhDfJPqlo2srm/LN17lpybq15AryXIRcWYLE= +github.com/matoous/godox v0.0.0-20230222163458-006bad1f9d26/go.mod h1:1BELzlh859Sh1c6+90blK8lbYy0kwQf1bYlBhBysy1s= +github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= +github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mbilski/exhaustivestruct v1.2.0 h1:wCBmUnSYufAHO6J4AVWY6ff+oxWxsVFrwgOdMUQePUo= +github.com/mbilski/exhaustivestruct v1.2.0/go.mod h1:OeTBVxQWoEmB2J2JCHmXWPJ0aksxSUOUy+nvtVEfzXc= +github.com/mgechev/revive v1.3.2 h1:Wb8NQKBaALBJ3xrrj4zpwJwqwNA6nDpyJSEQWcCka6U= +github.com/mgechev/revive v1.3.2/go.mod h1:UCLtc7o5vg5aXCwdUTU1kEBQ1v+YXPAkYDIDXbrs5I0= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/moricho/tparallel v0.3.1 h1:fQKD4U1wRMAYNngDonW5XupoB/ZGJHdpzrWqgyg9krA= +github.com/moricho/tparallel v0.3.1/go.mod h1:leENX2cUv7Sv2qDgdi0D0fCftN8fRC67Bcn8pqzeYNI= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/nakabonne/nestif v0.3.1 h1:wm28nZjhQY5HyYPx+weN3Q65k6ilSBxDb8v5S81B81U= +github.com/nakabonne/nestif v0.3.1/go.mod h1:9EtoZochLn5iUprVDmDjqGKPofoUEBL8U4Ngq6aY7OE= +github.com/nishanths/exhaustive v0.11.0 h1:T3I8nUGhl/Cwu5Z2hfc92l0e04D2GEW6e0l8pzda2l0= +github.com/nishanths/exhaustive v0.11.0/go.mod h1:RqwDsZ1xY0dNdqHho2z6X+bgzizwbLYOWnZbbl2wLB4= +github.com/nishanths/predeclared v0.2.2 h1:V2EPdZPliZymNAn79T8RkNApBjMmVKh5XRpLm/w98Vk= +github.com/nishanths/predeclared v0.2.2/go.mod h1:RROzoN6TnGQupbC+lqggsOlcgysk3LMK/HI84Mp280c= +github.com/nunnatsa/ginkgolinter v0.13.5 h1:fOsPB4CEZOPkyMqF4B9hoqOpooFWU7vWSVkCSscVpgU= +github.com/nunnatsa/ginkgolinter v0.13.5/go.mod h1:OBHy4536xtuX3102NM63XRtOyxqZOO02chsaeDWXVO8= +github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= +github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= +github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw= +github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= +github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs= +github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo= +github.com/otiai10/mint v1.3.1/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc= +github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= +github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pelletier/go-toml/v2 v2.0.5 h1:ipoSadvV8oGUjnUbMub59IDPPwfxF694nG/jwbMiyQg= +github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/polyfloyd/go-errorlint v1.4.4 h1:A9gytp+p6TYqeALTYRoxJESYP8wJRETRX2xzGWFsEBU= +github.com/polyfloyd/go-errorlint v1.4.4/go.mod h1:ry5NqF7l9Q77V+XqAfUg1zfryrEtyac3G5+WVpIK0xU= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.12.1 h1:ZiaPsmm9uiBeaSMRznKsCDNtPCS0T3JVDGF+06gjBzk= +github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/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.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4= +github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU= +github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/quasilyte/go-ruleguard v0.4.0 h1:DyM6r+TKL+xbKB4Nm7Afd1IQh9kEUKQs2pboWGKtvQo= +github.com/quasilyte/go-ruleguard v0.4.0/go.mod h1:Eu76Z/R8IXtViWUIHkE3p8gdH3/PKk1eh3YGfaEof10= +github.com/quasilyte/gogrep v0.5.0 h1:eTKODPXbI8ffJMN+W2aE0+oL0z/nh8/5eNdiO34SOAo= +github.com/quasilyte/gogrep v0.5.0/go.mod h1:Cm9lpz9NZjEoL1tgZ2OgeUKPIxL1meE7eo60Z6Sk+Ng= +github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727 h1:TCg2WBOl980XxGFEZSS6KlBGIV0diGdySzxATTWoqaU= +github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727/go.mod h1:rlzQ04UMyJXu/aOvhd8qT+hvDrFpiwqp8MRXDY9szc0= +github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 h1:M8mH9eK4OUR4lu7Gd+PU1fV2/qnDNfzT635KRSObncs= +github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567/go.mod h1:DWNGW8A4Y+GyBgPuaQJuWiy0XYftx4Xm/y5Jqk9I6VQ= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ryancurrah/gomodguard v1.3.0 h1:q15RT/pd6UggBXVBuLps8BXRvl5GPBcwVA7BJHMLuTw= +github.com/ryancurrah/gomodguard v1.3.0/go.mod h1:ggBxb3luypPEzqVtq33ee7YSN35V28XeGnid8dnni50= +github.com/ryanrolds/sqlclosecheck v0.4.0 h1:i8SX60Rppc1wRuyQjMciLqIzV3xnoHB7/tXbr6RGYNI= +github.com/ryanrolds/sqlclosecheck v0.4.0/go.mod h1:TBRRjzL31JONc9i4XMinicuo+s+E8yKZ5FN8X3G6CKQ= +github.com/sanposhiho/wastedassign/v2 v2.0.7 h1:J+6nrY4VW+gC9xFzUc+XjPD3g3wF3je/NsJFwFK7Uxc= +github.com/sanposhiho/wastedassign/v2 v2.0.7/go.mod h1:KyZ0MWTwxxBmfwn33zh3k1dmsbF2ud9pAAGfoLfjhtI= +github.com/sashamelentyev/interfacebloat v1.1.0 h1:xdRdJp0irL086OyW1H/RTZTr1h/tMEOsumirXcOJqAw= +github.com/sashamelentyev/interfacebloat v1.1.0/go.mod h1:+Y9yU5YdTkrNvoX0xHc84dxiN1iBi9+G8zZIhPVoNjQ= +github.com/sashamelentyev/usestdlibvars v1.24.0 h1:MKNzmXtGh5N0y74Z/CIaJh4GlB364l0K1RUT08WSWAc= +github.com/sashamelentyev/usestdlibvars v1.24.0/go.mod h1:9cYkq+gYJ+a5W2RPdhfaSCnTVUC1OQP/bSiiBhq3OZE= +github.com/securego/gosec/v2 v2.17.0 h1:ZpAStTDKY39insEG9OH6kV3IkhQZPTq9a9eGOLOjcdI= +github.com/securego/gosec/v2 v2.17.0/go.mod h1:lt+mgC91VSmriVoJLentrMkRCYs+HLTBnUFUBuhV2hc= +github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c h1:W65qqJCIOVP4jpqPQ0YvHYKwcMEMVWIzWC5iNQQfBTU= +github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c/go.mod h1:/PevMnwAxekIXwN8qQyfc5gl2NlkB3CQlkizAbOkeBs= +github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= +github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sivchari/containedctx v1.0.3 h1:x+etemjbsh2fB5ewm5FeLNi5bUjK0V8n0RB+Wwfd0XE= +github.com/sivchari/containedctx v1.0.3/go.mod h1:c1RDvCbnJLtH4lLcYD/GqwiBSSf4F5Qk0xld2rBqzJ4= +github.com/sivchari/nosnakecase v1.7.0 h1:7QkpWIRMe8x25gckkFd2A5Pi6Ymo0qgr4JrhGt95do8= +github.com/sivchari/nosnakecase v1.7.0/go.mod h1:CwDzrzPea40/GB6uynrNLiorAlgFRvRbFSgJx2Gs+QY= +github.com/sivchari/tenv v1.7.1 h1:PSpuD4bu6fSmtWMxSGWcvqUUgIn7k3yOJhOIzVWn8Ak= +github.com/sivchari/tenv v1.7.1/go.mod h1:64yStXKSOxDfX47NlhVwND4dHwfZDdbp2Lyl018Icvg= +github.com/sonatard/noctx v0.0.2 h1:L7Dz4De2zDQhW8S0t+KUjY0MAQJd6SgVwhzNIc4ok00= +github.com/sonatard/noctx v0.0.2/go.mod h1:kzFz+CzWSjQ2OzIm46uJZoXuBpa2+0y3T36U18dWqIo= +github.com/sourcegraph/go-diff v0.7.0 h1:9uLlrd5T46OXs5qpp8L/MTltk0zikUGi0sNNyCpA8G0= +github.com/sourcegraph/go-diff v0.7.0/go.mod h1:iBszgVvyxdc8SFZ7gm69go2KDdt3ag071iBaWPF6cjs= +github.com/spf13/afero v1.8.2 h1:xehSyVa0YnHWsJ49JFljMpg1HX19V6NDZ1fkm1Xznbo= +github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo= +github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= +github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= +github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= +github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= +github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= +github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.12.0 h1:CZ7eSOd3kZoaYDLbXnmzgQI5RlciuXBMA+18HwHRfZQ= +github.com/spf13/viper v1.12.0/go.mod h1:b6COn30jlNxbm/V2IqWiNWkJ+vZNiMNksliPCiuKtSI= +github.com/ssgreg/nlreturn/v2 v2.2.1 h1:X4XDI7jstt3ySqGU86YGAURbxw3oTDPK9sPEi6YEwQ0= +github.com/ssgreg/nlreturn/v2 v2.2.1/go.mod h1:E/iiPB78hV7Szg2YfRgyIrk1AD6JVMTRkkxBiELzh2I= +github.com/stbenjam/no-sprintf-host-port v0.1.1 h1:tYugd/yrm1O0dV+ThCbaKZh195Dfm07ysF0U6JQXczc= +github.com/stbenjam/no-sprintf-host-port v0.1.1/go.mod h1:TLhvtIvONRzdmkFiio4O8LHsN9N74I+PhRquPsxpL0I= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs= +github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= +github.com/t-yuki/gocover-cobertura v0.0.0-20180217150009-aaee18c8195c h1:+aPplBwWcHBo6q9xrfWdMrT9o4kltkmmvpemgIjep/8= +github.com/t-yuki/gocover-cobertura v0.0.0-20180217150009-aaee18c8195c/go.mod h1:SbErYREK7xXdsRiigaQiQkI9McGRzYMvlKYaP3Nimdk= +github.com/tdakkota/asciicheck v0.2.0 h1:o8jvnUANo0qXtnslk2d3nMKTFNlOnJjRrNcj0j9qkHM= +github.com/tdakkota/asciicheck v0.2.0/go.mod h1:Qb7Y9EgjCLJGup51gDHFzbI08/gbGhL/UVhYIPWG2rg= +github.com/tenntenn/modver v1.0.1/go.mod h1:bePIyQPb7UeioSRkw3Q0XeMhYZSMx9B8ePqg6SAMGH0= +github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3/go.mod h1:ON8b8w4BN/kE1EOhwT0o+d62W65a6aPw1nouo9LMgyY= +github.com/tetafro/godot v1.4.14 h1:ScO641OHpf9UpHPk8fCknSuXNMpi4iFlwuWoBs3L+1s= +github.com/tetafro/godot v1.4.14/go.mod h1:2oVxTBSftRTh4+MVfUaUXR6bn2GDXCaMcOG4Dk3rfio= +github.com/timakin/bodyclose v0.0.0-20230421092635-574207250966 h1:quvGphlmUVU+nhpFa4gg4yJyTRJ13reZMDHrKwYw53M= +github.com/timakin/bodyclose v0.0.0-20230421092635-574207250966/go.mod h1:27bSVNWSBOHm+qRp1T9qzaIpsWEP6TbUnei/43HK+PQ= +github.com/timonwong/loggercheck v0.9.4 h1:HKKhqrjcVj8sxL7K77beXh0adEm6DLjV/QOGeMXEVi4= +github.com/timonwong/loggercheck v0.9.4/go.mod h1:caz4zlPcgvpEkXgVnAJGowHAMW2NwHaNlpS8xDbVhTg= +github.com/tomarrell/wrapcheck/v2 v2.8.1 h1:HxSqDSN0sAt0yJYsrcYVoEeyM4aI9yAm3KQpIXDJRhQ= +github.com/tomarrell/wrapcheck/v2 v2.8.1/go.mod h1:/n2Q3NZ4XFT50ho6Hbxg+RV1uyo2Uow/Vdm9NQcl5SE= +github.com/tommy-muehle/go-mnd/v2 v2.5.1 h1:NowYhSdyE/1zwK9QCLeRb6USWdoif80Ie+v+yU8u1Zw= +github.com/tommy-muehle/go-mnd/v2 v2.5.1/go.mod h1:WsUAkMJMYww6l/ufffCD3m+P7LEvr8TnZn9lwVDlgzw= +github.com/ultraware/funlen v0.1.0 h1:BuqclbkY6pO+cvxoq7OsktIXZpgBSkYTQtmwhAK81vI= +github.com/ultraware/funlen v0.1.0/go.mod h1:XJqmOQja6DpxarLj6Jj1U7JuoS8PvL4nEqDaQhy22p4= +github.com/ultraware/whitespace v0.0.5 h1:hh+/cpIcopyMYbZNVov9iSxvJU3OYQg78Sfaqzi/CzI= +github.com/ultraware/whitespace v0.0.5/go.mod h1:aVMh/gQve5Maj9hQ/hg+F75lr/X5A89uZnzAmWSineA= +github.com/uudashr/gocognit v1.0.7 h1:e9aFXgKgUJrQ5+bs61zBigmj7bFJ/5cC6HmMahVzuDo= +github.com/uudashr/gocognit v1.0.7/go.mod h1:nAIUuVBnYU7pcninia3BHOvQkpQCeO76Uscky5BOwcY= +github.com/xen0n/gosmopolitan v1.2.1 h1:3pttnTuFumELBRSh+KQs1zcz4fN6Zy7aB0xlnQSn1Iw= +github.com/xen0n/gosmopolitan v1.2.1/go.mod h1:JsHq/Brs1o050OOdmzHeOr0N7OtlnKRAGAsElF8xBQA= +github.com/yagipy/maintidx v1.0.0 h1:h5NvIsCz+nRDapQ0exNv4aJ0yXSI0420omVANTv3GJM= +github.com/yagipy/maintidx v1.0.0/go.mod h1:0qNf/I/CCZXSMhsRsrEPDZ+DkekpKLXAJfsTACwgXLk= +github.com/yeya24/promlinter v0.2.0 h1:xFKDQ82orCU5jQujdaD8stOHiv8UN68BSdn2a8u8Y3o= +github.com/yeya24/promlinter v0.2.0/go.mod h1:u54lkmBOZrpEbQQ6gox2zWKKLKu2SGe+2KOiextY+IA= +github.com/ykadowak/zerologlint v0.1.3 h1:TLy1dTW3Nuc+YE3bYRPToG1Q9Ej78b5UUN6bjbGdxPE= +github.com/ykadowak/zerologlint v0.1.3/go.mod h1:KaUskqF3e/v59oPmdq1U1DnKcuHokl2/K1U4pmIELKg= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +gitlab.com/bosi/decorder v0.4.0 h1:HWuxAhSxIvsITcXeP+iIRg9d1cVfvVkmlF7M68GaoDY= +gitlab.com/bosi/decorder v0.4.0/go.mod h1:xarnteyUoJiOTEldDysquWKTVDCKo2TOIOIibSuWqOg= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.tmz.dev/musttag v0.7.2 h1:1J6S9ipDbalBSODNT5jCep8dhZyMr4ttnjQagmGYR5s= +go.tmz.dev/musttag v0.7.2/go.mod h1:m6q5NiiSKMnQYokefa2xGoyoXnrswCbJ0AWYzf4Zs28= +go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= +go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp v0.0.0-20230510235704-dd950f8aeaea h1:vLCWI/yYrdEHyN2JzIzPO3aaQJHQdp89IZBA/+azVC4= +golang.org/x/exp v0.0.0-20230510235704-dd950f8aeaea/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= +golang.org/x/exp/typeparams v0.0.0-20220428152302-39d4317da171/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= +golang.org/x/exp/typeparams v0.0.0-20230203172020-98cc5a0785f9/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= +golang.org/x/exp/typeparams v0.0.0-20230307190834-24139beb5833 h1:jWGQJV4niP+CCmFW9ekjA9Zx8vYORzOUH2/Nl5WPuLQ= +golang.org/x/exp/typeparams v0.0.0-20230307190834-24139beb5833/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= +golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= +golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211105183446-c75c47738b0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220702020025-31831981b65f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= +golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= +golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190321232350-e250d351ecad/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190910044552-dd2b5c81c578/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200324003944-a576cf524670/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200329025819-fd4102a86c65/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200724022722-7017fd6b1305/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200820010801-b793a1359eac/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201001104356-43ebab892c4c/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= +golang.org/x/tools v0.0.0-20201023174141-c8cfbd0f21e6/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.1-0.20210205202024-ef80cdb6ec6d/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU= +golang.org/x/tools v0.1.1-0.20210302220138-2ac05c832e1a/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= +golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= +golang.org/x/tools v0.1.11/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= +golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= +golang.org/x/tools v0.5.0/go.mod h1:N+Kgy78s5I24c24dU8OfWNEotWjutIs8SnJvn5IDq+k= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.12.0 h1:YW6HUoUmYBpwSgyaGaZq1fHjrBjX1rlpZ54T6mu2kss= +golang.org/x/tools v0.12.0/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.4.5 h1:YGD4H+SuIOOqsyoLOpZDWcieM28W47/zRO7f+9V3nvo= +honnef.co/go/tools v0.4.5/go.mod h1:GUV+uIBCLpdf0/v6UhHHG/yzI/z6qPskBeQCjcNB96k= +mvdan.cc/gofumpt v0.5.0 h1:0EQ+Z56k8tXjj/6TQD25BFNKQXpCvT0rnansIc7Ug5E= +mvdan.cc/gofumpt v0.5.0/go.mod h1:HBeVDtMKRZpXyxFciAirzdKklDlGu8aAy1wEbH5Y9js= +mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed h1:WX1yoOaKQfddO/mLzdV4wptyWgoH/6hwLs7QHTixo0I= +mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed/go.mod h1:Xkxe497xwlCKkIaQYRfC7CSLworTXY9RMqwhhCm+8Nc= +mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b h1:DxJ5nJdkhDlLok9K6qO+5290kphDJbHOQO1DFFFTeBo= +mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jCoyKnw3vv5biOc3JnIcYfL4= +mvdan.cc/unparam v0.0.0-20221223090309-7455f1af531d h1:3rvTIIM22r9pvXk+q3swxUQAQOxksVMGK7sml4nG57w= +mvdan.cc/unparam v0.0.0-20221223090309-7455f1af531d/go.mod h1:IeHQjmn6TOD+e4Z3RFiZMMsLVL+A96Nvptar8Fj71is= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/.bingo/misspell.mod b/.bingo/misspell.mod new file mode 100644 index 000000000..0a8c40ce0 --- /dev/null +++ b/.bingo/misspell.mod @@ -0,0 +1,5 @@ +module _ // Auto generated by https://github.com/bwplotka/bingo. DO NOT EDIT + +go 1.21.0 + +require github.com/client9/misspell v0.3.4 // cmd/misspell diff --git a/.bingo/misspell.sum b/.bingo/misspell.sum new file mode 100644 index 000000000..ee5948021 --- /dev/null +++ b/.bingo/misspell.sum @@ -0,0 +1,2 @@ +github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= diff --git a/.bingo/shfmt.mod b/.bingo/shfmt.mod new file mode 100644 index 000000000..ab6d8e3e9 --- /dev/null +++ b/.bingo/shfmt.mod @@ -0,0 +1,5 @@ +module _ // Auto generated by https://github.com/bwplotka/bingo. DO NOT EDIT + +go 1.21.0 + +require mvdan.cc/sh/v3 v3.7.0 // cmd/shfmt diff --git a/.bingo/shfmt.sum b/.bingo/shfmt.sum new file mode 100644 index 000000000..23095e424 --- /dev/null +++ b/.bingo/shfmt.sum @@ -0,0 +1,12 @@ +github.com/google/renameio/v2 v2.0.0 h1:UifI23ZTGY8Tt29JbYFiuyIU3eX+RNFtUwefq9qAhxg= +github.com/google/renameio/v2 v2.0.0/go.mod h1:BtmJXm5YlszgC+TD4HOEEUFgkJP3nLxehU6hfe7jRt4= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e h1:aoZm08cpOy4WuID//EZDgcC4zIxODThtZNPirFr42+A= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +mvdan.cc/editorconfig v0.2.0 h1:XL+7ys6ls/RKrkUNFQvEwIvNHh+JKx8Mj1pUV5wQxQE= +mvdan.cc/editorconfig v0.2.0/go.mod h1:lvnnD3BNdBYkhq+B4uBuFFKatfp02eB6HixDvEz91C0= +mvdan.cc/sh/v3 v3.7.0 h1:lSTjdP/1xsddtaKfGg7Myu7DnlHItd3/M2tomOcNNBg= +mvdan.cc/sh/v3 v3.7.0/go.mod h1:K2gwkaesF/D7av7Kxl0HbF5kGOd2ArupNTX3X44+8l8= diff --git a/.bingo/variables.env b/.bingo/variables.env new file mode 100644 index 000000000..ee1aadd88 --- /dev/null +++ b/.bingo/variables.env @@ -0,0 +1,20 @@ +# Auto generated binary variables helper managed by https://github.com/bwplotka/bingo v0.8. DO NOT EDIT. +# All tools are designed to be build inside $GOBIN. +# Those variables will work only until 'bingo get' was invoked, or if tools were installed via Makefile's Variables.mk. +GOBIN=${GOBIN:=$(go env GOBIN)} + +if [ -z "$GOBIN" ]; then + GOBIN="$(go env GOPATH)/bin" +fi + + +FAILLINT="${GOBIN}/faillint-v1.11.0" + +GOIMPORTS="${GOBIN}/goimports-v0.14.0" + +GOLANGCI_LINT="${GOBIN}/golangci-lint-v1.54.2" + +MISSPELL="${GOBIN}/misspell-v0.3.4" + +SHFMT="${GOBIN}/shfmt-v3.7.0" + diff --git a/.errcheck_excludes.txt b/.errcheck_excludes.txt new file mode 100644 index 000000000..0c956b457 --- /dev/null +++ b/.errcheck_excludes.txt @@ -0,0 +1,3 @@ +(github.com/go-kit/log.Logger).Log +fmt.Fprintln +fmt.Fprint diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml new file mode 100644 index 000000000..06f30b7b0 --- /dev/null +++ b/.github/workflows/lint.yaml @@ -0,0 +1,36 @@ +name: lint + +on: + push: + branches: + - main + tags: + pull_request: + +jobs: + lint: + runs-on: ubuntu-latest + name: Formatters + Linters (Static Analysis) for Go + env: + GOBIN: /tmp/.bin + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Install Go + uses: actions/setup-go@v3 + with: + go-version: 1.21.x + + - uses: actions/cache@v3 + with: + path: | + ~/.cache/go-build + ~/.cache/golangci-lint + ~/go/pkg/mod + key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go- + + - name: Linting, Formatting & vetting + run: make lint \ No newline at end of file diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 000000000..06ea4a0e9 --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,67 @@ +# This file contains all available configuration options +# with their default values. + +# options for analysis running +run: + # timeout for analysis, e.g. 30s, 5m, default is 1m + deadline: 5m + + # exit code when at least one issue was found, default is 1 + issues-exit-code: 1 + + # TODO(saswatamcode): Remove this by cleaning up our test suite. + tests: false + + # which dirs to skip: they won't be analyzed; + # can use regexp here: generated.*, regexp is applied on full path; + # default value is empty list, but next dirs are always skipped independently + # from this option's value: + # vendor$, third_party$, testdata$, examples$, Godeps$, builtin$ + skip-dirs: + - vendor + +# output configuration options +output: + # colored-line-number|line-number|json|tab|checkstyle, default is "colored-line-number" + format: colored-line-number + + # print lines of code with issue, default is true + print-issued-lines: true + + # print linter name in the end of issue text, default is true + print-linter-name: true + +linters: + enable: + # Sorted alphabetically. + - errcheck + - goconst + # TODO(saswatamcode): Re-enable godot at some point, once comments are in order. + # - godot + - gofmt + - goimports + - gosimple + - govet + - ineffassign + - misspell + - staticcheck + - typecheck + - unparam + - unused + - exportloopref + - promlinter + +linters-settings: + errcheck: + exclude: ./.errcheck_excludes.txt + misspell: + locale: US + goconst: + min-occurrences: 5 + +issues: + exclude-rules: + # We don't check metrics naming in the tests. + - path: _test\.go + linters: + - promlinter \ No newline at end of file diff --git a/Makefile b/Makefile index 7ee05f25a..1433bb4f7 100644 --- a/Makefile +++ b/Makefile @@ -2,6 +2,15 @@ # Copyright Contributors to the Open Cluster Management project -include /opt/build-harness/Makefile.prow +include .bingo/Variables.mk + +FILES_TO_FMT ?= $(shell find . -path ./vendor -prune -o -name '*.deepcopy.go' -prune -o -name '*.go' -print) +TMP_DIR := $(shell pwd)/tmp +BIN_DIR ?= $(TMP_DIR)/bin +GIT ?= $(shell which git) + +XARGS ?= $(shell which gxargs 2>/dev/null || which xargs) +GREP ?= $(shell which ggrep 2>/dev/null || which grep) # Image URL to use all building/pushing image targets IMG ?= quay.io/stolostron/multicluster-observability-operator:latest @@ -27,16 +36,16 @@ docker-push: unit-tests: unit-tests-operators unit-tests-loaders unit-tests-proxy unit-tests-collectors unit-tests-operators: - go test -v ${VERBOSE} `go list ./operators/... | grep -v test` + go test -v ${VERBOSE} `go list ./operators/... | $(GREP) -v test` unit-tests-loaders: - go test -v ${VERBOSE} `go list ./loaders/... | grep -v test` + go test -v ${VERBOSE} `go list ./loaders/... | $(GREP) -v test` unit-tests-proxy: - go test -v ${VERBOSE} `go list ./proxy/... | grep -v test` + go test -v ${VERBOSE} `go list ./proxy/... | $(GREP) -v test` unit-tests-collectors: - go test ${VERBOSE} `go list ./collectors/... | grep -v test` + go test ${VERBOSE} `go list ./collectors/... | $(GREP) -v test` .PHONY: e2e-tests e2e-tests: @@ -57,3 +66,79 @@ endif bundle: cd operators/multiclusterobservability && make bundle +.PHONY: check-git +check-git: +ifneq ($(GIT),) + @test -x $(GIT) || (echo >&2 "No git executable binary found at $(GIT)."; exit 1) +else + @echo >&2 "No git binary found."; exit 1 +endif + +.PHONY: deps +deps: ## Ensures fresh go.mod and go.sum. + @go mod tidy + @go mod verify + @go mod vendor + +.PHONY: go-format +go-format: ## Formats Go code including imports. +go-format: $(GOIMPORTS) + @echo ">> formatting go code" + @gofmt -s -w $(FILES_TO_FMT) + @$(GOIMPORTS) -w $(FILES_TO_FMT) + +.PHONY: shell-format +shell-format: $(SHFMT) + @echo ">> formatting shell scripts" + @$(SHFMT) -i 2 -ci -w -s $(shell find . -type f -name "*.sh" -not -path "*vendor*" -not -path "tmp/*") + +.PHONY: format +format: ## Formats code including imports. +format: go-format shell-format + +define require_clean_work_tree + @git update-index -q --ignore-submodules --refresh + + @if ! git diff-files --quiet --ignore-submodules --; then \ + echo >&2 "cannot $1: you have unstaged changes."; \ + git diff -r --ignore-submodules -- >&2; \ + echo >&2 "Please commit or stash them."; \ + exit 1; \ + fi + + @if ! git diff-index --cached --quiet HEAD --ignore-submodules --; then \ + echo >&2 "cannot $1: your index contains uncommitted changes."; \ + git diff --cached -r --ignore-submodules HEAD -- >&2; \ + echo >&2 "Please commit or stash them."; \ + exit 1; \ + fi + +endef + +# PROTIP: +# Add +# --cpu-profile-path string Path to CPU profile output file +# --mem-profile-path string Path to memory profile output file +# to debug big allocations during linting. +.PHONY: lint +lint: check-git deps format $(GOLANGCI_LINT) $(FAILLINT) + $(call require_clean_work_tree,'detected files without copyright, run make lint and commit changes') + @echo ">> verifying modules being imported" + @$(FAILLINT) -paths "github.com/prometheus/tsdb=github.com/prometheus/prometheus/tsdb,\ +github.com/prometheus/prometheus/pkg/testutils=github.com/thanos-io/thanos/pkg/testutil,\ +github.com/prometheus/client_golang/prometheus.{DefaultGatherer,DefBuckets,NewUntypedFunc,UntypedFunc},\ +github.com/prometheus/client_golang/prometheus.{NewCounter,NewCounterVec,NewCounterVec,NewGauge,NewGaugeVec,NewGaugeFunc,\ +NewHistorgram,NewHistogramVec,NewSummary,NewSummaryVec}=github.com/prometheus/client_golang/prometheus/promauto.{NewCounter,\ +NewCounterVec,NewCounterVec,NewGauge,NewGaugeVec,NewGaugeFunc,NewHistorgram,NewHistogramVec,NewSummary,NewSummaryVec},\ +github.com/NYTimes/gziphandler.{GzipHandler}=github.com/klauspost/compress/gzhttp.{GzipHandler},\ +sync/atomic=go.uber.org/atomic,\ +io/ioutil.{Discard,NopCloser,ReadAll,ReadDir,ReadFile,TempDir,TempFile,Writefile}" ./... + @$(FAILLINT) -paths "fmt.{Print,Println}" -ignore-tests ./... + @echo ">> examining all of the Go files" + @go vet -stdmethods=false ./... + @echo ">> linting all of the Go files GOGC=${GOGC}" + @$(GOLANGCI_LINT) run + # TODO(saswatamcode): Enable this in a separate commit. + # @echo ">> ensuring Copyright headers" + # @go run ./scripts/copyright + $(call require_clean_work_tree,'detected files without copyright, run make lint and commit changes') \ No newline at end of file diff --git a/README.md b/README.md index 9a2160791..39221bfe0 100644 --- a/README.md +++ b/README.md @@ -83,7 +83,7 @@ make deploy IMG=quay.io//multicluster-observability-opera kubectl apply -f operators/multiclusterobservability/config/samples/observability_v1beta2_multiclusterobservability.yaml ``` -5. Verify all the components for the Multicluster Observability are starting up and runing: +5. Verify all the components for the Multicluster Observability are starting up and running: ```bash kubectl -n open-cluster-management-observability get pod diff --git a/cicd-scripts/build.sh b/cicd-scripts/build.sh index 591ef8d36..16e7eee9b 100755 --- a/cicd-scripts/build.sh +++ b/cicd-scripts/build.sh @@ -6,9 +6,9 @@ set -e make docker-binary -git config --global url."https://$GITHUB_TOKEN@github.com/stolostron".insteadOf "https://github.com/stolostron" +git config --global url."https://$GITHUB_TOKEN@github.com/stolostron".insteadOf "https://github.com/stolostron" echo "Building multicluster-observability-operator image" export DOCKER_IMAGE_AND_TAG=${1} export DOCKER_FILE=Dockerfile -make docker/build \ No newline at end of file +make docker/build diff --git a/cicd-scripts/copyright-check.sh b/cicd-scripts/copyright-check.sh index fea69b260..6d0f6d422 100755 --- a/cicd-scripts/copyright-check.sh +++ b/cicd-scripts/copyright-check.sh @@ -18,9 +18,9 @@ current_year=$(date +"%Y") TRAVIS_BRANCH=$1 -ADDED_SINCE_1_MAR_2020=$(git log --name-status --pretty=oneline --since "1 Mar 2020" | egrep "^A\t" | awk '{print $2}' | sort | uniq | grep -v -f <(sed 's/\([.|]\)/\\\1/g; s/\?/./g ; s/\*/.*/g' .copyrightignore)) +ADDED_SINCE_1_MAR_2020=$(git log --name-status --pretty=oneline --since "1 Mar 2020" | egrep "^A\t" | awk '{print $2}' | sort | uniq | grep -v -f <(sed 's/\([.|]\)/\\\1/g; s/\?/./g ; s/\*/.*/g' .copyrightignore)) MODIFIED_SINCE_1_MAR_2020=$(diff --new-line-format="" --unchanged-line-format="" <(git log --name-status --pretty=oneline --since "1 Mar 2020" | egrep "^A\t|^M\t" | awk '{print $2}' | sort | uniq | grep -v -f <(sed 's/\([.|]\)/\\\1/g; s/\?/./g ; s/\*/.*/g' .copyrightignore)) <(git log --name-status --pretty=oneline --since "1 Mar 2020" | egrep "^A\t" | awk '{print $2}' | sort | uniq | grep -v -f <(sed 's/\([.|]\)/\\\1/g; s/\?/./g ; s/\*/.*/g' .copyrightignore))) -OLDER_GIT_FILES=$(git log --name-status --pretty=oneline | egrep "^A\t|^M\t" | awk '{print $2}' | sort | uniq | grep -v -f <(sed 's/\([.|]\)/\\\1/g; s/\?/./g ; s/\*/.*/g' .copyrightignore)) +OLDER_GIT_FILES=$(git log --name-status --pretty=oneline | egrep "^A\t|^M\t" | awk '{print $2}' | sort | uniq | grep -v -f <(sed 's/\([.|]\)/\\\1/g; s/\?/./g ; s/\*/.*/g' .copyrightignore)) if [[ "x${TRAVIS_BRANCH}" != "x" ]]; then FILES_TO_SCAN=$(git diff --name-only --diff-filter=AM ${TRAVIS_BRANCH}...HEAD | grep -v -f <(sed 's/\([.|]\)/\\\1/g; s/\?/./g ; s/\*/.*/g' .copyrightignore)) @@ -39,11 +39,9 @@ lic_redhat_identifier=" Copyright (c) ${current_year} Red Hat, Inc." lic_year=() #All possible combination within [origin_year, current_year] range is valid format #seq isn't recommanded after bash version 3.0 -for ((start_year=origin_year;start_year<=current_year;start_year++)); -do +for ((start_year = origin_year; start_year <= current_year; start_year++)); do lic_year+=(" (c) Copyright IBM Corporation ${start_year}. All Rights Reserved.") - for ((end_year=start_year+1;end_year<=current_year;end_year++)); - do + for ((end_year = start_year + 1; end_year <= current_year; end_year++)); do lic_year+=(" (c) Copyright IBM Corporation ${start_year}, ${end_year}. All Rights Reserved.") done done @@ -66,7 +64,7 @@ echo "##### Copyright check #####" #for f in `find .. -type f ! -path "../.eslintrc.js" ! -path "../build-harness/*" ! -path "../auth-setup/*" ! -path "../sslcert/*" ! -path "../node_modules/*" ! -path "../coverage/*" ! -path "../test-output/*" ! -path "../build/*" ! -path "../nls/*" ! -path "../public/*"`; do for f in $FILES_TO_SCAN; do if [ ! -f "$f" ]; then - continue + continue fi # Flags that indicate the licenses to check for @@ -77,16 +75,17 @@ for f in $FILES_TO_SCAN; do FILETYPE=$(basename ${f##*.}) case "${FILETYPE}" in - js | go | scss | properties | java | rb | sh ) + js | go | scss | properties | java | rb | sh) COMMENT_PREFIX="" ;; *) #printf " Extension $FILETYPE not considered !!!\n" continue + ;; esac #Read the first 15 lines, most Copyright headers use the first 10 lines. - header=`head -15 $f` + header=$(head -15 $f) # Strip directory prefix, if any if [[ $f == "./"* ]]; then @@ -94,15 +93,15 @@ for f in $FILES_TO_SCAN; do fi printf " ========>>>>>> Scanning $f . . .\n" - if [[ "${ADDED_SINCE_1_MAR_2020}" == *"$f"* ]]; then + if [[ ${ADDED_SINCE_1_MAR_2020} == *"$f"* ]]; then printf " ---> Added since 01/03/2020\n" must_have_redhat_license=true flag_ibm_license=true - elif [[ "${MODIFIED_SINCE_1_MAR_2020}" == *"$f"* ]]; then + elif [[ ${MODIFIED_SINCE_1_MAR_2020} == *"$f"* ]]; then printf " ---> Modified since 01/03/2020\n" must_have_redhat_license=true must_have_ibm_license=true - elif [[ "${OLDER_GIT_FILES}" == *"$f"* ]]; then + elif [[ ${OLDER_GIT_FILES} == *"$f"* ]]; then printf " ---> File older than 01/03/2020\n" must_have_ibm_license=true flag_redhat_license=true @@ -111,27 +110,26 @@ for f in $FILES_TO_SCAN; do must_have_redhat_license=true fi - if [[ "${must_have_redhat_license}" == "true" ]] && [[ "$header" != *"${lic_redhat_identifier}"* ]]; then + if [[ ${must_have_redhat_license} == "true" ]] && [[ $header != *"${lic_redhat_identifier}"* ]]; then printf " Missing copyright\n >> Could not find [${lic_redhat_identifier}] in the file.\n" ERROR=1 fi - if [[ "${flag_redhat_license}" == "true" ]] && [[ "$header" == *"${lic_redhat_identifier}"* ]]; then + if [[ ${flag_redhat_license} == "true" ]] && [[ $header == *"${lic_redhat_identifier}"* ]]; then printf " Warning: Older file, may not include Red Hat license.\n" fi - if [[ "${flag_ibm_license}" == "true" ]] && [[ "$header" == *"${lic_ibm_identifier}"* ]]; then + if [[ ${flag_ibm_license} == "true" ]] && [[ $header == *"${lic_ibm_identifier}"* ]]; then printf " Warning: newer file, may not contain IBM license.\n" fi - if [[ "${must_have_ibm_license}" == "true" ]]; then + if [[ ${must_have_ibm_license} == "true" ]]; then # Verify IBM copyright is present #Check for year copyright single line year_line_count=0 - for ((i=0;i<${lic_year_size};i++)); - do + for ((i = 0; i < lic_year_size; i++)); do #Validate year formart within [origin_year, current_year] range - if [[ "$header" == *"${lic_year[$i]}"* ]]; then + if [[ $header == *"${lic_year[$i]}"* ]]; then year_line_count=$((year_line_count + 1)) fi done @@ -140,14 +138,13 @@ for f in $FILES_TO_SCAN; do if [[ $year_line_count != 1 ]]; then printf "Missing copyright\n >>Could not find correct copyright year in the file $f\n" ERROR=1 - #break + #break fi #Check for rest copyright lines - for ((i=0;i<${lic_rest_size};i++)); - do + for ((i = 0; i < lic_rest_size; i++)); do #Validate the copyright line being checked is present - if [[ "$header" != *"${lic_rest[$i]}"* ]]; then + if [[ $header != *"${lic_rest[$i]}"* ]]; then printf "Missing copyright\n >>Could not find [${lic_rest[$i]}] in the file $f\n" ERROR=1 #break 2 @@ -156,7 +153,7 @@ for f in $FILES_TO_SCAN; do fi # end must_have_ibm_license #Add a status message of OK, if all copyright lines are found - if [[ "$ERROR" == 0 ]]; then + if [[ $ERROR == 0 ]]; then printf "OK\n" else RETURNCODE=$ERROR diff --git a/cicd-scripts/customize-mco.sh b/cicd-scripts/customize-mco.sh index ecccda552..f24ec2c67 100755 --- a/cicd-scripts/customize-mco.sh +++ b/cicd-scripts/customize-mco.sh @@ -5,26 +5,29 @@ set -exo pipefail -ROOTDIR="$(cd "$(dirname "$0")/.." ; pwd -P)" +ROOTDIR="$( + cd "$(dirname "$0")/.." + pwd -P +)" export PATH=${PATH}:${ROOTDIR}/bin if [[ "$(uname)" == "Linux" ]]; then - SED_COMMAND='sed -i-e -e' + SED_COMMAND='sed -i-e -e' elif [[ "$(uname)" == "Darwin" ]]; then - SED_COMMAND='sed -i '-e' -e' + SED_COMMAND='sed -i '-e' -e' fi # Use snapshot for target release. Use latest one if no branch info detected, or not a release branch BRANCH="" LATEST_SNAPSHOT="" -if [[ "${PULL_BASE_REF}" == "release-"* ]]; then - BRANCH=${PULL_BASE_REF#"release-"} - BRANCH=$(curl https://quay.io//api/v1/repository/stolostron/multicluster-observability-operator | jq '.tags|with_entries(select(.key|contains("'${BRANCH}'")))|keys[length-1]' | awk -F '-' '{print $1}') - BRANCH="${BRANCH#\"}" - LATEST_SNAPSHOT=$(curl https://quay.io//api/v1/repository/stolostron/multicluster-observability-operator | jq '.tags|with_entries(select(.key|contains("'${BRANCH}'-SNAPSHOT")))|keys[length-1]') +if [[ ${PULL_BASE_REF} == "release-"* ]]; then + BRANCH=${PULL_BASE_REF#"release-"} + BRANCH=$(curl https://quay.io//api/v1/repository/stolostron/multicluster-observability-operator | jq '.tags|with_entries(select(.key|contains("'${BRANCH}'")))|keys[length-1]' | awk -F '-' '{print $1}') + BRANCH="${BRANCH#\"}" + LATEST_SNAPSHOT=$(curl https://quay.io//api/v1/repository/stolostron/multicluster-observability-operator | jq '.tags|with_entries(select(.key|contains("'${BRANCH}'-SNAPSHOT")))|keys[length-1]') fi -if [[ "${LATEST_SNAPSHOT}" == "null" ]] || [[ "${LATEST_SNAPSHOT}" == "" ]]; then - LATEST_SNAPSHOT=$(curl https://quay.io/api/v1/repository/stolostron/multicluster-observability-operator | jq '.tags|with_entries(select((.key|contains("SNAPSHOT"))and(.key|contains("9.9.0")|not)))|keys[length-1]') +if [[ ${LATEST_SNAPSHOT} == "null" ]] || [[ ${LATEST_SNAPSHOT} == "" ]]; then + LATEST_SNAPSHOT=$(curl https://quay.io/api/v1/repository/stolostron/multicluster-observability-operator | jq '.tags|with_entries(select((.key|contains("SNAPSHOT"))and(.key|contains("9.9.0")|not)))|keys[length-1]') fi # trim the leading and tailing quotes @@ -37,165 +40,171 @@ GINKGO_FOCUS="" IMAGE="" update_mco_cr() { - if [ "${OPENSHIFT_CI}" == "true" ]; then - # discard unstaged changes - cd ${ROOTDIR} && git checkout -- . - for component_name in ${CHANGED_COMPONENTS}; do - component_anno_name=$(echo ${component_name} | sed 's/-/_/g') - get_image ${component_name} - ${SED_COMMAND} "/annotations.*/a \ \ \ \ mco-${component_anno_name}-image: ${IMAGE}" ${ROOTDIR}/examples/mco/e2e/v1beta1/observability.yaml - ${SED_COMMAND} "/annotations.*/a \ \ \ \ mco-${component_anno_name}-image: ${IMAGE}" ${ROOTDIR}/examples/mco/e2e/v1beta2/observability.yaml - done - else - if [[ -n "${RBAC_QUERY_PROXY_IMAGE_REF}" ]]; then - ${SED_COMMAND} "/annotations.*/a \ \ \ \ mco-rbac_query_proxy-image: ${RBAC_QUERY_PROXY_IMAGE_REF}" ${ROOTDIR}/examples/mco/e2e/v1beta1/observability.yaml - ${SED_COMMAND} "/annotations.*/a \ \ \ \ mco-rbac_query_proxy-image: ${RBAC_QUERY_PROXY_IMAGE_REF}" ${ROOTDIR}/examples/mco/e2e/v1beta2/observability.yaml - fi - if [[ -n "${ENDPOINT_MONITORING_OPERATOR_IMAGE_REF}" ]]; then - ${SED_COMMAND} "/annotations.*/a \ \ \ \ mco-endpoint_monitoring_operator-image: ${ENDPOINT_MONITORING_OPERATOR_IMAGE_REF}" ${ROOTDIR}/examples/mco/e2e/v1beta1/observability.yaml - ${SED_COMMAND} "/annotations.*/a \ \ \ \ mco-endpoint_monitoring_operator-image: ${ENDPOINT_MONITORING_OPERATOR_IMAGE_REF}" ${ROOTDIR}/examples/mco/e2e/v1beta2/observability.yaml - fi - if [[ -n "${GRAFANA_DASHBOARD_LOADER_IMAGE_REF}" ]]; then - ${SED_COMMAND} "/annotations.*/a \ \ \ \ mco-grafana_dashboard_loader-image: ${GRAFANA_DASHBOARD_LOADER_IMAGE_REF}" ${ROOTDIR}/examples/mco/e2e/v1beta1/observability.yaml - ${SED_COMMAND} "/annotations.*/a \ \ \ \ mco-grafana_dashboard_loader-image: ${GRAFANA_DASHBOARD_LOADER_IMAGE_REF}" ${ROOTDIR}/examples/mco/e2e/v1beta2/observability.yaml - fi - if [[ -n "${METRICS_COLLECTOR_IMAGE_REF}" ]]; then - ${SED_COMMAND} "/annotations.*/a \ \ \ \ mco-metrics_collector-image: ${METRICS_COLLECTOR_IMAGE_REF}" ${ROOTDIR}/examples/mco/e2e/v1beta1/observability.yaml - ${SED_COMMAND} "/annotations.*/a \ \ \ \ mco-metrics_collector-image: ${METRICS_COLLECTOR_IMAGE_REF}" ${ROOTDIR}/examples/mco/e2e/v1beta2/observability.yaml - fi - if [[ -n "${OBSERVATORIUM_OPERATOR_IMAGE_REF}" ]]; then - ${SED_COMMAND} "/annotations.*/a \ \ \ \ mco-observatorium_operator-image: ${OBSERVATORIUM_OPERATOR_IMAGE_REF}" ${ROOTDIR}/examples/mco/e2e/v1beta1/observability.yaml - ${SED_COMMAND} "/annotations.*/a \ \ \ \ mco-metrics_collector-image: ${OBSERVATORIUM_OPERATOR_IMAGE_REF}" ${ROOTDIR}/examples/mco/e2e/v1beta2/observability.yaml - fi + if [ "${OPENSHIFT_CI}" == "true" ]; then + # discard unstaged changes + cd ${ROOTDIR} && git checkout -- . + for component_name in ${CHANGED_COMPONENTS}; do + component_anno_name=$(echo ${component_name} | sed 's/-/_/g') + get_image ${component_name} + ${SED_COMMAND} "/annotations.*/a \ \ \ \ mco-${component_anno_name}-image: ${IMAGE}" ${ROOTDIR}/examples/mco/e2e/v1beta1/observability.yaml + ${SED_COMMAND} "/annotations.*/a \ \ \ \ mco-${component_anno_name}-image: ${IMAGE}" ${ROOTDIR}/examples/mco/e2e/v1beta2/observability.yaml + done + else + if [[ -n ${RBAC_QUERY_PROXY_IMAGE_REF} ]]; then + ${SED_COMMAND} "/annotations.*/a \ \ \ \ mco-rbac_query_proxy-image: ${RBAC_QUERY_PROXY_IMAGE_REF}" ${ROOTDIR}/examples/mco/e2e/v1beta1/observability.yaml + ${SED_COMMAND} "/annotations.*/a \ \ \ \ mco-rbac_query_proxy-image: ${RBAC_QUERY_PROXY_IMAGE_REF}" ${ROOTDIR}/examples/mco/e2e/v1beta2/observability.yaml fi + if [[ -n ${ENDPOINT_MONITORING_OPERATOR_IMAGE_REF} ]]; then + ${SED_COMMAND} "/annotations.*/a \ \ \ \ mco-endpoint_monitoring_operator-image: ${ENDPOINT_MONITORING_OPERATOR_IMAGE_REF}" ${ROOTDIR}/examples/mco/e2e/v1beta1/observability.yaml + ${SED_COMMAND} "/annotations.*/a \ \ \ \ mco-endpoint_monitoring_operator-image: ${ENDPOINT_MONITORING_OPERATOR_IMAGE_REF}" ${ROOTDIR}/examples/mco/e2e/v1beta2/observability.yaml + fi + if [[ -n ${GRAFANA_DASHBOARD_LOADER_IMAGE_REF} ]]; then + ${SED_COMMAND} "/annotations.*/a \ \ \ \ mco-grafana_dashboard_loader-image: ${GRAFANA_DASHBOARD_LOADER_IMAGE_REF}" ${ROOTDIR}/examples/mco/e2e/v1beta1/observability.yaml + ${SED_COMMAND} "/annotations.*/a \ \ \ \ mco-grafana_dashboard_loader-image: ${GRAFANA_DASHBOARD_LOADER_IMAGE_REF}" ${ROOTDIR}/examples/mco/e2e/v1beta2/observability.yaml + fi + if [[ -n ${METRICS_COLLECTOR_IMAGE_REF} ]]; then + ${SED_COMMAND} "/annotations.*/a \ \ \ \ mco-metrics_collector-image: ${METRICS_COLLECTOR_IMAGE_REF}" ${ROOTDIR}/examples/mco/e2e/v1beta1/observability.yaml + ${SED_COMMAND} "/annotations.*/a \ \ \ \ mco-metrics_collector-image: ${METRICS_COLLECTOR_IMAGE_REF}" ${ROOTDIR}/examples/mco/e2e/v1beta2/observability.yaml + fi + if [[ -n ${OBSERVATORIUM_OPERATOR_IMAGE_REF} ]]; then + ${SED_COMMAND} "/annotations.*/a \ \ \ \ mco-observatorium_operator-image: ${OBSERVATORIUM_OPERATOR_IMAGE_REF}" ${ROOTDIR}/examples/mco/e2e/v1beta1/observability.yaml + ${SED_COMMAND} "/annotations.*/a \ \ \ \ mco-metrics_collector-image: ${OBSERVATORIUM_OPERATOR_IMAGE_REF}" ${ROOTDIR}/examples/mco/e2e/v1beta2/observability.yaml + fi + fi - # Add mco-imageTagSuffix annotation - ${SED_COMMAND} "/annotations.*/a \ \ \ \ mco-imageTagSuffix: ${LATEST_SNAPSHOT}" ${ROOTDIR}/examples/mco/e2e/v1beta1/observability.yaml - ${SED_COMMAND} "/annotations.*/a \ \ \ \ mco-imageTagSuffix: ${LATEST_SNAPSHOT}" ${ROOTDIR}/examples/mco/e2e/v1beta2/observability.yaml + # Add mco-imageTagSuffix annotation + ${SED_COMMAND} "/annotations.*/a \ \ \ \ mco-imageTagSuffix: ${LATEST_SNAPSHOT}" ${ROOTDIR}/examples/mco/e2e/v1beta1/observability.yaml + ${SED_COMMAND} "/annotations.*/a \ \ \ \ mco-imageTagSuffix: ${LATEST_SNAPSHOT}" ${ROOTDIR}/examples/mco/e2e/v1beta2/observability.yaml - # need to add this annotation due to KinD cluster resources are insufficient - if [[ -n "${IS_KIND_ENV}" ]]; then - ${SED_COMMAND} "/annotations.*/a \ \ \ \ mco-thanos-without-resources-requests: true" ${ROOTDIR}/examples/mco/e2e/v1beta1/observability.yaml - ${SED_COMMAND} "/annotations.*/a \ \ \ \ mco-thanos-without-resources-requests: true" ${ROOTDIR}/examples/mco/e2e/v1beta2/observability.yaml - fi + # need to add this annotation due to KinD cluster resources are insufficient + if [[ -n ${IS_KIND_ENV} ]]; then + ${SED_COMMAND} "/annotations.*/a \ \ \ \ mco-thanos-without-resources-requests: true" ${ROOTDIR}/examples/mco/e2e/v1beta1/observability.yaml + ${SED_COMMAND} "/annotations.*/a \ \ \ \ mco-thanos-without-resources-requests: true" ${ROOTDIR}/examples/mco/e2e/v1beta2/observability.yaml + fi } get_image() { - if [[ $1 = "rbac-query-proxy" ]]; then - IMAGE="${RBAC_QUERY_PROXY_IMAGE_REF}" - fi - if [[ $1 = "endpoint-monitoring-operator" ]]; then - IMAGE="${ENDPOINT_MONITORING_OPERATOR_IMAGE_REF}" - fi - if [[ $1 = "grafana-dashboard-loader" ]]; then - IMAGE="${GRAFANA_DASHBOARD_LOADER_IMAGE_REF}" - fi - if [[ $1 = "metrics-collector" ]]; then - IMAGE="${METRICS_COLLECTOR_IMAGE_REF}" - fi + if [[ $1 == "rbac-query-proxy" ]]; then + IMAGE="${RBAC_QUERY_PROXY_IMAGE_REF}" + fi + if [[ $1 == "endpoint-monitoring-operator" ]]; then + IMAGE="${ENDPOINT_MONITORING_OPERATOR_IMAGE_REF}" + fi + if [[ $1 == "grafana-dashboard-loader" ]]; then + IMAGE="${GRAFANA_DASHBOARD_LOADER_IMAGE_REF}" + fi + if [[ $1 == "metrics-collector" ]]; then + IMAGE="${METRICS_COLLECTOR_IMAGE_REF}" + fi } # function get_changed_components is used to get the component used to test # get_changed_components is to get the component name based on the changes in your PR get_changed_components() { - if [ "${OPENSHIFT_CI}" == "true" ]; then - changed_files=$(cd ${ROOTDIR}; git diff --name-only HEAD~1) - for file in ${changed_files}; do - if [[ ${file} =~ ^proxy ]]; then - CHANGED_COMPONENTS+=" rbac-query-proxy" - continue - fi - if [[ ${file} =~ ^operators/endpointmetrics || ${file} =~ ^operators/pkg ]]; then - CHANGED_COMPONENTS+=" endpoint-monitoring-operator" - continue - fi - if [[ ${file} =~ ^loaders/dashboards ]]; then - CHANGED_COMPONENTS+=" grafana-dashboard-loader" - continue - fi - if [[ ${file} =~ ^collectors/metrics ]]; then - CHANGED_COMPONENTS+=" metrics-collector" - continue - fi - if [[ ${file} =~ ^pkg ]]; then - CHANGED_COMPONENTS="rbac-query-proxy metrics-collector endpoint-monitoring-operator grafana-dashboard-loader" - break - fi - done - fi - # remove duplicates - CHANGED_COMPONENTS=$(echo "${CHANGED_COMPONENTS}" | xargs -n1 | sort -u | xargs) - echo "Tested components are ${CHANGED_COMPONENTS}" + if [ "${OPENSHIFT_CI}" == "true" ]; then + changed_files=$( + cd ${ROOTDIR} + git diff --name-only HEAD~1 + ) + for file in ${changed_files}; do + if [[ ${file} =~ ^proxy ]]; then + CHANGED_COMPONENTS+=" rbac-query-proxy" + continue + fi + if [[ ${file} =~ ^operators/endpointmetrics || ${file} =~ ^operators/pkg ]]; then + CHANGED_COMPONENTS+=" endpoint-monitoring-operator" + continue + fi + if [[ ${file} =~ ^loaders/dashboards ]]; then + CHANGED_COMPONENTS+=" grafana-dashboard-loader" + continue + fi + if [[ ${file} =~ ^collectors/metrics ]]; then + CHANGED_COMPONENTS+=" metrics-collector" + continue + fi + if [[ ${file} =~ ^pkg ]]; then + CHANGED_COMPONENTS="rbac-query-proxy metrics-collector endpoint-monitoring-operator grafana-dashboard-loader" + break + fi + done + fi + # remove duplicates + CHANGED_COMPONENTS=$(echo "${CHANGED_COMPONENTS}" | xargs -n1 | sort -u | xargs) + echo "Tested components are ${CHANGED_COMPONENTS}" } # function get_ginkgo_focus is to get the required cases get_ginkgo_focus() { - if [ "${OPENSHIFT_CI}" == "true" ]; then - changed_files=$(cd $ROOTDIR; git diff --name-only HEAD~1) - for file in ${changed_files}; do - if [[ ${file} =~ ^proxy ]]; then - GINKGO_FOCUS+=" --focus grafana/g0 --focus metrics/g0" - continue - fi - if [[ ${file} =~ ^collectors/metrics ]]; then - GINKGO_FOCUS+=" --focus grafana/g0 --focus metrics/g0 --focus addon/g0" - continue - fi - if [[ ${file} =~ ^operators/endpointmetrics ]]; then - GINKGO_FOCUS+=" --focus grafana/g0 --focus metrics/g0 --focus addon/g0 --focus endpoint_preserve/g0" - continue - fi - if [[ ${file} =~ ^loaders/dashboards ]]; then - GINKGO_FOCUS+=" --focus grafana/g0 --focus metrics/g0 --focus addon/g0" - continue - fi - if [[ $file =~ ^operators/multiclusterobservability ]]; then - GINKGO_FOCUS+=" --focus addon/g0 --focus config/g0 --focus alert/g0 --focus alertforward/g0 --focus certrenew/g0 --focus grafana/g0 --focus grafana_dev/g0 --focus dashboard/g0 --focus manifestwork/g0 --focus metrics/g0 --focus observatorium_preserve/g0 --focus reconcile/g0 --focus retention/g0 --focus export/g0" - continue - fi - if [[ $file =~ ^operators/pkg ]]; then - GINKGO_FOCUS+=" --focus addon/g0 --focus config/g0 --focus alert/g0 --focus alertforward/g0 --focus certrenew/g0 --focus grafana/g0 --focus grafana_dev/g0 --focus dashboard/g0 --focus manifestwork/g0 --focus metrics/g0 --focus observatorium_preserve/g0 --focus reconcile/g0 --focus retention/g0 --focus endpoint_preserve/g0 --focus export/g0" - continue - fi - if [[ ${file} =~ ^pkg ]]; then - # test all cases - GINKGO_FOCUS="" - break - fi - if [[ $file =~ ^examples/alerts ]]; then - GINKGO_FOCUS+=" --focus alert/g0 --focus alertforward/g0" - continue - fi - if [[ ${file} =~ ^examples/dashboards ]]; then - GINKGO_FOCUS+=" --focus dashboard/g0" - continue - fi - if [[ ${file} =~ ^examples/metrics ]]; then - GINKGO_FOCUS+=" --focus metrics/g0" - continue - fi - if [[ ${file} =~ ^tests ]]; then - GINKGO_FOCUS+=" --focus $(echo ${file} | cut -d '/' -f4 | sed -En 's/observability_(.*)_test.go/\1/p')/g0" - continue - fi - if [[ ${file} =~ ^tools ]]; then - GINKGO_FOCUS+=" --focus grafana_dev/g0" - continue - fi - done - fi + if [ "${OPENSHIFT_CI}" == "true" ]; then + changed_files=$( + cd $ROOTDIR + git diff --name-only HEAD~1 + ) + for file in ${changed_files}; do + if [[ ${file} =~ ^proxy ]]; then + GINKGO_FOCUS+=" --focus grafana/g0 --focus metrics/g0" + continue + fi + if [[ ${file} =~ ^collectors/metrics ]]; then + GINKGO_FOCUS+=" --focus grafana/g0 --focus metrics/g0 --focus addon/g0" + continue + fi + if [[ ${file} =~ ^operators/endpointmetrics ]]; then + GINKGO_FOCUS+=" --focus grafana/g0 --focus metrics/g0 --focus addon/g0 --focus endpoint_preserve/g0" + continue + fi + if [[ ${file} =~ ^loaders/dashboards ]]; then + GINKGO_FOCUS+=" --focus grafana/g0 --focus metrics/g0 --focus addon/g0" + continue + fi + if [[ $file =~ ^operators/multiclusterobservability ]]; then + GINKGO_FOCUS+=" --focus addon/g0 --focus config/g0 --focus alert/g0 --focus alertforward/g0 --focus certrenew/g0 --focus grafana/g0 --focus grafana_dev/g0 --focus dashboard/g0 --focus manifestwork/g0 --focus metrics/g0 --focus observatorium_preserve/g0 --focus reconcile/g0 --focus retention/g0 --focus export/g0" + continue + fi + if [[ $file =~ ^operators/pkg ]]; then + GINKGO_FOCUS+=" --focus addon/g0 --focus config/g0 --focus alert/g0 --focus alertforward/g0 --focus certrenew/g0 --focus grafana/g0 --focus grafana_dev/g0 --focus dashboard/g0 --focus manifestwork/g0 --focus metrics/g0 --focus observatorium_preserve/g0 --focus reconcile/g0 --focus retention/g0 --focus endpoint_preserve/g0 --focus export/g0" + continue + fi + if [[ ${file} =~ ^pkg ]]; then + # test all cases + GINKGO_FOCUS="" + break + fi + if [[ $file =~ ^examples/alerts ]]; then + GINKGO_FOCUS+=" --focus alert/g0 --focus alertforward/g0" + continue + fi + if [[ ${file} =~ ^examples/dashboards ]]; then + GINKGO_FOCUS+=" --focus dashboard/g0" + continue + fi + if [[ ${file} =~ ^examples/metrics ]]; then + GINKGO_FOCUS+=" --focus metrics/g0" + continue + fi + if [[ ${file} =~ ^tests ]]; then + GINKGO_FOCUS+=" --focus $(echo ${file} | cut -d '/' -f4 | sed -En 's/observability_(.*)_test.go/\1/p')/g0" + continue + fi + if [[ ${file} =~ ^tools ]]; then + GINKGO_FOCUS+=" --focus grafana_dev/g0" + continue + fi + done + fi - if [[ -n "${IS_KIND_ENV}" ]]; then - # For KinD cluster, do not need to run all test cases - GINKGO_FOCUS=" --focus manifestwork/g0 --focus endpoint_preserve/g0 --focus grafana/g0 --focus metrics/g0 --focus addon/g0 --focus alert/g0 --focus dashboard/g0" - else - GINKGO_FOCUS=$(echo "${GINKGO_FOCUS}" | xargs -n2 | sort -u | xargs) - fi - echo "Test focuses are ${GINKGO_FOCUS}" + if [[ -n ${IS_KIND_ENV} ]]; then + # For KinD cluster, do not need to run all test cases + GINKGO_FOCUS=" --focus manifestwork/g0 --focus endpoint_preserve/g0 --focus grafana/g0 --focus metrics/g0 --focus addon/g0 --focus alert/g0 --focus dashboard/g0" + else + GINKGO_FOCUS=$(echo "${GINKGO_FOCUS}" | xargs -n2 | sort -u | xargs) + fi + echo "Test focuses are ${GINKGO_FOCUS}" } # start executing get_changed_components update_mco_cr get_ginkgo_focus -echo "${GINKGO_FOCUS}" > /tmp/ginkgo_focus +echo "${GINKGO_FOCUS}" >/tmp/ginkgo_focus diff --git a/cicd-scripts/deploy-to-cluster.sh b/cicd-scripts/deploy-to-cluster.sh index 6ede6dcc8..31b5b0dd2 100755 --- a/cicd-scripts/deploy-to-cluster.sh +++ b/cicd-scripts/deploy-to-cluster.sh @@ -1,4 +1,4 @@ # Copyright (c) 2021 Red Hat, Inc. # Copyright Contributors to the Open Cluster Management project -echo "DEPLOY TO CLUSTER GOES HERE! IT SHOULD DO NOTHING RIGHT NOW!" \ No newline at end of file +echo "DEPLOY TO CLUSTER GOES HERE! IT SHOULD DO NOTHING RIGHT NOW!" diff --git a/cicd-scripts/install-dependencies.sh b/cicd-scripts/install-dependencies.sh index 344c7ab45..ae24bc928 100755 --- a/cicd-scripts/install-dependencies.sh +++ b/cicd-scripts/install-dependencies.sh @@ -7,11 +7,11 @@ echo "install dependencies" _OPERATOR_SDK_VERSION=v1.4.2 if ! [ -x "$(command -v operator-sdk)" ]; then - if [[ "$OSTYPE" == "linux-gnu" ]]; then - curl -L https://github.com/operator-framework/operator-sdk/releases/download/${_OPERATOR_SDK_VERSION}/operator-sdk_linux_amd64 -o operator-sdk - elif [[ "$OSTYPE" == "darwin"* ]]; then - curl -L https://github.com/operator-framework/operator-sdk/releases/download/${_OPERATOR_SDK_VERSION}/operator-sdk_darwin_amd64 -o operator-sdk - fi - chmod +x operator-sdk - sudo mv operator-sdk /usr/local/bin/operator-sdk + if [[ $OSTYPE == "linux-gnu" ]]; then + curl -L https://github.com/operator-framework/operator-sdk/releases/download/${_OPERATOR_SDK_VERSION}/operator-sdk_linux_amd64 -o operator-sdk + elif [[ $OSTYPE == "darwin"* ]]; then + curl -L https://github.com/operator-framework/operator-sdk/releases/download/${_OPERATOR_SDK_VERSION}/operator-sdk_darwin_amd64 -o operator-sdk + fi + chmod +x operator-sdk + sudo mv operator-sdk /usr/local/bin/operator-sdk fi diff --git a/cicd-scripts/run-e2e-in-kind-via-prow.sh b/cicd-scripts/run-e2e-in-kind-via-prow.sh index d641ea16e..9e3b4d9d2 100755 --- a/cicd-scripts/run-e2e-in-kind-via-prow.sh +++ b/cicd-scripts/run-e2e-in-kind-via-prow.sh @@ -16,27 +16,27 @@ OPT=(-q -o "UserKnownHostsFile=/dev/null" -o "StrictHostKeyChecking=no" -i "${KE SED_COMMAND='sed -i-e -e' if [ "${OPENSHIFT_CI}" == "true" ]; then - ${SED_COMMAND} "$ a\export OPENSHIFT_CI=${OPENSHIFT_CI}" ./tests/run-in-kind/env.sh + ${SED_COMMAND} "$ a\export OPENSHIFT_CI=${OPENSHIFT_CI}" ./tests/run-in-kind/env.sh fi -if [[ -n "${PULL_BASE_REF}" ]]; then - ${SED_COMMAND} "$ a\export PULL_BASE_REF=${PULL_BASE_REF}" ./tests/run-in-kind/env.sh +if [[ -n ${PULL_BASE_REF} ]]; then + ${SED_COMMAND} "$ a\export PULL_BASE_REF=${PULL_BASE_REF}" ./tests/run-in-kind/env.sh fi -if [[ -n "${MULTICLUSTER_OBSERVABILITY_OPERATOR_IMAGE_REF}" ]]; then - ${SED_COMMAND} "$ a\export MULTICLUSTER_OBSERVABILITY_OPERATOR_IMAGE_REF=${MULTICLUSTER_OBSERVABILITY_OPERATOR_IMAGE_REF}" ./tests/run-in-kind/env.sh +if [[ -n ${MULTICLUSTER_OBSERVABILITY_OPERATOR_IMAGE_REF} ]]; then + ${SED_COMMAND} "$ a\export MULTICLUSTER_OBSERVABILITY_OPERATOR_IMAGE_REF=${MULTICLUSTER_OBSERVABILITY_OPERATOR_IMAGE_REF}" ./tests/run-in-kind/env.sh fi -if [[ -n "${ENDPOINT_MONITORING_OPERATOR_IMAGE_REF}" ]]; then - ${SED_COMMAND} "$ a\export ENDPOINT_MONITORING_OPERATOR_IMAGE_REF=${ENDPOINT_MONITORING_OPERATOR_IMAGE_REF}" ./tests/run-in-kind/env.sh +if [[ -n ${ENDPOINT_MONITORING_OPERATOR_IMAGE_REF} ]]; then + ${SED_COMMAND} "$ a\export ENDPOINT_MONITORING_OPERATOR_IMAGE_REF=${ENDPOINT_MONITORING_OPERATOR_IMAGE_REF}" ./tests/run-in-kind/env.sh fi -if [[ -n "${GRAFANA_DASHBOARD_LOADER_IMAGE_REF}" ]]; then - ${SED_COMMAND} "$ a\export GRAFANA_DASHBOARD_LOADER_IMAGE_REF=${GRAFANA_DASHBOARD_LOADER_IMAGE_REF}" ./tests/run-in-kind/env.sh +if [[ -n ${GRAFANA_DASHBOARD_LOADER_IMAGE_REF} ]]; then + ${SED_COMMAND} "$ a\export GRAFANA_DASHBOARD_LOADER_IMAGE_REF=${GRAFANA_DASHBOARD_LOADER_IMAGE_REF}" ./tests/run-in-kind/env.sh fi -if [[ -n "${METRICS_COLLECTOR_IMAGE_REF}" ]]; then - ${SED_COMMAND} "$ a\export METRICS_COLLECTOR_IMAGE_REF=${METRICS_COLLECTOR_IMAGE_REF}" ./tests/run-in-kind/env.sh +if [[ -n ${METRICS_COLLECTOR_IMAGE_REF} ]]; then + ${SED_COMMAND} "$ a\export METRICS_COLLECTOR_IMAGE_REF=${METRICS_COLLECTOR_IMAGE_REF}" ./tests/run-in-kind/env.sh fi -if [[ -n "${RBAC_QUERY_PROXY_IMAGE_REF}" ]]; then - ${SED_COMMAND} "$ a\export RBAC_QUERY_PROXY_IMAGE_REF=${RBAC_QUERY_PROXY_IMAGE_REF}" ./tests/run-in-kind/env.sh +if [[ -n ${RBAC_QUERY_PROXY_IMAGE_REF} ]]; then + ${SED_COMMAND} "$ a\export RBAC_QUERY_PROXY_IMAGE_REF=${RBAC_QUERY_PROXY_IMAGE_REF}" ./tests/run-in-kind/env.sh fi ssh "${OPT[@]}" "$HOST" sudo yum install gcc git -y diff --git a/cicd-scripts/run-e2e-tests.sh b/cicd-scripts/run-e2e-tests.sh index e306769fa..a9e6967ee 100755 --- a/cicd-scripts/run-e2e-tests.sh +++ b/cicd-scripts/run-e2e-tests.sh @@ -7,11 +7,14 @@ set -x -ROOTDIR="$(cd "$(dirname "$0")/.." ; pwd -P)" +ROOTDIR="$( + cd "$(dirname "$0")/.." + pwd -P +)" SED_COMMAND='sed -i -e' if [[ "$(uname)" == "Darwin" ]]; then - SED_COMMAND='sed -i '-e' -e' + SED_COMMAND='sed -i '-e' -e' fi # customize the images for testing @@ -19,89 +22,89 @@ ${ROOTDIR}/cicd-scripts/customize-mco.sh GINKGO_FOCUS="$(cat /tmp/ginkgo_focus)" # need to modify sc for KinD -if [[ -n "${IS_KIND_ENV}" ]]; then - ${SED_COMMAND} "s~gp3-csi$~standard~g" ${ROOTDIR}/examples/minio/minio-pvc.yaml - ${SED_COMMAND} "s~gp3-csi$~standard~g" ${ROOTDIR}/examples/minio-tls/minio-pvc.yaml +if [[ -n ${IS_KIND_ENV} ]]; then + ${SED_COMMAND} "s~gp3-csi$~standard~g" ${ROOTDIR}/examples/minio/minio-pvc.yaml + ${SED_COMMAND} "s~gp3-csi$~standard~g" ${ROOTDIR}/examples/minio-tls/minio-pvc.yaml fi kubeconfig_hub_path="" if [ ! -z "${SHARED_DIR}" ]; then - export KUBECONFIG="${SHARED_DIR}/hub-1.kc" - kubeconfig_hub_path="${SHARED_DIR}/hub-1.kc" + export KUBECONFIG="${SHARED_DIR}/hub-1.kc" + kubeconfig_hub_path="${SHARED_DIR}/hub-1.kc" else - # for local testing - if [ -z "${KUBECONFIG}" ]; then - echo "Error: environment variable KUBECONFIG must be specified!" - exit 1 - fi - kubeconfig_hub_path="${HOME}/.kube/kubeconfig-hub" - kubectl config view --raw --minify > ${kubeconfig_hub_path} + # for local testing + if [ -z "${KUBECONFIG}" ]; then + echo "Error: environment variable KUBECONFIG must be specified!" + exit 1 + fi + kubeconfig_hub_path="${HOME}/.kube/kubeconfig-hub" + kubectl config view --raw --minify >${kubeconfig_hub_path} fi kubecontext=$(kubectl config current-context) cluster_name="local-cluster" -if [[ -n "${IS_KIND_ENV}" ]]; then - clusterServerURL="https://127.0.0.1:32806" - base_domain="placeholder" +if [[ -n ${IS_KIND_ENV} ]]; then + clusterServerURL="https://127.0.0.1:32806" + base_domain="placeholder" else - clusterServerURL=$(kubectl config view -o jsonpath="{.clusters[0].cluster.server}") - app_domain=$(kubectl -n openshift-ingress-operator get ingresscontrollers default -ojsonpath='{.status.domain}') - base_domain="${app_domain#apps.}" - kubectl apply -f ${ROOTDIR}/operators/multiclusterobservability/config/crd/bases + clusterServerURL=$(kubectl config view -o jsonpath="{.clusters[0].cluster.server}") + app_domain=$(kubectl -n openshift-ingress-operator get ingresscontrollers default -ojsonpath='{.status.domain}') + base_domain="${app_domain#apps.}" + kubectl apply -f ${ROOTDIR}/operators/multiclusterobservability/config/crd/bases fi OPTIONSFILE=${ROOTDIR}/tests/resources/options.yaml # remove the options file if it exists rm -f ${OPTIONSFILE} -printf "options:" >> ${OPTIONSFILE} -printf "\n kubeconfig: ${kubeconfig_hub_path}" >> ${OPTIONSFILE} -printf "\n hub:" >> ${OPTIONSFILE} -printf "\n clusterServerURL: ${clusterServerURL}" >> ${OPTIONSFILE} -printf "\n kubeconfig: ${kubeconfig_hub_path}" >> ${OPTIONSFILE} -printf "\n kubecontext: ${kubecontext}" >> ${OPTIONSFILE} -printf "\n baseDomain: ${base_domain}" >> ${OPTIONSFILE} -if [[ -n "${IS_KIND_ENV}" ]]; then - printf "\n grafanaURL: http://127.0.0.1:31001" >> ${OPTIONSFILE} - printf "\n grafanaHost: grafana-test" >> ${OPTIONSFILE} +printf "options:" >>${OPTIONSFILE} +printf "\n kubeconfig: ${kubeconfig_hub_path}" >>${OPTIONSFILE} +printf "\n hub:" >>${OPTIONSFILE} +printf "\n clusterServerURL: ${clusterServerURL}" >>${OPTIONSFILE} +printf "\n kubeconfig: ${kubeconfig_hub_path}" >>${OPTIONSFILE} +printf "\n kubecontext: ${kubecontext}" >>${OPTIONSFILE} +printf "\n baseDomain: ${base_domain}" >>${OPTIONSFILE} +if [[ -n ${IS_KIND_ENV} ]]; then + printf "\n grafanaURL: http://127.0.0.1:31001" >>${OPTIONSFILE} + printf "\n grafanaHost: grafana-test" >>${OPTIONSFILE} fi -printf "\n clusters:" >> ${OPTIONSFILE} -printf "\n - name: ${cluster_name}" >> ${OPTIONSFILE} -if [[ -n "${IS_KIND_ENV}" ]]; then - printf "\n clusterServerURL: ${clusterServerURL}" >> ${OPTIONSFILE} +printf "\n clusters:" >>${OPTIONSFILE} +printf "\n - name: ${cluster_name}" >>${OPTIONSFILE} +if [[ -n ${IS_KIND_ENV} ]]; then + printf "\n clusterServerURL: ${clusterServerURL}" >>${OPTIONSFILE} fi -printf "\n baseDomain: ${base_domain}" >> ${OPTIONSFILE} -printf "\n kubeconfig: ${kubeconfig_hub_path}" >> ${OPTIONSFILE} -printf "\n kubecontext: ${kubecontext}" >> ${OPTIONSFILE} +printf "\n baseDomain: ${base_domain}" >>${OPTIONSFILE} +printf "\n kubeconfig: ${kubeconfig_hub_path}" >>${OPTIONSFILE} +printf "\n kubecontext: ${kubecontext}" >>${OPTIONSFILE} -if command -v ginkgo &> /dev/null; then - GINKGO_CMD=ginkgo +if command -v ginkgo &>/dev/null; then + GINKGO_CMD=ginkgo else - # just for Prow KinD vm - # uninstall old go version(1.16) and install new version - wget https://go.dev/dl/go1.20.4.linux-amd64.tar.gz - if command -v sudo >/dev/null 2>&1; then - sudo rm -fr /usr/local/go - sudo tar -C /usr/local -xzf go1.20.4.linux-amd64.tar.gz - # else - # rm -fr /usr/local/go - # tar -C /usr/local -xzf go1.20.4.linux-amd64.tar.gz - fi - go install github.com/onsi/ginkgo/ginkgo@latest - GINKGO_CMD="$(go env GOPATH)/bin/ginkgo" + # just for Prow KinD vm + # uninstall old go version(1.16) and install new version + wget https://go.dev/dl/go1.20.4.linux-amd64.tar.gz + if command -v sudo >/dev/null 2>&1; then + sudo rm -fr /usr/local/go + sudo tar -C /usr/local -xzf go1.20.4.linux-amd64.tar.gz + # else + # rm -fr /usr/local/go + # tar -C /usr/local -xzf go1.20.4.linux-amd64.tar.gz + fi + go install github.com/onsi/ginkgo/ginkgo@latest + GINKGO_CMD="$(go env GOPATH)/bin/ginkgo" fi go mod vendor ${GINKGO_CMD} -debug -trace ${GINKGO_FOCUS} -v ${ROOTDIR}/tests/pkg/tests -- -options=${OPTIONSFILE} -v=5 - + cat ${ROOTDIR}/tests/pkg/tests/results.xml | grep failures=\"0\" | grep errors=\"0\" if [ $? -ne 0 ]; then - echo "Cannot pass all test cases." - cat ${ROOTDIR}/tests/pkg/tests/results.xml - # The underlying cluster is still deleted. Setting large timeout won't help - # echo "sleeping for 60 min" - # sleep 3600 - # echo "waking up from sleep" - exit 1 + echo "Cannot pass all test cases." + cat ${ROOTDIR}/tests/pkg/tests/results.xml + # The underlying cluster is still deleted. Setting large timeout won't help + # echo "sleeping for 60 min" + # sleep 3600 + # echo "waking up from sleep" + exit 1 fi diff --git a/cicd-scripts/run-unit-tests.sh b/cicd-scripts/run-unit-tests.sh index 66648121e..cfa21ba91 100755 --- a/cicd-scripts/run-unit-tests.sh +++ b/cicd-scripts/run-unit-tests.sh @@ -6,4 +6,4 @@ echo "/: : $1" git config --global url."https://$GITHUB_TOKEN@github.com/stolostron".insteadOf "https://github.com/stolostron" -go test ./... \ No newline at end of file +go test ./... diff --git a/cicd-scripts/setup-e2e-tests.sh b/cicd-scripts/setup-e2e-tests.sh index 6300eaffd..f8820ae2c 100755 --- a/cicd-scripts/setup-e2e-tests.sh +++ b/cicd-scripts/setup-e2e-tests.sh @@ -7,12 +7,15 @@ set -exo pipefail -if [[ -z "${KUBECONFIG}" ]]; then +if [[ -z ${KUBECONFIG} ]]; then echo "Error: environment variable KUBECONFIG must be specified!" exit 1 fi -ROOTDIR="$(cd "$(dirname "$0")/.." ; pwd -P)" +ROOTDIR="$( + cd "$(dirname "$0")/.." + pwd -P +)" # Create bin directory and add it to PATH mkdir -p ${ROOTDIR}/bin export PATH=${PATH}:${ROOTDIR}/bin @@ -26,28 +29,28 @@ export MANAGED_CLUSTER="local-cluster" # registration-operator needs this SED_COMMAND='sed -i-e -e' if [[ "$(uname)" == "Darwin" ]]; then - SED_COMMAND='sed -i '-e' -e' + SED_COMMAND='sed -i '-e' -e' fi # install jq -if ! command -v jq &> /dev/null; then - if [[ "$(uname)" == "Linux" ]]; then - curl -o jq -L https://github.com/stedolan/jq/releases/download/jq-1.6/jq-linux64 - elif [[ "$(uname)" == "Darwin" ]]; then - curl -o jq -L https://github.com/stedolan/jq/releases/download/jq-1.6/jq-osx-amd64 - fi - chmod +x ./jq && mv ./jq ${ROOTDIR}/bin/jq +if ! command -v jq &>/dev/null; then + if [[ "$(uname)" == "Linux" ]]; then + curl -o jq -L https://github.com/stedolan/jq/releases/download/jq-1.6/jq-linux64 + elif [[ "$(uname)" == "Darwin" ]]; then + curl -o jq -L https://github.com/stedolan/jq/releases/download/jq-1.6/jq-osx-amd64 + fi + chmod +x ./jq && mv ./jq ${ROOTDIR}/bin/jq fi # Use snapshot for target release. Use latest one if no branch info detected, or not a release branch BRANCH="" LATEST_SNAPSHOT="" -if [[ "${PULL_BASE_REF}" == "release-"* ]]; then - BRANCH=${PULL_BASE_REF#"release-"} - LATEST_SNAPSHOT=`curl https://quay.io//api/v1/repository/open-cluster-management/multicluster-observability-operator | jq '.tags|with_entries(select(.key|test("'${BRANCH}'.*-SNAPSHOT-*")))|keys[length-1]'` +if [[ ${PULL_BASE_REF} == "release-"* ]]; then + BRANCH=${PULL_BASE_REF#"release-"} + LATEST_SNAPSHOT=$(curl https://quay.io//api/v1/repository/open-cluster-management/multicluster-observability-operator | jq '.tags|with_entries(select(.key|test("'${BRANCH}'.*-SNAPSHOT-*")))|keys[length-1]') fi -if [[ "${LATEST_SNAPSHOT}" == "null" ]] || [[ "${LATEST_SNAPSHOT}" == "" ]]; then - LATEST_SNAPSHOT=$(curl https://quay.io/api/v1/repository/stolostron/multicluster-observability-operator | jq '.tags|with_entries(select((.key|contains("SNAPSHOT"))and(.key|contains("9.9.0")|not)))|keys[length-1]') +if [[ ${LATEST_SNAPSHOT} == "null" ]] || [[ ${LATEST_SNAPSHOT} == "" ]]; then + LATEST_SNAPSHOT=$(curl https://quay.io/api/v1/repository/stolostron/multicluster-observability-operator | jq '.tags|with_entries(select((.key|contains("SNAPSHOT"))and(.key|contains("9.9.0")|not)))|keys[length-1]') fi # trim the leading and tailing quotes @@ -55,108 +58,108 @@ LATEST_SNAPSHOT="${LATEST_SNAPSHOT#\"}" LATEST_SNAPSHOT="${LATEST_SNAPSHOT%\"}" # install kubectl -if ! command -v kubectl &> /dev/null; then - echo "This script will install kubectl (https://kubernetes.io/docs/tasks/tools/install-kubectl/) on your machine" - if [[ "$(uname)" == "Linux" ]]; then - curl -LO https://dl.k8s.io/release/v1.28.2/bin/linux/amd64/kubectl - elif [[ "$(uname)" == "Darwin" ]]; then - curl -LO curl -LO "https://dl.k8s.io/release/v1.28.2/bin/darwin/arm64/kubectl" - fi - chmod +x ./kubectl && mv ./kubectl ${ROOTDIR}/bin/kubectl +if ! command -v kubectl &>/dev/null; then + echo "This script will install kubectl (https://kubernetes.io/docs/tasks/tools/install-kubectl/) on your machine" + if [[ "$(uname)" == "Linux" ]]; then + curl -LO https://dl.k8s.io/release/v1.28.2/bin/linux/amd64/kubectl + elif [[ "$(uname)" == "Darwin" ]]; then + curl -LO curl -LO "https://dl.k8s.io/release/v1.28.2/bin/darwin/arm64/kubectl" + fi + chmod +x ./kubectl && mv ./kubectl ${ROOTDIR}/bin/kubectl fi # install kustomize -if ! command -v kustomize &> /dev/null; then - echo "This script will install kustomize (sigs.k8s.io/kustomize/kustomize) on your machine" - if [[ "$(uname)" == "Linux" ]]; then - curl -o kustomize_v5.1.1.tar.gz -L https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize%2Fv5.1.1/kustomize_v5.1.1_linux_amd64.tar.gz - elif [[ "$(uname)" == "Darwin" ]]; then - curl -o kustomize_v5.1.1.tar.gz -L https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize%2Fv5.1.1/kustomize_v5.1.1_darwin_amd64.tar.gz - fi - tar xzvf kustomize_v5.1.1.tar.gz - chmod +x ./kustomize && mv ./kustomize ${ROOTDIR}/bin/kustomize +if ! command -v kustomize &>/dev/null; then + echo "This script will install kustomize (sigs.k8s.io/kustomize/kustomize) on your machine" + if [[ "$(uname)" == "Linux" ]]; then + curl -o kustomize_v5.1.1.tar.gz -L https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize%2Fv5.1.1/kustomize_v5.1.1_linux_amd64.tar.gz + elif [[ "$(uname)" == "Darwin" ]]; then + curl -o kustomize_v5.1.1.tar.gz -L https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize%2Fv5.1.1/kustomize_v5.1.1_darwin_amd64.tar.gz + fi + tar xzvf kustomize_v5.1.1.tar.gz + chmod +x ./kustomize && mv ./kustomize ${ROOTDIR}/bin/kustomize fi # deploy the hub and spoke core via OLM deploy_hub_spoke_core() { - cd ${ROOTDIR} - if [[ -d "registration-operator" ]]; then - rm -rf registration-operator - fi - git clone --depth 1 -b release-2.4 https://github.com/stolostron/registration-operator.git && cd registration-operator - ${SED_COMMAND} "s~clusterName: cluster1$~clusterName: ${MANAGED_CLUSTER}~g" deploy/klusterlet/config/samples/operator_open-cluster-management_klusterlets.cr.yaml - # deploy hub and spoke via OLM - #REGISTRATION_LATEST_SNAPSHOT=$(curl https://quay.io/api/v1/repository/stolostron/registration | jq '.tags|with_entries(select(.key|test("'2.4'.*-SNAPSHOT-*")))|keys[length-1]') - REGISTRATION_LATEST_SNAPSHOT='2.4.9-SNAPSHOT-2022-11-17-20-19-31' - make cluster-ip IMAGE_REGISTRY=quay.io/stolostron IMAGE_TAG=${REGISTRATION_LATEST_SNAPSHOT} WORK_TAG=${REGISTRATION_LATEST_SNAPSHOT} REGISTRATION_TAG=${REGISTRATION_LATEST_SNAPSHOT} PLACEMENT_TAG=${REGISTRATION_LATEST_SNAPSHOT} - make deploy IMAGE_REGISTRY=quay.io/stolostron IMAGE_TAG=${REGISTRATION_LATEST_SNAPSHOT} WORK_TAG=${REGISTRATION_LATEST_SNAPSHOT} REGISTRATION_TAG=${REGISTRATION_LATEST_SNAPSHOT} PLACEMENT_TAG=${REGISTRATION_LATEST_SNAPSHOT} + cd ${ROOTDIR} + if [[ -d "registration-operator" ]]; then + rm -rf registration-operator + fi + git clone --depth 1 -b release-2.4 https://github.com/stolostron/registration-operator.git && cd registration-operator + ${SED_COMMAND} "s~clusterName: cluster1$~clusterName: ${MANAGED_CLUSTER}~g" deploy/klusterlet/config/samples/operator_open-cluster-management_klusterlets.cr.yaml + # deploy hub and spoke via OLM + #REGISTRATION_LATEST_SNAPSHOT=$(curl https://quay.io/api/v1/repository/stolostron/registration | jq '.tags|with_entries(select(.key|test("'2.4'.*-SNAPSHOT-*")))|keys[length-1]') + REGISTRATION_LATEST_SNAPSHOT='2.4.9-SNAPSHOT-2022-11-17-20-19-31' + make cluster-ip IMAGE_REGISTRY=quay.io/stolostron IMAGE_TAG=${REGISTRATION_LATEST_SNAPSHOT} WORK_TAG=${REGISTRATION_LATEST_SNAPSHOT} REGISTRATION_TAG=${REGISTRATION_LATEST_SNAPSHOT} PLACEMENT_TAG=${REGISTRATION_LATEST_SNAPSHOT} + make deploy IMAGE_REGISTRY=quay.io/stolostron IMAGE_TAG=${REGISTRATION_LATEST_SNAPSHOT} WORK_TAG=${REGISTRATION_LATEST_SNAPSHOT} REGISTRATION_TAG=${REGISTRATION_LATEST_SNAPSHOT} PLACEMENT_TAG=${REGISTRATION_LATEST_SNAPSHOT} - # wait until hub and spoke are ready - wait_for_deployment_ready 10 60s ${HUB_NS} cluster-manager-registration-controller cluster-manager-registration-webhook cluster-manager-work-webhook - wait_for_deployment_ready 10 60s ${AGENT_NS} klusterlet-registration-agent klusterlet-work-agent + # wait until hub and spoke are ready + wait_for_deployment_ready 10 60s ${HUB_NS} cluster-manager-registration-controller cluster-manager-registration-webhook cluster-manager-work-webhook + wait_for_deployment_ready 10 60s ${AGENT_NS} klusterlet-registration-agent klusterlet-work-agent } # approve the CSR for cluster join request approve_csr_joinrequest() { - echo "wait for CSR for cluster join reqest is created..." - for i in {1..60}; do - # TODO(morvencao): remove the hard-coded cluster label - csrs=$(kubectl get csr -lopen-cluster-management.io/cluster-name=${MANAGED_CLUSTER}) - if [[ ! -z ${csrs} ]]; then - csrnames=$(kubectl get csr -lopen-cluster-management.io/cluster-name=${MANAGED_CLUSTER} -o jsonpath={.items..metadata.name}) - for csrname in ${csrnames}; do - echo "approve CSR: ${csrname}" - kubectl certificate approve ${csrname} - done - break - fi - if [[ ${i} -eq 60 ]]; then - echo "timeout wait for CSR is created." - exit 1 - fi - echo "retrying in 10s..." - sleep 10 - done + echo "wait for CSR for cluster join reqest is created..." + for i in {1..60}; do + # TODO(morvencao): remove the hard-coded cluster label + csrs=$(kubectl get csr -lopen-cluster-management.io/cluster-name=${MANAGED_CLUSTER}) + if [[ -n ${csrs} ]]; then + csrnames=$(kubectl get csr -lopen-cluster-management.io/cluster-name=${MANAGED_CLUSTER} -o jsonpath={.items..metadata.name}) + for csrname in ${csrnames}; do + echo "approve CSR: ${csrname}" + kubectl certificate approve ${csrname} + done + break + fi + if [[ ${i} -eq 60 ]]; then + echo "timeout wait for CSR is created." + exit 1 + fi + echo "retrying in 10s..." + sleep 10 + done - for i in {1..20}; do - clusters=$(kubectl get managedcluster) - if [[ ! -z ${clusters} ]]; then - clusternames=$(kubectl get managedcluster -o jsonpath={.items..metadata.name}) - for clustername in ${clusternames}; do - echo "approve joinrequest for ${clustername}" - kubectl patch managedcluster ${clustername} --patch '{"spec":{"hubAcceptsClient":true}}' --type=merge - if [[ -n "${IS_KIND_ENV}" ]]; then - # update vendor label for KinD env - kubectl label managedcluster ${clustername} vendor- - kubectl label managedcluster ${clustername} vendor=GKE - fi - done - break + for i in {1..20}; do + clusters=$(kubectl get managedcluster) + if [[ -n ${clusters} ]]; then + clusternames=$(kubectl get managedcluster -o jsonpath={.items..metadata.name}) + for clustername in ${clusternames}; do + echo "approve joinrequest for ${clustername}" + kubectl patch managedcluster ${clustername} --patch '{"spec":{"hubAcceptsClient":true}}' --type=merge + if [[ -n ${IS_KIND_ENV} ]]; then + # update vendor label for KinD env + kubectl label managedcluster ${clustername} vendor- + kubectl label managedcluster ${clustername} vendor=GKE fi - if [[ ${i} -eq 20 ]]; then - echo "timeout wait for managedcluster is created." - exit 1 - fi - echo "retrying in 10s..." - sleep 10 - done + done + break + fi + if [[ ${i} -eq 20 ]]; then + echo "timeout wait for managedcluster is created." + exit 1 + fi + echo "retrying in 10s..." + sleep 10 + done } # deploy the grafana-test to check the dashboards from browsers deploy_grafana_test() { - cd ${ROOTDIR} - ${SED_COMMAND} "s~name: grafana$~name: grafana-test~g; s~app: multicluster-observability-grafana$~app: multicluster-observability-grafana-test~g; s~secretName: grafana-config$~secretName: grafana-config-test~g; s~secretName: grafana-datasources$~secretName: grafana-datasources-test~g; /MULTICLUSTEROBSERVABILITY_CR_NAME/d" operators/multiclusterobservability/manifests/base/grafana/deployment.yaml - ${SED_COMMAND} "s~image: quay.io/stolostron/grafana-dashboard-loader:.*$~image: ${IMAGE_REPO}/grafana-dashboard-loader:${LATEST_SNAPSHOT}~g" operators/multiclusterobservability/manifests/base/grafana/deployment.yaml - ${SED_COMMAND} "s~image: quay.io/stolostron/grafana:.*$~image: ${IMAGE_REPO}/grafana:${LATEST_SNAPSHOT}~g" operators/multiclusterobservability/manifests/base/grafana/deployment.yaml - ${SED_COMMAND} "s~replicas: 2$~replicas: 1~g" operators/multiclusterobservability/manifests/base/grafana/deployment.yaml - kubectl apply -f operators/multiclusterobservability/manifests/base/grafana/deployment.yaml - kubectl apply -f ${ROOTDIR}/tests/run-in-kind/grafana # create grafana-test svc, grafana-test config and datasource configmaps + cd ${ROOTDIR} + ${SED_COMMAND} "s~name: grafana$~name: grafana-test~g; s~app: multicluster-observability-grafana$~app: multicluster-observability-grafana-test~g; s~secretName: grafana-config$~secretName: grafana-config-test~g; s~secretName: grafana-datasources$~secretName: grafana-datasources-test~g; /MULTICLUSTEROBSERVABILITY_CR_NAME/d" operators/multiclusterobservability/manifests/base/grafana/deployment.yaml + ${SED_COMMAND} "s~image: quay.io/stolostron/grafana-dashboard-loader:.*$~image: ${IMAGE_REPO}/grafana-dashboard-loader:${LATEST_SNAPSHOT}~g" operators/multiclusterobservability/manifests/base/grafana/deployment.yaml + ${SED_COMMAND} "s~image: quay.io/stolostron/grafana:.*$~image: ${IMAGE_REPO}/grafana:${LATEST_SNAPSHOT}~g" operators/multiclusterobservability/manifests/base/grafana/deployment.yaml + ${SED_COMMAND} "s~replicas: 2$~replicas: 1~g" operators/multiclusterobservability/manifests/base/grafana/deployment.yaml + kubectl apply -f operators/multiclusterobservability/manifests/base/grafana/deployment.yaml + kubectl apply -f ${ROOTDIR}/tests/run-in-kind/grafana # create grafana-test svc, grafana-test config and datasource configmaps - if [[ -z "${IS_KIND_ENV}" ]]; then - # TODO(morvencao): remove the following two extra routes after after accessing metrics from grafana url with bearer token is supported - temp_route=$(mktemp -d /tmp/grafana.XXXXXXXXXX) - # install grafana-test route - cat << EOF > ${temp_route}/grafana-test-route.yaml + if [[ -z ${IS_KIND_ENV} ]]; then + # TODO(morvencao): remove the following two extra routes after after accessing metrics from grafana url with bearer token is supported + temp_route=$(mktemp -d /tmp/grafana.XXXXXXXXXX) + # install grafana-test route + cat <${temp_route}/grafana-test-route.yaml apiVersion: route.openshift.io/v1 kind: Route metadata: @@ -169,109 +172,108 @@ spec: name: grafana-test EOF - app_domain=$(kubectl -n openshift-ingress-operator get ingresscontrollers default -o jsonpath='{.status.domain}') - ${SED_COMMAND} "s~host: grafana-test$~host: grafana-test.${app_domain}~g" ${temp_route}/grafana-test-route.yaml - kubectl -n ${OBSERVABILITY_NS} apply -f ${temp_route}/grafana-test-route.yaml - fi + app_domain=$(kubectl -n openshift-ingress-operator get ingresscontrollers default -o jsonpath='{.status.domain}') + ${SED_COMMAND} "s~host: grafana-test$~host: grafana-test.${app_domain}~g" ${temp_route}/grafana-test-route.yaml + kubectl -n ${OBSERVABILITY_NS} apply -f ${temp_route}/grafana-test-route.yaml + fi } # deploy the MCO operator via the kustomize resources deploy_mco_operator() { - if [[ -n "${MULTICLUSTER_OBSERVABILITY_OPERATOR_IMAGE_REF}" ]]; then - cd ${ROOTDIR}/operators/multiclusterobservability/config/manager && kustomize edit set image quay.io/stolostron/multicluster-observability-operator=${MULTICLUSTER_OBSERVABILITY_OPERATOR_IMAGE_REF} - else - cd ${ROOTDIR}/operators/multiclusterobservability/config/manager && kustomize edit set image quay.io/stolostron/multicluster-observability-operator="${IMAGE_REPO}/multicluster-observability-operator:${LATEST_SNAPSHOT}" - fi - cd ${ROOTDIR} - kustomize build ${ROOTDIR}/operators/multiclusterobservability/config/default | kubectl apply -n ${OCM_DEFAULT_NS} -f - + if [[ -n ${MULTICLUSTER_OBSERVABILITY_OPERATOR_IMAGE_REF} ]]; then + cd ${ROOTDIR}/operators/multiclusterobservability/config/manager && kustomize edit set image quay.io/stolostron/multicluster-observability-operator=${MULTICLUSTER_OBSERVABILITY_OPERATOR_IMAGE_REF} + else + cd ${ROOTDIR}/operators/multiclusterobservability/config/manager && kustomize edit set image quay.io/stolostron/multicluster-observability-operator="${IMAGE_REPO}/multicluster-observability-operator:${LATEST_SNAPSHOT}" + fi + cd ${ROOTDIR} + kustomize build ${ROOTDIR}/operators/multiclusterobservability/config/default | kubectl apply -n ${OCM_DEFAULT_NS} -f - - # wait until mco is ready - wait_for_deployment_ready 10 60s ${OCM_DEFAULT_NS} multicluster-observability-operator - echo "mco operator is deployed successfully." + # wait until mco is ready + wait_for_deployment_ready 10 60s ${OCM_DEFAULT_NS} multicluster-observability-operator + echo "mco operator is deployed successfully." - kubectl create ns ${OBSERVABILITY_NS} || true + kubectl create ns ${OBSERVABILITY_NS} || true } # wait for MCO CR reaadiness with budget wait_for_observability_ready() { - echo "wait for mco is ready and running..." - retry_number=10 - timeout=60s - for (( i = 1; i <= ${retry_number}; i++ )) ; do + echo "wait for mco is ready and running..." + retry_number=10 + timeout=60s + for ((i = 1; i <= retry_number; i++)); do - if kubectl wait --timeout=${timeout} --for=condition=Ready mco/observability &> /dev/null; then - echo "Observability has been started up and is runing." - break - else - echo "timeout wait for mco are ready, retry in 10s...." - sleep 10 - continue - fi - if [[ ${i} -eq ${retry_number} ]]; then - echo "timeout wait for mco is ready." - exit 1 - fi - done + if kubectl wait --timeout=${timeout} --for=condition=Ready mco/observability &>/dev/null; then + echo "Observability has been started up and is running." + break + else + echo "timeout wait for mco are ready, retry in 10s...." + sleep 10 + continue + fi + if [[ ${i} -eq ${retry_number} ]]; then + echo "timeout wait for mco is ready." + exit 1 + fi + done } # wait until deployment are ready with budget wait_for_deployment_ready() { - if [[ -z "${1}" ]]; then - echo "retry number is empty, exiting..." + if [[ -z ${1} ]]; then + echo "retry number is empty, exiting..." + fi + retry_number=${1} + if [[ -z ${2} ]]; then + echo "timeout is empty, exiting..." + fi + timeout=${2} + if [[ -z ${3} ]]; then + echo "namespace is empty, exiting..." + exit 1 + fi + ns=${3} + if [[ -z ${4} ]]; then + echo "at least one deployment should be specified, exiting..." + exit 1 + fi + + echo "wait for deployment ${@:4} in namespace ${ns} are starting up and running..." + for ((i = 1; i <= retry_number; i++)); do + if ! kubectl get ns ${ns} &>/dev/null; then + echo "namespace ${ns} is not created, retry in 10s...." + sleep 10 + continue fi - retry_number=${1} - if [[ -z "${2}" ]]; then - echo "timeout is empty, exiting..." + + if ! kubectl -n ${ns} get deploy ${@:4} &>/dev/null; then + echo "deployment ${@:4} are not created yet, retry in 10s...." + sleep 10 + continue fi - timeout=${2} - if [[ -z "${3}" ]]; then - echo "namespace is empty, exiting..." - exit 1 + + if kubectl -n ${ns} wait --timeout=${timeout} --for=condition=Available deploy ${@:4} &>/dev/null; then + echo "deployment ${@:4} have been started up and are running." + break + else + echo "timeout wait for deployment ${@:4} are ready, retry in 10s...." + sleep 10 + continue fi - ns=${3} - if [[ -z "${4}" ]]; then - echo "at least one deployment should be specified, exiting..." - exit 1 + if [[ ${i} -eq ${retry_number} ]]; then + echo "timeout wait for deployment ${@:4} are ready." + exit 1 fi - - echo "wait for deployment ${@:4} in namespace ${ns} are starting up and running..." - for (( i = 1; i <= ${retry_number}; i++ )) ; do - if ! kubectl get ns ${ns} &> /dev/null; then - echo "namespace ${ns} is not created, retry in 10s...." - sleep 10 - continue - fi - - if ! kubectl -n ${ns} get deploy ${@:4} &> /dev/null; then - echo "deployment ${@:4} are not created yet, retry in 10s...." - sleep 10 - continue - fi - - if kubectl -n ${ns} wait --timeout=${timeout} --for=condition=Available deploy ${@:4} &> /dev/null; then - echo "deployment ${@:4} have been started up and are runing." - break - else - echo "timeout wait for deployment ${@:4} are ready, retry in 10s...." - sleep 10 - continue - fi - if [[ ${i} -eq ${retry_number} ]]; then - echo "timeout wait for deployment ${@:4} are ready." - exit 1 - fi - done + done } # function execute is the main routine to do the actual work execute() { - deploy_hub_spoke_core - approve_csr_joinrequest - deploy_mco_operator - deploy_grafana_test - echo "OCM and MCO are installed successfuly..." + deploy_hub_spoke_core + approve_csr_joinrequest + deploy_mco_operator + deploy_grafana_test + echo "OCM and MCO are installed successfully..." } # start executing the ACTION execute - diff --git a/cicd-scripts/update-check-mco-csv.sh b/cicd-scripts/update-check-mco-csv.sh index 2b9cf2e63..d8afe5618 100755 --- a/cicd-scripts/update-check-mco-csv.sh +++ b/cicd-scripts/update-check-mco-csv.sh @@ -16,11 +16,11 @@ extra_text=" - name: observatoria.core.observatorium.io kind: ObservabilityAddon displayName: ObservabilityAddon description: ObservabilityAddon is the Schema for the observabilityaddon API" -echo "$extra_text" > extra_text_tmp +echo "$extra_text" >extra_text_tmp sed_command='sed -i-e -e' if [[ "$(uname)" == "Darwin" ]]; then - sed_command='sed -i '-e' -e' + sed_command='sed -i '-e' -e' fi $sed_command 's/serviceAccountName: open-cluster-management:multicluster-observability-operator/serviceAccountName: multicluster-observability-operator/g' deploy/olm-catalog/multicluster-observability-operator/manifests/multicluster-observability-operator.clusterserviceversion.yaml @@ -30,25 +30,25 @@ rm -rf extra_text_tmp deploy/olm-catalog/multicluster-observability-operator/man # check if there is something needs to be committed diff deploy/req_crds/core.observatorium.io_observatoria.yaml deploy/olm-catalog/multicluster-observability-operator/manifests/core.observatorium.io_observatoria.yaml if [ $? -ne 0 ]; then - echo "Failed to check csv: should update observatorium CRD" - exit 1 + echo "Failed to check csv: should update observatorium CRD" + exit 1 fi diff deploy/req_crds/observability.open-cluster-management.io_observabilityaddon_crd.yaml deploy/olm-catalog/multicluster-observability-operator/manifests/observability.open-cluster-management.io_observabilityaddon_crd.yaml if [ $? -ne 0 ]; then - echo "Failed to check csv: should update observabilityaddon CRD" - exit 1 + echo "Failed to check csv: should update observabilityaddon CRD" + exit 1 fi diff deploy/crds/observability.open-cluster-management.io_multiclusterobservabilities_crd.yaml deploy/olm-catalog/multicluster-observability-operator/manifests/observability.open-cluster-management.io_multiclusterobservabilities_crd.yaml if [ $? -ne 0 ]; then - echo "Failed to check csv: should update multiclusterobservability CRD" - exit 1 + echo "Failed to check csv: should update multiclusterobservability CRD" + exit 1 fi if git diff --exit-code deploy/olm-catalog/multicluster-observability-operator/manifests/multicluster-observability-operator.clusterserviceversion.yaml; then - echo "Check csv successfully" + echo "Check csv successfully" else - echo "Failed to check csv" - exit 1 + echo "Failed to check csv" + exit 1 fi diff --git a/collectors/metrics/cmd/metrics-collector/main.go b/collectors/metrics/cmd/metrics-collector/main.go index 844839243..dd1d7b392 100644 --- a/collectors/metrics/cmd/metrics-collector/main.go +++ b/collectors/metrics/cmd/metrics-collector/main.go @@ -4,6 +4,7 @@ package main import ( "context" + "errors" "fmt" stdlog "log" "net" @@ -11,14 +12,18 @@ import ( "net/url" "os" "os/signal" + "regexp" "strings" "syscall" "time" - "github.com/go-kit/kit/log" - "github.com/go-kit/kit/log/level" + "github.com/go-kit/log" + "github.com/go-kit/log/level" "github.com/oklog/run" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/collectors" "github.com/prometheus/common/expfmt" + "github.com/prometheus/common/version" "github.com/spf13/cobra" "k8s.io/apimachinery/pkg/util/uuid" @@ -282,17 +287,30 @@ type Options struct { } func (o *Options) Run() error { - var g run.Group + metricsReg := prometheus.NewRegistry() + metricsReg.MustRegister( + version.NewCollector("metrics_collector"), + collectors.NewGoCollector( + collectors.WithGoCollectorRuntimeMetrics(collectors.GoRuntimeMetricsRule{Matcher: regexp.MustCompile("/.*")}), + ), + collectors.NewProcessCollector(collectors.ProcessCollectorOpts{}), + ) + + // Some packages still use default Register. Replace to have those metrics. + prometheus.DefaultRegisterer = metricsReg + err, cfg := initConfig(o) if err != nil { return err } + metrics := forwarder.NewWorkerMetrics(metricsReg) + cfg.Metrics = metrics worker, err := forwarder.New(*cfg) if err != nil { - return fmt.Errorf("failed to configure metrics collector: %v", err) + return fmt.Errorf("failed to configure metrics collector: %w", err) } logger.Log( @@ -339,14 +357,14 @@ func (o *Options) Run() error { handlers := http.NewServeMux() collectorhttp.DebugRoutes(handlers) collectorhttp.HealthRoutes(handlers) - collectorhttp.MetricRoutes(handlers) + collectorhttp.MetricRoutes(handlers, metricsReg) collectorhttp.ReloadRoutes(handlers, func() error { return worker.Reconfigure(*cfg) }) handlers.Handle("/federate", serveLastMetrics(o.Logger, worker)) l, err := net.Listen("tcp", o.Listen) if err != nil { - return fmt.Errorf("failed to listen: %v", err) + return fmt.Errorf("failed to listen: %w", err) } { @@ -366,7 +384,7 @@ func (o *Options) Run() error { } } - err = runMultiWorkers(o) + err = runMultiWorkers(o, cfg) if err != nil { return err } @@ -374,7 +392,7 @@ func (o *Options) Run() error { if len(o.CollectRules) != 0 { evaluator, err := collectrule.New(*cfg) if err != nil { - return fmt.Errorf("failed to configure collect rule evaluator: %v", err) + return fmt.Errorf("failed to configure collect rule evaluator: %w", err) } ctx, cancel := context.WithCancel(context.Background()) g.Add(func() error { @@ -388,7 +406,7 @@ func (o *Options) Run() error { return g.Run() } -func runMultiWorkers(o *Options) error { +func runMultiWorkers(o *Options, cfg *forwarder.Config) error { for i := 1; i < int(o.WorkerNum); i++ { opt := &Options{ From: o.From, @@ -425,9 +443,10 @@ func runMultiWorkers(o *Options) error { return err } + forwardCfg.Metrics = cfg.Metrics forwardWorker, err := forwarder.New(*forwardCfg) if err != nil { - return fmt.Errorf("failed to configure metrics collector: %v", err) + return fmt.Errorf("failed to configure metrics collector: %w", err) } ctx, cancel := context.WithCancel(context.Background()) @@ -442,7 +461,7 @@ func runMultiWorkers(o *Options) error { func initConfig(o *Options) (error, *forwarder.Config) { if len(o.From) == 0 { - return fmt.Errorf("you must specify a Prometheus server to federate from (e.g. http://localhost:9090)"), nil + return errors.New("you must specify a Prometheus server to federate from (e.g. http://localhost:9090)"), nil } for _, flag := range o.LabelFlag { @@ -472,7 +491,7 @@ func initConfig(o *Options) (error, *forwarder.Config) { from, err := url.Parse(o.From) if err != nil { - return fmt.Errorf("--from is not a valid URL: %v", err), nil + return fmt.Errorf("--from is not a valid URL: %w", err), nil } from.Path = strings.TrimRight(from.Path, "/") if len(from.Path) == 0 { @@ -481,7 +500,7 @@ func initConfig(o *Options) (error, *forwarder.Config) { fromQuery, err := url.Parse(o.FromQuery) if err != nil { - return fmt.Errorf("--from-query is not a valid URL: %v", err), nil + return fmt.Errorf("--from-query is not a valid URL: %w", err), nil } fromQuery.Path = strings.TrimRight(fromQuery.Path, "/") if len(fromQuery.Path) == 0 { @@ -492,12 +511,12 @@ func initConfig(o *Options) (error, *forwarder.Config) { if len(o.ToUpload) > 0 { toUpload, err = url.Parse(o.ToUpload) if err != nil { - return fmt.Errorf("--to-upload is not a valid URL: %v", err), nil + return fmt.Errorf("--to-upload is not a valid URL: %w", err), nil } } if toUpload == nil { - return fmt.Errorf("--to-upload must be specified"), nil + return errors.New("--to-upload must be specified"), nil } var transformer metricfamily.MultiTransformer @@ -575,7 +594,7 @@ func initConfig(o *Options) (error, *forwarder.Config) { } } -// serveLastMetrics retrieves the last set of metrics served +// serveLastMetrics retrieves the last set of metrics served. func serveLastMetrics(l log.Logger, worker *forwarder.Worker) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { if req.Method != "GET" { diff --git a/collectors/metrics/cmd/metrics-collector/main_test.go b/collectors/metrics/cmd/metrics-collector/main_test.go index 43b667bbb..cc1200022 100644 --- a/collectors/metrics/cmd/metrics-collector/main_test.go +++ b/collectors/metrics/cmd/metrics-collector/main_test.go @@ -6,8 +6,10 @@ import ( "testing" "time" - "github.com/go-kit/kit/log" - "github.com/go-kit/kit/log/level" + "github.com/go-kit/log" + "github.com/go-kit/log/level" + "github.com/prometheus/client_golang/prometheus" + "github.com/stolostron/multicluster-observability-operator/collectors/metrics/pkg/forwarder" "github.com/stolostron/multicluster-observability-operator/collectors/metrics/pkg/logger" ) @@ -41,7 +43,7 @@ func TestMultiWorkers(t *testing.T) { stdlog.SetOutput(log.NewStdlibAdapter(l)) opt.Logger = l - err := runMultiWorkers(opt) + err := runMultiWorkers(opt, &forwarder.Config{Metrics: forwarder.NewWorkerMetrics(prometheus.NewRegistry())}) if err != nil { t.Fatal(err) } diff --git a/collectors/metrics/pkg/collectrule/evaluator.go b/collectors/metrics/pkg/collectrule/evaluator.go index 7dc2feb40..841a7c1fd 100644 --- a/collectors/metrics/pkg/collectrule/evaluator.go +++ b/collectors/metrics/pkg/collectrule/evaluator.go @@ -14,7 +14,7 @@ import ( "sync" "time" - "github.com/go-kit/kit/log" + "github.com/go-kit/log" clientmodel "github.com/prometheus/client_model/go" "github.com/prometheus/prometheus/model/labels" @@ -83,7 +83,8 @@ func New(cfg forwarder.Config) (*Evaluator, error) { LimitBytes: cfg.LimitBytes, Transformer: cfg.Transformer, - Logger: cfg.Logger, + Logger: cfg.Logger, + Metrics: cfg.Metrics, } from := &url.URL{ Scheme: cfg.From.Scheme, @@ -106,7 +107,7 @@ func New(cfg forwarder.Config) (*Evaluator, error) { evaluator.interval = 30 * time.Second } - fromClient, err := forwarder.CreateFromClient(cfg, evaluator.interval, "evaluate_query", cfg.Logger) + fromClient, err := forwarder.CreateFromClient(cfg, cfg.Metrics, evaluator.interval, "evaluate_query", cfg.Logger) if err != nil { return nil, err } @@ -118,7 +119,7 @@ func New(cfg forwarder.Config) (*Evaluator, error) { func (e *Evaluator) Reconfigure(cfg forwarder.Config) error { evaluator, err := New(cfg) if err != nil { - return fmt.Errorf("failed to reconfigure: %v", err) + return fmt.Errorf("failed to reconfigure: %w", err) } e.lock.Lock() @@ -149,7 +150,7 @@ func (e *Evaluator) Run(ctx context.Context) { e.evaluate(ctx) select { - // If the context is cancelled, then we're done. + // If the context is canceled, then we're done. case <-ctx.Done(): return case <-time.After(wait): @@ -203,7 +204,7 @@ func startWorker() error { var err error forwardWorker, err = forwarder.New(config) if err != nil { - return fmt.Errorf("failed to configure forwarder for additional metrics: %v", err) + return fmt.Errorf("failed to configure forwarder for additional metrics: %w", err) } var ctx context.Context ctx, cancel = context.WithCancel(context.Background()) @@ -214,7 +215,7 @@ func startWorker() error { } else { err := forwardWorker.Reconfigure(config) if err != nil { - return fmt.Errorf("failed to reconfigure forwarder for additional metrics: %v", err) + return fmt.Errorf("failed to reconfigure forwarder for additional metrics: %w", err) } } diff --git a/collectors/metrics/pkg/forwarder/forwarder.go b/collectors/metrics/pkg/forwarder/forwarder.go index 8df3dfe4d..d12ceb57a 100644 --- a/collectors/metrics/pkg/forwarder/forwarder.go +++ b/collectors/metrics/pkg/forwarder/forwarder.go @@ -9,7 +9,6 @@ import ( "encoding/json" "errors" "fmt" - "io/ioutil" "net/http" "net/url" "os" @@ -17,9 +16,9 @@ import ( "sync" "time" - "github.com/go-kit/kit/log" - + "github.com/go-kit/log" "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" clientmodel "github.com/prometheus/client_model/go" metricshttp "github.com/stolostron/multicluster-observability-operator/collectors/metrics/pkg/http" @@ -34,31 +33,10 @@ const ( failedStatusReportMsg = "Failed to report status" ) -var ( - gaugeFederateSamples = prometheus.NewGauge(prometheus.GaugeOpts{ - Name: "federate_samples", - Help: "Tracks the number of samples per federation", - }) - gaugeFederateFilteredSamples = prometheus.NewGauge(prometheus.GaugeOpts{ - Name: "federate_filtered_samples", - Help: "Tracks the number of samples filtered per federation", - }) - gaugeFederateErrors = prometheus.NewGauge(prometheus.GaugeOpts{ - Name: "federate_errors", - Help: "The number of times forwarding federated metrics has failed", - }) -) - type RuleMatcher interface { MatchRules() []string } -func init() { - prometheus.MustRegister( - gaugeFederateErrors, gaugeFederateSamples, gaugeFederateFilteredSamples, - ) -} - // Config defines the parameters that can be used to configure a worker. // The only required field is `From`. type Config struct { @@ -89,6 +67,8 @@ type Config struct { Logger log.Logger SimulatedTimeseriesFile string + + Metrics *workerMetrics } // Worker represents a metrics forwarding agent. It collects metrics from a source URL and forwards them to a sink. @@ -115,9 +95,11 @@ type Worker struct { simulatedTimeseriesFile string status status.StatusReport + + metrics *workerMetrics } -func CreateFromClient(cfg Config, interval time.Duration, name string, +func CreateFromClient(cfg Config, metrics *workerMetrics, interval time.Duration, name string, logger log.Logger) (*metricsclient.Client, error) { fromTransport := metricsclient.DefaultTransport(logger, false) if len(cfg.FromCAFile) > 0 { @@ -128,11 +110,11 @@ func CreateFromClient(cfg Config, interval time.Duration, name string, } pool, err := x509.SystemCertPool() if err != nil { - return nil, fmt.Errorf("failed to read system certificates: %v", err) + return nil, fmt.Errorf("failed to read system certificates: %w", err) } - data, err := ioutil.ReadFile(cfg.FromCAFile) + data, err := os.ReadFile(cfg.FromCAFile) if err != nil { - return nil, fmt.Errorf("failed to read from-ca-file: %v", err) + return nil, fmt.Errorf("failed to read from-ca-file: %w", err) } if !pool.AppendCertsFromPEM(data) { rlogger.Log(logger, rlogger.Warn, "msg", "no certs found in from-ca-file") @@ -154,9 +136,9 @@ func CreateFromClient(cfg Config, interval time.Duration, name string, fromClient.Transport = metricshttp.NewDebugRoundTripper(logger, fromClient.Transport) } if len(cfg.FromToken) == 0 && len(cfg.FromTokenFile) > 0 { - data, err := ioutil.ReadFile(cfg.FromTokenFile) + data, err := os.ReadFile(cfg.FromTokenFile) if err != nil { - return nil, fmt.Errorf("unable to read from-token-file: %v", err) + return nil, fmt.Errorf("unable to read from-token-file: %w", err) } cfg.FromToken = strings.TrimSpace(string(data)) } @@ -164,12 +146,12 @@ func CreateFromClient(cfg Config, interval time.Duration, name string, fromClient.Transport = metricshttp.NewBearerRoundTripper(cfg.FromToken, fromClient.Transport) } - from := metricsclient.New(logger, fromClient, cfg.LimitBytes, interval, "federate_from") + from := metricsclient.New(logger, metrics.clientMetrics, fromClient, cfg.LimitBytes, interval, "federate_from") return from, nil } -func createClients(cfg Config, interval time.Duration, +func createClients(cfg Config, metrics *metricsclient.ClientMetrics, interval time.Duration, logger log.Logger) (*metricsclient.Client, *metricsclient.Client, metricfamily.MultiTransformer, error) { var transformer metricfamily.MultiTransformer @@ -177,14 +159,14 @@ func createClients(cfg Config, interval time.Duration, // Configure the anonymization. anonymizeSalt := cfg.AnonymizeSalt if len(cfg.AnonymizeSalt) == 0 && len(cfg.AnonymizeSaltFile) > 0 { - data, err := ioutil.ReadFile(cfg.AnonymizeSaltFile) + data, err := os.ReadFile(cfg.AnonymizeSaltFile) if err != nil { - return nil, nil, transformer, fmt.Errorf("failed to read anonymize-salt-file: %v", err) + return nil, nil, transformer, fmt.Errorf("failed to read anonymize-salt-file: %w", err) } anonymizeSalt = strings.TrimSpace(string(data)) } if len(cfg.AnonymizeLabels) != 0 && len(anonymizeSalt) == 0 { - return nil, nil, transformer, fmt.Errorf("anonymize-salt must be specified if anonymize-labels is set") + return nil, nil, transformer, errors.New("anonymize-salt must be specified if anonymize-labels is set") } if len(cfg.AnonymizeLabels) == 0 { rlogger.Log(logger, rlogger.Warn, "msg", "not anonymizing any labels") @@ -197,7 +179,7 @@ func createClients(cfg Config, interval time.Duration, if len(cfg.AnonymizeLabels) > 0 { transformer.With(metricfamily.NewMetricsAnonymizer(anonymizeSalt, cfg.AnonymizeLabels, nil)) } - from, err := CreateFromClient(cfg, interval, "federate_from", logger) + from, err := CreateFromClient(cfg, cfg.Metrics, interval, "federate_from", logger) if err != nil { return nil, nil, transformer, err } @@ -206,17 +188,53 @@ func createClients(cfg Config, interval time.Duration, toTransport, err := metricsclient.MTLSTransport(logger, cfg.ToUploadCA, cfg.ToUploadCert, cfg.ToUploadKey) if err != nil { - return nil, nil, transformer, errors.New(err.Error()) + return nil, nil, transformer, fmt.Errorf("failed to create TLS transport: %w", err) } toTransport.Proxy = http.ProxyFromEnvironment toClient := &http.Client{Transport: toTransport} if cfg.Debug { toClient.Transport = metricshttp.NewDebugRoundTripper(logger, toClient.Transport) } - to := metricsclient.New(logger, toClient, cfg.LimitBytes, interval, "federate_to") + to := metricsclient.New(logger, metrics, toClient, cfg.LimitBytes, interval, "federate_to") return from, to, transformer, nil } +type workerMetrics struct { + gaugeFederateSamples prometheus.Gauge + gaugeFederateFilteredSamples prometheus.Gauge + gaugeFederateErrors prometheus.Gauge + + clientMetrics *metricsclient.ClientMetrics +} + +func NewWorkerMetrics(reg *prometheus.Registry) *workerMetrics { + return &workerMetrics{ + gaugeFederateSamples: promauto.With(reg).NewGauge(prometheus.GaugeOpts{ + Name: "federate_samples", + Help: "Tracks the number of samples per federation", + }), + gaugeFederateFilteredSamples: promauto.With(reg).NewGauge(prometheus.GaugeOpts{ + Name: "federate_filtered_samples", + Help: "Tracks the number of samples filtered per federation", + }), + gaugeFederateErrors: promauto.With(reg).NewGauge(prometheus.GaugeOpts{ + Name: "federate_errors", + Help: "The number of times forwarding federated metrics has failed", + }), + + clientMetrics: &metricsclient.ClientMetrics{ + GaugeRequestRetrieve: promauto.With(reg).NewGaugeVec(prometheus.GaugeOpts{ + Name: "metricsclient_request_retrieve", + Help: "Tracks the number of metrics retrievals", + }, []string{"client", "status_code"}), + GaugeRequestSend: promauto.With(reg).NewGaugeVec(prometheus.GaugeOpts{ + Name: "metricsclient_request_send", + Help: "Tracks the number of metrics sends", + }, []string{"client", "status_code"}), + }, + } +} + // New creates a new Worker based on the provided Config. If the Config contains invalid // values, then an error is returned. func New(cfg Config) (*Worker, error) { @@ -233,13 +251,14 @@ func New(cfg Config) (*Worker, error) { to: cfg.ToUpload, logger: log.With(cfg.Logger, "component", "forwarder/worker"), simulatedTimeseriesFile: cfg.SimulatedTimeseriesFile, + metrics: cfg.Metrics, } if w.interval == 0 { w.interval = 4*time.Minute + 30*time.Second } - fromClient, toClient, transformer, err := createClients(cfg, w.interval, logger) + fromClient, toClient, transformer, err := createClients(cfg, w.metrics.clientMetrics, w.interval, logger) if err != nil { return nil, err } @@ -250,9 +269,9 @@ func New(cfg Config) (*Worker, error) { // Configure the matching rules. rules := cfg.Rules if len(cfg.RulesFile) > 0 { - data, err := ioutil.ReadFile(cfg.RulesFile) + data, err := os.ReadFile(cfg.RulesFile) if err != nil { - return nil, fmt.Errorf("unable to read match-file: %v", err) + return nil, fmt.Errorf("unable to read match-file: %w", err) } rules = append(rules, strings.Split(string(data), "\n")...) } @@ -282,7 +301,7 @@ func New(cfg Config) (*Worker, error) { s, err := status.New(logger) if err != nil { - return nil, fmt.Errorf("unable to create StatusReport: %v", err) + return nil, fmt.Errorf("unable to create StatusReport: %w", err) } w.status = *s @@ -294,7 +313,7 @@ func New(cfg Config) (*Worker, error) { func (w *Worker) Reconfigure(cfg Config) error { worker, err := New(cfg) if err != nil { - return fmt.Errorf("failed to reconfigure: %v", err) + return fmt.Errorf("failed to reconfigure: %w", err) } w.lock.Lock() @@ -330,13 +349,13 @@ func (w *Worker) Run(ctx context.Context) { w.lock.Unlock() if err := w.forward(ctx); err != nil { - gaugeFederateErrors.Inc() + w.metrics.gaugeFederateErrors.Inc() rlogger.Log(w.logger, rlogger.Error, "msg", "unable to forward results", "err", err) wait = time.Minute } select { - // If the context is cancelled, then we're done. + // If the context is canceled, then we're done. case <-ctx.Done(): return case <-time.After(wait): @@ -362,7 +381,7 @@ func (w *Worker) forward(ctx context.Context) error { } else { families, err = w.getFederateMetrics(ctx) if err != nil { - statusErr := w.status.UpdateStatus("Degraded", "Degraded", "Failed to retrieve metrics") + statusErr := w.status.UpdateStatus("Degraded", "Failed to retrieve metrics") if statusErr != nil { rlogger.Log(w.logger, rlogger.Warn, "msg", failedStatusReportMsg, "err", statusErr) } @@ -371,7 +390,7 @@ func (w *Worker) forward(ctx context.Context) error { rfamilies, err := w.getRecordingMetrics(ctx) if err != nil && len(rfamilies) == 0 { - statusErr := w.status.UpdateStatus("Degraded", "Degraded", "Failed to retrieve recording metrics") + statusErr := w.status.UpdateStatus("Degraded", "Failed to retrieve recording metrics") if statusErr != nil { rlogger.Log(w.logger, rlogger.Warn, "msg", failedStatusReportMsg, "err", statusErr) } @@ -383,7 +402,7 @@ func (w *Worker) forward(ctx context.Context) error { before := metricfamily.MetricsCount(families) if err := metricfamily.Filter(families, w.transformer); err != nil { - statusErr := w.status.UpdateStatus("Degraded", "Degraded", "Failed to filter metrics") + statusErr := w.status.UpdateStatus("Degraded", "Failed to filter metrics") if statusErr != nil { rlogger.Log(w.logger, rlogger.Warn, "msg", failedStatusReportMsg, "err", statusErr) } @@ -393,14 +412,14 @@ func (w *Worker) forward(ctx context.Context) error { families = metricfamily.Pack(families) after := metricfamily.MetricsCount(families) - gaugeFederateSamples.Set(float64(before)) - gaugeFederateFilteredSamples.Set(float64(before - after)) + w.metrics.gaugeFederateSamples.Set(float64(before)) + w.metrics.gaugeFederateFilteredSamples.Set(float64(before - after)) w.lastMetrics = families if len(families) == 0 { rlogger.Log(w.logger, rlogger.Warn, "msg", "no metrics to send, doing nothing") - statusErr := w.status.UpdateStatus("Available", "Available", "No metrics to send") + statusErr := w.status.UpdateStatus("Available", "No metrics to send") if statusErr != nil { rlogger.Log(w.logger, rlogger.Warn, "msg", failedStatusReportMsg, "err", statusErr) } @@ -409,7 +428,7 @@ func (w *Worker) forward(ctx context.Context) error { if w.to == nil { rlogger.Log(w.logger, rlogger.Warn, "msg", "to is nil, doing nothing") - statusErr := w.status.UpdateStatus("Available", "Available", "Metrics is not required to send") + statusErr := w.status.UpdateStatus("Available", "Metrics is not required to send") if statusErr != nil { rlogger.Log(w.logger, rlogger.Warn, "msg", failedStatusReportMsg, "err", statusErr) } @@ -419,12 +438,12 @@ func (w *Worker) forward(ctx context.Context) error { req := &http.Request{Method: "POST", URL: w.to} err = w.toClient.RemoteWrite(ctx, req, families, w.interval) if err != nil { - statusErr := w.status.UpdateStatus("Degraded", "Degraded", "Failed to send metrics") + statusErr := w.status.UpdateStatus("Degraded", "Failed to send metrics") if statusErr != nil { rlogger.Log(w.logger, rlogger.Warn, "msg", failedStatusReportMsg, "err", statusErr) } } else if w.simulatedTimeseriesFile == "" { - statusErr := w.status.UpdateStatus("Available", "Available", "Cluster metrics sent successfully") + statusErr := w.status.UpdateStatus("Available", "Cluster metrics sent successfully") if statusErr != nil { rlogger.Log(w.logger, rlogger.Warn, "msg", failedStatusReportMsg, "err", statusErr) } diff --git a/collectors/metrics/pkg/forwarder/forwarder_test.go b/collectors/metrics/pkg/forwarder/forwarder_test.go index f82ca682a..e36965c0f 100644 --- a/collectors/metrics/pkg/forwarder/forwarder_test.go +++ b/collectors/metrics/pkg/forwarder/forwarder_test.go @@ -3,6 +3,7 @@ package forwarder import ( "context" + stdlog "log" "net/http" "net/http/httptest" "net/url" @@ -10,7 +11,8 @@ import ( "sync" "testing" - "github.com/go-kit/kit/log" + "github.com/go-kit/log" + "github.com/prometheus/client_golang/prometheus" ) func init() { @@ -123,6 +125,7 @@ func TestNew(t *testing.T) { } for i := range tc { + tc[i].c.Metrics = NewWorkerMetrics(prometheus.NewRegistry()) if _, err := New(tc[i].c); (err != nil) != tc[i].err { no := "no" if tc[i].err { @@ -139,8 +142,9 @@ func TestReconfigure(t *testing.T) { t.Fatalf("failed to parse `from` URL: %v", err) } c := Config{ - From: from, - Logger: log.NewNopLogger(), + From: from, + Logger: log.NewNopLogger(), + Metrics: NewWorkerMetrics(prometheus.NewRegistry()), } w, err := New(c) if err != nil { @@ -181,6 +185,7 @@ func TestReconfigure(t *testing.T) { } for i := range tc { + tc[i].c.Metrics = NewWorkerMetrics(prometheus.NewRegistry()) if err := w.Reconfigure(tc[i].c); (err != nil) != tc[i].err { no := "no" if tc[i].err { @@ -205,6 +210,7 @@ func TestRun(t *testing.T) { From: &url.URL{}, FromQuery: &url.URL{}, Logger: log.NewNopLogger(), + Metrics: NewWorkerMetrics(prometheus.NewRegistry()), } w, err := New(c) if err != nil { @@ -232,10 +238,10 @@ func TestRun(t *testing.T) { go func() { from, err := url.Parse(ts2.URL) if err != nil { - t.Fatalf("failed to parse second test server URL: %v", err) + stdlog.Fatalf("failed to parse second test server URL: %v", err) } - if err := w.Reconfigure(Config{From: from, FromQuery: from, Logger: log.NewNopLogger()}); err != nil { - t.Fatalf("failed to reconfigure worker with second test server url: %v", err) + if err := w.Reconfigure(Config{From: from, FromQuery: from, Logger: log.NewNopLogger(), Metrics: NewWorkerMetrics(prometheus.NewRegistry())}); err != nil { + stdlog.Fatalf("failed to reconfigure worker with second test server url: %v", err) } }() })) @@ -247,7 +253,7 @@ func TestRun(t *testing.T) { } if err := w.Reconfigure(Config{From: from, FromQuery: from, RecordingRules: []string{"{\"name\":\"test\",\"query\":\"test\"}"}, - Logger: log.NewNopLogger()}); err != nil { + Logger: log.NewNopLogger(), Metrics: NewWorkerMetrics(prometheus.NewRegistry())}); err != nil { t.Fatalf("failed to reconfigure worker with first test server url: %v", err) } diff --git a/collectors/metrics/pkg/http/client.go b/collectors/metrics/pkg/http/client.go deleted file mode 100644 index 634929026..000000000 --- a/collectors/metrics/pkg/http/client.go +++ /dev/null @@ -1,101 +0,0 @@ -package http - -import ( - "net/http" - - "github.com/prometheus/client_golang/prometheus/promhttp" - - "github.com/prometheus/client_golang/prometheus" -) - -var ( - inFlightGauge = prometheus.NewGaugeVec( - prometheus.GaugeOpts{ - Name: "client_in_flight_requests", - Help: "A gauge of in-flight requests for the wrapped client.", - }, - []string{"client"}, - ) - - counter = prometheus.NewCounterVec( - prometheus.CounterOpts{ - Name: "client_api_requests_total", - Help: "A counter for requests from the wrapped client.", - }, - []string{"code", "method", "client"}, - ) - - dnsLatencyVec = prometheus.NewHistogramVec( - prometheus.HistogramOpts{ - Name: "dns_duration_seconds", - Help: "Trace dns latency histogram.", - Buckets: []float64{.005, .01, .025, .05}, - }, - []string{"event", "client"}, - ) - - tlsLatencyVec = prometheus.NewHistogramVec( - prometheus.HistogramOpts{ - Name: "tls_duration_seconds", - Help: "Trace tls latency histogram.", - Buckets: []float64{.05, .1, .25, .5}, - }, - []string{"event", "client"}, - ) - - histVec = prometheus.NewHistogramVec( - prometheus.HistogramOpts{ - Name: "request_duration_seconds", - Help: "A histogram of request latencies.", - Buckets: prometheus.DefBuckets, - }, - []string{"method", "client"}, - ) -) - -func init() { - prometheus.MustRegister(counter, tlsLatencyVec, dnsLatencyVec, histVec, inFlightGauge) -} - -func NewInstrumentedRoundTripper(clientName string, next http.RoundTripper) http.RoundTripper { - trace := &promhttp.InstrumentTrace{ - DNSStart: func(t float64) { - dnsLatencyVec. - WithLabelValues("dns_start", clientName). - Observe(t) - }, - DNSDone: func(t float64) { - dnsLatencyVec. - WithLabelValues("dns_done", clientName). - Observe(t) - }, - TLSHandshakeStart: func(t float64) { - tlsLatencyVec. - WithLabelValues("tls_handshake_start", clientName). - Observe(t) - }, - TLSHandshakeDone: func(t float64) { - tlsLatencyVec. - WithLabelValues("tls_handshake_done", clientName). - Observe(t) - }, - } - - inFlightGauge := inFlightGauge.WithLabelValues(clientName) - - counter := counter.MustCurryWith(prometheus.Labels{ - "client": clientName, - }) - - histVec := histVec.MustCurryWith(prometheus.Labels{ - "client": clientName, - }) - - return promhttp.InstrumentRoundTripperInFlight(inFlightGauge, - promhttp.InstrumentRoundTripperCounter(counter, - promhttp.InstrumentRoundTripperTrace(trace, - promhttp.InstrumentRoundTripperDuration(histVec, next), - ), - ), - ) -} diff --git a/collectors/metrics/pkg/http/roundtripper.go b/collectors/metrics/pkg/http/roundtripper.go index ae05afc03..13b4b9aea 100644 --- a/collectors/metrics/pkg/http/roundtripper.go +++ b/collectors/metrics/pkg/http/roundtripper.go @@ -5,12 +5,11 @@ import ( "encoding/hex" "fmt" "io" - "io/ioutil" "net/http" "net/http/httputil" "unicode/utf8" - "github.com/go-kit/kit/log" + "github.com/go-kit/log" "github.com/stolostron/multicluster-observability-operator/collectors/metrics/pkg/logger" ) @@ -70,7 +69,7 @@ func bodyToString(body *io.ReadCloser) string { if err = (*body).Close(); err != nil { panic(err) } - *body = ioutil.NopCloser(&b) + *body = io.NopCloser(&b) s := b.String() if utf8.ValidString(s) { diff --git a/collectors/metrics/pkg/http/routes.go b/collectors/metrics/pkg/http/routes.go index 85f0cf0e7..cba2b3bdb 100644 --- a/collectors/metrics/pkg/http/routes.go +++ b/collectors/metrics/pkg/http/routes.go @@ -5,6 +5,7 @@ import ( "net/http" "net/http/pprof" + "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" ) @@ -27,8 +28,8 @@ func HealthRoutes(mux *http.ServeMux) *http.ServeMux { } // MetricRoutes adds the metrics endpoint to a mux. -func MetricRoutes(mux *http.ServeMux) *http.ServeMux { - mux.Handle("/metrics", promhttp.Handler()) +func MetricRoutes(mux *http.ServeMux, reg *prometheus.Registry) *http.ServeMux { + mux.Handle("/metrics", promhttp.HandlerFor(reg, promhttp.HandlerOpts{Registry: reg})) return mux } diff --git a/collectors/metrics/pkg/logger/logger.go b/collectors/metrics/pkg/logger/logger.go index b1ea13f42..bf848f0e0 100644 --- a/collectors/metrics/pkg/logger/logger.go +++ b/collectors/metrics/pkg/logger/logger.go @@ -4,8 +4,8 @@ import ( "fmt" "os" - "github.com/go-kit/kit/log" - "github.com/go-kit/kit/log/level" + "github.com/go-kit/log" + "github.com/go-kit/log/level" ) type LogLevel string @@ -17,7 +17,7 @@ const ( Error LogLevel = "error" ) -// LogLevelFromString determines log level to string, defaults to all, +// LogLevelFromString determines log level to string, defaults to all. func LogLevelFromString(l string) level.Option { switch l { case "debug": @@ -33,7 +33,7 @@ func LogLevelFromString(l string) level.Option { } } -// Log is used to handle the error of logger.Log globally +// Log is used to handle the error of logger.Log globally. func Log(log log.Logger, l LogLevel, keyvals ...interface{}) { //errkey := "failover_err_%d" switch l { diff --git a/collectors/metrics/pkg/metricfamily/hypershift_transformer.go b/collectors/metrics/pkg/metricfamily/hypershift_transformer.go index bd3a7b522..1abbbf021 100644 --- a/collectors/metrics/pkg/metricfamily/hypershift_transformer.go +++ b/collectors/metrics/pkg/metricfamily/hypershift_transformer.go @@ -3,11 +3,12 @@ package metricfamily import ( "context" - "errors" "fmt" "os" - "github.com/go-kit/kit/log" + "errors" + + "github.com/go-kit/log" hyperv1 "github.com/openshift/hypershift/api/v1alpha1" prom "github.com/prometheus/client_model/go" "k8s.io/client-go/kubernetes/scheme" @@ -59,7 +60,7 @@ func NewHypershiftTransformer(l log.Logger, c client.Client, labels map[string]s if err != nil { return nil, err } - hClient = fake.NewFakeClient() + hClient = fake.NewClientBuilder().Build() } } @@ -130,7 +131,7 @@ func getClusterName(h *hypershiftTransformer, id string) (string, error) { } clusterName, ok = h.hostedClusters[id] if !ok { - return "", fmt.Errorf("failed to find HosteCluster with id: %s", id) + return "", fmt.Errorf("failed to find HostedCluster with id: %s", id) } } return clusterName, nil diff --git a/collectors/metrics/pkg/metricfamily/hypershift_transformer_test.go b/collectors/metrics/pkg/metricfamily/hypershift_transformer_test.go index af0a0cd49..1fa130b95 100644 --- a/collectors/metrics/pkg/metricfamily/hypershift_transformer_test.go +++ b/collectors/metrics/pkg/metricfamily/hypershift_transformer_test.go @@ -53,7 +53,7 @@ func init() { } func TestTransform(t *testing.T) { - c := fake.NewFakeClient(hCluster) + c := fake.NewClientBuilder().WithRuntimeObjects(hCluster).Build() l := log.NewLogfmtLogger(log.NewSyncWriter(os.Stderr)) labels := map[string]string{ diff --git a/collectors/metrics/pkg/metricfamily/invalid.go b/collectors/metrics/pkg/metricfamily/invalid.go index 99d2c2f79..fdd3b5203 100644 --- a/collectors/metrics/pkg/metricfamily/invalid.go +++ b/collectors/metrics/pkg/metricfamily/invalid.go @@ -1,6 +1,7 @@ package metricfamily import ( + "errors" "fmt" "time" @@ -23,7 +24,7 @@ func (t *errorInvalidFederateSamples) Transform(family *clientmodel.MetricFamily return false, nil } if len(name) > 255 { - return false, fmt.Errorf("metrics_name cannot be longer than 255 characters") + return false, errors.New("metrics_name cannot be longer than 255 characters") } if family.Type == nil { return false, nil @@ -44,10 +45,10 @@ func (t *errorInvalidFederateSamples) Transform(family *clientmodel.MetricFamily } for _, label := range m.Label { if label.Name == nil || len(*label.Name) == 0 || len(*label.Name) > 255 { - return false, fmt.Errorf("label_name cannot be longer than 255 characters") + return false, errors.New("label_name cannot be longer than 255 characters") } if label.Value == nil || len(*label.Value) > 255 { - return false, fmt.Errorf("label_value cannot be longer than 255 characters") + return false, errors.New("label_value cannot be longer than 255 characters") } } if m.TimestampMs == nil { diff --git a/collectors/metrics/pkg/metricfamily/label.go b/collectors/metrics/pkg/metricfamily/label.go index b5bc96456..0a172d0c5 100644 --- a/collectors/metrics/pkg/metricfamily/label.go +++ b/collectors/metrics/pkg/metricfamily/label.go @@ -5,6 +5,7 @@ import ( clientmodel "github.com/prometheus/client_model/go" "github.com/prometheus/prometheus/prompb" + "golang.org/x/exp/slices" ) type LabelRetriever interface { @@ -81,7 +82,7 @@ func appendLabels( for k, v := range overrides { // only append real names and values // don't append anything overwritten above - if k != "" && v.GetValue() != "" && !contains(found, k) { + if k != "" && v.GetValue() != "" && !slices.Contains(found, k) { existing = insertLexicographicallyByName(existing, v) } } @@ -102,15 +103,6 @@ func insertLexicographicallyByName( return existing } -func contains(values []string, s string) bool { - for _, v := range values { - if s == v { - return true - } - } - return false -} - func InsertLabelLexicographicallyByName( existing []prompb.Label, value prompb.Label) []prompb.Label { diff --git a/collectors/metrics/pkg/metricfamily/overwrite.go b/collectors/metrics/pkg/metricfamily/overwrite.go deleted file mode 100644 index 4e17411c5..000000000 --- a/collectors/metrics/pkg/metricfamily/overwrite.go +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright Contributors to the Open Cluster Management project - -package metricfamily - -import ( - "time" - - "github.com/prometheus/client_golang/prometheus" - client "github.com/prometheus/client_model/go" -) - -// driftRange is used to observe timestamps being older than 5min, newer than 5min, -// or within the present (+-5min) -const driftRange = 5 * time.Minute - -var ( - overwrittenMetrics = prometheus.NewCounterVec(prometheus.CounterOpts{ - Name: "metricscollector_overwritten_timestamps_total", - Help: "Number of timestamps that were in the past, present or future", - }, []string{"tense"}) -) - -func init() { - prometheus.MustRegister(overwrittenMetrics) -} - -// OverwriteTimestamps sets all timestamps to the current time. -func OverwriteTimestamps(now func() time.Time) TransformerFunc { - return func(family *client.MetricFamily) (bool, error) { - timestamp := now().Unix() * 1000 - for i, m := range family.Metric { - observeDrift(now, m.GetTimestampMs()) - - family.Metric[i].TimestampMs = ×tamp - } - return true, nil - } -} - -func observeDrift(now func() time.Time, ms int64) { - timestamp := time.Unix(ms/1000, 0) - - if timestamp.Before(now().Add(-driftRange)) { - overwrittenMetrics.WithLabelValues("past").Inc() - } else if timestamp.After(now().Add(driftRange)) { - overwrittenMetrics.WithLabelValues("future").Inc() - } else { - overwrittenMetrics.WithLabelValues("present").Inc() - } - -} diff --git a/collectors/metrics/pkg/metricfamily/required.go b/collectors/metrics/pkg/metricfamily/required.go index 3ea01b353..43828a2d5 100644 --- a/collectors/metrics/pkg/metricfamily/required.go +++ b/collectors/metrics/pkg/metricfamily/required.go @@ -1,6 +1,7 @@ package metricfamily import ( + "errors" "fmt" clientmodel "github.com/prometheus/client_model/go" @@ -15,7 +16,7 @@ func NewRequiredLabels(labels map[string]string) Transformer { } var ( - ErrRequiredLabelMissing = fmt.Errorf("a required label is missing from the metric") + ErrRequiredLabelMissing = errors.New("a required label is missing from the metric") ) func (t requireLabel) Transform(family *clientmodel.MetricFamily) (bool, error) { diff --git a/collectors/metrics/pkg/metricfamily/sort.go b/collectors/metrics/pkg/metricfamily/sort.go index 87ee9ce6b..b44a676cb 100644 --- a/collectors/metrics/pkg/metricfamily/sort.go +++ b/collectors/metrics/pkg/metricfamily/sort.go @@ -104,7 +104,7 @@ func MergeSortedWithTimestamps(families []*clientmodel.MetricFamily) []*clientmo // PackedFamilyWithTimestampsByName sorts a packed slice of metrics // (no nils, all families have at least one metric, and all metrics -// have timestamps) in order of metric name and then oldest sample +// have timestamps) in order of metric name and then oldest sample. type PackedFamilyWithTimestampsByName []*clientmodel.MetricFamily func (families PackedFamilyWithTimestampsByName) Len() int { diff --git a/collectors/metrics/pkg/metricfamily/unsorted.go b/collectors/metrics/pkg/metricfamily/unsorted.go index 4a2bf1ce8..47d02c4bc 100644 --- a/collectors/metrics/pkg/metricfamily/unsorted.go +++ b/collectors/metrics/pkg/metricfamily/unsorted.go @@ -1,15 +1,15 @@ package metricfamily import ( - "fmt" + "errors" clientmodel "github.com/prometheus/client_model/go" ) var ( - ErrUnsorted = fmt.Errorf("metrics in provided family are not in increasing timestamp order") - ErrNoTimestamp = fmt.Errorf("metrics in provided family do not have a timestamp") - ErrTimestampTooOld = fmt.Errorf("metrics in provided family have a timestamp that is too old, check clock skew") + ErrUnsorted = errors.New("metrics in provided family are not in increasing timestamp order") + ErrNoTimestamp = errors.New("metrics in provided family do not have a timestamp") + ErrTimestampTooOld = errors.New("metrics in provided family have a timestamp that is too old, check clock skew") ) type errorOnUnsorted struct { diff --git a/collectors/metrics/pkg/metricsclient/metricsclient.go b/collectors/metrics/pkg/metricsclient/metricsclient.go index f5c78ae3c..52752b2ff 100644 --- a/collectors/metrics/pkg/metricsclient/metricsclient.go +++ b/collectors/metrics/pkg/metricsclient/metricsclient.go @@ -8,9 +8,9 @@ import ( "crypto/tls" "crypto/x509" "encoding/json" + "errors" "fmt" "io" - "io/ioutil" "net" "net/http" "os" @@ -20,10 +20,9 @@ import ( "time" "github.com/cenkalti/backoff" - "github.com/go-kit/kit/log" + "github.com/go-kit/log" "github.com/gogo/protobuf/proto" "github.com/golang/snappy" - "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" clientmodel "github.com/prometheus/client_model/go" "github.com/prometheus/common/expfmt" @@ -41,42 +40,33 @@ const ( maxSeriesLength = 10000 ) -var ( - gaugeRequestRetrieve = prometheus.NewGaugeVec(prometheus.GaugeOpts{ - Name: "metricsclient_request_retrieve", - Help: "Tracks the number of metrics retrievals", - }, []string{"client", "status_code"}) - gaugeRequestSend = prometheus.NewGaugeVec(prometheus.GaugeOpts{ - Name: "metricsclient_request_send", - Help: "Tracks the number of metrics sends", - }, []string{"client", "status_code"}) -) - -func init() { - prometheus.MustRegister( - gaugeRequestRetrieve, gaugeRequestSend, - ) -} - type Client struct { client *http.Client maxBytes int64 timeout time.Duration metricsName string logger log.Logger + + metrics *ClientMetrics +} + +type ClientMetrics struct { + GaugeRequestRetrieve *prometheus.GaugeVec + GaugeRequestSend *prometheus.GaugeVec } type PartitionedMetrics struct { Families []*clientmodel.MetricFamily } -func New(logger log.Logger, client *http.Client, maxBytes int64, timeout time.Duration, metricsName string) *Client { +func New(logger log.Logger, metrics *ClientMetrics, client *http.Client, maxBytes int64, timeout time.Duration, metricsName string) *Client { return &Client{ client: client, maxBytes: maxBytes, timeout: timeout, metricsName: metricsName, logger: log.With(logger, "component", "metricsclient"), + metrics: metrics, } } @@ -107,19 +97,19 @@ func (c *Client) RetrievRecordingMetrics( err := withCancel(ctx, c.client, req, func(resp *http.Response) error { switch resp.StatusCode { case http.StatusOK: - gaugeRequestRetrieve.WithLabelValues(c.metricsName, "200").Inc() + c.metrics.GaugeRequestRetrieve.WithLabelValues(c.metricsName, "200").Inc() case http.StatusUnauthorized: - gaugeRequestRetrieve.WithLabelValues(c.metricsName, "401").Inc() - return fmt.Errorf("Prometheus server requires authentication: %s", resp.Request.URL) + c.metrics.GaugeRequestRetrieve.WithLabelValues(c.metricsName, "401").Inc() + return fmt.Errorf("prometheus server requires authentication: %s", resp.Request.URL) case http.StatusForbidden: - gaugeRequestRetrieve.WithLabelValues(c.metricsName, "403").Inc() - return fmt.Errorf("Prometheus server forbidden: %s", resp.Request.URL) + c.metrics.GaugeRequestRetrieve.WithLabelValues(c.metricsName, "403").Inc() + return fmt.Errorf("prometheus server forbidden: %s", resp.Request.URL) case http.StatusBadRequest: - gaugeRequestRetrieve.WithLabelValues(c.metricsName, "400").Inc() + c.metrics.GaugeRequestRetrieve.WithLabelValues(c.metricsName, "400").Inc() return fmt.Errorf("bad request: %s", resp.Request.URL) default: - gaugeRequestRetrieve.WithLabelValues(c.metricsName, strconv.Itoa(resp.StatusCode)).Inc() - return fmt.Errorf("Prometheus server reported unexpected error code: %d", resp.StatusCode) + c.metrics.GaugeRequestRetrieve.WithLabelValues(c.metricsName, strconv.Itoa(resp.StatusCode)).Inc() + return fmt.Errorf("prometheus server reported unexpected error code: %d", resp.StatusCode) } decoder := json.NewDecoder(resp.Body) @@ -199,19 +189,19 @@ func (c *Client) Retrieve(ctx context.Context, req *http.Request) ([]*clientmode err := withCancel(ctx, c.client, req, func(resp *http.Response) error { switch resp.StatusCode { case http.StatusOK: - gaugeRequestRetrieve.WithLabelValues(c.metricsName, "200").Inc() + c.metrics.GaugeRequestRetrieve.WithLabelValues(c.metricsName, "200").Inc() case http.StatusUnauthorized: - gaugeRequestRetrieve.WithLabelValues(c.metricsName, "401").Inc() - return fmt.Errorf("Prometheus server requires authentication: %s", resp.Request.URL) + c.metrics.GaugeRequestRetrieve.WithLabelValues(c.metricsName, "401").Inc() + return fmt.Errorf("prometheus server requires authentication: %s", resp.Request.URL) case http.StatusForbidden: - gaugeRequestRetrieve.WithLabelValues(c.metricsName, "403").Inc() - return fmt.Errorf("Prometheus server forbidden: %s", resp.Request.URL) + c.metrics.GaugeRequestRetrieve.WithLabelValues(c.metricsName, "403").Inc() + return fmt.Errorf("prometheus server forbidden: %s", resp.Request.URL) case http.StatusBadRequest: - gaugeRequestRetrieve.WithLabelValues(c.metricsName, "400").Inc() + c.metrics.GaugeRequestRetrieve.WithLabelValues(c.metricsName, "400").Inc() return fmt.Errorf("bad request: %s", resp.Request.URL) default: - gaugeRequestRetrieve.WithLabelValues(c.metricsName, strconv.Itoa(resp.StatusCode)).Inc() - return fmt.Errorf("Prometheus server reported unexpected error code: %d", resp.StatusCode) + c.metrics.GaugeRequestRetrieve.WithLabelValues(c.metricsName, strconv.Itoa(resp.StatusCode)).Inc() + return fmt.Errorf("prometheus server reported unexpected error code: %d", resp.StatusCode) } // read the response into memory @@ -249,7 +239,7 @@ func (c *Client) Send(ctx context.Context, req *http.Request, families []*client } req.Header.Set("Content-Type", string(expfmt.FmtProtoDelim)) req.Header.Set("Content-Encoding", "snappy") - req.Body = ioutil.NopCloser(buf) + req.Body = io.NopCloser(buf) ctx, cancel := context.WithTimeout(ctx, c.timeout) req = req.WithContext(ctx) @@ -257,7 +247,7 @@ func (c *Client) Send(ctx context.Context, req *http.Request, families []*client logger.Log(c.logger, logger.Debug, "msg", "start to send") return withCancel(ctx, c.client, req, func(resp *http.Response) error { defer func() { - if _, err := io.Copy(ioutil.Discard, resp.Body); err != nil { + if _, err := io.Copy(io.Discard, resp.Body); err != nil { logger.Log(c.logger, logger.Error, "msg", "error copying body", "err", err) } if err := resp.Body.Close(); err != nil { @@ -267,20 +257,20 @@ func (c *Client) Send(ctx context.Context, req *http.Request, families []*client logger.Log(c.logger, logger.Debug, "msg", resp.StatusCode) switch resp.StatusCode { case http.StatusOK: - gaugeRequestSend.WithLabelValues(c.metricsName, "200").Inc() + c.metrics.GaugeRequestSend.WithLabelValues(c.metricsName, "200").Inc() case http.StatusUnauthorized: - gaugeRequestSend.WithLabelValues(c.metricsName, "401").Inc() + c.metrics.GaugeRequestSend.WithLabelValues(c.metricsName, "401").Inc() return fmt.Errorf("gateway server requires authentication: %s", resp.Request.URL) case http.StatusForbidden: - gaugeRequestSend.WithLabelValues(c.metricsName, "403").Inc() + c.metrics.GaugeRequestSend.WithLabelValues(c.metricsName, "403").Inc() return fmt.Errorf("gateway server forbidden: %s", resp.Request.URL) case http.StatusBadRequest: - gaugeRequestSend.WithLabelValues(c.metricsName, "400").Inc() + c.metrics.GaugeRequestSend.WithLabelValues(c.metricsName, "400").Inc() logger.Log(c.logger, logger.Debug, "msg", resp.Body) return fmt.Errorf("gateway server bad request: %s", resp.Request.URL) default: - gaugeRequestSend.WithLabelValues(c.metricsName, strconv.Itoa(resp.StatusCode)).Inc() - body, _ := ioutil.ReadAll(resp.Body) + c.metrics.GaugeRequestSend.WithLabelValues(c.metricsName, strconv.Itoa(resp.StatusCode)).Inc() + body, _ := io.ReadAll(resp.Body) if len(body) > 1024 { body = body[:1024] } @@ -328,6 +318,8 @@ func Write(w io.Writer, families []*clientmodel.MetricFamily) error { func withCancel(ctx context.Context, client *http.Client, req *http.Request, fn func(*http.Response) error) error { resp, err := client.Do(req) + // TODO(saswatamcode): Check error. + //nolint:errcheck defer func() error { if resp != nil { if err = resp.Body.Close(); err != nil { @@ -379,14 +371,14 @@ func MTLSTransport(logger log.Logger, caCertFile, tlsCrtFile, tlsKeyFile string) tlsCrtFile = "../../testdata/tls/tls.crt" } // Load Server CA cert - caCert, err := ioutil.ReadFile(filepath.Clean(caCertFile)) + caCert, err := os.ReadFile(filepath.Clean(caCertFile)) if err != nil { - return nil, errors.Wrap(err, "failed to load server ca cert file") + return nil, fmt.Errorf("failed to load server ca cert file: %w", err) } // Load client cert signed by Client CA cert, err := tls.LoadX509KeyPair(tlsCrtFile, tlsKeyFile) if err != nil { - return nil, errors.Wrap(err, "failed to load client ca cert") + return nil, fmt.Errorf("failed to load client ca cert: %w", err) } caCertPool := x509.NewCertPool() @@ -471,7 +463,7 @@ func convertToTimeseries(p *PartitionedMetrics, now time.Time) ([]prompb.TimeSer return timeseries, nil } -// RemoteWrite is used to push the metrics to remote thanos endpoint +// RemoteWrite is used to push the metrics to remote thanos endpoint. func (c *Client) RemoteWrite(ctx context.Context, req *http.Request, families []*clientmodel.MetricFamily, interval time.Duration) error { @@ -479,7 +471,7 @@ func (c *Client) RemoteWrite(ctx context.Context, req *http.Request, if err != nil { msg := "failed to convert timeseries" logger.Log(c.logger, logger.Warn, "msg", msg, "err", err) - return fmt.Errorf(msg) + return errors.New(msg) } if len(timeseries) == 0 { @@ -513,7 +505,7 @@ func (c *Client) RemoteWrite(ctx context.Context, req *http.Request, if err != nil { msg := "failed to marshal proto" logger.Log(c.logger, logger.Warn, "msg", msg, "err", err) - return fmt.Errorf(msg) + return errors.New(msg) } compressed := snappy.Encode(nil, data) @@ -537,8 +529,7 @@ func (c *Client) RemoteWrite(ctx context.Context, req *http.Request, return err } } - msg := fmt.Sprintf("Metrics pushed successfully") - logger.Log(c.logger, logger.Info, "msg", msg) + logger.Log(c.logger, logger.Info, "msg", "metrics pushed successfully") return nil } @@ -547,7 +538,7 @@ func (c *Client) sendRequest(serverURL string, body []byte) error { if err != nil { msg := "failed to create forwarding request" logger.Log(c.logger, logger.Warn, "msg", msg, "err", err) - return fmt.Errorf(msg) + return errors.New(msg) } //req.Header.Add("THANOS-TENANT", tenantID) @@ -561,12 +552,12 @@ func (c *Client) sendRequest(serverURL string, body []byte) error { if err != nil { msg := "failed to forward request" logger.Log(c.logger, logger.Warn, "msg", msg, "err", err) - return fmt.Errorf(msg) + return errors.New(msg) } if resp.StatusCode/100 != 2 { // surfacing upstreams error to our users too - bodyBytes, err := ioutil.ReadAll(resp.Body) + bodyBytes, err := io.ReadAll(resp.Body) if err != nil { logger.Log(c.logger, logger.Warn, err) } @@ -574,7 +565,7 @@ func (c *Client) sendRequest(serverURL string, body []byte) error { msg := fmt.Sprintf("response status code is %s, response body is %s", resp.Status, bodyString) logger.Log(c.logger, logger.Warn, msg) if resp.StatusCode != http.StatusConflict { - return fmt.Errorf(msg) + return errors.New(msg) } } return nil diff --git a/collectors/metrics/pkg/metricsclient/metricsclient_test.go b/collectors/metrics/pkg/metricsclient/metricsclient_test.go index fb6a503c4..fb7271a17 100644 --- a/collectors/metrics/pkg/metricsclient/metricsclient_test.go +++ b/collectors/metrics/pkg/metricsclient/metricsclient_test.go @@ -8,7 +8,7 @@ import ( "testing" "time" - "github.com/go-kit/kit/log" + "github.com/go-kit/log" clientmodel "github.com/prometheus/client_model/go" "github.com/prometheus/prometheus/prompb" ) diff --git a/collectors/metrics/pkg/reader/reader.go b/collectors/metrics/pkg/reader/reader.go index f7f8c558a..8a397cae4 100644 --- a/collectors/metrics/pkg/reader/reader.go +++ b/collectors/metrics/pkg/reader/reader.go @@ -1,7 +1,7 @@ package reader import ( - "fmt" + "errors" "io" ) @@ -21,7 +21,7 @@ func (c limitReadCloser) Close() error { return c.closer.Close() } -var ErrTooLong = fmt.Errorf("the incoming sample data is too long") +var ErrTooLong = errors.New("the incoming sample data is too long") // LimitReader returns a Reader that reads from r // but stops with ErrTooLong after n bytes. diff --git a/collectors/metrics/pkg/simulator/simulator.go b/collectors/metrics/pkg/simulator/simulator.go index 3c99ed526..992e4f750 100644 --- a/collectors/metrics/pkg/simulator/simulator.go +++ b/collectors/metrics/pkg/simulator/simulator.go @@ -7,7 +7,6 @@ import ( "crypto/rand" "fmt" "io" - "io/ioutil" "math/big" "os" "path/filepath" @@ -15,7 +14,7 @@ import ( "strings" "time" - "github.com/go-kit/kit/log" + "github.com/go-kit/log" clientmodel "github.com/prometheus/client_model/go" "github.com/prometheus/common/expfmt" @@ -61,7 +60,7 @@ func SimulateMetrics(logger log.Logger) []*clientmodel.MetricFamily { sb.WriteString("\n") } //rlogger.Log(logger, rlogger.Error, "data", sb.String()) - r := ioutil.NopCloser(bytes.NewReader([]byte(sb.String()))) + r := io.NopCloser(bytes.NewReader([]byte(sb.String()))) decoder := expfmt.NewDecoder(r, expfmt.FmtText) for { family := &clientmodel.MetricFamily{} diff --git a/collectors/metrics/pkg/status/status.go b/collectors/metrics/pkg/status/status.go index 74bbd20da..391a795d4 100644 --- a/collectors/metrics/pkg/status/status.go +++ b/collectors/metrics/pkg/status/status.go @@ -10,7 +10,7 @@ import ( "strings" "time" - "github.com/go-kit/kit/log" + "github.com/go-kit/log" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/kubernetes/scheme" @@ -38,21 +38,21 @@ func New(logger log.Logger) (*StatusReport, error) { standaloneMode := os.Getenv("STANDALONE") == "true" var kubeClient client.Client if testMode { - kubeClient = fake.NewFakeClient() + kubeClient = fake.NewClientBuilder().Build() } else if standaloneMode { kubeClient = nil } else { config, err := clientcmd.BuildConfigFromFlags("", "") if err != nil { - return nil, errors.New("Failed to create the kube config") + return nil, errors.New("failed to create the kube config") } s := scheme.Scheme if err := oav1beta1.AddToScheme(s); err != nil { - return nil, errors.New("Failed to add observabilityaddon into scheme") + return nil, errors.New("failed to add observabilityaddon into scheme") } kubeClient, err = client.New(config, client.Options{Scheme: s}) if err != nil { - return nil, errors.New("Failed to create the kube client") + return nil, errors.New("failed to create the kube client") } } @@ -62,7 +62,7 @@ func New(logger log.Logger) (*StatusReport, error) { }, nil } -func (s *StatusReport) UpdateStatus(t string, r string, m string) error { +func (s *StatusReport) UpdateStatus(t string, m string) error { if s.statusClient == nil { return nil } @@ -83,8 +83,7 @@ func (s *StatusReport) UpdateStatus(t string, r string, m string) error { found := false conditions := []oav1beta1.StatusCondition{} latestC := oav1beta1.StatusCondition{} - message, conditionType, reason := mergeCondtion(isUwl, t, r, m, - addon.Status.Conditions[len(addon.Status.Conditions)-1]) + message, conditionType, reason := mergeCondtion(isUwl, m, addon.Status.Conditions[len(addon.Status.Conditions)-1]) for _, c := range addon.Status.Conditions { if c.Status == metav1.ConditionTrue { if c.Type != conditionType { @@ -138,7 +137,7 @@ func (s *StatusReport) UpdateStatus(t string, r string, m string) error { return nil } -func mergeCondtion(isUwl bool, t, r, m string, condition oav1beta1.StatusCondition) (string, string, string) { +func mergeCondtion(isUwl bool, m string, condition oav1beta1.StatusCondition) (string, string, string) { messages := strings.Split(condition.Message, " ; ") if len(messages) == 1 { messages = append(messages, "") diff --git a/collectors/metrics/pkg/status/status_test.go b/collectors/metrics/pkg/status/status_test.go index db3a3dd06..fc8196b0a 100644 --- a/collectors/metrics/pkg/status/status_test.go +++ b/collectors/metrics/pkg/status/status_test.go @@ -7,7 +7,7 @@ import ( "testing" "time" - "github.com/go-kit/kit/log" + "github.com/go-kit/log" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes/scheme" @@ -48,43 +48,43 @@ func TestUpdateStatus(t *testing.T) { t.Fatalf("Failed to create observabilityAddon: (%v)", err) } - err = s.UpdateStatus("Disabled", "Disabled", "enableMetrics is set to False") + err = s.UpdateStatus("Disabled", "enableMetrics is set to False") if err != nil { t.Fatalf("Failed to update status: (%v)", err) } - err = s.UpdateStatus("Ready", "Deployed", "Metrics collector deployed and functional") + err = s.UpdateStatus("Ready", "Metrics collector deployed and functional") if err != nil { t.Fatalf("Failed to update status: (%v)", err) } - err = s.UpdateStatus("Ready", "Deployed", "Metrics collector deployed and updated") + err = s.UpdateStatus("Ready", "Metrics collector deployed and updated") if err != nil { t.Fatalf("Failed to update status: (%v)", err) } - err = s.UpdateStatus("Available", "Available", "Cluster metrics sent successfully") + err = s.UpdateStatus("Available", "Cluster metrics sent successfully") if err != nil { t.Fatalf("Failed to update status: (%v)", err) } os.Setenv("FROM", uwlPromURL) - err = s.UpdateStatus("Degraded", "Degraded", "Failed to retrieve metrics") + err = s.UpdateStatus("Degraded", "Failed to retrieve metrics") if err != nil { t.Fatalf("Failed to update status: (%v)", err) } - err = s.UpdateStatus("Degraded", "Degraded", "Failed to send metrics") + err = s.UpdateStatus("Degraded", "Failed to send metrics") if err != nil { t.Fatalf("Failed to update status: (%v)", err) } - err = s.UpdateStatus("Available", "Available", "Cluster metrics sent successfully") + err = s.UpdateStatus("Available", "Cluster metrics sent successfully") if err != nil { t.Fatalf("Failed to update status: (%v)", err) } os.Setenv("FROM", "") - err = s.UpdateStatus("Available", "Available", "Cluster metrics sent successfully") + err = s.UpdateStatus("Available", "Cluster metrics sent successfully") if err != nil { t.Fatalf("Failed to update status: (%v)", err) } diff --git a/collectors/metrics/test/integration/clean.sh b/collectors/metrics/test/integration/clean.sh index b01fe3a00..67f35b20e 100755 --- a/collectors/metrics/test/integration/clean.sh +++ b/collectors/metrics/test/integration/clean.sh @@ -2,21 +2,21 @@ # Copyright (c) 2021 Red Hat, Inc. # Copyright Contributors to the Open Cluster Management project -WORKDIR=`pwd` +WORKDIR=$(pwd) -delete_kind_hub() { - echo "====Delete kind cluster=====" - kind delete cluster --name hub - rm $HOME/.kube/kind-config-hub > /dev/null 2>&1 +delete_kind_hub() { + echo "====Delete kind cluster=====" + kind delete cluster --name hub + rm $HOME/.kube/kind-config-hub >/dev/null 2>&1 } -delete_command_binaries(){ - cd ${WORKDIR} - echo "Current directory" - echo $(pwd) - rm ./kind > /dev/null 2>&1 - rm ./kubectl > /dev/null 2>&1 +delete_command_binaries() { + cd ${WORKDIR} + echo "Current directory" + echo $(pwd) + rm ./kind >/dev/null 2>&1 + rm ./kubectl >/dev/null 2>&1 } delete_kind_hub -delete_command_binaries \ No newline at end of file +delete_command_binaries diff --git a/collectors/metrics/test/integration/prereq.sh b/collectors/metrics/test/integration/prereq.sh index b1202ab86..13cc26365 100755 --- a/collectors/metrics/test/integration/prereq.sh +++ b/collectors/metrics/test/integration/prereq.sh @@ -2,50 +2,49 @@ # Copyright (c) 2021 Red Hat, Inc. # Copyright Contributors to the Open Cluster Management project -WORKDIR=`pwd` +WORKDIR=$(pwd) setup_kubectl_command() { - command -v kubectl - if [ $? -ne 0 ]; then - echo "=====Setup kubectl=====" - # kubectl required for kind - echo "Install kubectl from openshift mirror (https://mirror.openshift.com/pub/openshift-v4/clients/ocp/4.4.14/openshift-client-mac-4.4.14.tar.gz)" - mv README.md README.md.tmp - if [[ "$(uname)" == "Darwin" ]]; then # then we are on a Mac - curl -LO https://mirror.openshift.com/pub/openshift-v4/clients/ocp/4.4.14/openshift-client-mac-4.4.14.tar.gz - tar xzvf openshift-client-mac-4.4.14.tar.gz # xzf to quiet logs - rm openshift-client-mac-4.4.14.tar.gz - elif [[ "$(uname)" == "Linux" ]]; then # we are in travis, building in rhel - curl -LO https://mirror.openshift.com/pub/openshift-v4/clients/ocp/4.4.14/openshift-client-linux-4.4.14.tar.gz - tar xzvf openshift-client-linux-4.4.14.tar.gz # xzf to quiet logs - rm openshift-client-linux-4.4.14.tar.gz - fi - # this package has a binary, so: + command -v kubectl + if [ $? -ne 0 ]; then + echo "=====Setup kubectl=====" + # kubectl required for kind + echo "Install kubectl from openshift mirror (https://mirror.openshift.com/pub/openshift-v4/clients/ocp/4.4.14/openshift-client-mac-4.4.14.tar.gz)" + mv README.md README.md.tmp + if [[ "$(uname)" == "Darwin" ]]; then # then we are on a Mac + curl -LO https://mirror.openshift.com/pub/openshift-v4/clients/ocp/4.4.14/openshift-client-mac-4.4.14.tar.gz + tar xzvf openshift-client-mac-4.4.14.tar.gz # xzf to quiet logs + rm openshift-client-mac-4.4.14.tar.gz + elif [[ "$(uname)" == "Linux" ]]; then # we are in travis, building in rhel + curl -LO https://mirror.openshift.com/pub/openshift-v4/clients/ocp/4.4.14/openshift-client-linux-4.4.14.tar.gz + tar xzvf openshift-client-linux-4.4.14.tar.gz # xzf to quiet logs + rm openshift-client-linux-4.4.14.tar.gz + fi + # this package has a binary, so: - echo "Current directory" - echo $(pwd) - mv README.md.tmp README.md - chmod +x ./kubectl - sudo cp ./kubectl /usr/local/bin/kubectl - fi - # kubectl are now installed in current dir - echo -n "kubectl version" && kubectl version + echo "Current directory" + echo $(pwd) + mv README.md.tmp README.md + chmod +x ./kubectl + sudo cp ./kubectl /usr/local/bin/kubectl + fi + # kubectl are now installed in current dir + echo -n "kubectl version" && kubectl version } - -install_kind() { - command -v kind - if [ $? -ne 0 ]; then - echo "Install kind from (https://kind.sigs.k8s.io/)." - - # uname returns your operating system name - # uname -- Print operating system name - # -L location, lowercase -o specify output name, uppercase -O Write output to a local file named like the remote file we get - curl -Lo ./kind "https://kind.sigs.k8s.io/dl/v0.7.0/kind-$(uname)-amd64" - chmod +x ./kind - sudo cp ./kind /usr/local/bin/kind - fi -} +install_kind() { + command -v kind + if [ $? -ne 0 ]; then + echo "Install kind from (https://kind.sigs.k8s.io/)." + + # uname returns your operating system name + # uname -- Print operating system name + # -L location, lowercase -o specify output name, uppercase -O Write output to a local file named like the remote file we get + curl -Lo ./kind "https://kind.sigs.k8s.io/dl/v0.7.0/kind-$(uname)-amd64" + chmod +x ./kind + sudo cp ./kind /usr/local/bin/kind + fi +} install_kind -setup_kubectl_command \ No newline at end of file +setup_kubectl_command diff --git a/collectors/metrics/test/integration/setup.sh b/collectors/metrics/test/integration/setup.sh index 1834dd771..521f50be3 100755 --- a/collectors/metrics/test/integration/setup.sh +++ b/collectors/metrics/test/integration/setup.sh @@ -2,181 +2,182 @@ # Copyright (c) 2021 Red Hat, Inc. # Copyright Contributors to the Open Cluster Management project -if [ "$#" -ne 1 ] ; then +if [ "$#" -ne 1 ]; then echo "Usage: $0 IMAGE" >&2 exit 1 fi -echo "=====running kind exploration=====" +echo "=====running kind exploration=====" IMAGE_NAME=$1 echo "IMAGE: " $IMAGE_NAME DEFAULT_NS="open-cluster-management" HUB_KUBECONFIG=$HOME/.kube/kind-config-hub -WORKDIR=`pwd` +WORKDIR=$(pwd) sed_command='sed -i-e -e' if [[ "$(uname)" == "Darwin" ]]; then - sed_command='sed -i '-e' -e' + sed_command='sed -i '-e' -e' fi deploy() { - #setup_kubectl_command - create_kind_hub - deploy_prometheus_operator - deploy_observatorium - deploy_thanos - deploy_metrics_collector $IMAGE_NAME + #setup_kubectl_command + create_kind_hub + deploy_prometheus_operator + deploy_observatorium + deploy_thanos + deploy_metrics_collector $IMAGE_NAME } setup_kubectl_command() { - echo "=====Setup kubectl=====" - # kubectl required for kind - echo "Install kubectl from openshift mirror (https://mirror.openshift.com/pub/openshift-v4/clients/ocp/4.4.14/openshift-client-mac-4.4.14.tar.gz)" - mv README.md README.md.tmp - if [[ "$(uname)" == "Darwin" ]]; then # then we are on a Mac - curl -LO https://mirror.openshift.com/pub/openshift-v4/clients/ocp/4.4.14/openshift-client-mac-4.4.14.tar.gz - tar xzvf openshift-client-mac-4.4.14.tar.gz # xzf to quiet logs - rm openshift-client-mac-4.4.14.tar.gz - elif [[ "$(uname)" == "Linux" ]]; then # we are in travis, building in rhel - curl -LO https://mirror.openshift.com/pub/openshift-v4/clients/ocp/4.4.14/openshift-client-linux-4.4.14.tar.gz - tar xzvf openshift-client-linux-4.4.14.tar.gz # xzf to quiet logs - rm openshift-client-linux-4.4.14.tar.gz - fi - # this package has a binary, so: - - echo "Current directory" - echo $(pwd) - mv README.md.tmp README.md - chmod +x ./kubectl - if [[ ! -f /usr/local/bin/kubectl ]]; then - sudo cp ./kubectl /usr/local/bin/kubectl - fi - # kubectl are now installed in current dir - echo -n "kubectl version" && kubectl version + echo "=====Setup kubectl=====" + # kubectl required for kind + echo "Install kubectl from openshift mirror (https://mirror.openshift.com/pub/openshift-v4/clients/ocp/4.4.14/openshift-client-mac-4.4.14.tar.gz)" + mv README.md README.md.tmp + if [[ "$(uname)" == "Darwin" ]]; then # then we are on a Mac + curl -LO https://mirror.openshift.com/pub/openshift-v4/clients/ocp/4.4.14/openshift-client-mac-4.4.14.tar.gz + tar xzvf openshift-client-mac-4.4.14.tar.gz # xzf to quiet logs + rm openshift-client-mac-4.4.14.tar.gz + elif [[ "$(uname)" == "Linux" ]]; then # we are in travis, building in rhel + curl -LO https://mirror.openshift.com/pub/openshift-v4/clients/ocp/4.4.14/openshift-client-linux-4.4.14.tar.gz + tar xzvf openshift-client-linux-4.4.14.tar.gz # xzf to quiet logs + rm openshift-client-linux-4.4.14.tar.gz + fi + # this package has a binary, so: + + echo "Current directory" + echo $(pwd) + mv README.md.tmp README.md + chmod +x ./kubectl + if [[ ! -f /usr/local/bin/kubectl ]]; then + sudo cp ./kubectl /usr/local/bin/kubectl + fi + # kubectl are now installed in current dir + echo -n "kubectl version" && kubectl version +} + +create_kind_hub() { + WORKDIR=$(pwd) + echo "Delete hub if it exists" + kind delete cluster --name hub || true + + echo "Start hub cluster" + rm -rf $HOME/.kube/kind-config-hub + kind create cluster --kubeconfig $HOME/.kube/kind-config-hub --name hub --config ${WORKDIR}/test/integration/kind/kind-hub.config.yaml + # kubectl cluster-info --context kind-hub --kubeconfig $(pwd)/.kube/kind-config-hub # confirm connection + export KUBECONFIG=$HOME/.kube/kind-config-hub } - -create_kind_hub() { - WORKDIR=`pwd` - echo "Delete hub if it exists" - kind delete cluster --name hub || true - - echo "Start hub cluster" - rm -rf $HOME/.kube/kind-config-hub - kind create cluster --kubeconfig $HOME/.kube/kind-config-hub --name hub --config ${WORKDIR}/test/integration/kind/kind-hub.config.yaml - # kubectl cluster-info --context kind-hub --kubeconfig $(pwd)/.kube/kind-config-hub # confirm connection - export KUBECONFIG=$HOME/.kube/kind-config-hub -} deploy_observatorium() { - echo "=====Setting up observatorium in kind cluster=====" - echo "Current directory" - echo $(pwd) - - echo -n "Create namespace open-cluster-management-observability: " && kubectl create namespace open-cluster-management-observability - echo "Apply observatorium yamls" - echo -n "Apply client ca cert and server certs: " && kubectl apply -f ./metrics-collector/test/integration/manifests/observatorium-ca-cert.yaml - echo -n "Apply secret with tenant yaml : " && kubectl apply -f ./metrics-collector/test/integration/manifests/observatorium-api-secret.yaml - echo -n "Apply configmap with rbac yaml : " && kubectl apply -f ./metrics-collector/test/integration/manifests/observatorium-api-configmap.yaml - echo -n "Apply Deployment yaml : " && kubectl apply -f ./metrics-collector/test/integration/manifests/observatorium-api.yaml - echo -n "Apply Service yaml : " && kubectl apply -f ./metrics-collector/test/integration/manifests/observatorium-api-service.yaml + echo "=====Setting up observatorium in kind cluster=====" + echo "Current directory" + echo $(pwd) + + echo -n "Create namespace open-cluster-management-observability: " && kubectl create namespace open-cluster-management-observability + echo "Apply observatorium yamls" + echo -n "Apply client ca cert and server certs: " && kubectl apply -f ./metrics-collector/test/integration/manifests/observatorium-ca-cert.yaml + echo -n "Apply secret with tenant yaml : " && kubectl apply -f ./metrics-collector/test/integration/manifests/observatorium-api-secret.yaml + echo -n "Apply configmap with rbac yaml : " && kubectl apply -f ./metrics-collector/test/integration/manifests/observatorium-api-configmap.yaml + echo -n "Apply Deployment yaml : " && kubectl apply -f ./metrics-collector/test/integration/manifests/observatorium-api.yaml + echo -n "Apply Service yaml : " && kubectl apply -f ./metrics-collector/test/integration/manifests/observatorium-api-service.yaml } deploy_thanos() { - echo "=====Setting up thanos in kind cluster=====" - echo -n "Apply create pvc yaml : " && kubectl apply -f ./metrics-collector/test/integration/manifests/thanos-pvc.yaml - echo -n "Apply configmap with hashring yaml : " && kubectl apply -f ./metrics-collector/test/integration/manifests/thanos-configmap.yaml - echo -n "Apply Deployment yaml : " && kubectl apply -f ./metrics-collector/test/integration/manifests/thanos-api.yaml - echo -n "Apply Service yaml : " && kubectl apply -f ./metrics-collector/test/integration/manifests/thanos-service.yaml - echo "Waiting 2 minutes for observatorium and thanos to start... " && sleep 120 + echo "=====Setting up thanos in kind cluster=====" + echo -n "Apply create pvc yaml : " && kubectl apply -f ./metrics-collector/test/integration/manifests/thanos-pvc.yaml + echo -n "Apply configmap with hashring yaml : " && kubectl apply -f ./metrics-collector/test/integration/manifests/thanos-configmap.yaml + echo -n "Apply Deployment yaml : " && kubectl apply -f ./metrics-collector/test/integration/manifests/thanos-api.yaml + echo -n "Apply Service yaml : " && kubectl apply -f ./metrics-collector/test/integration/manifests/thanos-service.yaml + echo "Waiting 2 minutes for observatorium and thanos to start... " && sleep 120 } deploy_prometheus_operator() { - echo "=====Setting up prometheus in kind cluster=====" - - WORKDIR=`pwd` - echo "Install prometheus operator." - echo "Current directory" - echo $(pwd) - cd ${WORKDIR}/.. - git clone https://github.com/coreos/kube-prometheus.git - echo "Replace namespace with openshift-monitoring" - $sed_command "s~namespace: monitoring~namespace: openshift-monitoring~g" kube-prometheus/manifests/*.yaml - $sed_command "s~namespace: monitoring~namespace: openshift-monitoring~g" kube-prometheus/manifests/setup/*.yaml - $sed_command "s~name: monitoring~name: openshift-monitoring~g" kube-prometheus/manifests/setup/*.yaml - $sed_command "s~replicas:.*$~replicas: 1~g" kube-prometheus/manifests/prometheus-prometheus.yaml - echo "Remove alertmanager and grafana to free up resource" - rm -rf kube-prometheus/manifests/alertmanager-*.yaml - rm -rf kube-prometheus/manifests/grafana-*.yaml - if [[ ! -z "$1" ]]; then - update_prometheus_remote_write $1 - else - update_prometheus_remote_write - fi - - echo "HUB_KUBECONFIG" ${HUB_KUBECONFIG} - echo "KUBECONFIG" ${KUBECONFIG} - - echo "Creating prometheus manifests setup" && kubectl create -f kube-prometheus/manifests/setup - until kubectl get servicemonitors --all-namespaces; do date; sleep 1; echo ""; done - echo "Creating prometheus manifests" && kubectl create -f kube-prometheus/manifests/ - rm -rf kube-prometheus - echo "Installed prometheus operator." - sleep 60 - echo -n "available services: " && kubectl get svc --all-namespaces + echo "=====Setting up prometheus in kind cluster=====" + + WORKDIR=$(pwd) + echo "Install prometheus operator." + echo "Current directory" + echo $(pwd) + cd ${WORKDIR}/.. + git clone https://github.com/coreos/kube-prometheus.git + echo "Replace namespace with openshift-monitoring" + $sed_command "s~namespace: monitoring~namespace: openshift-monitoring~g" kube-prometheus/manifests/*.yaml + $sed_command "s~namespace: monitoring~namespace: openshift-monitoring~g" kube-prometheus/manifests/setup/*.yaml + $sed_command "s~name: monitoring~name: openshift-monitoring~g" kube-prometheus/manifests/setup/*.yaml + $sed_command "s~replicas:.*$~replicas: 1~g" kube-prometheus/manifests/prometheus-prometheus.yaml + echo "Remove alertmanager and grafana to free up resource" + rm -rf kube-prometheus/manifests/alertmanager-*.yaml + rm -rf kube-prometheus/manifests/grafana-*.yaml + if [[ -n $1 ]]; then + update_prometheus_remote_write $1 + else + update_prometheus_remote_write + fi + + echo "HUB_KUBECONFIG" ${HUB_KUBECONFIG} + echo "KUBECONFIG" ${KUBECONFIG} + + echo "Creating prometheus manifests setup" && kubectl create -f kube-prometheus/manifests/setup + until kubectl get servicemonitors --all-namespaces; do + date + sleep 1 + echo "" + done + echo "Creating prometheus manifests" && kubectl create -f kube-prometheus/manifests/ + rm -rf kube-prometheus + echo "Installed prometheus operator." + sleep 60 + echo -n "available services: " && kubectl get svc --all-namespaces } deploy_metrics_collector() { - echo "=====Deploying metrics-collector=====" - echo -n "Switch to namespace: " && kubectl config set-context --current --namespace open-cluster-management-observability - - echo "Current directory" - echo $(pwd) - # git clone https://github.com/stolostron/multicluster-observability-operator/collectors/metrics.git - - cd metrics-collector - echo -n "Creating pull secret: " && kubectl create secret docker-registry multiclusterhub-operator-pull-secret --docker-server=quay.io --docker-username=$DOCKER_USER --docker-password=$DOCKER_PASS - - # apply yamls - echo "Apply hub yamls" - echo -n "Apply client-serving-certs-ca-bundle: " && kubectl apply -f ./test/integration/manifests/client-serving-certs-ca-bundle.yaml - echo -n "Apply rolebinding: " && kubectl apply -f ./test/integration/manifests/rolebinding.yaml - echo -n "Apply client secret: " && kubectl apply -f ./test/integration/manifests/client_secret.yaml - echo -n "Apply mtls certs: " && kubectl apply -f ./test/integration/manifests/metrics-collector-cert.yaml - cp ./test/integration/manifests/deployment.yaml ./test/integration/manifests/deployment_update.yaml - $sed_command "s~{{ METRICS_COLLECTOR_IMAGE }}~$1~g" ./test/integration/manifests/deployment_update.yaml - $sed_command "s~cluster=func_e2e_test_travis~cluster=func_e2e_test_travis-$1~g" ./test/integration/manifests/deployment_update.yaml - echo "Display deployment yaml" - cat ./test/integration/manifests/deployment_update.yaml - echo -n "Apply metrics collector deployment: " && kubectl apply -f ./test/integration/manifests/deployment_update.yaml - rm ./test/integration/manifests/deployment_update.yaml* - - echo -n "available pods: " && kubectl get pods --all-namespaces - echo "Waiting 3 minutes for the pod to set up and send data... " && sleep 180 - POD=$(kubectl get pod -l k8s-app=metrics-collector -n open-cluster-management-observability -o jsonpath="{.items[0].metadata.name}") - echo "Monitoring pod logs" - count=0 - - while true ; do - count=`expr $count + 1` - result=$(kubectl logs $POD | grep -i "Metrics pushed successfully" > /dev/null && echo "SUCCESS" || echo "FAILURE") - if [ $result == "SUCCESS" ] - then - echo "SUCCESS sending metrics to Thanos" - exit 0 - fi - echo "No Sucess yet ..Sleeping for 30s" - echo "available pods: " && kubectl describe pod $POD - sleep 30s - if [ $count -gt 10 ] - then - echo "FAILED sending metrics to Thanos" - exit 1 - fi - - done - echo "available pods: " && kubectl get pods --all-namespaces + echo "=====Deploying metrics-collector=====" + echo -n "Switch to namespace: " && kubectl config set-context --current --namespace open-cluster-management-observability + + echo "Current directory" + echo $(pwd) + # git clone https://github.com/stolostron/multicluster-observability-operator/collectors/metrics.git + + cd metrics-collector + echo -n "Creating pull secret: " && kubectl create secret docker-registry multiclusterhub-operator-pull-secret --docker-server=quay.io --docker-username=$DOCKER_USER --docker-password=$DOCKER_PASS + + # apply yamls + echo "Apply hub yamls" + echo -n "Apply client-serving-certs-ca-bundle: " && kubectl apply -f ./test/integration/manifests/client-serving-certs-ca-bundle.yaml + echo -n "Apply rolebinding: " && kubectl apply -f ./test/integration/manifests/rolebinding.yaml + echo -n "Apply client secret: " && kubectl apply -f ./test/integration/manifests/client_secret.yaml + echo -n "Apply mtls certs: " && kubectl apply -f ./test/integration/manifests/metrics-collector-cert.yaml + cp ./test/integration/manifests/deployment.yaml ./test/integration/manifests/deployment_update.yaml + $sed_command "s~{{ METRICS_COLLECTOR_IMAGE }}~$1~g" ./test/integration/manifests/deployment_update.yaml + $sed_command "s~cluster=func_e2e_test_travis~cluster=func_e2e_test_travis-$1~g" ./test/integration/manifests/deployment_update.yaml + echo "Display deployment yaml" + cat ./test/integration/manifests/deployment_update.yaml + echo -n "Apply metrics collector deployment: " && kubectl apply -f ./test/integration/manifests/deployment_update.yaml + rm ./test/integration/manifests/deployment_update.yaml* + + echo -n "available pods: " && kubectl get pods --all-namespaces + echo "Waiting 3 minutes for the pod to set up and send data... " && sleep 180 + POD=$(kubectl get pod -l k8s-app=metrics-collector -n open-cluster-management-observability -o jsonpath="{.items[0].metadata.name}") + echo "Monitoring pod logs" + count=0 + + while true; do + count=$(expr $count + 1) + result=$(kubectl logs $POD | grep -i "Metrics pushed successfully" >/dev/null && echo "SUCCESS" || echo "FAILURE") + if [ $result == "SUCCESS" ]; then + echo "SUCCESS sending metrics to Thanos" + exit 0 + fi + echo "No Success yet ..Sleeping for 30s" + echo "available pods: " && kubectl describe pod $POD + sleep 30s + if [ $count -gt 10 ]; then + echo "FAILED sending metrics to Thanos" + exit 1 + fi -} + done + echo "available pods: " && kubectl get pods --all-namespaces +} -deploy +deploy diff --git a/docs/scale-perf.md b/docs/scale-perf.md index d1918459b..03e12bf55 100644 --- a/docs/scale-perf.md +++ b/docs/scale-perf.md @@ -9,7 +9,7 @@ The resource consumption later is not for single pod/deployment, but for the Ope Your results might vary, depending on your environment, network speed, and changes to the product. ## Test environment -In the test environment, hub and managed clusters are located in Amazon Web Services cloud platfrom and have the same topology/configuration as below: +In the test environment, hub and managed clusters are located in Amazon Web Services cloud platform and have the same topology/configuration as below: Node | Flavor | vCPU | RAM (GiB) | Disk type | Disk size(GiB)/IOS | Count | Region diff --git a/examples/ceph/operator.yaml b/examples/ceph/operator.yaml index f5ee45ead..5728d3c88 100644 --- a/examples/ceph/operator.yaml +++ b/examples/ceph/operator.yaml @@ -455,7 +455,7 @@ spec: - name: ROOK_HOSTPATH_REQUIRES_PRIVILEGED value: "true" # In some situations SELinux relabelling breaks (times out) on large filesystems, and doesn't work with cephfs ReadWriteMany volumes (last relabel wins). - # Disable it here if you have similiar issues. + # Disable it here if you have similar issues. # For more details see https://github.com/rook/rook/issues/2417 - name: ROOK_ENABLE_SELINUX_RELABELING value: "true" diff --git a/examples/gen.go b/examples/gen.go index 3547aad53..f65667fb7 100644 --- a/examples/gen.go +++ b/examples/gen.go @@ -29,7 +29,6 @@ import ( "crypto/rsa" "crypto/x509" "encoding/pem" - "io/ioutil" "math/big" "net" "os" @@ -83,7 +82,7 @@ func main() { Type: "CERTIFICATE", Bytes: caBytes, }) - err = ioutil.WriteFile(caPath, caPEM, 0600) + err = os.WriteFile(caPath, caPEM, 0600) if err != nil { log.Error(err) os.Exit(1) @@ -99,7 +98,7 @@ func main() { Type: "CERTIFICATE", Bytes: certBytes, }) - err = ioutil.WriteFile(certPath, certPEM, 0600) + err = os.WriteFile(certPath, certPEM, 0600) if err != nil { log.Error(err) os.Exit(1) @@ -109,7 +108,7 @@ func main() { Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(certPrivKey), }) - err = ioutil.WriteFile(privkeyPath, certPrivKeyPEM, 0600) + err = os.WriteFile(privkeyPath, certPrivKeyPEM, 0600) if err != nil { log.Error(err) os.Exit(1) diff --git a/go.mod b/go.mod index 863937595..f23ee39be 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,6 @@ require ( github.com/cloudflare/cfssl v1.6.0 github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 github.com/go-co-op/gocron v1.18.0 - github.com/go-kit/kit v0.12.0 github.com/go-kit/log v0.2.1 github.com/go-logr/logr v1.2.4 github.com/gogo/protobuf v1.3.2 @@ -22,7 +21,6 @@ require ( github.com/openshift/client-go v0.0.0-20230120202327-72f107311084 github.com/openshift/cluster-monitoring-operator v0.0.0-20230118025836-20fcb9f6ef4e github.com/openshift/hypershift v0.1.11 - github.com/pkg/errors v0.9.1 github.com/prometheus-community/prom-label-proxy v0.6.0 github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.57.0 github.com/prometheus-operator/prometheus-operator/pkg/client v0.53.1 @@ -38,6 +36,7 @@ require ( github.com/stretchr/testify v1.8.4 github.com/thanos-io/thanos v0.30.0 go.uber.org/zap v1.24.0 + golang.org/x/exp v0.0.0-20221212164502-fae10dda9338 gopkg.in/yaml.v2 v2.4.0 k8s.io/api v0.28.2 k8s.io/apiextensions-apiserver v0.27.2 @@ -66,13 +65,14 @@ require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/dennwc/varint v1.0.0 // indirect github.com/edsrzf/mmap-go v1.1.0 // indirect - github.com/efficientgo/core v1.0.0-rc.0.0.20221201130417-ba593f67d2a4 // indirect + github.com/efficientgo/core v1.0.0-rc.2 // indirect github.com/efficientgo/tools/core v0.0.0-20220817170617-6c25e3b627dd // indirect github.com/emicklei/go-restful/v3 v3.10.2 // indirect github.com/evanphx/json-patch v5.6.0+incompatible // indirect github.com/evanphx/json-patch/v5 v5.6.0 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/go-errors/errors v1.4.2 // indirect + github.com/go-kit/kit v0.12.0 // indirect github.com/go-logfmt/logfmt v0.5.1 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-logr/zapr v1.2.4 // indirect @@ -117,6 +117,7 @@ require ( github.com/oklog/ulid v1.3.1 // indirect github.com/openshift/library-go v0.0.0-20230120214501-9bc305884fcb // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect + github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/common/sigv4 v0.1.0 // indirect github.com/prometheus/procfs v0.11.1 // indirect @@ -142,7 +143,6 @@ require ( go.uber.org/goleak v1.2.0 // indirect go.uber.org/multierr v1.8.0 // indirect golang.org/x/crypto v0.14.0 // indirect - golang.org/x/exp v0.0.0-20221212164502-fae10dda9338 // indirect golang.org/x/mod v0.10.0 // indirect golang.org/x/net v0.13.0 // indirect golang.org/x/oauth2 v0.10.0 // indirect diff --git a/go.sum b/go.sum index fff83997d..1f764e633 100644 --- a/go.sum +++ b/go.sum @@ -615,8 +615,8 @@ github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/edsrzf/mmap-go v1.1.0 h1:6EUwBLQ/Mcr1EYLE4Tn1VdW1A4ckqCQWZBw8Hr0kjpQ= github.com/edsrzf/mmap-go v1.1.0/go.mod h1:19H/e8pUPLicwkyNgOykDXkJ9F0MHE+Z52B8EIth78Q= -github.com/efficientgo/core v1.0.0-rc.0.0.20221201130417-ba593f67d2a4 h1:rydBwnBoywKQMjWF0z8SriYtQ+uUcaFsxuijMjJr5PI= -github.com/efficientgo/core v1.0.0-rc.0.0.20221201130417-ba593f67d2a4/go.mod h1:kQa0V74HNYMfuJH6jiPiwNdpWXl4xd/K4tzlrcvYDQI= +github.com/efficientgo/core v1.0.0-rc.2 h1:7j62qHLnrZqO3V3UA0AqOGd5d5aXV3AX6m/NZBHp78I= +github.com/efficientgo/core v1.0.0-rc.2/go.mod h1:FfGdkzWarkuzOlY04VY+bGfb1lWrjaL6x/GLcQ4vJps= github.com/efficientgo/e2e v0.11.2-0.20211027134903-67d538984a47/go.mod h1:vDnF4AAEZmO0mvyFIATeDJPFaSRM7ywaOnKd61zaSoE= github.com/efficientgo/tools/core v0.0.0-20210129205121-421d0828c9a6/go.mod h1:OmVcnJopJL8d3X3sSXTiypGoUSgFq1aDGmlrdi9dn/M= github.com/efficientgo/tools/core v0.0.0-20210201224146-3d78f4d30648/go.mod h1:cFZoHUhKg31xkPnPjhPKFtevnx0Xcg67ptBRxbpaxtk= diff --git a/loaders/dashboards/pkg/controller/dashboard_controller.go b/loaders/dashboards/pkg/controller/dashboard_controller.go index 4c7939b24..147e8dc7a 100644 --- a/loaders/dashboards/pkg/controller/dashboard_controller.go +++ b/loaders/dashboards/pkg/controller/dashboard_controller.go @@ -36,15 +36,9 @@ const ( homeDashboardTitle = "ACM - Clusters Overview" ) -// DashboardLoader ... -type DashboardLoader struct { - coreClient corev1client.CoreV1Interface - informer cache.SharedIndexInformer -} - var ( grafanaURI = "http://127.0.0.1:3001" - //retry on errors + // Retry on errors. retry = 10 ) @@ -103,6 +97,8 @@ func newKubeInformer(coreClient corev1client.CoreV1Interface) cache.SharedIndexI cache.Indexers{}, ) + // TODO(saswatamcode): Check error here. + //nolint:errcheck kubeInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{ AddFunc: func(obj interface{}) { if !isDesiredDashboardConfigmap(obj) { @@ -247,7 +243,7 @@ func getDashboardCustomFolderTitle(obj interface{}) string { return "" } -// updateDashboard is used to update the customized dashboards via calling grafana api +// updateDashboard is used to update the customized dashboards via calling grafana api. func updateDashboard(old, new interface{}, overwrite bool) { folderID := 0.0 folderTitle := getDashboardCustomFolderTitle(new) @@ -323,7 +319,10 @@ func updateDashboard(old, new interface{}, overwrite bool) { folderTitle = getDashboardCustomFolderTitle(old) folderID = hasCustomFolder(folderTitle) if isEmptyFolder(folderID) { - deleteCustomFolder(folderID) + if deleteCustomFolder(folderID) { + klog.Errorf("Failed to delete custom folder") + return + } } } @@ -355,10 +354,12 @@ func deleteDashboard(obj interface{}) { folderTitle := getDashboardCustomFolderTitle(obj) folderID := hasCustomFolder(folderTitle) if isEmptyFolder(folderID) { - deleteCustomFolder(folderID) + if deleteCustomFolder(folderID) { + klog.Errorf("Failed to delete custom folder") + return + } } } - return } func setHomeDashboard(id int) { diff --git a/loaders/dashboards/pkg/controller/dashboard_controller_test.go b/loaders/dashboards/pkg/controller/dashboard_controller_test.go index a23886263..85cb693d9 100644 --- a/loaders/dashboards/pkg/controller/dashboard_controller_test.go +++ b/loaders/dashboards/pkg/controller/dashboard_controller_test.go @@ -5,7 +5,7 @@ package controller import ( "context" - "io/ioutil" + stdlog "log" "net/http" "os" "testing" @@ -23,7 +23,7 @@ var ( func createDashboard() (*corev1.ConfigMap, error) { // read the whole file at once - data, err := ioutil.ReadFile("../../examples/k8s-dashboard.yaml") + data, err := os.ReadFile("../../examples/k8s-dashboard.yaml") if err != nil { panic(err) } @@ -86,7 +86,7 @@ func createFakeServer(t *testing.T) { err := http.ListenAndServe(":3001", server3001) if err != nil { - t.Fatal("fail to create internal server at 3001") + stdlog.Fatal("fail to create internal server at 3001") } } diff --git a/loaders/dashboards/pkg/util/grafana_util.go b/loaders/dashboards/pkg/util/grafana_util.go index 5b6367365..2555c8985 100644 --- a/loaders/dashboards/pkg/util/grafana_util.go +++ b/loaders/dashboards/pkg/util/grafana_util.go @@ -7,7 +7,6 @@ import ( "encoding/hex" "hash/fnv" "io" - "io/ioutil" "net/http" "time" @@ -18,7 +17,7 @@ const ( defaultAdmin = "WHAT_YOU_ARE_DOING_IS_VOIDING_SUPPORT_0000000000000000000000000000000000000000000000000000000000000000" ) -// GenerateUID generates UID for customized dashboard +// GenerateUID generates UID for customized dashboard. func GenerateUID(namespace string, name string) (string, error) { uid := namespace + "-" + name if len(uid) > 40 { @@ -32,7 +31,7 @@ func GenerateUID(namespace string, name string) (string, error) { return uid, nil } -// GetHTTPClient returns http client +// GetHTTPClient returns http client. func getHTTPClient() *http.Client { transport := &http.Transport{} client := &http.Client{Transport: transport} @@ -63,7 +62,7 @@ func SetRequest(method string, url string, body io.Reader, retry int) ([]byte, i if resp != nil { defer resp.Body.Close() - respBody, err := ioutil.ReadAll(resp.Body) + respBody, err := io.ReadAll(resp.Body) if err != nil { klog.Info("failed to parse response body ", "error ", err) } diff --git a/loaders/dashboards/pkg/util/grafana_util_test.go b/loaders/dashboards/pkg/util/grafana_util_test.go index 2bc9138dc..1afd75907 100644 --- a/loaders/dashboards/pkg/util/grafana_util_test.go +++ b/loaders/dashboards/pkg/util/grafana_util_test.go @@ -4,6 +4,7 @@ package util import ( + stdlog "log" "net/http" "testing" "time" @@ -32,7 +33,7 @@ func createFakeServer(t *testing.T) { ) err := http.ListenAndServe(":3002", server3002) if err != nil { - t.Fatal("fail to create internal server at 3002") + stdlog.Fatal("fail to create internal server at 3002") } } diff --git a/operators/endpointmetrics/controllers/observabilityendpoint/match_evaluator.go b/operators/endpointmetrics/controllers/observabilityendpoint/match_evaluator.go index d283463bb..eb6b17bf2 100644 --- a/operators/endpointmetrics/controllers/observabilityendpoint/match_evaluator.go +++ b/operators/endpointmetrics/controllers/observabilityendpoint/match_evaluator.go @@ -3,9 +3,8 @@ package observabilityendpoint import ( + "golang.org/x/exp/slices" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - - "github.com/stolostron/multicluster-observability-operator/operators/pkg/util" ) type evaluateFn func(metav1.LabelSelectorRequirement, ...interface{}) bool @@ -25,9 +24,9 @@ func evluateMatchExpression(expr metav1.LabelSelectorRequirement, params ...inte func evaluateClusterType(expr metav1.LabelSelectorRequirement, params ...interface{}) bool { switch expr.Operator { case metav1.LabelSelectorOpIn: - return util.Contains(expr.Values, params[1].(string)) + return slices.Contains(expr.Values, params[1].(string)) case metav1.LabelSelectorOpNotIn: - return !util.Contains(expr.Values, params[1].(string)) + return !slices.Contains(expr.Values, params[1].(string)) default: // return false for unsupported/invalid operator return false diff --git a/operators/endpointmetrics/controllers/observabilityendpoint/metrics_collector.go b/operators/endpointmetrics/controllers/observabilityendpoint/metrics_collector.go index 713a1a9be..3e75ccc47 100644 --- a/operators/endpointmetrics/controllers/observabilityendpoint/metrics_collector.go +++ b/operators/endpointmetrics/controllers/observabilityendpoint/metrics_collector.go @@ -516,8 +516,8 @@ func isUWLMonitoringEnabled(ctx context.Context, c client.Client) (bool, error) } // for custom uwl allowlist: -// 1. only support "names" and "matches" -// 2. inject namespace label filter for all entries in the allowlist +// 1. only support "names" and "matches". +// 2. inject namespace label filter for all entries in the allowlist. func injectNamespaceLabel(allowlist *operatorconfig.MetricsAllowlist, namespace string) *operatorconfig.MetricsAllowlist { updatedList := &operatorconfig.MetricsAllowlist{ diff --git a/operators/endpointmetrics/controllers/observabilityendpoint/observabilityaddon_controller.go b/operators/endpointmetrics/controllers/observabilityendpoint/observabilityaddon_controller.go index 4019421b4..f1677e7dd 100644 --- a/operators/endpointmetrics/controllers/observabilityendpoint/observabilityaddon_controller.go +++ b/operators/endpointmetrics/controllers/observabilityendpoint/observabilityaddon_controller.go @@ -8,6 +8,7 @@ import ( "os" "strconv" + "golang.org/x/exp/slices" "gopkg.in/yaml.v2" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" @@ -53,7 +54,7 @@ var ( hubNamespace = os.Getenv("HUB_NAMESPACE") ) -// ObservabilityAddonReconciler reconciles a ObservabilityAddon object +// ObservabilityAddonReconciler reconciles a ObservabilityAddon object. type ObservabilityAddonReconciler struct { Client client.Client Scheme *runtime.Scheme @@ -257,7 +258,7 @@ func (r *ObservabilityAddonReconciler) Reconcile(ctx context.Context, req ctrl.R func (r *ObservabilityAddonReconciler) initFinalization( ctx context.Context, delete bool, hubObsAddon *oav1beta1.ObservabilityAddon, isHypershift bool) (bool, error) { - if delete && contains(hubObsAddon.GetFinalizers(), obsAddonFinalizer) { + if delete && slices.Contains(hubObsAddon.GetFinalizers(), obsAddonFinalizer) { log.Info("To clean observability components/configurations in the cluster") err := deleteMetricsCollector(ctx, r.Client, metricsCollectorName) if err != nil { @@ -268,7 +269,7 @@ func (r *ObservabilityAddonReconciler) initFinalization( return false, err } // revert the change to cluster monitoring stack - err = revertClusterMonitoringConfig(ctx, r.Client, installPrometheus) + err = revertClusterMonitoringConfig(ctx, r.Client) if err != nil { return false, err } @@ -310,7 +311,7 @@ func (r *ObservabilityAddonReconciler) initFinalization( log.Info("Finalizer removed from observabilityaddon resource") return true, nil } - if !contains(hubObsAddon.GetFinalizers(), obsAddonFinalizer) { + if !slices.Contains(hubObsAddon.GetFinalizers(), obsAddonFinalizer) { hubObsAddon.SetFinalizers(append(hubObsAddon.GetFinalizers(), obsAddonFinalizer)) err := r.HubClient.Update(ctx, hubObsAddon) if err != nil { @@ -395,15 +396,6 @@ func (r *ObservabilityAddonReconciler) SetupWithManager(mgr ctrl.Manager) error Complete(r) } -func contains(list []string, s string) bool { - for _, v := range list { - if v == s { - return true - } - } - return false -} - func remove(list []string, s string) []string { result := []string{} for _, v := range list { diff --git a/operators/endpointmetrics/controllers/observabilityendpoint/observabilityaddon_controller_test.go b/operators/endpointmetrics/controllers/observabilityendpoint/observabilityaddon_controller_test.go index 20c2dda5d..5ec9638f1 100644 --- a/operators/endpointmetrics/controllers/observabilityendpoint/observabilityaddon_controller_test.go +++ b/operators/endpointmetrics/controllers/observabilityendpoint/observabilityaddon_controller_test.go @@ -10,6 +10,7 @@ import ( ocinfrav1 "github.com/openshift/api/config/v1" hyperv1 "github.com/openshift/hypershift/api/v1alpha1" + "golang.org/x/exp/slices" appv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" @@ -141,9 +142,9 @@ alertmanager-router-ca: | images := newImagesCM() objs := []runtime.Object{hubInfo, amAccessSrt, allowList, images, cv, infra} - hubClient := fake.NewFakeClient(hubObjs...) + hubClient := fake.NewClientBuilder().WithRuntimeObjects(hubObjs...).Build() util.SetHubClient(hubClient) - c := fake.NewFakeClient(objs...) + c := fake.NewClientBuilder().WithRuntimeObjects(objs...).Build() r := &ObservabilityAddonReconciler{ Client: c, @@ -224,7 +225,7 @@ alertmanager-router-ca: | if err != nil { t.Fatalf("Failed to get observabilityAddon: (%v)", err) } - if !contains(foundOba.Finalizers, obsAddonFinalizer) { + if !slices.Contains(foundOba.Finalizers, obsAddonFinalizer) { t.Fatal("Finalizer not set in observabilityAddon") } @@ -349,7 +350,7 @@ alertmanager-router-ca: | if err != nil { t.Fatalf("Failed to get observabilityAddon: (%v)", err) } - if contains(foundOba1.Finalizers, obsAddonFinalizer) { + if slices.Contains(foundOba1.Finalizers, obsAddonFinalizer) { t.Fatal("Finalizer not removed from observabilityAddon") } } diff --git a/operators/endpointmetrics/controllers/observabilityendpoint/ocp_monitoring_config.go b/operators/endpointmetrics/controllers/observabilityendpoint/ocp_monitoring_config.go index c52d19fd2..df65626a1 100644 --- a/operators/endpointmetrics/controllers/observabilityendpoint/ocp_monitoring_config.go +++ b/operators/endpointmetrics/controllers/observabilityendpoint/ocp_monitoring_config.go @@ -38,7 +38,7 @@ var ( ) // initializes clusterMonitoringConfigReverted based on the presence of clusterMonitoringRevertedName -// configmap in openshift-monitoring namespace +// configmap in openshift-monitoring namespace. func initPersistedRevertState(ctx context.Context, client client.Client) error { if !persistedRevertStateRead { // check if reverted configmap is present @@ -136,7 +136,7 @@ func unsetConfigReverted(ctx context.Context, client client.Client) error { return nil } -// createHubAmRouterCASecret creates the secret that contains CA of the Hub's Alertmanager Route +// createHubAmRouterCASecret creates the secret that contains CA of the Hub's Alertmanager Route. func createHubAmRouterCASecret( ctx context.Context, hubInfo *operatorconfig.HubInfo, @@ -186,33 +186,11 @@ func createHubAmRouterCASecret( } } -// deleteHubAmRouterCASecret deletes the secret that contains CA of the Hub's Alertmanager Route -func deleteHubAmRouterCASecret(ctx context.Context, client client.Client, targetNamespace string) error { - found := &corev1.Secret{} - err := client.Get(ctx, types.NamespacedName{Name: hubAmRouterCASecretName, - Namespace: targetNamespace}, found) - if err != nil { - if errors.IsNotFound(err) { - log.Info("the hub-alertmanager-router-ca secret is already deleted") - return nil - } - log.Error(err, "failed to check the hub-alertmanager-router-ca secret") - return err - } - err = client.Delete(ctx, found) - if err != nil { - log.Error(err, "error deleting the hub-alertmanager-router-ca secret") - return err - } - log.Info("the hub-alertmanager-router-ca secret is deleted") - return nil -} - -// createHubAmAccessorTokenSecret creates the secret that contains access token of the Hub's Alertmanager +// createHubAmAccessorTokenSecret creates the secret that contains access token of the Hub's Alertmanager. func createHubAmAccessorTokenSecret(ctx context.Context, client client.Client, targetNamespace string) error { amAccessorToken, err := getAmAccessorToken(ctx, client) if err != nil { - return fmt.Errorf("fail to get the alertmanager accessor token %v", err) + return fmt.Errorf("fail to get the alertmanager accessor token: %w", err) } dataMap := map[string][]byte{hubAmAccessorSecretKey: []byte(amAccessorToken)} @@ -257,29 +235,7 @@ func createHubAmAccessorTokenSecret(ctx context.Context, client client.Client, t } } -// deleteHubAmAccessorTokenSecret deletes the secret that contains access token of the Hub's Alertmanager -func deleteHubAmAccessorTokenSecret(ctx context.Context, client client.Client, targetNamespace string) error { - found := &corev1.Secret{} - err := client.Get(ctx, types.NamespacedName{Name: hubAmAccessorSecretName, - Namespace: targetNamespace}, found) - if err != nil { - if errors.IsNotFound(err) { - log.Info("the observability-alertmanager-accessor secret is already deleted") - return nil - } - log.Error(err, "failed to check the observability-alertmanager-accessor secret") - return err - } - err = client.Delete(ctx, found) - if err != nil { - log.Error(err, "error deleting the observability-alertmanager-accessor secret") - return err - } - log.Info("the observability-alertmanager-accessor secret is deleted") - return nil -} - -// getAmAccessorToken retrieves the alertmanager access token from observability-alertmanager-accessor secret +// getAmAccessorToken retrieves the alertmanager access token from observability-alertmanager-accessor secret. func getAmAccessorToken(ctx context.Context, client client.Client) (string, error) { amAccessorSecret := &corev1.Secret{} if err := client.Get(ctx, types.NamespacedName{Name: hubAmAccessorSecretName, @@ -315,19 +271,20 @@ func newAdditionalAlertmanagerConfig(hubInfo *operatorconfig.HubInfo) cmomanifes }, Key: hubAmAccessorSecretKey, }, - StaticConfigs: []string{strings.TrimLeft(hubInfo.AlertmanagerEndpoint, "https://")}, + StaticConfigs: []string{strings.TrimPrefix(hubInfo.AlertmanagerEndpoint, "https://")}, } } // createOrUpdateClusterMonitoringConfig creates or updates the configmap // cluster-monitoring-config and relevant resources (observability-alertmanager-accessor -// and hub-alertmanager-router-ca) for the openshift cluster monitoring stack +// and hub-alertmanager-router-ca) for the openshift cluster monitoring stack. func createOrUpdateClusterMonitoringConfig( ctx context.Context, hubInfo *operatorconfig.HubInfo, clusterID string, client client.Client, - installProm bool) error { + installProm bool, +) error { targetNamespace := promNamespace if installProm { // for *KS, the hub CA and alertmanager access token should be created @@ -356,7 +313,7 @@ func createOrUpdateClusterMonitoringConfig( return err } if !revertedAlready { - if err = revertClusterMonitoringConfig(ctx, client, installProm); err != nil { + if err = revertClusterMonitoringConfig(ctx, client); err != nil { return err } if err = setConfigReverted(ctx, client); err != nil { @@ -531,8 +488,8 @@ func unset(ctx context.Context, client client.Client) error { } // revertClusterMonitoringConfig reverts the configmap cluster-monitoring-config and relevant resources -// (observability-alertmanager-accessor and hub-alertmanager-router-ca) for the openshift cluster monitoring stack -func revertClusterMonitoringConfig(ctx context.Context, client client.Client, installProm bool) error { +// (observability-alertmanager-accessor and hub-alertmanager-router-ca) for the openshift cluster monitoring stack. +func revertClusterMonitoringConfig(ctx context.Context, client client.Client) error { log.Info("revertClusterMonitoringConfig called") // try to retrieve the current configmap in the cluster diff --git a/operators/endpointmetrics/controllers/observabilityendpoint/ocp_monitoring_config_test.go b/operators/endpointmetrics/controllers/observabilityendpoint/ocp_monitoring_config_test.go index 54ab6edd5..ddee60484 100644 --- a/operators/endpointmetrics/controllers/observabilityendpoint/ocp_monitoring_config_test.go +++ b/operators/endpointmetrics/controllers/observabilityendpoint/ocp_monitoring_config_test.go @@ -63,52 +63,6 @@ prometheusK8s: insecureSkipVerify: true` ) -func TestCreateDeleteHubAmRouterCASecret(t *testing.T) { - hubInfo := &operatorconfig.HubInfo{} - err := yaml.Unmarshal([]byte(hubInfoYAML), &hubInfo) - if err != nil { - t.Fatalf("Failed to unmarshal hubInfo: (%v)", err) - } - - hubInfoObj := newHubInfoSecret([]byte(hubInfoYAML)) - objs := []runtime.Object{hubInfoObj} - - ctx := context.TODO() - c := fake.NewFakeClient(objs...) - err = createHubAmRouterCASecret(ctx, hubInfo, c, promNamespace) - if err != nil { - t.Fatalf("Failed to create the hub-alertmanager-router-ca secret: (%v)", err) - } - err = deleteHubAmRouterCASecret(ctx, c, promNamespace) - if err != nil { - t.Fatalf("Failed to delete the hub-alertmanager-router-ca secret: (%v)", err) - } - err = deleteHubAmRouterCASecret(ctx, c, promNamespace) - if err != nil { - t.Fatalf("Run into error when try to delete hub-alertmanager-router-ca secret twice: (%v)", err) - } -} - -func TestCreateDeleteHubAmAccessorTokenSecret(t *testing.T) { - amAccessSrt := newAMAccessorSecret() - objs := []runtime.Object{amAccessSrt} - - ctx := context.TODO() - c := fake.NewFakeClient(objs...) - err := createHubAmAccessorTokenSecret(ctx, c, promNamespace) - if err != nil { - t.Fatalf("Failed to create the observability-alertmanager-accessor secret: (%v)", err) - } - err = deleteHubAmAccessorTokenSecret(ctx, c, promNamespace) - if err != nil { - t.Fatalf("Failed to delete the observability-alertmanager-accessor secret: (%v)", err) - } - err = deleteHubAmAccessorTokenSecret(ctx, c, promNamespace) - if err != nil { - t.Fatalf("Run into error when try to delete observability-alertmanager-accessor secret twice: (%v)", err) - } -} - func TestClusterMonitoringConfig(t *testing.T) { ctrl.SetLogger(zap.New(zap.UseFlagOptions(&zap.Options{Development: true}))) tests := []struct { @@ -188,7 +142,7 @@ prometheusK8s: if tt.ClusterMonitoringConfigCMExist { objs = append(objs, newClusterMonitoringConfigCM(tt.ClusterMonitoringConfigDataYaml, tt.Manager)) } - testCreateOrUpdateClusterMonitoringConfig(t, hubInfo, fake.NewFakeClient(objs...), tt.ExpectedDeleteClusterMonitoringConfigCM) + testCreateOrUpdateClusterMonitoringConfig(t, hubInfo, fake.NewClientBuilder().WithRuntimeObjects(objs...).Build(), tt.ExpectedDeleteClusterMonitoringConfigCM) }) } } @@ -455,7 +409,7 @@ func testCreateOrUpdateClusterMonitoringConfig(t *testing.T, hubInfo *operatorco t.Fatalf("no AlertmanagerConfig for OCM in ClusterMonitoringConfiguration.PrometheusK8sConfig.AlertmanagerConfigs: %v", foundClusterMonitoringConfiguration) } - err = revertClusterMonitoringConfig(ctx, c, false) + err = revertClusterMonitoringConfig(ctx, c) if err != nil { t.Fatalf("Failed to revert cluster-monitoring-config configmap: (%v)", err) } @@ -482,7 +436,7 @@ func testCreateOrUpdateClusterMonitoringConfig(t *testing.T, hubInfo *operatorco t.Fatalf("the secret %s should not be deleted", hubAmRouterCASecretName) } - err = revertClusterMonitoringConfig(ctx, c, false) + err = revertClusterMonitoringConfig(ctx, c) if err != nil { t.Fatalf("Run into error when try to revert cluster-monitoring-config configmap twice: (%v)", err) } diff --git a/operators/endpointmetrics/controllers/observabilityendpoint/ocp_resource_test.go b/operators/endpointmetrics/controllers/observabilityendpoint/ocp_resource_test.go index 136afd2a0..c5339916d 100644 --- a/operators/endpointmetrics/controllers/observabilityendpoint/ocp_resource_test.go +++ b/operators/endpointmetrics/controllers/observabilityendpoint/ocp_resource_test.go @@ -61,7 +61,7 @@ func init() { func TestCreateDeleteCAConfigmap(t *testing.T) { ctx := context.TODO() - c := fake.NewFakeClient() + c := fake.NewClientBuilder().Build() err := createCAConfigmap(ctx, c) if err != nil { t.Fatalf("Failed to create CA configmap: (%v)", err) @@ -78,7 +78,7 @@ func TestCreateDeleteCAConfigmap(t *testing.T) { func TestCreateDeleteMonitoringClusterRoleBinding(t *testing.T) { ctx := context.TODO() - c := fake.NewFakeClient() + c := fake.NewClientBuilder().Build() err := createMonitoringClusterRoleBinding(ctx, c) if err != nil { t.Fatalf("Failed to create clusterrolebinding: (%v)", err) @@ -124,7 +124,7 @@ func TestCreateDeleteMonitoringClusterRoleBinding(t *testing.T) { func TestGetClusterID(t *testing.T) { ctx := context.TODO() - c := fake.NewFakeClient(cv) + c := fake.NewClientBuilder().WithRuntimeObjects(cv).Build() found, err := getClusterID(ctx, c) if err != nil { t.Fatalf("Failed to get clusterversion: (%v)", err) @@ -136,7 +136,7 @@ func TestGetClusterID(t *testing.T) { func TestServiceMonitors(t *testing.T) { ctx := context.TODO() - c := fake.NewFakeClient(hCluster, sm) + c := fake.NewClientBuilder().WithRuntimeObjects(hCluster, sm).Build() err := createServiceMonitors(ctx, c) if err != nil { t.Fatalf("Failed to create ServiceMonitors: (%v)", err) @@ -149,7 +149,7 @@ func TestServiceMonitors(t *testing.T) { func TestDeleteServiceMonitor(t *testing.T) { ctx := context.TODO() - c := fake.NewFakeClient() + c := fake.NewClientBuilder().Build() err := deleteServiceMonitor(ctx, c, "test", "test") if err != nil { t.Fatalf("Failed to delete ServiceMonitors: (%v)", err) diff --git a/operators/endpointmetrics/controllers/status/status_controller.go b/operators/endpointmetrics/controllers/status/status_controller.go index 9c7e8da4a..337a18502 100644 --- a/operators/endpointmetrics/controllers/status/status_controller.go +++ b/operators/endpointmetrics/controllers/status/status_controller.go @@ -32,7 +32,7 @@ var ( hubNamespace = os.Getenv("HUB_NAMESPACE") ) -// StatusReconciler reconciles status object +// StatusReconciler reconciles status object. type StatusReconciler struct { Client client.Client Scheme *runtime.Scheme diff --git a/operators/endpointmetrics/controllers/status/status_controller_test.go b/operators/endpointmetrics/controllers/status/status_controller_test.go index 203204d21..ec25b4f4f 100644 --- a/operators/endpointmetrics/controllers/status/status_controller_test.go +++ b/operators/endpointmetrics/controllers/status/status_controller_test.go @@ -51,9 +51,9 @@ func init() { func TestStatusController(t *testing.T) { - hubClient := fake.NewFakeClient() + hubClient := fake.NewClientBuilder().Build() util.SetHubClient(hubClient) - c := fake.NewFakeClient() + c := fake.NewClientBuilder().Build() r := &StatusReconciler{ Client: c, diff --git a/operators/endpointmetrics/main.go b/operators/endpointmetrics/main.go index 78f68e3b8..cf7c864ee 100644 --- a/operators/endpointmetrics/main.go +++ b/operators/endpointmetrics/main.go @@ -80,18 +80,18 @@ func main() { namespaceSelector := fmt.Sprintf("metadata.namespace==%s", os.Getenv("WATCH_NAMESPACE")) gvkLabelMap := map[schema.GroupVersionKind][]filteredcache.Selector{ - v1.SchemeGroupVersion.WithKind("Secret"): []filteredcache.Selector{ + v1.SchemeGroupVersion.WithKind("Secret"): { {FieldSelector: namespaceSelector}, }, - v1.SchemeGroupVersion.WithKind("ConfigMap"): []filteredcache.Selector{ + v1.SchemeGroupVersion.WithKind("ConfigMap"): { {FieldSelector: namespaceSelector}, {FieldSelector: fmt.Sprintf("metadata.name==%s,metadata.namespace!=%s", operatorconfig.AllowlistCustomConfigMapName, "open-cluster-management-observability")}, }, - appsv1.SchemeGroupVersion.WithKind("Deployment"): []filteredcache.Selector{ + appsv1.SchemeGroupVersion.WithKind("Deployment"): { {FieldSelector: namespaceSelector}, }, - oav1beta1.GroupVersion.WithKind("ObservabilityAddon"): []filteredcache.Selector{ + oav1beta1.GroupVersion.WithKind("ObservabilityAddon"): { {FieldSelector: namespaceSelector}, }, } diff --git a/operators/endpointmetrics/pkg/rendering/renderer.go b/operators/endpointmetrics/pkg/rendering/renderer.go index 27125bfbe..6d6b79856 100644 --- a/operators/endpointmetrics/pkg/rendering/renderer.go +++ b/operators/endpointmetrics/pkg/rendering/renderer.go @@ -213,7 +213,7 @@ func Render( ) } // replace the hub alertmanager address. Address will be set to null when alerts are disabled - hubAmEp := strings.TrimLeft(hubInfo.AlertmanagerEndpoint, "https://") + hubAmEp := strings.TrimPrefix(hubInfo.AlertmanagerEndpoint, "https://") amConfig = strings.ReplaceAll(amConfig, "_ALERTMANAGER_ENDPOINT_", hubAmEp) s.StringData["alertmanager.yaml"] = amConfig diff --git a/operators/endpointmetrics/pkg/rendering/renderer_test.go b/operators/endpointmetrics/pkg/rendering/renderer_test.go index c895f2e44..2fb3982a4 100644 --- a/operators/endpointmetrics/pkg/rendering/renderer_test.go +++ b/operators/endpointmetrics/pkg/rendering/renderer_test.go @@ -49,8 +49,7 @@ func TestRender(t *testing.T) { AlertmanagerEndpoint: "testing.com", AlertmanagerRouterCA: "testing", } - - c := fake.NewFakeClient([]runtime.Object{getAllowlistCM()}...) + c := fake.NewClientBuilder().WithRuntimeObjects([]runtime.Object{getAllowlistCM()}...).Build() objs, err := Render(renderer, c, hubInfo) if err != nil { diff --git a/operators/endpointmetrics/pkg/rendering/templates/templates.go b/operators/endpointmetrics/pkg/rendering/templates/templates.go index 1d9c91778..fbdb3fb19 100644 --- a/operators/endpointmetrics/pkg/rendering/templates/templates.go +++ b/operators/endpointmetrics/pkg/rendering/templates/templates.go @@ -9,7 +9,7 @@ import ( "github.com/stolostron/multicluster-observability-operator/operators/pkg/rendering/templates" ) -// GetTemplates reads base manifest +// GetTemplates reads base manifest. func GetTemplates(r *templates.TemplateRenderer) ([]*resource.Resource, error) { // resourceList contains all kustomize resources diff --git a/operators/endpointmetrics/pkg/util/client.go b/operators/endpointmetrics/pkg/util/client.go index 2f30b64cd..ea130c96a 100644 --- a/operators/endpointmetrics/pkg/util/client.go +++ b/operators/endpointmetrics/pkg/util/client.go @@ -33,7 +33,7 @@ const ( hubKubeConfigPath = "/spoke/hub-kubeconfig/kubeconfig" ) -// GetOrCreateOCPClient get an existing hub client or create new one if it doesn't exist +// GetOrCreateOCPClient get an existing hub client or create new one if it doesn't exist. func GetOrCreateHubClient(renew bool) (client.Client, error) { if os.Getenv("UNIT_TEST") == "true" { return hubClient, nil @@ -65,7 +65,7 @@ func GetOrCreateHubClient(renew bool) (client.Client, error) { return hubClient, err } -// GetOrCreateOCPClient get an existing ocp client or create new one if it doesn't exist +// GetOrCreateOCPClient get an existing ocp client or create new one if it doesn't exist. func GetOrCreateOCPClient() (ocpClientSet.Interface, error) { if ocpClient != nil { return ocpClient, nil diff --git a/operators/endpointmetrics/pkg/util/client_test.go b/operators/endpointmetrics/pkg/util/client_test.go index 4c67f3ce9..26431af55 100644 --- a/operators/endpointmetrics/pkg/util/client_test.go +++ b/operators/endpointmetrics/pkg/util/client_test.go @@ -21,14 +21,14 @@ func init() { } func TestRenewAndRetry(t *testing.T) { - hubClient := fake.NewFakeClient() + hubClient := fake.NewClientBuilder().Build() SetHubClient(hubClient) _, _, err := RenewAndRetry(context.TODO()) if err == nil { t.Fatal("missing error") } - hubClient1 := fake.NewFakeClient(newObservabilityAddon(name, testNamespace)) + hubClient1 := fake.NewClientBuilder().WithRuntimeObjects(newObservabilityAddon(name, testNamespace)).Build() SetHubClient(hubClient1) _, _, err = RenewAndRetry(context.TODO()) if err != nil { diff --git a/operators/endpointmetrics/pkg/util/status.go b/operators/endpointmetrics/pkg/util/status.go index bbaa8b81b..c0ce19109 100644 --- a/operators/endpointmetrics/pkg/util/status.go +++ b/operators/endpointmetrics/pkg/util/status.go @@ -13,19 +13,19 @@ import ( var ( conditions = map[string]map[string]string{ - "Deployed": map[string]string{ + "Deployed": { "type": "Progressing", "reason": "Deployed", "message": "Metrics collector deployed"}, - "Disabled": map[string]string{ + "Disabled": { "type": "Disabled", "reason": "Disabled", "message": "enableMetrics is set to False"}, - "Degraded": map[string]string{ + "Degraded": { "type": "Degraded", "reason": "Degraded", "message": "Metrics collector deployment not successful"}, - "NotSupported": map[string]string{ + "NotSupported": { "type": "NotSupported", "reason": "NotSupported", "message": "No Prometheus service found in this cluster"}, diff --git a/operators/endpointmetrics/pkg/util/status_test.go b/operators/endpointmetrics/pkg/util/status_test.go index 87ee89e0d..f9ea12909 100644 --- a/operators/endpointmetrics/pkg/util/status_test.go +++ b/operators/endpointmetrics/pkg/util/status_test.go @@ -59,7 +59,7 @@ func TestReportStatus(t *testing.T) { statusList := []string{"NotSupported", "Deployed", "Disabled"} s.AddKnownTypes(oav1beta1.GroupVersion, oa) - c := fake.NewFakeClient(objs...) + c := fake.NewClientBuilder().WithRuntimeObjects(objs...).Build() for i := range statusList { ReportStatus(context.TODO(), c, oa, statusList[i]) if oa.Status.Conditions[0].Message != expectedStatus[i].Message || oa.Status.Conditions[0].Reason != expectedStatus[i].Reason || oa.Status.Conditions[0].Status != expectedStatus[i].Status || oa.Status.Conditions[0].Type != expectedStatus[i].Type { diff --git a/operators/multiclusterobservability/api/shared/multiclusterobservability_shared.go b/operators/multiclusterobservability/api/shared/multiclusterobservability_shared.go index b395aa033..8b6a2638c 100644 --- a/operators/multiclusterobservability/api/shared/multiclusterobservability_shared.go +++ b/operators/multiclusterobservability/api/shared/multiclusterobservability_shared.go @@ -12,7 +12,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -// ObservabilityAddonSpec is the spec of observability addon +// ObservabilityAddonSpec is the spec of observability addon. type ObservabilityAddonSpec struct { // EnableMetrics indicates the observability addon push metrics to hub server. // +optional diff --git a/operators/multiclusterobservability/api/v1beta1/groupversion_info.go b/operators/multiclusterobservability/api/v1beta1/groupversion_info.go index 65bd9519a..11c717cd7 100644 --- a/operators/multiclusterobservability/api/v1beta1/groupversion_info.go +++ b/operators/multiclusterobservability/api/v1beta1/groupversion_info.go @@ -27,10 +27,10 @@ import ( ) var ( - // GroupVersion is group version used to register these objects + // GroupVersion is group version used to register these objects. GroupVersion = schema.GroupVersion{Group: "observability.open-cluster-management.io", Version: "v1beta1"} - // SchemeBuilder is used to add go types to the GroupVersionKind scheme + // SchemeBuilder is used to add go types to the GroupVersionKind scheme. SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} // AddToScheme adds the types in this group-version to the given scheme. diff --git a/operators/multiclusterobservability/api/v1beta1/multiclusterobservability_types.go b/operators/multiclusterobservability/api/v1beta1/multiclusterobservability_types.go index b71a95b5a..d168eacbf 100644 --- a/operators/multiclusterobservability/api/v1beta1/multiclusterobservability_types.go +++ b/operators/multiclusterobservability/api/v1beta1/multiclusterobservability_types.go @@ -17,13 +17,13 @@ import ( type AvailabilityType string const ( - // HABasic stands up most app subscriptions with a replicaCount of 1 + // HABasic stands up most app subscriptions with a replicaCount of 1. HABasic AvailabilityType = "Basic" - // HAHigh stands up most app subscriptions with a replicaCount of 2 + // HAHigh stands up most app subscriptions with a replicaCount of 2. HAHigh AvailabilityType = "High" ) -// MultiClusterObservabilitySpec defines the desired state of MultiClusterObservability +// MultiClusterObservabilitySpec defines the desired state of MultiClusterObservability. type MultiClusterObservabilitySpec struct { // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster // Important: Run "make" to regenerate code after modifying this file @@ -105,7 +105,7 @@ type StorageConfigObject struct { StatefulSetStorageClass string `json:"statefulSetStorageClass,omitempty"` } -// MultiClusterObservabilityStatus defines the observed state of MultiClusterObservability +// MultiClusterObservabilityStatus defines the observed state of MultiClusterObservability. type MultiClusterObservabilityStatus struct { // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster // Important: Run "make" to regenerate code after modifying this file diff --git a/operators/multiclusterobservability/api/v1beta2/groupversion_info.go b/operators/multiclusterobservability/api/v1beta2/groupversion_info.go index 44b4fe03f..45bd93536 100644 --- a/operators/multiclusterobservability/api/v1beta2/groupversion_info.go +++ b/operators/multiclusterobservability/api/v1beta2/groupversion_info.go @@ -27,10 +27,10 @@ import ( ) var ( - // GroupVersion is group version used to register these objects + // GroupVersion is group version used to register these objects. GroupVersion = schema.GroupVersion{Group: "observability.open-cluster-management.io", Version: "v1beta2"} - // SchemeBuilder is used to add go types to the GroupVersionKind scheme + // SchemeBuilder is used to add go types to the GroupVersionKind scheme. SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} // AddToScheme adds the types in this group-version to the given scheme. diff --git a/operators/multiclusterobservability/api/v1beta2/multiclusterobservability_types.go b/operators/multiclusterobservability/api/v1beta2/multiclusterobservability_types.go index c04e28cc4..342dbf988 100644 --- a/operators/multiclusterobservability/api/v1beta2/multiclusterobservability_types.go +++ b/operators/multiclusterobservability/api/v1beta2/multiclusterobservability_types.go @@ -10,7 +10,7 @@ import ( observabilityshared "github.com/stolostron/multicluster-observability-operator/operators/multiclusterobservability/api/shared" ) -// MultiClusterObservabilitySpec defines the desired state of MultiClusterObservability +// MultiClusterObservabilitySpec defines the desired state of MultiClusterObservability. type MultiClusterObservabilitySpec struct { // Advanced configurations for observability // +optional @@ -91,7 +91,7 @@ type CommonSpec struct { Replicas *int32 `json:"replicas,omitempty"` } -// Thanos Query Spec +// Thanos Query Spec. type QuerySpec struct { // Annotations is an unstructured key value map stored with a service account // +optional @@ -100,7 +100,7 @@ type QuerySpec struct { CommonSpec `json:",inline"` } -// Thanos Receive Spec +// Thanos Receive Spec. type ReceiveSpec struct { // Annotations is an unstructured key value map stored with a service account // +optional @@ -109,7 +109,7 @@ type ReceiveSpec struct { CommonSpec `json:",inline"` } -// Thanos Store Spec +// Thanos Store Spec. type StoreSpec struct { // Annotations is an unstructured key value map stored with a service account // +optional @@ -118,7 +118,7 @@ type StoreSpec struct { CommonSpec `json:",inline"` } -// Thanos Rule Spec +// Thanos Rule Spec. type RuleSpec struct { // Evaluation interval // +optional @@ -131,7 +131,7 @@ type RuleSpec struct { CommonSpec `json:",inline"` } -// Thanos Compact Spec +// Thanos Compact Spec. type CompactSpec struct { // Compute Resources required by the compact. // +optional @@ -220,7 +220,7 @@ type StorageConfig struct { StoreStorageSize string `json:"storeStorageSize,omitempty"` } -// MultiClusterObservabilityStatus defines the observed state of MultiClusterObservability +// MultiClusterObservabilityStatus defines the observed state of MultiClusterObservability. type MultiClusterObservabilityStatus struct { // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster // Important: Run "make" to regenerate code after modifying this file diff --git a/operators/multiclusterobservability/api/v1beta2/multiclusterobservability_webhook.go b/operators/multiclusterobservability/api/v1beta2/multiclusterobservability_webhook.go index 1d1947b39..b9c0735a0 100644 --- a/operators/multiclusterobservability/api/v1beta2/multiclusterobservability_webhook.go +++ b/operators/multiclusterobservability/api/v1beta2/multiclusterobservability_webhook.go @@ -168,7 +168,7 @@ func (mco *MultiClusterObservability) validateUpdateMultiClusterObservabilitySto return nil } -// createOrGetKubeClient creates or gets the existing kubeClient +// createOrGetKubeClient creates or gets the existing kubeClient. func createOrGetKubeClient() (kubernetes.Interface, error) { if kubeClient != nil { return kubeClient, nil @@ -180,7 +180,7 @@ func createOrGetKubeClient() (kubernetes.Interface, error) { return kubeClient, nil } -// getSelectedStorageClassForMultiClusterObservability get secected for the MultiClusterObservability CR +// getSelectedStorageClassForMultiClusterObservability get secected for the MultiClusterObservability CR. func getSelectedStorageClassForMultiClusterObservability( c kubernetes.Interface, mco *MultiClusterObservability, @@ -217,7 +217,7 @@ func getSelectedStorageClassForMultiClusterObservability( return expectedSC, nil } -// storageClassAllowVolumeExpansion check if the storageclass allow volume expansion +// storageClassAllowVolumeExpansion check if the storageclass allow volume expansion. func storageClassAllowVolumeExpansion(c kubernetes.Interface, name string) (bool, error) { sc, err := c.StorageV1().StorageClasses().Get(context.TODO(), name, metav1.GetOptions{}) if err != nil { @@ -225,7 +225,7 @@ func storageClassAllowVolumeExpansion(c kubernetes.Interface, name string) (bool } scAllowVolumeExpansion := false - // AllowVolumeExpansion may be omited with default false value + // AllowVolumeExpansion may be omitted with default false value. if sc.AllowVolumeExpansion != nil { scAllowVolumeExpansion = *sc.AllowVolumeExpansion } diff --git a/operators/multiclusterobservability/controllers/multiclusterobservability/grafana.go b/operators/multiclusterobservability/controllers/multiclusterobservability/grafana.go index a88d5720a..eb494c3e0 100644 --- a/operators/multiclusterobservability/controllers/multiclusterobservability/grafana.go +++ b/operators/multiclusterobservability/controllers/multiclusterobservability/grafana.go @@ -68,7 +68,7 @@ type SecureJsonData struct { } // GenerateGrafanaDataSource is used to generate the GrafanaDatasource as a secret. -// the GrafanaDatasource points to observatorium api gateway service +// the GrafanaDatasource points to observatorium api gateway service. func GenerateGrafanaDataSource( c client.Client, scheme *runtime.Scheme, diff --git a/operators/multiclusterobservability/controllers/multiclusterobservability/multiclusterobservability_controller.go b/operators/multiclusterobservability/controllers/multiclusterobservability/multiclusterobservability_controller.go index 71f654040..66fa538fc 100644 --- a/operators/multiclusterobservability/controllers/multiclusterobservability/multiclusterobservability_controller.go +++ b/operators/multiclusterobservability/controllers/multiclusterobservability/multiclusterobservability_controller.go @@ -5,6 +5,7 @@ package multiclusterobservability import ( "context" + cerr "errors" "fmt" "os" "reflect" @@ -12,11 +13,11 @@ import ( "github.com/go-logr/logr" routev1 "github.com/openshift/api/route/v1" + "golang.org/x/exp/slices" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" storev1 "k8s.io/api/storage/v1" - "k8s.io/apimachinery/pkg/api/errors" apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/api/resource" @@ -39,7 +40,6 @@ import ( mcov1beta2 "github.com/stolostron/multicluster-observability-operator/operators/multiclusterobservability/api/v1beta2" placementctrl "github.com/stolostron/multicluster-observability-operator/operators/multiclusterobservability/controllers/placementrule" - "github.com/stolostron/multicluster-observability-operator/operators/multiclusterobservability/pkg/certificates" certctrl "github.com/stolostron/multicluster-observability-operator/operators/multiclusterobservability/pkg/certificates" "github.com/stolostron/multicluster-observability-operator/operators/multiclusterobservability/pkg/config" "github.com/stolostron/multicluster-observability-operator/operators/multiclusterobservability/pkg/rendering" @@ -53,7 +53,7 @@ import ( const ( resFinalizer = "observability.open-cluster-management.io/res-cleanup" - // deprecated one + // deprecated one. certFinalizer = "observability.open-cluster-management.io/cert-cleanup" ) @@ -64,7 +64,6 @@ const ( var ( log = logf.Log.WithName("controller_multiclustermonitoring") - enableHubRemoteWrite = os.Getenv("ENABLE_HUB_REMOTEWRITE") isAlertmanagerStorageSizeChanged = false isCompactStorageSizeChanged = false isRuleStorageSizeChanged = false @@ -138,7 +137,7 @@ func (r *MultiClusterObservabilityReconciler) Reconcile(ctx context.Context, req // start to update mco status StartStatusUpdate(r.Client, instance) - ingressCtlCrdExists, _ := r.CRDMap[config.IngressControllerCRD] + ingressCtlCrdExists := r.CRDMap[config.IngressControllerCRD] if os.Getenv("UNIT_TEST") != "true" { // start placement controller err := placementctrl.StartPlacementController(r.Manager, r.CRDMap) @@ -162,7 +161,7 @@ func (r *MultiClusterObservabilityReconciler) Reconcile(ctx context.Context, req } // check if the MCH CRD exists - mchCrdExists, _ := r.CRDMap[config.MCHCrdName] + mchCrdExists := r.CRDMap[config.MCHCrdName] // requeue after 10 seconds if the mch crd exists and image image manifests map is empty if mchCrdExists && len(config.GetImageManifests()) == 0 { // if the mch CR is not ready, then requeue the request after 10s @@ -283,7 +282,7 @@ func (r *MultiClusterObservabilityReconciler) Reconcile(ctx context.Context, req } // create the certificates - err = certificates.CreateObservabilityCerts(r.Client, r.Scheme, instance, ingressCtlCrdExists) + err = certctrl.CreateObservabilityCerts(r.Client, r.Scheme, instance, ingressCtlCrdExists) if err != nil { return ctrl.Result{}, err } @@ -300,7 +299,7 @@ func (r *MultiClusterObservabilityReconciler) Reconcile(ctx context.Context, req return *result, err } - svmCrdExists, _ := r.CRDMap[config.StorageVersionMigrationCrdName] + svmCrdExists := r.CRDMap[config.StorageVersionMigrationCrdName] if svmCrdExists { // create or update the storage version migration resource err = createOrUpdateObservabilityStorageVersionMigrationResource(r.Client, r.Scheme, instance) @@ -315,15 +314,9 @@ func (r *MultiClusterObservabilityReconciler) Reconcile(ctx context.Context, req return ctrl.Result{}, nil } -// labelsForMultiClusterMonitoring returns the labels for selecting the resources -// belonging to the given MultiClusterObservability CR name. -func labelsForMultiClusterMonitoring(name string) map[string]string { - return map[string]string{"observability.open-cluster-management.io/name": name} -} - func (r *MultiClusterObservabilityReconciler) initFinalization( mco *mcov1beta2.MultiClusterObservability) (bool, error) { - if mco.GetDeletionTimestamp() != nil && commonutil.Contains(mco.GetFinalizers(), resFinalizer) { + if mco.GetDeletionTimestamp() != nil && slices.Contains(mco.GetFinalizers(), resFinalizer) { log.Info("To delete resources across namespaces") // clean up the cluster resources, eg. clusterrole, clusterrolebinding, etc if err := cleanUpClusterScopedResources(r, mco); err != nil { @@ -347,7 +340,7 @@ func (r *MultiClusterObservabilityReconciler) initFinalization( return true, nil } - if !commonutil.Contains(mco.GetFinalizers(), resFinalizer) { + if !slices.Contains(mco.GetFinalizers(), resFinalizer) { mco.SetFinalizers(commonutil.Remove(mco.GetFinalizers(), certFinalizer)) mco.SetFinalizers(append(mco.GetFinalizers(), resFinalizer)) err := r.Client.Update(context.TODO(), mco) @@ -561,7 +554,7 @@ func (r *MultiClusterObservabilityReconciler) SetupWithManager(mgr ctrl.Manager) }, } - mchCrdExists, _ := r.CRDMap[config.MCHCrdName] + mchCrdExists := r.CRDMap[config.MCHCrdName] if mchCrdExists { // secondary watch for MCH ctrBuilder = ctrBuilder.Watches( @@ -672,16 +665,12 @@ func (r *MultiClusterObservabilityReconciler) HandleStorageSizeChange( } func updateStorageSizeChange(c client.Client, matchLabels map[string]string, storageSize string) error { - - pvcList := []corev1.PersistentVolumeClaim{} - stsList := []appsv1.StatefulSet{} - pvcList, err := commonutil.GetPVCList(c, config.GetDefaultNamespace(), matchLabels) if err != nil { return err } - stsList, err = commonutil.GetStatefulSetList(c, config.GetDefaultNamespace(), matchLabels) + stsList, err := commonutil.GetStatefulSetList(c, config.GetDefaultNamespace(), matchLabels) if err != nil { return err } @@ -702,7 +691,7 @@ func updateStorageSizeChange(c client.Client, matchLabels map[string]string, sto // update sts for index, sts := range stsList { err := c.Delete(context.TODO(), &stsList[index], &client.DeleteOptions{}) - if err != nil && !errors.IsNotFound(err) { + if err != nil && !apierrors.IsNotFound(err) { return err } log.Info("Successfully delete sts due to storage size changed", "sts", sts.Name) @@ -752,19 +741,19 @@ func GenerateAlertmanagerRoute( log.Info("BYO CA/Certificate found for the Route of Alertmanager, will using BYO CA/certificate for the Route of Alertmanager") amRouteCA, ok := amRouteBYOCaSrt.Data["tls.crt"] if !ok { - return &ctrl.Result{}, fmt.Errorf("Invalid BYO CA for the Route of Alertmanager") + return &ctrl.Result{}, cerr.New("Invalid BYO CA for the Route of Alertmanager") } amGateway.Spec.TLS.CACertificate = string(amRouteCA) amRouteCert, ok := amRouteBYOCertSrt.Data["tls.crt"] if !ok { - return &ctrl.Result{}, fmt.Errorf("Invalid BYO Certificate for the Route of Alertmanager") + return &ctrl.Result{}, cerr.New("Invalid BYO Certificate for the Route of Alertmanager") } amGateway.Spec.TLS.Certificate = string(amRouteCert) amRouteCertKey, ok := amRouteBYOCertSrt.Data["tls.key"] if !ok { - return &ctrl.Result{}, fmt.Errorf("Invalid BYO Certificate Key for the Route of Alertmanager") + return &ctrl.Result{}, cerr.New("Invalid BYO Certificate Key for the Route of Alertmanager") } amGateway.Spec.TLS.Key = string(amRouteCertKey) } @@ -780,7 +769,7 @@ func GenerateAlertmanagerRoute( types.NamespacedName{Name: amGateway.Name, Namespace: amGateway.Namespace}, found, ) - if err != nil && errors.IsNotFound(err) { + if err != nil && apierrors.IsNotFound(err) { log.Info( "Creating a new route to expose alertmanager", "amGateway.Namespace", @@ -846,19 +835,19 @@ func GenerateProxyRoute( log.Info("BYO CA/Certificate found for the Route of Proxy, will using BYO CA/certificate for the Route of Proxy") proxyRouteCA, ok := proxyRouteBYOCaSrt.Data["tls.crt"] if !ok { - return &ctrl.Result{}, fmt.Errorf("Invalid BYO CA for the Route of Proxy") + return &ctrl.Result{}, cerr.New("Invalid BYO CA for the Route of Proxy") } proxyGateway.Spec.TLS.CACertificate = string(proxyRouteCA) proxyRouteCert, ok := proxyRouteBYOCertSrt.Data["tls.crt"] if !ok { - return &ctrl.Result{}, fmt.Errorf("Invalid BYO Certificate for the Route of Proxy") + return &ctrl.Result{}, cerr.New("Invalid BYO Certificate for the Route of Proxy") } proxyGateway.Spec.TLS.Certificate = string(proxyRouteCert) proxyRouteCertKey, ok := proxyRouteBYOCertSrt.Data["tls.key"] if !ok { - return &ctrl.Result{}, fmt.Errorf("Invalid BYO Certificate Key for the Route of Proxy") + return &ctrl.Result{}, cerr.New("Invalid BYO Certificate Key for the Route of Proxy") } proxyGateway.Spec.TLS.Key = string(proxyRouteCertKey) } @@ -874,7 +863,7 @@ func GenerateProxyRoute( types.NamespacedName{Name: proxyGateway.Name, Namespace: proxyGateway.Namespace}, found, ) - if err != nil && errors.IsNotFound(err) { + if err != nil && apierrors.IsNotFound(err) { log.Info( "Creating a new route to expose rbac proxy", "proxyGateway.Namespace", @@ -933,7 +922,7 @@ func cleanUpClusterScopedResources( } } - ingressCtlCrdExists, _ := r.CRDMap[config.IngressControllerCRD] + ingressCtlCrdExists := r.CRDMap[config.IngressControllerCRD] if ingressCtlCrdExists { return DeleteGrafanaOauthClient(r.Client) } diff --git a/operators/multiclusterobservability/controllers/multiclusterobservability/multiclusterobservability_controller_test.go b/operators/multiclusterobservability/controllers/multiclusterobservability/multiclusterobservability_controller_test.go index 26924a1d5..99167d64f 100644 --- a/operators/multiclusterobservability/controllers/multiclusterobservability/multiclusterobservability_controller_test.go +++ b/operators/multiclusterobservability/controllers/multiclusterobservability/multiclusterobservability_controller_test.go @@ -5,21 +5,18 @@ package multiclusterobservability import ( "context" - "fmt" "os" "path" "strings" "testing" "time" - configv1 "github.com/openshift/api/config/v1" oauthv1 "github.com/openshift/api/oauth/v1" routev1 "github.com/openshift/api/route/v1" observatoriumv1alpha1 "github.com/stolostron/observatorium-operator/api/v1alpha1" "gopkg.in/yaml.v2" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" - apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1" "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -61,7 +58,7 @@ func setupTest(t *testing.T) func() { //clean up the manifest path if left over from previous test if fi, err := os.Lstat(testManifestsPath); err == nil && fi.Mode()&os.ModeSymlink != 0 { if err = os.Remove(testManifestsPath); err != nil { - t.Logf(fmt.Sprintf("Failed to delete symlink(%s) for the test manifests: (%v)", testManifestsPath, err)) + t.Logf("Failed to delete symlink(%s) for the test manifests: (%v)", testManifestsPath, err) } } err = os.Symlink(manifestsPath, testManifestsPath) @@ -73,7 +70,7 @@ func setupTest(t *testing.T) func() { return func() { t.Log("begin teardownTest") if err = os.Remove(testManifestsPath); err != nil { - t.Logf(fmt.Sprintf("Failed to delete symbollink(%s) for the test manifests: (%v)", testManifestsPath, err)) + t.Logf("Failed to delete symbollink(%s) for the test manifests: (%v)", testManifestsPath, err) } os.Remove(path.Join(wd, "../../tests")) os.Unsetenv("TEMPLATES_PATH") @@ -137,15 +134,6 @@ func newMCHInstanceWithVersion(namespace, version string) *mchv1.MultiClusterHub } } -func TestLabelsForMultiClusterMonitoring(t *testing.T) { - lab := labelsForMultiClusterMonitoring("test") - - value, _ := lab["observability.open-cluster-management.io/name"] - if value != "test" { - t.Errorf("value (%v) is not the expected (test)", value) - } -} - func createObservatoriumAPIService(name, namespace string) *corev1.Service { return &corev1.Service{ TypeMeta: metav1.TypeMeta{ @@ -268,37 +256,6 @@ func createFailedDeployment(name, namespace string) *appsv1.Deployment { } } -func createClusterVersion() *configv1.ClusterVersion { - return &configv1.ClusterVersion{ - ObjectMeta: metav1.ObjectMeta{Name: "version"}, - Spec: configv1.ClusterVersionSpec{ - ClusterID: configv1.ClusterID("xxx-xxxxxx-xxxx"), - }, - } -} - -func createMultiClusterHubCRD() *apiextensionsv1beta1.CustomResourceDefinition { - return &apiextensionsv1beta1.CustomResourceDefinition{ - ObjectMeta: metav1.ObjectMeta{Name: config.MCHCrdName}, - Spec: apiextensionsv1beta1.CustomResourceDefinitionSpec{ - Scope: apiextensionsv1beta1.NamespaceScoped, - Conversion: &apiextensionsv1beta1.CustomResourceConversion{Strategy: apiextensionsv1beta1.NoneConverter}, - Group: "operator.open-cluster-management.io", - Names: apiextensionsv1beta1.CustomResourceDefinitionNames{ - Kind: "MultiClusterHub", - ListKind: "MultiClusterHubList", - Plural: "multiclusterhubs", - ShortNames: []string{"mch"}, - Singular: "multiclusterhub", - }, - Version: "v1", - Versions: []apiextensionsv1beta1.CustomResourceDefinitionVersion{ - {Name: "v1", Storage: true, Served: true}, - }, - }, - } -} - func TestMultiClusterMonitoringCRUpdate(t *testing.T) { var ( name = "monitoring" @@ -360,7 +317,7 @@ func TestMultiClusterMonitoringCRUpdate(t *testing.T) { objs := []runtime.Object{mco, svc, serverCACerts, clientCACerts, proxyRouteBYOCACerts, grafanaCert, serverCert, testAmRouteBYOCaSecret, testAmRouteBYOCertSecret, proxyRouteBYOCert, clustermgmtAddon} // Create a fake client to mock API calls. - cl := fake.NewFakeClient(objs...) + cl := fake.NewClientBuilder().WithRuntimeObjects(objs...).Build() // Create a ReconcileMemcached object with the scheme and fake client. r := &MultiClusterObservabilityReconciler{Client: cl, Scheme: s, CRDMap: map[string]bool{config.IngressControllerCRD: true}} @@ -743,7 +700,7 @@ func TestImageReplaceForMCO(t *testing.T) { objs := []runtime.Object{mco, observatoriumAPIsvc, serverCACerts, clientCACerts, grafanaCert, serverCert, testMCHInstance, imageManifestsCM, testAmRouteBYOCaSecret, testAmRouteBYOCertSecret, clustermgmtAddon} // Create a fake client to mock API calls. - cl := fake.NewFakeClient(objs...) + cl := fake.NewClientBuilder().WithRuntimeObjects(objs...).Build() // Create a ReconcileMemcached object with the scheme and fake client. r := &MultiClusterObservabilityReconciler{Client: cl, Scheme: s, CRDMap: map[string]bool{config.MCHCrdName: true, config.IngressControllerCRD: true}} @@ -887,7 +844,7 @@ func TestCheckObjStorageStatus(t *testing.T) { s := scheme.Scheme mcov1beta2.SchemeBuilder.AddToScheme(s) objs := []runtime.Object{mco} - c := fake.NewFakeClient(objs...) + c := fake.NewClientBuilder().WithRuntimeObjects(objs...).Build() mcoCondition := checkObjStorageStatus(c, mco) if mcoCondition == nil { t.Errorf("check s3 conf failed: got %v, expected non-nil", mcoCondition) @@ -938,7 +895,7 @@ func TestHandleStorageSizeChange(t *testing.T) { createStatefulSet(mco.Name, config.GetDefaultNamespace(), "test"), createPersistentVolumeClaim(mco.Name, config.GetDefaultNamespace(), "test"), } - c := fake.NewFakeClient(objs...) + c := fake.NewClientBuilder().WithRuntimeObjects(objs...).Build() r := &MultiClusterObservabilityReconciler{Client: c, Scheme: s} isAlertmanagerStorageSizeChanged = true r.HandleStorageSizeChange(mco) diff --git a/operators/multiclusterobservability/controllers/multiclusterobservability/multiclusterobservability_status.go b/operators/multiclusterobservability/controllers/multiclusterobservability/multiclusterobservability_status.go index 6deaaa543..4d899a6ad 100644 --- a/operators/multiclusterobservability/controllers/multiclusterobservability/multiclusterobservability_status.go +++ b/operators/multiclusterobservability/controllers/multiclusterobservability/multiclusterobservability_status.go @@ -129,16 +129,13 @@ func checkReadyStatus(c client.Client, mco *mcov1beta2.MultiClusterObservability return false } - deployStatus := checkDeployStatus(c, mco) + deployStatus := checkDeployStatus(c) if deployStatus != nil { return false } - statefulStatus := checkStatefulSetStatus(c, mco) - if statefulStatus != nil { - return false - } - return true + statefulStatus := checkStatefulSetStatus(c) + return statefulStatus == nil } func updateReadyStatus( @@ -156,13 +153,13 @@ func updateReadyStatus( return } - deployStatus := checkDeployStatus(c, mco) + deployStatus := checkDeployStatus(c) if deployStatus != nil { setStatusCondition(conditions, *deployStatus) return } - statefulStatus := checkStatefulSetStatus(c, mco) + statefulStatus := checkStatefulSetStatus(c) if statefulStatus != nil { setStatusCondition(conditions, *statefulStatus) return @@ -174,10 +171,10 @@ func updateReadyStatus( // setStatusCondition sets the corresponding condition in conditions to newCondition. // conditions must be non-nil. -// 1. if the condition of the specified type already exists (all fields of the existing condition are updated to -// newCondition, LastTransitionTime is set to now if the new status differs from the old status) -// 2. if a condition of the specified type does not exist (LastTransitionTime is set to now() if unset, -// and newCondition is appended) +// 1. if the condition of the specified type already exists (all fields of the existing condition are updated to +// newCondition, LastTransitionTime is set to now if the new status differs from the old status) +// 2. if a condition of the specified type does not exist (LastTransitionTime is set to now() if unset, +// and newCondition is appended) func setStatusCondition(conditions *[]mcoshared.Condition, newCondition mcoshared.Condition) { if conditions == nil { return @@ -254,9 +251,7 @@ func getExpectedDeploymentNames() []string { } } -func checkDeployStatus( - c client.Client, - mco *mcov1beta2.MultiClusterObservability) *mcoshared.Condition { +func checkDeployStatus(c client.Client) *mcoshared.Condition { expectedDeploymentNames := getExpectedDeploymentNames() for _, name := range expectedDeploymentNames { found := &appsv1.Deployment{} @@ -290,9 +285,7 @@ func getExpectedStatefulSetNames() []string { } } -func checkStatefulSetStatus( - c client.Client, - mco *mcov1beta2.MultiClusterObservability) *mcoshared.Condition { +func checkStatefulSetStatus(c client.Client) *mcoshared.Condition { expectedStatefulSetNames := getExpectedStatefulSetNames() for _, name := range expectedStatefulSetNames { found := &appsv1.StatefulSet{} diff --git a/operators/multiclusterobservability/controllers/multiclusterobservability/multiclusterobservability_status_test.go b/operators/multiclusterobservability/controllers/multiclusterobservability/multiclusterobservability_status_test.go index a99d06351..e8c955866 100644 --- a/operators/multiclusterobservability/controllers/multiclusterobservability/multiclusterobservability_status_test.go +++ b/operators/multiclusterobservability/controllers/multiclusterobservability/multiclusterobservability_status_test.go @@ -228,7 +228,7 @@ func TestStartStatusUpdate(t *testing.T) { mcov1beta2.SchemeBuilder.AddToScheme(s) objs := []runtime.Object{mco, createSecret("test", "test", mcoconfig.GetMCONamespace())} - cl := fake.NewFakeClient(objs...) + cl := fake.NewClientBuilder().WithRuntimeObjects(objs...).Build() StartStatusUpdate(cl, mco) diff --git a/operators/multiclusterobservability/controllers/multiclusterobservability/observatorium.go b/operators/multiclusterobservability/controllers/multiclusterobservability/observatorium.go index 8812cddb9..9c7ce3021 100644 --- a/operators/multiclusterobservability/controllers/multiclusterobservability/observatorium.go +++ b/operators/multiclusterobservability/controllers/multiclusterobservability/observatorium.go @@ -15,6 +15,7 @@ import ( routev1 "github.com/openshift/api/route/v1" obsv1alpha1 "github.com/stolostron/observatorium-operator/api/v1alpha1" + "golang.org/x/exp/slices" "gopkg.in/yaml.v2" appsv1 "k8s.io/api/apps/v1" v1 "k8s.io/api/core/v1" @@ -30,7 +31,6 @@ import ( oashared "github.com/stolostron/multicluster-observability-operator/operators/multiclusterobservability/api/shared" mcov1beta2 "github.com/stolostron/multicluster-observability-operator/operators/multiclusterobservability/api/v1beta2" - "github.com/stolostron/multicluster-observability-operator/operators/multiclusterobservability/pkg/config" mcoconfig "github.com/stolostron/multicluster-observability-operator/operators/multiclusterobservability/pkg/config" mcoutil "github.com/stolostron/multicluster-observability-operator/operators/multiclusterobservability/pkg/util" "github.com/stolostron/multicluster-observability-operator/operators/pkg/util" @@ -196,7 +196,7 @@ func updateTenantID( newSpec.API.Tenants[idx].ID = oldTenant.ID for j, hashring := range newSpec.Hashrings { - if util.Contains(hashring.Tenants, newTenant.ID) { + if slices.Contains(hashring.Tenants, newTenant.ID) { newSpec.Hashrings[j].Tenants = util.Remove(newSpec.Hashrings[j].Tenants, newTenant.ID) newSpec.Hashrings[j].Tenants = append(newSpec.Hashrings[0].Tenants, oldTenant.ID) } @@ -251,9 +251,7 @@ func GenerateAPIGatewayRoute( return nil, nil } -func newDefaultObservatoriumSpec(cl client.Client, mco *mcov1beta2.MultiClusterObservability, - scSelected string, tlsSecretMountPath string) (*obsv1alpha1.ObservatoriumSpec, error) { - +func newDefaultObservatoriumSpec(cl client.Client, mco *mcov1beta2.MultiClusterObservability, scSelected string, tlsSecretMountPath string) (*obsv1alpha1.ObservatoriumSpec, error) { obs := &obsv1alpha1.ObservatoriumSpec{} obs.SecurityContext = &v1.SecurityContext{} obs.PullSecret = mcoconfig.GetImagePullSecret(mco.Spec) @@ -279,6 +277,13 @@ func newDefaultObservatoriumSpec(cl client.Client, mco *mcov1beta2.MultiClusterO obs.ObjectStorageConfig.Thanos.Name = objStorageConf.Name obs.ObjectStorageConfig.Thanos.Key = objStorageConf.Key obs.ObjectStorageConfig.Thanos.TLSSecretName = objStorageConf.TLSSecretName + + // Prefer using TLSSecretMountPath from the objstore config, rather than fetched one from secret. + obs.ObjectStorageConfig.Thanos.TLSSecretMountPath = tlsSecretMountPath + if objStorageConf.TLSSecretMountPath != "" { + obs.ObjectStorageConfig.Thanos.TLSSecretMountPath = objStorageConf.TLSSecretMountPath + } + obs.ObjectStorageConfig.Thanos.TLSSecretMountPath = objStorageConf.TLSSecretMountPath obs.ObjectStorageConfig.Thanos.ServiceAccountProjection = mco.Spec.StorageConfig.MetricObjectStorage.ServiceAccountProjection @@ -332,7 +337,7 @@ func newAPIRBAC() obsv1alpha1.APIRBAC { }, Subjects: []obsv1alpha1.Subject{ { - Name: config.GrafanaCN, + Name: mcoconfig.GrafanaCN, Kind: obsv1alpha1.User, }, }, @@ -344,7 +349,7 @@ func newAPIRBAC() obsv1alpha1.APIRBAC { }, Subjects: []obsv1alpha1.Subject{ { - Name: config.ManagedClusterOU, + Name: mcoconfig.ManagedClusterOU, Kind: obsv1alpha1.Group, }, }, @@ -359,7 +364,7 @@ func newAPITenants() []obsv1alpha1.APITenant { Name: mcoconfig.GetDefaultTenantName(), ID: mcoconfig.GetTenantUID(), MTLS: &obsv1alpha1.TenantMTLS{ - SecretName: config.ClientCACerts, + SecretName: mcoconfig.ClientCACerts, CAKey: "tls.crt", }, }, @@ -368,11 +373,11 @@ func newAPITenants() []obsv1alpha1.APITenant { func newAPITLS() obsv1alpha1.TLS { return obsv1alpha1.TLS{ - SecretName: config.ServerCerts, + SecretName: mcoconfig.ServerCerts, CertKey: "tls.crt", KeyKey: "tls.key", CAKey: "ca.crt", - ServerName: config.ServerCertCN, + ServerName: mcoconfig.ServerCertCN, } } @@ -390,13 +395,13 @@ func applyEndpointsSecret(c client.Client, eps []mcoutil.RemoteWriteEndpointWith }, ObjectMeta: metav1.ObjectMeta{ Name: endpointsConfigName, - Namespace: config.GetDefaultNamespace(), + Namespace: mcoconfig.GetDefaultNamespace(), }, Data: epsYamlMap, } found := &v1.Secret{} err = c.Get(context.TODO(), types.NamespacedName{Name: endpointsConfigName, - Namespace: config.GetDefaultNamespace()}, found) + Namespace: mcoconfig.GetDefaultNamespace()}, found) if err != nil { if k8serrors.IsNotFound(err) { err = c.Create(context.TODO(), epsSecret) @@ -413,8 +418,8 @@ func applyEndpointsSecret(c client.Client, eps []mcoutil.RemoteWriteEndpointWith if err != nil { return err } - err = util.UpdateDeployLabel(c, config.GetOperandName(config.ObservatoriumAPI), - config.GetDefaultNamespace(), endpointsRestartLabel) + err = util.UpdateDeployLabel(c, mcoconfig.GetOperandName(mcoconfig.ObservatoriumAPI), + mcoconfig.GetDefaultNamespace(), endpointsRestartLabel) if err != nil { return err } @@ -431,7 +436,7 @@ func newAPISpec(c client.Client, mco *mcov1beta2.MultiClusterObservability) (obs apiSpec.TLS = newAPITLS() apiSpec.Replicas = mcoconfig.GetReplicas(mcoconfig.ObservatoriumAPI, mco.Spec.AdvancedConfig) if !mcoconfig.WithoutResourcesRequests(mco.GetAnnotations()) { - apiSpec.Resources = mcoconfig.GetResources(config.ObservatoriumAPI, mco.Spec.AdvancedConfig) + apiSpec.Resources = mcoconfig.GetResources(mcoconfig.ObservatoriumAPI, mco.Spec.AdvancedConfig) } //set the default observatorium components' image apiSpec.Image = mcoconfig.DefaultImgRepository + "/" + mcoconfig.ObservatoriumAPIImgName + @@ -462,7 +467,7 @@ func newAPISpec(c client.Client, mco *mcov1beta2.MultiClusterObservability) (obs data, ok := storageSecret.Data[storageConfig.Key] if !ok { log.Error(err, "Invalid key in secret", "name", storageConfig.Name, "key", storageConfig.Key) - return apiSpec, errors.New(fmt.Sprintf("Invalid key %s in secret %s", storageConfig.Key, storageConfig.Name)) + return apiSpec, fmt.Errorf("Invalid key %s in secret %s", storageConfig.Key, storageConfig.Name) } ep := &mcoutil.RemoteWriteEndpointWithSecret{} err = yaml.Unmarshal(data, ep) @@ -524,12 +529,12 @@ func newReceiversSpec( if *receSpec.Replicas < 3 { receSpec.ReplicationFactor = receSpec.Replicas } else { - receSpec.ReplicationFactor = &config.Replicas3 + receSpec.ReplicationFactor = &mcoconfig.Replicas3 } receSpec.ServiceMonitor = true if !mcoconfig.WithoutResourcesRequests(mco.GetAnnotations()) { - receSpec.Resources = mcoconfig.GetResources(config.ThanosReceive, mco.Spec.AdvancedConfig) + receSpec.Resources = mcoconfig.GetResources(mcoconfig.ThanosReceive, mco.Spec.AdvancedConfig) } receSpec.VolumeClaimTemplate = newVolumeClaimTemplate( mco.Spec.StorageConfig.ReceiveStorageSize, @@ -568,7 +573,7 @@ func newRuleSpec(mco *mcov1beta2.MultiClusterObservability, scSelected string) o ruleSpec.ServiceMonitor = true if !mcoconfig.WithoutResourcesRequests(mco.GetAnnotations()) { - ruleSpec.Resources = mcoconfig.GetResources(config.ThanosRule, mco.Spec.AdvancedConfig) + ruleSpec.Resources = mcoconfig.GetResources(mcoconfig.ThanosRule, mco.Spec.AdvancedConfig) ruleSpec.ReloaderResources = v1.ResourceRequirements{ Requests: v1.ResourceList{ v1.ResourceName(v1.ResourceCPU): resource.MustParse(mcoconfig.ThanosRuleReloaderCPURequets), @@ -641,7 +646,7 @@ func newRuleSpec(mco *mcov1beta2.MultiClusterObservability, scSelected string) o func newStoreSpec(mco *mcov1beta2.MultiClusterObservability, scSelected string) obsv1alpha1.StoreSpec { storeSpec := obsv1alpha1.StoreSpec{} if !mcoconfig.WithoutResourcesRequests(mco.GetAnnotations()) { - storeSpec.Resources = mcoconfig.GetResources(config.ThanosStoreShard, mco.Spec.AdvancedConfig) + storeSpec.Resources = mcoconfig.GetResources(mcoconfig.ThanosStoreShard, mco.Spec.AdvancedConfig) } storeSpec.VolumeClaimTemplate = newVolumeClaimTemplate( @@ -740,7 +745,7 @@ func newQueryFrontendSpec(mco *mcov1beta2.MultiClusterObservability) obsv1alpha1 queryFrontendSpec.Replicas = mcoconfig.GetReplicas(mcoconfig.ThanosQueryFrontend, mco.Spec.AdvancedConfig) queryFrontendSpec.ServiceMonitor = true if !mcoconfig.WithoutResourcesRequests(mco.GetAnnotations()) { - queryFrontendSpec.Resources = mcoconfig.GetResources(config.ThanosQueryFrontend, mco.Spec.AdvancedConfig) + queryFrontendSpec.Resources = mcoconfig.GetResources(mcoconfig.ThanosQueryFrontend, mco.Spec.AdvancedConfig) } queryFrontendSpec.Cache = newMemCacheSpec(mcoconfig.ThanosQueryFrontendMemcached, mco) return queryFrontendSpec @@ -756,7 +761,7 @@ func newQuerySpec(mco *mcov1beta2.MultiClusterObservability) obsv1alpha1.QuerySp querySpec.LookbackDelta = fmt.Sprintf("%ds", mco.Spec.ObservabilityAddonSpec.Interval*2) } if !mcoconfig.WithoutResourcesRequests(mco.GetAnnotations()) { - querySpec.Resources = mcoconfig.GetResources(config.ThanosQuery, mco.Spec.AdvancedConfig) + querySpec.Resources = mcoconfig.GetResources(mcoconfig.ThanosQuery, mco.Spec.AdvancedConfig) } if mco.Spec.AdvancedConfig != nil && mco.Spec.AdvancedConfig.Query != nil && mco.Spec.AdvancedConfig.Query.ServiceAccountAnnotations != nil { @@ -799,7 +804,7 @@ func newCompactSpec(mco *mcov1beta2.MultiClusterObservability, scSelected string //Compactions are needed from time to time, only when new blocks appear. compactSpec.Replicas = &mcoconfig.Replicas1 if !mcoconfig.WithoutResourcesRequests(mco.GetAnnotations()) { - compactSpec.Resources = mcoconfig.GetResources(config.ThanosCompact, mco.Spec.AdvancedConfig) + compactSpec.Resources = mcoconfig.GetResources(mcoconfig.ThanosCompact, mco.Spec.AdvancedConfig) } compactSpec.ServiceMonitor = true compactSpec.EnableDownsampling = mco.Spec.EnableDownsampling @@ -857,19 +862,6 @@ func newVolumeClaimTemplate(size string, storageClass string) obsv1alpha1.Volume return vct } -func mergeVolumeClaimTemplate(oldVolumn, - newVolumn obsv1alpha1.VolumeClaimTemplate) obsv1alpha1.VolumeClaimTemplate { - requestRes := newVolumn.Spec.Resources.Requests - limitRes := newVolumn.Spec.Resources.Limits - if requestRes != nil { - oldVolumn.Spec.Resources.Requests[v1.ResourceStorage] = requestRes[v1.ResourceStorage] - } - if limitRes != nil { - oldVolumn.Spec.Resources.Limits[v1.ResourceStorage] = limitRes[v1.ResourceStorage] - } - return oldVolumn -} - func deleteStoreSts(cl client.Client, name string, oldNum int32, newNum int32) error { if oldNum > newNum { for i := newNum; i < oldNum; i++ { @@ -898,13 +890,12 @@ func deleteStoreSts(cl client.Client, name string, oldNum int32, newNum int32) e } func addBackupLabel(c client.Client, name string, backupS *v1.Secret) error { - if _, ok := config.BackupResourceMap[name]; !ok { + if _, ok := mcoconfig.BackupResourceMap[name]; !ok { log.Info("Adding backup label", "Secret", name) - config.BackupResourceMap[name] = config.ResourceTypeSecret + mcoconfig.BackupResourceMap[name] = mcoconfig.ResourceTypeSecret var err error - err = nil if backupS == nil { - err = mcoutil.AddBackupLabelToSecret(c, name, config.GetDefaultNamespace()) + err = mcoutil.AddBackupLabelToSecret(c, name, mcoconfig.GetDefaultNamespace()) } else { err = mcoutil.AddBackupLabelToSecretObj(c, backupS) } diff --git a/operators/multiclusterobservability/controllers/multiclusterobservability/observatorium_test.go b/operators/multiclusterobservability/controllers/multiclusterobservability/observatorium_test.go index 86de27eec..a32dd34f1 100644 --- a/operators/multiclusterobservability/controllers/multiclusterobservability/observatorium_test.go +++ b/operators/multiclusterobservability/controllers/multiclusterobservability/observatorium_test.go @@ -91,7 +91,7 @@ func TestNewDefaultObservatoriumSpec(t *testing.T) { objs := []runtime.Object{mco, writeStorageS} // Create a fake client to mock API calls. - cl := fake.NewFakeClient(objs...) + cl := fake.NewClientBuilder().WithRuntimeObjects(objs...).Build() obs, _ := newDefaultObservatoriumSpec(cl, mco, storageClassName, "") @@ -134,15 +134,6 @@ func TestNewDefaultObservatoriumSpec(t *testing.T) { } } -func TestMergeVolumeClaimTemplate(t *testing.T) { - vct1 := newVolumeClaimTemplate("1Gi", "test") - vct3 := newVolumeClaimTemplate("3Gi", "test") - mergeVolumeClaimTemplate(vct1, vct3) - if vct1.Spec.Resources.Requests[v1.ResourceStorage] != resource.MustParse("3Gi") { - t.Errorf("Failed to merge %v to %v", vct3, vct1) - } -} - func TestNoUpdateObservatoriumCR(t *testing.T) { var ( namespace = mcoconfig.GetDefaultNamespace() @@ -183,7 +174,7 @@ func TestNoUpdateObservatoriumCR(t *testing.T) { objs := []runtime.Object{mco} // Create a fake client to mock API calls. - cl := fake.NewFakeClient(objs...) + cl := fake.NewClientBuilder().WithRuntimeObjects(objs...).Build() mcoconfig.SetOperandNames(cl) _, err := GenerateObservatoriumCR(cl, s, mco) @@ -308,7 +299,7 @@ config: }, } - client := fake.NewFakeClient([]runtime.Object{}...) + client := fake.NewClientBuilder().Build() for _, c := range testCaseList { err := client.Create(context.TODO(), c.secret) if err != nil { diff --git a/operators/multiclusterobservability/controllers/multiclusterobservability/storageversionmigration_test.go b/operators/multiclusterobservability/controllers/multiclusterobservability/storageversionmigration_test.go index 66fcc3ec8..ccc4f8980 100644 --- a/operators/multiclusterobservability/controllers/multiclusterobservability/storageversionmigration_test.go +++ b/operators/multiclusterobservability/controllers/multiclusterobservability/storageversionmigration_test.go @@ -31,7 +31,7 @@ func TestCreateOrUpdateObservabilityStorageVersionMigrationResource(t *testing.T mcov1beta2.SchemeBuilder.AddToScheme(s) migrationv1alpha1.SchemeBuilder.AddToScheme(s) - c := fake.NewFakeClient() + c := fake.NewClientBuilder().Build() // test scenario of creating StorageVersionMigration err := createOrUpdateObservabilityStorageVersionMigrationResource(c, s, mco) @@ -52,7 +52,7 @@ func TestCreateOrUpdateObservabilityStorageVersionMigrationResource(t *testing.T }, }, } - c = fake.NewFakeClient(svm) + c = fake.NewClientBuilder().WithRuntimeObjects(svm).Build() err = createOrUpdateObservabilityStorageVersionMigrationResource(c, s, mco) if err != nil { t.Fatalf("createOrUpdateObservabilityStorageVersionMigrationResource: (%v)", err) diff --git a/operators/multiclusterobservability/controllers/placementrule/customize_img.go b/operators/multiclusterobservability/controllers/placementrule/customize_img.go index d124cd8a0..cd15ad945 100644 --- a/operators/multiclusterobservability/controllers/placementrule/customize_img.go +++ b/operators/multiclusterobservability/controllers/placementrule/customize_img.go @@ -17,7 +17,7 @@ import ( ) const ( - // ClusterImageRegistriesAnnotation value is a json string of ImageRegistries + // ClusterImageRegistriesAnnotation value is a json string of ImageRegistries. ClusterImageRegistriesAnnotation = "open-cluster-management.io/image-registries" ) @@ -124,7 +124,7 @@ func (c *DefaultClient) ImageOverride(imageName string) (newImageName string, er return overrideImageName, nil } -// getImageRegistries retrieves the imageRegistries from annotations of managedCluster +// getImageRegistries retrieves the imageRegistries from annotations of managedCluster. func (c *DefaultClient) getImageRegistries(clusterName string) (ImageRegistries, error) { imageRegistries := ImageRegistries{} managedCluster := &clusterv1.ManagedCluster{} diff --git a/operators/multiclusterobservability/controllers/placementrule/customize_img_test.go b/operators/multiclusterobservability/controllers/placementrule/customize_img_test.go index 9cb29f9be..550f189c3 100644 --- a/operators/multiclusterobservability/controllers/placementrule/customize_img_test.go +++ b/operators/multiclusterobservability/controllers/placementrule/customize_img_test.go @@ -5,6 +5,7 @@ package placementrule import ( "encoding/json" + "errors" "fmt" "testing" @@ -76,7 +77,7 @@ func Test_DefaultClientPullSecret(t *testing.T) { pullSecret: newPullSecret("pullSecret", "ns1", []byte("data")), clusterName: "cluster1", cluster: newFakeCluster("cluster1", "abc"), - expectedErr: fmt.Errorf("invalid character 'a' looking for beginning of value"), + expectedErr: errors.New("invalid character 'a' looking for beginning of value"), expectedPullSecret: nil, }, { @@ -84,7 +85,7 @@ func Test_DefaultClientPullSecret(t *testing.T) { pullSecret: newPullSecret("pullSecret", "ns1", []byte("data")), clusterName: "cluster1", cluster: newFakeCluster("cluster2", ""), - expectedErr: fmt.Errorf(`managedclusters.cluster.open-cluster-management.io "cluster1" not found`), + expectedErr: errors.New(`managedclusters.cluster.open-cluster-management.io "cluster1" not found`), expectedPullSecret: nil, }, { @@ -92,7 +93,7 @@ func Test_DefaultClientPullSecret(t *testing.T) { pullSecret: newPullSecret("pullSecret", "ns1", []byte("data")), clusterName: "cluster1", cluster: newFakeCluster("cluster1", newAnnotationRegistries(nil, "ns.test")), - expectedErr: fmt.Errorf("secrets \"test\" not found"), + expectedErr: errors.New("secrets \"test\" not found"), expectedPullSecret: nil, }, } @@ -197,7 +198,7 @@ func Test_DefaultClientImageOverride(t *testing.T) { cluster: newFakeCluster("cluster1", "abc"), image: "registry.redhat.io/rhacm2/registration@SHA256abc", expectedImage: "registry.redhat.io/rhacm2/registration@SHA256abc", - expectedErr: fmt.Errorf("invalid character 'a' looking for beginning of value"), + expectedErr: errors.New("invalid character 'a' looking for beginning of value"), }, { name: "return image without cluster", @@ -205,7 +206,7 @@ func Test_DefaultClientImageOverride(t *testing.T) { cluster: newFakeCluster("cluster2", ""), image: "registry.redhat.io/rhacm2/registration@SHA256abc", expectedImage: "registry.redhat.io/rhacm2/registration@SHA256abc", - expectedErr: fmt.Errorf(`managedclusters.cluster.open-cluster-management.io "cluster1" not found`), + expectedErr: errors.New(`managedclusters.cluster.open-cluster-management.io "cluster1" not found`), }, } diff --git a/operators/multiclusterobservability/controllers/placementrule/endpoint_metrics_operator.go b/operators/multiclusterobservability/controllers/placementrule/endpoint_metrics_operator.go index 724faff63..c5dbf25f8 100644 --- a/operators/multiclusterobservability/controllers/placementrule/endpoint_metrics_operator.go +++ b/operators/multiclusterobservability/controllers/placementrule/endpoint_metrics_operator.go @@ -26,7 +26,7 @@ const ( rolebindingName = "open-cluster-management:endpoint-observability-operator-rb" ) -// loadTemplates load manifests from manifests directory +// loadTemplates load manifests from manifests directory. func loadTemplates(mco *mcov1beta2.MultiClusterObservability) ( []runtime.RawExtension, *apiextensionsv1.CustomResourceDefinition, @@ -72,7 +72,10 @@ func updateRes(r *resource.Resource, kind := r.GetKind() if kind != "ClusterRole" && kind != "ClusterRoleBinding" && kind != "CustomResourceDefinition" { - r.SetNamespace(spokeNameSpace) + if err := r.SetNamespace(spokeNameSpace); err != nil { + log.Error(err, "failed to set namespace") + return nil, err + } } obj := util.GetK8sObj(kind) if kind == "CustomResourceDefinition" && r.GetGvk().Version == "v1beta1" { diff --git a/operators/multiclusterobservability/controllers/placementrule/hub_info_secret.go b/operators/multiclusterobservability/controllers/placementrule/hub_info_secret.go index ffb9bdf1e..a19091839 100644 --- a/operators/multiclusterobservability/controllers/placementrule/hub_info_secret.go +++ b/operators/multiclusterobservability/controllers/placementrule/hub_info_secret.go @@ -16,7 +16,7 @@ import ( ) // generateHubInfoSecret generates the secret that contains hubInfo. -// this function should only called when the watched resources are created/updated +// this function should only called when the watched resources are created/updated. func generateHubInfoSecret(client client.Client, obsNamespace string, namespace string, ingressCtlCrdExists bool) (*corev1.Secret, error) { diff --git a/operators/multiclusterobservability/controllers/placementrule/manifestwork.go b/operators/multiclusterobservability/controllers/placementrule/manifestwork.go index 511e03898..513b36c0d 100644 --- a/operators/multiclusterobservability/controllers/placementrule/manifestwork.go +++ b/operators/multiclusterobservability/controllers/placementrule/manifestwork.go @@ -17,7 +17,6 @@ import ( apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1" k8serrors "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" @@ -39,7 +38,7 @@ const ( workPostponeDeleteAnnoKey = "open-cluster-management/postpone-delete" ) -// intermidiate resources for the manifest work +// intermediate resources for the manifest work. var ( hubInfoSecret *corev1.Secret pullSecret *corev1.Secret @@ -54,7 +53,6 @@ var ( imageListConfigMap *corev1.ConfigMap rawExtensionList []runtime.RawExtension - //promRawExtensionList []runtime.RawExtension ) func deleteManifestWork(c client.Client, name string, namespace string) error { @@ -264,13 +262,19 @@ func generateGlobalManifestResources(c client.Client, mco *mcov1beta2.MultiClust return works, crdv1Work, crdv1beta1Work, nil } -func createManifestWorks(c client.Client, restMapper meta.RESTMapper, - clusterNamespace string, clusterName string, +func createManifestWorks( + c client.Client, + clusterNamespace string, + clusterName string, mco *mcov1beta2.MultiClusterObservability, - works []workv1.Manifest, allowlist *corev1.ConfigMap, - crdWork *workv1.Manifest, dep *appsv1.Deployment, - hubInfo *corev1.Secret, addonConfig *addonv1alpha1.AddOnDeploymentConfig, installProm bool) error { - + works []workv1.Manifest, + allowlist *corev1.ConfigMap, + crdWork *workv1.Manifest, + dep *appsv1.Deployment, + hubInfo *corev1.Secret, + addonConfig *addonv1alpha1.AddOnDeploymentConfig, + installProm bool, +) error { work := newManifestwork(clusterNamespace+workNameSuffix, clusterNamespace) manifests := work.Spec.Workload.Manifests diff --git a/operators/multiclusterobservability/controllers/placementrule/manifestwork_test.go b/operators/multiclusterobservability/controllers/placementrule/manifestwork_test.go index eab17df49..70c27a352 100644 --- a/operators/multiclusterobservability/controllers/placementrule/manifestwork_test.go +++ b/operators/multiclusterobservability/controllers/placementrule/manifestwork_test.go @@ -337,8 +337,7 @@ func TestManifestWork(t *testing.T) { }, } - err = createManifestWorks(c, nil, namespace, clusterName, newTestMCO(), works, metricsAllowlistConfigMap, - crdWork, endpointMetricsOperatorDeploy, hubInfoSecret, addonConfig, false) + err = createManifestWorks(c, namespace, clusterName, newTestMCO(), works, metricsAllowlistConfigMap, crdWork, endpointMetricsOperatorDeploy, hubInfoSecret, addonConfig, false) if err != nil { t.Fatalf("Failed to create manifestworks: (%v)", err) } @@ -411,8 +410,7 @@ func TestManifestWork(t *testing.T) { if err != nil { t.Fatalf("Failed to get global manifestwork resource: (%v)", err) } - err = createManifestWorks(c, nil, namespace, clusterName, newTestMCO(), works, metricsAllowlistConfigMap, - crdWork, endpointMetricsOperatorDeploy, hubInfoSecret, addonConfig, false) + err = createManifestWorks(c, namespace, clusterName, newTestMCO(), works, metricsAllowlistConfigMap, crdWork, endpointMetricsOperatorDeploy, hubInfoSecret, addonConfig, false) if err != nil { t.Fatalf("Failed to create manifestworks: (%v)", err) } @@ -425,8 +423,7 @@ func TestManifestWork(t *testing.T) { } spokeNameSpace = "spoke-ns" - err = createManifestWorks(c, nil, namespace, clusterName, newTestMCO(), works, metricsAllowlistConfigMap, - crdWork, endpointMetricsOperatorDeploy, hubInfoSecret, addonConfig, false) + err = createManifestWorks(c, namespace, clusterName, newTestMCO(), works, metricsAllowlistConfigMap, crdWork, endpointMetricsOperatorDeploy, hubInfoSecret, addonConfig, false) if err != nil { t.Fatalf("Failed to create manifestworks with updated namespace: (%v)", err) } @@ -455,7 +452,7 @@ func TestManifestWork(t *testing.T) { t.Fatalf("Failed to generate hubInfo secret: (%v)", err) } - err = createManifestWorks(c, nil, namespace, clusterName, newTestMCO(), works, metricsAllowlistConfigMap, crdWork, endpointMetricsOperatorDeploy, hubInfoSecret, addonConfig, false) + err = createManifestWorks(c, namespace, clusterName, newTestMCO(), works, metricsAllowlistConfigMap, crdWork, endpointMetricsOperatorDeploy, hubInfoSecret, addonConfig, false) if err != nil { t.Fatalf("Failed to create manifestworks: (%v)", err) } diff --git a/operators/multiclusterobservability/controllers/placementrule/mco_predicate.go b/operators/multiclusterobservability/controllers/placementrule/mco_predicate.go index cdc8d0615..fcb1aa7a7 100644 --- a/operators/multiclusterobservability/controllers/placementrule/mco_predicate.go +++ b/operators/multiclusterobservability/controllers/placementrule/mco_predicate.go @@ -25,7 +25,7 @@ func getMCOPred(c client.Client, ingressCtlCrdExists bool) predicate.Funcs { mco := e.Object.(*mcov1beta2.MultiClusterObservability) alertingStatus := config.IsAlertingDisabledInSpec(mco) config.SetAlertingDisabled(alertingStatus) - var err error = nil + var err error hubInfoSecret, err = generateHubInfoSecret(c, config.GetDefaultNamespace(), spokeNameSpace, ingressCtlCrdExists) if err != nil { log.Error(err, "unable to get HubInfoSecret", "controller", "PlacementRule") @@ -40,13 +40,11 @@ func getMCOPred(c client.Client, ingressCtlCrdExists bool) predicate.Funcs { // if value changed, then mustReconcile is true if oldAlertingStatus != newAlertingStatus { config.SetAlertingDisabled(newAlertingStatus) - var err error = nil - + var err error hubInfoSecret, err = generateHubInfoSecret(c, config.GetDefaultNamespace(), spokeNameSpace, ingressCtlCrdExists) if err != nil { log.Error(err, "unable to get HubInfoSecret", "controller", "PlacementRule") } - retval = true } diff --git a/operators/multiclusterobservability/controllers/placementrule/obsaddon.go b/operators/multiclusterobservability/controllers/placementrule/obsaddon.go index 48035ef03..e23767d2a 100644 --- a/operators/multiclusterobservability/controllers/placementrule/obsaddon.go +++ b/operators/multiclusterobservability/controllers/placementrule/obsaddon.go @@ -7,6 +7,7 @@ import ( "context" "time" + "golang.org/x/exp/slices" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" @@ -123,7 +124,7 @@ func deleteStaleObsAddon(c client.Client, namespace string, isForce bool) error } func deleteFinalizer(c client.Client, obsaddon *obsv1beta1.ObservabilityAddon) error { - if util.Contains(obsaddon.GetFinalizers(), obsAddonFinalizer) { + if slices.Contains(obsaddon.GetFinalizers(), obsAddonFinalizer) { obsaddon.SetFinalizers(util.Remove(obsaddon.GetFinalizers(), obsAddonFinalizer)) err := c.Update(context.TODO(), obsaddon) if err != nil { diff --git a/operators/multiclusterobservability/controllers/placementrule/placementrule_controller.go b/operators/multiclusterobservability/controllers/placementrule/placementrule_controller.go index 72c231a40..9bb87cfaa 100644 --- a/operators/multiclusterobservability/controllers/placementrule/placementrule_controller.go +++ b/operators/multiclusterobservability/controllers/placementrule/placementrule_controller.go @@ -13,6 +13,7 @@ import ( "github.com/go-logr/logr" operatorv1 "github.com/openshift/api/operator/v1" + "golang.org/x/exp/slices" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" k8serrors "k8s.io/apimachinery/pkg/api/errors" @@ -158,21 +159,18 @@ func (r *PlacementRuleReconciler) Reconcile(ctx context.Context, req ctrl.Reques } if !deleteAll { - res, err := createAllRelatedRes( + if err := createAllRelatedRes( r.Client, - r.RESTMapper, req, mco, obsAddonList, r.CRDMap, - ) - if err != nil { - return res, err + ); err != nil { + return ctrl.Result{}, err } } else { - res, err := deleteAllObsAddons(r.Client, obsAddonList) - if err != nil { - return res, err + if err := deleteAllObsAddons(r.Client, obsAddonList); err != nil { + return ctrl.Result{}, err } } @@ -208,7 +206,7 @@ func (r *PlacementRuleReconciler) Reconcile(ctx context.Context, req ctrl.Reques return ctrl.Result{}, err } } - if !commonutil.Contains(latestClusters, work.Namespace) { + if !slices.Contains(latestClusters, work.Namespace) { reqLogger.Info("To delete manifestwork", "namespace", work.Namespace) err = deleteManagedClusterRes(r.Client, work.Namespace) if err != nil { @@ -223,7 +221,7 @@ func (r *PlacementRuleReconciler) Reconcile(ctx context.Context, req ctrl.Reques // but the managedclusteraddon for observability will not deleted by the cluster manager, so check against the // managedclusteraddon list to remove the managedcluster resources after the managedcluster is detached. for _, mcaddon := range managedclusteraddonList.Items { - if !commonutil.Contains(latestClusters, mcaddon.Namespace) { + if !slices.Contains(latestClusters, mcaddon.Namespace) { reqLogger.Info("To delete managedcluster resources", "namespace", mcaddon.Namespace) err = deleteManagedClusterRes(r.Client, mcaddon.Namespace) if err != nil { @@ -267,30 +265,29 @@ func (r *PlacementRuleReconciler) Reconcile(ctx context.Context, req ctrl.Reques func createAllRelatedRes( c client.Client, - restMapper meta.RESTMapper, request ctrl.Request, mco *mcov1beta2.MultiClusterObservability, obsAddonList *mcov1beta1.ObservabilityAddonList, - CRDMap map[string]bool) (ctrl.Result, error) { - + CRDMap map[string]bool, +) error { var err error // create the clusterrole if not there if !isCRoleCreated { err = createClusterRole(c) if err != nil { - return ctrl.Result{}, err + return err } err = createResourceRole(c) if err != nil { - return ctrl.Result{}, err + return err } isCRoleCreated = true } //Get or create ClusterManagementAddon - clusterAddon, err = util.CreateClusterManagementAddon(c, !CRDMap[config.MCHCrdName]) + clusterAddon, err = util.CreateClusterManagementAddon(c) if err != nil { - return ctrl.Result{}, err + return err } for _, config := range clusterAddon.Spec.SupportedConfigs { if config.ConfigGroupResource.Group == util.AddonGroup && @@ -305,7 +302,7 @@ func createAllRelatedRes( addonConfig, ) if err != nil { - return ctrl.Result{}, err + return err } log.Info("There is default AddonDeploymentConfig for current addon") defaultAddonDeploymentConfig = addonConfig @@ -327,14 +324,14 @@ func createAllRelatedRes( works, crdv1Work, crdv1beta1Work, err := generateGlobalManifestResources(c, mco) if err != nil { - return ctrl.Result{}, err + return err } // regenerate the hubinfo secret if empty if hubInfoSecret == nil { var err error if hubInfoSecret, err = generateHubInfoSecret(c, config.GetDefaultNamespace(), spokeNameSpace, CRDMap[config.IngressControllerCRD]); err != nil { - return ctrl.Result{}, err + return err } } @@ -353,15 +350,15 @@ func createAllRelatedRes( request.Namespace, ) if openshiftVersion == "3" { - err = createManagedClusterRes(c, restMapper, mco, + err = createManagedClusterRes(c, mco, managedCluster, managedCluster, works, ocp311metricsAllowlistConfigMap, crdv1beta1Work, endpointMetricsOperatorDeploy, hubInfoSecret, false) } else if openshiftVersion == nonOCP { - err = createManagedClusterRes(c, restMapper, mco, + err = createManagedClusterRes(c, mco, managedCluster, managedCluster, works, metricsAllowlistConfigMap, crdv1Work, endpointMetricsOperatorDeploy, hubInfoSecret, true) } else { - err = createManagedClusterRes(c, restMapper, mco, + err = createManagedClusterRes(c, mco, managedCluster, managedCluster, works, metricsAllowlistConfigMap, crdv1Work, endpointMetricsOperatorDeploy, hubInfoSecret, false) } @@ -387,24 +384,24 @@ func createAllRelatedRes( } if failedCreateManagedClusterRes || failedDeleteOba { - return ctrl.Result{}, errors.New("failed to create managedcluster resources or" + - " failed to delete observabilityaddon, skip and reconcile later") + return errors.New("failed to create managedcluster resources or failed to delete observabilityaddon, skip and reconcile later") } - return ctrl.Result{}, nil + return nil } func deleteAllObsAddons( client client.Client, - obsAddonList *mcov1beta1.ObservabilityAddonList) (ctrl.Result, error) { + obsAddonList *mcov1beta1.ObservabilityAddonList, +) error { for _, ep := range obsAddonList.Items { err := deleteObsAddon(client, ep.Namespace) if err != nil { log.Error(err, "Failed to delete observabilityaddon", "namespace", ep.Namespace) - return ctrl.Result{}, err + return err } } - return ctrl.Result{}, nil + return nil } func deleteGlobalResource(c client.Client) error { @@ -425,10 +422,18 @@ func deleteGlobalResource(c client.Client) error { return nil } -func createManagedClusterRes(c client.Client, restMapper meta.RESTMapper, - mco *mcov1beta2.MultiClusterObservability, name string, namespace string, - works []workv1.Manifest, allowlist *corev1.ConfigMap, crdWork *workv1.Manifest, - dep *appsv1.Deployment, hubInfo *corev1.Secret, installProm bool) error { +func createManagedClusterRes( + c client.Client, + mco *mcov1beta2.MultiClusterObservability, + name string, + namespace string, + works []workv1.Manifest, + allowlist *corev1.ConfigMap, + crdWork *workv1.Manifest, + dep *appsv1.Deployment, + hubInfo *corev1.Secret, + installProm bool, +) error { err := createObsAddon(c, namespace) if err != nil { log.Error(err, "Failed to create observabilityaddon") @@ -469,9 +474,7 @@ func createManagedClusterRes(c client.Client, restMapper meta.RESTMapper, addonConfig = defaultAddonDeploymentConfig } - err = createManifestWorks(c, restMapper, namespace, name, mco, works, allowlist, crdWork, dep, - hubInfo, addonConfig, installProm) - if err != nil { + if err = createManifestWorks(c, namespace, name, mco, works, allowlist, crdWork, dep, hubInfo, addonConfig, installProm); err != nil { log.Error(err, "Failed to create manifestwork") return err } @@ -559,7 +562,10 @@ func (r *PlacementRuleReconciler) SetupWithManager(mgr ctrl.Manager) error { e.Object.GetName(), ) /* #nosec */ - removePostponeDeleteAnnotationForManifestwork(c, e.Object.GetNamespace()) + if err := removePostponeDeleteAnnotationForManifestwork(c, e.Object.GetNamespace()); err != nil { + log.Error(err, "postpone delete annotation for manifestwork could not be removed") + return false + } return true } return false @@ -770,14 +776,17 @@ func (r *PlacementRuleReconciler) SetupWithManager(mgr ctrl.Manager) error { e.Object.GetNamespace() == config.GetDefaultNamespace() { // wait 10s for access_token of alertmanager and generate the secret that contains the access_token /* #nosec */ - wait.Poll(2*time.Second, 10*time.Second, func() (bool, error) { + if err := wait.Poll(2*time.Second, 10*time.Second, func() (bool, error) { var err error log.Info("generate amAccessorTokenSecret for alertmanager access serviceaccount CREATE") if amAccessorTokenSecret, err = generateAmAccessorTokenSecret(c); err == nil { return true, nil } return false, err - }) + }); err != nil { + log.Error(err, "error polling in createfunc") + return false + } return true } return false diff --git a/operators/multiclusterobservability/controllers/placementrule/placementrule_controller_test.go b/operators/multiclusterobservability/controllers/placementrule/placementrule_controller_test.go index 6ee1ce178..d870e037b 100644 --- a/operators/multiclusterobservability/controllers/placementrule/placementrule_controller_test.go +++ b/operators/multiclusterobservability/controllers/placementrule/placementrule_controller_test.go @@ -5,7 +5,6 @@ package placementrule import ( "context" - "fmt" "os" "path" "strings" @@ -140,7 +139,7 @@ func setupTest(t *testing.T) func() { //clean up the manifest path if left over from previous test if fi, err := os.Lstat(testManifestsPath); err == nil && fi.Mode()&os.ModeSymlink != 0 { if err = os.Remove(testManifestsPath); err != nil { - t.Logf(fmt.Sprintf("Failed to delete symlink(%s) for the test manifests: (%v)", testManifestsPath, err)) + t.Logf("Failed to delete symlink(%s) for the test manifests: (%v)", testManifestsPath, err) } } err = os.Symlink(manifestsPath, testManifestsPath) @@ -152,7 +151,7 @@ func setupTest(t *testing.T) func() { return func() { t.Log("begin teardownTest") if err = os.Remove(testManifestsPath); err != nil { - t.Logf(fmt.Sprintf("Failed to delete symbollink(%s) for the test manifests: (%v)", testManifestsPath, err)) + t.Logf("Failed to delete symbollink(%s) for the test manifests: (%v)", testManifestsPath, err) } os.Remove(path.Join(wd, "../../tests")) os.Unsetenv("TEMPLATES_PATH") diff --git a/operators/multiclusterobservability/main.go b/operators/multiclusterobservability/main.go index fce8cd794..262517de5 100644 --- a/operators/multiclusterobservability/main.go +++ b/operators/multiclusterobservability/main.go @@ -172,36 +172,36 @@ func main() { mcoNamespace := config.GetMCONamespace() gvkLabelsMap := map[schema.GroupVersionKind][]filteredcache.Selector{ - corev1.SchemeGroupVersion.WithKind("Secret"): []filteredcache.Selector{ + corev1.SchemeGroupVersion.WithKind("Secret"): { {FieldSelector: fmt.Sprintf("metadata.namespace==%s", config.GetDefaultNamespace())}, {FieldSelector: fmt.Sprintf("metadata.namespace==%s", config.OpenshiftIngressOperatorNamespace)}, {FieldSelector: fmt.Sprintf("metadata.namespace==%s", config.OpenshiftIngressNamespace)}, }, - corev1.SchemeGroupVersion.WithKind("ConfigMap"): []filteredcache.Selector{ + corev1.SchemeGroupVersion.WithKind("ConfigMap"): { {FieldSelector: fmt.Sprintf("metadata.namespace==%s", config.GetDefaultNamespace())}, }, - corev1.SchemeGroupVersion.WithKind("Service"): []filteredcache.Selector{ + corev1.SchemeGroupVersion.WithKind("Service"): { {FieldSelector: fmt.Sprintf("metadata.namespace==%s", config.GetDefaultNamespace())}, }, - corev1.SchemeGroupVersion.WithKind("ServiceAccount"): []filteredcache.Selector{ + corev1.SchemeGroupVersion.WithKind("ServiceAccount"): { {FieldSelector: fmt.Sprintf("metadata.namespace==%s", config.GetDefaultNamespace())}, }, - appsv1.SchemeGroupVersion.WithKind("Deployment"): []filteredcache.Selector{ + appsv1.SchemeGroupVersion.WithKind("Deployment"): { {FieldSelector: fmt.Sprintf("metadata.namespace==%s", config.GetDefaultNamespace())}, }, - appsv1.SchemeGroupVersion.WithKind("StatefulSet"): []filteredcache.Selector{ + appsv1.SchemeGroupVersion.WithKind("StatefulSet"): { {FieldSelector: fmt.Sprintf("metadata.namespace==%s", config.GetDefaultNamespace())}, }, - workv1.SchemeGroupVersion.WithKind("ManifestWork"): []filteredcache.Selector{ + workv1.SchemeGroupVersion.WithKind("ManifestWork"): { {LabelSelector: "owner==multicluster-observability-operator"}, }, - clusterv1.SchemeGroupVersion.WithKind("ManagedCluster"): []filteredcache.Selector{ + clusterv1.SchemeGroupVersion.WithKind("ManagedCluster"): { {LabelSelector: "vendor!=auto-detect,observability!=disabled"}, }, - addonv1alpha1.SchemeGroupVersion.WithKind("ClusterManagementAddOn"): []filteredcache.Selector{ + addonv1alpha1.SchemeGroupVersion.WithKind("ClusterManagementAddOn"): { {FieldSelector: fmt.Sprintf("metadata.name=%s", util.ObservabilityController)}, }, - addonv1alpha1.SchemeGroupVersion.WithKind("ManagedClusterAddOn"): []filteredcache.Selector{ + addonv1alpha1.SchemeGroupVersion.WithKind("ManagedClusterAddOn"): { {FieldSelector: fmt.Sprintf("metadata.name=%s", util.ManagedClusterAddonName)}, }, } @@ -223,7 +223,7 @@ func main() { } } - // The following RBAC resources will not be watched by MCO, the selector will not impact the mco behaviour, which + // The following RBAC resources will not be watched by MCO, the selector will not impact the mco behavior, which // means MCO will fetch kube-apiserver for the correspoding resource if the resource can't be found in the cache. // Adding selector will reduce the cache size when the managedcluster scale. gvkLabelsMap[rbacv1.SchemeGroupVersion.WithKind("ClusterRole")] = []filteredcache.Selector{ diff --git a/operators/multiclusterobservability/pkg/certificates/cert_controller.go b/operators/multiclusterobservability/pkg/certificates/cert_controller.go index 49815a3d2..403217515 100644 --- a/operators/multiclusterobservability/pkg/certificates/cert_controller.go +++ b/operators/multiclusterobservability/pkg/certificates/cert_controller.go @@ -12,6 +12,7 @@ import ( "reflect" "time" + "golang.org/x/exp/slices" appv1 "k8s.io/api/apps/v1" v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" @@ -24,7 +25,6 @@ import ( mcov1beta2 "github.com/stolostron/multicluster-observability-operator/operators/multiclusterobservability/api/v1beta2" "github.com/stolostron/multicluster-observability-operator/operators/multiclusterobservability/pkg/config" - "github.com/stolostron/multicluster-observability-operator/operators/pkg/util" "open-cluster-management.io/addon-framework/pkg/addonmanager" ) @@ -132,7 +132,7 @@ func updateDeployLabel(c client.Client, dName string, isUpdate bool) { func needsRenew(s v1.Secret) bool { certSecretNames := []string{serverCACerts, clientCACerts, serverCerts, grafanaCerts} - if !util.Contains(certSecretNames, s.Name) { + if !slices.Contains(certSecretNames, s.Name) { return false } data := s.Data["tls.crt"] @@ -167,7 +167,7 @@ func onAdd(c client.Client) func(obj interface{}) { func onDelete(c client.Client) func(obj interface{}) { return func(obj interface{}) { s := *obj.(*v1.Secret) - if util.Contains(caSecretNames, s.Name) { + if slices.Contains(caSecretNames, s.Name) { mco := &mcov1beta2.MultiClusterObservability{} err := c.Get(context.TODO(), types.NamespacedName{ Name: config.GetMonitoringCRName(), @@ -217,7 +217,7 @@ func onUpdate(c client.Client, ingressCtlCrdExists bool) func(oldObj, newObj int if !reflect.DeepEqual(oldS.Data, newS.Data) { restartPods(c, newS, true) } else { - if util.Contains(caSecretNames, newS.Name) { + if slices.Contains(caSecretNames, newS.Name) { removeExpiredCA(c, newS.Name) } if needsRenew(newS) { diff --git a/operators/multiclusterobservability/pkg/certificates/cert_controller_test.go b/operators/multiclusterobservability/pkg/certificates/cert_controller_test.go index 379b4c478..fb076ffca 100644 --- a/operators/multiclusterobservability/pkg/certificates/cert_controller_test.go +++ b/operators/multiclusterobservability/pkg/certificates/cert_controller_test.go @@ -20,8 +20,6 @@ import ( ) func init() { - //logf.SetLogger(zap.New(zap.UseDevMode(true), zap.WriteTo(os.Stdout))) - s := scheme.Scheme mcov1beta2.SchemeBuilder.AddToScheme(s) config.SetMonitoringCRName(name) @@ -48,7 +46,7 @@ func newDeployment(name string) *appv1.Deployment { } func TestOnAdd(t *testing.T) { - c := fake.NewFakeClient() + c := fake.NewClientBuilder().Build() caSecret := &v1.Secret{ ObjectMeta: metav1.ObjectMeta{ Name: serverCACerts, @@ -58,8 +56,8 @@ func TestOnAdd(t *testing.T) { } config.SetOperandNames(c) onAdd(c)(caSecret) - c = fake.NewFakeClient(newDeployment(name+"-rbac-query-proxy"), - newDeployment(name+"-observatorium-api")) + c = fake.NewClientBuilder().WithRuntimeObjects(newDeployment(name+"-rbac-query-proxy"), + newDeployment(name+"-observatorium-api")).Build() onAdd(c)(caSecret) dep := &appv1.Deployment{} c.Get(context.TODO(), @@ -97,7 +95,7 @@ func TestOnDelete(t *testing.T) { "tls.crt": []byte("old cert"), }, } - c := fake.NewFakeClient(caSecret, getMco()) + c := fake.NewClientBuilder().WithRuntimeObjects(caSecret, getMco()).Build() onDelete(c)(deletCaSecret) c.Get(context.TODO(), types.NamespacedName{Name: serverCACerts, Namespace: namespace}, caSecret) data := string(caSecret.Data["tls.crt"]) @@ -109,7 +107,7 @@ func TestOnDelete(t *testing.T) { func TestOnUpdate(t *testing.T) { certSecret := getExpiredCertSecret() oldCertLength := len(certSecret.Data["tls.crt"]) - c := fake.NewFakeClient(certSecret) + c := fake.NewClientBuilder().WithRuntimeObjects(certSecret).Build() onUpdate(c, true)(certSecret, certSecret) certSecret.Name = clientCACerts onUpdate(c, true)(certSecret, certSecret) diff --git a/operators/multiclusterobservability/pkg/certificates/certificates.go b/operators/multiclusterobservability/pkg/certificates/certificates.go index 2c2e3b7e2..1ea200d67 100644 --- a/operators/multiclusterobservability/pkg/certificates/certificates.go +++ b/operators/multiclusterobservability/pkg/certificates/certificates.go @@ -15,6 +15,7 @@ import ( "net" "time" + "golang.org/x/exp/slices" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -27,7 +28,6 @@ import ( mcov1beta2 "github.com/stolostron/multicluster-observability-operator/operators/multiclusterobservability/api/v1beta2" "github.com/stolostron/multicluster-observability-operator/operators/multiclusterobservability/pkg/config" mcoutil "github.com/stolostron/multicluster-observability-operator/operators/multiclusterobservability/pkg/util" - "github.com/stolostron/multicluster-observability-operator/operators/pkg/util" ) const ( @@ -194,6 +194,9 @@ func createCACertificate(cn string, caKey *rsa.PrivateKey) ([]byte, []byte, erro return caKeyBytes, caBytes, nil } +// TODO(saswatamcode): Refactor function to remove ou. +// +//nolint:unparam func createCertSecret(c client.Client, scheme *runtime.Scheme, mco *mcov1beta2.MultiClusterObservability, isRenew bool, name string, isServer bool, @@ -255,7 +258,7 @@ func createCertSecret(c client.Client, } // to handle upgrade scenario in which hosts maybe update for _, dnsString := range dns { - if !util.Contains(serverCrt.DNSNames, dnsString) { + if !slices.Contains(serverCrt.DNSNames, dnsString) { isRenew = true break } diff --git a/operators/multiclusterobservability/pkg/certificates/certificates_test.go b/operators/multiclusterobservability/pkg/certificates/certificates_test.go index 64d7d92bf..9c27295d2 100644 --- a/operators/multiclusterobservability/pkg/certificates/certificates_test.go +++ b/operators/multiclusterobservability/pkg/certificates/certificates_test.go @@ -81,7 +81,7 @@ func TestCreateCertificates(t *testing.T) { mcov1beta2.SchemeBuilder.AddToScheme(s) routev1.AddToScheme(s) - c := fake.NewFakeClient(route) + c := fake.NewClientBuilder().WithRuntimeObjects(route).Build() err := CreateObservabilityCerts(c, s, mco, true) if err != nil { @@ -108,7 +108,7 @@ func TestRemoveExpiredCA(t *testing.T) { caSecret := getExpiredCertSecret() oldCertLength := len(caSecret.Data["tls.crt"]) - c := fake.NewFakeClient(caSecret) + c := fake.NewClientBuilder().WithRuntimeObjects(caSecret).Build() removeExpiredCA(c, serverCACerts) c.Get(context.TODO(), types.NamespacedName{Name: serverCACerts, Namespace: namespace}, diff --git a/operators/multiclusterobservability/pkg/certificates/signer.go b/operators/multiclusterobservability/pkg/certificates/signer.go index 5b2d182b8..16318605f 100644 --- a/operators/multiclusterobservability/pkg/certificates/signer.go +++ b/operators/multiclusterobservability/pkg/certificates/signer.go @@ -20,7 +20,7 @@ import ( func getClient(s *runtime.Scheme) (client.Client, error) { if os.Getenv("TEST") != "" { - c := fake.NewFakeClient() + c := fake.NewClientBuilder().Build() return c, nil } config, err := clientcmd.BuildConfigFromFlags("", "") diff --git a/operators/multiclusterobservability/pkg/config/azure_conf.go b/operators/multiclusterobservability/pkg/config/azure_conf.go index 7102f9852..3d8f4bde1 100644 --- a/operators/multiclusterobservability/pkg/config/azure_conf.go +++ b/operators/multiclusterobservability/pkg/config/azure_conf.go @@ -31,7 +31,7 @@ func validateAzure(conf Config) error { return nil } -// IsValidAzureConf is used to validate azure configuration +// IsValidAzureConf is used to validate azure configuration. func IsValidAzureConf(data []byte) (bool, error) { var objectConfg ObjectStorgeConf err := yaml.Unmarshal(data, &objectConfg) diff --git a/operators/multiclusterobservability/pkg/config/config.go b/operators/multiclusterobservability/pkg/config/config.go index c5a6cd541..ef8530706 100644 --- a/operators/multiclusterobservability/pkg/config/config.go +++ b/operators/multiclusterobservability/pkg/config/config.go @@ -121,7 +121,7 @@ const ( ObservatoriumOperatorImgName = "observatorium-operator" ObservatoriumOperatorImgKey = "observatorium_operator" ThanosReceiveControllerImgName = "thanos-receive-controller" - //ThanosReceiveControllerKey is used to get from mch-image-manifest.xxx configmap + //ThanosReceiveControllerKey is used to get from mch-image-manifest.xxx configmap. ThanosReceiveControllerKey = "thanos_receive_controller" ThanosReceiveControllerImgTag = "master-2022-04-01-b58820f" ThanosImgName = "thanos" @@ -256,22 +256,21 @@ const ( ResourceTypeSecret = "Secret" ) -// ObjectStorgeConf is used to Unmarshal from bytes to do validation +// ObjectStorgeConf is used to Unmarshal from bytes to do validation. type ObjectStorgeConf struct { Type string `yaml:"type"` Config Config `yaml:"config"` } var ( - log = logf.Log.WithName("config") - monitoringCRName = "" - tenantUID = "" - imageManifests = map[string]string{} - imageManifestConfigMapName = "" - hasCustomRuleConfigMap = false - hasCustomAlertmanagerConfig = false - certDuration = time.Hour * 24 * 365 - isAlertingDisabled = false + log = logf.Log.WithName("config") + monitoringCRName = "" + tenantUID = "" + imageManifests = map[string]string{} + imageManifestConfigMapName = "" + hasCustomRuleConfigMap = false + certDuration = time.Hour * 24 * 365 + isAlertingDisabled = false Replicas1 int32 = 1 Replicas2 int32 = 2 @@ -290,7 +289,7 @@ var ( ThanosQueryFrontendMemcached: &Replicas3, Alertmanager: &Replicas3, } - // use this map to store the operand name + // use this map to store the operand name. operandNames = map[string]string{} MemoryLimitMB = int32(1024) @@ -370,12 +369,12 @@ func GetReplicas(component string, advanced *observabilityv1beta2.AdvancedConfig return replicas } -// GetCrLabelKey returns the key for the CR label injected into the resources created by the operator +// GetCrLabelKey returns the key for the CR label injected into the resources created by the operator. func GetCrLabelKey() string { return crLabelKey } -// GetClusterNameLabelKey returns the key for the injected label +// GetClusterNameLabelKey returns the key for the injected label. func GetClusterNameLabelKey() string { return clusterNameLabelKey } @@ -384,7 +383,7 @@ func GetImageManifestConfigMapName() string { return imageManifestConfigMapName } -// ReadImageManifestConfigMap reads configmap with the label ocm-configmap-type=image-manifest +// ReadImageManifestConfigMap reads configmap with the label ocm-configmap-type=image-manifest. func ReadImageManifestConfigMap(c client.Client, version string) (bool, error) { mcoNamespace := GetMCONamespace() // List image manifest configmap with label ocm-configmap-type=image-manifest and ocm-release-version @@ -400,7 +399,7 @@ func ReadImageManifestConfigMap(c client.Client, version string) (bool, error) { imageCMList := &corev1.ConfigMapList{} err := c.List(context.TODO(), imageCMList, listOpts...) if err != nil { - return false, fmt.Errorf("Failed to list mch-image-manifest configmaps: %v", err) + return false, fmt.Errorf("failed to list mch-image-manifest configmaps: %w", err) } if len(imageCMList.Items) != 1 { @@ -418,15 +417,15 @@ func GetImageManifests() map[string]string { return imageManifests } -// SetImageManifests sets imageManifests +// SetImageManifests sets imageManifests. func SetImageManifests(images map[string]string) { imageManifests = images } -// ReplaceImage is used to replace the image with specified annotation or imagemanifest configmap +// ReplaceImage is used to replace the image with specified annotation or imagemanifest configmap. func ReplaceImage(annotations map[string]string, imageRepo, componentName string) (bool, string) { if annotations != nil { - annotationImageRepo, _ := annotations[AnnotationKeyImageRepository] + annotationImageRepo := annotations[AnnotationKeyImageRepository] if annotationImageRepo == "" { annotationImageRepo = DefaultImgRepository } @@ -464,12 +463,12 @@ func ReplaceImage(annotations map[string]string, imageRepo, componentName string } } -// GetDefaultTenantName returns the default tenant name +// GetDefaultTenantName returns the default tenant name. func GetDefaultTenantName() string { return defaultTenantName } -// GetObsAPIHost is used to get the URL for observartium api gateway +// GetObsAPIHost is used to get the URL for observartium api gateway. func GetObsAPIHost(client client.Client, namespace string) (string, error) { return GetRouteHost(client, obsAPIGateway, namespace) } @@ -504,7 +503,7 @@ func GetMCONamespace() string { return podNamespace } -// GetAlertmanagerEndpoint is used to get the URL for alertmanager +// GetAlertmanagerEndpoint is used to get the URL for alertmanager. func GetAlertmanagerEndpoint(client client.Client, namespace string) (string, error) { found := &routev1.Route{} @@ -526,7 +525,7 @@ func GetAlertmanagerEndpoint(client client.Client, namespace string) (string, er return found.Spec.Host, nil } -// getDomainForIngressController get the domain for the given ingresscontroller instance +// getDomainForIngressController get the domain for the given ingresscontroller instance. func getDomainForIngressController(client client.Client, name, namespace string) (string, error) { ingressOperatorInstance := &operatorv1.IngressController{} err := client.Get(context.TODO(), types.NamespacedName{Name: name, Namespace: namespace}, ingressOperatorInstance) @@ -540,7 +539,7 @@ func getDomainForIngressController(client client.Client, name, namespace string) return domain, nil } -// GetAlertmanagerRouterCA is used to get the CA of openshift Route +// GetAlertmanagerRouterCA is used to get the CA of openshift Route. func GetAlertmanagerRouterCA(client client.Client) (string, error) { amRouteBYOCaSrt := &corev1.Secret{} amRouteBYOCertSrt := &corev1.Secret{} @@ -586,7 +585,7 @@ func GetAlertmanagerRouterCA(client client.Client) (string, error) { return string(routerCASecret.Data["tls.crt"]), nil } -// GetAlertmanagerCA is used to get the CA of Alertmanager +// GetAlertmanagerCA is used to get the CA of Alertmanager. func GetAlertmanagerCA(client client.Client) (string, error) { amCAConfigmap := &corev1.ConfigMap{} err := client.Get( @@ -604,12 +603,12 @@ func GetDefaultNamespace() string { return defaultNamespace } -// GetMonitoringCRName returns monitoring cr name +// GetMonitoringCRName returns monitoring cr name. func GetMonitoringCRName() string { return monitoringCRName } -// SetMonitoringCRName sets the cr name +// SetMonitoringCRName sets the cr name. func SetMonitoringCRName(crName string) { monitoringCRName = crName } @@ -620,7 +619,7 @@ func infrastructureConfigNameNsN() types.NamespacedName { } } -// GetKubeAPIServerAddress is used to get the api server url +// GetKubeAPIServerAddress is used to get the api server url. func GetKubeAPIServerAddress(client client.Client) (string, error) { infraConfig := &ocinfrav1.Infrastructure{} if err := client.Get(context.TODO(), infrastructureConfigNameNsN(), infraConfig); err != nil { @@ -630,7 +629,7 @@ func GetKubeAPIServerAddress(client client.Client) (string, error) { return infraConfig.Status.APIServerURL, nil } -// GetClusterID is used to get the cluster uid +// GetClusterID is used to get the cluster uid. func GetClusterID(ocpClient ocpClientSet.Interface) (string, error) { clusterVersion, err := ocpClient.ConfigV1().ClusterVersions().Get(context.TODO(), "version", v1.GetOptions{}) if err != nil { @@ -642,7 +641,7 @@ func GetClusterID(ocpClient ocpClientSet.Interface) (string, error) { } // checkIsIBMCloud detects if the current cloud vendor is ibm or not -// we know we are on OCP already, so if it's also ibm cloud, it's roks +// we know we are on OCP already, so if it's also ibm cloud, it's roks. func CheckIsIBMCloud(c client.Client) (bool, error) { nodes := &corev1.NodeList{} err := c.List(context.TODO(), nodes) @@ -668,7 +667,7 @@ func GetDefaultCRName() string { return defaultCRName } -// IsPaused returns true if the multiclusterobservability instance is labeled as paused, and false otherwise +// IsPaused returns true if the multiclusterobservability instance is labeled as paused, and false otherwise. func IsPaused(annotations map[string]string) bool { if annotations == nil { return false @@ -699,7 +698,7 @@ func WithoutResourcesRequests(annotations map[string]string) bool { return false } -// GetTenantUID returns tenant uid +// GetTenantUID returns tenant uid. func GetTenantUID() string { if tenantUID == "" { tenantUID = string(uuid.NewUUID()) @@ -707,17 +706,17 @@ func GetTenantUID() string { return tenantUID } -// GetObsAPISvc returns observatorium api service +// GetObsAPISvc returns observatorium api service. func GetObsAPISvc(instanceName string) string { return instanceName + "-observatorium-api." + defaultNamespace + ".svc.cluster.local" } -// SetCustomRuleConfigMap set true if there is custom rule configmap +// SetCustomRuleConfigMap set true if there is custom rule configmap. func SetCustomRuleConfigMap(hasConfigMap bool) { hasCustomRuleConfigMap = hasConfigMap } -// HasCustomRuleConfigMap returns true if there is custom rule configmap +// HasCustomRuleConfigMap returns true if there is custom rule configmap. func HasCustomRuleConfigMap() bool { return hasCustomRuleConfigMap } @@ -1103,15 +1102,15 @@ func SetOperandNames(c client.Client) error { return nil } -// CleanUpOperandNames delete all the operand name items -// Should be called when the MCO CR is deleted +// CleanUpOperandNames delete all the operand name items. +// Should be called when the MCO CR is deleted. func CleanUpOperandNames() { for k := range operandNames { delete(operandNames, k) } } -// GetValidatingWebhookConfigurationForMCO return the ValidatingWebhookConfiguration for the MCO validaing webhook +// GetValidatingWebhookConfigurationForMCO return the ValidatingWebhookConfiguration for the MCO validaing webhook. func GetValidatingWebhookConfigurationForMCO() *admissionregistrationv1.ValidatingWebhookConfiguration { validatingWebhookPath := "/validate-observability-open-cluster-management-io-v1beta2-multiclusterobservability" noSideEffects := admissionregistrationv1.SideEffectClassNone @@ -1161,7 +1160,7 @@ func GetValidatingWebhookConfigurationForMCO() *admissionregistrationv1.Validati } } -// GetMulticloudConsoleHost is used to get the URL for multicloud-console route +// GetMulticloudConsoleHost is used to get the URL for multicloud-console route. func GetMulticloudConsoleHost(client client.Client, isStandalone bool) (string, error) { if multicloudConsoleRouteHost != "" { return multicloudConsoleRouteHost, nil @@ -1182,7 +1181,7 @@ func GetMulticloudConsoleHost(client client.Client, isStandalone bool) (string, return found.Spec.Host, nil } -// Set AnnotationMCOAlerting +// Set AnnotationMCOAlerting. func SetAlertingDisabled(status bool) { isAlertingDisabled = status } @@ -1191,7 +1190,7 @@ func IsAlertingDisabled() bool { return isAlertingDisabled } -// Get AnnotationMCOAlerting +// Get AnnotationMCOAlerting. func IsAlertingDisabledInSpec(mco *observabilityv1beta2.MultiClusterObservability) bool { if mco == nil { return false diff --git a/operators/multiclusterobservability/pkg/config/config_test.go b/operators/multiclusterobservability/pkg/config/config_test.go index 4957f957b..3ff34ade6 100644 --- a/operators/multiclusterobservability/pkg/config/config_test.go +++ b/operators/multiclusterobservability/pkg/config/config_test.go @@ -28,7 +28,6 @@ import ( var ( apiServerURL = "http://example.com" clusterID = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" - version = "2.1.1" DefaultDSImgRepository = "quay.io:443/acm-d" ) @@ -217,7 +216,7 @@ func TestGetKubeAPIServerAddress(t *testing.T) { } scheme := runtime.NewScheme() scheme.AddKnownTypes(configv1.GroupVersion, inf) - client := fake.NewFakeClientWithScheme(scheme, inf) + client := fake.NewClientBuilder().WithScheme(scheme).WithRuntimeObjects(inf).Build() apiURL, _ := GetKubeAPIServerAddress(client) if apiURL != apiServerURL { t.Errorf("Kubenetes API Server Address (%v) is not the expected (%v)", apiURL, apiServerURL) @@ -264,7 +263,7 @@ func TestGetObsAPIHost(t *testing.T) { } scheme := runtime.NewScheme() scheme.AddKnownTypes(routev1.GroupVersion, route) - client := fake.NewFakeClientWithScheme(scheme, route) + client := fake.NewClientBuilder().WithScheme(scheme).WithRuntimeObjects(route).Build() host, _ := GetObsAPIHost(client, "default") if host == apiServerURL { @@ -329,12 +328,11 @@ func NewFakeClient(mco *mcov1beta2.MultiClusterObservability, s.AddKnownTypes(mcov1beta2.GroupVersion, mco) s.AddKnownTypes(observatoriumv1alpha1.GroupVersion, obs) objs := []runtime.Object{mco, obs} - return fake.NewFakeClientWithScheme(s, objs...) + return fake.NewClientBuilder().WithScheme(s).WithRuntimeObjects(objs...).Build() } func TestReadImageManifestConfigMap(t *testing.T) { - var buildTestImageManifestCM func(ns, version string) *corev1.ConfigMap - buildTestImageManifestCM = func(ns, version string) *corev1.ConfigMap { + buildTestImageManifestCM := func(ns, version string) *corev1.ConfigMap { return &corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ Name: ImageManifestConfigMapNamePrefix + version, @@ -430,7 +428,7 @@ func TestReadImageManifestConfigMap(t *testing.T) { for _, cmName := range c.inputCMList { initObjs = append(initObjs, buildTestImageManifestCM(ns, cmName)) } - client := fake.NewFakeClientWithScheme(scheme, initObjs...) + client := fake.NewClientBuilder().WithScheme(scheme).WithRuntimeObjects(initObjs...).Build() gotRet, err := ReadImageManifestConfigMap(client, c.version) if err != nil { @@ -468,7 +466,7 @@ func Test_checkIsIBMCloud(t *testing.T) { { name: "is normal ocp", args: args{ - client: fake.NewFakeClientWithScheme(s, []runtime.Object{nodeOther}...), + client: fake.NewClientBuilder().WithScheme(s).WithRuntimeObjects(nodeOther).Build(), name: "test-secret", }, want: false, @@ -477,7 +475,7 @@ func Test_checkIsIBMCloud(t *testing.T) { { name: "is ibm", args: args{ - client: fake.NewFakeClientWithScheme(s, []runtime.Object{nodeIBM}...), + client: fake.NewClientBuilder().WithScheme(s).WithRuntimeObjects(nodeIBM).Build(), name: "test-secret", }, want: true, @@ -882,7 +880,7 @@ func TestGetOperandName(t *testing.T) { name: "No Observatorium CR", componentName: Alertmanager, prepare: func() { - SetOperandNames(fake.NewFakeClientWithScheme(runtime.NewScheme())) + SetOperandNames(fake.NewClientBuilder().WithScheme(runtime.NewScheme()).Build()) }, result: func() bool { return GetOperandName(Alertmanager) == GetOperandNamePrefix()+"alertmanager" @@ -920,7 +918,7 @@ func TestGetOperandName(t *testing.T) { s := scheme.Scheme mcov1beta2.SchemeBuilder.AddToScheme(s) observatoriumv1alpha1.AddToScheme(s) - client := fake.NewFakeClientWithScheme(s, []runtime.Object{mco, observatorium}...) + client := fake.NewClientBuilder().WithScheme(s).WithRuntimeObjects(mco, observatorium).Build() SetMonitoringCRName(GetDefaultCRName()) SetOperandNames(client) }, @@ -968,7 +966,7 @@ func TestGetOperandName(t *testing.T) { s := scheme.Scheme mcov1beta2.SchemeBuilder.AddToScheme(s) observatoriumv1alpha1.AddToScheme(s) - client := fake.NewFakeClientWithScheme(s, []runtime.Object{mco, observatorium}...) + client := fake.NewClientBuilder().WithScheme(s).WithRuntimeObjects(mco, observatorium).Build() SetMonitoringCRName(GetDefaultCRName()) SetOperandNames(client) @@ -1017,7 +1015,7 @@ func TestGetOperandName(t *testing.T) { s := scheme.Scheme mcov1beta2.SchemeBuilder.AddToScheme(s) observatoriumv1alpha1.AddToScheme(s) - client := fake.NewFakeClientWithScheme(s, []runtime.Object{mco, observatorium}...) + client := fake.NewClientBuilder().WithScheme(s).WithRuntimeObjects(mco, observatorium).Build() SetMonitoringCRName(GetDefaultCRName()) SetOperandNames(client) diff --git a/operators/multiclusterobservability/pkg/config/gcs_conf.go b/operators/multiclusterobservability/pkg/config/gcs_conf.go index 1bf7fbf02..e43e4caef 100644 --- a/operators/multiclusterobservability/pkg/config/gcs_conf.go +++ b/operators/multiclusterobservability/pkg/config/gcs_conf.go @@ -23,7 +23,7 @@ func validateGCS(conf Config) error { return nil } -// IsValidGCSConf is used to validate GCS configuration +// IsValidGCSConf is used to validate GCS configuration. func IsValidGCSConf(data []byte) (bool, error) { var objectConfg ObjectStorgeConf err := yaml.Unmarshal(data, &objectConfg) diff --git a/operators/multiclusterobservability/pkg/config/obj_storage_conf.go b/operators/multiclusterobservability/pkg/config/obj_storage_conf.go index 11ba78543..2831d5c2c 100644 --- a/operators/multiclusterobservability/pkg/config/obj_storage_conf.go +++ b/operators/multiclusterobservability/pkg/config/obj_storage_conf.go @@ -12,7 +12,7 @@ import ( "gopkg.in/yaml.v2" ) -// Config is for s3/azure/gcs compatiable configuration +// Config is for s3/azure/gcs compatible configuration. type Config struct { // s3 configuration Bucket string `yaml:"bucket"` @@ -65,7 +65,7 @@ type TLSConfig struct { InsecureSkipVerify bool `yaml:"insecure_skip_verify"` } -// CheckObjStorageConf is used to check/valid the object storage configurations +// CheckObjStorageConf is used to check/valid the object storage configurations. func CheckObjStorageConf(data []byte) (bool, error) { var objectConfg ObjectStorgeConf err := yaml.Unmarshal(data, &objectConfg) diff --git a/operators/multiclusterobservability/pkg/config/s3_conf.go b/operators/multiclusterobservability/pkg/config/s3_conf.go index ed2558d28..446cd0404 100644 --- a/operators/multiclusterobservability/pkg/config/s3_conf.go +++ b/operators/multiclusterobservability/pkg/config/s3_conf.go @@ -23,7 +23,7 @@ func validateS3(conf Config) error { return nil } -// IsValidS3Conf is used to validate s3 configuration +// IsValidS3Conf is used to validate s3 configuration. func IsValidS3Conf(data []byte) (bool, error) { var objectConfg ObjectStorgeConf err := yaml.Unmarshal(data, &objectConfg) diff --git a/operators/multiclusterobservability/pkg/rendering/renderer.go b/operators/multiclusterobservability/pkg/rendering/renderer.go index 4c1596392..bdd90c593 100644 --- a/operators/multiclusterobservability/pkg/rendering/renderer.go +++ b/operators/multiclusterobservability/pkg/rendering/renderer.go @@ -4,14 +4,11 @@ package rendering import ( - "fmt" - v1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" logf "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/kustomize/api/resource" obv1beta2 "github.com/stolostron/multicluster-observability-operator/operators/multiclusterobservability/api/v1beta2" "github.com/stolostron/multicluster-observability-operator/operators/multiclusterobservability/pkg/config" @@ -151,21 +148,3 @@ func (r *MCORenderer) Render() ([]*unstructured.Unstructured, error) { return resources, nil } - -func (r *MCORenderer) renderMutatingWebhookConfiguration(res *resource.Resource) (*unstructured.Unstructured, error) { - m, err := res.Map() - if err != nil { - return nil, err - } - u := &unstructured.Unstructured{Object: m} - webooks, ok := u.Object["webhooks"].([]interface{}) - if !ok { - return nil, fmt.Errorf("failed to find webhooks spec field") - } - webhook := webooks[0].(map[string]interface{}) - clientConfig := webhook["clientConfig"].(map[string]interface{}) - service := clientConfig["service"].(map[string]interface{}) - - service["namespace"] = mcoconfig.GetDefaultNamespace() - return u, nil -} diff --git a/operators/multiclusterobservability/pkg/rendering/templates/templates.go b/operators/multiclusterobservability/pkg/rendering/templates/templates.go index a7048b256..dc4e727ac 100644 --- a/operators/multiclusterobservability/pkg/rendering/templates/templates.go +++ b/operators/multiclusterobservability/pkg/rendering/templates/templates.go @@ -11,10 +11,10 @@ import ( "github.com/stolostron/multicluster-observability-operator/operators/pkg/rendering/templates" ) -// *Templates contains all kustomize resources +// *Templates contains all kustomize resources. var genericTemplates, grafanaTemplates, alertManagerTemplates, thanosTemplates, proxyTemplates, endpointObservabilityTemplates, prometheusTemplates []*resource.Resource -// GetOrLoadGenericTemplates reads base manifest +// GetOrLoadGenericTemplates reads base manifest. func GetOrLoadGenericTemplates(r *templates.TemplateRenderer) ([]*resource.Resource, error) { if len(genericTemplates) > 0 { return genericTemplates, nil @@ -35,7 +35,7 @@ func GetOrLoadGenericTemplates(r *templates.TemplateRenderer) ([]*resource.Resou return genericTemplates, nil } -// GetOrLoadGrafanaTemplates reads the grafana manifests +// GetOrLoadGrafanaTemplates reads the grafana manifests. func GetOrLoadGrafanaTemplates(r *templates.TemplateRenderer) ([]*resource.Resource, error) { if len(grafanaTemplates) > 0 { return grafanaTemplates, nil @@ -50,7 +50,7 @@ func GetOrLoadGrafanaTemplates(r *templates.TemplateRenderer) ([]*resource.Resou return grafanaTemplates, nil } -// GetOrLoadAlertManagerTemplates reads the alertmanager manifests +// GetOrLoadAlertManagerTemplates reads the alertmanager manifests. func GetOrLoadAlertManagerTemplates(r *templates.TemplateRenderer) ([]*resource.Resource, error) { if len(alertManagerTemplates) > 0 { return alertManagerTemplates, nil @@ -65,7 +65,7 @@ func GetOrLoadAlertManagerTemplates(r *templates.TemplateRenderer) ([]*resource. return alertManagerTemplates, nil } -// GetOrLoadThanosTemplates reads the thanos manifests +// GetOrLoadThanosTemplates reads the thanos manifests. func GetOrLoadThanosTemplates(r *templates.TemplateRenderer) ([]*resource.Resource, error) { if len(thanosTemplates) > 0 { return thanosTemplates, nil @@ -80,7 +80,7 @@ func GetOrLoadThanosTemplates(r *templates.TemplateRenderer) ([]*resource.Resour return thanosTemplates, nil } -// GetOrLoadProxyTemplates reads the rbac-query-proxy manifests +// GetOrLoadProxyTemplates reads the rbac-query-proxy manifests. func GetOrLoadProxyTemplates(r *templates.TemplateRenderer) ([]*resource.Resource, error) { if len(proxyTemplates) > 0 { return proxyTemplates, nil @@ -95,7 +95,7 @@ func GetOrLoadProxyTemplates(r *templates.TemplateRenderer) ([]*resource.Resourc return proxyTemplates, nil } -// GetEndpointObservabilityTemplates reads endpoint-observability manifest +// GetEndpointObservabilityTemplates reads endpoint-observability manifest. func GetOrLoadEndpointObservabilityTemplates(r *templates.TemplateRenderer) ([]*resource.Resource, error) { if len(endpointObservabilityTemplates) > 0 { return endpointObservabilityTemplates, nil @@ -111,7 +111,7 @@ func GetOrLoadEndpointObservabilityTemplates(r *templates.TemplateRenderer) ([]* return endpointObservabilityTemplates, nil } -// GetOrLoadPrometheusTemplates reads endpoint-observability manifest +// GetOrLoadPrometheusTemplates reads endpoint-observability manifest. func GetOrLoadPrometheusTemplates(r *templates.TemplateRenderer) ([]*resource.Resource, error) { if len(prometheusTemplates) > 0 { return prometheusTemplates, nil @@ -127,7 +127,7 @@ func GetOrLoadPrometheusTemplates(r *templates.TemplateRenderer) ([]*resource.Re return prometheusTemplates, nil } -// ResetTemplates reset all the loaded templates +// ResetTemplates reset all the loaded templates. func ResetTemplates() { genericTemplates = nil grafanaTemplates = nil diff --git a/operators/multiclusterobservability/pkg/util/clustermanagementaddon.go b/operators/multiclusterobservability/pkg/util/clustermanagementaddon.go index 955f39baa..ba52d8229 100644 --- a/operators/multiclusterobservability/pkg/util/clustermanagementaddon.go +++ b/operators/multiclusterobservability/pkg/util/clustermanagementaddon.go @@ -30,9 +30,9 @@ type clusterManagementAddOnSpec struct { CRDName string `json:"crdName"` } -func CreateClusterManagementAddon(c client.Client, isStandalone bool) ( +func CreateClusterManagementAddon(c client.Client) ( *addonv1alpha1.ClusterManagementAddOn, error) { - clusterManagementAddon, err := newClusterManagementAddon(c, isStandalone) + clusterManagementAddon, err := newClusterManagementAddon(c) if err != nil { return nil, err } @@ -69,7 +69,7 @@ func DeleteClusterManagementAddon(client client.Client) error { return nil } -func newClusterManagementAddon(c client.Client, isStandalone bool) (*addonv1alpha1.ClusterManagementAddOn, error) { +func newClusterManagementAddon(c client.Client) (*addonv1alpha1.ClusterManagementAddOn, error) { host, err := config.GetRouteHost(c, config.GrafanaRouteName, config.GetDefaultNamespace()) if err != nil { return nil, err diff --git a/operators/multiclusterobservability/pkg/util/clustermanagementaddon_test.go b/operators/multiclusterobservability/pkg/util/clustermanagementaddon_test.go index e439bf9f4..e68caf757 100644 --- a/operators/multiclusterobservability/pkg/util/clustermanagementaddon_test.go +++ b/operators/multiclusterobservability/pkg/util/clustermanagementaddon_test.go @@ -33,12 +33,12 @@ func TestClusterManagmentAddon(t *testing.T) { }, } - c := fake.NewFakeClient(consoleRoute) - _, err := CreateClusterManagementAddon(c, false) + c := fake.NewClientBuilder().WithRuntimeObjects(consoleRoute).Build() + _, err := CreateClusterManagementAddon(c) if err != nil { t.Fatalf("Failed to create clustermanagementaddon: (%v)", err) } - _, err = CreateClusterManagementAddon(c, false) + _, err = CreateClusterManagementAddon(c) if err != nil { t.Fatalf("Failed to create clustermanagementaddon twice: (%v)", err) } diff --git a/operators/multiclusterobservability/pkg/util/managedclusteraddon.go b/operators/multiclusterobservability/pkg/util/managedclusteraddon.go index 3e67d8a2d..428577d07 100644 --- a/operators/multiclusterobservability/pkg/util/managedclusteraddon.go +++ b/operators/multiclusterobservability/pkg/util/managedclusteraddon.go @@ -93,6 +93,8 @@ func CreateManagedClusterAddonCR(c client.Client, namespace, labelKey, labelValu } // got the created managedclusteraddon just now, uopdating its status + // TODO(saswatamcode): Remove deprecated field + //nolint:staticcheck managedClusterAddon.Status.AddOnConfiguration = addonv1alpha1.ConfigCoordinates{ CRDName: "observabilityaddons.observability.open-cluster-management.io", CRName: "observability-addon", diff --git a/operators/multiclusterobservability/pkg/util/managedclusteraddon_test.go b/operators/multiclusterobservability/pkg/util/managedclusteraddon_test.go index 0df777b84..c53786f61 100644 --- a/operators/multiclusterobservability/pkg/util/managedclusteraddon_test.go +++ b/operators/multiclusterobservability/pkg/util/managedclusteraddon_test.go @@ -22,7 +22,7 @@ const ( func TestManagedClusterAddon(t *testing.T) { s := scheme.Scheme addonv1alpha1.AddToScheme(s) - c := fake.NewFakeClient() + c := fake.NewClientBuilder().Build() _, err := CreateManagedClusterAddonCR(c, namespace, "testKey", "value") if err != nil { t.Fatalf("Failed to create managedclusteraddon: (%v)", err) diff --git a/operators/multiclusterobservability/pkg/util/remotewriteendpoint.go b/operators/multiclusterobservability/pkg/util/remotewriteendpoint.go index 436a9dac9..c77ab7b03 100644 --- a/operators/multiclusterobservability/pkg/util/remotewriteendpoint.go +++ b/operators/multiclusterobservability/pkg/util/remotewriteendpoint.go @@ -66,10 +66,10 @@ type HTTPClientConfigWithSecret struct { Authorization *AuthorizationWithSecret `yaml:"authorization,omitempty" json:"authorization,omitempty"` // The OAuth2 client credentials used to fetch a token for the targets. OAuth2 *OAuth2WithSecret `yaml:"oauth2,omitempty" json:"oauth2,omitempty"` - // The bearer token for the targets. Deprecated in favour of + // The bearer token for the targets. Deprecated in favor of // Authorization.Credentials. BearerToken string `yaml:"bearer_token,omitempty" json:"bearer_token,omitempty"` - // The bearer token file for the targets. Deprecated in favour of + // The bearer token file for the targets. Deprecated in favor of // Authorization.CredentialsFile. BearerTokenFile string `yaml:"bearer_token_file,omitempty" json:"bearer_token_file,omitempty"` // Name of the secret which contains the file @@ -81,7 +81,7 @@ type HTTPClientConfigWithSecret struct { TLSConfig *TLSConfigWithSecret `yaml:"tls_config,omitempty" json:"tls_config,omitempty"` // FollowRedirects specifies whether the client should follow HTTP 3xx redirects. // The omitempty flag is not set, because it would be hidden from the - // marshalled configuration when set to false. + // marshaled configuration when set to false. FollowRedirects bool `yaml:"follow_redirects" json:"follow_redirects"` } diff --git a/operators/multiclusterobservability/pkg/util/remotewriteendpoint_test.go b/operators/multiclusterobservability/pkg/util/remotewriteendpoint_test.go index e49e4760d..b137dbe29 100644 --- a/operators/multiclusterobservability/pkg/util/remotewriteendpoint_test.go +++ b/operators/multiclusterobservability/pkg/util/remotewriteendpoint_test.go @@ -1,7 +1,6 @@ package util import ( - "fmt" "path" "testing" ) @@ -49,31 +48,31 @@ func TestTransform(t *testing.T) { } newConfig, names := Transform(*config) - if newConfig.BasicAuth.PasswordFile != fmt.Sprintf(path.Join(MountPath, basicAuthSName, basicAuthSKey)) { + if newConfig.BasicAuth.PasswordFile != path.Join(MountPath, basicAuthSName, basicAuthSKey) { t.Fatalf("Wrong path for BasicAuth.PasswordFile: %s", newConfig.BasicAuth.PasswordFile) } - if newConfig.Authorization.CredentialsFile != fmt.Sprintf(path.Join(MountPath, AuthSName, AuthSKey)) { + if newConfig.Authorization.CredentialsFile != path.Join(MountPath, AuthSName, AuthSKey) { t.Fatalf("Wrong path for Authorization.CredentialsFile: %s", newConfig.Authorization.CredentialsFile) } - if newConfig.OAuth2.ClientSecretFile != fmt.Sprintf(path.Join(MountPath, OAuth2SName, OAuth2SKey)) { + if newConfig.OAuth2.ClientSecretFile != path.Join(MountPath, OAuth2SName, OAuth2SKey) { t.Fatalf("Wrong path for OAuth2.ClientSecretFile: %s", newConfig.OAuth2.ClientSecretFile) } - if newConfig.BearerTokenFile != fmt.Sprintf(path.Join(MountPath, BearerTokenSName, BearerTokenSKey)) { + if newConfig.BearerTokenFile != path.Join(MountPath, BearerTokenSName, BearerTokenSKey) { t.Fatalf("Wrong path for BearerTokenFile: %s", newConfig.BearerTokenFile) } - if newConfig.TLSConfig.CAFile != fmt.Sprintf(path.Join(MountPath, TLSSName, TLSCAKey)) { + if newConfig.TLSConfig.CAFile != path.Join(MountPath, TLSSName, TLSCAKey) { t.Fatalf("Wrong path for TLSConfig.CAFile: %s", newConfig.TLSConfig.CAFile) } - if newConfig.TLSConfig.CertFile != fmt.Sprintf(path.Join(MountPath, TLSSName, TLSCertKey)) { + if newConfig.TLSConfig.CertFile != path.Join(MountPath, TLSSName, TLSCertKey) { t.Fatalf("Wrong path for TLSConfig.CertFile: %s", newConfig.TLSConfig.CertFile) } - if newConfig.TLSConfig.KeyFile != fmt.Sprintf(path.Join(MountPath, TLSSName, TLSKeyKey)) { + if newConfig.TLSConfig.KeyFile != path.Join(MountPath, TLSSName, TLSKeyKey) { t.Fatalf("Wrong path for TLSConfig.KeyFile: %s", newConfig.TLSConfig.KeyFile) } diff --git a/operators/multiclusterobservability/pkg/webhook/webhook_controller_test.go b/operators/multiclusterobservability/pkg/webhook/webhook_controller_test.go index e6b2512a1..5d38b0e48 100644 --- a/operators/multiclusterobservability/pkg/webhook/webhook_controller_test.go +++ b/operators/multiclusterobservability/pkg/webhook/webhook_controller_test.go @@ -137,7 +137,7 @@ func TestWebhookController(t *testing.T) { if c.existingvwh != nil { objs = append(objs, c.existingvwh) } - cl := fake.NewFakeClient(objs...) + cl := fake.NewClientBuilder().WithRuntimeObjects(objs...).Build() wc := NewWebhookController(cl, c.reconciledmwh, c.reconciledvwh) ctx, cancel := context.WithCancel(context.Background()) go func() { diff --git a/operators/multiclusterobservability/prestop.sh b/operators/multiclusterobservability/prestop.sh index 9d86f2b48..018c61057 100755 --- a/operators/multiclusterobservability/prestop.sh +++ b/operators/multiclusterobservability/prestop.sh @@ -24,4 +24,3 @@ ValidatingWebhookConfigurationName=multicluster-observability-operator # Delete the validatingwebhookconfiguration with TOKEN curl --cacert ${CACERT} --header "Authorization: Bearer ${TOKEN}" -X DELETE ${APISERVER}/apis/admissionregistration.k8s.io/v1/validatingwebhookconfigurations/${ValidatingWebhookConfigurationName} - diff --git a/operators/pkg/config/config.go b/operators/pkg/config/config.go index 38f925cf8..9b3424f7f 100644 --- a/operators/pkg/config/config.go +++ b/operators/pkg/config/config.go @@ -47,7 +47,7 @@ const ( PrometheusConfigmapReloaderKey = "prometheus_config_reloader" ) -// Annotations to uspport OpenShift workload partitioning +// Annotations to uspport OpenShift workload partitioning. const ( WorkloadPartitioningPodAnnotationKey = "target.workload.openshift.io/management" WorkloadPodExpectedValueJSON = "{\"effect\":\"PreferredDuringScheduling\"}" diff --git a/operators/pkg/config/types.go b/operators/pkg/config/types.go index c0772cfc6..e4feaf48d 100644 --- a/operators/pkg/config/types.go +++ b/operators/pkg/config/types.go @@ -10,7 +10,7 @@ import ( // HubInfo is the struct that contains the common information about the hub // cluster, for example the name of managed cluster on the hub, the URL of // observatorium api gateway, the URL of hub alertmanager and the CA for the -// hub router +// hub router. type HubInfo struct { ClusterName string `yaml:"cluster-name"` ObservatoriumAPIEndpoint string `yaml:"observatorium-api-endpoint"` diff --git a/operators/pkg/deploying/deployer.go b/operators/pkg/deploying/deployer.go index 1f443c7d2..13d3cac04 100644 --- a/operators/pkg/deploying/deployer.go +++ b/operators/pkg/deploying/deployer.go @@ -28,13 +28,13 @@ var log = logf.Log.WithName("deploying") type deployerFn func(*unstructured.Unstructured, *unstructured.Unstructured) error -// Deployer is used create or update the resources +// Deployer is used create or update the resources. type Deployer struct { client client.Client deployerFns map[string]deployerFn } -// NewDeployer inits the deployer +// NewDeployer inits the deployer. func NewDeployer(client client.Client) *Deployer { deployer := &Deployer{client: client} deployer.deployerFns = map[string]deployerFn{ @@ -52,7 +52,7 @@ func NewDeployer(client client.Client) *Deployer { return deployer } -// Deploy is used to create or update the resources +// Deploy is used to create or update the resources. func (d *Deployer) Deploy(obj *unstructured.Unstructured) error { found := &unstructured.Unstructured{} found.SetGroupVersionKind(obj.GroupVersionKind()) diff --git a/operators/pkg/deploying/deployer_test.go b/operators/pkg/deploying/deployer_test.go index 5cc1d79bd..c90bf1090 100644 --- a/operators/pkg/deploying/deployer_test.go +++ b/operators/pkg/deploying/deployer_test.go @@ -471,11 +471,12 @@ func TestDeploy(t *testing.T) { } scheme := runtime.NewScheme() + corev1.AddToScheme(scheme) appsv1.AddToScheme(scheme) rbacv1.AddToScheme(scheme) prometheusv1.AddToScheme(scheme) - client := fake.NewFakeClientWithScheme(scheme, []runtime.Object{}...) + client := fake.NewClientBuilder().WithScheme(scheme).Build() deployer := NewDeployer(client) diff --git a/operators/pkg/rendering/renderer.go b/operators/pkg/rendering/renderer.go index 6aaaf6b32..7ffa15c83 100644 --- a/operators/pkg/rendering/renderer.go +++ b/operators/pkg/rendering/renderer.go @@ -4,7 +4,7 @@ package rendering import ( - "fmt" + "errors" "strconv" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -85,7 +85,9 @@ func (r *Renderer) RenderDeployments( return nil, err } */ - res.SetNamespace(namespace) + if err := res.SetNamespace(namespace); err != nil { + return nil, err + } m, err := res.Map() if err != nil { return nil, err @@ -106,7 +108,9 @@ func (r *Renderer) RenderNamespace( u := &unstructured.Unstructured{Object: m} if UpdateNamespace(u) { u.SetNamespace(namespace) - res.SetNamespace(namespace) + if err := res.SetNamespace(namespace); err != nil { + return nil, err + } } return u, nil @@ -157,7 +161,7 @@ func (r *Renderer) RenderClusterRoleBinding( subjects, ok := u.Object["subjects"].([]interface{}) if !ok { - return nil, fmt.Errorf("failed to find clusterrolebinding subjects field") + return nil, errors.New("failed to find clusterrolebinding subjects field") } subject := subjects[0].(map[string]interface{}) kind := subject["kind"] @@ -173,7 +177,7 @@ func (r *Renderer) RenderClusterRoleBinding( return u, nil } -// UpdateNamespace checks for annotiation to update NS +// UpdateNamespace checks for annotiation to update NS. func UpdateNamespace(u *unstructured.Unstructured) bool { annotations := u.GetAnnotations() v, ok := annotations[nsUpdateAnnoKey] diff --git a/operators/pkg/util/allowlist_test.go b/operators/pkg/util/allowlist_test.go index ea8ba7309..95098580a 100644 --- a/operators/pkg/util/allowlist_test.go +++ b/operators/pkg/util/allowlist_test.go @@ -9,6 +9,7 @@ import ( "github.com/stolostron/multicluster-observability-operator/operators/multiclusterobservability/pkg/config" operatorconfig "github.com/stolostron/multicluster-observability-operator/operators/pkg/config" + "golang.org/x/exp/slices" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/client/fake" @@ -101,7 +102,7 @@ names: } func TestMergeAllowList(t *testing.T) { - c := fake.NewFakeClient(getAllowlistCM(), geCustomAllowlistCM()) + c := fake.NewClientBuilder().WithRuntimeObjects(getAllowlistCM(), geCustomAllowlistCM()).Build() allowlist, ocp3Allowlist, uwlAllowlist, err := GetAllowList(c, operatorconfig.AllowlistConfigMapName, config.GetDefaultNamespace()) if err != nil { @@ -114,13 +115,13 @@ func TestMergeAllowList(t *testing.T) { } list, ocp3List, uwlList := MergeAllowlist(allowlist, customAllowlist, ocp3Allowlist, uwlAllowlist, customUwlAllowlist) - if !Contains(list.NameList, "custom_a") { + if !slices.Contains(list.NameList, "custom_a") { t.Error("metrics custom_a not merged into allowlist") } - if !Contains(ocp3List.NameList, "custom_a") { + if !slices.Contains(ocp3List.NameList, "custom_a") { t.Error("metrics custom_a not merged into allowlist") } - if !Contains(uwlList.NameList, "custom_uwl_a") { + if !slices.Contains(uwlList.NameList, "custom_uwl_a") { t.Error("metrics custom_uwl_a not merged into uwl allowlist") } } diff --git a/operators/pkg/util/client.go b/operators/pkg/util/client.go index 4c7a01aa4..761884ee8 100644 --- a/operators/pkg/util/client.go +++ b/operators/pkg/util/client.go @@ -31,7 +31,7 @@ var ( promClient promClientSet.Interface ) -// GetOrCreateKubeClient gets existing kubeclient or creates new one if it doesn't exist +// GetOrCreateKubeClient gets existing kubeclient or creates new one if it doesn't exist. func GetOrCreateKubeClient() (kubernetes.Interface, error) { if kubeClient != nil { return kubeClient, nil @@ -53,7 +53,7 @@ func GetOrCreateKubeClient() (kubernetes.Interface, error) { return kubeClient, nil } -// GetOrCreateOCPClient creates ocp client +// GetOrCreateOCPClient creates ocp client. func GetOrCreateOCPClient() (ocpClientSet.Interface, error) { if crdClient != nil { return ocpClient, nil @@ -75,7 +75,7 @@ func GetOrCreateOCPClient() (ocpClientSet.Interface, error) { return ocpClient, err } -// GetOrCreateCRDClient gets an existing or creates a new CRD client +// GetOrCreateCRDClient gets an existing or creates a new CRD client. func GetOrCreateCRDClient() (crdClientSet.Interface, error) { if crdClient != nil { return crdClient, nil @@ -97,7 +97,7 @@ func GetOrCreateCRDClient() (crdClientSet.Interface, error) { return crdClient, err } -// GetOrCreatePromClient creates prometheus client +// GetOrCreatePromClient creates prometheus client. func GetOrCreatePromClient() (promClientSet.Interface, error) { if promClient != nil { return promClient, nil @@ -165,7 +165,7 @@ func UpdateCRDWebhookNS(crdClient crdClientSet.Interface, namespace, crdName str return nil } -// GetPVCList get pvc with matched labels +// GetPVCList get pvc with matched labels. func GetPVCList(c client.Client, namespace string, matchLabels map[string]string) ([]corev1.PersistentVolumeClaim, error) { pvcList := &corev1.PersistentVolumeClaimList{} @@ -181,7 +181,7 @@ func GetPVCList(c client.Client, namespace string, return pvcList.Items, nil } -// GetStatefulSetList get sts with matched labels +// GetStatefulSetList get sts with matched labels. func GetStatefulSetList(c client.Client, namespace string, matchLabels map[string]string) ([]appsv1.StatefulSet, error) { stsList := &appsv1.StatefulSetList{} diff --git a/operators/pkg/util/client_test.go b/operators/pkg/util/client_test.go index f8848a7e3..a8a9f1736 100644 --- a/operators/pkg/util/client_test.go +++ b/operators/pkg/util/client_test.go @@ -15,7 +15,7 @@ const ( ) func TestGetStatefulSetList(t *testing.T) { - c := fake.NewFakeClient() + c := fake.NewClientBuilder().Build() _, err := GetStatefulSetList(c, namespace, map[string]string{}) if err != nil { t.Fatalf("Failed to list statefulset: (%v)", err) @@ -23,7 +23,7 @@ func TestGetStatefulSetList(t *testing.T) { } func TestGetPVCList(t *testing.T) { - c := fake.NewFakeClient() + c := fake.NewClientBuilder().Build() _, err := GetPVCList(c, namespace, map[string]string{}) if err != nil { t.Fatalf("Failed to list pvc: (%v)", err) diff --git a/operators/pkg/util/obj_compare.go b/operators/pkg/util/obj_compare.go index 81a16dbf7..07076c810 100644 --- a/operators/pkg/util/obj_compare.go +++ b/operators/pkg/util/obj_compare.go @@ -85,7 +85,7 @@ func CompareObject(re1 runtime.RawExtension, re2 runtime.RawExtension) bool { version1 := obj1.GetObjectKind().GroupVersionKind().Version version2 := obj2.GetObjectKind().GroupVersionKind().Version if kind1 != kind2 || version1 != version2 { - log.Info("obj1 and obj2 have differnt Kind or Version", + log.Info("obj1 and obj2 have different Kind or Version", "kind1", kind2, "kind2", kind2, "version1", version1, "version2", version2) return false } diff --git a/operators/pkg/util/util.go b/operators/pkg/util/util.go index daf65ee81..70e215be8 100644 --- a/operators/pkg/util/util.go +++ b/operators/pkg/util/util.go @@ -29,16 +29,6 @@ func Remove(list []string, s string) []string { return result } -// Contains is used to check whether a list contains string s -func Contains(list []string, s string) bool { - for _, v := range list { - if v == s { - return true - } - } - return false -} - // GetAnnotation returns the annotation value for a given key, or an empty string if not set func GetAnnotation(annotations map[string]string, key string) string { if annotations == nil { diff --git a/operators/pkg/util/util_test.go b/operators/pkg/util/util_test.go index 35eef480a..3511273f3 100644 --- a/operators/pkg/util/util_test.go +++ b/operators/pkg/util/util_test.go @@ -6,7 +6,7 @@ import ( "testing" ) -//Siddharth's code +// Siddharth's code func TestRemove(t *testing.T) { type testCaseList struct { name string @@ -32,28 +32,7 @@ func TestRemove(t *testing.T) { } } -func TestContains(t *testing.T) { - testCaseList := []struct { - name string - list []string - s string - expected bool - }{ - {"contain sub string", []string{"a", "b"}, "a", true}, - {"shoud contain empty string", []string{""}, "", true}, - {"should not contain sub string", []string{"a", "b"}, "c", false}, - {"shoud not contain empty string", []string{"a", "b"}, "", false}, - } - - for _, c := range testCaseList { - output := Contains(c.list, c.s) - if output != c.expected { - t.Errorf("case (%v) output: (%v) is not the expected: (%v)", c.name, output, c.expected) - } - } -} - -//Siddharth's code +// Siddharth's code func TestGetAnnotation(t *testing.T) { type testCaseList struct { name string @@ -85,7 +64,7 @@ func TestGetAnnotation(t *testing.T) { } } -//func TestGeneratePassword +// func TestGeneratePassword func TestGeneratePassword(t *testing.T) { type testCaseList struct { name string @@ -142,7 +121,7 @@ func TestProxyEnvVarsAreSet(t *testing.T) { } } -//Siddharth's code +// Siddharth's code func TestRemoveDuplicates(t *testing.T) { type testCaseList struct { name string diff --git a/proxy/pkg/config/config.go b/proxy/pkg/config/config.go index 25902e16a..79991ffe6 100644 --- a/proxy/pkg/config/config.go +++ b/proxy/pkg/config/config.go @@ -30,37 +30,37 @@ var ( requiredLabelList = []string{"name", "cluster.open-cluster-management.io/clusterset"} ) -// GetManagedClusterLabelAllowListConfigMapKey return the key name for the managedcluster labels +// GetManagedClusterLabelAllowListConfigMapKey return the key name for the managedcluster labels. func GetManagedClusterLabelAllowListConfigMapKey() string { return ManagedClusterLabelAllowListConfigMapKey } -// GetManagedClusterLabelConfigMapName return the name for the managedcluster labels configmap +// GetManagedClusterLabelConfigMapName return the name for the managedcluster labels configmap. func GetManagedClusterLabelAllowListConfigMapName() string { return ManagedClusterLabelAllowListConfigMapName } -// GetManagedClusterLabelList will return the current cluster label list +// GetManagedClusterLabelList will return the current cluster label list. func GetManagedClusterLabelList() *ManagedClusterLabelList { return &ManagedLabelList } -// GetSyncLabelList will return the synced label list +// GetSyncLabelList will return the synced label list. func GetRequiredLabelList() []string { return requiredLabelList } -// GetSyncLabelList will return the synced label list +// GetSyncLabelList will return the synced label list. func GetSyncLabelList() *ManagedClusterLabelList { return &SyncLabelList } -// GetRBACProxyLabelMetricName returns the name of the rbac query proxy label metric +// GetRBACProxyLabelMetricName returns the name of the rbac query proxy label metric. func GetRBACProxyLabelMetricName() string { return RBACProxyLabelMetricName } -// CreateManagedClusterLabelAllowListCM creates a managedcluster label allowlist configmap object +// CreateManagedClusterLabelAllowListCM creates a managedcluster label allowlist configmap object. func CreateManagedClusterLabelAllowListCM(namespace string) *v1.ConfigMap { return &v1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ @@ -89,7 +89,7 @@ ignore_labels: `}} } -// GetManagedClusterLabelAllowListConfigmap returns the managedcluster label allowlist configmap +// GetManagedClusterLabelAllowListConfigmap returns the managedcluster label allowlist configmap. func GetManagedClusterLabelAllowListConfigmap(kubeClient kubernetes.Interface, namespace string) (*v1.ConfigMap, error) { configmap, err := kubeClient.CoreV1().ConfigMaps(namespace).Get( diff --git a/proxy/pkg/config/types.go b/proxy/pkg/config/types.go index d253c68de..962d7eb20 100644 --- a/proxy/pkg/config/types.go +++ b/proxy/pkg/config/types.go @@ -4,7 +4,7 @@ package config // ManagedClusterLabelList is the struct that contains the -// list of labels that are assigned to the managed clusters +// list of labels that are assigned to the managed clusters. type ManagedClusterLabelList struct { IgnoreList []string `yaml:"ignore_labels,omitempty"` LabelList []string `yaml:"labels"` diff --git a/proxy/pkg/proxy/proxy.go b/proxy/pkg/proxy/proxy.go index 39c055780..d9a7920e5 100644 --- a/proxy/pkg/proxy/proxy.go +++ b/proxy/pkg/proxy/proxy.go @@ -8,7 +8,6 @@ import ( "compress/gzip" "errors" "io" - "io/ioutil" "net/http" "net/http/httputil" "net/url" @@ -36,7 +35,7 @@ var ( func shouldModifyAPISeriesResponse(res http.ResponseWriter, req *http.Request) bool { if strings.HasSuffix(req.URL.Path, "/api/v1/series") { - body, err := ioutil.ReadAll(req.Body) + body, err := io.ReadAll(req.Body) if err != nil { klog.Errorf("failed to read body: %v", err) } @@ -62,14 +61,14 @@ func shouldModifyAPISeriesResponse(res http.ResponseWriter, req *http.Request) b } } - req.Body = ioutil.NopCloser(strings.NewReader(string(body))) + req.Body = io.NopCloser(strings.NewReader(string(body))) req.ContentLength = int64(len([]rune(string(body)))) } return false } -// HandleRequestAndRedirect is used to init proxy handler +// HandleRequestAndRedirect is used to init proxy handler. func HandleRequestAndRedirect(res http.ResponseWriter, req *http.Request) { if preCheckRequest(req) != nil { _, err := res.Write(newEmptyMatrixHTTPBody()) @@ -108,13 +107,6 @@ func HandleRequestAndRedirect(res http.ResponseWriter, req *http.Request) { proxy.ServeHTTP(res, req) } -func errorHandle(rw http.ResponseWriter, req *http.Request, err error) { - token := req.Header.Get("X-Forwarded-Access-Token") - if token == "" { - rw.WriteHeader(http.StatusUnauthorized) - } -} - func preCheckRequest(req *http.Request) error { token := req.Header.Get("X-Forwarded-Access-Token") if token == "" { @@ -189,7 +181,7 @@ func proxyRequest(r *http.Request) { strings.HasSuffix(r.URL.Path, "/api/v1/series") { r.Method = http.MethodPost r.Header.Set("Content-Type", "application/x-www-form-urlencoded") - r.Body = ioutil.NopCloser(strings.NewReader(r.URL.RawQuery)) + r.Body = io.NopCloser(strings.NewReader(r.URL.RawQuery)) } } } diff --git a/proxy/pkg/proxy/proxy_test.go b/proxy/pkg/proxy/proxy_test.go index 84b8b8a84..5d3b1514d 100644 --- a/proxy/pkg/proxy/proxy_test.go +++ b/proxy/pkg/proxy/proxy_test.go @@ -7,7 +7,6 @@ import ( "bytes" "compress/gzip" "io" - "io/ioutil" "log" "net/http" "net/url" @@ -21,16 +20,30 @@ import ( func TestNewEmptyMatrixHTTPBody(t *testing.T) { body := newEmptyMatrixHTTPBody() gr, err := gzip.NewReader(bytes.NewBuffer([]byte(body))) - defer gr.Close() - data, err := ioutil.ReadAll(gr) + if err != nil { + log.Fatal(err) + } + defer func() { + if err := gr.Close(); err != nil { + log.Fatal(err) + } + }() + data, err := io.ReadAll(gr) if err != nil { log.Fatal(err) } var decompressedBuff bytes.Buffer gr, err = gzip.NewReader(bytes.NewBuffer([]byte(data))) - defer gr.Close() - data, err = ioutil.ReadAll(gr) + if err != nil { + log.Fatal(err) + } + defer func() { + if err := gr.Close(); err != nil { + log.Fatal(err) + } + }() + data, err = io.ReadAll(gr) if err != nil { t.Errorf("failed to ReadAll: %v", err) } @@ -69,21 +82,10 @@ func (r *FakeResponse) WriteHeader(status int) { r.status = status } -func TestErrorHandle(t *testing.T) { - req, _ := http.NewRequest("GET", "http://127.0.0.1:3002/metrics/query?query=foo", nil) - req.Header.Set("X-Forwarded-User", "test") - var err error - fakeResp := NewFakeResponse(t) - errorHandle(fakeResp, req, err) - if fakeResp.status != http.StatusUnauthorized { - t.Errorf("failed to get expected status: %v", fakeResp.status) - } -} - func TestPreCheckRequest(t *testing.T) { req, _ := http.NewRequest("GET", "http://127.0.0.1:3002/metrics/query?query=foo", nil) resp := http.Response{ - Body: ioutil.NopCloser(bytes.NewBufferString("test")), + Body: io.NopCloser(bytes.NewBufferString("test")), Header: make(http.Header), Request: req, } @@ -131,8 +133,15 @@ func TestGzipWrite(t *testing.T) { } var decompressedBuff bytes.Buffer gr, err := gzip.NewReader(bytes.NewBuffer(compressedBuff.Bytes())) - defer gr.Close() - data, err := ioutil.ReadAll(gr) + if err != nil { + log.Fatal(err) + } + defer func() { + if err := gr.Close(); err != nil { + log.Fatal(err) + } + }() + data, err := io.ReadAll(gr) if err != nil { t.Errorf("failed to decompressed: %v", err) } diff --git a/proxy/pkg/proxy/tls.go b/proxy/pkg/proxy/tls.go index a3d7a714e..1c835bcd1 100644 --- a/proxy/pkg/proxy/tls.go +++ b/proxy/pkg/proxy/tls.go @@ -6,9 +6,9 @@ package proxy import ( "crypto/tls" "crypto/x509" - "io/ioutil" "net" "net/http" + "os" "path" "path/filepath" "time" @@ -28,7 +28,7 @@ func getTLSTransport() (*http.Transport, error) { tlsCrtFile := path.Join(certPath, "tls.crt") // Load Server CA cert - caCert, err := ioutil.ReadFile(filepath.Clean(caCertFile)) + caCert, err := os.ReadFile(filepath.Clean(caCertFile)) if err != nil { klog.Error("failed to load server ca cert file") return nil, err diff --git a/proxy/pkg/rewrite/rewrite.go b/proxy/pkg/rewrite/rewrite.go index 579232019..de5d1bca4 100644 --- a/proxy/pkg/rewrite/rewrite.go +++ b/proxy/pkg/rewrite/rewrite.go @@ -17,7 +17,7 @@ const ( placeholderMetrics = "acm_metrics_placeholder" ) -// InjectLabels is used to inject addtional label filters into original query +// InjectLabels is used to inject additional label filters into original query. func InjectLabels(query string, label string, values []string) (string, error) { reg := regexp.MustCompile(`([{|,][ ]*)(` + label + `[ ]*)(=|!=|=~|!~)([ ]*"[^"]+")`) diff --git a/proxy/pkg/util/user_project_test.go b/proxy/pkg/util/user_project_test.go index 688ed1cbd..255cb5924 100644 --- a/proxy/pkg/util/user_project_test.go +++ b/proxy/pkg/util/user_project_test.go @@ -21,7 +21,7 @@ func TestGetUserProjectList(t *testing.T) { "1", &UserProjectInfo{ ProjectInfo: map[string]UserProject{ - "1": UserProject{ + "1": { UserName: "user" + strconv.Itoa(1), Timestamp: time.Now().Unix(), Token: strconv.Itoa(1), @@ -37,7 +37,7 @@ func TestGetUserProjectList(t *testing.T) { "invalid", &UserProjectInfo{ ProjectInfo: map[string]UserProject{ - "1": UserProject{ + "1": { UserName: "user" + strconv.Itoa(1), Timestamp: time.Now().Unix(), Token: strconv.Itoa(1), @@ -70,7 +70,7 @@ func TestCleanExpiredProjectInfo(t *testing.T) { "1", &UserProjectInfo{ ProjectInfo: map[string]UserProject{ - "1": UserProject{ + "1": { UserName: "user" + strconv.Itoa(1), Timestamp: time.Now().Unix(), Token: strconv.Itoa(1), @@ -86,7 +86,7 @@ func TestCleanExpiredProjectInfo(t *testing.T) { "2", &UserProjectInfo{ ProjectInfo: map[string]UserProject{ - "2": UserProject{ + "2": { UserName: "user" + strconv.Itoa(2), Timestamp: time.Now().Unix() + 10, Token: strconv.Itoa(2), diff --git a/proxy/pkg/util/util.go b/proxy/pkg/util/util.go index 6a3b4b532..3c2de8322 100644 --- a/proxy/pkg/util/util.go +++ b/proxy/pkg/util/util.go @@ -9,7 +9,7 @@ import ( "crypto/x509" "encoding/json" "fmt" - "io/ioutil" + "io" "net/http" "net/url" "os" @@ -25,19 +25,15 @@ import ( userv1 "github.com/openshift/api/user/v1" proxyconfig "github.com/stolostron/multicluster-observability-operator/proxy/pkg/config" "github.com/stolostron/multicluster-observability-operator/proxy/pkg/rewrite" - + "golang.org/x/exp/slices" "gopkg.in/yaml.v2" - v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/fields" - "k8s.io/client-go/kubernetes" "k8s.io/client-go/tools/cache" - "k8s.io/klog" "k8s.io/kubectl/pkg/util/slice" - clusterclientset "open-cluster-management.io/api/client/cluster/clientset/versioned" clusterv1 "open-cluster-management.io/api/cluster/v1" ) @@ -55,28 +51,28 @@ var ( syncLabelList = proxyconfig.GetSyncLabelList() ) -// resources for the gocron scheduler +// resources for the gocron scheduler. var ( resyncTag = "managed-cluster-label-allowlist-resync" scheduler *gocron.Scheduler ) -// GetAllManagedClusterNames returns all managed cluster names +// GetAllManagedClusterNames returns all managed cluster names. func GetAllManagedClusterNames() map[string]string { return allManagedClusterNames } -// GetAllManagedClusterLabelNames returns all managed cluster labels +// GetAllManagedClusterLabelNames returns all managed cluster labels. func GetAllManagedClusterLabelNames() map[string]bool { return allManagedClusterLabelNames } -// InitAllManagedClusterNames initializes all managed cluster names map +// InitAllManagedClusterNames initializes all managed cluster names map. func InitAllManagedClusterNames() { allManagedClusterNames = map[string]string{} } -// InitAllManagedClusterLabelNames initializes all managed cluster labels map +// InitAllManagedClusterLabelNames initializes all managed cluster labels map. func InitAllManagedClusterLabelNames() { allManagedClusterLabelNames = map[string]bool{} } @@ -85,7 +81,7 @@ func InitScheduler() { scheduler = gocron.NewScheduler(time.UTC) } -// shouldUpdateManagedClusterLabelNames determine whether the managedcluster label names map should be updated +// shouldUpdateManagedClusterLabelNames determine whether the managedcluster label names map should be updated. func shouldUpdateManagedClusterLabelNames(clusterLabels map[string]string, managedLabelList *proxyconfig.ManagedClusterLabelList) bool { updateRequired := false @@ -101,7 +97,7 @@ func shouldUpdateManagedClusterLabelNames(clusterLabels map[string]string, return updateRequired } -// addManagedClusterLabelNames set key to enable within the managedcluster label names map +// addManagedClusterLabelNames set key to enable within the managedcluster label names map. func addManagedClusterLabelNames(managedLabelList *proxyconfig.ManagedClusterLabelList) { for _, key := range managedLabelList.LabelList { if _, ok := allManagedClusterLabelNames[key]; !ok { @@ -131,7 +127,7 @@ func addManagedClusterLabelNames(managedLabelList *proxyconfig.ManagedClusterLab syncLabelList.RegexLabelList = managedLabelList.RegexLabelList } -// ignoreManagedClusterLabelNames set key to ignore within the managedcluster label names map +// ignoreManagedClusterLabelNames set key to ignore within the managedcluster label names map. func ignoreManagedClusterLabelNames(managedLabelList *proxyconfig.ManagedClusterLabelList) { for _, key := range managedLabelList.IgnoreList { if _, ok := allManagedClusterLabelNames[key]; !ok { @@ -158,7 +154,7 @@ func ignoreManagedClusterLabelNames(managedLabelList *proxyconfig.ManagedCluster syncLabelList.RegexLabelList = managedLabelList.RegexLabelList } -// updateAllManagedClusterLabelNames updates all managed cluster label names status within the map +// updateAllManagedClusterLabelNames updates all managed cluster label names status within the map. func updateAllManagedClusterLabelNames(managedLabelList *proxyconfig.ManagedClusterLabelList) { if managedLabelList.LabelList != nil { addManagedClusterLabelNames(managedLabelList) @@ -173,7 +169,7 @@ func updateAllManagedClusterLabelNames(managedLabelList *proxyconfig.ManagedClus } } -// ModifyMetricsQueryParams will modify request url params for query metrics +// ModifyMetricsQueryParams will modify request url params for query metrics. func ModifyMetricsQueryParams(req *http.Request, reqUrl string) { userName := req.Header.Get("X-Forwarded-User") klog.V(1).Infof("user is %v", userName) @@ -206,7 +202,7 @@ func ModifyMetricsQueryParams(req *http.Request, reqUrl string) { var rawQuery string if req.Method == "POST" { - body, _ := ioutil.ReadAll(req.Body) + body, _ := io.ReadAll(req.Body) _ = req.Body.Close() queryValues, err := url.ParseQuery(string(body)) if err != nil { @@ -219,7 +215,7 @@ func ModifyMetricsQueryParams(req *http.Request, reqUrl string) { queryValues = rewriteQuery(queryValues, clusterList, "query") queryValues = rewriteQuery(queryValues, clusterList, "match[]") rawQuery = queryValues.Encode() - req.Body = ioutil.NopCloser(strings.NewReader(rawQuery)) + req.Body = io.NopCloser(strings.NewReader(rawQuery)) req.Header.Set("Content-Length", fmt.Sprint(len([]rune(rawQuery)))) req.ContentLength = int64(len([]rune(rawQuery))) } else { @@ -237,10 +233,9 @@ func ModifyMetricsQueryParams(req *http.Request, reqUrl string) { klog.V(1).Infof("URL is: %s", req.URL) klog.V(1).Infof("URL path is: %v", req.URL.Path) klog.V(1).Infof("URL RawQuery is: %v", rawQuery) - return } -// GetManagedClusterEventHandler return event handler functions for managed cluster watch events +// GetManagedClusterEventHandler return event handler functions for managed cluster watch events. func GetManagedClusterEventHandler() cache.ResourceEventHandlerFuncs { return cache.ResourceEventHandlerFuncs{ AddFunc: func(obj interface{}) { @@ -275,7 +270,7 @@ func GetManagedClusterEventHandler() cache.ResourceEventHandlerFuncs { } } -// WatchManagedCluster will watch and save managedcluster when create/update/delete managedcluster +// WatchManagedCluster will watch and save managedcluster when create/update/delete managedcluster. func WatchManagedCluster(clusterClient clusterclientset.Interface, kubeClient kubernetes.Interface) { InitAllManagedClusterNames() InitAllManagedClusterLabelNames() @@ -297,7 +292,6 @@ func WatchManagedCluster(clusterClient clusterclientset.Interface, kubeClient ku } } -// ScheduleManagedClusterLabelAllowlistResync ... func ScheduleManagedClusterLabelAllowlistResync(kubeClient kubernetes.Interface) { if scheduler == nil { InitScheduler() @@ -312,7 +306,6 @@ func ScheduleManagedClusterLabelAllowlistResync(kubeClient kubernetes.Interface) scheduler.StartAsync() } -// StopScheduleManagedClusterLabelAllowlistResync ... func StopScheduleManagedClusterLabelAllowlistResync() { klog.Info("stopping scheduler for managedcluster allowlist resync") scheduler.Stop() @@ -322,7 +315,7 @@ func StopScheduleManagedClusterLabelAllowlistResync() { } } -// GetManagedClusterLabelAllowListEventHandler return event handler for managedcluster label allow list watch event +// GetManagedClusterLabelAllowListEventHandler return event handler for managedcluster label allow list watch event. func GetManagedClusterLabelAllowListEventHandler(kubeClient kubernetes.Interface) cache.ResourceEventHandlerFuncs { return cache.ResourceEventHandlerFuncs{ AddFunc: func(obj interface{}) { @@ -366,7 +359,7 @@ func GetManagedClusterLabelAllowListEventHandler(kubeClient kubernetes.Interface } // WatchManagedClusterLabelAllowList will watch and save managedcluster label allowlist configmap -// when create/update/delete +// when create/update/delete. func WatchManagedClusterLabelAllowList(kubeClient kubernetes.Interface) { watchlist := cache.NewListWatchFromClient(kubeClient.CoreV1().RESTClient(), "configmaps", proxyconfig.ManagedClusterLabelAllowListNamespace, fields.Everything()) @@ -399,7 +392,7 @@ func sendHTTPRequest(url string, verb string, token string) (*http.Response, err token = "Bearer " + token } req.Header.Set("Authorization", token) - caCert, err := ioutil.ReadFile(filepath.Clean(caPath)) + caCert, err := os.ReadFile(filepath.Clean(caPath)) if err != nil { klog.Error("failed to load root ca cert file") return nil, err @@ -469,24 +462,14 @@ func GetUserName(token string, url string) string { return user.Name } -// Contains is used to check whether a list contains string s -func Contains(list []string, s string) bool { - for _, v := range list { - if v == s { - return true - } - } - return false -} - -// canAccessAllClusters check user have permission to access all clusters +// canAccessAllClusters check user have permission to access all clusters. func canAccessAllClusters(projectList []string) bool { if len(allManagedClusterNames) == 0 && len(projectList) == 0 { return false } for name := range allManagedClusterNames { - if !Contains(projectList, name) { + if !slices.Contains(projectList, name) { return false } } @@ -601,7 +584,7 @@ func resyncManagedClusterLabelAllowList(kubeClient kubernetes.Interface) error { return nil } -// marshalLabelListToConfigMap marshal managedcluster label list data to configmap data key +// marshalLabelListToConfigMap marshal managedcluster label list data to configmap data key. func marshalLabelListToConfigMap(obj interface{}, key string, managedLabelList *proxyconfig.ManagedClusterLabelList) error { data, err := yaml.Marshal(managedLabelList) @@ -614,7 +597,7 @@ func marshalLabelListToConfigMap(obj interface{}, key string, return nil } -// unmarshalDataToManagedClusterLabelList unmarshal managedcluster label allowlist +// unmarshalDataToManagedClusterLabelList unmarshal managedcluster label allowlist. func unmarshalDataToManagedClusterLabelList(data map[string]string, key string, managedLabelList *proxyconfig.ManagedClusterLabelList) error { err := yaml.Unmarshal([]byte(data[key]), managedLabelList) @@ -627,7 +610,6 @@ func unmarshalDataToManagedClusterLabelList(data map[string]string, key string, return nil } -// sortManagedLabelList ... func sortManagedLabelList(managedLabelList *proxyconfig.ManagedClusterLabelList) { if managedLabelList != nil { sort.Strings(managedLabelList.IgnoreList) diff --git a/proxy/pkg/util/util_test.go b/proxy/pkg/util/util_test.go index 751286e78..fead740f8 100644 --- a/proxy/pkg/util/util_test.go +++ b/proxy/pkg/util/util_test.go @@ -5,9 +5,10 @@ package util import ( "context" - "io/ioutil" + stdlog "log" "net/http" "net/url" + "os" "strings" "testing" "time" @@ -36,7 +37,7 @@ func createFakeServerWithInvalidJSON(port string, t *testing.T) { ) err := http.ListenAndServe(":"+port, server) if err != nil { - t.Fatal("fail to create internal server at " + port) + stdlog.Fatal("fail to create internal server at " + port) } } @@ -102,7 +103,7 @@ func createFakeServer(port string, t *testing.T) { ) err := http.ListenAndServe(":"+port, server) if err != nil { - t.Fatal("fail to create internal server at " + port) + stdlog.Fatal("fail to create internal server at " + port) } } func TestModifyMetricsQueryParams(t *testing.T) { @@ -188,27 +189,6 @@ func TestGetAllManagedClusterLabelNames(t *testing.T) { } } -func TestContains(t *testing.T) { - testCaseList := []struct { - name string - list []string - s string - expected bool - }{ - {"contain sub string", []string{"a", "b"}, "a", true}, - {"shoud contain empty string", []string{""}, "", true}, - {"should not contain sub string", []string{"a", "b"}, "c", false}, - {"shoud not contain empty string", []string{"a", "b"}, "", false}, - } - - for _, c := range testCaseList { - output := Contains(c.list, c.s) - if output != c.expected { - t.Errorf("case (%v) output: (%v) is not the expected: (%v)", c.name, output, c.expected) - } - } -} - func TestRewriteQuery(t *testing.T) { testCaseList := []struct { name string @@ -227,7 +207,7 @@ func TestRewriteQuery(t *testing.T) { { "should rewrite", - map[string][]string{"key": []string{"value"}}, + map[string][]string{"key": {"value"}}, []string{"c1", "c2"}, "key", "value{cluster=~\"c1|c2\"}", @@ -235,7 +215,7 @@ func TestRewriteQuery(t *testing.T) { { "empty cluster list", - map[string][]string{"key": []string{"value"}}, + map[string][]string{"key": {"value"}}, []string{}, "key", "value{cluster=~\"\"}", @@ -323,7 +303,7 @@ func TestGetUserClusterList(t *testing.T) { func TestWriteError(t *testing.T) { writeError("test") - data, _ := ioutil.ReadFile("/tmp/health") + data, _ := os.ReadFile("/tmp/health") if !strings.Contains(string(data), "test") { t.Errorf("failed to find the health file") } diff --git a/scripts/copyright/copyright.go b/scripts/copyright/copyright.go new file mode 100644 index 000000000..9ff4d7a39 --- /dev/null +++ b/scripts/copyright/copyright.go @@ -0,0 +1,76 @@ +// Copyright (c) Red Hat, Inc. +// Copyright Contributors to the Open Cluster Management project +// Licensed under the Apache License 2.0 + +package main + +import ( + "bytes" + "log" + "os" + "path/filepath" + "strings" +) + +type copyright []byte + +var ( + stolostron copyright = []byte(`// Copyright (c) Red Hat, Inc. +// Copyright Contributors to the Open Cluster Management project +// Licensed under the Apache License 2.0 + +`) +) + +func applyLicenseToProtoAndGo() error { + return filepath.Walk(".", func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + + // Filter out stuff that does not need copyright. + if info.IsDir() { + switch path { + case "vendor": + return filepath.SkipDir + } + return nil + } + if strings.HasSuffix(path, ".deepcopy.go") { + return nil + } + if filepath.Ext(path) != ".proto" && filepath.Ext(path) != ".go" { + return nil + } + + b, err := os.ReadFile(filepath.Clean(path)) + if err != nil { + return err + } + + if err := writeLicence(stolostron, path, b); err != nil { + return err + } + return nil + }) +} + +func writeLicence(cr copyright, path string, b []byte) error { + if !strings.HasPrefix(string(b), string(cr)) { + log.Println("file", path, "is missing Copyright header. Adding.") + + var bb bytes.Buffer + _, _ = bb.Write(cr) + _, _ = bb.Write(b) + if err := os.WriteFile(path, bb.Bytes(), 0600); err != nil { + return err + } + } + return nil +} + +func main() { + if err := applyLicenseToProtoAndGo(); err != nil { + log.Fatal(err) + } +} diff --git a/tests/benchmark/clean-metrics-collector.sh b/tests/benchmark/clean-metrics-collector.sh index 79833ed37..29d51a7df 100755 --- a/tests/benchmark/clean-metrics-collector.sh +++ b/tests/benchmark/clean-metrics-collector.sh @@ -5,25 +5,25 @@ sed_command='sed -i' managed_cluster='managed' if [ $# -eq 2 ]; then - managed_cluster=$2 + managed_cluster=$2 fi if [ $# -lt 1 ]; then - echo "this script must be run with the number of clusters:" - echo -e "\n$0 total_clusters\n" - exit 1 + echo "this script must be run with the number of clusters:" + echo -e "\n$0 total_clusters\n" + exit 1 fi re='^[0-9]+$' -if ! [[ $1 =~ $re ]] ; then - echo "error: arguments <$1> not a number" >&2; exit 1 +if ! [[ $1 =~ $re ]]; then + echo "error: arguments <$1> not a number" >&2 + exit 1 fi -for i in $(seq 1 $1) -do - cluster_name=simulate-${managed_cluster}-cluster${i} - kubectl delete deploy -n ${cluster_name} metrics-collector-deployment - kubectl delete clusterrolebinding ${cluster_name}-clusters-metrics-collector-view - kubectl delete -n ${cluster_name} secret/observability-managed-cluster-certs - kubectl delete ns ${cluster_name} +for i in $(seq 1 $1); do + cluster_name=simulate-${managed_cluster}-cluster${i} + kubectl delete deploy -n ${cluster_name} metrics-collector-deployment + kubectl delete clusterrolebinding ${cluster_name}-clusters-metrics-collector-view + kubectl delete -n ${cluster_name} secret/observability-managed-cluster-certs + kubectl delete ns ${cluster_name} done diff --git a/tests/benchmark/setup-metrics-collector.sh b/tests/benchmark/setup-metrics-collector.sh index 5fcae62dd..a9d90dd3a 100755 --- a/tests/benchmark/setup-metrics-collector.sh +++ b/tests/benchmark/setup-metrics-collector.sh @@ -5,66 +5,65 @@ WORKDIR="$(pwd -P)" export PATH=${PATH}:${WORKDIR} -if ! command -v jq &> /dev/null; then - if [[ "$(uname)" == "Linux" ]]; then - curl -o jq -L https://github.com/stedolan/jq/releases/download/jq-1.6/jq-linux64 - elif [[ "$(uname)" == "Darwin" ]]; then - curl -o jq -L https://github.com/stedolan/jq/releases/download/jq-1.6/jq-osx-amd64 - fi - chmod +x ./jq +if ! command -v jq &>/dev/null; then + if [[ "$(uname)" == "Linux" ]]; then + curl -o jq -L https://github.com/stedolan/jq/releases/download/jq-1.6/jq-linux64 + elif [[ "$(uname)" == "Darwin" ]]; then + curl -o jq -L https://github.com/stedolan/jq/releases/download/jq-1.6/jq-osx-amd64 + fi + chmod +x ./jq fi sed_command='sed -i' if [[ "$(uname)" == "Darwin" ]]; then - sed_command='sed -i -e' + sed_command='sed -i -e' fi managed_cluster='managed' if [ $# -eq 2 ]; then - managed_cluster=$2 + managed_cluster=$2 fi if [ $# -lt 1 ]; then - echo "this script must be run with the number of clusters:" - echo -e "\n$0 total_clusters\n" - exit 1 + echo "this script must be run with the number of clusters:" + echo -e "\n$0 total_clusters\n" + exit 1 fi re='^[0-9]+$' -if ! [[ $1 =~ $re ]] ; then - echo "error: arguments <$1> not a number" >&2; exit 1 +if ! [[ $1 =~ $re ]]; then + echo "error: arguments <$1> not a number" >&2 + exit 1 fi -for i in $(seq 1 $1) -do - cluster_name=simulate-${managed_cluster}-cluster${i} - kubectl create ns ${cluster_name} +for i in $(seq 1 $1); do + cluster_name=simulate-${managed_cluster}-cluster${i} + kubectl create ns ${cluster_name} - # create ca/sa/rolebinding for metrics collector - kubectl get configmap metrics-collector-serving-certs-ca-bundle -n open-cluster-management-addon-observability -o json | jq 'del(.metadata.namespace,.metadata.resourceVersion,.metadata.uid) | .metadata.creationTimestamp=null' | kubectl apply -n ${cluster_name} -f - - kubectl get secret observability-controller-open-cluster-management.io-observability-signer-client-cert -n open-cluster-management-addon-observability -o json | jq 'del(.metadata.namespace,.metadata.resourceVersion,.metadata.uid) | .metadata.creationTimestamp=null' | kubectl apply -n ${cluster_name} -f - - kubectl get secret observability-managed-cluster-certs -n open-cluster-management-addon-observability -o json | jq 'del(.metadata.namespace,.metadata.resourceVersion,.metadata.uid) | .metadata.creationTimestamp=null' | kubectl apply -n ${cluster_name} -f - - kubectl get sa endpoint-observability-operator-sa -n open-cluster-management-addon-observability -o json | jq 'del(.metadata.namespace,.metadata.resourceVersion,.metadata.uid) | .metadata.creationTimestamp=null' | kubectl apply -n ${cluster_name} -f - - kubectl -n ${cluster_name} patch secret observability-managed-cluster-certs --type='json' -p='[{"op": "replace", "path": "/metadata/ownerReferences", "value": []}]' - kubectl -n ${cluster_name} patch sa endpoint-observability-operator-sa --type='json' -p='[{"op": "replace", "path": "/metadata/ownerReferences", "value": []}]' + # create ca/sa/rolebinding for metrics collector + kubectl get configmap metrics-collector-serving-certs-ca-bundle -n open-cluster-management-addon-observability -o json | jq 'del(.metadata.namespace,.metadata.resourceVersion,.metadata.uid) | .metadata.creationTimestamp=null' | kubectl apply -n ${cluster_name} -f - + kubectl get secret observability-controller-open-cluster-management.io-observability-signer-client-cert -n open-cluster-management-addon-observability -o json | jq 'del(.metadata.namespace,.metadata.resourceVersion,.metadata.uid) | .metadata.creationTimestamp=null' | kubectl apply -n ${cluster_name} -f - + kubectl get secret observability-managed-cluster-certs -n open-cluster-management-addon-observability -o json | jq 'del(.metadata.namespace,.metadata.resourceVersion,.metadata.uid) | .metadata.creationTimestamp=null' | kubectl apply -n ${cluster_name} -f - + kubectl get sa endpoint-observability-operator-sa -n open-cluster-management-addon-observability -o json | jq 'del(.metadata.namespace,.metadata.resourceVersion,.metadata.uid) | .metadata.creationTimestamp=null' | kubectl apply -n ${cluster_name} -f - + kubectl -n ${cluster_name} patch secret observability-managed-cluster-certs --type='json' -p='[{"op": "replace", "path": "/metadata/ownerReferences", "value": []}]' + kubectl -n ${cluster_name} patch sa endpoint-observability-operator-sa --type='json' -p='[{"op": "replace", "path": "/metadata/ownerReferences", "value": []}]' - # deploy metrics collector deployment to cluster ns - deploy_yaml_file=${cluster_name}-metrics-collector-deployment.yaml - kubectl get deploy metrics-collector-deployment -n open-cluster-management-addon-observability -o yaml > $deploy_yaml_file - $sed_command "s~cluster=.*$~cluster=${cluster_name}\"~g" "$deploy_yaml_file" - $sed_command "s~clusterID=.*$~clusterID=$(cat /proc/sys/kernel/random/uuid)\"~g" "$deploy_yaml_file" - $sed_command "s~namespace:\ open-cluster-management-addon-observability~namespace:\ ${cluster_name}~g" "$deploy_yaml_file" - cat "$deploy_yaml_file" | kubectl -n ${cluster_name} apply -f - - rm -rf "$deploy_yaml_file" - kubectl -n ${cluster_name} patch deploy metrics-collector-deployment --type='json' -p='[{"op": "replace", "path": "/metadata/ownerReferences", "value": []}]' - kubectl -n ${cluster_name} patch deploy metrics-collector-deployment --type='json' -p='[{"op": "remove", "path": "/spec/template/spec/containers/0/resources"}]' + # deploy metrics collector deployment to cluster ns + deploy_yaml_file=${cluster_name}-metrics-collector-deployment.yaml + kubectl get deploy metrics-collector-deployment -n open-cluster-management-addon-observability -o yaml >$deploy_yaml_file + $sed_command "s~cluster=.*$~cluster=${cluster_name}\"~g" "$deploy_yaml_file" + $sed_command "s~clusterID=.*$~clusterID=$(cat /proc/sys/kernel/random/uuid)\"~g" "$deploy_yaml_file" + $sed_command "s~namespace:\ open-cluster-management-addon-observability~namespace:\ ${cluster_name}~g" "$deploy_yaml_file" + cat "$deploy_yaml_file" | kubectl -n ${cluster_name} apply -f - + rm -rf "$deploy_yaml_file" + kubectl -n ${cluster_name} patch deploy metrics-collector-deployment --type='json' -p='[{"op": "replace", "path": "/metadata/ownerReferences", "value": []}]' + kubectl -n ${cluster_name} patch deploy metrics-collector-deployment --type='json' -p='[{"op": "remove", "path": "/spec/template/spec/containers/0/resources"}]' + # deploy ClusterRoleBinding for read metrics from OCP prometheus + rolebinding_yaml_file=${cluster_name}-metrics-collector-view.yaml + cp -rf metrics-collector-view.yaml "$rolebinding_yaml_file" + $sed_command "s~__CLUSTER_NAME__~${cluster_name}~g" "$rolebinding_yaml_file" + cat "$rolebinding_yaml_file" | kubectl -n ${cluster_name} apply -f - + rm -rf "$rolebinding_yaml_file" - # deploy ClusterRoleBinding for read metrics from OCP prometheus - rolebinding_yaml_file=${cluster_name}-metrics-collector-view.yaml - cp -rf metrics-collector-view.yaml "$rolebinding_yaml_file" - $sed_command "s~__CLUSTER_NAME__~${cluster_name}~g" "$rolebinding_yaml_file" - cat "$rolebinding_yaml_file" | kubectl -n ${cluster_name} apply -f - - rm -rf "$rolebinding_yaml_file" - done diff --git a/tests/format-results.sh b/tests/format-results.sh index d750407d4..c90fac9b8 100755 --- a/tests/format-results.sh +++ b/tests/format-results.sh @@ -7,8 +7,8 @@ #!/bin/bash if [ -z $1 ]; then - echo "Please provide the results file." - exit 1 + echo "Please provide the results file." + exit 1 fi sed -i "s~BeforeSuite~Observability: [P1][Sev1][observability] Cannot enable observability service successfully~g" $1 diff --git a/tests/grafana-dev-test.sh b/tests/grafana-dev-test.sh index c5f1c4e53..17629f080 100755 --- a/tests/grafana-dev-test.sh +++ b/tests/grafana-dev-test.sh @@ -3,7 +3,10 @@ # avoid client-side throttling due to HOME=/ export HOME=/tmp -base_dir="$(cd "$(dirname "$0")/.." ; pwd -P)" +base_dir="$( + cd "$(dirname "$0")/.." + pwd -P +)" cd "$base_dir" obs_namespace=open-cluster-management-observability @@ -14,28 +17,27 @@ kubectl apply -n "$obs_namespace" -f "$base_dir"/examples/dashboards/sample_cust cd $base_dir/tools ./setup-grafana-dev.sh --deploy if [ $? -ne 0 ]; then - echo "Failed run setup-grafana-dev.sh --deploy" - exit 1 + echo "Failed run setup-grafana-dev.sh --deploy" + exit 1 fi n=0 -until [ "$n" -ge 30 ] -do - kubectl get pods -n "$obs_namespace" -l app=multicluster-observability-grafana-dev | grep "3/3" | grep "Running" && break - n=$((n+1)) - echo "Retrying in 10s for waiting for grafana-dev pod ready ..." - sleep 10 +until [ "$n" -ge 30 ]; do + kubectl get pods -n "$obs_namespace" -l app=multicluster-observability-grafana-dev | grep "3/3" | grep "Running" && break + n=$((n + 1)) + echo "Retrying in 10s for waiting for grafana-dev pod ready ..." + sleep 10 done if [ $n -eq 30 ]; then - echo "Failed waiting for grafana-dev pod ready in 300s" - exit 1 + echo "Failed waiting for grafana-dev pod ready in 300s" + exit 1 fi podName=$(kubectl get pods -n "$obs_namespace" -l app=multicluster-observability-grafana-dev --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}') if [ $? -ne 0 ] || [ -z "$podName" ]; then - echo "Failed to get grafana pod name, please check your grafana-dev deployment" - exit 1 + echo "Failed to get grafana pod name, please check your grafana-dev deployment" + exit 1 fi sleep 10 @@ -44,42 +46,40 @@ kubectl -n "$obs_namespace" exec -it "$podName" -c grafana-dashboard-loader -- / sleep 30 n=0 -until [ "$n" -ge 10 ] -do - # test swith user to grafana admin - ./switch-to-grafana-admin.sh test - if [ $? -eq 0 ]; then - break - fi - n=$((n+1)) - sleep 5 +until [ "$n" -ge 10 ]; do + # test swith user to grafana admin + ./switch-to-grafana-admin.sh test + if [ $? -eq 0 ]; then + break + fi + n=$((n + 1)) + sleep 5 done if [ $n -eq 10 ]; then - echo "Failed run switch-to-grafana-admin.sh test" - exit 1 + echo "Failed run switch-to-grafana-admin.sh test" + exit 1 fi n=0 -until [ "$n" -ge 10 ] -do - # test export grafana dashboard - ./generate-dashboard-configmap-yaml.sh "Sample Dashboard for E2E" - if [ $? -eq 0 ]; then - break - fi - n=$((n+1)) - sleep 5 +until [ "$n" -ge 10 ]; do + # test export grafana dashboard + ./generate-dashboard-configmap-yaml.sh "Sample Dashboard for E2E" + if [ $? -eq 0 ]; then + break + fi + n=$((n + 1)) + sleep 5 done if [ $n -eq 10 ]; then - echo "Failed run generate-dashboard-configmap-yaml.sh" - exit 1 + echo "Failed run generate-dashboard-configmap-yaml.sh" + exit 1 fi # test clean grafan-dev ./setup-grafana-dev.sh --clean if [ $? -ne 0 ]; then - echo "Failed run setup-grafana-dev.sh --clean" - exit 1 + echo "Failed run setup-grafana-dev.sh --clean" + exit 1 fi # clean test env diff --git a/tests/pkg/kustomize/render.go b/tests/pkg/kustomize/render.go index 4ed09eecb..56041e20b 100644 --- a/tests/pkg/kustomize/render.go +++ b/tests/pkg/kustomize/render.go @@ -4,8 +4,8 @@ package kustomize import ( - "sigs.k8s.io/kustomize/api/filesys" "sigs.k8s.io/kustomize/api/krusty" + "sigs.k8s.io/kustomize/kyaml/filesys" "sigs.k8s.io/yaml" ) @@ -15,7 +15,7 @@ type Options struct { OutputPath string } -// Render is used to render the kustomization +// Render is used to render the kustomization. func Render(o Options) ([]byte, error) { fSys := filesys.MakeFsOnDisk() k := krusty.MakeKustomizer(krusty.MakeDefaultOptions()) @@ -26,7 +26,7 @@ func Render(o Options) ([]byte, error) { return m.AsYaml() } -// GetLabels return labels +// GetLabels return labels. func GetLabels(yamlB []byte) (interface{}, error) { data := map[string]interface{}{} err := yaml.Unmarshal(yamlB, &data) diff --git a/tests/pkg/tests/observability-e2e-test_suite_test.go b/tests/pkg/tests/observability-e2e-test_suite_test.go index a9712e438..3fd81b70d 100644 --- a/tests/pkg/tests/observability-e2e-test_suite_test.go +++ b/tests/pkg/tests/observability-e2e-test_suite_test.go @@ -6,7 +6,6 @@ package tests import ( "flag" "fmt" - "io/ioutil" "math/rand" "os" "testing" @@ -157,7 +156,7 @@ func initVars() { klog.V(1).Infof("options filename=%s", optionsFile) - data, err := ioutil.ReadFile(optionsFile) + data, err := os.ReadFile(optionsFile) if err != nil { klog.Errorf("--options error: %v", err) } diff --git a/tests/pkg/tests/observability_addon_test.go b/tests/pkg/tests/observability_addon_test.go index 2eba2d698..a3efbe967 100644 --- a/tests/pkg/tests/observability_addon_test.go +++ b/tests/pkg/tests/observability_addon_test.go @@ -7,6 +7,8 @@ import ( "fmt" "strings" + "errors" + . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "k8s.io/klog" @@ -71,12 +73,12 @@ var _ = Describe("Observability:", func() { "component=metrics-collector", ) if err != nil { - return fmt.Errorf("Failed to disable observability addon") + return errors.New("Failed to disable observability addon") } if len(podList.Items) != 0 { for _, po := range podList.Items { if po.Status.Phase == "Running" { - return fmt.Errorf("Failed to disable observability addon, there is still metrics-collector pod in Running") + return errors.New("Failed to disable observability addon, there is still metrics-collector pod in Running") } } } @@ -109,7 +111,7 @@ var _ = Describe("Observability:", func() { return nil } } - return fmt.Errorf("Check no metric data in grafana console error: %v", err) + return fmt.Errorf("Check no metric data in grafana console error: %w", err) }, EventuallyTimeoutMinute*2, EventuallyIntervalSecond*5).Should(Succeed()) }) diff --git a/tests/pkg/tests/observability_alert_test.go b/tests/pkg/tests/observability_alert_test.go index 5fb6cbd93..1f1cd94bb 100644 --- a/tests/pkg/tests/observability_alert_test.go +++ b/tests/pkg/tests/observability_alert_test.go @@ -9,7 +9,7 @@ import ( "crypto/x509" "encoding/json" "fmt" - "io/ioutil" + "io" "net/http" "net/url" "os" @@ -28,6 +28,10 @@ import ( "github.com/stolostron/multicluster-observability-operator/tests/pkg/utils" ) +const ( + trueStr = "true" +) + var _ = Describe("Observability:", func() { BeforeEach(func() { hubClient = utils.NewKubeClient( @@ -305,7 +309,7 @@ var _ = Describe("Observability:", func() { alertGetReq, err := http.NewRequest("GET", amURL.String(), nil) Expect(err).NotTo(HaveOccurred()) - if os.Getenv("IS_KIND_ENV") != "true" { + if os.Getenv("IS_KIND_ENV") != trueStr { if BearerToken == "" { BearerToken, err = utils.FetchBearerToken(testOptions) Expect(err).NotTo(HaveOccurred()) @@ -348,10 +352,10 @@ var _ = Describe("Observability:", func() { if resp.StatusCode != http.StatusOK { klog.Errorf("err: %+v\n", resp) - return fmt.Errorf("Failed to get alerts via alertmanager route with http reponse: %v", resp) + return fmt.Errorf("Failed to get alerts via alertmanager route with http response: %v", resp) } - alertResult, err := ioutil.ReadAll(resp.Body) + alertResult, err := io.ReadAll(resp.Body) if err != nil { return err } diff --git a/tests/pkg/tests/observability_config_test.go b/tests/pkg/tests/observability_config_test.go index b1de8c27c..7a74316a2 100644 --- a/tests/pkg/tests/observability_config_test.go +++ b/tests/pkg/tests/observability_config_test.go @@ -31,7 +31,7 @@ var _ = Describe("Observability:", func() { }) It("@BVT - [P1][Sev1][observability][Stable] Checking metrics default values on managed cluster (config/g0)", func() { - if os.Getenv("SKIP_INSTALL_STEP") == "true" { + if os.Getenv("SKIP_INSTALL_STEP") == trueStr { Skip("Skip the case due to MCO CR was created customized") } mcoRes, err := dynClient.Resource(utils.NewMCOGVRV1BETA2()). @@ -45,7 +45,7 @@ var _ = Describe("Observability:", func() { }) It("@BVT - [P1][Sev1][observability][Stable] Checking default value of PVC and StorageClass (config/g0)", func() { - if os.Getenv("SKIP_INSTALL_STEP") == "true" { + if os.Getenv("SKIP_INSTALL_STEP") == trueStr { Skip("Skip the case due to MCO CR was created customized") } mcoSC, err := dynClient.Resource(utils.NewMCOGVRV1BETA2()). @@ -59,7 +59,7 @@ var _ = Describe("Observability:", func() { scMatch := false defaultSC := "" for _, sc := range scList.Items { - if sc.Annotations["storageclass.kubernetes.io/is-default-class"] == "true" { + if sc.Annotations["storageclass.kubernetes.io/is-default-class"] == trueStr { defaultSC = sc.Name } if sc.Name == scInCR { diff --git a/tests/pkg/tests/observability_endpoint_preserve_test.go b/tests/pkg/tests/observability_endpoint_preserve_test.go index 232cd858e..8f0a1e4b7 100644 --- a/tests/pkg/tests/observability_endpoint_preserve_test.go +++ b/tests/pkg/tests/observability_endpoint_preserve_test.go @@ -113,7 +113,7 @@ var _ = Describe("Observability:", func() { }) It("[P2][Sev2][observability][Stable] Should revert any manual changes on metrics-collector-view clusterolebinding (endpoint_preserve/g0)", func() { - if os.Getenv("IS_KIND_ENV") == "true" { + if os.Getenv("IS_KIND_ENV") == trueStr { Skip("Skip the case due to run in KinD") } @@ -151,7 +151,7 @@ var _ = Describe("Observability:", func() { }) It("[P2][Sev2][observability][Stable] Should recreate on metrics-collector-serving-certs-ca-bundle configmap if deleted (endpoint_preserve/g0)", func() { - if os.Getenv("IS_KIND_ENV") == "true" { + if os.Getenv("IS_KIND_ENV") == trueStr { Skip("Skip the case due to run in KinD") } diff --git a/tests/pkg/tests/observability_export_test.go b/tests/pkg/tests/observability_export_test.go index dd04ee67b..df3f7dfc1 100644 --- a/tests/pkg/tests/observability_export_test.go +++ b/tests/pkg/tests/observability_export_test.go @@ -4,6 +4,7 @@ package tests import ( + "errors" "fmt" "os" @@ -51,7 +52,7 @@ var _ = Describe("Observability:", func() { By("Updating mco cr to inject WriteStorage") templatePath := "../../../examples/export/v1beta2" - if os.Getenv("IS_CANARY_ENV") != "true" { + if os.Getenv("IS_CANARY_ENV") != trueStr { templatePath = "../../../examples/export/v1beta2/custom-certs" } yamlB, err = kustomize.Render(kustomize.Options{KustomizationPath: templatePath}) @@ -83,7 +84,7 @@ var _ = Describe("Observability:", func() { `"code":"200`, `"name":"thanos-receiver"`}, ) if err != nil { - return fmt.Errorf("metrics not forwarded to thanos-receiver") + return errors.New("metrics not forwarded to thanos-receiver") } err, _ = utils.ContainManagedClusterMetric( testOptions, @@ -92,7 +93,7 @@ var _ = Describe("Observability:", func() { `"code":"204`, `"name":"victoriametrics"`}, ) if err != nil { - return fmt.Errorf("metrics not forwarded to victoriametrics") + return errors.New("metrics not forwarded to victoriametrics") } } return nil diff --git a/tests/pkg/tests/observability_install_test.go b/tests/pkg/tests/observability_install_test.go index 263cb432e..d65a5a85e 100644 --- a/tests/pkg/tests/observability_install_test.go +++ b/tests/pkg/tests/observability_install_test.go @@ -5,6 +5,7 @@ package tests import ( "context" + "errors" "fmt" "os" "time" @@ -19,7 +20,7 @@ import ( ) func installMCO() { - if os.Getenv("SKIP_INSTALL_STEP") == "true" { + if os.Getenv("SKIP_INSTALL_STEP") == trueStr { return } @@ -86,7 +87,7 @@ func installMCO() { }).Should(Succeed()) Expect(utils.CreateMCONamespace(testOptions)).NotTo(HaveOccurred()) - if os.Getenv("IS_CANARY_ENV") == "true" { + if os.Getenv("IS_CANARY_ENV") == trueStr { Expect(utils.CreatePullSecret(testOptions, mcoNs)).NotTo(HaveOccurred()) Expect(utils.CreateObjSecret(testOptions)).NotTo(HaveOccurred()) } else { @@ -111,7 +112,7 @@ func installMCO() { By("Creating the MCO testing RBAC resources") Expect(utils.CreateMCOTestingRBAC(testOptions)).NotTo(HaveOccurred()) - if os.Getenv("SKIP_INTEGRATION_CASES") != "true" { + if os.Getenv("SKIP_INTEGRATION_CASES") != trueStr { By("Creating MCO instance of v1beta1") v1beta1KustomizationPath := "../../../examples/mco/e2e/v1beta1" yamlB, err = kustomize.Render(kustomize.Options{KustomizationPath: v1beta1KustomizationPath}) @@ -143,7 +144,7 @@ func installMCO() { instance.Object["status"], ) } else { - return fmt.Errorf("Wait for reconciling.") + return errors.New("Wait for reconciling.") } }, EventuallyTimeoutMinute*20, EventuallyIntervalSecond*5).Should(Succeed()) @@ -165,7 +166,7 @@ func installMCO() { Expect(err).NotTo(HaveOccurred()) } - if os.Getenv("IS_CANARY_ENV") != "true" { + if os.Getenv("IS_CANARY_ENV") != trueStr { By("Recreating Minio-tls as object storage") //set resource quota and limit range for canary environment to avoid destruct the node yamlB, err := kustomize.Render(kustomize.Options{KustomizationPath: "../../../examples/minio-tls"}) diff --git a/tests/pkg/tests/observability_route_test.go b/tests/pkg/tests/observability_route_test.go index 2b2fcb3c6..9c122576b 100644 --- a/tests/pkg/tests/observability_route_test.go +++ b/tests/pkg/tests/observability_route_test.go @@ -8,11 +8,13 @@ import ( "crypto/tls" "crypto/x509" "fmt" - "io/ioutil" + "io" "net/http" "os" "strings" + "errors" + . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "k8s.io/klog" @@ -58,7 +60,7 @@ var _ = Describe("Observability:", func() { } client := &http.Client{} - if os.Getenv("IS_KIND_ENV") != "true" { + if os.Getenv("IS_KIND_ENV") != trueStr { client.Transport = tr req.Header.Set("Authorization", "Bearer "+BearerToken) } @@ -72,17 +74,17 @@ var _ = Describe("Observability:", func() { if resp.StatusCode != http.StatusOK { klog.Errorf("resp: %+v\n", resp) klog.Errorf("err: %+v\n", err) - return fmt.Errorf("Failed to access metrics via via rbac-query-proxy route") + return errors.New("Failed to access metrics via via rbac-query-proxy route") } - metricResult, err := ioutil.ReadAll(resp.Body) + metricResult, err := io.ReadAll(resp.Body) klog.V(5).Infof("metricResult: %s\n", metricResult) if err != nil { return err } if !strings.Contains(string(metricResult), "cluster_version") { - return fmt.Errorf("Failed to find metric name from response") + return errors.New("Failed to find metric name from response") } return nil }, EventuallyTimeoutMinute*5, EventuallyIntervalSecond*5).Should(Succeed()) @@ -131,7 +133,7 @@ var _ = Describe("Observability:", func() { } client := &http.Client{} - if os.Getenv("IS_KIND_ENV") != "true" { + if os.Getenv("IS_KIND_ENV") != trueStr { client.Transport = tr alertPostReq.Header.Set("Authorization", "Bearer "+BearerToken) } @@ -145,7 +147,7 @@ var _ = Describe("Observability:", func() { if resp.StatusCode != http.StatusOK { klog.Errorf("resp: %+v\n", resp) klog.Errorf("err: %+v\n", err) - return fmt.Errorf("Failed to create alert via alertmanager route") + return errors.New("Failed to create alert via alertmanager route") } } @@ -160,7 +162,7 @@ var _ = Describe("Observability:", func() { return err } - if os.Getenv("IS_KIND_ENV") != "true" { + if os.Getenv("IS_KIND_ENV") != trueStr { alertGetReq.Header.Set("Authorization", "Bearer "+BearerToken) } @@ -173,10 +175,10 @@ var _ = Describe("Observability:", func() { if resp.StatusCode != http.StatusOK { klog.Errorf("resp: %+v\n", resp) klog.Errorf("err: %+v\n", err) - return fmt.Errorf("Failed to access alert via alertmanager route") + return errors.New("Failed to access alert via alertmanager route") } - alertResult, err := ioutil.ReadAll(resp.Body) + alertResult, err := io.ReadAll(resp.Body) klog.V(5).Infof("alertResult: %s\n", alertResult) if err != nil { return err diff --git a/tests/pkg/tests/observability_uninstall_test.go b/tests/pkg/tests/observability_uninstall_test.go index 6eb7077f8..831da0f3c 100644 --- a/tests/pkg/tests/observability_uninstall_test.go +++ b/tests/pkg/tests/observability_uninstall_test.go @@ -5,7 +5,7 @@ package tests import ( "context" - "fmt" + "errors" "os" . "github.com/onsi/ginkgo" @@ -16,7 +16,7 @@ import ( ) func uninstallMCO() { - if os.Getenv("SKIP_UNINSTALL_STEP") == "true" { + if os.Getenv("SKIP_UNINSTALL_STEP") == trueStr { return } @@ -30,7 +30,7 @@ func uninstallMCO() { testOptions.KubeConfig, testOptions.HubCluster.KubeContext) - By("Deleteing the MCO testing RBAC resources") + By("Deleting the MCO testing RBAC resources") Expect(utils.DeleteMCOTestingRBAC(testOptions)).NotTo(HaveOccurred()) By("Uninstall MCO instance") @@ -56,7 +56,7 @@ func uninstallMCO() { Get(context.TODO(), name, metav1.GetOptions{}) if instance != nil { utils.PrintManagedClusterOBAObject(testOptions) - return fmt.Errorf("Failed to delete MCO addon instance") + return errors.New("Failed to delete MCO addon instance") } return nil }, EventuallyTimeoutMinute*5, EventuallyIntervalSecond*5).Should(Succeed()) diff --git a/tests/pkg/utils/cluster_deploy.go b/tests/pkg/utils/cluster_deploy.go index b07075686..9d51b8cd0 100644 --- a/tests/pkg/utils/cluster_deploy.go +++ b/tests/pkg/utils/cluster_deploy.go @@ -3,14 +3,14 @@ package utils -// ClusterDeploy defines the data passed to Hive +// ClusterDeploy defines the data passed to Hive. type ClusterDeploy struct { Kind string `yaml:"kind"` APIVersion string `yaml:"apiVersion"` Items []Items `yaml:"items"` } -// Items defines the list of items in the cluster deploy yaml +// Items defines the list of items in the cluster deploy yaml. type Items struct { Kind string `yaml:"kind"` Metadata Metadata `yaml:"metadata"` @@ -18,25 +18,25 @@ type Items struct { Spec Spec `yaml:"spec,omitempty"` } -// Metadata defines the name +// Metadata defines the name. type Metadata struct { Name string `yaml:"name,omitempty"` } -// StringData defiines the ssh values +// StringData defiines the ssh values. type StringData struct { Dockerconfigjson string `yaml:".dockerconfigjson,omitempty"` SSHPrivateKey string `yaml:"ssh-privatekey,omitempty"` } -// Spec defines the kube specifications +// Spec defines the kube specifications. type Spec struct { BaseDomain string `yaml:"baseDomain,omitempty"` ClusterName string `yaml:"clusterName,omitempty"` Provisioning Provisioning `yaml:"provisioning,omitempty"` } -// Provisioning defines the data related to cluster creation +// Provisioning defines the data related to cluster creation. type Provisioning struct { ReleaseImage string `yaml:"releaseImage,omitempty"` SSHKnownHosts []string `yaml:"sshKnownHosts,omitempty"` diff --git a/tests/pkg/utils/install_config.go b/tests/pkg/utils/install_config.go index 70dad2f64..a70e0c01c 100644 --- a/tests/pkg/utils/install_config.go +++ b/tests/pkg/utils/install_config.go @@ -3,7 +3,7 @@ package utils -// InstallConfig definition for install config structure from install-config.yaml +// InstallConfig definition for install config structure from install-config.yaml. type InstallConfig struct { BaseDomain string `yaml:"baseDomain,omitempty"` Networking Networking `yaml:"networking,omitempty"` @@ -13,18 +13,18 @@ type InstallConfig struct { SSHKey string `yaml:"sshKey,omitempty"` } -// Networking definition +// Networking definition. type Networking struct { NetworkType string `yaml:"networkType"` MachineCIDR string `yaml:"machineCIDR"` } -// Platform definition +// Platform definition. type Platform struct { Baremetal Baremetal `yaml:"baremetal,omitempty"` } -// Baremetal specs for target baremetal provisioning +// Baremetal specs for target baremetal provisioning. type Baremetal struct { ExternalBridge string `yaml:"externalBridge,omitempty"` ProvisioningBridge string `yaml:"provisioningBridge,omitempty"` @@ -38,7 +38,7 @@ type Baremetal struct { SSHKnownHosts string `yaml:"sshKnownHosts,omitempty"` } -// Host is an array of baremetal assets +// Host is an array of baremetal assets. type Host struct { Name string `yaml:"name"` Role string `yaml:"role"` @@ -47,7 +47,7 @@ type Host struct { HardwareProfile string `yaml:"hardwareProfile"` } -// Bmc definition +// Bmc definition. type Bmc struct { Address string `yaml:"address"` Username string `yaml:"username"` diff --git a/tests/pkg/utils/mco_dashboard.go b/tests/pkg/utils/mco_dashboard.go index 84d22400e..c2d84661a 100644 --- a/tests/pkg/utils/mco_dashboard.go +++ b/tests/pkg/utils/mco_dashboard.go @@ -5,8 +5,9 @@ package utils import ( "crypto/tls" + "errors" "fmt" - "io/ioutil" + "io" "net/http" "net/url" "os" @@ -53,17 +54,17 @@ func ContainDashboard(opt TestOptions, title string) (error, bool) { if resp.StatusCode != http.StatusOK { klog.Errorf("resp: %+v\n", resp) klog.Errorf("err: %+v\n", err) - return fmt.Errorf("failed to access grafana api"), false + return errors.New("failed to access grafana api"), false } - result, err := ioutil.ReadAll(resp.Body) + result, err := io.ReadAll(resp.Body) klog.V(1).Infof("result: %s\n", result) if err != nil { return err, false } if !strings.Contains(string(result), fmt.Sprintf(`"title":"%s"`, title)) { - return fmt.Errorf("failed to find the dashboard"), false + return errors.New("failed to find the dashboard"), false } else { return nil, true } diff --git a/tests/pkg/utils/mco_deploy.go b/tests/pkg/utils/mco_deploy.go index 2d4b156ce..66c923267 100644 --- a/tests/pkg/utils/mco_deploy.go +++ b/tests/pkg/utils/mco_deploy.go @@ -6,8 +6,8 @@ package utils import ( "context" "encoding/json" + "errors" "fmt" - "io/ioutil" "os" "path/filepath" "reflect" @@ -162,7 +162,6 @@ func PrintAllMCOPodsStatus(opt TestOptions) { isReady := false if pod.Status.Phase == corev1.PodRunning { isReady = true - break } // only print not ready pod status @@ -234,7 +233,6 @@ func PrintAllOBAPodsStatus(opt TestOptions) { isReady := false if pod.Status.Phase == corev1.PodRunning { isReady = true - break } // only print not ready pod status @@ -498,11 +496,11 @@ func CheckAdvRetentionConfig(opt TestOptions) (bool, error) { spec := mco.Object["spec"].(map[string]interface{}) if _, adv := spec["advanced"]; !adv { - return false, fmt.Errorf("the MCO CR did not have advanced spec configed") + return false, errors.New("the MCO CR did not have advanced spec configed") } else { advanced := spec["advanced"].(map[string]interface{}) if _, rec := advanced["retentionConfig"]; !rec { - return false, fmt.Errorf("the MCO CR did not have advanced retentionConfig spec configed") + return false, errors.New("the MCO CR did not have advanced retentionConfig spec configed") } else { return true, nil } @@ -563,7 +561,7 @@ func CheckMCOAddon(opt TestOptions) error { } } if !exist { - return fmt.Errorf(podName + " not found") + return errors.New(podName + " not found") } } return nil @@ -698,11 +696,11 @@ func GetMCOAddonSpecResources(opt TestOptions) (map[string]interface{}, error) { spec := mco.Object["spec"].(map[string]interface{}) if _, addonSpec := spec["observabilityAddonSpec"]; !addonSpec { - return nil, fmt.Errorf("the MCO CR did not have observabilityAddonSpec spec configed") + return nil, errors.New("the MCO CR did not have observabilityAddonSpec spec configed") } if _, resSpec := spec["observabilityAddonSpec"].(map[string]interface{})["resources"]; !resSpec { - return nil, fmt.Errorf("the MCO CR did not have observabilityAddonSpec.resources spec configed") + return nil, errors.New("the MCO CR did not have observabilityAddonSpec.resources spec configed") } res := spec["observabilityAddonSpec"].(map[string]interface{})["resources"].(map[string]interface{}) @@ -728,7 +726,7 @@ func CheckMCOConversion(opt TestOptions, v1beta1tov1beta2GoldenPath string) erro } decUnstructured := yaml.NewDecodingSerializer(unstructured.UnstructuredJSONScheme) - yamlB, err := ioutil.ReadFile(filepath.Clean(v1beta1tov1beta2GoldenPath)) + yamlB, err := os.ReadFile(filepath.Clean(v1beta1tov1beta2GoldenPath)) if err != nil { return err } @@ -799,22 +797,22 @@ func CreateObjSecret(opt TestOptions) error { bucket := os.Getenv("BUCKET") if bucket == "" { - return fmt.Errorf("failed to get s3 BUCKET env") + return errors.New("failed to get s3 BUCKET env") } region := os.Getenv("REGION") if region == "" { - return fmt.Errorf("failed to get s3 REGION env") + return errors.New("failed to get s3 REGION env") } accessKey := os.Getenv("AWS_ACCESS_KEY_ID") if accessKey == "" { - return fmt.Errorf("failed to get aws AWS_ACCESS_KEY_ID env") + return errors.New("failed to get aws AWS_ACCESS_KEY_ID env") } secretKey := os.Getenv("AWS_SECRET_ACCESS_KEY") if secretKey == "" { - return fmt.Errorf("failed to get aws AWS_SECRET_ACCESS_KEY env") + return errors.New("failed to get aws AWS_SECRET_ACCESS_KEY env") } objSecret := fmt.Sprintf(`apiVersion: v1 diff --git a/tests/pkg/utils/mco_managedcluster.go b/tests/pkg/utils/mco_managedcluster.go index e1ef022b7..75e9abe4e 100644 --- a/tests/pkg/utils/mco_managedcluster.go +++ b/tests/pkg/utils/mco_managedcluster.go @@ -5,7 +5,7 @@ package utils import ( "context" - "fmt" + "errors" goversion "github.com/hashicorp/go-version" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -63,7 +63,7 @@ func ListManagedClusters(opt TestOptions) ([]string, error) { } if len(clusterNames) == 0 { - return clusterNames, fmt.Errorf("no managedcluster found") + return clusterNames, errors.New("no managedcluster found") } return clusterNames, nil diff --git a/tests/pkg/utils/mco_metric.go b/tests/pkg/utils/mco_metric.go index 9dff600b5..9a4884789 100644 --- a/tests/pkg/utils/mco_metric.go +++ b/tests/pkg/utils/mco_metric.go @@ -7,8 +7,9 @@ import ( "bufio" "context" "crypto/tls" + "errors" "fmt" - "io/ioutil" + "io" "net/http" "net/url" "os" @@ -62,18 +63,18 @@ func ContainManagedClusterMetric(opt TestOptions, query string, matchedLabels [] return fmt.Errorf("failed to access managed cluster metrics via grafana console: %s", query), false } - metricResult, err := ioutil.ReadAll(resp.Body) + metricResult, err := io.ReadAll(resp.Body) klog.V(5).Infof("metricResult: %s\n", metricResult) if err != nil { return err, false } if !strings.Contains(string(metricResult), `"status":"success"`) { - return fmt.Errorf("failed to find valid status from response"), false + return errors.New("failed to find valid status from response"), false } if strings.Contains(string(metricResult), `"result":[]`) { - return fmt.Errorf("failed to find metric name from response"), false + return errors.New("failed to find metric name from response"), false } contained := true @@ -84,7 +85,7 @@ func ContainManagedClusterMetric(opt TestOptions, query string, matchedLabels [] } } if !contained { - return fmt.Errorf("failed to find metric name from response"), false + return errors.New("failed to find metric name from response"), false } return nil, true diff --git a/tests/pkg/utils/utils.go b/tests/pkg/utils/utils.go index 589ed1a5d..80ab93455 100644 --- a/tests/pkg/utils/utils.go +++ b/tests/pkg/utils/utils.go @@ -6,6 +6,7 @@ package utils import ( "context" "encoding/json" + "errors" "fmt" "os" "os/user" @@ -14,7 +15,6 @@ import ( "time" "github.com/ghodss/yaml" - appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" @@ -22,17 +22,16 @@ import ( apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" apiextensionsclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/version" - "k8s.io/klog" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured/unstructuredscheme" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/version" "k8s.io/client-go/dynamic" "k8s.io/client-go/kubernetes" _ "k8s.io/client-go/plugin/pkg/client/auth" "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" + "k8s.io/klog" ) func NewUnversionedRestClient(url, kubeconfig, ctx string) *rest.RESTClient { @@ -190,6 +189,7 @@ func FetchBearerToken(opt TestOptions) (string, error) { return "", err } for _, secret := range secretList.Items { + // nolint:staticcheck if secret.GetObjectMeta() != nil && len(secret.GetObjectMeta().GetAnnotations()) > 0 { annos := secret.GetObjectMeta().GetAnnotations() sa, saExists := annos["kubernetes.io/service-account.name"] @@ -202,7 +202,7 @@ func FetchBearerToken(opt TestOptions) (string, error) { } } } - return "", fmt.Errorf("failed to get bearer token") + return "", errors.New("failed to get bearer token") } func LoadConfig(url, kubeconfig, ctx string) (*rest.Config, error) { @@ -237,14 +237,14 @@ func LoadConfig(url, kubeconfig, ctx string) (*rest.Config, error) { } } - return nil, fmt.Errorf("could not create a valid kubeconfig") + return nil, errors.New("could not create a valid kubeconfig") } -//Apply a multi resources file to the cluster described by the url, kubeconfig and ctx. -//url of the cluster -//kubeconfig which contains the ctx -//ctx, the ctx to use -//yamlB, a byte array containing the resources file +// Apply a multi resources file to the cluster described by the url, kubeconfig and ctx. +// url of the cluster +// kubeconfig which contains the ctx +// ctx, the ctx to use +// yamlB, a byte array containing the resources file func Apply(url string, kubeconfig string, ctx string, yamlB []byte) error { yamls := strings.Split(string(yamlB), "---") // yamlFiles is an []string @@ -570,7 +570,7 @@ func Apply(url string, kubeconfig string, ctx string, yamlB []byte) error { return nil } -//StatusContainsTypeEqualTo check if u contains a condition type with value typeString +// StatusContainsTypeEqualTo check if u contains a condition type with value typeString func StatusContainsTypeEqualTo(u *unstructured.Unstructured, typeString string) bool { if u != nil { if v, ok := u.Object["status"]; ok { @@ -591,7 +591,7 @@ func StatusContainsTypeEqualTo(u *unstructured.Unstructured, typeString string) return false } -//GetCluster returns the first cluster with a given tag +// GetCluster returns the first cluster with a given tag func GetCluster(tag string, clusters []Cluster) *Cluster { for _, cluster := range clusters { if tag, ok := cluster.Tags[tag]; ok { @@ -603,7 +603,7 @@ func GetCluster(tag string, clusters []Cluster) *Cluster { return nil } -//GetClusters returns all clusters with a given tag +// GetClusters returns all clusters with a given tag func GetClusters(tag string, clusters []Cluster) []*Cluster { filteredClusters := make([]*Cluster, 0) for i, cluster := range clusters { @@ -758,7 +758,7 @@ func GetPullSecret(opt TestOptions) (string, error) { } if len(mchList.Items) == 0 { - return "", fmt.Errorf("can not find the MCH operator CR in the cluster") + return "", errors.New("can not find the MCH operator CR in the cluster") } mchName := mchList.Items[0].GetName() @@ -773,7 +773,7 @@ func GetPullSecret(opt TestOptions) (string, error) { spec := getMCH.Object["spec"].(map[string]interface{}) if _, ok := spec["imagePullSecret"]; !ok { - return "", fmt.Errorf("can not find imagePullSecret in MCH CR") + return "", errors.New("can not find imagePullSecret in MCH CR") } ips := spec["imagePullSecret"].(string) diff --git a/tests/run-in-kind/run-e2e-in-kind.sh b/tests/run-in-kind/run-e2e-in-kind.sh index da7565a9f..66e58f10e 100755 --- a/tests/run-in-kind/run-e2e-in-kind.sh +++ b/tests/run-in-kind/run-e2e-in-kind.sh @@ -2,7 +2,10 @@ set -exo pipefail -ROOTDIR="$(cd "$(dirname "$0")/../.." ; pwd -P)" +ROOTDIR="$( + cd "$(dirname "$0")/../.." + pwd -P +)" WORKDIR=${ROOTDIR}/tests/run-in-kind export IS_KIND_ENV=true @@ -11,69 +14,69 @@ export IS_KIND_ENV=true source ${WORKDIR}/env.sh setup_kubectl_command() { - if ! command -v kubectl >/dev/null 2>&1; then - echo "This script will install kubectl (https://kubernetes.io/docs/tasks/tools/install-kubectl/) on your machine" - if [[ "$(uname)" == "Linux" ]]; then - curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.18.0/bin/linux/amd64/kubectl - elif [[ "$(uname)" == "Darwin" ]]; then - curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.18.0/bin/darwin/amd64/kubectl - fi - chmod +x ./kubectl - sudo mv ./kubectl /usr/local/bin/kubectl + if ! command -v kubectl >/dev/null 2>&1; then + echo "This script will install kubectl (https://kubernetes.io/docs/tasks/tools/install-kubectl/) on your machine" + if [[ "$(uname)" == "Linux" ]]; then + curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.18.0/bin/linux/amd64/kubectl + elif [[ "$(uname)" == "Darwin" ]]; then + curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.18.0/bin/darwin/amd64/kubectl fi + chmod +x ./kubectl + sudo mv ./kubectl /usr/local/bin/kubectl + fi } create_kind_cluster() { - if ! command -v kind >/dev/null 2>&1; then - echo "This script will install kind (https://kind.sigs.k8s.io/) on your machine." - curl -Lo ./kind-amd64 "https://kind.sigs.k8s.io/dl/v0.10.0/kind-$(uname)-amd64" - chmod +x ./kind-amd64 - sudo mv ./kind-amd64 /usr/local/bin/kind - fi - echo "Delete the KinD cluster if exists" - kind delete cluster --name $1 || true - rm -rf $HOME/.kube/kind-config-$1 + if ! command -v kind >/dev/null 2>&1; then + echo "This script will install kind (https://kind.sigs.k8s.io/) on your machine." + curl -Lo ./kind-amd64 "https://kind.sigs.k8s.io/dl/v0.10.0/kind-$(uname)-amd64" + chmod +x ./kind-amd64 + sudo mv ./kind-amd64 /usr/local/bin/kind + fi + echo "Delete the KinD cluster if exists" + kind delete cluster --name $1 || true + rm -rf $HOME/.kube/kind-config-$1 - echo "Start KinD cluster with the default cluster name - $1" - kind create cluster --kubeconfig $HOME/.kube/kind-config-$1 --name $1 --config ${WORKDIR}/kind/kind-$1.config.yaml - export KUBECONFIG=$HOME/.kube/kind-config-$1 + echo "Start KinD cluster with the default cluster name - $1" + kind create cluster --kubeconfig $HOME/.kube/kind-config-$1 --name $1 --config ${WORKDIR}/kind/kind-$1.config.yaml + export KUBECONFIG=$HOME/.kube/kind-config-$1 } deploy_service_ca_operator() { - kubectl create ns openshift-config-managed - kubectl apply -f ${WORKDIR}/service-ca/ + kubectl create ns openshift-config-managed + kubectl apply -f ${WORKDIR}/service-ca/ } deploy_crds() { - kubectl apply -f ${WORKDIR}/req_crds/ + kubectl apply -f ${WORKDIR}/req_crds/ } deploy_templates() { - kubectl apply -f ${WORKDIR}/templates/ + kubectl apply -f ${WORKDIR}/templates/ } deploy_openshift_router() { - kubectl create ns openshift-ingress - kubectl apply -f ${WORKDIR}/router/ + kubectl create ns openshift-ingress + kubectl apply -f ${WORKDIR}/router/ } setup_e2e_test_env() { - ${ROOTDIR}/cicd-scripts/setup-e2e-tests.sh + ${ROOTDIR}/cicd-scripts/setup-e2e-tests.sh } run_e2e_test() { - ${ROOTDIR}/cicd-scripts/run-e2e-tests.sh + ${ROOTDIR}/cicd-scripts/run-e2e-tests.sh } run() { - setup_kubectl_command - create_kind_cluster hub - deploy_crds - deploy_templates - deploy_service_ca_operator - deploy_openshift_router - setup_e2e_test_env - run_e2e_test + setup_kubectl_command + create_kind_cluster hub + deploy_crds + deploy_templates + deploy_service_ca_operator + deploy_openshift_router + setup_e2e_test_env + run_e2e_test } run diff --git a/tools/generate-dashboard-configmap-yaml.sh b/tools/generate-dashboard-configmap-yaml.sh index 363898d39..bf35c6d02 100755 --- a/tools/generate-dashboard-configmap-yaml.sh +++ b/tools/generate-dashboard-configmap-yaml.sh @@ -4,18 +4,15 @@ obs_namespace='open-cluster-management-observability' -if command -v python &> /dev/null -then - PYTHON_CMD="python" -elif command -v python2 &> /dev/null -then - PYTHON_CMD="python2" -elif command -v python3 &> /dev/null -then - PYTHON_CMD="python3" +if command -v python &>/dev/null; then + PYTHON_CMD="python" +elif command -v python2 &>/dev/null; then + PYTHON_CMD="python2" +elif command -v python3 &>/dev/null; then + PYTHON_CMD="python3" else - echo "Failed to found python command, please install firstly" - exit 1 + echo "Failed to found python command, please install firstly" + exit 1 fi usage() { @@ -45,67 +42,66 @@ start() { savePath=$2 fi org_dashboard_name=$1 - dashboard_name=`echo ${1//[!(a-z\A-Z\0-9\-\.)]/-} | tr '[:upper:]' '[:lower:]'` - - while [[ $# -gt 0 ]] - do - key="$1" - case $key in - -h|--help) - usage - ;; - - -n|--namespace) - obs_namespace="$2" - shift - shift - ;; + dashboard_name=$(echo ${1//[!(a-z\A-Z\0-9\-\.)]/-} | tr '[:upper:]' '[:lower:]') + + while [[ $# -gt 0 ]]; do + key="$1" + case $key in + -h | --help) + usage + ;; + + -n | --namespace) + obs_namespace="$2" + shift + shift + ;; *) - shift - ;; - esac + shift + ;; + esac done if [ ! -d $savePath ]; then mkdir -p $savePath if [ $? -ne 0 ]; then - echo "Failed to create directory <$savePath>" - exit 1 + echo "Failed to create directory <$savePath>" + exit 1 fi fi - podName=`kubectl get pods -n "$obs_namespace" -l app=multicluster-observability-grafana-dev --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}'` + podName=$(kubectl get pods -n "$obs_namespace" -l app=multicluster-observability-grafana-dev --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}') if [ $? -ne 0 ] || [ -z "$podName" ]; then - echo "Failed to get grafana pod name, please check your grafana-dev deployment" - exit 1 + echo "Failed to get grafana pod name, please check your grafana-dev deployment" + exit 1 fi curlCMD="kubectl exec -it -n "$obs_namespace" $podName -c grafana-dashboard-loader -- /usr/bin/curl" XForwardedUser="WHAT_YOU_ARE_DOING_IS_VOIDING_SUPPORT_0000000000000000000000000000000000000000000000000000000000000000" - dashboards=`$curlCMD -s -X GET -H "Content-Type: application/json" -H "X-Forwarded-User: $XForwardedUser" 127.0.0.1:3001/api/search` + dashboards=$($curlCMD -s -X GET -H "Content-Type: application/json" -H "X-Forwarded-User: $XForwardedUser" 127.0.0.1:3001/api/search) if [ $? -ne 0 ]; then - echo "Failed to search dashboards, please check your grafana-dev instance" - exit 1 + echo "Failed to search dashboards, please check your grafana-dev instance" + exit 1 fi - dashboard=`echo $dashboards | $PYTHON_CMD -c "import sys, json;[sys.stdout.write(json.dumps(dash)) for dash in json.load(sys.stdin) if dash['title'] == '$org_dashboard_name']"` + dashboard=$(echo $dashboards | $PYTHON_CMD -c "import sys, json;[sys.stdout.write(json.dumps(dash)) for dash in json.load(sys.stdin) if dash['title'] == '$org_dashboard_name']") + + dashboardUID=$(echo $dashboard | $PYTHON_CMD -c "import sys, json; print(json.load(sys.stdin)['uid'])" 2>/dev/null) + dashboardFolderId=$(echo $dashboard | $PYTHON_CMD -c "import sys, json; print(json.load(sys.stdin)['folderId'])" 2>/dev/null) + dashboardFolderTitle=$(echo $dashboard | $PYTHON_CMD -c "import sys, json; print(json.load(sys.stdin)['folderTitle'])" 2>/dev/null) - dashboardUID=`echo $dashboard | $PYTHON_CMD -c "import sys, json; print(json.load(sys.stdin)['uid'])" 2>/dev/null` - dashboardFolderId=`echo $dashboard | $PYTHON_CMD -c "import sys, json; print(json.load(sys.stdin)['folderId'])" 2>/dev/null` - dashboardFolderTitle=`echo $dashboard | $PYTHON_CMD -c "import sys, json; print(json.load(sys.stdin)['folderTitle'])" 2>/dev/null` - - dashboardJson=`$curlCMD -s -X GET -H "Content-Type: application/json" -H "X-Forwarded-User:$XForwardedUser" 127.0.0.1:3001/api/dashboards/uid/$dashboardUID | $PYTHON_CMD -c "import sys, json; print(json.dumps(json.load(sys.stdin)['dashboard']))" 2>/dev/null` + dashboardJson=$($curlCMD -s -X GET -H "Content-Type: application/json" -H "X-Forwarded-User:$XForwardedUser" 127.0.0.1:3001/api/dashboards/uid/$dashboardUID | $PYTHON_CMD -c "import sys, json; print(json.dumps(json.load(sys.stdin)['dashboard']))" 2>/dev/null) if [ $? -ne 0 ]; then - echo "Failed to fetch dashboard json data, please check your dashboard name <$org_dashboard_name>" - exit 1 + echo "Failed to fetch dashboard json data, please check your dashboard name <$org_dashboard_name>" + exit 1 fi # delete dashboard uid avoid conflict with old dashboard - dashboardJson=`echo $dashboardJson | $PYTHON_CMD -c "import sys, json; d=json.load(sys.stdin);del d['uid'];print(json.dumps(d))"` + dashboardJson=$(echo $dashboardJson | $PYTHON_CMD -c "import sys, json; d=json.load(sys.stdin);del d['uid'];print(json.dumps(d))") if [ $dashboardFolderId -ne 0 ]; then - cat > $savePath/$dashboard_name.yaml <$savePath/$dashboard_name.yaml < $savePath/$dashboard_name.yaml <$savePath/$dashboard_name.yaml < grafana-dev-config.ini + kubectl get secret -n "$obs_namespace" grafana-config -o 'go-template={{index .data "grafana.ini"}}' | base64 --decode >grafana-dev-config.ini if [ $? -ne 0 ]; then - echo "Failed to get grafana config secret" - exit 1 + echo "Failed to get grafana config secret" + exit 1 fi $sed_command "s~%(domain)s/grafana/$~%(domain)s/grafana-dev/~g" grafana-dev-config.ini kubectl create secret generic grafana-dev-config -n "$obs_namespace" --from-file=grafana.ini=grafana-dev-config.ini - kubectl get deployment -n "$obs_namespace" -l app=multicluster-observability-grafana -o yaml > grafana-dev-deploy.yaml + kubectl get deployment -n "$obs_namespace" -l app=multicluster-observability-grafana -o yaml >grafana-dev-deploy.yaml if [ $? -ne 0 ]; then - echo "Failed to get grafana deployment" - exit 1 + echo "Failed to get grafana deployment" + exit 1 fi $sed_command "s~name: grafana$~name: grafana-dev~g" grafana-dev-deploy.yaml $sed_command "s~name: observability-grafana$~name: grafana-dev~g" grafana-dev-deploy.yaml @@ -48,7 +48,7 @@ deploy() { $sed_command "s~grafana-config$~grafana-dev-config~g" grafana-dev-deploy.yaml $sed_command "s~- multicluster-observability-grafana$~- multicluster-observability-grafana-dev~g" grafana-dev-deploy.yaml - POD_NAME=$(kubectl get pods -n "$obs_namespace" -l app=multicluster-observability-grafana |grep grafana|awk '{split($0, a, " "); print a[1]}' |head -n 1) + POD_NAME=$(kubectl get pods -n "$obs_namespace" -l app=multicluster-observability-grafana | grep grafana | awk '{split($0, a, " "); print a[1]}' | head -n 1) if [ -z "$POD_NAME" ]; then echo "Failed to get grafana pod name" exit 1 @@ -64,14 +64,14 @@ deploy() { $sed_command "s~--client-id=.*$~--client-id=grafana-proxy-client-dev~g" grafana-dev-deploy.yaml $sed_command "s~--client-secret=.*$~--client-secret=grafana-proxy-client-dev~g" grafana-dev-deploy.yaml $sed_command "s~ securityContext:.*$~ securityContext: {fsGroup: ${GROUP_ID}}~g" grafana-dev-deploy.yaml - sed "s~- emptyDir: {}$~- persistentVolumeClaim:$ claimName: grafana-dev~g" grafana-dev-deploy.yaml > grafana-dev-deploy.yaml.bak - tr $ '\n' < grafana-dev-deploy.yaml.bak > grafana-dev-deploy.yaml + sed "s~- emptyDir: {}$~- persistentVolumeClaim:$ claimName: grafana-dev~g" grafana-dev-deploy.yaml >grafana-dev-deploy.yaml.bak + tr $ '\n' grafana-dev-deploy.yaml kubectl apply -f grafana-dev-deploy.yaml - kubectl get svc -n "$obs_namespace" -l app=multicluster-observability-grafana -o yaml > grafana-dev-svc.yaml + kubectl get svc -n "$obs_namespace" -l app=multicluster-observability-grafana -o yaml >grafana-dev-svc.yaml if [ $? -ne 0 ]; then - echo "Failed to get grafana service" - exit 1 + echo "Failed to get grafana service" + exit 1 fi $sed_command "s~name: grafana$~name: grafana-dev~g" grafana-dev-svc.yaml $sed_command "s~app: multicluster-observability-grafana$~app: multicluster-observability-grafana-dev~g" grafana-dev-svc.yaml @@ -84,33 +84,33 @@ deploy() { $sed_command "s~service.beta.openshift.io/serving-cert-signed-by:.*$~~g" grafana-dev-svc.yaml kubectl apply -f grafana-dev-svc.yaml - kubectl get sa -n "$obs_namespace" grafana -o yaml > grafana-dev-sa.yaml + kubectl get sa -n "$obs_namespace" grafana -o yaml >grafana-dev-sa.yaml if [ $? -ne 0 ]; then - echo "Failed to get grafana serviceaccount" - exit 1 + echo "Failed to get grafana serviceaccount" + exit 1 fi $sed_command "s~name: grafana$~name: grafana-dev~g" grafana-dev-sa.yaml $sed_command 's/{"kind":"Route","name":"grafana"}/{"kind":"Route","name":"grafana-dev"}/g' grafana-dev-sa.yaml kubectl apply -f grafana-dev-sa.yaml - kubectl get clusterrolebinding open-cluster-management:grafana-crb -o yaml > grafana-dev-crb.yaml + kubectl get clusterrolebinding open-cluster-management:grafana-crb -o yaml >grafana-dev-crb.yaml if [ $? -ne 0 ]; then - echo "Failed to get grafana cluster role binding" - exit 1 + echo "Failed to get grafana cluster role binding" + exit 1 fi $sed_command "s~name: grafana$~name: grafana-dev~g" grafana-dev-crb.yaml $sed_command "s~name: open-cluster-management:grafana-crb$~name: open-cluster-management:grafana-crb-dev~g" grafana-dev-crb.yaml kubectl apply -f grafana-dev-crb.yaml - kubectl get route -n "$obs_namespace" grafana -o yaml > grafana-dev-route.yaml + kubectl get route -n "$obs_namespace" grafana -o yaml >grafana-dev-route.yaml if [ $? -ne 0 ]; then - echo "Failed to get grafana route" - exit 1 + echo "Failed to get grafana route" + exit 1 fi $sed_command "s~name: grafana$~name: grafana-dev~g" grafana-dev-route.yaml $sed_command "s~host:.*$~~g" grafana-dev-route.yaml kubectl apply -f grafana-dev-route.yaml - + cat >grafana-pvc.yaml < grafana-dev-oauthclient.yaml + kubectl get oauthclient grafana-proxy-client -o yaml >grafana-dev-oauthclient.yaml if [ $? -ne 0 ]; then - echo "Failed to get grafana oauthclient" - exit 1 + echo "Failed to get grafana oauthclient" + exit 1 fi $sed_command "s~name: grafana-proxy-client$~name: grafana-proxy-client-dev~g" grafana-dev-oauthclient.yaml $sed_command "s/https:\/\/grafana-/https:\/\/grafana-dev-/g" grafana-dev-oauthclient.yaml @@ -182,39 +182,38 @@ start() { usage fi - while [[ $# -gt 0 ]] - do - key="$1" - case $key in - -h|--help) - usage - ;; - - -n|--namespace) - obs_namespace="$2" - shift - shift - ;; - - -c|--clean) - clean - exit 0 - ;; - - -d|--deploy) - deploy_flag=1 - shift - ;; + while [[ $# -gt 0 ]]; do + key="$1" + case $key in + -h | --help) + usage + ;; + + -n | --namespace) + obs_namespace="$2" + shift + shift + ;; + + -c | --clean) + clean + exit 0 + ;; + + -d | --deploy) + deploy_flag=1 + shift + ;; *) - usage - ;; - esac + usage + ;; + esac done if [ $deploy_flag -eq 1 ]; then - deploy - exit + deploy + exit fi } diff --git a/tools/simulator/alert-forward/clean-alert-forwarder.sh b/tools/simulator/alert-forward/clean-alert-forwarder.sh index f5fa9ceea..61ee18f6f 100755 --- a/tools/simulator/alert-forward/clean-alert-forwarder.sh +++ b/tools/simulator/alert-forward/clean-alert-forwarder.sh @@ -3,13 +3,13 @@ # Copyright Contributors to the Open Cluster Management project KUBECTL="kubectl" -if ! command -v kubectl &> /dev/null; then - if command -v oc &> /dev/null; then - KUBECTL="oc" - else - echo "kubectl or oc must be installed!" - exit 1 - fi +if ! command -v kubectl &>/dev/null; then + if command -v oc &>/dev/null; then + KUBECTL="oc" + else + echo "kubectl or oc must be installed!" + exit 1 + fi fi ALERT_FORWARDER_NS="alert-forwarder" diff --git a/tools/simulator/alert-forward/main.go b/tools/simulator/alert-forward/main.go index 7582b7ecf..445344e57 100644 --- a/tools/simulator/alert-forward/main.go +++ b/tools/simulator/alert-forward/main.go @@ -3,9 +3,9 @@ package main import ( "bytes" "context" + "errors" "fmt" "io" - "io/ioutil" "log" "net/http" "net/http/httptrace" @@ -17,7 +17,6 @@ import ( "syscall" "time" - "github.com/pkg/errors" config_util "github.com/prometheus/common/config" "github.com/prometheus/common/model" "github.com/prometheus/prometheus/config" @@ -47,7 +46,7 @@ type alertForwarder struct { func newAlertFowarder(opts *alertForwarderOptions) (*alertForwarder, error) { if len(opts.amHost) == 0 { - return nil, fmt.Errorf("am-host must be specified!") + return nil, errors.New("am-host must be specified") } u := &url.URL{ @@ -60,26 +59,26 @@ func newAlertFowarder(opts *alertForwarderOptions) (*alertForwarder, error) { if len(opts.amAccessToken) > 0 { accessToken = opts.amAccessToken } else if len(opts.amAccessTokenFile) > 0 { - data, err := ioutil.ReadFile(opts.amAccessTokenFile) + data, err := os.ReadFile(opts.amAccessTokenFile) if err != nil { return nil, err } accessToken = strings.TrimSpace(string(data)) } else { - return nil, fmt.Errorf("am-access-token or am-access-token-file must be specified!") + return nil, errors.New("am-access-token or am-access-token-file must be specified") } alerts := "" if len(opts.alerts) > 0 { alerts = opts.alerts } else if len(opts.alertsFile) > 0 { - data, err := ioutil.ReadFile(opts.alertsFile) + data, err := os.ReadFile(opts.alertsFile) if err != nil { return nil, err } alerts = strings.TrimSpace(string(data)) } else { - return nil, fmt.Errorf("alerts or alerts-file must be specified!") + return nil, errors.New("alerts or alerts-file must be specified") } return &alertForwarder{ @@ -194,7 +193,7 @@ func main() { } } -// createAlertmanagerConfig creates and returns the configuration for the target Alertmanager +// createAlertmanagerConfig creates and returns the configuration for the target Alertmanager. func createAlertmanagerConfig(amHost, amScheme, amAPIVersion, amAccessToken string) *config.AlertmanagerConfig { return &config.AlertmanagerConfig{ APIVersion: config.AlertmanagerAPIVersion(amAPIVersion), @@ -221,7 +220,7 @@ func createAlertmanagerConfig(amHost, amScheme, amAPIVersion, amAccessToken stri } } -// send alerts to alertmanager with one http request +// send alerts to alertmanager with one http request. func sendOne(c *http.Client, traceCtx context.Context, url string, b []byte) error { req, err := http.NewRequestWithContext(traceCtx, "POST", url, bytes.NewReader(b)) if err != nil { @@ -237,14 +236,16 @@ func sendOne(c *http.Client, traceCtx context.Context, url string, b []byte) err defer func() { /* #nosec */ - io.Copy(ioutil.Discard, resp.Body) + // TODO(saswatamcode): Check err here. + //nolint:errcheck + io.Copy(io.Discard, resp.Body) /* #nosec */ resp.Body.Close() }() // Any HTTP status 2xx is OK. if resp.StatusCode/100 != 2 { - return errors.Errorf("bad response status %s", resp.Status) + return fmt.Errorf("bad response status %s", resp.Status) } return nil } diff --git a/tools/simulator/alert-forward/setup-alert-forwarder.sh b/tools/simulator/alert-forward/setup-alert-forwarder.sh index 235d9fc1b..e816134a5 100755 --- a/tools/simulator/alert-forward/setup-alert-forwarder.sh +++ b/tools/simulator/alert-forward/setup-alert-forwarder.sh @@ -2,21 +2,24 @@ # Copyright (c) 2021 Red Hat, Inc. # Copyright Contributors to the Open Cluster Management project -WORK_DIR="$(cd "$(dirname "$0")" ; pwd -P)" +WORK_DIR="$( + cd "$(dirname "$0")" + pwd -P +)" KUBECTL="kubectl" -if ! command -v kubectl &> /dev/null; then - if command -v oc &> /dev/null; then - KUBECTL="oc" - else - echo "kubectl or oc must be installed!" - exit 1 - fi +if ! command -v kubectl &>/dev/null; then + if command -v oc &>/dev/null; then + KUBECTL="oc" + else + echo "kubectl or oc must be installed!" + exit 1 + fi fi SED_COMMAND='sed -i' if [[ "$(uname)" == "Darwin" ]]; then - SED_COMMAND='sed -i -e' + SED_COMMAND='sed -i -e' fi function usage() { @@ -30,7 +33,7 @@ function usage() { } INTERVAL="30s" # default alert forward interval -WORKERS=1000 # default alert forward workers +WORKERS=1000 # default alert forward workers # Allow command-line args to override the defaults. while getopts ":i:w:h" opt; do @@ -67,4 +70,3 @@ ${SED_COMMAND} "s~--workers=1000~--workers=${WORKERS}~g" ${WORK_DIR}/deployment. ${KUBECTL} create ns ${ALERT_FORWARDER_NS} ${KUBECTL} -n ${ALERT_FORWARDER_NS} create secret generic ${AM_ACCESS_TOKEN_SECRET} --from-literal=token=${AM_ACCESS_TOKEN} ${KUBECTL} -n ${ALERT_FORWARDER_NS} apply -f ${WORK_DIR}/deployment.yaml - diff --git a/tools/simulator/managed-cluster/clean-managedcluster.sh b/tools/simulator/managed-cluster/clean-managedcluster.sh index cfdd401a6..dd132d622 100755 --- a/tools/simulator/managed-cluster/clean-managedcluster.sh +++ b/tools/simulator/managed-cluster/clean-managedcluster.sh @@ -5,18 +5,17 @@ set -exo pipefail KUBECTL="kubectl" -if ! command -v kubectl &> /dev/null; then - if command -v oc &> /dev/null; then - KUBECTL="oc" - else - echo "kubectl or oc must be installed!" - exit 1 - fi +if ! command -v kubectl &>/dev/null; then + if command -v oc &>/dev/null; then + KUBECTL="oc" + else + echo "kubectl or oc must be installed!" + exit 1 + fi fi # deleting the simulated managedcluster -for i in $(seq $1 $2) -do - echo "Deleting Simulated managedCluster simulated-${i}-managedcluster..." - ${KUBECTL} delete managedcluster simulated-${i}-managedcluster +for i in $(seq $1 $2); do + echo "Deleting Simulated managedCluster simulated-${i}-managedcluster..." + ${KUBECTL} delete managedcluster simulated-${i}-managedcluster done diff --git a/tools/simulator/managed-cluster/setup-managedcluster.sh b/tools/simulator/managed-cluster/setup-managedcluster.sh index 087dc5f63..35e282e73 100755 --- a/tools/simulator/managed-cluster/setup-managedcluster.sh +++ b/tools/simulator/managed-cluster/setup-managedcluster.sh @@ -4,31 +4,33 @@ set -exo pipefail -WORK_DIR="$(cd "$(dirname "$0")" ; pwd -P)" +WORK_DIR="$( + cd "$(dirname "$0")" + pwd -P +)" # Create bin directory and add it to PATH mkdir -p ${WORK_DIR}/bin export PATH=${PATH}:${WORK_DIR}/bin KUBECTL="kubectl" -if ! command -v kubectl &> /dev/null; then - if command -v oc &> /dev/null; then - KUBECTL="oc" - else - echo "This script will install kubectl (https://kubernetes.io/docs/tasks/tools/install-kubectl/) on your machine" - if [[ "$(uname)" == "Linux" ]]; then - curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.21.0/bin/linux/amd64/kubectl - elif [[ "$(uname)" == "Darwin" ]]; then - curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.21.0/bin/darwin/amd64/kubectl - fi - chmod +x ./kubectl && mv ./kubectl ${WORK_DIR}/bin/kubectl +if ! command -v kubectl &>/dev/null; then + if command -v oc &>/dev/null; then + KUBECTL="oc" + else + echo "This script will install kubectl (https://kubernetes.io/docs/tasks/tools/install-kubectl/) on your machine" + if [[ "$(uname)" == "Linux" ]]; then + curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.21.0/bin/linux/amd64/kubectl + elif [[ "$(uname)" == "Darwin" ]]; then + curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.21.0/bin/darwin/amd64/kubectl fi + chmod +x ./kubectl && mv ./kubectl ${WORK_DIR}/bin/kubectl + fi fi # creating the simulated managedcluster -for i in $(seq $1 $2) -do - echo "Creating Simulated managedCluster simulated-${i}-managedcluster..." - cat < /dev/null; then - if command -v oc &> /dev/null; then - KUBECTL="oc" - else - echo "kubectl or oc must be installed!" - exit 1 - fi +if ! command -v kubectl &>/dev/null; then + if command -v oc &>/dev/null; then + KUBECTL="oc" + else + echo "kubectl or oc must be installed!" + exit 1 + fi fi function usage() { - echo "${0} -n NUMBERS [-m MANAGED_CLUSTER_PREFIX]" - echo '' - # shellcheck disable=SC2016 - echo ' -n: Specifies the total number of simulated metrics collectors, required' - # shellcheck disable=SC2016 - echo ' -m: Specifies the prefix for the simulated managedcluster name, optional, the default value is "simulated-managed-cluster".' - echo '' + echo "${0} -n NUMBERS [-m MANAGED_CLUSTER_PREFIX]" + echo '' + # shellcheck disable=SC2016 + echo ' -n: Specifies the total number of simulated metrics collectors, required' + # shellcheck disable=SC2016 + echo ' -m: Specifies the prefix for the simulated managedcluster name, optional, the default value is "simulated-managed-cluster".' + echo '' } MANAGED_CLUSTER_PREFIX="simulated-managed-cluster" # default managedccluster name prefix # Allow command-line args to override the defaults. while getopts ":n:m:h" opt; do - case ${opt} in - n) - NUMBERS=${OPTARG} - ;; - m) - MANAGED_CLUSTER_PREFIX=${OPTARG} - ;; - h) - usage - exit 0 - ;; - \?) - echo "Invalid option: -${OPTARG}" >&2 - usage - exit 1 - ;; - esac + case ${opt} in + n) + NUMBERS=${OPTARG} + ;; + m) + MANAGED_CLUSTER_PREFIX=${OPTARG} + ;; + h) + usage + exit 0 + ;; + \?) + echo "Invalid option: -${OPTARG}" >&2 + usage + exit 1 + ;; + esac done -if [[ -z "${NUMBERS}" ]]; then - echo "Error: NUMBERS (-n) must be specified!" - usage - exit 1 +if [[ -z ${NUMBERS} ]]; then + echo "Error: NUMBERS (-n) must be specified!" + usage + exit 1 fi re='^[0-9]+$' -if ! [[ ${NUMBERS} =~ ${re} ]] ; then - echo "error: arguments <${NUMBERS}> is not a number" >&2; exit 1 +if ! [[ ${NUMBERS} =~ ${re} ]]; then + echo "error: arguments <${NUMBERS}> is not a number" >&2 + exit 1 fi -for i in $(seq 1 ${NUMBERS}) -do - cluster_name=${MANAGED_CLUSTER_PREFIX}-${i} - ${KUBECTL} delete deploy -n ${cluster_name} metrics-collector-deployment - ${KUBECTL} delete clusterrolebinding ${cluster_name}-clusters-metrics-collector-view - ${KUBECTL} delete -n ${cluster_name} secret/observability-managed-cluster-certs - ${KUBECTL} delete ns ${cluster_name} +for i in $(seq 1 ${NUMBERS}); do + cluster_name=${MANAGED_CLUSTER_PREFIX}-${i} + ${KUBECTL} delete deploy -n ${cluster_name} metrics-collector-deployment + ${KUBECTL} delete clusterrolebinding ${cluster_name}-clusters-metrics-collector-view + ${KUBECTL} delete -n ${cluster_name} secret/observability-managed-cluster-certs + ${KUBECTL} delete ns ${cluster_name} done diff --git a/tools/simulator/metrics-collector/generate-metrics-data.sh b/tools/simulator/metrics-collector/generate-metrics-data.sh index ff5ce5e6e..953322dc8 100755 --- a/tools/simulator/metrics-collector/generate-metrics-data.sh +++ b/tools/simulator/metrics-collector/generate-metrics-data.sh @@ -6,7 +6,10 @@ set -eo pipefail -WORKDIR="$(cd "$(dirname "$0")" ; pwd -P)" +WORKDIR="$( + cd "$(dirname "$0")" + pwd -P +)" # Create bin directory and add it to PATH mkdir -p ${ROOTDIR}/bin export PATH={ROOTDIR}/bin:${PATH} @@ -20,38 +23,38 @@ TIME_SERIES_OUT=${WORKDIR}/timeseries.txt METRICS_ALLOW_LIST_URL=${METRICS_ALLOW_LIST_URL:-https://raw.githubusercontent.com/stolostron/multicluster-observability-operator/main/operators/multiclusterobservability/manifests/base/config/metrics_allowlist.yaml} METRICS_IMAGE=${METRICS_IMAGE-quay.io/ocm-observability/metrics-data:2.4.0} -if [[ -z "${IS_TIMESERIES_ONLY}" ]]; then - # check docker - if ! command -v docker &> /dev/null; then - echo "docker must be installed to run this script." - exit 1 - fi +if [[ -z ${IS_TIMESERIES_ONLY} ]]; then + # check docker + if ! command -v docker &>/dev/null; then + echo "docker must be installed to run this script." + exit 1 + fi fi # install kubectl KUBECTL="kubectl" -if ! command -v kubectl &> /dev/null; then - if command -v oc &> /dev/null; then - KUBECTL="oc" - else - if [[ "$(uname)" == "Linux" ]]; then - curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.21.0/bin/linux/amd64/kubectl - elif [[ "$(uname)" == "Darwin" ]]; then - curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.21.0/bin/darwin/amd64/kubectl - fi - chmod +x ./kubectl && mv ./kubectl ${WORK_DIR}/bin/kubectl +if ! command -v kubectl &>/dev/null; then + if command -v oc &>/dev/null; then + KUBECTL="oc" + else + if [[ "$(uname)" == "Linux" ]]; then + curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.21.0/bin/linux/amd64/kubectl + elif [[ "$(uname)" == "Darwin" ]]; then + curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.21.0/bin/darwin/amd64/kubectl fi + chmod +x ./kubectl && mv ./kubectl ${WORK_DIR}/bin/kubectl + fi fi # install jq -if ! command -v jq &> /dev/null; then - if [[ "$(uname)" == "Linux" ]]; then - curl -o jq -L https://github.com/stedolan/jq/releases/download/jq-1.6/jq-linux64 - elif [[ "$(uname)" == "Darwin" ]]; then - curl -o jq -L https://github.com/stedolan/jq/releases/download/jq-1.6/jq-osx-amd64 - fi - chmod +x ./jq - chmod +x ./jq && mv ./jq ${WORK_DIR}/bin/jq +if ! command -v jq &>/dev/null; then + if [[ "$(uname)" == "Linux" ]]; then + curl -o jq -L https://github.com/stedolan/jq/releases/download/jq-1.6/jq-linux64 + elif [[ "$(uname)" == "Darwin" ]]; then + curl -o jq -L https://github.com/stedolan/jq/releases/download/jq-1.6/jq-osx-amd64 + fi + chmod +x ./jq + chmod +x ./jq && mv ./jq ${WORK_DIR}/bin/jq fi # install gojsontoyaml @@ -59,86 +62,83 @@ GOBIN=${WORK_DIR}/bin go install github.com/brancz/gojsontoyaml GOJSONTOYAML_BIN=${WORK_DIR}/bin/gojsontoyaml function get_metrics_list() { - echo "getting metrics list..." - if [[ -z "${IS_GENERATING_OCP311_METRICS}" ]]; then - matches=$(curl -L ${METRICS_ALLOW_LIST_URL} | ${GOJSONTOYAML_BIN} --yamltojson | jq -r '.data."metrics_list.yaml"' | ${GOJSONTOYAML_BIN} --yamltojson | jq -r '.matches' | jq '"{" + .[] + "}"') - names=$(curl -L ${METRICS_ALLOW_LIST_URL} | ${GOJSONTOYAML_BIN} --yamltojson | jq -r '.data."metrics_list.yaml"' | ${GOJSONTOYAML_BIN} --yamltojson | jq -r '.names' | jq '"{__name__=\"" + .[] + "\"}"') - echo $matches $names | jq -s . > ${METRICS_JSON_OUT} - else - matches=$(curl -L ${METRICS_ALLOW_LIST_URL} | ${GOJSONTOYAML_BIN} --yamltojson | jq -r '.data."ocp311_metrics_list.yaml"' | ${GOJSONTOYAML_BIN} --yamltojson | jq -r '.matches' | jq '"{" + .[] + "}"') - names=$(curl -L ${METRICS_ALLOW_LIST_URL} | ${GOJSONTOYAML_BIN} --yamltojson | jq -r '.data."ocp311_metrics_list.yaml"' | ${GOJSONTOYAML_BIN} --yamltojson | jq -r '.names' | jq '"{__name__=\"" + .[] + "\"}"') - echo $matches $names | jq -s . > ${METRICS_JSON_OUT} - fi + echo "getting metrics list..." + if [[ -z ${IS_GENERATING_OCP311_METRICS} ]]; then + matches=$(curl -L ${METRICS_ALLOW_LIST_URL} | ${GOJSONTOYAML_BIN} --yamltojson | jq -r '.data."metrics_list.yaml"' | ${GOJSONTOYAML_BIN} --yamltojson | jq -r '.matches' | jq '"{" + .[] + "}"') + names=$(curl -L ${METRICS_ALLOW_LIST_URL} | ${GOJSONTOYAML_BIN} --yamltojson | jq -r '.data."metrics_list.yaml"' | ${GOJSONTOYAML_BIN} --yamltojson | jq -r '.names' | jq '"{__name__=\"" + .[] + "\"}"') + echo $matches $names | jq -s . >${METRICS_JSON_OUT} + else + matches=$(curl -L ${METRICS_ALLOW_LIST_URL} | ${GOJSONTOYAML_BIN} --yamltojson | jq -r '.data."ocp311_metrics_list.yaml"' | ${GOJSONTOYAML_BIN} --yamltojson | jq -r '.matches' | jq '"{" + .[] + "}"') + names=$(curl -L ${METRICS_ALLOW_LIST_URL} | ${GOJSONTOYAML_BIN} --yamltojson | jq -r '.data."ocp311_metrics_list.yaml"' | ${GOJSONTOYAML_BIN} --yamltojson | jq -r '.names' | jq '"{__name__=\"" + .[] + "\"}"') + echo $matches $names | jq -s . >${METRICS_JSON_OUT} + fi } function get_recordingrules_list() { - echo "getting recordingrules list..." - if [[ -z "${IS_GENERATING_OCP311_METRICS}" ]]; then - recordingrules=$(curl -L ${METRICS_ALLOW_LIST_URL} | ${GOJSONTOYAML_BIN} --yamltojson | jq -r '.data."metrics_list.yaml"' | ${GOJSONTOYAML_BIN} --yamltojson | jq '.recording_rules[]') - echo "$recordingrules" | jq -s . > ${RECORDINGRULES_JSON_OUT} - else - recordingrules=$(curl -L ${METRICS_ALLOW_LIST_URL} | ${GOJSONTOYAML_BIN} --yamltojson | jq -r '.data."ocp311_metrics_list.yaml"' | ${GOJSONTOYAML_BIN} --yamltojson | jq '.recording_rules[]') - echo "$recordingrules" | jq -s . > ${RECORDINGRULES_JSON_OUT} - fi + echo "getting recordingrules list..." + if [[ -z ${IS_GENERATING_OCP311_METRICS} ]]; then + recordingrules=$(curl -L ${METRICS_ALLOW_LIST_URL} | ${GOJSONTOYAML_BIN} --yamltojson | jq -r '.data."metrics_list.yaml"' | ${GOJSONTOYAML_BIN} --yamltojson | jq '.recording_rules[]') + echo "$recordingrules" | jq -s . >${RECORDINGRULES_JSON_OUT} + else + recordingrules=$(curl -L ${METRICS_ALLOW_LIST_URL} | ${GOJSONTOYAML_BIN} --yamltojson | jq -r '.data."ocp311_metrics_list.yaml"' | ${GOJSONTOYAML_BIN} --yamltojson | jq '.recording_rules[]') + echo "$recordingrules" | jq -s . >${RECORDINGRULES_JSON_OUT} + fi } function generate_metrics() { - echo "generating metrics..." - federate="curl --fail --silent -G http://localhost:9090/federate" - for rule in $(cat ${METRICS_JSON_OUT} | jq -r '.[]'); - do - federate="${federate} $(printf -- "--data-urlencode match[]=%s" ${rule})" - done - echo '# Beggining for metrics' > ${TIME_SERIES_OUT} - ${federate} >> ${TIME_SERIES_OUT} + echo "generating metrics..." + federate="curl --fail --silent -G http://localhost:9090/federate" + for rule in $(cat ${METRICS_JSON_OUT} | jq -r '.[]'); do + federate="${federate} $(printf -- "--data-urlencode match[]=%s" ${rule})" + done + echo '# Beginning for metrics' >${TIME_SERIES_OUT} + ${federate} >>${TIME_SERIES_OUT} } function generate_recordingrules() { - echo "generating recordingrules..." - query="curl --fail --silent -G http://localhost:9090/api/v1/query" - cat ${RECORDINGRULES_JSON_OUT} | jq -cr '.[]' | while read item; - do - record=$(jq -r '.record' <<< "$item") - expr=$(jq -r '.expr' <<< "$item") - #expr=${expr//\"/\\\"} - expr=$(echo "${expr}" | tr -d " ") - querycmd="${query} $(printf -- "--data-urlencode query=%s" ${expr})" - echo -e "\n# TYPE ${record} untyped" >> ${TIME_SERIES_OUT} - ${querycmd} | jq -r '.data.result' | jq -cr '.[]' | while read result; - do - vec="${record}" - metric=$(jq -r '.metric | to_entries | map("\(.key)=\"\(.value | tostring)\"") | .[]' <<< "$result") - metric=$(echo "${metric}" | sed ':a;N;$!ba;s/\n/,/g') - vec="${vec}{${metric}}" - timestamp=$(jq -r '.value[0]' <<< "$result") - value=$(jq -r '.value[1]' <<< "$result") - timestamp=$(echo "${timestamp} * 1000" | bc) - timestamp=${timestamp%.*} - echo "${vec} ${value} ${timestamp}" >> ${TIME_SERIES_OUT} - done - done + echo "generating recordingrules..." + query="curl --fail --silent -G http://localhost:9090/api/v1/query" + cat ${RECORDINGRULES_JSON_OUT} | jq -cr '.[]' | while read item; do + record=$(jq -r '.record' <<<"$item") + expr=$(jq -r '.expr' <<<"$item") + #expr=${expr//\"/\\\"} + expr=$(echo "${expr}" | tr -d " ") + querycmd="${query} $(printf -- "--data-urlencode query=%s" ${expr})" + echo -e "\n# TYPE ${record} untyped" >>${TIME_SERIES_OUT} + ${querycmd} | jq -r '.data.result' | jq -cr '.[]' | while read result; do + vec="${record}" + metric=$(jq -r '.metric | to_entries | map("\(.key)=\"\(.value | tostring)\"") | .[]' <<<"$result") + metric=$(echo "${metric}" | sed ':a;N;$!ba;s/\n/,/g') + vec="${vec}{${metric}}" + timestamp=$(jq -r '.value[0]' <<<"$result") + value=$(jq -r '.value[1]' <<<"$result") + timestamp=$(echo "${timestamp} * 1000" | bc) + timestamp=${timestamp%.*} + echo "${vec} ${value} ${timestamp}" >>${TIME_SERIES_OUT} + done + done } function generate_timeseries() { - ${KUBECTL} port-forward -n openshift-monitoring prometheus-k8s-0 9090 > /dev/null & - sleep 10 - generate_metrics - generate_recordingrules - jobs -p | xargs -r kill + ${KUBECTL} port-forward -n openshift-monitoring prometheus-k8s-0 9090 >/dev/null & + sleep 10 + generate_metrics + generate_recordingrules + jobs -p | xargs -r kill } function build_metrics_data_image() { - docker build -t ${METRICS_IMAGE} . + docker build -t ${METRICS_IMAGE} . } function push_metrics_data_image() { - docker push ${METRICS_IMAGE} + docker push ${METRICS_IMAGE} } get_metrics_list get_recordingrules_list generate_timeseries -if [[ -z "${IS_TIMESERIES_ONLY}" ]]; then - build_metrics_data_image - push_metrics_data_image +if [[ -z ${IS_TIMESERIES_ONLY} ]]; then + build_metrics_data_image + push_metrics_data_image fi diff --git a/tools/simulator/metrics-collector/metrics-extractor/extract-metrics-data.sh b/tools/simulator/metrics-collector/metrics-extractor/extract-metrics-data.sh index ffee606d6..0b945853e 100755 --- a/tools/simulator/metrics-collector/metrics-extractor/extract-metrics-data.sh +++ b/tools/simulator/metrics-collector/metrics-extractor/extract-metrics-data.sh @@ -10,7 +10,10 @@ set -eo pipefail IS_TIMESERIES_ONLY=true # expectig gojsontoyaml to be installed here GOJSONTOYAML_BIN=/usr/local/bin/gojsontoyaml -WORKDIR="$(cd "$(dirname "$0")" ; pwd -P)" +WORKDIR="$( + cd "$(dirname "$0")" + pwd -P +)" # Create bin directory and add it to PATH mkdir -p ${WORKDIR}/bin export PATH={WORKDIR}/bin:${PATH} @@ -26,8 +29,6 @@ TIME_SERIES_OUT=${WORKDIR}/../output/timeseries.txt METRICS_ALLOW_LIST_URL=${METRICS_ALLOW_LIST_URL:-https://raw.githubusercontent.com/stolostron/multicluster-observability-operator/main/operators/multiclusterobservability/manifests/base/config/metrics_allowlist.yaml} - - # function get_metrics_list() { # echo "getting metrics list..." @@ -39,58 +40,54 @@ METRICS_ALLOW_LIST_URL=${METRICS_ALLOW_LIST_URL:-https://raw.githubusercontent.c # function get_recordingrules_list() { # echo "getting recordingrules list..." - + # recordingrules=$(curl -L ${METRICS_ALLOW_LIST_URL} | ${GOJSONTOYAML_BIN} --yamltojson | jq -r '.data."metrics_list.yaml"' | ${GOJSONTOYAML_BIN} --yamltojson | jq '.recording_rules[]') # echo "$recordingrules" | jq -s . > ${RECORDINGRULES_JSON_OUT} # } function generate_metrics() { - echo "generating metrics..." - federate="curl --fail --silent -G http://localhost:9090/federate" - for rule in $(cat ${METRICS_JSON_OUT} | jq -r '.[]'); - do - federate="${federate} $(printf -- "--data-urlencode match[]=%s" ${rule})" - done - echo '# Beggining for metrics' > ${TIME_SERIES_OUT} - ${federate} >> ${TIME_SERIES_OUT} + echo "generating metrics..." + federate="curl --fail --silent -G http://localhost:9090/federate" + for rule in $(cat ${METRICS_JSON_OUT} | jq -r '.[]'); do + federate="${federate} $(printf -- "--data-urlencode match[]=%s" ${rule})" + done + echo '# Beginning for metrics' >${TIME_SERIES_OUT} + ${federate} >>${TIME_SERIES_OUT} } function generate_recordingrules() { - echo "generating recordingrules..." - query="curl --fail --silent -G http://localhost:9090/api/v1/query" - cat ${RECORDINGRULES_JSON_OUT} | jq -cr '.[]' | while read item; - do - record=$(jq -r '.record' <<< "$item") - expr=$(jq -r '.expr' <<< "$item") - #expr=${expr//\"/\\\"} - expr=$(echo "${expr}" | tr -d " ") - querycmd="${query} $(printf -- "--data-urlencode query=%s" ${expr})" - echo -e "\n# TYPE ${record} untyped" >> ${TIME_SERIES_OUT} - ${querycmd} | jq -r '.data.result' | jq -cr '.[]' | while read result; - do - vec="${record}" - metric=$(jq -r '.metric | to_entries | map("\(.key)=\"\(.value | tostring)\"") | .[]' <<< "$result") - metric=$(echo "${metric}" | sed ':a;N;$!ba;s/\n/,/g') - vec="${vec}{${metric}}" - timestamp=$(jq -r '.value[0]' <<< "$result") - value=$(jq -r '.value[1]' <<< "$result") - timestamp=$(echo "${timestamp} * 1000" | bc) - timestamp=${timestamp%.*} - echo "${vec} ${value} ${timestamp}" >> ${TIME_SERIES_OUT} - done - done + echo "generating recordingrules..." + query="curl --fail --silent -G http://localhost:9090/api/v1/query" + cat ${RECORDINGRULES_JSON_OUT} | jq -cr '.[]' | while read item; do + record=$(jq -r '.record' <<<"$item") + expr=$(jq -r '.expr' <<<"$item") + #expr=${expr//\"/\\\"} + expr=$(echo "${expr}" | tr -d " ") + querycmd="${query} $(printf -- "--data-urlencode query=%s" ${expr})" + echo -e "\n# TYPE ${record} untyped" >>${TIME_SERIES_OUT} + ${querycmd} | jq -r '.data.result' | jq -cr '.[]' | while read result; do + vec="${record}" + metric=$(jq -r '.metric | to_entries | map("\(.key)=\"\(.value | tostring)\"") | .[]' <<<"$result") + metric=$(echo "${metric}" | sed ':a;N;$!ba;s/\n/,/g') + vec="${vec}{${metric}}" + timestamp=$(jq -r '.value[0]' <<<"$result") + value=$(jq -r '.value[1]' <<<"$result") + timestamp=$(echo "${timestamp} * 1000" | bc) + timestamp=${timestamp%.*} + echo "${vec} ${value} ${timestamp}" >>${TIME_SERIES_OUT} + done + done } function generate_timeseries() { - kubectl port-forward -n openshift-monitoring prometheus-k8s-0 9090 > /dev/null & - sleep 10 - generate_metrics - generate_recordingrules - jobs -p | xargs -r kill + kubectl port-forward -n openshift-monitoring prometheus-k8s-0 9090 >/dev/null & + sleep 10 + generate_metrics + generate_recordingrules + jobs -p | xargs -r kill } - #get_metrics_list #get_recordingrules_list oc login ${OC_CLUSTER_URL} --token ${OC_TOKEN} --insecure-skip-tls-verify=true diff --git a/tools/simulator/metrics-collector/setup-metrics-collector.sh b/tools/simulator/metrics-collector/setup-metrics-collector.sh index 9b0129137..6db913727 100755 --- a/tools/simulator/metrics-collector/setup-metrics-collector.sh +++ b/tools/simulator/metrics-collector/setup-metrics-collector.sh @@ -2,157 +2,162 @@ # Copyright (c) 2021 Red Hat, Inc. # Copyright Contributors to the Open Cluster Management project -WORK_DIR="$(cd "$(dirname "$0")" ; pwd -P)" +WORK_DIR="$( + cd "$(dirname "$0")" + pwd -P +)" # Create bin directory and add it to PATH mkdir -p ${WORK_DIR}/bin export PATH=${PATH}:${WORK_DIR}/bin -if ! command -v jq &> /dev/null; then - if [[ "$(uname)" == "Linux" ]]; then - curl -o jq -L https://github.com/stedolan/jq/releases/download/jq-1.6/jq-linux64 - elif [[ "$(uname)" == "Darwin" ]]; then - curl -o jq -L https://github.com/stedolan/jq/releases/download/jq-1.6/jq-osx-amd64 - fi - chmod +x ./jq - chmod +x ./jq && mv ./jq ${WORK_DIR}/bin/jq +if ! command -v jq &>/dev/null; then + if [[ "$(uname)" == "Linux" ]]; then + curl -o jq -L https://github.com/stedolan/jq/releases/download/jq-1.6/jq-linux64 + elif [[ "$(uname)" == "Darwin" ]]; then + curl -o jq -L https://github.com/stedolan/jq/releases/download/jq-1.6/jq-osx-amd64 + fi + chmod +x ./jq + chmod +x ./jq && mv ./jq ${WORK_DIR}/bin/jq fi KUBECTL="kubectl" -if ! command -v kubectl &> /dev/null; then - if command -v oc &> /dev/null; then - KUBECTL="oc" - else - echo "This script will install kubectl (https://kubernetes.io/docs/tasks/tools/install-kubectl/) on your machine" - if [[ "$(uname)" == "Linux" ]]; then - curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.21.0/bin/linux/amd64/kubectl - elif [[ "$(uname)" == "Darwin" ]]; then - curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.21.0/bin/darwin/amd64/kubectl - fi - chmod +x ./kubectl && mv ./kubectl ${WORK_DIR}/bin/kubectl +if ! command -v kubectl &>/dev/null; then + if command -v oc &>/dev/null; then + KUBECTL="oc" + else + echo "This script will install kubectl (https://kubernetes.io/docs/tasks/tools/install-kubectl/) on your machine" + if [[ "$(uname)" == "Linux" ]]; then + curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.21.0/bin/linux/amd64/kubectl + elif [[ "$(uname)" == "Darwin" ]]; then + curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.21.0/bin/darwin/amd64/kubectl fi + chmod +x ./kubectl && mv ./kubectl ${WORK_DIR}/bin/kubectl + fi fi SED_COMMAND='sed -i' if [[ "$(uname)" == "Darwin" ]]; then - SED_COMMAND='sed -i -e' + SED_COMMAND='sed -i -e' fi function usage() { - echo "${0} -n NUMBERS [-t METRICS_DATA_TYPE] [-w WORKERS] [-m MANAGED_CLUSTER_PREFIX]" - echo '' - # shellcheck disable=SC2016 - echo ' -n: Specifies the total number of simulated metrics collectors, required' - # shellcheck disable=SC2016 - echo ' -t: Specifies the data type of metrics data source, the default value is "NON_SNO", it also can be "SNO".' - # shellcheck disable=SC2016 - echo ' -w: Specifies the worker threads for each simulated metrics collector, optional, the default value is "1".' - # shellcheck disable=SC2016 - echo ' -m: Specifies the prefix for the simulated managedcluster name, optional, the default value is "simulated-managed-cluster".' - echo '' + echo "${0} -n NUMBERS [-t METRICS_DATA_TYPE] [-w WORKERS] [-m MANAGED_CLUSTER_PREFIX]" + echo '' + # shellcheck disable=SC2016 + echo ' -n: Specifies the total number of simulated metrics collectors, required' + # shellcheck disable=SC2016 + echo ' -t: Specifies the data type of metrics data source, the default value is "NON_SNO", it also can be "SNO".' + # shellcheck disable=SC2016 + echo ' -w: Specifies the worker threads for each simulated metrics collector, optional, the default value is "1".' + # shellcheck disable=SC2016 + echo ' -m: Specifies the prefix for the simulated managedcluster name, optional, the default value is "simulated-managed-cluster".' + echo '' } -WORKERS=1 # default worker threads for each simulated metrics collector -METRICS_DATA_TYPE="NON_SNO" # default metrics data source type +WORKERS=1 # default worker threads for each simulated metrics collector +METRICS_DATA_TYPE="NON_SNO" # default metrics data source type MANAGED_CLUSTER_PREFIX="simulated-managed-cluster" # default managedccluster name prefix # Allow command-line args to override the defaults. while getopts ":n:t:w:m:h" opt; do - case ${opt} in - n) - NUMBERS=${OPTARG} - ;; - t) - METRICS_DATA_TYPE=${OPTARG} - ;; - w) - WORKERS=${OPTARG} - ;; - m) - MANAGED_CLUSTER_PREFIX=${OPTARG} - ;; - h) - usage - exit 0 - ;; - \?) - echo "Invalid option: -${OPTARG}" >&2 - usage - exit 1 - ;; - esac + case ${opt} in + n) + NUMBERS=${OPTARG} + ;; + t) + METRICS_DATA_TYPE=${OPTARG} + ;; + w) + WORKERS=${OPTARG} + ;; + m) + MANAGED_CLUSTER_PREFIX=${OPTARG} + ;; + h) + usage + exit 0 + ;; + \?) + echo "Invalid option: -${OPTARG}" >&2 + usage + exit 1 + ;; + esac done -if [[ -z "${NUMBERS}" ]]; then - echo "Error: NUMBERS (-n) must be specified!" - usage - exit 1 +if [[ -z ${NUMBERS} ]]; then + echo "Error: NUMBERS (-n) must be specified!" + usage + exit 1 fi re='^[0-9]+$' -if ! [[ ${NUMBERS} =~ ${re} ]] ; then - echo "error: arguments <${NUMBERS}> is not a number" >&2; exit 1 +if ! [[ ${NUMBERS} =~ ${re} ]]; then + echo "error: arguments <${NUMBERS}> is not a number" >&2 + exit 1 fi -if [[ ${METRICS_DATA_TYPE} != "SNO" && ${METRICS_DATA_TYPE} != "NON_SNO" ]] ; then - echo "error: arguments <${METRICS_DATA_TYPE}> is not valid, it must be 'SNO' of 'NON_SNO'" >&2; exit 1 +if [[ ${METRICS_DATA_TYPE} != "SNO" && ${METRICS_DATA_TYPE} != "NON_SNO" ]]; then + echo "error: arguments <${METRICS_DATA_TYPE}> is not valid, it must be 'SNO' of 'NON_SNO'" >&2 + exit 1 fi -if ! [[ ${WORKERS} =~ ${re} ]] ; then - echo "error: arguments <${WORKERS}> is not a number" >&2; exit 1 +if ! [[ ${WORKERS} =~ ${re} ]]; then + echo "error: arguments <${WORKERS}> is not a number" >&2 + exit 1 fi OBSERVABILITY_NS="open-cluster-management-addon-observability" # metrics data source image DEFAULT_METRICS_IMAGE="quay.io/ocm-observability/metrics-data:2.4.0" -if [[ ${METRICS_DATA_TYPE} == "SNO" ]] ; then - DEFAULT_METRICS_IMAGE="quay.io/ocm-observability/metrics-data:2.4.0-sno" +if [[ ${METRICS_DATA_TYPE} == "SNO" ]]; then + DEFAULT_METRICS_IMAGE="quay.io/ocm-observability/metrics-data:2.4.0-sno" fi METRICS_IMAGE="${METRICS_IMAGE:-$DEFAULT_METRICS_IMAGE}" -for i in $(seq 1 ${NUMBERS}) -do - cluster_name=${MANAGED_CLUSTER_PREFIX}-${i} - ${KUBECTL} create ns ${cluster_name} - - # create ca/sa/rolebinding for metrics collector - ${KUBECTL} get configmap metrics-collector-serving-certs-ca-bundle -n ${OBSERVABILITY_NS} -o json | jq 'del(.metadata.namespace,.metadata.resourceVersion,.metadata.uid) | .metadata.creationTimestamp=null' | ${KUBECTL} apply -n ${cluster_name} -f - - ${KUBECTL} get secret observability-controller-open-cluster-management.io-observability-signer-client-cert -n ${OBSERVABILITY_NS} -o json | jq 'del(.metadata.namespace,.metadata.resourceVersion,.metadata.uid) | .metadata.creationTimestamp=null' | ${KUBECTL} apply -n ${cluster_name} -f - - ${KUBECTL} get secret observability-managed-cluster-certs -n ${OBSERVABILITY_NS} -o json | jq 'del(.metadata.namespace,.metadata.resourceVersion,.metadata.uid) | .metadata.creationTimestamp=null' | ${KUBECTL} apply -n ${cluster_name} -f - - ${KUBECTL} get sa endpoint-observability-operator-sa -n ${OBSERVABILITY_NS} -o json | jq 'del(.metadata.namespace,.metadata.resourceVersion,.metadata.uid) | .metadata.creationTimestamp=null' | ${KUBECTL} apply -n ${cluster_name} -f - - ${KUBECTL} -n ${cluster_name} patch secret observability-managed-cluster-certs --type='json' -p='[{"op": "replace", "path": "/metadata/ownerReferences", "value": []}]' - ${KUBECTL} -n ${cluster_name} patch sa endpoint-observability-operator-sa --type='json' -p='[{"op": "replace", "path": "/metadata/ownerReferences", "value": []}]' - - # deploy metrics collector deployment to cluster ns - deploy_yaml_file=${cluster_name}-metrics-collector-deployment.json - ${KUBECTL} get deploy metrics-collector-deployment -n ${OBSERVABILITY_NS} -o json > ${deploy_yaml_file} - - # replace namespace, cluster and clusterID. Insert --simulated-timeseries-file - uuid=$(cat /proc/sys/kernel/random/uuid) - jq \ - --arg cluster_name ${cluster_name} \ - --arg cluster "--label=\"cluster=${cluster_name}\"" \ - --arg clusterID "--label=\"clusterID=${uuid}\"" \ - --arg workerNum "--worker-number=${WORKERS}" \ - --arg file "--simulated-timeseries-file=/metrics-volume/timeseries.txt" \ - '.metadata.namespace=$cluster_name | .spec.template.spec.containers[0].command[.spec.template.spec.containers[0].command|length] |= . + $cluster |.spec.template.spec.containers[0].command[.spec.template.spec.containers[0].command|length] |= . + $clusterID | .spec.template.spec.containers[0].command[.spec.template.spec.containers[0].command|length] |= . + $file | .spec.template.spec.containers[0].command[.spec.template.spec.containers[0].command|length] |= . + $workerNum' ${deploy_yaml_file} > ${deploy_yaml_file}.tmp && mv ${deploy_yaml_file}.tmp ${deploy_yaml_file} - - # insert metrics initContainer - jq \ - --argjson init '{"initContainers": [{"command":["sh","-c","cp /tmp/timeseries.txt /metrics-volume"],"image":"'${METRICS_IMAGE}'","imagePullPolicy":"IfNotPresent","name":"init-metrics","volumeMounts":[{"mountPath":"/metrics-volume","name":"metrics-volume"}]}]}' \ - --argjson emptydir '{"emptyDir": {}, "name": "metrics-volume"}' \ - --argjson metricsdir '{"mountPath": "/metrics-volume","name": "metrics-volume"}' \ - '.spec.template.spec += $init | .spec.template.spec.volumes += [$emptydir] | .spec.template.spec.containers[0].volumeMounts += [$metricsdir]' ${deploy_yaml_file} > ${deploy_yaml_file}.tmp && mv ${deploy_yaml_file}.tmp ${deploy_yaml_file} - - cat "${deploy_yaml_file}" | ${KUBECTL} -n ${cluster_name} apply -f - - rm -f "${deploy_yaml_file}" "${deploy_yaml_file}".tmp - ${KUBECTL} -n ${cluster_name} patch deploy metrics-collector-deployment --type='json' -p='[{"op": "replace", "path": "/metadata/ownerReferences", "value": []}]' - ${KUBECTL} -n ${cluster_name} patch deploy metrics-collector-deployment --type='json' -p='[{"op": "remove", "path": "/spec/template/spec/containers/0/resources"}]' - - # deploy ClusterRoleBinding for read metrics from OCP prometheus - rolebinding_yaml_file=${cluster_name}-metrics-collector-view.yaml - cp -rf metrics-collector-view.yaml "$rolebinding_yaml_file" - ${SED_COMMAND} "s~__CLUSTER_NAME__~${cluster_name}~g" "${rolebinding_yaml_file}" - cat "${rolebinding_yaml_file}" | ${KUBECTL} -n ${cluster_name} apply -f - - rm -f "${rolebinding_yaml_file}" +for i in $(seq 1 ${NUMBERS}); do + cluster_name=${MANAGED_CLUSTER_PREFIX}-${i} + ${KUBECTL} create ns ${cluster_name} + + # create ca/sa/rolebinding for metrics collector + ${KUBECTL} get configmap metrics-collector-serving-certs-ca-bundle -n ${OBSERVABILITY_NS} -o json | jq 'del(.metadata.namespace,.metadata.resourceVersion,.metadata.uid) | .metadata.creationTimestamp=null' | ${KUBECTL} apply -n ${cluster_name} -f - + ${KUBECTL} get secret observability-controller-open-cluster-management.io-observability-signer-client-cert -n ${OBSERVABILITY_NS} -o json | jq 'del(.metadata.namespace,.metadata.resourceVersion,.metadata.uid) | .metadata.creationTimestamp=null' | ${KUBECTL} apply -n ${cluster_name} -f - + ${KUBECTL} get secret observability-managed-cluster-certs -n ${OBSERVABILITY_NS} -o json | jq 'del(.metadata.namespace,.metadata.resourceVersion,.metadata.uid) | .metadata.creationTimestamp=null' | ${KUBECTL} apply -n ${cluster_name} -f - + ${KUBECTL} get sa endpoint-observability-operator-sa -n ${OBSERVABILITY_NS} -o json | jq 'del(.metadata.namespace,.metadata.resourceVersion,.metadata.uid) | .metadata.creationTimestamp=null' | ${KUBECTL} apply -n ${cluster_name} -f - + ${KUBECTL} -n ${cluster_name} patch secret observability-managed-cluster-certs --type='json' -p='[{"op": "replace", "path": "/metadata/ownerReferences", "value": []}]' + ${KUBECTL} -n ${cluster_name} patch sa endpoint-observability-operator-sa --type='json' -p='[{"op": "replace", "path": "/metadata/ownerReferences", "value": []}]' + + # deploy metrics collector deployment to cluster ns + deploy_yaml_file=${cluster_name}-metrics-collector-deployment.json + ${KUBECTL} get deploy metrics-collector-deployment -n ${OBSERVABILITY_NS} -o json >${deploy_yaml_file} + + # replace namespace, cluster and clusterID. Insert --simulated-timeseries-file + uuid=$(cat /proc/sys/kernel/random/uuid) + jq \ + --arg cluster_name ${cluster_name} \ + --arg cluster "--label=\"cluster=${cluster_name}\"" \ + --arg clusterID "--label=\"clusterID=${uuid}\"" \ + --arg workerNum "--worker-number=${WORKERS}" \ + --arg file "--simulated-timeseries-file=/metrics-volume/timeseries.txt" \ + '.metadata.namespace=$cluster_name | .spec.template.spec.containers[0].command[.spec.template.spec.containers[0].command|length] |= . + $cluster |.spec.template.spec.containers[0].command[.spec.template.spec.containers[0].command|length] |= . + $clusterID | .spec.template.spec.containers[0].command[.spec.template.spec.containers[0].command|length] |= . + $file | .spec.template.spec.containers[0].command[.spec.template.spec.containers[0].command|length] |= . + $workerNum' ${deploy_yaml_file} >${deploy_yaml_file}.tmp && mv ${deploy_yaml_file}.tmp ${deploy_yaml_file} + + # insert metrics initContainer + jq \ + --argjson init '{"initContainers": [{"command":["sh","-c","cp /tmp/timeseries.txt /metrics-volume"],"image":"'${METRICS_IMAGE}'","imagePullPolicy":"IfNotPresent","name":"init-metrics","volumeMounts":[{"mountPath":"/metrics-volume","name":"metrics-volume"}]}]}' \ + --argjson emptydir '{"emptyDir": {}, "name": "metrics-volume"}' \ + --argjson metricsdir '{"mountPath": "/metrics-volume","name": "metrics-volume"}' \ + '.spec.template.spec += $init | .spec.template.spec.volumes += [$emptydir] | .spec.template.spec.containers[0].volumeMounts += [$metricsdir]' ${deploy_yaml_file} >${deploy_yaml_file}.tmp && mv ${deploy_yaml_file}.tmp ${deploy_yaml_file} + + cat "${deploy_yaml_file}" | ${KUBECTL} -n ${cluster_name} apply -f - + rm -f "${deploy_yaml_file}" "${deploy_yaml_file}".tmp + ${KUBECTL} -n ${cluster_name} patch deploy metrics-collector-deployment --type='json' -p='[{"op": "replace", "path": "/metadata/ownerReferences", "value": []}]' + ${KUBECTL} -n ${cluster_name} patch deploy metrics-collector-deployment --type='json' -p='[{"op": "remove", "path": "/spec/template/spec/containers/0/resources"}]' + + # deploy ClusterRoleBinding for read metrics from OCP prometheus + rolebinding_yaml_file=${cluster_name}-metrics-collector-view.yaml + cp -rf metrics-collector-view.yaml "$rolebinding_yaml_file" + ${SED_COMMAND} "s~__CLUSTER_NAME__~${cluster_name}~g" "${rolebinding_yaml_file}" + cat "${rolebinding_yaml_file}" | ${KUBECTL} -n ${cluster_name} apply -f - + rm -f "${rolebinding_yaml_file}" done diff --git a/tools/switch-to-grafana-admin.sh b/tools/switch-to-grafana-admin.sh index d425e177f..e371df5fd 100755 --- a/tools/switch-to-grafana-admin.sh +++ b/tools/switch-to-grafana-admin.sh @@ -4,18 +4,15 @@ obs_namespace='open-cluster-management-observability' -if command -v python &> /dev/null -then - PYTHON_CMD="python" -elif command -v python2 &> /dev/null -then - PYTHON_CMD="python2" -elif command -v python3 &> /dev/null -then - PYTHON_CMD="python3" +if command -v python &>/dev/null; then + PYTHON_CMD="python" +elif command -v python2 &>/dev/null; then + PYTHON_CMD="python2" +elif command -v python3 &>/dev/null; then + PYTHON_CMD="python3" else - echo "Failed to found python command, please install firstly" - exit 1 + echo "Failed to found python command, please install firstly" + exit 1 fi usage() { @@ -39,72 +36,71 @@ start() { fi user_name="$1" - while [[ $# -gt 0 ]] - do - key="$1" - case $key in - -h|--help) - usage - ;; - - -n|--namespace) - obs_namespace="$2" - shift - shift - ;; + while [[ $# -gt 0 ]]; do + key="$1" + case $key in + -h | --help) + usage + ;; + + -n | --namespace) + obs_namespace="$2" + shift + shift + ;; *) - shift - ;; - esac + shift + ;; + esac done # if username contains the number sign '#', we need to replace it with '%23' # due to use it in URL parameters username_no_num_sign=$user_name if [[ $user_name == *"#"* ]]; then - username_no_num_sign="${user_name//#/%23}" + username_no_num_sign="${user_name//#/%23}" fi - podName=`kubectl get pods -n "$obs_namespace" -l app=multicluster-observability-grafana-dev --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}'` + podName=$(kubectl get pods -n "$obs_namespace" -l app=multicluster-observability-grafana-dev --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}') if [ $? -ne 0 ] || [ -z "$podName" ]; then - echo "Failed to get grafana pod name, please check your grafana-dev deployment" - exit 1 + echo "Failed to get grafana pod name, please check your grafana-dev deployment" + exit 1 fi curlCMD="kubectl exec -it -n "$obs_namespace" $podName -c grafana-dashboard-loader -- /usr/bin/curl" XForwardedUser="WHAT_YOU_ARE_DOING_IS_VOIDING_SUPPORT_0000000000000000000000000000000000000000000000000000000000000000" - userID=`$curlCMD -s -X GET -H "Content-Type: application/json" -H "X-Forwarded-User: $XForwardedUser" 127.0.0.1:3001/api/users/lookup?loginOrEmail=$username_no_num_sign | $PYTHON_CMD -c "import sys, json; print(json.load(sys.stdin)['id'])" 2>/dev/null` + userID=$($curlCMD -s -X GET -H "Content-Type: application/json" -H "X-Forwarded-User: $XForwardedUser" 127.0.0.1:3001/api/users/lookup?loginOrEmail=$username_no_num_sign | $PYTHON_CMD -c "import sys, json; print(json.load(sys.stdin)['id'])" 2>/dev/null) if [ $? -ne 0 ]; then - echo "Failed to fetch user ID, please check your user name" - exit 1 + echo "Failed to fetch user ID, please check your user name" + exit 1 fi - - orgID=`$curlCMD -s -X GET -H "Content-Type: application/json" -H "X-Forwarded-User:$XForwardedUser" 127.0.0.1:3001/api/users/lookup?loginOrEmail=$username_no_num_sign | $PYTHON_CMD -c "import sys, json; print(json.load(sys.stdin)['orgId'])" 2>/dev/null` + + orgID=$($curlCMD -s -X GET -H "Content-Type: application/json" -H "X-Forwarded-User:$XForwardedUser" 127.0.0.1:3001/api/users/lookup?loginOrEmail=$username_no_num_sign | $PYTHON_CMD -c "import sys, json; print(json.load(sys.stdin)['orgId'])" 2>/dev/null) if [ $? -ne 0 ]; then - echo "Failed to fetch organization ID, please check your user name" - exit 1 + echo "Failed to fetch organization ID, please check your user name" + exit 1 fi - $curlCMD -s -X DELETE -H "Content-Type: application/json" -H "X-Forwarded-User:$XForwardedUser" 127.0.0.1:3001/api/orgs/$orgID/users/$userID > /dev/null + $curlCMD -s -X DELETE -H "Content-Type: application/json" -H "X-Forwarded-User:$XForwardedUser" 127.0.0.1:3001/api/orgs/$orgID/users/$userID >/dev/null if [ $? -ne 0 ]; then - echo "Failed to delete user <$user_name>" - exit 1 + echo "Failed to delete user <$user_name>" + exit 1 fi - $curlCMD -s -X POST -H "Content-Type: application/json" -d "{\"loginOrEmail\":\"$user_name\", \"role\": \"Admin\"}" -H "X-Forwarded-User:$XForwardedUser" 127.0.0.1:3001/api/orgs/$orgID/users > /dev/null + $curlCMD -s -X POST -H "Content-Type: application/json" -d "{\"loginOrEmail\":\"$user_name\", \"role\": \"Admin\"}" -H "X-Forwarded-User:$XForwardedUser" 127.0.0.1:3001/api/orgs/$orgID/users >/dev/null if [ $? -ne 0 ]; then - echo "Failed to switch the user <$user_name> to be grafana admin" - exit 1 + echo "Failed to switch the user <$user_name> to be grafana admin" + exit 1 fi echo "User <$user_name> switched to be grafana admin" # disable getting start -# kubectl exec -it -n "$obs_namespace" $podName -c grafana-dev -- sqlite3 /var/lib/grafana/grafana.db "update user set help_flags1=1 where id=$userID;" > /dev/null -# if [ $? -ne 0 ]; then -# echo "Failed to disable getting start for the user <$user_name>" -# exit 1 -# fi + # kubectl exec -it -n "$obs_namespace" $podName -c grafana-dev -- sqlite3 /var/lib/grafana/grafana.db "update user set help_flags1=1 where id=$userID;" > /dev/null + # if [ $? -ne 0 ]; then + # echo "Failed to disable getting start for the user <$user_name>" + # exit 1 + # fi }