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

Delete namespace when a gitRepo is deleted #2373

Merged
merged 2 commits into from
May 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
20 changes: 20 additions & 0 deletions charts/fleet-crd/templates/crds.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,10 @@ spec:
description: DeleteCRDResources deletes CRDs. Warning! this
will also delete all your Custom Resources.
type: boolean
deleteNamespace:
description: DeleteNamespace can be used to delete the deployed
namespace when removing the bundle
type: boolean
diff:
description: Diff can be used to ignore the modified state of
objects which are amended at runtime.
Expand Down Expand Up @@ -538,6 +542,10 @@ spec:
description: DeleteCRDResources deletes CRDs. Warning! this
will also delete all your Custom Resources.
type: boolean
deleteNamespace:
description: DeleteNamespace can be used to delete the deployed
namespace when removing the bundle
type: boolean
diff:
description: Diff can be used to ignore the modified state of
objects which are amended at runtime.
Expand Down Expand Up @@ -1284,6 +1292,10 @@ spec:
description: DeleteCRDResources deletes CRDs. Warning! this will
also delete all your Custom Resources.
type: boolean
deleteNamespace:
description: DeleteNamespace can be used to delete the deployed
namespace when removing the bundle
type: boolean
dependsOn:
description: DependsOn refers to the bundles which must be ready
before this bundle can be deployed.
Expand Down Expand Up @@ -2167,6 +2179,10 @@ spec:
description: DeleteCRDResources deletes CRDs. Warning! this
will also delete all your Custom Resources.
type: boolean
deleteNamespace:
description: DeleteNamespace can be used to delete the deployed
namespace when removing the bundle
type: boolean
diff:
description: Diff can be used to ignore the modified state
of objects which are amended at runtime.
Expand Down Expand Up @@ -5737,6 +5753,10 @@ spec:
in the helm history.
type: boolean
type: object
deleteNamespace:
description: DeleteNamespace specifies if the namespace created
must be deleted after deleting the GitRepo.
type: boolean
disablePolling:
description: Disables git polling. When enabled only webhooks will
be used.
Expand Down
11 changes: 11 additions & 0 deletions e2e/assets/single-cluster/delete-namespace/gitrepo.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
kind: GitRepo
apiVersion: fleet.cattle.io/v1alpha1
metadata:
name: my-gitrepo
spec:
repo: https://github.com/rancher/fleet-test-data
branch: master
paths:
- helm-verify
targetNamespace: {{.TargetNamespace}}
deleteNamespace: {{.DeleteNamespace}}
110 changes: 110 additions & 0 deletions e2e/single-cluster/delete_namespaces_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package singlecluster_test

import (
"errors"
"strings"
"time"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/rancher/fleet/e2e/testenv"
"github.com/rancher/fleet/e2e/testenv/kubectl"
)

var _ = Describe("delete namespaces", func() {
var (
k kubectl.Command
targetNamespace string
deleteNamespace bool
interval = 100 * time.Millisecond
duration = 2 * time.Second
)

type TemplateData struct {
TargetNamespace string
DeleteNamespace bool
}

BeforeEach(func() {
k = env.Kubectl.Namespace(env.Namespace)
deleteNamespace = false

DeferCleanup(func() {
_, _ = k.Delete("ns", "my-custom-namespace", "--wait=false")
})
})

JustBeforeEach(func() {
err := testenv.ApplyTemplate(k, testenv.AssetPath("single-cluster/delete-namespace/gitrepo.yaml"),
TemplateData{targetNamespace, deleteNamespace})

Expect(err).ToNot(HaveOccurred())
Eventually(func() error {
out, err := k.Namespace(targetNamespace).Get("configmaps")
if err != nil {
return err
}

if !strings.Contains(out, "app-config") {
return errors.New("expected configmap is not found")
}

return nil
}).ShouldNot(HaveOccurred())
})

When("delete namespaces is false", func() {
BeforeEach(func() {
targetNamespace = "my-custom-namespace"
})

It("preserves targetNamespace when GitRepo is deleted", func() {
out, err := k.Delete("gitrepo", "my-gitrepo", "-n", "fleet-local")
Expect(err).ToNot(HaveOccurred(), out)

Consistently(func() error {
_, err := k.Get("namespaces", targetNamespace)
return err
}, duration, interval).ShouldNot(HaveOccurred())
})
})

When("delete namespaces is true", func() {
BeforeEach(func() {
deleteNamespace = true
})

It("targetNamespace is deleted after deleting gitRepo", func() {
_, err := k.Get("namespaces", targetNamespace)
Expect(err).To(BeNil())

out, err := k.Delete("gitrepo", "my-gitrepo", "-n", "fleet-local")
Expect(err).ToNot(HaveOccurred(), out)

Eventually(func() error {
_, err = k.Get("namespaces", targetNamespace)
return err
}).ShouldNot(BeNil())
})
})

When("delete namespaces is true but resources are deployed in default namespace", func() {
BeforeEach(func() {
deleteNamespace = true
targetNamespace = "default"
})

It("default namespace exists", func() {
out, err := k.Delete("gitrepo", "my-gitrepo", "-n", "fleet-local")
Expect(err).ToNot(HaveOccurred(), out)

Eventually(func() string {
out, _ = k.Namespace(targetNamespace).Get("configmap", "app-config", "-o", "yaml")
return out
}).Should(ContainSubstring("Error from server (NotFound)"))

_, err = k.Get("namespaces", targetNamespace)
Expect(err).ToNot(HaveOccurred())
})
})
})
5 changes: 5 additions & 0 deletions internal/bundlereader/read.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ type Options struct {
Auth Auth
HelmRepoURLRegex string
KeepResources bool
DeleteNamespace bool
CorrectDrift *fleet.CorrectDrift
}

Expand Down Expand Up @@ -261,6 +262,10 @@ func read(ctx context.Context, name, baseDir string, bundleSpecReader io.Reader,
bundle.Spec.KeepResources = opts.KeepResources
}

if opts.DeleteNamespace {
bundle.Spec.DeleteNamespace = opts.DeleteNamespace
}

if opts.CorrectDrift != nil && opts.CorrectDrift.Enabled {
bundle.Spec.CorrectDrift = opts.CorrectDrift
}
Expand Down
2 changes: 2 additions & 0 deletions internal/cmd/cli/apply.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ type Apply struct {
SSHPrivateKeyFile string `usage:"Path of ssh-private-key for helm repo" name:"ssh-privatekey-file"`
HelmRepoURLRegex string `usage:"Helm credentials will be used if the helm repo matches this regex. Credentials will always be used if this is empty or not provided" name:"helm-repo-url-regex"`
KeepResources bool `usage:"Keep resources created after the GitRepo or Bundle is deleted" name:"keep-resources"`
DeleteNamespace bool `usage:"Delete GitRepo target namespace after the GitRepo or Bundle is deleted" name:"delete-namespace"`
HelmCredentialsByPathFile string `usage:"Path of file containing helm credentials for paths" name:"helm-credentials-by-path-file"`
CorrectDrift bool `usage:"Rollback any change made from outside of Fleet" name:"correct-drift"`
CorrectDriftForce bool `usage:"Use --force when correcting drift. Resources can be deleted and recreated" name:"correct-drift-force"`
Expand Down Expand Up @@ -85,6 +86,7 @@ func (a *Apply) Run(cmd *cobra.Command, args []string) error {
SyncGeneration: int64(a.SyncGeneration),
HelmRepoURLRegex: a.HelmRepoURLRegex,
KeepResources: a.KeepResources,
DeleteNamespace: a.DeleteNamespace,
CorrectDrift: a.CorrectDrift,
CorrectDriftForce: a.CorrectDriftForce,
CorrectDriftKeepFailHistory: a.CorrectDriftKeepFailHistory,
Expand Down
2 changes: 2 additions & 0 deletions internal/cmd/cli/apply/apply.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ type Options struct {
Auth bundlereader.Auth
HelmRepoURLRegex string
KeepResources bool
DeleteNamespace bool
AuthByPath map[string]bundlereader.Auth
CorrectDrift bool
CorrectDriftForce bool
Expand Down Expand Up @@ -181,6 +182,7 @@ func readBundle(ctx context.Context, name, baseDir string, opts *Options) (*flee
Auth: opts.Auth,
HelmRepoURLRegex: opts.HelmRepoURLRegex,
KeepResources: opts.KeepResources,
DeleteNamespace: opts.DeleteNamespace,
CorrectDrift: &fleet.CorrectDrift{
Enabled: opts.CorrectDrift,
Force: opts.CorrectDriftForce,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,10 @@ func argsAndEnvs(gitrepo *v1alpha1.GitRepo, debug bool) ([]string, []corev1.EnvV
args = append(args, "--keep-resources")
}

if gitrepo.Spec.DeleteNamespace {
args = append(args, "--delete-namespace")
}

if gitrepo.Spec.CorrectDrift != nil && gitrepo.Spec.CorrectDrift.Enabled {
args = append(args, "--correct-drift")
if gitrepo.Spec.CorrectDrift.Force {
Expand Down
54 changes: 54 additions & 0 deletions internal/cmd/controller/reconciler/gitrepo_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import (
"context"
"fmt"
"reflect"
"slices"
"strings"

grutil "github.com/rancher/fleet/internal/cmd/controller/gitrepo"
"github.com/rancher/fleet/internal/cmd/controller/imagescan"
Expand All @@ -20,6 +22,7 @@ import (

corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
errutil "k8s.io/apimachinery/pkg/util/errors"
Expand Down Expand Up @@ -285,6 +288,25 @@ func purgeBundles(ctx context.Context, c client.Client, gitrepo types.Namespaced
return err
}

// At this point, access to the GitRepo is unavailable as it has been deleted and cannot be found within the cluster.
// Nevertheless, `deleteNamespace` can be found within all bundles generated from that GitRepo. Checking any bundle to get this value would be enough.
namespace := ""
deleteNamespace := false
sampleBundle := fleet.Bundle{}
if len(bundles.Items) > 0 {
sampleBundle = bundles.Items[0]
deleteNamespace = sampleBundle.Spec.DeleteNamespace
namespace = sampleBundle.Spec.TargetNamespace

if sampleBundle.Spec.KeepResources {
deleteNamespace = false
}
}

if err = purgeNamespace(ctx, c, deleteNamespace, namespace); err != nil {
return err
}

for _, bundle := range bundles.Items {
err := c.Delete(ctx, &bundle) // nolint:gosec // does not store pointer
if err != nil {
Expand Down Expand Up @@ -335,6 +357,38 @@ func purgeImageScans(ctx context.Context, c client.Client, gitrepo types.Namespa
return nil
}

func purgeNamespace(ctx context.Context, c client.Client, deleteNamespace bool, ns string) error {
if !deleteNamespace {
return nil
}

if ns == "" {
return nil
}

// Ignore default namespaces
defaultNamespaces := []string{"fleet-local", "cattle-fleet-system", "fleet-default", "cattle-fleet-clusters-system", "default"}
if slices.Contains(defaultNamespaces, ns) {
return nil
}

// Ignore system namespaces
if _, isKubeNamespace := strings.CutPrefix(ns, "kube-"); isKubeNamespace {
return nil
}

namespace := &corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: ns,
},
}
if err := c.Delete(ctx, namespace); err != nil {
return err
}

return nil
}

func acceptedLastUpdate(conds []genericcondition.GenericCondition) string {
for _, cond := range conds {
if cond.Type == "Accepted" {
Expand Down
3 changes: 3 additions & 0 deletions pkg/apis/fleet.cattle.io/v1alpha1/bundledeployment_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@ type BundleDeploymentOptions struct {
// KeepResources can be used to keep the deployed resources when removing the bundle
KeepResources bool `json:"keepResources,omitempty"`

// DeleteNamespace can be used to delete the deployed namespace when removing the bundle
DeleteNamespace bool `json:"deleteNamespace,omitempty"`

//IgnoreOptions can be used to ignore fields when monitoring the bundle.
IgnoreOptions `json:"ignore,omitempty"`

Expand Down
3 changes: 3 additions & 0 deletions pkg/apis/fleet.cattle.io/v1alpha1/gitrepo_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,9 @@ type GitRepoSpec struct {
// KeepResources specifies if the resources created must be kept after deleting the GitRepo.
KeepResources bool `json:"keepResources,omitempty"`

// DeleteNamespace specifies if the namespace created must be deleted after deleting the GitRepo.
DeleteNamespace bool `json:"deleteNamespace,omitempty"`

// CorrectDrift specifies how drift correction should work.
CorrectDrift *CorrectDrift `json:"correctDrift,omitempty"`

Expand Down
Loading