218 lines
5.9 KiB
Go
218 lines
5.9 KiB
Go
// Package index provides index-level operations for OpenSearch.
|
|
package index
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
|
|
"es-demo/client"
|
|
|
|
"github.com/opensearch-project/opensearch-go/v2/opensearchapi"
|
|
)
|
|
|
|
var (
|
|
// ErrInvalidTemplate is returned when the template configuration is invalid.
|
|
ErrInvalidTemplate = errors.New("invalid template configuration")
|
|
|
|
// ErrTemplateNotFound is returned when the specified template does not exist.
|
|
ErrTemplateNotFound = errors.New("template not found")
|
|
)
|
|
|
|
// Template represents an OpenSearch index template.
|
|
type Template struct {
|
|
// IndexPatterns defines the index patterns this template applies to.
|
|
IndexPatterns []string `json:"index_patterns"`
|
|
|
|
// Settings contains index settings like number of shards and replicas.
|
|
Settings map[string]any `json:"settings,omitempty"`
|
|
|
|
// Mappings defines the field mappings for the index.
|
|
Mappings map[string]any `json:"mappings,omitempty"`
|
|
|
|
// Aliases defines index aliases.
|
|
Aliases map[string]any `json:"aliases,omitempty"`
|
|
|
|
// Priority determines template precedence when multiple templates match.
|
|
Priority int `json:"priority,omitempty"`
|
|
|
|
// Version is used for external version management.
|
|
Version int `json:"version,omitempty"`
|
|
}
|
|
|
|
// TemplateResponse represents the response when getting a template.
|
|
type TemplateResponse struct {
|
|
IndexTemplates []struct {
|
|
Name string `json:"name"`
|
|
IndexTemplate Template `json:"index_template"`
|
|
} `json:"index_templates"`
|
|
}
|
|
|
|
// PutTemplate creates or updates an index template.
|
|
func PutTemplate(ctx context.Context, c *client.Client, name string, template *Template) error {
|
|
if err := validateTemplate(template); err != nil {
|
|
return err
|
|
}
|
|
|
|
if name == "" {
|
|
return fmt.Errorf("%w: template name is required", ErrInvalidTemplate)
|
|
}
|
|
|
|
body, err := json.Marshal(template)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to marshal template: %w", err)
|
|
}
|
|
|
|
req := opensearchapi.IndicesPutIndexTemplateRequest{
|
|
Name: name,
|
|
Body: bytes.NewReader(body),
|
|
}
|
|
|
|
res, err := req.Do(ctx, c.GetClient())
|
|
if err != nil {
|
|
return fmt.Errorf("failed to execute put template request: %w", err)
|
|
}
|
|
defer func() {
|
|
if closeErr := res.Body.Close(); closeErr != nil {
|
|
fmt.Fprintf(os.Stderr, "warning: failed to close response body: %v\n", closeErr)
|
|
}
|
|
}()
|
|
|
|
if res.IsError() {
|
|
bodyBytes, _ := io.ReadAll(res.Body)
|
|
return fmt.Errorf("put template failed with status %s: %s", res.Status(), string(bodyBytes))
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// GetTemplate retrieves an index template by name.
|
|
func GetTemplate(ctx context.Context, c *client.Client, name string) (*Template, error) {
|
|
if name == "" {
|
|
return nil, fmt.Errorf("%w: template name is required", ErrInvalidTemplate)
|
|
}
|
|
|
|
req := opensearchapi.IndicesGetIndexTemplateRequest{
|
|
Name: []string{name},
|
|
}
|
|
|
|
res, err := req.Do(ctx, c.GetClient())
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to execute get template request: %w", err)
|
|
}
|
|
defer func() {
|
|
if closeErr := res.Body.Close(); closeErr != nil {
|
|
fmt.Fprintf(os.Stderr, "warning: failed to close response body: %v\n", closeErr)
|
|
}
|
|
}()
|
|
|
|
if res.IsError() {
|
|
if res.StatusCode == 404 {
|
|
return nil, ErrTemplateNotFound
|
|
}
|
|
bodyBytes, _ := io.ReadAll(res.Body)
|
|
return nil, fmt.Errorf("get template failed with status %s: %s", res.Status(), string(bodyBytes))
|
|
}
|
|
|
|
var response TemplateResponse
|
|
if err := json.NewDecoder(res.Body).Decode(&response); err != nil {
|
|
return nil, fmt.Errorf("failed to decode template response: %w", err)
|
|
}
|
|
|
|
if len(response.IndexTemplates) == 0 {
|
|
return nil, ErrTemplateNotFound
|
|
}
|
|
|
|
return &response.IndexTemplates[0].IndexTemplate, nil
|
|
}
|
|
|
|
// DeleteTemplate deletes an index template.
|
|
func DeleteTemplate(ctx context.Context, c *client.Client, name string) error {
|
|
if name == "" {
|
|
return fmt.Errorf("%w: template name is required", ErrInvalidTemplate)
|
|
}
|
|
|
|
req := opensearchapi.IndicesDeleteIndexTemplateRequest{
|
|
Name: name,
|
|
}
|
|
|
|
res, err := req.Do(ctx, c.GetClient())
|
|
if err != nil {
|
|
return fmt.Errorf("failed to execute delete template request: %w", err)
|
|
}
|
|
defer func() {
|
|
if closeErr := res.Body.Close(); closeErr != nil {
|
|
fmt.Fprintf(os.Stderr, "warning: failed to close response body: %v\n", closeErr)
|
|
}
|
|
}()
|
|
|
|
if res.IsError() {
|
|
if res.StatusCode == 404 {
|
|
return ErrTemplateNotFound
|
|
}
|
|
bodyBytes, _ := io.ReadAll(res.Body)
|
|
return fmt.Errorf("delete template failed with status %s: %s", res.Status(), string(bodyBytes))
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// ListTemplates retrieves all index templates or templates matching a pattern.
|
|
func ListTemplates(ctx context.Context, c *client.Client, names ...string) (map[string]*Template, error) {
|
|
var nameList []string
|
|
if len(names) > 0 {
|
|
nameList = names
|
|
}
|
|
|
|
req := opensearchapi.IndicesGetIndexTemplateRequest{
|
|
Name: nameList,
|
|
}
|
|
|
|
res, err := req.Do(ctx, c.GetClient())
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to execute list templates request: %w", err)
|
|
}
|
|
defer func() {
|
|
if closeErr := res.Body.Close(); closeErr != nil {
|
|
fmt.Fprintf(os.Stderr, "warning: failed to close response body: %v\n", closeErr)
|
|
}
|
|
}()
|
|
|
|
if res.IsError() {
|
|
if res.StatusCode == 404 {
|
|
return make(map[string]*Template), nil
|
|
}
|
|
bodyBytes, _ := io.ReadAll(res.Body)
|
|
return nil, fmt.Errorf("list templates failed with status %s: %s", res.Status(), string(bodyBytes))
|
|
}
|
|
|
|
var response TemplateResponse
|
|
if err := json.NewDecoder(res.Body).Decode(&response); err != nil {
|
|
return nil, fmt.Errorf("failed to decode templates response: %w", err)
|
|
}
|
|
|
|
templates := make(map[string]*Template)
|
|
for _, item := range response.IndexTemplates {
|
|
templates[item.Name] = &item.IndexTemplate
|
|
}
|
|
|
|
return templates, nil
|
|
}
|
|
|
|
// validateTemplate validates the template configuration.
|
|
func validateTemplate(template *Template) error {
|
|
if template == nil {
|
|
return fmt.Errorf("%w: template cannot be nil", ErrInvalidTemplate)
|
|
}
|
|
|
|
if len(template.IndexPatterns) == 0 {
|
|
return fmt.Errorf("%w: index patterns are required", ErrInvalidTemplate)
|
|
}
|
|
|
|
return nil
|
|
}
|