Skip to content

Commit

Permalink
Change virt-v2v bash script to use go wrapper.
Browse files Browse the repository at this point in the history
Signed-off-by: Bella Khizgiyaev <[email protected]>
  • Loading branch information
bkhizgiy committed Feb 15, 2024
1 parent 0e672a4 commit 171377e
Show file tree
Hide file tree
Showing 3 changed files with 236 additions and 104 deletions.
23 changes: 20 additions & 3 deletions virt-v2v/cold/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
load(
"@io_bazel_rules_docker//container:container.bzl",
"container_image",
Expand Down Expand Up @@ -89,15 +90,31 @@ container_image(
visibility = ["//visibility:public"],
)

go_library(
name = "cold_lib",
srcs = ["entrypoint.go"],
importpath = "github.com/konveyor/forklift-controller/virt-v2v/cold",
visibility = ["//visibility:private"],
)

go_binary(
name = "virt-v2v-wrapper",
embed = [":cold_lib"],
visibility = ["//visibility:public"],
)

container_image(
name = "forklift-virt-v2v",
base = ":virt-v2v-layer",
directory = "/usr/local/bin/",
empty_dirs = ["/disks"],
entrypoint = ["/usr/local/bin/entrypoint"],
env = {"LIBGUESTFS_BACKEND": "direct"},
entrypoint = ["/usr/local/bin/virt-v2v-wrapper"],
env = {
"LIBGUESTFS_BACKEND": "direct",
"LIBGUESTFS_PATH": "/usr/lib64/guestfs/appliance",
},
files = [
"entrypoint",
":virt-v2v-wrapper",
"@forklift//cmd/image-converter",
"@forklift//cmd/virt-v2v-monitor",
],
Expand Down
101 changes: 0 additions & 101 deletions virt-v2v/cold/entrypoint

This file was deleted.

216 changes: 216 additions & 0 deletions virt-v2v/cold/entrypoint.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
package main

import (
"context"
"fmt"
"net/http"
"os"
"os/exec"
"path/filepath"
"strconv"
"strings"
)

const (
OVA = "ova"
vSphere = "vSphere"
DIR = "/var/tmp/v2v"
FS = "/mnt/disks/disk[0-9]*"
Block = "/dev/block[0-9]*"
VDDK = "/opt/vmware-vix-disklib-distrib"
)

var (
xmlFilePath string
server *http.Server
)

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

requiredEnvVars := map[string][]string{
vSphere: {"V2V_libvirtURL", "V2V_secretKey", "V2V_vmName"},
OVA: {"V2V_diskPath", "V2V_vmName"},
}

if envVars, ok := requiredEnvVars[source]; ok {
if !checkEnvVariablesSet(envVars...) {
fmt.Printf("Following environment variables need to be defined: %v\n", envVars)
os.Exit(1)
}
}

switch source {
case vSphere:
virtV2vArgs = append(virtV2vArgs, "-i", "libvirt", "-ic", os.Getenv("V2V_libvirtURL"))
if _, err := os.Stat("/etc/secret/cacert"); err == nil {
err = os.Symlink("/etc/secret/cacert", "/opt/ca-bundle.crt")
if err != nil {
fmt.Println("Error creating ca cert link ", err)
os.Exit(1)
}
} else {
err := os.Symlink("/etc/pki/tls/certs/ca-bundle.crt.bak", "/opt/ca-bundle.crt")
if err != nil {
fmt.Println("Error creating ca cert link ", err)
os.Exit(1)
}
}
virtV2vArgs = append(virtV2vArgs, "-ip /etc/secret/secretKey")

if info, err := os.Stat(VDDK); err == nil && info.IsDir() {
virtV2vArgs = append(virtV2vArgs,
"-it", "vddk",
"-io", fmt.Sprintf("vddk-libdir=%s", VDDK),
"-io", fmt.Sprintf("vddk-thumbprint=%s", os.Getenv("V2V_fingerprint")),
)
}
virtV2vArgs = append(virtV2vArgs, "--", os.Getenv("V2V_vmName"))
case OVA:
virtV2vArgs = append(virtV2vArgs, "-i", "ova", os.Getenv("V2V_diskPath"))
}

fmt.Println("Preparing virt-v2v")
if err := os.MkdirAll(DIR, os.ModePerm); err != nil {
fmt.Println("Error creating directory ", err)
os.Exit(1)
}
virtV2vArgs = append(virtV2vArgs, "-o", "local", "-os", DIR)

//Disks on filesystem storage.
if err := LinkDisks(FS, 15); err != nil {
os.Exit(1)
}
//Disks on block storage.
if err := LinkDisks(Block, 10); err != nil {
os.Exit(1)
}

if err := executeVirtV2v(virtV2vArgs); err != nil {
fmt.Println("Error executing virt-v2v command ", err)
os.Exit(1)
}

if source == OVA {
var err error
xmlFilePath, err = getXMLFile(DIR, "xml")
if err != nil {
fmt.Println("Error gettin XML file:", err)
os.Exit(1)
}

http.HandleFunc("/xml", xmlHandler)
http.HandleFunc("/shutdown", shutdownHandler)
server = &http.Server{Addr: ":8080"}

fmt.Println("Starting server on :8080")
if err := server.ListenAndServe(); err != http.ErrServerClosed {
fmt.Printf("Error starting server: %v\n", err)
os.Exit(1)
}
}
}

func checkEnvVariablesSet(envVars ...string) bool {
for _, v := range envVars {
if os.Getenv(v) == "" {
return false
}
}
return true
}

func genName(diskNum int) string {
if diskNum <= 0 {
return ""
}

letters := []int32("abcdefghijklmnopqrstuvwxyz")
index := (diskNum - 1) % len(letters)
cycels := (diskNum - 1) % len(letters)

return genName(cycels) + string(letters[index])
}

func LinkDisks(diskKind string, num int) (err error) {
disks, err := filepath.Glob(diskKind)
if err != nil {
fmt.Println("Error getting disks ", err)
return
}

for _, disk := range disks {
diskNum, err := strconv.Atoi(disk[num:])
if err != nil {
fmt.Println("Error geting disks names ", err)
return err
}
diskLink := fmt.Sprintf("%s/%s-sd%s", DIR, os.Getenv("V2V_vmName"), genName(diskNum+1))
diskImgPath := disk
if diskKind == FS {
diskImgPath = fmt.Sprintf("%s/disk.img", disk)
}
if err = os.Symlink(diskImgPath, diskLink); err != nil {
fmt.Println("Error creating disk link ", err)
return err
}
}
return
}

func executeVirtV2v(args []string) (err error) {
virtV2vCmd := exec.Command("bash", "-c", strings.Join(args, " "), "|& /usr/local/bin/virt-v2v-monitor")
virtV2vCmd.Stdout = os.Stdout
virtV2vCmd.Stderr = os.Stderr
if err = virtV2vCmd.Run(); err != nil {
fmt.Printf("Error executing command: %v\n", err)
}
return
}

func getXMLFile(dir, fileExtension string) (string, error) {
files, err := filepath.Glob(filepath.Join(dir, "*."+fileExtension))
if err != nil {
return "", err
}
if len(files) > 0 {
return files[0], nil
}
return "", fmt.Errorf("XML file was not found.")
}

func xmlHandler(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
}

xmlData, err := os.ReadFile(xmlFilePath)
if err != nil {
fmt.Printf("Error reading XML file: %v\n", err)
http.Error(w, "Error reading XML file", http.StatusInternalServerError)
return
}

w.Header().Set("Content-Type", "application/xml")
_, err = w.Write(xmlData)
if err == nil {
w.WriteHeader(http.StatusOK)
} else {
fmt.Printf("Error writing response: %v\n", err)
http.Error(w, "Error writing response", http.StatusInternalServerError)
}

}

func shutdownHandler(w http.ResponseWriter, r *http.Request) {
fmt.Println("Shutdown request received. Shutting down server.")
err := server.Shutdown(context.Background())
if err != nil {
fmt.Printf("Error shutting down server: %v\n", err)
} else {
fmt.Println("Server shut down successfully.")
}
}

0 comments on commit 171377e

Please sign in to comment.