|
@@ -38,6 +38,8 @@ var acceptedPsFilterTags = map[string]bool{
|
|
"volume": true,
|
|
"volume": true,
|
|
"network": true,
|
|
"network": true,
|
|
"is-task": true,
|
|
"is-task": true,
|
|
|
|
+ "publish": true,
|
|
|
|
+ "expose": true,
|
|
}
|
|
}
|
|
|
|
|
|
// iterationAction represents possible outcomes happening during the container iteration.
|
|
// iterationAction represents possible outcomes happening during the container iteration.
|
|
@@ -89,6 +91,12 @@ type listContext struct {
|
|
taskFilter bool
|
|
taskFilter bool
|
|
// isTask tells us if the we should filter container that are a task (true) or not (false)
|
|
// isTask tells us if the we should filter container that are a task (true) or not (false)
|
|
isTask bool
|
|
isTask bool
|
|
|
|
+
|
|
|
|
+ // publish is a list of published ports to filter with
|
|
|
|
+ publish map[nat.Port]bool
|
|
|
|
+ // expose is a list of exposed ports to filter with
|
|
|
|
+ expose map[nat.Port]bool
|
|
|
|
+
|
|
// ContainerListOptions is the filters set by the user
|
|
// ContainerListOptions is the filters set by the user
|
|
*types.ContainerListOptions
|
|
*types.ContainerListOptions
|
|
}
|
|
}
|
|
@@ -311,6 +319,54 @@ func (daemon *Daemon) foldFilter(config *types.ContainerListOptions) (*listConte
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ publishFilter := map[nat.Port]bool{}
|
|
|
|
+ err = psFilters.WalkValues("publish", func(value string) error {
|
|
|
|
+ if strings.Contains(value, ":") {
|
|
|
|
+ return fmt.Errorf("filter for 'publish' should not contain ':': %v", value)
|
|
|
|
+ }
|
|
|
|
+ //support two formats, original format <portnum>/[<proto>] or <startport-endport>/[<proto>]
|
|
|
|
+ proto, port := nat.SplitProtoPort(value)
|
|
|
|
+ start, end, err := nat.ParsePortRange(port)
|
|
|
|
+ if err != nil {
|
|
|
|
+ return fmt.Errorf("error while looking up for publish %v: %s", value, err)
|
|
|
|
+ }
|
|
|
|
+ for i := start; i <= end; i++ {
|
|
|
|
+ p, err := nat.NewPort(proto, strconv.FormatUint(i, 10))
|
|
|
|
+ if err != nil {
|
|
|
|
+ return fmt.Errorf("error while looking up for publish %v: %s", value, err)
|
|
|
|
+ }
|
|
|
|
+ publishFilter[p] = true
|
|
|
|
+ }
|
|
|
|
+ return nil
|
|
|
|
+ })
|
|
|
|
+ if err != nil {
|
|
|
|
+ return nil, err
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ exposeFilter := map[nat.Port]bool{}
|
|
|
|
+ err = psFilters.WalkValues("expose", func(value string) error {
|
|
|
|
+ if strings.Contains(value, ":") {
|
|
|
|
+ return fmt.Errorf("filter for 'expose' should not contain ':': %v", value)
|
|
|
|
+ }
|
|
|
|
+ //support two formats, original format <portnum>/[<proto>] or <startport-endport>/[<proto>]
|
|
|
|
+ proto, port := nat.SplitProtoPort(value)
|
|
|
|
+ start, end, err := nat.ParsePortRange(port)
|
|
|
|
+ if err != nil {
|
|
|
|
+ return fmt.Errorf("error while looking up for 'expose' %v: %s", value, err)
|
|
|
|
+ }
|
|
|
|
+ for i := start; i <= end; i++ {
|
|
|
|
+ p, err := nat.NewPort(proto, strconv.FormatUint(i, 10))
|
|
|
|
+ if err != nil {
|
|
|
|
+ return fmt.Errorf("error while looking up for 'expose' %v: %s", value, err)
|
|
|
|
+ }
|
|
|
|
+ exposeFilter[p] = true
|
|
|
|
+ }
|
|
|
|
+ return nil
|
|
|
|
+ })
|
|
|
|
+ if err != nil {
|
|
|
|
+ return nil, err
|
|
|
|
+ }
|
|
|
|
+
|
|
return &listContext{
|
|
return &listContext{
|
|
filters: psFilters,
|
|
filters: psFilters,
|
|
ancestorFilter: ancestorFilter,
|
|
ancestorFilter: ancestorFilter,
|
|
@@ -320,6 +376,8 @@ func (daemon *Daemon) foldFilter(config *types.ContainerListOptions) (*listConte
|
|
sinceFilter: sinceContFilter,
|
|
sinceFilter: sinceContFilter,
|
|
taskFilter: taskFilter,
|
|
taskFilter: taskFilter,
|
|
isTask: isTask,
|
|
isTask: isTask,
|
|
|
|
+ publish: publishFilter,
|
|
|
|
+ expose: exposeFilter,
|
|
ContainerListOptions: config,
|
|
ContainerListOptions: config,
|
|
names: daemon.nameIndex.GetAll(),
|
|
names: daemon.nameIndex.GetAll(),
|
|
}, nil
|
|
}, nil
|
|
@@ -459,6 +517,32 @@ func includeContainerInList(container *container.Container, ctx *listContext) it
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ if len(ctx.publish) > 0 {
|
|
|
|
+ shouldSkip := true
|
|
|
|
+ for port := range ctx.publish {
|
|
|
|
+ if _, ok := container.HostConfig.PortBindings[port]; ok {
|
|
|
|
+ shouldSkip = false
|
|
|
|
+ break
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if shouldSkip {
|
|
|
|
+ return excludeContainer
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if len(ctx.expose) > 0 {
|
|
|
|
+ shouldSkip := true
|
|
|
|
+ for port := range ctx.expose {
|
|
|
|
+ if _, ok := container.Config.ExposedPorts[port]; ok {
|
|
|
|
+ shouldSkip = false
|
|
|
|
+ break
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if shouldSkip {
|
|
|
|
+ return excludeContainer
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
return includeContainer
|
|
return includeContainer
|
|
}
|
|
}
|
|
|
|
|