Skip to content

Adding support for Modules with no OOT kmod #1084

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

Merged
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
5 changes: 3 additions & 2 deletions api/v1beta1/module_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,8 @@ type ModuleSpec struct {

// ModuleLoader allows overriding some properties of the container that loads the kernel module on the node.
// Name and image are ignored and are set automatically by the KMM Operator.
ModuleLoader ModuleLoaderSpec `json:"moduleLoader"`
// +optional
ModuleLoader *ModuleLoaderSpec `json:"moduleLoader,omitempty"`

// ImageRepoSecret is an optional secret that is used to pull both the module loader and the device plugin, and
// to push the resulting image from the module loader build, if enabled.
Expand Down Expand Up @@ -351,7 +352,7 @@ type ModuleStatus struct {
// if it was deployed during reconciliation
DevicePlugin DaemonSetStatus `json:"devicePlugin,omitempty"`
// ModuleLoader contains the status of the ModuleLoader daemonset
ModuleLoader DaemonSetStatus `json:"moduleLoader"`
ModuleLoader DaemonSetStatus `json:"moduleLoader,omitempty"`
}

//+kubebuilder:object:root=true
Expand Down
6 changes: 5 additions & 1 deletion api/v1beta1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -2728,7 +2728,6 @@ spec:
type: object
type: array
required:
- moduleLoader
- selector
type: object
selector:
Expand Down
3 changes: 0 additions & 3 deletions config/crd/bases/kmm.sigs.x-k8s.io_modules.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2704,7 +2704,6 @@ spec:
type: object
type: array
required:
- moduleLoader
- selector
type: object
status:
Expand Down Expand Up @@ -2745,8 +2744,6 @@ spec:
format: int32
type: integer
type: object
required:
- moduleLoader
type: object
type: object
served: true
Expand Down
78 changes: 49 additions & 29 deletions internal/controllers/device_plugin_reconciler.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,9 +182,10 @@ func (dprh *devicePluginReconcilerHelper) handleDevicePlugin(ctx context.Context
}

logger := log.FromContext(ctx)
ds := getExistingDS(existingDevicePluginDS, mod.Namespace, mod.Name, mod.Spec.ModuleLoader.Container.Version)

ds, version := getExistingDSFromVersion(existingDevicePluginDS, mod.Namespace, mod.Name, mod.Spec.ModuleLoader)
if ds == nil {
logger.Info("creating new device plugin DS", "version", mod.Spec.ModuleLoader.Container.Version)
logger.Info("creating new device plugin DS", "version", version)
ds = &appsv1.DaemonSet{
ObjectMeta: metav1.ObjectMeta{Namespace: mod.Namespace, GenerateName: mod.Name + "-device-plugin-"},
}
Expand All @@ -203,6 +204,11 @@ func (dprh *devicePluginReconcilerHelper) handleDevicePlugin(ctx context.Context
func (dprh *devicePluginReconcilerHelper) garbageCollect(ctx context.Context,
mod *kmmv1beta1.Module,
existingDS []appsv1.DaemonSet) error {
if mod.Spec.ModuleLoader == nil {
Copy link
Contributor

Choose a reason for hiding this comment

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

lets add a comment here that explains why we don't need to go through garbage collect flow in case module loader does not exists

// If ModuleLoader is not exist, Ordered Upgrade is not relevant
// so there is no need to delete older-versioned Deamonsets
return nil
}

logger := log.FromContext(ctx)
deleted := make([]string, 0)
Expand Down Expand Up @@ -248,21 +254,22 @@ func (dprh *devicePluginReconcilerHelper) setKMMOMetrics(ctx context.Context) {
if mod.Spec.DevicePlugin != nil {
numModulesWithDevicePlugin += 1
}
buildCapable, signCapable := isModuleBuildAndSignCapable(&mod)
if buildCapable {
numModulesWithBuild += 1
}
if signCapable {
numModulesWithSign += 1
}

if mod.Spec.ModuleLoader.Container.Modprobe.Args != nil {
modprobeArgs := strings.Join(mod.Spec.ModuleLoader.Container.Modprobe.Args.Load, ",")
dprh.metricsAPI.SetKMMModprobeArgs(mod.Name, mod.Namespace, modprobeArgs)
}
if mod.Spec.ModuleLoader.Container.Modprobe.RawArgs != nil {
modprobeRawArgs := strings.Join(mod.Spec.ModuleLoader.Container.Modprobe.RawArgs.Load, ",")
dprh.metricsAPI.SetKMMModprobeRawArgs(mod.Name, mod.Namespace, modprobeRawArgs)
if mod.Spec.ModuleLoader != nil {
Copy link
Contributor

Choose a reason for hiding this comment

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

WDYT about moving the "if mod.Spec.ModuleLoader != nil {" above line 259? numModulesWithBuild and numModulesWithSign need to be calculated only in case ModuleLoader is not nil. And, in addition, we want have to change the isModuleBuildAndSignCapable function, since the pointer was verified prior to calling that function

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@yevgeny-shnaidman isModuleBuildAndSignCapable returns false, false whenever ModuleLoader is nil automatically though

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

buildCapable, signCapable := isModuleBuildAndSignCapable(&mod)
if buildCapable {
numModulesWithBuild += 1
}
if signCapable {
numModulesWithSign += 1
}
if mod.Spec.ModuleLoader.Container.Modprobe.Args != nil {
modprobeArgs := strings.Join(mod.Spec.ModuleLoader.Container.Modprobe.Args.Load, ",")
dprh.metricsAPI.SetKMMModprobeArgs(mod.Name, mod.Namespace, modprobeArgs)
}
if mod.Spec.ModuleLoader.Container.Modprobe.RawArgs != nil {
modprobeRawArgs := strings.Join(mod.Spec.ModuleLoader.Container.Modprobe.RawArgs.Load, ",")
dprh.metricsAPI.SetKMMModprobeRawArgs(mod.Name, mod.Namespace, modprobeRawArgs)
}
}
}
dprh.metricsAPI.SetKMMModulesNum(numModules)
Expand Down Expand Up @@ -348,14 +355,8 @@ func (dsci *daemonSetCreatorImpl) setDevicePluginAsDesired(
},
},
}
standardLabels := map[string]string{constants.ModuleNameLabel: mod.Name}
nodeSelector := map[string]string{utils.GetKernelModuleReadyNodeLabel(mod.Namespace, mod.Name): ""}

if mod.Spec.ModuleLoader.Container.Version != "" {
versionLabel := utils.GetDevicePluginVersionLabelName(mod.Namespace, mod.Name)
standardLabels[versionLabel] = mod.Spec.ModuleLoader.Container.Version
nodeSelector[versionLabel] = mod.Spec.ModuleLoader.Container.Version
}
standardLabels, nodeSelector := generateDevicePluginLabelsAndSelector(mod)

ds.SetLabels(
overrideLabels(ds.GetLabels(), standardLabels),
Expand Down Expand Up @@ -395,6 +396,21 @@ func (dsci *daemonSetCreatorImpl) setDevicePluginAsDesired(
return controllerutil.SetControllerReference(mod, ds, dsci.scheme)
}

func generateDevicePluginLabelsAndSelector(mod *kmmv1beta1.Module) (map[string]string, map[string]string) {
labels := map[string]string{constants.ModuleNameLabel: mod.Name}
nodeSelector := map[string]string{utils.GetKernelModuleReadyNodeLabel(mod.Namespace, mod.Name): ""}

if mod.Spec.ModuleLoader != nil && mod.Spec.ModuleLoader.Container.Version != "" {
versionLabel := utils.GetDevicePluginVersionLabelName(mod.Namespace, mod.Name)
labels[versionLabel] = mod.Spec.ModuleLoader.Container.Version
nodeSelector[versionLabel] = mod.Spec.ModuleLoader.Container.Version
} else if mod.Spec.ModuleLoader == nil {
nodeSelector = mod.Spec.Selector
}

return labels, nodeSelector
}

func isModuleBuildAndSignCapable(mod *kmmv1beta1.Module) (bool, bool) {
buildCapable := mod.Spec.ModuleLoader.Container.Build != nil
signCapable := mod.Spec.ModuleLoader.Container.Sign != nil
Expand All @@ -412,19 +428,23 @@ func isModuleBuildAndSignCapable(mod *kmmv1beta1.Module) (bool, bool) {
return buildCapable, signCapable
}

func getExistingDS(existingDS []appsv1.DaemonSet,
func getExistingDSFromVersion(existingDS []appsv1.DaemonSet,
moduleNamespace string,
moduleName string,
moduleVersion string) *appsv1.DaemonSet {
moduleLoader *kmmv1beta1.ModuleLoaderSpec) (*appsv1.DaemonSet, string) {
version := ""
if moduleLoader != nil {
version = moduleLoader.Container.Version
}

versionLabel := utils.GetDevicePluginVersionLabelName(moduleNamespace, moduleName)
for _, ds := range existingDS {
dsModuleVersion := ds.GetLabels()[versionLabel]
if dsModuleVersion == moduleVersion {
return &ds
if dsModuleVersion == version {
return &ds, version
}
}
return nil
return nil, version
}

func isOlderVersionUnusedDevicePluginDaemonset(ds *appsv1.DaemonSet, moduleVersion string) bool {
Expand Down
83 changes: 66 additions & 17 deletions internal/controllers/device_plugin_reconciler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ var _ = Describe("DevicePluginReconciler_garbageCollect", func() {
Namespace: "namespace",
},
Spec: kmmv1beta1.ModuleSpec{
ModuleLoader: kmmv1beta1.ModuleLoaderSpec{
ModuleLoader: &kmmv1beta1.ModuleLoaderSpec{
Container: kmmv1beta1.ModuleLoaderContainerSpec{
Version: currentModuleVersion,
},
Expand Down Expand Up @@ -298,6 +298,23 @@ var _ = Describe("DevicePluginReconciler_garbageCollect", func() {
err := dprh.garbageCollect(context.Background(), mod, existingDS)
Expect(err).To(HaveOccurred())
})

It("should pass if moduleLoader is not defined", func() {
modWithoutModuleLoader := mod
modWithoutModuleLoader.Spec.ModuleLoader = nil
deleteDS := appsv1.DaemonSet{
ObjectMeta: metav1.ObjectMeta{
Name: "devicePlugin",
Namespace: "namespace",
Labels: map[string]string{constants.ModuleNameLabel: mod.Name, devicePluginVersionLabel: "formerVersion"},
},
}

existingDS := []appsv1.DaemonSet{deleteDS}

err := dprh.garbageCollect(context.Background(), modWithoutModuleLoader, existingDS)
Expect(err).ToNot(HaveOccurred())
})
})

var _ = Describe("DevicePluginReconciler_handleModuleDeletion", func() {
Expand Down Expand Up @@ -365,9 +382,20 @@ var _ = Describe("DevicePluginReconciler_setKMMOMetrics", func() {
Name: "moduleName",
Namespace: "namespace",
},
Spec: kmmv1beta1.ModuleSpec{
ModuleLoader: &kmmv1beta1.ModuleLoaderSpec{},
},
}
mod2 := kmmv1beta1.Module{
Spec: kmmv1beta1.ModuleSpec{
ModuleLoader: &kmmv1beta1.ModuleLoaderSpec{},
},
}
mod3 := kmmv1beta1.Module{
Spec: kmmv1beta1.ModuleSpec{
ModuleLoader: &kmmv1beta1.ModuleLoaderSpec{},
},
}
mod2 := kmmv1beta1.Module{}
mod3 := kmmv1beta1.Module{}
numBuild := 0
numSign := 0
numDevicePlugin := 0
Expand Down Expand Up @@ -453,7 +481,11 @@ var _ = Describe("DevicePluginReconciler_moduleUpdateDevicePluginStatus", func()
ctx := context.Background()

It("device plugin not defined in the module", func() {
mod := kmmv1beta1.Module{}
mod := kmmv1beta1.Module{
Spec: kmmv1beta1.ModuleSpec{
ModuleLoader: &kmmv1beta1.ModuleLoaderSpec{},
},
}
err := dprh.moduleUpdateDevicePluginStatus(ctx, &mod, nil)
Expect(err).NotTo(HaveOccurred())
})
Expand Down Expand Up @@ -527,8 +559,13 @@ var _ = Describe("DevicePluginReconciler_setDevicePluginAsDesired", func() {

It("should return an error if DevicePlugin not set in the Spec", func() {
ds := appsv1.DaemonSet{}
mod := kmmv1beta1.Module{
Spec: kmmv1beta1.ModuleSpec{
ModuleLoader: &kmmv1beta1.ModuleLoaderSpec{},
},
}
Expect(
dsc.setDevicePluginAsDesired(context.Background(), &ds, &kmmv1beta1.Module{}),
dsc.setDevicePluginAsDesired(context.Background(), &ds, &mod),
).To(
HaveOccurred(),
)
Expand Down Expand Up @@ -563,7 +600,7 @@ var _ = Describe("DevicePluginReconciler_setDevicePluginAsDesired", func() {
Namespace: namespace,
},
Spec: kmmv1beta1.ModuleSpec{
ModuleLoader: kmmv1beta1.ModuleLoaderSpec{
ModuleLoader: &kmmv1beta1.ModuleLoaderSpec{
Container: kmmv1beta1.ModuleLoaderContainerSpec{
Version: "some version",
},
Expand All @@ -589,7 +626,7 @@ var _ = Describe("DevicePluginReconciler_setDevicePluginAsDesired", func() {
Expect(ds.GetLabels()).Should(HaveKeyWithValue(versionLabel, "some version"))
})

It("should work as expected", func() {
DescribeTable("should work as expected", func(moduleLoader *kmmv1beta1.ModuleLoaderSpec, expectedNodeSelector map[string]string) {
const (
dsName = "ds-name"
serviceAccountName = "some-service-account"
Expand Down Expand Up @@ -646,6 +683,7 @@ var _ = Describe("DevicePluginReconciler_setDevicePluginAsDesired", func() {
Namespace: namespace,
},
Spec: kmmv1beta1.ModuleSpec{
ModuleLoader: moduleLoader,
DevicePlugin: &kmmv1beta1.DevicePluginSpec{
Container: kmmv1beta1.DevicePluginContainerSpec{
Args: args,
Expand Down Expand Up @@ -722,10 +760,8 @@ var _ = Describe("DevicePluginReconciler_setDevicePluginAsDesired", func() {
},
},
},
ImagePullSecrets: []v1.LocalObjectReference{repoSecret},
NodeSelector: map[string]string{
utils.GetKernelModuleReadyNodeLabel(mod.Namespace, mod.Name): "",
},
ImagePullSecrets: []v1.LocalObjectReference{repoSecret},
NodeSelector: expectedNodeSelector,
PriorityClassName: "system-node-critical",
ServiceAccountName: serviceAccountName,
Volumes: []v1.Volume{
Expand All @@ -750,10 +786,19 @@ var _ = Describe("DevicePluginReconciler_setDevicePluginAsDesired", func() {
).To(
BeTrue(), cmp.Diff(expected, ds),
)
})
},
Entry("moduleLoader is nil",
nil,
map[string]string{"has-feature-x": "true"},
),
Entry("moduleLoader is defined",
&kmmv1beta1.ModuleLoaderSpec{},
map[string]string{utils.GetKernelModuleReadyNodeLabel(namespace, moduleName): ""},
),
)
})

var _ = Describe("DevicePluginReconciler_getExistingDS", func() {
var _ = Describe("DevicePluginReconciler_getExistingDSFromVersion", func() {
const (
moduleName = "moduleName"
moduleNamespace = "moduleNamespace"
Expand All @@ -771,22 +816,26 @@ var _ = Describe("DevicePluginReconciler_getExistingDS", func() {

It("various scenarios", func() {
By("empty daemonset list")
res := getExistingDS(nil, moduleNamespace, moduleName, moduleVersion)
res, version := getExistingDSFromVersion(nil, moduleNamespace, moduleName, &kmmv1beta1.ModuleLoaderSpec{Container: kmmv1beta1.ModuleLoaderContainerSpec{Version: moduleVersion}})
Expect(res).To(BeNil())
Expect(version).To(Equal(moduleVersion))

By("device plugin, module version equal")
ds.SetLabels(devicePluginLabels)
res = getExistingDS([]appsv1.DaemonSet{ds}, moduleNamespace, moduleName, moduleVersion)
res, version = getExistingDSFromVersion([]appsv1.DaemonSet{ds}, moduleNamespace, moduleName, &kmmv1beta1.ModuleLoaderSpec{Container: kmmv1beta1.ModuleLoaderContainerSpec{Version: moduleVersion}})
Expect(res).To(Equal(&ds))
Expect(version).To(Equal(moduleVersion))

By("device plugin, module version not equal")
res = getExistingDS([]appsv1.DaemonSet{ds}, moduleNamespace, moduleName, "some version")
res, version = getExistingDSFromVersion([]appsv1.DaemonSet{ds}, moduleNamespace, moduleName, &kmmv1beta1.ModuleLoaderSpec{Container: kmmv1beta1.ModuleLoaderContainerSpec{Version: "some-version"}})
Expect(res).To(BeNil())
Expect(version).To(Equal("some-version"))

By("device plugin, module version label missing, and module version parameter is empty")
ds.SetLabels(map[string]string{})
res = getExistingDS([]appsv1.DaemonSet{ds}, moduleNamespace, moduleName, "")
res, version = getExistingDSFromVersion([]appsv1.DaemonSet{ds}, moduleNamespace, moduleName, &kmmv1beta1.ModuleLoaderSpec{Container: kmmv1beta1.ModuleLoaderContainerSpec{Version: ""}})
Expect(res).To(Equal(&ds))
Expect(version).To(Equal(""))
})
})

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ var _ = Describe("ManagedClusterModuleReconciler_Reconcile", func() {
},
Spec: v1beta1.ManagedClusterModuleSpec{
ModuleSpec: kmmv1beta1.ModuleSpec{
ModuleLoader: kmmv1beta1.ModuleLoaderSpec{
ModuleLoader: &kmmv1beta1.ModuleLoaderSpec{
Container: kmmv1beta1.ModuleLoaderContainerSpec{
Build: &kmmv1beta1.Build{},
},
Expand Down
5 changes: 5 additions & 0 deletions internal/controllers/module_reconciler.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,11 @@ func (mr *ModuleReconciler) Reconcile(ctx context.Context, mod *kmmv1beta1.Modul
return ctrl.Result{}, fmt.Errorf("failed to set finalizer on Module %s/%s: %v", mod.Namespace, mod.Name, err)
}

if mod.Spec.ModuleLoader == nil {
logger.Info("ModuleLoader is not defined, skipping loading kernel module")
return ctrl.Result{}, nil
}

// get nodes targeted by selector
targetedNodes, err := mr.nodeAPI.GetNodesListBySelector(ctx, mod.Spec.Selector, mod.Spec.Tolerations)
if err != nil {
Expand Down
Loading