feat: provide a way to load Linux kernel modules

Fixes #4693

Machine configuration change plus very simple controllers which transform
config into the module spec and finally load modules.

There's no support for advanced features like module params and aliases,
but we can add it later.

Signed-off-by: Andrey Smirnov <andrey.smirnov@talos-systems.com>
This commit is contained in:
Andrey Smirnov 2021-12-23 23:55:26 +03:00
parent 4d1514add6
commit 3623da136b
No known key found for this signature in database
GPG Key ID: 7B26396447AB6DFD
21 changed files with 623 additions and 9 deletions

1
go.mod
View File

@ -73,6 +73,7 @@ require (
github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417
github.com/packethost/packngo v0.20.0
github.com/pin/tftp v2.1.0+incompatible
github.com/pmorjan/kmod v1.0.0
github.com/prometheus/procfs v0.7.3
github.com/rivo/tview v0.0.0-20211202162923-2a6de950f73b
github.com/rs/xid v1.3.0

2
go.sum
View File

@ -976,6 +976,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmorjan/kmod v1.0.0 h1:vzC1NAs8Ot25gFWkrN2jAy9GzDrYkTXlucr378FhZ7k=
github.com/pmorjan/kmod v1.0.0/go.mod h1:8aTvlzx0I6TjLFDiaRL0VbSrsQkjMjA9wH08gYAkvEU=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=
github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA=

View File

@ -28,7 +28,7 @@ const (
fsFileMax = "fs.file-max"
)
type KernelParamSuite struct {
type RuntimeSuite struct {
suite.Suite
state state.State
@ -40,7 +40,7 @@ type KernelParamSuite struct {
ctxCancel context.CancelFunc
}
func (suite *KernelParamSuite) SetupTest() {
func (suite *RuntimeSuite) SetupTest() {
suite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 3*time.Minute)
suite.state = state.WrapCore(namespaced.NewState(inmem.Build))
@ -53,7 +53,7 @@ func (suite *KernelParamSuite) SetupTest() {
suite.Require().NoError(err)
}
func (suite *KernelParamSuite) startRuntime() {
func (suite *RuntimeSuite) startRuntime() {
suite.wg.Add(1)
go func() {
@ -63,7 +63,7 @@ func (suite *KernelParamSuite) startRuntime() {
}()
}
func (suite *KernelParamSuite) assertResource(md resource.Metadata, compare func(res resource.Resource) bool) func() error {
func (suite *RuntimeSuite) assertResource(md resource.Metadata, compare func(res resource.Resource) bool) func() error {
return func() error {
r, err := suite.state.Get(suite.ctx, md)
if err != nil {
@ -82,7 +82,7 @@ func (suite *KernelParamSuite) assertResource(md resource.Metadata, compare func
}
}
func (suite *KernelParamSuite) TearDownTest() {
func (suite *RuntimeSuite) TearDownTest() {
suite.T().Log("tear down")
suite.ctxCancel()

View File

@ -0,0 +1,104 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package runtime
import (
"context"
"fmt"
"github.com/AlekSi/pointer"
"github.com/cosi-project/runtime/pkg/controller"
"github.com/cosi-project/runtime/pkg/resource"
"github.com/cosi-project/runtime/pkg/state"
"go.uber.org/zap"
"github.com/talos-systems/talos/pkg/machinery/resources/config"
"github.com/talos-systems/talos/pkg/machinery/resources/runtime"
)
// KernelModuleConfigController watches v1alpha1.Config, creates/updates/deletes kernel module specs.
type KernelModuleConfigController struct{}
// Name implements controller.Controller interface.
func (ctrl *KernelModuleConfigController) Name() string {
return "runtime.KernelModuleConfigController"
}
// Inputs implements controller.Controller interface.
func (ctrl *KernelModuleConfigController) Inputs() []controller.Input {
return []controller.Input{
{
Namespace: config.NamespaceName,
Type: config.MachineConfigType,
ID: pointer.ToString(config.V1Alpha1ID),
},
}
}
// Outputs implements controller.Controller interface.
func (ctrl *KernelModuleConfigController) Outputs() []controller.Output {
return []controller.Output{
{
Type: runtime.KernelModuleSpecType,
Kind: controller.OutputShared,
},
}
}
// Run implements controller.Controller interface.
//
//nolint:gocyclo
func (ctrl *KernelModuleConfigController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {
for {
select {
case <-ctx.Done():
return nil
case <-r.EventCh():
cfg, err := r.Get(ctx, resource.NewMetadata(config.NamespaceName, config.MachineConfigType, config.V1Alpha1ID, resource.VersionUndefined))
if err != nil {
if !state.IsNotFoundError(err) {
return fmt.Errorf("error getting config: %w", err)
}
}
touchedIDs := make(map[resource.ID]struct{})
if cfg != nil {
c, _ := cfg.(*config.MachineConfig) //nolint:errcheck
for _, module := range c.Config().Machine().Kernel().Modules() {
touchedIDs[module.Name()] = struct{}{}
item := runtime.NewKernelModuleSpec(runtime.NamespaceName, module.Name())
if err = r.Modify(ctx, item, func(res resource.Resource) error {
res.(*runtime.KernelModuleSpec).TypedSpec().Name = module.Name()
return nil
}); err != nil {
return err
}
}
}
// list keys for cleanup
list, err := r.List(ctx, resource.NewMetadata(runtime.NamespaceName, runtime.KernelModuleSpecType, "", resource.VersionUndefined))
if err != nil {
return fmt.Errorf("error listing resources: %w", err)
}
for _, res := range list.Items {
if res.Metadata().Owner() != ctrl.Name() {
continue
}
if _, ok := touchedIDs[res.Metadata().ID()]; !ok {
if err = r.Destroy(ctx, res.Metadata()); err != nil {
return fmt.Errorf("error cleaning up specs: %w", err)
}
}
}
}
}
}

View File

@ -0,0 +1,98 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package runtime_test
import (
"fmt"
"testing"
"time"
"github.com/cosi-project/runtime/pkg/resource"
"github.com/cosi-project/runtime/pkg/state"
"github.com/stretchr/testify/suite"
"github.com/talos-systems/go-retry/retry"
runtimecontrollers "github.com/talos-systems/talos/internal/app/machined/pkg/controllers/runtime"
"github.com/talos-systems/talos/pkg/machinery/config/types/v1alpha1"
"github.com/talos-systems/talos/pkg/machinery/resources/config"
runtimeresource "github.com/talos-systems/talos/pkg/machinery/resources/runtime"
)
type KernelModuleConfigSuite struct {
RuntimeSuite
}
func (suite *KernelModuleConfigSuite) TestReconcileConfig() {
suite.Require().NoError(suite.runtime.RegisterController(&runtimecontrollers.KernelModuleConfigController{}))
suite.startRuntime()
cfg := config.NewMachineConfig(&v1alpha1.Config{
ConfigVersion: "v1alpha1",
MachineConfig: &v1alpha1.MachineConfig{
MachineKernel: &v1alpha1.KernelConfig{
KernelModules: []*v1alpha1.KernelModuleConfig{
{
ModuleName: "brtfs",
},
{
ModuleName: "e1000",
},
},
},
},
ClusterConfig: &v1alpha1.ClusterConfig{},
})
suite.Require().NoError(suite.state.Create(suite.ctx, cfg))
specMD := resource.NewMetadata(runtimeresource.NamespaceName, runtimeresource.KernelModuleSpecType, "e1000", resource.VersionUndefined)
suite.Assert().NoError(retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
suite.assertResource(
specMD,
func(res resource.Resource) bool {
return res.(*runtimeresource.KernelModuleSpec).TypedSpec().Name == "e1000"
},
),
))
cfg = config.NewMachineConfig(&v1alpha1.Config{
ConfigVersion: "v1alpha1",
MachineConfig: &v1alpha1.MachineConfig{
MachineKernel: nil,
},
ClusterConfig: &v1alpha1.ClusterConfig{},
})
old := cfg.Metadata().Version()
cfg.Metadata().BumpVersion()
suite.Require().NoError(suite.state.Update(suite.ctx, old, cfg))
var err error
// wait for the resource to be removed
suite.Assert().NoError(retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
func() error {
for _, md := range []resource.Metadata{specMD} {
_, err = suite.state.Get(suite.ctx, md)
if err != nil {
if state.IsNotFoundError(err) {
return nil
}
return err
}
}
return retry.ExpectedError(fmt.Errorf("resource still exists"))
},
))
}
func TestKernelModuleConfigSuite(t *testing.T) {
suite.Run(t, new(KernelModuleConfigSuite))
}

View File

@ -0,0 +1,70 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package runtime
import (
"context"
"fmt"
"github.com/cosi-project/runtime/pkg/controller"
"github.com/cosi-project/runtime/pkg/resource"
"github.com/pmorjan/kmod"
"go.uber.org/zap"
"github.com/talos-systems/talos/pkg/machinery/resources/runtime"
)
// KernelModuleSpecController watches KernelModuleSpecs, sets/resets kernel params.
type KernelModuleSpecController struct{}
// Name implements controller.Controller interface.
func (ctrl *KernelModuleSpecController) Name() string {
return "runtime.KernelModuleSpecController"
}
// Inputs implements controller.Controller interface.
func (ctrl *KernelModuleSpecController) Inputs() []controller.Input {
return []controller.Input{
{
Namespace: runtime.NamespaceName,
Type: runtime.KernelModuleSpecType,
Kind: controller.InputStrong,
},
}
}
// Outputs implements controller.Controller interface.
func (ctrl *KernelModuleSpecController) Outputs() []controller.Output {
return nil
}
// Run implements controller.Controller interface.
func (ctrl *KernelModuleSpecController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {
manager, err := kmod.New()
if err != nil {
return fmt.Errorf("error initializing kmod manager")
}
for {
select {
case <-ctx.Done():
return nil
case <-r.EventCh():
modules, err := r.List(ctx, resource.NewMetadata(runtime.NamespaceName, runtime.KernelModuleSpecType, "", resource.VersionUndefined))
if err != nil {
return err
}
// note: this code doesn't support module unloading in any way for now
for _, res := range modules.Items {
module := res.(*runtime.KernelModuleSpec).TypedSpec()
if err = manager.Load(module.Name, "", 0); err != nil {
return fmt.Errorf("error loading module %q: %w", module.Name, err)
}
}
}
}
}

View File

@ -20,7 +20,7 @@ import (
)
type KernelParamConfigSuite struct {
KernelParamSuite
RuntimeSuite
}
func (suite *KernelParamConfigSuite) TestReconcileConfig() {

View File

@ -19,7 +19,7 @@ import (
)
type KernelParamDefaultsSuite struct {
KernelParamSuite
RuntimeSuite
}
func getParams(mode runtime.Mode) []*kernel.Param {

View File

@ -22,7 +22,7 @@ import (
)
type KernelParamSpecSuite struct {
KernelParamSuite
RuntimeSuite
}
func (suite *KernelParamSpecSuite) TestParamsSynced() {

View File

@ -100,6 +100,7 @@ func (r *Runtime) CanApplyImmediate(cfg config.Provider) error {
// * .machine.logging
// * .machine.controlplane
// * .machine.kubelet
// * .machine.kernel
newConfig.ConfigDebug = currentConfig.ConfigDebug
newConfig.ClusterConfig = currentConfig.ClusterConfig
@ -111,6 +112,7 @@ func (r *Runtime) CanApplyImmediate(cfg config.Provider) error {
newConfig.MachineConfig.MachineLogging = currentConfig.MachineConfig.MachineLogging
newConfig.MachineConfig.MachineControlPlane = currentConfig.MachineConfig.MachineControlPlane
newConfig.MachineConfig.MachineKubelet = currentConfig.MachineConfig.MachineKubelet
newConfig.MachineConfig.MachineKernel = currentConfig.MachineConfig.MachineKernel
}
if !reflect.DeepEqual(currentConfig, newConfig) {

View File

@ -184,6 +184,8 @@ func (ctrl *Controller) Run(ctx context.Context, drainer *runtime.Drainer) error
Cmdline: procfs.ProcCmdline(),
Drainer: drainer,
},
&runtimecontrollers.KernelModuleConfigController{},
&runtimecontrollers.KernelModuleSpecController{},
&runtimecontrollers.KernelParamConfigController{},
&runtimecontrollers.KernelParamDefaultsController{
V1Alpha1Mode: ctrl.v1alpha1Runtime.State().Platform().Mode(),

View File

@ -124,6 +124,7 @@ func NewState() (*State, error) {
&network.TimeServerSpec{},
&perf.CPU{},
&perf.Memory{},
&runtime.KernelModuleSpec{},
&runtime.KernelParamSpec{},
&runtime.KernelParamDefaultSpec{},
&runtime.KernelParamStatus{},

View File

@ -52,6 +52,7 @@ type MachineConfig interface {
Features() Features
Udev() UdevConfig
Logging() Logging
Kernel() Kernel
}
// Disk represents the options available for partitioning, formatting, and
@ -517,3 +518,13 @@ type LoggingDestination interface {
Endpoint() *url.URL
Format() string
}
// Kernel describes Talos Linux kernel configuration.
type Kernel interface {
Modules() []KernelModule
}
// KernelModule describes Linux module to load.
type KernelModule interface {
Name() string
}

View File

@ -0,0 +1,28 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package v1alpha1
import (
"github.com/talos-systems/talos/pkg/machinery/config"
)
// Modules implements config.Kernel interface.
func (kc *KernelConfig) Modules() []config.KernelModule {
if kc.KernelModules == nil {
return nil
}
res := make([]config.KernelModule, len(kc.KernelModules))
for i, m := range kc.KernelModules {
res[i] = config.KernelModule(m)
}
return res
}
// Name implements config.KernelModule interface.
func (kmc *KernelModuleConfig) Name() string {
return kmc.ModuleName
}

View File

@ -333,6 +333,15 @@ func (m *MachineConfig) Logging() config.Logging {
return m.MachineLogging
}
// Kernel implements the config.MachineConfig interface.
func (m *MachineConfig) Kernel() config.Kernel {
if m.MachineKernel == nil {
return &KernelConfig{}
}
return m.MachineKernel
}
// Image implements the config.Provider interface.
func (k *KubeletConfig) Image() string {
image := k.KubeletImage

View File

@ -496,6 +496,14 @@ metadata:
},
},
}
machineKernelExample = &KernelConfig{
KernelModules: []*KernelModuleConfig{
{
ModuleName: "brtfs",
},
},
}
)
// Config defines the v1alpha1 configuration file.
@ -694,6 +702,11 @@ type MachineConfig struct {
// examples:
// - value: machineLoggingExample
MachineLogging *LoggingConfig `yaml:"logging,omitempty"`
// description: |
// Configures the kernel.
// examples:
// - value: machineKernelExample
MachineKernel *KernelConfig `yaml:"kernel,omitempty"`
}
// ClusterConfig represents the cluster-wide config values.
@ -2105,3 +2118,17 @@ type LoggingDestination struct {
// - json_lines
LoggingFormat string `yaml:"format"`
}
// KernelConfig struct configures Talos Linux kernel.
type KernelConfig struct {
// description: |
// Kernel modules to load.
KernelModules []*KernelModuleConfig `yaml:"modules,omitempty"`
}
// KernelModuleConfig struct configures Linux kernel modules to load.
type KernelModuleConfig struct {
// description: |
// Module name.
ModuleName string `yaml:"name"`
}

View File

@ -73,6 +73,8 @@ var (
UdevConfigDoc encoder.Doc
LoggingConfigDoc encoder.Doc
LoggingDestinationDoc encoder.Doc
KernelConfigDoc encoder.Doc
KernelModuleConfigDoc encoder.Doc
)
func init() {
@ -134,7 +136,7 @@ func init() {
FieldName: "machine",
},
}
MachineConfigDoc.Fields = make([]encoder.Doc, 18)
MachineConfigDoc.Fields = make([]encoder.Doc, 19)
MachineConfigDoc.Fields[0].Name = "type"
MachineConfigDoc.Fields[0].Type = "string"
MachineConfigDoc.Fields[0].Note = ""
@ -275,6 +277,13 @@ func init() {
MachineConfigDoc.Fields[17].Comments[encoder.LineComment] = "Configures the logging system."
MachineConfigDoc.Fields[17].AddExample("", machineLoggingExample)
MachineConfigDoc.Fields[18].Name = "kernel"
MachineConfigDoc.Fields[18].Type = "KernelConfig"
MachineConfigDoc.Fields[18].Note = ""
MachineConfigDoc.Fields[18].Description = "Configures the kernel."
MachineConfigDoc.Fields[18].Comments[encoder.LineComment] = "Configures the kernel."
MachineConfigDoc.Fields[18].AddExample("", machineKernelExample)
ClusterConfigDoc.Type = "ClusterConfig"
ClusterConfigDoc.Comments[encoder.LineComment] = "ClusterConfig represents the cluster-wide config values."
@ -2299,6 +2308,40 @@ func init() {
LoggingDestinationDoc.Fields[1].Values = []string{
"json_lines",
}
KernelConfigDoc.Type = "KernelConfig"
KernelConfigDoc.Comments[encoder.LineComment] = "KernelConfig struct configures Talos Linux kernel."
KernelConfigDoc.Description = "KernelConfig struct configures Talos Linux kernel."
KernelConfigDoc.AddExample("", machineKernelExample)
KernelConfigDoc.AppearsIn = []encoder.Appearance{
{
TypeName: "MachineConfig",
FieldName: "kernel",
},
}
KernelConfigDoc.Fields = make([]encoder.Doc, 1)
KernelConfigDoc.Fields[0].Name = "modules"
KernelConfigDoc.Fields[0].Type = "[]KernelModuleConfig"
KernelConfigDoc.Fields[0].Note = ""
KernelConfigDoc.Fields[0].Description = "Kernel modules to load."
KernelConfigDoc.Fields[0].Comments[encoder.LineComment] = "Kernel modules to load."
KernelModuleConfigDoc.Type = "KernelModuleConfig"
KernelModuleConfigDoc.Comments[encoder.LineComment] = "KernelModuleConfig struct configures Linux kernel modules to load."
KernelModuleConfigDoc.Description = "KernelModuleConfig struct configures Linux kernel modules to load."
KernelModuleConfigDoc.AppearsIn = []encoder.Appearance{
{
TypeName: "KernelConfig",
FieldName: "modules",
},
}
KernelModuleConfigDoc.Fields = make([]encoder.Doc, 1)
KernelModuleConfigDoc.Fields[0].Name = "name"
KernelModuleConfigDoc.Fields[0].Type = "string"
KernelModuleConfigDoc.Fields[0].Note = ""
KernelModuleConfigDoc.Fields[0].Description = "Module name."
KernelModuleConfigDoc.Fields[0].Comments[encoder.LineComment] = "Module name."
}
func (_ Config) Doc() *encoder.Doc {
@ -2545,6 +2588,14 @@ func (_ LoggingDestination) Doc() *encoder.Doc {
return &LoggingDestinationDoc
}
func (_ KernelConfig) Doc() *encoder.Doc {
return &KernelConfigDoc
}
func (_ KernelModuleConfig) Doc() *encoder.Doc {
return &KernelModuleConfigDoc
}
// GetConfigurationDoc returns documentation for the file ./v1alpha1_types_doc.go.
func GetConfigurationDoc() *encoder.FileDoc {
return &encoder.FileDoc{
@ -2612,6 +2663,8 @@ func GetConfigurationDoc() *encoder.FileDoc {
&UdevConfigDoc,
&LoggingConfigDoc,
&LoggingDestinationDoc,
&KernelConfigDoc,
&KernelModuleConfigDoc,
},
}
}

View File

@ -833,6 +833,49 @@ func (in *InstallDiskSizeMatcher) DeepCopy() *InstallDiskSizeMatcher {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *KernelConfig) DeepCopyInto(out *KernelConfig) {
*out = *in
if in.KernelModules != nil {
in, out := &in.KernelModules, &out.KernelModules
*out = make([]*KernelModuleConfig, len(*in))
for i := range *in {
if (*in)[i] != nil {
in, out := &(*in)[i], &(*out)[i]
*out = new(KernelModuleConfig)
**out = **in
}
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KernelConfig.
func (in *KernelConfig) DeepCopy() *KernelConfig {
if in == nil {
return nil
}
out := new(KernelConfig)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *KernelModuleConfig) DeepCopyInto(out *KernelModuleConfig) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KernelModuleConfig.
func (in *KernelModuleConfig) DeepCopy() *KernelModuleConfig {
if in == nil {
return nil
}
out := new(KernelModuleConfig)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *KubeletConfig) DeepCopyInto(out *KubeletConfig) {
*out = *in
@ -1027,6 +1070,11 @@ func (in *MachineConfig) DeepCopyInto(out *MachineConfig) {
*out = new(LoggingConfig)
(*in).DeepCopyInto(*out)
}
if in.MachineKernel != nil {
in, out := &in.MachineKernel, &out.MachineKernel
*out = new(KernelConfig)
(*in).DeepCopyInto(*out)
}
return
}

View File

@ -0,0 +1,75 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package runtime
import (
"fmt"
"github.com/cosi-project/runtime/pkg/resource"
"github.com/cosi-project/runtime/pkg/resource/meta"
)
// KernelModuleSpecType is type of KernelModuleSpec resource.
const KernelModuleSpecType = resource.Type("KernelModuleSpecs.runtime.talos.dev")
// KernelModuleSpec resource holds information about Linux kernel module to load.
type KernelModuleSpec struct {
md resource.Metadata
spec KernelModuleSpecSpec
}
// KernelModuleSpecSpec describes Linux kernel module to load.
type KernelModuleSpecSpec struct {
Name string `yaml:"string"`
// more options in the future: args, aliases, etc.
}
// NewKernelModuleSpec initializes a KernelModuleSpec resource.
func NewKernelModuleSpec(namespace resource.Namespace, id resource.ID) *KernelModuleSpec {
r := &KernelModuleSpec{
md: resource.NewMetadata(namespace, KernelModuleSpecType, id, resource.VersionUndefined),
spec: KernelModuleSpecSpec{},
}
r.md.BumpVersion()
return r
}
// Metadata implements resource.Resource.
func (r *KernelModuleSpec) Metadata() *resource.Metadata {
return &r.md
}
// Spec implements resource.Resource.
func (r *KernelModuleSpec) Spec() interface{} {
return r.spec
}
func (r *KernelModuleSpec) String() string {
return fmt.Sprintf("runtime.KernelModuleSpec.(%q)", r.md.ID())
}
// DeepCopy implements resource.Resource.
func (r *KernelModuleSpec) DeepCopy() resource.Resource {
return &KernelModuleSpec{
md: r.md,
spec: r.spec,
}
}
// ResourceDefinition implements meta.ResourceDefinitionProvider interface.
func (r *KernelModuleSpec) ResourceDefinition() meta.ResourceDefinitionSpec {
return meta.ResourceDefinitionSpec{
Type: KernelModuleSpecType,
Aliases: []resource.Type{"modules"},
DefaultNamespace: NamespaceName,
}
}
// TypedSpec allows to access the KernelModuleSpecSpec with the proper type.
func (r *KernelModuleSpec) TypedSpec() *KernelModuleSpecSpec {
return &r.spec
}

View File

@ -25,6 +25,7 @@ func TestRegisterResource(t *testing.T) {
resourceRegistry := registry.NewResourceRegistry(resources)
for _, resource := range []resource.Resource{
&runtime.KernelModuleSpec{},
&runtime.KernelParamSpec{},
&runtime.KernelParamStatus{},
&runtime.MountStatus{},

View File

@ -815,6 +815,31 @@ logging:
```
</div>
<hr />
<div class="dd">
<code>kernel</code> <i><a href="#kernelconfig">KernelConfig</a></i>
</div>
<div class="dt">
Configures the kernel.
Examples:
``` yaml
kernel:
# Kernel modules to load.
modules:
- name: brtfs # Module name.
```
</div>
<hr />
@ -5851,3 +5876,60 @@ Valid values:
<hr />
## KernelConfig
KernelConfig struct configures Talos Linux kernel.
Appears in:
- <code><a href="#machineconfig">MachineConfig</a>.kernel</code>
``` yaml
# Kernel modules to load.
modules:
- name: brtfs # Module name.
```
<hr />
<div class="dd">
<code>modules</code> <i>[]<a href="#kernelmoduleconfig">KernelModuleConfig</a></i>
</div>
<div class="dt">
Kernel modules to load.
</div>
<hr />
## KernelModuleConfig
KernelModuleConfig struct configures Linux kernel modules to load.
Appears in:
- <code><a href="#kernelconfig">KernelConfig</a>.modules</code>
<hr />
<div class="dd">
<code>name</code> <i>string</i>
</div>
<div class="dt">
Module name.
</div>
<hr />