Skip to content

Upgrading

Upgrading the exporter safely means checking a few things before and after each release; this page covers those steps. It also documents the deliberate, one-time breaking changes made immediately before 1.0, so dashboards and alerts built against pre-1.0 metric names can be migrated cleanly.

If you only read one thing: the 1.0 release includes a single, deliberate breaking sweep of metric names and labels. After 1.0, Stable metrics only change through the dual-publish deprecation window in the Metric Stability & Deprecation Policy.

How to upgrade

The exporter ships as a Docker image and a Helm chart, both published per release (see the Release Process). Upgrading is a matter of moving to the new image tag.

  1. Read the Changelog first. Every release's breaking changes, renames, and deprecations are listed there. Do this before bumping the tag - it is where breaking metric and configuration changes are announced (see Where breaking changes are announced).
  2. Pin to a specific version tag, not :main (which is a rolling edge build). Use the vX.Y.Z release tag for reproducible upgrades.
  3. Roll out to a non-production instance first if you run one, scrape it, and confirm your dashboards and alert rules still resolve against the new metric surface.
  4. Apply the new tag to production. The exporter is stateless (all state is derived from the Meraki API on each collection cycle), so a rolling restart is safe - there is no migration step or persistent store to convert.

Verify image signatures

Release images and charts are signed. See Security for how to verify signatures before deploying.

Changes at 1.1

Configuration compatibility changes

Review these settings before deploying 1.1; several configurations accepted by 1.0.2 are now refused or behave differently:

  • meraki.api_base_url must use HTTPS. Local HTTP mock endpoints and plaintext proxies are no longer accepted.
  • A base URL outside the built-in Meraki regional URL set requires meraki.allow_custom_api_base_url=true. Corporate proxies and egress gateways must opt in and must still expose an HTTPS URL.
  • collectors.collector_timeout must be at least api.per_fetch_deadline_seconds; values from 30 through 119 seconds therefore fail with the shipped 120-second fetch deadline.
  • Disabling every collector is refused. This also means a webhook-receiver-only deployment must leave at least one collector enabled.
  • An active network_filter that resolves successfully to no networks is refused.
  • Enabling the webhook receiver with webhooks.require_secret=false is refused unless webhooks.allow_insecure=true explicitly acknowledges the unauthenticated configuration. The recommended action is to configure webhooks.shared_secret and keep secret validation enabled.
  • api.rate_limit_burst now defaults to 10 instead of 20.
  • The effective global collector concurrency may be lower than collectors.max_concurrent_collectors because it is bounded by SDK executor capacity. With the shipped api.executor_workers=10 and api.concurrency_limit=5, the effective cap is 2.
  • The two control POST endpoints require server.api_token, as detailed below.

In adaptive scheduler mode, an unset collection profile continues to collect the full endpoint-group surface while the solved full plan fits the effective API-budget target. Above that shape-aware threshold, startup refuses to proceed until MERAKI_EXPORTER_COLLECTORS__PROFILE is set explicitly to availability (priority 1), standard (priorities 1–3), or full (all priorities). The error reports the estimated demand and budget target. The selected profile is then solved honestly: if it still exceeds budget, priorities 1 and 2 keep their volatility floors while lower-priority groups are shed, and meraki_exporter_scheduler_over_budget remains alertable. Fixed scheduler mode never applies this adaptive profile-selection gate.

The API client also strips its Authorization header on every cross-origin redirect, including when a custom API base URL was explicitly allowed. Proxies must complete authenticated redirects without forwarding the Meraki credential to a different origin.

Network filtering and collected series

NetworkFilter is now applied before switch port and power data is emitted. If a switch's network is excluded, its meraki_ms_port_* and meraki_ms_power_* series disappear after upgrading; this is the intended correction. Update alerts or dashboards that previously depended on those leaked series, or include the network in the filter. Network inventory, device collection, and endpoint group cost calculations now use the same filtered network set.

Self-observability metric semantics

  • meraki_exporter_api_requests_total{endpoint,method,status_code} counts outbound SDK request attempts, including retries. method is derived from the SDK operation. status_code contains HTTP status values only; calls that fail without an HTTP response are represented by meraki_exporter_api_request_attempts_total{operation,status="exception"} instead of placing an exception name in status_code. A facade-owned 429 retry increments meraki_exporter_api_retry_total once per retry.
  • Endpoint-group last-success and scheduler-run state advance only after the owning endpoint group succeeds. A group with no applicable work is neither a success nor an endpoint failure, while an attempted group with no explicit success remains fail-closed. This can make old false-success timestamps stop advancing.
  • The shared task-admission metrics meraki_exporter_tasks_active, meraki_exporter_tasks_pending, meraki_exporter_task_queue_wait_seconds, and meraki_exporter_task_expired_before_start_total use bounded phase values: collector_admission for whole collector runs and task_group for bounded child work. They describe exporter scheduling pressure, not Meraki endpoint failures.
  • Reverse-DNS timeouts increment meraki_exporter_client_dns_lookups_timeout_total; other resolver failures increment meraki_exporter_client_dns_lookups_failed_total, never both for one lookup. meraki_exporter_client_dns_queue_depth is the peak producer backlog from the most recently started completed batch, with overlapping older batches prevented from overwriting newer data.

meraki_exporter_cardinality_product_series now counts only meraki_* product-data samples. Exporter instrumentation and Python/process runtime samples move to the new meraki_exporter_cardinality_exporter_series bucket; the cardinality monitor's own samples remain in meraki_exporter_cardinality_self_series. The three buckets still reconcile exactly to meraki_exporter_cardinality_exposed_series and the compatibility alias meraki_exporter_total_series.

Webhook metrics now separate authenticated deliveries from unique accepted alerts: meraki_webhook_delivery_attempts_total includes Meraki retries, meraki_webhook_unique_alerts_total counts first acceptance, and meraki_webhook_replays_rejected_total counts TTL-cache duplicates. Deliveries outside the configured freshness window are acknowledged without applying device state and increment meraki_webhook_stale_rejected_total. The bounded replay cache is per process, so deduplication is not shared between replicas or retained across restarts.

Breaking changes at 1.0

The 1.0 release carries a one-time, pre-1.0 breaking sweep. This churn is explicitly permitted by, and described in, the Metric Stability & Deprecation Policy - it happens exactly once so that the disruptive renames land before the compatibility promise takes effect, rather than trickling out afterwards.

Metric name and unit renames

Metric names were corrected so that suffixes and units are consistent and base-SI:

  • _total suffixes now denote only true monotonic counters. Windowed and snapshot gauges that previously carried _total were renamed to _count or bare-plural forms, with any measurement window documented in the metric's # HELP.
  • Non-base units were converted to base-SI (bytes, seconds, joules). The only retained non-base units are the documented exceptions that carry their unit in the name: device memory in KiB (binary ×1024), link speed as _mbps, and the radio-native _mhz / _dbm units.
  • _percent and other unit suffixes were standardised.

The authoritative, per-metric list of current names, labels, and units is the generated Complete Metrics Reference. Diff your dashboard and alert queries against it after upgrading.

Mutable name labels moved to _info join metrics

Mutable, human-readable name labels - org_name, network_name, device name, port_name, description, hostname, and similar - were dropped from numeric metric series and moved onto id-keyed *_info join metrics. Per-client series were reduced to ID-only.

This was done because a rename (of an org, network, or port) would otherwise change the label set of every affected series, starting a new Prometheus time series and orphaning the old one - breaking rate() / increase() continuity. Keying numeric series by the stable ID and carrying the mutable name on a separate _info metric means a rename touches exactly one info series instead of the whole fleet.

What you must change: any query or dashboard panel that selected or displayed a name label directly off a numeric series. Join to the info metric on the ID to pull the name back in:

meraki_device_up
  * on (serial) group_left (name)
  meraki_device_status_info

The same pattern applies to organizations (on (org_id) group_left (org_name) meraki_org_info) and to clients (join to meraki_client_info). The info carriers are meraki_org_info, meraki_device_status_info, meraki_network_info, meraki_ms_port_info, meraki_mv_zone_info, and meraki_client_info. Full detail is in the stability policy's Name labels are not part of numeric series section.

Single-org deployment contract (BREAKING)

From 1.0, each exporter instance polls exactly one Meraki organization (1 poller = 1 org). This is a deliberate breaking change: it makes each instance's rate-limit budget, inventory cache, and metric cardinality well-defined and scoped to a single organization, so per-instance capacity can be reasoned about.

How the organization is resolved at startup:

  • MERAKI_EXPORTER_MERAKI__ORG_ID set - the exporter polls that organization. This is the recommended production configuration.
  • org_id unset and the API key sees exactly one organization - that organization is auto-selected and the exporter starts normally, so a single-org key needs no org_id.
  • org_id unset and the API key sees several organizations - the exporter fails fast at startup (it aborts before serving) with an error listing the visible organizations and telling you to set MERAKI_EXPORTER_MERAKI__ORG_ID to one of them.

What changed: previously an unset org_id caused the exporter to discover and poll every organization the API key could see. That multi-org polling behaviour is gone. If you relied on a single instance covering multiple organizations, split it into one instance per organization (shard by org). See the Scaling Guide for shard-by-org / HA recipes and the Helm chart's multi-instance example (charts/meraki-dashboard-exporter) for running one release per organization, and the Configuration reference for the org_id key.

Control API now requires an API token (BREAKING)

The manual Run Now and Clear DNS Cache controls, and their POST endpoints (/api/collectors/trigger and /api/clients/clear-dns-cache), now fail closed when server.api_token is unset. Tokenless requests return HTTP 401 and the UI controls are disabled with a configuration tooltip. Configure MERAKI_EXPORTER_SERVER__API_TOKEN and have API clients or the authenticating reverse proxy supply Authorization: Bearer <token>. There is no unauthenticated compatibility flag. /metrics, /health, and /ready are unchanged.

Startup configuration validation

The exporter now adds six deterministic configuration refusals before serving: a non-HTTPS API base URL, a custom API base URL without the explicit opt-in, an active Network Filter that successfully resolves to zero networks, no effective enabled collectors, a MERAKI_EXPORTER_COLLECTORS__COLLECTOR_TIMEOUT lower than MERAKI_EXPORTER_API__PER_FETCH_DEADLINE_SECONDS, or an invalid profile value. Each error names the setting to correct. Temporary Meraki API failures during startup verification do not abort the process; collection loops continue and retry when the API recovers.

Where breaking changes are announced

Breaking metric and configuration changes are announced in the Changelog, which is generated from Conventional Commits by release-please (see the Release Process).

The conventions the project follows so you can spot them:

  • Breaking changes are flagged with a ! in the commit type (e.g. feat(metrics)!: ...) or a BREAKING CHANGE: footer. These surface as a dedicated breaking-changes section in the changelog for that release and drive the semantic-version bump.
  • Metric deprecations and removals are called out in the changelog and follow the dual-publish deprecation window described in the Metric Stability & Deprecation Policy: a Stable metric is emitted under both the old and new name for at least one full minor release before the old name is removed, and the old metric's # HELP is prefixed with a DEPRECATED: note naming the replacement.

Always read the changelog entry for the version you are moving to before upgrading production.