From 3b25e94352b7db6c6028a6b97c425aa01dcf3aa3 Mon Sep 17 00:00:00 2001 From: Fran Bull Date: Fri, 6 Jun 2025 09:38:34 -0700 Subject: [PATCH] cmd/natc: allow specifying the tsnet state dir Which can make operating the service more convenient. It makes sense to put the cluster state with this if specified, so rearrange the logic to handle that. Updates #14667 Signed-off-by: Fran Bull --- cmd/natc/ippool/consensusippool.go | 32 +-------------------------- cmd/natc/natc.go | 35 ++++++++++++++++++++++++++++-- 2 files changed, 34 insertions(+), 33 deletions(-) diff --git a/cmd/natc/ippool/consensusippool.go b/cmd/natc/ippool/consensusippool.go index adf2090d1..3bc21bd03 100644 --- a/cmd/natc/ippool/consensusippool.go +++ b/cmd/natc/ippool/consensusippool.go @@ -10,8 +10,6 @@ import ( "fmt" "log" "net/netip" - "os" - "path/filepath" "time" "github.com/hashicorp/raft" @@ -155,11 +153,7 @@ func (ipp *ConsensusIPPool) domainLookup(from tailcfg.NodeID, addr netip.Addr) ( func (ipp *ConsensusIPPool) StartConsensus(ctx context.Context, ts *tsnet.Server, clusterTag string, clusterStateDir string) error { cfg := tsconsensus.DefaultConfig() cfg.ServeDebugMonitor = true - var err error - cfg.StateDirPath, err = getStatePath(clusterStateDir) - if err != nil { - return err - } + cfg.StateDirPath = clusterStateDir cns, err := tsconsensus.Start(ctx, ts, ipp, clusterTag, cfg) if err != nil { return err @@ -211,30 +205,6 @@ func (ps *consensusPerPeerState) unusedIPV4(ipset *netipx.IPSet, reuseDeadline t return netip.Addr{}, false, "", errors.New("ip pool exhausted") } -func getStatePath(pathFromFlag string) (string, error) { - var dirPath string - if pathFromFlag != "" { - dirPath = pathFromFlag - } else { - confDir, err := os.UserConfigDir() - if err != nil { - return "", err - } - dirPath = filepath.Join(confDir, "nat-connector-cluster-state") - } - - if err := os.MkdirAll(dirPath, 0700); err != nil { - return "", err - } - if fi, err := os.Stat(dirPath); err != nil { - return "", err - } else if !fi.IsDir() { - return "", fmt.Errorf("%v is not a directory", dirPath) - } - - return dirPath, nil -} - // isCloseToExpiry returns true if the lastUsed and now times are more than // half the lifetime apart func isCloseToExpiry(lastUsed, now time.Time, lifetime time.Duration) bool { diff --git a/cmd/natc/natc.go b/cmd/natc/natc.go index 719d5d20d..247bb2101 100644 --- a/cmd/natc/natc.go +++ b/cmd/natc/natc.go @@ -18,6 +18,7 @@ import ( "net/http" "net/netip" "os" + "path/filepath" "strings" "time" @@ -59,7 +60,7 @@ func main() { wgPort = fs.Uint("wg-port", 0, "udp port for wireguard and peer to peer traffic") clusterTag = fs.String("cluster-tag", "", "optionally run in a consensus cluster with other nodes with this tag") server = fs.String("login-server", ipn.DefaultControlURL, "the base URL of control server") - clusterStateDir = fs.String("cluster-state-dir", "", "path to directory in which to store raft state") + stateDir = fs.String("state-dir", "", "path to directory in which to store app state") ) ff.Parse(fs, os.Args[1:], ff.WithEnvVarPrefix("TS_NATC")) @@ -96,6 +97,7 @@ func main() { } ts := &tsnet.Server{ Hostname: *hostname, + Dir: *stateDir, } ts.ControlURL = *server if *wgPort != 0 { @@ -156,7 +158,11 @@ func main() { var ipp ippool.IPPool if *clusterTag != "" { cipp := ippool.NewConsensusIPPool(addrPool) - err = cipp.StartConsensus(ctx, ts, *clusterTag, *clusterStateDir) + clusterStateDir, err := getClusterStatePath(*stateDir) + if err != nil { + log.Fatalf("Creating cluster state dir failed: %v", err) + } + err = cipp.StartConsensus(ctx, ts, *clusterTag, clusterStateDir) if err != nil { log.Fatalf("StartConsensus: %v", err) } @@ -570,3 +576,28 @@ func proxyTCPConn(c net.Conn, dest string, ctor *connector) { p.Start() } + +func getClusterStatePath(stateDirFlag string) (string, error) { + var dirPath string + if stateDirFlag != "" { + dirPath = stateDirFlag + } else { + confDir, err := os.UserConfigDir() + if err != nil { + return "", err + } + dirPath = filepath.Join(confDir, "nat-connector-state") + } + dirPath = filepath.Join(dirPath, "cluster") + + if err := os.MkdirAll(dirPath, 0700); err != nil { + return "", err + } + if fi, err := os.Stat(dirPath); err != nil { + return "", err + } else if !fi.IsDir() { + return "", fmt.Errorf("%v is not a directory", dirPath) + } + + return dirPath, nil +}