mirror of
https://github.com/garethgeorge/backrest.git
synced 2026-05-29 16:00:57 +00:00
more bug fixes and progress
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"maps"
|
||||
"slices"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@@ -67,9 +68,9 @@ func peerStateToProto(state *PeerState) *v1sync.PeerState {
|
||||
LastHeartbeatMillis: state.LastHeartbeat.UnixMilli(),
|
||||
State: state.ConnectionState,
|
||||
StatusMessage: state.ConnectionStateMessage,
|
||||
// KnownRepos: slices.Collect(maps.Keys(state.KnownRepos)),
|
||||
// KnownPlans: slices.Collect(maps.Keys(state.KnownPlans)),
|
||||
RemoteConfig: state.Config,
|
||||
KnownRepos: slices.Collect(maps.Values(state.KnownRepos)),
|
||||
KnownPlans: slices.Collect(maps.Values(state.KnownPlans)),
|
||||
RemoteConfig: state.Config,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -234,12 +235,10 @@ func (m *SqlitePeerStateManager) SetPeerState(keyID string, state *PeerState) {
|
||||
stateBytes, err := proto.Marshal(stateProto)
|
||||
if err != nil {
|
||||
zap.S().Warnf("error marshalling peer state for key %s: %v", keyID, err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := m.kvstore.Set(keyID, stateBytes); err != nil {
|
||||
zap.S().Warnf("error setting peer state for key %s: %v", keyID, err)
|
||||
return
|
||||
}
|
||||
m.onStateChanged.Emit(state.Clone())
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"github.com/garethgeorge/backrest/gen/go/v1sync"
|
||||
"github.com/garethgeorge/backrest/internal/kvstore"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"google.golang.org/protobuf/testing/protocmp"
|
||||
)
|
||||
|
||||
func PeerStateManagersForTest(t testing.TB) map[string]PeerStateManager {
|
||||
@@ -31,9 +32,11 @@ func TestPeerStateManager_GetSet(t *testing.T) {
|
||||
t.Parallel()
|
||||
keyID := "testKey"
|
||||
state := &PeerState{
|
||||
InstanceID: "testInstance",
|
||||
KeyID: keyID,
|
||||
LastHeartbeat: time.Now().Round(time.Millisecond),
|
||||
InstanceID: "testInstance",
|
||||
KeyID: keyID,
|
||||
LastHeartbeat: time.Now().Round(time.Millisecond),
|
||||
ConnectionState: v1sync.ConnectionState_CONNECTION_STATE_CONNECTED,
|
||||
ConnectionStateMessage: "hello world!",
|
||||
KnownRepos: map[string]*v1sync.RepoMetadata{
|
||||
"repo1": {
|
||||
Id: "repo1",
|
||||
@@ -52,7 +55,7 @@ func TestPeerStateManager_GetSet(t *testing.T) {
|
||||
}
|
||||
psm.SetPeerState(keyID, state)
|
||||
gotState := psm.GetPeerState(keyID)
|
||||
if diff := cmp.Diff(state, gotState, cmp.AllowUnexported(PeerState{})); diff != "" {
|
||||
if diff := cmp.Diff(state, gotState, cmp.AllowUnexported(PeerState{}), protocmp.Transform()); diff != "" {
|
||||
t.Errorf("unexpected diff: %v", diff)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -284,6 +284,7 @@ func TestSimpleOperationSync(t *testing.T) {
|
||||
{
|
||||
Id: defaultRepoID,
|
||||
Guid: defaultRepoGUID,
|
||||
Uri: "test-uri",
|
||||
},
|
||||
},
|
||||
Multihost: &v1.Multihost{
|
||||
@@ -336,12 +337,12 @@ func TestSimpleOperationSync(t *testing.T) {
|
||||
DisplayMessage: "hostop1",
|
||||
},
|
||||
})...)
|
||||
peerHost.oplog.Add(testutil.OperationsWithDefaults(basicClientOperationTempl, []*v1.Operation{
|
||||
{
|
||||
DisplayMessage: "clientop-missing",
|
||||
OriginalId: 1234, // must be an ID that doesn't exist remotely
|
||||
},
|
||||
})...)
|
||||
// peerHost.oplog.Add(testutil.OperationsWithDefaults(basicClientOperationTempl, []*v1.Operation{
|
||||
// {
|
||||
// DisplayMessage: "clientop-deleted",
|
||||
// OriginalId: 1234, // must be an ID that doesn't exist remotely
|
||||
// },
|
||||
// })...)
|
||||
|
||||
if err := peerClient.oplog.Add(testutil.OperationsWithDefaults(basicClientOperationTempl, []*v1.Operation{
|
||||
{
|
||||
@@ -410,6 +411,7 @@ func TestSyncMutations(t *testing.T) {
|
||||
{
|
||||
Id: defaultRepoID,
|
||||
Guid: defaultRepoGUID,
|
||||
Uri: "test-uri",
|
||||
},
|
||||
},
|
||||
Multihost: &v1.Multihost{
|
||||
@@ -608,7 +610,7 @@ func tryExpectOperationsSynced(t *testing.T, ctx context.Context, peer1 *peerUnd
|
||||
return errors.New("no operations found in peer2")
|
||||
}
|
||||
if diff := cmp.Diff(peer1Ops, peer2Ops, protocmp.Transform()); diff != "" {
|
||||
return fmt.Errorf("unexpected diff: %v", diff)
|
||||
return fmt.Errorf("%s: unexpected diff: %v", message, diff)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -196,7 +196,7 @@ func (c *syncSessionHandlerClient) applyPermissions() {
|
||||
}
|
||||
}
|
||||
for _, repo := range c.syncConfigSnapshot.config.Repos {
|
||||
if c.permissions.CheckPermissionForRepo(repo.Guid, v1.Multihost_Permission_PERMISSION_READ_OPERATIONS) {
|
||||
if c.permissions.CheckPermissionForRepo(repo.Id, v1.Multihost_Permission_PERMISSION_READ_OPERATIONS) {
|
||||
c.canForwardReposSet[repo.Guid] = struct{}{}
|
||||
}
|
||||
}
|
||||
@@ -429,7 +429,7 @@ func (c *syncSessionHandlerClient) HandleReceiveResources(ctx context.Context, s
|
||||
|
||||
// Note unused: there isn't a situation where the host would send its config for information, the host will only call 'SetConfig' to update the config.
|
||||
func (c *syncSessionHandlerClient) HandleReceiveConfig(ctx context.Context, stream *bidiSyncCommandStream, item *v1sync.SyncStreamItem_SyncActionReceiveConfig) error {
|
||||
c.l.Sugar().Debugf("received remote config update", zap.Any("config", item.GetConfig()))
|
||||
c.l.Sugar().Debugf("received remote config update")
|
||||
peerState := c.mgr.peerStateManager.GetPeerState(c.peer.Keyid).Clone()
|
||||
if peerState == nil {
|
||||
return NewSyncErrorInternal(fmt.Errorf("peer state for %q not found", c.peer.Keyid))
|
||||
@@ -506,20 +506,20 @@ func (c *syncSessionHandlerClient) HandleSetConfig(ctx context.Context, stream *
|
||||
}
|
||||
}
|
||||
|
||||
for _, repo := range item.GetReposToDelete() {
|
||||
c.l.Sugar().Debugf("received repo deletion request: %s", repo)
|
||||
if !c.permissions.CheckPermissionForRepo(repo, permissions.PermsCanWriteConfiguration...) {
|
||||
return NewSyncErrorAuth(fmt.Errorf("peer %q is not allowed to delete repo %q", c.peer.InstanceId, repo))
|
||||
for _, repoID := range item.GetReposToDelete() {
|
||||
c.l.Sugar().Debugf("received repo deletion request: %s", repoID)
|
||||
if !c.permissions.CheckPermissionForRepo(repoID, permissions.PermsCanWriteConfiguration...) {
|
||||
return NewSyncErrorAuth(fmt.Errorf("peer %q is not allowed to delete repo %q", c.peer.InstanceId, repoID))
|
||||
}
|
||||
|
||||
// Remove the repo from the local config
|
||||
idx := slices.IndexFunc(latestConfig.Repos, func(r *v1.Repo) bool {
|
||||
return r.Id == repo
|
||||
return r.Id == repoID
|
||||
})
|
||||
if idx >= 0 {
|
||||
latestConfig.Repos = append(latestConfig.Repos[:idx], latestConfig.Repos[idx+1:]...)
|
||||
} else {
|
||||
c.l.Sugar().Warnf("received repo deletion request for non-existent repo %q, ignoring", repo)
|
||||
c.l.Sugar().Warnf("received repo deletion request for non-existent repo %q, ignoring", repoID)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -567,7 +567,7 @@ func (c *syncSessionHandlerClient) sendResourceList(ctx context.Context, stream
|
||||
planMetadatas := []*v1sync.PlanMetadata{}
|
||||
|
||||
for _, repo := range c.syncConfigSnapshot.config.Repos {
|
||||
if c.permissions.CheckPermissionForRepo(repo.Guid, permissions.PermsCanViewResources...) {
|
||||
if c.permissions.CheckPermissionForRepo(repo.Id, permissions.PermsCanViewResources...) {
|
||||
repoMetadatas = append(repoMetadatas, &v1sync.RepoMetadata{
|
||||
Id: repo.Id,
|
||||
Guid: repo.Guid,
|
||||
|
||||
@@ -335,7 +335,7 @@ func (h *syncSessionHandlerServer) sendConfigToClient(stream *bidiSyncCommandStr
|
||||
}
|
||||
|
||||
func (h *syncSessionHandlerServer) sendOperationSyncRequest(stream *bidiSyncCommandStream) error {
|
||||
highestID, highestModno, err := h.mgr.oplog.GetHighestOpIDAndModno()
|
||||
highestID, highestModno, err := h.mgr.oplog.GetHighestOpIDAndModno(oplog.Query{}.SetOriginalInstanceKeyid(h.peer.Keyid))
|
||||
if err != nil {
|
||||
return fmt.Errorf("getting highest opid and modno: %w", err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user