Files
dokku/plugins/docker-options/triggers.go
Jose Diaz-Gonzalez 8d4e7d9793 fix: match docker options by shell word when removing
Options drained out of the pre-0.38.0 `DOCKER_OPTIONS_<PHASE>` files were copied verbatim rather than re-serialized the way `docker-options:add` stores them, so `docker-options:remove` compared the canonical string it builds against a stored value that could never match it and exited successfully without removing anything. Removal now matches stored options by shell word, and stored options are rewritten into the canonical form once on upgrade, which additionally splits an entry that carried several flags on a single line into one entry per flag so a single flag can be removed and so the readers that match on a flag prefix see one value per entry. The leftover `.migrated` sentinel drain is restored to running ahead of the global short-circuit that had made it unreachable, and the plugin's Go tests are added to the test target that had never run them.
2026-08-07 13:35:37 -04:00

149 lines
4.2 KiB
Go

package dockeroptions
import (
"fmt"
"io"
"os"
"strings"
"github.com/dokku/dokku/plugins/common"
)
// TriggerInstall sets up the docker-options property directory and migrates
// any pre-existing DOCKER_OPTIONS_* files into property lists.
func TriggerInstall() error {
if err := common.PropertySetup("docker-options"); err != nil {
return fmt.Errorf("Unable to install the docker-options plugin: %v", err)
}
if err := migrateLegacyDockerOptionsFiles(); err != nil {
return fmt.Errorf("Unable to migrate legacy docker-options files: %v", err)
}
if err := migrateTraefikLabelBackticks(); err != nil {
return fmt.Errorf("Unable to repair docker-options label backticks: %v", err)
}
if err := migrateNonCanonicalOptions(); err != nil {
return fmt.Errorf("Unable to rewrite docker-options into canonical form: %v", err)
}
return nil
}
// TriggerPostAppCloneSetup copies docker option properties from the source app
// to the cloned app.
func TriggerPostAppCloneSetup(oldAppName string, newAppName string) error {
return common.PropertyClone("docker-options", oldAppName, newAppName)
}
// TriggerPostAppRenameSetup moves docker option properties from the old app
// name to the new one.
func TriggerPostAppRenameSetup(oldAppName string, newAppName string) error {
if err := common.PropertyClone("docker-options", oldAppName, newAppName); err != nil {
return err
}
return common.PropertyDestroy("docker-options", oldAppName)
}
// TriggerPostDelete removes the docker option properties for an app and
// cleans up any leftover migrated legacy files.
func TriggerPostDelete(appName string) error {
if err := common.PropertyDestroy("docker-options", appName); err != nil {
return err
}
return nil
}
// TriggerDockerArgs implements the legacy docker-args-{build,deploy,run}
// triggers. It echoes stdin verbatim, then appends the default-scope options
// for the given phase after applying image-source-type filtering.
func TriggerDockerArgs(phase, appName, imageSourceType, processType string) error {
stdin, err := io.ReadAll(os.Stdin)
if err != nil {
return err
}
if _, err := os.Stdout.Write(stdin); err != nil {
return err
}
options, err := GetDockerOptionsForProcessPhase(appName, DefaultProcessType, phase)
if err != nil {
return err
}
emitFilteredOptions(phase, imageSourceType, options)
return nil
}
// TriggerDockerArgsProcessDeploy implements docker-args-process-deploy. It
// echoes stdin verbatim, then appends the deploy-phase options for the
// process-specific scope (filtered by image source type). Default-scope
// options are emitted by TriggerDockerArgs (docker-args-deploy), which the
// scheduler invokes alongside the per-process trigger.
func TriggerDockerArgsProcessDeploy(appName, imageSourceType, processType string) error {
stdin, err := io.ReadAll(os.Stdin)
if err != nil {
return err
}
if _, err := os.Stdout.Write(stdin); err != nil {
return err
}
if processType == "" || processType == DefaultProcessType {
return nil
}
options, err := GetDockerOptionsForProcessPhase(appName, processType, "deploy")
if err != nil {
return err
}
emitFilteredOptions("deploy", imageSourceType, options)
return nil
}
// emitFilteredOptions writes filtered docker options to stdout, prefixed with
// a single space so concatenation with prior output stays well-formed. It
// reproduces the filtering historically performed by the bash docker-args-*
// triggers.
func emitFilteredOptions(phase, imageSourceType string, options []string) {
for _, option := range options {
option = strings.TrimSpace(option)
if option == "" || strings.HasPrefix(option, "#") {
continue
}
if strings.HasPrefix(option, "--restart") {
if phase == "deploy" {
fmt.Printf(" %s", option)
}
continue
}
switch imageSourceType {
case "dockerfile", "nixpacks", "railpack":
if hasAnyPrefix(option, "--link", "-v", "--volume") {
continue
}
case "herokuish":
if hasAnyPrefix(option, "--file", "--build-args") {
continue
}
}
fmt.Printf(" %s", option)
}
}
func hasAnyPrefix(s string, prefixes ...string) bool {
for _, prefix := range prefixes {
if s == prefix || strings.HasPrefix(s, prefix+"=") || strings.HasPrefix(s, prefix+" ") {
return true
}
}
return false
}