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

Add featuregate package and use it in controllers #673

Merged
merged 2 commits into from
Apr 4, 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
4 changes: 3 additions & 1 deletion controllers/sriovnetworknodepolicy_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ import (

sriovnetworkv1 "github.com/k8snetworkplumbingwg/sriov-network-operator/api/v1"
constants "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/consts"
"github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/featuregate"
"github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/render"
"github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/utils"
"github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/vars"
Expand All @@ -58,7 +59,8 @@ const nodePolicySyncEventName = "node-policy-sync-event"
// SriovNetworkNodePolicyReconciler reconciles a SriovNetworkNodePolicy object
type SriovNetworkNodePolicyReconciler struct {
client.Client
Scheme *runtime.Scheme
Scheme *runtime.Scheme
FeatureGate featuregate.FeatureGate
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This field is not used. I guess it will be used in some future PR, right?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this is preparation for the next PR.

}

//+kubebuilder:rbac:groups=sriovnetwork.openshift.io,resources=sriovnetworknodepolicies,verbs=get;list;watch;create;update;patch;delete
Expand Down
5 changes: 4 additions & 1 deletion controllers/sriovnetworknodepolicy_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
sriovnetworkv1 "github.com/k8snetworkplumbingwg/sriov-network-operator/api/v1"
v1 "github.com/k8snetworkplumbingwg/sriov-network-operator/api/v1"
"github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/consts"
"github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/featuregate"
"github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/vars"
)

Expand Down Expand Up @@ -211,7 +212,9 @@ func TestRenderDevicePluginConfigData(t *testing.T) {
},
}

reconciler := SriovNetworkNodePolicyReconciler{}
reconciler := SriovNetworkNodePolicyReconciler{
FeatureGate: featuregate.New(),
}

node := corev1.Node{ObjectMeta: metav1.ObjectMeta{Name: "node1"}}
nodeState := sriovnetworkv1.SriovNetworkNodeState{ObjectMeta: metav1.ObjectMeta{Name: node.Name, Namespace: vars.Namespace}}
Expand Down
15 changes: 7 additions & 8 deletions controllers/sriovoperatorconfig_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import (
sriovnetworkv1 "github.com/k8snetworkplumbingwg/sriov-network-operator/api/v1"
apply "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/apply"
consts "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/consts"
"github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/featuregate"
snolog "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/log"
"github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/platforms"
render "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/render"
Expand All @@ -53,6 +54,7 @@ type SriovOperatorConfigReconciler struct {
client.Client
Scheme *runtime.Scheme
PlatformHelper platforms.Interface
FeatureGate featuregate.FeatureGate
}

//+kubebuilder:rbac:groups=sriovnetwork.openshift.io,resources=sriovoperatorconfigs,verbs=get;list;watch;create;update;patch;delete
Expand Down Expand Up @@ -87,6 +89,9 @@ func (r *SriovOperatorConfigReconciler) Reconcile(ctx context.Context, req ctrl.

snolog.SetLogLevel(defaultConfig.Spec.LogLevel)

r.FeatureGate.Init(defaultConfig.Spec.FeatureGates)
logger.Info("enabled featureGates", "featureGates", r.FeatureGate.String())

if !defaultConfig.Spec.EnableInjector {
logger.Info("SR-IOV Network Resource Injector is disabled.")
}
Expand Down Expand Up @@ -171,10 +176,7 @@ func (r *SriovOperatorConfigReconciler) syncConfigDaemonSet(ctx context.Context,
} else {
data.Data["UsedSystemdMode"] = false
}
data.Data["ParallelNicConfig"] = false
if parallelConfig, ok := dc.Spec.FeatureGates[consts.ParallelNicConfigFeatureGate]; ok {
data.Data["ParallelNicConfig"] = parallelConfig
}
data.Data["ParallelNicConfig"] = r.FeatureGate.IsEnabled(consts.ParallelNicConfigFeatureGate)

envCniBinPath := os.Getenv("SRIOV_CNI_BIN_PATH")
if envCniBinPath == "" {
Expand Down Expand Up @@ -248,10 +250,7 @@ func (r *SriovOperatorConfigReconciler) syncWebhookObjs(ctx context.Context, dc
}

// check for ResourceInjectorMatchConditionFeatureGate feature gate
data.Data[consts.ResourceInjectorMatchConditionFeatureGate] = false
if resourceInjector, ok := dc.Spec.FeatureGates[consts.ResourceInjectorMatchConditionFeatureGate]; ok {
data.Data[consts.ResourceInjectorMatchConditionFeatureGate] = resourceInjector
}
data.Data[consts.ResourceInjectorMatchConditionFeatureGate] = r.FeatureGate.IsEnabled(consts.ResourceInjectorMatchConditionFeatureGate)

objs, err := render.RenderDir(path, &data)
if err != nil {
Expand Down
2 changes: 2 additions & 0 deletions controllers/sriovoperatorconfig_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
sriovnetworkv1 "github.com/k8snetworkplumbingwg/sriov-network-operator/api/v1"
"github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/consts"
constants "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/consts"
"github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/featuregate"
mock_platforms "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/platforms/mock"
"github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/platforms/openshift"
util "github.com/k8snetworkplumbingwg/sriov-network-operator/test/util"
Expand Down Expand Up @@ -75,6 +76,7 @@ var _ = Describe("SriovOperatorConfig controller", Ordered, func() {
Client: k8sManager.GetClient(),
Scheme: k8sManager.GetScheme(),
PlatformHelper: platformHelper,
FeatureGate: featuregate.New(),
}).SetupWithManager(k8sManager)
Expect(err).ToNot(HaveOccurred())

Expand Down
9 changes: 7 additions & 2 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import (

sriovnetworkv1 "github.com/k8snetworkplumbingwg/sriov-network-operator/api/v1"
"github.com/k8snetworkplumbingwg/sriov-network-operator/controllers"
"github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/featuregate"
"github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/leaderelection"

snolog "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/log"
Expand Down Expand Up @@ -156,6 +157,8 @@ func main() {
os.Exit(1)
}

featureGate := featuregate.New()

if err = (&controllers.SriovNetworkReconciler{
Client: mgrGlobal.GetClient(),
Scheme: mgrGlobal.GetScheme(),
Expand All @@ -171,8 +174,9 @@ func main() {
os.Exit(1)
}
if err = (&controllers.SriovNetworkNodePolicyReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
FeatureGate: featureGate,
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "SriovNetworkNodePolicy")
os.Exit(1)
Expand All @@ -181,6 +185,7 @@ func main() {
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
PlatformHelper: platformsHelper,
FeatureGate: featureGate,
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "SriovOperatorConfig")
os.Exit(1)
Expand Down
64 changes: 64 additions & 0 deletions pkg/featuregate/featuregate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package featuregate

import (
"fmt"
"strings"
"sync"
)

// FeatureGate provides methods to check state of the feature
type FeatureGate interface {
// IsEnabled returns state of the feature,
// if feature name is unknown will always return false
IsEnabled(feature string) bool
// Init set state for the features from the provided map.
// completely removes the previous state
Init(features map[string]bool)
// String returns string representation of the feature state
String() string
}

// New returns default implementation of the FeatureGate interface
func New() FeatureGate {
return &featureGate{
lock: &sync.RWMutex{},
state: map[string]bool{},
}
}

type featureGate struct {
lock *sync.RWMutex
state map[string]bool
}

// IsEnabled returns state of the feature,
// if feature name is unknown will always return false
func (fg *featureGate) IsEnabled(feature string) bool {
fg.lock.RLock()
defer fg.lock.RUnlock()
return fg.state[feature]
}

// Init set state for the features from the provided map.
// completely removes the previous state
func (fg *featureGate) Init(features map[string]bool) {
fg.lock.Lock()
defer fg.lock.Unlock()
fg.state = make(map[string]bool, len(features))
for k, v := range features {
fg.state[k] = v
}
}

// String returns string representation of the feature state
func (fg *featureGate) String() string {
fg.lock.RLock()
defer fg.lock.RUnlock()
var result strings.Builder
var sep string
for k, v := range fg.state {
result.WriteString(fmt.Sprintf("%s%s:%t", sep, k, v))
sep = ", "
}
return result.String()
}
32 changes: 32 additions & 0 deletions pkg/featuregate/featuregate_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package featuregate

import (
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)

var _ = Describe("FeatureGate", func() {
Context("IsEnabled", func() {
It("return false for unknown feature", func() {
Expect(New().IsEnabled("something")).To(BeFalse())
})
})
Context("Init", func() {
It("should update the state", func() {
f := New()
f.Init(map[string]bool{"feat1": true, "feat2": false})
Expect(f.IsEnabled("feat1")).To(BeTrue())
Expect(f.IsEnabled("feat2")).To(BeFalse())
})
})
Context("String", func() {
It("no features", func() {
Expect(New().String()).To(Equal(""))
})
It("print feature state", func() {
f := New()
f.Init(map[string]bool{"feat1": true, "feat2": false})
Expect(f.String()).To(And(ContainSubstring("feat1:true"), ContainSubstring("feat2:false")))
})
})
})
21 changes: 21 additions & 0 deletions pkg/featuregate/suite_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package featuregate

import (
"testing"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"

"go.uber.org/zap/zapcore"
"sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
)

func TestFeatureGate(t *testing.T) {
log.SetLogger(zap.New(
zap.WriteTo(GinkgoWriter),
zap.Level(zapcore.Level(-2)),
zap.UseDevMode(true)))
RegisterFailHandler(Fail)
RunSpecs(t, "Package featuregate Suite")
}
Loading