diff --git a/.changelog/10612.txt b/.changelog/10612.txt new file mode 100644 index 0000000000..e9a54002da --- /dev/null +++ b/.changelog/10612.txt @@ -0,0 +1,3 @@ +```release-note:improvement +acl: replication routine to report the last error message. +``` diff --git a/agent/consul/acl_replication.go b/agent/consul/acl_replication.go index 0e8da6e9ff..aabd49c471 100644 --- a/agent/consul/acl_replication.go +++ b/agent/consul/acl_replication.go @@ -484,11 +484,12 @@ func (s *Server) IsACLReplicationEnabled() bool { s.config.ACLTokenReplication } -func (s *Server) updateACLReplicationStatusError() { +func (s *Server) updateACLReplicationStatusError(errorMsg string) { s.aclReplicationStatusLock.Lock() defer s.aclReplicationStatusLock.Unlock() s.aclReplicationStatus.LastError = time.Now().Round(time.Second).UTC() + s.aclReplicationStatus.LastErrorMessage = errorMsg } func (s *Server) updateACLReplicationStatusIndex(replicationType structs.ACLReplicationType, index uint64) { diff --git a/agent/consul/acl_replication_test.go b/agent/consul/acl_replication_test.go index 26726fe360..0bb96a8457 100644 --- a/agent/consul/acl_replication_test.go +++ b/agent/consul/acl_replication_test.go @@ -780,6 +780,7 @@ func TestACLReplication_TokensRedacted(t *testing.T) { require.True(r, status.ReplicatedTokenIndex < token2.CreateIndex, "ReplicatedTokenIndex is not less than the token2s create index") // ensures that token replication is erroring require.True(r, status.LastError.After(minErrorTime), "Replication LastError not after the minErrorTime") + require.Equal(r, status.LastErrorMessage, "failed to retrieve unredacted tokens - replication token in use does not grant acl:write") }) } diff --git a/agent/consul/leader.go b/agent/consul/leader.go index c076ab34bc..7c41ce9575 100644 --- a/agent/consul/leader.go +++ b/agent/consul/leader.go @@ -807,7 +807,7 @@ func (s *Server) runLegacyACLReplication(ctx context.Context) error { 0, ) lastRemoteIndex = 0 - s.updateACLReplicationStatusError() + s.updateACLReplicationStatusError(err.Error()) legacyACLLogger.Warn("Legacy ACL replication error (will retry if still leader)", "error", err) } else { metrics.SetGauge([]string{"leader", "replication", "acl-legacy", "status"}, @@ -924,7 +924,7 @@ func (s *Server) runACLReplicator( 0, ) lastRemoteIndex = 0 - s.updateACLReplicationStatusError() + s.updateACLReplicationStatusError(err.Error()) logger.Warn("ACL replication error (will retry if still leader)", "error", err, ) diff --git a/agent/structs/acl.go b/agent/structs/acl.go index 056d7e7181..64d5656da1 100644 --- a/agent/structs/acl.go +++ b/agent/structs/acl.go @@ -1273,6 +1273,7 @@ type ACLReplicationStatus struct { ReplicatedTokenIndex uint64 LastSuccess time.Time LastError time.Time + LastErrorMessage string } // ACLTokenSetRequest is used for token creation and update operations diff --git a/api/acl.go b/api/acl.go index f48071f002..ebb8e5a967 100644 --- a/api/acl.go +++ b/api/acl.go @@ -106,6 +106,7 @@ type ACLReplicationStatus struct { ReplicatedTokenIndex uint64 LastSuccess time.Time LastError time.Time + LastErrorMessage string } // ACLServiceIdentity represents a high-level grant of all necessary privileges