mirror of
https://github.com/podman-container-tools/podman.git
synced 2026-10-18 03:47:33 +00:00
Merge pull request #8920 from Luap99/ps-network-filter
podman ps/pod ps add network filter and .Networks format placeholder
This commit is contained in:
commit
bc0fa658f7
15 changed files with 222 additions and 94 deletions
|
|
@ -982,9 +982,10 @@ func AutocompletePsFilters(cmd *cobra.Command, args []string, toComplete string)
|
|||
return []string{define.HealthCheckHealthy,
|
||||
define.HealthCheckUnhealthy}, cobra.ShellCompDirectiveNoFileComp
|
||||
},
|
||||
"label=": nil,
|
||||
"exited=": nil,
|
||||
"until=": nil,
|
||||
"network=": func(s string) ([]string, cobra.ShellCompDirective) { return getNetworks(cmd, s) },
|
||||
"label=": nil,
|
||||
"exited=": nil,
|
||||
"until=": nil,
|
||||
}
|
||||
return completeKeyValues(toComplete, kv)
|
||||
}
|
||||
|
|
@ -1004,7 +1005,8 @@ func AutocompletePodPsFilters(cmd *cobra.Command, args []string, toComplete stri
|
|||
"ctr-status=": func(_ string) ([]string, cobra.ShellCompDirective) {
|
||||
return containerStatuses, cobra.ShellCompDirectiveNoFileComp
|
||||
},
|
||||
"label=": nil,
|
||||
"network=": func(s string) ([]string, cobra.ShellCompDirective) { return getNetworks(cmd, s) },
|
||||
"label=": nil,
|
||||
}
|
||||
return completeKeyValues(toComplete, kv)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -392,6 +392,11 @@ func (l psReporter) Names() string {
|
|||
return l.ListContainer.Names[0]
|
||||
}
|
||||
|
||||
// Networks returns the container network names in string format
|
||||
func (l psReporter) Networks() string {
|
||||
return strings.Join(l.ListContainer.Networks, ",")
|
||||
}
|
||||
|
||||
// Ports converts from Portmappings to the string form
|
||||
// required by ps
|
||||
func (l psReporter) Ports() string {
|
||||
|
|
|
|||
|
|
@ -191,6 +191,11 @@ func (l ListPodReporter) Labels() map[string]string {
|
|||
return l.ListPodsReport.Labels
|
||||
}
|
||||
|
||||
// Networks returns the infra container network names in string format
|
||||
func (l ListPodReporter) Networks() string {
|
||||
return strings.Join(l.ListPodsReport.Networks, ",")
|
||||
}
|
||||
|
||||
// NumberOfContainers returns an int representation for
|
||||
// the number of containers belonging to the pod
|
||||
func (l ListPodReporter) NumberOfContainers() int {
|
||||
|
|
|
|||
|
|
@ -72,6 +72,8 @@ Valid placeholders for the Go template are listed below:
|
|||
| .Cgroup | Cgroup path of pod |
|
||||
| .Created | Creation time of pod |
|
||||
| .InfraID | Pod infra container ID |
|
||||
| .Networks | Show all networks connected to the infra container |
|
||||
|
||||
#### **--sort**
|
||||
|
||||
Sort by created, ID, name, status, or number of containers
|
||||
|
|
@ -93,6 +95,7 @@ Valid filters are listed below:
|
|||
| name | [Name] Pod's name (accepts regex) |
|
||||
| label | [Key] or [Key=Value] Label assigned to a container |
|
||||
| status | Pod's status: `stopped`, `running`, `paused`, `exited`, `dead`, `created`, `degraded` |
|
||||
| network | [Network] name or full ID of network |
|
||||
| ctr-names | Container name within the pod (accepts regex) |
|
||||
| ctr-ids | Container ID within the pod (accepts regex) |
|
||||
| ctr-status | Container status within the pod |
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ Valid filters are listed below:
|
|||
| volume | [VolumeName] or [MountpointDestination] Volume mounted in container |
|
||||
| health | [Status] healthy or unhealthy |
|
||||
| pod | [Pod] name or full or partial ID of pod |
|
||||
| network | [Network] name or full ID of network |
|
||||
|
||||
|
||||
#### **--format**=*format*
|
||||
|
|
@ -79,6 +80,7 @@ Valid placeholders for the Go template are listed below:
|
|||
| .Ports | Exposed ports |
|
||||
| .Size | Size of container |
|
||||
| .Names | Name of container |
|
||||
| .Networks | Show all networks connected to the container |
|
||||
| .Labels | All the labels assigned to the container |
|
||||
| .Mounts | Volumes mounted in the container |
|
||||
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ func PodCreate(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
func Pods(w http.ResponseWriter, r *http.Request) {
|
||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
||||
query := struct {
|
||||
Filters map[string][]string `schema:"filters"`
|
||||
|
|
@ -55,7 +56,11 @@ func Pods(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
pods, err := utils.GetPods(w, r)
|
||||
containerEngine := abi.ContainerEngine{Libpod: runtime}
|
||||
podPSOptions := entities.PodPSOptions{
|
||||
Filters: query.Filters,
|
||||
}
|
||||
pods, err := containerEngine.PodPs(r.Context(), podPSOptions)
|
||||
if err != nil {
|
||||
utils.Error(w, "Something went wrong", http.StatusInternalServerError, err)
|
||||
return
|
||||
|
|
|
|||
|
|
@ -1,87 +0,0 @@
|
|||
package utils
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/containers/podman/v2/libpod"
|
||||
"github.com/containers/podman/v2/pkg/domain/entities"
|
||||
dfilters "github.com/containers/podman/v2/pkg/domain/filters"
|
||||
"github.com/gorilla/schema"
|
||||
)
|
||||
|
||||
func GetPods(w http.ResponseWriter, r *http.Request) ([]*entities.ListPodsReport, error) {
|
||||
var (
|
||||
pods []*libpod.Pod
|
||||
)
|
||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
||||
|
||||
query := struct {
|
||||
All bool
|
||||
Filters map[string][]string `schema:"filters"`
|
||||
Digests bool
|
||||
}{}
|
||||
|
||||
if err := decoder.Decode(&query, r.URL.Query()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, found := r.URL.Query()["digests"]; found && query.Digests {
|
||||
UnSupportedParameter("digests")
|
||||
}
|
||||
|
||||
filters := make([]libpod.PodFilter, 0, len(query.Filters))
|
||||
for k, v := range query.Filters {
|
||||
f, err := dfilters.GeneratePodFilterFunc(k, v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
filters = append(filters, f)
|
||||
}
|
||||
pods, err := runtime.Pods(filters...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(pods) == 0 {
|
||||
return []*entities.ListPodsReport{}, nil
|
||||
}
|
||||
|
||||
lps := make([]*entities.ListPodsReport, 0, len(pods))
|
||||
for _, pod := range pods {
|
||||
status, err := pod.GetPodStatus()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ctrs, err := pod.AllContainers()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
infraID, err := pod.InfraContainerID()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
lp := entities.ListPodsReport{
|
||||
Cgroup: pod.CgroupParent(),
|
||||
Created: pod.CreatedTime(),
|
||||
Id: pod.ID(),
|
||||
Name: pod.Name(),
|
||||
Namespace: pod.Namespace(),
|
||||
Status: status,
|
||||
InfraId: infraID,
|
||||
Labels: pod.Labels(),
|
||||
}
|
||||
for _, ctr := range ctrs {
|
||||
state, err := ctr.State()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
lp.Containers = append(lp.Containers, &entities.ListPodContainer{
|
||||
Id: ctr.ID(),
|
||||
Names: ctr.Name(),
|
||||
Status: state.String(),
|
||||
})
|
||||
}
|
||||
lps = append(lps, &lp)
|
||||
}
|
||||
return lps, nil
|
||||
}
|
||||
|
|
@ -43,6 +43,8 @@ type ListContainer struct {
|
|||
// Namespaces the container belongs to. Requires the
|
||||
// namespace boolean to be true
|
||||
Namespaces ListContainerNamespaces
|
||||
// The network names assigned to the container
|
||||
Networks []string
|
||||
// The process id of the container
|
||||
Pid int
|
||||
// If the container is part of Pod, the Pod ID. Requires the pod
|
||||
|
|
|
|||
|
|
@ -28,8 +28,10 @@ type ListPodsReport struct {
|
|||
InfraId string //nolint
|
||||
Name string
|
||||
Namespace string
|
||||
Status string
|
||||
Labels map[string]string
|
||||
// Network names connected to infra container
|
||||
Networks []string
|
||||
Status string
|
||||
Labels map[string]string
|
||||
}
|
||||
|
||||
type ListPodContainer struct {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import (
|
|||
|
||||
"github.com/containers/podman/v2/libpod"
|
||||
"github.com/containers/podman/v2/libpod/define"
|
||||
"github.com/containers/podman/v2/libpod/network"
|
||||
"github.com/containers/podman/v2/pkg/timetype"
|
||||
"github.com/containers/podman/v2/pkg/util"
|
||||
"github.com/pkg/errors"
|
||||
|
|
@ -233,6 +234,24 @@ func GenerateContainerFilterFuncs(filter string, filterValues []string, r *libpo
|
|||
}
|
||||
return false
|
||||
}, nil
|
||||
case "network":
|
||||
return func(c *libpod.Container) bool {
|
||||
networks, _, err := c.Networks()
|
||||
// if err or no networks, quick out
|
||||
if err != nil || len(networks) == 0 {
|
||||
return false
|
||||
}
|
||||
for _, net := range networks {
|
||||
netID := network.GetNetworkID(net)
|
||||
for _, val := range filterValues {
|
||||
// match by network name or id
|
||||
if val == net || val == netID {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}, nil
|
||||
}
|
||||
return nil, errors.Errorf("%s is an invalid filter", filter)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import (
|
|||
|
||||
"github.com/containers/podman/v2/libpod"
|
||||
"github.com/containers/podman/v2/libpod/define"
|
||||
"github.com/containers/podman/v2/libpod/network"
|
||||
"github.com/containers/podman/v2/pkg/util"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
|
@ -134,6 +135,29 @@ func GeneratePodFilterFunc(filter string, filterValues []string) (
|
|||
}
|
||||
return true
|
||||
}, nil
|
||||
case "network":
|
||||
return func(p *libpod.Pod) bool {
|
||||
infra, err := p.InfraContainer()
|
||||
// no infra, quick out
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
networks, _, err := infra.Networks()
|
||||
// if err or no networks, quick out
|
||||
if err != nil || len(networks) == 0 {
|
||||
return false
|
||||
}
|
||||
for _, net := range networks {
|
||||
netID := network.GetNetworkID(net)
|
||||
for _, val := range filterValues {
|
||||
// match by network name or id
|
||||
if val == net || val == netID {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}, nil
|
||||
}
|
||||
return nil, errors.Errorf("%s is an invalid filter", filter)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -333,6 +333,17 @@ func (ic *ContainerEngine) PodPs(ctx context.Context, options entities.PodPSOpti
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
networks := []string{}
|
||||
if len(infraID) > 0 {
|
||||
infra, err := p.InfraContainer()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
networks, _, err = infra.Networks()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
reports = append(reports, &entities.ListPodsReport{
|
||||
Cgroup: p.CgroupParent(),
|
||||
Containers: lpcs,
|
||||
|
|
@ -341,6 +352,7 @@ func (ic *ContainerEngine) PodPs(ctx context.Context, options entities.PodPSOpti
|
|||
InfraId: infraID,
|
||||
Name: p.Name(),
|
||||
Namespace: p.Namespace(),
|
||||
Networks: networks,
|
||||
Status: status,
|
||||
Labels: p.Labels(),
|
||||
})
|
||||
|
|
|
|||
|
|
@ -178,6 +178,11 @@ func ListContainerBatch(rt *libpod.Runtime, ctr *libpod.Container, opts entities
|
|||
return entities.ListContainer{}, err
|
||||
}
|
||||
|
||||
networks, _, err := ctr.Networks()
|
||||
if err != nil {
|
||||
return entities.ListContainer{}, err
|
||||
}
|
||||
|
||||
ps := entities.ListContainer{
|
||||
AutoRemove: ctr.AutoRemove(),
|
||||
Command: conConfig.Command,
|
||||
|
|
@ -192,6 +197,7 @@ func ListContainerBatch(rt *libpod.Runtime, ctr *libpod.Container, opts entities
|
|||
Labels: conConfig.Labels,
|
||||
Mounts: ctr.UserVolumes(),
|
||||
Names: []string{conConfig.Name},
|
||||
Networks: networks,
|
||||
Pid: pid,
|
||||
Pod: conConfig.Pod,
|
||||
Ports: portMappings,
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import (
|
|||
"sort"
|
||||
|
||||
. "github.com/containers/podman/v2/test/utils"
|
||||
"github.com/containers/storage/pkg/stringid"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
. "github.com/onsi/gomega/gexec"
|
||||
|
|
@ -280,6 +281,69 @@ var _ = Describe("Podman ps", func() {
|
|||
Expect(session.OutputToString()).To(Not(ContainSubstring(podid3)))
|
||||
})
|
||||
|
||||
It("podman pod ps filter network", func() {
|
||||
net := stringid.GenerateNonCryptoID()
|
||||
session := podmanTest.Podman([]string{"network", "create", net})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(BeZero())
|
||||
defer podmanTest.removeCNINetwork(net)
|
||||
|
||||
session = podmanTest.Podman([]string{"pod", "create", "--network", net})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(BeZero())
|
||||
podWithNet := session.OutputToString()
|
||||
|
||||
session = podmanTest.Podman([]string{"pod", "create"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(BeZero())
|
||||
podWithoutNet := session.OutputToString()
|
||||
|
||||
session = podmanTest.Podman([]string{"pod", "ps", "--no-trunc", "--filter", "network=" + net})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(BeZero())
|
||||
Expect(session.OutputToString()).To(ContainSubstring(podWithNet))
|
||||
Expect(session.OutputToString()).To(Not(ContainSubstring(podWithoutNet)))
|
||||
})
|
||||
|
||||
It("podman pod ps --format networks", func() {
|
||||
session := podmanTest.Podman([]string{"pod", "create"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(BeZero())
|
||||
|
||||
session = podmanTest.Podman([]string{"pod", "ps", "--format", "{{ .Networks }}"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(BeZero())
|
||||
if isRootless() {
|
||||
// rootless container don't have a network by default
|
||||
Expect(session.OutputToString()).To(Equal(""))
|
||||
} else {
|
||||
// default network name is podman
|
||||
Expect(session.OutputToString()).To(Equal("podman"))
|
||||
}
|
||||
|
||||
net1 := stringid.GenerateNonCryptoID()
|
||||
session = podmanTest.Podman([]string{"network", "create", net1})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(BeZero())
|
||||
defer podmanTest.removeCNINetwork(net1)
|
||||
net2 := stringid.GenerateNonCryptoID()
|
||||
session = podmanTest.Podman([]string{"network", "create", net2})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(BeZero())
|
||||
defer podmanTest.removeCNINetwork(net2)
|
||||
|
||||
session = podmanTest.Podman([]string{"pod", "create", "--network", net1 + "," + net2})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(BeZero())
|
||||
pid := session.OutputToString()
|
||||
|
||||
session = podmanTest.Podman([]string{"pod", "ps", "--format", "{{ .Networks }}", "--filter", "id=" + pid})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(BeZero())
|
||||
// the output is not deterministic so check both possible orders
|
||||
Expect(session.OutputToString()).To(Or(Equal(net1+","+net2), Equal(net2+","+net1)))
|
||||
})
|
||||
|
||||
It("pod no infra should ps", func() {
|
||||
session := podmanTest.Podman([]string{"pod", "create", "--infra=false"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import (
|
|||
"strings"
|
||||
|
||||
. "github.com/containers/podman/v2/test/utils"
|
||||
"github.com/containers/storage/pkg/stringid"
|
||||
"github.com/docker/go-units"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
|
|
@ -724,4 +725,67 @@ var _ = Describe("Podman ps", func() {
|
|||
|
||||
})
|
||||
|
||||
It("podman ps filter network", func() {
|
||||
net := stringid.GenerateNonCryptoID()
|
||||
session := podmanTest.Podman([]string{"network", "create", net})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(BeZero())
|
||||
defer podmanTest.removeCNINetwork(net)
|
||||
|
||||
session = podmanTest.Podman([]string{"create", "--network", net, ALPINE})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(BeZero())
|
||||
ctrWithNet := session.OutputToString()
|
||||
|
||||
session = podmanTest.Podman([]string{"create", ALPINE})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(BeZero())
|
||||
ctrWithoutNet := session.OutputToString()
|
||||
|
||||
session = podmanTest.Podman([]string{"ps", "--all", "--no-trunc", "--filter", "network=" + net})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(BeZero())
|
||||
Expect(session.OutputToString()).To(ContainSubstring(ctrWithNet))
|
||||
Expect(session.OutputToString()).To(Not(ContainSubstring(ctrWithoutNet)))
|
||||
})
|
||||
|
||||
It("podman ps --format networks", func() {
|
||||
session := podmanTest.Podman([]string{"create", ALPINE})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(BeZero())
|
||||
|
||||
session = podmanTest.Podman([]string{"ps", "--all", "--format", "{{ .Networks }}"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(BeZero())
|
||||
if isRootless() {
|
||||
// rootless container don't have a network by default
|
||||
Expect(session.OutputToString()).To(Equal(""))
|
||||
} else {
|
||||
// default network name is podman
|
||||
Expect(session.OutputToString()).To(Equal("podman"))
|
||||
}
|
||||
|
||||
net1 := stringid.GenerateNonCryptoID()
|
||||
session = podmanTest.Podman([]string{"network", "create", net1})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(BeZero())
|
||||
defer podmanTest.removeCNINetwork(net1)
|
||||
net2 := stringid.GenerateNonCryptoID()
|
||||
session = podmanTest.Podman([]string{"network", "create", net2})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(BeZero())
|
||||
defer podmanTest.removeCNINetwork(net2)
|
||||
|
||||
session = podmanTest.Podman([]string{"create", "--network", net1 + "," + net2, ALPINE})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(BeZero())
|
||||
cid := session.OutputToString()
|
||||
|
||||
session = podmanTest.Podman([]string{"ps", "--all", "--format", "{{ .Networks }}", "--filter", "id=" + cid})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(BeZero())
|
||||
// the output is not deterministic so check both possible orders
|
||||
Expect(session.OutputToString()).To(Or(Equal(net1+","+net2), Equal(net2+","+net1)))
|
||||
})
|
||||
|
||||
})
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue