Created
September 4, 2019 18:20
-
-
Save alaypatel07/94bd7f1da85c1db17a9e684384de1882 to your computer and use it in GitHub Desktop.
remove member from data directory
This file contains 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
package main | |
import ( | |
"encoding/binary" | |
"flag" | |
"fmt" | |
"log" | |
"os" | |
"path/filepath" | |
"strings" | |
"time" | |
bolt "go.etcd.io/bbolt" | |
"go.etcd.io/etcd/mvcc/mvccpb" | |
) | |
func snapDir(dataDir string) string { | |
return filepath.Join(dataDir, "member", "snap") | |
} | |
func existFileOrDir(name string) bool { | |
_, err := os.Stat(name) | |
return err == nil | |
} | |
type decoder func(k, v []byte) | |
var decoders = map[string]decoder{ | |
"key": keyDecoder, | |
} | |
type revision struct { | |
main int64 | |
sub int64 | |
} | |
func bytesToRev(bytes []byte) revision { | |
return revision{ | |
main: int64(binary.BigEndian.Uint64(bytes[0:8])), | |
sub: int64(binary.BigEndian.Uint64(bytes[9:])), | |
} | |
} | |
func keyDecoder(k, v []byte) { | |
rev := bytesToRev(k) | |
var kv mvccpb.KeyValue | |
if err := kv.Unmarshal(v); err != nil { | |
panic(err) | |
} | |
fmt.Printf("rev=%+v, value=[key %q | val %q | created %d | mod %d | ver %d]\n", rev, string(kv.Key), string(kv.Value), kv.CreateRevision, kv.ModRevision, kv.Version) | |
} | |
func iterateBucket(dbPath, bucket string, limit uint64, decode bool) (err error) { | |
db, err := bolt.Open(dbPath, 0600, &bolt.Options{Timeout: 10 * time.Second}) | |
if err != nil { | |
return fmt.Errorf("failed to open bolt DB %v", err) | |
} | |
defer db.Close() | |
err = db.View(func(tx *bolt.Tx) error { | |
b := tx.Bucket([]byte(bucket)) | |
if b == nil { | |
return fmt.Errorf("got nil bucket for %s", bucket) | |
} | |
c := b.Cursor() | |
// iterate in reverse order (use First() and Next() for ascending order) | |
for k, v := c.Last(); k != nil; k, v = c.Prev() { | |
// TODO: remove sensitive information | |
// (https://github.com/etcd-io/etcd/issues/7620) | |
if dec, ok := decoders[bucket]; decode && ok { | |
dec(k, v) | |
} else { | |
fmt.Printf("key=%q, value=%q\n", k, v) | |
} | |
limit-- | |
if limit == 0 { | |
break | |
} | |
} | |
return nil | |
}) | |
return err | |
} | |
// Find returns the smallest index i at which x == a[i], | |
// or len(a) if there is no such index. | |
func Find(a []string, x string) int { | |
fmt.Println(x) | |
for i, n := range a { | |
if x == n { | |
return i | |
} | |
} | |
return len(a) | |
} | |
func removeIDs(dbPath, bucket string, ids []string) error { | |
db, err := bolt.Open(dbPath, 0600, &bolt.Options{Timeout: 10 * time.Second}) | |
if err != nil { | |
return fmt.Errorf("failed to open bolt DB %v", err) | |
} | |
defer db.Close() | |
if bucket != "members" { | |
return fmt.Errorf("can not remove member if this is not a member bucket") | |
} | |
tx, err := db.Begin(true) | |
if err != nil { | |
log.Printf("unable to open a writable transaction %v", err) | |
} | |
c := tx.Bucket([]byte(bucket)).Cursor() | |
defer tx.Commit() | |
// iterate in reverse order (use First() and Next() for ascending order) | |
for k, v := c.First(); k != nil; k, v = c.Next() { | |
// TODO: remove sensitive information | |
// (https://github.com/etcd-io/etcd/issues/7620) | |
index := Find(ids, string(k)) | |
fmt.Printf("Index %v\n", index) | |
if index >= len(ids) { | |
fmt.Printf("ignoring key %q: not to be deleted\n", k) | |
} | |
if index < len(ids) { | |
fmt.Printf("deleteing key %v with value %v\n", k, v) | |
if err := c.Delete(); err != nil { | |
log.Printf("unable to delete %v: %v", k, err) | |
} | |
} | |
} | |
return err | |
} | |
var dataDir string | |
var remove_ids string | |
func main() { | |
flag.StringVar(&dataDir, "data-dir", "/var/etcd/data", "Enter the filepath to etcd data directory") | |
flag.StringVar(&remove_ids, "remove-ids", "", "[OPTIONAL] Enter the ids to be removed separated by ','") | |
flag.Parse() | |
if !strings.HasSuffix(dataDir, "db") { | |
dataDir = filepath.Join(snapDir(dataDir), "db") | |
} | |
if !existFileOrDir(dataDir) { | |
log.Fatalf("%q does not exist", dataDir) | |
} | |
err := iterateBucket(dataDir, "members", 0, true) | |
if err != nil { | |
log.Fatal(err) | |
} | |
err = iterateBucket(dataDir, "members_removed", 0, true) | |
if err != nil { | |
log.Fatal(err) | |
} | |
err = iterateBucket(dataDir, "cluster", 0, true) | |
if err != nil { | |
log.Fatal(err) | |
} | |
if remove_ids != "" { | |
ids := strings.Split(remove_ids, ",") | |
fmt.Printf("ids to be removed %v\n", ids) | |
err := removeIDs(dataDir, "members", ids) | |
if err != nil { | |
log.Println(err) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment