tailkit

package module
v0.5.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 15, 2026 License: MIT Imports: 21 Imported by: 0

README

tailkit

Go library for building Tailscale-native tools. tailkit has two distinct concerns:

  1. tsnet utilities — useful for any tailnet tool regardless of tailkitd
  2. tailkitd client SDK — typed HTTP client for every tailkitd endpoint

Tools built with tailkit get consistent auth, peer discovery, and access to node-level integrations (Docker, systemd, metrics, files, vars, exec) across every node running tailkitd.

Recent additions include first-class SSE stream support for exec jobs, Docker logs/stats, systemd journal tails, and metrics streams including TCP listen-port discovery.

Tailkit's shared model is organized around four entities:

  • Peer: any Tailscale machine in the tailnet
  • Host: a peer with an associated tailkitd-* sidecar
  • Service: a workload on a host, such as a systemd unit, Docker container, script, or tool
  • Tailkitd: the tailkitd-* tsnet sidecar peer exposing the management API for one host

Install

go get github.com/wf-pro-dev/tailkit

Quick start

srv, err := tailkit.NewServer(tailkit.ServerConfig{
    Hostname: "devbox",
    AuthKey:  os.Getenv("TS_AUTHKEY"),
})
defer srv.Close()

// register this tool with tailkitd on startup
tailkit.Install(ctx, client.Tool{Name: "devbox", Version: build.Version, TsnetHost: "devbox"})

// single node
containers, err := tailkit.Node(srv, "vps-1").Docker().Containers(ctx)
err = tailkit.Node(srv, "vps-1").Metrics().StreamPorts(ctx, func(e tailkit.Event[tailkit.PortUpdate]) error {
    switch e.Data.Kind {
    case "snapshot":
        // replace current local state with e.Data.Ports
    case "bound", "released":
        // update local state with e.Data.Port
    }
    return nil
})

// fleet
hosts, err := tailkit.ListHosts(ctx, srv, tailkit.ListOnline)
cpuByNode, errs := tailkit.Nodes(srv, tailkit.PeersFromHosts(hosts)).Metrics().CPU(ctx)

Streaming APIs

tailkit now exposes a generic typed SSE helper plus typed stream helpers:

  • tailkit.Stream(node, ctx, path, eventNames, fn)
  • node.ExecJobStream(...)
  • node.Docker().StreamLogs(...)
  • node.Docker().StreamStats(...)
  • node.Systemd().StreamJournal(...)
  • node.Systemd().StreamSystemJournal(...)
  • node.Metrics().StreamCPU(...)
  • node.Metrics().StreamMemory(...)
  • node.Metrics().StreamNetwork(...)
  • node.Metrics().StreamProcesses(...)
  • node.Metrics().StreamAll(...)
  • node.Metrics().Ports()
  • node.Metrics().PortsAvailable()
  • node.Metrics().StreamPorts(...)

Both tailkit.Stream(...) and the typed stream helpers use tailkit.Event[T], preserving Name and ID alongside the decoded payload in Data.


Docs

Document Description
server.md NewServer, ServerConfig, TLS helpers, AuthMiddleware
node.md Node, Tools, Files, Vars, Docker, Systemd, Metrics
fleet.md Nodes, Discover, Broadcast, peer discovery primitives
errors.md Typed errors and how to check them

License

MIT

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrConflict     = client.ErrConflict
	ErrUnauthorized = client.ErrUnauthorized
)

Functions

func AuthMiddleware

func AuthMiddleware(srv *Server) func(http.Handler) http.Handler

AuthMiddleware authenticates every inbound request via Tailscale's WhoIs API.

func ExecWith

func ExecWith(ctx context.Context, vars map[string]string, argv []string) error

ExecWith injects vars into the environment of a local subprocess and runs it. Vars are set as KEY=VALUE environment variables. The subprocess inherits the current process's environment with the vars overlaid on top.

Secrets exist only in the child process environment and disappear when it exits — they are never written to disk.

Example:

vars, err := tailkit.Node(srv, "vps-1").Vars("myapp", "prod").List(ctx)
err = tailkit.ExecWith(ctx, vars, []string{"/usr/bin/node", "server.js"})

func Install

func Install(ctx context.Context, tool client.Tool) error

Install writes a Tool registration file to /etc/tailkitd/tools/{name}.json.

Call Install once at install time and again on every tool upgrade. tailkitd reads this file to populate its tool registry and exec command list. The write is atomic — tailkitd will never read a partially-written file.

Install validates:

  • Tool.Name is non-empty and matches [a-zA-Z0-9_-]+
  • Tool.Version is non-empty
  • Each Command.Name is non-empty
  • Each Command.ExecParts is non-empty and ExecParts[0] exists on disk
  • Each Command.Timeout is positive
  • Each Arg.Pattern (if set) is a valid regular expression

It creates /etc/tailkitd/tools/ if it does not exist.

func ListAgents added in v0.5.1

func ListAgents(ctx context.Context, srv *Server, opts *client.AgentListOptions) ([]client.Tailkitd, error)

ListAgents returns tailkitd-* sidecar peers, including orphans without a matching host peer.

func ListHosts added in v0.5.1

func ListHosts(ctx context.Context, srv *Server, opts *client.HostListOptions) ([]client.Host, error)

ListHosts returns hosts classified from Tailscale status by pairing each machine peer with its tailkitd-<hostname> sidecar.

Results do not include operator metadata from tailkitd's /host API. Use Node(...).Host or FleetClient.Hosts for that.

func ListPeers added in v0.5.1

func ListPeers(ctx context.Context, srv *Server, opts *client.PeerListOptions) ([]client.Peer, error)

ListPeers returns tailnet machine peers from local Tailscale status. tailkitd-* sidecar peers are excluded.

func NewClient added in v0.5.1

func NewClient(srv *Server) client.TailnetClient

NewClient creates the entry point for all operations on the Tailnet. It initializes the concrete HTTP transport and returns the top-level namespaces.

func PeersFromHosts added in v0.5.1

func PeersFromHosts(hosts []client.Host) []client.Peer

PeersFromHosts returns machine peers for a host list. It is the usual input shape for tailkit.Nodes.

func Uninstall

func Uninstall(name string) error

Uninstall removes the tool registration file for the named tool.

If the file does not exist, Uninstall returns nil — it is safe to call Uninstall when the tool may or may not be installed.

Types

type AgentListOptions added in v0.5.1

type AgentListOptions struct{ ReachableOnly bool }

type CPU added in v0.4.0

type CPU = client.CPU

type CallerContextKey

type CallerContextKey struct{}

CallerContextKey is the exported context key type for CallerIdentity.

type CallerIdentity

type CallerIdentity struct {
	Hostname    string
	TailscaleIP string
	UserLogin   string
	Caps        map[string]bool
}

CallerIdentity holds the verified identity of the caller on an inbound request.

func CallerFromContext

func CallerFromContext(ctx context.Context) (CallerIdentity, bool)

CallerFromContext retrieves the CallerIdentity injected by AuthMiddleware.

func (CallerIdentity) HasCap

func (id CallerIdentity) HasCap(cap string) bool

HasCap reports whether the caller was granted the given ACL capability.

type Event added in v0.3.4

type Event[T any] = client.Event[T]

type Host added in v0.5.0

type Host = client.Host

type JobUpdate added in v0.4.0

type JobUpdate = client.JobUpdate

type JournalEntry added in v0.3.4

type JournalEntry = client.JournalEntry

type LogLine added in v0.3.4

type LogLine = client.LogLine

type Memory added in v0.4.0

type Memory = client.Memory

type Metrics added in v0.4.0

type Metrics = client.Metrics

type Peer added in v0.1.12

type Peer = client.Peer

type Port added in v0.4.0

type Port = client.Port

type PortUpdate added in v0.4.0

type PortUpdate = client.PortUpdate

type Process added in v0.4.0

type Process = client.Process

type Server

type Server struct {
	*tsnet.Server
	Config ServerConfig
	// contains filtered or unexported fields
}

Server is a tailkit-managed tsnet server.

func NewServer

func NewServer(cfg ServerConfig) (*Server, error)

NewServer constructs and starts a tsnet server.

func (*Server) Close added in v0.4.1

func (s *Server) Close() error

Close shuts down the shared HTTP transport and underlying tsnet server.

func (*Server) HTTPClient added in v0.4.1

func (s *Server) HTTPClient() *http.Client

HTTPClient returns the shared HTTP client used for outbound peer requests.

func (*Server) ListenAndServe

func (s *Server) ListenAndServe(addr string, handler http.Handler) error

ListenAndServe starts a plain HTTP server on the tsnet listener.

func (*Server) ListenAndServeTLS

func (s *Server) ListenAndServeTLS(addr string, handler http.Handler) error

ListenAndServeTLS starts an HTTPS server on the tsnet listener.

func (*Server) StreamHTTPClient added in v0.4.2

func (s *Server) StreamHTTPClient() *http.Client

StreamHTTPClient returns the shared HTTP client used for long-lived streams.

func (*Server) TLSConfig

func (s *Server) TLSConfig() *tls.Config

TLSConfig returns a *tls.Config using Tailscale-issued certificates.

type ServerConfig

type ServerConfig struct {
	Hostname     string
	AuthKey      string
	StateDir     string
	Ephemeral    bool
	PeerCacheTTL time.Duration
	ControlURL   string
}

ServerConfig holds configuration for a tailkit-managed tsnet server.

type Service added in v0.5.0

type Service = client.Service

type ServiceCapabilities added in v0.5.1

type ServiceCapabilities = client.ServiceCapabilities

type ServiceListOptions added in v0.5.1

type ServiceListOptions struct {
}

type ServiceStatus added in v0.5.1

type ServiceStatus = client.ServiceStatus

type Tailkitd added in v0.5.1

type Tailkitd = client.Tailkitd

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL