Adds Remote Cluster related API endpoints (#27432)
* Adds Remote Cluster related API endpoints
New endpoints for the following routes are added:
- Get Remote Clusters at `GET /api/v4/remotecluster`
- Create Remote Cluster at `POST /api/v4/remotecluster`
- Accept Remote Cluster invite at `POST
/api/v4/remotecluster/accept_invite`
- Generate Remote Cluster invite at `POST
/api/v4/remotecluster/{remote_id}/generate_invite`
- Get Remote Cluster at `GET /api/v4/remotecluster/{remote_id}`
- Patch Remote Cluster at `PATCH /api/v4/remotecluster/{remote_id}`
- Delete Remote Cluster at `DELETE /api/v4/remotecluster/{remote_id}`
These endpoints are planned to be used from the system console, and
gated through the `manage_secure_connections` permission.
* Update server/channels/api4/remote_cluster_test.go
Co-authored-by: Doug Lauder <wiggin77@warpmail.net>
* Fix AppError names
---------
Co-authored-by: Doug Lauder <wiggin77@warpmail.net>
Co-authored-by: Mattermost Build <build@mattermost.com>
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
cc5e87ae24
Коммит
809ad4f76d
@@ -7828,7 +7828,7 @@ func (s *OpenTracingLayerRemoteClusterStore) Get(remoteClusterId string) (*model
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (s *OpenTracingLayerRemoteClusterStore) GetAll(filter model.RemoteClusterQueryFilter) ([]*model.RemoteCluster, error) {
|
||||
func (s *OpenTracingLayerRemoteClusterStore) GetAll(offset int, limit int, filter model.RemoteClusterQueryFilter) ([]*model.RemoteCluster, error) {
|
||||
origCtx := s.Root.Store.Context()
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "RemoteClusterStore.GetAll")
|
||||
s.Root.Store.SetContext(newCtx)
|
||||
@@ -7837,7 +7837,7 @@ func (s *OpenTracingLayerRemoteClusterStore) GetAll(filter model.RemoteClusterQu
|
||||
}()
|
||||
|
||||
defer span.Finish()
|
||||
result, err := s.RemoteClusterStore.GetAll(filter)
|
||||
result, err := s.RemoteClusterStore.GetAll(offset, limit, filter)
|
||||
if err != nil {
|
||||
span.LogFields(spanlog.Error(err))
|
||||
ext.Error.Set(span, true)
|
||||
|
||||
@@ -8909,11 +8909,11 @@ func (s *RetryLayerRemoteClusterStore) Get(remoteClusterId string) (*model.Remot
|
||||
|
||||
}
|
||||
|
||||
func (s *RetryLayerRemoteClusterStore) GetAll(filter model.RemoteClusterQueryFilter) ([]*model.RemoteCluster, error) {
|
||||
func (s *RetryLayerRemoteClusterStore) GetAll(offset int, limit int, filter model.RemoteClusterQueryFilter) ([]*model.RemoteCluster, error) {
|
||||
|
||||
tries := 0
|
||||
for {
|
||||
result, err := s.RemoteClusterStore.GetAll(filter)
|
||||
result, err := s.RemoteClusterStore.GetAll(offset, limit, filter)
|
||||
if err == nil {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
@@ -162,7 +162,14 @@ func (s sqlRemoteClusterStore) GetByPluginID(pluginID string) (*model.RemoteClus
|
||||
return &rc, nil
|
||||
}
|
||||
|
||||
func (s sqlRemoteClusterStore) GetAll(filter model.RemoteClusterQueryFilter) ([]*model.RemoteCluster, error) {
|
||||
func (s sqlRemoteClusterStore) GetAll(offset, limit int, filter model.RemoteClusterQueryFilter) ([]*model.RemoteCluster, error) {
|
||||
if offset < 0 {
|
||||
return nil, errors.New("offset must be a positive integer")
|
||||
}
|
||||
if limit < 0 {
|
||||
return nil, errors.New("limit must be a positive integer")
|
||||
}
|
||||
|
||||
query := s.getQueryBuilder().
|
||||
Select(remoteClusterFields("rc")...).
|
||||
From("RemoteClusters rc")
|
||||
@@ -195,6 +202,10 @@ func (s sqlRemoteClusterStore) GetAll(filter model.RemoteClusterQueryFilter) ([]
|
||||
query = query.Where(sq.NotEq{"rc.PluginID": ""})
|
||||
}
|
||||
|
||||
if filter.ExcludePlugins {
|
||||
query = query.Where(sq.Eq{"rc.PluginID": ""})
|
||||
}
|
||||
|
||||
if filter.RequireOptions != 0 {
|
||||
query = query.Where(sq.NotEq{fmt.Sprintf("(rc.Options & %d)", filter.RequireOptions): 0})
|
||||
}
|
||||
@@ -208,6 +219,8 @@ func (s sqlRemoteClusterStore) GetAll(filter model.RemoteClusterQueryFilter) ([]
|
||||
query = query.Where(sq.Or{sq.Like{"rc.Topics": queryTopic}, sq.Eq{"rc.Topics": "*"}})
|
||||
}
|
||||
|
||||
query = query.Offset(uint64(offset)).Limit(uint64(limit))
|
||||
|
||||
queryString, args, err := query.ToSql()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "remote_cluster_getall_tosql")
|
||||
|
||||
@@ -533,7 +533,7 @@ type RemoteClusterStore interface {
|
||||
Delete(remoteClusterId string) (bool, error)
|
||||
Get(remoteClusterId string) (*model.RemoteCluster, error)
|
||||
GetByPluginID(pluginID string) (*model.RemoteCluster, error)
|
||||
GetAll(filter model.RemoteClusterQueryFilter) ([]*model.RemoteCluster, error)
|
||||
GetAll(offset, limit int, filter model.RemoteClusterQueryFilter) ([]*model.RemoteCluster, error)
|
||||
UpdateTopics(remoteClusterId string, topics string) (*model.RemoteCluster, error)
|
||||
SetLastPingAt(remoteClusterId string) error
|
||||
}
|
||||
|
||||
@@ -72,9 +72,9 @@ func (_m *RemoteClusterStore) Get(remoteClusterId string) (*model.RemoteCluster,
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetAll provides a mock function with given fields: filter
|
||||
func (_m *RemoteClusterStore) GetAll(filter model.RemoteClusterQueryFilter) ([]*model.RemoteCluster, error) {
|
||||
ret := _m.Called(filter)
|
||||
// GetAll provides a mock function with given fields: offset, limit, filter
|
||||
func (_m *RemoteClusterStore) GetAll(offset int, limit int, filter model.RemoteClusterQueryFilter) ([]*model.RemoteCluster, error) {
|
||||
ret := _m.Called(offset, limit, filter)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for GetAll")
|
||||
@@ -82,19 +82,19 @@ func (_m *RemoteClusterStore) GetAll(filter model.RemoteClusterQueryFilter) ([]*
|
||||
|
||||
var r0 []*model.RemoteCluster
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(model.RemoteClusterQueryFilter) ([]*model.RemoteCluster, error)); ok {
|
||||
return rf(filter)
|
||||
if rf, ok := ret.Get(0).(func(int, int, model.RemoteClusterQueryFilter) ([]*model.RemoteCluster, error)); ok {
|
||||
return rf(offset, limit, filter)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(model.RemoteClusterQueryFilter) []*model.RemoteCluster); ok {
|
||||
r0 = rf(filter)
|
||||
if rf, ok := ret.Get(0).(func(int, int, model.RemoteClusterQueryFilter) []*model.RemoteCluster); ok {
|
||||
r0 = rf(offset, limit, filter)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]*model.RemoteCluster)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(model.RemoteClusterQueryFilter) error); ok {
|
||||
r1 = rf(filter)
|
||||
if rf, ok := ret.Get(1).(func(int, int, model.RemoteClusterQueryFilter) error); ok {
|
||||
r1 = rf(offset, limit, filter)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
@@ -238,6 +238,7 @@ func testRemoteClusterGetAll(t *testing.T, _ request.CTX, ss store.Store) {
|
||||
idsOnline := make([]string, 0)
|
||||
idsShareTopic := make([]string, 0)
|
||||
idsPlugin := make([]string, 0)
|
||||
idsNotPlugin := make([]string, 0)
|
||||
idsConfirmed := make([]string, 0)
|
||||
|
||||
for _, item := range data {
|
||||
@@ -253,6 +254,8 @@ func testRemoteClusterGetAll(t *testing.T, _ request.CTX, ss store.Store) {
|
||||
}
|
||||
if item.PluginID != "" {
|
||||
idsPlugin = append(idsPlugin, saved.RemoteId)
|
||||
} else {
|
||||
idsNotPlugin = append(idsNotPlugin, saved.RemoteId)
|
||||
}
|
||||
if item.SiteURL != "" {
|
||||
idsConfirmed = append(idsConfirmed, saved.RemoteId)
|
||||
@@ -261,7 +264,7 @@ func testRemoteClusterGetAll(t *testing.T, _ request.CTX, ss store.Store) {
|
||||
|
||||
t.Run("GetAll", func(t *testing.T) {
|
||||
filter := model.RemoteClusterQueryFilter{}
|
||||
remotes, err := ss.RemoteCluster().GetAll(filter)
|
||||
remotes, err := ss.RemoteCluster().GetAll(0, 999999, filter)
|
||||
require.NoError(t, err)
|
||||
// make sure all the test data remotes were returned.
|
||||
ids := getIds(remotes)
|
||||
@@ -272,7 +275,7 @@ func testRemoteClusterGetAll(t *testing.T, _ request.CTX, ss store.Store) {
|
||||
filter := model.RemoteClusterQueryFilter{
|
||||
ExcludeOffline: true,
|
||||
}
|
||||
remotes, err := ss.RemoteCluster().GetAll(filter)
|
||||
remotes, err := ss.RemoteCluster().GetAll(0, 999999, filter)
|
||||
require.NoError(t, err)
|
||||
// make sure all the online remotes were returned.
|
||||
ids := getIds(remotes)
|
||||
@@ -283,7 +286,7 @@ func testRemoteClusterGetAll(t *testing.T, _ request.CTX, ss store.Store) {
|
||||
filter := model.RemoteClusterQueryFilter{
|
||||
Topic: "shared",
|
||||
}
|
||||
remotes, err := ss.RemoteCluster().GetAll(filter)
|
||||
remotes, err := ss.RemoteCluster().GetAll(0, 999999, filter)
|
||||
require.NoError(t, err)
|
||||
// make sure only correct topic returned
|
||||
ids := getIds(remotes)
|
||||
@@ -295,7 +298,7 @@ func testRemoteClusterGetAll(t *testing.T, _ request.CTX, ss store.Store) {
|
||||
ExcludeOffline: true,
|
||||
Topic: "shared",
|
||||
}
|
||||
remotes, err := ss.RemoteCluster().GetAll(filter)
|
||||
remotes, err := ss.RemoteCluster().GetAll(0, 999999, filter)
|
||||
require.NoError(t, err)
|
||||
// make sure only online remotes were returned.
|
||||
ids := getIds(remotes)
|
||||
@@ -309,7 +312,7 @@ func testRemoteClusterGetAll(t *testing.T, _ request.CTX, ss store.Store) {
|
||||
filter := model.RemoteClusterQueryFilter{
|
||||
CreatorId: userId,
|
||||
}
|
||||
remotes, err := ss.RemoteCluster().GetAll(filter)
|
||||
remotes, err := ss.RemoteCluster().GetAll(0, 999999, filter)
|
||||
require.NoError(t, err)
|
||||
// make sure only correct creator returned
|
||||
assert.Len(t, remotes, 3)
|
||||
@@ -322,7 +325,7 @@ func testRemoteClusterGetAll(t *testing.T, _ request.CTX, ss store.Store) {
|
||||
filter := model.RemoteClusterQueryFilter{
|
||||
OnlyConfirmed: true,
|
||||
}
|
||||
remotes, err := ss.RemoteCluster().GetAll(filter)
|
||||
remotes, err := ss.RemoteCluster().GetAll(0, 999999, filter)
|
||||
require.NoError(t, err)
|
||||
// make sure only confirmed returned
|
||||
for _, rc := range remotes {
|
||||
@@ -337,7 +340,7 @@ func testRemoteClusterGetAll(t *testing.T, _ request.CTX, ss store.Store) {
|
||||
filter := model.RemoteClusterQueryFilter{
|
||||
OnlyPlugins: true,
|
||||
}
|
||||
remotes, err := ss.RemoteCluster().GetAll(filter)
|
||||
remotes, err := ss.RemoteCluster().GetAll(0, 999999, filter)
|
||||
require.NoError(t, err)
|
||||
// make sure only plugin remotes returned
|
||||
for _, rc := range remotes {
|
||||
@@ -348,6 +351,22 @@ func testRemoteClusterGetAll(t *testing.T, _ request.CTX, ss store.Store) {
|
||||
ids := getIds(remotes)
|
||||
assert.ElementsMatch(t, ids, idsPlugin)
|
||||
})
|
||||
|
||||
t.Run("GetAll excluding plugins", func(t *testing.T) {
|
||||
filter := model.RemoteClusterQueryFilter{
|
||||
ExcludePlugins: true,
|
||||
}
|
||||
remotes, err := ss.RemoteCluster().GetAll(0, 999999, filter)
|
||||
require.NoError(t, err)
|
||||
// make sure only non plugin remotes returned
|
||||
for _, rc := range remotes {
|
||||
assert.Empty(t, rc.PluginID)
|
||||
assert.False(t, rc.IsPlugin())
|
||||
}
|
||||
// make sure all of the non plugin remotes were returned.
|
||||
ids := getIds(remotes)
|
||||
assert.ElementsMatch(t, ids, idsNotPlugin)
|
||||
})
|
||||
}
|
||||
|
||||
func testRemoteClusterGetAllInChannel(t *testing.T, rctx request.CTX, ss store.Store) {
|
||||
@@ -411,7 +430,7 @@ func testRemoteClusterGetAllInChannel(t *testing.T, rctx request.CTX, ss store.S
|
||||
filter := model.RemoteClusterQueryFilter{
|
||||
InChannel: channel1.Id,
|
||||
}
|
||||
list, err := ss.RemoteCluster().GetAll(filter)
|
||||
list, err := ss.RemoteCluster().GetAll(0, 999999, filter)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, list, 2, "channel 1 should have 2 remote clusters")
|
||||
ids := getIds(list)
|
||||
@@ -425,7 +444,7 @@ func testRemoteClusterGetAllInChannel(t *testing.T, rctx request.CTX, ss store.S
|
||||
ExcludeOffline: true,
|
||||
InChannel: channel1.Id,
|
||||
}
|
||||
list, err := ss.RemoteCluster().GetAll(filter)
|
||||
list, err := ss.RemoteCluster().GetAll(0, 999999, filter)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, list, 1, "channel 1 should have 1 online remote clusters")
|
||||
ids := getIds(list)
|
||||
@@ -436,7 +455,7 @@ func testRemoteClusterGetAllInChannel(t *testing.T, rctx request.CTX, ss store.S
|
||||
filter := model.RemoteClusterQueryFilter{
|
||||
InChannel: channel2.Id,
|
||||
}
|
||||
list, err := ss.RemoteCluster().GetAll(filter)
|
||||
list, err := ss.RemoteCluster().GetAll(0, 999999, filter)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, list, 3, "channel 2 should have 3 remote clusters")
|
||||
ids := getIds(list)
|
||||
@@ -448,7 +467,7 @@ func testRemoteClusterGetAllInChannel(t *testing.T, rctx request.CTX, ss store.S
|
||||
ExcludeOffline: true,
|
||||
InChannel: channel2.Id,
|
||||
}
|
||||
list, err := ss.RemoteCluster().GetAll(filter)
|
||||
list, err := ss.RemoteCluster().GetAll(0, 999999, filter)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, list, 2, "channel 2 should have 2 online remote clusters")
|
||||
ids := getIds(list)
|
||||
@@ -459,7 +478,7 @@ func testRemoteClusterGetAllInChannel(t *testing.T, rctx request.CTX, ss store.S
|
||||
filter := model.RemoteClusterQueryFilter{
|
||||
InChannel: channel3.Id,
|
||||
}
|
||||
list, err := ss.RemoteCluster().GetAll(filter)
|
||||
list, err := ss.RemoteCluster().GetAll(0, 999999, filter)
|
||||
require.NoError(t, err)
|
||||
require.Empty(t, list, "channel 3 should have 0 remote clusters")
|
||||
})
|
||||
@@ -520,7 +539,7 @@ func testRemoteClusterGetAllNotInChannel(t *testing.T, rctx request.CTX, ss stor
|
||||
filter := model.RemoteClusterQueryFilter{
|
||||
NotInChannel: channel1.Id,
|
||||
}
|
||||
list, err := ss.RemoteCluster().GetAll(filter)
|
||||
list, err := ss.RemoteCluster().GetAll(0, 999999, filter)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, list, 3, "channel 1 should have 3 remote clusters that are not already members")
|
||||
ids := getIds(list)
|
||||
@@ -531,7 +550,7 @@ func testRemoteClusterGetAllNotInChannel(t *testing.T, rctx request.CTX, ss stor
|
||||
filter := model.RemoteClusterQueryFilter{
|
||||
NotInChannel: channel2.Id,
|
||||
}
|
||||
list, err := ss.RemoteCluster().GetAll(filter)
|
||||
list, err := ss.RemoteCluster().GetAll(0, 999999, filter)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, list, 3, "channel 2 should have 3 remote clusters that are not already members")
|
||||
ids := getIds(list)
|
||||
@@ -542,7 +561,7 @@ func testRemoteClusterGetAllNotInChannel(t *testing.T, rctx request.CTX, ss stor
|
||||
filter := model.RemoteClusterQueryFilter{
|
||||
NotInChannel: channel3.Id,
|
||||
}
|
||||
list, err := ss.RemoteCluster().GetAll(filter)
|
||||
list, err := ss.RemoteCluster().GetAll(0, 999999, filter)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, list, 4, "channel 3 should have 4 remote clusters that are not already members")
|
||||
ids := getIds(list)
|
||||
@@ -553,7 +572,7 @@ func testRemoteClusterGetAllNotInChannel(t *testing.T, rctx request.CTX, ss stor
|
||||
filter := model.RemoteClusterQueryFilter{
|
||||
NotInChannel: model.NewId(),
|
||||
}
|
||||
list, err := ss.RemoteCluster().GetAll(filter)
|
||||
list, err := ss.RemoteCluster().GetAll(0, 999999, filter)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, list, 5, "should have 5 remote clusters that are not already members")
|
||||
ids := getIds(list)
|
||||
@@ -605,7 +624,7 @@ func testRemoteClusterGetByTopic(t *testing.T, _ request.CTX, ss store.Store) {
|
||||
filter := model.RemoteClusterQueryFilter{
|
||||
Topic: tt.topic,
|
||||
}
|
||||
list, err := ss.RemoteCluster().GetAll(filter)
|
||||
list, err := ss.RemoteCluster().GetAll(0, 999999, filter)
|
||||
if tt.expectError {
|
||||
assert.Errorf(t, err, "expected error for topic=%s", tt.topic)
|
||||
} else {
|
||||
@@ -653,7 +672,7 @@ func testRemoteClusterUpdateTopics(t *testing.T, _ request.CTX, ss store.Store)
|
||||
}
|
||||
|
||||
func clearRemoteClusters(ss store.Store) error {
|
||||
list, err := ss.RemoteCluster().GetAll(model.RemoteClusterQueryFilter{})
|
||||
list, err := ss.RemoteCluster().GetAll(0, 999999, model.RemoteClusterQueryFilter{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -7065,10 +7065,10 @@ func (s *TimerLayerRemoteClusterStore) Get(remoteClusterId string) (*model.Remot
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (s *TimerLayerRemoteClusterStore) GetAll(filter model.RemoteClusterQueryFilter) ([]*model.RemoteCluster, error) {
|
||||
func (s *TimerLayerRemoteClusterStore) GetAll(offset int, limit int, filter model.RemoteClusterQueryFilter) ([]*model.RemoteCluster, error) {
|
||||
start := time.Now()
|
||||
|
||||
result, err := s.RemoteClusterStore.GetAll(filter)
|
||||
result, err := s.RemoteClusterStore.GetAll(offset, limit, filter)
|
||||
|
||||
elapsed := float64(time.Since(start)) / float64(time.Second)
|
||||
if s.Root.Metrics != nil {
|
||||
|
||||
Ссылка в новой задаче
Block a user