cmd/run, pkg/podman: Make podman.InspectContainer() return a Container
Unmarshal the JSON from 'podman inspect --format json --type container' directly inside podman.InspectContainer() to confine the details within the podman package. The JSON samples for the unit tests were taken using the default Toolbx container on versions of Fedora that shipped a specific Podman and Toolbx version. This accounts for differences in the JSON caused by different major versions of Podman and the way different Toolbx versions set up the containers. One exception was Fedora 28, which had Podman 1.1.2 and Toolbx 0.0.9, which was the last Toolbx version before 'toolbox init-container' became the entry point for all Toolbx containers [1]. However, the default Toolbx image is no longer available from registry.fedoraproject.org. Hence, the image for Fedora 29 was used. The minimum required Podman version is 1.6.4 [2], and the Go implementation has been encouraging users to create containers with Toolbx version 0.0.17 or newer [3]. The versions used to collect the JSON samples for the unit tests were chosen accordingly. They don't exhaustively cover all possible supported and unsupported version combinations, but hopefully enough to be useful. [1] Commit8b84b5e460https://github.com/containers/toolbox/commit/8b84b5e4604921fa https://github.com/debarshiray/toolbox/pull/160 [2] Commit8e80dd5db1https://github.com/containers/toolbox/commit/8e80dd5db1e6f40b https://github.com/containers/toolbox/pull/1253 [3] Commit238f2451e7https://github.com/containers/toolbox/commit/238f2451e7d7d54a https://github.com/containers/toolbox/pull/318 https://github.com/containers/toolbox/pull/1490
This commit is contained in:
parent
e611969726
commit
ec7eb59bb0
|
|
@ -13,3 +13,4 @@
|
|||
{"/var/lib/flatpak", "/run/host/var/lib/flatpak", "ro"},
|
||||
{"/var/lib/systemd/coredump", "/run/host/var/lib/systemd/coredump", "ro"},
|
||||
{"/var/log/journal", "/run/host/var/log/journal", "ro"},
|
||||
" \"ro\"," +
|
||||
|
|
|
|||
|
|
@ -433,17 +433,16 @@ func runHelp(cmd *cobra.Command, args []string) {
|
|||
func callFlatpakSessionHelper(container string) error {
|
||||
logrus.Debugf("Inspecting mounts of container %s", container)
|
||||
|
||||
info, err := podman.InspectContainer(container)
|
||||
containerObj, err := podman.InspectContainer(container)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to inspect entry point of container %s", container)
|
||||
}
|
||||
|
||||
var needsFlatpakSessionHelper bool
|
||||
|
||||
mounts := info["Mounts"].([]interface{})
|
||||
mounts := containerObj.Mounts()
|
||||
for _, mount := range mounts {
|
||||
destination := mount.(map[string]interface{})["Destination"].(string)
|
||||
if destination == "/run/host/monitor" {
|
||||
if mount == "/run/host/monitor" {
|
||||
logrus.Debug("Requires org.freedesktop.Flatpak.SessionHelper")
|
||||
needsFlatpakSessionHelper = true
|
||||
break
|
||||
|
|
@ -526,30 +525,17 @@ func constructExecArgs(container, preserveFDs string,
|
|||
func getEntryPointAndPID(container string) (string, int, error) {
|
||||
logrus.Debugf("Inspecting entry point of container %s", container)
|
||||
|
||||
info, err := podman.InspectContainer(container)
|
||||
containerObj, err := podman.InspectContainer(container)
|
||||
if err != nil {
|
||||
return "", 0, fmt.Errorf("failed to inspect entry point of container %s", container)
|
||||
}
|
||||
|
||||
config := info["Config"].(map[string]interface{})
|
||||
entryPoint := config["Cmd"].([]interface{})[0].(string)
|
||||
entryPoint := containerObj.EntryPoint()
|
||||
entryPointPID := containerObj.EntryPointPID()
|
||||
|
||||
state := info["State"].(map[string]interface{})
|
||||
entryPointPID := state["Pid"]
|
||||
logrus.Debugf("Entry point PID is a %T", entryPointPID)
|
||||
logrus.Debugf("Entry point of container %s is %s (PID=%d)", container, entryPoint, entryPointPID)
|
||||
|
||||
var entryPointPIDInt int
|
||||
|
||||
switch entryPointPID := entryPointPID.(type) {
|
||||
case float64:
|
||||
entryPointPIDInt = int(entryPointPID)
|
||||
default:
|
||||
return "", 0, fmt.Errorf("failed to inspect entry point PID of container %s", container)
|
||||
}
|
||||
|
||||
logrus.Debugf("Entry point of container %s is %s (PID=%d)", container, entryPoint, entryPointPIDInt)
|
||||
|
||||
return entryPoint, entryPointPIDInt, nil
|
||||
return entryPoint, entryPointPID, nil
|
||||
}
|
||||
|
||||
func isCommandPresent(container, command string) (bool, error) {
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ sources = files(
|
|||
'pkg/podman/container.go',
|
||||
'pkg/podman/errors.go',
|
||||
'pkg/podman/podman.go',
|
||||
'pkg/podman/containerInspect_test.go',
|
||||
'pkg/shell/shell.go',
|
||||
'pkg/shell/shell_test.go',
|
||||
'pkg/skopeo/skopeo.go',
|
||||
|
|
|
|||
|
|
@ -18,27 +18,46 @@ package podman
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/containers/toolbox/pkg/utils"
|
||||
)
|
||||
|
||||
type Container interface {
|
||||
Created() string
|
||||
EntryPoint() string
|
||||
EntryPointPID() int
|
||||
ID() string
|
||||
Image() string
|
||||
Labels() map[string]string
|
||||
Mounts() []string
|
||||
Name() string
|
||||
Names() []string
|
||||
Status() string
|
||||
}
|
||||
|
||||
type containerInspect struct {
|
||||
created string
|
||||
entryPoint string
|
||||
entryPointPID int
|
||||
id string
|
||||
image string
|
||||
labels map[string]string
|
||||
mounts []string
|
||||
name string
|
||||
status string
|
||||
}
|
||||
|
||||
type containerPS struct {
|
||||
created string
|
||||
id string
|
||||
image string
|
||||
labels map[string]string
|
||||
names []string
|
||||
status string
|
||||
created string
|
||||
entryPoint string
|
||||
entryPointPID int
|
||||
id string
|
||||
image string
|
||||
labels map[string]string
|
||||
mounts []string
|
||||
names []string
|
||||
status string
|
||||
}
|
||||
|
||||
type Containers struct {
|
||||
|
|
@ -46,10 +65,105 @@ type Containers struct {
|
|||
i int
|
||||
}
|
||||
|
||||
func (container *containerInspect) Created() string {
|
||||
return container.created
|
||||
}
|
||||
|
||||
func (container *containerInspect) EntryPoint() string {
|
||||
return container.entryPoint
|
||||
}
|
||||
|
||||
func (container *containerInspect) EntryPointPID() int {
|
||||
return container.entryPointPID
|
||||
}
|
||||
|
||||
func (container *containerInspect) ID() string {
|
||||
return container.id
|
||||
}
|
||||
|
||||
func (container *containerInspect) Image() string {
|
||||
return container.image
|
||||
}
|
||||
|
||||
func (container *containerInspect) Labels() map[string]string {
|
||||
return container.labels
|
||||
}
|
||||
|
||||
func (container *containerInspect) Mounts() []string {
|
||||
return container.mounts
|
||||
}
|
||||
|
||||
func (container *containerInspect) Name() string {
|
||||
return container.name
|
||||
}
|
||||
|
||||
func (container *containerInspect) Names() []string {
|
||||
return []string{container.name}
|
||||
}
|
||||
|
||||
func (container *containerInspect) Status() string {
|
||||
return container.status
|
||||
}
|
||||
|
||||
func (container *containerInspect) UnmarshalJSON(data []byte) error {
|
||||
var raw struct {
|
||||
Config struct {
|
||||
Cmd []string
|
||||
Labels map[string]string
|
||||
}
|
||||
Created time.Time
|
||||
ID string
|
||||
ImageName string
|
||||
Mounts []struct {
|
||||
Destination string
|
||||
}
|
||||
Name string
|
||||
State struct {
|
||||
PID int
|
||||
Status string
|
||||
}
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(raw.Config.Cmd) > 0 {
|
||||
container.entryPoint = raw.Config.Cmd[0]
|
||||
}
|
||||
|
||||
container.entryPointPID = raw.State.PID
|
||||
|
||||
created := raw.Created.Unix()
|
||||
container.created = utils.HumanDuration(created)
|
||||
|
||||
container.id = raw.ID
|
||||
container.image = raw.ImageName
|
||||
container.labels = raw.Config.Labels
|
||||
|
||||
for _, mount := range raw.Mounts {
|
||||
if mount.Destination != "" {
|
||||
container.mounts = append(container.mounts, mount.Destination)
|
||||
}
|
||||
}
|
||||
|
||||
container.name = raw.Name
|
||||
container.status = raw.State.Status
|
||||
return nil
|
||||
}
|
||||
|
||||
func (container *containerPS) Created() string {
|
||||
return container.created
|
||||
}
|
||||
|
||||
func (container *containerPS) EntryPoint() string {
|
||||
return container.entryPoint
|
||||
}
|
||||
|
||||
func (container *containerPS) EntryPointPID() int {
|
||||
return container.entryPointPID
|
||||
}
|
||||
|
||||
func (container *containerPS) ID() string {
|
||||
return container.id
|
||||
}
|
||||
|
|
@ -62,6 +176,10 @@ func (container *containerPS) Labels() map[string]string {
|
|||
return container.labels
|
||||
}
|
||||
|
||||
func (container *containerPS) Mounts() []string {
|
||||
return container.mounts
|
||||
}
|
||||
|
||||
func (container *containerPS) Name() string {
|
||||
return container.names[0]
|
||||
}
|
||||
|
|
@ -76,11 +194,14 @@ func (container *containerPS) Status() string {
|
|||
|
||||
func (container *containerPS) UnmarshalJSON(data []byte) error {
|
||||
var raw struct {
|
||||
Command []string
|
||||
Created interface{}
|
||||
ID string
|
||||
Image string
|
||||
Labels map[string]string
|
||||
Mounts []string
|
||||
Names interface{}
|
||||
PID int
|
||||
State interface{}
|
||||
Status string
|
||||
}
|
||||
|
|
@ -89,6 +210,12 @@ func (container *containerPS) UnmarshalJSON(data []byte) error {
|
|||
return err
|
||||
}
|
||||
|
||||
if len(raw.Command) > 0 {
|
||||
container.entryPoint = raw.Command[0]
|
||||
}
|
||||
|
||||
container.entryPointPID = raw.PID
|
||||
|
||||
// In Podman V1 the field 'Created' held a human-readable string in format
|
||||
// "5 minutes ago". Since Podman V2 the field holds an integer with Unix time.
|
||||
// After a discussion in https://github.com/containers/podman/issues/6594 the
|
||||
|
|
@ -106,6 +233,7 @@ func (container *containerPS) UnmarshalJSON(data []byte) error {
|
|||
container.id = raw.ID
|
||||
container.image = raw.Image
|
||||
container.labels = raw.Labels
|
||||
container.mounts = raw.Mounts
|
||||
|
||||
// In Podman V1 the field 'Names' held a single string but since Podman V2 the
|
||||
// field holds an array of strings
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -302,7 +302,7 @@ func ImageExists(image string) (bool, error) {
|
|||
}
|
||||
|
||||
// InspectContainer is a wrapper around 'podman inspect --type container' command
|
||||
func InspectContainer(container string) (map[string]interface{}, error) {
|
||||
func InspectContainer(container string) (Container, error) {
|
||||
var stdout bytes.Buffer
|
||||
|
||||
logLevelString := LogLevel.String()
|
||||
|
|
@ -313,13 +313,12 @@ func InspectContainer(container string) (map[string]interface{}, error) {
|
|||
}
|
||||
|
||||
output := stdout.Bytes()
|
||||
var info []map[string]interface{}
|
||||
|
||||
if err := json.Unmarshal(output, &info); err != nil {
|
||||
var containers []containerInspect
|
||||
if err := json.Unmarshal(output, &containers); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return info[0], nil
|
||||
return &containers[0], nil
|
||||
}
|
||||
|
||||
// InspectImage is a wrapper around 'podman inspect --type image' command
|
||||
|
|
@ -344,12 +343,12 @@ func InspectImage(image string) (map[string]interface{}, error) {
|
|||
}
|
||||
|
||||
func IsToolboxContainer(container string) (bool, error) {
|
||||
info, err := InspectContainer(container)
|
||||
containerObj, err := InspectContainer(container)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("failed to inspect container %s", container)
|
||||
}
|
||||
|
||||
labels, _ := info["Config"].(map[string]interface{})["Labels"].(map[string]interface{})
|
||||
labels := containerObj.Labels()
|
||||
if labels["com.github.containers.toolbox"] != "true" && labels["com.github.debarshiray.toolbox"] != "true" {
|
||||
return false, fmt.Errorf("%s is not a Toolbx container", container)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue