Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions pkg/compose/uninstall.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,16 +64,16 @@ func UninstallApps(ctx context.Context, cfg *Config, appRefs []string, options .
}

if opts.Prune {
// Prune unused images, it should remove app images of stopped apps
// from the docker store, unless they are used by some 3rd party containers/apps
// TODO: don't remove unused images that does not belong to any of the specified apps
// If the same image is used by one of the specified apps and some 3rd party app - how
// to figure out it so we can skip this image removal
cli, errClient := GetDockerClient(cfg.DockerHost)
if errClient != nil {
return errClient
}
_, err = cli.ImagesPrune(ctx, filters.NewArgs(filters.Arg("dangling", "false")))
// Prune only dangling images.
// The dangling images are the ones that are not tagged and not referenced by any container.
// TODO: consider pruning volumes and networks if needed.
// TODO: consider pruning only those images that are related to the uninstalled apps,
// otherwise it prunes all dangling images including those that are not managed by composectl
_, err = cli.ImagesPrune(ctx, filters.NewArgs(filters.Arg("dangling", "true")))
}
return err
}
88 changes: 88 additions & 0 deletions test/integration/update_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -551,3 +551,91 @@ services:
t.Fatalf("there is/are %d failed updates, expected %d\n", failureCount, 0)
}
}

func TestAppPruning(t *testing.T) {
appComposeDef01 := `
services:
srvs-01:
image: registry:5000/factory/runner-image:v0.1
command: sh -c "while true; do sleep 60; done"
ports:
- 8081:81
busybox-1:
image: ghcr.io/foundriesio/busybox:1.36
command: sh -c "while true; do sleep 60; done"
busybox-2:
image: ghcr.io/foundriesio/busybox:1.36-multiarch
command: sh -c "while true; do sleep 120; done"
`
appComposeDef02 := `
services:
srvs-01:
image: registry:5000/factory/runner-image:v0.1
command: sh -c "while true; do sleep 60; done"
ports:
- 8082:82
busybox-1:
image: ghcr.io/foundriesio/busybox:1.36
command: sh -c "while true; do sleep 70; done"
busybox-2:
image: ghcr.io/foundriesio/busybox:1.36-multiarch
command: sh -c "while true; do sleep 110; done"
`
var appURIs []string
for _, appDef := range []string{appComposeDef01, appComposeDef02} {
app := f.NewApp(t, appDef)
app.Publish(t)
appURIs = append(appURIs, app.PublishedUri)
}

cfg := f.NewTestConfig(t)
ctx := context.Background()

updateRunner, err := update.NewUpdate(cfg, "target-10")
f.Check(t, err)

// do update
f.Check(t, updateRunner.Init(ctx, appURIs))
f.Check(t, updateRunner.Fetch(ctx))
f.Check(t, updateRunner.Install(ctx))
f.Check(t, updateRunner.Start(ctx))
f.Check(t, updateRunner.Complete(ctx, update.CompleteWithPruning()))

// check that both apps are running
appsStatus, err := compose.CheckAppsStatus(ctx, cfg, nil)
f.Check(t, err)
if !appsStatus.AreRunning() {
t.Fatal("apps are expected to be running")
}

// do sync update, remove the second app
updateRunner, err = update.NewUpdate(cfg, "target-10")
f.Check(t, err)
oneAppURI := []string{appURIs[0]}
f.Check(t, updateRunner.Init(ctx, oneAppURI, update.WithInitCheckStatus(false)))
f.Check(t, updateRunner.Fetch(ctx))
// Stop apps before installing the update, which effectively removes the second app
f.Check(t, compose.StopApps(ctx, cfg, appURIs))
f.Check(t, updateRunner.Install(ctx))
// Start only the first app
f.Check(t, updateRunner.Start(ctx))
// Complete with pruning to remove the second app
f.Check(t, updateRunner.Complete(ctx, update.CompleteWithPruning()))

appsStatus, err = compose.CheckAppsStatus(ctx, cfg, nil)
f.Check(t, err)
if !appsStatus.AreRunning() {
t.Fatal("app is expected to be running")
}
if len(appsStatus.Apps) > 1 || len(appsStatus.Apps) == 0 {
t.Fatalf("only one app is expected to be running, found %d", len(appsStatus.Apps))
}
if appsStatus.Apps[0].Ref().String() != appURIs[0] {
t.Fatalf("expected app URI %s, found %s", appURIs[0], appsStatus.Apps[0].Ref().String())
}

// stop, uninstall, and remove all apps
f.Check(t, compose.StopApps(ctx, cfg, oneAppURI))
f.Check(t, compose.UninstallApps(ctx, cfg, oneAppURI, compose.WithImagePruning()))
f.Check(t, compose.RemoveApps(ctx, cfg, oneAppURI))
}