Skip to content

Commit

Permalink
zone manager: Handle exisitng SOA serial use case
Browse files Browse the repository at this point in the history
When zone manager is created, if zone file already exist and contains SOA serial,
then the next SOA serial should continue the existing one.

Signed-off-by: Diana Teplits <dteplits@redhat.com>
  • Loading branch information
dteplits committed Dec 21, 2022
1 parent 27f994c commit 26a3f6c
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 20 deletions.
7 changes: 6 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,12 @@ func main() {
os.Exit(1)
}

zoneManager := zonemgr.NewZoneManager()
zoneManager, err := zonemgr.NewZoneManager()
if err != nil {
setupLog.Error(err, "unable to create zone manager")
os.Exit(1)
}

if err = (&controllers.VirtualMachineInstanceReconciler{
Client: mgr.GetClient(),
Log: ctrl.Log.WithName("controllers").WithName("VirtualMachineInstance"),
Expand Down
45 changes: 45 additions & 0 deletions pkg/zonemgr/zone_file.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
package zonemgr

import (
"errors"
"fmt"
"os"
"regexp"
"strconv"
)

const zoneFilePerm = 0644

var soaSerialReg = regexp.MustCompile("SOA .*\\(([0-9]+) ")

type ZoneFile struct {
zoneFileFullName string
}
Expand All @@ -19,3 +25,42 @@ func NewZoneFile(fileName string) *ZoneFile {
func (zoneFile *ZoneFile) writeFile(content string) (err error) {
return os.WriteFile(zoneFile.zoneFileFullName, []byte(content), zoneFilePerm)
}

func (zoneFile *ZoneFile) readFile() ([]byte, error) {
return os.ReadFile(zoneFile.zoneFileFullName)
}

func (zoneFile *ZoneFile) isFileExist() (bool, error) {
var err error
isExist := false
if _, err = os.Stat(zoneFile.zoneFileFullName); err == nil {
isExist = true
} else if errors.Is(err, os.ErrNotExist) {
err = nil
}
return isExist, err
}

func (zoneFile *ZoneFile) ReadSoaSerial() (*int, error) {
if isFileExist, err := zoneFile.isFileExist(); !isFileExist || err != nil {
return nil, err
}
if content, err := zoneFile.readFile(); content == nil || err != nil {
return nil, err
} else {
return fetchSoaSerial(string(content))
}
}

func fetchSoaSerial(content string) (*int, error) {
if result := soaSerialReg.FindStringSubmatch(content); result != nil && len(result) > 0 {
soaSerial := result[1]
if soaSerialInt, err := strconv.Atoi(soaSerial); err == nil {
return &soaSerialInt, nil
} else {
return nil, err
}
} else {
return nil, errors.New(fmt.Sprintf("failed to fetch SOA serial value from the zone file content: %s", content))
}
}
16 changes: 7 additions & 9 deletions pkg/zonemgr/zone_file_cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ const (
expire = "1209600" // 2 weeks (seconds) - how long a nameserver should wait prior to considering data from a secondary zone invalid and stop answering queries for that zone
ttl = "3600" // 1 hour (seconds) - the duration that the record may be cached by any resolver

domainDefault = "vm"
nameServerDefault = "ns"
adminEmailDefault = "email"
)
Expand All @@ -40,10 +39,16 @@ type ZoneFileCache struct {
vmiRecordsMap map[string][]string
}

func NewZoneFileCache(nameServerIP string, domain string) *ZoneFileCache {
func NewZoneFileCache(nameServerIP string, domain string, soaSerial *int) *ZoneFileCache {
soaSerialInt := 0
if soaSerial != nil {
soaSerialInt = *soaSerial
}

zoneFileCache := &ZoneFileCache{
nameServerIP: nameServerIP,
domain: domain,
soaSerial: soaSerialInt,
}
zoneFileCache.prepare()
return zoneFileCache
Expand All @@ -53,18 +58,11 @@ func (zoneFileCache *ZoneFileCache) prepare() {
zoneFileCache.initCustomFields()
zoneFileCache.generateHeaderPrefix()
zoneFileCache.generateHeaderSuffix()
zoneFileCache.soaSerial = 0
zoneFileCache.header = zoneFileCache.generateHeader()
zoneFileCache.content = zoneFileCache.header
zoneFileCache.vmiRecordsMap = make(map[string][]string)
}

func (zoneFileCache *ZoneFileCache) initCustomFields() {
if zoneFileCache.domain == "" {
zoneFileCache.domain = domainDefault
} else {
zoneFileCache.domain = fmt.Sprintf("%s.%s", domainDefault, zoneFileCache.domain)
}
zoneFileCache.nameServerName = fmt.Sprintf("%s.%s", nameServerDefault, zoneFileCache.domain)
zoneFileCache.adminEmail = fmt.Sprintf("%s.%s", adminEmailDefault, zoneFileCache.domain)
}
Expand Down
29 changes: 19 additions & 10 deletions pkg/zonemgr/zone_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,18 @@ package zonemgr

import (
"errors"
"fmt"
"os"

k8stypes "k8s.io/apimachinery/pkg/types"

v1 "kubevirt.io/api/core/v1"
)

const (
zoneFileName = "/zones/db."
envVarDomain = "DOMAIN"
envVarNameServerIP = "NAME_SERVER_IP"
zoneFileNamePrefix = "/zones/db."
domainDefault = "vm"
)

type SecIfaceData struct {
Expand All @@ -27,19 +28,27 @@ type ZoneManager struct {
zoneFile *ZoneFile
}

func NewZoneManager() *ZoneManager {
func NewZoneManager() (*ZoneManager, error) {
zoneMgr := &ZoneManager{}
zoneMgr.prepare()
return zoneMgr
err := zoneMgr.prepare()
return zoneMgr, err
}

func (zoneMgr *ZoneManager) prepare() {
domain := os.Getenv(envVarDomain)
func (zoneMgr *ZoneManager) prepare() error {
domain := domainDefault
nameServerIP := os.Getenv(envVarNameServerIP)
if customDomain := os.Getenv(envVarDomain); customDomain != "" {
domain = fmt.Sprintf("%s.%s", domain, customDomain)
}
zoneFileName := zoneFileNamePrefix + domain
zoneMgr.zoneFile = NewZoneFile(zoneFileName)

zoneMgr.zoneFileCache = NewZoneFileCache(nameServerIP, domain)

zoneMgr.zoneFile = NewZoneFile(zoneFileName + zoneMgr.zoneFileCache.domain)
soaSerial, err := zoneMgr.zoneFile.ReadSoaSerial()
if err != nil {
return err
}
zoneMgr.zoneFileCache = NewZoneFileCache(nameServerIP, domain, soaSerial)
return nil
}

func (zoneMgr *ZoneManager) UpdateZone(namespacedName k8stypes.NamespacedName, interfaces []v1.VirtualMachineInstanceNetworkInterface) error {
Expand Down

0 comments on commit 26a3f6c

Please sign in to comment.