Documentation
¶
Index ¶
- Constants
- Variables
- func CtxAsBool(ctx context.Context, key contextKey) bool
- func CtxAsInt(ctx context.Context, key contextKey) int
- func CtxAsString(ctx context.Context, key contextKey) string
- func ExecuteClusterRemoteCmd(ctx context.Context, w io.Writer, hosts []RemoteCmdHost, remoteCmd string)
- func NewClient(ctx context.Context) *tailscale.Client
- func NewOauthClient(ctx context.Context) *tailscale.Client
- func ParseColumns(s string) (mapset.Set[string], mapset.Set[string])
- func ParseFilter(filter string) (filtercomp.AST, error)
- func RenderASCIITableView(ctx context.Context, tableView *GeneralTableView, w io.Writer) error
- func RenderIPs(ctx context.Context, tableView *GeneralTableView, w io.Writer) error
- func RenderJson(ctx context.Context, tableView *GeneralTableView, w io.Writer) error
- func RenderLogLine(ctx context.Context, w io.Writer, idx int, isStdErr bool, ...)
- func RenderRemoteSummary(ctx context.Context, w io.Writer, success, errors uint32, ...) error
- func RenderTableView(ctx context.Context, tableView *GeneralTableView, w io.Writer) error
- type CachedRepository
- type ConfigCtx
- type ContextView
- type DBQuery
- type Db
- func (d *Db[T]) Close() error
- func (d *Db[T]) Erase() error
- func (d *Db[T]) Exists(ctx context.Context) (bool, error)
- func (d *Db[T]) File() string
- func (d *Db[T]) IndexOpaqueItems(ctx context.Context, bucketName string, items []T) error
- func (d *Db[T]) LookupOpaqueItem(ctx context.Context, bucketName, primaryKey string) (*T, error)
- func (d *Db[T]) Open() error
- func (d *Db[T]) SearchOpaqueItems(ctx context.Context, bucketName string, query DBQuery) ([]T, error)
- func (d *Db[T]) TailnetScope() string
- type DbStats
- type DevicesTable
- type DevicesView
- type GeneralTableView
- type Header
- type HeaderMatchName
- type Indexer
- type InnerRepo
- type MockedDeviceRepo
- type RemoteCmdHost
- type RemoteDeviceRepo
- type SelfView
- type SortDirection
- type SortSpec
- type TailnetView
- type TailscaleAPICfgCtx
- type TailscaleCLICfgCtx
- type WrappedDevice
Constants ¶
const ( AppLongName = "Tailscale IPs" AppShortName = "tips" )
const ( // These two buckets contain FULL data. DevicesBucket = "bucket:devices.full" StatsBucket = "bucket:stats" StatsKey = "key:stats" )
Variables ¶
var ( AppVersion = "0.0.1" UserAgent = fmt.Sprintf("%s/%s", AppShortName, AppVersion) )
var ( // CtxKeyConfig holds all config settings that were resolved from the environment/config file/cli flags CtxKeyConfig = contextKey("configuration") CtxKeyUserQuery = contextKey("user-query") )
var ( HdrAddress = Header{Title: "Address", MatchName: MatchNameAddress} HdrAuthorized = Header{Title: "Authorized", MatchName: MatchNameAuthorized} HdrExitStatus = Header{Title: "Exit Status", MatchName: MatchNameExitStatus} HdrIpv4 = Header{Title: "Ipv4", MatchName: MatchNameIpv4} HdrIpv6 = Header{Title: "Ipv6", MatchName: MatchNameIpv6} HdrLastSeenAgo = Header{Title: "Last Seen", MatchName: MatchNameLastSeenAgo, ReqEnriched: true} HdrMachine = Header{Title: "Machine", MatchName: MatchNameMachine} HdrNo = Header{Title: "No", MatchName: MatchNameNo} HdrTags = Header{Title: "Tags", MatchName: MatchNameTags} HdrUser = Header{Title: "User", MatchName: MatchNameUser} HdrVersion = Header{Title: "Version", MatchName: MatchNameVersion} // AllHeadersList must contain the complete list of headers. AllHeadersList = []Header{ HdrAddress, HdrAuthorized, HdrExitStatus, HdrIpv4, HdrIpv6, HdrLastSeenAgo, HdrMachine, HdrNo, HdrTags, HdrUser, HdrVersion, } // AllHeadersMap initializes a map of HeaderMatchName to Header. AllHeadersMap = func() map[HeaderMatchName]Header { a := make(map[HeaderMatchName]Header) for _, hdr := range AllHeadersList { a[hdr.MatchName] = hdr } return a }() // DefaultColumnSet is the column set that ships out of the box. // Order matters which is why it's created as a slice. DefaultColumnSet = []Header{ HdrNo, HdrMachine, HdrIpv4, HdrTags, HdrUser, HdrVersion, HdrExitStatus, HdrLastSeenAgo, } )
Functions ¶
func CtxAsString ¶
func ExecuteClusterRemoteCmd ¶
func ParseFilter ¶
func ParseFilter(filter string) (filtercomp.AST, error)
func RenderASCIITableView ¶
func RenderJson ¶
func RenderLogLine ¶
func RenderRemoteSummary ¶
func RenderTableView ¶
Types ¶
type CachedRepository ¶
type CachedRepository struct {
// contains filtered or unexported fields
}
func NewCachedRepo ¶
func NewCachedRepo(innerRepo InnerRepo) *CachedRepository
func (*CachedRepository) DevicesResource ¶
func (c *CachedRepository) DevicesResource(ctx context.Context) ([]*WrappedDevice, error)
type ConfigCtx ¶
type ConfigCtx struct { Basic bool CacheTimeout time.Duration Columns mapset.Set[string] ColumnsExclude mapset.Set[string] Concurrency int Filters filtercomp.AST IPsOutput bool IPsDelimiter string JsonOutput bool NoCache bool NoColor bool PrefixFilter *prefixcomp.PrimaryFilterAST RemoteCmd string Slice *slicecomp.Slice SortOrder []SortSpec Tailnet string CachedElapsed time.Duration TailscaleAPI TailscaleAPICfgCtx TailscaleCLI TailscaleCLICfgCtx Page int TestMode bool }
func CtxAsConfig ¶
func NewConfigCtx ¶
func NewConfigCtx() *ConfigCtx
func (*ConfigCtx) IsRemoteCommand ¶
type ContextView ¶
type DBQuery ¶ added in v0.0.4
type DBQuery struct { PrefixFilters *prefixcomp.PrimaryFilterAST PrimaryKeys []string }
type Db ¶ added in v0.0.6
type Db[T Indexer] struct { // contains filtered or unexported fields }
func (*Db[T]) IndexOpaqueItems ¶ added in v0.0.6
func (*Db[T]) LookupOpaqueItem ¶ added in v0.0.6
func (*Db[T]) SearchOpaqueItems ¶ added in v0.0.6
func (d *Db[T]) SearchOpaqueItems(ctx context.Context, bucketName string, query DBQuery) ([]T, error)
SearchOpaqueItems can generically search with 3 different ways. 1. Using one or more primary keys, in which case this is a direct lookup (not technically a search) 2. Using the * (all/everything) construct, this is just a full table scan really. 3. Using a prefix scan, this is a seek to a segment of the index and should be fast assuming good selectivity.
func (*Db[T]) TailnetScope ¶ added in v0.0.6
type DevicesTable ¶
type DevicesTable struct { TailnetView Devices *DevicesView }
type GeneralTableView ¶
type GeneralTableView struct { ContextView TailnetView Self *SelfView Headers []Header Rows [][]string }
func ProcessDevicesTable ¶
func ProcessDevicesTable(ctx context.Context, devList []*WrappedDevice) (*GeneralTableView, error)
ProcessDevicesTable will apply sorting (if required), slicing (if required) and the massage/transformation of data to produce a final `*DevicesTable` that has everything required to render.
func (*GeneralTableView) HeaderTitles ¶ added in v0.0.7
func (g *GeneralTableView) HeaderTitles() []string
type Header ¶ added in v0.0.7
type Header struct { ReqEnriched bool MatchName HeaderMatchName Title string }
type HeaderMatchName ¶ added in v0.0.7
type HeaderMatchName string
const ( MatchNameAddress HeaderMatchName = "address" MatchNameAuthorized HeaderMatchName = "authorized" MatchNameBlocksIncomingConnections HeaderMatchName = "blocksincomingconnections" MatchNameClientVersion HeaderMatchName = "clientversion" MatchNameExitStatus HeaderMatchName = "exitstatus" MatchNameFullname HeaderMatchName = "fullname" MatchNameIpv4 HeaderMatchName = "ipv4" MatchNameIpv6 HeaderMatchName = "ipv6" MatchNameHostname HeaderMatchName = "hostname" MatchNameLastSeen HeaderMatchName = "lastseen" MatchNameLastSeenAgo HeaderMatchName = "lastseen.ago" MatchNameMachine HeaderMatchName = "machine" MatchNameName HeaderMatchName = "name" MatchNameNo HeaderMatchName = "no" MatchNameOS HeaderMatchName = "os" MatchNameTags HeaderMatchName = "tags" MatchNameUser HeaderMatchName = "user" MatchNameVersion HeaderMatchName = "version" )
type InnerRepo ¶
type InnerRepo interface {
DevicesResource(ctx context.Context) ([]*WrappedDevice, error)
}
type MockedDeviceRepo ¶
type MockedDeviceRepo struct {
// contains filtered or unexported fields
}
func NewMockedDeviceRepo ¶
func NewMockedDeviceRepo() *MockedDeviceRepo
func NewMockedDeviceRepoWithPath ¶ added in v0.0.6
func NewMockedDeviceRepoWithPath(filePath string) *MockedDeviceRepo
func (*MockedDeviceRepo) DevicesResource ¶
func (r *MockedDeviceRepo) DevicesResource(ctx context.Context) ([]*WrappedDevice, error)
type RemoteCmdHost ¶
type RemoteDeviceRepo ¶
type RemoteDeviceRepo struct {
// contains filtered or unexported fields
}
func NewRemoteDeviceRepo ¶
func NewRemoteDeviceRepo(client *tailscale.Client) *RemoteDeviceRepo
func (*RemoteDeviceRepo) DevicesResource ¶
func (r *RemoteDeviceRepo) DevicesResource(ctx context.Context) ([]*WrappedDevice, error)
type SortSpec ¶
type SortSpec struct { Field string Direction SortDirection }
func ParseSortString ¶
Parse the sort string and return a slice of SortSpec
type TailnetView ¶
TailnetView has everything known about a Tailnet
type TailscaleAPICfgCtx ¶
type TailscaleAPICfgCtx struct { Timeout time.Duration // ApiKey for regular authentication ApiKey string // OAuthClientID for OAuth based login. OAuthClientID string // OAuthClientSecret for Oauth based login. OAuthClientSecret string // ElapsedTime records the time this API call took. It's meant to be mutated during the API call and populated then. ElapsedTime time.Duration }
type TailscaleCLICfgCtx ¶
type TailscaleCLICfgCtx struct { }
type WrappedDevice ¶
type WrappedDevice struct { tailscale.Device EnrichedInfo *tailscale_cli.DeviceInfo `json:"enrichedInfo"` }
WrappedDevice is a type that wraps the core `tailscale.Device` type. It also holds the joined `tailscale_cli.DeviceInfo` that may or may not be present when fetched from within the tailnet. It also implements the `Indexer` interface, so it may be stored in the DB.
func (*WrappedDevice) EvalColumnField ¶ added in v0.0.7
func (w *WrappedDevice) EvalColumnField(ctx context.Context, idx int, headerMatchName HeaderMatchName) string
EvalColumnField is invoked for each "column" requested per device field. This code was built purposely to be dynamic and if it gets more complex it may be worthwhile to break the code up further into discreet functions per field. One additional thing I've been considering is the memoize of any redundant "heavy" work but so far there is none here.
func (*WrappedDevice) Key ¶
func (w *WrappedDevice) Key() string
Key returns the device field of how this device gets indexed into the cached db. Currently, it just uses the name such: "blade.tail372c.ts.net" which implies devices are stored in alphabetical order as ascending via their `name` field.