Skip to content

Add subscribe API support for azure#2118

Open
edwardrf wants to merge 4 commits into
mainfrom
edw/azure-subscribe
Open

Add subscribe API support for azure#2118
edwardrf wants to merge 4 commits into
mainfrom
edw/azure-subscribe

Conversation

@edwardrf
Copy link
Copy Markdown
Contributor

@edwardrf edwardrf commented May 19, 2026

Description

So defang cli only exits when all services are up correctly.

Linked Issues

#2073

Checklist

  • I have performed a self-review of my code
  • I have added appropriate tests
  • I have updated the Defang CLI docs and/or README to reflect my changes, if necessary

Summary by CodeRabbit

  • New Features

    • Real-time Azure deployment subscription: monitor CD execution status, image builds, and instance provisioning health.
    • Deployment execution timestamp tracking for clearer timeline visibility.
    • Tailing now logs when a timeout is used.
  • Tests

    • Comprehensive tests for subscription behavior: successful flows, failures, state mappings, and build lifecycle events.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 19, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 092791b9-cf2f-402e-bdb4-2419cbf96461

📥 Commits

Reviewing files that changed from the base of the PR and between 209ef0f and 373ec42.

📒 Files selected for processing (5)
  • src/pkg/cli/client/byoc/azure/subscribe.go
  • src/pkg/cli/client/byoc/azure/subscribe_test.go
  • src/pkg/cli/tailAndMonitor.go
  • src/pkg/clouds/azure/aca/revisions.go
  • src/pkg/clouds/azure/acr/runs.go
✅ Files skipped from review due to trivial changes (1)
  • src/pkg/cli/tailAndMonitor.go
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/pkg/clouds/azure/aca/revisions.go
  • src/pkg/clouds/azure/acr/runs.go
  • src/pkg/cli/client/byoc/azure/subscribe_test.go
  • src/pkg/cli/client/byoc/azure/subscribe.go

📝 Walkthrough

Walkthrough

Implements Azure BYOC Subscribe: adds cloud API helpers (ACA revisions, ACR runs), tracks CD start times in ByocAzure, implements Subscribe orchestration with concurrent CD/ACR/revision pollers and gating, and adds integration/unit tests and a small CLI log message.

Changes

Azure Deployment Event Streaming

Layer / File(s) Summary
Azure Container Apps and ACR API helpers
src/pkg/clouds/azure/aca/revisions.go, src/pkg/clouds/azure/acr/runs.go
Adds RevisionState and GetRevisionState to read revision lifecycle and not-found mapping; adds RunsLister, RunInfo, ListRunsSince, IsTerminal, and IsSuccess to page ACR task runs and classify statuses.
ByocAzure CD execution start timestamp
src/pkg/cli/client/byoc/azure/byoc.go, src/pkg/cli/client/byoc/azure/byoc_test.go
Adds cdStart time.Time to ByocAzure; CdCommand and deploy capture and persist execution start timestamps. Test replaced with one asserting Subscribe fails when no CD has run.
Subscribe orchestration and concurrent pollers
src/pkg/cli/client/byoc/azure/subscribe.go
Implements ByocAzure.Subscribe and internal subscribe() orchestration: validates active CD/ETag, launches CD, ACR, and per-service revision pollers, multiplexes events, gates service completion behind CD success, de-duplicates emissions, and terminates on terminal states or CD failure.
Subscribe integration and unit tests
src/pkg/cli/client/byoc/azure/subscribe_test.go
Adds TestMain with accelerated polls, fake clients for revisions/ACR/CD, drain helper, integration tests for success/failure flows, build-state emission test, and unit tests for mapping helpers.
Minor CLI logging
src/pkg/cli/tailAndMonitor.go
Logs an info message when waitTimeout > 0 to indicate tailing with timeout.

Sequence Diagram

sequenceDiagram
  participant Client
  participant Subscribe as ByocAzure.Subscribe
  participant Aggregator as Event Aggregator
  participant PollCD as pollCD goroutine
  participant PollRevisions as pollRevision goroutine
  participant PollBuilds as pollBuilds goroutine
  
  Client->>Subscribe: Subscribe(ctx, request)
  Subscribe->>Subscribe: Validate CD run active
  Subscribe->>Subscribe: Check ETag match
  Subscribe->>Aggregator: Create event multiplexer
  
  Aggregator->>PollCD: Launch concurrent poller
  Aggregator->>PollRevisions: Launch per-service pollers
  Aggregator->>PollBuilds: Launch build poller
  
  par Concurrent Polling
    PollCD->>PollCD: Poll job execution status
    PollRevisions->>PollRevisions: Poll revision states
    PollBuilds->>PollBuilds: Poll ACR run history
  end
  
  PollCD-->>Aggregator: CD success/failure event
  PollRevisions-->>Aggregator: Revision state change event
  PollBuilds-->>Aggregator: Build status event
  
  Aggregator->>Aggregator: Gate ready behind CD success
  Aggregator->>Aggregator: Track per-service terminal states
  
  loop Until all services terminal
    Aggregator-->>Client: SubscribeResponse stream
  end
  
  Aggregator->>Client: Stream ends
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested reviewers

  • jordanstephens
  • lionello

Poem

🐰 From azure clouds the events unfurl,
Three pollers hum, they dance and whirl,
Revisions, builds, and CD’s sign,
Streamed in order, one small line.
A rabbit cheers: "Deployments shine!"

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 24.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: implementing Azure support for the subscribe API, which is the primary focus of this pull request.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch edw/azure-subscribe

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (2.12.2)

level=warning msg="The linter 'gomodguard' is deprecated (since v2.12.0) due to: new major version. Replaced by gomodguard_v2."
level=warning msg="Suggested new configuration:\nlinters:\n enable:\n - gomodguard_v2\n"
level=warning msg="[linters_context] running gomodguard failed: unable to read module file go.mod: current working directory must have a go.mod file: if you are not using go modules it is suggested to disable this linter"
level=error msg="[linters_context] typechecking error: pattern ./...: directory prefix . does not contain main module or its selected dependencies"


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

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (1)
src/pkg/cli/client/byoc/azure/subscribe_test.go (1)

251-276: ⚡ Quick win

Collapse mapRevisionState unit tests into a table-driven test.

These three tests are repetitive and should be table-driven for consistency and easier case expansion.

As per coding guidelines: **/*_test.go: Use table-driven tests for comprehensive test coverage in unit tests.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/pkg/cli/client/byoc/azure/subscribe_test.go` around lines 251 - 276,
Replace the three repetitive tests (TestMapRevisionState_NotFound,
TestMapRevisionState_Healthy, TestMapRevisionState_FailedProvisioning) with a
single table-driven test that iterates a slice of cases (each with a name, input
*aca.RevisionState, expected defangv1.ServiceState value, and expected terminal
bool), calling mapRevisionState for each case inside t.Run; include the three
cases: nil → UPDATE_QUEUED/terminal=false, &aca.RevisionState{NotFound:true} →
UPDATE_QUEUED/terminal=false, healthyRevision() →
DEPLOYMENT_COMPLETED/terminal=true, and &aca.RevisionState{ProvisioningState:
armappcontainersv3.RevisionProvisioningStateFailed} →
DEPLOYMENT_FAILED/terminal=true, and assert expected state and terminal for each
case.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/pkg/cli/client/byoc/azure/subscribe_test.go`:
- Line 230: The test currently ignores the error returned by drain when calling
got, _ := drain(t, t.Context(), subscribeInputs{...}); update the call in the
build-state test to capture and assert the error (e.g., err := drain(...)) and
fail the test when err != nil using the test helper (t.Fatal/t.Fatalf or the
test harness’s equivalent). Ensure you reference the drain function and
subscribeInputs invocation so the test fails on any stream/drain errors instead
of silently passing.

In `@src/pkg/cli/client/byoc/azure/subscribe.go`:
- Around line 139-144: The loop in subscribe.go currently treats ev.err
non-terminal by calling yield(nil, ev.err) and then continuing; change the
control flow so that after emitting an error via yield (when ev.err != nil) the
subscription loop breaks/returns immediately instead of continuing, ensuring
pollers stop and the iterator completes; locate the block handling ev.err in the
subscription loop (the section that calls yield(nil, ev.err)) and replace the
continue with a terminal exit (return or break) so errors are treated as
terminal by the Subscribe/iterator logic.

In `@src/pkg/clouds/azure/aca/revisions.go`:
- Around line 24-27: Wrap the raw errors returned from the credential/setup
calls with contextual messages using fmt.Errorf and %w: replace direct returns
of err from the c.NewCreds() call (the cred, err := c.NewCreds() path) and the
other setup return around the 35-38 block with something like fmt.Errorf("setup
<describe operation>: %w", err) so callers see which operation failed; add the
fmt import if missing and ensure the message names the operation (e.g.,
"creating Azure creds" or "initializing subscription").

In `@src/pkg/clouds/azure/acr/runs.go`:
- Around line 38-41: Wrap and annotate raw errors returned from setup/discovery
paths so callers keep context: in the functions/methods ensureClients (where you
call r.NewCreds()), findRegistry, and the ListRunsSince entry path, replace bare
"return err" with fmt.Errorf including a short contextual message and %w to wrap
the original error (e.g., "ensureClients: failed to get creds: %w"). Use
fmt.Errorf consistently for each failing call site referenced (including the
spots around the r.NewCreds() call and the other locations at the review comment
ranges) so the error chain preserves original error values while adding
operation context.
- Around line 109-117: The early-exit check uses a zero-valued create when
run.Properties.CreateTime is nil, causing create.Before(since) to be true and
prematurely stopping pagination; modify the logic in the block handling
run.Properties.CreateTime so the "if !since.IsZero() && create.Before(since)"
check only runs when run.Properties.CreateTime != nil (i.e., move the since
comparison inside the CreateTime non-nil branch or otherwise skip the
early-return when CreateTime is nil) to avoid skipping newer runs.

---

Nitpick comments:
In `@src/pkg/cli/client/byoc/azure/subscribe_test.go`:
- Around line 251-276: Replace the three repetitive tests
(TestMapRevisionState_NotFound, TestMapRevisionState_Healthy,
TestMapRevisionState_FailedProvisioning) with a single table-driven test that
iterates a slice of cases (each with a name, input *aca.RevisionState, expected
defangv1.ServiceState value, and expected terminal bool), calling
mapRevisionState for each case inside t.Run; include the three cases: nil →
UPDATE_QUEUED/terminal=false, &aca.RevisionState{NotFound:true} →
UPDATE_QUEUED/terminal=false, healthyRevision() →
DEPLOYMENT_COMPLETED/terminal=true, and &aca.RevisionState{ProvisioningState:
armappcontainersv3.RevisionProvisioningStateFailed} →
DEPLOYMENT_FAILED/terminal=true, and assert expected state and terminal for each
case.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 89863da9-0416-4dd9-a371-2c745552b027

📥 Commits

Reviewing files that changed from the base of the PR and between 5c42faa and 209ef0f.

📒 Files selected for processing (6)
  • src/pkg/cli/client/byoc/azure/byoc.go
  • src/pkg/cli/client/byoc/azure/byoc_test.go
  • src/pkg/cli/client/byoc/azure/subscribe.go
  • src/pkg/cli/client/byoc/azure/subscribe_test.go
  • src/pkg/clouds/azure/aca/revisions.go
  • src/pkg/clouds/azure/acr/runs.go

Comment thread src/pkg/cli/client/byoc/azure/subscribe_test.go Outdated
Comment thread src/pkg/cli/client/byoc/azure/subscribe.go
Comment thread src/pkg/clouds/azure/aca/revisions.go
Comment thread src/pkg/clouds/azure/acr/runs.go
Comment thread src/pkg/clouds/azure/acr/runs.go Outdated
@edwardrf edwardrf linked an issue May 19, 2026 that may be closed by this pull request
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.

Azure: support etag, for monitoring (Subscribe API)

2 participants