From b0d655d3d17ee186f518ed465f7ff9228d9707e1 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Wed, 25 Mar 2020 13:14:34 +0000 Subject: [PATCH] Move 9p mount logic into QemuBuilder/qemuexec Drain another thing out of `cmd-run`. This is prep for making `cmd-run` be a tiny wrapper around `kola qemuexec`. Also, using 9p mounts can be very useful for testing; i.e. this helps unlock having qemu-specific tests that bind mount in data without copying. (One thing I'm thinking for example is that we support pulling container images from the host) --- mantle/cmd/kola/qemuexec.go | 31 ++++++++++++++++++++++++++++++- mantle/go.mod | 1 + mantle/platform/conf/conf.go | 33 +++++++++++++++++++++++++++++++++ mantle/platform/qemu.go | 13 +++++++++++++ src/cmd-run | 15 ++++----------- 5 files changed, 81 insertions(+), 12 deletions(-) diff --git a/mantle/cmd/kola/qemuexec.go b/mantle/cmd/kola/qemuexec.go index 7fa62c4b35..62176b1d47 100644 --- a/mantle/cmd/kola/qemuexec.go +++ b/mantle/cmd/kola/qemuexec.go @@ -19,6 +19,7 @@ package main import ( "fmt" "io/ioutil" + "strings" v3 "github.com/coreos/ignition/v2/config/v3_0" v3types "github.com/coreos/ignition/v2/config/v3_0/types" @@ -49,6 +50,8 @@ var ( knetargs string ignitionFragments []string + bindro []string + bindrw []string forceConfigInjection bool ) @@ -62,6 +65,8 @@ func init() { cmdQemuExec.Flags().StringVarP(&hostname, "hostname", "", "", "Set hostname via DHCP") cmdQemuExec.Flags().IntVarP(&memory, "memory", "m", 0, "Memory in MB") cmdQemuExec.Flags().StringVarP(&ignition, "ignition", "i", "", "Path to ignition config") + cmdQemuExec.Flags().StringArrayVar(&bindro, "bind-ro", nil, "Mount readonly via 9pfs a host directory (use --bind-ro=/path/to/host,/var/mnt/guest") + cmdQemuExec.Flags().StringArrayVar(&bindrw, "bind-rw", nil, "Same as above, but writable") cmdQemuExec.Flags().BoolVarP(&forceConfigInjection, "inject-ignition", "", false, "Force injecting Ignition config using guestfs") } @@ -79,6 +84,14 @@ func renderFragments(config v3types.Config) (*v3types.Config, error) { return &config, nil } +func parseBindOpt(s string) (string, string, error) { + parts := strings.SplitN(s, ",", 2) + if len(parts) == 1 { + return "", "", fmt.Errorf("malformed bind option, required: SRC,DEST") + } + return parts[0], parts[1], nil +} + func runQemuExec(cmd *cobra.Command, args []string) error { var err error buf, err := ioutil.ReadFile(ignition) @@ -97,10 +110,26 @@ func runQemuExec(cmd *cobra.Command, args []string) error { config = *newconfig } builder := platform.NewBuilder() + builder.ForceConfigInjection = forceConfigInjection + for _, b := range bindro { + src, dest, err := parseBindOpt(b) + if err != nil { + return err + } + builder.Mount9p(src, dest, true) + config = v3.Merge(config, conf.Mount9p(dest, true)) + } + for _, b := range bindrw { + src, dest, err := parseBindOpt(b) + if err != nil { + return err + } + builder.Mount9p(src, dest, false) + config = v3.Merge(config, conf.Mount9p(dest, false)) + } if err := builder.SetConfig(config, kola.Options.IgnitionVersion == "v2"); err != nil { return errors.Wrapf(err, "rendering config") } - builder.ForceConfigInjection = forceConfigInjection if len(knetargs) > 0 { builder.IgnitionNetworkKargs = knetargs } diff --git a/mantle/go.mod b/mantle/go.mod index 78075dd045..bfd673bc3b 100644 --- a/mantle/go.mod +++ b/mantle/go.mod @@ -13,6 +13,7 @@ require ( github.com/aws/aws-sdk-go v1.25.14 github.com/coreos/container-linux-config-transpiler v0.8.0 github.com/coreos/go-semver v0.3.0 + github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e github.com/coreos/go-systemd/v22 v22.0.0 github.com/coreos/ign-converter v0.0.0-20200228175238-237c8512310a github.com/coreos/ignition v0.35.0 diff --git a/mantle/platform/conf/conf.go b/mantle/platform/conf/conf.go index c3153cbbc0..37601746c7 100644 --- a/mantle/platform/conf/conf.go +++ b/mantle/platform/conf/conf.go @@ -26,6 +26,7 @@ import ( ignconverter "github.com/coreos/ign-converter" ct "github.com/coreos/container-linux-config-transpiler/config" + systemdunit "github.com/coreos/go-systemd/unit" ignerr "github.com/coreos/ignition/config/shared/errors" v2 "github.com/coreos/ignition/config/v2_0" v2types "github.com/coreos/ignition/config/v2_0/types" @@ -856,3 +857,35 @@ func GetAutologin() v3types.Config { conf.Systemd.Units = append(conf.Systemd.Units, getAutologinFragment("serial-getty@.service", "--keep-baud 115200,38400,9600")) return conf } + +func Mount9p(dest string, readonly bool) v3types.Config { + conf := v3types.Config{ + Ignition: v3types.Ignition{ + Version: "3.0.0", + }, + Systemd: v3types.Systemd{}, + } + readonlyStr := "" + if readonly { + readonlyStr = ",ro" + } + mntBuf := fmt.Sprintf(`[Unit] +DefaultDependencies=no +After=systemd-tmpfiles-setup.service +Before=basic.target +[Mount] +What=%s +Where=%s +Type=9p +Options=trans=virtio,version=9p2000.L%s +[Install] +WantedBy=multi-user.target +`, dest, dest, readonlyStr) + enable := true + conf.Systemd.Units = append(conf.Systemd.Units, v3types.Unit{ + Name: fmt.Sprintf("%s.mount", systemdunit.UnitNameEscape(dest[1:])), + Contents: &mntBuf, + Enabled: &enable, + }) + return conf +} diff --git a/mantle/platform/qemu.go b/mantle/platform/qemu.go index 6c90d3e6a9..6d458404b1 100644 --- a/mantle/platform/qemu.go +++ b/mantle/platform/qemu.go @@ -173,6 +173,7 @@ type QemuBuilder struct { finalized bool diskId uint + fs9pId uint fds []*os.File } @@ -280,6 +281,18 @@ func (builder *QemuBuilder) EnableUsermodeNetworking(forwardedPort uint) { builder.Append("-netdev", netdev, "-device", virtio("net", "netdev=eth0")) } +// Mount9p sets up a mount point from the host to guest. To be replaced +// with https://virtio-fs.gitlab.io/ once it lands everywhere. +func (builder *QemuBuilder) Mount9p(source, destHint string, readonly bool) { + builder.fs9pId += 1 + readonlyStr := "" + if readonly { + readonlyStr = ",readonly" + } + builder.Append("--fsdev", fmt.Sprintf("local,id=fs%d,path=%s,security_model=mapped%s", builder.fs9pId, source, readonlyStr)) + builder.Append("-device", virtio("9p", fmt.Sprintf("fsdev=fs%d,mount_tag=%s", builder.fs9pId, destHint))) +} + // supportsFwCfg if the target system supports injecting // Ignition via the qemu -fw_cfg option. func (builder *QemuBuilder) supportsFwCfg() bool { diff --git a/src/cmd-run b/src/cmd-run index 51627ecc16..c1dd4a0389 100755 --- a/src/cmd-run +++ b/src/cmd-run @@ -137,17 +137,6 @@ append_systemd_unit() { fi } -if [ -n "${VM_SRV_MNT}" ]; then - set -- --fsdev local,id=var-srv,path="${VM_SRV_MNT}",security_model=mapped,readonly \ - -device virtio-9p-"${devtype}",fsdev=var-srv,mount_tag=/var/srv "$@" - # The dependency changes are hacks around https://github.com/coreos/fedora-coreos-tracker/issues/223 - append_systemd_unit '{ -"name": "var-srv.mount", -"enabled": true, -"contents": "[Unit]\nDefaultDependencies=no\nAfter=systemd-tmpfiles-setup.service\nBefore=basic.target\n[Mount]\nWhat=/var/srv\nWhere=/var/srv\nType=9p\nOptions=ro,trans=virtio,version=9p2000.L\n[Install]\nWantedBy=multi-user.target\n" -}' -fi - if [ -n "${IGNITION_CONFIG_FILE:-}" ]; then user_config=$(base64 --wrap 0 "${IGNITION_CONFIG_FILE}") user_config=$(cat << EOF @@ -238,6 +227,10 @@ case "${DISK_CHANNEL}" in *) die "Invalid --disk-channel ${DISK_CHANNEL}" ;; esac +if [ -n "${VM_SRV_MNT}" ]; then + kola_args+=("--bind-ro=${VM_SRV_MNT},/var/srv") +fi + if [ "${IMAGE_TYPE}" == metal4k ]; then kola_args+=("--qemu-native-4k") fi