DocsAWS 101Blog
← Back to Blog

v1.3.23 — OpenSearch, EventBridge auto-fire, 5 new services, improve in idle RAM

May 1, 2026 · v1.3.23

1.3.23 closes the biggest service gaps the community has been asking for. OpenSearch arrives with a full management plane and an optional real cluster on demand. EventBridge rate() rules now actually fire on schedule. AWS Organizations, Account, Batch, and WAF v1 ship as account-scoped stubs so legacy SDKs no longer hit 405. The Docker image trims off idle RAM with two well-known knobs and zero correctness cost.

1. Amazon OpenSearch Service

The new opensearch service implements the management plane on the /2021-01-01/* REST path: CreateDomain, DescribeDomain / DescribeDomains, DeleteDomain, ListDomainNames with the EngineType filter, UpdateDomainConfig, DescribeDomainConfig with the AWS-canonical Options / Status wrapping, DescribeDomainChangeProgress, ListVersions, GetCompatibleVersions, and the AddTags / ListTags / RemoveTags trio. State is account-scoped so multi-tenant tests stay isolated.

By default the data plane is a stub endpoint — DescribeDomain.Endpoint returns <domain>.ministack.local:9200 — so management-plane tests stay fast and offline. Set OPENSEARCH_DATAPLANE=1 on the gateway and ministack spawns one real opensearchproject/opensearch container per CreateDomain, the same pattern ElastiCache and RDS already use:

docker run -d --name ministack -p 4566:4566 \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -e OPENSEARCH_DATAPLANE=1 \
  ministackorg/ministack:1.3.23

aws --endpoint-url=http://localhost:4566 \
    opensearch create-domain --domain-name search-prod \
    --engine-version OpenSearch_2.15

# DescribeDomain now returns a real container endpoint
curl http://localhost:14571/_cluster/health
# {"cluster_name":"docker-cluster","status":"green",...}

Add OPENSEARCH_DASHBOARDS=1 alongside the dataplane flag and each domain also gets a per-domain opensearchproject/opensearch-dashboards sidecar; DescribeDomain.DomainStatus.DashboardEndpoint is then populated with the URL. Both containers are labeled com.docker.compose.project=ministack so they show up grouped in Docker Desktop. DeleteDomain stops and removes them. Terraform aws_opensearch_domain resource compatible. Requested by @marcin-nowak-scl.

2. EventBridge: rate() rules now fire automatically

Until 1.3.23, an EventBridge rule with ScheduleExpression: rate(1 minute) was stored but never invoked — _dispatch_event short-circuited any rule without an EventPattern, and there was no scheduler thread anywhere. 1.3.23 ships a daemon thread (eb-scheduler) that ticks every 10 seconds and dispatches enabled rate() rules whose interval has elapsed. The countdown anchors to each rule's CreationTime, so the first fire lands one full interval after PutRule, matching the AWS-documented behaviour ("the countdown begins when you create the rule"). Iterates the rules store directly so multi-account setups all dispatch correctly.

The scheduled-event payload matches the AWS wire format exactly — "source": "aws.events", "detail-type": "Scheduled Event", "detail": {}, "version": "0", "resources": [<rule-arn>], and "time" as an ISO 8601 UTC string. cron() expressions are stored but not yet auto-fired; the scheduler logs an INFO line once per cron rule the first time it observes one, so the parity gap is visible while we plan the cron parser. Contributed by @hiddengearz.

3. AWS Organizations

A new organizations service handles DescribeOrganization, ListRoots, ListAccounts, DescribeAccount, ListOrganizationalUnitsForParent, ListAccountsForParent, plus CreateOrganizationalUnit / DescribeOrganizationalUnit / DeleteOrganizationalUnit. The org is auto-initialised on the first call so existing test setups need zero ceremony. Nested OUs carry the new Path field that AWS added 2026-03-31:

orgs = boto3.client("organizations", endpoint_url="http://localhost:4566")
root = orgs.list_roots()["Roots"][0]
eng  = orgs.create_organizational_unit(ParentId=root["Id"], Name="Engineering")
back = orgs.create_organizational_unit(
    ParentId=eng["OrganizationalUnit"]["Id"], Name="Backend",
)
# back["OrganizationalUnit"]["Path"] == "/Engineering/Backend/"

Older boto3 builds whose service spec predates the additive change strip Path client-side — the field is on the wire, newer SDKs see it.

4. AWS Account service

boto3.client("account") now resolves: GetAccountInformation, GetContactInformation, ListRegions, and GetRegionOptStatus. GetAccountInformation returns the new AccountState field (additive, AWS released 2026-04-29). ListRegions covers the standard 31 commercial regions with realistic opt-in-not-required / opted-in status per region.

5. AWS Batch

A control-plane stub: CreateComputeEnvironment / DescribeComputeEnvironments, CreateJobQueue / DescribeJobQueues (lookup by name or ARN), RegisterJobDefinition with auto-incrementing revisions, SubmitJob / DescribeJobs / ListJobs. Submitted jobs transition immediately to SUCCEEDED with exit code 0 — ministack is the scheduler, not a real container runner. Account-scoped state.

6. WAF Classic + WAF Regional (v1)

Legacy v1 WAF (target prefixes AWSWAF_20150824 and AWSWAF_Regional_20161128) is now routed to a minimal stub. All 17 List* ops return empty arrays with valid NextMarker, GetChangeToken and GetChangeTokenStatus return real-shaped responses, and Get* on unknown resources returns WAFNonexistentItemException — so Terraform / old CFN templates / JDK examples that target v1 no longer hit a 405. For real WebACL state use wafv2, which is unchanged.

7. EC2 DescribeRegions

The action returned InvalidAction; ministack now serves the standard 31 commercial AWS regions with the right OptInStatus per region, RegionNames filtering, and AllRegions support. Region-discovery code in test frameworks (boto3, Java SDK v2, Go SDK v2) gets a clean shape.

8. AWS-additive fields and shape fixes

9. Improve in idle RAM

The published Docker image now sets PYTHONOPTIMIZE=2 and MALLOC_ARENA_MAX=2, two well-known knobs that take idle RSS from ~92 MiB down to ~64 MiB without changing throughput. Verified by an empty grep for assert, __doc__, and __debug__ in the source — PYTHONOPTIMIZE=2 can't strip anything ministack relies on. Test suite passes identically with and without the flag.

Upgrade

# Regular image (Alpine)
docker pull ministackorg/ministack:1.3.23

# Full image (Debian + DuckDB + psycopg2 + pymysql)
docker pull ministackorg/ministack:1.3.23-full

# pip
pip install -U ministack

Full changelog: CHANGELOG.md.

Shipped by the MiniStack community. Contributions credited throughout. GitHub · r/ministack