Skip to content

Commit

Permalink
Added ability to include custom combustion scripts in an image
Browse files Browse the repository at this point in the history
  • Loading branch information
jdob committed Nov 2, 2023
1 parent 3bc45ca commit d9d4705
Show file tree
Hide file tree
Showing 4 changed files with 163 additions and 0 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ the structure of this directory will be better fleshed out. For now, the require
are no restrictions on the naming; the image configuration file will specify which image in this directory to use
for a particular build.

There are a number of optional directories that may be included in the image configuration directory:

* `scripts` - If present, all the files in this directory will be included in the built image and automatically
executed during the combustion phase.

### Running EIB

The image configuration directory must be attached to the container at runtime. This serves as both the mechanism
Expand Down
5 changes: 5 additions & 0 deletions pkg/build/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ func (b *Builder) Build() error {
return fmt.Errorf("configuring the welcome message: %w", err)
}

err = b.configureScripts()
if err != nil {
return fmt.Errorf("configuring custom scripts: %w", err)
}

err = b.generateCombustionScript()
if err != nil {
return fmt.Errorf("generating combustion script: %w", err)
Expand Down
54 changes: 54 additions & 0 deletions pkg/build/scripts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package build

import (
"fmt"
"os"
"path/filepath"
)

const (
scriptsDir = "scripts"
scriptMode = 0o744
)

func (b *Builder) configureScripts() error {
fullScriptsDir := filepath.Join(b.buildConfig.ImageConfigDir, scriptsDir)

// Nothing to do if the image config dir doesn't have the scripts directory
_, err := os.Stat(fullScriptsDir)
if err != nil {
if os.IsNotExist(err) {
return nil
}
return fmt.Errorf("checking for scripts directory at %s: %w", fullScriptsDir, err)
}

dirListing, err := os.ReadDir(fullScriptsDir)
if err != nil {
return fmt.Errorf("reading the scripts directory at %s: %w", fullScriptsDir, err)
}

// If the directory exists but there's nothing in it, consider it an error case
if len(dirListing) == 0 {
return fmt.Errorf("no scripts found in directory %s", fullScriptsDir)
}

for _, scriptEntry := range dirListing {
copyMe := filepath.Join(fullScriptsDir, scriptEntry.Name())
copyTo := filepath.Join(b.combustionDir, scriptEntry.Name())

err = copyFile(copyMe, copyTo)
if err != nil {
return fmt.Errorf("copying script to %s: %w", copyTo, err)
}
err = os.Chmod(copyTo, scriptMode)
if err != nil {
return fmt.Errorf("modifying permissions for script %s: %w", copyTo, err)
}

// Make sure the combustion main script will execute the newly copied script
b.registerCombustionScript(scriptEntry.Name())
}

return nil
}
99 changes: 99 additions & 0 deletions pkg/build/scripts_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package build

import (
"os"
"path/filepath"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/suse-edge/edge-image-builder/pkg/config"
)

func TestConfigureScripts(t *testing.T) {
// Setup
// - Testing image config directory
tmpSrcDir, err := os.MkdirTemp("", "eib-")
require.NoError(t, err)
defer os.RemoveAll(tmpSrcDir)

// - scripts directory to look in
fullScriptsDir := filepath.Join(tmpSrcDir, scriptsDir)
err = os.MkdirAll(fullScriptsDir, os.ModePerm)
require.NoError(t, err)

// - create sample scripts to be copied
_, err = os.Create(filepath.Join(fullScriptsDir, "foo.sh"))
require.NoError(t, err)
_, err = os.Create(filepath.Join(fullScriptsDir, "bar.sh"))
require.NoError(t, err)

// - combustion directory into which the scripts should be copied
tmpDestDir, err := os.MkdirTemp("", "eib-")
require.NoError(t, err)
defer os.RemoveAll(tmpDestDir)

builder := New(nil, &config.BuildConfig{ImageConfigDir: tmpSrcDir})
builder.combustionDir = tmpDestDir

// Test
err = builder.configureScripts()

// Verify
require.NoError(t, err)

// - make sure the scripts were added to the build directory
foundDirListing, err := os.ReadDir(tmpDestDir)
require.NoError(t, err)
assert.Equal(t, 2, len(foundDirListing))

// - make sure the copied files have the right permissions
for _, entry := range foundDirListing {
fullEntryPath := filepath.Join(builder.combustionDir, entry.Name())
stats, err := os.Stat(fullEntryPath)
require.NoError(t, err)
foundMode := stats.Mode()
assert.Equal(t, "-rwxr--r--", foundMode.String())
}

// - make sure entries were added to the combustion scripts list, so they are
// present in the script file that is generated
assert.Equal(t, 2, len(builder.combustionScripts))
}

func TestConfigureScriptsNoScriptsDir(t *testing.T) {
// Setup
tmpSrcDir, err := os.MkdirTemp("", "eib-")
require.NoError(t, err)
defer os.RemoveAll(tmpSrcDir)

builder := New(nil, &config.BuildConfig{ImageConfigDir: tmpSrcDir})

// Test
err = builder.configureScripts()

// Verify
require.NoError(t, err)
}

func TestConfigureScriptsEmptyScriptsDir(t *testing.T) {
// Setup
// - Testing image config directory
tmpSrcDir, err := os.MkdirTemp("", "eib-")
require.NoError(t, err)
defer os.RemoveAll(tmpSrcDir)

// - scripts directory to look in
fullScriptsDir := filepath.Join(tmpSrcDir, scriptsDir)
err = os.MkdirAll(fullScriptsDir, os.ModePerm)
require.NoError(t, err)

builder := New(nil, &config.BuildConfig{ImageConfigDir: tmpSrcDir})

// Test
err = builder.configureScripts()

// Verify
require.Error(t, err)
assert.Contains(t, err.Error(), "no scripts found in directory")
}

0 comments on commit d9d4705

Please sign in to comment.