// 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" "fmt" "os" "path/filepath" "strings" "github.com/coreos/go-iptables/iptables" "github.com/hashicorp/go-getter" "github.com/talos-systems/go-cmd/pkg/cmd" "github.com/talos-systems/talos/pkg/machinery/constants" "github.com/talos-systems/talos/pkg/provision" ) func (p *provisioner) preflightChecks(ctx context.Context, request provision.ClusterRequest, options provision.Options, arch Arch) error { checkContext := preflightCheckContext{ request: request, options: options, arch: arch, } for _, check := range []func(ctx context.Context) error{ checkContext.verifyRoot, checkContext.checkKVM, checkContext.qemuExecutable, checkContext.checkFlashImages, checkContext.cniDirectories, checkContext.cniBundle, checkContext.checkIptables, } { if err := check(ctx); err != nil { return err } } return nil } type preflightCheckContext struct { request provision.ClusterRequest options provision.Options arch Arch } func (check *preflightCheckContext) verifyRoot(ctx context.Context) error { if os.Geteuid() != 0 { return fmt.Errorf("error: please run as root user (CNI requirement), we recommend running with `sudo -E`") } return nil } func (check *preflightCheckContext) checkKVM(ctx context.Context) error { f, err := os.OpenFile("/dev/kvm", os.O_RDWR, 0) if err != nil { return fmt.Errorf("error opening /dev/kvm, please make sure KVM support is enabled in Linux kernel: %w", err) } return f.Close() } func (check *preflightCheckContext) qemuExecutable(ctx context.Context) error { if _, err := cmd.Run(check.arch.QemuExecutable(), "--version"); err != nil { return fmt.Errorf("error running QEMU %q, please install QEMU with package manager: %w", check.arch.QemuExecutable(), err) } return nil } func (check *preflightCheckContext) checkFlashImages(ctx context.Context) error { for _, flashImage := range check.arch.PFlash(check.options.UEFIEnabled) { found := false for _, path := range flashImage.SourcePaths { _, err := os.Stat(path) if err == nil { found = true break } } if !found { return fmt.Errorf("the required flash image was not found in any of the expected paths for (%q), please install it with the package manager", flashImage.SourcePaths) } } return nil } func (check *preflightCheckContext) cniDirectories(ctx context.Context) error { cniDirs := append(check.request.Network.CNI.BinPath, check.request.Network.CNI.CacheDir, check.request.Network.CNI.ConfDir) for _, cniDir := range cniDirs { st, err := os.Stat(cniDir) if err != nil { if !os.IsNotExist(err) { return fmt.Errorf("error checking CNI directory %q: %w", cniDir, err) } fmt.Printf("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{ Ctx: ctx, Src: strings.ReplaceAll(check.request.Network.CNI.BundleURL, constants.ArchVariable, check.options.TargetArch), Dst: check.request.Network.CNI.BinPath[0], Pwd: pwd, Mode: getter.ClientModeDir, } fmt.Printf("downloading CNI bundle from %q to %q\n", client.Src, client.Dst) return client.Get() } func (check *preflightCheckContext) checkIptables(ctx context.Context) error { _, err := iptables.New() if err != nil { return fmt.Errorf("error accessing iptables: %w", err) } return nil }