Auto calculate image size on actions (#122)

This commit is contained in:
Itxaka 2023-08-08 10:44:42 +02:00 committed by GitHub
parent 3e9befa230
commit 4108aa929e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 102 additions and 14 deletions

2
go.mod
View File

@ -12,7 +12,7 @@ require (
github.com/hashicorp/go-multierror v1.1.1
github.com/jaypipes/ghw v0.12.0
github.com/joho/godotenv v1.5.1
github.com/kairos-io/kairos-sdk v0.0.11
github.com/kairos-io/kairos-sdk v0.0.12
github.com/labstack/echo/v4 v4.10.2
github.com/mitchellh/mapstructure v1.5.0
github.com/mudler/go-nodepair v0.0.0-20221223092639-ba399a66fdfb

2
go.sum
View File

@ -371,6 +371,8 @@ github.com/kairos-io/kairos-sdk v0.0.10 h1:TUgrGSGP6Z1CPfA4gjmbb+cCaJg1OR18c+LD+
github.com/kairos-io/kairos-sdk v0.0.10/go.mod h1:AK9poWisuhnzri04diXnTG8L7EkOSUArSeeDn2LYFU0=
github.com/kairos-io/kairos-sdk v0.0.11 h1:+EWuO4gWMzBa81s8gbF1L7wOvEjbph1z8UkfUrMyvxc=
github.com/kairos-io/kairos-sdk v0.0.11/go.mod h1:AK9poWisuhnzri04diXnTG8L7EkOSUArSeeDn2LYFU0=
github.com/kairos-io/kairos-sdk v0.0.12 h1:+uibTjjsAh8klupXHWpWse2AKww6p8ROu8Ii28t3k48=
github.com/kairos-io/kairos-sdk v0.0.12/go.mod h1:AK9poWisuhnzri04diXnTG8L7EkOSUArSeeDn2LYFU0=
github.com/kbinani/screenshot v0.0.0-20210720154843-7d3a670d8329 h1:qq2nCpSrXrmvDGRxW0ruW9BVEV1CN2a9YDOExdt+U0o=
github.com/kbinani/screenshot v0.0.0-20210720154843-7d3a670d8329/go.mod h1:2VPVQDR4wO7KXHwP+DAypEy67rXf+okUx2zjgpCxZw4=
github.com/kendru/darwin/go/depgraph v0.0.0-20221105232959-877d6a81060c h1:eKb4PqwAMhlqwXw0W3atpKaYaPGlXE/Fwh+xpCEYaPk=

View File

@ -18,8 +18,7 @@ package config
import (
"fmt"
"github.com/kairos-io/kairos-agent/v2/pkg/utils/fs"
"github.com/kairos-io/kairos-agent/v2/pkg/utils/partitions"
"io/fs"
"path/filepath"
"reflect"
"strings"
@ -27,6 +26,8 @@ import (
"github.com/kairos-io/kairos-agent/v2/internal/common"
"github.com/kairos-io/kairos-agent/v2/pkg/constants"
v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1"
"github.com/kairos-io/kairos-agent/v2/pkg/utils/fs"
"github.com/kairos-io/kairos-agent/v2/pkg/utils/partitions"
"github.com/mitchellh/mapstructure"
"github.com/sanity-io/litter"
"github.com/sirupsen/logrus"
@ -95,7 +96,19 @@ func NewInstallSpec(cfg *Config) *v1.InstallSpec {
Recovery: recoveryImg,
Passive: passiveImg,
}
// Calculate the partitions sizes automatically based on the images set size
// Get the actual source size to calculate the image size and partitions size
size, err := GetSourceSize(cfg, spec.Active.Source)
if err != nil {
cfg.Logger.Warnf("Failed to infer size for images: %s", err.Error())
} else {
cfg.Logger.Infof("Setting image size to %dMb", size)
spec.Active.Size = uint(size)
spec.Passive.Size = uint(size)
spec.Recovery.Size = uint(size)
}
// Calculate the partitions afterwards so they use the image sizes for the final partition sizes
spec.Partitions = NewInstallElementalPartitions(spec)
return spec
@ -237,13 +250,26 @@ func NewUpgradeSpec(cfg *Config) (*v1.UpgradeSpec, error) {
}
}
return &v1.UpgradeSpec{
spec := &v1.UpgradeSpec{
Active: active,
Recovery: recovery,
Passive: passive,
Partitions: ep,
State: installState,
}, nil
}
// Get the actual source size to calculate the image size and partitions size
size, err := GetSourceSize(cfg, spec.Active.Source)
if err != nil {
cfg.Logger.Warnf("Failed to infer size for images: %s", err.Error())
} else {
cfg.Logger.Infof("Setting image size to %dMb", size)
// On upgrade only the active or recovery will be upgraded, so we dont need to override passive
spec.Active.Size = uint(size)
spec.Recovery.Size = uint(size)
}
return spec, nil
}
// NewResetSpec returns a ResetSpec struct all based on defaults and current host state
@ -343,7 +369,7 @@ func NewResetSpec(cfg *Config) (*v1.ResetSpec, error) {
}
activeFile := filepath.Join(ep.State.MountPoint, "cOS", constants.ActiveImgFile)
return &v1.ResetSpec{
spec := &v1.ResetSpec{
Target: target,
Partitions: ep,
Efi: efiExists,
@ -367,7 +393,19 @@ func NewResetSpec(cfg *Config) (*v1.ResetSpec, error) {
FS: constants.LinuxImgFs,
},
State: installState,
}, nil
}
// Get the actual source size to calculate the image size and partitions size
size, err := GetSourceSize(cfg, spec.Active.Source)
if err != nil {
cfg.Logger.Warnf("Failed to infer size for images: %s", err.Error())
} else {
cfg.Logger.Infof("Setting image size to %dMb", size)
spec.Active.Size = uint(size)
spec.Passive.Size = uint(size)
}
return spec, nil
}
// ReadResetSpecFromConfig will return a proper v1.ResetSpec based on an agent Config
@ -400,6 +438,44 @@ func ReadInstallSpecFromConfig(c *Config) (*v1.InstallSpec, error) {
return installSpec, nil
}
// GetSourceSize will try to gather the actual size of the source
// Useful to create the exact size of images and by side effect the partition size
// This helps adjust the size to be juuuuust right.
// It can still be manually override from the cloud config by setting all values manually
// But by default it should adjust the sizes properly
func GetSourceSize(config *Config, source *v1.ImageSource) (int64, error) {
var size int64
var err error
switch {
case source.IsDocker():
size, err = config.ImageExtractor.GetOCIImageSize(source.Value(), config.Platform.String())
case source.IsDir():
err = fsutils.WalkDirFs(config.Fs, source.Value(), func(path string, d fs.DirEntry, err error) error {
if err != nil {
return err
}
info, err := d.Info()
if err != nil {
return err
}
size += info.Size()
return nil
})
case source.IsFile():
file, err := config.Fs.Stat(source.Value())
if err == nil {
size = file.Size()
}
}
// Normalize size to Mb before returning and add 100Mb to round the size from bytes to mb+extra files like grub stuff
if size != 0 {
size = (size / 1000 / 1000) + 100
}
return size, err
}
// ReadUpgradeSpecFromConfig will return a proper v1.UpgradeSpec based on an agent Config
func ReadUpgradeSpecFromConfig(c *Config) (*v1.UpgradeSpec, error) {
sp, err := ReadSpecFromCloudConfig(c, "upgrade")

View File

@ -252,7 +252,7 @@ func (e Elemental) UnmountImage(img *v1.Image) error {
// CreateFileSystemImage creates the image file for config.target
func (e Elemental) CreateFileSystemImage(img *v1.Image) error {
e.config.Logger.Infof("Creating file system image %s", img.File)
e.config.Logger.Infof("Creating file system image %s with size %dMb", img.File, img.Size)
err := fsutils.MkdirAll(e.config.Fs, filepath.Dir(img.File), cnst.DirPerm)
if err != nil {
return err

View File

@ -387,13 +387,13 @@ var _ = Describe("Elemental", Label("elemental"), func() {
"mkpart", "oem", "ext4", "133120", "264191",
}, {"mkfs.ext4", "-L", "COS_OEM", "/some/device2"}, {
"parted", "--script", "--machine", "--", "/some/device", "unit", "s",
"mkpart", "recovery", "ext4", "264192", "6760447",
"mkpart", "recovery", "ext4", "264192", "468991",
}, {"mkfs.ext4", "-L", "COS_RECOVERY", "/some/device3"}, {
"parted", "--script", "--machine", "--", "/some/device", "unit", "s",
"mkpart", "state", "ext4", "6760448", "19548159",
"mkpart", "state", "ext4", "468992", "673791",
}, {"mkfs.ext4", "-L", "COS_STATE", "/some/device4"}, {
"parted", "--script", "--machine", "--", "/some/device", "unit", "s",
"mkpart", "persistent", "ext4", "19548160", "100%",
"mkpart", "persistent", "ext4", "673792", "100%",
}, {"mkfs.ext4", "-L", "COS_PERSISTENT", "/some/device5"},
}

View File

@ -22,6 +22,7 @@ import (
type ImageExtractor interface {
ExtractImage(imageRef, destination, platformRef string) error
GetOCIImageSize(imageRef, platformRef string) (int64, error)
}
type OCIImageExtractor struct{}
@ -31,3 +32,7 @@ var _ ImageExtractor = OCIImageExtractor{}
func (e OCIImageExtractor) ExtractImage(imageRef, destination, platformRef string) error {
return utils.ExtractOCIImage(imageRef, destination, platformRef)
}
func (e OCIImageExtractor) GetOCIImageSize(imageRef, platformRef string) (int64, error) {
return utils.GetOCIImageSize(imageRef, platformRef)
}

View File

@ -20,6 +20,7 @@ limitations under the License.
package fsutils
import (
"errors"
"io/fs"
"os"
"path/filepath"
@ -198,7 +199,7 @@ func WalkDirFs(fs v1.FS, root string, fn fs.WalkDirFunc) error {
} else {
err = walkDir(fs, root, &statDirEntry{info}, fn)
}
if err == filepath.SkipDir {
if errors.Is(err, filepath.SkipDir) {
return nil
}
return err
@ -225,7 +226,7 @@ func walkDir(fs v1.FS, path string, d fs.DirEntry, walkDirFn fs.WalkDirFunc) err
for _, d1 := range dirs {
path1 := filepath.Join(path, d1.Name())
if err := walkDir(fs, path1, d1, walkDirFn); err != nil {
if err == filepath.SkipDir {
if errors.Is(err, filepath.SkipDir) {
break
}
return err

View File

@ -23,6 +23,10 @@ type FakeImageExtractor struct {
SideEffect func(imageRef, destination, platformRef string) error
}
func (f FakeImageExtractor) GetOCIImageSize(imageRef, platformRef string) (int64, error) {
return 0, nil
}
var _ v1.ImageExtractor = FakeImageExtractor{}
func NewFakeImageExtractor(logger v1.Logger) *FakeImageExtractor {