types.go 4.21 KB
Newer Older
ale's avatar
ale committed
1 2 3 4 5 6 7 8
package tabacco

import (
	"context"
	"fmt"
	"regexp"
	"strings"
	"time"
9

ale's avatar
ale committed
10
	"git.autistici.org/ai3/tools/tabacco/jobs"
ale's avatar
ale committed
11 12
)

ale's avatar
ale committed
13 14 15 16 17 18 19 20 21 22 23 24
// Params are configurable parameters in a format friendly to YAML
// representation.
type Params map[string]interface{}

// Get a string value for a parameter.
func (p Params) Get(key string) string {
	if s, ok := p[key].(string); ok {
		return s
	}
	return ""
}

ale's avatar
ale committed
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
// GetBool returns a boolean value for a parameter (may be a string).
// Returns value and presence.
func (p Params) GetBool(key string) (bool, bool) {
	if b, ok := p[key].(bool); ok {
		return b, true
	}
	if s, ok := p[key].(string); ok {
		switch strings.ToLower(s) {
		case "on", "yes", "true", "1":
			return true, true
		}
		return false, true
	}
	return false, false
}

ale's avatar
ale committed
41 42 43 44 45 46 47 48 49 50 51 52
// Backup is the over-arching entity describing a high level backup
// operation. Backups are initiated autonomously by individual hosts,
// so each Backup belongs to a single Host.
type Backup struct {
	// Backup ID (globally unique identifier).
	ID string `json:"id"`

	// Timestamp (backup start).
	Timestamp time.Time `json:"timestamp"`

	// Host.
	Host string `json:"host"`
ale's avatar
ale committed
53 54 55

	// Datasets.
	Datasets []*Dataset `json:"datasets"`
ale's avatar
ale committed
56 57 58
}

// An Atom is a bit of data that can be restored independently as part
59 60 61
// of a Dataset. Atoms are identified uniquely by their absolute path
// in the global atom namespace: this path is built by concatenating
// the source name, the dataset name, and the atom name.
ale's avatar
ale committed
62
type Atom struct {
ale's avatar
ale committed
63
	// Name (path-like).
ale's avatar
ale committed
64 65
	Name string `json:"name"`

ale's avatar
ale committed
66 67 68 69
	// Special attribute for the 'file' handler (path relative to
	// source root path).
	Path string `json:"path,omitempty"`
}
ale's avatar
ale committed
70 71 72 73 74 75 76 77

// A Dataset describes a data set as a high level structure containing
// one or more atoms. The 1-to-many scenario is justified by the
// following use case: imagine a sql database server, we may want to
// back it up as a single operation, but it contains multiple
// databases (the atom we're interested in), which we might want to
// restore independently.
type Dataset struct {
ale's avatar
ale committed
78
	// Name of the dataset (path-like). Will be prepended to atom
ale's avatar
ale committed
79 80 81
	// paths.
	Name string `json:"name"`

ale's avatar
ale committed
82 83 84
	// Source is the name of the source that created this Dataset,
	// stored so that the restore knows what to do.
	Source string `json:"source"`
ale's avatar
ale committed
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111

	// Atoms that are part of this dataset.
	Atoms []Atom `json:"atoms"`
}

// FindRequest specifies search criteria for atoms.
type FindRequest struct {
	Pattern   string `json:"pattern"`
	patternRx *regexp.Regexp

	Host        string `json:"host"`
	NumVersions int    `json:"num_versions"`
}

func (req *FindRequest) matchPattern(s string) bool {
	if req.patternRx == nil {
		req.patternRx = regexp.MustCompile(
			fmt.Sprintf("^%s$", strings.Replace(req.Pattern, "*", ".*", -1)))
	}
	return req.patternRx.MatchString(s)
}

// MetadataStore is the client interface to the global metadata store.
type MetadataStore interface {
	// Find the datasets that match a specific criteria. Only
	// atoms matching the criteria will be included in the Dataset
	// objects in the response.
ale's avatar
ale committed
112
	FindAtoms(context.Context, *FindRequest) ([]*Backup, error)
ale's avatar
ale committed
113 114

	// Add a dataset entry (the Backup might already exist).
ale's avatar
ale committed
115
	AddDataset(context.Context, *Backup, *Dataset) error
ale's avatar
ale committed
116 117 118 119
}

// Handler can backup and restore a specific class of datasets.
type Handler interface {
ale's avatar
ale committed
120 121
	BackupJob(RuntimeContext, Repository, *Backup, *Dataset) jobs.Job
	RestoreJob(RuntimeContext, Repository, *Backup, *Dataset, string) jobs.Job
ale's avatar
ale committed
122 123 124 125
}

// Repository is the interface to a remote repository.
type Repository interface {
ale's avatar
ale committed
126 127 128 129 130
	Init(context.Context, RuntimeContext) error
	BackupCmd(*Backup, *Dataset, []string) string
	RestoreCmd(context.Context, RuntimeContext, *Backup, *Dataset, []string, string) (string, error)
	BackupStreamCmd(*Backup, *Dataset) string
	RestoreStreamCmd(context.Context, RuntimeContext, *Backup, *Dataset, string) (string, error)
ale's avatar
ale committed
131 132
	Close() error
}
133 134 135

// Manager for backups and restores.
type Manager interface {
ale's avatar
ale committed
136 137 138 139
	BackupJob(context.Context, *SourceSpec) (*Backup, jobs.Job, error)
	Backup(context.Context, *SourceSpec) (*Backup, error)
	RestoreJob(context.Context, *FindRequest, string) (jobs.Job, error)
	Restore(context.Context, *FindRequest, string) error
140
	Close() error
141 142 143

	// Debug interface.
	GetStatus() ([]jobs.Status, []jobs.Status, []jobs.Status)
144
}