If an env file is written as a root user - for example, during plugin install - the permissions on the file may change to root. This forces those permissions back to what they should be so that the dokku user can edit the files later on. Closes #5190
177 lines
4.5 KiB
Go
177 lines
4.5 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, restart bool) (err error) {
|
|
global := appName == ""
|
|
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
|
|
}
|
|
}
|
|
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(env.Filename(), 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 == ""
|
|
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(env.Filename(), 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 == ""
|
|
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(env.Filename(), 0600)
|
|
triggerUpdate(appName, "clear", []string{})
|
|
}
|
|
if !global && restart && env.GetBoolDefault("DOKKU_APP_RESTORE", true) {
|
|
triggerRestart(appName)
|
|
}
|
|
return
|
|
}
|
|
|
|
func triggerRestart(appName string) {
|
|
common.LogInfo1(fmt.Sprintf("Restarting app %s", appName))
|
|
if err := common.PlugnTrigger("release-and-deploy", appName); 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...)
|
|
if err := common.PlugnTrigger("post-config-update", args...); 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
|
|
}
|