// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. package qemu import ( "context" "errors" "fmt" "io/fs" "os" "os/exec" "path/filepath" "runtime" "strings" "github.com/coreos/go-iptables/iptables" "github.com/hashicorp/go-getter/v2" "github.com/siderolabs/talos/pkg/machinery/constants" ) func (check *preflightCheckContext) verifyPlatformSpecific(ctx context.Context) error { for _, check := range []func(ctx context.Context) error{ check.cniDirectories, check.cniBundle, check.checkIptables, check.swtpmExecutable, check.checkKVM, } { if err := check(ctx); err != nil { return err } } return nil } func (check *preflightCheckContext) cniDirectories(ctx context.Context) error { cniDirs := append([]string{}, check.request.Network.CNI.BinPath...) cniDirs = append(cniDirs, check.request.Network.CNI.CacheDir, check.request.Network.CNI.ConfDir) for _, cniDir := range cniDirs { st, err := os.Stat(cniDir) if err != nil { if !errors.Is(err, fs.ErrNotExist) { return fmt.Errorf("error checking CNI directory %q: %w", cniDir, err) } fmt.Fprintf(check.options.LogWriter, "creating %q\n", cniDir) err = os.MkdirAll(cniDir, 0o777) if err != nil { return err } continue } if !st.IsDir() { return fmt.Errorf("CNI path %q exists, but it's not a directory", cniDir) } } return nil } func (check *preflightCheckContext) cniBundle(ctx context.Context) error { var missing bool requiredCNIPlugins := []string{"bridge", "firewall", "static", "tc-redirect-tap"} for _, cniPlugin := range requiredCNIPlugins { missing = true for _, binPath := range check.request.Network.CNI.BinPath { _, err := os.Stat(filepath.Join(binPath, cniPlugin)) if err == nil { missing = false break } } if missing { break } } if !missing { return nil } if check.request.Network.CNI.BundleURL == "" { return fmt.Errorf("error: required CNI plugins %q were not found in %q", requiredCNIPlugins, check.request.Network.CNI.BinPath) } pwd, err := os.Getwd() if err != nil { return err } client := getter.Client{} src := strings.ReplaceAll(check.request.Network.CNI.BundleURL, constants.ArchVariable, runtime.GOARCH) dst := check.request.Network.CNI.BinPath[0] fmt.Fprintf(check.options.LogWriter, "downloading CNI bundle from %q to %q\n", src, dst) _, err = client.Get(ctx, &getter.Request{ Src: src, Dst: dst, Pwd: pwd, GetMode: getter.ModeDir, }) return err } func (check *preflightCheckContext) checkIptables(ctx context.Context) error { _, err := iptables.New() if err != nil { return fmt.Errorf("error accessing iptables: %w", err) } return nil } func (check *preflightCheckContext) swtpmExecutable(ctx context.Context) error { if check.options.TPM1_2Enabled || check.options.TPM2Enabled { if _, err := exec.LookPath("swtpm"); err != nil { return fmt.Errorf("swtpm not found in PATH, please install swtpm-tools with the package manager: %w", err) } } return nil } func (check *preflightCheckContext) checkKVM(ctx context.Context) error { err := checkKVM() if err != nil { fmt.Printf("error opening /dev/kvm, please make sure KVM support is enabled in Linux kernel: %s\n", err) fmt.Println("running without KVM") } return nil } func checkKVM() error { f, err := os.OpenFile("/dev/kvm", os.O_RDWR, 0) if err != nil { return err } return f.Close() }