add podman pod inspect
first pass of podman pod inspect Signed-off-by: baude <bbaude@redhat.com> Closes: #1236 Approved by: rhatdan
This commit is contained in:
parent
879453eaf1
commit
06fafe4cd0
|
|
@ -11,6 +11,7 @@ Pods are a group of one or more containers sharing the same network, pid and ipc
|
||||||
`
|
`
|
||||||
podSubCommands = []cli.Command{
|
podSubCommands = []cli.Command{
|
||||||
podCreateCommand,
|
podCreateCommand,
|
||||||
|
podInspectCommand,
|
||||||
podKillCommand,
|
podKillCommand,
|
||||||
podPauseCommand,
|
podPauseCommand,
|
||||||
podPsCommand,
|
podPsCommand,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,65 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"fmt"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"github.com/projectatomic/libpod/cmd/podman/libpodruntime"
|
||||||
|
"github.com/projectatomic/libpod/libpod"
|
||||||
|
"github.com/urfave/cli"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
podInspectFlags = []cli.Flag{
|
||||||
|
LatestPodFlag,
|
||||||
|
}
|
||||||
|
podInspectDescription = "display the configuration for a pod by name or id"
|
||||||
|
podInspectCommand = cli.Command{
|
||||||
|
Name: "inspect",
|
||||||
|
Usage: "displays a pod configuration",
|
||||||
|
Description: podInspectDescription,
|
||||||
|
Flags: podInspectFlags,
|
||||||
|
Action: podInspectCmd,
|
||||||
|
UseShortOptionHandling: true,
|
||||||
|
ArgsUsage: "[POD_NAME_OR_ID]",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func podInspectCmd(c *cli.Context) error {
|
||||||
|
var (
|
||||||
|
pod *libpod.Pod
|
||||||
|
)
|
||||||
|
if err := checkMutuallyExclusiveFlags(c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
args := c.Args()
|
||||||
|
runtime, err := libpodruntime.GetRuntime(c)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "could not get runtime")
|
||||||
|
}
|
||||||
|
defer runtime.Shutdown(false)
|
||||||
|
|
||||||
|
if c.Bool("latest") {
|
||||||
|
pod, err = runtime.GetLatestPod()
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "unable to get latest pod")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pod, err = runtime.LookupPod(args[0])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
podInspectData, err := pod.Inspect()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
b, err := json.MarshalIndent(&podInspectData, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fmt.Println(string(b))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
@ -31,6 +31,7 @@
|
||||||
| [podman-pause(1)](/docs/podman-pause.1.md) | Pause one or more running containers |[](https://asciinema.org/a/141292)|
|
| [podman-pause(1)](/docs/podman-pause.1.md) | Pause one or more running containers |[](https://asciinema.org/a/141292)|
|
||||||
| [podman-pod(1)](/docs/podman-pod.1.md) | Simple management tool for groups of containers, called pods ||
|
| [podman-pod(1)](/docs/podman-pod.1.md) | Simple management tool for groups of containers, called pods ||
|
||||||
| [podman-pod-create(1)](/docs/podman-pod-create.1.md) | Create a new pod ||
|
| [podman-pod-create(1)](/docs/podman-pod-create.1.md) | Create a new pod ||
|
||||||
|
| [podman-pod-inspect(1)](/docs/podman-pod-inspect.1.md) | Inspect a pod ||
|
||||||
| [podman-pod-kill(1)](podman-pod-kill.1.md) | Kill the main process of each container in pod. ||
|
| [podman-pod-kill(1)](podman-pod-kill.1.md) | Kill the main process of each container in pod. ||
|
||||||
| [podman-pod-ps(1)](/docs/podman-pod-ps.1.md) | List the pods on the system ||
|
| [podman-pod-ps(1)](/docs/podman-pod-ps.1.md) | List the pods on the system ||
|
||||||
| [podman-pod-pause(1)](podman-pod-pause.1.md) | Pause one or more pods. ||
|
| [podman-pod-pause(1)](podman-pod-pause.1.md) | Pause one or more pods. ||
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
% podman-pod-inspect "1"
|
||||||
|
|
||||||
|
## NAME
|
||||||
|
podman\-pod\-inspect - Displays information describing a pod
|
||||||
|
|
||||||
|
## SYNOPSIS
|
||||||
|
**podman pod inspect** [*options*] *pod* ...
|
||||||
|
|
||||||
|
## DESCRIPTION
|
||||||
|
Displays configuration and state information about a given pod. It also displays information about containers
|
||||||
|
that belong to the pod.
|
||||||
|
|
||||||
|
## OPTIONS
|
||||||
|
**--latest, -l**
|
||||||
|
|
||||||
|
Instead of providing the pod name or ID, use the last created pod. If you use methods other than Podman
|
||||||
|
to run pods such as CRI-O, the last started pod could be from either of those methods.
|
||||||
|
|
||||||
|
|
||||||
|
## EXAMPLE
|
||||||
|
```
|
||||||
|
# podman pod inspect foobar
|
||||||
|
{
|
||||||
|
"Config": {
|
||||||
|
"id": "3513ca70583dd7ef2bac83331350f6b6c47d7b4e526c908e49d89ebf720e4693",
|
||||||
|
"name": "foobar",
|
||||||
|
"labels": {},
|
||||||
|
"cgroupParent": "/libpod_parent",
|
||||||
|
"UsePodCgroup": true,
|
||||||
|
"created": "2018-08-08T11:15:18.823115347-05:00"
|
||||||
|
},
|
||||||
|
"State": {
|
||||||
|
"CgroupPath": ""
|
||||||
|
},
|
||||||
|
"Containers": [
|
||||||
|
{
|
||||||
|
"id": "d53f8bf1e9730281264aac6e6586e327429f62c704abea4b6afb5d8a2b2c9f2c",
|
||||||
|
"state": "configured"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## SEE ALSO
|
||||||
|
podman-pod(1), podman-pod-ps(1)
|
||||||
|
|
||||||
|
## HISTORY
|
||||||
|
August 2018, Originally compiled by Brent Baude <bbaude@redhat.com>
|
||||||
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"github.com/docker/docker/pkg/stringid"
|
"github.com/docker/docker/pkg/stringid"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
"github.com/ulule/deepcopier"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Pod represents a group of containers that are managed together.
|
// Pod represents a group of containers that are managed together.
|
||||||
|
|
@ -59,6 +60,20 @@ type podState struct {
|
||||||
CgroupPath string
|
CgroupPath string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PodInspect represents the data we want to display for
|
||||||
|
// podman pod inspect
|
||||||
|
type PodInspect struct {
|
||||||
|
Config *PodConfig
|
||||||
|
State *podState
|
||||||
|
Containers []PodContainerInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
// PodContainerInfo keeps information on a container in a pod
|
||||||
|
type PodContainerInfo struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
State string `json:"state"`
|
||||||
|
}
|
||||||
|
|
||||||
// ID retrieves the pod's ID
|
// ID retrieves the pod's ID
|
||||||
func (p *Pod) ID() string {
|
func (p *Pod) ID() string {
|
||||||
return p.config.ID
|
return p.config.ID
|
||||||
|
|
@ -696,3 +711,38 @@ func (p *Pod) Status() (map[string]ContainerStatus, error) {
|
||||||
// TODO add pod batching
|
// TODO add pod batching
|
||||||
// Lock pod to avoid lock contention
|
// Lock pod to avoid lock contention
|
||||||
// Store and lock all containers (no RemoveContainer in batch guarantees cache will not become stale)
|
// Store and lock all containers (no RemoveContainer in batch guarantees cache will not become stale)
|
||||||
|
|
||||||
|
// Inspect returns a PodInspect struct to describe the pod
|
||||||
|
func (p *Pod) Inspect() (*PodInspect, error) {
|
||||||
|
var (
|
||||||
|
podContainers []PodContainerInfo
|
||||||
|
)
|
||||||
|
|
||||||
|
containers, err := p.AllContainers()
|
||||||
|
if err != nil {
|
||||||
|
return &PodInspect{}, err
|
||||||
|
}
|
||||||
|
for _, c := range containers {
|
||||||
|
containerStatus := "unknown"
|
||||||
|
// Ignoring possible errors here because we dont want this to be
|
||||||
|
// catastrophic in nature
|
||||||
|
containerState, err := c.State()
|
||||||
|
if err == nil {
|
||||||
|
containerStatus = containerState.String()
|
||||||
|
}
|
||||||
|
pc := PodContainerInfo{
|
||||||
|
ID: c.ID(),
|
||||||
|
State: containerStatus,
|
||||||
|
}
|
||||||
|
podContainers = append(podContainers, pc)
|
||||||
|
}
|
||||||
|
|
||||||
|
config := new(PodConfig)
|
||||||
|
deepcopier.Copy(p.config).To(config)
|
||||||
|
inspectData := PodInspect{
|
||||||
|
Config: config,
|
||||||
|
State: p.state,
|
||||||
|
Containers: podContainers,
|
||||||
|
}
|
||||||
|
return &inspectData, nil
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ import (
|
||||||
. "github.com/onsi/ginkgo"
|
. "github.com/onsi/ginkgo"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
"github.com/onsi/gomega/gexec"
|
"github.com/onsi/gomega/gexec"
|
||||||
|
"github.com/projectatomic/libpod/libpod"
|
||||||
"github.com/projectatomic/libpod/pkg/inspect"
|
"github.com/projectatomic/libpod/pkg/inspect"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -339,6 +340,14 @@ func (s *PodmanSession) InspectContainerToJSON() []inspect.ContainerData {
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// InspectPodToJSON takes the sessions output from a pod inspect and returns json
|
||||||
|
func (s *PodmanSession) InspectPodToJSON() libpod.PodInspect {
|
||||||
|
var i libpod.PodInspect
|
||||||
|
err := json.Unmarshal(s.Out.Contents(), &i)
|
||||||
|
Expect(err).To(BeNil())
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
// InspectImageJSON takes the session output of an inspect
|
// InspectImageJSON takes the session output of an inspect
|
||||||
// image and returns json
|
// image and returns json
|
||||||
func (s *PodmanSession) InspectImageJSON() []inspect.ImageData {
|
func (s *PodmanSession) InspectImageJSON() []inspect.ImageData {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,61 @@
|
||||||
|
package integration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
. "github.com/onsi/ginkgo"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = Describe("Podman pod inspect", func() {
|
||||||
|
var (
|
||||||
|
tempdir string
|
||||||
|
err error
|
||||||
|
podmanTest PodmanTest
|
||||||
|
)
|
||||||
|
|
||||||
|
BeforeEach(func() {
|
||||||
|
tempdir, err = CreateTempDirInTempDir()
|
||||||
|
if err != nil {
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
podmanTest = PodmanCreate(tempdir)
|
||||||
|
podmanTest.RestoreAllArtifacts()
|
||||||
|
})
|
||||||
|
|
||||||
|
AfterEach(func() {
|
||||||
|
podmanTest.CleanupPod()
|
||||||
|
f := CurrentGinkgoTestDescription()
|
||||||
|
timedResult := fmt.Sprintf("Test: %s completed in %f seconds", f.TestText, f.Duration.Seconds())
|
||||||
|
GinkgoWriter.Write([]byte(timedResult))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("podman inspect bogus pod", func() {
|
||||||
|
session := podmanTest.Podman([]string{"pod", "inspect", "foobar"})
|
||||||
|
session.WaitWithDefaultTimeout()
|
||||||
|
Expect(session.ExitCode()).To(Not(Equal(0)))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("podman inspect a pod", func() {
|
||||||
|
session := podmanTest.Podman([]string{"pod", "create"})
|
||||||
|
session.WaitWithDefaultTimeout()
|
||||||
|
Expect(session.ExitCode()).To(Equal(0))
|
||||||
|
podid := session.OutputToString()
|
||||||
|
|
||||||
|
session = podmanTest.RunTopContainerInPod("", podid)
|
||||||
|
session.WaitWithDefaultTimeout()
|
||||||
|
Expect(session.ExitCode()).To(Equal(0))
|
||||||
|
|
||||||
|
session = podmanTest.RunTopContainerInPod("", podid)
|
||||||
|
session.WaitWithDefaultTimeout()
|
||||||
|
Expect(session.ExitCode()).To(Equal(0))
|
||||||
|
|
||||||
|
inspect := podmanTest.Podman([]string{"pod", "inspect", podid})
|
||||||
|
inspect.WaitWithDefaultTimeout()
|
||||||
|
Expect(inspect.ExitCode()).To(Equal(0))
|
||||||
|
Expect(inspect.IsJSONOutputValid()).To(BeTrue())
|
||||||
|
podData := inspect.InspectPodToJSON()
|
||||||
|
Expect(podData.Config.ID).To(Equal(podid))
|
||||||
|
})
|
||||||
|
})
|
||||||
Loading…
Reference in New Issue