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}
|
return &AppDoesNotExist{appName}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
apps, _ := filterApps([]string{appName})
|
||||||
|
if len(apps) != 1 {
|
||||||
|
return &AppDoesNotExist{appName}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,10 @@ var (
|
|||||||
testEnvLine2 = "export testKey=TESTING"
|
testEnvLine2 = "export testKey=TESTING"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func setupTests() (err error) {
|
||||||
|
return os.Setenv("PLUGIN_ENABLED_PATH", "/var/lib/dokku/plugins/enabled")
|
||||||
|
}
|
||||||
|
|
||||||
func setupTestApp() (err error) {
|
func setupTestApp() (err error) {
|
||||||
Expect(os.MkdirAll(testAppDir, 0644)).To(Succeed())
|
Expect(os.MkdirAll(testAppDir, 0644)).To(Succeed())
|
||||||
b := []byte(testEnvLine + "\n")
|
b := []byte(testEnvLine + "\n")
|
||||||
@@ -48,32 +52,37 @@ func teardownTestApp2() {
|
|||||||
|
|
||||||
func TestCommonGetEnv(t *testing.T) {
|
func TestCommonGetEnv(t *testing.T) {
|
||||||
RegisterTestingT(t)
|
RegisterTestingT(t)
|
||||||
|
Expect(setupTests()).To(Succeed())
|
||||||
Expect(MustGetEnv("DOKKU_ROOT")).To(Equal("/home/dokku"))
|
Expect(MustGetEnv("DOKKU_ROOT")).To(Equal("/home/dokku"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCommonGetAppImageRepo(t *testing.T) {
|
func TestCommonGetAppImageRepo(t *testing.T) {
|
||||||
RegisterTestingT(t)
|
RegisterTestingT(t)
|
||||||
|
Expect(setupTests()).To(Succeed())
|
||||||
Expect(GetAppImageRepo("testapp")).To(Equal("dokku/testapp"))
|
Expect(GetAppImageRepo("testapp")).To(Equal("dokku/testapp"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCommonVerifyImageInvalid(t *testing.T) {
|
func TestCommonVerifyImageInvalid(t *testing.T) {
|
||||||
RegisterTestingT(t)
|
RegisterTestingT(t)
|
||||||
|
Expect(setupTests()).To(Succeed())
|
||||||
Expect(VerifyImage("testapp")).To(Equal(false))
|
Expect(VerifyImage("testapp")).To(Equal(false))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCommonVerifyAppNameInvalid(t *testing.T) {
|
func TestCommonVerifyAppNameInvalid(t *testing.T) {
|
||||||
RegisterTestingT(t)
|
RegisterTestingT(t)
|
||||||
err := VerifyAppName("1994testApp")
|
Expect(setupTests()).To(Succeed())
|
||||||
Expect(err).To(HaveOccurred())
|
Expect(VerifyAppName("1994testApp")).To(HaveOccurred())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCommonVerifyAppName(t *testing.T) {
|
func TestCommonVerifyAppName(t *testing.T) {
|
||||||
RegisterTestingT(t)
|
RegisterTestingT(t)
|
||||||
|
Expect(setupTests()).To(Succeed())
|
||||||
Expect(setupTestApp()).To(Succeed())
|
Expect(setupTestApp()).To(Succeed())
|
||||||
Expect(VerifyAppName(testAppName)).To(Succeed())
|
Expect(VerifyAppName(testAppName)).To(Succeed())
|
||||||
teardownTestApp()
|
teardownTestApp()
|
||||||
|
|
||||||
RegisterTestingT(t)
|
RegisterTestingT(t)
|
||||||
|
Expect(setupTests()).To(Succeed())
|
||||||
Expect(setupTestApp2()).To(Succeed())
|
Expect(setupTestApp2()).To(Succeed())
|
||||||
Expect(VerifyAppName(testAppName2)).To(Succeed())
|
Expect(VerifyAppName(testAppName2)).To(Succeed())
|
||||||
teardownTestApp2()
|
teardownTestApp2()
|
||||||
@@ -81,13 +90,14 @@ func TestCommonVerifyAppName(t *testing.T) {
|
|||||||
|
|
||||||
func TestCommonDokkuAppsError(t *testing.T) {
|
func TestCommonDokkuAppsError(t *testing.T) {
|
||||||
RegisterTestingT(t)
|
RegisterTestingT(t)
|
||||||
|
Expect(setupTests()).To(Succeed())
|
||||||
_, err := DokkuApps()
|
_, err := DokkuApps()
|
||||||
Expect(err).To(HaveOccurred())
|
Expect(err).To(HaveOccurred())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCommonDokkuApps(t *testing.T) {
|
func TestCommonDokkuApps(t *testing.T) {
|
||||||
RegisterTestingT(t)
|
RegisterTestingT(t)
|
||||||
os.Setenv("PLUGIN_ENABLED_PATH", "/var/lib/dokku/plugins/enabled")
|
Expect(setupTests()).To(Succeed())
|
||||||
Expect(setupTestApp()).To(Succeed())
|
Expect(setupTestApp()).To(Succeed())
|
||||||
apps, err := DokkuApps()
|
apps, err := DokkuApps()
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
@@ -98,6 +108,7 @@ func TestCommonDokkuApps(t *testing.T) {
|
|||||||
|
|
||||||
func TestCommonStripInlineComments(t *testing.T) {
|
func TestCommonStripInlineComments(t *testing.T) {
|
||||||
RegisterTestingT(t)
|
RegisterTestingT(t)
|
||||||
|
Expect(setupTests()).To(Succeed())
|
||||||
text := StripInlineComments(strings.Join([]string{testEnvLine, "# testing comment"}, " "))
|
text := StripInlineComments(strings.Join([]string{testEnvLine, "# testing comment"}, " "))
|
||||||
Expect(text).To(Equal(testEnvLine))
|
Expect(text).To(Equal(testEnvLine))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -250,23 +250,12 @@ is_valid_app_name_old() {
|
|||||||
verify_app_name() {
|
verify_app_name() {
|
||||||
declare desc="verify app name format and app existence"
|
declare desc="verify app name format and app existence"
|
||||||
declare APP="$1"
|
declare APP="$1"
|
||||||
local VALID_NEW=false
|
|
||||||
local VALID_OLD=false
|
if "$PLUGIN_CORE_AVAILABLE_PATH/common/common" --quiet verify-app-name "$APP"; then
|
||||||
if fn-is-valid-app-name "$APP" 2>/dev/null; then
|
return 0
|
||||||
VALID_NEW=true
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if fn-is-valid-app-name-old "$APP" 2>/dev/null; then
|
DOKKU_FAIL_EXIT_CODE=20 dokku_log_fail "App $APP does not exist"
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
verify_image() {
|
verify_image() {
|
||||||
|
|||||||
@@ -61,6 +61,19 @@ func LogFailWithError(err error) {
|
|||||||
os.Exit(1)
|
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)
|
// LogFailQuiet is the failure log formatter (with quiet option)
|
||||||
// prints text to stderr and exits with status 1
|
// prints text to stderr and exits with status 1
|
||||||
func LogFailQuiet(text string) {
|
func LogFailQuiet(text string) {
|
||||||
|
|||||||
@@ -38,11 +38,14 @@ func main() {
|
|||||||
appName = "--global"
|
appName = "--global"
|
||||||
}
|
}
|
||||||
fmt.Print(common.GetAppScheduler(appName))
|
fmt.Print(common.GetAppScheduler(appName))
|
||||||
|
case "verify-app-name":
|
||||||
|
appName := flag.Arg(1)
|
||||||
|
err = common.VerifyAppName(appName)
|
||||||
default:
|
default:
|
||||||
err = fmt.Errorf("Invalid common command call: %v", cmd)
|
err = fmt.Errorf("Invalid common command call: %v", cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
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
|
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
|
TRIGGERS = triggers/config-export triggers/config-get triggers/config-get-global
|
||||||
BUILD = commands subcommands triggers
|
BUILD = commands config_sub subcommands triggers
|
||||||
PLUGIN_NAME = config
|
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
|
include ../../common.mk
|
||||||
|
|||||||
@@ -18,6 +18,10 @@ var (
|
|||||||
globalConfigFile = strings.Join([]string{dokkuRoot, "ENV"}, "/")
|
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) {
|
func setupTestApp() (err error) {
|
||||||
Expect(os.MkdirAll(testAppDir, 0766)).To(Succeed())
|
Expect(os.MkdirAll(testAppDir, 0766)).To(Succeed())
|
||||||
b := []byte("export testKey=TESTING\n")
|
b := []byte("export testKey=TESTING\n")
|
||||||
@@ -38,6 +42,7 @@ func teardownTestApp() {
|
|||||||
|
|
||||||
func TestConfigGetWithDefault(t *testing.T) {
|
func TestConfigGetWithDefault(t *testing.T) {
|
||||||
RegisterTestingT(t)
|
RegisterTestingT(t)
|
||||||
|
Expect(setupTests()).To(Succeed())
|
||||||
Expect(setupTestApp()).To(Succeed())
|
Expect(setupTestApp()).To(Succeed())
|
||||||
Expect(GetWithDefault(testAppName, "unknownKey", "UNKNOWN")).To(Equal("UNKNOWN"))
|
Expect(GetWithDefault(testAppName, "unknownKey", "UNKNOWN")).To(Equal("UNKNOWN"))
|
||||||
Expect(GetWithDefault(testAppName, "testKey", "testKey")).To(Equal("TESTING"))
|
Expect(GetWithDefault(testAppName, "testKey", "testKey")).To(Equal("TESTING"))
|
||||||
@@ -47,6 +52,7 @@ func TestConfigGetWithDefault(t *testing.T) {
|
|||||||
|
|
||||||
func TestConfigGet(t *testing.T) {
|
func TestConfigGet(t *testing.T) {
|
||||||
RegisterTestingT(t)
|
RegisterTestingT(t)
|
||||||
|
Expect(setupTests()).To(Succeed())
|
||||||
Expect(setupTestApp()).To(Succeed())
|
Expect(setupTestApp()).To(Succeed())
|
||||||
defer teardownTestApp()
|
defer teardownTestApp()
|
||||||
|
|
||||||
@@ -59,45 +65,48 @@ func TestConfigGet(t *testing.T) {
|
|||||||
|
|
||||||
func TestConfigSetMany(t *testing.T) {
|
func TestConfigSetMany(t *testing.T) {
|
||||||
RegisterTestingT(t)
|
RegisterTestingT(t)
|
||||||
|
Expect(setupTests()).To(Succeed())
|
||||||
Expect(setupTestApp()).To(Succeed())
|
Expect(setupTestApp()).To(Succeed())
|
||||||
defer teardownTestApp()
|
defer teardownTestApp()
|
||||||
|
|
||||||
expectValue(testAppName, "testKey", "TESTING")
|
expectValue(testAppName, "testKey", "TESTING")
|
||||||
|
|
||||||
vals := map[string]string{"testKey": "updated", "testKey2": "new"}
|
vals := []string{"testKey=updated", "testKey2=new"}
|
||||||
Expect(SetMany(testAppName, vals, false)).To(Succeed())
|
Expect(CommandSet(testAppName, vals, false, true, false)).To(Succeed())
|
||||||
expectValue(testAppName, "testKey", "updated")
|
expectValue(testAppName, "testKey", "updated")
|
||||||
expectValue(testAppName, "testKey2", "new")
|
expectValue(testAppName, "testKey2", "new")
|
||||||
|
|
||||||
vals = map[string]string{"testKey": "updated_global", "testKey2": "new_global"}
|
vals = []string{"testKey=updated_global", "testKey2=new_global"}
|
||||||
Expect(SetMany("", vals, false)).To(Succeed())
|
Expect(CommandSet("", vals, true, true, false)).To(Succeed())
|
||||||
expectValue("", "testKey", "updated_global")
|
expectValue("", "testKey", "updated_global")
|
||||||
expectValue("", "testKey2", "new_global")
|
expectValue("", "testKey2", "new_global")
|
||||||
expectValue("", "globalKey", "GLOBAL_VALUE")
|
expectValue("", "globalKey", "GLOBAL_VALUE")
|
||||||
expectValue(testAppName, "testKey", "updated")
|
expectValue(testAppName, "testKey", "updated")
|
||||||
expectValue(testAppName, "testKey2", "new")
|
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) {
|
func TestConfigUnsetAll(t *testing.T) {
|
||||||
RegisterTestingT(t)
|
RegisterTestingT(t)
|
||||||
|
Expect(setupTests()).To(Succeed())
|
||||||
Expect(setupTestApp()).To(Succeed())
|
Expect(setupTestApp()).To(Succeed())
|
||||||
defer teardownTestApp()
|
defer teardownTestApp()
|
||||||
|
|
||||||
expectValue(testAppName, "testKey", "TESTING")
|
expectValue(testAppName, "testKey", "TESTING")
|
||||||
expectValue("", "testKey", "GLOBAL_TESTING")
|
expectValue("", "testKey", "GLOBAL_TESTING")
|
||||||
|
|
||||||
Expect(UnsetAll(testAppName, false)).To(Succeed())
|
Expect(CommandClear(testAppName, false, true)).To(Succeed())
|
||||||
expectNoValue(testAppName, "testKey")
|
expectNoValue(testAppName, "testKey")
|
||||||
expectNoValue(testAppName, "noKey")
|
expectNoValue(testAppName, "noKey")
|
||||||
expectNoValue(testAppName, "globalKey")
|
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) {
|
func TestConfigUnsetMany(t *testing.T) {
|
||||||
RegisterTestingT(t)
|
RegisterTestingT(t)
|
||||||
|
Expect(setupTests()).To(Succeed())
|
||||||
Expect(setupTestApp()).To(Succeed())
|
Expect(setupTestApp()).To(Succeed())
|
||||||
defer teardownTestApp()
|
defer teardownTestApp()
|
||||||
|
|
||||||
@@ -105,19 +114,20 @@ func TestConfigUnsetMany(t *testing.T) {
|
|||||||
expectValue("", "testKey", "GLOBAL_TESTING")
|
expectValue("", "testKey", "GLOBAL_TESTING")
|
||||||
|
|
||||||
keys := []string{"testKey", "noKey"}
|
keys := []string{"testKey", "noKey"}
|
||||||
Expect(UnsetMany(testAppName, keys, false)).To(Succeed())
|
Expect(CommandUnset(testAppName, keys, false, true)).To(Succeed())
|
||||||
expectNoValue(testAppName, "testKey")
|
expectNoValue(testAppName, "testKey")
|
||||||
expectValue("", "testKey", "GLOBAL_TESTING")
|
expectValue("", "testKey", "GLOBAL_TESTING")
|
||||||
|
|
||||||
Expect(UnsetMany(testAppName, keys, false)).To(Succeed())
|
Expect(CommandUnset(testAppName, keys, false, true)).To(Succeed())
|
||||||
expectNoValue(testAppName, "testKey")
|
expectNoValue(testAppName, "testKey")
|
||||||
expectNoValue(testAppName, "globalKey")
|
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) {
|
func TestEnvironmentLoading(t *testing.T) {
|
||||||
RegisterTestingT(t)
|
RegisterTestingT(t)
|
||||||
|
Expect(setupTests()).To(Succeed())
|
||||||
Expect(setupTestApp()).To(Succeed())
|
Expect(setupTestApp()).To(Succeed())
|
||||||
defer teardownTestApp()
|
defer teardownTestApp()
|
||||||
|
|
||||||
@@ -142,6 +152,7 @@ func TestEnvironmentLoading(t *testing.T) {
|
|||||||
|
|
||||||
func TestInvalidKeys(t *testing.T) {
|
func TestInvalidKeys(t *testing.T) {
|
||||||
RegisterTestingT(t)
|
RegisterTestingT(t)
|
||||||
|
Expect(setupTests()).To(Succeed())
|
||||||
Expect(setupTestApp()).To(Succeed())
|
Expect(setupTestApp()).To(Succeed())
|
||||||
defer teardownTestApp()
|
defer teardownTestApp()
|
||||||
|
|
||||||
@@ -158,6 +169,7 @@ func TestInvalidKeys(t *testing.T) {
|
|||||||
|
|
||||||
func TestInvalidEnvOnDisk(t *testing.T) {
|
func TestInvalidEnvOnDisk(t *testing.T) {
|
||||||
RegisterTestingT(t)
|
RegisterTestingT(t)
|
||||||
|
Expect(setupTests()).To(Succeed())
|
||||||
Expect(setupTestApp()).To(Succeed())
|
Expect(setupTestApp()).To(Succeed())
|
||||||
defer teardownTestApp()
|
defer teardownTestApp()
|
||||||
|
|
||||||
|
|||||||
@@ -60,10 +60,6 @@ func newEnvFromString(rep string) (env *Env, err error) {
|
|||||||
|
|
||||||
//LoadAppEnv loads an environment for the given app
|
//LoadAppEnv loads an environment for the given app
|
||||||
func LoadAppEnv(appName string) (env *Env, err error) {
|
func LoadAppEnv(appName string) (env *Env, err error) {
|
||||||
err = common.VerifyAppName(appName)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
appfile, err := getAppFile(appName)
|
appfile, err := getAppFile(appName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
@@ -357,10 +353,6 @@ func loadFromFile(name string, filename string) (env *Env, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getAppFile(appName string) (string, 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
|
return filepath.Join(common.MustGetEnv("DOKKU_ROOT"), appName, "ENV"), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ config_sub() {
|
|||||||
declare desc="executes a config subcommand"
|
declare desc="executes a config subcommand"
|
||||||
local name="$1"
|
local name="$1"
|
||||||
shift
|
shift
|
||||||
"$PLUGIN_AVAILABLE_PATH/config/subcommands/$name" "config:$name" "$@"
|
"$PLUGIN_AVAILABLE_PATH/config/config_sub" "$name" "$@"
|
||||||
}
|
}
|
||||||
|
|
||||||
config_export() {
|
config_export() {
|
||||||
|
|||||||
@@ -1,13 +1,16 @@
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
import "fmt"
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
func export(appName string, global bool, merged bool, format string) error {
|
"github.com/dokku/dokku/plugins/common"
|
||||||
appName, err := getAppNameOrGlobal(appName, global)
|
)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
|
func export(appName string, merged bool, format string) error {
|
||||||
env := getEnvironment(appName, merged)
|
env := getEnvironment(appName, merged)
|
||||||
exportType := ExportFormatExports
|
exportType := ExportFormatExports
|
||||||
suffix := "\n"
|
suffix := "\n"
|
||||||
@@ -37,3 +40,113 @@ func export(appName string, global bool, merged bool, format string) error {
|
|||||||
fmt.Print(exported + suffix)
|
fmt.Print(exported + suffix)
|
||||||
return nil
|
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
|
package config
|
||||||
|
|
||||||
import (
|
// CommandBundle creates a tarball of a .env.d directory
|
||||||
"encoding/base64"
|
// containing env vars for the app
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/dokku/dokku/plugins/common"
|
|
||||||
)
|
|
||||||
|
|
||||||
// CommandBundle implements config:bundle
|
|
||||||
func CommandBundle(appName string, global bool, merged bool) error {
|
func CommandBundle(appName string, global bool, merged bool) error {
|
||||||
appName, err := getAppNameOrGlobal(appName, global)
|
appName, err := getAppNameOrGlobal(appName, global)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
env := getEnvironment(appName, merged)
|
return SubBundle(appName, merged)
|
||||||
return env.ExportBundle(os.Stdout)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CommandClear implements config:clear
|
// CommandClear unsets all environment variables in use
|
||||||
func CommandClear(appName string, global bool, noRestart bool) error {
|
func CommandClear(appName string, global bool, noRestart bool) error {
|
||||||
appName, err := getAppNameOrGlobal(appName, global)
|
appName, err := getAppNameOrGlobal(appName, global)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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 {
|
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 {
|
func CommandGet(appName string, keys []string, global bool, quoted bool) error {
|
||||||
appName, err := getAppNameOrGlobal(appName, global)
|
appName, err := getAppNameOrGlobal(appName, global)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(keys) == 0 {
|
return SubGet(appName, keys, quoted)
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CommandKeys implements config:keys
|
// CommandKeys shows the keys set for the specified environment
|
||||||
func CommandKeys(appName string, global bool, merged bool) error {
|
func CommandKeys(appName string, global bool, merged bool) error {
|
||||||
appName, err := getAppNameOrGlobal(appName, global)
|
appName, err := getAppNameOrGlobal(appName, global)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
env := getEnvironment(appName, merged)
|
return SubKeys(appName, merged)
|
||||||
for _, k := range env.Keys() {
|
|
||||||
fmt.Println(k)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 {
|
func CommandSet(appName string, pairs []string, global bool, noRestart bool, encoded bool) error {
|
||||||
appName, err := getAppNameOrGlobal(appName, global)
|
appName, err := getAppNameOrGlobal(appName, global)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(pairs) == 0 {
|
return SubSet(appName, pairs, noRestart, encoded)
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CommandShow implements config:show
|
// CommandShow pretty-prints the specified environment vaiables
|
||||||
func CommandShow(appName string, global bool, merged bool, shell bool, export bool) error {
|
func CommandShow(appName string, global bool, merged bool, shell bool, export bool) error {
|
||||||
appName, err := getAppNameOrGlobal(appName, global)
|
appName, err := getAppNameOrGlobal(appName, global)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
env := getEnvironment(appName, merged)
|
return SubShow(appName, merged, shell, export)
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 {
|
func CommandUnset(appName string, keys []string, global bool, noRestart bool) error {
|
||||||
appName, err := getAppNameOrGlobal(appName, global)
|
appName, err := getAppNameOrGlobal(appName, global)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(keys) == 0 {
|
return SubUnset(appName, keys, noRestart)
|
||||||
return fmt.Errorf("At least one key must be given")
|
|
||||||
}
|
|
||||||
|
|
||||||
return UnsetMany(appName, keys, !noRestart)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,13 @@ func TriggerConfigExport(appName string, global string, merged string, format st
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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
|
// TriggerConfigGet returns an app config value by key
|
||||||
|
|||||||
Reference in New Issue
Block a user