Skip to content

Commit 16094fa

Browse files
cgwaltersopenshift-merge-robot
authored andcommitted
kola/qemu: Support injecting kernel network arguments
This is useful for quickly testing static IP addresses on the kernel cmdline without actually having to catch the GRUB prompt or go through a whole series of `coreos-installer iso embed` etc.
1 parent 94c4054 commit 16094fa

File tree

2 files changed

+68
-28
lines changed

2 files changed

+68
-28
lines changed

mantle/cmd/kola/qemuexec.go

+5
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,12 @@ var (
3838

3939
hostname string
4040
ignition string
41+
knetargs string
4142
)
4243

4344
func init() {
4445
root.AddCommand(cmdQemuExec)
46+
cmdQemuExec.Flags().StringVarP(&knetargs, "knetargs", "", "", "Arguments for Ignition networking on kernel commandline")
4547
cmdQemuExec.Flags().BoolVarP(&usernet, "usernet", "U", false, "Enable usermode networking")
4648
cmdQemuExec.Flags().StringVarP(&hostname, "hostname", "", "", "Set hostname via DHCP")
4749
cmdQemuExec.Flags().IntVarP(&memory, "memory", "m", 0, "Memory in MB")
@@ -52,6 +54,9 @@ func runQemuExec(cmd *cobra.Command, args []string) error {
5254
var err error
5355

5456
builder := platform.NewBuilder(kola.QEMUOptions.Board, ignition)
57+
if len(knetargs) > 0 {
58+
builder.IgnitionNetworkKargs = knetargs
59+
}
5560
defer builder.Close()
5661
builder.Firmware = kola.QEMUOptions.Firmware
5762
if kola.QEMUOptions.DiskImage != "" {

mantle/platform/qemu.go

+63-28
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,9 @@ type QemuBuilder struct {
148148
Pdeathsig bool
149149
Argv []string
150150

151+
// IgnitionNetworkKargs are written to /boot/ignition
152+
IgnitionNetworkKargs string
153+
151154
Hostname string
152155

153156
InheritConsole bool
@@ -277,70 +280,99 @@ func findLabel(label, pid string) (string, error) {
277280
return strings.TrimSpace(string(stdout)), nil
278281
}
279282

280-
// setupIgnition copies the ignition file inside the disk image.
281-
func setupIgnition(confPath string, diskImagePath string) error {
283+
type coreosGuestfish struct {
284+
cmd *exec.ExecCmd
285+
286+
remote string
287+
}
288+
289+
func newGuestfish(diskImagePath string) (*coreosGuestfish, error) {
282290
// Set guestfish backend to direct in order to avoid libvirt as backend.
283291
// Using libvirt can lead to permission denied issues if it does not have access
284292
// rights to the qcow image
285293
cmd := exec.Command("guestfish", "--listen", "-a", diskImagePath)
286294
cmd.Env = append(os.Environ(), "LIBGUESTFS_BACKEND=direct")
287295
stdout, err := cmd.StdoutPipe()
288296
if err != nil {
289-
return fmt.Errorf("getting stdout pipe: %v", err)
297+
return nil, fmt.Errorf("getting stdout pipe: %v", err)
290298
}
291299
defer stdout.Close()
292300

293301
if err := cmd.Start(); err != nil {
294-
return fmt.Errorf("running guestfish: %v", err)
302+
return nil, fmt.Errorf("running guestfish: %v", err)
295303
}
296304
buf, err := ioutil.ReadAll(stdout)
297305
if err != nil {
298-
return fmt.Errorf("reading guestfish output: %v", err)
306+
return nil, fmt.Errorf("reading guestfish output: %v", err)
299307
}
300308
if err := cmd.Wait(); err != nil {
301-
return fmt.Errorf("waiting for guestfish response: %v", err)
309+
return nil, fmt.Errorf("waiting for guestfish response: %v", err)
302310
}
303311
//GUESTFISH_PID=$PID; export GUESTFISH_PID
304312
gfVarPid := strings.Split(string(buf), ";")
305313
if len(gfVarPid) != 2 {
306-
return fmt.Errorf("Failing parsing GUESTFISH_PID got: expecting length 2 got instead %d", len(gfVarPid))
314+
return nil, fmt.Errorf("Failing parsing GUESTFISH_PID got: expecting length 2 got instead %d", len(gfVarPid))
307315
}
308316
gfVarPidArr := strings.Split(gfVarPid[0], "=")
309317
if len(gfVarPidArr) != 2 {
310-
return fmt.Errorf("Failing parsing GUESTFISH_PID got: expecting length 2 got instead %d", len(gfVarPid))
318+
return nil, fmt.Errorf("Failing parsing GUESTFISH_PID got: expecting length 2 got instead %d", len(gfVarPid))
311319
}
312320
pid := gfVarPidArr[1]
313321
remote := fmt.Sprintf("--remote=%s", pid)
314322

315-
defer func() {
316-
plog.Debugf("guestfish exit (PID:%s)", pid)
317-
if err := exec.Command("guestfish", remote, "exit").Run(); err != nil {
318-
plog.Errorf("guestfish exit failed: %v", err)
319-
}
320-
}()
321-
322323
if err := exec.Command("guestfish", remote, "run").Run(); err != nil {
323-
return fmt.Errorf("guestfish launch failed: %v", err)
324+
return nil, fmt.Errorf("guestfish launch failed: %v", err)
324325
}
325326

326327
bootfs, err := findLabel("boot", pid)
327328
if err != nil {
328-
return fmt.Errorf("guestfish command failed to find boot label: %v", err)
329+
return nil, fmt.Errorf("guestfish command failed to find boot label: %v", err)
329330
}
330331

331332
if err := exec.Command("guestfish", remote, "mount", bootfs, "/").Run(); err != nil {
332-
return fmt.Errorf("guestfish boot mount failed: %v", err)
333+
return nil, fmt.Errorf("guestfish boot mount failed: %v", err)
333334
}
334335

335-
if err := exec.Command("guestfish", remote, "mkdir-p", "/ignition").Run(); err != nil {
336-
return fmt.Errorf("guestfish directory creation failed: %v", err)
336+
return &coreosGuestfish{
337+
cmd: cmd,
338+
remote: remote,
339+
}, nil
340+
}
341+
342+
func (gf *coreosGuestfish) destroy() {
343+
if err := exec.Command("guestfish", gf.remote, "exit").Run(); err != nil {
344+
plog.Errorf("guestfish exit failed: %v", err)
337345
}
346+
}
338347

339-
if err := exec.Command("guestfish", remote, "upload", confPath, fileRemoteLocation).Run(); err != nil {
340-
return fmt.Errorf("guestfish upload failed: %v", err)
348+
// setupIgnition copies the ignition file inside the disk image and/or sets
349+
// networking kernel arguments
350+
func setupIgnition(confPath string, knetargs string, diskImagePath string) error {
351+
gf, err := newGuestfish(diskImagePath)
352+
if err != nil {
353+
return err
341354
}
355+
defer gf.destroy()
342356

343-
if err := exec.Command("guestfish", remote, "umount-all").Run(); err != nil {
357+
if confPath != "" {
358+
if err := exec.Command("guestfish", gf.remote, "mkdir-p", "/ignition").Run(); err != nil {
359+
return fmt.Errorf("guestfish directory creation failed: %v", err)
360+
}
361+
362+
if err := exec.Command("guestfish", gf.remote, "upload", confPath, fileRemoteLocation).Run(); err != nil {
363+
return fmt.Errorf("guestfish upload failed: %v", err)
364+
}
365+
}
366+
367+
// See /boot/grub2/grub.cfg
368+
if knetargs != "" {
369+
grubStr := fmt.Sprintf("set ignition_network_kcmdline='%s'\n", knetargs)
370+
if err := exec.Command("guestfish", gf.remote, "write", "/ignition.firstboot", grubStr).Run(); err != nil {
371+
return errors.Wrapf(err, "guestfish write")
372+
}
373+
}
374+
375+
if err := exec.Command("guestfish", gf.remote, "umount-all").Run(); err != nil {
344376
return fmt.Errorf("guestfish umount failed: %v", err)
345377
}
346378
return nil
@@ -396,11 +428,14 @@ func (builder *QemuBuilder) addDiskImpl(disk *Disk, primary bool) error {
396428
if err := qemuImg.Run(); err != nil {
397429
return err
398430
}
399-
// If the board doesn't support -fw_cfg, inject via libguestfs on the
400-
// primary disk.
401-
if primary && builder.Config != "" && !builder.supportsFwCfg() {
402-
if err = setupIgnition(builder.Config, dstFileName); err != nil {
403-
return fmt.Errorf("ignition injection with guestfs failed: %v", err)
431+
if primary {
432+
// If the board doesn't support -fw_cfg, inject via libguestfs on the
433+
// primary disk.
434+
requiresInjection := builder.Config != "" && !builder.supportsFwCfg()
435+
if requiresInjection || builder.IgnitionNetworkKargs != "" {
436+
if err = setupIgnition(builder.Config, builder.IgnitionNetworkKargs, dstFileName); err != nil {
437+
return fmt.Errorf("ignition injection with guestfs failed: %v", err)
438+
}
404439
}
405440
}
406441
fd, err := os.OpenFile(dstFileName, os.O_RDWR, 0)

0 commit comments

Comments
 (0)