Files
dokku/plugins/config/config.go
2025-11-08 01:02:19 -05:00

204 lines
5.0 KiB
Go

package config
import (
"fmt"
"os"
"regexp"
"github.com/dokku/dokku/plugins/common"
)
// Get retrieves a value from a config. If appName is empty the global config is used.
func Get(appName string, key string) (value string, ok bool) {
env, err := loadAppOrGlobalEnv(appName)
if err != nil {
return "", false
}
if err = validateKey(key); err != nil {
return "", false
}
return env.Get(key)
}
// GetWithDefault gets a value from a config. If appName is empty the global config is used. If the appName or key do not exist defaultValue is returned.
func GetWithDefault(appName string, key string, defaultValue string) (value string) {
value, ok := Get(appName, key)
if !ok {
return defaultValue
}
return value
}
// SetMany variables in the environment. If appName is empty the global config is used. If restart is true the app is restarted.
func SetMany(appName string, entries map[string]string, replace bool, restart bool) (err error) {
global := appName == "" || appName == "--global"
env, err := loadAppOrGlobalEnv(appName)
if err != nil {
return
}
keys := make([]string, 0, len(entries))
for k := range entries {
if err = validateKey(k); err != nil {
return
}
}
if replace {
env.Clear()
}
for k, v := range entries {
env.Set(k, v)
keys = append(keys, k)
}
if len(entries) != 0 {
common.LogInfo1Quiet("Setting config vars")
if os.Getenv("DOKKU_QUIET_OUTPUT") == "" {
fmt.Println(prettyPrintEnvEntries(" ", entries))
}
env.Write()
common.SetPermissions(common.SetPermissionInput{
Filename: env.Filename(),
Mode: os.FileMode(0600),
})
triggerUpdate(appName, "set", keys)
}
if !global && restart && env.GetBoolDefault("DOKKU_APP_RESTORE", true) {
triggerRestart(appName)
}
return
}
// UnsetMany a value in a config. If appName is empty the global config is used. If restart is true the app is restarted.
func UnsetMany(appName string, keys []string, restart bool) (err error) {
global := appName == "" || appName == "--global"
env, err := loadAppOrGlobalEnv(appName)
if err != nil {
return
}
var changed = false
for _, k := range keys {
if err = validateKey(k); err != nil {
return
}
}
for _, k := range keys {
if _, hasKey := env.Map()[k]; hasKey {
common.LogInfo1Quiet(fmt.Sprintf("Unsetting %s", k))
env.Unset(k)
changed = true
} else {
common.LogInfo1Quiet(fmt.Sprintf("Skipping %s, it is not set in the environment", k))
}
}
if changed {
env.Write()
common.SetPermissions(common.SetPermissionInput{
Filename: env.Filename(),
Mode: os.FileMode(0600),
})
triggerUpdate(appName, "unset", keys)
}
if !global && restart && env.GetBoolDefault("DOKKU_APP_RESTORE", true) {
triggerRestart(appName)
}
return
}
// UnsetAll removes all config keys
func UnsetAll(appName string, restart bool) (err error) {
global := appName == "" || appName == "--global"
env, err := loadAppOrGlobalEnv(appName)
if err != nil {
return
}
var changed = false
for k := range env.Map() {
common.LogInfo1Quiet(fmt.Sprintf("Unsetting %s", k))
env.Unset(k)
changed = true
}
if changed {
env.Write()
common.SetPermissions(common.SetPermissionInput{
Filename: env.Filename(),
Mode: os.FileMode(0600),
})
triggerUpdate(appName, "clear", []string{})
}
if !global && restart && env.GetBoolDefault("DOKKU_APP_RESTORE", true) {
triggerRestart(appName)
}
return
}
func triggerRestart(appName string) {
if !common.IsDeployed(appName) {
return
}
common.LogInfo1(fmt.Sprintf("Restarting app %s", appName))
_, err := common.CallPlugnTrigger(common.PlugnTriggerInput{
Trigger: "release-and-deploy",
Args: []string{appName},
StreamStdio: true,
})
if err != nil {
common.LogWarn(fmt.Sprintf("Failure while restarting app: %s", err))
}
}
func triggerUpdate(appName string, operation string, args []string) {
args = append([]string{appName, operation}, args...)
_, err := common.CallPlugnTrigger(common.PlugnTriggerInput{
Trigger: "post-config-update",
Args: args,
StreamStdio: true,
})
if err != nil {
common.LogWarn(fmt.Sprintf("Failure while triggering post-config-update: %s", err))
}
}
// getEnvironment for the given app (global config if appName is empty). Merge with global environment if merged is true.
func getEnvironment(appName string, merged bool) (env *Env) {
var err error
if appName != "" && merged {
env, err = LoadMergedAppEnv(appName)
} else {
env, err = loadAppOrGlobalEnv(appName)
}
if err != nil {
common.LogFailWithError(err)
}
return env
}
func getAppNameOrGlobal(appName string, global bool) (string, error) {
if global {
return appName, nil
}
if err := common.VerifyAppName(appName); err != nil {
return appName, err
}
return appName, nil
}
func loadAppOrGlobalEnv(appName string) (env *Env, err error) {
if appName == "" || appName == "--global" {
return LoadGlobalEnv()
}
return LoadAppEnv(appName)
}
func validateKey(key string) error {
r, _ := regexp.Compile("^[a-zA-Z_][a-zA-Z0-9_]*$")
if !r.MatchString(key) {
return fmt.Errorf("Invalid key name: '%s'", key)
}
return nil
}