fix: Missing reloader.go

This commit is contained in:
TheiLLeniumStudios
2026-01-08 14:22:43 +01:00
parent f7210204d4
commit 193f64c0ec
3 changed files with 264 additions and 9 deletions

1
.gitignore vendored
View File

@@ -11,6 +11,7 @@ vendor
dist
Reloader
!**/chart/reloader
!**/internal/reloader
*.tgz
styles/
site/

View File

@@ -0,0 +1,250 @@
package reloader
import (
"context"
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"
"time"
)
// Config holds configuration for a Reloader deployment.
type Config struct {
Version string
Image string
Namespace string
ReloadStrategy string
}
// Manager handles Reloader deployment operations.
type Manager struct {
config Config
kubeContext string
}
// NewManager creates a new Reloader manager.
func NewManager(config Config) *Manager {
return &Manager{
config: config,
}
}
// SetKubeContext sets the kubeconfig context to use.
func (m *Manager) SetKubeContext(kubeContext string) {
m.kubeContext = kubeContext
}
// kubectl returns kubectl command with optional context.
func (m *Manager) kubectl(ctx context.Context, args ...string) *exec.Cmd {
if m.kubeContext != "" {
args = append([]string{"--context", m.kubeContext}, args...)
}
return exec.CommandContext(ctx, "kubectl", args...)
}
// namespace returns the namespace for this reloader instance.
func (m *Manager) namespace() string {
if m.config.Namespace != "" {
return m.config.Namespace
}
return fmt.Sprintf("reloader-%s", m.config.Version)
}
// releaseName returns the release name for this instance.
func (m *Manager) releaseName() string {
return fmt.Sprintf("reloader-%s", m.config.Version)
}
// Job returns the Prometheus job name for this Reloader instance.
func (m *Manager) Job() string {
return fmt.Sprintf("reloader-%s", m.config.Version)
}
// Deploy deploys Reloader to the cluster using raw manifests.
func (m *Manager) Deploy(ctx context.Context) error {
ns := m.namespace()
name := m.releaseName()
fmt.Printf("Deploying Reloader (%s) with image %s...\n", m.config.Version, m.config.Image)
manifest := m.buildManifest(ns, name)
applyCmd := m.kubectl(ctx, "apply", "-f", "-")
applyCmd.Stdin = strings.NewReader(manifest)
applyCmd.Stdout = os.Stdout
applyCmd.Stderr = os.Stderr
if err := applyCmd.Run(); err != nil {
return fmt.Errorf("applying manifest: %w", err)
}
fmt.Printf("Waiting for Reloader deployment to be ready...\n")
waitCmd := m.kubectl(ctx, "rollout", "status", "deployment", name,
"-n", ns,
"--timeout=120s")
waitCmd.Stdout = os.Stdout
waitCmd.Stderr = os.Stderr
if err := waitCmd.Run(); err != nil {
return fmt.Errorf("waiting for deployment: %w", err)
}
time.Sleep(2 * time.Second)
fmt.Printf("Reloader (%s) deployed successfully\n", m.config.Version)
return nil
}
// buildManifest creates the raw Kubernetes manifest for Reloader.
func (m *Manager) buildManifest(ns, name string) string {
var args []string
args = append(args, "--log-format=json")
if m.config.ReloadStrategy != "" && m.config.ReloadStrategy != "default" {
args = append(args, fmt.Sprintf("--reload-strategy=%s", m.config.ReloadStrategy))
}
argsYAML := ""
if len(args) > 0 {
argsYAML = " args:\n"
for _, arg := range args {
argsYAML += fmt.Sprintf(" - %q\n", arg)
}
}
return fmt.Sprintf(`---
apiVersion: v1
kind: Namespace
metadata:
name: %[1]s
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: %[2]s
namespace: %[1]s
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: %[2]s
rules:
- apiGroups: ["*"]
resources: ["*"]
verbs: ["*"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: %[2]s
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: %[2]s
subjects:
- kind: ServiceAccount
name: %[2]s
namespace: %[1]s
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: %[2]s
namespace: %[1]s
labels:
app: %[2]s
app.kubernetes.io/name: reloader
loadtest-version: %[3]s
spec:
replicas: 1
selector:
matchLabels:
app: %[2]s
template:
metadata:
labels:
app: %[2]s
app.kubernetes.io/name: reloader
loadtest-version: %[3]s
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "9090"
prometheus.io/path: "/metrics"
spec:
serviceAccountName: %[2]s
securityContext:
runAsNonRoot: true
runAsUser: 65534
containers:
- name: reloader
image: %[4]s
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 9090
%[5]s resources:
requests:
cpu: 10m
memory: 64Mi
limits:
cpu: 500m
memory: 256Mi
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
`, ns, name, m.config.Version, m.config.Image, argsYAML)
}
// Cleanup removes all Reloader resources from the cluster.
func (m *Manager) Cleanup(ctx context.Context) error {
ns := m.namespace()
name := m.releaseName()
delDeploy := m.kubectl(ctx, "delete", "deployment", name, "-n", ns, "--ignore-not-found")
delDeploy.Run()
delCRB := m.kubectl(ctx, "delete", "clusterrolebinding", name, "--ignore-not-found")
delCRB.Run()
delCR := m.kubectl(ctx, "delete", "clusterrole", name, "--ignore-not-found")
delCR.Run()
delNS := m.kubectl(ctx, "delete", "namespace", ns, "--wait=false", "--ignore-not-found")
if err := delNS.Run(); err != nil {
return fmt.Errorf("deleting namespace: %w", err)
}
return nil
}
// CollectLogs collects logs from the Reloader pod and writes them to the specified file.
func (m *Manager) CollectLogs(ctx context.Context, logPath string) error {
ns := m.namespace()
name := m.releaseName()
if err := os.MkdirAll(filepath.Dir(logPath), 0755); err != nil {
return fmt.Errorf("creating log directory: %w", err)
}
cmd := m.kubectl(ctx, "logs",
"-n", ns,
"-l", fmt.Sprintf("app=%s", name),
"--tail=-1")
out, err := cmd.Output()
if err != nil {
cmd = m.kubectl(ctx, "logs",
"-n", ns,
"-l", "app.kubernetes.io/name=reloader",
"--tail=-1")
out, err = cmd.Output()
if err != nil {
return fmt.Errorf("collecting logs: %w", err)
}
}
if err := os.WriteFile(logPath, out, 0644); err != nil {
return fmt.Errorf("writing logs: %w", err)
}
return nil
}

View File

@@ -1137,7 +1137,7 @@ func (s *SecretsAndMixedScenario) Run(ctx context.Context, client kubernetes.Int
for time.Now().Before(endTime) {
select {
case <-ctx.Done():
return s.calculateExpected(secretUpdateCount, cmUpdateCount, numSecretOnlyDeploys, numConfigMapOnlyDeploys, numMixedDeploys), nil
return s.calculateExpected(secretUpdateCount, cmUpdateCount, numSecrets, numConfigMaps, numSecretOnlyDeploys, numConfigMapOnlyDeploys, numMixedDeploys), nil
case <-ticker.C:
if updateSecret {
// Update a random Secret
@@ -1169,21 +1169,25 @@ func (s *SecretsAndMixedScenario) Run(ctx context.Context, client kubernetes.Int
}
log.Printf("S10: Completed %d Secret updates and %d ConfigMap updates", secretUpdateCount, cmUpdateCount)
return s.calculateExpected(secretUpdateCount, cmUpdateCount, numSecretOnlyDeploys, numConfigMapOnlyDeploys, numMixedDeploys), nil
return s.calculateExpected(secretUpdateCount, cmUpdateCount, numSecrets, numConfigMaps, numSecretOnlyDeploys, numConfigMapOnlyDeploys, numMixedDeploys), nil
}
func (s *SecretsAndMixedScenario) calculateExpected(secretUpdates, cmUpdates, secretOnlyDeploys, cmOnlyDeploys, mixedDeploys int) ExpectedMetrics {
// Secret updates trigger: secret-only deploys + mixed deploys
secretTriggeredReloads := secretUpdates * (secretOnlyDeploys + mixedDeploys)
// ConfigMap updates trigger: cm-only deploys + mixed deploys
cmTriggeredReloads := cmUpdates * (cmOnlyDeploys + mixedDeploys)
func (s *SecretsAndMixedScenario) calculateExpected(secretUpdates, cmUpdates, numSecrets, numConfigMaps, secretOnlyDeploys, cmOnlyDeploys, mixedDeploys int) ExpectedMetrics {
// Average deploys triggered per random secret update
avgSecretReloads := float64(secretOnlyDeploys)/float64(numSecrets) + float64(mixedDeploys)/float64(numSecrets)
secretTriggeredReloads := int(float64(secretUpdates) * avgSecretReloads)
// Average deploys triggered per random CM update
avgCMReloads := float64(cmOnlyDeploys)/float64(numConfigMaps) + float64(mixedDeploys)/float64(numConfigMaps)
cmTriggeredReloads := int(float64(cmUpdates) * avgCMReloads)
totalExpectedReloads := secretTriggeredReloads + cmTriggeredReloads
return ExpectedMetrics{
ActionTotal: totalExpectedReloads,
ReloadExecutedTotal: totalExpectedReloads,
Description: fmt.Sprintf("S10: %d Secret updates (→%d reloads) + %d CM updates (→%d reloads) = %d total",
secretUpdates, secretTriggeredReloads, cmUpdates, cmTriggeredReloads, totalExpectedReloads),
Description: fmt.Sprintf("S10: %d Secret updates (→%d reloads, avg %.1f/update) + %d CM updates (→%d reloads, avg %.1f/update) = %d total",
secretUpdates, secretTriggeredReloads, avgSecretReloads, cmUpdates, cmTriggeredReloads, avgCMReloads, totalExpectedReloads),
}
}