Support deleting records
This commit is contained in:
parent
48514a61be
commit
7534108b79
194
main.go
194
main.go
@ -8,6 +8,8 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/libdns/cloudflare"
|
"github.com/libdns/cloudflare"
|
||||||
"github.com/libdns/libdns"
|
"github.com/libdns/libdns"
|
||||||
@ -16,76 +18,184 @@ import (
|
|||||||
var (
|
var (
|
||||||
domain = os.Getenv("DOMAIN")
|
domain = os.Getenv("DOMAIN")
|
||||||
token = os.Getenv("CF_TOKEN")
|
token = os.Getenv("CF_TOKEN")
|
||||||
|
ip = net.IPv4(127, 0, 0, 1)
|
||||||
|
cname string
|
||||||
|
sub = "<UNSET>"
|
||||||
|
path string
|
||||||
|
del = false
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func genRecord() (libdns.Record, error) {
|
||||||
|
switch {
|
||||||
|
case cname != "":
|
||||||
|
return libdns.Record{
|
||||||
|
Type: "CNAME",
|
||||||
|
Name: sub,
|
||||||
|
Value: cname,
|
||||||
|
}, nil
|
||||||
|
case len(ip) == net.IPv4len:
|
||||||
|
return libdns.Record{
|
||||||
|
Type: "A",
|
||||||
|
Name: sub,
|
||||||
|
Value: ip.To4().String(),
|
||||||
|
}, nil
|
||||||
|
case len(ip) == net.IPv6len:
|
||||||
|
return libdns.Record{
|
||||||
|
Type: "AAAA",
|
||||||
|
Name: sub,
|
||||||
|
Value: ip.To16().String(),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
return libdns.Record{}, fmt.Errorf("neither cname nor valid ip is set")
|
||||||
|
}
|
||||||
|
|
||||||
|
func selectRecordsToDelete(recs []libdns.Record) []libdns.Record {
|
||||||
|
name := func() string {
|
||||||
|
if sub == "@" {
|
||||||
|
return domain
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%s.%s", sub, domain)
|
||||||
|
}()
|
||||||
|
recs = func() (result []libdns.Record) {
|
||||||
|
for _, r := range recs {
|
||||||
|
if r.Name == name {
|
||||||
|
result = append(result, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}()
|
||||||
|
fmt.Printf("Records matching %s\n", name)
|
||||||
|
for i, r := range recs {
|
||||||
|
fmt.Printf("%5d %6s %s\n", i, r.Type, r.Value)
|
||||||
|
}
|
||||||
|
var delRange string
|
||||||
|
fmt.Print("Enter record indexes seperated by comma(,) to delete. Use hyphen(-) for a closed range. Also can be all or none\nIndexes: ")
|
||||||
|
if _, err := fmt.Scanln(&delRange); err != nil {
|
||||||
|
log.Panicln(err)
|
||||||
|
}
|
||||||
|
switch {
|
||||||
|
case delRange == "all":
|
||||||
|
return recs
|
||||||
|
case delRange == "none":
|
||||||
|
return nil
|
||||||
|
default:
|
||||||
|
indexGen := func() func() int {
|
||||||
|
indexes := parseRange(delRange, len(recs)-1)
|
||||||
|
indexIndex := 0
|
||||||
|
return func() int {
|
||||||
|
if indexIndex == len(indexes) {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
val := indexes[indexIndex]
|
||||||
|
indexIndex++
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
return func() (result []libdns.Record) {
|
||||||
|
nextIndex := indexGen()
|
||||||
|
for i, r := range recs {
|
||||||
|
if i == nextIndex {
|
||||||
|
result = append(result, r)
|
||||||
|
nextIndex = indexGen()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
ctx := context.TODO()
|
ctx := context.TODO()
|
||||||
ip := net.IPv4(127, 0, 0, 1)
|
|
||||||
var cname string
|
|
||||||
sub := "<UNSET>"
|
|
||||||
var path string
|
|
||||||
|
|
||||||
flag.StringVar(&domain, "d", domain, "Domain name, e.g. example.com")
|
flag.StringVar(&domain, "d", domain, "Domain name, e.g. example.com")
|
||||||
flag.StringVar(&sub, "s", sub, "Subdomain to add dns entry for, e.g. blog")
|
flag.StringVar(&sub, "s", sub, "Subdomain, e.g. blog. Use @ for root")
|
||||||
flag.StringVar(&token, "a", token, "Cloudflare API Token")
|
flag.StringVar(&token, "a", token, "Cloudflare API Token")
|
||||||
flag.TextVar(&ip, "i", ip, "IP address")
|
flag.TextVar(&ip, "i", ip, "IP address")
|
||||||
flag.StringVar(&cname, "c", cname, "CNAME target")
|
flag.StringVar(&cname, "c", cname, "CNAME target")
|
||||||
flag.StringVar(&path, "o", path, "path to save all records as json, e.g. ./records.json")
|
flag.StringVar(&path, "o", path, "Path to save all records as json, e.g. ./records.json")
|
||||||
|
flag.BoolVar(&del, "x", del, "Delete records of subdomain")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
provider := cloudflare.Provider{APIToken: token}
|
provider := cloudflare.Provider{APIToken: token}
|
||||||
zone := domain + "."
|
zone := domain + "."
|
||||||
fmt.Println(zone, sub, cname)
|
|
||||||
makeRecord := func() (libdns.Record, error) {
|
|
||||||
switch {
|
|
||||||
case cname != "":
|
|
||||||
return libdns.Record{
|
|
||||||
Type: "CNAME",
|
|
||||||
Name: sub,
|
|
||||||
Value: cname,
|
|
||||||
}, nil
|
|
||||||
case len(ip) == net.IPv4len:
|
|
||||||
return libdns.Record{
|
|
||||||
Type: "A",
|
|
||||||
Name: sub,
|
|
||||||
Value: ip.To4().String(),
|
|
||||||
}, nil
|
|
||||||
case len(ip) == net.IPv6len:
|
|
||||||
return libdns.Record{
|
|
||||||
Type: "AAAA",
|
|
||||||
Name: sub,
|
|
||||||
Value: ip.To16().String(),
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
return libdns.Record{}, fmt.Errorf("neither cname nor valid ip is set")
|
|
||||||
}
|
|
||||||
|
|
||||||
if sub != "<UNSET>" {
|
if sub != "<UNSET>" {
|
||||||
record, err := makeRecord()
|
if del {
|
||||||
if err != nil {
|
recs, err := provider.GetRecords(ctx, zone)
|
||||||
panic(err)
|
if err != nil {
|
||||||
|
log.Panicln(err)
|
||||||
|
}
|
||||||
|
recs = selectRecordsToDelete(recs)
|
||||||
|
recs, err = provider.DeleteRecords(ctx, zone, recs)
|
||||||
|
if err != nil {
|
||||||
|
log.Panicln(err)
|
||||||
|
}
|
||||||
|
if len(recs) == 0 {
|
||||||
|
fmt.Println("Nothing was deleted")
|
||||||
|
} else {
|
||||||
|
fmt.Println("Records deleted:")
|
||||||
|
for i, r := range recs {
|
||||||
|
fmt.Printf("%5d %6s %s\n", i, r.Type, r.Value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
|
||||||
|
record, err := genRecord()
|
||||||
|
if err != nil {
|
||||||
|
log.Panicln(err)
|
||||||
|
}
|
||||||
|
log.Printf("setting record, %+v", record)
|
||||||
|
newRecs, err := provider.SetRecords(ctx, zone, []libdns.Record{record})
|
||||||
|
if err != nil {
|
||||||
|
log.Panicln(err)
|
||||||
|
}
|
||||||
|
fmt.Println(newRecs)
|
||||||
}
|
}
|
||||||
log.Printf("setting record, %+v", record)
|
|
||||||
newRecs, err := provider.SetRecords(ctx, zone, []libdns.Record{record})
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
fmt.Println(newRecs)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if path != "" {
|
if path != "" {
|
||||||
recs, err := provider.GetRecords(ctx, zone)
|
recs, err := provider.GetRecords(ctx, zone)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
log.Panicln(err)
|
||||||
}
|
}
|
||||||
data, err := json.Marshal(recs)
|
data, err := json.Marshal(recs)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
log.Panicln(err)
|
||||||
}
|
}
|
||||||
err = os.WriteFile(path, data, 0644)
|
err = os.WriteFile(path, data, 0644)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
log.Panicln(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseRange(rs string, max int) []int {
|
||||||
|
var indexes []int
|
||||||
|
m := uint(max)
|
||||||
|
for _, s := range strings.Split(rs, ",") {
|
||||||
|
s = strings.TrimSpace(s)
|
||||||
|
var i, a, b uint
|
||||||
|
if _, err := fmt.Sscanf(s, "%v-%v", &a, &b); err == nil {
|
||||||
|
for s := a; s <= b && s <= m; {
|
||||||
|
indexes = append(indexes, int(s))
|
||||||
|
s++
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if _, err := fmt.Sscanf(s, "%v", &i); err == nil && i <= m {
|
||||||
|
indexes = append(indexes, int(i))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sort.Ints(indexes)
|
||||||
|
var uniq []int
|
||||||
|
last := -1
|
||||||
|
for _, i := range indexes {
|
||||||
|
if i != last {
|
||||||
|
uniq = append(uniq, i)
|
||||||
|
last = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return uniq
|
||||||
|
}
|
||||||
|
15
main_test.go
Normal file
15
main_test.go
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestParseRange(t *testing.T) {
|
||||||
|
expected := []int{0, 1, 2, 6}
|
||||||
|
actual := parseRange("0-2,-5,6,-7-7,1, 11", 10)
|
||||||
|
if fmt.Sprint(expected) != fmt.Sprint(actual) {
|
||||||
|
fmt.Printf("unexpected %#v\n", actual)
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user