diff options
Diffstat (limited to 'cmd/podman/inspect.go')
-rw-r--r-- | cmd/podman/inspect.go | 364 |
1 files changed, 364 insertions, 0 deletions
diff --git a/cmd/podman/inspect.go b/cmd/podman/inspect.go new file mode 100644 index 000000000..7fd039b75 --- /dev/null +++ b/cmd/podman/inspect.go @@ -0,0 +1,364 @@ +package main + +import ( + "encoding/json" + + specs "github.com/opencontainers/runtime-spec/specs-go" + "github.com/pkg/errors" + "github.com/projectatomic/libpod/cmd/podman/formats" + "github.com/projectatomic/libpod/libpod" + "github.com/sirupsen/logrus" + "github.com/urfave/cli" +) + +const ( + inspectTypeContainer = "container" + inspectTypeImage = "image" + inspectAll = "all" +) + +var ( + inspectFlags = []cli.Flag{ + cli.StringFlag{ + Name: "type, t", + Value: inspectAll, + Usage: "Return JSON for specified type, (e.g image, container or task)", + }, + cli.StringFlag{ + Name: "format, f", + Usage: "Change the output format to a Go template", + }, + cli.BoolFlag{ + Name: "size", + Usage: "Display total file size if the type is container", + }, + } + inspectDescription = "This displays the low-level information on containers and images identified by name or ID. By default, this will render all results in a JSON array. If the container and image have the same name, this will return container JSON for unspecified type." + inspectCommand = cli.Command{ + Name: "inspect", + Usage: "Displays the configuration of a container or image", + Description: inspectDescription, + Flags: inspectFlags, + Action: inspectCmd, + ArgsUsage: "CONTAINER-OR-IMAGE", + } +) + +func inspectCmd(c *cli.Context) error { + args := c.Args() + if len(args) == 0 { + return errors.Errorf("container or image name must be specified: podman inspect [options [...]] name") + } + if len(args) > 1 { + return errors.Errorf("too many arguments specified") + } + if err := validateFlags(c, inspectFlags); err != nil { + return err + } + + runtime, err := getRuntime(c) + if err != nil { + return errors.Wrapf(err, "error creating libpod runtime") + } + defer runtime.Shutdown(false) + + if c.String("type") != inspectTypeContainer && c.String("type") != inspectTypeImage && c.String("type") != inspectAll { + return errors.Errorf("the only recognized types are %q, %q, and %q", inspectTypeContainer, inspectTypeImage, inspectAll) + } + + name := args[0] + + outputFormat := c.String("format") + var data interface{} + switch c.String("type") { + case inspectTypeContainer: + ctr, err := runtime.LookupContainer(name) + if err != nil { + return errors.Wrapf(err, "error looking up container %q", name) + } + libpodInspectData, err := ctr.Inspect(c.Bool("size")) + if err != nil { + return errors.Wrapf(err, "error getting libpod container inspect data %q", ctr.ID) + } + data, err = getCtrInspectInfo(ctr, libpodInspectData) + if err != nil { + return errors.Wrapf(err, "error parsing container data %q", ctr.ID()) + } + case inspectTypeImage: + image, err := runtime.GetImage(name) + if err != nil { + return errors.Wrapf(err, "error getting image %q", name) + } + data, err = runtime.GetImageInspectInfo(*image) + if err != nil { + return errors.Wrapf(err, "error parsing image data %q", image.ID) + } + case inspectAll: + ctr, err := runtime.LookupContainer(name) + if err != nil { + image, err := runtime.GetImage(name) + if err != nil { + return errors.Wrapf(err, "error getting image %q", name) + } + data, err = runtime.GetImageInspectInfo(*image) + if err != nil { + return errors.Wrapf(err, "error parsing image data %q", image.ID) + } + } else { + libpodInspectData, err := ctr.Inspect(c.Bool("size")) + if err != nil { + return errors.Wrapf(err, "error getting libpod container inspect data %q", ctr.ID) + } + data, err = getCtrInspectInfo(ctr, libpodInspectData) + if err != nil { + return errors.Wrapf(err, "error parsing container data %q", ctr.ID) + } + } + } + + var out formats.Writer + if outputFormat != "" && outputFormat != formats.JSONString { + //template + out = formats.StdoutTemplate{Output: data, Template: outputFormat} + } else { + // default is json output + out = formats.JSONStruct{Output: data} + } + + formats.Writer(out).Out() + return nil +} + +func getCtrInspectInfo(ctr *libpod.Container, ctrInspectData *libpod.ContainerInspectData) (*ContainerData, error) { + config := ctr.Config() + spec := config.Spec + + cpus, mems, period, quota, realtimePeriod, realtimeRuntime, shares := getCPUInfo(spec) + blkioWeight, blkioWeightDevice, blkioReadBps, blkioWriteBps, blkioReadIOPS, blkioeWriteIOPS := getBLKIOInfo(spec) + memKernel, memReservation, memSwap, memSwappiness, memDisableOOMKiller := getMemoryInfo(spec) + pidsLimit := getPidsInfo(spec) + cgroup := getCgroup(spec) + + var createArtifact createConfig + artifact, err := ctr.GetArtifact("create-config") + if err == nil { + if err := json.Unmarshal(artifact, &createArtifact); err != nil { + return nil, err + } + } else { + logrus.Errorf("couldn't get some inspect information, error getting artifact %q: %v", ctr.ID(), err) + } + + data := &ContainerData{ + CtrInspectData: ctrInspectData, + HostConfig: &HostConfig{ + ConsoleSize: spec.Process.ConsoleSize, + OomScoreAdj: spec.Process.OOMScoreAdj, + CPUShares: shares, + BlkioWeight: blkioWeight, + BlkioWeightDevice: blkioWeightDevice, + BlkioDeviceReadBps: blkioReadBps, + BlkioDeviceWriteBps: blkioWriteBps, + BlkioDeviceReadIOps: blkioReadIOPS, + BlkioDeviceWriteIOps: blkioeWriteIOPS, + CPUPeriod: period, + CPUQuota: quota, + CPURealtimePeriod: realtimePeriod, + CPURealtimeRuntime: realtimeRuntime, + CPUSetCPUs: cpus, + CPUSetMems: mems, + Devices: spec.Linux.Devices, + KernelMemory: memKernel, + MemoryReservation: memReservation, + MemorySwap: memSwap, + MemorySwappiness: memSwappiness, + OomKillDisable: memDisableOOMKiller, + PidsLimit: pidsLimit, + Privileged: spec.Process.NoNewPrivileges, + ReadonlyRootfs: spec.Root.Readonly, + Runtime: ctr.RuntimeName(), + NetworkMode: string(createArtifact.NetMode), + IpcMode: string(createArtifact.IpcMode), + Cgroup: cgroup, + UTSMode: string(createArtifact.UtsMode), + UsernsMode: createArtifact.NsUser, + GroupAdd: spec.Process.User.AdditionalGids, + ContainerIDFile: createArtifact.CidFile, + AutoRemove: createArtifact.Rm, + CapAdd: createArtifact.CapAdd, + CapDrop: createArtifact.CapDrop, + DNS: createArtifact.DNSServers, + DNSOptions: createArtifact.DNSOpt, + DNSSearch: createArtifact.DNSSearch, + PidMode: string(createArtifact.PidMode), + CgroupParent: createArtifact.CgroupParent, + ShmSize: createArtifact.Resources.ShmSize, + Memory: createArtifact.Resources.Memory, + Ulimits: createArtifact.Resources.Ulimit, + SecurityOpt: createArtifact.SecurityOpts, + }, + Config: &CtrConfig{ + Hostname: spec.Hostname, + User: spec.Process.User, + Env: spec.Process.Env, + Image: config.RootfsImageName, + WorkingDir: spec.Process.Cwd, + Labels: config.Labels, + Annotations: spec.Annotations, + Tty: spec.Process.Terminal, + OpenStdin: config.Stdin, + StopSignal: config.StopSignal, + Cmd: config.Spec.Process.Args, + Entrypoint: createArtifact.Entrypoint, + }, + } + return data, nil +} + +func getCPUInfo(spec *specs.Spec) (string, string, *uint64, *int64, *uint64, *int64, *uint64) { + if spec.Linux.Resources == nil { + return "", "", nil, nil, nil, nil, nil + } + cpu := spec.Linux.Resources.CPU + if cpu == nil { + return "", "", nil, nil, nil, nil, nil + } + return cpu.Cpus, cpu.Mems, cpu.Period, cpu.Quota, cpu.RealtimePeriod, cpu.RealtimeRuntime, cpu.Shares +} + +func getBLKIOInfo(spec *specs.Spec) (*uint16, []specs.LinuxWeightDevice, []specs.LinuxThrottleDevice, []specs.LinuxThrottleDevice, []specs.LinuxThrottleDevice, []specs.LinuxThrottleDevice) { + if spec.Linux.Resources == nil { + return nil, nil, nil, nil, nil, nil + } + blkio := spec.Linux.Resources.BlockIO + if blkio == nil { + return nil, nil, nil, nil, nil, nil + } + return blkio.Weight, blkio.WeightDevice, blkio.ThrottleReadBpsDevice, blkio.ThrottleWriteBpsDevice, blkio.ThrottleReadIOPSDevice, blkio.ThrottleWriteIOPSDevice +} + +func getMemoryInfo(spec *specs.Spec) (*int64, *int64, *int64, *uint64, *bool) { + if spec.Linux.Resources == nil { + return nil, nil, nil, nil, nil + } + memory := spec.Linux.Resources.Memory + if memory == nil { + return nil, nil, nil, nil, nil + } + return memory.Kernel, memory.Reservation, memory.Swap, memory.Swappiness, memory.DisableOOMKiller +} + +func getPidsInfo(spec *specs.Spec) *int64 { + if spec.Linux.Resources == nil { + return nil + } + pids := spec.Linux.Resources.Pids + if pids == nil { + return nil + } + return &pids.Limit +} + +func getCgroup(spec *specs.Spec) string { + cgroup := "host" + for _, ns := range spec.Linux.Namespaces { + if ns.Type == specs.CgroupNamespace && ns.Path != "" { + cgroup = "container" + } + } + return cgroup +} + +// ContainerData holds the podman inspect data for a container +type ContainerData struct { + CtrInspectData *libpod.ContainerInspectData `json:"CtrInspectData"` + HostConfig *HostConfig `json:"HostConfig"` + Config *CtrConfig `json:"Config"` +} + +// LogConfig holds the log information for a container +type LogConfig struct { + Type string `json:"Type"` // TODO + Config map[string]string `json:"Config"` //idk type, TODO +} + +// HostConfig represents the host configuration for the container +type HostConfig struct { + ContainerIDFile string `json:"ContainerIDFile"` + LogConfig *LogConfig `json:"LogConfig"` //TODO + NetworkMode string `json:"NetworkMode"` + PortBindings map[string]struct{} `json:"PortBindings"` //TODO + AutoRemove bool `json:"AutoRemove"` + CapAdd []string `json:"CapAdd"` + CapDrop []string `json:"CapDrop"` + DNS []string `json:"DNS"` + DNSOptions []string `json:"DNSOptions"` + DNSSearch []string `json:"DNSSearch"` + ExtraHosts []string `json:"ExtraHosts"` + GroupAdd []uint32 `json:"GroupAdd"` + IpcMode string `json:"IpcMode"` + Cgroup string `json:"Cgroup"` + OomScoreAdj *int `json:"OomScoreAdj"` + PidMode string `json:"PidMode"` + Privileged bool `json:"Privileged"` + PublishAllPorts bool `json:"PublishAllPorts"` //TODO + ReadonlyRootfs bool `json:"ReadonlyRootfs"` + SecurityOpt []string `json:"SecurityOpt"` + UTSMode string `json:"UTSMode"` + UsernsMode string `json:"UsernsMode"` + ShmSize string `json:"ShmSize"` + Runtime string `json:"Runtime"` + ConsoleSize *specs.Box `json:"ConsoleSize"` + Isolation string `json:"Isolation"` //TODO + CPUShares *uint64 `json:"CPUSShares"` + Memory int64 `json:"Memory"` + NanoCPUs int `json:"NanoCPUs"` //check type, TODO + CgroupParent string `json:"CgroupParent"` + BlkioWeight *uint16 `json:"BlkioWeight"` + BlkioWeightDevice []specs.LinuxWeightDevice `json:"BlkioWeightDevice"` + BlkioDeviceReadBps []specs.LinuxThrottleDevice `json:"BlkioDeviceReadBps"` + BlkioDeviceWriteBps []specs.LinuxThrottleDevice `json:"BlkioDeviceWriteBps"` + BlkioDeviceReadIOps []specs.LinuxThrottleDevice `json:"BlkioDeviceReadIOps"` + BlkioDeviceWriteIOps []specs.LinuxThrottleDevice `json:"BlkioDeviceWriteIOps"` + CPUPeriod *uint64 `json:"CPUPeriod"` + CPUQuota *int64 `json:"CPUQuota"` + CPURealtimePeriod *uint64 `json:"CPURealtimePeriod"` + CPURealtimeRuntime *int64 `json:"CPURealtimeRuntime"` + CPUSetCPUs string `json:"CPUSetCPUs"` + CPUSetMems string `json:"CPUSetMems"` + Devices []specs.LinuxDevice `json:"Devices"` + DiskQuota int `json:"DiskQuota"` //check type, TODO + KernelMemory *int64 `json:"KernelMemory"` + MemoryReservation *int64 `json:"MemoryReservation"` + MemorySwap *int64 `json:"MemorySwap"` + MemorySwappiness *uint64 `json:"MemorySwappiness"` + OomKillDisable *bool `json:"OomKillDisable"` + PidsLimit *int64 `json:"PidsLimit"` + Ulimits []string `json:"Ulimits"` + CPUCount int `json:"CPUCount"` //check type, TODO + CPUPercent int `json:"CPUPercent"` //check type, TODO + IOMaximumIOps int `json:"IOMaximumIOps"` //check type, TODO + IOMaximumBandwidth int `json:"IOMaximumBandwidth"` //check type, TODO +} + +// CtrConfig holds information about the container configuration +type CtrConfig struct { + Hostname string `json:"Hostname"` + DomainName string `json:"Domainname"` //TODO + User specs.User `json:"User"` + AttachStdin bool `json:"AttachStdin"` //TODO + AttachStdout bool `json:"AttachStdout"` //TODO + AttachStderr bool `json:"AttachStderr"` //TODO + Tty bool `json:"Tty"` + OpenStdin bool `json:"OpenStdin"` + StdinOnce bool `json:"StdinOnce"` //TODO + Env []string `json:"Env"` + Cmd []string `json:"Cmd"` + Image string `json:"Image"` + Volumes map[string]struct{} `json:"Volumes"` + WorkingDir string `json:"WorkingDir"` + Entrypoint string `json:"Entrypoint"` + Labels map[string]string `json:"Labels"` + Annotations map[string]string `json:"Annotations"` + StopSignal uint `json:"StopSignal"` +} |