From eef997102735e958b210110f5a032685a4e8a388 Mon Sep 17 00:00:00 2001 From: Tomas Hozza Date: Fri, 10 Sep 2021 18:52:15 +0200 Subject: [PATCH] osbuild2: add support for `org.osbuild.tuned` stage Add support for a new osbuild stage `org.osbuild.tuned`, for setting TuneD profile. Add unit tests for the new stage. Related to https://github.com/osbuild/osbuild/pull/797. Signed-off-by: Tomas Hozza --- internal/osbuild2/stage.go | 2 + internal/osbuild2/stage_test.go | 12 ++++++ internal/osbuild2/tuned_stage.go | 40 ++++++++++++++++++ internal/osbuild2/tuned_stage_test.go | 59 +++++++++++++++++++++++++++ 4 files changed, 113 insertions(+) create mode 100644 internal/osbuild2/tuned_stage.go create mode 100644 internal/osbuild2/tuned_stage_test.go diff --git a/internal/osbuild2/stage.go b/internal/osbuild2/stage.go index 578456039..bc88dbdf4 100644 --- a/internal/osbuild2/stage.go +++ b/internal/osbuild2/stage.go @@ -122,6 +122,8 @@ func (stage *Stage) UnmarshalJSON(data []byte) error { options = new(PamLimitsConfStageOptions) case "org.osbuild.truncate": options = new(TruncateStageOptions) + case "org.osbuild.tuned": + options = new(TunedStageOptions) case "org.osbuild.sfdisk": options = new(SfdiskStageOptions) case "org.osbuild.copy": diff --git a/internal/osbuild2/stage_test.go b/internal/osbuild2/stage_test.go index 5c3556ff1..0789fcb34 100644 --- a/internal/osbuild2/stage_test.go +++ b/internal/osbuild2/stage_test.go @@ -378,6 +378,18 @@ func TestStage_UnmarshalJSON(t *testing.T) { data: []byte(`{"type":"org.osbuild.pam.limits.conf","options":{"filename":"example.conf","config":[{"domain":"user1","type":"hard","item":"nofile","value":-1}]}}`), }, }, + { + name: "tuned", + fields: fields{ + Type: "org.osbuild.tuned", + Options: &TunedStageOptions{ + Profiles: []string{"sap-hana"}, + }, + }, + args: args{ + data: []byte(`{"type":"org.osbuild.tuned","options":{"profiles":["sap-hana"]}}`), + }, + }, { name: "rhsm-empty", fields: fields{ diff --git a/internal/osbuild2/tuned_stage.go b/internal/osbuild2/tuned_stage.go new file mode 100644 index 000000000..82041864d --- /dev/null +++ b/internal/osbuild2/tuned_stage.go @@ -0,0 +1,40 @@ +package osbuild2 + +import ( + "encoding/json" + "fmt" +) + +// TunedStageOptions represents manually set TuneD profiles. +type TunedStageOptions struct { + // List of TuneD profiles to apply. + Profiles []string `json:"profiles"` +} + +func (TunedStageOptions) isStageOptions() {} + +// NewTunedStageOptions creates a new TuneD Stage options object. +func NewTunedStageOptions(profiles ...string) *TunedStageOptions { + return &TunedStageOptions{ + Profiles: profiles, + } +} + +// Unexported alias for use in TunedStageOptions's MarshalJSON() to prevent recursion +type tunedStageOptions TunedStageOptions + +func (o TunedStageOptions) MarshalJSON() ([]byte, error) { + if len(o.Profiles) == 0 { + return nil, fmt.Errorf("at least one Profile must be provided") + } + options := tunedStageOptions(o) + return json.Marshal(options) +} + +// NewTunedStage creates a new TuneD Stage object. +func NewTunedStage(options *TunedStageOptions) *Stage { + return &Stage{ + Type: "org.osbuild.tuned", + Options: options, + } +} diff --git a/internal/osbuild2/tuned_stage_test.go b/internal/osbuild2/tuned_stage_test.go new file mode 100644 index 000000000..ffc8ea977 --- /dev/null +++ b/internal/osbuild2/tuned_stage_test.go @@ -0,0 +1,59 @@ +package osbuild2 + +import ( + "encoding/json" + "fmt" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestNewTunedStageOptions(t *testing.T) { + tests := []struct { + profiles []string + expectedOptions *TunedStageOptions + }{ + { + profiles: []string{"balanced"}, + expectedOptions: &TunedStageOptions{Profiles: []string{"balanced"}}, + }, + { + profiles: []string{"balanced", "sap-hana"}, + expectedOptions: &TunedStageOptions{Profiles: []string{"balanced", "sap-hana"}}, + }, + } + + for idx, tt := range tests { + t.Run(fmt.Sprint(idx), func(t *testing.T) { + actualOptions := NewTunedStageOptions(tt.profiles...) + assert.Equalf(t, tt.expectedOptions, actualOptions, "NewTunedStageOptions() failed [idx: %d]", idx) + }) + } +} + +func TestNewTunedStage(t *testing.T) { + expectedStage := &Stage{ + Type: "org.osbuild.tuned", + Options: &TunedStageOptions{}, + } + actualStage := NewTunedStage(&TunedStageOptions{}) + assert.Equal(t, expectedStage, actualStage) +} + +func TestTunedStageOptions_MarshalJSON_Invalid(t *testing.T) { + tests := []struct { + name string + options TunedStageOptions + }{ + { + name: "empty-options", + options: TunedStageOptions{}, + }, + } + 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) + }) + } +}