Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions scenarios/aws/microVMs/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const (
DDMicroVMLocalWorkingDirectory = "localWorkingDir"
DDMicroVMRemoteWorkingDirectory = "remoteWorkingDir"
DDMicroVMShutdownPeriod = "shutdownPeriod"
DDMicroVMSetupGDB = "setupGDB"
)

var SSHKeyConfigNames = map[string]string{
Expand Down
82 changes: 65 additions & 17 deletions scenarios/aws/microVMs/microvms/domain.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@ import (
"path/filepath"
"runtime"
"strings"
"time"

"github.com/pulumi/pulumi-libvirt/sdk/go/libvirt"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"

"github.com/DataDog/test-infra-definitions/common/config"
"github.com/DataDog/test-infra-definitions/common/namer"
"github.com/DataDog/test-infra-definitions/common/utils"
microvmConfig "github.com/DataDog/test-infra-definitions/scenarios/aws/microVMs/config"
"github.com/DataDog/test-infra-definitions/scenarios/aws/microVMs/microvms/resources"
"github.com/DataDog/test-infra-definitions/scenarios/aws/microVMs/vmconfig"
)
Expand All @@ -21,6 +23,8 @@ const (
dhcpEntriesTemplate = "<host mac='%s' name='%s' ip='%s'/>"
sharedFSMountPoint = "/opt/kernel-version-testing"
maxDomainIDLength = 64
gdbPortRangeStart = 4321
gdbPortRangeEnd = 4421
)

func getNextVMIP(ip *net.IP) net.IP {
Expand All @@ -41,6 +45,7 @@ type Domain struct {
lvDomain *libvirt.Domain
tag string
vmset vmconfig.VMSet
gdbPort int
}

func generateDomainIdentifier(vcpu, memory int, vmsetTags, tag, arch string) string {
Expand Down Expand Up @@ -101,7 +106,7 @@ func getCPUTuneXML(vmcpus, hostCPUSet, cpuCount int) (string, int) {
return fmt.Sprintf("<cputune>%s</cputune>", strings.Join(vcpuMap, "\n")), hostCPUSet
}

func newDomainConfiguration(e config.Env, set *vmconfig.VMSet, vcpu, memory int, kernel vmconfig.Kernel, cputune string) (*Domain, error) {
func newDomainConfiguration(e config.Env, set *vmconfig.VMSet, vcpu, memory, gdbPort int, kernel vmconfig.Kernel, cputune string) (*Domain, error) {
var err error

domain := new(Domain)
Expand Down Expand Up @@ -146,6 +151,12 @@ func newDomainConfiguration(e config.Env, set *vmconfig.VMSet, vcpu, memory int,
hostOS = "linux" // Remote VMs are always on Linux hosts
}

qemuArgs := make(map[string]pulumi.StringInput)
if gdbPort != 0 {
qemuArgs["-gdb"] = pulumi.Sprintf("tcp:127.0.0.1:%d", gdbPort)
domain.gdbPort = gdbPort
}

var driver string
if hostOS == "linux" {
hypervisor = "kvm"
Expand All @@ -155,25 +166,23 @@ func newDomainConfiguration(e config.Env, set *vmconfig.VMSet, vcpu, memory int,
// We have to use QEMU network devices because libvirt does not support the macOS
// network devices.
netID := libvirtResourceName(domainName, "netdev")
qemuArgs := map[string]pulumi.StringInput{
"-netdev": pulumi.Sprintf("vmnet-shared,id=%s", netID),
// Important: use virtio-net-pci instead of virtio-net-device so that the guest has a PCI
// device and that information can be used by udev to rename the device, instead of having eth0.
// This makes the naming consistent across different execution environments and avoids
// problems (for example, DHCP is configured for interfaces starting with en*, so
// if we had eth0 we wouldn't have a network connection)
// Also, configure the PCI address as 17 so that we don't have conflicts with other libvirt controlled devices
"-device": pulumi.Sprintf("virtio-net-pci,netdev=%s,mac=%s,addr=17", netID, domain.mac),
}

for k, v := range qemuArgs {
commandLine = pulumi.Sprintf("%s\n<arg value='%s' />", commandLine, k)
commandLine = pulumi.Sprintf("%s\n<arg value='%s' />", commandLine, v)
}

qemuArgs["-netdev"] = pulumi.Sprintf("vmnet-shared,id=%s", netID)
// Important: use virtio-net-pci instead of virtio-net-device so that the guest has a PCI
// device and that information can be used by udev to rename the device, instead of having eth0.
// This makes the naming consistent across different execution environments and avoids
// problems (for example, DHCP is configured for interfaces starting with en*, so
// if we had eth0 we wouldn't have a network connection)
// Also, configure the PCI address as 17 so that we don't have conflicts with other libvirt controlled devices
qemuArgs["-device"] = pulumi.Sprintf("virtio-net-pci,netdev=%s,mac=%s,addr=17", netID, domain.mac)
driver = "<driver name=\"qemu\" type=\"qcow2\"/>"
}

for k, v := range qemuArgs {
commandLine = pulumi.Sprintf("%s\n<arg value='%s' />", commandLine, k)
commandLine = pulumi.Sprintf("%s\n<arg value='%s' />", commandLine, v)
}

domain.RecipeLibvirtDomainArgs.Xls = rc.GetDomainXLS(
map[string]pulumi.StringInput{
resources.SharedFSMount: pulumi.String(sharedFSMountPoint),
Expand Down Expand Up @@ -227,15 +236,54 @@ func getVolumeDiskTarget(isRootVolume bool, lastDisk string) string {
return fmt.Sprintf("/dev/vd%c", rune(int(lastDisk[len(lastDisk)-1])+1))
}

// isPortFree checks if a given TCP port on localhost in free
func isPortFree(port int) bool {
address := fmt.Sprintf("127.0.0.1:%d", port)
conn, err := net.DialTimeout("tcp", address, 1*time.Second)
if err != nil {
// If there's an error connecting, we assume the port is free
return true
}

conn.Close()
// If connection was successful, port is in use
return false
}

func GenerateDomainConfigurationsForVMSet(e config.Env, providerFn LibvirtProviderFn, depends []pulumi.Resource, set *vmconfig.VMSet, fs *LibvirtFilesystem, cpuSetStart int) ([]*Domain, int, error) {
var domains []*Domain
var cpuTuneXML string

commonEnv, err := config.NewCommonEnvironment(e.Ctx())
if err != nil {
return nil, 0, err
}
m := microvmConfig.NewMicroVMConfig(commonEnv)
setupGDB := m.GetBoolWithDefault(m.MicroVMConfig, microvmConfig.DDMicroVMSetupGDB, false) && set.Arch == LocalVMSet
gdbPort := gdbPortRangeStart

for _, vcpu := range set.VCpu {
for _, memory := range set.Memory {
for _, kernel := range set.Kernels {
cpuTuneXML, cpuSetStart = getCPUTuneXML(vcpu, cpuSetStart, set.VMHost.AvailableCPUs)
domain, err := newDomainConfiguration(e, set, vcpu, memory, kernel, cpuTuneXML)

domainPort := 0
if setupGDB {
for port := gdbPort; port < gdbPortRangeEnd; port++ {
if isPortFree(port) {
domainPort = port
break
}
}

if domainPort == 0 {
return nil, 0, fmt.Errorf("could not find free port in range [%d,%d] for gdb server", gdbPortRangeStart, gdbPortRangeEnd)
}

gdbPort = domainPort + 1 // evaluate another port in the next iteration
}

domain, err := newDomainConfiguration(e, set, vcpu, memory, domainPort, kernel, cpuTuneXML)
if err != nil {
return []*Domain{}, 0, err
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@
<xsl:template match="domain/devices/video" />

<xsl:template match="/domain/devices">
<commandline xmlns="http://libvirt.org/schemas/domain/qemu/1.0">
{commandLine}
</commandline>
<xsl:copy>
<xsl:apply-templates select="node()|@*" />
<xsl:element name="memballoon">
Expand Down
1 change: 1 addition & 0 deletions scenarios/aws/microVMs/microvms/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,7 @@ func exportVMInformation(ctx *pulumi.Context, instances map[string]*Instance, vm
"tag": pulumi.ToOutput(domain.tag),
"vmset-tags": pulumi.ToArrayOutput(tags),
"ssh-key-path": pulumi.ToOutput(filepath.Join(GetWorkingDirectory(domain.vmset.Arch), "ddvm_rsa")),
"gdb-port": pulumi.ToOutput(domain.gdbPort),
}))
}
}
Expand Down
Loading