Documentation
¶
Overview ¶
Package sdk is the contract between tt and the modules compiled into it.
A module may import this module and the other modules under sdk/ and nothing else from the tt repository.
The root package holds the module contract and the error contract:
- a module is a Constructor: given the core's Services, it returns cobra commands as [Mount]s, each with the path of the group it goes under;
- Services give a module's commands a logger, the Tarantool to run and its TarantoolVersion, files read through the Integrity checks, the Project directory, prompts (Services.Confirm), the standard Streams with their printers, the cluster configuration of a ClusterSource (Services.ClusterConfig) and the core's way to end the process for code that cannot return an error (Services.Exit);
- ExitError and ExitCode carry the exit code a command's error should end tt with, and UsageError marks an error in how a command was invoked, which tt follows with the command's usage;
- CoreVersion reports the version of the tt core the binary was built with;
- ClusterSource names where a cluster configuration comes from - an application (AppSource), a file (FileSource) or a configuration storage (StorageSource) - and ParseClusterSource tells them apart in a command-line argument; AddAppFlags declares --scope and --template, which find an application as the instance commands find it (AppLookup, ClusterSource.WithLookup); SplitInstance splits an "app:instance" reference, and Instances and InstanceConfig read the instances of a cluster configuration and the configuration each of them resolves.
The subpackages hold the rest:
- github.com/tarantool/tt/sdk/console runs an interactive console with line editing and history over a command processor;
- github.com/tarantool/tt/sdk/formatter renders the YAML a Tarantool console answers with as YAML, Lua or tables, the way tt's consoles print it;
- github.com/tarantool/tt/sdk/log is the logging facade and the secret redaction logic;
- github.com/tarantool/tt/sdk/output writes a command's result to stdout in the format the user asked for;
- github.com/tarantool/tt/sdk/sdktest fakes the core's Services and runs a module's commands in tests.
The contract module depends on cobra, pflag and go-config (github.com/tarantool/go-config/v2), whose types appear in it, and pins their versions: a module builds against the versions the core uses. It also depends on github.com/tarantool/tt/sdk/connect, whose URI rules ParseClusterSource applies. The formatter adds go-pretty and yaml.v2, which render its output, and the console adds go-prompt and x/term.
The process itself - which handlers log where, at what level, in which format - is configured by the tt core. Nothing in the SDK changes process state beyond what its documentation says.
Index ¶
- Constants
- Variables
- func AddAppFlags(cmd *cobra.Command, lookup *AppLookup)
- func CoreVersion() (string, bool)
- func ExitCode(err error) int
- func InstanceConfig(cfg goconfig.Config, name string) (goconfig.Config, error)
- func Instances(cfg goconfig.Config) ([]string, error)
- func SplitInstance(ref string) (string, string)
- type AppLookup
- type ClusterConfig
- type ClusterSource
- type Constructor
- type Credentials
- type Edition
- type ExitCoder
- type ExitError
- type Integrity
- type Mount
- type Project
- type ReleaseType
- type Services
- type Streams
- type Tarantool
- type TarantoolVersion
- type UsageError
Constants ¶
const ( // ScopeFlag is --scope, the scope the application is looked for in: // project, user or system. ScopeFlag = "scope" // TemplateFlag is --template, the template of the application its // instances and its cluster config are taken from. TemplateFlag = "template" )
The flags with which a command of tt that takes an application finds it, as the instance commands do. AddAppFlags declares them.
const ( // ExitOK is a command that did what it was asked. ExitOK = 0 // ExitFailure is a request that cannot be carried out as given, and the // fix is on the caller's side: an invalid manifest, a stale lock, an // unresolvable dependency, a malformed URL, a missing path. It is also the // code of every error that carries none. ExitFailure = 1 // ExitSystem is a failure of the system the command ran on rather than of // the request: a build backend that failed, a server that could not be // reached or did not answer in time, a filesystem that refused an // operation for want of permission or space. ExitSystem = 2 // ExitPartial is a multi-target operation that partly succeeded: some of // its targets went through and some did not. ExitPartial = 3 )
Process exit codes tt returns. `tt help errors` describes them to users.
Variables ¶
var ErrNotFound = errors.New("not found")
ErrNotFound reports a thing tt looked for and did not find, such as a Tarantool executable. Services wrap it; test for it with errors.Is.
Functions ¶
func AddAppFlags ¶
AddAppFlags declares --scope and --template on cmd, bound to lookup, as every command of tt that takes an application declares them, with the same help and the same completion. The values are checked when the application is looked for: Services.ClusterConfig refuses a scope other than project, user and system, and a template the application cannot have.
func CoreVersion ¶
CoreVersion returns the version of the tt core the running binary was built with, as Go recorded it in the build info: v3.1.0, or a pseudo-version for an untagged commit. When the binary is tt itself that is the main module's version; otherwise it is the version of the core dependency, or of its replacement when the dependency is replaced.
It reports false when the version is unknown: a binary without build info, a core built from a working tree ("(devel)"), or a core replaced by a local directory.
The core version may later be offered by Services instead.
func ExitCode ¶
ExitCode returns the process exit code for err: ExitOK for nil, otherwise the first code other than ExitFailure that an ExitCoder in the chain carries, and ExitFailure when there is none.
ExitFailure is the weakest code. It is the one a command wraps its errors in generically, so it does not hide what it wraps: a build backend failure (ExitSystem) wrapped as "building the package" with ExitFailure still exits ExitSystem. Any other code is a deliberate verdict and stands, even over a different code deeper in the chain.
The search follows errors.As order. After a code-1 carrier it continues into what that carrier wraps, not into its siblings in a joined error.
Classifying errors that carry no code - a failed dial, a refused write - as ExitSystem is not done here: that policy is tt's, applied once to every command's error, and a result of ExitFailure from this function is its input.
func InstanceConfig ¶
InstanceConfig returns the configuration of the instance name in cfg, the Config of a ClusterConfig, as Tarantool resolves it for that instance: what the instance sets, over what its replicaset sets, over its group's, over the global section. Credentials are merged across the levels rather than replaced.
An instance cfg does not declare is an error wrapping ErrNotFound; a cfg without the Tarantool inheritance hierarchy is an error too.
func Instances ¶
Instances returns the names of the instances cfg declares, sorted. cfg is the Config of a ClusterConfig: one without the Tarantool inheritance hierarchy is an error.
func SplitInstance ¶
SplitInstance splits ref, a reference to an instance of the form "app:instance", into the application and the instance. A ref without the delimiter is an application alone, and instance is empty. Only the first delimiter splits: "a:b:c" is the instance "b:c" of the application "a".
Types ¶
type AppLookup ¶
type AppLookup struct {
// Scope is "project", "user" or "system", or empty.
Scope string
// Template is the name of a template of the application, or empty.
Template string
}
AppLookup is how the application of an AppSource is found: the scope it is looked for in and the template its pair, the instances description and the cluster config, is taken from - the values of --scope and --template (AddAppFlags). An empty field leaves the choice to the rules the instance commands follow without the flag: the project the command runs in when it has the name, and the system scope otherwise; the template the application runs from, "default" unless the host has a pair of its own.
type ClusterConfig ¶
type ClusterConfig struct {
// Config is the configuration: an immutable go-config snapshot carrying
// the Tarantool hierarchy, so [Instances] and [InstanceConfig] read it.
Config goconfig.Config
// Dir is the absolute directory a relative path in the configuration -
// such as an SSL file of an instance - is relative to: the application
// directory, where its instances run, for an application, and the
// directory of the file for a cluster configuration file. It is "" for a
// configuration storage, whose paths have no directory of their own.
Dir string
}
ClusterConfig is a cluster configuration and the directory it was read from, as Services.ClusterConfig returns them.
type ClusterSource ¶
type ClusterSource struct {
// contains filtered or unexported fields
}
ClusterSource names where a cluster configuration comes from: an application (AppSource), a cluster configuration file (FileSource) or a configuration storage (StorageSource). ParseClusterSource tells them apart in a command-line argument.
The zero ClusterSource names nothing, and Services.ClusterConfig refuses it. ClusterSource is comparable: two sources are equal when they were built by the same constructor from the same arguments, with the same AppLookup, so a source can be a map key.
func AppSource ¶
func AppSource(name string) ClusterSource
AppSource names the cluster configuration of the application name, found as the instance commands find it without --scope and --template: the cluster config of the pair it runs from, together with the TT_* environment and the centralized storage the file names. name is an application name without an instance; see SplitInstance. ClusterSource.WithLookup finds it as the flags say.
func FileSource ¶
func FileSource(path string) ClusterSource
FileSource names the cluster configuration file at path, together with the TT_* environment and the centralized storage the file names. A relative path is relative to the working directory.
func ParseClusterSource ¶
func ParseClusterSource(arg string, creds Credentials) ClusterSource
ParseClusterSource classifies arg, a command-line argument naming a cluster configuration, the way tt's own commands do: a storage URI (a URL with a scheme and a host, see github.com/tarantool/tt/sdk/connect.CreateURIOpts) is a StorageSource; otherwise the path of an existing regular file is a FileSource; anything else is an AppSource. creds are used by a storage source only.
An argument that names an instance too, such as "app:instance", is split with SplitInstance first.
func StorageSource ¶
func StorageSource(uri string, creds Credentials) ClusterSource
StorageSource names the cluster configuration kept in an etcd or a Tarantool config storage under the prefix of uri, such as "http://user:pass@localhost:2379/prefix?timeout=5". The storage alone is read: no file and no environment are merged in.
The credentials used are the ones uri carries when it carries a user name or a password. Otherwise each of creds' fields is used, and an empty one is taken from the environment: TT_CLI_ETCD_USERNAME and TT_CLI_ETCD_PASSWORD for etcd, TT_CLI_USERNAME and TT_CLI_PASSWORD for a Tarantool config storage.
func (ClusterSource) App ¶
func (s ClusterSource) App() (string, bool)
App returns the application name of a source built by AppSource, and whether it was.
func (ClusterSource) File ¶
func (s ClusterSource) File() (string, bool)
File returns the path of a source built by FileSource, and whether it was.
func (ClusterSource) Lookup ¶
func (s ClusterSource) Lookup() AppLookup
Lookup returns how the application of a source built by AppSource is found (ClusterSource.WithLookup), and the zero AppLookup for any other source.
func (ClusterSource) Storage ¶
func (s ClusterSource) Storage() (string, Credentials, bool)
Storage returns the URI and the credentials of a source built by StorageSource, and whether it was.
func (ClusterSource) String ¶
func (s ClusterSource) String() string
String describes the source for a message: `application "name"`, `file "path"` or `storage "uri"`. The URI is shown without its user information and the credentials are never shown.
func (ClusterSource) WithLookup ¶
func (s ClusterSource) WithLookup(lookup AppLookup) ClusterSource
WithLookup returns s, built by AppSource, with its application found as lookup says, as --scope and --template of a command give it. Any other source is returned as it is: a file and a storage are not looked for.
type Constructor ¶
Constructor builds a module's commands. The core calls it once per process, before tt is configured, so only Services.Log may be used while it runs; the other services are for the commands' hooks, which run after. A constructor must not change process state: it declares commands and their flags and nothing else.
type Credentials ¶
type Credentials struct {
// Username is the user name; empty when none is given.
Username string
// Password is the password; empty when none is given.
Password string
}
Credentials are a user name and a password for a configuration storage.
type ExitCoder ¶
type ExitCoder interface {
error
// ExitStatus returns the process exit code for this error.
ExitStatus() int
}
ExitCoder is implemented by errors that carry the process exit code tt should return for them.
The method is called ExitStatus rather than ExitCode on purpose: *exec.ExitError has an ExitCode method that reports a child process's status (-1 when it was killed by a signal), and a child's status wrapped deep in an error chain is not tt's verdict on the command.
type ExitError ¶
type ExitError struct {
// Code is the process exit code, one of the Exit* constants.
Code int
// Err is the wrapped error. It must not be nil.
Err error
}
ExitError wraps an error with the process exit code tt should return for it.
func Errorf ¶
Errorf formats an error the way fmt.Errorf does, %w included, and wraps it with an exit code.
type Integrity ¶
type Integrity interface {
// Open opens the file at path for reading, having checked it.
Open(path string) (io.ReadCloser, error)
}
Integrity reads files through tt's integrity checks: a file that fails them cannot be opened.
type Mount ¶
type Mount struct {
// Path is the command's parent, named by command names from the root down
// and separated by spaces: "" is the root, "replicaset vshard" is the
// vshard group under replicaset. Aliases do not name a parent. A group on
// the path that no module provides is created, without a description.
Path string
// Cmd is the command. It is fresh - built by the constructor that returns
// it, with no parent - and the core owns it once the constructor returns:
// the core adds it to the tree and wraps its hooks to report the errors
// they return.
Cmd *cobra.Command
}
Mount is a command a module contributes to tt, and where it goes.
type Project ¶
type Project interface {
// Dir returns the project directory as an absolute path: the directory
// the user named on the command line, or the working directory. No
// manifest is searched for.
Dir() (string, error)
}
Project is the directory a command works on.
type ReleaseType ¶
type ReleaseType int
ReleaseType is the stage of a Tarantool release.
const ( // ReleaseGA is a general-availability release, 3.2.1. It is the zero // value, so a TarantoolVersion given numbers alone is a release. ReleaseGA ReleaseType = iota // ReleaseNightly is the first commit of a release series, spelled // "entrypoint": 3.3.0-entrypoint. ReleaseNightly // ReleaseAlpha is an alpha: 3.0.0-alpha2. ReleaseAlpha // ReleaseBeta is a beta: 3.0.0-beta1. ReleaseBeta // ReleaseRC is a release candidate: 3.0.0-rc1. ReleaseRC )
func (ReleaseType) String ¶
func (r ReleaseType) String() string
String returns the release type as a version spells it: "entrypoint", "alpha", "beta" or "rc", and "" for ReleaseGA.
type Services ¶
type Services interface {
// Log returns the module's logger: the process logger with a
// module=<name> attribute. Whether debug records are shown is the
// process's --verbose; test it with Logger.Enabled.
Log() *slog.Logger
// Tarantool returns the Tarantool the command should run: the one the
// project bundles, when it has one, and the environment's otherwise.
// When there is none the error wraps ErrNotFound.
Tarantool() (Tarantool, error)
// Integrity returns the integrity checks files are read through.
Integrity() Integrity
// Project returns the project the command works on.
Project() Project
// Confirm asks the user question on stderr and reads a yes or no answer
// from stdin. When the user asked tt not to prompt (--no-prompt) it asks
// nothing and returns fallback, which is therefore the answer that is
// safe to assume.
Confirm(question string, fallback bool) (bool, error)
// Streams returns the process's standard streams and the printers bound
// to them.
Streams() Streams
// ClusterConfig returns the cluster configuration of src as Tarantool 3
// sees it, as an immutable snapshot, with the directory of the file it
// was read from ([ClusterConfig.Dir]):
//
// - for an application or a file, the cluster config file merged with
// the TT_* environment and with the etcd or Tarantool config storage
// the file names, in Tarantool's order of precedence, the storage
// read through the integrity checks;
// - for a storage, what the storage holds under the URI's prefix (or
// at its key= parameter), and nothing else.
//
// The configuration is not validated against Tarantool's schema. It
// carries the Tarantool hierarchy, so [Instances] and [InstanceConfig]
// read it. An application or a file that does not exist, an application
// without a cluster configuration and a storage that holds nothing under
// the prefix (or at the key) wrap ErrNotFound. A storage that cannot be
// reached is another error.
ClusterConfig(ctx context.Context, src ClusterSource) (ClusterConfig, error)
// Exit ends the process as the core ends it for a command that returned
// err: it reports err once and exits with the code tt returns for it
// ([ExitCode], and ExitSystem for a failure of the system). Exit(nil)
// exits ExitOK. It is for code that cannot return an error to the
// command, such as a callback of an interactive prompt; a command that
// can return its error must. Exit does not return.
Exit(err error)
}
Services are what the tt core offers a module.
Only the core and github.com/tarantool/tt/sdk/sdktest implement Services; a module must not, since methods may be added in a minor release of the SDK. Log is valid at any time. Every other method is valid only once tt is configured - in a command's hooks - and panics before that with a message naming the module and the method. Services are safe for concurrent use.
type Streams ¶
type Streams interface {
// IO returns stdin, stdout and stderr.
IO() output.Streams
// Printer returns a Printer writing to stdout in format, with every
// format the core encodes (such as YAML) and the core's check of whether
// stdout is a terminal.
Printer(format output.Format) (*output.Printer, error)
}
Streams are the process's standard streams.
type Tarantool ¶
type Tarantool interface {
// Path returns the path to the executable.
Path() string
// Version returns the version the executable reports. It runs the
// executable the first time and remembers the answer.
Version() (TarantoolVersion, error)
}
Tarantool is a Tarantool executable.
type TarantoolVersion ¶
type TarantoolVersion struct {
// Major, Minor and Patch are the version numbers.
Major, Minor, Patch uint64
// Release is the release stage; ReleaseGA for a release.
Release ReleaseType
// ReleaseNum is the number of the stage, 2 in 3.0.0-rc2; 0 when the stage
// has none.
ReleaseNum uint64
// Commits is the number of commits after the release tag, 12 in
// 3.2.0-12-g1a2b3c4.
Commits uint64
// Hash is the abbreviated commit hash, 1a2b3c4 in 3.2.0-12-g1a2b3c4,
// without the "g" of git describe; "" when the version has none.
Hash string
// Revision is the build revision of an Enterprise SDK, 579 in -r579.
Revision uint64
// BuildName is the name of a custom build that prefixes the version,
// "debug" in debug-3.2.0; "" when there is none.
BuildName string
// Edition is the edition of the build; EditionUnknown when it was not
// determined. The version string does not carry it.
Edition Edition
// Raw is the version string the version was parsed from; "" for a
// version built from its fields.
Raw string
}
TarantoolVersion is the version of a Tarantool build, as its --version reports it: 3.2.0-0-g8aef7fc-r40, say. It is a plain value; the zero value is 0.0.0.
func ParseTarantoolVersion ¶
func ParseTarantoolVersion(str string) (TarantoolVersion, error)
ParseTarantoolVersion parses a Tarantool version string - the last word of the first line of tarantool --version. The edition is not part of the string and stays EditionUnknown.
func (TarantoolVersion) AtLeast ¶
func (v TarantoolVersion) AtLeast(major, minor, patch uint64) bool
AtLeast reports whether v is major.minor.patch or newer. A pre-release of that version is older: 3.0.0-rc1 is not at least 3.0.0.
func (TarantoolVersion) Compare ¶
func (v TarantoolVersion) Compare(other TarantoolVersion) int
Compare returns -1 when v is older than other, 1 when it is newer and 0 when neither is. Versions are ordered by their numbers, then by release stage (entrypoint, alpha, beta, rc, release) and its number, then by commits and revision. The hash, build name, edition and Raw do not take part.
func (TarantoolVersion) String ¶
func (v TarantoolVersion) String() string
String returns Raw when the version was parsed, and otherwise spells the version from its fields the way Tarantool does: [build-]major.minor.patch[-stageN][-commits][-ghash][-rrevision].
type UsageError ¶
type UsageError struct {
// Err is the wrapped error. It must not be nil.
Err error
}
UsageError is a command invoked the wrong way: an argument or a flag value the command cannot accept. tt reports it the way it reports its own argument errors - the message, then the command's usage - and exits ExitFailure unless the wrapped error carries another code.
Return one from a command's RunE; test for one with errors.As.
func Usagef ¶
func Usagef(format string, args ...any) *UsageError
Usagef formats a usage error the way fmt.Errorf does, %w included.
func WithUsage ¶
func WithUsage(err error) *UsageError
WithUsage marks err as a usage error. It panics when err is nil, as WithCode does.
func (*UsageError) Unwrap ¶
func (e *UsageError) Unwrap() error
Unwrap exposes the wrapped error to errors.Is and errors.As.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
backup
module
|
|
|
cluster
module
|
|
|
connect
module
|
|
|
Package console runs an interactive console over a command processor.
|
Package console runs an interactive console over a command processor. |
|
dial
module
|
|
|
Package formatter renders the results of a Tarantool console request.
|
Package formatter renders the results of a Tarantool console request. |
|
integrity
module
|
|
|
internal
|
|
|
clusteryaml
Package clusteryaml builds a cluster configuration from YAML the way the tt core builds one: with the Tarantool inheritance hierarchy, so that the SDK's InstanceConfig and Instances work on the result.
|
Package clusteryaml builds a cluster configuration from YAML the way the tt core builds one: with the Tarantool inheritance hierarchy, so that the SDK's InstanceConfig and Instances work on the result. |
|
Package log is tt's logging facade over log/slog.
|
Package log is tt's logging facade over log/slog. |
|
logtest
Package logtest captures slog records for tests.
|
Package logtest captures slog records for tests. |
|
Package output writes a command's result to stdout.
|
Package output writes a command's result to stdout. |
|
Package sdktest is a fake of the tt core for testing modules: Services that record what a module does with them, and Run, which hangs a module's commands on a root the way the core does and runs one.
|
Package sdktest is a fake of the tt core for testing modules: Services that record what a module does with them, and Run, which hangs a module's commands on a root the way the core does and runs one. |