Merge pull request #4008 from dokku/standardize-golang-commands
Standardize golang command code
This commit is contained in:
@@ -7,3 +7,11 @@ The `tls` name is no longer a reserved app name, and can be used by applications
|
||||
## Deprecations
|
||||
|
||||
- `git#git_deploy_branch()` is deprecated in favor of `plugn trigger git-deploy-branch`.
|
||||
- The `config` command is deprecated in favor of `config:show`.
|
||||
- Usage of this command in conjunction with either the `--export` or `--shell` flag is deprecated in favor of `config:export --format` with the correct format value (`exports` or `shell`, respectively).
|
||||
|
||||
## Removals
|
||||
|
||||
The `apps:destroy` command no longer takes a second argument `force`. Instead, this can be passed as the `--force` flag, either globally or as a flag to the command itself.
|
||||
|
||||
The `proxy:enable` and `proxy:disable` no longer restart apps when setting the `DOKKU_DISABLE_PROXY` environment variable. A future release will disable usage of `DOKKU_DISABLE_PROXY` altogether.
|
||||
|
||||
@@ -103,6 +103,16 @@ dokku --force apps:destroy node-js-app
|
||||
Destroying node-js-app (including all add-ons)
|
||||
```
|
||||
|
||||
The `--force` flag can also be specified on the command vs globally:
|
||||
|
||||
```shell
|
||||
dokku apps:destroy --force node-js-app
|
||||
```
|
||||
|
||||
```
|
||||
Destroying node-js-app (including all add-ons)
|
||||
```
|
||||
|
||||
Destroying an application will unlink all linked services and destroy any config related to the application. Note that linked services will retain their data for later use (or removal).
|
||||
|
||||
### Renaming a deployed app
|
||||
|
||||
@@ -86,26 +86,6 @@ func destroyApp(appName string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func getAppName(args []string) (appName string, err error) {
|
||||
if len(args) >= 1 {
|
||||
appName = args[0]
|
||||
} else {
|
||||
err = errors.New("Please specify an app to run the command on")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func getNewAppName(args []string) (appName string, err error) {
|
||||
if len(args) >= 2 {
|
||||
appName = args[1]
|
||||
} else {
|
||||
err = errors.New("Please specify an new app name")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func listImagesByAppLabel(appName string) ([]string, error) {
|
||||
command := []string{
|
||||
common.DockerBin(),
|
||||
|
||||
@@ -22,44 +22,57 @@ func main() {
|
||||
skipDeploy := args.Bool("skip-deploy", false, "--skip-deploy: skip deploy of the new app")
|
||||
ignoreExisting := args.Bool("ignore-existing", false, "--ignore-existing: exit 0 if new app already exists")
|
||||
args.Parse(os.Args[2:])
|
||||
err = apps.CommandClone(args.Args(), *skipDeploy, *ignoreExisting)
|
||||
oldAppName := args.Arg(0)
|
||||
newAppName := args.Arg(1)
|
||||
err = apps.CommandClone(oldAppName, newAppName, *skipDeploy, *ignoreExisting)
|
||||
case "create":
|
||||
args := flag.NewFlagSet("apps:create", flag.ExitOnError)
|
||||
args.Parse(os.Args[2:])
|
||||
err = apps.CommandCreate(args.Args())
|
||||
appName := args.Arg(0)
|
||||
err = apps.CommandCreate(appName)
|
||||
case "destroy":
|
||||
args := flag.NewFlagSet("apps:destroy", flag.ExitOnError)
|
||||
force := args.Bool("force", false, "--force: force destroy without confirmation")
|
||||
args.Parse(os.Args[2:])
|
||||
err = apps.CommandDestroy(args.Args())
|
||||
appName := args.Arg(0)
|
||||
err = apps.CommandDestroy(appName, *force)
|
||||
case "exists":
|
||||
args := flag.NewFlagSet("apps:exists", flag.ExitOnError)
|
||||
args.Parse(os.Args[2:])
|
||||
err = apps.CommandExists(args.Args())
|
||||
appName := args.Arg(0)
|
||||
err = apps.CommandExists(appName)
|
||||
case "list":
|
||||
args := flag.NewFlagSet("apps:list", flag.ExitOnError)
|
||||
args.Parse(os.Args[2:])
|
||||
err = apps.CommandList(args.Args())
|
||||
err = apps.CommandList()
|
||||
case "lock":
|
||||
args := flag.NewFlagSet("apps:lock", flag.ExitOnError)
|
||||
args.Parse(os.Args[2:])
|
||||
err = apps.CommandLock(args.Args())
|
||||
appName := args.Arg(0)
|
||||
err = apps.CommandLock(appName)
|
||||
case "locked":
|
||||
args := flag.NewFlagSet("apps:locked", flag.ExitOnError)
|
||||
args.Parse(os.Args[2:])
|
||||
err = apps.CommandLocked(args.Args())
|
||||
appName := args.Arg(0)
|
||||
err = apps.CommandLocked(appName)
|
||||
case "rename":
|
||||
args := flag.NewFlagSet("apps:rename", flag.ExitOnError)
|
||||
skipDeploy := args.Bool("skip-deploy", false, "--skip-deploy: skip deploy of the new app")
|
||||
args.Parse(os.Args[2:])
|
||||
err = apps.CommandRename(args.Args(), *skipDeploy)
|
||||
oldAppName := args.Arg(0)
|
||||
newAppName := args.Arg(1)
|
||||
err = apps.CommandRename(oldAppName, newAppName, *skipDeploy)
|
||||
case "report":
|
||||
args := flag.NewFlagSet("apps:report", flag.ExitOnError)
|
||||
args.Parse(os.Args[2:])
|
||||
err = apps.CommandReport(args.Args())
|
||||
appName := args.Arg(0)
|
||||
infoFlag := args.Arg(1)
|
||||
err = apps.CommandReport(appName, infoFlag)
|
||||
case "unlock":
|
||||
args := flag.NewFlagSet("apps:unlock", flag.ExitOnError)
|
||||
args.Parse(os.Args[2:])
|
||||
err = apps.CommandUnlock(args.Args())
|
||||
appName := args.Arg(0)
|
||||
err = apps.CommandUnlock(appName)
|
||||
default:
|
||||
common.LogFail(fmt.Sprintf("Invalid plugin subcommand call: %s", subcommand))
|
||||
}
|
||||
|
||||
@@ -10,30 +10,28 @@ import (
|
||||
)
|
||||
|
||||
// CommandClone clones an app
|
||||
func CommandClone(args []string, skipDeploy bool, ignoreExisting bool) error {
|
||||
oldAppName, err := getAppName(args)
|
||||
if err != nil {
|
||||
func CommandClone(oldAppName string, newAppName string, skipDeploy bool, ignoreExisting bool) error {
|
||||
if oldAppName == "" {
|
||||
return errors.New("Please specify an app to run the command on")
|
||||
}
|
||||
|
||||
if newAppName == "" {
|
||||
return errors.New("Please specify an new app name")
|
||||
}
|
||||
|
||||
if err := common.IsValidAppName(oldAppName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
newAppName, err := getNewAppName(args)
|
||||
if err != nil {
|
||||
if err := common.IsValidAppName(newAppName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = common.IsValidAppName(oldAppName); err != nil {
|
||||
if err := appExists(oldAppName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = common.IsValidAppName(newAppName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = appExists(oldAppName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = appExists(newAppName); err == nil {
|
||||
if err := appExists(newAppName); err == nil {
|
||||
if ignoreExisting {
|
||||
common.LogWarn("Name is already taken")
|
||||
return nil
|
||||
@@ -43,11 +41,11 @@ func CommandClone(args []string, skipDeploy bool, ignoreExisting bool) error {
|
||||
}
|
||||
|
||||
common.LogInfo1Quiet(fmt.Sprintf("Cloning %s to %s", oldAppName, newAppName))
|
||||
if err = createApp(newAppName); err != nil {
|
||||
if err := createApp(newAppName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = common.PlugnTrigger("post-app-clone-setup", []string{oldAppName, newAppName}...); err != nil {
|
||||
if err := common.PlugnTrigger("post-app-clone-setup", []string{oldAppName, newAppName}...); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -55,7 +53,7 @@ func CommandClone(args []string, skipDeploy bool, ignoreExisting bool) error {
|
||||
os.Setenv("SKIP_REBUILD", "true")
|
||||
}
|
||||
|
||||
if err = common.PlugnTrigger("post-app-clone", []string{oldAppName, newAppName}...); err != nil {
|
||||
if err := common.PlugnTrigger("post-app-clone", []string{oldAppName, newAppName}...); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -63,44 +61,38 @@ func CommandClone(args []string, skipDeploy bool, ignoreExisting bool) error {
|
||||
}
|
||||
|
||||
// CommandCreate creates app via command line
|
||||
func CommandCreate(args []string) error {
|
||||
appName, err := getAppName(args)
|
||||
if err != nil {
|
||||
return err
|
||||
func CommandCreate(appName string) error {
|
||||
if appName == "" {
|
||||
return errors.New("Please specify an app to run the command on")
|
||||
}
|
||||
|
||||
return createApp(appName)
|
||||
}
|
||||
|
||||
// CommandDestroy destroys an app
|
||||
func CommandDestroy(args []string) error {
|
||||
appName, err := getAppName(args)
|
||||
if err != nil {
|
||||
return err
|
||||
func CommandDestroy(appName string, force bool) error {
|
||||
if appName == "" {
|
||||
return errors.New("Please specify an app to run the command on")
|
||||
}
|
||||
|
||||
if len(args) >= 2 {
|
||||
force := args[1]
|
||||
if force == "force" {
|
||||
os.Setenv("DOKKU_APPS_FORCE_DELETE", "1")
|
||||
}
|
||||
if force {
|
||||
os.Setenv("DOKKU_APPS_FORCE_DELETE", "1")
|
||||
}
|
||||
|
||||
return destroyApp(appName)
|
||||
}
|
||||
|
||||
// CommandExists checks if an app exists
|
||||
func CommandExists(args []string) error {
|
||||
appName, err := getAppName(args)
|
||||
if err != nil {
|
||||
return err
|
||||
func CommandExists(appName string) error {
|
||||
if appName == "" {
|
||||
return errors.New("Please specify an app to run the command on")
|
||||
}
|
||||
|
||||
return appExists(appName)
|
||||
}
|
||||
|
||||
// CommandList lists all apps
|
||||
func CommandList(args []string) error {
|
||||
func CommandList() error {
|
||||
common.LogInfo2Quiet("My Apps")
|
||||
apps, err := common.DokkuApps()
|
||||
if err != nil {
|
||||
@@ -116,10 +108,9 @@ func CommandList(args []string) error {
|
||||
}
|
||||
|
||||
// CommandLock locks an app for deployment
|
||||
func CommandLock(args []string) error {
|
||||
appName, err := getAppName(args)
|
||||
if err != nil {
|
||||
return err
|
||||
func CommandLock(appName string) error {
|
||||
if appName == "" {
|
||||
return errors.New("Please specify an app to run the command on")
|
||||
}
|
||||
|
||||
if err := common.VerifyAppName(appName); err != nil {
|
||||
@@ -127,7 +118,7 @@ func CommandLock(args []string) error {
|
||||
}
|
||||
|
||||
lockfilePath := fmt.Sprintf("%v/.deploy.lock", common.AppRoot(appName))
|
||||
if _, err = os.Create(lockfilePath); err != nil {
|
||||
if _, err := os.Create(lockfilePath); err != nil {
|
||||
return errors.New("Unable to create deploy lock")
|
||||
}
|
||||
|
||||
@@ -136,10 +127,9 @@ func CommandLock(args []string) error {
|
||||
}
|
||||
|
||||
// CommandLocked checks if an app is locked for deployment
|
||||
func CommandLocked(args []string) error {
|
||||
appName, err := getAppName(args)
|
||||
if err != nil {
|
||||
return err
|
||||
func CommandLocked(appName string) error {
|
||||
if appName == "" {
|
||||
return errors.New("Please specify an app to run the command on")
|
||||
}
|
||||
|
||||
if err := common.VerifyAppName(appName); err != nil {
|
||||
@@ -155,44 +145,42 @@ func CommandLocked(args []string) error {
|
||||
}
|
||||
|
||||
// CommandRename renames an app
|
||||
func CommandRename(args []string, skipDeploy bool) error {
|
||||
oldAppName, err := getAppName(args)
|
||||
if err != nil {
|
||||
func CommandRename(oldAppName string, newAppName string, skipDeploy bool) error {
|
||||
if oldAppName == "" {
|
||||
return errors.New("Please specify an app to run the command on")
|
||||
}
|
||||
|
||||
if newAppName == "" {
|
||||
return errors.New("Please specify an new app name")
|
||||
}
|
||||
|
||||
if err := common.IsValidAppName(oldAppName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
newAppName, err := getNewAppName(args)
|
||||
if err != nil {
|
||||
if err := common.IsValidAppName(newAppName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = common.IsValidAppName(oldAppName); err != nil {
|
||||
if err := appExists(oldAppName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = common.IsValidAppName(newAppName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = appExists(oldAppName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = appExists(newAppName); err == nil {
|
||||
if err := appExists(newAppName); err == nil {
|
||||
return errors.New("Name is already taken")
|
||||
}
|
||||
|
||||
common.LogInfo1Quiet(fmt.Sprintf("Renaming %s to %s", oldAppName, newAppName))
|
||||
if err = createApp(newAppName); err != nil {
|
||||
if err := createApp(newAppName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = common.PlugnTrigger("post-app-rename-setup", []string{oldAppName, newAppName}...); err != nil {
|
||||
if err := common.PlugnTrigger("post-app-rename-setup", []string{oldAppName, newAppName}...); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
os.Setenv("DOKKU_APPS_FORCE_DELETE", "1")
|
||||
if err = destroyApp(oldAppName); err != nil {
|
||||
if err := destroyApp(oldAppName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -200,7 +188,7 @@ func CommandRename(args []string, skipDeploy bool) error {
|
||||
os.Setenv("SKIP_REBUILD", "true")
|
||||
}
|
||||
|
||||
if err = common.PlugnTrigger("post-app-rename", []string{oldAppName, newAppName}...); err != nil {
|
||||
if err := common.PlugnTrigger("post-app-rename", []string{oldAppName, newAppName}...); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -208,15 +196,9 @@ func CommandRename(args []string, skipDeploy bool) error {
|
||||
}
|
||||
|
||||
// CommandReport displays an app report for one or more apps
|
||||
func CommandReport(args []string) error {
|
||||
appName, err := getAppName(args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
infoFlag := ""
|
||||
if len(args) > 1 {
|
||||
infoFlag = args[1]
|
||||
func CommandReport(appName string, infoFlag string) error {
|
||||
if appName == "" {
|
||||
return errors.New("Please specify an app to run the command on")
|
||||
}
|
||||
|
||||
if strings.HasPrefix(appName, "--") {
|
||||
@@ -241,10 +223,9 @@ func CommandReport(args []string) error {
|
||||
}
|
||||
|
||||
// CommandUnlock unlocks an app for deployment
|
||||
func CommandUnlock(args []string) error {
|
||||
appName, err := getAppName(args)
|
||||
if err != nil {
|
||||
return err
|
||||
func CommandUnlock(appName string) error {
|
||||
if appName == "" {
|
||||
return errors.New("Please specify an app to run the command on")
|
||||
}
|
||||
|
||||
if err := common.VerifyAppName(appName); err != nil {
|
||||
@@ -252,17 +233,15 @@ func CommandUnlock(args []string) error {
|
||||
}
|
||||
|
||||
lockfilePath := fmt.Sprintf("%v/.deploy.lock", common.AppRoot(appName))
|
||||
_, err = os.Stat(lockfilePath)
|
||||
if !os.IsNotExist(err) {
|
||||
if _, err := os.Stat(lockfilePath); !os.IsNotExist(err) {
|
||||
common.LogWarn("A deploy may be in progress.")
|
||||
common.LogWarn("Removing the app lock will not stop in progress deploys.")
|
||||
}
|
||||
|
||||
err = os.Remove(lockfilePath)
|
||||
if err == nil {
|
||||
common.LogInfo1("Deploy lock removed")
|
||||
return nil
|
||||
if err := os.Remove(lockfilePath); err != nil {
|
||||
return errors.New("Unable to remove deploy lock")
|
||||
}
|
||||
|
||||
return errors.New("Unable to remove deploy lock")
|
||||
common.LogInfo1("Deploy lock removed")
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -2,14 +2,26 @@ package buildpacks
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func getAppName(args []string) (appName string, err error) {
|
||||
if len(args) >= 1 {
|
||||
appName = args[0]
|
||||
} else {
|
||||
err = errors.New("Please specify an app to run the command on")
|
||||
func validBuildpackURL(buildpack string) (string, error) {
|
||||
if buildpack == "" {
|
||||
return buildpack, errors.New("Must specify a buildpack to add")
|
||||
}
|
||||
|
||||
return
|
||||
reHerokuValue := regexp.MustCompile(`(?m)^([\w]+\/[\w]+)$`)
|
||||
if found := reHerokuValue.Find([]byte(buildpack)); found != nil {
|
||||
parts := strings.SplitN(buildpack, "/", 2)
|
||||
return fmt.Sprintf("https://github.com/%s/heroku-buildpack-%s.git", parts[0], parts[1]), nil
|
||||
}
|
||||
|
||||
reString := regexp.MustCompile(`(?m)^(http|https|git)(:\/\/|@)([^\/:]+)[\/:]([^\/:]+)\/(.+)(.git(#derp)?)?$`)
|
||||
if found := reString.Find([]byte(buildpack)); found != nil {
|
||||
return buildpack, nil
|
||||
}
|
||||
|
||||
return buildpack, fmt.Errorf("Invalid buildpack specified: %v", buildpack)
|
||||
}
|
||||
|
||||
@@ -21,30 +21,39 @@ func main() {
|
||||
args := flag.NewFlagSet("buildpacks:add", flag.ExitOnError)
|
||||
index := args.Int("index", 0, "--index: the 1-based index of the URL in the list of URLs")
|
||||
args.Parse(os.Args[2:])
|
||||
err = buildpacks.CommandAdd(args.Args(), *index)
|
||||
appName := args.Arg(0)
|
||||
buildpack := args.Arg(1)
|
||||
err = buildpacks.CommandAdd(appName, buildpack, *index)
|
||||
case "clear":
|
||||
args := flag.NewFlagSet("buildpacks:clear", flag.ExitOnError)
|
||||
args.Parse(os.Args[2:])
|
||||
err = buildpacks.CommandClear(args.Args())
|
||||
appName := args.Arg(0)
|
||||
err = buildpacks.CommandClear(appName)
|
||||
case "list":
|
||||
args := flag.NewFlagSet("buildpacks:list", flag.ExitOnError)
|
||||
args.Parse(os.Args[2:])
|
||||
buildpacks.CommandList(args.Args())
|
||||
appName := args.Arg(0)
|
||||
err = buildpacks.CommandList(appName)
|
||||
case "remove":
|
||||
args := flag.NewFlagSet("buildpacks:remove", flag.ExitOnError)
|
||||
index := args.Int("index", 0, "--index: the 1-based index of the URL in the list of URLs")
|
||||
args.Parse(os.Args[2:])
|
||||
err = buildpacks.CommandRemove(args.Args(), *index)
|
||||
appName := args.Arg(0)
|
||||
buildpack := args.Arg(1)
|
||||
err = buildpacks.CommandRemove(appName, buildpack, *index)
|
||||
case "report":
|
||||
flag.Parse()
|
||||
appName := flag.Arg(1)
|
||||
infoFlag := flag.Arg(2)
|
||||
buildpacks.CommandReport(appName, infoFlag)
|
||||
args := flag.NewFlagSet("buildpacks:report", flag.ExitOnError)
|
||||
args.Parse(os.Args[2:])
|
||||
appName := args.Arg(0)
|
||||
infoFlag := args.Arg(1)
|
||||
err = buildpacks.CommandReport(appName, infoFlag)
|
||||
case "set":
|
||||
args := flag.NewFlagSet("buildpacks:set", flag.ExitOnError)
|
||||
index := args.Int("index", 0, "--index: the 1-based index of the URL in the list of URLs")
|
||||
args.Parse(os.Args[2:])
|
||||
err = buildpacks.CommandSet(args.Args(), *index)
|
||||
appName := args.Arg(0)
|
||||
buildpack := args.Arg(1)
|
||||
err = buildpacks.CommandSet(appName, buildpack, *index)
|
||||
default:
|
||||
common.LogFail(fmt.Sprintf("Invalid plugin subcommand call: %s", subcommand))
|
||||
}
|
||||
|
||||
@@ -3,71 +3,38 @@ package buildpacks
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/dokku/dokku/plugins/common"
|
||||
)
|
||||
|
||||
func validBuildpackURL(buildpack string) (string, error) {
|
||||
if buildpack == "" {
|
||||
return buildpack, errors.New("Must specify a buildpack to add")
|
||||
}
|
||||
|
||||
reHerokuValue := regexp.MustCompile(`(?m)^([\w]+\/[\w]+)$`)
|
||||
if found := reHerokuValue.Find([]byte(buildpack)); found != nil {
|
||||
parts := strings.SplitN(buildpack, "/", 2)
|
||||
return fmt.Sprintf("https://github.com/%s/heroku-buildpack-%s.git", parts[0], parts[1]), nil
|
||||
}
|
||||
|
||||
reString := regexp.MustCompile(`(?m)^(http|https|git)(:\/\/|@)([^\/:]+)[\/:]([^\/:]+)\/(.+)(.git(#derp)?)?$`)
|
||||
if found := reString.Find([]byte(buildpack)); found != nil {
|
||||
return buildpack, nil
|
||||
}
|
||||
|
||||
return buildpack, fmt.Errorf("Invalid buildpack specified: %v", buildpack)
|
||||
}
|
||||
|
||||
// CommandAdd implements buildpacks:add
|
||||
func CommandAdd(args []string, index int) (err error) {
|
||||
var appName string
|
||||
appName, err = getAppName(args)
|
||||
if err != nil {
|
||||
return
|
||||
func CommandAdd(appName string, buildpack string, index int) error {
|
||||
if appName == "" {
|
||||
return errors.New("Please specify an app to run the command on")
|
||||
}
|
||||
|
||||
buildpack := ""
|
||||
if len(args) >= 2 {
|
||||
buildpack = args[1]
|
||||
}
|
||||
|
||||
buildpack, err = validBuildpackURL(buildpack)
|
||||
buildpack, err := validBuildpackURL(buildpack)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = common.PropertyListAdd("buildpacks", appName, "buildpacks", buildpack, index)
|
||||
return
|
||||
return common.PropertyListAdd("buildpacks", appName, "buildpacks", buildpack, index)
|
||||
}
|
||||
|
||||
// CommandClear implements buildpacks:clear
|
||||
func CommandClear(args []string) (err error) {
|
||||
var appName string
|
||||
appName, err = getAppName(args)
|
||||
if err != nil {
|
||||
return
|
||||
func CommandClear(appName string) error {
|
||||
if appName == "" {
|
||||
return errors.New("Please specify an app to run the command on")
|
||||
}
|
||||
|
||||
common.PropertyDelete("buildpacks", appName, "buildpacks")
|
||||
return
|
||||
return common.PropertyDelete("buildpacks", appName, "buildpacks")
|
||||
}
|
||||
|
||||
// CommandList implements buildpacks:list
|
||||
func CommandList(args []string) (err error) {
|
||||
var appName string
|
||||
appName, err = getAppName(args)
|
||||
if err != nil {
|
||||
return
|
||||
func CommandList(appName string) (err error) {
|
||||
if appName == "" {
|
||||
return errors.New("Please specify an app to run the command on")
|
||||
}
|
||||
|
||||
buildpacks, err := common.PropertyListGet("buildpacks", appName, "buildpacks")
|
||||
@@ -83,17 +50,11 @@ func CommandList(args []string) (err error) {
|
||||
}
|
||||
|
||||
// CommandRemove implements buildpacks:remove
|
||||
func CommandRemove(args []string, index int) (err error) {
|
||||
var appName string
|
||||
appName, err = getAppName(args)
|
||||
if err != nil {
|
||||
return
|
||||
func CommandRemove(appName string, buildpack string, index int) (err error) {
|
||||
if appName == "" {
|
||||
return errors.New("Please specify an app to run the command on")
|
||||
}
|
||||
|
||||
buildpack := ""
|
||||
if len(args) >= 2 {
|
||||
buildpack = args[1]
|
||||
}
|
||||
if index != 0 && buildpack != "" {
|
||||
err = errors.New("Please choose either index or Buildpack, but not both")
|
||||
return
|
||||
@@ -164,23 +125,15 @@ func CommandReport(appName string, infoFlag string) error {
|
||||
}
|
||||
|
||||
return ReportSingleApp(appName, infoFlag)
|
||||
|
||||
}
|
||||
|
||||
// CommandSet implements buildpacks:set
|
||||
func CommandSet(args []string, index int) (err error) {
|
||||
var appName string
|
||||
appName, err = getAppName(args)
|
||||
if err != nil {
|
||||
return
|
||||
func CommandSet(appName string, buildpack string, index int) error {
|
||||
if appName == "" {
|
||||
return errors.New("Please specify an app to run the command on")
|
||||
}
|
||||
|
||||
buildpack := ""
|
||||
if len(args) >= 2 {
|
||||
buildpack = args[1]
|
||||
}
|
||||
|
||||
buildpack, err = validBuildpackURL(buildpack)
|
||||
buildpack, err := validBuildpackURL(buildpack)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -189,10 +142,5 @@ func CommandSet(args []string, index int) (err error) {
|
||||
index--
|
||||
}
|
||||
|
||||
err = common.PropertyListSet("buildpacks", appName, "buildpacks", buildpack, index)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
return common.PropertyListSet("buildpacks", appName, "buildpacks", buildpack, index)
|
||||
}
|
||||
|
||||
@@ -527,6 +527,15 @@ func RightPad(str string, length int, pad string) string {
|
||||
return str + times(pad, length-len(str))
|
||||
}
|
||||
|
||||
// ShiftString removes the first and returns that entry as well as the rest of the list
|
||||
func ShiftString(a []string) (string, []string) {
|
||||
if len(a) == 0 {
|
||||
return "", a
|
||||
}
|
||||
|
||||
return a[0], a[1:]
|
||||
}
|
||||
|
||||
// StripInlineComments removes bash-style comment from input line
|
||||
func StripInlineComments(text string) string {
|
||||
bytes := []byte(text)
|
||||
|
||||
@@ -64,6 +64,10 @@ func PropertyClone(pluginName string, oldAppName string, newAppName string) erro
|
||||
func PropertyDelete(pluginName string, appName string, property string) error {
|
||||
propertyPath := getPropertyPath(pluginName, appName, property)
|
||||
if err := os.Remove(propertyPath); err != nil {
|
||||
if !PropertyExists(pluginName, appName, property) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("Unable to remove %s property %s.%s", pluginName, appName, property)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
SUBCOMMANDS = subcommands/export subcommands/get subcommands/set subcommands/unset subcommands/keys subcommands/bundle
|
||||
SUBCOMMANDS = subcommands/bundle subcommands/export subcommands/get subcommands/keys subcommands/show subcommands/set subcommands/unset
|
||||
TRIGGERS = triggers/config-get triggers/config-get-global
|
||||
BUILD = commands subcommands triggers
|
||||
PLUGIN_NAME = config
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"regexp"
|
||||
@@ -129,6 +130,27 @@ func triggerUpdate(appName string, operation string, args []string) {
|
||||
}
|
||||
}
|
||||
|
||||
//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.LogFail(err.Error())
|
||||
}
|
||||
return env
|
||||
}
|
||||
|
||||
func getAppNameOrGlobal(appName string, global bool) (string, error) {
|
||||
if appName == "" && !global {
|
||||
return appName, errors.New("Please specify an app to run the command on or --global")
|
||||
}
|
||||
return appName, nil
|
||||
}
|
||||
|
||||
func loadAppOrGlobalEnv(appName string) (env *Env, err error) {
|
||||
if appName == "" || appName == "--global" {
|
||||
return LoadGlobalEnv()
|
||||
|
||||
@@ -21,11 +21,12 @@ Additional commands:`
|
||||
|
||||
helpContent = `
|
||||
config (<app>|--global), Pretty-print an app or global environment
|
||||
config:bundle (<app>|--global) [--merged], Bundle environment into tarfile
|
||||
config:clear (<app>|--global), Clears environment variables
|
||||
config:export (<app>|--global) [--envfile], Export a global or app environment
|
||||
config:get (<app>|--global) KEY, Display a global or app-specific config value
|
||||
config:keys (<app>|--global) [--merged], Show keys set in environment
|
||||
config:bundle [--merged] (<app>|--global), Bundle environment into tarfile
|
||||
config:clear [--no-restart] (<app>|--global), Clears environment variables
|
||||
config:export [--format=FORMAT] [--merged] (<app>|--global), Export a global or app environment
|
||||
config:get [--quoted] (<app>|--global) KEY, Display a global or app-specific config value
|
||||
config:keys [--merged] (<app>|--global), Show keys set in environment
|
||||
config:show [--merged] (<app>|--global), Show keys set in environment
|
||||
config:set [--encoded] [--no-restart] (<app>|--global) KEY1=VALUE1 [KEY2=VALUE2 ...], Set one or more config vars
|
||||
config:unset [--no-restart] (<app>|--global) KEY1 [KEY2 ...], Unset one or more config vars
|
||||
`
|
||||
@@ -37,14 +38,19 @@ func main() {
|
||||
|
||||
cmd := flag.Arg(0)
|
||||
switch cmd {
|
||||
case "config", "config:show":
|
||||
case "config":
|
||||
common.LogWarn("Deprecated: Use the 'config:show' command instead")
|
||||
args := flag.NewFlagSet("config:show", flag.ExitOnError)
|
||||
global := args.Bool("global", false, "--global: use the global environment")
|
||||
shell := args.Bool("shell", false, "--shell: in a single-line for usage in command-line utilities [deprecated]")
|
||||
export := args.Bool("export", false, "--export: print the env as eval-compatible exports [deprecated]")
|
||||
merged := args.Bool("merged", false, "--merged: display the app's environment merged with the global environment")
|
||||
args.Parse(os.Args[2:])
|
||||
config.CommandShow(args.Args(), *global, *shell, *export, *merged)
|
||||
appName := args.Arg(0)
|
||||
err := config.CommandShow(appName, *global, *merged, *shell, *export)
|
||||
if err != nil {
|
||||
common.LogFail(err.Error())
|
||||
}
|
||||
case "config:help":
|
||||
usage()
|
||||
case "help":
|
||||
|
||||
@@ -10,58 +10,104 @@ import (
|
||||
"github.com/dokku/dokku/plugins/config"
|
||||
)
|
||||
|
||||
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() {
|
||||
parts := strings.Split(os.Args[0], "/")
|
||||
subcommand := parts[len(parts)-1]
|
||||
|
||||
var err error
|
||||
var appName string
|
||||
switch subcommand {
|
||||
case "bundle":
|
||||
args := flag.NewFlagSet("config: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:])
|
||||
config.CommandBundle(args.Args(), *global, *merged)
|
||||
if !*global {
|
||||
appName = args.Arg(0)
|
||||
}
|
||||
err = config.CommandBundle(appName, *global, *merged)
|
||||
case "clear":
|
||||
args := flag.NewFlagSet("config: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:])
|
||||
config.CommandClear(args.Args(), *global, *noRestart)
|
||||
if !*global {
|
||||
appName = args.Arg(0)
|
||||
}
|
||||
err = config.CommandClear(appName, *global, *noRestart)
|
||||
case "export":
|
||||
args := flag.NewFlagSet("config: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: [ exports | envfile | docker-args | shell | pretty | json | json-list ] which format to export as)")
|
||||
args.Parse(os.Args[2:])
|
||||
config.CommandExport(args.Args(), *global, *merged, *format)
|
||||
if !*global {
|
||||
appName = args.Arg(0)
|
||||
}
|
||||
err = config.CommandExport(appName, *global, *merged, *format)
|
||||
case "get":
|
||||
args := flag.NewFlagSet("config: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:])
|
||||
config.CommandGet(args.Args(), *global, *quoted)
|
||||
if !*global {
|
||||
appName = args.Arg(0)
|
||||
}
|
||||
keys := getKeys(args.Args(), *global)
|
||||
err = config.CommandGet(appName, keys, *global, *quoted)
|
||||
case "keys":
|
||||
args := flag.NewFlagSet("config: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:])
|
||||
config.CommandKeys(args.Args(), *global, *merged)
|
||||
if !*global {
|
||||
appName = args.Arg(0)
|
||||
}
|
||||
err = config.CommandKeys(appName, *global, *merged)
|
||||
case "show":
|
||||
args := flag.NewFlagSet("config: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.CommandShow(appName, *global, *merged, false, false)
|
||||
case "set":
|
||||
args := flag.NewFlagSet("config: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:])
|
||||
config.CommandSet(args.Args(), *global, *noRestart, *encoded)
|
||||
if !*global {
|
||||
appName = args.Arg(0)
|
||||
}
|
||||
pairs := getKeys(args.Args(), *global)
|
||||
err = config.CommandSet(appName, pairs, *global, *noRestart, *encoded)
|
||||
case "unset":
|
||||
args := flag.NewFlagSet("config: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:])
|
||||
config.CommandUnset(args.Args(), *global, *noRestart)
|
||||
if !*global {
|
||||
appName = args.Arg(0)
|
||||
}
|
||||
keys := getKeys(args.Args(), *global)
|
||||
err = config.CommandUnset(appName, keys, *global, *noRestart)
|
||||
default:
|
||||
common.LogFail(fmt.Sprintf("Invalid plugin subcommand call: %s", subcommand))
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
common.LogFail(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package config
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
@@ -9,16 +10,154 @@ import (
|
||||
"github.com/dokku/dokku/plugins/common"
|
||||
)
|
||||
|
||||
//CommandShow implements config:show
|
||||
func CommandShow(args []string, global bool, shell bool, export bool, merged bool) {
|
||||
appName, _ := getCommonArgs(global, args)
|
||||
// CommandBundle implements config:bundle
|
||||
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)
|
||||
}
|
||||
|
||||
// CommandClear implements config:clear
|
||||
func CommandClear(appName string, global bool, noRestart bool) error {
|
||||
appName, err := getAppNameOrGlobal(appName, global)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return UnsetAll(appName, !noRestart)
|
||||
}
|
||||
|
||||
// CommandExport implements config:export
|
||||
func CommandExport(appName string, global bool, merged bool, format string) error {
|
||||
appName, err := getAppNameOrGlobal(appName, global)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
env := getEnvironment(appName, merged)
|
||||
exportType := ExportFormatExports
|
||||
suffix := "\n"
|
||||
|
||||
exportTypes := map[string]ExportFormat{
|
||||
"exports": ExportFormatExports,
|
||||
"envfile": ExportFormatEnvfile,
|
||||
"docker-args": ExportFormatDockerArgs,
|
||||
"shell": ExportFormatShell,
|
||||
"pretty": ExportFormatPretty,
|
||||
"json": ExportFormatJSON,
|
||||
"json-list": ExportFormatJSONList,
|
||||
}
|
||||
|
||||
exportType, ok := exportTypes[format]
|
||||
if !ok {
|
||||
return fmt.Errorf("Unknown export format: %v", format)
|
||||
}
|
||||
|
||||
if exportType == ExportFormatShell {
|
||||
suffix = " "
|
||||
}
|
||||
|
||||
exported := env.Export(exportType)
|
||||
fmt.Print(exported + suffix)
|
||||
return nil
|
||||
}
|
||||
|
||||
// CommandGet implements config:get
|
||||
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
|
||||
}
|
||||
|
||||
// CommandKeys implements config:keys
|
||||
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
|
||||
}
|
||||
|
||||
// CommandSet implements config:set
|
||||
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)
|
||||
}
|
||||
|
||||
// CommandShow implements config:show
|
||||
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 {
|
||||
common.LogFail("Only one of --shell and --export can be given")
|
||||
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"
|
||||
@@ -28,157 +167,20 @@ func CommandShow(args []string, global bool, shell bool, export bool, merged boo
|
||||
common.LogInfo2Quiet(contextName + " env vars")
|
||||
fmt.Println(env.Export(ExportFormatPretty))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
//CommandGet implements config:get
|
||||
func CommandGet(args []string, global bool, quoted bool) {
|
||||
appName, keys := getCommonArgs(global, args)
|
||||
if len(keys) > 1 {
|
||||
common.LogFail(fmt.Sprintf("Unexpected argument(s): %v", keys[1:]))
|
||||
// CommandUnset implements config:unset
|
||||
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 {
|
||||
common.LogFail("Expected: key")
|
||||
return fmt.Errorf("At least one key must be given")
|
||||
}
|
||||
if value, ok := Get(appName, keys[0]); !ok {
|
||||
os.Exit(1)
|
||||
} else {
|
||||
if quoted {
|
||||
fmt.Printf("'%s'\n", singleQuoteEscape(value))
|
||||
} else {
|
||||
fmt.Printf("%s\n", value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//CommandClear implements config:clear
|
||||
func CommandClear(args []string, global bool, noRestart bool) {
|
||||
appName, _ := getCommonArgs(global, args)
|
||||
err := UnsetAll(appName, !noRestart)
|
||||
if err != nil {
|
||||
common.LogFail(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
//CommandUnset implements config:unset
|
||||
func CommandUnset(args []string, global bool, noRestart bool) {
|
||||
appName, keys := getCommonArgs(global, args)
|
||||
if len(keys) == 0 {
|
||||
common.LogFail("At least one key must be given")
|
||||
}
|
||||
err := UnsetMany(appName, keys, !noRestart)
|
||||
if err != nil {
|
||||
common.LogFail(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
//CommandSet implements config:set
|
||||
func CommandSet(args []string, global bool, noRestart bool, encoded bool) {
|
||||
appName, pairs := getCommonArgs(global, args)
|
||||
if len(pairs) == 0 {
|
||||
common.LogFail("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 {
|
||||
common.LogFail("Invalid env pair: " + e)
|
||||
}
|
||||
key, value := parts[0], parts[1]
|
||||
if encoded {
|
||||
decoded, err := base64.StdEncoding.DecodeString(value)
|
||||
if err != nil {
|
||||
common.LogFail(fmt.Sprintf("%s for key '%s'", err.Error(), key))
|
||||
}
|
||||
value = string(decoded)
|
||||
}
|
||||
updated[key] = value
|
||||
}
|
||||
err := SetMany(appName, updated, !noRestart)
|
||||
if err != nil {
|
||||
common.LogFail(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
//CommandKeys implements config:keys
|
||||
func CommandKeys(args []string, global bool, merged bool) {
|
||||
appName, trailingArgs := getCommonArgs(global, args)
|
||||
if len(trailingArgs) > 0 {
|
||||
common.LogFail(fmt.Sprintf("Trailing argument(s): %v", trailingArgs))
|
||||
}
|
||||
env := getEnvironment(appName, merged)
|
||||
for _, k := range env.Keys() {
|
||||
fmt.Println(k)
|
||||
}
|
||||
}
|
||||
|
||||
//CommandExport implements config:export
|
||||
func CommandExport(args []string, global bool, merged bool, format string) {
|
||||
appName, trailingArgs := getCommonArgs(global, args)
|
||||
if len(trailingArgs) > 0 {
|
||||
common.LogFail(fmt.Sprintf("Trailing argument(s): %v", trailingArgs))
|
||||
}
|
||||
env := getEnvironment(appName, merged)
|
||||
exportType := ExportFormatExports
|
||||
suffix := "\n"
|
||||
switch format {
|
||||
case "exports":
|
||||
exportType = ExportFormatExports
|
||||
case "envfile":
|
||||
exportType = ExportFormatEnvfile
|
||||
case "docker-args":
|
||||
exportType = ExportFormatDockerArgs
|
||||
case "shell":
|
||||
exportType = ExportFormatShell
|
||||
suffix = " "
|
||||
case "pretty":
|
||||
exportType = ExportFormatPretty
|
||||
case "json":
|
||||
exportType = ExportFormatJSON
|
||||
case "json-list":
|
||||
exportType = ExportFormatJSONList
|
||||
default:
|
||||
common.LogFail(fmt.Sprintf("Unknown export format: %v", format))
|
||||
}
|
||||
exported := env.Export(exportType)
|
||||
fmt.Print(exported + suffix)
|
||||
}
|
||||
|
||||
//CommandBundle implements config:bundle
|
||||
func CommandBundle(args []string, global bool, merged bool) {
|
||||
appName, trailingArgs := getCommonArgs(global, args)
|
||||
if len(trailingArgs) > 0 {
|
||||
common.LogFail(fmt.Sprintf("Trailing argument(s): %v", trailingArgs))
|
||||
}
|
||||
env := getEnvironment(appName, merged)
|
||||
env.ExportBundle(os.Stdout)
|
||||
}
|
||||
|
||||
//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.LogFail(err.Error())
|
||||
}
|
||||
return env
|
||||
}
|
||||
|
||||
//getCommonArgs extracts common positional args (appName and keys)
|
||||
func getCommonArgs(global bool, args []string) (appName string, keys []string) {
|
||||
keys = args
|
||||
if !global {
|
||||
if len(args) > 0 {
|
||||
appName = args[0]
|
||||
}
|
||||
if appName == "" {
|
||||
common.LogFail("Please specify an app or --global")
|
||||
} else {
|
||||
keys = args[1:]
|
||||
}
|
||||
}
|
||||
return appName, keys
|
||||
return UnsetMany(appName, keys, !noRestart)
|
||||
}
|
||||
|
||||
@@ -25,17 +25,19 @@ var (
|
||||
)
|
||||
|
||||
// BuildConfig builds network config files
|
||||
func BuildConfig(appName string) {
|
||||
func BuildConfig(appName string) error {
|
||||
if err := common.VerifyAppName(appName); err != nil {
|
||||
common.LogFail(err.Error())
|
||||
return err
|
||||
}
|
||||
|
||||
if !common.IsDeployed(appName) {
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
appRoot := common.AppRoot(appName)
|
||||
scaleFile := strings.Join([]string{appRoot, "DOKKU_SCALE"}, "/")
|
||||
if !common.FileExists(scaleFile) {
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
image := common.GetAppImageName(appName, "", "")
|
||||
@@ -43,8 +45,9 @@ func BuildConfig(appName string) {
|
||||
common.LogInfo1(fmt.Sprintf("Ensuring network configuration is in sync for %s", appName))
|
||||
lines, err := common.FileToSlice(scaleFile)
|
||||
if err != nil {
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
for _, line := range lines {
|
||||
if line == "" || strings.HasPrefix(line, "#") {
|
||||
continue
|
||||
@@ -91,6 +94,8 @@ func BuildConfig(appName string) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetContainerIpaddress returns the ipaddr for a given app container
|
||||
|
||||
@@ -14,56 +14,60 @@ import (
|
||||
func main() {
|
||||
parts := strings.Split(os.Args[0], "/")
|
||||
subcommand := parts[len(parts)-1]
|
||||
flag.Parse()
|
||||
|
||||
var err error
|
||||
switch subcommand {
|
||||
case "create":
|
||||
networkName := flag.Arg(1)
|
||||
err := network.CommandCreate(networkName)
|
||||
if err != nil {
|
||||
common.LogFail(err.Error())
|
||||
}
|
||||
args := flag.NewFlagSet("network:create", flag.ExitOnError)
|
||||
args.Parse(os.Args[2:])
|
||||
networkName := args.Arg(0)
|
||||
err = network.CommandCreate(networkName)
|
||||
case "destroy":
|
||||
networkName := flag.Arg(1)
|
||||
forceDestroy := false
|
||||
if flag.Arg(2) == "force" {
|
||||
forceDestroy = true
|
||||
}
|
||||
err := network.CommandDestroy(networkName, forceDestroy)
|
||||
if err != nil {
|
||||
common.LogFail(err.Error())
|
||||
}
|
||||
args := flag.NewFlagSet("network:destroy", flag.ExitOnError)
|
||||
force := args.Bool("force", false, "--force: force destroy without confirmation")
|
||||
args.Parse(os.Args[2:])
|
||||
networkName := args.Arg(0)
|
||||
err = network.CommandDestroy(networkName, *force)
|
||||
case "exists":
|
||||
networkName := flag.Arg(1)
|
||||
err := network.CommandExists(networkName)
|
||||
if err != nil {
|
||||
common.LogFail(err.Error())
|
||||
}
|
||||
args := flag.NewFlagSet("network:exists", flag.ExitOnError)
|
||||
args.Parse(os.Args[2:])
|
||||
networkName := args.Arg(0)
|
||||
err = network.CommandExists(networkName)
|
||||
case "info":
|
||||
err := network.CommandInfo()
|
||||
if err != nil {
|
||||
common.LogFail(err.Error())
|
||||
}
|
||||
args := flag.NewFlagSet("network:info", flag.ExitOnError)
|
||||
args.Parse(os.Args[2:])
|
||||
err = network.CommandInfo()
|
||||
case "list":
|
||||
err := network.CommandList()
|
||||
if err != nil {
|
||||
common.LogFail(err.Error())
|
||||
}
|
||||
args := flag.NewFlagSet("network:list", flag.ExitOnError)
|
||||
args.Parse(os.Args[2:])
|
||||
err = network.CommandList()
|
||||
case "rebuild":
|
||||
appName := flag.Arg(1)
|
||||
network.BuildConfig(appName)
|
||||
args := flag.NewFlagSet("network:rebuild", flag.ExitOnError)
|
||||
args.Parse(os.Args[2:])
|
||||
appName := args.Arg(0)
|
||||
err = network.BuildConfig(appName)
|
||||
case "rebuildall":
|
||||
network.CommandRebuildall()
|
||||
args := flag.NewFlagSet("network:rebuildall", flag.ExitOnError)
|
||||
args.Parse(os.Args[2:])
|
||||
err = network.CommandRebuildall()
|
||||
case "report":
|
||||
appName := flag.Arg(1)
|
||||
infoFlag := flag.Arg(2)
|
||||
network.CommandReport(appName, infoFlag)
|
||||
args := flag.NewFlagSet("network:report", flag.ExitOnError)
|
||||
args.Parse(os.Args[2:])
|
||||
appName := args.Arg(0)
|
||||
infoFlag := args.Arg(1)
|
||||
err = network.CommandReport(appName, infoFlag)
|
||||
case "set":
|
||||
appName := flag.Arg(1)
|
||||
property := flag.Arg(2)
|
||||
value := flag.Arg(3)
|
||||
network.CommandSet(appName, property, value)
|
||||
args := flag.NewFlagSet("network:set", flag.ExitOnError)
|
||||
args.Parse(os.Args[2:])
|
||||
appName := args.Arg(0)
|
||||
property := args.Arg(1)
|
||||
value := args.Arg(2)
|
||||
err = network.CommandSet(appName, property, value)
|
||||
default:
|
||||
common.LogFail(fmt.Sprintf("Invalid plugin subcommand call: %s", subcommand))
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
common.LogFail(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,14 +106,20 @@ func CommandList() error {
|
||||
}
|
||||
|
||||
// CommandRebuildall rebuilds network settings for all apps
|
||||
func CommandRebuildall() {
|
||||
func CommandRebuildall() error {
|
||||
apps, err := common.DokkuApps()
|
||||
if err != nil {
|
||||
common.LogFail(err.Error())
|
||||
return err
|
||||
}
|
||||
|
||||
for _, appName := range apps {
|
||||
BuildConfig(appName)
|
||||
err = BuildConfig(appName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CommandReport displays a network report for one or more apps
|
||||
@@ -140,7 +146,7 @@ func CommandReport(appName string, infoFlag string) error {
|
||||
}
|
||||
|
||||
// CommandSet set or clear a network property for an app
|
||||
func CommandSet(appName string, property string, value string) {
|
||||
func CommandSet(appName string, property string, value string) error {
|
||||
if property == "bind-all-interfaces" && value == "" {
|
||||
value = "false"
|
||||
}
|
||||
@@ -156,13 +162,14 @@ func CommandSet(appName string, property string, value string) {
|
||||
}
|
||||
if attachProperites[property] {
|
||||
if invalidNetworks[value] {
|
||||
common.LogFail("Invalid network name specified for attach")
|
||||
return errors.New("Invalid network name specified for attach")
|
||||
}
|
||||
|
||||
if isConflictingPropertyValue(appName, property, value) {
|
||||
common.LogFail("Network name already associated with this app")
|
||||
return errors.New("Network name already associated with this app")
|
||||
}
|
||||
}
|
||||
|
||||
common.CommandPropertySet("network", appName, property, value, DefaultProperties)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -93,16 +93,6 @@ func filterAppProxyPorts(appName string, scheme string, hostPort int) []PortMap
|
||||
return filteredProxyMaps
|
||||
}
|
||||
|
||||
func getAppName(args []string) (appName string, err error) {
|
||||
if len(args) >= 1 {
|
||||
appName = args[0]
|
||||
} else {
|
||||
err = errors.New("Please specify an app to run the command on")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func getAppProxyType(appName string) string {
|
||||
return config.GetWithDefault(appName, "DOKKU_APP_PROXY_TYPE", "nginx")
|
||||
}
|
||||
|
||||
@@ -19,40 +19,55 @@ func main() {
|
||||
switch subcommand {
|
||||
case "disable":
|
||||
args := flag.NewFlagSet("proxy:disable", flag.ExitOnError)
|
||||
skipRestart := args.Bool("no-restart", false, "--no-restart: skip restart of the app")
|
||||
args.Parse(os.Args[2:])
|
||||
err = proxy.CommandDisable(args.Args())
|
||||
appName := args.Arg(0)
|
||||
err = proxy.CommandDisable(appName, *skipRestart)
|
||||
case "enable":
|
||||
args := flag.NewFlagSet("proxy:enable", flag.ExitOnError)
|
||||
args.Parse(os.Args[2:])
|
||||
err = proxy.CommandEnable(args.Args())
|
||||
appName := args.Arg(0)
|
||||
err = proxy.CommandEnable(appName)
|
||||
case "ports":
|
||||
args := flag.NewFlagSet("proxy:ports", flag.ExitOnError)
|
||||
args.Parse(os.Args[2:])
|
||||
err = proxy.CommandPorts(args.Args())
|
||||
appName := args.Arg(0)
|
||||
err = proxy.CommandPorts(appName)
|
||||
case "ports-add":
|
||||
args := flag.NewFlagSet("proxy:ports-add", flag.ExitOnError)
|
||||
args.Parse(os.Args[2:])
|
||||
err = proxy.CommandPortsAdd(args.Args())
|
||||
appName := args.Arg(0)
|
||||
_, portMaps := common.ShiftString(args.Args())
|
||||
err = proxy.CommandPortsAdd(appName, portMaps)
|
||||
case "ports-clear":
|
||||
args := flag.NewFlagSet("proxy:ports-clear", flag.ExitOnError)
|
||||
args.Parse(os.Args[2:])
|
||||
err = proxy.CommandPortsClear(args.Args())
|
||||
appName := args.Arg(0)
|
||||
err = proxy.CommandPortsClear(appName)
|
||||
case "ports-remove":
|
||||
args := flag.NewFlagSet("proxy:ports-remove", flag.ExitOnError)
|
||||
args.Parse(os.Args[2:])
|
||||
err = proxy.CommandPortsRemove(args.Args())
|
||||
appName := args.Arg(0)
|
||||
_, portMaps := common.ShiftString(args.Args())
|
||||
err = proxy.CommandPortsRemove(appName, portMaps)
|
||||
case "ports-set":
|
||||
args := flag.NewFlagSet("proxy:ports-set", flag.ExitOnError)
|
||||
args.Parse(os.Args[2:])
|
||||
err = proxy.CommandPortsSet(args.Args())
|
||||
appName := args.Arg(0)
|
||||
_, portMaps := common.ShiftString(args.Args())
|
||||
err = proxy.CommandPortsSet(appName, portMaps)
|
||||
case "report":
|
||||
args := flag.NewFlagSet("proxy:report", flag.ExitOnError)
|
||||
args.Parse(os.Args[2:])
|
||||
err = proxy.CommandReport(args.Args())
|
||||
appName := args.Arg(0)
|
||||
infoFlag := args.Arg(1)
|
||||
err = proxy.CommandReport(appName, infoFlag)
|
||||
case "set":
|
||||
args := flag.NewFlagSet("proxy:set", flag.ExitOnError)
|
||||
args.Parse(os.Args[2:])
|
||||
err = proxy.CommandSet(args.Args())
|
||||
appName := args.Arg(0)
|
||||
proxyType := args.Arg(1)
|
||||
err = proxy.CommandSet(appName, proxyType)
|
||||
default:
|
||||
common.LogFail(fmt.Sprintf("Invalid plugin subcommand call: %s", subcommand))
|
||||
}
|
||||
|
||||
@@ -9,10 +9,9 @@ import (
|
||||
)
|
||||
|
||||
// CommandDisable disables the proxy for app via command line
|
||||
func CommandDisable(args []string) error {
|
||||
appName, err := getAppName(args)
|
||||
if err != nil {
|
||||
return err
|
||||
func CommandDisable(appName string, skipRestart bool) error {
|
||||
if appName == "" {
|
||||
return errors.New("Please specify an app to run the command on")
|
||||
}
|
||||
|
||||
if !IsAppProxyEnabled(appName) {
|
||||
@@ -21,16 +20,11 @@ func CommandDisable(args []string) error {
|
||||
}
|
||||
|
||||
common.LogInfo1("Disabling proxy for app")
|
||||
restart := true
|
||||
if len(args) >= 2 && args[1] == "--no-restart" {
|
||||
restart = false
|
||||
}
|
||||
|
||||
entries := map[string]string{
|
||||
"DOKKU_DISABLE_PROXY": "1",
|
||||
}
|
||||
|
||||
if err := config.SetMany(appName, entries, restart); err != nil {
|
||||
if err := config.SetMany(appName, entries, false); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -38,10 +32,9 @@ func CommandDisable(args []string) error {
|
||||
}
|
||||
|
||||
// CommandEnable enables the proxy for app via command line
|
||||
func CommandEnable(args []string) error {
|
||||
appName, err := getAppName(args)
|
||||
if err != nil {
|
||||
return err
|
||||
func CommandEnable(appName string) error {
|
||||
if appName == "" {
|
||||
return errors.New("Please specify an app to run the command on")
|
||||
}
|
||||
|
||||
if IsAppProxyEnabled(appName) {
|
||||
@@ -50,13 +43,8 @@ func CommandEnable(args []string) error {
|
||||
}
|
||||
|
||||
common.LogInfo1("Enabling proxy for app")
|
||||
restart := true
|
||||
if len(args) >= 2 && args[1] == "--no-restart" {
|
||||
restart = false
|
||||
}
|
||||
|
||||
keys := []string{"DOKKU_DISABLE_PROXY"}
|
||||
if err := config.UnsetMany(appName, keys, restart); err != nil {
|
||||
if err := config.UnsetMany(appName, keys, false); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -64,28 +52,25 @@ func CommandEnable(args []string) error {
|
||||
}
|
||||
|
||||
// CommandPorts is a cmd wrapper to list proxy port mappings for an app
|
||||
func CommandPorts(args []string) error {
|
||||
appName, err := getAppName(args)
|
||||
if err != nil {
|
||||
return err
|
||||
func CommandPorts(appName string) error {
|
||||
if appName == "" {
|
||||
return errors.New("Please specify an app to run the command on")
|
||||
}
|
||||
|
||||
return listAppProxyPorts(appName)
|
||||
}
|
||||
|
||||
// CommandPortsAdd adds proxy port mappings to an app
|
||||
func CommandPortsAdd(args []string) error {
|
||||
appName, err := getAppName(args)
|
||||
if err != nil {
|
||||
return err
|
||||
func CommandPortsAdd(appName string, portMaps []string) error {
|
||||
if appName == "" {
|
||||
return errors.New("Please specify an app to run the command on")
|
||||
}
|
||||
|
||||
if len(args) == 1 {
|
||||
if len(portMaps) == 0 {
|
||||
return errors.New("No port mapping specified")
|
||||
}
|
||||
|
||||
stringPortMap := strings.Join(args[1:], " ")
|
||||
proxyPortMap, err := parseProxyPortMapString(stringPortMap)
|
||||
proxyPortMap, err := parseProxyPortMapString(strings.Join(portMaps, " "))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -98,15 +83,13 @@ func CommandPortsAdd(args []string) error {
|
||||
}
|
||||
|
||||
// CommandPortsClear clears all proxy port mappings for an app
|
||||
func CommandPortsClear(args []string) error {
|
||||
appName, err := getAppName(args)
|
||||
if err != nil {
|
||||
return err
|
||||
func CommandPortsClear(appName string) error {
|
||||
if appName == "" {
|
||||
return errors.New("Please specify an app to run the command on")
|
||||
}
|
||||
|
||||
keys := []string{"DOKKU_PROXY_PORT_MAP"}
|
||||
err = config.UnsetMany(appName, keys, false)
|
||||
if err != nil {
|
||||
if err := config.UnsetMany(appName, keys, false); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -114,18 +97,16 @@ func CommandPortsClear(args []string) error {
|
||||
}
|
||||
|
||||
// CommandPortsRemove removes specific proxy port mappings from an app
|
||||
func CommandPortsRemove(args []string) error {
|
||||
appName, err := getAppName(args)
|
||||
if err != nil {
|
||||
return err
|
||||
func CommandPortsRemove(appName string, portMaps []string) error {
|
||||
if appName == "" {
|
||||
return errors.New("Please specify an app to run the command on")
|
||||
}
|
||||
|
||||
if len(args) == 1 {
|
||||
if len(portMaps) == 0 {
|
||||
return errors.New("No port mapping specified")
|
||||
}
|
||||
|
||||
stringPortMap := strings.Join(args[1:], " ")
|
||||
proxyPortMap, err := parseProxyPortMapString(stringPortMap)
|
||||
proxyPortMap, err := parseProxyPortMapString(strings.Join(portMaps, " "))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -138,18 +119,16 @@ func CommandPortsRemove(args []string) error {
|
||||
}
|
||||
|
||||
// CommandPortsSet sets proxy port mappings for an app
|
||||
func CommandPortsSet(args []string) error {
|
||||
appName, err := getAppName(args)
|
||||
if err != nil {
|
||||
return err
|
||||
func CommandPortsSet(appName string, portMaps []string) error {
|
||||
if appName == "" {
|
||||
return errors.New("Please specify an app to run the command on")
|
||||
}
|
||||
|
||||
if len(args) == 1 {
|
||||
if len(portMaps) == 0 {
|
||||
return errors.New("No port mapping specified")
|
||||
}
|
||||
|
||||
stringPortMap := strings.Join(args[1:], " ")
|
||||
proxyPortMap, err := parseProxyPortMapString(stringPortMap)
|
||||
proxyPortMap, err := parseProxyPortMapString(strings.Join(portMaps, " "))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -162,17 +141,7 @@ func CommandPortsSet(args []string) error {
|
||||
}
|
||||
|
||||
// CommandReport displays a proxy report for one or more apps
|
||||
func CommandReport(args []string) error {
|
||||
appName, err := getAppName(args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
infoFlag := ""
|
||||
if len(args) > 1 {
|
||||
infoFlag = args[1]
|
||||
}
|
||||
|
||||
func CommandReport(appName string, infoFlag string) error {
|
||||
if strings.HasPrefix(appName, "--") {
|
||||
infoFlag = appName
|
||||
appName = ""
|
||||
@@ -195,17 +164,15 @@ func CommandReport(args []string) error {
|
||||
}
|
||||
|
||||
// CommandSet sets a proxy for an app
|
||||
func CommandSet(args []string) error {
|
||||
appName, err := getAppName(args)
|
||||
if err != nil {
|
||||
return err
|
||||
func CommandSet(appName string, proxyType string) error {
|
||||
if appName == "" {
|
||||
return errors.New("Please specify an app to run the command on")
|
||||
}
|
||||
|
||||
if len(appName) < 2 {
|
||||
if len(proxyType) < 2 {
|
||||
return errors.New("Please specify a proxy type")
|
||||
}
|
||||
|
||||
proxyType := args[1]
|
||||
entries := map[string]string{
|
||||
"DOKKU_APP_PROXY_TYPE": proxyType,
|
||||
}
|
||||
|
||||
@@ -14,16 +14,18 @@ import (
|
||||
func main() {
|
||||
parts := strings.Split(os.Args[0], "/")
|
||||
subcommand := parts[len(parts)-1]
|
||||
flag.Parse()
|
||||
|
||||
var err error
|
||||
switch subcommand {
|
||||
case "gc":
|
||||
flag.Parse()
|
||||
appName := flag.Arg(1)
|
||||
args := flag.NewFlagSet("repo:gc", flag.ExitOnError)
|
||||
args.Parse(os.Args[2:])
|
||||
appName := args.Arg(0)
|
||||
err = repo.CommandGc(appName)
|
||||
case "purge-cache":
|
||||
appName := flag.Arg(1)
|
||||
args := flag.NewFlagSet("repo:purge-cache", flag.ExitOnError)
|
||||
args.Parse(os.Args[2:])
|
||||
appName := args.Arg(0)
|
||||
err = repo.CommandPurgeCache(appName)
|
||||
default:
|
||||
common.LogFail(fmt.Sprintf("Invalid plugin subcommand call: %s", subcommand))
|
||||
|
||||
129
plugins/resource/functions.go
Normal file
129
plugins/resource/functions.go
Normal file
@@ -0,0 +1,129 @@
|
||||
package resource
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/dokku/dokku/plugins/common"
|
||||
)
|
||||
|
||||
func clearByResourceType(appName string, processType string, resourceType string) {
|
||||
noun := "limits"
|
||||
if resourceType == "reserve" {
|
||||
noun = "reservation"
|
||||
}
|
||||
|
||||
message := fmt.Sprintf("clearing %v %v", appName, noun)
|
||||
if processType != "_default_" && processType != "" {
|
||||
message = fmt.Sprintf("%v (%v)", message, processType)
|
||||
}
|
||||
common.LogInfo2Quiet(message)
|
||||
|
||||
if processType == "" {
|
||||
resources, err := common.PropertyGetAll("resource", appName)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for key := range resources {
|
||||
common.PropertyDelete("resource", appName, key)
|
||||
}
|
||||
} else {
|
||||
resources := []string{
|
||||
"cpu",
|
||||
"memory",
|
||||
"memory-swap",
|
||||
"network",
|
||||
"network-ingress",
|
||||
"network-egress",
|
||||
"nvidia-gpu",
|
||||
}
|
||||
|
||||
for _, key := range resources {
|
||||
property := propertyKey(processType, resourceType, key)
|
||||
common.PropertyDelete("resource", appName, property)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func setResourceType(appName string, processType string, r Resource, resourceType string) error {
|
||||
if len(processType) == 0 {
|
||||
processType = "_default_"
|
||||
}
|
||||
|
||||
resources := map[string]string{
|
||||
"cpu": r.CPU,
|
||||
"memory": r.Memory,
|
||||
"memory-swap": r.MemorySwap,
|
||||
"network": r.Network,
|
||||
"network-ingress": r.NetworkIngress,
|
||||
"network-egress": r.NetworkEgress,
|
||||
"nvidia-gpu": r.NvidiaGPU,
|
||||
}
|
||||
|
||||
hasValues := false
|
||||
for _, value := range resources {
|
||||
if value != "" {
|
||||
hasValues = true
|
||||
}
|
||||
}
|
||||
|
||||
if !hasValues {
|
||||
reportResourceType(appName, processType, resourceType)
|
||||
return nil
|
||||
}
|
||||
|
||||
noun := "limits"
|
||||
if resourceType == "reserve" {
|
||||
noun = "reservation"
|
||||
}
|
||||
message := fmt.Sprintf("Setting resource %v for %v", noun, appName)
|
||||
if processType != "_default_" {
|
||||
message = fmt.Sprintf("%v (%v)", message, processType)
|
||||
}
|
||||
common.LogInfo2Quiet(message)
|
||||
|
||||
for key, value := range resources {
|
||||
if value == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
common.LogVerbose(fmt.Sprintf("%v: %v", key, value))
|
||||
property := propertyKey(processType, resourceType, key)
|
||||
err := common.PropertyWrite("resource", appName, property, value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func reportResourceType(appName string, processType string, resourceType string) {
|
||||
noun := "limits"
|
||||
if resourceType == "reserve" {
|
||||
noun = "reservation"
|
||||
}
|
||||
|
||||
message := fmt.Sprintf("resource %v %v information", noun, appName)
|
||||
if processType == "_default_" {
|
||||
message = fmt.Sprintf("%v [defaults]", message)
|
||||
} else {
|
||||
message = fmt.Sprintf("%v (%v)", message, processType)
|
||||
}
|
||||
common.LogInfo2Quiet(message)
|
||||
|
||||
resources := []string{
|
||||
"cpu",
|
||||
"memory",
|
||||
"memory-swap",
|
||||
"network",
|
||||
"network-ingress",
|
||||
"network-egress",
|
||||
"nvidia-gpu",
|
||||
}
|
||||
|
||||
for _, key := range resources {
|
||||
property := propertyKey(processType, resourceType, key)
|
||||
value := common.PropertyGet("resource", appName, property)
|
||||
common.LogVerbose(fmt.Sprintf("%v: %v", key, value))
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
package resource
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/dokku/dokku/plugins/common"
|
||||
@@ -63,16 +62,3 @@ func GetResourceValue(appName string, processType string, resourceType string, k
|
||||
func propertyKey(processType string, resourceType string, key string) string {
|
||||
return fmt.Sprintf("%v.%v.%v", processType, resourceType, key)
|
||||
}
|
||||
|
||||
func getAppName(args []string) (string, error) {
|
||||
if len(args) < 1 {
|
||||
return "", errors.New("Please specify an app to run the command on")
|
||||
}
|
||||
|
||||
appName := args[0]
|
||||
if err := common.VerifyAppName(appName); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return appName, nil
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ func main() {
|
||||
networkEgress := args.String("network-egress", "", "network-egress: The amount of egress network bandwidth to limit processes by")
|
||||
nvidiaGpu := args.String("nvidia-gpu", "", "nvidia-gpu: The number of Nvidia GPUs to limit a process to")
|
||||
args.Parse(os.Args[2:])
|
||||
appName := args.Arg(0)
|
||||
|
||||
resources := resource.Resource{
|
||||
CPU: *cpu,
|
||||
@@ -39,17 +40,19 @@ func main() {
|
||||
NvidiaGPU: *nvidiaGpu,
|
||||
}
|
||||
|
||||
err = resource.CommandLimit(args.Args(), *processType, resources)
|
||||
err = resource.CommandLimit(appName, *processType, resources)
|
||||
case "limit-clear":
|
||||
args := flag.NewFlagSet("resource:limit-clear", flag.ExitOnError)
|
||||
processType := args.String("process-type", "", "process-type: A process type to clear")
|
||||
args.Parse(os.Args[2:])
|
||||
err = resource.CommandLimitClear(args.Args(), *processType)
|
||||
appName := args.Arg(0)
|
||||
err = resource.CommandLimitClear(appName, *processType)
|
||||
case "report":
|
||||
flag.Parse()
|
||||
appName := flag.Arg(1)
|
||||
infoFlag := flag.Arg(2)
|
||||
resource.CommandReport(appName, infoFlag)
|
||||
args := flag.NewFlagSet("resource:report", flag.ExitOnError)
|
||||
args.Parse(os.Args[2:])
|
||||
appName := args.Arg(0)
|
||||
infoFlag := args.Arg(1)
|
||||
err = resource.CommandReport(appName, infoFlag)
|
||||
case "reserve":
|
||||
args := flag.NewFlagSet("resource:reserve", flag.ExitOnError)
|
||||
processType := args.String("process-type", "", "process-type: A process type to manage")
|
||||
@@ -61,6 +64,7 @@ func main() {
|
||||
networkEgress := args.String("network-egress", "", "network-egress: The amount of egress network bandwidth to reserve for processes")
|
||||
nvidiaGpu := args.String("nvidia-gpu", "", "nvidia-gpu: The number of Nvidia GPUs to resource for a process")
|
||||
args.Parse(os.Args[2:])
|
||||
appName := args.Arg(0)
|
||||
|
||||
resources := resource.Resource{
|
||||
CPU: *cpu,
|
||||
@@ -72,12 +76,13 @@ func main() {
|
||||
NvidiaGPU: *nvidiaGpu,
|
||||
}
|
||||
|
||||
err = resource.CommandReserve(args.Args(), *processType, resources)
|
||||
err = resource.CommandReserve(appName, *processType, resources)
|
||||
case "reserve-clear":
|
||||
args := flag.NewFlagSet("resource:reserve-clear", flag.ExitOnError)
|
||||
processType := args.String("process-type", "", "process-type: A process type to clear")
|
||||
args.Parse(os.Args[2:])
|
||||
err = resource.CommandReserveClear(args.Args(), *processType)
|
||||
appName := args.Arg(0)
|
||||
err = resource.CommandReserveClear(appName, *processType)
|
||||
default:
|
||||
common.LogFail(fmt.Sprintf("Invalid plugin subcommand call: %s", subcommand))
|
||||
}
|
||||
|
||||
@@ -1,27 +1,25 @@
|
||||
package resource
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"github.com/dokku/dokku/plugins/common"
|
||||
)
|
||||
|
||||
// CommandLimit implements resource:limit
|
||||
func CommandLimit(args []string, processType string, r Resource) error {
|
||||
appName, err := getAppName(args)
|
||||
if err != nil {
|
||||
return err
|
||||
func CommandLimit(appName string, processType string, r Resource) error {
|
||||
if appName == "" {
|
||||
return errors.New("Please specify an app to run the command on")
|
||||
}
|
||||
|
||||
return setResourceType(appName, processType, r, "limit")
|
||||
}
|
||||
|
||||
// CommandLimitClear implements resource:limit-clear
|
||||
func CommandLimitClear(args []string, processType string) error {
|
||||
appName, err := getAppName(args)
|
||||
if err != nil {
|
||||
return err
|
||||
func CommandLimitClear(appName string, processType string) error {
|
||||
if appName == "" {
|
||||
return errors.New("Please specify an app to run the command on")
|
||||
}
|
||||
|
||||
clearByResourceType(appName, processType, "limit")
|
||||
@@ -52,145 +50,20 @@ func CommandReport(appName string, infoFlag string) error {
|
||||
}
|
||||
|
||||
// CommandReserve implements resource:reserve
|
||||
func CommandReserve(args []string, processType string, r Resource) error {
|
||||
appName, err := getAppName(args)
|
||||
if err != nil {
|
||||
return err
|
||||
func CommandReserve(appName string, processType string, r Resource) error {
|
||||
if appName == "" {
|
||||
return errors.New("Please specify an app to run the command on")
|
||||
}
|
||||
|
||||
return setResourceType(appName, processType, r, "reserve")
|
||||
}
|
||||
|
||||
// CommandReserveClear implements resource:reserve-clear
|
||||
func CommandReserveClear(args []string, processType string) error {
|
||||
appName, err := getAppName(args)
|
||||
if err != nil {
|
||||
return err
|
||||
func CommandReserveClear(appName string, processType string) error {
|
||||
if appName == "" {
|
||||
return errors.New("Please specify an app to run the command on")
|
||||
}
|
||||
|
||||
clearByResourceType(appName, processType, "reserve")
|
||||
return nil
|
||||
}
|
||||
|
||||
func clearByResourceType(appName string, processType string, resourceType string) {
|
||||
noun := "limits"
|
||||
if resourceType == "reserve" {
|
||||
noun = "reservation"
|
||||
}
|
||||
|
||||
message := fmt.Sprintf("clearing %v %v", appName, noun)
|
||||
if processType != "_default_" && processType != "" {
|
||||
message = fmt.Sprintf("%v (%v)", message, processType)
|
||||
}
|
||||
common.LogInfo2Quiet(message)
|
||||
|
||||
if processType == "" {
|
||||
resources, err := common.PropertyGetAll("resource", appName)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for key := range resources {
|
||||
common.PropertyDelete("resource", appName, key)
|
||||
}
|
||||
} else {
|
||||
resources := []string{
|
||||
"cpu",
|
||||
"memory",
|
||||
"memory-swap",
|
||||
"network",
|
||||
"network-ingress",
|
||||
"network-egress",
|
||||
"nvidia-gpu",
|
||||
}
|
||||
|
||||
for _, key := range resources {
|
||||
property := propertyKey(processType, resourceType, key)
|
||||
common.PropertyDelete("resource", appName, property)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func setResourceType(appName string, processType string, r Resource, resourceType string) error {
|
||||
if len(processType) == 0 {
|
||||
processType = "_default_"
|
||||
}
|
||||
|
||||
resources := map[string]string{
|
||||
"cpu": r.CPU,
|
||||
"memory": r.Memory,
|
||||
"memory-swap": r.MemorySwap,
|
||||
"network": r.Network,
|
||||
"network-ingress": r.NetworkIngress,
|
||||
"network-egress": r.NetworkEgress,
|
||||
"nvidia-gpu": r.NvidiaGPU,
|
||||
}
|
||||
|
||||
hasValues := false
|
||||
for _, value := range resources {
|
||||
if value != "" {
|
||||
hasValues = true
|
||||
}
|
||||
}
|
||||
|
||||
if !hasValues {
|
||||
reportResourceType(appName, processType, resourceType)
|
||||
return nil
|
||||
}
|
||||
|
||||
noun := "limits"
|
||||
if resourceType == "reserve" {
|
||||
noun = "reservation"
|
||||
}
|
||||
message := fmt.Sprintf("Setting resource %v for %v", noun, appName)
|
||||
if processType != "_default_" {
|
||||
message = fmt.Sprintf("%v (%v)", message, processType)
|
||||
}
|
||||
common.LogInfo2Quiet(message)
|
||||
|
||||
for key, value := range resources {
|
||||
if value == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
common.LogVerbose(fmt.Sprintf("%v: %v", key, value))
|
||||
property := propertyKey(processType, resourceType, key)
|
||||
err := common.PropertyWrite("resource", appName, property, value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func reportResourceType(appName string, processType string, resourceType string) {
|
||||
noun := "limits"
|
||||
if resourceType == "reserve" {
|
||||
noun = "reservation"
|
||||
}
|
||||
|
||||
message := fmt.Sprintf("resource %v %v information", noun, appName)
|
||||
if processType == "_default_" {
|
||||
message = fmt.Sprintf("%v [defaults]", message)
|
||||
} else {
|
||||
message = fmt.Sprintf("%v (%v)", message, processType)
|
||||
}
|
||||
common.LogInfo2Quiet(message)
|
||||
|
||||
resources := []string{
|
||||
"cpu",
|
||||
"memory",
|
||||
"memory-swap",
|
||||
"network",
|
||||
"network-ingress",
|
||||
"network-egress",
|
||||
"nvidia-gpu",
|
||||
}
|
||||
|
||||
for _, key := range resources {
|
||||
property := propertyKey(processType, resourceType, key)
|
||||
value := common.PropertyGet("resource", appName, property)
|
||||
common.LogVerbose(fmt.Sprintf("%v: %v", key, value))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ teardown() {
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_output "FAILED: At least one env pair must be given"
|
||||
[ "$status" -eq 1 ]
|
||||
assert_failure
|
||||
|
||||
run /bin/bash -c "dokku config:get $TEST_APP test_var1 | grep true"
|
||||
echo "output: $output"
|
||||
@@ -105,7 +105,7 @@ teardown() {
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_output "FAILED: At least one env pair must be given"
|
||||
[ "$status" -eq 1 ]
|
||||
assert_failure
|
||||
|
||||
run /bin/bash -c "dokku --app $TEST_APP config:get test_var1 | grep true"
|
||||
echo "output: $output"
|
||||
@@ -150,7 +150,7 @@ teardown() {
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_output "FAILED: At least one key must be given"
|
||||
[ "$status" -eq 1 ]
|
||||
assert_failure
|
||||
}
|
||||
|
||||
@test "(config) global config (herokuish)" {
|
||||
|
||||
@@ -19,6 +19,11 @@ SKIPPED_TEST_ERR_MSG="previous test failed! skipping remaining tests..."
|
||||
# skips remaining tests on first failure
|
||||
global_setup() {
|
||||
[[ ! -f "${BATS_PARENT_TMPNAME}.skip" ]] || skip "$SKIPPED_TEST_ERR_MSG"
|
||||
|
||||
dokku apps:list
|
||||
docker container ls
|
||||
free -m
|
||||
docker container ls --quiet | xargs -n1 docker container rm -f || true
|
||||
}
|
||||
|
||||
global_teardown() {
|
||||
|
||||
Reference in New Issue
Block a user