Compare commits

..

72 Commits

Author SHA1 Message Date
Dario Tranchitella
1731e8c2ed Merge commit from fork
* fix(etcd): using rangeEnd function to restrict permissions

Signed-off-by: Dario Tranchitella <dario@tranchitella.eu>

* Update internal/datastore/etcd.go

Co-authored-by: Simon Kienzler <SimonKienzler@users.noreply.github.com>

---------

Signed-off-by: Dario Tranchitella <dario@tranchitella.eu>
Co-authored-by: Simon Kienzler <SimonKienzler@users.noreply.github.com>
2024-08-12 16:41:16 +02:00
Adriano Pezzuto
5addb80f91 docs: using private images for datastore migration (#537) 2024-08-12 14:17:53 +02:00
Adriano Pezzuto
d8a86edcec feat(helm): add default datastore name in the helm chart (#536) 2024-08-12 09:24:56 +02:00
Dario Tranchitella
d2f3cfda24 feat(helm)!: kamaji-etcd chart dependency (#529)
* feat(helm)!: kamaji-etcd chart dependency

Signed-off-by: Dario Tranchitella <dario@tranchitella.eu>

* chore(ci): building dependencies prior linting

Signed-off-by: Dario Tranchitella <dario@tranchitella.eu>

* chore(make): building helm dependencies prior e2e

Signed-off-by: Dario Tranchitella <dario@tranchitella.eu>

---------

Signed-off-by: Dario Tranchitella <dario@tranchitella.eu>
2024-08-11 10:40:37 +02:00
dependabot[bot]
535257935d feat(deps): bump github.com/docker/docker (#534)
Bumps [github.com/docker/docker](https://github.com/docker/docker) from 27.0.3+incompatible to 27.1.1+incompatible.
- [Release notes](https://github.com/docker/docker/releases)
- [Commits](https://github.com/docker/docker/compare/v27.0.3...v27.1.1)

---
updated-dependencies:
- dependency-name: github.com/docker/docker
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-09 22:43:00 +02:00
dependabot[bot]
8cdc619124 feat(deps): bump go.etcd.io/etcd/client/v3 from 3.5.12 to 3.5.15 (#533)
Bumps [go.etcd.io/etcd/client/v3](https://github.com/etcd-io/etcd) from 3.5.12 to 3.5.15.
- [Release notes](https://github.com/etcd-io/etcd/releases)
- [Commits](https://github.com/etcd-io/etcd/compare/v3.5.12...v3.5.15)

---
updated-dependencies:
- dependency-name: go.etcd.io/etcd/client/v3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-09 11:33:01 +02:00
dependabot[bot]
ea5799420e feat(deps): bump github.com/onsi/ginkgo/v2 from 2.19.0 to 2.20.0 (#531)
Bumps [github.com/onsi/ginkgo/v2](https://github.com/onsi/ginkgo) from 2.19.0 to 2.20.0.
- [Release notes](https://github.com/onsi/ginkgo/releases)
- [Changelog](https://github.com/onsi/ginkgo/blob/master/CHANGELOG.md)
- [Commits](https://github.com/onsi/ginkgo/compare/v2.19.0...v2.20.0)

---
updated-dependencies:
- dependency-name: github.com/onsi/ginkgo/v2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-09 11:07:56 +02:00
dependabot[bot]
a16d2c5e98 feat(deps): bump github.com/go-sql-driver/mysql from 1.6.0 to 1.8.1 (#530)
Bumps [github.com/go-sql-driver/mysql](https://github.com/go-sql-driver/mysql) from 1.6.0 to 1.8.1.
- [Release notes](https://github.com/go-sql-driver/mysql/releases)
- [Changelog](https://github.com/go-sql-driver/mysql/blob/master/CHANGELOG.md)
- [Commits](https://github.com/go-sql-driver/mysql/compare/v1.6.0...v1.8.1)

---
updated-dependencies:
- dependency-name: github.com/go-sql-driver/mysql
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-09 11:06:29 +02:00
dependabot[bot]
a33c16fbbd feat(deps): bump go.uber.org/automaxprocs from 1.5.1 to 1.5.3 (#532)
Bumps [go.uber.org/automaxprocs](https://github.com/uber-go/automaxprocs) from 1.5.1 to 1.5.3.
- [Release notes](https://github.com/uber-go/automaxprocs/releases)
- [Changelog](https://github.com/uber-go/automaxprocs/blob/master/CHANGELOG.md)
- [Commits](https://github.com/uber-go/automaxprocs/compare/v1.5.1...v1.5.3)

---
updated-dependencies:
- dependency-name: go.uber.org/automaxprocs
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-09 11:06:17 +02:00
Dario Tranchitella
d8dfc62794 feat(deps): bump github.com/testcontainers/testcontainers-go from 0.13.0 to 0.32.0 (#528)
* feat(deps): bump github.com/testcontainers/testcontainers-go

Bumps [github.com/testcontainers/testcontainers-go](https://github.com/testcontainers/testcontainers-go) from 0.13.0 to 0.32.0.
- [Release notes](https://github.com/testcontainers/testcontainers-go/releases)
- [Commits](testcontainers/testcontainers-go@v0.13.0...v0.32.0)

---
updated-dependencies:
- dependency-name: github.com/testcontainers/testcontainers-go
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: Dario Tranchitella <dario@tranchitella.eu>

* feat(test): aligning to testcontainters-go version

Signed-off-by: Dario Tranchitella <dario@tranchitella.eu>

---------

Signed-off-by: Dario Tranchitella <dario@tranchitella.eu>
2024-08-07 23:46:11 +02:00
dependabot[bot]
033a18f8f9 feat(deps): bump go.etcd.io/etcd/api/v3 from 3.5.10 to 3.5.15 (#520)
Bumps [go.etcd.io/etcd/api/v3](https://github.com/etcd-io/etcd) from 3.5.10 to 3.5.15.
- [Release notes](https://github.com/etcd-io/etcd/releases)
- [Commits](https://github.com/etcd-io/etcd/compare/v3.5.10...v3.5.15)

---
updated-dependencies:
- dependency-name: go.etcd.io/etcd/api/v3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-07 23:15:00 +02:00
dependabot[bot]
a1700fcde5 feat(deps): bump the arrow group with 2 updates (#519)
Bumps the arrow group with 2 updates: [k8s.io/klog/v2](https://github.com/kubernetes/klog) and [k8s.io/kubernetes](https://github.com/kubernetes/kubernetes).


Updates `k8s.io/klog/v2` from 2.120.1 to 2.130.1
- [Release notes](https://github.com/kubernetes/klog/releases)
- [Changelog](https://github.com/kubernetes/klog/blob/main/RELEASE.md)
- [Commits](https://github.com/kubernetes/klog/compare/v2.120.1...v2.130.1)

Updates `k8s.io/kubernetes` from 1.30.2 to 1.30.3
- [Release notes](https://github.com/kubernetes/kubernetes/releases)
- [Commits](https://github.com/kubernetes/kubernetes/compare/v1.30.2...v1.30.3)

---
updated-dependencies:
- dependency-name: k8s.io/klog/v2
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: arrow
- dependency-name: k8s.io/kubernetes
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: arrow
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-07 23:14:42 +02:00
dependabot[bot]
5274a91c0c feat(deps): bump github.com/onsi/gomega from 1.32.0 to 1.34.1 (#524)
Bumps [github.com/onsi/gomega](https://github.com/onsi/gomega) from 1.32.0 to 1.34.1.
- [Release notes](https://github.com/onsi/gomega/releases)
- [Changelog](https://github.com/onsi/gomega/blob/master/CHANGELOG.md)
- [Commits](https://github.com/onsi/gomega/compare/v1.32.0...v1.34.1)

---
updated-dependencies:
- dependency-name: github.com/onsi/gomega
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-07 23:14:24 +02:00
dependabot[bot]
710ad4da8a feat(deps): bump github.com/go-pg/pg/v10 from 10.10.6 to 10.13.0 (#525)
Bumps [github.com/go-pg/pg/v10](https://github.com/go-pg/pg) from 10.10.6 to 10.13.0.
- [Release notes](https://github.com/go-pg/pg/releases)
- [Changelog](https://github.com/go-pg/pg/blob/v10/CHANGELOG.md)
- [Commits](https://github.com/go-pg/pg/compare/v10.10.6...v10.13.0)

---
updated-dependencies:
- dependency-name: github.com/go-pg/pg/v10
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-07 23:14:11 +02:00
dependabot[bot]
7a2c02996b feat(deps): bump github.com/nats-io/nats.go from 1.34.1 to 1.36.0 (#521)
Bumps [github.com/nats-io/nats.go](https://github.com/nats-io/nats.go) from 1.34.1 to 1.36.0.
- [Release notes](https://github.com/nats-io/nats.go/releases)
- [Commits](https://github.com/nats-io/nats.go/compare/v1.34.1...v1.36.0)

---
updated-dependencies:
- dependency-name: github.com/nats-io/nats.go
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-07 21:44:51 +02:00
dependabot[bot]
beeb66b552 chore(ci): bump golangci/golangci-lint-action from 3.2.0 to 6.1.0 (#518)
Bumps [golangci/golangci-lint-action](https://github.com/golangci/golangci-lint-action) from 3.2.0 to 6.1.0.
- [Release notes](https://github.com/golangci/golangci-lint-action/releases)
- [Commits](https://github.com/golangci/golangci-lint-action/compare/v3.2.0...v6.1.0)

---
updated-dependencies:
- dependency-name: golangci/golangci-lint-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-07 21:43:32 +02:00
dependabot[bot]
810eec9e8c feat(deps): bump github.com/spf13/viper from 1.10.1 to 1.19.0 (#523)
Bumps [github.com/spf13/viper](https://github.com/spf13/viper) from 1.10.1 to 1.19.0.
- [Release notes](https://github.com/spf13/viper/releases)
- [Commits](https://github.com/spf13/viper/compare/v1.10.1...v1.19.0)

---
updated-dependencies:
- dependency-name: github.com/spf13/viper
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-07 21:43:06 +02:00
dependabot[bot]
7f5cb3ab7c chore(ci): bump actions/setup-go from 3 to 5 (#515)
Bumps [actions/setup-go](https://github.com/actions/setup-go) from 3 to 5.
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](https://github.com/actions/setup-go/compare/v3...v5)

---
updated-dependencies:
- dependency-name: actions/setup-go
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-07 21:42:48 +02:00
Dario Tranchitella
b6cb9d2bee fix(helm): restoring default value for etcd auto compaction retention (#511)
* fix(helm): restoring default value for etcd auto compaction retention

Signed-off-by: Dario Tranchitella <dario@tranchitella.eu>

* fix(gh): running e2e upon helm chart changes

Signed-off-by: Dario Tranchitella <dario@tranchitella.eu>

---------

Signed-off-by: Dario Tranchitella <dario@tranchitella.eu>
2024-08-07 20:08:50 +02:00
Dario Tranchitella
e812136d61 feat(ci): enabling dependabot (#512)
Signed-off-by: Dario Tranchitella <dario@tranchitella.eu>
2024-08-07 20:08:08 +02:00
zyue110026
d4d38c8eaf fix(helm): etcd.compactionInterval not being respect (#506) 2024-07-30 23:07:03 +02:00
Dario Tranchitella
2e17d6b701 fix(ingress): comparing status enhancement (#503)
Signed-off-by: Dario Tranchitella <dario@tranchitella.eu>
2024-07-29 09:40:04 +02:00
Adriano Pezzuto
00356d8c97 feat(docs): document edge release (#502) 2024-07-29 09:38:55 +02:00
Dario Tranchitella
3b75b23e05 chore(ci): building edge releases (#498) 2024-07-26 16:02:46 +02:00
Dario Tranchitella
a707c618d5 docs: openinfra day france 2024 video (#495) 2024-07-17 13:57:10 +02:00
Mario Valderrama
84e669316a chore: update default konnectivity version (#492)
Signed-off-by: Mario Valderrama <mario.valderrama@ionos.com>
2024-07-17 11:34:43 +02:00
Mario Valderrama
2e235a4e32 fix: silence ginkgo versions mismatch warning (#493)
Signed-off-by: Mario Valderrama <mario.valderrama@ionos.com>
2024-07-17 11:32:44 +02:00
Dario Tranchitella
52c1ee8aba chore(kine): upgrading to v0.11.10
Signed-off-by: Dario Tranchitella <dario@tranchitella.eu>
2024-07-11 14:16:31 +02:00
Johann Wagner
b541962163 fix(ipv6): use net.JoinHostPort instead of fmt.Sprintf 2024-07-11 13:20:02 +02:00
Dario Tranchitella
f4c0cec4f9 chore(helm): releasing v1.0.0 2024-06-28 10:50:18 +02:00
Dario Tranchitella
db3a092d3d chore(kustomize): releasing v1.0.0 2024-06-28 10:50:18 +02:00
bsctl
d590b9d17d feat(docs): conformance for v1.30
Signed-off-by: bsctl <adriano@clastix.io>
2024-06-27 16:26:57 +02:00
bsctl
9147ae9977 feat(docs): conformance for v1.29
Signed-off-by: bsctl <adriano@clastix.io>
2024-06-27 16:26:57 +02:00
Dario Tranchitella
d2ff044228 chore(kustomize): enable telemetry
Signed-off-by: Dario Tranchitella <dario@tranchitella.eu>
2024-06-27 11:38:41 +02:00
bsctl
a147869944 feat(helm): enable telemetry
Signed-off-by: bsctl <adriano@clastix.io>
Signed-off-by: Dario Tranchitella <dario@tranchitella.eu>
2024-06-27 11:38:41 +02:00
bsctl
056ad4002a feat(docs): document telemetry
Signed-off-by: bsctl <adriano@clastix.io>
Signed-off-by: Dario Tranchitella <dario@tranchitella.eu>
2024-06-27 11:38:41 +02:00
Dario Tranchitella
91cbf0c507 feat: telemetry
Signed-off-by: Dario Tranchitella <dario@tranchitella.eu>
2024-06-27 11:38:41 +02:00
Dario Tranchitella
d57d5b5a56 feat(deps): bumping up sigs.k8s.io/controller-runtime to v0.18.4
Signed-off-by: Dario Tranchitella <dario@tranchitella.eu>
2024-06-27 11:38:41 +02:00
Dario Tranchitella
24714d7168 chore(lease): changing lease holder name
Signed-off-by: Dario Tranchitella <dario@tranchitella.eu>
2024-06-27 11:38:41 +02:00
devopsdatacomm
422d225682 chore(adopters): adding DCloud as vendor 2024-06-27 06:52:37 +02:00
Dario Tranchitella
c57c07693f chore(helm): releasing v0.6.1
Signed-off-by: Dario Tranchitella <dario@tranchitella.eu>
2024-06-24 18:32:02 +02:00
Dario Tranchitella
fa560446f1 chore(kustomize): releasing v0.6.1
Signed-off-by: Dario Tranchitella <dario@tranchitella.eu>
2024-06-24 18:32:02 +02:00
Dario Tranchitella
6ba4b4abac feat: supporting k8s v1.30.2
Signed-off-by: Dario Tranchitella <dario@tranchitella.eu>
2024-06-24 18:32:02 +02:00
Dario Tranchitella
45d0869b91 feat(webhook): validating DNS service IPs on Service CIDR
Signed-off-by: Dario Tranchitella <dario@tranchitella.eu>
2024-05-31 12:05:09 +02:00
Dario Tranchitella
511a08889e fix: nil pointer in datastore certificate handler
Signed-off-by: Dario Tranchitella <dario@tranchitella.eu>
2024-05-31 12:04:28 +02:00
Mario Valderrama
6217f2ca25 feat: add category to CRD 2024-05-24 18:01:27 +02:00
Andrei Kvapil
e51df96777 fix: removing hardcoded cluster.local domain from TCP client
Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
2024-05-21 22:25:00 +02:00
Dario Tranchitella
f235689bf5 chore(helm): releasing v0.16.0 chart 2024-05-19 12:09:12 +02:00
Dario Tranchitella
aed48e1bf0 docs: releasing v0.6.0
Signed-off-by: Dario Tranchitella <dario@tranchitella.eu>
2024-05-19 11:59:33 +02:00
Dario Tranchitella
0037e6e689 chore(helm): releasing v0.6.0
Signed-off-by: Dario Tranchitella <dario@tranchitella.eu>
2024-05-19 11:59:33 +02:00
Dario Tranchitella
56071434e6 chore(kustomize): releasing v0.6.0
Signed-off-by: Dario Tranchitella <dario@tranchitella.eu>
2024-05-19 11:59:33 +02:00
Dario Tranchitella
2d39c9ab0b fix(ci): kamaji-etcd v0.6.0 changes
Signed-off-by: Dario Tranchitella <dario@tranchitella.eu>
2024-05-19 11:59:33 +02:00
Dario Tranchitella
b2fbb52361 feat: supporting k8s v1.30.1
Signed-off-by: Dario Tranchitella <dario@tranchitella.eu>
2024-05-19 11:59:33 +02:00
Dario Tranchitella
a2236e76cf chore(deps): supporting k8s v1.30.1
Signed-off-by: Dario Tranchitella <dario@tranchitella.eu>
2024-05-19 11:59:33 +02:00
Dario Tranchitella
b1ea75f9c0 fix(psql): granting privileges to root user prior deletion
Signed-off-by: Dario Tranchitella <dario@tranchitella.eu>
2024-05-17 20:41:11 +02:00
lansaloni
6aea80ce45 chore(adopters): adding Sicuro Tech Labs as end-user 2024-05-16 12:08:37 +02:00
Dario Tranchitella
5ebe123994 docs(nats): missing multi-tenancy support
Signed-off-by: Dario Tranchitella <dario@tranchitella.eu>
2024-05-09 16:55:14 +02:00
Dario Tranchitella
d1910cd389 fix(nats): blocking reconciliation for missing multi-tenancy
Signed-off-by: Dario Tranchitella <dario@tranchitella.eu>
2024-05-09 16:55:01 +02:00
Dario Tranchitella
203e168397 docs: konnectivity agent tolerations support
Signed-off-by: Dario Tranchitella <dario@tranchitella.eu>
2024-05-09 11:36:07 +02:00
Dario Tranchitella
b29a79da36 feat(helm): konnectivity agent tolerations support
Signed-off-by: Dario Tranchitella <dario@tranchitella.eu>
2024-05-09 11:36:07 +02:00
Dario Tranchitella
5ec586960f feat(kustomize): konnectivity agent tolerations support
Signed-off-by: Dario Tranchitella <dario@tranchitella.eu>
2024-05-09 11:36:07 +02:00
Dario Tranchitella
90aef60c18 feat: konnectivity agent tolerations support
Signed-off-by: Dario Tranchitella <dario@tranchitella.eu>
2024-05-09 11:36:07 +02:00
TheCodeAssassin
9ce8da0b37 feat: making DataStore TLS configuration optional
Co-authored-by: Dario Tranchitella <dario@tranchitella.eu>
2024-05-09 11:34:50 +02:00
Mario Valderrama
9d73905965 fix: simplify arg parsing
Signed-off-by: Mario Valderrama <mario.valderrama@ionos.com>
2024-05-08 14:16:17 +02:00
ignaziodinataliTIM
32383be1d0 chore(adopters): adding TIM as R&D early adopter 2024-05-08 14:14:00 +02:00
Dario Tranchitella
6ffd6bbdfd feat(nats): webhook for missing multi-tenancy support
Signed-off-by: Dario Tranchitella <dario@tranchitella.eu>
2024-05-06 17:32:29 +02:00
Dario Tranchitella
b7169215ae chore(go): nats dependency
Signed-off-by: Dario Tranchitella <dario@tranchitella.eu>
2024-05-06 17:32:29 +02:00
TheCodeAssassin
f8a0206785 fix(nats): noEmbed is required in newer versions of kine 2024-05-02 18:26:32 +02:00
Dario Tranchitella
1d548665ee fix(kubeadm): version getter must return component versions
Signed-off-by: Dario Tranchitella <dario@tranchitella.eu>
2024-04-24 16:28:37 +02:00
Hamza BOUDOUCHE
37616865b4 feat: support for custom service account 2024-04-23 11:03:33 +02:00
Hamza BOUDOUCHE
d31b3eab0a feat: pod additional metadata 2024-04-22 17:55:38 +02:00
TheCodeAssassin
28a098af21 feat: initial support for NATS as Datastore (#442) 2024-04-22 15:31:35 +02:00
104 changed files with 3947 additions and 4189 deletions

20
.github/dependabot.yml vendored Normal file
View File

@@ -0,0 +1,20 @@
version: 2
updates:
- package-ecosystem: gomod
directory: /
schedule:
interval: daily
rebase-strategy: disabled
commit-message:
prefix: "feat(deps)"
groups:
arrow:
patterns:
- "k8s.io*"
- package-ecosystem: github-actions
directory: /
schedule:
interval: daily
rebase-strategy: disabled
commit-message:
prefix: "chore(ci)"

View File

@@ -12,12 +12,12 @@ jobs:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v2
- uses: actions/setup-go@v3
- uses: actions/setup-go@v5
with:
go-version: '1.22'
check-latest: true
- name: Run golangci-lint
uses: golangci/golangci-lint-action@v3.2.0
uses: golangci/golangci-lint-action@v6.1.0
with:
version: v1.54.2
only-new-issues: false
@@ -29,7 +29,7 @@ jobs:
- uses: actions/checkout@v2
with:
fetch-depth: 0
- uses: actions/setup-go@v3
- uses: actions/setup-go@v5
with:
go-version: '1.22'
check-latest: true

View File

@@ -4,6 +4,7 @@ on:
push:
tags:
- "v*"
- "edge-*"
jobs:
docker-ci:

View File

@@ -6,6 +6,7 @@ on:
paths:
- '.github/workflows/e2e.yml'
- 'api/**'
- 'charts/kamaji/**'
- 'controllers/**'
- 'e2e/*'
- 'Dockerfile'
@@ -19,6 +20,7 @@ on:
paths:
- '.github/workflows/e2e.yml'
- 'api/**'
- 'charts/kamaji/**'
- 'controllers/**'
- 'e2e/*'
- 'Dockerfile'
@@ -36,7 +38,7 @@ jobs:
- uses: actions/checkout@v2
with:
fetch-depth: 0
- uses: actions/setup-go@v3
- uses: actions/setup-go@v5
with:
go-version: '1.22'
check-latest: true

View File

@@ -25,6 +25,10 @@ jobs:
- uses: azure/setup-helm@v1
with:
version: 3.3.4
- name: Building dependencies
run: |-
helm repo add clastix https://clastix.github.io/charts
helm dependency build ./charts/kamaji
- name: Linting Chart
run: helm lint ./charts/kamaji
release:

6
.gitignore vendored
View File

@@ -32,5 +32,9 @@ bin
**/*.key
**/*.pem
**/*.csr
**/server-csr.json
.DS_Store
**/server-csr.json
!deploy/kine/mysql/server-csr.json
!deploy/kine/nats/server-csr.json
charts/kamaji/charts

View File

@@ -3,7 +3,7 @@ linters-settings:
sections:
- standard
- default
- prefix(github.com/clastix/kamaji)
- prefix(github.com/clastix/kamaji/)
goheader:
template: |-
Copyright 2022 Clastix Labs
@@ -37,6 +37,8 @@ linters:
- funlen
- dupl
- cyclop
- gocognit
- nestif
# deprecated linters
- deadcode
- golint

View File

@@ -7,12 +7,16 @@ Feel free to open a Pull-Request to get yours listed.
| Type | Name | Since | Website | Use-Case |
|:-|:-|:-|:-|:-|
| Vendor | DCloud | 2024 | [link](https://dcloud.co.id) | DCloud is an Indonesian Cloud Provider using Kamaji to build and offer [Managed Kubernetes Service](https://dcloud.co.id/dkubes.html). |
| End-user | Sicuro Tech Lab | 2024 | [link](https://sicurotechlab.it/) | Sicuro Tech Lab offers cloud infrastructure for Web Agencies and uses kamaji to provide managed k8s services. |
| R&D | TIM | 2024 | [link](https://www.gruppotim.it) | TIM is an Italian telecommunications company using Kamaji for experimental research and development purposes. |
| End-user | KINX | 2024 | [link](https://kinx.net/?lang=en) | KINX is an Internet infrastructure service provider and will use kamaji for its new [Managed Kubernetes Service](https://kinx.net/service/cloud/kubernetes/intro/?lang=en). |
| End-user | sevensphere | 2023 | [link](https://www.sevensphere.io) | Sevensphere provides consulting services for end-user companies / cloud providers and uses Kamaji for designing cloud/on-premises Kubernetes-as-a-Service platform. |
| Vendor | Ænix | 2023 | [link](https://aenix.io/) | Ænix provides consulting services for cloud providers and uses Kamaji for running Kubernetes-as-a-Service in free PaaS platform [Cozystack](https://cozystack.io). |
| Vendor | Netsons | 2023 | [link](https://www.netsons.com) | Netsons is an Italian hosting and cloud provider and uses Kamaji in its [Managed Kubernetes](https://www.netsons.com/kubernetes) offering. |
| Vendor | Aknostic | 2023 | [link](https://aknostic.com) | Aknostic is a cloud-native consultancy company using Kamaji to build a Kubernetes based PaaS. |
### Adopter Types
**End-user**: The organization runs Kamaji in production in some way.
@@ -20,3 +24,5 @@ Feel free to open a Pull-Request to get yours listed.
**Integration**: The organization has a product that integrates with Kamaji, but does not contain Kamaji.
**Vendor**: The organization packages Kamaji in their product and sells it as part of their product.
**R&D**: Company that exploring innovative technologies and solutions for research and development purposes.

View File

@@ -3,7 +3,7 @@
# To re-generate a bundle for another specific version without changing the standard setup, you can:
# - use the VERSION as arg of the bundle target (e.g make bundle VERSION=0.0.2)
# - use environment variables to overwrite this value (e.g export VERSION=0.0.2)
VERSION ?= 0.5.1
VERSION ?= 1.0.0
# CHANNELS define the bundle channels used in the bundle.
# Add a new line here if you would like to change its default config. (E.g CHANNELS = "candidate,fast,stable")
@@ -77,7 +77,7 @@ helm: ## Download helm locally if necessary.
GINKGO = $(shell pwd)/bin/ginkgo
ginkgo: ## Download ginkgo locally if necessary.
$(call go-install-tool,$(GINKGO),github.com/onsi/ginkgo/v2/ginkgo@v2.6.0)
$(call go-install-tool,$(GINKGO),github.com/onsi/ginkgo/v2/ginkgo)
KIND = $(shell pwd)/bin/kind
kind: ## Download kind locally if necessary.
@@ -132,7 +132,11 @@ datastore-postgres:
$(MAKE) NAME=gold _datastore-postgres
_datastore-etcd:
$(HELM) upgrade --install etcd-$(NAME) clastix/kamaji-etcd --create-namespace -n etcd-system --set datastore.enabled=true
$(HELM) upgrade --install etcd-$(NAME) clastix/kamaji-etcd --create-namespace -n etcd-system --set datastore.enabled=true --set fullnameOverride=etcd-$(NAME)
_datastore-nats:
$(MAKE) NAME=$(NAME) NAMESPACE=nats-system -C deploy/kine/nats nats
kubectl apply -f $(shell pwd)/config/samples/kamaji_v1alpha1_datastore_nats_$(NAME).yaml
datastore-etcd: helm
$(HELM) repo add clastix https://clastix.github.io/charts
@@ -141,7 +145,15 @@ datastore-etcd: helm
$(MAKE) NAME=silver _datastore-etcd
$(MAKE) NAME=gold _datastore-etcd
datastores: datastore-mysql datastore-etcd datastore-postgres ## Install all Kamaji DataStores with multiple drivers, and different tiers.
datastore-nats: helm
$(HELM) repo add nats https://nats-io.github.io/k8s/helm/charts/
$(HELM) repo update
$(MAKE) NAME=bronze _datastore-nats
$(MAKE) NAME=silver _datastore-nats
$(MAKE) NAME=gold _datastore-nats
$(MAKE) NAME=notls _datastore-nats
datastores: datastore-mysql datastore-etcd datastore-postgres datastore-nats ## Install all Kamaji DataStores with multiple drivers, and different tiers.
##@ Build
@@ -295,7 +307,9 @@ env:
.PHONY: e2e
e2e: env load helm ginkgo cert-manager ## Create a KinD cluster, install Kamaji on it and run the test suite.
$(HELM) upgrade --debug --install kamaji ./charts/kamaji --create-namespace --namespace kamaji-system --set "image.pullPolicy=Never"
$(HELM) repo add clastix https://clastix.github.io/charts
$(HELM) dependency build ./charts/kamaji
$(HELM) upgrade --debug --install kamaji ./charts/kamaji --create-namespace --namespace kamaji-system --set "image.pullPolicy=Never" --set "telemetry.disabled=true"
$(MAKE) datastores
$(GINKGO) -v ./e2e

View File

@@ -53,7 +53,7 @@ The state is managed by the `Datastore` API, a cluster-scoped resource which can
- **Managing core addons**: Kamaji allows configuring automatically `kube-proxy`, `CoreDNS`, and `konnectivity`, with automatic remediation in case of user errors (e.g.: deleting the `CoreDNS` deployment).
- **Auto Healing**: the `TenantControlPlane` objects in the management cluster are tracked by Kamaji, in case of deletion of those, everything is created in an idempotent way.
- **Datastore multi-tenancy**: optionally, Kamaji allows running multiple Control Planes on the same _Datastore_ instance leveraging on the multi-tenancy of each driver, decreasing operations and optimizing costs.
- **Overcoming `etcd` limitations**: optionally, Kamaji allows using a different _Datastore_ thanks to [`kine`](https://github.com/k3s-io/kine) by supporting `MySQL` or `PostgreSQL` as an alternative.
- **Overcoming `etcd` limitations**: optionally, Kamaji allows using a different _Datastore_ thanks to [`kine`](https://github.com/k3s-io/kine) by supporting `MySQL`, `PostgreSQL`, or `NATS` as an alternative.
- **Simplifying mixed-networks setup**: thanks to [`Konnectivity`](https://kubernetes.io/docs/tasks/extend-kubernetes/setup-konnectivity/),
the Tenant Control Plane is connected to the worker nodes hosted in a different network, overcoming the no-NAT availability when dealing with nodes with a non routable IP address
(e.g.: worker nodes in a different infrastructure).
@@ -104,7 +104,7 @@ Since Kamaji is just focusing on the Control Plane a [Kamaji's Cluster API Contr
- [x] Dynamic address on Load Balancer
- [x] Zero Downtime Tenant Control Plane upgrade
- [x] [Join worker nodes from anywhere thanks to Konnectivity](https://kamaji.clastix.io/concepts/#konnectivity)
- [x] [Alternative datastore MySQL and PostgreSQL](https://kamaji.clastix.io/guides/alternative-datastore/)
- [x] [Alternative datastore MySQL, PostgreSQL, NATS](https://kamaji.clastix.io/guides/alternative-datastore/)
- [x] [Pool of multiple datastores](https://kamaji.clastix.io/concepts/#datastores)
- [x] [Seamless migration between datastores](https://kamaji.clastix.io/guides/datastore-migration/)
- [ ] Automatic assignment to a datastore
@@ -122,6 +122,7 @@ Since Kamaji is just focusing on the Control Plane a [Kamaji's Cluster API Contr
- YouTube ▶️ [Equinix, Kamaji, and Cluster API](https://www.youtube.com/watch?v=TLBTqROj_wA)
- YouTube ▶️ [Rancher & Kamaji: solving multitenancy challenges in the Kubernetes world](https://www.youtube.com/watch?v=VXHNrMmlF8U)
- YouTube ▶️ [Enabling Self-Service Kubernetes clusters with Kamaji and Paralus](https://www.youtube.com/watch?v=JWA2LwZazM0)
- YouTube ▶️ [Hosted Control Plane on Kubernetes (HPC) with Kamaji and K0mostron by Hervé Leclerc, ALTER WAY](https://www.youtube.com/watch?v=vmRdE2ngn78)
### 🏷️ Versioning
@@ -157,4 +158,4 @@ The code is provided as-is with no warranties.
If you're looking to run Kamaji in production and would like to learn more, **CLASTIX** can help by offering [Open Source support plans](https://clastix.io/support),
as well as providing a comprehensive Enterprise Platform named [CLASTIX Enterprise Platform](https://clastix.cloud/), built on top of the Kamaji and [Capsule](https://capsule.clastix.io/) project (now donated to CNCF as a Sandbox project).
Feel free to get in touch with the provided [Contact form](https://clastix.io/contact).
Feel free to get in touch with the provided [Contact form](https://clastix.io/contact).

View File

@@ -8,7 +8,7 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// +kubebuilder:validation:Enum=etcd;MySQL;PostgreSQL
// +kubebuilder:validation:Enum=etcd;MySQL;PostgreSQL;NATS
type Driver string
@@ -16,6 +16,7 @@ var (
EtcdDriver Driver = "etcd"
KineMySQLDriver Driver = "MySQL"
KinePostgreSQLDriver Driver = "PostgreSQL"
KineNatsDriver Driver = "NATS"
)
// +kubebuilder:validation:MinItems=1
@@ -33,7 +34,8 @@ type DataStoreSpec struct {
// This value is optional.
BasicAuth *BasicAuth `json:"basicAuth,omitempty"`
// Defines the TLS/SSL configuration required to connect to the data store in a secure way.
TLSConfig TLSConfig `json:"tlsConfig"`
// This value is optional.
TLSConfig *TLSConfig `json:"tlsConfig,omitempty"`
}
// TLSConfig contains the information used to connect to the data store using a secured connection.
@@ -42,7 +44,7 @@ type TLSConfig struct {
// The key reference is required since etcd authentication is based on certificates, and Kamaji is responsible in creating this.
CertificateAuthority CertKeyPair `json:"certificateAuthority"`
// Specifies the SSL/TLS key and private key pair used to connect to the data store.
ClientCertificate ClientCertificate `json:"clientCertificate"`
ClientCertificate *ClientCertificate `json:"clientCertificate,omitempty"`
}
type ClientCertificate struct {

View File

@@ -43,20 +43,22 @@ func (d *DatastoreUsedSecret) ExtractValue() client.IndexerFunc {
}
}
if ds.Spec.TLSConfig.CertificateAuthority.Certificate.SecretRef != nil {
res = append(res, d.namespacedName(*ds.Spec.TLSConfig.CertificateAuthority.Certificate.SecretRef))
}
if ds.Spec.TLSConfig != nil {
if ds.Spec.TLSConfig.CertificateAuthority.Certificate.SecretRef != nil {
res = append(res, d.namespacedName(*ds.Spec.TLSConfig.CertificateAuthority.Certificate.SecretRef))
}
if ds.Spec.TLSConfig.CertificateAuthority.PrivateKey != nil && ds.Spec.TLSConfig.CertificateAuthority.PrivateKey.SecretRef != nil {
res = append(res, d.namespacedName(*ds.Spec.TLSConfig.CertificateAuthority.PrivateKey.SecretRef))
}
if ds.Spec.TLSConfig.CertificateAuthority.PrivateKey != nil && ds.Spec.TLSConfig.CertificateAuthority.PrivateKey.SecretRef != nil {
res = append(res, d.namespacedName(*ds.Spec.TLSConfig.CertificateAuthority.PrivateKey.SecretRef))
}
if ds.Spec.TLSConfig.ClientCertificate.Certificate.SecretRef != nil {
res = append(res, d.namespacedName(*ds.Spec.TLSConfig.ClientCertificate.Certificate.SecretRef))
}
if ds.Spec.TLSConfig.ClientCertificate.Certificate.SecretRef != nil {
res = append(res, d.namespacedName(*ds.Spec.TLSConfig.ClientCertificate.Certificate.SecretRef))
}
if ds.Spec.TLSConfig.ClientCertificate.PrivateKey.SecretRef != nil {
res = append(res, d.namespacedName(*ds.Spec.TLSConfig.ClientCertificate.PrivateKey.SecretRef))
if ds.Spec.TLSConfig.ClientCertificate.PrivateKey.SecretRef != nil {
res = append(res, d.namespacedName(*ds.Spec.TLSConfig.ClientCertificate.PrivateKey.SecretRef))
}
}
return res

View File

@@ -141,8 +141,9 @@ type DeploymentSpec struct {
// such as kube-apiserver, controller-manager, and scheduler. WARNING - This option
// can override existing parameters and cause components to misbehave in unxpected ways.
// Only modify if you know what you are doing.
ExtraArgs *ControlPlaneExtraArgs `json:"extraArgs,omitempty"`
AdditionalMetadata AdditionalMetadata `json:"additionalMetadata,omitempty"`
ExtraArgs *ControlPlaneExtraArgs `json:"extraArgs,omitempty"`
AdditionalMetadata AdditionalMetadata `json:"additionalMetadata,omitempty"`
PodAdditionalMetadata AdditionalMetadata `json:"podAdditionalMetadata,omitempty"`
// AdditionalInitContainers allows adding additional init containers to the Control Plane deployment.
AdditionalInitContainers []corev1.Container `json:"additionalInitContainers,omitempty"`
// AdditionalContainers allows adding additional containers to the Control Plane deployment.
@@ -152,6 +153,9 @@ type DeploymentSpec struct {
// AdditionalVolumeMounts allows to mount an additional volume into each component of the Control Plane
// (kube-apiserver, controller-manager, and scheduler).
AdditionalVolumeMounts *AdditionalVolumeMounts `json:"additionalVolumeMounts,omitempty"`
// +kubebuilder:default="default"
// ServiceAccountName allows to specify the service account to be mounted to the pods of the Control plane deployment
ServiceAccountName string `json:"serviceAccountName,omitempty"`
}
// AdditionalVolumeMounts allows mounting additional volumes to the Control Plane components.
@@ -200,7 +204,7 @@ type KonnectivityServerSpec struct {
// The port which Konnectivity server is listening to.
Port int32 `json:"port"`
// Container image version of the Konnectivity server.
// +kubebuilder:default=v0.0.32
// +kubebuilder:default=v0.28.6
Version string `json:"version,omitempty"`
// Container image used by the Konnectivity server.
// +kubebuilder:default=registry.k8s.io/kas-network-proxy/proxy-server
@@ -215,16 +219,20 @@ type KonnectivityAgentSpec struct {
// +kubebuilder:default=registry.k8s.io/kas-network-proxy/proxy-agent
Image string `json:"image,omitempty"`
// Version for Konnectivity agent.
// +kubebuilder:default=v0.0.32
Version string `json:"version,omitempty"`
ExtraArgs ExtraArgs `json:"extraArgs,omitempty"`
// +kubebuilder:default=v0.28.6
Version string `json:"version,omitempty"`
// Tolerations for the deployed agent.
// Can be customized to start the konnectivity-agent even if the nodes are not ready or tainted.
// +kubebuilder:default={{key: "CriticalAddonsOnly", operator: "Exists"}}
Tolerations []corev1.Toleration `json:"tolerations,omitempty"`
ExtraArgs ExtraArgs `json:"extraArgs,omitempty"`
}
// KonnectivitySpec defines the spec for Konnectivity.
type KonnectivitySpec struct {
// +kubebuilder:default={version:"v0.0.32",image:"registry.k8s.io/kas-network-proxy/proxy-server",port:8132}
// +kubebuilder:default={version:"v0.28.6",image:"registry.k8s.io/kas-network-proxy/proxy-server",port:8132}
KonnectivityServerSpec KonnectivityServerSpec `json:"server,omitempty"`
// +kubebuilder:default={version:"v0.0.32",image:"registry.k8s.io/kas-network-proxy/proxy-agent"}
// +kubebuilder:default={version:"v0.28.6",image:"registry.k8s.io/kas-network-proxy/proxy-agent"}
KonnectivityAgentSpec KonnectivityAgentSpec `json:"agent,omitempty"`
}
@@ -258,7 +266,7 @@ type TenantControlPlaneSpec struct {
// +kubebuilder:object:root=true
// +kubebuilder:subresource:status
// +kubebuilder:subresource:scale:specpath=.spec.controlPlane.deployment.replicas,statuspath=.status.kubernetesResources.deployment.replicas,selectorpath=.status.kubernetesResources.deployment.selector
// +kubebuilder:resource:shortName=tcp
// +kubebuilder:resource:categories=kamaji,shortName=tcp
// +kubebuilder:printcolumn:name="Version",type="string",JSONPath=".spec.kubernetes.version",description="Kubernetes version"
// +kubebuilder:printcolumn:name="Status",type="string",JSONPath=".status.kubernetesResources.version.status",description="Status"
// +kubebuilder:printcolumn:name="Control-Plane endpoint",type="string",JSONPath=".status.controlPlaneEndpoint",description="Tenant Control Plane Endpoint (API server)"

View File

@@ -1,5 +1,4 @@
//go:build !ignore_autogenerated
// +build !ignore_autogenerated
// Copyright 2022 Clastix Labs
// SPDX-License-Identifier: Apache-2.0
@@ -526,7 +525,11 @@ func (in *DataStoreSpec) DeepCopyInto(out *DataStoreSpec) {
*out = new(BasicAuth)
(*in).DeepCopyInto(*out)
}
in.TLSConfig.DeepCopyInto(&out.TLSConfig)
if in.TLSConfig != nil {
in, out := &in.TLSConfig, &out.TLSConfig
*out = new(TLSConfig)
(*in).DeepCopyInto(*out)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DataStoreSpec.
@@ -578,6 +581,11 @@ func (in *DatastoreUsedSecret) DeepCopy() *DatastoreUsedSecret {
func (in *DeploymentSpec) DeepCopyInto(out *DeploymentSpec) {
*out = *in
out.RegistrySettings = in.RegistrySettings
if in.Replicas != nil {
in, out := &in.Replicas, &out.Replicas
*out = new(int32)
**out = **in
}
if in.NodeSelector != nil {
in, out := &in.NodeSelector, &out.NodeSelector
*out = make(map[string]string, len(*in))
@@ -616,6 +624,7 @@ func (in *DeploymentSpec) DeepCopyInto(out *DeploymentSpec) {
(*in).DeepCopyInto(*out)
}
in.AdditionalMetadata.DeepCopyInto(&out.AdditionalMetadata)
in.PodAdditionalMetadata.DeepCopyInto(&out.PodAdditionalMetadata)
if in.AdditionalInitContainers != nil {
in, out := &in.AdditionalInitContainers, &out.AdditionalInitContainers
*out = make([]v1.Container, len(*in))
@@ -775,6 +784,13 @@ func (in *IngressSpec) DeepCopy() *IngressSpec {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *KonnectivityAgentSpec) DeepCopyInto(out *KonnectivityAgentSpec) {
*out = *in
if in.Tolerations != nil {
in, out := &in.Tolerations, &out.Tolerations
*out = make([]v1.Toleration, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
if in.ExtraArgs != nil {
in, out := &in.ExtraArgs, &out.ExtraArgs
*out = make(ExtraArgs, len(*in))
@@ -1196,7 +1212,11 @@ func (in *StorageStatus) DeepCopy() *StorageStatus {
func (in *TLSConfig) DeepCopyInto(out *TLSConfig) {
*out = *in
in.CertificateAuthority.DeepCopyInto(&out.CertificateAuthority)
in.ClientCertificate.DeepCopyInto(&out.ClientCertificate)
if in.ClientCertificate != nil {
in, out := &in.ClientCertificate, &out.ClientCertificate
*out = new(ClientCertificate)
(*in).DeepCopyInto(*out)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TLSConfig.

6
charts/kamaji/Chart.lock Normal file
View File

@@ -0,0 +1,6 @@
dependencies:
- name: kamaji-etcd
repository: https://clastix.github.io/charts
version: 0.7.0
digest: sha256:2e23a11b06da2aa3a935a56a93d56876c6c8ef0a7800ee44070f9a269dfbca71
generated: "2024-08-10T23:03:35.382486587+02:00"

View File

@@ -1,5 +1,5 @@
apiVersion: v2
appVersion: v0.5.1
appVersion: v1.0.0
description: Kamaji is the Hosted Control Plane Manager for Kubernetes.
home: https://github.com/clastix/kamaji
icon: https://github.com/clastix/kamaji/raw/master/assets/logo-colored.png
@@ -17,8 +17,33 @@ name: kamaji
sources:
- https://github.com/clastix/kamaji
type: application
version: 0.15.3
version: 2.0.0
dependencies:
- name: kamaji-etcd
repository: https://clastix.github.io/charts
version: ">=0.7.0"
condition: kamaji-etcd.deploy
annotations:
catalog.cattle.io/certified: partner
catalog.cattle.io/release-name: kamaji
catalog.cattle.io/display-name: Kamaji
artifacthub.io/crds: |
- kind: TenantControlPlane
version: v1alpha1
name: tenantcontrolplanes.kamaji.clastix.io
displayName: TenantControlPlane
description: TenantControlPlane defines the desired state for a Control Plane backed by Kamaji.
- kind: DataStore
version: v1alpha1
name: datastores.kamaji.clastix.io
displayName: DataStore
description: DataStores is holding all the required details to communicate with a Datastore, such as etcd, MySQL, PostgreSQL, and NATS.
artifacthub.io/links: |
- name: CLASTIX
url: https://clastix.io
- name: support
url: https://clastix.io/support
artifacthub.io/operator: "true"
artifacthub.io/operatorCapabilities: "full lifecycle"
artifacthub.io/changes: |
- Using dependency chart `kamaji-etcd` as a default DataStore.

View File

@@ -1,6 +1,6 @@
# kamaji
![Version: 0.15.3](https://img.shields.io/badge/Version-0.15.3-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: v0.5.1](https://img.shields.io/badge/AppVersion-v0.5.1-informational?style=flat-square)
![Version: 2.0.0](https://img.shields.io/badge/Version-2.0.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: v1.0.0](https://img.shields.io/badge/AppVersion-v1.0.0-informational?style=flat-square)
Kamaji is the Hosted Control Plane Manager for Kubernetes.
@@ -20,6 +20,10 @@ Kamaji is the Hosted Control Plane Manager for Kubernetes.
Kubernetes: `>=1.21.0-0`
| Repository | Name | Version |
|------------|------|---------|
| https://clastix.github.io/charts | kamaji-etcd | >=0.7.0 |
[Kamaji](https://github.com/clastix/kamaji) requires a [multi-tenant `etcd`](https://github.com/clastix/kamaji-internal/blob/master/deploy/getting-started-with-kamaji.md#setup-internal-multi-tenant-etcd) cluster.
This Helm Chart starting from v0.1.1 provides the installation of an internal `etcd` in order to streamline the local test. If you'd like to use an externally managed etcd instance, you can specify the overrides and by setting the value `etcd.deploy=false`.
@@ -66,48 +70,7 @@ Here the values you can override:
| Key | Type | Default | Description |
|-----|------|---------|-------------|
| affinity | object | `{}` | Kubernetes affinity rules to apply to Kamaji controller pods |
| cfssl.image.repository | string | `"cfssl/cfssl"` | |
| cfssl.image.tag | string | `"latest"` | |
| datastore.basicAuth.passwordSecret.keyPath | string | `nil` | The Secret key where the data is stored. |
| datastore.basicAuth.passwordSecret.name | string | `nil` | The name of the Secret containing the password used to connect to the relational database. |
| datastore.basicAuth.passwordSecret.namespace | string | `nil` | The namespace of the Secret containing the password used to connect to the relational database. |
| datastore.basicAuth.usernameSecret.keyPath | string | `nil` | The Secret key where the data is stored. |
| datastore.basicAuth.usernameSecret.name | string | `nil` | The name of the Secret containing the username used to connect to the relational database. |
| datastore.basicAuth.usernameSecret.namespace | string | `nil` | The namespace of the Secret containing the username used to connect to the relational database. |
| datastore.driver | string | `"etcd"` | (string) The Kamaji Datastore driver, supported: etcd, MySQL, PostgreSQL (defaults=etcd). |
| datastore.enabled | bool | `true` | (bool) Enable the Kamaji Datastore creation (default=true) |
| datastore.endpoints | list | `[]` | (array) List of endpoints of the selected Datastore. When letting the Chart install the etcd datastore, this field is populated automatically. |
| datastore.nameOverride | string | `nil` | The Datastore name override, if empty and enabled=true defaults to `default`, if enabled=false, this is the name of the Datastore to connect to. |
| datastore.tlsConfig.certificateAuthority.certificate.keyPath | string | `nil` | Key of the Secret which contains the content of the certificate. |
| datastore.tlsConfig.certificateAuthority.certificate.name | string | `nil` | Name of the Secret containing the CA required to establish the mandatory SSL/TLS connection to the datastore. |
| datastore.tlsConfig.certificateAuthority.certificate.namespace | string | `nil` | Namespace of the Secret containing the CA required to establish the mandatory SSL/TLS connection to the datastore. |
| datastore.tlsConfig.certificateAuthority.privateKey.keyPath | string | `nil` | Key of the Secret which contains the content of the private key. |
| datastore.tlsConfig.certificateAuthority.privateKey.name | string | `nil` | Name of the Secret containing the CA private key required to establish the mandatory SSL/TLS connection to the datastore. |
| datastore.tlsConfig.certificateAuthority.privateKey.namespace | string | `nil` | Namespace of the Secret containing the CA private key required to establish the mandatory SSL/TLS connection to the datastore. |
| datastore.tlsConfig.clientCertificate.certificate.keyPath | string | `nil` | Key of the Secret which contains the content of the certificate. |
| datastore.tlsConfig.clientCertificate.certificate.name | string | `nil` | Name of the Secret containing the client certificate required to establish the mandatory SSL/TLS connection to the datastore. |
| datastore.tlsConfig.clientCertificate.certificate.namespace | string | `nil` | Namespace of the Secret containing the client certificate required to establish the mandatory SSL/TLS connection to the datastore. |
| datastore.tlsConfig.clientCertificate.privateKey.keyPath | string | `nil` | Key of the Secret which contains the content of the private key. |
| datastore.tlsConfig.clientCertificate.privateKey.name | string | `nil` | Name of the Secret containing the client certificate private key required to establish the mandatory SSL/TLS connection to the datastore. |
| datastore.tlsConfig.clientCertificate.privateKey.namespace | string | `nil` | Namespace of the Secret containing the client certificate private key required to establish the mandatory SSL/TLS connection to the datastore. |
| etcd.compactionInterval | int | `0` | ETCD Compaction interval (e.g. "5m0s"). (default: "0" (disabled)) |
| etcd.deploy | bool | `true` | Install an etcd with enabled multi-tenancy along with Kamaji |
| etcd.image | object | `{"pullPolicy":"IfNotPresent","repository":"quay.io/coreos/etcd","tag":"v3.5.6"}` | Install specific etcd image |
| etcd.livenessProbe | object | `{"failureThreshold":8,"httpGet":{"path":"/health?serializable=true","port":2381,"scheme":"HTTP"},"initialDelaySeconds":10,"periodSeconds":10,"timeoutSeconds":15}` | The livenessProbe for the etcd container |
| etcd.overrides.caSecret.name | string | `"etcd-certs"` | Name of the secret which contains CA's certificate and private key. (default: "etcd-certs") |
| etcd.overrides.caSecret.namespace | string | `"kamaji-system"` | Namespace of the secret which contains CA's certificate and private key. (default: "kamaji-system") |
| etcd.overrides.clientSecret.name | string | `"root-client-certs"` | Name of the secret which contains ETCD client certificates. (default: "root-client-certs") |
| etcd.overrides.clientSecret.namespace | string | `"kamaji-system"` | Name of the namespace where the secret which contains ETCD client certificates is. (default: "kamaji-system") |
| etcd.overrides.endpoints | object | `{"etcd-0":"etcd-0.etcd.kamaji-system.svc.cluster.local","etcd-1":"etcd-1.etcd.kamaji-system.svc.cluster.local","etcd-2":"etcd-2.etcd.kamaji-system.svc.cluster.local"}` | (map) Dictionary of the endpoints for the etcd cluster's members, key is the name of the etcd server. Don't define the protocol (TLS is automatically inflected), or any port, inflected from .etcd.peerApiPort value. |
| etcd.peerApiPort | int | `2380` | The peer API port which servers are listening to. |
| etcd.persistence.accessModes[0] | string | `"ReadWriteOnce"` | |
| etcd.persistence.customAnnotations | object | `{}` | The custom annotations to add to the PVC |
| etcd.persistence.size | string | `"10Gi"` | |
| etcd.persistence.storageClassName | string | `""` | |
| etcd.port | int | `2379` | The client request port. |
| etcd.serviceAccount.create | bool | `true` | Create a ServiceAccount, required to install and provision the etcd backing storage (default: true) |
| etcd.serviceAccount.name | string | `""` | Define the ServiceAccount name to use during the setup and provision of the etcd backing storage (default: "") |
| etcd.tolerations | list | `[]` | (array) Kubernetes affinity rules to apply to Kamaji etcd pods |
| defaultDatastoreName | string | `"default"` | Specify the default DataStore name for the Kamaji instance. |
| extraArgs | list | `[]` | A list of extra arguments to add to the kamaji controller default ones |
| fullnameOverride | string | `""` | |
| healthProbeBindAddress | string | `":8081"` | The address the probe endpoint binds to. (default ":8081") |
@@ -115,9 +78,13 @@ Here the values you can override:
| image.repository | string | `"clastix/kamaji"` | The container image of the Kamaji controller. |
| image.tag | string | `nil` | Overrides the image tag whose default is the chart appVersion. |
| imagePullSecrets | list | `[]` | |
| kamaji-etcd.datastore.enabled | bool | `true` | |
| kamaji-etcd.datastore.name | string | `"default"` | |
| kamaji-etcd.deploy | bool | `true` | |
| kamaji-etcd.fullnameOverride | string | `"kamaji-etcd"` | |
| livenessProbe | object | `{"httpGet":{"path":"/healthz","port":"healthcheck"},"initialDelaySeconds":15,"periodSeconds":20}` | The livenessProbe for the controller container |
| loggingDevel.enable | bool | `false` | (string) Development Mode defaults(encoder=consoleEncoder,logLevel=Debug,stackTraceLevel=Warn). Production Mode defaults(encoder=jsonEncoder,logLevel=Info,stackTraceLevel=Error) (default false) |
| metricsBindAddress | string | `":8080"` | (string) The address the metric endpoint binds to. (default ":8080") |
| loggingDevel.enable | bool | `false` | Development Mode defaults(encoder=consoleEncoder,logLevel=Debug,stackTraceLevel=Warn). Production Mode defaults(encoder=jsonEncoder,logLevel=Info,stackTraceLevel=Error) (default false) |
| metricsBindAddress | string | `":8080"` | The address the metric endpoint binds to. (default ":8080") |
| nameOverride | string | `""` | |
| nodeSelector | object | `{}` | Kubernetes node selector rules to schedule Kamaji controller |
| podAnnotations | object | `{}` | The annotations to apply to the Kamaji controller pods. |
@@ -133,6 +100,7 @@ Here the values you can override:
| serviceAccount.create | bool | `true` | |
| serviceAccount.name | string | `"kamaji-controller-manager"` | |
| serviceMonitor.enabled | bool | `false` | Toggle the ServiceMonitor true if you have Prometheus Operator installed and configured |
| telemetry | object | `{"disabled":false}` | Disable the analytics traces collection |
| temporaryDirectoryPath | string | `"/tmp/kamaji"` | Directory which will be used to work with temporary files. (default "/tmp/kamaji") |
| tolerations | list | `[]` | Kubernetes node taints that the Kamaji controller pods would tolerate |

View File

@@ -71,10 +71,12 @@ spec:
minLength: 1
type: string
name:
description: name is unique within a namespace to reference a secret resource.
description: name is unique within a namespace to reference
a secret resource.
type: string
namespace:
description: namespace defines the space within which the secret name must be unique.
description: namespace defines the space within which
the secret name must be unique.
type: string
required:
- keyPath
@@ -98,10 +100,12 @@ spec:
minLength: 1
type: string
name:
description: name is unique within a namespace to reference a secret resource.
description: name is unique within a namespace to reference
a secret resource.
type: string
namespace:
description: namespace defines the space within which the secret name must be unique.
description: namespace defines the space within which
the secret name must be unique.
type: string
required:
- keyPath
@@ -118,6 +122,7 @@ spec:
- etcd
- MySQL
- PostgreSQL
- NATS
type: string
endpoints:
description: |-
@@ -128,7 +133,9 @@ spec:
minItems: 1
type: array
tlsConfig:
description: Defines the TLS/SSL configuration required to connect to the data store in a secure way.
description: |-
Defines the TLS/SSL configuration required to connect to the data store in a secure way.
This value is optional.
properties:
certificateAuthority:
description: |-
@@ -152,10 +159,12 @@ spec:
minLength: 1
type: string
name:
description: name is unique within a namespace to reference a secret resource.
description: name is unique within a namespace to
reference a secret resource.
type: string
namespace:
description: namespace defines the space within which the secret name must be unique.
description: namespace defines the space within which
the secret name must be unique.
type: string
required:
- keyPath
@@ -179,10 +188,12 @@ spec:
minLength: 1
type: string
name:
description: name is unique within a namespace to reference a secret resource.
description: name is unique within a namespace to
reference a secret resource.
type: string
namespace:
description: namespace defines the space within which the secret name must be unique.
description: namespace defines the space within which
the secret name must be unique.
type: string
required:
- keyPath
@@ -193,7 +204,8 @@ spec:
- certificate
type: object
clientCertificate:
description: Specifies the SSL/TLS key and private key pair used to connect to the data store.
description: Specifies the SSL/TLS key and private key pair used
to connect to the data store.
properties:
certificate:
properties:
@@ -212,10 +224,12 @@ spec:
minLength: 1
type: string
name:
description: name is unique within a namespace to reference a secret resource.
description: name is unique within a namespace to
reference a secret resource.
type: string
namespace:
description: namespace defines the space within which the secret name must be unique.
description: namespace defines the space within which
the secret name must be unique.
type: string
required:
- keyPath
@@ -239,10 +253,12 @@ spec:
minLength: 1
type: string
name:
description: name is unique within a namespace to reference a secret resource.
description: name is unique within a namespace to
reference a secret resource.
type: string
namespace:
description: namespace defines the space within which the secret name must be unique.
description: namespace defines the space within which
the secret name must be unique.
type: string
required:
- keyPath
@@ -255,18 +271,17 @@ spec:
type: object
required:
- certificateAuthority
- clientCertificate
type: object
required:
- driver
- endpoints
- tlsConfig
type: object
status:
description: DataStoreStatus defines the observed state of DataStore.
properties:
usedBy:
description: List of the Tenant Control Planes, namespaced named, using this data store.
description: List of the Tenant Control Planes, namespaced named,
using this data store.
items:
type: string
type: array

File diff suppressed because it is too large Load Diff

View File

@@ -1,94 +0,0 @@
{{/*
Create a default fully qualified datastore name.
*/}}
{{- define "datastore.fullname" -}}
{{- if .Values.datastore.enabled }}
{{- default "default" .Values.datastore.nameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- required "A valid .Values.datastore.nameOverride required!" .Values.datastore.nameOverride }}
{{- end }}
{{- end }}
{{/*
Common labels
*/}}
{{- define "datastore.labels" -}}
kamaji.clastix.io/datastore: {{ .Values.datastore.driver }}
helm.sh/chart: {{ include "kamaji.chart" . }}
{{ include "kamaji.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}
{{/*
Datastore endpoints, in case of ETCD, retrieving the one provided by the chart.
*/}}
{{- define "datastore.endpoints" -}}
{{- if eq .Values.datastore.driver "etcd" }}
{{ include "etcd.endpoints" . }}
{{- else }}
{{ .Values.datastore.endpoints }}
{{- end }}
{{- end }}
{{/*
The Certificate Authority section for the DataSource object.
*/}}
{{- define "datastore.certificateAuthority" -}}
{{- if eq .Values.datastore.driver "etcd" }}
certificate:
secretReference:
name: {{ include "etcd.caSecretName" . }}
namespace: {{ include "etcd.caSecretNamespace" . }}
keyPath: ca.crt
privateKey:
secretReference:
name: {{ include "etcd.caSecretName" . }}
namespace: {{ include "etcd.caSecretNamespace" . }}
keyPath: ca.key
{{- else }}
certificate:
secretReference:
name: {{ .Values.datastore.tlsConfig.certificateAuthority.certificate.name }}
namespace: {{ .Values.datastore.tlsConfig.certificateAuthority.certificate.namespace }}
keyPath: {{ .Values.datastore.tlsConfig.certificateAuthority.certificate.keyPath }}
{{- if .Values.datastore.tlsConfig.certificateAuthority.privateKey.name }}
privateKey:
secretReference:
name: {{ .Values.datastore.tlsConfig.certificateAuthority.privateKey.name }}
namespace: {{ .Values.datastore.tlsConfig.certificateAuthority.privateKey.namespace }}
keyPath: {{ .Values.datastore.tlsConfig.certificateAuthority.privateKey.keyPath }}
{{- end }}
{{- end }}
{{- end }}
{{/*
The Client Certificate section for the DataSource object.
*/}}
{{- define "datastore.clientCertificate" -}}
{{- if eq .Values.datastore.driver "etcd" }}
certificate:
secretReference:
name: {{ include "etcd.clientSecretName" . }}
namespace: {{ include "etcd.clientSecretNamespace" . }}
keyPath: tls.crt
privateKey:
secretReference:
name: {{ include "etcd.clientSecretName" . }}
namespace: {{ include "etcd.clientSecretNamespace" . }}
keyPath: tls.key
{{- else }}
certificate:
secretReference:
name: {{ .Values.datastore.tlsConfig.clientCertificate.certificate.name }}
namespace: {{ .Values.datastore.tlsConfig.clientCertificate.certificate.namespace }}
keyPath: {{ .Values.datastore.tlsConfig.clientCertificate.certificate.keyPath }}
privateKey:
secretReference:
name: {{ .Values.datastore.tlsConfig.clientCertificate.privateKey.name }}
namespace: {{ .Values.datastore.tlsConfig.clientCertificate.privateKey.namespace }}
keyPath: {{ .Values.datastore.tlsConfig.clientCertificate.privateKey.keyPath }}
{{- end }}
{{- end }}

View File

@@ -1,142 +0,0 @@
{{/*
Create a default fully qualified etcd name.
*/}}
{{- define "etcd.fullname" -}}
{{- printf "etcd" }}
{{- end }}
{{/*
Create the name of the service account to use
*/}}
{{- define "etcd.serviceAccountName" -}}
{{- if .Values.etcd.serviceAccount.create }}
{{- default (include "etcd.fullname" .) .Values.etcd.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.etcd.serviceAccount.name }}
{{- end }}
{{- end }}
{{/*
Create the name of the Service to use
*/}}
{{- define "etcd.serviceName" -}}
{{- printf "%s" (include "etcd.fullname" .) | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Common labels
*/}}
{{- define "etcd.labels" -}}
app.kubernetes.io/name: {{ include "kamaji.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/components: etcd
{{- end }}
{{/*
Selector labels.
*/}}
{{- define "etcd.selectorLabels" -}}
app.kubernetes.io/name: {{ include "kamaji.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/component: etcd
{{- end }}
{{/*
Name of the etcd CA secret.
*/}}
{{- define "etcd.caSecretName" }}
{{- if .Values.etcd.deploy }}
{{- printf "%s-%s" (include "etcd.fullname" .) "certs" | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- required "A valid .Values.etcd.overrides.caSecret.name required!" .Values.etcd.overrides.caSecret.name }}
{{- end }}
{{- end }}
{{/*
Namespace of the etcd CA secret.
*/}}
{{- define "etcd.caSecretNamespace" }}
{{- if .Values.etcd.deploy }}
{{- .Release.Namespace }}
{{- else }}
{{- required "A valid .Values.etcd.overrides.caSecret.namespace required!" .Values.etcd.overrides.caSecret.namespace }}
{{- end }}
{{- end }}
{{/*
Name of the certificate signing requests for the certificates required by etcd.
*/}}
{{- define "etcd.csrConfigMapName" }}
{{- printf "%s-csr" (include "etcd.fullname" .) }}
{{- end }}
{{/*
Name of the etcd root-client secret.
*/}}
{{- define "etcd.clientSecretName" }}
{{- if .Values.etcd.deploy }}
{{- printf "root-client-certs" }}
{{- else }}
{{- required "A valid .Values.etcd.overrides.clientSecret.name required!" .Values.etcd.overrides.clientSecret.name }}
{{- end }}
{{- end }}
{{/*
Namespace of the etcd root-client secret.
*/}}
{{- define "etcd.clientSecretNamespace" }}
{{- if .Values.etcd.deploy }}
{{- .Release.Namespace }}
{{- else }}
{{- required "A valid .Values.etcd.overrides.clientSecret.namespace required!" .Values.etcd.overrides.clientSecret.namespace }}
{{- end }}
{{- end }}
{{/*
Comma separated list of etcd endpoints, using the overrides in case of unmanaged etcd.
*/}}
{{- define "etcd.endpoints" }}
{{- $list := list -}}
{{- if .Values.etcd.deploy }}
{{- range $count := until 3 -}}
{{- $list = append $list (printf "%s-%d.%s.%s.svc.cluster.local:%d" "etcd" $count ( include "etcd.serviceName" . ) $.Release.Namespace (int $.Values.etcd.port) ) -}}
{{- end }}
{{- else if .Values.etcd.overrides.endpoints }}
{{- range $v := .Values.etcd.overrides.endpoints -}}
{{- $list = append $list (printf "%s:%d" $v (int $.Values.etcd.port) ) -}}
{{- end -}}
{{- else if not .Values.etcd.overrides.endpoints }}
{{- fail "A valid .Values.etcd.overrides.endpoints required!" }}
{{- end }}
{{- $list | toYaml }}
{{- end }}
{{/*
Key-value of the etcd peers, using the overrides in case of unmanaged etcd.
*/}}
{{- define "etcd.initialCluster" }}
{{- $list := list -}}
{{- if .Values.etcd.deploy }}
{{- range $i, $count := until 3 -}}
{{- $list = append $list ( printf "etcd-%d=https://%s-%d.%s.%s.svc.cluster.local:%d" $i "etcd" $count ( include "etcd.serviceName" . ) $.Release.Namespace (int $.Values.etcd.peerApiPort) ) -}}
{{- end }}
{{- else if .Values.etcd.overrides.endpoints }}
{{- range $k, $v := .Values.etcd.overrides.endpoints -}}
{{- $list = append $list ( printf "%s=%s:%d" $k $v (int $.Values.etcd.peerApiPort) ) -}}
{{- end -}}
{{- else if not .Values.etcd.overrides.endpoints }}
{{- fail "A valid .Values.etcd.overrides.endpoints required!" }}
{{- end }}
{{- join "," $list -}}
{{- end }}
{{/*
Retrieve the current Kubernetes version to launch a kubectl container with the minimum version skew possible.
*/}}
{{- define "etcd.jobsTagKubeVersion" -}}
{{- if contains "-eks-" .Capabilities.KubeVersion.GitVersion }}
{{- print "v" .Capabilities.KubeVersion.Major "." (.Capabilities.KubeVersion.Minor | replace "+" "") -}}
{{- else }}
{{- print "v" .Capabilities.KubeVersion.Major "." .Capabilities.KubeVersion.Minor -}}
{{- end }}
{{- end }}

View File

@@ -33,7 +33,11 @@ spec:
- --leader-elect
- --metrics-bind-address={{ .Values.metricsBindAddress }}
- --tmp-directory={{ .Values.temporaryDirectoryPath }}
- --datastore={{ include "datastore.fullname" . }}
{{- $datastoreName := .Values.defaultDatastoreName | required ".Values.defaultDatastoreName is required!" }}
- --datastore={{ $datastoreName }}
{{- if .Values.telemetry.disabled }}
- --disable-telemetry
{{- end }}
{{- if .Values.loggingDevel.enable }}
- --zap-devel
{{- end }}

View File

@@ -1,28 +0,0 @@
{{- if .Values.datastore.enabled}}
apiVersion: kamaji.clastix.io/v1alpha1
kind: DataStore
metadata:
name: {{ include "datastore.fullname" . }}
annotations:
"helm.sh/hook": pre-install
labels:
{{- include "datastore.labels" . | nindent 4 }}
spec:
driver: {{ .Values.datastore.driver }}
endpoints:
{{- include "datastore.endpoints" . | indent 4 }}
{{- if (and .Values.datastore.basicAuth.usernameSecret.name .Values.datastore.basicAuth.passwordSecret.name) }}
basicAuth:
username:
secretReference:
{{- .Values.datastore.basicAuth.usernameSecret | toYaml | nindent 8 }}
password:
secretReference:
{{- .Values.datastore.basicAuth.passwordSecret | toYaml | nindent 8 }}
{{- end }}
tlsConfig:
certificateAuthority:
{{- include "datastore.certificateAuthority" . | indent 6 }}
clientCertificate:
{{- include "datastore.clientCertificate" . | indent 6 }}
{{- end}}

View File

@@ -1,98 +0,0 @@
{{- if .Values.etcd.deploy }}
apiVersion: v1
kind: ConfigMap
metadata:
labels:
{{- include "etcd.labels" . | nindent 4 }}
name: {{ include "etcd.csrConfigMapName" . }}
namespace: {{ .Release.Namespace }}
annotations:
"helm.sh/hook": pre-install
"helm.sh/hook-weight": "-5"
"helm.sh/hook-delete-policy": "hook-succeeded,hook-failed"
data:
ca-csr.json: |-
{
"CN": "Clastix CA",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "IT",
"ST": "Italy",
"L": "Milan"
}
]
}
config.json: |-
{
"signing": {
"default": {
"expiry": "8760h"
},
"profiles": {
"server-authentication": {
"usages": ["signing", "key encipherment", "server auth"],
"expiry": "8760h"
},
"client-authentication": {
"usages": ["signing", "key encipherment", "client auth"],
"expiry": "8760h"
},
"peer-authentication": {
"usages": ["signing", "key encipherment", "server auth", "client auth"],
"expiry": "8760h"
}
}
}
}
server-csr.json: |-
{
"CN": "etcd",
"key": {
"algo": "rsa",
"size": 2048
},
"hosts": [
{{- range $count := until 3 -}}
{{ printf "\"etcd-%d.%s.%s.svc.cluster.local\"," $count (include "etcd.serviceName" .) $.Release.Namespace }}
{{- end }}
"etcd-server.{{ .Release.Namespace }}.svc.cluster.local",
"etcd-server.{{ .Release.Namespace }}.svc",
"etcd-server",
"127.0.0.1"
]
}
peer-csr.json: |-
{
"CN": "etcd",
"key": {
"algo": "rsa",
"size": 2048
},
"hosts": [
{{- range $count := until 3 -}}
{{ printf "\"etcd-%d\"," $count }}
{{ printf "\"etcd-%d.%s\"," $count (include "etcd.serviceName" .) }}
{{ printf "\"etcd-%d.%s.%s.svc\"," $count (include "etcd.serviceName" .) $.Release.Namespace }}
{{ printf "\"etcd-%d.%s.%s.svc.cluster.local\"," $count (include "etcd.serviceName" .) $.Release.Namespace }}
{{- end }}
"127.0.0.1"
]
}
root-client-csr.json: |-
{
"CN": "root",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"O": "system:masters"
}
]
}
{{- end }}

View File

@@ -1,35 +0,0 @@
{{- if .Values.etcd.deploy }}
apiVersion: batch/v1
kind: Job
metadata:
labels:
{{- include "etcd.labels" . | nindent 4 }}
annotations:
"helm.sh/hook": pre-delete
"helm.sh/hook-weight": "-5"
"helm.sh/hook-delete-policy": "hook-succeeded,hook-failed"
name: "{{ .Release.Name }}-etcd-teardown"
namespace: {{ .Release.Namespace }}
spec:
template:
metadata:
name: "{{ .Release.Name }}"
spec:
serviceAccountName: {{ include "etcd.serviceAccountName" . }}
restartPolicy: Never
containers:
- name: kubectl
image: {{ printf "clastix/kubectl:%s" (include "etcd.jobsTagKubeVersion" .) }}
command:
- kubectl
- --namespace={{ .Release.Namespace }}
- delete
- secret
- --ignore-not-found=true
- {{ include "etcd.caSecretName" . }}
- {{ include "etcd.clientSecretName" . }}
{{- with .Values.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- end }}

View File

@@ -1,74 +0,0 @@
{{- if .Values.etcd.deploy }}
apiVersion: batch/v1
kind: Job
metadata:
labels:
{{- include "etcd.labels" . | nindent 4 }}
annotations:
"helm.sh/hook": post-install
"helm.sh/hook-weight": "-5"
"helm.sh/hook-delete-policy": "hook-succeeded,hook-failed"
name: "{{ .Release.Name }}-etcd-setup"
namespace: {{ .Release.Namespace }}
spec:
template:
metadata:
name: "{{ .Release.Name }}"
spec:
serviceAccountName: {{ include "etcd.serviceAccountName" . }}
restartPolicy: Never
initContainers:
- name: kubectl
image: {{ printf "clastix/kubectl:%s" (include "etcd.jobsTagKubeVersion" .) }}
command:
- sh
- -c
- |-
kubectl --namespace={{ .Release.Namespace }} rollout status sts/etcd --timeout=300s
containers:
- command:
- bash
- -c
- |-
etcdctl member list -w table
if etcdctl user get root &>/dev/null; then
echo "User already exists, nothing to do"
else
etcdctl user add --no-password=true root &&
etcdctl role add root &&
etcdctl user grant-role root root &&
etcdctl auth enable
fi
env:
- name: ETCDCTL_ENDPOINTS
value: https://etcd-0.{{ include "etcd.serviceName" . }}.{{ .Release.Namespace }}.svc.cluster.local:2379
- name: ETCDCTL_CACERT
value: /opt/certs/ca/ca.crt
- name: ETCDCTL_CERT
value: /opt/certs/root-certs/tls.crt
- name: ETCDCTL_KEY
value: /opt/certs/root-certs/tls.key
image: quay.io/coreos/etcd:v3.5.1
imagePullPolicy: Always
name: etcd-client
volumeMounts:
- name: root-certs
mountPath: /opt/certs/root-certs
- name: certs
mountPath: /opt/certs/ca
securityContext:
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
volumes:
- name: root-certs
secret:
secretName: {{ include "etcd.clientSecretName" . }}
- name: certs
secret:
secretName: {{ include "etcd.caSecretName" . }}
{{- with .Values.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- end }}

View File

@@ -1,72 +0,0 @@
{{- if .Values.etcd.deploy }}
apiVersion: batch/v1
kind: Job
metadata:
labels:
{{- include "etcd.labels" . | nindent 4 }}
annotations:
"helm.sh/hook": pre-install
"helm.sh/hook-weight": "-5"
"helm.sh/hook-delete-policy": "hook-succeeded"
name: "{{ .Release.Name }}-etcd-certs"
namespace: {{ .Release.Namespace }}
spec:
template:
metadata:
name: "{{ .Release.Name }}"
spec:
serviceAccountName: {{ include "etcd.serviceAccountName" . }}
restartPolicy: Never
initContainers:
- name: cfssl
image: "{{ .Values.cfssl.image.repository }}:{{ .Values.cfssl.image.tag }}"
command:
- bash
- -c
- |-
cfssl gencert -initca /csr/ca-csr.json | cfssljson -bare /certs/ca &&
mv /certs/ca.pem /certs/ca.crt && mv /certs/ca-key.pem /certs/ca.key &&
cfssl gencert -ca=/certs/ca.crt -ca-key=/certs/ca.key -config=/csr/config.json -profile=peer-authentication /csr/peer-csr.json | cfssljson -bare /certs/peer &&
cfssl gencert -ca=/certs/ca.crt -ca-key=/certs/ca.key -config=/csr/config.json -profile=peer-authentication /csr/server-csr.json | cfssljson -bare /certs/server &&
cfssl gencert -ca=/certs/ca.crt -ca-key=/certs/ca.key -config=/csr/config.json -profile=client-authentication /csr/root-client-csr.json | cfssljson -bare /certs/root-client
volumeMounts:
- mountPath: /certs
name: certs
- mountPath: /csr
name: csr
containers:
- name: kubectl
image: {{ printf "clastix/kubectl:%s" (include "etcd.jobsTagKubeVersion" .) }}
command: ["/bin/sh", "-c"]
args:
- |
if kubectl get secret {{ include "etcd.caSecretName" . }} --namespace={{ .Release.Namespace }} &>/dev/null; then
echo "Secret {{ include "etcd.caSecretName" . }} already exists"
else
echo "Creating secret {{ include "etcd.caSecretName" . }}"
kubectl --namespace={{ .Release.Namespace }} create secret generic {{ include "etcd.caSecretName" . }} --from-file=/certs/ca.crt --from-file=/certs/ca.key --from-file=/certs/peer-key.pem --from-file=/certs/peer.pem --from-file=/certs/server-key.pem --from-file=/certs/server.pem
fi
if kubectl get secret {{ include "etcd.clientSecretName" . }} --namespace={{ .Release.Namespace }} &>/dev/null; then
echo "Secret {{ include "etcd.clientSecretName" . }} already exists"
else
echo "Creating secret {{ include "etcd.clientSecretName" . }}"
kubectl --namespace={{ .Release.Namespace }} create secret tls {{ include "etcd.clientSecretName" . }} --key=/certs/root-client-key.pem --cert=/certs/root-client.pem
fi
volumeMounts:
- mountPath: /certs
name: certs
securityContext:
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
volumes:
- name: csr
configMap:
name: {{ include "etcd.csrConfigMapName" . }}
- name: certs
emptyDir: {}
{{- with .Values.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- end }}

View File

@@ -1,56 +0,0 @@
{{- if .Values.etcd.deploy }}
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
labels:
{{- include "etcd.labels" . | nindent 4 }}
name: etcd-gen-certs-role
annotations:
"helm.sh/hook": pre-install
"helm.sh/hook-weight": "-5"
namespace: {{ .Release.Namespace }}
rules:
- apiGroups:
- ""
resources:
- secrets
verbs:
- get
- delete
resourceNames:
- {{ include "etcd.caSecretName" . }}
- {{ include "etcd.clientSecretName" . }}
- apiGroups:
- ""
resources:
- secrets
verbs:
- create
- apiGroups:
- apps
resources:
- statefulsets
verbs:
- get
- list
- watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
labels:
{{- include "etcd.labels" . | nindent 4 }}
name: etcd-gen-certs-rolebiding
namespace: {{ .Release.Namespace }}
annotations:
"helm.sh/hook": pre-install
"helm.sh/hook-weight": "-5"
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: etcd-gen-certs-role
subjects:
- kind: ServiceAccount
name: {{ include "etcd.serviceAccountName" . }}
namespace: {{ .Release.Namespace }}
{{- end }}

View File

@@ -1,12 +0,0 @@
{{- if .Values.etcd.deploy }}
apiVersion: v1
kind: ServiceAccount
metadata:
labels:
{{- include "etcd.labels" . | nindent 4 }}
name: {{ include "etcd.serviceAccountName" . }}
annotations:
"helm.sh/hook": pre-install
"helm.sh/hook-weight": "-5"
namespace: {{ .Release.Namespace }}
{{- end }}

View File

@@ -1,18 +0,0 @@
{{- if .Values.etcd.deploy }}
apiVersion: v1
kind: Service
metadata:
labels:
{{- include "etcd.labels" . | nindent 4 }}
name: {{ include "etcd.serviceName" . }}
namespace: {{ .Release.Namespace }}
spec:
clusterIP: None
ports:
- port: {{ .Values.etcd.port }}
name: client
- port: {{ .Values.etcd.peerApiPort }}
name: peer
selector:
{{- include "etcd.selectorLabels" . | nindent 4 }}
{{- end }}

View File

@@ -1,101 +0,0 @@
{{- if .Values.etcd.deploy }}
apiVersion: apps/v1
kind: StatefulSet
metadata:
labels:
{{- include "etcd.labels" . | nindent 4 }}
name: {{ include "etcd.fullname" . }}
namespace: {{ .Release.Namespace }}
spec:
serviceName: {{ include "etcd.serviceName" . }}
selector:
matchLabels:
{{- include "etcd.selectorLabels" . | nindent 6 }}
replicas: 3
template:
metadata:
name: etcd
labels:
{{- include "etcd.selectorLabels" . | nindent 8 }}
spec:
volumes:
- name: certs
secret:
secretName: {{ include "etcd.caSecretName" . }}
{{- with .Values.etcd.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
containers:
- name: etcd
image: {{ .Values.etcd.image.repository }}:{{ .Values.etcd.image.tag | default "v3.5.4" }}
imagePullPolicy: {{ .Values.etcd.image.pullPolicy }}
ports:
- containerPort: 2379
name: client
- containerPort: 2380
name: peer
volumeMounts:
- name: data
mountPath: /var/run/etcd
- name: certs
mountPath: /etc/etcd/pki
command:
- etcd
- --data-dir=/var/run/etcd
- --name=$(POD_NAME)
- --initial-cluster-state=new
- --initial-cluster={{ include "etcd.initialCluster" . }}
- --initial-advertise-peer-urls=https://$(POD_NAME).etcd.$(POD_NAMESPACE).svc.cluster.local:2380
- --advertise-client-urls=https://$(POD_NAME).etcd.$(POD_NAMESPACE).svc.cluster.local:2379
- --initial-cluster-token=kamaji
- --listen-client-urls=https://0.0.0.0:2379
- --listen-metrics-urls=http://0.0.0.0:2381
- --listen-peer-urls=https://0.0.0.0:2380
- --client-cert-auth=true
- --peer-client-cert-auth=true
- --trusted-ca-file=/etc/etcd/pki/ca.crt
- --cert-file=/etc/etcd/pki/server.pem
- --key-file=/etc/etcd/pki/server-key.pem
- --peer-trusted-ca-file=/etc/etcd/pki/ca.crt
- --peer-cert-file=/etc/etcd/pki/peer.pem
- --peer-key-file=/etc/etcd/pki/peer-key.pem
- --auto-compaction-mode=periodic
- --auto-compaction-retention=5m
- --snapshot-count=10000
- --quota-backend-bytes=8589934592
- --v=8
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
{{- with .Values.etcd.livenessProbe }}
livenessProbe:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.etcd.startupProbe }}
startupProbe:
{{- toYaml . | nindent 12 }}
{{- end }}
volumeClaimTemplates:
- metadata:
name: data
{{- with .Values.etcd.persistence.customAnnotations }}
annotations:
{{- toYaml . | nindent 8 }}
{{- end }}
spec:
storageClassName: {{ .Values.etcd.persistence.storageClassName }}
accessModes:
{{- range .Values.etcd.persistence.accessModes }}
- {{ . | quote }}
{{- end }}
resources:
requests:
storage: {{ .Values.etcd.persistence.size }}
{{- end }}

View File

@@ -8,6 +8,27 @@ metadata:
{{- include "kamaji.labels" $data | nindent 4 }}
name: kamaji-validating-webhook-configuration
webhooks:
- admissionReviewVersions:
- v1
clientConfig:
service:
name: {{ include "kamaji.webhookServiceName" . }}
namespace: {{ .Release.Namespace }}
path: /telemetry
failurePolicy: Ignore
name: telemetry.kamaji.clastix.io
rules:
- apiGroups:
- kamaji.clastix.io
apiVersions:
- v1alpha1
operations:
- CREATE
- UPDATE
- DELETE
resources:
- tenantcontrolplanes
sideEffects: None
- admissionReviewVersions:
- v1
clientConfig:

View File

@@ -15,74 +15,10 @@ image:
# -- A list of extra arguments to add to the kamaji controller default ones
extraArgs: []
serviceMonitor:
# -- Toggle the ServiceMonitor true if you have Prometheus Operator installed and configured
enabled: false
etcd:
# -- Install an etcd with enabled multi-tenancy along with Kamaji
deploy: true
# -- The peer API port which servers are listening to.
peerApiPort: 2380
# -- The client request port.
port: 2379
# -- Install specific etcd image
image:
repository: quay.io/coreos/etcd
tag: "v3.5.6"
pullPolicy: IfNotPresent
# -- The livenessProbe for the etcd container
livenessProbe:
failureThreshold: 8
httpGet:
path: /health?serializable=true
port: 2381
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 10
timeoutSeconds: 15
serviceAccount:
# -- Create a ServiceAccount, required to install and provision the etcd backing storage (default: true)
create: true
# -- Define the ServiceAccount name to use during the setup and provision of the etcd backing storage (default: "")
name: ""
persistence:
size: 10Gi
storageClassName: ""
accessModes:
- ReadWriteOnce
# -- The custom annotations to add to the PVC
customAnnotations: {}
# volumeType: local
# -- (array) Kubernetes affinity rules to apply to Kamaji etcd pods
tolerations: []
overrides:
caSecret:
# -- Name of the secret which contains CA's certificate and private key. (default: "etcd-certs")
name: etcd-certs
# -- Namespace of the secret which contains CA's certificate and private key. (default: "kamaji-system")
namespace: kamaji-system
clientSecret:
# -- Name of the secret which contains ETCD client certificates. (default: "root-client-certs")
name: root-client-certs
# -- Name of the namespace where the secret which contains ETCD client certificates is. (default: "kamaji-system")
namespace: kamaji-system
# -- (map) Dictionary of the endpoints for the etcd cluster's members, key is the name of the etcd server. Don't define the protocol (TLS is automatically inflected), or any port, inflected from .etcd.peerApiPort value.
endpoints:
etcd-0: etcd-0.etcd.kamaji-system.svc.cluster.local
etcd-1: etcd-1.etcd.kamaji-system.svc.cluster.local
etcd-2: etcd-2.etcd.kamaji-system.svc.cluster.local
# -- ETCD Compaction interval (e.g. "5m0s"). (default: "0" (disabled))
compactionInterval: 0
# -- The address the probe endpoint binds to. (default ":8081")
healthProbeBindAddress: ":8081"
@@ -102,7 +38,7 @@ readinessProbe:
initialDelaySeconds: 5
periodSeconds: 10
# -- (string) The address the metric endpoint binds to. (default ":8080")
# -- The address the metric endpoint binds to. (default ":8080")
metricsBindAddress: ":8080"
imagePullSecrets: []
@@ -156,66 +92,20 @@ affinity: {}
temporaryDirectoryPath: "/tmp/kamaji"
loggingDevel:
# -- (string) Development Mode defaults(encoder=consoleEncoder,logLevel=Debug,stackTraceLevel=Warn). Production Mode defaults(encoder=jsonEncoder,logLevel=Info,stackTraceLevel=Error) (default false)
# -- Development Mode defaults(encoder=consoleEncoder,logLevel=Debug,stackTraceLevel=Warn). Production Mode defaults(encoder=jsonEncoder,logLevel=Info,stackTraceLevel=Error) (default false)
enable: false
datastore:
# -- (bool) Enable the Kamaji Datastore creation (default=true)
enabled: true
# -- (string) The Datastore name override, if empty and enabled=true defaults to `default`, if enabled=false, this is the name of the Datastore to connect to.
nameOverride:
# -- (string) The Kamaji Datastore driver, supported: etcd, MySQL, PostgreSQL (defaults=etcd).
driver: etcd
# -- (array) List of endpoints of the selected Datastore. When letting the Chart install the etcd datastore, this field is populated automatically.
endpoints: []
basicAuth:
usernameSecret:
# -- The name of the Secret containing the username used to connect to the relational database.
name:
# -- The namespace of the Secret containing the username used to connect to the relational database.
namespace:
# -- The Secret key where the data is stored.
keyPath:
passwordSecret:
# -- The name of the Secret containing the password used to connect to the relational database.
name:
# -- The namespace of the Secret containing the password used to connect to the relational database.
namespace:
# -- The Secret key where the data is stored.
keyPath:
tlsConfig:
certificateAuthority:
certificate:
# -- Name of the Secret containing the CA required to establish the mandatory SSL/TLS connection to the datastore.
name:
# -- Namespace of the Secret containing the CA required to establish the mandatory SSL/TLS connection to the datastore.
namespace:
# -- Key of the Secret which contains the content of the certificate.
keyPath:
privateKey:
# -- Name of the Secret containing the CA private key required to establish the mandatory SSL/TLS connection to the datastore.
name:
# -- Namespace of the Secret containing the CA private key required to establish the mandatory SSL/TLS connection to the datastore.
namespace:
# -- Key of the Secret which contains the content of the private key.
keyPath:
clientCertificate:
certificate:
# -- Name of the Secret containing the client certificate required to establish the mandatory SSL/TLS connection to the datastore.
name:
# -- Namespace of the Secret containing the client certificate required to establish the mandatory SSL/TLS connection to the datastore.
namespace:
# -- Key of the Secret which contains the content of the certificate.
keyPath:
privateKey:
# -- Name of the Secret containing the client certificate private key required to establish the mandatory SSL/TLS connection to the datastore.
name:
# -- Namespace of the Secret containing the client certificate private key required to establish the mandatory SSL/TLS connection to the datastore.
namespace:
# -- Key of the Secret which contains the content of the private key.
keyPath:
# -- Specify the default DataStore name for the Kamaji instance.
defaultDatastoreName: default
cfssl:
image:
repository: cfssl/cfssl
tag: latest
kamaji-etcd:
deploy: true
fullnameOverride: kamaji-etcd
datastore:
enabled: true
name: default
# -- Disable the analytics traces collection
telemetry:
disabled: false

View File

@@ -7,10 +7,12 @@ import (
"flag"
"fmt"
"io"
"net/http"
"os"
goRuntime "runtime"
"time"
telemetryclient "github.com/clastix/kamaji-telemetry/pkg/client"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"k8s.io/apimachinery/pkg/runtime"
@@ -53,6 +55,7 @@ func NewCmd(scheme *runtime.Scheme) *cobra.Command {
webhookCABundle []byte
migrateJobImage string
maxConcurrentReconciles int
disableTelemetry bool
webhookCAPath string
)
@@ -95,8 +98,14 @@ func NewCmd(scheme *runtime.Scheme) *cobra.Command {
setupLog.Info(fmt.Sprintf("Build date: %s", internal.BuildTime))
setupLog.Info(fmt.Sprintf("Go Version: %s", goRuntime.Version()))
setupLog.Info(fmt.Sprintf("Go OS/Arch: %s/%s", goRuntime.GOOS, goRuntime.GOARCH))
setupLog.Info(fmt.Sprintf("Telemetry enabled: %t", !disableTelemetry))
mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
telemetryClient := telemetryclient.New(http.Client{Timeout: 5 * time.Second}, "https://telemetry.clastix.io")
if disableTelemetry {
telemetryClient = telemetryclient.NewNewOp()
}
ctrlOpts := ctrl.Options{
Scheme: scheme,
Metrics: metricsserver.Options{
BindAddress: metricsBindAddress,
@@ -107,13 +116,15 @@ func NewCmd(scheme *runtime.Scheme) *cobra.Command {
HealthProbeBindAddress: healthProbeBindAddress,
LeaderElection: leaderElect,
LeaderElectionNamespace: managerNamespace,
LeaderElectionID: "799b98bc.clastix.io",
LeaderElectionID: "kamaji.clastix.io",
NewCache: func(config *rest.Config, opts cache.Options) (cache.Cache, error) {
opts.SyncPeriod = &cacheResyncPeriod
return cache.New(config, opts)
},
})
}
mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrlOpts)
if err != nil {
setupLog.Error(err, "unable to start manager")
@@ -152,6 +163,29 @@ func NewCmd(scheme *runtime.Scheme) *cobra.Command {
return err
}
k8sVersion, versionErr := cmdutils.KubernetesVersion(mgr.GetConfig())
if versionErr != nil {
setupLog.Error(err, "unable to get kubernetes version")
k8sVersion = "Unknown"
}
if !disableTelemetry {
err = mgr.Add(&controllers.TelemetryController{
Client: mgr.GetClient(),
KubernetesVersion: k8sVersion,
KamajiVersion: internal.GitTag,
TelemetryClient: telemetryClient,
LeaderElectionNamespace: ctrlOpts.LeaderElectionNamespace,
LeaderElectionID: ctrlOpts.LeaderElectionID,
})
if err != nil {
setupLog.Error(err, "unable to create controller", "controller", "TelemetryController")
return err
}
}
if err = (&controllers.CertificateLifecycle{Channel: certChannel}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "CertificateLifecycle")
@@ -175,7 +209,9 @@ func NewCmd(scheme *runtime.Scheme) *cobra.Command {
handlers.Freeze{},
},
routes.TenantControlPlaneDefaults{}: {
handlers.TenantControlPlaneDefaults{DefaultDatastore: datastore},
handlers.TenantControlPlaneDefaults{
DefaultDatastore: datastore,
},
},
routes.TenantControlPlaneValidate{}: {
handlers.TenantControlPlaneName{},
@@ -192,6 +228,15 @@ func NewCmd(scheme *runtime.Scheme) *cobra.Command {
Scheme: *mgr.GetScheme(),
},
},
handlers.TenantControlPlaneServiceCIDR{},
},
routes.TenantControlPlaneTelemetry{}: {
handlers.TenantControlPlaneTelemetry{
Enabled: !disableTelemetry,
TelemetryClient: telemetryClient,
KamajiVersion: internal.GitTag,
KubernetesVersion: k8sVersion,
},
},
routes.DataStoreValidate{}: {
handlers.DataStoreValidation{Client: mgr.GetClient()},
@@ -252,7 +297,7 @@ func NewCmd(scheme *runtime.Scheme) *cobra.Command {
cmd.Flags().StringVar(&healthProbeBindAddress, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.")
cmd.Flags().BoolVar(&leaderElect, "leader-elect", true, "Enable leader election for controller manager. Enabling this will ensure there is only one active controller manager.")
cmd.Flags().StringVar(&tmpDirectory, "tmp-directory", "/tmp/kamaji", "Directory which will be used to work with temporary files.")
cmd.Flags().StringVar(&kineImage, "kine-image", "rancher/kine:v0.9.2-amd64", "Container image along with tag to use for the Kine sidecar container (used only if etcd-storage-type is set to one of kine strategies).")
cmd.Flags().StringVar(&kineImage, "kine-image", "rancher/kine:v0.11.10-amd64", "Container image along with tag to use for the Kine sidecar container (used only if etcd-storage-type is set to one of kine strategies).")
cmd.Flags().StringVar(&datastore, "datastore", "etcd", "The default DataStore that should be used by Kamaji to setup the required storage.")
cmd.Flags().StringVar(&migrateJobImage, "migrate-image", fmt.Sprintf("clastix/kamaji:%s", internal.GitTag), "Specify the container image to launch when a TenantControlPlane is migrated to a new datastore.")
cmd.Flags().IntVar(&maxConcurrentReconciles, "max-concurrent-tcp-reconciles", 1, "Specify the number of workers for the Tenant Control Plane controller (beware of CPU consumption)")
@@ -262,6 +307,7 @@ func NewCmd(scheme *runtime.Scheme) *cobra.Command {
cmd.Flags().StringVar(&webhookCAPath, "webhook-ca-path", "/tmp/k8s-webhook-server/serving-certs/ca.crt", "Path to the Manager webhook server CA, required for the TenantControlPlane migration jobs.")
cmd.Flags().DurationVar(&controllerReconcileTimeout, "controller-reconcile-timeout", 30*time.Second, "The reconciliation request timeout before the controller withdraw the external resource calls, such as dealing with the Datastore, or the Tenant Control Plane API endpoint.")
cmd.Flags().DurationVar(&cacheResyncPeriod, "cache-resync-period", 10*time.Hour, "The controller-runtime.Manager cache resync period.")
cmd.Flags().BoolVar(&disableTelemetry, "disable-telemetry", false, "Disable the analytics traces collection.")
cobra.OnInitialize(func() {
viper.AutomaticEnv()

24
cmd/utils/k8s_version.go Normal file
View File

@@ -0,0 +1,24 @@
// Copyright 2022 Clastix Labs
// SPDX-License-Identifier: Apache-2.0
package utils
import (
"github.com/pkg/errors"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
)
func KubernetesVersion(config *rest.Config) (string, error) {
cs, csErr := kubernetes.NewForConfig(config)
if csErr != nil {
return "", errors.Wrap(csErr, "cannot create kubernetes clientset")
}
sv, svErr := cs.ServerVersion()
if svErr != nil {
return "", errors.Wrap(svErr, "cannot get Kubernetes version")
}
return sv.GitVersion, nil
}

View File

@@ -121,6 +121,7 @@ spec:
- etcd
- MySQL
- PostgreSQL
- NATS
type: string
endpoints:
description: |-
@@ -131,8 +132,9 @@ spec:
minItems: 1
type: array
tlsConfig:
description: Defines the TLS/SSL configuration required to connect
to the data store in a secure way.
description: |-
Defines the TLS/SSL configuration required to connect to the data store in a secure way.
This value is optional.
properties:
certificateAuthority:
description: |-
@@ -268,12 +270,10 @@ spec:
type: object
required:
- certificateAuthority
- clientCertificate
type: object
required:
- driver
- endpoints
- tlsConfig
type: object
status:
description: DataStoreStatus defines the observed state of DataStore.

View File

@@ -8,6 +8,8 @@ metadata:
spec:
group: kamaji.clastix.io
names:
categories:
- kamaji
kind: TenantControlPlane
listKind: TenantControlPlaneList
plural: tenantcontrolplanes
@@ -93,7 +95,7 @@ spec:
agent:
default:
image: registry.k8s.io/kas-network-proxy/proxy-agent
version: v0.0.32
version: v0.28.6
properties:
extraArgs:
description: |-
@@ -109,8 +111,52 @@ spec:
description: AgentImage defines the container image for
Konnectivity's agent.
type: string
tolerations:
default:
- key: CriticalAddonsOnly
operator: Exists
description: |-
Tolerations for the deployed agent.
Can be customized to start the konnectivity-agent even if the nodes are not ready or tainted.
items:
description: |-
The pod this Toleration is attached to tolerates any taint that matches
the triple <key,value,effect> using the matching operator <operator>.
properties:
effect:
description: |-
Effect indicates the taint effect to match. Empty means match all taint effects.
When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute.
type: string
key:
description: |-
Key is the taint key that the toleration applies to. Empty means match all taint keys.
If the key is empty, operator must be Exists; this combination means to match all values and all keys.
type: string
operator:
description: |-
Operator represents a key's relationship to the value.
Valid operators are Exists and Equal. Defaults to Equal.
Exists is equivalent to wildcard for value, so that a pod can
tolerate all taints of a particular category.
type: string
tolerationSeconds:
description: |-
TolerationSeconds represents the period of time the toleration (which must be
of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default,
it is not set, which means tolerate the taint forever (do not evict). Zero and
negative values will be treated as 0 (evict immediately) by the system.
format: int64
type: integer
value:
description: |-
Value is the taint value the toleration matches to.
If the operator is Exists, the value should be empty, otherwise just a regular string.
type: string
type: object
type: array
version:
default: v0.0.32
default: v0.28.6
description: Version for Konnectivity agent.
type: string
type: object
@@ -118,7 +164,7 @@ spec:
default:
image: registry.k8s.io/kas-network-proxy/proxy-server
port: 8132
version: v0.0.32
version: v0.28.6
properties:
extraArgs:
description: |-
@@ -197,7 +243,7 @@ spec:
type: object
type: object
version:
default: v0.0.32
default: v0.28.6
description: Container image version of the Konnectivity
server.
type: string
@@ -301,10 +347,15 @@ spec:
description: The key to select.
type: string
name:
default: ""
description: |-
Name of the referent.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
TODO: Add other useful fields. apiVersion, kind, uid?
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
type: string
optional:
description: Specify whether the ConfigMap
@@ -367,10 +418,15 @@ spec:
key.
type: string
name:
default: ""
description: |-
Name of the referent.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
TODO: Add other useful fields. apiVersion, kind, uid?
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
type: string
optional:
description: Specify whether the Secret
@@ -404,10 +460,15 @@ spec:
description: The ConfigMap to select from
properties:
name:
default: ""
description: |-
Name of the referent.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
TODO: Add other useful fields. apiVersion, kind, uid?
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
type: string
optional:
description: Specify whether the ConfigMap
@@ -423,10 +484,15 @@ spec:
description: The Secret to select from
properties:
name:
default: ""
description: |-
Name of the referent.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
TODO: Add other useful fields. apiVersion, kind, uid?
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
type: string
optional:
description: Specify whether the Secret must
@@ -1727,10 +1793,15 @@ spec:
description: The key to select.
type: string
name:
default: ""
description: |-
Name of the referent.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
TODO: Add other useful fields. apiVersion, kind, uid?
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
type: string
optional:
description: Specify whether the ConfigMap
@@ -1793,10 +1864,15 @@ spec:
key.
type: string
name:
default: ""
description: |-
Name of the referent.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
TODO: Add other useful fields. apiVersion, kind, uid?
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
type: string
optional:
description: Specify whether the Secret
@@ -1830,10 +1906,15 @@ spec:
description: The ConfigMap to select from
properties:
name:
default: ""
description: |-
Name of the referent.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
TODO: Add other useful fields. apiVersion, kind, uid?
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
type: string
optional:
description: Specify whether the ConfigMap
@@ -1849,10 +1930,15 @@ spec:
description: The Secret to select from
properties:
name:
default: ""
description: |-
Name of the referent.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
TODO: Add other useful fields. apiVersion, kind, uid?
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
type: string
optional:
description: Specify whether the Secret must
@@ -3438,10 +3524,15 @@ spec:
More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it
properties:
name:
default: ""
description: |-
Name of the referent.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
TODO: Add other useful fields. apiVersion, kind, uid?
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
type: string
type: object
x-kubernetes-map-type: atomic
@@ -3477,10 +3568,15 @@ spec:
to OpenStack.
properties:
name:
default: ""
description: |-
Name of the referent.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
TODO: Add other useful fields. apiVersion, kind, uid?
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
type: string
type: object
x-kubernetes-map-type: atomic
@@ -3547,10 +3643,15 @@ spec:
type: array
x-kubernetes-list-type: atomic
name:
default: ""
description: |-
Name of the referent.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
TODO: Add other useful fields. apiVersion, kind, uid?
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
type: string
optional:
description: optional specify whether the ConfigMap
@@ -3583,10 +3684,15 @@ spec:
secret object contains more than one secret, all secret references are passed.
properties:
name:
default: ""
description: |-
Name of the referent.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
TODO: Add other useful fields. apiVersion, kind, uid?
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
type: string
type: object
x-kubernetes-map-type: atomic
@@ -4068,10 +4174,15 @@ spec:
scripts.
properties:
name:
default: ""
description: |-
Name of the referent.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
TODO: Add other useful fields. apiVersion, kind, uid?
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
type: string
type: object
x-kubernetes-map-type: atomic
@@ -4263,10 +4374,15 @@ spec:
target and initiator authentication
properties:
name:
default: ""
description: |-
Name of the referent.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
TODO: Add other useful fields. apiVersion, kind, uid?
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
type: string
type: object
x-kubernetes-map-type: atomic
@@ -4531,10 +4647,15 @@ spec:
type: array
x-kubernetes-list-type: atomic
name:
default: ""
description: |-
Name of the referent.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
TODO: Add other useful fields. apiVersion, kind, uid?
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
type: string
optional:
description: optional specify whether
@@ -4670,10 +4791,15 @@ spec:
type: array
x-kubernetes-list-type: atomic
name:
default: ""
description: |-
Name of the referent.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
TODO: Add other useful fields. apiVersion, kind, uid?
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
type: string
optional:
description: optional field specify whether
@@ -4804,10 +4930,15 @@ spec:
More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it
properties:
name:
default: ""
description: |-
Name of the referent.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
TODO: Add other useful fields. apiVersion, kind, uid?
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
type: string
type: object
x-kubernetes-map-type: atomic
@@ -4851,10 +4982,15 @@ spec:
sensitive information. If this is not provided, Login operation will fail.
properties:
name:
default: ""
description: |-
Name of the referent.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
TODO: Add other useful fields. apiVersion, kind, uid?
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
type: string
type: object
x-kubernetes-map-type: atomic
@@ -4971,10 +5107,15 @@ spec:
credentials. If not specified, default values will be attempted.
properties:
name:
default: ""
description: |-
Name of the referent.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
TODO: Add other useful fields. apiVersion, kind, uid?
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
type: string
type: object
x-kubernetes-map-type: atomic
@@ -5991,6 +6132,20 @@ spec:
Selector which must match a node's labels for the pod to be scheduled on that node.
More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/
type: object
podAdditionalMetadata:
description: AdditionalMetadata defines which additional metadata,
such as labels and annotations, must be attached to the
created resource.
properties:
annotations:
additionalProperties:
type: string
type: object
labels:
additionalProperties:
type: string
type: object
type: object
registrySettings:
default:
apiServerImage: kube-apiserver
@@ -6266,6 +6421,11 @@ spec:
empty definition that uses the default runtime handler.
More info: https://git.k8s.io/enhancements/keps/sig-node/585-runtime-class
type: string
serviceAccountName:
default: default
description: ServiceAccountName allows to specify the service
account to be mounted to the pods of the Control plane deployment
type: string
strategy:
default:
rollingUpdate:

View File

@@ -127,6 +127,7 @@ spec:
- etcd
- MySQL
- PostgreSQL
- NATS
type: string
endpoints:
description: |-
@@ -137,7 +138,9 @@ spec:
minItems: 1
type: array
tlsConfig:
description: Defines the TLS/SSL configuration required to connect to the data store in a secure way.
description: |-
Defines the TLS/SSL configuration required to connect to the data store in a secure way.
This value is optional.
properties:
certificateAuthority:
description: |-
@@ -264,12 +267,10 @@ spec:
type: object
required:
- certificateAuthority
- clientCertificate
type: object
required:
- driver
- endpoints
- tlsConfig
type: object
status:
description: DataStoreStatus defines the observed state of DataStore.
@@ -308,6 +309,8 @@ spec:
- v1
group: kamaji.clastix.io
names:
categories:
- kamaji
kind: TenantControlPlane
listKind: TenantControlPlaneList
plural: tenantcontrolplanes
@@ -391,7 +394,7 @@ spec:
agent:
default:
image: registry.k8s.io/kas-network-proxy/proxy-agent
version: v0.0.32
version: v0.28.6
properties:
extraArgs:
description: |-
@@ -406,8 +409,52 @@ spec:
default: registry.k8s.io/kas-network-proxy/proxy-agent
description: AgentImage defines the container image for Konnectivity's agent.
type: string
tolerations:
default:
- key: CriticalAddonsOnly
operator: Exists
description: |-
Tolerations for the deployed agent.
Can be customized to start the konnectivity-agent even if the nodes are not ready or tainted.
items:
description: |-
The pod this Toleration is attached to tolerates any taint that matches
the triple <key,value,effect> using the matching operator <operator>.
properties:
effect:
description: |-
Effect indicates the taint effect to match. Empty means match all taint effects.
When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute.
type: string
key:
description: |-
Key is the taint key that the toleration applies to. Empty means match all taint keys.
If the key is empty, operator must be Exists; this combination means to match all values and all keys.
type: string
operator:
description: |-
Operator represents a key's relationship to the value.
Valid operators are Exists and Equal. Defaults to Equal.
Exists is equivalent to wildcard for value, so that a pod can
tolerate all taints of a particular category.
type: string
tolerationSeconds:
description: |-
TolerationSeconds represents the period of time the toleration (which must be
of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default,
it is not set, which means tolerate the taint forever (do not evict). Zero and
negative values will be treated as 0 (evict immediately) by the system.
format: int64
type: integer
value:
description: |-
Value is the taint value the toleration matches to.
If the operator is Exists, the value should be empty, otherwise just a regular string.
type: string
type: object
type: array
version:
default: v0.0.32
default: v0.28.6
description: Version for Konnectivity agent.
type: string
type: object
@@ -415,7 +462,7 @@ spec:
default:
image: registry.k8s.io/kas-network-proxy/proxy-server
port: 8132
version: v0.0.32
version: v0.28.6
properties:
extraArgs:
description: |-
@@ -490,7 +537,7 @@ spec:
type: object
type: object
version:
default: v0.0.32
default: v0.28.6
description: Container image version of the Konnectivity server.
type: string
required:
@@ -587,10 +634,15 @@ spec:
description: The key to select.
type: string
name:
default: ""
description: |-
Name of the referent.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
TODO: Add other useful fields. apiVersion, kind, uid?
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
type: string
optional:
description: Specify whether the ConfigMap or its key must be defined
@@ -643,10 +695,15 @@ spec:
description: The key of the secret to select from. Must be a valid secret key.
type: string
name:
default: ""
description: |-
Name of the referent.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
TODO: Add other useful fields. apiVersion, kind, uid?
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
type: string
optional:
description: Specify whether the Secret or its key must be defined
@@ -678,10 +735,15 @@ spec:
description: The ConfigMap to select from
properties:
name:
default: ""
description: |-
Name of the referent.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
TODO: Add other useful fields. apiVersion, kind, uid?
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
type: string
optional:
description: Specify whether the ConfigMap must be defined
@@ -695,10 +757,15 @@ spec:
description: The Secret to select from
properties:
name:
default: ""
description: |-
Name of the referent.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
TODO: Add other useful fields. apiVersion, kind, uid?
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
type: string
optional:
description: Specify whether the Secret must be defined
@@ -1941,10 +2008,15 @@ spec:
description: The key to select.
type: string
name:
default: ""
description: |-
Name of the referent.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
TODO: Add other useful fields. apiVersion, kind, uid?
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
type: string
optional:
description: Specify whether the ConfigMap or its key must be defined
@@ -1997,10 +2069,15 @@ spec:
description: The key of the secret to select from. Must be a valid secret key.
type: string
name:
default: ""
description: |-
Name of the referent.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
TODO: Add other useful fields. apiVersion, kind, uid?
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
type: string
optional:
description: Specify whether the Secret or its key must be defined
@@ -2032,10 +2109,15 @@ spec:
description: The ConfigMap to select from
properties:
name:
default: ""
description: |-
Name of the referent.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
TODO: Add other useful fields. apiVersion, kind, uid?
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
type: string
optional:
description: Specify whether the ConfigMap must be defined
@@ -2049,10 +2131,15 @@ spec:
description: The Secret to select from
properties:
name:
default: ""
description: |-
Name of the referent.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
TODO: Add other useful fields. apiVersion, kind, uid?
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
type: string
optional:
description: Specify whether the Secret must be defined
@@ -3565,10 +3652,15 @@ spec:
More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it
properties:
name:
default: ""
description: |-
Name of the referent.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
TODO: Add other useful fields. apiVersion, kind, uid?
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
type: string
type: object
x-kubernetes-map-type: atomic
@@ -3604,10 +3696,15 @@ spec:
to OpenStack.
properties:
name:
default: ""
description: |-
Name of the referent.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
TODO: Add other useful fields. apiVersion, kind, uid?
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
type: string
type: object
x-kubernetes-map-type: atomic
@@ -3672,10 +3769,15 @@ spec:
type: array
x-kubernetes-list-type: atomic
name:
default: ""
description: |-
Name of the referent.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
TODO: Add other useful fields. apiVersion, kind, uid?
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
type: string
optional:
description: optional specify whether the ConfigMap or its keys must be defined
@@ -3705,10 +3807,15 @@ spec:
secret object contains more than one secret, all secret references are passed.
properties:
name:
default: ""
description: |-
Name of the referent.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
TODO: Add other useful fields. apiVersion, kind, uid?
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
type: string
type: object
x-kubernetes-map-type: atomic
@@ -4159,10 +4266,15 @@ spec:
scripts.
properties:
name:
default: ""
description: |-
Name of the referent.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
TODO: Add other useful fields. apiVersion, kind, uid?
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
type: string
type: object
x-kubernetes-map-type: atomic
@@ -4347,10 +4459,15 @@ spec:
description: secretRef is the CHAP Secret for iSCSI target and initiator authentication
properties:
name:
default: ""
description: |-
Name of the referent.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
TODO: Add other useful fields. apiVersion, kind, uid?
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
type: string
type: object
x-kubernetes-map-type: atomic
@@ -4601,10 +4718,15 @@ spec:
type: array
x-kubernetes-list-type: atomic
name:
default: ""
description: |-
Name of the referent.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
TODO: Add other useful fields. apiVersion, kind, uid?
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
type: string
optional:
description: optional specify whether the ConfigMap or its keys must be defined
@@ -4715,10 +4837,15 @@ spec:
type: array
x-kubernetes-list-type: atomic
name:
default: ""
description: |-
Name of the referent.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
TODO: Add other useful fields. apiVersion, kind, uid?
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
type: string
optional:
description: optional field specify whether the Secret or its key must be defined
@@ -4845,10 +4972,15 @@ spec:
More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it
properties:
name:
default: ""
description: |-
Name of the referent.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
TODO: Add other useful fields. apiVersion, kind, uid?
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
type: string
type: object
x-kubernetes-map-type: atomic
@@ -4889,10 +5021,15 @@ spec:
sensitive information. If this is not provided, Login operation will fail.
properties:
name:
default: ""
description: |-
Name of the referent.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
TODO: Add other useful fields. apiVersion, kind, uid?
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
type: string
type: object
x-kubernetes-map-type: atomic
@@ -5003,10 +5140,15 @@ spec:
credentials. If not specified, default values will be attempted.
properties:
name:
default: ""
description: |-
Name of the referent.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
TODO: Add other useful fields. apiVersion, kind, uid?
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
type: string
type: object
x-kubernetes-map-type: atomic
@@ -5966,6 +6108,18 @@ spec:
Selector which must match a node's labels for the pod to be scheduled on that node.
More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/
type: object
podAdditionalMetadata:
description: AdditionalMetadata defines which additional metadata, such as labels and annotations, must be attached to the created resource.
properties:
annotations:
additionalProperties:
type: string
type: object
labels:
additionalProperties:
type: string
type: object
type: object
registrySettings:
default:
apiServerImage: kube-apiserver
@@ -6234,6 +6388,10 @@ spec:
empty definition that uses the default runtime handler.
More info: https://git.k8s.io/enhancements/keps/sig-node/585-runtime-class
type: string
serviceAccountName:
default: default
description: ServiceAccountName allows to specify the service account to be mounted to the pods of the Control plane deployment
type: string
strategy:
default:
rollingUpdate:
@@ -7858,7 +8016,7 @@ spec:
valueFrom:
fieldRef:
fieldPath: spec.serviceAccountName
image: clastix/kamaji:v0.5.1
image: clastix/kamaji:v1.0.0
imagePullPolicy: Always
livenessProbe:
httpGet:
@@ -8050,6 +8208,27 @@ metadata:
cluster.x-k8s.io/provider: kamaji-core
name: kamaji-validating-webhook-configuration
webhooks:
- admissionReviewVersions:
- v1
clientConfig:
service:
name: kamaji-webhook-service
namespace: kamaji-system
path: /telemetry
failurePolicy: Ignore
name: telemetry.kamaji.clastix.io
rules:
- apiGroups:
- kamaji.clastix.io
apiVersions:
- v1alpha1
operations:
- CREATE
- UPDATE
- DELETE
resources:
- tenantcontrolplanes
sideEffects: None
- admissionReviewVersions:
- v1
clientConfig:

View File

@@ -13,4 +13,4 @@ kind: Kustomization
images:
- name: controller
newName: clastix/kamaji
newTag: v0.5.1
newTag: v1.0.0

View File

@@ -0,0 +1,34 @@
apiVersion: kamaji.clastix.io/v1alpha1
kind: DataStore
metadata:
name: nats-bronze
spec:
driver: NATS
endpoints:
- bronze-nats.nats-system.svc:4222
basicAuth:
username:
content: YWRtaW4=
password:
secretReference:
name: nats-bronze-config
namespace: nats-system
keyPath: password
tlsConfig:
certificateAuthority:
certificate:
secretReference:
name: nats-bronze-config
namespace: nats-system
keyPath: ca.crt
clientCertificate:
certificate:
secretReference:
name: nats-bronze-config
namespace: nats-system
keyPath: server.crt
privateKey:
secretReference:
name: nats-bronze-config
namespace: nats-system
keyPath: server.key

View File

@@ -0,0 +1,34 @@
apiVersion: kamaji.clastix.io/v1alpha1
kind: DataStore
metadata:
name: nats-gold
spec:
driver: NATS
endpoints:
- nats-gold.nats-system.svc:4222
basicAuth:
username:
content: YWRtaW4=
password:
secretReference:
name: nats-gold-config
namespace: nats-system
keyPath: password
tlsConfig:
certificateAuthority:
certificate:
secretReference:
name: nats-gold-config
namespace: nats-system
keyPath: ca.crt
clientCertificate:
certificate:
secretReference:
name: nats-gold-config
namespace: nats-system
keyPath: server.crt
privateKey:
secretReference:
name: nats-gold-config
namespace: nats-system
keyPath: server.key

View File

@@ -0,0 +1,17 @@
apiVersion: kamaji.clastix.io/v1alpha1
kind: DataStore
metadata:
name: nats-notls
spec:
driver: NATS
endpoints:
- notls-nats.nats-system.svc:4222
basicAuth:
username:
content: YWRtaW4=
password:
secretReference:
name: nats-notls-config
namespace: nats-system
keyPath: password

View File

@@ -0,0 +1,34 @@
apiVersion: kamaji.clastix.io/v1alpha1
kind: DataStore
metadata:
name: nats-silver
spec:
driver: NATS
endpoints:
- nats-silver.nats-system.svc:4222
basicAuth:
username:
content: YWRtaW4=
password:
secretReference:
name: nats-silver-config
namespace: nats-system
keyPath: password
tlsConfig:
certificateAuthority:
certificate:
secretReference:
name: nats-silver-config
namespace: nats-system
keyPath: ca.crt
clientCertificate:
certificate:
secretReference:
name: nats-silver-config
namespace: nats-system
keyPath: server.crt
privateKey:
secretReference:
name: nats-silver-config
namespace: nats-system
keyPath: server.key

View File

@@ -30,6 +30,27 @@ kind: ValidatingWebhookConfiguration
metadata:
name: validating-webhook-configuration
webhooks:
- admissionReviewVersions:
- v1
clientConfig:
service:
name: webhook-service
namespace: system
path: /telemetry
failurePolicy: Ignore
name: telemetry.kamaji.clastix.io
rules:
- apiGroups:
- kamaji.clastix.io
apiVersions:
- v1alpha1
operations:
- CREATE
- UPDATE
- DELETE
resources:
- tenantcontrolplanes
sideEffects: None
- admissionReviewVersions:
- v1
clientConfig:

View File

@@ -19,7 +19,6 @@ import (
"sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/predicate"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
"sigs.k8s.io/controller-runtime/pkg/source"
kamajiv1alpha1 "github.com/clastix/kamaji/api/v1alpha1"
)
@@ -98,7 +97,7 @@ func (r *DataStore) SetupWithManager(mgr controllerruntime.Manager) error {
For(&kamajiv1alpha1.DataStore{}, builder.WithPredicates(
predicate.ResourceVersionChangedPredicate{},
)).
WatchesRawSource(source.Kind(mgr.GetCache(), &kamajiv1alpha1.TenantControlPlane{}), handler.Funcs{
Watches(&kamajiv1alpha1.TenantControlPlane{}, handler.Funcs{
CreateFunc: func(_ context.Context, createEvent event.CreateEvent, limitingInterface workqueue.RateLimitingInterface) {
enqueueFn(createEvent.Object.(*kamajiv1alpha1.TenantControlPlane), limitingInterface)
},

View File

@@ -205,6 +205,9 @@ func getKubeconfigResources(c client.Client, tcpReconcilerConfig TenantControlPl
func getKubernetesStorageResources(c client.Client, dbConnection datastore.Connection, datastore kamajiv1alpha1.DataStore) []resources.Resource {
return []resources.Resource{
&ds.MultiTenancy{
DataStore: datastore,
},
&ds.Config{
Client: c,
ConnString: dbConnection.GetConnectionString(),

View File

@@ -79,7 +79,7 @@ func (c *CoreDNS) SetupWithManager(mgr manager.Manager) error {
For(&rbacv1.ClusterRoleBinding{}, builder.WithPredicates(predicate.NewPredicateFuncs(func(object client.Object) bool {
return object.GetName() == kubeadm.CoreDNSClusterRoleBindingName
}))).
WatchesRawSource(&source.Channel{Source: c.TriggerChannel}, &handler.EnqueueRequestForObject{}).
WatchesRawSource(source.Channel(c.TriggerChannel, &handler.EnqueueRequestForObject{})).
Owns(&rbacv1.ClusterRole{}).
Owns(&corev1.ServiceAccount{}).
Owns(&corev1.Service{}).

View File

@@ -80,7 +80,7 @@ func (k *KonnectivityAgent) SetupWithManager(mgr manager.Manager) error {
For(&appsv1.DaemonSet{}, builder.WithPredicates(predicate.NewPredicateFuncs(func(object client.Object) bool {
return object.GetName() == konnectivity.AgentName && object.GetNamespace() == konnectivity.AgentNamespace
}))).
WatchesRawSource(source.Kind(mgr.GetCache(), &corev1.ServiceAccount{}), handler.EnqueueRequestsFromMapFunc(func(_ context.Context, object client.Object) []reconcile.Request {
Watches(&corev1.ServiceAccount{}, handler.EnqueueRequestsFromMapFunc(func(_ context.Context, object client.Object) []reconcile.Request {
if object.GetName() == konnectivity.AgentName && object.GetNamespace() == konnectivity.AgentNamespace {
return []reconcile.Request{
{
@@ -94,7 +94,7 @@ func (k *KonnectivityAgent) SetupWithManager(mgr manager.Manager) error {
return nil
})).
WatchesRawSource(source.Kind(mgr.GetCache(), &v1.ClusterRoleBinding{}), handler.EnqueueRequestsFromMapFunc(func(_ context.Context, object client.Object) []reconcile.Request {
Watches(&v1.ClusterRoleBinding{}, handler.EnqueueRequestsFromMapFunc(func(_ context.Context, object client.Object) []reconcile.Request {
if object.GetName() == konnectivity.CertCommonName {
return []reconcile.Request{
{
@@ -107,6 +107,6 @@ func (k *KonnectivityAgent) SetupWithManager(mgr manager.Manager) error {
return nil
})).
WatchesRawSource(&source.Channel{Source: k.TriggerChannel}, &handler.EnqueueRequestForObject{}).
WatchesRawSource(source.Channel(k.TriggerChannel, &handler.EnqueueRequestForObject{})).
Complete(k)
}

View File

@@ -67,6 +67,6 @@ func (k *KubeadmPhase) SetupWithManager(mgr manager.Manager) error {
return controllerruntime.NewControllerManagedBy(mgr).
For(k.Phase.GetWatchedObject(), builder.WithPredicates(predicate.NewPredicateFuncs(k.Phase.GetPredicateFunc()))).
WatchesRawSource(&source.Channel{Source: k.TriggerChannel}, &handler.EnqueueRequestForObject{}).
WatchesRawSource(source.Channel(k.TriggerChannel, &handler.EnqueueRequestForObject{})).
Complete(k)
}

View File

@@ -79,7 +79,7 @@ func (k *KubeProxy) SetupWithManager(mgr manager.Manager) error {
For(&rbacv1.ClusterRoleBinding{}, builder.WithPredicates(predicate.NewPredicateFuncs(func(object client.Object) bool {
return object.GetName() == kubeadm.KubeProxyClusterRoleBindingName
}))).
WatchesRawSource(&source.Channel{Source: k.TriggerChannel}, &handler.EnqueueRequestForObject{}).
WatchesRawSource(source.Channel(k.TriggerChannel, &handler.EnqueueRequestForObject{})).
Owns(&corev1.ServiceAccount{}).
Owns(&rbacv1.Role{}).
Owns(&rbacv1.RoleBinding{}).

View File

@@ -187,7 +187,7 @@ func (m *Migrate) SetupWithManager(mgr manager.Manager) error {
return object.GetName() == vwc.GetName()
}))).
WatchesRawSource(&source.Channel{Source: m.TriggerChannel}, &handler.EnqueueRequestForObject{}).
WatchesRawSource(source.Channel(m.TriggerChannel, &handler.EnqueueRequestForObject{})).
Complete(m)
}

View File

@@ -302,7 +302,7 @@ func (m *Manager) SetupWithManager(mgr manager.Manager) error {
m.sootMap = make(map[string]sootItem)
return controllerruntime.NewControllerManagedBy(mgr).
WatchesRawSource(&source.Channel{Source: m.sootManagerErrChan}, &handler.EnqueueRequestForObject{}).
WatchesRawSource(source.Channel(m.sootManagerErrChan, &handler.EnqueueRequestForObject{})).
For(&kamajiv1alpha1.TenantControlPlane{}, builder.WithPredicates(predicate.NewPredicateFuncs(func(object client.Object) bool {
obj := object.(*kamajiv1alpha1.TenantControlPlane) //nolint:forcetypeassert
// status is required to understand if we have to start or stop the soot manager

View File

@@ -0,0 +1,120 @@
// Copyright 2022 Clastix Labs
// SPDX-License-Identifier: Apache-2.0
package controllers
import (
"context"
"time"
"github.com/clastix/kamaji-telemetry/api"
telemetry "github.com/clastix/kamaji-telemetry/pkg/client"
"github.com/pkg/errors"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/log"
kamajiv1alpha1 "github.com/clastix/kamaji/api/v1alpha1"
)
type TelemetryController struct {
Client client.Client
TelemetryClient telemetry.Client
LeaderElectionNamespace string
LeaderElectionID string
KamajiVersion string
KubernetesVersion string
}
func (m *TelemetryController) retrieveControllerUID(ctx context.Context) (string, error) {
var defaultSvc corev1.Service
if err := m.Client.Get(ctx, types.NamespacedName{Name: "kubernetes", Namespace: "default"}, &defaultSvc); err != nil {
return "", errors.Wrap(err, "cannot start the telemetry controller")
}
return string(defaultSvc.UID), nil
}
func (m *TelemetryController) Start(ctx context.Context) error {
logger := log.FromContext(ctx)
ticker := time.NewTicker(5 * time.Minute)
defer ticker.Stop()
uid, err := m.retrieveControllerUID(ctx)
if err != nil {
logger.Error(err, "cannot retrieve controller UID")
return err
}
// First run to avoid waiting 5 minutes
go m.collectStats(ctx, uid)
for {
select {
case <-ctx.Done():
return nil
case <-ticker.C:
go m.collectStats(ctx, uid)
}
}
}
func (m *TelemetryController) collectStats(ctx context.Context, uid string) {
logger := log.FromContext(ctx)
stats := api.Stats{
UUID: uid,
KamajiVersion: m.KamajiVersion,
KubernetesVersion: m.KubernetesVersion,
TenantControlPlanes: api.TenantControlPlane{},
Datastores: api.Datastores{},
}
var tcpList kamajiv1alpha1.TenantControlPlaneList
if err := m.Client.List(ctx, &tcpList); err != nil {
logger.Error(err, "cannot list TenantControlPlane")
return
}
for _, tcp := range tcpList.Items {
switch {
case tcp.Spec.ControlPlane.Deployment.Replicas == nil || *tcp.Spec.ControlPlane.Deployment.Replicas == 0:
stats.TenantControlPlanes.Sleeping++
case tcp.Status.Kubernetes.Version.Status != nil && *tcp.Status.Kubernetes.Version.Status == kamajiv1alpha1.VersionNotReady:
stats.TenantControlPlanes.NotReady++
case tcp.Status.Kubernetes.Version.Status != nil && *tcp.Status.Kubernetes.Version.Status == kamajiv1alpha1.VersionUpgrading:
stats.TenantControlPlanes.Upgrading++
default:
stats.TenantControlPlanes.Running++
}
}
var datastoreList kamajiv1alpha1.DataStoreList
if err := m.Client.List(ctx, &datastoreList); err != nil {
logger.Error(err, "cannot list DataStores")
return
}
for _, ds := range datastoreList.Items {
switch ds.Spec.Driver {
case kamajiv1alpha1.EtcdDriver:
stats.Datastores.Etcd.ShardCount++
stats.Datastores.Etcd.UsedByCount += len(ds.Status.UsedBy)
case kamajiv1alpha1.KinePostgreSQLDriver:
stats.Datastores.PostgreSQL.ShardCount++
stats.Datastores.PostgreSQL.UsedByCount += len(ds.Status.UsedBy)
case kamajiv1alpha1.KineMySQLDriver:
stats.Datastores.MySQL.ShardCount++
stats.Datastores.MySQL.UsedByCount += len(ds.Status.UsedBy)
case kamajiv1alpha1.KineNatsDriver:
stats.Datastores.NATS.ShardCount++
stats.Datastores.NATS.UsedByCount += len(ds.Status.UsedBy)
}
}
m.TelemetryClient.PushStats(ctx, stats)
}

View File

@@ -227,29 +227,29 @@ func (r *TenantControlPlaneReconciler) SetupWithManager(mgr ctrl.Manager) error
r.clock = clock.RealClock{}
return ctrl.NewControllerManagedBy(mgr).
WatchesRawSource(&source.Channel{Source: r.CertificateChan}, handler.Funcs{GenericFunc: func(_ context.Context, genericEvent event.GenericEvent, limitingInterface workqueue.RateLimitingInterface) {
WatchesRawSource(source.Channel(r.CertificateChan, handler.Funcs{GenericFunc: func(_ context.Context, genericEvent event.GenericEvent, limitingInterface workqueue.RateLimitingInterface) {
limitingInterface.AddRateLimited(ctrl.Request{
NamespacedName: k8stypes.NamespacedName{
Namespace: genericEvent.Object.GetNamespace(),
Name: genericEvent.Object.GetName(),
},
})
}}).
WatchesRawSource(&source.Channel{Source: r.TriggerChan}, handler.Funcs{GenericFunc: func(_ context.Context, genericEvent event.GenericEvent, limitingInterface workqueue.RateLimitingInterface) {
}})).
WatchesRawSource(source.Channel(r.TriggerChan, handler.Funcs{GenericFunc: func(_ context.Context, genericEvent event.GenericEvent, limitingInterface workqueue.RateLimitingInterface) {
limitingInterface.AddRateLimited(ctrl.Request{
NamespacedName: k8stypes.NamespacedName{
Namespace: genericEvent.Object.GetNamespace(),
Name: genericEvent.Object.GetName(),
},
})
}}).
}})).
For(&kamajiv1alpha1.TenantControlPlane{}).
Owns(&corev1.Secret{}).
Owns(&corev1.ConfigMap{}).
Owns(&appsv1.Deployment{}).
Owns(&corev1.Service{}).
Owns(&networkingv1.Ingress{}).
WatchesRawSource(source.Kind(mgr.GetCache(), &batchv1.Job{}), handler.EnqueueRequestsFromMapFunc(func(_ context.Context, object client.Object) []reconcile.Request {
Watches(&batchv1.Job{}, handler.EnqueueRequestsFromMapFunc(func(_ context.Context, object client.Object) []reconcile.Request {
labels := object.GetLabels()
name, namespace := labels["tcp.kamaji.clastix.io/name"], labels["tcp.kamaji.clastix.io/namespace"]

View File

@@ -26,7 +26,7 @@ nodes:
## expose port 31132 of the node to port 31132 on the host for konnectivity
- containerPort: 31132
hostPort: 31132
protocol: TCP
protocol: TCP
## expose port 31443 of the node to port 31443 on the host
- containerPort: 31443
hostPort: 31443

View File

@@ -1,14 +0,0 @@
{
"CN": "bronze.mysql-system.svc.cluster.local",
"key": {
"algo": "rsa",
"size": 2048
},
"hosts": [
"127.0.0.1",
"localhost",
"bronze",
"bronze.mysql-system.svc",
"bronze.mysql-system.svc.cluster.local"
]
}

View File

@@ -44,7 +44,7 @@ spec:
secretName: mysql-certs
containers:
- name: kine-tenant
image: rancher/kine:v0.9.2-amd64
image: rancher/kine:v0.11.10-amd64
ports:
- containerPort: 2379
name: server

40
deploy/kine/nats/Makefile Normal file
View File

@@ -0,0 +1,40 @@
ROOT_DIR:=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))
NAME:=default
NAMESPACE:=nats-system
.PHONY: helm
HELM = $(shell pwd)/../../../bin/helm
helm: ## Download helm locally if necessary.
$(call go-install-tool,$(HELM),helm.sh/helm/v3/cmd/helm@v3.9.0)
nats: nats-certificates nats-secret nats-deployment
nats-certificates:
rm -rf $(ROOT_DIR)/certs/$(NAME) && mkdir -p $(ROOT_DIR)/certs/$(NAME)
cfssl gencert -initca $(ROOT_DIR)/ca-csr.json | cfssljson -bare $(ROOT_DIR)/certs/$(NAME)/ca
@mv $(ROOT_DIR)/certs/$(NAME)/ca.pem $(ROOT_DIR)/certs/$(NAME)/ca.crt
@mv $(ROOT_DIR)/certs/$(NAME)/ca-key.pem $(ROOT_DIR)/certs/$(NAME)/ca.key
@NAME=$(NAME) NAMESPACE=$(NAMESPACE) envsubst < server-csr.json > $(ROOT_DIR)/certs/$(NAME)/server-csr.json
cfssl gencert -ca=$(ROOT_DIR)/certs/$(NAME)/ca.crt -ca-key=$(ROOT_DIR)/certs/$(NAME)/ca.key \
-config=$(ROOT_DIR)/config.json -profile=server \
$(ROOT_DIR)/certs/$(NAME)/server-csr.json | cfssljson -bare $(ROOT_DIR)/certs/$(NAME)/server
@mv $(ROOT_DIR)/certs/$(NAME)/server.pem $(ROOT_DIR)/certs/$(NAME)/server.crt
@mv $(ROOT_DIR)/certs/$(NAME)/server-key.pem $(ROOT_DIR)/certs/$(NAME)/server.key
chmod 644 $(ROOT_DIR)/certs/$(NAME)/*
nats-secret:
@kubectl create namespace $(NAMESPACE) || true
@kubectl -n $(NAMESPACE) create secret generic nats-$(NAME)-config \
--from-file=$(ROOT_DIR)/certs/$(NAME)/ca.crt --from-file=$(ROOT_DIR)/certs/$(NAME)/ca.key \
--from-file=$(ROOT_DIR)/certs/$(NAME)/server.key --from-file=$(ROOT_DIR)/certs/$(NAME)/server.crt \
--from-literal=password=password \
--dry-run=client -o yaml | kubectl apply -f -
nats-deployment:
@VALUES_FILE=$(if $(findstring notls,$(NAME)),values-notls.yaml,values.yaml); \
NAME=$(NAME) envsubst < $(ROOT_DIR)/$$VALUES_FILE | $(HELM) upgrade --install $(NAME) nats/nats --create-namespace -n nats-system -f -
nats-destroy:
@NAME=$(NAME) envsubst < $(ROOT_DIR)/nats.yaml | kubectl -n $(NAMESPACE) delete --ignore-not-found -f -
@kubectl delete -n $(NAMESPACE) secret mysql-$(NAME)config --ignore-not-found

View File

@@ -0,0 +1,18 @@
{
"CN": "Clastix CA",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "IT",
"ST": "Italy",
"L": "Milan"
}
],
"hosts": [
"127.0.0.1",
"localhost"
]
}

View File

@@ -0,0 +1,18 @@
{
"signing": {
"default": {
"expiry": "8760h"
},
"profiles": {
"server": {
"expiry": "8760h",
"usages": [
"signing",
"key encipherment",
"server auth",
"client auth"
]
}
}
}
}

View File

@@ -0,0 +1,14 @@
{
"CN": "$NAME.$NAMESPACE.svc.cluster.local",
"key": {
"algo": "rsa",
"size": 2048
},
"hosts": [
"127.0.0.1",
"localhost",
"$NAME-nats",
"$NAME-nats.$NAMESPACE.svc",
"$NAME-nats.$NAMESPACE.svc.cluster.local"
]
}

View File

@@ -0,0 +1,14 @@
config:
merge:
accounts:
private:
jetstream: enabled
users:
- {user: admin, password: "password", permissions: {subscribe: [">"], publish: [">"]}}
cluster:
enabled: no
jetstream:
enabled: true
fileStore:
pvc:
size: 32Mi

View File

@@ -0,0 +1,20 @@
config:
merge:
accounts:
private:
jetstream: enabled
users:
- {user: admin, password: "password", permissions: {subscribe: [">"], publish: [">"]}}
cluster:
enabled: no
nats:
tls:
enabled: true
secretName: nats-$NAME-config
cert: server.crt
key: server.key
jetstream:
enabled: true
fileStore:
pvc:
size: 32Mi

View File

@@ -1,43 +1,32 @@
# Use Alternative Datastores
Kamaji offers the possibility of having a different storage system than `etcd` thanks to [kine](https://github.com/k3s-io/kine) integration. One of the implementations is [PostgreSQL](https://www.postgresql.org/).
Kamaji offers the possibility of having a different storage system than `etcd` thanks to [kine](https://github.com/k3s-io/kine) integration.
## Install the datastore
## Installing Drivers
On the Management Cluster, install one of the alternative supported datastore:
The following `make` recipes help you to setup alternative `Datastore` resources.
- **MySQL** install it with command:
> The default settings are not production grade:
> the following scripts are just used to test the Kamaji usage of different drivers.
`$ make -C deploy/kine/mysql mariadb`
On the Management Cluster, you can use the following commands:
- **PostgreSQL** install it with command:
- **MySQL**: `$ make -C deploy/kine/mysql mariadb`
`$ make -C deploy/kine/postgresql postgresql`
- **PostgreSQL**: `$ make -C deploy/kine/postgresql postgresql`
## Install Cert Manager
- **NATS**: `$ make -C deploy/kine/nats nats`
As prerequisite for Kamaji, install the Cert Manager
## Defining a default Datastore upon Kamaji installation
```bash
helm repo add jetstack https://charts.jetstack.io
helm repo update
helm install \
cert-manager jetstack/cert-manager \
--namespace cert-manager \
--create-namespace \
--version v1.11.0 \
--set installCRDs=true
```
Use Helm to install the Kamaji Operator and make sure it uses a datastore with the proper driver `datastore.driver=<MySQL|PostgreSQL|NATS>`.
Please refer to the Chart available values for more information on supported options.
## Install Kamaji
Use Helm to install the Kamaji Operator and make sure it uses a datastore with the proper driver `datastore.driver=<MySQL|PostgreSQL>`.
For example, with a PostreSQL datastore installed:
For example, with a PostgreSQL datastore installed:
```bash
helm install kamaji charts/kamaji -n kamaji-system --create-namespace \
--set etcd.deploy=false \
--set kamaji-etcd.deploy=false \
--set datastore.driver=PostgreSQL \
--set datastore.endpoints[0]=postgres-default-rw.kamaji-system.svc:5432 \
--set datastore.basicAuth.usernameSecret.name=postgres-default-superuser \
@@ -60,4 +49,19 @@ helm install kamaji charts/kamaji -n kamaji-system --create-namespace \
--set datastore.tlsConfig.clientCertificate.privateKey.keyPath=tls.key
```
Once installed, you will able to create Tenant Control Planes using an alternative datastore.
Once installed, you will be able to create Tenant Control Planes using an alternative datastore.
## Defining specific Datastore per Tenant Control Plane
Each `TenantControlPlane` can refer to a specific `Datastore` thanks to the `/spec/dataStore` field.
This allows you to implement your preferred sharding or pooling strategy.
When the said key is omitted, Kamaji will use the default datastore configured with its CLI argument `--datastore`.
## NATS considerations
The NATS support is still experimental, mostly because multi-tenancy is **NOT** supported.
> A `NATS` based DataStore can host one and only one Tenant Control Plane.
> When a `TenantControlPlane` is referring to a NATS `DataStore` already used by another instance,
> reconciliation will fail and blocked.

View File

@@ -99,7 +99,7 @@ The rotation will occur the day before their expiration.
> Nota Bene:
>
> Kamaji is responsible for creating the `etcd` client certificate, and the generation of a new one will occur.
> For other Datastore drivers, such as MySQL or PostgreSQL, the referenced Secret will always be deleted by the Controller to trigger the rotation:
> For other Datastore drivers, such as MySQL, PostgreSQL, or NATS, the referenced Secret will always be deleted by the Controller to trigger the rotation:
> the PKI management, since it's offloaded externally, must provide the renewed certificates.
## Certificate Authority rotation

View File

@@ -69,7 +69,9 @@ From the main view, clicking on a Tenant Control Plane row will bring you to the
![Console Tenant Control Plane View](../images/console-tcp-view.png)
### Working with Datastore
From the menu bar on the left, clicking on the Datastores item, you can access the list of provisioned Datastores. It shows a summary about datastores, including name and the used driver, i.e. etcd, mysql, and postgresql.
From the menu bar on the left, clicking on the Datastores item, you can access the list of provisioned Datastores.
It shows a summary about datastores, including name and the used driver, i.e. `etcd`, `MySQL`, `PostgreSQL`, and `NATS`.
![Console Datastore List](../images/console-ds-list.png)

View File

@@ -1,6 +1,7 @@
# Datastore Migration
On the Management Cluster, you can deploy one or more multi-tenant datastores as `etcd`, `PostgreSQL`, and `MySQL` to save the state of the Tenant Clusters. A Tenant Control Plane can be migrated from a datastore to another one without service disruption or without complex and error prone backup & restore procedures.
On the Management Cluster, you can deploy one or more multi-tenant datastores as `etcd`, `PostgreSQL`, `MySQL`, and `NATS` to save the state of the Tenant Clusters.
A Tenant Control Plane can be migrated from a datastore to another one without service disruption or without complex and error-prone backup & restore procedures.
This guide will assist you to live migrate Tenant's data from a datastore to another one having the same `etcd` driver.
@@ -80,7 +81,7 @@ helm install dedicated clastix/kamaji-etcd -n dedicated --create-namespace --set
You should end up with a new datastore `dedicated` provided by an `etcd` cluster:
```yaml
kubectl get datastore dedicated -o yaml
# kubectl get datastore dedicated -o yaml
apiVersion: kamaji.clastix.io/v1alpha1
kind: DataStore
metadata:
@@ -171,4 +172,25 @@ After a while, depending on the amount of data to migrate, the Tenant Control Pl
> Please, note the datastore migration leaves the data on the default datastore, so you have to remove it manually.
## Post migration
After migrating data to the new datastore, complete the migration procedure by restarting the `kubelet.service` on all the tenant worker nodes.
After migrating data to the new datastore, complete the migration procedure by restarting the `kubelet.service` on all the tenant worker nodes.
## Troubleshooting
### Migration Job Image Version
When migrating between datastores, the Kamaji controller automatically creates a migration job to transfer data from the source to the destination datastore. By default, this job uses the same image version as the running Kamaji controller. If you need to use a different image version for the migration job, you can specify it by passing extra arguments to the controller:
```shell
helm upgrade kamaji clastix/kamaji -n kamaji-system
--set extraArgs[0]=--migrate-image=custom/kamaji:version`
```
### Handling Private Registry Images
If the Kamaji controller images are stored in a private registry that requires authentication, the migration job will fail because it does not use any `ImagePullSecret` by default. You need to attach your registry secret to the `kamaji-controller-manager` service account, which is used by the migration job. You can do this with the following command:
```shell
kubectl -n kamaji-system patch serviceaccount kamaji-controller-manager \
-p '{"imagePullSecrets": [{"name": "myregistry-credentials"}]}'
```
This command patches the kamaji-controller-manager service account to include your registry secret, allowing the migration job to pull images from the private registry successfully.

View File

@@ -125,7 +125,7 @@ helm install kamaji clastix/kamaji -n kamaji-system --create-namespace
```
!!! note "A managed datastore is highly recommended in production"
The [kamaji-etcd](https://github.com/clastix/kamaji-etcd) project provides the code to setup a multi-tenant `etcd` running as StatefulSet made of three replicas. Optionally, Kamaji offers support for a more robust storage system, as `MySQL` or `PostgreSQL` compatible database, thanks to the native [kine](https://github.com/k3s-io/kine) integration.
The [kamaji-etcd](https://github.com/clastix/kamaji-etcd) project provides the code to setup a multi-tenant `etcd` running as StatefulSet made of three replicas. Optionally, Kamaji offers support for a more robust storage system, as `MySQL`, `PostgreSQL`, or `NATS` compatible database, thanks to the native [kine](https://github.com/k3s-io/kine) integration.
## Create Tenant Cluster

View File

@@ -89,7 +89,7 @@ DataStoreSpec defines the desired state of DataStore.
<td>
The driver to use to connect to the shared datastore.<br/>
<br/>
<i>Enum</i>: etcd, MySQL, PostgreSQL<br/>
<i>Enum</i>: etcd, MySQL, PostgreSQL, NATS<br/>
</td>
<td>true</td>
</tr><tr>
@@ -100,13 +100,6 @@ DataStoreSpec defines the desired state of DataStore.
No need for protocol, just bare IP/FQDN and port.<br/>
</td>
<td>true</td>
</tr><tr>
<td><b><a href="#datastorespectlsconfig">tlsConfig</a></b></td>
<td>object</td>
<td>
Defines the TLS/SSL configuration required to connect to the data store in a secure way.<br/>
</td>
<td>true</td>
</tr><tr>
<td><b><a href="#datastorespecbasicauth">basicAuth</a></b></td>
<td>object</td>
@@ -115,6 +108,202 @@ No need for protocol, just bare IP/FQDN and port.<br/>
This value is optional.<br/>
</td>
<td>false</td>
</tr><tr>
<td><b><a href="#datastorespectlsconfig">tlsConfig</a></b></td>
<td>object</td>
<td>
Defines the TLS/SSL configuration required to connect to the data store in a secure way.
This value is optional.<br/>
</td>
<td>false</td>
</tr></tbody>
</table>
### DataStore.spec.basicAuth
In case of authentication enabled for the given data store, specifies the username and password pair.
This value is optional.
<table>
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Description</th>
<th>Required</th>
</tr>
</thead>
<tbody><tr>
<td><b><a href="#datastorespecbasicauthpassword">password</a></b></td>
<td>object</td>
<td>
<br/>
</td>
<td>true</td>
</tr><tr>
<td><b><a href="#datastorespecbasicauthusername">username</a></b></td>
<td>object</td>
<td>
<br/>
</td>
<td>true</td>
</tr></tbody>
</table>
### DataStore.spec.basicAuth.password
<table>
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Description</th>
<th>Required</th>
</tr>
</thead>
<tbody><tr>
<td><b>content</b></td>
<td>string</td>
<td>
Bare content of the file, base64 encoded.
It has precedence over the SecretReference value.<br/>
<br/>
<i>Format</i>: byte<br/>
</td>
<td>false</td>
</tr><tr>
<td><b><a href="#datastorespecbasicauthpasswordsecretreference">secretReference</a></b></td>
<td>object</td>
<td>
<br/>
</td>
<td>false</td>
</tr></tbody>
</table>
### DataStore.spec.basicAuth.password.secretReference
<table>
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Description</th>
<th>Required</th>
</tr>
</thead>
<tbody><tr>
<td><b>keyPath</b></td>
<td>string</td>
<td>
Name of the key for the given Secret reference where the content is stored.
This value is mandatory.<br/>
</td>
<td>true</td>
</tr><tr>
<td><b>name</b></td>
<td>string</td>
<td>
name is unique within a namespace to reference a secret resource.<br/>
</td>
<td>false</td>
</tr><tr>
<td><b>namespace</b></td>
<td>string</td>
<td>
namespace defines the space within which the secret name must be unique.<br/>
</td>
<td>false</td>
</tr></tbody>
</table>
### DataStore.spec.basicAuth.username
<table>
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Description</th>
<th>Required</th>
</tr>
</thead>
<tbody><tr>
<td><b>content</b></td>
<td>string</td>
<td>
Bare content of the file, base64 encoded.
It has precedence over the SecretReference value.<br/>
<br/>
<i>Format</i>: byte<br/>
</td>
<td>false</td>
</tr><tr>
<td><b><a href="#datastorespecbasicauthusernamesecretreference">secretReference</a></b></td>
<td>object</td>
<td>
<br/>
</td>
<td>false</td>
</tr></tbody>
</table>
### DataStore.spec.basicAuth.username.secretReference
<table>
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Description</th>
<th>Required</th>
</tr>
</thead>
<tbody><tr>
<td><b>keyPath</b></td>
<td>string</td>
<td>
Name of the key for the given Secret reference where the content is stored.
This value is mandatory.<br/>
</td>
<td>true</td>
</tr><tr>
<td><b>name</b></td>
<td>string</td>
<td>
name is unique within a namespace to reference a secret resource.<br/>
</td>
<td>false</td>
</tr><tr>
<td><b>namespace</b></td>
<td>string</td>
<td>
namespace defines the space within which the secret name must be unique.<br/>
</td>
<td>false</td>
</tr></tbody>
</table>
@@ -124,6 +313,7 @@ This value is optional.<br/>
Defines the TLS/SSL configuration required to connect to the data store in a secure way.
This value is optional.
<table>
<thead>
@@ -148,7 +338,7 @@ The key reference is required since etcd authentication is based on certificates
<td>
Specifies the SSL/TLS key and private key pair used to connect to the data store.<br/>
</td>
<td>true</td>
<td>false</td>
</tr></tbody>
</table>
@@ -493,194 +683,6 @@ It has precedence over the SecretReference value.<br/>
<table>
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Description</th>
<th>Required</th>
</tr>
</thead>
<tbody><tr>
<td><b>keyPath</b></td>
<td>string</td>
<td>
Name of the key for the given Secret reference where the content is stored.
This value is mandatory.<br/>
</td>
<td>true</td>
</tr><tr>
<td><b>name</b></td>
<td>string</td>
<td>
name is unique within a namespace to reference a secret resource.<br/>
</td>
<td>false</td>
</tr><tr>
<td><b>namespace</b></td>
<td>string</td>
<td>
namespace defines the space within which the secret name must be unique.<br/>
</td>
<td>false</td>
</tr></tbody>
</table>
### DataStore.spec.basicAuth
In case of authentication enabled for the given data store, specifies the username and password pair.
This value is optional.
<table>
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Description</th>
<th>Required</th>
</tr>
</thead>
<tbody><tr>
<td><b><a href="#datastorespecbasicauthpassword">password</a></b></td>
<td>object</td>
<td>
<br/>
</td>
<td>true</td>
</tr><tr>
<td><b><a href="#datastorespecbasicauthusername">username</a></b></td>
<td>object</td>
<td>
<br/>
</td>
<td>true</td>
</tr></tbody>
</table>
### DataStore.spec.basicAuth.password
<table>
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Description</th>
<th>Required</th>
</tr>
</thead>
<tbody><tr>
<td><b>content</b></td>
<td>string</td>
<td>
Bare content of the file, base64 encoded.
It has precedence over the SecretReference value.<br/>
<br/>
<i>Format</i>: byte<br/>
</td>
<td>false</td>
</tr><tr>
<td><b><a href="#datastorespecbasicauthpasswordsecretreference">secretReference</a></b></td>
<td>object</td>
<td>
<br/>
</td>
<td>false</td>
</tr></tbody>
</table>
### DataStore.spec.basicAuth.password.secretReference
<table>
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Description</th>
<th>Required</th>
</tr>
</thead>
<tbody><tr>
<td><b>keyPath</b></td>
<td>string</td>
<td>
Name of the key for the given Secret reference where the content is stored.
This value is mandatory.<br/>
</td>
<td>true</td>
</tr><tr>
<td><b>name</b></td>
<td>string</td>
<td>
name is unique within a namespace to reference a secret resource.<br/>
</td>
<td>false</td>
</tr><tr>
<td><b>namespace</b></td>
<td>string</td>
<td>
namespace defines the space within which the secret name must be unique.<br/>
</td>
<td>false</td>
</tr></tbody>
</table>
### DataStore.spec.basicAuth.username
<table>
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Description</th>
<th>Required</th>
</tr>
</thead>
<tbody><tr>
<td><b>content</b></td>
<td>string</td>
<td>
Bare content of the file, base64 encoded.
It has precedence over the SecretReference value.<br/>
<br/>
<i>Format</i>: byte<br/>
</td>
<td>false</td>
</tr><tr>
<td><b><a href="#datastorespecbasicauthusernamesecretreference">secretReference</a></b></td>
<td>object</td>
<td>
<br/>
</td>
<td>false</td>
</tr></tbody>
</table>
### DataStore.spec.basicAuth.username.secretReference
<table>
<thead>
<tr>
@@ -1038,6 +1040,13 @@ Selector which must match a node's labels for the pod to be scheduled on that no
More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/<br/>
</td>
<td>false</td>
</tr><tr>
<td><b><a href="#tenantcontrolplanespeccontrolplanedeploymentpodadditionalmetadata">podAdditionalMetadata</a></b></td>
<td>object</td>
<td>
AdditionalMetadata defines which additional metadata, such as labels and annotations, must be attached to the created resource.<br/>
</td>
<td>false</td>
</tr><tr>
<td><b><a href="#tenantcontrolplanespeccontrolplanedeploymentregistrysettings">registrySettings</a></b></td>
<td>object</td>
@@ -1077,6 +1086,15 @@ empty definition that uses the default runtime handler.
More info: https://git.k8s.io/enhancements/keps/sig-node/585-runtime-class<br/>
</td>
<td>false</td>
</tr><tr>
<td><b>serviceAccountName</b></td>
<td>string</td>
<td>
ServiceAccountName allows to specify the service account to be mounted to the pods of the Control plane deployment<br/>
<br/>
<i>Default</i>: default<br/>
</td>
<td>false</td>
</tr><tr>
<td><b><a href="#tenantcontrolplanespeccontrolplanedeploymentstrategy">strategy</a></b></td>
<td>object</td>
@@ -1511,8 +1529,14 @@ Selects a key of a ConfigMap.
<td>string</td>
<td>
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
TODO: Add other useful fields. apiVersion, kind, uid?
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Add other useful fields. apiVersion, kind, uid?<br/>
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.<br/>
<br/>
<i>Default</i>: <br/>
</td>
<td>false</td>
</tr><tr>
@@ -1628,8 +1652,14 @@ Selects a key of a secret in the pod's namespace
<td>string</td>
<td>
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
TODO: Add other useful fields. apiVersion, kind, uid?
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Add other useful fields. apiVersion, kind, uid?<br/>
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.<br/>
<br/>
<i>Default</i>: <br/>
</td>
<td>false</td>
</tr><tr>
@@ -1703,8 +1733,14 @@ The ConfigMap to select from
<td>string</td>
<td>
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
TODO: Add other useful fields. apiVersion, kind, uid?
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Add other useful fields. apiVersion, kind, uid?<br/>
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.<br/>
<br/>
<i>Default</i>: <br/>
</td>
<td>false</td>
</tr><tr>
@@ -1738,8 +1774,14 @@ The Secret to select from
<td>string</td>
<td>
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
TODO: Add other useful fields. apiVersion, kind, uid?
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Add other useful fields. apiVersion, kind, uid?<br/>
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.<br/>
<br/>
<i>Default</i>: <br/>
</td>
<td>false</td>
</tr><tr>
@@ -4328,8 +4370,14 @@ Selects a key of a ConfigMap.
<td>string</td>
<td>
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
TODO: Add other useful fields. apiVersion, kind, uid?
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Add other useful fields. apiVersion, kind, uid?<br/>
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.<br/>
<br/>
<i>Default</i>: <br/>
</td>
<td>false</td>
</tr><tr>
@@ -4445,8 +4493,14 @@ Selects a key of a secret in the pod's namespace
<td>string</td>
<td>
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
TODO: Add other useful fields. apiVersion, kind, uid?
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Add other useful fields. apiVersion, kind, uid?<br/>
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.<br/>
<br/>
<i>Default</i>: <br/>
</td>
<td>false</td>
</tr><tr>
@@ -4520,8 +4574,14 @@ The ConfigMap to select from
<td>string</td>
<td>
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
TODO: Add other useful fields. apiVersion, kind, uid?
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Add other useful fields. apiVersion, kind, uid?<br/>
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.<br/>
<br/>
<i>Default</i>: <br/>
</td>
<td>false</td>
</tr><tr>
@@ -4555,8 +4615,14 @@ The Secret to select from
<td>string</td>
<td>
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
TODO: Add other useful fields. apiVersion, kind, uid?
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Add other useful fields. apiVersion, kind, uid?<br/>
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.<br/>
<br/>
<i>Default</i>: <br/>
</td>
<td>false</td>
</tr><tr>
@@ -7647,8 +7713,14 @@ More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it
<td>string</td>
<td>
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
TODO: Add other useful fields. apiVersion, kind, uid?
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Add other useful fields. apiVersion, kind, uid?<br/>
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.<br/>
<br/>
<i>Default</i>: <br/>
</td>
<td>false</td>
</tr></tbody>
@@ -7731,8 +7803,14 @@ to OpenStack.
<td>string</td>
<td>
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
TODO: Add other useful fields. apiVersion, kind, uid?
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Add other useful fields. apiVersion, kind, uid?<br/>
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.<br/>
<br/>
<i>Default</i>: <br/>
</td>
<td>false</td>
</tr></tbody>
@@ -7787,8 +7865,14 @@ relative and may not contain the '..' path or start with '..'.<br/>
<td>string</td>
<td>
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
TODO: Add other useful fields. apiVersion, kind, uid?
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Add other useful fields. apiVersion, kind, uid?<br/>
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.<br/>
<br/>
<i>Default</i>: <br/>
</td>
<td>false</td>
</tr><tr>
@@ -7939,8 +8023,14 @@ secret object contains more than one secret, all secret references are passed.
<td>string</td>
<td>
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
TODO: Add other useful fields. apiVersion, kind, uid?
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Add other useful fields. apiVersion, kind, uid?<br/>
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.<br/>
<br/>
<i>Default</i>: <br/>
</td>
<td>false</td>
</tr></tbody>
@@ -8819,8 +8909,14 @@ scripts.
<td>string</td>
<td>
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
TODO: Add other useful fields. apiVersion, kind, uid?
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Add other useful fields. apiVersion, kind, uid?<br/>
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.<br/>
<br/>
<i>Default</i>: <br/>
</td>
<td>false</td>
</tr></tbody>
@@ -9188,8 +9284,14 @@ secretRef is the CHAP Secret for iSCSI target and initiator authentication
<td>string</td>
<td>
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
TODO: Add other useful fields. apiVersion, kind, uid?
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Add other useful fields. apiVersion, kind, uid?<br/>
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.<br/>
<br/>
<i>Default</i>: <br/>
</td>
<td>false</td>
</tr></tbody>
@@ -9660,8 +9762,14 @@ relative and may not contain the '..' path or start with '..'.<br/>
<td>string</td>
<td>
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
TODO: Add other useful fields. apiVersion, kind, uid?
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Add other useful fields. apiVersion, kind, uid?<br/>
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.<br/>
<br/>
<i>Default</i>: <br/>
</td>
<td>false</td>
</tr><tr>
@@ -9913,8 +10021,14 @@ relative and may not contain the '..' path or start with '..'.<br/>
<td>string</td>
<td>
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
TODO: Add other useful fields. apiVersion, kind, uid?
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Add other useful fields. apiVersion, kind, uid?<br/>
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.<br/>
<br/>
<i>Default</i>: <br/>
</td>
<td>false</td>
</tr><tr>
@@ -10212,8 +10326,14 @@ More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it
<td>string</td>
<td>
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
TODO: Add other useful fields. apiVersion, kind, uid?
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Add other useful fields. apiVersion, kind, uid?<br/>
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.<br/>
<br/>
<i>Default</i>: <br/>
</td>
<td>false</td>
</tr></tbody>
@@ -10337,8 +10457,14 @@ sensitive information. If this is not provided, Login operation will fail.
<td>string</td>
<td>
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
TODO: Add other useful fields. apiVersion, kind, uid?
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Add other useful fields. apiVersion, kind, uid?<br/>
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.<br/>
<br/>
<i>Default</i>: <br/>
</td>
<td>false</td>
</tr></tbody>
@@ -10543,8 +10669,14 @@ credentials. If not specified, default values will be attempted.
<td>string</td>
<td>
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
TODO: Add other useful fields. apiVersion, kind, uid?
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Add other useful fields. apiVersion, kind, uid?<br/>
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.<br/>
<br/>
<i>Default</i>: <br/>
</td>
<td>false</td>
</tr></tbody>
@@ -12246,6 +12378,39 @@ Only modify if you know what you are doing.
</table>
### TenantControlPlane.spec.controlPlane.deployment.podAdditionalMetadata
AdditionalMetadata defines which additional metadata, such as labels and annotations, must be attached to the created resource.
<table>
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Description</th>
<th>Required</th>
</tr>
</thead>
<tbody><tr>
<td><b>annotations</b></td>
<td>map[string]string</td>
<td>
<br/>
</td>
<td>false</td>
</tr><tr>
<td><b>labels</b></td>
<td>map[string]string</td>
<td>
<br/>
</td>
<td>false</td>
</tr></tbody>
</table>
### TenantControlPlane.spec.controlPlane.deployment.registrySettings
@@ -13344,7 +13509,7 @@ Enables the Konnectivity addon in the Tenant Cluster, required if the worker nod
<td>
<br/>
<br/>
<i>Default</i>: map[image:registry.k8s.io/kas-network-proxy/proxy-agent version:v0.0.32]<br/>
<i>Default</i>: map[image:registry.k8s.io/kas-network-proxy/proxy-agent version:v0.28.6]<br/>
</td>
<td>false</td>
</tr><tr>
@@ -13353,7 +13518,7 @@ Enables the Konnectivity addon in the Tenant Cluster, required if the worker nod
<td>
<br/>
<br/>
<i>Default</i>: map[image:registry.k8s.io/kas-network-proxy/proxy-server port:8132 version:v0.0.32]<br/>
<i>Default</i>: map[image:registry.k8s.io/kas-network-proxy/proxy-server port:8132 version:v0.28.6]<br/>
</td>
<td>false</td>
</tr></tbody>
@@ -13394,13 +13559,89 @@ unxpected ways. Only modify if you know what you are doing.<br/>
<i>Default</i>: registry.k8s.io/kas-network-proxy/proxy-agent<br/>
</td>
<td>false</td>
</tr><tr>
<td><b><a href="#tenantcontrolplanespecaddonskonnectivityagenttolerationsindex">tolerations</a></b></td>
<td>[]object</td>
<td>
Tolerations for the deployed agent.
Can be customized to start the konnectivity-agent even if the nodes are not ready or tainted.<br/>
<br/>
<i>Default</i>: [map[key:CriticalAddonsOnly operator:Exists]]<br/>
</td>
<td>false</td>
</tr><tr>
<td><b>version</b></td>
<td>string</td>
<td>
Version for Konnectivity agent.<br/>
<br/>
<i>Default</i>: v0.0.32<br/>
<i>Default</i>: v0.28.6<br/>
</td>
<td>false</td>
</tr></tbody>
</table>
### TenantControlPlane.spec.addons.konnectivity.agent.tolerations[index]
The pod this Toleration is attached to tolerates any taint that matches
the triple <key,value,effect> using the matching operator <operator>.
<table>
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Description</th>
<th>Required</th>
</tr>
</thead>
<tbody><tr>
<td><b>effect</b></td>
<td>string</td>
<td>
Effect indicates the taint effect to match. Empty means match all taint effects.
When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute.<br/>
</td>
<td>false</td>
</tr><tr>
<td><b>key</b></td>
<td>string</td>
<td>
Key is the taint key that the toleration applies to. Empty means match all taint keys.
If the key is empty, operator must be Exists; this combination means to match all values and all keys.<br/>
</td>
<td>false</td>
</tr><tr>
<td><b>operator</b></td>
<td>string</td>
<td>
Operator represents a key's relationship to the value.
Valid operators are Exists and Equal. Defaults to Equal.
Exists is equivalent to wildcard for value, so that a pod can
tolerate all taints of a particular category.<br/>
</td>
<td>false</td>
</tr><tr>
<td><b>tolerationSeconds</b></td>
<td>integer</td>
<td>
TolerationSeconds represents the period of time the toleration (which must be
of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default,
it is not set, which means tolerate the taint forever (do not evict). Zero and
negative values will be treated as 0 (evict immediately) by the system.<br/>
<br/>
<i>Format</i>: int64<br/>
</td>
<td>false</td>
</tr><tr>
<td><b>value</b></td>
<td>string</td>
<td>
Value is the taint value the toleration matches to.
If the operator is Exists, the value should be empty, otherwise just a regular string.<br/>
</td>
<td>false</td>
</tr></tbody>
@@ -13463,7 +13704,7 @@ unxpected ways. Only modify if you know what you are doing.<br/>
<td>
Container image version of the Konnectivity server.<br/>
<br/>
<i>Default</i>: v0.0.32<br/>
<i>Default</i>: v0.28.6<br/>
</td>
<td>false</td>
</tr></tbody>

View File

@@ -10,7 +10,7 @@ Available flags are the following:
| `--health-probe-bind-address` | The address the probe endpoint binds to. | `:8081` |
| `--leader-elect` | Enable leader election for controller manager. Enabling this will ensure there is only one active controller manager. | `true` |
| `--tmp-directory` | Directory which will be used to work with temporary files. | `/tmp/kamaji` |
| `--kine-image` | Container image along with tag to use for the Kine sidecar container (used only if etcd-storage-type is set to one of kine strategies). | `rancher/kine:v0.9.2-amd64` |
| `--kine-image` | Container image along with tag to use for the Kine sidecar container (used only if etcd-storage-type is set to one of kine strategies). | `rancher/kine:v0.11.10-amd64` |
| `--datastore` | The default DataStore that should be used by Kamaji to setup the required storage. | `etcd` |
| `--migrate-image` | Specify the container image to launch when a TenantControlPlane is migrated to a new datastore. | `migrate-image` |
| `--max-concurrent-tcp-reconciles` | Specify the number of workers for the Tenant Control Plane controller (beware of CPU consumption). | `1` |

View File

@@ -12,6 +12,8 @@ All the _“Tenant Clusters”_ built with Kamaji are CNCF conformant:
- [v1.26](https://github.com/cncf/k8s-conformance/pull/2787)
- [v1.27](https://github.com/cncf/k8s-conformance/pull/2786)
- [v1.28](https://github.com/cncf/k8s-conformance/pull/2785)
- [v1.29](https://github.com/cncf/k8s-conformance/pull/3273)
- [v1.30](https://github.com/cncf/k8s-conformance/pull/3274)
<p align="left" style="padding: 6px 6px">
<img src="https://raw.githubusercontent.com/cncf/artwork/master/projects/kubernetes/certified-kubernetes/versionless/color/certified-kubernetes-color.png" width="100" />

View File

@@ -1,12 +1,26 @@
# Versioning
# Releases and Versions
[Clastix Labs](https://github.com/clastix) organization publishes Kamaji's versions that correspond to specific project milestones and sets of new features. These versions are available in different types of release artifacts.
## Types of release artifacts
### Edge Releases
Edge Release artifacts are published on a monthly basis as part of the open source project. Versioning follows the form `edge-{year}.{month}.{incremental}` where incremental refers to the monthly release. For example, `edge-24.7.1` is the first edge release shipped in July 2024. The full list of edge release artifacts can be found on the Kamaji's GitHub [releases page](https://github.com/clastix/kamaji/releases).
Edge Release artifacts contain the code in from the main branch at the point in time when they were cut. This means they always have the latest features and fixes, and have undergone automated testing as well as maintainer code review. Edge Releases may involve partial features that are later modified or backed out. They may also involve breaking changes, of course, we do our best to avoid this. Edge Releases are generally considered production ready, and the project will mark specific releases as “_not recommended_” if bugs are discovered after release.
Using Edge Release artifacts and reporting bugs helps us ensure a rapid pace of development and is a great way to help maintainers. We publish edge release guidance as part of the release notes and strive to always provide production-ready artifacts.
### Stable Releases
Stable Release artifacts of Kamaji follow semantic versioning, whereby changes in major version denote large feature additions and possible breaking changes and changes in minor versions denote safe upgrades without breaking changes.
As of July 2024, [Clastix Labs](https://github.com/clastix) organization does not no longer provide stable release artifacts. Stable Release artefacts are offered on a subscription basis by [CLASTIX](https://clastix.io), the main Kamaji project contributor.
In Kamaji, there are different components that might require independent versioning and support level:
| Kamaji | Management Cluster | Tenant Cluster |
|--------|--------------------|----------------------|
| v0.0 | v1.22+ | [v1.21.0 .. v1.23.5] |
| v0.1 | v1.22+ | [v1.21.0 .. v1.25.0] |
| v0.2 | v1.22+ | [v1.21.0 .. v1.27.0] |
| v0.3.0 | v1.22+ | [v1.21.0 .. v1.27.0] |
| v0.3.1 | v1.22+ | [v1.21.0 .. v1.27.3] |
| v0.3.2 | v1.22+ | [v1.21.0 .. v1.27.3] |
@@ -18,4 +32,5 @@ In Kamaji, there are different components that might require independent version
| v0.4.1 | v1.22+ | [v1.21.0 .. v1.29.1] |
| v0.4.2 | v1.22+ | [v1.21.0 .. v1.29.1] |
| v0.5.0 | v1.22+ | [v1.21.0 .. v1.30.0] |
| v0.5.1 | v1.22+ | [v1.21.0 .. v1.30.0] |
| v0.6.0 | v1.22+ | [v1.21.0 .. v1.30.1] |
| v1.0.0 | v1.22+ | [v1.21.0 .. v1.30.2] |

49
docs/content/telemetry.md Normal file
View File

@@ -0,0 +1,49 @@
# Telemetry
This document outlines the telemetry feature within the Kamaji project, detailing the rationale behind data collection, the nature of the data collected, data handling practices, and instructions for opting out.
## Why We Collect Telemetry
The Kamaji project, being open source, benefits from insights into how it is used. These insights help the project maintainers make informed decisions regarding feature prioritization, test automation, and bug fixes. Without this data, decisions on feature deprecation and enhancements would be based on limited information, potentially hindering the project's evolution and maintainability. Our goal is to ensure Kamaji's development is driven by the needs of its community, and telemetry data plays a crucial role in achieving this.
## What We Collect and How
It's important to clarify that our interest lies in the usage patterns of Kamaji, not in personal information about its users. We collect data about Kamaji version and Tenant Control Planes.
### Telemetry Payload Example
Below is a simplified example of what a telemetry payload might look like:
```json
// General status
{"uuid": "56279633-3131-436b-b8f2-9008a49a2f12", "running": 1, "sleeping": 0, "not_ready": 0, "upgrading": 0, "kamaji_version": "v0.6.1", "kubernetes_version": "v1.27.3"}
```
```json
// Creating a TCP
{"tcp_version": "v1.26.0", "kamaji_version": "v0.6.1", "kubernetes_version": "v1.27.3"}
```
```json
// Modifying a TCP (n.b.: version upgrade)
{"kamaji_version": "v0.6.1", "new_tcp_version": "v1.27.0", "old_tcp_version": "v1.26.0", "kubernetes_version": "v1.27.3"}
```
```json
// Deleting a TCP
{"status": "Ready", "tcp_version": "v1.27.0", "kamaji_version": "v0.6.1", "kubernetes_version": "v1.27.3"}
```
Data is collected through a component within Kamaji, which periodically sends this information to our backend. The telemetry backend, managed by the Kamaji maintainers, ensures data is stored securely and access is strictly controlled.
## Telemetry Opt-Out
We respect the privacy and autonomy of our users. If you prefer not to participate in telemetry, Kamaji provides an easy opt-out mechanism.
For Helm based deployments, include the `--set telemetry.disabled=true` flag when installing or upgrading Kamaji.
For manual deployments, set the flag `--disable-telemetry=true` int the Kamaji controller configuration to disable telemetry reporting.
To re-enable telemetry, simply reverse the opt-out process using the appropriate method for your deployment.
## Conclusion
Telemetry in Kamaji is designed to foster a data-driven development process that aligns with the needs and preferences of our user community. Your participation helps us make Kamaji better for everyone.

View File

@@ -76,4 +76,5 @@ nav:
- reference/conformance.md
- reference/versioning.md
- reference/api.md
- 'Telemetry': telemetry.md
- 'Contribute': contribute.md

74
e2e/tcp_custom_sa_test.go Normal file
View File

@@ -0,0 +1,74 @@
// Copyright 2022 Clastix Labs
// SPDX-License-Identifier: Apache-2.0
package e2e
import (
"context"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
pointer "k8s.io/utils/ptr"
kamajiv1alpha1 "github.com/clastix/kamaji/api/v1alpha1"
)
var _ = Describe("Deploy a TenantControlPlane with resource with custom service account", func() {
// service account object
sa := &corev1.ServiceAccount{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
Namespace: "default",
},
}
// Fill TenantControlPlane object
tcp := &kamajiv1alpha1.TenantControlPlane{
ObjectMeta: metav1.ObjectMeta{
Name: "tcp-clusterip-customsa",
Namespace: "default",
},
Spec: kamajiv1alpha1.TenantControlPlaneSpec{
ControlPlane: kamajiv1alpha1.ControlPlane{
Deployment: kamajiv1alpha1.DeploymentSpec{
Replicas: pointer.To(int32(1)),
ServiceAccountName: sa.GetName(),
},
Service: kamajiv1alpha1.ServiceSpec{
ServiceType: "ClusterIP",
},
},
NetworkProfile: kamajiv1alpha1.NetworkProfileSpec{
Address: "172.18.0.2",
},
Kubernetes: kamajiv1alpha1.KubernetesSpec{
Version: "v1.23.6",
Kubelet: kamajiv1alpha1.KubeletSpec{
CGroupFS: "cgroupfs",
},
AdmissionControllers: kamajiv1alpha1.AdmissionControllers{
"LimitRanger",
"ResourceQuota",
},
},
Addons: kamajiv1alpha1.AddonsSpec{},
},
}
// Create service account and TenantControlPlane resources into the cluster
JustBeforeEach(func() {
Expect(k8sClient.Create(context.Background(), sa)).NotTo(HaveOccurred())
Expect(k8sClient.Create(context.Background(), tcp)).NotTo(HaveOccurred())
})
// Delete the service account and TenantControlPlane resources after test is finished
JustAfterEach(func() {
Expect(k8sClient.Delete(context.Background(), tcp)).Should(Succeed())
})
// Check if TenantControlPlane resource has been created and if its pods have the right service account
It("Should be Ready and have correct sa", func() {
StatusMustEqualTo(tcp, kamajiv1alpha1.VersionReady)
PodsServiceAccountMustEqualTo(tcp, sa)
})
})

View File

@@ -0,0 +1,54 @@
// Copyright 2022 Clastix Labs
// SPDX-License-Identifier: Apache-2.0
package e2e
import (
"context"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
pointer "k8s.io/utils/ptr"
kamajiv1alpha1 "github.com/clastix/kamaji/api/v1alpha1"
)
var _ = Describe("Deploy a TenantControlPlane resource with the NATS driver without TLS", func() {
// Fill TenantControlPlane object
tcp := &kamajiv1alpha1.TenantControlPlane{
ObjectMeta: metav1.ObjectMeta{
Name: "nats-notls",
Namespace: "default",
},
Spec: kamajiv1alpha1.TenantControlPlaneSpec{
DataStore: "nats-notls",
ControlPlane: kamajiv1alpha1.ControlPlane{
Deployment: kamajiv1alpha1.DeploymentSpec{
Replicas: pointer.To(int32(1)),
},
Service: kamajiv1alpha1.ServiceSpec{
ServiceType: "ClusterIP",
},
},
Kubernetes: kamajiv1alpha1.KubernetesSpec{
Version: "v1.23.6",
Kubelet: kamajiv1alpha1.KubeletSpec{
CGroupFS: "cgroupfs",
},
},
},
}
// Create a TenantControlPlane resource into the cluster
JustBeforeEach(func() {
Expect(k8sClient.Create(context.Background(), tcp)).NotTo(HaveOccurred())
})
// Delete the TenantControlPlane resource after test is finished
JustAfterEach(func() {
Expect(k8sClient.Delete(context.Background(), tcp)).Should(Succeed())
})
// Check if TenantControlPlane resource has been created
It("Should be Ready", func() {
StatusMustEqualTo(tcp, kamajiv1alpha1.VersionReady)
})
})

View File

@@ -0,0 +1,54 @@
// Copyright 2022 Clastix Labs
// SPDX-License-Identifier: Apache-2.0
package e2e
import (
"context"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
pointer "k8s.io/utils/ptr"
kamajiv1alpha1 "github.com/clastix/kamaji/api/v1alpha1"
)
var _ = Describe("Deploy a TenantControlPlane resource with the NATS driver", func() {
// Fill TenantControlPlane object
tcp := &kamajiv1alpha1.TenantControlPlane{
ObjectMeta: metav1.ObjectMeta{
Name: "nats",
Namespace: "default",
},
Spec: kamajiv1alpha1.TenantControlPlaneSpec{
DataStore: "nats-bronze",
ControlPlane: kamajiv1alpha1.ControlPlane{
Deployment: kamajiv1alpha1.DeploymentSpec{
Replicas: pointer.To(int32(1)),
},
Service: kamajiv1alpha1.ServiceSpec{
ServiceType: "ClusterIP",
},
},
Kubernetes: kamajiv1alpha1.KubernetesSpec{
Version: "v1.23.6",
Kubelet: kamajiv1alpha1.KubeletSpec{
CGroupFS: "cgroupfs",
},
},
},
}
// Create a TenantControlPlane resource into the cluster
JustBeforeEach(func() {
Expect(k8sClient.Create(context.Background(), tcp)).NotTo(HaveOccurred())
})
// Delete the TenantControlPlane resource after test is finished
JustAfterEach(func() {
Expect(k8sClient.Delete(context.Background(), tcp)).Should(Succeed())
})
// Check if TenantControlPlane resource has been created
It("Should be Ready", func() {
StatusMustEqualTo(tcp, kamajiv1alpha1.VersionReady)
})
})

View File

@@ -0,0 +1,78 @@
// Copyright 2022 Clastix Labs
// SPDX-License-Identifier: Apache-2.0
package e2e
import (
"context"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
pointer "k8s.io/utils/ptr"
kamajiv1alpha1 "github.com/clastix/kamaji/api/v1alpha1"
)
var _ = Describe("Deploy a TenantControlPlane resource with additional pod metadata", func() {
// Fill TenantControlPlane object
tcp := &kamajiv1alpha1.TenantControlPlane{
ObjectMeta: metav1.ObjectMeta{
Name: "tcp-clusterip-additional-metadata",
Namespace: "default",
},
Spec: kamajiv1alpha1.TenantControlPlaneSpec{
ControlPlane: kamajiv1alpha1.ControlPlane{
Deployment: kamajiv1alpha1.DeploymentSpec{
Replicas: pointer.To(int32(1)),
PodAdditionalMetadata: kamajiv1alpha1.AdditionalMetadata{
Labels: map[string]string{
"hello-label": "world",
"foo-label": "bar",
},
Annotations: map[string]string{
"hello-ann": "world",
"foo-ann": "bar",
},
},
},
Service: kamajiv1alpha1.ServiceSpec{
ServiceType: "ClusterIP",
},
},
NetworkProfile: kamajiv1alpha1.NetworkProfileSpec{
Address: "172.18.0.2",
},
Kubernetes: kamajiv1alpha1.KubernetesSpec{
Version: "v1.23.6",
Kubelet: kamajiv1alpha1.KubeletSpec{
CGroupFS: "cgroupfs",
},
AdmissionControllers: kamajiv1alpha1.AdmissionControllers{
"LimitRanger",
"ResourceQuota",
},
},
Addons: kamajiv1alpha1.AddonsSpec{},
},
}
// Create a TenantControlPlane resource into the cluster
JustBeforeEach(func() {
Expect(k8sClient.Create(context.Background(), tcp)).NotTo(HaveOccurred())
})
// Delete the TenantControlPlane resource after test is finished
JustAfterEach(func() {
Expect(k8sClient.Delete(context.Background(), tcp)).Should(Succeed())
})
// Check if TenantControlPlane resource has been created
It("Should be Ready with expected additional metadata", func() {
StatusMustEqualTo(tcp, kamajiv1alpha1.VersionReady)
AllPodsLabelMustEqualTo(tcp, "hello-label", "world")
AllPodsLabelMustEqualTo(tcp, "foo-label", "bar")
AllPodsAnnotationMustEqualTo(tcp, "hello-ann", "world")
AllPodsAnnotationMustEqualTo(tcp, "foo-ann", "bar")
})
})

View File

@@ -17,6 +17,7 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/kubernetes"
"sigs.k8s.io/controller-runtime/pkg/client"
kamajiv1alpha1 "github.com/clastix/kamaji/api/v1alpha1"
)
@@ -136,3 +137,61 @@ func StatusMustEqualTo(tcp *kamajiv1alpha1.TenantControlPlane, status kamajiv1al
return *tcp.Status.Kubernetes.Version.Status
}, 5*time.Minute, time.Second).Should(Equal(status))
}
func AllPodsLabelMustEqualTo(tcp *kamajiv1alpha1.TenantControlPlane, label string, value string) {
Eventually(func() bool {
tcpPods := &corev1.PodList{}
err := k8sClient.List(context.Background(), tcpPods, client.MatchingLabels{
"kamaji.clastix.io/name": tcp.GetName(),
})
if err != nil {
return false
}
for _, pod := range tcpPods.Items {
if pod.Labels[label] != value {
return false
}
}
return true
}, 5*time.Minute, time.Second).Should(BeTrue())
}
func AllPodsAnnotationMustEqualTo(tcp *kamajiv1alpha1.TenantControlPlane, annotation string, value string) {
Eventually(func() bool {
tcpPods := &corev1.PodList{}
err := k8sClient.List(context.Background(), tcpPods, client.MatchingLabels{
"kamaji.clastix.io/name": tcp.GetName(),
})
if err != nil {
return false
}
for _, pod := range tcpPods.Items {
if pod.Annotations[annotation] != value {
return false
}
}
return true
}, 5*time.Minute, time.Second).Should(BeTrue())
}
func PodsServiceAccountMustEqualTo(tcp *kamajiv1alpha1.TenantControlPlane, sa *corev1.ServiceAccount) {
saName := sa.GetName()
Eventually(func() bool {
tcpPods := &corev1.PodList{}
err := k8sClient.List(context.Background(), tcpPods, client.MatchingLabels{
"kamaji.clastix.io/name": tcp.GetName(),
})
if err != nil {
return false
}
for _, pod := range tcpPods.Items {
if pod.Spec.ServiceAccountName != saName {
return false
}
}
return true
}, 5*time.Minute, time.Second).Should(BeTrue())
}

View File

@@ -11,6 +11,8 @@ import (
"strings"
"time"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/mount"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/testcontainers/testcontainers-go"
@@ -73,9 +75,17 @@ var _ = Describe("starting a kind worker with kubeadm", func() {
workerContainer, err = testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
ContainerRequest: testcontainers.ContainerRequest{
HostConfigModifier: func(config *container.HostConfig) {
config.Mounts = []mount.Mount{
{
Type: mount.TypeBind,
Source: "/lib/modules",
Target: "/lib/modules",
},
}
},
Name: fmt.Sprintf("%s-worker-node", tcp.GetName()),
Image: fmt.Sprintf("kindest/node:%s", tcp.Spec.Kubernetes.Version),
Mounts: testcontainers.ContainerMounts{testcontainers.BindMount("/lib/modules", "/lib/modules")},
Networks: []string{"kind"},
Privileged: true,
},
@@ -135,7 +145,7 @@ var _ = Describe("starting a kind worker with kubeadm", func() {
By("executing the command in the worker node", func() {
cmds := append(strings.Split(strings.TrimSpace(joinCommandBuffer.String()), " "), "--ignore-preflight-errors", "SystemVerification")
exitCode, err := workerContainer.Exec(ctx, cmds)
exitCode, _, err := workerContainer.Exec(ctx, cmds)
Expect(exitCode).To(Equal(0))
Expect(err).ToNot(HaveOccurred())
})

212
go.mod
View File

@@ -7,75 +7,83 @@ toolchain go1.22.1
require (
github.com/JamesStewy/go-mysqldump v0.2.2
github.com/blang/semver v3.5.1+incompatible
github.com/go-logr/logr v1.4.1
github.com/go-pg/pg/v10 v10.10.6
github.com/go-sql-driver/mysql v1.6.0
github.com/clastix/kamaji-telemetry v1.0.0
github.com/docker/docker v27.1.1+incompatible
github.com/go-logr/logr v1.4.2
github.com/go-pg/pg/v10 v10.13.0
github.com/go-sql-driver/mysql v1.8.1
github.com/google/go-cmp v0.6.0
github.com/google/uuid v1.3.0
github.com/google/uuid v1.6.0
github.com/json-iterator/go v1.1.12
github.com/juju/mutex/v2 v2.0.0
github.com/onsi/ginkgo/v2 v2.17.1
github.com/onsi/gomega v1.32.0
github.com/nats-io/nats.go v1.36.0
github.com/onsi/ginkgo/v2 v2.20.0
github.com/onsi/gomega v1.34.1
github.com/pkg/errors v0.9.1
github.com/spf13/cobra v1.7.0
github.com/spf13/cobra v1.8.1
github.com/spf13/pflag v1.0.5
github.com/spf13/viper v1.10.1
github.com/testcontainers/testcontainers-go v0.13.0
go.etcd.io/etcd/api/v3 v3.5.10
go.etcd.io/etcd/client/v3 v3.5.10
go.uber.org/automaxprocs v1.5.1
github.com/spf13/viper v1.19.0
github.com/testcontainers/testcontainers-go v0.32.0
go.etcd.io/etcd/api/v3 v3.5.15
go.etcd.io/etcd/client/v3 v3.5.15
go.uber.org/automaxprocs v1.5.3
gomodules.xyz/jsonpatch/v2 v2.4.0
k8s.io/api v0.30.0
k8s.io/apimachinery v0.30.0
k8s.io/apiserver v0.30.0
k8s.io/client-go v0.30.0
k8s.io/api v0.30.2
k8s.io/apimachinery v0.30.2
k8s.io/apiserver v0.30.2
k8s.io/client-go v0.30.2
k8s.io/cluster-bootstrap v0.0.0
k8s.io/klog/v2 v2.120.1
k8s.io/klog/v2 v2.130.1
k8s.io/kubelet v0.0.0
k8s.io/kubernetes v1.30.0
k8s.io/kubernetes v1.30.3
k8s.io/utils v0.0.0-20230726121419-3b25d923346b
sigs.k8s.io/controller-runtime v0.17.1-0.20240416095710-67b27f27e514
sigs.k8s.io/controller-runtime v0.18.4
)
require (
dario.cat/mergo v1.0.0 // indirect
filippo.io/edwards25519 v1.1.0 // indirect
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
github.com/DATA-DOG/go-sqlmock v1.5.0 // indirect
github.com/Microsoft/go-winio v0.6.0 // indirect
github.com/Microsoft/hcsshim v0.8.25 // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/Microsoft/hcsshim v0.11.5 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/blang/semver/v4 v4.0.0 // indirect
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/containerd/cgroups v1.1.0 // indirect
github.com/containerd/containerd v1.5.9 // indirect
github.com/containerd/containerd v1.7.18 // indirect
github.com/containerd/errdefs v0.1.0 // indirect
github.com/containerd/log v0.1.0 // indirect
github.com/coredns/caddy v1.1.1 // indirect
github.com/coredns/corefile-migration v1.0.21 // indirect
github.com/coreos/go-semver v0.3.1 // indirect
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/distribution/reference v0.5.0 // indirect
github.com/docker/distribution v2.8.1+incompatible // indirect
github.com/docker/docker v20.10.11+incompatible // indirect
github.com/docker/go-connections v0.4.0 // indirect
github.com/cpuguy83/dockercfg v0.3.1 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/distribution/reference v0.6.0 // indirect
github.com/docker/go-connections v0.5.0 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
github.com/evanphx/json-patch v5.6.0+incompatible // indirect
github.com/evanphx/json-patch/v5 v5.9.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/go-errors/errors v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-logr/zapr v1.3.0 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/go-openapi/jsonpointer v0.19.6 // indirect
github.com/go-openapi/jsonreference v0.20.2 // indirect
github.com/go-openapi/swag v0.22.3 // indirect
github.com/go-pg/zerochecker v0.2.0 // indirect
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/btree v1.0.1 // indirect
github.com/google/gnostic-models v0.6.8 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect
github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 // indirect
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
@@ -84,76 +92,90 @@ require (
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/juju/errors v0.0.0-20220203013757-bd733f3c86b9 // indirect
github.com/klauspost/compress v1.17.8 // indirect
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
github.com/lithammer/dedent v1.1.0 // indirect
github.com/magiconair/properties v1.8.5 // indirect
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // 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.4.3 // indirect
github.com/moby/sys/mount v0.2.0 // indirect
github.com/moby/sys/mountinfo v0.6.2 // indirect
github.com/moby/term v0.0.0-20221205130635-1aeaba878587 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/moby/docker-image-spec v1.3.1 // indirect
github.com/moby/patternmatcher v0.6.0 // indirect
github.com/moby/sys/sequential v0.5.0 // indirect
github.com/moby/sys/user v0.1.0 // indirect
github.com/moby/term v0.5.0 // 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
github.com/morikuni/aec v1.0.0 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/nats-io/nkeys v0.4.7 // indirect
github.com/nats-io/nuid v1.0.1 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.0.2 // indirect
github.com/opencontainers/runc v1.1.12 // indirect
github.com/pelletier/go-toml v1.9.4 // indirect
github.com/opencontainers/image-spec v1.1.0 // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
github.com/prometheus/client_golang v1.18.0 // indirect
github.com/prometheus/client_model v0.5.0 // indirect
github.com/prometheus/common v0.45.0 // indirect
github.com/prometheus/procfs v0.12.0 // indirect
github.com/sirupsen/logrus v1.9.0 // indirect
github.com/spf13/afero v1.9.2 // indirect
github.com/spf13/cast v1.4.1 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/subosito/gotenv v1.2.0 // indirect
github.com/sagikazarmark/locafero v0.4.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/shirou/gopsutil/v3 v3.23.12 // indirect
github.com/shoenig/go-m1cpu v0.1.6 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
github.com/spf13/afero v1.11.0 // indirect
github.com/spf13/cast v1.6.0 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
github.com/tklauser/go-sysconf v0.3.12 // indirect
github.com/tklauser/numcpus v0.6.1 // indirect
github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc // indirect
github.com/vmihailenco/bufpool v0.1.11 // indirect
github.com/vmihailenco/msgpack/v5 v5.3.4 // indirect
github.com/vmihailenco/tagparser v0.1.2 // indirect
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
github.com/xlab/treeprint v1.2.0 // indirect
go.etcd.io/etcd/client/pkg/v3 v3.5.10 // indirect
go.opencensus.io v0.24.0 // indirect
github.com/yusufpapurcu/wmi v1.2.3 // indirect
go.etcd.io/etcd/client/pkg/v3 v3.5.15 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect
go.opentelemetry.io/otel v1.24.0 // indirect
go.opentelemetry.io/otel/metric v1.24.0 // indirect
go.opentelemetry.io/otel/trace v1.24.0 // indirect
go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.26.0 // indirect
golang.org/x/crypto v0.21.0 // indirect
golang.org/x/exp v0.0.0-20220827204233-334a2380cb91 // indirect
golang.org/x/mod v0.15.0 // indirect
golang.org/x/net v0.23.0 // indirect
golang.org/x/oauth2 v0.12.0 // indirect
golang.org/x/sync v0.6.0 // indirect
golang.org/x/sys v0.18.0 // indirect
golang.org/x/term v0.18.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/time v0.3.0 // indirect
golang.org/x/tools v0.18.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20230726155614-23370e0ffb3e // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect
google.golang.org/grpc v1.58.3 // indirect
google.golang.org/protobuf v1.33.0 // indirect
golang.org/x/crypto v0.26.0 // indirect
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
golang.org/x/net v0.28.0 // indirect
golang.org/x/oauth2 v0.18.0 // indirect
golang.org/x/sync v0.8.0 // indirect
golang.org/x/sys v0.23.0 // indirect
golang.org/x/term v0.23.0 // indirect
golang.org/x/text v0.17.0 // indirect
golang.org/x/time v0.5.0 // indirect
golang.org/x/tools v0.24.0 // indirect
google.golang.org/appengine v1.6.8 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240311132316-a219d84964c2 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240314234333-6e1732d8331c // indirect
google.golang.org/grpc v1.62.1 // indirect
google.golang.org/protobuf v1.34.1 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/ini.v1 v1.66.2 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/apiextensions-apiserver v0.30.0 // indirect
k8s.io/cli-runtime v0.30.0 // indirect
k8s.io/component-base v0.30.0 // indirect
k8s.io/apiextensions-apiserver v0.30.1 // indirect
k8s.io/cli-runtime v0.30.1 // indirect
k8s.io/component-base v0.30.2 // indirect
k8s.io/component-helpers v0.0.0 // indirect
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect
k8s.io/kube-proxy v0.0.0 // indirect
k8s.io/system-validators v1.8.0 // indirect
mellium.im/sasl v0.3.0 // indirect
mellium.im/sasl v0.3.1 // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 // indirect
sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3 // indirect
@@ -162,33 +184,33 @@ require (
)
replace (
k8s.io/api => k8s.io/api v0.30.0
k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.30.0
k8s.io/apimachinery => k8s.io/apimachinery v0.30.0
k8s.io/apiserver => k8s.io/apiserver v0.30.0
k8s.io/cli-runtime => k8s.io/cli-runtime v0.30.0
k8s.io/client-go => k8s.io/client-go v0.30.0
k8s.io/cloud-provider => k8s.io/cloud-provider v0.30.0
k8s.io/cluster-bootstrap => k8s.io/cluster-bootstrap v0.30.0
k8s.io/code-generator => k8s.io/code-generator v0.30.0
k8s.io/component-base => k8s.io/component-base v0.30.0
k8s.io/component-helpers => k8s.io/component-helpers v0.30.0
k8s.io/controller-manager => k8s.io/controller-manager v0.30.0
k8s.io/cri-api => k8s.io/cri-api v0.30.0
k8s.io/csi-translation-lib => k8s.io/csi-translation-lib v0.30.0
k8s.io/dynamic-resource-allocation => k8s.io/dynamic-resource-allocation v0.30.0
k8s.io/endpointslice => k8s.io/endpointslice v0.30.0
k8s.io/kube-aggregator => k8s.io/kube-aggregator v0.30.0
k8s.io/kube-controller-manager => k8s.io/kube-controller-manager v0.30.0
k8s.io/kube-proxy => k8s.io/kube-proxy v0.30.0
k8s.io/kube-scheduler => k8s.io/kube-scheduler v0.30.0
k8s.io/kubectl => k8s.io/kubectl v0.30.0
k8s.io/kubelet => k8s.io/kubelet v0.30.0
k8s.io/legacy-cloud-providers => k8s.io/legacy-cloud-providers v0.30.0
k8s.io/metrics => k8s.io/metrics v0.30.0
k8s.io/mount-utils => k8s.io/mount-utils v0.30.0
k8s.io/pod-security-admission => k8s.io/pod-security-admission v0.30.0
k8s.io/sample-apiserver => k8s.io/sample-apiserver v0.30.0
k8s.io/api => k8s.io/api v0.30.2
k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.30.2
k8s.io/apimachinery => k8s.io/apimachinery v0.30.2
k8s.io/apiserver => k8s.io/apiserver v0.30.2
k8s.io/cli-runtime => k8s.io/cli-runtime v0.30.2
k8s.io/client-go => k8s.io/client-go v0.30.2
k8s.io/cloud-provider => k8s.io/cloud-provider v0.30.2
k8s.io/cluster-bootstrap => k8s.io/cluster-bootstrap v0.30.2
k8s.io/code-generator => k8s.io/code-generator v0.30.2
k8s.io/component-base => k8s.io/component-base v0.30.2
k8s.io/component-helpers => k8s.io/component-helpers v0.30.2
k8s.io/controller-manager => k8s.io/controller-manager v0.30.2
k8s.io/cri-api => k8s.io/cri-api v0.30.2
k8s.io/csi-translation-lib => k8s.io/csi-translation-lib v0.30.2
k8s.io/dynamic-resource-allocation => k8s.io/dynamic-resource-allocation v0.30.2
k8s.io/endpointslice => k8s.io/endpointslice v0.30.2
k8s.io/kube-aggregator => k8s.io/kube-aggregator v0.30.2
k8s.io/kube-controller-manager => k8s.io/kube-controller-manager v0.30.2
k8s.io/kube-proxy => k8s.io/kube-proxy v0.30.2
k8s.io/kube-scheduler => k8s.io/kube-scheduler v0.30.2
k8s.io/kubectl => k8s.io/kubectl v0.30.2
k8s.io/kubelet => k8s.io/kubelet v0.30.2
k8s.io/legacy-cloud-providers => k8s.io/legacy-cloud-providers v0.30.2
k8s.io/metrics => k8s.io/metrics v0.30.2
k8s.io/mount-utils => k8s.io/mount-utils v0.30.2
k8s.io/pod-security-admission => k8s.io/pod-security-admission v0.30.2
k8s.io/sample-apiserver => k8s.io/sample-apiserver v0.30.2
)
replace github.com/JamesStewy/go-mysqldump => github.com/vtoma/go-mysqldump v1.0.0

2485
go.sum

File diff suppressed because it is too large Load Diff

View File

@@ -61,7 +61,8 @@ func (d Deployment) Build(ctx context.Context, deployment *appsv1.Deployment, te
d.setLabels(deployment, utilities.MergeMaps(utilities.KamajiLabels(tenantControlPlane.GetName(), "deployment"), tenantControlPlane.Spec.ControlPlane.Deployment.AdditionalMetadata.Labels))
d.setAnnotations(deployment, utilities.MergeMaps(deployment.Annotations, tenantControlPlane.Spec.ControlPlane.Deployment.AdditionalMetadata.Annotations))
d.setTemplateLabels(&deployment.Spec.Template, d.templateLabels(ctx, &tenantControlPlane))
d.setTemplateLabels(&deployment.Spec.Template, utilities.MergeMaps(d.templateLabels(ctx, &tenantControlPlane), tenantControlPlane.Spec.ControlPlane.Deployment.PodAdditionalMetadata.Labels))
d.setTemplateAnnotations(&deployment.Spec.Template, tenantControlPlane.Spec.ControlPlane.Deployment.PodAdditionalMetadata.Annotations)
d.setNodeSelector(&deployment.Spec.Template.Spec, tenantControlPlane)
d.setToleration(&deployment.Spec.Template.Spec, tenantControlPlane)
d.setAffinity(&deployment.Spec.Template.Spec, tenantControlPlane)
@@ -76,6 +77,7 @@ func (d Deployment) Build(ctx context.Context, deployment *appsv1.Deployment, te
d.setContainers(&deployment.Spec.Template.Spec, tenantControlPlane, address)
d.setAdditionalVolumes(&deployment.Spec.Template.Spec, tenantControlPlane)
d.setVolumes(&deployment.Spec.Template.Spec, tenantControlPlane)
d.setServiceAccount(&deployment.Spec.Template.Spec, tenantControlPlane)
d.Client.Scheme().Default(deployment)
}
@@ -708,7 +710,7 @@ func (d Deployment) buildKubeAPIServerCommand(tenantControlPlane kamajiv1alpha1.
}
switch d.DataStore.Spec.Driver {
case kamajiv1alpha1.KineMySQLDriver, kamajiv1alpha1.KinePostgreSQLDriver:
case kamajiv1alpha1.KineMySQLDriver, kamajiv1alpha1.KinePostgreSQLDriver, kamajiv1alpha1.KineNatsDriver:
desiredArgs["--etcd-servers"] = "http://127.0.0.1:2379"
case kamajiv1alpha1.EtcdDriver:
httpsEndpoints := make([]string, 0, len(d.DataStore.Spec.Endpoints))
@@ -803,7 +805,10 @@ func (d Deployment) removeKineContainers(podSpec *corev1.PodSpec) {
podSpec.Containers = containers
}
// Removing the kine init-container, if present
d.removeKineInitContainers(podSpec)
}
func (d Deployment) removeKineInitContainers(podSpec *corev1.PodSpec) {
if found, index := utilities.HasNamedContainer(podSpec.InitContainers, kineInitContainerName); found {
var initContainers []corev1.Container
@@ -821,45 +826,67 @@ func (d Deployment) buildKine(podSpec *corev1.PodSpec, tcp kamajiv1alpha1.Tenant
return
}
// Ensuring the init container required for kine is present:
// a chmod is required for kine in order to read the certificates to connect to the secured datastore.
found, index := utilities.HasNamedContainer(podSpec.InitContainers, kineInitContainerName)
if !found {
index = len(podSpec.InitContainers)
podSpec.InitContainers = append(podSpec.InitContainers, corev1.Container{})
// Building kine arguments, taking in consideration the user-space ones if provided.
args := map[string]string{}
if d.DataStore.Spec.TLSConfig != nil {
// Ensuring the init container required for kine is present:
// a chmod is required for kine in order to read the certificates to connect to the secured datastore.
found, index := utilities.HasNamedContainer(podSpec.InitContainers, kineInitContainerName)
if !found {
index = len(podSpec.InitContainers)
podSpec.InitContainers = append(podSpec.InitContainers, corev1.Container{})
}
podSpec.InitContainers[index].Name = kineInitContainerName
podSpec.InitContainers[index].Image = d.KineContainerImage
podSpec.InitContainers[index].Command = []string{"sh"}
podSpec.InitContainers[index].Args = []string{
"-c",
"cp /kine/*.* /certs && chmod -R 600 /certs/*.*",
}
podSpec.InitContainers[index].VolumeMounts = []corev1.VolumeMount{
{
Name: dataStoreCertsVolumeName,
ReadOnly: true,
MountPath: "/kine",
},
{
Name: kineVolumeCertName,
MountPath: "/certs",
ReadOnly: false,
},
}
args["--ca-file"] = "/certs/ca.crt"
if d.DataStore.Spec.TLSConfig.ClientCertificate != nil {
args["--cert-file"] = "/certs/server.crt"
args["--key-file"] = "/certs/server.key"
}
} else {
// if no TLS configuration is provided, the kine initContainer must be removed.
d.removeKineInitContainers(podSpec)
}
podSpec.InitContainers[index].Name = kineInitContainerName
podSpec.InitContainers[index].Image = d.KineContainerImage
podSpec.InitContainers[index].Command = []string{"sh"}
podSpec.InitContainers[index].Args = []string{
"-c",
"cp /kine/*.* /certs && chmod -R 600 /certs/*.*",
}
podSpec.InitContainers[index].VolumeMounts = []corev1.VolumeMount{
{
Name: dataStoreCertsVolumeName,
ReadOnly: true,
MountPath: "/kine",
},
{
Name: kineVolumeCertName,
MountPath: "/certs",
ReadOnly: false,
},
}
// Kine is expecting an additional container, and it must be removed before proceeding with the additional one
// in order to make this function idempotent.
found, index = utilities.HasNamedContainer(podSpec.Containers, kineContainerName)
found, index := utilities.HasNamedContainer(podSpec.Containers, kineContainerName)
if !found {
index = len(podSpec.Containers)
podSpec.Containers = append(podSpec.Containers, corev1.Container{})
}
// Building kine arguments, taking in consideration the user-space ones if provided.
args := map[string]string{}
if tcp.Spec.ControlPlane.Deployment.ExtraArgs != nil {
args = utilities.ArgsFromSliceToMap(tcp.Spec.ControlPlane.Deployment.ExtraArgs.Kine)
utilArgs := utilities.ArgsFromSliceToMap(tcp.Spec.ControlPlane.Deployment.ExtraArgs.Kine)
// Merging the user-space arguments with the Kamaji ones.
for k, v := range utilArgs {
args[k] = v
}
}
switch d.DataStore.Spec.Driver {
@@ -867,12 +894,10 @@ func (d Deployment) buildKine(podSpec *corev1.PodSpec, tcp kamajiv1alpha1.Tenant
args["--endpoint"] = "mysql://$(DB_USER):$(DB_PASSWORD)@tcp($(DB_CONNECTION_STRING))/$(DB_SCHEMA)"
case kamajiv1alpha1.KinePostgreSQLDriver:
args["--endpoint"] = "postgres://$(DB_USER):$(DB_PASSWORD)@$(DB_CONNECTION_STRING)/$(DB_SCHEMA)"
case kamajiv1alpha1.KineNatsDriver:
args["--endpoint"] = "nats://$(DB_USER):$(DB_PASSWORD)@$(DB_CONNECTION_STRING)?bucket=$(DB_SCHEMA)&noEmbed"
}
args["--ca-file"] = "/certs/ca.crt"
args["--cert-file"] = "/certs/server.crt"
args["--key-file"] = "/certs/server.key"
podSpec.Containers[index].Name = kineContainerName
podSpec.Containers[index].Image = d.KineContainerImage
podSpec.Containers[index].Command = []string{"/bin/kine"}
@@ -999,6 +1024,10 @@ func (d Deployment) setTemplateLabels(template *corev1.PodTemplateSpec, labels m
template.SetLabels(labels)
}
func (d Deployment) setTemplateAnnotations(template *corev1.PodTemplateSpec, annotations map[string]string) {
template.SetAnnotations(annotations)
}
func (d Deployment) setLabels(resource *appsv1.Deployment, labels map[string]string) {
resource.SetLabels(labels)
}
@@ -1064,3 +1093,13 @@ func (d Deployment) setToleration(spec *corev1.PodSpec, tcp kamajiv1alpha1.Tenan
func (d Deployment) setAffinity(spec *corev1.PodSpec, tcp kamajiv1alpha1.TenantControlPlane) {
spec.Affinity = tcp.Spec.ControlPlane.Deployment.Affinity
}
func (d Deployment) setServiceAccount(spec *corev1.PodSpec, tcp kamajiv1alpha1.TenantControlPlane) {
if len(tcp.Spec.ControlPlane.Deployment.ServiceAccountName) > 0 {
spec.ServiceAccountName = tcp.Spec.ControlPlane.Deployment.ServiceAccountName
return
}
spec.ServiceAccountName = "default"
}

View File

@@ -21,18 +21,26 @@ func NewStorageConnection(ctx context.Context, client client.Client, ds kamajiv1
switch ds.Spec.Driver {
case kamajiv1alpha1.KineMySQLDriver:
cc.TLSConfig.ServerName = cc.Endpoints[0].Host
if ds.Spec.TLSConfig != nil {
cc.TLSConfig.ServerName = cc.Endpoints[0].Host
}
cc.Parameters = map[string][]string{
"multiStatements": {"true"},
}
return NewMySQLConnection(*cc)
case kamajiv1alpha1.KinePostgreSQLDriver:
cc.TLSConfig.ServerName = cc.Endpoints[0].Host
if ds.Spec.TLSConfig != nil {
cc.TLSConfig.ServerName = cc.Endpoints[0].Host
}
return NewPostgreSQLConnection(*cc)
case kamajiv1alpha1.EtcdDriver:
return NewETCDConnection(*cc)
case kamajiv1alpha1.KineNatsDriver:
return NewNATSConnection(*cc)
default:
return nil, fmt.Errorf("%s is not a valid driver", ds.Spec.Driver)
}

View File

@@ -23,7 +23,7 @@ type ConnectionEndpoint struct {
}
func (r ConnectionEndpoint) String() string {
return fmt.Sprintf("%s:%d", r.Host, r.Port)
return net.JoinHostPort(r.Host, strconv.FormatInt(int64(r.Port), 10))
}
type ConnectionConfig struct {
@@ -36,29 +36,41 @@ type ConnectionConfig struct {
}
func NewConnectionConfig(ctx context.Context, client client.Client, ds kamajiv1alpha1.DataStore) (*ConnectionConfig, error) {
ca, err := ds.Spec.TLSConfig.CertificateAuthority.Certificate.GetContent(ctx, client)
if err != nil {
return nil, err
var tlsConfig *tls.Config
if ds.Spec.TLSConfig != nil {
ca, err := ds.Spec.TLSConfig.CertificateAuthority.Certificate.GetContent(ctx, client)
if err != nil {
return nil, err
}
rootCAs := x509.NewCertPool()
if ok := rootCAs.AppendCertsFromPEM(ca); !ok {
return nil, fmt.Errorf("error create root CA for the DB connector")
}
tlsConfig = &tls.Config{
RootCAs: rootCAs,
}
}
crt, err := ds.Spec.TLSConfig.ClientCertificate.Certificate.GetContent(ctx, client)
if err != nil {
return nil, err
}
if ds.Spec.TLSConfig != nil && ds.Spec.TLSConfig.ClientCertificate != nil {
crt, err := ds.Spec.TLSConfig.ClientCertificate.Certificate.GetContent(ctx, client)
if err != nil {
return nil, err
}
key, err := ds.Spec.TLSConfig.ClientCertificate.PrivateKey.GetContent(ctx, client)
if err != nil {
return nil, err
}
key, err := ds.Spec.TLSConfig.ClientCertificate.PrivateKey.GetContent(ctx, client)
if err != nil {
return nil, err
}
rootCAs := x509.NewCertPool()
if ok := rootCAs.AppendCertsFromPEM(ca); !ok {
return nil, fmt.Errorf("error create root CA for the DB connector")
}
certificate, err := tls.X509KeyPair(crt, key)
if err != nil {
return nil, errors.Wrap(err, "cannot retrieve x.509 key pair from the Kine Secret")
}
certificate, err := tls.X509KeyPair(crt, key)
if err != nil {
return nil, errors.Wrap(err, "cannot retrieve x.509 key pair from the Kine Secret")
tlsConfig.Certificates = []tls.Certificate{certificate}
}
var user, password string
@@ -99,10 +111,7 @@ func NewConnectionConfig(ctx context.Context, client client.Client, ds kamajiv1a
User: user,
Password: password,
Endpoints: eps,
TLSConfig: &tls.Config{
RootCAs: rootCAs,
Certificates: []tls.Certificate{certificate},
},
TLSConfig: tlsConfig,
}, nil
}

View File

@@ -16,13 +16,6 @@ import (
"github.com/clastix/kamaji/internal/datastore/errors"
)
const (
// rangeEnd is the key following the last key of the range.
// If rangeEnd is \0, the range is all keys greater than or equal to the key argument
// source: https://etcd.io/docs/v3.5/learning/api/
rangeEnd = "\\0"
)
func NewETCDConnection(config ConnectionConfig) (Connection, error) {
endpoints := make([]string, 0, len(config.Endpoints))
@@ -68,7 +61,8 @@ func (e *EtcdClient) GrantPrivileges(ctx context.Context, user, dbName string) e
permission := etcdclient.PermissionType(authpb.READWRITE)
key := e.buildKey(dbName)
if _, err := e.Client.RoleGrantPermission(ctx, user, key, rangeEnd, permission); err != nil {
if _, err := e.Client.RoleGrantPermission(ctx, user, key, etcdclient.GetPrefixRangeEnd(key), permission); err != nil {
return errors.NewGrantPrivilegesError(err)
}
@@ -170,6 +164,13 @@ func (e *EtcdClient) Driver() string {
return string(kamajiv1alpha1.EtcdDriver)
}
// buildKey adds slashes to the beginning and end of the key. This ensures that the range
// end for etcd RBAC is calculated using the entire key prefix, not only the key name. If
// the range end was calculated e.g. for `/cp-a`, the result would be `/cp-b`, which also
// includes `/cp-aa` (etcd uses lexicographic ordering on key ranges for RBAC). Using
// `/cp-a/` as the input for the range end calculation results in `/cp-a0`, which doesn't
// allow for any other potential control plane key prefixes to be located within the range.
// For more information, see also https://etcd.io/docs/v3.3/learning/api/#key-ranges
func (e *EtcdClient) buildKey(key string) string {
return fmt.Sprintf("/%s/", key)
}
@@ -181,7 +182,9 @@ func (e *EtcdClient) Migrate(ctx context.Context, tcp kamajiv1alpha1.TenantContr
return err
}
response, err := e.Client.Get(ctx, e.buildKey(fmt.Sprintf("%s_%s", tcp.GetNamespace(), tcp.GetName())), etcdclient.WithRange(rangeEnd))
key := e.buildKey(fmt.Sprintf("%s_%s", tcp.GetNamespace(), tcp.GetName()))
response, err := e.Client.Get(ctx, key, etcdclient.WithPrefix())
if err != nil {
return err
}

View File

@@ -112,12 +112,14 @@ func NewMySQLConnection(config ConnectionConfig) (Connection, error) {
tlsKey := "mysql"
if err = mysql.RegisterTLSConfig(tlsKey, config.TLSConfig); err != nil {
return nil, err
if config.TLSConfig != nil {
if err = mysql.RegisterTLSConfig(tlsKey, config.TLSConfig); err != nil {
return nil, err
}
mysqlConfig.TLSConfig = tlsKey
}
mysqlConfig.DBName = config.DBName
mysqlConfig.TLSConfig = tlsKey
parsedDSN := mysqlConfig.FormatDSN()
db, err := sql.Open("mysql", parsedDSN)

184
internal/datastore/nats.go Normal file
View File

@@ -0,0 +1,184 @@
// Copyright 2022 Clastix Labs
// SPDX-License-Identifier: Apache-2.0
package datastore
import (
"context"
"fmt"
"strings"
"github.com/nats-io/nats.go"
"github.com/pkg/errors"
kamajiv1alpha1 "github.com/clastix/kamaji/api/v1alpha1"
)
// NATSConnection represents a connection to a NATS KV store.
type NATSConnection struct {
js nats.JetStreamContext
conn *nats.Conn
config ConnectionConfig
}
// NewNATSConnection initializes a connection to NATS and sets up the KV store.
func NewNATSConnection(config ConnectionConfig) (*NATSConnection, error) {
var endpoints string
if len(config.Endpoints) > 1 {
// comma separated list of endpoints
var ep []string
for _, e := range config.Endpoints {
ep = append(ep, fmt.Sprintf("nats://%s", e.String()))
}
endpoints = strings.Join(ep, ",")
} else {
endpoints = fmt.Sprintf("nats://%s", config.Endpoints[0].String())
}
var conn *nats.Conn
var err error
var natsOpts []nats.Option
if config.TLSConfig != nil {
natsOpts = append(natsOpts, nats.Secure(config.TLSConfig))
}
if config.User != "" && config.Password != "" {
natsOpts = append(natsOpts, nats.UserInfo(config.User, config.Password))
}
conn, err = nats.Connect(endpoints, natsOpts...)
if err != nil {
return nil, err
}
js, err := conn.JetStream()
if err != nil {
return nil, err
}
return &NATSConnection{
js: js,
conn: conn,
config: config,
}, nil
}
func (nc *NATSConnection) CreateUser(_ context.Context, _, _ string) error {
return nil
}
func (nc *NATSConnection) CreateDB(_ context.Context, dbName string) error {
_, err := nc.js.CreateKeyValue(&nats.KeyValueConfig{Bucket: dbName})
if err != nil {
return errors.Wrap(err, "unable to create the datastore")
}
return nil
}
func (nc *NATSConnection) GrantPrivileges(_ context.Context, _, _ string) error {
return nil
}
func (nc *NATSConnection) UserExists(_ context.Context, _ string) (bool, error) {
return true, nil
}
func (nc *NATSConnection) DBExists(_ context.Context, dbName string) (bool, error) {
_, err := nc.js.KeyValue(dbName)
if err != nil {
if errors.Is(err, nats.ErrBucketNotFound) {
return false, nil
}
return false, err
}
return true, nil
}
func (nc *NATSConnection) GrantPrivilegesExists(_ context.Context, _, _ string) (bool, error) {
return true, nil
}
func (nc *NATSConnection) DeleteUser(_ context.Context, _ string) error {
return nil
}
func (nc *NATSConnection) DeleteDB(_ context.Context, dbName string) error {
err := nc.js.DeleteKeyValue(dbName)
return err
}
func (nc *NATSConnection) RevokePrivileges(_ context.Context, _, _ string) error {
return nil
}
func (nc *NATSConnection) GetConnectionString() string {
return nc.config.Endpoints[0].String()
}
func (nc *NATSConnection) Close() error {
return nc.conn.Drain()
}
func (nc *NATSConnection) Check(_ context.Context) error {
status := nc.conn.Status()
if status != nats.CONNECTED {
return errors.New("connection to NATS is not established")
}
return nil
}
func (nc *NATSConnection) Driver() string {
return string(kamajiv1alpha1.KineNatsDriver)
}
func (nc *NATSConnection) GetConfig() ConnectionConfig {
return nc.config
}
func (nc *NATSConnection) Migrate(ctx context.Context, tcp kamajiv1alpha1.TenantControlPlane, target Connection) error {
targetClient := target.(*NATSConnection) //nolint:forcetypeassert
dbName := tcp.Status.Storage.Setup.Schema
targetKv, err := targetClient.js.KeyValue(dbName)
if err != nil {
return err
}
sourceKv, err := nc.js.KeyValue(dbName)
if err != nil {
return err
}
if err := target.Check(ctx); err != nil {
return err
}
// copy all keys from source to target
keys, err := sourceKv.Keys()
if err != nil {
return err
}
for _, key := range keys {
entry, err := sourceKv.Get(key)
if err != nil {
return err
}
_, err = targetKv.Put(key, entry.Value())
if err != nil {
return err
}
}
return nil
}

View File

@@ -10,6 +10,7 @@ import (
"strings"
"github.com/go-pg/pg/v10"
goerrors "github.com/pkg/errors"
kamajiv1alpha1 "github.com/clastix/kamaji/api/v1alpha1"
"github.com/clastix/kamaji/internal/datastore/errors"
@@ -34,6 +35,7 @@ const (
type PostgreSQLConnection struct {
db *pg.DB
connection ConnectionEndpoint
rootUser string
switchDatabaseFn func(dbName string) *pg.DB
}
@@ -114,6 +116,7 @@ func NewPostgreSQLConnection(config ConnectionConfig) (Connection, error) {
return &PostgreSQLConnection{
db: pg.Connect(opt),
switchDatabaseFn: fn,
rootUser: config.User,
connection: config.Endpoints[0],
}, nil
}
@@ -232,6 +235,10 @@ func (r *PostgreSQLConnection) DeleteUser(ctx context.Context, user string) erro
}
func (r *PostgreSQLConnection) DeleteDB(ctx context.Context, dbName string) error {
if err := r.GrantPrivileges(ctx, r.rootUser, dbName); err != nil {
return errors.NewCannotDeleteDatabaseError(goerrors.Wrap(err, "cannot grant privileges to root user"))
}
if _, err := r.db.ExecContext(ctx, fmt.Sprintf(postgresqlDropDBStatement, dbName)); err != nil {
return errors.NewCannotDeleteDatabaseError(err)
}

View File

@@ -46,7 +46,6 @@ func (r *Certificate) Define(_ context.Context, tenantControlPlane *kamajiv1alph
Name: r.getPrefixedName(tenantControlPlane),
Namespace: tenantControlPlane.GetNamespace(),
},
Data: map[string][]byte{},
}
return nil
@@ -80,79 +79,93 @@ func (r *Certificate) mutate(ctx context.Context, tenantControlPlane *kamajiv1al
return func() error {
logger := log.FromContext(ctx, "resource", r.GetName())
ca, err := r.DataStore.Spec.TLSConfig.CertificateAuthority.Certificate.GetContent(ctx, r.Client)
if err != nil {
logger.Error(err, "cannot retrieve CA certificate content")
if r.DataStore.Spec.TLSConfig != nil {
ca, err := r.DataStore.Spec.TLSConfig.CertificateAuthority.Certificate.GetContent(ctx, r.Client)
if err != nil {
logger.Error(err, "cannot retrieve CA certificate content")
return err
}
return err
}
r.resource.Data["ca.crt"] = ca
if r.resource.Data == nil {
r.resource.Data = map[string][]byte{}
}
r.resource.SetLabels(utilities.MergeMaps(
utilities.KamajiLabels(tenantControlPlane.GetName(), r.GetName()),
map[string]string{
constants.ControllerLabelResource: "x509",
},
))
r.resource.Data["ca.crt"] = ca
if err = ctrl.SetControllerReference(tenantControlPlane, r.resource, r.Client.Scheme()); err != nil {
logger.Error(err, "cannot set controller reference", "resource", r.GetName())
r.resource.SetLabels(utilities.MergeMaps(
utilities.KamajiLabels(tenantControlPlane.GetName(), r.GetName()),
map[string]string{
constants.ControllerLabelResource: "x509",
},
))
return err
}
if err = ctrl.SetControllerReference(tenantControlPlane, r.resource, r.Client.Scheme()); err != nil {
logger.Error(err, "cannot set controller reference", "resource", r.GetName())
if utilities.GetObjectChecksum(r.resource) == utilities.CalculateMapChecksum(r.resource.Data) {
if r.DataStore.Spec.Driver == kamajiv1alpha1.EtcdDriver {
if isValid, _ := crypto.IsValidCertificateKeyPairBytes(r.resource.Data["server.crt"], r.resource.Data["server.key"]); isValid {
return nil
return err
}
if utilities.GetObjectChecksum(r.resource) == utilities.CalculateMapChecksum(r.resource.Data) {
if r.DataStore.Spec.Driver == kamajiv1alpha1.EtcdDriver {
if isValid, _ := crypto.IsValidCertificateKeyPairBytes(r.resource.Data["server.crt"], r.resource.Data["server.key"]); isValid {
return nil
}
}
}
var crt, key *bytes.Buffer
switch r.DataStore.Spec.Driver {
case kamajiv1alpha1.EtcdDriver:
var privateKey []byte
// When dealing with the etcd storage we cannot use the basic authentication, thus the generation of a
// certificate used for authentication is mandatory, along with the CA private key.
if privateKey, err = r.DataStore.Spec.TLSConfig.CertificateAuthority.PrivateKey.GetContent(ctx, r.Client); err != nil {
logger.Error(err, "unable to retrieve CA private key content")
return err
}
if crt, key, err = crypto.GenerateCertificatePrivateKeyPair(crypto.NewCertificateTemplate(tenantControlPlane.Status.Storage.Setup.User), ca, privateKey); err != nil {
logger.Error(err, "unable to generate certificate and private key")
return err
}
case kamajiv1alpha1.KineMySQLDriver, kamajiv1alpha1.KinePostgreSQLDriver, kamajiv1alpha1.KineNatsDriver:
var crtBytes, keyBytes []byte
// For the SQL drivers we just need to copy the certificate, since the basic authentication is used
// to connect to the desired schema and database.
if r.DataStore.Spec.TLSConfig.ClientCertificate != nil {
if crtBytes, err = r.DataStore.Spec.TLSConfig.ClientCertificate.Certificate.GetContent(ctx, r.Client); err != nil {
logger.Error(err, "unable to retrieve certificate content")
return err
}
crt = bytes.NewBuffer(crtBytes)
if keyBytes, err = r.DataStore.Spec.TLSConfig.ClientCertificate.PrivateKey.GetContent(ctx, r.Client); err != nil {
logger.Error(err, "unable to retrieve private key content")
return err
}
key = bytes.NewBuffer(keyBytes)
}
default:
return fmt.Errorf("unrecognized driver for Certificate generation")
}
if r.DataStore.Spec.TLSConfig.ClientCertificate != nil {
r.resource.Data["server.crt"] = crt.Bytes()
r.resource.Data["server.key"] = key.Bytes()
}
} else {
// set r.resource.Data to empty to allow switching from TLS to non-tls
r.resource.Data = map[string][]byte{}
}
var crt, key *bytes.Buffer
switch r.DataStore.Spec.Driver {
case kamajiv1alpha1.EtcdDriver:
var privateKey []byte
// When dealing with the etcd storage we cannot use the basic authentication, thus the generation of a
// certificate used for authentication is mandatory, along with the CA private key.
if privateKey, err = r.DataStore.Spec.TLSConfig.CertificateAuthority.PrivateKey.GetContent(ctx, r.Client); err != nil {
logger.Error(err, "unable to retrieve CA private key content")
return err
}
if crt, key, err = crypto.GenerateCertificatePrivateKeyPair(crypto.NewCertificateTemplate(tenantControlPlane.Status.Storage.Setup.User), ca, privateKey); err != nil {
logger.Error(err, "unable to generate certificate and private key")
return err
}
case kamajiv1alpha1.KineMySQLDriver, kamajiv1alpha1.KinePostgreSQLDriver:
var crtBytes, keyBytes []byte
// For the SQL drivers we just need to copy the certificate, since the basic authentication is used
// to connect to the desired schema and database.
if crtBytes, err = r.DataStore.Spec.TLSConfig.ClientCertificate.Certificate.GetContent(ctx, r.Client); err != nil {
logger.Error(err, "unable to retrieve certificate content")
return err
}
crt = bytes.NewBuffer(crtBytes)
if keyBytes, err = r.DataStore.Spec.TLSConfig.ClientCertificate.PrivateKey.GetContent(ctx, r.Client); err != nil {
logger.Error(err, "unable to retrieve private key content")
return err
}
key = bytes.NewBuffer(keyBytes)
default:
return fmt.Errorf("unrecognized driver for Certificate generation")
}
r.resource.Data["server.crt"] = crt.Bytes()
r.resource.Data["server.key"] = key.Bytes()
utilities.SetObjectChecksum(r.resource, r.resource.Data)
return nil

View File

@@ -0,0 +1,62 @@
// Copyright 2022 Clastix Labs
// SPDX-License-Identifier: Apache-2.0
package datastore
import (
"context"
"github.com/pkg/errors"
"k8s.io/apimachinery/pkg/util/sets"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
kamajiv1alpha1 "github.com/clastix/kamaji/api/v1alpha1"
)
type MultiTenancy struct {
DataStore kamajiv1alpha1.DataStore
}
func (m MultiTenancy) Define(context.Context, *kamajiv1alpha1.TenantControlPlane) error {
return nil
}
func (m MultiTenancy) ShouldCleanup(*kamajiv1alpha1.TenantControlPlane) bool {
return false
}
func (m MultiTenancy) CleanUp(context.Context, *kamajiv1alpha1.TenantControlPlane) (bool, error) {
return false, nil
}
func (m MultiTenancy) CreateOrUpdate(_ context.Context, tcp *kamajiv1alpha1.TenantControlPlane) (controllerutil.OperationResult, error) {
// If the NATS Datastore is already used by a Tenant Control Plane
// and a new one is reclaiming it, we need to stop it, since it's not allowed.
// TODO(prometherion): remove this after multi-tenancy is implemented for NATS.
if m.DataStore.Spec.Driver != kamajiv1alpha1.KineNatsDriver {
return controllerutil.OperationResultNone, nil
}
usedBy := sets.New[string](m.DataStore.Status.UsedBy...)
switch {
case usedBy.Has(tcp.Namespace + "/" + tcp.Name):
return controllerutil.OperationResultNone, nil
case usedBy.Len() == 0:
return controllerutil.OperationResultNone, nil
default:
return controllerutil.OperationResultNone, errors.New("NATS doesn't support multi-tenancy, the current datastore is already in use")
}
}
func (m MultiTenancy) GetName() string {
return "ds.multitenancy"
}
func (m MultiTenancy) ShouldStatusBeUpdated(context.Context, *kamajiv1alpha1.TenantControlPlane) bool {
return false
}
func (m MultiTenancy) UpdateTenantControlPlaneStatus(context.Context, *kamajiv1alpha1.TenantControlPlane) error {
return nil
}

View File

@@ -104,9 +104,10 @@ func (r *Config) UpdateTenantControlPlaneStatus(_ context.Context, tenantControl
return nil
}
func (r *Config) mutate(_ context.Context, tenantControlPlane *kamajiv1alpha1.TenantControlPlane) controllerutil.MutateFn {
func (r *Config) mutate(ctx context.Context, tenantControlPlane *kamajiv1alpha1.TenantControlPlane) controllerutil.MutateFn {
return func() error {
var password []byte
var username []byte
hash := utilities.GetObjectChecksum(r.resource)
switch {
@@ -133,10 +134,31 @@ func (r *Config) mutate(_ context.Context, tenantControlPlane *kamajiv1alpha1.Te
finalizersList.Insert(finalizers.DatastoreSecretFinalizer)
r.resource.SetFinalizers(finalizersList.UnsortedList())
// TODO(thecodeassassin): remove this after multi-tenancy is implemented for NATS.
// Due to NATS is missing a programmatic approach to create users and password,
// we're using the Datastore root password.
if r.DataStore.Spec.Driver == kamajiv1alpha1.KineNatsDriver {
// set username and password to the basicAuth values of the NATS datastore
u, err := r.DataStore.Spec.BasicAuth.Username.GetContent(ctx, r.Client)
if err != nil {
return errors.Wrap(err, "failed to retrieve the username for the NATS datastore")
}
p, err := r.DataStore.Spec.BasicAuth.Password.GetContent(ctx, r.Client)
if err != nil {
return errors.Wrap(err, "failed to retrieve the password for the NATS datastore")
}
username = u
password = p
} else {
username = coalesceFn(tenantControlPlane.Status.Storage.Setup.User)
}
r.resource.Data = map[string][]byte{
"DB_CONNECTION_STRING": []byte(r.ConnString),
"DB_SCHEMA": coalesceFn(tenantControlPlane.Status.Storage.Setup.Schema),
"DB_USER": coalesceFn(tenantControlPlane.Status.Storage.Setup.User),
"DB_USER": username,
"DB_PASSWORD": password,
}

View File

@@ -30,20 +30,49 @@ func (r *KubernetesIngressResource) ShouldStatusBeUpdated(_ context.Context, tcp
case tcp.Spec.ControlPlane.Ingress == nil && tcp.Status.Kubernetes.Ingress == nil:
// No update in case of no ingress in spec, neither in status.
return false
case tcp.Spec.ControlPlane.Ingress != nil && tcp.Status.Kubernetes.Ingress == nil,
// Must be updated when TCP is using an Ingress, and status is not tracking it
// or
// Must be updated when the status is referring to an Ingress, although spec doesn't.
tcp.Spec.ControlPlane.Ingress == nil && tcp.Status.Kubernetes.Ingress != nil:
case tcp.Spec.ControlPlane.Ingress != nil && tcp.Status.Kubernetes.Ingress == nil, // TCP is using an Ingress, Status not tracking it
tcp.Spec.ControlPlane.Ingress == nil && tcp.Status.Kubernetes.Ingress != nil: // Status tracks an Ingress, Spec doesn't
return true
case len(r.resource.Status.LoadBalancer.Ingress) > 0 && tcp.Status.Kubernetes.Ingress == nil || tcp.Status.Kubernetes.Ingress.LoadBalancer.Ingress == nil:
// Must be updated since missing the Ingress status
return true
case r.resource.Status.LoadBalancer.Ingress[0].IP != tcp.Status.Kubernetes.Ingress.LoadBalancer.Ingress[0].IP:
// Must bne updated, Ingress load balancer IP is slightly different
case len(tcp.Status.Kubernetes.Ingress.IngressStatus.LoadBalancer.Ingress) != len(r.resource.Status.LoadBalancer.Ingress):
// Mismatch count of tracked LoadBalancer Ingress
return true
default:
return tcp.Status.Kubernetes.Ingress.Name != r.resource.GetName() || tcp.Status.Kubernetes.Ingress.Namespace != r.resource.GetNamespace()
statusIngress := tcp.Status.Kubernetes.Ingress.IngressStatus.LoadBalancer.Ingress
for i, ingress := range r.resource.Status.LoadBalancer.Ingress {
if ingress.IP != statusIngress[i].IP {
return true
}
if len(ingress.Ports) != len(statusIngress[i].Ports) {
return true
}
for p, port := range ingress.Ports {
if port.Port != statusIngress[i].Ports[p].Port {
return true
}
if port.Protocol != statusIngress[i].Ports[p].Protocol {
return true
}
if port.Error == nil && statusIngress[i].Ports[p].Error != nil ||
port.Error != nil && statusIngress[i].Ports[p].Error == nil {
return true
}
if port.Error == nil && statusIngress[i].Ports[p].Error == nil {
continue
}
if *port.Error != *statusIngress[i].Ports[p].Error {
return true
}
}
}
return false
}
}

View File

@@ -5,7 +5,8 @@ package resources
import (
"context"
"fmt"
"net"
"strconv"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -53,8 +54,7 @@ func (r *KubernetesServiceResource) UpdateTenantControlPlaneStatus(ctx context.C
return err
}
tenantControlPlane.Status.ControlPlaneEndpoint = fmt.Sprintf("%s:%d", address, tenantControlPlane.Spec.NetworkProfile.Port)
tenantControlPlane.Status.ControlPlaneEndpoint = net.JoinHostPort(address, strconv.FormatInt(int64(tenantControlPlane.Spec.NetworkProfile.Port), 10))
return nil
}

View File

@@ -126,12 +126,7 @@ func (r *Agent) mutate(ctx context.Context, tenantControlPlane *kamajiv1alpha1.T
))
r.resource.Spec.Template.Spec.PriorityClassName = "system-cluster-critical"
r.resource.Spec.Template.Spec.Tolerations = []corev1.Toleration{
{
Key: "CriticalAddonsOnly",
Operator: "Exists",
},
}
r.resource.Spec.Template.Spec.Tolerations = tenantControlPlane.Spec.Addons.Konnectivity.KonnectivityAgentSpec.Tolerations
r.resource.Spec.Template.Spec.NodeSelector = map[string]string{
"kubernetes.io/os": "linux",
}

View File

@@ -5,7 +5,8 @@ package resources
import (
"context"
"fmt"
"net"
"strconv"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -74,7 +75,7 @@ func (r *KubeadmConfigResource) getControlPlaneEndpoint(ingress *kamajiv1alpha1.
address, port = utilities.GetControlPlaneAddressAndPortFromHostname(ingress.Hostname, port)
}
return fmt.Sprintf("%s:%d", address, port)
return net.JoinHostPort(address, strconv.FormatInt(int64(port), 10))
}
func (r *KubeadmConfigResource) mutate(ctx context.Context, tenantControlPlane *kamajiv1alpha1.TenantControlPlane) controllerutil.MutateFn {

View File

@@ -4,5 +4,5 @@
package upgrade
const (
KubeadmVersion = "v1.30.0"
KubeadmVersion = "v1.30.2"
)

View File

@@ -14,13 +14,7 @@ func ArgsFromSliceToMap(args []string) (m map[string]string) {
m = make(map[string]string)
for _, arg := range args {
parts := strings.SplitN(arg, "=", 2)
flag, value := parts[0], ""
if len(parts) > 1 {
value = parts[1]
}
flag, value, _ := strings.Cut(arg, "=")
m[flag] = value
}

View File

@@ -0,0 +1,30 @@
// Copyright 2022 Clastix Labs
// SPDX-License-Identifier: Apache-2.0
package utilities
import (
"maps"
"testing"
)
func TestArgsFromSliceToMap(t *testing.T) {
tests := map[string]map[string]string{
"--a": {"--a": ""},
"--a=": {"--a": ""},
"--a=b": {"--a": "b"},
"--a=b=c": {"--a": "b=c"},
}
got := ArgsFromSliceToMap([]string{})
if len(got) != 0 {
t.Errorf("expected empty input to result in empty map, but got %+v", got)
}
for arg, expect := range tests {
got := ArgsFromSliceToMap([]string{arg})
if !maps.Equal(expect, got) {
t.Errorf("expected input %q to result in %+v, but got %+v", arg, expect, got)
}
}
}

View File

@@ -60,7 +60,7 @@ func GetRESTClientConfig(ctx context.Context, client client.Client, tenantContro
}
config := &restclient.Config{
Host: fmt.Sprintf("https://%s.%s.svc.cluster.local:%d", tenantControlPlane.GetName(), tenantControlPlane.GetNamespace(), tenantControlPlane.Spec.NetworkProfile.Port),
Host: fmt.Sprintf("https://%s.%s.svc:%d", tenantControlPlane.GetName(), tenantControlPlane.GetNamespace(), tenantControlPlane.Spec.NetworkProfile.Port),
TLSClientConfig: restclient.TLSClientConfig{
CAData: kubeconfig.Clusters[0].Cluster.CertificateAuthorityData,
CertData: kubeconfig.AuthInfos[0].AuthInfo.ClientCertificateData,

Some files were not shown because too many files have changed in this diff Show More