osbuild2: add support for org.osbuild.dracut.conf stage

Add support for the `org.osbuild.dracut.conf` osbuild stage [1], which
allows one to configure dracut by creating configuration files.

Add unit test cases for the newly added stage.

[1] https://github.com/osbuild/osbuild/pull/688

Signed-off-by: Tomas Hozza <thozza@redhat.com>
This commit is contained in:
Tomas Hozza 2021-06-30 12:12:20 +02:00 committed by Ondřej Budai
parent c0e8d4bdc4
commit 92719e05a2
4 changed files with 187 additions and 0 deletions

View file

@ -0,0 +1,109 @@
package osbuild2
import (
"encoding/json"
"fmt"
)
type DracutConfStageOptions struct {
ConfigFiles map[string]DracutConfigFile `json:"configuration_files,omitempty"`
}
func (DracutConfStageOptions) isStageOptions() {}
// Dracut.conf stage creates dracut configuration files under /usr/lib/dracut/dracut.conf.d/
func NewDracutConfStageOptions(options *DracutConfStageOptions) *Stage {
return &Stage{
Type: "org.osbuild.dracut.conf",
Options: options,
}
}
type DracutConfigFile struct {
// Compression method for the initramfs
Compress string `json:"compress,omitempty"`
// Exact list of dracut modules to use
Modules []string `json:"dracutmodules,omitempty"`
// Additional dracut modules to include
AddModules []string `json:"add_dracutmodules,omitempty"`
// Dracut modules to not include
OmitModules []string `json:"omit_dracutmodules,omitempty"`
// Kernel modules to exclusively include
Drivers []string `json:"drivers,omitempty"`
// Add a specific kernel module
AddDrivers []string `json:"add_drivers,omitempty"`
// Add driver and ensure that they are tried to be loaded
ForceDrivers []string `json:"force_drivers,omitempty"`
// Kernel filesystem modules to exclusively include
Filesystems []string `json:"filesystems,omitempty"`
// Install the specified files
Install []string `json:"install_items,omitempty"`
// Combine early microcode with the initramfs
EarlyMicrocode *bool `json:"early_microcode,omitempty"`
// Create reproducible images
Reproducible *bool `json:"reproducible,omitempty"`
}
// Unexported struct for use in DracutConfigFile MarshalJSON() to prevent recursion
type dracutConfigFile struct {
// Compression method for the initramfs
Compress string `json:"compress,omitempty"`
// Exact list of dracut modules to use
Modules []string `json:"dracutmodules,omitempty"`
// Additional dracut modules to include
AddModules []string `json:"add_dracutmodules,omitempty"`
// Dracut modules to not include
OmitModules []string `json:"omit_dracutmodules,omitempty"`
// Kernel modules to exclusively include
Drivers []string `json:"drivers,omitempty"`
// Add a specific kernel module
AddDrivers []string `json:"add_drivers,omitempty"`
// Add driver and ensure that they are tried to be loaded
ForceDrivers []string `json:"force_drivers,omitempty"`
// Kernel filesystem modules to exclusively include
Filesystems []string `json:"filesystems,omitempty"`
// Install the specified files
Install []string `json:"install_items,omitempty"`
// Combine early microcode with the initramfs
EarlyMicrocode *bool `json:"early_microcode,omitempty"`
// Create reproducible images
Reproducible *bool `json:"reproducible,omitempty"`
}
func (c DracutConfigFile) MarshalJSON() ([]byte, error) {
if c.Compress == "" &&
len(c.Modules) == 0 &&
len(c.AddModules) == 0 &&
len(c.OmitModules) == 0 &&
len(c.Drivers) == 0 &&
len(c.AddDrivers) == 0 &&
len(c.ForceDrivers) == 0 &&
len(c.Filesystems) == 0 &&
len(c.Install) == 0 &&
c.EarlyMicrocode == nil &&
c.Reproducible == nil {
return nil, fmt.Errorf("at least one dracut configuration option must be specified")
}
configFile := dracutConfigFile(c)
return json.Marshal(configFile)
}

View file

@ -0,0 +1,39 @@
package osbuild2
import (
"encoding/json"
"testing"
"github.com/stretchr/testify/assert"
)
func TestNewDracutConfStage(t *testing.T) {
expectedStage := &Stage{
Type: "org.osbuild.dracut.conf",
Options: &DracutConfStageOptions{},
}
actualStage := NewDracutConfStageOptions(&DracutConfStageOptions{})
assert.Equal(t, expectedStage, actualStage)
}
func TestDracutConfStage_MarshalJSON_Invalid(t *testing.T) {
tests := []struct {
name string
options DracutConfStageOptions
}{
{
name: "no-options-in-config",
options: DracutConfStageOptions{
ConfigFiles: map[string]DracutConfigFile{
"testing.conf": {},
},
},
},
}
for idx, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gotBytes, err := json.Marshal(tt.options)
assert.NotNilf(t, err, "json.Marshal() didn't return an error, but %s [idx: %d]", string(gotBytes), idx)
})
}
}

View file

@ -87,6 +87,8 @@ func (stage *Stage) UnmarshalJSON(data []byte) error {
options = new(TimezoneStageOptions)
case "org.osbuild.chrony":
options = new(ChronyStageOptions)
case "org.osbuild.dracut.conf":
options = new(DracutConfStageOptions)
case "org.osbuild.keymap":
options = new(KeymapStageOptions)
case "org.osbuild.modprobe":

View file

@ -62,6 +62,43 @@ func TestStage_UnmarshalJSON(t *testing.T) {
data: []byte(`{"type":"org.osbuild.chrony","options":{"timeservers":null}}`),
},
},
{
name: "dracut.conf",
fields: fields{
Type: "org.osbuild.dracut.conf",
Options: &DracutConfStageOptions{},
},
args: args{
data: []byte(`{"type":"org.osbuild.dracut.conf","options":{}}`),
},
},
{
name: "dracut.conf-data",
fields: fields{
Type: "org.osbuild.dracut.conf",
Options: &DracutConfStageOptions{
ConfigFiles: map[string]DracutConfigFile{
"sgdisk.conf": {
Install: []string{"sgdisk"},
},
"testing.conf": {
Compress: "xz",
AddModules: []string{"floppy"},
OmitModules: []string{"nouveau"},
AddDrivers: []string{"driver1"},
ForceDrivers: []string{"driver2"},
Filesystems: []string{"ext4"},
Install: []string{"file1"},
EarlyMicrocode: common.BoolToPtr(false),
Reproducible: common.BoolToPtr(false),
},
},
},
},
args: args{
data: []byte(`{"type":"org.osbuild.dracut.conf","options":{"configuration_files":{"sgdisk.conf":{"install_items":["sgdisk"]},"testing.conf":{"compress":"xz","add_dracutmodules":["floppy"],"omit_dracutmodules":["nouveau"],"add_drivers":["driver1"],"force_drivers":["driver2"],"filesystems":["ext4"],"install_items":["file1"],"early_microcode":false,"reproducible":false}}}}`),
},
},
{
name: "firewall",
fields: fields{