mirror of
https://github.com/aauren/tailscale-bind-ddns.git
synced 2026-10-25 13:19:34 +00:00
120 lines
3.3 KiB
Go
120 lines
3.3 KiB
Go
package cmd
|
|
|
|
import (
|
|
"flag"
|
|
"fmt"
|
|
"os"
|
|
"time"
|
|
|
|
"github.com/aauren/tailscale-bind-ddns/pkg/config"
|
|
"github.com/spf13/cobra"
|
|
"github.com/spf13/viper"
|
|
"k8s.io/klog/v2"
|
|
)
|
|
|
|
const (
|
|
defaultPollInterval = 30 * time.Second
|
|
defaultBindPort = 53
|
|
defaultTTL = 300 * time.Second
|
|
defaultUpdateInterval = 60 * time.Second
|
|
testTimeout = 30 * time.Second
|
|
)
|
|
|
|
var (
|
|
cfgFile string
|
|
cfg *config.Config
|
|
)
|
|
|
|
// rootCmd represents the base command when called without any subcommands
|
|
var rootCmd = &cobra.Command{
|
|
Use: "tailscale-bind-ddns",
|
|
Short: "A tool to sync Tailscale machines to Bind DNS records",
|
|
Long: `Tailscale-Bind DDNS is a tool that connects to your Tailscale tailnet,
|
|
retrieves the list of online machines, and automatically updates DNS A records
|
|
in your Bind server using RFC 2136 dynamic updates with TSIG authentication.
|
|
|
|
The tool supports configuration via:
|
|
- Command line flags
|
|
- Environment variables (prefixed with TSBD_)
|
|
- YAML configuration files
|
|
|
|
Example usage:
|
|
tailscale-bind-ddns run --tailscale-api-key YOUR_KEY --bind-server dns.example.com
|
|
tailscale-bind-ddns run --config config.yaml
|
|
TSBD_TAILSCALE_API_KEY=your_key tailscale-bind-ddns run`,
|
|
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
|
|
var err error
|
|
cfg, err = config.LoadConfig()
|
|
if err != nil {
|
|
return fmt.Errorf("loading configuration: %w", err)
|
|
}
|
|
return nil
|
|
},
|
|
}
|
|
|
|
// setupLogging configures the logging based on the configuration
|
|
func setupLogging() error {
|
|
// Create a custom flagset for klog
|
|
flagset := flag.NewFlagSet("klog", flag.ContinueOnError)
|
|
klog.InitFlags(flagset)
|
|
|
|
// Set verbosity level based on configuration
|
|
var verbosity int
|
|
switch cfg.General.LogLevel {
|
|
case "debug":
|
|
verbosity = 2
|
|
case "verbose":
|
|
verbosity = 1
|
|
case "info":
|
|
verbosity = 0
|
|
default:
|
|
return fmt.Errorf("invalid log level: %s", cfg.General.LogLevel)
|
|
}
|
|
|
|
// Set the verbosity flag in the flagset
|
|
if err := flagset.Set("v", fmt.Sprintf("%d", verbosity)); err != nil {
|
|
return fmt.Errorf("setting klog verbosity: %w", err)
|
|
}
|
|
|
|
// Parse the flagset to apply the settings
|
|
if err := flagset.Parse([]string{}); err != nil {
|
|
return fmt.Errorf("parsing klog flags: %w", err)
|
|
}
|
|
|
|
klog.V(1).Infof("Logging configured with level: %s (verbosity: %d)", cfg.General.LogLevel, verbosity)
|
|
return nil
|
|
}
|
|
|
|
// initializeCommands sets up all commands and flags
|
|
func initializeCommands() {
|
|
// Add all commands
|
|
rootCmd.AddCommand(runCmd)
|
|
rootCmd.AddCommand(statusCmd)
|
|
rootCmd.AddCommand(testCmd)
|
|
|
|
// Global flags
|
|
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is config.yaml)")
|
|
rootCmd.PersistentFlags().String("log-level", "info",
|
|
"log level (debug, verbose, info) (WARNING: debug level may leak secrets)")
|
|
|
|
// Bind global flags to viper
|
|
bindGlobalFlagsToViper()
|
|
}
|
|
|
|
// bindGlobalFlagsToViper binds global flags to viper configuration
|
|
func bindGlobalFlagsToViper() {
|
|
// General flags
|
|
if err := viper.BindPFlag("general.log_level", rootCmd.PersistentFlags().Lookup("log-level")); err != nil {
|
|
klog.Errorf("Failed to bind log-level flag: %v", err)
|
|
}
|
|
}
|
|
|
|
// Execute adds all child commands to the root command and sets flags appropriately.
|
|
func Execute() {
|
|
initializeCommands()
|
|
if err := rootCmd.Execute(); err != nil {
|
|
fmt.Fprintln(os.Stderr, err)
|
|
os.Exit(1)
|
|
}
|
|
}
|