This is the last part of the series. Part 1 built a file portal on Amazon FSx for NetApp ONTAP (FSx for ONTAP) S3 access points, Part 2 added ransomware response and WORM retention, Part 3 put AI agents on it, Part 4 delegated 182 storage operations, and Part 5 collected what the running cluster refused.
This part is what was left off the screen. That is the difference from last time: where Parts 4 and 5 were about operations you run from a screen, this one has two subjects. How much of ONTAP stays usable without going through the portal at all, and the operational work that was handed to a schedule instead of a button.
What this part does not cover: performance figures (this measures whether things are possible and under what condition, not throughput), running SnapLock or Object Lock (irreversible, so not enabled without an instruction naming the retention), and actual tiering into a capacity pool (needs a different aggregate configuration, which was not on this path).
When you read and write files over the S3 API through an FSx for ONTAP S3 access point, how much of ONTAP stays usable alongside it? You want qtrees to carve up directories, quotas to stop a tenant running away with the space, FlexClone to spin a verification copy. Does any of that sound like your environment?
Start looking into it and NetApp's documentation gives you . ONTAP S3 interoperability records qtrees, quotas, FlexClone, and a volume clone of a FlexGroup containing ONTAP S3 buckets as not supported — for the ONTAP S3 server.
That is where it stalls. The FSx for ONTAP S3 access point is an AWS mechanism, and what it attaches to is a volume, not a bucket. Attaching one does stand up an ONTAP S3 server on the SVM, and I/O through the access point goes through ONTAP's S3 protocol stack. So the two are not unrelated. Does the same restriction appear?
I measured it. Up front: everything I measured worked.
| ONTAP feature | Result on the S3 access point path |
|---|---|
| Qtree | Can be created. Appears as an S3 prefix, and an object PUT into it lands inside the qtree |
| Quota | A tree quota refuses an S3 PUT |
| FlexClone (volume granularity) | The clone can be made, and the clone itself can take an S3 access point |
| FlexClone (file granularity) | A file written over S3 can be cloned, and the clone is visible as an object through the access point |
| FlexGroup volume | |
| An S3 access point can be attached. PUT / GET / LIST and multipart all work | |
| Clone of a FlexGroup | The clone can be created |
The four items that table lists did not appear as restrictions on this path. Reading that table as "not supported there, therefore not supported here" is wrong, and so is the reverse: a "supported" row is not evidence about this path either. The subjects differ, so nothing is known until it is measured.
What actually tripped me up was not in the table at all. Three things.
AVAILABLE
, and then refuses every data operation with AccessDenied
. AVAILABLE
says nothing about the health of the file system layeraws fsx delete-volume
removes itBelow is the walkthrough, and how the controls were set up.
| Item | Value |
|---|---|
| Date | 2026-08-26 (UTC) |
| Region | ap-northeast-1 |
| ONTAP version | 9.18.1P3D1 |
| Deployment type / throughput | SINGLE_AZ_1 / 128 MBps |
| Test volumes | UNIX security style 1 GiB × 2 (one with an access point, one as the control), NTFS 1 GiB × 1, FlexGroup 400 GiB × 1 |
| Access point identity | UNIX root , internet origin |
| Cleanup | Throwaway volumes only. All deleted |
A note on the identity: UNIXroot
was used to keep the measurement simple. Every request through an access point is authorized as that one file system identity, so specifyingroot
removes any narrowing by file permissions.This is not a recommended configuration.Use a dedicated user with only the permissions the writes need, and split access points per purpose (FileSystemIdentity
cannot be changed after creation).
Let me settle the vocabulary first, because mixing these two makes every result below read wrong.
| Mechanism | What it is | Whose |
|---|---|---|
| ONTAP S3 | ||
| The S3 server with which ONTAP serves buckets. This is what NetApp's table is about | NetApp | |
| FSx for ONTAP S3 access point | ||
| An AWS access point attached to an FSx for ONTAP volume | ||
| AWS |
They are not unrelated. Attaching one stands up an ONTAP S3 server on the SVM, and the I/O goes through ONTAP's S3 protocol stack (measured). That is exactly why NetApp's table is the right place to start.
Being the right place to start is not the same as being the conclusion. The target is a volume rather than a bucket, and the namespace and the authorization path both differ. "Not supported there, therefore not supported here" turns something unchecked into something checked. The reverse reading is the same error.
| Step | Result |
|---|---|
| Create a qtree in the volume with an access point | Succeeded |
| Control: the same qtree in the volume with no access point | Succeeded. No difference |
list-objects-v2 --delimiter / |
|
| The qtree appears in CommonPrefixes | |
| PUT into the qtree prefix | Succeeded |
| Inspect the qtree from ONTAP | The written file is inside the qtree directory |
NetApp's "Qtrees: not supported" does not manifest as a refusal on this path. The qtree is created, it is visible as a prefix in the S3 namespace, and an object written into that prefix lands inside it. Together with the quota result below, it behaves as a qtree.
Incidentally, a volume with an access point attached carries an internal ____NTAP_S3_MAPPING
directory at its root. It is visible over NFS and SMB, so anyone who inspects a collect-layer volume by hand will see it.
| Step | Result |
|---|---|
| Set a tree quota on the qtree (space 1 MiB, files 10) and enable quotas on the volume | Succeeded |
quota report |
|
| The rule is active, and the file written over S3 is counted in files used | |
| PUT 15 small objects | |
| 8 succeeded, 7 refused. files used stopped at exactly 10/10 | |
| What the S3 client received on refusal | HTTP 507 InsufficientCapacity / Maximum storage capacity of file system has been reached. |
| Control: raise the files limit 10 → 50 and re-PUT the refused key with the same body | Succeeded |
The control carries the conclusion. Raising the limit alone made the identical PUT succeed, so the refusal was the quota, not a capacity shortage and not a permissions artefact.
That the response mis-describes its cause matters to the design. The file system was not full; a qtree file-count quota was reached. An operator who sees a 507 and "maximum storage capacity of file system" will consider growing the file system. If you use quotas on this path, write down what that response actually means in the runbook.
There are two granularities, and they behave differently.
| File granularity | Volume granularity | |
|---|---|---|
| Where it lands | The same volume. It appears as a new key on the same access point | A separate volume |
| Authorization boundary | Same as the parent | Its own access point, its own policy, its own identity |
| Time before it is usable | None | 599 to 1,177 s measured, for a volume created through the ONTAP API to appear on the AWS side |
| Visible over S3 | Yes. StorageClass=FSX_ONTAP , sha256 matches the source |
|
| Yes. LIST / GET / PUT through the clone's own access point |
At either granularity the clone shares data blocks with its parent. Cloning a 256 MiB file four times:
| Point | Logical | Physical |
|---|---|---|
| Just after one 256 MiB PUT | — | 253,534,208 B |
| After four file-granularity clones | 1,350,942,720 B | 277,200,896 B |
Logical grew to five copies, physical by about 23 MB. FSx for ONTAP bills provisioned SSD capacity, so there is no capacity to provision per duplicate.
NetApp states that copies consume no storage except what is required for metadata until changes are written to the copy (FlexClone volumes, files, and LUNs). The operation that ends the sharing is a split (volume clone split start
), which I did not measure. From ONTAP 9.4, on AFF systems where the volume guarantee is none
, the documentation states that the split shares the physical blocks rather than copying data (splitting procedure).
A file-granularity clone gives no observable failure, however. POST /api/storage/file/clone
returns 202 and a job UUID, but the UUID resolved to 404 entry doesn't exist
and appeared in no job listing. The same fsxadmin
retrieves volume-create and volume-clone jobs as state=success
, so this is not a permissions problem. A call naming a destination directory that does not exist also returned 202 and created nothing. Judge the outcome by inspecting the destination file.
Creation has conditions, learned by failing in order.
| Step | Result |
|---|---|
| Create with default parameters | Failed. Volumes of this type must be at least 50GB |
| Retry at 50 GiB | Failed. Aggregates not matching FabricPool requirements: aggr1 |
| Retry with the aggregate named explicitly | Failed. Minimum size is "400GB" (8 constituents × 50 GiB) |
400 GiB, explicit aggregate, tiering.policy=none , thin |
|
| Succeeded |
The FSx for ONTAP API offers no way to create a FlexGroup, so it is created on the ONTAP side. What follows is the point.
| Step | Result |
|---|---|
Appears on the FSx for ONTAP side as VolumeStyle=FLEXGROUP |
|
It does, with an fsvol- identifier |
|
| Attach an S3 access point to the FlexGroup | |
Succeeded. Lifecycle=AVAILABLE |
|
| PUT / GET / LIST | Succeeded. The GET content matched |
| 12 MiB multipart upload | Succeeded. StorageClass=FSX_ONTAP |
| Snapshot the FlexGroup | Succeeded |
| Clone that FlexGroup | |
Succeeded. style=flexgroup , is_flexclone=true , online |
That last row is the item NetApp's table records as "volume clone of the FlexGroup volume containing ONTAP S3 buckets: not supported".
The constraints were not on NetApp's side of the table. Within what I measured, these three are the real traps.
| Step | Result |
|---|---|
Attach with an NTFS-security-style volume + UNIX identity (root ) |
|
Succeeded. Lifecycle=AVAILABLE |
|
| PUT through that access point | Refused. AccessDenied , body only Access Denied |
| Control: same identity, same caller, UNIX volume | PUT / GET / LIST all succeeded |
| CIFS server on this SVM | |
| None. The UNIX-to-Windows mapping cannot resolve |
** AVAILABLE does not mean the file system layer is healthy.** Attachable and usable are different properties: IAM and the access point policy are both passed, and the file system layer refuses after that. The body is only
Access Denied
and does not name the layer. A refusal at the identity layer says no identity-based policy allows ...
instead, so Trying WINDOWS identity on the same SVM does not even complete the attachment.
| Step | Result |
|---|---|
| Attach with WINDOWS identity on an SVM with no CIFS server | Failed. did not stabilize (NotStabilized ), stack rolled back |
| Whether an attachment survives the rollback | |
| It does not. Nothing was orphaned |
A volume created through the ONTAP API is not immediately in the AWS-side describe-volumes
. Without an fsvol-
identifier, neither AWS::FSx::S3AccessPointAttachment
nor create-and-attach-s3-access-point
can reference it.
| Measurement | Result |
|---|---|
| FlexGroup, polled every 20 s with no gaps | |
Appeared at 599 s (about 10 min), with an fsvol- identifier |
|
| A FlexClone volume, polled every 20 s with no gaps | Appeared at 1,177 s (about 19.6 min) |
| A separate run | Still absent at 1,258 s (about 21 min) |
The three observations disagree, so this is not an upper bound. The order of magnitude is tens of minutes, which is not enough to bake a fixed wait into a design. AWS documents the following, and the measurement is longer than its "several minutes".
Amazon FSx periodically syncs with ONTAP to ensure consistency. If you create or modify volumes using NetApp applications, it may take up to several minutes for these changes to be reflected in the AWS Management Console, AWS CLI, API and SDKs.
—
[Managing FSx for ONTAP resources using NetApp applications]
I first misread this delay as absence. From an observation of about 2.5 minutes I concluded that a volume created through the ONTAP API has no fsvol-
identifier, and wrote that neither a clone nor a FlexGroup could take an access point. Both were wrong: wait, and it appears, and it attaches. Two and a half minutes is inside AWS's "several minutes", and I had not separated "not there yet" from "never appears".
It lags in the other direction too. Setting a junction path on the ONTAP side and attaching immediately fails with Amazon FSx is unable to attach S3access point because the volume is not mounted.
The AWS-side JunctionPath
was None
at that moment and still was two minutes later. Setting it with aws fsx update-volume
made it visible on the AWS side in about 40 seconds, and the attachment then succeeded. The error message was telling the truth. What was wrong was my assumption that setting it in ONTAP made it visible to AWS.
This one came on a different day. A volume that has once carried an S3 access point cannot be deleted from the ONTAP side, even after every access point is detached.
Cannot delete volume "..." in SVM "..." because it is associated with the following
object store NAS buckets: "amazon-fsx-<volume-id>"
| What was checked | Result |
|---|---|
| Where the bucket name comes from | |
| An exact match for the volume ID. It is created per volume, not per access point | |
| After deleting every access point | Still refused, and still refused hours later |
| Bringing the volume back online and mounted | Still refused |
| Re-attaching an access point and detaching it in the correct order | Still refused. It is independent of the access point lifecycle |
aws fsx delete-volume |
|
| Succeeded. Both the volume and the bucket went |
NetApp's documented procedure for removing a NAS bucket configuration uses vserver object-store-server bucket delete
, which cannot be applied here because the target cannot be listed.
Do not read "invisible" as "absent". This is the half that generalises.
| Reader | How it shows this bucket / S3 server |
|---|---|
ONTAP REST /protocols/s3/buckets |
|
| Does not list it | |
ONTAP CLI vserver object-store-server bucket show |
|
| Does not list it | |
ONTAP REST /svm/svms (the s3 field) |
|
Reports the S3 server as enabled |
|
ONTAP REST /protocols/s3/services |
|
| Does not list the same SVM |
Objects that AWS manages are hidden from the standard ONTAP S3 views. I confirmed the bucket's absence across two readers, and both shared the same blind spot.
One more ordering trap, if you have made clones. delete-volume
returned DELETING
and then silently went back to CREATED
, twice. The reason appears only in LifecycleTransitionReason
on describe-volumes
: Failed to delete volume because it has one or more clones.
The clones had been deleted, and were sitting in ONTAP's volume recovery queue. The parent kept clone.has_flexclone
at true
, and the AWS-side delete reads that flag and refuses. Purging the recovery queue cleared the flag and the same delete-volume
worked. That queue appears in neither the console nor the FSx for ONTAP API.
Translated into operational terms, the measurements come to five points.
| # | What to write in the runbook |
|---|---|
| 1 | |
| Match the security style to the identity. UNIX identity for UNIX volumes, WINDOWS identity for NTFS ones. Avoid a UNIX identity on NTFS even where the SVM does have a CIFS server | |
| 2 | |
Do not use Make the acceptance criterion a PUT and a read-back after attachingAVAILABLE as a connectivity check. |
|
| 3 | |
Budget tens of minutes into automation that creates a resource in ONTAP and then handles it through the AWS API. Poll for the fsvol- identifier rather than sleeping a fixed interval |
|
| 4 | |
| Write through the AWS management plane. Where a setting can be made from either side, as with the junction path, the AWS side reflects faster (about 40 seconds against more than two minutes) | |
| 5 | |
Tear down through the AWS-side API. A procedure built on ONTAP's volume delete gets stuck on a volume that has carried an S3 access point |
Everything so far was about whether an operation is possible. Operations has another kind of work: checking capacity, taking stock of snapshots, revisiting tiering policy, confirming throughput is still right-sized. All of it is daily or weekly, and a button for it does not get pressed. That work suits a schedule better than a screen, so six patterns live in operations/
.
| ID | Pattern | What it does |
|---|---|---|
| OPS1 | capacity-rightsizing | Capacity and throughput monitoring, tier recommendation, what-if cost |
| OPS2 | storage-efficiency | Tracks deduplication and compression efficiency, recommends enabling them |
| OPS3 | tiering-optimizer | Cold-data analysis, tiering policy recommendation and savings estimate |
| OPS4 | snapshot-lifecycle | Retention policy compliance check and drift detection |
| OPS5 | cost-optimization | Cost breakdown, unit economics ($/GB), growth projection |
| OPS6 | qos-monitoring | QoS policy adherence, bandwidth contention risk |
The shape is the same in all six. An EventBridge schedule starts a Step Functions workflow, a VPC Lambda collects from the ONTAP REST API and CloudWatch, another analyses, and a third writes the report. Unit tests total 74 across the six (capacity-rightsizing
27, snapshot-lifecycle
19, tiering-optimizer
11, storage-efficiency
6, cost-optimization
6, qos-monitoring
5).
The report has two destinations. With OutputDestination=FSXN_S3AP
it is written to an FSx for ONTAP volume through an S3 access point, which means anyone with the NFS or SMB mount reads it in the file explorer they already use. On the real cluster the same 4,240-byte JSON appeared on the ONTAP volume as in the S3 bucket, the Step Functions execution took around 15 seconds, and four metrics were published to the FSxOps
namespace.
A recommendation comes out like this.
{
"recommendation_type": "downsize",
"target": "vol_backup_temp",
"current_value": "10.0% (1024 GB allocated, 102 GB used)",
"recommended_value": "Shrink to 205 GB or enable autosize (grow_shrink)",
"monthly_cost_delta_usd": -102.4
}
DemoMode=true
runs the whole workflow on mock data with no file system, so the report layout and the shape of the recommendations can be reviewed first. Running cost itself — Lambda, Step Functions and S3 storage — came to roughly $1-5 a month for a daily run over a handful of file systems.
Honestly, here. The template's AutomationLevel
accepts 0 through 3.
| Level | Intended behaviour | Implemented |
|---|---|---|
| 0 | Report only | Yes (default) |
| 1 | Notify over SNS | Yes |
| 2 | Execute after human review | No |
| 3 | Auto-execute within guardrails | No |
The code branches in exactly one place, automation_level >= 1
, deciding whether to send SNS. So 2 or 3 deploys successfully and behaves identically to Level 1. The values the parameter accepts and the values the code distinguishes do not match.
I noticed this while writing. The values listed in AllowedValues are not a declaration of what is implemented — accepting a value and honouring it are different things. It is the same point Part 4 made about not shipping buttons that cannot be pressed, showing up on the parameter side instead. Until the approval flow exists, narrowing
AllowedValues
to 0 and 1 would be the accurate move.None of this replaces existing tooling. The vendor's CloudWatch dashboards and auto-resize solutions, and the SSD capacity auto-expansion AWS documents, differ in immediacy and in scope. The six here suit a flow where analysis and a recommendation come first and a person decides. Choose on the use case.
On how recommendations are treated: OPS4's snapshot deletion recommendations exclude anything below the minimum retention. A recommendation is an assistive signal, not a final decision. Which retention period satisfies your regulatory requirements is a legal and compliance judgement, and neither this article nor the pattern stands in for it.
"Unverified" is not "cannot be done". Every result above turned out that way, so on this path nothing is known until it is measured.
| Item | State |
|---|---|
| FlexClone at LUN granularity | Unverified. Creating a LUN needs an iSCSI configuration, which is not on this path |
| The FlexClone split | Unverified. Documentation only |
| An upper bound on the ONTAP-to-AWS reflection time | Unverified. The three observations disagree |
| FabricPool tiering | Unverified. Needs a different aggregate configuration |
| QoS / deduplication and compression / SnapMirror / Vscan | Unverified |
| SnapLock / Object Lock | Unverified. Irreversible, so not enabled without an instruction naming the retention value |
| Attaching on a FlexCache cache volume | Unverified. Requires a cluster peer and an SVM peer |
| OPS Levels 2 and 3 | |
| Not implemented. The approval flow and auto-execution are not in the code | |
| Whether the OPS recommendations are sound | Not evaluated. They are produced; none was applied and measured |
| OPS across many file systems | Unmeasured. Only a handful were run |
Two things were left off the screen, and both were written up here.
On the ONTAP side I took NetApp's table as the starting point and measured on the S3 access point path. The four items it lists as unsupported did not appear as restrictions here. Qtrees work, a quota refuses an S3 PUT, FlexClone works at both volume and file granularity, a FlexGroup takes an access point, and a clone of that FlexGroup can be created. The constraints were elsewhere: AVAILABLE
says nothing about the file system layer, something created in ONTAP takes tens of minutes to appear on the AWS side, and a volume that has carried an access point can only be deleted from the AWS side.
On the operations side, the daily work went to a schedule rather than a screen. One more thing turned up while writing it: AutomationLevel
accepts 0 through 3 while the code distinguishes only up to 1.
Across the series the same thing kept happening. Two misreadings (concluding "never appears" from a 2.5-minute observation, and confirming "there is no bucket" across two readers that shared one blind spot), one correction (blaming privilege for the recovery queue purge), one broken display (reading lock state from only one of two fields), and one parameter that merely accepts its values. In every case, another explanation looked just as correct until one more control, or a second vantage point, was added.
Thank you for reading all six parts. It started with showing files in a browser and ended outside the screen entirely. I hope the series is useful to anyone operating FSx for ONTAP, or building this kind of admin screen.
All test resources were deleted. The figures come from one specific environment and configuration and will differ with workload and setup. This article does not stand in for governance or regulatory judgement.