145 lines
3.3 KiB
Go
145 lines
3.3 KiB
Go
|
package powerdns
|
||
|
|
||
|
import (
|
||
|
"errors"
|
||
|
"log"
|
||
|
"net/http"
|
||
|
"strings"
|
||
|
"time"
|
||
|
|
||
|
"go.dev.pztrn.name/hosts-translator/internal/configuration"
|
||
|
"go.dev.pztrn.name/hosts-translator/internal/parser"
|
||
|
)
|
||
|
|
||
|
var ErrPowerDNSStorageError = errors.New("powerdns storage")
|
||
|
|
||
|
// PowerDNS is a controlling structure for PowerDNS storage.
|
||
|
type PowerDNS struct {
|
||
|
parser *parser.Parser
|
||
|
|
||
|
httpClient *http.Client
|
||
|
}
|
||
|
|
||
|
// NewPowerDNS creates new PowerDNS storage.
|
||
|
func NewPowerDNS(p *parser.Parser) *PowerDNS {
|
||
|
s := &PowerDNS{
|
||
|
parser: p,
|
||
|
}
|
||
|
|
||
|
s.initialize()
|
||
|
|
||
|
return s
|
||
|
}
|
||
|
|
||
|
// Initializes storage internal state.
|
||
|
func (s *PowerDNS) initialize() {
|
||
|
s.httpClient = &http.Client{
|
||
|
Timeout: time.Second * 5,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Process processes parsed data.
|
||
|
func (s *PowerDNS) Process() error {
|
||
|
log.Println("Processing parsed data into PowerDNS storage...")
|
||
|
|
||
|
zoneData, err := s.getZoneData(configuration.DomainPostfix)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
hostsParsedData := s.parser.GetParsedData()
|
||
|
|
||
|
// Check what we should to create, update or delete.
|
||
|
recordsToCreate := make([]RRSet, 0)
|
||
|
recordsToDelete := make([]RRSet, 0)
|
||
|
recordsToUpdate := make([]RRSet, 0)
|
||
|
|
||
|
// First iteration - figure out what to create or update.
|
||
|
for _, hostData := range hostsParsedData {
|
||
|
var found bool
|
||
|
|
||
|
for _, rrset := range zoneData.RRSets {
|
||
|
// We're only for A or AAAA things here.
|
||
|
if strings.ToUpper(rrset.Type) != "A" && strings.ToUpper(rrset.Type) != "AAAA" {
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
// ToDo: multiple addresses support somehow?
|
||
|
if strings.TrimSuffix(rrset.Name, ".") == hostData.Domain {
|
||
|
found = true
|
||
|
|
||
|
if rrset.Records[0].Content != hostData.Address {
|
||
|
recordsToUpdate = append(recordsToUpdate, RRSet{
|
||
|
ChangeType: "REPLACE",
|
||
|
Name: rrset.Name,
|
||
|
Records: []Record{
|
||
|
{
|
||
|
Content: hostData.Address,
|
||
|
},
|
||
|
},
|
||
|
TTL: 300,
|
||
|
Type: rrset.Type,
|
||
|
})
|
||
|
}
|
||
|
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if !found {
|
||
|
recordsToCreate = append(recordsToCreate, RRSet{
|
||
|
ChangeType: "REPLACE",
|
||
|
Name: hostData.Domain + ".",
|
||
|
Records: []Record{
|
||
|
{
|
||
|
Content: hostData.Address,
|
||
|
},
|
||
|
},
|
||
|
TTL: 300,
|
||
|
// ToDo: support for AAAA?
|
||
|
Type: "A",
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Second iteration - figure out what to delete.
|
||
|
for _, rrset := range zoneData.RRSets {
|
||
|
// We're only for A or AAAA things here.
|
||
|
if strings.ToUpper(rrset.Type) != "A" || strings.ToUpper(rrset.Type) != "AAAA" {
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
var found bool
|
||
|
|
||
|
for _, hostData := range hostsParsedData {
|
||
|
if strings.TrimSuffix(rrset.Name, ".") == hostData.Domain+"." {
|
||
|
found = true
|
||
|
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if !found {
|
||
|
rrset.ChangeType = "DELETE"
|
||
|
recordsToDelete = append(recordsToDelete, rrset)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
log.Println("Got", len(zoneData.RRSets), "RRSets in NS")
|
||
|
log.Println("Got", len(recordsToCreate), "RRSets to create")
|
||
|
log.Println("Got", len(recordsToUpdate), "RRSets to update")
|
||
|
log.Println("Got", len(recordsToDelete), "RRSets to delete")
|
||
|
|
||
|
recordsUnchanged := len(zoneData.RRSets) - len(recordsToDelete) - len(recordsToUpdate)
|
||
|
log.Println("Got", recordsUnchanged, "RRSets unchanged")
|
||
|
|
||
|
// ToDo: '-debug'?
|
||
|
log.Printf("Got RRSets to create: %+v\n", recordsToCreate)
|
||
|
// log.Printf("Got RRSets to update: %+v\n", recordsToUpdate)
|
||
|
// log.Printf("Got RRSets to delete: %+v\n", recordsToDelete)
|
||
|
|
||
|
s.updateZoneData(zoneData.Name, append(recordsToCreate, append(recordsToUpdate, recordsToDelete...)...))
|
||
|
|
||
|
return nil
|
||
|
}
|