Skip to content

Commit

Permalink
*: support custom content check offline in v2store
Browse files Browse the repository at this point in the history
Part of #18993

Signed-off-by: Wei Fu <[email protected]>
  • Loading branch information
fuweid committed Dec 28, 2024
1 parent 762e938 commit cc7875b
Show file tree
Hide file tree
Showing 3 changed files with 132 additions and 0 deletions.
1 change: 1 addition & 0 deletions etcdutl/ctl.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ func init() {
etcdutl.NewDefragCommand(),
etcdutl.NewSnapshotCommand(),
etcdutl.NewVersionCommand(),
etcdutl.NewCheckCommand(),
)
}

Expand Down
112 changes: 112 additions & 0 deletions etcdutl/etcdutl/check_command.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
// Copyright 2024 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.

package etcdutl

import (
"errors"
"fmt"
"path/filepath"

"github.com/spf13/cobra"

"go.etcd.io/etcd/pkg/v3/cobrautl"
"go.etcd.io/etcd/server/v3/etcdserver/api/membership"
"go.etcd.io/etcd/server/v3/etcdserver/api/snap"
"go.etcd.io/etcd/server/v3/etcdserver/api/v2store"
"go.etcd.io/etcd/server/v3/wal"
)

// NewCheckCommand returns the cobra command for "check".
func NewCheckCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "check <subcommand>",
Short: "commands for checking properties",
}
cmd.AddCommand(NewCheckV2StoreCommand())
return cmd
}

var (
argCheckV2StoreDataDir string
)

// NewCheckV2StoreCommand returns the cobra command for "check v2store".
func NewCheckV2StoreCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "v2store",
Short: "Check custom content in v2store",
Run: checkV2StoreRunFunc,
}
cmd.Flags().StringVar(&argCheckV2StoreDataDir, "data-dir", "", "Required. A data directory not in use by etcd.")
cmd.MarkFlagRequired("data-dir")
return cmd
}

func checkV2StoreRunFunc(_ *cobra.Command, _ []string) {
err := checkV2StoreDataDir(argCheckV2StoreDataDir)
if err != nil {
cobrautl.ExitWithError(cobrautl.ExitError, err)
}
}

func checkV2StoreDataDir(dataDir string) error {
var (
storeClusterPrefix = "/0"
storeKeysPrefix = "/1"

lg = GetLogger()

walDir = filepath.Join(dataDir, "member", "wal")
snapDir = filepath.Join(dataDir, "member", "snap")
)

walSnaps, err := wal.ValidSnapshotEntries(lg, walDir)
if err != nil {
if errors.Is(err, wal.ErrFileNotFound) {
return nil
}
return err
}

ss := snap.New(lg, snapDir)
snapshot, err := ss.LoadNewestAvailable(walSnaps)
if err != nil {
if errors.Is(err, snap.ErrNoSnapshot) {
return nil
}
return err
}
if snapshot == nil {
return nil
}

st := v2store.New(storeClusterPrefix, storeKeysPrefix)

if err := st.Recovery(snapshot.Data); err != nil {
return fmt.Errorf("failed to recover v2store from snapshot: %w", err)
}
return assertNoV2StoreContent(st)
}

func assertNoV2StoreContent(st v2store.Store) error {
metaOnly, err := membership.IsMetaStoreOnly(st)
if err != nil {
return err
}
if metaOnly {
return nil
}
return fmt.Errorf("detected custom content in v2store")
}
19 changes: 19 additions & 0 deletions tests/e2e/v2store_deprecation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,3 +97,22 @@ func TestV2DeprecationWriteOnlyNoV2Api(t *testing.T) {
_, err = proc.Expect("--enable-v2 and --v2-deprecation=write-only are mutually exclusive")
assert.NoError(t, err)
}

func TestV2DeprecationCheckCustomContentOffline(t *testing.T) {
e2e.BeforeTest(t)
dataDirPath := t.TempDir()

createV2store(t, dataDirPath)

assertVerifyCheckCustomContentOffline(t, dataDirPath)
}

func assertVerifyCheckCustomContentOffline(t *testing.T, dataDirPath string) {
t.Logf("Checking custom content in v2store - %s", dataDirPath)

proc, err := e2e.SpawnCmd([]string{e2e.BinDir + "/etcdutl", "check", "v2store", "--data-dir=" + dataDirPath}, nil)
assert.NoError(t, err)

_, err = proc.Expect("detected custom content in v2store")
assert.NoError(t, err)
}

0 comments on commit cc7875b

Please sign in to comment.