github.com/argoproj/argo-cd/v2@v2.10.9/docs/operator-manual/resource_actions.md (about) 1 # Resource Actions 2 3 ## Overview 4 Argo CD allows operators to define custom actions which users can perform on specific resource types. This is used internally to provide actions like `restart` for a `DaemonSet`, or `retry` for an Argo Rollout. 5 6 Operators can add actions to custom resources in form of a Lua script and expand those capabilities. 7 8 ## Custom Resource Actions 9 10 Argo CD supports custom resource actions written in [Lua](https://www.lua.org/). This is useful if you: 11 12 * Have a custom resource for which Argo CD does not provide any built-in actions. 13 * Have a commonly performed manual task that might be error prone if executed by users via `kubectl` 14 15 The resource actions act on a single object. 16 17 You can define your own custom resource actions in the `argocd-cm` ConfigMap. 18 19 ### Custom Resource Action Types 20 21 #### An action that modifies the source resource 22 23 This action modifies and returns the source resource. 24 This kind of action was the only one available till 2.8, and it is still supported. 25 26 #### An action that produces a list of new or modified resources 27 28 **An alpha feature, introduced in 2.8.** 29 30 This action returns a list of impacted resources, each impacted resource has a K8S resource and an operation to perform on. 31 Currently supported operations are "create" and "patch", "patch" is only supported for the source resource. 32 Creating new resources is possible, by specifying a "create" operation for each such resource in the returned list. 33 One of the returned resources can be the modified source object, with a "patch" operation, if needed. 34 See the definition examples below. 35 36 ### Define a Custom Resource Action in `argocd-cm` ConfigMap 37 38 Custom resource actions can be defined in `resource.customizations.actions.<group_kind>` field of `argocd-cm`. Following example demonstrates a set of custom actions for `CronJob` resources, each such action returns the modified CronJob. 39 The customizations key is in the format of `resource.customizations.actions.<apiGroup_Kind>`. 40 41 ```yaml 42 resource.customizations.actions.batch_CronJob: | 43 discovery.lua: | 44 actions = {} 45 actions["suspend"] = {["disabled"] = true} 46 actions["resume"] = {["disabled"] = true} 47 48 local suspend = false 49 if obj.spec.suspend ~= nil then 50 suspend = obj.spec.suspend 51 end 52 if suspend then 53 actions["resume"]["disabled"] = false 54 else 55 actions["suspend"]["disabled"] = false 56 end 57 return actions 58 definitions: 59 - name: suspend 60 action.lua: | 61 obj.spec.suspend = true 62 return obj 63 - name: resume 64 action.lua: | 65 if obj.spec.suspend ~= nil and obj.spec.suspend then 66 obj.spec.suspend = false 67 end 68 return obj 69 ``` 70 71 The `discovery.lua` script must return a table where the key name represents the action name. You can optionally include logic to enable or disable certain actions based on the current object state. 72 73 Each action name must be represented in the list of `definitions` with an accompanying `action.lua` script to control the resource modifications. The `obj` is a global variable which contains the resource. Each action script returns an optionally modified version of the resource. In this example, we are simply setting `.spec.suspend` to either `true` or `false`. 74 75 #### Creating new resources with a custom action 76 77 !!! important 78 Creating resources via the Argo CD UI is an intentional, strategic departure from GitOps principles. We recommend 79 that you use this feature sparingly and only for resources that are not part of the desired state of the 80 application. 81 82 The resource the action is invoked on would be referred to as the `source resource`. 83 The new resource and all the resources implicitly created as a result, must be permitted on the AppProject level, otherwise the creation will fail. 84 85 ##### Creating a source resource child resources with a custom action 86 87 If the new resource represents a k8s child of the source resource, the source resource ownerReference must be set on the new resource. 88 Here is an example Lua snippet, that takes care of constructing a Job resource that is a child of a source CronJob resource - the `obj` is a global variable, which contains the source resource: 89 90 ```lua 91 -- ... 92 ownerRef = {} 93 ownerRef.apiVersion = obj.apiVersion 94 ownerRef.kind = obj.kind 95 ownerRef.name = obj.metadata.name 96 ownerRef.uid = obj.metadata.uid 97 job = {} 98 job.metadata = {} 99 job.metadata.ownerReferences = {} 100 job.metadata.ownerReferences[1] = ownerRef 101 -- ... 102 ``` 103 104 ##### Creating independent child resources with a custom action 105 106 If the new resource is independent of the source resource, the default behavior of such new resource is that it is not known by the App of the source resource (as it is not part of the desired state and does not have an `ownerReference`). 107 To make the App aware of the new resource, the `app.kubernetes.io/instance` label (or other ArgoCD tracking label, if configured) must be set on the resource. 108 It can be copied from the source resource, like this: 109 110 ```lua 111 -- ... 112 newObj = {} 113 newObj.metadata = {} 114 newObj.metadata.labels = {} 115 newObj.metadata.labels["app.kubernetes.io/instance"] = obj.metadata.labels["app.kubernetes.io/instance"] 116 -- ... 117 ``` 118 119 While the new resource will be part of the App with the tracking label in place, it will be immediately deleted if auto prune is set on the App. 120 To keep the resource, set `Prune=false` annotation on the resource, with this Lua snippet: 121 122 ```lua 123 -- ... 124 newObj.metadata.annotations = {} 125 newObj.metadata.annotations["argocd.argoproj.io/sync-options"] = "Prune=false" 126 -- ... 127 ``` 128 129 (If setting `Prune=false` behavior, the resource will not be deleted upon the deletion of the App, and will require a manual cleanup). 130 131 The resource and the App will now appear out of sync - which is the expected ArgoCD behavior upon creating a resource that is not part of the desired state. 132 133 If you wish to treat such an App as a synced one, add the following resource annotation in Lua code: 134 135 ```lua 136 -- ... 137 newObj.metadata.annotations["argocd.argoproj.io/compare-options"] = "IgnoreExtraneous" 138 -- ... 139 ``` 140 141 #### An action that produces a list of resources - a complete example: 142 143 ```yaml 144 resource.customizations.actions.ConfigMap: | 145 discovery.lua: | 146 actions = {} 147 actions["do-things"] = {} 148 return actions 149 definitions: 150 - name: do-things 151 action.lua: | 152 -- Create a new ConfigMap 153 cm1 = {} 154 cm1.apiVersion = "v1" 155 cm1.kind = "ConfigMap" 156 cm1.metadata = {} 157 cm1.metadata.name = "cm1" 158 cm1.metadata.namespace = obj.metadata.namespace 159 cm1.metadata.labels = {} 160 -- Copy ArgoCD tracking label so that the resource is recognized by the App 161 cm1.metadata.labels["app.kubernetes.io/instance"] = obj.metadata.labels["app.kubernetes.io/instance"] 162 cm1.metadata.annotations = {} 163 -- For Apps with auto-prune, set the prune false on the resource, so it does not get deleted 164 cm1.metadata.annotations["argocd.argoproj.io/sync-options"] = "Prune=false" 165 -- Keep the App synced even though it has a resource that is not in Git 166 cm1.metadata.annotations["argocd.argoproj.io/compare-options"] = "IgnoreExtraneous" 167 cm1.data = {} 168 cm1.data.myKey1 = "myValue1" 169 impactedResource1 = {} 170 impactedResource1.operation = "create" 171 impactedResource1.resource = cm1 172 173 -- Patch the original cm 174 obj.metadata.labels["aKey"] = "aValue" 175 impactedResource2 = {} 176 impactedResource2.operation = "patch" 177 impactedResource2.resource = obj 178 179 result = {} 180 result[1] = impactedResource1 181 result[2] = impactedResource2 182 return result 183 ```