Skip to content

feat: add LocalStack-based local testing environment - #724

Draft
redhat-chai-bot wants to merge 13 commits into
openshift-online:mainfrom
redhat-chai-bot:feat/localstack-dev-env
Draft

feat: add LocalStack-based local testing environment#724
redhat-chai-bot wants to merge 13 commits into
openshift-online:mainfrom
redhat-chai-bot:feat/localstack-dev-env

Conversation

@redhat-chai-bot

Copy link
Copy Markdown
Contributor

Summary

Add a LocalStack-based local development environment that emulates the multi-account AWS setup used by the ROSA HyperFleet deployment pipeline. This allows developers to test configuration rendering, pipeline bootstrapping, and environment provisioning workflows locally without needing real AWS accounts or deploying actual clusters.

Motivation

The existing make ephemeral-provision workflow provisions real AWS infrastructure across 5 accounts via CodePipeline, which is slow (~1 hour) and requires AWS credentials. A LocalStack-based alternative enables rapid iteration on infrastructure changes, config rendering, and pipeline logic without incurring AWS costs or waiting for real provisioning.

What's Included

Docker Compose (docker-compose.localstack.yaml)

  • LocalStack Community Edition with 27 AWS services enabled
  • Auto-initialization via mounted init script
  • Health check and persistence support

Init Script (scripts/localstack/init-aws.sh)

  • Bootstraps the multi-account environment matching the real 5-account model:
    • Central (000000000001) — pipeline infrastructure, SSM parameters, terraform state
    • RC (000000000002) — regional cluster account
    • MC (000000000003) — management cluster account
    • Customer (000000000004) — customer workload account
  • Creates IAM roles with OrganizationAccountAccessRole pattern for cross-account access
  • Sets up SSM parameters at the paths render.py expects (/infra/localstack/<region>/account_id)
  • Creates Route53 hosted zones, S3 state buckets, VPC infrastructure, CodePipeline/CodeBuild stubs
  • Creates DynamoDB tables, Secrets Manager entries, KMS keys, and SNS/SQS resources

Lifecycle Manager (scripts/localstack/localstack-env.sh)

  • Follows the same pattern as scripts/dev/ephemeral-env.sh
  • Subcommands: up, provision, teardown, status, reset, shell
  • Auto-detects container engine (docker compose / podman-compose)

Config Preset (config/localstack/)

  • Hardcoded mock account IDs (no SSM resolution needed)
  • Local DNS domain (localstack.rosa.local)
  • Expensive features disabled for fast iteration (bastion, CloudTrail, API custom domain, rate limiting)

Makefile Targets

  • localstack-up — Start LocalStack services
  • localstack-provision — Bootstrap the local AWS environment
  • localstack-teardown — Stop and clean up
  • localstack-shell — Interactive AWS CLI shell against LocalStack
  • localstack-status — Health check
  • localstack-reset — Full destroy + recreate

Documentation (docs/localstack-testing.md)

  • Prerequisites, quick start, architecture diagram
  • Account mapping table (real → LocalStack)
  • Known limitations and troubleshooting

Validation

  • shellcheck passes on both shell scripts
  • render.py successfully renders config/localstack/ alongside existing environments
  • prettier formatting applied to documentation
  • check-docs annotation check passes
  • .gitignore updated for LocalStack state directories

Known Limitations

  • LocalStack Community Edition does not fully emulate EKS, RDS Aurora, or ElastiCache — these are stubbed for API compatibility
  • No actual Kubernetes clusters are deployed; the focus is on testing the AWS account/infrastructure provisioning pipeline
  • CodePipeline/CodeBuild are stubbed — pipeline execution logic is not emulated

@psav requested in Slack thread

Add a LocalStack development environment that emulates the multi-account
AWS infrastructure locally, allowing developers to test the deployment
pipeline without real AWS accounts or clusters.

New files:
- docker-compose.localstack.yaml: LocalStack service configuration
- scripts/localstack/init-aws.sh: Bootstrap mock AWS resources
- scripts/localstack/localstack-env.sh: Lifecycle management CLI
- config/localstack/: Environment config (defaults + us-east-1)
- docs/localstack-testing.md: Setup, usage, and limitations guide
- deploy/localstack/: Rendered pipeline inputs and ArgoCD manifests

The init script creates mock IAM roles (OrganizationAccountAccessRole),
SSM parameters, Route53 zones, S3 state buckets, VPC infrastructure,
DynamoDB tables, KMS keys, and CodePipeline/CodeBuild projects matching
the patterns used by the real ephemeral provisioning flow.

Makefile targets: localstack-up, localstack-provision, localstack-teardown,
localstack-shell, localstack-status, localstack-reset.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@openshift-ci openshift-ci Bot added the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Jul 30, 2026
@openshift-ci

openshift-ci Bot commented Jul 30, 2026

Copy link
Copy Markdown

Skipping CI for Draft Pull Request.
If you want CI signal for your change, please convert it to an actual PR.
You can still manually trigger a test run with /test all

@openshift-ci

openshift-ci Bot commented Jul 30, 2026

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign theautoroboto for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 32aa4568-0a60-4f89-a615-d2665c95d14c

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

redhat-chai-bot and others added 12 commits July 30, 2026 17:27
Switch to localstack/localstack-pro image for full EKS emulation,
Lambda container image support, and IAM policy enforcement. Add
LOCALSTACK_AUTH_TOKEN pass-through and set ENFORCE_IAM=1 by default
so IAM policies are tested against real permission checks.

- docker-compose: use Pro image, add auth token and ENFORCE_IAM=1
- init-aws.sh: create IAM users with access keys and scoped policies
- localstack-env.sh: preflight check for LOCALSTACK_AUTH_TOKEN
- defaults.yaml: reflect Pro capabilities in config header
- docs: document Pro requirements, auth token setup, IAM enforcement

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adopt Podman as the container engine for the LocalStack development
environment, following the patterns established in rosa-log-router.

docker-compose.localstack.yaml:
- Mount podman socket via DOCKER_SOCK env var with fallback
- Add :Z SELinux labels on all volume mounts
- Run as user "0" with privileged: true for socket access
- Use named network with explicit bridge driver
- Switch LAMBDA_EXECUTOR to docker-reuse for faster cold starts

localstack-env.sh:
- Add podman socket activation (systemctl --user enable --now)
- Simplify compose detection to docker compose only
- Replace manual health-check loop with timeout-based approach (120s)
- Remove emoji characters for cleaner terminal output

Makefile:
- Add podman socket activation in localstack-up target

docs/localstack-testing.md:
- Update prerequisites to recommend Podman with docker compose
- Add Podman socket setup section
- Add Podman socket troubleshooting section

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove DEFAULT_REGION (deprecated since LocalStack 0.12.7) and
  LAMBDA_EXECUTOR (deprecated since LocalStack 2.0.0) from compose file
- Add wait_for_service helper and service readiness checks before each
  AWS service section in init-aws.sh to prevent race conditions
- Add retry wrapper around SSM put-parameter calls with || true to
  handle transient failures that caused exit code 255
- Change default Docker socket path from /run/user/1000/podman/podman.sock
  to /var/run/docker.sock (works for Docker and rootful Podman); document
  DOCKER_SOCK override for Podman rootless users

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Root cause: create_iam_user() stores access key credentials in SSM
(put-parameter), but wait_for_service "ssm" only ran later in the
standalone SSM Parameters section. When the init script ran as a
ready.d hook during container startup, the SSM service wasn't ready
yet — awslocal returned exit code 255 (AWS CLI catchall), and
set -euo pipefail aborted the script.

Fix:
- Add wait_for_service "ssm" before the IAM Users section (first SSM
  usage in the script, inside create_iam_user)
- Add || true to all EC2 VPC/subnet/security-group variable assignments
  that were also missing error handling (same class of bug)
- Use ${VAR:-<failed>} in echo output for visibility when commands fail

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The init-aws.sh script was crashing with exit code 255 during the SSM
Parameters section, but `set -euo pipefail` caused silent failures with
no indication of which command failed or why.

Changes:
- Add `set -x` (bash debug trace) to print every command before execution
- Add ERR trap that prints exact source file, line number, and exit code
- Replace `set -e` with explicit per-command error handling via run_aws()
  and run_aws_capture() wrappers that capture stderr and log the full
  command line, exit code, and error output on failure
- Add log() helper with timestamps for every operation
- Add `set -E` to propagate ERR trap into functions and subshells
- Remove all `2>/dev/null` from awslocal calls so errors are visible
- Add `|| true` safety on arithmetic expressions to prevent edge cases
- Quote all $AWSLOCAL expansions for correctness

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…uce debug noise

- Remove all --no-cli-pager flags from init-aws.sh (unsupported by AWS
  CLI v1 bundled in LocalStack container). Set AWS_PAGER="" at the top
  of the script instead, which works on both v1 and v2.

- Trim SERVICES list in docker-compose.localstack.yaml to only the 18
  services actually exercised by init-aws.sh, cutting startup time.

- Fix false "FAILED [exit 0]" reporting in run_aws/run_aws_capture:
  capture exit code via `cmd || rc=$?` instead of relying on `$?` after
  an `if` block (which always yields 0 in bash).

- Remove per-attempt retry logging and wait_for_service progress
  messages to reduce noise. Error and milestone messages retained.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Expand SERVICES in docker-compose.localstack.yaml to all 29 AWS services
  the project uses (excluding cloudtrail and codestar-connections)
- Add EKS cluster creation (rc-cluster, mc-cluster) to init-aws.sh using
  LocalStack Pro k3s emulation, with ACTIVE polling and timeout
- Add assume-role subcommand to localstack-env.sh + Makefile target that
  maps account names (central/rc/mc/customer) to IDs and drops into a
  subshell with temporary STS credentials
- Add eks-kubeconfig subcommand + Makefile target to update kubeconfig
  for LocalStack EKS clusters via awslocal
- Add trigger-pipeline subcommand + Makefile target supporting both
  CodeBuild (source upload to S3) and CodePipeline, with optional
  REPO= and COMMIT= parameters for custom source
- Update docs/localstack-testing.md with documentation for all new tools

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ORCE_IAM

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…for root bootstrap

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
LocalStack's ENFORCE_IAM does not evaluate inline or managed policies
attached to the root user. After 4 attempts (AdministratorAccess,
PassRole inline, wildcard inline), cross-account operations still fail
with AccessDeniedException during bootstrap.

Disable ENFORCE_IAM by default (opt-in via LOCALSTACK_ENFORCE_IAM=1).
The 4 scoped IAM users are still created for realistic IAM testing
after init completes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant