@@ -18,15 +18,16 @@ package config
18
18
19
19
import (
20
20
"fmt"
21
- "github.com/kairos-io/kairos-agent/v2/pkg/utils/fs"
22
- "github.com/kairos-io/kairos-agent/v2/pkg/utils/partitions"
21
+ "io/fs"
23
22
"path/filepath"
24
23
"reflect"
25
24
"strings"
26
25
27
26
"github.com/kairos-io/kairos-agent/v2/internal/common"
28
27
"github.com/kairos-io/kairos-agent/v2/pkg/constants"
29
28
v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1"
29
+ "github.com/kairos-io/kairos-agent/v2/pkg/utils/fs"
30
+ "github.com/kairos-io/kairos-agent/v2/pkg/utils/partitions"
30
31
"github.com/mitchellh/mapstructure"
31
32
"github.com/sanity-io/litter"
32
33
"github.com/sirupsen/logrus"
@@ -95,7 +96,19 @@ func NewInstallSpec(cfg *Config) *v1.InstallSpec {
95
96
Recovery : recoveryImg ,
96
97
Passive : passiveImg ,
97
98
}
98
- // Calculate the partitions sizes automatically based on the images set size
99
+
100
+ // Get the actual source size to calculate the image size and partitions size
101
+ size , err := GetSourceSize (cfg , spec .Active .Source )
102
+ if err != nil {
103
+ cfg .Logger .Warnf ("Failed to infer size for images: %s" , err .Error ())
104
+ } else {
105
+ cfg .Logger .Infof ("Setting image size to %dMb" , size )
106
+ spec .Active .Size = uint (size )
107
+ spec .Passive .Size = uint (size )
108
+ spec .Recovery .Size = uint (size )
109
+ }
110
+
111
+ // Calculate the partitions afterwards so they use the image sizes for the final partition sizes
99
112
spec .Partitions = NewInstallElementalPartitions (spec )
100
113
101
114
return spec
@@ -237,13 +250,26 @@ func NewUpgradeSpec(cfg *Config) (*v1.UpgradeSpec, error) {
237
250
}
238
251
}
239
252
240
- return & v1.UpgradeSpec {
253
+ spec := & v1.UpgradeSpec {
241
254
Active : active ,
242
255
Recovery : recovery ,
243
256
Passive : passive ,
244
257
Partitions : ep ,
245
258
State : installState ,
246
- }, nil
259
+ }
260
+
261
+ // Get the actual source size to calculate the image size and partitions size
262
+ size , err := GetSourceSize (cfg , spec .Active .Source )
263
+ if err != nil {
264
+ cfg .Logger .Warnf ("Failed to infer size for images: %s" , err .Error ())
265
+ } else {
266
+ cfg .Logger .Infof ("Setting image size to %dMb" , size )
267
+ // On upgrade only the active or recovery will be upgraded, so we dont need to override passive
268
+ spec .Active .Size = uint (size )
269
+ spec .Recovery .Size = uint (size )
270
+ }
271
+
272
+ return spec , nil
247
273
}
248
274
249
275
// NewResetSpec returns a ResetSpec struct all based on defaults and current host state
@@ -343,7 +369,7 @@ func NewResetSpec(cfg *Config) (*v1.ResetSpec, error) {
343
369
}
344
370
345
371
activeFile := filepath .Join (ep .State .MountPoint , "cOS" , constants .ActiveImgFile )
346
- return & v1.ResetSpec {
372
+ spec := & v1.ResetSpec {
347
373
Target : target ,
348
374
Partitions : ep ,
349
375
Efi : efiExists ,
@@ -367,7 +393,19 @@ func NewResetSpec(cfg *Config) (*v1.ResetSpec, error) {
367
393
FS : constants .LinuxImgFs ,
368
394
},
369
395
State : installState ,
370
- }, nil
396
+ }
397
+
398
+ // Get the actual source size to calculate the image size and partitions size
399
+ size , err := GetSourceSize (cfg , spec .Active .Source )
400
+ if err != nil {
401
+ cfg .Logger .Warnf ("Failed to infer size for images: %s" , err .Error ())
402
+ } else {
403
+ cfg .Logger .Infof ("Setting image size to %dMb" , size )
404
+ spec .Active .Size = uint (size )
405
+ spec .Passive .Size = uint (size )
406
+ }
407
+
408
+ return spec , nil
371
409
}
372
410
373
411
// ReadResetSpecFromConfig will return a proper v1.ResetSpec based on an agent Config
@@ -400,6 +438,44 @@ func ReadInstallSpecFromConfig(c *Config) (*v1.InstallSpec, error) {
400
438
return installSpec , nil
401
439
}
402
440
441
+ // GetSourceSize will try to gather the actual size of the source
442
+ // Useful to create the exact size of images and by side effect the partition size
443
+ // This helps adjust the size to be juuuuust right.
444
+ // It can still be manually override from the cloud config by setting all values manually
445
+ // But by default it should adjust the sizes properly
446
+ func GetSourceSize (config * Config , source * v1.ImageSource ) (int64 , error ) {
447
+ var size int64
448
+ var err error
449
+
450
+ switch {
451
+ case source .IsDocker ():
452
+ size , err = config .ImageExtractor .GetOCIImageSize (source .Value (), config .Platform .String ())
453
+ case source .IsDir ():
454
+ err = fsutils .WalkDirFs (config .Fs , source .Value (), func (path string , d fs.DirEntry , err error ) error {
455
+ if err != nil {
456
+ return err
457
+ }
458
+ info , err := d .Info ()
459
+ if err != nil {
460
+ return err
461
+ }
462
+ size += info .Size ()
463
+ return nil
464
+ })
465
+
466
+ case source .IsFile ():
467
+ file , err := config .Fs .Stat (source .Value ())
468
+ if err == nil {
469
+ size = file .Size ()
470
+ }
471
+ }
472
+ // Normalize size to Mb before returning and add 100Mb to round the size from bytes to mb+extra files like grub stuff
473
+ if size != 0 {
474
+ size = (size / 1000 / 1000 ) + 100
475
+ }
476
+ return size , err
477
+ }
478
+
403
479
// ReadUpgradeSpecFromConfig will return a proper v1.UpgradeSpec based on an agent Config
404
480
func ReadUpgradeSpecFromConfig (c * Config ) (* v1.UpgradeSpec , error ) {
405
481
sp , err := ReadSpecFromCloudConfig (c , "upgrade" )
0 commit comments