mirror of
https://github.com/cozystack/cozystack.git
synced 2026-03-07 15:38:55 +00:00
Compare commits
3 Commits
lineage-co
...
openapi-al
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
759d64c738 | ||
|
|
79a9c11430 | ||
|
|
55d8e46345 |
2
.github/workflows/pre-commit.yml
vendored
2
.github/workflows/pre-commit.yml
vendored
@@ -28,7 +28,7 @@ jobs:
|
||||
|
||||
- name: Install generate
|
||||
run: |
|
||||
curl -sSL https://github.com/cozystack/cozyvalues-gen/releases/download/v0.8.5/cozyvalues-gen-linux-amd64.tar.gz | tar -xzvf- -C /usr/local/bin/ cozyvalues-gen
|
||||
curl -sSL https://github.com/cozystack/cozyvalues-gen/releases/download/v0.8.4/cozyvalues-gen-linux-amd64.tar.gz | tar -xzvf- -C /usr/local/bin/ cozyvalues-gen
|
||||
|
||||
- name: Run pre-commit hooks
|
||||
run: |
|
||||
|
||||
15
.github/workflows/pull-requests.yaml
vendored
15
.github/workflows/pull-requests.yaml
vendored
@@ -1,7 +1,7 @@
|
||||
name: Pull Request
|
||||
|
||||
env:
|
||||
REGISTRY: ${{ vars.OCIR_REPO }}
|
||||
REGISTRY: ${{ secrets.OCIR_REPO }}
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened]
|
||||
@@ -32,14 +32,7 @@ jobs:
|
||||
fetch-depth: 0
|
||||
fetch-tags: true
|
||||
|
||||
- name: Set up Docker config
|
||||
run: |
|
||||
if [ -d ~/.docker ]; then
|
||||
cp -r ~/.docker "${{ runner.temp }}/.docker"
|
||||
fi
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
if: ${{ !github.event.pull_request.head.repo.fork }}
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.OCIR_USER}}
|
||||
@@ -261,11 +254,6 @@ jobs:
|
||||
done
|
||||
echo "✅ The task completed successfully after $attempt attempts."
|
||||
|
||||
- name: Run OpenAPI tests
|
||||
run: |
|
||||
cd /tmp/$SANDBOX_NAME
|
||||
make -C packages/core/testing SANDBOX_NAME=$SANDBOX_NAME test-openapi
|
||||
|
||||
detect_test_matrix:
|
||||
name: "Detect e2e test matrix"
|
||||
runs-on: ubuntu-latest
|
||||
@@ -281,7 +269,6 @@ jobs:
|
||||
|
||||
test_apps:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix: ${{ fromJson(needs.detect_test_matrix.outputs.matrix) }}
|
||||
name: Test ${{ matrix.app }}
|
||||
runs-on: [self-hosted]
|
||||
|
||||
1
Makefile
1
Makefile
@@ -18,7 +18,6 @@ build: build-deps
|
||||
make -C packages/system/cilium image
|
||||
make -C packages/system/kubeovn image
|
||||
make -C packages/system/kubeovn-webhook image
|
||||
make -C packages/system/kubeovn-plunger image
|
||||
make -C packages/system/dashboard image
|
||||
make -C packages/system/metallb image
|
||||
make -C packages/system/kamaji image
|
||||
|
||||
@@ -38,7 +38,6 @@ import (
|
||||
|
||||
cozystackiov1alpha1 "github.com/cozystack/cozystack/api/v1alpha1"
|
||||
"github.com/cozystack/cozystack/internal/controller"
|
||||
"github.com/cozystack/cozystack/internal/controller/lineagelabeler"
|
||||
"github.com/cozystack/cozystack/internal/telemetry"
|
||||
|
||||
helmv2 "github.com/fluxcd/helm-controller/api/v2"
|
||||
@@ -68,7 +67,6 @@ func main() {
|
||||
var telemetryEndpoint string
|
||||
var telemetryInterval string
|
||||
var cozystackVersion string
|
||||
var watchResources string
|
||||
var tlsOpts []func(*tls.Config)
|
||||
flag.StringVar(&metricsAddr, "metrics-bind-address", "0", "The address the metrics endpoint binds to. "+
|
||||
"Use :8443 for HTTPS or :8080 for HTTP, or leave as 0 to disable the metrics service.")
|
||||
@@ -88,9 +86,6 @@ func main() {
|
||||
"Interval between telemetry data collection (e.g. 15m, 1h)")
|
||||
flag.StringVar(&cozystackVersion, "cozystack-version", "unknown",
|
||||
"Version of Cozystack")
|
||||
flag.StringVar(&watchResources, "watch-resources",
|
||||
"v1/Pod,v1/Service,v1/Secret,v1/PersistentVolumeClaim",
|
||||
"Comma-separated list of resources to watch in the form 'group/version/Kind'.")
|
||||
opts := zap.Options{
|
||||
Development: false,
|
||||
}
|
||||
@@ -219,15 +214,6 @@ func main() {
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if err := (&lineagelabeler.LineageLabelerReconciler{
|
||||
Client: mgr.GetClient(),
|
||||
Scheme: mgr.GetScheme(),
|
||||
WatchResourceCSV: watchResources,
|
||||
}).SetupWithManager(mgr); err != nil {
|
||||
setupLog.Error(err, "unable to create controller", "controller", "LineageLabeler")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// +kubebuilder:scaffold:builder
|
||||
|
||||
if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil {
|
||||
|
||||
@@ -1,176 +0,0 @@
|
||||
/*
|
||||
Copyright 2025.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"flag"
|
||||
"os"
|
||||
|
||||
// Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.)
|
||||
// to ensure that exec-entrypoint and run can make use of them.
|
||||
_ "k8s.io/client-go/plugin/pkg/client/auth"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/healthz"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log/zap"
|
||||
"sigs.k8s.io/controller-runtime/pkg/metrics"
|
||||
"sigs.k8s.io/controller-runtime/pkg/metrics/filters"
|
||||
metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"
|
||||
"sigs.k8s.io/controller-runtime/pkg/webhook"
|
||||
|
||||
"github.com/cozystack/cozystack/internal/controller/kubeovnplunger"
|
||||
// +kubebuilder:scaffold:imports
|
||||
)
|
||||
|
||||
var (
|
||||
scheme = runtime.NewScheme()
|
||||
setupLog = ctrl.Log.WithName("setup")
|
||||
)
|
||||
|
||||
func init() {
|
||||
utilruntime.Must(clientgoscheme.AddToScheme(scheme))
|
||||
|
||||
// +kubebuilder:scaffold:scheme
|
||||
}
|
||||
|
||||
func main() {
|
||||
var metricsAddr string
|
||||
var enableLeaderElection bool
|
||||
var probeAddr string
|
||||
var kubeOVNNamespace string
|
||||
var ovnCentralName string
|
||||
var secureMetrics bool
|
||||
var enableHTTP2 bool
|
||||
var disableTelemetry bool
|
||||
var tlsOpts []func(*tls.Config)
|
||||
flag.StringVar(&metricsAddr, "metrics-bind-address", "0", "The address the metrics endpoint binds to. "+
|
||||
"Use :8443 for HTTPS or :8080 for HTTP, or leave as 0 to disable the metrics service.")
|
||||
flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.")
|
||||
flag.StringVar(&kubeOVNNamespace, "kube-ovn-namespace", "cozy-kubeovn", "Namespace where kube-OVN is deployed.")
|
||||
flag.StringVar(&ovnCentralName, "ovn-central-name", "ovn-central", "Ovn-central deployment name.")
|
||||
flag.BoolVar(&enableLeaderElection, "leader-elect", false,
|
||||
"Enable leader election for controller manager. "+
|
||||
"Enabling this will ensure there is only one active controller manager.")
|
||||
flag.BoolVar(&secureMetrics, "metrics-secure", true,
|
||||
"If set, the metrics endpoint is served securely via HTTPS. Use --metrics-secure=false to use HTTP instead.")
|
||||
flag.BoolVar(&enableHTTP2, "enable-http2", false,
|
||||
"If set, HTTP/2 will be enabled for the metrics and webhook servers")
|
||||
flag.BoolVar(&disableTelemetry, "disable-telemetry", false,
|
||||
"Disable telemetry collection")
|
||||
opts := zap.Options{
|
||||
Development: false,
|
||||
}
|
||||
opts.BindFlags(flag.CommandLine)
|
||||
flag.Parse()
|
||||
|
||||
ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts)))
|
||||
|
||||
// if the enable-http2 flag is false (the default), http/2 should be disabled
|
||||
// due to its vulnerabilities. More specifically, disabling http/2 will
|
||||
// prevent from being vulnerable to the HTTP/2 Stream Cancellation and
|
||||
// Rapid Reset CVEs. For more information see:
|
||||
// - https://github.com/advisories/GHSA-qppj-fm5r-hxr3
|
||||
// - https://github.com/advisories/GHSA-4374-p667-p6c8
|
||||
disableHTTP2 := func(c *tls.Config) {
|
||||
setupLog.Info("disabling http/2")
|
||||
c.NextProtos = []string{"http/1.1"}
|
||||
}
|
||||
|
||||
if !enableHTTP2 {
|
||||
tlsOpts = append(tlsOpts, disableHTTP2)
|
||||
}
|
||||
|
||||
webhookServer := webhook.NewServer(webhook.Options{
|
||||
TLSOpts: tlsOpts,
|
||||
})
|
||||
|
||||
// Metrics endpoint is enabled in 'config/default/kustomization.yaml'. The Metrics options configure the server.
|
||||
// More info:
|
||||
// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.19.1/pkg/metrics/server
|
||||
// - https://book.kubebuilder.io/reference/metrics.html
|
||||
metricsServerOptions := metricsserver.Options{
|
||||
BindAddress: metricsAddr,
|
||||
SecureServing: secureMetrics,
|
||||
TLSOpts: tlsOpts,
|
||||
}
|
||||
|
||||
if secureMetrics {
|
||||
// FilterProvider is used to protect the metrics endpoint with authn/authz.
|
||||
// These configurations ensure that only authorized users and service accounts
|
||||
// can access the metrics endpoint. The RBAC are configured in 'config/rbac/kustomization.yaml'. More info:
|
||||
// https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.19.1/pkg/metrics/filters#WithAuthenticationAndAuthorization
|
||||
metricsServerOptions.FilterProvider = filters.WithAuthenticationAndAuthorization
|
||||
|
||||
// TODO(user): If CertDir, CertName, and KeyName are not specified, controller-runtime will automatically
|
||||
// generate self-signed certificates for the metrics server. While convenient for development and testing,
|
||||
// this setup is not recommended for production.
|
||||
}
|
||||
|
||||
mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
|
||||
Scheme: scheme,
|
||||
Metrics: metricsServerOptions,
|
||||
WebhookServer: webhookServer,
|
||||
HealthProbeBindAddress: probeAddr,
|
||||
LeaderElection: enableLeaderElection,
|
||||
LeaderElectionID: "29a0338b.cozystack.io",
|
||||
// LeaderElectionReleaseOnCancel defines if the leader should step down voluntarily
|
||||
// when the Manager ends. This requires the binary to immediately end when the
|
||||
// Manager is stopped, otherwise, this setting is unsafe. Setting this significantly
|
||||
// speeds up voluntary leader transitions as the new leader don't have to wait
|
||||
// LeaseDuration time first.
|
||||
//
|
||||
// In the default scaffold provided, the program ends immediately after
|
||||
// the manager stops, so would be fine to enable this option. However,
|
||||
// if you are doing or is intended to do any operation such as perform cleanups
|
||||
// after the manager stops then its usage might be unsafe.
|
||||
// LeaderElectionReleaseOnCancel: true,
|
||||
})
|
||||
if err != nil {
|
||||
setupLog.Error(err, "unable to create manager")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if err = (&kubeovnplunger.KubeOVNPlunger{
|
||||
Client: mgr.GetClient(),
|
||||
Scheme: mgr.GetScheme(),
|
||||
Registry: metrics.Registry,
|
||||
}).SetupWithManager(mgr, kubeOVNNamespace, ovnCentralName); err != nil {
|
||||
setupLog.Error(err, "unable to create controller", "controller", "KubeOVNPlunger")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// +kubebuilder:scaffold:builder
|
||||
|
||||
if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil {
|
||||
setupLog.Error(err, "unable to set up health check")
|
||||
os.Exit(1)
|
||||
}
|
||||
if err := mgr.AddReadyzCheck("readyz", healthz.Ping); err != nil {
|
||||
setupLog.Error(err, "unable to set up ready check")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
setupLog.Info("starting manager")
|
||||
if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
|
||||
setupLog.Error(err, "problem running manager")
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,3 @@
|
||||
|
||||
<!--
|
||||
https://github.com/cozystack/cozystack/releases/tag/v0..
|
||||
-->
|
||||
|
||||
## Major Features and Improvements
|
||||
|
||||
## Security
|
||||
@@ -14,7 +9,3 @@ https://github.com/cozystack/cozystack/releases/tag/v0..
|
||||
## Documentation
|
||||
|
||||
## Development, Testing, and CI/CD
|
||||
|
||||
---
|
||||
|
||||
**Full Changelog**: **Full Changelog**: https://github.com/cozystack/cozystack/compare/v0.34.0...v0.35.0
|
||||
|
||||
@@ -129,7 +129,7 @@ For more information, read the [Cozystack Release Workflow](https://github.com/c
|
||||
* [platform] Reduce requested CPU and RAM for the `kamaji` provider. (@klinch0 in https://github.com/cozystack/cozystack/pull/825)
|
||||
* [platform] Improve the reconciliation loop for the Cozystack system HelmReleases logic. (@klinch0 in https://github.com/cozystack/cozystack/pull/809 and https://github.com/cozystack/cozystack/pull/810, @kvaps in https://github.com/cozystack/cozystack/pull/811)
|
||||
* [platform] Remove extra dependencies for the Piraeus operator. (@klinch0 in https://github.com/cozystack/cozystack/pull/856)
|
||||
* [platform] Refactor dashboard values. (@kvaps in https://github.com/cozystack/cozystack/pull/928, patched by @lllamnyp in https://github.com/cozystack/cozystack/pull/952)
|
||||
* [platform] Refactor dashboard values. (@kvaps in https://github.com/cozystack/cozystack/pull/928, patched by @llamnyp in https://github.com/cozystack/cozystack/pull/952)
|
||||
* [platform] Make FluxCD artifact disabled by default. (@klinch0 in https://github.com/cozystack/cozystack/pull/964)
|
||||
* [kubernetes] Update garbage collection of HelmReleases in tenant Kubernetes clusters. (@kvaps in https://github.com/cozystack/cozystack/pull/835)
|
||||
* [kubernetes] Fix merging `valuesOverride` for tenant clusters. (@kvaps in https://github.com/cozystack/cozystack/pull/879)
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
Cozystack v0.34.0 is a stable release.
|
||||
It focuses on cluster reliability, virtualization capabilities, and enhancements to the Cozystack API.
|
||||
|
||||
<!--
|
||||
https://github.com/cozystack/cozystack/releases/tag/v0.34.0
|
||||
-->
|
||||
|
||||
> [!WARNING]
|
||||
> A regression was found in this release and fixed in patch [0.34.3](https://github.com/cozystack/cozystack/releases/tag/v0.34.3).
|
||||
> When upgrading Cozystack, it's recommended to skip this version and upgrade directly to [0.34.3](https://github.com/cozystack/cozystack/releases/tag/v0.34.3).
|
||||
|
||||
|
||||
## Major Features and Improvements
|
||||
|
||||
* [kubernetes] Enable users to select Kubernetes versions in tenant clusters. Supported versions range from 1.28 to 1.33, updated to the latest patches. (@lllamnyp and @IvanHunters in https://github.com/cozystack/cozystack/pull/1202)
|
||||
* [kubernetes] Enable PVC snapshot capability in tenant Kubernetes clusters. (@klinch0 in https://github.com/cozystack/cozystack/pull/1203)
|
||||
* [vpa] Implement autoscaling for the Vertical Pod Autoscaler itself, ensuring that VPA has sufficient resources and reducing the number of configuration parameters that platform administrators have to manage. (@lllamnyp in https://github.com/cozystack/cozystack/pull/1198)
|
||||
* [vm-instance] Enable running [Windows](https://cozystack.io/docs/operations/virtualization/windows/) and [MikroTik RouterOS](https://cozystack.io/docs/operations/virtualization/mikrotik/) in Cozystack. Add `bus` option and always specify `bootOrder` for all disks. (@kvaps in https://github.com/cozystack/cozystack/pull/1168)
|
||||
* [cozystack-api] Specify OpenAPI schema for apps. (@kvaps in https://github.com/cozystack/cozystack/pull/1174)
|
||||
* [cozystack-api] Refactor OpenAPI Schema and support reading it from config. (@kvaps in https://github.com/cozystack/cozystack/pull/1173)
|
||||
* [cozystack-api] Enable using singular resource names in Cozystack API. For example, `kubectl get tenant` is now a valid command, in addition to `kubectl get tenants`. (@kvaps in https://github.com/cozystack/cozystack/pull/1169)
|
||||
* [postgres] Explain how to back up and restore PostgreSQL using Velero backups. (@klinch0 and @NickVolynkin in https://github.com/cozystack/cozystack/pull/1141)
|
||||
* [seaweedfs] Support multi-zone configuration for S3 storage. (@kvaps in https://github.com/cozystack/cozystack/pull/1194)
|
||||
* [dashboard] Put YAML editor first when deploying and upgrading applications, as a more powerful option. Fix handling multiline strings. (@kvaps in https://github.com/cozystack/cozystack/pull/1227)
|
||||
|
||||
## Security
|
||||
|
||||
* [seaweedfs] Ensure that JWT signing keys in the SeaweedFS security configuration remain consistent across Helm upgrades. Resolve an upstream issue. (@kvaps in https://github.com/cozystack/cozystack/pull/1193 and https://github.com/seaweedfs/seaweedfs/pull/6967)
|
||||
|
||||
## Fixes
|
||||
|
||||
* [cozystack-controller] Fix stale workloads not being deleted when marked for deletion. (@lllamnyp in https://github.com/cozystack/cozystack/pull/1210, @kvaps in https://github.com/cozystack/cozystack/pull/1229)
|
||||
* [cozystack-controller] Improve reliability when updating HelmRelease objects to prevent unintended changes during reconciliation. (@klinch0 in https://github.com/cozystack/cozystack/pull/1205)
|
||||
* [kubevirt-csi] Fix a regression by updating the role of the CSI controller. (@lllamnyp in https://github.com/cozystack/cozystack/pull/1165)
|
||||
* [virtual-machine,vm-instance] Adjusted RBAC role to let users read the service associated with the VMs they create. Consequently, users can now see details of the service in the dashboard and therefore read the IP address of the VM. (@klinch0 in https://github.com/cozystack/cozystack/pull/1161)
|
||||
* [virtual-machine] Fix cloudInit and sshKeys processing. (@kvaps in https://github.com/cozystack/cozystack/pull/1175 and https://github.com/cozystack/cozystack/commit/da3ee5d0ea9e87529c8adc4fcccffabe8782292e)
|
||||
* [cozystack-api] Fix an error with `resourceVersion` which resulted in message 'failed to update HelmRelease: helmreleases.helm.toolkit.fluxcd.io "xxx" is invalid...'. (@kvaps in https://github.com/cozystack/cozystack/pull/1170)
|
||||
* [cozystack-api] Fix an error in updating lists in Cozystack objects, which resulted in message "Warning: resource ... is missing the kubectl.kubernetes.io/last-applied-configuration annotation". (@kvaps in https://github.com/cozystack/cozystack/pull/1171)
|
||||
* [cozystack-api] Disable `strategic-json-patch` support. (@kvaps in https://github.com/cozystack/cozystack/pull/1179)
|
||||
* [cozystack-api] Fix non-existing OpenAPI references. (@kvaps in https://github.com/cozystack/cozystack/pull/1208)
|
||||
* [dashboard] Fix the code for removing dashboard comments which used to mistakenly remove shebang from `cloudInit` scripts. (@kvaps in https://github.com/cozystack/cozystack/pull/1175).
|
||||
* [applications] Reorder configuration values in application README's for better readability. (@NickVolynkin in https://github.com/cozystack/cozystack/pull/1214)
|
||||
* [applications] Disallow selecting `resourcePreset = none` in the visual editor when deploying and upgrading applications. (@NickVolynkin in https://github.com/cozystack/cozystack/pull/1196)
|
||||
* [applications] Fix a typo in preset resource tables in the built-in documentation of managed applications. (@NickVolynkin in https://github.com/cozystack/cozystack/pull/1172)
|
||||
* [kubernetes] Enable deleting Velero component from a tenant Kubernetes cluster. (@klinch0 in https://github.com/cozystack/cozystack/pull/1176)
|
||||
* [kubernetes] Explicitly mention available K8s versions for tenant clusters in the README. (@NickVolynkin in https://github.com/cozystack/cozystack/pull/1212)
|
||||
* [oidc] Enable deleting Keycloak service. (@klinch0 in https://github.com/cozystack/cozystack/pull/1178)
|
||||
* [tenant] Enable deleting extra applications from a tenant. (@klinch0 and @kvaps and in https://github.com/cozystack/cozystack/pull/1162)
|
||||
* [nats] Fix a typo in the application template. (@klinch0 in https://github.com/cozystack/cozystack/pull/1195)
|
||||
* [postgres] Resolve an issue with the visibility of PostgreSQL load balancer on the dashboard. (@klinch0 https://github.com/cozystack/cozystack/pull/1204)
|
||||
* [objectstorage] Update COSI controller and sidecar, including fixes from upstream. (@kvaps in https://github.com/cozystack/cozystack/pull/1209, https://github.com/kubernetes-sigs/container-object-storage-interface/pull/89, and https://github.com/kubernetes-sigs/container-object-storage-interface/pull/90)
|
||||
|
||||
|
||||
## Dependencies
|
||||
|
||||
* Update FerretDB from v1 to v2.4.0.<br>**Breaking change:** before upgrading FerretDB instances, back up and restore the data following the [migration guide](https://docs.ferretdb.io/migration/migrating-from-v1/). (@kvaps in https://github.com/cozystack/cozystack/pull/1206)
|
||||
* Update Talos Linux to v1.10.5. (@kvaps in https://github.com/cozystack/cozystack/pull/1186)
|
||||
* Update LINSTOR to v1.31.2. (@kvaps in https://github.com/cozystack/cozystack/pull/1180)
|
||||
* Update KubeVirt to v1.5.2. (@kvaps in https://github.com/cozystack/cozystack/pull/1183)
|
||||
* Update CDI to v1.62.0. (@kvaps in https://github.com/cozystack/cozystack/pull/1183)
|
||||
* Update Flux Operator to 0.24.0. (@kingdonb in https://github.com/cozystack/cozystack/pull/1167)
|
||||
* Update Kamaji to edge-25.7.1. (@kvaps in https://github.com/cozystack/cozystack/pull/1184)
|
||||
* Update Kube-OVN to v1.13.14. (@kvaps in https://github.com/cozystack/cozystack/pull/1182)
|
||||
* Update Cilium to v1.17.5. (@kvaps in https://github.com/cozystack/cozystack/pull/1181)
|
||||
* Update MariaDB Operator to v0.38.1. (@kvaps in https://github.com/cozystack/cozystack/pull/1188)
|
||||
* Update SeaweedFS to v3.94. (@kvaps in https://github.com/cozystack/cozystack/pull/1194)
|
||||
|
||||
|
||||
## Documentation
|
||||
|
||||
* [Updated Cozystack Roadmap and Backlog for 2024-2026](https://cozystack.io/docs/roadmap/). (@tym83 and @kvapsova in https://github.com/cozystack/website/pull/249)
|
||||
* [Running Windows VMs](https://cozystack.io/docs/operations/virtualization/windows/). (@kvaps and @NickVolynkin in https://github.com/cozystack/website/pull/246)
|
||||
* [Running MikroTik RouterOS VMs](https://cozystack.io/docs/operations/virtualization/mikrotik/). (@kvaps and @NickVolynkin in https://github.com/cozystack/website/pull/247)
|
||||
* [Public-network Kubernetes Deployment](https://cozystack.io/docs/operations/faq/#public-network-kubernetes-deployment). (@klinch0 and @NickVolynkin in https://github.com/cozystack/website/pull/242)
|
||||
* [How to allocate space on system disk for user storage](https://cozystack.io/docs/operations/faq/#how-to-allocate-space-on-system-disk-for-user-storage). (@klinch0 and @NickVolynkin in https://github.com/cozystack/website/pull/242)
|
||||
* [Resource Management in Cozystack](https://cozystack.io/docs/guides/resource-management/). (@NickVolynkin in https://github.com/cozystack/website/pull/233)
|
||||
* [Key Concepts of Cozystack](https://cozystack.io/docs/guides/concepts/). (@NickVolynkin in https://github.com/cozystack/website/pull/254)
|
||||
* [Cozystack Architecture and Platform Stack](https://cozystack.io/docs/guides/platform-stack/). (@NickVolynkin in https://github.com/cozystack/website/pull/252)
|
||||
* Fixed a parameter in Kubespan: `cluster.discovery.enabled = true`. (@lb0o in https://github.com/cozystack/website/pull/241)
|
||||
* Updated the Linux Foundation trademark text on the Cozystack website. (@krook in https://github.com/cozystack/website/pull/251)
|
||||
* Auto-update the managed applications reference pages. (@NickVolynkin in https://github.com/cozystack/website/pull/243 and https://github.com/cozystack/website/pull/245)
|
||||
|
||||
## Development, Testing, and CI/CD
|
||||
|
||||
* [ci] Improve workflow for contributors submitting PRs from forks. Use Oracle Cloud Infrastructure Registry for non-release PRs, bypassing restrictions preventing pushing to ghcr.io with default GitHub token. (@lllamnyp in https://github.com/cozystack/cozystack/pull/1226)
|
||||
|
||||
**Full Changelog**: https://github.com/cozystack/cozystack/compare/v0.33.0...v0.34.0
|
||||
@@ -1,15 +0,0 @@
|
||||
<!--
|
||||
https://github.com/cozystack/cozystack/releases/tag/v0.34.1
|
||||
-->
|
||||
|
||||
> [!WARNING]
|
||||
> A regression was found in this release and fixed in patch [0.34.3](https://github.com/cozystack/cozystack/releases/tag/v0.34.3).
|
||||
> When upgrading Cozystack, it's recommended to skip this version and upgrade directly to [0.34.3](https://github.com/cozystack/cozystack/releases/tag/v0.34.3).
|
||||
|
||||
|
||||
## Fixes
|
||||
|
||||
* [kubernetes] Fix regression in `volumesnapshotclass` installation from https://github.com/cozystack/cozystack/pull/1203. (@kvaps in https://github.com/cozystack/cozystack/pull/1238)
|
||||
* [objectstorage] Fix building objectstorage images. (@kvaps in https://github.com/cozystack/cozystack/commit/a9e9dfca1fadde1bf2b4e100753e0731bbcfe923)
|
||||
|
||||
**Full Changelog**: https://github.com/cozystack/cozystack/compare/v0.34.0...v0.34.1
|
||||
@@ -1,14 +0,0 @@
|
||||
<!--
|
||||
https://github.com/cozystack/cozystack/releases/tag/v0.34.2
|
||||
-->
|
||||
|
||||
> [!WARNING]
|
||||
> A regression was found in this release and fixed in patch [0.34.3](https://github.com/cozystack/cozystack/releases/tag/v0.34.3).
|
||||
> When upgrading Cozystack, it's recommended to skip this version and upgrade directly to [0.34.3](https://github.com/cozystack/cozystack/releases/tag/v0.34.3).
|
||||
|
||||
|
||||
## Fixes
|
||||
|
||||
* [objectstorage] Fix recording image in objectstorage. (@kvaps in https://github.com/cozystack/cozystack/commit/4d9a8389d6bc7e86d63dd976ec853b374a91a637)
|
||||
|
||||
**Full Changelog**: https://github.com/cozystack/cozystack/compare/v0.34.1...v0.34.2
|
||||
@@ -1,13 +0,0 @@
|
||||
<!--
|
||||
https://github.com/cozystack/cozystack/releases/tag/v0.34.3
|
||||
-->
|
||||
|
||||
## Fixes
|
||||
|
||||
* [tenant] Fix tenant network policy to allow traffic to additional tenant-related services across namespace hierarchies. (@klinch0 in https://github.com/cozystack/cozystack/pull/1232, backported in https://github.com/cozystack/cozystack/pull/1272)
|
||||
* [kubernetes] Add dependency for snapshot CRD and migration to latest version. (@kvaps in https://github.com/cozystack/cozystack/pull/1275, backported in https://github.com/cozystack/cozystack/pull/1279)
|
||||
* [seaweedfs] Add support for whitelisting and exporting via nginx-ingress. Update cosi-driver. (@kvaps in https://github.com/cozystack/cozystack/pull/1277)
|
||||
* [kubevirt] Fix building Kubevirt CCM (@kvaps in 3c7e256906e1dbb0f957dc3a205fa77a147d419d)
|
||||
* [virtual-machine] Fix a regression with field `optional=true`. (@kvaps in https://github.com/cozystack/cozystack/commit/01053f7c3180d1bd045d7c5fb949984c2bdaf19d)
|
||||
|
||||
**Full Changelog**: https://github.com/cozystack/cozystack/compare/v0.34.2...v0.34.3
|
||||
@@ -1,21 +0,0 @@
|
||||
<!--
|
||||
https://github.com/cozystack/cozystack/releases/tag/v0.34.4
|
||||
-->
|
||||
|
||||
## Security
|
||||
|
||||
* [keycloak] Store administrative passwords in the management cluster's secrets. (@IvanHunters in https://github.com/cozystack/cozystack/pull/1286)
|
||||
* [keycloak] Update Keycloak client redirect URI to use HTTPS instead of HTTP. Enable `cookie-secure`. (@klinch0 in https://github.com/cozystack/cozystack/pull/1287, backported in https://github.com/cozystack/cozystack/pull/1291)
|
||||
|
||||
|
||||
## Fixes
|
||||
|
||||
* [kubernetes] Resolve problems with pod names exceeding allowed length by shortening the name of volume snapshot CRD from `*-volumesnapshot-crd-for-tenant-k8s` to `*-vsnap-crd`. To apply this change, update each affected tenant Kubernetes cluster after updating Cozystack. (@klinch0 in https://github.com/cozystack/cozystack/pull/1284)
|
||||
* [cozystack-api] Show correct `kind` values of `ApplicationList`. (@kvaps in https://github.com/cozystack/cozystack/pull/1290, backported in https://github.com/cozystack/cozystack/pull/1293)
|
||||
|
||||
|
||||
## Development, Testing, and CI/CD
|
||||
|
||||
* [tests] Add tests for S3 buckets. (@IvanHunters in https://github.com/cozystack/cozystack/pull/1283, backported in https://github.com/cozystack/cozystack/pull/1292)
|
||||
|
||||
**Full Changelog**: https://github.com/cozystack/cozystack/compare/v0.34.3...v0.34.4
|
||||
@@ -1,11 +0,0 @@
|
||||
<!--
|
||||
https://github.com/cozystack/cozystack/releases/tag/v0.34.5
|
||||
-->
|
||||
|
||||
|
||||
## Fixes
|
||||
|
||||
* [virtual-machine] Enable using custom `instanceType` values in `virtual-machine` and `vm-instance` by disabling field validation. (@lllamnyp in https://github.com/cozystack/cozystack/pull/1300, backported in https://github.com/cozystack/cozystack/pull/1303)
|
||||
* [kubernetes] Disable VPA for VPA in tenant Kubernetes clusters. Tenant clusters have no need for this feature, and it was not designed to work in a tenant cluster, but was enabled by mistake. (@lllamnyp in https://github.com/cozystack/cozystack/pull/1301, backported in https://github.com/cozystack/cozystack/pull/1305)
|
||||
|
||||
**Full Changelog**: https://github.com/cozystack/cozystack/compare/v0.34.4...v0.34.5
|
||||
@@ -1,9 +0,0 @@
|
||||
<!--
|
||||
https://github.com/cozystack/cozystack/releases/tag/v0.34.6
|
||||
-->
|
||||
|
||||
## Fixes
|
||||
|
||||
* [dashboard] Fix filling multiline values in the visual editor. (@kvaps in https://github.com/cozystack/cozystack/commit/56fca9bd75efeca25f9483f6c514b6fec26d5d22 and https://github.com/cozystack/kubeapps/commit/4926bc68fabb0914afab574006643c85a597b371)
|
||||
|
||||
**Full Changelog**: https://github.com/cozystack/cozystack/compare/v0.34.5...v0.34.6
|
||||
@@ -1,11 +0,0 @@
|
||||
<!--
|
||||
https://github.com/cozystack/cozystack/releases/tag/v0.34.7
|
||||
-->
|
||||
|
||||
## Fixes
|
||||
|
||||
* [seaweedfs] Disable proxy buffering and proxy request buffering for ingress. (@kvaps in https://github.com/cozystack/cozystack/pull/1330, backported in https://github.com/cozystack/cozystack/commit/96d462e911d4458704b596533d3f10e4b5e80862)
|
||||
* [linstor] Update LINSTOR monitoring configuration to use label `controller_node` instead of `node`. (@kvaps in https://github.com/cozystack/cozystack/pull/1326, backported in https://github.com/cozystack/cozystack/pull/1327)
|
||||
* [kubernetes] Disable VPA for VPA in tenant Kubernetes clusters, patched a fix from v0.34.5. (@lllamnyp in https://github.com/cozystack/cozystack/pull/1318, backported in https://github.com/cozystack/cozystack/pull/1319)
|
||||
|
||||
**Full Changelog**: https://github.com/cozystack/cozystack/compare/v0.34.6...v0.34.7
|
||||
@@ -1,11 +0,0 @@
|
||||
<!--
|
||||
https://github.com/cozystack/cozystack/releases/tag/v0.34.8
|
||||
-->
|
||||
|
||||
## Fixes
|
||||
|
||||
* [etcd] Fix `topologySpreadConstraints`. (@klinch0 in https://github.com/cozystack/cozystack/pull/1331, backported in https://github.com/cozystack/cozystack/pull/1332)
|
||||
* [linstor] Update LINSTOR monitoring configuration: switch labels on `linstor-satellite` and `linstor-controller`. (@kvaps in https://github.com/cozystack/cozystack/pull/1335, backported in https://github.com/cozystack/cozystack/pull/1336)
|
||||
* [kamaji] Fix broken migration jobs originating from missing environment variables in the in-tree build. (@lllamnyp in https://github.com/cozystack/cozystack/pull/1338, backported in https://github.com/cozystack/cozystack/pull/1340)
|
||||
|
||||
**Full Changelog**: https://github.com/cozystack/cozystack/compare/v0.34.7...v0.34.8
|
||||
@@ -1,138 +0,0 @@
|
||||
<!--
|
||||
https://github.com/cozystack/cozystack/releases/tag/v0.35.0
|
||||
-->
|
||||
|
||||
## Feature Highlights
|
||||
|
||||
### External Application Sources in Cozystack
|
||||
|
||||
Cozystack now supports adding external application packages to the platform's application catalog.
|
||||
Platform administrators can include custom or third-party applications alongside built-in ones, using the Cozystack API.
|
||||
|
||||
Adding an application requires making an application package, similar to the ones included in Cozystack
|
||||
under [`packages/apps`](https://github.com/cozystack/cozystack/tree/main/packages/apps).
|
||||
Using external packages is enabled by a new CustomResourceDefinition (CRD) called `CozystackResourceDefinition` and
|
||||
a corresponding controller (reconciler) that watches for these resources.
|
||||
|
||||
Add your own managed application using the [documentation](https://cozystack.io/docs/applications/external/)
|
||||
and an example at [github.com/cozystack/external-apps-example](https://github.com/cozystack/external-apps-example).
|
||||
|
||||
<!--
|
||||
* [platform] Enable using external application packages by adding a `CozystackResourceDefinition` reconciler. Read the documentation on [adding external applications to Cozystack](https://cozystack.io/docs/applications/external/) to learn more. (@klinch0 in https://github.com/cozystack/cozystack/pull/1313)
|
||||
* [cozystack-api] Provide an API for administrators to define custom managed applications alongside existing managed apps. (@klinch in https://github.com/cozystack/cozystack/pull/1230)
|
||||
-->
|
||||
|
||||
|
||||
### Cozystack API Improvements
|
||||
|
||||
This release brings significant improvements to the OpenAPI specs for all managed applications in Cozystack,
|
||||
including databases, tenant Kubernetes, virtual machines, monitoring, and others.
|
||||
These changes include more precise type definitions for fields that were previously defined only as generic objects,
|
||||
and many fields now have value constraints.
|
||||
Now many possible misconfigurations are detected immediately upon API request, and not later, with a failed deployment.
|
||||
|
||||
The Cozystack API now also displays default values for the application resources.
|
||||
Most other fields now have sane default values when such values are possible.
|
||||
|
||||
All these changes pave the road for the new Cozystack UI, which is currently under development.
|
||||
|
||||
### Hetzner RobotLB Support
|
||||
|
||||
MetalLB, the default load balancer included in Cozystack, is built for bare metal and self-hosted VMs,
|
||||
but is not supported on most cloud providers.
|
||||
For example, Hetzner provides its own RobotLB service, which Cozystack now supports as an optional component.
|
||||
|
||||
Read the updated guide on [deploying Cozystack on Hetzner.com](https://cozystack.io/docs/install/providers/hetzner/)
|
||||
to learn more and deploy your own Cozystack cluster on Hetzner.
|
||||
|
||||
### S3 Service: Dedicated Clusters and Monitoring
|
||||
|
||||
You can now deploy dedicated Cozystack clusters to run the S3 service, powered by SeaweedFS.
|
||||
Thanks to the support for [integration with remote filer endpoints](https://cozystack.io/docs/operations/stretched/seaweedfs-multidc/),
|
||||
you can connect your primary Cozystack cluster to use S3 storage in a dedicated cluster.
|
||||
|
||||
For security, platform administrators can now configure the SeaweedFS application with
|
||||
a list of IP addresses or CIDR ranges that are allowed to access the filer service.
|
||||
|
||||
SeaweedFS has also been integrated into the monitoring stack and now has its own Grafana dashboard.
|
||||
Together, these enhancements help Cozystack users build a more reliable, scalable, and observable S3 service.
|
||||
|
||||
### ClickHouse Keeper
|
||||
|
||||
The ClickHouse application now includes a ClickHouse Keeper service to improve cluster reliability and availability.
|
||||
This component is deployed by default with every ClickHouse cluster.
|
||||
|
||||
Learn more in the [ClickHouse configuration reference](https://cozystack.io/docs/applications/clickhouse/#clickhouse-keeper-parameters).
|
||||
|
||||
## Major Features and Improvements
|
||||
|
||||
* [platform] Enable using external application packages by adding a `CozystackResourceDefinition` reconciler. Read the documentation on [adding external applications to Cozystack](https://cozystack.io/docs/applications/external/) to learn more. (@klinch0 in https://github.com/cozystack/cozystack/pull/1313)
|
||||
* [cozystack-api, apps] Add default values, clear type definitions, value constraints and other improvements to the OpenAPI specs and READMEs by migrating to [cozyvalue-gen](https://github.com/cozystack/cozyvalues-gen). (@kvaps and @NickVolynkin in https://github.com/cozystack/cozystack/pull/1216, https://github.com/cozystack/cozystack/pull/1314, https://github.com/cozystack/cozystack/pull/1316, https://github.com/cozystack/cozystack/pull/1321, and https://github.com/cozystack/cozystack/pull/1333)
|
||||
* [cozystack-api] Show default values from the OpenAPI spec in the application resources. (@kvaps in https://github.com/cozystack/cozystack/pull/1241)
|
||||
* [cozystack-api] Provide an API for administrators to define custom managed applications alongside existing managed apps. (@klinch in https://github.com/cozystack/cozystack/pull/1230)
|
||||
* [robotlb] Introduce the Hetzner RobotLB balancer. (@IvanHunters and @gwynbleidd2106 in https://github.com/cozystack/cozystack/pull/1233)
|
||||
* [platform, robotlb] Autodetect if node ports should be assigned to load balancer services. (@lllamnyp in https://github.com/cozystack/cozystack/pull/1271)
|
||||
* [seaweedfs] Enable [integration with remote filer endpoints](https://cozystack.io/docs/operations/stretched/seaweedfs-multidc/) by adding new `Client` topology. (@kvaps in https://github.com/cozystack/cozystack/pull/1239)
|
||||
* [seaweedfs] Add support for whitelisting and exporting via nginx-ingress. Update cosi-driver. (@kvaps in https://github.com/cozystack/cozystack/pull/1277)
|
||||
* [monitoring, seaweedfs] Add monitoring and Grafana dashboard for SeaweedFS. (@IvanHunters in https://github.com/cozystack/cozystack/pull/1285)
|
||||
* [clickhouse] Add the ClickHouse Keeper component. (@klinch0 in https://github.com/cozystack/cozystack/pull/1298 and https://github.com/cozystack/cozystack/pull/1320)
|
||||
|
||||
## Security
|
||||
|
||||
* [keycloak] Store administrative passwords in the management cluster's secrets. (@IvanHunters in https://github.com/cozystack/cozystack/pull/1286)
|
||||
* [keycloak] Update Keycloak client redirect URI to use HTTPS instead of HTTP. Enable `cookie-secure`. (@klinch0 in https://github.com/cozystack/cozystack/pull/1287)
|
||||
|
||||
## Fixes
|
||||
|
||||
* [platform] Introduce a fixed 2-second delay at the start of reconciliation for system and tenant Helm operations. (@klinch0 in https://github.com/cozystack/cozystack/pull/1343)
|
||||
* [kubernetes] Add dependency for snapshot CRD and migration to the latest version. (@kvaps in https://github.com/cozystack/cozystack/pull/1275)
|
||||
* [kubernetes] Fix regression in `volumesnapshotclass` installation from https://github.com/cozystack/cozystack/pull/1203. (@kvaps in https://github.com/cozystack/cozystack/pull/1238)
|
||||
* [kubernetes] Resolve problems with pod names exceeding allowed length by shortening the name of volume snapshot CRD from `*-volumesnapshot-crd-for-tenant-k8s` to `*-vsnap-crd`. To apply this change, update each affected tenant Kubernetes cluster after updating Cozystack. (@klinch0 in https://github.com/cozystack/cozystack/pull/1284)
|
||||
* [kubernetes] Disable VPA for VPA in tenant Kubernetes clusters. Tenant clusters have no need for this feature, and it was not designed to work in a tenant cluster, but was enabled by mistake. (@lllamnyp in https://github.com/cozystack/cozystack/pull/1301 and https://github.com/cozystack/cozystack/pull/1318)
|
||||
* [kamaji] Fix broken migration jobs originating from missing environment variables in the in-tree build. (@lllamnyp in https://github.com/cozystack/cozystack/pull/1338)
|
||||
* [etcd] Fix the `topologySpreadConstraints` for etcd. (@klinch0 in https://github.com/cozystack/cozystack/pull/1331)
|
||||
* [tenant] Fix tenant network policy to allow traffic to additional tenant-related services across namespace hierarchies. (@klinch0 in https://github.com/cozystack/cozystack/pull/1232)
|
||||
* [tenant, monitoring] Improve the reliability of tenant monitoring by increasing the timeout and number of retries. (@IvanHunters in https://github.com/cozystack/cozystack/pull/1294)
|
||||
* [kubevirt] Fix building KubeVirt CCM image. (@kvaps in https://github.com/cozystack/cozystack/commit/3c7e256906e1dbb0f957dc3a205fa77a147d419d)
|
||||
* [virtual-machine] Fix a regression with `optional=true` field. (@kvaps in https://github.com/cozystack/cozystack/commit/01053f7c3180d1bd045d7c5fb949984c2bdaf19d)
|
||||
* [virtual-machine] Enable using custom `instanceType` values in `virtual-machine` and `vm-instance` by disabling field validation. (@lllamnyp in https://github.com/cozystack/cozystack/pull/1300, backported in https://github.com/cozystack/cozystack/pull/1303)
|
||||
* [cozystack-api] Show correct `kind` values of `ApplicationList`. (@kvaps in https://github.com/cozystack/cozystack/pull/1290)
|
||||
* [cozystack-api] Add missing roles to allow cozystack-controller to read Kubernetes deployments. (@klinch0 in https://github.com/cozystack/cozystack/pull/1342)
|
||||
* [linstor] Update LINSTOR monitoring configuration to use label `controller_node` instead of `node`. (@kvaps in https://github.com/cozystack/cozystack/pull/1326 and https://github.com/cozystack/cozystack/pull/1335)
|
||||
* [seaweedfs] Fix SeaweedFS volume configuration. Increase the volume size limit from 100MB to 30,000MB. (@kvaps in https://github.com/cozystack/cozystack/pull/1328)
|
||||
* [seaweedfs] Disable proxy buffering and proxy request buffering for ingress. (@kvaps in https://github.com/cozystack/cozystack/pull/1330)
|
||||
|
||||
|
||||
## Dependencies
|
||||
|
||||
* Update flux-operator to 0.28.0. (@kingdonb in https://github.com/cozystack/cozystack/pull/1315 and https://github.com/cozystack/cozystack/pull/1344)
|
||||
|
||||
## Documentation
|
||||
|
||||
* [Reimplement Cozystack Roadmap as a GitHub project](https://github.com/orgs/cozystack/projects/1). (@cozystack team)
|
||||
* [SeaweedFS Multi-DC Configuration](https://cozystack.io/docs/operations/stretched/seaweedfs-multidc/). (@kvaps and @NickVolynkin in https://github.com/cozystack/website/pull/272)
|
||||
* [Troubleshooting Kube-OVN](https://cozystack.io/docs/operations/troubleshooting/#kube-ovn-crash). (@kvaps and @NickVolynkin in https://github.com/cozystack/website/pull/273)
|
||||
* [Removing failed nodes from Cozystack cluster](https://cozystack.io/docs/operations/troubleshooting/#remove-a-failed-node-from-the-cluster). (@kvaps and @NickVolynkin in https://github.com/cozystack/website/pull/273)
|
||||
* [Installing Talos with `kexec`](https://cozystack.io/docs/talos/install/kexec/). (@kvaps and @NickVolynkin in https://github.com/cozystack/website/pull/268)
|
||||
* [Rewrite Cozystack tutorial](https://cozystack.io/docs/getting-started/). (@NickVolynkin in https://github.com/cozystack/website/pull/262 and https://github.com/cozystack/website/pull/268)
|
||||
* [How to install Cozystack in Hetzner](https://cozystack.io/docs/install/providers/hetzner/). (@NickVolynkin and @IvanHunters in https://github.com/cozystack/website/pull/280)
|
||||
* [Adding External Applications to Cozystack Catalog](https://cozystack.io/docs/applications/external/). (@klinch0 and @NickVolynkin in https://github.com/cozystack/website/pull/283)
|
||||
* [Creating and Using Named VM Images (Golden Images)](https://cozystack.io/docs/virtualization/vm-image/) (@NickVolynkin and @kvaps in https://github.com/cozystack/website/pull/276)
|
||||
* [Creating Encrypted Storage on LINSTOR](https://cozystack.io/docs/operations/storage/disk-encryption/). (@kvaps and @NickVolynkin in https://github.com/cozystack/website/pull/282)
|
||||
* [Adding and removing components on Cozystack installation using `bundle-enable` and `bundle-disable`](https://cozystack.io/docs/operations/bundles/#how-to-enable-and-disable-bundle-components) (@NickVolynkin in https://github.com/cozystack/website/pull/281)
|
||||
* Restructure Cozystack documentation. Bring [managed Kubernetes](https://cozystack.io/docs/kubernetes/), [managed applications](https://cozystack.io/docs/applications/), [virtualization](https://cozystack.io/docs/virtualization/), and [networking](https://cozystack.io/docs/networking/) guides to the top level. (@NickVolynkin in https://github.com/cozystack/website/pull/266)
|
||||
|
||||
|
||||
## Development, Testing, and CI/CD
|
||||
|
||||
* [tests] Add tests for S3 buckets. (@IvanHunters in https://github.com/cozystack/cozystack/pull/1283)
|
||||
* [tests, ci] Simplify test discovery logic; run two k8s tests as separate jobs; delete Clickhouse application after a successful test. (@lllamnyp in https://github.com/cozystack/cozystack/pull/1236)
|
||||
* [dx] When running `make` commands with `BUILDER` value specified, `PLATFORM` is optional. (@kvaps in https://github.com/cozystack/cozystack/pull/1288)
|
||||
* [tests] Fix resource specification in virtual machine tests. (@IvanHunters in https://github.com/cozystack/cozystack/pull/1308)
|
||||
* [tests] Increase available space for e2e tests. (@kvaps in https://github.com/cozystack/cozystack/commit/168a24ffdf1202b3bf2e7d2b5ef54b72b7403baf)
|
||||
* [tests, ci] Continue application tests after one of them fails. (@NickVolynkin in https://github.com/cozystack/cozystack/commit/634b77edad6c32c101f3e5daea6a5ffc0c83d904)
|
||||
* [ci] Use a subdomain of aenix.org for Nexus service in CI. (@lllamnyp in https://github.com/cozystack/cozystack/pull/1322)
|
||||
|
||||
---
|
||||
|
||||
**Full Changelog**: https://github.com/cozystack/cozystack/compare/v0.34.0...v0.35.0
|
||||
@@ -1,10 +0,0 @@
|
||||
|
||||
<!--
|
||||
https://github.com/cozystack/cozystack/releases/tag/v0.35.1
|
||||
-->
|
||||
|
||||
## Fixes
|
||||
|
||||
* [cozy-lib] Fix malformed retrieval of `cozyConfig` in the cozy-lib template. (@lllamnyp in https://github.com/cozystack/cozystack/pull/1348)
|
||||
|
||||
**Full Changelog**: https://github.com/cozystack/cozystack/compare/v0.35.0...v0.35.1
|
||||
@@ -1,22 +0,0 @@
|
||||
|
||||
<!--
|
||||
https://github.com/cozystack/cozystack/releases/tag/v0.35.2
|
||||
-->
|
||||
|
||||
## Features and Improvements
|
||||
|
||||
* [talos] Add LLDPD (`ghcr.io/siderolabs/lldpd`) as a built-in system extension, enabling LLDP-based neighbor discovery out of the box. (@lllamnyp in https://github.com/cozystack/cozystack/pull/1351 and https://github.com/cozystack/cozystack/pull/1360)
|
||||
|
||||
## Fixes
|
||||
|
||||
* [cozystack-api] Sanitize the OpenAPI v2 schema. (@kvaps in https://github.com/cozystack/cozystack/pull/1353)
|
||||
* [seaweedfs] Fix a problem where S3 gateway would be moved to an external pod, resulting in authentication failure. (@kvaps in https://github.com/cozystack/cozystack/pull/1361)
|
||||
|
||||
|
||||
## Dependencies
|
||||
|
||||
* Update LINSTOR to v1.31.3. (@kvaps in https://github.com/cozystack/cozystack/pull/1358)
|
||||
* Update SeaweedFS to v3.96. (@kvaps in https://github.com/cozystack/cozystack/pull/1361)
|
||||
|
||||
|
||||
**Full Changelog**: https://github.com/cozystack/cozystack/compare/v0.35.1...v0.35.2
|
||||
3
go.mod
3
go.mod
@@ -59,7 +59,6 @@ require (
|
||||
github.com/google/go-cmp v0.6.0 // indirect
|
||||
github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/gorilla/websocket v1.5.0 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect
|
||||
github.com/imdario/mergo v0.3.6 // indirect
|
||||
@@ -67,11 +66,9 @@ require (
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/moby/spdystream v0.4.0 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/prometheus/client_golang v1.19.1 // indirect
|
||||
|
||||
6
go.sum
6
go.sum
@@ -2,8 +2,6 @@ github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cq
|
||||
github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c=
|
||||
github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI=
|
||||
github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g=
|
||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
|
||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
||||
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA=
|
||||
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
@@ -117,8 +115,6 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/moby/spdystream v0.4.0 h1:Vy79D6mHeJJjiPdFEL2yku1kl0chZpJfZcPpb16BRl8=
|
||||
github.com/moby/spdystream v0.4.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
@@ -126,8 +122,6 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus=
|
||||
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
|
||||
github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA=
|
||||
github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To=
|
||||
github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk=
|
||||
|
||||
@@ -48,7 +48,7 @@ kubectl get ns --no-headers | awk '$2 != "Active"' |
|
||||
|
||||
echo "Collecting helmreleases..."
|
||||
kubectl get hr -A > $REPORT_DIR/kubernetes/helmreleases.txt 2>&1
|
||||
kubectl get hr -A --no-headers | awk '$4 != "True"' | \
|
||||
kubectl get hr -A | awk '$4 != "True"' | \
|
||||
while read NAMESPACE NAME _; do
|
||||
DIR=$REPORT_DIR/kubernetes/helmreleases/$NAMESPACE/$NAME
|
||||
mkdir -p $DIR
|
||||
@@ -105,7 +105,7 @@ kubectl get svc -A --no-headers | awk '$4 == "<pending>"' |
|
||||
|
||||
echo "Collecting pvcs..."
|
||||
kubectl get pvc -A > $REPORT_DIR/kubernetes/pvcs.txt 2>&1
|
||||
kubectl get pvc -A --no-headers | awk '$3 != "Bound"' |
|
||||
kubectl get pvc -A | awk '$3 != "Bound"' |
|
||||
while read NAMESPACE NAME _; do
|
||||
DIR=$REPORT_DIR/kubernetes/pvc/$NAMESPACE/$NAME
|
||||
mkdir -p $DIR
|
||||
|
||||
@@ -24,7 +24,7 @@ run_one() {
|
||||
|
||||
echo "╭ » Run test: $title"
|
||||
START=$(date +%s)
|
||||
skip_next="+ $fn"
|
||||
skip_next="+ $fn" # первую строку трассировки с именем функции пропустим
|
||||
|
||||
{
|
||||
(
|
||||
@@ -83,11 +83,11 @@ awk '
|
||||
}
|
||||
printf("### %s\n", title)
|
||||
printf("%s() {\n", fname)
|
||||
print " set -e"
|
||||
print " set -e" # ошибка → падение теста
|
||||
next
|
||||
}
|
||||
/^}$/ {
|
||||
print " return 0"
|
||||
print " return 0" # если автор не сделал exit 1 — тест ОК
|
||||
print "}"
|
||||
next
|
||||
}
|
||||
|
||||
@@ -18,8 +18,8 @@ spec:
|
||||
EOF
|
||||
sleep 5
|
||||
kubectl -n tenant-test wait hr vm-disk-$name --timeout=5s --for=condition=ready
|
||||
kubectl -n tenant-test wait dv vm-disk-$name --timeout=250s --for=condition=ready
|
||||
kubectl -n tenant-test wait pvc vm-disk-$name --timeout=200s --for=jsonpath='{.status.phase}'=Bound
|
||||
kubectl -n tenant-test wait dv vm-disk-$name --timeout=150s --for=condition=ready
|
||||
kubectl -n tenant-test wait pvc vm-disk-$name --timeout=100s --for=jsonpath='{.status.phase}'=Bound
|
||||
}
|
||||
|
||||
@test "Create a VM Instance" {
|
||||
@@ -42,6 +42,9 @@ spec:
|
||||
disks:
|
||||
- name: $diskName
|
||||
gpus: []
|
||||
resources:
|
||||
cpu: ""
|
||||
memory: ""
|
||||
sshKeys:
|
||||
- ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPht0dPk5qQ+54g1hSX7A6AUxXJW5T6n/3d7Ga2F8gTF
|
||||
test@test
|
||||
|
||||
@@ -123,24 +123,16 @@ EOF
|
||||
|
||||
@test "Configure Tenant and wait for applications" {
|
||||
# Patch root tenant and wait for its releases
|
||||
|
||||
kubectl patch tenants/root -n tenant-root --type merge -p '{"spec":{"host":"example.org","ingress":true,"monitoring":true,"etcd":true,"isolated":true, "seaweedfs": true}}'
|
||||
|
||||
timeout 60 sh -ec 'until kubectl get hr -n tenant-root etcd ingress monitoring seaweedfs tenant-root >/dev/null 2>&1; do sleep 1; done'
|
||||
kubectl wait hr/etcd hr/ingress hr/tenant-root hr/seaweedfs -n tenant-root --timeout=4m --for=condition=ready
|
||||
|
||||
# TODO: Workaround ingress unvailability issue
|
||||
if ! kubectl wait hr/monitoring -n tenant-root --timeout=2m --for=condition=ready; then
|
||||
flux reconcile hr monitoring -n tenant-root --force
|
||||
kubectl wait hr/monitoring -n tenant-root --timeout=2m --for=condition=ready
|
||||
fi
|
||||
|
||||
if ! kubectl wait hr/seaweedfs-system -n tenant-root --timeout=2m --for=condition=ready; then
|
||||
flux reconcile hr seaweedfs-system -n tenant-root --force
|
||||
kubectl wait hr/seaweedfs-system -n tenant-root --timeout=2m --for=condition=ready
|
||||
fi
|
||||
|
||||
|
||||
# Expose Cozystack services through ingress
|
||||
kubectl patch configmap/cozystack -n cozy-system --type merge -p '{"data":{"expose-services":"api,dashboard,cdi-uploadproxy,vm-exportproxy,keycloak"}}'
|
||||
|
||||
@@ -152,7 +144,7 @@ EOF
|
||||
kubectl wait sts/etcd -n tenant-root --for=jsonpath='{.status.readyReplicas}'=3 --timeout=5m
|
||||
|
||||
# VictoriaMetrics components
|
||||
kubectl wait vmalert/vmalert-shortterm vmalertmanager/alertmanager -n tenant-root --for=jsonpath='{.status.updateStatus}'=operational --timeout=15m
|
||||
kubectl wait vmalert/vmalert-shortterm vmalertmanager/alertmanager -n tenant-root --for=jsonpath='{.status.updateStatus}'=operational --timeout=5m
|
||||
kubectl wait vlogs/generic -n tenant-root --for=jsonpath='{.status.updateStatus}'=operational --timeout=5m
|
||||
kubectl wait vmcluster/shortterm vmcluster/longterm -n tenant-root --for=jsonpath='{.status.clusterStatus}'=operational --timeout=5m
|
||||
|
||||
@@ -189,22 +181,9 @@ spec:
|
||||
ingress: false
|
||||
isolated: true
|
||||
monitoring: false
|
||||
resourceQuotas:
|
||||
cpu: "60"
|
||||
memory: "128Gi"
|
||||
storage: "100Gi"
|
||||
resourceQuotas: {}
|
||||
seaweedfs: false
|
||||
EOF
|
||||
kubectl wait hr/tenant-test -n tenant-root --timeout=1m --for=condition=ready
|
||||
kubectl wait namespace tenant-test --timeout=20s --for=jsonpath='{.status.phase}'=Active
|
||||
# Wait for ResourceQuota to appear and assert values
|
||||
timeout 60 sh -ec 'until [ "$(kubectl get quota -n tenant-test --no-headers 2>/dev/null | wc -l)" -ge 1 ]; do sleep 1; done'
|
||||
kubectl get quota -n tenant-test \
|
||||
-o jsonpath='{range .items[*]}{.spec.hard.requests\.memory}{" "}{.spec.hard.requests\.storage}{"\n"}{end}' \
|
||||
| grep -qx '137438953472 100Gi'
|
||||
|
||||
# Assert LimitRange defaults for containers
|
||||
kubectl get limitrange -n tenant-test \
|
||||
-o jsonpath='{range .items[*].spec.limits[*]}{.default.cpu}{" "}{.default.memory}{" "}{.defaultRequest.cpu}{" "}{.defaultRequest.memory}{"\n"}{end}' \
|
||||
| grep -qx '250m 128Mi 25m 128Mi'
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ EOF
|
||||
for i in 1 2 3; do
|
||||
cp nocloud-amd64.raw srv${i}/system.img
|
||||
qemu-img resize srv${i}/system.img 50G
|
||||
qemu-img create srv${i}/data.img 200G
|
||||
qemu-img create srv${i}/data.img 100G
|
||||
done
|
||||
}
|
||||
|
||||
@@ -132,7 +132,6 @@ machine:
|
||||
- usermode_helper=disabled
|
||||
- name: zfs
|
||||
- name: spl
|
||||
- name: lldpd
|
||||
registries:
|
||||
mirrors:
|
||||
docker.io:
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
#!/usr/bin/env bats
|
||||
# -----------------------------------------------------------------------------
|
||||
# Test OpenAPI endpoints in a Kubernetes cluster
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
@test "Test OpenAPI v2 endpoint" {
|
||||
kubectl get -v7 --raw '/openapi/v2?timeout=32s' > /dev/null
|
||||
}
|
||||
|
||||
@test "Test OpenAPI v3 endpoint" {
|
||||
kubectl get -v7 --raw '/openapi/v3/apis/apps.cozystack.io/v1alpha1' > /dev/null
|
||||
}
|
||||
|
||||
@test "Test OpenAPI v2 endpoint (protobuf)" {
|
||||
(
|
||||
kubectl proxy --port=21234 & sleep 0.5
|
||||
trap "kill $!" EXIT
|
||||
curl -sS --fail 'http://localhost:21234/openapi/v2?timeout=32s' -H 'Accept: application/com.github.proto-openapi.spec.v2@v1.0+protobuf' > /dev/null
|
||||
)
|
||||
}
|
||||
@@ -2,25 +2,14 @@ package controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"sort"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/cozystack/cozystack/internal/shared/crdmem"
|
||||
|
||||
cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/builder"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/handler"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||
@@ -31,55 +20,85 @@ type CozystackResourceDefinitionReconciler struct {
|
||||
client.Client
|
||||
Scheme *runtime.Scheme
|
||||
|
||||
// Configurable debounce duration
|
||||
Debounce time.Duration
|
||||
|
||||
// Internal state for debouncing
|
||||
mu sync.Mutex
|
||||
lastEvent time.Time
|
||||
lastHandled time.Time
|
||||
|
||||
mem *crdmem.Memory
|
||||
lastEvent time.Time // Time of last CRUD event on CozystackResourceDefinition
|
||||
lastHandled time.Time // Last time the Deployment was actually restarted
|
||||
}
|
||||
|
||||
// Reconcile handles the logic to restart the target Deployment only once,
|
||||
// even if multiple events occur close together
|
||||
func (r *CozystackResourceDefinitionReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
|
||||
logger := log.FromContext(ctx)
|
||||
log := log.FromContext(ctx)
|
||||
|
||||
crd := &cozyv1alpha1.CozystackResourceDefinition{}
|
||||
err := r.Get(ctx, types.NamespacedName{Name: req.Name}, crd)
|
||||
if err == nil {
|
||||
if r.mem != nil {
|
||||
r.mem.Upsert(crd)
|
||||
}
|
||||
|
||||
r.mu.Lock()
|
||||
r.lastEvent = time.Now()
|
||||
r.mu.Unlock()
|
||||
// Only respond to our target deployment
|
||||
if req.Namespace != "cozy-system" || req.Name != "cozystack-api" {
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
if err != nil && !apierrors.IsNotFound(err) {
|
||||
|
||||
r.mu.Lock()
|
||||
le := r.lastEvent
|
||||
lh := r.lastHandled
|
||||
debounce := r.Debounce
|
||||
r.mu.Unlock()
|
||||
|
||||
if debounce <= 0 {
|
||||
debounce = 5 * time.Second
|
||||
}
|
||||
|
||||
// No events received yet — nothing to do
|
||||
if le.IsZero() {
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
|
||||
// Wait until the debounce duration has passed since the last event
|
||||
if d := time.Since(le); d < debounce {
|
||||
return ctrl.Result{RequeueAfter: debounce - d}, nil
|
||||
}
|
||||
|
||||
// Already handled this event — skip restart
|
||||
if !lh.Before(le) {
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
|
||||
// Perform the restart by patching the deployment annotation
|
||||
deploy := &appsv1.Deployment{}
|
||||
if err := r.Get(ctx, types.NamespacedName{Namespace: "cozy-system", Name: "cozystack-api"}, deploy); err != nil {
|
||||
log.Error(err, "Failed to get Deployment cozy-system/cozystack-api")
|
||||
return ctrl.Result{}, client.IgnoreNotFound(err)
|
||||
}
|
||||
|
||||
patch := client.MergeFrom(deploy.DeepCopy())
|
||||
if deploy.Spec.Template.Annotations == nil {
|
||||
deploy.Spec.Template.Annotations = make(map[string]string)
|
||||
}
|
||||
deploy.Spec.Template.Annotations["kubectl.kubernetes.io/restartedAt"] = time.Now().Format(time.RFC3339)
|
||||
|
||||
if err := r.Patch(ctx, deploy, patch); err != nil {
|
||||
log.Error(err, "Failed to patch Deployment annotation")
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
if apierrors.IsNotFound(err) && r.mem != nil {
|
||||
r.mem.Delete(req.Name)
|
||||
}
|
||||
if req.Namespace == "cozy-system" && req.Name == "cozystack-api" {
|
||||
return r.debouncedRestart(ctx, logger)
|
||||
}
|
||||
|
||||
// Mark this event as handled
|
||||
r.mu.Lock()
|
||||
r.lastHandled = le
|
||||
r.mu.Unlock()
|
||||
|
||||
log.Info("Deployment cozy-system/cozystack-api successfully restarted")
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
|
||||
// SetupWithManager configures how the controller listens to events
|
||||
func (r *CozystackResourceDefinitionReconciler) SetupWithManager(mgr ctrl.Manager) error {
|
||||
if r.Debounce == 0 {
|
||||
r.Debounce = 5 * time.Second
|
||||
}
|
||||
if r.mem == nil {
|
||||
r.mem = crdmem.Global()
|
||||
}
|
||||
if err := r.mem.EnsurePrimingWithManager(mgr); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return ctrl.NewControllerManagedBy(mgr).
|
||||
Named("cozystackresource-controller").
|
||||
For(&cozyv1alpha1.CozystackResourceDefinition{}, builder.WithPredicates()).
|
||||
Named("cozystack-restart-controller").
|
||||
Watches(
|
||||
&cozyv1alpha1.CozystackResourceDefinition{},
|
||||
handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, obj client.Object) []reconcile.Request {
|
||||
@@ -96,88 +115,3 @@ func (r *CozystackResourceDefinitionReconciler) SetupWithManager(mgr ctrl.Manage
|
||||
).
|
||||
Complete(r)
|
||||
}
|
||||
|
||||
type crdHashView struct {
|
||||
Name string `json:"name"`
|
||||
Spec cozyv1alpha1.CozystackResourceDefinitionSpec `json:"spec"`
|
||||
}
|
||||
|
||||
func (r *CozystackResourceDefinitionReconciler) computeConfigHash() (string, error) {
|
||||
if r.mem == nil {
|
||||
return "", nil
|
||||
}
|
||||
snapshot := r.mem.Snapshot()
|
||||
sort.Slice(snapshot, func(i, j int) bool { return snapshot[i].Name < snapshot[j].Name })
|
||||
views := make([]crdHashView, 0, len(snapshot))
|
||||
for i := range snapshot {
|
||||
views = append(views, crdHashView{
|
||||
Name: snapshot[i].Name,
|
||||
Spec: snapshot[i].Spec,
|
||||
})
|
||||
}
|
||||
b, err := json.Marshal(views)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
sum := sha256.Sum256(b)
|
||||
return hex.EncodeToString(sum[:]), nil
|
||||
}
|
||||
|
||||
func (r *CozystackResourceDefinitionReconciler) debouncedRestart(ctx context.Context, logger logr.Logger) (ctrl.Result, error) {
|
||||
r.mu.Lock()
|
||||
le := r.lastEvent
|
||||
lh := r.lastHandled
|
||||
debounce := r.Debounce
|
||||
r.mu.Unlock()
|
||||
|
||||
if debounce <= 0 {
|
||||
debounce = 5 * time.Second
|
||||
}
|
||||
if le.IsZero() {
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
if d := time.Since(le); d < debounce {
|
||||
return ctrl.Result{RequeueAfter: debounce - d}, nil
|
||||
}
|
||||
if !lh.Before(le) {
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
|
||||
newHash, err := r.computeConfigHash()
|
||||
if err != nil {
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
|
||||
deploy := &appsv1.Deployment{}
|
||||
if err := r.Get(ctx, types.NamespacedName{Namespace: "cozy-system", Name: "cozystack-api"}, deploy); err != nil {
|
||||
return ctrl.Result{}, client.IgnoreNotFound(err)
|
||||
}
|
||||
|
||||
if deploy.Spec.Template.Annotations == nil {
|
||||
deploy.Spec.Template.Annotations = map[string]string{}
|
||||
}
|
||||
oldHash := deploy.Spec.Template.Annotations["cozystack.io/config-hash"]
|
||||
|
||||
if oldHash == newHash && oldHash != "" {
|
||||
r.mu.Lock()
|
||||
r.lastHandled = le
|
||||
r.mu.Unlock()
|
||||
logger.Info("No changes in CRD config; skipping restart", "hash", newHash)
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
|
||||
patch := client.MergeFrom(deploy.DeepCopy())
|
||||
deploy.Spec.Template.Annotations["cozystack.io/config-hash"] = newHash
|
||||
|
||||
if err := r.Patch(ctx, deploy, patch); err != nil {
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
|
||||
r.mu.Lock()
|
||||
r.lastHandled = le
|
||||
r.mu.Unlock()
|
||||
|
||||
logger.Info("Updated cozystack-api podTemplate config-hash; rollout triggered",
|
||||
"old", oldHash, "new", newHash)
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
|
||||
@@ -1,280 +0,0 @@
|
||||
package kubeovnplunger
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/cozystack/cozystack/internal/sse"
|
||||
"github.com/cozystack/cozystack/pkg/ovnstatus"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/remotecommand"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/event"
|
||||
"sigs.k8s.io/controller-runtime/pkg/handler"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||
"sigs.k8s.io/controller-runtime/pkg/manager"
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
"sigs.k8s.io/controller-runtime/pkg/source"
|
||||
)
|
||||
|
||||
var (
|
||||
srv *sse.Server
|
||||
)
|
||||
|
||||
const (
|
||||
rescanInterval = 1 * time.Minute
|
||||
)
|
||||
|
||||
// KubeOVNPlunger watches the ovn-central cluster members
|
||||
type KubeOVNPlunger struct {
|
||||
client.Client
|
||||
Scheme *runtime.Scheme
|
||||
ClientSet kubernetes.Interface
|
||||
REST *rest.Config
|
||||
Registry prometheus.Registerer
|
||||
metrics metrics
|
||||
lastLeader map[string]string
|
||||
seenCIDs map[string]map[string]struct{}
|
||||
}
|
||||
|
||||
// Reconcile runs the checks on the ovn-central members to see if their views of the cluster are consistent
|
||||
func (r *KubeOVNPlunger) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
|
||||
l := log.FromContext(ctx)
|
||||
|
||||
deploy := &appsv1.Deployment{}
|
||||
if err := r.Get(ctx, req.NamespacedName, deploy); err != nil {
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
|
||||
iphints := map[string]string{}
|
||||
for _, env := range deploy.Spec.Template.Spec.Containers[0].Env {
|
||||
if env.Name != "NODE_IPS" {
|
||||
continue
|
||||
}
|
||||
for _, ip := range strings.Split(env.Value, ",") {
|
||||
iphints[ip] = ""
|
||||
}
|
||||
break
|
||||
}
|
||||
if len(iphints) == 0 {
|
||||
l.Info("WARNING: running without IP hints, some error conditions cannot be detected")
|
||||
}
|
||||
pods := &corev1.PodList{}
|
||||
|
||||
if err := r.List(ctx, pods, client.InNamespace(req.Namespace), client.MatchingLabels(map[string]string{"app": req.Name})); err != nil {
|
||||
return ctrl.Result{}, fmt.Errorf("list ovn-central pods: %w", err)
|
||||
}
|
||||
|
||||
nbmv := make([]ovnstatus.MemberView, 0, len(pods.Items))
|
||||
sbmv := make([]ovnstatus.MemberView, 0, len(pods.Items))
|
||||
nbSnaps := make([]ovnstatus.HealthSnapshot, 0, len(pods.Items))
|
||||
sbSnaps := make([]ovnstatus.HealthSnapshot, 0, len(pods.Items))
|
||||
// TODO: get real iphints
|
||||
for i := range pods.Items {
|
||||
o := ovnstatus.OVNClient{}
|
||||
o.ApplyDefaults()
|
||||
o.Runner = func(ctx context.Context, bin string, args ...string) (string, error) {
|
||||
cmd := append([]string{bin}, args...)
|
||||
eo := ExecOptions{
|
||||
Namespace: req.Namespace,
|
||||
Pod: pods.Items[i].Name,
|
||||
Container: pods.Items[i].Spec.Containers[0].Name,
|
||||
Command: cmd,
|
||||
}
|
||||
res, err := r.ExecPod(ctx, eo)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return res.Stdout, nil
|
||||
}
|
||||
nb, sb, err1, err2 := o.HealthBoth(ctx)
|
||||
if err1 != nil || err2 != nil {
|
||||
l.Error(fmt.Errorf("health check failed: nb=%w, sb=%w", err1, err2), "pod", pods.Items[i].Name)
|
||||
continue
|
||||
}
|
||||
nbSnaps = append(nbSnaps, nb)
|
||||
sbSnaps = append(sbSnaps, sb)
|
||||
nbmv = append(nbmv, ovnstatus.BuildMemberView(nb))
|
||||
sbmv = append(sbmv, ovnstatus.BuildMemberView(sb))
|
||||
}
|
||||
r.recordAndPruneCIDs("nb", cidFromSnaps(nbSnaps))
|
||||
r.recordAndPruneCIDs("sb", cidFromSnaps(sbSnaps))
|
||||
nbmv = ovnstatus.NormalizeViews(nbmv)
|
||||
sbmv = ovnstatus.NormalizeViews(sbmv)
|
||||
nbecv := ovnstatus.AnalyzeConsensusWithIPHints(nbmv, &ovnstatus.Hints{ExpectedIPs: iphints})
|
||||
sbecv := ovnstatus.AnalyzeConsensusWithIPHints(sbmv, &ovnstatus.Hints{ExpectedIPs: iphints})
|
||||
expected := len(iphints)
|
||||
r.WriteClusterMetrics("nb", nbSnaps, nbecv, expected)
|
||||
r.WriteClusterMetrics("sb", sbSnaps, sbecv, expected)
|
||||
r.WriteMemberMetrics("nb", nbSnaps, nbmv, nbecv)
|
||||
r.WriteMemberMetrics("sb", sbSnaps, sbmv, sbecv)
|
||||
srv.Publish(nbecv.PrettyString() + sbecv.PrettyString())
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
|
||||
// SetupWithManager attaches a generic ticker to trigger a reconcile every <interval> seconds
|
||||
func (r *KubeOVNPlunger) SetupWithManager(mgr ctrl.Manager, kubeOVNNamespace, appName string) error {
|
||||
r.REST = rest.CopyConfig(mgr.GetConfig())
|
||||
cs, err := kubernetes.NewForConfig(r.REST)
|
||||
if err != nil {
|
||||
return fmt.Errorf("build clientset: %w", err)
|
||||
}
|
||||
r.ClientSet = cs
|
||||
ch := make(chan event.GenericEvent, 10)
|
||||
mapFunc := func(context.Context, client.Object) []reconcile.Request {
|
||||
return []reconcile.Request{{
|
||||
NamespacedName: types.NamespacedName{Namespace: kubeOVNNamespace, Name: appName},
|
||||
}}
|
||||
}
|
||||
mapper := handler.EnqueueRequestsFromMapFunc(mapFunc)
|
||||
srv = sse.New(sse.Options{
|
||||
Addr: ":18080",
|
||||
AllowCORS: true,
|
||||
})
|
||||
r.initMetrics()
|
||||
r.lastLeader = make(map[string]string)
|
||||
r.seenCIDs = map[string]map[string]struct{}{"nb": {}, "sb": {}}
|
||||
if err := ctrl.NewControllerManagedBy(mgr).
|
||||
Named("kubeovnplunger").
|
||||
WatchesRawSource(source.Channel(ch, mapper)).
|
||||
Complete(r); err != nil {
|
||||
return err
|
||||
}
|
||||
_ = mgr.Add(manager.RunnableFunc(func(ctx context.Context) error {
|
||||
go srv.ListenAndServe()
|
||||
<-ctx.Done()
|
||||
_ = srv.Shutdown(context.Background())
|
||||
return nil
|
||||
}))
|
||||
return mgr.Add(manager.RunnableFunc(func(ctx context.Context) error {
|
||||
ticker := time.NewTicker(rescanInterval)
|
||||
defer ticker.Stop()
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil
|
||||
case <-ticker.C:
|
||||
ch <- event.GenericEvent{
|
||||
Object: &metav1.PartialObjectMetadata{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: kubeOVNNamespace,
|
||||
Name: appName,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
type ExecOptions struct {
|
||||
Namespace string
|
||||
Pod string
|
||||
Container string
|
||||
Command []string // e.g. []string{"sh", "-c", "echo hi"}
|
||||
Stdin io.Reader // optional
|
||||
TTY bool // if true, stderr is merged into stdout
|
||||
Timeout time.Duration // optional overall timeout
|
||||
}
|
||||
|
||||
type ExecResult struct {
|
||||
Stdout string
|
||||
Stderr string
|
||||
ExitCode *int // nil if not determinable
|
||||
}
|
||||
|
||||
// ExecPod runs a command in a pod and returns stdout/stderr/exit code.
|
||||
func (r *KubeOVNPlunger) ExecPod(ctx context.Context, opts ExecOptions) (*ExecResult, error) {
|
||||
if opts.Namespace == "" || opts.Pod == "" || opts.Container == "" {
|
||||
return nil, fmt.Errorf("namespace, pod, and container are required")
|
||||
}
|
||||
|
||||
req := r.ClientSet.CoreV1().RESTClient().
|
||||
Post().
|
||||
Resource("pods").
|
||||
Namespace(opts.Namespace).
|
||||
Name(opts.Pod).
|
||||
SubResource("exec").
|
||||
VersionedParams(&corev1.PodExecOptions{
|
||||
Container: opts.Container,
|
||||
Command: opts.Command,
|
||||
Stdin: opts.Stdin != nil,
|
||||
Stdout: true,
|
||||
Stderr: !opts.TTY,
|
||||
TTY: opts.TTY,
|
||||
}, scheme.ParameterCodec)
|
||||
|
||||
exec, err := remotecommand.NewSPDYExecutor(r.REST, "POST", req.URL())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("spdy executor: %w", err)
|
||||
}
|
||||
|
||||
var stdout, stderr bytes.Buffer
|
||||
streamCtx := ctx
|
||||
if opts.Timeout > 0 {
|
||||
var cancel context.CancelFunc
|
||||
streamCtx, cancel = context.WithTimeout(ctx, opts.Timeout)
|
||||
defer cancel()
|
||||
}
|
||||
|
||||
streamErr := exec.StreamWithContext(streamCtx, remotecommand.StreamOptions{
|
||||
Stdin: opts.Stdin,
|
||||
Stdout: &stdout,
|
||||
Stderr: &stderr,
|
||||
Tty: opts.TTY,
|
||||
})
|
||||
|
||||
res := &ExecResult{Stdout: stdout.String(), Stderr: stderr.String()}
|
||||
if streamErr != nil {
|
||||
// Try to surface exit code instead of treating all failures as transport errors
|
||||
type exitCoder interface{ ExitStatus() int }
|
||||
if ec, ok := streamErr.(exitCoder); ok {
|
||||
code := ec.ExitStatus()
|
||||
res.ExitCode = &code
|
||||
return res, nil
|
||||
}
|
||||
return res, fmt.Errorf("exec stream: %w", streamErr)
|
||||
}
|
||||
zero := 0
|
||||
res.ExitCode = &zero
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (r *KubeOVNPlunger) recordAndPruneCIDs(db, currentCID string) {
|
||||
|
||||
// Mark current as seen
|
||||
if r.seenCIDs[db] == nil {
|
||||
r.seenCIDs[db] = map[string]struct{}{}
|
||||
}
|
||||
if currentCID != "" {
|
||||
r.seenCIDs[db][currentCID] = struct{}{}
|
||||
}
|
||||
|
||||
// Build a set of "still active" CIDs this cycle (could be none if you failed to collect)
|
||||
active := map[string]struct{}{}
|
||||
if currentCID != "" {
|
||||
active[currentCID] = struct{}{}
|
||||
}
|
||||
|
||||
// Any seen CID that isn't active now is stale -> delete all its series
|
||||
for cid := range r.seenCIDs[db] {
|
||||
if _, ok := active[cid]; ok {
|
||||
continue
|
||||
}
|
||||
r.deleteAllFor(db, cid)
|
||||
delete(r.seenCIDs[db], cid)
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
package kubeovnplunger
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client/config"
|
||||
)
|
||||
|
||||
var testPlunger *KubeOVNPlunger
|
||||
|
||||
func init() {
|
||||
scheme := runtime.NewScheme()
|
||||
cfg := config.GetConfigOrDie()
|
||||
c, _ := client.New(cfg, client.Options{})
|
||||
cs, _ := kubernetes.NewForConfig(cfg)
|
||||
testPlunger = &KubeOVNPlunger{
|
||||
Client: c,
|
||||
Scheme: scheme,
|
||||
ClientSet: cs,
|
||||
REST: cfg,
|
||||
}
|
||||
}
|
||||
|
||||
func TestPlungerGetsStatuses(t *testing.T) {
|
||||
_, err := testPlunger.Reconcile(context.Background(), ctrl.Request{})
|
||||
if err != nil {
|
||||
t.Errorf("error should be nil but it's %s", err)
|
||||
}
|
||||
}
|
||||
@@ -1,423 +0,0 @@
|
||||
package kubeovnplunger
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/cozystack/cozystack/pkg/ovnstatus"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
)
|
||||
|
||||
type metrics struct {
|
||||
// --- Core cluster health (per DB/cid) ---
|
||||
clusterQuorum *prometheus.GaugeVec // 1/0
|
||||
allAgree *prometheus.GaugeVec // 1/0
|
||||
membersExpected *prometheus.GaugeVec
|
||||
membersObserved *prometheus.GaugeVec
|
||||
ipsExpected *prometheus.GaugeVec
|
||||
ipsObserved *prometheus.GaugeVec
|
||||
excessMembers *prometheus.GaugeVec
|
||||
missingMembers *prometheus.GaugeVec
|
||||
unexpectedIPsCount *prometheus.GaugeVec
|
||||
missingExpectedIPsCount *prometheus.GaugeVec
|
||||
ipConflictsCount *prometheus.GaugeVec
|
||||
sidAddrDisagreements *prometheus.GaugeVec
|
||||
|
||||
// --- Consensus summary (per DB/cid) ---
|
||||
consensusMajoritySize *prometheus.GaugeVec
|
||||
consensusMinoritySize *prometheus.GaugeVec
|
||||
consensusDiffsTotal *prometheus.GaugeVec
|
||||
|
||||
// --- Detail exports (sparse, keyed by IP/SID) ---
|
||||
unexpectedIPGauge *prometheus.GaugeVec // {db,cid,ip} -> 1
|
||||
missingExpectedIPGauge *prometheus.GaugeVec // {db,cid,ip} -> 1
|
||||
ipConflictGauge *prometheus.GaugeVec // {db,cid,ip} -> count(sids)
|
||||
suspectStaleGauge *prometheus.GaugeVec // {db,cid,sid} -> 1
|
||||
|
||||
// --- Per-member liveness/freshness (per DB/cid/sid[/ip]) ---
|
||||
memberConnected *prometheus.GaugeVec // {db,cid,sid,ip}
|
||||
memberLeader *prometheus.GaugeVec // {db,cid,sid}
|
||||
memberLastMsgMs *prometheus.GaugeVec // {db,cid,sid}
|
||||
memberIndex *prometheus.GaugeVec // {db,cid,sid}
|
||||
memberIndexGap *prometheus.GaugeVec // {db,cid,sid}
|
||||
memberReporter *prometheus.GaugeVec // {db,cid,sid}
|
||||
memberMissingReporter *prometheus.GaugeVec // {db,cid,sid}
|
||||
|
||||
// --- Ops/housekeeping ---
|
||||
leaderTransitionsTotal *prometheus.CounterVec // {db,cid}
|
||||
collectErrorsTotal *prometheus.CounterVec // {db,cid}
|
||||
publishEventsTotal *prometheus.CounterVec // {db,cid}
|
||||
snapshotTimestampSec *prometheus.GaugeVec // {db,cid}
|
||||
}
|
||||
|
||||
func (r *KubeOVNPlunger) initMetrics() {
|
||||
p := promauto.With(r.Registry)
|
||||
|
||||
ns := "ovn"
|
||||
|
||||
// --- Core cluster health ---
|
||||
r.metrics.clusterQuorum = p.NewGaugeVec(prometheus.GaugeOpts{
|
||||
Namespace: ns, Subsystem: "cluster", Name: "quorum",
|
||||
Help: "1 if cluster has quorum, else 0",
|
||||
}, []string{"db", "cid"})
|
||||
|
||||
r.metrics.allAgree = p.NewGaugeVec(prometheus.GaugeOpts{
|
||||
Namespace: ns, Subsystem: "cluster", Name: "all_agree",
|
||||
Help: "1 if all members report identical membership",
|
||||
}, []string{"db", "cid"})
|
||||
|
||||
r.metrics.membersExpected = p.NewGaugeVec(prometheus.GaugeOpts{
|
||||
Namespace: ns, Subsystem: "cluster", Name: "members_expected",
|
||||
Help: "Expected cluster size (replicas)",
|
||||
}, []string{"db", "cid"})
|
||||
|
||||
r.metrics.membersObserved = p.NewGaugeVec(prometheus.GaugeOpts{
|
||||
Namespace: ns, Subsystem: "cluster", Name: "members_observed",
|
||||
Help: "Observed members (distinct SIDs across views)",
|
||||
}, []string{"db", "cid"})
|
||||
|
||||
r.metrics.ipsExpected = p.NewGaugeVec(prometheus.GaugeOpts{
|
||||
Namespace: ns, Subsystem: "cluster", Name: "ips_expected",
|
||||
Help: "Expected distinct member IPs (from k8s hints)",
|
||||
}, []string{"db", "cid"})
|
||||
|
||||
r.metrics.ipsObserved = p.NewGaugeVec(prometheus.GaugeOpts{
|
||||
Namespace: ns, Subsystem: "cluster", Name: "ips_observed",
|
||||
Help: "Observed distinct member IPs (from OVN views)",
|
||||
}, []string{"db", "cid"})
|
||||
|
||||
r.metrics.excessMembers = p.NewGaugeVec(prometheus.GaugeOpts{
|
||||
Namespace: ns, Subsystem: "cluster", Name: "excess_members",
|
||||
Help: "Members over expected (>=0)",
|
||||
}, []string{"db", "cid"})
|
||||
|
||||
r.metrics.missingMembers = p.NewGaugeVec(prometheus.GaugeOpts{
|
||||
Namespace: ns, Subsystem: "cluster", Name: "missing_members",
|
||||
Help: "Members short of expected (>=0)",
|
||||
}, []string{"db", "cid"})
|
||||
|
||||
r.metrics.unexpectedIPsCount = p.NewGaugeVec(prometheus.GaugeOpts{
|
||||
Namespace: ns, Subsystem: "cluster", Name: "unexpected_ips",
|
||||
Help: "Count of IPs in OVN not present in k8s expected set",
|
||||
}, []string{"db", "cid"})
|
||||
|
||||
r.metrics.missingExpectedIPsCount = p.NewGaugeVec(prometheus.GaugeOpts{
|
||||
Namespace: ns, Subsystem: "cluster", Name: "missing_expected_ips",
|
||||
Help: "Count of expected IPs not found in OVN",
|
||||
}, []string{"db", "cid"})
|
||||
|
||||
r.metrics.ipConflictsCount = p.NewGaugeVec(prometheus.GaugeOpts{
|
||||
Namespace: ns, Subsystem: "cluster", Name: "ip_conflicts",
|
||||
Help: "Number of IPs claimed by multiple SIDs",
|
||||
}, []string{"db", "cid"})
|
||||
|
||||
r.metrics.sidAddrDisagreements = p.NewGaugeVec(prometheus.GaugeOpts{
|
||||
Namespace: ns, Subsystem: "cluster", Name: "sid_address_disagreements",
|
||||
Help: "Number of SIDs seen with >1 distinct addresses",
|
||||
}, []string{"db", "cid"})
|
||||
|
||||
// --- Consensus summary ---
|
||||
r.metrics.consensusMajoritySize = p.NewGaugeVec(prometheus.GaugeOpts{
|
||||
Namespace: ns, Subsystem: "consensus", Name: "majority_size",
|
||||
Help: "Majority group size (0 if none)",
|
||||
}, []string{"db", "cid"})
|
||||
|
||||
r.metrics.consensusMinoritySize = p.NewGaugeVec(prometheus.GaugeOpts{
|
||||
Namespace: ns, Subsystem: "consensus", Name: "minority_size",
|
||||
Help: "Minority group size",
|
||||
}, []string{"db", "cid"})
|
||||
|
||||
r.metrics.consensusDiffsTotal = p.NewGaugeVec(prometheus.GaugeOpts{
|
||||
Namespace: ns, Subsystem: "consensus", Name: "diffs_total",
|
||||
Help: "Total per-reporter differences vs truth (missing + extra + mismatches)",
|
||||
}, []string{"db", "cid"})
|
||||
|
||||
// --- Detail exports (sparse) ---
|
||||
r.metrics.unexpectedIPGauge = p.NewGaugeVec(prometheus.GaugeOpts{
|
||||
Namespace: ns, Subsystem: "consensus", Name: "unexpected_ip",
|
||||
Help: "Unexpected IP present in OVN; value fixed at 1",
|
||||
}, []string{"db", "cid", "ip"})
|
||||
|
||||
r.metrics.missingExpectedIPGauge = p.NewGaugeVec(prometheus.GaugeOpts{
|
||||
Namespace: ns, Subsystem: "consensus", Name: "missing_expected_ip",
|
||||
Help: "Expected IP missing from OVN; value fixed at 1",
|
||||
}, []string{"db", "cid", "ip"})
|
||||
|
||||
r.metrics.ipConflictGauge = p.NewGaugeVec(prometheus.GaugeOpts{
|
||||
Namespace: ns, Subsystem: "consensus", Name: "ip_conflict",
|
||||
Help: "Number of SIDs claiming the same IP for this key",
|
||||
}, []string{"db", "cid", "ip"})
|
||||
|
||||
r.metrics.suspectStaleGauge = p.NewGaugeVec(prometheus.GaugeOpts{
|
||||
Namespace: ns, Subsystem: "consensus", Name: "suspect_stale",
|
||||
Help: "Suspected stale SID candidate for kick; value fixed at 1 (emit only when remediation is warranted)",
|
||||
}, []string{"db", "cid", "sid"})
|
||||
|
||||
// --- Per-member liveness/freshness ---
|
||||
r.metrics.memberConnected = p.NewGaugeVec(prometheus.GaugeOpts{
|
||||
Namespace: ns, Subsystem: "member", Name: "connected",
|
||||
Help: "1 if local server reports connected/quorum, else 0",
|
||||
}, []string{"db", "cid", "sid", "ip"})
|
||||
|
||||
r.metrics.memberLeader = p.NewGaugeVec(prometheus.GaugeOpts{
|
||||
Namespace: ns, Subsystem: "member", Name: "leader",
|
||||
Help: "1 if this member is leader, else 0",
|
||||
}, []string{"db", "cid", "sid"})
|
||||
|
||||
r.metrics.memberLastMsgMs = p.NewGaugeVec(prometheus.GaugeOpts{
|
||||
Namespace: ns, Subsystem: "member", Name: "last_msg_ms",
|
||||
Help: "Follower->leader 'last msg' age in ms (legacy heuristic). NaN/omit if unknown",
|
||||
}, []string{"db", "cid", "sid"})
|
||||
|
||||
r.metrics.memberIndex = p.NewGaugeVec(prometheus.GaugeOpts{
|
||||
Namespace: ns, Subsystem: "member", Name: "index",
|
||||
Help: "Local Raft log index",
|
||||
}, []string{"db", "cid", "sid"})
|
||||
|
||||
r.metrics.memberIndexGap = p.NewGaugeVec(prometheus.GaugeOpts{
|
||||
Namespace: ns, Subsystem: "member", Name: "index_gap",
|
||||
Help: "Leader index minus local index (>=0)",
|
||||
}, []string{"db", "cid", "sid"})
|
||||
|
||||
r.metrics.memberReporter = p.NewGaugeVec(prometheus.GaugeOpts{
|
||||
Namespace: ns, Subsystem: "member", Name: "reporter",
|
||||
Help: "1 if a self-view from this SID was collected in the scrape cycle",
|
||||
}, []string{"db", "cid", "sid"})
|
||||
|
||||
r.metrics.memberMissingReporter = p.NewGaugeVec(prometheus.GaugeOpts{
|
||||
Namespace: ns, Subsystem: "member", Name: "missing_reporter",
|
||||
Help: "1 if SID appears in union but produced no self-view",
|
||||
}, []string{"db", "cid", "sid"})
|
||||
|
||||
// --- Ops/housekeeping ---
|
||||
r.metrics.leaderTransitionsTotal = p.NewCounterVec(prometheus.CounterOpts{
|
||||
Namespace: ns, Subsystem: "ops", Name: "leader_transitions_total",
|
||||
Help: "Count of observed leader SID changes",
|
||||
}, []string{"db", "cid"})
|
||||
|
||||
r.metrics.collectErrorsTotal = p.NewCounterVec(prometheus.CounterOpts{
|
||||
Namespace: ns, Subsystem: "ops", Name: "collect_errors_total",
|
||||
Help: "Count of errors during health collection/analysis",
|
||||
}, []string{"db", "cid"})
|
||||
|
||||
r.metrics.publishEventsTotal = p.NewCounterVec(prometheus.CounterOpts{
|
||||
Namespace: ns, Subsystem: "ops", Name: "publish_events_total",
|
||||
Help: "Count of SSE publish events (optional)",
|
||||
}, []string{"db", "cid"})
|
||||
|
||||
r.metrics.snapshotTimestampSec = p.NewGaugeVec(prometheus.GaugeOpts{
|
||||
Namespace: ns, Subsystem: "ops", Name: "snapshot_timestamp_seconds",
|
||||
Help: "Unix timestamp of the last successful consensus snapshot",
|
||||
}, []string{"db", "cid"})
|
||||
}
|
||||
|
||||
func (r *KubeOVNPlunger) WriteClusterMetrics(db string, snaps []ovnstatus.HealthSnapshot, ecv ovnstatus.ExtendedConsensusResult, expectedReplicas int) {
|
||||
cid := cidFromSnaps(snaps)
|
||||
|
||||
// Core cluster health
|
||||
r.metrics.clusterQuorum.WithLabelValues(db, cid).Set(b2f(ecv.HasMajority))
|
||||
r.metrics.allAgree.WithLabelValues(db, cid).Set(b2f(ecv.AllAgree))
|
||||
r.metrics.membersExpected.WithLabelValues(db, cid).Set(float64(expectedReplicas))
|
||||
r.metrics.membersObserved.WithLabelValues(db, cid).Set(float64(ecv.MembersCount))
|
||||
r.metrics.ipsExpected.WithLabelValues(db, cid).Set(float64(len(ecv.ConsensusResult.TruthView.Members))) // optional; or len(hints.ExpectedIPs)
|
||||
r.metrics.ipsObserved.WithLabelValues(db, cid).Set(float64(ecv.DistinctIPCount))
|
||||
r.metrics.excessMembers.WithLabelValues(db, cid).Set(float64(ecv.ExpectedExcess))
|
||||
r.metrics.missingMembers.WithLabelValues(db, cid).Set(float64(ecv.ExpectedShortfall))
|
||||
r.metrics.unexpectedIPsCount.WithLabelValues(db, cid).Set(float64(len(ecv.UnexpectedIPs)))
|
||||
r.metrics.missingExpectedIPsCount.WithLabelValues(db, cid).Set(float64(len(ecv.MissingExpectedIPs)))
|
||||
r.metrics.ipConflictsCount.WithLabelValues(db, cid).Set(float64(len(ecv.IPConflicts)))
|
||||
|
||||
// Count SIDs with >1 distinct addresses
|
||||
disagree := 0
|
||||
for _, n := range ecv.SIDAddressDisagreements {
|
||||
if n > 1 {
|
||||
disagree++
|
||||
}
|
||||
}
|
||||
r.metrics.sidAddrDisagreements.WithLabelValues(db, cid).Set(float64(disagree))
|
||||
|
||||
// Consensus summary
|
||||
r.metrics.consensusMajoritySize.WithLabelValues(db, cid).Set(float64(len(ecv.MajorityMembers)))
|
||||
r.metrics.consensusMinoritySize.WithLabelValues(db, cid).Set(float64(len(ecv.MinorityMembers)))
|
||||
|
||||
// Sum diffs across reporters (missing + extra + mismatches)
|
||||
totalDiffs := 0
|
||||
for _, d := range ecv.Diffs {
|
||||
totalDiffs += len(d.MissingSIDs) + len(d.ExtraSIDs) + len(d.AddressMismatches)
|
||||
}
|
||||
r.metrics.consensusDiffsTotal.WithLabelValues(db, cid).Set(float64(totalDiffs))
|
||||
|
||||
// Sparse per-key exports (reset then re-emit for this {db,cid})
|
||||
r.metrics.unexpectedIPGauge.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid})
|
||||
for _, ip := range ecv.UnexpectedIPs {
|
||||
r.metrics.unexpectedIPGauge.WithLabelValues(db, cid, ip).Set(1)
|
||||
}
|
||||
|
||||
r.metrics.missingExpectedIPGauge.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid})
|
||||
for _, ip := range ecv.MissingExpectedIPs {
|
||||
r.metrics.missingExpectedIPGauge.WithLabelValues(db, cid, ip).Set(1)
|
||||
}
|
||||
|
||||
r.metrics.ipConflictGauge.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid})
|
||||
for ip, sids := range ecv.IPConflicts {
|
||||
r.metrics.ipConflictGauge.WithLabelValues(db, cid, ip).Set(float64(len(sids)))
|
||||
}
|
||||
|
||||
// Only emit suspects when remediation is warranted (e.g., TooManyMembers / unexpected IPs / conflicts)
|
||||
r.metrics.suspectStaleGauge.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid})
|
||||
if ecv.TooManyMembers || len(ecv.UnexpectedIPs) > 0 || len(ecv.IPConflicts) > 0 {
|
||||
for _, sid := range ecv.SuspectStaleSIDs {
|
||||
r.metrics.suspectStaleGauge.WithLabelValues(db, cid, sid).Set(1)
|
||||
}
|
||||
}
|
||||
|
||||
// Snapshot timestamp
|
||||
r.metrics.snapshotTimestampSec.WithLabelValues(db, cid).Set(float64(time.Now().Unix()))
|
||||
}
|
||||
|
||||
func (r *KubeOVNPlunger) WriteMemberMetrics(db string, snaps []ovnstatus.HealthSnapshot, views []ovnstatus.MemberView, ecv ovnstatus.ExtendedConsensusResult) {
|
||||
cid := cidFromSnaps(snaps)
|
||||
|
||||
// Figure out current leader SID (prefer local view from any leader snapshot)
|
||||
curLeader := ""
|
||||
for _, s := range snaps {
|
||||
if s.Local.Leader {
|
||||
curLeader = s.Local.SID
|
||||
break
|
||||
}
|
||||
}
|
||||
// Leader transitions
|
||||
key := db + "|" + cid
|
||||
if prev, ok := r.lastLeader[key]; ok && prev != "" && curLeader != "" && prev != curLeader {
|
||||
r.metrics.leaderTransitionsTotal.WithLabelValues(db, cid).Inc()
|
||||
}
|
||||
if curLeader != "" {
|
||||
r.lastLeader[key] = curLeader
|
||||
}
|
||||
|
||||
// Build quick maps for reporter set & IP per SID (best-effort)
|
||||
reporter := map[string]struct{}{}
|
||||
for _, v := range views {
|
||||
if v.FromSID != "" {
|
||||
reporter[v.FromSID] = struct{}{}
|
||||
}
|
||||
}
|
||||
sidToIP := map[string]string{}
|
||||
for _, v := range views {
|
||||
for sid, addr := range v.Members {
|
||||
if sidToIP[sid] == "" && addr != "" {
|
||||
sidToIP[sid] = ovnstatus.AddrToIP(addr) // expose addrToIP or wrap here
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Reset member vectors for this {db,cid} (avoid stale series)
|
||||
r.metrics.memberConnected.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid})
|
||||
r.metrics.memberLeader.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid})
|
||||
r.metrics.memberLastMsgMs.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid})
|
||||
r.metrics.memberIndex.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid})
|
||||
r.metrics.memberIndexGap.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid})
|
||||
r.metrics.memberReporter.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid})
|
||||
r.metrics.memberMissingReporter.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid})
|
||||
|
||||
// Leader index (to compute gaps)
|
||||
lIdx := leaderIndex(snaps, curLeader)
|
||||
|
||||
// Emit one series per snapshot (self view)
|
||||
for _, s := range snaps {
|
||||
sid := s.Local.SID
|
||||
ip := sidToIP[sid]
|
||||
if ip == "" {
|
||||
ip = "unknown"
|
||||
}
|
||||
|
||||
r.metrics.memberConnected.WithLabelValues(db, cid, sid, ip).Set(b2f(s.Local.Connected))
|
||||
r.metrics.memberLeader.WithLabelValues(db, cid, sid).Set(b2f(s.Local.Leader))
|
||||
r.metrics.memberIndex.WithLabelValues(db, cid, sid).Set(float64(s.Local.Index))
|
||||
|
||||
if lIdx != nil && s.Local.Index >= 0 {
|
||||
gap := *lIdx - s.Local.Index
|
||||
if gap < 0 {
|
||||
gap = 0
|
||||
}
|
||||
r.metrics.memberIndexGap.WithLabelValues(db, cid, sid).Set(float64(gap))
|
||||
}
|
||||
|
||||
// Reporter presence
|
||||
_, isReporter := reporter[sid]
|
||||
r.metrics.memberReporter.WithLabelValues(db, cid, sid).Set(b2f(isReporter))
|
||||
}
|
||||
|
||||
// “Missing reporter” SIDs = union − reporters (from ecv)
|
||||
reporterSet := map[string]struct{}{}
|
||||
for sid := range reporter {
|
||||
reporterSet[sid] = struct{}{}
|
||||
}
|
||||
unionSet := map[string]struct{}{}
|
||||
for _, sid := range ecv.UnionMembers {
|
||||
unionSet[sid] = struct{}{}
|
||||
}
|
||||
for sid := range unionSet {
|
||||
if _, ok := reporterSet[sid]; !ok {
|
||||
r.metrics.memberMissingReporter.WithLabelValues(db, cid, sid).Set(1)
|
||||
}
|
||||
}
|
||||
|
||||
// Legacy follower freshness (if you kept LastMsgMs in servers parsing)
|
||||
// We only know LastMsgMs from the Full.Servers in each snapshot; pick the freshest per SID.
|
||||
lastMsg := map[string]int64{}
|
||||
for _, s := range snaps {
|
||||
for _, srv := range s.Full.Servers {
|
||||
if srv.LastMsgMs != nil {
|
||||
cur, ok := lastMsg[srv.SID]
|
||||
if !ok || *srv.LastMsgMs < cur {
|
||||
lastMsg[srv.SID] = *srv.LastMsgMs
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for sid, ms := range lastMsg {
|
||||
r.metrics.memberLastMsgMs.WithLabelValues(db, cid, sid).Set(float64(ms))
|
||||
}
|
||||
}
|
||||
|
||||
func (r *KubeOVNPlunger) deleteAllFor(db, cid string) {
|
||||
// Cluster-level vecs (db,cid)
|
||||
r.metrics.clusterQuorum.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid})
|
||||
r.metrics.allAgree.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid})
|
||||
r.metrics.membersExpected.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid})
|
||||
r.metrics.membersObserved.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid})
|
||||
r.metrics.ipsExpected.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid})
|
||||
r.metrics.ipsObserved.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid})
|
||||
r.metrics.excessMembers.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid})
|
||||
r.metrics.missingMembers.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid})
|
||||
r.metrics.unexpectedIPsCount.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid})
|
||||
r.metrics.missingExpectedIPsCount.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid})
|
||||
r.metrics.ipConflictsCount.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid})
|
||||
r.metrics.sidAddrDisagreements.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid})
|
||||
|
||||
r.metrics.consensusMajoritySize.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid})
|
||||
r.metrics.consensusMinoritySize.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid})
|
||||
r.metrics.consensusDiffsTotal.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid})
|
||||
|
||||
// Sparse detail vecs (db,cid,*)
|
||||
r.metrics.unexpectedIPGauge.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid})
|
||||
r.metrics.missingExpectedIPGauge.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid})
|
||||
r.metrics.ipConflictGauge.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid})
|
||||
r.metrics.suspectStaleGauge.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid})
|
||||
|
||||
// Per-member vecs (db,cid,*)
|
||||
r.metrics.memberConnected.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid})
|
||||
r.metrics.memberLeader.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid})
|
||||
r.metrics.memberLastMsgMs.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid})
|
||||
r.metrics.memberIndex.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid})
|
||||
r.metrics.memberIndexGap.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid})
|
||||
r.metrics.memberReporter.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid})
|
||||
r.metrics.memberMissingReporter.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid})
|
||||
|
||||
// Ops vecs (db,cid)
|
||||
r.metrics.leaderTransitionsTotal.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid})
|
||||
r.metrics.collectErrorsTotal.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid})
|
||||
r.metrics.publishEventsTotal.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid})
|
||||
r.metrics.snapshotTimestampSec.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid})
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
package kubeovnplunger
|
||||
|
||||
import "github.com/cozystack/cozystack/pkg/ovnstatus"
|
||||
|
||||
func b2f(b bool) float64 {
|
||||
if b {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// Pull a cluster UUID (cid) from any snapshots’ Local.CID (falls back to "")
|
||||
func cidFromSnaps(snaps []ovnstatus.HealthSnapshot) string {
|
||||
for _, s := range snaps {
|
||||
if s.Local.CID != "" {
|
||||
return s.Local.CID
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// Map SID -> last local index to compute gaps (optional)
|
||||
func leaderIndex(snaps []ovnstatus.HealthSnapshot, leaderSID string) (idx *int64) {
|
||||
for _, s := range snaps {
|
||||
if s.Local.SID == leaderSID && s.Local.Index > 0 {
|
||||
v := s.Local.Index
|
||||
return &v
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1,367 +0,0 @@
|
||||
package lineagelabeler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1"
|
||||
"github.com/cozystack/cozystack/internal/shared/crdmem"
|
||||
"github.com/cozystack/cozystack/pkg/lineage"
|
||||
|
||||
helmv2 "github.com/fluxcd/helm-controller/api/v2"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/client-go/discovery"
|
||||
"k8s.io/client-go/discovery/cached/memory"
|
||||
"k8s.io/client-go/dynamic"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/restmapper"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/builder"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/handler"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||
"sigs.k8s.io/controller-runtime/pkg/predicate"
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
)
|
||||
|
||||
var ErrNoAncestors = errors.New("no ancestors")
|
||||
|
||||
type LineageLabelerReconciler struct {
|
||||
client.Client
|
||||
Scheme *runtime.Scheme
|
||||
|
||||
WatchResourceCSV string
|
||||
|
||||
dynClient dynamic.Interface
|
||||
mapper meta.RESTMapper
|
||||
|
||||
appMap atomic.Value
|
||||
once sync.Once
|
||||
|
||||
mem *crdmem.Memory
|
||||
}
|
||||
|
||||
type chartRef struct{ repo, chart string }
|
||||
type appRef struct{ groupVersion, kind, prefix string }
|
||||
|
||||
func (r *LineageLabelerReconciler) initMapping() {
|
||||
r.once.Do(func() {
|
||||
r.appMap.Store(make(map[chartRef]appRef))
|
||||
})
|
||||
}
|
||||
|
||||
func (r *LineageLabelerReconciler) currentMap() map[chartRef]appRef {
|
||||
val := r.appMap.Load()
|
||||
if val == nil {
|
||||
return map[chartRef]appRef{}
|
||||
}
|
||||
return val.(map[chartRef]appRef)
|
||||
}
|
||||
|
||||
func (r *LineageLabelerReconciler) Map(hr *helmv2.HelmRelease) (string, string, string, error) {
|
||||
cfg := r.currentMap()
|
||||
s := hr.Spec.Chart.Spec
|
||||
key := chartRef{s.SourceRef.Name, s.Chart}
|
||||
if v, ok := cfg[key]; ok {
|
||||
return v.groupVersion, v.kind, v.prefix, nil
|
||||
}
|
||||
return "", "", "", fmt.Errorf("cannot map helm release %s/%s to dynamic app", hr.Namespace, hr.Name)
|
||||
}
|
||||
|
||||
func parseGVKList(csv string) ([]schema.GroupVersionKind, error) {
|
||||
csv = strings.TrimSpace(csv)
|
||||
if csv == "" {
|
||||
return nil, fmt.Errorf("watch resource list is empty")
|
||||
}
|
||||
parts := strings.Split(csv, ",")
|
||||
out := make([]schema.GroupVersionKind, 0, len(parts))
|
||||
for _, p := range parts {
|
||||
p = strings.TrimSpace(p)
|
||||
s := strings.Split(p, "/")
|
||||
if len(s) == 2 {
|
||||
out = append(out, schema.GroupVersionKind{Group: "", Version: s[0], Kind: s[1]})
|
||||
continue
|
||||
}
|
||||
if len(s) == 3 {
|
||||
out = append(out, schema.GroupVersionKind{Group: s[0], Version: s[1], Kind: s[2]})
|
||||
continue
|
||||
}
|
||||
return nil, fmt.Errorf("invalid resource token %q, expected 'group/version/Kind' or 'v1/Kind'", p)
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (r *LineageLabelerReconciler) SetupWithManager(mgr ctrl.Manager) error {
|
||||
r.initMapping()
|
||||
|
||||
cfg := rest.CopyConfig(mgr.GetConfig())
|
||||
dc, err := dynamic.NewForConfig(cfg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
disco, err := discovery.NewDiscoveryClientForConfig(cfg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cached := memory.NewMemCacheClient(disco)
|
||||
r.dynClient = dc
|
||||
r.mapper = restmapper.NewDeferredDiscoveryRESTMapper(cached)
|
||||
|
||||
if r.mem == nil {
|
||||
r.mem = crdmem.Global()
|
||||
}
|
||||
if err := r.mem.EnsurePrimingWithManager(mgr); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
gvks, err := parseGVKList(r.WatchResourceCSV)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(gvks) == 0 {
|
||||
return fmt.Errorf("no resources to watch")
|
||||
}
|
||||
|
||||
b := ctrl.NewControllerManagedBy(mgr).Named("lineage-labeler")
|
||||
|
||||
nsPred := predicate.NewPredicateFuncs(func(obj client.Object) bool {
|
||||
ns := obj.GetNamespace()
|
||||
return ns != "" && strings.HasPrefix(ns, "tenant-")
|
||||
})
|
||||
|
||||
primary := gvks[0]
|
||||
primaryObj := &unstructured.Unstructured{}
|
||||
primaryObj.SetGroupVersionKind(primary)
|
||||
b = b.For(primaryObj,
|
||||
builder.WithPredicates(
|
||||
predicate.And(
|
||||
nsPred,
|
||||
predicate.Or(
|
||||
predicate.GenerationChangedPredicate{},
|
||||
predicate.ResourceVersionChangedPredicate{},
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
for _, gvk := range gvks[1:] {
|
||||
u := &unstructured.Unstructured{}
|
||||
u.SetGroupVersionKind(gvk)
|
||||
b = b.Watches(u,
|
||||
&handler.EnqueueRequestForObject{},
|
||||
builder.WithPredicates(
|
||||
predicate.And(
|
||||
nsPred,
|
||||
predicate.Or(
|
||||
predicate.GenerationChangedPredicate{},
|
||||
predicate.ResourceVersionChangedPredicate{},
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
b = b.Watches(
|
||||
&cozyv1alpha1.CozystackResourceDefinition{},
|
||||
handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, obj client.Object) []reconcile.Request {
|
||||
_ = r.refreshAppMap(ctx)
|
||||
return nil
|
||||
}),
|
||||
)
|
||||
|
||||
_ = r.refreshAppMap(context.Background())
|
||||
|
||||
return b.Complete(r)
|
||||
}
|
||||
|
||||
func (r *LineageLabelerReconciler) refreshAppMap(ctx context.Context) error {
|
||||
var items []cozyv1alpha1.CozystackResourceDefinition
|
||||
var err error
|
||||
if r.mem != nil {
|
||||
items, err = r.mem.ListFromCacheOrAPI(ctx, r.Client)
|
||||
} else {
|
||||
var list cozyv1alpha1.CozystackResourceDefinitionList
|
||||
err = r.Client.List(ctx, &list)
|
||||
items = list.Items
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
newMap := make(map[chartRef]appRef, len(items))
|
||||
for _, crd := range items {
|
||||
k := chartRef{
|
||||
repo: crd.Spec.Release.Chart.SourceRef.Name,
|
||||
chart: crd.Spec.Release.Chart.Name,
|
||||
}
|
||||
v := appRef{
|
||||
groupVersion: "apps.cozystack.io/v1alpha1",
|
||||
kind: crd.Spec.Application.Kind,
|
||||
prefix: crd.Spec.Release.Prefix,
|
||||
}
|
||||
if _, exists := newMap[k]; exists {
|
||||
continue
|
||||
}
|
||||
newMap[k] = v
|
||||
}
|
||||
r.appMap.Store(newMap)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *LineageLabelerReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
|
||||
l := log.FromContext(ctx)
|
||||
|
||||
if req.Namespace == "" || !strings.HasPrefix(req.Namespace, "tenant-") {
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
|
||||
if len(r.currentMap()) == 0 {
|
||||
_ = r.refreshAppMap(ctx)
|
||||
if len(r.currentMap()) == 0 {
|
||||
return ctrl.Result{RequeueAfter: 2 * time.Second}, nil
|
||||
}
|
||||
}
|
||||
|
||||
gvks, err := parseGVKList(r.WatchResourceCSV)
|
||||
if err != nil {
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
|
||||
var obj *unstructured.Unstructured
|
||||
found := false
|
||||
|
||||
for _, gvk := range gvks {
|
||||
mapping, mErr := r.mapper.RESTMapping(gvk.GroupKind(), gvk.Version)
|
||||
if mErr != nil {
|
||||
continue
|
||||
}
|
||||
ns := req.Namespace
|
||||
if mapping.Scope.Name() != meta.RESTScopeNameNamespace {
|
||||
ns = ""
|
||||
}
|
||||
res, gErr := r.dynClient.Resource(mapping.Resource).Namespace(ns).Get(ctx, req.Name, metav1.GetOptions{})
|
||||
if gErr != nil {
|
||||
if apierrors.IsNotFound(gErr) {
|
||||
continue
|
||||
}
|
||||
continue
|
||||
}
|
||||
obj = res
|
||||
found = true
|
||||
break
|
||||
}
|
||||
|
||||
if !found || obj == nil {
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
|
||||
existing := obj.GetLabels()
|
||||
if existing == nil {
|
||||
existing = map[string]string{}
|
||||
}
|
||||
|
||||
keys := []string{
|
||||
"apps.cozystack.io/application.group",
|
||||
"apps.cozystack.io/application.kind",
|
||||
"apps.cozystack.io/application.name",
|
||||
}
|
||||
allPresent := true
|
||||
for _, k := range keys {
|
||||
if _, ok := existing[k]; !ok {
|
||||
allPresent = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if allPresent {
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
|
||||
labels, warn, err := r.computeLabels(ctx, obj)
|
||||
if err != nil {
|
||||
if errors.Is(err, ErrNoAncestors) {
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
return ctrl.Result{}, client.IgnoreNotFound(err)
|
||||
}
|
||||
if warn != "" {
|
||||
l.V(1).Info("lineage ambiguous; using first ancestor", "name", req.NamespacedName)
|
||||
}
|
||||
|
||||
for k, v := range labels {
|
||||
existing[k] = v
|
||||
}
|
||||
obj.SetLabels(existing)
|
||||
|
||||
// Server-Side Apply: claim ownership of our label keys
|
||||
gvk := obj.GroupVersionKind()
|
||||
patch := &unstructured.Unstructured{}
|
||||
patch.SetGroupVersionKind(gvk)
|
||||
patch.SetNamespace(obj.GetNamespace())
|
||||
patch.SetName(obj.GetName())
|
||||
patch.SetLabels(map[string]string{
|
||||
"apps.cozystack.io/application.group": existing["apps.cozystack.io/application.group"],
|
||||
"apps.cozystack.io/application.kind": existing["apps.cozystack.io/application.kind"],
|
||||
"apps.cozystack.io/application.name": existing["apps.cozystack.io/application.name"],
|
||||
})
|
||||
|
||||
// Use controller-runtime client with Apply patch type and field owner
|
||||
if err := r.Patch(ctx, patch,
|
||||
client.Apply,
|
||||
client.FieldOwner("cozystack/lineage"),
|
||||
client.ForceOwnership(false),
|
||||
); err != nil {
|
||||
if apierrors.IsConflict(err) {
|
||||
return ctrl.Result{RequeueAfter: 500 * time.Millisecond}, nil
|
||||
}
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
|
||||
func (r *LineageLabelerReconciler) computeLabels(ctx context.Context, o *unstructured.Unstructured) (map[string]string, string, error) {
|
||||
owners := lineage.WalkOwnershipGraph(ctx, r.dynClient, r.mapper, r, o)
|
||||
if len(owners) == 0 {
|
||||
return nil, "", ErrNoAncestors
|
||||
}
|
||||
obj, err := owners[0].GetUnstructured(ctx, r.dynClient, r.mapper)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
gv, err := schema.ParseGroupVersion(obj.GetAPIVersion())
|
||||
if err != nil {
|
||||
return nil, "", fmt.Errorf("invalid APIVersion %s: %w", obj.GetAPIVersion(), err)
|
||||
}
|
||||
var warn string
|
||||
if len(owners) > 1 {
|
||||
warn = "ambiguous"
|
||||
}
|
||||
group := gv.Group
|
||||
if len(group) > 63 {
|
||||
group = trimDNSLabel(group[:63])
|
||||
}
|
||||
return map[string]string{
|
||||
"apps.cozystack.io/application.group": group,
|
||||
"apps.cozystack.io/application.kind": obj.GetKind(),
|
||||
"apps.cozystack.io/application.name": obj.GetName(),
|
||||
}, warn, nil
|
||||
}
|
||||
|
||||
func trimDNSLabel(s string) string {
|
||||
for len(s) > 0 {
|
||||
b := s[len(s)-1]
|
||||
if (b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z') || (b >= '0' && b <= '9') {
|
||||
return s
|
||||
}
|
||||
s = s[:len(s)-1]
|
||||
}
|
||||
return s
|
||||
}
|
||||
@@ -33,7 +33,6 @@ const requestedAt = "reconcile.fluxcd.io/requestedAt"
|
||||
|
||||
func (r *CozystackConfigReconciler) Reconcile(ctx context.Context, _ ctrl.Request) (ctrl.Result, error) {
|
||||
log := log.FromContext(ctx)
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
digest, err := r.computeDigest(ctx)
|
||||
if err != nil {
|
||||
|
||||
@@ -26,7 +26,6 @@ type TenantHelmReconciler struct {
|
||||
|
||||
func (r *TenantHelmReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
|
||||
logger := log.FromContext(ctx)
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
hr := &helmv2.HelmRelease{}
|
||||
if err := r.Get(ctx, req.NamespacedName, hr); err != nil {
|
||||
|
||||
@@ -1,99 +0,0 @@
|
||||
package crdmem
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
|
||||
cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
)
|
||||
|
||||
type Memory struct {
|
||||
mu sync.RWMutex
|
||||
data map[string]cozyv1alpha1.CozystackResourceDefinition
|
||||
primed bool
|
||||
primeOnce sync.Once
|
||||
}
|
||||
|
||||
func New() *Memory {
|
||||
return &Memory{data: make(map[string]cozyv1alpha1.CozystackResourceDefinition)}
|
||||
}
|
||||
|
||||
var (
|
||||
global *Memory
|
||||
globalOnce sync.Once
|
||||
)
|
||||
|
||||
func Global() *Memory {
|
||||
globalOnce.Do(func() { global = New() })
|
||||
return global
|
||||
}
|
||||
|
||||
func (m *Memory) Upsert(obj *cozyv1alpha1.CozystackResourceDefinition) {
|
||||
if obj == nil {
|
||||
return
|
||||
}
|
||||
m.mu.Lock()
|
||||
m.data[obj.Name] = *obj.DeepCopy()
|
||||
m.mu.Unlock()
|
||||
}
|
||||
|
||||
func (m *Memory) Delete(name string) {
|
||||
m.mu.Lock()
|
||||
delete(m.data, name)
|
||||
m.mu.Unlock()
|
||||
}
|
||||
|
||||
func (m *Memory) Snapshot() []cozyv1alpha1.CozystackResourceDefinition {
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
out := make([]cozyv1alpha1.CozystackResourceDefinition, 0, len(m.data))
|
||||
for _, v := range m.data {
|
||||
out = append(out, v)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func (m *Memory) IsPrimed() bool {
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
return m.primed
|
||||
}
|
||||
|
||||
type runnable func(context.Context) error
|
||||
|
||||
func (r runnable) Start(ctx context.Context) error { return r(ctx) }
|
||||
|
||||
func (m *Memory) EnsurePrimingWithManager(mgr ctrl.Manager) error {
|
||||
var errOut error
|
||||
m.primeOnce.Do(func() {
|
||||
errOut = mgr.Add(runnable(func(ctx context.Context) error {
|
||||
if ok := mgr.GetCache().WaitForCacheSync(ctx); !ok {
|
||||
return nil
|
||||
}
|
||||
var list cozyv1alpha1.CozystackResourceDefinitionList
|
||||
if err := mgr.GetClient().List(ctx, &list); err == nil {
|
||||
for i := range list.Items {
|
||||
m.Upsert(&list.Items[i])
|
||||
}
|
||||
m.mu.Lock()
|
||||
m.primed = true
|
||||
m.mu.Unlock()
|
||||
}
|
||||
return nil
|
||||
}))
|
||||
})
|
||||
return errOut
|
||||
}
|
||||
|
||||
func (m *Memory) ListFromCacheOrAPI(ctx context.Context, c client.Client) ([]cozyv1alpha1.CozystackResourceDefinition, error) {
|
||||
if m.IsPrimed() {
|
||||
return m.Snapshot(), nil
|
||||
}
|
||||
var list cozyv1alpha1.CozystackResourceDefinitionList
|
||||
if err := c.List(ctx, &list); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return list.Items, nil
|
||||
}
|
||||
@@ -1,293 +0,0 @@
|
||||
// Package sse provides a tiny Server-Sent Events server with pluggable routes.
|
||||
// No external deps; safe for quick demos and small dashboards.
|
||||
package sse
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"log"
|
||||
"net/http"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Options configures the SSE server.
|
||||
type Options struct {
|
||||
// Addr is the listening address, e.g. ":8080" or "127.0.0.1:0".
|
||||
Addr string
|
||||
|
||||
// IndexPath is the path serving a minimal live HTML page ("" to disable).
|
||||
// e.g. "/" or "/status"
|
||||
IndexPath string
|
||||
|
||||
// StreamPath is the SSE endpoint path, e.g. "/stream".
|
||||
StreamPath string
|
||||
|
||||
// Title for the index page (cosmetic).
|
||||
Title string
|
||||
|
||||
// AllowCORS, if true, sets Access-Control-Allow-Origin: * for /stream.
|
||||
AllowCORS bool
|
||||
|
||||
// ClientBuf is the per-client buffered message queue size.
|
||||
// If 0, defaults to 16. When full, new messages are dropped for that client.
|
||||
ClientBuf int
|
||||
|
||||
// Heartbeat sends a comment line every interval to keep connections alive.
|
||||
// If 0, defaults to 25s.
|
||||
Heartbeat time.Duration
|
||||
|
||||
// Logger (optional). If nil, log.Printf is used.
|
||||
Logger *log.Logger
|
||||
}
|
||||
|
||||
// Server is a simple SSE broadcaster.
|
||||
type Server struct {
|
||||
opts Options
|
||||
mux *http.ServeMux
|
||||
http *http.Server
|
||||
|
||||
clientsMu sync.RWMutex
|
||||
clients map[*client]struct{}
|
||||
|
||||
// latest holds the most recent payload (sent to new clients on connect).
|
||||
latestMu sync.RWMutex
|
||||
latest string
|
||||
}
|
||||
|
||||
type client struct {
|
||||
ch chan string
|
||||
closeCh chan struct{}
|
||||
flusher http.Flusher
|
||||
w http.ResponseWriter
|
||||
req *http.Request
|
||||
logf func(string, ...any)
|
||||
heartbeat time.Duration
|
||||
}
|
||||
|
||||
func New(opts Options) *Server {
|
||||
if opts.ClientBuf <= 0 {
|
||||
opts.ClientBuf = 16
|
||||
}
|
||||
if opts.Heartbeat <= 0 {
|
||||
opts.Heartbeat = 25 * time.Second
|
||||
}
|
||||
if opts.Addr == "" {
|
||||
opts.Addr = ":8080"
|
||||
}
|
||||
if opts.StreamPath == "" {
|
||||
opts.StreamPath = "/stream"
|
||||
}
|
||||
if opts.IndexPath == "" {
|
||||
opts.IndexPath = "/"
|
||||
}
|
||||
s := &Server{
|
||||
opts: opts,
|
||||
mux: http.NewServeMux(),
|
||||
clients: make(map[*client]struct{}),
|
||||
}
|
||||
s.routes()
|
||||
s.http = &http.Server{
|
||||
Addr: opts.Addr,
|
||||
Handler: s.mux,
|
||||
ReadHeaderTimeout: 10 * time.Second,
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Server) routes() {
|
||||
if s.opts.IndexPath != "" {
|
||||
s.mux.HandleFunc(s.opts.IndexPath, s.handleIndex)
|
||||
}
|
||||
s.mux.HandleFunc(s.opts.StreamPath, s.handleStream)
|
||||
}
|
||||
|
||||
func (s *Server) logf(format string, args ...any) {
|
||||
if s.opts.Logger != nil {
|
||||
s.opts.Logger.Printf(format, args...)
|
||||
} else {
|
||||
log.Printf(format, args...)
|
||||
}
|
||||
}
|
||||
|
||||
// ListenAndServe starts the HTTP server (blocking).
|
||||
func (s *Server) ListenAndServe() error {
|
||||
s.logf("sse: listening on http://%s (index=%s, stream=%s)", s.http.Addr, s.opts.IndexPath, s.opts.StreamPath)
|
||||
return s.http.ListenAndServe()
|
||||
}
|
||||
|
||||
// Shutdown gracefully stops the server.
|
||||
func (s *Server) Shutdown(ctx context.Context) error {
|
||||
s.clientsMu.Lock()
|
||||
for c := range s.clients {
|
||||
close(c.closeCh)
|
||||
}
|
||||
s.clientsMu.Unlock()
|
||||
return s.http.Shutdown(ctx)
|
||||
}
|
||||
|
||||
// Publish broadcasts a new payload to all clients and stores it as latest.
|
||||
func (s *Server) Publish(payload string) {
|
||||
// Store latest
|
||||
s.latestMu.Lock()
|
||||
s.latest = payload
|
||||
s.latestMu.Unlock()
|
||||
|
||||
// Broadcast
|
||||
s.clientsMu.RLock()
|
||||
defer s.clientsMu.RUnlock()
|
||||
for c := range s.clients {
|
||||
select {
|
||||
case c.ch <- payload:
|
||||
default:
|
||||
// Drop if client is slow (buffer full)
|
||||
if s.opts.Logger != nil {
|
||||
s.opts.Logger.Printf("sse: dropping message to slow client %p", c)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) handleIndex(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||
page := indexTemplate(s.opts.Title, s.opts.StreamPath)
|
||||
_, _ = w.Write([]byte(page))
|
||||
}
|
||||
|
||||
func (s *Server) handleStream(w http.ResponseWriter, r *http.Request) {
|
||||
// Required SSE headers
|
||||
if s.opts.AllowCORS {
|
||||
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||
}
|
||||
w.Header().Set("Content-Type", "text/event-stream")
|
||||
w.Header().Set("Cache-Control", "no-cache")
|
||||
w.Header().Set("Connection", "keep-alive")
|
||||
|
||||
flusher, ok := w.(http.Flusher)
|
||||
if !ok {
|
||||
http.Error(w, "streaming unsupported", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
c := &client{
|
||||
ch: make(chan string, s.opts.ClientBuf),
|
||||
closeCh: make(chan struct{}),
|
||||
flusher: flusher,
|
||||
w: w,
|
||||
req: r,
|
||||
logf: s.logf,
|
||||
heartbeat: s.opts.Heartbeat,
|
||||
}
|
||||
|
||||
// Register client
|
||||
s.clientsMu.Lock()
|
||||
s.clients[c] = struct{}{}
|
||||
s.clientsMu.Unlock()
|
||||
|
||||
// Initial comment to open the stream for some proxies
|
||||
fmt.Fprintf(w, ": connected %s\n\n", time.Now().Format(time.RFC3339))
|
||||
flusher.Flush()
|
||||
|
||||
// Send latest if any
|
||||
s.latestMu.RLock()
|
||||
latest := s.latest
|
||||
s.latestMu.RUnlock()
|
||||
if latest != "" {
|
||||
writeSSE(w, latest)
|
||||
flusher.Flush()
|
||||
}
|
||||
|
||||
// Start pump
|
||||
go c.pump()
|
||||
|
||||
// Block until client disconnects
|
||||
<-r.Context().Done()
|
||||
|
||||
// Unregister client
|
||||
close(c.closeCh)
|
||||
s.clientsMu.Lock()
|
||||
delete(s.clients, c)
|
||||
s.clientsMu.Unlock()
|
||||
}
|
||||
|
||||
func (c *client) pump() {
|
||||
t := time.NewTicker(c.heartbeat)
|
||||
defer t.Stop()
|
||||
for {
|
||||
select {
|
||||
case <-c.closeCh:
|
||||
return
|
||||
case msg := <-c.ch:
|
||||
writeSSE(c.w, msg)
|
||||
c.flusher.Flush()
|
||||
case <-t.C:
|
||||
// heartbeat comment (keeps connections alive through proxies)
|
||||
fmt.Fprint(c.w, ": hb\n\n")
|
||||
c.flusher.Flush()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func writeSSE(w http.ResponseWriter, msg string) {
|
||||
// Split on lines; each needs its own "data:" field per the SSE spec
|
||||
lines := strings.Split(strings.TrimRight(msg, "\n"), "\n")
|
||||
for _, ln := range lines {
|
||||
fmt.Fprintf(w, "data: %s\n", ln)
|
||||
}
|
||||
fmt.Fprint(w, "\n")
|
||||
}
|
||||
|
||||
// Minimal index page with live updates
|
||||
func indexTemplate(title, streamPath string) string {
|
||||
if title == "" {
|
||||
title = "SSE Stream"
|
||||
}
|
||||
if streamPath == "" {
|
||||
streamPath = "/stream"
|
||||
}
|
||||
const tpl = `<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>{{.Title}}</title>
|
||||
<style>
|
||||
body { font-family: system-ui, sans-serif; margin: 2rem; }
|
||||
pre { background:#111; color:#eee; padding:1rem; border-radius:12px; white-space:pre-wrap;}
|
||||
.status { margin-bottom: 1rem; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>{{.Title}}</h1>
|
||||
<div class="status">Connecting…</div>
|
||||
<pre id="out"></pre>
|
||||
<script>
|
||||
const statusEl = document.querySelector('.status');
|
||||
const out = document.getElementById('out');
|
||||
const es = new EventSource('{{.Stream}}');
|
||||
es.onmessage = (e) => {
|
||||
// Replace content with the latest full snapshot
|
||||
if (e.data === "") return;
|
||||
// We accumulate until a blank 'data:' terminator; simpler approach: reset on first line.
|
||||
// For this demo, server always sends full content in one event, so just overwrite.
|
||||
out.textContent = (out._acc ?? "") + e.data + "\n";
|
||||
};
|
||||
es.addEventListener('open', () => { statusEl.textContent = "Connected"; out._acc = ""; });
|
||||
es.addEventListener('error', () => { statusEl.textContent = "Disconnected (browser will retry)…"; out._acc = ""; });
|
||||
// Optional: keep the latest only per message
|
||||
es.onmessage = (e) => {
|
||||
out.textContent = e.data + "\n";
|
||||
statusEl.textContent = "Connected";
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>`
|
||||
page, _ := template.New("idx").Parse(tpl)
|
||||
var b strings.Builder
|
||||
_ = page.Execute(&b, map[string]any{
|
||||
"Title": title,
|
||||
"Stream": streamPath,
|
||||
})
|
||||
return b.String()
|
||||
}
|
||||
@@ -16,7 +16,7 @@ type: application
|
||||
# This is the chart version. This version number should be incremented each time you make changes
|
||||
# to the chart and its templates, including the app version.
|
||||
# Versions are expected to follow Semantic Versioning (https://semver.org/)
|
||||
version: 0.13.0
|
||||
version: 0.12.0
|
||||
|
||||
# This is the version number of the application being deployed. This version number should be
|
||||
# incremented each time you make changes to the application. Versions are not expected to
|
||||
|
||||
@@ -8,11 +8,16 @@ generate:
|
||||
|
||||
image:
|
||||
docker buildx build images/clickhouse-backup \
|
||||
--provenance false \
|
||||
--builder=$(BUILDER) \
|
||||
--platform=$(PLATFORM) \
|
||||
--tag $(REGISTRY)/clickhouse-backup:$(call settag,$(CLICKHOUSE_BACKUP_TAG)) \
|
||||
--cache-from type=registry,ref=$(REGISTRY)/clickhouse-backup:latest \
|
||||
--cache-to type=inline \
|
||||
--metadata-file images/clickhouse-backup.json \
|
||||
$(BUILDX_ARGS)
|
||||
--push=$(PUSH) \
|
||||
--label "org.opencontainers.image.source=https://github.com/cozystack/cozystack" \
|
||||
--load=$(LOAD)
|
||||
echo "$(REGISTRY)/clickhouse-backup:$(call settag,$(CLICKHOUSE_BACKUP_TAG))@$$(yq e '."containerimage.digest"' images/clickhouse-backup.json -o json -r)" \
|
||||
> images/clickhouse-backup.tag
|
||||
rm -f images/clickhouse-backup.json
|
||||
|
||||
@@ -28,8 +28,10 @@ For more details, read [Restic: Effective Backup from Stdin](https://blog.aenix.
|
||||
| `replicas` | Number of Clickhouse replicas | `int` | `2` |
|
||||
| `shards` | Number of Clickhouse shards | `int` | `1` |
|
||||
| `resources` | Explicit CPU and memory configuration for each Clickhouse replica. When left empty, the preset defined in `resourcesPreset` is applied. | `*object` | `{}` |
|
||||
| `resources.cpu` | CPU available to each replica | `*quantity` | `null` |
|
||||
| `resources.memory` | Memory (RAM) available to each replica | `*quantity` | `null` |
|
||||
| `resources.cpu` | CPU | `*quantity` | `null` |
|
||||
| `resources.memory` | Memory | `*quantity` | `null` |
|
||||
| `resources.cpu` | CPU | `*quantity` | `null` |
|
||||
| `resources.memory` | Memory | `*quantity` | `null` |
|
||||
| `resourcesPreset` | Default sizing preset used when `resources` is omitted. Allowed values: `nano`, `micro`, `small`, `medium`, `large`, `xlarge`, `2xlarge`. | `string` | `small` |
|
||||
| `size` | Persistent Volume Claim size, available for application data | `quantity` | `10Gi` |
|
||||
| `storageClass` | StorageClass used to store the data | `string` | `""` |
|
||||
@@ -44,6 +46,8 @@ For more details, read [Restic: Effective Backup from Stdin](https://blog.aenix.
|
||||
| `users` | Users configuration | `map[string]object` | `{...}` |
|
||||
| `users[name].password` | Password for the user | `*string` | `null` |
|
||||
| `users[name].readonly` | User is `readonly`, default is `false`. | `*bool` | `null` |
|
||||
| `users[name].password` | Password for the user | `*string` | `null` |
|
||||
| `users[name].readonly` | User is `readonly`, default is `false`. | `*bool` | `null` |
|
||||
|
||||
|
||||
### Backup parameters
|
||||
@@ -56,20 +60,32 @@ For more details, read [Restic: Effective Backup from Stdin](https://blog.aenix.
|
||||
| `backup.s3Bucket` | S3 bucket used for storing backups | `string` | `s3.example.org/clickhouse-backups` |
|
||||
| `backup.schedule` | Cron schedule for automated backups | `string` | `0 2 * * *` |
|
||||
| `backup.cleanupStrategy` | Retention strategy for cleaning up old backups | `string` | `--keep-last=3 --keep-daily=3 --keep-within-weekly=1m` |
|
||||
| `backup.s3AccessKey` | Access key for S3, used for authentication | `string` | `<your-access-key>` |
|
||||
| `backup.s3SecretKey` | Secret key for S3, used for authentication | `string` | `<your-secret-key>` |
|
||||
| `backup.resticPassword` | Password for Restic backup encryption | `string` | `<password>` |
|
||||
| `backup.s3AccessKey` | Access key for S3, used for authentication | `string` | `oobaiRus9pah8PhohL1ThaeTa4UVa7gu` |
|
||||
| `backup.s3SecretKey` | Secret key for S3, used for authentication | `string` | `ju3eum4dekeich9ahM1te8waeGai0oog` |
|
||||
| `backup.resticPassword` | Password for Restic backup encryption | `string` | `ChaXoveekoh6eigh4siesheeda2quai0` |
|
||||
| `backup.enabled` | Enable regular backups, default is `false` | `bool` | `false` |
|
||||
| `backup.s3Region` | AWS S3 region where backups are stored | `string` | `us-east-1` |
|
||||
| `backup.s3Bucket` | S3 bucket used for storing backups | `string` | `s3.example.org/clickhouse-backups` |
|
||||
| `backup.schedule` | Cron schedule for automated backups | `string` | `0 2 * * *` |
|
||||
| `backup.cleanupStrategy` | Retention strategy for cleaning up old backups | `string` | `--keep-last=3 --keep-daily=3 --keep-within-weekly=1m` |
|
||||
| `backup.s3AccessKey` | Access key for S3, used for authentication | `string` | `oobaiRus9pah8PhohL1ThaeTa4UVa7gu` |
|
||||
| `backup.s3SecretKey` | Secret key for S3, used for authentication | `string` | `ju3eum4dekeich9ahM1te8waeGai0oog` |
|
||||
| `backup.resticPassword` | Password for Restic backup encryption | `string` | `ChaXoveekoh6eigh4siesheeda2quai0` |
|
||||
|
||||
|
||||
### Clickhouse Keeper parameters
|
||||
|
||||
| Name | Description | Type | Value |
|
||||
| ---------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | ----------- | ------- |
|
||||
| `clickhouseKeeper` | Clickhouse Keeper configuration | `*object` | `{}` |
|
||||
| `clickhouseKeeper.enabled` | Deploy ClickHouse Keeper for cluster coordination | `*bool` | `true` |
|
||||
| `clickhouseKeeper.size` | Persistent Volume Claim size, available for application data | `*quantity` | `1Gi` |
|
||||
| `clickhouseKeeper.resourcesPreset` | Default sizing preset used when `resources` is omitted. Allowed values: `nano`, `micro`, `small`, `medium`, `large`, `xlarge`, `2xlarge`. | `string` | `micro` |
|
||||
| `clickhouseKeeper.replicas` | Number of Keeper replicas | `*int` | `3` |
|
||||
| Name | Description | Type | Value |
|
||||
| ---------------------------------- | --------------------------------------------------------------------------------------------------------------------------- | ----------- | ------- |
|
||||
| `clickhouseKeeper` | Clickhouse Keeper configuration | `*object` | `{}` |
|
||||
| `clickhouseKeeper.enabled` | Deploy ClickHouse Keeper for cluster coordination | `*bool` | `true` |
|
||||
| `clickhouseKeeper.size` | Persistent Volume Claim size, available for application data | `*quantity` | `1Gi` |
|
||||
| `clickhouseKeeper.resourcesPreset` | Default sizing preset used when `resources` is omitted. Allowed values: nano, micro, small, medium, large, xlarge, 2xlarge. | `string` | `micro` |
|
||||
| `clickhouseKeeper.replicas` | Number of keeper replicas | `*int` | `3` |
|
||||
| `clickhouseKeeper.enabled` | Deploy ClickHouse Keeper for cluster coordination | `*bool` | `true` |
|
||||
| `clickhouseKeeper.size` | Persistent Volume Claim size, available for application data | `*quantity` | `1Gi` |
|
||||
| `clickhouseKeeper.resourcesPreset` | Default sizing preset used when `resources` is omitted. Allowed values: nano, micro, small, medium, large, xlarge, 2xlarge. | `string` | `micro` |
|
||||
| `clickhouseKeeper.replicas` | Number of keeper replicas | `*int` | `3` |
|
||||
|
||||
|
||||
## Parameter examples and reference
|
||||
|
||||
@@ -1 +1 @@
|
||||
ghcr.io/cozystack/cozystack/clickhouse-backup:0.13.0@sha256:3faf7a4cebf390b9053763107482de175aa0fdb88c1e77424fd81100b1c3a205
|
||||
ghcr.io/cozystack/cozystack/clickhouse-backup:0.11.1@sha256:3faf7a4cebf390b9053763107482de175aa0fdb88c1e77424fd81100b1c3a205
|
||||
|
||||
@@ -8,11 +8,11 @@
|
||||
"default": {
|
||||
"cleanupStrategy": "--keep-last=3 --keep-daily=3 --keep-within-weekly=1m",
|
||||
"enabled": false,
|
||||
"resticPassword": "\u003cpassword\u003e",
|
||||
"s3AccessKey": "\u003cyour-access-key\u003e",
|
||||
"resticPassword": "ChaXoveekoh6eigh4siesheeda2quai0",
|
||||
"s3AccessKey": "oobaiRus9pah8PhohL1ThaeTa4UVa7gu",
|
||||
"s3Bucket": "s3.example.org/clickhouse-backups",
|
||||
"s3Region": "us-east-1",
|
||||
"s3SecretKey": "\u003cyour-secret-key\u003e",
|
||||
"s3SecretKey": "ju3eum4dekeich9ahM1te8waeGai0oog",
|
||||
"schedule": "0 2 * * *"
|
||||
},
|
||||
"required": [
|
||||
@@ -39,12 +39,12 @@
|
||||
"resticPassword": {
|
||||
"description": "Password for Restic backup encryption",
|
||||
"type": "string",
|
||||
"default": "\u003cpassword\u003e"
|
||||
"default": "ChaXoveekoh6eigh4siesheeda2quai0"
|
||||
},
|
||||
"s3AccessKey": {
|
||||
"description": "Access key for S3, used for authentication",
|
||||
"type": "string",
|
||||
"default": "\u003cyour-access-key\u003e"
|
||||
"default": "oobaiRus9pah8PhohL1ThaeTa4UVa7gu"
|
||||
},
|
||||
"s3Bucket": {
|
||||
"description": "S3 bucket used for storing backups",
|
||||
@@ -59,7 +59,7 @@
|
||||
"s3SecretKey": {
|
||||
"description": "Secret key for S3, used for authentication",
|
||||
"type": "string",
|
||||
"default": "\u003cyour-secret-key\u003e"
|
||||
"default": "ju3eum4dekeich9ahM1te8waeGai0oog"
|
||||
},
|
||||
"schedule": {
|
||||
"description": "Cron schedule for automated backups",
|
||||
@@ -87,12 +87,12 @@
|
||||
"default": true
|
||||
},
|
||||
"replicas": {
|
||||
"description": "Number of Keeper replicas",
|
||||
"description": "Number of keeper replicas",
|
||||
"type": "integer",
|
||||
"default": 3
|
||||
},
|
||||
"resourcesPreset": {
|
||||
"description": "Default sizing preset used when `resources` is omitted. Allowed values: `nano`, `micro`, `small`, `medium`, `large`, `xlarge`, `2xlarge`.",
|
||||
"description": "Default sizing preset used when `resources` is omitted. Allowed values: nano, micro, small, medium, large, xlarge, 2xlarge.",
|
||||
"type": "string",
|
||||
"default": "micro",
|
||||
"enum": [
|
||||
@@ -151,7 +151,7 @@
|
||||
"default": {},
|
||||
"properties": {
|
||||
"cpu": {
|
||||
"description": "CPU available to each replica",
|
||||
"description": "CPU",
|
||||
"pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
|
||||
"anyOf": [
|
||||
{
|
||||
@@ -164,7 +164,7 @@
|
||||
"x-kubernetes-int-or-string": true
|
||||
},
|
||||
"memory": {
|
||||
"description": "Memory (RAM) available to each replica",
|
||||
"description": "Memory",
|
||||
"pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
|
||||
"anyOf": [
|
||||
{
|
||||
|
||||
@@ -5,8 +5,8 @@ replicas: 2
|
||||
## @param shards {int} Number of Clickhouse shards
|
||||
shards: 1
|
||||
## @param resources {*resources} Explicit CPU and memory configuration for each Clickhouse replica. When left empty, the preset defined in `resourcesPreset` is applied.
|
||||
## @field resources.cpu {*quantity} CPU available to each replica
|
||||
## @field resources.memory {*quantity} Memory (RAM) available to each replica
|
||||
## @field resources.cpu {*quantity} CPU
|
||||
## @field resources.memory {*quantity} Memory
|
||||
# resources:
|
||||
# cpu: 4000m
|
||||
# memory: 4Gi
|
||||
@@ -56,20 +56,20 @@ users: {}
|
||||
backup:
|
||||
enabled: false
|
||||
s3Region: us-east-1
|
||||
s3Bucket: "s3.example.org/clickhouse-backups"
|
||||
s3Bucket: s3.example.org/clickhouse-backups
|
||||
schedule: "0 2 * * *"
|
||||
cleanupStrategy: "--keep-last=3 --keep-daily=3 --keep-within-weekly=1m"
|
||||
s3AccessKey: "<your-access-key>"
|
||||
s3SecretKey: "<your-secret-key>"
|
||||
resticPassword: "<password>"
|
||||
s3AccessKey: oobaiRus9pah8PhohL1ThaeTa4UVa7gu
|
||||
s3SecretKey: ju3eum4dekeich9ahM1te8waeGai0oog
|
||||
resticPassword: ChaXoveekoh6eigh4siesheeda2quai0
|
||||
|
||||
|
||||
## @section Clickhouse Keeper parameters
|
||||
## @param clickhouseKeeper {*clickhouseKeeper} Clickhouse Keeper configuration
|
||||
## @field clickhouseKeeper.enabled {*bool} Deploy ClickHouse Keeper for cluster coordination
|
||||
## @field clickhouseKeeper.size {*quantity} Persistent Volume Claim size, available for application data
|
||||
## @field clickhouseKeeper.resourcesPreset {string enum:"nano,micro,small,medium,large,xlarge,2xlarge"} Default sizing preset used when `resources` is omitted. Allowed values: `nano`, `micro`, `small`, `medium`, `large`, `xlarge`, `2xlarge`.
|
||||
## @field clickhouseKeeper.replicas {*int} Number of Keeper replicas
|
||||
## @field clickhouseKeeper.resourcesPreset {string enum:"nano,micro,small,medium,large,xlarge,2xlarge"} Default sizing preset used when `resources` is omitted. Allowed values: nano, micro, small, medium, large, xlarge, 2xlarge.
|
||||
## @field clickhouseKeeper.replicas {*int} Number of keeper replicas
|
||||
clickhouseKeeper:
|
||||
enabled: true
|
||||
size: 1Gi
|
||||
|
||||
@@ -16,7 +16,7 @@ type: application
|
||||
# This is the chart version. This version number should be incremented each time you make changes
|
||||
# to the chart and its templates, including the app version.
|
||||
# Versions are expected to follow Semantic Versioning (https://semver.org/)
|
||||
version: 1.1.0
|
||||
version: 1.0.0
|
||||
|
||||
# This is the version number of the application being deployed. This version number should be
|
||||
# incremented each time you make changes to the application. Versions are not expected to
|
||||
|
||||
@@ -12,8 +12,10 @@ Internally, FerretDB service is backed by Postgres.
|
||||
| ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------- | ----------- | ------- |
|
||||
| `replicas` | Number of replicas | `int` | `2` |
|
||||
| `resources` | Explicit CPU and memory configuration for each FerretDB replica. When left empty, the preset defined in `resourcesPreset` is applied. | `*object` | `{}` |
|
||||
| `resources.cpu` | CPU available to each replica | `*quantity` | `null` |
|
||||
| `resources.memory` | Memory (RAM) available to each replica | `*quantity` | `null` |
|
||||
| `resources.cpu` | CPU | `*quantity` | `null` |
|
||||
| `resources.memory` | Memory | `*quantity` | `null` |
|
||||
| `resources.cpu` | CPU | `*quantity` | `null` |
|
||||
| `resources.memory` | Memory | `*quantity` | `null` |
|
||||
| `resourcesPreset` | Default sizing preset used when `resources` is omitted. Allowed values: `nano`, `micro`, `small`, `medium`, `large`, `xlarge`, `2xlarge`. | `string` | `micro` |
|
||||
| `size` | Persistent Volume Claim size, available for application data | `quantity` | `10Gi` |
|
||||
| `storageClass` | StorageClass used to store the data | `string` | `""` |
|
||||
@@ -27,8 +29,11 @@ Internally, FerretDB service is backed by Postgres.
|
||||
| `quorum` | Configuration for the quorum-based synchronous replication | `object` | `{}` |
|
||||
| `quorum.minSyncReplicas` | Minimum number of synchronous replicas that must acknowledge a transaction before it is considered committed | `int` | `0` |
|
||||
| `quorum.maxSyncReplicas` | Maximum number of synchronous replicas that can acknowledge a transaction (must be lower than the total number of replicas) | `int` | `0` |
|
||||
| `quorum.minSyncReplicas` | Minimum number of synchronous replicas that must acknowledge a transaction before it is considered committed | `int` | `0` |
|
||||
| `quorum.maxSyncReplicas` | Maximum number of synchronous replicas that can acknowledge a transaction (must be lower than the total number of replicas) | `int` | `0` |
|
||||
| `users` | Users configuration | `map[string]object` | `{...}` |
|
||||
| `users[name].password` | Password for the user | `*string` | `null` |
|
||||
| `users[name].password` | Password for the user | `*string` | `null` |
|
||||
|
||||
|
||||
### Backup parameters
|
||||
@@ -41,8 +46,15 @@ Internally, FerretDB service is backed by Postgres.
|
||||
| `backup.retentionPolicy` | Retention policy | `string` | `30d` |
|
||||
| `backup.endpointURL` | S3 Endpoint used to upload data to the cloud | `string` | `http://minio-gateway-service:9000` |
|
||||
| `backup.destinationPath` | Path to store the backup (i.e. s3://bucket/path/to/folder) | `string` | `s3://bucket/path/to/folder/` |
|
||||
| `backup.s3AccessKey` | Access key for S3, used for authentication | `string` | `<your-access-key>` |
|
||||
| `backup.s3SecretKey` | Secret key for S3, used for authentication | `string` | `<your-secret-key>` |
|
||||
| `backup.s3AccessKey` | Access key for S3, used for authentication | `string` | `oobaiRus9pah8PhohL1ThaeTa4UVa7gu` |
|
||||
| `backup.s3SecretKey` | Secret key for S3, used for authentication | `string` | `ju3eum4dekeich9ahM1te8waeGai0oog` |
|
||||
| `backup.enabled` | Enable regular backups, default is `false`. | `bool` | `false` |
|
||||
| `backup.schedule` | Cron schedule for automated backups | `string` | `0 2 * * * *` |
|
||||
| `backup.retentionPolicy` | Retention policy | `string` | `30d` |
|
||||
| `backup.endpointURL` | S3 Endpoint used to upload data to the cloud | `string` | `http://minio-gateway-service:9000` |
|
||||
| `backup.destinationPath` | Path to store the backup (i.e. s3://bucket/path/to/folder) | `string` | `s3://bucket/path/to/folder/` |
|
||||
| `backup.s3AccessKey` | Access key for S3, used for authentication | `string` | `oobaiRus9pah8PhohL1ThaeTa4UVa7gu` |
|
||||
| `backup.s3SecretKey` | Secret key for S3, used for authentication | `string` | `ju3eum4dekeich9ahM1te8waeGai0oog` |
|
||||
|
||||
|
||||
### Bootstrap (recovery) parameters
|
||||
@@ -53,6 +65,9 @@ Internally, FerretDB service is backed by Postgres.
|
||||
| `bootstrap.enabled` | Restore database cluster from a backup | `*bool` | `false` |
|
||||
| `bootstrap.recoveryTime` | Timestamp (PITR) up to which recovery will proceed, expressed in RFC 3339 format. If left empty, will restore latest. | `*string` | `""` |
|
||||
| `bootstrap.oldName` | Name of database cluster before deleting | `*string` | `""` |
|
||||
| `bootstrap.enabled` | Restore database cluster from a backup | `*bool` | `false` |
|
||||
| `bootstrap.recoveryTime` | Timestamp (PITR) up to which recovery will proceed, expressed in RFC 3339 format. If left empty, will restore latest. | `*string` | `""` |
|
||||
| `bootstrap.oldName` | Name of database cluster before deleting | `*string` | `""` |
|
||||
|
||||
|
||||
## Parameter examples and reference
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
"enabled": false,
|
||||
"endpointURL": "http://minio-gateway-service:9000",
|
||||
"retentionPolicy": "30d",
|
||||
"s3AccessKey": "\u003cyour-access-key\u003e",
|
||||
"s3SecretKey": "\u003cyour-secret-key\u003e",
|
||||
"s3AccessKey": "oobaiRus9pah8PhohL1ThaeTa4UVa7gu",
|
||||
"s3SecretKey": "ju3eum4dekeich9ahM1te8waeGai0oog",
|
||||
"schedule": "0 2 * * * *"
|
||||
},
|
||||
"required": [
|
||||
@@ -47,12 +47,12 @@
|
||||
"s3AccessKey": {
|
||||
"description": "Access key for S3, used for authentication",
|
||||
"type": "string",
|
||||
"default": "\u003cyour-access-key\u003e"
|
||||
"default": "oobaiRus9pah8PhohL1ThaeTa4UVa7gu"
|
||||
},
|
||||
"s3SecretKey": {
|
||||
"description": "Secret key for S3, used for authentication",
|
||||
"type": "string",
|
||||
"default": "\u003cyour-secret-key\u003e"
|
||||
"default": "ju3eum4dekeich9ahM1te8waeGai0oog"
|
||||
},
|
||||
"schedule": {
|
||||
"description": "Cron schedule for automated backups",
|
||||
@@ -125,7 +125,7 @@
|
||||
"default": {},
|
||||
"properties": {
|
||||
"cpu": {
|
||||
"description": "CPU available to each replica",
|
||||
"description": "CPU",
|
||||
"pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
|
||||
"anyOf": [
|
||||
{
|
||||
@@ -138,7 +138,7 @@
|
||||
"x-kubernetes-int-or-string": true
|
||||
},
|
||||
"memory": {
|
||||
"description": "Memory (RAM) available to each replica",
|
||||
"description": "Memory",
|
||||
"pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
|
||||
"anyOf": [
|
||||
{
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
## @param replicas {int} Number of replicas
|
||||
replicas: 2
|
||||
## @param resources {*resources} Explicit CPU and memory configuration for each FerretDB replica. When left empty, the preset defined in `resourcesPreset` is applied.
|
||||
## @field resources.cpu {*quantity} CPU available to each replica
|
||||
## @field resources.memory {*quantity} Memory (RAM) available to each replica
|
||||
## @field resources.cpu {*quantity} CPU
|
||||
## @field resources.memory {*quantity} Memory
|
||||
# resources:
|
||||
# cpu: 4000m
|
||||
# memory: 4Gi
|
||||
@@ -58,8 +58,8 @@ backup:
|
||||
retentionPolicy: 30d
|
||||
endpointURL: http://minio-gateway-service:9000
|
||||
destinationPath: s3://bucket/path/to/folder/
|
||||
s3AccessKey: "<your-access-key>"
|
||||
s3SecretKey: "<your-secret-key>"
|
||||
s3AccessKey: oobaiRus9pah8PhohL1ThaeTa4UVa7gu
|
||||
s3SecretKey: ju3eum4dekeich9ahM1te8waeGai0oog
|
||||
|
||||
|
||||
## @section Bootstrap (recovery) parameters
|
||||
|
||||
@@ -16,7 +16,7 @@ type: application
|
||||
# This is the chart version. This version number should be incremented each time you make changes
|
||||
# to the chart and its templates, including the app version.
|
||||
# Versions are expected to follow Semantic Versioning (https://semver.org/)
|
||||
version: 0.7.0
|
||||
version: 0.6.1
|
||||
|
||||
# This is the version number of the application being deployed. This version number should be
|
||||
# incremented each time you make changes to the application. Versions are not expected to
|
||||
|
||||
@@ -7,11 +7,16 @@ image: image-nginx
|
||||
|
||||
image-nginx:
|
||||
docker buildx build images/nginx-cache \
|
||||
--provenance false \
|
||||
--builder=$(BUILDER) \
|
||||
--platform=$(PLATFORM) \
|
||||
--tag $(REGISTRY)/nginx-cache:$(call settag,$(NGINX_CACHE_TAG)) \
|
||||
--cache-from type=registry,ref=$(REGISTRY)/nginx-cache:latest \
|
||||
--cache-to type=inline \
|
||||
--metadata-file images/nginx-cache.json \
|
||||
$(BUILDX_ARGS)
|
||||
--push=$(PUSH) \
|
||||
--label "org.opencontainers.image.source=https://github.com/cozystack/cozystack" \
|
||||
--load=$(LOAD)
|
||||
echo "$(REGISTRY)/nginx-cache:$(call settag,$(NGINX_CACHE_TAG))@$$(yq e '."containerimage.digest"' images/nginx-cache.json -o json -r)" \
|
||||
> images/nginx-cache.tag
|
||||
rm -f images/nginx-cache.json
|
||||
|
||||
@@ -81,8 +81,17 @@ The deployment architecture is illustrated in the diagram below:
|
||||
| `haproxy` | HAProxy configuration | `object` | `{}` |
|
||||
| `haproxy.replicas` | Number of HAProxy replicas | `int` | `2` |
|
||||
| `haproxy.resources` | Explicit CPU and memory configuration for each replica. When left empty, the preset defined in `resourcesPreset` is applied. | `object` | `{}` |
|
||||
| `haproxy.resources.cpu` | CPU available to each replica | `*quantity` | `null` |
|
||||
| `haproxy.resources.memory` | Memory (RAM) available to each replica | `*quantity` | `null` |
|
||||
| `haproxy.resources.cpu` | CPU | `*quantity` | `null` |
|
||||
| `haproxy.resources.memory` | Memory | `*quantity` | `null` |
|
||||
| `haproxy.resources.cpu` | CPU | `*quantity` | `null` |
|
||||
| `haproxy.resources.memory` | Memory | `*quantity` | `null` |
|
||||
| `haproxy.resourcesPreset` | Default sizing preset used when `resources` is omitted. Allowed values: `nano`, `micro`, `small`, `medium`, `large`, `xlarge`, `2xlarge`. | `string` | `nano` |
|
||||
| `haproxy.replicas` | Number of HAProxy replicas | `int` | `2` |
|
||||
| `haproxy.resources` | Explicit CPU and memory configuration for each replica. When left empty, the preset defined in `resourcesPreset` is applied. | `object` | `{}` |
|
||||
| `haproxy.resources.cpu` | CPU | `*quantity` | `null` |
|
||||
| `haproxy.resources.memory` | Memory | `*quantity` | `null` |
|
||||
| `haproxy.resources.cpu` | CPU | `*quantity` | `null` |
|
||||
| `haproxy.resources.memory` | Memory | `*quantity` | `null` |
|
||||
| `haproxy.resourcesPreset` | Default sizing preset used when `resources` is omitted. Allowed values: `nano`, `micro`, `small`, `medium`, `large`, `xlarge`, `2xlarge`. | `string` | `nano` |
|
||||
|
||||
|
||||
@@ -93,8 +102,17 @@ The deployment architecture is illustrated in the diagram below:
|
||||
| `nginx` | Nginx configuration | `object` | `{}` |
|
||||
| `nginx.replicas` | Number of Nginx replicas | `int` | `2` |
|
||||
| `nginx.resources` | Explicit CPU and memory configuration for each replica. When left empty, the preset defined in `resourcesPreset` is applied. | `*object` | `null` |
|
||||
| `nginx.resources.cpu` | CPU available to each replica | `*quantity` | `null` |
|
||||
| `nginx.resources.memory` | Memory (RAM) available to each replica | `*quantity` | `null` |
|
||||
| `nginx.resources.cpu` | CPU | `*quantity` | `null` |
|
||||
| `nginx.resources.memory` | Memory | `*quantity` | `null` |
|
||||
| `nginx.resources.cpu` | CPU | `*quantity` | `null` |
|
||||
| `nginx.resources.memory` | Memory | `*quantity` | `null` |
|
||||
| `nginx.resourcesPreset` | Default sizing preset used when `resources` is omitted. Allowed values: `nano`, `micro`, `small`, `medium`, `large`, `xlarge`, `2xlarge`. | `string` | `nano` |
|
||||
| `nginx.replicas` | Number of Nginx replicas | `int` | `2` |
|
||||
| `nginx.resources` | Explicit CPU and memory configuration for each replica. When left empty, the preset defined in `resourcesPreset` is applied. | `*object` | `null` |
|
||||
| `nginx.resources.cpu` | CPU | `*quantity` | `null` |
|
||||
| `nginx.resources.memory` | Memory | `*quantity` | `null` |
|
||||
| `nginx.resources.cpu` | CPU | `*quantity` | `null` |
|
||||
| `nginx.resources.memory` | Memory | `*quantity` | `null` |
|
||||
| `nginx.resourcesPreset` | Default sizing preset used when `resources` is omitted. Allowed values: `nano`, `micro`, `small`, `medium`, `large`, `xlarge`, `2xlarge`. | `string` | `nano` |
|
||||
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
ghcr.io/cozystack/cozystack/nginx-cache:0.7.0@sha256:e0a07082bb6fc6aeaae2315f335386f1705a646c72f9e0af512aebbca5cb2b15
|
||||
ghcr.io/cozystack/cozystack/nginx-cache:0.6.1@sha256:b7633717cd7449c0042ae92d8ca9b36e4d69566561f5c7d44e21058e7d05c6d5
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
"default": {},
|
||||
"properties": {
|
||||
"cpu": {
|
||||
"description": "CPU available to each replica",
|
||||
"description": "CPU",
|
||||
"pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
|
||||
"anyOf": [
|
||||
{
|
||||
@@ -53,7 +53,7 @@
|
||||
"x-kubernetes-int-or-string": true
|
||||
},
|
||||
"memory": {
|
||||
"description": "Memory (RAM) available to each replica",
|
||||
"description": "Memory",
|
||||
"pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
|
||||
"anyOf": [
|
||||
{
|
||||
@@ -107,7 +107,7 @@
|
||||
"default": {},
|
||||
"properties": {
|
||||
"cpu": {
|
||||
"description": "CPU available to each replica",
|
||||
"description": "CPU",
|
||||
"pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
|
||||
"anyOf": [
|
||||
{
|
||||
@@ -120,7 +120,7 @@
|
||||
"x-kubernetes-int-or-string": true
|
||||
},
|
||||
"memory": {
|
||||
"description": "Memory (RAM) available to each replica",
|
||||
"description": "Memory",
|
||||
"pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
|
||||
"anyOf": [
|
||||
{
|
||||
|
||||
@@ -28,8 +28,8 @@ haproxy:
|
||||
## @field haproxy.replicas {int} Number of HAProxy replicas
|
||||
replicas: 2
|
||||
## @field haproxy.resources {resources} Explicit CPU and memory configuration for each replica. When left empty, the preset defined in `resourcesPreset` is applied.
|
||||
## @field resources.cpu {*quantity} CPU available to each replica
|
||||
## @field resources.memory {*quantity} Memory (RAM) available to each replica
|
||||
## @field resources.cpu {*quantity} CPU
|
||||
## @field resources.memory {*quantity} Memory
|
||||
resources: {}
|
||||
# resources:
|
||||
# cpu: 4000m
|
||||
|
||||
@@ -18,6 +18,10 @@
|
||||
| `topics[i].partitions` | Number of partitions | `int` | `0` |
|
||||
| `topics[i].replicas` | Number of replicas | `int` | `0` |
|
||||
| `topics[i].config` | Topic configuration | `object` | `{}` |
|
||||
| `topics[i].name` | Topic name | `string` | `""` |
|
||||
| `topics[i].partitions` | Number of partitions | `int` | `0` |
|
||||
| `topics[i].replicas` | Number of replicas | `int` | `0` |
|
||||
| `topics[i].config` | Topic configuration | `object` | `{}` |
|
||||
|
||||
|
||||
### Kafka configuration
|
||||
@@ -27,8 +31,19 @@
|
||||
| `kafka` | Kafka configuration | `object` | `{}` |
|
||||
| `kafka.replicas` | Number of Kafka replicas | `int` | `3` |
|
||||
| `kafka.resources` | Explicit CPU and memory configuration for each replica. When left empty, the preset defined in `resourcesPreset` is applied. | `*object` | `null` |
|
||||
| `kafka.resources.cpu` | CPU available to each replica | `*quantity` | `null` |
|
||||
| `kafka.resources.memory` | Memory (RAM) available to each replica | `*quantity` | `null` |
|
||||
| `kafka.resources.cpu` | CPU | `*quantity` | `null` |
|
||||
| `kafka.resources.memory` | Memory | `*quantity` | `null` |
|
||||
| `kafka.resources.cpu` | CPU | `*quantity` | `null` |
|
||||
| `kafka.resources.memory` | Memory | `*quantity` | `null` |
|
||||
| `kafka.resourcesPreset` | Default sizing preset used when `resources` is omitted. Allowed values: `nano`, `micro`, `small`, `medium`, `large`, `xlarge`, `2xlarge`. | `string` | `small` |
|
||||
| `kafka.size` | Persistent Volume size for Kafka | `quantity` | `10Gi` |
|
||||
| `kafka.storageClass` | StorageClass used to store the Kafka data | `string` | `""` |
|
||||
| `kafka.replicas` | Number of Kafka replicas | `int` | `3` |
|
||||
| `kafka.resources` | Explicit CPU and memory configuration for each replica. When left empty, the preset defined in `resourcesPreset` is applied. | `*object` | `null` |
|
||||
| `kafka.resources.cpu` | CPU | `*quantity` | `null` |
|
||||
| `kafka.resources.memory` | Memory | `*quantity` | `null` |
|
||||
| `kafka.resources.cpu` | CPU | `*quantity` | `null` |
|
||||
| `kafka.resources.memory` | Memory | `*quantity` | `null` |
|
||||
| `kafka.resourcesPreset` | Default sizing preset used when `resources` is omitted. Allowed values: `nano`, `micro`, `small`, `medium`, `large`, `xlarge`, `2xlarge`. | `string` | `small` |
|
||||
| `kafka.size` | Persistent Volume size for Kafka | `quantity` | `10Gi` |
|
||||
| `kafka.storageClass` | StorageClass used to store the Kafka data | `string` | `""` |
|
||||
@@ -41,8 +56,19 @@
|
||||
| `zookeeper` | Zookeeper configuration | `object` | `{}` |
|
||||
| `zookeeper.replicas` | Number of ZooKeeper replicas | `int` | `3` |
|
||||
| `zookeeper.resources` | Explicit CPU and memory configuration for each replica. When left empty, the preset defined in `resourcesPreset` is applied. | `*object` | `null` |
|
||||
| `zookeeper.resources.cpu` | CPU available to each replica | `*quantity` | `null` |
|
||||
| `zookeeper.resources.memory` | Memory (RAM) available to each replica | `*quantity` | `null` |
|
||||
| `zookeeper.resources.cpu` | CPU | `*quantity` | `null` |
|
||||
| `zookeeper.resources.memory` | Memory | `*quantity` | `null` |
|
||||
| `zookeeper.resources.cpu` | CPU | `*quantity` | `null` |
|
||||
| `zookeeper.resources.memory` | Memory | `*quantity` | `null` |
|
||||
| `zookeeper.resourcesPreset` | Default sizing preset used when `resources` is omitted. Allowed values: `nano`, `micro`, `small`, `medium`, `large`, `xlarge`, `2xlarge`. | `string` | `small` |
|
||||
| `zookeeper.size` | Persistent Volume size for ZooKeeper | `quantity` | `5Gi` |
|
||||
| `zookeeper.storageClass` | StorageClass used to store the ZooKeeper data | `string` | `""` |
|
||||
| `zookeeper.replicas` | Number of ZooKeeper replicas | `int` | `3` |
|
||||
| `zookeeper.resources` | Explicit CPU and memory configuration for each replica. When left empty, the preset defined in `resourcesPreset` is applied. | `*object` | `null` |
|
||||
| `zookeeper.resources.cpu` | CPU | `*quantity` | `null` |
|
||||
| `zookeeper.resources.memory` | Memory | `*quantity` | `null` |
|
||||
| `zookeeper.resources.cpu` | CPU | `*quantity` | `null` |
|
||||
| `zookeeper.resources.memory` | Memory | `*quantity` | `null` |
|
||||
| `zookeeper.resourcesPreset` | Default sizing preset used when `resources` is omitted. Allowed values: `nano`, `micro`, `small`, `medium`, `large`, `xlarge`, `2xlarge`. | `string` | `small` |
|
||||
| `zookeeper.size` | Persistent Volume size for ZooKeeper | `quantity` | `5Gi` |
|
||||
| `zookeeper.storageClass` | StorageClass used to store the ZooKeeper data | `string` | `""` |
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
"default": {},
|
||||
"properties": {
|
||||
"cpu": {
|
||||
"description": "CPU available to each replica",
|
||||
"description": "CPU",
|
||||
"pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
|
||||
"anyOf": [
|
||||
{
|
||||
@@ -48,7 +48,7 @@
|
||||
"x-kubernetes-int-or-string": true
|
||||
},
|
||||
"memory": {
|
||||
"description": "Memory (RAM) available to each replica",
|
||||
"description": "Memory",
|
||||
"pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
|
||||
"anyOf": [
|
||||
{
|
||||
@@ -157,7 +157,7 @@
|
||||
"default": {},
|
||||
"properties": {
|
||||
"cpu": {
|
||||
"description": "CPU available to each replica",
|
||||
"description": "CPU",
|
||||
"pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
|
||||
"anyOf": [
|
||||
{
|
||||
@@ -170,7 +170,7 @@
|
||||
"x-kubernetes-int-or-string": true
|
||||
},
|
||||
"memory": {
|
||||
"description": "Memory (RAM) available to each replica",
|
||||
"description": "Memory",
|
||||
"pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
|
||||
"anyOf": [
|
||||
{
|
||||
|
||||
@@ -37,8 +37,8 @@ kafka:
|
||||
## @field kafka.replicas {int} Number of Kafka replicas
|
||||
replicas: 3
|
||||
## @field kafka.resources {*resources} Explicit CPU and memory configuration for each replica. When left empty, the preset defined in `resourcesPreset` is applied.
|
||||
## @field resources.cpu {*quantity} CPU available to each replica
|
||||
## @field resources.memory {*quantity} Memory (RAM) available to each replica
|
||||
## @field resources.cpu {*quantity} CPU
|
||||
## @field resources.memory {*quantity} Memory
|
||||
# resources:
|
||||
# cpu: 4000m
|
||||
# memory: 4Gi
|
||||
|
||||
@@ -16,7 +16,7 @@ type: application
|
||||
# This is the chart version. This version number should be incremented each time you make changes
|
||||
# to the chart and its templates, including the app version.
|
||||
# Versions are expected to follow Semantic Versioning (https://semver.org/)
|
||||
version: 0.29.0
|
||||
version: 0.26.3
|
||||
|
||||
# This is the version number of the application being deployed. This version number should be
|
||||
# incremented each time you make changes to the application. Versions are not expected to
|
||||
|
||||
@@ -12,37 +12,52 @@ image: image-ubuntu-container-disk image-kubevirt-cloud-provider image-kubevirt-
|
||||
|
||||
image-ubuntu-container-disk:
|
||||
docker buildx build images/ubuntu-container-disk \
|
||||
--provenance false \
|
||||
--builder=$(BUILDER) \
|
||||
--platform=$(PLATFORM) \
|
||||
--build-arg KUBERNETES_VERSION=${KUBERNETES_VERSION} \
|
||||
--tag $(REGISTRY)/ubuntu-container-disk:$(call settag,$(KUBERNETES_VERSION)) \
|
||||
--tag $(REGISTRY)/ubuntu-container-disk:$(call settag,$(KUBERNETES_VERSION)-$(TAG)) \
|
||||
--cache-from type=registry,ref=$(REGISTRY)/ubuntu-container-disk:latest \
|
||||
--cache-to type=inline \
|
||||
--metadata-file images/ubuntu-container-disk.json \
|
||||
$(BUILDX_ARGS)
|
||||
--push=$(PUSH) \
|
||||
--label "org.opencontainers.image.source=https://github.com/cozystack/cozystack" \
|
||||
--load=$(LOAD)
|
||||
echo "$(REGISTRY)/ubuntu-container-disk:$(call settag,$(KUBERNETES_VERSION))@$$(yq e '."containerimage.digest"' images/ubuntu-container-disk.json -o json -r)" \
|
||||
> images/ubuntu-container-disk.tag
|
||||
rm -f images/ubuntu-container-disk.json
|
||||
|
||||
image-kubevirt-cloud-provider:
|
||||
docker buildx build images/kubevirt-cloud-provider \
|
||||
--provenance false \
|
||||
--builder=$(BUILDER) \
|
||||
--platform=$(PLATFORM) \
|
||||
--tag $(REGISTRY)/kubevirt-cloud-provider:$(call settag,$(KUBERNETES_PKG_TAG)) \
|
||||
--tag $(REGISTRY)/kubevirt-cloud-provider:$(call settag,$(KUBERNETES_PKG_TAG)-$(TAG)) \
|
||||
--cache-from type=registry,ref=$(REGISTRY)/kubevirt-cloud-provider:latest \
|
||||
--cache-to type=inline \
|
||||
--metadata-file images/kubevirt-cloud-provider.json \
|
||||
$(BUILDX_ARGS)
|
||||
--push=$(PUSH) \
|
||||
--label "org.opencontainers.image.source=https://github.com/cozystack/cozystack" \
|
||||
--load=$(LOAD)
|
||||
echo "$(REGISTRY)/kubevirt-cloud-provider:$(call settag,$(KUBERNETES_PKG_TAG))@$$(yq e '."containerimage.digest"' images/kubevirt-cloud-provider.json -o json -r)" \
|
||||
> images/kubevirt-cloud-provider.tag
|
||||
rm -f images/kubevirt-cloud-provider.json
|
||||
|
||||
image-kubevirt-csi-driver:
|
||||
docker buildx build images/kubevirt-csi-driver \
|
||||
--provenance false \
|
||||
--builder=$(BUILDER) \
|
||||
--platform=$(PLATFORM) \
|
||||
--tag $(REGISTRY)/kubevirt-csi-driver:$(call settag,$(KUBERNETES_PKG_TAG)) \
|
||||
--tag $(REGISTRY)/kubevirt-csi-driver:$(call settag,$(KUBERNETES_PKG_TAG)-$(TAG)) \
|
||||
--cache-from type=registry,ref=$(REGISTRY)/kubevirt-csi-driver:latest \
|
||||
--cache-to type=inline \
|
||||
--metadata-file images/kubevirt-csi-driver.json \
|
||||
$(BUILDX_ARGS)
|
||||
--push=$(PUSH) \
|
||||
--label "org.opencontainers.image.source=https://github.com/cozystack/cozystack" \
|
||||
--load=$(LOAD)
|
||||
echo "$(REGISTRY)/kubevirt-csi-driver:$(call settag,$(KUBERNETES_PKG_TAG))@$$(yq e '."containerimage.digest"' images/kubevirt-csi-driver.json -o json -r)" \
|
||||
> images/kubevirt-csi-driver.tag
|
||||
IMAGE=$$(cat images/kubevirt-csi-driver.tag) \
|
||||
@@ -52,12 +67,17 @@ image-kubevirt-csi-driver:
|
||||
|
||||
image-cluster-autoscaler:
|
||||
docker buildx build images/cluster-autoscaler \
|
||||
--provenance false \
|
||||
--builder=$(BUILDER) \
|
||||
--platform=$(PLATFORM) \
|
||||
--tag $(REGISTRY)/cluster-autoscaler:$(call settag,$(KUBERNETES_PKG_TAG)) \
|
||||
--tag $(REGISTRY)/cluster-autoscaler:$(call settag,$(KUBERNETES_PKG_TAG)-$(TAG)) \
|
||||
--cache-from type=registry,ref=$(REGISTRY)/cluster-autoscaler:latest \
|
||||
--cache-to type=inline \
|
||||
--metadata-file images/cluster-autoscaler.json \
|
||||
$(BUILDX_ARGS)
|
||||
--push=$(PUSH) \
|
||||
--label "org.opencontainers.image.source=https://github.com/cozystack/cozystack" \
|
||||
--load=$(LOAD)
|
||||
echo "$(REGISTRY)/cluster-autoscaler:$(call settag,$(KUBERNETES_PKG_TAG))@$$(yq e '."containerimage.digest"' images/cluster-autoscaler.json -o json -r)" \
|
||||
> images/cluster-autoscaler.tag
|
||||
rm -f images/cluster-autoscaler.json
|
||||
|
||||
@@ -93,7 +93,7 @@ See the reference for components utilized in this service:
|
||||
|
||||
| Name | Description | Type | Value |
|
||||
| ----------------------------------- | ----------------------------------------------------------------------------------------------------------------- | ------------------- | ------- |
|
||||
| `version` | Kubernetes version given as vMAJOR.MINOR. Available are versions from 1.28 to 1.33. | `string` | `v1.33` |
|
||||
| `version` | Kubernetes version given as vMAJOR.MINOR. Available are versions from 1.28 to 1.33. | `string` | `v1.32` |
|
||||
| `host` | Hostname used to access the Kubernetes cluster externally. Defaults to `<cluster-name>.<tenant-host>` when empty. | `string` | `""` |
|
||||
| `nodeGroups` | Worker nodes configuration | `map[string]object` | `{...}` |
|
||||
| `nodeGroups[name].minReplicas` | Minimum amount of replicas | `int` | `0` |
|
||||
@@ -101,11 +101,27 @@ See the reference for components utilized in this service:
|
||||
| `nodeGroups[name].instanceType` | Virtual machine instance type | `string` | `""` |
|
||||
| `nodeGroups[name].ephemeralStorage` | Ephemeral storage size | `quantity` | `""` |
|
||||
| `nodeGroups[name].roles` | List of node's roles | `[]string` | `[]` |
|
||||
| `nodeGroups[name].resources` | Resources available to each worker node | `object` | `{}` |
|
||||
| `nodeGroups[name].resources.cpu` | CPU available to each worker node | `*quantity` | `null` |
|
||||
| `nodeGroups[name].resources.memory` | Memory (RAM) available to each worker node | `*quantity` | `null` |
|
||||
| `nodeGroups[name].resources` | Available resources for each worker node | `object` | `{}` |
|
||||
| `nodeGroups[name].resources.cpu` | Available CPU | `*quantity` | `null` |
|
||||
| `nodeGroups[name].resources.memory` | Available memory (RAM) | `*quantity` | `null` |
|
||||
| `nodeGroups[name].resources.cpu` | Available CPU | `*quantity` | `null` |
|
||||
| `nodeGroups[name].resources.memory` | Available memory (RAM) | `*quantity` | `null` |
|
||||
| `nodeGroups[name].gpus` | List of GPUs to attach (WARN: NVIDIA driver requires at least 4 GiB of RAM) | `[]object` | `[]` |
|
||||
| `nodeGroups[name].gpus.name` | Name of GPU, such as "nvidia.com/AD102GL_L40S" | `string` | `""` |
|
||||
| `nodeGroups[name].gpus.name` | Name of GPU, such as "nvidia.com/AD102GL_L40S" | `string` | `""` |
|
||||
| `nodeGroups[name].minReplicas` | Minimum amount of replicas | `int` | `0` |
|
||||
| `nodeGroups[name].maxReplicas` | Maximum amount of replicas | `int` | `0` |
|
||||
| `nodeGroups[name].instanceType` | Virtual machine instance type | `string` | `""` |
|
||||
| `nodeGroups[name].ephemeralStorage` | Ephemeral storage size | `quantity` | `""` |
|
||||
| `nodeGroups[name].roles` | List of node's roles | `[]string` | `[]` |
|
||||
| `nodeGroups[name].resources` | Available resources for each worker node | `object` | `{}` |
|
||||
| `nodeGroups[name].resources.cpu` | Available CPU | `*quantity` | `null` |
|
||||
| `nodeGroups[name].resources.memory` | Available memory (RAM) | `*quantity` | `null` |
|
||||
| `nodeGroups[name].resources.cpu` | Available CPU | `*quantity` | `null` |
|
||||
| `nodeGroups[name].resources.memory` | Available memory (RAM) | `*quantity` | `null` |
|
||||
| `nodeGroups[name].gpus` | List of GPUs to attach (WARN: NVIDIA driver requires at least 4 GiB of RAM) | `[]object` | `[]` |
|
||||
| `nodeGroups[name].gpus.name` | Name of GPU, such as "nvidia.com/AD102GL_L40S" | `string` | `""` |
|
||||
| `nodeGroups[name].gpus.name` | Name of GPU, such as "nvidia.com/AD102GL_L40S" | `string` | `""` |
|
||||
|
||||
|
||||
### Cluster Addons
|
||||
@@ -116,60 +132,230 @@ See the reference for components utilized in this service:
|
||||
| `addons.certManager` | Cert-manager: automatically creates and manages SSL/TLS certificate | `object` | `{}` |
|
||||
| `addons.certManager.enabled` | Enable cert-manager, which automatically creates and manages SSL/TLS certificates. | `bool` | `false` |
|
||||
| `addons.certManager.valuesOverride` | Custom values to override | `object` | `{}` |
|
||||
| `addons.certManager.enabled` | Enable cert-manager, which automatically creates and manages SSL/TLS certificates. | `bool` | `false` |
|
||||
| `addons.certManager.valuesOverride` | Custom values to override | `object` | `{}` |
|
||||
| `addons.cilium` | Cilium CNI plugin | `object` | `{}` |
|
||||
| `addons.cilium.valuesOverride` | Custom values to override | `object` | `{}` |
|
||||
| `addons.cilium.valuesOverride` | Custom values to override | `object` | `{}` |
|
||||
| `addons.gatewayAPI` | Gateway API | `object` | `{}` |
|
||||
| `addons.gatewayAPI.enabled` | Enable the Gateway API | `bool` | `false` |
|
||||
| `addons.gatewayAPI.enabled` | Enable the Gateway API | `bool` | `false` |
|
||||
| `addons.ingressNginx` | Ingress-NGINX Controller | `object` | `{}` |
|
||||
| `addons.ingressNginx.enabled` | Enable the Ingress-NGINX controller (requires nodes labeled with the 'ingress-nginx' role). | `bool` | `false` |
|
||||
| `addons.ingressNginx.exposeMethod` | Method to expose the Ingress-NGINX controller. Allowed values: `Proxied`, `LoadBalancer`. | `string` | `Proxied` |
|
||||
| `addons.ingressNginx.hosts` | List of domain names that the parent cluster should route to this tenant cluster. Taken into account only when `exposeMethod` is set to `Proxied`. | `[]string` | `[]` |
|
||||
| `addons.ingressNginx.valuesOverride` | Custom values to override | `object` | `{}` |
|
||||
| `addons.ingressNginx.enabled` | Enable the Ingress-NGINX controller (requires nodes labeled with the 'ingress-nginx' role). | `bool` | `false` |
|
||||
| `addons.ingressNginx.exposeMethod` | Method to expose the Ingress-NGINX controller. Allowed values: `Proxied`, `LoadBalancer`. | `string` | `Proxied` |
|
||||
| `addons.ingressNginx.hosts` | List of domain names that the parent cluster should route to this tenant cluster. Taken into account only when `exposeMethod` is set to `Proxied`. | `[]string` | `[]` |
|
||||
| `addons.ingressNginx.valuesOverride` | Custom values to override | `object` | `{}` |
|
||||
| `addons.gpuOperator` | GPU-operator: NVIDIA GPU Operator | `object` | `{}` |
|
||||
| `addons.gpuOperator.enabled` | Enable the GPU-operator | `bool` | `false` |
|
||||
| `addons.gpuOperator.valuesOverride` | Custom values to override | `object` | `{}` |
|
||||
| `addons.gpuOperator.enabled` | Enable the GPU-operator | `bool` | `false` |
|
||||
| `addons.gpuOperator.valuesOverride` | Custom values to override | `object` | `{}` |
|
||||
| `addons.fluxcd` | Flux CD | `object` | `{}` |
|
||||
| `addons.fluxcd.enabled` | Enable FluxCD | `bool` | `false` |
|
||||
| `addons.fluxcd.valuesOverride` | Custom values to override | `object` | `{}` |
|
||||
| `addons.fluxcd.enabled` | Enable FluxCD | `bool` | `false` |
|
||||
| `addons.fluxcd.valuesOverride` | Custom values to override | `object` | `{}` |
|
||||
| `addons.monitoringAgents` | MonitoringAgents | `object` | `{}` |
|
||||
| `addons.monitoringAgents.enabled` | Enable monitoring agents (Fluent Bit and VMAgents) to send logs and metrics. If tenant monitoring is enabled, data is sent to tenant storage; otherwise, it goes to root storage. | `bool` | `false` |
|
||||
| `addons.monitoringAgents.valuesOverride` | Custom values to override | `object` | `{}` |
|
||||
| `addons.monitoringAgents.enabled` | Enable monitoring agents (Fluent Bit and VMAgents) to send logs and metrics. If tenant monitoring is enabled, data is sent to tenant storage; otherwise, it goes to root storage. | `bool` | `false` |
|
||||
| `addons.monitoringAgents.valuesOverride` | Custom values to override | `object` | `{}` |
|
||||
| `addons.verticalPodAutoscaler` | VerticalPodAutoscaler | `object` | `{}` |
|
||||
| `addons.verticalPodAutoscaler.valuesOverride` | Custom values to override | `object` | `{}` |
|
||||
| `addons.verticalPodAutoscaler.valuesOverride` | Custom values to override | `object` | `{}` |
|
||||
| `addons.velero` | Velero | `object` | `{}` |
|
||||
| `addons.velero.enabled` | Enable Velero for backup and recovery of a tenant Kubernetes cluster. | `bool` | `false` |
|
||||
| `addons.velero.valuesOverride` | Custom values to override | `object` | `{}` |
|
||||
| `addons.coredns` | Coredns | `object` | `{}` |
|
||||
| `addons.coredns.valuesOverride` | Custom values to override | `object` | `{}` |
|
||||
| `addons.velero.enabled` | Enable Velero for backup and recovery of a tenant Kubernetes cluster. | `bool` | `false` |
|
||||
| `addons.velero.valuesOverride` | Custom values to override | `object` | `{}` |
|
||||
| `addons.certManager` | Cert-manager: automatically creates and manages SSL/TLS certificate | `object` | `{}` |
|
||||
| `addons.certManager.enabled` | Enable cert-manager, which automatically creates and manages SSL/TLS certificates. | `bool` | `false` |
|
||||
| `addons.certManager.valuesOverride` | Custom values to override | `object` | `{}` |
|
||||
| `addons.certManager.enabled` | Enable cert-manager, which automatically creates and manages SSL/TLS certificates. | `bool` | `false` |
|
||||
| `addons.certManager.valuesOverride` | Custom values to override | `object` | `{}` |
|
||||
| `addons.cilium` | Cilium CNI plugin | `object` | `{}` |
|
||||
| `addons.cilium.valuesOverride` | Custom values to override | `object` | `{}` |
|
||||
| `addons.cilium.valuesOverride` | Custom values to override | `object` | `{}` |
|
||||
| `addons.gatewayAPI` | Gateway API | `object` | `{}` |
|
||||
| `addons.gatewayAPI.enabled` | Enable the Gateway API | `bool` | `false` |
|
||||
| `addons.gatewayAPI.enabled` | Enable the Gateway API | `bool` | `false` |
|
||||
| `addons.ingressNginx` | Ingress-NGINX Controller | `object` | `{}` |
|
||||
| `addons.ingressNginx.enabled` | Enable the Ingress-NGINX controller (requires nodes labeled with the 'ingress-nginx' role). | `bool` | `false` |
|
||||
| `addons.ingressNginx.exposeMethod` | Method to expose the Ingress-NGINX controller. Allowed values: `Proxied`, `LoadBalancer`. | `string` | `Proxied` |
|
||||
| `addons.ingressNginx.hosts` | List of domain names that the parent cluster should route to this tenant cluster. Taken into account only when `exposeMethod` is set to `Proxied`. | `[]string` | `[]` |
|
||||
| `addons.ingressNginx.valuesOverride` | Custom values to override | `object` | `{}` |
|
||||
| `addons.ingressNginx.enabled` | Enable the Ingress-NGINX controller (requires nodes labeled with the 'ingress-nginx' role). | `bool` | `false` |
|
||||
| `addons.ingressNginx.exposeMethod` | Method to expose the Ingress-NGINX controller. Allowed values: `Proxied`, `LoadBalancer`. | `string` | `Proxied` |
|
||||
| `addons.ingressNginx.hosts` | List of domain names that the parent cluster should route to this tenant cluster. Taken into account only when `exposeMethod` is set to `Proxied`. | `[]string` | `[]` |
|
||||
| `addons.ingressNginx.valuesOverride` | Custom values to override | `object` | `{}` |
|
||||
| `addons.gpuOperator` | GPU-operator: NVIDIA GPU Operator | `object` | `{}` |
|
||||
| `addons.gpuOperator.enabled` | Enable the GPU-operator | `bool` | `false` |
|
||||
| `addons.gpuOperator.valuesOverride` | Custom values to override | `object` | `{}` |
|
||||
| `addons.gpuOperator.enabled` | Enable the GPU-operator | `bool` | `false` |
|
||||
| `addons.gpuOperator.valuesOverride` | Custom values to override | `object` | `{}` |
|
||||
| `addons.fluxcd` | Flux CD | `object` | `{}` |
|
||||
| `addons.fluxcd.enabled` | Enable FluxCD | `bool` | `false` |
|
||||
| `addons.fluxcd.valuesOverride` | Custom values to override | `object` | `{}` |
|
||||
| `addons.fluxcd.enabled` | Enable FluxCD | `bool` | `false` |
|
||||
| `addons.fluxcd.valuesOverride` | Custom values to override | `object` | `{}` |
|
||||
| `addons.monitoringAgents` | MonitoringAgents | `object` | `{}` |
|
||||
| `addons.monitoringAgents.enabled` | Enable monitoring agents (Fluent Bit and VMAgents) to send logs and metrics. If tenant monitoring is enabled, data is sent to tenant storage; otherwise, it goes to root storage. | `bool` | `false` |
|
||||
| `addons.monitoringAgents.valuesOverride` | Custom values to override | `object` | `{}` |
|
||||
| `addons.monitoringAgents.enabled` | Enable monitoring agents (Fluent Bit and VMAgents) to send logs and metrics. If tenant monitoring is enabled, data is sent to tenant storage; otherwise, it goes to root storage. | `bool` | `false` |
|
||||
| `addons.monitoringAgents.valuesOverride` | Custom values to override | `object` | `{}` |
|
||||
| `addons.verticalPodAutoscaler` | VerticalPodAutoscaler | `object` | `{}` |
|
||||
| `addons.verticalPodAutoscaler.valuesOverride` | Custom values to override | `object` | `{}` |
|
||||
| `addons.verticalPodAutoscaler.valuesOverride` | Custom values to override | `object` | `{}` |
|
||||
| `addons.velero` | Velero | `object` | `{}` |
|
||||
| `addons.velero.enabled` | Enable Velero for backup and recovery of a tenant Kubernetes cluster. | `bool` | `false` |
|
||||
| `addons.velero.valuesOverride` | Custom values to override | `object` | `{}` |
|
||||
| `addons.velero.enabled` | Enable Velero for backup and recovery of a tenant Kubernetes cluster. | `bool` | `false` |
|
||||
| `addons.velero.valuesOverride` | Custom values to override | `object` | `{}` |
|
||||
|
||||
|
||||
### Kubernetes Control Plane Configuration
|
||||
|
||||
| Name | Description | Type | Value |
|
||||
| --------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | ----------- | -------- |
|
||||
| `controlPlane` | Control Plane Configuration | `object` | `{}` |
|
||||
| `controlPlane.replicas` | Number of replicas for Kubernetes control plane components. | `int` | `2` |
|
||||
| `controlPlane.apiServer` | Control plane API server configuration. | `object` | `{}` |
|
||||
| `controlPlane.apiServer.resources` | Explicit CPU and memory configuration for the API Server. When left empty, the preset defined in `resourcesPreset` is applied. | `object` | `{}` |
|
||||
| `controlPlane.apiServer.resources.cpu` | CPU available to each worker node | `*quantity` | `null` |
|
||||
| `controlPlane.apiServer.resources.memory` | Memory (RAM) available to each worker node | `*quantity` | `null` |
|
||||
| `controlPlane.apiServer.resourcesPreset` | Default sizing preset used when `resources` is omitted. Allowed values: `nano`, `micro`, `small`, `medium`, `large`, `xlarge`, `2xlarge`. | `string` | `medium` |
|
||||
| `controlPlane.controllerManager` | Controller Manager configuration. | `object` | `{}` |
|
||||
| `controlPlane.controllerManager.resources` | Explicit CPU and memory configuration for the Controller Manager. When left empty, the preset defined in `resourcesPreset` is applied. | `object` | `{}` |
|
||||
| `controlPlane.controllerManager.resources.cpu` | CPU available to each worker node | `*quantity` | `null` |
|
||||
| `controlPlane.controllerManager.resources.memory` | Memory (RAM) available to each worker node | `*quantity` | `null` |
|
||||
| `controlPlane.controllerManager.resourcesPreset` | Default sizing preset used when `resources` is omitted. Allowed values: `nano`, `micro`, `small`, `medium`, `large`, `xlarge`, `2xlarge`. | `string` | `micro` |
|
||||
| `controlPlane.scheduler` | Scheduler configuration. | `object` | `{}` |
|
||||
| `controlPlane.scheduler.resources` | Explicit CPU and memory configuration for the Scheduler. When left empty, the preset defined in `resourcesPreset` is applied. | `object` | `{}` |
|
||||
| `controlPlane.scheduler.resources.cpu` | CPU available to each worker node | `*quantity` | `null` |
|
||||
| `controlPlane.scheduler.resources.memory` | Memory (RAM) available to each worker node | `*quantity` | `null` |
|
||||
| `controlPlane.scheduler.resourcesPreset` | Default sizing preset used when `resources` is omitted. Allowed values: `nano`, `micro`, `small`, `medium`, `large`, `xlarge`, `2xlarge`. | `string` | `micro` |
|
||||
| `controlPlane.konnectivity` | Konnectivity configuration. | `object` | `{}` |
|
||||
| `controlPlane.konnectivity.server` | Konnectivity server configuration. | `object` | `{}` |
|
||||
| `controlPlane.konnectivity.server.resources` | Explicit CPU and memory configuration for Konnectivity. When left empty, the preset defined in `resourcesPreset` is applied. | `object` | `{}` |
|
||||
| `controlPlane.konnectivity.server.resources.cpu` | CPU available to each worker node | `*quantity` | `null` |
|
||||
| `controlPlane.konnectivity.server.resources.memory` | Memory (RAM) available to each worker node | `*quantity` | `null` |
|
||||
| `controlPlane.konnectivity.server.resourcesPreset` | Default sizing preset used when `resources` is omitted. Allowed values: `nano`, `micro`, `small`, `medium`, `large`, `xlarge`, `2xlarge`. | `string` | `micro` |
|
||||
| Name | Description | Type | Value |
|
||||
| --------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | ----------- | -------- |
|
||||
| `controlPlane` | Control Plane Configuration | `object` | `{}` |
|
||||
| `controlPlane.replicas` | Number of replicas for Kubernetes control plane components. | `int` | `2` |
|
||||
| `controlPlane.apiServer` | Control plane API server configuration. | `object` | `{}` |
|
||||
| `controlPlane.apiServer.resources` | Explicit CPU and memory configuration for the API Server. When left empty, the preset defined in `resourcesPreset` is applied. | `object` | `{}` |
|
||||
| `controlPlane.apiServer.resources.cpu` | Available CPU | `*quantity` | `null` |
|
||||
| `controlPlane.apiServer.resources.memory` | Available memory (RAM) | `*quantity` | `null` |
|
||||
| `controlPlane.apiServer.resources.cpu` | Available CPU | `*quantity` | `null` |
|
||||
| `controlPlane.apiServer.resources.memory` | Available memory (RAM) | `*quantity` | `null` |
|
||||
| `controlPlane.apiServer.resourcesPreset` | Default sizing preset used when `resources` is omitted. Allowed values: nano, micro, small, medium, large, xlarge, 2xlarge. | `string` | `medium` |
|
||||
| `controlPlane.apiServer.resources` | Explicit CPU and memory configuration for the API Server. When left empty, the preset defined in `resourcesPreset` is applied. | `object` | `{}` |
|
||||
| `controlPlane.apiServer.resources.cpu` | Available CPU | `*quantity` | `null` |
|
||||
| `controlPlane.apiServer.resources.memory` | Available memory (RAM) | `*quantity` | `null` |
|
||||
| `controlPlane.apiServer.resources.cpu` | Available CPU | `*quantity` | `null` |
|
||||
| `controlPlane.apiServer.resources.memory` | Available memory (RAM) | `*quantity` | `null` |
|
||||
| `controlPlane.apiServer.resourcesPreset` | Default sizing preset used when `resources` is omitted. Allowed values: nano, micro, small, medium, large, xlarge, 2xlarge. | `string` | `medium` |
|
||||
| `controlPlane.controllerManager` | Controller Manager configuration. | `object` | `{}` |
|
||||
| `controlPlane.controllerManager.resources` | Explicit CPU and memory configuration for the Controller Manager. When left empty, the preset defined in `resourcesPreset` is applied. | `object` | `{}` |
|
||||
| `controlPlane.controllerManager.resources.cpu` | Available CPU | `*quantity` | `null` |
|
||||
| `controlPlane.controllerManager.resources.memory` | Available memory (RAM) | `*quantity` | `null` |
|
||||
| `controlPlane.controllerManager.resources.cpu` | Available CPU | `*quantity` | `null` |
|
||||
| `controlPlane.controllerManager.resources.memory` | Available memory (RAM) | `*quantity` | `null` |
|
||||
| `controlPlane.controllerManager.resourcesPreset` | Default sizing preset used when `resources` is omitted. Allowed values: nano, micro, small, medium, large, xlarge, 2xlarge. | `string` | `micro` |
|
||||
| `controlPlane.controllerManager.resources` | Explicit CPU and memory configuration for the Controller Manager. When left empty, the preset defined in `resourcesPreset` is applied. | `object` | `{}` |
|
||||
| `controlPlane.controllerManager.resources.cpu` | Available CPU | `*quantity` | `null` |
|
||||
| `controlPlane.controllerManager.resources.memory` | Available memory (RAM) | `*quantity` | `null` |
|
||||
| `controlPlane.controllerManager.resources.cpu` | Available CPU | `*quantity` | `null` |
|
||||
| `controlPlane.controllerManager.resources.memory` | Available memory (RAM) | `*quantity` | `null` |
|
||||
| `controlPlane.controllerManager.resourcesPreset` | Default sizing preset used when `resources` is omitted. Allowed values: nano, micro, small, medium, large, xlarge, 2xlarge. | `string` | `micro` |
|
||||
| `controlPlane.scheduler` | Scheduler configuration. | `object` | `{}` |
|
||||
| `controlPlane.scheduler.resources` | Explicit CPU and memory configuration for the Scheduler. When left empty, the preset defined in `resourcesPreset` is applied. | `object` | `{}` |
|
||||
| `controlPlane.scheduler.resources.cpu` | Available CPU | `*quantity` | `null` |
|
||||
| `controlPlane.scheduler.resources.memory` | Available memory (RAM) | `*quantity` | `null` |
|
||||
| `controlPlane.scheduler.resources.cpu` | Available CPU | `*quantity` | `null` |
|
||||
| `controlPlane.scheduler.resources.memory` | Available memory (RAM) | `*quantity` | `null` |
|
||||
| `controlPlane.scheduler.resourcesPreset` | Default sizing preset used when `resources` is omitted. Allowed values: nano, micro, small, medium, large, xlarge, 2xlarge. | `string` | `micro` |
|
||||
| `controlPlane.scheduler.resources` | Explicit CPU and memory configuration for the Scheduler. When left empty, the preset defined in `resourcesPreset` is applied. | `object` | `{}` |
|
||||
| `controlPlane.scheduler.resources.cpu` | Available CPU | `*quantity` | `null` |
|
||||
| `controlPlane.scheduler.resources.memory` | Available memory (RAM) | `*quantity` | `null` |
|
||||
| `controlPlane.scheduler.resources.cpu` | Available CPU | `*quantity` | `null` |
|
||||
| `controlPlane.scheduler.resources.memory` | Available memory (RAM) | `*quantity` | `null` |
|
||||
| `controlPlane.scheduler.resourcesPreset` | Default sizing preset used when `resources` is omitted. Allowed values: nano, micro, small, medium, large, xlarge, 2xlarge. | `string` | `micro` |
|
||||
| `controlPlane.konnectivity` | Konnectivity configuration. | `object` | `{}` |
|
||||
| `controlPlane.konnectivity.server` | Konnectivity server configuration. | `object` | `{}` |
|
||||
| `controlPlane.konnectivity.server.resources` | Explicit CPU and memory configuration for Konnectivity. When left empty, the preset defined in `resourcesPreset` is applied. | `object` | `{}` |
|
||||
| `controlPlane.konnectivity.server.resources.cpu` | Available CPU | `*quantity` | `null` |
|
||||
| `controlPlane.konnectivity.server.resources.memory` | Available memory (RAM) | `*quantity` | `null` |
|
||||
| `controlPlane.konnectivity.server.resources.cpu` | Available CPU | `*quantity` | `null` |
|
||||
| `controlPlane.konnectivity.server.resources.memory` | Available memory (RAM) | `*quantity` | `null` |
|
||||
| `controlPlane.konnectivity.server.resourcesPreset` | Default sizing preset used when `resources` is omitted. Allowed values: nano, micro, small, medium, large, xlarge, 2xlarge. | `string` | `micro` |
|
||||
| `controlPlane.konnectivity.server.resources` | Explicit CPU and memory configuration for Konnectivity. When left empty, the preset defined in `resourcesPreset` is applied. | `object` | `{}` |
|
||||
| `controlPlane.konnectivity.server.resources.cpu` | Available CPU | `*quantity` | `null` |
|
||||
| `controlPlane.konnectivity.server.resources.memory` | Available memory (RAM) | `*quantity` | `null` |
|
||||
| `controlPlane.konnectivity.server.resources.cpu` | Available CPU | `*quantity` | `null` |
|
||||
| `controlPlane.konnectivity.server.resources.memory` | Available memory (RAM) | `*quantity` | `null` |
|
||||
| `controlPlane.konnectivity.server.resourcesPreset` | Default sizing preset used when `resources` is omitted. Allowed values: nano, micro, small, medium, large, xlarge, 2xlarge. | `string` | `micro` |
|
||||
| `controlPlane.konnectivity.server` | Konnectivity server configuration. | `object` | `{}` |
|
||||
| `controlPlane.konnectivity.server.resources` | Explicit CPU and memory configuration for Konnectivity. When left empty, the preset defined in `resourcesPreset` is applied. | `object` | `{}` |
|
||||
| `controlPlane.konnectivity.server.resources.cpu` | Available CPU | `*quantity` | `null` |
|
||||
| `controlPlane.konnectivity.server.resources.memory` | Available memory (RAM) | `*quantity` | `null` |
|
||||
| `controlPlane.konnectivity.server.resources.cpu` | Available CPU | `*quantity` | `null` |
|
||||
| `controlPlane.konnectivity.server.resources.memory` | Available memory (RAM) | `*quantity` | `null` |
|
||||
| `controlPlane.konnectivity.server.resourcesPreset` | Default sizing preset used when `resources` is omitted. Allowed values: nano, micro, small, medium, large, xlarge, 2xlarge. | `string` | `micro` |
|
||||
| `controlPlane.konnectivity.server.resources` | Explicit CPU and memory configuration for Konnectivity. When left empty, the preset defined in `resourcesPreset` is applied. | `object` | `{}` |
|
||||
| `controlPlane.konnectivity.server.resources.cpu` | Available CPU | `*quantity` | `null` |
|
||||
| `controlPlane.konnectivity.server.resources.memory` | Available memory (RAM) | `*quantity` | `null` |
|
||||
| `controlPlane.konnectivity.server.resources.cpu` | Available CPU | `*quantity` | `null` |
|
||||
| `controlPlane.konnectivity.server.resources.memory` | Available memory (RAM) | `*quantity` | `null` |
|
||||
| `controlPlane.konnectivity.server.resourcesPreset` | Default sizing preset used when `resources` is omitted. Allowed values: nano, micro, small, medium, large, xlarge, 2xlarge. | `string` | `micro` |
|
||||
| `controlPlane.replicas` | Number of replicas for Kubernetes control plane components. | `int` | `2` |
|
||||
| `controlPlane.apiServer` | Control plane API server configuration. | `object` | `{}` |
|
||||
| `controlPlane.apiServer.resources` | Explicit CPU and memory configuration for the API Server. When left empty, the preset defined in `resourcesPreset` is applied. | `object` | `{}` |
|
||||
| `controlPlane.apiServer.resources.cpu` | Available CPU | `*quantity` | `null` |
|
||||
| `controlPlane.apiServer.resources.memory` | Available memory (RAM) | `*quantity` | `null` |
|
||||
| `controlPlane.apiServer.resources.cpu` | Available CPU | `*quantity` | `null` |
|
||||
| `controlPlane.apiServer.resources.memory` | Available memory (RAM) | `*quantity` | `null` |
|
||||
| `controlPlane.apiServer.resourcesPreset` | Default sizing preset used when `resources` is omitted. Allowed values: nano, micro, small, medium, large, xlarge, 2xlarge. | `string` | `medium` |
|
||||
| `controlPlane.apiServer.resources` | Explicit CPU and memory configuration for the API Server. When left empty, the preset defined in `resourcesPreset` is applied. | `object` | `{}` |
|
||||
| `controlPlane.apiServer.resources.cpu` | Available CPU | `*quantity` | `null` |
|
||||
| `controlPlane.apiServer.resources.memory` | Available memory (RAM) | `*quantity` | `null` |
|
||||
| `controlPlane.apiServer.resources.cpu` | Available CPU | `*quantity` | `null` |
|
||||
| `controlPlane.apiServer.resources.memory` | Available memory (RAM) | `*quantity` | `null` |
|
||||
| `controlPlane.apiServer.resourcesPreset` | Default sizing preset used when `resources` is omitted. Allowed values: nano, micro, small, medium, large, xlarge, 2xlarge. | `string` | `medium` |
|
||||
| `controlPlane.controllerManager` | Controller Manager configuration. | `object` | `{}` |
|
||||
| `controlPlane.controllerManager.resources` | Explicit CPU and memory configuration for the Controller Manager. When left empty, the preset defined in `resourcesPreset` is applied. | `object` | `{}` |
|
||||
| `controlPlane.controllerManager.resources.cpu` | Available CPU | `*quantity` | `null` |
|
||||
| `controlPlane.controllerManager.resources.memory` | Available memory (RAM) | `*quantity` | `null` |
|
||||
| `controlPlane.controllerManager.resources.cpu` | Available CPU | `*quantity` | `null` |
|
||||
| `controlPlane.controllerManager.resources.memory` | Available memory (RAM) | `*quantity` | `null` |
|
||||
| `controlPlane.controllerManager.resourcesPreset` | Default sizing preset used when `resources` is omitted. Allowed values: nano, micro, small, medium, large, xlarge, 2xlarge. | `string` | `micro` |
|
||||
| `controlPlane.controllerManager.resources` | Explicit CPU and memory configuration for the Controller Manager. When left empty, the preset defined in `resourcesPreset` is applied. | `object` | `{}` |
|
||||
| `controlPlane.controllerManager.resources.cpu` | Available CPU | `*quantity` | `null` |
|
||||
| `controlPlane.controllerManager.resources.memory` | Available memory (RAM) | `*quantity` | `null` |
|
||||
| `controlPlane.controllerManager.resources.cpu` | Available CPU | `*quantity` | `null` |
|
||||
| `controlPlane.controllerManager.resources.memory` | Available memory (RAM) | `*quantity` | `null` |
|
||||
| `controlPlane.controllerManager.resourcesPreset` | Default sizing preset used when `resources` is omitted. Allowed values: nano, micro, small, medium, large, xlarge, 2xlarge. | `string` | `micro` |
|
||||
| `controlPlane.scheduler` | Scheduler configuration. | `object` | `{}` |
|
||||
| `controlPlane.scheduler.resources` | Explicit CPU and memory configuration for the Scheduler. When left empty, the preset defined in `resourcesPreset` is applied. | `object` | `{}` |
|
||||
| `controlPlane.scheduler.resources.cpu` | Available CPU | `*quantity` | `null` |
|
||||
| `controlPlane.scheduler.resources.memory` | Available memory (RAM) | `*quantity` | `null` |
|
||||
| `controlPlane.scheduler.resources.cpu` | Available CPU | `*quantity` | `null` |
|
||||
| `controlPlane.scheduler.resources.memory` | Available memory (RAM) | `*quantity` | `null` |
|
||||
| `controlPlane.scheduler.resourcesPreset` | Default sizing preset used when `resources` is omitted. Allowed values: nano, micro, small, medium, large, xlarge, 2xlarge. | `string` | `micro` |
|
||||
| `controlPlane.scheduler.resources` | Explicit CPU and memory configuration for the Scheduler. When left empty, the preset defined in `resourcesPreset` is applied. | `object` | `{}` |
|
||||
| `controlPlane.scheduler.resources.cpu` | Available CPU | `*quantity` | `null` |
|
||||
| `controlPlane.scheduler.resources.memory` | Available memory (RAM) | `*quantity` | `null` |
|
||||
| `controlPlane.scheduler.resources.cpu` | Available CPU | `*quantity` | `null` |
|
||||
| `controlPlane.scheduler.resources.memory` | Available memory (RAM) | `*quantity` | `null` |
|
||||
| `controlPlane.scheduler.resourcesPreset` | Default sizing preset used when `resources` is omitted. Allowed values: nano, micro, small, medium, large, xlarge, 2xlarge. | `string` | `micro` |
|
||||
| `controlPlane.konnectivity` | Konnectivity configuration. | `object` | `{}` |
|
||||
| `controlPlane.konnectivity.server` | Konnectivity server configuration. | `object` | `{}` |
|
||||
| `controlPlane.konnectivity.server.resources` | Explicit CPU and memory configuration for Konnectivity. When left empty, the preset defined in `resourcesPreset` is applied. | `object` | `{}` |
|
||||
| `controlPlane.konnectivity.server.resources.cpu` | Available CPU | `*quantity` | `null` |
|
||||
| `controlPlane.konnectivity.server.resources.memory` | Available memory (RAM) | `*quantity` | `null` |
|
||||
| `controlPlane.konnectivity.server.resources.cpu` | Available CPU | `*quantity` | `null` |
|
||||
| `controlPlane.konnectivity.server.resources.memory` | Available memory (RAM) | `*quantity` | `null` |
|
||||
| `controlPlane.konnectivity.server.resourcesPreset` | Default sizing preset used when `resources` is omitted. Allowed values: nano, micro, small, medium, large, xlarge, 2xlarge. | `string` | `micro` |
|
||||
| `controlPlane.konnectivity.server.resources` | Explicit CPU and memory configuration for Konnectivity. When left empty, the preset defined in `resourcesPreset` is applied. | `object` | `{}` |
|
||||
| `controlPlane.konnectivity.server.resources.cpu` | Available CPU | `*quantity` | `null` |
|
||||
| `controlPlane.konnectivity.server.resources.memory` | Available memory (RAM) | `*quantity` | `null` |
|
||||
| `controlPlane.konnectivity.server.resources.cpu` | Available CPU | `*quantity` | `null` |
|
||||
| `controlPlane.konnectivity.server.resources.memory` | Available memory (RAM) | `*quantity` | `null` |
|
||||
| `controlPlane.konnectivity.server.resourcesPreset` | Default sizing preset used when `resources` is omitted. Allowed values: nano, micro, small, medium, large, xlarge, 2xlarge. | `string` | `micro` |
|
||||
| `controlPlane.konnectivity.server` | Konnectivity server configuration. | `object` | `{}` |
|
||||
| `controlPlane.konnectivity.server.resources` | Explicit CPU and memory configuration for Konnectivity. When left empty, the preset defined in `resourcesPreset` is applied. | `object` | `{}` |
|
||||
| `controlPlane.konnectivity.server.resources.cpu` | Available CPU | `*quantity` | `null` |
|
||||
| `controlPlane.konnectivity.server.resources.memory` | Available memory (RAM) | `*quantity` | `null` |
|
||||
| `controlPlane.konnectivity.server.resources.cpu` | Available CPU | `*quantity` | `null` |
|
||||
| `controlPlane.konnectivity.server.resources.memory` | Available memory (RAM) | `*quantity` | `null` |
|
||||
| `controlPlane.konnectivity.server.resourcesPreset` | Default sizing preset used when `resources` is omitted. Allowed values: nano, micro, small, medium, large, xlarge, 2xlarge. | `string` | `micro` |
|
||||
| `controlPlane.konnectivity.server.resources` | Explicit CPU and memory configuration for Konnectivity. When left empty, the preset defined in `resourcesPreset` is applied. | `object` | `{}` |
|
||||
| `controlPlane.konnectivity.server.resources.cpu` | Available CPU | `*quantity` | `null` |
|
||||
| `controlPlane.konnectivity.server.resources.memory` | Available memory (RAM) | `*quantity` | `null` |
|
||||
| `controlPlane.konnectivity.server.resources.cpu` | Available CPU | `*quantity` | `null` |
|
||||
| `controlPlane.konnectivity.server.resources.memory` | Available memory (RAM) | `*quantity` | `null` |
|
||||
| `controlPlane.konnectivity.server.resourcesPreset` | Default sizing preset used when `resources` is omitted. Allowed values: nano, micro, small, medium, large, xlarge, 2xlarge. | `string` | `micro` |
|
||||
|
||||
|
||||
## Parameter examples and reference
|
||||
|
||||
@@ -1 +1 @@
|
||||
ghcr.io/cozystack/cozystack/cluster-autoscaler:0.29.0@sha256:2d39989846c3579dd020b9f6c77e6e314cc81aa344eaac0f6d633e723c17196d
|
||||
ghcr.io/cozystack/cozystack/cluster-autoscaler:0.26.2@sha256:3a8170433e1632e5cc2b6d9db34d0605e8e6c63c158282c38450415e700e932e
|
||||
|
||||
@@ -1 +1 @@
|
||||
ghcr.io/cozystack/cozystack/kubevirt-cloud-provider:0.29.0@sha256:5335c044313b69ee13b30ca4941687e509005e55f4ae25723861edbf2fbd6dd2
|
||||
ghcr.io/cozystack/cozystack/kubevirt-cloud-provider:0.26.2@sha256:5335c044313b69ee13b30ca4941687e509005e55f4ae25723861edbf2fbd6dd2
|
||||
|
||||
@@ -1 +1 @@
|
||||
ghcr.io/cozystack/cozystack/kubevirt-csi-driver:0.29.0@sha256:3a3bc912f70ccba1e9f92a0754179dbdc4c01f24073467b6d1406c77da794863
|
||||
ghcr.io/cozystack/cozystack/kubevirt-csi-driver:0.26.2@sha256:761e7235ff9cb7f6f223f00954943e6a5af32ed6624ee592a8610122f96febb0
|
||||
|
||||
@@ -127,6 +127,9 @@ spec:
|
||||
resources: {{- include "cozy-lib.resources.defaultingSanitize" (list .Values.controlPlane.scheduler.resourcesPreset .Values.controlPlane.scheduler.resources $) | nindent 6 }}
|
||||
dataStoreName: "{{ $etcd }}"
|
||||
addons:
|
||||
coreDNS:
|
||||
dnsServiceIPs:
|
||||
- 10.95.0.10
|
||||
konnectivity:
|
||||
server:
|
||||
port: 8132
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
{{- define "cozystack.defaultCoreDNSValues" -}}
|
||||
coredns:
|
||||
service:
|
||||
clusterIP: "10.95.0.10"
|
||||
{{- end }}
|
||||
|
||||
apiVersion: helm.toolkit.fluxcd.io/v2
|
||||
kind: HelmRelease
|
||||
metadata:
|
||||
name: {{ .Release.Name }}-coredns
|
||||
labels:
|
||||
cozystack.io/repository: system
|
||||
cozystack.io/target-cluster-name: {{ .Release.Name }}
|
||||
spec:
|
||||
interval: 5m
|
||||
releaseName: coredns
|
||||
chart:
|
||||
spec:
|
||||
chart: cozy-coredns
|
||||
reconcileStrategy: Revision
|
||||
sourceRef:
|
||||
kind: HelmRepository
|
||||
name: cozystack-system
|
||||
namespace: cozy-system
|
||||
version: '>= 0.0.0-0'
|
||||
kubeConfig:
|
||||
secretRef:
|
||||
name: {{ .Release.Name }}-admin-kubeconfig
|
||||
key: super-admin.svc
|
||||
targetNamespace: kube-system
|
||||
storageNamespace: kube-system
|
||||
install:
|
||||
createNamespace: true
|
||||
remediation:
|
||||
retries: -1
|
||||
upgrade:
|
||||
remediation:
|
||||
retries: -1
|
||||
values:
|
||||
{{- toYaml (deepCopy .Values.addons.coredns.valuesOverride | mergeOverwrite (fromYaml (include "cozystack.defaultCoreDNSValues" .))) | nindent 4 }}
|
||||
dependsOn:
|
||||
{{- if lookup "helm.toolkit.fluxcd.io/v2" "HelmRelease" .Release.Namespace .Release.Name }}
|
||||
- name: {{ .Release.Name }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
{{- end }}
|
||||
- name: {{ .Release.Name }}-cilium
|
||||
namespace: {{ .Release.Namespace }}
|
||||
@@ -41,7 +41,6 @@ spec:
|
||||
{{ .Release.Name }}-fluxcd
|
||||
{{ .Release.Name }}-gpu-operator
|
||||
{{ .Release.Name }}-velero
|
||||
{{ .Release.Name }}-coredns
|
||||
-p '{"spec": {"suspend": true}}'
|
||||
--type=merge --field-manager=flux-client-side-apply || true
|
||||
---
|
||||
@@ -82,7 +81,6 @@ rules:
|
||||
- {{ .Release.Name }}-fluxcd
|
||||
- {{ .Release.Name }}-gpu-operator
|
||||
- {{ .Release.Name }}-velero
|
||||
- {{ .Release.Name }}-coredns
|
||||
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
|
||||
@@ -13,9 +13,6 @@
|
||||
"cilium": {
|
||||
"valuesOverride": {}
|
||||
},
|
||||
"coredns": {
|
||||
"valuesOverride": {}
|
||||
},
|
||||
"fluxcd": {
|
||||
"enabled": false,
|
||||
"valuesOverride": {}
|
||||
@@ -48,7 +45,6 @@
|
||||
"required": [
|
||||
"certManager",
|
||||
"cilium",
|
||||
"coredns",
|
||||
"fluxcd",
|
||||
"gatewayAPI",
|
||||
"gpuOperator",
|
||||
@@ -101,24 +97,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"coredns": {
|
||||
"description": "Coredns",
|
||||
"type": "object",
|
||||
"default": {
|
||||
"valuesOverride": {}
|
||||
},
|
||||
"required": [
|
||||
"valuesOverride"
|
||||
],
|
||||
"properties": {
|
||||
"valuesOverride": {
|
||||
"description": "Custom values to override",
|
||||
"type": "object",
|
||||
"default": {},
|
||||
"x-kubernetes-preserve-unknown-fields": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"fluxcd": {
|
||||
"description": "Flux CD",
|
||||
"type": "object",
|
||||
@@ -351,7 +329,7 @@
|
||||
"default": {},
|
||||
"properties": {
|
||||
"cpu": {
|
||||
"description": "CPU available to each worker node",
|
||||
"description": "Available CPU",
|
||||
"pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
|
||||
"anyOf": [
|
||||
{
|
||||
@@ -364,7 +342,7 @@
|
||||
"x-kubernetes-int-or-string": true
|
||||
},
|
||||
"memory": {
|
||||
"description": "Memory (RAM) available to each worker node",
|
||||
"description": "Available memory (RAM)",
|
||||
"pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
|
||||
"anyOf": [
|
||||
{
|
||||
@@ -379,7 +357,7 @@
|
||||
}
|
||||
},
|
||||
"resourcesPreset": {
|
||||
"description": "Default sizing preset used when `resources` is omitted. Allowed values: `nano`, `micro`, `small`, `medium`, `large`, `xlarge`, `2xlarge`.",
|
||||
"description": "Default sizing preset used when `resources` is omitted. Allowed values: nano, micro, small, medium, large, xlarge, 2xlarge.",
|
||||
"type": "string",
|
||||
"default": "medium",
|
||||
"enum": [
|
||||
@@ -412,7 +390,7 @@
|
||||
"default": {},
|
||||
"properties": {
|
||||
"cpu": {
|
||||
"description": "CPU available to each worker node",
|
||||
"description": "Available CPU",
|
||||
"pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
|
||||
"anyOf": [
|
||||
{
|
||||
@@ -425,7 +403,7 @@
|
||||
"x-kubernetes-int-or-string": true
|
||||
},
|
||||
"memory": {
|
||||
"description": "Memory (RAM) available to each worker node",
|
||||
"description": "Available memory (RAM)",
|
||||
"pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
|
||||
"anyOf": [
|
||||
{
|
||||
@@ -440,7 +418,7 @@
|
||||
}
|
||||
},
|
||||
"resourcesPreset": {
|
||||
"description": "Default sizing preset used when `resources` is omitted. Allowed values: `nano`, `micro`, `small`, `medium`, `large`, `xlarge`, `2xlarge`.",
|
||||
"description": "Default sizing preset used when `resources` is omitted. Allowed values: nano, micro, small, medium, large, xlarge, 2xlarge.",
|
||||
"type": "string",
|
||||
"default": "micro",
|
||||
"enum": [
|
||||
@@ -486,7 +464,7 @@
|
||||
"default": {},
|
||||
"properties": {
|
||||
"cpu": {
|
||||
"description": "CPU available to each worker node",
|
||||
"description": "Available CPU",
|
||||
"pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
|
||||
"anyOf": [
|
||||
{
|
||||
@@ -499,7 +477,7 @@
|
||||
"x-kubernetes-int-or-string": true
|
||||
},
|
||||
"memory": {
|
||||
"description": "Memory (RAM) available to each worker node",
|
||||
"description": "Available memory (RAM)",
|
||||
"pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
|
||||
"anyOf": [
|
||||
{
|
||||
@@ -514,7 +492,7 @@
|
||||
}
|
||||
},
|
||||
"resourcesPreset": {
|
||||
"description": "Default sizing preset used when `resources` is omitted. Allowed values: `nano`, `micro`, `small`, `medium`, `large`, `xlarge`, `2xlarge`.",
|
||||
"description": "Default sizing preset used when `resources` is omitted. Allowed values: nano, micro, small, medium, large, xlarge, 2xlarge.",
|
||||
"type": "string",
|
||||
"default": "micro",
|
||||
"enum": [
|
||||
@@ -554,7 +532,7 @@
|
||||
"default": {},
|
||||
"properties": {
|
||||
"cpu": {
|
||||
"description": "CPU available to each worker node",
|
||||
"description": "Available CPU",
|
||||
"pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
|
||||
"anyOf": [
|
||||
{
|
||||
@@ -567,7 +545,7 @@
|
||||
"x-kubernetes-int-or-string": true
|
||||
},
|
||||
"memory": {
|
||||
"description": "Memory (RAM) available to each worker node",
|
||||
"description": "Available memory (RAM)",
|
||||
"pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
|
||||
"anyOf": [
|
||||
{
|
||||
@@ -582,7 +560,7 @@
|
||||
}
|
||||
},
|
||||
"resourcesPreset": {
|
||||
"description": "Default sizing preset used when `resources` is omitted. Allowed values: `nano`, `micro`, `small`, `medium`, `large`, `xlarge`, `2xlarge`.",
|
||||
"description": "Default sizing preset used when `resources` is omitted. Allowed values: nano, micro, small, medium, large, xlarge, 2xlarge.",
|
||||
"type": "string",
|
||||
"default": "micro",
|
||||
"enum": [
|
||||
@@ -613,7 +591,10 @@
|
||||
"instanceType": "u1.medium",
|
||||
"maxReplicas": 10,
|
||||
"minReplicas": 0,
|
||||
"resources": {},
|
||||
"resources": {
|
||||
"cpu": "",
|
||||
"memory": ""
|
||||
},
|
||||
"roles": [
|
||||
"ingress-nginx"
|
||||
]
|
||||
@@ -671,11 +652,11 @@
|
||||
"type": "integer"
|
||||
},
|
||||
"resources": {
|
||||
"description": "Resources available to each worker node",
|
||||
"description": "Available resources for each worker node",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"cpu": {
|
||||
"description": "CPU available to each worker node",
|
||||
"description": "Available CPU",
|
||||
"pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
|
||||
"anyOf": [
|
||||
{
|
||||
@@ -688,7 +669,7 @@
|
||||
"x-kubernetes-int-or-string": true
|
||||
},
|
||||
"memory": {
|
||||
"description": "Memory (RAM) available to each worker node",
|
||||
"description": "Available memory (RAM)",
|
||||
"pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
|
||||
"anyOf": [
|
||||
{
|
||||
@@ -720,7 +701,7 @@
|
||||
"version": {
|
||||
"description": "Kubernetes version given as vMAJOR.MINOR. Available are versions from 1.28 to 1.33.",
|
||||
"type": "string",
|
||||
"default": "v1.33",
|
||||
"default": "v1.32",
|
||||
"enum": [
|
||||
"v1.28",
|
||||
"v1.29",
|
||||
|
||||
@@ -5,7 +5,7 @@ storageClass: replicated
|
||||
|
||||
## @section Application-specific parameters
|
||||
## @param version {string} Kubernetes version given as vMAJOR.MINOR. Available are versions from 1.28 to 1.33.
|
||||
version: "v1.33"
|
||||
version: "v1.32"
|
||||
## @param host {string} Hostname used to access the Kubernetes cluster externally. Defaults to `<cluster-name>.<tenant-host>` when empty.
|
||||
host: ""
|
||||
|
||||
@@ -16,9 +16,9 @@ host: ""
|
||||
## @field node.instanceType {string} Virtual machine instance type
|
||||
## @field node.ephemeralStorage {quantity} Ephemeral storage size
|
||||
## @field node.roles {[]string} List of node's roles
|
||||
## @field node.resources {resources} Resources available to each worker node
|
||||
## @field resources.cpu {*quantity} CPU available to each worker node
|
||||
## @field resources.memory {*quantity} Memory (RAM) available to each worker node
|
||||
## @field node.resources {resources} Available resources for each worker node
|
||||
## @field resources.cpu {*quantity} Available CPU
|
||||
## @field resources.memory {*quantity} Available memory (RAM)
|
||||
## @field node.gpus {[]gpu} List of GPUs to attach (WARN: NVIDIA driver requires at least 4 GiB of RAM)
|
||||
## @field gpu.name {string} Name of GPU, such as "nvidia.com/AD102GL_L40S"
|
||||
##
|
||||
@@ -122,13 +122,6 @@ addons:
|
||||
enabled: false
|
||||
valuesOverride: {}
|
||||
|
||||
## @field addons.coredns {coredns} Coredns
|
||||
##
|
||||
coredns:
|
||||
## @field coredns.valuesOverride {object} Custom values to override
|
||||
##
|
||||
valuesOverride: {}
|
||||
|
||||
## @section Kubernetes Control Plane Configuration
|
||||
##
|
||||
## @param controlPlane {controlPlane} Control Plane Configuration
|
||||
@@ -144,20 +137,20 @@ controlPlane:
|
||||
## memory: 4Gi
|
||||
##
|
||||
resources: {}
|
||||
## @field apiServer.resourcesPreset {string enum:"nano,micro,small,medium,large,xlarge,2xlarge"} Default sizing preset used when `resources` is omitted. Allowed values: `nano`, `micro`, `small`, `medium`, `large`, `xlarge`, `2xlarge`.
|
||||
## @field apiServer.resourcesPreset {string enum:"nano,micro,small,medium,large,xlarge,2xlarge"} Default sizing preset used when `resources` is omitted. Allowed values: nano, micro, small, medium, large, xlarge, 2xlarge.
|
||||
resourcesPreset: "medium"
|
||||
|
||||
## @field controlPlane.controllerManager {controllerManager} Controller Manager configuration.
|
||||
controllerManager:
|
||||
## @field controllerManager.resources {resources} Explicit CPU and memory configuration for the Controller Manager. When left empty, the preset defined in `resourcesPreset` is applied.
|
||||
## @field controllerManager.resourcesPreset {string enum:"nano,micro,small,medium,large,xlarge,2xlarge"} Default sizing preset used when `resources` is omitted. Allowed values: `nano`, `micro`, `small`, `medium`, `large`, `xlarge`, `2xlarge`.
|
||||
## @field controllerManager.resourcesPreset {string enum:"nano,micro,small,medium,large,xlarge,2xlarge"} Default sizing preset used when `resources` is omitted. Allowed values: nano, micro, small, medium, large, xlarge, 2xlarge.
|
||||
resourcesPreset: "micro"
|
||||
resources: {}
|
||||
|
||||
## @field controlPlane.scheduler {scheduler} Scheduler configuration.
|
||||
scheduler:
|
||||
## @field scheduler.resources {resources} Explicit CPU and memory configuration for the Scheduler. When left empty, the preset defined in `resourcesPreset` is applied.
|
||||
## @field scheduler.resourcesPreset {string enum:"nano,micro,small,medium,large,xlarge,2xlarge"} Default sizing preset used when `resources` is omitted. Allowed values: `nano`, `micro`, `small`, `medium`, `large`, `xlarge`, `2xlarge`.
|
||||
## @field scheduler.resourcesPreset {string enum:"nano,micro,small,medium,large,xlarge,2xlarge"} Default sizing preset used when `resources` is omitted. Allowed values: nano, micro, small, medium, large, xlarge, 2xlarge.
|
||||
resourcesPreset: "micro"
|
||||
resources: {}
|
||||
|
||||
@@ -166,6 +159,6 @@ controlPlane:
|
||||
## @field konnectivity.server {konnectivityServer} Konnectivity server configuration.
|
||||
server:
|
||||
## @field konnectivityServer.resources {resources} Explicit CPU and memory configuration for Konnectivity. When left empty, the preset defined in `resourcesPreset` is applied.
|
||||
## @field konnectivityServer.resourcesPreset {string enum:"nano,micro,small,medium,large,xlarge,2xlarge"} Default sizing preset used when `resources` is omitted. Allowed values: `nano`, `micro`, `small`, `medium`, `large`, `xlarge`, `2xlarge`.
|
||||
## @field konnectivityServer.resourcesPreset {string enum:"nano,micro,small,medium,large,xlarge,2xlarge"} Default sizing preset used when `resources` is omitted. Allowed values: nano, micro, small, medium, large, xlarge, 2xlarge.
|
||||
resourcesPreset: "micro"
|
||||
resources: {}
|
||||
|
||||
@@ -16,7 +16,7 @@ type: application
|
||||
# This is the chart version. This version number should be incremented each time you make changes
|
||||
# to the chart and its templates, including the app version.
|
||||
# Versions are expected to follow Semantic Versioning (https://semver.org/)
|
||||
version: 0.10.0
|
||||
version: 0.9.1
|
||||
|
||||
# This is the version number of the application being deployed. This version number should be
|
||||
# incremented each time you make changes to the application. Versions are not expected to
|
||||
|
||||
@@ -8,11 +8,16 @@ generate:
|
||||
|
||||
image:
|
||||
docker buildx build images/mariadb-backup \
|
||||
--provenance false \
|
||||
--builder=$(BUILDER) \
|
||||
--platform=$(PLATFORM) \
|
||||
--tag $(REGISTRY)/mariadb-backup:$(call settag,$(MARIADB_BACKUP_TAG)) \
|
||||
--cache-from type=registry,ref=$(REGISTRY)/mariadb-backup:latest \
|
||||
--cache-to type=inline \
|
||||
--metadata-file images/mariadb-backup.json \
|
||||
$(BUILDX_ARGS)
|
||||
--push=$(PUSH) \
|
||||
--label "org.opencontainers.image.source=https://github.com/cozystack/cozystack" \
|
||||
--load=$(LOAD)
|
||||
echo "$(REGISTRY)/mariadb-backup:$(call settag,$(MARIADB_BACKUP_TAG))@$$(yq e '."containerimage.digest"' images/mariadb-backup.json -o json -r)" \
|
||||
> images/mariadb-backup.tag
|
||||
rm -f images/mariadb-backup.json
|
||||
|
||||
@@ -14,12 +14,12 @@ This managed service is controlled by mariadb-operator, ensuring efficient manag
|
||||
|
||||
### How to switch master/slave replica
|
||||
|
||||
```bash
|
||||
```
|
||||
kubectl edit mariadb <instnace>
|
||||
```
|
||||
update:
|
||||
|
||||
```bash
|
||||
```
|
||||
spec:
|
||||
replication:
|
||||
primary:
|
||||
@@ -28,7 +28,7 @@ spec:
|
||||
|
||||
check status:
|
||||
|
||||
```bash
|
||||
```
|
||||
NAME READY STATUS PRIMARY POD AGE
|
||||
<instance> True Running app-db1-1 41d
|
||||
```
|
||||
@@ -36,13 +36,13 @@ NAME READY STATUS PRIMARY POD AGE
|
||||
### How to restore backup:
|
||||
|
||||
find snapshot:
|
||||
```bash
|
||||
```
|
||||
restic -r s3:s3.example.org/mariadb-backups/database_name snapshots
|
||||
```
|
||||
|
||||
|
||||
restore:
|
||||
```bash
|
||||
```
|
||||
restic -r s3:s3.example.org/mariadb-backups/database_name restore latest --target /tmp/
|
||||
```
|
||||
|
||||
@@ -51,16 +51,15 @@ more details:
|
||||
|
||||
### Known issues
|
||||
|
||||
- **Replication can't be finished with various errors**
|
||||
- **Replication can't be finished in case if `binlog` purged**
|
||||
|
||||
Until `mariadbbackup` is not used to bootstrap a node by mariadb-operator (this feature is not inmplemented yet), follow these manual steps to fix it:
|
||||
- **Replication can't not be finished with various errors**
|
||||
- **Replication can't be finised in case if binlog purged**
|
||||
Until mariadbbackup is not used to bootstrap a node by mariadb-operator (this feature is not inmplemented yet), follow these manual steps to fix it:
|
||||
https://github.com/mariadb-operator/mariadb-operator/issues/141#issuecomment-1804760231
|
||||
|
||||
- **Corrupted indicies**
|
||||
Sometimes some indecies can be corrupted on master replica, you can recover them from slave:
|
||||
|
||||
```bash
|
||||
```
|
||||
mysqldump -h <slave> -P 3306 -u<user> -p<password> --column-statistics=0 <database> <table> ~/tmp/fix-table.sql
|
||||
mysql -h <master> -P 3306 -u<user> -p<password> <database> < ~/tmp/fix-table.sql
|
||||
```
|
||||
@@ -73,8 +72,10 @@ more details:
|
||||
| ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------- | ----------- | ------- |
|
||||
| `replicas` | Number of MariaDB replicas | `int` | `2` |
|
||||
| `resources` | Explicit CPU and memory configuration for each MariaDB replica. When left empty, the preset defined in `resourcesPreset` is applied. | `*object` | `{}` |
|
||||
| `resources.cpu` | CPU available to each replica | `*quantity` | `null` |
|
||||
| `resources.memory` | Memory (RAM) available to each replica | `*quantity` | `null` |
|
||||
| `resources.cpu` | CPU | `*quantity` | `null` |
|
||||
| `resources.memory` | Memory | `*quantity` | `null` |
|
||||
| `resources.cpu` | CPU | `*quantity` | `null` |
|
||||
| `resources.memory` | Memory | `*quantity` | `null` |
|
||||
| `resourcesPreset` | Default sizing preset used when `resources` is omitted. Allowed values: `nano`, `micro`, `small`, `medium`, `large`, `xlarge`, `2xlarge`. | `string` | `nano` |
|
||||
| `size` | Persistent Volume Claim size, available for application data | `quantity` | `10Gi` |
|
||||
| `storageClass` | StorageClass used to store the data | `string` | `""` |
|
||||
@@ -88,10 +89,19 @@ more details:
|
||||
| `users` | Users configuration | `map[string]object` | `{...}` |
|
||||
| `users[name].password` | Password for the user | `string` | `""` |
|
||||
| `users[name].maxUserConnections` | Maximum amount of connections | `int` | `0` |
|
||||
| `users[name].password` | Password for the user | `string` | `""` |
|
||||
| `users[name].maxUserConnections` | Maximum amount of connections | `int` | `0` |
|
||||
| `databases` | Databases configuration | `map[string]object` | `{...}` |
|
||||
| `databases[name].roles` | Roles for the database | `*object` | `null` |
|
||||
| `databases[name].roles.admin` | List of users with admin privileges | `[]string` | `[]` |
|
||||
| `databases[name].roles.readonly` | List of users with read-only privileges | `[]string` | `[]` |
|
||||
| `databases[name].roles.admin` | List of users with admin privileges | `[]string` | `[]` |
|
||||
| `databases[name].roles.readonly` | List of users with read-only privileges | `[]string` | `[]` |
|
||||
| `databases[name].roles` | Roles for the database | `*object` | `null` |
|
||||
| `databases[name].roles.admin` | List of users with admin privileges | `[]string` | `[]` |
|
||||
| `databases[name].roles.readonly` | List of users with read-only privileges | `[]string` | `[]` |
|
||||
| `databases[name].roles.admin` | List of users with admin privileges | `[]string` | `[]` |
|
||||
| `databases[name].roles.readonly` | List of users with read-only privileges | `[]string` | `[]` |
|
||||
|
||||
|
||||
### Backup parameters
|
||||
@@ -101,12 +111,20 @@ more details:
|
||||
| `backup` | Backup configuration | `object` | `{}` |
|
||||
| `backup.enabled` | Enable regular backups, default is `false`. | `bool` | `false` |
|
||||
| `backup.s3Region` | AWS S3 region where backups are stored | `string` | `us-east-1` |
|
||||
| `backup.s3Bucket` | S3 bucket used for storing backups | `string` | `s3.example.org/mysql-backups` |
|
||||
| `backup.s3Bucket` | S3 bucket used for storing backups | `string` | `s3.example.org/postgres-backups` |
|
||||
| `backup.schedule` | Cron schedule for automated backups | `string` | `0 2 * * *` |
|
||||
| `backup.cleanupStrategy` | Retention strategy for cleaning up old backups | `string` | `--keep-last=3 --keep-daily=3 --keep-within-weekly=1m` |
|
||||
| `backup.s3AccessKey` | Access key for S3, used for authentication | `string` | `<your-access-key>` |
|
||||
| `backup.s3SecretKey` | Secret key for S3, used for authentication | `string` | `<your-secret-key>` |
|
||||
| `backup.resticPassword` | Password for Restic backup encryption | `string` | `<password>` |
|
||||
| `backup.s3AccessKey` | Access key for S3, used for authentication | `string` | `oobaiRus9pah8PhohL1ThaeTa4UVa7gu` |
|
||||
| `backup.s3SecretKey` | Secret key for S3, used for authentication | `string` | `ju3eum4dekeich9ahM1te8waeGai0oog` |
|
||||
| `backup.resticPassword` | Password for Restic backup encryption | `string` | `ChaXoveekoh6eigh4siesheeda2quai0` |
|
||||
| `backup.enabled` | Enable regular backups, default is `false`. | `bool` | `false` |
|
||||
| `backup.s3Region` | AWS S3 region where backups are stored | `string` | `us-east-1` |
|
||||
| `backup.s3Bucket` | S3 bucket used for storing backups | `string` | `s3.example.org/postgres-backups` |
|
||||
| `backup.schedule` | Cron schedule for automated backups | `string` | `0 2 * * *` |
|
||||
| `backup.cleanupStrategy` | Retention strategy for cleaning up old backups | `string` | `--keep-last=3 --keep-daily=3 --keep-within-weekly=1m` |
|
||||
| `backup.s3AccessKey` | Access key for S3, used for authentication | `string` | `oobaiRus9pah8PhohL1ThaeTa4UVa7gu` |
|
||||
| `backup.s3SecretKey` | Secret key for S3, used for authentication | `string` | `ju3eum4dekeich9ahM1te8waeGai0oog` |
|
||||
| `backup.resticPassword` | Password for Restic backup encryption | `string` | `ChaXoveekoh6eigh4siesheeda2quai0` |
|
||||
|
||||
|
||||
## Parameter examples and reference
|
||||
|
||||
@@ -1 +1 @@
|
||||
ghcr.io/cozystack/cozystack/mariadb-backup:0.10.0@sha256:a3789db9e9e065ff60cbac70771b4a8aa1460db3194307cf5ca5d4fe1b412b6b
|
||||
ghcr.io/cozystack/cozystack/mariadb-backup:0.9.1@sha256:a3789db9e9e065ff60cbac70771b4a8aa1460db3194307cf5ca5d4fe1b412b6b
|
||||
|
||||
@@ -8,11 +8,11 @@
|
||||
"default": {
|
||||
"cleanupStrategy": "--keep-last=3 --keep-daily=3 --keep-within-weekly=1m",
|
||||
"enabled": false,
|
||||
"resticPassword": "\u003cpassword\u003e",
|
||||
"s3AccessKey": "\u003cyour-access-key\u003e",
|
||||
"s3Bucket": "s3.example.org/mysql-backups",
|
||||
"resticPassword": "ChaXoveekoh6eigh4siesheeda2quai0",
|
||||
"s3AccessKey": "oobaiRus9pah8PhohL1ThaeTa4UVa7gu",
|
||||
"s3Bucket": "s3.example.org/postgres-backups",
|
||||
"s3Region": "us-east-1",
|
||||
"s3SecretKey": "\u003cyour-secret-key\u003e",
|
||||
"s3SecretKey": "ju3eum4dekeich9ahM1te8waeGai0oog",
|
||||
"schedule": "0 2 * * *"
|
||||
},
|
||||
"required": [
|
||||
@@ -39,17 +39,17 @@
|
||||
"resticPassword": {
|
||||
"description": "Password for Restic backup encryption",
|
||||
"type": "string",
|
||||
"default": "\u003cpassword\u003e"
|
||||
"default": "ChaXoveekoh6eigh4siesheeda2quai0"
|
||||
},
|
||||
"s3AccessKey": {
|
||||
"description": "Access key for S3, used for authentication",
|
||||
"type": "string",
|
||||
"default": "\u003cyour-access-key\u003e"
|
||||
"default": "oobaiRus9pah8PhohL1ThaeTa4UVa7gu"
|
||||
},
|
||||
"s3Bucket": {
|
||||
"description": "S3 bucket used for storing backups",
|
||||
"type": "string",
|
||||
"default": "s3.example.org/mysql-backups"
|
||||
"default": "s3.example.org/postgres-backups"
|
||||
},
|
||||
"s3Region": {
|
||||
"description": "AWS S3 region where backups are stored",
|
||||
@@ -59,7 +59,7 @@
|
||||
"s3SecretKey": {
|
||||
"description": "Secret key for S3, used for authentication",
|
||||
"type": "string",
|
||||
"default": "\u003cyour-secret-key\u003e"
|
||||
"default": "ju3eum4dekeich9ahM1te8waeGai0oog"
|
||||
},
|
||||
"schedule": {
|
||||
"description": "Cron schedule for automated backups",
|
||||
@@ -114,7 +114,7 @@
|
||||
"default": {},
|
||||
"properties": {
|
||||
"cpu": {
|
||||
"description": "CPU available to each replica",
|
||||
"description": "CPU",
|
||||
"pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
|
||||
"anyOf": [
|
||||
{
|
||||
@@ -127,7 +127,7 @@
|
||||
"x-kubernetes-int-or-string": true
|
||||
},
|
||||
"memory": {
|
||||
"description": "Memory (RAM) available to each replica",
|
||||
"description": "Memory",
|
||||
"pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
|
||||
"anyOf": [
|
||||
{
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
## @param replicas {int} Number of MariaDB replicas
|
||||
replicas: 2
|
||||
## @param resources {*resources} Explicit CPU and memory configuration for each MariaDB replica. When left empty, the preset defined in `resourcesPreset` is applied.
|
||||
## @field resources.cpu {*quantity} CPU available to each replica
|
||||
## @field resources.memory {*quantity} Memory (RAM) available to each replica
|
||||
## @field resources.cpu {*quantity} CPU
|
||||
## @field resources.memory {*quantity} Memory
|
||||
resources: {}
|
||||
# resources:
|
||||
# cpu: 4000m
|
||||
@@ -64,10 +64,10 @@ databases: {}
|
||||
backup:
|
||||
enabled: false
|
||||
s3Region: us-east-1
|
||||
s3Bucket: "s3.example.org/mysql-backups"
|
||||
s3Bucket: s3.example.org/postgres-backups
|
||||
schedule: "0 2 * * *"
|
||||
cleanupStrategy: "--keep-last=3 --keep-daily=3 --keep-within-weekly=1m"
|
||||
s3AccessKey: "<your-access-key>"
|
||||
s3SecretKey: "<your-secret-key>"
|
||||
resticPassword: "<password>"
|
||||
s3AccessKey: oobaiRus9pah8PhohL1ThaeTa4UVa7gu
|
||||
s3SecretKey: ju3eum4dekeich9ahM1te8waeGai0oog
|
||||
resticPassword: ChaXoveekoh6eigh4siesheeda2quai0
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ type: application
|
||||
# This is the chart version. This version number should be incremented each time you make changes
|
||||
# to the chart and its templates, including the app version.
|
||||
# Versions are expected to follow Semantic Versioning (https://semver.org/)
|
||||
version: 0.9.0
|
||||
version: 0.8.1
|
||||
|
||||
# This is the version number of the application being deployed. This version number should be
|
||||
# incremented each time you make changes to the application. Versions are not expected to
|
||||
|
||||
@@ -11,8 +11,8 @@ It provides a data layer for cloud native applications, IoT messaging, and micro
|
||||
| ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------- | ----------- | ------- |
|
||||
| `replicas` | Number of replicas | `int` | `2` |
|
||||
| `resources` | Explicit CPU and memory configuration for each NATS replica. When left empty, the preset defined in `resourcesPreset` is applied. | `*object` | `{}` |
|
||||
| `resources.cpu` | CPU available to each replica | `*quantity` | `null` |
|
||||
| `resources.memory` | Memory (RAM) available to each replica | `*quantity` | `null` |
|
||||
| `resources.cpu` | CPU | `*quantity` | `null` |
|
||||
| `resources.memory` | Memory | `*quantity` | `null` |
|
||||
| `resourcesPreset` | Default sizing preset used when `resources` is omitted. Allowed values: `nano`, `micro`, `small`, `medium`, `large`, `xlarge`, `2xlarge`. | `string` | `nano` |
|
||||
| `storageClass` | StorageClass used to store the data | `string` | `""` |
|
||||
| `external` | Enable external access from outside the cluster | `bool` | `false` |
|
||||
|
||||
@@ -10,18 +10,10 @@
|
||||
"resolver": {}
|
||||
},
|
||||
"properties": {
|
||||
"merge": {
|
||||
"description": "Additional configuration to merge into NATS config (see example)",
|
||||
"type": "object",
|
||||
"default": {},
|
||||
"x-kubernetes-preserve-unknown-fields": true
|
||||
"metadata": {
|
||||
"type": "object"
|
||||
},
|
||||
"resolver": {
|
||||
"description": "Additional resolver configuration to merge into NATS config (see example)",
|
||||
"type": "object",
|
||||
"default": {},
|
||||
"x-kubernetes-preserve-unknown-fields": true
|
||||
}
|
||||
"spec": {}
|
||||
}
|
||||
},
|
||||
"external": {
|
||||
@@ -31,35 +23,9 @@
|
||||
},
|
||||
"jetstream": {
|
||||
"description": "Jetstream configuration",
|
||||
"type": "object",
|
||||
"default": {
|
||||
"enabled": true,
|
||||
"size": "10Gi"
|
||||
},
|
||||
"required": [
|
||||
"enabled",
|
||||
"size"
|
||||
],
|
||||
"properties": {
|
||||
"enabled": {
|
||||
"description": "Enable or disable Jetstream. Set to `true` (default) to enable Jetstream for persistent messaging in NATS.",
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"size": {
|
||||
"description": "Jetstream persistent storage size. Specifies the size of the persistent storage for Jetstream (message store).",
|
||||
"default": "10Gi",
|
||||
"pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "integer"
|
||||
},
|
||||
{
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"x-kubernetes-int-or-string": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"replicas": {
|
||||
@@ -73,7 +39,7 @@
|
||||
"default": {},
|
||||
"properties": {
|
||||
"cpu": {
|
||||
"description": "CPU available to each replica",
|
||||
"description": "CPU",
|
||||
"pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
|
||||
"anyOf": [
|
||||
{
|
||||
@@ -86,7 +52,7 @@
|
||||
"x-kubernetes-int-or-string": true
|
||||
},
|
||||
"memory": {
|
||||
"description": "Memory (RAM) available to each replica",
|
||||
"description": "Memory",
|
||||
"pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
|
||||
"anyOf": [
|
||||
{
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
## @param replicas {int} Number of replicas
|
||||
replicas: 2
|
||||
## @param resources {*resources} Explicit CPU and memory configuration for each NATS replica. When left empty, the preset defined in `resourcesPreset` is applied.
|
||||
## @field resources.cpu {*quantity} CPU available to each replica
|
||||
## @field resources.memory {*quantity} Memory (RAM) available to each replica
|
||||
## @field resources.cpu {*quantity} CPU
|
||||
## @field resources.memory {*quantity} Memory
|
||||
resources: {}
|
||||
# resources:
|
||||
# cpu: 4000m
|
||||
|
||||
@@ -16,7 +16,7 @@ type: application
|
||||
# This is the chart version. This version number should be incremented each time you make changes
|
||||
# to the chart and its templates, including the app version.
|
||||
# Versions are expected to follow Semantic Versioning (https://semver.org/)
|
||||
version: 0.18.0
|
||||
version: 0.17.3
|
||||
|
||||
# This is the version number of the application being deployed. This version number should be
|
||||
# incremented each time you make changes to the application. Versions are not expected to
|
||||
|
||||
@@ -70,8 +70,10 @@ See:
|
||||
| ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------- | ----------- | ------- |
|
||||
| `replicas` | Number of Postgres replicas | `int` | `2` |
|
||||
| `resources` | Explicit CPU and memory configuration for each PostgreSQL replica. When left empty, the preset defined in `resourcesPreset` is applied. | `*object` | `{}` |
|
||||
| `resources.cpu` | CPU available to each replica | `*quantity` | `null` |
|
||||
| `resources.memory` | Memory (RAM) available to each replica | `*quantity` | `null` |
|
||||
| `resources.cpu` | CPU | `*quantity` | `null` |
|
||||
| `resources.memory` | Memory | `*quantity` | `null` |
|
||||
| `resources.cpu` | CPU | `*quantity` | `null` |
|
||||
| `resources.memory` | Memory | `*quantity` | `null` |
|
||||
| `resourcesPreset` | Default sizing preset used when `resources` is omitted. Allowed values: `nano`, `micro`, `small`, `medium`, `large`, `xlarge`, `2xlarge`. | `string` | `micro` |
|
||||
| `size` | Persistent Volume Claim size, available for application data | `quantity` | `10Gi` |
|
||||
| `storageClass` | StorageClass used to store the data | `string` | `""` |
|
||||
@@ -85,16 +87,32 @@ See:
|
||||
| `postgresql` | PostgreSQL server configuration | `object` | `{}` |
|
||||
| `postgresql.parameters` | PostgreSQL server parameters | `object` | `{}` |
|
||||
| `postgresql.parameters.max_connections` | Determines the maximum number of concurrent connections to the database server. The default is typically 100 connections | `int` | `100` |
|
||||
| `postgresql.parameters.max_connections` | Determines the maximum number of concurrent connections to the database server. The default is typically 100 connections | `int` | `100` |
|
||||
| `postgresql.parameters` | PostgreSQL server parameters | `object` | `{}` |
|
||||
| `postgresql.parameters.max_connections` | Determines the maximum number of concurrent connections to the database server. The default is typically 100 connections | `int` | `100` |
|
||||
| `postgresql.parameters.max_connections` | Determines the maximum number of concurrent connections to the database server. The default is typically 100 connections | `int` | `100` |
|
||||
| `quorum` | Quorum configuration for synchronous replication | `object` | `{}` |
|
||||
| `quorum.minSyncReplicas` | Minimum number of synchronous replicas that must acknowledge a transaction before it is considered committed. | `int` | `0` |
|
||||
| `quorum.maxSyncReplicas` | Maximum number of synchronous replicas that can acknowledge a transaction (must be lower than the number of instances). | `int` | `0` |
|
||||
| `quorum.minSyncReplicas` | Minimum number of synchronous replicas that must acknowledge a transaction before it is considered committed. | `int` | `0` |
|
||||
| `quorum.maxSyncReplicas` | Maximum number of synchronous replicas that can acknowledge a transaction (must be lower than the number of instances). | `int` | `0` |
|
||||
| `users` | Users configuration | `map[string]object` | `{...}` |
|
||||
| `users[name].password` | Password for the user | `*string` | `null` |
|
||||
| `users[name].replication` | Whether the user has replication privileges | `*bool` | `null` |
|
||||
| `users[name].password` | Password for the user | `*string` | `null` |
|
||||
| `users[name].replication` | Whether the user has replication privileges | `*bool` | `null` |
|
||||
| `databases` | Databases configuration | `map[string]object` | `{...}` |
|
||||
| `databases[name].roles` | Roles for the database | `*object` | `null` |
|
||||
| `databases[name].roles.admin` | List of users with admin privileges | `[]string` | `[]` |
|
||||
| `databases[name].roles.readonly` | List of users with read-only privileges | `[]string` | `[]` |
|
||||
| `databases[name].roles.admin` | List of users with admin privileges | `[]string` | `[]` |
|
||||
| `databases[name].roles.readonly` | List of users with read-only privileges | `[]string` | `[]` |
|
||||
| `databases[name].extensions` | Extensions enabled for the database | `[]string` | `[]` |
|
||||
| `databases[name].roles` | Roles for the database | `*object` | `null` |
|
||||
| `databases[name].roles.admin` | List of users with admin privileges | `[]string` | `[]` |
|
||||
| `databases[name].roles.readonly` | List of users with read-only privileges | `[]string` | `[]` |
|
||||
| `databases[name].roles.admin` | List of users with admin privileges | `[]string` | `[]` |
|
||||
| `databases[name].roles.readonly` | List of users with read-only privileges | `[]string` | `[]` |
|
||||
| `databases[name].extensions` | Extensions enabled for the database | `[]string` | `[]` |
|
||||
|
||||
|
||||
@@ -108,8 +126,15 @@ See:
|
||||
| `backup.retentionPolicy` | Retention policy | `*string` | `30d` |
|
||||
| `backup.destinationPath` | Path to store the backup (i.e. s3://bucket/path/to/folder) | `*string` | `s3://bucket/path/to/folder/` |
|
||||
| `backup.endpointURL` | S3 Endpoint used to upload data to the cloud | `*string` | `http://minio-gateway-service:9000` |
|
||||
| `backup.s3AccessKey` | Access key for S3, used for authentication | `*string` | `<your-access-key>` |
|
||||
| `backup.s3SecretKey` | Secret key for S3, used for authentication | `*string` | `<your-secret-key>` |
|
||||
| `backup.s3AccessKey` | Access key for S3, used for authentication | `*string` | `<access key>` |
|
||||
| `backup.s3SecretKey` | Secret key for S3, used for authentication | `*string` | `<secret key>` |
|
||||
| `backup.enabled` | Enable regular backups | `*bool` | `false` |
|
||||
| `backup.schedule` | Cron schedule for automated backups | `*string` | `0 2 * * * *` |
|
||||
| `backup.retentionPolicy` | Retention policy | `*string` | `30d` |
|
||||
| `backup.destinationPath` | Path to store the backup (i.e. s3://bucket/path/to/folder) | `*string` | `s3://bucket/path/to/folder/` |
|
||||
| `backup.endpointURL` | S3 Endpoint used to upload data to the cloud | `*string` | `http://minio-gateway-service:9000` |
|
||||
| `backup.s3AccessKey` | Access key for S3, used for authentication | `*string` | `<access key>` |
|
||||
| `backup.s3SecretKey` | Secret key for S3, used for authentication | `*string` | `<secret key>` |
|
||||
|
||||
|
||||
### Bootstrap (recovery) parameters
|
||||
@@ -120,6 +145,9 @@ See:
|
||||
| `bootstrap.enabled` | Restore database cluster from a backup | `bool` | `false` |
|
||||
| `bootstrap.recoveryTime` | Timestamp (PITR) up to which recovery will proceed, expressed in RFC 3339 format. If left empty, will restore latest | `*string` | `""` |
|
||||
| `bootstrap.oldName` | Name of database cluster before deleting | `string` | `""` |
|
||||
| `bootstrap.enabled` | Restore database cluster from a backup | `bool` | `false` |
|
||||
| `bootstrap.recoveryTime` | Timestamp (PITR) up to which recovery will proceed, expressed in RFC 3339 format. If left empty, will restore latest | `*string` | `""` |
|
||||
| `bootstrap.oldName` | Name of database cluster before deleting | `string` | `""` |
|
||||
|
||||
|
||||
## Parameter examples and reference
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
"enabled": false,
|
||||
"endpointURL": "http://minio-gateway-service:9000",
|
||||
"retentionPolicy": "30d",
|
||||
"s3AccessKey": "\u003cyour-access-key\u003e",
|
||||
"s3SecretKey": "\u003cyour-secret-key\u003e",
|
||||
"s3AccessKey": "\u003caccess key\u003e",
|
||||
"s3SecretKey": "\u003csecret key\u003e",
|
||||
"schedule": "0 2 * * * *"
|
||||
},
|
||||
"properties": {
|
||||
@@ -38,12 +38,12 @@
|
||||
"s3AccessKey": {
|
||||
"description": "Access key for S3, used for authentication",
|
||||
"type": "string",
|
||||
"default": "\u003cyour-access-key\u003e"
|
||||
"default": "\u003caccess key\u003e"
|
||||
},
|
||||
"s3SecretKey": {
|
||||
"description": "Secret key for S3, used for authentication",
|
||||
"type": "string",
|
||||
"default": "\u003cyour-secret-key\u003e"
|
||||
"default": "\u003csecret key\u003e"
|
||||
},
|
||||
"schedule": {
|
||||
"description": "Cron schedule for automated backups",
|
||||
@@ -188,7 +188,7 @@
|
||||
"default": {},
|
||||
"properties": {
|
||||
"cpu": {
|
||||
"description": "CPU available to each replica",
|
||||
"description": "CPU",
|
||||
"pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
|
||||
"anyOf": [
|
||||
{
|
||||
@@ -201,7 +201,7 @@
|
||||
"x-kubernetes-int-or-string": true
|
||||
},
|
||||
"memory": {
|
||||
"description": "Memory (RAM) available to each replica",
|
||||
"description": "Memory",
|
||||
"pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
|
||||
"anyOf": [
|
||||
{
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
## @param replicas {int} Number of Postgres replicas
|
||||
replicas: 2
|
||||
## @param resources {*resources} Explicit CPU and memory configuration for each PostgreSQL replica. When left empty, the preset defined in `resourcesPreset` is applied.
|
||||
## @field resources.cpu {*quantity} CPU available to each replica
|
||||
## @field resources.memory {*quantity} Memory (RAM) available to each replica
|
||||
## @field resources.cpu {*quantity} CPU
|
||||
## @field resources.memory {*quantity} Memory
|
||||
resources: {}
|
||||
# resources:
|
||||
# cpu: 4000m
|
||||
@@ -91,8 +91,8 @@ backup:
|
||||
destinationPath: "s3://bucket/path/to/folder/"
|
||||
endpointURL: "http://minio-gateway-service:9000"
|
||||
schedule: "0 2 * * * *"
|
||||
s3AccessKey: "<your-access-key>"
|
||||
s3SecretKey: "<your-secret-key>"
|
||||
s3AccessKey: "<access key>"
|
||||
s3SecretKey: "<secret key>"
|
||||
|
||||
## @section Bootstrap (recovery) parameters
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ type: application
|
||||
# This is the chart version. This version number should be incremented each time you make changes
|
||||
# to the chart and its templates, including the app version.
|
||||
# Versions are expected to follow Semantic Versioning (https://semver.org/)
|
||||
version: 0.9.0
|
||||
version: 0.8.1
|
||||
|
||||
# This is the version number of the application being deployed. This version number should be
|
||||
# incremented each time you make changes to the application. Versions are not expected to
|
||||
|
||||
@@ -17,8 +17,8 @@ The service utilizes official RabbitMQ operator. This ensures the reliability an
|
||||
| ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------- | ----------- | ------- |
|
||||
| `replicas` | Number of RabbitMQ replicas | `int` | `3` |
|
||||
| `resources` | Explicit CPU and memory configuration for each RabbitMQ replica. When left empty, the preset defined in `resourcesPreset` is applied. | `*object` | `{}` |
|
||||
| `resources.cpu` | CPU available to each replica | `*quantity` | `null` |
|
||||
| `resources.memory` | Memory (RAM) available to each replica | `*quantity` | `null` |
|
||||
| `resources.cpu` | CPU | `*quantity` | `null` |
|
||||
| `resources.memory` | Memory | `*quantity` | `null` |
|
||||
| `resourcesPreset` | Default sizing preset used when `resources` is omitted. Allowed values: `nano`, `micro`, `small`, `medium`, `large`, `xlarge`, `2xlarge`. | `string` | `nano` |
|
||||
| `size` | Persistent Volume Claim size, available for application data | `quantity` | `10Gi` |
|
||||
| `storageClass` | StorageClass used to store the data | `string` | `""` |
|
||||
@@ -35,6 +35,10 @@ The service utilizes official RabbitMQ operator. This ensures the reliability an
|
||||
| `vhosts[name].roles` | Virtual host roles list | `object` | `{}` |
|
||||
| `vhosts[name].roles.admin` | List of admin users | `[]string` | `[]` |
|
||||
| `vhosts[name].roles.readonly` | List of readonly users | `[]string` | `[]` |
|
||||
| `vhost` | Virtual Host | `object` | `{}` |
|
||||
| `vhost.roles` | Virtual host roles list | `object` | `{}` |
|
||||
| `vhost.roles.admin` | List of admin users | `[]string` | `[]` |
|
||||
| `vhost.roles.readonly` | List of readonly users | `[]string` | `[]` |
|
||||
|
||||
|
||||
## Parameter examples and reference
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
"default": {},
|
||||
"properties": {
|
||||
"cpu": {
|
||||
"description": "CPU available to each replica",
|
||||
"description": "CPU",
|
||||
"pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
|
||||
"anyOf": [
|
||||
{
|
||||
@@ -31,7 +31,7 @@
|
||||
"x-kubernetes-int-or-string": true
|
||||
},
|
||||
"memory": {
|
||||
"description": "Memory (RAM) available to each replica",
|
||||
"description": "Memory",
|
||||
"pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
|
||||
"anyOf": [
|
||||
{
|
||||
@@ -91,6 +91,35 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"vhost": {
|
||||
"description": "Virtual Host",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"roles"
|
||||
],
|
||||
"properties": {
|
||||
"roles": {
|
||||
"description": "Virtual host roles list",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"admin": {
|
||||
"description": "List of admin users",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"readonly": {
|
||||
"description": "List of readonly users",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"vhosts": {
|
||||
"description": "Virtual Hosts configuration",
|
||||
"type": "object",
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
## @param replicas {int} Number of RabbitMQ replicas
|
||||
replicas: 3
|
||||
## @param resources {*resources} Explicit CPU and memory configuration for each RabbitMQ replica. When left empty, the preset defined in `resourcesPreset` is applied.
|
||||
## @field resources.cpu {*quantity} CPU available to each replica
|
||||
## @field resources.memory {*quantity} Memory (RAM) available to each replica
|
||||
## @field resources.cpu {*quantity} CPU
|
||||
## @field resources.memory {*quantity} Memory
|
||||
# resources:
|
||||
# cpu: 4000m
|
||||
# memory: 4Gi
|
||||
@@ -36,6 +36,7 @@ external: false
|
||||
users: {}
|
||||
|
||||
## @param vhosts {map[string]vhost} Virtual Hosts configuration
|
||||
## @param vhost {vhost} Virtual Host
|
||||
## @field vhost.roles {roles} Virtual host roles list
|
||||
## @field roles.admin {[]string} List of admin users
|
||||
## @field roles.readonly {[]string} List of readonly users
|
||||
|
||||
@@ -16,7 +16,7 @@ type: application
|
||||
# This is the chart version. This version number should be incremented each time you make changes
|
||||
# to the chart and its templates, including the app version.
|
||||
# Versions are expected to follow Semantic Versioning (https://semver.org/)
|
||||
version: 0.10.0
|
||||
version: 0.9.1
|
||||
|
||||
# This is the version number of the application being deployed. This version number should be
|
||||
# incremented each time you make changes to the application. Versions are not expected to
|
||||
|
||||
@@ -17,8 +17,8 @@ Service utilizes the Spotahome Redis Operator for efficient management and orche
|
||||
| ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------- | ----------- | ------- |
|
||||
| `replicas` | Number of Redis replicas | `int` | `2` |
|
||||
| `resources` | Explicit CPU and memory configuration for each Redis replica. When left empty, the preset defined in `resourcesPreset` is applied. | `*object` | `{}` |
|
||||
| `resources.cpu` | CPU available to each replica | `*quantity` | `null` |
|
||||
| `resources.memory` | Memory (RAM) available to each replica | `*quantity` | `null` |
|
||||
| `resources.cpu` | CPU | `*quantity` | `null` |
|
||||
| `resources.memory` | Memory | `*quantity` | `null` |
|
||||
| `resourcesPreset` | Default sizing preset used when `resources` is omitted. Allowed values: `nano`, `micro`, `small`, `medium`, `large`, `xlarge`, `2xlarge`. | `string` | `nano` |
|
||||
| `size` | Persistent Volume Claim size, available for application data | `quantity` | `1Gi` |
|
||||
| `storageClass` | StorageClass used to store the data | `string` | `""` |
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
"default": {},
|
||||
"properties": {
|
||||
"cpu": {
|
||||
"description": "CPU available to each replica",
|
||||
"description": "CPU",
|
||||
"pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
|
||||
"anyOf": [
|
||||
{
|
||||
@@ -36,7 +36,7 @@
|
||||
"x-kubernetes-int-or-string": true
|
||||
},
|
||||
"memory": {
|
||||
"description": "Memory (RAM) available to each replica",
|
||||
"description": "Memory",
|
||||
"pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
|
||||
"anyOf": [
|
||||
{
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
## @param replicas {int} Number of Redis replicas
|
||||
replicas: 2
|
||||
## @param resources {*resources} Explicit CPU and memory configuration for each Redis replica. When left empty, the preset defined in `resourcesPreset` is applied.
|
||||
## @field resources.cpu {*quantity} CPU available to each replica
|
||||
## @field resources.memory {*quantity} Memory (RAM) available to each replica
|
||||
## @field resources.cpu {*quantity} CPU
|
||||
## @field resources.memory {*quantity} Memory
|
||||
resources: {}
|
||||
# resources:
|
||||
# cpu: 4000m
|
||||
|
||||
@@ -16,7 +16,7 @@ type: application
|
||||
# This is the chart version. This version number should be incremented each time you make changes
|
||||
# to the chart and its templates, including the app version.
|
||||
# Versions are expected to follow Semantic Versioning (https://semver.org/)
|
||||
version: 0.6.0
|
||||
version: 0.5.1
|
||||
|
||||
# This is the version number of the application being deployed. This version number should be
|
||||
# incremented each time you make changes to the application. Versions are not expected to
|
||||
|
||||
@@ -16,8 +16,10 @@ Managed TCP Load Balancer Service efficiently utilizes HAProxy for load balancin
|
||||
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------ | ----------- | ------- |
|
||||
| `replicas` | Number of HAProxy replicas | `int` | `2` |
|
||||
| `resources` | Explicit CPU and memory configuration for each TCP Balancer replica. When left empty, the preset defined in `resourcesPreset` is applied. | `*object` | `null` |
|
||||
| `resources.cpu` | CPU available to each replica | `*quantity` | `null` |
|
||||
| `resources.memory` | Memory (RAM) available to each replica | `*quantity` | `null` |
|
||||
| `resources.cpu` | CPU | `*quantity` | `null` |
|
||||
| `resources.memory` | Memory | `*quantity` | `null` |
|
||||
| `resources.cpu` | CPU | `*quantity` | `null` |
|
||||
| `resources.memory` | Memory | `*quantity` | `null` |
|
||||
| `resourcesPreset` | Default sizing preset used when `resources` is omitted. Allowed values: `nano`, `micro`, `small`, `medium`, `large`, `xlarge`, `2xlarge`. | `string` | `nano` |
|
||||
| `external` | Enable external access from outside the cluster | `bool` | `false` |
|
||||
|
||||
@@ -31,6 +33,15 @@ Managed TCP Load Balancer Service efficiently utilizes HAProxy for load balancin
|
||||
| `httpAndHttps.targetPorts` | Target ports configuration | `object` | `{}` |
|
||||
| `httpAndHttps.targetPorts.http` | HTTP port number. | `int` | `80` |
|
||||
| `httpAndHttps.targetPorts.https` | HTTPS port number. | `int` | `443` |
|
||||
| `httpAndHttps.targetPorts.http` | HTTP port number. | `int` | `80` |
|
||||
| `httpAndHttps.targetPorts.https` | HTTPS port number. | `int` | `443` |
|
||||
| `httpAndHttps.endpoints` | Endpoint addresses list | `[]string` | `[]` |
|
||||
| `httpAndHttps.mode` | Mode for balancer. Allowed values: `tcp` and `tcp-with-proxy` | `string` | `tcp` |
|
||||
| `httpAndHttps.targetPorts` | Target ports configuration | `object` | `{}` |
|
||||
| `httpAndHttps.targetPorts.http` | HTTP port number. | `int` | `80` |
|
||||
| `httpAndHttps.targetPorts.https` | HTTPS port number. | `int` | `443` |
|
||||
| `httpAndHttps.targetPorts.http` | HTTP port number. | `int` | `80` |
|
||||
| `httpAndHttps.targetPorts.https` | HTTPS port number. | `int` | `443` |
|
||||
| `httpAndHttps.endpoints` | Endpoint addresses list | `[]string` | `[]` |
|
||||
| `whitelistHTTP` | Secure HTTP by whitelisting client networks, `false` by default. | `bool` | `false` |
|
||||
| `whitelist` | List of allowed client networks | `[]string` | `[]` |
|
||||
|
||||
@@ -76,7 +76,7 @@
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"cpu": {
|
||||
"description": "CPU available to each replica",
|
||||
"description": "CPU",
|
||||
"pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
|
||||
"anyOf": [
|
||||
{
|
||||
@@ -89,7 +89,7 @@
|
||||
"x-kubernetes-int-or-string": true
|
||||
},
|
||||
"memory": {
|
||||
"description": "Memory (RAM) available to each replica",
|
||||
"description": "Memory",
|
||||
"pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
|
||||
"anyOf": [
|
||||
{
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
## @param replicas {int} Number of HAProxy replicas
|
||||
replicas: 2
|
||||
## @param resources {*resources} Explicit CPU and memory configuration for each TCP Balancer replica. When left empty, the preset defined in `resourcesPreset` is applied.
|
||||
## @field resources.cpu {*quantity} CPU available to each replica
|
||||
## @field resources.memory {*quantity} Memory (RAM) available to each replica
|
||||
## @field resources.cpu {*quantity} CPU
|
||||
## @field resources.memory {*quantity} Memory
|
||||
#resources: {}
|
||||
# resources:
|
||||
# cpu: 4000m
|
||||
|
||||
@@ -4,4 +4,4 @@ description: Separated tenant namespace
|
||||
icon: /logos/tenant.svg
|
||||
|
||||
type: application
|
||||
version: 1.14.0
|
||||
version: 1.11.2
|
||||
|
||||
@@ -20,7 +20,5 @@ spec:
|
||||
version: "*"
|
||||
interval: 1m0s
|
||||
timeout: 5m0s
|
||||
upgrade:
|
||||
force: true
|
||||
values: {}
|
||||
{{- end }}
|
||||
|
||||
@@ -19,10 +19,10 @@ spec:
|
||||
namespace: cozy-public
|
||||
install:
|
||||
remediation:
|
||||
retries: -1
|
||||
retries: 10
|
||||
upgrade:
|
||||
remediation:
|
||||
retries: -1
|
||||
retries: 10
|
||||
interval: 1m0s
|
||||
timeout: 10m0s
|
||||
{{- end }}
|
||||
|
||||
@@ -20,11 +20,7 @@ metadata:
|
||||
name: allow-external-communication
|
||||
namespace: {{ include "tenant.name" . }}
|
||||
spec:
|
||||
endpointSelector:
|
||||
matchExpressions:
|
||||
- key: policy.cozystack.io/allow-external-communication
|
||||
operator: NotIn
|
||||
values: ["false"]
|
||||
endpointSelector: {}
|
||||
ingress:
|
||||
- fromEntities:
|
||||
- world
|
||||
|
||||
@@ -7,21 +7,4 @@ metadata:
|
||||
spec:
|
||||
hard:
|
||||
{{- include "cozy-lib.resources.flatten" (list .Values.resourceQuotas $) | nindent 6 }}
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: LimitRange
|
||||
metadata:
|
||||
name: tenant-range-limits
|
||||
namespace: {{ include "tenant.name" . }}
|
||||
spec:
|
||||
limits:
|
||||
- default:
|
||||
cpu: "250m"
|
||||
memory: "128Mi"
|
||||
ephemeral-storage: "2Gi"
|
||||
defaultRequest:
|
||||
cpu: "25m"
|
||||
memory: "128Mi"
|
||||
ephemeral-storage: "50Mi"
|
||||
type: Container
|
||||
{{- end }}
|
||||
|
||||
@@ -17,12 +17,6 @@ spec:
|
||||
kind: HelmRepository
|
||||
name: cozystack-extra
|
||||
namespace: cozy-public
|
||||
install:
|
||||
remediation:
|
||||
retries: -1
|
||||
upgrade:
|
||||
remediation:
|
||||
retries: -1
|
||||
interval: 1m0s
|
||||
timeout: 10m0s
|
||||
timeout: 5m0s
|
||||
{{- end }}
|
||||
|
||||
@@ -16,8 +16,7 @@ clickhouse 0.10.0 6358fd7a
|
||||
clickhouse 0.10.1 4369b031
|
||||
clickhouse 0.11.0 08cb7c0f
|
||||
clickhouse 0.11.1 0e47e1e8
|
||||
clickhouse 0.12.0 c02a3818
|
||||
clickhouse 0.13.0 HEAD
|
||||
clickhouse 0.12.0 HEAD
|
||||
ferretdb 0.1.0 e9716091
|
||||
ferretdb 0.1.1 91b0499a
|
||||
ferretdb 0.2.0 6c5cf5bf
|
||||
@@ -31,8 +30,7 @@ ferretdb 0.6.1 632224a3
|
||||
ferretdb 0.7.0 62cb694d
|
||||
ferretdb 0.7.1 4369b031
|
||||
ferretdb 0.8.0 08cb7c0f
|
||||
ferretdb 1.0.0 c02a3818
|
||||
ferretdb 1.1.0 HEAD
|
||||
ferretdb 1.0.0 HEAD
|
||||
http-cache 0.1.0 263e47be
|
||||
http-cache 0.2.0 53f2365e
|
||||
http-cache 0.3.0 6c5cf5bf
|
||||
@@ -42,8 +40,7 @@ http-cache 0.5.0 6130f43d
|
||||
http-cache 0.5.1 62cb694d
|
||||
http-cache 0.5.2 4369b031
|
||||
http-cache 0.6.0 08cb7c0f
|
||||
http-cache 0.6.1 c02a3818
|
||||
http-cache 0.7.0 HEAD
|
||||
http-cache 0.6.1 HEAD
|
||||
kafka 0.1.0 f7eaab0a
|
||||
kafka 0.2.0 c0685f43
|
||||
kafka 0.2.1 dfbc210b
|
||||
@@ -68,10 +65,7 @@ kubernetes 0.25.2 08cb7c0f
|
||||
kubernetes 0.26.0 9584e5f5
|
||||
kubernetes 0.26.1 0e47e1e8
|
||||
kubernetes 0.26.2 8ddbe32e
|
||||
kubernetes 0.26.3 c02a3818
|
||||
kubernetes 0.27.0 6cd5e746
|
||||
kubernetes 0.28.0 7f477eec
|
||||
kubernetes 0.29.0 HEAD
|
||||
kubernetes 0.26.3 HEAD
|
||||
mysql 0.1.0 263e47be
|
||||
mysql 0.2.0 c24a103f
|
||||
mysql 0.3.0 53f2365e
|
||||
@@ -86,8 +80,7 @@ mysql 0.7.1 632224a3
|
||||
mysql 0.8.0 62cb694d
|
||||
mysql 0.8.1 4369b031
|
||||
mysql 0.9.0 08cb7c0f
|
||||
mysql 0.9.1 c02a3818
|
||||
mysql 0.10.0 HEAD
|
||||
mysql 0.9.1 HEAD
|
||||
nats 0.1.0 e9716091
|
||||
nats 0.2.0 6c5cf5bf
|
||||
nats 0.3.0 78366f19
|
||||
@@ -100,8 +93,7 @@ nats 0.6.1 632224a3
|
||||
nats 0.7.0 62cb694d
|
||||
nats 0.7.1 4369b031
|
||||
nats 0.8.0 08cb7c0f
|
||||
nats 0.8.1 c02a3818
|
||||
nats 0.9.0 HEAD
|
||||
nats 0.8.1 HEAD
|
||||
postgres 0.1.0 263e47be
|
||||
postgres 0.2.0 53f2365e
|
||||
postgres 0.2.1 d7cfa53c
|
||||
@@ -125,8 +117,7 @@ postgres 0.15.1 4369b031
|
||||
postgres 0.16.0 70f82667
|
||||
postgres 0.17.0 acd4663a
|
||||
postgres 0.17.1 08cb7c0f
|
||||
postgres 0.17.3 c02a3818
|
||||
postgres 0.18.0 HEAD
|
||||
postgres 0.17.3 HEAD
|
||||
rabbitmq 0.1.0 263e47be
|
||||
rabbitmq 0.2.0 53f2365e
|
||||
rabbitmq 0.3.0 6c5cf5bf
|
||||
@@ -140,8 +131,7 @@ rabbitmq 0.6.0 632224a3
|
||||
rabbitmq 0.7.0 62cb694d
|
||||
rabbitmq 0.7.1 4369b031
|
||||
rabbitmq 0.8.0 08cb7c0f
|
||||
rabbitmq 0.8.1 c02a3818
|
||||
rabbitmq 0.9.0 HEAD
|
||||
rabbitmq 0.8.1 HEAD
|
||||
redis 0.1.1 263e47be
|
||||
redis 0.2.0 53f2365e
|
||||
redis 0.3.0 6c5cf5bf
|
||||
@@ -154,8 +144,7 @@ redis 0.7.1 632224a3
|
||||
redis 0.8.0 62cb694d
|
||||
redis 0.8.1 4369b031
|
||||
redis 0.9.0 08cb7c0f
|
||||
redis 0.9.1 c02a3818
|
||||
redis 0.10.0 HEAD
|
||||
redis 0.9.1 HEAD
|
||||
tcp-balancer 0.1.0 263e47be
|
||||
tcp-balancer 0.2.0 53f2365e
|
||||
tcp-balancer 0.3.0 93bdf411
|
||||
@@ -163,18 +152,52 @@ tcp-balancer 0.4.0 6130f43d
|
||||
tcp-balancer 0.4.1 62cb694d
|
||||
tcp-balancer 0.4.2 4369b031
|
||||
tcp-balancer 0.5.0 08cb7c0f
|
||||
tcp-balancer 0.5.1 c02a3818
|
||||
tcp-balancer 0.6.0 HEAD
|
||||
tenant 1.13.0 8f1975d1
|
||||
tenant 1.14.0 HEAD
|
||||
virtual-machine 0.14.0 HEAD
|
||||
tcp-balancer 0.5.1 HEAD
|
||||
tenant 1.10.0 4369b031
|
||||
tenant 1.11.0 08cb7c0f
|
||||
tenant 1.11.1 28c9fcd6
|
||||
tenant 1.11.2 HEAD
|
||||
virtual-machine 0.1.4 f2015d65
|
||||
virtual-machine 0.1.5 263e47be
|
||||
virtual-machine 0.2.0 c0685f43
|
||||
virtual-machine 0.3.0 6c5cf5bf
|
||||
virtual-machine 0.4.0 b8e33d19
|
||||
virtual-machine 0.5.0 1ec10165
|
||||
virtual-machine 0.6.0 4e68e65c
|
||||
virtual-machine 0.7.0 e23286a3
|
||||
virtual-machine 0.7.1 0ab39f20
|
||||
virtual-machine 0.8.0 3fa4dd3a
|
||||
virtual-machine 0.8.1 93c46161
|
||||
virtual-machine 0.8.2 de19450f
|
||||
virtual-machine 0.9.0 721c12a7
|
||||
virtual-machine 0.9.1 93bdf411
|
||||
virtual-machine 0.10.0 6130f43d
|
||||
virtual-machine 0.10.2 632224a3
|
||||
virtual-machine 0.11.0 4369b031
|
||||
virtual-machine 0.12.0 acd4663a
|
||||
virtual-machine 0.12.1 909208ba
|
||||
virtual-machine 0.12.2 8ddbe32e
|
||||
virtual-machine 0.12.3 HEAD
|
||||
vm-disk 0.1.0 d971f2ff
|
||||
vm-disk 0.1.1 6130f43d
|
||||
vm-disk 0.1.2 632224a3
|
||||
vm-disk 0.2.0 4369b031
|
||||
vm-disk 0.3.0 c02a3818
|
||||
vm-disk 0.4.0 HEAD
|
||||
vm-instance 0.12.0 HEAD
|
||||
vm-disk 0.3.0 HEAD
|
||||
vm-instance 0.1.0 1ec10165
|
||||
vm-instance 0.2.0 84f3ccc0
|
||||
vm-instance 0.3.0 4e68e65c
|
||||
vm-instance 0.4.0 e23286a3
|
||||
vm-instance 0.4.1 0ab39f20
|
||||
vm-instance 0.5.0 3fa4dd3a
|
||||
vm-instance 0.5.1 de19450f
|
||||
vm-instance 0.6.0 721c12a7
|
||||
vm-instance 0.7.0 6130f43d
|
||||
vm-instance 0.7.2 632224a3
|
||||
vm-instance 0.8.0 4369b031
|
||||
vm-instance 0.9.0 acd4663a
|
||||
vm-instance 0.10.0 909208ba
|
||||
vm-instance 0.10.1 8ddbe32e
|
||||
vm-instance 0.10.2 HEAD
|
||||
vpn 0.1.0 263e47be
|
||||
vpn 0.2.0 53f2365e
|
||||
vpn 0.3.0 6c5cf5bf
|
||||
@@ -185,5 +208,4 @@ vpn 0.5.1 632224a3
|
||||
vpn 0.6.1 62cb694d
|
||||
vpn 0.6.2 4369b031
|
||||
vpn 0.7.0 08cb7c0f
|
||||
vpn 0.7.1 c02a3818
|
||||
vpn 0.8.0 HEAD
|
||||
vpn 0.7.1 HEAD
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user