aboutsummaryrefslogtreecommitdiff
path: root/libpod/info_linux.go
blob: 801dcdb43695ff520e553db5780df78f40908830 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
package libpod

import (
	"bufio"
	"fmt"
	"math"
	"os"
	"os/exec"
	"strconv"
	"strings"

	"github.com/containers/common/pkg/apparmor"
	"github.com/containers/common/pkg/cgroups"
	"github.com/containers/common/pkg/seccomp"
	"github.com/containers/podman/v4/libpod/define"
	"github.com/containers/podman/v4/pkg/rootless"
	"github.com/opencontainers/selinux/go-selinux"
	"github.com/sirupsen/logrus"
)

func (r *Runtime) setPlatformHostInfo(info *define.HostInfo) error {
	seccompProfilePath, err := DefaultSeccompPath()
	if err != nil {
		return fmt.Errorf("error getting Seccomp profile path: %w", err)
	}

	// Cgroups version
	unified, err := cgroups.IsCgroup2UnifiedMode()
	if err != nil {
		return fmt.Errorf("error reading cgroups mode: %w", err)
	}

	// Get Map of all available controllers
	availableControllers, err := cgroups.GetAvailableControllers(nil, unified)
	if err != nil {
		return fmt.Errorf("error getting available cgroup controllers: %w", err)
	}

	info.CgroupManager = r.config.Engine.CgroupManager
	info.CgroupControllers = availableControllers
	info.IDMappings = define.IDMappings{}
	info.Security = define.SecurityInfo{
		AppArmorEnabled:     apparmor.IsEnabled(),
		DefaultCapabilities: strings.Join(r.config.Containers.DefaultCapabilities, ","),
		Rootless:            rootless.IsRootless(),
		SECCOMPEnabled:      seccomp.IsEnabled(),
		SECCOMPProfilePath:  seccompProfilePath,
		SELinuxEnabled:      selinux.GetEnabled(),
	}
	info.Slirp4NetNS = define.SlirpInfo{}

	cgroupVersion := "v1"
	if unified {
		cgroupVersion = "v2"
	}
	info.CgroupsVersion = cgroupVersion

	slirp4netnsPath := r.config.Engine.NetworkCmdPath
	if slirp4netnsPath == "" {
		slirp4netnsPath, _ = exec.LookPath("slirp4netns")
	}
	if slirp4netnsPath != "" {
		version, err := programVersion(slirp4netnsPath)
		if err != nil {
			logrus.Warnf("Failed to retrieve program version for %s: %v", slirp4netnsPath, err)
		}
		program := define.SlirpInfo{
			Executable: slirp4netnsPath,
			Package:    packageVersion(slirp4netnsPath),
			Version:    version,
		}
		info.Slirp4NetNS = program
	}

	if rootless.IsRootless() {
		uidmappings, err := rootless.ReadMappingsProc("/proc/self/uid_map")
		if err != nil {
			return fmt.Errorf("error reading uid mappings: %w", err)
		}
		gidmappings, err := rootless.ReadMappingsProc("/proc/self/gid_map")
		if err != nil {
			return fmt.Errorf("error reading gid mappings: %w", err)
		}
		idmappings := define.IDMappings{
			GIDMap: gidmappings,
			UIDMap: uidmappings,
		}
		info.IDMappings = idmappings
	}

	return nil
}

func statToPercent(stats []string) (*define.CPUUsage, error) {
	userTotal, err := strconv.ParseFloat(stats[1], 64)
	if err != nil {
		return nil, fmt.Errorf("unable to parse user value %q: %w", stats[1], err)
	}
	systemTotal, err := strconv.ParseFloat(stats[3], 64)
	if err != nil {
		return nil, fmt.Errorf("unable to parse system value %q: %w", stats[3], err)
	}
	idleTotal, err := strconv.ParseFloat(stats[4], 64)
	if err != nil {
		return nil, fmt.Errorf("unable to parse idle value %q: %w", stats[4], err)
	}
	total := userTotal + systemTotal + idleTotal
	s := define.CPUUsage{
		UserPercent:   math.Round((userTotal/total*100)*100) / 100,
		SystemPercent: math.Round((systemTotal/total*100)*100) / 100,
		IdlePercent:   math.Round((idleTotal/total*100)*100) / 100,
	}
	return &s, nil
}

// getCPUUtilization Returns a CPUUsage object that summarizes CPU
// usage for userspace, system, and idle time.
func getCPUUtilization() (*define.CPUUsage, error) {
	f, err := os.Open("/proc/stat")
	if err != nil {
		return nil, err
	}
	defer f.Close()
	scanner := bufio.NewScanner(f)
	// Read first line of /proc/stat that has entries for system ("cpu" line)
	for scanner.Scan() {
		break
	}
	// column 1 is user, column 3 is system, column 4 is idle
	stats := strings.Fields(scanner.Text())
	return statToPercent(stats)
}