Skip to content

Commit

Permalink
check boot of vm with ssh connection
Browse files Browse the repository at this point in the history
  • Loading branch information
lukas016 committed Mar 15, 2024
1 parent 615412e commit 0bc3690
Show file tree
Hide file tree
Showing 5 changed files with 200 additions and 12 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ test: manifests generate fmt vet envtest ## Run tests. Some test depend on Linux

.PHONY: integration-tests
integration-tests: ## Run integration tests against code. For dependencies, refer to the integration-test workflow.
go run github.com/onsi/ginkgo/v2/ginkgo run -r --label-filter="integration" -coverprofile cover.out
go run github.com/onsi/ginkgo/v2/ginkgo run -r --label-filter="integration" -coverprofile cover.out -v

##@ Documentation

Expand Down
1 change: 0 additions & 1 deletion provider/server/exec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import (
)

var _ = Describe("Exec", func() {

It("should verify an exec-url with a token", func(ctx SpecContext) {
By("creating the test machine")
createResp, err := machineClient.CreateMachine(ctx, &iri.CreateMachineRequest{
Expand Down
26 changes: 17 additions & 9 deletions provider/server/machine_volume_detach_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import (
"libvirt.org/go/libvirtxml"
)

var _ = Describe("DetachVolume", func() {
var _ = FDescribe("DetachVolume", Ordered, func() {
It("should correctly detach volume from machine", func(ctx SpecContext) {
By("creating a machine with two empty disks and single ceph volume")
createResp, err := machineClient.CreateMachine(ctx, &iri.CreateMachineRequest{
Expand All @@ -28,9 +28,15 @@ var _ = Describe("DetachVolume", func() {
Spec: &iri.MachineSpec{
Power: iri.Power_POWER_ON,
Image: &iri.ImageSpec{
Image: osImage,
Image: squashfsOSImage,
},
Class: machineClassx3xlarge,
NetworkInterfaces: []*iri.NetworkInterface{
{
Name: "eth0",
NetworkId: networkID.Name,
},
},
Volumes: []*iri.Volume{
{
Name: "disk-1",
Expand All @@ -46,7 +52,7 @@ var _ = Describe("DetachVolume", func() {
},
Device: "odb",
},
{
/*{
Name: "volume-1",
Device: "odc",
Connection: &iri.VolumeConnection{
Expand All @@ -61,7 +67,7 @@ var _ = Describe("DetachVolume", func() {
"userKey": []byte(cephUserkey),
},
},
},
},*/
},
},
},
Expand Down Expand Up @@ -121,11 +127,11 @@ var _ = Describe("DetachVolume", func() {
Handle: "libvirt-provider.ironcore.dev/empty-disk/disk-2",
State: iri.VolumeState_VOLUME_ATTACHED,
},
&iri.VolumeStatus{
/*&iri.VolumeStatus{
Name: "volume-1",
Handle: "libvirt-provider.ironcore.dev/ceph/libvirt-provider.ironcore.dev/ceph^dummy",
State: iri.VolumeState_VOLUME_ATTACHED,
})),
}*/)),
HaveField("State", Equal(iri.MachineState_MACHINE_RUNNING)),
))

Expand All @@ -138,13 +144,15 @@ var _ = Describe("DetachVolume", func() {
g.Expect(domainXML.Unmarshal(domainXMLData)).Should(Succeed())
disks = domainXML.Devices.Disks
return len(disks)
}).Should(Equal(4))
}).Should(Equal(3))
Expect(disks[0].Serial).To(HavePrefix("oda"))
Expect(disks[1].Serial).To(HavePrefix("odb"))
Expect(disks[2].Serial).To(HavePrefix("odc"))
//Expect(disks[2].Serial).To(HavePrefix("odc"))

// wait to complete machine reconciliation
time.Sleep(20 * time.Second)
Eventually(func(g Gomega) {
isDomainVMUpAndRunning(g, libvirtConn, &domain, &networkID)
}).WithTimeout(2 * time.Minute).WithPolling(2 * time.Second).Should(Succeed())

By("detaching empty disk disk-1 from machine")
diskDetachResp, err := machineClient.DetachVolume(ctx, &iri.DetachVolumeRequest{
Expand Down
9 changes: 8 additions & 1 deletion provider/server/server_suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ var (
cephImage = os.Getenv("CEPH_IMAGE")
cephUsername = os.Getenv("CEPH_USERNAME")
cephUserkey = os.Getenv("CEPH_USERKEY")
networkID = libvirt.Network{Name: "default"}
)

func TestServer(t *testing.T) {
Expand Down Expand Up @@ -95,7 +96,7 @@ var _ = BeforeSuite(func() {
DeferCleanup(os.Remove, machineClassesFile.Name())

pluginOpts := networkinterfaceplugin.NewDefaultOptions()
pluginOpts.PluginName = "isolated"
pluginOpts.PluginName = "providernet"

tempDir = GinkgoT().TempDir()
Expect(os.Chmod(tempDir, 0730)).Should(Succeed())
Expand Down Expand Up @@ -146,7 +147,13 @@ var _ = BeforeSuite(func() {
libvirtConn = libvirt.NewWithDialer(c)
Expect(libvirtConn.Connect()).To(Succeed())
Expect(libvirtConn.IsConnected(), BeTrue())

Expect(createOrGetNetwork(&networkID)).NotTo(HaveOccurred())

DeferCleanup(libvirtConn.ConnectClose)
DeferCleanup(func() {
Expect(deleteNetwork(libvirtConn, &networkID)).Should(Succeed())
})
})

func isSocketAvailable(socketPath string) error {
Expand Down
174 changes: 174 additions & 0 deletions provider/server/testutils_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
// SPDX-FileCopyrightText: 2023 SAP SE or an SAP affiliate company and IronCore contributors
// SPDX-License-Identifier: Apache-2.0

package server_test

import (
"fmt"
"net"
"time"

"github.com/digitalocean/go-libvirt"
"github.com/onsi/gomega"
"libvirt.org/go/libvirtxml"
)

func getAnyDomainIPForNetwork(libvirtConn *libvirt.Libvirt, network *libvirt.Network, domain *libvirt.Domain) (string, error) {
domainXMLData, err := libvirtConn.DomainGetXMLDesc(*domain, 0)
if err != nil {
return "", err
}

domainXML := &libvirtxml.Domain{}
err = domainXML.Unmarshal(domainXMLData)
if err != nil {
return "", nil
}

mac, err := getDomainMAC(domainXML, network.Name)
if err != nil {
return "", nil
}

leases, _, err := libvirtConn.NetworkGetDhcpLeases(*network, libvirt.OptString{mac}, 1, 0)
if err != nil {
return "", err
}

// return first ip
for _, lease := range leases {
if lease.Mac[0] == mac {
return lease.Ipaddr, nil
}
}

return "", fmt.Errorf("failed to find ip address for domain %s", domain.Name)
}

func getDomainMAC(domain *libvirtxml.Domain, networkName string) (string, error) {
for _, netIF := range domain.Devices.Interfaces {
if isInterfaceInSpecificNetwork(netIF.Source, networkName) && isMACValid(netIF.MAC) {
return netIF.MAC.Address, nil
}
}

return "", fmt.Errorf("failed to find mac adress for network %s", networkName)

Check failure on line 55 in provider/server/testutils_test.go

View workflow job for this annotation

GitHub Actions / lint

`adress` is a misspelling of `address` (misspell)
}

func isInterfaceInSpecificNetwork(source *libvirtxml.DomainInterfaceSource, networkName string) bool {
return source != nil && source.Network != nil && source.Network.Network == networkName
}

func isMACValid(mac *libvirtxml.DomainInterfaceMAC) bool {
return mac != nil && mac.Address != ""
}

func isSSHListenToDefualtPort(ip string) bool {
timeout := time.Second
conn, err := net.DialTimeout("tcp", net.JoinHostPort(ip, "22"), timeout)
if err != nil {
return false
}

if conn != nil {
// tests aren't long running so we can ignore errors
_ = conn.Close()
return true
}

return false
}

func isDomainVMUpAndRunning(g gomega.Gomega, libvirtConn *libvirt.Libvirt, domain *libvirt.Domain, network *libvirt.Network) {
ip, err := getAnyDomainIPForNetwork(libvirtConn, network, domain)
g.Expect(err).NotTo(gomega.HaveOccurred())
g.Expect(isSSHListenToDefualtPort(ip)).Should(gomega.BeTrue())
}

func createOrGetNetwork(networkID *libvirt.Network) error {
currentNetwork, err := libvirtConn.NetworkLookupByName(networkID.Name)
if err != nil {
libvirtErr, ok := err.(libvirt.Error)
if !ok {
return err
}

if libvirtErr.Code != uint32(libvirt.ErrNoNetwork) {
return err
}

newNetworkXML, err := generateDefaultNetworkXML(networkID.Name)
if err != nil {
return err
}

newNetworkID, err := libvirtConn.NetworkDefineXML(newNetworkXML)
if err != nil {
return err
}

networkID.UUID = newNetworkID.UUID
} else {
networkID.UUID = currentNetwork.UUID
}

// start existing network
active, err := libvirtConn.NetworkIsActive(*networkID)
if err != nil {
return fmt.Errorf("failed to get network '%s' active state: %w", networkID.Name, err)
}

if active == 1 {
return nil
}

// create and start defined network
err = libvirtConn.NetworkCreate(*networkID)
if err != nil {
return fmt.Errorf("failed to start network '%s': %w", networkID.Name, err)
}

return nil
}

func generateDefaultNetworkXML(name string) (string, error) {
newNetwork := libvirtxml.Network{
Name: name,
Forward: &libvirtxml.NetworkForward{
Mode: "nat",
NAT: &libvirtxml.NetworkForwardNAT{
Ports: []libvirtxml.NetworkForwardNATPort{{Start: 1024, End: 65535}},
},
},
IPs: []libvirtxml.NetworkIP{
{
Address: "192.168.168.1",
Netmask: "255.255.255.0",
DHCP: &libvirtxml.NetworkDHCP{
Ranges: []libvirtxml.NetworkDHCPRange{
{
Start: "192.168.168.2",
End: "192.168.168.254",
},
},
},
},
},
Bridge: &libvirtxml.NetworkBridge{
Name: "virbrtest0",
STP: "on",
Delay: "0",
},
}

return newNetwork.Marshal()
}

func deleteNetwork(libvirtConn *libvirt.Libvirt, networkID *libvirt.Network) error {
err := libvirtConn.NetworkDestroy(*networkID)
if err != nil {
return err
}

return libvirtConn.NetworkUndefine(*networkID)
}

0 comments on commit 0bc3690

Please sign in to comment.