You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
134 lines
2.8 KiB
134 lines
2.8 KiB
package cluster |
|
|
|
import ( |
|
"io/fs" |
|
"path/filepath" |
|
|
|
"darvaza.org/resolver" |
|
"darvaza.org/slog" |
|
"darvaza.org/slog/handlers/discard" |
|
"github.com/hack-pad/hackpadfs/os" |
|
) |
|
|
|
// A ScanOption pre-configures the Zones before scanning |
|
type ScanOption func(*Cluster, *ScanOptions) error |
|
|
|
// ScanOptions contains flags used by the initial scan |
|
type ScanOptions struct { |
|
// DontResolvePublicAddresses indicates we shouldn't |
|
// pre-populate Machine.PublicAddresses during the |
|
// initial scan |
|
DontResolvePublicAddresses bool |
|
|
|
// Logger specifies the logger to be used. otherwise |
|
// the scanner will be mute |
|
slog.Logger |
|
} |
|
|
|
// ResolvePublicAddresses instructs the scanner to use |
|
// the DNS resolver to get PublicAddresses of nodes. |
|
// Default is true |
|
func ResolvePublicAddresses(resolve bool) ScanOption { |
|
return func(m *Cluster, opt *ScanOptions) error { |
|
opt.DontResolvePublicAddresses = !resolve |
|
return nil |
|
} |
|
} |
|
|
|
// WithLookuper specifies what resolver.Lookuper to use to |
|
// find public addresses |
|
func WithLookuper(h resolver.Lookuper) ScanOption { |
|
return func(m *Cluster, opt *ScanOptions) error { |
|
if h == nil { |
|
return fs.ErrInvalid |
|
} |
|
m.resolver = resolver.NewResolver(h) |
|
return nil |
|
} |
|
} |
|
|
|
// WithResolver specifies what resolver to use to find |
|
// public addresses. if nil is passed, the [net.Resolver] will be used. |
|
// The default is using Cloudflare's 1.1.1.1. |
|
func WithResolver(h resolver.Resolver) ScanOption { |
|
return func(m *Cluster, opt *ScanOptions) error { |
|
if h == nil { |
|
h = resolver.SystemResolver(true) |
|
} |
|
|
|
m.resolver = h |
|
return nil |
|
} |
|
} |
|
|
|
// WithLogger specifies what to use for logging |
|
func WithLogger(log slog.Logger) ScanOption { |
|
return func(m *Cluster, opt *ScanOptions) error { |
|
if log == nil { |
|
log = discard.New() |
|
} |
|
|
|
opt.Logger = log |
|
m.log = log |
|
return nil |
|
} |
|
} |
|
|
|
func (m *Cluster) setDefaults(opt *ScanOptions) error { |
|
if m.resolver == nil { |
|
h := resolver.NewCloudflareLookuper() |
|
|
|
if err := WithLookuper(h)(m, opt); err != nil { |
|
return err |
|
} |
|
} |
|
|
|
if opt.Logger == nil { |
|
if err := WithLogger(nil)(m, opt); err != nil { |
|
return err |
|
} |
|
} |
|
|
|
return nil |
|
} |
|
|
|
// NewFS builds a [Cluster] tree using the given directory |
|
func NewFS(dir fs.FS, domain string, opts ...ScanOption) (*Cluster, error) { |
|
var scanOptions ScanOptions |
|
|
|
z := &Cluster{ |
|
dir: dir, |
|
domain: domain, |
|
} |
|
|
|
for _, opt := range opts { |
|
if err := opt(z, &scanOptions); err != nil { |
|
return nil, err |
|
} |
|
} |
|
|
|
if err := z.setDefaults(&scanOptions); err != nil { |
|
return nil, err |
|
} |
|
|
|
if err := z.scan(&scanOptions); err != nil { |
|
return nil, err |
|
} |
|
|
|
return z, nil |
|
} |
|
|
|
// New builds a [Cluster] tree using the given directory |
|
func New(dir, domain string, opts ...ScanOption) (*Cluster, error) { |
|
dir, err := filepath.Abs(dir) |
|
if err != nil { |
|
return nil, err |
|
} |
|
|
|
base, err := os.NewFS().Sub(dir[1:]) |
|
if err != nil { |
|
return nil, err |
|
} |
|
|
|
return NewFS(base, domain, opts...) |
|
}
|
|
|