mirror of
https://github.com/tailscale/tailscale.git
synced 2025-02-27 10:47:35 +00:00
cmd/tailscaled, ipn: add tailscaled --statedir flag for var directory
Fixes #2932 Change-Id: I1aa2b323ad542386d140f8336bcc4dcbb8310bd0 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
parent
c7bff35fee
commit
649f7556e8
@ -20,6 +20,7 @@ import (
|
|||||||
"net/http/pprof"
|
"net/http/pprof"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
"strconv"
|
"strconv"
|
||||||
@ -78,6 +79,7 @@ var args struct {
|
|||||||
debug string
|
debug string
|
||||||
port uint16
|
port uint16
|
||||||
statepath string
|
statepath string
|
||||||
|
statedir string
|
||||||
socketpath string
|
socketpath string
|
||||||
birdSocketPath string
|
birdSocketPath string
|
||||||
verbose int
|
verbose int
|
||||||
@ -114,7 +116,8 @@ func main() {
|
|||||||
flag.StringVar(&args.httpProxyAddr, "outbound-http-proxy-listen", "", `optional [ip]:port to run an outbound HTTP proxy (e.g. "localhost:8080")`)
|
flag.StringVar(&args.httpProxyAddr, "outbound-http-proxy-listen", "", `optional [ip]:port to run an outbound HTTP proxy (e.g. "localhost:8080")`)
|
||||||
flag.StringVar(&args.tunname, "tun", defaultTunName(), `tunnel interface name; use "userspace-networking" (beta) to not use TUN`)
|
flag.StringVar(&args.tunname, "tun", defaultTunName(), `tunnel interface name; use "userspace-networking" (beta) to not use TUN`)
|
||||||
flag.Var(flagtype.PortValue(&args.port, 0), "port", "UDP port to listen on for WireGuard and peer-to-peer traffic; 0 means automatically select")
|
flag.Var(flagtype.PortValue(&args.port, 0), "port", "UDP port to listen on for WireGuard and peer-to-peer traffic; 0 means automatically select")
|
||||||
flag.StringVar(&args.statepath, "state", paths.DefaultTailscaledStateFile(), "path of state file; use 'kube:<secret-name>' to use Kubernetes secrets or 'arn:aws:ssm:...' to store in AWS SSM")
|
flag.StringVar(&args.statepath, "state", paths.DefaultTailscaledStateFile(), "absolute path of state file; use 'kube:<secret-name>' to use Kubernetes secrets or 'arn:aws:ssm:...' to store in AWS SSM. If empty and --statedir is provided, the default is <statedir>/tailscaled.state")
|
||||||
|
flag.StringVar(&args.statedir, "statedir", "", "path to directory for storage of config state, TLS certs, temporary incoming Taildrop files, etc. If empty, it's derived from --state when possible.")
|
||||||
flag.StringVar(&args.socketpath, "socket", paths.DefaultTailscaledSocket(), "path of the service unix socket")
|
flag.StringVar(&args.socketpath, "socket", paths.DefaultTailscaledSocket(), "path of the service unix socket")
|
||||||
flag.StringVar(&args.birdSocketPath, "bird-socket", "", "path of the bird unix socket")
|
flag.StringVar(&args.birdSocketPath, "bird-socket", "", "path of the bird unix socket")
|
||||||
flag.BoolVar(&printVersion, "version", false, "print version information and exit")
|
flag.BoolVar(&printVersion, "version", false, "print version information and exit")
|
||||||
@ -202,6 +205,16 @@ func trySynologyMigration(p string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func statePathOrDefault() string {
|
||||||
|
if args.statepath != "" {
|
||||||
|
return args.statepath
|
||||||
|
}
|
||||||
|
if args.statedir != "" {
|
||||||
|
return filepath.Join(args.statedir, "tailscaled.state")
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
func ipnServerOpts() (o ipnserver.Options) {
|
func ipnServerOpts() (o ipnserver.Options) {
|
||||||
// Allow changing the OS-specific IPN behavior for tests
|
// Allow changing the OS-specific IPN behavior for tests
|
||||||
// so we can e.g. test Windows-specific behaviors on Linux.
|
// so we can e.g. test Windows-specific behaviors on Linux.
|
||||||
@ -211,8 +224,17 @@ func ipnServerOpts() (o ipnserver.Options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
o.Port = 41112
|
o.Port = 41112
|
||||||
o.StatePath = args.statepath
|
o.StatePath = statePathOrDefault()
|
||||||
o.SocketPath = args.socketpath // even for goos=="windows", for tests
|
o.SocketPath = args.socketpath // even for goos=="windows", for tests
|
||||||
|
o.VarRoot = args.statedir
|
||||||
|
|
||||||
|
// If an absolute --state is provided but not --statedir, try to derive
|
||||||
|
// a state directory.
|
||||||
|
if o.VarRoot == "" && filepath.IsAbs(args.statepath) {
|
||||||
|
if dir := filepath.Dir(args.statepath); strings.EqualFold(filepath.Base(dir), "tailscale") {
|
||||||
|
o.VarRoot = dir
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch goos {
|
switch goos {
|
||||||
default:
|
default:
|
||||||
@ -261,10 +283,10 @@ func run() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if args.statepath == "" {
|
if args.statepath == "" && args.statedir == "" {
|
||||||
log.Fatalf("--state is required")
|
log.Fatalf("--statedir (or at least --state) is required")
|
||||||
}
|
}
|
||||||
if err := trySynologyMigration(args.statepath); err != nil {
|
if err := trySynologyMigration(statePathOrDefault()); err != nil {
|
||||||
log.Printf("error in synology migration: %v", err)
|
log.Printf("error in synology migration: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,6 +96,7 @@ type LocalBackend struct {
|
|||||||
gotPortPollRes chan struct{} // closed upon first readPoller result
|
gotPortPollRes chan struct{} // closed upon first readPoller result
|
||||||
serverURL string // tailcontrol URL
|
serverURL string // tailcontrol URL
|
||||||
newDecompressor func() (controlclient.Decompressor, error)
|
newDecompressor func() (controlclient.Decompressor, error)
|
||||||
|
varRoot string // or empty if SetVarRoot never called
|
||||||
|
|
||||||
filterHash deephash.Sum
|
filterHash deephash.Sum
|
||||||
|
|
||||||
@ -1998,34 +1999,29 @@ func normalizeResolver(cfg dnstype.Resolver) dnstype.Resolver {
|
|||||||
return cfg
|
return cfg
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetVarRoot sets the root directory of Tailscale's writable
|
||||||
|
// storage area . (e.g. "/var/lib/tailscale")
|
||||||
|
//
|
||||||
|
// It should only be called before the LocalBackend is used.
|
||||||
|
func (b *LocalBackend) SetVarRoot(dir string) {
|
||||||
|
b.varRoot = dir
|
||||||
|
}
|
||||||
|
|
||||||
// TailscaleVarRoot returns the root directory of Tailscale's writable
|
// TailscaleVarRoot returns the root directory of Tailscale's writable
|
||||||
// storage area. (e.g. "/var/lib/tailscale")
|
// storage area. (e.g. "/var/lib/tailscale")
|
||||||
//
|
//
|
||||||
// It returns an empty string if there's no configured or discovered
|
// It returns an empty string if there's no configured or discovered
|
||||||
// location.
|
// location.
|
||||||
func (b *LocalBackend) TailscaleVarRoot() string {
|
func (b *LocalBackend) TailscaleVarRoot() string {
|
||||||
|
if b.varRoot != "" {
|
||||||
|
return b.varRoot
|
||||||
|
}
|
||||||
switch runtime.GOOS {
|
switch runtime.GOOS {
|
||||||
case "ios", "android":
|
case "ios", "android":
|
||||||
dir, _ := paths.AppSharedDir.Load().(string)
|
dir, _ := paths.AppSharedDir.Load().(string)
|
||||||
return dir
|
return dir
|
||||||
}
|
}
|
||||||
// Temporary (2021-09-27) transitional fix for #2927 (Synology
|
return ""
|
||||||
// cert dir) on the way towards a more complete fix
|
|
||||||
// (#2932). It fixes any case where the state file is provided
|
|
||||||
// to tailscaled explicitly when it's not in the default
|
|
||||||
// location.
|
|
||||||
if fs, ok := b.store.(*ipn.FileStore); ok {
|
|
||||||
if fp := fs.Path(); fp != "" {
|
|
||||||
if dir := filepath.Dir(fp); strings.EqualFold(filepath.Base(dir), "tailscale") {
|
|
||||||
return dir
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stateFile := paths.DefaultTailscaledStateFile()
|
|
||||||
if stateFile == "" {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return filepath.Dir(stateFile)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *LocalBackend) fileRootLocked(uid tailcfg.UserID) string {
|
func (b *LocalBackend) fileRootLocked(uid tailcfg.UserID) string {
|
||||||
|
@ -61,8 +61,25 @@ type Options struct {
|
|||||||
Port int
|
Port int
|
||||||
|
|
||||||
// StatePath is the path to the stored agent state.
|
// StatePath is the path to the stored agent state.
|
||||||
|
// It should be an absolute path to a file.
|
||||||
|
//
|
||||||
|
// Special cases:
|
||||||
|
//
|
||||||
|
// * empty string means to use an in-memory store
|
||||||
|
// * if the string begins with "kube:", the suffix
|
||||||
|
// is a Kubernetes secret name
|
||||||
|
// * if the string begins with "arn:", the value is
|
||||||
|
// an AWS ARN for an SSM.
|
||||||
StatePath string
|
StatePath string
|
||||||
|
|
||||||
|
// VarRoot is the the Tailscale daemon's private writable
|
||||||
|
// directory (usually "/var/lib/tailscale" on Linux) that
|
||||||
|
// contains the "tailscaled.state" file, the "certs" directory
|
||||||
|
// for TLS certs, and the "files" directory for incoming
|
||||||
|
// Taildrop files before they're moved to a user directory.
|
||||||
|
// If empty, Taildrop and TLS certs don't function.
|
||||||
|
VarRoot string
|
||||||
|
|
||||||
// AutostartStateKey, if non-empty, immediately starts the agent
|
// AutostartStateKey, if non-empty, immediately starts the agent
|
||||||
// using the given StateKey. If empty, the agent stays idle and
|
// using the given StateKey. If empty, the agent stays idle and
|
||||||
// waits for a frontend to start it.
|
// waits for a frontend to start it.
|
||||||
@ -744,6 +761,7 @@ func New(logf logger.Logf, logid string, store ipn.StateStore, eng wgengine.Engi
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("NewLocalBackend: %v", err)
|
return nil, fmt.Errorf("NewLocalBackend: %v", err)
|
||||||
}
|
}
|
||||||
|
b.SetVarRoot(opts.VarRoot)
|
||||||
b.SetDecompressor(func() (controlclient.Decompressor, error) {
|
b.SetDecompressor(func() (controlclient.Decompressor, error) {
|
||||||
return smallzstd.NewDecoder(nil)
|
return smallzstd.NewDecoder(nil)
|
||||||
})
|
})
|
||||||
|
Loading…
x
Reference in New Issue
Block a user