Skip to content

Migrate every sample from the localstack CLI to lstk - #277

Open
HarshCasper wants to merge 8 commits into
masterfrom
migrate-to-lstk
Open

HarshCasper wants to merge 8 commits into
masterfrom
migrate-to-lstk

Conversation

@HarshCasper

@HarshCasper HarshCasper commented Oct 15, 2026 •

Copy link
Copy Markdown
Member

Moves the whole repository from the localstack CLI to lstk, following the pattern elb-load-balancing set in #271. It also replaces the awslocal and tflocal wrappers with lstk aws and lstk tf. After this PR, no sample, README, script or workflow invokes or installs the old CLI, awslocal or tflocal.

What changed

  • Makefiles (44 samples and the archived ones):

    • check looks for lstk, and install runs npm install -g @localstack/lstk instead of pip install localstack.
    • start runs lstk start --non-interactive --type aws.
    • ready runs lstk status (lstk start already waits for LocalStack to be ready), logs runs lstk logs > logs.txt, and stop runs lstk stop.
  • Settings the old CLI forwarded implicitly: lstk only forwards LOCALSTACK_-prefixed variables to the container, so they now carry the prefix:

    • DEBUG becomes LOCALSTACK_DEBUG.
    • EC2_VM_MANAGER (ec2-docker-instances).
    • export ENFORCE_IAM=1 (iam-policy-enforcement, multi-account-multi-region-s3-access).
    • export SERVICES=... (athena-s3-queries, cognito-jwt, glacier-s3-select, neptune-graph-db and archived samples).
  • Lambda debugging SAM samples (Java, JavaScript, Python, TypeScript): lstk has no --volume flag, so each sample gets a .lstk/config.toml that mounts lambda_debug_mode_config.yaml. lstk reads it when run from the sample directory. The debug mode variables were already LOCALSTACK_-prefixed, and IMAGE_NAME is gone, since lstk's AWS emulator is the Pro image.

  • Docker Compose samples: route53-dns-failover and java-notification-app start LocalStack with Docker Compose. They only used the CLI to wait for, read logs from, or stop that container. They now:

    • wait on /_localstack/health
    • save logs with docker compose logs localstack
    • stop with docker compose down

    emr-serverless-python-dependencies starts with lstk, so its stop is now lstk stop instead of a docker compose down that never stopped that container.

  • READMEs: the prerequisite bullet links the lstk docs. localstack start examples are now lstk start with prefixed variables, and the root README uses lstk login instead of localstack auth set-token. Its Makefile template is updated as well.

  • Scripts: glue-etl-jobs/run.sh uses lstk logs.

  • awslocal and tflocal: lstk aws runs the AWS CLI with the LocalStack endpoint, credentials and region set, and lstk tf runs Terraform with the LocalStack provider overrides, so:

    • every awslocal call is now lstk aws, and every tflocal call is lstk tf (Makefiles, scripts, READMEs)
    • check targets look for the aws binary lstk aws runs, and install targets no longer pip install awscli-local
    • README prerequisites list the AWS CLI and Terraform, used through lstk aws and lstk tf
  • CI (test.yml): installs lstk with npm instead of the localstack Python package, and the AWS CLI (v1, as awscli-local[ver1] did) instead of awscli-local. It passes LOCALSTACK_DEBUG and LOCALSTACK_DNS_ADDRESS, since plain DEBUG/DNS_ADDRESS no longer reach the container.

Fixes found by running every sample on lstk

  • CI runs lstk setup aws. Without the localstack AWS profile, lstk aws prints a setup note on stdout. That broke every script piping its output into jq, and made cloudformation package upload to real S3. The root README tells users to run lstk setup aws once.
  • multi-account-multi-region-s3-access: with the profile in place, lstk aws reads AWS_ACCESS_KEY_ID only as a 12-digit account id and drops IAM-user access keys. The calls signed as the ls-a/ls-b users therefore use the AWS CLI with the LocalStack endpoint. The account-id calls keep lstk aws.
  • route53-dns-failover, java-notification-app: these run LocalStack with Docker Compose but call lstk aws, so they require lstk again.

Sample bugs that the current LocalStack image now rejects, as AWS does:

  • ecs-ecr-container-app: Fargate tasks use awsvpc, where the host port must equal the container port. The 45139 → 80 mapping is dropped.
  • serverless-websockets: the test now connects to the stage URL (no stage gives HTTP 401). The handler now returns a proper proxy response (the raw event gave HTTP 502).

Environment changes:

  • emr-serverless-python-dependencies: localstack/localstack:latest no longer ships curl, so the build image installs it before fetching Poetry.
  • glue-msk-schema-registry: the MSK wait is now about 5 minutes. LocalStack downloads Kafka on first use, and that download was slow on some runners.

Not changed on purpose

  • cdklocal and samlocal. lstk has lstk cdk and lstk sam, but lstk sam doesn't support container-image Lambdas or nested stacks yet, so these are left for a follow-up.
  • sample-archive/sagemaker-ml-jobs still pip installs localstack into its virtualenv, because run_job.py imports it as a library (from localstack.utils.aws import aws_stack).

Checks

make -n passes for start, stop, ready and logs in every changed Makefile, and actionlint passes on the workflow. CI passes for all 47 jobs: https://github.com/localstack-samples/localstack-pro-samples/actions/runs/38747440649

Replace the localstack CLI with lstk across all samples, the archived
samples, the root Makefile and README, and CI:
- check/install targets look for lstk and install it with npm
- start runs lstk start --non-interactive --type aws; settings the old
  CLI forwarded implicitly now carry the LOCALSTACK_ prefix that lstk
  forwards (DEBUG, EC2_VM_MANAGER, ENFORCE_IAM, SERVICES)
- ready/logs/stop use lstk status, lstk logs and lstk stop
- the Lambda debugging SAM samples mount their debug config through a
  project .lstk/config.toml instead of --volume
- route53-dns-failover and java-notification-app manage LocalStack with
  Docker Compose, so they wait on the health endpoint and use
  docker compose logs/down instead of either CLI
- CI installs lstk instead of the localstack Python package and passes
  LOCALSTACK_DEBUG and LOCALSTACK_DNS_ADDRESS
- READMEs link the lstk docs and use lstk start / lstk login

Claude-Session: https://claude.ai/code/session_01DZfDmzUBPqNAu3yFKyfCNM
lstk aws runs the AWS CLI against LocalStack with the endpoint,
credentials and region set, and lstk tf runs Terraform with the
LocalStack provider overrides, so the separate wrappers are no longer
needed:
- every awslocal call is now lstk aws, and every tflocal call lstk tf
- check targets look for the aws binary lstk aws runs, and install
  targets no longer pip install awscli-local
- README prerequisites list the AWS CLI and Terraform, used through
  lstk aws and lstk tf
- CI installs the AWS CLI (v1, as awscli-local[ver1] did) instead of
  awscli-local

Claude-Session: https://claude.ai/code/session_01DZfDmzUBPqNAu3yFKyfCNM
- Without a localstack AWS profile, lstk aws prints a setup note on
  stdout, so scripts that pipe its output into jq fail. CI now runs
  lstk setup aws after installing lstk, and the README tells users to
  run it once.
- The localstack/localstack image no longer ships curl, so the EMR
  Serverless dependencies image installs it before fetching Poetry.

Claude-Session: https://claude.ai/code/session_01DZfDmzUBPqNAu3yFKyfCNM
route53-dns-failover and java-notification-app start LocalStack with
Docker Compose but call the AWS CLI through lstk aws, so their check
targets look for lstk again, and route53-dns-failover installs it.

Claude-Session: https://claude.ai/code/session_01DZfDmzUBPqNAu3yFKyfCNM
Fargate tasks use awsvpc networking, where AWS requires the host port to
equal the container port. RegisterTaskDefinition now rejects the old
45139 -> 80 mapping on LocalStack too, rolling back the stack. Drop the
HostPort parameter; make run already reads the bound port from the
task's network bindings.

Claude-Session: https://claude.ai/code/session_01DZfDmzUBPqNAu3yFKyfCNM
lstk aws reads AWS_ACCESS_KEY_ID only as a 12-digit account id and
drops any other value once the localstack profile exists, so calls
meant to run as the ls-a/ls-b IAM users ran with the profile's root
credentials and the access-denied check passed by mistake. Those calls
now use the AWS CLI with the LocalStack endpoint; the account-id calls
keep using lstk aws. DEBUG also gets the LOCALSTACK_ prefix lstk
forwards.

Claude-Session: https://claude.ai/code/session_01DZfDmzUBPqNAu3yFKyfCNM
- serverless-websockets: test.py connected to the API endpoint without
  a stage path, which LocalStack now rejects with HTTP 401 (AWS needs
  the stage too). It now appends the deployed stage.
- glue-msk-schema-registry: Kafka can take more than the 140s the
  script waited for the MSK cluster to become ACTIVE on a busy runner.
  Wait up to about 5 minutes.

Claude-Session: https://claude.ai/code/session_01DZfDmzUBPqNAu3yFKyfCNM
The handler returned the raw event, which isn't a valid Lambda proxy
response; LocalStack now rejects the connection with HTTP 502, as AWS
does. Return statusCode 200 and echo the message body, which API
Gateway sends back to the client on routes with a route response.

Claude-Session: https://claude.ai/code/session_01DZfDmzUBPqNAu3yFKyfCNM
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants