diff --git a/plugins/builder/functions.go b/plugins/builder/functions.go index df7d2f863..6d3e06f57 100644 --- a/plugins/builder/functions.go +++ b/plugins/builder/functions.go @@ -3,7 +3,6 @@ package builder import ( "bytes" "errors" - "fmt" "io/ioutil" "os" "path" @@ -12,30 +11,6 @@ import ( "github.com/dokku/dokku/plugins/common" ) -func listImagesByAppLabel(appName string) ([]string, error) { - command := []string{ - common.DockerBin(), - "image", - "ls", - "--quiet", - "--filter", - fmt.Sprintf("label=com.dokku.app-name=%v", appName), - } - - var stderr bytes.Buffer - listCmd := common.NewShellCmd(strings.Join(command, " ")) - listCmd.ShowOutput = false - listCmd.Command.Stderr = &stderr - b, err := listCmd.Output() - - if err != nil { - return []string{}, errors.New(strings.TrimSpace(stderr.String())) - } - - output := strings.Split(strings.TrimSpace(string(b[:])), "\n") - return output, nil -} - func listImagesByImageRepo(imageRepo string) ([]string, error) { command := []string{ common.DockerBin(), diff --git a/plugins/builder/src/triggers/triggers.go b/plugins/builder/src/triggers/triggers.go index 2205d6cce..9fd5ce538 100644 --- a/plugins/builder/src/triggers/triggers.go +++ b/plugins/builder/src/triggers/triggers.go @@ -50,6 +50,10 @@ func main() { case "post-delete": appName := flag.Arg(0) err = builder.TriggerPostDelete(appName) + case "post-release-builder": + builderType := flag.Arg(0) + appName := flag.Arg(1) + err = builder.TriggerPostReleaseBuilder(builderType, appName) case "report": appName := flag.Arg(0) err = builder.ReportSingleApp(appName, "", "") diff --git a/plugins/builder/triggers.go b/plugins/builder/triggers.go index 2b4cc240b..4465fa503 100644 --- a/plugins/builder/triggers.go +++ b/plugins/builder/triggers.go @@ -133,7 +133,9 @@ func TriggerPostDelete(appName string) error { return err } - imagesByAppLabel, err := listImagesByAppLabel(appName) + imagesByAppLabel, err := common.DockerFilterImages([]string{ + fmt.Sprintf("label=com.dokku.app-name=%s", appName), + }) if err != nil { common.LogWarn(err.Error()) } @@ -149,3 +151,17 @@ func TriggerPostDelete(appName string) error { return nil } + +// TriggerPostReleaseBuilder deletes unused build images +func TriggerPostReleaseBuilder(builderType string, appName string) error { + images, _ := common.DockerFilterImages([]string{ + "label=com.dokku.image-stage=build", + fmt.Sprintf("label=com.dokku.app-name=%s", appName), + }) + + if err := common.RemoveImages(images); err != nil { + common.LogWarn(err.Error()) + } + + return nil +} diff --git a/plugins/common/docker.go b/plugins/common/docker.go index 9393a4a6c..abff46043 100644 --- a/plugins/common/docker.go +++ b/plugins/common/docker.go @@ -300,17 +300,58 @@ func IsImageHerokuishBased(image string, appName string) bool { // ListDanglingImages lists all dangling image ids for a given app func ListDanglingImages(appName string) ([]string, error) { + filters := []string{"dangling=true"} + if appName != "" { + filters = append(filters, []string{fmt.Sprintf("label=com.dokku.app-name=%v", appName)}...) + } + return DockerFilterImages(filters) +} + +// RemoveImages removes images by ID +func RemoveImages(imageIDs []string) error { + if len(imageIDs) == 0 { + return nil + } + command := []string{ DockerBin(), "image", - "ls", - "--quiet", - "--filter", - "dangling=true", + "rm", } - if appName != "" { - command = append(command, []string{"--filter", fmt.Sprintf("label=com.dokku.app-name=%v", appName)}...) + command = append(command, 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())) + } + + return nil +} + +// 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() +} + +// DockerFilterContainers returns a slice of container IDs based on the passed in filters +func DockerFilterContainers(filters []string) ([]string, error) { + command := []string{ + DockerBin(), + "container", + "ls", + "--quiet", + "--all", + } + + for _, filter := range filters { + command = append(command, "--filter", filter) } var stderr bytes.Buffer @@ -327,39 +368,11 @@ func ListDanglingImages(appName string) ([]string, error) { return output, nil } -// RemoveImages removes images by ID -func RemoveImages(imageIDs []string) { - if len(imageIDs) == 0 { - return - } - +// DockerFilterImages returns a slice of image IDs based on the passed in filters +func DockerFilterImages(filters []string) ([]string, error) { command := []string{ DockerBin(), "image", - "rm", - } - - command = append(command, imageIDs...) - - var stderr bytes.Buffer - rmCmd := NewShellCmd(strings.Join(command, " ")) - rmCmd.ShowOutput = false - rmCmd.Command.Stderr = &stderr - rmCmd.Execute() -} - -// 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() -} - -// DockerFilterContainers returns a slice of container IDs based on the passed in filters -func DockerFilterContainers(filters []string) ([]string, error) { - command := []string{ - DockerBin(), - "container", "ls", "--quiet", "--all",