diff -Nru vip-manager2-2.2.0/.github/workflows/build.yml vip-manager2-2.3.0/.github/workflows/build.yml --- vip-manager2-2.2.0/.github/workflows/build.yml 2024-01-08 10:25:51.000000000 +0000 +++ vip-manager2-2.3.0/.github/workflows/build.yml 2024-01-19 07:32:37.000000000 +0000 @@ -19,6 +19,12 @@ uses: actions/setup-go@v5 with: go-version: '1.21' + + - name: Get dependencies + run: | + go mod download + go version + go build - name: GolangCI-Lint if: runner.os == 'Linux' @@ -27,15 +33,21 @@ version: latest args: --verbose - - name: Get dependencies + - uses: awalsh128/cache-apt-pkgs-action@latest + if: runner.os == 'Linux' + with: + packages: etcd ncat + version: 1.0 + + - name: Test E2E + if: runner.os == 'Linux' run: | - go mod download - go version - go build + sudo test/behaviour_test.sh + sudo rm -r default.etcd || true - name: Run GoReleaser if: runner.os == 'Linux' uses: goreleaser/goreleaser-action@v5 with: version: latest - args: release --snapshot --skip-publish --clean + args: release --snapshot --skip=publish --clean diff -Nru vip-manager2-2.2.0/.goreleaser.yml vip-manager2-2.3.0/.goreleaser.yml --- vip-manager2-2.2.0/.goreleaser.yml 2024-01-08 10:25:51.000000000 +0000 +++ vip-manager2-2.3.0/.goreleaser.yml 2024-01-19 07:32:37.000000000 +0000 @@ -13,7 +13,7 @@ archives: - name_template: >- - {{ .ProjectName }}_ + {{ .ProjectName }}_{{ .Version }}_ {{- title .Os }}_ {{- if eq .Arch "amd64" }}x86_64 {{- else if eq .Arch "386" }}i386 @@ -42,7 +42,7 @@ # note that this is an array of nfpm configs - file_name_template: >- - {{ .ProjectName }}_ + {{ .ProjectName }}_{{ .Version }}_ {{- title .Os }}_ {{- if eq .Arch "amd64" }}x86_64 {{- else if eq .Arch "386" }}i386 diff -Nru vip-manager2-2.2.0/README.md vip-manager2-2.3.0/README.md --- vip-manager2-2.2.0/README.md 2024-01-08 10:25:51.000000000 +0000 +++ vip-manager2-2.3.0/README.md 2024-01-19 07:32:37.000000000 +0000 @@ -125,7 +125,7 @@ `etcd-user` | `VIP_ETCD_USER` | no | patroni | A username that is allowed to look at the `trigger-key` in an etcd DCS. Optional when using `dcs-type=etcd` . `etcd-password` | `VIP_ETCD_PASSWORD` | no | snakeoil | The password for `etcd-user`. Optional when using `dcs-type=etcd` . Requires that `etcd-user` is also set. `consul-token` | `VIP_CONSUL_TOKEN` | no | snakeoil | A token that can be used with the consul-API for authentication. Optional when using `dcs-type=consul` . -`interval` | `VIP_INTERVAL` | no | 1000 | The time vip-manager main loop sleeps before checking for changes. Measured in ms. Defaults to `1000`. +`interval` | `VIP_INTERVAL` | no | 1000 | The time vip-manager main loop sleeps before checking for changes. Measured in ms. Defaults to `1000`. Doesn't affect etcd checker since v2.3.0. `retry-after` | `VIP_RETRY_AFTER` | no | 250 | The time to wait before retrying interactions with components outside of vip-manager. Measured in ms. Defaults to `250`. `retry-num` | `VIP_RETRY_NUM` | no | 3 | The number of times interactions with components outside of vip-manager are retried. Defaults to `3`. `etcd-ca-file` | `VIP_ETCD_CA_FILE` | no | /etc/etcd/ca.cert.pem | A certificate authority file that can be used to verify the certificate provided by etcd endpoints. Make sure to change `dcs-endpoints` to reflect that `https` is used. diff -Nru vip-manager2-2.2.0/checker/etcd_leader_checker.go vip-manager2-2.3.0/checker/etcd_leader_checker.go --- vip-manager2-2.2.0/checker/etcd_leader_checker.go 2024-01-08 10:25:51.000000000 +0000 +++ vip-manager2-2.3.0/checker/etcd_leader_checker.go 2024-01-19 07:32:37.000000000 +0000 @@ -10,22 +10,35 @@ "time" "github.com/cybertec-postgresql/vip-manager/vipconfig" - client "go.etcd.io/etcd/client/v3" + clientv3 "go.etcd.io/etcd/client/v3" ) // EtcdLeaderChecker is used to check state of the leader key in Etcd type EtcdLeaderChecker struct { - key string - nodename string - kapi client.KV + *vipconfig.Config + *clientv3.Client } -// naming this c_conf to avoid conflict with conf in etcd_leader_checker.go -var eConf *vipconfig.Config +// NewEtcdLeaderChecker returns a new instance +func NewEtcdLeaderChecker(conf *vipconfig.Config) (*EtcdLeaderChecker, error) { + tlsConfig, err := getTransport(conf) + if err != nil { + return nil, err + } + cfg := clientv3.Config{ + Endpoints: conf.Endpoints, + TLS: tlsConfig, + DialKeepAliveTimeout: 5 * time.Second, + DialKeepAliveTime: 5 * time.Second, + Username: conf.EtcdUser, + Password: conf.EtcdPassword, + } + c, err := clientv3.New(cfg) + return &EtcdLeaderChecker{conf, c}, err +} func getTransport(conf *vipconfig.Config) (*tls.Config, error) { var caCertPool *x509.CertPool - // create valid CertPool only if the ca certificate file exists if conf.EtcdCAFile != "" { caCert, err := os.ReadFile(conf.EtcdCAFile) @@ -36,9 +49,7 @@ caCertPool = x509.NewCertPool() caCertPool.AppendCertsFromPEM(caCert) } - var certificates []tls.Certificate - // create valid []Certificate only if the client cert and key files exists if conf.EtcdCertFile != "" && conf.EtcdKeyFile != "" { cert, err := tls.LoadX509KeyPair(conf.EtcdCertFile, conf.EtcdKeyFile) @@ -48,79 +59,57 @@ certificates = []tls.Certificate{cert} } - tlsClientConfig := new(tls.Config) - if caCertPool != nil { tlsClientConfig.RootCAs = caCertPool if certificates != nil { tlsClientConfig.Certificates = certificates } } - return tlsClientConfig, nil } -// NewEtcdLeaderChecker returns a new instance -func NewEtcdLeaderChecker(con *vipconfig.Config) (*EtcdLeaderChecker, error) { - eConf = con - e := &EtcdLeaderChecker{key: eConf.Key, nodename: eConf.Nodename} - - tlsConfig, err := getTransport(eConf) - if err != nil { - return nil, err - } - - cfg := client.Config{ - Endpoints: eConf.Endpoints, - TLS: tlsConfig, - DialKeepAliveTimeout: time.Second, - Username: eConf.EtcdUser, - Password: eConf.EtcdPassword, - } - c, err := client.New(cfg) +// init gets the current leader from etcd +func (elc *EtcdLeaderChecker) init(ctx context.Context, out chan<- bool) { + resp, err := elc.Get(ctx, elc.Key) if err != nil { - return nil, err + log.Printf("etcd error: %s", err) + out <- false + return + } + for _, kv := range resp.Kvs { + log.Printf("Current Leader from DCS: %s", kv.Value) + out <- string(kv.Value) == elc.Nodename } - e.kapi = c.KV - return e, nil } -// GetChangeNotificationStream checks the status in the loop -func (e *EtcdLeaderChecker) GetChangeNotificationStream(ctx context.Context, out chan<- bool) error { - var state bool - var alreadyConnected = false -checkLoop: +// watch monitors the leader change from etcd +func (elc *EtcdLeaderChecker) watch(ctx context.Context, out chan<- bool) error { + watchChan := elc.Watch(ctx, elc.Key) + log.Println("set WATCH on " + elc.Key) for { - resp, err := e.kapi.Get(ctx, e.key) - - if err != nil { - if ctx.Err() != nil { - break checkLoop - } - log.Printf("etcd error: %s", err) - out <- false - time.Sleep(time.Duration(eConf.Interval) * time.Millisecond) - continue - } - - if (!alreadyConnected) { - log.Printf("etcd checker started up, found key %s", e.key) - alreadyConnected = true - } - - for _, kv := range resp.Kvs { - state = string(kv.Value) == e.nodename - } - select { case <-ctx.Done(): - break checkLoop - case out <- state: - time.Sleep(time.Duration(eConf.Interval) * time.Millisecond) - continue + return ctx.Err() + case watchResp := <-watchChan: + if err := watchResp.Err(); err != nil { + log.Printf("etcd watcher returned error: %s", err) + out <- false + continue + } + for _, event := range watchResp.Events { + out <- string(event.Kv.Value) == elc.Nodename + log.Printf("Current Leader from DCS: %s", event.Kv.Value) + } } } +} - return ctx.Err() +// GetChangeNotificationStream monitors the leader in etcd +func (elc *EtcdLeaderChecker) GetChangeNotificationStream(ctx context.Context, out chan<- bool) error { + defer elc.Close() + go elc.init(ctx, out) + wctx, cancel := context.WithCancel(ctx) + defer cancel() + return elc.watch(wctx, out) } diff -Nru vip-manager2-2.2.0/debian/changelog vip-manager2-2.3.0/debian/changelog --- vip-manager2-2.2.0/debian/changelog 2024-01-19 16:15:23.000000000 +0000 +++ vip-manager2-2.3.0/debian/changelog 2024-02-10 15:15:05.000000000 +0000 @@ -1,3 +1,12 @@ +vip-manager2 (2.3.0-1) unstable; urgency=medium + + * New upstream release. + * debian/patches/behaviour_test.patch: Refreshed. + * debian/patches/go_deps.patch: Likewise. + * debian/patches/etcd-3.4-build-fixes.patch: Likewise. + + -- Michael Banck Sat, 10 Feb 2024 16:15:05 +0100 + vip-manager2 (2.2.0-1) unstable; urgency=medium * New upstream release. diff -Nru vip-manager2-2.2.0/debian/patches/behaviour_test.patch vip-manager2-2.3.0/debian/patches/behaviour_test.patch --- vip-manager2-2.2.0/debian/patches/behaviour_test.patch 2023-10-24 15:43:22.000000000 +0000 +++ vip-manager2-2.3.0/debian/patches/behaviour_test.patch 2024-02-10 10:02:17.000000000 +0000 @@ -14,23 +14,12 @@ } dev="`get_dev`" -@@ -56,8 +57,8 @@ trap cleanup EXIT - # podman run -d --name etcd -p 2379:2379 -e "ETCD_ENABLE_V2=true" -e "ALLOW_NONE_AUTHENTICATION=yes" bitnami/etcd - - # run etcd locally maybe? --#etcd --enable-v2 & --#echo $! > .etcdPid -+etcd --enable-v2 & -+echo $! > .etcdPid - sleep 2 - - # simulate server, e.g. postgres @@ -67,7 +68,7 @@ echo $! > .ncatPid etcdctl del service/pgcluster/leader || true touch .failed --./vip-manager --interface $dev --ip $vip --netmask 32 --trigger-key service/pgcluster/leader --trigger-value $HOSTNAME & #2>&1 & -+vip-manager --interface $dev --ip $vip --netmask 32 --trigger-key service/pgcluster/leader --trigger-value $HOSTNAME & #2>&1 & +-./vip-manager --interval 3000 --interface $dev --ip $vip --netmask 32 --trigger-key service/pgcluster/leader --trigger-value $HOSTNAME & #2>&1 & ++vip-manager --interval 3000 --interface $dev --ip $vip --netmask 32 --trigger-key service/pgcluster/leader --trigger-value $HOSTNAME & #2>&1 & echo $! > .vipPid sleep 2 diff -Nru vip-manager2-2.2.0/debian/patches/etcd-3.4-build-fixes.patch vip-manager2-2.3.0/debian/patches/etcd-3.4-build-fixes.patch --- vip-manager2-2.2.0/debian/patches/etcd-3.4-build-fixes.patch 2023-10-24 15:43:22.000000000 +0000 +++ vip-manager2-2.3.0/debian/patches/etcd-3.4-build-fixes.patch 2024-02-10 10:05:25.000000000 +0000 @@ -6,8 +6,8 @@ "time" "github.com/cybertec-postgresql/vip-manager/vipconfig" -- client "go.etcd.io/etcd/client/v3" -+ client "go.etcd.io/etcd/clientv3" +- clientv3 "go.etcd.io/etcd/client/v3" ++ clientv3 "go.etcd.io/etcd/clientv3" ) // EtcdLeaderChecker is used to check state of the leader key in Etcd diff -Nru vip-manager2-2.2.0/debian/patches/go_deps.patch vip-manager2-2.3.0/debian/patches/go_deps.patch --- vip-manager2-2.2.0/debian/patches/go_deps.patch 2024-01-19 16:11:44.000000000 +0000 +++ vip-manager2-2.3.0/debian/patches/go_deps.patch 2024-02-10 10:02:59.000000000 +0000 @@ -33,6 +33,6 @@ github.com/spf13/viper v1.18.2 - go.etcd.io/etcd/client/v3 v3.5.11 + go.etcd.io/etcd/clientv3 v3.4.23 - golang.org/x/sys v0.15.0 + golang.org/x/sys v0.16.0 ) diff -Nru vip-manager2-2.2.0/go.mod vip-manager2-2.3.0/go.mod --- vip-manager2-2.2.0/go.mod 2024-01-08 10:25:51.000000000 +0000 +++ vip-manager2-2.3.0/go.mod 2024-01-19 07:32:37.000000000 +0000 @@ -3,12 +3,12 @@ go 1.21 require ( - github.com/hashicorp/consul/api v1.26.1 + github.com/hashicorp/consul/api v1.27.0 github.com/mdlayher/arp v0.0.0-20220512170110-6706a2966875 github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.18.2 go.etcd.io/etcd/client/v3 v3.5.11 - golang.org/x/sys v0.15.0 + golang.org/x/sys v0.16.0 ) require ( diff -Nru vip-manager2-2.2.0/go.sum vip-manager2-2.3.0/go.sum --- vip-manager2-2.2.0/go.sum 2024-01-08 10:25:51.000000000 +0000 +++ vip-manager2-2.3.0/go.sum 2024-01-19 07:32:37.000000000 +0000 @@ -69,10 +69,10 @@ github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/hashicorp/consul/api v1.26.1 h1:5oSXOO5fboPZeW5SN+TdGFP/BILDgBm19OrPZ/pICIM= -github.com/hashicorp/consul/api v1.26.1/go.mod h1:B4sQTeaSO16NtynqrAdwOlahJ7IUDZM9cj2420xYL8A= -github.com/hashicorp/consul/sdk v0.15.0 h1:2qK9nDrr4tiJKRoxPGhm6B7xJjLVIQqkjiab2M4aKjU= -github.com/hashicorp/consul/sdk v0.15.0/go.mod h1:r/OmRRPbHOe0yxNahLw7G9x5WG17E1BIECMtCjcPSNo= +github.com/hashicorp/consul/api v1.27.0 h1:gmJ6DPKQog1426xsdmgk5iqDyoRiNc+ipBdJOqKQFjc= +github.com/hashicorp/consul/api v1.27.0/go.mod h1:JkekNRSou9lANFdt+4IKx3Za7XY0JzzpQjEb4Ivo1c8= +github.com/hashicorp/consul/sdk v0.15.1 h1:kKIGxc7CZtflcF5DLfHeq7rOQmRq3vk7kwISN9bif8Q= +github.com/hashicorp/consul/sdk v0.15.1/go.mod h1:7pxqqhqoaPqnBnzXD1StKed62LqJeClzVsUEy85Zr0A= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -318,8 +318,8 @@ golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= -golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= diff -Nru vip-manager2-2.2.0/test/behaviour_test.sh vip-manager2-2.3.0/test/behaviour_test.sh --- vip-manager2-2.2.0/test/behaviour_test.sh 2024-01-08 10:25:51.000000000 +0000 +++ vip-manager2-2.3.0/test/behaviour_test.sh 2024-01-19 07:32:37.000000000 +0000 @@ -53,11 +53,11 @@ # run etcd with podman/docker maybe? # podman rm etcd || true -# podman run -d --name etcd -p 2379:2379 -e "ETCD_ENABLE_V2=true" -e "ALLOW_NONE_AUTHENTICATION=yes" bitnami/etcd +# podman run -d --name etcd -p 2379:2379 -e "ALLOW_NONE_AUTHENTICATION=yes" bitnami/etcd # run etcd locally maybe? -#etcd --enable-v2 & -#echo $! > .etcdPid +etcd & +echo $! > .etcdPid sleep 2 # simulate server, e.g. postgres @@ -67,7 +67,7 @@ etcdctl del service/pgcluster/leader || true touch .failed -./vip-manager --interface $dev --ip $vip --netmask 32 --trigger-key service/pgcluster/leader --trigger-value $HOSTNAME & #2>&1 & +./vip-manager --interval 3000 --interface $dev --ip $vip --netmask 32 --trigger-key service/pgcluster/leader --trigger-value $HOSTNAME & #2>&1 & echo $! > .vipPid sleep 2