From f58920baf490c7f046abbff14654395f566e8c99 Mon Sep 17 00:00:00 2001 From: Tom Wiesing Date: Sat, 1 Oct 2022 19:39:41 +0200 Subject: [PATCH] component/snapshots: Create new component This commit creates a new 'snapshots' component that is intended to manage snapshots and backups. --- cmd/backup.go | 6 +- cmd/snapshot.go | 6 +- cmd/system_update.go | 4 +- internal/component/snapshots/snapshots.go | 72 +++++++++++++++++++++++ internal/wisski/backup_prune.go | 2 +- internal/wisski/component.go | 8 +++ internal/wisski/snapshot.go | 54 ----------------- 7 files changed, 89 insertions(+), 63 deletions(-) create mode 100644 internal/component/snapshots/snapshots.go diff --git a/cmd/backup.go b/cmd/backup.go index ab44db4..ce2e600 100644 --- a/cmd/backup.go +++ b/cmd/backup.go @@ -53,7 +53,7 @@ func (bk backupC) Run(context wisski_distillery.Context) error { if !bk.StagingOnly { // regular mode: create a temporary staging directory logging.LogMessage(context.IOStream, "Creating new snapshot staging directory") - sPath, err = dis.NewSnapshotStagingDir("") + sPath, err = dis.Snapshots().NewStagingDir("") if err != nil { return errSnapshotFailed.Wrap(err) } @@ -65,7 +65,7 @@ func (bk backupC) Run(context wisski_distillery.Context) error { // staging mode: use dest as a destination sPath = bk.Positionals.Dest if sPath == "" { - sPath, err = dis.NewSnapshotStagingDir("") + sPath, err = dis.Snapshots().NewStagingDir("") if err != nil { return errSnapshotFailed.Wrap(err) } @@ -100,7 +100,7 @@ func (bk backupC) Run(context wisski_distillery.Context) error { // create the archive path archivePath := bk.Positionals.Dest if archivePath == "" { - archivePath = dis.NewSnapshotArchivePath("") + archivePath = dis.Snapshots().NewArchivePath("") } // and write everything into it! diff --git a/cmd/snapshot.go b/cmd/snapshot.go index 2832c38..dce8816 100644 --- a/cmd/snapshot.go +++ b/cmd/snapshot.go @@ -55,7 +55,7 @@ func (bi snapshot) Run(context wisski_distillery.Context) error { if !bi.StagingOnly { // regular mode: create a temporary staging directory logging.LogMessage(context.IOStream, "Creating new snapshot staging directory") - sPath, err = dis.NewSnapshotStagingDir(instance.Slug) + sPath, err = dis.Snapshots().NewStagingDir(instance.Slug) if err != nil { return errSnapshotFailed.Wrap(err) } @@ -67,7 +67,7 @@ func (bi snapshot) Run(context wisski_distillery.Context) error { // staging mode: use dest as a destination sPath = bi.Positionals.Dest if sPath == "" { - sPath, err = dis.NewSnapshotStagingDir(instance.Slug) + sPath, err = dis.Snapshots().NewStagingDir(instance.Slug) if err != nil { return errSnapshotFailed.Wrap(err) } @@ -107,7 +107,7 @@ func (bi snapshot) Run(context wisski_distillery.Context) error { // create the archive path archivePath := bi.Positionals.Dest if archivePath == "" { - archivePath = dis.NewSnapshotArchivePath(instance.Slug) + archivePath = dis.Snapshots().NewArchivePath(instance.Slug) } // and write everything into it! diff --git a/cmd/system_update.go b/cmd/system_update.go index c0dce85..0b8ffbe 100644 --- a/cmd/system_update.go +++ b/cmd/system_update.go @@ -70,8 +70,8 @@ func (si systemupdate) Run(context wisski_distillery.Context) error { for _, d := range []string{ dis.Config.DeployRoot, dis.Instances().Path(), - dis.SnapshotsStagingPath(), - dis.SnapshotsArchivePath(), + dis.Snapshots().StagingPath(), + dis.Snapshots().ArchivePath(), } { context.Println(d) if err := dis.Core.Environment.MkdirAll(d, environment.DefaultDirPerm); err != nil { diff --git a/internal/component/snapshots/snapshots.go b/internal/component/snapshots/snapshots.go new file mode 100644 index 0000000..7107b66 --- /dev/null +++ b/internal/component/snapshots/snapshots.go @@ -0,0 +1,72 @@ +package snapshots + +import ( + "fmt" + "path/filepath" + "time" + + "github.com/FAU-CDI/wisski-distillery/internal/component" + "github.com/FAU-CDI/wisski-distillery/pkg/environment" + "github.com/FAU-CDI/wisski-distillery/pkg/fsx" + "github.com/FAU-CDI/wisski-distillery/pkg/password" +) + +// Snapshots manages snapshots and backups +type Snapshots struct { + component.ComponentBase +} + +func (Snapshots) Name() string { return "snapshots" } + +// Path returns the path that contains all snapshot related data. +func (dis *Snapshots) Path() string { + return filepath.Join(dis.Config.DeployRoot, "snapshots") +} + +// StagingPath returns the path to the directory containing a temporary staging area for snapshots. +// Use NewSnapshotStagingDir to generate a new staging area. +func (dis *Snapshots) StagingPath() string { + return filepath.Join(dis.Path(), "staging") +} + +// ArchivePath returns the path to the directory containing all exported archives. +// Use NewSnapshotArchivePath to generate a path to a new archive in this directory. +func (dis *Snapshots) ArchivePath() string { + return filepath.Join(dis.Path(), "archives") +} + +// NewArchivePath returns the path to a new archive with the provided prefix. +// The path is guaranteed to not exist. +func (dis *Snapshots) NewArchivePath(prefix string) (path string) { + // TODO: Consider moving these into a subdirectory with the provided prefix. + for path == "" || fsx.Exists(dis.Environment, path) { + name := dis.newSnapshotName(prefix) + ".tar.gz" + path = filepath.Join(dis.ArchivePath(), name) + } + return +} + +// newSnapshot name returns a new basename for a snapshot with the provided prefix. +// The name is guaranteed to be unique within this process. +func (*Snapshots) newSnapshotName(prefix string) string { + suffix, _ := password.Password(64) // silently ignore any errors! + if prefix == "" { + prefix = "backup" + } else { + prefix = "snapshot-" + prefix + } + return fmt.Sprintf("%s-%d-%s", prefix, time.Now().Unix(), suffix) +} + +// NewStagingDir returns the path to a new snapshot directory. +// The directory is guaranteed to have been freshly created. +func (dis *Snapshots) NewStagingDir(prefix string) (path string, err error) { + for path == "" || environment.IsExist(err) { + path = filepath.Join(dis.StagingPath(), dis.newSnapshotName(prefix)) + err = dis.Core.Environment.Mkdir(path, environment.DefaultFilePerm) + } + if err != nil { + path = "" + } + return +} diff --git a/internal/wisski/backup_prune.go b/internal/wisski/backup_prune.go index 3efd5aa..2cfc2a1 100644 --- a/internal/wisski/backup_prune.go +++ b/internal/wisski/backup_prune.go @@ -14,7 +14,7 @@ func (dis *Distillery) ShouldPrune(modtime time.Time) bool { // PruneBackups prunes all backups older than the maximum backup age func (dis *Distillery) PruneBackups(io stream.IOStream) error { - sPath := dis.SnapshotsArchivePath() + sPath := dis.Snapshots().ArchivePath() // list all the files entries, err := dis.Core.Environment.ReadDir(sPath) diff --git a/internal/wisski/component.go b/internal/wisski/component.go index 22ef65d..4368027 100644 --- a/internal/wisski/component.go +++ b/internal/wisski/component.go @@ -6,6 +6,7 @@ import ( "github.com/FAU-CDI/wisski-distillery/internal/component" "github.com/FAU-CDI/wisski-distillery/internal/component/control" "github.com/FAU-CDI/wisski-distillery/internal/component/instances" + "github.com/FAU-CDI/wisski-distillery/internal/component/snapshots" "github.com/FAU-CDI/wisski-distillery/internal/component/sql" "github.com/FAU-CDI/wisski-distillery/internal/component/ssh" "github.com/FAU-CDI/wisski-distillery/internal/component/triplestore" @@ -29,6 +30,7 @@ type components struct { // other components instances lazy.Lazy[*instances.Instances] + snapshots lazy.Lazy[*snapshots.Snapshots] } // @@ -73,6 +75,12 @@ func (dis *Distillery) Instances() *instances.Instances { }) } +func (dis *Distillery) Snapshots() *snapshots.Snapshots { + return component.Initialize(dis.Core, &dis.components.snapshots, func(snapshots *snapshots.Snapshots) { + + }) +} + // // ALL COMPONENTS // diff --git a/internal/wisski/snapshot.go b/internal/wisski/snapshot.go index c6eab45..3cb9222 100644 --- a/internal/wisski/snapshot.go +++ b/internal/wisski/snapshot.go @@ -15,65 +15,11 @@ import ( "github.com/FAU-CDI/wisski-distillery/pkg/fsx" "github.com/FAU-CDI/wisski-distillery/pkg/logging" "github.com/FAU-CDI/wisski-distillery/pkg/opgroup" - "github.com/FAU-CDI/wisski-distillery/pkg/password" "github.com/tkw1536/goprogram/status" "github.com/tkw1536/goprogram/stream" "golang.org/x/exp/slices" ) -// SnapshotsDir returns the path that contains all snapshot related data. -func (dis *Distillery) SnapshotsDir() string { - return filepath.Join(dis.Config.DeployRoot, "snapshots") -} - -// SnapshotsStagingPath returns the path to the directory containing a temporary staging area for snapshots. -// Use NewSnapshotStagingDir to generate a new staging area. -func (dis *Distillery) SnapshotsStagingPath() string { - return filepath.Join(dis.SnapshotsDir(), "staging") -} - -// SnapshotsArchivePath returns the path to the directory containing all exported archives. -// Use NewSnapshotArchivePath to generate a path to a new archive in this directory. -func (dis *Distillery) SnapshotsArchivePath() string { - return filepath.Join(dis.SnapshotsDir(), "archives") -} - -// NewSnapshotArchivePath returns the path to a new archive with the provided prefix. -// The path is guaranteed to not exist. -func (dis *Distillery) NewSnapshotArchivePath(prefix string) (path string) { - // TODO: Consider moving these into a subdirectory with the provided prefix. - for path == "" || fsx.Exists(dis.Environment, path) { - name := dis.newSnapshotName(prefix) + ".tar.gz" - path = filepath.Join(dis.SnapshotsArchivePath(), name) - } - return -} - -// newSnapshot name returns a new basename for a snapshot with the provided prefix. -// The name is guaranteed to be unique within this process. -func (*Distillery) newSnapshotName(prefix string) string { - suffix, _ := password.Password(64) // silently ignore any errors! - if prefix == "" { - prefix = "backup" - } else { - prefix = "snapshot-" + prefix - } - return fmt.Sprintf("%s-%d-%s", prefix, time.Now().Unix(), suffix) -} - -// NewSnapshotStagingDir returns the path to a new snapshot directory. -// The directory is guaranteed to have been freshly created. -func (dis *Distillery) NewSnapshotStagingDir(prefix string) (path string, err error) { - for path == "" || environment.IsExist(err) { - path = filepath.Join(dis.SnapshotsStagingPath(), dis.newSnapshotName(prefix)) - err = dis.Core.Environment.Mkdir(path, environment.DefaultFilePerm) - } - if err != nil { - path = "" - } - return -} - // SnapshotDescription is a description for a snapshot type SnapshotDescription struct { Dest string // destination path