instances

package
v3.0.0-alpha.2 Latest Latest
Warning

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

Go to latest
Published: Nov 5, 2026 License: BSD-2-Clause Imports: 15 Imported by: 0

Documentation

Overview

Package instances parses the description of the instances an application runs: the instances.yaml of a project template or of a host. It takes bytes rather than a path, because the records of the instance registry in etcd, when it comes, are in the same format and go through the same parser.

Format

A description is a YAML mapping from an instance name to its record, like the instances.yml of tt2, so a tt2 file is a valid description and migrating one comes down to adding fields. An empty record, written as a bare name or as {}, is valid:

router-1:
storage-1: {}
legacy-1:
  script: init.lua
worker-1:
  binary: ./bin/worker
  args: [--port, 8080]
  env:
    LOG_LEVEL: info
  workdir: ./var/worker
  stop_signal: SIGINT
  stop_timeout: 30s
  logrotate_signal: SIGHUP
  restart: on-failure

The fields a record sets tell what the instance is (Kind): with neither binary nor script it is a Tarantool instance configured by the cluster config, with script a Tarantool instance that configures itself in its script (box.cfg), with binary an external process. binary and script are mutually exclusive.

Parse returns the records in the order of the description: the order the instances start in and the order status lists them in follow it, so neither may depend on the iteration order of a map.

The record "*"

The record named "*" stands for every instance of the topology of the cluster config that no other record names, so that an instance added to the config runs without being repeated in the description:

"*":
  restart: on-failure
router-1:
  restart: always
worker-1:
  binary: ./bin/worker

Its instances are Tarantool instances configured by the cluster config, each with the fields of "*"; binary and script, which would make them something else, are refused in it. A record naming one of them replaces "*" for it whole: router-1 above restarts always and takes nothing from "*". Which instances "*" stands for is up to whoever reads the config with the description, which is why Parse returns "*" apart from the records that name instances (Description.Wildcard), with the place it takes among them: whoever iterates the instances cannot take "*" for one.

"*" has to be quoted. Unquoted, a * starts an alias, which YAML refuses without a name; the message of that error points at the quotes.

Strictness

Whatever the parser does not understand is an error, never dropped: an unknown field, a field without a value, a name declared twice, a second YAML document. A misspelt field that is silently dropped leaves the instance running with the default its author meant to change; tt2 read instances.yml that way, and that is what users complained about.

Aliases and merge keys are refused as well. Without them every value in the result is written out in the input, so a small input cannot expand into a huge result; and accepting them later breaks no description written before.

Parse reports every problem it finds, not only the first, each as an *Error that wraps ErrInvalid and names the line, the instance and the field, so that a broken description is fixed in one pass.

Values

A field that holds a string, and every item of args and value of env, takes a plain scalar by the text it is written with: "args: [--port, 8080]" passes "8080", and "RATIO: 1.50" in env sets "1.50", not the "1.5" a round trip through a number would give. A scalar with a tag that is not a plain YAML type (!!binary, a local tag) is refused, because its text is not the value its author meant.

stop_signal and logrotate_signal are signal names with or without the SIG prefix, in upper case; only the signals that Linux and macOS share are known, so that a description runs on either. stop_timeout is a positive Go duration such as 30s. restart is one of the values of systemd's Restart= that the supervisor can follow: no (the default), on-failure and always.

Paths

A relative binary, script or workdir is resolved against the application directory given to Parse, not against the location of the description: the description of a host lives in <root>/etc/<app>/, while the paths in it point into the version of the application, so ./bin/worker means the same in a template and in the description of a host. The one exception is a binary without a slash: "binary: python3" names a program, looked up when the instance starts in .rocks/bin of the application, where tt builds its executable components, and then in PATH, the way a shell looks up a command. Any other file shipped with the application is spelled with a slash, as bin/worker or ./worker; a script is always a path, since it is never looked up.

Out of scope

The parser reads no files and knows no topology. Whether the names of the Tarantool instances are in the topology of the cluster config, and which instances "*" stands for, is up to whoever loads the config together with the description. Every field is accepted in every record, and fields a record leaves out stay zero, except restart: which fields an instance of each kind honours, and the defaults for the stop signal and the stop timeout, belong to whoever builds its supervisor.Spec, and they differ between Tarantool and external processes.

Index

Constants

View Source
const WildcardName = "*"

WildcardName is the name of the record that stands for the instances of the topology of the cluster config that the description does not name (Wildcard). It names no instance, so that app:* of a target keeps meaning every instance of the application.

Variables

View Source
var ErrInvalid = errors.New("invalid instance description")

ErrInvalid is wrapped by every problem Parse finds in a description, so that a broken description can be told from a mistake of the caller.

Functions

This section is empty.

Types

type Description

type Description struct {
	// Instances are the records that name an instance, in the order they
	// are written in. The record "*" is not among them: it names none.
	Instances []Instance
	// Wildcard is the record "*", nil when the description has none.
	Wildcard *Wildcard
}

Description is what Parse reads from a description.

func Parse

func Parse(data []byte, appDir string) (Description, error)

Parse parses a description and returns its records in the order they are written in, the record "*" apart from the others. An empty description, with no document or a null one, has no records.

A relative path in script and workdir, and in binary when it has a slash, is resolved against appDir, which must be absolute; Parse reads nothing from it. A binary without a slash is a program name and is kept as it is. When appDir is reached through a link that may be switched, such as <root>/apps/<app>, pass the directory the link points to, so that the paths stay the same for as long as the instance runs.

The returned error is a join of every problem found, each an *Error, when the description is invalid; Parse returns no records then.

type Error

type Error struct {
	// Line is the line of the problem, counted from 1; zero when the problem
	// has no single line, as with a syntax error, whose message carries it.
	Line int
	// Instance is the name of the record the problem is in, WildcardName for
	// the record "*"; empty for a problem outside of a record or with the
	// name itself.
	Instance string
	// Field is the field the problem is in; empty for a problem with the
	// record as a whole.
	Field string
	// Msg says what is wrong. It names the field itself, so that the message
	// reads on its own.
	Msg string
}

Error is a problem in a description. Callers match ErrInvalid with errors.Is and get at the location with errors.As rather than parse the message.

func (*Error) Error

func (err *Error) Error() string

func (*Error) Unwrap

func (err *Error) Unwrap() error

type Instance

type Instance struct {
	// Name is the key of the record. It is not empty, not "." or "..", and
	// has neither a slash nor a control character, so that it can name a
	// directory.
	Name string
	// Binary is the executable of an external process: an absolute path, or,
	// when the record names it without a slash, the name of a program to look
	// up when the instance starts, in .rocks/bin of the application and then
	// in PATH.
	Binary string
	// Script is the absolute path of the script of a Tarantool instance that
	// configures itself.
	Script string
	// Args are the arguments, without the program name.
	Args []string
	// Env holds the variables set on top of the inherited environment.
	Env map[string]string
	// Workdir is the absolute path of the working directory.
	Workdir string
	// StopSignal is the signal that stops the instance.
	StopSignal syscall.Signal
	// StopTimeout is how long the instance may take to stop after the stop
	// signal before it is killed. It is positive when set.
	StopTimeout time.Duration
	// Restart is the restart policy; RestartNo when the record sets none.
	Restart RestartPolicy
	// LogrotateSignal is the signal that makes an external process reopen
	// its logs; zero when the record sets none.
	LogrotateSignal syscall.Signal
}

Instance is one record of a description. A field the record leaves out is zero, except Restart.

func (*Instance) Kind

func (inst *Instance) Kind() Kind

Kind tells how the instance runs.

type Kind

type Kind int

Kind tells how an instance runs. It follows from the fields of its record.

const (
	// KindCluster is a Tarantool instance configured by the cluster config:
	// a record with neither binary nor script.
	KindCluster Kind = iota
	// KindScript is a Tarantool instance configured by its own script: a
	// record with script.
	KindScript
	// KindExternal is an external process: a record with binary.
	KindExternal
)

type RestartPolicy

type RestartPolicy string

RestartPolicy tells whether the supervisor starts an instance again after it exits on its own. The values are those of systemd's Restart=, so that a unit generated for the instance carries the policy over unchanged.

const (
	// RestartNo never starts the instance again. It is the default.
	RestartNo RestartPolicy = "no"
	// RestartOnFailure starts the instance again after it exits with a
	// non-zero status or is killed by a signal.
	RestartOnFailure RestartPolicy = "on-failure"
	// RestartAlways starts the instance again whatever its exit.
	RestartAlways RestartPolicy = "always"
)

type Wildcard

type Wildcard struct {
	// At is where the instances "*" stands for go among
	// Description.Instances: after the first At records, which are those
	// written before it.
	At int
	// Fields are the fields of "*", as a record named WildcardName. It is a
	// Tarantool instance configured by the cluster config (KindCluster):
	// binary and script are refused in "*".
	Fields Instance
}

Wildcard is the record "*" of a description. It stands for every instance of the topology of the cluster config that no other record of the description names, each a Tarantool instance configured by that config with the fields of "*"; a record naming one of them replaces "*" for it whole, without taking any of its fields.

Which instances those are is up to whoever reads the config together with the description: the parser does not know the topology.

func (*Wildcard) Instance

func (wildcard *Wildcard) Instance(name string) Instance

Instance returns the record of the instance name that "*" stands for: the fields of "*" under that name, sharing nothing with another instance.

Jump to

Keyboard shortcuts

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