Files
dokku/plugins/scheduler-k3s/pull_secret.go
Jose Diaz-Gonzalez 7ba453e588 fix: thread secret annotations and labels through new helm charts
The new config and pull secret helm releases need to honor user-set annotations and labels for `--resource-type secret` so existing scheduler-k3s annotation tests keep passing. The dedicated charts now render `.Values.global.annotations` and `.Values.global.labels` onto their Secret manifest, and the deploy trigger plumbs `SecretAnnotations` and `SecretLabels` from the global annotation/label config. The rollback regression bats test now uses `dokku ps:rebuild` for its second deploy because git push of an unchanged ref is rejected by the dokku remote.
2026-04-29 12:18:06 -04:00

184 lines
5.5 KiB
Go

package scheduler_k3s
import (
"context"
"encoding/base64"
"fmt"
"os"
"path/filepath"
"github.com/dokku/dokku/plugins/common"
)
// ImagePullSecretValues contains the values for the dokku-managed image pull secret helm chart
type ImagePullSecretValues struct {
Global ImagePullSecretGlobalValues `yaml:"global"`
}
// ImagePullSecretGlobalValues contains the global values for the image pull secret chart
type ImagePullSecretGlobalValues struct {
Annotations map[string]string `yaml:"annotations,omitempty"`
AppName string `yaml:"app_name"`
Labels map[string]string `yaml:"labels,omitempty"`
Namespace string `yaml:"namespace"`
PullSecretBase64 string `yaml:"pull_secret_base64"`
}
// GetImagePullSecretReleaseName returns the helm release name for the image pull secret
func GetImagePullSecretReleaseName(appName string) string {
return fmt.Sprintf("pull-secret-%s", appName)
}
// GetImagePullSecretName returns the kubernetes secret name for the dokku-managed image pull secret
func GetImagePullSecretName(appName string) string {
return fmt.Sprintf("pull-secret-%s", appName)
}
// CreateOrUpdateImagePullSecretInput contains the inputs to CreateOrUpdateImagePullSecret
type CreateOrUpdateImagePullSecretInput struct {
AppName string
DockerConfigJSON []byte
Annotations map[string]string
Labels map[string]string
}
// CreateOrUpdateImagePullSecret creates or updates the image pull secret helm chart for an app
func CreateOrUpdateImagePullSecret(ctx context.Context, input CreateOrUpdateImagePullSecretInput) error {
appName := input.AppName
if err := isKubernetesAvailable(); err != nil {
common.LogDebug("kubernetes not available, skipping image pull secret creation")
return nil
}
scheduler := common.PropertyGetDefault("scheduler", appName, "selected", "")
globalScheduler := common.PropertyGetDefault("scheduler", "--global", "selected", "docker-local")
if scheduler == "" {
scheduler = globalScheduler
}
if scheduler != "k3s" {
common.LogDebug("app does not use k3s scheduler, skipping image pull secret creation")
return nil
}
chartDir, err := os.MkdirTemp("", "dokku-pull-secret-chart-")
if err != nil {
return fmt.Errorf("error creating chart directory: %w", err)
}
defer os.RemoveAll(chartDir)
if err := os.MkdirAll(filepath.Join(chartDir, "templates"), os.FileMode(0755)); err != nil {
return fmt.Errorf("error creating chart templates directory: %w", err)
}
namespace := getComputedNamespace(appName)
releaseName := GetImagePullSecretReleaseName(appName)
chart := &Chart{
ApiVersion: "v2",
AppVersion: "1.0.0",
Name: releaseName,
Icon: "https://dokku.com/assets/dokku-logo.svg",
Version: "0.0.1",
}
err = writeYaml(WriteYamlInput{
Object: chart,
Path: filepath.Join(chartDir, "Chart.yaml"),
})
if err != nil {
return fmt.Errorf("error writing chart: %w", err)
}
b, err := templates.ReadFile("templates/pull-secret-chart/templates/pull-secret.yaml")
if err != nil {
return fmt.Errorf("error reading pull-secret template: %w", err)
}
filename := filepath.Join(chartDir, "templates", "pull-secret.yaml")
err = os.WriteFile(filename, b, os.FileMode(0644))
if err != nil {
return fmt.Errorf("error writing pull-secret template: %w", err)
}
if os.Getenv("DOKKU_TRACE") == "1" {
common.CatFile(filename)
}
values := &ImagePullSecretValues{
Global: ImagePullSecretGlobalValues{
Annotations: input.Annotations,
AppName: appName,
Labels: input.Labels,
Namespace: namespace,
PullSecretBase64: base64.StdEncoding.EncodeToString(input.DockerConfigJSON),
},
}
err = writeYaml(WriteYamlInput{
Object: values,
Path: filepath.Join(chartDir, "values.yaml"),
})
if err != nil {
return fmt.Errorf("error writing values: %w", err)
}
if err := createKubernetesNamespace(ctx, namespace); err != nil {
return fmt.Errorf("error creating namespace: %w", err)
}
helmAgent, err := NewHelmAgent(namespace, DeployLogPrinter)
if err != nil {
return fmt.Errorf("error creating helm agent: %w", err)
}
chartPath, err := filepath.Abs(chartDir)
if err != nil {
return fmt.Errorf("error getting chart path: %w", err)
}
common.LogVerboseQuiet(fmt.Sprintf("Installing image pull secret for %s", appName))
err = helmAgent.InstallOrUpgradeChart(ctx, ChartInput{
ChartPath: chartPath,
Namespace: namespace,
ReleaseName: releaseName,
Wait: false,
})
if err != nil {
return fmt.Errorf("error installing image pull secret chart: %w", err)
}
return nil
}
// DeleteImagePullSecret deletes the image pull secret helm chart for an app
func DeleteImagePullSecret(ctx context.Context, appName string) error {
if err := isKubernetesAvailable(); err != nil {
common.LogDebug("kubernetes not available, skipping image pull secret deletion")
return nil
}
namespace := getComputedNamespace(appName)
releaseName := GetImagePullSecretReleaseName(appName)
helmAgent, err := NewHelmAgent(namespace, DeployLogPrinter)
if err != nil {
return fmt.Errorf("error creating helm agent: %w", err)
}
exists, err := helmAgent.ChartExists(releaseName)
if err != nil {
return fmt.Errorf("error checking if image pull secret chart exists: %w", err)
}
if !exists {
return nil
}
common.LogVerboseQuiet(fmt.Sprintf("Removing image pull secret for %s", appName))
if err := helmAgent.UninstallChart(releaseName); err != nil {
return fmt.Errorf("error uninstalling image pull secret chart: %w", err)
}
return nil
}