Skip to content

Commit

Permalink
fix virt-v2v progress
Browse files Browse the repository at this point in the history
Signed-off-by: Bella Khizgiyaev <[email protected]>
  • Loading branch information
bkhizgiy committed May 19, 2024
1 parent 9f1287c commit a618bcb
Show file tree
Hide file tree
Showing 2 changed files with 110 additions and 25 deletions.
9 changes: 7 additions & 2 deletions cmd/virt-v2v-monitor/virt-v2v-monitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package main
import (
"bufio"
"flag"
"fmt"
"net/http"
"os"
"regexp"
Expand All @@ -15,7 +16,7 @@ import (
)

var COPY_DISK_RE = regexp.MustCompile(`^.*Copying disk (\d+)/(\d+)`)
var DISK_PROGRESS_RE = regexp.MustCompile(`^..\s*(\d+)% \[.*\]`)
var DISK_PROGRESS_RE = regexp.MustCompile(`\s+\((\d+).*|.+ (\d+)% \[[*-]+\]`)
var FINISHED_RE = regexp.MustCompile(`^\[[ .0-9]*\] Finishing off`)

// Here is a scan function that imposes limit on returned line length. virt-v2v
Expand Down Expand Up @@ -64,6 +65,7 @@ func main() {

// Start prometheus metrics HTTP handler
klog.Info("Setting up prometheus endpoint :2112/metrics")
klog.Info("this is Bella test")
http.Handle("/metrics", promhttp.Handler())
go http.ListenAndServe(":2112", nil)

Expand Down Expand Up @@ -98,13 +100,16 @@ func main() {
klog.Fatal("Output monitoring failed! ", err)
}

fmt.Println("this is the line we scanning now ", string(line))

if match := COPY_DISK_RE.FindSubmatch(line); match != nil {
diskNumber, _ = strconv.ParseUint(string(match[1]), 10, 0)
disks, _ = strconv.ParseUint(string(match[2]), 10, 0)
klog.Infof("Copying disk %d out of %d", diskNumber, disks)
progress = 0
err = updateProgress(progressCounter, diskNumber, progress)
} else if match := DISK_PROGRESS_RE.FindSubmatch(line); match != nil {
klog.Info("we are here at progress ", line)
progress, _ = strconv.ParseUint(string(match[1]), 10, 0)
klog.Infof("Progress update, completed %d %%", progress)
err = updateProgress(progressCounter, diskNumber, progress)
Expand All @@ -116,7 +121,7 @@ func main() {
err = updateProgress(progressCounter, disk, 100)
}
} else {
klog.V(1).Info("Ignoring line: ", string(line))
klog.Infof("Ignoring line: ", string(line))
}
if err != nil {
// Don't make processing errors fatal.
Expand Down
126 changes: 103 additions & 23 deletions virt-v2v/cold/entrypoint.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
package main

import (
"bufio"
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"os/exec"
"path/filepath"
"regexp"
"strconv"
"strings"
)
Expand All @@ -27,8 +28,8 @@ var (
server *http.Server
)

const LETTERS = "abcdefghijklmnopqrstuvwxyz"
const LETTERS_LENGTH = len(LETTERS)
var UEFI_RE = regexp.MustCompile(`(?i)UEFI\s+bootloader?`)
var firmware = "bios"

func main() {
source := os.Getenv("V2V_source")
Expand All @@ -50,7 +51,7 @@ func main() {
}
}

if err := executeVirtV2v(buildCommand()); err != nil {
if err := executeVirtV2v(source, buildCommand()); err != nil {
fmt.Println("Error executing virt-v2v command ", err)
os.Exit(1)
}
Expand All @@ -63,7 +64,7 @@ func main() {
os.Exit(1)
}

http.HandleFunc("/ovf", ovfHandler)
http.HandleFunc("/vm", vmHandler)
http.HandleFunc("/shutdown", shutdownHandler)
server = &http.Server{Addr: ":8080"}

Expand All @@ -76,7 +77,7 @@ func main() {
}

func buildCommand() []string {
virtV2vArgs := []string{"virt-v2v", "-v", "-x"}
virtV2vArgs := []string{"virt-v2v"}
source := os.Getenv("V2V_source")

if !isValidSource(source) {
Expand Down Expand Up @@ -135,15 +136,6 @@ func buildCommand() []string {
"-io", fmt.Sprintf("vddk-thumbprint=%s", os.Getenv("V2V_fingerprint")),
)
}
var extraArgs []string
if envExtraArgs := os.Getenv("V2V_extra_args"); envExtraArgs != "" {
if err := json.Unmarshal([]byte(envExtraArgs), &extraArgs); err != nil {
fmt.Println("Error parsing extra arguments ", err)
os.Exit(1)
}
}
virtV2vArgs = append(virtV2vArgs, extraArgs...)

virtV2vArgs = append(virtV2vArgs, "--", os.Getenv("V2V_vmName"))
}
return virtV2vArgs
Expand All @@ -163,10 +155,15 @@ func genName(diskNum int) string {
return ""
}

index := (diskNum - 1) % LETTERS_LENGTH
cycles := (diskNum - 1) / LETTERS_LENGTH
letters := "abcdefghijklmnopqrstuvwxyz"
index := (diskNum - 1) % len(letters)
cycles := (diskNum - 1) / len(letters)

return genName(cycles) + string(LETTERS[index])
if cycles == 0 {
return string(letters[index])
} else {
return genName(cycles) + string(letters[index])
}
}

func LinkDisks(diskKind string, num int) (err error) {
Expand Down Expand Up @@ -195,16 +192,26 @@ func LinkDisks(diskKind string, num int) (err error) {
return
}

func executeVirtV2v(args []string) (err error) {
func executeVirtV2v(source string, args []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 {
Expand All @@ -213,7 +220,7 @@ func executeVirtV2v(args []string) (err error) {
}

virtV2vMonitorCmd := exec.Command("/usr/local/bin/virt-v2v-monitor")
virtV2vMonitorCmd.Stdin = tee
virtV2vMonitorCmd.Stdin = virtV2vStdoutPipe
virtV2vMonitorCmd.Stdout = os.Stdout
virtV2vMonitorCmd.Stderr = os.Stderr

Expand All @@ -222,6 +229,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 = "efi"
}
}

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
Expand All @@ -240,13 +267,19 @@ func getXMLFile(dir, fileExtension string) (string, error) {
return "", fmt.Errorf("XML file was not found.")
}

func ovfHandler(w http.ResponseWriter, r *http.Request) {
func vmHandler(w http.ResponseWriter, r *http.Request) {
if xmlFilePath == "" {
fmt.Println("Error: XML file path is empty.")
http.Error(w, "XML file path is empty", http.StatusInternalServerError)
return
}

if err := addFirmwareToXml(xmlFilePath); err != nil {
fmt.Println("Error setting the firmware configuration in the ovf ", err)
http.Error(w, "Error setting the firmware configuration in the ovf", http.StatusInternalServerError)
return
}

xmlData, err := os.ReadFile(xmlFilePath)
if err != nil {
fmt.Printf("Error reading XML file: %v\n", err)
Expand Down Expand Up @@ -281,3 +314,50 @@ func isValidSource(source string) bool {
return false
}
}

func addFirmwareToXml(filePath string) (err error) {
newFirmwareData := fmt.Sprintf(` <firmware>
<bootloader type='%s'/>
</firmware>`, firmware)

file, err := os.Open(filePath)
if err != nil {
return
}
defer file.Close()

tempFilePath := filePath + ".tmp"

tempFile, err := os.Create(tempFilePath)
if err != nil {
return
}
defer tempFile.Close()

scanner := bufio.NewScanner(file)

for scanner.Scan() {
line := scanner.Text()

if _, err = tempFile.WriteString(line + "\n"); err != nil {
return
}

if strings.Contains(line, "</os>") {
if _, err = tempFile.WriteString(newFirmwareData + "\n"); err != nil {
return
}
}
}

if err = scanner.Err(); err != nil {
return
}

if err = os.Rename(tempFilePath, filePath); err != nil {
return
}

fmt.Println("XML file has been modified successfully.")
return
}

0 comments on commit a618bcb

Please sign in to comment.