Add OpenSearch 2.x/3.x support with transparent API compatibility#44
Merged
Add OpenSearch 2.x/3.x support with transparent API compatibility#44
Conversation
61ed356 to
4431bb8
Compare
This update enables Ductile to work seamlessly with both Elasticsearch 7.x and OpenSearch 2.x/3.x without requiring code changes in applications. Key Features: - Engine parameter: Add :engine option to connection (defaults to :elasticsearch) - Feature detection: Runtime capability checking (ILM, ISM, data streams) - Policy transformation: Automatic ILM→ISM conversion for OpenSearch - Response normalization: OpenSearch responses match Elasticsearch format - Multi-engine testing: Test infrastructure supports all engines Changes: - Add src/ductile/capabilities.clj for engine detection - Add src/ductile/features.clj for feature compatibility - Add src/ductile/lifecycle.clj for ILM/ISM transformation - Update src/ductile/index.clj with policy normalization - Update src/ductile/conn.clj to handle engine parameter - Update src/ductile/schemas.clj with engine schema - Add OpenSearch 2.19.0 and 3.1.0 Docker containers - Update GitHub Actions for multi-engine testing - Update README.md with OpenSearch examples - Bump version to 0.6.0-SNAPSHOT Testing: - 18 test suites, 379 assertions passing - All core APIs working: policies, data streams, indices, documents - Tested against ES 7.10.1, OpenSearch 2.19.0, OpenSearch 3.1.0 Breaking Changes: None - 100% backward compatible 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
4431bb8 to
dcbe0ea
Compare
… indices - Fix data-stream-test arity exception by wrapping cleanup in anonymous function - Fix fetch-test to use subset check instead of equality to handle OpenSearch internal indices
…cycle namespace ## Changes ### 1. Simplify EngineInfo schema (capabilities.clj) - Remove unused :distribution and :build-flavor fields from EngineInfo - Update detect-engine to only return :engine and :version - These fields were extracted but never consumed by any code - Aligns with goal of hiding engine-specific details from applications ### 2. Move policy API to lifecycle namespace - Move policy-uri, create-policy!, delete-policy!, get-policy from ductile.index to ductile.lifecycle - Better cohesion: lifecycle.clj now contains all policy logic (schemas, transformations, HTTP operations) - Clearer separation: index.clj focuses on index operations only - Update all tests and documentation to use ductile.lifecycle ### 3. Documentation improvements - Add comment explaining supports-legacy-templates? is a placeholder for future deprecation handling - Update README.md with new API usage ## Testing - All tests pass: 54 tests, 244 assertions, 0 failures, 0 errors - No breaking changes to functionality, only namespace reorganization 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
575d7f0 to
2fec090
Compare
gbuisson
approved these changes
Dec 4, 2025
Contributor
gbuisson
left a comment
There was a problem hiding this comment.
you forgot to commit these 2 files:
OPENSEARCH_MIGRATION.md - Step-by-step migration guide (716 lines)
IMPLEMENTATION_SUMMARY.md - Technical overview and architecture (496 lines)
src/ductile/lifecycle.clj
Outdated
| ;; Unsupported actions are logged but not transformed | ||
| (do | ||
| (when-not (#{:set_priority :allocate :migrate} action-name) | ||
| (println (str "Warning: Unsupported ILM action: " action-name))) |
Contributor
There was a problem hiding this comment.
Should use clojure.tools.logging/warn instead of println for consistency with the
rest of the codebase.
| (let [feature-checks {:ilm supports-ilm? | ||
| :ism supports-ism? | ||
| :data-streams supports-data-streams? | ||
| :composable-templates supports-composable-templates? |
Contributor
There was a problem hiding this comment.
you should add :legacy-templates for consistency
src/ductile/capabilities.clj
Outdated
| [version-str] | ||
| (when version-str | ||
| (let [parts (str/split version-str #"\.") | ||
| [major minor patch] (map #(Integer/parseInt %) parts)] |
Contributor
There was a problem hiding this comment.
consider wapping in a try/catch in order to avoid a potential npe.
- Use log/warn instead of println for unsupported ILM actions (lifecycle.clj) - Add :legacy-templates to require-feature! checks for consistency (features.clj) - Wrap Integer/parseInt in try/catch to handle malformed versions (capabilities.clj) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
- OPENSEARCH_MIGRATION.md: Step-by-step migration guide with examples - IMPLEMENTATION_SUMMARY.md: Technical architecture and design overview 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR adds full OpenSearch 2.x and 3.x support to Ductile with transparent API compatibility. Applications can migrate from Elasticsearch to OpenSearch by simply changing a single connection parameter - no code changes required.
Key Changes
:engineparameter to connection (defaults to:elasticsearchfor backward compatibility)Implementation Details
New Modules:
src/ductile/capabilities.clj- Engine detection and version comparison (123 lines)src/ductile/features.clj- Feature compatibility checks (154 lines)src/ductile/lifecycle.clj- ILM/ISM policy transformation (252 lines)Modified Modules:
src/ductile/conn.clj- Handle engine parametersrc/ductile/schemas.clj- Add engine to connection schemasrc/ductile/index.clj- Policy operations with response normalizationTesting:
Documentation:
README.md- Completely rewritten with OpenSearch examples (526 lines)OPENSEARCH_MIGRATION.md- Step-by-step migration guide (716 lines)IMPLEMENTATION_SUMMARY.md- Technical overview and architecture (496 lines)Breaking Changes
None! This is 100% backward compatible:
:engineparameter, defaults to:elasticsearchExample Usage
Test Plan
Local Testing:
lein test(379 assertions, 18 test suites)Manual Testing:
Files Changed
Known Limitations
_templateAPI has some issues with OpenSearch (deprecated API, non-critical)_index_templateAPI works perfectly for all enginesNext Steps
0.6.0:engine :opensearch🤖 Generated with Claude Code