Implement initial 'wdcli backup_instance' command
This commit performs an initial implementation of the 'backup_instance' command.
This commit is contained in:
parent
a64c02cd78
commit
2a14d93d3c
17 changed files with 437 additions and 135 deletions
52
env/backup.go
vendored
Normal file
52
env/backup.go
vendored
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
package env
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (dis Distillery) BackupDir() string {
|
||||
return filepath.Join(dis.Config.DeployRoot, "backups")
|
||||
}
|
||||
|
||||
func (dis Distillery) InprogressBackupPath() string {
|
||||
return filepath.Join(dis.BackupDir(), "inprogress")
|
||||
}
|
||||
|
||||
func (dis Distillery) FinalBackupPath() string {
|
||||
return filepath.Join(dis.BackupDir(), "final")
|
||||
}
|
||||
|
||||
// NewFinalBackupFile returns the path to a new final backup file.
|
||||
func (dis Distillery) FinalBackupArchive(prefix string) string {
|
||||
counter := atomic.AddUint64(&globalBackupCounter, 1)
|
||||
|
||||
// generate a new name with the current time, a global counter, and the prefix
|
||||
name := fmt.Sprintf("%s-%d-%d.tar.gz", prefix, time.Now().Unix(), counter)
|
||||
path := filepath.Join(dis.FinalBackupPath(), name)
|
||||
|
||||
return path
|
||||
}
|
||||
|
||||
var globalBackupCounter uint64
|
||||
|
||||
// NewInprogressBackupPath returns the path to a new inprogress backup directory.
|
||||
// The directory is guaranteed to have been freshly created.
|
||||
func (dis Distillery) NewInprogressBackupPath(prefix string) (string, error) {
|
||||
counter := atomic.AddUint64(&globalBackupCounter, 1)
|
||||
|
||||
// generate a new name with the current time, a global counter, and the prefix
|
||||
name := fmt.Sprintf("%s-%d-%d", prefix, time.Now().Unix(), counter)
|
||||
path := filepath.Join(dis.InprogressBackupPath(), name)
|
||||
|
||||
// create the directory
|
||||
if err := os.Mkdir(path, os.ModeDir); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// and it is here!
|
||||
return path, nil
|
||||
}
|
||||
23
env/dirs.go
vendored
23
env/dirs.go
vendored
|
|
@ -1,23 +0,0 @@
|
|||
package env
|
||||
|
||||
import "path/filepath"
|
||||
|
||||
func (dis Distillery) BackupDir() string {
|
||||
return filepath.Join(dis.Config.DeployRoot, "backups")
|
||||
}
|
||||
|
||||
func (dis Distillery) RuntimeDir() string {
|
||||
return filepath.Join(dis.Config.DeployRoot, "runtime")
|
||||
}
|
||||
|
||||
func (dis Distillery) RuntimeUtilsDir() string {
|
||||
return filepath.Join(dis.Config.DeployRoot, "runtime", "utils")
|
||||
}
|
||||
|
||||
func (dis Distillery) InprogressBackupPath() string {
|
||||
return filepath.Join(dis.BackupDir(), "inprogress")
|
||||
}
|
||||
|
||||
func (dis Distillery) FinalBackupPath() string {
|
||||
return filepath.Join(dis.BackupDir(), "final")
|
||||
}
|
||||
5
env/instances.go
vendored
5
env/instances.go
vendored
|
|
@ -30,6 +30,11 @@ var ErrInstanceNotFound = exit.Error{
|
|||
ExitCode: exit.ExitGeneric,
|
||||
}
|
||||
|
||||
var errSQL = exit.Error{
|
||||
Message: "Unknown SQL Error %s",
|
||||
ExitCode: exit.ExitGeneric,
|
||||
}
|
||||
|
||||
// Instance returns the instance of the WissKI Distillery with the provided slug
|
||||
func (dis *Distillery) Instance(slug string) (i Instance, err error) {
|
||||
if err := dis.SQLWaitForConnection(); err != nil {
|
||||
|
|
|
|||
13
env/runtime.go
vendored
Normal file
13
env/runtime.go
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
package env
|
||||
|
||||
import "path/filepath"
|
||||
|
||||
// RuntimeDir returns the path to the runtime directory
|
||||
func (dis Distillery) RuntimeDir() string {
|
||||
return filepath.Join(dis.Config.DeployRoot, "runtime")
|
||||
}
|
||||
|
||||
// RuntimeUtilsDir returns the path to the runtime utility dir
|
||||
func (dis Distillery) RuntimeUtilsDir() string {
|
||||
return filepath.Join(dis.Config.DeployRoot, "runtime", "utils")
|
||||
}
|
||||
2
env/stack.go
vendored
2
env/stack.go
vendored
|
|
@ -6,6 +6,8 @@ import (
|
|||
"github.com/FAU-CDI/wisski-distillery/internal/stack"
|
||||
)
|
||||
|
||||
// TODO: Move everything into specific subpackages
|
||||
|
||||
// Stacks returns the Stacks of this distillery
|
||||
func (dis *Distillery) Stacks() []stack.Installable {
|
||||
// TODO: Do we want to cache these stacks?
|
||||
|
|
|
|||
17
env/stack_sql.go
vendored
17
env/stack_sql.go
vendored
|
|
@ -2,6 +2,7 @@ package env
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"time"
|
||||
|
||||
|
|
@ -76,6 +77,22 @@ func (dis *Distillery) sqlBkTable(silent bool) (*gorm.DB, error) {
|
|||
return table, nil
|
||||
}
|
||||
|
||||
var errSQLBackup = errors.New("SQLBackup: Mysqldump returned non-zero exit code")
|
||||
|
||||
// SQLBackup makes a backup of the sql database into dest.
|
||||
func (dis *Distillery) SQLBackup(io stream.IOStream, dest io.Writer, database string) error {
|
||||
io = stream.NewIOStream(dest, io.Stderr, nil, 0)
|
||||
|
||||
code, err := dis.SQLStack().Exec(io, "sql", "mysqldump", "--database", database)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if code != 0 {
|
||||
return errSQLBackup
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SQLShell executes a mysql shell inside the SQLStack.
|
||||
func (dis *Distillery) SQLShell(io stream.IOStream, argv ...string) (int, error) {
|
||||
return dis.SQLStack().Exec(io, "sql", "mysql", argv...)
|
||||
|
|
|
|||
15
env/stack_triplestore.go
vendored
15
env/stack_triplestore.go
vendored
|
|
@ -200,6 +200,21 @@ func (dis *Distillery) TriplestorePurgeRepo(repo string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
var errTSBackupWrongStatusCode = errors.New("Distillery.Backup: Wrong status code")
|
||||
|
||||
// TriplestoreBackup backs up the repository named repo into the writer dst.
|
||||
func (dis *Distillery) TriplestoreBackup(dst io.Writer, repo string) (int64, error) {
|
||||
res, err := dis.triplestoreRequest("GET", "/repositories/"+repo+"/statements?infer=false", nil, "", "application/n-quads")
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
return 0, errTSBackupWrongStatusCode
|
||||
}
|
||||
defer res.Body.Close()
|
||||
return io.Copy(dst, res.Body)
|
||||
}
|
||||
|
||||
var errTriplestoreFailedSecurity = errors.New("failed to enable triplestore security: request did not succeed with HTTP 200 OK")
|
||||
|
||||
func (dis *Distillery) TriplestoreBootstrap(io stream.IOStream) error {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue