diff --git a/go.mod b/go.mod index 983ecd49..e10c48a8 100644 --- a/go.mod +++ b/go.mod @@ -22,7 +22,7 @@ require ( github.com/open-policy-agent/gatekeeper/v3 v3.15.1 github.com/orcaman/concurrent-map/v2 v2.0.1 github.com/pkg/errors v0.9.1 - github.com/pluralsh/console-client-go v0.11.2 + github.com/pluralsh/console-client-go v0.11.8 github.com/pluralsh/controller-reconcile-helper v0.0.4 github.com/pluralsh/gophoenix v0.1.3-0.20231201014135-dff1b4309e34 github.com/pluralsh/polly v0.1.10 diff --git a/go.sum b/go.sum index f584b369..d95db83a 100644 --- a/go.sum +++ b/go.sum @@ -532,8 +532,8 @@ github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= -github.com/pluralsh/console-client-go v0.11.2 h1:mxWaLRKlYr3MsVA4ViYxj/FV/5JjCE1NvBjBlDvAbj8= -github.com/pluralsh/console-client-go v0.11.2/go.mod h1:eyCiLA44YbXiYyJh8303jk5JdPkt9McgCo5kBjk4lKo= +github.com/pluralsh/console-client-go v0.11.8 h1:QRr9/IEEEHUOkBLZefRsjcZ598JnfGAkmx9ZoIBSmb0= +github.com/pluralsh/console-client-go v0.11.8/go.mod h1:eyCiLA44YbXiYyJh8303jk5JdPkt9McgCo5kBjk4lKo= github.com/pluralsh/controller-reconcile-helper v0.0.4 h1:1o+7qYSyoeqKFjx+WgQTxDz4Q2VMpzprJIIKShxqG0E= github.com/pluralsh/controller-reconcile-helper v0.0.4/go.mod h1:AfY0gtteD6veBjmB6jiRx/aR4yevEf6K0M13/pGan/s= github.com/pluralsh/gophoenix v0.1.3-0.20231201014135-dff1b4309e34 h1:ab2PN+6if/Aq3/sJM0AVdy1SYuMAnq4g20VaKhTm/Bw= diff --git a/pkg/controller/service/reconciler.go b/pkg/controller/service/reconciler.go index 7e245807..d301c224 100644 --- a/pkg/controller/service/reconciler.go +++ b/pkg/controller/service/reconciler.go @@ -9,6 +9,7 @@ import ( console "github.com/pluralsh/console-client-go" "github.com/pluralsh/polly/algorithms" "github.com/samber/lo" + "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime/schema" @@ -20,6 +21,7 @@ import ( "sigs.k8s.io/cli-utils/pkg/apply" "sigs.k8s.io/cli-utils/pkg/common" "sigs.k8s.io/cli-utils/pkg/inventory" + "sigs.k8s.io/cli-utils/pkg/object" "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/reconcile" @@ -61,6 +63,7 @@ type ServiceReconciler struct { UtilFactory util.Factory RestoreNamespace string + mapper meta.RESTMapper discoveryClient *discovery.DiscoveryClient pinger *ping.Pinger ctx context.Context @@ -86,7 +89,10 @@ func NewServiceReconciler(ctx context.Context, consoleClient client.Client, conf manifestCache := manifests.NewCache(manifestTTL, deployToken, consoleURL) f := utils.NewFactory(config) - + mapper, err := f.ToRESTMapper() + if err != nil { + return nil, err + } cs, err := f.KubernetesClientSet() if err != nil { return nil, err @@ -127,6 +133,7 @@ func NewServiceReconciler(ctx context.Context, consoleClient client.Client, conf pinger: ping.New(consoleClient, discoveryClient, f), RestoreNamespace: restoreNamespace, ctx: ctx, + mapper: mapper, }, nil } @@ -188,6 +195,49 @@ func newDestroyer(invFactory inventory.ClientFactory, f util.Factory) (*apply.De Build() } +func (s *ServiceReconciler) enforceNamespace(objs []*unstructured.Unstructured, svc *console.GetServiceDeploymentForAgent_ServiceDeployment) error { + if svc == nil { + return nil + } + if svc.SyncConfig == nil { + return nil + } + if svc.SyncConfig.EnforceNamespace == nil { + return nil + } + if !*svc.SyncConfig.EnforceNamespace { + return nil + } + + var crdObjs []*unstructured.Unstructured + // find any crds in the set of resources. + for _, obj := range objs { + if object.IsCRD(obj) { + crdObjs = append(crdObjs, obj) + } + } + for _, obj := range objs { + + // Look up the scope of the resource so we know if the resource + // should have a namespace set or not. + scope, err := object.LookupResourceScope(obj, crdObjs, s.mapper) + if err != nil { + return err + } + + switch scope { + case meta.RESTScopeNamespace: + obj.SetNamespace(svc.Namespace) + case meta.RESTScopeRoot: + return fmt.Errorf("the service %s with 'enforceNamespace' flag has cluster-scoped resources", svc.ID) + default: + return fmt.Errorf("unknown RESTScope %q", scope.Name()) + } + } + + return nil +} + func postProcess(mans []*unstructured.Unstructured) []*unstructured.Unstructured { return lo.Map(mans, func(man *unstructured.Unstructured, ind int) *unstructured.Unstructured { labels := man.GetLabels() @@ -372,6 +422,11 @@ func (s *ServiceReconciler) Reconcile(ctx context.Context, id string) (result re return } + err = s.enforceNamespace(manifests, svc) + if err != nil { + return + } + options := apply.ApplierOptions{ ServerSideOptions: common.ServerSideOptions{ ServerSideApply: true,