Merge pull request #6716 from dokku/1558-move-env

Move app and global ENV files to consolidated config path
This commit is contained in:
Jose Diaz-Gonzalez
2026-04-27 02:50:24 -04:00
committed by GitHub
13 changed files with 191 additions and 21 deletions

View File

@@ -541,6 +541,10 @@ func PropertySetup(pluginName string) error {
}
func PropertySetupApp(pluginName string, appName string) error {
if err := PropertySetup(pluginName); err != nil {
return err
}
if err := makePluginAppPropertyPath(pluginName, appName); err != nil {
return fmt.Errorf("Unable to create %s config directory for %s: %s", pluginName, appName, err.Error())
}

View File

@@ -5,3 +5,4 @@
/config-*
/config_sub
/post-*
/install

View File

@@ -1,6 +1,6 @@
GOARCH ?= amd64
SUBCOMMANDS = subcommands/bundle subcommands/clear subcommands/export subcommands/get subcommands/import subcommands/keys subcommands/show subcommands/set subcommands/unset
TRIGGERS = triggers/config-export triggers/config-get triggers/config-get-global triggers/config-set triggers/config-unset triggers/post-app-clone-setup triggers/post-app-rename-setup
TRIGGERS = triggers/config-export triggers/config-get triggers/config-get-global triggers/install triggers/config-set triggers/config-unset triggers/post-app-clone-setup triggers/post-app-rename-setup triggers/post-create triggers/post-delete
BUILD = commands config_sub subcommands triggers
PLUGIN_NAME = config

View File

@@ -2,6 +2,7 @@ package config
import (
"os"
"path/filepath"
"strings"
"testing"
@@ -13,8 +14,10 @@ import (
var (
testAppName = "test-app-1"
dokkuRoot = common.MustGetEnv("DOKKU_ROOT")
testAppDir = strings.Join([]string{dokkuRoot, testAppName}, "/")
globalConfigFile = strings.Join([]string{dokkuRoot, "ENV"}, "/")
dokkuLibRoot = common.MustGetEnv("DOKKU_LIB_ROOT")
testAppRoot = filepath.Join(dokkuRoot, testAppName)
testAppDir = filepath.Join(dokkuLibRoot, "config", testAppName)
globalConfigFile = filepath.Join(dokkuLibRoot, "config", "--global", "ENV")
)
func setupTests() (err error) {
@@ -26,12 +29,14 @@ func setupTests() (err error) {
}
func setupTestApp() (err error) {
Expect(os.MkdirAll(testAppRoot, 0766)).To(Succeed())
Expect(os.MkdirAll(testAppDir, 0766)).To(Succeed())
b := []byte("export testKey=TESTING\n")
if err = os.WriteFile(strings.Join([]string{testAppDir, "/ENV"}, ""), b, 0644); err != nil {
return
}
Expect(os.MkdirAll(filepath.Dir(globalConfigFile), 0766)).To(Succeed())
b = []byte("export testKey=GLOBAL_TESTING\nexport globalKey=GLOBAL_VALUE")
if err = os.WriteFile(globalConfigFile, b, 0644); err != nil {
return
@@ -40,6 +45,7 @@ func setupTestApp() (err error) {
}
func teardownTestApp() {
os.RemoveAll(testAppRoot)
os.RemoveAll(testAppDir)
}

View File

@@ -392,9 +392,9 @@ func loadFromFileJSON(name string, filename string) (env *Env, err error) {
}, nil
}
func getAppFile(appName string) (string, error) {
return filepath.Join(common.MustGetEnv("DOKKU_ROOT"), appName, "ENV"), nil
return filepath.Join(common.MustGetEnv("DOKKU_LIB_ROOT"), "config", appName, "ENV"), nil
}
func getGlobalFile() string {
return filepath.Join(common.MustGetEnv("DOKKU_ROOT"), "ENV")
return filepath.Join(common.MustGetEnv("DOKKU_LIB_ROOT"), "config", "--global", "ENV")
}

View File

@@ -51,6 +51,8 @@ func main() {
restart = flag.Arg(1)
}
err = config.TriggerConfigUnset(appName, key, common.ToBool(restart))
case "install":
err = config.TriggerInstall()
case "post-app-clone-setup":
oldAppName := flag.Arg(0)
newAppName := flag.Arg(1)
@@ -59,6 +61,12 @@ func main() {
oldAppName := flag.Arg(0)
newAppName := flag.Arg(1)
err = config.TriggerPostAppRenameSetup(oldAppName, newAppName)
case "post-create":
appName := flag.Arg(0)
err = config.TriggerPostCreate(appName)
case "post-delete":
appName := flag.Arg(0)
err = config.TriggerPostDelete(appName)
default:
err = fmt.Errorf("Invalid plugin trigger call: %s", trigger)
}

View File

@@ -2,7 +2,11 @@ package config
import (
"fmt"
"os"
"path/filepath"
"strconv"
"github.com/dokku/dokku/plugins/common"
)
// TriggerConfigExport returns a global config value by key
@@ -56,6 +60,130 @@ func TriggerConfigUnset(appName string, key string, restart bool) error {
return nil
}
func setupAppConfigDir(appName string) error {
appFile, err := getAppFile(appName)
if err != nil {
return err
}
appConfigDir := filepath.Dir(appFile)
if err := os.MkdirAll(appConfigDir, 0755); err != nil {
return err
}
return common.SetPermissions(common.SetPermissionInput{
Filename: appConfigDir,
Mode: os.FileMode(0755),
})
}
func migrateGlobalEnv() error {
if err := common.PropertySetup("--global"); err != nil {
return fmt.Errorf("Unable to setup global environment: %s", err.Error())
}
oldGlobalEnvFile := filepath.Join(common.MustGetEnv("DOKKU_ROOT"), "ENV")
isGlobalMigrated := common.PropertyGetDefault("config", "--global", "env-migrated", "")
if isGlobalMigrated == "true" {
return nil
}
oldGlobalEnv, err := loadFromFile("--global", oldGlobalEnvFile)
if err != nil {
return fmt.Errorf("Unable to load old global environment: %s", err.Error())
}
globalEnv, err := LoadGlobalEnv()
if err != nil {
return fmt.Errorf("Unable to load global environment: %s", err.Error())
}
globalEnv.Merge(oldGlobalEnv)
if err := globalEnv.Write(); err != nil {
return fmt.Errorf("Unable to write global environment: %s", err.Error())
}
if err := common.SetPermissions(common.SetPermissionInput{
Filename: globalEnv.Filename(),
Mode: os.FileMode(0600),
}); err != nil {
return fmt.Errorf("Unable to set permissions on global environment: %s", err.Error())
}
if err := common.PropertyWrite("config", "--global", "env-migrated", "true"); err != nil {
return fmt.Errorf("Unable to set env-migrated property: %s", err.Error())
}
return nil
}
// TriggerInstall runs the install step for the config plugin
func TriggerInstall() error {
if err := common.PropertySetup("config"); err != nil {
return fmt.Errorf("Unable to install the config plugin: %s", err.Error())
}
if err := migrateGlobalEnv(); err != nil {
return fmt.Errorf("Unable to migrate global environment: %s", err.Error())
}
apps, err := common.UnfilteredDokkuApps()
if err != nil {
return nil
}
// migrate all app ENV files to config path
for _, appName := range apps {
if err := common.PropertySetupApp("config", appName); err != nil {
return fmt.Errorf("Unable to setup app environment: %s", err.Error())
}
if err := setupAppConfigDir(appName); err != nil {
return fmt.Errorf("Unable to setup app config directory: %s", err.Error())
}
oldEnvFile := filepath.Join(common.AppRoot(appName), "ENV")
isMigrated := common.PropertyGetDefault("config", appName, "env-migrated", "")
// delete the old file on the next install
if isMigrated == "true" {
if err := os.RemoveAll(oldEnvFile); err != nil {
return fmt.Errorf("Unable to remove old ENV file: %s", err.Error())
}
continue
}
// skip if the file doesn't exist
if _, err := os.Stat(oldEnvFile); err != nil {
if err := common.PropertyWrite("config", appName, "env-migrated", "true"); err != nil {
return fmt.Errorf("Unable to set env-migrated property: %s", err.Error())
}
continue
}
// merge in the old env into the new env
oldEnv, err := loadFromFile(appName, oldEnvFile)
if err != nil {
return fmt.Errorf("Unable to load old environment: %s", err.Error())
}
env, err := LoadAppEnv(appName)
if err != nil {
return fmt.Errorf("Unable to load app environment: %s", err.Error())
}
env.Merge(oldEnv)
if err := env.Write(); err != nil {
return fmt.Errorf("Unable to write app environment: %s", err.Error())
}
if err := common.PropertyWrite("config", appName, "env-migrated", "true"); err != nil {
return fmt.Errorf("Unable to set env-migrated property: %s", err.Error())
}
}
return nil
}
// TriggerPostAppCloneSetup creates new buildpacks files
func TriggerPostAppCloneSetup(oldAppName string, newAppName string) error {
oldEnv, err := LoadAppEnv(oldAppName)
@@ -95,3 +223,22 @@ func TriggerPostAppRenameSetup(oldAppName string, newAppName string) error {
return nil
}
// TriggerPostCreate ensures apps have the correct config structure
func TriggerPostCreate(appName string) error {
if err := common.PropertySetupApp("config", appName); err != nil {
return err
}
return setupAppConfigDir(appName)
}
// TriggerPostDelete destroys the config data for a given app container
func TriggerPostDelete(appName string) error {
appFile, err := getAppFile(appName)
if err == nil {
os.RemoveAll(filepath.Dir(appFile))
}
return common.PropertyDestroy("config", appName)
}