Skip to content

Commit 19d2713

Browse files
authored
Merge pull request #825 from Pacho20/daemonset-deployment-mode
Daemonset deployment mode
2 parents 197a553 + 5e13985 commit 19d2713

14 files changed

+2938
-261
lines changed

controllers/daemonset_reconcile.go

Lines changed: 938 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
package controllers
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
k8serrors "k8s.io/apimachinery/pkg/api/errors"
8+
meta "k8s.io/apimachinery/pkg/api/meta"
9+
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
10+
"k8s.io/apimachinery/pkg/runtime/schema"
11+
"sigs.k8s.io/controller-runtime/pkg/client"
12+
)
13+
14+
// Create enum to represent the state of the deployment mode
15+
type DeploymentMode int
16+
17+
const (
18+
MachineConfigMode DeploymentMode = iota
19+
DaemonSetMode
20+
)
21+
22+
// Create enum to represent the configuration of the deployment mode
23+
type DeploymentModeOption string
24+
25+
const (
26+
MachineConfigOption DeploymentModeOption = "MachineConfig"
27+
DaemonSetOption DeploymentModeOption = "DaemonSet"
28+
DaemonSetFallbackOption DeploymentModeOption = "DaemonSetFallback"
29+
)
30+
31+
const (
32+
machineConfigGroup = "machineconfiguration.openshift.io"
33+
machineConfigVersion = "v1"
34+
machineConfigKind = "MachineConfig"
35+
)
36+
37+
func ParseDeploymentModeOption(s string) (DeploymentModeOption, error) {
38+
switch DeploymentModeOption(s) {
39+
case MachineConfigOption, DaemonSetOption, DaemonSetFallbackOption:
40+
return DeploymentModeOption(s), nil
41+
default:
42+
return "", fmt.Errorf("invalid DeploymentMode: %q", s)
43+
}
44+
}
45+
46+
func (d DeploymentModeOption) String() string {
47+
return string(d)
48+
}
49+
50+
// Process the DeploymentMode feature gate (FG).
51+
// This method is invoked by the reconcile loop at its initiation.
52+
// It examines the current state of the FeatureGate and adjusts the deployment mode (DaemonSet or MachineConfig)
53+
// based on the selected DeploymentModeOption and the availability of the MachineConfig Add-on.
54+
//
55+
// The behavior is as follows:
56+
// - If the mode is MachineConfigOption, the deployment mode is set to MachineConfig.
57+
// - If the mode is DaemonSetOption, the deployment mode is forcibly set to DaemonSet, regardless of MachineConfig availability.
58+
// - If the mode is DaemonSetFallbackOption, the deployment mode is set to DaemonSet only if the MachineConfig Add-on is unavailable.
59+
// Otherwise, it defaults to MachineConfig.
60+
func (r *KataConfigOpenShiftReconciler) handleDeploymentModeFeature(mode DeploymentModeOption) error {
61+
r.Log.Info("Feature gate", "featuregate", DeploymentModeConfig, "state", mode)
62+
63+
machineConfigAvailable, err := r.isMachineConfigAvailable()
64+
if err != nil {
65+
r.Log.Info("Error checking if MachineConfig is available")
66+
return err
67+
}
68+
69+
if mode == MachineConfigOption {
70+
if !machineConfigAvailable {
71+
return fmt.Errorf("deployment mode is set to MachineConfig, but it's not available")
72+
}
73+
74+
r.Log.Info("Deployment mode will be set to MachineConfig")
75+
r.DeploymentMode = MachineConfigMode
76+
return nil
77+
}
78+
79+
if mode == DaemonSetOption {
80+
r.Log.Info("Deployment mode will be set to DaemonSet")
81+
r.DeploymentMode = DaemonSetMode
82+
return nil
83+
}
84+
85+
if mode == DaemonSetFallbackOption && !machineConfigAvailable {
86+
r.Log.Info("MachineConfig is not available, deployment mode will be set to DaemonSet")
87+
r.DeploymentMode = DaemonSetMode
88+
} else {
89+
r.Log.Info("Deployment mode will be set to MachineConfig")
90+
r.DeploymentMode = MachineConfigMode
91+
}
92+
93+
return nil
94+
}
95+
96+
// isMachineConfigAvailable checks if MachineConfig CRD is available.
97+
//
98+
// It returns a boolean indicating availability and an error if any.
99+
func (r *KataConfigOpenShiftReconciler) isMachineConfigAvailable() (bool, error) {
100+
machineConfig := &unstructured.Unstructured{}
101+
machineConfig.SetGroupVersionKind(schema.GroupVersionKind{
102+
Group: machineConfigGroup,
103+
Version: machineConfigVersion,
104+
Kind: machineConfigKind,
105+
})
106+
107+
// Attempt to GET any MachineConfig to verify if the GVK is known.
108+
// If the CRD isn’t installed, it will return a NoMatchError.
109+
err := r.Client.Get(context.Background(), client.ObjectKey{Name: "dummy-machine-config"}, machineConfig)
110+
if err == nil || k8serrors.IsNotFound(err) {
111+
r.Log.Info("MachineConfig CRD is present")
112+
return true, nil
113+
}
114+
115+
if meta.IsNoMatchError(err) {
116+
r.Log.Info("MachineConfig CRD not found")
117+
return false, nil
118+
}
119+
120+
return false, err
121+
}

controllers/fg_handler.go

Lines changed: 55 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package controllers
22

33
import (
44
"context"
5+
"strconv"
56

67
corev1 "k8s.io/api/core/v1"
78
k8serrors "k8s.io/apimachinery/pkg/api/errors"
@@ -12,15 +13,19 @@ const (
1213
FgConfigMapName = "osc-feature-gates"
1314
ConfidentialFeatureGate = "confidential"
1415
LayeredImageDeployment = "layeredImageDeployment"
16+
DeploymentModeConfig = "deploymentMode"
1517
)
1618

17-
var DefaultFeatureGates = map[string]bool{
18-
ConfidentialFeatureGate: false,
19-
LayeredImageDeployment: false,
19+
var DefaultFeatureGates = FeatureGateStatus{
20+
Confidential: false,
21+
LayeredImageDeployment: false,
22+
DeploymentModeOption: MachineConfigOption,
2023
}
2124

2225
type FeatureGateStatus struct {
23-
FeatureGates map[string]bool
26+
Confidential bool
27+
LayeredImageDeployment bool
28+
DeploymentModeOption DeploymentModeOption
2429
}
2530

2631
// Create enum to represent the state of the feature gates
@@ -40,22 +45,38 @@ const (
4045
// Return an error for any other reason, such as an API error.
4146
func (r *KataConfigOpenShiftReconciler) NewFeatureGateStatus() (*FeatureGateStatus, error) {
4247
fgStatus := &FeatureGateStatus{
43-
FeatureGates: make(map[string]bool),
48+
Confidential: DefaultFeatureGates.Confidential,
49+
LayeredImageDeployment: DefaultFeatureGates.LayeredImageDeployment,
50+
DeploymentModeOption: DefaultFeatureGates.DeploymentModeOption,
4451
}
4552

4653
cfgMap := &corev1.ConfigMap{}
4754
err := r.Client.Get(context.TODO(), types.NamespacedName{Name: FgConfigMapName,
4855
Namespace: OperatorNamespace}, cfgMap)
4956
if err == nil {
50-
for feature, value := range cfgMap.Data {
51-
fgStatus.FeatureGates[feature] = value == "true"
57+
if value, ok := cfgMap.Data[ConfidentialFeatureGate]; ok {
58+
confidential, err := strconv.ParseBool(value)
59+
if err != nil {
60+
r.Log.Info("Couldn't parse confidential status, using default value", "default", DefaultFeatureGates.Confidential, "error", err)
61+
} else {
62+
fgStatus.Confidential = confidential
63+
}
5264
}
53-
}
54-
55-
// Add default values for missing feature gates
56-
for feature, defaultValue := range DefaultFeatureGates {
57-
if _, exists := fgStatus.FeatureGates[feature]; !exists {
58-
fgStatus.FeatureGates[feature] = defaultValue
65+
if value, ok := cfgMap.Data[LayeredImageDeployment]; ok {
66+
layeredImageDeployment, err := strconv.ParseBool(value)
67+
if err != nil {
68+
r.Log.Info("Couldn't parse layeredImageDeployment status, using default value", "default", DefaultFeatureGates.LayeredImageDeployment, "error", err)
69+
} else {
70+
fgStatus.LayeredImageDeployment = layeredImageDeployment
71+
}
72+
}
73+
if value, ok := cfgMap.Data[DeploymentModeConfig]; ok {
74+
mode, err := ParseDeploymentModeOption(value)
75+
if err != nil {
76+
r.Log.Info("Couldn't parse deploymentMode status, using default value", "default", DefaultFeatureGates.DeploymentModeOption, "error", err)
77+
} else {
78+
fgStatus.DeploymentModeOption = mode
79+
}
5980
}
6081
}
6182

@@ -66,8 +87,16 @@ func (r *KataConfigOpenShiftReconciler) NewFeatureGateStatus() (*FeatureGateStat
6687
}
6788
}
6889

69-
func IsEnabled(fgStatus *FeatureGateStatus, feature string) bool {
70-
return fgStatus.FeatureGates[feature]
90+
var statusChecker = map[string]func(fgstatus *FeatureGateStatus) bool{
91+
ConfidentialFeatureGate: func(fgstatus *FeatureGateStatus) bool { return fgstatus.Confidential },
92+
LayeredImageDeployment: func(fgstatus *FeatureGateStatus) bool { return fgstatus.LayeredImageDeployment },
93+
}
94+
95+
func (fgstatus *FeatureGateStatus) IsEnabled(key string) bool {
96+
if checkStatus, ok := statusChecker[key]; ok {
97+
return checkStatus(fgstatus)
98+
}
99+
return false
71100
}
72101

73102
// Function to handle the feature gates
@@ -82,7 +111,7 @@ func (r *KataConfigOpenShiftReconciler) processFeatureGates() error {
82111
// Check which feature gates are enabled in the FG ConfigMap and
83112
// perform the necessary actions
84113
if r.kataConfig.Spec.EnablePeerPods {
85-
if IsEnabled(fgStatus, ConfidentialFeatureGate) {
114+
if fgStatus.IsEnabled(ConfidentialFeatureGate) {
86115
r.Log.Info("Feature gate is enabled", "featuregate", ConfidentialFeatureGate)
87116
// Perform the necessary actions
88117
if err := r.handleFeatureConfidential(Enabled); err != nil {
@@ -97,8 +126,17 @@ func (r *KataConfigOpenShiftReconciler) processFeatureGates() error {
97126
}
98127
}
99128

129+
if err := r.handleDeploymentModeFeature(fgStatus.DeploymentModeOption); err != nil {
130+
return err
131+
}
132+
133+
if r.DeploymentMode == DaemonSetMode {
134+
r.Log.Info("Skipping layered image deployment feature, not using MCO")
135+
return nil
136+
}
137+
100138
// Check layered Image deployment FG
101-
if IsEnabled(fgStatus, LayeredImageDeployment) {
139+
if fgStatus.IsEnabled(LayeredImageDeployment) {
102140
r.Log.Info("Feature gate is enabled", "featuregate", LayeredImageDeployment)
103141
// Perform the necessary actions
104142
return r.handleLayeredImageDeploymentFeature(Enabled)

0 commit comments

Comments
 (0)