-
Notifications
You must be signed in to change notification settings - Fork 228
USHIFT-1083 microshift admin data backup command
#1819
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
openshift-merge-robot
merged 27 commits into
openshift:main
from
pmtk:upgrade-ostree-backup-new
Jun 1, 2023
Merged
Changes from all commits
Commits
Show all changes
27 commits
Select commit
Hold shift + click to select a range
1fd95f7
microshift admin backup
pmtk c505f6b
configurable backup dest dir
pmtk da262e5
use config var for default value
pmtk 3332008
more logs and logic for backup
pmtk 3fa1bd7
ensure microshift is not running
pmtk c69fe38
move backup under data subcommand
pmtk f3cd8ca
DataManager interface
pmtk 52fe5d3
check if svc is inactive instead of `ps aux`
pmtk 59b7c7b
fix ireturn
pmtk 8548161
rename `--dest` and make sure args are not empty
pmtk 6fa81a2
rename DataManager to Manager
pmtk d8a68cb
catch empty args early
pmtk 8d86dc3
log dir creation
pmtk 35a428a
move logic around...
pmtk 3d45018
rename microshiftShouldNotRun
pmtk b566524
rename existing backup instead of deleting it before having new one i…
pmtk 58f172b
move BackupCfg validation to separate func
pmtk 28fb007
tweak logs
pmtk 41d41d2
tweak logic re errs in BackupConfig.Validate()
pmtk e90d88a
change backup unit of work start log
pmtk aced3e6
move microshift running check
pmtk 25dd11b
--force to overwrite backup via cli
pmtk 4bb597f
rename manager.go for better logs
pmtk b5d84fe
interface impl assertion and better 'Restore not impl' log
pmtk aeb0b2e
fix linter
pmtk 5816743
separate std out and err
pmtk a6e672c
simplify by requiring non-existing backup name
pmtk File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,6 @@ | ||
| module github.com/openshift/microshift | ||
|
|
||
| go 1.19 | ||
| go 1.20 | ||
|
|
||
| require ( | ||
| github.com/apparentlymart/go-cidr v1.1.0 | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,105 @@ | ||
| package data | ||
|
|
||
| import ( | ||
| "bytes" | ||
| "fmt" | ||
| "os/exec" | ||
| "path/filepath" | ||
| "strings" | ||
|
|
||
| "github.com/openshift/microshift/pkg/config" | ||
| "github.com/openshift/microshift/pkg/util" | ||
| "k8s.io/klog/v2" | ||
| ) | ||
|
|
||
| var ( | ||
| cpArgs = []string{ | ||
| "--verbose", | ||
| "--recursive", | ||
| "--preserve", | ||
| "--reflink=auto", | ||
| } | ||
| ) | ||
|
|
||
| func NewManager(storage StoragePath) (*manager, error) { | ||
| if storage == "" { | ||
| return nil, &EmptyArgErr{argName: "storage"} | ||
| } | ||
| return &manager{storage: storage}, nil | ||
| } | ||
|
|
||
| var _ Manager = (*manager)(nil) | ||
|
|
||
| type manager struct { | ||
| storage StoragePath | ||
| } | ||
|
|
||
| func (dm *manager) GetBackupPath(name BackupName) string { | ||
| return filepath.Join(string(dm.storage), string(name)) | ||
| } | ||
|
|
||
| func (dm *manager) BackupExists(name BackupName) (bool, error) { | ||
| return pathExists(dm.GetBackupPath(name)) | ||
| } | ||
|
|
||
| func (dm *manager) Backup(name BackupName) error { | ||
| klog.InfoS("Backing up the data", | ||
| "storage", dm.storage, "name", name, "data", config.DataDir) | ||
|
|
||
| if name == "" { | ||
| return &EmptyArgErr{"name"} | ||
| } | ||
|
|
||
| if found, err := pathExists(string(dm.storage)); err != nil { | ||
| return err | ||
| } else if !found { | ||
| if makeDirErr := util.MakeDir(string(dm.storage)); makeDirErr != nil { | ||
| return fmt.Errorf("making %s directory failed: %w", dm.storage, makeDirErr) | ||
| } | ||
| klog.InfoS("Backup storage directory created", "path", dm.storage) | ||
| } else { | ||
| klog.InfoS("Backup storage directory already existed", "path", dm.storage) | ||
| } | ||
|
|
||
| dest := dm.GetBackupPath(name) | ||
|
|
||
| if err := copyDataDir(dest); err != nil { | ||
| return err | ||
| } | ||
|
|
||
| klog.InfoS("Backup finished", "backup", dest, "data", config.DataDir) | ||
| return nil | ||
| } | ||
|
|
||
| func (dm *manager) Restore(n BackupName) error { | ||
| return fmt.Errorf("Restore not implemented") | ||
| } | ||
|
|
||
| func copyDataDir(dest string) error { | ||
| cmd := exec.Command("cp", append(cpArgs, config.DataDir, dest)...) //nolint:gosec | ||
| klog.InfoS("Executing command", "cmd", cmd) | ||
|
|
||
| var outb, errb bytes.Buffer | ||
| cmd.Stdout = &outb | ||
| cmd.Stderr = &errb | ||
| err := cmd.Run() | ||
|
|
||
| klog.InfoS("Command finished running", "cmd", cmd, | ||
| "stdout", strings.ReplaceAll(outb.String(), "\n", `, `), | ||
| "stderr", errb.String()) | ||
|
|
||
| if err != nil { | ||
| return fmt.Errorf("command %s failed: %w", cmd, err) | ||
| } | ||
|
|
||
| klog.InfoS("Command successful", "cmd", cmd) | ||
| return nil | ||
| } | ||
|
|
||
| func pathExists(path string) (bool, error) { | ||
| exists, err := util.PathExists(path) | ||
| if err != nil { | ||
| return false, fmt.Errorf("checking if %s exists failed: %w", path, err) | ||
| } | ||
| return exists, nil | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| package data | ||
|
|
||
| import ( | ||
| "fmt" | ||
| "os/exec" | ||
| "strings" | ||
|
|
||
| "k8s.io/klog/v2" | ||
| ) | ||
|
|
||
| const ( | ||
| expectedState = "inactive" | ||
| ) | ||
|
|
||
| var ( | ||
| services = []string{"microshift.service", "microshift-etcd.scope"} | ||
| ) | ||
|
|
||
| func MicroShiftIsNotRunning() error { | ||
| for _, service := range services { | ||
| cmd := exec.Command("systemctl", "show", "-p", "ActiveState", "--value", service) | ||
| out, err := cmd.CombinedOutput() | ||
| state := strings.TrimSpace(string(out)) | ||
| if err != nil { | ||
| return fmt.Errorf("error when checking if %s is active: %w", service, err) | ||
| } | ||
|
|
||
| klog.InfoS("Service state", "service", service, "state", state) | ||
|
|
||
| if state != expectedState { | ||
| return fmt.Errorf("service %s is %s - expected to be %s", service, state, expectedState) | ||
| } | ||
| } | ||
|
|
||
| return nil | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| package data | ||
|
|
||
| import ( | ||
| "fmt" | ||
| ) | ||
|
|
||
| type EmptyArgErr struct { | ||
| argName string | ||
| } | ||
|
|
||
| func (e *EmptyArgErr) Error() string { | ||
| return fmt.Sprintf("empty argument: %s", e.argName) | ||
| } | ||
|
|
||
| type StoragePath string | ||
| type BackupName string | ||
|
|
||
| type Manager interface { | ||
| Backup(BackupName) error | ||
| Restore(BackupName) error | ||
|
|
||
| BackupExists(BackupName) (bool, error) | ||
| GetBackupPath(BackupName) string | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,75 @@ | ||
| package cmd | ||
|
|
||
| import ( | ||
| "fmt" | ||
| "time" | ||
|
|
||
| "github.com/openshift/microshift/pkg/admin/data" | ||
| "github.com/openshift/microshift/pkg/config" | ||
| "github.com/openshift/microshift/pkg/version" | ||
|
|
||
| "github.com/spf13/cobra" | ||
| ) | ||
|
|
||
| func backup(cmd *cobra.Command, args []string) error { | ||
| storage := data.StoragePath(cmd.Flag("storage").Value.String()) | ||
| name := data.BackupName(cmd.Flag("name").Value.String()) | ||
|
|
||
| dataManager, err := data.NewManager(storage) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| if exists, err := dataManager.BackupExists(name); err != nil { | ||
| return err | ||
| } else if exists { | ||
| return fmt.Errorf("backup %s already exists", dataManager.GetBackupPath(name)) | ||
| } | ||
|
|
||
| return dataManager.Backup(name) | ||
| } | ||
|
|
||
| func newAdminDataCommand() *cobra.Command { | ||
| backup := &cobra.Command{ | ||
| Use: "backup", | ||
| Short: "Backup MicroShift data", | ||
| RunE: backup, | ||
| } | ||
|
|
||
| data := &cobra.Command{ | ||
| Use: "data", | ||
| Short: "Commands for managing MicroShift data", | ||
| PersistentPreRunE: func(cmd *cobra.Command, args []string) error { | ||
| if cmd.Flag("storage").Value.String() == "" { | ||
| return fmt.Errorf("--storage must not be empty") | ||
| } | ||
|
|
||
| if cmd.Flag("name").Value.String() == "" { | ||
| return fmt.Errorf("--name must not be empty") | ||
| } | ||
|
|
||
| if err := data.MicroShiftIsNotRunning(); err != nil { | ||
| return fmt.Errorf("microshift must not be running: %w", err) | ||
| } | ||
|
|
||
| return nil | ||
| }, | ||
| } | ||
| v := version.Get() | ||
| data.PersistentFlags().String("storage", config.BackupsDir, "Directory with backups") | ||
| data.PersistentFlags().String("name", | ||
| fmt.Sprintf("%s.%s__%s", v.Major, v.Minor, time.Now().UTC().Format("20060102_150405")), | ||
| "Backup name") | ||
|
|
||
| data.AddCommand(backup) | ||
| return data | ||
| } | ||
|
|
||
| func NewAdminCommand() *cobra.Command { | ||
| cmd := &cobra.Command{ | ||
| Use: "admin", | ||
| Short: "Commands for managing MicroShift", | ||
| } | ||
| cmd.AddCommand(newAdminDataCommand()) | ||
| return cmd | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This indicates an attempt to write over an existing backup, right? I would expect that to be an error.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not really, that's the "parent directory" where backups are stored. Maybe you have how can we name it better ("backup storage") or maybe just simply delete this log (and keep only one about creating /var/lib/microshift-backups/)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I see what's going on now.