Skip to content

Commit

Permalink
Merge pull request #11697 from hashicorp/f-raft-state-err
Browse files Browse the repository at this point in the history
cli: return error from raft commands if db is open
  • Loading branch information
schmichael authored Dec 16, 2021
2 parents 55018bd + fa3de73 commit 3ca534a
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 1 deletion.
20 changes: 19 additions & 1 deletion helper/raftutil/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,38 @@ package raftutil

import (
"bytes"
"errors"
"fmt"
"os"
"path/filepath"
"strings"
"time"

"github.com/boltdb/bolt"
"github.com/hashicorp/go-msgpack/codec"
"github.com/hashicorp/nomad/nomad/structs"
"github.com/hashicorp/raft"
raftboltdb "github.com/hashicorp/raft-boltdb"
)

var (
errAlreadyOpen = errors.New("unable to open raft logs that are in use")
)

// RaftStateInfo returns info about the nomad state, as found in the passed data-dir directory
func RaftStateInfo(p string) (store *raftboltdb.BoltStore, firstIdx uint64, lastIdx uint64, err error) {
s, err := raftboltdb.NewBoltStore(p)
opts := raftboltdb.Options{
Path: p,
BoltOptions: &bolt.Options{
ReadOnly: true,
Timeout: 1 * time.Second,
},
}
s, err := raftboltdb.New(opts)
if err != nil {
if strings.HasSuffix(err.Error(), "timeout") {
return nil, 0, 0, errAlreadyOpen
}
return nil, 0, 0, fmt.Errorf("failed to open raft logs: %v", err)
}

Expand Down
52 changes: 52 additions & 0 deletions helper/raftutil/state_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package raftutil

import (
"path/filepath"
"testing"

raftboltdb "github.com/hashicorp/raft-boltdb"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

// TestRaftStateInfo_InUse asserts that commands that inspect raft
// state such as "nomad operator raft info" and "nomad operator raft
// logs" fail with a helpful error message when called on an inuse
// database.
func TestRaftStateInfo_InUse(t *testing.T) {
t.Parallel() // since there's a 1s timeout.

// First create an empty raft db
dir := filepath.Join(t.TempDir(), "raft.db")

fakedb, err := raftboltdb.NewBoltStore(dir)
require.NoError(t, err)

// Next try to read the db without closing it
s, _, _, err := RaftStateInfo(dir)
assert.Nil(t, s)
require.EqualError(t, err, errAlreadyOpen.Error())

// LogEntries should produce the same error
_, _, err = LogEntries(dir)
require.EqualError(t, err, "failed to open raft logs: "+errAlreadyOpen.Error())

// Commands should work once the db is closed
require.NoError(t, fakedb.Close())

s, _, _, err = RaftStateInfo(dir)
assert.NotNil(t, s)
require.NoError(t, err)
require.NoError(t, s.Close())

logCh, errCh, err := LogEntries(dir)
require.NoError(t, err)

// Consume entries to cleanly close db
for closed := false; closed; {
select {
case _, closed = <-logCh:
case <-errCh:
}
}
}

0 comments on commit 3ca534a

Please sign in to comment.