Skip to content

Azure Optimizations

The Azure Optimizations module scans your Azure subscription for cost reduction opportunities using Azure Monitor metrics and Azure Pricing. It stores findings in dedicated az_* tables in the shared PostgreSQL database and surfaces them in the Strawly UI.

What it scans

The module identifies two types of opportunity across supported resource types:

  • Downsize — resources provisioned above their actual usage that can move to a smaller SKU
  • Terminate — idle or unused resources that can be stopped or deleted
Resource type Downsize Terminate Details
App Service Plans Yes Yes App Service Plans
Managed Disks Yes Yes Managed Disks
SQL Databases Yes Yes SQL Databases
Virtual Machines Yes Yes Virtual Machines

Additional resource types are added in new releases.

Enable the module

  1. Open strawly-deployment.yml and set enabled: true:

    modules:
      optimizations-azure:
        enabled: true
        port: 3002
    
  2. Regenerate, redeploy, and refresh the module registry:

    npm run generate-compose
    docker compose -f docker-compose.generated.yml pull
    docker compose -f docker-compose.generated.yml up -d
    npm run seed-modules
    
  3. Verify the module is running:

    curl http://localhost:3002/health
    

    Expected response:

    {
      "status": "ok",
      "service": "optimizations-azure",
      "timestamp": "2026-05-17T03:00:00.000Z"
    }
    
  4. Open Settings > Credentials in the Strawly UI and enter your Service Principal credentials: tenant ID, client ID, client secret, and subscription ID. The Service Principal must have the Reader and Monitoring Reader roles on the target subscription. Credentials are encrypted before being stored in the database.

Scan types

The module runs four kinds of scan, each on its own schedule and each with its own manual trigger:

  • Inventory — lists the resources in your subscriptions and stores them in the az_* inventory tables. A run first syncs the subscription list, then scans each resource type.
  • Metrics — pulls Azure Monitor metrics (CPU, memory, and so on) for the scanned resources and writes one row per resource per day.
  • Recommendations — reads the metrics tables and produces the downsize and terminate opportunities.
  • Pricing — refreshes Azure retail prices so savings figures stay current.

All four behave the same way: configure a schedule for automatic runs, or trigger an immediate run from the same UI.

Where to configure scans

Open Settings > Modules and select Azure. Schedules and manual runs are split across two views:

  • Provider view (Azure selected, no resource type chosen) holds the global schedules and global manual runs. This is where you set the Inventory, Recommendations, and Pricing schedules, the global Metrics schedule, and where you run all enabled resource types at once.
  • Resource-type view (a resource type such as Virtual Machines or App Service Plans selected) holds per-resource settings: a Metrics schedule override and per-resource manual runs for Inventory and Metrics.

Schedules

No schedule is set by default. Nothing runs automatically until you set one. For each scan, pick a preset (Daily, Weekly, Monthly, or Custom cron). Schedules are saved immediately and the scheduler re-reads them within 60 seconds, so no redeploy is needed. To stop automatic runs, set the schedule back to None.

Global schedules

In the provider view you set one schedule per scan type:

  • Inventory — applies to every enabled resource type. Each run syncs subscriptions first, then scans the enabled types.
  • Metrics — the global default used by every enabled resource type that has not set its own override.
  • Recommendations and Pricing — apply to the whole Azure module.

Per-resource Metrics override

In the resource-type view, the Metrics schedule defaults to Follow global, meaning the resource inherits the global Metrics schedule. Pick a preset to give that resource type its own cadence instead, and choose how much data each run collects (last day, last 7 days, or last 30 days). Switch back to Follow global to drop the override.

Inventory, Recommendations, and Pricing do not have per-resource schedules; they run on the global schedules only.

Manual runs

Every scan type can be triggered immediately. A manual run streams its log live and is recorded in the run history alongside scheduled runs.

  • Global manual runs (provider view): Run now runs Inventory across all enabled resource types (syncing subscriptions first). Sync subscriptions updates only the subscription list without collecting inventory. Recommendations and Pricing each have their own Run now.
  • Per-resource manual runs (resource-type view): each resource type has its own Run now for Inventory and for Metrics. Metrics runs let you pick a preset or a custom date range (up to 30 days, ending no later than yesterday).

Recommendation lifecycle

Each recommendation moves through a set of statuses as the team reviews and acts on it. User-settable statuses (In Review, Planned, Snoozed, Ignored) represent team intent. Engine-set statuses (New, Grouped, Resurfaced, Dismissed, Implemented) are set automatically. Implemented is detected by comparing the current Azure estate against the recommended or agreed change on each engine run, and drives the realized savings calculation. Resources can be exempted from specific recommendation types so the engine does not create new recommendations for them.

See Recommendation statuses for the full status reference, transition rules, and guidance on snooze vs ignored, dismissed vs ignored, tier overrides, and resource exemptions.

What runs depends on enabled modules

Both scheduled and manual runs collect data only from enabled modules:

  • Inventory and Metrics scan only the resource types you have enabled. A run for a disabled resource type is skipped.
  • Recommendations and Pricing run whenever the Azure module itself is enabled. Pricing collects prices for all supported resource types regardless of which are enabled, since prices are needed to value any opportunity.
  • If the Azure module is disabled, scheduled runs are skipped entirely.

Pricing and negotiated discounts

All savings are computed from Azure public retail prices, collected by the Pricing scan. If your organisation buys Azure at a discount, configure the percentage in the Discounts section of the Azure provider view, or per resource type for an agreement that prices service families differently.

See Negotiated discounts for how the rate is applied, why it reduces potential savings as well as cost, and how effective dating keeps already-reported savings from being restated.