diff --git a/cmd/machine/cmd/init.go b/cmd/machine/cmd/init.go index 755951f..e444156 100644 --- a/cmd/machine/cmd/init.go +++ b/cmd/machine/cmd/init.go @@ -1,10 +1,9 @@ /* - Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -86,7 +85,7 @@ var machineTypes = map[string]string{ func getMachineTypes() []string { var mTypes []string - for key, _ := range machineTypes { + for key := range machineTypes { mTypes = append(mTypes, key) } sort.Strings(mTypes) @@ -175,7 +174,7 @@ func DoCreateMachine(machineName, machineType, fileName string, editFile bool) e return fmt.Errorf("Error calling editor: %s", err) } } - log.Debug("Got config:\n%s", string(machineBytes)) + log.Debugf("Got config:\n%s", string(machineBytes)) for { if err = yaml.Unmarshal(machineBytes, &newMachine); err == nil { @@ -196,7 +195,9 @@ func DoCreateMachine(machineName, machineType, fileName string, editFile bool) e } } - checkMachineFilePaths(&newMachine) + if err := checkMachineFilePaths(&newMachine); err != nil { + return fmt.Errorf("Error while checking machine fiel paths: %s", err) + } // persist config if not ephemeral err = postMachine(newMachine) @@ -265,6 +266,14 @@ func checkMachineFilePaths(newMachine *api.Machine) error { log.Infof("Fully qualified uefi-vars path %s", newPath) newMachine.Config.UEFIVars = newPath } + if newMachine.Config.UEFICode != "" { + newPath, err := verifyPath(cwd, newMachine.Config.UEFICode) + if err != nil { + return fmt.Errorf("Failed to verify path to uefi-code: %q: %s", newMachine.Config.UEFICode, err) + } + log.Infof("Fully qualified uefi-code path %s", newPath) + newMachine.Config.UEFICode = newPath + } return nil } @@ -302,6 +311,10 @@ func doInitArgsValidate(cmd *cobra.Command, args []string) error { cmd.SilenceUsage = true return fmt.Errorf("Invalid machine-type '%s', must be one of: %s", mType, strings.Join(mTypes, ", ")) } + debug, _ := cmd.Flags().GetBool("debug") + if debug { + log.SetLevel(log.DebugLevel) + } return nil } @@ -310,5 +323,6 @@ func init() { rootCmd.AddCommand(initCmd) initCmd.PersistentFlags().StringP("file", "f", "", "yaml file to import. If unspecified, use stdin") initCmd.PersistentFlags().BoolP("edit", "e", false, "edit the yaml file inline") + initCmd.PersistentFlags().BoolP("debug", "D", false, "enable debug logging") initCmd.PersistentFlags().StringP("machine-type", "m", defaultMachineType, fmt.Sprintf("specify the machine type, one of [%s]", strings.Join(mTypes, ", "))) } diff --git a/pkg/api/qconfig.go b/pkg/api/qconfig.go index c955e0c..fab79f7 100644 --- a/pkg/api/qconfig.go +++ b/pkg/api/qconfig.go @@ -2,7 +2,6 @@ package api import ( "fmt" - "github.com/project-machine/qcli" "os" "path" "path/filepath" @@ -10,6 +9,8 @@ import ( "strconv" "strings" + "github.com/project-machine/qcli" + log "github.com/sirupsen/logrus" ) @@ -66,7 +67,7 @@ func NewDefaultX86Config(name string, numCpus, numMemMB uint32, sockDir string) SMP: smp, Memory: mem, RngDevices: []qcli.RngDevice{ - qcli.RngDevice{ + { Driver: qcli.VirtioRng, ID: "rng0", Bus: "pcie.0", @@ -75,13 +76,13 @@ func NewDefaultX86Config(name string, numCpus, numMemMB uint32, sockDir string) }, }, CharDevices: []qcli.CharDevice{ - qcli.CharDevice{ + { Driver: qcli.LegacySerial, Backend: qcli.Socket, ID: "serial0", Path: filepath.Join(sockDir, "console.sock"), }, - qcli.CharDevice{ + { Driver: qcli.LegacySerial, Backend: qcli.Socket, ID: "monitor0", @@ -89,17 +90,17 @@ func NewDefaultX86Config(name string, numCpus, numMemMB uint32, sockDir string) }, }, LegacySerialDevices: []qcli.LegacySerialDevice{ - qcli.LegacySerialDevice{ + { ChardevID: "serial0", }, }, MonitorDevices: []qcli.MonitorDevice{ - qcli.MonitorDevice{ + { ChardevID: "monitor0", }, }, QMPSockets: []qcli.QMPSocket{ - qcli.QMPSocket{ + { Type: "unix", Server: true, NoWait: true, @@ -107,7 +108,7 @@ func NewDefaultX86Config(name string, numCpus, numMemMB uint32, sockDir string) }, }, PCIeRootPortDevices: []qcli.PCIeRootPortDevice{ - qcli.PCIeRootPortDevice{ + { ID: "root-port.0x4.0", Bus: "pcie.0", Chassis: "0x0", @@ -116,7 +117,7 @@ func NewDefaultX86Config(name string, numCpus, numMemMB uint32, sockDir string) Addr: "0x5", Multifunction: true, }, - qcli.PCIeRootPortDevice{ + { ID: "root-port.0x4.1", Bus: "pcie.0", Chassis: "0x1", @@ -171,13 +172,13 @@ func NewDefaultAarch64Config(name string, numCpus uint32, numMemMB uint32, sockD CPUModel: "host", Memory: mem, CharDevices: []qcli.CharDevice{ - qcli.CharDevice{ + { Driver: qcli.PCISerialDevice, Backend: qcli.Socket, ID: "serial0", Path: "/tmp/console.sock", }, - qcli.CharDevice{ + { Driver: qcli.LegacySerial, Backend: qcli.Socket, ID: "monitor0", @@ -185,7 +186,7 @@ func NewDefaultAarch64Config(name string, numCpus uint32, numMemMB uint32, sockD }, }, SerialDevices: []qcli.SerialDevice{ - qcli.SerialDevice{ + { Driver: qcli.PCISerialDevice, ID: "pciser0", ChardevIDs: []string{"serial0"}, @@ -193,12 +194,12 @@ func NewDefaultAarch64Config(name string, numCpus uint32, numMemMB uint32, sockD }, }, MonitorDevices: []qcli.MonitorDevice{ - qcli.MonitorDevice{ + { ChardevID: "monitor0", }, }, QMPSockets: []qcli.QMPSocket{ - qcli.QMPSocket{ + { Type: "unix", Server: true, NoWait: true, @@ -363,21 +364,41 @@ func (nd NicDef) QNetDevice(qti *qcli.QemuTypeIndex) (qcli.NetDevice, error) { return ndev, nil } -func ConfigureUEFIVars(c *qcli.Config, srcVars, runDir string, secureBoot bool) error { +func ConfigureUEFIVars(c *qcli.Config, srcCode, srcVars, runDir string, secureBoot bool) error { uefiDev, err := qcli.NewSystemUEFIFirmwareDevice(secureBoot) if err != nil { return fmt.Errorf("failed to create a UEFI Firmware Device: %s", err) } - src := uefiDev.Vars + // Import source UEFI Code (if provided) + src := uefiDev.Code + if len(srcCode) > 0 { + src = srcCode + } + // FIXME: create a qcli.UEFICodeFileName + dest := filepath.Join(runDir, "uefi-code.fd") + log.Infof("Importing UEFI Code from '%s' to '%q'", src, dest) + if err := CopyFileBits(src, dest); err != nil { + return fmt.Errorf("Failed to import UEFI Code from '%s' to '%q': %s", src, dest, err) + } + uefiDev.Code = dest + + // Import source UEFI Vxrs (if provided) + src = uefiDev.Vars if len(srcVars) > 0 { src = srcVars } - dest := filepath.Join(runDir, qcli.UEFIVarsFileName) + dest = filepath.Join(runDir, qcli.UEFIVarsFileName) log.Infof("Importing UEFI Vars from '%s' to '%q'", src, dest) + // FIXME: should we skip re-import of srcVars, the imported Vars may have + // had changes that a new import would clobber, warning for now + if PathExists(dest) { + log.Warnf("Already imported UEFI Vars file %q to %q, overwriting...", src, dest) + } if err := CopyFileBits(src, dest); err != nil { return fmt.Errorf("Failed to import UEFI Vars from '%s' to '%q': %s", src, dest, err) } uefiDev.Vars = dest + c.UEFIFirmwareDevices = []qcli.UEFIFirmwareDevice{*uefiDev} return nil } @@ -396,7 +417,7 @@ func GenerateQConfig(runDir, sockDir string, v VMDef) (*qcli.Config, error) { return c, err } - err = ConfigureUEFIVars(c, v.UEFIVars, runDir, v.SecureBoot) + err = ConfigureUEFIVars(c, v.UEFICode, v.UEFIVars, runDir, v.SecureBoot) if err != nil { return c, fmt.Errorf("Error configuring UEFI Vars: %s", err) } diff --git a/pkg/api/vm.go b/pkg/api/vm.go index 5b4008c..934fc18 100644 --- a/pkg/api/vm.go +++ b/pkg/api/vm.go @@ -1,11 +1,9 @@ /* - - Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -67,6 +65,7 @@ type VMDef struct { Disks []QemuDisk `yaml:"disks"` Boot string `yaml:"boot"` Cdrom string `yaml:"cdrom"` + UEFICode string `yaml:"uefi-code"` UEFIVars string `yaml:"uefi-vars"` TPM bool `yaml:"tpm"` TPMVersion string `yaml:"tpm-version"`