@@ -6,24 +6,34 @@ import (
66 "io"
77 "os"
88 "path/filepath"
9- "strconv"
109 "strings"
1110 "time"
1211
1312 "github.com/coreos/coreos-assembler/mantle/kola"
1413 "github.com/coreos/coreos-assembler/mantle/kola/cluster"
1514 "github.com/coreos/coreos-assembler/mantle/kola/register"
16- "github.com/coreos/coreos-assembler/mantle/platform"
17- "github.com/coreos/coreos-assembler/mantle/platform/conf"
18- "github.com/coreos/coreos-assembler/mantle/platform/machine/qemu"
19- coreosarch "github.com/coreos/stream-metadata-go/arch"
2015 "github.com/pkg/errors"
2116)
2217
2318const (
2419 installTimeoutMins = 12
20+
21+ // defaultQemuHostIPv4 is documented in `man qemu-kvm`, under the `-netdev` option
22+ defaultQemuHostIPv4 = "10.0.2.2"
2523)
2624
25+ // This object gets serialized to YAML and fed to coreos-installer:
26+ // https://coreos.github.io/coreos-installer/customizing-install/#config-file-format
27+ type CoreosInstallerConfig struct {
28+ ImageURL string `yaml:"image-url,omitempty"`
29+ IgnitionFile string `yaml:"ignition-file,omitempty"`
30+ Insecure bool `yaml:"insecure,omitempty"`
31+ AppendKargs []string `yaml:"append-karg,omitempty"`
32+ CopyNetwork bool `yaml:"copy-network,omitempty"`
33+ DestDevice string `yaml:"dest-device,omitempty"`
34+ Console []string `yaml:"console,omitempty"`
35+ }
36+
2737type IsoTestOpts struct {
2838 // Flags().BoolVarP(&instInsecure, "inst-insecure", "S", false, "Do not verify signature on metal image")
2939 instInsecure bool
@@ -62,114 +72,7 @@ func isoTest(name string, run func(c cluster.TestCluster), arch []string) *regis
6272 }
6373}
6474
65- func newBaseQemuBuilder (opts IsoTestOpts , outdir string ) (* platform.QemuBuilder , error ) {
66- builder := qemu .NewMetalQemuBuilderDefault ()
67- if opts .enableUefiSecure {
68- builder .Firmware = "uefi-secure"
69- } else if opts .enableUefi {
70- builder .Firmware = "uefi"
71- }
72-
73- if err := os .MkdirAll (outdir , 0755 ); err != nil {
74- return nil , err
75- }
76-
77- builder .InheritConsole = opts .console
78- if ! opts .console {
79- builder .ConsoleFile = filepath .Join (outdir , "console.txt" )
80- }
81-
82- if kola .QEMUOptions .Memory != "" {
83- parsedMem , err := strconv .ParseInt (kola .QEMUOptions .Memory , 10 , 32 )
84- if err != nil {
85- return nil , err
86- }
87- builder .MemoryMiB = int (parsedMem )
88- }
89-
90- // increase the memory for pxe tests with appended rootfs in the initrd
91- // we were bumping up into the 4GiB limit in RHCOS/c9s
92- // pxe-offline-install.rootfs-appended.bios tests
93- if opts .pxeAppendRootfs && builder .MemoryMiB < 5120 {
94- builder .MemoryMiB = 5120
95- }
96-
97- return builder , nil
98- }
99-
100- func newQemuBuilder (opts IsoTestOpts , outdir string ) (* platform.QemuBuilder , * conf.Conf , error ) {
101- builder , err := newBaseQemuBuilder (opts , outdir )
102- if err != nil {
103- return nil , nil , err
104- }
105-
106- config , err := conf .EmptyIgnition ().Render (conf .FailWarnings )
107- if err != nil {
108- return nil , nil , err
109- }
110-
111- err = forwardJournal (outdir , builder , config )
112- if err != nil {
113- return nil , nil , err
114- }
115-
116- return builder , config , nil
117- }
118-
119- func forwardJournal (outdir string , builder * platform.QemuBuilder , config * conf.Conf ) error {
120- journalPipe , err := builder .VirtioJournal (config , "" )
121- if err != nil {
122- return err
123- }
124- journalOut , err := os .OpenFile (filepath .Join (outdir , "journal.txt" ), os .O_WRONLY | os .O_CREATE , 0644 )
125- if err != nil {
126- return err
127- }
128-
129- go func () {
130- _ , err := io .Copy (journalOut , journalPipe )
131- if err != nil && err != io .EOF {
132- fmt .Printf ("error copying journal: %v\n " , err )
133- }
134- }()
135-
136- return nil
137- }
138-
139- func newQemuBuilderWithDisk (opts IsoTestOpts , outdir string ) (* platform.QemuBuilder , * conf.Conf , error ) {
140- builder , config , err := newQemuBuilder (opts , outdir )
141-
142- if err != nil {
143- return nil , nil , err
144- }
145-
146- sectorSize := 0
147- if opts .enable4k {
148- sectorSize = 4096
149- }
150-
151- disk := platform.Disk {
152- Size : "12G" , // Arbitrary
153- SectorSize : sectorSize ,
154- MultiPathDisk : opts .enableMultipath ,
155- }
156-
157- //TBD: see if we can remove this and just use AddDisk and inject bootindex during startup
158- if coreosarch .CurrentRpmArch () == "s390x" || coreosarch .CurrentRpmArch () == "aarch64" {
159- // s390x and aarch64 need to use bootindex as they don't support boot once
160- if err := builder .AddDisk (& disk ); err != nil {
161- return nil , nil , err
162- }
163- } else {
164- if err := builder .AddPrimaryDisk (& disk ); err != nil {
165- return nil , nil , err
166- }
167- }
168-
169- return builder , config , nil
170- }
171-
172- func CheckTestOutput (output * os.File , expected []string ) error {
75+ func checkTestOutput (output * os.File , expected []string ) error {
17376 reader := bufio .NewReader (output )
17477 for _ , exp := range expected {
17578 line , err := reader .ReadString ('\n' )
@@ -192,8 +95,11 @@ func CheckTestOutput(output *os.File, expected []string) error {
19295 return nil
19396}
19497
195- func EnsureLiveArtifactsExist () error {
196- if kola .CosaBuild .Meta .BuildArtifacts .LiveIso == nil || kola .CosaBuild .Meta .BuildArtifacts .LiveKernel == nil {
98+ func ensureLiveArtifactsExist () error {
99+ if kola .CosaBuild .Meta .BuildArtifacts .LiveIso == nil {
100+ return errors .Errorf ("Build %s is missing live-iso artifacts\n " , kola .CosaBuild .Meta .Name )
101+ }
102+ if kola .CosaBuild .Meta .BuildArtifacts .LiveRootfs == nil || kola .CosaBuild .Meta .BuildArtifacts .LiveKernel == nil || kola .CosaBuild .Meta .BuildArtifacts .LiveInitramfs == nil {
197103 return errors .Errorf ("Build %s is missing live artifacts\n " , kola .CosaBuild .Meta .Name )
198104 }
199105 if kola .CosaBuild .Meta .BuildArtifacts .Metal == nil || kola .CosaBuild .Meta .BuildArtifacts .Metal4KNative == nil {
@@ -202,59 +108,54 @@ func EnsureLiveArtifactsExist() error {
202108 return nil
203109}
204110
205- func awaitCompletion (c cluster.TestCluster , inst * platform.QemuInstance , console bool , outdir string , qchan * os.File , booterrchan chan error , expected []string ) error {
206- ctx := c .Context ()
111+ // Sometimes the logs that stream from various virtio streams can be
112+ // incomplete because they depend on services inside the guest.
113+ // When you are debugging earlyboot/initramfs issues this can be
114+ // problematic. Let's add a hook here to enable more debugging.
115+ func renderCosaTestIsoDebugKargs () []string {
116+ if _ , ok := os .LookupEnv ("COSA_TESTISO_DEBUG" ); ok {
117+ return []string {"systemd.log_color=0" , "systemd.log_level=debug" ,
118+ "systemd.journald.forward_to_console=1" ,
119+ "systemd.journald.max_level_console=debug" }
120+ } else {
121+ return []string {}
122+ }
123+ }
124+
125+ func absSymlink (src , dest string ) error {
126+ src , err := filepath .Abs (src )
127+ if err != nil {
128+ return err
129+ }
130+ return os .Symlink (src , dest )
131+ }
207132
208- errchan := make (chan error )
209- go func () {
210- timeout := (time .Duration (installTimeoutMins * (100 + kola .Options .ExtendTimeoutPercent )) * time .Minute ) / 100
211- time .Sleep (timeout )
212- errchan <- fmt .Errorf ("timed out after %v" , timeout )
213- }()
214- if ! console {
215- go func () {
216- errBuf , err := inst .WaitIgnitionError (ctx )
217- if err == nil {
218- if errBuf != "" {
219- c .Logf ("entered emergency.target in initramfs" )
220- path := filepath .Join (outdir , "ignition-virtio-dump.txt" )
221- if err := os .WriteFile (path , []byte (errBuf ), 0644 ); err != nil {
222- c .Errorf ("Failed to write journal: %v" , err )
223- }
224- err = platform .ErrInitramfsEmergency
225- }
226- }
227- if err != nil {
228- errchan <- err
229- }
230- }()
133+ // setupMetalImage creates a symlink to the metal image.
134+ func setupMetalImage (builddir , metalimg , destdir string ) (string , error ) {
135+ if err := absSymlink (filepath .Join (builddir , metalimg ), filepath .Join (destdir , metalimg )); err != nil {
136+ return "" , err
231137 }
232- go func () {
233- err := inst .Wait ()
234- // only one Wait() gets process data, so also manually check for signal
235- //plog.Debugf("qemu exited err=%v", err)
236- if err == nil && inst .Signaled () {
237- err = errors .New ("process killed" )
238- }
138+ return metalimg , nil
139+ }
140+
141+ func cat (outfile string , infiles ... string ) error {
142+ out , err := os .OpenFile (outfile , os .O_WRONLY | os .O_CREATE , 0644 )
143+ if err != nil {
144+ return err
145+ }
146+ defer out .Close ()
147+ for _ , infile := range infiles {
148+ in , err := os .Open (infile )
239149 if err != nil {
240- errchan <- errors . Wrapf ( err , "QEMU unexpectedly exited while awaiting completion" )
150+ return err
241151 }
242- time .Sleep (1 * time .Minute )
243- errchan <- fmt .Errorf ("QEMU exited; timed out waiting for completion" )
244- }()
245- go func () {
246- errchan <- CheckTestOutput (qchan , expected )
247- }()
248- go func () {
249- //check for error when switching boot order
250- if booterrchan != nil {
251- if err := <- booterrchan ; err != nil {
252- errchan <- err
253- }
152+ defer in .Close ()
153+ _ , err = io .Copy (out , in )
154+ if err != nil {
155+ return err
254156 }
255- }()
256- err := <- errchan
257- return err
157+ }
158+ return nil
258159}
259160
260161var liveOKSignal = "live-test-OK"
0 commit comments