Skip to content

fix(scheduler): extend ambient host-account UUID tagging to Azure/GCP - #725

Merged
cristim merged 2 commits into
feat/multicloud-web-frontendfrom
fix/662-scheduler-tagging-azure-gcp
May 27, 2026
Merged

fix(scheduler): extend ambient host-account UUID tagging to Azure/GCP#725
cristim merged 2 commits into
feat/multicloud-web-frontendfrom
fix/662-scheduler-tagging-azure-gcp

Conversation

@cristim

@cristim cristim commented May 25, 2026

Copy link
Copy Markdown
Member

Closes #662. Mirrors PR #607's AWS pattern for the two non-AWS providers.

Defect

collectAzureRecommendations and collectGCPRecommendations returned nil, nil, nil when no accounts were registered — no ambient fallback path, breaking downstream attribution. AWS already had the fallback via PR #607.

Changes (internal/scheduler/scheduler.go)

  1. resolveAmbientAccountID(ctx, provider, externalID string) string — provider-agnostic helper that looks up (provider, externalID) in cloud_accounts and returns the UUID or "". Errors swallowed (logged at WARN), mirroring the AWS resolveAmbientHostAccountID design.

  2. collectAzureAmbient(ctx, subscriptionID string) — creates an Azure provider via the injected factory (testable via mock) with the subscription ID pre-set to avoid an unnecessary auto-discovery API call.

  3. collectGCPAmbient(ctx) — creates a GCP provider via the injected factory using ADC.

  4. collectAzureRecommendations extended — when len(accounts) == 0 and AZURE_SUBSCRIPTION_ID is set, falls back to ambient credentials and tags recs with the registered subscription UUID if found.

  5. collectGCPRecommendations extended — same pattern using GCP_PROJECT_ID.

Tests (+10, 92 total in scheduler)

  • Azure: happy path, no registered row, store error, env var absent
  • GCP: happy path, no registered row, store error, env var absent
  • resolveAmbientAccountID: empty externalID guard, store error swallowed

go vet + gofmt clean.

Summary by CodeRabbit

  • New Features

    • Automatic ambient cloud detection for Azure and GCP recommendations: when runtime environment is configured, recommendations collected from ambient environments will be tagged with the matching registered cloud account ID if present; otherwise they preserve prior ambient behavior.
  • Tests

    • Added tests covering ambient detection and tagging across success, missing-account, error, and env-var-absent scenarios.

Review Change Stack

Issue #662: Azure and GCP lacked an ambient-credential fallback path when
no cloud accounts were registered. Unlike AWS (which PR #607 already fixed),
they silently returned empty rather than falling back to the host identity.

This commit extends the #607 pattern to both providers:

- Adds resolveAmbientAccountID: a provider-agnostic helper that looks up
  (provider, externalID) in cloud_accounts and returns the UUID, or "" for
  truly-orphan deployments. Errors are swallowed (logged at WARN) so a DB
  blip never fails the collection.

- Adds collectAzureAmbient: ambient path via providerFactory for Azure,
  accepting the subscription ID explicitly to skip the API round-trip that
  would otherwise auto-discover subscriptions.

- Adds collectGCPAmbient: ambient path via providerFactory for GCP (ADC).

- Extends collectAzureRecommendations: when no accounts are registered and
  AZURE_SUBSCRIPTION_ID is set, falls back to ambient credentials and tags
  recs with the registered subscription UUID if found in cloud_accounts.

- Extends collectGCPRecommendations: same pattern using GCP_PROJECT_ID.

Eight new tests covering: happy path (UUID tagged), no registered row (nil
preserved), store error (nil preserved, collection succeeds), env var absent
(skips gracefully), plus two unit tests for resolveAmbientAccountID itself.

Closes #662
@cristim cristim added triaged Item has been triaged priority/p2 Backlog-worthy severity/medium Moderate harm urgency/this-quarter Within the quarter impact/few Limited audience effort/s Hours type/bug Defect labels May 25, 2026
@coderabbitai

coderabbitai Bot commented May 25, 2026

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 0cb2c362-c871-4469-bc9f-7d81bccd6a5a

📥 Commits

Reviewing files that changed from the base of the PR and between be588db and daa9af0.

📒 Files selected for processing (1)
  • internal/scheduler/scheduler_test.go

📝 Walkthrough

Walkthrough

The PR extends ambient-path host-account UUID tagging to Azure and GCP collectors, mirroring the fix applied to AWS in PR #607. A new resolveAmbientAccountID helper looks up registered accounts by provider and external ID, while new ambient collection helpers fetch recommendations without enabled account constraints. Both collectors now perform ambient collection when no enabled accounts exist and the corresponding environment variables are set, then tag results with resolved account UUIDs.

Changes

Ambient account tagging for Azure and GCP

Layer / File(s) Summary
Ambient account resolution infrastructure
internal/scheduler/scheduler.go, internal/scheduler/scheduler_test.go
resolveAmbientAccountID helper looks up cloud_accounts UUID by provider and external ID, gracefully handling empty inputs and store errors by returning "". New collectAzureAmbient and collectGCPAmbient create validated ambient providers and convert recommendations into scheduler records. Unit tests verify empty external IDs skip store access and lookup errors are absorbed.
Azure recommendations with ambient tagging
internal/scheduler/scheduler.go, internal/scheduler/scheduler_test.go
collectAzureRecommendations checks AZURE_SUBSCRIPTION_ID when no enabled accounts exist, skips if unset, otherwise collects ambient recommendations and tags them via resolveAmbientAccountID. Tests cover successful tagging when a registered account exists by external ID, nil tagging when lookup finds no match or fails, and verified skipping when env var is absent.
GCP recommendations with ambient tagging
internal/scheduler/scheduler.go, internal/scheduler/scheduler_test.go
collectGCPRecommendations checks GCP_PROJECT_ID when no enabled accounts exist, skips if unset, otherwise collects ambient recommendations and tags them via resolveAmbientAccountID. Tests cover successful tagging when a registered account exists by external ID, nil tagging when lookup finds no match or fails, and verified skipping when env var is absent.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • LeanerCloud/CUDly#603: Scheduler ambient-path changes populate CloudAccountID in collected recommendations used by single-account execution logic that derives per-account credentials.
  • LeanerCloud/CUDly#607: Implemented the same ambient account UUID tagging pattern for AWS collectors; this PR extends that pattern to Azure and GCP.

Suggested labels

impact/internal

Poem

🐰 I hopped through clouds with scholarly cheer,
Tagged ambient hosts both far and near,
Azure and GCP now wear their name,
UUIDs snug—no more orphaned frame,
The scheduler hums along, all clear.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and accurately summarizes the main change: extending ambient host-account UUID tagging to Azure/GCP collectors, which is the primary objective of the PR.
Linked Issues check ✅ Passed The PR fully addresses issue #662: it confirms Azure/GCP collectors have the same nil-host-account behavior as AWS, and extends the UUID tagging fix to both platforms via resolveAmbientAccountID, collectAzureAmbient, collectGCPAmbient helpers, with comprehensive test coverage.
Out of Scope Changes check ✅ Passed All changes are scoped to extending the ambient host-account UUID tagging fix to Azure and GCP collectors; no unrelated changes or broader refactoring is present.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ 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 fix/662-scheduler-tagging-azure-gcp

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

@cristim

cristim commented May 25, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 25, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@cristim

cristim commented May 26, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 26, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@cristim

cristim commented May 26, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 26, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@cristim

cristim commented May 26, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 26, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@cristim

cristim commented May 26, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 26, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
internal/scheduler/scheduler_test.go (1)

2202-2202: ⚡ Quick win

Tighten Azure factory expectations to lock in the subscription pre-set contract.

These Azure ambient tests currently use permissive mock.Anything matchers, so they won’t fail if the code stops passing "azure" or the expected AzureSubscriptionID in ProviderConfig.

Suggested test hardening
- mockFactory.On("CreateAndValidateProvider", mock.Anything, mock.Anything, mock.Anything).Return(mockProvider, nil)
+ mockFactory.On(
+   "CreateAndValidateProvider",
+   mock.Anything,
+   "azure",
+   mock.MatchedBy(func(cfg *provider.ProviderConfig) bool {
+     return cfg != nil && cfg.AzureSubscriptionID == "sub-abc-123"
+   }),
+ ).Return(mockProvider, nil)

Apply the same pattern to the other Azure ambient tests with their respective subscription IDs.

Also applies to: 2246-2246, 2281-2281

🤖 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 `@internal/scheduler/scheduler_test.go` at line 2202, The test uses permissive
mock.Anything for mockFactory.On("CreateAndValidateProvider", ...) which allows
regressions; update the expectation to assert the provider type and subscription
ID are passed: call mockFactory.On("CreateAndValidateProvider",
ctxMatcher/anythingMatcher for context, mock.MatchedBy(func(cfg ProviderConfig)
bool { return cfg.Type == "azure" && cfg.AzureSubscriptionID ==
"<expected-subscription-id>" }), mock.Anything).Return(mockProvider, nil) (or
the equivalent matcher in your test framework) and apply the same change for the
other Azure ambient test cases (lines referencing CreateAndValidateProvider at
the other noted locations) so each test locks to the correct "azure" string and
the specific AzureSubscriptionID constant.
🤖 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.

Nitpick comments:
In `@internal/scheduler/scheduler_test.go`:
- Line 2202: The test uses permissive mock.Anything for
mockFactory.On("CreateAndValidateProvider", ...) which allows regressions;
update the expectation to assert the provider type and subscription ID are
passed: call mockFactory.On("CreateAndValidateProvider",
ctxMatcher/anythingMatcher for context, mock.MatchedBy(func(cfg ProviderConfig)
bool { return cfg.Type == "azure" && cfg.AzureSubscriptionID ==
"<expected-subscription-id>" }), mock.Anything).Return(mockProvider, nil) (or
the equivalent matcher in your test framework) and apply the same change for the
other Azure ambient test cases (lines referencing CreateAndValidateProvider at
the other noted locations) so each test locks to the correct "azure" string and
the specific AzureSubscriptionID constant.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e5143d41-a4c7-4208-aa3d-0c7c82b758fe

📥 Commits

Reviewing files that changed from the base of the PR and between 5abf40b and be588db.

📒 Files selected for processing (2)
  • internal/scheduler/scheduler.go
  • internal/scheduler/scheduler_test.go

Replace permissive mock.Anything matchers in the three Azure ambient-tagging
tests with mock.MatchedBy checks that assert both the provider type ("azure")
and the exact AzureSubscriptionID each test wires via AZURE_SUBSCRIPTION_ID.
This locks in the field-level contract so a future regression (wrong provider
name or wrong subscription routed to the factory) would be caught immediately.

Resolves CodeRabbit nitpick on PR #725.
@cristim

cristim commented May 26, 2026

Copy link
Copy Markdown
Member Author

Addressed the nitpick from the 2026-05-26 review pass.

All three Azure ambient-tagging tests now use strict matchers instead of mock.Anything for both the provider-type and config arguments:

  • TestScheduler_CollectAzureRecommendations_AmbientTagging_HappyPath (line 2202): asserts provider = "azure" and cfg.AzureSubscriptionID == "sub-abc-123"
  • TestScheduler_CollectAzureRecommendations_AmbientTagging_NoRegisteredAccount (line 2248): asserts provider = "azure" and cfg.AzureSubscriptionID == "sub-unregistered"
  • TestScheduler_CollectAzureRecommendations_AmbientTagging_StoreError (line 2285): asserts provider = "azure" and cfg.AzureSubscriptionID == "sub-abc-123"

Commit: daa9af0. All 6 TestScheduler_CollectAzure* tests remain green.

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 26, 2026

Copy link
Copy Markdown
Contributor

@cristim: Thanks for tightening those matchers — verifying both provider == "azure" and cfg.AzureSubscriptionID explicitly is exactly the right level of precision for this kind of factory-injection test. Triggering a fresh review now.

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@cristim

cristim commented May 26, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 26, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@cristim

cristim commented May 26, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 26, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@cristim

cristim commented May 26, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 26, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@cristim

cristim commented May 26, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 26, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@cristim

cristim commented May 26, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 26, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@cristim

cristim commented May 26, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 26, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@cristim

cristim commented May 26, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 26, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@cristim

cristim commented May 26, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 26, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@cristim

cristim commented May 26, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 26, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@cristim

cristim commented May 26, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 26, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@cristim
cristim merged commit 4add718 into feat/multicloud-web-frontend May 27, 2026
4 checks passed
@cristim

cristim commented May 27, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 27, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

effort/s Hours impact/few Limited audience priority/p2 Backlog-worthy severity/medium Moderate harm triaged Item has been triaged type/bug Defect urgency/this-quarter Within the quarter

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant