From eb3f6e512a0eb5e607ae95b599025ad2239a7223 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Sat, 15 Jun 2024 14:55:08 +0000
Subject: [PATCH 1/7] chore(deps): update grouped non-major updates (#236)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
[![Mend
Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com)
This PR contains the following updates:
| Package | Type | Update | Change | Age | Adoption | Passing |
Confidence |
|---|---|---|---|---|---|---|---|
| [actions/checkout](https://togithub.com/actions/checkout) | action |
patch | `v4.1.6` -> `v4.1.7` |
[![age](https://developer.mend.io/api/mc/badges/age/github-tags/actions%2fcheckout/v4.1.7?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/github-tags/actions%2fcheckout/v4.1.7?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/github-tags/actions%2fcheckout/v4.1.6/v4.1.7?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/github-tags/actions%2fcheckout/v4.1.6/v4.1.7?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
|
[docker/build-push-action](https://togithub.com/docker/build-push-action)
| action | minor | `v5.3.0` -> `v5.4.0` |
[![age](https://developer.mend.io/api/mc/badges/age/github-tags/docker%2fbuild-push-action/v5.4.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/github-tags/docker%2fbuild-push-action/v5.4.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/github-tags/docker%2fbuild-push-action/v5.3.0/v5.4.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/github-tags/docker%2fbuild-push-action/v5.3.0/v5.4.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
| [golangci/golangci-lint](https://togithub.com/golangci/golangci-lint)
| | patch | `v1.59.0` -> `v1.59.1` |
[![age](https://developer.mend.io/api/mc/badges/age/github-tags/golangci%2fgolangci-lint/v1.59.1?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/github-tags/golangci%2fgolangci-lint/v1.59.1?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/github-tags/golangci%2fgolangci-lint/v1.59.0/v1.59.1?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/github-tags/golangci%2fgolangci-lint/v1.59.0/v1.59.1?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
| [helm/helm](https://togithub.com/helm/helm) | | patch | `v3.15.1` ->
`v3.15.2` |
[![age](https://developer.mend.io/api/mc/badges/age/github-tags/helm%2fhelm/v3.15.2?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/github-tags/helm%2fhelm/v3.15.2?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/github-tags/helm%2fhelm/v3.15.1/v3.15.2?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/github-tags/helm%2fhelm/v3.15.1/v3.15.2?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
| [k8s.io/api](https://togithub.com/kubernetes/api) | require | patch |
`v0.30.1` -> `v0.30.2` |
[![age](https://developer.mend.io/api/mc/badges/age/go/k8s.io%2fapi/v0.30.2?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/go/k8s.io%2fapi/v0.30.2?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/go/k8s.io%2fapi/v0.30.1/v0.30.2?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/go/k8s.io%2fapi/v0.30.1/v0.30.2?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
| [k8s.io/apimachinery](https://togithub.com/kubernetes/apimachinery) |
require | patch | `v0.30.1` -> `v0.30.2` |
[![age](https://developer.mend.io/api/mc/badges/age/go/k8s.io%2fapimachinery/v0.30.2?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/go/k8s.io%2fapimachinery/v0.30.2?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/go/k8s.io%2fapimachinery/v0.30.1/v0.30.2?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/go/k8s.io%2fapimachinery/v0.30.1/v0.30.2?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
| [k8s.io/client-go](https://togithub.com/kubernetes/client-go) |
require | patch | `v0.30.1` -> `v0.30.2` |
[![age](https://developer.mend.io/api/mc/badges/age/go/k8s.io%2fclient-go/v0.30.2?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/go/k8s.io%2fclient-go/v0.30.2?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/go/k8s.io%2fclient-go/v0.30.1/v0.30.2?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/go/k8s.io%2fclient-go/v0.30.1/v0.30.2?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
| [kubernetes/kubernetes](https://togithub.com/kubernetes/kubernetes) |
| patch | `v1.30.0` -> `v1.30.2` |
[![age](https://developer.mend.io/api/mc/badges/age/github-tags/kubernetes%2fkubernetes/v1.30.2?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/github-tags/kubernetes%2fkubernetes/v1.30.2?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/github-tags/kubernetes%2fkubernetes/v1.30.0/v1.30.2?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/github-tags/kubernetes%2fkubernetes/v1.30.0/v1.30.2?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
|
[losisin/helm-values-schema-json](https://togithub.com/losisin/helm-values-schema-json)
| | patch | `v1.4.0` -> `v1.4.1` |
[![age](https://developer.mend.io/api/mc/badges/age/github-tags/losisin%2fhelm-values-schema-json/v1.4.1?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/github-tags/losisin%2fhelm-values-schema-json/v1.4.1?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/github-tags/losisin%2fhelm-values-schema-json/v1.4.0/v1.4.1?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/github-tags/losisin%2fhelm-values-schema-json/v1.4.0/v1.4.1?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
---
### Release Notes
actions/checkout (actions/checkout)
###
[`v4.1.7`](https://togithub.com/actions/checkout/blob/HEAD/CHANGELOG.md#v417)
[Compare
Source](https://togithub.com/actions/checkout/compare/v4.1.6...v4.1.7)
- Bump the minor-npm-dependencies group across 1 directory with 4
updates by [@dependabot](https://togithub.com/dependabot) in
[https://github.com/actions/checkout/pull/1739](https://togithub.com/actions/checkout/pull/1739)
- Bump actions/checkout from 3 to 4 by
[@dependabot](https://togithub.com/dependabot) in
[https://github.com/actions/checkout/pull/1697](https://togithub.com/actions/checkout/pull/1697)
- Check out other refs/\* by commit by
[@orhantoy](https://togithub.com/orhantoy) in
[https://github.com/actions/checkout/pull/1774](https://togithub.com/actions/checkout/pull/1774)
- Pin actions/checkout's own workflows to a known, good, stable version.
by [@jww3](https://togithub.com/jww3) in
[https://github.com/actions/checkout/pull/1776](https://togithub.com/actions/checkout/pull/1776)
docker/build-push-action (docker/build-push-action)
###
[`v5.4.0`](https://togithub.com/docker/build-push-action/compare/v5.3.0...v5.4.0)
[Compare
Source](https://togithub.com/docker/build-push-action/compare/v5.3.0...v5.4.0)
golangci/golangci-lint (golangci/golangci-lint)
###
[`v1.59.1`](https://togithub.com/golangci/golangci-lint/releases/tag/v1.59.1)
[Compare
Source](https://togithub.com/golangci/golangci-lint/compare/v1.59.0...v1.59.1)
`golangci-lint` is a free and open-source project built by volunteers.
If you value it, consider supporting us, the
[maintainers](https://opencollective.com/golangci-lint) and [linter
authors](https://golangci-lint.run/product/thanks/).
We appreciate it! :heart:
For key updates, see the
[changelog](https://golangci-lint.run/product/changelog/#1591).
#### Changelog
-
[`f738736`](https://togithub.com/golangci/golangci-lint/commit/f7387361)
build(deps): bump github.com/Antonboom/testifylint from 1.3.0 to 1.3.1
([#4759](https://togithub.com/golangci/golangci-lint/issues/4759))
-
[`44b3cdd`](https://togithub.com/golangci/golangci-lint/commit/44b3cdd1)
build(deps): bump github.com/go-viper/mapstructure/v2 from 2.0.0-alpha.1
to 2.0.0
([#4788](https://togithub.com/golangci/golangci-lint/issues/4788))
-
[`1a55854`](https://togithub.com/golangci/golangci-lint/commit/1a55854a)
build(deps): bump github.com/golangci/misspell from 0.5.1 to 0.6.0
([#4804](https://togithub.com/golangci/golangci-lint/issues/4804))
-
[`9a7a1ad`](https://togithub.com/golangci/golangci-lint/commit/9a7a1ad4)
build(deps): bump github.com/polyfloyd/go-errorlint from 1.5.1 to 1.5.2
([#4785](https://togithub.com/golangci/golangci-lint/issues/4785))
-
[`aaff918`](https://togithub.com/golangci/golangci-lint/commit/aaff9184)
build(deps): bump github.com/sashamelentyev/usestdlibvars from 1.25.0 to
1.26.0
([#4801](https://togithub.com/golangci/golangci-lint/issues/4801))
-
[`a0d2c83`](https://togithub.com/golangci/golangci-lint/commit/a0d2c830)
build(deps): bump github.com/shirou/gopsutil/v3 from 3.24.4 to 3.24.5
([#4782](https://togithub.com/golangci/golangci-lint/issues/4782))
-
[`2042b1f`](https://togithub.com/golangci/golangci-lint/commit/2042b1f1)
build(deps): bump go-simpler.org/sloglint from 0.7.0 to 0.7.1
([#4784](https://togithub.com/golangci/golangci-lint/issues/4784))
-
[`327a78a`](https://togithub.com/golangci/golangci-lint/commit/327a78a8)
build(deps): bump golang.org/x/tools from 0.21.0 to 0.22.0
([#4802](https://togithub.com/golangci/golangci-lint/issues/4802))
-
[`e1a8055`](https://togithub.com/golangci/golangci-lint/commit/e1a80557)
fix: SARIF format require issue column >= 1
([#4775](https://togithub.com/golangci/golangci-lint/issues/4775))
-
[`88f60c8`](https://togithub.com/golangci/golangci-lint/commit/88f60c8c)
fix: gomnd deprecated configuration compatibility
([#4768](https://togithub.com/golangci/golangci-lint/issues/4768))
-
[`8173166`](https://togithub.com/golangci/golangci-lint/commit/81731668)
fix: init empty result slice for SARIF printer
([#4758](https://togithub.com/golangci/golangci-lint/issues/4758))
-
[`02740ea`](https://togithub.com/golangci/golangci-lint/commit/02740ea1)
intrange: add style preset
([#4797](https://togithub.com/golangci/golangci-lint/issues/4797))
-
[`615b873`](https://togithub.com/golangci/golangci-lint/commit/615b873d)
unparam: bump to HEAD
([#4786](https://togithub.com/golangci/golangci-lint/issues/4786))
helm/helm (helm/helm)
### [`v3.15.2`](https://togithub.com/helm/helm/releases/tag/v3.15.2):
Helm v3.15.2
[Compare
Source](https://togithub.com/helm/helm/compare/v3.15.1...v3.15.2)
Helm v3.15.2 is a security (patch) release. Users are strongly
recommended to update to this release.
The community keeps growing, and we'd love to see you there!
- Join the discussion in [Kubernetes
Slack](https://kubernetes.slack.com):
- for questions and just to hang out
- for discussing PRs, code, and bugs
- Hang out at the Public Developer Call: Thursday, 9:30 Pacific via
[Zoom](https://zoom.us/j/696660622)
- Test, debug, and contribute charts:
[ArtifactHub/packages](https://artifacthub.io/packages/search?kind=0)
#### Installation and Upgrading
Download Helm v3.15.2. The common platform binaries are here:
- [MacOS amd64](https://get.helm.sh/helm-v3.15.2-darwin-amd64.tar.gz)
([checksum](https://get.helm.sh/helm-v3.15.2-darwin-amd64.tar.gz.sha256sum)
/ e99a9266a5328cb575d81ef10247911f42d9e90c76ef6eef154c5c535565658b)
- [MacOS arm64](https://get.helm.sh/helm-v3.15.2-darwin-arm64.tar.gz)
([checksum](https://get.helm.sh/helm-v3.15.2-darwin-arm64.tar.gz.sha256sum)
/ 30143dabc1da9d32c7d6c589fad04b1f1ecc73841393d5823fa21c5d7f5bf8f6)
- [Linux amd64](https://get.helm.sh/helm-v3.15.2-linux-amd64.tar.gz)
([checksum](https://get.helm.sh/helm-v3.15.2-linux-amd64.tar.gz.sha256sum)
/ 2694b91c3e501cff57caf650e639604a274645f61af2ea4d601677b746b44fe2)
- [Linux arm](https://get.helm.sh/helm-v3.15.2-linux-arm.tar.gz)
([checksum](https://get.helm.sh/helm-v3.15.2-linux-arm.tar.gz.sha256sum)
/ 2b28fda1d8c6f087011bc7ec820051a13409dadce8385529f306476632e24e85)
- [Linux arm64](https://get.helm.sh/helm-v3.15.2-linux-arm64.tar.gz)
([checksum](https://get.helm.sh/helm-v3.15.2-linux-arm64.tar.gz.sha256sum)
/ adcf07b08484b52508e5cbc8b5f4b0b0db50342f7bc487ecd88b8948b680e6a7)
- [Linux i386](https://get.helm.sh/helm-v3.15.2-linux-386.tar.gz)
([checksum](https://get.helm.sh/helm-v3.15.2-linux-386.tar.gz.sha256sum)
/ 8e0bb5a08c7c227a8e285026b6283726ddc0e1f406e2af4d4d600fa1dd85c21e)
- [Linux ppc64le](https://get.helm.sh/helm-v3.15.2-linux-ppc64le.tar.gz)
([checksum](https://get.helm.sh/helm-v3.15.2-linux-ppc64le.tar.gz.sha256sum)
/ 9d95528fb797f6429f7f9b6dee0cf87bf8c71f6470e1db4a51e844c169c285a3)
- [Linux s390x](https://get.helm.sh/helm-v3.15.2-linux-s390x.tar.gz)
([checksum](https://get.helm.sh/helm-v3.15.2-linux-s390x.tar.gz.sha256sum)
/ 5b42bc3d08fd0ffaf4f9ed810f28464f52ec4ea431b809c7179071d76f3d6f16)
- [Linux riscv64](https://get.helm.sh/helm-v3.15.2-linux-riscv64.tar.gz)
([checksum](https://get.helm.sh/helm-v3.15.2-linux-riscv64.tar.gz.sha256sum)
/ 2998bae9971a55f862c21bff337c325cb6a44f28ef76e11bffc93d16989e11e6)
- [Windows amd64](https://get.helm.sh/helm-v3.15.2-windows-amd64.zip)
([checksum](https://get.helm.sh/helm-v3.15.2-windows-amd64.zip.sha256sum)
/ cbf40b79fa2a7dbd6e24201f8660b56261d10d6e7b5cadc3ff78100fb45b3c69)
This release was signed with ` 672C 657B E06B 4B30 969C 4A57 4614 49C2
5E36 B98E ` and can be found at
[@mattfarina](https://togithub.com/mattfarina) [keybase
account](https://keybase.io/mattfarina). Please use the attached
signatures for verifying this release using `gpg`.
The [Quickstart Guide](https://helm.sh/docs/intro/quickstart/) will get
you going from there. For **upgrade instructions** or detailed
installation notes, check the [install
guide](https://helm.sh/docs/intro/install/). You can also use a [script
to
install](https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3)
on any system with `bash`.
#### What's Next
- 3.15.3 will contain only bug fixes and be released on July 10, 2024.
- 3.16.0 is the next feature release and will be on September 11, 2024.
#### Changelog
- fix: wrong cli description
[`1a500d5`](https://togithub.com/helm/helm/commit/1a500d5625419a524fdae4b33de351cc4f58ec35)
(yyzxw)
- fix typo in load_plugins.go
[`70b225c`](https://togithub.com/helm/helm/commit/70b225c9abc014cfeb73f7c9f506b0e73e912b61)
(yxxhero)
- fix docs of DeployedAll
[`b3640f1`](https://togithub.com/helm/helm/commit/b3640f196a2cf77136ab01295bffe76fa184991d)
(Daniel Strobusch)
- Bump github.com/docker/docker
[`46e2ba0`](https://togithub.com/helm/helm/commit/46e2ba0341d43e19493b2f90c86126da8ad8a64e)
(dependabot\[bot])
- bump oras minor version
[`fb311d3`](https://togithub.com/helm/helm/commit/fb311d331f66f7f9153b5d0c7aa07a77bc9528ca)
(Austin Abro)
- feat(load.go): add warning on requirements.lock
[`23552a7`](https://togithub.com/helm/helm/commit/23552a7de6f45aacec47bc2bfe70de02b9d7ab70)
(Aaron U'Ren)
kubernetes/api (k8s.io/api)
###
[`v0.30.2`](https://togithub.com/kubernetes/api/compare/v0.30.1...v0.30.2)
[Compare
Source](https://togithub.com/kubernetes/api/compare/v0.30.1...v0.30.2)
kubernetes/apimachinery (k8s.io/apimachinery)
###
[`v0.30.2`](https://togithub.com/kubernetes/apimachinery/compare/v0.30.1...v0.30.2)
[Compare
Source](https://togithub.com/kubernetes/apimachinery/compare/v0.30.1...v0.30.2)
kubernetes/client-go (k8s.io/client-go)
###
[`v0.30.2`](https://togithub.com/kubernetes/client-go/compare/v0.30.1...v0.30.2)
[Compare
Source](https://togithub.com/kubernetes/client-go/compare/v0.30.1...v0.30.2)
kubernetes/kubernetes (kubernetes/kubernetes)
###
[`v1.30.2`](https://togithub.com/kubernetes/kubernetes/releases/tag/v1.30.2):
Kubernetes v1.30.2
[Compare
Source](https://togithub.com/kubernetes/kubernetes/compare/v1.30.1...v1.30.2)
See
[kubernetes-announce@](https://groups.google.com/forum/#!forum/kubernetes-announce).
Additional binary downloads are linked in the
[CHANGELOG](https://togithub.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.30.md).
See [the
CHANGELOG](https://togithub.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.30.md)
for more details.
###
[`v1.30.1`](https://togithub.com/kubernetes/kubernetes/releases/tag/v1.30.1):
Kubernetes v1.30.1
[Compare
Source](https://togithub.com/kubernetes/kubernetes/compare/v1.30.0...v1.30.1)
See
[kubernetes-announce@](https://groups.google.com/forum/#!forum/kubernetes-announce).
Additional binary downloads are linked in the
[CHANGELOG](https://togithub.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.30.md).
See [the
CHANGELOG](https://togithub.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.30.md)
for more details.
losisin/helm-values-schema-json
(losisin/helm-values-schema-json)
###
[`v1.4.1`](https://togithub.com/losisin/helm-values-schema-json/releases/tag/v1.4.1)
[Compare
Source](https://togithub.com/losisin/helm-values-schema-json/compare/v1.4.0...v1.4.1)
#### Changelog
##### Other
-
[`4106fe3`](https://togithub.com/losisin/helm-values-schema-json/commit/4106fe3)
Add documentation and another test case
-
[`c08b884`](https://togithub.com/losisin/helm-values-schema-json/commit/c08b884)
Add: option to apply enum on array items
-
[`ad5fbbd`](https://togithub.com/losisin/helm-values-schema-json/commit/ad5fbbd)
bump version to 1.4.1
---
### Configuration
📅 **Schedule**: Branch creation - "* * * * 6" (UTC), Automerge - At any
time (no schedule defined).
🚦 **Automerge**: Enabled.
â™» **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.
👻 **Immortal**: This PR will be recreated if closed unmerged. Get
[config help](https://togithub.com/renovatebot/renovate/discussions) if
that's undesired.
---
- [ ] If you want to rebase/retry this PR, check
this box
---
This PR has been generated by [Mend
Renovate](https://www.mend.io/free-developer-tools/renovate/). View
repository job log
[here](https://developer.mend.io/github/aenix-io/etcd-operator).
---------
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Hidden Marten
---
.github/workflows/docker-publish.yaml | 4 ++--
.github/workflows/helm-publish.yaml | 2 +-
.github/workflows/hugo.yaml | 2 +-
.github/workflows/make-test-e2e.yaml | 2 +-
.github/workflows/make-test.yaml | 2 +-
.github/workflows/nilaway-lint.yaml | 2 +-
.github/workflows/pre-commit.yaml | 2 +-
.github/workflows/release-assets.yaml | 2 +-
Makefile | 6 +++---
go.mod | 6 +++---
go.sum | 12 ++++++------
11 files changed, 21 insertions(+), 21 deletions(-)
diff --git a/.github/workflows/docker-publish.yaml b/.github/workflows/docker-publish.yaml
index 0b6f370f..7064cbba 100644
--- a/.github/workflows/docker-publish.yaml
+++ b/.github/workflows/docker-publish.yaml
@@ -29,7 +29,7 @@ jobs:
steps:
- name: Checkout repository
- uses: actions/checkout@v4.1.6
+ uses: actions/checkout@v4.1.7
# Install the cosign tool except on PR
# https://github.com/sigstore/cosign-installer
@@ -67,7 +67,7 @@ jobs:
# https://github.com/docker/build-push-action
- name: Build and push Docker image
id: build-and-push
- uses: docker/build-push-action@v5.3.0
+ uses: docker/build-push-action@v5.4.0
with:
context: .
push: ${{ github.event_name != 'pull_request' }}
diff --git a/.github/workflows/helm-publish.yaml b/.github/workflows/helm-publish.yaml
index 98d7cf28..42168f94 100644
--- a/.github/workflows/helm-publish.yaml
+++ b/.github/workflows/helm-publish.yaml
@@ -23,7 +23,7 @@ jobs:
steps:
- name: Checkout repository
- uses: actions/checkout@v4.1.6
+ uses: actions/checkout@v4.1.7
- name: Install Helm
uses: azure/setup-helm@v4.2.0
diff --git a/.github/workflows/hugo.yaml b/.github/workflows/hugo.yaml
index 6fe53973..e7081f4d 100644
--- a/.github/workflows/hugo.yaml
+++ b/.github/workflows/hugo.yaml
@@ -41,7 +41,7 @@ jobs:
- name: Install Dart Sass
run: sudo snap install dart-sass
- name: Checkout
- uses: actions/checkout@v4.1.6
+ uses: actions/checkout@v4.1.7
with:
submodules: recursive
fetch-depth: 0
diff --git a/.github/workflows/make-test-e2e.yaml b/.github/workflows/make-test-e2e.yaml
index ccac6da4..31448122 100644
--- a/.github/workflows/make-test-e2e.yaml
+++ b/.github/workflows/make-test-e2e.yaml
@@ -23,7 +23,7 @@ jobs:
attribute: latest
runs-on: ubuntu-22.04
steps:
- - uses: actions/checkout@v4.1.6
+ - uses: actions/checkout@v4.1.7
- uses: actions/setup-go@v5.0.1
with:
go-version: 1.22.4
diff --git a/.github/workflows/make-test.yaml b/.github/workflows/make-test.yaml
index 8d58d1bd..2942f6c8 100644
--- a/.github/workflows/make-test.yaml
+++ b/.github/workflows/make-test.yaml
@@ -23,7 +23,7 @@ jobs:
attribute: latest
runs-on: ubuntu-22.04
steps:
- - uses: actions/checkout@v4.1.6
+ - uses: actions/checkout@v4.1.7
- uses: actions/setup-go@v5.0.1
with:
go-version: 1.22.4
diff --git a/.github/workflows/nilaway-lint.yaml b/.github/workflows/nilaway-lint.yaml
index 3da57c48..5600b56a 100644
--- a/.github/workflows/nilaway-lint.yaml
+++ b/.github/workflows/nilaway-lint.yaml
@@ -7,7 +7,7 @@ jobs:
nilaway-lint:
runs-on: ubuntu-22.04
steps:
- - uses: actions/checkout@v4.1.6
+ - uses: actions/checkout@v4.1.7
- uses: actions/setup-go@v5.0.1
with:
go-version: 1.22.4
diff --git a/.github/workflows/pre-commit.yaml b/.github/workflows/pre-commit.yaml
index d5479a01..ca967c13 100644
--- a/.github/workflows/pre-commit.yaml
+++ b/.github/workflows/pre-commit.yaml
@@ -7,7 +7,7 @@ jobs:
pre-commit:
runs-on: ubuntu-22.04
steps:
- - uses: actions/checkout@v4.1.6
+ - uses: actions/checkout@v4.1.7
- uses: actions/setup-go@v5.0.1
with:
go-version: 1.22.4
diff --git a/.github/workflows/release-assets.yaml b/.github/workflows/release-assets.yaml
index 8d58970d..589380d5 100644
--- a/.github/workflows/release-assets.yaml
+++ b/.github/workflows/release-assets.yaml
@@ -14,7 +14,7 @@ jobs:
permissions:
contents: write
steps:
- - uses: actions/checkout@v4.1.6
+ - uses: actions/checkout@v4.1.7
- uses: actions/setup-go@v5.0.1
with:
go-version: 1.22.4
diff --git a/Makefile b/Makefile
index 722b17f4..b2e24953 100644
--- a/Makefile
+++ b/Makefile
@@ -254,13 +254,13 @@ KUSTOMIZE_VERSION ?= v5.3.0
CONTROLLER_TOOLS_VERSION ?= v0.15.0
ENVTEST_VERSION ?= latest
# renovate: datasource=github-tags depName=golangci/golangci-lint
-GOLANGCI_LINT_VERSION ?= v1.59.0
+GOLANGCI_LINT_VERSION ?= v1.59.1
# renovate: datasource=github-tags depName=kubernetes-sigs/kind
KIND_VERSION ?= v0.23.0
# renovate: datasource=github-tags depName=helm/helm
-HELM_VERSION ?= v3.15.1
+HELM_VERSION ?= v3.15.2
# renovate: datasource=github-tags depName=losisin/helm-values-schema-json
-HELM_SCHEMA_VERSION ?= v1.4.0
+HELM_SCHEMA_VERSION ?= v1.4.1
# renovate: datasource=github-tags depName=norwoodj/helm-docs
HELM_DOCS_VERSION ?= v1.13.1
# renovate: datasource=github-tags depName=mikefarah/yq
diff --git a/go.mod b/go.mod
index c4454997..ae9ce48c 100644
--- a/go.mod
+++ b/go.mod
@@ -12,9 +12,9 @@ require (
go.etcd.io/etcd/client/v3 v3.5.14
go.uber.org/zap v1.27.0
go.uber.org/zap/exp v0.2.0
- k8s.io/api v0.30.1
- k8s.io/apimachinery v0.30.1
- k8s.io/client-go v0.30.1
+ k8s.io/api v0.30.2
+ k8s.io/apimachinery v0.30.2
+ k8s.io/client-go v0.30.2
k8s.io/utils v0.0.0-20240502163921-fe8a2dddb1d0
sigs.k8s.io/controller-runtime v0.18.4
)
diff --git a/go.sum b/go.sum
index ed763278..a0c4a088 100644
--- a/go.sum
+++ b/go.sum
@@ -234,14 +234,14 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-k8s.io/api v0.30.1 h1:kCm/6mADMdbAxmIh0LBjS54nQBE+U4KmbCfIkF5CpJY=
-k8s.io/api v0.30.1/go.mod h1:ddbN2C0+0DIiPntan/bye3SW3PdwLa11/0yqwvuRrJM=
+k8s.io/api v0.30.2 h1:+ZhRj+28QT4UOH+BKznu4CBgPWgkXO7XAvMcMl0qKvI=
+k8s.io/api v0.30.2/go.mod h1:ULg5g9JvOev2dG0u2hig4Z7tQ2hHIuS+m8MNZ+X6EmI=
k8s.io/apiextensions-apiserver v0.30.1 h1:4fAJZ9985BmpJG6PkoxVRpXv9vmPUOVzl614xarePws=
k8s.io/apiextensions-apiserver v0.30.1/go.mod h1:R4GuSrlhgq43oRY9sF2IToFh7PVlF1JjfWdoG3pixk4=
-k8s.io/apimachinery v0.30.1 h1:ZQStsEfo4n65yAdlGTfP/uSHMQSoYzU/oeEbkmF7P2U=
-k8s.io/apimachinery v0.30.1/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc=
-k8s.io/client-go v0.30.1 h1:uC/Ir6A3R46wdkgCV3vbLyNOYyCJ8oZnjtJGKfytl/Q=
-k8s.io/client-go v0.30.1/go.mod h1:wrAqLNs2trwiCH/wxxmT/x3hKVH9PuV0GGW0oDoHVqc=
+k8s.io/apimachinery v0.30.2 h1:fEMcnBj6qkzzPGSVsAZtQThU62SmQ4ZymlXRC5yFSCg=
+k8s.io/apimachinery v0.30.2/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc=
+k8s.io/client-go v0.30.2 h1:sBIVJdojUNPDU/jObC+18tXWcTJVcwyqS9diGdWHk50=
+k8s.io/client-go v0.30.2/go.mod h1:JglKSWULm9xlJLx4KCkfLLQ7XwtlbflV6uFFSHTMgVs=
k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw=
k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag=
From df56b4d5f78ec381a5b671376c88802f8d033f36 Mon Sep 17 00:00:00 2001
From: Andrei Kvapil
Date: Tue, 18 Jun 2024 10:27:06 +0200
Subject: [PATCH 2/7] Add kubectl-etcd plugin (#220)
fixes https://github.com/aenix-io/etcd-operator/issues/212
```
Manage etcd pods spawned by etcd-operator
Usage:
kubectl-etcd [command]
Available Commands:
alarm Manage etcd alarms
completion Generate the autocompletion script for the specified shell
defrag Defragment etcd database on the node
forfeit-leadership Tell node to forfeit etcd cluster leadership
help Help about any command
leave Tell node to leave etcd cluster
members Get the list of etcd cluster members
remove-member Remove a node from the etcd cluster
snapshot Stream snapshot of the etcd node to the path.
status Get the status of etcd cluster member
Flags:
-h, --help help for kubectl-etcd
-k, --kubeconfig string Path to the kubeconfig file (default "/Users/kvaps/git/clients/fin-dev/infra/clusters/dev2/kubeconfig")
-n, --namespace string Namespace of the etcd pod (default is the current namespace from kubeconfig)
-p, --pod string Name of the etcd pod
Use "kubectl-etcd [command] --help" for more information about a command.
```
Signed-off-by: Andrei Kvapil
---
Dockerfile | 2 +-
Makefile | 5 +-
cmd/kubectl-etcd/main.go | 702 ++++++++++++++++++++++++++++++++++++++
cmd/{ => manager}/main.go | 0
go.mod | 6 +
go.sum | 17 +
6 files changed, 730 insertions(+), 2 deletions(-)
create mode 100644 cmd/kubectl-etcd/main.go
rename cmd/{ => manager}/main.go (100%)
diff --git a/Dockerfile b/Dockerfile
index f3175bcf..ab23db9f 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -20,7 +20,7 @@ COPY internal/ ./internal/
# was called. For example, if we call make docker-build in a local env which has the Apple Silicon M1 SO
# the docker BUILDPLATFORM arg will be linux/arm64 when for Apple x86 it will be linux/amd64. Therefore,
# by leaving it empty we can ensure that the container and binary shipped on it will have the same platform.
-RUN CGO_ENABLED=0 GOOS="${TARGETOS:-linux}" GOARCH="${TARGETARCH}" go build -a -o manager cmd/main.go
+RUN CGO_ENABLED=0 GOOS="${TARGETOS:-linux}" GOARCH="${TARGETARCH}" go build -a -o manager cmd/manager/main.go
# Use distroless as minimal base image to package the manager binary
# Refer to https://github.com/GoogleContainerTools/distroless for more details
diff --git a/Makefile b/Makefile
index b2e24953..b324f38c 100644
--- a/Makefile
+++ b/Makefile
@@ -118,7 +118,10 @@ helm-crd-copy: yq kustomize ## Copy CRDs from kustomize to helm-chart
.PHONY: build
build: manifests generate fmt vet ## Build manager binary.
- go build -o bin/manager cmd/main.go
+ go build -o bin/manager cmd/manager/main.go
+
+build-plugin:
+ go build -o bin/kubectl-etcd cmd/kubectl-etcd/main.go
.PHONY: run
run: manifests generate fmt vet ## Run a controller from your host.
diff --git a/cmd/kubectl-etcd/main.go b/cmd/kubectl-etcd/main.go
new file mode 100644
index 00000000..05be2e06
--- /dev/null
+++ b/cmd/kubectl-etcd/main.go
@@ -0,0 +1,702 @@
+package main
+
+import (
+ "context"
+ "crypto/tls"
+ "crypto/x509"
+ "fmt"
+ "io"
+ "net/http"
+ "net/url"
+ "os"
+ "path/filepath"
+ "strconv"
+ "strings"
+ "time"
+
+ "github.com/dustin/go-humanize"
+ "github.com/spf13/cobra"
+ clientv3 "go.etcd.io/etcd/client/v3"
+ corev1 "k8s.io/api/core/v1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/client-go/kubernetes"
+ "k8s.io/client-go/tools/clientcmd"
+ "k8s.io/client-go/tools/portforward"
+ "k8s.io/client-go/transport/spdy"
+ "k8s.io/client-go/util/homedir"
+)
+
+func main() {
+ var rootCmd = &cobra.Command{
+ Use: "kubectl-etcd",
+ Short: "Kubectl etcd plugin",
+ Long: `Manage etcd pods spawned by etcd-operator`,
+ }
+
+ // Initialize configuration
+ config := initializeConfig(rootCmd)
+
+ // Register subcommands
+ rootCmd.AddCommand(
+ createStatusCmd(config),
+ createDefragCmd(config),
+ createCompactCmd(config),
+ createAlarmCmd(config),
+ createForfeitLeadershipCmd(config),
+ createLeaveCmd(config),
+ createMembersCmd(config),
+ createRemoveMemberCmd(config),
+ createAddMemberCmd(config),
+ createSnapshotCmd(config),
+ )
+
+ // Execute the root command
+ if err := rootCmd.Execute(); err != nil {
+ fmt.Println("Error:", err)
+ os.Exit(1)
+ }
+}
+
+func createStatusCmd(config *Config) *cobra.Command {
+ return &cobra.Command{
+ Use: "status",
+ Short: "Get the status of etcd cluster member",
+ Run: func(cmd *cobra.Command, args []string) {
+ etcdClient, err := setupEtcdClient(config)
+ if err != nil {
+ fmt.Println(err)
+ return
+ }
+ //nolint:errcheck
+ defer etcdClient.Close()
+
+ ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
+ defer cancel()
+
+ status, err := etcdClient.Status(ctx, etcdClient.Endpoints()[0])
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Failed to get etcd status: %v\n", err)
+ return
+ }
+
+ fmt.Printf("%-17s %-9s %-15s %-18s %-11s %-20s %-8s %-s\n",
+ "MEMBER", "DB SIZE", "IN USE", "LEADER", "RAFT INDEX", "RAFT APPLIED INDEX", "LEARNER", "ERRORS")
+ inUse := fmt.Sprintf("%.2f%%", float64(status.DbSizeInUse)/float64(status.DbSize)*100)
+ fmt.Printf("%-17x %-9s %-15s %-18x %-11d %-20d %-8v\n",
+ status.Header.MemberId, humanize.Bytes(uint64(status.DbSize)),
+ fmt.Sprintf("%s (%s)", humanize.Bytes(uint64(status.DbSizeInUse)), inUse),
+ status.Leader, status.RaftIndex, status.RaftAppliedIndex, status.IsLearner)
+ },
+ }
+}
+
+func createDefragCmd(config *Config) *cobra.Command {
+ return &cobra.Command{
+ Use: "defrag",
+ Short: "Defragment etcd database on the node",
+ Long: `Defragmentation is a maintenance operation that compacts the historical
+records and optimizes the database storage.`,
+ Run: func(cmd *cobra.Command, args []string) {
+ etcdClient, err := setupEtcdClient(config)
+ if err != nil {
+ fmt.Println(err)
+ return
+ }
+ //nolint:errcheck
+ defer etcdClient.Close()
+
+ ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
+ defer cancel()
+
+ _, err = etcdClient.Defragment(ctx, etcdClient.Endpoints()[0])
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Failed to defragment etcd database: %v\n", err)
+ return
+ }
+ },
+ }
+}
+
+func createCompactCmd(config *Config) *cobra.Command {
+ return &cobra.Command{
+ Use: "compact",
+ Short: "Compact the etcd database",
+ Long: `Compacts the etcd database up to the latest revision to free up space.
+This removes old versions of keys and their associated data.`,
+ Run: func(cmd *cobra.Command, args []string) {
+ etcdClient, err := setupEtcdClient(config)
+ if err != nil {
+ fmt.Println("Error setting up etcd client:", err)
+ return
+ }
+ //nolint:errcheck
+ defer etcdClient.Close()
+
+ ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
+ defer cancel()
+
+ // Fetch the latest revision
+ statusResp, err := etcdClient.Status(ctx, etcdClient.Endpoints()[0])
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Failed to get etcd status: %v\n", err)
+ return
+ }
+
+ // Compact the etcd database up to the latest revision
+ _, err = etcdClient.Compact(ctx, statusResp.Header.Revision)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Failed to compact etcd database: %v\n", err)
+ return
+ }
+ },
+ }
+}
+
+func createAlarmCmd(config *Config) *cobra.Command {
+ alarmCmd := &cobra.Command{
+ Use: "alarm",
+ Short: "Manage etcd alarms",
+ Long: `Manage the alarms of an etcd cluster.`,
+ }
+
+ alarmCmd.AddCommand(
+ createAlarmsListCmd(config),
+ createAlarmsDisarmCmd(config),
+ )
+
+ return alarmCmd
+}
+
+func createAlarmsListCmd(config *Config) *cobra.Command {
+ return &cobra.Command{
+ Use: "list",
+ Short: "List the etcd alarms for the node",
+ Run: func(cmd *cobra.Command, args []string) {
+ etcdClient, err := setupEtcdClient(config)
+ if err != nil {
+ fmt.Println("Error setting up etcd client:", err)
+ return
+ }
+ //nolint:errcheck
+ defer etcdClient.Close()
+
+ ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
+ defer cancel()
+
+ // Call to etcd client to list alarms
+ resp, err := etcdClient.AlarmList(ctx)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Failed to list etcd alarms: %v\n", err)
+ return
+ }
+
+ for _, alarm := range resp.Alarms {
+ fmt.Printf("Alarm: %v, MemberID: %x\n", alarm.Alarm, alarm.MemberID)
+ }
+ },
+ }
+}
+
+func createAlarmsDisarmCmd(config *Config) *cobra.Command {
+ return &cobra.Command{
+ Use: "disarm",
+ Short: "Disarm the etcd alarms for the node",
+ Run: func(cmd *cobra.Command, args []string) {
+ etcdClient, err := setupEtcdClient(config)
+ if err != nil {
+ fmt.Println("Error setting up etcd client:", err)
+ return
+ }
+ //nolint:errcheck
+ defer etcdClient.Close()
+
+ ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
+ defer cancel()
+
+ // Call to etcd client to disarm alarms
+ _, err = etcdClient.AlarmDisarm(ctx, &clientv3.AlarmMember{})
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Failed to disarm etcd alarms: %v\n", err)
+ return
+ }
+ },
+ }
+}
+
+// setupEtcdClient sets up the port forwarding and creates an etcd client.
+func setupEtcdClient(config *Config) (*clientv3.Client, error) {
+ if config.PodName == "" {
+ return nil, fmt.Errorf("You must specify the pod name")
+ }
+
+ clientConfig, err := clientcmd.BuildConfigFromFlags("", config.Kubeconfig)
+ if err != nil {
+ return nil, fmt.Errorf("error building kubeconfig: %s", err)
+ }
+
+ clientset, err := kubernetes.NewForConfig(clientConfig)
+ if err != nil {
+ return nil, fmt.Errorf("error creating Kubernetes client: %s", err)
+ }
+
+ tlsConfig, localPort, err := setupPortForwarding(config, clientset)
+ if err != nil {
+ return nil, fmt.Errorf("failed to setup port forwarding: %s", err)
+ }
+
+ etcdConfig := clientv3.Config{
+ Endpoints: []string{fmt.Sprintf("localhost:%d", localPort)},
+ DialTimeout: 5 * time.Second,
+ }
+ if tlsConfig != nil {
+ etcdConfig.TLS = tlsConfig
+ }
+
+ etcdClient, err := clientv3.New(etcdConfig)
+ if err != nil {
+ return nil, fmt.Errorf("failed to connect to etcd server: %s", err)
+ }
+
+ return etcdClient, nil
+}
+
+func createForfeitLeadershipCmd(config *Config) *cobra.Command {
+ return &cobra.Command{
+ Use: "forfeit-leadership",
+ Short: "Tell node to forfeit etcd cluster leadership",
+ Run: func(cmd *cobra.Command, args []string) {
+ etcdClient, err := setupEtcdClient(config)
+ if err != nil {
+ fmt.Println("Error setting up etcd client:", err)
+ return
+ }
+ //nolint:errcheck
+ defer etcdClient.Close()
+
+ ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
+ defer cancel()
+
+ // Retrieve the current status to find the leader
+ status, err := etcdClient.Status(ctx, etcdClient.Endpoints()[0])
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Failed to get current etcd status: %v\n", err)
+ return
+ }
+
+ // Retrieve member list to find a member to transfer leadership to
+ members, err := etcdClient.MemberList(ctx)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Failed to get etcd member list: %v\n", err)
+ return
+ }
+
+ for _, member := range members.Members {
+ if member.ID != status.Leader {
+ _, err = etcdClient.MoveLeader(ctx, member.ID)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Failed to forfeit leadership: %v\n", err)
+ return
+ }
+ return
+ }
+ }
+ fmt.Println("No eligible member found to transfer leadership to or already not the leader.")
+ },
+ }
+}
+
+func createLeaveCmd(config *Config) *cobra.Command {
+ return &cobra.Command{
+ Use: "leave",
+ Short: "Tell node to leave etcd cluster",
+ Run: func(cmd *cobra.Command, args []string) {
+ etcdClient, err := setupEtcdClient(config)
+ if err != nil {
+ fmt.Println("Error setting up etcd client:", err)
+ return
+ }
+ //nolint:errcheck
+ defer etcdClient.Close()
+
+ ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
+ defer cancel()
+
+ // This operation might require administrative privileges on the etcd cluster.
+ memberListResp, err := etcdClient.MemberList(ctx)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Failed to retrieve member list: %v\n", err)
+ return
+ }
+
+ for _, member := range memberListResp.Members {
+ if member.Name == config.PodName { // Assuming PodName is set as the member name
+ _, err = etcdClient.MemberRemove(ctx, member.ID)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Failed to remove member from cluster: %v\n", err)
+ return
+ }
+ return
+ }
+ }
+
+ fmt.Println("Specified pod is not a member of the etcd cluster.")
+ },
+ }
+}
+
+func createMembersCmd(config *Config) *cobra.Command {
+ return &cobra.Command{
+ Use: "members",
+ Short: "Get the list of etcd cluster members",
+ Run: func(cmd *cobra.Command, args []string) {
+ etcdClient, err := setupEtcdClient(config)
+ if err != nil {
+ fmt.Println("Error setting up etcd client:", err)
+ return
+ }
+ //nolint:errcheck
+ defer etcdClient.Close()
+
+ ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
+ defer cancel()
+
+ membersResp, err := etcdClient.MemberList(ctx)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Failed to list etcd members: %v\n", err)
+ return
+ }
+
+ // Header for the table
+ fmt.Printf("%-19s %-10s %-30s %-30s %-7s\n", "ID", "HOSTNAME", "PEER URLS", "CLIENT URLS", "LEARNER")
+ for _, member := range membersResp.Members {
+ fmt.Printf("%-19x %-10s %-30s %-30s %-7v\n",
+ member.ID, member.Name, strings.Join(member.PeerURLs, ","), strings.Join(member.ClientURLs, ","), member.IsLearner)
+ }
+ },
+ }
+}
+
+func createRemoveMemberCmd(config *Config) *cobra.Command {
+ return &cobra.Command{
+ Use: "remove-member ",
+ Short: "Remove a node from the etcd cluster",
+ Long: `Remove a member from the etcd cluster using its member ID.`,
+ Args: cobra.ExactArgs(1), // Ensures exactly one argument is passed
+ Run: func(cmd *cobra.Command, args []string) {
+ etcdClient, err := setupEtcdClient(config)
+ if err != nil {
+ fmt.Println("Error setting up etcd client:", err)
+ return
+ }
+ //nolint:errcheck
+ defer etcdClient.Close()
+
+ ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
+ defer cancel()
+
+ // Parse the member ID from the command line argument
+ memberID, err := strconv.ParseUint(args[0], 16, 64)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Invalid member ID format: %v\n", err)
+ return
+ }
+
+ // Remove the member using the provided member ID
+ _, err = etcdClient.MemberRemove(ctx, memberID)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Failed to remove member: %v\n", err)
+ return
+ }
+ },
+ }
+}
+
+func createAddMemberCmd(config *Config) *cobra.Command {
+ return &cobra.Command{
+ Use: "add-member [urls]",
+ Short: "Add a new member to the etcd cluster",
+ Long: `Add a new member to the etcd cluster using specified peer URLs.`,
+ Args: cobra.ExactArgs(1), // Requires exactly one argument: the new member URL
+ Run: func(cmd *cobra.Command, args []string) {
+ addMember(config, args[0])
+ },
+ }
+}
+
+func addMember(config *Config, memberURL string) {
+ etcdClient, err := setupEtcdClient(config)
+ if err != nil {
+ fmt.Printf("Failed to set up etcd client: %s\n", err)
+ return
+ }
+ //nolint:errcheck
+ defer etcdClient.Close()
+
+ ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
+ defer cancel()
+
+ urls := []string{memberURL}
+ _, err = etcdClient.MemberAdd(ctx, urls)
+ if err != nil {
+ fmt.Printf("Failed to add member: %s\n", err)
+ return
+ }
+
+ fmt.Println("Member successfully added")
+}
+
+func createSnapshotCmd(config *Config) *cobra.Command {
+ var snapshotCmd = &cobra.Command{
+ Use: "snapshot ",
+ Short: "Stream snapshot of the etcd node to the path.",
+ Long: `Take a snapshot of the etcd database and save it to a specified file path.
+This operation is typically used for backup purposes.`,
+ Args: cobra.ExactArgs(1), // This command requires exactly one argument for the file path
+ Run: func(cmd *cobra.Command, args []string) {
+ path := args[0] // The file path where the snapshot will be saved
+
+ etcdClient, err := setupEtcdClient(config)
+ if err != nil {
+ fmt.Println("Error setting up etcd client:", err)
+ return
+ }
+ //nolint:errcheck
+ defer etcdClient.Close()
+
+ ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute) // Snapshot can take time
+ defer cancel()
+
+ // Requesting a snapshot from the etcd server
+ r, err := etcdClient.Snapshot(ctx)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Failed to create snapshot: %v\n", err)
+ return
+ }
+ //nolint:errcheck
+ defer r.Close() // Make sure to close the snapshot reader
+
+ // Open the file for writing the snapshot
+ f, err := os.Create(path)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Failed to open file %s for writing: %v\n", path, err)
+ return
+ }
+ //nolint:errcheck
+ defer f.Close() // Ensure file is closed after writing
+
+ // Copy the snapshot stream to the file
+ if _, err = io.Copy(f, r); err != nil {
+ fmt.Fprintf(os.Stderr, "Failed to write snapshot to file: %v\n", err)
+ return
+ }
+ },
+ }
+
+ // Optional flags can be added here
+
+ return snapshotCmd
+}
+
+func setupPortForwarding(config *Config, clientset *kubernetes.Clientset) (*tls.Config, uint16, error) {
+ pod, err := clientset.CoreV1().Pods(config.Namespace).Get(context.Background(), config.PodName, metav1.GetOptions{})
+ if err != nil {
+ return nil, 0, fmt.Errorf("failed to get pod: %w", err)
+ }
+
+ path := fmt.Sprintf("/api/v1/namespaces/%s/pods/%s/portforward", config.Namespace, config.PodName)
+ clientConfig, err := clientcmd.BuildConfigFromFlags("", config.Kubeconfig)
+ if err != nil {
+ return nil, 0, fmt.Errorf("error building kubeconfig: %w", err)
+ }
+
+ transport, upgrader, err := spdy.RoundTripperFor(clientConfig)
+ if err != nil {
+ return nil, 0, fmt.Errorf("failed to create round tripper: %w", err)
+ }
+
+ hostURL, err := url.Parse(clientConfig.Host)
+ if err != nil {
+ return nil, 0, fmt.Errorf("failed to parse host URL: %w", err)
+ }
+
+ hostURL.Path = path
+
+ stopChan, readyChan := make(chan struct{}, 1), make(chan struct{}, 1)
+ dialer := spdy.NewDialer(upgrader, &http.Client{Transport: transport}, "POST", hostURL)
+
+ silentOut := &silentWriter{}
+ portForwarder, err := portforward.New(dialer, []string{"0:2379"}, stopChan, readyChan, silentOut, os.Stderr)
+ if err != nil {
+ return nil, 0, fmt.Errorf("failed to create port forwarder: %w", err)
+ }
+
+ // Starting port forwarding
+ go func() {
+ if err := portForwarder.ForwardPorts(); err != nil {
+ fmt.Printf("Failed to start port forwarding: %s\n", err)
+ }
+ }()
+
+ <-readyChan // Waiting for port forwarding to be ready
+
+ // Obtaining the local port used for forwarding
+ forwardedPorts, err := portForwarder.GetPorts()
+ if err != nil {
+ return nil, 0, fmt.Errorf("failed to get forwarded ports: %w", err)
+ }
+
+ localPort := forwardedPorts[0].Local
+
+ tlsConfig, err := getTLSConfig(clientset, pod, config.Namespace)
+ if err != nil {
+ return nil, 0, fmt.Errorf("failed to get TLS config: %w", err)
+ }
+
+ return tlsConfig, localPort, nil
+}
+
+// Initialize configuration via Cobra command
+func initializeConfig(cmd *cobra.Command) *Config {
+ var kubeconfig, namespace, podName string
+
+ // Checking environment variable first
+ envKubeconfig := os.Getenv("KUBECONFIG")
+ if envKubeconfig != "" {
+ kubeconfig = envKubeconfig
+ } else {
+ // Use default kubeconfig from home directory
+ kubeconfig = filepath.Join(homedir.HomeDir(), ".kube", "config")
+ }
+
+ // Binding flags
+ cmd.PersistentFlags().StringVarP(&kubeconfig, "kubeconfig", "k", kubeconfig, "Path to the kubeconfig file")
+ cmd.PersistentFlags().StringVarP(&namespace, "namespace", "n", "",
+ "Namespace of the etcd pod (default is the current namespace from kubeconfig)")
+ cmd.PersistentFlags().StringVarP(&podName, "pod", "p", "", "Name of the etcd pod")
+
+ // Parse flags
+ if err := cmd.ParseFlags(os.Args[1:]); err != nil {
+ fmt.Fprintf(os.Stderr, "Failed to parse flags: %v\n", err)
+ os.Exit(1)
+ }
+
+ // If namespace is not specified, fetch it from kubeconfig context
+ if namespace == "" {
+ configLoader := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(
+ clientcmd.NewDefaultClientConfigLoadingRules(),
+ &clientcmd.ConfigOverrides{})
+ ns, _, err := configLoader.Namespace()
+ if err != nil {
+ fmt.Printf("Error fetching namespace from kubeconfig: %s\n", err)
+ os.Exit(1)
+ }
+ namespace = ns
+ if namespace == "" {
+ namespace = "default" // Default to "default" if not specified
+ }
+ }
+
+ return &Config{
+ Kubeconfig: kubeconfig,
+ Namespace: namespace,
+ PodName: podName,
+ }
+}
+
+// Config struct to hold configuration
+type Config struct {
+ Kubeconfig string
+ Namespace string
+ PodName string
+}
+
+func getTLSConfig(clientset *kubernetes.Clientset, pod *corev1.Pod, namespace string) (*tls.Config, error) {
+ for _, container := range pod.Spec.Containers {
+ if container.Name == "etcd" {
+ secretName, err := findSecretNameForTLS(pod, container)
+ if err != nil {
+ if err.Error() == "trusted CA file path not specified in container args" {
+ return nil, nil
+ }
+ return nil, err
+ }
+
+ caCertPool, clientCert, err := extractTLSFiles(clientset, namespace, secretName)
+ if err != nil {
+ return nil, err
+ }
+
+ return &tls.Config{
+ Certificates: []tls.Certificate{*clientCert},
+ RootCAs: caCertPool,
+ }, nil
+ }
+ }
+ return nil, fmt.Errorf("etcd container not found")
+}
+
+func findSecretNameForTLS(pod *corev1.Pod, container corev1.Container) (string, error) {
+ caFilePath := ""
+ for _, arg := range append(container.Command, container.Args...) {
+ if strings.HasPrefix(arg, "--trusted-ca-file=") {
+ caFilePath = strings.TrimPrefix(arg, "--trusted-ca-file=")
+ break
+ }
+ }
+
+ if caFilePath == "" {
+ return "", fmt.Errorf("trusted CA file path not specified in container args")
+ }
+
+ for _, vm := range container.VolumeMounts {
+ if strings.HasPrefix(caFilePath, vm.MountPath) {
+ // We found the mount path, now find the volume
+ for _, vol := range pod.Spec.Volumes {
+ if vol.Name == vm.Name && vol.Secret != nil {
+ return vol.Secret.SecretName, nil
+ }
+ }
+ }
+ }
+
+ return "", fmt.Errorf("secret for the trusted CA file not found")
+}
+
+func extractTLSFiles(clientset *kubernetes.Clientset, namespace, secretName string) (
+ *x509.CertPool, *tls.Certificate, error) {
+ secret, err := clientset.CoreV1().Secrets(namespace).Get(context.Background(), secretName, metav1.GetOptions{})
+ if err != nil {
+ return nil, nil, err
+ }
+
+ caPem, ok := secret.Data["ca.crt"]
+ if !ok {
+ return nil, nil, fmt.Errorf("CA certificate not found in secret")
+ }
+ caCertPool := x509.NewCertPool()
+ if !caCertPool.AppendCertsFromPEM(caPem) {
+ return nil, nil, fmt.Errorf("failed to parse CA certificate")
+ }
+
+ certPem, ok := secret.Data["tls.crt"]
+ if !ok {
+ return nil, nil, fmt.Errorf("TLS certificate not found in secret")
+ }
+ keyPem, ok := secret.Data["tls.key"]
+ if !ok {
+ return nil, nil, fmt.Errorf("TLS key not found in secret")
+ }
+
+ clientCert, err := tls.X509KeyPair(certPem, keyPem)
+ if err != nil {
+ return nil, nil, fmt.Errorf("failed to create X509 key pair: %s", err)
+ }
+
+ return caCertPool, &clientCert, nil
+}
+
+type silentWriter struct{}
+
+func (sw *silentWriter) Write(p []byte) (int, error) {
+ return len(p), nil
+}
diff --git a/cmd/main.go b/cmd/manager/main.go
similarity index 100%
rename from cmd/main.go
rename to cmd/manager/main.go
diff --git a/go.mod b/go.mod
index ae9ce48c..d74f4195 100644
--- a/go.mod
+++ b/go.mod
@@ -3,10 +3,12 @@ module github.com/aenix-io/etcd-operator
go 1.22.4
require (
+ github.com/dustin/go-humanize v1.0.1
github.com/go-logr/logr v1.4.2
github.com/google/uuid v1.6.0
github.com/onsi/ginkgo/v2 v2.19.0
github.com/onsi/gomega v1.33.1
+ github.com/spf13/cobra v1.7.0
github.com/spf13/pflag v1.0.5
github.com/spf13/viper v1.19.0
go.etcd.io/etcd/client/v3 v3.5.14
@@ -40,17 +42,21 @@ require (
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 // indirect
+ github.com/gorilla/websocket v1.5.0 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/imdario/mergo v0.3.6 // indirect
+ github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
+ github.com/moby/spdystream v0.2.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
+ github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/prometheus/client_golang v1.18.0 // indirect
diff --git a/go.sum b/go.sum
index a0c4a088..a13159d3 100644
--- a/go.sum
+++ b/go.sum
@@ -1,3 +1,5 @@
+github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
+github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
@@ -6,11 +8,14 @@ github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr
github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
+github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
+github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=
github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84=
@@ -55,10 +60,15 @@ github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 h1:k7nVchz72niMH6YLQN
github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
+github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28=
github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
+github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
+github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
@@ -80,6 +90,8 @@ github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvls
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
+github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8=
+github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
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=
@@ -87,6 +99,8 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
+github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus=
+github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA=
github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To=
github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk=
@@ -108,6 +122,7 @@ github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
+github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ=
github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
@@ -118,6 +133,8 @@ github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
+github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
+github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI=
From 087b4a3eeceef1df605c27fb7a377aa4f88ce0eb Mon Sep 17 00:00:00 2001
From: Artem Bortnikov
Date: Thu, 20 Jun 2024 14:28:37 +0300
Subject: [PATCH 3/7] run kind for e2e tests with kube-proxy in ipvs mode
Signed-off-by: Artem Bortnikov
---
Makefile | 7 +++----
test/e2e/config.yaml | 4 ++++
2 files changed, 7 insertions(+), 4 deletions(-)
create mode 100644 test/e2e/config.yaml
diff --git a/Makefile b/Makefile
index b324f38c..89b9ff1c 100644
--- a/Makefile
+++ b/Makefile
@@ -203,11 +203,10 @@ kind-load: docker-build kind ## Build and upload docker image to the local Kind
.PHONY: kind-create
kind-create: kind yq ## Create kubernetes cluster using Kind.
@if ! $(KIND) get clusters | grep -q $(KIND_CLUSTER_NAME); then \
- $(KIND) create cluster --name $(KIND_CLUSTER_NAME) --image kindest/node:$(K8S_VERSION); \
- fi
- @if ! $(CONTAINER_TOOL) container inspect $$($(KIND) get nodes) | $(YQ) e '.[0].Config.Image' | grep -q $(K8S_VERSION); then \
+ $(KIND) create cluster --name $(KIND_CLUSTER_NAME) --image kindest/node:$(K8S_VERSION) --config test/e2e/config.yaml; \
+ elif ! $(CONTAINER_TOOL) container inspect $$($(KIND) get nodes --name $(KIND_CLUSTER_NAME)) | $(YQ) e '.[0].Config.Image' | grep -q $(K8S_VERSION); then \
$(KIND) delete cluster --name $(KIND_CLUSTER_NAME); \
- $(KIND) create cluster --name $(KIND_CLUSTER_NAME) --image kindest/node:$(K8S_VERSION); \
+ $(KIND) create cluster --name $(KIND_CLUSTER_NAME) --image kindest/node:$(K8S_VERSION) --config test/e2e/config.yaml; \
fi
.PHONY: kind-delete
diff --git a/test/e2e/config.yaml b/test/e2e/config.yaml
new file mode 100644
index 00000000..afe81483
--- /dev/null
+++ b/test/e2e/config.yaml
@@ -0,0 +1,4 @@
+kind: Cluster
+apiVersion: kind.x-k8s.io/v1alpha4
+networking:
+ kubeProxyMode: "ipvs"
From 2ef99eeb4807a446b384ab3da1151268dbdf7ebe Mon Sep 17 00:00:00 2001
From: Artem Bortnikov
Date: Thu, 6 Jun 2024 15:26:43 +0300
Subject: [PATCH 4/7] add volumeClaimTemplates only if storage.EmptyDir is nil
Signed-off-by: Artem Bortnikov
---
internal/controller/factory/statefulset.go | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/internal/controller/factory/statefulset.go b/internal/controller/factory/statefulset.go
index 68dc9b1c..4fd5c91e 100644
--- a/internal/controller/factory/statefulset.go
+++ b/internal/controller/factory/statefulset.go
@@ -59,8 +59,9 @@ func CreateOrUpdateStatefulSet(
podMetadata.Annotations = cluster.Spec.PodTemplate.Annotations
}
- volumeClaimTemplates := []corev1.PersistentVolumeClaim{
- {
+ volumeClaimTemplates := make([]corev1.PersistentVolumeClaim, 0)
+ if cluster.Spec.Storage.EmptyDir == nil {
+ volumeClaimTemplates = append(volumeClaimTemplates, corev1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{
Name: GetPVCName(cluster),
Labels: cluster.Spec.Storage.VolumeClaimTemplate.Labels,
@@ -68,7 +69,7 @@ func CreateOrUpdateStatefulSet(
},
Spec: cluster.Spec.Storage.VolumeClaimTemplate.Spec,
Status: cluster.Spec.Storage.VolumeClaimTemplate.Status,
- },
+ })
}
volumes := generateVolumes(cluster)
From a5f7cb9c7c07bbbedd818f3ddbd77e2e246fa175 Mon Sep 17 00:00:00 2001
From: Artem Bortnikov
Date: Thu, 20 Jun 2024 17:44:57 +0300
Subject: [PATCH 5/7] e2e test for etcd cluster with empydir storage
Signed-off-by: Artem Bortnikov
---
examples/manifests/etcdcluster-emptydir.yaml | 10 ++++
test/e2e/e2e_test.go | 51 +++++++++++++++++++-
2 files changed, 60 insertions(+), 1 deletion(-)
create mode 100644 examples/manifests/etcdcluster-emptydir.yaml
diff --git a/examples/manifests/etcdcluster-emptydir.yaml b/examples/manifests/etcdcluster-emptydir.yaml
new file mode 100644
index 00000000..06871b89
--- /dev/null
+++ b/examples/manifests/etcdcluster-emptydir.yaml
@@ -0,0 +1,10 @@
+---
+apiVersion: etcd.aenix.io/v1alpha1
+kind: EtcdCluster
+metadata:
+ name: test
+spec:
+ storage:
+ emptyDir:
+ sizeLimit: 1Gi
+ replicas: 3
diff --git a/test/e2e/e2e_test.go b/test/e2e/e2e_test.go
index c9967858..aadc826f 100644
--- a/test/e2e/e2e_test.go
+++ b/test/e2e/e2e_test.go
@@ -62,7 +62,7 @@ var _ = Describe("etcd-operator", Ordered, func() {
})
- if os.Getenv("DO_NOT_CLEANUP_AFTER_E2E") == "true" {
+ if os.Getenv("DO_CLEANUP_AFTER_E2E") == "true" {
AfterAll(func() {
By("Delete kind environment", func() {
cmd := exec.Command("make", "kind-delete")
@@ -120,6 +120,55 @@ var _ = Describe("etcd-operator", Ordered, func() {
})
})
+ Context("With emptyDir", func() {
+ It("should deploy etcd cluster", func() {
+ var err error
+ const namespace = "test-emtydir-etcd-cluster"
+ var wg sync.WaitGroup
+ wg.Add(1)
+
+ By("create namespace", func() {
+ cmd := exec.Command("sh", "-c",
+ fmt.Sprintf("kubectl create namespace %s --dry-run=client -o yaml | kubectl apply -f -", namespace)) // nolint:lll
+ _, err = utils.Run(cmd)
+ ExpectWithOffset(1, err).NotTo(HaveOccurred())
+ })
+
+ By("apply etcd cluster with emptydir manifest", func() {
+ dir, _ := utils.GetProjectDir()
+ cmd := exec.Command("kubectl", "apply",
+ "--filename", dir+"/examples/manifests/etcdcluster-emptydir.yaml",
+ "--namespace", namespace,
+ )
+ _, err = utils.Run(cmd)
+ ExpectWithOffset(1, err).NotTo(HaveOccurred())
+ })
+
+ By("wait for statefulset is ready", func() {
+ cmd := exec.Command("kubectl", "wait",
+ "statefulset/test",
+ "--for", "jsonpath={.status.readyReplicas}=3",
+ "--namespace", namespace,
+ "--timeout", "5m",
+ )
+ _, err = utils.Run(cmd)
+ ExpectWithOffset(1, err).NotTo(HaveOccurred())
+ })
+
+ client, err := utils.GetEtcdClient(ctx, client.ObjectKey{Namespace: namespace, Name: "test"})
+ Expect(err).NotTo(HaveOccurred())
+ defer func() {
+ err := client.Close()
+ Expect(err).NotTo(HaveOccurred())
+ }()
+
+ By("check etcd cluster is healthy", func() {
+ Expect(utils.IsEtcdClusterHealthy(ctx, client)).To(BeTrue())
+ })
+
+ })
+ })
+
Context("TLS and enabled auth", func() {
It("should deploy etcd cluster with auth", func() {
var err error
From 5e27419dab668bb003448562bb8b0a0962e65434 Mon Sep 17 00:00:00 2001
From: Artem Bortnikov
Date: Thu, 20 Jun 2024 21:06:58 +0300
Subject: [PATCH 6/7] upd golangci-lint rules
Signed-off-by: Artem Bortnikov
---
.golangci.yml | 3 +++
1 file changed, 3 insertions(+)
diff --git a/.golangci.yml b/.golangci.yml
index aed8644d..32eec7ed 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -16,6 +16,9 @@ issues:
linters:
- dupl
- lll
+ - path: _test\.go
+ linters:
+ - dupl
linters:
disable-all: true
enable:
From f86a17a4ac5acf58088868617973a83069c3f5d2 Mon Sep 17 00:00:00 2001
From: Artem Bortnikov
Date: Thu, 20 Jun 2024 22:17:10 +0300
Subject: [PATCH 7/7] set cosign-installer to use default (latest) cosign
version
Signed-off-by: Artem Bortnikov
---
.github/workflows/docker-publish.yaml | 2 --
1 file changed, 2 deletions(-)
diff --git a/.github/workflows/docker-publish.yaml b/.github/workflows/docker-publish.yaml
index 7064cbba..5c676a57 100644
--- a/.github/workflows/docker-publish.yaml
+++ b/.github/workflows/docker-publish.yaml
@@ -36,8 +36,6 @@ jobs:
- name: Install cosign
if: github.event_name != 'pull_request'
uses: sigstore/cosign-installer@v3.5.0
- with:
- cosign-release: 'v2.1.1'
# Set up BuildKit Docker container builder to be able to build
# multi-platform images and export cache