Skip to content

Commit

Permalink
Merge branch 'main' into vcolombo/gh-1089
Browse files Browse the repository at this point in the history
  • Loading branch information
victorcolombo committed Sep 18, 2023
2 parents ee8753b + a924f4a commit 417ab31
Show file tree
Hide file tree
Showing 7 changed files with 155 additions and 6 deletions.
11 changes: 11 additions & 0 deletions cli/cli/commands/clean/clean.go
Expand Up @@ -72,6 +72,16 @@ func run(
return stacktrace.Propagate(err, "Expected a boolean flag with key '%v' but none was found; this is an error in Kurtosis!", shouldCleanAll)
}

if shouldCleanAll {
images, err := kurtosisBackend.PruneUnusedImages(ctx)
if len(images) > 0 {
logrus.Infof("Pruned unused images '%v'", images)
}
if err != nil {
return stacktrace.Propagate(err, "Failed to prune all unused images")
}
}

// Map of cleaning_phase_title -> (successfully_destroyed_object_id, object_destruction_errors, clean_error)
cleaningPhaseFunctions := map[string]func() ([]string, []error, error){
oldEngineCleaningPhaseTitle: func() ([]string, []error, error) {
Expand Down Expand Up @@ -126,6 +136,7 @@ func run(
// Private Helper Functions
//
// ====================================================================================================

func cleanStoppedEngineContainers(ctx context.Context, kurtosisBackend backend_interface.KurtosisBackend) ([]string, []error, error) {

engineFilters := &engine.EngineFilters{
Expand Down
Expand Up @@ -84,6 +84,18 @@ func (backend *DockerKurtosisBackend) FetchImage(ctx context.Context, image stri
return nil
}

func (backend *DockerKurtosisBackend) PruneUnusedImages(ctx context.Context) ([]string, error) {
prunedImages, err := backend.dockerManager.PruneUnusedImages(ctx)
prunedImageNames := []string{}
for _, prunedImage := range prunedImages {
prunedImageNames = append(prunedImageNames, prunedImage.ID)
}
if err != nil {
return prunedImageNames, stacktrace.Propagate(err, "An error occurred pruning image from kurtosis backend")
}
return prunedImageNames, nil
}

func (backend *DockerKurtosisBackend) CreateEngine(
ctx context.Context,
imageOrgAndRepo string,
Expand Down
Expand Up @@ -29,6 +29,7 @@ import (
"io"
"math"
"net"
"regexp"
"strings"
"sync"
"time"
Expand Down Expand Up @@ -131,6 +132,8 @@ const (
coresToMilliCores = 1000
bytesInMegaBytes = 1000000
dontStreamStats = false

kurtosisTagPrefix = "kurtosistech/"
)

type RestartPolicy string
Expand Down Expand Up @@ -254,6 +257,61 @@ func (manager *DockerManager) ListNetworks(ctx context.Context) ([]types.Network
return networks, nil
}

func (manager *DockerManager) PruneUnusedImages(ctx context.Context) ([]types.ImageSummary, error) {
unusedImages, err := manager.ListUnusedImages(ctx)
if err != nil {
return nil, stacktrace.Propagate(err, "Failed to list unused images")
}
logrus.Debugf("List of unused images to be pruned '%v'", unusedImages)
successfulPrunedImages := []types.ImageSummary{}
for _, image := range unusedImages {
imagePruneResponse, err := manager.dockerClient.ImageRemove(ctx, image.ID, types.ImageRemoveOptions{}) //nolint:exhaustruct
if err != nil {
return successfulPrunedImages, stacktrace.Propagate(err, "Failed to remove image '%v'", image.ID)
}
logrus.Debugf("Pruned image '%v' with response '%v'", image, imagePruneResponse)
successfulPrunedImages = append(successfulPrunedImages, image)
}
return successfulPrunedImages, nil
}

func containsSemVer(s string) bool {
// Matches patterns like X.Y.Z
semVerRegex := `\b(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)\b`
matched, _ := regexp.MatchString(semVerRegex, s)
return matched
}

func (manager *DockerManager) ListUnusedImages(ctx context.Context) ([]types.ImageSummary, error) {
images, err := manager.dockerClient.ImageList(ctx, types.ImageListOptions{}) //nolint:exhaustruct
if err != nil {
return nil, stacktrace.Propagate(err, "Failed to list Docker images")
}
containers, err := manager.dockerClient.ContainerList(ctx, types.ContainerListOptions{All: true}) //nolint:exhaustruct
if err != nil {
return nil, stacktrace.Propagate(err, "Failed to list Docker images")
}

usedImages := make(map[string]bool)
for _, cont := range containers {
usedImages[cont.ImageID] = true
}

unusedImages := []types.ImageSummary{}
for _, image := range images {
if _, used := usedImages[image.ID]; used {
logrus.Debugf("Skipping image '%v' since its in use", image.ID)
continue
}
for _, tag := range image.RepoTags {
if strings.Contains(tag, kurtosisTagPrefix) && containsSemVer(tag) {
unusedImages = append(unusedImages, image)
}
}
}
return unusedImages, nil
}

/*
GetNetworksByName
Returns Network list matching the given name (if any).
Expand Down
Expand Up @@ -122,6 +122,11 @@ func (backend *KubernetesKurtosisBackend) FetchImage(ctx context.Context, image
return nil
}

func (backend *KubernetesKurtosisBackend) PruneUnusedImages(ctx context.Context) ([]string, error) {
logrus.Warnf("PruneUnusedImages isn't implemented for Kubernetes yet")
return nil, nil
}

func (backend *KubernetesKurtosisBackend) CreateEngine(
ctx context.Context,
imageOrgAndRepo string,
Expand Down
Expand Up @@ -32,6 +32,14 @@ func (backend *MetricsReportingKurtosisBackend) FetchImage(ctx context.Context,
return nil
}

func (backend *MetricsReportingKurtosisBackend) PruneUnusedImages(ctx context.Context) ([]string, error) {
prunedImages, err := backend.underlying.PruneUnusedImages(ctx)
if err != nil {
return prunedImages, stacktrace.Propagate(err, "An error occurred pruning unused images")
}
return prunedImages, nil
}

func (backend *MetricsReportingKurtosisBackend) CreateEngine(
ctx context.Context,
imageOrgAndRepo string,
Expand Down
Expand Up @@ -24,8 +24,10 @@ import (
// KurtosisBackend abstracts a Kurtosis backend, which will be a container engine (Docker or Kubernetes).
// The heuristic for "do I need a method in KurtosisBackend?" here is "will I make one or more calls to
// the underlying container engine?"
// mockery -r --name=KurtosisBackend --filename=mock_kurtosis_backend.go --structname=MockKurtosisBackend --with-expecter --inpackage
type KurtosisBackend interface {
FetchImage(ctx context.Context, image string) error
PruneUnusedImages(ctx context.Context) ([]string, error)

// Creates an engine with the given parameters
CreateEngine(
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 417ab31

Please sign in to comment.