fix: use imager incoming version for extension validation

Use the version coming from imager to validate extension constraints.

Part of : #9694

Signed-off-by: Noel Georgi <git@frezbo.dev>
This commit is contained in:
Noel Georgi
2024-11-11 18:50:46 +05:30
parent 9a02ecc49f
commit 682718d4c9
5 changed files with 108 additions and 33 deletions

View File

@@ -16,11 +16,12 @@ import (
func (i *Installer) installExtensions() error {
builder := extensions.Builder{
InitramfsPath: fmt.Sprintf(constants.InitramfsAssetPath, i.options.Arch),
Arch: i.options.Arch,
ExtensionTreePath: constants.SystemExtensionsPath,
Printf: log.Printf,
Quirks: quirks.New(i.options.Version),
InitramfsPath: fmt.Sprintf(constants.InitramfsAssetPath, i.options.Arch),
Arch: i.options.Arch,
ExtensionTreePath: constants.SystemExtensionsPath,
ExtensionValidateContents: true,
Printf: log.Printf,
Quirks: quirks.New(i.options.Version),
}
return builder.Build()

View File

@@ -24,6 +24,8 @@ type Builder struct {
Arch string
// ExtensionTreePath is a path to the extracted extension tree.
ExtensionTreePath string
// ExtensionValidateContents enables validation of the extension contents.
ExtensionValidateContents bool
// Printf is used for logging.
Printf func(format string, v ...any)
// Quirks for the Talos version being used.
@@ -95,8 +97,17 @@ func (builder *Builder) Build() error {
func (builder *Builder) validateExtensions(extensions []*extensions.Extension) error {
builder.Printf("validating system extensions")
opts := []extinterface.ValidationOption{
extinterface.WithValidateConstraints(),
extinterface.WithTalosVersion(builder.Quirks.Version()),
}
if builder.ExtensionValidateContents {
opts = append(opts, extinterface.WithValidateContents())
}
for _, ext := range extensions {
if err := ext.Validate(); err != nil {
if err := ext.Validate(opts...); err != nil {
return fmt.Errorf("error validating extension %q: %w", ext.Manifest.Metadata.Name, err)
}
}

View File

@@ -8,11 +8,11 @@ import (
"path/filepath"
"testing"
"github.com/blang/semver/v4"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/siderolabs/talos/pkg/machinery/extensions"
"github.com/siderolabs/talos/pkg/machinery/version"
)
func TestLoadValidate(t *testing.T) {
@@ -21,25 +21,19 @@ func TestLoadValidate(t *testing.T) {
assert.Equal(t, "gvisor", ext.Manifest.Metadata.Name)
// override Talos version to make it predictable
oldVersion := version.Tag
version.Tag = "v1.0.0"
version, err := semver.Parse("1.0.0")
require.NoError(t, err)
t.Cleanup(func() {
version.Tag = oldVersion
})
assert.NoError(t, ext.Validate())
assert.NoError(t, ext.Validate(
extensions.WithValidateConstraints(),
extensions.WithValidateContents(),
extensions.WithTalosVersion(version),
))
}
func TestValidateFailures(t *testing.T) {
// override Talos version to make it predictable
oldVersion := version.Tag
version.Tag = "v1.0.0"
t.Cleanup(func() {
version.Tag = oldVersion
})
version, err := semver.Parse("1.0.0")
require.NoError(t, err)
for _, tt := range []struct {
name string
@@ -73,7 +67,12 @@ func TestValidateFailures(t *testing.T) {
}
if err == nil {
err = ext.Validate()
err = ext.Validate(
extensions.WithValidateConstraints(),
extensions.WithValidateContents(),
extensions.WithTalosVersion(version),
)
assert.EqualError(t, err, tt.validateError)
}
})

View File

@@ -16,24 +16,83 @@ import (
"github.com/siderolabs/talos/pkg/machinery/version"
)
// Validate the extension: compatibility, contents, etc.
func (ext *Extension) Validate() error {
if err := ext.validateConstraints(); err != nil {
return err
}
// ValidationOptions are used to configure the validation process.
type ValidationOptions struct {
// ValidateContstraints enables validation of the extension constraints.
ValidateContstraints bool
// ValidateContents enables validation of the extension contents.
ValidateContents bool
return ext.validateContents()
// TalosVersion is the version of Talos to validate against.
TalosVersion *semver.Version
}
func (ext *Extension) validateConstraints() error {
constraint := ext.Manifest.Metadata.Compatibility.Talos.Version
// WithValidateConstraints enables validation of the extension constraints.
func WithValidateConstraints() ValidationOption {
return func(o *ValidationOptions) error {
o.ValidateContstraints = true
if constraint != "" {
talosVersion, err := semver.ParseTolerant(version.Tag)
return nil
}
}
// WithValidateContents enables validation of the extension contents.
func WithValidateContents() ValidationOption {
return func(o *ValidationOptions) error {
o.ValidateContents = true
return nil
}
}
// WithTalosVersion sets the Talos version to validate against.
func WithTalosVersion(version semver.Version) ValidationOption {
return func(o *ValidationOptions) error {
o.TalosVersion = &version
return nil
}
}
// ValidationOption is a function that configures the validation options.
type ValidationOption func(*ValidationOptions) error
// Validate the extension: compatibility, contents, etc.
func (ext *Extension) Validate(opts ...ValidationOption) error {
validationOptions := &ValidationOptions{}
for _, opt := range opts {
if err := opt(validationOptions); err != nil {
panic(err)
}
}
if validationOptions.TalosVersion == nil {
version, err := semver.ParseTolerant(version.Tag)
if err != nil {
return err
}
validationOptions.TalosVersion = &version
}
if validationOptions.ValidateContstraints {
if err := ext.validateConstraints(*validationOptions.TalosVersion); err != nil {
return err
}
}
if validationOptions.ValidateContents {
return ext.validateContents()
}
return nil
}
func (ext *Extension) validateConstraints(talosVersion semver.Version) error {
constraint := ext.Manifest.Metadata.Compatibility.Talos.Version
if constraint != "" {
versionConstraint, err := semver.ParseRange(trim(constraint))
if err != nil {
return fmt.Errorf("error parsing Talos version constraint: %w", err)

View File

@@ -29,6 +29,11 @@ func New(talosVersion string) Quirks {
var minVersionResetOption = semver.MustParse("1.4.0")
// Version returns the Talos version.
func (q Quirks) Version() semver.Version {
return *q.v
}
// SupportsResetGRUBOption returns true if the Talos version supports the reset option in GRUB menu (image and ISO).
func (q Quirks) SupportsResetGRUBOption() bool {
// if the version doesn't parse, we assume it's latest Talos