osbuild2: support org.osbuild.dnf-automatic.config stage

Add support for the new `org.osbuild.dnf-automatic.config` stage for
configuring DNF Automatic.

Add appropriate new unit tests for the stage implementation and modify
necessary existing unit tests.

Related to https://github.com/osbuild/osbuild/pull/936

Signed-off-by: Tomas Hozza <thozza@redhat.com>
This commit is contained in:
Tomas Hozza 2021-12-14 17:21:47 +01:00 committed by Tomáš Hozza
parent 97ef7fbf28
commit 09cd5b3576
4 changed files with 161 additions and 0 deletions

View file

@ -0,0 +1,70 @@
package osbuild2
import "fmt"
type DNFAutomaticUpgradeTypeValue string
// Valid values of the 'upgrade_type' option
const (
DNFAutomaticUpgradeTypeDefault DNFAutomaticUpgradeTypeValue = "default"
DNFAutomaticUpgradeTypeSecurity DNFAutomaticUpgradeTypeValue = "security"
)
// DNFAutomaticConfigCommands represents the 'commands' configuration section.
type DNFAutomaticConfigCommands struct {
// Whether packages comprising the available updates should be installed
ApplyUpdates *bool `json:"apply_updates,omitempty"`
// What kind of upgrades to look at
UpgradeType DNFAutomaticUpgradeTypeValue `json:"upgrade_type,omitempty"`
}
// DNFAutomaticConfig represents DNF Automatic configuration.
type DNFAutomaticConfig struct {
Commands *DNFAutomaticConfigCommands `json:"commands,omitempty"`
}
type DNFAutomaticConfigStageOptions struct {
Config *DNFAutomaticConfig `json:"config,omitempty"`
}
func (DNFAutomaticConfigStageOptions) isStageOptions() {}
// NewDNFAutomaticConfigStageOptions creates a new DNFAutomaticConfig Stage options object.
func NewDNFAutomaticConfigStageOptions(config *DNFAutomaticConfig) *DNFAutomaticConfigStageOptions {
return &DNFAutomaticConfigStageOptions{
Config: config,
}
}
func (o DNFAutomaticConfigStageOptions) validate() error {
if o.Config != nil && o.Config.Commands != nil {
allowedUpgradeTypeValues := []DNFAutomaticUpgradeTypeValue{
DNFAutomaticUpgradeTypeDefault,
DNFAutomaticUpgradeTypeSecurity,
"", // default empty value when the option is not set
}
valid := false
for _, value := range allowedUpgradeTypeValues {
if o.Config.Commands.UpgradeType == value {
valid = true
break
}
}
if !valid {
return fmt.Errorf("'upgrade_type' option does not allow %q as a value", o.Config.Commands.UpgradeType)
}
}
return nil
}
func NewDNFAutomaticConfigStage(options *DNFAutomaticConfigStageOptions) *Stage {
if err := options.validate(); err != nil {
panic(err)
}
return &Stage{
Type: "org.osbuild.dnf-automatic.config",
Options: options,
}
}

View file

@ -0,0 +1,79 @@
package osbuild2
import (
"testing"
"github.com/osbuild/osbuild-composer/internal/common"
"github.com/stretchr/testify/assert"
)
func TestNewDNFAutomaticConfigStage(t *testing.T) {
stageOptions := NewDNFAutomaticConfigStageOptions(&DNFAutomaticConfig{})
expectedStage := &Stage{
Type: "org.osbuild.dnf-automatic.config",
Options: stageOptions,
}
actualStage := NewDNFAutomaticConfigStage(stageOptions)
assert.Equal(t, expectedStage, actualStage)
}
func TestDNFAutomaticConfigStageOptionsValidate(t *testing.T) {
tests := []struct {
name string
options DNFAutomaticConfigStageOptions
err bool
}{
{
name: "empty-options",
options: DNFAutomaticConfigStageOptions{},
err: false,
},
{
name: "invalid-upgrade_type",
options: DNFAutomaticConfigStageOptions{
Config: &DNFAutomaticConfig{
Commands: &DNFAutomaticConfigCommands{
ApplyUpdates: common.BoolToPtr(true),
UpgradeType: "invalid",
},
},
},
err: true,
},
{
name: "valid-data-1",
options: DNFAutomaticConfigStageOptions{
Config: &DNFAutomaticConfig{
Commands: &DNFAutomaticConfigCommands{
ApplyUpdates: common.BoolToPtr(true),
UpgradeType: DNFAutomaticUpgradeTypeDefault,
},
},
},
err: false,
},
{
name: "valid-data-2",
options: DNFAutomaticConfigStageOptions{
Config: &DNFAutomaticConfig{
Commands: &DNFAutomaticConfigCommands{
ApplyUpdates: common.BoolToPtr(false),
UpgradeType: DNFAutomaticUpgradeTypeSecurity,
},
},
},
err: false,
},
}
for idx, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.err {
assert.Errorf(t, tt.options.validate(), "%q didn't return an error [idx: %d]", tt.name, idx)
assert.Panics(t, func() { NewDNFAutomaticConfigStage(&tt.options) })
} else {
assert.NoErrorf(t, tt.options.validate(), "%q returned an error [idx: %d]", tt.name, idx)
assert.NotPanics(t, func() { NewDNFAutomaticConfigStage(&tt.options) })
}
})
}
}

View file

@ -71,6 +71,8 @@ func (stage *Stage) UnmarshalJSON(data []byte) error {
options = new(ChronyStageOptions)
case "org.osbuild.dnf.config":
options = new(DNFConfigStageOptions)
case "org.osbuild.dnf-automatic.config":
options = new(DNFAutomaticConfigStageOptions)
case "org.osbuild.dracut":
options = new(DracutStageOptions)
case "org.osbuild.dracut.conf":

View file

@ -146,6 +146,16 @@ func TestStage_UnmarshalJSON(t *testing.T) {
data: []byte(`{"type":"org.osbuild.dnf.config","options":{}}`),
},
},
{
name: "dnf-automatic-config",
fields: fields{
Type: "org.osbuild.dnf-automatic.config",
Options: &DNFAutomaticConfigStageOptions{},
},
args: args{
data: []byte(`{"type":"org.osbuild.dnf-automatic.config","options":{}}`),
},
},
{
name: "dracut",
fields: fields{