summaryrefslogtreecommitdiff
path: root/libpod
diff options
context:
space:
mode:
authorBrent Baude <bbaude@redhat.com>2020-03-15 11:53:59 -0500
committerBrent Baude <bbaude@redhat.com>2020-04-06 12:45:42 -0500
commite20ecc733c878f0c4b67a21204f0d5ae11929bf0 (patch)
tree8686fd9c9f123cbed11f0589655caaa128b12061 /libpod
parente318b09b6800ddb013ddf3b9a2fb99ebc55bd920 (diff)
downloadpodman-e20ecc733c878f0c4b67a21204f0d5ae11929bf0.tar.gz
podman-e20ecc733c878f0c4b67a21204f0d5ae11929bf0.tar.bz2
podman-e20ecc733c878f0c4b67a21204f0d5ae11929bf0.zip
refactor info
the current implementation of info, while typed, is very loosely done so. we need stronger types for our apiv2 implmentation and bindings. Signed-off-by: Brent Baude <bbaude@redhat.com>
Diffstat (limited to 'libpod')
-rw-r--r--libpod/define/info.go101
-rw-r--r--libpod/info.go243
-rw-r--r--libpod/oci.go3
-rw-r--r--libpod/oci_conmon_linux.go28
-rw-r--r--libpod/oci_conmon_unsupported.go4
-rw-r--r--libpod/oci_missing.go15
-rw-r--r--libpod/runtime.go40
7 files changed, 284 insertions, 150 deletions
diff --git a/libpod/define/info.go b/libpod/define/info.go
new file mode 100644
index 000000000..e9809c367
--- /dev/null
+++ b/libpod/define/info.go
@@ -0,0 +1,101 @@
+package define
+
+import "github.com/containers/storage/pkg/idtools"
+
+// Info is the overall struct that describes the host system
+// running libpod/podman
+type Info struct {
+ Host *HostInfo `json:"host"`
+ Store *StoreInfo `json:"store"`
+ Registries map[string]interface{} `json:"registries"`
+}
+
+//HostInfo describes the libpod host
+type HostInfo struct {
+ Arch string `json:"arch"`
+ BuildahVersion string `json:"buildahVersion"`
+ CGroupsVersion string `json:"cgroupVersion"`
+ Conmon *ConmonInfo `json:"conmon"`
+ CPUs int `json:"cpus"`
+ Distribution DistributionInfo `json:"distribution"`
+ EventLogger string `json:"eventLogger"`
+ Hostname string `json:"hostname"`
+ IDMappings IDMappings `json:"idMappings,omitempty"`
+ Kernel string `json:"kernel"`
+ MemFree int64 `json:"memFree"`
+ MemTotal int64 `json:"memTotal"`
+ OCIRuntime *OCIRuntimeInfo `json:"ociRuntime"`
+ OS string `json:"os"`
+ Rootless bool `json:"rootless"`
+ RuntimeInfo map[string]interface{} `json:"runtimeInfo,omitempty"`
+ Slirp4NetNS SlirpInfo `json:"slirp4netns,omitempty"`
+ SwapFree int64 `json:"swapFree"`
+ SwapTotal int64 `json:"swapTotal"`
+ Uptime string `json:"uptime"`
+}
+
+// SlirpInfo describes the slirp exectuable that
+// is being being used.
+type SlirpInfo struct {
+ Executable string `json:"executable"`
+ Package string `json:"package"`
+ Version string `json:"version"`
+}
+
+// IDMappings describe the GID and UID mappings
+type IDMappings struct {
+ GIDMap []idtools.IDMap `json:"gidmap"`
+ UIDMap []idtools.IDMap `json:"uidmap"`
+}
+
+// DistributionInfo describes the host distribution
+// for libpod
+type DistributionInfo struct {
+ Distribution string `json:"distribution"`
+ Version string `json:"version"`
+}
+
+// ConmonInfo describes the conmon executable being used
+type ConmonInfo struct {
+ Package string `json:"package"`
+ Path string `json:"path"`
+ Version string `json:"version"`
+}
+
+// OCIRuntimeInfo describes the runtime (crun or runc) being
+// used with podman
+type OCIRuntimeInfo struct {
+ Name string `json:"name"`
+ Package string `json:"package"`
+ Path string `json:"path"`
+ Version string `json:"version"`
+}
+
+// StoreInfo describes the container storage and its
+// attributes
+type StoreInfo struct {
+ ConfigFile string `json:"configFile"`
+ ContainerStore ContainerStore `json:"containerStore"`
+ GraphDriverName string `json:"graphDriverName"`
+ GraphOptions map[string]interface{} `json:"graphOptions"`
+ GraphRoot string `json:"graphRoot"`
+ GraphStatus map[string]string `json:"graphStatus"`
+ ImageStore ImageStore `json:"imageStore"`
+ RunRoot string `json:"runRoot"`
+ VolumePath string `json:"volumePath"`
+}
+
+// ImageStore describes the image store. Right now only the number
+// of images present
+type ImageStore struct {
+ Number int `json:"number"`
+}
+
+// ContainerStore describes the quantity of containers in the
+// store by status
+type ContainerStore struct {
+ Number int `json:"number"`
+ Paused int `json:"paused"`
+ Running int `json:"running"`
+ Stopped int `json:"stopped"`
+}
diff --git a/libpod/info.go b/libpod/info.go
index 8d411f0d4..3cc767be6 100644
--- a/libpod/info.go
+++ b/libpod/info.go
@@ -13,7 +13,9 @@ import (
"time"
"github.com/containers/buildah"
+ "github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/pkg/cgroups"
+ registries2 "github.com/containers/libpod/pkg/registries"
"github.com/containers/libpod/pkg/rootless"
"github.com/containers/storage"
"github.com/containers/storage/pkg/system"
@@ -21,14 +23,80 @@ import (
"github.com/sirupsen/logrus"
)
+// Info returns the store and host information
+func (r *Runtime) info() (*define.Info, error) {
+ info := define.Info{}
+ // get host information
+ hostInfo, err := r.hostInfo()
+ if err != nil {
+ return nil, errors.Wrapf(err, "error getting host info")
+ }
+ info.Host = hostInfo
+
+ // get store information
+ storeInfo, err := r.storeInfo()
+ if err != nil {
+ return nil, errors.Wrapf(err, "error getting store info")
+ }
+ info.Store = storeInfo
+ registries := make(map[string]interface{})
+ data, err := registries2.GetRegistriesData()
+ if err != nil {
+ return nil, errors.Wrapf(err, "error getting registries")
+ }
+ for _, reg := range data {
+ registries[reg.Prefix] = reg
+ }
+ regs, err := registries2.GetRegistries()
+ if err != nil {
+ return nil, errors.Wrapf(err, "error getting registries")
+ }
+ if len(regs) > 0 {
+ registries["search"] = regs
+ }
+
+ info.Registries = registries
+ return &info, nil
+}
+
// top-level "host" info
-func (r *Runtime) hostInfo() (map[string]interface{}, error) {
+func (r *Runtime) hostInfo() (*define.HostInfo, error) {
// lets say OS, arch, number of cpus, amount of memory, maybe os distribution/version, hostname, kernel version, uptime
- info := map[string]interface{}{}
- info["os"] = runtime.GOOS
- info["arch"] = runtime.GOARCH
- info["cpus"] = runtime.NumCPU()
- info["rootless"] = rootless.IsRootless()
+ mi, err := system.ReadMemInfo()
+ if err != nil {
+ return nil, errors.Wrapf(err, "error reading memory info")
+ }
+
+ hostDistributionInfo := r.GetHostDistributionInfo()
+
+ kv, err := readKernelVersion()
+ if err != nil {
+ return nil, errors.Wrapf(err, "error reading kernel version")
+ }
+
+ host, err := os.Hostname()
+ if err != nil {
+ return nil, errors.Wrapf(err, "error getting hostname")
+ }
+ info := define.HostInfo{
+ Arch: runtime.GOARCH,
+ BuildahVersion: buildah.Version,
+ CPUs: runtime.NumCPU(),
+ Distribution: hostDistributionInfo,
+ EventLogger: r.eventer.String(),
+ Hostname: host,
+ IDMappings: define.IDMappings{},
+ Kernel: kv,
+ MemFree: mi.MemFree,
+ MemTotal: mi.MemTotal,
+ OS: runtime.GOOS,
+ Rootless: rootless.IsRootless(),
+ Slirp4NetNS: define.SlirpInfo{},
+ SwapFree: mi.SwapFree,
+ SwapTotal: mi.SwapTotal,
+ }
+
+ // CGroups version
unified, err := cgroups.IsCgroup2UnifiedMode()
if err != nil {
return nil, errors.Wrapf(err, "error reading cgroups mode")
@@ -37,17 +105,8 @@ func (r *Runtime) hostInfo() (map[string]interface{}, error) {
if unified {
cgroupVersion = "v2"
}
- info["CgroupVersion"] = cgroupVersion
- mi, err := system.ReadMemInfo()
- if err != nil {
- return nil, errors.Wrapf(err, "error reading memory info")
- }
- // TODO this might be a place for github.com/dustin/go-humanize
- info["MemTotal"] = mi.MemTotal
- info["MemFree"] = mi.MemFree
- info["SwapTotal"] = mi.SwapTotal
- info["SwapFree"] = mi.SwapFree
- hostDistributionInfo := r.GetHostDistributionInfo()
+ info.CGroupsVersion = cgroupVersion
+
if rootless.IsRootless() {
if path, err := exec.LookPath("slirp4netns"); err == nil {
logrus.Warnf("Failed to retrieve program version for %s: %v", path, err)
@@ -55,11 +114,12 @@ func (r *Runtime) hostInfo() (map[string]interface{}, error) {
if err != nil {
logrus.Warnf("Failed to retrieve program version for %s: %v", path, err)
}
- program := map[string]interface{}{}
- program["Executable"] = path
- program["Version"] = version
- program["Package"] = packageVersion(path)
- info["slirp4netns"] = program
+ program := define.SlirpInfo{
+ Executable: path,
+ Package: packageVersion(path),
+ Version: version,
+ }
+ info.Slirp4NetNS = program
}
uidmappings, err := rootless.ReadMappingsProc("/proc/self/uid_map")
if err != nil {
@@ -69,29 +129,19 @@ func (r *Runtime) hostInfo() (map[string]interface{}, error) {
if err != nil {
return nil, errors.Wrapf(err, "error reading gid mappings")
}
- idmappings := make(map[string]interface{})
- idmappings["uidmap"] = uidmappings
- idmappings["gidmap"] = gidmappings
- info["IDMappings"] = idmappings
- }
- info["Distribution"] = map[string]interface{}{
- "distribution": hostDistributionInfo["Distribution"],
- "version": hostDistributionInfo["Version"],
- }
- info["BuildahVersion"] = buildah.Version
- kv, err := readKernelVersion()
- if err != nil {
- return nil, errors.Wrapf(err, "error reading kernel version")
+ idmappings := define.IDMappings{
+ GIDMap: gidmappings,
+ UIDMap: uidmappings,
+ }
+ info.IDMappings = idmappings
}
- info["kernel"] = kv
- runtimeInfo, err := r.defaultOCIRuntime.RuntimeInfo()
+ conmonInfo, ociruntimeInfo, err := r.defaultOCIRuntime.RuntimeInfo()
if err != nil {
logrus.Errorf("Error getting info on OCI runtime %s: %v", r.defaultOCIRuntime.Name(), err)
} else {
- for k, v := range runtimeInfo {
- info[k] = v
- }
+ info.Conmon = conmonInfo
+ info.OCIRuntime = ociruntimeInfo
}
up, err := readUptime()
@@ -105,6 +155,7 @@ func (r *Runtime) hostInfo() (map[string]interface{}, error) {
return nil, errors.Wrapf(err, "error parsing system uptime")
}
+ // TODO Isnt there a simple lib for this, something like humantime?
hoursFound := false
var timeBuffer bytes.Buffer
var hoursBuffer bytes.Buffer
@@ -121,32 +172,75 @@ func (r *Runtime) hostInfo() (map[string]interface{}, error) {
}
}
- info["uptime"] = timeBuffer.String()
+ info.Uptime = timeBuffer.String()
if hoursFound {
hours, err := strconv.ParseFloat(hoursBuffer.String(), 64)
if err == nil {
days := hours / 24
- info["uptime"] = fmt.Sprintf("%s (Approximately %.2f days)", info["uptime"], days)
+ info.Uptime = fmt.Sprintf("%s (Approximately %.2f days)", info.Uptime, days)
}
}
- host, err := os.Hostname()
+ return &info, nil
+}
+
+func (r *Runtime) getContainerStoreInfo() (define.ContainerStore, error) {
+ var (
+ paused, running, stopped int
+ )
+ cs := define.ContainerStore{}
+ cons, err := r.GetAllContainers()
if err != nil {
- return nil, errors.Wrapf(err, "error getting hostname")
+ return cs, err
}
- info["hostname"] = host
- info["eventlogger"] = r.eventer.String()
-
- return info, nil
+ for _, con := range cons {
+ state, err := con.State()
+ if err != nil {
+ return cs, err
+ }
+ switch state {
+ case define.ContainerStateRunning:
+ running += 1
+ case define.ContainerStatePaused:
+ paused += 1
+ default:
+ stopped += 1
+ }
+ }
+ cs.Number = len(cons)
+ cs.Paused = paused
+ cs.Stopped = stopped
+ cs.Running = running
+ return cs, nil
}
// top-level "store" info
-func (r *Runtime) storeInfo() (map[string]interface{}, error) {
+func (r *Runtime) storeInfo() (*define.StoreInfo, error) {
// lets say storage driver in use, number of images, number of containers
- info := map[string]interface{}{}
- info["GraphRoot"] = r.store.GraphRoot()
- info["RunRoot"] = r.store.RunRoot()
- info["GraphDriverName"] = r.store.GraphDriverName()
+ configFile, err := storage.DefaultConfigFile(rootless.IsRootless())
+ if err != nil {
+ return nil, err
+ }
+ images, err := r.store.Images()
+ if err != nil {
+ return nil, errors.Wrapf(err, "error getting number of images")
+ }
+ conInfo, err := r.getContainerStoreInfo()
+ if err != nil {
+ return nil, err
+ }
+ imageInfo := define.ImageStore{Number: len(images)}
+
+ info := define.StoreInfo{
+ ImageStore: imageInfo,
+ ContainerStore: conInfo,
+ GraphRoot: r.store.GraphRoot(),
+ RunRoot: r.store.RunRoot(),
+ GraphDriverName: r.store.GraphDriverName(),
+ GraphOptions: nil,
+ VolumePath: r.config.Engine.VolumePath,
+ ConfigFile: configFile,
+ }
graphOptions := map[string]interface{}{}
for _, o := range r.store.GraphOptions() {
split := strings.SplitN(o, "=", 2)
@@ -164,14 +258,8 @@ func (r *Runtime) storeInfo() (map[string]interface{}, error) {
graphOptions[split[0]] = split[1]
}
}
- info["GraphOptions"] = graphOptions
- info["VolumePath"] = r.config.Engine.VolumePath
+ info.GraphOptions = graphOptions
- configFile, err := storage.DefaultConfigFile(rootless.IsRootless())
- if err != nil {
- return nil, err
- }
- info["ConfigFile"] = configFile
statusPairs, err := r.store.Status()
if err != nil {
return nil, err
@@ -180,24 +268,8 @@ func (r *Runtime) storeInfo() (map[string]interface{}, error) {
for _, pair := range statusPairs {
status[pair[0]] = pair[1]
}
- info["GraphStatus"] = status
- images, err := r.store.Images()
- if err != nil {
- return nil, errors.Wrapf(err, "error getting number of images")
- }
- info["ImageStore"] = map[string]interface{}{
- "number": len(images),
- }
-
- containers, err := r.store.Containers()
- if err != nil {
- return nil, errors.Wrapf(err, "error getting number of containers")
- }
- info["ContainerStore"] = map[string]interface{}{
- "number": len(containers),
- }
-
- return info, nil
+ info.GraphStatus = status
+ return &info, nil
}
func readKernelVersion() (string, error) {
@@ -225,14 +297,13 @@ func readUptime() (string, error) {
}
// GetHostDistributionInfo returns a map containing the host's distribution and version
-func (r *Runtime) GetHostDistributionInfo() map[string]string {
- dist := make(map[string]string)
-
+func (r *Runtime) GetHostDistributionInfo() define.DistributionInfo {
// Populate values in case we cannot find the values
// or the file
- dist["Distribution"] = "unknown"
- dist["Version"] = "unknown"
-
+ dist := define.DistributionInfo{
+ Distribution: "unknown",
+ Version: "unknown",
+ }
f, err := os.Open("/etc/os-release")
if err != nil {
return dist
@@ -242,10 +313,10 @@ func (r *Runtime) GetHostDistributionInfo() map[string]string {
l := bufio.NewScanner(f)
for l.Scan() {
if strings.HasPrefix(l.Text(), "ID=") {
- dist["Distribution"] = strings.TrimPrefix(l.Text(), "ID=")
+ dist.Distribution = strings.TrimPrefix(l.Text(), "ID=")
}
if strings.HasPrefix(l.Text(), "VERSION_ID=") {
- dist["Version"] = strings.Trim(strings.TrimPrefix(l.Text(), "VERSION_ID="), "\"")
+ dist.Version = strings.Trim(strings.TrimPrefix(l.Text(), "VERSION_ID="), "\"")
}
}
return dist
diff --git a/libpod/oci.go b/libpod/oci.go
index e4fbcb62e..6adf42497 100644
--- a/libpod/oci.go
+++ b/libpod/oci.go
@@ -5,7 +5,6 @@ import (
"net"
"github.com/containers/libpod/libpod/define"
-
"k8s.io/client-go/tools/remotecommand"
)
@@ -122,7 +121,7 @@ type OCIRuntime interface {
ExitFilePath(ctr *Container) (string, error)
// RuntimeInfo returns verbose information about the runtime.
- RuntimeInfo() (map[string]interface{}, error)
+ RuntimeInfo() (*define.ConmonInfo, *define.OCIRuntimeInfo, error)
}
// ExecOptions are options passed into ExecContainer. They control the command
diff --git a/libpod/oci_conmon_linux.go b/libpod/oci_conmon_linux.go
index 2e96dbe57..c20e3f0b4 100644
--- a/libpod/oci_conmon_linux.go
+++ b/libpod/oci_conmon_linux.go
@@ -999,32 +999,30 @@ func (r *ConmonOCIRuntime) ExitFilePath(ctr *Container) (string, error) {
}
// RuntimeInfo provides information on the runtime.
-func (r *ConmonOCIRuntime) RuntimeInfo() (map[string]interface{}, error) {
+func (r *ConmonOCIRuntime) RuntimeInfo() (*define.ConmonInfo, *define.OCIRuntimeInfo, error) {
runtimePackage := packageVersion(r.path)
conmonPackage := packageVersion(r.conmonPath)
runtimeVersion, err := r.getOCIRuntimeVersion()
if err != nil {
- return nil, errors.Wrapf(err, "error getting version of OCI runtime %s", r.name)
+ return nil, nil, errors.Wrapf(err, "error getting version of OCI runtime %s", r.name)
}
conmonVersion, err := r.getConmonVersion()
if err != nil {
- return nil, errors.Wrapf(err, "error getting conmon version")
+ return nil, nil, errors.Wrapf(err, "error getting conmon version")
}
- info := make(map[string]interface{})
- info["Conmon"] = map[string]interface{}{
- "path": r.conmonPath,
- "package": conmonPackage,
- "version": conmonVersion,
+ conmon := define.ConmonInfo{
+ Package: conmonPackage,
+ Path: r.conmonPath,
+ Version: conmonVersion,
}
- info["OCIRuntime"] = map[string]interface{}{
- "name": r.name,
- "path": r.path,
- "package": runtimePackage,
- "version": runtimeVersion,
+ ocirt := define.OCIRuntimeInfo{
+ Name: r.name,
+ Path: r.path,
+ Package: runtimePackage,
+ Version: runtimeVersion,
}
-
- return info, nil
+ return &conmon, &ocirt, nil
}
// makeAccessible changes the path permission and each parent directory to have --x--x--x
diff --git a/libpod/oci_conmon_unsupported.go b/libpod/oci_conmon_unsupported.go
index 395b6f6d9..1f9d89ff6 100644
--- a/libpod/oci_conmon_unsupported.go
+++ b/libpod/oci_conmon_unsupported.go
@@ -117,8 +117,8 @@ func (r *ConmonOCIRuntime) ExitFilePath(ctr *Container) (string, error) {
}
// RuntimeInfo is not supported on this OS.
-func (r *ConmonOCIRuntime) RuntimeInfo() (map[string]interface{}, error) {
- return nil, define.ErrNotImplemented
+func (r *ConmonOCIRuntime) RuntimeInfo() (*define.ConmonInfo, *define.OCIRuntimeInfo, error) {
+ return nil, nil, define.ErrNotImplemented
}
// Package is not supported on this OS.
diff --git a/libpod/oci_missing.go b/libpod/oci_missing.go
index a5d589255..5284fb4b7 100644
--- a/libpod/oci_missing.go
+++ b/libpod/oci_missing.go
@@ -195,15 +195,14 @@ func (r *MissingRuntime) ExitFilePath(ctr *Container) (string, error) {
}
// RuntimeInfo returns information on the missing runtime
-func (r *MissingRuntime) RuntimeInfo() (map[string]interface{}, error) {
- info := make(map[string]interface{})
- info["OCIRuntime"] = map[string]interface{}{
- "name": r.name,
- "path": "missing",
- "package": "missing",
- "version": "missing",
+func (r *MissingRuntime) RuntimeInfo() (*define.ConmonInfo, *define.OCIRuntimeInfo, error) {
+ ocirt := define.OCIRuntimeInfo{
+ Name: r.name,
+ Path: "missing",
+ Package: "missing",
+ Version: "missing",
}
- return info, nil
+ return nil, &ocirt, nil
}
// Return an error indicating the runtime is missing
diff --git a/libpod/runtime.go b/libpod/runtime.go
index 422b79359..a6032ad23 100644
--- a/libpod/runtime.go
+++ b/libpod/runtime.go
@@ -9,16 +9,14 @@ import (
"sync"
"syscall"
+ "github.com/containers/common/pkg/config"
is "github.com/containers/image/v5/storage"
"github.com/containers/image/v5/types"
-
- "github.com/containers/common/pkg/config"
"github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/libpod/events"
"github.com/containers/libpod/libpod/image"
"github.com/containers/libpod/libpod/lock"
"github.com/containers/libpod/pkg/cgroups"
- sysreg "github.com/containers/libpod/pkg/registries"
"github.com/containers/libpod/pkg/rootless"
"github.com/containers/libpod/pkg/util"
"github.com/containers/storage"
@@ -675,40 +673,8 @@ func (r *Runtime) refresh(alivePath string) error {
}
// Info returns the store and host information
-func (r *Runtime) Info() ([]define.InfoData, error) {
- info := []define.InfoData{}
- // get host information
- hostInfo, err := r.hostInfo()
- if err != nil {
- return nil, errors.Wrapf(err, "error getting host info")
- }
- info = append(info, define.InfoData{Type: "host", Data: hostInfo})
-
- // get store information
- storeInfo, err := r.storeInfo()
- if err != nil {
- return nil, errors.Wrapf(err, "error getting store info")
- }
- info = append(info, define.InfoData{Type: "store", Data: storeInfo})
-
- registries := make(map[string]interface{})
- data, err := sysreg.GetRegistriesData()
- if err != nil {
- return nil, errors.Wrapf(err, "error getting registries")
- }
- for _, reg := range data {
- registries[reg.Prefix] = reg
- }
- regs, err := sysreg.GetRegistries()
- if err != nil {
- return nil, errors.Wrapf(err, "error getting registries")
- }
- if len(regs) > 0 {
- registries["search"] = regs
- }
-
- info = append(info, define.InfoData{Type: "registries", Data: registries})
- return info, nil
+func (r *Runtime) Info() (*define.Info, error) {
+ return r.info()
}
// generateName generates a unique name for a container or pod.