Skip to content

Commit 6247224

Browse files
authored
Do not overwrite kapp deploy status during delete (#1460)
Signed-off-by: Praveen Rewar <[email protected]>
1 parent ba21a6c commit 6247224

File tree

2 files changed

+109
-7
lines changed

2 files changed

+109
-7
lines changed

pkg/app/app_reconcile.go

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -166,13 +166,14 @@ func (a *App) updateLastDeploy(result exec.CmdRunResult) exec.CmdRunResult {
166166
result = result.WithFriendlyYAMLStrings()
167167

168168
a.app.Status.Deploy = &v1alpha1.AppStatusDeploy{
169-
Stdout: result.Stdout,
170-
Stderr: result.Stderr,
171-
Finished: result.Finished,
172-
ExitCode: result.ExitCode,
173-
Error: result.ErrorStr(),
174-
StartedAt: a.app.Status.Deploy.StartedAt,
175-
UpdatedAt: metav1.NewTime(time.Now().UTC()),
169+
Stdout: result.Stdout,
170+
Stderr: result.Stderr,
171+
Finished: result.Finished,
172+
ExitCode: result.ExitCode,
173+
Error: result.ErrorStr(),
174+
StartedAt: a.app.Status.Deploy.StartedAt,
175+
UpdatedAt: metav1.NewTime(time.Now().UTC()),
176+
KappDeployStatus: a.app.Status.Deploy.KappDeployStatus,
176177
}
177178

178179
defer a.updateStatus("marking last deploy")
@@ -181,6 +182,11 @@ func (a *App) updateLastDeploy(result exec.CmdRunResult) exec.CmdRunResult {
181182
return result
182183
}
183184

185+
// Do not overwrite kapp deploy status during delete
186+
if len(a.metadata.LastChange.Namespaces) == 0 {
187+
return result
188+
}
189+
184190
usedGKs := []metav1.GroupKind{}
185191
for _, gk := range a.metadata.UsedGKs {
186192
usedGKs = append(usedGKs, metav1.GroupKind{

test/e2e/kappcontroller/namespace_deletion_test.go

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"testing"
1010

1111
"github.com/stretchr/testify/assert"
12+
"github.com/stretchr/testify/require"
1213
"github.com/vmware-tanzu/carvel-kapp-controller/test/e2e"
1314
)
1415

@@ -292,3 +293,98 @@ spec:
292293
assert.Error(t, err, "Expected to get time out error, but did not")
293294
})
294295
}
296+
297+
func Test_NamespaceDelete_AppWithResourcesInOutOfOrderTerminatingNamespaces(t *testing.T) {
298+
env := e2e.BuildEnv(t)
299+
logger := e2e.Logger{}
300+
kapp := e2e.Kapp{t, env.Namespace, logger}
301+
kubectl := e2e.Kubectl{t, env.Namespace, logger}
302+
303+
nsName1 := "ns-delete-1"
304+
nsName2 := "ns-delete-2"
305+
nsApp := "testnamespaces"
306+
name := "resources-in-different-namespaces"
307+
308+
namespaceTemplate := `---
309+
apiVersion: v1
310+
kind: Namespace
311+
metadata:
312+
name: %v`
313+
namespaceYAML := fmt.Sprintf(namespaceTemplate, nsName1) + "\n" + fmt.Sprintf(namespaceTemplate, nsName2)
314+
315+
appYaml := fmt.Sprintf(`---
316+
apiVersion: kappctrl.k14s.io/v1alpha1
317+
kind: App
318+
metadata:
319+
name: %s
320+
spec:
321+
serviceAccountName: kappctrl-e2e-ns-sa
322+
fetch:
323+
- inline:
324+
paths:
325+
file.yml: |
326+
apiVersion: v1
327+
kind: ConfigMap
328+
metadata:
329+
name: configmap
330+
namespace: %s
331+
data:
332+
key: value
333+
---
334+
apiVersion: v1
335+
kind: ConfigMap
336+
metadata:
337+
finalizers:
338+
- kubernetes
339+
name: configmap
340+
namespace: %s
341+
data:
342+
key: value
343+
template:
344+
- ytt: {}
345+
deploy:
346+
- kapp:
347+
delete:
348+
rawOptions: ["--wait-timeout=2s"]`, name, nsName1, nsName2) + e2e.ServiceAccounts{nsName1}.ForClusterYAML()
349+
350+
cleanUp := func() {
351+
kapp.Run([]string{"delete", "-a", name})
352+
}
353+
354+
cleanUpTestNamespace := func() {
355+
kapp.Run([]string{"delete", "-a", name})
356+
kapp.Run([]string{"delete", "-a", nsApp})
357+
}
358+
359+
cleanUp()
360+
defer cleanUp()
361+
defer cleanUpTestNamespace()
362+
363+
logger.Section("create namespace and deploy App", func() {
364+
kapp.RunWithOpts([]string{"deploy", "-a", nsApp, "-f", "-"}, e2e.RunOpts{StdinReader: strings.NewReader(namespaceYAML)})
365+
kapp.RunWithOpts([]string{"deploy", "-f", "-", "-a", name, "--into-ns", nsName1}, e2e.RunOpts{StdinReader: strings.NewReader(appYaml)})
366+
})
367+
368+
logger.Section("delete namespace", func() {
369+
// Deleting the namespace directly could delete the service account, so let's delete the App first
370+
_, err := kubectl.RunWithOpts([]string{"delete", "app", name, "-n", nsName1, "--timeout=10s"}, e2e.RunOpts{AllowError: true, NoNamespace: true})
371+
require.Error(t, err, "Expected to timeout")
372+
373+
// Deletion should timeout as test-ns-2 is not being terminated and the cm present in it has a finalizer
374+
_, err = kubectl.RunWithOpts([]string{"delete", "ns", nsName1, "--timeout=10s"}, e2e.RunOpts{AllowError: true, NoNamespace: true})
375+
require.Error(t, err, "Expected to timeout")
376+
377+
// At this point the service account should be deleted,
378+
// so removing the finalizer on cm in test-ns-2 wouldn't help
379+
kubectl.RunWithOpts([]string{"patch", "cm", "configmap", "--type=json", "--patch", `[{ "op": "remove", "path": "/metadata/finalizers"}]`,
380+
"-n", nsName2}, e2e.RunOpts{NoNamespace: true})
381+
382+
kubectl.RunWithOpts([]string{"get", "App", name, "-n", nsName1}, e2e.RunOpts{NoNamespace: true})
383+
384+
// Deleting the second namespace now should do a noop delete for the App
385+
kubectl.RunWithOpts([]string{"delete", "ns", nsName2, "--timeout=1m"}, e2e.RunOpts{NoNamespace: true})
386+
387+
_, err = kubectl.RunWithOpts([]string{"get", "App", name, "-n", nsName1}, e2e.RunOpts{NoNamespace: true, AllowError: true})
388+
require.Error(t, err, "Expected not found error")
389+
})
390+
}

0 commit comments

Comments
 (0)