diff --git a/services/search/pkg/bleve/index.go b/services/search/pkg/bleve/index.go index 11927288b2..817ae09ca4 100644 --- a/services/search/pkg/bleve/index.go +++ b/services/search/pkg/bleve/index.go @@ -63,7 +63,7 @@ func NewIndex(root string) (bleve.Index, searchmapping.Classification, error) { switch classification.Verdict { case searchmapping.VerdictBreaking: _ = index.Close() - return nil, classification, searchmapping.ManualActionRequiredError(destination, classification.Reasons) + return nil, classification, searchmapping.ManualActionRequiredError(destination, "delete the index directory "+destination, classification.Reasons) case searchmapping.VerdictAdditive: // The classifier guarantees everything else is identical and the new // fields hold no data yet, so storing the code mapping only adds diff --git a/services/search/pkg/mapping/classify.go b/services/search/pkg/mapping/classify.go index f87d30282e..dfaac5ebdc 100644 --- a/services/search/pkg/mapping/classify.go +++ b/services/search/pkg/mapping/classify.go @@ -15,18 +15,20 @@ var ErrManualActionRequired = errors.New("manual action required") // ManualActionRequiredError builds the operator-facing error for a breaking // schema change, shared by both engines. index is the index name (OpenSearch) -// or path (bleve). -func ManualActionRequiredError(index string, reasons []string) error { +// or path (bleve); deleteStep is the engine-specific instruction to remove the +// index, e.g. "delete the index (DELETE /name)" or "delete the index +// directory /path". +func ManualActionRequiredError(index, deleteStep string, reasons []string) error { return fmt.Errorf( "%w: search index %s was built with a different schema (%s). "+ - "There is no in-place migration: stop the service, delete %s, "+ + "There is no in-place migration: stop the service, %s, "+ "start the service (an empty index with the new schema is created), "+ "then rebuild the content by running: opencloud search index --all-spaces. "+ "To bring the instance up without search until a maintenance window, "+ "set OC_EXCLUDE_RUN_SERVICES=search; until the service is back, search "+ "and features built on it (e.g. the search bar and the tag list) are "+ "unavailable", - ErrManualActionRequired, index, strings.Join(reasons, "; "), index, + ErrManualActionRequired, index, strings.Join(reasons, "; "), deleteStep, ) } diff --git a/services/search/pkg/opensearch/index.go b/services/search/pkg/opensearch/index.go index e9591202b1..1efffad670 100644 --- a/services/search/pkg/opensearch/index.go +++ b/services/search/pkg/opensearch/index.go @@ -166,7 +166,7 @@ func (m IndexManager) Apply(ctx context.Context, name string, client *opensearch ) reasons = append(reasons, classification.Reasons...) if len(reasons) > 0 { - return searchmapping.ManualActionRequiredError(name, reasons) + return searchmapping.ManualActionRequiredError(name, fmt.Sprintf("delete the index (DELETE /%s)", name), reasons) } if len(classification.NewFields) == 0 { return nil // schema is up to date @@ -183,14 +183,14 @@ func (m IndexManager) Apply(ctx context.Context, name string, client *opensearch case err != nil && errors.As(err, &putErr) && putErr.Err.Type == "illegal_argument_exception" && (strings.Contains(putErr.Err.Reason, "cannot be changed") || strings.Contains(putErr.Err.Reason, "Cannot update parameter")): // backstop, should be unreachable after the classification above - return searchmapping.ManualActionRequiredError(name, []string{putErr.Err.Reason}) + return searchmapping.ManualActionRequiredError(name, fmt.Sprintf("delete the index (DELETE /%s)", name), []string{putErr.Err.Reason}) case err != nil: return fmt.Errorf("failed to update mapping of index %s: %w", name, err) case !putResp.Acknowledged: return fmt.Errorf("failed to update mapping of index %s: not acknowledged", name) } - logger.Info().Strs("fields", classification.NewFields).Str("index", name).Msg("extended the search index mapping with new fields") + logger.Warn().Strs("fields", classification.NewFields).Str("index", name).Msg("extended the search index mapping with new fields; documents indexed before the upgrade do not contain them and queries on these fields will miss those documents until they are re-indexed; to re-index everything run: opencloud search index --all-spaces") return nil }