diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml
index 9db2e7d2..6515f8ea 100644
--- a/.github/workflows/lint.yaml
+++ b/.github/workflows/lint.yaml
@@ -38,7 +38,7 @@ jobs:
- name: Run golangci-lint
run: |
- curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b . v1.52.2
+ curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b . v1.54.2
./golangci-lint run --sort-results
codespell:
diff --git a/.golangci.yaml b/.golangci.yaml
index c79f1bed..8ba4a2ae 100644
--- a/.golangci.yaml
+++ b/.golangci.yaml
@@ -37,12 +37,15 @@ linters-settings:
goimports:
local-prefixes: github.com/flant/
depguard:
- list-type: blacklist
- include-go-root: true
- packages:
- - github.com/evanphx/json-patch
- packages-with-error-message:
- - github.com/evanphx/json-patch: "The 'github.com/evanphx/json-patch' package is superseded. Use pkg/utils/jsonpatch.go instead."
+ rules:
+ Main:
+ files:
+ - $all
+ deny:
+ - pkg: "github.com/evanphx/json-patch"
+ desc: "The 'github.com/evanphx/json-patch' package is superseded. Use pkg/utils/jsonpatch.go instead."
+ - pkg: "gopkg.in/satori/go.uuid.v1"
+ desc: "Use https://github.com/gofrs/uuid instead. Satori/go.uuid is no longer maintained and has critical vulnerabilities."
issues:
exclude:
# Using underscores is a common practice, refactor in the future
diff --git a/cmd/addon-operator/main.go b/cmd/addon-operator/main.go
index fd515d05..a8baf5d7 100644
--- a/cmd/addon-operator/main.go
+++ b/cmd/addon-operator/main.go
@@ -7,10 +7,12 @@ import (
"os"
"time"
+ log "github.com/sirupsen/logrus"
"gopkg.in/alecthomas/kingpin.v2"
addon_operator "github.com/flant/addon-operator/pkg/addon-operator"
"github.com/flant/addon-operator/pkg/app"
+ "github.com/flant/addon-operator/pkg/kube_config_manager/backend/configmap"
"github.com/flant/addon-operator/pkg/utils/stdliblogtologrus"
"github.com/flant/kube-client/klogtologrus"
sh_app "github.com/flant/shell-operator/pkg/app"
@@ -46,14 +48,23 @@ func main() {
rand.Seed(time.Now().UnixNano())
operator := addon_operator.NewAddonOperator(context.Background())
- err := operator.Start()
+
+ bk := configmap.New(log.StandardLogger(), operator.KubeClient(), app.Namespace, app.ConfigMapName)
+ operator.SetupKubeConfigManager(bk)
+
+ err := operator.Setup()
+ if err != nil {
+ os.Exit(1)
+ }
+
+ err = operator.Start()
if err != nil {
os.Exit(1)
}
// Block action by waiting signals from OS.
utils_signal.WaitForProcessInterruption(func() {
- operator.Shutdown()
+ operator.Stop()
os.Exit(1)
})
diff --git a/go.mod b/go.mod
index 52f17628..0899ffd0 100644
--- a/go.mod
+++ b/go.mod
@@ -4,19 +4,21 @@ go 1.19
require (
github.com/davecgh/go-spew v1.1.1
- github.com/flant/kube-client v0.26.1
- github.com/flant/shell-operator v0.0.0-20231013105726-aa38dfcd70d1
+ github.com/distribution/distribution/v3 v3.0.0-20220526142353-ffbd94cbe269
+ github.com/flant/kube-client v1.0.1
+ github.com/flant/shell-operator v1.4.1
github.com/go-chi/chi/v5 v5.0.10
github.com/go-openapi/loads v0.19.5
github.com/go-openapi/spec v0.19.8
github.com/go-openapi/strfmt v0.19.5
- github.com/go-openapi/swag v0.19.14
+ github.com/go-openapi/swag v0.21.1
github.com/go-openapi/validate v0.19.12
+ github.com/gofrs/uuid/v5 v5.0.0
github.com/hashicorp/go-multierror v1.1.1
github.com/kennygrant/sanitize v1.2.4
- github.com/onsi/gomega v1.27.10
+ github.com/onsi/gomega v1.28.1
github.com/pkg/errors v0.9.1
- github.com/prometheus/client_golang v1.16.0
+ github.com/prometheus/client_golang v1.17.0
github.com/segmentio/go-camelcase v0.0.0-20160726192923-7085f1e3c734
github.com/sirupsen/logrus v1.9.3
github.com/stretchr/testify v1.8.4
@@ -24,20 +26,17 @@ require (
github.com/tidwall/sjson v1.2.5
go.uber.org/goleak v1.2.0
gopkg.in/alecthomas/kingpin.v2 v2.2.6
- gopkg.in/satori/go.uuid.v1 v1.2.0
gopkg.in/yaml.v3 v3.0.1
helm.sh/helm/v3 v3.10.3
- k8s.io/api v0.25.5
- k8s.io/apimachinery v0.25.5
+ k8s.io/api v0.26.9
+ k8s.io/apimachinery v0.26.9
k8s.io/cli-runtime v0.25.5
- k8s.io/client-go v0.25.5
- k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed
+ k8s.io/client-go v0.26.9
+ k8s.io/utils v0.0.0-20221107191617-1a15be271d1d
sigs.k8s.io/yaml v1.3.0
)
require (
- cloud.google.com/go/compute v1.19.1 // indirect
- cloud.google.com/go/compute/metadata v0.2.3 // indirect
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
github.com/BurntSushi/toml v1.1.0 // indirect
github.com/MakeNowJust/heredoc v1.0.0 // indirect
@@ -45,8 +44,6 @@ require (
github.com/Masterminds/semver/v3 v3.1.1 // indirect
github.com/Masterminds/sprig/v3 v3.2.2 // indirect
github.com/Masterminds/squirrel v1.5.3 // indirect
- github.com/PuerkitoBio/purell v1.1.1 // indirect
- github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect
github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 // indirect
@@ -62,11 +59,10 @@ require (
github.com/docker/go-connections v0.4.0 // indirect
github.com/docker/go-metrics v0.0.1 // indirect
github.com/docker/go-units v0.4.0 // indirect
- github.com/emicklei/go-restful/v3 v3.8.0 // indirect
+ github.com/emicklei/go-restful/v3 v3.9.0 // indirect
github.com/evanphx/json-patch v5.6.0+incompatible // indirect
github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect
github.com/fatih/color v1.13.0 // indirect
- github.com/felixge/httpsnoop v1.0.3 // indirect
github.com/flant/libjq-go v1.6.3-0.20201126171326-c46a40ff22ee // indirect
github.com/go-errors/errors v1.0.1 // indirect
github.com/go-gorp/gorp/v3 v3.0.2 // indirect
@@ -74,7 +70,7 @@ require (
github.com/go-openapi/analysis v0.19.10 // indirect
github.com/go-openapi/errors v0.19.7 // indirect
github.com/go-openapi/jsonpointer v0.19.5 // indirect
- github.com/go-openapi/jsonreference v0.19.5 // indirect
+ github.com/go-openapi/jsonreference v0.20.0 // indirect
github.com/go-openapi/runtime v0.19.16 // indirect
github.com/go-stack/stack v1.8.0 // indirect
github.com/gobwas/glob v0.2.3 // indirect
@@ -82,7 +78,7 @@ require (
github.com/golang/protobuf v1.5.3 // indirect
github.com/google/btree v1.0.1 // indirect
github.com/google/gnostic v0.5.7-v3refs // indirect
- github.com/google/go-cmp v0.5.9 // indirect
+ github.com/google/go-cmp v0.6.0 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
github.com/google/uuid v1.3.0 // indirect
@@ -92,7 +88,7 @@ require (
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/huandu/xstrings v1.3.2 // indirect
github.com/imdario/mergo v0.3.15 // indirect
- github.com/inconshreveable/mousetrap v1.0.0 // indirect
+ github.com/inconshreveable/mousetrap v1.0.1 // indirect
github.com/jmoiron/sqlx v1.3.5 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
@@ -101,7 +97,7 @@ require (
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect
github.com/lib/pq v1.10.6 // indirect
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
- github.com/mailru/easyjson v0.7.6 // indirect
+ github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-colorable v0.1.12 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/mattn/go-runewidth v0.0.9 // indirect
@@ -112,7 +108,7 @@ require (
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/moby/locker v1.0.1 // indirect
github.com/moby/spdystream v0.2.0 // indirect
- github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect
+ github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
@@ -122,14 +118,14 @@ require (
github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 // indirect
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
- github.com/prometheus/client_model v0.3.0 // indirect
- github.com/prometheus/common v0.42.0 // indirect
- github.com/prometheus/procfs v0.10.1 // indirect
+ github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 // indirect
+ github.com/prometheus/common v0.44.0 // indirect
+ github.com/prometheus/procfs v0.11.1 // indirect
github.com/rubenv/sql-migrate v1.1.2 // indirect
github.com/russross/blackfriday v1.5.2 // indirect
github.com/shopspring/decimal v1.2.0 // indirect
github.com/spf13/cast v1.4.1 // indirect
- github.com/spf13/cobra v1.5.0 // indirect
+ github.com/spf13/cobra v1.6.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.0 // indirect
@@ -137,13 +133,14 @@ require (
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
github.com/xlab/treeprint v1.1.0 // indirect
- go.etcd.io/etcd/api/v3 v3.5.4 // indirect
+ go.etcd.io/etcd/api/v3 v3.5.5 // indirect
go.mongodb.org/mongo-driver v1.5.4 // indirect
+ go.opencensus.io v0.24.0 // indirect
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 // indirect
golang.org/x/crypto v0.14.0 // indirect
golang.org/x/net v0.17.0 // indirect
- golang.org/x/oauth2 v0.7.0 // indirect
- golang.org/x/sync v0.2.0 // indirect
+ golang.org/x/oauth2 v0.8.0 // indirect
+ golang.org/x/sync v0.3.0 // indirect
golang.org/x/sys v0.13.0 // indirect
golang.org/x/term v0.13.0 // indirect
golang.org/x/text v0.13.0 // indirect
@@ -151,15 +148,15 @@ require (
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
google.golang.org/grpc v1.56.3 // indirect
- google.golang.org/protobuf v1.30.0 // indirect
+ google.golang.org/protobuf v1.31.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/robfig/cron.v2 v2.0.0-20150107220207-be2e0b0deed5 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
- k8s.io/apiextensions-apiserver v0.25.4 // indirect
- k8s.io/apiserver v0.25.4 // indirect
- k8s.io/component-base v0.25.5 // indirect
- k8s.io/klog/v2 v2.70.1 // indirect
- k8s.io/kube-openapi v0.0.0-20220803162953-67bda5d908f1 // indirect
+ k8s.io/apiextensions-apiserver v0.26.9 // indirect
+ k8s.io/apiserver v0.26.9 // indirect
+ k8s.io/component-base v0.26.9 // indirect
+ k8s.io/klog/v2 v2.80.1 // indirect
+ k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 // indirect
k8s.io/kubectl v0.25.5 // indirect
oras.land/oras-go v1.2.0 // indirect
sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect
diff --git a/go.sum b/go.sum
index 51ec28c6..1cfe8fa3 100644
--- a/go.sum
+++ b/go.sum
@@ -24,10 +24,6 @@ cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvf
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/compute v1.19.1 h1:am86mquDUgjGNWxiGn+5PGLbmgiWXlE/yNWpIpNvuXY=
-cloud.google.com/go/compute v1.19.1/go.mod h1:6ylj3a05WF8leseCdIf77NK0g1ey+nj5IKd5/kvShxE=
-cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY=
-cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
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/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
@@ -64,9 +60,7 @@ github.com/Masterminds/squirrel v1.5.3/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA4
github.com/Microsoft/go-winio v0.5.2 h1:a9IhgEQBCUEk6QCdml9CiJGhAws+YwffDHEMp1VMrpA=
github.com/Microsoft/hcsshim v0.9.6 h1:VwnDOgLeoi2du6dAznfmspNqTiwczvjv4K7NxuY9jsY=
github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
-github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
-github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d h1:UrqY+r/OJnIp5u0s1SbQ8dVfLCZJsnvazdBP5hS4iRs=
github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM=
@@ -99,6 +93,7 @@ github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd h1:rFt+Y/IK1aEZ
github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b h1:otBG+dV+YK+Soembjv71DPz3uX/V/6MMlSyD9JBQ6kQ=
github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0 h1:nvj0OLI3YqYXer/kZD8Ri1aaunCxIEsOst1BVJswV0o=
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.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chai2010/gettext-go v1.0.2 h1:1Lwwip6Q2QGsAdl/ZKPCwTe9fe0CjlUbqj5bFNSjIRk=
@@ -110,6 +105,7 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk
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/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/containerd/cgroups v1.0.4 h1:jN/mbWBEaz+T1pi5OFtnkQ+8qnmEbAr1Oo1FRm5B0dA=
github.com/containerd/containerd v1.6.18 h1:qZbsLvmyu+Vlty0/Ex5xc0z2YtKpIsb5n45mAMI+2Ns=
github.com/containerd/containerd v1.6.18/go.mod h1:1RdCUu95+gc2v9t3IL+zIlpClSmew7/0YS8O5eQZrOw=
@@ -128,6 +124,7 @@ 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/denisenkom/go-mssqldb v0.9.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
github.com/distribution/distribution/v3 v3.0.0-20220526142353-ffbd94cbe269 h1:hbCT8ZPPMqefiAWD2ZKjn7ypokIGViTvBBg/ExLSdCk=
+github.com/distribution/distribution/v3 v3.0.0-20220526142353-ffbd94cbe269/go.mod h1:28YO/VJk9/64+sTGNuYaBjWxrXTPrj0C0XmgTIOjxX4=
github.com/docker/cli v20.10.17+incompatible h1:eO2KS7ZFeov5UJeaDmIs1NFEDRf32PaqRpvoEkKBy5M=
github.com/docker/cli v20.10.17+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8=
@@ -146,14 +143,15 @@ github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDD
github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1 h1:ZClxb8laGDf5arXfYcAtECDFgAgHklGI8CxgjHnXKJ4=
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153 h1:yUdfgN0XgIJw7foRItutHYUIhlcKzcSf5vDpdhQAKTc=
-github.com/emicklei/go-restful/v3 v3.8.0 h1:eCZ8ulSerjdAiaNpF7GxXIE7ZCMo1moN1qX+S609eVw=
-github.com/emicklei/go-restful/v3 v3.8.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
+github.com/emicklei/go-restful/v3 v3.9.0 h1:XwGDlfxEnQZzuopoqxwSEllNcCOM9DhhFyhFIIGKwxE=
+github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
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/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
+github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U=
github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
@@ -163,15 +161,14 @@ github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5Kwzbycv
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk=
-github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/flant/go-openapi-validate v0.19.12-flant.0 h1:xk6kvc9fHKMgUdB6J7kbpbLR5vJOUzKAK8p3nrD7mDk=
github.com/flant/go-openapi-validate v0.19.12-flant.0/go.mod h1:Rzou8hA/CBw8donlS6WNEUQupNvUZ0waH08tGe6kAQ4=
-github.com/flant/kube-client v0.26.1 h1:QIT/Skmdv5Mpu8OWBzncmZdtlKXDKzkyhte7wlXnbVE=
-github.com/flant/kube-client v0.26.1/go.mod h1:BPNhiy57FgJmnSBXy0l8AwBN6F9SHOfgFgHi3UG2Jrw=
+github.com/flant/kube-client v1.0.1 h1:W2cUtu07VF8eWpdv49FomTJzREBHprkFzZgz/UbVp5A=
+github.com/flant/kube-client v1.0.1/go.mod h1:YVcJ8PxomM0iYsK7nj2I3lmog2D0j/GloJfLYnhjlls=
github.com/flant/libjq-go v1.6.3-0.20201126171326-c46a40ff22ee h1:evii83J+/6QGNvyf6tjQ/p27DPY9iftxIBb37ALJRTg=
github.com/flant/libjq-go v1.6.3-0.20201126171326-c46a40ff22ee/go.mod h1:f+REaGl/+pZR97rbTcwHEka/MAipoQQ2Mc0iQUj4ak0=
-github.com/flant/shell-operator v0.0.0-20231013105726-aa38dfcd70d1 h1:IBVnUuPA4j7NQIiH1AhnE67bSMbCVoM5agrgpyg/PdU=
-github.com/flant/shell-operator v0.0.0-20231013105726-aa38dfcd70d1/go.mod h1:0Sb2td567MG7qRrPMz5Mqx4Y/6JWot/pKJMYFUGlikU=
+github.com/flant/shell-operator v1.4.1 h1:nhgI9izYCzY51sdU+PgVnxYSoPK/VrSzNnrrr9GNUkM=
+github.com/flant/shell-operator v1.4.1/go.mod h1:s5u0p4BtKMQAGoYU7x8qwwN/bD/eiY1gZ50XPGqHA+E=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
@@ -188,7 +185,6 @@ github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2
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-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
@@ -209,8 +205,8 @@ github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34
github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
-github.com/go-openapi/jsonreference v0.19.5 h1:1WJP/wi4OjB4iV8KVbH73rQaoialJrqv8gitZLxGLtM=
-github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg=
+github.com/go-openapi/jsonreference v0.20.0 h1:MYlu0sBgChmCfJxxUKZ8g1cPWFOB37YSZqewK7OKeyA=
+github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo=
github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
github.com/go-openapi/loads v0.19.5 h1:jZVYWawIQiA1NBnHla28ktg6hrcfTHsCE+3QLVRBIls=
github.com/go-openapi/loads v0.19.5/go.mod h1:dswLCAdonkRufe/gSUC3gN8nTSaB9uaS2es0x5/IbjY=
@@ -229,8 +225,8 @@ github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.19.7/go.mod h1:ao+8BpOPyKdpQz3AOJfbeEVpLmWAvlT1IfTe5McPyhY=
github.com/go-openapi/swag v0.19.9/go.mod h1:ao+8BpOPyKdpQz3AOJfbeEVpLmWAvlT1IfTe5McPyhY=
-github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng=
-github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
+github.com/go-openapi/swag v0.21.1 h1:wm0rhTb5z7qpJRHBdPOMuY4QjVUMbF6/kwoYeRAOrKU=
+github.com/go-openapi/swag v0.21.1/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
@@ -272,6 +268,8 @@ 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/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/godror/godror v0.24.2/go.mod h1:wZv/9vPiUib6tkoDl+AZ/QLf5YZgMravZ7jxH2eQWAE=
+github.com/gofrs/uuid/v5 v5.0.0 h1:p544++a97kEL+svbcFbCQVM9KFu0Yo25UoISXGNNH9M=
+github.com/gofrs/uuid/v5 v5.0.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
@@ -327,8 +325,8 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.3/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.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
-github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
+github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
@@ -346,7 +344,7 @@ github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLe
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
-github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE=
+github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
@@ -399,8 +397,9 @@ github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/imdario/mergo v0.3.15 h1:M8XP7IuFNsqUx6VPK2P9OSmsYsI/YFaGil0uD21V3dM=
github.com/imdario/mergo v0.3.15/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
-github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
+github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc=
+github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g=
@@ -458,8 +457,9 @@ github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.7.1/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
-github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA=
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
+github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
+github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/markbates/errx v1.1.0 h1:QDFeR+UP95dO12JgW+tgi2UVfo0V8YBHiUIOaeBPiEI=
github.com/markbates/errx v1.1.0/go.mod h1:PLa46Oex9KNbVDZhKel8v1OT7hD5JZ2eI7AHhA0wswc=
github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE=
@@ -509,8 +509,8 @@ github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQ
github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8=
github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
github.com/moby/sys/mountinfo v0.5.0 h1:2Ks8/r6lopsxWi9m58nlwjaeSzUX9iiL1vj5qB/9ObI=
-github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 h1:dcztxKSvZ4Id8iPpHERQBbIJfabdt4wUm5qy3wOL2Zc=
-github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw=
+github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae h1:O4SWKdcHVCvYqyDV+9CJA1fcDN2L11Bule0iFy3YlAI=
+github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -529,9 +529,9 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
-github.com/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU=
-github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
-github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M=
+github.com/onsi/ginkgo/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4=
+github.com/onsi/gomega v1.28.1 h1:MijcGUbfYuznzK/5R4CPNoUP/9Xvuo20sXfEm6XxoTA=
+github.com/onsi/gomega v1.28.1/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 h1:rc3tiVYb5z54aKaDfakKn0dDjIyPpTtszkjuMzyt7ec=
@@ -558,22 +558,22 @@ github.com/poy/onpar v0.0.0-20190519213022-ee068f8ea4d1/go.mod h1:nSbFQvMj97ZyhF
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.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
-github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8=
-github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc=
+github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q=
+github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY=
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.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
-github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
+github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 h1:v7DLqVdK4VrYkVD5diGdl4sxJurKJEMnODWRJlxV9oM=
+github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
-github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM=
-github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc=
+github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY=
+github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY=
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.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
-github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg=
-github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM=
+github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwaUuI=
+github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
@@ -604,15 +604,14 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
-github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cast v1.4.1 h1:s0hze+J0196ZfEMTs80N7UlFt0BDuQ7Q+JDnHiMWKdA=
github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk=
-github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU=
-github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM=
+github.com/spf13/cobra v1.6.0 h1:42a0n6jwCot1pUmomAp4T7DeMD+20LFv4Q54pxLf2LI=
+github.com/spf13/cobra v1.6.0/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY=
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
@@ -622,13 +621,18 @@ github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag
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.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
+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.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
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.1/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.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
@@ -669,8 +673,8 @@ github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f h1
github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs=
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
-go.etcd.io/etcd/api/v3 v3.5.4 h1:OHVyt3TopwtUQ2GKdd5wu3PmmipR4FTwCqoEjSyRdIc=
-go.etcd.io/etcd/api/v3 v3.5.4/go.mod h1:5GB2vv4A4AOn3yk7MftYGHkUfGtDHnEraIjym4dYz5A=
+go.etcd.io/etcd/api/v3 v3.5.5 h1:BX4JIbQ7hl7+jL+g+2j5UAr0o1bctCm6/Ct+ArBGkf0=
+go.etcd.io/etcd/api/v3 v3.5.5/go.mod h1:KFtNaxGDw4Yx/BA4iPPwevUTAuqcsPxzyX8PHydchN8=
go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ=
go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
@@ -686,6 +690,8 @@ 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.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
+go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
+go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 h1:+FNtrFTmVw0YZGpBGX56XDee331t6JAXeK2bcyhLOOc=
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5/go.mod h1:nmDLcffg48OtT/PSW0Hg7FvpRQsQh5OSqIylirxKC7o=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
@@ -802,8 +808,8 @@ golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ
golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.7.0 h1:qe6s0zUXlPX80/dITx3440hWZ7GwMwgDDyrSGTPJG/g=
-golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4=
+golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8=
+golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE=
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=
@@ -816,8 +822,8 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ
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.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI=
-golang.org/x/sync v0.2.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-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
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=
@@ -958,7 +964,7 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
-golang.org/x/tools v0.9.3 h1:Gn1I8+64MsuTb/HpH+LmQtNas23LhUVr3rYZ0eKuaMM=
+golang.org/x/tools v0.12.0 h1:YW6HUoUmYBpwSgyaGaZq1fHjrBjX1rlpZ54T6mu2kss=
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=
@@ -1057,6 +1063,7 @@ google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAG
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
+google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k=
google.golang.org/grpc v1.56.3 h1:8I4C0Yq1EjstUzUJzpcRVbuYA2mODtEmpWiQoN/b2nc=
google.golang.org/grpc v1.56.3/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
@@ -1071,8 +1078,8 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj
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.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
-google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
+google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
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=
@@ -1087,8 +1094,6 @@ gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/robfig/cron.v2 v2.0.0-20150107220207-be2e0b0deed5 h1:E846t8CnR+lv5nE+VuiKTDG/v1U2stad0QzddfJC7kY=
gopkg.in/robfig/cron.v2 v2.0.0-20150107220207-be2e0b0deed5/go.mod h1:hiOFpYm0ZJbusNj2ywpbrXowU3G8U6GIQzqn2mw1UIE=
-gopkg.in/satori/go.uuid.v1 v1.2.0 h1:AH9uksa7bGe9rluapecRKBCpZvxaBEyu0RepitcD0Hw=
-gopkg.in/satori/go.uuid.v1 v1.2.0/go.mod h1:kjjdhYBBaa5W5DYP+OcVG3fRM6VWu14hqDYST4Zvw+E=
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.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
@@ -1114,29 +1119,28 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
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=
-k8s.io/api v0.25.5 h1:mqyHf7aoaYMpdvO87mqpol+Qnsmo+y09S0PMIXwiZKo=
-k8s.io/api v0.25.5/go.mod h1:RzplZX0Z8rV/WhSTfEvnyd91bBhBQTRWo85qBQwRmb8=
-k8s.io/apiextensions-apiserver v0.25.4 h1:7hu9pF+xikxQuQZ7/30z/qxIPZc2J1lFElPtr7f+B6U=
-k8s.io/apiextensions-apiserver v0.25.4/go.mod h1:bkSGki5YBoZWdn5pWtNIdGvDrrsRWlmnvl9a+tAw5vQ=
-k8s.io/apimachinery v0.25.5 h1:SQomYHvv+aO43qdu3QKRf9YuI0oI8w3RrOQ1qPbAUGY=
-k8s.io/apimachinery v0.25.5/go.mod h1:1S2i1QHkmxc8+EZCIxe/fX5hpldVXk4gvnJInMEb8D4=
-k8s.io/apiserver v0.25.4 h1:/3TwZcgLqX7wUxq7TtXOUqXeBTwXIblVMQdhR5XZ7yo=
-k8s.io/apiserver v0.25.4/go.mod h1:rPcm567XxjOnnd7jedDUnGJGmDGAo+cT6H7QHAN+xV0=
+k8s.io/api v0.26.9 h1:s8Y+G1u2JM55b90+Yo2RVb3PGT/hkWNVPN4idPERxJg=
+k8s.io/api v0.26.9/go.mod h1:W/W4fEWRVzPD36820LlVUQfNBiSbiq0VPWRFJKwzmUg=
+k8s.io/apiextensions-apiserver v0.26.9 h1:aJqWRuBj9i9J6tIDniqUDYM5QCRajTKXK/GO+zEccGQ=
+k8s.io/apiextensions-apiserver v0.26.9/go.mod h1:L1uysxOP2kC1vkZTlHGUlUl5WSpa7e4GHJmGEZY7yLg=
+k8s.io/apimachinery v0.26.9 h1:5yAV9cFR7Z4gIorKcAjWnx4uxtxiFsERwq4Pvmx0CCg=
+k8s.io/apimachinery v0.26.9/go.mod h1:qYzLkrQ9lhrZRh0jNKo2cfvf/R1/kQONnSiyB7NUJU0=
+k8s.io/apiserver v0.26.9 h1:G8D5XIXbhLzqdRY3FajzkKE2lt8hnAW5Vjq67mzEeR8=
+k8s.io/apiserver v0.26.9/go.mod h1:HY2TzNkDgq71jsNLyk61ZoDrpiyvujdY6kHyT9DwvtU=
k8s.io/cli-runtime v0.25.5 h1:5Q37ITYtPtSw2JQcN6EBsdOQBnGvvo/D1g93Da4ceYI=
k8s.io/cli-runtime v0.25.5/go.mod h1:o7lT2rFyfbLrQOzTFsV828OyxKsTE/FmVc3ag1nx0IU=
-k8s.io/client-go v0.25.5 h1:7QWVK0Ph4bLn0UwotPTc2FTgm8shreQXyvXnnHDd8rE=
-k8s.io/client-go v0.25.5/go.mod h1:bOeoaUUdpyz3WDFGo+Xm3nOQFh2KuYXRDwrvbAPtFQA=
-k8s.io/component-base v0.25.5 h1:tVni0kgpceq71MDMBSixp8Y621YGvTS/1zq3RABgX9A=
-k8s.io/component-base v0.25.5/go.mod h1:9J+e9uIUwUOG2x5q5+aaOR0b8QI5OIqwqPAbeODkYpc=
-k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
-k8s.io/klog/v2 v2.70.1 h1:7aaoSdahviPmR+XkS7FyxlkkXs6tHISSG03RxleQAVQ=
-k8s.io/klog/v2 v2.70.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
-k8s.io/kube-openapi v0.0.0-20220803162953-67bda5d908f1 h1:MQ8BAZPZlWk3S9K4a9NCkIFQtZShWqoha7snGixVgEA=
-k8s.io/kube-openapi v0.0.0-20220803162953-67bda5d908f1/go.mod h1:C/N6wCaBHeBHkHUesQOQy2/MZqGgMAFPqGsGQLdbZBU=
+k8s.io/client-go v0.26.9 h1:TGWi/6guEjIgT0Hg871Gsmx0qFuoGyGFjlFedrk7It0=
+k8s.io/client-go v0.26.9/go.mod h1:tU1FZS0bwAmAFyPYpZycUQrQnUMzQ5MHloop7EbX6ow=
+k8s.io/component-base v0.26.9 h1:qQVdQgyEIUe8EUkB3EEuQ9l5sgVlG2KgOB519yWEBGw=
+k8s.io/component-base v0.26.9/go.mod h1:3WmW9lH9tbjpuvpAc22cPF/6C3VxCjMxkOU1j2mpzr8=
+k8s.io/klog/v2 v2.80.1 h1:atnLQ121W371wYYFawwYx1aEY2eUfs4l3J72wtgAwV4=
+k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
+k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 h1:+70TFaan3hfJzs+7VK2o+OGxg8HsuBr/5f6tVAjDu6E=
+k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280/go.mod h1:+Axhij7bCpeqhklhUTe3xmOn6bWxolyZEeyaFpjGtl4=
k8s.io/kubectl v0.25.5 h1:m3Y3ysrlRR+wAD0TYoFCrngcYtwVH7UPCqubEwbe6oo=
k8s.io/kubectl v0.25.5/go.mod h1:EeHEydYE+pR8EUo5LkO27CP9ONxZpdmE2BWPEqTS8hY=
-k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed h1:jAne/RjBTyawwAy0utX5eqigAwz/lQhTmy+Hr/Cpue4=
-k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
+k8s.io/utils v0.0.0-20221107191617-1a15be271d1d h1:0Smp/HP1OH4Rvhe+4B8nWGERtlqAGSftbSbbmm45oFs=
+k8s.io/utils v0.0.0-20221107191617-1a15be271d1d/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
oras.land/oras-go v1.2.0 h1:yoKosVIbsPoFMqAIFHTnrmOuafHal+J/r+I5bdbVWu4=
oras.land/oras-go v1.2.0/go.mod h1:pFNs7oHp2dYsYMSS82HaX5l4mpnGO7hbpPN6EWH2ltc=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
diff --git a/pkg/addon-operator/bootstrap.go b/pkg/addon-operator/bootstrap.go
index ec35f6a6..d34acf96 100644
--- a/pkg/addon-operator/bootstrap.go
+++ b/pkg/addon-operator/bootstrap.go
@@ -1,13 +1,11 @@
package addon_operator
import (
- "fmt"
-
log "github.com/sirupsen/logrus"
"github.com/flant/addon-operator/pkg/app"
- "github.com/flant/addon-operator/pkg/helm"
"github.com/flant/addon-operator/pkg/kube_config_manager"
+ "github.com/flant/addon-operator/pkg/kube_config_manager/backend"
"github.com/flant/addon-operator/pkg/module_manager"
sh_app "github.com/flant/shell-operator/pkg/app"
"github.com/flant/shell-operator/pkg/config"
@@ -17,42 +15,24 @@ import (
// Bootstrap inits all dependencies for a full-fledged AddonOperator instance.
func (op *AddonOperator) bootstrap() error {
- runtimeConfig := config.NewConfig()
+ op.runtimeConfig = config.NewConfig()
// Init logging subsystem.
- sh_app.SetupLogging(runtimeConfig)
+ sh_app.SetupLogging(op.runtimeConfig)
log.Infof(sh_app.AppStartMessage)
log.Infof("Search modules in: %s", app.ModulesDir)
- globalHooksDir, err := shell_operator.RequireExistingDirectory(app.GlobalHooksDir)
- if err != nil {
- log.Errorf("Fatal: global hooks directory: %s", err)
- return err
- }
- log.Infof("Global hooks directory: %s", globalHooksDir)
-
- tempDir, err := shell_operator.EnsureTempDirectory(sh_app.TempDir)
- if err != nil {
- log.Errorf("Fatal: temp directory: %s", err)
- return err
- }
-
log.Infof("Addon-operator namespace: %s", app.Namespace)
// Debug server.
- debugServer, err := shell_operator.InitDefaultDebugServer()
+ // TODO: rewrite sh_app global variables to the addon-operator ones
+ debugServer, err := shell_operator.RunDefaultDebugServer(sh_app.DebugUnixSocket, sh_app.DebugHttpServerAddr)
if err != nil {
log.Errorf("Fatal: start Debug server: %s", err)
return err
}
- err = shell_operator.AssembleCommonOperator(op.ShellOperator)
- if err != nil {
- log.Errorf("Fatal: %s", err)
- return err
- }
-
- err = op.Assemble(app.ModulesDir, globalHooksDir, tempDir, debugServer, runtimeConfig)
+ err = op.Assemble(debugServer)
if err != nil {
log.Errorf("Fatal: %s", err)
return err
@@ -61,39 +41,24 @@ func (op *AddonOperator) bootstrap() error {
return nil
}
-func (op *AddonOperator) Assemble(modulesDir string, globalHooksDir string, tempDir string, debugServer *debug.Server, runtimeConfig *config.Config) (err error) {
- op.RegisterDefaultRoutes()
+func (op *AddonOperator) Assemble(debugServer *debug.Server) (err error) {
+ op.registerDefaultRoutes()
if app.AdmissionServerEnabled {
op.AdmissionServer.start(op.ctx)
}
- RegisterAddonOperatorMetrics(op.MetricStorage)
- StartLiveTicksUpdater(op.MetricStorage)
- StartTasksQueueLengthUpdater(op.MetricStorage, op.TaskQueues)
+ RegisterAddonOperatorMetrics(op.engine.MetricStorage)
+ StartLiveTicksUpdater(op.engine.MetricStorage)
+ StartTasksQueueLengthUpdater(op.engine.MetricStorage, op.engine.TaskQueues)
// Register routes in debug server.
- shell_operator.RegisterDebugQueueRoutes(debugServer, op.ShellOperator)
- shell_operator.RegisterDebugConfigRoutes(debugServer, runtimeConfig)
+ op.engine.RegisterDebugQueueRoutes(debugServer)
+ op.engine.RegisterDebugConfigRoutes(debugServer, op.runtimeConfig)
op.RegisterDebugGlobalRoutes(debugServer)
op.RegisterDebugModuleRoutes(debugServer)
// service (kubernetes object) does not have endpoints before addon-operator is ready
// we have to wait readiness probe (linked on the first-converge) before manipulating in-cluster objects covered with validation webhook
op.OnFirstConvergeDone()
- // Helm client factory.
- op.Helm, err = helm.InitHelmClientFactory(op.KubeClient)
- if err != nil {
- return fmt.Errorf("initialize Helm: %s", err)
- }
-
- // Helm resources monitor.
- // It uses a separate client-go instance. (Metrics are registered when 'main' client is initialized).
- op.HelmResourcesManager, err = InitDefaultHelmResourcesManager(op.ctx, op.MetricStorage)
- if err != nil {
- return fmt.Errorf("initialize Helm resources manager: %s", err)
- }
-
- op.SetupModuleManager(modulesDir, globalHooksDir, tempDir, runtimeConfig)
-
err = op.InitModuleManager()
if err != nil {
return err
@@ -102,17 +67,17 @@ func (op *AddonOperator) Assemble(modulesDir string, globalHooksDir string, temp
return nil
}
-func (op *AddonOperator) SetupModuleManager(modulesDir string, globalHooksDir string, tempDir string, runtimeConfig *config.Config) {
- // Create manager to check values in ConfigMap.
- kcfg := kube_config_manager.Config{
- Namespace: app.Namespace,
- ConfigMapName: app.ConfigMapName,
- KubeClient: op.KubeClient,
- RuntimeConfig: runtimeConfig,
+// SetupKubeConfigManager sets manager, which reads configuration for Modules from a cluster
+func (op *AddonOperator) SetupKubeConfigManager(bk backend.ConfigHandler) {
+ if op.KubeConfigManager != nil {
+ // return if kube config manager is already set
+ return
}
- manager := kube_config_manager.NewKubeConfigManager(op.ctx, &kcfg)
- op.KubeConfigManager = manager
+ op.KubeConfigManager = kube_config_manager.NewKubeConfigManager(op.ctx, bk, op.runtimeConfig)
+}
+
+func (op *AddonOperator) SetupModuleManager(modulesDir string, globalHooksDir string, tempDir string) {
// Create manager that runs modules and hooks.
dirConfig := module_manager.DirectoryConfig{
ModulesDir: modulesDir,
@@ -120,14 +85,14 @@ func (op *AddonOperator) SetupModuleManager(modulesDir string, globalHooksDir st
TempDir: tempDir,
}
deps := module_manager.ModuleManagerDependencies{
- KubeObjectPatcher: op.ObjectPatcher,
- KubeEventsManager: op.KubeEventsManager,
- KubeConfigManager: manager,
- ScheduleManager: op.ScheduleManager,
+ KubeObjectPatcher: op.engine.ObjectPatcher,
+ KubeEventsManager: op.engine.KubeEventsManager,
+ KubeConfigManager: op.KubeConfigManager,
+ ScheduleManager: op.engine.ScheduleManager,
Helm: op.Helm,
HelmResourcesManager: op.HelmResourcesManager,
- MetricStorage: op.MetricStorage,
- HookMetricStorage: op.HookMetricStorage,
+ MetricStorage: op.engine.MetricStorage,
+ HookMetricStorage: op.engine.HookMetricStorage,
}
cfg := module_manager.ModuleManagerConfig{
diff --git a/pkg/addon-operator/debug_server.go b/pkg/addon-operator/debug_server.go
index a48b1872..43276df6 100644
--- a/pkg/addon-operator/debug_server.go
+++ b/pkg/addon-operator/debug_server.go
@@ -4,6 +4,7 @@ import (
"fmt"
"net/http"
"os"
+ "sort"
"strconv"
"github.com/go-chi/chi/v5"
@@ -14,25 +15,25 @@ import (
)
func (op *AddonOperator) RegisterDebugGlobalRoutes(dbgSrv *debug.Server) {
- dbgSrv.Route("/global/list.{format:(json|yaml)}", func(_ *http.Request) (interface{}, error) {
+ dbgSrv.RegisterHandler(http.MethodGet, "/global/list.{format:(json|yaml)}", func(_ *http.Request) (interface{}, error) {
return map[string]interface{}{
"globalHooks": op.ModuleManager.GetGlobalHooksNames(),
}, nil
})
- dbgSrv.Route("/global/values.{format:(json|yaml)}", func(_ *http.Request) (interface{}, error) {
+ dbgSrv.RegisterHandler(http.MethodGet, "/global/values.{format:(json|yaml)}", func(_ *http.Request) (interface{}, error) {
return op.ModuleManager.GlobalValues()
})
- dbgSrv.Route("/global/config.{format:(json|yaml)}", func(_ *http.Request) (interface{}, error) {
+ dbgSrv.RegisterHandler(http.MethodGet, "/global/config.{format:(json|yaml)}", func(_ *http.Request) (interface{}, error) {
return op.ModuleManager.GlobalConfigValues(), nil
})
- dbgSrv.Route("/global/patches.{format:(json|yaml)}", func(_ *http.Request) (interface{}, error) {
+ dbgSrv.RegisterHandler(http.MethodGet, "/global/patches.{format:(json|yaml)}", func(_ *http.Request) (interface{}, error) {
return op.ModuleManager.GlobalValuesPatches(), nil
})
- dbgSrv.Route("/global/snapshots.{format:(json|yaml)}", func(r *http.Request) (interface{}, error) {
+ dbgSrv.RegisterHandler(http.MethodGet, "/global/snapshots.{format:(json|yaml)}", func(r *http.Request) (interface{}, error) {
kubeHookNames := op.ModuleManager.GetGlobalHooksInOrder(types.OnKubernetesEvent)
snapshots := make(map[string]interface{})
for _, hName := range kubeHookNames {
@@ -45,11 +46,13 @@ func (op *AddonOperator) RegisterDebugGlobalRoutes(dbgSrv *debug.Server) {
}
func (op *AddonOperator) RegisterDebugModuleRoutes(dbgSrv *debug.Server) {
- dbgSrv.Route("/module/list.{format:(json|yaml|text)}", func(_ *http.Request) (interface{}, error) {
- return map[string][]string{"enabledModules": op.ModuleManager.GetEnabledModuleNames()}, nil
+ dbgSrv.RegisterHandler(http.MethodGet, "/module/list.{format:(json|yaml|text)}", func(_ *http.Request) (interface{}, error) {
+ modules := op.ModuleManager.GetEnabledModuleNames()
+ sort.Strings(modules)
+ return map[string][]string{"enabledModules": modules}, nil
})
- dbgSrv.Route("/module/{name}/{type:(config|values)}.{format:(json|yaml)}", func(r *http.Request) (interface{}, error) {
+ dbgSrv.RegisterHandler(http.MethodGet, "/module/{name}/{type:(config|values)}.{format:(json|yaml)}", func(r *http.Request) (interface{}, error) {
modName := chi.URLParam(r, "name")
valType := chi.URLParam(r, "type")
@@ -67,11 +70,12 @@ func (op *AddonOperator) RegisterDebugModuleRoutes(dbgSrv *debug.Server) {
return "no values", nil
})
- dbgSrv.Route("/module/{name}/render", func(r *http.Request) (interface{}, error) {
+ dbgSrv.RegisterHandler(http.MethodGet, "/module/{name}/render", func(r *http.Request) (interface{}, error) {
modName := chi.URLParam(r, "name")
- debug, err := strconv.ParseBool(r.URL.Query().Get("debug"))
+ dbg, err := strconv.ParseBool(r.URL.Query().Get("debug"))
if err != nil {
- return nil, fmt.Errorf("can't parse debug query parameter: %w", err)
+ // if empty or unparsable - set false
+ dbg = false
}
m := op.ModuleManager.GetModule(modName)
@@ -85,10 +89,10 @@ func (op *AddonOperator) RegisterDebugModuleRoutes(dbgSrv *debug.Server) {
}
defer os.Remove(valuesPath)
- return op.Helm.NewClient().Render(m.Name, m.Path, []string{valuesPath}, nil, app.Namespace, debug)
+ return op.Helm.NewClient().Render(m.Name, m.Path, []string{valuesPath}, nil, app.Namespace, dbg)
})
- dbgSrv.Route("/module/{name}/patches.json", func(r *http.Request) (interface{}, error) {
+ dbgSrv.RegisterHandler(http.MethodGet, "/module/{name}/patches.json", func(r *http.Request) (interface{}, error) {
modName := chi.URLParam(r, "name")
m := op.ModuleManager.GetModule(modName)
@@ -99,7 +103,7 @@ func (op *AddonOperator) RegisterDebugModuleRoutes(dbgSrv *debug.Server) {
return op.ModuleManager.ModuleDynamicValuesPatches(modName), nil
})
- dbgSrv.Route("/module/resource-monitor.{format:(json|yaml)}", func(_ *http.Request) (interface{}, error) {
+ dbgSrv.RegisterHandler(http.MethodGet, "/module/resource-monitor.{format:(json|yaml)}", func(_ *http.Request) (interface{}, error) {
dump := map[string]interface{}{}
for _, moduleName := range op.ModuleManager.GetEnabledModuleNames() {
@@ -115,7 +119,7 @@ func (op *AddonOperator) RegisterDebugModuleRoutes(dbgSrv *debug.Server) {
return dump, nil
})
- dbgSrv.Route("/module/{name}/snapshots.{format:(json|yaml)}", func(r *http.Request) (interface{}, error) {
+ dbgSrv.RegisterHandler(http.MethodGet, "/module/{name}/snapshots.{format:(json|yaml)}", func(r *http.Request) (interface{}, error) {
modName := chi.URLParam(r, "name")
m := op.ModuleManager.GetModule(modName)
diff --git a/pkg/addon-operator/http_server.go b/pkg/addon-operator/http_server.go
index 7173d27b..76911625 100644
--- a/pkg/addon-operator/http_server.go
+++ b/pkg/addon-operator/http_server.go
@@ -6,30 +6,33 @@ import (
"strings"
"github.com/prometheus/client_golang/prometheus/promhttp"
+
+ "github.com/flant/addon-operator/pkg/app"
)
-func (op *AddonOperator) RegisterDefaultRoutes() {
- http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
- _, _ = writer.Write([]byte(`
+func (op *AddonOperator) registerDefaultRoutes() {
+ op.engine.APIServer.RegisterRoute(http.MethodGet, "/", func(writer http.ResponseWriter, request *http.Request) {
+ _, _ = writer.Write([]byte(fmt.Sprintf(`
Addon-operator
Addon-operator
- go tool pprof goprofex http://ADDON_OPERATOR_IP:9115/debug/pprof/profile
+ go tool pprof http://ADDON_OPERATOR_IP:%s/debug/pprof/profile
+ show all possible routes
prometheus metrics
health url
ready url
- `))
+ `, app.ListenPort)))
})
- http.Handle("/metrics", promhttp.Handler())
+ op.engine.APIServer.RegisterRoute(http.MethodGet, "/metrics", promhttp.Handler().ServeHTTP)
- http.HandleFunc("/healthz", func(writer http.ResponseWriter, request *http.Request) {
+ op.engine.APIServer.RegisterRoute(http.MethodGet, "/healthz", func(writer http.ResponseWriter, request *http.Request) {
writer.WriteHeader(http.StatusOK)
})
- http.HandleFunc("/readyz", func(w http.ResponseWriter, request *http.Request) {
+ op.engine.APIServer.RegisterRoute(http.MethodGet, "/readyz", func(w http.ResponseWriter, request *http.Request) {
if op.IsStartupConvergeDone() {
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte("Startup converge done.\n"))
@@ -39,8 +42,8 @@ func (op *AddonOperator) RegisterDefaultRoutes() {
}
})
- http.HandleFunc("/status/converge", func(writer http.ResponseWriter, request *http.Request) {
- convergeTasks := ConvergeTasksInQueue(op.TaskQueues.GetMain())
+ op.engine.APIServer.RegisterRoute(http.MethodGet, "/status/converge", func(writer http.ResponseWriter, request *http.Request) {
+ convergeTasks := ConvergeTasksInQueue(op.engine.TaskQueues.GetMain())
statusLines := make([]string, 0)
switch op.ConvergeState.firstRunPhase {
diff --git a/pkg/addon-operator/kube_client.go b/pkg/addon-operator/kube_client.go
index 22f62485..28645471 100644
--- a/pkg/addon-operator/kube_client.go
+++ b/pkg/addon-operator/kube_client.go
@@ -9,26 +9,26 @@ import (
klient "github.com/flant/kube-client/client"
sh_app "github.com/flant/shell-operator/pkg/app"
"github.com/flant/shell-operator/pkg/metric_storage"
- shell_operator "github.com/flant/shell-operator/pkg/shell-operator"
+ utils "github.com/flant/shell-operator/pkg/utils/labels"
)
// DefaultHelmMonitorKubeClientMetricLabels are labels that indicates go client metrics producer.
// Important! These labels should be consistent with similar labels in ShellOperator!
var DefaultHelmMonitorKubeClientMetricLabels = map[string]string{"component": "helm_monitor"}
-// DefaultHelmMonitorKubeClient initializes a Kubernetes client for helm monitor.
-func DefaultHelmMonitorKubeClient(metricStorage *metric_storage.MetricStorage, metricLabels map[string]string) klient.Client {
+// defaultHelmMonitorKubeClient initializes a Kubernetes client for helm monitor.
+func defaultHelmMonitorKubeClient(metricStorage *metric_storage.MetricStorage, metricLabels map[string]string) *klient.Client {
client := klient.New()
client.WithContextName(sh_app.KubeContext)
client.WithConfigPath(sh_app.KubeConfig)
client.WithRateLimiterSettings(app.HelmMonitorKubeClientQps, app.HelmMonitorKubeClientBurst)
client.WithMetricStorage(metricStorage)
- client.WithMetricLabels(shell_operator.DefaultIfEmpty(metricLabels, DefaultHelmMonitorKubeClientMetricLabels))
+ client.WithMetricLabels(utils.DefaultIfEmpty(metricLabels, DefaultHelmMonitorKubeClientMetricLabels))
return client
}
func InitDefaultHelmResourcesManager(ctx context.Context, metricStorage *metric_storage.MetricStorage) (helm_resources_manager.HelmResourcesManager, error) {
- kubeClient := DefaultHelmMonitorKubeClient(metricStorage, DefaultHelmMonitorKubeClientMetricLabels)
+ kubeClient := defaultHelmMonitorKubeClient(metricStorage, DefaultHelmMonitorKubeClientMetricLabels)
if err := kubeClient.Init(); err != nil {
return nil, fmt.Errorf("initialize Kubernetes client for Helm resources manager: %s\n", err)
}
diff --git a/pkg/addon-operator/operator.go b/pkg/addon-operator/operator.go
index 4bb49226..2eb13714 100644
--- a/pkg/addon-operator/operator.go
+++ b/pkg/addon-operator/operator.go
@@ -3,23 +3,26 @@ package addon_operator
import (
"context"
"fmt"
- _ "net/http/pprof" // Webserver pprof endpoint injection
"path"
"runtime/trace"
"strings"
"time"
+ "github.com/gofrs/uuid/v5"
log "github.com/sirupsen/logrus"
- uuid "gopkg.in/satori/go.uuid.v1"
"github.com/flant/addon-operator/pkg/app"
"github.com/flant/addon-operator/pkg/helm"
"github.com/flant/addon-operator/pkg/helm_resources_manager"
hookTypes "github.com/flant/addon-operator/pkg/hook/types"
"github.com/flant/addon-operator/pkg/kube_config_manager"
+ "github.com/flant/addon-operator/pkg/kube_config_manager/config"
"github.com/flant/addon-operator/pkg/module_manager"
"github.com/flant/addon-operator/pkg/task"
"github.com/flant/addon-operator/pkg/utils"
+ "github.com/flant/kube-client/client"
+ sh_app "github.com/flant/shell-operator/pkg/app"
+ runtimeConfig "github.com/flant/shell-operator/pkg/config"
bc "github.com/flant/shell-operator/pkg/hook/binding_context"
"github.com/flant/shell-operator/pkg/hook/controller"
htypes "github.com/flant/shell-operator/pkg/hook/types"
@@ -27,16 +30,19 @@ import (
shell_operator "github.com/flant/shell-operator/pkg/shell-operator"
sh_task "github.com/flant/shell-operator/pkg/task"
"github.com/flant/shell-operator/pkg/task/queue"
+ fileUtils "github.com/flant/shell-operator/pkg/utils/file"
"github.com/flant/shell-operator/pkg/utils/measure"
)
// AddonOperator extends ShellOperator with modules and global hooks
// and with a value storage.
type AddonOperator struct {
- *shell_operator.ShellOperator
+ engine *shell_operator.ShellOperator
ctx context.Context
cancel context.CancelFunc
+ runtimeConfig *runtimeConfig.Config
+
// KubeConfigManager monitors changes in ConfigMap.
KubeConfigManager *kube_config_manager.KubeConfigManager
@@ -53,7 +59,7 @@ type AddonOperator struct {
ConvergeState *ConvergeState
// Initial KubeConfig to bypass initial loading from the ConfigMap.
- InitialKubeConfig *kube_config_manager.KubeConfig
+ InitialKubeConfig *config.KubeConfig
// AdmissionServer handles validation and mutation admission webhooks
AdmissionServer *AdmissionServer
@@ -65,13 +71,18 @@ type AddonOperator struct {
func NewAddonOperator(ctx context.Context) *AddonOperator {
cctx, cancel := context.WithCancel(ctx)
- so := shell_operator.NewShellOperator()
- so.WithContext(cctx)
+ so := shell_operator.NewShellOperator(cctx)
+
+ // Have to initialize common operator to have all common dependencies below
+ err := so.AssembleCommonOperator(app.ListenAddress, app.ListenPort)
+ if err != nil {
+ panic(err)
+ }
ao := &AddonOperator{
ctx: cctx,
cancel: cancel,
- ShellOperator: so,
+ engine: so,
ConvergeState: NewConvergeState(),
ExplicitlyPurgeModules: make([]string, 0),
}
@@ -81,12 +92,92 @@ func NewAddonOperator(ctx context.Context) *AddonOperator {
return ao
}
+func (op *AddonOperator) Setup() error {
+ // Helm client factory.
+ helmClient, err := helm.InitHelmClientFactory(op.engine.KubeClient)
+ if err != nil {
+ return fmt.Errorf("initialize Helm: %s", err)
+ }
+
+ // Helm resources monitor.
+ // It uses a separate client-go instance. (Metrics are registered when 'main' client is initialized).
+ helmResourcesManager, err := InitDefaultHelmResourcesManager(op.ctx, op.engine.MetricStorage)
+ if err != nil {
+ return fmt.Errorf("initialize Helm resources manager: %s", err)
+ }
+
+ op.Helm = helmClient
+ op.HelmResourcesManager = helmResourcesManager
+
+ globalHooksDir, err := fileUtils.RequireExistingDirectory(app.GlobalHooksDir)
+ if err != nil {
+ return fmt.Errorf("global hooks directory: %s", err)
+ }
+ log.Infof("Global hooks directory: %s", globalHooksDir)
+
+ tempDir, err := fileUtils.EnsureTempDirectory(sh_app.TempDir)
+ if err != nil {
+ return fmt.Errorf("temp directory: %s", err)
+ }
+
+ if op.KubeConfigManager == nil {
+ return fmt.Errorf("KubeConfigManager must be set before Setup")
+ }
+
+ op.SetupModuleManager(app.ModulesDir, globalHooksDir, tempDir)
+
+ return nil
+}
+
+// Start runs all managers, event and queue handlers.
+func (op *AddonOperator) Start() error {
+ if err := op.bootstrap(); err != nil {
+ return err
+ }
+
+ // start http server with metrics
+ op.engine.APIServer.Start(op.ctx)
+
+ log.Info("Start first converge for modules")
+ // Loading the onStartup hooks into the queue and running all modules.
+ // Turning tracking changes on only after startup ends.
+
+ // Bootstrap main queue with tasks to run Startup process.
+ op.BootstrapMainQueue(op.engine.TaskQueues)
+ // Start main task queue handler
+ op.engine.TaskQueues.StartMain()
+
+ // Global hooks are registered, initialize their queues.
+ op.CreateAndStartQueuesForGlobalHooks()
+
+ // ManagerEventsHandler handle events for kubernetes and schedule bindings.
+ // Start it before start all informers to catch all kubernetes events (#42)
+ op.engine.ManagerEventsHandler.Start()
+
+ // Enable events from schedule manager.
+ op.engine.ScheduleManager.Start()
+
+ op.KubeConfigManager.Start()
+ op.ModuleManager.Start()
+ op.StartModuleManagerEventHandler()
+
+ return nil
+}
+
func (op *AddonOperator) Stop() {
+ op.KubeConfigManager.Stop()
+ op.engine.Shutdown()
+
if op.cancel != nil {
op.cancel()
}
}
+// KubeClient returns default common kubernetes client initialized by shell-operator
+func (op *AddonOperator) KubeClient() *client.Client {
+ return op.engine.KubeClient
+}
+
func (op *AddonOperator) IsStartupConvergeDone() bool {
return op.ConvergeState.firstRunPhase == firstDone
}
@@ -112,11 +203,11 @@ func (op *AddonOperator) InitModuleManager() error {
// Also, it is possible to override initial KubeConfig to give global hooks a chance
// to handle the ConfigMap content later.
if op.InitialKubeConfig == nil {
- op.KubeConfigManager.SafeReadConfig(func(config *kube_config_manager.KubeConfig) {
+ op.KubeConfigManager.SafeReadConfig(func(config *config.KubeConfig) {
_, err = op.ModuleManager.HandleNewKubeConfig(config)
})
if err != nil {
- return fmt.Errorf("init module manager: load config from ConfigMap: %s", err)
+ return fmt.Errorf("init module manager: load initial config for KubeConfigManager: %s", err)
}
} else {
_, err = op.ModuleManager.HandleNewKubeConfig(op.InitialKubeConfig)
@@ -147,9 +238,9 @@ func (op *AddonOperator) AllowHandleScheduleEvent(hook *module_manager.CommonHoo
}
func (op *AddonOperator) RegisterManagerEventsHandlers() {
- op.ManagerEventsHandler.WithScheduleEventHandler(func(crontab string) []sh_task.Task {
+ op.engine.ManagerEventsHandler.WithScheduleEventHandler(func(crontab string) []sh_task.Task {
logLabels := map[string]string{
- "event.id": uuid.NewV4().String(),
+ "event.id": uuid.Must(uuid.NewV4()).String(),
"binding": string(htypes.Schedule),
}
logEntry := log.WithFields(utils.LabelsToLogFields(logLabels))
@@ -223,9 +314,9 @@ func (op *AddonOperator) RegisterManagerEventsHandlers() {
return tasks
})
- op.ManagerEventsHandler.WithKubeEventHandler(func(kubeEvent types.KubeEvent) []sh_task.Task {
+ op.engine.ManagerEventsHandler.WithKubeEventHandler(func(kubeEvent types.KubeEvent) []sh_task.Task {
logLabels := map[string]string{
- "event.id": uuid.NewV4().String(),
+ "event.id": uuid.Must(uuid.NewV4()).String(),
"binding": string(htypes.OnKubernetesEvent),
}
logEntry := log.WithFields(utils.LabelsToLogFields(logLabels))
@@ -292,38 +383,6 @@ func (op *AddonOperator) RegisterManagerEventsHandlers() {
})
}
-// Start runs all managers, event and queue handlers.
-func (op *AddonOperator) Start() error {
- if err := op.bootstrap(); err != nil {
- return err
- }
-
- log.Info("Start first converge for modules")
- // Loading the onStartup hooks into the queue and running all modules.
- // Turning tracking changes on only after startup ends.
-
- // Bootstrap main queue with tasks to run Startup process.
- op.BootstrapMainQueue(op.TaskQueues)
- // Start main task queue handler
- op.TaskQueues.StartMain()
-
- // Global hooks are registered, initialize their queues.
- op.CreateAndStartQueuesForGlobalHooks()
-
- // ManagerEventsHandler handle events for kubernetes and schedule bindings.
- // Start it before start all informers to catch all kubernetes events (#42)
- op.ManagerEventsHandler.Start()
-
- // Enable events from schedule manager.
- op.ScheduleManager.Start()
-
- op.KubeConfigManager.Start()
- op.ModuleManager.Start()
- op.StartModuleManagerEventHandler()
-
- return nil
-}
-
// BootstrapMainQueue adds tasks to initiate Startup sequence:
//
// - Run onStartup hooks.
@@ -346,7 +405,7 @@ func (op *AddonOperator) BootstrapMainQueue(tqs *queue.TaskQueueSet) {
tasks := op.CreateBootstrapTasks(logLabels)
op.logTaskAdd(logEntry, "append", tasks...)
for _, tsk := range tasks {
- op.TaskQueues.GetMain().AddLast(tsk)
+ op.engine.TaskQueues.GetMain().AddLast(tsk)
}
}
@@ -502,7 +561,7 @@ func (op *AddonOperator) HandleConvergeModules(t sh_task.Task, logLabels map[str
if taskEvent == KubeConfigChanged {
logEntry.Debugf("ConvergeModules: handle KubeConfigChanged")
var state *module_manager.ModulesState
- op.KubeConfigManager.SafeReadConfig(func(config *kube_config_manager.KubeConfig) {
+ op.KubeConfigManager.SafeReadConfig(func(config *config.KubeConfig) {
state, handleErr = op.ModuleManager.HandleNewKubeConfig(config)
})
if handleErr == nil {
@@ -537,7 +596,7 @@ func (op *AddonOperator) HandleConvergeModules(t sh_task.Task, logLabels map[str
// If Converge is in progress, drain converge tasks after current task
// and put ConvergeModules at start.
// Else put ConvergeModules to the end of the main queue.
- convergeDrained := RemoveCurrentConvergeTasks(op.TaskQueues.GetMain(), t.GetId())
+ convergeDrained := RemoveCurrentConvergeTasks(op.engine.TaskQueues.GetMain(), t.GetId())
if convergeDrained {
logEntry.Infof("ConvergeModules: kube config modification detected, restart current converge process (%s)", op.ConvergeState.Phase)
res.AfterTasks = []sh_task.Task{
@@ -561,7 +620,7 @@ func (op *AddonOperator) HandleConvergeModules(t sh_task.Task, logLabels map[str
logEntry.Debugf("ConvergeModules: start")
// Deduplicate tasks: remove ConvergeModules tasks right after the current task.
- RemoveAdjacentConvergeModules(op.TaskQueues.GetByName(t.GetQueueName()), t.GetId())
+ RemoveAdjacentConvergeModules(op.engine.TaskQueues.GetByName(t.GetQueueName()), t.GetId())
op.ConvergeState.Phase = RunBeforeAll
}
@@ -632,7 +691,7 @@ func (op *AddonOperator) HandleConvergeModules(t sh_task.Task, logLabels map[str
if handleErr != nil {
res.Status = queue.Fail
logEntry.Errorf("ConvergeModules failed in phase '%s', requeue task to retry after delay. Failed count is %d. Error: %s", op.ConvergeState.Phase, t.GetFailureCount()+1, handleErr)
- op.MetricStorage.CounterAdd("{PREFIX}modules_discover_errors_total", 1.0, map[string]string{})
+ op.engine.MetricStorage.CounterAdd("{PREFIX}modules_discover_errors_total", 1.0, map[string]string{})
t.UpdateFailureMessage(handleErr.Error())
t.WithQueuedAt(time.Now())
return res
@@ -720,11 +779,8 @@ func (op *AddonOperator) CreateAfterAllTasks(logLabels map[string]string, eventD
if err != nil {
return nil, err
}
- taskMetadata.ValuesChecksum, err = globalValues.Checksum()
+ taskMetadata.ValuesChecksum = globalValues.Checksum()
taskMetadata.DynamicEnabledChecksum = op.ModuleManager.DynamicEnabledChecksum()
- if err != nil {
- return nil, err
- }
}
newTask := sh_task.NewTask(task.GlobalHookRun).
@@ -740,11 +796,11 @@ func (op *AddonOperator) CreateAfterAllTasks(logLabels map[string]string, eventD
// CreateAndStartQueue creates a named queue and starts it.
// It returns false is queue is already created
func (op *AddonOperator) CreateAndStartQueue(queueName string) bool {
- if op.TaskQueues.GetByName(queueName) != nil {
+ if op.engine.TaskQueues.GetByName(queueName) != nil {
return false
}
- op.TaskQueues.NewNamedQueue(queueName, op.TaskHandler)
- op.TaskQueues.GetByName(queueName).Start()
+ op.engine.TaskQueues.NewNamedQueue(queueName, op.TaskHandler)
+ op.engine.TaskQueues.GetByName(queueName).Start()
return true
}
@@ -799,10 +855,10 @@ func (op *AddonOperator) DrainModuleQueues(modName string) {
for _, hookName := range op.ModuleManager.GetModuleHookNames(modName) {
h := op.ModuleManager.GetModuleHook(hookName)
for _, hookBinding := range h.Config.Schedules {
- DrainNonMainQueue(op.TaskQueues.GetByName(hookBinding.Queue))
+ DrainNonMainQueue(op.engine.TaskQueues.GetByName(hookBinding.Queue))
}
for _, hookBinding := range h.Config.OnKubernetesEvents {
- DrainNonMainQueue(op.TaskQueues.GetByName(hookBinding.Queue))
+ DrainNonMainQueue(op.engine.TaskQueues.GetByName(hookBinding.Queue))
}
}
}
@@ -814,16 +870,16 @@ func (op *AddonOperator) StartModuleManagerEventHandler() {
select {
case kubeConfigEvent := <-op.KubeConfigManager.KubeConfigEventCh():
logLabels := map[string]string{
- "event.id": uuid.NewV4().String(),
+ "event.id": uuid.Must(uuid.NewV4()).String(),
}
eventLogEntry := logEntry.WithFields(utils.LabelsToLogFields(logLabels))
- if kubeConfigEvent == kube_config_manager.KubeConfigInvalid {
+ if kubeConfigEvent == config.KubeConfigInvalid {
op.ModuleManager.SetKubeConfigValid(false)
eventLogEntry.Infof("KubeConfig become invalid")
}
- if kubeConfigEvent == kube_config_manager.KubeConfigChanged {
+ if kubeConfigEvent == config.KubeConfigChanged {
if !op.ModuleManager.GetKubeConfigValid() {
eventLogEntry.Infof("KubeConfig become valid")
}
@@ -835,21 +891,21 @@ func (op *AddonOperator) StartModuleManagerEventHandler() {
KubeConfigChanged,
logLabels,
)
- op.TaskQueues.GetMain().AddFirst(convergeTask)
+ op.engine.TaskQueues.GetMain().AddFirst(convergeTask)
// Cancel delay in case the head task is stuck in the error loop.
- op.TaskQueues.GetMain().CancelTaskDelay()
+ op.engine.TaskQueues.GetMain().CancelTaskDelay()
op.logTaskAdd(eventLogEntry, "KubeConfig is changed, put first", convergeTask)
}
case absentResourcesEvent := <-op.HelmResourcesManager.Ch():
logLabels := map[string]string{
- "event.id": uuid.NewV4().String(),
+ "event.id": uuid.Must(uuid.NewV4()).String(),
"module": absentResourcesEvent.ModuleName,
}
eventLogEntry := logEntry.WithFields(utils.LabelsToLogFields(logLabels))
// Do not add ModuleRun task if it is already queued.
- hasTask := QueueHasPendingModuleRunTask(op.TaskQueues.GetMain(), absentResourcesEvent.ModuleName)
+ hasTask := QueueHasPendingModuleRunTask(op.engine.TaskQueues.GetMain(), absentResourcesEvent.ModuleName)
if !hasTask {
newTask := sh_task.NewTask(task.ModuleRun).
WithLogLabels(logLabels).
@@ -858,7 +914,7 @@ func (op *AddonOperator) StartModuleManagerEventHandler() {
EventDescription: "DetectAbsentHelmResources",
ModuleName: absentResourcesEvent.ModuleName,
})
- op.TaskQueues.GetMain().AddLast(newTask.WithQueuedAt(time.Now()))
+ op.engine.TaskQueues.GetMain().AddLast(newTask.WithQueuedAt(time.Now()))
taskAddDescription := fmt.Sprintf("got %d absent module resources, append", len(absentResourcesEvent.Absent))
op.logTaskAdd(logEntry, taskAddDescription, newTask)
} else {
@@ -978,7 +1034,7 @@ func (op *AddonOperator) UpdateWaitInQueueMetric(t sh_task.Task) {
}
taskWaitTime := time.Since(t.GetQueuedAt()).Seconds()
- op.MetricStorage.CounterAdd("{PREFIX}task_wait_in_queue_seconds_total", taskWaitTime, metricLabels)
+ op.engine.MetricStorage.CounterAdd("{PREFIX}task_wait_in_queue_seconds_total", taskWaitTime, metricLabels)
}
// HandleGlobalHookEnableKubernetesBindings add Synchronization tasks.
@@ -1011,7 +1067,7 @@ func (op *AddonOperator) HandleGlobalHookEnableKubernetesBindings(t sh_task.Task
}
delete(taskLogLabels, "task.id")
- kubernetesBindingID := uuid.NewV4().String()
+ kubernetesBindingID := uuid.Must(uuid.NewV4()).String()
newTask := sh_task.NewTask(task.GlobalHookRun).
WithLogLabels(taskLogLabels).
WithQueueName(info.QueueName).
@@ -1045,7 +1101,7 @@ func (op *AddonOperator) HandleGlobalHookEnableKubernetesBindings(t sh_task.Task
if err != nil {
hookLabel := path.Base(globalHook.Path)
// TODO use separate metric, as in shell-operator?
- op.MetricStorage.CounterAdd("{PREFIX}global_hook_errors_total", 1.0, map[string]string{
+ op.engine.MetricStorage.CounterAdd("{PREFIX}global_hook_errors_total", 1.0, map[string]string{
"hook": hookLabel,
"binding": "GlobalEnableKubernetesBindings",
"queue": t.GetQueueName(),
@@ -1064,7 +1120,7 @@ func (op *AddonOperator) HandleGlobalHookEnableKubernetesBindings(t sh_task.Task
// "Wait" tasks are queued first
for _, tsk := range parallelSyncTasksToWait {
- q := op.TaskQueues.GetByName(tsk.GetQueueName())
+ q := op.engine.TaskQueues.GetByName(tsk.GetQueueName())
if q == nil {
log.Errorf("Queue %s is not created while run GlobalHookEnableKubernetesBindings task!", tsk.GetQueueName())
} else {
@@ -1077,7 +1133,7 @@ func (op *AddonOperator) HandleGlobalHookEnableKubernetesBindings(t sh_task.Task
op.logTaskAdd(logEntry, "append", parallelSyncTasksToWait...)
for _, tsk := range parallelSyncTasks {
- q := op.TaskQueues.GetByName(tsk.GetQueueName())
+ q := op.engine.TaskQueues.GetByName(tsk.GetQueueName())
if q == nil {
log.Errorf("Queue %s is not created while run GlobalHookEnableKubernetesBindings task!", tsk.GetQueueName())
} else {
@@ -1165,7 +1221,7 @@ func (op *AddonOperator) HandleModuleDelete(t sh_task.Task, labels map[string]st
module.State.LastModuleErr = err
if err != nil {
- op.MetricStorage.CounterAdd("{PREFIX}module_delete_errors_total", 1.0, map[string]string{"module": hm.ModuleName})
+ op.engine.MetricStorage.CounterAdd("{PREFIX}module_delete_errors_total", 1.0, map[string]string{"module": hm.ModuleName})
logEntry.Errorf("Module delete failed, requeue task to retry after delay. Failed count is %d. Error: %s", t.GetFailureCount()+1, err)
t.UpdateFailureMessage(err.Error())
t.WithQueuedAt(time.Now())
@@ -1211,7 +1267,7 @@ func (op *AddonOperator) HandleModuleRun(t sh_task.Task, labels map[string]strin
}
defer measure.Duration(func(d time.Duration) {
- op.MetricStorage.HistogramObserve("{PREFIX}module_run_seconds", d.Seconds(), metricLabels, nil)
+ op.engine.MetricStorage.HistogramObserve("{PREFIX}module_run_seconds", d.Seconds(), metricLabels, nil)
})()
var moduleRunErr error
@@ -1278,7 +1334,7 @@ func (op *AddonOperator) HandleModuleRun(t sh_task.Task, labels map[string]strin
}
delete(taskLogLabels, "task.id")
- kubernetesBindingID := uuid.NewV4().String()
+ kubernetesBindingID := uuid.Must(uuid.NewV4()).String()
taskMeta := task.HookMetadata{
EventDescription: hm.EventDescription,
ModuleName: hm.ModuleName,
@@ -1316,7 +1372,7 @@ func (op *AddonOperator) HandleModuleRun(t sh_task.Task, labels map[string]strin
} else {
// Queue parallel tasks that should be waited.
for _, tsk := range parallelSyncTasksToWait {
- q := op.TaskQueues.GetByName(tsk.GetQueueName())
+ q := op.engine.TaskQueues.GetByName(tsk.GetQueueName())
if q == nil {
logEntry.Errorf("queue %s is not found while EnableKubernetesBindings task", tsk.GetQueueName())
} else {
@@ -1329,7 +1385,7 @@ func (op *AddonOperator) HandleModuleRun(t sh_task.Task, labels map[string]strin
// Queue regular parallel tasks.
for _, tsk := range parallelSyncTasks {
- q := op.TaskQueues.GetByName(tsk.GetQueueName())
+ q := op.engine.TaskQueues.GetByName(tsk.GetQueueName())
if q == nil {
logEntry.Errorf("queue %s is not found while EnableKubernetesBindings task", tsk.GetQueueName())
} else {
@@ -1396,7 +1452,7 @@ func (op *AddonOperator) HandleModuleRun(t sh_task.Task, labels map[string]strin
if moduleRunErr != nil {
res.Status = queue.Fail
logEntry.Errorf("ModuleRun failed in phase '%s'. Requeue task to retry after delay. Failed count is %d. Error: %s", module.State.Phase, t.GetFailureCount()+1, moduleRunErr)
- op.MetricStorage.CounterAdd("{PREFIX}module_run_errors_total", 1.0, map[string]string{"module": hm.ModuleName})
+ op.engine.MetricStorage.CounterAdd("{PREFIX}module_run_errors_total", 1.0, map[string]string{"module": hm.ModuleName})
t.UpdateFailureMessage(moduleRunErr.Error())
t.WithQueuedAt(time.Now())
} else {
@@ -1454,7 +1510,7 @@ func (op *AddonOperator) HandleModuleHookRun(t sh_task.Task, labels map[string]s
}
defer measure.Duration(func(d time.Duration) {
- op.MetricStorage.HistogramObserve("{PREFIX}module_hook_run_seconds", d.Seconds(), metricLabels, nil)
+ op.engine.MetricStorage.HistogramObserve("{PREFIX}module_hook_run_seconds", d.Seconds(), metricLabels, nil)
})()
shouldRunHook := true
@@ -1475,7 +1531,7 @@ func (op *AddonOperator) HandleModuleHookRun(t sh_task.Task, labels map[string]s
// Combine tasks in the queue and compact binding contexts for v1 hooks.
if shouldRunHook && taskHook.Config.Version == "v1" {
- combineResult := op.CombineBindingContextForHook(op.TaskQueues.GetByName(t.GetQueueName()), t, func(tsk sh_task.Task) bool {
+ combineResult := op.engine.CombineBindingContextForHook(op.engine.TaskQueues.GetByName(t.GetQueueName()), t, func(tsk sh_task.Task) bool {
thm := task.HookMetadataAccessor(tsk)
// Stop combine process when Synchronization tasks have different
// values in WaitForSynchronization or ExecuteOnSynchronization fields.
@@ -1579,7 +1635,7 @@ func (op *AddonOperator) HandleModuleHookRun(t sh_task.Task, labels map[string]s
delete(logLabels, "watchEvent")
// Do not add ModuleRun task if it is already queued.
- hasTask := QueueHasPendingModuleRunTask(op.TaskQueues.GetMain(), hm.ModuleName)
+ hasTask := QueueHasPendingModuleRunTask(op.engine.TaskQueues.GetMain(), hm.ModuleName)
if !hasTask {
newTask := sh_task.NewTask(task.ModuleRun).
WithLogLabels(logLabels).
@@ -1590,7 +1646,7 @@ func (op *AddonOperator) HandleModuleHookRun(t sh_task.Task, labels map[string]s
})
newTask.SetProp("triggered-by", triggeredBy)
- op.TaskQueues.GetMain().AddLast(newTask.WithQueuedAt(time.Now()))
+ op.engine.TaskQueues.GetMain().AddLast(newTask.WithQueuedAt(time.Now()))
op.logTaskAdd(logEntry, "module values are changed, append", newTask)
} else {
logEntry.WithField("task.flow", "noop").Infof("module values are changed, ModuleRun task already queued")
@@ -1598,9 +1654,9 @@ func (op *AddonOperator) HandleModuleHookRun(t sh_task.Task, labels map[string]s
}
}
- op.MetricStorage.CounterAdd("{PREFIX}module_hook_allowed_errors_total", allowed, metricLabels)
- op.MetricStorage.CounterAdd("{PREFIX}module_hook_errors_total", errors, metricLabels)
- op.MetricStorage.CounterAdd("{PREFIX}module_hook_success_total", success, metricLabels)
+ op.engine.MetricStorage.CounterAdd("{PREFIX}module_hook_allowed_errors_total", allowed, metricLabels)
+ op.engine.MetricStorage.CounterAdd("{PREFIX}module_hook_errors_total", errors, metricLabels)
+ op.engine.MetricStorage.CounterAdd("{PREFIX}module_hook_success_total", success, metricLabels)
}
if isSynchronization && res.Status == queue.Success {
@@ -1641,7 +1697,7 @@ func (op *AddonOperator) HandleGlobalHookRun(t sh_task.Task, labels map[string]s
}
defer measure.Duration(func(d time.Duration) {
- op.MetricStorage.HistogramObserve("{PREFIX}global_hook_run_seconds", d.Seconds(), metricLabels, nil)
+ op.engine.MetricStorage.HistogramObserve("{PREFIX}global_hook_run_seconds", d.Seconds(), metricLabels, nil)
})()
isSynchronization := hm.IsSynchronization()
@@ -1663,7 +1719,7 @@ func (op *AddonOperator) HandleGlobalHookRun(t sh_task.Task, labels map[string]s
if shouldRunHook && taskHook.Config.Version == "v1" {
// Combine binding contexts in the queue.
- combineResult := op.CombineBindingContextForHook(op.TaskQueues.GetByName(t.GetQueueName()), t, func(tsk sh_task.Task) bool {
+ combineResult := op.engine.CombineBindingContextForHook(op.engine.TaskQueues.GetByName(t.GetQueueName()), t, func(tsk sh_task.Task) bool {
thm := task.HookMetadataAccessor(tsk)
// Stop combine process when Synchronization tasks have different
// values in WaitForSynchronization or ExecuteOnSynchronization fields.
@@ -1808,7 +1864,7 @@ func (op *AddonOperator) HandleGlobalHookRun(t sh_task.Task, labels map[string]s
// Reload all using "ConvergeModules" task.
newTask := NewConvergeModulesTask(eventDescription, GlobalValuesChanged, logLabels)
newTask.SetProp("triggered-by", triggeredBy)
- op.TaskQueues.GetMain().AddLast(newTask)
+ op.engine.TaskQueues.GetMain().AddLast(newTask)
op.logTaskAdd(logEntry, "global values are changed, append", newTask)
}
// TODO rethink helm monitors pause-resume. It is not working well with parallel hooks without locks. But locks will destroy parallelization.
@@ -1817,9 +1873,9 @@ func (op *AddonOperator) HandleGlobalHookRun(t sh_task.Task, labels map[string]s
//}
}
- op.MetricStorage.CounterAdd("{PREFIX}global_hook_allowed_errors_total", allowed, metricLabels)
- op.MetricStorage.CounterAdd("{PREFIX}global_hook_errors_total", errors, metricLabels)
- op.MetricStorage.CounterAdd("{PREFIX}global_hook_success_total", success, metricLabels)
+ op.engine.MetricStorage.CounterAdd("{PREFIX}global_hook_allowed_errors_total", allowed, metricLabels)
+ op.engine.MetricStorage.CounterAdd("{PREFIX}global_hook_errors_total", errors, metricLabels)
+ op.engine.MetricStorage.CounterAdd("{PREFIX}global_hook_success_total", success, metricLabels)
}
if isSynchronization && res.Status == queue.Success {
@@ -1838,7 +1894,7 @@ func (op *AddonOperator) CreateReloadModulesTasks(moduleNames []string, logLabel
newTasks := make([]sh_task.Task, 0, len(moduleNames))
queuedAt := time.Now()
- queuedModuleNames := ModulesWithPendingModuleRun(op.TaskQueues.GetMain())
+ queuedModuleNames := ModulesWithPendingModuleRun(op.engine.TaskQueues.GetMain())
// Add ModuleRun tasks to reload only specific modules.
for _, moduleName := range moduleNames {
@@ -1916,7 +1972,7 @@ func (op *AddonOperator) CreateConvergeModulesTasks(state *module_manager.Module
// CheckConvergeStatus detects if converge process is started and
// updates ConvergeState. It updates metrics on converge finish.
func (op *AddonOperator) CheckConvergeStatus(t sh_task.Task) {
- convergeTasks := ConvergeTasksInQueue(op.TaskQueues.GetMain())
+ convergeTasks := ConvergeTasksInQueue(op.engine.TaskQueues.GetMain())
// Converge state is 'Started'. Update StartedAt and
// Activation if the converge process is just started.
@@ -1929,8 +1985,8 @@ func (op *AddonOperator) CheckConvergeStatus(t sh_task.Task) {
// reset StartedAt and Activation if the converge process is just stopped.
if convergeTasks == 0 && op.ConvergeState.StartedAt != 0 {
convergeSeconds := time.Duration(time.Now().UnixNano() - op.ConvergeState.StartedAt).Seconds()
- op.MetricStorage.CounterAdd("{PREFIX}convergence_seconds", convergeSeconds, map[string]string{"activation": op.ConvergeState.Activation})
- op.MetricStorage.CounterAdd("{PREFIX}convergence_total", 1.0, map[string]string{"activation": op.ConvergeState.Activation})
+ op.engine.MetricStorage.CounterAdd("{PREFIX}convergence_seconds", convergeSeconds, map[string]string{"activation": op.ConvergeState.Activation})
+ op.engine.MetricStorage.CounterAdd("{PREFIX}convergence_total", 1.0, map[string]string{"activation": op.ConvergeState.Activation})
op.ConvergeState.StartedAt = 0
op.ConvergeState.Activation = ""
}
@@ -1940,7 +1996,7 @@ func (op *AddonOperator) CheckConvergeStatus(t sh_task.Task) {
// Report modules left to process.
if convergeTasks > 0 && (t.GetType() == task.ModuleRun || t.GetType() == task.ModuleDelete) {
- moduleTasks := ConvergeModulesInQueue(op.TaskQueues.GetMain())
+ moduleTasks := ConvergeModulesInQueue(op.engine.TaskQueues.GetMain())
log.Infof("Converge modules in progress: %d modules left to process in queue 'main'", moduleTasks)
}
}
@@ -1965,11 +2021,6 @@ func (op *AddonOperator) UpdateFirstConvergeStatus(convergeTasks int) {
}
}
-func (op *AddonOperator) Shutdown() {
- op.KubeConfigManager.Stop()
- op.ShellOperator.Shutdown()
-}
-
// taskDescriptionForTaskFlowLog returns a human friendly description of the task.
func taskDescriptionForTaskFlowLog(tsk sh_task.Task, action string, phase string, status string) string {
hm := task.HookMetadataAccessor(tsk)
@@ -2139,7 +2190,7 @@ func (op *AddonOperator) OnFirstConvergeDone() {
// Let's add a short pause so that the service gets online and we don't get a rejection from the validation webhook (timeout reason)
time.Sleep(3 * time.Second) // wait for service to be resolved
- err := op.ModuleManager.SyncModulesCR(op.KubeConfigManager.KubeClient)
+ err := op.ModuleManager.SyncModulesCR(op.KubeClient())
if err != nil {
log.Errorf("Modules CR registration failed: %s", err)
}
@@ -2152,7 +2203,7 @@ func (op *AddonOperator) EmitModulesSync() {
return
}
- err := op.ModuleManager.SyncModulesCR(op.KubeConfigManager.KubeClient)
+ err := op.ModuleManager.SyncModulesCR(op.KubeClient())
if err != nil {
log.Errorf("Modules CR registration failed: %s", err)
}
diff --git a/pkg/addon-operator/operator_test.go b/pkg/addon-operator/operator_test.go
index b7829721..cde8eb4a 100644
--- a/pkg/addon-operator/operator_test.go
+++ b/pkg/addon-operator/operator_test.go
@@ -21,11 +21,11 @@ import (
mockhelmresmgr "github.com/flant/addon-operator/pkg/helm_resources_manager/test/mock"
. "github.com/flant/addon-operator/pkg/hook/types"
"github.com/flant/addon-operator/pkg/kube_config_manager"
+ "github.com/flant/addon-operator/pkg/kube_config_manager/backend/configmap"
"github.com/flant/addon-operator/pkg/module_manager"
"github.com/flant/addon-operator/pkg/task"
"github.com/flant/kube-client/fake"
. "github.com/flant/shell-operator/pkg/hook/types"
- shell_operator "github.com/flant/shell-operator/pkg/shell-operator"
sh_task "github.com/flant/shell-operator/pkg/task"
"github.com/flant/shell-operator/pkg/task/queue"
file_utils "github.com/flant/shell-operator/pkg/utils/file"
@@ -103,7 +103,7 @@ func assembleTestAddonOperator(t *testing.T, configPath string) (*AddonOperator,
// Assemble AddonOperator.
op := NewAddonOperator(context.Background())
- op.KubeClient = kubeClient
+ op.engine.KubeClient = kubeClient
// Mock helm client for ModuleManager
result.helmClient = &mockhelm.Client{}
op.Helm = mockhelm.NewClientFactory(result.helmClient)
@@ -111,15 +111,10 @@ func assembleTestAddonOperator(t *testing.T, configPath string) (*AddonOperator,
result.helmResourcesManager = &mockhelmresmgr.MockHelmResourcesManager{}
op.HelmResourcesManager = result.helmResourcesManager
- shell_operator.SetupEventManagers(op.ShellOperator)
+ op.engine.SetupEventManagers()
- kcfg := kube_config_manager.Config{
- Namespace: result.cmNamespace,
- ConfigMapName: result.cmName,
- KubeClient: op.KubeClient,
- RuntimeConfig: nil,
- }
- manager := kube_config_manager.NewKubeConfigManager(op.ctx, &kcfg)
+ bk := configmap.New(nil, op.engine.KubeClient, result.cmNamespace, result.cmName)
+ manager := kube_config_manager.NewKubeConfigManager(op.ctx, bk, op.runtimeConfig)
op.KubeConfigManager = manager
dirs := module_manager.DirectoryConfig{
@@ -129,9 +124,9 @@ func assembleTestAddonOperator(t *testing.T, configPath string) (*AddonOperator,
}
deps := module_manager.ModuleManagerDependencies{
KubeObjectPatcher: nil,
- KubeEventsManager: op.KubeEventsManager,
+ KubeEventsManager: op.engine.KubeEventsManager,
KubeConfigManager: manager,
- ScheduleManager: op.ScheduleManager,
+ ScheduleManager: op.engine.ScheduleManager,
Helm: op.Helm,
HelmResourcesManager: op.HelmResourcesManager,
MetricStorage: nil,
@@ -154,7 +149,7 @@ func convergeDone(op *AddonOperator) func(g Gomega) bool {
if op.IsStartupConvergeDone() {
return true
}
- mainQueue := op.TaskQueues.GetMain()
+ mainQueue := op.engine.TaskQueues.GetMain()
g.Expect(func() bool {
if mainQueue.IsEmpty() {
return true
@@ -173,7 +168,7 @@ func Test_Operator_startup_tasks(t *testing.T) {
op, _ := assembleTestAddonOperator(t, "startup_tasks")
- op.BootstrapMainQueue(op.TaskQueues)
+ op.BootstrapMainQueue(op.engine.TaskQueues)
expectTasks := []struct {
taskType sh_task.TaskType
@@ -197,7 +192,7 @@ func Test_Operator_startup_tasks(t *testing.T) {
}
i := 0
- op.TaskQueues.GetMain().Iterate(func(tsk sh_task.Task) {
+ op.engine.TaskQueues.GetMain().Iterate(func(tsk sh_task.Task) {
// Stop checking if no expects left.
if i >= len(expectTasks) {
return
@@ -221,7 +216,8 @@ func Test_Operator_ConvergeModules_main_queue_only(t *testing.T) {
log.SetLevel(log.ErrorLevel)
op, res := assembleTestAddonOperator(t, "converge__main_queue_only")
- op.BootstrapMainQueue(op.TaskQueues)
+
+ op.BootstrapMainQueue(op.engine.TaskQueues)
// Fill mocked helm with two releases: one to purge and one to disable during converge process.
moduleToPurge := "moduleToPurge"
@@ -238,7 +234,7 @@ func Test_Operator_ConvergeModules_main_queue_only(t *testing.T) {
}
taskHandleHistory := make([]taskInfo, 0)
- op.TaskQueues.GetMain().WithHandler(func(tsk sh_task.Task) queue.TaskResult {
+ op.engine.TaskQueues.GetMain().WithHandler(func(tsk sh_task.Task) queue.TaskResult {
// Put task info to history.
hm := task.HookMetadataAccessor(tsk)
phase := ""
@@ -260,7 +256,7 @@ func Test_Operator_ConvergeModules_main_queue_only(t *testing.T) {
return op.TaskHandler(tsk)
})
- op.TaskQueues.StartMain()
+ op.engine.TaskQueues.StartMain()
// Wait until converge is done.
g.Eventually(convergeDone(op), "30s", "200ms").Should(BeTrue())
@@ -355,7 +351,7 @@ func Test_HandleConvergeModules_global_changed_during_converge(t *testing.T) {
op, res := assembleTestAddonOperator(t, "converge__main_queue_only")
// Prefill main queue and start required managers.
- op.BootstrapMainQueue(op.TaskQueues)
+ op.BootstrapMainQueue(op.engine.TaskQueues)
op.KubeConfigManager.Start()
op.ModuleManager.Start()
@@ -377,7 +373,7 @@ func Test_HandleConvergeModules_global_changed_during_converge(t *testing.T) {
historyMu := new(sync.Mutex)
taskHandleHistory := make([]taskInfo, 0)
- op.TaskQueues.GetMain().WithHandler(func(tsk sh_task.Task) queue.TaskResult {
+ op.engine.TaskQueues.GetMain().WithHandler(func(tsk sh_task.Task) queue.TaskResult {
// Put task info to history.
hm := task.HookMetadataAccessor(tsk)
phase := ""
@@ -410,7 +406,7 @@ func Test_HandleConvergeModules_global_changed_during_converge(t *testing.T) {
})
// Start 'main' queue and wait for first converge.
- op.TaskQueues.StartMain()
+ op.engine.TaskQueues.StartMain()
// Emulate changing ConfigMap during converge.
go func() {
@@ -420,7 +416,7 @@ func Test_HandleConvergeModules_global_changed_during_converge(t *testing.T) {
"path": "/data/global",
"value": "param: newValue"}]`
- cmPatched, err := op.KubeClient.CoreV1().ConfigMaps(res.cmNamespace).Patch(context.TODO(),
+ cmPatched, err := op.engine.KubeClient.CoreV1().ConfigMaps(res.cmNamespace).Patch(context.TODO(),
res.cmName,
k8types.JSONPatchType,
[]byte(globalValuesChangePatch),
@@ -465,7 +461,7 @@ func Test_HandleConvergeModules_global_changed(t *testing.T) {
op, res := assembleTestAddonOperator(t, "converge__main_queue_only")
- op.BootstrapMainQueue(op.TaskQueues)
+ op.BootstrapMainQueue(op.engine.TaskQueues)
op.KubeConfigManager.Start()
op.ModuleManager.Start()
@@ -482,7 +478,7 @@ func Test_HandleConvergeModules_global_changed(t *testing.T) {
historyMu := new(sync.Mutex)
taskHandleHistory := make([]taskInfo, 0)
- op.TaskQueues.GetMain().WithHandler(func(tsk sh_task.Task) queue.TaskResult {
+ op.engine.TaskQueues.GetMain().WithHandler(func(tsk sh_task.Task) queue.TaskResult {
// Put task info to history.
hm := task.HookMetadataAccessor(tsk)
phase := ""
@@ -509,7 +505,7 @@ func Test_HandleConvergeModules_global_changed(t *testing.T) {
return op.TaskHandler(tsk)
})
- op.TaskQueues.StartMain()
+ op.engine.TaskQueues.StartMain()
g.Eventually(convergeDone(op), "30s", "200ms").Should(BeTrue())
@@ -523,7 +519,7 @@ func Test_HandleConvergeModules_global_changed(t *testing.T) {
"path": "/data/global",
"value": "param: newValue"}]`
- cmPatched, err := op.KubeClient.CoreV1().ConfigMaps(res.cmNamespace).Patch(context.TODO(),
+ cmPatched, err := op.engine.KubeClient.CoreV1().ConfigMaps(res.cmNamespace).Patch(context.TODO(),
res.cmName,
k8types.JSONPatchType,
[]byte(globalValuesChangePatch),
@@ -587,8 +583,8 @@ func Test_Operator_logTask(t *testing.T) {
log.AddHook(logHook)
op, _ := assembleTestAddonOperator(t, "log_task__wait_for_synchronization")
- op.BootstrapMainQueue(op.TaskQueues)
- op.TaskQueues.StartMain()
+ op.BootstrapMainQueue(op.engine.TaskQueues)
+ op.engine.TaskQueues.StartMain()
op.CreateAndStartQueuesForGlobalHooks()
// Wait until converge is done.
diff --git a/pkg/app/app.go b/pkg/app/app.go
index 1faa5501..47fdd876 100644
--- a/pkg/app/app.go
+++ b/pkg/app/app.go
@@ -14,8 +14,8 @@ var (
AppDescription = ""
Version = "dev"
- DefaultListenAddress = "0.0.0.0"
- DefaultListenPort = "9650"
+ ListenAddress = "0.0.0.0"
+ ListenPort = "9650"
DefaultPrometheusMetricsPrefix = "addon_operator_"
@@ -76,21 +76,16 @@ func DefineStartCommandFlags(kpApp *kingpin.Application, cmd *kingpin.CmdClause)
cmd.Flag("prometheus-listen-address", "Address to use to serve metrics to Prometheus.").
Envar("ADDON_OPERATOR_LISTEN_ADDRESS").
- Default(DefaultListenAddress).
- StringVar(&sh_app.ListenAddress)
+ Default(ListenAddress).
+ StringVar(&ListenAddress)
cmd.Flag("prometheus-listen-port", "Port to use to serve metrics to Prometheus.").
Envar("ADDON_OPERATOR_LISTEN_PORT").
- Default(DefaultListenPort).
- StringVar(&sh_app.ListenPort)
+ Default(ListenPort).
+ StringVar(&ListenPort)
cmd.Flag("prometheus-metrics-prefix", "Prefix for Prometheus metrics.").
Envar("ADDON_OPERATOR_PROMETHEUS_METRICS_PREFIX").
Default(DefaultPrometheusMetricsPrefix).
StringVar(&sh_app.PrometheusMetricsPrefix)
- cmd.Flag("hook-metrics-listen-port", "Port to use to serve hooks’ custom metrics to Prometheus. Can be set with $ADDON_OPERATOR_HOOK_METRICS_LISTEN_PORT. Equal to prometheus-listen-port if empty.").
- Envar("ADDON_OPERATOR_HOOK_METRICS_LISTEN_PORT").
- Default("").
- StringVar(&sh_app.HookMetricsListenPort)
-
cmd.Flag("helm-history-max", "Helm: limit the maximum number of revisions saved per release. Use 0 for no limit.").
Envar("HELM_HISTORY_MAX").
Default(strconv.Itoa(int(Helm3HistoryMax))).
diff --git a/pkg/app/debug-cmd.go b/pkg/app/debug-cmd.go
index 33d1fae9..8a306e65 100644
--- a/pkg/app/debug-cmd.go
+++ b/pkg/app/debug-cmd.go
@@ -13,90 +13,82 @@ var outputFormat = "text"
func DefineDebugCommands(kpApp *kingpin.Application) {
globalCmd := sh_app.CommandWithDefaultUsageTemplate(kpApp, "global", "manage global values")
+ globalCmd.Flag("output", "Output format: json|yaml.").Short('o').
+ Default("yaml").
+ EnumVar(&outputFormat, "json", "yaml", "text")
+ sh_app.DefineDebugUnixSocketFlag(globalCmd)
+ // -o json|yaml|text
- globalListCmd := globalCmd.Command("list", "List global hooks.").
+ globalCmd.Command("list", "List global hooks.").
Action(func(c *kingpin.ParseContext) error {
- dump, err := Global(sh_debug.DefaultClient()).List(outputFormat)
+ dump, err := globalRequest(sh_debug.DefaultClient()).List(outputFormat)
if err != nil {
return err
}
fmt.Println(string(dump))
return nil
})
- // -o json|yaml and --debug-unix-socket
- AddOutputJsonYamlFlag(globalListCmd)
- sh_app.DefineDebugUnixSocketFlag(globalListCmd)
- globalValuesCmd := globalCmd.Command("values", "Dump current global values.").
+ globalCmd.Command("values", "Dump current global values.").
Action(func(c *kingpin.ParseContext) error {
- dump, err := Global(sh_debug.DefaultClient()).Values(outputFormat)
+ dump, err := globalRequest(sh_debug.DefaultClient()).Values(outputFormat)
if err != nil {
return err
}
fmt.Println(string(dump))
return nil
})
- // -o json|yaml and --debug-unix-socket
- AddOutputJsonYamlFlag(globalValuesCmd)
- sh_app.DefineDebugUnixSocketFlag(globalValuesCmd)
- globalConfigCmd := globalCmd.Command("config", "Dump global config values.").
+ globalCmd.Command("config", "Dump global config values.").
Action(func(c *kingpin.ParseContext) error {
- dump, err := Global(sh_debug.DefaultClient()).Config(outputFormat)
+ dump, err := globalRequest(sh_debug.DefaultClient()).Config(outputFormat)
if err != nil {
return err
}
fmt.Println(string(dump))
return nil
})
- // -o json|yaml and --debug-unix-socket
- AddOutputJsonYamlFlag(globalConfigCmd)
- sh_app.DefineDebugUnixSocketFlag(globalConfigCmd)
- globalPatchesCmd := globalCmd.Command("patches", "Dump global value patches.").
+ globalCmd.Command("patches", "Dump global value patches.").
Action(func(c *kingpin.ParseContext) error {
- dump, err := Global(sh_debug.DefaultClient()).Patches()
+ dump, err := globalRequest(sh_debug.DefaultClient()).Patches()
if err != nil {
return err
}
fmt.Println(string(dump))
return nil
})
- // --debug-unix-socket
- sh_app.DefineDebugUnixSocketFlag(globalPatchesCmd)
- globalSnapshotsCmd := globalCmd.Command("snapshots", "Dump snapshots for all global hooks.").
+ globalCmd.Command("snapshots", "Dump snapshots for all global hooks.").
Action(func(c *kingpin.ParseContext) error {
- out, err := Global(sh_debug.DefaultClient()).Snapshots(outputFormat)
+ out, err := globalRequest(sh_debug.DefaultClient()).Snapshots(outputFormat)
if err != nil {
return err
}
fmt.Println(string(out))
return nil
})
- // -o json|yaml and --debug-unix-socket
- AddOutputJsonYamlFlag(globalSnapshotsCmd)
- sh_app.DefineDebugUnixSocketFlag(globalSnapshotsCmd)
moduleCmd := sh_app.CommandWithDefaultUsageTemplate(kpApp, "module", "List modules and dump their values")
+ moduleCmd.Flag("output", "Output format: json|yaml.").Short('o').
+ Default("yaml").
+ EnumVar(&outputFormat, "json", "yaml", "text")
+ sh_app.DefineDebugUnixSocketFlag(moduleCmd)
- moduleListCmd := moduleCmd.Command("list", "List available modules and their enabled status.").
+ moduleCmd.Command("list", "List available modules and their enabled status.").
Action(func(c *kingpin.ParseContext) error {
- modules, err := Module(sh_debug.DefaultClient()).List(outputFormat)
+ modules, err := moduleRequest(sh_debug.DefaultClient()).List(outputFormat)
if err != nil {
return err
}
fmt.Println(string(modules))
return nil
})
- // -o json|yaml|text and --debug-unix-socket
- sh_debug.AddOutputJsonYamlTextFlag(moduleListCmd)
- sh_app.DefineDebugUnixSocketFlag(moduleListCmd)
var moduleName string
moduleValuesCmd := moduleCmd.Command("values", "Dump module values by name.").
Action(func(c *kingpin.ParseContext) error {
- dump, err := Module(sh_debug.DefaultClient()).Name(moduleName).Values(outputFormat)
+ dump, err := moduleRequest(sh_debug.DefaultClient()).Name(moduleName).Values(outputFormat)
if err != nil {
return err
}
@@ -104,14 +96,11 @@ func DefineDebugCommands(kpApp *kingpin.Application) {
return nil
})
moduleValuesCmd.Arg("module_name", "").Required().StringVar(&moduleName)
- // -o json|yaml and --debug-unix-socket
- AddOutputJsonYamlFlag(moduleValuesCmd)
- sh_app.DefineDebugUnixSocketFlag(moduleValuesCmd)
var debug bool
moduleRenderCmd := moduleCmd.Command("render", "Render module manifests.").
Action(func(c *kingpin.ParseContext) error {
- dump, err := Module(sh_debug.DefaultClient()).Name(moduleName).Render(debug)
+ dump, err := moduleRequest(sh_debug.DefaultClient()).Name(moduleName).Render(debug)
if err != nil {
return err
}
@@ -120,12 +109,10 @@ func DefineDebugCommands(kpApp *kingpin.Application) {
})
moduleRenderCmd.Arg("module_name", "").Required().StringVar(&moduleName)
moduleRenderCmd.Flag("debug", "enable debug mode").Default("false").BoolVar(&debug)
- AddOutputJsonYamlFlag(moduleRenderCmd)
- sh_app.DefineDebugUnixSocketFlag(moduleRenderCmd)
moduleConfigCmd := moduleCmd.Command("config", "Dump module config values by name.").
Action(func(c *kingpin.ParseContext) error {
- dump, err := Module(sh_debug.DefaultClient()).Name(moduleName).Config(outputFormat)
+ dump, err := moduleRequest(sh_debug.DefaultClient()).Name(moduleName).Config(outputFormat)
if err != nil {
return err
}
@@ -133,13 +120,10 @@ func DefineDebugCommands(kpApp *kingpin.Application) {
return nil
})
moduleConfigCmd.Arg("module_name", "").Required().StringVar(&moduleName)
- // -o json|yaml and --debug-unix-socket
- AddOutputJsonYamlFlag(moduleConfigCmd)
- sh_app.DefineDebugUnixSocketFlag(moduleConfigCmd)
modulePatchesCmd := moduleCmd.Command("patches", "Dump module value patches by name.").
Action(func(c *kingpin.ParseContext) error {
- dump, err := Module(sh_debug.DefaultClient()).Name(moduleName).Patches()
+ dump, err := moduleRequest(sh_debug.DefaultClient()).Name(moduleName).Patches()
if err != nil {
return err
}
@@ -147,12 +131,10 @@ func DefineDebugCommands(kpApp *kingpin.Application) {
return nil
})
modulePatchesCmd.Arg("module_name", "").Required().StringVar(&moduleName)
- // --debug-unix-socket
- sh_app.DefineDebugUnixSocketFlag(modulePatchesCmd)
moduleResourceMonitorCmd := moduleCmd.Command("resource-monitor", "Dump resource monitors.").
Action(func(c *kingpin.ParseContext) error {
- out, err := Module(sh_debug.DefaultClient()).Name(moduleName).ResourceMonitor(outputFormat)
+ out, err := moduleRequest(sh_debug.DefaultClient()).Name(moduleName).ResourceMonitor(outputFormat)
if err != nil {
return err
}
@@ -160,13 +142,10 @@ func DefineDebugCommands(kpApp *kingpin.Application) {
return nil
})
moduleResourceMonitorCmd.Arg("module_name", "").StringVar(&moduleName)
- // -o json|yaml and --debug-unix-socket
- AddOutputJsonYamlFlag(moduleResourceMonitorCmd)
- sh_app.DefineDebugUnixSocketFlag(moduleResourceMonitorCmd)
moduleSnapshotsCmd := moduleCmd.Command("snapshots", "Dump snapshots for all hooks.").
Action(func(c *kingpin.ParseContext) error {
- out, err := Module(sh_debug.DefaultClient()).Name(moduleName).Snapshots(outputFormat)
+ out, err := moduleRequest(sh_debug.DefaultClient()).Name(moduleName).Snapshots(outputFormat)
if err != nil {
return err
}
@@ -174,94 +153,85 @@ func DefineDebugCommands(kpApp *kingpin.Application) {
return nil
})
moduleSnapshotsCmd.Arg("module_name", "").Required().StringVar(&moduleName)
- // -o json|yaml and --debug-unix-socket
- AddOutputJsonYamlFlag(moduleSnapshotsCmd)
- sh_app.DefineDebugUnixSocketFlag(moduleSnapshotsCmd)
-}
-
-func AddOutputJsonYamlFlag(cmd *kingpin.CmdClause) {
- cmd.Flag("output", "Output format: json|yaml.").Short('o').
- Default("yaml").
- EnumVar(&outputFormat, "json", "yaml")
}
-type GlobalRequest struct {
+type cliGlobalSectionRequest struct {
client *sh_debug.Client
}
-func Global(client *sh_debug.Client) *GlobalRequest {
- return &GlobalRequest{client: client}
+func globalRequest(client *sh_debug.Client) *cliGlobalSectionRequest {
+ return &cliGlobalSectionRequest{client: client}
}
-func (gr *GlobalRequest) List(format string) ([]byte, error) {
+func (gr *cliGlobalSectionRequest) List(format string) ([]byte, error) {
url := fmt.Sprintf("http://unix/global/list.%s", format)
return gr.client.Get(url)
}
-func (gr *GlobalRequest) Values(format string) ([]byte, error) {
+func (gr *cliGlobalSectionRequest) Values(format string) ([]byte, error) {
url := fmt.Sprintf("http://unix/global/values.%s", format)
return gr.client.Get(url)
}
-func (gr *GlobalRequest) Config(format string) ([]byte, error) {
+func (gr *cliGlobalSectionRequest) Config(format string) ([]byte, error) {
url := fmt.Sprintf("http://unix/global/config.%s", format)
return gr.client.Get(url)
}
-func (gr *GlobalRequest) Patches() ([]byte, error) {
+func (gr *cliGlobalSectionRequest) Patches() ([]byte, error) {
return gr.client.Get("http://unix/global/patches.json")
}
-func (gr *GlobalRequest) Snapshots(format string) ([]byte, error) {
+func (gr *cliGlobalSectionRequest) Snapshots(format string) ([]byte, error) {
url := fmt.Sprintf("http://unix/global/snapshots.%s", format)
return gr.client.Get(url)
}
-type ModuleRequest struct {
+type cliModuleSectionRequest struct {
client *sh_debug.Client
name string
}
-func Module(client *sh_debug.Client) *ModuleRequest {
- return &ModuleRequest{client: client}
+func moduleRequest(client *sh_debug.Client) *cliModuleSectionRequest {
+ return &cliModuleSectionRequest{client: client}
}
-func (mr *ModuleRequest) List(format string) ([]byte, error) {
+func (mr *cliModuleSectionRequest) List(format string) ([]byte, error) {
url := fmt.Sprintf("http://unix/module/list.%s", format)
return mr.client.Get(url)
}
-func (mr *ModuleRequest) ResourceMonitor(format string) ([]byte, error) {
+func (mr *cliModuleSectionRequest) ResourceMonitor(format string) ([]byte, error) {
url := fmt.Sprintf("http://unix/module/resource-monitor.%s", format)
return mr.client.Get(url)
}
-func (mr *ModuleRequest) Name(name string) *ModuleRequest {
+func (mr *cliModuleSectionRequest) Name(name string) *cliModuleSectionRequest {
mr.name = name
return mr
}
-func (mr *ModuleRequest) Values(format string) ([]byte, error) {
+func (mr *cliModuleSectionRequest) Values(format string) ([]byte, error) {
url := fmt.Sprintf("http://unix/module/%s/values.%s", mr.name, format)
return mr.client.Get(url)
}
-func (mr *ModuleRequest) Render(debug bool) ([]byte, error) {
+func (mr *cliModuleSectionRequest) Render(debug bool) ([]byte, error) {
url := fmt.Sprintf("http://unix/module/%s/render?debug=%t", mr.name, debug)
return mr.client.Get(url)
}
-func (mr *ModuleRequest) Patches() ([]byte, error) {
+func (mr *cliModuleSectionRequest) Patches() ([]byte, error) {
url := fmt.Sprintf("http://unix/module/%s/patches.json", mr.name)
return mr.client.Get(url)
}
-func (mr *ModuleRequest) Config(format string) ([]byte, error) {
+func (mr *cliModuleSectionRequest) Config(format string) ([]byte, error) {
url := fmt.Sprintf("http://unix/module/%s/config.%s", mr.name, format)
return mr.client.Get(url)
}
-func (mr *ModuleRequest) Snapshots(format string) ([]byte, error) {
+func (mr *cliModuleSectionRequest) Snapshots(format string) ([]byte, error) {
url := fmt.Sprintf("http://unix/module/%s/snapshots.%s", mr.name, format)
return mr.client.Get(url)
}
diff --git a/pkg/helm/helm.go b/pkg/helm/helm.go
index 2fde0172..6940f040 100644
--- a/pkg/helm/helm.go
+++ b/pkg/helm/helm.go
@@ -21,7 +21,7 @@ func (f *ClientFactory) NewClient(logLabels ...map[string]string) client.HelmCli
return nil
}
-func InitHelmClientFactory(kubeClient klient.Client) (*ClientFactory, error) {
+func InitHelmClientFactory(kubeClient *klient.Client) (*ClientFactory, error) {
helmVersion, err := DetectHelmVersion()
if err != nil {
return nil, err
diff --git a/pkg/helm/helm3/helm3.go b/pkg/helm/helm3/helm3.go
index 544f07fe..cf43628a 100644
--- a/pkg/helm/helm3/helm3.go
+++ b/pkg/helm/helm3/helm3.go
@@ -27,7 +27,7 @@ type Helm3Options struct {
Namespace string
HistoryMax int32
Timeout time.Duration
- KubeClient klient.Client
+ KubeClient *klient.Client
}
var Options *Helm3Options
@@ -46,7 +46,7 @@ func Init(options *Helm3Options) error {
}
type Helm3Client struct {
- KubeClient klient.Client
+ KubeClient *klient.Client
LogEntry *log.Entry
Namespace string
}
@@ -66,7 +66,7 @@ func NewClient(logLabels ...map[string]string) client.HelmClient {
}
}
-func (h *Helm3Client) WithKubeClient(client klient.Client) {
+func (h *Helm3Client) WithKubeClient(client *klient.Client) {
h.KubeClient = client
}
diff --git a/pkg/helm/helm3lib/helm3lib.go b/pkg/helm/helm3lib/helm3lib.go
index b54b78c1..daa5b303 100644
--- a/pkg/helm/helm3lib/helm3lib.go
+++ b/pkg/helm/helm3lib/helm3lib.go
@@ -37,7 +37,7 @@ func Init(opts *Options) {
// LibClient use helm3 package as Go library.
type LibClient struct {
- KubeClient klient.Client
+ KubeClient *klient.Client
LogEntry *log.Entry
Namespace string
}
@@ -46,7 +46,7 @@ type Options struct {
Namespace string
HistoryMax int32
Timeout time.Duration
- KubeClient klient.Client
+ KubeClient *klient.Client
}
var (
diff --git a/pkg/helm_resources_manager/helm_resources_manager.go b/pkg/helm_resources_manager/helm_resources_manager.go
index 3654ac7f..0b88d4f6 100644
--- a/pkg/helm_resources_manager/helm_resources_manager.go
+++ b/pkg/helm_resources_manager/helm_resources_manager.go
@@ -12,7 +12,7 @@ import (
type HelmResourcesManager interface {
WithContext(ctx context.Context)
- WithKubeClient(client klient.Client)
+ WithKubeClient(client *klient.Client)
WithDefaultNamespace(namespace string)
Stop()
StopMonitors()
@@ -35,7 +35,7 @@ type helmResourcesManager struct {
Namespace string
- kubeClient klient.Client
+ kubeClient *klient.Client
monitors map[string]*ResourcesMonitor
@@ -51,7 +51,7 @@ func NewHelmResourcesManager() HelmResourcesManager {
}
}
-func (hm *helmResourcesManager) WithKubeClient(client klient.Client) {
+func (hm *helmResourcesManager) WithKubeClient(client *klient.Client) {
hm.kubeClient = client
}
diff --git a/pkg/helm_resources_manager/resources_monitor.go b/pkg/helm_resources_manager/resources_monitor.go
index 20cdbd65..a19240d6 100644
--- a/pkg/helm_resources_manager/resources_monitor.go
+++ b/pkg/helm_resources_manager/resources_monitor.go
@@ -28,7 +28,7 @@ type ResourcesMonitor struct {
manifests []manifest.Manifest
defaultNamespace string
- kubeClient klient.Client
+ kubeClient *klient.Client
logLabels map[string]string
absentCb func(moduleName string, absent []manifest.Manifest, defaultNs string)
@@ -52,7 +52,7 @@ func (r *ResourcesMonitor) Stop() {
}
}
-func (r *ResourcesMonitor) WithKubeClient(client klient.Client) {
+func (r *ResourcesMonitor) WithKubeClient(client *klient.Client) {
r.kubeClient = client
}
diff --git a/pkg/helm_resources_manager/test/mock/mock.go b/pkg/helm_resources_manager/test/mock/mock.go
index 3da4f82b..6778f161 100644
--- a/pkg/helm_resources_manager/test/mock/mock.go
+++ b/pkg/helm_resources_manager/test/mock/mock.go
@@ -15,7 +15,7 @@ type MockHelmResourcesManager struct {
func (h *MockHelmResourcesManager) WithContext(_ context.Context) {}
-func (h *MockHelmResourcesManager) WithKubeClient(_ klient.Client) {}
+func (h *MockHelmResourcesManager) WithKubeClient(_ *klient.Client) {}
func (h *MockHelmResourcesManager) WithDefaultNamespace(_ string) {}
diff --git a/pkg/kube_config_manager/access_config_map.go b/pkg/kube_config_manager/access_config_map.go
deleted file mode 100644
index 818d8317..00000000
--- a/pkg/kube_config_manager/access_config_map.go
+++ /dev/null
@@ -1,76 +0,0 @@
-package kube_config_manager
-
-import (
- "context"
-
- v1 "k8s.io/api/core/v1"
- "k8s.io/apimachinery/pkg/api/errors"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-
- "github.com/flant/addon-operator/pkg/utils"
- klient "github.com/flant/kube-client/client"
-)
-
-// ConfigMapGet gets the ConfigMap object from the cluster.
-func ConfigMapGet(kubeClient klient.Client, namespace string, name string) (*v1.ConfigMap, error) {
- obj, err := kubeClient.CoreV1().
- ConfigMaps(namespace).
- Get(context.TODO(), name, metav1.GetOptions{})
-
- if errors.IsNotFound(err) {
- return nil, nil
- }
- if err != nil {
- return nil, err
- }
-
- return obj, err
-}
-
-// ConfigMapUpdate gets the ConfigMap object from the cluster,
-// call transformation callback and save modified object.
-func ConfigMapUpdate(kubeClient klient.Client, namespace string, name string, transformFn func(*v1.ConfigMap) error) error {
- var err error
-
- obj, err := ConfigMapGet(kubeClient, namespace, name)
- if err != nil {
- return nil
- }
-
- isUpdate := true
- if obj == nil {
- obj = &v1.ConfigMap{}
- obj.Name = name
- isUpdate = false
- }
-
- if obj.Data == nil {
- obj.Data = make(map[string]string)
- }
-
- err = transformFn(obj)
- if err != nil {
- return err
- }
-
- if isUpdate {
- _, err = kubeClient.CoreV1().ConfigMaps(namespace).Update(context.TODO(), obj, metav1.UpdateOptions{})
- } else {
- _, err = kubeClient.CoreV1().ConfigMaps(namespace).Create(context.TODO(), obj, metav1.CreateOptions{})
- }
- return err
-}
-
-// ConfigMapMergeValues is a helper to use ConfigMapUpdate to save Values object in the ConfigMap.
-func ConfigMapMergeValues(kubeClient klient.Client, namespace string, name string, values utils.Values) error {
- cmData, err := values.AsConfigMapData()
- if err != nil {
- return err
- }
- return ConfigMapUpdate(kubeClient, namespace, name, func(obj *v1.ConfigMap) error {
- for k, v := range cmData {
- obj.Data[k] = v
- }
- return nil
- })
-}
diff --git a/pkg/kube_config_manager/backend/backend.go b/pkg/kube_config_manager/backend/backend.go
new file mode 100644
index 00000000..93206dcc
--- /dev/null
+++ b/pkg/kube_config_manager/backend/backend.go
@@ -0,0 +1,21 @@
+package backend
+
+import (
+ "context"
+
+ "github.com/flant/addon-operator/pkg/kube_config_manager/config"
+ "github.com/flant/addon-operator/pkg/utils"
+)
+
+// ConfigHandler load and saves(optional) configuration for module
+type ConfigHandler interface {
+ // StartInformer starts backend watcher which follows a resource, parse and send module/modules values for kube_config_manager
+ StartInformer(ctx context.Context, eventC chan config.Event)
+
+ // LoadConfig loads initial modules config before starting the informer
+ LoadConfig(ctx context.Context) (*config.KubeConfig, error)
+
+ // SaveConfigValues saves patches for modules in backend (if supported), overriding the configuration
+ // Deprecated: saving values in the values source is not recommended and shouldn't be used anymore
+ SaveConfigValues(ctx context.Context, key string, values utils.Values) ( /*checksum*/ string, error)
+}
diff --git a/pkg/kube_config_manager/backend/configmap/configmap.go b/pkg/kube_config_manager/backend/configmap/configmap.go
new file mode 100644
index 00000000..f4fdcc53
--- /dev/null
+++ b/pkg/kube_config_manager/backend/configmap/configmap.go
@@ -0,0 +1,389 @@
+package configmap
+
+import (
+ "context"
+ "fmt"
+ "strings"
+ "time"
+
+ dlogger "github.com/distribution/distribution/v3/context"
+ log "github.com/sirupsen/logrus"
+ "gopkg.in/yaml.v3"
+ v1 "k8s.io/api/core/v1"
+ "k8s.io/apimachinery/pkg/api/errors"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/fields"
+ corev1 "k8s.io/client-go/informers/core/v1"
+ "k8s.io/client-go/tools/cache"
+
+ "github.com/flant/addon-operator/pkg/kube_config_manager/config"
+ "github.com/flant/addon-operator/pkg/utils"
+ "github.com/flant/kube-client/client"
+)
+
+// Backend implements ConfigMap backend for kube_config_manager
+type Backend struct {
+ namespace string
+ name string
+
+ logger dlogger.Logger
+ client *client.Client
+}
+
+// New initializes backend for kube_config_manager based on ConfigMap with modules values
+func New(logger dlogger.Logger, kubeClient *client.Client, namespace, name string) *Backend {
+ if logger == nil {
+ logger = log.WithField("operator.component", "ConfigHandler").WithField("backend", "configmap")
+ }
+
+ backend := &Backend{
+ logger: logger,
+ namespace: namespace,
+ name: name,
+ client: kubeClient,
+ }
+
+ return backend
+}
+
+// LoadConfig gets config from ConfigMap before starting informer.
+// Set checksums for global section and modules.
+func (b Backend) LoadConfig(ctx context.Context) (*config.KubeConfig, error) {
+ obj, err := b.getConfigMap(ctx)
+ if err != nil {
+ return nil, err
+ }
+
+ if obj == nil {
+ b.logger.Infof("Initial config from ConfigMap/%s: resource is not found", b.name)
+ return nil, nil
+ }
+
+ return parseConfigMapData(obj.Data)
+}
+
+// SaveConfigValues saves patches in the ConfigMap
+func (b Backend) SaveConfigValues(ctx context.Context, key string, values utils.Values) ( /*checksum*/ string, error) {
+ if key == utils.GlobalValuesKey {
+ return b.saveGlobalConfigValues(ctx, values)
+ }
+
+ return b.saveModuleConfigValues(ctx, key, values)
+}
+
+func (b Backend) saveGlobalConfigValues(ctx context.Context, values utils.Values) ( /*checksum*/ string, error) {
+ globalKubeConfig, err := config.ParseGlobalKubeConfigFromValues(values)
+ if err != nil {
+ return "", err
+ }
+ if globalKubeConfig == nil {
+ return "", nil
+ }
+
+ if b.isDebugEnabled(ctx) {
+ b.logger.Infof("Save global values to ConfigMap/%s:\n%s", b.name, values.DebugString())
+ } else {
+ b.logger.Infof("Save global values to ConfigMap/%s", b.name)
+ }
+
+ err = b.mergeValues(ctx, globalKubeConfig.GetValues())
+
+ return globalKubeConfig.Checksum, err
+}
+
+func (b Backend) isDebugEnabled(ctx context.Context) bool {
+ debug, ok := ctx.Value("kube-config-manager-debug").(bool)
+ if !ok {
+ return false
+ }
+
+ return debug
+}
+
+// saveModuleConfigValues updates module section in ConfigMap.
+// It uses knownChecksums to prevent KubeConfigChanged event on self-update.
+func (b Backend) saveModuleConfigValues(ctx context.Context, moduleName string, values utils.Values) ( /*checksum*/ string, error) {
+ moduleKubeConfig := config.ParseModuleKubeConfigFromValues(moduleName, values)
+
+ if moduleKubeConfig == nil {
+ return "", nil
+ }
+
+ if b.isDebugEnabled(ctx) {
+ b.logger.Infof("Save module '%s' values to ConfigMap/%s:\n%s", moduleName, b.name, values.DebugString())
+ } else {
+ b.logger.Infof("Save module '%s' values to ConfigMap/%s", moduleName, b.name)
+ }
+
+ err := b.mergeValues(ctx, moduleKubeConfig.GetValues())
+
+ return moduleKubeConfig.Checksum, err
+}
+
+func (b Backend) getConfigMap(ctx context.Context) (*v1.ConfigMap, error) {
+ obj, err := b.client.CoreV1().
+ ConfigMaps(b.namespace).
+ Get(ctx, b.name, metav1.GetOptions{})
+
+ if errors.IsNotFound(err) {
+ return nil, nil
+ }
+ if err != nil {
+ return nil, err
+ }
+
+ return obj, err
+}
+
+func parseConfigMapData(data map[string]string) (cfg *config.KubeConfig, err error) {
+ cfg = config.NewConfig()
+ // Parse values in global section.
+ cfg.Global, err = getGlobalKubeConfigFromConfigData(data)
+ if err != nil {
+ return nil, err
+ }
+
+ moduleNames, err := getModulesNamesFromConfigData(data)
+ if err != nil {
+ return nil, err
+ }
+
+ for moduleName := range moduleNames {
+ cfg.Modules[moduleName], err = extractModuleKubeConfig(moduleName, data)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ return cfg, nil
+}
+
+func getGlobalKubeConfigFromConfigData(configData map[string]string) (*config.GlobalKubeConfig, error) {
+ yamlData, hasKey := configData[utils.GlobalValuesKey]
+ if !hasKey {
+ return nil, nil
+ }
+
+ values, err := utils.NewGlobalValues(yamlData)
+ if err != nil {
+ return nil, fmt.Errorf("ConfigMap: bad yaml at key '%s': %s:\n%s", utils.GlobalValuesKey, err, yamlData)
+ }
+
+ checksum := values.Checksum()
+
+ return &config.GlobalKubeConfig{
+ Values: values,
+ Checksum: checksum,
+ }, nil
+}
+
+// getModulesNamesFromConfigData returns all keys in kube config except global
+// modNameEnabled keys are also handled
+func getModulesNamesFromConfigData(configData map[string]string) (map[string]bool, error) {
+ res := make(map[string]bool)
+
+ for key := range configData {
+ // Ignore global section.
+ if key == utils.GlobalValuesKey {
+ continue
+ }
+
+ // Treat Enabled flags as module section.
+ key = strings.TrimSuffix(key, "Enabled")
+
+ modName := utils.ModuleNameFromValuesKey(key)
+
+ if utils.ModuleNameToValuesKey(modName) != key {
+ return nil, fmt.Errorf("bad module name '%s': should be camelCased", key)
+ }
+ res[modName] = true
+ }
+
+ return res, nil
+}
+
+// extractModuleKubeConfig returns ModuleKubeConfig with values loaded from ConfigMap
+func extractModuleKubeConfig(moduleName string, configData map[string]string) (*config.ModuleKubeConfig, error) {
+ moduleConfig, err := fromConfigMapData(moduleName, configData)
+ if err != nil {
+ return nil, fmt.Errorf("bad yaml at key '%s': %s", utils.ModuleNameToValuesKey(moduleName), err)
+ }
+ // NOTE this should never happen because of GetModulesNamesFromConfigData
+ if moduleConfig == nil {
+ return nil, fmt.Errorf("possible bug!!! No section '%s' for module '%s'", utils.ModuleNameToValuesKey(moduleName), moduleName)
+ }
+
+ return &config.ModuleKubeConfig{
+ ModuleConfig: *moduleConfig,
+ Checksum: moduleConfig.Checksum(),
+ }, nil
+}
+
+// fromConfigMapData loads module config from a structure with string keys and yaml string values (ConfigMap)
+//
+// Example:
+//
+// simpleModule: |
+//
+// param1: 10
+// param2: 120
+//
+// simpleModuleEnabled: "true"
+func fromConfigMapData(moduleName string, configData map[string]string) (*utils.ModuleConfig, error) {
+ mc := utils.NewModuleConfig(moduleName, nil)
+ // create Values with moduleNameKey and moduleEnabled keys
+ configValues := make(utils.Values)
+
+ // if there is data for module, unmarshal it and put into configValues
+ valuesYaml, hasKey := configData[mc.ModuleConfigKey()]
+ if hasKey {
+ var moduleValues interface{}
+
+ err := yaml.Unmarshal([]byte(valuesYaml), &moduleValues)
+ if err != nil {
+ return nil, fmt.Errorf("unmarshal yaml data in a module config key '%s': %v", mc.ModuleConfigKey(), err)
+ }
+
+ configValues[mc.ModuleConfigKey()] = moduleValues
+ }
+
+ // if there is enabled key, treat it as boolean
+ enabledString, hasKey := configData[mc.ModuleEnabledKey()]
+ if hasKey {
+ var enabled bool
+
+ switch enabledString {
+ case "true":
+ enabled = true
+ case "false":
+ enabled = false
+ default:
+ return nil, fmt.Errorf("module enabled key '%s' should have a boolean value, got '%v'", mc.ModuleEnabledKey(), enabledString)
+ }
+
+ configValues[mc.ModuleEnabledKey()] = enabled
+ }
+
+ if len(configValues) == 0 {
+ return mc, nil
+ }
+
+ return mc.LoadFromValues(configValues)
+}
+
+func (b Backend) mergeValues(ctx context.Context, values utils.Values) error {
+ cmData, err := values.AsConfigMapData()
+ if err != nil {
+ return err
+ }
+ return b.updateConfigMap(ctx, func(obj *v1.ConfigMap) error {
+ for k, v := range cmData {
+ obj.Data[k] = v
+ }
+ return nil
+ })
+}
+
+func (b Backend) updateConfigMap(ctx context.Context, transformFn func(*v1.ConfigMap) error) error {
+ var err error
+
+ obj, err := b.getConfigMap(ctx)
+ if err != nil {
+ return nil
+ }
+
+ isUpdate := true
+ if obj == nil {
+ obj = &v1.ConfigMap{}
+ obj.Name = b.name
+ isUpdate = false
+ }
+
+ if obj.Data == nil {
+ obj.Data = make(map[string]string)
+ }
+
+ err = transformFn(obj)
+ if err != nil {
+ return err
+ }
+
+ if isUpdate {
+ _, err = b.client.CoreV1().ConfigMaps(b.namespace).Update(ctx, obj, metav1.UpdateOptions{})
+ } else {
+ _, err = b.client.CoreV1().ConfigMaps(b.namespace).Create(ctx, obj, metav1.CreateOptions{})
+ }
+ return err
+}
+
+func (b Backend) StartInformer(ctx context.Context, eventC chan config.Event) {
+ // define resyncPeriod for informer
+ resyncPeriod := time.Duration(5) * time.Minute
+
+ // define indexers for informer
+ indexers := cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}
+
+ // define tweakListOptions for informer
+ tweakListOptions := func(options *metav1.ListOptions) {
+ options.FieldSelector = fields.OneTermEqualSelector("metadata.name", b.name).String()
+ }
+
+ cmInformer := corev1.NewFilteredConfigMapInformer(b.client, b.namespace, resyncPeriod, indexers, tweakListOptions)
+ _, _ = cmInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{
+ AddFunc: func(obj interface{}) {
+ b.logConfigMapEvent(ctx, obj, "add")
+ err := b.handleConfigMapEvent(obj.(*v1.ConfigMap), eventC)
+ if err != nil {
+ b.logger.Errorf("Handle ConfigMap/%s 'add' error: %s", b.name, err)
+ }
+ },
+ UpdateFunc: func(prevObj interface{}, obj interface{}) {
+ b.logConfigMapEvent(ctx, obj, "update")
+ err := b.handleConfigMapEvent(obj.(*v1.ConfigMap), eventC)
+ if err != nil {
+ b.logger.Errorf("Handle ConfigMap/%s 'update' error: %s", b.name, err)
+ }
+ },
+ DeleteFunc: func(obj interface{}) {
+ b.logConfigMapEvent(ctx, obj, "delete")
+ _ = b.handleConfigMapEvent(nil, eventC)
+ },
+ })
+
+ go func() {
+ cmInformer.Run(ctx.Done())
+ }()
+}
+
+func (b Backend) logConfigMapEvent(ctx context.Context, obj interface{}, eventName string) {
+ if !b.isDebugEnabled(ctx) {
+ return
+ }
+
+ objYaml, err := yaml.Marshal(obj)
+ if err != nil {
+ b.logger.Infof("Dump ConfigMap/%s '%s' error: %s", b.name, eventName, err)
+ return
+ }
+ b.logger.Infof("Dump ConfigMap/%s '%s':\n%s", b.name, eventName, objYaml)
+}
+
+func (b Backend) handleConfigMapEvent(obj *v1.ConfigMap, eventC chan config.Event) error {
+ // ConfigMap is deleted, reset cached config and fire event.
+ if obj == nil {
+ eventC <- config.Event{Key: ""}
+ return nil
+ }
+
+ newConfig, err := parseConfigMapData(obj.Data)
+ if err != nil {
+ eventC <- config.Event{Key: "batch", Err: err}
+ // Do not update caches to detect changes on next update.
+ b.logger.Errorf("ConfigMap/%s invalid: %v", b.name, err)
+ return err
+ }
+
+ eventC <- config.Event{Key: "batch", Config: newConfig}
+
+ return nil
+}
diff --git a/pkg/kube_config_manager/config_test.go b/pkg/kube_config_manager/backend/configmap/configmap_test.go
similarity index 82%
rename from pkg/kube_config_manager/config_test.go
rename to pkg/kube_config_manager/backend/configmap/configmap_test.go
index 7c51dc97..b8aaab61 100644
--- a/pkg/kube_config_manager/config_test.go
+++ b/pkg/kube_config_manager/backend/configmap/configmap_test.go
@@ -1,4 +1,4 @@
-package kube_config_manager
+package configmap
import (
"testing"
@@ -6,41 +6,28 @@ import (
"github.com/stretchr/testify/assert"
)
-func Test_ParseCM_Nil(t *testing.T) {
- cfg, err := ParseConfigMapData(nil)
- assert.NoError(t, err, "Should parse nil data correctly")
- assert.NotNil(t, cfg, "Config should not be nil for nil data")
- assert.Nil(t, cfg.Global, "No global config should present for nil data")
- assert.NotNil(t, cfg.Modules, "Modules should not be nil for nil data")
- assert.Len(t, cfg.Modules, 0, "No module configs should present for nil data")
-}
-
-func Test_ParseCM_Empty(t *testing.T) {
- cfg, err := ParseConfigMapData(map[string]string{})
- assert.NoError(t, err, "Should parse empty data correctly")
- assert.NotNil(t, cfg, "Config should not be nil for empty data")
- assert.Nil(t, cfg.Global, "No global config should present for empty data")
- assert.NotNil(t, cfg.Modules, "Modules should not be nil for empty data")
- assert.Len(t, cfg.Modules, 0, "No module configs should present for empty data")
-}
+func Test_ParseCM_Malformed_Data(t *testing.T) {
+ var err error
-func Test_ParseCM_only_Global(t *testing.T) {
- cfg, err := ParseConfigMapData(map[string]string{
- "global": `
+ _, err = parseConfigMapData(map[string]string{
+ "Malformed-section-name": `
param1: val1
param2: val2
`,
})
- assert.NoError(t, err, "Should parse global only data correctly")
- assert.NotNil(t, cfg, "Config should not be nil for global only data")
- assert.NotNil(t, cfg.Global, "Global config should present for global only data")
- assert.True(t, cfg.Global.Values.HasGlobal(), "Config should have global values for global only data")
- assert.NotNil(t, cfg.Modules, "Modules should not be nil for global only data")
- assert.Len(t, cfg.Modules, 0, "No module configs should present for global only data")
+ assert.Error(t, err, "Should parse malformed module name with error")
+
+ _, err = parseConfigMapData(map[string]string{
+ "invalidYAML": `
+param1: val1
+ param2: val2
+`,
+ })
+ assert.Error(t, err, "Should parse bad module values with error")
}
func Test_ParseCM_only_Modules(t *testing.T) {
- cfg, err := ParseConfigMapData(map[string]string{
+ cfg, err := parseConfigMapData(map[string]string{
"modOne": `
param1: val1
param2: val2
@@ -60,37 +47,50 @@ param2: val2
assert.Containsf(t, cfg.Modules, "mod-one", "Config for modOne should present for modules only data")
mod := cfg.Modules["mod-one"]
- assert.Equal(t, "modOneEnabled", mod.ModuleEnabledKey)
- assert.Equal(t, "modOne", mod.ModuleConfigKey)
+ assert.Equal(t, "modOneEnabled", mod.ModuleEnabledKey())
+ assert.Equal(t, "modOne", mod.ModuleConfigKey())
assert.Equal(t, "false", mod.GetEnabled())
assert.Containsf(t, cfg.Modules, "mod-two", "Config for modOne should present for modules only data")
mod = cfg.Modules["mod-two"]
- assert.Equal(t, "modTwoEnabled", mod.ModuleEnabledKey)
- assert.Equal(t, "modTwo", mod.ModuleConfigKey)
+ assert.Equal(t, "modTwoEnabled", mod.ModuleEnabledKey())
+ assert.Equal(t, "modTwo", mod.ModuleConfigKey())
assert.Equal(t, "n/d", mod.GetEnabled())
assert.Containsf(t, cfg.Modules, "mod-three", "Config for modOne should present for modules only data")
mod = cfg.Modules["mod-three"]
- assert.Equal(t, "modThreeEnabled", mod.ModuleEnabledKey)
- assert.Equal(t, "modThree", mod.ModuleConfigKey)
+ assert.Equal(t, "modThreeEnabled", mod.ModuleEnabledKey())
+ assert.Equal(t, "modThree", mod.ModuleConfigKey())
assert.Equal(t, "true", mod.GetEnabled())
}
-func Test_ParseCM_Malformed_Data(t *testing.T) {
- var err error
-
- _, err = ParseConfigMapData(map[string]string{
- "Malformed-section-name": `
+func Test_ParseCM_only_Global(t *testing.T) {
+ cfg, err := parseConfigMapData(map[string]string{
+ "global": `
param1: val1
param2: val2
`,
})
- assert.Error(t, err, "Should parse malformed module name with error")
+ assert.NoError(t, err, "Should parse global only data correctly")
+ assert.NotNil(t, cfg, "Config should not be nil for global only data")
+ assert.NotNil(t, cfg.Global, "Global config should present for global only data")
+ assert.True(t, cfg.Global.Values.HasGlobal(), "Config should have global values for global only data")
+ assert.NotNil(t, cfg.Modules, "Modules should not be nil for global only data")
+ assert.Len(t, cfg.Modules, 0, "No module configs should present for global only data")
+}
- _, err = ParseConfigMapData(map[string]string{
- "invalidYAML": `
-param1: val1
- param2: val2
-`,
- })
- assert.Error(t, err, "Should parse bad module values with error")
+func Test_ParseCM_Nil(t *testing.T) {
+ cfg, err := parseConfigMapData(nil)
+ assert.NoError(t, err, "Should parse nil data correctly")
+ assert.NotNil(t, cfg, "Config should not be nil for nil data")
+ assert.Nil(t, cfg.Global, "No global config should present for nil data")
+ assert.NotNil(t, cfg.Modules, "Modules should not be nil for nil data")
+ assert.Len(t, cfg.Modules, 0, "No module configs should present for nil data")
+}
+
+func Test_ParseCM_Empty(t *testing.T) {
+ cfg, err := parseConfigMapData(map[string]string{})
+ assert.NoError(t, err, "Should parse empty data correctly")
+ assert.NotNil(t, cfg, "Config should not be nil for empty data")
+ assert.Nil(t, cfg.Global, "No global config should present for empty data")
+ assert.NotNil(t, cfg.Modules, "Modules should not be nil for empty data")
+ assert.Len(t, cfg.Modules, 0, "No module configs should present for empty data")
}
diff --git a/pkg/kube_config_manager/config.go b/pkg/kube_config_manager/config.go
deleted file mode 100644
index bfe792d0..00000000
--- a/pkg/kube_config_manager/config.go
+++ /dev/null
@@ -1,42 +0,0 @@
-package kube_config_manager
-
-type KubeConfig struct {
- Global *GlobalKubeConfig
- Modules map[string]*ModuleKubeConfig
-}
-
-func NewConfig() *KubeConfig {
- return &KubeConfig{
- Modules: make(map[string]*ModuleKubeConfig),
- }
-}
-
-type KubeConfigEvent string
-
-const (
- KubeConfigChanged KubeConfigEvent = "Changed"
- KubeConfigInvalid KubeConfigEvent = "Invalid"
-)
-
-func ParseConfigMapData(data map[string]string) (cfg *KubeConfig, err error) {
- cfg = NewConfig()
- // Parse values in global section.
- cfg.Global, err = GetGlobalKubeConfigFromConfigData(data)
- if err != nil {
- return nil, err
- }
-
- moduleNames, err := GetModulesNamesFromConfigData(data)
- if err != nil {
- return nil, err
- }
-
- for moduleName := range moduleNames {
- cfg.Modules[moduleName], err = ExtractModuleKubeConfig(moduleName, data)
- if err != nil {
- return nil, err
- }
- }
-
- return cfg, nil
-}
diff --git a/pkg/kube_config_manager/config/config.go b/pkg/kube_config_manager/config/config.go
new file mode 100644
index 00000000..45a64bb2
--- /dev/null
+++ b/pkg/kube_config_manager/config/config.go
@@ -0,0 +1,79 @@
+package config
+
+import (
+ "github.com/flant/addon-operator/pkg/utils"
+)
+
+type KubeConfig struct {
+ Global *GlobalKubeConfig
+ Modules map[string]*ModuleKubeConfig
+}
+
+type GlobalKubeConfig struct {
+ Values utils.Values
+ Checksum string
+}
+
+// GetValues returns global values, enrich them with top level key 'global'
+/* TODO: since we have specified struct for global values, we don't need to encapsulate them into the map {"global": ... }
+but we have to change this behavior somewhere in the module-manager */
+func (gkc GlobalKubeConfig) GetValues() utils.Values {
+ if len(gkc.Values) == 0 {
+ return gkc.Values
+ }
+
+ if gkc.Values.HasKey("global") {
+ return gkc.Values
+ }
+
+ return utils.Values{"global": gkc.Values}
+}
+
+type ModuleKubeConfig struct {
+ utils.ModuleConfig
+ Checksum string
+}
+
+func NewConfig() *KubeConfig {
+ return &KubeConfig{
+ Modules: make(map[string]*ModuleKubeConfig),
+ }
+}
+
+type KubeConfigEvent string
+
+const (
+ KubeConfigChanged KubeConfigEvent = "Changed"
+ KubeConfigInvalid KubeConfigEvent = "Invalid"
+)
+
+func ParseGlobalKubeConfigFromValues(values utils.Values) (*GlobalKubeConfig, error) {
+ if !values.HasGlobal() {
+ return nil, nil
+ }
+
+ globalValues := values.Global()
+
+ checksum := globalValues.Checksum()
+
+ return &GlobalKubeConfig{
+ Values: globalValues,
+ Checksum: checksum,
+ }, nil
+}
+
+func ParseModuleKubeConfigFromValues(moduleName string, values utils.Values) *ModuleKubeConfig {
+ valuesKey := utils.ModuleNameToValuesKey(moduleName)
+ if !values.HasKey(valuesKey) {
+ return nil
+ }
+
+ moduleValues := values.SectionByKey(valuesKey)
+
+ checksum := moduleValues.Checksum()
+
+ return &ModuleKubeConfig{
+ ModuleConfig: *utils.NewModuleConfig(moduleName, moduleValues),
+ Checksum: checksum,
+ }
+}
diff --git a/pkg/kube_config_manager/config/event.go b/pkg/kube_config_manager/config/event.go
new file mode 100644
index 00000000..e480c438
--- /dev/null
+++ b/pkg/kube_config_manager/config/event.go
@@ -0,0 +1,12 @@
+package config
+
+type Event struct {
+ // Key possible values
+ // "" - reset the whole config
+ // "batch" - set global and modules config at once
+ // "global" - set only global config
+ // " - set only config for the module
+ Key string
+ Config *KubeConfig
+ Err error
+}
diff --git a/pkg/kube_config_manager/global_kube_config.go b/pkg/kube_config_manager/global_kube_config.go
deleted file mode 100644
index b9c9a6a1..00000000
--- a/pkg/kube_config_manager/global_kube_config.go
+++ /dev/null
@@ -1,60 +0,0 @@
-package kube_config_manager
-
-import (
- "fmt"
-
- "github.com/flant/addon-operator/pkg/utils"
-)
-
-type GlobalKubeConfig struct {
- Values utils.Values
- Checksum string
- ConfigData map[string]string
-}
-
-func GetGlobalKubeConfigFromValues(values utils.Values) (*GlobalKubeConfig, error) {
- if !values.HasGlobal() {
- return nil, nil
- }
-
- globalValues := values.Global()
-
- configData, err := globalValues.AsConfigMapData()
- if err != nil {
- return nil, fmt.Errorf("cannot dump yaml for global kube config: %s. Failed values data: %#v", err, globalValues.DebugString())
- }
-
- checksum, err := globalValues.Checksum()
- if err != nil {
- return nil, fmt.Errorf("global kube config checksum: %s", err)
- }
-
- return &GlobalKubeConfig{
- Values: globalValues,
- Checksum: checksum,
- ConfigData: configData,
- }, nil
-}
-
-func GetGlobalKubeConfigFromConfigData(configData map[string]string) (*GlobalKubeConfig, error) {
- yamlData, hasKey := configData[utils.GlobalValuesKey]
- if !hasKey {
- return nil, nil
- }
-
- values, err := utils.NewGlobalValues(yamlData)
- if err != nil {
- return nil, fmt.Errorf("ConfigMap: bad yaml at key '%s': %s:\n%s", utils.GlobalValuesKey, err, yamlData)
- }
-
- checksum, err := values.Checksum()
- if err != nil {
- return nil, fmt.Errorf("ConfigMap: global kube config checksum: %s", err)
- }
-
- return &GlobalKubeConfig{
- ConfigData: map[string]string{utils.GlobalValuesKey: yamlData},
- Values: values,
- Checksum: checksum,
- }, nil
-}
diff --git a/pkg/kube_config_manager/kube_config_manager.go b/pkg/kube_config_manager/kube_config_manager.go
index 75a12aaf..5ff9c45c 100644
--- a/pkg/kube_config_manager/kube_config_manager.go
+++ b/pkg/kube_config_manager/kube_config_manager.go
@@ -3,30 +3,18 @@ package kube_config_manager
import (
"context"
"fmt"
+ "reflect"
"strconv"
"sync"
- "time"
log "github.com/sirupsen/logrus"
- "gopkg.in/yaml.v3"
- v1 "k8s.io/api/core/v1"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "k8s.io/apimachinery/pkg/fields"
- corev1 "k8s.io/client-go/informers/core/v1"
- "k8s.io/client-go/tools/cache"
+ "github.com/flant/addon-operator/pkg/kube_config_manager/backend"
+ "github.com/flant/addon-operator/pkg/kube_config_manager/config"
"github.com/flant/addon-operator/pkg/utils"
- klient "github.com/flant/kube-client/client"
- "github.com/flant/shell-operator/pkg/config"
+ runtimeConfig "github.com/flant/shell-operator/pkg/config"
)
-type Config struct {
- Namespace string
- ConfigMapName string
- KubeClient klient.Client
- RuntimeConfig *config.Config
-}
-
// KubeConfigManager watches for changes in ConfigMap/addon-operator and provides
// methods to change its content.
// It stores values parsed from ConfigMap data. OpenAPI validation of these config values
@@ -35,166 +23,111 @@ type KubeConfigManager struct {
ctx context.Context
cancel context.CancelFunc
- KubeClient klient.Client
- Namespace string
- ConfigMapName string
+ logEntry *log.Entry
// Checksums to ignore self-initiated updates.
knownChecksums *Checksums
// Channel to emit events.
- configEventCh chan KubeConfigEvent
-
- // Runtime config to enable logging all events from the ConfigMap at runtime.
- runtimeConfig *config.Config
- logConfigMapEvents bool
- logEntry *log.Entry
+ configEventCh chan config.KubeConfigEvent
+ backend backend.ConfigHandler
m sync.Mutex
- currentConfig *KubeConfig
+ currentConfig *config.KubeConfig
}
-// kubeConfigManager should implement KubeConfigManager
-
-func NewKubeConfigManager(ctx context.Context, cfg *Config) *KubeConfigManager {
+func NewKubeConfigManager(ctx context.Context, bk backend.ConfigHandler, runtimeConfig *runtimeConfig.Config) *KubeConfigManager {
cctx, cancel := context.WithCancel(ctx)
+ logger := log.WithField("component", "KubeConfigManager")
+ logger.WithField("backend", reflect.TypeOf(bk)).Infof("Setup KubeConfigManager backend")
+
+ // Runtime config to enable logging all events from the ConfigMap at runtime.
+ if runtimeConfig != nil {
+ runtimeConfig.Register(
+ "log.configmap.events",
+ fmt.Sprintf("Set to true to log all operations with Configuration manager/%s", reflect.TypeOf(bk)),
+ "false",
+ func(oldValue string, newValue string) error {
+ val, err := strconv.ParseBool(newValue)
+ if err != nil {
+ return err
+ }
+ //nolint: revive,staticcheck // basic type is enough here
+ cctx = context.WithValue(cctx, "kube-config-manager-debug", val)
+ return nil
+ },
+ nil,
+ )
+ }
+
return &KubeConfigManager{
ctx: cctx,
cancel: cancel,
- KubeClient: cfg.KubeClient,
- Namespace: cfg.Namespace,
- ConfigMapName: cfg.ConfigMapName,
- runtimeConfig: cfg.RuntimeConfig,
-
- currentConfig: NewConfig(),
+ currentConfig: config.NewConfig(),
knownChecksums: NewChecksums(),
- configEventCh: make(chan KubeConfigEvent, 1),
- logEntry: log.WithField("component", "KubeConfigManager"),
+ configEventCh: make(chan config.KubeConfigEvent, 1),
+ logEntry: logger,
+ backend: bk,
}
}
-func (kcm *KubeConfigManager) SaveGlobalConfigValues(values utils.Values) error {
- globalKubeConfig, err := GetGlobalKubeConfigFromValues(values)
- if err != nil {
- return err
- }
- if globalKubeConfig == nil {
- return nil
- }
-
- if kcm.logConfigMapEvents {
- kcm.logEntry.Infof("Save global values to ConfigMap/%s:\n%s", kcm.ConfigMapName, values.DebugString())
- } else {
- kcm.logEntry.Infof("Save global values to ConfigMap/%s", kcm.ConfigMapName)
- }
-
- // Put checksum to known to ignore self-update.
- kcm.withLock(func() {
- kcm.knownChecksums.Add(utils.GlobalValuesKey, globalKubeConfig.Checksum)
- })
+func (kcm *KubeConfigManager) Init() error {
+ kcm.logEntry.Debug("Init: KubeConfigManager")
- err = ConfigMapMergeValues(kcm.KubeClient, kcm.Namespace, kcm.ConfigMapName, globalKubeConfig.Values)
+ // Load config and calculate checksums at start. No locking required.
+ err := kcm.loadConfig()
if err != nil {
- // Remove known checksum on error.
- kcm.withLock(func() {
- kcm.knownChecksums.Remove(utils.GlobalValuesKey, globalKubeConfig.Checksum)
- })
return err
}
return nil
}
-// SaveModuleConfigValues updates module section in ConfigMap.
+// SaveConfigValues updates `global` or `module` section in ConfigMap.
// It uses knownChecksums to prevent KubeConfigChanged event on self-update.
-func (kcm *KubeConfigManager) SaveModuleConfigValues(moduleName string, values utils.Values) error {
- moduleKubeConfig, err := GetModuleKubeConfigFromValues(moduleName, values)
+func (kcm *KubeConfigManager) SaveConfigValues(key string, values utils.Values) error {
+ checksum, err := kcm.backend.SaveConfigValues(kcm.ctx, key, values)
if err != nil {
- return err
- }
- if moduleKubeConfig == nil {
- return nil
- }
+ kcm.withLock(func() {
+ kcm.knownChecksums.Remove(key, checksum)
+ })
- if kcm.logConfigMapEvents {
- kcm.logEntry.Infof("Save module '%s' values to ConfigMap/%s:\n%s", moduleName, kcm.ConfigMapName, values.DebugString())
- } else {
- kcm.logEntry.Infof("Save module '%s' values to ConfigMap/%s", moduleName, kcm.ConfigMapName)
+ return err
}
- // Put checksum to known to ignore self-update.
kcm.withLock(func() {
- kcm.knownChecksums.Add(moduleName, moduleKubeConfig.Checksum)
+ kcm.knownChecksums.Add(key, checksum)
})
- err = ConfigMapMergeValues(kcm.KubeClient, kcm.Namespace, kcm.ConfigMapName, moduleKubeConfig.Values)
- if err != nil {
- kcm.withLock(func() {
- kcm.knownChecksums.Remove(moduleName, moduleKubeConfig.Checksum)
- })
- return err
- }
-
return nil
}
// KubeConfigEventCh return a channel that emits new KubeConfig on ConfigMap changes in global section or enabled modules.
-func (kcm *KubeConfigManager) KubeConfigEventCh() chan KubeConfigEvent {
+func (kcm *KubeConfigManager) KubeConfigEventCh() chan config.KubeConfigEvent {
return kcm.configEventCh
}
// loadConfig gets config from ConfigMap before starting informer.
// Set checksums for global section and modules.
func (kcm *KubeConfigManager) loadConfig() error {
- obj, err := ConfigMapGet(kcm.KubeClient, kcm.Namespace, kcm.ConfigMapName)
+ newConfig, err := kcm.backend.LoadConfig(kcm.ctx)
if err != nil {
return err
}
- if obj == nil {
- kcm.logEntry.Infof("Initial config from ConfigMap/%s: resource is not found", kcm.ConfigMapName)
- return nil
+ if newConfig.Global != nil {
+ kcm.knownChecksums.Set(utils.GlobalValuesKey, newConfig.Global.Checksum)
}
- newConfig, err := ParseConfigMapData(obj.Data)
- if err != nil {
- return err
+ for moduleName, moduleConfig := range newConfig.Modules {
+ kcm.knownChecksums.Set(moduleName, moduleConfig.Checksum)
}
kcm.currentConfig = newConfig
return nil
}
-func (kcm *KubeConfigManager) Init() error {
- kcm.logEntry.Debug("INIT: KUBE_CONFIG")
-
- if kcm.runtimeConfig != nil {
- kcm.runtimeConfig.Register(
- "log.configmap.events",
- fmt.Sprintf("Set to true to log all operations with ConfigMap/%s", kcm.ConfigMapName),
- "false",
- func(oldValue string, newValue string) error {
- val, err := strconv.ParseBool(newValue)
- if err != nil {
- return err
- }
- kcm.logConfigMapEvents = val
- return nil
- },
- nil,
- )
- }
-
- // Load config and calculate checksums at start. No locking required.
- err := kcm.loadConfig()
- if err != nil {
- return err
- }
-
- return nil
-}
-
// currentModuleNames gather modules names from the checksums map and from the currentConfig struct.
func (kcm *KubeConfigManager) currentModuleNames() map[string]struct{} {
names := make(map[string]struct{})
@@ -205,7 +138,7 @@ func (kcm *KubeConfigManager) currentModuleNames() map[string]struct{} {
}
// isGlobalChanged returns true when changes in "global" section requires firing event.
-func (kcm *KubeConfigManager) isGlobalChanged(newConfig *KubeConfig) bool {
+func (kcm *KubeConfigManager) isGlobalChanged(newConfig *config.KubeConfig) bool {
if newConfig.Global == nil {
// Fire event when global section is deleted: ConfigMap has no global section but global config is cached.
// Note: no checksum checking here, "save" operations can't delete global section.
@@ -240,26 +173,96 @@ func (kcm *KubeConfigManager) isGlobalChanged(newConfig *KubeConfig) bool {
return false
}
-// handleNewCm determine changes in kube config. It sends KubeConfigChanged event if something
-// changed or KubeConfigInvalid event if ConfigMap is incorrect.
-func (kcm *KubeConfigManager) handleCmEvent(obj *v1.ConfigMap) error {
- // ConfigMap is deleted, reset cached config and fire event.
- if obj == nil {
+// handleConfigEvent determine changes in kube config. It sends KubeConfigChanged event if something
+// changed or KubeConfigInvalid event if Config is incorrect.
+func (kcm *KubeConfigManager) handleConfigEvent(obj config.Event) {
+ if obj.Err != nil {
+ // Do not update caches to detect changes on next update.
+ kcm.configEventCh <- config.KubeConfigInvalid
+ kcm.logEntry.Errorf("Config/%s invalid: %v", obj.Key, obj.Err)
+ return
+ }
+
+ switch obj.Key {
+ case "":
+ // Config backend was reset
+ kcm.m.Lock()
+ kcm.currentConfig = config.NewConfig()
+ kcm.m.Unlock()
+ kcm.configEventCh <- config.KubeConfigChanged
+
+ case utils.GlobalValuesKey:
+ // global values
+
kcm.m.Lock()
- kcm.currentConfig = NewConfig()
+ globalChanged := kcm.isGlobalChanged(obj.Config)
+ // Update state after successful parsing.
+ kcm.currentConfig.Global = obj.Config.Global
+ kcm.m.Unlock()
+ if globalChanged {
+ kcm.configEventCh <- config.KubeConfigChanged
+ }
+
+ default:
+ // some module values
+ modulesChanged := false
+
+ // module update
+ kcm.m.Lock()
+ moduleName := obj.Key
+ moduleCfg := obj.Config.Modules[obj.Key]
+ currentModuleNames := kcm.currentModuleNames()
+ _, exists := currentModuleNames[obj.Key]
+ if !exists {
+ kcm.logEntry.Infof("Module sections deleted: %+v", moduleName)
+ modulesChanged = true
+ }
+ // Module section is changed if new checksum not equal to saved one and not in known checksums.
+ if kcm.knownChecksums.HasEqualChecksum(moduleName, moduleCfg.Checksum) {
+ // Remove known checksum, do not fire event on self-update.
+ kcm.knownChecksums.Remove(moduleName, moduleCfg.Checksum)
+ } else {
+ if currModuleCfg, has := kcm.currentConfig.Modules[moduleName]; has {
+ if currModuleCfg.Checksum != moduleCfg.Checksum {
+ modulesChanged = true
+ kcm.logEntry.Infof("Module section '%s' changed. Enabled flag transition: %s--%s",
+ moduleName,
+ kcm.currentConfig.Modules[moduleName].GetEnabled(),
+ moduleCfg.GetEnabled(),
+ )
+ }
+ } else {
+ modulesChanged = true
+ kcm.logEntry.Infof("Module section '%s' added. Enabled flag: %s", moduleName, moduleCfg.GetEnabled())
+ }
+ }
+
+ if modulesChanged {
+ kcm.currentConfig.Modules[obj.Key] = moduleCfg
+ kcm.configEventCh <- config.KubeConfigChanged
+ }
kcm.m.Unlock()
- kcm.configEventCh <- KubeConfigChanged
- return nil
}
+}
- newConfig, err := ParseConfigMapData(obj.Data)
- if err != nil {
+func (kcm *KubeConfigManager) handleBatchConfigEvent(obj config.Event) {
+ if obj.Err != nil {
// Do not update caches to detect changes on next update.
- kcm.configEventCh <- KubeConfigInvalid
- kcm.logEntry.Errorf("ConfigMap/%s invalid: %v", kcm.ConfigMapName, err)
- return err
+ kcm.configEventCh <- config.KubeConfigInvalid
+ kcm.logEntry.Errorf("Batch Config invalid: %v", obj.Err)
+ return
+ }
+
+ if obj.Key == "" {
+ // Config backend was reset
+ kcm.m.Lock()
+ kcm.currentConfig = config.NewConfig()
+ kcm.m.Unlock()
+ kcm.configEventCh <- config.KubeConfigChanged
}
+ newConfig := obj.Config
+
// Lock to read known checksums and update config.
kcm.m.Lock()
@@ -306,51 +309,35 @@ func (kcm *KubeConfigManager) handleCmEvent(obj *v1.ConfigMap) error {
// Fire event if ConfigMap has changes.
if globalChanged || modulesChanged {
- kcm.configEventCh <- KubeConfigChanged
+ kcm.configEventCh <- config.KubeConfigChanged
}
-
- return nil
}
func (kcm *KubeConfigManager) Start() {
kcm.logEntry.Debugf("Start kube config manager")
- // define resyncPeriod for informer
- resyncPeriod := time.Duration(5) * time.Minute
+ go kcm.start()
+}
- // define indexers for informer
- indexers := cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}
+func (kcm *KubeConfigManager) start() {
+ eventC := make(chan config.Event, 100)
- // define tweakListOptions for informer
- tweakListOptions := func(options *metav1.ListOptions) {
- options.FieldSelector = fields.OneTermEqualSelector("metadata.name", kcm.ConfigMapName).String()
- }
+ kcm.backend.StartInformer(kcm.ctx, eventC)
- cmInformer := corev1.NewFilteredConfigMapInformer(kcm.KubeClient, kcm.Namespace, resyncPeriod, indexers, tweakListOptions)
- cmInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{
- AddFunc: func(obj interface{}) {
- kcm.logConfigMapEvent(obj, "add")
- err := kcm.handleCmEvent(obj.(*v1.ConfigMap))
- if err != nil {
- kcm.logEntry.Errorf("Handle ConfigMap/%s 'add' error: %s", kcm.ConfigMapName, err)
- }
- },
- UpdateFunc: func(prevObj interface{}, obj interface{}) {
- kcm.logConfigMapEvent(obj, "update")
- err := kcm.handleCmEvent(obj.(*v1.ConfigMap))
- if err != nil {
- kcm.logEntry.Errorf("Handle ConfigMap/%s 'update' error: %s", kcm.ConfigMapName, err)
+ for {
+ select {
+ case event := <-eventC:
+ if event.Key == "batch" {
+ kcm.handleBatchConfigEvent(event)
+ } else {
+ kcm.handleConfigEvent(event)
}
- },
- DeleteFunc: func(obj interface{}) {
- kcm.logConfigMapEvent(obj, "delete")
- _ = kcm.handleCmEvent(nil)
- },
- })
- go func() {
- cmInformer.Run(kcm.ctx.Done())
- }()
+ case <-kcm.ctx.Done():
+ kcm.logEntry.Debugf("Stop kube config manager")
+ return
+ }
+ }
}
func (kcm *KubeConfigManager) Stop() {
@@ -359,21 +346,8 @@ func (kcm *KubeConfigManager) Stop() {
}
}
-func (kcm *KubeConfigManager) logConfigMapEvent(obj interface{}, eventName string) {
- if !kcm.logConfigMapEvents {
- return
- }
-
- objYaml, err := yaml.Marshal(obj)
- if err != nil {
- kcm.logEntry.Infof("Dump ConfigMap/%s '%s' error: %s", kcm.ConfigMapName, eventName, err)
- return
- }
- kcm.logEntry.Infof("Dump ConfigMap/%s '%s':\n%s", kcm.ConfigMapName, eventName, objYaml)
-}
-
// SafeReadConfig locks currentConfig to safely read from it in external services.
-func (kcm *KubeConfigManager) SafeReadConfig(handler func(config *KubeConfig)) {
+func (kcm *KubeConfigManager) SafeReadConfig(handler func(config *config.KubeConfig)) {
if handler == nil {
return
}
diff --git a/pkg/kube_config_manager/kube_config_manager_test.go b/pkg/kube_config_manager/kube_config_manager_test.go
index 8c104b43..5a4eb93d 100644
--- a/pkg/kube_config_manager/kube_config_manager_test.go
+++ b/pkg/kube_config_manager/kube_config_manager_test.go
@@ -11,6 +11,8 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
+ "github.com/flant/addon-operator/pkg/kube_config_manager/backend/configmap"
+ "github.com/flant/addon-operator/pkg/kube_config_manager/config"
"github.com/flant/addon-operator/pkg/utils"
klient "github.com/flant/kube-client/client"
)
@@ -19,7 +21,7 @@ const testConfigMapName = "test-addon-operator"
// initKubeConfigManager returns an initialized KubeConfigManager instance.
// Pass string or map to prefill ConfigMap.
-func initKubeConfigManager(t *testing.T, kubeClient klient.Client, cmData map[string]string, cmContent string) *KubeConfigManager {
+func initKubeConfigManager(t *testing.T, kubeClient *klient.Client, cmData map[string]string, cmContent string) *KubeConfigManager {
g := NewWithT(t)
cm := &v1.ConfigMap{}
@@ -37,18 +39,13 @@ func initKubeConfigManager(t *testing.T, kubeClient klient.Client, cmData map[st
_, err := kubeClient.CoreV1().ConfigMaps("default").Create(context.TODO(), cm, metav1.CreateOptions{})
g.Expect(err).ShouldNot(HaveOccurred(), "ConfigMap should be created")
- kcfg := Config{
- Namespace: "default",
- ConfigMapName: testConfigMapName,
- KubeClient: kubeClient,
- RuntimeConfig: nil,
- }
- kcm := NewKubeConfigManager(context.Background(), &kcfg)
+ bk := configmap.New(nil, kubeClient, "default", testConfigMapName)
+ kcm := NewKubeConfigManager(context.Background(), bk, nil)
err = kcm.Init()
g.Expect(err).ShouldNot(HaveOccurred(), "KubeConfigManager should init correctly")
- go kcm.Start()
+ kcm.Start()
return kcm
}
@@ -137,16 +134,16 @@ grafanaEnabled: "false"
for name, expect := range tests {
t.Run(name, func(t *testing.T) {
if name == "global" {
- kcm.SafeReadConfig(func(config *KubeConfig) {
+ kcm.SafeReadConfig(func(config *config.KubeConfig) {
assert.Equal(t, expect.values, config.Global.Values)
})
} else {
- kcm.SafeReadConfig(func(config *KubeConfig) {
+ kcm.SafeReadConfig(func(config *config.KubeConfig) {
// module
moduleConfig, hasConfig := config.Modules[name]
assert.True(t, hasConfig)
assert.Equal(t, expect.isEnabled, moduleConfig.IsEnabled)
- assert.Equal(t, expect.values, moduleConfig.Values)
+ assert.Equal(t, expect.values, moduleConfig.GetValues())
})
}
})
@@ -246,12 +243,12 @@ func Test_KubeConfigManager_SaveValuesToConfigMap(t *testing.T) {
}
assert.Contains(t, cm.Data, utils.ModuleNameToValuesKey("mymodule"), "ConfigMap should contain a '%s' key", utils.ModuleNameToValuesKey("mymodule"))
- mconf, err := ExtractModuleKubeConfig("mymodule", cm.Data)
- if assert.NoError(t, err, "ModuleConfig should load") {
- assert.Equal(t, *module, mconf.Values)
- } else {
- t.FailNow()
- }
+ // mconf, err := ExtractModuleKubeConfig("mymodule", cm.Data)
+ // if assert.NoError(t, err, "ModuleConfig should load") {
+ // assert.Equal(t, *module, mconf.Values)
+ // } else {
+ // t.FailNow()
+ //}
},
},
}
@@ -259,12 +256,12 @@ func Test_KubeConfigManager_SaveValuesToConfigMap(t *testing.T) {
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
if test.globalValues != nil {
- err = kcm.SaveGlobalConfigValues(*test.globalValues)
+ err = kcm.SaveConfigValues(utils.GlobalValuesKey, *test.globalValues)
if !assert.NoError(t, err, "Global Values should be saved") {
t.FailNow()
}
} else if test.moduleValues != nil {
- err = kcm.SaveModuleConfigValues(test.moduleName, *test.moduleValues)
+ err = kcm.SaveConfigValues(test.moduleName, *test.moduleValues)
if !assert.NoError(t, err, "Module Values should be saved") {
t.FailNow()
}
@@ -300,7 +297,7 @@ param2: val2
defer kcm.Stop()
// Check initial modules configs.
- kcm.SafeReadConfig(func(config *KubeConfig) {
+ kcm.SafeReadConfig(func(config *config.KubeConfig) {
g.Expect(config.Modules).To(HaveLen(0), "No modules section should be after Init()")
})
@@ -320,7 +317,7 @@ param2: val2
// Wait for event.
g.Eventually(kcm.KubeConfigEventCh(), "20s", "100ms").Should(Receive(), "KubeConfigManager should emit event")
- kcm.SafeReadConfig(func(config *KubeConfig) {
+ kcm.SafeReadConfig(func(config *config.KubeConfig) {
g.Expect(config.Modules).To(HaveLen(1), "Module section should appear after ConfigMap update")
g.Expect(config.Modules).To(HaveKey("module-2"), "module-2 section should appear after ConfigMap update")
})
@@ -341,7 +338,7 @@ param2: val2
// Wait for event.
g.Eventually(kcm.KubeConfigEventCh(), "20s", "100ms").Should(Receive(), "KubeConfigManager should emit event")
- kcm.SafeReadConfig(func(config *KubeConfig) {
+ kcm.SafeReadConfig(func(config *config.KubeConfig) {
g.Expect(config.Global.Values).To(HaveKey("global"), "Should update global section cache")
g.Expect(config.Global.Values["global"]).To(HaveKey("param1"), "Should update global section cache")
})
@@ -370,7 +367,7 @@ moduleLongName:
g.Expect(err).ShouldNot(HaveOccurred(), "values should load from bytes")
g.Expect(modVals).To(HaveKey("moduleLongName"))
- err = kcm.SaveModuleConfigValues("module-long-name", modVals)
+ err = kcm.SaveConfigValues("module-long-name", modVals)
g.Expect(err).ShouldNot(HaveOccurred())
// Check that values are updated in ConfigMap
@@ -406,7 +403,7 @@ func Test_KubeConfigManager_error_on_Init(t *testing.T) {
// Wait for event
ev := <-kcm.KubeConfigEventCh()
- g.Expect(ev).To(Equal(KubeConfigInvalid), "Invalid name in module section should generate 'invalid' event")
+ g.Expect(ev).To(Equal(config.KubeConfigInvalid), "Invalid name in module section should generate 'invalid' event")
// kcm.SafeReadConfig(func(config *KubeConfig) {
// g.Expect(config.IsInvalid).To(Equal(true), "Current config should be invalid")
@@ -430,13 +427,13 @@ func Test_KubeConfigManager_error_on_Init(t *testing.T) {
// Wait for event
ev = <-kcm.KubeConfigEventCh()
- g.Expect(ev).To(Equal(KubeConfigChanged), "Valid section patch should generate 'changed' event")
+ g.Expect(ev).To(Equal(config.KubeConfigChanged), "Valid section patch should generate 'changed' event")
- kcm.SafeReadConfig(func(config *KubeConfig) {
+ kcm.SafeReadConfig(func(config *config.KubeConfig) {
// g.Expect(config.IsInvalid).To(Equal(false), "Current config should be valid")
g.Expect(config.Modules).To(HaveLen(1), "Current config should have module sections")
g.Expect(config.Modules).To(HaveKey("valid-module-name"), "Current config should have module section for 'valid-module-name'")
- modValues := config.Modules["valid-module-name"].Values
+ modValues := config.Modules["valid-module-name"].GetValues()
g.Expect(modValues.HasKey("validModuleName")).To(BeTrue())
m := modValues["validModuleName"]
vals := m.(map[string]interface{})
diff --git a/pkg/kube_config_manager/module_kube_config.go b/pkg/kube_config_manager/module_kube_config.go
deleted file mode 100644
index 8dc3bb60..00000000
--- a/pkg/kube_config_manager/module_kube_config.go
+++ /dev/null
@@ -1,91 +0,0 @@
-package kube_config_manager
-
-import (
- "fmt"
- "strings"
-
- "github.com/flant/addon-operator/pkg/utils"
-)
-
-// GetModulesNamesFromConfigData returns all keys in kube config except global
-// modNameEnabled keys are also handled
-func GetModulesNamesFromConfigData(configData map[string]string) (map[string]bool, error) {
- res := make(map[string]bool)
-
- for key := range configData {
- // Ignore global section.
- if key == utils.GlobalValuesKey {
- continue
- }
-
- // Treat Enabled flags as module section.
- key = strings.TrimSuffix(key, "Enabled")
-
- modName := utils.ModuleNameFromValuesKey(key)
-
- if utils.ModuleNameToValuesKey(modName) != key {
- return nil, fmt.Errorf("bad module name '%s': should be camelCased", key)
- }
- res[modName] = true
- }
-
- return res, nil
-}
-
-type ModuleKubeConfig struct {
- utils.ModuleConfig
- Checksum string
- ConfigData map[string]string
-}
-
-func (m *ModuleKubeConfig) GetEnabled() string {
- if m == nil {
- return ""
- }
- return m.ModuleConfig.GetEnabled()
-}
-
-func GetModuleKubeConfigFromValues(moduleName string, values utils.Values) (*ModuleKubeConfig, error) {
- valuesKey := utils.ModuleNameToValuesKey(moduleName)
- if !values.HasKey(valuesKey) {
- return nil, nil
- }
-
- moduleValues := values.SectionByKey(valuesKey)
-
- configData, err := moduleValues.AsConfigMapData()
- if err != nil {
- return nil, fmt.Errorf("cannot dump yaml for module '%s' kube config: %s. Failed values data: %s", moduleName, err, moduleValues.DebugString())
- }
-
- checksum, err := moduleValues.Checksum()
- if err != nil {
- return nil, fmt.Errorf("module '%s' kube config checksum: %s", moduleName, err)
- }
-
- return &ModuleKubeConfig{
- ModuleConfig: utils.ModuleConfig{
- ModuleName: moduleName,
- Values: moduleValues,
- },
- ConfigData: configData,
- Checksum: checksum,
- }, nil
-}
-
-// ExtractModuleKubeConfig returns ModuleKubeConfig with values loaded from ConfigMap
-func ExtractModuleKubeConfig(moduleName string, configData map[string]string) (*ModuleKubeConfig, error) {
- moduleConfig, err := utils.NewModuleConfig(moduleName).FromConfigMapData(configData)
- if err != nil {
- return nil, fmt.Errorf("bad yaml at key '%s': %s", utils.ModuleNameToValuesKey(moduleName), err)
- }
- // NOTE this should never happen because of GetModulesNamesFromConfigData
- if moduleConfig == nil {
- return nil, fmt.Errorf("possible bug!!! No section '%s' for module '%s'", utils.ModuleNameToValuesKey(moduleName), moduleName)
- }
-
- return &ModuleKubeConfig{
- ModuleConfig: *moduleConfig,
- Checksum: moduleConfig.Checksum(),
- }, nil
-}
diff --git a/pkg/module_manager/global_hook.go b/pkg/module_manager/global_hook.go
index 6df0ead8..1a671966 100644
--- a/pkg/module_manager/global_hook.go
+++ b/pkg/module_manager/global_hook.go
@@ -5,9 +5,9 @@ import (
"path/filepath"
"strings"
+ uuid "github.com/gofrs/uuid/v5"
"github.com/hashicorp/go-multierror"
log "github.com/sirupsen/logrus"
- uuid "gopkg.in/satori/go.uuid.v1"
. "github.com/flant/addon-operator/pkg/hook/types"
"github.com/flant/addon-operator/pkg/module_manager/go_hook"
@@ -212,7 +212,7 @@ func (h *GlobalHook) Run(bindingType BindingType, bindingContext []BindingContex
)
}
- err := h.moduleManager.dependencies.KubeConfigManager.SaveGlobalConfigValues(configValuesPatchResult.Values)
+ err := h.moduleManager.dependencies.KubeConfigManager.SaveConfigValues(utils.GlobalValuesKey, configValuesPatchResult.Values)
if err != nil {
logEntry.Debugf("Global hook '%s' kube config global values stay unchanged:\n%s", h.Name, h.moduleManager.kubeGlobalConfigValues.DebugString())
return fmt.Errorf("global hook '%s': set kube config failed: %s", h.Name, err)
@@ -327,7 +327,7 @@ func (h *GlobalHook) prepareConfigValuesJsonFile() (string, error) {
return "", err
}
- path := filepath.Join(h.TmpDir, fmt.Sprintf("global-hook-%s-config-values-%s.json", h.SafeName(), uuid.NewV4().String()))
+ path := filepath.Join(h.TmpDir, fmt.Sprintf("global-hook-%s-config-values-%s.json", h.SafeName(), uuid.Must(uuid.NewV4()).String()))
err = dumpData(path, data)
if err != nil {
return "", err
@@ -353,7 +353,7 @@ func (h *GlobalHook) prepareValuesJsonFile() (filePath string, err error) {
return "", err
}
- filePath = filepath.Join(h.TmpDir, fmt.Sprintf("global-hook-%s-values-%s.json", h.SafeName(), uuid.NewV4().String()))
+ filePath = filepath.Join(h.TmpDir, fmt.Sprintf("global-hook-%s-values-%s.json", h.SafeName(), uuid.Must(uuid.NewV4()).String()))
err = dumpData(filePath, data)
if err != nil {
return "", err
@@ -366,7 +366,7 @@ func (h *GlobalHook) prepareValuesJsonFile() (filePath string, err error) {
// BINDING_CONTEXT_PATH
func (h *GlobalHook) prepareBindingContextJsonFile(bindingContext []byte) (string, error) {
- path := filepath.Join(h.TmpDir, fmt.Sprintf("global-hook-%s-binding-context-%s.json", h.SafeName(), uuid.NewV4().String()))
+ path := filepath.Join(h.TmpDir, fmt.Sprintf("global-hook-%s-binding-context-%s.json", h.SafeName(), uuid.Must(uuid.NewV4()).String()))
err := dumpData(path, bindingContext)
if err != nil {
return "", err
@@ -380,7 +380,7 @@ func (h *GlobalHook) prepareBindingContextJsonFile(bindingContext []byte) (strin
// CONFIG_VALUES_JSON_PATCH_PATH
func (h *GlobalHook) prepareConfigValuesJsonPatchFile() (string, error) {
- path := filepath.Join(h.TmpDir, fmt.Sprintf("%s.global-hook-config-values-%s.json-patch", h.SafeName(), uuid.NewV4().String()))
+ path := filepath.Join(h.TmpDir, fmt.Sprintf("%s.global-hook-config-values-%s.json-patch", h.SafeName(), uuid.Must(uuid.NewV4()).String()))
if err := CreateEmptyWritableFile(path); err != nil {
return "", err
}
@@ -389,7 +389,7 @@ func (h *GlobalHook) prepareConfigValuesJsonPatchFile() (string, error) {
// VALUES_JSON_PATCH_PATH
func (h *GlobalHook) prepareValuesJsonPatchFile() (string, error) {
- path := filepath.Join(h.TmpDir, fmt.Sprintf("%s.global-hook-values-%s.json-patch", h.SafeName(), uuid.NewV4().String()))
+ path := filepath.Join(h.TmpDir, fmt.Sprintf("%s.global-hook-values-%s.json-patch", h.SafeName(), uuid.Must(uuid.NewV4()).String()))
if err := CreateEmptyWritableFile(path); err != nil {
return "", err
}
@@ -398,7 +398,7 @@ func (h *GlobalHook) prepareValuesJsonPatchFile() (string, error) {
// METRICS_PATH
func (h *GlobalHook) prepareMetricsFile() (string, error) {
- path := filepath.Join(h.TmpDir, fmt.Sprintf("%s.global-hook-metrics-%s.json", h.SafeName(), uuid.NewV4().String()))
+ path := filepath.Join(h.TmpDir, fmt.Sprintf("%s.global-hook-metrics-%s.json", h.SafeName(), uuid.Must(uuid.NewV4()).String()))
if err := CreateEmptyWritableFile(path); err != nil {
return "", err
}
@@ -407,7 +407,7 @@ func (h *GlobalHook) prepareMetricsFile() (string, error) {
// KUBERNETES PATCH PATH
func (h *GlobalHook) prepareKubernetesPatchFile() (string, error) {
- path := filepath.Join(h.TmpDir, fmt.Sprintf("%s-object-patch-%s", h.SafeName(), uuid.NewV4().String()))
+ path := filepath.Join(h.TmpDir, fmt.Sprintf("%s-object-patch-%s", h.SafeName(), uuid.Must(uuid.NewV4()).String()))
if err := CreateEmptyWritableFile(path); err != nil {
return "", err
}
diff --git a/pkg/module_manager/go_hook/go_hook.go b/pkg/module_manager/go_hook/go_hook.go
index 50994b2b..b84440f8 100644
--- a/pkg/module_manager/go_hook/go_hook.go
+++ b/pkg/module_manager/go_hook/go_hook.go
@@ -59,8 +59,11 @@ type BindingAction struct {
}
type HookConfig struct {
- Schedule []ScheduleConfig
- Kubernetes []KubernetesConfig
+ Schedule []ScheduleConfig
+ Kubernetes []KubernetesConfig
+ // OnStartup runs hook on module/global startup
+ // Attention! During the startup you don't have snapshots available
+ // use native KubeClient to fetch resources
OnStartup *OrderedConfig
OnBeforeHelm *OrderedConfig
OnAfterHelm *OrderedConfig
diff --git a/pkg/module_manager/go_hook/metrics/collector.go b/pkg/module_manager/go_hook/metrics/collector.go
index d10e17b8..3222f884 100644
--- a/pkg/module_manager/go_hook/metrics/collector.go
+++ b/pkg/module_manager/go_hook/metrics/collector.go
@@ -34,7 +34,7 @@ func (dms *MemoryMetricsCollector) Add(name string, value float64, labels map[st
Name: name,
Group: opts.group,
Action: "add",
- Value: pointer.Float64Ptr(value),
+ Value: pointer.Float64(value),
Labels: labels,
})
}
@@ -51,7 +51,7 @@ func (dms *MemoryMetricsCollector) Set(name string, value float64, labels map[st
Name: name,
Group: opts.group,
Action: "set",
- Value: pointer.Float64Ptr(value),
+ Value: pointer.Float64(value),
Labels: labels,
})
}
diff --git a/pkg/module_manager/module.go b/pkg/module_manager/module.go
index 507fefe1..8d9e24a8 100644
--- a/pkg/module_manager/module.go
+++ b/pkg/module_manager/module.go
@@ -9,9 +9,9 @@ import (
"strings"
"time"
+ uuid "github.com/gofrs/uuid/v5"
"github.com/kennygrant/sanitize"
log "github.com/sirupsen/logrus"
- uuid "gopkg.in/satori/go.uuid.v1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"sigs.k8s.io/yaml"
@@ -454,10 +454,7 @@ func (m *Module) runHooksByBindingAndCheckValues(binding BindingType, logLabels
if err != nil {
return false, err
}
- valuesChecksum, err := values.Checksum()
- if err != nil {
- return false, err
- }
+ valuesChecksum := values.Checksum()
for _, moduleHookName := range moduleHooks {
moduleHook := m.moduleManager.GetModuleHook(moduleHookName)
@@ -503,10 +500,7 @@ func (m *Module) runHooksByBindingAndCheckValues(binding BindingType, logLabels
if err != nil {
return false, err
}
- newValuesChecksum, err := newValues.Checksum()
- if err != nil {
- return false, err
- }
+ newValuesChecksum := newValues.Checksum()
if newValuesChecksum != valuesChecksum {
return true, nil
@@ -522,7 +516,7 @@ func (m *Module) prepareConfigValuesJsonFile() (string, error) {
return "", err
}
- path := filepath.Join(m.moduleManager.TempDir, fmt.Sprintf("%s.module-config-values-%s.json", m.SafeName(), uuid.NewV4().String()))
+ path := filepath.Join(m.moduleManager.TempDir, fmt.Sprintf("%s.module-config-values-%s.json", m.SafeName(), uuid.Must(uuid.NewV4()).String()))
err = dumpData(path, data)
if err != nil {
return "", err
@@ -545,7 +539,7 @@ func (m *Module) PrepareValuesYamlFile() (string, error) {
return "", err
}
- path := filepath.Join(m.moduleManager.TempDir, fmt.Sprintf("%s.module-values.yaml-%s", m.SafeName(), uuid.NewV4().String()))
+ path := filepath.Join(m.moduleManager.TempDir, fmt.Sprintf("%s.module-values.yaml-%s", m.SafeName(), uuid.Must(uuid.NewV4()).String()))
err = dumpData(path, data)
if err != nil {
return "", err
@@ -563,7 +557,7 @@ func (m *Module) prepareValuesJsonFileWith(values utils.Values) (string, error)
return "", err
}
- path := filepath.Join(m.moduleManager.TempDir, fmt.Sprintf("%s.module-values-%s.json", m.SafeName(), uuid.NewV4().String()))
+ path := filepath.Join(m.moduleManager.TempDir, fmt.Sprintf("%s.module-values-%s.json", m.SafeName(), uuid.Must(uuid.NewV4()).String()))
err = dumpData(path, data)
if err != nil {
return "", err
@@ -641,8 +635,8 @@ func (m *Module) StaticAndConfigValues() utils.Values {
// Init module section.
utils.Values{m.ValuesKey(): map[string]interface{}{}},
// Merge static values from various values.yaml files.
- m.CommonStaticConfig.Values,
- m.StaticConfig.Values,
+ m.CommonStaticConfig.GetValues(),
+ m.StaticConfig.GetValues(),
// Apply config values defaults before ConfigMap overrides.
&ApplyDefaultsForModule{
m.ValuesKey(),
@@ -664,8 +658,8 @@ func (m *Module) StaticAndNewValues(newValues utils.Values) utils.Values {
// Init module section.
utils.Values{m.ValuesKey(): map[string]interface{}{}},
// Merge static values from various values.yaml files.
- m.CommonStaticConfig.Values,
- m.StaticConfig.Values,
+ m.CommonStaticConfig.GetValues(),
+ m.StaticConfig.GetValues(),
// Apply config values defaults before overrides.
&ApplyDefaultsForModule{
m.ValuesKey(),
@@ -697,8 +691,8 @@ func (m *Module) Values() (utils.Values, error) {
// Init module section.
utils.Values{m.ValuesKey(): map[string]interface{}{}},
// Merge static values from various values.yaml files.
- m.CommonStaticConfig.Values,
- m.StaticConfig.Values,
+ m.CommonStaticConfig.GetValues(),
+ m.StaticConfig.GetValues(),
// Apply config values defaults before ConfigMap overrides.
&ApplyDefaultsForModule{
m.ValuesKey(),
@@ -971,7 +965,7 @@ func (mm *ModuleManager) ValidateModule(module *Module) error {
}
// SyncModulesCR synchronize modules CR from current modules list to the cluster one
-func (mm *ModuleManager) SyncModulesCR(client klient.Client) error {
+func (mm *ModuleManager) SyncModulesCR(client *klient.Client) error {
if mm.moduleProducer == nil {
return nil
}
@@ -1036,16 +1030,16 @@ func (mm *ModuleManager) createModuleOperations(module *Module) (object_patch.Op
// loadStaticValues loads config for module from values.yaml
// Module is enabled if values.yaml is not exists.
func (m *Module) loadStaticValues() (err error) {
- m.CommonStaticConfig, err = utils.NewModuleConfig(m.Name).LoadFromValues(m.moduleManager.commonStaticValues)
+ m.CommonStaticConfig, err = utils.NewModuleConfig(m.Name, nil).LoadFromValues(m.moduleManager.commonStaticValues)
if err != nil {
return err
}
- log.Debugf("module %s static values in common file: %s", m.Name, m.CommonStaticConfig.Values.DebugString())
+ log.Debugf("module %s static values in common file: %s", m.Name, m.CommonStaticConfig.GetValues().DebugString())
valuesYamlPath := filepath.Join(m.Path, ValuesFileName)
if _, err := os.Stat(valuesYamlPath); os.IsNotExist(err) {
- m.StaticConfig = utils.NewModuleConfig(m.Name)
+ m.StaticConfig = utils.NewModuleConfig(m.Name, nil)
log.Debugf("module %s has no static values", m.Name)
return nil
}
@@ -1055,11 +1049,11 @@ func (m *Module) loadStaticValues() (err error) {
return fmt.Errorf("cannot read '%s': %s", m.Path, err)
}
- m.StaticConfig, err = utils.NewModuleConfig(m.Name).FromYaml(data)
+ m.StaticConfig, err = utils.NewModuleConfig(m.Name, nil).FromYaml(data)
if err != nil {
return err
}
- log.Debugf("module %s static values: %s", m.Name, m.StaticConfig.Values.DebugString())
+ log.Debugf("module %s static values: %s", m.Name, m.StaticConfig.GetValues().DebugString())
return nil
}
diff --git a/pkg/module_manager/module_hook.go b/pkg/module_manager/module_hook.go
index cb8ae2c2..737527bb 100644
--- a/pkg/module_manager/module_hook.go
+++ b/pkg/module_manager/module_hook.go
@@ -5,9 +5,9 @@ import (
"path/filepath"
"strings"
+ uuid "github.com/gofrs/uuid/v5"
"github.com/hashicorp/go-multierror"
log "github.com/sirupsen/logrus"
- uuid "gopkg.in/satori/go.uuid.v1"
. "github.com/flant/addon-operator/pkg/hook/types"
"github.com/flant/addon-operator/pkg/module_manager/go_hook"
@@ -227,7 +227,7 @@ func (h *ModuleHook) Run(bindingType BindingType, context []BindingContext, logL
)
}
- err := h.moduleManager.dependencies.KubeConfigManager.SaveModuleConfigValues(moduleName, configValuesPatchResult.Values)
+ err := h.moduleManager.dependencies.KubeConfigManager.SaveConfigValues(moduleName, configValuesPatchResult.Values)
if err != nil {
logEntry.Debugf("Module hook '%s' kube module config values stay unchanged:\n%s", h.Name, h.moduleManager.kubeModulesConfigValues[moduleName].DebugString())
return fmt.Errorf("module hook '%s': set kube module config failed: %s", h.Name, err)
@@ -337,7 +337,7 @@ func (h *ModuleHook) prepareConfigValuesJsonFile() (string, error) {
// BINDING_CONTEXT_PATH
func (h *ModuleHook) prepareBindingContextJsonFile(bindingContext []byte) (string, error) {
// data := utils.MustDump(utils.DumpValuesJson(context))
- path := filepath.Join(h.TmpDir, fmt.Sprintf("%s.module-hook-%s-binding-context-%s.json", h.Module.SafeName(), h.SafeName(), uuid.NewV4().String()))
+ path := filepath.Join(h.TmpDir, fmt.Sprintf("%s.module-hook-%s-binding-context-%s.json", h.Module.SafeName(), h.SafeName(), uuid.Must(uuid.NewV4()).String()))
err := dumpData(path, bindingContext)
if err != nil {
return "", err
@@ -351,7 +351,7 @@ func (h *ModuleHook) prepareBindingContextJsonFile(bindingContext []byte) (strin
// CONFIG_VALUES_JSON_PATCH_PATH
func (h *ModuleHook) prepareConfigValuesJsonPatchFile() (string, error) {
- path := filepath.Join(h.TmpDir, fmt.Sprintf("%s.module-hook-config-values-%s.json-patch", h.SafeName(), uuid.NewV4().String()))
+ path := filepath.Join(h.TmpDir, fmt.Sprintf("%s.module-hook-config-values-%s.json-patch", h.SafeName(), uuid.Must(uuid.NewV4()).String()))
if err := CreateEmptyWritableFile(path); err != nil {
return "", err
}
@@ -360,7 +360,7 @@ func (h *ModuleHook) prepareConfigValuesJsonPatchFile() (string, error) {
// VALUES_JSON_PATCH_PATH
func (h *ModuleHook) prepareValuesJsonPatchFile() (string, error) {
- path := filepath.Join(h.TmpDir, fmt.Sprintf("%s.module-hook-values-%s.json-patch", h.SafeName(), uuid.NewV4().String()))
+ path := filepath.Join(h.TmpDir, fmt.Sprintf("%s.module-hook-values-%s.json-patch", h.SafeName(), uuid.Must(uuid.NewV4()).String()))
if err := CreateEmptyWritableFile(path); err != nil {
return "", err
}
@@ -369,7 +369,7 @@ func (h *ModuleHook) prepareValuesJsonPatchFile() (string, error) {
// METRICS_PATH
func (h *ModuleHook) prepareMetricsFile() (string, error) {
- path := filepath.Join(h.TmpDir, fmt.Sprintf("%s.module-hook-metrics-%s.json", h.SafeName(), uuid.NewV4().String()))
+ path := filepath.Join(h.TmpDir, fmt.Sprintf("%s.module-hook-metrics-%s.json", h.SafeName(), uuid.Must(uuid.NewV4()).String()))
if err := CreateEmptyWritableFile(path); err != nil {
return "", err
}
@@ -378,7 +378,7 @@ func (h *ModuleHook) prepareMetricsFile() (string, error) {
// KUBERNETES PATCH PATH
func (h *ModuleHook) prepareKubernetesPatchFile() (string, error) {
- path := filepath.Join(h.TmpDir, fmt.Sprintf("%s-object-patch-%s", h.SafeName(), uuid.NewV4().String()))
+ path := filepath.Join(h.TmpDir, fmt.Sprintf("%s-object-patch-%s", h.SafeName(), uuid.Must(uuid.NewV4()).String()))
if err := CreateEmptyWritableFile(path); err != nil {
return "", err
}
diff --git a/pkg/module_manager/module_manager.go b/pkg/module_manager/module_manager.go
index 30900358..6111f9ba 100644
--- a/pkg/module_manager/module_manager.go
+++ b/pkg/module_manager/module_manager.go
@@ -17,7 +17,7 @@ import (
"github.com/flant/addon-operator/pkg/helm"
"github.com/flant/addon-operator/pkg/helm_resources_manager"
. "github.com/flant/addon-operator/pkg/hook/types"
- "github.com/flant/addon-operator/pkg/kube_config_manager"
+ "github.com/flant/addon-operator/pkg/kube_config_manager/config"
"github.com/flant/addon-operator/pkg/module_manager/go_hook"
"github.com/flant/addon-operator/pkg/utils"
"github.com/flant/addon-operator/pkg/values/validation"
@@ -54,8 +54,7 @@ type DirectoryConfig struct {
}
type KubeConfigManager interface {
- SaveGlobalConfigValues(values utils.Values) error
- SaveModuleConfigValues(moduleName string, values utils.Values) error
+ SaveConfigValues(key string, values utils.Values) error
}
// ModuleManagerDependencies pass dependencies for ModuleManager
@@ -221,7 +220,7 @@ func (mm *ModuleManager) runModulesEnabledScript(modules []string, logLabels map
// - mm.enabledModulesByConfig
// - mm.kubeGlobalConfigValues
// - mm.kubeModulesConfigValues
-func (mm *ModuleManager) HandleNewKubeConfig(kubeConfig *kube_config_manager.KubeConfig) (*ModulesState, error) {
+func (mm *ModuleManager) HandleNewKubeConfig(kubeConfig *config.KubeConfig) (*ModulesState, error) {
var err error
mm.warnAboutUnknownModules(kubeConfig)
@@ -243,15 +242,12 @@ func (mm *ModuleManager) HandleNewKubeConfig(kubeConfig *kube_config_manager.Kub
newGlobalValues = make(utils.Values)
}
if kubeConfig != nil && kubeConfig.Global != nil {
- globalChecksum, err := mm.kubeGlobalConfigValues.Checksum()
- if err != nil {
- return nil, err
- }
+ globalChecksum := mm.kubeGlobalConfigValues.Checksum()
if kubeConfig.Global.Checksum != globalChecksum {
hasGlobalChange = true
}
- newGlobalValues = kubeConfig.Global.Values
+ newGlobalValues = kubeConfig.Global.GetValues()
}
// Full reload if enabled flags are changed.
@@ -277,7 +273,7 @@ func (mm *ModuleManager) HandleNewKubeConfig(kubeConfig *kube_config_manager.Kub
modValues, hasConfigValues := mm.kubeModulesConfigValues[moduleName]
// New module state from ConfigMap.
hasNewKubeConfig := false
- var newModConfig *kube_config_manager.ModuleKubeConfig
+ var newModConfig *config.ModuleKubeConfig
if kubeConfig != nil {
newModConfig, hasNewKubeConfig = kubeConfig.Modules[moduleName]
}
@@ -290,14 +286,8 @@ func (mm *ModuleManager) HandleNewKubeConfig(kubeConfig *kube_config_manager.Kub
// Compare checksums for new and saved values.
if hasConfigValues && hasNewKubeConfig {
- modValuesChecksum, err := modValues.Checksum()
- if err != nil {
- return nil, err
- }
- newModValuesChecksum, err := newModConfig.Values.Checksum()
- if err != nil {
- return nil, err
- }
+ modValuesChecksum := modValues.Checksum()
+ newModValuesChecksum := newModConfig.GetValues().Checksum()
if modValuesChecksum != newModValuesChecksum {
modulesChanged = append(modulesChanged, moduleName)
}
@@ -309,7 +299,7 @@ func (mm *ModuleManager) HandleNewKubeConfig(kubeConfig *kube_config_manager.Kub
newKubeModuleConfigValues := make(map[string]utils.Values)
if kubeConfig != nil {
for moduleName, moduleConfig := range kubeConfig.Modules {
- newKubeModuleConfigValues[moduleName] = moduleConfig.Values
+ newKubeModuleConfigValues[moduleName] = moduleConfig.GetValues()
}
}
@@ -338,7 +328,7 @@ func (mm *ModuleManager) HandleNewKubeConfig(kubeConfig *kube_config_manager.Kub
}
// warnAboutUnknownModules prints to log all unknown module section names.
-func (mm *ModuleManager) warnAboutUnknownModules(kubeConfig *kube_config_manager.KubeConfig) {
+func (mm *ModuleManager) warnAboutUnknownModules(kubeConfig *config.KubeConfig) {
// Ignore empty kube config.
if kubeConfig == nil {
return
@@ -361,7 +351,7 @@ func (mm *ModuleManager) warnAboutUnknownModules(kubeConfig *kube_config_manager
//
// Module is enabled by config if module section in ConfigMap is a map or an array
// or ConfigMap has no module section and module has a map or an array in values.yaml
-func (mm *ModuleManager) calculateEnabledModulesByConfig(config *kube_config_manager.KubeConfig) map[string]struct{} {
+func (mm *ModuleManager) calculateEnabledModulesByConfig(config *config.KubeConfig) map[string]struct{} {
enabledByConfig := make(map[string]struct{})
for _, module := range mm.modules.List() {
@@ -433,7 +423,7 @@ func (mm *ModuleManager) Init() error {
}
// validateKubeConfig checks validity of all sections in ConfigMap with OpenAPI schemas.
-func (mm *ModuleManager) validateKubeConfig(kubeConfig *kube_config_manager.KubeConfig, enabledModules map[string]struct{}) error {
+func (mm *ModuleManager) validateKubeConfig(kubeConfig *config.KubeConfig, enabledModules map[string]struct{}) error {
// Ignore empty kube config.
if kubeConfig == nil {
mm.SetKubeConfigValuesValid(true)
@@ -442,7 +432,7 @@ func (mm *ModuleManager) validateKubeConfig(kubeConfig *kube_config_manager.Kube
// Validate values in global section merged with static values.
var validationErr error
if kubeConfig.Global != nil {
- err := mm.ValuesValidator.ValidateGlobalConfigValues(mm.GlobalStaticAndNewValues(kubeConfig.Global.Values))
+ err := mm.ValuesValidator.ValidateGlobalConfigValues(mm.GlobalStaticAndNewValues(kubeConfig.Global.GetValues()))
if err != nil {
validationErr = multierror.Append(
validationErr,
@@ -459,11 +449,11 @@ func (mm *ModuleManager) validateKubeConfig(kubeConfig *kube_config_manager.Kube
continue
}
mod := mm.GetModule(moduleName)
- moduleErr := mm.ValuesValidator.ValidateModuleConfigValues(mod.ValuesKey(), mod.StaticAndNewValues(modCfg.Values))
+ moduleErr := mm.ValuesValidator.ValidateModuleConfigValues(mod.ValuesKey(), mod.StaticAndNewValues(modCfg.GetValues()))
if moduleErr != nil {
validationErr = multierror.Append(
validationErr,
- fmt.Errorf("'%s' module section in ConfigMap/%s is not valid", mod.ValuesKey(), app.ConfigMapName),
+ fmt.Errorf("'%s' module section in KubeConfig is not valid", mod.ValuesKey()),
moduleErr,
)
}
@@ -767,10 +757,7 @@ func (mm *ModuleManager) RunGlobalHook(hookName string, binding BindingType, bin
if err != nil {
return "", "", err
}
- beforeChecksum, err := beforeValues.Checksum()
- if err != nil {
- return "", "", err
- }
+ beforeChecksum := beforeValues.Checksum()
// Update kubernetes snapshots just before execute a hook
if binding == OnKubernetesEvent || binding == Schedule {
@@ -796,10 +783,7 @@ func (mm *ModuleManager) RunGlobalHook(hookName string, binding BindingType, bin
if err != nil {
return "", "", err
}
- afterChecksum, err := afterValues.Checksum()
- if err != nil {
- return "", "", err
- }
+ afterChecksum := afterValues.Checksum()
return beforeChecksum, afterChecksum, nil
}
@@ -811,10 +795,7 @@ func (mm *ModuleManager) RunModuleHook(hookName string, binding BindingType, bin
if err != nil {
return "", "", err
}
- valuesChecksum, err := values.Checksum()
- if err != nil {
- return "", "", err
- }
+ valuesChecksum := values.Checksum()
// Update kubernetes snapshots just before execute a hook
// Note: BeforeHelm and AfterHelm are run by runHookByBinding
@@ -838,10 +819,7 @@ func (mm *ModuleManager) RunModuleHook(hookName string, binding BindingType, bin
if err != nil {
return "", "", err
}
- newValuesChecksum, err := newValues.Checksum()
- if err != nil {
- return "", "", err
- }
+ newValuesChecksum := newValues.Checksum()
return valuesChecksum, newValuesChecksum, nil
}
diff --git a/pkg/module_manager/module_manager_test.go b/pkg/module_manager/module_manager_test.go
index 48d8ceb5..373142d0 100644
--- a/pkg/module_manager/module_manager_test.go
+++ b/pkg/module_manager/module_manager_test.go
@@ -20,6 +20,8 @@ import (
mockhelmresmgr "github.com/flant/addon-operator/pkg/helm_resources_manager/test/mock"
. "github.com/flant/addon-operator/pkg/hook/types"
"github.com/flant/addon-operator/pkg/kube_config_manager"
+ "github.com/flant/addon-operator/pkg/kube_config_manager/backend/configmap"
+ "github.com/flant/addon-operator/pkg/kube_config_manager/config"
_ "github.com/flant/addon-operator/pkg/module_manager/test/go_hooks/global-hooks"
"github.com/flant/addon-operator/pkg/utils"
klient "github.com/flant/kube-client/client"
@@ -33,8 +35,8 @@ type TestKubeConfigManager interface {
Init() error
Start()
Stop()
- KubeConfigEventCh() chan kube_config_manager.KubeConfigEvent
- SafeReadConfig(handler func(config *kube_config_manager.KubeConfig))
+ KubeConfigEventCh() chan config.KubeConfigEvent
+ SafeReadConfig(handler func(config *config.KubeConfig))
}
type initModuleManagerResult struct {
@@ -42,7 +44,7 @@ type initModuleManagerResult struct {
kubeConfigManager TestKubeConfigManager
helmClient *mockhelm.Client
helmResourcesManager *mockhelmresmgr.MockHelmResourcesManager
- kubeClient klient.Client
+ kubeClient *klient.Client
initialState *ModulesState
initialStateErr error
cmName string
@@ -102,13 +104,8 @@ func initModuleManager(t *testing.T, configPath string) (*ModuleManager, *initMo
require.NoError(t, err, "Should create ConfigMap/%s", result.cmName)
}
- kcfg := kube_config_manager.Config{
- Namespace: result.cmNamespace,
- ConfigMapName: result.cmName,
- KubeClient: result.kubeClient,
- RuntimeConfig: nil,
- }
- manager := kube_config_manager.NewKubeConfigManager(context.Background(), &kcfg)
+ bk := configmap.New(nil, result.kubeClient, result.cmNamespace, result.cmName)
+ manager := kube_config_manager.NewKubeConfigManager(context.Background(), bk, nil)
result.kubeConfigManager = manager
err = result.kubeConfigManager.Init()
@@ -138,7 +135,7 @@ func initModuleManager(t *testing.T, configPath string) (*ModuleManager, *initMo
// Start KubeConfigManager to be able to change config values via patching ConfigMap.
result.kubeConfigManager.Start()
- result.kubeConfigManager.SafeReadConfig(func(config *kube_config_manager.KubeConfig) {
+ result.kubeConfigManager.SafeReadConfig(func(config *config.KubeConfig) {
result.initialState, result.initialStateErr = result.moduleManager.HandleNewKubeConfig(config)
})
@@ -191,11 +188,11 @@ func Test_ModuleManager_LoadValuesInInit(t *testing.T) {
with1 := mm.modules.Get("with-values-1")
assert.NotNil(t, with1.StaticConfig)
- assert.Equal(t, modWithValues1Expected, with1.StaticConfig.Values)
+ assert.Equal(t, modWithValues1Expected, with1.StaticConfig.GetValues())
with2 := mm.modules.Get("with-values-2")
assert.NotNil(t, with2.StaticConfig)
- assert.Equal(t, modWithValues2Expected, with2.StaticConfig.Values)
+ assert.Equal(t, modWithValues2Expected, with2.StaticConfig.GetValues())
},
},
{
@@ -227,19 +224,19 @@ func Test_ModuleManager_LoadValuesInInit(t *testing.T) {
assert.NotNil(t, with1.CommonStaticConfig)
assert.NotNil(t, with1.StaticConfig)
assert.Equal(t, "with-values-1", with1.CommonStaticConfig.ModuleName)
- assert.Equal(t, "withValues1", with1.CommonStaticConfig.ModuleConfigKey)
- assert.Equal(t, "withValues1Enabled", with1.CommonStaticConfig.ModuleEnabledKey)
+ assert.Equal(t, "withValues1", with1.CommonStaticConfig.ModuleConfigKey())
+ assert.Equal(t, "withValues1Enabled", with1.CommonStaticConfig.ModuleEnabledKey())
assert.Equal(t, "with-values-1", with1.StaticConfig.ModuleName)
// with-values-1 is enabled by common values.yaml
assert.True(t, *with1.CommonStaticConfig.IsEnabled)
assert.False(t, *with1.StaticConfig.IsEnabled)
- assert.Len(t, with1.CommonStaticConfig.Values["withValues1"], 1)
- assert.Len(t, with1.StaticConfig.Values["withValues1"], 3)
+ assert.Len(t, with1.CommonStaticConfig.GetValues()["withValues1"], 1)
+ assert.Len(t, with1.StaticConfig.GetValues()["withValues1"], 3)
// with-values-1 has "a" value in common and in module static values
- assert.Contains(t, with1.CommonStaticConfig.Values["withValues1"], "a")
- assert.Contains(t, with1.StaticConfig.Values["withValues1"], "a")
+ assert.Contains(t, with1.CommonStaticConfig.GetValues()["withValues1"], "a")
+ assert.Contains(t, with1.StaticConfig.GetValues()["withValues1"], "a")
assert.NotContains(t, mm.kubeModulesConfigValues, "with-values-1")
@@ -293,8 +290,8 @@ func Test_ModuleManager_LoadValues_ApplyDefaults(t *testing.T) {
assert.NotNil(t, modOne.StaticConfig)
assert.Equal(t, "module-one", modOne.CommonStaticConfig.ModuleName)
assert.Equal(t, "module-one", modOne.StaticConfig.ModuleName)
- assert.Equal(t, "moduleOne", modOne.CommonStaticConfig.ModuleConfigKey)
- assert.Equal(t, "moduleOneEnabled", modOne.CommonStaticConfig.ModuleEnabledKey)
+ assert.Equal(t, "moduleOne", modOne.CommonStaticConfig.ModuleConfigKey())
+ assert.Equal(t, "moduleOneEnabled", modOne.CommonStaticConfig.ModuleEnabledKey())
// module-one is not enabled in any of values.yaml
assert.Nil(t, modOne.CommonStaticConfig.IsEnabled)
@@ -1231,7 +1228,7 @@ func Test_ModuleManager_ModulesState_detect_ConfigMap_changes(t *testing.T) {
<-res.kubeConfigManager.KubeConfigEventCh()
var state *ModulesState
- res.kubeConfigManager.SafeReadConfig(func(config *kube_config_manager.KubeConfig) {
+ res.kubeConfigManager.SafeReadConfig(func(config *config.KubeConfig) {
state, err = mm.HandleNewKubeConfig(config)
})
require.Len(t, state.ModulesToReload, 0, "Enabled flag change should lead to reload all modules")
@@ -1271,7 +1268,7 @@ func Test_ModuleManager_ModulesState_detect_ConfigMap_changes(t *testing.T) {
<-res.kubeConfigManager.KubeConfigEventCh()
var state *ModulesState
- res.kubeConfigManager.SafeReadConfig(func(config *kube_config_manager.KubeConfig) {
+ res.kubeConfigManager.SafeReadConfig(func(config *config.KubeConfig) {
state, err = mm.HandleNewKubeConfig(config)
})
require.Len(t, state.ModulesToReload, 2, "Enabled flag change should lead to reload all modules")
@@ -1311,7 +1308,7 @@ func Test_ModuleManager_ModulesState_detect_ConfigMap_changes(t *testing.T) {
<-res.kubeConfigManager.KubeConfigEventCh()
var state *ModulesState
- res.kubeConfigManager.SafeReadConfig(func(config *kube_config_manager.KubeConfig) {
+ res.kubeConfigManager.SafeReadConfig(func(config *config.KubeConfig) {
state, err = mm.HandleNewKubeConfig(config)
})
require.NoError(t, err, "Should handle new ConfigMap")
diff --git a/pkg/utils/logger/logger.go b/pkg/utils/logger/logger.go
new file mode 100644
index 00000000..08a42d2c
--- /dev/null
+++ b/pkg/utils/logger/logger.go
@@ -0,0 +1,33 @@
+package logger
+
+type Logger interface {
+ // standard logger methods
+ Print(args ...interface{})
+ Printf(format string, args ...interface{})
+ Println(args ...interface{})
+
+ Fatal(args ...interface{})
+ Fatalf(format string, args ...interface{})
+ Fatalln(args ...interface{})
+
+ Panic(args ...interface{})
+ Panicf(format string, args ...interface{})
+ Panicln(args ...interface{})
+
+ // Leveled methods, from logrus
+ Debug(args ...interface{})
+ Debugf(format string, args ...interface{})
+ Debugln(args ...interface{})
+
+ Error(args ...interface{})
+ Errorf(format string, args ...interface{})
+ Errorln(args ...interface{})
+
+ Info(args ...interface{})
+ Infof(format string, args ...interface{})
+ Infoln(args ...interface{})
+
+ Warn(args ...interface{})
+ Warnf(format string, args ...interface{})
+ Warnln(args ...interface{})
+}
diff --git a/pkg/utils/module_config.go b/pkg/utils/module_config.go
index 535aceef..2bf7b6f4 100644
--- a/pkg/utils/module_config.go
+++ b/pkg/utils/module_config.go
@@ -3,10 +3,10 @@ package utils
import (
"encoding/json"
"fmt"
+ "strconv"
"strings"
"github.com/davecgh/go-spew/spew"
- "sigs.k8s.io/yaml"
utils_checksum "github.com/flant/shell-operator/pkg/utils/checksum"
)
@@ -17,18 +17,25 @@ var (
)
type ModuleConfig struct {
- ModuleName string
- IsEnabled *bool
- Values Values
- IsUpdated bool
- ModuleConfigKey string
- ModuleEnabledKey string
- RawConfig []string
+ ModuleName string
+ IsEnabled *bool
+ // module values, don't read it directly, use GetValues() for reading
+ values Values
}
// String returns description of ModuleConfig values.
func (mc *ModuleConfig) String() string {
- return fmt.Sprintf("Module(Name=%s IsEnabled=%v IsUpdated=%v Values:\n%s)", mc.ModuleName, mc.IsEnabled, mc.IsUpdated, mc.Values.DebugString())
+ return fmt.Sprintf("Module(Name=%s IsEnabled=%v Values:\n%s)", mc.ModuleName, mc.IsEnabled, mc.values.DebugString())
+}
+
+// ModuleConfigKey transforms module kebab-case name to the config camelCase name
+func (mc *ModuleConfig) ModuleConfigKey() string {
+ return ModuleNameToValuesKey(mc.ModuleName)
+}
+
+// ModuleEnabledKey transforms module kebab-case name to the config camelCase name with 'Enabled' suffix
+func (mc *ModuleConfig) ModuleEnabledKey() string {
+ return ModuleNameToValuesKey(mc.ModuleName) + "Enabled"
}
// GetEnabled returns string description of enabled status.
@@ -46,34 +53,36 @@ func (mc *ModuleConfig) GetEnabled() string {
}
}
-func NewModuleConfig(moduleName string) *ModuleConfig {
+func NewModuleConfig(moduleName string, values Values) *ModuleConfig {
+ if values == nil {
+ values = make(Values)
+ }
return &ModuleConfig{
- ModuleName: moduleName,
- IsEnabled: nil,
- Values: make(Values),
- ModuleConfigKey: ModuleNameToValuesKey(moduleName),
- ModuleEnabledKey: ModuleNameToValuesKey(moduleName) + "Enabled",
- RawConfig: make([]string, 0),
+ ModuleName: moduleName,
+ IsEnabled: nil,
+ values: values,
}
}
-func (mc *ModuleConfig) WithEnabled(v bool) *ModuleConfig {
- if v {
- mc.IsEnabled = &ModuleEnabled
- } else {
- mc.IsEnabled = &ModuleDisabled
+// GetValues enrich module values with module's name top level key
+// if key is already present - returns values as it
+// module: test-module with values {"a": "b", "c": "d} will return:
+//
+// testModule:
+// a: b
+// c: d
+/* TODO: since we have specified struct for module values, we don't need to encapsulate them into the map {"": ... }
+ we have to change this behavior somewhere in the module-manager */
+func (mc *ModuleConfig) GetValues() Values {
+ if len(mc.values) == 0 {
+ return mc.values
}
- return mc
-}
-func (mc *ModuleConfig) WithUpdated(v bool) *ModuleConfig {
- mc.IsUpdated = v
- return mc
-}
+ if mc.values.HasKey(ModuleNameToValuesKey(mc.ModuleName)) {
+ return mc.values
+ }
-func (mc *ModuleConfig) WithValues(values Values) *ModuleConfig {
- mc.Values = values
- return mc
+ return Values{ModuleNameToValuesKey(mc.ModuleName): mc.values}
}
// LoadFromValues loads module config from a map.
@@ -81,25 +90,25 @@ func (mc *ModuleConfig) WithValues(values Values) *ModuleConfig {
// Values for module in `values` map are addressed by a key.
// This key should be produced with ModuleNameToValuesKey.
func (mc *ModuleConfig) LoadFromValues(values Values) (*ModuleConfig, error) {
- if moduleValuesData, hasModuleData := values[mc.ModuleConfigKey]; hasModuleData {
+ if moduleValuesData, hasModuleData := values[mc.ModuleConfigKey()]; hasModuleData {
switch v := moduleValuesData.(type) {
case map[string]interface{}, []interface{}:
- data := map[string]interface{}{mc.ModuleConfigKey: v}
+ data := map[string]interface{}{mc.ModuleConfigKey(): v}
values, err := NewValues(data)
if err != nil {
return nil, err
}
- mc.Values = values
+ mc.values = values
default:
return nil, fmt.Errorf("load '%s' values: module config should be array or map. Got: %s", mc.ModuleName, spew.Sdump(moduleValuesData))
}
}
- if moduleEnabled, hasModuleEnabled := values[mc.ModuleEnabledKey]; hasModuleEnabled {
+ if moduleEnabled, hasModuleEnabled := values[mc.ModuleEnabledKey()]; hasModuleEnabled {
switch v := moduleEnabled.(type) {
case bool:
- mc.WithEnabled(v)
+ mc.IsEnabled = &v
default:
return nil, fmt.Errorf("load '%s' enable config: enabled value should be bool. Got: %#v", mc.ModuleName, moduleEnabled)
}
@@ -124,74 +133,16 @@ func (mc *ModuleConfig) FromYaml(yamlString []byte) (*ModuleConfig, error) {
return nil, fmt.Errorf("load module '%s' yaml config: %s\n%s", mc.ModuleName, err, string(yamlString))
}
- mc.RawConfig = []string{string(yamlString)}
-
return mc.LoadFromValues(values)
}
-// FromConfigMapData loads module config from a structure with string keys and yaml string values (ConfigMap)
-//
-// Example:
-//
-// simpleModule: |
-// param1: 10
-// param2: 120
-// simpleModuleEnabled: "true"
-
-// TODO "msg": "Kube config manager: cannot handle ConfigMap update: ConfigMap:
-// bad yaml at key 'deployWithHooks':
-// data is not compatible with JSON and YAML:
-// error marshaling into JSON:
-// json: unsupported type: map[interface {}]interface {}, data:
-// (map[string]interface {}) (len=1) {\n (string) (len=15) \"deployWithHooks\": (map[interface {}]interface {}) (len=3) {\n (string) (len=6) \"param2\": (string) (len=11) \"srqweqweqwe\",\n (string) (len=8) \"paramArr\": ([]interface {}) (len=4 cap=4) {\n (string) (len=3) \"asd\",\n (string) (len=3) \"qwe\",\n (string) (len=6) \"sadasd\",\n (string) (len=5) \"salad\"\n },\n (string) (len=6) \"param1\": (int) 1\n }\n}\n",
-
-func (mc *ModuleConfig) FromConfigMapData(configData map[string]string) (*ModuleConfig, error) {
- // create Values with moduleNameKey and moduleEnabled keys
- configValues := make(Values)
-
- // if there is data for module, unmarshal it and put into configValues
- valuesYaml, hasKey := configData[mc.ModuleConfigKey]
- if hasKey {
- var moduleValues interface{}
-
- err := yaml.Unmarshal([]byte(valuesYaml), &moduleValues)
- if err != nil {
- return nil, fmt.Errorf("unmarshal yaml data in a module config key '%s': %v", mc.ModuleConfigKey, err)
- }
-
- configValues[mc.ModuleConfigKey] = moduleValues
-
- mc.RawConfig = append(mc.RawConfig, valuesYaml)
- }
-
- // if there is enabled key, treat it as boolean
- enabledString, hasKey := configData[mc.ModuleEnabledKey]
- if hasKey {
- var enabled bool
-
- switch enabledString {
- case "true":
- enabled = true
- case "false":
- enabled = false
- default:
- return nil, fmt.Errorf("module enabled key '%s' should have a boolean value, got '%v'", mc.ModuleEnabledKey, enabledString)
- }
-
- configValues[mc.ModuleEnabledKey] = enabled
-
- mc.RawConfig = append(mc.RawConfig, enabledString)
- }
-
- if len(configValues) == 0 {
- return mc, nil
- }
-
- return mc.LoadFromValues(configValues)
-}
-
func (mc *ModuleConfig) Checksum() string {
- return utils_checksum.CalculateChecksum(mc.RawConfig...)
+ vChecksum := mc.values.Checksum()
+ enabled := ""
+ if mc.IsEnabled != nil {
+ enabled = strconv.FormatBool(*mc.IsEnabled)
+ }
+ return utils_checksum.CalculateChecksum(enabled, vChecksum)
}
func ModuleEnabledValue(i interface{}) (*bool, error) {
diff --git a/pkg/utils/module_config_test.go b/pkg/utils/module_config_test.go
index 58e2c8d9..2cc35852 100644
--- a/pkg/utils/module_config_test.go
+++ b/pkg/utils/module_config_test.go
@@ -5,6 +5,7 @@ import (
. "github.com/onsi/gomega"
. "github.com/onsi/gomega/gstruct"
+ "k8s.io/utils/pointer"
)
// Test_FromYaml creates ModuleConfig objects from different input yaml strings
@@ -45,7 +46,7 @@ testModule:
func() {
g.Expect(err).ShouldNot(HaveOccurred())
g.Expect(config).ToNot(BeNil())
- g.Expect(config.Values).To(BeEmpty())
+ g.Expect(config.GetValues()).To(BeEmpty())
g.Expect(config.IsEnabled).To(Equal(&ModuleDisabled))
},
},
@@ -55,7 +56,7 @@ testModule:
func() {
g.Expect(err).ShouldNot(HaveOccurred())
g.Expect(config).ToNot(BeNil())
- g.Expect(config.Values).To(BeEmpty())
+ g.Expect(config.GetValues()).To(BeEmpty())
g.Expect(config.IsEnabled).To(Equal(&ModuleEnabled))
},
},
@@ -78,11 +79,11 @@ testModuleEnabled: true
g.Expect(config).ToNot(BeNil())
g.Expect(config.IsEnabled).To(Equal(&ModuleEnabled))
- g.Expect(config.Values).ToNot(BeEmpty())
- g.Expect(config.Values).To(HaveKey("testModule"))
- g.Expect(config.Values["testModule"]).To(BeAssignableToTypeOf(map[string]interface{}{}))
+ g.Expect(config.GetValues()).ToNot(BeEmpty())
+ g.Expect(config.GetValues()).To(HaveKey("testModule"))
+ g.Expect(config.GetValues()["testModule"]).To(BeAssignableToTypeOf(map[string]interface{}{}))
- modValsMap := config.Values["testModule"].(map[string]interface{})
+ modValsMap := config.GetValues()["testModule"].(map[string]interface{})
g.Expect(modValsMap["hello"]).To(Equal("world"))
g.Expect(modValsMap["4"]).To(Equal("123"))
g.Expect(modValsMap["5"]).To(Equal(5.0))
@@ -112,7 +113,7 @@ testModule:
return (element.(map[string]interface{})["id"]).(string)
}
- g.Expect(config.Values).To(MatchAllKeys(Keys{
+ g.Expect(config.GetValues()).To(MatchAllKeys(Keys{
"testModule": MatchAllElements(arrayID, Elements{
"0": MatchAllKeys(Keys{
"a": Equal(1.0),
@@ -131,7 +132,7 @@ testModule:
t.Run(test.name, func(t *testing.T) {
config = nil
err = nil
- config, err = NewModuleConfig("test-module").FromYaml([]byte(test.yaml))
+ config, err = NewModuleConfig("test-module", nil).FromYaml([]byte(test.yaml))
test.assertFn()
})
}
@@ -163,24 +164,6 @@ testModule:
testModuleEnabled: true
`
- configMapDataMapValues := map[string]string{
- "global": `asd: qwe`,
- "test-module": `
-foo: bar
-`,
- "testModule": `
-hello: world
-4: "123"
-5: 5
-aaa:
- "no":
- - one
- - two
- - three
-`,
- "testModuleEnabled": "false",
- }
-
expectedData := Values{
"testModule": map[string]interface{}{
"hello": "world", "4": "123", "5": 5.0,
@@ -188,24 +171,17 @@ aaa:
},
}
- config, err = NewModuleConfig("test-module").LoadFromValues(inputData)
+ config, err = NewModuleConfig("test-module", nil).LoadFromValues(inputData)
g.Expect(err).ShouldNot(HaveOccurred())
g.Expect(config).ToNot(BeNil())
- g.Expect(config.Values).To(Equal(expectedData))
+ g.Expect(config.GetValues()).To(Equal(expectedData))
- config, err = NewModuleConfig("test-module").FromYaml([]byte(inputValuesYaml))
+ config, err = NewModuleConfig("test-module", nil).FromYaml([]byte(inputValuesYaml))
g.Expect(err).ShouldNot(HaveOccurred())
g.Expect(config).ToNot(BeNil())
- g.Expect(config.Values).To(Equal(expectedData))
+ g.Expect(config.GetValues()).To(Equal(expectedData))
g.Expect(config.IsEnabled).ToNot(BeNil())
g.Expect(config.IsEnabled).To(Equal(&ModuleEnabled))
-
- config, err = NewModuleConfig("test-module").FromConfigMapData(configMapDataMapValues)
- g.Expect(err).ShouldNot(HaveOccurred())
- g.Expect(config).ToNot(BeNil())
- g.Expect(config.Values).To(Equal(expectedData))
- g.Expect(config.IsEnabled).ToNot(BeNil())
- g.Expect(config.IsEnabled).To(Equal(&ModuleDisabled))
}
func Test_GetEnabled(t *testing.T) {
@@ -245,7 +221,7 @@ func Test_GetEnabled(t *testing.T) {
"nil",
func() {
config = &ModuleConfig{}
- config.WithEnabled(true)
+ config.IsEnabled = pointer.Bool(true)
},
"true",
},
@@ -253,7 +229,7 @@ func Test_GetEnabled(t *testing.T) {
"nil",
func() {
config = &ModuleConfig{}
- config.WithEnabled(false)
+ config.IsEnabled = pointer.Bool(false)
},
"false",
},
diff --git a/pkg/utils/values.go b/pkg/utils/values.go
index e7f5c25e..6de53284 100644
--- a/pkg/utils/values.go
+++ b/pkg/utils/values.go
@@ -115,12 +115,10 @@ func (v Values) DebugString() string {
return string(b)
}
-func (v Values) Checksum() (string, error) {
- valuesJson, err := json.Marshal(v)
- if err != nil {
- return "", err
- }
- return utils_checksum.CalculateChecksum(string(valuesJson)), nil
+func (v Values) Checksum() string {
+ valuesJson, _ := json.Marshal(v)
+
+ return utils_checksum.CalculateChecksum(string(valuesJson))
}
func (v Values) HasKey(key string) bool {