Skip to content

Commit

Permalink
Merge pull request #718 from Prashanth684/virtio-blk-multiarch
Browse files Browse the repository at this point in the history
Use virtio-blk instead of disk for injecting ignition config for s390x and ppc64
  • Loading branch information
MalloZup authored Mar 25, 2020
2 parents c2b6ef5 + 889c3a1 commit 5136098
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 90 deletions.
2 changes: 1 addition & 1 deletion examples/v0.12/coreos/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ with their own Ignition configuration


### Supported architectures
This example will work on i686 (x86), x86\_64 (AMD64), aarch64 (ARM64), s390x (IBM Z) and IBM PowerPC. On i686, x86\_64, and aarch64, the Terraform provider uses QEMU's firmware configuration (fw\_cfg) device to pass the Ignition config through to the Ignition instance running in the virtual machine. In order for this to work, Ignition needs to be run with `--provider=qemu`. Unfortunately, QEMU doesn't support the firmware configuration device for s390x and PowerPC guests, so the Terraform provider falls back to using an OpenStack config-drive instead. The config-drive will automatically be created by the provider, provided that `mkisofs` is installed in the path, so no changes are necessary to the Terraform templates. Ignition needs to be run with `--provider=openstack` when inside of an s390x or PowerPc guest in order to find the config-drive.
This example will work on i686 (x86), x86\_64 (AMD64), aarch64 (ARM64), s390x (IBM Z) and IBM PowerPC. On i686, x86\_64, and aarch64, the Terraform provider uses QEMU's firmware configuration (fw\_cfg) device to pass the Ignition config through to the Ignition instance running in the virtual machine. In order for this to work, Ignition needs to be run with `--provider=qemu`. Unfortunately, QEMU doesn't support the firmware configuration device for s390x and PowerPC guests, so alternatively, a virtio-blk device is created with a serial of `ignition` which ignition detects and reads.


### Using the QEMU Guest Agent
Expand Down
58 changes: 9 additions & 49 deletions libvirt/coreos_ignition_def.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ import (
"io/ioutil"
"log"
"os"
"os/exec"
"path/filepath"
"strings"

libvirt "github.com/libvirt/libvirt-go"
Expand Down Expand Up @@ -52,55 +50,17 @@ func (ign *defIgnition) CreateAndUpload(client *Client) (string, error) {
volumeDef := newDefVolume()
volumeDef.Name = ign.Name

tmpDir, err := ioutil.TempDir("", "ignition")
ignFile, err := ign.createFile()
if err != nil {
return "", fmt.Errorf("Failed to create Ignition directory: %v", err)
return "", err
}
defer func() {
if err = os.RemoveAll(tmpDir); err != nil {
log.Printf("Error while removing Ignition directory: %v", err)
if err = os.Remove(ignFile); err != nil {
log.Printf("Error while removing tmp Ignition file: %v", err)
}
}()

ignPath, err := ign.createFile(tmpDir)
if err != nil {
return "", err
}

arch, err := getHostArchitecture(client.libvirt)
if err != nil {
return "", fmt.Errorf("Error retrieving host architecture: %s", err)
}

var userdataPath string
switch arch {
case "i686", "x86_64", "aarch64":
userdataPath = ignPath
case "s390", "s390x", "ppc64", "ppc64le":
configDrivePath := filepath.Join(tmpDir, "config.iso")
cmd := exec.Command(
"mkisofs",
"-output",
configDrivePath,
"-volid",
"config-2",
"-root",
"openstack/latest",
"-joliet",
"-rock",
ignPath)

log.Printf("Executing command: %+v", cmd)
if err = cmd.Run(); err != nil {
return "", fmt.Errorf("Failed to create Config Drive ISO image: %v", err)
}

userdataPath = configDrivePath
default:
return "", fmt.Errorf("Ignition not supported on %q", arch)
}

img, err := newImage(userdataPath)
img, err := newImage(ignFile)
if err != nil {
return "", err
}
Expand Down Expand Up @@ -156,12 +116,12 @@ func getIgnitionVolumeKeyFromTerraformID(id string) (string, error) {
}

// Dumps the Ignition object - either generated by Terraform or supplied as a file -
// to a userdata Ignition file in the provided directory
func (ign *defIgnition) createFile(dir string) (string, error) {
// to a temporary ignition file
func (ign *defIgnition) createFile() (string, error) {
log.Print("Creating Ignition temporary file")
tempFile, err := os.Create(filepath.Join(dir, "user_data"))
tempFile, err := ioutil.TempFile("", ign.Name)
if err != nil {
return "", fmt.Errorf("Error creating userdata file: %v", err)
return "", fmt.Errorf("Error creating tmp file: %v", err)
}
defer tempFile.Close()

Expand Down
60 changes: 31 additions & 29 deletions libvirt/domain.go
Original file line number Diff line number Diff line change
Expand Up @@ -198,26 +198,14 @@ func domainGetIfacesInfo(domain libvirt.Domain, rd *schema.ResourceData) ([]libv
return interfaces, nil
}

func newDiskForCloudInit(virConn *libvirt.Connect, volumeKey string, arch string) (libvirtxml.DomainDisk, error) {
var target *libvirtxml.DomainDiskTarget
switch arch {
case "s390", "s390x", "ppc64", "ppc64le":
target = &libvirtxml.DomainDiskTarget{
// s390 and ppc64 platforms don't support IDE controllers
Dev: "vdb",
Bus: "scsi",
}
default:
target = &libvirtxml.DomainDiskTarget{
func newDiskForCloudInit(virConn *libvirt.Connect, volumeKey string) (libvirtxml.DomainDisk, error) {
disk := libvirtxml.DomainDisk{
Device: "cdrom",
Target: &libvirtxml.DomainDiskTarget{
// Last device letter possible with a single IDE controller on i440FX
Dev: "hdd",
Bus: "ide",
}
}

disk := libvirtxml.DomainDisk{
Device: "cdrom",
Target: target,
},
Driver: &libvirtxml.DomainDiskDriver{
Name: "qemu",
Type: "raw",
Expand Down Expand Up @@ -270,17 +258,31 @@ func setCoreOSIgnition(d *schema.ResourceData, domainDef *libvirtxml.Domain, vir
}
}
case "s390", "s390x", "ppc64", "ppc64le":
// System Z and PowerPC do not support any of the same pass-through
// mechanisms as Ignition. As a temporary workaround, the OpenStack
// Config Drive can be used instead. The Ignition volume already
// contains a Config Drive at this point.

disk, err := newDiskForCloudInit(virConn, ignitionKey, arch)
if err != nil {
return err
// System Z and PowerPC do not support the Firmware Configuration
// device. After a discussion about the best way to support a similar
// method for qemu in https://github.com/coreos/ignition/issues/928,
// decided on creating a virtio-blk device with a serial of ignition
// which contains the ignition config and have ignition support for
// reading from the device which landed in https://github.com/coreos/ignition/pull/936
igndisk := libvirtxml.DomainDisk{
Device: "disk",
Source: &libvirtxml.DomainDiskSource{
File: &libvirtxml.DomainDiskSourceFile{
File: ignitionKey,
},
},
Target: &libvirtxml.DomainDiskTarget{
Dev: "vdb",
Bus: "virtio",
},
Driver: &libvirtxml.DomainDiskDriver{
Name: "qemu",
Type: "raw",
},
ReadOnly: &libvirtxml.DomainDiskReadOnly{},
Serial: "ignition",
}

domainDef.Devices.Disks = append(domainDef.Devices.Disks, disk)
domainDef.Devices.Disks = append(domainDef.Devices.Disks, igndisk)
default:
return fmt.Errorf("Ignition not supported on %q", arch)
}
Expand Down Expand Up @@ -655,13 +657,13 @@ func setFilesystems(d *schema.ResourceData, domainDef *libvirtxml.Domain) error
return nil
}

func setCloudinit(d *schema.ResourceData, domainDef *libvirtxml.Domain, virConn *libvirt.Connect, arch string) error {
func setCloudinit(d *schema.ResourceData, domainDef *libvirtxml.Domain, virConn *libvirt.Connect) error {
if cloudinit, ok := d.GetOk("cloudinit"); ok {
cloudinitID, err := getCloudInitVolumeKeyFromTerraformID(cloudinit.(string))
if err != nil {
return err
}
disk, err := newDiskForCloudInit(virConn, cloudinitID, arch)
disk, err := newDiskForCloudInit(virConn, cloudinitID)
if err != nil {
return err
}
Expand Down
9 changes: 2 additions & 7 deletions libvirt/resource_libvirt_domain.go
Original file line number Diff line number Diff line change
Expand Up @@ -497,7 +497,7 @@ func resourceLibvirtDomainCreate(d *schema.ResourceData, meta interface{}) error
return err
}

if err := setCloudinit(d, &domainDef, virConn, arch); err != nil {
if err := setCloudinit(d, &domainDef, virConn); err != nil {
return err
}

Expand Down Expand Up @@ -652,12 +652,7 @@ func resourceLibvirtDomainUpdate(d *schema.ResourceData, meta interface{}) error
return err
}

arch, err := getHostArchitecture(virConn)
if err != nil {
return fmt.Errorf("Error retrieving host architecture: %s", err)
}

disk, err := newDiskForCloudInit(virConn, cloudinitID, arch)
disk, err := newDiskForCloudInit(virConn, cloudinitID)
if err != nil {
return err
}
Expand Down
7 changes: 3 additions & 4 deletions website/docs/r/coreos_ignition.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,9 @@ a CoreOS Domain during first boot.

~> **Note:** On the i686 (x86), x86\_64 (AMD64), and aarch64 (ARM64) platforms,
the QEMU firmware config device (`-fw_cfg`) is used to pass Ignition configs
into the guests. On the s390x (IBM Z) platform however, the QEMU firmware
config device is not supported. As alternative, the OpenStack config-drive
mechanism is instead used. The `mkisofs` utility must be installed into the
path and Ignition must be run with the `--provider=openstack` flag.
into the guests. On the s390x (IBM Z) and PowerPC platforms however, the QEMU firmware
config device is not supported. As an alternative, a virtio-blk device is created with a serial
of `ignition` which ignition recognizes and reads the config from the device

## Example Usage

Expand Down

0 comments on commit 5136098

Please sign in to comment.