diff --git a/server/channels/api4/cluster.go b/server/channels/api4/cluster.go index f2b246d832..102ee25485 100644 --- a/server/channels/api4/cluster.go +++ b/server/channels/api4/cluster.go @@ -20,7 +20,12 @@ func getClusterStatus(c *Context, w http.ResponseWriter, r *http.Request) { return } - infos := c.App.GetClusterStatus(c.AppContext) + infos, err := c.App.GetClusterStatus(c.AppContext) + if err != nil { + c.Err = model.NewAppError("getClusterStatus", "api.marshal_error", nil, "", http.StatusInternalServerError).Wrap(err) + return + } + js, err := json.Marshal(infos) if err != nil { c.Err = model.NewAppError("getClusterStatus", "api.marshal_error", nil, "", http.StatusInternalServerError).Wrap(err) diff --git a/server/channels/app/admin.go b/server/channels/app/admin.go index 67330c677c..2c043695fd 100644 --- a/server/channels/app/admin.go +++ b/server/channels/app/admin.go @@ -131,14 +131,11 @@ func (a *App) GetLogsSkipSend(rctx request.CTX, page, perPage int, logFilter *mo return a.Srv().GetLogsSkipSend(rctx, page, perPage, logFilter) } -func (a *App) GetClusterStatus(rctx request.CTX) []*model.ClusterInfo { - infos := make([]*model.ClusterInfo, 0) - - if a.Cluster() != nil { - infos = a.Cluster().GetClusterInfos() +func (a *App) GetClusterStatus(rctx request.CTX) ([]*model.ClusterInfo, error) { + if a.Cluster() == nil { + return make([]*model.ClusterInfo, 0), nil } - - return infos + return a.Cluster().GetClusterInfos() } func (s *Server) InvalidateAllCaches() *model.AppError { diff --git a/server/channels/app/busy_test.go b/server/channels/app/busy_test.go index 44187513ed..741b684b0e 100644 --- a/server/channels/app/busy_test.go +++ b/server/channels/app/busy_test.go @@ -138,11 +138,11 @@ func (c *ClusterMock) StartInterNodeCommunication() {} func (c *ClusterMock) StopInterNodeCommunication() {} func (c *ClusterMock) RegisterClusterMessageHandler(event model.ClusterEvent, crm einterfaces.ClusterMessageHandler) { } -func (c *ClusterMock) GetClusterId() string { return "cluster_mock" } -func (c *ClusterMock) IsLeader() bool { return false } -func (c *ClusterMock) GetMyClusterInfo() *model.ClusterInfo { return nil } -func (c *ClusterMock) GetClusterInfos() []*model.ClusterInfo { return nil } -func (c *ClusterMock) NotifyMsg(buf []byte) {} +func (c *ClusterMock) GetClusterId() string { return "cluster_mock" } +func (c *ClusterMock) IsLeader() bool { return false } +func (c *ClusterMock) GetMyClusterInfo() *model.ClusterInfo { return nil } +func (c *ClusterMock) GetClusterInfos() ([]*model.ClusterInfo, error) { return nil, nil } +func (c *ClusterMock) NotifyMsg(buf []byte) {} func (c *ClusterMock) GetClusterStats(rctx request.CTX) ([]*model.ClusterStats, *model.AppError) { return nil, nil } diff --git a/server/channels/app/platform/busy_test.go b/server/channels/app/platform/busy_test.go index 0a341aab32..d04955c930 100644 --- a/server/channels/app/platform/busy_test.go +++ b/server/channels/app/platform/busy_test.go @@ -139,11 +139,11 @@ func (c *ClusterMock) StartInterNodeCommunication() {} func (c *ClusterMock) StopInterNodeCommunication() {} func (c *ClusterMock) RegisterClusterMessageHandler(event model.ClusterEvent, crm einterfaces.ClusterMessageHandler) { } -func (c *ClusterMock) GetClusterId() string { return "cluster_mock" } -func (c *ClusterMock) IsLeader() bool { return false } -func (c *ClusterMock) GetMyClusterInfo() *model.ClusterInfo { return nil } -func (c *ClusterMock) GetClusterInfos() []*model.ClusterInfo { return nil } -func (c *ClusterMock) NotifyMsg(buf []byte) {} +func (c *ClusterMock) GetClusterId() string { return "cluster_mock" } +func (c *ClusterMock) IsLeader() bool { return false } +func (c *ClusterMock) GetMyClusterInfo() *model.ClusterInfo { return nil } +func (c *ClusterMock) GetClusterInfos() ([]*model.ClusterInfo, error) { return nil, nil } +func (c *ClusterMock) NotifyMsg(buf []byte) {} func (c *ClusterMock) GetClusterStats(rctx request.CTX) ([]*model.ClusterStats, *model.AppError) { return nil, nil } diff --git a/server/channels/app/platform/support_packet.go b/server/channels/app/platform/support_packet.go index 28153d4481..f6a45705d1 100644 --- a/server/channels/app/platform/support_packet.go +++ b/server/channels/app/platform/support_packet.go @@ -141,8 +141,12 @@ func (ps *PlatformService) getSupportPacketDiagnostics(rctx request.CTX) (*model /* Cluster */ if cluster := ps.Cluster(); cluster != nil { d.Cluster.ID = cluster.GetClusterId() - clusterInfo := cluster.GetClusterInfos() - d.Cluster.NumberOfNodes = len(clusterInfo) + clusterInfo, e := cluster.GetClusterInfos() + if e != nil { + rErr = multierror.Append(rErr, errors.Wrap(e, "error while getting cluster infos")) + } else { + d.Cluster.NumberOfNodes = len(clusterInfo) + } } /* LDAP */ diff --git a/server/channels/jobs/batch_migration_worker.go b/server/channels/jobs/batch_migration_worker.go index 3f20d89969..21f7221c1d 100644 --- a/server/channels/jobs/batch_migration_worker.go +++ b/server/channels/jobs/batch_migration_worker.go @@ -14,7 +14,7 @@ import ( ) type BatchMigrationWorkerAppIFace interface { - GetClusterStatus(rctx request.CTX) []*model.ClusterInfo + GetClusterStatus(rctx request.CTX) ([]*model.ClusterInfo, error) } // BatchMigrationWorker processes database migration jobs in batches to help avoid table locks. @@ -87,7 +87,11 @@ func (worker *BatchMigrationWorker) doBatch(rctx *request.Context, job *model.Jo // checkIsClusterInSync returns true if all nodes in the cluster are running the same version, // logging a warning on the first mismatch found. func (worker *BatchMigrationWorker) checkIsClusterInSync(rctx request.CTX) bool { - clusterStatus := worker.app.GetClusterStatus(rctx) + clusterStatus, err := worker.app.GetClusterStatus(rctx) + if err != nil { + worker.logger.Error("Worker: Failed to get cluster status", mlog.Err(err)) + return false + } for i := 1; i < len(clusterStatus); i++ { if clusterStatus[i].SchemaVersion != clusterStatus[0].SchemaVersion { rctx.Logger().Warn( diff --git a/server/channels/jobs/batch_migration_worker_test.go b/server/channels/jobs/batch_migration_worker_test.go index 31b172e500..2ee34ed112 100644 --- a/server/channels/jobs/batch_migration_worker_test.go +++ b/server/channels/jobs/batch_migration_worker_test.go @@ -20,8 +20,8 @@ type MockApp struct { clusterInfo []*model.ClusterInfo } -func (ma MockApp) GetClusterStatus(rctx request.CTX) []*model.ClusterInfo { - return ma.clusterInfo +func (ma MockApp) GetClusterStatus(rctx request.CTX) ([]*model.ClusterInfo, error) { + return ma.clusterInfo, nil } func (ma *MockApp) SetInSync() { diff --git a/server/channels/testlib/cluster.go b/server/channels/testlib/cluster.go index e4c4aacdbd..daec048268 100644 --- a/server/channels/testlib/cluster.go +++ b/server/channels/testlib/cluster.go @@ -35,7 +35,7 @@ func (c *FakeClusterInterface) IsLeader() bool { return false } func (c *FakeClusterInterface) GetMyClusterInfo() *model.ClusterInfo { return nil } -func (c *FakeClusterInterface) GetClusterInfos() []*model.ClusterInfo { return nil } +func (c *FakeClusterInterface) GetClusterInfos() ([]*model.ClusterInfo, error) { return nil, nil } func (c *FakeClusterInterface) SendClusterMessage(message *model.ClusterMessage) { c.mut.Lock() diff --git a/server/einterfaces/cluster.go b/server/einterfaces/cluster.go index 47fac99026..f86e2a44e3 100644 --- a/server/einterfaces/cluster.go +++ b/server/einterfaces/cluster.go @@ -21,7 +21,7 @@ type ClusterInterface interface { // and zero means "totally healthy". HealthScore() int GetMyClusterInfo() *model.ClusterInfo - GetClusterInfos() []*model.ClusterInfo + GetClusterInfos() ([]*model.ClusterInfo, error) SendClusterMessage(msg *model.ClusterMessage) SendClusterMessageToNode(nodeID string, msg *model.ClusterMessage) error NotifyMsg(buf []byte) diff --git a/server/einterfaces/mocks/ClusterInterface.go b/server/einterfaces/mocks/ClusterInterface.go index a313b64120..11dea92b5d 100644 --- a/server/einterfaces/mocks/ClusterInterface.go +++ b/server/einterfaces/mocks/ClusterInterface.go @@ -87,7 +87,7 @@ func (_m *ClusterInterface) GetClusterId() string { } // GetClusterInfos provides a mock function with given fields: -func (_m *ClusterInterface) GetClusterInfos() []*model.ClusterInfo { +func (_m *ClusterInterface) GetClusterInfos() ([]*model.ClusterInfo, error) { ret := _m.Called() if len(ret) == 0 { @@ -95,6 +95,10 @@ func (_m *ClusterInterface) GetClusterInfos() []*model.ClusterInfo { } var r0 []*model.ClusterInfo + var r1 error + if rf, ok := ret.Get(0).(func() ([]*model.ClusterInfo, error)); ok { + return rf() + } if rf, ok := ret.Get(0).(func() []*model.ClusterInfo); ok { r0 = rf() } else { @@ -103,7 +107,13 @@ func (_m *ClusterInterface) GetClusterInfos() []*model.ClusterInfo { } } - return r0 + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 } // GetClusterStats provides a mock function with given fields: rctx