You've already forked cloudflare-dns-cli
							
							Support deleting records
This commit is contained in:
		
							
								
								
									
										160
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										160
									
								
								main.go
									
									
									
									
									
								
							@@ -8,6 +8,8 @@ import (
 | 
			
		||||
	"log"
 | 
			
		||||
	"net"
 | 
			
		||||
	"os"
 | 
			
		||||
	"sort"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/libdns/cloudflare"
 | 
			
		||||
	"github.com/libdns/libdns"
 | 
			
		||||
@@ -16,27 +18,14 @@ import (
 | 
			
		||||
var (
 | 
			
		||||
	domain = os.Getenv("DOMAIN")
 | 
			
		||||
	token  = os.Getenv("CF_TOKEN")
 | 
			
		||||
	ip     = net.IPv4(127, 0, 0, 1)
 | 
			
		||||
	cname  string
 | 
			
		||||
	sub    = "<UNSET>"
 | 
			
		||||
	path   string
 | 
			
		||||
	del    = false
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
	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(&sub, "s", sub, "Subdomain to add dns entry for, e.g. blog")
 | 
			
		||||
	flag.StringVar(&token, "a", token, "Cloudflare API Token")
 | 
			
		||||
	flag.TextVar(&ip, "i", ip, "IP address")
 | 
			
		||||
	flag.StringVar(&cname, "c", cname, "CNAME target")
 | 
			
		||||
	flag.StringVar(&path, "o", path, "path to save all records as json, e.g. ./records.json")
 | 
			
		||||
	flag.Parse()
 | 
			
		||||
 | 
			
		||||
	provider := cloudflare.Provider{APIToken: token}
 | 
			
		||||
	zone := domain + "."
 | 
			
		||||
	fmt.Println(zone, sub, cname)
 | 
			
		||||
	makeRecord := func() (libdns.Record, error) {
 | 
			
		||||
func genRecord() (libdns.Record, error) {
 | 
			
		||||
	switch {
 | 
			
		||||
	case cname != "":
 | 
			
		||||
		return libdns.Record{
 | 
			
		||||
@@ -60,32 +49,153 @@ func main() {
 | 
			
		||||
	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() {
 | 
			
		||||
	ctx := context.TODO()
 | 
			
		||||
 | 
			
		||||
	flag.StringVar(&domain, "d", domain, "Domain name, e.g. example.com")
 | 
			
		||||
	flag.StringVar(&sub, "s", sub, "Subdomain, e.g. blog. Use @ for root")
 | 
			
		||||
	flag.StringVar(&token, "a", token, "Cloudflare API Token")
 | 
			
		||||
	flag.TextVar(&ip, "i", ip, "IP address")
 | 
			
		||||
	flag.StringVar(&cname, "c", cname, "CNAME target")
 | 
			
		||||
	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()
 | 
			
		||||
 | 
			
		||||
	provider := cloudflare.Provider{APIToken: token}
 | 
			
		||||
	zone := domain + "."
 | 
			
		||||
 | 
			
		||||
	if sub != "<UNSET>" {
 | 
			
		||||
		record, err := makeRecord()
 | 
			
		||||
		if del {
 | 
			
		||||
			recs, err := provider.GetRecords(ctx, zone)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
			panic(err)
 | 
			
		||||
				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 {
 | 
			
		||||
			panic(err)
 | 
			
		||||
				log.Panicln(err)
 | 
			
		||||
			}
 | 
			
		||||
			fmt.Println(newRecs)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if path != "" {
 | 
			
		||||
		recs, err := provider.GetRecords(ctx, zone)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			panic(err)
 | 
			
		||||
			log.Panicln(err)
 | 
			
		||||
		}
 | 
			
		||||
		data, err := json.Marshal(recs)
 | 
			
		||||
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			panic(err)
 | 
			
		||||
			log.Panicln(err)
 | 
			
		||||
		}
 | 
			
		||||
		err = os.WriteFile(path, data, 0644)
 | 
			
		||||
		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()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user