package main import ( "encoding/json" "fmt" "net/http" "os" "sync" "git.xbudex.com/buddy/update-dns/dns" "github.com/pkg/errors" "github.com/urfave/cli" ) func main() { app := cli.NewApp() app.Name = "update-dns" app.Usage = "update dnsimple with public ip address" app.Version = "0.2.0-dev" app.Action = action app.Flags = []cli.Flag{ cli.StringFlag{ Name: "url", Value: "https://whatismyipv6.buddy.wtf/json", Usage: "url to use to get public ip address", }, cli.StringFlag{ EnvVar: "DNSIMPLE_TOKEN", Name: "dnsimple-token", Usage: "dnsimple token", }, } app.Run(os.Args) } type runtimeError string func (e runtimeError) Error() string { return string(e) } func action(context *cli.Context) error { var wg sync.WaitGroup if context.NArg() < 1 { return runtimeError("requires host argument") } host := context.Args().Get(0) wg.Add(1) var getIPError error var ip string go func() { defer wg.Done() result, err := getIP(context.String("url")) if err != nil { getIPError = errors.Wrap(err, "could not get IP address") return } ip = result.IP }() client := dns.New(context.String("dnsimple-token")) records := []dns.Record{} var getRecordsError error wg.Add(1) go func() { defer wg.Done() fmt.Println("Getting records") if results, err := client.GetRecords(host, "AAAA"); err != nil { getRecordsError = errors.Wrap(err, "could not get records for host") } else { records = results } }() wg.Wait() if getIPError != nil { return errors.Wrap(getIPError, "could no get ip address") } if getRecordsError != nil { return errors.Wrap(getRecordsError, "could no get record") } if len(records) == 1 && records[0].Content == ip { fmt.Printf("%s record for %s already set as %s\n", "AAAA", host, ip) return nil } if err := client.CreateRecord(host, dns.Record{Type: "AAAA", Content: ip}); err != nil { return errors.Wrap(err, "could not create record") } fmt.Printf("%s record created for %s as %s\n", "AAAA", host, ip) var deleteWG sync.WaitGroup for _, record := range records { deleteWG.Add(1) go func(r dns.Record) { defer deleteWG.Done() fmt.Printf("%s record for %s being deleting %s\n", r.Type, host, r.Content) client.DeleteRecord(r) }(record) } deleteWG.Wait() return nil } type whatIsMyIPResult struct { IP string `json:ip` Version string `json:version` } func getIP(url string) (*whatIsMyIPResult, error) { result, err := http.Get(url) if err != nil { return nil, errors.Wrap(err, "could not get url "+url) } defer result.Body.Close() ipResult := &whatIsMyIPResult{} if err := json.NewDecoder(result.Body).Decode(ipResult); err != nil { return nil, errors.Wrap(err, "could parse json from url "+url) } return ipResult, nil }