|
9 | 9 | "testing"
|
10 | 10 |
|
11 | 11 | "github.com/stretchr/testify/assert"
|
| 12 | + "github.com/stretchr/testify/require" |
12 | 13 | "github.com/vmware-tanzu/carvel-kapp-controller/test/e2e"
|
13 | 14 | )
|
14 | 15 |
|
@@ -292,3 +293,98 @@ spec:
|
292 | 293 | assert.Error(t, err, "Expected to get time out error, but did not")
|
293 | 294 | })
|
294 | 295 | }
|
| 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