podman

Форк
0
/
info.go 
311 строк · 8.4 Кб
1
//go:build !remote
2

3
package libpod
4

5
import (
6
	"bufio"
7
	"bytes"
8
	"errors"
9
	"fmt"
10
	"math"
11
	"os"
12
	"runtime"
13
	"strings"
14
	"syscall"
15
	"time"
16

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"
27
)
28

29
// Info returns the store and host information
30
func (r *Runtime) info() (*define.Info, error) {
31
	info := define.Info{}
32
	versionInfo, err := define.GetVersion()
33
	if err != nil {
34
		return nil, fmt.Errorf("getting version info: %w", err)
35
	}
36
	info.Version = versionInfo
37
	// get host information
38
	hostInfo, err := r.hostInfo()
39
	if err != nil {
40
		return nil, fmt.Errorf("getting host info: %w", err)
41
	}
42
	info.Host = hostInfo
43

44
	// get store information
45
	storeInfo, err := r.storeInfo()
46
	if err != nil {
47
		return nil, fmt.Errorf("getting store info: %w", err)
48
	}
49
	info.Store = storeInfo
50
	registries := make(map[string]interface{})
51

52
	sys := r.SystemContext()
53
	data, err := sysregistriesv2.GetRegistries(sys)
54
	if err != nil {
55
		return nil, fmt.Errorf("getting registries: %w", err)
56
	}
57
	for _, reg := range data {
58
		registries[reg.Prefix] = reg
59
	}
60
	regs, err := sysregistriesv2.UnqualifiedSearchRegistries(sys)
61
	if err != nil {
62
		return nil, fmt.Errorf("getting registries: %w", err)
63
	}
64
	if len(regs) > 0 {
65
		registries["search"] = regs
66
	}
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)
72
	}
73
	info.Plugins.Volume = volumePlugins
74
	info.Plugins.Network = r.network.Drivers()
75
	info.Plugins.Log = logDrivers
76

77
	info.Registries = registries
78
	return &info, nil
79
}
80

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()
85
	if err != nil {
86
		return nil, fmt.Errorf("reading memory info: %w", err)
87
	}
88

89
	hostDistributionInfo := r.GetHostDistributionInfo()
90

91
	kv, err := util.ReadKernelVersion()
92
	if err != nil {
93
		return nil, fmt.Errorf("reading kernel version: %w", err)
94
	}
95

96
	host, err := os.Hostname()
97
	if err != nil {
98
		return nil, fmt.Errorf("getting hostname: %w", err)
99
	}
100

101
	cpuUtil, err := getCPUUtilization()
102
	if err != nil {
103
		return nil, err
104
	}
105

106
	locksFree, err := r.lockManager.AvailableLocks()
107
	if err != nil {
108
		return nil, fmt.Errorf("getting free locks: %w", err)
109
	}
110

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,
122
		Hostname:           host,
123
		Kernel:             kv,
124
		MemFree:            mi.MemFree,
125
		MemTotal:           mi.MemTotal,
126
		NetworkBackend:     r.config.Network.NetworkBackend,
127
		NetworkBackendInfo: r.network.NetworkInfo(),
128
		OS:                 runtime.GOOS,
129
		RootlessNetworkCmd: r.config.Network.DefaultRootlessNetworkCmd,
130
		SwapFree:           mi.SwapFree,
131
		SwapTotal:          mi.SwapTotal,
132
	}
133
	platform := parse.DefaultPlatform()
134
	pArr := strings.Split(platform, "/")
135
	if len(pArr) == 3 {
136
		info.Variant = pArr[2]
137
	}
138
	if err := r.setPlatformHostInfo(&info); err != nil {
139
		return nil, err
140
	}
141

142
	conmonInfo, ociruntimeInfo, err := r.defaultOCIRuntime.RuntimeInfo()
143
	if err != nil {
144
		logrus.Errorf("Getting info on OCI runtime %s: %v", r.defaultOCIRuntime.Name(), err)
145
	} else {
146
		info.Conmon = conmonInfo
147
		info.OCIRuntime = ociruntimeInfo
148
	}
149

150
	duration, err := util.ReadUptime()
151
	if err != nil {
152
		return nil, fmt.Errorf("reading up time: %w", err)
153
	}
154

155
	uptime := struct {
156
		hours   float64
157
		minutes float64
158
		seconds float64
159
	}{
160
		hours:   duration.Truncate(time.Hour).Hours(),
161
		minutes: duration.Truncate(time.Minute).Minutes(),
162
		seconds: duration.Truncate(time.Second).Seconds(),
163
	}
164

165
	// Could not find a humanize-formatter for time.Duration
166
	var buffer bytes.Buffer
167
	buffer.WriteString(fmt.Sprintf("%.0fh %.0fm %.2fs",
168
		uptime.hours,
169
		math.Mod(uptime.seconds, 3600)/60,
170
		math.Mod(uptime.seconds, 60),
171
	))
172
	if int64(uptime.hours) > 0 {
173
		buffer.WriteString(fmt.Sprintf(" (Approximately %.2f days)", uptime.hours/24))
174
	}
175
	info.Uptime = buffer.String()
176

177
	return &info, nil
178
}
179

180
func (r *Runtime) getContainerStoreInfo() (define.ContainerStore, error) {
181
	var paused, running, stopped int
182
	cs := define.ContainerStore{}
183
	cons, err := r.GetAllContainers()
184
	if err != nil {
185
		return cs, err
186
	}
187
	cs.Number = len(cons)
188
	for _, con := range cons {
189
		state, err := con.State()
190
		if err != nil {
191
			if errors.Is(err, define.ErrNoSuchCtr) {
192
				// container was probably removed
193
				cs.Number--
194
				continue
195
			}
196
			return cs, err
197
		}
198
		switch state {
199
		case define.ContainerStateRunning:
200
			running++
201
		case define.ContainerStatePaused:
202
			paused++
203
		default:
204
			stopped++
205
		}
206
	}
207
	cs.Paused = paused
208
	cs.Stopped = stopped
209
	cs.Running = running
210
	return cs, nil
211
}
212

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()
217
	if err != nil {
218
		return nil, err
219
	}
220
	images, err := r.store.Images()
221
	if err != nil {
222
		return nil, fmt.Errorf("getting number of images: %w", err)
223
	}
224
	conInfo, err := r.getContainerStoreInfo()
225
	if err != nil {
226
		return nil, err
227
	}
228
	imageInfo := define.ImageStore{Number: len(images)}
229

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)
233
	}
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(),
244
		GraphOptions:       nil,
245
		VolumePath:         r.config.Engine.VolumePath,
246
		ConfigFile:         configFile,
247
		TransientStore:     r.store.TransientStore(),
248
	}
249

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])
255
			if err != nil {
256
				logrus.Warnf("Failed to retrieve program version for %s: %v", split[1], err)
257
			}
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
263
		} else {
264
			graphOptions[split[0]] = split[1]
265
		}
266
	}
267
	info.GraphOptions = graphOptions
268

269
	statusPairs, err := r.store.Status()
270
	if err != nil {
271
		return nil, err
272
	}
273
	status := map[string]string{}
274
	for _, pair := range statusPairs {
275
		status[pair[0]] = pair[1]
276
	}
277
	info.GraphStatus = status
278
	return &info, nil
279
}
280

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
284
	// or the file
285
	dist := define.DistributionInfo{
286
		Distribution: "unknown",
287
		Version:      "unknown",
288
	}
289
	f, err := os.Open("/etc/os-release")
290
	if err != nil {
291
		return dist
292
	}
293
	defer f.Close()
294

295
	l := bufio.NewScanner(f)
296
	for l.Scan() {
297
		if strings.HasPrefix(l.Text(), "ID=") {
298
			dist.Distribution = strings.Trim(strings.TrimPrefix(l.Text(), "ID="), "\"")
299
		}
300
		if strings.HasPrefix(l.Text(), "VARIANT_ID=") {
301
			dist.Variant = strings.Trim(strings.TrimPrefix(l.Text(), "VARIANT_ID="), "\"")
302
		}
303
		if strings.HasPrefix(l.Text(), "VERSION_ID=") {
304
			dist.Version = strings.Trim(strings.TrimPrefix(l.Text(), "VERSION_ID="), "\"")
305
		}
306
		if strings.HasPrefix(l.Text(), "VERSION_CODENAME=") {
307
			dist.Codename = strings.Trim(strings.TrimPrefix(l.Text(), "VERSION_CODENAME="), "\"")
308
		}
309
	}
310
	return dist
311
}
312

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.