-
Notifications
You must be signed in to change notification settings - Fork 5.8k
feat(hooks): capture and surface lifecycle hook output #14091
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
33a7e99
d947e14
9a27758
9eeb69a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -107,6 +107,10 @@ func (s *composeService) down(ctx context.Context, projectName string, options a | |
| } | ||
| } | ||
|
|
||
| if err := s.removePreStartHookContainers(ctx, projectName, options.Services); err != nil { | ||
| return err | ||
| } | ||
|
|
||
| ops := s.ensureNetworksDown(ctx, project) | ||
|
|
||
| if options.Images != "" { | ||
|
|
@@ -385,3 +389,43 @@ func (s *composeService) getProjectWithResources(ctx context.Context, containers | |
|
|
||
| return project, nil | ||
| } | ||
|
|
||
| // removePreStartHookContainers force-removes any pre_start hook containers that | ||
| // were retained after a failed hook run. These containers are created without a | ||
| // ConfigHashLabel, so getContainers and the normal teardown path never see them; | ||
| // without this step they would survive compose down. When services is non-empty | ||
| // the cleanup is scoped to those services; otherwise the whole project is swept. | ||
| // Individual removal failures are logged at warn level and do not abort teardown. | ||
| func (s *composeService) removePreStartHookContainers(ctx context.Context, projectName string, services []string) error { | ||
| var filters []client.Filters | ||
| if len(services) == 0 { | ||
| f := projectFilter(projectName) | ||
| f.Add("label", hookFilter(preStartHookType)) | ||
| filters = []client.Filters{f} | ||
| } else { | ||
| for _, service := range services { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Follow-up: scoping by |
||
| f := projectFilter(projectName) | ||
| f.Add("label", serviceFilter(service)) | ||
| f.Add("label", hookFilter(preStartHookType)) | ||
| filters = append(filters, f) | ||
| } | ||
| } | ||
| for _, f := range filters { | ||
| res, err := s.apiClient().ContainerList(ctx, client.ContainerListOptions{ | ||
| All: true, | ||
| Filters: f, | ||
| }) | ||
| if err != nil { | ||
| return err | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Follow-up: this |
||
| } | ||
| for _, ctr := range res.Items { | ||
| if _, removeErr := s.apiClient().ContainerRemove(ctx, ctr.ID, client.ContainerRemoveOptions{ | ||
| Force: true, | ||
| RemoveVolumes: true, | ||
| }); removeErr != nil { | ||
| logrus.Warnf("failed to remove retained pre_start hook container %s: %v", ctr.ID, removeErr) | ||
| } | ||
| } | ||
| } | ||
| return nil | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Follow-up / to verify: the retained hook containers reference the service containers' volumes via
VolumesFrom, and they are removed after the service containers — so the service'srm -vmay fail to reclaim anonymous volumes still referenced by a retained hook (they'd only go away with the hook's ownRemoveVolumesafterwards). Sweeping hooks before the service containers would be the safer order.