Support Elasticsearch v9 (for v10.11) (#35925)
* Support Elasticsearch v9 alongside v8 * Add CI workflow changes for Elasticsearch v8/v9 testing * Support Elasticsearch v7 in addition to v8/v9, add v7 CI test job Lowers the minimum supported ES version from 8 to 7 to avoid dropping v7 support in a dot release. Adds a dedicated CI job to verify v7 compatibility alongside the existing v8 and v9 (default) jobs. * Fix ES7 plugin install crash on cgroup v2 hosts * Fix ES 7 container startup on cgroup v2 Linux (GitHub Actions) ES 7 bundles JDK 11, which crashes with a NullPointerException in CgroupV2Subsystem.getMountPoint() on modern Linux kernels that use cgroup v2 (including GitHub Actions ubuntu-latest runners). The flag was already set during the Dockerfile RUN step, but not at runtime. Adding -XX:-UseContainerSupport to ES_JAVA_OPTS in docker-compose fixes the crash. The flag is harmless on ES 8/9 which ship JDK 17+ where the cgroup v2 bug is fixed (it simply opts out of container-aware JVM sizing). * Capture docker compose logs in CI test artifact * Use ES 7.17.29 for v7 CI test; remove cgroup v2 workarounds ES 7.17.0 bundled JDK 17.0.1 which had a cgroup v2 bug (CgroupV2Subsystem NPE) not fixable via -XX:-UseContainerSupport. ES 7.17.29 bundles JDK 22 where the bug is long fixed. Reverts the -XX:-UseContainerSupport workarounds added in the previous two commits as they were based on a wrong diagnosis and are no longer needed. --------- Co-authored-by: Mattermost Build <build@mattermost.com>
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
b65ae49523
Коммит
f6760151c4
109
server/enterprise/elasticsearch/elasticsearch/check_version_test.go
Обычный файл
109
server/enterprise/elasticsearch/elasticsearch/check_version_test.go
Обычный файл
@@ -0,0 +1,109 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.enterprise for license information.
|
||||
|
||||
package elasticsearch
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
elastic "github.com/elastic/go-elasticsearch/v8"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func newTestClient(t *testing.T, handler http.Handler) *elastic.TypedClient {
|
||||
t.Helper()
|
||||
ts := httptest.NewServer(handler)
|
||||
t.Cleanup(ts.Close)
|
||||
|
||||
client, err := elastic.NewTypedClient(elastic.Config{
|
||||
Addresses: []string{ts.URL},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
return client
|
||||
}
|
||||
|
||||
func infoHandler(version string) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Header().Set("X-Elastic-Product", "Elasticsearch")
|
||||
fmt.Fprintf(w, `{"cluster_name":"test","version":{"number":%q,"build_flavor":"default","build_hash":"abc","build_date":"2024-01-01","build_snapshot":false,"build_type":"docker","lucene_version":"9.0.0","minimum_wire_compatibility_version":"7.0.0","minimum_index_compatibility_version":"7.0.0"}}`, version)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCheckVersion(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
version string
|
||||
wantVersion string
|
||||
wantMajor int
|
||||
wantErrID string
|
||||
}{
|
||||
{
|
||||
name: "ES 8 is supported",
|
||||
version: "8.9.0",
|
||||
wantVersion: "8.9.0",
|
||||
wantMajor: 8,
|
||||
},
|
||||
{
|
||||
name: "ES 9 is supported",
|
||||
version: "9.0.0",
|
||||
wantVersion: "9.0.0",
|
||||
wantMajor: 9,
|
||||
},
|
||||
{
|
||||
name: "ES 7 is supported",
|
||||
version: "7.17.0",
|
||||
wantVersion: "7.17.0",
|
||||
wantMajor: 7,
|
||||
},
|
||||
{
|
||||
name: "ES 6 is too old",
|
||||
version: "6.8.0",
|
||||
wantErrID: "ent.elasticsearch.min_version.app_error",
|
||||
},
|
||||
{
|
||||
name: "ES 10 is too new",
|
||||
version: "10.0.0",
|
||||
wantErrID: "ent.elasticsearch.max_version.app_error",
|
||||
},
|
||||
{
|
||||
name: "invalid version string",
|
||||
version: "invalid",
|
||||
wantErrID: "ent.elasticsearch.start.parse_server_version.app_error",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
client := newTestClient(t, infoHandler(tc.version))
|
||||
version, major, appErr := checkVersion(client, nil)
|
||||
if tc.wantErrID != "" {
|
||||
require.NotNil(t, appErr)
|
||||
assert.Equal(t, tc.wantErrID, appErr.Id)
|
||||
} else {
|
||||
require.Nil(t, appErr)
|
||||
assert.Equal(t, tc.wantVersion, version)
|
||||
assert.Equal(t, tc.wantMajor, major)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCheckVersionConnectionError(t *testing.T) {
|
||||
ts := httptest.NewServer(http.NotFoundHandler())
|
||||
ts.Close() // close immediately to force connection error
|
||||
|
||||
client, err := elastic.NewTypedClient(elastic.Config{
|
||||
Addresses: []string{ts.URL},
|
||||
MaxRetries: 0,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
_, _, appErr := checkVersion(client, nil)
|
||||
require.NotNil(t, appErr)
|
||||
assert.Equal(t, "ent.elasticsearch.start.get_server_version.app_error", appErr.Id)
|
||||
}
|
||||
@@ -28,7 +28,8 @@ import (
|
||||
"github.com/elastic/go-elasticsearch/v8/typedapi/types/enums/sortorder"
|
||||
)
|
||||
|
||||
const elasticsearchMaxVersion = 8
|
||||
const elasticsearchMinVersion = 7
|
||||
const elasticsearchMaxVersion = 9
|
||||
|
||||
var (
|
||||
purgeIndexListAllowedIndexes = []string{common.IndexBaseChannels}
|
||||
@@ -106,7 +107,7 @@ func (es *ElasticsearchInterfaceImpl) Start() *model.AppError {
|
||||
return appErr
|
||||
}
|
||||
|
||||
version, major, appErr := checkMaxVersion(es.client, es.Platform.Config())
|
||||
version, major, appErr := checkVersion(es.client, es.Platform.Config())
|
||||
if appErr != nil {
|
||||
return appErr
|
||||
}
|
||||
@@ -1245,7 +1246,7 @@ func (es *ElasticsearchInterfaceImpl) TestConfig(rctx request.CTX, cfg *model.Co
|
||||
return appErr
|
||||
}
|
||||
|
||||
_, _, appErr = checkMaxVersion(client, cfg)
|
||||
_, _, appErr = checkVersion(client, cfg)
|
||||
if appErr != nil {
|
||||
return appErr
|
||||
}
|
||||
@@ -1830,19 +1831,22 @@ func (es *ElasticsearchInterfaceImpl) DeleteFilesBatch(rctx request.CTX, endTime
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkMaxVersion(client *elastic.TypedClient, cfg *model.Config) (string, int, *model.AppError) {
|
||||
func checkVersion(client *elastic.TypedClient, cfg *model.Config) (string, int, *model.AppError) {
|
||||
resp, err := client.API.Core.Info().Do(context.Background())
|
||||
if err != nil {
|
||||
return "", 0, model.NewAppError("Elasticsearch.checkMaxVersion", "ent.elasticsearch.start.get_server_version.app_error", map[string]any{"Backend": model.ElasticsearchSettingsESBackend}, "", http.StatusInternalServerError).Wrap(err)
|
||||
return "", 0, model.NewAppError("Elasticsearch.checkVersion", "ent.elasticsearch.start.get_server_version.app_error", map[string]any{"Backend": model.ElasticsearchSettingsESBackend}, "", http.StatusInternalServerError).Wrap(err)
|
||||
}
|
||||
|
||||
major, _, _, esErr := common.GetVersionComponents(resp.Version.Int)
|
||||
if esErr != nil {
|
||||
return "", 0, model.NewAppError("Elasticsearch.checkMaxVersion", "ent.elasticsearch.start.parse_server_version.app_error", map[string]any{"Backend": model.ElasticsearchSettingsESBackend}, "", http.StatusInternalServerError).Wrap(err)
|
||||
return "", 0, model.NewAppError("Elasticsearch.checkVersion", "ent.elasticsearch.start.parse_server_version.app_error", map[string]any{"Backend": model.ElasticsearchSettingsESBackend}, "", http.StatusInternalServerError).Wrap(esErr)
|
||||
}
|
||||
|
||||
if major < elasticsearchMinVersion {
|
||||
return "", 0, model.NewAppError("Elasticsearch.checkVersion", "ent.elasticsearch.min_version.app_error", map[string]any{"Version": major, "MinVersion": elasticsearchMinVersion, "Backend": model.ElasticsearchSettingsESBackend}, "", http.StatusBadRequest)
|
||||
}
|
||||
if major > elasticsearchMaxVersion {
|
||||
return "", 0, model.NewAppError("Elasticsearch.checkMaxVersion", "ent.elasticsearch.max_version.app_error", map[string]any{"Version": major, "MaxVersion": elasticsearchMaxVersion, "Backend": model.ElasticsearchSettingsESBackend}, "", http.StatusBadRequest)
|
||||
return "", 0, model.NewAppError("Elasticsearch.checkVersion", "ent.elasticsearch.max_version.app_error", map[string]any{"Version": major, "MaxVersion": elasticsearchMaxVersion, "Backend": model.ElasticsearchSettingsESBackend}, "", http.StatusBadRequest)
|
||||
}
|
||||
return resp.Version.Int, major, nil
|
||||
}
|
||||
|
||||
Ссылка в новой задаче
Block a user