Merge pull request #46484 from vchiranjeeviak/vchiranjeeviak/container-list-code-refactor

daemon: containers list code refactor
This commit is contained in:
Paweł Gronowski 2023-09-25 11:34:51 +02:00 committed by GitHub
commit 7f6bd671fe
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -39,22 +39,15 @@ var acceptedPsFilterTags = map[string]bool{
// iterationAction represents possible outcomes happening during the container iteration.
type iterationAction int
// containerReducer represents a reducer for a container.
// Returns the object to serialize by the api.
type containerReducer func(context.Context, *container.Snapshot) (*types.Container, error)
const (
// includeContainer is the action to include a container in the reducer.
// includeContainer is the action to include a container.
includeContainer iterationAction = iota
// excludeContainer is the action to exclude a container in the reducer.
// excludeContainer is the action to exclude a container.
excludeContainer
// stopIteration is the action to stop iterating over the list of containers.
stopIteration
)
// errStopIteration makes the iterator to stop without returning an error.
var errStopIteration = errors.New("container list iteration stopped")
// List returns an array of all containers registered in the daemon.
func (daemon *Daemon) List() []*container.Container {
return daemon.containers.List()
@ -106,7 +99,59 @@ func (r byCreatedDescending) Less(i, j int) bool {
// Containers returns the list of containers to show given the user's filtering.
func (daemon *Daemon) Containers(ctx context.Context, config *types.ContainerListOptions) ([]*types.Container, error) {
return daemon.reduceContainers(ctx, config, daemon.refreshImage)
if err := config.Filters.Validate(acceptedPsFilterTags); err != nil {
return nil, err
}
var (
view = daemon.containersReplica.Snapshot()
containers = []*types.Container{}
)
filter, err := daemon.foldFilter(ctx, view, config)
if err != nil {
return nil, err
}
// fastpath to only look at a subset of containers if specific name
// or ID matches were provided by the user--otherwise we potentially
// end up querying many more containers than intended
containerList, err := daemon.filterByNameIDMatches(view, filter)
if err != nil {
return nil, err
}
for i := range containerList {
currentContainer := &containerList[i]
switch includeContainerInList(currentContainer, filter) {
case excludeContainer:
continue
case stopIteration:
return containers, nil
}
// transform internal container struct into api structs
newC, err := daemon.refreshImage(ctx, currentContainer)
if err != nil {
return nil, err
}
// release lock because size calculation is slow
if filter.Size {
sizeRw, sizeRootFs, err := daemon.imageService.GetContainerLayerSize(ctx, newC.ID)
if err != nil {
return nil, err
}
newC.SizeRw = sizeRw
newC.SizeRootFs = sizeRootFs
}
if newC != nil {
containers = append(containers, newC)
filter.idx++
}
}
return containers, nil
}
func (daemon *Daemon) filterByNameIDMatches(view *container.View, filter *listContext) ([]container.Snapshot, error) {
@ -178,75 +223,6 @@ func (daemon *Daemon) filterByNameIDMatches(view *container.View, filter *listCo
return cntrs, nil
}
// reduceContainers parses the user's filtering options and generates the list of containers to return based on a reducer.
func (daemon *Daemon) reduceContainers(ctx context.Context, config *types.ContainerListOptions, reducer containerReducer) ([]*types.Container, error) {
if err := config.Filters.Validate(acceptedPsFilterTags); err != nil {
return nil, err
}
var (
view = daemon.containersReplica.Snapshot()
containers = []*types.Container{}
)
filter, err := daemon.foldFilter(ctx, view, config)
if err != nil {
return nil, err
}
// fastpath to only look at a subset of containers if specific name
// or ID matches were provided by the user--otherwise we potentially
// end up querying many more containers than intended
containerList, err := daemon.filterByNameIDMatches(view, filter)
if err != nil {
return nil, err
}
for i := range containerList {
t, err := daemon.reducePsContainer(ctx, &containerList[i], filter, reducer)
if err != nil {
if err != errStopIteration {
return nil, err
}
break
}
if t != nil {
containers = append(containers, t)
filter.idx++
}
}
return containers, nil
}
// reducePsContainer is the basic representation for a container as expected by the ps command.
func (daemon *Daemon) reducePsContainer(ctx context.Context, container *container.Snapshot, filter *listContext, reducer containerReducer) (*types.Container, error) {
// filter containers to return
switch includeContainerInList(container, filter) {
case excludeContainer:
return nil, nil
case stopIteration:
return nil, errStopIteration
}
// transform internal container struct into api structs
newC, err := reducer(ctx, container)
if err != nil {
return nil, err
}
// release lock because size calculation is slow
if filter.Size {
sizeRw, sizeRootFs, err := daemon.imageService.GetContainerLayerSize(ctx, newC.ID)
if err != nil {
return nil, err
}
newC.SizeRw = sizeRw
newC.SizeRootFs = sizeRootFs
}
return newC, nil
}
// foldFilter generates the container filter based on the user's filtering options.
func (daemon *Daemon) foldFilter(ctx context.Context, view *container.View, config *types.ContainerListOptions) (*listContext, error) {
psFilters := config.Filters