242 lines
11 KiB
Markdown
242 lines
11 KiB
Markdown
# OpenSearch Service
|
||
|
||
**Protocol:** REST JSON
|
||
**Endpoint:** `http://localhost:4566/2021-01-01/...`
|
||
**Credential scope:** `es`
|
||
|
||
## Implementation Modes
|
||
|
||
OpenSearch supports two modes controlled by `FLOCI_SERVICES_OPENSEARCH_MOCK`.
|
||
|
||
### Mock mode (`mock: true`)
|
||
|
||
Domain metadata is stored in-process. No Docker containers are started. Domains appear `Created: true` and `Processing: false` immediately. Use this in CI or whenever you only need the management API shape, not a real search cluster.
|
||
|
||
### Real mode (`mock: false`, default)
|
||
|
||
Floci starts an **OpenSearch** Docker container per domain, choosing the image based on the requested `EngineVersion` (e.g. `OpenSearch_3.6` → `opensearchproject/opensearch:3.6.0`, `Elasticsearch_7.10` → `docker.elastic.co/elasticsearch/elasticsearch-oss:7.10.2`). The container is exposed on a host port from the configured range (`9400–9499`). Once `/_cluster/health` returns `green` or `yellow`, the domain transitions to `Created: true` and the `Endpoint` field is populated with the container's address.
|
||
|
||
OpenSearch 2.12+ requires an initial admin password even when the security plugin is disabled; Floci sets `OPENSEARCH_INITIAL_ADMIN_PASSWORD=FlociAdmin1!` automatically for those versions. The security plugin itself stays disabled.
|
||
|
||
!!! note "Docker socket required"
|
||
Real mode starts Docker containers. Mount the Docker socket and set the Docker network so containers can reach each other. For private registry authentication and other Docker settings see [Docker Configuration](../configuration/docker.md).
|
||
|
||
```yaml
|
||
services:
|
||
floci:
|
||
image: floci/floci:latest
|
||
volumes:
|
||
- /var/run/docker.sock:/var/run/docker.sock
|
||
ports:
|
||
- "4566:4566"
|
||
environment:
|
||
FLOCI_SERVICES_DOCKER_NETWORK: my_project_default
|
||
```
|
||
|
||
## Supported Operations
|
||
|
||
### Domain Lifecycle
|
||
|
||
| Operation | Method + Path | Description |
|
||
|---|---|---|
|
||
| `CreateDomain` | `POST /2021-01-01/opensearch/domain` | Create a new domain |
|
||
| `DescribeDomain` | `GET /2021-01-01/opensearch/domain/{name}` | Get domain details |
|
||
| `DescribeDomains` | `POST /2021-01-01/opensearch/domain-info` | Batch describe domains |
|
||
| `DescribeDomainConfig` | `GET /2021-01-01/opensearch/domain/{name}/config` | Get domain configuration |
|
||
| `UpdateDomainConfig` | `POST /2021-01-01/opensearch/domain/{name}/config` | Update cluster config, EBS options, engine version, access policies |
|
||
| `DeleteDomain` | `DELETE /2021-01-01/opensearch/domain/{name}` | Delete a domain |
|
||
| `ListDomainNames` | `GET /2021-01-01/domain` | List all domains (supports `?engineType=` filter) |
|
||
|
||
### Tags
|
||
|
||
| Operation | Method + Path | Description |
|
||
|---|---|---|
|
||
| `AddTags` | `POST /2021-01-01/tags` | Add tags to a domain by ARN |
|
||
| `ListTags` | `GET /2021-01-01/tags/?arn=` | List tags for a domain |
|
||
| `RemoveTags` | `POST /2021-01-01/tags-removal` | Remove tag keys from a domain |
|
||
|
||
### Versions & Instance Types
|
||
|
||
| Operation | Method + Path | Description |
|
||
|---|---|---|
|
||
| `ListVersions` | `GET /2021-01-01/opensearch/versions` | List supported engine versions |
|
||
| `GetCompatibleVersions` | `GET /2021-01-01/opensearch/compatibleVersions` | List valid upgrade paths |
|
||
| `ListInstanceTypeDetails` | `GET /2021-01-01/opensearch/instanceTypeDetails/{version}` | List available instance types |
|
||
| `DescribeInstanceTypeLimits` | `GET /2021-01-01/opensearch/instanceTypeLimits/{version}/{type}` | Get limits for an instance type |
|
||
|
||
### Stubs (SDK-compatible, no-op responses)
|
||
|
||
| Operation | Notes |
|
||
|---|---|
|
||
| `DescribeDomainChangeProgress` | Returns empty `ChangeProgressStatus` |
|
||
| `DescribeDomainAutoTunes` | Returns empty `AutoTunes` list |
|
||
| `DescribeDryRunProgress` | Returns empty `DryRunProgressStatus` |
|
||
| `DescribeDomainHealth` | Returns `ClusterHealth: Green` |
|
||
| `GetUpgradeHistory` | Returns empty list |
|
||
| `GetUpgradeStatus` | Returns `StepStatus: SUCCEEDED` |
|
||
| `UpgradeDomain` | Stores new engine version, returns immediately with a generated `UpgradeId` |
|
||
| `CancelDomainConfigChange` | Returns empty `CancelledChangeIds` |
|
||
| `StartServiceSoftwareUpdate` | Returns no-op `ServiceSoftwareOptions` |
|
||
| `CancelServiceSoftwareUpdate` | Returns no-op `ServiceSoftwareOptions` |
|
||
|
||
## Configuration
|
||
|
||
| Variable | Default | Description |
|
||
|---|---|---|
|
||
| `FLOCI_SERVICES_OPENSEARCH_ENABLED` | `true` | Enable/disable the service |
|
||
| `FLOCI_SERVICES_OPENSEARCH_MOCK` | `false` | `true` = metadata only (no Docker) |
|
||
| `FLOCI_SERVICES_OPENSEARCH_DEFAULT_IMAGE` | *(unset)* | Optional fixed image used for every domain regardless of `EngineVersion`. Useful for private registry mirrors. When unset, images resolve per-version from the built-in version map. |
|
||
| `FLOCI_SERVICES_OPENSEARCH_PROXY_BASE_PORT` | `9400` | Port range start for real mode |
|
||
| `FLOCI_SERVICES_OPENSEARCH_PROXY_MAX_PORT` | `9499` | Port range end for real mode |
|
||
| `FLOCI_SERVICES_OPENSEARCH_KEEP_RUNNING_ON_SHUTDOWN` | `false` | Leave containers running after Floci stops |
|
||
| `FLOCI_SERVICES_DOCKER_NETWORK` | *(unset)* | Shared Docker network for all container-based services including OpenSearch |
|
||
| `FLOCI_STORAGE_SERVICES_OPENSEARCH_FLUSH_INTERVAL_MS` | `5000` | Flush interval (ms) |
|
||
|
||
### Mock mode (CI / tests)
|
||
|
||
Use `FLOCI_SERVICES_OPENSEARCH_MOCK=true` when you only need the API shape:
|
||
|
||
```yaml
|
||
# docker-compose.yml — CI / test environment
|
||
services:
|
||
floci:
|
||
image: floci/floci:latest
|
||
environment:
|
||
FLOCI_SERVICES_OPENSEARCH_MOCK: "true"
|
||
```
|
||
|
||
## Emulation Behaviour
|
||
|
||
- **Domain name validation:** 3–28 characters, must start with a lowercase letter, only lowercase letters, digits, and hyphens.
|
||
- **ARN format:** `arn:aws:es:{region}:{accountId}:domain/{domainName}`
|
||
- **Domain ID format:** `{accountId}/{domainName}`
|
||
- **`Created` flag:** `true` immediately in mock mode; set to `true` by the readiness poller in real mode once `/_cluster/health` reports `green` or `yellow`.
|
||
- **`Processing` flag:** `false` immediately in mock mode; `true` until the container is ready in real mode.
|
||
- **Engine version default:** `OpenSearch_2.19`
|
||
- **Supported engine versions:** `OpenSearch_3.6`, `OpenSearch_3.5`, `OpenSearch_3.4`, `OpenSearch_3.3`, `OpenSearch_3.2`, `OpenSearch_3.1`, `OpenSearch_3.0`, `OpenSearch_2.19`, `OpenSearch_2.17`, `OpenSearch_2.15`, `OpenSearch_2.13`, `OpenSearch_2.11`, `OpenSearch_2.9`, `OpenSearch_2.7`, `OpenSearch_2.5`, `OpenSearch_2.3`, `OpenSearch_1.3`, `OpenSearch_1.2`, `Elasticsearch_7.10`, `Elasticsearch_7.9`, `Elasticsearch_7.8`
|
||
- **Version validation:** `CreateDomain`, `UpdateDomainConfig`, and `UpgradeDomain` reject unknown engine versions with `ValidationException`. `UpgradeDomain` also rejects targets that aren't reachable from the current version per AWS's documented upgrade matrix.
|
||
- **Cluster defaults:** `m5.large.search`, 1 instance, EBS enabled with 10 GiB `gp2` volume.
|
||
- **Instance type families:** `t3.*` / `m5/m6g/m7g.*` / `r5/r6g/r7g.*` / `c5/c6g/c7g.*` are EBS-backed (3584 GiB max). `i3.*` are local-NVMe instance-store. `or1.*` are S3-backed and surface a much larger volume ceiling on `DescribeInstanceTypeLimits` (8–36 TiB depending on size). Floci still boots one Docker container per domain regardless of family — the metadata fidelity matters for SDK clients that introspect, not for runtime data placement.
|
||
- **Container storage:** each domain gets a named Docker volume (`floci-opensearch-{volumeId}`) created automatically. In memory mode the volume is removed on domain delete; in persistent modes it is retained unless `FLOCI_STORAGE_PRUNE_VOLUMES_ON_DELETE=true`.
|
||
|
||
## Examples
|
||
|
||
```bash
|
||
export AWS_ENDPOINT_URL=http://localhost:4566
|
||
export AWS_DEFAULT_REGION=us-east-1
|
||
export AWS_ACCESS_KEY_ID=test
|
||
export AWS_SECRET_ACCESS_KEY=test
|
||
|
||
# Create a domain
|
||
aws opensearch create-domain \
|
||
--domain-name my-search \
|
||
--engine-version "OpenSearch_2.11" \
|
||
--cluster-config InstanceType=m5.large.search,InstanceCount=1 \
|
||
--ebs-options EBSEnabled=true,VolumeType=gp2,VolumeSize=10
|
||
|
||
# Describe the domain
|
||
aws opensearch describe-domain --domain-name my-search
|
||
|
||
# List all domains
|
||
aws opensearch list-domain-names
|
||
|
||
# Update cluster config
|
||
aws opensearch update-domain-config \
|
||
--domain-name my-search \
|
||
--cluster-config InstanceCount=3
|
||
|
||
# Add tags
|
||
aws opensearch add-tags \
|
||
--arn arn:aws:es:us-east-1:000000000000:domain/my-search \
|
||
--tag-list Key=env,Value=dev
|
||
|
||
# List tags
|
||
aws opensearch list-tags \
|
||
--arn arn:aws:es:us-east-1:000000000000:domain/my-search
|
||
|
||
# Delete domain
|
||
aws opensearch delete-domain --domain-name my-search
|
||
```
|
||
|
||
## SDK Example (Java)
|
||
|
||
```java
|
||
OpenSearchClient os = OpenSearchClient.builder()
|
||
.endpointOverride(URI.create("http://localhost:4566"))
|
||
.region(Region.US_EAST_1)
|
||
.credentialsProvider(StaticCredentialsProvider.create(
|
||
AwsBasicCredentials.create("test", "test")))
|
||
.build();
|
||
|
||
// Create a domain
|
||
CreateDomainResponse created = os.createDomain(req -> req
|
||
.domainName("my-search")
|
||
.engineVersion("OpenSearch_2.11")
|
||
.clusterConfig(c -> c
|
||
.instanceType(OpenSearchPartitionInstanceType.M5_LARGE_SEARCH)
|
||
.instanceCount(1))
|
||
.ebsOptions(e -> e
|
||
.ebsEnabled(true)
|
||
.volumeType(VolumeType.GP2)
|
||
.volumeSize(10)));
|
||
|
||
System.out.println("ARN: " + created.domainStatus().arn());
|
||
|
||
// Wait for domain to be ready (real mode)
|
||
// created.domainStatus().created() == true when ready
|
||
|
||
// Describe the domain
|
||
DescribeDomainResponse desc = os.describeDomain(req -> req
|
||
.domainName("my-search"));
|
||
|
||
System.out.println("Version: " + desc.domainStatus().engineVersion());
|
||
System.out.println("Endpoint: " + desc.domainStatus().endpoint());
|
||
|
||
// List domains
|
||
os.listDomainNames(req -> req.build())
|
||
.domainNames()
|
||
.forEach(d -> System.out.println(d.domainName()));
|
||
|
||
// Delete
|
||
os.deleteDomain(req -> req.domainName("my-search"));
|
||
```
|
||
|
||
## SDK Example (Python)
|
||
|
||
```python
|
||
import boto3
|
||
|
||
os_client = boto3.client(
|
||
"opensearch",
|
||
endpoint_url="http://localhost:4566",
|
||
region_name="us-east-1",
|
||
aws_access_key_id="test",
|
||
aws_secret_access_key="test"
|
||
)
|
||
|
||
# Create a domain
|
||
response = os_client.create_domain(
|
||
DomainName="my-search",
|
||
EngineVersion="OpenSearch_2.11",
|
||
ClusterConfig={"InstanceType": "m5.large.search", "InstanceCount": 1},
|
||
EBSOptions={"EBSEnabled": True, "VolumeType": "gp2", "VolumeSize": 10}
|
||
)
|
||
print(response["DomainStatus"]["ARN"])
|
||
|
||
# List domains
|
||
domains = os_client.list_domain_names()
|
||
for d in domains["DomainNames"]:
|
||
print(d["DomainName"])
|
||
|
||
# Delete
|
||
os_client.delete_domain(DomainName="my-search")
|
||
```
|
||
|
||
## Limitations
|
||
|
||
- In mock mode, no data-plane endpoints (`/_search`, `/_index`, etc.) are served — only the management API is emulated.
|
||
- No Elasticsearch-compatible management endpoints (`/2015-01-01/es/domain/...`).
|
||
- `AccessPolicies`, `VPCOptions`, `AdvancedSecurityOptions`, `EncryptionAtRestOptions`, `NodeToNodeEncryptionOptions`, and `DomainEndpointOptions` round-trip on `CreateDomain` / `UpdateDomainConfig` / `DescribeDomain` / `DescribeDomainConfig`, but are not enforced by the running container — Floci serves the domain over plain HTTP with the security plugin disabled regardless, and `AccessPolicies` is stored verbatim without being evaluated. Round-tripping is enough for SDK clients (Terraform, CDK, Pulumi) to detect drift correctly.
|
||
- Master passwords for `AdvancedSecurityOptions.MasterUserOptions` are accepted but never echoed back, matching AWS behavior.
|
||
- Cross-cluster connections, VPC endpoints, packages, applications, and data sources are not supported and return `UnsupportedOperationException`.
|