Skip to content

Commit 4d3842b

Browse files
committed
feat: add support for Prune/Delete=false sync option
For consistency with Prune/Delete=confirm that are now present as application level sync option add Prune/Delete=false as sync option too. Signed-off-by: Arthur Outhenin-Chalandre <[email protected]>
1 parent afa5bae commit 4d3842b

File tree

5 files changed

+69
-0
lines changed

5 files changed

+69
-0
lines changed

controller/appcontroller.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1153,6 +1153,7 @@ func (ctrl *ApplicationController) removeProjectFinalizer(proj *appv1.AppProject
11531153
func (ctrl *ApplicationController) shouldBeDeleted(app *appv1.Application, obj *unstructured.Unstructured) bool {
11541154
return !kube.IsCRD(obj) && !isSelfReferencedApp(app, kube.GetObjectRef(obj)) &&
11551155
!resourceutil.HasAnnotationOption(obj, synccommon.AnnotationSyncOptions, synccommon.SyncOptionDisableDeletion) &&
1156+
(app.Spec.SyncPolicy == nil || !app.Spec.SyncPolicy.SyncOptions.HasOption(synccommon.SyncOptionDisableDeletion)) &&
11561157
!resourceutil.HasAnnotationOption(obj, helm.ResourcePolicyAnnotation, helm.ResourcePolicyKeep)
11571158
}
11581159

controller/appcontroller_test.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2358,6 +2358,17 @@ func Test_syncDeleteOption(t *testing.T) {
23582358
})
23592359
}
23602360

2361+
func Test_syncDeleteOptionGlobal(t *testing.T) {
2362+
app := newFakeApp()
2363+
app.Spec.SyncPolicy.SyncOptions = []string{"Delete=false"}
2364+
ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}, nil)
2365+
2366+
cm := newFakeCM()
2367+
cmObj := kube.MustToUnstructured(&cm)
2368+
delete := ctrl.shouldBeDeleted(app, cmObj)
2369+
assert.False(t, delete)
2370+
}
2371+
23612372
func TestAddControllerNamespace(t *testing.T) {
23622373
t.Run("set controllerNamespace when the app is in the controller namespace", func(t *testing.T) {
23632374
app := newFakeApp()

controller/sync.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,7 @@ func (m *appStateManager) SyncAppState(app *v1alpha1.Application, state *v1alpha
378378
sync.WithServerSideApplyManager(cdcommon.ArgoCDSSAManager),
379379
sync.WithPruneConfirmed(app.IsDeletionConfirmed(state.StartedAt.Time)),
380380
sync.WithRequiresPruneConfirmation(syncOp.SyncOptions.HasOption(common.SyncOptionPruneRequireConfirm)),
381+
sync.WithPruneDisabled(syncOp.SyncOptions.HasOption(common.SyncOptionDisablePrune)),
381382
sync.WithSkipDryRunOnMissingResource(syncOp.SyncOptions.HasOption(common.SyncOptionSkipDryRunOnMissingResource)),
382383
}
383384

docs/user-guide/sync-options.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,21 @@ metadata:
1414
argocd.argoproj.io/sync-options: Prune=false
1515
```
1616
17+
If you want to prevent any object from being pruned in the Application,
18+
it also can be enabled at the application level like in the example below:
19+
20+
```yaml
21+
apiVersion: argoproj.io/v1alpha1
22+
kind: Application
23+
spec:
24+
syncPolicy:
25+
syncOptions:
26+
- Prune=false
27+
```
28+
29+
Note that setting a Prune sync option on the application level will not override
30+
the same sync option set on a specific resource, both will still be applied.
31+
1732
The sync-status panel shows that pruning was skipped, and why:
1833
1934
![sync option no prune](../assets/sync-option-no-prune-sync-status.png)
@@ -101,6 +116,21 @@ metadata:
101116
argocd.argoproj.io/sync-options: Delete=false
102117
```
103118

119+
If you want to prevent any object from being deleted in the Application,
120+
it also can be enabled at the application level like in the example below:
121+
122+
```yaml
123+
apiVersion: argoproj.io/v1alpha1
124+
kind: Application
125+
spec:
126+
syncPolicy:
127+
syncOptions:
128+
- Delete=false
129+
```
130+
131+
Note that setting a Delete sync option on the application level will not override
132+
the same sync option set on a specific resource, both will still be applied.
133+
104134
## Resource Deletion With Confirmation
105135

106136
Resources such as Namespaces are critical and should not be deleted without confirmation. You can set the `Delete=confirm`

test/e2e/app_management_test.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1747,6 +1747,32 @@ func TestSyncOptionPruneFalse(t *testing.T) {
17471747
Expect(ResourceSyncStatusIs("Pod", "pod-1", SyncStatusCodeOutOfSync))
17481748
}
17491749

1750+
// make sure that if we deleted a resource from the app, it is not pruned if the app has the sync option Prune=false
1751+
func TestSyncOptionSyncOptionPruneFalse(t *testing.T) {
1752+
Given(t).
1753+
Path("two-nice-pods").
1754+
When().
1755+
CreateApp().
1756+
PatchApp(`[{
1757+
"op": "add",
1758+
"path": "/spec/syncPolicy",
1759+
"value": { "syncOptions": ["Prune=false"] }
1760+
}]`).
1761+
Sync().
1762+
Then().
1763+
Expect(OperationPhaseIs(OperationSucceeded)).
1764+
Expect(SyncStatusIs(SyncStatusCodeSynced)).
1765+
When().
1766+
DeleteFile("pod-1.yaml").
1767+
Refresh(RefreshTypeHard).
1768+
IgnoreErrors().
1769+
Sync().
1770+
Then().
1771+
Expect(OperationPhaseIs(OperationSucceeded)).
1772+
Expect(SyncStatusIs(SyncStatusCodeOutOfSync)).
1773+
Expect(ResourceSyncStatusIs("Pod", "pod-1", SyncStatusCodeOutOfSync))
1774+
}
1775+
17501776
// make sure that if we have an invalid manifest, we can add it if we disable validation, we get a server error rather than a client error
17511777
func TestSyncOptionValidateFalse(t *testing.T) {
17521778
Given(t).

0 commit comments

Comments
 (0)