NetApp Community Update
This site will enter Read Only mode on July 23 as we prepare to move to a new platform. You will still be able to view content, but posting and replying will be temporarily disabled.
We're excited to launch our new Community experience on July 30 and more information will follow soon.
Stay connected during the transition - Join our Discord community today.

Tech ONTAP Blogs

Resource Transformations in NetApp Trident Protect

PatricU
NetApp
58 Views

The recently introduced resource transformations in NetApp Trident Protect enable you to modify a resource as it is being restored. This is useful when the restored version needs to differ from the original — for example, changing a virtual machine's IP address when restoring it to a different network or scaling down a deployment.

We can use the following operations to modify resources:

  • add: Add a value to a resource.
  • copy: Copy a value from one path to another.
  • move: Move a value within a resource.
  • remove: Remove a value from a resource.
  • replace: Replace a value within a resource.
  • test: Test an operation before performing it.
Spoiler
Note that modifying PersistentVolumeClaims and Namespaces by resource transformations is currently not supported. The destination Namespaces can be specified during the restore process, though.

In this blog post, we’ll walk you through a restore scenarios using resource transformations to scale up an application during restore as an example how to use resource transformations.

We also show you how to create resource transformation rules.

Scenario and prerequisites

We demonstrate the use of Trident Protect resource transformations on a K8s cluster which has NetApp Trident and Trident Protect version 26.06 already installed and configured. Resource transformations are supported starting with Trident Protect 26.06.

As sample application, we use a simple Alpine deployment in the namespace pu-alpine, protected with a Trident Protect snapshot as application pu-alpine.  

$ kubectl get all,pvc,volumesnapshots -n pu-alpine
NAME                          READY   STATUS    RESTARTS   AGE
pod/alpine-85cb86d5fb-2wjd7   1/1     Running   0          2d1h

NAME                     READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/alpine   1/1     1            1           2d1h

NAME                                DESIRED   CURRENT   READY   AGE
replicaset.apps/alpine-85cb86d5fb   1         1         1       2d1h

NAME                               STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS                  VOLUMEATTRIBUTESCLASS   AGE
persistentvolumeclaim/alpinedata   Bound    pvc-a6fbd817-a80c-4c94-b77f-463c25c06269   50Gi       RWX            azure-netapp-files-standard   <unset>                 2d1h

NAME                                                                                                                            READYTOUSE   SOURCEPVC    SOURCESNAPSHOTCONTENT   RESTORESIZE   SNAPSHOTCLASS           SNAPSHOTCONTENT                                    CREATIONTIME   AGE
volumesnapshot.snapshot.storage.k8s.io/snapshot-b9012d00-d547-4b81-8679-0b6b81d0bf69-pvc-a6fbd817-a80c-4c94-b77f-463c25c06269   true         alpinedata                           50Gi          csi-trident-snapclass   snapcontent-35611620-c5d5-4206-babb-5d4abee49516   41h            41h

$ tridentctl-protect get application -n pu-alpine
+-----------+------------+-------+-------+
|   NAME    | NAMESPACES | STATE |  AGE  |
+-----------+------------+-------+-------+
| pu-alpine | pu-alpine  | Ready | 1d17h |
+-----------+------------+-------+-------+

Rescale an application during restore

The Trident Protect CLI tridentctl-protect has two options to specify the transformation rules, either in human-readable or in JSON format. As always, you can also use Trident Protect custom resources (CRs) to restore applications and specify the transformation rules in the CR. In this document we focus on the CLI, look at the documentation to learn more about all the details of resource transformations.

 

Let’s start with the JSON format option of the CLI and restore the sample application into the namespace pu-alpine-restore on the same cluster, scaling up the alpine deployment to two pods during the restore. The --dry-run option of the CLI allows us to look at the corresponding snapshotrestore CR before execution:

$ tridentctl-protect create snapshotrestore --snapshot pu-alpine/pu-alpine-lacj30 --namespace-mapping pu-alpine:pu-alpine-restore --destination-app-name pu-alpine-restore --transformation_json '{"resource":{"group":"apps","version":"v1","kind":"Deployment","name":"alpine"},"operations":[{"op":"replace","path":"/spec/replicas","value":2}]}' -n pu-alpine-restore --dry-run
apiVersion: protect.trident.netapp.io/v1
kind: SnapshotRestore
metadata:
  name: pu-alpine-4nxlsu
  namespace: pu-alpine-restore
spec:
  appArchivePath: pu-alpine_64172278-e753-4707-88e6-0e1be7c020aa/snapshots/20260707084659_pu-alpine-lacj30_3e24bd6d-cb46-49f8-b663-1033c38787be
  appVaultRef: demo
  cleanUpAdditionalExecHooks: true
  cleanUpArchivedExecHooks: false
  destinationApplicationName: pu-alpine-restore
  namespaceMapping:
  - destination: pu-alpine-restore
    source: pu-alpine
  resourceFilter: {}
  runArchivedExecHooks: true
  skipApplicationCreation: false
  transformations:
  - operations:
    - op: replace
      path: /spec/replicas
      value: 2
    resource:
      group: apps
      kind: Deployment
      name: alpine
      version: v1
status:
  postRestoreExecHooksRunResults: null
  state: ""

Now let’s execute the restore.

$ tridentctl-protect create snapshotrestore --snapshot pu-alpine/pu-alpine-lacj30 --namespace-mapping pu-alpine:pu-alpine-restore --destination-app-name pu-alpine-restore --transformation_json '{"resource":{"group":"apps","version":"v1","kind":"Deployment","name":"alpine"},"operations":[{"op":"replace","path":"/spec/replicas","value":2}]}' -n pu-alpine-restore
SnapshotRestore "pu-alpine-st92s8" created.

The restore finishes in some minutes and we can confirm that the restored Alpine application was indeed scaled up.

$ kubectl get all,pvc,volumesnapshots -n pu-alpine-restore
NAME                          READY   STATUS    RESTARTS   AGE
pod/alpine-85cb86d5fb-dm62k   1/1     Running   0          66s
pod/alpine-85cb86d5fb-j56lp   1/1     Running   0          66s
NAME                     READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/alpine   2/2     2            2           66s
NAME                                DESIRED   CURRENT   READY   AGE
replicaset.apps/alpine-85cb86d5fb   2         2         2       67s
NAME                               STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS                  VOLUMEATTRIBUTESCLASS   AGE
persistentvolumeclaim/alpinedata   Bound    pvc-befdc220-2095-4c93-915f-377af6358a0d   50Gi       RWX            azure-netapp-files-standard   <unset>                 71s

In human-readable format, the Trident Protect CLI command looks like this:

$ tridentctl-protect create snapshotrestore --snapshot pu-alpine/pu-alpine-lacj30 --namespace-mapping pu-alpine:pu-alpine-restore --destination-app-name pu-alpine-restore --transformation 'apps,v1,Deployment,alpine:replace{"path":"/spec/replicas","value":2}' -n pu-alpine-restore

Create and use resource transformation rules

Instead of specifying the transformation rules in each restore operation, we can create transformation rules at the namespace level (ResourceTransformationRule CRD) or cluster level (ResourceTransformationClusterRule CRD) and simply reference the rule we want to apply during the restore using the --transformationsRuleRef or --transformationsClusterRuleRef flags of the tridentctl-protect command.

 

Let’s look at transformation rules at the namespace level first.

As a transformation rule at the namespace level needs to exist in the target namespace of the restore, we need to create the namespace for the restore first.

$ kubectl create ns pu-alpine-restore
namespace/pu-alpine-restore created

Now we can create our transformation rule in the newly created namespace by applying this manifest:

$ cat scale-up-alpine-deployment-to-two_ResourceTransformationRule.yaml
apiVersion: protect.trident.netapp.io/v1
kind: ResourceTransformationRule
metadata:
  name: scale-up-alpine-deployment-to-two
spec:
  transformations:
  - resource:
      group: apps
      kind: Deployment
      version: v1
      name: alpine
    operations:
    - op: replace
      path: /spec/replicas
      value: 2

$ kubectl -n pu-alpine-restore apply -f scale-up-alpine-deployment-to-two_ResourceTransformationRule.yaml
resourcetransformationrule.protect.trident.netapp.io/scale-up-alpine-deployment-to-two created

$ kubectl -n pu-alpine-restore get resourcetransformationrules
NAME             	                 AGE
scale-up-alpine-deployment-to-two  20s

The CLI command and the snapshotrestore CR are now much simpler, only referencing the transformation rule with the --transformationsRuleRef flag:

$ tridentctl-protect create snapshotrestore --snapshot pu-alpine/pu-alpine-4frnyj --namespace-mapping pu-alpine:pu-alpine-restore --destination-app-name pu-alpine-restore --transformationsRuleRef scale-up-alpine-deployment-to-two -n pu-alpine-restore --dry-run
apiVersion: protect.trident.netapp.io/v1
kind: SnapshotRestore
metadata:
  name: pu-alpine-e4zgfc
  namespace: pu-alpine-restore
spec:
  appArchivePath: pu-alpine_2b9d9467-5697-4066-8acf-3c569b6627a9/snapshots/20260707161646_pu-alpine-4frnyj_b9012d00-d547-4b81-8679-0b6b81d0bf69
  appVaultRef: demo
  cleanUpAdditionalExecHooks: true
  cleanUpArchivedExecHooks: false
  destinationApplicationName: pu-alpine-restore
  namespaceMapping:
  - destination: pu-alpine-restore
    source: pu-alpine
  resourceFilter: {}
  runArchivedExecHooks: true
  skipApplicationCreation: false
  transformationsRef:
    kind: ResourceTransformationRule
    name: scale-up-alpine-deployment-to-two
status:
  postRestoreExecHooksRunResults: null
  state: ""

Now let’s see how we can leverage ResourceTransformatioClusterRules to modify resources during restores. Below is a manifest for a ResourceTransformatioClusterRule that scales any deployment to two. As the resource name (like group and version) is an optional argument, we don’t specify it in the ResourceTransformatioClusterRule, making it more generic – but keep in mind that any deployment will be re-scaled by applying this rule.

$ cat scale-up-deployment-to-two_ResourceTransformationClusterRule.yaml
apiVersion: protect.trident.netapp.io/v1
kind: ResourceTransformationClusterRule
metadata:
  name: scale-up-deployment-to-two
spec:
  transformations:
  - resource:
      group: apps
      kind: Deployment
      version: v1
    operations:
    - op: replace
      path: /spec/replicas
      value: 2 

We apply this manifest to create the cluster rule:

$ kubectl apply -f scale-up-deployment-to-two_ResourceTransformationClusterRule.yaml
resourcetransformationclusterrule.protect.trident.netapp.io/scale-up-deployment-to-two created

$ kubectl get ResourceTransformationClusterRule
NAME                         AGE
scale-up-deployment-to-two   16s

With the --transformationsClusterRuleRef flag of tridentctl-protect, we can now reference the cluster rule during the restore from snapshot easily:

$ tridentctl-protect create snapshotrestore --snapshot pu-alpine/pu-alpine-4frnyj --namespace-mapping pu-alpine:pu-alpine-restore --destination-app-name pu-alpine-restore --transformationsClusterRuleRef scale-up-deployment-to-two -n pu-alpine-restore
SnapshotRestore "pu-alpine-ywvuzx" created.

Checking the restore namespace, we confirm that the alpine deployment was scaled up to two pods as expected:

$ kubectl get all,pvc,volumesnapshots -n pu-alpine-restore
NAME                          READY   STATUS    RESTARTS   AGE
pod/alpine-85cb86d5fb-5qjm6   1/1     Running   0          5m28s
pod/alpine-85cb86d5fb-phkqh   1/1     Running   0          5m28s

NAME                     READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/alpine   2/2     2            2           5m29s

NAME                                DESIRED   CURRENT   READY   AGE
replicaset.apps/alpine-85cb86d5fb   2         2         2       5m29s

NAME                               STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS                  VOLUMEATTRIBUTESCLASS   AGE
persistentvolumeclaim/alpinedata   Bound    pvc-6318a214-c800-4fa8-95fe-c32edf74f288   50Gi       RWX            azure-netapp-files-standard   <unset>                 5m33
Spoiler

When doing cross-cluster restores, the ResourceTransformationClusterRules must exist in the target cluster!

Before the introduction of resource transformation in Trident Protect, operations like  rescaling an application or changing its image registry during restore were only possible by using post-restore hook scripts executed in helper pods, as outlined in these two blog post:

You’ll agree that using resource transformation for such operations is much easier and less error prone.

Summary

NetApp Trident Protect's resource transformations feature simplifies the restoration of Kubernetes applications by enabling modifications to resources during the restore process. For instance, scaling a deployment or changing a virtual machine's IP address can now be achieved directly through transformation rules. Supported operations include add, replace, remove, and more, offering granular control over resource adjustments.

 

Key highlights include:

  • CLI Integration: Users can specify transformation rules via JSON or human-readable formats using tridentctl-protect.
  • Predefined Rules: Transformation rules can be pre-created and referenced during restores, reducing complexity.

Before this feature, resource modifications required post-restore scripts, which were prone to errors and operational overhead. Resource transformations now offer a more streamlined and efficient alternative, improving disaster recovery workflows.

 

This blog post walks through practical scenarios, such as scaling a deployment during restore, and demonstrates how to create and apply transformation rules using both CLI commands and manifests. Whether you're restoring applications within the same cluster or across clusters, resource transformations ensure a seamless and automated recovery experience.

Public