Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Taskfile.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ includes:
artifact:
taskfile: ./images/operator-helm-controller/Taskfile.dist.yaml
dir: ./images/operator-helm-controller
chart-values-artifact:
taskfile: ./images/chart-values-controller/Taskfile.dist.yaml
dir: ./images/chart-values-controller

deps:
taskfile: https://raw.githubusercontent.com/werf/common-ci/refs/heads/main/Taskfile.deps.yml
Expand Down Expand Up @@ -114,13 +117,15 @@ tasks:
- task: api:format
- task: hooks:format
- task: artifact:format
- task: chart-values-artifact:format
- task: e2e:format

lint:
cmds:
- task: api:lint
- task: hooks:lint
- task: artifact:lint
- task: chart-values-artifact:lint
- task: e2e:lint
- task: lint:doc-ru

Expand Down
109 changes: 109 additions & 0 deletions images/chart-values-controller/.golangci.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
# https://golangci-lint.run/usage/configuration/
version: "2"

run:
concurrency: 4
timeout: 10m

issues:
# Show all errors.
max-issues-per-linter: 0
max-same-issues: 0
exclude:
- "don't use an underscore in package name"

output:
sort-results: true

exclusions:
paths:
- "^zz_generated.*"

formatters:
enable:
- gci
- gofmt
- gofumpt
- goimports
settings:
gci:
sections:
- standard
- default
- prefix(github.com/deckhouse/)
gofumpt:
extra-rules: true
goimports:
local-prefixes: github.com/deckhouse/

linters:
default: none
enable:
- asciicheck # checks that your code does not contain non-ASCII identifiers
- bidichk # checks for dangerous unicode character sequences
- bodyclose # checks whether HTTP response body is closed successfully
- contextcheck # [maybe too many false positives] checks the function whether use a non-inherited context
- dogsled # checks assignments with too many blank identifiers (e.g. x, _, _, _, := f())
- errcheck # checking for unchecked errors, these unchecked errors can be critical bugs in some cases
- errname # checks that sentinel errors are prefixed with the Err and error types are suffixed with the Error
- errorlint # finds code that will cause problems with the error wrapping scheme introduced in Go 1.13
- copyloopvar # detects places where loop variables are copied (Go 1.22+)
- gocritic # provides diagnostics that check for bugs, performance and style issues
- govet # reports suspicious constructs, such as Printf calls whose arguments do not align with the format string
- ineffassign # detects when assignments to existing variables are not used
- misspell # finds commonly misspelled English words in comments
- nolintlint # reports ill-formed or insufficient nolint directives
- reassign # checks that package variables are not reassigned
- revive # fast, configurable, extensible, flexible, and beautiful linter for Go, drop-in replacement of golint
- staticcheck # is a go vet on steroids, applying a ton of static analysis checks
- testifylint # checks usage of github.com/stretchr/testify
- unconvert # removes unnecessary type conversions
- unparam # reports unused function parameters
- unused # checks for unused constants, variables, functions and types
- usetesting # reports uses of functions with replacement inside the testing package
- testableexamples # checks if examples are testable (have an expected output)
- thelper # detects golang test helpers without t.Helper() call and checks the consistency of test helpers
- tparallel # detects inappropriate usage of t.Parallel() method in your Go test codes
- whitespace # detects leading and trailing whitespace
- wastedassign # finds wasted assignment statements
- importas # checks import aliases against the configured convention
settings:
errcheck:
exclude-functions:
- "(*os.File).Close"
- "(*net.TCPConn).Close"
- "(io.ReadCloser).Close"
- "(net.Listener).Close"
- "(net.Conn).Close"
- "(net.Conn).Close"
- "(*golang.org/x/crypto/ssh.Session).Close"
- "(*github.com/fsnotify/fsnotify.Watcher).Close"
staticcheck:
dot-import-whitelist:
- github.com/onsi/ginkgo/v2
- github.com/onsi/gomega
revive:
rules:
- name: dot-imports
disabled: true
- name: exported
disabled: true
- name: package-comments
disabled: true
nolintlint:
# Exclude following linters from requiring an explanation.
# Default: []
allow-no-explanation: [funlen, gocognit, lll]
# Enable to require an explanation of nonzero length after each nolint directive.
# Default: false
require-explanation: true
# Enable to require nolint directives to mention the specific linter being suppressed.
# Default: false
require-specific: true
importas:
# Do not allow unaliased imports of aliased packages.
# Default: false
no-unaliased: true
# Do not allow non-required aliases.
# Default: false
no-extra-aliases: false
15 changes: 15 additions & 0 deletions images/chart-values-controller/Taskfile.dist.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
version: "3"

silent: true

includes:
artifact:
taskfile: https://raw.githubusercontent.com/werf/common-ci/refs/heads/main/Taskfile.format_lint.yml
flatten: true
vars:
gciPrefix: '{{.gciPrefix | default "github.com/deckhouse/"}}'
golangciConfigPath: '{{.golangciConfigPath | default "./.golangci.yaml"}}'
golangciLintBinDir: '{{.golangciLintBinDir | default "../../bin"}}'
golangciLintVersion: '{{.golangciLintVersion | default "v2.8.0"}}'
golangciPaths: '{{.golangciPaths | default "./..."}}'
paths: '{{.paths | default "."}}'
134 changes: 134 additions & 0 deletions images/chart-values-controller/cmd/chart-values-controller/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
/*
Copyright 2026 Flant JSC.

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 (
"flag"
"net/http"
"os"
"time"

sourcev1 "github.com/werf/nelm-source-controller/api/v1"
"k8s.io/apimachinery/pkg/runtime"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
_ "k8s.io/client-go/plugin/pkg/client/auth"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/healthz"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"

"github.com/deckhouse/chart-values-controller/internal/cache"
"github.com/deckhouse/chart-values-controller/internal/controller"
"github.com/deckhouse/chart-values-controller/internal/resolver"
"github.com/deckhouse/chart-values-controller/internal/server"
helmv1alpha1 "github.com/deckhouse/operator-helm/api/v1alpha1"
)

// artifactDownloadTimeout bounds a single artifact download from the in-cluster
// source-controller.
const artifactDownloadTimeout = 60 * time.Second

var scheme = runtime.NewScheme()

func init() {
_ = clientgoscheme.AddToScheme(scheme)
_ = helmv1alpha1.AddToScheme(scheme)
_ = sourcev1.AddToScheme(scheme)
}

func main() {
var (
metricsAddr string
healthProbeAddr string
apiAddr string
cacheDir string
cacheTTL time.Duration
sourceInterval time.Duration
maxChartSizeMB int
)

flag.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metrics endpoint binds to.")
flag.StringVar(&healthProbeAddr, "health-probe-bind-address", ":9440", "The address the health probe endpoint binds to.")
flag.StringVar(&apiAddr, "api-bind-address", "127.0.0.1:8081", "The address the chart-values HTTP API binds to.")
flag.StringVar(&cacheDir, "cache-dir", "/cache", "Directory used to cache extracted values.yaml files.")
flag.DurationVar(&cacheTTL, "chart-values-cache-ttl", time.Hour, "Lifetime of auxiliary source resources and their cache entries; refreshed on each request.")
flag.DurationVar(&sourceInterval, "source-interval", 10*time.Minute, "Reconcile interval set on auxiliary source resources.")
flag.IntVar(&maxChartSizeMB, "max-chart-size-mb", 100, "Maximum accepted chart artifact size in MiB; larger artifacts are rejected.")
opts := zap.Options{Development: false}
opts.BindFlags(flag.CommandLine)
flag.Parse()

ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts)))
logger := ctrl.Log.WithName("setup")

if maxChartSizeMB <= 0 {
logger.Error(nil, "invalid --max-chart-size-mb, must be greater than 0", "value", maxChartSizeMB)
os.Exit(1)
}
maxArtifactBytes := int64(maxChartSizeMB) << 20

mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
Scheme: scheme,
Metrics: metricsserver.Options{
BindAddress: metricsAddr,
},
HealthProbeBindAddress: healthProbeAddr,
LeaderElection: false,
})
if err != nil {
logger.Error(err, "unable to create manager")
os.Exit(1)
}

valuesCache := cache.New(cacheDir)
httpClient := &http.Client{Timeout: artifactDownloadTimeout}

res := resolver.New(
mgr.GetClient(),
valuesCache,
httpClient,
helmv1alpha1.TargetNamespace,
cacheTTL,
sourceInterval,
maxArtifactBytes,
)

if err := mgr.Add(server.New(apiAddr, res)); err != nil {
logger.Error(err, "unable to add HTTP server")
os.Exit(1)
}

if err := controller.SetupWithManager(mgr, valuesCache, httpClient, maxArtifactBytes); err != nil {
logger.Error(err, "unable to setup auxiliary-resource controllers")
os.Exit(1)
}

if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil {
logger.Error(err, "unable to set up health check")
os.Exit(1)
}
if err := mgr.AddReadyzCheck("readyz", healthz.Ping); err != nil {
logger.Error(err, "unable to set up ready check")
os.Exit(1)
}

logger.Info("starting manager")
if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
logger.Error(err, "manager exited with error")
os.Exit(1)
}
}
72 changes: 72 additions & 0 deletions images/chart-values-controller/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
module github.com/deckhouse/chart-values-controller

go 1.26.3

replace github.com/deckhouse/operator-helm/api => ../../api

require (
github.com/deckhouse/operator-helm/api v0.0.0-00010101000000-000000000000
github.com/werf/3p-fluxcd-pkg/apis/meta v1.23.0-nelm.1
github.com/werf/nelm-source-controller/api v0.1.5
k8s.io/api v0.35.1
k8s.io/apimachinery v0.35.1
k8s.io/client-go v0.35.1
sigs.k8s.io/controller-runtime v0.23.1
)

require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/emicklei/go-restful/v3 v3.12.2 // indirect
github.com/evanphx/json-patch/v5 v5.9.11 // indirect
github.com/fsnotify/fsnotify v1.9.0 // indirect
github.com/fxamacker/cbor/v2 v2.9.0 // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/zapr v1.3.0 // indirect
github.com/go-openapi/jsonpointer v0.21.1 // indirect
github.com/go-openapi/jsonreference v0.21.0 // indirect
github.com/go-openapi/swag v0.23.1 // indirect
github.com/google/btree v1.1.3 // indirect
github.com/google/gnostic-models v0.7.0 // indirect
github.com/google/go-cmp v0.7.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/mailru/easyjson v0.9.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/prometheus/client_golang v1.23.2 // indirect
github.com/prometheus/client_model v0.6.2 // indirect
github.com/prometheus/common v0.66.1 // indirect
github.com/prometheus/procfs v0.16.1 // indirect
github.com/spf13/pflag v1.0.10 // indirect
github.com/werf/3p-fluxcd-pkg/apis/acl v0.9.0-nelm.1 // indirect
github.com/x448/float16 v0.8.4 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect
go.yaml.in/yaml/v2 v2.4.3 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/net v0.48.0 // indirect
golang.org/x/oauth2 v0.30.0 // indirect
golang.org/x/sync v0.19.0 // indirect
golang.org/x/sys v0.40.0 // indirect
golang.org/x/term v0.39.0 // indirect
golang.org/x/text v0.33.0 // indirect
golang.org/x/time v0.12.0 // indirect
gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
google.golang.org/protobuf v1.36.8 // indirect
gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/apiextensions-apiserver v0.35.1 // indirect
k8s.io/klog/v2 v2.130.1 // indirect
k8s.io/kube-openapi v0.0.0-20260127142750-a19766b6e2d4 // indirect
k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 // indirect
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect
sigs.k8s.io/randfill v1.0.0 // indirect
sigs.k8s.io/structured-merge-diff/v6 v6.3.2-0.20260122202528-d9cc6641c482 // indirect
sigs.k8s.io/yaml v1.6.0 // indirect
)
Loading
Loading