Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Create job action (#12174 and #4116) #12925

Merged
merged 67 commits into from
Jun 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
f9d79b0
Kind wildcard support in health customizations
reggie-k Oct 10, 2022
aff1d44
Updated health customizations docs to using the correct field with a /
reggie-k Oct 10, 2022
0654777
Updated health customizations docs to using the correct field with a /
reggie-k Oct 10, 2022
eedcd09
Document resource kind wildcard for custom health check
reggie-k Oct 10, 2022
a01a85e
Merge branch 'master' into master
reggie-k Oct 10, 2022
df70776
Merge branch 'master' into master
reggie-k Oct 11, 2022
e98d753
Implemented wildcard * support in API Group and Resource Kind and upd…
reggie-k Oct 12, 2022
90004c8
Merge branch 'master' of https://github.com/reggie-k/argo-cd
reggie-k Oct 12, 2022
a51f39a
Merge branch 'argoproj:master' into master
reggie-k Oct 12, 2022
55e2a0a
Merge branch 'master' of https://github.com/reggie-k/argo-cd
reggie-k Oct 12, 2022
1117332
Implemented wildcard * support in API Group and Resource Kind and upd…
reggie-k Oct 12, 2022
28d7d31
Implemented wildcard * support in API Group and Resource Kind and upd…
reggie-k Oct 12, 2022
1b603e4
Merge branch 'argoproj:master' into master
reggie-k Oct 13, 2022
390c71a
Added a custom create-from CronJob action
reggie-k Oct 14, 2022
82eba74
Merge branch 'argoproj:master' into create-job-action
reggie-k Oct 15, 2022
c2e5094
upstream sync
reggie-k Jan 13, 2023
5b8583e
Merge branch 'master' of https://github.com/argoproj/argo-cd into cre…
reggie-k Jan 14, 2023
53f43c4
Merge branch 'master' of https://github.com/argoproj/argo-cd into cre…
reggie-k Jan 27, 2023
3188376
Merge branch 'master' of https://github.com/argoproj/argo-cd into cre…
reggie-k Feb 1, 2023
76be5a6
in progress
reggie-k Feb 1, 2023
2e72471
in progress
reggie-k Feb 1, 2023
6c9cf61
in progress
reggie-k Feb 10, 2023
581d089
in progress
reggie-k Feb 23, 2023
13cdd0e
Merge branch 'master' of https://github.com/argoproj/argo-cd into cre…
reggie-k Feb 23, 2023
41be919
Merge branch 'master' of https://github.com/argoproj/argo-cd into cre…
reggie-k Feb 24, 2023
84f0b33
added a ns in the action.lua and fixed tests
reggie-k Feb 24, 2023
e6c0788
create-job
reggie-k Mar 3, 2023
512068d
in progress
reggie-k Mar 4, 2023
0ca42dd
upstream sync
reggie-k Mar 7, 2023
ea71a0e
more changes
reggie-k Mar 11, 2023
b28298e
full unit tests and action returning an array
reggie-k Mar 18, 2023
d41b64a
master sync
reggie-k Mar 18, 2023
fa757a9
cleanup
reggie-k Mar 18, 2023
a35891b
fix the custom tests
reggie-k Mar 20, 2023
c9bdc62
Merge branch 'master' of https://github.com/argoproj/argo-cd into cre…
reggie-k Mar 20, 2023
abdae1b
e2e tests
reggie-k Mar 20, 2023
aea1d86
Merge branch 'master' of https://github.com/argoproj/argo-cd into cre…
reggie-k Mar 20, 2023
9429865
json marshaling annotations ImpactedResource, e2e tests and docs
reggie-k Mar 21, 2023
063cacf
more docs and tests
reggie-k Mar 24, 2023
752333e
upstream sync
reggie-k Mar 24, 2023
6708f49
Merge branch 'master' of https://github.com/argoproj/argo-cd into cre…
reggie-k Mar 24, 2023
2a0b3c7
upstream sync
reggie-k Mar 24, 2023
e99e097
fix wrong return upon going over the impacted resources + docs + fixi…
reggie-k Mar 25, 2023
3d271c0
docs
reggie-k Mar 25, 2023
6df8f23
better error handling
reggie-k Mar 25, 2023
58893d4
K8SOperation as an enum
reggie-k Apr 13, 2023
8dabaf3
added dry-run for create operation
reggie-k Apr 14, 2023
d8c22bb
Merge branch 'master' of https://github.com/argoproj/argo-cd into cre…
reggie-k Apr 14, 2023
d956180
merge upstream
crenshaw-dev May 27, 2023
73d2cdd
small changes
crenshaw-dev May 27, 2023
9632537
Merge pull request #2 from crenshaw-dev/create-job-action-changes
reggie-k May 28, 2023
e19d400
Merge remote-tracking branch 'origin/master' into create-job-action
crenshaw-dev May 29, 2023
f8dc6f7
Merge branch 'master' of https://github.com/argoproj/argo-cd into cre…
reggie-k May 30, 2023
b1e845b
ref to my gitops-engine fork out
reggie-k May 30, 2023
872630c
ref to my gitops-engine fork out
reggie-k May 30, 2023
128d78b
ref to my gitops-engine fork out
reggie-k May 30, 2023
89f2dcf
ref to my gitops-engine fork out
reggie-k May 30, 2023
c139cea
ref to my gitops-engine fork out
reggie-k May 30, 2023
44726ee
Merge branch 'master' of https://github.com/argoproj/argo-cd into cre…
reggie-k May 30, 2023
84bb8a3
gitops engine dependency and test fixes
reggie-k Jun 2, 2023
d43a014
upstream sync
reggie-k Jun 2, 2023
76c0aa2
add workflows action
crenshaw-dev Jun 5, 2023
aa07050
cronworkflow and workflowtemplate actions
crenshaw-dev Jun 22, 2023
6fb165f
Merge pull request #3 from crenshaw-dev/create-job-action
reggie-k Jun 22, 2023
99e0d45
Merge remote-tracking branch 'origin/master' into create-job-action
crenshaw-dev Jun 22, 2023
fff31f1
Merge branch 'master' into create-job-action
reggie-k Jun 23, 2023
cd2302f
update gitops-engine
crenshaw-dev Jun 23, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 18 additions & 5 deletions cmd/argocd/commands/admin/settings.go
Original file line number Diff line number Diff line change
Expand Up @@ -538,13 +538,26 @@ argocd admin settings resource-overrides action run /tmp/deploy.yaml restart --a
modifiedRes, err := luaVM.ExecuteResourceAction(&res, action.ActionLua)
errors.CheckError(err)

if reflect.DeepEqual(&res, modifiedRes) {
_, _ = fmt.Printf("No fields had been changed by action: \n%s\n", action.Name)
return
for _, impactedResource := range modifiedRes {
result := impactedResource.UnstructuredObj
switch impactedResource.K8SOperation {
// No default case since a not supported operation would have failed upon unmarshaling earlier
case lua.PatchOperation:
if reflect.DeepEqual(&res, modifiedRes) {
_, _ = fmt.Printf("No fields had been changed by action: \n%s\n", action.Name)
return
}

_, _ = fmt.Printf("Following fields have been changed:\n\n")
_ = cli.PrintDiff(res.GetName(), &res, result)
case lua.CreateOperation:
yamlBytes, err := yaml.Marshal(impactedResource.UnstructuredObj)
errors.CheckError(err)
fmt.Println("Following resource was created:")
fmt.Println(bytes.NewBuffer(yamlBytes).String())
}
}

_, _ = fmt.Printf("Following fields have been changed:\n\n")
_ = cli.PrintDiff(res.GetName(), &res, modifiedRes)
})
},
}
Expand Down
65 changes: 64 additions & 1 deletion cmd/argocd/commands/admin/settings_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,17 @@ spec:
replicas: 0`
)

const (
testCronJobYAML = `apiVersion: batch/v1
kind: CronJob
metadata:
name: hello
namespace: test-ns
uid: "123"
spec:
schedule: "* * * * *"`
)

func tempFile(content string) (string, io.Closer, error) {
f, err := os.CreateTemp("", "*.yaml")
if err != nil {
Expand Down Expand Up @@ -335,6 +346,12 @@ func TestResourceOverrideAction(t *testing.T) {
}
defer utils.Close(closer)

cronJobFile, closer, err := tempFile(testCronJobYAML)
if !assert.NoError(t, err) {
return
}
defer utils.Close(closer)

t.Run("NoActions", func(t *testing.T) {
cmd := NewResourceOverridesCommand(newCmdContext(map[string]string{
"resource.customizations": `apps/Deployment: {}`}))
Expand All @@ -347,7 +364,7 @@ func TestResourceOverrideAction(t *testing.T) {
assert.Contains(t, out, "Actions are not configured")
})

t.Run("ActionConfigured", func(t *testing.T) {
t.Run("OldStyleActionConfigured", func(t *testing.T) {
cmd := NewResourceOverridesCommand(newCmdContext(map[string]string{
"resource.customizations": `apps/Deployment:
actions: |
Expand Down Expand Up @@ -381,4 +398,50 @@ restart false
resume false
`)
})

t.Run("NewStyleActionConfigured", func(t *testing.T) {
cmd := NewResourceOverridesCommand(newCmdContext(map[string]string{
"resource.customizations": `batch/CronJob:
actions: |
discovery.lua: |
actions = {}
actions["create-a-job"] = {["disabled"] = false}
return actions
definitions:
- name: test
action.lua: |
job1 = {}
job1.apiVersion = "batch/v1"
job1.kind = "Job"
job1.metadata = {}
job1.metadata.name = "hello-1"
job1.metadata.namespace = "obj.metadata.namespace"
impactedResource1 = {}
impactedResource1.operation = "create"
impactedResource1.resource = job1
result = {}
result[1] = impactedResource1
return result
`}))
out, err := captureStdout(func() {
cmd.SetArgs([]string{"run-action", cronJobFile, "test"})
err := cmd.Execute()
assert.NoError(t, err)
})
assert.NoError(t, err)
assert.Contains(t, out, "resource was created:")
assert.Contains(t, out, "hello-1")

out, err = captureStdout(func() {
cmd.SetArgs([]string{"list-actions", cronJobFile})
err := cmd.Execute()
assert.NoError(t, err)
})

assert.NoError(t, err)
assert.Contains(t, out, "NAME")
assert.Contains(t, out, "ENABLED")
assert.Contains(t, out, "create-a-job")
assert.Contains(t, out, "false")
})
}
133 changes: 131 additions & 2 deletions docs/operator-manual/resource_actions.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,30 @@ Argo CD supports custom resource actions written in [Lua](https://www.lua.org/).
* Have a custom resource for which Argo CD does not provide any built-in actions.
* Have a commonly performed manual task that might be error prone if executed by users via `kubectl`

The resource actions act on a single object.

You can define your own custom resource actions in the `argocd-cm` ConfigMap.

### Custom Resource Action Types

#### An action that modifies the source resource

This action modifies and returns the source resource.
This kind of action was the only one available till 2.8, and it is still supported.

#### An action that produces a list of new or modified resources

**An alpha feature, introduced in 2.8.**

This action returns a list of impacted resources, each impacted resource has a K8S resource and an operation to perform on.
Currently supported operations are "create" and "patch", "patch" is only supported for the source resource.
Creating new resources is possible, by specifying a "create" operation for each such resource in the returned list.
One of the returned resources can be the modified source object, with a "patch" operation, if needed.
See the definition examples below.

### Define a Custom Resource Action in `argocd-cm` ConfigMap

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.
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.
The customizations key is in the format of `resource.customizations.actions.<apiGroup_Kind>`.

```yaml
Expand Down Expand Up @@ -51,4 +70,114 @@ resource.customizations.actions.batch_CronJob: |

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.

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 must return an optionally modified version of the resource. In this example, we are simply setting `.spec.suspend` to either `true` or `false`.
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`.

#### Creating new resources with a custom action

!!! important
Creating resources via the Argo CD UI is an intentional, strategic departure from GitOps principles. We recommend
that you use this feature sparingly and only for resources that are not part of the desired state of the
application.

The resource the action is invoked on would be referred to as the `source resource`.
The new resource and all the resources implicitly created as a result, must be permitted on the AppProject level, otherwise the creation will fail.

##### Creating a source resource child resources with a custom action

If the new resource represents a k8s child of the source resource, the source resource ownerReference must be set on the new resource.
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:

```lua
-- ...
ownerRef = {}
ownerRef.apiVersion = obj.apiVersion
ownerRef.kind = obj.kind
ownerRef.name = obj.metadata.name
ownerRef.uid = obj.metadata.uid
job = {}
job.metadata = {}
job.metadata.ownerReferences = {}
job.metadata.ownerReferences[1] = ownerRef
-- ...
```

##### Creating independent child resources with a custom action

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`).
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.
It can be copied from the source resource, like this:

```lua
-- ...
newObj = {}
newObj.metadata = {}
newObj.metadata.labels = {}
newObj.metadata.labels["app.kubernetes.io/instance"] = obj.metadata.labels["app.kubernetes.io/instance"]
-- ...
```

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.
To keep the resource, set `Prune=false` annotation on the resource, with this Lua snippet:

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

(If setting `Prune=false` behavior, the resource will not be deleted upon the deletion of the App, and will require a manual cleanup).

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.

If you wish to treat such an App as a synced one, add the following resource annotation in Lua code:

```lua
-- ...
newObj.metadata.annotations["argocd.argoproj.io/compare-options"] = "IgnoreExtraneous"
-- ...
```

#### An action that produces a list of resources - a complete example:

```yaml
resource.customizations.actions.ConfigMap: |
discovery.lua: |
actions = {}
actions["do-things"] = {}
return actions
definitions:
- name: do-things
action.lua: |
-- Create a new ConfigMap
cm1 = {}
cm1.apiVersion = "v1"
cm1.kind = "ConfigMap"
cm1.metadata = {}
cm1.metadata.name = "cm1"
cm1.metadata.namespace = obj.metadata.namespace
cm1.metadata.labels = {}
-- Copy ArgoCD tracking label so that the resource is recognized by the App
cm1.metadata.labels["app.kubernetes.io/instance"] = obj.metadata.labels["app.kubernetes.io/instance"]
cm1.metadata.annotations = {}
-- For Apps with auto-prune, set the prune false on the resource, so it does not get deleted
cm1.metadata.annotations["argocd.argoproj.io/sync-options"] = "Prune=false"
-- Keep the App synced even though it has a resource that is not in Git
cm1.metadata.annotations["argocd.argoproj.io/compare-options"] = "IgnoreExtraneous"
cm1.data = {}
cm1.data.myKey1 = "myValue1"
impactedResource1 = {}
impactedResource1.operation = "create"
impactedResource1.resource = cm1

-- Patch the original cm
obj.metadata.labels["aKey"] = "aValue"
impactedResource2 = {}
impactedResource2.operation = "patch"
impactedResource2.resource = obj

result = {}
result[1] = impactedResource1
result[2] = impactedResource2
return result
```
42 changes: 42 additions & 0 deletions docs/operator-manual/upgrading/2.7-2.8.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,45 @@ Prior to `v2.8`, the `List` endpoint on the `ClusterService` did **not** filter
clusters when responding, despite accepting query parameters. This bug has
been addressed, and query parameters are now taken into account to filter the
resulting list of clusters.

## Configure RBAC to account for new actions

2.8 introduces three new actions:
* Create a Job from a CronJob
* Create a Workflow from a CronWorkflow
* Create a Workflow from a WorkflowTemplate

When you upgrade to 2.8, RBAC policies with `applications` in the *resource*
field and `*` or `action/*` in the action field, it will automatically grant the
ability to use these new actions.

If you would like to avoid granting these new permissions, you can update your RBAC policies to be more specific.

### Example

Old:

```csv
p, role:action-runner, applications, actions/, *, allow
```

New:

```csv
p, role:action-runner, applications, action/argoproj.io/Rollout/abort, *, allow
p, role:action-runner, applications, action/argoproj.io/Rollout/promote-full, *, allow
p, role:action-runner, applications, action/argoproj.io/Rollout/retry, *, allow
p, role:action-runner, applications, action/argoproj.io/Rollout/resume, *, allow
p, role:action-runner, applications, action/argoproj.io/Rollout/restart, *, allow
p, role:action-runner, applications, action/argoproj.io/AnalysisRun/terminate, *, allow
p, role:action-runner, applications, action/apps/DaemonSet/restart, *, allow
p, role:action-runner, applications, action/apps/StatefulSet/restart, *, allow
p, role:action-runner, applications, action/apps/Deployment/pause, *, allow
p, role:action-runner, applications, action/apps/Deployment/resume, *, allow
p, role:action-runner, applications, action/apps/Deployment/restart, *, allow

# If you don't want to grant the new permissions, don't include the following lines
p, role:action-runner, applications, action/argoproj.io/WorkflowTemplate/create-workflow, *, allow
p, role:action-runner, applications, action/argoproj.io/CronWorkflow/create-workflow, *, allow
p, role:action-runner, applications, action/batch/CronJob/create-job, *, allow
```
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ require (
github.com/TomOnTime/utfutil v0.0.0-20180511104225-09c41003ee1d
github.com/alicebob/miniredis/v2 v2.30.3
github.com/antonmedv/expr v1.12.5
github.com/argoproj/gitops-engine v0.7.1-0.20230526233214-ad9a694fe4bc
github.com/argoproj/gitops-engine v0.7.1-0.20230607163028-425d65e07695
github.com/argoproj/notifications-engine v0.4.1-0.20230620204159-3446d4ae8520
github.com/argoproj/pkg v0.13.7-0.20221221191914-44694015343d
github.com/aws/aws-sdk-go v1.44.288
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,8 @@ github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210826220005-b48c857c3a0e/go.m
github.com/antonmedv/expr v1.12.5 h1:Fq4okale9swwL3OeLLs9WD9H6GbgBLJyN/NUHRv+n0E=
github.com/antonmedv/expr v1.12.5/go.mod h1:FPC8iWArxls7axbVLsW+kpg1mz29A1b2M6jt+hZfDkU=
github.com/appscode/go v0.0.0-20191119085241-0887d8ec2ecc/go.mod h1:OawnOmAL4ZX3YaPdN+8HTNwBveT1jMsqP74moa9XUbE=
github.com/argoproj/gitops-engine v0.7.1-0.20230526233214-ad9a694fe4bc h1:i6OgOvFFsoWiGBFEhhDNcYoRtxxtrVwcD7wCEeqhct4=
github.com/argoproj/gitops-engine v0.7.1-0.20230526233214-ad9a694fe4bc/go.mod h1:WpA/B7tgwfz+sdNE3LqrTrb7ArEY1FOPI2pAGI0hfPc=
github.com/argoproj/gitops-engine v0.7.1-0.20230607163028-425d65e07695 h1:w8OPbqHyhWxLyC4LZgs5JBUe7AOkJpNZqFa92yy7Kmc=
github.com/argoproj/gitops-engine v0.7.1-0.20230607163028-425d65e07695/go.mod h1:WpA/B7tgwfz+sdNE3LqrTrb7ArEY1FOPI2pAGI0hfPc=
github.com/argoproj/notifications-engine v0.4.1-0.20230620204159-3446d4ae8520 h1:ZCpg1Zk78E8QxMI52w6ZIddxkBHv27YWmfWQdxxWUkw=
github.com/argoproj/notifications-engine v0.4.1-0.20230620204159-3446d4ae8520/go.mod h1:sbhf4EjAUGAqRdHIzifDIiWsjlsTfmytVJJCCiUdyVA=
github.com/argoproj/pkg v0.13.7-0.20221221191914-44694015343d h1:7fXEKF3OQ9i1PrgieA6FLrXOL3UAKyiotomn0RHevds=
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ metadata:
annotations:
deployment.kubernetes.io/revision: "1"
creationTimestamp: "2021-09-21T22:35:20Z"
name: nginx-deploy
namespace: default
generation: 2
spec:
paused: true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ metadata:
deployment.kubernetes.io/revision: "1"
creationTimestamp: "2021-09-21T22:35:20Z"
generation: 3
name: nginx-deploy
namespace: default
spec:
progressDeadlineSeconds: 600
replicas: 3
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
actionTests:
- action: create-workflow
inputPath: testdata/cronworkflow.yaml
expectedOutputPath: testdata/workflow.yaml
Loading