diff --git a/go.mod b/go.mod index ddce4a5..e92f1c2 100644 --- a/go.mod +++ b/go.mod @@ -1,10 +1,14 @@ module github.com/sap/dns-masquerading-operator-cop -go 1.23.5 +go 1.24.0 + +replace github.com/sap/component-operator-runtime => /Users/D052597/dev/github.com/sap/component-operator-runtime require ( github.com/pkg/errors v0.9.1 github.com/sap/component-operator-runtime v0.3.67 + istio.io/client-go v1.24.3 + k8s.io/api v0.32.1 k8s.io/apiextensions-apiserver v0.32.1 k8s.io/apimachinery v0.32.1 k8s.io/client-go v0.32.1 @@ -61,12 +65,12 @@ require ( github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/common v0.55.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect - github.com/sap/go-generics v0.2.25 // indirect + github.com/sap/go-generics v0.2.27 // indirect github.com/shopspring/decimal v1.4.0 // indirect github.com/spf13/afero v1.6.0 // indirect github.com/spf13/cast v1.7.1 // indirect github.com/spf13/cobra v1.8.1 // indirect - github.com/spf13/pflag v1.0.5 // indirect + github.com/spf13/pflag v1.0.6 // indirect github.com/x448/float16 v0.8.4 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect @@ -78,15 +82,16 @@ require ( golang.org/x/sys v0.28.0 // indirect golang.org/x/term v0.27.0 // indirect golang.org/x/text v0.21.0 // indirect - golang.org/x/time v0.9.0 // indirect + golang.org/x/time v0.10.0 // indirect golang.org/x/tools v0.28.0 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240826202546-f6391c0de4c7 // indirect google.golang.org/protobuf v1.36.1 // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/api v0.32.1 // indirect + istio.io/api v1.24.3-0.20250110021705-fef7700e8ddf // indirect k8s.io/gengo/v2 v2.0.0-20240911193312-2b36238f13e9 // indirect k8s.io/klog/v2 v2.130.1 // indirect k8s.io/kube-openapi v0.0.0-20241212222426-2c72e554b1e7 // indirect diff --git a/go.sum b/go.sum index 1a5209f..17040cb 100644 --- a/go.sum +++ b/go.sum @@ -131,10 +131,8 @@ github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoG github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/sap/component-operator-runtime v0.3.67 h1:7A9bEikT5d8eDYKs7YrCpRFElHPiBjYeNAWeQDjminU= -github.com/sap/component-operator-runtime v0.3.67/go.mod h1:7f7v3XXG7hSLjmLe1qgauBFvEYmyWtWi9AK72RwzNtI= -github.com/sap/go-generics v0.2.25 h1:E4POOgwyOGSKNff4cdWTk/6hziQn4gR4dTCB9JdrKhs= -github.com/sap/go-generics v0.2.25/go.mod h1:aL5vyHr72/qEzbUOgewA/srS5Gf5nbxEYVoawQRG72s= +github.com/sap/go-generics v0.2.27 h1:NqqAaJj6Nj3ZDhoFcVJyMT/5D9YtBwO1pCewW0cFotQ= +github.com/sap/go-generics v0.2.27/go.mod h1:YyEx00Jl5fIZx7jy6ss2m87UUzTQfVysPHUUOKnRj6Q= github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY= @@ -143,8 +141,9 @@ github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y= github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= -github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= +github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= @@ -201,8 +200,8 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= -golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY= -golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/time v0.10.0 h1:3usCWA8tQn0L8+hFJQNgzpWbd89begxN66o1Ojdn5L4= +golang.org/x/time v0.10.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= @@ -215,6 +214,8 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= +google.golang.org/genproto/googleapis/api v0.0.0-20240826202546-f6391c0de4c7 h1:YcyjlL1PRr2Q17/I0dPk2JmYS5CDXfcdb2Z3YRioEbw= +google.golang.org/genproto/googleapis/api v0.0.0-20240826202546-f6391c0de4c7/go.mod h1:OCdP9MfskevB/rbYvHTsXTtKC+3bHWajPdoKgjcYkfo= google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk= google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -232,6 +233,10 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +istio.io/api v1.24.3-0.20250110021705-fef7700e8ddf h1:T/0/73F7PxdDo4JaX6b7jfxn2/1LCQ5TKWc1tJBEQkQ= +istio.io/api v1.24.3-0.20250110021705-fef7700e8ddf/go.mod h1:MQnRok7RZ20/PE56v0LxmoWH0xVxnCQPNuf9O7PAN1I= +istio.io/client-go v1.24.3 h1:TB8IcM3yyMCDzKRJo0YfFOUGNQmkhwH/JE/Yr3lzVAk= +istio.io/client-go v1.24.3/go.mod h1:zSyw/c4luKQKosFIHQaWAQOA0c3bODu4SahQCAMlKA4= k8s.io/api v0.32.1 h1:f562zw9cy+GvXzXf0CKlVQ7yHJVYzLfL6JAS4kOAaOc= k8s.io/api v0.32.1/go.mod h1:/Yi/BqkuueW1BgpoePYBRdDYfjPF5sgTr5+YqDZra5k= k8s.io/apiextensions-apiserver v0.32.1 h1:hjkALhRUeCariC8DiVmb5jj0VjIc1N0DREP32+6UXZw= @@ -256,8 +261,7 @@ sigs.k8s.io/cli-utils v0.37.2 h1:GOfKw5RV2HDQZDJlru5KkfLO1tbxqMoyn1IYUxqBpNg= sigs.k8s.io/cli-utils v0.37.2/go.mod h1:V+IZZr4UoGj7gMJXklWBg6t5xbdThFBcpj4MrZuCYco= sigs.k8s.io/controller-runtime v0.20.1 h1:JbGMAG/X94NeM3xvjenVUaBjy6Ui4Ogd/J5ZtjZnHaE= sigs.k8s.io/controller-runtime v0.20.1/go.mod h1:BrP3w158MwvB3ZbNpaAcIKkHQ7YGpYnzpoSTZ8E14WU= -sigs.k8s.io/controller-runtime/tools/setup-envtest v0.0.0-20250129234522-e93668e17ac1 h1:StK7h3z5prvRsRuCt485ffD3zfrKNRjtKnVRlJiMc3s= -sigs.k8s.io/controller-runtime/tools/setup-envtest v0.0.0-20250129234522-e93668e17ac1/go.mod h1:Is2SwCWbWAoyGVoVBA627n1SWhWaEwUhaIYSEbtzHT4= +sigs.k8s.io/controller-runtime/tools/setup-envtest v0.0.0-20250130183723-1a91ccca639b h1:WrrMeolPju7bfK9/SBJg+nOTxR2rPobpPwB94V2xT0U= sigs.k8s.io/controller-runtime/tools/setup-envtest v0.0.0-20250130183723-1a91ccca639b/go.mod h1:Is2SwCWbWAoyGVoVBA627n1SWhWaEwUhaIYSEbtzHT4= sigs.k8s.io/controller-tools v0.16.5 h1:5k9FNRqziBPwqr17AMEPPV/En39ZBplLAdOwwQHruP4= sigs.k8s.io/controller-tools v0.16.5/go.mod h1:8vztuRVzs8IuuJqKqbXCSlXcw+lkAv/M2sTpg55qjMY= diff --git a/pkg/operator/operator.go b/pkg/operator/operator.go index c19f93f..ae18b71 100644 --- a/pkg/operator/operator.go +++ b/pkg/operator/operator.go @@ -6,18 +6,28 @@ SPDX-License-Identifier: Apache-2.0 package operator import ( + "context" "embed" "flag" + "fmt" + "time" "github.com/pkg/errors" + + corev1 "k8s.io/api/core/v1" + networkingv1 "k8s.io/api/networking/v1" "k8s.io/apimachinery/pkg/runtime" utilruntime "k8s.io/apimachinery/pkg/util/runtime" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + + istionetworkingv1 "istio.io/client-go/pkg/apis/networking/v1" "github.com/sap/component-operator-runtime/pkg/component" helmgenerator "github.com/sap/component-operator-runtime/pkg/manifests/helm" "github.com/sap/component-operator-runtime/pkg/operator" + componentoperatorruntimetypes "github.com/sap/component-operator-runtime/pkg/types" operatorv1alpha1 "github.com/sap/dns-masquerading-operator-cop/api/v1alpha1" "github.com/sap/dns-masquerading-operator-cop/internal/transformer" @@ -25,6 +35,11 @@ import ( const Name = "dns-masquerading-operator-cop.cs.sap.com" +const ( + managedIndexKey = ".metadata.managed" + finalizer = "dns.cs.sap.com/masquerading-operator" +) + //go:embed all:data var data embed.FS @@ -81,6 +96,7 @@ func (o *Operator) GetName() string { } func (o *Operator) InitScheme(scheme *runtime.Scheme) { + utilruntime.Must(istionetworkingv1.AddToScheme(scheme)) utilruntime.Must(operatorv1alpha1.AddToScheme(scheme)) } @@ -97,6 +113,18 @@ func (o *Operator) GetUncacheableTypes() []client.Object { } func (o *Operator) Setup(mgr ctrl.Manager) error { + if err := mgr.GetCache().IndexField(context.TODO(), &corev1.Service{}, managedIndexKey, indexByManaged); err != nil { + return errors.Wrapf(err, "failed setting index field %s", managedIndexKey) + } + if err := mgr.GetCache().IndexField(context.TODO(), &networkingv1.Ingress{}, managedIndexKey, indexByManaged); err != nil { + return errors.Wrapf(err, "failed setting index field %s", managedIndexKey) + } + /* + if err := mgr.GetCache().IndexField(context.TODO(), &istionetworkingv1.Gateway{}, managedIndexKey, indexByManaged); err != nil { + return errors.Wrapf(err, "failed setting index field %s", managedIndexKey) + } + */ + resourceGenerator, err := helmgenerator.NewHelmGeneratorWithParameterTransformer( data, "data/charts/dns-masquerading-operator", @@ -113,9 +141,56 @@ func (o *Operator) Setup(mgr ctrl.Manager) error { component.ReconcilerOptions{ DefaultServiceAccount: &o.options.DefaultServiceAccount, }, - ).SetupWithManager(mgr); err != nil { + ).WithPreDeleteHook(preDeleteHook).SetupWithManager(mgr); err != nil { return errors.Wrapf(err, "unable to create controller") } return nil } + +func indexByManaged(object client.Object) []string { + if controllerutil.ContainsFinalizer(object, finalizer) { + return []string{"true"} + } + return nil +} + +func preDeleteHook(ctx context.Context, clnt client.Client, c *operatorv1alpha1.DNSMasqueradingOperator) error { + // TODO: it would be more elegant to maintain a custom cache index and use MatchingFields in the List() call ... + // TODO: limit results to 1 + + if c.Spec.EnableServiceController { + serviceList := &corev1.ServiceList{} + if err := clnt.List(ctx, serviceList, client.MatchingFields{managedIndexKey: "true"}); err != nil { + return err + } + if len(serviceList.Items) > 0 { + service := serviceList.Items[0] + return componentoperatorruntimetypes.NewRetriableError(fmt.Errorf("deletion blocked by service %s/%s", service.Namespace, service.Name), &[]time.Duration{10 * time.Second}[0]) + } + } + + if c.Spec.EnableIngressController { + ingressList := &networkingv1.IngressList{} + if err := clnt.List(ctx, ingressList, client.MatchingFields{managedIndexKey: "true"}); err != nil { + return err + } + if len(ingressList.Items) > 0 { + ingress := ingressList.Items[0] + return componentoperatorruntimetypes.NewRetriableError(fmt.Errorf("deletion blocked by ingress %s/%s", ingress.Namespace, ingress.Name), &[]time.Duration{10 * time.Second}[0]) + } + } + + if c.Spec.EnableIstioGatewayController { + gatewayList := &istionetworkingv1.GatewayList{} + if err := clnt.List(ctx, gatewayList, client.MatchingFields{managedIndexKey: "true"}); err != nil { + return err + } + if len(gatewayList.Items) > 0 { + gateway := gatewayList.Items[0] + return componentoperatorruntimetypes.NewRetriableError(fmt.Errorf("deletion blocked by gateway %s/%s", gateway.Namespace, gateway.Name), &[]time.Duration{10 * time.Second}[0]) + } + } + + return nil +}