Skip to content

Commit a77c2e9

Browse files
authored
Merge pull request #416 from bpradipt/layered-image-new
Kata installation using RHCOS image layer
2 parents fd0c445 + e339996 commit a77c2e9

File tree

5 files changed

+214
-18
lines changed

5 files changed

+214
-18
lines changed

config/samples/featuregates.yaml

+3-4
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ metadata:
44
name: osc-feature-gates
55
namespace: openshift-sandboxed-containers-operator
66
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"
7+
# layeredImageDeployment allows deploying Kata using RHCOS layered image
8+
# This feature gate needs a ConfigMap named layered-image-deploy-cm
9+
layeredImageDeployment: "false"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
apiVersion: v1
2+
data:
3+
osImageURL: "quay.io/openshift_sandboxed_containers/kata-ocp415:tdx"
4+
kernelArguments: "kvm_intel.tdx=1"
5+
6+
kind: ConfigMap
7+
metadata:
8+
name: layered-image-deploy-cm
9+
namespace: openshift-sandboxed-containers-operator

controllers/fg_handler.go

+12-1
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@ import (
1111
const (
1212
FgConfigMapName = "osc-feature-gates"
1313
ConfidentialFeatureGate = "confidential"
14+
LayeredImageDeployment = "layeredImageDeployment"
1415
)
1516

1617
var DefaultFeatureGates = map[string]bool{
1718
ConfidentialFeatureGate: false,
19+
LayeredImageDeployment: false,
1820
}
1921

2022
type FeatureGateStatus struct {
@@ -95,6 +97,15 @@ func (r *KataConfigOpenShiftReconciler) processFeatureGates() error {
9597
}
9698
}
9799

98-
return err
100+
// Check layered Image deployment FG
101+
if IsEnabled(fgStatus, LayeredImageDeployment) {
102+
r.Log.Info("Feature gate is enabled", "featuregate", LayeredImageDeployment)
103+
// Perform the necessary actions
104+
return r.handleLayeredImageDeploymentFeature(Enabled)
105+
} else {
106+
r.Log.Info("Feature gate is disabled", "featuregate", LayeredImageDeployment)
107+
// Perform the necessary actions
108+
return r.handleLayeredImageDeploymentFeature(Disabled)
109+
}
99110

100111
}

controllers/layered_image_handler.go

+164
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
package controllers
2+
3+
import (
4+
"context"
5+
"encoding/json"
6+
"fmt"
7+
"strings"
8+
9+
ignTypes "github.com/coreos/ignition/v2/config/v3_2/types"
10+
mcfgv1 "github.com/openshift/machine-config-operator/pkg/apis/machineconfiguration.openshift.io/v1"
11+
corev1 "k8s.io/api/core/v1"
12+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
13+
"k8s.io/apimachinery/pkg/runtime"
14+
"k8s.io/apimachinery/pkg/types"
15+
)
16+
17+
const (
18+
LayeredImageDeployCm = "layered-image-deploy-cm"
19+
image_mc_name = "50-enable-sandboxed-containers-image"
20+
)
21+
22+
// Process the LayeredImageDeployment feature gate (FG)
23+
// This method will be called by the processFeatureGates method during the beginning of the reconcile loop
24+
// The method will check for any existing MachineConfig related to KataConfig and return to the caller
25+
// by setting r.ImgMc to the image MachineConfig if present. This will allow the remainder of the reconcile loop
26+
// to use the image MachineConfig as needed.
27+
// If neither extension or image MachineConfig exists, and layeredImageDeployment feature is enabled,
28+
// then this method will create the image MachineConfig from the fg ConfigMap and set r.ImgMc to the
29+
// newly created image MachineConfig.
30+
// If layeredImageDeployment feature is disabled, then the method will reset r.ImgMc to nil
31+
// The key design aspect of this FG is that it has effect only during the creation of the KataConfig.
32+
// After creation of the KataConfig this FG has no effect.
33+
func (r *KataConfigOpenShiftReconciler) handleLayeredImageDeploymentFeature(state FeatureGateState) error {
34+
35+
// Check if MachineConfig exists and return the same without changing anything
36+
mc, err := r.getExistingMachineConfig()
37+
if err != nil {
38+
r.Log.Info("Error in getting existing MachineConfig", "err", err)
39+
return err
40+
}
41+
42+
if mc != nil {
43+
r.Log.Info("MachineConfig is already present. No changes will be done")
44+
// If the MachineConfig is imageMachineConfig, then set r.ImgMc to the same
45+
if mc.Name == image_mc_name {
46+
r.ImgMc = mc
47+
}
48+
return nil
49+
}
50+
51+
if state == Enabled {
52+
r.Log.Info("LayeredImageDeployment feature is enabled")
53+
54+
cm := &corev1.ConfigMap{}
55+
err := r.Client.Get(context.Background(), types.NamespacedName{
56+
Name: LayeredImageDeployCm,
57+
Namespace: OperatorNamespace,
58+
}, cm)
59+
if err != nil {
60+
r.Log.Info("Error in retrieving LayeredImageDeployment ConfigMap", "err", err)
61+
return err
62+
}
63+
64+
// Set the ImgMc here
65+
r.ImgMc, err = r.createMachineConfigFromConfigMap(cm)
66+
if err != nil {
67+
r.Log.Info("Error in creating MachineConfig for LayeredImageDeployment from ConfigMap", "err", err)
68+
return err
69+
}
70+
71+
} else {
72+
r.Log.Info("LayeredImageDeployment feature is disabled. Resetting ImgMc")
73+
// Reset ImgMc
74+
r.ImgMc = nil
75+
76+
}
77+
78+
return nil
79+
}
80+
81+
func (r *KataConfigOpenShiftReconciler) getExistingMachineConfig() (*mcfgv1.MachineConfig, error) {
82+
r.Log.Info("Getting any existing MachineConfigs related to KataConfig")
83+
84+
// Retrieve the existing MachineConfig for Kata - either extension or image
85+
// Check for label "app":r.kataConfig.Name
86+
// and name "50-enable-sandboxed-containers-extension" or name "50-enable-sandboxed-containers-image"
87+
mcList := &mcfgv1.MachineConfigList{}
88+
err := r.Client.List(context.Background(), mcList)
89+
if err != nil {
90+
r.Log.Info("Error in listing MachineConfigs", "err", err)
91+
return nil, err
92+
}
93+
94+
for _, mc := range mcList.Items {
95+
if mc.Labels["app"] == r.kataConfig.Name &&
96+
(mc.Name == extension_mc_name || mc.Name == image_mc_name) {
97+
return &mc, nil
98+
}
99+
}
100+
101+
r.Log.Info("No existing MachineConfigs related to KataConfig found")
102+
103+
return nil, nil
104+
}
105+
106+
// Method to create a new MachineConfig object from configMap data
107+
// The configMap data will have two keys: "osImageURL" and "kernelArgs"
108+
func (r *KataConfigOpenShiftReconciler) createMachineConfigFromConfigMap(cm *corev1.ConfigMap) (*mcfgv1.MachineConfig, error) {
109+
110+
// Get the osImageURL from the ConfigMap
111+
// osImageURL is mandatory for creating a MachineConfig
112+
osImageURL, exists := cm.Data["osImageURL"]
113+
if !exists {
114+
return nil, fmt.Errorf("osImageURL not found in ConfigMap")
115+
}
116+
117+
ic := ignTypes.Config{
118+
Ignition: ignTypes.Ignition{
119+
Version: "3.2.0",
120+
},
121+
}
122+
123+
icb, err := json.Marshal(ic)
124+
if err != nil {
125+
return nil, err
126+
}
127+
mc := &mcfgv1.MachineConfig{
128+
TypeMeta: metav1.TypeMeta{
129+
APIVersion: "machineconfiguration.openshift.io/v1",
130+
Kind: "MachineConfig",
131+
},
132+
ObjectMeta: metav1.ObjectMeta{
133+
Name: image_mc_name,
134+
Namespace: OperatorNamespace,
135+
},
136+
Spec: mcfgv1.MachineConfigSpec{
137+
Config: runtime.RawExtension{
138+
Raw: icb,
139+
},
140+
OSImageURL: osImageURL,
141+
},
142+
}
143+
144+
if kernelArguments, ok := cm.Data["kernelArguments"]; ok {
145+
// Parse the kernel arguments and set them in the MachineConfig
146+
// Note that in the configmap the kernel arguments are stored as a single string
147+
// eg. "a=b c=d ..." and we need to split them into individual arguments
148+
// eg ["a=b", "c=d", ...]
149+
// Split the kernel arguments string into individual arguments
150+
mc.Spec.KernelArguments = strings.Fields(kernelArguments)
151+
}
152+
153+
// Set the required labels
154+
mcp, err := r.getMcpName()
155+
if err != nil {
156+
return nil, err
157+
}
158+
mc.Labels = map[string]string{
159+
"machineconfiguration.openshift.io/role": mcp,
160+
"app": r.kataConfig.Name,
161+
}
162+
163+
return mc, nil
164+
}

controllers/openshift_controller.go

+26-13
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ type KataConfigOpenShiftReconciler struct {
6161
Scheme *runtime.Scheme
6262

6363
kataConfig *kataconfigurationv1.KataConfig
64+
65+
ImgMc *mcfgv1.MachineConfig
6466
}
6567

6668
const (
@@ -494,6 +496,12 @@ func getExtensionName() string {
494496
func (r *KataConfigOpenShiftReconciler) newMCForCR(machinePool string) (*mcfgv1.MachineConfig, error) {
495497
r.Log.Info("Creating MachineConfig for Custom Resource")
496498

499+
if r.ImgMc != nil {
500+
r.Log.Info("Image based MachineConfig", "MachineConfig", r.ImgMc)
501+
return r.ImgMc, nil
502+
}
503+
504+
// Create extension MachineConfig
497505
ic := ignTypes.Config{
498506
Ignition: ignTypes.Ignition{
499507
Version: "3.2.0",
@@ -528,6 +536,8 @@ func (r *KataConfigOpenShiftReconciler) newMCForCR(machinePool string) (*mcfgv1.
528536
},
529537
}
530538

539+
r.Log.Info("Extension based MachineConfig", "MachineConfig", mc)
540+
531541
return &mc, nil
532542
}
533543

@@ -843,6 +853,8 @@ func (r *KataConfigOpenShiftReconciler) processKataConfigDeleteRequest() (ctrl.R
843853
err = r.Client.Get(context.TODO(), types.NamespacedName{Name: mc.Name}, mc)
844854
if err != nil && k8serrors.IsNotFound(err) {
845855
isMcDeleted = true
856+
// Reset ImgMc
857+
r.ImgMc = nil
846858
} else if err != nil {
847859
return ctrl.Result{}, err
848860
}
@@ -1053,7 +1065,7 @@ func (r *KataConfigOpenShiftReconciler) processKataConfigInstallRequest() (ctrl.
10531065
r.Log.Info("SCNodeRole is: " + machinePool)
10541066
}
10551067

1056-
wasMcJustCreated, err := r.createExtensionMc(machinePool)
1068+
wasMcJustCreated, err := r.createMc(machinePool)
10571069
if err != nil {
10581070
return ctrl.Result{Requeue: true}, nil
10591071
}
@@ -1281,24 +1293,24 @@ func (r *KataConfigOpenShiftReconciler) processKataConfigInstallRequest() (ctrl.
12811293
// If the first return value is 'true' it means that the MC was just created
12821294
// by this call, 'false' means that it's already existed. As usual, the first
12831295
// return value is only valid if the second one is nil.
1284-
func (r *KataConfigOpenShiftReconciler) createExtensionMc(machinePool string) (bool, error) {
1296+
func (r *KataConfigOpenShiftReconciler) createMc(machinePool string) (bool, error) {
12851297

12861298
// In case we're returning an error we want to make it explicit that
12871299
// the first return value is "not care". Unfortunately golang seems
12881300
// to lack syntax for creating an expression with default bool value
12891301
// hence this work-around.
12901302
var dummy bool
12911303

1292-
/* Create Machine Config object to enable sandboxed containers RHCOS extension */
1293-
mc := &mcfgv1.MachineConfig{}
1294-
err := r.Client.Get(context.TODO(), types.NamespacedName{Name: extension_mc_name}, mc)
1295-
if err != nil && (k8serrors.IsNotFound(err) || k8serrors.IsGone(err)) {
1304+
/* Create Machine Config object to install sandboxed containers */
12961305

1297-
r.Log.Info("creating RHCOS extension MachineConfig")
1298-
mc, err = r.newMCForCR(machinePool)
1299-
if err != nil {
1300-
return dummy, err
1301-
}
1306+
r.Log.Info("creating RHCOS MachineConfig")
1307+
mc, err := r.newMCForCR(machinePool)
1308+
if err != nil {
1309+
return dummy, err
1310+
}
1311+
1312+
err = r.Client.Get(context.TODO(), types.NamespacedName{Name: mc.Name}, mc)
1313+
if err != nil && (k8serrors.IsNotFound(err) || k8serrors.IsGone(err)) {
13021314

13031315
err = r.Client.Create(context.TODO(), mc)
13041316
if err != nil {
@@ -1308,12 +1320,13 @@ func (r *KataConfigOpenShiftReconciler) createExtensionMc(machinePool string) (b
13081320
r.Log.Info("MachineConfig successfully created", "mc.Name", mc.Name)
13091321
return true, nil
13101322
} else if err != nil {
1311-
r.Log.Info("failed to retrieve extension MachineConfig", "err", err)
1323+
r.Log.Info("failed to retrieve MachineConfig", "err", err)
13121324
return dummy, err
13131325
} else {
1314-
r.Log.Info("extension MachineConfig already exists")
1326+
r.Log.Info("MachineConfig already exists")
13151327
return false, nil
13161328
}
1329+
13171330
}
13181331

13191332
func (r *KataConfigOpenShiftReconciler) makeReconcileRequest() reconcile.Request {

0 commit comments

Comments
 (0)