refactor: implement most of ps plugin in golang
This commit is contained in:
@@ -5,3 +5,15 @@
|
||||
- Underscores are no longer valid characters in app names. Please rename applications before upgrading.
|
||||
- Process type names specified in Procfile may no longer use characters not valid in DNS Label Names ([RFC 1123](https://tools.ietf.org/html/rfc1123)).
|
||||
- The minimum Docker version is now 17.05.0.
|
||||
|
||||
## Removals
|
||||
|
||||
The `ps` command has had a few removals as a result of a rewrite to Golang:
|
||||
|
||||
- The `ps:set-restart-policy` command has been removed in favor the `ps:set` command.
|
||||
- The `ps:restart-policy` command has been removed in favor of the `ps:report` command.
|
||||
- The `ps:rebuildall` command has been removed in favor of calling the `ps:rebuild` with the `--all` flag instead of an app name.
|
||||
- The `ps:restartall` command has been removed in favor of calling the `ps:restart` with the `--all` flag instead of an app name.
|
||||
- The `ps:stopall` command has been removed in favor of calling the `ps:stop` with the `--all` flag instead of an app name.
|
||||
- The `ps:startall` command has been removed in favor of calling the `ps:start` with the `--all` flag instead of an app name.
|
||||
- The `DOKKU_PROCFILE` file is no longer located in the git directory for a given app on the server. It's location is currently not exposed.
|
||||
|
||||
@@ -8,10 +8,9 @@ ps:rebuild <app> # Rebuild an app from source
|
||||
ps:rebuildall # Rebuild all apps from source
|
||||
ps:report [<app>] [<flag>] # Displays a process report for one or more apps
|
||||
ps:restart <app> # Restart app container(s)
|
||||
ps:restart-policy <app> # Shows the restart-policy for an app
|
||||
ps:restartall # Restart all deployed app containers
|
||||
ps:scale <app> <proc>=<count> [<proc>=<count>] # Get/Set how many instances of a given process to run
|
||||
ps:set-restart-policy <app> <policy> # Sets app restart-policy
|
||||
ps:set <app> <key> <value> # Set or clear a ps property for an app
|
||||
ps:start <app> # Start app container(s)
|
||||
ps:startall # Start all deployed app containers
|
||||
ps:stop <app> # Stop app container(s)
|
||||
@@ -133,68 +132,29 @@ dokku ps:startall
|
||||
|
||||
> New as of 0.7.0
|
||||
|
||||
By default, Dokku will automatically restart containers that exit with a non-zero status up to 10 times via the [on-failure Docker restart policy](https://docs.docker.com/engine/reference/run/#restart-policies-restart).
|
||||
|
||||
### Showing the current restart policy
|
||||
|
||||
The `ps:restart-policy` command will show the currently configured restart policy for an application. The default policy is `on-failure:10`
|
||||
|
||||
```shell
|
||||
dokku ps:restart-policy node-js-app
|
||||
```
|
||||
|
||||
```
|
||||
=====> node-js-app restart-policy:
|
||||
on-failure:10
|
||||
```
|
||||
By default, Dokku will automatically restart containers that exit with a non-zero status up to 10 times via the [on-failure Docker restart policy](https://docs.docker.com/engine/reference/run/#restart-policies---restart).
|
||||
|
||||
### Setting the restart policy
|
||||
|
||||
You can configure this via the `ps:set-restart-policy` command:
|
||||
> A change in the restart policy must be followed by a `ps:rebuild` call.
|
||||
|
||||
You can configure this via the `ps:set` command:
|
||||
|
||||
```shell
|
||||
# always restart an exited container
|
||||
dokku ps:set-restart-policy node-js-app always
|
||||
```
|
||||
dokku ps:set node-js-app restart-policy always
|
||||
|
||||
```
|
||||
-----> Setting restart policy: always
|
||||
```
|
||||
|
||||
```shell
|
||||
# never restart an exited container
|
||||
dokku ps:set-restart-policy node-js-app no
|
||||
```
|
||||
dokku ps:set node-js-app restart-policy no
|
||||
|
||||
```
|
||||
-----> Setting restart policy: no
|
||||
```
|
||||
|
||||
```shell
|
||||
# only restart it on Docker restart if it was not manually stopped
|
||||
dokku ps:set-restart-policy node-js-app unless-stopped
|
||||
```
|
||||
dokku ps:set node-js-app restart-policy unless-stopped
|
||||
|
||||
```
|
||||
-----> Setting restart policy: unless-stopped
|
||||
```
|
||||
|
||||
```shell
|
||||
# restart only on non-zero exit status
|
||||
dokku ps:set-restart-policy node-js-app on-failure
|
||||
```
|
||||
dokku ps:set node-js-app restart-policy on-failure
|
||||
|
||||
```
|
||||
-----> Setting restart policy: on-failure
|
||||
```
|
||||
|
||||
```shell
|
||||
# restart only on non-zero exit status up to 20 times
|
||||
dokku ps:set-restart-policy node-js-app on-failure:20
|
||||
```
|
||||
|
||||
```
|
||||
-----> Setting restart policy: on-failure:20
|
||||
dokku ps:set node-js-app restart-policy on-failure:20
|
||||
```
|
||||
|
||||
Restart policies have no bearing on server reboot, and Dokku will always attempt to restart your applications at that point unless they were manually stopped.
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"reflect"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode"
|
||||
|
||||
@@ -379,6 +380,16 @@ func ToBool(s string) bool {
|
||||
return s == "true"
|
||||
}
|
||||
|
||||
// ToInt returns an int value for a given string
|
||||
func ToInt(s string, defaultValue int) int {
|
||||
i, err := strconv.Atoi(s)
|
||||
if err != nil {
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
return i
|
||||
}
|
||||
|
||||
// UcFirst uppercases the first character in a string
|
||||
func UcFirst(str string) string {
|
||||
for i, v := range str {
|
||||
|
||||
@@ -4,13 +4,39 @@ import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/dokku/dokku/plugins/common"
|
||||
)
|
||||
|
||||
func SetDockerOptionForPhases(appName string, phases []string, name string, value string) error {
|
||||
for _, phase := range phases {
|
||||
if err := touchPhaseFile(appName, phase); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
options, err := GetDockerOptionsForPhase(appName, phase)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
newOptions := []string{}
|
||||
for _, option := range options {
|
||||
if strings.HasPrefix(option, fmt.Sprintf("--%s=", name)) {
|
||||
continue
|
||||
}
|
||||
|
||||
newOptions = append(newOptions, option)
|
||||
}
|
||||
|
||||
newOptions = append(newOptions, fmt.Sprintf("--%s=%s", name, value))
|
||||
sort.Strings(newOptions)
|
||||
if err = writeDockerOptionsForPhase(appName, phase, newOptions); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddDockerOptionToPhases adds docker option to specified phases
|
||||
func AddDockerOptionToPhases(appName string, phases []string, option string) error {
|
||||
for _, phase := range phases {
|
||||
@@ -58,29 +84,3 @@ func GetDockerOptionsForPhase(appName string, phase string) ([]string, error) {
|
||||
|
||||
return options, nil
|
||||
}
|
||||
|
||||
func getPhaseFilePath(appName string, phase string) string {
|
||||
return filepath.Join(common.MustGetEnv("DOKKU_ROOT"), appName, "DOCKER_OPTIONS_"+strings.ToUpper(phase))
|
||||
}
|
||||
|
||||
func touchPhaseFile(appName string, phase string) error {
|
||||
phaseFilePath := getPhaseFilePath(appName, phase)
|
||||
|
||||
_, err := os.Stat(phaseFilePath)
|
||||
if !os.IsNotExist(err) {
|
||||
return nil
|
||||
}
|
||||
|
||||
file, err := os.Create(phaseFilePath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to create docker options phase file %s.%s: %s", appName, phase, err.Error())
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func writeDockerOptionsForPhase(appName string, phase string, options []string) error {
|
||||
phaseFilePath := getPhaseFilePath(appName, phase)
|
||||
return common.WriteSliceToFile(phaseFilePath, options)
|
||||
}
|
||||
|
||||
36
plugins/docker-options/functions.go
Normal file
36
plugins/docker-options/functions.go
Normal file
@@ -0,0 +1,36 @@
|
||||
package dockeroptions
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/dokku/dokku/plugins/common"
|
||||
)
|
||||
|
||||
func getPhaseFilePath(appName string, phase string) string {
|
||||
return filepath.Join(common.AppRoot(appName), "DOCKER_OPTIONS_"+strings.ToUpper(phase))
|
||||
}
|
||||
|
||||
func touchPhaseFile(appName string, phase string) error {
|
||||
phaseFilePath := getPhaseFilePath(appName, phase)
|
||||
|
||||
_, err := os.Stat(phaseFilePath)
|
||||
if !os.IsNotExist(err) {
|
||||
return nil
|
||||
}
|
||||
|
||||
file, err := os.Create(phaseFilePath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to create docker options phase file %s.%s: %s", appName, phase, err.Error())
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func writeDockerOptionsForPhase(appName string, phase string, options []string) error {
|
||||
phaseFilePath := getPhaseFilePath(appName, phase)
|
||||
return common.WriteSliceToFile(phaseFilePath, options)
|
||||
}
|
||||
11
plugins/ps/.gitignore
vendored
Normal file
11
plugins/ps/.gitignore
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
/commands
|
||||
/subcommands/*
|
||||
/triggers/*
|
||||
/triggers
|
||||
/proxy-*
|
||||
/install
|
||||
/post-*
|
||||
/report
|
||||
/pre-*
|
||||
/procfile-*
|
||||
/app-restart
|
||||
6
plugins/ps/Makefile
Normal file
6
plugins/ps/Makefile
Normal file
@@ -0,0 +1,6 @@
|
||||
SUBCOMMANDS = subcommands/inspect subcommands/rebuild subcommands/rebuildall subcommands/report subcommands/restart subcommands/restart-policy subcommands/restartall subcommands/restore subcommands/retire subcommands/scale subcommands/set subcommands/start subcommands/startall subcommands/stop subcommands/stopall
|
||||
TRIGGERS = triggers/app-restart triggers/install triggers/post-app-clone triggers/post-app-rename triggers/post-create triggers/post-delete triggers/post-stop triggers/pre-deploy triggers/procfile-extract triggers/procfile-get-command triggers/procfile-remove triggers/report
|
||||
BUILD = commands subcommands triggers
|
||||
PLUGIN_NAME = ps
|
||||
|
||||
include ../../common.mk
|
||||
@@ -1,15 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eo pipefail
|
||||
[[ $DOKKU_TRACE ]] && set -x
|
||||
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
|
||||
source "$PLUGIN_AVAILABLE_PATH/ps/functions"
|
||||
|
||||
trigger-ps-app-restart() {
|
||||
declare desc="ps app-restart plugin trigger"
|
||||
declare trigger="app-restart"
|
||||
declare APP="$1"
|
||||
|
||||
ps_restart "$APP"
|
||||
}
|
||||
|
||||
trigger-ps-app-restart "$@"
|
||||
@@ -1,16 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
[[ " help ps:help " == *" $1 "* ]] || exit "$DOKKU_NOT_IMPLEMENTED_EXIT"
|
||||
source "$PLUGIN_AVAILABLE_PATH/ps/help-functions"
|
||||
set -eo pipefail
|
||||
[[ $DOKKU_TRACE ]] && set -x
|
||||
|
||||
case "$1" in
|
||||
help | ps:help)
|
||||
cmd-ps-help "$@"
|
||||
;;
|
||||
|
||||
*)
|
||||
exit "$DOKKU_NOT_IMPLEMENTED_EXIT"
|
||||
;;
|
||||
|
||||
esac
|
||||
@@ -1,17 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eo pipefail
|
||||
[[ $DOKKU_TRACE ]] && set -x
|
||||
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
|
||||
source "$PLUGIN_AVAILABLE_PATH/config/functions"
|
||||
source "$PLUGIN_AVAILABLE_PATH/ps/functions"
|
||||
|
||||
trigger-ps-core-post-deploy() {
|
||||
declare desc="ps core-post-deploy plugin trigger"
|
||||
declare trigger="core-post-deploy"
|
||||
declare APP="$1"
|
||||
|
||||
remove_procfile "$APP"
|
||||
DOKKU_QUIET_OUTPUT=1 config_set --no-restart "$APP" DOKKU_APP_RESTORE=1
|
||||
}
|
||||
|
||||
trigger-ps-core-post-deploy "$@"
|
||||
287
plugins/ps/functions.go
Normal file
287
plugins/ps/functions.go
Normal file
@@ -0,0 +1,287 @@
|
||||
package ps
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/dokku/dokku/plugins/common"
|
||||
dockeroptions "github.com/dokku/dokku/plugins/docker-options"
|
||||
)
|
||||
|
||||
func canScaleApp(appName string) bool {
|
||||
return !common.FileExists(getScalefilePath(appName))
|
||||
}
|
||||
|
||||
func extractProcfile(appName, image string, procfilePath string) error {
|
||||
if err := removeProcfile(appName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
destination := getProcfilePath(appName)
|
||||
common.CopyFromImage(appName, image, "Procfile", destination)
|
||||
if !common.FileExists(destination) {
|
||||
common.LogInfo1Quiet("No Procfile found in app image")
|
||||
return nil
|
||||
}
|
||||
|
||||
common.LogInfo1Quiet("App Procfile file found")
|
||||
checkCmd := common.NewShellCmd(strings.Join([]string{
|
||||
"procfile-util",
|
||||
"check",
|
||||
"--procfile",
|
||||
destination,
|
||||
}, " "))
|
||||
var stderr bytes.Buffer
|
||||
checkCmd.ShowOutput = false
|
||||
checkCmd.Command.Stderr = &stderr
|
||||
_, err := checkCmd.Output()
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf(strings.TrimSpace(stderr.String()))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
func extractOrGenerateScalefile(appName string, image string) error {
|
||||
destination := getScalefilePath(appName)
|
||||
extracted := getScalefileExtractedPath(appName)
|
||||
if err := common.CopyFromImage(appName, image, "DOKKU_SCALE", destination); err != nil {
|
||||
os.Remove(extracted)
|
||||
os.Remove(destination)
|
||||
} else if err := common.CopyFile(destination, extracted); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if common.FileExists(destination) {
|
||||
return nil
|
||||
}
|
||||
|
||||
common.LogInfo1Quiet("DOKKU_SCALE file not found in app image. Generating one based on Procfile...")
|
||||
if err := generateScalefile(appName, destination); err != nil {
|
||||
common.LogDebug(fmt.Sprintf("Error: %s", err.Error()))
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func generateScalefile(appName string, destination string) error {
|
||||
procfilePath := getProcfilePath(appName)
|
||||
content := []string{"web=1"}
|
||||
if !common.FileExists(procfilePath) {
|
||||
return common.WriteSliceToFile(destination, content)
|
||||
}
|
||||
|
||||
lines, err := common.FileToSlice(procfilePath)
|
||||
if err != nil {
|
||||
return common.WriteSliceToFile(destination, content)
|
||||
}
|
||||
|
||||
content = []string{}
|
||||
for _, line := range lines {
|
||||
if line == "" || strings.HasPrefix(line, "#") {
|
||||
continue
|
||||
}
|
||||
|
||||
parts := strings.Split(line, ":")
|
||||
count := 0
|
||||
if parts[0] == "web" {
|
||||
count = 1
|
||||
}
|
||||
|
||||
content = append(content, fmt.Sprintf("%s=%d", parts[0], count))
|
||||
}
|
||||
|
||||
return common.WriteSliceToFile(destination, content)
|
||||
}
|
||||
|
||||
func getProcfileCommand(procfilePath string, processType string, port int) (string, error) {
|
||||
shellCmd := common.NewShellCmd(strings.Join([]string{
|
||||
"procfile-util",
|
||||
"show",
|
||||
"--procfile",
|
||||
procfilePath,
|
||||
"--process-type",
|
||||
processType,
|
||||
"--default-port",
|
||||
strconv.Itoa(port),
|
||||
}, " "))
|
||||
var stderr bytes.Buffer
|
||||
shellCmd.ShowOutput = false
|
||||
shellCmd.Command.Stderr = &stderr
|
||||
b, err := shellCmd.Output()
|
||||
|
||||
if err != nil {
|
||||
return "", fmt.Errorf(strings.TrimSpace(stderr.String()))
|
||||
}
|
||||
|
||||
return strings.TrimSpace(string(b[:])), nil
|
||||
}
|
||||
|
||||
func getProcfilePath(appName string) string {
|
||||
directory := filepath.Join(common.MustGetEnv("DOKKU_LIB_ROOT"), "data", "ps", appName)
|
||||
return filepath.Join(directory, "Procfile")
|
||||
}
|
||||
|
||||
func getRestartPolicy(appName string) (string, error) {
|
||||
options, err := dockeroptions.GetDockerOptionsForPhase(appName, "deploy")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
for _, option := range options {
|
||||
if strings.HasPrefix(option, "--restart=") {
|
||||
return strings.TrimPrefix(option, "--restart="), nil
|
||||
}
|
||||
}
|
||||
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func getRunningState(appName string) string {
|
||||
scheduler := common.GetAppScheduler(appName)
|
||||
b, _ := common.PlugnTriggerOutput("scheduler-app-status", []string{scheduler, appName}...)
|
||||
return strings.Split(strings.TrimSpace(string(b[:])), " ")[1]
|
||||
}
|
||||
|
||||
func getScalefilePath(appName string) string {
|
||||
return filepath.Join(common.AppRoot(appName), "DOKKU_SCALE")
|
||||
}
|
||||
|
||||
func getScalefileExtractedPath(appName string) string {
|
||||
return filepath.Join(common.AppRoot(appName), "DOKKU_SCALE.extracted")
|
||||
}
|
||||
|
||||
func isValidRestartPolicy(policy string) bool {
|
||||
if policy == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
validRestartPolicies := map[string]bool{
|
||||
"no": true,
|
||||
"always": true,
|
||||
"unless-stopped": true,
|
||||
"on-failure": true,
|
||||
}
|
||||
|
||||
if _, ok := validRestartPolicies[policy]; ok {
|
||||
return true
|
||||
}
|
||||
|
||||
return strings.HasPrefix(policy, "on-failure:")
|
||||
}
|
||||
|
||||
func processesInProcfile(procfilePath string) (map[string]bool, error) {
|
||||
processes := map[string]bool{}
|
||||
|
||||
shellCmd := common.NewShellCmd(strings.Join([]string{
|
||||
"procfile-util",
|
||||
"list",
|
||||
"--procfile",
|
||||
procfilePath,
|
||||
}, " "))
|
||||
var stderr bytes.Buffer
|
||||
shellCmd.ShowOutput = false
|
||||
shellCmd.Command.Stderr = &stderr
|
||||
b, err := shellCmd.Output()
|
||||
|
||||
if err != nil {
|
||||
return processes, fmt.Errorf(strings.TrimSpace(stderr.String()))
|
||||
}
|
||||
|
||||
for _, s := range strings.Split(strings.TrimSpace(string(b[:])), "\n") {
|
||||
processes[s] = true
|
||||
}
|
||||
|
||||
return processes, nil
|
||||
}
|
||||
|
||||
func removeProcfile(appName string) error {
|
||||
procfile := getProcfilePath(appName)
|
||||
if !common.FileExists(procfile) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return os.Remove(procfile)
|
||||
}
|
||||
|
||||
func updateScalefile(appName string, processTuples []string) error {
|
||||
procfilePath := getProcfilePath(appName)
|
||||
scalefilePath := getScalefilePath(appName)
|
||||
lines, err := common.FileToSlice(scalefilePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
processTypes, err := processesInProcfile(procfilePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
newLines := []string{}
|
||||
for processType := range processTypes {
|
||||
found := false
|
||||
for _, line := range lines {
|
||||
if strings.HasPrefix(line, fmt.Sprintf("%s=", processType)) {
|
||||
newLines = append(newLines, line)
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
newLines = append(newLines, fmt.Sprintf("%s=0", processType))
|
||||
}
|
||||
}
|
||||
|
||||
scale := []string{}
|
||||
for _, processTuple := range processTuples {
|
||||
s := strings.Split(processTuple, "=")
|
||||
if len(s) == 1 {
|
||||
return fmt.Errorf("Missing count for process type %s", processTuple)
|
||||
}
|
||||
|
||||
processType := s[0]
|
||||
count, err := strconv.Atoi(s[1])
|
||||
if err != nil {
|
||||
return fmt.Errorf("Invalid count for process type %s", s[0])
|
||||
}
|
||||
|
||||
if _, ok := processTypes[processType]; !ok {
|
||||
if count != 0 && len(processTypes) == 0 {
|
||||
return fmt.Errorf("%s is not a valid process name to scale up", processType)
|
||||
}
|
||||
}
|
||||
|
||||
scale = append(scale, fmt.Sprintf("%s=%d", processType, count))
|
||||
}
|
||||
|
||||
for _, line := range newLines {
|
||||
s := strings.Split(line, "=")
|
||||
processType := s[0]
|
||||
|
||||
found := false
|
||||
for _, s := range scale {
|
||||
if strings.HasPrefix(s, fmt.Sprintf("%s=", processType)) {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
scale = append(scale, line)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if err := common.WriteSliceToFile(scalefilePath, scale); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
15
plugins/ps/go.mod
Normal file
15
plugins/ps/go.mod
Normal file
@@ -0,0 +1,15 @@
|
||||
module github.com/dokku/dokku/plugins/ps
|
||||
|
||||
go 1.14
|
||||
|
||||
require (
|
||||
github.com/codeskyblue/go-sh v0.0.0-20190412065543-76bd3d59ff27
|
||||
github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000
|
||||
github.com/dokku/dokku/plugins/config v0.0.0-00010101000000-000000000000
|
||||
github.com/dokku/dokku/plugins/docker-options v0.0.0-00010101000000-000000000000
|
||||
github.com/ryanuber/columnize v1.1.2-0.20190319233515-9e6335e58db3
|
||||
)
|
||||
|
||||
replace github.com/dokku/dokku/plugins/common => ../common
|
||||
replace github.com/dokku/dokku/plugins/config => ../config
|
||||
replace github.com/dokku/dokku/plugins/docker-options => ../docker-options
|
||||
10
plugins/ps/go.sum
Normal file
10
plugins/ps/go.sum
Normal file
@@ -0,0 +1,10 @@
|
||||
github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 h1:sDMmm+q/3+BukdIpxwO365v/Rbspp2Nt5XntgQRXq8Q=
|
||||
github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM=
|
||||
github.com/codeskyblue/go-sh v0.0.0-20190412065543-76bd3d59ff27 h1:HHUr4P/aKh4quafGxDT9LDasjGdlGkzLbfmmrlng3kA=
|
||||
github.com/codeskyblue/go-sh v0.0.0-20190412065543-76bd3d59ff27/go.mod h1:VQx0hjo2oUeQkQUET7wRwradO6f+fN5jzXgB/zROxxE=
|
||||
github.com/dokku/dokku v0.21.4 h1:WG0hyPzNqKqoQXuI7H/N+cWX9B7mAxTW6Yop40BjCQk=
|
||||
github.com/joho/godotenv v1.2.0 h1:vGTvz69FzUFp+X4/bAkb0j5BoLC+9bpqTWY8mjhA9pc=
|
||||
github.com/joho/godotenv v1.2.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
|
||||
github.com/ryanuber/columnize v1.1.2-0.20190319233515-9e6335e58db3 h1:utdYOikI1XjNtTFGCwSM6OmFJblU4ld4gACoJsbadJg=
|
||||
github.com/ryanuber/columnize v1.1.2-0.20190319233515-9e6335e58db3/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
@@ -1,45 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eo pipefail
|
||||
[[ $DOKKU_TRACE ]] && set -x
|
||||
|
||||
cmd-ps-help() {
|
||||
declare desc="help command"
|
||||
declare CMD="$1"
|
||||
local plugin_name="ps"
|
||||
local plugin_description="Manage container processes"
|
||||
|
||||
if [[ "$CMD" == "$plugin_name:help" ]]; then
|
||||
echo -e "Usage: dokku $plugin_name[:COMMAND]"
|
||||
echo ''
|
||||
echo "$plugin_description"
|
||||
echo ''
|
||||
echo 'Additional commands:'
|
||||
fn-help-content | sort | column -c2 -t -s,
|
||||
elif [[ $(ps -o command= $PPID) == *"--all"* ]]; then
|
||||
fn-help-content
|
||||
else
|
||||
cat <<help_desc
|
||||
$plugin_name, $plugin_description
|
||||
help_desc
|
||||
fi
|
||||
}
|
||||
|
||||
fn-help-content() {
|
||||
declare desc="return help content"
|
||||
cat <<help_content
|
||||
ps:inspect <app>, Displays a sanitized version of docker inspect for an app
|
||||
ps:scale <app> <proc>=<count> [<proc>=<count>...], Get/Set how many instances of a given process to run
|
||||
ps:start <app>, Start app container(s)
|
||||
ps:startall, Starts all apps via command line
|
||||
ps:stop <app>, Stop app container(s)
|
||||
ps:stopall, Stop all app container(s)
|
||||
ps:rebuild <app>, Rebuild an app from source
|
||||
ps:rebuildall, Rebuild all apps from source
|
||||
ps:report [<app>] [<flag>], Displays a process report for one or more apps
|
||||
ps:restart <app>, Restart app container(s)
|
||||
ps:restartall, Restart all deployed app containers
|
||||
ps:restore, Start previously running apps e.g. after reboot
|
||||
ps:restart-policy <app>, Shows the restart-policy for an app
|
||||
ps:set-restart-policy <app> <policy>, Sets app restart-policy
|
||||
help_content
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eo pipefail
|
||||
[[ $DOKKU_TRACE ]] && set -x
|
||||
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
|
||||
source "$PLUGIN_AVAILABLE_PATH/docker-options/functions"
|
||||
source "$PLUGIN_AVAILABLE_PATH/ps/functions"
|
||||
|
||||
trigger-ps-install() {
|
||||
declare desc="set the default restart policy for all applications if there is not one already set"
|
||||
declare trigger="install"
|
||||
local APPS="$(dokku_apps)"
|
||||
local APP
|
||||
|
||||
mkdir -p "${DOKKU_LIB_ROOT}/data/ps"
|
||||
chown -R "${DOKKU_SYSTEM_USER}:${DOKKU_SYSTEM_GROUP}" "${DOKKU_LIB_ROOT}/data/ps"
|
||||
|
||||
for APP in $APPS; do
|
||||
local RESTART_POLICIES=$(get_restart_policies "$(get_phase_file_path "deploy")")
|
||||
if [[ -z "$RESTART_POLICIES" ]]; then
|
||||
local passed_phases=(deploy)
|
||||
add_passed_docker_option passed_phases[@] "--restart=on-failure:10"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
trigger-ps-install "$@"
|
||||
@@ -1,18 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eo pipefail
|
||||
[[ $DOKKU_TRACE ]] && set -x
|
||||
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
|
||||
source "$PLUGIN_AVAILABLE_PATH/config/functions"
|
||||
source "$PLUGIN_AVAILABLE_PATH/ps/functions"
|
||||
|
||||
trigger-ps-post-app-clone() {
|
||||
declare desc="ps post-app-clone plugin trigger"
|
||||
declare trigger="post-app-clone"
|
||||
declare OLD_APP="$1" NEW_APP="$2"
|
||||
|
||||
if [[ "$SKIP_REBUILD" != "true" ]]; then
|
||||
ps_rebuild "$NEW_APP"
|
||||
fi
|
||||
}
|
||||
|
||||
trigger-ps-post-app-clone "$@"
|
||||
@@ -1,18 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eo pipefail
|
||||
[[ $DOKKU_TRACE ]] && set -x
|
||||
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
|
||||
source "$PLUGIN_AVAILABLE_PATH/config/functions"
|
||||
source "$PLUGIN_AVAILABLE_PATH/ps/functions"
|
||||
|
||||
trigger-ps-post-app-rename() {
|
||||
declare desc="ps post-app-rename plugin trigger"
|
||||
declare trigger="post-app-rename"
|
||||
declare OLD_APP="$1" NEW_APP="$2"
|
||||
|
||||
if [[ "$SKIP_REBUILD" != "true" ]]; then
|
||||
ps_rebuild "$NEW_APP"
|
||||
fi
|
||||
}
|
||||
|
||||
trigger-ps-post-app-rename "$@"
|
||||
@@ -1,20 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eo pipefail
|
||||
[[ $DOKKU_TRACE ]] && set -x
|
||||
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
|
||||
source "$PLUGIN_AVAILABLE_PATH/docker-options/functions"
|
||||
source "$PLUGIN_AVAILABLE_PATH/ps/functions"
|
||||
|
||||
trigger-ps-post-create() {
|
||||
declare desc="ps post-create plugin trigger"
|
||||
declare trigger="post-create"
|
||||
local APP="$1"
|
||||
|
||||
local passed_phases=(deploy)
|
||||
add_passed_docker_option passed_phases[@] "--restart=on-failure:10"
|
||||
|
||||
mkdir -p "${DOKKU_LIB_ROOT}/data/ps/${APP}"
|
||||
chown -R "${DOKKU_SYSTEM_USER}:${DOKKU_SYSTEM_GROUP}" "${DOKKU_LIB_ROOT}/data/ps/${APP}"
|
||||
}
|
||||
|
||||
trigger-ps-post-create "$@"
|
||||
@@ -1,24 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eo pipefail
|
||||
[[ $DOKKU_TRACE ]] && set -x
|
||||
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
|
||||
|
||||
trigger-ps-post-extract() {
|
||||
declare desc="ps post-extract plugin trigger"
|
||||
declare trigger="post-extract"
|
||||
declare APP="$1" TMP_WORK_DIR="$2" REV="$3"
|
||||
|
||||
if [[ ! -f "$TMP_WORK_DIR/Procfile" ]]; then
|
||||
return
|
||||
fi
|
||||
|
||||
pushd "$TMP_WORK_DIR" >/dev/null
|
||||
for process_type in $(procfile-util list); do
|
||||
if echo "$process_type" | grep -vqE '^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$'; then
|
||||
dokku_log_fail "Invalid process type name ($process_type)"
|
||||
fi
|
||||
done
|
||||
popd >/dev/null
|
||||
}
|
||||
|
||||
trigger-ps-post-extract "$@"
|
||||
@@ -1,16 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eo pipefail
|
||||
[[ $DOKKU_TRACE ]] && set -x
|
||||
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
|
||||
source "$PLUGIN_AVAILABLE_PATH/config/functions"
|
||||
source "$PLUGIN_AVAILABLE_PATH/ps/functions"
|
||||
|
||||
trigger-ps-post-stop() {
|
||||
declare desc="ps post-stop plugin trigger"
|
||||
declare trigger="post-stop"
|
||||
declare APP="$1"
|
||||
|
||||
DOKKU_QUIET_OUTPUT=1 config_set --no-restart "$APP" DOKKU_APP_RESTORE=0
|
||||
}
|
||||
|
||||
trigger-ps-post-stop "$@"
|
||||
@@ -1,16 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eo pipefail
|
||||
[[ $DOKKU_TRACE ]] && set -x
|
||||
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
|
||||
source "$PLUGIN_AVAILABLE_PATH/ps/functions"
|
||||
|
||||
trigger-ps-pre-deploy() {
|
||||
declare desc="ps pre-deploy plugin trigger"
|
||||
declare trigger="pre-deploy"
|
||||
declare APP="$1" IMAGE_TAG="$2"
|
||||
|
||||
extract_procfile "$APP" "$IMAGE_TAG"
|
||||
generate_scale_file "$APP" "$IMAGE_TAG"
|
||||
}
|
||||
|
||||
trigger-ps-pre-deploy "$@"
|
||||
@@ -1,25 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eo pipefail
|
||||
[[ $DOKKU_TRACE ]] && set -x
|
||||
source "$PLUGIN_AVAILABLE_PATH/ps/functions"
|
||||
|
||||
trigger-ps-procfile-extract() {
|
||||
declare desc="ps procfile-extract plugin trigger"
|
||||
declare trigger="procfile-extract"
|
||||
declare desc="extract procfile from a specified docker image"
|
||||
declare APP="$1" IMAGE="$2" FORCE_EXTRACT="$3" PROCFILE_PATH="$4"
|
||||
|
||||
if [[ -z "$PROCFILE_PATH" ]]; then
|
||||
PROCFILE_PATH="$DOKKU_LIB_ROOT/data/ps/$APP/Procfile.extracted"
|
||||
mkdir -p "${DOKKU_LIB_ROOT}/data/ps/${APP}"
|
||||
chown -R "${DOKKU_SYSTEM_USER}:${DOKKU_SYSTEM_GROUP}" "${DOKKU_LIB_ROOT}/data/ps/${APP}"
|
||||
fi
|
||||
|
||||
if [[ "$FORCE_EXTRACT" == "true" ]]; then
|
||||
plugn trigger procfile-remove "$APP" "$PROCFILE_PATH"
|
||||
fi
|
||||
|
||||
fn-procfile-extract "$IMAGE" "$PROCFILE_PATH"
|
||||
}
|
||||
|
||||
trigger-ps-procfile-extract "$@"
|
||||
@@ -1,19 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eo pipefail
|
||||
[[ $DOKKU_TRACE ]] && set -x
|
||||
source "$PLUGIN_AVAILABLE_PATH/ps/functions"
|
||||
|
||||
trigger-ps-procfile-get-command() {
|
||||
declare desc="ps procfile-get-command plugin trigger"
|
||||
declare trigger="procfile-get-command"
|
||||
declare desc="extract command from an app procfile"
|
||||
declare APP="$1" PROCESS_TYPE="$2" PORT="$3" PROCFILE_PATH="$4"
|
||||
|
||||
if [[ -z "$PROCFILE_PATH" ]]; then
|
||||
PROCFILE_PATH="$DOKKU_LIB_ROOT/data/ps/$APP/Procfile.extracted"
|
||||
fi
|
||||
|
||||
fn-procfile-get-command "$PROCFILE_PATH" "$PROCESS_TYPE" "$PORT"
|
||||
}
|
||||
|
||||
trigger-ps-procfile-get-command "$@"
|
||||
@@ -1,22 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eo pipefail
|
||||
[[ $DOKKU_TRACE ]] && set -x
|
||||
|
||||
trigger-ps-procfile-remove() {
|
||||
declare desc="ps procfile-remove plugin trigger"
|
||||
declare trigger="procfile-remove"
|
||||
declare desc="remove procfile for a given app"
|
||||
declare APP="$1" PROCFILE_PATH="$2"
|
||||
|
||||
if [[ -z "$PROCFILE_PATH" ]]; then
|
||||
PROCFILE_PATH="$DOKKU_LIB_ROOT/data/ps/$APP/Procfile.extracted"
|
||||
fi
|
||||
|
||||
if [[ ! -f "$PROCFILE_PATH" ]]; then
|
||||
return
|
||||
fi
|
||||
|
||||
rm -f "$PROCFILE_PATH" 2>/dev/null
|
||||
}
|
||||
|
||||
trigger-ps-procfile-remove "$@"
|
||||
148
plugins/ps/ps.go
Normal file
148
plugins/ps/ps.go
Normal file
@@ -0,0 +1,148 @@
|
||||
package ps
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/dokku/dokku/plugins/common"
|
||||
)
|
||||
|
||||
const RUN_IN_SERIAL = -1
|
||||
|
||||
type ParallelCommand func(string) error
|
||||
|
||||
var (
|
||||
// DefaultProperties is a map of all valid ps properties with corresponding default property values
|
||||
DefaultProperties = map[string]string{
|
||||
"restart-policy": "on-failure:10",
|
||||
}
|
||||
)
|
||||
|
||||
func RunCommandAgainstAllApps(command ParallelCommand, commandName string, runInSerial bool, parallelCount int) error {
|
||||
if runInSerial && parallelCount != RUN_IN_SERIAL {
|
||||
common.LogWarn("Ignoring --parallel value and running in serial mode")
|
||||
}
|
||||
|
||||
if runInSerial {
|
||||
return RunCommandAgainstAllAppsSerially(command, commandName)
|
||||
}
|
||||
|
||||
return RunCommandAgainstAllAppsInParallel(command, commandName, parallelCount)
|
||||
}
|
||||
|
||||
// TODO: implement me
|
||||
func RunCommandAgainstAllAppsInParallel(command ParallelCommand, commandName string, parallelCount int) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func RunCommandAgainstAllAppsSerially(command ParallelCommand, commandName string) error {
|
||||
apps, err := common.DokkuApps()
|
||||
if err != nil {
|
||||
common.LogWarn(err.Error())
|
||||
return nil
|
||||
}
|
||||
|
||||
errorCount := 0
|
||||
for _, appName := range apps {
|
||||
if err = command(appName); err != nil {
|
||||
errorCount += 1
|
||||
}
|
||||
}
|
||||
|
||||
if errorCount > 0 {
|
||||
return fmt.Errorf("%s command returned %d errors", commandName, errorCount)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Rebuild rebuilds app from base image
|
||||
func Rebuild(appName string) error {
|
||||
return common.PlugnTrigger("receive-app", []string{appName}...)
|
||||
}
|
||||
|
||||
// ReportSingleApp is an internal function that displays the ps report for one or more apps
|
||||
// TODO: implement me
|
||||
func ReportSingleApp(appName, infoFlag string) error {
|
||||
if err := common.VerifyAppName(appName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
policy, _ := getRestartPolicy(appName)
|
||||
if policy == "" {
|
||||
policy = DefaultProperties["restart-policy"]
|
||||
}
|
||||
|
||||
infoFlags := map[string]string{
|
||||
"--ps-restart-policy": policy,
|
||||
}
|
||||
|
||||
trimPrefix := false
|
||||
uppercaseFirstCharacter := true
|
||||
return common.ReportSingleApp("ps", appName, infoFlag, infoFlags, trimPrefix, uppercaseFirstCharacter)
|
||||
}
|
||||
|
||||
// Restart restarts the app
|
||||
func Restart(appName string) error {
|
||||
if !common.IsDeployed(appName) {
|
||||
common.LogWarn(fmt.Sprintf("App %s has not been deployed", appName))
|
||||
return nil
|
||||
}
|
||||
|
||||
return common.PlugnTrigger("release-and-deploy", []string{appName}...)
|
||||
}
|
||||
|
||||
// Start starts the app
|
||||
func Start(appName string) error {
|
||||
imageTag, _ := common.GetRunningImageTag(appName)
|
||||
|
||||
if !common.IsDeployed(appName) {
|
||||
common.LogWarn(fmt.Sprintf("App %s has not been deployed", appName))
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := common.PlugnTrigger("pre-start", []string{appName}...); err != nil {
|
||||
return fmt.Errorf("Failure in pre-start hook: %s", err)
|
||||
}
|
||||
|
||||
runningState := getRunningState(appName)
|
||||
|
||||
if runningState == "mixed" {
|
||||
common.LogWarn("App is running in mixed mode, releasing")
|
||||
}
|
||||
|
||||
if runningState != "true" {
|
||||
if err := common.PlugnTrigger("release-and-deploy", []string{appName, imageTag}...); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
common.LogWarn(fmt.Sprintf("App %s already running", appName))
|
||||
}
|
||||
|
||||
if err := common.PlugnTrigger("proxy-build-config", []string{appName}...); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Stop stops the app
|
||||
func Stop(appName string) error {
|
||||
if !common.IsDeployed(appName) {
|
||||
common.LogWarn(fmt.Sprintf("App %s has not been deployed", appName))
|
||||
return nil
|
||||
}
|
||||
|
||||
common.LogQuiet(fmt.Sprintf("Stopping %s", appName))
|
||||
scheduler := common.GetAppScheduler(appName)
|
||||
|
||||
if err := common.PlugnTrigger("scheduler-stop", []string{scheduler, appName}...); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := common.PlugnTrigger("post-stop", []string{appName}...); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
source "$PLUGIN_AVAILABLE_PATH/ps/internal-functions"
|
||||
set -eo pipefail
|
||||
[[ $DOKKU_TRACE ]] && set -x
|
||||
|
||||
cmd-ps-report-single "$@"
|
||||
62
plugins/ps/src/commands/commands.go
Normal file
62
plugins/ps/src/commands/commands.go
Normal file
@@ -0,0 +1,62 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/dokku/dokku/plugins/common"
|
||||
)
|
||||
|
||||
const (
|
||||
helpHeader = `Usage: dokku ps[:COMMAND]
|
||||
|
||||
Manage app processes
|
||||
|
||||
Additional commands:`
|
||||
|
||||
helpContent = `
|
||||
ps:inspect <app>, Displays a sanitized version of docker inspect for an app
|
||||
ps:scale <app> <proc>=<count> [<proc>=<count>...], Get/Set how many instances of a given process to run
|
||||
ps:start [--parallel count] [--serial] [--all|<app>], Start an app
|
||||
ps:stop [--parallel count] [--serial] [--all|<app>], Stop an app
|
||||
ps:rebuild [--parallel count] [--serial] [--all|<app>], Rebuilds an app from source
|
||||
ps:report [<app>] [<flag>], Displays a process report for one or more apps
|
||||
ps:restart [--parallel count] [--serial] [--all|<app>], Restart an app
|
||||
ps:restore, Start previously running apps e.g. after reboot
|
||||
`
|
||||
)
|
||||
|
||||
func main() {
|
||||
flag.Usage = usage
|
||||
flag.Parse()
|
||||
|
||||
cmd := flag.Arg(0)
|
||||
switch cmd {
|
||||
case "ps", "ps:help":
|
||||
usage()
|
||||
case "help":
|
||||
command := common.NewShellCmd(fmt.Sprintf("ps -o command= %d", os.Getppid()))
|
||||
command.ShowOutput = false
|
||||
output, err := command.Output()
|
||||
|
||||
if err == nil && strings.Contains(string(output), "--all") {
|
||||
fmt.Println(helpContent)
|
||||
} else {
|
||||
fmt.Print("\n ps, Manage app processes\n")
|
||||
}
|
||||
default:
|
||||
dokkuNotImplementExitCode, err := strconv.Atoi(os.Getenv("DOKKU_NOT_IMPLEMENTED_EXIT"))
|
||||
if err != nil {
|
||||
fmt.Println("failed to retrieve DOKKU_NOT_IMPLEMENTED_EXIT environment variable")
|
||||
dokkuNotImplementExitCode = 10
|
||||
}
|
||||
os.Exit(dokkuNotImplementExitCode)
|
||||
}
|
||||
}
|
||||
|
||||
func usage() {
|
||||
common.CommandUsage(helpHeader, helpContent)
|
||||
}
|
||||
92
plugins/ps/src/subcommands/subcommands.go
Normal file
92
plugins/ps/src/subcommands/subcommands.go
Normal file
@@ -0,0 +1,92 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/dokku/dokku/plugins/common"
|
||||
"github.com/dokku/dokku/plugins/ps"
|
||||
)
|
||||
|
||||
// main entrypoint to all subcommands
|
||||
func main() {
|
||||
parts := strings.Split(os.Args[0], "/")
|
||||
subcommand := parts[len(parts)-1]
|
||||
|
||||
var err error
|
||||
switch subcommand {
|
||||
case "inspect":
|
||||
args := flag.NewFlagSet("ps:inspect", flag.ExitOnError)
|
||||
args.Parse(os.Args[2:])
|
||||
appName := args.Arg(0)
|
||||
err = ps.CommandInspect(appName)
|
||||
case "rebuild":
|
||||
args := flag.NewFlagSet("ps:rebuild", flag.ExitOnError)
|
||||
allApps := args.Bool("all", false, "--all: restart all apps")
|
||||
parallelCount := args.Int("parallel", ps.RUN_IN_SERIAL, "--parallel: number of apps to restart in parallel, -1 to match cpu count")
|
||||
runInSerial := args.Bool("serial", false, "--serial: restart apps serially")
|
||||
args.Parse(os.Args[2:])
|
||||
appName := args.Arg(0)
|
||||
err = ps.CommandRebuild(appName, *allApps, *runInSerial, *parallelCount)
|
||||
case "report":
|
||||
args := flag.NewFlagSet("ps:report", flag.ExitOnError)
|
||||
args.Parse(os.Args[2:])
|
||||
appName := args.Arg(0)
|
||||
infoFlag := args.Arg(1)
|
||||
err = ps.CommandReport(appName, infoFlag)
|
||||
case "restart":
|
||||
args := flag.NewFlagSet("ps:restart", flag.ExitOnError)
|
||||
allApps := args.Bool("all", false, "--all: restart all apps")
|
||||
parallelCount := args.Int("parallel", ps.RUN_IN_SERIAL, "--parallel: number of apps to restart in parallel, -1 to match cpu count")
|
||||
runInSerial := args.Bool("serial", false, "--serial: restart apps serially")
|
||||
args.Parse(os.Args[2:])
|
||||
appName := args.Arg(0)
|
||||
err = ps.CommandRestart(appName, *allApps, *runInSerial, *parallelCount)
|
||||
case "restore":
|
||||
args := flag.NewFlagSet("ps:restore", flag.ExitOnError)
|
||||
args.Parse(os.Args[2:])
|
||||
appName := args.Arg(0)
|
||||
err = ps.CommandRestore(appName)
|
||||
case "retire":
|
||||
args := flag.NewFlagSet("ps:retire", flag.ExitOnError)
|
||||
args.Parse(os.Args[2:])
|
||||
err = ps.CommandRetire()
|
||||
case "scale":
|
||||
args := flag.NewFlagSet("ps:scale", flag.ExitOnError)
|
||||
args.Parse(os.Args[2:])
|
||||
appName := args.Arg(0)
|
||||
_, processTuples := common.ShiftString(args.Args())
|
||||
err = ps.CommandScale(appName, processTuples)
|
||||
case "set":
|
||||
args := flag.NewFlagSet("ps:set", flag.ExitOnError)
|
||||
args.Parse(os.Args[2:])
|
||||
appName := args.Arg(0)
|
||||
property := args.Arg(1)
|
||||
value := args.Arg(2)
|
||||
err = ps.CommandSet(appName, property, value)
|
||||
case "start":
|
||||
args := flag.NewFlagSet("ps:start", flag.ExitOnError)
|
||||
allApps := args.Bool("all", false, "--all: restart all apps")
|
||||
parallelCount := args.Int("parallel", ps.RUN_IN_SERIAL, "--parallel: number of apps to restart in parallel, -1 to match cpu count")
|
||||
runInSerial := args.Bool("serial", false, "--serial: restart apps serially")
|
||||
args.Parse(os.Args[2:])
|
||||
appName := args.Arg(0)
|
||||
err = ps.CommandStart(appName, *allApps, *runInSerial, *parallelCount)
|
||||
case "stop":
|
||||
args := flag.NewFlagSet("ps:stop", flag.ExitOnError)
|
||||
allApps := args.Bool("all", false, "--all: restart all apps")
|
||||
parallelCount := args.Int("parallel", ps.RUN_IN_SERIAL, "--parallel: number of apps to restart in parallel, -1 to match cpu count")
|
||||
runInSerial := args.Bool("serial", false, "--serial: restart apps serially")
|
||||
args.Parse(os.Args[2:])
|
||||
appName := args.Arg(0)
|
||||
err = ps.CommandStop(appName, *allApps, *runInSerial, *parallelCount)
|
||||
default:
|
||||
common.LogFail(fmt.Sprintf("Invalid plugin subcommand call: %s", subcommand))
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
common.LogFail(err.Error())
|
||||
}
|
||||
}
|
||||
80
plugins/ps/src/triggers/triggers.go
Normal file
80
plugins/ps/src/triggers/triggers.go
Normal file
@@ -0,0 +1,80 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/dokku/dokku/plugins/common"
|
||||
"github.com/dokku/dokku/plugins/ps"
|
||||
)
|
||||
|
||||
// main entrypoint to all triggers
|
||||
func main() {
|
||||
parts := strings.Split(os.Args[0], "/")
|
||||
trigger := parts[len(parts)-1]
|
||||
flag.Parse()
|
||||
|
||||
var err error
|
||||
switch trigger {
|
||||
case "app-restart":
|
||||
appName := flag.Arg(0)
|
||||
err = ps.TriggerAppRestart(appName)
|
||||
case "core-post-deploy":
|
||||
appName := flag.Arg(0)
|
||||
err = ps.TriggerCorePostDeploy(appName)
|
||||
case "install":
|
||||
err = ps.TriggerInstall()
|
||||
case "post-app-clone":
|
||||
oldAppName := flag.Arg(0)
|
||||
newAppName := flag.Arg(1)
|
||||
err = ps.TriggerPostAppClone(oldAppName, newAppName)
|
||||
case "post-app-rename":
|
||||
oldAppName := flag.Arg(0)
|
||||
newAppName := flag.Arg(1)
|
||||
err = ps.TriggerPostAppRename(oldAppName, newAppName)
|
||||
case "post-create":
|
||||
appName := flag.Arg(0)
|
||||
err = ps.TriggerPostCreate(appName)
|
||||
case "post-delete":
|
||||
appName := flag.Arg(0)
|
||||
err = ps.TriggerPostDelete(appName)
|
||||
case "post-extract":
|
||||
appName := flag.Arg(0)
|
||||
tmpWorkDir := flag.Arg(1)
|
||||
err = ps.TriggerPostExtract(appName, tmpWorkDir)
|
||||
case "post-stop":
|
||||
appName := flag.Arg(0)
|
||||
err = ps.TriggerPostStop(appName)
|
||||
case "pre-deploy":
|
||||
appName := flag.Arg(0)
|
||||
imageTag := flag.Arg(1)
|
||||
err = ps.TriggerPreDeploy(appName, imageTag)
|
||||
case "procfile-extract":
|
||||
appName := flag.Arg(0)
|
||||
image := flag.Arg(1)
|
||||
forceExtract := common.ToBool(flag.Arg(2))
|
||||
procfilePath := flag.Arg(3)
|
||||
err = ps.TriggerProcfileExtract(appName, image, forceExtract, procfilePath)
|
||||
case "procfile-get-command":
|
||||
appName := flag.Arg(0)
|
||||
processType := flag.Arg(1)
|
||||
port := common.ToInt(flag.Arg(2), 5000)
|
||||
procfilePath := flag.Arg(3)
|
||||
err = ps.TriggerProcfileGetCommand(appName, processType, port, procfilePath)
|
||||
case "procfile-remove":
|
||||
appName := flag.Arg(0)
|
||||
procfilePath := flag.Arg(1)
|
||||
err = ps.TriggerProcfileRemove(appName, procfilePath)
|
||||
case "report":
|
||||
appName := flag.Arg(0)
|
||||
err = ps.ReportSingleApp(appName, "")
|
||||
default:
|
||||
common.LogFail(fmt.Sprintf("Invalid plugin trigger call: %s", trigger))
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
common.LogFail(err.Error())
|
||||
}
|
||||
}
|
||||
215
plugins/ps/subcommands.go
Normal file
215
plugins/ps/subcommands.go
Normal file
@@ -0,0 +1,215 @@
|
||||
package ps
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
dockeroptions "github.com/dokku/dokku/plugins/docker-options"
|
||||
|
||||
"github.com/dokku/dokku/plugins/common"
|
||||
"github.com/ryanuber/columnize"
|
||||
)
|
||||
|
||||
func CommandInspect(appName string) error {
|
||||
if appName == "" {
|
||||
return errors.New("Please specify an app to run the command on")
|
||||
}
|
||||
|
||||
if err := common.VerifyAppName(appName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
scheduler := common.GetAppScheduler(appName)
|
||||
return common.PlugnTrigger("scheduler-inspect", []string{scheduler, appName}...)
|
||||
}
|
||||
|
||||
func CommandRebuild(appName string, allApps bool, runInSerial bool, parallelCount int) error {
|
||||
if allApps {
|
||||
return RunCommandAgainstAllApps(Rebuild, "rebuild", runInSerial, parallelCount)
|
||||
}
|
||||
|
||||
if appName == "" {
|
||||
return errors.New("Please specify an app to run the command on")
|
||||
}
|
||||
|
||||
if err := common.VerifyAppName(appName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return Rebuild(appName)
|
||||
}
|
||||
|
||||
// CommandReport displays a ps report for one or more apps
|
||||
func CommandReport(appName string, infoFlag string) error {
|
||||
if strings.HasPrefix(appName, "--") {
|
||||
infoFlag = appName
|
||||
appName = ""
|
||||
}
|
||||
|
||||
if len(appName) == 0 {
|
||||
apps, err := common.DokkuApps()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, appName := range apps {
|
||||
if err := ReportSingleApp(appName, infoFlag); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
return ReportSingleApp(appName, infoFlag)
|
||||
}
|
||||
|
||||
func CommandRestart(appName string, allApps bool, runInSerial bool, parallelCount int) error {
|
||||
if allApps {
|
||||
return RunCommandAgainstAllApps(Restart, "restart", runInSerial, parallelCount)
|
||||
}
|
||||
|
||||
if appName == "" {
|
||||
return errors.New("Please specify an app to run the command on")
|
||||
}
|
||||
|
||||
if err := common.VerifyAppName(appName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return Restart(appName)
|
||||
}
|
||||
|
||||
// TODO: implement me
|
||||
func CommandRestore(appName string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO: implement me
|
||||
func CommandRetire() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO: implement me
|
||||
func CommandScale(appName string, processTuples []string) error {
|
||||
if appName == "" {
|
||||
return errors.New("Please specify an app to run the command on")
|
||||
}
|
||||
|
||||
if err := common.VerifyAppName(appName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
procfilePath := getProcfilePath(appName)
|
||||
scalefilePath := getScalefilePath(appName)
|
||||
if !common.FileExists(procfilePath) {
|
||||
image := common.GetAppImageRepo(appName)
|
||||
extractProcfile(appName, image, procfilePath)
|
||||
}
|
||||
|
||||
if !common.FileExists(scalefilePath) {
|
||||
err := common.SuppressOutput(func() error {
|
||||
return generateScalefile(appName, scalefilePath)
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else if common.FileExists(procfilePath) {
|
||||
if err := updateScalefile(appName, []string{}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if len(processTuples) == 0 {
|
||||
lines, err := common.FileToSlice(scalefilePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
common.LogInfo1Quiet(fmt.Sprintf("Scaling for %s", appName))
|
||||
config := columnize.DefaultConfig()
|
||||
config.Delim = "="
|
||||
config.Glue = ": "
|
||||
config.Prefix = " "
|
||||
config.Empty = ""
|
||||
|
||||
content := []string{}
|
||||
if os.Getenv("DOKKU_QUIET_OUTPUT") == "" {
|
||||
content = append(content, "proctype=qty","--------=---")
|
||||
}
|
||||
|
||||
sort.Strings(lines)
|
||||
for _, line := range lines {
|
||||
content = append(content, line)
|
||||
}
|
||||
|
||||
for _, line := range content {
|
||||
s := strings.Split(line, "=")
|
||||
common.Log(fmt.Sprintf("%s %s", common.RightPad(fmt.Sprintf("%s:", s[0]), 5, " "), s[1]))
|
||||
}
|
||||
} else {
|
||||
if !canScaleApp(appName) {
|
||||
return fmt.Errorf("App %s contains DOKKU_SCALE file and cannot be manually scaled", appName)
|
||||
}
|
||||
|
||||
if err := updateScalefile(appName, processTuples); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
imageTag, err := common.GetRunningImageTag(appName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return common.PlugnTrigger("release-and-deploy", []string{appName, imageTag}...)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO: implement me
|
||||
func CommandSet(appName string, property string, value string) error {
|
||||
if property == "restart-policy" {
|
||||
if !isValidRestartPolicy(value) {
|
||||
return errors.New("Invalid restart-policy specified")
|
||||
}
|
||||
|
||||
common.LogInfo2Quiet(fmt.Sprintf("Setting %s to %s", property, value))
|
||||
return dockeroptions.SetDockerOptionForPhases(appName, []string{"deploy"}, "restart", value)
|
||||
}
|
||||
|
||||
common.CommandPropertySet("ps", appName, property, value, DefaultProperties)
|
||||
return nil
|
||||
}
|
||||
|
||||
func CommandStart(appName string, allApps bool, runInSerial bool, parallelCount int) error {
|
||||
if allApps {
|
||||
return RunCommandAgainstAllApps(Start, "start", runInSerial, parallelCount)
|
||||
}
|
||||
|
||||
if appName == "" {
|
||||
return errors.New("Please specify an app to run the command on")
|
||||
}
|
||||
|
||||
if err := common.VerifyAppName(appName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return Start(appName)
|
||||
}
|
||||
|
||||
func CommandStop(appName string, allApps bool, runInSerial bool, parallelCount int) error {
|
||||
if allApps {
|
||||
return RunCommandAgainstAllApps(Stop, "stop", runInSerial, parallelCount)
|
||||
}
|
||||
|
||||
if appName == "" {
|
||||
return errors.New("Please specify an app to run the command on")
|
||||
}
|
||||
|
||||
if err := common.VerifyAppName(appName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return Stop(appName)
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eo pipefail
|
||||
[[ $DOKKU_TRACE ]] && set -x
|
||||
source "$PLUGIN_AVAILABLE_PATH/ps/help-functions"
|
||||
|
||||
cmd-ps-help "ps:help"
|
||||
@@ -1,6 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
source "$PLUGIN_AVAILABLE_PATH/ps/internal-functions"
|
||||
set -eo pipefail
|
||||
[[ $DOKKU_TRACE ]] && set -x
|
||||
|
||||
cmd-ps-inspect "$@"
|
||||
@@ -1,22 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eo pipefail
|
||||
[[ $DOKKU_TRACE ]] && set -x
|
||||
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
|
||||
source "$PLUGIN_AVAILABLE_PATH/ps/functions"
|
||||
|
||||
cmd-ps-rebuild() {
|
||||
declare desc="rebuilds an app from source"
|
||||
declare cmd="ps:rebuild"
|
||||
[[ "$1" == "$cmd" ]] && shift 1
|
||||
declare APP="$1"
|
||||
|
||||
[[ -z "$APP" ]] && dokku_log_fail "Please specify an app to run the command on"
|
||||
|
||||
if (is_deployed "$APP"); then
|
||||
ps_rebuild "$APP"
|
||||
else
|
||||
dokku_log_warn "App $APP has not been deployed"
|
||||
fi
|
||||
}
|
||||
|
||||
cmd-ps-rebuild "$@"
|
||||
@@ -1,15 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eo pipefail
|
||||
[[ $DOKKU_TRACE ]] && set -x
|
||||
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
|
||||
source "$PLUGIN_AVAILABLE_PATH/ps/internal-functions"
|
||||
|
||||
cmd-ps-rebuildall() {
|
||||
declare desc="rebuilds all apps from source"
|
||||
declare cmd="ps:rebuildall"
|
||||
[[ "$1" == "$cmd" ]] && shift 1
|
||||
|
||||
fn-ps-parallel-cmd "rebuild"
|
||||
}
|
||||
|
||||
cmd-ps-rebuildall "$@"
|
||||
@@ -1,6 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
source "$PLUGIN_AVAILABLE_PATH/ps/internal-functions"
|
||||
set -eo pipefail
|
||||
[[ $DOKKU_TRACE ]] && set -x
|
||||
|
||||
cmd-ps-report "$@"
|
||||
@@ -1,16 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eo pipefail
|
||||
[[ $DOKKU_TRACE ]] && set -x
|
||||
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
|
||||
|
||||
cmd-ps-restart() {
|
||||
declare desc="restarts app via command line"
|
||||
declare cmd="ps:restart"
|
||||
[[ "$1" == "$cmd" ]] && shift 1
|
||||
declare APP="$1"
|
||||
|
||||
[[ -z "$APP" ]] && dokku_log_fail "Please specify an app to run the command on"
|
||||
plugn trigger app-restart "$APP"
|
||||
}
|
||||
|
||||
cmd-ps-restart "$@"
|
||||
@@ -1,22 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eo pipefail
|
||||
[[ $DOKKU_TRACE ]] && set -x
|
||||
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
|
||||
source "$PLUGIN_AVAILABLE_PATH/docker-options/functions"
|
||||
source "$PLUGIN_AVAILABLE_PATH/ps/functions"
|
||||
|
||||
cmd-ps-restart-policy() {
|
||||
declare desc="shows the restart-policy for an app"
|
||||
declare cmd="ps:restart-policy"
|
||||
[[ "$1" == "$cmd" ]] && shift 1
|
||||
declare APP="$1"
|
||||
local passed_phases="deploy"
|
||||
|
||||
[[ -z "$APP" ]] && dokku_log_fail "Please specify an app to run the command on"
|
||||
verify_app_name "$APP"
|
||||
|
||||
dokku_log_info2_quiet "$APP restart-policy:"
|
||||
get_restart_policies "$(get_phase_file_path "$passed_phases")"
|
||||
}
|
||||
|
||||
cmd-ps-restart-policy "$@"
|
||||
@@ -1,15 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eo pipefail
|
||||
[[ $DOKKU_TRACE ]] && set -x
|
||||
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
|
||||
source "$PLUGIN_AVAILABLE_PATH/ps/internal-functions"
|
||||
|
||||
cmd-ps-restartall() {
|
||||
declare desc="restarts all apps via command line"
|
||||
declare cmd="ps:restartall"
|
||||
[[ "$1" == "$cmd" ]] && shift 1
|
||||
|
||||
fn-ps-parallel-cmd "restart"
|
||||
}
|
||||
|
||||
cmd-ps-restartall "$@"
|
||||
@@ -1,40 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eo pipefail
|
||||
[[ $DOKKU_TRACE ]] && set -x
|
||||
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
|
||||
source "$PLUGIN_AVAILABLE_PATH/config/functions"
|
||||
source "$PLUGIN_AVAILABLE_PATH/ps/functions"
|
||||
source "$PLUGIN_AVAILABLE_PATH/ps/internal-functions"
|
||||
|
||||
cmd-ps-restore() {
|
||||
declare desc="starts all apps with DOKKU_APP_RESTORE not set to 0 via command line"
|
||||
declare cmd="ps:restore"
|
||||
[[ "$1" == "$cmd" ]] && shift 1
|
||||
declare APP="$1"
|
||||
local DOKKU_SCHEDULER
|
||||
|
||||
DOKKU_SCHEDULER=$(get_app_scheduler "$APP")
|
||||
plugn trigger pre-restore "$DOKKU_SCHEDULER" "$APP"
|
||||
|
||||
if [[ -n "$APP" ]]; then
|
||||
plugn trigger proxy-clear-config "$APP"
|
||||
|
||||
if ! (is_deployed "$APP"); then
|
||||
dokku_log_warn "App $APP has not been deployed"
|
||||
return
|
||||
fi
|
||||
|
||||
DOKKU_APP_RESTORE="$(config_get "$APP" DOKKU_APP_RESTORE || true)"
|
||||
if [[ $DOKKU_APP_RESTORE != 0 ]]; then
|
||||
ps_restore "$APP" || dokku_log_warn "dokku ps:restore ${APP} failed"
|
||||
fi
|
||||
else
|
||||
for APP in $(dokku_apps); do
|
||||
plugn trigger proxy-clear-config "$APP"
|
||||
done
|
||||
|
||||
fn-ps-parallel-cmd "restore"
|
||||
fi
|
||||
}
|
||||
|
||||
cmd-ps-restore "$@"
|
||||
@@ -1,20 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eo pipefail
|
||||
[[ $DOKKU_TRACE ]] && set -x
|
||||
source "$PLUGIN_AVAILABLE_PATH/config/functions"
|
||||
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
|
||||
|
||||
cmd-ps-retire() {
|
||||
declare desc="ensures old containers are retired"
|
||||
declare cmd="ps:retire"
|
||||
[[ "$1" == "$cmd" ]] && shift 1
|
||||
|
||||
local LOCK_FILE="${DOKKU_LIB_ROOT}/data/ps/retire"
|
||||
local DOKKU_SCHEDULER=$(config_get "--global" DOKKU_SCHEDULER || echo "docker-local")
|
||||
|
||||
acquire_advisory_lock "$LOCK_FILE" "exclusive" "" "Failed to acquire ps:retire lock"
|
||||
plugn trigger scheduler-retire "$DOKKU_SCHEDULER"
|
||||
release_advisory_lock "$LOCK_FILE"
|
||||
}
|
||||
|
||||
cmd-ps-retire "$@"
|
||||
@@ -1,17 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eo pipefail
|
||||
[[ $DOKKU_TRACE ]] && set -x
|
||||
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
|
||||
source "$PLUGIN_AVAILABLE_PATH/ps/functions"
|
||||
|
||||
cmd-ps-scale() {
|
||||
declare desc="sets app scaling config via command line"
|
||||
declare cmd="ps:scale"
|
||||
[[ "$1" == "$cmd" ]] && shift 1
|
||||
declare APP="$1"
|
||||
|
||||
[[ -z "$APP" ]] && dokku_log_fail "Please specify an app to run the command on"
|
||||
ps_scale "$@"
|
||||
}
|
||||
|
||||
cmd-ps-scale "$@"
|
||||
@@ -1,34 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eo pipefail
|
||||
[[ $DOKKU_TRACE ]] && set -x
|
||||
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
|
||||
source "$PLUGIN_AVAILABLE_PATH/docker-options/functions"
|
||||
source "$PLUGIN_AVAILABLE_PATH/ps/functions"
|
||||
|
||||
cmd-ps-set-restart-policy() {
|
||||
declare desc="sets app restart-policy"
|
||||
declare cmd="ps:set-restart-policy"
|
||||
[[ "$1" == "$cmd" ]] && shift 1
|
||||
declare APP="$1" RESTART_POLICY="$2"
|
||||
|
||||
[[ -z "$APP" ]] && dokku_log_fail "Please specify an app to run the command on"
|
||||
verify_app_name "$APP"
|
||||
local RE_RESTART_POLICY="^(no|unless-stopped|always|on-failure(:[1-9][0-9]*)?)$"
|
||||
|
||||
if [[ ! "$RESTART_POLICY" =~ $RE_RESTART_POLICY ]]; then
|
||||
dokku_log_fail "Please specify an valid restart policy matching the following regex: ${RE_RESTART_POLICY}"
|
||||
fi
|
||||
|
||||
local RESTART_POLICIES=$(get_raw_restart_policies "$(get_phase_file_path "deploy")")
|
||||
local passed_phases=(deploy)
|
||||
|
||||
for policy in $RESTART_POLICIES; do
|
||||
remove_passed_docker_option passed_phases[@] "$policy"
|
||||
done
|
||||
|
||||
dokku_log_info1_quiet "Setting restart policy: ${RESTART_POLICY}"
|
||||
local passed_phases=(deploy)
|
||||
add_passed_docker_option passed_phases[@] "--restart=${RESTART_POLICY}"
|
||||
}
|
||||
|
||||
cmd-ps-set-restart-policy "$@"
|
||||
@@ -1,17 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eo pipefail
|
||||
[[ $DOKKU_TRACE ]] && set -x
|
||||
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
|
||||
source "$PLUGIN_AVAILABLE_PATH/ps/functions"
|
||||
|
||||
cmd-ps-start() {
|
||||
declare desc="starts app via command line"
|
||||
declare cmd="ps:start"
|
||||
[[ "$1" == "$cmd" ]] && shift 1
|
||||
declare APP="$1"
|
||||
|
||||
[[ -z "$APP" ]] && dokku_log_fail "Please specify an app to run the command on"
|
||||
ps_start "$APP"
|
||||
}
|
||||
|
||||
cmd-ps-start "$@"
|
||||
@@ -1,15 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eo pipefail
|
||||
[[ $DOKKU_TRACE ]] && set -x
|
||||
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
|
||||
source "$PLUGIN_AVAILABLE_PATH/ps/internal-functions"
|
||||
|
||||
cmd-ps-startall() {
|
||||
declare desc="starts all apps via command line"
|
||||
declare cmd="ps:startall"
|
||||
[[ "$1" == "$cmd" ]] && shift 1
|
||||
|
||||
fn-ps-parallel-cmd "start"
|
||||
}
|
||||
|
||||
cmd-ps-startall "$@"
|
||||
@@ -1,17 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eo pipefail
|
||||
[[ $DOKKU_TRACE ]] && set -x
|
||||
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
|
||||
source "$PLUGIN_AVAILABLE_PATH/ps/functions"
|
||||
|
||||
cmd-ps-stop() {
|
||||
declare desc="stops app via command line"
|
||||
declare cmd="ps:stop"
|
||||
[[ "$1" == "$cmd" ]] && shift 1
|
||||
declare APP="$1"
|
||||
|
||||
[[ -z "$APP" ]] && dokku_log_fail "Please specify an app to run the command on"
|
||||
ps_stop "$APP"
|
||||
}
|
||||
|
||||
cmd-ps-stop "$@"
|
||||
@@ -1,15 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eo pipefail
|
||||
[[ $DOKKU_TRACE ]] && set -x
|
||||
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
|
||||
source "$PLUGIN_AVAILABLE_PATH/ps/internal-functions"
|
||||
|
||||
cmd-ps-stopall() {
|
||||
declare desc="stops all apps via command line"
|
||||
declare cmd="ps:stopall"
|
||||
[[ "$1" == "$cmd" ]] && shift 1
|
||||
|
||||
fn-ps-parallel-cmd "stop"
|
||||
}
|
||||
|
||||
cmd-ps-stopall "$@"
|
||||
193
plugins/ps/triggers.go
Normal file
193
plugins/ps/triggers.go
Normal file
@@ -0,0 +1,193 @@
|
||||
package ps
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/dokku/dokku/plugins/common"
|
||||
"github.com/dokku/dokku/plugins/config"
|
||||
dockeroptions "github.com/dokku/dokku/plugins/docker-options"
|
||||
sh "github.com/codeskyblue/go-sh"
|
||||
)
|
||||
|
||||
func TriggerAppRestart(appName string) error {
|
||||
return Restart(appName)
|
||||
}
|
||||
|
||||
func TriggerCorePostDeploy(appName string) error {
|
||||
if err := removeProcfile(appName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
entries := map[string]string{
|
||||
"DOKKU_APP_RESTORE": "1",
|
||||
}
|
||||
|
||||
return common.SuppressOutput(func() error {
|
||||
return config.SetMany(appName, entries, false)
|
||||
})
|
||||
}
|
||||
|
||||
func TriggerInstall() error {
|
||||
directory := filepath.Join(common.MustGetEnv("DOKKU_LIB_ROOT"), "data", "ps")
|
||||
if err := os.MkdirAll(directory, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := common.SetPermissions(directory, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
apps, err := common.DokkuApps()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, appName := range apps {
|
||||
policies, err := getRestartPolicy(appName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(policies) != 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
if err := dockeroptions.AddDockerOptionToPhases(appName, []string{"deploy"}, "--restart=on-failure:10"); err != nil {
|
||||
common.LogWarn(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func TriggerPostAppClone(oldAppName string, newAppName string) error {
|
||||
if os.Getenv("SKIP_REBUILD") == "true" {
|
||||
return nil
|
||||
}
|
||||
|
||||
return Rebuild(newAppName)
|
||||
}
|
||||
|
||||
func TriggerPostAppRename(oldAppName string, newAppName string) error {
|
||||
if os.Getenv("SKIP_REBUILD") == "true" {
|
||||
return nil
|
||||
}
|
||||
|
||||
return Rebuild(newAppName)
|
||||
}
|
||||
|
||||
func TriggerPostCreate(appName string) error {
|
||||
if err := dockeroptions.AddDockerOptionToPhases(appName, []string{"deploy"}, "--restart=on-failure:10"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
directory := filepath.Join(common.MustGetEnv("DOKKU_LIB_ROOT"), "data", "ps", appName)
|
||||
if err := os.MkdirAll(directory, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := common.SetPermissions(directory, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// TriggerPostDelete destroys the ps properties for a given app container
|
||||
func TriggerPostDelete(appName string) error {
|
||||
return common.PropertyDestroy("ps", appName)
|
||||
}
|
||||
|
||||
func TriggerPostExtract(appName string, tempWorkDir string) error {
|
||||
procfile := filepath.Join(tempWorkDir, "Procfile")
|
||||
if !common.FileExists(procfile) {
|
||||
return nil
|
||||
}
|
||||
|
||||
b, err := sh.Command("procfile-util", "check", "-P", procfile).CombinedOutput()
|
||||
if err != nil {
|
||||
return fmt.Errorf(strings.TrimSpace(string(b[:])))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func TriggerPostStop(appName string) error {
|
||||
entries := map[string]string{
|
||||
"DOKKU_APP_RESTORE": "0",
|
||||
}
|
||||
|
||||
return common.SuppressOutput(func() error {
|
||||
return config.SetMany(appName, entries, false)
|
||||
})
|
||||
}
|
||||
|
||||
func TriggerPreDeploy(appName string, imageTag string) error {
|
||||
image := common.GetAppImageRepo(appName)
|
||||
removeProcfile(appName)
|
||||
|
||||
procfilePath := getProcfilePath(appName)
|
||||
if err := extractProcfile(appName, image, procfilePath); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := extractOrGenerateScalefile(appName, imageTag); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func TriggerProcfileExtract(appName string, image string, forceExtract bool, procfilePath string) error {
|
||||
if procfilePath == "" {
|
||||
directory := filepath.Join(common.MustGetEnv("DOKKU_LIB_ROOT"), "data", "ps", appName)
|
||||
if err := os.MkdirAll(directory, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := common.SetPermissions(directory, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
procfilePath = getProcfilePath(appName)
|
||||
}
|
||||
|
||||
if forceExtract {
|
||||
if err := common.PlugnTrigger("procfile-remove", []string{appName, procfilePath}...); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return extractProcfile(appName, image, procfilePath)
|
||||
}
|
||||
|
||||
func TriggerProcfileGetCommand(appName string, processType string, port int, procfilePath string) error {
|
||||
if procfilePath == "" {
|
||||
procfilePath = getProcfilePath(appName)
|
||||
}
|
||||
|
||||
command, err := getProcfileCommand(procfilePath, processType, port)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if command != "" {
|
||||
fmt.Printf("%s\n", command)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func TriggerProcfileRemove(appName string, procfilePath string) error {
|
||||
if procfilePath == "" {
|
||||
procfilePath = getProcfilePath(appName)
|
||||
}
|
||||
|
||||
if !common.FileExists(procfilePath) {
|
||||
return nil
|
||||
}
|
||||
|
||||
os.Remove(procfilePath)
|
||||
return nil
|
||||
}
|
||||
@@ -16,13 +16,13 @@ teardown() {
|
||||
run /bin/bash -c "dokku ps"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_output_contains "Manage container processes"
|
||||
assert_output_contains "Manage app processes"
|
||||
help_output="$output"
|
||||
|
||||
run /bin/bash -c "dokku ps:help"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_output_contains "Manage container processes"
|
||||
assert_output_contains "Manage app processes"
|
||||
assert_output "$help_output"
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ EOF
|
||||
run /bin/bash -c "dokku --quiet ps:scale $TEST_APP"
|
||||
output=$(echo "$output" | tr -s " ")
|
||||
echo "output: ($output)"
|
||||
assert_output $'cron: 0 \ncustom: 0 \nrelease: 0 \nweb: 1 \nworker: 0 '
|
||||
assert_output $'cron: 0\ncustom: 0\nrelease: 0\nweb: 1\nworker: 0'
|
||||
|
||||
pushd $TMP
|
||||
echo scaletest: sleep infinity >> Procfile
|
||||
@@ -74,28 +74,27 @@ EOF
|
||||
run /bin/bash -c "dokku --quiet ps:scale $TEST_APP"
|
||||
output=$(echo "$output" | tr -s " ")
|
||||
echo "output: ($output)"
|
||||
assert_output $'cron: 0 \ncustom: 0 \nrelease: 0 \nweb: 1 \nworker: 0 \nscaletest: 0 '
|
||||
assert_output $'cron: 0\ncustom: 0\nrelease: 0\nscaletest: 0\nweb: 1\nworker: 0'
|
||||
|
||||
popd
|
||||
rm -rf "$TMP"
|
||||
}
|
||||
|
||||
@test "(ps:restart-policy) default policy" {
|
||||
run /bin/bash -c "dokku --quiet ps:restart-policy $TEST_APP"
|
||||
run /bin/bash -c "dokku --quiet ps:report $TEST_APP --ps-restart-policy"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_output "on-failure:10"
|
||||
}
|
||||
|
||||
|
||||
@test "(ps:restart-policy) ps:set-restart-policy, ps:restart-policy" {
|
||||
@test "(ps:restart-policy) ps:set restart-policy" {
|
||||
for policy in no unless-stopped always on-failure on-failure:20; do
|
||||
run /bin/bash -c "dokku ps:set-restart-policy $TEST_APP $policy"
|
||||
run /bin/bash -c "dokku ps:set $TEST_APP restart-policy $policy"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
|
||||
run /bin/bash -c "dokku --quiet ps:restart-policy $TEST_APP"
|
||||
run /bin/bash -c "dokku --quiet ps:report $TEST_APP --ps-restart-policy"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_output "$policy"
|
||||
@@ -104,12 +103,12 @@ EOF
|
||||
|
||||
@test "(ps:restart-policy) deployed policy" {
|
||||
test_restart_policy="on-failure:20"
|
||||
run /bin/bash -c "dokku ps:set-restart-policy $TEST_APP $test_restart_policy"
|
||||
run /bin/bash -c "dokku ps:set $TEST_APP restart-policy $test_restart_policy"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
|
||||
run /bin/bash -c "dokku --quiet ps:restart-policy $TEST_APP"
|
||||
run /bin/bash -c "dokku --quiet ps:report $TEST_APP --ps-restart-policy"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_output "$test_restart_policy"
|
||||
|
||||
Reference in New Issue
Block a user