Files
es-demo/operations/index/policy.go
mouseleee fc14798af5 feat: 增加ism管理接口
test: 索引模板和ism的单元测试和集成测试
2025-11-16 23:00:31 +08:00

150 lines
4.6 KiB
Go

// Package index provides index-level operations for OpenSearch.
package index
import (
"context"
"encoding/json"
"errors"
)
var (
// ErrInvalidPolicy is returned when the policy configuration is invalid.
ErrInvalidPolicy = errors.New("invalid policy configuration")
)
// PolicyManager defines the interface for managing index lifecycle policies.
// This interface abstracts both AWS OpenSearch ISM (Index State Management)
// and Elasticsearch ILM (Index Lifecycle Management) to provide a unified API.
type PolicyManager interface {
// PutPolicy creates or updates a lifecycle policy.
PutPolicy(ctx context.Context, name string, policy *Policy) error
// GetPolicy retrieves a lifecycle policy by name.
GetPolicy(ctx context.Context, name string) (*Policy, error)
// DeletePolicy deletes a lifecycle policy by name.
DeletePolicy(ctx context.Context, name string) error
// ListPolicies retrieves all lifecycle policies.
ListPolicies(ctx context.Context) (map[string]*Policy, error)
}
// Policy represents a generic index lifecycle policy.
// It can be converted to ISM (AWS OpenSearch) or ILM (Elasticsearch) format.
type Policy struct {
// Description of the policy
Description string `json:"description,omitempty"`
// DefaultState is the initial state (ISM specific)
DefaultState string `json:"default_state,omitempty"`
// States defines the lifecycle states (ISM format)
States []State `json:"states,omitempty"`
// Phases defines the lifecycle phases (ILM format)
// This field is used when targeting Elasticsearch
Phases map[string]Phase `json:"phases,omitempty"`
// ISMTemplate for applying policy to indices (ISM specific)
ISMTemplate []ISMTemplate `json:"ism_template,omitempty"`
}
// State represents a state in ISM (AWS OpenSearch).
type State struct {
Name string `json:"name"`
Actions []Action `json:"actions,omitempty"`
Transitions []Transition `json:"transitions,omitempty"`
}
// Action represents an action within a state.
// In ISM, actions are serialized as a single key-value object where
// the key is the action type and the value is the configuration.
type Action struct {
// Config contains the action type as the key and its configuration as the value
// Example: {"rollover": {"min_index_age": "1d"}}
Config map[string]interface{}
}
// NewAction creates a new action with the specified type and configuration.
func NewAction(actionType string, config map[string]interface{}) Action {
return Action{
Config: map[string]interface{}{
actionType: config,
},
}
}
// MarshalJSON implements custom JSON marshaling for Action.
// It directly marshals the Config map instead of wrapping it in a "Config" field.
func (a Action) MarshalJSON() ([]byte, error) {
return json.Marshal(a.Config)
}
// UnmarshalJSON implements custom JSON unmarshaling for Action.
func (a *Action) UnmarshalJSON(data []byte) error {
return json.Unmarshal(data, &a.Config)
}
// Transition defines when to move to the next state.
type Transition struct {
StateName string `json:"state_name"`
Conditions *Conditions `json:"conditions,omitempty"`
}
// Conditions defines the conditions for state transitions.
type Conditions struct {
MinIndexAge string `json:"min_index_age,omitempty"`
MinDocCount *int64 `json:"min_doc_count,omitempty"`
MinSize string `json:"min_size,omitempty"`
}
// Phase represents a phase in ILM (Elasticsearch).
// This is for future Elasticsearch compatibility.
type Phase struct {
MinAge string `json:"min_age,omitempty"`
Actions map[string]interface{} `json:"actions,omitempty"`
}
// ISMTemplate defines index patterns for automatic policy application.
type ISMTemplate struct {
IndexPatterns []string `json:"index_patterns"`
Priority int `json:"priority"`
}
// Validate checks if the policy configuration is valid.
func (p *Policy) Validate() error {
if p == nil {
return ErrInvalidPolicy
}
// For ISM: must have at least one state with a default_state
if len(p.States) > 0 {
if p.DefaultState == "" {
return errors.New("default_state is required when states are defined")
}
// Verify default_state exists in states
found := false
for _, state := range p.States {
if state.Name == p.DefaultState {
found = true
break
}
}
if !found {
return errors.New("default_state must match one of the defined states")
}
}
// For ILM: must have at least one phase
if len(p.Phases) > 0 && len(p.States) > 0 {
return errors.New("cannot define both ISM states and ILM phases in the same policy")
}
if len(p.States) == 0 && len(p.Phases) == 0 {
return errors.New("policy must define either states (ISM) or phases (ILM)")
}
return nil
}