app

package
v1.11.7 Latest Latest
Warning

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

Go to latest
Published: Mar 7, 2023 License: Apache-2.0 Imports: 28 Imported by: 27

Documentation

Overview

Example

To start the first node of a dqlite cluster for the first time, its network address should be specified using the app.WithAddress() option.

When the node is restarted a second time, the app.WithAddress() option might be omitted, since the node address will be persisted in the info.yaml file.

The very first node has always the same ID (dqlite.BootstrapID).

package main

import (
	"fmt"
	"io/ioutil"
	"os"

	"github.com/canonical/go-dqlite/app"
)

func main() {
	dir, err := ioutil.TempDir("", "dqlite-app-example-")
	if err != nil {
		return
	}
	defer os.RemoveAll(dir)

	node, err := app.New(dir, app.WithAddress("127.0.0.1:9001"))
	if err != nil {
		return
	}

	fmt.Printf("0x%x %s\n", node.ID(), node.Address())

	if err := node.Close(); err != nil {
		return
	}

	node, err = app.New(dir)
	if err != nil {
		return
	}
	defer node.Close()

	fmt.Printf("0x%x %s\n", node.ID(), node.Address())
}
Output:

0x2dc171858c3155be 127.0.0.1:9001
0x2dc171858c3155be 127.0.0.1:9001

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func SimpleDialTLSConfig

func SimpleDialTLSConfig(cert tls.Certificate, pool *x509.CertPool) *tls.Config

SimpleDialTLSConfig returns a client-side TLS configuration with sane defaults (e.g. TLS version, ciphers and mutual authentication).

The cert parameter must be a public/private key pair, typically loaded from disk using tls.LoadX509KeyPair().

The pool parameter can be used to specify a custom signing CA (e.g. for self-signed certificates).

When server and client both use the same certificate, the same key pair and pool should be passed to SimpleListenTLSConfig() in order to generate the server-side config.

The returned config can be used as "client" parameter for the WithTLS App option, or as "config" parameter for the client.DialFuncWithTLS() helper.

TLS connections using the same `Config` will share a ClientSessionCache. You can override this behaviour by setting your own ClientSessionCache or nil.

A user can modify the returned config to suit their specifig needs.

func SimpleListenTLSConfig

func SimpleListenTLSConfig(cert tls.Certificate, pool *x509.CertPool) *tls.Config

SimpleListenTLSConfig returns a server-side TLS configuration with sane defaults (e.g. TLS version, ciphers and mutual authentication).

The cert parameter must be a public/private key pair, typically loaded from disk using tls.LoadX509KeyPair().

The pool parameter can be used to specify a custom signing CA (e.g. for self-signed certificates).

When server and client both use the same certificate, the same key pair and pool should be passed to SimpleDialTLSConfig() in order to generate the client-side config.

The returned config can be used as "listen" parameter for the WithTLS option.

A user can modify the returned config to suit their specifig needs.

func SimpleTLSConfig

func SimpleTLSConfig(cert tls.Certificate, pool *x509.CertPool) (*tls.Config, *tls.Config)

Types

type App

type App struct {
	// contains filtered or unexported fields
}

App is a high-level helper for initializing a typical dqlite-based Go application.

It takes care of starting a dqlite node and registering a dqlite Go SQL driver.

func New

func New(dir string, options ...Option) (app *App, err error)

New creates a new application node.

func (*App) Address added in v1.6.0

func (a *App) Address() string

Address returns the dqlite address of this application node.

func (*App) Client added in v1.7.0

func (a *App) Client(ctx context.Context) (*client.Client, error)

Client returns a client connected to the local node.

func (*App) Close

func (a *App) Close() error

Close the application node, releasing all resources it created.

func (*App) Driver added in v1.6.0

func (a *App) Driver() string

Driver returns the name used to register the dqlite driver.

func (*App) Handover added in v1.6.0

func (a *App) Handover(ctx context.Context) error

Handover transfers all responsibilities for this node (such has leadership and voting rights) to another node, if one is available.

This method should always be called before invoking Close(), in order to gracefully shutdown a node.

func (*App) ID

func (a *App) ID() uint64

ID returns the dqlite ID of this application node.

func (*App) Leader

func (a *App) Leader(ctx context.Context) (*client.Client, error)

Leader returns a client connected to the current cluster leader, if any.

func (*App) Open

func (a *App) Open(ctx context.Context, database string) (*sql.DB, error)

Open the dqlite database with the given name

func (*App) Ready added in v1.6.0

func (a *App) Ready(ctx context.Context) error

Ready can be used to wait for a node to complete some initial tasks that are initiated at startup. For example a brand new node will attempt to join the cluster, a restarted node will check if it should assume some particular role, etc.

If this method returns without error it means that those initial tasks have succeeded and follow-up operations like Open() are more likely to succeeed quickly.

type Option

type Option func(*options)

Option can be used to tweak app parameters.

func WithAddress

func WithAddress(address string) Option

WithAddress sets the network address of the application node.

Other application nodes must be able to connect to this application node using the given address.

If the application node is not the first one in the cluster, the address must match the value that was passed to the App.Add() method upon registration.

If not given the first non-loopback IP address of any of the system network interfaces will be used, with port 9000.

The address must be stable across application restarts.

func WithCluster

func WithCluster(cluster []string) Option

WithCluster must be used when starting a newly added application node for the first time.

It should contain the addresses of one or more applications nodes which are already part of the cluster.

Example

After starting the very first node, a second node can be started by passing the address of the first node using the app.WithCluster() option.

In general additional nodes can be started by specifying one or more addresses of existing nodes using the app.Cluster() option.

When the node is restarted a second time, the app.WithCluster() option might be omitted, since the node has already joined the cluster.

Each additional node will be automatically assigned a unique ID.

package main

import (
	"fmt"
	"io/ioutil"
	"os"

	"github.com/canonical/go-dqlite/app"
)

func main() {
	dir1, err := ioutil.TempDir("", "dqlite-app-example-")
	if err != nil {
		return
	}
	defer os.RemoveAll(dir1)

	dir2, err := ioutil.TempDir("", "dqlite-app-example-")
	if err != nil {
		return
	}
	defer os.RemoveAll(dir2)

	dir3, err := ioutil.TempDir("", "dqlite-app-example-")
	if err != nil {
		return
	}
	defer os.RemoveAll(dir3)

	node1, err := app.New(dir1, app.WithAddress("127.0.0.1:9001"))
	if err != nil {
		return
	}
	defer node1.Close()

	node2, err := app.New(dir2, app.WithAddress("127.0.0.1:9002"), app.WithCluster([]string{"127.0.0.1:9001"}))
	if err != nil {
		return
	}
	defer node2.Close()

	node3, err := app.New(dir3, app.WithAddress("127.0.0.1:9003"), app.WithCluster([]string{"127.0.0.1:9001"}))
	if err != nil {
		return
	}

	fmt.Println(node1.ID() != node2.ID(), node1.ID() != node3.ID(), node2.ID() != node3.ID())
	// true true true

	// Restart the third node, the only argument we need to pass to
	// app.New() is its dir.
	id3 := node3.ID()
	if err := node3.Close(); err != nil {
		return
	}

	node3, err = app.New(dir3)
	if err != nil {
		return
	}
	defer node3.Close()

	fmt.Println(node3.ID() == id3, node3.Address())
	// true 127.0.0.1:9003
}
Output:

func WithDiskMode added in v1.11.6

func WithDiskMode(disk bool) Option

WithDiskMode enables or disables disk-mode. WARNING: This is experimental API, use with caution and prepare for data loss. UNSTABLE: Behavior can change in future. NOT RECOMMENDED for production use-cases, use at own risk.

func WithExternalConn added in v1.11.0

func WithExternalConn(dialFunc client.DialFunc, acceptCh chan net.Conn) Option

WithExternalConn enables passing an external dial function that will be used whenever dqlite needs to make an outside connection.

Also takes a net.Conn channel that should be received when the external connection has been accepted.

func WithFailureDomain added in v1.7.0

func WithFailureDomain(code uint64) Option

WithFailureDomain sets the node's failure domain.

Failure domains are taken into account when deciding which nodes to promote to Voter or StandBy when needed.

func WithLogFunc

func WithLogFunc(log client.LogFunc) Option

WithLogFunc sets a custom log function.

func WithNetworkLatency added in v1.8.0

func WithNetworkLatency(latency time.Duration) Option

WithNetworkLatency sets the average one-way network latency.

func WithRolesAdjustmentFrequency added in v1.6.0

func WithRolesAdjustmentFrequency(frequency time.Duration) Option

WithRolesAdjustmentFrequency sets the frequency at which the current cluster leader will check if the roles of the various nodes in the cluster matches the desired setup and perform promotions/demotions to adjust the situation if needed.

The default is 30 seconds.

func WithSnapshotParams added in v1.9.0

func WithSnapshotParams(params dqlite.SnapshotParams) Option

WithSnapshotParams sets the raft snapshot parameters.

func WithStandBys added in v1.6.0

func WithStandBys(n int) Option

WithStandBys sets the number of nodes in the cluster that should have the StandBy role.

When a new node is added to the cluster or it is started again after a shutdown it will be assigned the StandBy role in case there are already enough online voters, but the current number of stand-bys is below n.

Similarly when a node with the StandBy role is shutdown gracefully by calling the Handover() method, it will try to transfer its StandBy role to another non-StandBy node, if one is available.

All App instances in a cluster must be created with the same WithStandBys setting.

The default value is 3.

func WithTLS

func WithTLS(listen *tls.Config, dial *tls.Config) Option

WithTLS enables TLS encryption of network traffic.

The "listen" parameter must hold the TLS configuration to use when accepting incoming connections clients or application nodes.

The "dial" parameter must hold the TLS configuration to use when establishing outgoing connections to other application nodes.

func WithUnixSocket added in v1.11.0

func WithUnixSocket(path string) Option

WithUnixSocket allows setting a specific socket path for communication between go-dqlite and dqlite.

The default is an empty string which means a random abstract unix socket.

func WithVoters added in v1.6.0

func WithVoters(n int) Option

WithVoters sets the number of nodes in the cluster that should have the Voter role.

When a new node is added to the cluster or it is started again after a shutdown it will be assigned the Voter role in case the current number of voters is below n.

Similarly when a node with the Voter role is shutdown gracefully by calling the Handover() method, it will try to transfer its Voter role to another non-Voter node, if one is available.

All App instances in a cluster must be created with the same WithVoters setting.

The given value must be an odd number greater than one.

The default value is 3.

type RolesChanges added in v1.7.0

type RolesChanges struct {
	// Algorithm configuration.
	Config RolesConfig

	// Current state of the cluster. Each node in the cluster must be
	// present as a key in the map, and its value should be its associated
	// failure domain and weight metadata or nil if the node is currently
	// offline.
	State map[client.NodeInfo]*client.NodeMetadata
}

RolesChanges implements an algorithm to take decisions about which node should have which role in a cluster.

You normally don't need to use this data structure since it's already transparently wired into the high-level App object. However this is exposed for users who don't want to use the high-level App object but still want to implement the same roles management algorithm.

func (*RolesChanges) Adjust added in v1.7.0

func (c *RolesChanges) Adjust(leader uint64) (client.NodeRole, []client.NodeInfo)

Adjust decides if there should be changes in the current roles.

Return the role that should be assigned and a list of candidates that should assume it, in order of preference.

func (*RolesChanges) Assume added in v1.7.0

func (c *RolesChanges) Assume(id uint64) client.NodeRole

Assume decides if a node should assume a different role than the one it currently has. It should normally be run at node startup, where the algorithm might decide that the node should assume the Voter or Stand-By role in case there's a shortage of them.

Return -1 in case no role change is needed.

func (*RolesChanges) Handover added in v1.7.0

func (c *RolesChanges) Handover(id uint64) (client.NodeRole, []client.NodeInfo)

Handover decides if a node should transfer its current role to another node. This is typically run when the node is shutting down and is hence going to be offline soon.

Return the role that should be handed over and list of candidates that should receive it, in order of preference.

type RolesConfig added in v1.7.0

type RolesConfig struct {
	Voters   int // Target number of voters, 3 by default.
	StandBys int // Target number of stand-bys, 3 by default.
}

RolesConfig can be used to tweak the algorithm implemented by RolesChanges.

Jump to

Keyboard shortcuts

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