From 2c5cc783ecffe732e7f52b99672d79517fecd5b5 Mon Sep 17 00:00:00 2001 From: Bella Khizgiyaev Date: Tue, 5 Mar 2024 10:14:33 +0200 Subject: [PATCH] OVA: workaround for virt-v2v firmware detection Signed-off-by: Bella Khizgiyaev --- pkg/controller/plan/BUILD.bazel | 1 - pkg/controller/plan/kubevirt.go | 15 ++++----- virt-v2v/cold/entrypoint.go | 54 ++++++++++++++++++++++++++++++--- 3 files changed, 55 insertions(+), 15 deletions(-) diff --git a/pkg/controller/plan/BUILD.bazel b/pkg/controller/plan/BUILD.bazel index dfabf6820..d98417dff 100644 --- a/pkg/controller/plan/BUILD.bazel +++ b/pkg/controller/plan/BUILD.bazel @@ -23,7 +23,6 @@ go_library( "//pkg/controller/base", "//pkg/controller/plan/adapter", "//pkg/controller/plan/adapter/base", - "//pkg/controller/plan/adapter/ova", "//pkg/controller/plan/context", "//pkg/controller/plan/handler", "//pkg/controller/plan/scheduler", diff --git a/pkg/controller/plan/kubevirt.go b/pkg/controller/plan/kubevirt.go index 77be3a86d..23baa708f 100644 --- a/pkg/controller/plan/kubevirt.go +++ b/pkg/controller/plan/kubevirt.go @@ -34,7 +34,6 @@ import ( "github.com/konveyor/forklift-controller/pkg/apis/forklift/v1beta1/plan" "github.com/konveyor/forklift-controller/pkg/apis/forklift/v1beta1/ref" "github.com/konveyor/forklift-controller/pkg/controller/plan/adapter" - ovfparser "github.com/konveyor/forklift-controller/pkg/controller/plan/adapter/ova" plancontext "github.com/konveyor/forklift-controller/pkg/controller/plan/context" libcnd "github.com/konveyor/forklift-controller/pkg/lib/condition" liberr "github.com/konveyor/forklift-controller/pkg/lib/error" @@ -860,7 +859,7 @@ func (r *KubeVirt) UpdateVmByConvertedConfig(vm *plan.VMStatus, pod *core.Pod, s return } - url := fmt.Sprintf("http://%s:8080/ovf", pod.Status.PodIP) + url := fmt.Sprintf("http://%s:8080/firmware", pod.Status.PodIP) /* Due to the virt-v2v operation, the ovf file is only available after the command's execution, meaning it appears following the copydisks phase. @@ -878,17 +877,15 @@ func (r *KubeVirt) UpdateVmByConvertedConfig(vm *plan.VMStatus, pod *core.Pod, s } defer resp.Body.Close() - vmConfigXML, err := io.ReadAll(resp.Body) + vmFirmware, err := io.ReadAll(resp.Body) if err != nil { return } - firmware, err := ovfparser.GetFirmwareFromConfig(string(vmConfigXML)) - if err != nil { - return - } - - vm.Firmware = firmware + vm.Firmware = string(vmFirmware) + r.Log.Info("Setting the vm fimware", + "vm", + vm.String()) shutdownURL := fmt.Sprintf("http://%s:8080/shutdown", pod.Status.PodIP) resp, err = http.Post(shutdownURL, "application/json", nil) diff --git a/virt-v2v/cold/entrypoint.go b/virt-v2v/cold/entrypoint.go index c98f3217a..5163d8921 100644 --- a/virt-v2v/cold/entrypoint.go +++ b/virt-v2v/cold/entrypoint.go @@ -1,6 +1,7 @@ package main import ( + "bufio" "context" "fmt" "io" @@ -8,6 +9,7 @@ import ( "os" "os/exec" "path/filepath" + "regexp" "strconv" ) @@ -20,6 +22,9 @@ const ( VDDK = "/opt/vmware-vix-disklib-distrib" ) +var UEFI_RE = regexp.MustCompile(`(?i)UEFI\s+bootloader?`) +var firmware = "bios" + var ( xmlFilePath string server *http.Server @@ -97,7 +102,7 @@ func main() { virtV2vArgs = append(virtV2vArgs, "--", os.Getenv("V2V_vmName")) } - if err := executeVirtV2v(virtV2vArgs); err != nil { + if err := executeVirtV2v(virtV2vArgs, source); err != nil { fmt.Println("Error executing virt-v2v command ", err) os.Exit(1) } @@ -111,6 +116,7 @@ func main() { } http.HandleFunc("/ovf", ovfHandler) + http.HandleFunc("/firmware", firmwareHandler) http.HandleFunc("/shutdown", shutdownHandler) server = &http.Server{Addr: ":8080"} @@ -169,16 +175,26 @@ func LinkDisks(diskKind string, num int) (err error) { return } -func executeVirtV2v(args []string) (err error) { +func executeVirtV2v(args []string, source string) (err error) { virtV2vCmd := exec.Command(args[0], args[1:]...) virtV2vStdoutPipe, err := virtV2vCmd.StdoutPipe() if err != nil { fmt.Printf("Error setting up stdout pipe: %v\n", err) return } + teeOut := io.TeeReader(virtV2vStdoutPipe, os.Stdout) - tee := io.TeeReader(virtV2vStdoutPipe, os.Stdout) - virtV2vCmd.Stderr = os.Stderr + var teeErr io.Reader + if source == OVA { + virtV2vStderrPipe, err := virtV2vCmd.StderrPipe() + if err != nil { + fmt.Printf("Error setting up stdout pipe: %v\n", err) + return err + } + teeErr = io.TeeReader(virtV2vStderrPipe, os.Stderr) + } else { + virtV2vCmd.Stderr = os.Stderr + } fmt.Println("exec ", virtV2vCmd) if err = virtV2vCmd.Start(); err != nil { @@ -187,7 +203,7 @@ func executeVirtV2v(args []string) (err error) { } virtV2vMonitorCmd := exec.Command("/usr/local/bin/virt-v2v-monitor") - virtV2vMonitorCmd.Stdin = tee + virtV2vMonitorCmd.Stdin = teeOut virtV2vMonitorCmd.Stdout = os.Stdout virtV2vMonitorCmd.Stderr = os.Stderr @@ -196,6 +212,26 @@ func executeVirtV2v(args []string) (err error) { return } + if source == OVA { + scanner := bufio.NewScanner(teeErr) + const maxCapacity = 1024 * 1024 + buf := make([]byte, 0, 64*1024) + scanner.Buffer(buf, maxCapacity) + + for scanner.Scan() { + line := scanner.Bytes() + if match := UEFI_RE.FindSubmatch(line); match != nil { + fmt.Println("UEFI firmware detected") + firmware = "uefi" + } + } + + if err = scanner.Err(); err != nil { + fmt.Println("Output query failed:", err) + return err + } + } + if err = virtV2vCmd.Wait(); err != nil { fmt.Printf("Error waiting for virt-v2v to finish: %v\n", err) return @@ -236,7 +272,15 @@ func ovfHandler(w http.ResponseWriter, r *http.Request) { fmt.Printf("Error writing response: %v\n", err) http.Error(w, "Error writing response", http.StatusInternalServerError) } +} +func firmwareHandler(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "text/plain") + if _, err := w.Write([]byte(firmware)); err != nil { + fmt.Printf("Error writing response: %v\n", err) + http.Error(w, "Error writing response", http.StatusInternalServerError) + return + } } func shutdownHandler(w http.ResponseWriter, r *http.Request) {