|
@@ -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
|