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 && shouldRestart(appName) { 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 && shouldRestart(appName) { 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 && shouldRestart(appName) { triggerRestart(appName) } return } func shouldRestart(appName string) bool { results, _ := common.CallPlugnTrigger(common.PlugnTriggerInput{ Trigger: "ps-get-property", Args: []string{appName, "restore"}, }) return results.StdoutContents() != "false" } 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, "", "config-redeploy"}, 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 }