more bug fixes and progress

This commit is contained in:
Gareth
2025-11-01 14:34:04 -07:00
parent 9de7ddc3a0
commit 0dcfbd2beb
10 changed files with 164 additions and 32 deletions
+4 -5
View File
@@ -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 -4
View File
@@ -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)
}
})
+9 -7
View File
@@ -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
+9 -9
View File
@@ -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,
+1 -1
View File
@@ -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)
}