Prior this commit the ami images were tested locally using qemu. This does not reflect at all how they're used in practice. This commit introduces the support for running them in the actual AWS. Yay! The structure of code reflects that we want to switch to osbuild-composer to build the images soon.
229 lines
5.4 KiB
Go
229 lines
5.4 KiB
Go
// +build integration
|
|
|
|
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
"log"
|
|
"os"
|
|
"os/exec"
|
|
"time"
|
|
)
|
|
|
|
// withNetworkNamespace provides the function f with a new network namespace
|
|
// which is deleted immediately after f returns
|
|
func withNetworkNamespace(f func(ns netNS) error) error {
|
|
ns, err := newNetworkNamespace()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
defer func() {
|
|
err := ns.Delete()
|
|
if err != nil {
|
|
log.Printf("cannot delete network namespace: %#v", err)
|
|
}
|
|
}()
|
|
|
|
return f(ns)
|
|
}
|
|
|
|
// withTempFile provides the function f with a new temporary file
|
|
// dir and pattern parameters have the same semantics as in ioutil.TempFile
|
|
func withTempFile(dir, pattern string, f func(file *os.File) error) error {
|
|
tempFile, err := ioutil.TempFile(dir, pattern)
|
|
if err != nil {
|
|
return fmt.Errorf("cannot create the temporary file: %#v", err)
|
|
}
|
|
|
|
defer func() {
|
|
err := os.Remove(tempFile.Name())
|
|
if err != nil {
|
|
log.Printf("cannot remove the temporary file: %#v", err)
|
|
}
|
|
}()
|
|
|
|
return f(tempFile)
|
|
}
|
|
|
|
func withTempDir(dir, pattern string, f func(dir string) error) error {
|
|
tempDir, err := ioutil.TempDir(dir, pattern)
|
|
if err != nil {
|
|
return fmt.Errorf("cannot create the temporary directory %#v", err)
|
|
}
|
|
|
|
defer func() {
|
|
err := os.RemoveAll(tempDir)
|
|
if err != nil {
|
|
log.Printf("cannot remove the temporary directory: %#v", err)
|
|
}
|
|
}()
|
|
|
|
return f(tempDir)
|
|
}
|
|
|
|
// writeCloudInitSO creates cloud-init iso from specified userData and
|
|
// metaData and writes it to the writer
|
|
func writeCloudInitISO(writer io.Writer, userData, metaData string) error {
|
|
isoCmd := exec.Command(
|
|
"genisoimage",
|
|
"-quiet",
|
|
"-input-charset", "utf-8",
|
|
"-volid", "cidata",
|
|
"-joliet",
|
|
"-rock",
|
|
userData,
|
|
metaData,
|
|
)
|
|
isoCmd.Stdout = writer
|
|
isoCmd.Stderr = os.Stderr
|
|
|
|
err := isoCmd.Run()
|
|
if err != nil {
|
|
return fmt.Errorf("cannot create cloud-init iso: %#v", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// withBootedQemuImage boots the specified image in the specified namespace
|
|
// using qemu. The VM is killed immediately after function returns.
|
|
func withBootedQemuImage(image string, ns netNS, f func() error) error {
|
|
return withTempFile("", "osbuild-image-tests-cloudinit", func(cloudInitFile *os.File) error {
|
|
err := writeCloudInitISO(
|
|
cloudInitFile,
|
|
testPaths.userData,
|
|
testPaths.metaData,
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = cloudInitFile.Close()
|
|
if err != nil {
|
|
return fmt.Errorf("cannot close temporary cloudinit file: %#v", err)
|
|
}
|
|
|
|
qemuCmd := ns.NamespacedCommand(
|
|
"qemu-system-x86_64",
|
|
"-m", "1024",
|
|
"-snapshot",
|
|
"-accel", "accel=kvm:hvf:tcg",
|
|
"-cdrom", cloudInitFile.Name(),
|
|
"-net", "nic,model=rtl8139", "-net", "user,hostfwd=tcp::22-:22",
|
|
"-nographic",
|
|
image,
|
|
)
|
|
|
|
err = qemuCmd.Start()
|
|
if err != nil {
|
|
return fmt.Errorf("cannot start the qemu process: %#v", err)
|
|
}
|
|
|
|
defer func() {
|
|
err := killProcessCleanly(qemuCmd.Process, time.Second)
|
|
if err != nil {
|
|
log.Printf("cannot kill the qemu process: %#v", err)
|
|
}
|
|
}()
|
|
|
|
return f()
|
|
})
|
|
}
|
|
|
|
// withBootedNspawnImage boots the specified image in the specified namespace
|
|
// using nspawn. The VM is killed immediately after function returns.
|
|
func withBootedNspawnImage(image, name string, ns netNS, f func() error) error {
|
|
cmd := exec.Command(
|
|
"systemd-nspawn",
|
|
"--boot", "--register=no",
|
|
"-M", name,
|
|
"--image", image,
|
|
"--network-namespace-path", ns.Path(),
|
|
)
|
|
|
|
err := cmd.Start()
|
|
if err != nil {
|
|
return fmt.Errorf("cannot start the systemd-nspawn process: %#v", err)
|
|
}
|
|
|
|
defer func() {
|
|
err := killProcessCleanly(cmd.Process, time.Second)
|
|
if err != nil {
|
|
log.Printf("cannot kill the systemd-nspawn process: %#v", err)
|
|
}
|
|
}()
|
|
|
|
return f()
|
|
}
|
|
|
|
// withBootedNspawnImage boots the specified directory in the specified namespace
|
|
// using nspawn. The VM is killed immediately after function returns.
|
|
func withBootedNspawnDirectory(dir, name string, ns netNS, f func() error) error {
|
|
cmd := exec.Command(
|
|
"systemd-nspawn",
|
|
"--boot", "--register=no",
|
|
"-M", name,
|
|
"--directory", dir,
|
|
"--network-namespace-path", ns.Path(),
|
|
)
|
|
|
|
err := cmd.Start()
|
|
if err != nil {
|
|
return fmt.Errorf("cannot start the systemd-nspawn process: %#v", err)
|
|
}
|
|
|
|
defer func() {
|
|
err := killProcessCleanly(cmd.Process, time.Second)
|
|
if err != nil {
|
|
log.Printf("cannot kill the systemd-nspawn process: %#v", err)
|
|
}
|
|
}()
|
|
|
|
return f()
|
|
}
|
|
|
|
// withExtractedTarArchive extracts the provided archive and passes
|
|
// a path to the result to the function f. The result is deleted
|
|
// immediately after the function returns.
|
|
func withExtractedTarArchive(archive string, f func(dir string) error) error {
|
|
return withTempDir("", "tar-archive", func(dir string) error {
|
|
cmd := exec.Command(
|
|
"tar",
|
|
"xf", archive,
|
|
"-C", dir,
|
|
)
|
|
cmd.Stderr = os.Stderr
|
|
cmd.Stdout = os.Stdout
|
|
|
|
err := cmd.Run()
|
|
if err != nil {
|
|
return fmt.Errorf("cannot untar the archive: %#v", err)
|
|
}
|
|
|
|
return f(dir)
|
|
})
|
|
}
|
|
|
|
// withSSHKeyPair runs the function f with a newly generated
|
|
// ssh key-pair, they key-pair is deleted immediately after
|
|
// the function f returns
|
|
func withSSHKeyPair(f func(privateKey, publicKey string) error) error {
|
|
return withTempDir("", "keys", func(dir string) error {
|
|
privateKey := dir + "/id_rsa"
|
|
publicKey := dir + "/id_rsa.pub"
|
|
cmd := exec.Command("ssh-keygen",
|
|
"-N", "",
|
|
"-f", privateKey,
|
|
)
|
|
|
|
err := cmd.Run()
|
|
if err != nil {
|
|
return fmt.Errorf("ssh-keygen failed: %#v", err)
|
|
}
|
|
|
|
return f(privateKey, publicKey)
|
|
})
|
|
}
|