diff --git a/cmd/jpictl/dns.go b/cmd/jpictl/dns.go index 9023730..f3a2cbe 100644 --- a/cmd/jpictl/dns.go +++ b/cmd/jpictl/dns.go @@ -2,9 +2,11 @@ package main import ( "context" + "net/netip" "os" "time" + "darvaza.org/core" "github.com/spf13/cobra" "git.jpi.io/amery/jpictl/pkg/cluster" @@ -149,10 +151,43 @@ var dnsShowCmd = &cobra.Command{ }, } +var dnsAddCmd = &cobra.Command{ + Use: "add ", + Short: "dns add registers a new machine on the public DNS", + Args: cobra.MinimumNArgs(2), + PreRun: setVerbosity, + RunE: func(cmd *cobra.Command, args []string) error { + var addrs []netip.Addr + + for _, s := range args[1:] { + addr, err := core.ParseAddr(s) + switch { + case err != nil: + return core.Wrap(err, s) + case !addr.IsValid(), addr.IsUnspecified(), addr.IsPrivate(), addr.IsMulticast(): + return core.Wrap(core.ErrInvalid, s) + default: + addrs = append(addrs, addr) + } + } + + mgr, err := newDNSManagerCommand(cmd, true, true) + if err != nil { + return err + } + + ctx, cancel := context.WithTimeout(context.Background(), DNSSyncTimeout) + defer cancel() + + return mgr.Add(ctx, args[0], addrs...) + }, +} + func init() { rootCmd.AddCommand(dnsCmd) dnsCmd.AddCommand(dnsWriteCmd) dnsCmd.AddCommand(dnsSyncCmd) dnsCmd.AddCommand(dnsShowCmd) + dnsCmd.AddCommand(dnsAddCmd) } diff --git a/pkg/dns/add.go b/pkg/dns/add.go new file mode 100644 index 0000000..3c9c6c4 --- /dev/null +++ b/pkg/dns/add.go @@ -0,0 +1,69 @@ +package dns + +import ( + "context" + "net/netip" + "os" + "time" + + "darvaza.org/core" + "github.com/libdns/libdns" +) + +// Add adds a machine to the DNS records +func (mgr *Manager) Add(ctx context.Context, name string, addrs ...netip.Addr) error { + // TODO: validate name + + cur, err := mgr.GetRecords(ctx, name) + if err != nil { + return core.Wrap(err, "GetRecords") + } + + // merge []SyncAddr for name + s := mgr.asSyncRecordsMap(cur)[name+mgr.suffix] + for _, addr := range addrs { + s = AppendSyncAddr(s, addr) + } + + return mgr.addSyncAddr(ctx, name, s) +} + +func (mgr *Manager) addSyncAddr(ctx context.Context, name string, s []SyncAddr) error { + var recs []libdns.Record + + for _, a := range s { + recs = append(recs, libdns.Record{ + ID: a.ID, + Name: name + mgr.suffix, + Type: core.IIf(a.Addr.Is6(), "AAAA", "A"), + TTL: time.Second, + Value: a.Addr.String(), + }) + } + + SortRecords(recs) + err := writeRecords(recs, os.Stdout) + if err != nil { + return err + } + + _, err = mgr.p.SetRecords(ctx, mgr.domain, recs) + return err +} + +// AppendSyncAddr appends a [netip.Addr] to a [SyncAddr] slice +// if the address is new. +func AppendSyncAddr(s []SyncAddr, addr netip.Addr) []SyncAddr { + for _, se := range s { + if se.Addr.Compare(addr) == 0 { + // found + return s + } + } + + s = append(s, SyncAddr{ + Addr: addr, + TTL: time.Second, + }) + return s +}