> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/argoproj/argo-cd/llms.txt
> Use this file to discover all available pages before exploring further.

# Resource Actions

> Define custom actions that users can perform on Kubernetes resources

## Overview

Argo CD allows operators to define custom actions that users can perform on specific resource types. Actions are implemented as Lua scripts and can modify resources or create new ones.

<Info>
  **Built-in Actions**

  Argo CD includes built-in actions like `restart` for DaemonSet/Deployment/StatefulSet and `retry` for Argo Rollouts. You can extend these capabilities with custom actions.
</Info>

## Action Types

Argo CD supports two types of resource actions:

<Tabs>
  <Tab title="Modify Resource (Classic)">
    Returns the modified source resource. This was the only action type until v2.8 and is still supported.

    ```lua theme={null}
    -- Suspend a CronJob
    obj.spec.suspend = true
    return obj
    ```
  </Tab>

  <Tab title="Create/Patch Resources (v2.8+)">
    Returns a list of impacted resources with operations. Supports creating new resources.

    ```lua theme={null}
    -- Create a Job from CronJob and patch the CronJob
    result = {}
    result[1] = {operation = "create", resource = newJob}
    result[2] = {operation = "patch", resource = obj}
    return result
    ```

    <Note>
      This is an alpha feature introduced in v2.8.
    </Note>
  </Tab>
</Tabs>

## Basic Configuration

Define actions in the `argocd-cm` ConfigMap using the format:
`resource.customizations.actions.<apiGroup>_<kind>`

### Simple Action Example

```yaml theme={null}
apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-cm
  namespace: argocd
data:
  resource.customizations.actions.batch_CronJob: |
    discovery.lua: |
      actions = {}
      actions["suspend"] = {["disabled"] = true}
      actions["resume"] = {["disabled"] = true}
      
      local suspend = false
      if obj.spec.suspend ~= nil then
        suspend = obj.spec.suspend
      end
      
      if suspend then
        actions["resume"]["disabled"] = false
      else
        actions["suspend"]["disabled"] = false
      end
      
      return actions
      
    definitions:
    - name: suspend
      action.lua: |
        obj.spec.suspend = true
        return obj
        
    - name: resume
      action.lua: |
        if obj.spec.suspend ~= nil and obj.spec.suspend then
          obj.spec.suspend = false
        end
        return obj
```

## Discovery Script

The `discovery.lua` script determines which actions are available and whether they're enabled:

```lua theme={null}
actions = {}

-- Define available actions
actions["restart"] = {}
actions["scale"] = {}
actions["delete-pod"] = {["disabled"] = true}

-- Conditionally enable actions based on resource state
if obj.spec.replicas ~= nil and obj.spec.replicas == 0 then
  actions["restart"]["disabled"] = true
end

if obj.status ~= nil and obj.status.availableReplicas ~= nil then
  actions["delete-pod"]["disabled"] = false
end

return actions
```

<Tip>
  **Dynamic Actions**

  Use the resource's current state to enable/disable actions dynamically. This provides better UX by only showing relevant actions.
</Tip>

## Action Definitions

Each action must have a definition with the action logic:

```yaml theme={null}
definitions:
- name: restart
  action.lua: |
    local os = require("os")
    if obj.spec.template.metadata == nil then
      obj.spec.template.metadata = {}
    end
    if obj.spec.template.metadata.annotations == nil then
      obj.spec.template.metadata.annotations = {}
    end
    obj.spec.template.metadata.annotations["kubectl.kubernetes.io/restartedAt"] = os.date("!%Y-%m-%dT%XZ")
    return obj
```

## Customizing Action Appearance

Add icons and display names to your actions:

```lua theme={null}
local actions = {}

actions["create-workflow"] = {
  ["iconClass"] = "fa fa-fw fa-plus",
  ["displayName"] = "Create Workflow"
}

actions["terminate"] = {
  ["iconClass"] = "fa fa-fw fa-stop-circle",
  ["displayName"] = "Terminate Analysis"
}

return actions
```

<Note>
  Use [FontAwesome free icons](https://fontawesome.com/search?ic=free). The `fa-fw` class ensures fixed-width display.
</Note>

## Action Parameters

Define parameters that users can provide when executing actions:

```lua theme={null}
actions["scale"] = {
  ["displayName"] = "Scale",
  ["iconClass"] = "fa fa-fw fa-arrows-v"
}

actions["scale"].params = {
  {
    name = "replicas",
    type = "number",
    default = "1"
  }
}

return actions
```

Access parameters in the action script:

```lua theme={null}
local replicas = tonumber(params.replicas) or 1
obj.spec.replicas = replicas
return obj
```

## Creating New Resources

<Warning>
  **GitOps Departure**

  Creating resources via the UI departs from GitOps principles. Use this sparingly and only for resources not part of the desired state.
</Warning>

### Creating Child Resources

Set `ownerReference` for Kubernetes garbage collection:

```lua theme={null}
-- Create a Job from a CronJob
ownerRef = {}
ownerRef.apiVersion = obj.apiVersion
ownerRef.kind = obj.kind
ownerRef.name = obj.metadata.name
ownerRef.uid = obj.metadata.uid

job = {}
job.apiVersion = "batch/v1"
job.kind = "Job"
job.metadata = {}
job.metadata.name = obj.metadata.name .. "-manual-" .. os.time()
job.metadata.namespace = obj.metadata.namespace
job.metadata.ownerReferences = {ownerRef}
job.spec = obj.spec.jobTemplate.spec

result = {}
result[1] = {operation = "create", resource = job}
return result
```

### Creating Independent Resources

<Steps>
  <Step title="Add Tracking Label">
    Copy the Argo CD tracking label so the App recognizes the resource:

    ```lua theme={null}
    newObj.metadata.labels = {}
    newObj.metadata.labels["app.kubernetes.io/instance"] = 
      obj.metadata.labels["app.kubernetes.io/instance"]
    ```
  </Step>

  <Step title="Prevent Auto-Prune">
    Set annotation to prevent deletion with auto-prune:

    ```lua theme={null}
    newObj.metadata.annotations = {}
    newObj.metadata.annotations["argocd.argoproj.io/sync-options"] = 
      "Prune=false"
    ```
  </Step>

  <Step title="Keep App Synced (Optional)">
    Prevent out-of-sync status:

    ```lua theme={null}
    newObj.metadata.annotations["argocd.argoproj.io/compare-options"] = 
      "IgnoreExtraneous"
    ```
  </Step>
</Steps>

### Complete Creation Example

```yaml theme={null}
resource.customizations.actions.ConfigMap: |
  discovery.lua: |
    actions = {}
    actions["create-backup"] = {
      ["iconClass"] = "fa fa-fw fa-save",
      ["displayName"] = "Create Backup"
    }
    return actions
    
  definitions:
  - name: create-backup
    action.lua: |
      local os = require("os")
      
      -- Create backup ConfigMap
      backup = {}
      backup.apiVersion = "v1"
      backup.kind = "ConfigMap"
      backup.metadata = {}
      backup.metadata.name = obj.metadata.name .. "-backup-" .. os.time()
      backup.metadata.namespace = obj.metadata.namespace
      backup.metadata.labels = {}
      backup.metadata.labels["app.kubernetes.io/instance"] = 
        obj.metadata.labels["app.kubernetes.io/instance"]
      backup.metadata.labels["backup-of"] = obj.metadata.name
      backup.metadata.annotations = {}
      backup.metadata.annotations["argocd.argoproj.io/sync-options"] = 
        "Prune=false"
      backup.metadata.annotations["argocd.argoproj.io/compare-options"] = 
        "IgnoreExtraneous"
      backup.data = obj.data
      
      -- Also update original with backup timestamp
      if obj.metadata.annotations == nil then
        obj.metadata.annotations = {}
      end
      obj.metadata.annotations["last-backup"] = os.date("!%Y-%m-%dT%XZ")
      
      result = {}
      result[1] = {operation = "create", resource = backup}
      result[2] = {operation = "patch", resource = obj}
      return result
```

## Merging with Built-in Actions

By default, custom actions override built-in actions. To keep built-in actions:

```yaml theme={null}
resource.customizations.actions.argoproj.io_Rollout: |
  mergeBuiltinActions: true
  discovery.lua: |
    actions = {}
    actions["custom-action"] = {}
    return actions
  definitions:
  - name: custom-action
    action.lua: |
      return obj
```

<Note>
  Custom actions have precedence over built-in actions when names conflict.
</Note>

## Contributing Actions

Contribute actions to the Argo CD repository:

```
argo-cd/
└── resource_customizations/
    └── your.crd.group.io/
        └── MyKind/
            └── actions/
                ├── action_test.yaml
                ├── discovery.lua
                ├── testdata/
                │   ├── running.yaml
                │   └── terminated.yaml
                └── <action-name>/
                    └── action.lua
```

### Test File Format

```yaml theme={null}
discoveryTests:
- inputPath: testdata/running.yaml
  result:
  - name: terminate
    disabled: false
  - name: suspend  
    disabled: true
    
- inputPath: testdata/terminated.yaml
  result:
  - name: terminate
    disabled: true

actionTests:
- action: terminate
  inputPath: testdata/running.yaml
  expectedOutputPath: testdata/running_terminated.yaml
```

**Run tests:**

```bash theme={null}
go test -v ./resource_customizations/.../actions/
```

## RBAC for Actions

Control access to actions using RBAC:

```csv theme={null}
p, role:action-runner, action/*, *, */*, allow
p, role:limited-user, action/apps/Deployment/restart, *, */*, allow
p, role:limited-user, action/apps/Deployment/scale, *, */*, deny
```

See the [RBAC documentation](https://argo-cd.readthedocs.io/en/latest/operator-manual/rbac/#the-action-action) for details.

## Best Practices

<AccordionGroup>
  <Accordion title="Validate Input" icon="shield-check">
    Always validate user input and resource state:

    ```lua theme={null}
    if obj.spec.replicas == nil then
      error("Resource does not support scaling")
    end

    local replicas = tonumber(params.replicas)
    if replicas == nil or replicas < 0 then
      error("Invalid replica count")
    end
    ```
  </Accordion>

  <Accordion title="Provide Feedback" icon="message">
    Return meaningful messages on errors:

    ```lua theme={null}
    if obj.status.phase == "Failed" then
      error("Cannot restart a failed job. Delete and recreate instead.")
    end
    ```
  </Accordion>

  <Accordion title="Test Thoroughly" icon="vial">
    Create comprehensive tests covering:

    * Normal operation
    * Edge cases
    * Error conditions
    * Various resource states
  </Accordion>

  <Accordion title="Use Semantic Names" icon="tag">
    Choose clear, action-oriented names:

    * ✅ `restart`, `scale`, `create-backup`
    * ❌ `do-thing`, `action1`, `fix`
  </Accordion>
</AccordionGroup>

## Security Considerations

<Warning>
  **Resource Permissions**

  When creating resources:

  * New resources must be permitted at the AppProject level
  * Users need appropriate RBAC permissions
  * Consider the security implications of creating resources outside GitOps
</Warning>

## Example: Scale Deployment

```yaml theme={null}
resource.customizations.actions.apps_Deployment: |
  discovery.lua: |
    actions = {}
    actions["scale"] = {
      ["iconClass"] = "fa fa-fw fa-arrows-v",
      ["displayName"] = "Scale"
    }
    
    -- Add parameter definition
    actions["scale"].params = {
      {
        name = "replicas",
        type = "number",
        default = tostring(obj.spec.replicas or 1)
      }
    }
    
    -- Disable if already scaling
    if obj.status ~= nil and obj.status.replicas ~= obj.status.updatedReplicas then
      actions["scale"]["disabled"] = true
    end
    
    return actions
    
  definitions:
  - name: scale  
    action.lua: |
      local replicas = tonumber(params.replicas)
      
      if replicas == nil or replicas < 0 then
        error("Invalid replica count: " .. params.replicas)
      end
      
      if replicas > 100 then
        error("Replica count exceeds maximum allowed (100)")
      end
      
      obj.spec.replicas = replicas
      return obj
```

## Next Steps

<CardGroup cols={2}>
  <Card title="Custom Health Checks" icon="heart-pulse" href="/developers/custom-health-checks">
    Define custom health checks for resources
  </Card>

  <Card title="UI Extensions" icon="puzzle-piece" href="/developers/ui-extensions">
    Extend the Argo CD web interface
  </Card>

  <Card title="Built-in Actions" icon="github" href="https://github.com/argoproj/argo-cd/tree/master/resource_customizations">
    Browse built-in resource actions
  </Card>

  <Card title="RBAC" icon="shield" href="https://argo-cd.readthedocs.io/en/latest/operator-manual/rbac/">
    Configure action permissions
  </Card>
</CardGroup>
