> This page is for NVIDIA Infra Controller.

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.nvidia.com/infra-controller/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.nvidia.com/infra-controller/_mcp/server.

## Expected Switch NVOS declarations — unreleased

### REST API compatibility exception

The Expected Switch primary-port change tracked in [issue #7310](https://github.com/dsx-ai-factory/infra-controller/issues/7310) intentionally tightens the REST create and replace-all contracts:

* `POST /v2/org/{org}/nico/expected-switch` requires a non-empty `nvosInterfaces` array.
* `PUT /v2/org/{org}/nico/expected-switch/all` requires a non-empty `nvosInterfaces` array in every `expectedSwitches` entry. An empty top-level `expectedSwitches` array still clears the inventory.

Omitting a port set or supplying an empty one returns HTTP 400. This is a breaking-change exception: zero-port declarations cannot initialize successfully because Site Explorer no longer fills or overwrites operator-declared NVOS ports. Existing zero-port records are not repaired automatically.

Before deploying this change, update clients and inventory templates to send `nvosInterfaces` entries with `macAddress` and select the primary (eth0) port with `isPrimary: true`. REST defaults the first entry to primary if none is marked; a single port is always primary. For example, the port field can be:

```json
{
  "nvosInterfaces": [
    { "macAddress": "02:00:00:00:00:01", "isPrimary": true }
  ]
}
```

The deprecated `nvosMacAddresses` request field remains accepted but ignored regardless of its JSON value; it does not satisfy the new requirement. This also breaks clients that relied on that field to configure ports. Sending both fields is allowed, but only `nvosInterfaces` takes effect. PATCH requests may omit `nvosInterfaces` to preserve stored ports; an explicit empty array is rejected.

### Client and inventory-file migration

Update automation that uses the old NVOS names:

| Surface                                           | Old name             | Replacement and behavior                                                                                                                                                                          |
| ------------------------------------------------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| REST requests                                     | `nvosMacAddresses`   | Use `nvosInterfaces` objects with `macAddress` and `isPrimary`. The old field is ignored, including on PATCH; an otherwise valid legacy-only PATCH can succeed without changing ports.            |
| REST responses                                    | `nvosMacAddresses`   | Read `nvosInterfaces` for primary selection. Responses still include the deprecated flat `nvosMacAddresses` list; it has not been removed.                                                        |
| `nico-admin-cli expected-switch add` and `update` | `--nvos-mac-address` | Use repeated `--nvos-interface MAC[,primary]` flags. Append `,primary` to the eth0 MAC. The old flag has no alias and is rejected.                                                                |
| `nico-admin-cli expected-switch replace-all` JSON | `nvos_mac_addresses` | Use `nvos_interfaces` objects with `mac_address` and `is_primary`. An old-only file is rejected for missing `nvos_interfaces` before the replacement RPC is sent; it does not clear stored ports. |

The CLI replacement file uses snake_case, not the REST API's camelCase. Its top-level object contains an `expected_switches` array. Each entry requires `bmc_mac_address`, `bmc_username`, `bmc_password`, `switch_serial_number`, and a non-empty `nvos_interfaces` array. For example:

```json
{
  "expected_switches": [
    {
      "bmc_mac_address": "02:00:00:00:00:10",
      "bmc_username": "admin",
      "bmc_password": "REPLACE_WITH_BMC_PASSWORD",
      "switch_serial_number": "SWITCH-001",
      "nvos_interfaces": [
        { "mac_address": "02:00:00:00:00:01", "is_primary": true },
        { "mac_address": "02:00:00:00:00:02", "is_primary": false }
      ]
    }
  ]
}
```

Protect this file because it contains credentials. `is_primary` defaults to `false`; if no entry is marked, the CLI selects the first port. More than one marked primary is rejected. The optional top-level `expected_switches_count` must equal the array length when supplied. Replacement removes records omitted from the file; `{"expected_switches": []}` clears the entire expected-switch inventory.

## DPF provisioning: Site Explorer suppression

[PR #7775](https://github.com/dsx-ai-factory/infra-controller/pull/7775) pauses periodic Site Explorer scans during DPF provisioning. Report-refresh requests are saved and return the cached report marked as pending. Periodic scans and queued refreshes run after all Site Explorer suppressions are cleared. Re-exploration requests are rejected rather than queued; operators must retry them after suppression clears.

### Upgrade compatibility

Older `nico-api` binaries cannot decode suppression rows with source `dpf_provisioning`. While these rows exist, an older replica fails its Site Explorer suppression read and cannot complete exploration cycles.

Upgrade every `nico-api` replica before starting DPF provisioning. At sites already using DPF, plan an API maintenance window: stop all old replicas before starting updated replicas. The default rolling update can overlap old and new binaries and does not meet this requirement.

When upgrading from a version without this feature, machines already provisioning are not retroactively suppressed. Suppression is created when a managed host transitions from having no DPU in `WaitingForReady` or `HandleReboot` to having at least one DPU in either state. Existing suppression rows remain effective across restarts.

### Downgrading to a binary without DPF suppression support

Stop all updated `nico-api` replicas first, so their controllers cannot recreate the suppression rows. Then run this statement against the NICo Core database before starting older replicas:

```sql
DELETE FROM bmc_suppressions
WHERE source = 'dpf_provisioning';
```

This preserves suppression rows owned by other workflows. Removing these rows clears the DPF exploration pause; it does not stop provisioning by the DPF operator.