ONTAP automation hub

Choose the interface that matches the job: Ansible for convergent configuration, Terraform for lifecycle-managed infrastructure, PowerShell for Windows operations, and Python or direct REST for custom workflows. All current paths converge on ONTAP's HTTPS REST API; keep legacy ZAPI/ONTAPI only while a required operation still lacks a supported replacement.

Automation tools flowing through ONTAP REST to a cluster

The automation landscape

ToolBest fitState model
Ansible netapp.ontapRepeatable configuration and orchestrationModule compares desired and actual state
NetApp ONTAP Terraform providerProvisioned objects owned by a Terraform statePlan/state lifecycle
PowerShell ToolkitInteractive and scheduled Windows administrationImperative cmdlets
netapp-ontap Python clientApplications, checks, custom workflow logicCode-defined
REST/curlDebugging and thin integrationsCaller-defined

REST details, pagination and asynchronous jobs live in the ONTAP REST API guide; this page focuses on tool choice and production patterns.

REST is the foundation

ONTAP resources are below https://cluster-mgmt/api, not /api/v1. The endpoint's OpenAPI UI is normally at /docs/api. Basic authentication is supported; beginning with ONTAP 9.14, OAuth 2.0 bearer tokens come from an external authorization server. /api/security/authentication/login is not the documented ONTAP token-issuance workflow—check your product and release if an example shows it.

export ONTAP_HOST=cluster1.example.com
export ONTAP_USER=svc_automation
read -s ONTAP_PASSWORD
curl --fail --silent --show-error --user "$ONTAP_USER:$ONTAP_PASSWORD" \
  "https://$ONTAP_HOST/api/storage/volumes?name=app_data&fields=name,size,state,svm"
{"records":[{"name":"app_data","size":107374182400,"state":"online","svm":{"name":"svm_app"}}],"num_records":1}
curl --fail --silent --show-error \
  -H "Authorization: Bearer $ONTAP_TOKEN" -H "Accept: application/json" \
  "https://$ONTAP_HOST/api/cluster?fields=name,version"
{"name":"cluster1","version":{"full":"NetApp Release 9.19.1"}}

Use a trusted CA bundle; -k is acceptable only for an isolated first test. REST has evolved by ONTAP release through resource and field additions rather than a public v1/v2 URL switch. Inspect the target cluster's API documentation and release notes, request only needed fields, and treat deprecated ONTAPI/ZAPI calls as migration work.

Ansible: convergent configuration

Install the official collection, keep connection values in inventory or encrypted variables, and prefer REST-capable modules. The collection documents na_ontap_volume, na_ontap_svm, na_ontap_lun and na_ontap_snapmirror.

$ ansible-galaxy collection install netapp.ontap
Starting galaxy collection install process
netapp.ontap:23.1.0 was installed successfully
# inventory/host_vars/cluster1.yml — password supplied by Vault
ansible_host: cluster1.example.com
ontap_username: svc_ansible
ontap_password: "{{ vault_ontap_password }}"
ontap_https: true
ontap_validate_certs: true
- name: Build application storage
  hosts: ontap
  gather_facts: false
  collections: [netapp.ontap]
  tasks:
    - name: Ensure SVM exists
      na_ontap_svm:
        state: present
        name: svm_app
        root_volume: svm_app_root
        root_volume_aggregate: aggr1
        hostname: "{{ ansible_host }}"
        username: "{{ ontap_username }}"
        password: "{{ ontap_password }}"
        https: true
        validate_certs: true
        use_rest: always
    - name: Ensure 500 GiB volume exists
      na_ontap_volume:
        state: present
        vserver: svm_app
        name: app_data
        aggregate_name: aggr1
        size: 500
        size_unit: gb
        junction_path: /app_data
        space_guarantee: none
        hostname: "{{ ansible_host }}"
        username: "{{ ontap_username }}"
        password: "{{ ontap_password }}"
        https: true
        validate_certs: true
        use_rest: always
- name: Ensure database LUN and mirror exist
  block:
    - netapp.ontap.na_ontap_lun:
        state: present
        vserver: svm_app
        name: /vol/app_data/db01
        size: 200
        size_unit: gb
        ostype: linux
        hostname: "{{ ansible_host }}"
        username: "{{ ontap_username }}"
        password: "{{ ontap_password }}"
        https: true
        validate_certs: true
    - netapp.ontap.na_ontap_snapmirror:
        state: present
        source_endpoint: {cluster: cluster1, path: "svm_app:app_data"}
        destination_endpoint: {cluster: cluster2, path: "svm_dr:app_data_dp"}
        schedule: hourly
        policy: MirrorAndVault
        hostname: cluster2.example.com
        username: "{{ ontap_username }}"
        password: "{{ ontap_password }}"
        https: true
        validate_certs: true
  rescue:
    - debug: {msg: "Provisioning failed; preserve task output and REST error for triage"}

Terraform: state-owned infrastructure

The verified Registry source is NetApp/netapp-ontap; resource names use the netapp-ontap_ prefix. Provider releases change schema, so pin a reviewed version and consult that version's Registry documentation.

terraform {
  required_providers {
    netapp-ontap = { source = "NetApp/netapp-ontap", version = "~> 2.0" }
  }
}
provider "netapp-ontap" {
  connection_profiles = [{
    name = "prod"
    hostname = var.ontap_host
    username = var.ontap_username
    password = var.ontap_password
    validate_certs = true
  }]
}
resource "netapp-ontap_svm" "app" {
  cx_profile_name = "prod"
  name = "svm_app"
  ipspace = "Default"
  aggregates = [{ name = "aggr1" }]
}
resource "netapp-ontap_volume" "data" {
  cx_profile_name = "prod"
  name = "app_data"
  svm_name = netapp-ontap_svm.app.name
  aggregates = [{ name = "aggr1" }]
  space_guarantee = "none"
  space = { size = 500, size_unit = "gb", percent_snapshot_space = 5 }
  nas = { junction_path = "/app_data", security_style = "unix" }
}

Import existing objects before managing them, review every plan, store state in an encrypted locked backend, and never let two tools own the same setting.

PowerShell Toolkit

The Data ONTAP PowerShell Toolkit exposes familiar Nc cmdlets. Exact parameters vary by toolkit and ONTAP version; use Get-Help ... -Full before production scripting.

$cred = Get-Credential svc_automation
$nc = Connect-NcController -Name cluster1.example.com -HTTPS -Credential $cred
Get-NcVol -Controller $nc -Vserver svm_app -Name app_data |
  Select-Object Name, State, TotalSize, Available

Name      State  TotalSize     Available
----      -----  ---------     ---------
app_data online 536870912000  498216206336
New-NcVol -Controller $nc -VserverContext svm_app \
  -Name logs -Aggregate aggr1 -Size 100GB -JunctionPath /logs
Name  State  Aggregate Size
----  -----  --------- ----
logs  online aggr1     107374182400

Python client library

The netapp-ontap package wraps REST resources and exceptions. Pin a version compatible with the ONTAP releases you manage.

from netapp_ontap import HostConnection
from netapp_ontap.resources import Volume
from netapp_ontap.error import NetAppRestError

with HostConnection("cluster1.example.com", username=user, password=password,
                    verify=True):
    try:
        for vol in Volume.get_collection(name="app_data", fields="name,size,state"):
            print(vol.name, vol.size, vol.state)
    except NetAppRestError as err:
        raise SystemExit(f"ONTAP request failed: {err}")

Idempotency, errors and scale

  • Read, compare, change: PATCH only fields that differ; accept success on a desired state already present.
  • Jobs: a 202 response may carry a job link. Poll it to success or failure instead of treating acceptance as completion.
  • Errors: log HTTP status, ONTAP error code/message and correlation context, but redact authorization headers.
  • Load: request specific fields, paginate collections, cache UUID lookups, limit concurrency, honor 429/Retry-After if returned, and use exponential backoff with jitter for transient 429/5xx responses. Published limits can vary—measure and check your version.
  • Ownership: define which system owns each object; drift correction is dangerous when Terraform, Ansible and humans fight.

CI/CD and where automation fits

Good targets are configuration management, compliance drift reports, repeatable provisioning and backup/replication orchestration. Destructive recovery and security changes should retain approval gates.

name: ontap-config
on: [pull_request, workflow_dispatch]
jobs:
  check:
    runs-on: self-hosted
    steps:
      - uses: actions/checkout@v4
      - run: ansible-playbook -i inventory/prod.yml storage.yml --check --diff
        env:
          ANSIBLE_VAULT_PASSWORD_FILE: ${{ secrets.VAULT_PASSWORD_FILE }}
      - if: github.event_name == 'workflow_dispatch'
        run: ansible-playbook -i inventory/prod.yml storage.yml
        env:
          ANSIBLE_VAULT_PASSWORD_FILE: ${{ secrets.VAULT_PASSWORD_FILE }}

Use an isolated runner with management-network reachability, environment-protected secrets, least-privilege ONTAP RBAC, pinned actions/collections/providers, change review and an audit trail.

Official sources