Skip to content

Commit

Permalink
Set disable to true if one of ExclusionGroup feature is enabled (#344)
Browse files Browse the repository at this point in the history
Signed-off-by: Rokibul Hasan <[email protected]>
Signed-off-by: Tamal Saha <[email protected]>
Co-authored-by: Tamal Saha <[email protected]>
  • Loading branch information
RokibulHasan7 and tamalsaha authored Nov 12, 2024
1 parent 35bddad commit 6f5de65
Show file tree
Hide file tree
Showing 20 changed files with 1,477 additions and 236 deletions.
5 changes: 3 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,10 @@ require (
k8s.io/klog/v2 v2.130.1
k8s.io/kube-openapi v0.0.0-20240709000822-3c01b740850f
k8s.io/kube-state-metrics/v2 v2.12.0
k8s.io/utils v0.0.0-20240502163921-fe8a2dddb1d0
kmodules.xyz/apiversion v0.2.0
kmodules.xyz/authorizer v0.29.1
kmodules.xyz/client-go v0.30.34
kmodules.xyz/client-go v0.30.37
kmodules.xyz/custom-resources v0.30.0
kmodules.xyz/go-containerregistry v0.0.12
kmodules.xyz/monitoring-agent-api v0.30.2
Expand All @@ -57,6 +58,7 @@ require (
kubeops.dev/falco-ui-server v0.0.4
kubeops.dev/scanner v0.0.18
kubepack.dev/lib-helm v0.29.13
open-cluster-management.io/api v0.15.0
sigs.k8s.io/cli-utils v0.37.2
sigs.k8s.io/controller-runtime v0.18.4
sigs.k8s.io/yaml v1.4.0
Expand Down Expand Up @@ -240,7 +242,6 @@ require (
k8s.io/cli-runtime v0.30.1 // indirect
k8s.io/component-helpers v0.29.0 // indirect
k8s.io/kms v0.30.3 // indirect
k8s.io/utils v0.0.0-20240502163921-fe8a2dddb1d0 // indirect
kubevault.dev/apimachinery v0.18.3 // indirect
moul.io/http2curl/v2 v2.3.1-0.20221024080105-10c404f653f7 // indirect
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.29.0 // indirect
Expand Down
6 changes: 4 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -922,8 +922,8 @@ kmodules.xyz/apiversion v0.2.0 h1:vAQYqZFm4xu4pbB1cAdHbFEPES6EQkcR4wc06xdTOWk=
kmodules.xyz/apiversion v0.2.0/go.mod h1:oPX8g8LvlPdPX3Yc5YvCzJHQnw3YF/X4/jdW0b1am80=
kmodules.xyz/authorizer v0.29.1 h1:uByGGoryKbZcfiEAhjcK/Y345I9mygNQP7DVpkMbNQQ=
kmodules.xyz/authorizer v0.29.1/go.mod h1:kZRhclL8twzyt2bQuJQJbpYww2sc+qFr8I5PPoq/sWY=
kmodules.xyz/client-go v0.30.34 h1:AsmdB6/6jK1MxD+4VgibHA1vTbW1U56I+lPAhO2xf+0=
kmodules.xyz/client-go v0.30.34/go.mod h1:CAu+JlA8RVGtj6LQHu0Q1w2mnFUajuti49c7T1AvGdM=
kmodules.xyz/client-go v0.30.37 h1:hj4BMsNDgRVc2aDPB6Y3x5iCylXTZDZeQPJp/oA6lxs=
kmodules.xyz/client-go v0.30.37/go.mod h1:CAu+JlA8RVGtj6LQHu0Q1w2mnFUajuti49c7T1AvGdM=
kmodules.xyz/crd-schema-fuzz v0.29.1 h1:zJTlWYOrT5dsVVHW8HGcnR/vaWfxQfNh11QwTtkYpcs=
kmodules.xyz/crd-schema-fuzz v0.29.1/go.mod h1:n708z9YQqLMP2KNLQVgBcRJw1QpSWLvpNCEi+KJDOYE=
kmodules.xyz/custom-resources v0.30.0 h1:vR3CbseHMLwR4GvtcJJuRuwIV8voKqFqNii27rMcm1o=
Expand Down Expand Up @@ -952,6 +952,8 @@ kubevault.dev/apimachinery v0.18.3 h1:Bq180AGBYnRXXNWbJ6Zg82+8/3M1Y8WYPez32uTry8
kubevault.dev/apimachinery v0.18.3/go.mod h1:b9uUVFx3a3ThDziL2J2O4xQL+muY1/pGavAhDdJC99E=
moul.io/http2curl/v2 v2.3.1-0.20221024080105-10c404f653f7 h1:NykkTlRB+X40z86cLHdEmuoTxhNKhQebLT379b1EumA=
moul.io/http2curl/v2 v2.3.1-0.20221024080105-10c404f653f7/go.mod h1:RW4hyBjTWSYDOxapodpNEtX0g5Eb16sxklBqmd2RHcE=
open-cluster-management.io/api v0.15.0 h1:lRee1KOlGHZb2scTA7ff9E9Fxt2hJc7jpkHnaCbvkOU=
open-cluster-management.io/api v0.15.0/go.mod h1:9erZEWEn4bEqh0nIX2wA7f/s3KCuFycQdBrPrRzi0QM=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.29.0 h1:/U5vjBbQn3RChhv7P11uhYvCSm5G2GaIi5AIGBS6r4c=
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.29.0/go.mod h1:z7+wmGM2dfIiLRfrC6jb5kV2Mq/sK1ZP303cxzkV5Y4=
Expand Down
15 changes: 12 additions & 3 deletions pkg/apiserver/apiserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import (
policyinstall "kubeops.dev/ui-server/apis/policy/install"
policyapi "kubeops.dev/ui-server/apis/policy/v1alpha1"
clustermetacontroller "kubeops.dev/ui-server/pkg/controllers/clustermetadata"
clusterclaimcontroller "kubeops.dev/ui-server/pkg/controllers/feature"
projectquotacontroller "kubeops.dev/ui-server/pkg/controllers/projectquota"
"kubeops.dev/ui-server/pkg/graph"
"kubeops.dev/ui-server/pkg/metricshandler"
Expand Down Expand Up @@ -89,7 +90,6 @@ import (
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
restclient "k8s.io/client-go/rest"
"k8s.io/klog/v2"
"k8s.io/klog/v2/klogr"
"kmodules.xyz/authorizer"
kmapi "kmodules.xyz/client-go/api/v1"
cu "kmodules.xyz/client-go/client"
Expand All @@ -107,6 +107,7 @@ import (
uiinstall "kmodules.xyz/resource-metadata/apis/ui/install"
uiapi "kmodules.xyz/resource-metadata/apis/ui/v1alpha1"
identitylib "kmodules.xyz/resource-metadata/pkg/identity"
clusterv1alpha1 "open-cluster-management.io/api/cluster/v1alpha1"
"sigs.k8s.io/controller-runtime/pkg/cache"
"sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/manager"
Expand Down Expand Up @@ -140,6 +141,7 @@ func init() {
utilruntime.Must(fluxsrc.AddToScheme(Scheme))
utilruntime.Must(monitoringv1.AddToScheme(Scheme))
utilruntime.Must(falco.AddToScheme(Scheme))
utilruntime.Must(clusterv1alpha1.Install(Scheme))

// we need to add the options to empty v1
// TODO fix the server code to avoid this
Expand Down Expand Up @@ -210,8 +212,7 @@ func (c completedConfig) New(ctx context.Context) (*UIServer, error) {
return nil, err
}

// ctrl.SetLogger(...)
log.SetLogger(klogr.New()) // nolint:staticcheck
log.SetLogger(klog.NewKlogr())
setupLog := log.Log.WithName("setup")

cfg := c.ExtraConfig.ClientConfig
Expand Down Expand Up @@ -298,6 +299,14 @@ func (c completedConfig) New(ctx context.Context) (*UIServer, error) {
}
}

if clustermeta.DetectClusterManager(mgr.GetClient()).ManagedByOCMSpoke() {
err = clusterclaimcontroller.NewClusterClaimReconciler(mgr.GetClient()).SetupWithManager(mgr)
if err != nil {
klog.Error(err, "unable to create controller", "controller", "ClusterClaim")
os.Exit(1)
}
}

s := &UIServer{
GenericAPIServer: genericServer,
Manager: mgr,
Expand Down
107 changes: 107 additions & 0 deletions pkg/controllers/feature/clusterclaim_reconciler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/*
Copyright AppsCode Inc. and Contributors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package feature

import (
"context"
"fmt"
"sort"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/utils/ptr"
kmapi "kmodules.xyz/client-go/api/v1"
cu "kmodules.xyz/client-go/client"
uiapi "kmodules.xyz/resource-metadata/apis/ui/v1alpha1"
clusterv1alpha1 "open-cluster-management.io/api/cluster/v1alpha1"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
"sigs.k8s.io/yaml"
)

type ClusterClaimReconciler struct {
kc client.Client
}

var _ reconcile.Reconciler = &ClusterClaimReconciler{}

func NewClusterClaimReconciler(kc client.Client) *ClusterClaimReconciler {
return &ClusterClaimReconciler{
kc: kc,
}
}

func (r *ClusterClaimReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
var err error
var featureList uiapi.FeatureList
if err = r.kc.List(ctx, &featureList); err != nil {
return ctrl.Result{}, err
}

var enabledFeatures, extFeatures, disabledFeatures []string
for _, feature := range featureList.Items {
if feature.Status.Enabled == nil {
return ctrl.Result{}, fmt.Errorf("feature %s is not reconciled yet", feature.Name)
}
if ptr.Deref(feature.Status.Enabled, false) {
enabledFeatures = append(enabledFeatures, feature.Name)
if !ptr.Deref(feature.Status.Managed, false) {
extFeatures = append(extFeatures, feature.Name)
}
}

if feature.Spec.Disabled {
disabledFeatures = append(disabledFeatures, feature.Name)
}
}

sort.Strings(enabledFeatures)
sort.Strings(extFeatures)
sort.Strings(disabledFeatures)

data, err := yaml.Marshal(kmapi.ClusterClaimFeatures{
EnabledFeatures: enabledFeatures,
ExternallyManagedFeatures: extFeatures,
DisabledFeatures: disabledFeatures,
})
if err != nil {
return ctrl.Result{}, err
}

obj := &clusterv1alpha1.ClusterClaim{
TypeMeta: metav1.TypeMeta{},
ObjectMeta: metav1.ObjectMeta{
Name: kmapi.ClusterClaimKeyFeatures,
},
}
_, err = cu.CreateOrPatch(context.TODO(), r.kc, obj, func(o client.Object, createOp bool) client.Object {
in := o.(*clusterv1alpha1.ClusterClaim)
in.Spec.Value = string(data)
return in
})
if err != nil {
return ctrl.Result{}, err
}
return ctrl.Result{}, nil
}

// SetupWithManager sets up the controller with the Manager.
func (r *ClusterClaimReconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
For(&uiapi.Feature{}).
Complete(r)
}
49 changes: 49 additions & 0 deletions pkg/controllers/feature/feature_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import (
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
"k8s.io/utils/ptr"
cu "kmodules.xyz/client-go/client"
meta_util "kmodules.xyz/client-go/meta"
uiapi "kmodules.xyz/resource-metadata/apis/ui/v1alpha1"
Expand Down Expand Up @@ -102,6 +103,12 @@ func (r *FeatureReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct
return ctrl.Result{}, err
}

if fr.feature.Spec.FeatureExclusionGroup != "" {
if err = fr.handleFeatureExclusionGroups(); err != nil {
return ctrl.Result{}, err
}
}

err = fr.updateFeatureSetEntry(ctx)
if err != nil && !apierrors.IsNotFound(err) {
return ctrl.Result{}, err
Expand Down Expand Up @@ -553,3 +560,45 @@ func (r *FeatureReconciler) findFeatureForHelmRelease(ctx context.Context, relea
},
}
}

func (r *frReconciler) handleFeatureExclusionGroups() error {
var err error
exclusionGroupName := r.feature.Spec.FeatureExclusionGroup

var fs uiapi.FeatureSet
err = r.client.Get(context.Background(), types.NamespacedName{Name: r.feature.Spec.FeatureSet}, &fs)
if err != nil {
return err
}

var exclusionGrp bool
for _, f := range fs.Status.Features {
var otherFeature uiapi.Feature
err = r.client.Get(context.Background(), types.NamespacedName{Name: f.Name}, &otherFeature)
if err != nil {
return err
}

if otherFeature.Spec.FeatureExclusionGroup != exclusionGroupName || otherFeature.Name == r.feature.Name {
continue
}

// Mark the exclusion group as active if this feature is enabled
if ptr.Deref(otherFeature.Status.Enabled, false) {
exclusionGrp = true
}
}

// If feature is in an exclusion group and another feature in that group is enabled,
// disable this feature if it’s not already enabled
if exclusionGrp {
r.feature.Spec.Disabled = !ptr.Deref(r.feature.Status.Enabled, false)
} else {
r.feature.Spec.Disabled = false
}

if err := r.client.Update(context.Background(), r.feature); err != nil {
return err
}
return nil
}
19 changes: 0 additions & 19 deletions vendor/k8s.io/klog/v2/klogr/README.md

This file was deleted.

Loading

0 comments on commit 6f5de65

Please sign in to comment.