Skip to content

Commit

Permalink
detect image being larger than root
Browse files Browse the repository at this point in the history
  • Loading branch information
taukakao committed Jul 30, 2024
1 parent 710b07a commit 49c823f
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 0 deletions.
55 changes: 55 additions & 0 deletions core/oci.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"os"
"path/filepath"
"strings"
"syscall"
"time"

"github.com/containers/buildah"
Expand All @@ -31,6 +32,12 @@ import (
"github.com/vanilla-os/prometheus"
)

type NotEnoughSpaceError struct{}

func (v *NotEnoughSpaceError) Error() string {
return "not enough space in disk"
}

var Progressbar = pterm.ProgressbarPrinter{
Total: 100,
BarCharacter: "■",
Expand Down Expand Up @@ -137,6 +144,12 @@ func OciExportRootFs(buildImageName string, imageRecipe *ImageRecipe, transDir s
return err
}

err = checkImageSize(mountDir, dest)
if err != nil {
PrintVerboseErr("OciExportRootFs", 8.5, err)
return err
}

// copy mount dir contents to dest
err = rsyncCmd(mountDir+"/", dest, []string{"--delete", "--checksum"}, false)
if err != nil {
Expand All @@ -154,6 +167,48 @@ func OciExportRootFs(buildImageName string, imageRecipe *ImageRecipe, transDir s
return nil
}

// returns nil if there's enough space in the filesystem for the image
// returns NotEnoughSpaceError if there is not enough space
// returns other error if the sizes were not calculated correctly
func checkImageSize(imageDir string, filesystemMount string) error {
imageDirStat, err := os.Stat(imageDir)
if err != nil {
PrintVerboseErr("OciExportRootFs", 8.1, err)
return err
}

var imageDirSize int64
if imageDirStat.IsDir() {
imageDirSize, err = getDirSize(imageDir)
if err != nil {
PrintVerboseErr("OciExportRootFs", 8.2, err)
return err
}
} else {
imageDirSize = imageDirStat.Size()
}

var stat syscall.Statfs_t
err = syscall.Statfs(filesystemMount, &stat)
if err != nil {
PrintVerboseErr("OciExportRootFs", 8.3, err)
return err
}

availableSpace := stat.Blocks * uint64(stat.Bsize)
if settings.Cnf.ThinProvisioning {
availableSpace /= 2
}

if uint64(imageDirSize) > availableSpace {
err := &NotEnoughSpaceError{}
PrintVerboseErr("OciExportRootFs", 8.4, err)
return err
}

return nil
}

// pullImageWithProgressbar pulls the image specified in the provided recipe
// and reports the download progress using pterm progressbars. Each blob has
// its own bar, similar to how docker and podman report downloads in their
Expand Down
29 changes: 29 additions & 0 deletions core/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,14 @@ package core
*/

import (
"bytes"
"errors"
"fmt"
"io"
"os"
"os/exec"
"strconv"
"strings"
)

var abrootDir = "/etc/abroot"
Expand Down Expand Up @@ -122,3 +126,28 @@ func isDeviceLUKSEncrypted(devicePath string) (bool, error) {

return true, nil
}

// getDirSize calculates the total size of a directory recursively.
//
// FIXME: find a way to avoid using du and any other external command
func getDirSize(path string) (int64, error) {
cmd := exec.Command("du", "-s", "-b", path)
var out bytes.Buffer
cmd.Stdout = &out
err := cmd.Run()
if err != nil {
return 0, err
}

output := strings.Fields(out.String())
if len(output) == 0 {
return 0, errors.New("failed to get directory size")
}

size, err := strconv.ParseInt(output[0], 10, 64)
if err != nil {
return 0, err
}

return size, nil
}

0 comments on commit 49c823f

Please sign in to comment.