Skip to content

Commit d97cfde

Browse files
committed
feature-gates: adding initial structure
This commit introduces the `FeatureGates` struct in the operator's configuration, enabling a flexible and controlled approach to feature rollout. The `FeatureGates` configMap allows for the enabling or disabling of specific features, with a default behaviour based on each feature's maturity level. For each new feature, developers need to modify the "default" struct, just in case users don't have to set their desired behaviour. User's choice will override default values. I'm trying to use a simple approach here where we could change promote/depromote a feature by just changing the comments and the default values. Fixes: #KATA-2677 Signed-off-by: Beraldo Leal <[email protected]>
1 parent 721edad commit d97cfde

File tree

6 files changed

+124
-2
lines changed

6 files changed

+124
-2
lines changed

Dockerfile

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ COPY main.go main.go
1515
COPY api api/
1616
COPY config config/
1717
COPY controllers controllers/
18+
COPY internal internal/
1819

1920
RUN go mod download
2021
# needed for docker build but not for local builds

bundle-custom.Dockerfile

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ COPY go.sum go.sum
1010
COPY api api/
1111
COPY config config/
1212
COPY controllers controllers/
13+
COPY internal internal/
1314

1415
RUN go mod download
1516
# needed for docker build but not for local builds

config/samples/featuregates.yaml

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
apiVersion: v1
2+
kind: ConfigMap
3+
metadata:
4+
name: osc-feature-gates
5+
namespace: openshift-sandboxed-containers-operator
6+
data:
7+
# timeTravel allows navigating through cluster states across time.
8+
# It is useful for scenarios where you want to view historical data or
9+
# predict future states based on current trends. Default is "false".
10+
# timeTravel: "false"
11+
12+
# quantumEntanglementSync enables instant state consistency across clusters
13+
# using principles of quantum mechanics. This advanced feature ensures
14+
# data is synchronized across different locations without traditional
15+
# network latency. Default is "false".
16+
# quantumEntanglementSync: "false"
17+
18+
# autoHealingWithAI employs artificial intelligence to automatically
19+
# detect and resolve cluster issues. It leverages machine learning algorithms
20+
# to predict potential problems before they occur, ensuring high availability.
21+
# Default is "true".
22+
# autoHealingWithAI: "true"

controllers/openshift_controller.go

+50-2
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import (
3535
mcfgv1 "github.com/openshift/machine-config-operator/pkg/apis/machineconfiguration.openshift.io/v1"
3636
mcfgconsts "github.com/openshift/machine-config-operator/pkg/daemon/constants"
3737
kataconfigurationv1 "github.com/openshift/sandboxed-containers-operator/api/v1"
38+
"github.com/openshift/sandboxed-containers-operator/internal/featuregates"
3839
corev1 "k8s.io/api/core/v1"
3940
nodeapi "k8s.io/api/node/v1"
4041
k8serrors "k8s.io/apimachinery/pkg/api/errors"
@@ -59,7 +60,8 @@ type KataConfigOpenShiftReconciler struct {
5960
Log logr.Logger
6061
Scheme *runtime.Scheme
6162

62-
kataConfig *kataconfigurationv1.KataConfig
63+
kataConfig *kataconfigurationv1.KataConfig
64+
FeatureGates *featuregates.FeatureGates
6365
}
6466

6567
const (
@@ -120,6 +122,10 @@ func (r *KataConfigOpenShiftReconciler) Reconcile(ctx context.Context, req ctrl.
120122
return ctrl.Result{}, err
121123
}
122124

125+
if r.FeatureGates.IsEnabled(ctx, "timeTravel") {
126+
r.Log.Info("TimeTravel feature is enabled. Performing feature-specific logic...")
127+
}
128+
123129
return func() (ctrl.Result, error) {
124130

125131
// k8s resource correctness checking on creation/modification
@@ -1329,6 +1335,45 @@ func logMcpChange(log logr.Logger, statusOld, statusNew mcfgv1.MachineConfigPool
13291335
}
13301336
}
13311337

1338+
type ConfigMapEventHandler struct {
1339+
reconciler *KataConfigOpenShiftReconciler
1340+
}
1341+
1342+
func (eh *ConfigMapEventHandler) isConfigMapRelevant(configMap *corev1.ConfigMap) bool {
1343+
if eh.reconciler == nil || eh.reconciler.FeatureGates == nil {
1344+
return false
1345+
}
1346+
relevantNamespace := configMap.Namespace == eh.reconciler.FeatureGates.Namespace
1347+
relevantName := configMap.Name == eh.reconciler.FeatureGates.ConfigMapName
1348+
return relevantNamespace && relevantName
1349+
}
1350+
1351+
func (eh *ConfigMapEventHandler) Create(ctx context.Context, evt event.CreateEvent, queue workqueue.RateLimitingInterface) {
1352+
configMap, ok := evt.Object.(*corev1.ConfigMap)
1353+
if !ok || !eh.isConfigMapRelevant(configMap) {
1354+
return
1355+
}
1356+
queue.Add(eh.reconciler.makeReconcileRequest())
1357+
}
1358+
1359+
func (eh *ConfigMapEventHandler) Update(ctx context.Context, evt event.UpdateEvent, queue workqueue.RateLimitingInterface) {
1360+
configMap, ok := evt.ObjectNew.(*corev1.ConfigMap)
1361+
if !ok || !eh.isConfigMapRelevant(configMap) {
1362+
return
1363+
}
1364+
}
1365+
1366+
func (eh *ConfigMapEventHandler) Delete(ctx context.Context, evt event.DeleteEvent, queue workqueue.RateLimitingInterface) {
1367+
configMap, ok := evt.Object.(*corev1.ConfigMap)
1368+
if !ok || !eh.isConfigMapRelevant(configMap) {
1369+
return
1370+
}
1371+
queue.Add(eh.reconciler.makeReconcileRequest())
1372+
}
1373+
1374+
func (eh *ConfigMapEventHandler) Generic(ctx context.Context, evt event.GenericEvent, queue workqueue.RateLimitingInterface) {
1375+
}
1376+
13321377
type McpEventHandler struct {
13331378
reconciler *KataConfigOpenShiftReconciler
13341379
}
@@ -1572,7 +1617,10 @@ func (r *KataConfigOpenShiftReconciler) SetupWithManager(mgr ctrl.Manager) error
15721617
Watches(
15731618
&corev1.Node{},
15741619
&NodeEventHandler{r}).
1575-
Complete(r)
1620+
Watches(
1621+
&corev1.ConfigMap{},
1622+
&ConfigMapEventHandler{r},
1623+
).Complete(r)
15761624
}
15771625

15781626
func (r *KataConfigOpenShiftReconciler) getNodes() (*corev1.NodeList, error) {

internal/featuregates/featuregates.go

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package featuregates
2+
3+
import (
4+
"context"
5+
corev1 "k8s.io/api/core/v1"
6+
"log"
7+
"sigs.k8s.io/controller-runtime/pkg/client"
8+
)
9+
10+
type FeatureGates struct {
11+
Client client.Client
12+
Namespace string
13+
ConfigMapName string
14+
}
15+
16+
var DefaultFeatureGates = map[string]bool{
17+
"timeTravel": false,
18+
"quantumEntanglementSync": false,
19+
"autoHealingWithAI": true,
20+
}
21+
22+
func (fg *FeatureGates) IsEnabled(ctx context.Context, feature string) bool {
23+
if fg == nil {
24+
return false
25+
}
26+
cfgMap := &corev1.ConfigMap{}
27+
err := fg.Client.Get(ctx,
28+
client.ObjectKey{Name: fg.ConfigMapName, Namespace: fg.Namespace},
29+
cfgMap)
30+
31+
if err != nil {
32+
log.Printf("Error fetching feature gates: %v", err)
33+
} else {
34+
if value, exists := cfgMap.Data[feature]; exists {
35+
return value == "true"
36+
}
37+
}
38+
39+
defaultValue, exists := DefaultFeatureGates[feature]
40+
if exists {
41+
return defaultValue
42+
}
43+
return false
44+
}

main.go

+6
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ import (
5454

5555
kataconfigurationv1 "github.com/openshift/sandboxed-containers-operator/api/v1"
5656
"github.com/openshift/sandboxed-containers-operator/controllers"
57+
"github.com/openshift/sandboxed-containers-operator/internal/featuregates"
5758
// +kubebuilder:scaffold:imports
5859
)
5960

@@ -142,6 +143,11 @@ func main() {
142143
Client: mgr.GetClient(),
143144
Log: ctrl.Log.WithName("controllers").WithName("KataConfig"),
144145
Scheme: mgr.GetScheme(),
146+
FeatureGates: &featuregates.FeatureGates{
147+
Client: mgr.GetClient(),
148+
Namespace: OperatorNamespace,
149+
ConfigMapName: "osc-feature-gates",
150+
},
145151
}).SetupWithManager(mgr); err != nil {
146152
setupLog.Error(err, "unable to create KataConfig controller for OpenShift cluster", "controller", "KataConfig")
147153
os.Exit(1)

0 commit comments

Comments
 (0)