first-commit
This commit is contained in:
94
modules/indexer/internal/elasticsearch/indexer.go
Normal file
94
modules/indexer/internal/elasticsearch/indexer.go
Normal file
@@ -0,0 +1,94 @@
|
||||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package elasticsearch
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"code.gitea.io/gitea/modules/indexer/internal"
|
||||
|
||||
"github.com/olivere/elastic/v7"
|
||||
)
|
||||
|
||||
var _ internal.Indexer = &Indexer{}
|
||||
|
||||
// Indexer represents a basic elasticsearch indexer implementation
|
||||
type Indexer struct {
|
||||
Client *elastic.Client
|
||||
|
||||
url string
|
||||
indexName string
|
||||
version int
|
||||
mapping string
|
||||
}
|
||||
|
||||
func NewIndexer(url, indexName string, version int, mapping string) *Indexer {
|
||||
return &Indexer{
|
||||
url: url,
|
||||
indexName: indexName,
|
||||
version: version,
|
||||
mapping: mapping,
|
||||
}
|
||||
}
|
||||
|
||||
// Init initializes the indexer
|
||||
func (i *Indexer) Init(ctx context.Context) (bool, error) {
|
||||
if i == nil {
|
||||
return false, errors.New("cannot init nil indexer")
|
||||
}
|
||||
if i.Client != nil {
|
||||
return false, errors.New("indexer is already initialized")
|
||||
}
|
||||
|
||||
client, err := i.initClient()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
i.Client = client
|
||||
|
||||
exists, err := i.Client.IndexExists(i.VersionedIndexName()).Do(ctx)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if exists {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
if err := i.createIndex(ctx); err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return exists, nil
|
||||
}
|
||||
|
||||
// Ping checks if the indexer is available
|
||||
func (i *Indexer) Ping(ctx context.Context) error {
|
||||
if i == nil {
|
||||
return errors.New("cannot ping nil indexer")
|
||||
}
|
||||
if i.Client == nil {
|
||||
return errors.New("indexer is not initialized")
|
||||
}
|
||||
|
||||
resp, err := i.Client.ClusterHealth().Do(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if resp.Status != "green" && resp.Status != "yellow" {
|
||||
// It's healthy if the status is green, and it's available if the status is yellow,
|
||||
// see https://www.elastic.co/guide/en/elasticsearch/reference/current/cluster-health.html
|
||||
return fmt.Errorf("status of elasticsearch cluster is %s", resp.Status)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Close closes the indexer
|
||||
func (i *Indexer) Close() {
|
||||
if i == nil {
|
||||
return
|
||||
}
|
||||
i.Client = nil
|
||||
}
|
68
modules/indexer/internal/elasticsearch/util.go
Normal file
68
modules/indexer/internal/elasticsearch/util.go
Normal file
@@ -0,0 +1,68 @@
|
||||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package elasticsearch
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
|
||||
"github.com/olivere/elastic/v7"
|
||||
)
|
||||
|
||||
// VersionedIndexName returns the full index name with version
|
||||
func (i *Indexer) VersionedIndexName() string {
|
||||
return versionedIndexName(i.indexName, i.version)
|
||||
}
|
||||
|
||||
func versionedIndexName(indexName string, version int) string {
|
||||
if version == 0 {
|
||||
// Old index name without version
|
||||
return indexName
|
||||
}
|
||||
return fmt.Sprintf("%s.v%d", indexName, version)
|
||||
}
|
||||
|
||||
func (i *Indexer) createIndex(ctx context.Context) error {
|
||||
createIndex, err := i.Client.CreateIndex(i.VersionedIndexName()).BodyString(i.mapping).Do(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !createIndex.Acknowledged {
|
||||
return fmt.Errorf("create index %s with %s failed", i.VersionedIndexName(), i.mapping)
|
||||
}
|
||||
|
||||
i.checkOldIndexes(ctx)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *Indexer) initClient() (*elastic.Client, error) {
|
||||
opts := []elastic.ClientOptionFunc{
|
||||
elastic.SetURL(i.url),
|
||||
elastic.SetSniff(false),
|
||||
elastic.SetHealthcheckInterval(10 * time.Second),
|
||||
elastic.SetGzip(false),
|
||||
}
|
||||
|
||||
logger := log.GetLogger(log.DEFAULT)
|
||||
|
||||
opts = append(opts, elastic.SetTraceLog(&log.PrintfLogger{Logf: logger.Trace}))
|
||||
opts = append(opts, elastic.SetInfoLog(&log.PrintfLogger{Logf: logger.Info}))
|
||||
opts = append(opts, elastic.SetErrorLog(&log.PrintfLogger{Logf: logger.Error}))
|
||||
|
||||
return elastic.NewClient(opts...)
|
||||
}
|
||||
|
||||
func (i *Indexer) checkOldIndexes(ctx context.Context) {
|
||||
for v := 0; v < i.version; v++ {
|
||||
indexName := versionedIndexName(i.indexName, v)
|
||||
exists, err := i.Client.IndexExists(indexName).Do(ctx)
|
||||
if err == nil && exists {
|
||||
log.Warn("Found older elasticsearch index named %q, Gitea will keep the old NOT DELETED. You can delete the old version after the upgrade succeed.", indexName)
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user