talos

Форк
0
203 строки · 4.9 Кб
1
// This Source Code Form is subject to the terms of the Mozilla Public
2
// License, v. 2.0. If a copy of the MPL was not distributed with this
3
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
4

5
package qemu
6

7
import (
8
	"context"
9
	"errors"
10
	"fmt"
11
	"os"
12
	"os/exec"
13
	"path/filepath"
14
	"runtime"
15
	"strings"
16

17
	"github.com/coreos/go-iptables/iptables"
18
	"github.com/hashicorp/go-getter/v2"
19

20
	"github.com/siderolabs/talos/pkg/machinery/constants"
21
	"github.com/siderolabs/talos/pkg/provision"
22
)
23

24
func (p *provisioner) preflightChecks(ctx context.Context, request provision.ClusterRequest, options provision.Options, arch Arch) error {
25
	checkContext := preflightCheckContext{
26
		request: request,
27
		options: options,
28
		arch:    arch,
29
	}
30

31
	for _, check := range []func(ctx context.Context) error{
32
		checkContext.verifyRoot,
33
		checkContext.checkKVM,
34
		checkContext.qemuExecutable,
35
		checkContext.checkFlashImages,
36
		checkContext.swtpmExecutable,
37
		checkContext.cniDirectories,
38
		checkContext.cniBundle,
39
		checkContext.checkIptables,
40
	} {
41
		if err := check(ctx); err != nil {
42
			return err
43
		}
44
	}
45

46
	return nil
47
}
48

49
type preflightCheckContext struct {
50
	request provision.ClusterRequest
51
	options provision.Options
52
	arch    Arch
53
}
54

55
func (check *preflightCheckContext) verifyRoot(ctx context.Context) error {
56
	if os.Geteuid() != 0 {
57
		return errors.New("error: please run as root user (CNI requirement), we recommend running with `sudo -E`")
58
	}
59

60
	return nil
61
}
62

63
func (check *preflightCheckContext) checkKVM(ctx context.Context) error {
64
	f, err := os.OpenFile("/dev/kvm", os.O_RDWR, 0)
65
	if err != nil {
66
		return fmt.Errorf("error opening /dev/kvm, please make sure KVM support is enabled in Linux kernel: %w", err)
67
	}
68

69
	return f.Close()
70
}
71

72
func (check *preflightCheckContext) qemuExecutable(ctx context.Context) error {
73
	if check.arch.QemuExecutable() == "" {
74
		return fmt.Errorf("QEMU executable (qemu-system-%s or qemu-kvm) not found, please install QEMU with package manager", check.arch.QemuArch())
75
	}
76

77
	return nil
78
}
79

80
func (check *preflightCheckContext) checkFlashImages(ctx context.Context) error {
81
	for _, flashImage := range check.arch.PFlash(check.options.UEFIEnabled, check.options.ExtraUEFISearchPaths) {
82
		if len(flashImage.SourcePaths) == 0 {
83
			continue
84
		}
85

86
		found := false
87

88
		for _, path := range flashImage.SourcePaths {
89
			_, err := os.Stat(path)
90
			if err == nil {
91
				found = true
92

93
				break
94
			}
95
		}
96

97
		if !found {
98
			return fmt.Errorf("the required flash image was not found in any of the expected paths for (%q), "+
99
				"please install it with the package manager or specify --extra-uefi-search-paths", flashImage.SourcePaths)
100
		}
101
	}
102

103
	return nil
104
}
105

106
func (check *preflightCheckContext) swtpmExecutable(ctx context.Context) error {
107
	if check.options.TPM2Enabled {
108
		if _, err := exec.LookPath("swtpm"); err != nil {
109
			return fmt.Errorf("swtpm not found in PATH, please install swtpm-tools with the package manager: %w", err)
110
		}
111
	}
112

113
	return nil
114
}
115

116
func (check *preflightCheckContext) cniDirectories(ctx context.Context) error {
117
	cniDirs := append([]string{}, check.request.Network.CNI.BinPath...)
118
	cniDirs = append(cniDirs, check.request.Network.CNI.CacheDir, check.request.Network.CNI.ConfDir)
119

120
	for _, cniDir := range cniDirs {
121
		st, err := os.Stat(cniDir)
122
		if err != nil {
123
			if !os.IsNotExist(err) {
124
				return fmt.Errorf("error checking CNI directory %q: %w", cniDir, err)
125
			}
126

127
			fmt.Fprintf(os.Stderr, "creating %q\n", cniDir)
128

129
			err = os.MkdirAll(cniDir, 0o777)
130
			if err != nil {
131
				return err
132
			}
133

134
			continue
135
		}
136

137
		if !st.IsDir() {
138
			return fmt.Errorf("CNI path %q exists, but it's not a directory", cniDir)
139
		}
140
	}
141

142
	return nil
143
}
144

145
func (check *preflightCheckContext) cniBundle(ctx context.Context) error {
146
	var missing bool
147

148
	requiredCNIPlugins := []string{"bridge", "firewall", "static", "tc-redirect-tap"}
149

150
	for _, cniPlugin := range requiredCNIPlugins {
151
		missing = true
152

153
		for _, binPath := range check.request.Network.CNI.BinPath {
154
			_, err := os.Stat(filepath.Join(binPath, cniPlugin))
155
			if err == nil {
156
				missing = false
157

158
				break
159
			}
160
		}
161

162
		if missing {
163
			break
164
		}
165
	}
166

167
	if !missing {
168
		return nil
169
	}
170

171
	if check.request.Network.CNI.BundleURL == "" {
172
		return fmt.Errorf("error: required CNI plugins %q were not found in %q", requiredCNIPlugins, check.request.Network.CNI.BinPath)
173
	}
174

175
	pwd, err := os.Getwd()
176
	if err != nil {
177
		return err
178
	}
179

180
	client := getter.Client{}
181
	src := strings.ReplaceAll(check.request.Network.CNI.BundleURL, constants.ArchVariable, runtime.GOARCH)
182
	dst := check.request.Network.CNI.BinPath[0]
183

184
	fmt.Fprintf(os.Stderr, "downloading CNI bundle from %q to %q\n", src, dst)
185

186
	_, err = client.Get(ctx, &getter.Request{
187
		Src:     src,
188
		Dst:     dst,
189
		Pwd:     pwd,
190
		GetMode: getter.ModeDir,
191
	})
192

193
	return err
194
}
195

196
func (check *preflightCheckContext) checkIptables(ctx context.Context) error {
197
	_, err := iptables.New()
198
	if err != nil {
199
		return fmt.Errorf("error accessing iptables: %w", err)
200
	}
201

202
	return nil
203
}
204

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

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

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

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