Skip to content

Commit

Permalink
Add ddev delete command to kill projects and images, fixes #1465, fixes
Browse files Browse the repository at this point in the history
#1562, fixes #1464 (#1743)

* Add a delete command to delete projects, fixes #1562
* Add ddev delete images
  • Loading branch information
rfay committed Jul 30, 2019
1 parent 2ad94a0 commit 0fa6264
Show file tree
Hide file tree
Showing 3 changed files with 198 additions and 26 deletions.
92 changes: 92 additions & 0 deletions cmd/ddev/cmd/delete-images.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package cmd

import (
"github.com/drud/ddev/pkg/dockerutil"
"github.com/drud/ddev/pkg/util"
"github.com/drud/ddev/pkg/version"
docker "github.com/fsouza/go-dockerclient"
"github.com/spf13/cobra"
"os"
"strings"
)

// DeleteImagesCmd implements the ddev delete images command
var DeleteImagesCmd = &cobra.Command{
Use: "images",
Short: "Delete docker images not currently in use",
Example: `ddev delete images`,
Args: cobra.NoArgs,
Run: func(cmd *cobra.Command, args []string) {
// This is were stuff goes
if !util.Confirm("Deleting unused ddev images. \nThis is a non-destructive operation, \nbut it may require that the images be downloaded again when you need them. \nOK to continue?") {
os.Exit(1)
}
util.Success("Powering off ddev to avoid conflicts")
powerOff()

client := dockerutil.GetDockerClient()

images, err := client.ListImages(docker.ListImagesOptions{
All: true,
})
if err != nil {
util.Failed("Failed to list images: %v", err)
}
webimg := version.GetWebImage()
dbimg101 := version.GetDBImage("10.1")
dbimg102 := version.GetDBImage("10.2")
dbaimage := version.GetDBAImage()
routerimage := version.RouterImage + ":" + version.RouterTag
sshimage := version.SSHAuthImage + ":" + version.SSHAuthTag

// Too much code inside this loop, but complicated by multiple db images
// and discrete names of images
for _, image := range images {
for _, tag := range image.RepoTags {
// If a webimage, but doesn't match our webimage, delete it
if strings.HasPrefix(tag, version.WebImg) && !strings.HasPrefix(tag, webimg) {
if err = removeImage(client, tag); err != nil {
util.Failed("Failed to remove %s: %v", tag, err)
}
}
// If a dbimage, but doesn't match our dbimages, delete it
if strings.HasPrefix(tag, version.DBImg) && !strings.HasPrefix(tag, dbimg101) && !strings.HasPrefix(tag, dbimg102) {
if err = removeImage(client, tag); err != nil {
util.Failed("Failed to remove %s: %v", tag, err)
}
}
// If a dbaimage, but doesn't match our dbaimage, delete it
if strings.HasPrefix(tag, version.DBAImg) && !strings.HasPrefix(tag, dbaimage) {
if err = removeImage(client, tag); err != nil {
util.Failed("Failed to remove %s: %v", tag, err)
}
}
// If a routerImage, but doesn't match our routerimage, delete it
if strings.HasPrefix(tag, version.RouterImage) && !strings.HasPrefix(tag, routerimage) {
if err = removeImage(client, tag); err != nil {
util.Failed("Failed to remove %s: %v", tag, err)
}
}
// If a sshAgentImage, but doesn't match our sshAgentImage, delete it
if strings.HasPrefix(tag, version.SSHAuthImage) && !strings.HasPrefix(tag, sshimage) {
if err = removeImage(client, tag); err != nil {
util.Failed("Failed to remove %s: %v", tag, err)
}
}
}
}
},
}

func init() {
DeleteCmd.AddCommand(DeleteImagesCmd)
}

func removeImage(client *docker.Client, tag string) error {
util.Warning("Removing container: %s", tag)
err := client.RemoveImage(tag)
if err != nil {
util.Failed("Failed to remove %s: %v", tag, err)
}
return nil
}
76 changes: 76 additions & 0 deletions cmd/ddev/cmd/delete.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package cmd

import (
"fmt"
"github.com/drud/ddev/pkg/ddevapp"
"github.com/drud/ddev/pkg/util"
"github.com/spf13/cobra"
)

// noConfirm: If true, --yes, we won't stop and prompt before each deletion
var noConfirm bool

// if deleteAll is true, we'll delete all projects
var deleteAll bool

// DeleteCmd provides the delete command
var DeleteCmd = &cobra.Command{
Use: "delete [projectname ...]",
Short: "Remove all project information (including database) for an existing project",
Long: `Removes all ddev project information (including database) for an existing project, but does not touch the project codebase or the codebase's .ddev folder.'.`,
Example: `ddev delete
ddev delete proj1 proj2 proj3
ddev delete --omit-snapshot proj1
ddev delete --omit-snapshot --yes proj1 proj2
ddev delete --all`,
Run: func(cmd *cobra.Command, args []string) {
if noConfirm && deleteAll {
util.Failed("Sorry, it's not possible to use flags --all and --yes together")
}
projects, err := getRequestedProjects(args, deleteAll)
if err != nil {
util.Failed("Failed to get project(s): %v", err)
}

// Iterate through the list of projects built above, removing each one.
for _, project := range projects {
if !noConfirm {
prompt := "OK to delete this project and its database?\n %s in %s\nThe code and its .ddev directory will not be touched.\n"
if !omitSnapshot {
prompt = prompt + "A database snapshot will be made before the database is deleted.\n"
}
if !util.Confirm(fmt.Sprintf(prompt+"OK to delete %s?", project.Name, project.AppRoot, project.Name)) {
continue
}
}
// Explanation of what's going on (including where the project is)
// Stop it.
// Delete database
// Delete any other associated volumes

// We do the snapshot UNLESS omit-snapshot is set; the project may have to be
// started to do the snapshot.
if project.SiteStatus() != ddevapp.SiteRunning && !omitSnapshot {
util.Warning("project must be started to do the snapshot")
err = project.Start()
if err != nil {
util.Failed("Failed to start project %s: %v", project.Name, err)
}
}
if err := project.Stop(true, !omitSnapshot); err != nil {
util.Failed("Failed to remove project %s: \n%v", project.GetName(), err)
}

util.Success("Project %s has been deleted.", project.GetName())
}
},
}

func init() {
DeleteCmd.Flags().Bool("clean-containers", true, "Clean up all ddev docker containers which are not required by this version of ddev")
DeleteCmd.Flags().BoolVarP(&omitSnapshot, "omit-snapshot", "O", false, "Omit/skip database snapshot")
DeleteCmd.Flags().BoolVarP(&noConfirm, "yes", "y", false, "Yes - skip confirmation prompt")
DeleteCmd.Flags().BoolVarP(&deleteAll, "all", "a", false, "Delete all projects")

RootCmd.AddCommand(DeleteCmd)
}
56 changes: 30 additions & 26 deletions cmd/ddev/cmd/poweroff.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,35 +14,39 @@ var PoweroffCommand = &cobra.Command{
Example: `ddev poweroff`,
Args: cobra.NoArgs,
Run: func(cmd *cobra.Command, args []string) {
projects, err := ddevapp.GetProjects(true)
if err != nil {
util.Failed("Failed to get project(s): %v", err)
}

// Iterate through the list of projects built above, removing each one.
for _, project := range projects {
if project.SiteStatus() == ddevapp.SiteStopped {
util.Warning("Project %s is not currently running. Try 'ddev start'.", project.GetName())
}

// We do the snapshot if either --snapshot or --remove-data UNLESS omit-snapshot is set
doSnapshot := (createSnapshot || removeData) && !omitSnapshot
if err := project.Stop(removeData, doSnapshot); err != nil {
util.Failed("Failed to remove project %s: \n%v", project.GetName(), err)
}
if unlist {
project.RemoveGlobalProjectInfo()
}

util.Success("Project %s has been stopped.", project.GetName())
}

if err := ddevapp.RemoveSSHAgentContainer(); err != nil {
util.Error("Failed to remove ddev-ssh-agent: %v", err)
}
powerOff()
},
}

func init() {
RootCmd.AddCommand(PoweroffCommand)
}

func powerOff() {
projects, err := ddevapp.GetProjects(true)
if err != nil {
util.Failed("Failed to get project(s): %v", err)
}

// Iterate through the list of projects built above, removing each one.
for _, project := range projects {
if project.SiteStatus() == ddevapp.SiteStopped {
util.Warning("Project %s is not currently running. Try 'ddev start'.", project.GetName())
}

// We do the snapshot if either --snapshot or --remove-data UNLESS omit-snapshot is set
doSnapshot := (createSnapshot || removeData) && !omitSnapshot
if err := project.Stop(removeData, doSnapshot); err != nil {
util.Failed("Failed to remove project %s: \n%v", project.GetName(), err)
}
if unlist {
project.RemoveGlobalProjectInfo()
}

util.Success("Project %s has been stopped.", project.GetName())
}

if err := ddevapp.RemoveSSHAgentContainer(); err != nil {
util.Error("Failed to remove ddev-ssh-agent: %v", err)
}
}

0 comments on commit 0fa6264

Please sign in to comment.