Skip to content

Commit

Permalink
Merge pull request #65 from AlonaKaplan/defaultRecord
Browse files Browse the repository at this point in the history
Add a default A record for each VM
  • Loading branch information
kubevirt-bot authored Oct 8, 2023
2 parents b2ae26f + 7970921 commit eb90ade
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 14 deletions.
19 changes: 17 additions & 2 deletions pkg/zonemgr/internal/zone-file-cache/zone_file_cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package zone_file_cache
import (
"fmt"
"reflect"
"regexp"
"sort"
"strconv"

Expand All @@ -22,6 +23,8 @@ const (
adminEmailDefault = "email"
)

var aRecordRegex = regexp.MustCompile(`IN A ([\d.]+)`)

type ZoneFileCache struct {
soaSerial int
adminEmail string
Expand Down Expand Up @@ -114,20 +117,32 @@ func buildARecordsArr(name string, namespace string, interfaces []v1.VirtualMach
IPs := iface.IPs
for _, IP := range IPs {
if net.IsIPv4String(IP) {
recordsArr = append(recordsArr, generateARecord(name, namespace, iface.Name, IP))
recordsArr = append(recordsArr, generateIfaceARecord(name, namespace, iface.Name, IP))
break
}
}
}
sort.Strings(recordsArr)
if len(recordsArr) > 0 {
recordsArr = append(recordsArr, generateDefaultARecord(name, namespace, getIPFromARecord(recordsArr[0])))
}
return recordsArr
}

func generateARecord(name string, namespace string, ifaceName string, ifaceIP string) string {
func generateIfaceARecord(name string, namespace string, ifaceName string, ifaceIP string) string {
fqdn := fmt.Sprintf("%s.%s.%s", ifaceName, name, namespace)
return fmt.Sprintf("%s IN A %s\n", fqdn, ifaceIP)
}

func generateDefaultARecord(name string, namespace string, ifaceIP string) string {
fqdn := fmt.Sprintf("%s.%s", name, namespace)
return fmt.Sprintf("%s IN A %s\n", fqdn, ifaceIP)
}

func getIPFromARecord(record string) string {
return aRecordRegex.FindStringSubmatch(record)[1]
}

func (zoneFileCache ZoneFileCache) generateARecords() string {
aRecords := ""
for _, recordsArr := range zoneFileCache.vmiRecordsMap {
Expand Down
39 changes: 29 additions & 10 deletions pkg/zonemgr/internal/zone-file-cache/zone_file_cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ var _ = Describe("cached zone file content maintenance", func() {
nic4IP = "13.14.15.16"
IPv6 = "fe80::74c8:f2ff:fe5f:ff2b"

aRecordFmt = "%s.%s.%s IN A %s\n"
aRecordFmt = "%s.%s.%s IN A %s\n"
defaultARecordFmt = "%s.%s IN A %s\n"

updated = true
notUpdated = false
Expand All @@ -81,6 +82,11 @@ var _ = Describe("cached zone file content maintenance", func() {

aRecord_nic3_vm1_ns2 = fmt.Sprintf(aRecordFmt, nic3Name, vmi1Name, namespace2, nic3IP)
aRecord_nic4_vm1_ns2 = fmt.Sprintf(aRecordFmt, nic4Name, vmi1Name, namespace2, nic4IP)

defARecord_nic1_vm1_ns1 = fmt.Sprintf(defaultARecordFmt, vmi1Name, namespace1, nic1IP)
defARecord_nic1_vm2_ns1 = fmt.Sprintf(defaultARecordFmt, vmi2Name, namespace1, nic1IP)
defARecord_nic3_vm2_ns1 = fmt.Sprintf(defaultARecordFmt, vmi2Name, namespace1, nic3IP)
defARecord_nic3_vm1_ns2 = fmt.Sprintf(defaultARecordFmt, vmi1Name, namespace2, nic3IP)
)

validateUpdateFunc := func(vmiName, vmiNamespace string, newInterfaces []v1.VirtualMachineInstanceNetworkInterface,
Expand All @@ -102,7 +108,7 @@ var _ = Describe("cached zone file content maintenance", func() {
namespace1,
[]v1.VirtualMachineInstanceNetworkInterface{{IPs: []string{nic1IP}, Name: nic1Name}},
updated,
aRecord_nic1_vm1_ns1,
aRecord_nic1_vm1_ns1+defARecord_nic1_vm1_ns1,
1,
),
Entry("when non existing vmi is deleted",
Expand Down Expand Up @@ -142,8 +148,10 @@ var _ = Describe("cached zone file content maintenance", func() {
updated,
aRecord_nic1_vm1_ns1+
aRecord_nic2_vm1_ns1+
defARecord_nic1_vm1_ns1+
aRecord_nic3_vm2_ns1+
aRecord_nic4_vm2_ns1,
aRecord_nic4_vm2_ns1+
defARecord_nic3_vm2_ns1,
2,
),
Entry("when existing vmi is deleted",
Expand All @@ -160,7 +168,8 @@ var _ = Describe("cached zone file content maintenance", func() {
[]v1.VirtualMachineInstanceNetworkInterface{{IPs: []string{nic1IP}, Name: nic1Name}, {IPs: []string{nic4IP}, Name: nic4Name}},
updated,
aRecord_nic1_vm1_ns1+
aRecord_nic4_vm1_ns1,
aRecord_nic4_vm1_ns1+
defARecord_nic1_vm1_ns1,
2,
),
Entry("when existing vmi is not changed but its interfaces order is changed",
Expand All @@ -169,7 +178,8 @@ var _ = Describe("cached zone file content maintenance", func() {
[]v1.VirtualMachineInstanceNetworkInterface{{IPs: []string{nic2IP}, Name: nic2Name}, {IPs: []string{nic1IP}, Name: nic1Name}},
notUpdated,
aRecord_nic1_vm1_ns1+
aRecord_nic2_vm1_ns1,
aRecord_nic2_vm1_ns1+
defARecord_nic1_vm1_ns1,
1,
),
)
Expand Down Expand Up @@ -197,7 +207,10 @@ var _ = Describe("cached zone file content maintenance", func() {
aRecord_nic1_vm2_ns1+
aRecord_nic2_vm2_ns1+
aRecord_nic3_vm1_ns2+
aRecord_nic4_vm1_ns2,
aRecord_nic4_vm1_ns2+
defARecord_nic1_vm1_ns1+
defARecord_nic1_vm2_ns1+
defARecord_nic3_vm1_ns2,
3,
),
Entry("when existing vmi is deleted",
Expand All @@ -206,7 +219,8 @@ var _ = Describe("cached zone file content maintenance", func() {
nil,
updated,
aRecord_nic1_vm2_ns1+
aRecord_nic2_vm2_ns1,
aRecord_nic2_vm2_ns1+
defARecord_nic1_vm2_ns1,
3,
),
Entry("when existing vmi interfaces list is changed",
Expand All @@ -216,8 +230,10 @@ var _ = Describe("cached zone file content maintenance", func() {
updated,
aRecord_nic1_vm1_ns1+
aRecord_nic4_vm1_ns1+
defARecord_nic1_vm1_ns1+
aRecord_nic1_vm2_ns1+
aRecord_nic2_vm2_ns1,
aRecord_nic2_vm2_ns1+
defARecord_nic1_vm2_ns1,
3,
),
Entry("when existing vmi is not changed but its interfaces order is changed",
Expand All @@ -228,7 +244,9 @@ var _ = Describe("cached zone file content maintenance", func() {
aRecord_nic2_vm1_ns1+
aRecord_nic1_vm1_ns1+
aRecord_nic1_vm2_ns1+
aRecord_nic2_vm2_ns1,
aRecord_nic2_vm2_ns1+
defARecord_nic1_vm1_ns1+
defARecord_nic1_vm2_ns1,
2,
),
)
Expand All @@ -246,7 +264,8 @@ var _ = Describe("cached zone file content maintenance", func() {
[]v1.VirtualMachineInstanceNetworkInterface{{IPs: []string{nic1IP, IPv6}, Name: nic1Name}, {IPs: []string{nic2IP, IPv6}, Name: nic2Name}},
updated,
aRecord_nic1_vm1_ns1+
aRecord_nic2_vm1_ns1,
aRecord_nic2_vm1_ns1+
defARecord_nic1_vm1_ns1,
1,
),
Entry("vmi interfaces contain IPv6 only",
Expand Down
23 changes: 21 additions & 2 deletions tests/vm_startup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,19 +88,38 @@ var _ = Describe("Virtual Machines Startup", func() {
var nslookupOutput []byte
Eventually(func() error {
var nslookupErr error
nslookupOutput, nslookupErr = exec.Command("nslookup", fmt.Sprintf("-port=%s", dnsPort), fmt.Sprintf("%s.%s.%s.%s.", interfaceName, vmiName, testNamespace, domain), dnsIP).CombinedOutput()
nslookupOutput, nslookupErr = nslookup(fmt.Sprintf("%s.%s.%s.%s.", interfaceName, vmiName, testNamespace, domain))
if nslookupErr != nil {
nslookupErr = fmt.Errorf("err: %v, output: %s", nslookupErr, nslookupOutput)
}
return nslookupErr
}, time.Minute, pollingInterval).ShouldNot(HaveOccurred(), "nslookup failed")

By("Comparing the VirtualMachineInstance IP to the nslookup result")
Expect(nslookupOutput).To(ContainSubstring(fmt.Sprintf("Address: %s\n", vmiIp)), fmt.Sprintf("nsloookup doesn't return the VMI IP address - %s. nslookup output - %s", vmiIp, nslookupOutput))
verifyIPInOutput(nslookupOutput, vmiIp)

By("Invoking nslookup on the VMI default FQDN")
defaultNslookupOuput, err := nslookup(fmt.Sprintf("%s.%s.%s.", vmiName, testNamespace, domain))
Expect(err).ToNot(HaveOccurred(), "failed nslookup the default VMI FQDN")

By("Comparing the VirtualMachineInstance IP to the default nslookup result")
verifyIPInOutput(defaultNslookupOuput, vmiIp)
})
})
})

func verifyIPInOutput(output []byte, vmiIp string) bool {
return ExpectWithOffset(1, output).To(ContainSubstring(fmt.Sprintf("Address: %s\n", vmiIp)), fmt.Sprintf("nsloookup doesn't return the VMI IP address - %s. nslookup output - %s", vmiIp, output))
}

func nslookup(fqdn string) ([]byte, error) {
output, err := exec.Command("nslookup", fmt.Sprintf("-port=%s", dnsPort), fqdn, dnsIP).CombinedOutput()
if err != nil {
return output, fmt.Errorf("err: %v, output: %s", err, output)
}
return output, nil
}

func createNetworkAttachmentDefinition(namespace, name string) error {
nad := networkv1.NetworkAttachmentDefinition{
ObjectMeta: metav1.ObjectMeta{
Expand Down

0 comments on commit eb90ade

Please sign in to comment.