CLICommandsl4 commitments

l4 commitments expiring

l4 commitments expiring lists the commitments whose term ends inside a window. With --fail-within it also returns exit code 2, which is what makes it usable as a build gate.

l4 commitments expiring [flags]

A term ending is not an event anything currently interrupts. The commitment simply stops, and the usage it was covering reverts to on-demand rates on the next bill. This command is how that becomes something a pipeline notices.

Flags

FlagDescription
--within <w>Window to list. Defaults to 90d
--fail-within <w>Exit 2 when a commitment lapses inside this window. Unset by default
--provider <id>aws (expiry is not measured elsewhere)

Durations take d, w or m. A month is 30 days.

Global flags apply. See CLI overview.

The gate

Without --fail-within the command only reports, and always exits 0.

l4 commitments expiring --fail-within 30d
ID       SERVICE  KIND  HOLDER  EXPIRES  UTIL   COVERAGE      PROTECTS/MO
ri-a1b2  EC2      RI    prod    18d      98.2%  61.4%         $12400.00

Error: 1 commitment(s) lapse within 30d.
$ echo $?
2

Exit 2 is this CLI's "issues found" code, shared with l4 estimate --fail-above and l4 diff --fail-above. It means the command ran correctly and did not like what it found, which is distinct from 1, a command that failed.

The listing widens to match

Passing only --fail-within widens the listing to the same window, so the output explains the exit code it just produced. Pass --within as well to keep a wider view than the gate:

l4 commitments expiring --within 180d --fail-within 30d

That lists six months of upcoming expiries and fails on the next thirty days.

It survives the output flags

The gate runs whatever the output format is. Under --json, --jq or --template the payload goes to stdout and both the pass and fail notices go to stderr, so the document stays parseable and the exit code still arrives:

l4 commitments expiring --fail-within 30d --json > expiring.json
echo $?
This is worth checking if you fork this behaviour anywhere. A gate that stops firing the moment someone adds --json is the failure the gate exists to prevent, and it is invisible in any test that only exercises the happy path.

Under --quiet nothing prints at all and the exit code is the whole result, which is the documented contract for that flag.

In a pipeline

GitHub Actions:

- name: Commitment expiry check
  env:
    LEVELFOUR_TOKEN: ${{ secrets.LEVELFOUR_TOKEN }}
  run: l4 commitments expiring --fail-within 30d

GitLab CI:

commitment-expiry:
  script:
    - l4 commitments expiring --fail-within 30d

A read-only key is enough. See CLI authentication.

Run it on a schedule rather than on every push. Nothing about a commitment's term changes between two commits, and a daily or weekly job gives the thirty days of warning the gate is asking for.

Providers that cannot be checked

Commitment expiry is measured for AWS. Elsewhere the command names why and exits 0:

$ l4 commitments expiring --fail-within 30d --provider gcp
Commitment expiry is not measured for Google Cloud: the commitment lifecycle export is not enabled.
Nothing checked.
$ echo $?
0
Exiting 0 there is deliberate. A gate that cannot measure must not fail a build for ever. The line says nothing was checked, so an unmeasurable provider is visible in the log rather than silently passing.

Errors

ExitSymptomCause
2N commitment(s) lapse within <w>The gate fired. This is the intended result, not a fault
4Authentication requiredNo token resolvable; run l4 auth login or set LEVELFOUR_TOKEN
1invalid window--within or --fail-within was not a number followed by d, w or m
0Commitments are not yet available for your account.The API does not serve the commitments routes yet