package main import ( "context" "net/netip" "os" "time" "darvaza.org/core" "github.com/spf13/cobra" "git.jpi.io/amery/jpictl/pkg/cluster" "git.jpi.io/amery/jpictl/pkg/dns" ) const ( // DNSSyncTimeout specifies how long are we willing to wait for a DNS // synchronization DNSSyncTimeout = 10 * time.Second ) func newDNSManager(m *cluster.Cluster, provider dns.Provider) (*dns.Manager, error) { domain := m.Domain if m.Name != "" { domain = m.Name + "." + domain } mgr, err := dns.NewManager(dns.WithDomain(domain), dns.WithLogger(log)) if err != nil { return nil, err } if provider != nil { // set provider only if specified err = dns.WithProvider(provider)(mgr) if err != nil { return nil, err } } if err := populateDNSManager(mgr, m); err != nil { return nil, err } return mgr, nil } func populateDNSManager(mgr *dns.Manager, m *cluster.Cluster) error { var err error ctx := context.TODO() m.ForEachZone(func(z *cluster.Zone) bool { z.ForEachMachine(func(p *cluster.Machine) bool { err = mgr.AddHost(ctx, z.Name, p.ID, p.IsActive(), p.PublicAddresses...) return err != nil }) return err != nil }) if err != nil { return err } m.ForEachRegion(func(r *cluster.Region) bool { r.ForEachZone(func(z *cluster.Zone) bool { err = mgr.AddRegion(ctx, r.Name, z.Name) return err != nil }) return err != nil }) return err } // revive:disable:flag-parameter func newDNSManagerCommand(_ *cobra.Command, resolve bool, withCredentials bool) (*dns.Manager, error) { // revive:enable:flag-parameter var cred dns.Provider if withCredentials { var err error cred, err = dns.DefaultDNSProvider() if err != nil { return nil, err } } m, err := cfg.LoadZones(resolve) if err != nil { return nil, err } return newDNSManager(m, cred) } // Command var dnsCmd = &cobra.Command{ Use: "dns", } var dnsWriteCmd = &cobra.Command{ Use: "write", Short: "dns write generates public DNS records", PreRun: setVerbosity, RunE: func(cmd *cobra.Command, _ []string) error { mgr, err := newDNSManagerCommand(cmd, true, false) if err != nil { return err } _, err = mgr.WriteTo(os.Stdout) return err }, } var dnsSyncCmd = &cobra.Command{ Use: "sync", Short: "dns sync updates public DNS records", PreRun: setVerbosity, RunE: func(cmd *cobra.Command, _ []string) error { mgr, err := newDNSManagerCommand(cmd, true, true) if err != nil { return err } ctx, cancel := context.WithTimeout(context.Background(), DNSSyncTimeout) defer cancel() return mgr.Sync(ctx) }, } var dnsShowCmd = &cobra.Command{ Use: "show [...]", Short: "dns show lists entries on DNS for our domain", PreRun: setVerbosity, RunE: func(cmd *cobra.Command, args []string) error { mgr, err := newDNSManagerCommand(cmd, true, true) if err != nil { return err } ctx, cancel := context.WithTimeout(context.Background(), DNSSyncTimeout) defer cancel() return mgr.Show(ctx, args...) }, } 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) }