Skip to content

Commit ce1aa00

Browse files
committed
Add support for s390x on coreos ignition
now x86 platform use fw_cfg to process coreos ingition but fw_cfg is not usable in s390 platform. so we need use libguestfs to update the coreos image by injecting the ignition into it. we have some comments like following to try but that's not for coreos https://gitlab.gnome.org/GNOME/gnome-boxes/blob/master/src/unattended-file.vala
1 parent 5c01d18 commit ce1aa00

File tree

4 files changed

+406
-2
lines changed

4 files changed

+406
-2
lines changed

libvirt/domain.go

Lines changed: 151 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
package libvirt
22

33
import (
4+
"bytes"
45
"errors"
56
"fmt"
7+
"io"
68
"log"
79
"net"
810
"net/url"
11+
"os"
12+
"os/exec"
13+
"runtime"
914
"sort"
1015
"strconv"
1116
"strings"
@@ -230,7 +235,143 @@ func newDiskForCloudInit(virConn *libvirt.Connect, volumeKey string) (libvirtxml
230235
return disk, nil
231236
}
232237

233-
func setCoreOSIgnition(d *schema.ResourceData, domainDef *libvirtxml.Domain) error {
238+
func getFirstDiskPath(d *schema.ResourceData, domainDef *libvirtxml.Domain, virConn *libvirt.Connect) (string, error) {
239+
prefix := fmt.Sprintf("disk.%d", 0)
240+
241+
if volumeKey, ok := d.GetOk(prefix + ".volume_id"); ok {
242+
diskVolume, err := virConn.LookupStorageVolByKey(volumeKey.(string))
243+
if err != nil {
244+
return "", fmt.Errorf("Error lookup storage disk volume: %s", err)
245+
}
246+
diskVolumeFile, err := diskVolume.GetPath()
247+
if err != nil {
248+
return "", fmt.Errorf("Error get path of disk volume: %s", err)
249+
}
250+
return diskVolumeFile, nil
251+
}
252+
return "", fmt.Errorf("failed to find disk 0")
253+
}
254+
255+
func getStderr(stderr io.ReadCloser) string {
256+
buf := new(bytes.Buffer)
257+
buf.ReadFrom(stderr)
258+
return buf.String()
259+
}
260+
261+
func inlineUpdateCoreOsIgnition(d *schema.ResourceData, domainDef *libvirtxml.Domain, virConn *libvirt.Connect) error {
262+
if ignition, ok := d.GetOk("coreos_ignition"); ok {
263+
264+
// Get the root disk (first disk) volume location
265+
rootPath, err := getFirstDiskPath(d, domainDef, virConn)
266+
if err != nil {
267+
return err
268+
}
269+
270+
// Get the ingition file to be uploaded
271+
ignitionKey, err := getIgnitionVolumeKeyFromTerraformID(ignition.(string))
272+
if err != nil {
273+
return err
274+
}
275+
diskVolume, err := virConn.LookupStorageVolByKey(ignitionKey)
276+
if err != nil {
277+
return err
278+
}
279+
fileToUpload, err := diskVolume.GetPath()
280+
if err != nil {
281+
return err
282+
}
283+
err = guestfishExecution(rootPath, fileToUpload)
284+
if err != nil {
285+
return err
286+
}
287+
}
288+
return nil
289+
}
290+
291+
var execCommand = exec.Command
292+
293+
func guestfishExecution(rootPath string, fileToUpload string) error {
294+
// This is the file in coreos image going to be copied from local
295+
fileRemoteLocation := "/ignition/config.ign"
296+
297+
// eval $(guestfish --listen -a $1)
298+
cmd := execCommand("guestfish", "--listen", "-a", rootPath)
299+
stdout, err := cmd.StdoutPipe()
300+
if err != nil {
301+
return fmt.Errorf("Get stdout failed: %v", err)
302+
}
303+
stderr, err := cmd.StderrPipe()
304+
if err != nil {
305+
return fmt.Errorf("Get stderr failed: %v", err)
306+
}
307+
308+
err = cmd.Start()
309+
if err != nil {
310+
return fmt.Errorf("Start command failed: %v", err)
311+
}
312+
313+
// if the command start successfully, the output will be following format
314+
// GUESTFISH_PID=xxxx; export GUESTFISH_PID, so we need get the PID and set by using os.Setenv
315+
buf := new(bytes.Buffer)
316+
buf.ReadFrom(stdout)
317+
guestfishPidLabel := strings.Split(buf.String(), ";")
318+
guestfishPidValue := strings.Split(guestfishPidLabel[0], "=")
319+
os.Setenv(guestfishPidValue[0], guestfishPidValue[1])
320+
321+
// guestfish --remote -- run
322+
cmd = execCommand("guestfish", "--remote", "--", "run")
323+
err = cmd.Run()
324+
if err != nil {
325+
return fmt.Errorf("Launch failed: %v, %s", err, getStderr(stderr))
326+
}
327+
328+
// guestfish --remote -- exit
329+
defer func() {
330+
cmd := execCommand("guestfish", "--remote", "--", "exit")
331+
cmd.Run()
332+
}()
333+
334+
// guestfish --remote -- findfs-label
335+
cmd = execCommand("guestfish", "--remote", "--", "findfs-label", "boot")
336+
output, err := cmd.Output()
337+
338+
if err != nil {
339+
return fmt.Errorf("Failed to find fs label: %v", err)
340+
}
341+
342+
bootDisk := strings.TrimSpace(string(output))
343+
if len(bootDisk) == 0 {
344+
return fmt.Errorf("failed to get the boot filesystem")
345+
}
346+
347+
// guestfish --remote -- mount $2 /
348+
cmd = execCommand("guestfish", "--remote", "--", "mount", bootDisk, "/")
349+
err = cmd.Run()
350+
if err != nil {
351+
return fmt.Errorf("Mount failed: %v, %s", err, getStderr(stderr))
352+
}
353+
354+
// This is the real command that upload the file from current location (the local file system)
355+
// to remote file location (the coreos file system)
356+
// guestfish --remote -- upload $4 $3/$4
357+
cmd = execCommand("guestfish", "--remote", "--", "upload", fileToUpload, fileRemoteLocation)
358+
err = cmd.Run()
359+
if err != nil {
360+
return fmt.Errorf("Upload failed: %v, %s", err, getStderr(stderr))
361+
}
362+
363+
// guestfish --remote -- umount-all
364+
cmd = execCommand("guestfish", "--remote", "--", "umount-all")
365+
err = cmd.Run()
366+
if err != nil {
367+
return fmt.Errorf("Unmount failed: %v, %s", err, getStderr(stderr))
368+
}
369+
370+
return nil
371+
}
372+
373+
// Use fw_cfg device to update coresos
374+
func fwcfgUpdateCoreOSIgnition(d *schema.ResourceData, domainDef *libvirtxml.Domain) error {
234375
if ignition, ok := d.GetOk("coreos_ignition"); ok {
235376
ignitionKey, err := getIgnitionVolumeKeyFromTerraformID(ignition.(string))
236377
if err != nil {
@@ -252,6 +393,15 @@ func setCoreOSIgnition(d *schema.ResourceData, domainDef *libvirtxml.Domain) err
252393
return nil
253394
}
254395

396+
func updateCoreOSIgnition(d *schema.ResourceData, domainDef *libvirtxml.Domain, virConn *libvirt.Connect) error {
397+
if runtime.GOARCH == "s390x" || runtime.GOARCH == "s390" {
398+
// There is no support for fw_cfg in s390x, so instead of doing fw_cfg
399+
// we have to inline update the coreos ignition file
400+
return inlineUpdateCoreOsIgnition(d, domainDef, virConn)
401+
}
402+
return fwcfgUpdateCoreOSIgnition(d, domainDef)
403+
}
404+
255405
func setVideo(d *schema.ResourceData, domainDef *libvirtxml.Domain) error {
256406
prefix := "video.0"
257407
if _, ok := d.GetOk(prefix); ok {

0 commit comments

Comments
 (0)