Skip to main content

Contract-driven ECS deploys: render a task definition from SSM, register it, repoint the service, observe the rollout

Project description

longshore

Contract-driven ECS deploys. longshore reads a service's configuration from SSM Parameter Store (/services/{name}/*), renders a Fargate task definition, registers it, repoints the ECS service, and observes the rollout. It is stateless and deliberately small: your infrastructure tooling (Terraform, CloudFormation, CDK, a script) owns the ECS service; longshore owns only the task definition.

Producer (your IaC)                 longshore
───────────────────                 ─────────
owns the ECS service                renders task-def JSON from SSM
owns autoscaling / desired count    registers new task-def revision
owns networking, LB, roles, logs    update_service(taskDefinition=…) — nothing else
owns circuit breaker + rollback     polls rolloutState, reports events
writes /services/{name}/* (SSM)  ─► reads /services/{name}/*

Because update_service is called with only the taskDefinition argument, the tool structurally cannot touch desired count, networking, or load-balancer settings. Rollback is server-side via the ECS deployment circuit breaker — longshore only observes and reports.

Install

uvx longshore --help          # zero-install, always the latest release
uvx longshore==0.1.0 --help   # pinned (recommended in CI)
# or: pip install longshore

Usage

# The main path (CI and local; identical behaviour)
longshore deploy --service myapp-production --image <ecr-url>:<tag> [--region us-east-2] [--wait-minutes 12]

# Config gates (read-only against AWS)
longshore validate --service myapp-production                 # contract compliance report
longshore render --service myapp-production [--image <url>] [--output task-def.json]
longshore diff   --service myapp-production [--image <url>]   # vs the registered revision

# Operator verbs (need broader IAM than the deploy path; see below)
longshore run  --service myapp-production --command 'php artisan migrate --force'
longshore exec --service myapp-production                     # needs the session-manager-plugin

Cluster, roles, networking, and log-group coordinates all come from SSM — there is no per-service config file. Adding a service or a secret requires no change here.

Exit codes

  • 0 — success (deploy: rollout COMPLETED; run: container exited 0).
  • non-zero — validation error, rollout FAILED (circuit breaker triggered; rollback is already underway server-side), watch timeout, or the one-off task's exit code.

The contract

The SSM interface — which parameter keys the tool understands relative to /services/{name}/, their parse semantics, and when they are required — is defined by the versioned contract bundled with the package: src/longshore/data/services.yaml. It is the single source of truth and is not user-configurable; any producer that writes compliant parameters works with this tool unmodified.

longshore validate --service <name> reports a live prefix's compliance: missing required keys, type/enum violations, structural problems (e.g. a sidecar without a name), per-container env counts, and any keys under the prefix the tool ignores.

Highlights of the interface:

  • Env is per-container and secrets-only. Every parameter under containers/{container}/env/ (String or SecureString) becomes a valueFrom secret on that container — values are never read by the tool, only ARNs; ECS resolves them at task start via the execution role.
  • Sidecars are raw container definitions published at ecs/sidecars with producer-pinned images; --image only ever targets the primary container.
  • FireLens needs no special support: a log-router sidecar plus an ecs/log_configuration override (used verbatim) switches the primary container to awsfirelens.

Interface changes bump the contract version and ship as new releases.

GitHub Action

The repo doubles as a composite action pinned to the same version as the code:

jobs:
  deploy:
    runs-on: ubuntu-latest
    permissions:
      id-token: write   # OIDC
      contents: read
    steps:
      - uses: telasystems/longshore@v0
        with:
          service-name: myapp-production
          image: ${{ needs.build.outputs.image }}
          role-arn: ${{ vars.DEPLOY_ROLE_ARN }}

IAM for the deploy path

A CI deploy role needs only: ssm:GetParameter/GetParametersByPath on the service prefix, ecs:RegisterTaskDefinition (+ DescribeTaskDefinition, TagResource), ecs:UpdateService/DescribeServices on the one service, iam:PassRole on the task's two roles, and (optional, for failure diagnostics) cluster-scoped ecs:ListTasks/DescribeTasks. run and exec intentionally need more (ecs:RunTask, ecs:ExecuteCommand) — keep those off the CI role and use operator credentials.

Development

uv sync                      # install (incl. dev deps)
uv run pytest                # tests (renderer, contract pinning, engine, CLI)
uv run ruff check .          # lint
uv run ruff format --check . # formatting
uv run mypy                  # types

The contract-pinning tests walk the bundled contract and assert the renderer honours every entry (type, default, required, enum) — a contract change fails tests until the renderer handles it, so spec and code cannot drift silently.

License

MIT © Tela Systems

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

longshore-0.1.0.tar.gz (80.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

longshore-0.1.0-py3-none-any.whl (22.6 kB view details)

Uploaded Python 3

File details

Details for the file longshore-0.1.0.tar.gz.

File metadata

  • Download URL: longshore-0.1.0.tar.gz
  • Upload date:
  • Size: 80.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for longshore-0.1.0.tar.gz
Algorithm Hash digest
SHA256 ae91ba62568fc55161ab99fee71322c183511ab32b9104e2dbaba14a5d1f6e1f
MD5 4d48c21628a763133476dccb2992c1aa
BLAKE2b-256 3bac57192f383e8a9cfc288ad2415be2d918f1fc0d3abc09c1859d10916924aa

See more details on using hashes here.

Provenance

The following attestation bundles were made for longshore-0.1.0.tar.gz:

Publisher: release.yml on telasystems/longshore

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file longshore-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: longshore-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 22.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for longshore-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 6f1682c2d2e0c2b5db06c5bad59c101d1e0e626167563907957c3251b623bcdd
MD5 e15fbf9559fea168c1eeecc43ee834cf
BLAKE2b-256 966f67b2aab3597862161fc1cf68ffca15ec4d99acd8c791e0dc7761d53ea1fc

See more details on using hashes here.

Provenance

The following attestation bundles were made for longshore-0.1.0-py3-none-any.whl:

Publisher: release.yml on telasystems/longshore

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page