17
"github.com/containers/buildah"
18
"github.com/containers/buildah/pkg/parse"
19
"github.com/containers/buildah/pkg/util"
20
"github.com/containers/common/pkg/version"
21
"github.com/containers/image/v5/pkg/sysregistriesv2"
22
"github.com/containers/podman/v5/libpod/define"
23
"github.com/containers/podman/v5/libpod/linkmode"
24
"github.com/containers/storage"
25
"github.com/containers/storage/pkg/system"
26
"github.com/sirupsen/logrus"
29
// Info returns the store and host information
30
func (r *Runtime) info() (*define.Info, error) {
32
versionInfo, err := define.GetVersion()
34
return nil, fmt.Errorf("getting version info: %w", err)
36
info.Version = versionInfo
37
// get host information
38
hostInfo, err := r.hostInfo()
40
return nil, fmt.Errorf("getting host info: %w", err)
44
// get store information
45
storeInfo, err := r.storeInfo()
47
return nil, fmt.Errorf("getting store info: %w", err)
49
info.Store = storeInfo
50
registries := make(map[string]interface{})
52
sys := r.SystemContext()
53
data, err := sysregistriesv2.GetRegistries(sys)
55
return nil, fmt.Errorf("getting registries: %w", err)
57
for _, reg := range data {
58
registries[reg.Prefix] = reg
60
regs, err := sysregistriesv2.UnqualifiedSearchRegistries(sys)
62
return nil, fmt.Errorf("getting registries: %w", err)
65
registries["search"] = regs
67
volumePlugins := make([]string, 0, len(r.config.Engine.VolumePlugins)+1)
68
// the local driver always exists
69
volumePlugins = append(volumePlugins, "local")
70
for plugin := range r.config.Engine.VolumePlugins {
71
volumePlugins = append(volumePlugins, plugin)
73
info.Plugins.Volume = volumePlugins
74
info.Plugins.Network = r.network.Drivers()
75
info.Plugins.Log = logDrivers
77
info.Registries = registries
81
// top-level "host" info
82
func (r *Runtime) hostInfo() (*define.HostInfo, error) {
83
// let's say OS, arch, number of cpus, amount of memory, maybe os distribution/version, hostname, kernel version, uptime
84
mi, err := system.ReadMemInfo()
86
return nil, fmt.Errorf("reading memory info: %w", err)
89
hostDistributionInfo := r.GetHostDistributionInfo()
91
kv, err := util.ReadKernelVersion()
93
return nil, fmt.Errorf("reading kernel version: %w", err)
96
host, err := os.Hostname()
98
return nil, fmt.Errorf("getting hostname: %w", err)
101
cpuUtil, err := getCPUUtilization()
106
locksFree, err := r.lockManager.AvailableLocks()
108
return nil, fmt.Errorf("getting free locks: %w", err)
111
info := define.HostInfo{
112
Arch: runtime.GOARCH,
113
BuildahVersion: buildah.Version,
114
DatabaseBackend: r.config.Engine.DBBackend,
115
Linkmode: linkmode.Linkmode(),
116
CPUs: runtime.NumCPU(),
117
CPUUtilization: cpuUtil,
118
Distribution: hostDistributionInfo,
119
LogDriver: r.config.Containers.LogDriver,
120
EventLogger: r.eventer.String(),
121
FreeLocks: locksFree,
125
MemTotal: mi.MemTotal,
126
NetworkBackend: r.config.Network.NetworkBackend,
127
NetworkBackendInfo: r.network.NetworkInfo(),
129
RootlessNetworkCmd: r.config.Network.DefaultRootlessNetworkCmd,
130
SwapFree: mi.SwapFree,
131
SwapTotal: mi.SwapTotal,
133
platform := parse.DefaultPlatform()
134
pArr := strings.Split(platform, "/")
136
info.Variant = pArr[2]
138
if err := r.setPlatformHostInfo(&info); err != nil {
142
conmonInfo, ociruntimeInfo, err := r.defaultOCIRuntime.RuntimeInfo()
144
logrus.Errorf("Getting info on OCI runtime %s: %v", r.defaultOCIRuntime.Name(), err)
146
info.Conmon = conmonInfo
147
info.OCIRuntime = ociruntimeInfo
150
duration, err := util.ReadUptime()
152
return nil, fmt.Errorf("reading up time: %w", err)
160
hours: duration.Truncate(time.Hour).Hours(),
161
minutes: duration.Truncate(time.Minute).Minutes(),
162
seconds: duration.Truncate(time.Second).Seconds(),
165
// Could not find a humanize-formatter for time.Duration
166
var buffer bytes.Buffer
167
buffer.WriteString(fmt.Sprintf("%.0fh %.0fm %.2fs",
169
math.Mod(uptime.seconds, 3600)/60,
170
math.Mod(uptime.seconds, 60),
172
if int64(uptime.hours) > 0 {
173
buffer.WriteString(fmt.Sprintf(" (Approximately %.2f days)", uptime.hours/24))
175
info.Uptime = buffer.String()
180
func (r *Runtime) getContainerStoreInfo() (define.ContainerStore, error) {
181
var paused, running, stopped int
182
cs := define.ContainerStore{}
183
cons, err := r.GetAllContainers()
187
cs.Number = len(cons)
188
for _, con := range cons {
189
state, err := con.State()
191
if errors.Is(err, define.ErrNoSuchCtr) {
192
// container was probably removed
199
case define.ContainerStateRunning:
201
case define.ContainerStatePaused:
213
// top-level "store" info
214
func (r *Runtime) storeInfo() (*define.StoreInfo, error) {
215
// let's say storage driver in use, number of images, number of containers
216
configFile, err := storage.DefaultConfigFile()
220
images, err := r.store.Images()
222
return nil, fmt.Errorf("getting number of images: %w", err)
224
conInfo, err := r.getContainerStoreInfo()
228
imageInfo := define.ImageStore{Number: len(images)}
230
var grStats syscall.Statfs_t
231
if err := syscall.Statfs(r.store.GraphRoot(), &grStats); err != nil {
232
return nil, fmt.Errorf("unable to collect graph root usasge for %q: %w", r.store.GraphRoot(), err)
234
allocated := uint64(grStats.Bsize) * grStats.Blocks
235
info := define.StoreInfo{
236
ImageStore: imageInfo,
237
ImageCopyTmpDir: os.Getenv("TMPDIR"),
238
ContainerStore: conInfo,
239
GraphRoot: r.store.GraphRoot(),
240
GraphRootAllocated: allocated,
241
GraphRootUsed: allocated - (uint64(grStats.Bsize) * grStats.Bfree),
242
RunRoot: r.store.RunRoot(),
243
GraphDriverName: r.store.GraphDriverName(),
245
VolumePath: r.config.Engine.VolumePath,
246
ConfigFile: configFile,
247
TransientStore: r.store.TransientStore(),
250
graphOptions := map[string]interface{}{}
251
for _, o := range r.store.GraphOptions() {
252
split := strings.SplitN(o, "=", 2)
253
if strings.HasSuffix(split[0], "mount_program") {
254
ver, err := version.Program(split[1])
256
logrus.Warnf("Failed to retrieve program version for %s: %v", split[1], err)
258
program := map[string]interface{}{}
259
program["Executable"] = split[1]
260
program["Version"] = ver
261
program["Package"] = version.Package(split[1])
262
graphOptions[split[0]] = program
264
graphOptions[split[0]] = split[1]
267
info.GraphOptions = graphOptions
269
statusPairs, err := r.store.Status()
273
status := map[string]string{}
274
for _, pair := range statusPairs {
275
status[pair[0]] = pair[1]
277
info.GraphStatus = status
281
// GetHostDistributionInfo returns a map containing the host's distribution and version
282
func (r *Runtime) GetHostDistributionInfo() define.DistributionInfo {
283
// Populate values in case we cannot find the values
285
dist := define.DistributionInfo{
286
Distribution: "unknown",
289
f, err := os.Open("/etc/os-release")
295
l := bufio.NewScanner(f)
297
if strings.HasPrefix(l.Text(), "ID=") {
298
dist.Distribution = strings.Trim(strings.TrimPrefix(l.Text(), "ID="), "\"")
300
if strings.HasPrefix(l.Text(), "VARIANT_ID=") {
301
dist.Variant = strings.Trim(strings.TrimPrefix(l.Text(), "VARIANT_ID="), "\"")
303
if strings.HasPrefix(l.Text(), "VERSION_ID=") {
304
dist.Version = strings.Trim(strings.TrimPrefix(l.Text(), "VERSION_ID="), "\"")
306
if strings.HasPrefix(l.Text(), "VERSION_CODENAME=") {
307
dist.Codename = strings.Trim(strings.TrimPrefix(l.Text(), "VERSION_CODENAME="), "\"")