Blame cmd/osbuild-image-tests/vmwaretest/vmware.go

Packit 63bb0d
// +build integration
Packit 63bb0d
Packit 63bb0d
package vmwaretest
Packit 63bb0d
Packit 63bb0d
import (
Packit 63bb0d
	"errors"
Packit 63bb0d
	"fmt"
Packit 63bb0d
	"io/ioutil"
Packit 63bb0d
	"os"
Packit 63bb0d
	"os/exec"
Packit 63bb0d
	"path/filepath"
Packit 63bb0d
	"strings"
Packit 63bb0d
Packit 63bb0d
	// importing the packages registers these cli commands
Packit 63bb0d
	"github.com/vmware/govmomi/govc/cli"
Packit 63bb0d
	_ "github.com/vmware/govmomi/govc/datastore"
Packit 63bb0d
	_ "github.com/vmware/govmomi/govc/importx"
Packit 63bb0d
	_ "github.com/vmware/govmomi/govc/vm"
Packit 63bb0d
	_ "github.com/vmware/govmomi/govc/vm/guest"
Packit 63bb0d
)
Packit 63bb0d
Packit 63bb0d
const WaitTimeout = 6000 // in seconds
Packit 63bb0d
Packit 63bb0d
type AuthOptions struct {
Packit 63bb0d
	Host       string
Packit 63bb0d
	Username   string
Packit 63bb0d
	Password   string
Packit 63bb0d
	Datacenter string
Packit 63bb0d
	Cluster    string
Packit 63bb0d
	Network    string
Packit 63bb0d
	Datastore  string
Packit 63bb0d
	Folder     string
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
func AuthOptionsFromEnv() (*AuthOptions, error) {
Packit 63bb0d
	host, hostExists := os.LookupEnv("GOVMOMI_URL")
Packit 63bb0d
	username, userExists := os.LookupEnv("GOVMOMI_USERNAME")
Packit 63bb0d
	password, pwdExists := os.LookupEnv("GOVMOMI_PASSWORD")
Packit 63bb0d
	datacenter, dcExists := os.LookupEnv("GOVMOMI_DATACENTER")
Packit 63bb0d
	cluster, clusterExists := os.LookupEnv("GOVMOMI_CLUSTER")
Packit 63bb0d
	network, netExists := os.LookupEnv("GOVMOMI_NETWORK")
Packit 63bb0d
	datastore, dsExists := os.LookupEnv("GOVMOMI_DATASTORE")
Packit 63bb0d
	folder, folderExists := os.LookupEnv("GOVMOMI_FOLDER")
Packit 63bb0d
Packit 63bb0d
	// If only one/two of them are not set, then fail
Packit 63bb0d
	if !hostExists {
Packit 63bb0d
		return nil, errors.New("GOVMOMI_URL not set")
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	if !userExists {
Packit 63bb0d
		return nil, errors.New("GOVMOMI_USERNAME not set")
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	if !pwdExists {
Packit 63bb0d
		return nil, errors.New("GOVMOMI_PASSWORD not set")
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	if !dcExists {
Packit 63bb0d
		return nil, errors.New("GOVMOMI_DATACENTER not set")
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	if !clusterExists {
Packit 63bb0d
		return nil, errors.New("GOVMOMI_CLUSTER not set")
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	if !netExists {
Packit 63bb0d
		return nil, errors.New("GOVMOMI_NETWORK not set")
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	if !dsExists {
Packit 63bb0d
		return nil, errors.New("GOVMOMI_DATASTORE not set")
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	if !folderExists {
Packit 63bb0d
		return nil, errors.New("GOVMOMI_FOLDER not set")
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	return &AuthOptions{
Packit 63bb0d
		Host:       host,
Packit 63bb0d
		Username:   username,
Packit 63bb0d
		Password:   password,
Packit 63bb0d
		Datacenter: datacenter,
Packit 63bb0d
		Cluster:    cluster,
Packit 63bb0d
		Network:    network,
Packit 63bb0d
		Datastore:  datastore,
Packit 63bb0d
		Folder:     folder,
Packit 63bb0d
	}, nil
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
func ImportImage(creds *AuthOptions, imagePath, imageName string) error {
Packit 63bb0d
	args := []string{
Packit 63bb0d
		"import.vmdk",
Packit 63bb0d
		fmt.Sprintf("-u=%s:%s@%s", creds.Username, creds.Password, creds.Host),
Packit 63bb0d
		"-k=true",
Packit 63bb0d
		fmt.Sprintf("-dc=%s", creds.Datacenter),
Packit 63bb0d
		fmt.Sprintf("-ds=%s", creds.Datastore),
Packit 63bb0d
		imagePath,
Packit 63bb0d
		imageName,
Packit 63bb0d
	}
Packit 63bb0d
	retcode := cli.Run(args)
Packit 63bb0d
Packit 63bb0d
	if retcode != 0 {
Packit 63bb0d
		return errors.New("importing vmdk failed")
Packit 63bb0d
	}
Packit 63bb0d
	return nil
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
func DeleteImage(creds *AuthOptions, directoryName string) error {
Packit 63bb0d
	retcode := cli.Run([]string{
Packit 63bb0d
		"datastore.rm",
Packit 63bb0d
		"-f=true",
Packit 63bb0d
		fmt.Sprintf("-u=%s:%s@%s", creds.Username, creds.Password, creds.Host),
Packit 63bb0d
		"-k=true",
Packit 63bb0d
		fmt.Sprintf("-dc=%s", creds.Datacenter),
Packit 63bb0d
		fmt.Sprintf("-ds=%s", creds.Datastore),
Packit 63bb0d
		directoryName + "*", // because vm.create creates another directory with _1 prefix
Packit 63bb0d
	})
Packit 63bb0d
Packit 63bb0d
	if retcode != 0 {
Packit 63bb0d
		return errors.New("deleting directory failed")
Packit 63bb0d
	}
Packit 63bb0d
	return nil
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
func runWithStdout(args []string) (string, int) {
Packit 63bb0d
	oldStdout := os.Stdout
Packit 63bb0d
	r, w, _ := os.Pipe()
Packit 63bb0d
	os.Stdout = w
Packit 63bb0d
Packit 63bb0d
	retcode := cli.Run(args)
Packit 63bb0d
Packit 63bb0d
	w.Close()
Packit 63bb0d
	out, _ := ioutil.ReadAll(r)
Packit 63bb0d
	os.Stdout = oldStdout
Packit 63bb0d
Packit 63bb0d
	return strings.TrimSpace(string(out)), retcode
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
func WithBootedImage(creds *AuthOptions, imagePath, imageName, publicKey string, f func(address string) error) (retErr error) {
Packit 63bb0d
	vmdkBaseName := filepath.Base(imagePath)
Packit 63bb0d
Packit 63bb0d
	args := []string{
Packit 63bb0d
		"vm.create",
Packit 63bb0d
		fmt.Sprintf("-u=%s:%s@%s", creds.Username, creds.Password, creds.Host),
Packit 63bb0d
		"-k=true",
Packit 63bb0d
		fmt.Sprintf("-dc=%s", creds.Datacenter),
Packit 63bb0d
		fmt.Sprintf("-ds=%s", creds.Datastore),
Packit 63bb0d
		fmt.Sprintf("-folder=%s", creds.Folder),
Packit 63bb0d
		fmt.Sprintf("-net=%s", creds.Network),
Packit 63bb0d
		"-m=2048", "-g=rhel8_64Guest", "-on=true", "-firmware=bios",
Packit 63bb0d
		fmt.Sprintf("-disk=%s/%s", imageName, vmdkBaseName),
Packit 63bb0d
		"--disk.controller=ide",
Packit 63bb0d
		imageName,
Packit 63bb0d
	}
Packit 63bb0d
	retcode := cli.Run(args)
Packit 63bb0d
	if retcode != 0 {
Packit 63bb0d
		return errors.New("Creating VM from vmdk failed")
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	defer func() {
Packit 63bb0d
		args = []string{
Packit 63bb0d
			"vm.destroy",
Packit 63bb0d
			fmt.Sprintf("-u=%s:%s@%s", creds.Username, creds.Password, creds.Host),
Packit 63bb0d
			"-k=true",
Packit 63bb0d
			imageName,
Packit 63bb0d
		}
Packit 63bb0d
		retcode := cli.Run(args)
Packit 63bb0d
Packit 63bb0d
		if retcode != 0 {
Packit 63bb0d
			fmt.Printf("Deleting VM %s failed", imageName)
Packit 63bb0d
			return
Packit 63bb0d
		}
Packit 63bb0d
	}()
Packit 63bb0d
Packit 63bb0d
	// note: by default this will wait/block until an IP address is returned
Packit 63bb0d
	// note: using exec() instead of running the command b/c .Run() returns an int
Packit 63bb0d
	args = []string{
Packit 63bb0d
		"vm.ip",
Packit 63bb0d
		fmt.Sprintf("-u=%s:%s@%s", creds.Username, creds.Password, creds.Host),
Packit 63bb0d
		"-k=true",
Packit 63bb0d
		imageName,
Packit 63bb0d
	}
Packit 63bb0d
	ipAddress, retcode := runWithStdout(args)
Packit 63bb0d
Packit 63bb0d
	if retcode != 0 {
Packit 63bb0d
		return errors.New("Getting IP address for VM failed")
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	// Disabled b/c of https://github.com/vmware/govmomi/issues/2054
Packit 63bb0d
	// upload public key on the VM
Packit 63bb0d
	//args = []string{
Packit 63bb0d
	//	"guest.mkdir",
Packit 63bb0d
	//	fmt.Sprintf("-u=%s:%s@%s", creds.Username, creds.Password, creds.Host),
Packit 63bb0d
	//	"-k=true",
Packit 63bb0d
	//	fmt.Sprintf("-vm=%s", imageName),
Packit 63bb0d
	//	"-p", "/root/.ssh",
Packit 63bb0d
	//}
Packit 63bb0d
	//retcode = cli.Run(args)
Packit 63bb0d
	//if retcode != 0 {
Packit 63bb0d
	//	return errors.New("mkdir /root/.ssh on VM failed")
Packit 63bb0d
	//}
Packit 63bb0d
Packit 63bb0d
	//args = []string{
Packit 63bb0d
	//	"guest.upload",
Packit 63bb0d
	//	fmt.Sprintf("-u=%s:%s@%s", creds.Username, creds.Password, creds.Host),
Packit 63bb0d
	//	"-k=true",
Packit 63bb0d
	//	fmt.Sprintf("-vm=%s", imageName),
Packit 63bb0d
	//	"-f=true",
Packit 63bb0d
	//	publicKey, // this is a file path
Packit 63bb0d
	//	"/root/.ssh/authorized_keys",
Packit 63bb0d
	//}
Packit 63bb0d
	//retcode = cli.Run(args)
Packit 63bb0d
	//if retcode != 0 {
Packit 63bb0d
	//	return errors.New("Uploading public key to VM failed")
Packit 63bb0d
	//}
Packit 63bb0d
Packit 63bb0d
	return f(ipAddress)
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// hard-coded SSH keys b/c we're having troubles uploading publicKey
Packit 63bb0d
// to the VM, see https://github.com/vmware/govmomi/issues/2054
Packit 63bb0d
func WithSSHKeyPair(f func(privateKey, publicKey string) error) error {
Packit 63bb0d
	public := "/usr/share/tests/osbuild-composer/keyring/id_rsa.pub"
Packit 63bb0d
	private := "/usr/share/tests/osbuild-composer/keyring/id_rsa"
Packit 63bb0d
Packit 63bb0d
	return f(private, public)
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
func ConvertToStreamOptimizedVmdk(imagePath string) (string, error) {
Packit 63bb0d
	optimizedVmdk, err := ioutil.TempFile("/var/tmp", "osbuild-composer-stream-optimized-*.vmdk")
Packit 63bb0d
	if err != nil {
Packit 63bb0d
		return "", err
Packit 63bb0d
	}
Packit 63bb0d
	optimizedVmdk.Close()
Packit 63bb0d
Packit 63bb0d
	cmd := exec.Command(
Packit 63bb0d
		"/usr/bin/qemu-img", "convert", "-O", "vmdk", "-o", "subformat=streamOptimized",
Packit 63bb0d
		imagePath, optimizedVmdk.Name())
Packit 63bb0d
	err = cmd.Run()
Packit 63bb0d
	if err != nil {
Packit 63bb0d
		return "", err
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	return optimizedVmdk.Name(), nil
Packit 63bb0d
}