MM-49984: Displaying active search backend in system console (#22721)

This will be shown in the system console to let users know
which search backend is active.

Implemented via adding an extra param in the ping response.

https://mattermost.atlassian.net/browse/MM-49984

```release-note
The database section in the system console now has an additional
read-only section which shows the active search backend in use.

This can be helpful to confirm which is the currently active
search engine when there are multiple of them configured.
```
---------

Co-authored-by: Mattermost Build <build@mattermost.com>
This commit is contained in:
Agniva De Sarker 2023-04-14 14:28:50 +05:30 committed by GitHub
parent 4bf31bd227
commit 56bf1b695a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 166 additions and 6 deletions

View file

@ -190,6 +190,8 @@ func getSystemPing(c *Context, w http.ResponseWriter, r *http.Request) {
s["CanReceiveNotifications"] = c.App.SendTestPushNotification(deviceID)
}
s["ActiveSearchBackend"] = c.App.ActiveSearchBackend()
if s[model.STATUS] != model.StatusOk {
w.WriteHeader(http.StatusInternalServerError)
}

View file

@ -400,6 +400,7 @@ type AppIface interface {
VerifyPlugin(plugin, signature io.ReadSeeker) *model.AppError
AccountMigration() einterfaces.AccountMigrationInterface
ActivateMfa(userID, token string) *model.AppError
ActiveSearchBackend() string
AddChannelsToRetentionPolicy(policyID string, channelIDs []string) *model.AppError
AddConfigListener(listener func(*model.Config, *model.Config)) string
AddDirectChannels(c request.CTX, teamID string, user *model.User) *model.AppError

View file

@ -89,6 +89,23 @@ func (a *OpenTracingAppLayer) ActivateMfa(userID string, token string) *model.Ap
return resultVar0
}
func (a *OpenTracingAppLayer) ActiveSearchBackend() string {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.ActiveSearchBackend")
a.ctx = newCtx
a.app.Srv().Store().SetContext(newCtx)
defer func() {
a.app.Srv().Store().SetContext(origCtx)
a.ctx = origCtx
}()
defer span.Finish()
resultVar0 := a.app.ActiveSearchBackend()
return resultVar0
}
func (a *OpenTracingAppLayer) AddChannelMember(c request.CTX, userID string, channel *model.Channel, opts app.ChannelMemberOpts) (*model.ChannelMember, *model.AppError) {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.AddChannelMember")

View file

@ -60,3 +60,7 @@ func (a *App) PurgeBleveIndexes() *model.AppError {
}
return nil
}
func (a *App) ActiveSearchBackend() string {
return a.ch.srv.platform.SearchEngine.ActiveEngine()
}

View file

@ -7795,6 +7795,10 @@
"id": "ent.elasticsearch.indexer.index_batch.nothing_left_to_index.error",
"translation": "Trying to index a new batch when all the entities are completed"
},
{
"id": "ent.elasticsearch.max_version.app_error",
"translation": "Elasticsearch version {{.Version}} is higher than max supported version of {{.MaxVersion}}"
},
{
"id": "ent.elasticsearch.not_started.error",
"translation": "Elasticsearch is not started"
@ -7863,10 +7867,6 @@
"id": "ent.elasticsearch.search_users.unmarshall_user_failed",
"translation": "Failed to decode search results"
},
{
"id": "ent.elasticsearch.start.already_started.app_error",
"translation": "Elasticsearch is already started."
},
{
"id": "ent.elasticsearch.start.create_bulk_processor_failed.app_error",
"translation": "Failed to create Elasticsearch bulk processor."

View file

@ -45,8 +45,19 @@ func (seb *Broker) GetActiveEngines() []SearchEngineInterface {
if seb.ElasticsearchEngine != nil && seb.ElasticsearchEngine.IsActive() {
engines = append(engines, seb.ElasticsearchEngine)
}
if seb.BleveEngine != nil && seb.BleveEngine.IsActive() {
if seb.BleveEngine != nil && seb.BleveEngine.IsActive() && seb.BleveEngine.IsIndexingEnabled() {
engines = append(engines, seb.BleveEngine)
}
return engines
}
func (seb *Broker) ActiveEngine() string {
activeEngines := seb.GetActiveEngines()
if len(activeEngines) > 0 {
return activeEngines[0].GetName()
}
if *seb.cfg.SqlSettings.DisableDatabaseSearch {
return "none"
}
return "database"
}

View file

@ -0,0 +1,42 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package searchengine
import (
"testing"
"github.com/mattermost/mattermost-server/v6/model"
"github.com/mattermost/mattermost-server/v6/server/platform/services/searchengine/mocks"
"github.com/stretchr/testify/assert"
)
func TestActiveEngine(t *testing.T) {
cfg := &model.Config{}
cfg.SetDefaults()
b := NewBroker(cfg)
esMock := &mocks.SearchEngineInterface{}
esMock.On("IsActive").Return(true)
esMock.On("GetName").Return("elasticsearch")
bleveMock := &mocks.SearchEngineInterface{}
bleveMock.On("IsActive").Return(true)
bleveMock.On("IsIndexingEnabled").Return(true)
bleveMock.On("GetName").Return("bleve")
assert.Equal(t, "database", b.ActiveEngine())
b.ElasticsearchEngine = esMock
assert.Equal(t, "elasticsearch", b.ActiveEngine())
b.ElasticsearchEngine = nil
b.BleveEngine = bleveMock
assert.Equal(t, "bleve", b.ActiveEngine())
b.BleveEngine = nil
*b.cfg.SqlSettings.DisableDatabaseSearch = true
assert.Equal(t, "none", b.ActiveEngine())
}

View file

@ -353,6 +353,36 @@ exports[`components/DatabaseSettings should match snapshot 1`] = `
</div>
</div>
</div>
<div
className="form-group"
>
<label
className="control-label col-sm-4"
>
<MemoizedFormattedMessage
defaultMessage="Active Search Backend:"
id="admin.database.search_backend.title"
/>
</label>
<div
className="col-sm-8"
>
<input
className="form-control"
disabled={true}
type="text"
value=""
/>
<div
className="help-text"
>
<MemoizedFormattedMessage
defaultMessage="Shows the currently active backend used for search. Values can be none, database, elasticsearch, bleve etc."
id="admin.database.search_backend.help_text"
/>
</div>
</div>
</div>
</SettingsGroup>
<div
className="admin-console-save"

View file

@ -4,7 +4,7 @@
import React from 'react';
import {FormattedMessage} from 'react-intl';
import {recycleDatabaseConnection} from 'actions/admin_actions.jsx';
import {recycleDatabaseConnection, ping} from 'actions/admin_actions';
import * as Utils from 'utils/utils';
import {t} from 'utils/i18n';
@ -19,6 +19,15 @@ import TextSetting from './text_setting';
import MigrationsTable from './database';
export default class DatabaseSettings extends AdminSettings {
constructor(props) {
super(props);
this.state = {
...this.state,
searchBackend: '',
};
}
getConfigFromState = (config) => {
// driverName and dataSource are read-only from the UI
@ -34,6 +43,17 @@ export default class DatabaseSettings extends AdminSettings {
return config;
};
componentDidMount() {
this.getSearchBackend().then((searchBackend) => {
this.setState({searchBackend});
});
}
async getSearchBackend() {
const res = await ping()();
return res.ActiveSearchBackend;
}
getStateFromConfig(config) {
return {
driverName: config.SqlSettings.DriverName,
@ -368,6 +388,30 @@ export default class DatabaseSettings extends AdminSettings {
</div>
</div>
</div>
<div className='form-group'>
<label
className='control-label col-sm-4'
>
<FormattedMessage
id='admin.database.search_backend.title'
defaultMessage='Active Search Backend:'
/>
</label>
<div className='col-sm-8'>
<input
type='text'
className='form-control'
value={this.state.searchBackend}
disabled={true}
/>
<div className='help-text'>
<FormattedMessage
id='admin.database.search_backend.help_text'
defaultMessage='Shows the currently active backend used for search. Values can be none, database, elasticsearch, bleve etc.'
/>
</div>
</div>
</div>
</SettingsGroup>
);
};

View file

@ -7,8 +7,14 @@ import {shallow} from 'enzyme';
import DatabaseSettings from 'components/admin_console/database_settings.jsx';
jest.mock('actions/admin_actions.jsx', () => {
const pingFn = () => {
return jest.fn(() => {
return {ActiveSearchBackend: 'none'};
});
};
return {
recycleDatabaseConnection: jest.fn(),
ping: pingFn,
};
});

View file

@ -741,6 +741,8 @@
"admin.database.migrations_table.name": "Name",
"admin.database.migrations_table.title": "Applied Schema Migrations",
"admin.database.migrations_table.version": "Version",
"admin.database.search_backend.help_text": "Shows the currently active backend used for search. Values can be none, database, elasticsearch, bleve etc.",
"admin.database.search_backend.title": "Active Search Backend",
"admin.database.title": "Database",
"admin.developer.title": "Developer Settings",
"admin.elasticsearch.bulkIndexingTitle": "Bulk Indexing:",

View file

@ -2439,6 +2439,7 @@ export default class Client4 {
ping = () => {
return this.doFetch<{
status: string;
ActiveSearchBackend: string;
}>(
`${this.getBaseRoute()}/system/ping?time=${Date.now()}`,
{method: 'get'},