@@ -148,6 +148,9 @@ type QemuBuilder struct {
148
148
Pdeathsig bool
149
149
Argv []string
150
150
151
+ // IgnitionNetworkKargs are written to /boot/ignition
152
+ IgnitionNetworkKargs string
153
+
151
154
Hostname string
152
155
153
156
InheritConsole bool
@@ -277,70 +280,99 @@ func findLabel(label, pid string) (string, error) {
277
280
return strings .TrimSpace (string (stdout )), nil
278
281
}
279
282
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 ) {
282
290
// Set guestfish backend to direct in order to avoid libvirt as backend.
283
291
// Using libvirt can lead to permission denied issues if it does not have access
284
292
// rights to the qcow image
285
293
cmd := exec .Command ("guestfish" , "--listen" , "-a" , diskImagePath )
286
294
cmd .Env = append (os .Environ (), "LIBGUESTFS_BACKEND=direct" )
287
295
stdout , err := cmd .StdoutPipe ()
288
296
if err != nil {
289
- return fmt .Errorf ("getting stdout pipe: %v" , err )
297
+ return nil , fmt .Errorf ("getting stdout pipe: %v" , err )
290
298
}
291
299
defer stdout .Close ()
292
300
293
301
if err := cmd .Start (); err != nil {
294
- return fmt .Errorf ("running guestfish: %v" , err )
302
+ return nil , fmt .Errorf ("running guestfish: %v" , err )
295
303
}
296
304
buf , err := ioutil .ReadAll (stdout )
297
305
if err != nil {
298
- return fmt .Errorf ("reading guestfish output: %v" , err )
306
+ return nil , fmt .Errorf ("reading guestfish output: %v" , err )
299
307
}
300
308
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 )
302
310
}
303
311
//GUESTFISH_PID=$PID; export GUESTFISH_PID
304
312
gfVarPid := strings .Split (string (buf ), ";" )
305
313
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 ))
307
315
}
308
316
gfVarPidArr := strings .Split (gfVarPid [0 ], "=" )
309
317
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 ))
311
319
}
312
320
pid := gfVarPidArr [1 ]
313
321
remote := fmt .Sprintf ("--remote=%s" , pid )
314
322
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
-
322
323
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 )
324
325
}
325
326
326
327
bootfs , err := findLabel ("boot" , pid )
327
328
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 )
329
330
}
330
331
331
332
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 )
333
334
}
334
335
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 )
337
345
}
346
+ }
338
347
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
341
354
}
355
+ defer gf .destroy ()
342
356
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 {
344
376
return fmt .Errorf ("guestfish umount failed: %v" , err )
345
377
}
346
378
return nil
@@ -396,11 +428,14 @@ func (builder *QemuBuilder) addDiskImpl(disk *Disk, primary bool) error {
396
428
if err := qemuImg .Run (); err != nil {
397
429
return err
398
430
}
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
+ }
404
439
}
405
440
}
406
441
fd , err := os .OpenFile (dstFileName , os .O_RDWR , 0 )
0 commit comments