2020-10-10 19:39:40 -04:00
|
|
|
package common
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"fmt"
|
|
|
|
|
"os"
|
2024-09-28 22:24:06 -04:00
|
|
|
"strconv"
|
2020-10-10 19:39:40 -04:00
|
|
|
"strings"
|
2021-01-07 00:12:44 -05:00
|
|
|
"time"
|
2020-10-10 19:39:40 -04:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// ContainerIsRunning checks to see if a container is running
|
|
|
|
|
func ContainerIsRunning(containerID string) bool {
|
|
|
|
|
b, err := DockerInspect(containerID, "'{{.State.Running}}'")
|
|
|
|
|
if err != nil {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
return strings.TrimSpace(string(b[:])) == "true"
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-12 20:58:51 -05:00
|
|
|
// ContainerStart runs 'docker container start' against an existing container
|
|
|
|
|
func ContainerStart(containerID string) bool {
|
|
|
|
|
result, err := CallExecCommand(ExecCommandInput{
|
|
|
|
|
Command: DockerBin(),
|
|
|
|
|
Args: []string{"container", "start", containerID},
|
|
|
|
|
StreamStderr: true,
|
|
|
|
|
})
|
|
|
|
|
if err != nil {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
return result.ExitCode == 0
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-26 06:45:24 -05:00
|
|
|
// ContainerRemove runs 'docker container remove' against an existing container
|
|
|
|
|
func ContainerRemove(containerID string) bool {
|
2024-02-12 19:28:23 -05:00
|
|
|
result, err := CallExecCommand(ExecCommandInput{
|
2024-02-12 20:07:43 -05:00
|
|
|
Command: DockerBin(),
|
|
|
|
|
Args: []string{"container", "remove", "-f", containerID},
|
|
|
|
|
StreamStderr: true,
|
2024-02-12 19:28:23 -05:00
|
|
|
})
|
|
|
|
|
if err != nil {
|
2024-01-26 06:45:24 -05:00
|
|
|
return false
|
|
|
|
|
}
|
2024-02-12 19:28:23 -05:00
|
|
|
return result.ExitCode == 0
|
2024-01-26 06:45:24 -05:00
|
|
|
}
|
|
|
|
|
|
2021-01-04 00:30:22 -05:00
|
|
|
// ContainerExists checks to see if a container exists
|
|
|
|
|
func ContainerExists(containerID string) bool {
|
2024-02-12 19:28:23 -05:00
|
|
|
result, err := CallExecCommand(ExecCommandInput{
|
2024-02-12 20:07:43 -05:00
|
|
|
Command: DockerBin(),
|
|
|
|
|
Args: []string{"container", "inspect", containerID},
|
2024-02-12 19:28:23 -05:00
|
|
|
})
|
|
|
|
|
if err != nil {
|
2021-01-04 00:30:22 -05:00
|
|
|
return false
|
|
|
|
|
}
|
2024-02-12 19:28:23 -05:00
|
|
|
return result.ExitCode == 0
|
2021-01-04 00:30:22 -05:00
|
|
|
}
|
|
|
|
|
|
2024-02-12 20:58:51 -05:00
|
|
|
// 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
|
|
|
|
|
}
|
2024-09-28 22:24:06 -04:00
|
|
|
|
|
|
|
|
stdout := result.StdoutContents()
|
|
|
|
|
if stdout != "0" {
|
|
|
|
|
exitCode, err := strconv.Atoi(stdout)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return exitCode == 0
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-12 20:58:51 -05:00
|
|
|
return result.ExitCode == 0
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-07 00:12:44 -05:00
|
|
|
// ContainerWaitTilReady will wait timeout seconds and then check if a container is running
|
|
|
|
|
// returning an error if it is not running at the end of the timeout
|
|
|
|
|
func ContainerWaitTilReady(containerID string, timeout time.Duration) error {
|
|
|
|
|
time.Sleep(timeout)
|
|
|
|
|
|
|
|
|
|
if !ContainerIsRunning(containerID) {
|
|
|
|
|
return fmt.Errorf("Container %s is not running", containerID)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-10 19:39:40 -04:00
|
|
|
// CopyFromImage copies a file from named image to destination
|
|
|
|
|
func CopyFromImage(appName string, image string, source string, destination string) error {
|
|
|
|
|
if !VerifyImage(image) {
|
|
|
|
|
return fmt.Errorf("Invalid docker image for copying content")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if !IsAbsPath(source) {
|
2024-01-18 22:38:37 -05:00
|
|
|
workDir := GetWorkingDir(appName, image)
|
2020-10-10 19:39:40 -04:00
|
|
|
if workDir != "" {
|
|
|
|
|
source = fmt.Sprintf("%s/%s", workDir, source)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-22 01:59:22 +08:00
|
|
|
tmpFile, err := os.CreateTemp(os.TempDir(), fmt.Sprintf("dokku-%s-%s", MustGetEnv("DOKKU_PID"), "CopyFromImage"))
|
2020-10-10 19:39:40 -04:00
|
|
|
if err != nil {
|
|
|
|
|
return fmt.Errorf("Cannot create temporary file: %v", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
defer tmpFile.Close()
|
|
|
|
|
defer os.Remove(tmpFile.Name())
|
|
|
|
|
|
|
|
|
|
globalRunArgs := MustGetEnv("DOKKU_GLOBAL_RUN_ARGS")
|
|
|
|
|
createLabelArgs := []string{"--label", fmt.Sprintf("com.dokku.app-name=%s", appName), globalRunArgs}
|
|
|
|
|
containerID, err := DockerContainerCreate(image, createLabelArgs)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return fmt.Errorf("Unable to create temporary container: %v", err)
|
|
|
|
|
}
|
2024-02-13 01:09:24 -05:00
|
|
|
defer ContainerRemove(containerID)
|
2020-10-10 19:39:40 -04:00
|
|
|
|
|
|
|
|
// 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
|
2024-02-13 01:09:24 -05:00
|
|
|
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())
|
2020-10-10 19:39:40 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fi, err := os.Stat(tmpFile.Name())
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if fi.Size() == 0 {
|
|
|
|
|
return fmt.Errorf("Unable to copy file %s from image", source)
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-24 22:43:43 -05:00
|
|
|
// workaround when owner is root. seems to only happen when running inside docker
|
2024-02-13 01:09:24 -05:00
|
|
|
CallExecCommand(ExecCommandInput{
|
|
|
|
|
Command: "dos2unix",
|
|
|
|
|
Args: []string{"-l", "-n", tmpFile.Name(), destination},
|
|
|
|
|
}) // nolint: errcheck
|
2020-10-10 19:39:40 -04:00
|
|
|
|
|
|
|
|
// add trailing newline for certain places where file parsing depends on it
|
2024-02-13 01:09:24 -05:00
|
|
|
result, err = CallExecCommand(ExecCommandInput{
|
2024-02-12 20:28:31 -05:00
|
|
|
Command: "tail",
|
|
|
|
|
Args: []string{"-c1", destination},
|
2024-02-12 19:28:23 -05:00
|
|
|
})
|
|
|
|
|
if err != nil || result.ExitCode != 0 {
|
|
|
|
|
return fmt.Errorf("Unable to append trailing newline to copied file: %v", result.Stderr)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if result.Stdout != "" {
|
2020-10-10 19:39:40 -04:00
|
|
|
f, err := os.OpenFile(destination, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
defer f.Close()
|
|
|
|
|
if _, err := f.WriteString("\n"); err != nil {
|
|
|
|
|
return fmt.Errorf("Unable to append trailing newline to copied file: %v", err)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// DockerBin returns a string which contains a path to the current docker binary
|
|
|
|
|
func DockerBin() string {
|
|
|
|
|
dockerBin := os.Getenv("DOCKER_BIN")
|
|
|
|
|
if dockerBin == "" {
|
|
|
|
|
dockerBin = "docker"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return dockerBin
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// DockerCleanup cleans up all exited/dead containers and removes all dangling images
|
|
|
|
|
func DockerCleanup(appName string, forceCleanup bool) error {
|
|
|
|
|
if !forceCleanup {
|
|
|
|
|
skipCleanup := false
|
|
|
|
|
if appName != "" {
|
2022-07-29 22:45:23 -04:00
|
|
|
triggerName := "config-get"
|
|
|
|
|
triggerArgs := []string{appName, "DOKKU_SKIP_CLEANUP"}
|
|
|
|
|
if appName == "--global" {
|
|
|
|
|
triggerName = "config-get-global"
|
|
|
|
|
triggerArgs = []string{"DOKKU_SKIP_CLEANUP"}
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-14 01:18:28 -04:00
|
|
|
results, _ := CallPlugnTrigger(PlugnTriggerInput{
|
|
|
|
|
Trigger: triggerName,
|
|
|
|
|
Args: triggerArgs,
|
|
|
|
|
})
|
|
|
|
|
if results.StdoutContents() == "true" {
|
2020-10-10 19:39:40 -04:00
|
|
|
skipCleanup = true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if skipCleanup || os.Getenv("DOKKU_SKIP_CLEANUP") == "true" {
|
|
|
|
|
LogInfo1("DOKKU_SKIP_CLEANUP set. Skipping dokku cleanup")
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LogInfo1("Cleaning up...")
|
|
|
|
|
if appName == "--global" {
|
|
|
|
|
appName = ""
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// delete all non-running and dead containers
|
|
|
|
|
exitedContainerIDs, _ := listContainers("exited", appName)
|
|
|
|
|
deadContainerIDs, _ := listContainers("dead", appName)
|
|
|
|
|
containerIDs := append(exitedContainerIDs, deadContainerIDs...)
|
|
|
|
|
|
|
|
|
|
if len(containerIDs) > 0 {
|
2022-11-28 02:24:27 -05:00
|
|
|
DockerRemoveContainers(containerIDs)
|
2020-10-10 19:39:40 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// delete dangling images
|
2021-08-03 16:22:57 -04:00
|
|
|
imageIDs, _ := ListDanglingImages(appName)
|
2020-10-10 19:39:40 -04:00
|
|
|
if len(imageIDs) > 0 {
|
|
|
|
|
RemoveImages(imageIDs)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if appName != "" {
|
|
|
|
|
// delete unused images
|
|
|
|
|
pruneUnusedImages(appName)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// DockerContainerCreate creates a new container and returns the container ID
|
|
|
|
|
func DockerContainerCreate(image string, containerCreateArgs []string) (string, error) {
|
2024-02-13 01:09:24 -05:00
|
|
|
args := []string{
|
2020-10-10 19:39:40 -04:00
|
|
|
"container",
|
|
|
|
|
"create",
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-13 01:09:24 -05:00
|
|
|
args = append(args, containerCreateArgs...)
|
|
|
|
|
args = append(args, image)
|
2020-10-10 19:39:40 -04:00
|
|
|
|
2024-02-13 01:09:24 -05:00
|
|
|
result, err := CallExecCommand(ExecCommandInput{
|
|
|
|
|
Command: DockerBin(),
|
|
|
|
|
Args: args,
|
|
|
|
|
})
|
2020-10-10 19:39:40 -04:00
|
|
|
if err != nil {
|
2024-02-13 01:09:24 -05:00
|
|
|
return "", fmt.Errorf("Unable to create container: %w", err)
|
|
|
|
|
}
|
|
|
|
|
if result.ExitCode != 0 {
|
|
|
|
|
return "", fmt.Errorf("Unable to create container: %s", result.StderrContents())
|
2020-10-10 19:39:40 -04:00
|
|
|
}
|
|
|
|
|
|
2024-02-13 01:09:24 -05:00
|
|
|
return result.StdoutContents(), nil
|
2020-10-10 19:39:40 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// DockerInspect runs an inspect command with a given format against a container or image ID
|
|
|
|
|
func DockerInspect(containerOrImageID, format string) (output string, err error) {
|
2024-02-12 19:28:23 -05:00
|
|
|
result, err := CallExecCommand(ExecCommandInput{
|
2024-02-12 20:28:31 -05:00
|
|
|
Command: DockerBin(),
|
|
|
|
|
Args: []string{"inspect", "--format", format, containerOrImageID},
|
2024-02-12 19:28:23 -05:00
|
|
|
})
|
2020-10-10 19:39:40 -04:00
|
|
|
if err != nil {
|
|
|
|
|
return "", err
|
|
|
|
|
}
|
2024-02-12 19:28:23 -05:00
|
|
|
|
|
|
|
|
output = result.StdoutContents()
|
2020-10-10 19:39:40 -04:00
|
|
|
if strings.HasPrefix(output, "'") && strings.HasSuffix(output, "'") {
|
|
|
|
|
output = strings.TrimSuffix(strings.TrimPrefix(output, "'"), "'")
|
|
|
|
|
}
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-18 22:38:37 -05:00
|
|
|
// GetWorkingDir returns the working directory for a given image
|
|
|
|
|
func GetWorkingDir(appName string, image string) string {
|
|
|
|
|
if IsImageCnbBased(image) {
|
|
|
|
|
return "/workspace"
|
|
|
|
|
} else if IsImageHerokuishBased(image, appName) {
|
|
|
|
|
return "/app"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
workDir, _ := DockerInspect(image, "{{.Config.WorkingDir}}")
|
|
|
|
|
return workDir
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-26 06:45:24 -05:00
|
|
|
func IsComposeInstalled() bool {
|
|
|
|
|
result, err := CallExecCommand(ExecCommandInput{
|
2024-02-12 20:28:31 -05:00
|
|
|
Command: DockerBin(),
|
|
|
|
|
Args: []string{"info", "--format", "{{range .ClientInfo.Plugins}}{{if eq .Name \"compose\"}}true{{end}}{{end}}')"},
|
2024-01-26 06:45:24 -05:00
|
|
|
})
|
|
|
|
|
return err == nil && result.ExitCode == 0
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-11 06:48:38 -05:00
|
|
|
// IsImageCnbBased returns true if app image is based on cnb
|
|
|
|
|
func IsImageCnbBased(image string) bool {
|
|
|
|
|
if len(image) == 0 {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
output, err := DockerInspect(image, "{{index .Config.Labels \"io.buildpacks.stack.id\" }}")
|
|
|
|
|
if err != nil {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
return output != ""
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-10 19:39:40 -04:00
|
|
|
// IsImageHerokuishBased returns true if app image is based on herokuish
|
|
|
|
|
func IsImageHerokuishBased(image string, appName string) bool {
|
2021-02-11 06:49:19 -05:00
|
|
|
if len(image) == 0 {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if IsImageCnbBased(image) {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dokkuAppUser := ""
|
|
|
|
|
if len(appName) != 0 {
|
2024-03-14 01:18:28 -04:00
|
|
|
results, err := CallPlugnTrigger(PlugnTriggerInput{
|
|
|
|
|
Trigger: "config-get",
|
|
|
|
|
Args: []string{appName, "DOKKU_APP_USER"},
|
|
|
|
|
})
|
2021-02-11 06:49:19 -05:00
|
|
|
if err == nil {
|
2024-03-14 01:18:28 -04:00
|
|
|
dokkuAppUser = results.StdoutContents()
|
2021-02-11 06:49:19 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(dokkuAppUser) == 0 {
|
|
|
|
|
dokkuAppUser = "herokuishuser"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
output, err := DockerInspect(image, fmt.Sprintf("{{range .Config.Env}}{{if eq . \"USER=%s\" }}{{println .}}{{end}}{{end}}", dokkuAppUser))
|
2020-10-10 19:39:40 -04:00
|
|
|
if err != nil {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
return output != ""
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-03 16:24:59 -04:00
|
|
|
// ListDanglingImages lists all dangling image ids for a given app
|
2021-08-03 16:22:57 -04:00
|
|
|
func ListDanglingImages(appName string) ([]string, error) {
|
2023-10-14 22:36:31 -04:00
|
|
|
filters := []string{"dangling=true"}
|
2021-08-03 16:22:57 -04:00
|
|
|
if appName != "" {
|
2023-10-14 22:36:31 -04:00
|
|
|
filters = append(filters, []string{fmt.Sprintf("label=com.dokku.app-name=%v", appName)}...)
|
2021-08-03 16:22:57 -04:00
|
|
|
}
|
2023-10-14 22:36:31 -04:00
|
|
|
return DockerFilterImages(filters)
|
2021-08-03 16:22:57 -04:00
|
|
|
}
|
|
|
|
|
|
2020-10-10 19:39:40 -04:00
|
|
|
// RemoveImages removes images by ID
|
2023-10-14 22:36:31 -04:00
|
|
|
func RemoveImages(imageIDs []string) error {
|
2023-07-01 03:22:01 -04:00
|
|
|
if len(imageIDs) == 0 {
|
2023-10-14 22:36:31 -04:00
|
|
|
return nil
|
2023-07-01 03:22:01 -04:00
|
|
|
}
|
|
|
|
|
|
2024-02-13 01:09:24 -05:00
|
|
|
args := []string{
|
2020-10-10 19:39:40 -04:00
|
|
|
"image",
|
|
|
|
|
"rm",
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-13 01:09:24 -05:00
|
|
|
args = append(args, imageIDs...)
|
2020-10-10 19:39:40 -04:00
|
|
|
|
2024-02-13 01:09:24 -05:00
|
|
|
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())
|
2023-10-14 22:36:31 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil
|
2020-10-10 19:39:40 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// VerifyImage returns true if docker image exists in local repo
|
|
|
|
|
func VerifyImage(image string) bool {
|
2024-02-13 01:09:24 -05:00
|
|
|
result, err := CallExecCommand(ExecCommandInput{
|
|
|
|
|
Command: DockerBin(),
|
|
|
|
|
Args: []string{"image", "inspect", image},
|
|
|
|
|
})
|
|
|
|
|
return err == nil && result.ExitCode == 0
|
2020-10-10 19:39:40 -04:00
|
|
|
}
|
|
|
|
|
|
2022-11-28 02:24:27 -05:00
|
|
|
// DockerFilterContainers returns a slice of container IDs based on the passed in filters
|
|
|
|
|
func DockerFilterContainers(filters []string) ([]string, error) {
|
2024-02-13 01:09:24 -05:00
|
|
|
args := []string{
|
2020-10-10 19:39:40 -04:00
|
|
|
"container",
|
2023-07-01 03:29:00 -04:00
|
|
|
"ls",
|
2020-10-10 19:39:40 -04:00
|
|
|
"--quiet",
|
|
|
|
|
"--all",
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-28 02:24:27 -05:00
|
|
|
for _, filter := range filters {
|
2024-02-13 01:09:24 -05:00
|
|
|
args = append(args, "--filter", filter)
|
2020-10-10 19:39:40 -04:00
|
|
|
}
|
|
|
|
|
|
2024-02-13 01:09:24 -05:00
|
|
|
result, err := CallExecCommand(ExecCommandInput{
|
|
|
|
|
Command: DockerBin(),
|
|
|
|
|
Args: args,
|
|
|
|
|
})
|
2020-10-10 19:39:40 -04:00
|
|
|
if err != nil {
|
2024-02-13 01:09:24 -05:00
|
|
|
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())
|
2020-10-10 19:39:40 -04:00
|
|
|
}
|
|
|
|
|
|
2024-02-13 01:09:24 -05:00
|
|
|
output := strings.Split(result.StdoutContents(), "\n")
|
2020-10-10 19:39:40 -04:00
|
|
|
return output, nil
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-14 22:36:31 -04:00
|
|
|
// DockerFilterImages returns a slice of image IDs based on the passed in filters
|
|
|
|
|
func DockerFilterImages(filters []string) ([]string, error) {
|
2024-02-13 01:09:24 -05:00
|
|
|
args := []string{
|
2023-10-14 22:36:31 -04:00
|
|
|
"image",
|
|
|
|
|
"ls",
|
|
|
|
|
"--quiet",
|
|
|
|
|
"--all",
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, filter := range filters {
|
2024-02-13 01:09:24 -05:00
|
|
|
args = append(args, "--filter", filter)
|
2023-10-14 22:36:31 -04:00
|
|
|
}
|
|
|
|
|
|
2024-02-13 01:09:24 -05:00
|
|
|
result, err := CallExecCommand(ExecCommandInput{
|
|
|
|
|
Command: DockerBin(),
|
|
|
|
|
Args: args,
|
|
|
|
|
})
|
2023-10-14 22:36:31 -04:00
|
|
|
if err != nil {
|
2024-02-13 01:09:24 -05:00
|
|
|
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())
|
2023-10-14 22:36:31 -04:00
|
|
|
}
|
|
|
|
|
|
2024-02-13 01:09:24 -05:00
|
|
|
output := strings.Split(result.StdoutContents(), "\n")
|
2023-10-14 22:36:31 -04:00
|
|
|
return output, nil
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-28 02:24:27 -05:00
|
|
|
func listContainers(status string, appName string) ([]string, error) {
|
|
|
|
|
filters := []string{
|
|
|
|
|
fmt.Sprintf("status=%v", status),
|
|
|
|
|
fmt.Sprintf("label=%v", os.Getenv("DOKKU_CONTAINER_LABEL")),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if appName != "" {
|
|
|
|
|
filters = append(filters, fmt.Sprintf("label=com.dokku.app-name=%v", appName))
|
|
|
|
|
}
|
|
|
|
|
return DockerFilterContainers(filters)
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-10 19:39:40 -04:00
|
|
|
func pruneUnusedImages(appName string) {
|
2024-02-13 01:09:24 -05:00
|
|
|
args := []string{
|
2020-10-10 19:39:40 -04:00
|
|
|
"image",
|
|
|
|
|
"prune",
|
|
|
|
|
"--all",
|
|
|
|
|
"--force",
|
|
|
|
|
"--filter",
|
|
|
|
|
fmt.Sprintf("label=com.dokku.app-name=%v", appName),
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-13 01:09:24 -05:00
|
|
|
CallExecCommand(ExecCommandInput{
|
|
|
|
|
Command: DockerBin(),
|
|
|
|
|
Args: args,
|
|
|
|
|
}) // nolint: errcheck
|
2020-10-10 19:39:40 -04:00
|
|
|
}
|
|
|
|
|
|
2022-11-28 02:24:27 -05:00
|
|
|
// DockerRemoveContainers will call `docker container rm` on the specified containers
|
|
|
|
|
func DockerRemoveContainers(containerIDs []string) {
|
2024-02-13 01:09:24 -05:00
|
|
|
args := []string{
|
2020-10-10 19:39:40 -04:00
|
|
|
"container",
|
|
|
|
|
"rm",
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-13 01:09:24 -05:00
|
|
|
args = append(args, containerIDs...)
|
2020-10-10 19:39:40 -04:00
|
|
|
|
2024-02-13 01:09:24 -05:00
|
|
|
CallExecCommand(ExecCommandInput{
|
|
|
|
|
Command: DockerBin(),
|
|
|
|
|
Args: args,
|
|
|
|
|
}) // nolint: errcheck
|
2020-10-10 19:39:40 -04:00
|
|
|
}
|