Merge remote-tracking branch 'origin/master' into feature/add-latest-tag
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
[plugin]
|
||||
description = "dokku core standard plugin"
|
||||
version = "0.33.5"
|
||||
version = "0.33.7"
|
||||
[plugin.config]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[plugin]
|
||||
description = "dokku core events logging plugin"
|
||||
version = "0.33.5"
|
||||
version = "0.33.7"
|
||||
[plugin.config]
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package appjson
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
@@ -332,13 +331,16 @@ func executeScript(appName string, image string, imageTag string, phase string)
|
||||
fmt.Sprintf("LABEL com.dokku.%s-phase=true", phase),
|
||||
}...)
|
||||
commitArgs = append(commitArgs, containerID, image)
|
||||
containerCommitCmd := common.NewShellCmdWithArgs(
|
||||
common.DockerBin(),
|
||||
commitArgs...,
|
||||
)
|
||||
containerCommitCmd.ShowOutput = false
|
||||
containerCommitCmd.Command.Stderr = os.Stderr
|
||||
if !containerCommitCmd.Execute() {
|
||||
result, err := common.CallExecCommand(common.ExecCommandInput{
|
||||
Command: common.DockerBin(),
|
||||
Args: commitArgs,
|
||||
StreamStderr: true,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("Commiting of '%s' to image failed: %w", phase, err)
|
||||
}
|
||||
|
||||
if result.ExitCode != 0 {
|
||||
return fmt.Errorf("Commiting of '%s' to image failed: %s", phase, command)
|
||||
}
|
||||
|
||||
@@ -390,34 +392,11 @@ func getCommandFromImage(image string) (string, error) {
|
||||
}
|
||||
|
||||
func waitForExecution(containerID string) bool {
|
||||
containerStartCmd := common.NewShellCmdWithArgs(
|
||||
common.DockerBin(),
|
||||
"container",
|
||||
"start",
|
||||
containerID,
|
||||
)
|
||||
containerStartCmd.ShowOutput = false
|
||||
containerStartCmd.Command.Stderr = os.Stderr
|
||||
if !containerStartCmd.Execute() {
|
||||
if !common.ContainerStart(containerID) {
|
||||
return false
|
||||
}
|
||||
|
||||
containerWaitCmd := common.NewShellCmdWithArgs(
|
||||
common.DockerBin(),
|
||||
"container",
|
||||
"wait",
|
||||
containerID,
|
||||
)
|
||||
|
||||
containerWaitCmd.ShowOutput = false
|
||||
containerWaitCmd.Command.Stderr = os.Stderr
|
||||
b, err := containerWaitCmd.Output()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
containerExitCode := strings.TrimSpace(string(b[:]))
|
||||
return containerExitCode == "0"
|
||||
return common.ContainerWait(containerID)
|
||||
}
|
||||
|
||||
func createdContainerID(appName string, dockerArgs []string, image string, command []string, phase string) (string, error) {
|
||||
@@ -440,21 +419,19 @@ func createdContainerID(appName string, dockerArgs []string, image string, comma
|
||||
return "", err
|
||||
}
|
||||
|
||||
containerCreateCmd := common.NewShellCmdWithArgs(
|
||||
common.DockerBin(),
|
||||
arguments...,
|
||||
)
|
||||
var stderr bytes.Buffer
|
||||
containerCreateCmd.Env = env
|
||||
containerCreateCmd.ShowOutput = false
|
||||
containerCreateCmd.Command.Stderr = &stderr
|
||||
|
||||
b, err = containerCreateCmd.Output()
|
||||
result, err := common.CallExecCommand(common.ExecCommandInput{
|
||||
Command: common.DockerBin(),
|
||||
Args: arguments,
|
||||
Env: env,
|
||||
})
|
||||
if err != nil {
|
||||
return "", errors.New(stderr.String())
|
||||
return "", err
|
||||
}
|
||||
if result.ExitCode != 0 {
|
||||
return "", errors.New(result.StderrContents())
|
||||
}
|
||||
|
||||
containerID := strings.TrimSpace(string(b))
|
||||
containerID := result.StdoutContents()
|
||||
err = common.PlugnTrigger("post-container-create", []string{"app", containerID, appName, phase}...)
|
||||
return containerID, err
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[plugin]
|
||||
description = "dokku core app-json plugin"
|
||||
version = "0.33.5"
|
||||
version = "0.33.7"
|
||||
[plugin.config]
|
||||
|
||||
@@ -19,8 +19,7 @@ Additional commands:`
|
||||
|
||||
helpContent = `
|
||||
app-json:report [<app>] [<flag>], Displays a app-json report for one or more apps
|
||||
app-json:set <app> <property> (<value>), Set or clear a app-json property for an app
|
||||
`
|
||||
app-json:set <app> <property> (<value>), Set or clear a app-json property for an app`
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -33,10 +32,8 @@ func main() {
|
||||
usage()
|
||||
case "help":
|
||||
result, err := common.CallExecCommand(common.ExecCommandInput{
|
||||
Command: "ps",
|
||||
Args: []string{"-o", "command=", strconv.Itoa(os.Getppid())},
|
||||
CaptureOutput: true,
|
||||
StreamStdio: false,
|
||||
Command: "ps",
|
||||
Args: []string{"-o", "command=", strconv.Itoa(os.Getppid())},
|
||||
})
|
||||
if err == nil && strings.Contains(result.StdoutContents(), "--all") {
|
||||
fmt.Println(helpContent)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[plugin]
|
||||
description = "dokku core apps plugin"
|
||||
version = "0.33.5"
|
||||
version = "0.33.7"
|
||||
[plugin.config]
|
||||
|
||||
@@ -28,8 +28,7 @@ Additional commands:`
|
||||
apps:locked <app>, Checks if an app is locked for deployment
|
||||
apps:rename <old-app> <new-app>, Rename an app
|
||||
apps:report [<app>] [<flag>], Display report about an app
|
||||
apps:unlock <app>, Unlocks an app for deployment
|
||||
`
|
||||
apps:unlock <app>, Unlocks an app for deployment`
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -50,10 +49,8 @@ func main() {
|
||||
usage()
|
||||
case "help":
|
||||
result, err := common.CallExecCommand(common.ExecCommandInput{
|
||||
Command: "ps",
|
||||
Args: []string{"-o", "command=", strconv.Itoa(os.Getppid())},
|
||||
CaptureOutput: true,
|
||||
StreamStdio: false,
|
||||
Command: "ps",
|
||||
Args: []string{"-o", "command=", strconv.Itoa(os.Getppid())},
|
||||
})
|
||||
if err == nil && strings.Contains(result.StdoutContents(), "--all") {
|
||||
fmt.Println(helpContent)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[plugin]
|
||||
description = "dokku core builder-dockerfile plugin"
|
||||
version = "0.33.5"
|
||||
version = "0.33.7"
|
||||
[plugin.config]
|
||||
|
||||
@@ -36,27 +36,24 @@ trigger-builder-herokuish-builder-build() {
|
||||
local CID TAR_CID
|
||||
|
||||
pushd "$SOURCECODE_WORK_DIR" &>/dev/null
|
||||
if [[ -f "$SOURCECODE_WORK_DIR/.dockerignore" ]]; then
|
||||
rm -f "$SOURCECODE_WORK_DIR/.dockerignore"
|
||||
fi
|
||||
|
||||
eval "$(config_export app "$APP")"
|
||||
plugn trigger builder-create-dokku-image "$BUILDER_TYPE" "$APP" "$SOURCECODE_WORK_DIR" "$DOKKU_IMAGE"
|
||||
NEW_DOKKU_IMAGE=$(plugn trigger builder-dokku-image "$BUILDER_TYPE" "$APP" "$SOURCECODE_WORK_DIR" "$DOKKU_IMAGE")
|
||||
[[ -n "$NEW_DOKKU_IMAGE" ]] && DOKKU_IMAGE="$NEW_DOKKU_IMAGE"
|
||||
|
||||
if ! TAR_CID=$(tar -c . | "$DOCKER_BIN" container run "${DOCKER_RUN_LABEL_ARGS[@]}" $DOKKU_GLOBAL_RUN_ARGS -i -a stdin "$DOKKU_IMAGE" /bin/bash -c "mkdir -p /app && tar -xC /app"); then
|
||||
local DOCKER_BUILD_LABEL_ARGS="--label=org.label-schema.schema-version=1.0 --label=org.label-schema.vendor=dokku --label=com.dokku.app-name=$APP"
|
||||
DOKKU_APP_USER=$(config_get "$APP" DOKKU_APP_USER || true)
|
||||
DOKKU_APP_USER=${DOKKU_APP_USER:="herokuishuser"}
|
||||
if ! suppress_output "$DOCKER_BIN" image build "${DOCKER_BUILD_LABEL_ARGS[@]}" $DOKKU_GLOBAL_BUILD_ARGS -f "$PLUGIN_AVAILABLE_PATH/builder-herokuish/dockerfiles/copy-source.Dockerfile" --build-arg APP_IMAGE="$DOKKU_IMAGE" --build-arg DOKKU_APP_USER=$DOKKU_APP_USER -t $IMAGE "$SOURCECODE_WORK_DIR"; then
|
||||
DOKKU_SKIP_IMAGE_CLEANUP_REGISTRATION=1 plugn trigger scheduler-register-retired "$APP" "$TAR_CID"
|
||||
dokku_log_warn "Failure extracting app code"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if test "$("$DOCKER_BIN" container wait "$TAR_CID")" -ne 0; then
|
||||
DOKKU_SKIP_IMAGE_CLEANUP_REGISTRATION=1 plugn trigger scheduler-register-retired "$APP" "$TAR_CID"
|
||||
dokku_log_warn "Failure extracting app code"
|
||||
return 1
|
||||
fi
|
||||
|
||||
"$DOCKER_BIN" container commit "${DOCKER_COMMIT_LABEL_ARGS[@]}" "$TAR_CID" "$IMAGE" >/dev/null
|
||||
DOKKU_SKIP_IMAGE_CLEANUP_REGISTRATION=1 plugn trigger scheduler-register-retired "$APP" "$TAR_CID"
|
||||
|
||||
if fn-plugn-trigger-exists "pre-build-buildpack"; then
|
||||
dokku_log_warn "Deprecated: please upgrade plugin to use 'pre-build' plugin trigger instead of pre-build-buildpack"
|
||||
plugn trigger pre-build-buildpack "$APP" "$SOURCECODE_WORK_DIR"
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
ARG APP_IMAGE
|
||||
FROM $APP_IMAGE
|
||||
|
||||
ARG DOKKU_APP_USER herokuishuser
|
||||
RUN USER=$DOKKU_APP_USER /exec true
|
||||
COPY --chown=$DOKKU_APP_USER . /app
|
||||
WORKDIR /app
|
||||
@@ -1,4 +1,4 @@
|
||||
[plugin]
|
||||
description = "dokku core builder-herokuish plugin"
|
||||
version = "0.33.5"
|
||||
version = "0.33.7"
|
||||
[plugin.config]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[plugin]
|
||||
description = "dokku core builder-lambda plugin"
|
||||
version = "0.33.5"
|
||||
version = "0.33.7"
|
||||
[plugin.config]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[plugin]
|
||||
description = "dokku core builder-nixpacks plugin"
|
||||
version = "0.33.5"
|
||||
version = "0.33.7"
|
||||
[plugin.config]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[plugin]
|
||||
description = "dokku core builder-null plugin"
|
||||
version = "0.33.5"
|
||||
version = "0.33.7"
|
||||
[plugin.config]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[plugin]
|
||||
description = "dokku core builder-pack plugin"
|
||||
version = "0.33.5"
|
||||
version = "0.33.7"
|
||||
[plugin.config]
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
package builder
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
@@ -11,25 +10,18 @@ import (
|
||||
)
|
||||
|
||||
func listImagesByImageRepo(imageRepo string) ([]string, error) {
|
||||
command := []string{
|
||||
common.DockerBin(),
|
||||
"image",
|
||||
"ls",
|
||||
"--quiet",
|
||||
imageRepo,
|
||||
}
|
||||
|
||||
var stderr bytes.Buffer
|
||||
listCmd := common.NewShellCmd(strings.Join(command, " "))
|
||||
listCmd.ShowOutput = false
|
||||
listCmd.Command.Stderr = &stderr
|
||||
b, err := listCmd.Output()
|
||||
|
||||
result, err := common.CallExecCommand(common.ExecCommandInput{
|
||||
Command: common.DockerBin(),
|
||||
Args: []string{"image", "ls", "--quiet", imageRepo},
|
||||
})
|
||||
if err != nil {
|
||||
return []string{}, errors.New(strings.TrimSpace(stderr.String()))
|
||||
return []string{}, fmt.Errorf("Unable to list images: %w", err)
|
||||
}
|
||||
if result.ExitCode != 0 {
|
||||
return []string{}, fmt.Errorf("Unable to list images: %s", result.StderrContents())
|
||||
}
|
||||
|
||||
output := strings.Split(strings.TrimSpace(string(b[:])), "\n")
|
||||
output := strings.Split(result.StdoutContents(), "\n")
|
||||
return output, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[plugin]
|
||||
description = "dokku core builder plugin"
|
||||
version = "0.33.5"
|
||||
version = "0.33.7"
|
||||
[plugin.config]
|
||||
|
||||
@@ -19,8 +19,7 @@ Additional commands:`
|
||||
|
||||
helpContent = `
|
||||
builder:report [<app>] [<flag>], Displays a builder report for one or more apps
|
||||
builder:set <app> <property> (<value>), Set or clear a builder property for an app
|
||||
`
|
||||
builder:set <app> <property> (<value>), Set or clear a builder property for an app`
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -33,10 +32,8 @@ func main() {
|
||||
usage()
|
||||
case "help":
|
||||
result, err := common.CallExecCommand(common.ExecCommandInput{
|
||||
Command: "ps",
|
||||
Args: []string{"-o", "command=", strconv.Itoa(os.Getppid())},
|
||||
CaptureOutput: true,
|
||||
StreamStdio: false,
|
||||
Command: "ps",
|
||||
Args: []string{"-o", "command=", strconv.Itoa(os.Getppid())},
|
||||
})
|
||||
if err == nil && strings.Contains(result.StdoutContents(), "--all") {
|
||||
fmt.Println(helpContent)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[plugin]
|
||||
description = "dokku core buildpacks plugin"
|
||||
version = "0.33.5"
|
||||
version = "0.33.7"
|
||||
[plugin.config]
|
||||
|
||||
@@ -24,8 +24,7 @@ Additional commands:`
|
||||
buildpacks:remove <app> <buildpack>, Remove a buildpack set on the app
|
||||
buildpacks:report [<app>] [<flag>], Displays a buildpack report for one or more apps
|
||||
buildpacks:set [--index 1] <app> <buildpack>, Set new app buildpack at a given position defaulting to the first buildpack if no index is specified
|
||||
buildpacks:set-property [--global|<app>] <key> <value>, Set or clear a buildpacks property for an app
|
||||
`
|
||||
buildpacks:set-property [--global|<app>] <key> <value>, Set or clear a buildpacks property for an app`
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -38,10 +37,8 @@ func main() {
|
||||
usage()
|
||||
case "help":
|
||||
result, err := common.CallExecCommand(common.ExecCommandInput{
|
||||
Command: "ps",
|
||||
Args: []string{"-o", "command=", strconv.Itoa(os.Getppid())},
|
||||
CaptureOutput: true,
|
||||
StreamStdio: false,
|
||||
Command: "ps",
|
||||
Args: []string{"-o", "command=", strconv.Itoa(os.Getppid())},
|
||||
})
|
||||
if err == nil && strings.Contains(result.StdoutContents(), "--all") {
|
||||
fmt.Println(helpContent)
|
||||
|
||||
1
plugins/caddy-vhosts/Dockerfile
Normal file
1
plugins/caddy-vhosts/Dockerfile
Normal file
@@ -0,0 +1 @@
|
||||
FROM lucaslorentz/caddy-docker-proxy:2.8
|
||||
@@ -46,7 +46,7 @@ fn-caddy-template-compose-file() {
|
||||
}
|
||||
|
||||
fn-caddy-image() {
|
||||
fn-plugin-property-get-default "caddy" "--global" "image" "lucaslorentz/caddy-docker-proxy:2.8"
|
||||
fn-plugin-property-get-default "caddy" "--global" "image" "$(grep "FROM" "$PLUGIN_AVAILABLE_PATH/caddy-vhosts/Dockerfile" | awk '{print $2}')"
|
||||
}
|
||||
|
||||
fn-caddy-letsencrypt-email() {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[plugin]
|
||||
description = "dokku core caddy-vhosts plugin"
|
||||
version = "0.33.5"
|
||||
version = "0.33.7"
|
||||
[plugin.config]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[plugin]
|
||||
description = "dokku core certificate management plugin"
|
||||
version = "0.33.5"
|
||||
version = "0.33.7"
|
||||
[plugin.config]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[plugin]
|
||||
description = "dokku core checks plugin"
|
||||
version = "0.33.5"
|
||||
version = "0.33.7"
|
||||
[plugin.config]
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/codeskyblue/go-sh"
|
||||
)
|
||||
|
||||
// ContainerIsRunning checks to see if a container is running
|
||||
@@ -21,40 +17,54 @@ func ContainerIsRunning(containerID string) bool {
|
||||
}
|
||||
|
||||
// ContainerStart runs 'docker container start' against an existing container
|
||||
// whether that container is running or not
|
||||
func ContainerStart(containerID string) bool {
|
||||
cmd := sh.Command(DockerBin(), "container", "start", containerID)
|
||||
cmd.Stdout = nil
|
||||
cmd.Stderr = nil
|
||||
if err := cmd.Run(); err != nil {
|
||||
result, err := CallExecCommand(ExecCommandInput{
|
||||
Command: DockerBin(),
|
||||
Args: []string{"container", "start", containerID},
|
||||
StreamStderr: true,
|
||||
})
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
return result.ExitCode == 0
|
||||
}
|
||||
|
||||
// ContainerRemove runs 'docker container remove' against an existing container
|
||||
func ContainerRemove(containerID string) bool {
|
||||
cmd := sh.Command(DockerBin(), "container", "remove", "-f", containerID)
|
||||
cmd.Stdout = nil
|
||||
cmd.Stderr = nil
|
||||
if err := cmd.Run(); err != nil {
|
||||
result, err := CallExecCommand(ExecCommandInput{
|
||||
Command: DockerBin(),
|
||||
Args: []string{"container", "remove", "-f", containerID},
|
||||
StreamStderr: true,
|
||||
})
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
return result.ExitCode == 0
|
||||
}
|
||||
|
||||
// ContainerExists checks to see if a container exists
|
||||
func ContainerExists(containerID string) bool {
|
||||
cmd := sh.Command(DockerBin(), "container", "inspect", containerID)
|
||||
cmd.Stdout = nil
|
||||
cmd.Stderr = nil
|
||||
if err := cmd.Run(); err != nil {
|
||||
result, err := CallExecCommand(ExecCommandInput{
|
||||
Command: DockerBin(),
|
||||
Args: []string{"container", "inspect", containerID},
|
||||
})
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return result.ExitCode == 0
|
||||
}
|
||||
|
||||
return true
|
||||
// ContainerWait runs 'docker container wait' against an existing container
|
||||
func ContainerWait(containerID string) bool {
|
||||
result, err := CallExecCommand(ExecCommandInput{
|
||||
Command: DockerBin(),
|
||||
Args: []string{"container", "wait", containerID},
|
||||
StreamStderr: true,
|
||||
})
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return result.ExitCode == 0
|
||||
}
|
||||
|
||||
// ContainerWaitTilReady will wait timeout seconds and then check if a container is running
|
||||
@@ -96,32 +106,20 @@ func CopyFromImage(appName string, image string, source string, destination stri
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to create temporary container: %v", err)
|
||||
}
|
||||
defer ContainerRemove(containerID)
|
||||
|
||||
// docker cp exits with status 1 when run as non-root user when it tries to chown the file
|
||||
// after successfully copying the file. Thus, we suppress stderr.
|
||||
// ref: https://github.com/dotcloud/docker/issues/3986
|
||||
containerCopyCmd := NewShellCmd(strings.Join([]string{
|
||||
DockerBin(),
|
||||
"container",
|
||||
"cp",
|
||||
fmt.Sprintf("%s:%s", containerID, source),
|
||||
tmpFile.Name(),
|
||||
}, " "))
|
||||
containerCopyCmd.ShowOutput = false
|
||||
fileCopied := containerCopyCmd.Execute()
|
||||
|
||||
containerRemoveCmd := NewShellCmd(strings.Join([]string{
|
||||
DockerBin(),
|
||||
"container",
|
||||
"rm",
|
||||
"--force",
|
||||
containerID,
|
||||
}, " "))
|
||||
containerRemoveCmd.ShowOutput = false
|
||||
containerRemoveCmd.Execute()
|
||||
|
||||
if !fileCopied {
|
||||
return fmt.Errorf("Unable to copy file %s from image", source)
|
||||
result, err := CallExecCommand(ExecCommandInput{
|
||||
Command: DockerBin(),
|
||||
Args: []string{"container", "cp", fmt.Sprintf("%s:%s", containerID, source), tmpFile.Name()},
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to copy file %s from image: %w", source, err)
|
||||
}
|
||||
if result.ExitCode != 0 {
|
||||
return fmt.Errorf("Unable to copy file %s from image: %v", source, result.StderrContents())
|
||||
}
|
||||
|
||||
fi, err := os.Stat(tmpFile.Name())
|
||||
@@ -134,19 +132,21 @@ func CopyFromImage(appName string, image string, source string, destination stri
|
||||
}
|
||||
|
||||
// workaround when owner is root. seems to only happen when running inside docker
|
||||
dos2unixCmd := NewShellCmd(strings.Join([]string{
|
||||
"dos2unix",
|
||||
"-l",
|
||||
"-n",
|
||||
tmpFile.Name(),
|
||||
destination,
|
||||
}, " "))
|
||||
dos2unixCmd.ShowOutput = false
|
||||
dos2unixCmd.Execute()
|
||||
CallExecCommand(ExecCommandInput{
|
||||
Command: "dos2unix",
|
||||
Args: []string{"-l", "-n", tmpFile.Name(), destination},
|
||||
}) // nolint: errcheck
|
||||
|
||||
// add trailing newline for certain places where file parsing depends on it
|
||||
b, err := sh.Command("tail", "-c1", destination).Output()
|
||||
if string(b) != "" {
|
||||
result, err = CallExecCommand(ExecCommandInput{
|
||||
Command: "tail",
|
||||
Args: []string{"-c1", destination},
|
||||
})
|
||||
if err != nil || result.ExitCode != 0 {
|
||||
return fmt.Errorf("Unable to append trailing newline to copied file: %v", result.Stderr)
|
||||
}
|
||||
|
||||
if result.Stdout != "" {
|
||||
f, err := os.OpenFile(destination, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -225,34 +225,39 @@ func DockerCleanup(appName string, forceCleanup bool) error {
|
||||
|
||||
// DockerContainerCreate creates a new container and returns the container ID
|
||||
func DockerContainerCreate(image string, containerCreateArgs []string) (string, error) {
|
||||
cmd := []string{
|
||||
DockerBin(),
|
||||
args := []string{
|
||||
"container",
|
||||
"create",
|
||||
}
|
||||
|
||||
cmd = append(cmd, containerCreateArgs...)
|
||||
cmd = append(cmd, image)
|
||||
args = append(args, containerCreateArgs...)
|
||||
args = append(args, image)
|
||||
|
||||
var stderr bytes.Buffer
|
||||
containerCreateCmd := NewShellCmd(strings.Join(cmd, " "))
|
||||
containerCreateCmd.ShowOutput = false
|
||||
containerCreateCmd.Command.Stderr = &stderr
|
||||
b, err := containerCreateCmd.Output()
|
||||
result, err := CallExecCommand(ExecCommandInput{
|
||||
Command: DockerBin(),
|
||||
Args: args,
|
||||
})
|
||||
if err != nil {
|
||||
return "", errors.New(strings.TrimSpace(stderr.String()))
|
||||
return "", fmt.Errorf("Unable to create container: %w", err)
|
||||
}
|
||||
if result.ExitCode != 0 {
|
||||
return "", fmt.Errorf("Unable to create container: %s", result.StderrContents())
|
||||
}
|
||||
|
||||
return strings.TrimSpace(string(b[:])), nil
|
||||
return result.StdoutContents(), nil
|
||||
}
|
||||
|
||||
// DockerInspect runs an inspect command with a given format against a container or image ID
|
||||
func DockerInspect(containerOrImageID, format string) (output string, err error) {
|
||||
b, err := sh.Command(DockerBin(), "inspect", "--format", format, containerOrImageID).Output()
|
||||
result, err := CallExecCommand(ExecCommandInput{
|
||||
Command: DockerBin(),
|
||||
Args: []string{"inspect", "--format", format, containerOrImageID},
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
output = strings.TrimSpace(string(b[:]))
|
||||
|
||||
output = result.StdoutContents()
|
||||
if strings.HasPrefix(output, "'") && strings.HasSuffix(output, "'") {
|
||||
output = strings.TrimSuffix(strings.TrimPrefix(output, "'"), "'")
|
||||
}
|
||||
@@ -273,9 +278,8 @@ func GetWorkingDir(appName string, image string) string {
|
||||
|
||||
func IsComposeInstalled() bool {
|
||||
result, err := CallExecCommand(ExecCommandInput{
|
||||
Command: DockerBin(),
|
||||
Args: []string{"info", "--format", "{{range .ClientInfo.Plugins}}{{if eq .Name \"compose\"}}true{{end}}{{end}}')"},
|
||||
CaptureOutput: true,
|
||||
Command: DockerBin(),
|
||||
Args: []string{"info", "--format", "{{range .ClientInfo.Plugins}}{{if eq .Name \"compose\"}}true{{end}}{{end}}')"},
|
||||
})
|
||||
return err == nil && result.ExitCode == 0
|
||||
}
|
||||
@@ -337,21 +341,22 @@ func RemoveImages(imageIDs []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
command := []string{
|
||||
DockerBin(),
|
||||
args := []string{
|
||||
"image",
|
||||
"rm",
|
||||
}
|
||||
|
||||
command = append(command, imageIDs...)
|
||||
args = append(args, imageIDs...)
|
||||
|
||||
var stderr bytes.Buffer
|
||||
rmCmd := NewShellCmd(strings.Join(command, " "))
|
||||
rmCmd.ShowOutput = false
|
||||
rmCmd.Command.Stderr = &stderr
|
||||
rmCmd.Execute()
|
||||
if _, err := rmCmd.Output(); err != nil {
|
||||
return errors.New(strings.TrimSpace(stderr.String()))
|
||||
result, err := CallExecCommand(ExecCommandInput{
|
||||
Command: DockerBin(),
|
||||
Args: args,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to remove images: %w", err)
|
||||
}
|
||||
if result.ExitCode != 0 {
|
||||
return fmt.Errorf("Unable to remove images: %s", result.StderrContents())
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -359,15 +364,16 @@ func RemoveImages(imageIDs []string) error {
|
||||
|
||||
// VerifyImage returns true if docker image exists in local repo
|
||||
func VerifyImage(image string) bool {
|
||||
imageCmd := NewShellCmd(strings.Join([]string{DockerBin(), "image", "inspect", image}, " "))
|
||||
imageCmd.ShowOutput = false
|
||||
return imageCmd.Execute()
|
||||
result, err := CallExecCommand(ExecCommandInput{
|
||||
Command: DockerBin(),
|
||||
Args: []string{"image", "inspect", image},
|
||||
})
|
||||
return err == nil && result.ExitCode == 0
|
||||
}
|
||||
|
||||
// DockerFilterContainers returns a slice of container IDs based on the passed in filters
|
||||
func DockerFilterContainers(filters []string) ([]string, error) {
|
||||
command := []string{
|
||||
DockerBin(),
|
||||
args := []string{
|
||||
"container",
|
||||
"ls",
|
||||
"--quiet",
|
||||
@@ -375,27 +381,27 @@ func DockerFilterContainers(filters []string) ([]string, error) {
|
||||
}
|
||||
|
||||
for _, filter := range filters {
|
||||
command = append(command, "--filter", filter)
|
||||
args = append(args, "--filter", filter)
|
||||
}
|
||||
|
||||
var stderr bytes.Buffer
|
||||
listCmd := NewShellCmd(strings.Join(command, " "))
|
||||
listCmd.ShowOutput = false
|
||||
listCmd.Command.Stderr = &stderr
|
||||
b, err := listCmd.Output()
|
||||
|
||||
result, err := CallExecCommand(ExecCommandInput{
|
||||
Command: DockerBin(),
|
||||
Args: args,
|
||||
})
|
||||
if err != nil {
|
||||
return []string{}, errors.New(strings.TrimSpace(stderr.String()))
|
||||
return []string{}, fmt.Errorf("Unable to filter containers: %w", err)
|
||||
}
|
||||
if result.ExitCode != 0 {
|
||||
return []string{}, fmt.Errorf("Unable to filter containers: %s", result.StderrContents())
|
||||
}
|
||||
|
||||
output := strings.Split(strings.TrimSpace(string(b[:])), "\n")
|
||||
output := strings.Split(result.StdoutContents(), "\n")
|
||||
return output, nil
|
||||
}
|
||||
|
||||
// DockerFilterImages returns a slice of image IDs based on the passed in filters
|
||||
func DockerFilterImages(filters []string) ([]string, error) {
|
||||
command := []string{
|
||||
DockerBin(),
|
||||
args := []string{
|
||||
"image",
|
||||
"ls",
|
||||
"--quiet",
|
||||
@@ -403,20 +409,21 @@ func DockerFilterImages(filters []string) ([]string, error) {
|
||||
}
|
||||
|
||||
for _, filter := range filters {
|
||||
command = append(command, "--filter", filter)
|
||||
args = append(args, "--filter", filter)
|
||||
}
|
||||
|
||||
var stderr bytes.Buffer
|
||||
listCmd := NewShellCmd(strings.Join(command, " "))
|
||||
listCmd.ShowOutput = false
|
||||
listCmd.Command.Stderr = &stderr
|
||||
b, err := listCmd.Output()
|
||||
|
||||
result, err := CallExecCommand(ExecCommandInput{
|
||||
Command: DockerBin(),
|
||||
Args: args,
|
||||
})
|
||||
if err != nil {
|
||||
return []string{}, errors.New(strings.TrimSpace(stderr.String()))
|
||||
return []string{}, fmt.Errorf("Unable to filter images: %w", err)
|
||||
}
|
||||
if result.ExitCode != 0 {
|
||||
return []string{}, fmt.Errorf("Unable to filter images: %s", result.StderrContents())
|
||||
}
|
||||
|
||||
output := strings.Split(strings.TrimSpace(string(b[:])), "\n")
|
||||
output := strings.Split(result.StdoutContents(), "\n")
|
||||
return output, nil
|
||||
}
|
||||
|
||||
@@ -433,8 +440,7 @@ func listContainers(status string, appName string) ([]string, error) {
|
||||
}
|
||||
|
||||
func pruneUnusedImages(appName string) {
|
||||
command := []string{
|
||||
DockerBin(),
|
||||
args := []string{
|
||||
"image",
|
||||
"prune",
|
||||
"--all",
|
||||
@@ -443,26 +449,23 @@ func pruneUnusedImages(appName string) {
|
||||
fmt.Sprintf("label=com.dokku.app-name=%v", appName),
|
||||
}
|
||||
|
||||
var stderr bytes.Buffer
|
||||
pruneCmd := NewShellCmd(strings.Join(command, " "))
|
||||
pruneCmd.ShowOutput = false
|
||||
pruneCmd.Command.Stderr = &stderr
|
||||
pruneCmd.Execute()
|
||||
CallExecCommand(ExecCommandInput{
|
||||
Command: DockerBin(),
|
||||
Args: args,
|
||||
}) // nolint: errcheck
|
||||
}
|
||||
|
||||
// DockerRemoveContainers will call `docker container rm` on the specified containers
|
||||
func DockerRemoveContainers(containerIDs []string) {
|
||||
command := []string{
|
||||
DockerBin(),
|
||||
args := []string{
|
||||
"container",
|
||||
"rm",
|
||||
}
|
||||
|
||||
command = append(command, containerIDs...)
|
||||
args = append(args, containerIDs...)
|
||||
|
||||
var stderr bytes.Buffer
|
||||
rmCmd := NewShellCmd(strings.Join(command, " "))
|
||||
rmCmd.ShowOutput = false
|
||||
rmCmd.Command.Stderr = &stderr
|
||||
rmCmd.Execute()
|
||||
CallExecCommand(ExecCommandInput{
|
||||
Command: DockerBin(),
|
||||
Args: args,
|
||||
}) // nolint: errcheck
|
||||
}
|
||||
|
||||
@@ -23,8 +23,8 @@ type ExecCommandInput struct {
|
||||
// Args are the arguments to pass to the command
|
||||
Args []string
|
||||
|
||||
// CaptureOutput determines whether to capture the output of the command
|
||||
CaptureOutput bool
|
||||
// DisableStdioBuffer disables the stdio buffer
|
||||
DisableStdioBuffer bool
|
||||
|
||||
// Env is the environment variables to pass to the command
|
||||
Env map[string]string
|
||||
@@ -42,6 +42,12 @@ type ExecCommandInput struct {
|
||||
// StreamStderr prints stderr directly to os.Stderr as the command runs.
|
||||
StreamStderr bool
|
||||
|
||||
// StdoutWriter is the writer to write stdout to
|
||||
StdoutWriter io.Writer
|
||||
|
||||
// StderrWriter is the writer to write stderr to
|
||||
StderrWriter io.Writer
|
||||
|
||||
// Sudo runs the command with sudo -n -u root
|
||||
Sudo bool
|
||||
}
|
||||
@@ -95,7 +101,7 @@ func CallExecCommandWithContext(ctx context.Context, input ExecCommandInput) (Ex
|
||||
// being captured, then color output can be forced.
|
||||
isatty := !color.NoColor
|
||||
env := os.Environ()
|
||||
if isatty && !input.CaptureOutput {
|
||||
if isatty && input.DisableStdioBuffer {
|
||||
env = append(env, "FORCE_TTY=1")
|
||||
}
|
||||
if input.Env != nil {
|
||||
@@ -115,11 +121,15 @@ func CallExecCommandWithContext(ctx context.Context, input ExecCommandInput) (Ex
|
||||
Command: command,
|
||||
Args: commandArgs,
|
||||
Env: env,
|
||||
DisableStdioBuffer: !input.CaptureOutput,
|
||||
DisableStdioBuffer: input.DisableStdioBuffer,
|
||||
}
|
||||
|
||||
if os.Getenv("DOKKU_TRACE") == "1" {
|
||||
cmd.PrintCommand = true
|
||||
argsSt := ""
|
||||
if len(cmd.Args) > 0 {
|
||||
argsSt = strings.Join(cmd.Args, " ")
|
||||
}
|
||||
LogWarn(fmt.Sprintf("exec: %s %s", cmd.Command, argsSt))
|
||||
}
|
||||
|
||||
if input.Stdin != nil {
|
||||
@@ -137,6 +147,12 @@ func CallExecCommandWithContext(ctx context.Context, input ExecCommandInput) (Ex
|
||||
if input.StreamStderr {
|
||||
cmd.StdErrWriter = os.Stderr
|
||||
}
|
||||
if input.StdoutWriter != nil {
|
||||
cmd.StdOutWriter = input.StdoutWriter
|
||||
}
|
||||
if input.StderrWriter != nil {
|
||||
cmd.StdErrWriter = input.StderrWriter
|
||||
}
|
||||
|
||||
res, err := cmd.Execute(ctx)
|
||||
if err != nil {
|
||||
|
||||
@@ -38,15 +38,16 @@ func Copy(src, dst string) error {
|
||||
}
|
||||
|
||||
// ensure file has the correct line endings
|
||||
dos2unixCmd := NewShellCmd(strings.Join([]string{
|
||||
"dos2unix",
|
||||
"-l",
|
||||
"-n",
|
||||
src,
|
||||
dst,
|
||||
}, " "))
|
||||
dos2unixCmd.ShowOutput = false
|
||||
dos2unixCmd.Execute()
|
||||
result, err := CallExecCommand(ExecCommandInput{
|
||||
Command: "dos2unix",
|
||||
Args: []string{"-l", "-n", src, dst},
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error running dos2unix: %s", err)
|
||||
}
|
||||
if result.ExitCode != 0 {
|
||||
return fmt.Errorf("Error running dos2unix: %s", result.StderrContents())
|
||||
}
|
||||
|
||||
// ensure file permissions are correct
|
||||
b, err := os.ReadFile(dst)
|
||||
|
||||
@@ -174,22 +174,27 @@ func LogVerboseQuietContainerLogsTail(containerID string, lines int, tail bool)
|
||||
args = append(args, "--follow")
|
||||
}
|
||||
|
||||
sc := NewShellCmdWithArgs(DockerBin(), args...)
|
||||
var mu sync.Mutex
|
||||
sc.Command.Stdout = &writer{
|
||||
mu: &mu,
|
||||
source: "stdout",
|
||||
}
|
||||
sc.Command.Stderr = &writer{
|
||||
mu: &mu,
|
||||
source: "stderr",
|
||||
}
|
||||
result, err := CallExecCommand(ExecCommandInput{
|
||||
Command: DockerBin(),
|
||||
Args: args,
|
||||
DisableStdioBuffer: true,
|
||||
StdoutWriter: &writer{
|
||||
mu: &mu,
|
||||
source: "stdout",
|
||||
},
|
||||
StderrWriter: &writer{
|
||||
mu: &mu,
|
||||
source: "stderr",
|
||||
},
|
||||
})
|
||||
|
||||
if err := sc.Command.Start(); err != nil {
|
||||
if err != nil {
|
||||
LogExclaim(fmt.Sprintf("Failed to fetch container logs: %s", containerID))
|
||||
return
|
||||
}
|
||||
|
||||
if err := sc.Command.Wait(); err != nil {
|
||||
if !tail && result.ExitCode != 0 {
|
||||
LogExclaim(fmt.Sprintf("Failed to fetch container logs: %s", containerID))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[plugin]
|
||||
description = "dokku core common plugin"
|
||||
version = "0.33.5"
|
||||
version = "0.33.7"
|
||||
[plugin.config]
|
||||
|
||||
@@ -2,7 +2,10 @@ package common
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// PlugnTriggerInput is the input for CallPlugnTrigger
|
||||
@@ -10,8 +13,8 @@ type PlugnTriggerInput struct {
|
||||
// Args are the arguments to pass to the trigger
|
||||
Args []string
|
||||
|
||||
// CaptureOutput determines whether to capture the output of the trigger
|
||||
CaptureOutput bool
|
||||
// DisableStdioBuffer disables the stdio buffer
|
||||
DisableStdioBuffer bool
|
||||
|
||||
// Env is the environment variables to pass to the trigger
|
||||
Env map[string]string
|
||||
@@ -41,14 +44,25 @@ func CallPlugnTrigger(input PlugnTriggerInput) (ExecCommandResponse, error) {
|
||||
func CallPlugnTriggerWithContext(ctx context.Context, input PlugnTriggerInput) (ExecCommandResponse, error) {
|
||||
args := []string{"trigger", input.Trigger}
|
||||
args = append(args, input.Args...)
|
||||
return CallExecCommandWithContext(ctx, ExecCommandInput{
|
||||
Command: "plugn",
|
||||
Args: args,
|
||||
CaptureOutput: input.CaptureOutput,
|
||||
Env: input.Env,
|
||||
Stdin: input.Stdin,
|
||||
StreamStdio: input.StreamStdio,
|
||||
StreamStdout: input.StreamStdout,
|
||||
StreamStderr: input.StreamStderr,
|
||||
result, err := CallExecCommandWithContext(ctx, ExecCommandInput{
|
||||
Command: "plugn",
|
||||
Args: args,
|
||||
DisableStdioBuffer: input.DisableStdioBuffer,
|
||||
Env: input.Env,
|
||||
Stdin: input.Stdin,
|
||||
StreamStdio: input.StreamStdio,
|
||||
StreamStdout: input.StreamStdout,
|
||||
StreamStderr: input.StreamStderr,
|
||||
})
|
||||
|
||||
if os.Getenv("DOKKU_TRACE") == "1" {
|
||||
for _, line := range strings.Split(result.Stderr, "\n") {
|
||||
LogDebug(fmt.Sprintf("plugn trigger %s stderr: %s", input.Trigger, line))
|
||||
}
|
||||
for _, line := range strings.Split(result.Stdout, "\n") {
|
||||
LogDebug(fmt.Sprintf("plugn trigger %s stdout: %s", input.Trigger, line))
|
||||
}
|
||||
}
|
||||
|
||||
return result, err
|
||||
}
|
||||
|
||||
@@ -31,8 +31,8 @@ type SshCommandInput struct {
|
||||
// Args are the arguments to pass to the command.
|
||||
Args []string
|
||||
|
||||
// CaptureOutput saves any output from in the TaskResult
|
||||
CaptureOutput bool
|
||||
// DisableStdioBuffer disables the stdio buffer
|
||||
DisableStdioBuffer bool
|
||||
|
||||
// Env is a list of environment variables to add to the current environment
|
||||
Env map[string]string
|
||||
@@ -137,7 +137,7 @@ func CallSshCommandWithContext(ctx context.Context, input SshCommandInput) (SshR
|
||||
Command: input.Command,
|
||||
Args: input.Args,
|
||||
Env: env,
|
||||
DisableStdioBuffer: !input.CaptureOutput,
|
||||
DisableStdioBuffer: input.DisableStdioBuffer,
|
||||
AllowUknownHosts: input.AllowUknownHosts,
|
||||
Hostname: u.Hostname(),
|
||||
Port: uint(port),
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[plugin]
|
||||
description = "dokku core config plugin"
|
||||
version = "0.33.5"
|
||||
version = "0.33.7"
|
||||
[plugin.config]
|
||||
|
||||
@@ -27,8 +27,7 @@ Additional commands:`
|
||||
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
|
||||
`
|
||||
config:unset [--no-restart] (<app>|--global) KEY1 [KEY2 ...], Unset one or more config vars`
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -54,10 +53,8 @@ func main() {
|
||||
usage()
|
||||
case "help":
|
||||
result, err := common.CallExecCommand(common.ExecCommandInput{
|
||||
Command: "ps",
|
||||
Args: []string{"-o", "command=", strconv.Itoa(os.Getppid())},
|
||||
CaptureOutput: true,
|
||||
StreamStdio: false,
|
||||
Command: "ps",
|
||||
Args: []string{"-o", "command=", strconv.Itoa(os.Getppid())},
|
||||
})
|
||||
if err == nil && strings.Contains(result.StdoutContents(), "--all") {
|
||||
fmt.Println(helpContent)
|
||||
|
||||
@@ -9,7 +9,7 @@ require (
|
||||
github.com/robfig/cron/v3 v3.0.1
|
||||
github.com/ryanuber/columnize v2.1.2+incompatible
|
||||
github.com/spf13/pflag v1.0.5
|
||||
mvdan.cc/sh/v3 v3.7.0
|
||||
mvdan.cc/sh/v3 v3.8.0
|
||||
)
|
||||
|
||||
require (
|
||||
|
||||
@@ -8,8 +8,8 @@ github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
|
||||
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
|
||||
github.com/frankban/quicktest v1.14.5 h1:dfYrrRyLtiqT9GyKXgdh+k4inNeTvmGbuSgZ3lx3GhA=
|
||||
github.com/frankban/quicktest v1.14.5/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
|
||||
@@ -47,8 +47,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
||||
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
||||
github.com/rogpeppe/go-internal v1.10.1-0.20230524175051-ec119421bb97 h1:3RPlVWzZ/PDqmVuf/FKHARG5EMid/tl7cv54Sw/QRVY=
|
||||
github.com/rogpeppe/go-internal v1.10.1-0.20230524175051-ec119421bb97/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
|
||||
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
||||
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
||||
github.com/ryanuber/columnize v2.1.2+incompatible h1:C89EOx/XBWwIXl8wm8OPJBd7kPF25UfsK2X7Ph/zCAk=
|
||||
github.com/ryanuber/columnize v2.1.2+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
@@ -107,5 +107,5 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
mvdan.cc/sh/v3 v3.7.0 h1:lSTjdP/1xsddtaKfGg7Myu7DnlHItd3/M2tomOcNNBg=
|
||||
mvdan.cc/sh/v3 v3.7.0/go.mod h1:K2gwkaesF/D7av7Kxl0HbF5kGOd2ArupNTX3X44+8l8=
|
||||
mvdan.cc/sh/v3 v3.8.0 h1:ZxuJipLZwr/HLbASonmXtcvvC9HXY9d2lXZHnKGjFc8=
|
||||
mvdan.cc/sh/v3 v3.8.0/go.mod h1:w04623xkgBVo7/IUK89E0g8hBykgEpN0vgOj3RJr6MY=
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[plugin]
|
||||
description = "dokku core cron plugin"
|
||||
version = "0.33.5"
|
||||
version = "0.33.7"
|
||||
[plugin.config]
|
||||
|
||||
@@ -20,8 +20,7 @@ Additional commands:`
|
||||
helpContent = `
|
||||
cron:list <app> [--format json|stdout], List scheduled cron tasks for an app
|
||||
cron:report [<app>] [<flag>], Display report about an app
|
||||
cron:run <app> <cron_id> [--detach], Run a cron task on the fly
|
||||
`
|
||||
cron:run <app> <cron_id> [--detach], Run a cron task on the fly`
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -34,10 +33,8 @@ func main() {
|
||||
usage()
|
||||
case "help":
|
||||
result, err := common.CallExecCommand(common.ExecCommandInput{
|
||||
Command: "ps",
|
||||
Args: []string{"-o", "command=", strconv.Itoa(os.Getppid())},
|
||||
CaptureOutput: true,
|
||||
StreamStdio: false,
|
||||
Command: "ps",
|
||||
Args: []string{"-o", "command=", strconv.Itoa(os.Getppid())},
|
||||
})
|
||||
if err == nil && strings.Contains(result.StdoutContents(), "--all") {
|
||||
fmt.Println(helpContent)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[plugin]
|
||||
description = "dokku core docker-options plugin"
|
||||
version = "0.33.5"
|
||||
version = "0.33.7"
|
||||
[plugin.config]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[plugin]
|
||||
description = "dokku core domains plugin"
|
||||
version = "0.33.5"
|
||||
version = "0.33.7"
|
||||
[plugin.config]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[plugin]
|
||||
description = "dokku core enter plugin"
|
||||
version = "0.33.5"
|
||||
version = "0.33.7"
|
||||
[plugin.config]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[plugin]
|
||||
description = "dokku core git plugin"
|
||||
version = "0.33.5"
|
||||
version = "0.33.7"
|
||||
[plugin.config]
|
||||
|
||||
1
plugins/haproxy-vhosts/Dockerfile
Normal file
1
plugins/haproxy-vhosts/Dockerfile
Normal file
@@ -0,0 +1 @@
|
||||
FROM byjg/easy-haproxy:4.4.0
|
||||
@@ -44,7 +44,7 @@ fn-haproxy-template-compose-file() {
|
||||
}
|
||||
|
||||
fn-haproxy-image() {
|
||||
fn-plugin-property-get-default "haproxy" "--global" "image" "byjg/easy-haproxy:4.3.0"
|
||||
fn-plugin-property-get-default "haproxy" "--global" "image" "$(grep "FROM" "$PLUGIN_AVAILABLE_PATH/haproxy-vhosts/Dockerfile" | awk '{print $2}')"
|
||||
}
|
||||
|
||||
fn-haproxy-log-level() {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[plugin]
|
||||
description = "dokku core haproxy-vhosts plugin"
|
||||
version = "0.33.5"
|
||||
version = "0.33.7"
|
||||
[plugin.config]
|
||||
|
||||
1
plugins/logs/Dockerfile
Normal file
1
plugins/logs/Dockerfile
Normal file
@@ -0,0 +1 @@
|
||||
FROM timberio/vector:0.36.X-debian
|
||||
@@ -38,8 +38,7 @@ const vectorOldContainerName = "vector"
|
||||
|
||||
func getComposeFile() ([]byte, error) {
|
||||
result, err := common.CallPlugnTrigger(common.PlugnTriggerInput{
|
||||
Trigger: "vector-template-source",
|
||||
CaptureOutput: true,
|
||||
Trigger: "vector-template-source",
|
||||
})
|
||||
if err == nil && result.ExitCode == 0 && strings.TrimSpace(result.Stdout) != "" {
|
||||
contents, err := os.ReadFile(strings.TrimSpace(result.Stdout))
|
||||
@@ -122,6 +121,17 @@ func startVectorContainer(vectorImage string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func getComputedVectorImage() string {
|
||||
return common.PropertyGetDefault("logs", "--global", "vector-image", getDefaultVectorImage())
|
||||
}
|
||||
|
||||
// getDefaultVectorImage returns the default image used for the vector container
|
||||
func getDefaultVectorImage() string {
|
||||
contents := strings.TrimSpace(VectorDockerfile)
|
||||
parts := strings.SplitN(contents, " ", 2)
|
||||
return parts[1]
|
||||
}
|
||||
|
||||
func stopVectorContainer() error {
|
||||
if !common.IsComposeInstalled() {
|
||||
return errors.New("Required docker compose plugin is not installed")
|
||||
@@ -160,7 +170,7 @@ func stopVectorContainer() error {
|
||||
data := vectorTemplateData{
|
||||
DokkuLibRoot: dokkuLibRoot,
|
||||
DokkuLogsDir: dokkuLogsDir,
|
||||
VectorImage: VectorImage,
|
||||
VectorImage: getComputedVectorImage(),
|
||||
}
|
||||
|
||||
if err := tmpl.Execute(tmpFile, data); err != nil {
|
||||
|
||||
@@ -3,7 +3,6 @@ module github.com/dokku/dokku/plugins/logs
|
||||
go 1.21
|
||||
|
||||
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/docker-options v0.0.0-00010101000000-000000000000
|
||||
github.com/joncalhoun/qson v0.0.0-20200422171543-84433dcd3da0
|
||||
@@ -13,6 +12,7 @@ require (
|
||||
require (
|
||||
github.com/alexellis/go-execute/v2 v2.2.1 // indirect
|
||||
github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 // indirect
|
||||
github.com/codeskyblue/go-sh v0.0.0-20190412065543-76bd3d59ff27 // indirect
|
||||
github.com/fatih/color v1.16.0 // indirect
|
||||
github.com/hashicorp/errwrap v1.0.0 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
|
||||
@@ -25,8 +25,11 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
// VectorImage contains the default vector image to run
|
||||
const VectorImage = "timberio/vector:0.35.X-debian"
|
||||
// VectorDockerfile is the contents of the default Dockerfile
|
||||
// containing the version of vector Dokku uses
|
||||
//
|
||||
//go:embed Dockerfile
|
||||
var VectorDockerfile string
|
||||
|
||||
// VectorDefaultSink contains the default sink in use for vector log shipping
|
||||
const VectorDefaultSink = "blackhole://?print_interval_secs=1"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[plugin]
|
||||
description = "dokku core logs plugin"
|
||||
version = "0.33.5"
|
||||
version = "0.33.7"
|
||||
[plugin.config]
|
||||
|
||||
@@ -44,7 +44,7 @@ func reportGlobalMaxSize(appName string) string {
|
||||
}
|
||||
|
||||
func reportVectorGlobalImage(appName string) string {
|
||||
return common.PropertyGetDefault("logs", "--global", "vector-image", VectorImage)
|
||||
return getComputedVectorImage()
|
||||
}
|
||||
|
||||
func reportGlobalVectorSink(appName string) string {
|
||||
|
||||
@@ -28,8 +28,7 @@ Additional commands:`
|
||||
logs:set [--global|<app>] <key> <value>, Set or clear a logs property for an app
|
||||
logs:vector-logs [--num num] [--tail], Display vector log output
|
||||
logs:vector-start, Start the vector logging container
|
||||
logs:vector-stop, Stop the vector logging container
|
||||
`
|
||||
logs:vector-stop, Stop the vector logging container`
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -60,10 +59,8 @@ func main() {
|
||||
usage()
|
||||
case "help":
|
||||
result, err := common.CallExecCommand(common.ExecCommandInput{
|
||||
Command: "ps",
|
||||
Args: []string{"-o", "command=", strconv.Itoa(os.Getppid())},
|
||||
CaptureOutput: true,
|
||||
StreamStdio: false,
|
||||
Command: "ps",
|
||||
Args: []string{"-o", "command=", strconv.Itoa(os.Getppid())},
|
||||
})
|
||||
if err == nil && strings.Contains(result.StdoutContents(), "--all") {
|
||||
fmt.Println(helpContent)
|
||||
|
||||
@@ -104,7 +104,7 @@ func CommandVectorStart(vectorImage string) error {
|
||||
}
|
||||
|
||||
if vectorImage == "" {
|
||||
vectorImage = common.PropertyGetDefault("logs", "--global", "vector-image", VectorImage)
|
||||
vectorImage = common.PropertyGetDefault("logs", "--global", "vector-image", getComputedVectorImage())
|
||||
}
|
||||
|
||||
common.LogVerbose("Starting vector container")
|
||||
|
||||
@@ -10,8 +10,6 @@ import (
|
||||
|
||||
"github.com/dokku/dokku/plugins/common"
|
||||
dockeroptions "github.com/dokku/dokku/plugins/docker-options"
|
||||
|
||||
sh "github.com/codeskyblue/go-sh"
|
||||
)
|
||||
|
||||
// TriggerDockerArgsProcessDeploy outputs the logs plugin docker options for an app
|
||||
@@ -47,9 +45,12 @@ func TriggerDockerArgsProcessDeploy(appName string) error {
|
||||
}
|
||||
|
||||
if !hasDriverOpt {
|
||||
b, _ := sh.Command(common.DockerBin(), "system", "info", "--format", "{{ .LoggingDriver }}").Output()
|
||||
output := strings.TrimSpace(string(b[:]))
|
||||
if !allowedDrivers[output] {
|
||||
result, _ := common.CallExecCommand(common.ExecCommandInput{
|
||||
Command: common.DockerBin(),
|
||||
Args: []string{"system", "info", "--format", "{{ .LoggingDriver }}"},
|
||||
})
|
||||
|
||||
if !allowedDrivers[result.StdoutContents()] {
|
||||
ignoreMaxSize = true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
package network
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/dokku/dokku/plugins/common"
|
||||
|
||||
sh "github.com/codeskyblue/go-sh"
|
||||
)
|
||||
|
||||
// attachAppToNetwork attaches a container to a network
|
||||
@@ -18,7 +15,6 @@ func attachAppToNetwork(containerID string, networkName string, appName string,
|
||||
}
|
||||
|
||||
cmdParts := []string{
|
||||
common.DockerBin(),
|
||||
"network",
|
||||
"connect",
|
||||
}
|
||||
@@ -45,14 +41,16 @@ func attachAppToNetwork(containerID string, networkName string, appName string,
|
||||
|
||||
cmdParts = append(cmdParts, networkName)
|
||||
cmdParts = append(cmdParts, containerID)
|
||||
attachCmd := common.NewShellCmd(strings.Join(cmdParts, " "))
|
||||
var stderr bytes.Buffer
|
||||
attachCmd.ShowOutput = false
|
||||
attachCmd.Command.Stderr = &stderr
|
||||
_, err := attachCmd.Output()
|
||||
|
||||
result, err := common.CallExecCommand(common.ExecCommandInput{
|
||||
Command: common.DockerBin(),
|
||||
Args: cmdParts,
|
||||
})
|
||||
if err != nil {
|
||||
err = errors.New(strings.TrimSpace(stderr.String()))
|
||||
return fmt.Errorf("Unable to attach container to network: %v", err.Error())
|
||||
return fmt.Errorf("Unable to attach container to network: %w", err)
|
||||
}
|
||||
if result.ExitCode != 0 {
|
||||
return fmt.Errorf("Unable to attach container to network: %s", result.StderrContents())
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -60,20 +58,21 @@ func attachAppToNetwork(containerID string, networkName string, appName string,
|
||||
|
||||
// isContainerInNetwork returns true if the container is already attached to the specified network
|
||||
func isContainerInNetwork(containerID string, networkName string) bool {
|
||||
b, err := sh.Command(
|
||||
common.DockerBin(),
|
||||
"container",
|
||||
"inspect",
|
||||
"--format",
|
||||
"{{range $net, $v := .NetworkSettings.Networks}}{{println $net}}{{end}}",
|
||||
containerID,
|
||||
).Output()
|
||||
result, err := common.CallExecCommand(common.ExecCommandInput{
|
||||
Command: common.DockerBin(),
|
||||
Args: []string{"container", "inspect", "--format", "{{range $net, $v := .NetworkSettings.Networks}}{{println $net}}{{end}}", containerID},
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
common.LogVerboseQuiet(fmt.Sprintf("Error checking container networking status:%v", err.Error()))
|
||||
common.LogVerboseQuiet(fmt.Sprintf("Error checking container networking status: %v", err.Error()))
|
||||
return false
|
||||
}
|
||||
if result.ExitCode != 0 {
|
||||
common.LogVerboseQuiet(fmt.Sprintf("Error checking container networking status: %v", result.StderrContents()))
|
||||
return false
|
||||
}
|
||||
|
||||
for _, line := range strings.Split(strings.TrimSpace(string(b[:])), "\n") {
|
||||
for _, line := range strings.Split(result.StdoutContents(), "\n") {
|
||||
network := strings.TrimSpace(line)
|
||||
if network == "" {
|
||||
continue
|
||||
@@ -128,15 +127,19 @@ func networkExists(networkName string) (bool, error) {
|
||||
|
||||
// listNetworks returns a list of docker networks
|
||||
func listNetworks() ([]string, error) {
|
||||
b, err := sh.Command(common.DockerBin(), "network", "ls", "--format", "{{ .Name }}").Output()
|
||||
output := strings.TrimSpace(string(b[:]))
|
||||
|
||||
networks := []string{}
|
||||
result, err := common.CallExecCommand(common.ExecCommandInput{
|
||||
Command: common.DockerBin(),
|
||||
Args: []string{"network", "ls", "--format", "{{ .Name }}"},
|
||||
})
|
||||
if err != nil {
|
||||
common.LogVerboseQuiet(output)
|
||||
return networks, err
|
||||
common.LogVerboseQuiet(result.StderrContents())
|
||||
return []string{}, err
|
||||
}
|
||||
if result.ExitCode != 0 {
|
||||
common.LogVerboseQuiet(result.StderrContents())
|
||||
return []string{}, fmt.Errorf("Unable to list networks")
|
||||
}
|
||||
|
||||
networks = strings.Split(output, "\n")
|
||||
networks := strings.Split(result.StdoutContents(), "\n")
|
||||
return networks, nil
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ module github.com/dokku/dokku/plugins/network
|
||||
go 1.21
|
||||
|
||||
require (
|
||||
github.com/codeskyblue/go-sh v0.0.0-20190412065543-76bd3d59ff27
|
||||
github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000
|
||||
github.com/spf13/pflag v1.0.5
|
||||
)
|
||||
@@ -11,6 +10,7 @@ require (
|
||||
require (
|
||||
github.com/alexellis/go-execute/v2 v2.2.1 // indirect
|
||||
github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 // indirect
|
||||
github.com/codeskyblue/go-sh v0.0.0-20190412065543-76bd3d59ff27 // indirect
|
||||
github.com/fatih/color v1.16.0 // indirect
|
||||
github.com/hashicorp/errwrap v1.0.0 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[plugin]
|
||||
description = "dokku core network plugin"
|
||||
version = "0.33.5"
|
||||
version = "0.33.7"
|
||||
[plugin.config]
|
||||
|
||||
@@ -26,8 +26,7 @@ Additional commands:`
|
||||
network:rebuild <app>, Rebuilds network settings for an app
|
||||
network:rebuildall, Rebuild network settings for all apps
|
||||
network:report [<app>] [<flag>], Displays a network report for one or more apps
|
||||
network:set <app> <property> (<value>...), Set or clear a network property for an app
|
||||
`
|
||||
network:set <app> <property> (<value>...), Set or clear a network property for an app`
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -40,10 +39,8 @@ func main() {
|
||||
usage()
|
||||
case "help":
|
||||
result, err := common.CallExecCommand(common.ExecCommandInput{
|
||||
Command: "ps",
|
||||
Args: []string{"-o", "command=", strconv.Itoa(os.Getppid())},
|
||||
CaptureOutput: true,
|
||||
StreamStdio: false,
|
||||
Command: "ps",
|
||||
Args: []string{"-o", "command=", strconv.Itoa(os.Getppid())},
|
||||
})
|
||||
if err == nil && strings.Contains(result.StdoutContents(), "--all") {
|
||||
fmt.Println(helpContent)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package network
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
@@ -13,22 +12,15 @@ import (
|
||||
// CommandCreate is an alias for "docker network create"
|
||||
func CommandCreate(networkName string) error {
|
||||
common.LogInfo1Quiet(fmt.Sprintf("Creating network %v", networkName))
|
||||
createCmd := common.NewShellCmd(strings.Join([]string{
|
||||
common.DockerBin(),
|
||||
"network",
|
||||
"create",
|
||||
"--attachable",
|
||||
"--label",
|
||||
fmt.Sprintf("com.dokku.network-name=%v", networkName),
|
||||
networkName,
|
||||
}, " "))
|
||||
var stderr bytes.Buffer
|
||||
createCmd.ShowOutput = false
|
||||
createCmd.Command.Stderr = &stderr
|
||||
_, err := createCmd.Output()
|
||||
|
||||
result, err := common.CallExecCommand(common.ExecCommandInput{
|
||||
Command: common.DockerBin(),
|
||||
Args: []string{"network", "create", "--attachable", "--label", fmt.Sprintf("com.dokku.network-name=%v", networkName), networkName},
|
||||
})
|
||||
if err != nil {
|
||||
err = errors.New(strings.TrimSpace(stderr.String()))
|
||||
return fmt.Errorf("Unable to create network: %w", err)
|
||||
}
|
||||
if result.ExitCode != 0 {
|
||||
return fmt.Errorf("Unable to create network: %s", result.StderrContents())
|
||||
}
|
||||
|
||||
return err
|
||||
@@ -47,22 +39,18 @@ func CommandDestroy(networkName string, forceDestroy bool) error {
|
||||
}
|
||||
|
||||
common.LogInfo1Quiet(fmt.Sprintf("Destroying network %v", networkName))
|
||||
destroyCmd := common.NewShellCmd(strings.Join([]string{
|
||||
common.DockerBin(),
|
||||
"network",
|
||||
"rm",
|
||||
networkName,
|
||||
}, " "))
|
||||
var stderr bytes.Buffer
|
||||
destroyCmd.ShowOutput = false
|
||||
destroyCmd.Command.Stderr = &stderr
|
||||
_, err := destroyCmd.Output()
|
||||
|
||||
result, err := common.CallExecCommand(common.ExecCommandInput{
|
||||
Command: common.DockerBin(),
|
||||
Args: []string{"network", "rm", networkName},
|
||||
})
|
||||
if err != nil {
|
||||
err = errors.New(strings.TrimSpace(stderr.String()))
|
||||
return fmt.Errorf("Unable to destroy network: %w", err)
|
||||
}
|
||||
if result.ExitCode != 0 {
|
||||
return fmt.Errorf("Unable to destroy network: %s", result.StderrContents())
|
||||
}
|
||||
|
||||
return err
|
||||
return nil
|
||||
}
|
||||
|
||||
// CommandExists checks if a network exists
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[plugin]
|
||||
description = "dokku core nginx-vhosts plugin"
|
||||
version = "0.33.5"
|
||||
version = "0.33.7"
|
||||
[plugin.config]
|
||||
|
||||
1
plugins/openresty-vhosts/Dockerfile
Normal file
1
plugins/openresty-vhosts/Dockerfile
Normal file
@@ -0,0 +1 @@
|
||||
FROM dokku/openresty-docker-proxy:0.6.0
|
||||
@@ -112,7 +112,7 @@ fn-openresty-hsts-is-enabled() {
|
||||
}
|
||||
|
||||
fn-openresty-image() {
|
||||
fn-plugin-property-get-default "openresty" "--global" "image" "dokku/openresty-docker-proxy:0.6.0"
|
||||
fn-plugin-property-get-default "openresty" "--global" "image" "$(grep "FROM" "$PLUGIN_AVAILABLE_PATH/openresty-vhosts/Dockerfile" | awk '{print $2}')"
|
||||
}
|
||||
|
||||
fn-openresty-letsencrypt-email() {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[plugin]
|
||||
description = "dokku core openresty-vhosts plugin"
|
||||
version = "0.33.5"
|
||||
version = "0.33.7"
|
||||
[plugin.config]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[plugin]
|
||||
description = "dokku core plugin plugin"
|
||||
version = "0.33.5"
|
||||
version = "0.33.7"
|
||||
[plugin.config]
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
"github.com/ryanuber/columnize"
|
||||
)
|
||||
|
||||
// addPortMaps adds port mappings to an app
|
||||
func addPortMaps(appName string, portMaps []PortMap) error {
|
||||
allPortMaps := getPortMaps(appName)
|
||||
allPortMaps = append(allPortMaps, portMaps...)
|
||||
@@ -21,6 +22,7 @@ func addPortMaps(appName string, portMaps []PortMap) error {
|
||||
return setPortMaps(appName, allPortMaps)
|
||||
}
|
||||
|
||||
// clearPorts clears all port mappings for an app
|
||||
func clearPorts(appName string) error {
|
||||
if err := common.PropertyDelete("ports", appName, "map"); err != nil {
|
||||
return err
|
||||
@@ -29,6 +31,7 @@ func clearPorts(appName string) error {
|
||||
return common.PropertyDelete("ports", appName, "map-detected")
|
||||
}
|
||||
|
||||
// doesCertExist checks if a cert exists for an app
|
||||
func doesCertExist(appName string) bool {
|
||||
certsExists, _ := common.PlugnTriggerOutputAsString("certs-exists", []string{appName}...)
|
||||
if certsExists == "true" {
|
||||
@@ -39,6 +42,7 @@ func doesCertExist(appName string) bool {
|
||||
return certsForce == "true"
|
||||
}
|
||||
|
||||
// filterAppPortMaps filters the port mappings for an app
|
||||
func filterAppPortMaps(appName string, scheme string, hostPort int) []PortMap {
|
||||
var filteredPortMaps []PortMap
|
||||
for _, portMap := range getPortMaps(appName) {
|
||||
@@ -50,6 +54,7 @@ func filterAppPortMaps(appName string, scheme string, hostPort int) []PortMap {
|
||||
return filteredPortMaps
|
||||
}
|
||||
|
||||
// getAvailablePort gets an available port
|
||||
func getAvailablePort() int {
|
||||
addr, err := net.ResolveTCPAddr("tcp", "localhost:0")
|
||||
if err != nil {
|
||||
@@ -70,6 +75,7 @@ func getAvailablePort() int {
|
||||
}
|
||||
}
|
||||
|
||||
// getComputedProxyPort gets the computed proxy port for an app
|
||||
func getComputedProxyPort(appName string) int {
|
||||
port := getProxyPort(appName)
|
||||
if port == 0 {
|
||||
@@ -79,6 +85,7 @@ func getComputedProxyPort(appName string) int {
|
||||
return port
|
||||
}
|
||||
|
||||
// getComputedProxySSLPort gets the computed proxy ssl port for an app
|
||||
func getComputedProxySSLPort(appName string) int {
|
||||
port := getProxySSLPort(appName)
|
||||
if port == 0 {
|
||||
@@ -88,6 +95,7 @@ func getComputedProxySSLPort(appName string) int {
|
||||
return port
|
||||
}
|
||||
|
||||
// getDetectedPortMaps gets the detected port mappings for an app
|
||||
func getDetectedPortMaps(appName string) []PortMap {
|
||||
basePort := getComputedProxyPort(appName)
|
||||
if basePort == 0 {
|
||||
@@ -145,6 +153,7 @@ func getDetectedPortMaps(appName string) []PortMap {
|
||||
return portMaps
|
||||
}
|
||||
|
||||
// getGlobalProxyPort gets the global proxy port
|
||||
func getGlobalProxyPort() int {
|
||||
port := 0
|
||||
b, _ := common.PlugnTriggerOutput("config-get-global", []string{"DOKKU_PROXY_PORT"}...)
|
||||
@@ -155,6 +164,7 @@ func getGlobalProxyPort() int {
|
||||
return port
|
||||
}
|
||||
|
||||
// getGlobalProxySSLPort gets the global proxy ssl port
|
||||
func getGlobalProxySSLPort() int {
|
||||
port := 0
|
||||
b, _ := common.PlugnTriggerOutput("config-get-global", []string{"DOKKU_PROXY_SSL_PORT"}...)
|
||||
@@ -165,6 +175,7 @@ func getGlobalProxySSLPort() int {
|
||||
return port
|
||||
}
|
||||
|
||||
// getPortMaps gets the port mappings for an app
|
||||
func getPortMaps(appName string) []PortMap {
|
||||
value, err := common.PropertyListGet("ports", appName, "map")
|
||||
if err != nil {
|
||||
@@ -175,6 +186,7 @@ func getPortMaps(appName string) []PortMap {
|
||||
return portMaps
|
||||
}
|
||||
|
||||
// getProxyPort gets the proxy port for an app
|
||||
func getProxyPort(appName string) int {
|
||||
port := 0
|
||||
b, _ := common.PlugnTriggerOutput("config-get", []string{appName, "DOKKU_PROXY_PORT"}...)
|
||||
@@ -185,6 +197,7 @@ func getProxyPort(appName string) int {
|
||||
return port
|
||||
}
|
||||
|
||||
// getProxySSLPort gets the proxy ssl port for an app
|
||||
func getProxySSLPort(appName string) int {
|
||||
port := 0
|
||||
b, _ := common.PlugnTriggerOutput("config-get", []string{appName, "DOKKU_PROXY_SSL_PORT"}...)
|
||||
@@ -195,6 +208,7 @@ func getProxySSLPort(appName string) int {
|
||||
return port
|
||||
}
|
||||
|
||||
// initializeProxyPort initializes the proxy port for an app
|
||||
func initializeProxyPort(appName string) error {
|
||||
port := getProxyPort(appName)
|
||||
if port != 0 {
|
||||
@@ -219,6 +233,7 @@ func initializeProxyPort(appName string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// initializeProxySSLPort initializes the proxy ssl port for an app
|
||||
func initializeProxySSLPort(appName string) error {
|
||||
port := getProxySSLPort(appName)
|
||||
if port != 0 {
|
||||
@@ -246,10 +261,12 @@ func initializeProxySSLPort(appName string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// inRange checks if a value is within a range
|
||||
func inRange(value int, min int, max int) bool {
|
||||
return min < value && value < max
|
||||
}
|
||||
|
||||
// isAppVhostEnabled checks if the app vhost is enabled
|
||||
func isAppVhostEnabled(appName string) bool {
|
||||
if err := common.PlugnTrigger("domains-vhost-enabled", []string{appName}...); err != nil {
|
||||
return false
|
||||
@@ -257,6 +274,7 @@ func isAppVhostEnabled(appName string) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// listAppPortMaps lists the port mappings for an app
|
||||
func listAppPortMaps(appName string) error {
|
||||
portMaps := getPortMaps(appName)
|
||||
|
||||
@@ -283,6 +301,7 @@ func listAppPortMaps(appName string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// parsePortMapString parses a port map string into a slice of PortMap structs
|
||||
func parsePortMapString(stringPortMap string) ([]PortMap, error) {
|
||||
var portMaps []PortMap
|
||||
|
||||
@@ -334,9 +353,10 @@ func parsePortMapString(stringPortMap string) ([]PortMap, error) {
|
||||
})
|
||||
}
|
||||
|
||||
return uniquePortMaps(portMaps), nil
|
||||
return portMaps, nil
|
||||
}
|
||||
|
||||
// removePortMaps removes specific port mappings from an app
|
||||
func removePortMaps(appName string, portMaps []PortMap) error {
|
||||
toRemove := map[string]bool{}
|
||||
toRemoveByPort := map[int]bool{}
|
||||
@@ -369,9 +389,29 @@ func removePortMaps(appName string, portMaps []PortMap) error {
|
||||
return setPortMaps(appName, toSet)
|
||||
}
|
||||
|
||||
// reusesSchemeHostPort returns true if the port maps reuse the same scheme:host-port
|
||||
func reusesSchemeHostPort(portMaps []PortMap) error {
|
||||
found := map[string]bool{}
|
||||
|
||||
for _, portMap := range portMaps {
|
||||
key := fmt.Sprintf("%s:%d", portMap.Scheme, portMap.HostPort)
|
||||
if found[key] {
|
||||
return fmt.Errorf("The same scheme:host-port is being reused: %s", key)
|
||||
}
|
||||
found[key] = true
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// setPortMaps sets the port maps for an app
|
||||
func setPortMaps(appName string, portMaps []PortMap) error {
|
||||
if err := reusesSchemeHostPort(portMaps); err != nil {
|
||||
return fmt.Errorf("Error validating port mappings: %s", err)
|
||||
}
|
||||
|
||||
var value []string
|
||||
for _, portMap := range uniquePortMaps(portMaps) {
|
||||
for _, portMap := range portMaps {
|
||||
if portMap.AllowsPersistence() {
|
||||
continue
|
||||
}
|
||||
@@ -383,6 +423,7 @@ func setPortMaps(appName string, portMaps []PortMap) error {
|
||||
return common.PropertyListWrite("ports", appName, "map", value)
|
||||
}
|
||||
|
||||
// setProxyPort sets the proxy port for an app
|
||||
func setProxyPort(appName string, port int) error {
|
||||
return common.EnvWrap(func() error {
|
||||
entries := map[string]string{
|
||||
@@ -392,6 +433,7 @@ func setProxyPort(appName string, port int) error {
|
||||
}, map[string]string{"DOKKU_QUIET_OUTPUT": "1"})
|
||||
}
|
||||
|
||||
// setProxySSLPort sets the proxy ssl port for an app
|
||||
func setProxySSLPort(appName string, port int) error {
|
||||
return common.EnvWrap(func() error {
|
||||
entries := map[string]string{
|
||||
@@ -401,18 +443,20 @@ func setProxySSLPort(appName string, port int) error {
|
||||
}, map[string]string{"DOKKU_QUIET_OUTPUT": "1"})
|
||||
}
|
||||
|
||||
// uniquePortMaps returns a unique set of port maps
|
||||
func uniquePortMaps(portMaps []PortMap) []PortMap {
|
||||
var unique []PortMap
|
||||
existingPortMaps := map[string]bool{}
|
||||
uniquePortMaps := []PortMap{}
|
||||
found := map[string]bool{}
|
||||
|
||||
for _, portMap := range portMaps {
|
||||
if existingPortMaps[portMap.String()] {
|
||||
key := fmt.Sprintf("%s:%d", portMap.Scheme, portMap.HostPort)
|
||||
if found[key] {
|
||||
continue
|
||||
}
|
||||
|
||||
existingPortMaps[portMap.String()] = true
|
||||
unique = append(unique, portMap)
|
||||
found[key] = true
|
||||
uniquePortMaps = append(uniquePortMaps, portMap)
|
||||
}
|
||||
|
||||
return unique
|
||||
return uniquePortMaps
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[plugin]
|
||||
description = "dokku core ports plugin"
|
||||
version = "0.33.5"
|
||||
version = "0.33.7"
|
||||
[plugin.config]
|
||||
|
||||
@@ -6,9 +6,14 @@ import (
|
||||
|
||||
// PortMap is a struct that contains a scheme:host-port:container-port mapping
|
||||
type PortMap struct {
|
||||
ContainerPort int `json:"container_port"`
|
||||
HostPort int `json:"host_port"`
|
||||
Scheme string `json:"scheme"`
|
||||
// ContainerPort is the port on the container
|
||||
ContainerPort int `json:"container_port"`
|
||||
|
||||
// HostPort is the port on the host
|
||||
HostPort int `json:"host_port"`
|
||||
|
||||
// Scheme is the scheme of the port mapping
|
||||
Scheme string `json:"scheme"`
|
||||
}
|
||||
|
||||
func (p PortMap) String() string {
|
||||
|
||||
@@ -23,8 +23,7 @@ Additional commands:`
|
||||
ports:clear <app>, Clear all port mappings for an app
|
||||
ports:remove <app> [<host-port>|<scheme>:<host-port>:<container-port>...], Remove specific port mappings from an app
|
||||
ports:set <app> [<scheme>:<host-port>:<container-port>...], Set port mappings for an app
|
||||
ports:report [<app>] [<flag>], Displays a ports report for one or more apps
|
||||
`
|
||||
ports:report [<app>] [<flag>], Displays a ports report for one or more apps`
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -37,10 +36,8 @@ func main() {
|
||||
usage()
|
||||
case "help":
|
||||
result, err := common.CallExecCommand(common.ExecCommandInput{
|
||||
Command: "ps",
|
||||
Args: []string{"-o", "command=", strconv.Itoa(os.Getppid())},
|
||||
CaptureOutput: true,
|
||||
StreamStdio: false,
|
||||
Command: "ps",
|
||||
Args: []string{"-o", "command=", strconv.Itoa(os.Getppid())},
|
||||
})
|
||||
if err == nil && strings.Contains(result.StdoutContents(), "--all") {
|
||||
fmt.Println(helpContent)
|
||||
|
||||
@@ -2,6 +2,7 @@ package ports
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/dokku/dokku/plugins/common"
|
||||
@@ -31,6 +32,16 @@ func CommandAdd(appName string, portMapStrings []string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := reusesSchemeHostPort(portMaps); err != nil {
|
||||
return fmt.Errorf("Error validating new port mappings: %s", err)
|
||||
}
|
||||
|
||||
existingPortMaps := getPortMaps(appName)
|
||||
allPortMaps := append(existingPortMaps, portMaps...)
|
||||
if err := reusesSchemeHostPort(allPortMaps); err != nil {
|
||||
return fmt.Errorf("Error validating all port mappings: %s", err)
|
||||
}
|
||||
|
||||
if err := addPortMaps(appName, portMaps); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -88,6 +99,10 @@ func CommandSet(appName string, portMapStrings []string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := reusesSchemeHostPort(portMaps); err != nil {
|
||||
return fmt.Errorf("Error validating port mappings: %s", err)
|
||||
}
|
||||
|
||||
if err := setPortMaps(appName, portMaps); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -87,6 +87,8 @@ func TriggerPortsGet(appName string, format string) error {
|
||||
persisted = append(persisted, portMap)
|
||||
}
|
||||
|
||||
persisted = uniquePortMaps(persisted)
|
||||
|
||||
if format == "json" {
|
||||
b, err := json.Marshal(persisted)
|
||||
if err != nil {
|
||||
@@ -207,6 +209,8 @@ func TriggerPostCertsUpdate(appName string) error {
|
||||
}
|
||||
}
|
||||
|
||||
http80Ports = uniquePortMaps(http80Ports)
|
||||
|
||||
if len(http80Ports) > 0 {
|
||||
var https443Ports []PortMap
|
||||
for _, portMap := range portMaps {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[plugin]
|
||||
description = "dokku core proxy plugin"
|
||||
version = "0.33.5"
|
||||
version = "0.33.7"
|
||||
[plugin.config]
|
||||
|
||||
@@ -23,8 +23,7 @@ Additional commands:`
|
||||
proxy:disable <app>, Disable proxy for app
|
||||
proxy:enable <app>, Enable proxy for app
|
||||
proxy:report [<app>] [<flag>], Displays a proxy report for one or more apps
|
||||
proxy:set <app> <proxy-type>, Set proxy type for app
|
||||
`
|
||||
proxy:set <app> <proxy-type>, Set proxy type for app`
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -37,10 +36,8 @@ func main() {
|
||||
usage()
|
||||
case "help":
|
||||
result, err := common.CallExecCommand(common.ExecCommandInput{
|
||||
Command: "ps",
|
||||
Args: []string{"-o", "command=", strconv.Itoa(os.Getppid())},
|
||||
CaptureOutput: true,
|
||||
StreamStdio: false,
|
||||
Command: "ps",
|
||||
Args: []string{"-o", "command=", strconv.Itoa(os.Getppid())},
|
||||
})
|
||||
if err == nil && strings.Contains(result.StdoutContents(), "--all") {
|
||||
fmt.Println(helpContent)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package ps
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
@@ -24,26 +23,18 @@ func getProcfileCommand(procfilePath string, processType string, port int) (stri
|
||||
return "", errors.New("No procfile found")
|
||||
}
|
||||
|
||||
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()
|
||||
|
||||
result, err := common.CallExecCommand(common.ExecCommandInput{
|
||||
Command: "procfile-util",
|
||||
Args: []string{"show", "--procfile", procfilePath, "--process-type", processType, "--default-port", strconv.Itoa(port)},
|
||||
})
|
||||
if err != nil {
|
||||
return "", fmt.Errorf(strings.TrimSpace(stderr.String()))
|
||||
return "", fmt.Errorf("Error running procfile-util: %s", err)
|
||||
}
|
||||
if result.ExitCode != 0 {
|
||||
return "", fmt.Errorf("Error running procfile-util: %s", result.StderrContents())
|
||||
}
|
||||
|
||||
return strings.TrimSpace(string(b[:])), nil
|
||||
return result.StdoutContents(), nil
|
||||
}
|
||||
|
||||
func getProcfilePath(appName string) string {
|
||||
@@ -154,22 +145,18 @@ func parseProcessTuples(processTuples []string) (FormationSlice, error) {
|
||||
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()
|
||||
|
||||
result, err := common.CallExecCommand(common.ExecCommandInput{
|
||||
Command: "procfile-util",
|
||||
Args: []string{"list", "--procfile", procfilePath},
|
||||
})
|
||||
if err != nil {
|
||||
return processes, fmt.Errorf(strings.TrimSpace(stderr.String()))
|
||||
return processes, fmt.Errorf("Error listing processes: %s", err)
|
||||
}
|
||||
if result.ExitCode != 0 {
|
||||
return processes, fmt.Errorf("Error listing processes: %s", result.StderrContents())
|
||||
}
|
||||
|
||||
for _, s := range strings.Split(strings.TrimSpace(string(b[:])), "\n") {
|
||||
for _, s := range strings.Split(result.StdoutContents(), "\n") {
|
||||
processes[s] = true
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ module github.com/dokku/dokku/plugins/ps
|
||||
go 1.21
|
||||
|
||||
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
|
||||
@@ -14,6 +13,7 @@ require (
|
||||
require (
|
||||
github.com/alexellis/go-execute/v2 v2.2.1 // indirect
|
||||
github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 // indirect
|
||||
github.com/codeskyblue/go-sh v0.0.0-20190412065543-76bd3d59ff27 // indirect
|
||||
github.com/fatih/color v1.16.0 // indirect
|
||||
github.com/hashicorp/errwrap v1.0.0 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[plugin]
|
||||
description = "dokku core ps plugin"
|
||||
version = "0.33.5"
|
||||
version = "0.33.7"
|
||||
[plugin.config]
|
||||
|
||||
@@ -40,10 +40,8 @@ func main() {
|
||||
usage()
|
||||
case "help":
|
||||
result, err := common.CallExecCommand(common.ExecCommandInput{
|
||||
Command: "ps",
|
||||
Args: []string{"-o", "command=", strconv.Itoa(os.Getppid())},
|
||||
CaptureOutput: true,
|
||||
StreamStdio: false,
|
||||
Command: "ps",
|
||||
Args: []string{"-o", "command=", strconv.Itoa(os.Getppid())},
|
||||
})
|
||||
if err == nil && strings.Contains(result.StdoutContents(), "--all") {
|
||||
fmt.Println(helpContent)
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
sh "github.com/codeskyblue/go-sh"
|
||||
"github.com/dokku/dokku/plugins/common"
|
||||
"github.com/dokku/dokku/plugins/config"
|
||||
dockeroptions "github.com/dokku/dokku/plugins/docker-options"
|
||||
@@ -103,8 +102,15 @@ func TriggerCorePostExtract(appName string, sourceWorkDir string) error {
|
||||
}
|
||||
}
|
||||
|
||||
if b, err := sh.Command("procfile-util", "check", "-P", processSpecificProcfile).CombinedOutput(); err != nil {
|
||||
return fmt.Errorf(strings.TrimSpace(string(b[:])))
|
||||
result, err := common.CallExecCommand(common.ExecCommandInput{
|
||||
Command: "procfile-util",
|
||||
Args: []string{"check", "-P", processSpecificProcfile},
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf(result.StderrContents())
|
||||
}
|
||||
if result.ExitCode != 0 {
|
||||
return fmt.Errorf("Invalid Procfile: %s", result.StderrContents())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -4,12 +4,10 @@ import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"github.com/codeskyblue/go-sh"
|
||||
"github.com/dokku/dokku/plugins/common"
|
||||
)
|
||||
|
||||
@@ -152,25 +150,21 @@ func pushToRegistry(appName string, tag int, imageID string, imageRepo string) e
|
||||
}
|
||||
|
||||
func dockerTag(imageID string, imageTag string) bool {
|
||||
cmd := sh.Command(common.DockerBin(), "image", "tag", imageID, imageTag)
|
||||
cmd.Stdout = nil
|
||||
cmd.Stderr = nil
|
||||
if err := cmd.Run(); err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
result, err := common.CallExecCommand(common.ExecCommandInput{
|
||||
Command: common.DockerBin(),
|
||||
Args: []string{"image", "tag", imageID, imageTag},
|
||||
StreamStdio: true,
|
||||
})
|
||||
return err == nil && result.ExitCode == 0
|
||||
}
|
||||
|
||||
func dockerPush(imageTag string) bool {
|
||||
cmd := sh.Command(common.DockerBin(), "image", "push", imageTag)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
if err := cmd.Run(); err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
result, err := common.CallExecCommand(common.ExecCommandInput{
|
||||
Command: common.DockerBin(),
|
||||
Args: []string{"image", "push", imageTag},
|
||||
StreamStdio: true,
|
||||
})
|
||||
return err == nil && result.ExitCode == 0
|
||||
}
|
||||
|
||||
func imageCleanup(appName string, imageRepo string, imageTag string, tag int) {
|
||||
|
||||
@@ -3,7 +3,6 @@ module github.com/dokku/dokku/plugins/registry
|
||||
go 1.21
|
||||
|
||||
require (
|
||||
github.com/codeskyblue/go-sh v0.0.0-20190412065543-76bd3d59ff27
|
||||
github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000
|
||||
github.com/spf13/pflag v1.0.5
|
||||
)
|
||||
@@ -11,6 +10,7 @@ require (
|
||||
require (
|
||||
github.com/alexellis/go-execute/v2 v2.2.1 // indirect
|
||||
github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 // indirect
|
||||
github.com/codeskyblue/go-sh v0.0.0-20190412065543-76bd3d59ff27 // indirect
|
||||
github.com/fatih/color v1.16.0 // indirect
|
||||
github.com/hashicorp/errwrap v1.0.0 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[plugin]
|
||||
description = "dokku core registry plugin"
|
||||
version = "0.33.5"
|
||||
version = "0.33.7"
|
||||
[plugin.config]
|
||||
|
||||
@@ -20,8 +20,7 @@ Additional commands:`
|
||||
helpContent = `
|
||||
registry:login [--password-stdin] <server> <username> [<password>], Login to a docker registry
|
||||
registry:report [<app>] [<flag>], Displays a registry report for one or more apps
|
||||
registry:set <app> <property> (<value>), Set or clear a registry property for an app
|
||||
`
|
||||
registry:set <app> <property> (<value>), Set or clear a registry property for an app`
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -34,10 +33,8 @@ func main() {
|
||||
usage()
|
||||
case "help":
|
||||
result, err := common.CallExecCommand(common.ExecCommandInput{
|
||||
Command: "ps",
|
||||
Args: []string{"-o", "command=", strconv.Itoa(os.Getppid())},
|
||||
CaptureOutput: true,
|
||||
StreamStdio: false,
|
||||
Command: "ps",
|
||||
Args: []string{"-o", "command=", strconv.Itoa(os.Getppid())},
|
||||
})
|
||||
if err == nil && strings.Contains(result.StdoutContents(), "--all") {
|
||||
fmt.Println(helpContent)
|
||||
|
||||
@@ -3,6 +3,7 @@ package registry
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
@@ -35,29 +36,26 @@ func CommandLogin(server string, username string, password string, passwordStdin
|
||||
server = "docker.io"
|
||||
}
|
||||
|
||||
command := []string{
|
||||
common.DockerBin(),
|
||||
"login",
|
||||
"--username",
|
||||
username,
|
||||
"--password-stdin",
|
||||
server,
|
||||
}
|
||||
|
||||
buffer := bytes.Buffer{}
|
||||
buffer.Write([]byte(password + "\n"))
|
||||
|
||||
loginCmd := common.NewShellCmd(strings.Join(command, " "))
|
||||
loginCmd.Command.Stdin = &buffer
|
||||
if !loginCmd.Execute() {
|
||||
return errors.New("Failed to log into registry")
|
||||
result, err := common.CallExecCommand(common.ExecCommandInput{
|
||||
Command: common.DockerBin(),
|
||||
Args: []string{"login", "--username", username, "--password-stdin", server},
|
||||
Stdin: &buffer,
|
||||
StreamStdio: true,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to run docker login: %w", err)
|
||||
}
|
||||
if result.ExitCode != 0 {
|
||||
return fmt.Errorf("Unable to run docker login: %s", result.StderrContents())
|
||||
}
|
||||
|
||||
_, err := common.CallPlugnTrigger(common.PlugnTriggerInput{
|
||||
Trigger: "post-registry-login",
|
||||
Args: []string{server, username},
|
||||
StreamStdio: true,
|
||||
CaptureOutput: false,
|
||||
_, err = common.CallPlugnTrigger(common.PlugnTriggerInput{
|
||||
Trigger: "post-registry-login",
|
||||
Args: []string{server, username},
|
||||
StreamStdio: true,
|
||||
Env: map[string]string{
|
||||
"DOCKER_REGISTRY_PASS": password,
|
||||
},
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[plugin]
|
||||
description = "dokku core repo plugin"
|
||||
version = "0.33.5"
|
||||
version = "0.33.7"
|
||||
[plugin.config]
|
||||
|
||||
@@ -2,8 +2,6 @@ package repo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/dokku/dokku/plugins/common"
|
||||
)
|
||||
@@ -33,18 +31,16 @@ func PurgeCache(appName string) error {
|
||||
if len(containerIDs) > 0 {
|
||||
common.DockerRemoveContainers(containerIDs)
|
||||
}
|
||||
purgeCacheCmd := common.NewShellCmd(strings.Join([]string{
|
||||
common.DockerBin(),
|
||||
"volume",
|
||||
"rm", "-f", fmt.Sprintf("cache-%s", appName)}, " "))
|
||||
purgeCacheCmd.ShowOutput = false
|
||||
purgeCacheCmd.Command.Stderr = os.Stderr
|
||||
if !purgeCacheCmd.Execute() {
|
||||
exitCode := 1
|
||||
if purgeCacheCmd.ExitError != nil {
|
||||
exitCode = purgeCacheCmd.ExitError.ExitCode()
|
||||
}
|
||||
return &PurgeCacheFailed{exitCode}
|
||||
result, err := common.CallExecCommand(common.ExecCommandInput{
|
||||
Command: common.DockerBin(),
|
||||
Args: []string{"volume", "rm", "-f", fmt.Sprintf("cache-%s", appName)},
|
||||
StreamStderr: true,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to remove cache volume: %w", err)
|
||||
}
|
||||
if result.ExitCode != 0 {
|
||||
return &PurgeCacheFailed{result.ExitCode}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -19,8 +19,7 @@ Additional commands:`
|
||||
|
||||
helpContent = `
|
||||
repo:gc <app>, Runs 'git gc --aggressive' against the application's repo
|
||||
repo:purge-cache <app>, Deletes the contents of the build cache stored in the repository
|
||||
`
|
||||
repo:purge-cache <app>, Deletes the contents of the build cache stored in the repository`
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -33,10 +32,8 @@ func main() {
|
||||
usage()
|
||||
case "help":
|
||||
result, err := common.CallExecCommand(common.ExecCommandInput{
|
||||
Command: "ps",
|
||||
Args: []string{"-o", "command=", strconv.Itoa(os.Getppid())},
|
||||
CaptureOutput: true,
|
||||
StreamStdio: false,
|
||||
Command: "ps",
|
||||
Args: []string{"-o", "command=", strconv.Itoa(os.Getppid())},
|
||||
})
|
||||
if err == nil && strings.Contains(result.StdoutContents(), "--all") {
|
||||
fmt.Println(helpContent)
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package repo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/dokku/dokku/plugins/common"
|
||||
)
|
||||
|
||||
@@ -14,9 +16,20 @@ func CommandGc(appName string) error {
|
||||
cmdEnv := map[string]string{
|
||||
"GIT_DIR": appRoot,
|
||||
}
|
||||
gitGcCmd := common.NewShellCmd("git gc --aggressive")
|
||||
gitGcCmd.Env = cmdEnv
|
||||
gitGcCmd.Execute()
|
||||
|
||||
result, err := common.CallExecCommand(common.ExecCommandInput{
|
||||
Command: "git",
|
||||
Args: []string{"gc", "--aggressive"},
|
||||
Env: cmdEnv,
|
||||
StreamStdio: true,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to run git gc: %w", err)
|
||||
}
|
||||
if result.ExitCode != 0 {
|
||||
return fmt.Errorf("Unable to run git gc: %s", result.StderrContents())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[plugin]
|
||||
description = "dokku core resource plugin"
|
||||
version = "0.33.5"
|
||||
version = "0.33.7"
|
||||
[plugin.config]
|
||||
|
||||
@@ -22,8 +22,7 @@ Additional commands:`
|
||||
resource:limit-clear [--process-type <process-type>] <app>, Limit resources for a given app/process-type combination
|
||||
resource:report [<app>] [<flag>], Displays a resource report for one or more apps
|
||||
resource:reserve [--process-type <process-type>] [RESOURCE_OPTS...] <app>, Reserve resources for a given app/process-type combination
|
||||
resource:reserve-clear [--process-type <process-type>] <app>, Reserve resources for a given app/process-type combination
|
||||
`
|
||||
resource:reserve-clear [--process-type <process-type>] <app>, Reserve resources for a given app/process-type combination`
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -36,10 +35,8 @@ func main() {
|
||||
usage()
|
||||
case "help":
|
||||
result, err := common.CallExecCommand(common.ExecCommandInput{
|
||||
Command: "ps",
|
||||
Args: []string{"-o", "command=", strconv.Itoa(os.Getppid())},
|
||||
CaptureOutput: true,
|
||||
StreamStdio: false,
|
||||
Command: "ps",
|
||||
Args: []string{"-o", "command=", strconv.Itoa(os.Getppid())},
|
||||
})
|
||||
if err == nil && strings.Contains(result.StdoutContents(), "--all") {
|
||||
fmt.Println(helpContent)
|
||||
|
||||
@@ -28,7 +28,7 @@ fn-help-content() {
|
||||
declare desc="return help content"
|
||||
cat <<help_content
|
||||
run [-e|--env KEY=VALUE] [--no-tty] <app> <cmd>, Run a command in a new container using the current app image
|
||||
run:detached [-e|-env KEY=VALUE] [--no-tty|--force-tty] <app> <cmd>, Run a command in a new detached container using the current app image
|
||||
run:detached [-e|-env KEY=VALUE] [--force-tty] <app> <cmd>, Run a command in a new detached container using the current app image
|
||||
run:list [--format json|stdout] <app>, List all run containers for an app
|
||||
run:logs <app|--container CONTAINER> [-h] [-t] [-n num] [-q], Display recent log output for run containers
|
||||
run:stop <app|--container CONTAINER>, Stops all run containers for an app or a specified run container
|
||||
|
||||
@@ -5,6 +5,8 @@ source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
|
||||
|
||||
fn-run() {
|
||||
declare desc="runs command in container"
|
||||
declare CMD="$1"
|
||||
shift 1
|
||||
|
||||
declare APP=""
|
||||
local CRON_ID
|
||||
@@ -54,6 +56,10 @@ fn-run() {
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ "$CMD" == "run:detached" ]] && [[ "$DOKKU_FORCE_TTY" != "true" ]]; then
|
||||
export DOKKU_DISABLE_TTY=true
|
||||
fi
|
||||
|
||||
if [[ "$DOKKU_DISABLE_TTY" == "true" ]] && [[ "$DOKKU_FORCE_TTY" == "true" ]]; then
|
||||
dokku_log_fail "Cannot specify both --force-tty and --no-tty"
|
||||
fi
|
||||
@@ -70,7 +76,7 @@ cmd-run() {
|
||||
[[ "$1" == "$cmd" ]] && shift 1
|
||||
|
||||
export DOKKU_RM_CONTAINER=1
|
||||
fn-run "$@"
|
||||
fn-run "$cmd" "$@"
|
||||
}
|
||||
|
||||
cmd-run-detached() {
|
||||
@@ -79,9 +85,8 @@ cmd-run-detached() {
|
||||
[[ "$1" == "$cmd" ]] && shift 1
|
||||
|
||||
export DOKKU_DETACH_CONTAINER=1
|
||||
export DOKKU_DISABLE_TTY=true
|
||||
export DOKKU_RM_CONTAINER=1
|
||||
fn-run "$@"
|
||||
fn-run "$cmd" "$@"
|
||||
}
|
||||
|
||||
cmd-run-list() {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[plugin]
|
||||
description = "dokku core run plugin"
|
||||
version = "0.33.5"
|
||||
version = "0.33.7"
|
||||
[plugin.config]
|
||||
|
||||
@@ -15,17 +15,25 @@ import (
|
||||
)
|
||||
|
||||
func deleteCrontab() error {
|
||||
command := common.NewShellCmd("sudo /usr/bin/crontab -l -u dokku")
|
||||
command.ShowOutput = false
|
||||
if !command.Execute() {
|
||||
result, err := common.CallExecCommand(common.ExecCommandInput{
|
||||
Command: "/usr/bin/crontab",
|
||||
Args: []string{"-l", "-u", "dokku"},
|
||||
Sudo: true,
|
||||
})
|
||||
if err != nil || result.ExitCode != 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
command = common.NewShellCmd("sudo /usr/bin/crontab -r -u dokku")
|
||||
command.ShowOutput = false
|
||||
out, err := command.CombinedOutput()
|
||||
result, err = common.CallExecCommand(common.ExecCommandInput{
|
||||
Command: "/usr/bin/crontab",
|
||||
Args: []string{"-r", "-u", "dokku"},
|
||||
Sudo: true,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to remove schedule file: %v", string(out))
|
||||
return fmt.Errorf("Unable to remove schedule file: %w", err)
|
||||
}
|
||||
if result.ExitCode != 0 {
|
||||
return fmt.Errorf("Unable to remove schedule file: %s", result.StderrContents())
|
||||
}
|
||||
|
||||
common.LogInfo1("Removed")
|
||||
@@ -139,11 +147,16 @@ func writeCronEntries() error {
|
||||
return fmt.Errorf("Unable to template out schedule file: %v", err)
|
||||
}
|
||||
|
||||
command := common.NewShellCmd(fmt.Sprintf("sudo /usr/bin/crontab -u dokku %s", tmpFile.Name()))
|
||||
command.ShowOutput = false
|
||||
out, err := command.CombinedOutput()
|
||||
result, err := common.CallExecCommand(common.ExecCommandInput{
|
||||
Command: "/usr/bin/crontab",
|
||||
Args: []string{"-u", "dokku", tmpFile.Name()},
|
||||
Sudo: true,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to update schedule file: %s", string(out))
|
||||
return fmt.Errorf("Unable to update schedule file: %w", err)
|
||||
}
|
||||
if result.ExitCode != 0 {
|
||||
return fmt.Errorf("Unable to update schedule file: %s", result.StderrContents())
|
||||
}
|
||||
|
||||
common.LogInfo1("Updated schedule file")
|
||||
|
||||
@@ -29,7 +29,7 @@ require (
|
||||
github.com/ryanuber/columnize v2.1.2+incompatible // indirect
|
||||
golang.org/x/crypto v0.19.0 // indirect
|
||||
golang.org/x/sys v0.17.0 // indirect
|
||||
mvdan.cc/sh/v3 v3.7.0 // indirect
|
||||
mvdan.cc/sh/v3 v3.8.0 // indirect
|
||||
)
|
||||
|
||||
replace github.com/dokku/dokku/plugins/app-json => ../app-json
|
||||
|
||||
@@ -8,8 +8,8 @@ github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
|
||||
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
|
||||
github.com/frankban/quicktest v1.14.5 h1:dfYrrRyLtiqT9GyKXgdh+k4inNeTvmGbuSgZ3lx3GhA=
|
||||
github.com/frankban/quicktest v1.14.5/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
|
||||
@@ -47,8 +47,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
||||
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
||||
github.com/rogpeppe/go-internal v1.10.1-0.20230524175051-ec119421bb97 h1:3RPlVWzZ/PDqmVuf/FKHARG5EMid/tl7cv54Sw/QRVY=
|
||||
github.com/rogpeppe/go-internal v1.10.1-0.20230524175051-ec119421bb97/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
|
||||
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
||||
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
||||
github.com/ryanuber/columnize v2.1.2+incompatible h1:C89EOx/XBWwIXl8wm8OPJBd7kPF25UfsK2X7Ph/zCAk=
|
||||
github.com/ryanuber/columnize v2.1.2+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
@@ -105,5 +105,5 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
mvdan.cc/sh/v3 v3.7.0 h1:lSTjdP/1xsddtaKfGg7Myu7DnlHItd3/M2tomOcNNBg=
|
||||
mvdan.cc/sh/v3 v3.7.0/go.mod h1:K2gwkaesF/D7av7Kxl0HbF5kGOd2ArupNTX3X44+8l8=
|
||||
mvdan.cc/sh/v3 v3.8.0 h1:ZxuJipLZwr/HLbASonmXtcvvC9HXY9d2lXZHnKGjFc8=
|
||||
mvdan.cc/sh/v3 v3.8.0/go.mod h1:w04623xkgBVo7/IUK89E0g8hBykgEpN0vgOj3RJr6MY=
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[plugin]
|
||||
description = "dokku core scheduler-docker-local plugin"
|
||||
version = "0.33.5"
|
||||
version = "0.33.7"
|
||||
[plugin.config]
|
||||
|
||||
@@ -35,7 +35,7 @@ trigger-scheduler-docker-local-scheduler-logs() {
|
||||
if [[ $PRETTY_PRINT == "true" ]]; then
|
||||
local DOKKU_LOGS_CMD+="($DOCKER_BIN logs $DOKKU_LOGS_ARGS $CID 2>&1)"
|
||||
else
|
||||
local DOKKU_LOGS_PRETTY_PRINT_CMD="sed -r 's/^([^Z]+Z )/\x1b[${COLOR}m\1app[$DYNO]:\x1b[0m /gm'"
|
||||
local DOKKU_LOGS_PRETTY_PRINT_CMD="sed -u -r 's/^([^Z]+Z )/\x1b[${COLOR}m\1app[$DYNO]:\x1b[0m /gm'"
|
||||
local DOKKU_LOGS_CMD+="($DOCKER_BIN logs -t $DOKKU_LOGS_ARGS $CID 2>&1 | $DOKKU_LOGS_PRETTY_PRINT_CMD)"
|
||||
fi
|
||||
if [[ $i != "$MAX_INDEX" ]]; then
|
||||
|
||||
@@ -38,7 +38,7 @@ trigger-scheduler-docker-local-scheduler-logs() {
|
||||
if [[ $PRETTY_PRINT == "true" ]]; then
|
||||
local DOKKU_LOGS_CMD+="($DOCKER_BIN logs $DOKKU_LOGS_ARGS $CID 2>&1)"
|
||||
else
|
||||
local DOKKU_LOGS_PRETTY_PRINT_CMD="sed -r 's/^([^Z]+Z )/\x1b[${COLOR}m\1app[$DYNO]:\x1b[0m /gm'"
|
||||
local DOKKU_LOGS_PRETTY_PRINT_CMD="sed -u -r 's/^([^Z]+Z )/\x1b[${COLOR}m\1app[$DYNO]:\x1b[0m /gm'"
|
||||
local DOKKU_LOGS_CMD+="($DOCKER_BIN logs -t $DOKKU_LOGS_ARGS $CID 2>&1 | $DOKKU_LOGS_PRETTY_PRINT_CMD)"
|
||||
fi
|
||||
if [[ $i != "$MAX_INDEX" ]]; then
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
SUBCOMMANDS = subcommands/initialize subcommands/cluster-add subcommands/cluster-list subcommands/cluster-remove subcommands/report subcommands/set subcommands/show-kubeconfig subcommands/uninstall
|
||||
TRIGGERS = triggers/install triggers/post-app-clone-setup triggers/post-app-rename-setup triggers/post-delete triggers/post-registry-login triggers/report triggers/scheduler-deploy triggers/scheduler-enter triggers/scheduler-logs triggers/scheduler-post-delete triggers/scheduler-run triggers/scheduler-run-list triggers/scheduler-stop
|
||||
TRIGGERS = triggers/install triggers/post-app-clone-setup triggers/post-app-rename-setup triggers/post-delete triggers/report triggers/scheduler-deploy triggers/scheduler-enter triggers/scheduler-logs triggers/scheduler-post-delete triggers/scheduler-run triggers/scheduler-run-list triggers/scheduler-stop
|
||||
BUILD = commands subcommands triggers
|
||||
PLUGIN_NAME = scheduler-k3s
|
||||
|
||||
|
||||
@@ -149,16 +149,18 @@ func applyClusterIssuers(ctx context.Context) error {
|
||||
clusterIssuerValues := ClusterIssuerValues{
|
||||
ClusterIssuers: map[string]ClusterIssuer{
|
||||
"letsencrypt-stag": {
|
||||
Email: letsencryptEmailStag,
|
||||
Enabled: letsencryptEmailStag != "",
|
||||
Name: "letsencrypt-stag",
|
||||
Server: "https://acme-staging-v02.api.letsencrypt.org/directory",
|
||||
Email: letsencryptEmailStag,
|
||||
Enabled: letsencryptEmailStag != "",
|
||||
IngressClass: getGlobalIngressClass(),
|
||||
Name: "letsencrypt-stag",
|
||||
Server: "https://acme-staging-v02.api.letsencrypt.org/directory",
|
||||
},
|
||||
"letsencrypt-prod": {
|
||||
Email: letsencryptEmailProd,
|
||||
Enabled: letsencryptEmailProd != "",
|
||||
Name: "letsencrypt-prod",
|
||||
Server: "https://acme-v02.api.letsencrypt.org/directory",
|
||||
Email: letsencryptEmailProd,
|
||||
Enabled: letsencryptEmailProd != "",
|
||||
IngressClass: getGlobalIngressClass(),
|
||||
Name: "letsencrypt-prod",
|
||||
Server: "https://acme-v02.api.letsencrypt.org/directory",
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -333,10 +335,8 @@ func extractStartCommand(input StartCommandInput) string {
|
||||
}
|
||||
|
||||
resp, err := common.CallPlugnTrigger(common.PlugnTriggerInput{
|
||||
Trigger: "config-get",
|
||||
Args: []string{input.AppName, "DOKKU_START_CMD"},
|
||||
CaptureOutput: true,
|
||||
StreamStdio: false,
|
||||
Trigger: "config-get",
|
||||
Args: []string{input.AppName, "DOKKU_START_CMD"},
|
||||
})
|
||||
if err == nil && resp.ExitCode == 0 && len(resp.Stdout) > 0 {
|
||||
command = strings.TrimSpace(resp.Stdout)
|
||||
@@ -344,10 +344,8 @@ func extractStartCommand(input StartCommandInput) string {
|
||||
|
||||
if input.ImageSourceType == "dockerfile" {
|
||||
resp, err := common.CallPlugnTrigger(common.PlugnTriggerInput{
|
||||
Trigger: "config-get",
|
||||
Args: []string{input.AppName, "DOKKU_DOCKERFILE_START_CMD"},
|
||||
CaptureOutput: true,
|
||||
StreamStdio: false,
|
||||
Trigger: "config-get",
|
||||
Args: []string{input.AppName, "DOKKU_DOCKERFILE_START_CMD"},
|
||||
})
|
||||
if err == nil && resp.ExitCode == 0 && len(resp.Stdout) > 0 {
|
||||
command = strings.TrimSpace(resp.Stdout)
|
||||
@@ -496,7 +494,7 @@ func getComputedImagePullSecrets(appName string) string {
|
||||
}
|
||||
|
||||
func getGlobalIngressClass() string {
|
||||
return common.PropertyGetDefault("scheduler-k3s", "global", "ingress-class", DefaultIngressClass)
|
||||
return common.PropertyGetDefault("scheduler-k3s", "--global", "ingress-class", DefaultIngressClass)
|
||||
}
|
||||
|
||||
func getIngressAnnotations(appName string, processType string) (map[string]string, error) {
|
||||
@@ -826,55 +824,86 @@ func getProcessHealtchecks(healthchecks []appjson.Healthcheck, primaryPort int32
|
||||
|
||||
func getProcessResources(appName string, processType string) (ProcessResourcesMap, error) {
|
||||
processResources := ProcessResourcesMap{
|
||||
Limits: ProcessResources{
|
||||
CPU: "1000m",
|
||||
Memory: "512Mi",
|
||||
},
|
||||
Limits: ProcessResources{},
|
||||
Requests: ProcessResources{
|
||||
CPU: "1000m",
|
||||
Memory: "512Mi",
|
||||
CPU: "100m",
|
||||
Memory: "128Mi",
|
||||
},
|
||||
}
|
||||
cpuLimit, err := common.PlugnTriggerOutputAsString("resource-get-property", []string{appName, processType, "limit", "cpu"}...)
|
||||
if err != nil && cpuLimit != "" && cpuLimit != "0" {
|
||||
_, err := resource.ParseQuantity(cpuLimit)
|
||||
|
||||
emptyValues := map[string]bool{
|
||||
"": true,
|
||||
"0": true,
|
||||
}
|
||||
|
||||
result, err := common.CallPlugnTrigger(common.PlugnTriggerInput{
|
||||
Trigger: "resource-get-property",
|
||||
Args: []string{appName, processType, "limit", "cpu"},
|
||||
})
|
||||
if err == nil && !emptyValues[result.StdoutContents()] {
|
||||
quantity, err := resource.ParseQuantity(result.StdoutContents())
|
||||
if err != nil {
|
||||
return ProcessResourcesMap{}, fmt.Errorf("Error parsing cpu limit: %w", err)
|
||||
}
|
||||
processResources.Limits.CPU = cpuLimit
|
||||
if quantity.MilliValue() != 0 {
|
||||
processResources.Limits.CPU = quantity.String()
|
||||
} else {
|
||||
processResources.Limits.CPU = ""
|
||||
}
|
||||
}
|
||||
nvidiaGpuLimit, err := common.PlugnTriggerOutputAsString("resource-get-property", []string{appName, processType, "limit", "nvidia-gpu"}...)
|
||||
if err != nil && nvidiaGpuLimit != "" && nvidiaGpuLimit != "0" {
|
||||
if err == nil && nvidiaGpuLimit != "" && nvidiaGpuLimit != "0" {
|
||||
_, err := resource.ParseQuantity(nvidiaGpuLimit)
|
||||
if err != nil {
|
||||
return ProcessResourcesMap{}, fmt.Errorf("Error parsing nvidia-gpu limit: %w", err)
|
||||
}
|
||||
processResources.Limits.NvidiaGPU = nvidiaGpuLimit
|
||||
}
|
||||
memoryLimit, err := common.PlugnTriggerOutputAsString("resource-get-property", []string{appName, processType, "limit", "memory"}...)
|
||||
if err != nil && memoryLimit != "" && memoryLimit != "0" {
|
||||
_, err := resource.ParseQuantity(memoryLimit)
|
||||
result, err = common.CallPlugnTrigger(common.PlugnTriggerInput{
|
||||
Trigger: "resource-get-property",
|
||||
Args: []string{appName, processType, "limit", "memory"},
|
||||
})
|
||||
if err == nil && !emptyValues[result.StdoutContents()] {
|
||||
quantity, err := parseMemoryQuantity(result.StdoutContents())
|
||||
if err != nil {
|
||||
return ProcessResourcesMap{}, fmt.Errorf("Error parsing memory limit: %w", err)
|
||||
}
|
||||
processResources.Limits.Memory = memoryLimit
|
||||
if quantity != "0Mi" {
|
||||
processResources.Limits.Memory = quantity
|
||||
} else {
|
||||
processResources.Limits.Memory = ""
|
||||
}
|
||||
}
|
||||
|
||||
cpuRequest, err := common.PlugnTriggerOutputAsString("resource-get-property", []string{appName, processType, "reserve", "cpu"}...)
|
||||
if err != nil && cpuRequest != "" && cpuRequest != "0" {
|
||||
_, err := resource.ParseQuantity(cpuRequest)
|
||||
result, err = common.CallPlugnTrigger(common.PlugnTriggerInput{
|
||||
Trigger: "resource-get-property",
|
||||
Args: []string{appName, processType, "reserve", "cpu"},
|
||||
})
|
||||
if err == nil && !emptyValues[result.StdoutContents()] {
|
||||
quantity, err := resource.ParseQuantity(result.StdoutContents())
|
||||
if err != nil {
|
||||
return ProcessResourcesMap{}, fmt.Errorf("Error parsing cpu request: %w", err)
|
||||
}
|
||||
processResources.Requests.CPU = cpuRequest
|
||||
if quantity.MilliValue() != 0 {
|
||||
processResources.Requests.CPU = quantity.String()
|
||||
} else {
|
||||
processResources.Requests.CPU = ""
|
||||
}
|
||||
}
|
||||
memoryRequest, err := common.PlugnTriggerOutputAsString("resource-get-property", []string{appName, processType, "reserve", "memory"}...)
|
||||
if err != nil && memoryRequest != "" && memoryRequest != "0" {
|
||||
_, err := resource.ParseQuantity(memoryRequest)
|
||||
result, err = common.CallPlugnTrigger(common.PlugnTriggerInput{
|
||||
Trigger: "resource-get-property",
|
||||
Args: []string{appName, processType, "reserve", "memory"},
|
||||
})
|
||||
if err == nil && !emptyValues[result.StdoutContents()] {
|
||||
quantity, err := parseMemoryQuantity(result.StdoutContents())
|
||||
if err != nil {
|
||||
return ProcessResourcesMap{}, fmt.Errorf("Error parsing memory request: %w", err)
|
||||
}
|
||||
processResources.Requests.Memory = memoryRequest
|
||||
if quantity != "0Mi" {
|
||||
processResources.Requests.Memory = quantity
|
||||
} else {
|
||||
processResources.Requests.Memory = ""
|
||||
}
|
||||
}
|
||||
|
||||
return processResources, nil
|
||||
@@ -1113,22 +1142,38 @@ func installHelm(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// isKubernetesAvailable returns an error if kubernetes api is not available
|
||||
func isKubernetesAvailable() error {
|
||||
client, err := NewKubernetesClient()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating kubernetes client: %w", err)
|
||||
}
|
||||
|
||||
if err := client.Ping(); err != nil {
|
||||
return fmt.Errorf("Error pinging kubernetes: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// isK3sInstalled returns an error if k3s is not installed
|
||||
func isK3sInstalled() error {
|
||||
if !common.FileExists("/usr/local/bin/k3s") {
|
||||
return fmt.Errorf("k3s binary is not available")
|
||||
}
|
||||
|
||||
if !common.FileExists(RegistryConfigPath) {
|
||||
return fmt.Errorf("k3s registry config is not available")
|
||||
}
|
||||
|
||||
if !common.FileExists(KubeConfigPath) {
|
||||
if !common.FileExists(getKubeconfigPath()) {
|
||||
return fmt.Errorf("k3s kubeconfig is not available")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// isK3sKubernetes returns true if the current kubernetes cluster is configured to be k3s
|
||||
func isK3sKubernetes() bool {
|
||||
return getKubeconfigPath() == KubeConfigPath
|
||||
}
|
||||
|
||||
func isPodReady(ctx context.Context, clientset KubernetesClient, podName, namespace string) wait.ConditionWithContextFunc {
|
||||
return func(ctx context.Context) (bool, error) {
|
||||
fmt.Printf(".")
|
||||
@@ -1188,6 +1233,19 @@ func kubernetesNodeToNode(node v1.Node) Node {
|
||||
}
|
||||
}
|
||||
|
||||
// parseMemoryQuantity parses a string into a valid memory quantity
|
||||
func parseMemoryQuantity(input string) (string, error) {
|
||||
if _, err := strconv.ParseInt(input, 10, 64); err == nil {
|
||||
input = fmt.Sprintf("%sMi", input)
|
||||
}
|
||||
quantity, err := resource.ParseQuantity(input)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return quantity.String(), nil
|
||||
}
|
||||
|
||||
func uninstallHelperCommands(ctx context.Context) error {
|
||||
errs, _ := errgroup.WithContext(ctx)
|
||||
errs.Go(func() error {
|
||||
|
||||
@@ -13,22 +13,20 @@ require (
|
||||
github.com/go-openapi/jsonpointer v0.19.6
|
||||
github.com/go-resty/resty/v2 v2.11.0
|
||||
github.com/gofrs/flock v0.8.1
|
||||
github.com/hashicorp/go-multierror v1.1.1
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
|
||||
github.com/rancher/wharfie v0.6.5
|
||||
github.com/ryanuber/columnize v2.1.2+incompatible
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/traefik/traefik/v2 v2.10.7
|
||||
golang.org/x/sync v0.6.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
helm.sh/helm/v3 v3.13.3
|
||||
helm.sh/helm/v3 v3.14.2
|
||||
k8s.io/api v0.29.0
|
||||
k8s.io/apimachinery v0.29.0
|
||||
k8s.io/client-go v0.29.0
|
||||
k8s.io/kubectl v0.28.4
|
||||
k8s.io/kubectl v0.29.0
|
||||
k8s.io/kubernetes v1.29.1
|
||||
k8s.io/utils v0.0.0-20240102154912-e7106e64919e
|
||||
mvdan.cc/sh/v3 v3.7.0
|
||||
mvdan.cc/sh/v3 v3.8.0
|
||||
)
|
||||
|
||||
require (
|
||||
@@ -61,7 +59,7 @@ require (
|
||||
github.com/docker/go-metrics v0.0.1 // indirect
|
||||
github.com/docker/go-units v0.5.0 // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
|
||||
github.com/evanphx/json-patch v5.6.0+incompatible // indirect
|
||||
github.com/evanphx/json-patch v5.7.0+incompatible // indirect
|
||||
github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/go-acme/lego/v4 v4.14.0 // indirect
|
||||
@@ -78,7 +76,6 @@ require (
|
||||
github.com/google/btree v1.0.1 // indirect
|
||||
github.com/google/gnostic-models v0.6.8 // indirect
|
||||
github.com/google/go-cmp v0.6.0 // indirect
|
||||
github.com/google/go-containerregistry v0.14.0 // indirect
|
||||
github.com/google/gofuzz v1.2.0 // indirect
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
||||
github.com/google/uuid v1.3.1 // indirect
|
||||
@@ -87,6 +84,7 @@ require (
|
||||
github.com/gosuri/uitable v0.0.4 // indirect
|
||||
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/huandu/xstrings v1.4.0 // indirect
|
||||
github.com/imdario/mergo v0.3.13 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
@@ -108,7 +106,6 @@ require (
|
||||
github.com/melbahja/goph v1.4.0 // indirect
|
||||
github.com/miekg/dns v1.1.55 // indirect
|
||||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
|
||||
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||
github.com/moby/locker v1.0.1 // indirect
|
||||
@@ -138,7 +135,7 @@ require (
|
||||
github.com/shopspring/decimal v1.3.1 // indirect
|
||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||
github.com/spf13/cast v1.5.0 // indirect
|
||||
github.com/spf13/cobra v1.7.0 // indirect
|
||||
github.com/spf13/cobra v1.8.0 // indirect
|
||||
github.com/traefik/paerser v0.2.0 // indirect
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||
@@ -149,26 +146,25 @@ require (
|
||||
go.opentelemetry.io/otel/metric v1.20.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.20.0 // indirect
|
||||
go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
golang.org/x/crypto v0.19.0 // indirect
|
||||
golang.org/x/mod v0.14.0 // indirect
|
||||
golang.org/x/net v0.19.0 // indirect
|
||||
golang.org/x/net v0.20.0 // indirect
|
||||
golang.org/x/oauth2 v0.12.0 // indirect
|
||||
golang.org/x/sys v0.17.0 // indirect
|
||||
golang.org/x/term v0.17.0 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
golang.org/x/time v0.3.0 // indirect
|
||||
golang.org/x/tools v0.16.1 // indirect
|
||||
golang.org/x/tools v0.17.0 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230911183012-2d3300fd4832 // indirect
|
||||
google.golang.org/grpc v1.59.0 // indirect
|
||||
google.golang.org/protobuf v1.31.0 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
k8s.io/apiextensions-apiserver v0.28.4 // indirect
|
||||
k8s.io/apiserver v0.28.4 // indirect
|
||||
k8s.io/apiextensions-apiserver v0.29.0 // indirect
|
||||
k8s.io/apiserver v0.29.0 // indirect
|
||||
k8s.io/cli-runtime v0.29.0 // indirect
|
||||
k8s.io/component-base v0.28.4 // indirect
|
||||
k8s.io/component-base v0.29.0 // indirect
|
||||
k8s.io/klog/v2 v2.110.1 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 // indirect
|
||||
oras.land/oras-go v1.2.4 // indirect
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user