Skip to content

feat(cost_ccm): add costs ccm recommendations search#543

Open
gm2211 wants to merge 1 commit into
DataDog:mainfrom
gm2211:feat/ccm-recommendations
Open

feat(cost_ccm): add costs ccm recommendations search#543
gm2211 wants to merge 1 commit into
DataDog:mainfrom
gm2211:feat/ccm-recommendations

Conversation

@gm2211
Copy link
Copy Markdown

@gm2211 gm2211 commented May 30, 2026

Summary

Surfaces Datadog Cloud Cost Management recommendations (POST /api/v2/cost/recommendations) via the CLI. CCM optimization recommendations were previously unreachable from pup — the costs ccm subtree covered custom-costs, budgets, commitments, and tags but had no entry point for rightsize / terminate / idle-resource suggestions.

Changes

  • src/main.rs: new CostCcmActions::Recommendations variant + CostCcmRecommendationsActions::Search subcommand with --view, --filter, --sort-by, --order, --page-size, --page-token; dispatched in the Commands::Cost { action } match.
  • src/commands/cost_ccm.rs: recommendations_search async function + build_recommendations_body helper. Client-side validation of --view (active | dismissed | open | in-progress | completed | all) and --order (asc | desc); --order requires --sort-by. Builds the JSON:API envelope (type: recommendations_filter) and uses client::raw_request so the file stays consistent with sibling commands (custom-costs, budgets, etc.).

Testing

cargo fmt --check, cargo clippy --all-targets -- -D warnings, and cargo test --bin pup cost_ccm all pass.

Unit tests (added):

  • test_build_recommendations_body_minimal — happy path with only --view.
  • test_build_recommendations_body_with_sort_default_order--sort-by without --order defaults to desc.
  • test_build_recommendations_body_with_filter_and_sort_asc — full envelope shape with filter + asc sort.
  • test_build_recommendations_body_invalid_view — rejects unknown view.
  • test_build_recommendations_body_invalid_order — rejects unknown order.
  • test_build_recommendations_body_order_without_sort_by — rejects --order without --sort-by.
  • test_recommendations_search_success — mockito-backed end-to-end happy path.
  • test_recommendations_search_invalid_view_errors_before_request — confirms the validation fires before any HTTP call.

Live verification against datadoghq.com:

$ pup --no-agent costs ccm recommendations search --view active --page-size 2
{ "data": [ ... 2 recommendations ... ],
  "meta": { "page": { "next_page_token": "...", "page_size": 2, ... } } }

$ pup --no-agent costs ccm recommendations search \
    --sort-by potential_daily_savings --order desc --page-size 3
# savings amounts come back in descending order

$ pup --no-agent costs ccm recommendations search --view bogus
Error: invalid --view 'bogus'; expected one of: active, dismissed, open, in-progress, completed, all

Notes

  • Scope intentionally limited to search (list). The public SDK exposes a single search_cost_recommendations operation; there is no get-by-id, dismiss, or apply endpoint to wrap.
  • --filter is passed through verbatim to the server. The API accepts a facet-style filter expression; I deliberately did not document a specific syntax in --help because the public API docs do not pin it down. Happy to refine the help text if there's a canonical reference to point at.

Surfaces Datadog Cloud Cost Management recommendations
(POST /api/v2/cost/recommendations) via the CLI. CCM optimization
recommendations were previously unreachable from pup — the `costs ccm`
subtree covered custom-costs, budgets, commitments, and tags but had
no entry point for rightsize / terminate / idle-resource suggestions.

Adds:
- `pup costs ccm recommendations search` with `--view`,
  `--filter`, `--sort-by`, `--order`, `--page-size`, `--page-token`
- Client-side validation of `--view` (active | dismissed | open |
  in-progress | completed | all) and `--order` (asc | desc).
- `--order` requires `--sort-by`; mismatched flags fail before any
  HTTP request.

Implementation matches the existing `cost_ccm.rs` style: builds the
JSON:API envelope manually and uses `client::raw_request` (the typed
SDK method exists as `search_cost_recommendations` but cost_ccm.rs
consistently uses raw requests, so this keeps the file uniform).

Verified live against datadoghq.com:
- Default view returns recommendations + pagination token.
- `--sort-by potential_daily_savings --order desc` returns rows in
  descending order.
- Invalid `--view` fails fast with a clear error.

Tests:
- 6 unit tests on `build_recommendations_body` cover the happy path
  (minimal + filter/sort), default-order behavior, and three error
  branches (invalid view, invalid order, `--order` without
  `--sort-by`).
- 2 mockito-backed tests cover the success path through
  `recommendations_search` and confirm the invalid-view check fires
  before any network call.

cargo fmt, cargo clippy -- -D warnings, and cargo test all pass.
@gm2211 gm2211 requested a review from a team as a code owner May 30, 2026 06:37
Comment thread src/commands/cost_ccm.rs
let resp = client::raw_request(
cfg,
"POST",
"/api/v2/cost/recommendations",
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Should this already be in the SDK? Instead of maintaining 2 mappings

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