wdcli: Implement backup & snapshot
This commit implements command backup and snapshot.
This commit is contained in:
parent
d818cb93a5
commit
fc3b9170a6
11 changed files with 535 additions and 178 deletions
108
cmd/snapshot.go
108
cmd/snapshot.go
|
|
@ -1,9 +1,8 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
wisski_distillery "github.com/FAU-CDI/wisski-distillery"
|
||||
"github.com/FAU-CDI/wisski-distillery/env"
|
||||
|
|
@ -16,7 +15,8 @@ import (
|
|||
var Snapshot wisski_distillery.Command = snapshot{}
|
||||
|
||||
type snapshot struct {
|
||||
Keepalive bool `short:"k" long:"keepalive" description:"Keep instance running while taking a backup. Might lead to inconsistent state"`
|
||||
Keepalive bool `short:"k" long:"keepalive" description:"Keep instance running while taking a backup. Might lead to inconsistent state"`
|
||||
StagingOnly bool `short:"s" long:"staging-only" description:"Do not package into a snapshot archive, but only create a staging directory"`
|
||||
|
||||
Positionals struct {
|
||||
Slug string `positional-arg-name:"SLUG" required:"1-1" description:"slug of instance to take a snapshot of"`
|
||||
|
|
@ -46,65 +46,81 @@ func (bi snapshot) Run(context wisski_distillery.Context) error {
|
|||
return err
|
||||
}
|
||||
|
||||
// TODO: Allow skipping backups of individual parts and make them concurrent!
|
||||
|
||||
// start the snapshot and shutdown the instance (if requested)
|
||||
logging.LogMessage(context.IOStream, "Creating snapshot of instance %s", bi.Positionals.Slug)
|
||||
|
||||
// create a new temporary directory
|
||||
logging.LogMessage(context.IOStream, "Creating new snapshot staging directory")
|
||||
sPath, err := dis.NewSnapshotStagingDir(instance.Slug)
|
||||
if err != nil {
|
||||
return errSnapshotFailed.Wrap(err)
|
||||
// determine the target path for the archive
|
||||
var sPath string
|
||||
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)
|
||||
if err != nil {
|
||||
return errSnapshotFailed.Wrap(err)
|
||||
}
|
||||
defer func() {
|
||||
logging.LogMessage(context.IOStream, "Removing snapshot staging directory")
|
||||
os.RemoveAll(sPath)
|
||||
}()
|
||||
} else {
|
||||
// staging mode: use dest as a destination
|
||||
sPath = bi.Positionals.Dest
|
||||
if sPath == "" {
|
||||
sPath, err = dis.NewSnapshotStagingDir(instance.Slug)
|
||||
if err != nil {
|
||||
return errSnapshotFailed.Wrap(err)
|
||||
}
|
||||
}
|
||||
|
||||
// create the directory (if it doesn't already exist)
|
||||
logging.LogMessage(context.IOStream, "Creating staging directory")
|
||||
err = os.Mkdir(sPath, fs.ModePerm)
|
||||
if !os.IsExist(err) && err != nil {
|
||||
return errSnapshotFailed.WithMessageF(err)
|
||||
}
|
||||
err = nil
|
||||
}
|
||||
defer func() {
|
||||
logging.LogMessage(context.IOStream, "Removing snapshot staging directory")
|
||||
os.RemoveAll(sPath)
|
||||
}()
|
||||
context.Println(sPath)
|
||||
|
||||
// TODO: Allow skipping backups of individual parts and make them concurrent!
|
||||
|
||||
// take a snapshot into the staging area!
|
||||
sreport := instance.Snapshot(context.IOStream, bi.Keepalive, sPath)
|
||||
|
||||
// write out the report!
|
||||
logging.LogOperation(func() error {
|
||||
sreport := instance.Snapshot(context.IOStream, env.SnapshotDescription{
|
||||
Dest: sPath,
|
||||
Keepalive: bi.Keepalive,
|
||||
})
|
||||
|
||||
logging.LogOperation(func() error {
|
||||
reportPath := filepath.Join(sPath, "report.txt")
|
||||
context.Println(reportPath)
|
||||
|
||||
// create the report file!
|
||||
report, err := os.Create(reportPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer report.Close()
|
||||
|
||||
// print the report into it!
|
||||
_, err = fmt.Fprintf(report, "%#v\n", sreport)
|
||||
return err
|
||||
}, context.IOStream, "Writing snapshot report")
|
||||
// write out the report, ignoring any errors!
|
||||
sreport.WriteReport(context.IOStream)
|
||||
|
||||
return nil
|
||||
}, context.IOStream, "Creating snapshot")
|
||||
}, context.IOStream, "Generating Snapshot")
|
||||
|
||||
// copy everything into the final archive
|
||||
|
||||
finalPath := bi.Positionals.Dest
|
||||
if finalPath == "" {
|
||||
finalPath = dis.NewSnapshotArchivePath(instance.Slug)
|
||||
// if we requested to only have a staging area, then we are done
|
||||
if bi.StagingOnly {
|
||||
context.Printf("Wrote %s\n", sPath)
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := logging.LogOperation(func() error {
|
||||
context.IOStream.Println(finalPath)
|
||||
// create the archive path
|
||||
archivePath := bi.Positionals.Dest
|
||||
if archivePath == "" {
|
||||
archivePath = dis.NewSnapshotArchivePath(instance.Slug)
|
||||
}
|
||||
|
||||
targz.Package(finalPath, sPath, func(src string) {
|
||||
context.Println(src)
|
||||
// and write everything into it!
|
||||
// TODO: Should we move the open call to here?
|
||||
var count int64
|
||||
if err := logging.LogOperation(func() error {
|
||||
context.IOStream.Println(archivePath)
|
||||
|
||||
count, err = targz.Package(archivePath, sPath, func(dst, src string) {
|
||||
context.Println(dst)
|
||||
})
|
||||
return err
|
||||
}, context.IOStream, "Writing final backup"); err != nil {
|
||||
}, context.IOStream, "Writing snapshot archive"); err != nil {
|
||||
return errSnapshotFailed.Wrap(err)
|
||||
}
|
||||
context.Printf("Wrote %s\n", finalPath)
|
||||
|
||||
context.Printf("Wrote %d byte(s) to %s\n", count, archivePath)
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue