diff --git a/cmd/kola/options.go b/cmd/kola/options.go index ee7bf83d5..bd44c2e34 100644 --- a/cmd/kola/options.go +++ b/cmd/kola/options.go @@ -73,6 +73,9 @@ func init() { // general options sv(&outputDir, "output-dir", "", "Temporary output directory for test data and logs") sv(&kola.TorcxManifestFile, "torcx-manifest", "", "Path to a torcx manifest that should be made available to tests") + sv(&kola.DevcontainerURL, "devcontainer-url", "http://bincache.flatcar-linux.net/images/@ARCH@/@VERSION@", "URL to a dev container archive that should be made available to tests") + sv(&kola.DevcontainerFile, "devcontainer-file", "", "Path to a dev container archive that should be made available to tests as alternative to devcontainer-url, note that a working devcontainer-binhost-url is still needed") + sv(&kola.DevcontainerBinhostURL, "devcontainer-binhost-url", "http://bincache.flatcar-linux.net/boards/@ARCH@-usr/@VERSION@/pkgs", "URL to a binary host that the devcontainer test should use") root.PersistentFlags().StringVarP(&kolaPlatform, "platform", "p", "qemu", "VM platform: "+strings.Join(kolaPlatforms, ", ")) root.PersistentFlags().StringVarP(&kolaChannel, "channel", "", "stable", "Channel: "+strings.Join(kolaChannels, ", ")) root.PersistentFlags().StringVarP(&kolaOffering, "offering", "", "basic", "Offering: "+strings.Join(kolaOfferings, ", ")) diff --git a/kola/harness.go b/kola/harness.go index 2a6b61905..82ff02f64 100644 --- a/kola/harness.go +++ b/kola/harness.go @@ -73,9 +73,12 @@ var ( EquinixMetalOptions = equinixmetalapi.Options{Options: &Options} // glue to set platform options from main QEMUOptions = qemu.Options{Options: &Options} // glue to set platform options from main - TestParallelism int //glue var to set test parallelism from main - TAPFile string // if not "", write TAP results here - TorcxManifestFile string // torcx manifest to expose to tests, if set + TestParallelism int //glue var to set test parallelism from main + TAPFile string // if not "", write TAP results here + TorcxManifestFile string // torcx manifest to expose to tests, if set + DevcontainerURL string // dev container to expose to tests, if set + DevcontainerBinhostURL string // dev container binhost URL to use in the devcontainer test + DevcontainerFile string // dev container path to expose to tests, if set // TorcxManifest is the unmarshalled torcx manifest file. It is available for // tests to access via `kola.TorcxManifest`. It will be nil if there was no // manifest given to kola. @@ -625,7 +628,7 @@ func runTest(h *harness.H, t *register.Test, pltfrm string, flight platform.Flig // drop kolet binary on machines if t.NativeFuncs != nil { - scpKolet(tcluster, architecture(pltfrm)) + ScpKolet(tcluster, architecture(pltfrm)) } defer func() { @@ -676,8 +679,8 @@ func findExecDir() string { return filepath.Dir(p) } -// scpKolet searches for a kolet binary and copies it to the machine. -func scpKolet(c cluster.TestCluster, mArch string) { +// ScpKolet searches for a kolet binary and copies it to the machine. +func ScpKolet(c cluster.TestCluster, mArch string) { for _, d := range []string{ ".", findExecDir(), diff --git a/kola/tests/devcontainer/devcontainer.go b/kola/tests/devcontainer/devcontainer.go index 454020a7c..e89f37de0 100644 --- a/kola/tests/devcontainer/devcontainer.go +++ b/kola/tests/devcontainer/devcontainer.go @@ -18,18 +18,23 @@ import ( "encoding/base64" "errors" "fmt" + "os" "strings" "text/template" + "time" "unicode" "github.com/coreos/go-semver/semver" + "github.com/flatcar/mantle/kola" "github.com/flatcar/mantle/kola/cluster" "github.com/flatcar/mantle/kola/register" "github.com/flatcar/mantle/platform" "github.com/flatcar/mantle/platform/conf" + "github.com/flatcar/mantle/platform/local" "github.com/flatcar/mantle/platform/machine/qemu" "github.com/flatcar/mantle/platform/machine/unprivqemu" + "github.com/flatcar/mantle/util" ) // Both template parameters may contain @ARCH@ and @VERSION@ @@ -50,11 +55,6 @@ func trimLeftSpace(contents string) string { } var ( - defaultScriptTemplateParameters = scriptTemplateParameters{ - BinhostURLTemplate: "http://bincache.flatcar-linux.net/boards/@ARCH@-usr/@VERSION@/pkgs", - ImageDirectoryURLTemplate: "http://bincache.flatcar-linux.net/images/@ARCH@/@VERSION@", - } - devContainerScriptTemplate = trimLeftSpace(` #!/bin/bash @@ -215,6 +215,9 @@ func init() { Platforms: []string{"qemu", "qemu-unpriv"}, Distros: []string{"cl"}, MinVersion: semver.Version{Major: 2592}, + NativeFuncs: map[string]func() error{ + "Http": Serve, + }, }) register.Register(®ister.Test{ Name: "devcontainer.docker", @@ -225,18 +228,32 @@ func init() { Distros: []string{"cl"}, // TODO: Revisit this flag when updating SELinux policies. Flags: []register.Flag{register.NoEnableSelinux}, + NativeFuncs: map[string]func() error{ + "Http": Serve, + }, }) } func withSystemdNspawn(c cluster.TestCluster) { - runDevContainerTest(c, defaultScriptTemplateParameters, systemdNspawnScriptBody) + runDevContainerTest(c, systemdNspawnScriptBody) } func withDocker(c cluster.TestCluster) { - runDevContainerTest(c, defaultScriptTemplateParameters, dockerScriptBody) + runDevContainerTest(c, dockerScriptBody) } -func runDevContainerTest(c cluster.TestCluster, scriptParameters scriptTemplateParameters, scriptBody string) { +func runDevContainerTest(c cluster.TestCluster, scriptBody string) { + devcontainerURL := kola.DevcontainerURL + if kola.DevcontainerFile != "" { + // This URL is deterministic as it runs on the started machine. + devcontainerURL = "http://localhost:8080" + } + + scriptParameters := scriptTemplateParameters{ + BinhostURLTemplate: kola.DevcontainerBinhostURL, + ImageDirectoryURLTemplate: devcontainerURL, + } + userdata, err := prepareUserData(scriptParameters, scriptBody) if err != nil { c.Fatalf("preparing user data failed: %v", err) @@ -245,6 +262,11 @@ func runDevContainerTest(c cluster.TestCluster, scriptParameters scriptTemplateP if err != nil { c.Fatalf("creating a machine failed: %v", err) } + + if kola.DevcontainerFile != "" { + configureHTTPServer(c, machine) + } + if _, err := c.SSH(machine, "/home/core/main-script"); err != nil { c.Fatalf("main script failed: %v", err) } @@ -297,3 +319,33 @@ func newMachineWithLargeDisk(c cluster.TestCluster, userData *conf.UserData) (pl } return nil, errors.New("unknown cluster type, this test should only be running on qemu or qemu-unpriv platforms") } + +func Serve() error { + httpServer := local.SimpleHTTP{} + return httpServer.Serve() +} + +func configureHTTPServer(c cluster.TestCluster, srv platform.Machine) { + // manually copy Kolet on the host, as the initial size cluster is 0. + kola.ScpKolet(c, strings.SplitN(kola.QEMUOptions.Board, "-", 2)[0]) + + in, err := os.Open(kola.DevcontainerFile) + if err != nil { + c.Fatalf("opening dev container file: %v", err) + } + + defer in.Close() + + if err := platform.InstallFile(in, srv, "/var/www/flatcar_developer_container.bin.bz2"); err != nil { + c.Fatalf("copying dev container to HTTP server: %v", err) + } + + c.MustSSH(srv, fmt.Sprintf("sudo systemd-run --quiet ./kolet run %s Http", c.H.Name())) + + if err := util.WaitUntilReady(60*time.Second, 5*time.Second, func() (bool, error) { + _, _, err := srv.SSH(fmt.Sprintf("curl %s:8080", srv.PrivateIP())) + return err == nil, nil + }); err != nil { + c.Fatal("timed out waiting for http server to become active") + } +} diff --git a/platform/local/http.go b/platform/local/http.go new file mode 100644 index 000000000..526e8b143 --- /dev/null +++ b/platform/local/http.go @@ -0,0 +1,15 @@ +// Copyright The Mantle Authors +// SPDX-License-Identifier: Apache-2.0 + +package local + +import ( + "net/http" +) + +// SimpleHTTP provides a single http server. +type SimpleHTTP struct{} + +func (s *SimpleHTTP) Serve() error { + return http.ListenAndServe(":8080", http.FileServer(http.Dir("/var/www"))) +}