Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions custom-recipes/buildernet/mkosi/playground.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,14 @@ recipe:
depends_on:
- builder-hub-proxy:healthy
files:
"/server.key": "server.key"
"/server.crt": "server.crt"
"/server.key": "config/server.key"
"/server.crt": "config/server.crt"

builder:
lifecycle_hooks: true
init:
- rm -rf .runtime/buildernet-vm.qcow2 || true
- ./prepare.sh
start: ./start.sh
- ./scripts/prepare.sh
start: ./scripts/start.sh
stop:
- ./stop.sh
- ./scripts/stop.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
set -eu -o pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_DIR="${SCRIPT_DIR}/.."

FLASHBOTS_IMAGES_DIR="${SCRIPT_DIR}/.flashbots-images"
FLASHBOTS_IMAGES_DIR="${PROJECT_DIR}/.flashbots-images"

if [[ ! -d "${FLASHBOTS_IMAGES_DIR}" ]]; then
echo "Error: flashbots-images not found. Run ./sync.sh first."
echo "Error: flashbots-images not found. Run ./scripts/sync.sh first."
exit 1
fi

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@
set -eu -o pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_DIR="${SCRIPT_DIR}/.."

FLASHBOTS_IMAGES_DIR="${SCRIPT_DIR}/.flashbots-images"
RUNTIME_DIR="${SCRIPT_DIR}/.runtime"
FLASHBOTS_IMAGES_DIR="${PROJECT_DIR}/.flashbots-images"
RUNTIME_DIR="${PROJECT_DIR}/.runtime"
PIDFILE="${RUNTIME_DIR}/qemu.pid"

# Check if VM is running
if [[ -f "${PIDFILE}" ]] && kill -0 $(cat "${PIDFILE}") 2>/dev/null; then
echo "Error: VM is still running. Run ./stop.sh first."
echo "Error: VM is still running. Run ./scripts/stop.sh first."
exit 1
fi

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
set -eu -o pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
CONSOLE_SOCK="${SCRIPT_DIR}/.runtime/console.sock"
PROJECT_DIR="${SCRIPT_DIR}/.."
CONSOLE_SOCK="${PROJECT_DIR}/.runtime/console.sock"

if [[ ! -S "${CONSOLE_SOCK}" ]]; then
echo "Error: Console socket not found. Is the VM running?"
echo "Run ./start.sh first."
echo "Run ./scripts/start.sh first."
exit 1
fi

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
set -eu -o pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_DIR="${SCRIPT_DIR}/.."

FLASHBOTS_IMAGES_DIR="${SCRIPT_DIR}/.flashbots-images"
RUNTIME_DIR="${SCRIPT_DIR}/.runtime"
FLASHBOTS_IMAGES_DIR="${PROJECT_DIR}/.flashbots-images"
RUNTIME_DIR="${PROJECT_DIR}/.runtime"

QEMU_QCOW2="${FLASHBOTS_IMAGES_DIR}/mkosi.output/buildernet-qemu_latest.qcow2"

Expand All @@ -14,7 +15,7 @@ VM_DATA_DISK="${RUNTIME_DIR}/persistent.raw"

if [[ ! -f "${QEMU_QCOW2}" ]]; then
echo "Error: QEMU qcow2 image not found: ${QEMU_QCOW2}"
echo "Run ./build.sh first."
echo "Run ./scripts/build.sh first."
exit 1
fi

Expand All @@ -27,4 +28,4 @@ cp --sparse=always "${QEMU_QCOW2}" "${VM_IMAGE}"
qemu-img create -f raw "${VM_DATA_DISK}" 100G

echo "Runtime ready: ${RUNTIME_DIR}"
ls -lah "${RUNTIME_DIR}"
ls -lah "${RUNTIME_DIR}"
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
set -eu -o pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_DIR="${SCRIPT_DIR}/.."

RUNTIME_DIR="${SCRIPT_DIR}/.runtime"
RUNTIME_DIR="${PROJECT_DIR}/.runtime"
VM_IMAGE="${RUNTIME_DIR}/buildernet-vm.qcow2"
VM_DATA_DISK="${RUNTIME_DIR}/persistent.raw"
PIDFILE="${RUNTIME_DIR}/qemu.pid"
Expand All @@ -20,7 +21,7 @@ HAPROXY_HTTP_PORT=10080
HAPROXY_HTTPS_PORT=10443

if [[ ! -f "${VM_IMAGE}" ]]; then
echo "Error: VM image not found. Run ./prepare.sh first."
echo "Error: VM image not found. Run ./scripts/prepare.sh first."
exit 1
fi

Expand Down Expand Up @@ -60,7 +61,7 @@ qemu-system-x86_64 \
-device virtconsole,chardev=virtcon,name=org.qemu.console.0

echo "VM started (PID: $(cat ${PIDFILE}))"
echo "Use './stop.sh' to stop, './console.sh' to connect"
echo "Use './scripts/stop.sh' to stop, './scripts/console.sh' to connect"
echo "Use 'tail -f ${CONSOLE_LOG}' to watch console output"


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
set -eu -o pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PIDFILE="${SCRIPT_DIR}/.runtime/qemu.pid"
PROJECT_DIR="${SCRIPT_DIR}/.."
PIDFILE="${PROJECT_DIR}/.runtime/qemu.pid"

if [[ ! -f "${PIDFILE}" ]]; then
echo "No pidfile found"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
set -eu -o pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_DIR="${SCRIPT_DIR}/.."

FLASHBOTS_IMAGES_DIR="${SCRIPT_DIR}/.flashbots-images"
FLASHBOTS_IMAGES_DIR="${PROJECT_DIR}/.flashbots-images"
FLASHBOTS_IMAGES_BRANCH="fryd/mkosi-playground"
FLASHBOTS_IMAGES_REPO="https://github.com/flashbots/flashbots-images.git"

Expand Down
57 changes: 0 additions & 57 deletions custom-recipes/buildernet/mkosi/send-tx.sh

This file was deleted.

38 changes: 31 additions & 7 deletions playground/custom_recipes.go
Original file line number Diff line number Diff line change
Expand Up @@ -208,12 +208,26 @@ func GenerateCustomRecipeToDir(customRecipeName, targetDir string) (string, erro
return "", err
}

// Extract files to target directory
// Extract files to target directory, preserving subdirectory structure
err = fs.WalkDir(CustomRecipesFS, recipePath, func(path string, d fs.DirEntry, err error) error {
if err != nil {
return err
}

// Compute relative path from recipe root
relPath, err := filepath.Rel(recipePath, path)
if err != nil {
return fmt.Errorf("failed to compute relative path for %s: %w", path, err)
}

if d.IsDir() {
// Create subdirectories in target
if relPath != "." {
dirPath := filepath.Join(targetDir, relPath)
if err := os.MkdirAll(dirPath, 0o755); err != nil {
return fmt.Errorf("failed to create directory %s: %w", dirPath, err)
}
}
return nil
}

Expand All @@ -230,10 +244,16 @@ func GenerateCustomRecipeToDir(customRecipeName, targetDir string) (string, erro
return fmt.Errorf("failed to read %s: %w", path, err)
}

// Write the file to target directory (playground.yaml is already correctly named)
fullPath := filepath.Join(targetDir, fileName)
// Write the file preserving subdirectory structure
fullPath := filepath.Join(targetDir, relPath)

if err := os.WriteFile(fullPath, content, 0o755); err != nil {
// Use executable permissions for shell scripts, regular permissions for everything else
perm := os.FileMode(0o644)
if strings.HasSuffix(fileName, ".sh") {
perm = 0o755
}

if err := os.WriteFile(fullPath, content, perm); err != nil {
return fmt.Errorf("failed to write %s: %w", fullPath, err)
}
return nil
Expand Down Expand Up @@ -311,7 +331,7 @@ func listCustomRecipeFiles(customRecipeName string) ([]string, error) {
return nil, err
}

// Collect output files
// Collect output files, preserving relative paths
var files []string
err = fs.WalkDir(CustomRecipesFS, recipePath, func(path string, d fs.DirEntry, err error) error {
if err != nil {
Expand All @@ -321,15 +341,19 @@ func listCustomRecipeFiles(customRecipeName string) ([]string, error) {
return nil
}

relPath, err := filepath.Rel(recipePath, path)
if err != nil {
return fmt.Errorf("failed to compute relative path for %s: %w", path, err)
}

fileName := filepath.Base(path)

// Skip other yaml files that aren't the selected custom recipe
if (strings.HasSuffix(fileName, ".yaml") || strings.HasSuffix(fileName, ".yml")) && fileName != yamlFile {
return nil
}

// playground.yaml is already correctly named
files = append(files, fileName)
files = append(files, relPath)
return nil
})
if err != nil {
Expand Down
35 changes: 35 additions & 0 deletions playground/custom_recipes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,16 @@ recipe:
"custom-recipes/testdir/sample/extra.toml": &fstest.MapFile{
Data: []byte("[section]\nkey = \"value\"\n"),
},
// Subdirectory files for testing directory preservation
"custom-recipes/testdir/sample/scripts/build.sh": &fstest.MapFile{
Data: []byte("#!/bin/bash\necho build\n"),
},
"custom-recipes/testdir/sample/scripts/start.sh": &fstest.MapFile{
Data: []byte("#!/bin/bash\necho start\n"),
},
"custom-recipes/testdir/sample/config/server.crt": &fstest.MapFile{
Data: []byte("CERT_DATA"),
},
"custom-recipes/testdir/another/playground.yaml": &fstest.MapFile{
Data: []byte(`base: l1
description: Another test recipe
Expand Down Expand Up @@ -185,6 +195,11 @@ func TestListCustomRecipeFiles(t *testing.T) {
// Should include playground.yaml and non-YAML sibling files
require.Contains(t, files, "playground.yaml")
require.Contains(t, files, "extra.toml")

// Should include files in subdirectories with relative paths
require.Contains(t, files, filepath.Join("scripts", "build.sh"))
require.Contains(t, files, filepath.Join("scripts", "start.sh"))
require.Contains(t, files, filepath.Join("config", "server.crt"))
}

func TestListCustomRecipeFiles_InvalidName(t *testing.T) {
Expand Down Expand Up @@ -227,6 +242,26 @@ func TestGenerateCustomRecipeToDir(t *testing.T) {
extraContent, err := os.ReadFile(extraPath)
require.NoError(t, err)
require.Contains(t, string(extraContent), "key = \"value\"")

// Verify subdirectory files were extracted with correct paths
scriptPath := filepath.Join(tmpDir, "scripts", "build.sh")
scriptContent, err := os.ReadFile(scriptPath)
require.NoError(t, err)
require.Contains(t, string(scriptContent), "echo build")

certPath := filepath.Join(tmpDir, "config", "server.crt")
certContent, err := os.ReadFile(certPath)
require.NoError(t, err)
require.Equal(t, "CERT_DATA", string(certContent))

// Verify permissions: .sh files should be executable, others should not
scriptInfo, err := os.Stat(scriptPath)
require.NoError(t, err)
require.Equal(t, os.FileMode(0o755), scriptInfo.Mode().Perm(), "shell scripts should be executable")

certInfo, err := os.Stat(certPath)
require.NoError(t, err)
require.Equal(t, os.FileMode(0o644), certInfo.Mode().Perm(), "non-script files should not be executable")
}

func TestGenerateCustomRecipeToDir_InvalidName(t *testing.T) {
Expand Down