mirror of
https://github.com/dokku/dokku.git
synced 2025-12-29 00:25:08 +01:00
Merge pull request #5183 from dokku/user-access-to-app
Filter apps when verifying app names
This commit is contained in:
@@ -581,6 +581,11 @@ func VerifyAppName(appName string) error {
|
||||
return &AppDoesNotExist{appName}
|
||||
}
|
||||
|
||||
apps, _ := filterApps([]string{appName})
|
||||
if len(apps) != 1 {
|
||||
return &AppDoesNotExist{appName}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,10 @@ var (
|
||||
testEnvLine2 = "export testKey=TESTING"
|
||||
)
|
||||
|
||||
func setupTests() (err error) {
|
||||
return os.Setenv("PLUGIN_ENABLED_PATH", "/var/lib/dokku/plugins/enabled")
|
||||
}
|
||||
|
||||
func setupTestApp() (err error) {
|
||||
Expect(os.MkdirAll(testAppDir, 0644)).To(Succeed())
|
||||
b := []byte(testEnvLine + "\n")
|
||||
@@ -48,32 +52,37 @@ func teardownTestApp2() {
|
||||
|
||||
func TestCommonGetEnv(t *testing.T) {
|
||||
RegisterTestingT(t)
|
||||
Expect(setupTests()).To(Succeed())
|
||||
Expect(MustGetEnv("DOKKU_ROOT")).To(Equal("/home/dokku"))
|
||||
}
|
||||
|
||||
func TestCommonGetAppImageRepo(t *testing.T) {
|
||||
RegisterTestingT(t)
|
||||
Expect(setupTests()).To(Succeed())
|
||||
Expect(GetAppImageRepo("testapp")).To(Equal("dokku/testapp"))
|
||||
}
|
||||
|
||||
func TestCommonVerifyImageInvalid(t *testing.T) {
|
||||
RegisterTestingT(t)
|
||||
Expect(setupTests()).To(Succeed())
|
||||
Expect(VerifyImage("testapp")).To(Equal(false))
|
||||
}
|
||||
|
||||
func TestCommonVerifyAppNameInvalid(t *testing.T) {
|
||||
RegisterTestingT(t)
|
||||
err := VerifyAppName("1994testApp")
|
||||
Expect(err).To(HaveOccurred())
|
||||
Expect(setupTests()).To(Succeed())
|
||||
Expect(VerifyAppName("1994testApp")).To(HaveOccurred())
|
||||
}
|
||||
|
||||
func TestCommonVerifyAppName(t *testing.T) {
|
||||
RegisterTestingT(t)
|
||||
Expect(setupTests()).To(Succeed())
|
||||
Expect(setupTestApp()).To(Succeed())
|
||||
Expect(VerifyAppName(testAppName)).To(Succeed())
|
||||
teardownTestApp()
|
||||
|
||||
RegisterTestingT(t)
|
||||
Expect(setupTests()).To(Succeed())
|
||||
Expect(setupTestApp2()).To(Succeed())
|
||||
Expect(VerifyAppName(testAppName2)).To(Succeed())
|
||||
teardownTestApp2()
|
||||
@@ -81,13 +90,14 @@ func TestCommonVerifyAppName(t *testing.T) {
|
||||
|
||||
func TestCommonDokkuAppsError(t *testing.T) {
|
||||
RegisterTestingT(t)
|
||||
Expect(setupTests()).To(Succeed())
|
||||
_, err := DokkuApps()
|
||||
Expect(err).To(HaveOccurred())
|
||||
}
|
||||
|
||||
func TestCommonDokkuApps(t *testing.T) {
|
||||
RegisterTestingT(t)
|
||||
os.Setenv("PLUGIN_ENABLED_PATH", "/var/lib/dokku/plugins/enabled")
|
||||
Expect(setupTests()).To(Succeed())
|
||||
Expect(setupTestApp()).To(Succeed())
|
||||
apps, err := DokkuApps()
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
@@ -98,6 +108,7 @@ func TestCommonDokkuApps(t *testing.T) {
|
||||
|
||||
func TestCommonStripInlineComments(t *testing.T) {
|
||||
RegisterTestingT(t)
|
||||
Expect(setupTests()).To(Succeed())
|
||||
text := StripInlineComments(strings.Join([]string{testEnvLine, "# testing comment"}, " "))
|
||||
Expect(text).To(Equal(testEnvLine))
|
||||
}
|
||||
|
||||
@@ -250,23 +250,12 @@ is_valid_app_name_old() {
|
||||
verify_app_name() {
|
||||
declare desc="verify app name format and app existence"
|
||||
declare APP="$1"
|
||||
local VALID_NEW=false
|
||||
local VALID_OLD=false
|
||||
if fn-is-valid-app-name "$APP" 2>/dev/null; then
|
||||
VALID_NEW=true
|
||||
|
||||
if "$PLUGIN_CORE_AVAILABLE_PATH/common/common" --quiet verify-app-name "$APP"; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
if fn-is-valid-app-name-old "$APP" 2>/dev/null; then
|
||||
VALID_OLD=true
|
||||
fi
|
||||
|
||||
if [[ "$VALID_NEW" == "false" ]] && [[ "$VALID_OLD" == "false" ]]; then
|
||||
dokku_log_fail "App name must begin with lowercase alphanumeric character, and cannot include uppercase characters, colons, or underscores"
|
||||
fi
|
||||
|
||||
[[ ! -d "$DOKKU_ROOT/$APP" ]] && DOKKU_FAIL_EXIT_CODE=20 dokku_log_fail "App $APP does not exist"
|
||||
|
||||
return 0
|
||||
DOKKU_FAIL_EXIT_CODE=20 dokku_log_fail "App $APP does not exist"
|
||||
}
|
||||
|
||||
verify_image() {
|
||||
|
||||
@@ -61,6 +61,19 @@ func LogFailWithError(err error) {
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// LogFailWithErrorQuiet is the failure log formatter (with quiet option)
|
||||
// prints text to stderr and exits with the specified exit code
|
||||
// The error message is not printed if DOKKU_QUIET_OUTPUT has any value
|
||||
func LogFailWithErrorQuiet(err error) {
|
||||
if os.Getenv("DOKKU_QUIET_OUTPUT") == "" {
|
||||
fmt.Fprintln(os.Stderr, fmt.Sprintf(" ! %s", err.Error()))
|
||||
}
|
||||
if errExit, ok := err.(ErrWithExitCode); ok {
|
||||
os.Exit(errExit.ExitCode())
|
||||
}
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// LogFailQuiet is the failure log formatter (with quiet option)
|
||||
// prints text to stderr and exits with status 1
|
||||
func LogFailQuiet(text string) {
|
||||
|
||||
@@ -38,11 +38,14 @@ func main() {
|
||||
appName = "--global"
|
||||
}
|
||||
fmt.Print(common.GetAppScheduler(appName))
|
||||
case "verify-app-name":
|
||||
appName := flag.Arg(1)
|
||||
err = common.VerifyAppName(appName)
|
||||
default:
|
||||
err = fmt.Errorf("Invalid common command call: %v", cmd)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
common.LogFailQuiet(err.Error())
|
||||
common.LogFailWithErrorQuiet(err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
SUBCOMMANDS = subcommands/bundle subcommands/clear subcommands/export subcommands/get subcommands/keys subcommands/show subcommands/set subcommands/unset
|
||||
TRIGGERS = triggers/config-export triggers/config-get triggers/config-get-global
|
||||
BUILD = commands subcommands triggers
|
||||
BUILD = commands config_sub subcommands triggers
|
||||
PLUGIN_NAME = config
|
||||
|
||||
clean-config_sub:
|
||||
rm -rf config_sub
|
||||
|
||||
config_sub: clean-config_sub **/**/config_sub.go
|
||||
go build -ldflags="-s -w" $(GO_ARGS) -o config_sub src/config_sub/config_sub.go
|
||||
|
||||
include ../../common.mk
|
||||
|
||||
@@ -18,6 +18,10 @@ var (
|
||||
globalConfigFile = strings.Join([]string{dokkuRoot, "ENV"}, "/")
|
||||
)
|
||||
|
||||
func setupTests() (err error) {
|
||||
return os.Setenv("PLUGIN_ENABLED_PATH", "/var/lib/dokku/plugins/enabled")
|
||||
}
|
||||
|
||||
func setupTestApp() (err error) {
|
||||
Expect(os.MkdirAll(testAppDir, 0766)).To(Succeed())
|
||||
b := []byte("export testKey=TESTING\n")
|
||||
@@ -38,6 +42,7 @@ func teardownTestApp() {
|
||||
|
||||
func TestConfigGetWithDefault(t *testing.T) {
|
||||
RegisterTestingT(t)
|
||||
Expect(setupTests()).To(Succeed())
|
||||
Expect(setupTestApp()).To(Succeed())
|
||||
Expect(GetWithDefault(testAppName, "unknownKey", "UNKNOWN")).To(Equal("UNKNOWN"))
|
||||
Expect(GetWithDefault(testAppName, "testKey", "testKey")).To(Equal("TESTING"))
|
||||
@@ -47,6 +52,7 @@ func TestConfigGetWithDefault(t *testing.T) {
|
||||
|
||||
func TestConfigGet(t *testing.T) {
|
||||
RegisterTestingT(t)
|
||||
Expect(setupTests()).To(Succeed())
|
||||
Expect(setupTestApp()).To(Succeed())
|
||||
defer teardownTestApp()
|
||||
|
||||
@@ -59,45 +65,48 @@ func TestConfigGet(t *testing.T) {
|
||||
|
||||
func TestConfigSetMany(t *testing.T) {
|
||||
RegisterTestingT(t)
|
||||
Expect(setupTests()).To(Succeed())
|
||||
Expect(setupTestApp()).To(Succeed())
|
||||
defer teardownTestApp()
|
||||
|
||||
expectValue(testAppName, "testKey", "TESTING")
|
||||
|
||||
vals := map[string]string{"testKey": "updated", "testKey2": "new"}
|
||||
Expect(SetMany(testAppName, vals, false)).To(Succeed())
|
||||
vals := []string{"testKey=updated", "testKey2=new"}
|
||||
Expect(CommandSet(testAppName, vals, false, true, false)).To(Succeed())
|
||||
expectValue(testAppName, "testKey", "updated")
|
||||
expectValue(testAppName, "testKey2", "new")
|
||||
|
||||
vals = map[string]string{"testKey": "updated_global", "testKey2": "new_global"}
|
||||
Expect(SetMany("", vals, false)).To(Succeed())
|
||||
vals = []string{"testKey=updated_global", "testKey2=new_global"}
|
||||
Expect(CommandSet("", vals, true, true, false)).To(Succeed())
|
||||
expectValue("", "testKey", "updated_global")
|
||||
expectValue("", "testKey2", "new_global")
|
||||
expectValue("", "globalKey", "GLOBAL_VALUE")
|
||||
expectValue(testAppName, "testKey", "updated")
|
||||
expectValue(testAppName, "testKey2", "new")
|
||||
|
||||
Expect(SetMany(testAppName+"does_not_exist", vals, false)).ToNot(Succeed())
|
||||
Expect(CommandSet(testAppName+"does_not_exist", vals, false, true, false)).ToNot(Succeed())
|
||||
}
|
||||
|
||||
func TestConfigUnsetAll(t *testing.T) {
|
||||
RegisterTestingT(t)
|
||||
Expect(setupTests()).To(Succeed())
|
||||
Expect(setupTestApp()).To(Succeed())
|
||||
defer teardownTestApp()
|
||||
|
||||
expectValue(testAppName, "testKey", "TESTING")
|
||||
expectValue("", "testKey", "GLOBAL_TESTING")
|
||||
|
||||
Expect(UnsetAll(testAppName, false)).To(Succeed())
|
||||
Expect(CommandClear(testAppName, false, true)).To(Succeed())
|
||||
expectNoValue(testAppName, "testKey")
|
||||
expectNoValue(testAppName, "noKey")
|
||||
expectNoValue(testAppName, "globalKey")
|
||||
|
||||
Expect(UnsetAll(testAppName+"does-not-exist", false)).ToNot(Succeed())
|
||||
Expect(CommandClear(testAppName+"does-not-exist", false, true)).ToNot(Succeed())
|
||||
}
|
||||
|
||||
func TestConfigUnsetMany(t *testing.T) {
|
||||
RegisterTestingT(t)
|
||||
Expect(setupTests()).To(Succeed())
|
||||
Expect(setupTestApp()).To(Succeed())
|
||||
defer teardownTestApp()
|
||||
|
||||
@@ -105,19 +114,20 @@ func TestConfigUnsetMany(t *testing.T) {
|
||||
expectValue("", "testKey", "GLOBAL_TESTING")
|
||||
|
||||
keys := []string{"testKey", "noKey"}
|
||||
Expect(UnsetMany(testAppName, keys, false)).To(Succeed())
|
||||
Expect(CommandUnset(testAppName, keys, false, true)).To(Succeed())
|
||||
expectNoValue(testAppName, "testKey")
|
||||
expectValue("", "testKey", "GLOBAL_TESTING")
|
||||
|
||||
Expect(UnsetMany(testAppName, keys, false)).To(Succeed())
|
||||
Expect(CommandUnset(testAppName, keys, false, true)).To(Succeed())
|
||||
expectNoValue(testAppName, "testKey")
|
||||
expectNoValue(testAppName, "globalKey")
|
||||
|
||||
Expect(UnsetMany(testAppName+"does-not-exist", keys, false)).ToNot(Succeed())
|
||||
Expect(CommandUnset(testAppName+"does-not-exist", keys, false, true)).ToNot(Succeed())
|
||||
}
|
||||
|
||||
func TestEnvironmentLoading(t *testing.T) {
|
||||
RegisterTestingT(t)
|
||||
Expect(setupTests()).To(Succeed())
|
||||
Expect(setupTestApp()).To(Succeed())
|
||||
defer teardownTestApp()
|
||||
|
||||
@@ -142,6 +152,7 @@ func TestEnvironmentLoading(t *testing.T) {
|
||||
|
||||
func TestInvalidKeys(t *testing.T) {
|
||||
RegisterTestingT(t)
|
||||
Expect(setupTests()).To(Succeed())
|
||||
Expect(setupTestApp()).To(Succeed())
|
||||
defer teardownTestApp()
|
||||
|
||||
@@ -158,6 +169,7 @@ func TestInvalidKeys(t *testing.T) {
|
||||
|
||||
func TestInvalidEnvOnDisk(t *testing.T) {
|
||||
RegisterTestingT(t)
|
||||
Expect(setupTests()).To(Succeed())
|
||||
Expect(setupTestApp()).To(Succeed())
|
||||
defer teardownTestApp()
|
||||
|
||||
|
||||
@@ -60,10 +60,6 @@ func newEnvFromString(rep string) (env *Env, err error) {
|
||||
|
||||
//LoadAppEnv loads an environment for the given app
|
||||
func LoadAppEnv(appName string) (env *Env, err error) {
|
||||
err = common.VerifyAppName(appName)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
appfile, err := getAppFile(appName)
|
||||
if err != nil {
|
||||
return
|
||||
@@ -357,10 +353,6 @@ func loadFromFile(name string, filename string) (env *Env, err error) {
|
||||
}
|
||||
|
||||
func getAppFile(appName string) (string, error) {
|
||||
err := common.VerifyAppName(appName)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return filepath.Join(common.MustGetEnv("DOKKU_ROOT"), appName, "ENV"), nil
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ config_sub() {
|
||||
declare desc="executes a config subcommand"
|
||||
local name="$1"
|
||||
shift
|
||||
"$PLUGIN_AVAILABLE_PATH/config/subcommands/$name" "config:$name" "$@"
|
||||
"$PLUGIN_AVAILABLE_PATH/config/config_sub" "$name" "$@"
|
||||
}
|
||||
|
||||
config_export() {
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
package config
|
||||
|
||||
import "fmt"
|
||||
import (
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
func export(appName string, global bool, merged bool, format string) error {
|
||||
appName, err := getAppNameOrGlobal(appName, global)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
"github.com/dokku/dokku/plugins/common"
|
||||
)
|
||||
|
||||
func export(appName string, merged bool, format string) error {
|
||||
env := getEnvironment(appName, merged)
|
||||
exportType := ExportFormatExports
|
||||
suffix := "\n"
|
||||
@@ -37,3 +40,113 @@ func export(appName string, global bool, merged bool, format string) error {
|
||||
fmt.Print(exported + suffix)
|
||||
return nil
|
||||
}
|
||||
|
||||
// SubBundle implements the logic for config:bundle without app name validation
|
||||
func SubBundle(appName string, merged bool) error {
|
||||
env := getEnvironment(appName, merged)
|
||||
return env.ExportBundle(os.Stdout)
|
||||
}
|
||||
|
||||
// SubClear implements the logic for config:clear without app name validation
|
||||
func SubClear(appName string, noRestart bool) error {
|
||||
return UnsetAll(appName, !noRestart)
|
||||
}
|
||||
|
||||
// SubExport implements the logic for config:export without app name validation
|
||||
func SubExport(appName string, merged bool, format string) error {
|
||||
return export(appName, merged, format)
|
||||
}
|
||||
|
||||
// SubGet implements the logic for config:get without app name validation
|
||||
func SubGet(appName string, keys []string, quoted bool) error {
|
||||
if len(keys) == 0 {
|
||||
return errors.New("Expected: key")
|
||||
}
|
||||
|
||||
if len(keys) != 1 {
|
||||
return fmt.Errorf("Unexpected argument(s): %v", keys[1:])
|
||||
}
|
||||
|
||||
value, ok := Get(appName, keys[0])
|
||||
if !ok {
|
||||
os.Exit(1)
|
||||
return nil
|
||||
}
|
||||
|
||||
if quoted {
|
||||
fmt.Printf("'%s'\n", singleQuoteEscape(value))
|
||||
} else {
|
||||
fmt.Printf("%s\n", value)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SubKeys implements the logic for config:keys without app name validation
|
||||
func SubKeys(appName string, merged bool) error {
|
||||
env := getEnvironment(appName, merged)
|
||||
for _, k := range env.Keys() {
|
||||
fmt.Println(k)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SubSet implements the logic for config:set without app name validation
|
||||
func SubSet(appName string, pairs []string, noRestart bool, encoded bool) error {
|
||||
if len(pairs) == 0 {
|
||||
return errors.New("At least one env pair must be given")
|
||||
}
|
||||
|
||||
updated := make(map[string]string)
|
||||
for _, e := range pairs {
|
||||
parts := strings.SplitN(e, "=", 2)
|
||||
if len(parts) == 1 {
|
||||
return fmt.Errorf("Invalid env pair: %v", e)
|
||||
}
|
||||
|
||||
key, value := parts[0], parts[1]
|
||||
if encoded {
|
||||
decoded, err := base64.StdEncoding.DecodeString(value)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s for key '%s'", err.Error(), key)
|
||||
}
|
||||
value = string(decoded)
|
||||
}
|
||||
updated[key] = value
|
||||
}
|
||||
|
||||
return SetMany(appName, updated, !noRestart)
|
||||
}
|
||||
|
||||
// SubShow implements the logic for config:show without app name validation
|
||||
func SubShow(appName string, merged bool, shell bool, export bool) error {
|
||||
env := getEnvironment(appName, merged)
|
||||
if shell && export {
|
||||
return errors.New("Only one of --shell and --export can be given")
|
||||
}
|
||||
if shell {
|
||||
common.LogWarn("Deprecated: Use 'config:export --format shell' instead")
|
||||
fmt.Print(env.Export(ExportFormatShell))
|
||||
} else if export {
|
||||
common.LogWarn("Deprecated: Use 'config:export --format exports' instead")
|
||||
fmt.Println(env.Export(ExportFormatExports))
|
||||
} else {
|
||||
contextName := "global"
|
||||
if appName != "" {
|
||||
contextName = appName
|
||||
}
|
||||
common.LogInfo2Quiet(contextName + " env vars")
|
||||
fmt.Println(env.Export(ExportFormatPretty))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SubUnset implements the logic for config:unset without app name validation
|
||||
func SubUnset(appName string, keys []string, noRestart bool) error {
|
||||
if len(keys) == 0 {
|
||||
return fmt.Errorf("At least one key must be given")
|
||||
}
|
||||
|
||||
return UnsetMany(appName, keys, !noRestart)
|
||||
}
|
||||
|
||||
112
plugins/config/src/config_sub/config_sub.go
Normal file
112
plugins/config/src/config_sub/config_sub.go
Normal file
@@ -0,0 +1,112 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/dokku/dokku/plugins/common"
|
||||
"github.com/dokku/dokku/plugins/config"
|
||||
|
||||
flag "github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
func getKeys(args []string, global bool) []string {
|
||||
keys := args
|
||||
if !global && len(keys) > 0 {
|
||||
keys = keys[1:]
|
||||
}
|
||||
return keys
|
||||
}
|
||||
|
||||
// main entrypoint to all subcommands
|
||||
func main() {
|
||||
action := os.Args[1]
|
||||
|
||||
var err error
|
||||
appName := "--global"
|
||||
switch action {
|
||||
case "bundle":
|
||||
args := flag.NewFlagSet("bundle", flag.ExitOnError)
|
||||
global := args.Bool("global", false, "--global: use the global environment")
|
||||
merged := args.Bool("merged", false, "--merged: merge app environment and global environment")
|
||||
args.Parse(os.Args[2:])
|
||||
if !*global {
|
||||
appName = args.Arg(0)
|
||||
}
|
||||
err = config.SubBundle(appName, *merged)
|
||||
case "clear":
|
||||
args := flag.NewFlagSet("clear", flag.ExitOnError)
|
||||
global := args.Bool("global", false, "--global: use the global environment")
|
||||
noRestart := args.Bool("no-restart", false, "--no-restart: no restart")
|
||||
args.Parse(os.Args[2:])
|
||||
if !*global {
|
||||
appName = args.Arg(0)
|
||||
}
|
||||
err = config.SubClear(appName, *noRestart)
|
||||
case "export":
|
||||
args := flag.NewFlagSet("export", flag.ExitOnError)
|
||||
global := args.Bool("global", false, "--global: use the global environment")
|
||||
merged := args.Bool("merged", false, "--merged: merge app environment and global environment")
|
||||
format := args.String("format", "exports", "--format: [ docker-args | docker-args-keys | exports | envfile | json | json-list | pack-keys | pretty | shell ] which format to export as)")
|
||||
args.Parse(os.Args[2:])
|
||||
if !*global {
|
||||
appName = args.Arg(0)
|
||||
}
|
||||
err = config.SubExport(appName, *merged, *format)
|
||||
case "get":
|
||||
args := flag.NewFlagSet("get", flag.ExitOnError)
|
||||
global := args.Bool("global", false, "--global: use the global environment")
|
||||
quoted := args.Bool("quoted", false, "--quoted: get the value quoted")
|
||||
args.Parse(os.Args[2:])
|
||||
if !*global {
|
||||
appName = args.Arg(0)
|
||||
}
|
||||
keys := getKeys(args.Args(), *global)
|
||||
err = config.SubGet(appName, keys, *quoted)
|
||||
case "keys":
|
||||
args := flag.NewFlagSet("keys", flag.ExitOnError)
|
||||
global := args.Bool("global", false, "--global: use the global environment")
|
||||
merged := args.Bool("merged", false, "--merged: merge app environment and global environment")
|
||||
args.Parse(os.Args[2:])
|
||||
if !*global {
|
||||
appName = args.Arg(0)
|
||||
}
|
||||
err = config.SubKeys(appName, *merged)
|
||||
case "show":
|
||||
args := flag.NewFlagSet("show", flag.ExitOnError)
|
||||
global := args.Bool("global", false, "--global: use the global environment")
|
||||
merged := args.Bool("merged", false, "--merged: display the app's environment merged with the global environment")
|
||||
args.Parse(os.Args[2:])
|
||||
if !*global {
|
||||
appName = args.Arg(0)
|
||||
}
|
||||
err = config.SubShow(appName, *merged, false, false)
|
||||
case "set":
|
||||
args := flag.NewFlagSet("set", flag.ExitOnError)
|
||||
global := args.Bool("global", false, "--global: use the global environment")
|
||||
encoded := args.Bool("encoded", false, "--encoded: interpret VALUEs as base64")
|
||||
noRestart := args.Bool("no-restart", false, "--no-restart: no restart")
|
||||
args.Parse(os.Args[2:])
|
||||
if !*global {
|
||||
appName = args.Arg(0)
|
||||
}
|
||||
pairs := getKeys(args.Args(), *global)
|
||||
err = config.SubSet(appName, pairs, *noRestart, *encoded)
|
||||
case "unset":
|
||||
args := flag.NewFlagSet("unset", flag.ExitOnError)
|
||||
global := args.Bool("global", false, "--global: use the global environment")
|
||||
noRestart := args.Bool("no-restart", false, "--no-restart: no restart")
|
||||
args.Parse(os.Args[2:])
|
||||
if !*global {
|
||||
appName = args.Arg(0)
|
||||
}
|
||||
keys := getKeys(args.Args(), *global)
|
||||
err = config.SubUnset(appName, keys, *noRestart)
|
||||
default:
|
||||
err = fmt.Errorf("Invalid plugin config_sub call: %s", action)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
common.LogFailWithError(err)
|
||||
}
|
||||
}
|
||||
@@ -1,156 +1,83 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/dokku/dokku/plugins/common"
|
||||
)
|
||||
|
||||
// CommandBundle implements config:bundle
|
||||
// CommandBundle creates a tarball of a .env.d directory
|
||||
// containing env vars for the app
|
||||
func CommandBundle(appName string, global bool, merged bool) error {
|
||||
appName, err := getAppNameOrGlobal(appName, global)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
env := getEnvironment(appName, merged)
|
||||
return env.ExportBundle(os.Stdout)
|
||||
return SubBundle(appName, merged)
|
||||
}
|
||||
|
||||
// CommandClear implements config:clear
|
||||
// CommandClear unsets all environment variables in use
|
||||
func CommandClear(appName string, global bool, noRestart bool) error {
|
||||
appName, err := getAppNameOrGlobal(appName, global)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return UnsetAll(appName, !noRestart)
|
||||
return SubClear(appName, noRestart)
|
||||
}
|
||||
|
||||
// CommandExport implements config:export
|
||||
// CommandExport outputs all env vars (merged or not, global or not)
|
||||
// in the specified format for consumption by other tools
|
||||
func CommandExport(appName string, global bool, merged bool, format string) error {
|
||||
return export(appName, global, merged, format)
|
||||
appName, err := getAppNameOrGlobal(appName, global)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return SubExport(appName, merged, format)
|
||||
}
|
||||
|
||||
// CommandGet implements config:get
|
||||
// CommandGet gets the value for the specified environment variable
|
||||
func CommandGet(appName string, keys []string, global bool, quoted bool) error {
|
||||
appName, err := getAppNameOrGlobal(appName, global)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(keys) == 0 {
|
||||
return errors.New("Expected: key")
|
||||
}
|
||||
|
||||
if len(keys) != 1 {
|
||||
return fmt.Errorf("Unexpected argument(s): %v", keys[1:])
|
||||
}
|
||||
|
||||
value, ok := Get(appName, keys[0])
|
||||
if !ok {
|
||||
os.Exit(1)
|
||||
return nil
|
||||
}
|
||||
|
||||
if quoted {
|
||||
fmt.Printf("'%s'\n", singleQuoteEscape(value))
|
||||
} else {
|
||||
fmt.Printf("%s\n", value)
|
||||
}
|
||||
|
||||
return nil
|
||||
return SubGet(appName, keys, quoted)
|
||||
}
|
||||
|
||||
// CommandKeys implements config:keys
|
||||
// CommandKeys shows the keys set for the specified environment
|
||||
func CommandKeys(appName string, global bool, merged bool) error {
|
||||
appName, err := getAppNameOrGlobal(appName, global)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
env := getEnvironment(appName, merged)
|
||||
for _, k := range env.Keys() {
|
||||
fmt.Println(k)
|
||||
}
|
||||
return nil
|
||||
return SubKeys(appName, merged)
|
||||
}
|
||||
|
||||
// CommandSet implements config:set
|
||||
// CommandSet sets one or more environment variable pairs
|
||||
func CommandSet(appName string, pairs []string, global bool, noRestart bool, encoded bool) error {
|
||||
appName, err := getAppNameOrGlobal(appName, global)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(pairs) == 0 {
|
||||
return errors.New("At least one env pair must be given")
|
||||
}
|
||||
|
||||
updated := make(map[string]string)
|
||||
for _, e := range pairs {
|
||||
parts := strings.SplitN(e, "=", 2)
|
||||
if len(parts) == 1 {
|
||||
return fmt.Errorf("Invalid env pair: %v", e)
|
||||
}
|
||||
|
||||
key, value := parts[0], parts[1]
|
||||
if encoded {
|
||||
decoded, err := base64.StdEncoding.DecodeString(value)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s for key '%s'", err.Error(), key)
|
||||
}
|
||||
value = string(decoded)
|
||||
}
|
||||
updated[key] = value
|
||||
}
|
||||
|
||||
return SetMany(appName, updated, !noRestart)
|
||||
return SubSet(appName, pairs, noRestart, encoded)
|
||||
}
|
||||
|
||||
// CommandShow implements config:show
|
||||
// CommandShow pretty-prints the specified environment vaiables
|
||||
func CommandShow(appName string, global bool, merged bool, shell bool, export bool) error {
|
||||
appName, err := getAppNameOrGlobal(appName, global)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
env := getEnvironment(appName, merged)
|
||||
if shell && export {
|
||||
return errors.New("Only one of --shell and --export can be given")
|
||||
}
|
||||
if shell {
|
||||
common.LogWarn("Deprecated: Use 'config:export --format shell' instead")
|
||||
fmt.Print(env.Export(ExportFormatShell))
|
||||
} else if export {
|
||||
common.LogWarn("Deprecated: Use 'config:export --format exports' instead")
|
||||
fmt.Println(env.Export(ExportFormatExports))
|
||||
} else {
|
||||
contextName := "global"
|
||||
if appName != "" {
|
||||
contextName = appName
|
||||
}
|
||||
common.LogInfo2Quiet(contextName + " env vars")
|
||||
fmt.Println(env.Export(ExportFormatPretty))
|
||||
}
|
||||
|
||||
return nil
|
||||
return SubShow(appName, merged, shell, export)
|
||||
}
|
||||
|
||||
// CommandUnset implements config:unset
|
||||
// CommandUnset unsets one or more keys in a specified environment
|
||||
func CommandUnset(appName string, keys []string, global bool, noRestart bool) error {
|
||||
appName, err := getAppNameOrGlobal(appName, global)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(keys) == 0 {
|
||||
return fmt.Errorf("At least one key must be given")
|
||||
}
|
||||
|
||||
return UnsetMany(appName, keys, !noRestart)
|
||||
return SubUnset(appName, keys, noRestart)
|
||||
}
|
||||
|
||||
@@ -16,7 +16,13 @@ func TriggerConfigExport(appName string, global string, merged string, format st
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return export(appName, g, m, format)
|
||||
|
||||
appName, err = getAppNameOrGlobal(appName, g)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return export(appName, m, format)
|
||||
}
|
||||
|
||||
// TriggerConfigGet returns an app config value by key
|
||||
|
||||
Reference in New Issue
Block a user