diff --git a/model/config.go b/model/config.go
index 3e98aa8f6c..7bf891462d 100644
--- a/model/config.go
+++ b/model/config.go
@@ -1662,8 +1662,6 @@ func (o *Config) Sanitize() {
o.SqlSettings.DataSourceSearchReplicas[i] = FAKE_SETTING
}
- *o.ElasticSearchSettings.ConnectionUrl = FAKE_SETTING
- *o.ElasticSearchSettings.Username = FAKE_SETTING
*o.ElasticSearchSettings.Password = FAKE_SETTING
}
diff --git a/utils/config.go b/utils/config.go
index f8ceccc2c8..478e3ba999 100644
--- a/utils/config.go
+++ b/utils/config.go
@@ -536,11 +536,6 @@ func getClientConfig(c *model.Config) map[string]string {
props["PasswordRequireSymbol"] = strconv.FormatBool(*c.PasswordSettings.Symbol)
}
- if *License.Features.Elasticsearch {
- props["ElasticSearchEnableIndexing"] = strconv.FormatBool(*c.ElasticSearchSettings.EnableIndexing)
- props["ElasticSearchEnableSearching"] = strconv.FormatBool(*c.ElasticSearchSettings.EnableSearching)
- }
-
if *License.Features.Announcement {
props["EnableBanner"] = strconv.FormatBool(*c.AnnouncementSettings.EnableBanner)
props["BannerText"] = *c.AnnouncementSettings.BannerText
@@ -616,12 +611,6 @@ func Desanitize(cfg *model.Config) {
cfg.SqlSettings.AtRestEncryptKey = Cfg.SqlSettings.AtRestEncryptKey
}
- if *cfg.ElasticSearchSettings.ConnectionUrl == model.FAKE_SETTING {
- *cfg.ElasticSearchSettings.ConnectionUrl = *Cfg.ElasticSearchSettings.ConnectionUrl
- }
- if *cfg.ElasticSearchSettings.Username == model.FAKE_SETTING {
- *cfg.ElasticSearchSettings.Username = *Cfg.ElasticSearchSettings.Username
- }
if *cfg.ElasticSearchSettings.Password == model.FAKE_SETTING {
*cfg.ElasticSearchSettings.Password = *Cfg.ElasticSearchSettings.Password
}
diff --git a/webapp/actions/admin_actions.jsx b/webapp/actions/admin_actions.jsx
index fdaeb87326..ac02ac058f 100644
--- a/webapp/actions/admin_actions.jsx
+++ b/webapp/actions/admin_actions.jsx
@@ -383,3 +383,16 @@ export function getPostsPerDayAnalytics(teamId) {
export function getUsersPerDayAnalytics(teamId) {
AdminActions.getUsersPerDayAnalytics(teamId)(dispatch, getState);
}
+
+export function elasticsearchTest(config, success, error) {
+ AdminActions.testElasticsearch(config)(dispatch, getState).then(
+ (data) => {
+ if (data && success) {
+ success(data);
+ } else if (data == null && error) {
+ const serverError = getState().requests.admin.testElasticsearch.error;
+ error({id: serverError.server_error_id, ...serverError});
+ }
+ }
+ );
+}
diff --git a/webapp/components/admin_console/admin_sidebar.jsx b/webapp/components/admin_console/admin_sidebar.jsx
index 1dbbff2f20..9b27ab81e1 100644
--- a/webapp/components/admin_console/admin_sidebar.jsx
+++ b/webapp/components/admin_console/admin_sidebar.jsx
@@ -258,6 +258,21 @@ export default class AdminSidebar extends React.Component {
/>
);
+ let elasticSearchSettings = null;
+ if (window.mm_license.IsLicensed === 'true') {
+ elasticSearchSettings = (
+
+ }
+ />
+ );
+ }
+
return (
@@ -618,6 +633,7 @@ export default class AdminSidebar extends React.Component {
/>
}
/>
+ {elasticSearchSettings}
{
+ this.setState({
+ configTested: true,
+ canSave: true
+ });
+ success();
+ },
+ (err) => {
+ this.setState({
+ configTested: false,
+ canSave: false
+ });
+ error(err);
+ }
+ );
+ }
+
+ renderTitle() {
+ return (
+
+ );
+ }
+
+ renderSettings() {
+ return (
+
+
+
+ }
+ helpText={
+
+
+
+ )
+ }}
+ />
+ }
+ value={this.state.enableIndexing}
+ onChange={this.handleChange}
+ />
+
+ }
+ placeholder={Utils.localizeMessage('admin.elasticsearch.connectionUrlExample', 'E.g.: "https://elasticsearch.example.org:9200"')}
+ helpText={
+
+
+
+ )
+ }}
+ />
+ }
+ value={this.state.connectionUrl}
+ disabled={!this.state.enableIndexing}
+ onChange={this.handleChange}
+ />
+
+ }
+ placeholder={Utils.localizeMessage('admin.elasticsearch.usernameExample', 'E.g.: "elastic"')}
+ helpText={
+
+ }
+ value={this.state.username}
+ disabled={!this.state.enableIndexing}
+ onChange={this.handleChange}
+ />
+
+ }
+ placeholder={Utils.localizeMessage('admin.elasticsearch.password', 'E.g.: "yourpassword"')}
+ helpText={
+
+ }
+ value={this.state.password}
+ disabled={!this.state.enableIndexing}
+ onChange={this.handleChange}
+ />
+
+ }
+ helpText={
+
+ }
+ value={this.state.sniff}
+ disabled={!this.state.enableIndexing}
+ onChange={this.handleChange}
+ />
+
+ }
+ buttonText={
+
+ }
+ disabled={!this.state.enableIndexing}
+ />
+
+ }
+ helpText={
+
+ }
+ value={this.state.enableSearching}
+ disabled={!this.state.enableIndexing || !this.state.configTested}
+ onChange={this.handleChange}
+ />
+
+ );
+ }
+}
diff --git a/webapp/i18n/en.json b/webapp/i18n/en.json
index c4c0951f4a..684fe73297 100755
--- a/webapp/i18n/en.json
+++ b/webapp/i18n/en.json
@@ -235,6 +235,27 @@
"admin.customization.support": "Legal and Support",
"admin.database.title": "Database Settings",
"admin.developer.title": "Developer Settings",
+ "admin.elasticsearch.title": "Elasticsearch Settings",
+ "admin.elasticsearch.noteDescription": "Changing properties in this section will require a server restart before taking effect.",
+ "admin.elasticsearch.enableIndexingTitle": "Enable Elasticsearch Indexing:",
+ "admin.elasticsearch.enableIndexingDescription": "When true, indexing of new posts occurs automatically. Search queries will use database search until \"Enable Elasticsearch for search queries\" is enabled. {documentationLink}",
+ "admin.elasticsearch.enableIndexingDescription.documentationLinkText": "Learn more about Elasticsearch in our documentation.",
+ "admin.elasticsearch.connectionUrlTitle": "Server Connection Address:",
+ "admin.elasticsearch.connectionUrlDescription": "The address of the Elasticsearch server. {documentationLink}",
+ "admin.elasticsearch.connectionUrlExample.documentationLinkText": "Please see documentation with server setup instructions.",
+ "admin.elasticsearch.usernameTitle": "Server Username:",
+ "admin.elasticsearch.usernameDescription": "(Optional) The username to authenticate to the Elasticsearch server.",
+ "admin.elasticsearch.passwordTitle": "Server Password:",
+ "admin.elasticsearch.passwordDescription": "(Optional) The password to authenticate to the Elasticsearch server.",
+ "admin.elasticsearch.sniffTitle": "Enable Cluster Sniffing:",
+ "admin.elasticsearch.sniffDescription": "When true, sniffing finds and connects to all data nodes in your cluster automatically.",
+ "admin.elasticsearch.enableSearchingTitle": "Enable Elasticsearch for search queries:",
+ "admin.elasticsearch.enableSearchingDescription": "Requires a successful connection to the Elasticsearch server. When true, Elasticsearch will be used for all search queries using the latest index. Search results may be incomplete until a bulk index of the existing post database is finished. When false, database search is used.",
+ "admin.elasticsearch.connectionUrlExample": "E.g.: \"https://elasticsearch.example.org:9200\"",
+ "admin.elasticsearch.usernameExample": "E.g.: \"elastic\"",
+ "admin.elasticsearch.password": "E.g.: \"yourpassword\"",
+ "admin.elasticsearch.testHelpText": "Tests if the Mattermost server can connect to the Elasticsearch server specified. Testing the connection does not save the configuration. See log file for more detailed error messages.",
+ "admin.elasticsearch.elasticsearch_test_button": "Test Connection",
"admin.email.agreeHPNS": " I understand and accept the Mattermost Hosted Push Notification Service Terms of Service and Privacy Policy.",
"admin.email.allowEmailSignInDescription": "When true, Mattermost allows users to sign in using their email and password.",
"admin.email.allowEmailSignInTitle": "Enable sign-in with email: ",
diff --git a/webapp/routes/route_admin_console.jsx b/webapp/routes/route_admin_console.jsx
index b0b6ebf628..17e0290c2e 100644
--- a/webapp/routes/route_admin_console.jsx
+++ b/webapp/routes/route_admin_console.jsx
@@ -45,6 +45,7 @@ import TeamAnalytics from 'components/analytics/team_analytics';
import LicenseSettings from 'components/admin_console/license_settings.jsx';
import Audits from 'components/admin_console/audits';
import Logs from 'components/admin_console/server_logs';
+import ElasticsearchSettings from 'components/admin_console/elasticsearch_settings.jsx';
export default (
@@ -199,6 +200,10 @@ export default (
path='database'
component={DatabaseSettings}
/>
+