mirror of
https://github.com/kairos-io/kairos-agent.git
synced 2025-08-21 01:34:03 +00:00
Auto calculate image size on actions (#122)
This commit is contained in:
parent
3e9befa230
commit
4108aa929e
2
go.mod
2
go.mod
@ -12,7 +12,7 @@ require (
|
|||||||
github.com/hashicorp/go-multierror v1.1.1
|
github.com/hashicorp/go-multierror v1.1.1
|
||||||
github.com/jaypipes/ghw v0.12.0
|
github.com/jaypipes/ghw v0.12.0
|
||||||
github.com/joho/godotenv v1.5.1
|
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/labstack/echo/v4 v4.10.2
|
||||||
github.com/mitchellh/mapstructure v1.5.0
|
github.com/mitchellh/mapstructure v1.5.0
|
||||||
github.com/mudler/go-nodepair v0.0.0-20221223092639-ba399a66fdfb
|
github.com/mudler/go-nodepair v0.0.0-20221223092639-ba399a66fdfb
|
||||||
|
2
go.sum
2
go.sum
@ -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.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 h1:+EWuO4gWMzBa81s8gbF1L7wOvEjbph1z8UkfUrMyvxc=
|
||||||
github.com/kairos-io/kairos-sdk v0.0.11/go.mod h1:AK9poWisuhnzri04diXnTG8L7EkOSUArSeeDn2LYFU0=
|
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 h1:qq2nCpSrXrmvDGRxW0ruW9BVEV1CN2a9YDOExdt+U0o=
|
||||||
github.com/kbinani/screenshot v0.0.0-20210720154843-7d3a670d8329/go.mod h1:2VPVQDR4wO7KXHwP+DAypEy67rXf+okUx2zjgpCxZw4=
|
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=
|
github.com/kendru/darwin/go/depgraph v0.0.0-20221105232959-877d6a81060c h1:eKb4PqwAMhlqwXw0W3atpKaYaPGlXE/Fwh+xpCEYaPk=
|
||||||
|
@ -18,8 +18,7 @@ package config
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/kairos-io/kairos-agent/v2/pkg/utils/fs"
|
"io/fs"
|
||||||
"github.com/kairos-io/kairos-agent/v2/pkg/utils/partitions"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
@ -27,6 +26,8 @@ import (
|
|||||||
"github.com/kairos-io/kairos-agent/v2/internal/common"
|
"github.com/kairos-io/kairos-agent/v2/internal/common"
|
||||||
"github.com/kairos-io/kairos-agent/v2/pkg/constants"
|
"github.com/kairos-io/kairos-agent/v2/pkg/constants"
|
||||||
v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1"
|
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/mitchellh/mapstructure"
|
||||||
"github.com/sanity-io/litter"
|
"github.com/sanity-io/litter"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
@ -95,7 +96,19 @@ func NewInstallSpec(cfg *Config) *v1.InstallSpec {
|
|||||||
Recovery: recoveryImg,
|
Recovery: recoveryImg,
|
||||||
Passive: passiveImg,
|
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)
|
spec.Partitions = NewInstallElementalPartitions(spec)
|
||||||
|
|
||||||
return spec
|
return spec
|
||||||
@ -237,13 +250,26 @@ func NewUpgradeSpec(cfg *Config) (*v1.UpgradeSpec, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &v1.UpgradeSpec{
|
spec := &v1.UpgradeSpec{
|
||||||
Active: active,
|
Active: active,
|
||||||
Recovery: recovery,
|
Recovery: recovery,
|
||||||
Passive: passive,
|
Passive: passive,
|
||||||
Partitions: ep,
|
Partitions: ep,
|
||||||
State: installState,
|
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
|
// 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)
|
activeFile := filepath.Join(ep.State.MountPoint, "cOS", constants.ActiveImgFile)
|
||||||
return &v1.ResetSpec{
|
spec := &v1.ResetSpec{
|
||||||
Target: target,
|
Target: target,
|
||||||
Partitions: ep,
|
Partitions: ep,
|
||||||
Efi: efiExists,
|
Efi: efiExists,
|
||||||
@ -367,7 +393,19 @@ func NewResetSpec(cfg *Config) (*v1.ResetSpec, error) {
|
|||||||
FS: constants.LinuxImgFs,
|
FS: constants.LinuxImgFs,
|
||||||
},
|
},
|
||||||
State: installState,
|
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
|
// 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
|
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
|
// ReadUpgradeSpecFromConfig will return a proper v1.UpgradeSpec based on an agent Config
|
||||||
func ReadUpgradeSpecFromConfig(c *Config) (*v1.UpgradeSpec, error) {
|
func ReadUpgradeSpecFromConfig(c *Config) (*v1.UpgradeSpec, error) {
|
||||||
sp, err := ReadSpecFromCloudConfig(c, "upgrade")
|
sp, err := ReadSpecFromCloudConfig(c, "upgrade")
|
||||||
|
@ -252,7 +252,7 @@ func (e Elemental) UnmountImage(img *v1.Image) error {
|
|||||||
|
|
||||||
// CreateFileSystemImage creates the image file for config.target
|
// CreateFileSystemImage creates the image file for config.target
|
||||||
func (e Elemental) CreateFileSystemImage(img *v1.Image) error {
|
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)
|
err := fsutils.MkdirAll(e.config.Fs, filepath.Dir(img.File), cnst.DirPerm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -387,13 +387,13 @@ var _ = Describe("Elemental", Label("elemental"), func() {
|
|||||||
"mkpart", "oem", "ext4", "133120", "264191",
|
"mkpart", "oem", "ext4", "133120", "264191",
|
||||||
}, {"mkfs.ext4", "-L", "COS_OEM", "/some/device2"}, {
|
}, {"mkfs.ext4", "-L", "COS_OEM", "/some/device2"}, {
|
||||||
"parted", "--script", "--machine", "--", "/some/device", "unit", "s",
|
"parted", "--script", "--machine", "--", "/some/device", "unit", "s",
|
||||||
"mkpart", "recovery", "ext4", "264192", "6760447",
|
"mkpart", "recovery", "ext4", "264192", "468991",
|
||||||
}, {"mkfs.ext4", "-L", "COS_RECOVERY", "/some/device3"}, {
|
}, {"mkfs.ext4", "-L", "COS_RECOVERY", "/some/device3"}, {
|
||||||
"parted", "--script", "--machine", "--", "/some/device", "unit", "s",
|
"parted", "--script", "--machine", "--", "/some/device", "unit", "s",
|
||||||
"mkpart", "state", "ext4", "6760448", "19548159",
|
"mkpart", "state", "ext4", "468992", "673791",
|
||||||
}, {"mkfs.ext4", "-L", "COS_STATE", "/some/device4"}, {
|
}, {"mkfs.ext4", "-L", "COS_STATE", "/some/device4"}, {
|
||||||
"parted", "--script", "--machine", "--", "/some/device", "unit", "s",
|
"parted", "--script", "--machine", "--", "/some/device", "unit", "s",
|
||||||
"mkpart", "persistent", "ext4", "19548160", "100%",
|
"mkpart", "persistent", "ext4", "673792", "100%",
|
||||||
}, {"mkfs.ext4", "-L", "COS_PERSISTENT", "/some/device5"},
|
}, {"mkfs.ext4", "-L", "COS_PERSISTENT", "/some/device5"},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@ import (
|
|||||||
|
|
||||||
type ImageExtractor interface {
|
type ImageExtractor interface {
|
||||||
ExtractImage(imageRef, destination, platformRef string) error
|
ExtractImage(imageRef, destination, platformRef string) error
|
||||||
|
GetOCIImageSize(imageRef, platformRef string) (int64, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type OCIImageExtractor struct{}
|
type OCIImageExtractor struct{}
|
||||||
@ -31,3 +32,7 @@ var _ ImageExtractor = OCIImageExtractor{}
|
|||||||
func (e OCIImageExtractor) ExtractImage(imageRef, destination, platformRef string) error {
|
func (e OCIImageExtractor) ExtractImage(imageRef, destination, platformRef string) error {
|
||||||
return utils.ExtractOCIImage(imageRef, destination, platformRef)
|
return utils.ExtractOCIImage(imageRef, destination, platformRef)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e OCIImageExtractor) GetOCIImageSize(imageRef, platformRef string) (int64, error) {
|
||||||
|
return utils.GetOCIImageSize(imageRef, platformRef)
|
||||||
|
}
|
||||||
|
@ -20,6 +20,7 @@ limitations under the License.
|
|||||||
package fsutils
|
package fsutils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@ -198,7 +199,7 @@ func WalkDirFs(fs v1.FS, root string, fn fs.WalkDirFunc) error {
|
|||||||
} else {
|
} else {
|
||||||
err = walkDir(fs, root, &statDirEntry{info}, fn)
|
err = walkDir(fs, root, &statDirEntry{info}, fn)
|
||||||
}
|
}
|
||||||
if err == filepath.SkipDir {
|
if errors.Is(err, filepath.SkipDir) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
@ -225,7 +226,7 @@ func walkDir(fs v1.FS, path string, d fs.DirEntry, walkDirFn fs.WalkDirFunc) err
|
|||||||
for _, d1 := range dirs {
|
for _, d1 := range dirs {
|
||||||
path1 := filepath.Join(path, d1.Name())
|
path1 := filepath.Join(path, d1.Name())
|
||||||
if err := walkDir(fs, path1, d1, walkDirFn); err != nil {
|
if err := walkDir(fs, path1, d1, walkDirFn); err != nil {
|
||||||
if err == filepath.SkipDir {
|
if errors.Is(err, filepath.SkipDir) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
|
@ -23,6 +23,10 @@ type FakeImageExtractor struct {
|
|||||||
SideEffect func(imageRef, destination, platformRef string) error
|
SideEffect func(imageRef, destination, platformRef string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f FakeImageExtractor) GetOCIImageSize(imageRef, platformRef string) (int64, error) {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
var _ v1.ImageExtractor = FakeImageExtractor{}
|
var _ v1.ImageExtractor = FakeImageExtractor{}
|
||||||
|
|
||||||
func NewFakeImageExtractor(logger v1.Logger) *FakeImageExtractor {
|
func NewFakeImageExtractor(logger v1.Logger) *FakeImageExtractor {
|
||||||
|
Loading…
Reference in New Issue
Block a user