mirror of
https://github.com/etcd-io/etcd.git
synced 2024-09-27 06:25:44 +00:00
Merge pull request #13972 from ahrtr/simplify_etcdctl_backup
Simply etcdutl backup command to cleanup v2 related implementation
This commit is contained in:
commit
e74c72ef4f
@ -61,7 +61,7 @@ func NewBackupCommand() *cobra.Command {
|
|||||||
cmd.Flags().StringVar(&walDir, "wal-dir", "", "Path to the etcd wal dir")
|
cmd.Flags().StringVar(&walDir, "wal-dir", "", "Path to the etcd wal dir")
|
||||||
cmd.Flags().StringVar(&backupDir, "backup-dir", "", "Path to the backup dir")
|
cmd.Flags().StringVar(&backupDir, "backup-dir", "", "Path to the backup dir")
|
||||||
cmd.Flags().StringVar(&backupWalDir, "backup-wal-dir", "", "Path to the backup wal dir")
|
cmd.Flags().StringVar(&backupWalDir, "backup-wal-dir", "", "Path to the backup wal dir")
|
||||||
cmd.Flags().BoolVar(&withV3, "with-v3", true, "Backup v3 backend data")
|
cmd.Flags().BoolVar(&withV3, "with-v3", true, "Backup v3 backend data. Note -with-v3=false is not supported since etcd v3.6. Please use v3.5.x client as the last supporting this deprecated functionality.")
|
||||||
cmd.MarkFlagRequired("data-dir")
|
cmd.MarkFlagRequired("data-dir")
|
||||||
cmd.MarkFlagRequired("backup-dir")
|
cmd.MarkFlagRequired("backup-dir")
|
||||||
cmd.MarkFlagDirname("data-dir")
|
cmd.MarkFlagDirname("data-dir")
|
||||||
@ -107,6 +107,11 @@ func newDesiredCluster() desiredCluster {
|
|||||||
func HandleBackup(withV3 bool, srcDir string, destDir string, srcWAL string, destWAL string) error {
|
func HandleBackup(withV3 bool, srcDir string, destDir string, srcWAL string, destWAL string) error {
|
||||||
lg := GetLogger()
|
lg := GetLogger()
|
||||||
|
|
||||||
|
if !withV3 {
|
||||||
|
lg.Warn("-with-v3=false is not supported since etcd v3.6. Please use v3.5.x client as the last supporting this deprecated functionality.")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
srcSnap := datadir.ToSnapDir(srcDir)
|
srcSnap := datadir.ToSnapDir(srcDir)
|
||||||
destSnap := datadir.ToSnapDir(destDir)
|
destSnap := datadir.ToSnapDir(destDir)
|
||||||
|
|
||||||
@ -127,8 +132,8 @@ func HandleBackup(withV3 bool, srcDir string, destDir string, srcWAL string, des
|
|||||||
desired := newDesiredCluster()
|
desired := newDesiredCluster()
|
||||||
|
|
||||||
walsnap := saveSnap(lg, destSnap, srcSnap, &desired)
|
walsnap := saveSnap(lg, destSnap, srcSnap, &desired)
|
||||||
metadata, state, ents := translateWAL(lg, srcWAL, walsnap, withV3)
|
metadata, state, ents := translateWAL(lg, srcWAL, walsnap)
|
||||||
saveDB(lg, destDbPath, srcDbPath, state.Commit, state.Term, &desired, withV3)
|
saveDB(lg, destDbPath, srcDbPath, state.Commit, state.Term, &desired)
|
||||||
|
|
||||||
neww, err := wal.Create(lg, destWAL, pbutil.MustMarshal(&metadata))
|
neww, err := wal.Create(lg, destWAL, pbutil.MustMarshal(&metadata))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -189,7 +194,7 @@ func mustTranslateV2store(lg *zap.Logger, storeData []byte, desired *desiredClus
|
|||||||
return outputData
|
return outputData
|
||||||
}
|
}
|
||||||
|
|
||||||
func translateWAL(lg *zap.Logger, srcWAL string, walsnap walpb.Snapshot, v3 bool) (etcdserverpb.Metadata, raftpb.HardState, []raftpb.Entry) {
|
func translateWAL(lg *zap.Logger, srcWAL string, walsnap walpb.Snapshot) (etcdserverpb.Metadata, raftpb.HardState, []raftpb.Entry) {
|
||||||
w, err := wal.OpenForRead(lg, srcWAL, walsnap)
|
w, err := wal.OpenForRead(lg, srcWAL, walsnap)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
lg.Fatal("wal.OpenForRead failed", zap.Error(err))
|
lg.Fatal("wal.OpenForRead failed", zap.Error(err))
|
||||||
@ -239,22 +244,13 @@ func translateWAL(lg *zap.Logger, srcWAL string, walsnap walpb.Snapshot, v3 bool
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if v2Req != nil {
|
|
||||||
lg.Debug("preserving log entry", zap.Stringer("entry", &ents[i]))
|
|
||||||
}
|
|
||||||
|
|
||||||
if raftReq.ClusterMemberAttrSet != nil {
|
if raftReq.ClusterMemberAttrSet != nil {
|
||||||
lg.Info("ignoring cluster_member_attr_set")
|
lg.Info("ignoring cluster_member_attr_set")
|
||||||
raftEntryToNoOp(&ents[i])
|
raftEntryToNoOp(&ents[i])
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if v3 || raftReq.Header == nil {
|
lg.Debug("preserving log entry", zap.Stringer("entry", &ents[i]))
|
||||||
lg.Debug("preserving log entry", zap.Stringer("entry", &ents[i]))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
lg.Info("ignoring v3 raft entry")
|
|
||||||
raftEntryToNoOp(&ents[i])
|
|
||||||
}
|
}
|
||||||
var metadata etcdserverpb.Metadata
|
var metadata etcdserverpb.Metadata
|
||||||
pbutil.MustUnmarshal(&metadata, wmetadata)
|
pbutil.MustUnmarshal(&metadata, wmetadata)
|
||||||
@ -269,45 +265,43 @@ func raftEntryToNoOp(entry *raftpb.Entry) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// saveDB copies the v3 backend and strips cluster information.
|
// saveDB copies the v3 backend and strips cluster information.
|
||||||
func saveDB(lg *zap.Logger, destDB, srcDB string, idx uint64, term uint64, desired *desiredCluster, v3 bool) {
|
func saveDB(lg *zap.Logger, destDB, srcDB string, idx uint64, term uint64, desired *desiredCluster) {
|
||||||
|
|
||||||
// open src db to safely copy db state
|
// open src db to safely copy db state
|
||||||
if v3 {
|
var src *bolt.DB
|
||||||
var src *bolt.DB
|
ch := make(chan *bolt.DB, 1)
|
||||||
ch := make(chan *bolt.DB, 1)
|
go func() {
|
||||||
go func() {
|
db, err := bolt.Open(srcDB, 0444, &bolt.Options{ReadOnly: true})
|
||||||
db, err := bolt.Open(srcDB, 0444, &bolt.Options{ReadOnly: true})
|
|
||||||
if err != nil {
|
|
||||||
lg.Fatal("bolt.Open FAILED", zap.Error(err))
|
|
||||||
}
|
|
||||||
ch <- db
|
|
||||||
}()
|
|
||||||
select {
|
|
||||||
case src = <-ch:
|
|
||||||
case <-time.After(time.Second):
|
|
||||||
lg.Fatal("timed out waiting to acquire lock on", zap.String("srcDB", srcDB))
|
|
||||||
}
|
|
||||||
defer src.Close()
|
|
||||||
|
|
||||||
tx, err := src.Begin(false)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
lg.Fatal("bbolt.BeginTx failed", zap.Error(err))
|
lg.Fatal("bolt.Open FAILED", zap.Error(err))
|
||||||
}
|
}
|
||||||
|
ch <- db
|
||||||
|
}()
|
||||||
|
select {
|
||||||
|
case src = <-ch:
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
lg.Fatal("timed out waiting to acquire lock on", zap.String("srcDB", srcDB))
|
||||||
|
}
|
||||||
|
defer src.Close()
|
||||||
|
|
||||||
// copy srcDB to destDB
|
tx, err := src.Begin(false)
|
||||||
dest, err := os.Create(destDB)
|
if err != nil {
|
||||||
if err != nil {
|
lg.Fatal("bbolt.BeginTx failed", zap.Error(err))
|
||||||
lg.Fatal("creation of destination file failed", zap.String("dest", destDB), zap.Error(err))
|
|
||||||
}
|
|
||||||
if _, err := tx.WriteTo(dest); err != nil {
|
|
||||||
lg.Fatal("bbolt write to destination file failed", zap.String("dest", destDB), zap.Error(err))
|
|
||||||
}
|
|
||||||
dest.Close()
|
|
||||||
if err := tx.Rollback(); err != nil {
|
|
||||||
lg.Fatal("bbolt tx.Rollback failed", zap.String("dest", destDB), zap.Error(err))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// copy srcDB to destDB
|
||||||
|
dest, err := os.Create(destDB)
|
||||||
|
if err != nil {
|
||||||
|
lg.Fatal("creation of destination file failed", zap.String("dest", destDB), zap.Error(err))
|
||||||
|
}
|
||||||
|
if _, err := tx.WriteTo(dest); err != nil {
|
||||||
|
lg.Fatal("bbolt write to destination file failed", zap.String("dest", destDB), zap.Error(err))
|
||||||
|
}
|
||||||
|
dest.Close()
|
||||||
|
if err := tx.Rollback(); err != nil {
|
||||||
|
lg.Fatal("bbolt tx.Rollback failed", zap.String("dest", destDB), zap.Error(err))
|
||||||
|
}
|
||||||
|
|
||||||
|
// trim membership info
|
||||||
be := backend.NewDefaultBackend(lg, destDB)
|
be := backend.NewDefaultBackend(lg, destDB)
|
||||||
defer be.Close()
|
defer be.Close()
|
||||||
ms := schema.NewMembershipBackend(lg, be)
|
ms := schema.NewMembershipBackend(lg, be)
|
||||||
@ -319,16 +313,4 @@ func saveDB(lg *zap.Logger, destDB, srcDB string, idx uint64, term uint64, desir
|
|||||||
raftCluster.SetID(desired.nodeId, desired.clusterId)
|
raftCluster.SetID(desired.nodeId, desired.clusterId)
|
||||||
raftCluster.SetBackend(ms)
|
raftCluster.SetBackend(ms)
|
||||||
raftCluster.PushMembershipToStorage()
|
raftCluster.PushMembershipToStorage()
|
||||||
|
|
||||||
if !v3 {
|
|
||||||
tx := be.BatchTx()
|
|
||||||
tx.LockOutsideApply()
|
|
||||||
defer tx.Unlock()
|
|
||||||
schema.UnsafeCreateMetaBucket(tx)
|
|
||||||
schema.UnsafeUpdateConsistentIndexForce(tx, idx, term)
|
|
||||||
} else {
|
|
||||||
// Thanks to translateWAL not moving entries, but just replacing them with
|
|
||||||
// 'empty', there is no need to update the consistency index.
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user