diff --git a/mantle/kola/tests/ignition/qemufailure.go b/mantle/kola/tests/ignition/qemufailure.go index 681f2295a2..7208101c63 100644 --- a/mantle/kola/tests/ignition/qemufailure.go +++ b/mantle/kola/tests/ignition/qemufailure.go @@ -17,6 +17,9 @@ package ignition import ( "context" "fmt" + "os" + "os/exec" + "path" "time" "github.com/pkg/errors" @@ -28,6 +31,8 @@ import ( "github.com/coreos/coreos-assembler/mantle/platform/conf" ) +var console bool + func init() { register.RegisterTest(®ister.Test{ Name: "coreos.ignition.failure", @@ -37,6 +42,13 @@ func init() { Platforms: []string{"qemu"}, Tags: []string{"ignition"}, }) + register.RegisterTest(®ister.Test{ + Name: "coreos.unique.boot.failure", + ClusterSize: 0, + Description: "Verify boot fails if there are pre-existing boot filesystems.", + Platforms: []string{"qemu"}, + Run: runBootfsFailure, + }) } func runIgnitionFailure(c cluster.TestCluster) { @@ -45,6 +57,12 @@ func runIgnitionFailure(c cluster.TestCluster) { } } +func runBootfsFailure(c cluster.TestCluster) { + if err := bootfsFailure(c); err != nil { + c.Fatal(err.Error()) + } +} + func ignitionFailure(c cluster.TestCluster) error { // We can't create files in / due to the immutable bit OSTree creates, so // this is a convenient way to test Ignition failure. @@ -101,3 +119,104 @@ func ignitionFailure(c cluster.TestCluster) error { return nil } } + +// Attach a block device which has a pre-existing boot filesystem on it +func bootfsFailure(c cluster.TestCluster) error { + builder := platform.NewQemuBuilder() + // inserting log file for troubleshooting + // file located in coreos-assembler directory + builder.InheritConsole = console + if !console { + builder.ConsoleFile = "console.txt" + fmt.Println("Console log saved...") + } + + failConfig, err := conf.EmptyIgnition().Render(conf.FailWarnings) + if err != nil { + return errors.Wrapf(err, "creating empty config") + } + defer builder.Close() + builder.SetConfig(failConfig) + + // get current path and create tmp dir + fakeBoot := "fakeboot" + tempPath, err := builder.TempFile(fakeBoot) + if err != nil { + return err + } + pathName := tempPath.Name() + fmt.Printf("Temp path: %v\n", pathName) + lastElement := path.Base(pathName) + + createBoot, err := os.Create(lastElement) + if err != nil { + return err + } + fmt.Printf("createBoot: %v\n", createBoot.Name()) + + // Truncate the file to 1 gigabyte + const oneGB = 1 << 30 + err = createBoot.Truncate(oneGB) + if err != nil { + return err + } + + cmd := exec.Command("mkfs.ext4", "-L", "boot", createBoot.Name()) + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + c.Fatal(err) + } + + // BackingFormat: "raw" casues timeout + err = builder.AddDisk(&platform.Disk{ + BackingFile: kola.QEMUOptions.DiskImage, + // BackingFormat: "raw", + }) + if err != nil { + return err + } + err = builder.AddBootDisk(&platform.Disk{ + BackingFile: kola.QEMUOptions.DiskImage, + }) + + if err != nil { + return err + } + builder.MemoryMiB = 1024 + builder.Firmware = kola.QEMUOptions.Firmware + inst, err := builder.Exec() + if err != nil { + return err + } + defer inst.Destroy() + + ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute) + defer cancel() + + errchan := make(chan error) + go func() { + err := inst.WaitAll(ctx) + if err == nil { + err = fmt.Errorf("bootfs unexpectedly succeeded") + } else if err == platform.ErrInitramfsEmergency { + // The expected case + err = nil + } else { + err = errors.Wrapf(err, "expected initramfs emergency.target error") + } + errchan <- err + }() + + select { + case <-ctx.Done(): + if err := inst.Kill(); err != nil { + return errors.Wrapf(err, "failed to kill the vm instance") + } + return errors.Wrapf(ctx.Err(), "timed out waiting for initramfs error") + case err := <-errchan: + if err != nil { + return err + } + return nil + } +}