Skip to content

Commit

Permalink
refactor: make some of the extensions package public
Browse files Browse the repository at this point in the history
Moving the loading and validation to the machinery package, so that we
can import and use that from other projects.

Co-authored-by: Noel Georgi <[email protected]>
Signed-off-by: Andrey Smirnov <[email protected]>
  • Loading branch information
smira and frezbo committed May 21, 2024
1 parent ce8c86d commit ff60f6f
Show file tree
Hide file tree
Showing 19 changed files with 159 additions and 110 deletions.
10 changes: 5 additions & 5 deletions internal/pkg/extensions/compress.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,14 @@ func (ext *Extension) Compress(squashPath, initramfsPath string, quirks quirks.Q
}

for _, path := range initramfsPaths {
if _, err := os.Stat(filepath.Join(ext.rootfsPath, path)); err == nil {
if err = moveFiles(filepath.Join(ext.rootfsPath, path), filepath.Join(initramfsPath, path)); err != nil {
if _, err := os.Stat(filepath.Join(ext.RootfsPath(), path)); err == nil {
if err = moveFiles(filepath.Join(ext.RootfsPath(), path), filepath.Join(initramfsPath, path)); err != nil {
return "", err
}
}
}

squashPath = filepath.Join(squashPath, fmt.Sprintf("%s.sqsh", ext.directory))
squashPath = filepath.Join(squashPath, fmt.Sprintf("%s.sqsh", ext.Directory()))

var compressArgs []string

Expand All @@ -62,7 +62,7 @@ func (ext *Extension) Compress(squashPath, initramfsPath string, quirks quirks.Q
compressArgs = []string{"-comp", "xz", "-Xdict-size", "100%"}
}

cmd := exec.Command("mksquashfs", append([]string{ext.rootfsPath, squashPath, "-all-root", "-noappend", "-no-progress"}, compressArgs...)...)
cmd := exec.Command("mksquashfs", append([]string{ext.RootfsPath(), squashPath, "-all-root", "-noappend", "-no-progress"}, compressArgs...)...)
cmd.Stderr = os.Stderr

return squashPath, cmd.Run()
Expand All @@ -89,7 +89,7 @@ func appendBlob(dst io.Writer, srcPath string) error {

func (ext *Extension) handleUcode(initramfsPath string) error {
for _, ucode := range earlyCPUUcode {
matches, err := filepath.Glob(filepath.Join(ext.rootfsPath, ucode.glob))
matches, err := filepath.Glob(filepath.Join(ext.RootfsPath(), ucode.glob))
if err != nil {
return err
}
Expand Down
22 changes: 2 additions & 20 deletions internal/pkg/extensions/extensions.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,10 @@
package extensions

import (
"path/filepath"

"github.com/siderolabs/talos/pkg/machinery/extensions"
)

// Extension represents unpacked extension in the filesystem.
// Extension wraps the extensions.Extension type with additional methods.
type Extension struct {
Manifest extensions.Manifest

directory string
rootfsPath string
}

func newExtension(rootfsPath, directory string) *Extension {
extension := &Extension{
rootfsPath: rootfsPath,
directory: directory,
}

if extension.directory == "" {
extension.directory = filepath.Base(rootfsPath)
}

return extension
*extensions.Extension
}
72 changes: 5 additions & 67 deletions internal/pkg/extensions/extensions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,87 +14,25 @@ import (

"github.com/siderolabs/talos/internal/pkg/extensions"
"github.com/siderolabs/talos/pkg/machinery/imager/quirks"
"github.com/siderolabs/talos/pkg/machinery/version"
)

func TestLoadValidate(t *testing.T) {
ext, err := extensions.Load("testdata/good/extension1")
require.NoError(t, err)

assert.Equal(t, "gvisor", ext.Manifest.Metadata.Name)

// override Talos version to make it predictable
oldVersion := version.Tag
version.Tag = "v1.0.0"

t.Cleanup(func() {
version.Tag = oldVersion
})

assert.NoError(t, ext.Validate())
}

func TestCompress(t *testing.T) {
// Compress is going to change contents of the extension, copy to some temporary directory
extDir := t.TempDir()

require.NoError(t, exec.Command("cp", "-r", "testdata/good/extension1", extDir).Run())

ext, err := extensions.Load(filepath.Join(extDir, "extension1"))
exts, err := extensions.List(extDir)
require.NoError(t, err)

require.Len(t, exts, 1)

ext := exts[0]

squashDest, initramfsDest := t.TempDir(), t.TempDir()
squashFile, err := ext.Compress(squashDest, initramfsDest, quirks.New(""))
assert.NoError(t, err)

assert.FileExists(t, squashFile)
assert.FileExists(t, filepath.Join(initramfsDest, "lib", "firmware", "amd", "cpu"))
}

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
})

for _, tt := range []struct {
name string
loadError string
validateError string
}{
{
name: "wrongfiles",
loadError: "unexpected file \"a\"",
},
{
name: "emptymanifest",
loadError: "unsupported manifest version: \"\"",
},
{
name: "norootfs",
loadError: "extension rootfs is missing",
},
{
name: "badpaths",
validateError: "path \"/boot/vmlinuz\" is not allowed in extensions",
},
} {
t.Run(tt.name, func(t *testing.T) {
ext, err := extensions.Load(filepath.Join("testdata/bad", tt.name))

if tt.loadError == "" {
require.NoError(t, err)
} else {
assert.EqualError(t, err, tt.loadError)
}

if err == nil {
err = ext.Validate()
assert.EqualError(t, err, tt.validateError)
}
})
}
}
24 changes: 13 additions & 11 deletions internal/pkg/extensions/kernel_modules.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ func (ext *Extension) ProvidesKernelModules() bool {

// KernelModuleDirectory returns the path to the kernel modules directory.
func (ext *Extension) KernelModuleDirectory() string {
return filepath.Join(ext.rootfsPath, constants.KernelModulesPath)
return filepath.Join(ext.RootfsPath(), constants.KernelModulesPath)
}

func autoDecompress(r io.Reader) (io.Reader, error) {
Expand Down Expand Up @@ -142,18 +142,20 @@ func GenerateKernelModuleDependencyTreeExtension(extensionPathsWithKernelModules
return nil, err
}

kernelModulesDepTreeExtension := newExtension(kernelModulesDependencyTreeStagingDir, "modules.dep")
kernelModulesDepTreeExtension.Manifest = extensions.Manifest{
Version: kernelVersionPath,
Metadata: extensions.Metadata{
Name: "modules.dep",
Version: kernelVersionPath,
Author: "Talos Machinery",
Description: "Combined modules.dep for all extensions",
kernelModulesDepTreeExtension := extensions.New(
kernelModulesDependencyTreeStagingDir, "modules.dep",
extensions.Manifest{
Version: kernelVersionPath,
Metadata: extensions.Metadata{
Name: "modules.dep",
Version: kernelVersionPath,
Author: "Talos Machinery",
Description: "Combined modules.dep for all extensions",
},
},
}
)

return kernelModulesDepTreeExtension, nil
return &Extension{kernelModulesDepTreeExtension}, nil
}

func logErr(msg string, f func() error) {
Expand Down
6 changes: 4 additions & 2 deletions internal/pkg/extensions/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import (
"os"
"path/filepath"
"sort"

"github.com/siderolabs/talos/pkg/machinery/extensions"
)

// List prepared unpacked extensions under rootPath.
Expand All @@ -35,12 +37,12 @@ func List(rootPath string) ([]*Extension, error) {
return nil, fmt.Errorf("unexpected non-directory entry: %q", item.Name())
}

ext, err := Load(filepath.Join(rootPath, item.Name()))
ext, err := extensions.Load(filepath.Join(rootPath, item.Name()))
if err != nil {
return nil, fmt.Errorf("error loading extension %s: %w", item.Name(), err)
}

result = append(result, ext)
result = append(result, &Extension{ext})
}

return result, nil
Expand Down
36 changes: 36 additions & 0 deletions pkg/machinery/extensions/extensions.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
// Package extensions contains Talos extensions specific API.
package extensions

import "path/filepath"

// AllowedPaths lists paths allowed in the extension images.
var AllowedPaths = []string{
"/etc/cri/conf.d",
Expand All @@ -18,3 +20,37 @@ var AllowedPaths = []string{
"/usr/share/egl",
"/etc/vulkan",
}

// Extension represents unpacked extension in the filesystem.
type Extension struct {
Manifest Manifest

directory string
rootfsPath string
}

// RootfsPath returns the path to the rootfs directory.
func (ext *Extension) RootfsPath() string {
return ext.rootfsPath
}

// Directory returns the directory name of the extension.
func (ext *Extension) Directory() string {
return ext.directory
}

// New creates a new extension from the rootfs path, directory name and manifest.
func New(rootfsPath, directory string, manifest Manifest) *Extension {
extension := &Extension{
Manifest: manifest,

rootfsPath: rootfsPath,
directory: directory,
}

if extension.directory == "" {
extension.directory = filepath.Base(rootfsPath)
}

return extension
}
81 changes: 81 additions & 0 deletions pkg/machinery/extensions/extensions_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// 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 extensions_test

import (
"path/filepath"
"testing"

"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) {
ext, err := extensions.Load("testdata/good/extension1")
require.NoError(t, err)

assert.Equal(t, "gvisor", ext.Manifest.Metadata.Name)

// override Talos version to make it predictable
oldVersion := version.Tag
version.Tag = "v1.0.0"

t.Cleanup(func() {
version.Tag = oldVersion
})

assert.NoError(t, ext.Validate())
}

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
})

for _, tt := range []struct {
name string
loadError string
validateError string
}{
{
name: "wrongfiles",
loadError: "unexpected file \"a\"",
},
{
name: "emptymanifest",
loadError: "unsupported manifest version: \"\"",
},
{
name: "norootfs",
loadError: "extension rootfs is missing",
},
{
name: "badpaths",
validateError: "path \"/boot/vmlinuz\" is not allowed in extensions",
},
} {
t.Run(tt.name, func(t *testing.T) {
ext, err := extensions.Load(filepath.Join("testdata/bad", tt.name))

if tt.loadError == "" {
require.NoError(t, err)
} else {
assert.EqualError(t, err, tt.loadError)
}

if err == nil {
err = ext.Validate()
assert.EqualError(t, err, tt.validateError)
}
})
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ import (
"path/filepath"

"gopkg.in/yaml.v3"

"github.com/siderolabs/talos/pkg/machinery/extensions"
)

// Load extension from the filesystem.
Expand Down Expand Up @@ -41,7 +39,7 @@ func Load(path string) (*Extension, error) {
}
}

var zeroManifest extensions.Manifest
var zeroManifest Manifest

if extension.Manifest == zeroManifest {
return nil, errors.New("extension manifest is missing")
Expand Down
10 changes: 10 additions & 0 deletions pkg/machinery/extensions/testdata/good/extension1/manifest.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
version: v1alpha1
metadata:
name: gvisor
version: 20220117.0-v1.0.0
author: Andrew Rynhard
description: >
This system extension provides gVisor using containerd's runtime handler.
compatibility:
talos:
version: ">= v1.0.0"
Empty file.
Empty file.
Empty file.
Loading

0 comments on commit ff60f6f

Please sign in to comment.