Rework engine to apply changes at the end & add pushover notification
This commit is contained in:
parent
4b1861fa9b
commit
50dcc9d994
6 changed files with 186 additions and 57 deletions
|
|
@ -1,2 +1,5 @@
|
||||||
DRY_RUN=true
|
DRY_RUN=true
|
||||||
HETZNER_API_TOKEN=token-goes-here
|
HETZNER_API_TOKEN=token-goes-here
|
||||||
|
PUSHOVER_ENABLE=false
|
||||||
|
PUSHOVER_APP_KEY=key-goes-here
|
||||||
|
PUSHOVER_USER_KEY=key-goes-here
|
||||||
1
go.mod
1
go.mod
|
|
@ -12,6 +12,7 @@ require (
|
||||||
github.com/go-logfmt/logfmt v0.6.0 // indirect
|
github.com/go-logfmt/logfmt v0.6.0 // indirect
|
||||||
github.com/golobby/cast v1.3.3 // indirect
|
github.com/golobby/cast v1.3.3 // indirect
|
||||||
github.com/golobby/dotenv v1.3.2 // indirect
|
github.com/golobby/dotenv v1.3.2 // indirect
|
||||||
|
github.com/gregdel/pushover v1.3.1 // indirect
|
||||||
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
|
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
github.com/miekg/dns v1.1.63 // indirect
|
github.com/miekg/dns v1.1.63 // indirect
|
||||||
|
|
|
||||||
2
go.sum
2
go.sum
|
|
@ -19,6 +19,8 @@ github.com/golobby/cast v1.3.3 h1:s2Lawb9RMz7YyYf8IrfMQY4IFmA1R/lgfmj97Vc6fig=
|
||||||
github.com/golobby/cast v1.3.3/go.mod h1:0oDO5IT84HTXcbLDf1YXuk0xtg/cRDrxhbpWKxwtJCY=
|
github.com/golobby/cast v1.3.3/go.mod h1:0oDO5IT84HTXcbLDf1YXuk0xtg/cRDrxhbpWKxwtJCY=
|
||||||
github.com/golobby/dotenv v1.3.2 h1:9vA8XqXXIB3cX/5xQ1CTbOCPegioHtHXIxeFng+uOqQ=
|
github.com/golobby/dotenv v1.3.2 h1:9vA8XqXXIB3cX/5xQ1CTbOCPegioHtHXIxeFng+uOqQ=
|
||||||
github.com/golobby/dotenv v1.3.2/go.mod h1:9MMVXqzLNluhVxCv3X/DLYBNUb289f05tr+df1+7278=
|
github.com/golobby/dotenv v1.3.2/go.mod h1:9MMVXqzLNluhVxCv3X/DLYBNUb289f05tr+df1+7278=
|
||||||
|
github.com/gregdel/pushover v1.3.1 h1:4bMLITOZ15+Zpi6qqoGqOPuVHCwSUvMCgVnN5Xhilfo=
|
||||||
|
github.com/gregdel/pushover v1.3.1/go.mod h1:EcaO66Nn1StkpEm1iKtBTV3d2A16SoMsVER1PthX7to=
|
||||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,11 @@ type Config struct {
|
||||||
Hetzner struct {
|
Hetzner struct {
|
||||||
ApiToken string `env:"HETZNER_API_TOKEN"`
|
ApiToken string `env:"HETZNER_API_TOKEN"`
|
||||||
}
|
}
|
||||||
|
PushOver struct {
|
||||||
|
Enable bool `env:"PUSHOVER_ENABLE"`
|
||||||
|
AppKey string `env:"PUSHOVER_APP_KEY"`
|
||||||
|
UserKey string `env:"PUSHOVER_USER_KEY"`
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var configParsed bool
|
var configParsed bool
|
||||||
|
|
|
||||||
44
helpers/pushover.go
Normal file
44
helpers/pushover.go
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
package helpers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/gregdel/pushover"
|
||||||
|
)
|
||||||
|
|
||||||
|
type PushoverMessage struct {
|
||||||
|
AppKey string
|
||||||
|
UserKey string
|
||||||
|
Title string
|
||||||
|
Message string
|
||||||
|
}
|
||||||
|
|
||||||
|
func PushoverSendMessage(message PushoverMessage) error {
|
||||||
|
if len(message.AppKey) == 0 {
|
||||||
|
return fmt.Errorf("pushover app key is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(message.UserKey) == 0 {
|
||||||
|
return fmt.Errorf("pushover user key is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(message.Message) == 0 {
|
||||||
|
return fmt.Errorf("pushover message is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
app := pushover.New(message.AppKey)
|
||||||
|
user := pushover.NewRecipient(message.UserKey)
|
||||||
|
|
||||||
|
var msg *pushover.Message
|
||||||
|
if len(message.Title) > 0 {
|
||||||
|
msg = pushover.NewMessageWithTitle(
|
||||||
|
message.Message,
|
||||||
|
message.Title,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
msg = pushover.NewMessage(message.Message)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := app.SendMessage(msg, user)
|
||||||
|
return err
|
||||||
|
}
|
||||||
176
main.go
176
main.go
|
|
@ -1,6 +1,7 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"slices"
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
|
@ -96,7 +97,16 @@ func main() {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info("Starting sync (step 1: create/update)", "dry_run", config.DryRun)
|
// Keep operations in these slices
|
||||||
|
// Sync is only performed after diff calculation is done
|
||||||
|
var recordsToCreate []hetzner.Record
|
||||||
|
var recordsToUpdate []hetzner.Record
|
||||||
|
var recordsToDelete []hetzner.Record
|
||||||
|
|
||||||
|
// PushOver message, will only be sent if PushOver enabled and message not empty
|
||||||
|
var pushoverMessages []string
|
||||||
|
|
||||||
|
log.Info("Calculating sync diff (step 1: create/update)")
|
||||||
var keepTheseIds []string
|
var keepTheseIds []string
|
||||||
for _, zone := range zones {
|
for _, zone := range zones {
|
||||||
if zone.DefaultTTL <= 0 {
|
if zone.DefaultTTL <= 0 {
|
||||||
|
|
@ -105,7 +115,7 @@ func main() {
|
||||||
|
|
||||||
for _, hZone := range hZones {
|
for _, hZone := range hZones {
|
||||||
if strings.EqualFold(zone.Domain, hZone.Name) {
|
if strings.EqualFold(zone.Domain, hZone.Name) {
|
||||||
log.Info("Syncing zone", "step", 1, "name", zone.Domain)
|
log.Info("Calculating sync diff for zone", "name", zone.Domain)
|
||||||
|
|
||||||
var alreadyFoundIds []string
|
var alreadyFoundIds []string
|
||||||
for _, record := range zone.Records {
|
for _, record := range zone.Records {
|
||||||
|
|
@ -162,14 +172,15 @@ func main() {
|
||||||
|
|
||||||
if updateNeeded {
|
if updateNeeded {
|
||||||
log.Info(
|
log.Info(
|
||||||
"Updating record",
|
"Marking record for update",
|
||||||
|
"id", id,
|
||||||
"name", record.Name,
|
"name", record.Name,
|
||||||
"type", record.Type,
|
"type", record.Type,
|
||||||
"id", id,
|
"value", record.Value,
|
||||||
|
"ttl", record.TTL,
|
||||||
)
|
)
|
||||||
|
|
||||||
if !config.DryRun {
|
recordsToUpdate = append(recordsToUpdate, hetzner.Record{
|
||||||
newRecord, err := hetzner.UpdateRecord(&hetzner.Record{
|
|
||||||
ID: id,
|
ID: id,
|
||||||
Type: record.Type,
|
Type: record.Type,
|
||||||
Name: record.Name,
|
Name: record.Name,
|
||||||
|
|
@ -177,85 +188,148 @@ func main() {
|
||||||
TTL: record.TTL,
|
TTL: record.TTL,
|
||||||
ZoneID: hZone.ID,
|
ZoneID: hZone.ID,
|
||||||
})
|
})
|
||||||
if err != nil {
|
|
||||||
log.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Info(
|
pushoverMessages = append(pushoverMessages, fmt.Sprintf(
|
||||||
"Record updated",
|
"Action: update\nZone: %s\nRecord: %s\nType: %s\nValue: %s\nTTL: %d",
|
||||||
"ID", newRecord.ID,
|
zone.Domain,
|
||||||
)
|
record.Name,
|
||||||
}
|
record.Type,
|
||||||
|
record.Value,
|
||||||
|
record.TTL,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log.Info(
|
log.Info(
|
||||||
"Creating record",
|
"Marking record for creation",
|
||||||
|
"zone_id", hZone.ID,
|
||||||
"name", record.Name,
|
"name", record.Name,
|
||||||
"type", record.Type,
|
"type", record.Type,
|
||||||
"value", record.Value,
|
"value", record.Value,
|
||||||
"ttl", record.TTL,
|
"ttl", record.TTL,
|
||||||
)
|
)
|
||||||
|
|
||||||
if !config.DryRun {
|
recordsToCreate = append(recordsToCreate, hetzner.Record{
|
||||||
newRecord, err := hetzner.CreateRecord(&hetzner.Record{
|
|
||||||
Type: record.Type,
|
Type: record.Type,
|
||||||
Name: record.Name,
|
Name: record.Name,
|
||||||
Value: record.Value,
|
Value: record.Value,
|
||||||
TTL: record.TTL,
|
TTL: record.TTL,
|
||||||
ZoneID: hZone.ID,
|
ZoneID: hZone.ID,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
pushoverMessages = append(pushoverMessages, fmt.Sprintf(
|
||||||
|
"Action: create\nZone: %s\nRecord: %s\nType: %s\nValue: %s\nTTL: %d",
|
||||||
|
zone.Domain,
|
||||||
|
record.Name,
|
||||||
|
record.Type,
|
||||||
|
record.Value,
|
||||||
|
record.TTL,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("Calculating sync diff (step 2: delete)")
|
||||||
|
for _, zone := range zones {
|
||||||
|
for _, hZone := range hZones {
|
||||||
|
if strings.EqualFold(zone.Domain, hZone.Name) {
|
||||||
|
log.Info("Calculating sync diff for zone", "name", zone.Domain)
|
||||||
|
|
||||||
|
for _, hRecord := range hZone.Records {
|
||||||
|
if !slices.Contains(keepTheseIds, hRecord.ID) {
|
||||||
|
log.Info(
|
||||||
|
"Marking record for deletion",
|
||||||
|
"id", hRecord.ID,
|
||||||
|
"name", hRecord.Name,
|
||||||
|
"type", hRecord.Type,
|
||||||
|
"value", hRecord.Value,
|
||||||
|
"ttl", hRecord.TTL,
|
||||||
|
)
|
||||||
|
|
||||||
|
recordsToDelete = append(recordsToDelete, hetzner.Record{
|
||||||
|
ID: hRecord.ID,
|
||||||
|
})
|
||||||
|
|
||||||
|
pushoverMessages = append(pushoverMessages, fmt.Sprintf(
|
||||||
|
"Action: delete\nZone: %s\nRecord: %s\nType: %s\nValue: %s\nTTL: %d",
|
||||||
|
hZone.Name,
|
||||||
|
hRecord.Name,
|
||||||
|
hRecord.Type,
|
||||||
|
hRecord.Value,
|
||||||
|
hRecord.TTL,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("Starting sync (step 1: delete)", "dry_run", config.DryRun)
|
||||||
|
for _, record := range recordsToDelete {
|
||||||
|
if !config.DryRun {
|
||||||
|
hetzner.DeleteRecord(&record)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info(
|
log.Warn(
|
||||||
|
"Record deleted",
|
||||||
|
"ID", record.ID,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("Starting sync (step 2: create)", "dry_run", config.DryRun)
|
||||||
|
for _, record := range recordsToCreate {
|
||||||
|
if !config.DryRun {
|
||||||
|
newRecord, err := hetzner.UpdateRecord(&record)
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Warn(
|
||||||
"Record created",
|
"Record created",
|
||||||
"ID", newRecord.ID,
|
"ID", newRecord.ID,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Info("Starting sync (step 2: delete)", "dry_run", config.DryRun)
|
|
||||||
for _, zone := range zones {
|
|
||||||
for _, hZone := range hZones {
|
|
||||||
if strings.EqualFold(zone.Domain, hZone.Name) {
|
|
||||||
log.Info("Syncing zone", "setp", 2, "name", zone.Domain)
|
|
||||||
|
|
||||||
for _, hRecord := range hZone.Records {
|
|
||||||
if !slices.Contains(keepTheseIds, hRecord.ID) {
|
|
||||||
log.Info(
|
|
||||||
"Deleting record",
|
|
||||||
"name", hRecord.Name,
|
|
||||||
"type", hRecord.Type,
|
|
||||||
"id", hRecord.ID,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
log.Info("Starting sync (step 3: update)", "dry_run", config.DryRun)
|
||||||
|
for _, record := range recordsToUpdate {
|
||||||
if !config.DryRun {
|
if !config.DryRun {
|
||||||
hetzner.DeleteRecord(&hetzner.Record{
|
newRecord, err := hetzner.UpdateRecord(&record)
|
||||||
ID: hRecord.ID,
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info(
|
log.Warn(
|
||||||
"Record deleted",
|
"Record updated",
|
||||||
"ID", hRecord.ID,
|
"ID", newRecord.ID,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Info("Sync is finished, all done!")
|
log.Info("Sync is finished, all done!")
|
||||||
|
|
||||||
|
if !config.DryRun && config.PushOver.Enable && len(pushoverMessages) > 0 {
|
||||||
|
log.Info("Changes made, sending PushOver notifications")
|
||||||
|
|
||||||
|
for _, message := range pushoverMessages {
|
||||||
|
err = helpers.PushoverSendMessage(helpers.PushoverMessage{
|
||||||
|
Message: message,
|
||||||
|
Title: "Changes made to DNS record",
|
||||||
|
AppKey: config.PushOver.AppKey,
|
||||||
|
UserKey: config.PushOver.UserKey,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue