Pace
OPEN SOURCE · APACHE 2.0

Storage automation, in three different styles.

Pace is an open-source library of ready-to-run automation examples for NetApp, starting with ONTAP. Workflows are written across three styles — as imperative scripts that execute step by step, declarative playbooks that describe the desired outcome, or stateful blueprints that track and enforce infrastructure over time — making it easier to pick the right approach for each job.

3 styles, side by side open source · Apache 2.0
WHY PACE

Three styles, side by side.

Picking an automation style up front, without seeing each one in action, is hard. Pace places the three styles side by side, with worked examples, to make the trade-offs concrete.

See the trade-offs.

Tasks are built in three styles, side by side. Underneath, they all talk to the same storage system — so the real differences are obvious: how much code you write, how safe it is to re-run, how easy it is to undo, and how much the tool handles for you versus how much you handle yourself.

Some styles give you full control over every step. Others let you describe what you want and figure out the rest. The same task, the same outcome — just different trade-offs in readability, flexibility, and maintenance. Seeing them next to each other makes those trade-offs concrete instead of theoretical.

Each example just runs

Copy one folder, fill in your cluster details, run it. Nothing extra to install.

PICK YOUR STYLE

One task, three styles.

Here's one task — printing cluster info — written in all three styles. The tool used in each example is one representative of its style. Across the wider library, coverage varies — not every example exists in every style.

Imperative scripts — you write each step yourself.

You spell out every step in order: call this, then call that, retry if it fails. A natural fit when a job needs custom logic, data transforms, or has to talk to other systems. Today shown in Python; the same idea fits other general-purpose languages.

Style
Imperative scripts
Tracks state
No — you handle it
Safe to re-run
You write that in
Lines of code
145 + 188 helpersNAS provisioning example
See every API call — easy to debug
Fits one-off jobs and gluing systems together
When you need branching, retries, or custom integrations
Imperative scripts · cluster info
# Connect to ONTAP and print cluster version + nodes
from ontap_client import OntapClient

client = OntapClient.from_env()
cluster = client.get("/cluster")
nodes   = client.get("/cluster/nodes")

print(f"Cluster: {cluster['name']} (ONTAP {cluster['version']['full']})")
for node in nodes["records"]:
    print(f"  - {node['name']:30}  state={node['state']}")

Declarative playbooks — say what you want, not how.

You write a playbook — "the volume should exist with these settings" — and the tool figures out what to change. Safe to run over and over, and easy to apply to many clusters at once. Today shown in Ansible; the same idea fits other configuration-management tools.

Style
Declarative playbooks
Tracks state
No — checks each run
Safe to re-run
Built in
Lines of code
96NAS provisioning example
Run the same playbook across many clusters at once
Safe to re-run any time — won't double up
Fits when you need to keep many clusters in a known good state
Declarative playbooks · cluster info
--- # Print ONTAP cluster info using netapp.ontap collection
- hosts: ontap
  gather_facts: false
  tasks:
    - name: Get cluster info
      netapp.ontap.na_ontap_rest_info:
        hostname: "{{ ontap_host }}"
        username: "{{ ontap_user }}"
        password: "{{ ontap_pass }}"
        gather_subset:
          - cluster
          - cluster/nodes
      register: result

    - name: Show summary
      ansible.builtin.debug:
        msg: "{{ result.ontap_info.cluster.name }} ({{ result.ontap_info.cluster.version.full }})"

Stateful blueprints — track everything, see every change.

You declare the resources you want, and the tool keeps a record of what it built. Before any change, you get a preview of exactly what will happen. Cleanup is one command. Today shown in Terraform; the same idea fits other declarative IaC tools.

Style
Stateful blueprints
Tracks state
Yes — full record
Safe to re-run
Preview, then apply
Lines of code
155NAS provisioning example
Full lifecycle: create, update, clean teardown
See exactly what changed since last time
Fits when you need an audit trail
Stateful blueprints · cluster info
terraform {
  required_providers {
    netapp-ontap = {
      source  = "NetApp/netapp-ontap"
      version = "~> 1.1"
    }
  }
}

data "netapp-ontap_cluster_info" "this" {
  cx_profile_name = "primary"
}

output "cluster_summary" {
  value = "${data.netapp-ontap_cluster_info.this.name} (ONTAP ${data.netapp-ontap_cluster_info.this.version.full})"
}
PROMPT TEMPLATES

Reusable prompts: plan, generate, review.

The repo includes reusable prompts that cover the full loop — planning a new use case, generating a first draft, and reviewing the result. Paste them into your AI assistant of choice; the output is a starting point that still needs human review and testing.

Plan

Break a use case into the resources, dependencies, and edge cases worth handling — before any code is written.

Generate

Scaffold a first draft in the style you choose, following the project's structure, helpers, and conventions.

Review

Surface idempotency, error handling, naming, and convention drift — a second pair of eyes before opening a PR.

AI output is a draft, not a merge. Run the project's checks, validate against a real cluster, and have a maintainer review before opening a PR — the same as any human-written change.
HOW TO CONTRIBUTE

From your first edit to a merged PR in 5 steps.

Use clear commit messages, get one approving review, make sure the checks pass. That's the whole protocol — no matter which style you contribute to.

1

Fork & clone

Make your own copy of the repo and branch off the main line.

2

Set up locally

Install the tools for the style you'll touch — the contribution guide walks through it.

3

Add a use case

One style is enough — script, playbook, or blueprint. Add more if you'd like.

4

Run the checks

Run the same checks locally that CI runs on every PR — lint, tests, formatting.

5

Open a PR

Clear commit message, one approving review, you're in.

Got a use case — or a new tool to add?

Adding examples in another tool, or a use case we haven't covered yet? Welcome here.