etcd/etcdctl/ctlv2/command/backup_command.go

119 lines
3.3 KiB
Go
Raw Normal View History

2016-05-13 06:51:39 +03:00
// Copyright 2015 The etcd Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
2014-11-07 23:53:32 +03:00
package command
import (
"fmt"
2014-11-07 23:53:32 +03:00
"log"
"path"
"time"
"github.com/coreos/etcd/etcdserver/etcdserverpb"
2016-06-23 01:01:27 +03:00
"github.com/coreos/etcd/pkg/fileutil"
"github.com/coreos/etcd/pkg/idutil"
2014-11-07 23:53:32 +03:00
"github.com/coreos/etcd/pkg/pbutil"
"github.com/coreos/etcd/snap"
"github.com/coreos/etcd/wal"
2015-01-06 10:27:03 +03:00
"github.com/coreos/etcd/wal/walpb"
2016-06-21 01:06:52 +03:00
"github.com/urfave/cli"
2014-11-07 23:53:32 +03:00
)
func NewBackupCommand() cli.Command {
return cli.Command{
Name: "backup",
Usage: "backup an etcd directory",
ArgsUsage: " ",
2014-11-07 23:53:32 +03:00
Flags: []cli.Flag{
cli.StringFlag{Name: "data-dir", Value: "", Usage: "Path to the etcd data dir"},
cli.StringFlag{Name: "wal-dir", Value: "", Usage: "Path to the etcd wal dir"},
2014-11-07 23:53:32 +03:00
cli.StringFlag{Name: "backup-dir", Value: "", Usage: "Path to the backup dir"},
cli.StringFlag{Name: "backup-wal-dir", Value: "", Usage: "Path to the backup wal dir"},
2014-11-07 23:53:32 +03:00
},
Action: handleBackup,
}
}
// handleBackup handles a request that intends to do a backup.
func handleBackup(c *cli.Context) error {
var srcWAL string
var destWAL string
srcSnap := path.Join(c.String("data-dir"), "member", "snap")
destSnap := path.Join(c.String("backup-dir"), "member", "snap")
if c.String("wal-dir") != "" {
srcWAL = c.String("wal-dir")
} else {
srcWAL = path.Join(c.String("data-dir"), "member", "wal")
}
if c.String("backup-wal-dir") != "" {
destWAL = c.String("backup-wal-dir")
} else {
destWAL = path.Join(c.String("backup-dir"), "member", "wal")
}
2014-11-07 23:53:32 +03:00
2016-06-23 01:01:27 +03:00
if err := fileutil.CreateDirAll(destSnap); err != nil {
log.Fatalf("failed creating backup snapshot dir %v: %v", destSnap, err)
}
2014-11-07 23:53:32 +03:00
ss := snap.New(srcSnap)
snapshot, err := ss.Load()
if err != nil && err != snap.ErrNoSnapshot {
log.Fatal(err)
}
2015-01-06 10:27:03 +03:00
var walsnap walpb.Snapshot
2014-11-07 23:53:32 +03:00
if snapshot != nil {
2015-01-06 10:27:03 +03:00
walsnap.Index, walsnap.Term = snapshot.Metadata.Index, snapshot.Metadata.Term
2014-11-07 23:53:32 +03:00
newss := snap.New(destSnap)
if err = newss.SaveSnap(*snapshot); err != nil {
log.Fatal(err)
}
2014-11-07 23:53:32 +03:00
}
w, err := wal.OpenForRead(srcWAL, walsnap)
2014-11-07 23:53:32 +03:00
if err != nil {
log.Fatal(err)
}
defer w.Close()
wmetadata, state, ents, err := w.ReadAll()
switch err {
case nil:
case wal.ErrSnapshotNotFound:
fmt.Printf("Failed to find the match snapshot record %+v in wal %v.", walsnap, srcWAL)
fmt.Printf("etcdctl will add it back. Start auto fixing...")
default:
2014-11-07 23:53:32 +03:00
log.Fatal(err)
}
var metadata etcdserverpb.Metadata
pbutil.MustUnmarshal(&metadata, wmetadata)
2014-12-16 03:07:47 +03:00
idgen := idutil.NewGenerator(0, time.Now())
metadata.NodeID = idgen.Next()
metadata.ClusterID = idgen.Next()
2014-11-07 23:53:32 +03:00
neww, err := wal.Create(destWAL, pbutil.MustMarshal(&metadata))
if err != nil {
log.Fatal(err)
}
defer neww.Close()
if err := neww.Save(state, ents); err != nil {
log.Fatal(err)
}
if err := neww.SaveSnapshot(walsnap); err != nil {
log.Fatal(err)
}
return nil
2014-11-07 23:53:32 +03:00
}