Skip to content

Commit c2ecca1

Browse files
authored
feat(import): add storage_size parameter (#77)
Add optional storage_size parameter to allow manual specification of storage device size when importing images. This solves an issue where compressed images that expand significantly would fail due to insufficient storage space. - Add StorageSize field to import post-processor - Modify storage creation logic to use manual size when specified - Add tests - Update generated HCL2 specs and documentation Signed-off-by: Ville Vesilehto <ville.vesilehto@upcloud.com>
1 parent cd3bf9e commit c2ecca1

File tree

7 files changed

+135
-4
lines changed

7 files changed

+135
-4
lines changed

.web-docs/components/post-processor/upcloud-import/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ Username and password configuration arguments can be omitted if environment vari
3131

3232
- `storage_tier` (string) - The storage tier to use. Available options are `maxiops`, `archive`, and `standard`. Defaults to `maxiops`.
3333

34+
- `storage_size` (int) - The storage size in gigabytes. If not specified, defaults to the image size
35+
(minimum 10GB). When importing compressed images that expand significantly, specify
36+
a larger value to ensure adequate space for the uncompressed content.
37+
3438
- `state_timeout_duration` (duration string | ex: "1h5m2s") - The amount of time to wait for resource state changes. Defaults to `60m`.
3539

3640
<!-- End of code generated from the comments of the Config struct in post-processor/upcloud-import/config.go; -->

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ See updating [Changelog example here](https://keepachangelog.com/en/1.0.0/)
55

66
## [Unreleased]
77

8+
### Added
9+
10+
- `storage_size` parameter to upcloud-import post-processor
11+
812
### Fixed
913

1014
- Update Go version to 1.24.6

docs-partials/post-processor/upcloud-import/Config-not-required.mdx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010

1111
- `storage_tier` (string) - The storage tier to use. Available options are `maxiops`, `archive`, and `standard`. Defaults to `maxiops`.
1212

13+
- `storage_size` (int) - The storage size in gigabytes. If not specified, defaults to the image size
14+
(minimum 10GB). When importing compressed images that expand significantly, specify
15+
a larger value to ensure adequate space for the uncompressed content.
16+
1317
- `state_timeout_duration` (duration string | ex: "1h5m2s") - The amount of time to wait for resource state changes. Defaults to `60m`.
1418

1519
<!-- End of code generated from the comments of the Config struct in post-processor/upcloud-import/config.go; -->

post-processor/upcloud-import/config.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@ type Config struct {
4040
// The storage tier to use. Available options are `maxiops`, `archive`, and `standard`. Defaults to `maxiops`.
4141
StorageTier string `mapstructure:"storage_tier"`
4242

43+
// The storage size in gigabytes. If not specified, defaults to the image size
44+
// (minimum 10GB). When importing compressed images that expand significantly, specify
45+
// a larger value to ensure adequate space for the uncompressed content.
46+
StorageSize int `mapstructure:"storage_size"`
47+
4348
// The amount of time to wait for resource state changes. Defaults to `60m`.
4449
Timeout time.Duration `mapstructure:"state_timeout_duration"`
4550

@@ -92,6 +97,20 @@ func (c *Config) validate() *packer.MultiError {
9297
errs = packer.MultiErrorAppend(errs, authErrs.Errors...)
9398
}
9499

100+
// Validate storage size if specified
101+
if c.StorageSize > 0 {
102+
if c.StorageSize < storageMinSizeGB {
103+
errs = packer.MultiErrorAppend(
104+
errs, fmt.Errorf("'storage_size' must be at least %dGB", storageMinSizeGB),
105+
)
106+
}
107+
if c.StorageSize > storageMaxSizeGB {
108+
errs = packer.MultiErrorAppend(
109+
errs, fmt.Errorf("'storage_size' cannot exceed %dGB", storageMaxSizeGB),
110+
)
111+
}
112+
}
113+
95114
return errs
96115
}
97116

post-processor/upcloud-import/config.hcl2spec.go

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

post-processor/upcloud-import/config_test.go

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,3 +286,95 @@ func TestNewConfig_StorageTierDefault(t *testing.T) {
286286
require.NotNil(t, c)
287287
assert.Equal(t, "maxiops", c.StorageTier)
288288
}
289+
290+
func TestNewConfig_StorageSize(t *testing.T) {
291+
t.Parallel()
292+
293+
tests := []struct {
294+
name string
295+
storageSize interface{} // Use interface{} to test both presence and absence
296+
expectError bool
297+
expectedSize int
298+
errorContains string
299+
}{
300+
{
301+
name: "not specified - should default to 0",
302+
storageSize: nil, // Don't include storage_size in config
303+
expectError: false,
304+
expectedSize: 0,
305+
},
306+
{
307+
name: "valid size",
308+
storageSize: 50,
309+
expectError: false,
310+
expectedSize: 50,
311+
},
312+
{
313+
name: "minimum valid size",
314+
storageSize: 10,
315+
expectError: false,
316+
expectedSize: 10,
317+
},
318+
{
319+
name: "maximum valid size",
320+
storageSize: 4096,
321+
expectError: false,
322+
expectedSize: 4096,
323+
},
324+
{
325+
name: "too small - below minimum",
326+
storageSize: 5,
327+
expectError: true,
328+
errorContains: "'storage_size' must be at least 10GB",
329+
},
330+
{
331+
name: "too large - above maximum",
332+
storageSize: 5000,
333+
expectError: true,
334+
errorContains: "'storage_size' cannot exceed 4096GB",
335+
},
336+
{
337+
name: "zero - invalid",
338+
storageSize: 0,
339+
expectError: false, // 0 means not specified, which is valid
340+
expectedSize: 0,
341+
},
342+
{
343+
name: "negative - invalid",
344+
storageSize: -10,
345+
expectError: false, // Negative values are treated as 0 (not specified)
346+
expectedSize: -10, // The value is stored as-is, validation only checks > 0
347+
},
348+
}
349+
350+
for _, tt := range tests {
351+
t.Run(tt.name, func(t *testing.T) {
352+
t.Parallel()
353+
354+
configMap := map[string]interface{}{
355+
"token": "test-token",
356+
"zones": []string{"fi-hel1"},
357+
"template_name": "my-template",
358+
}
359+
360+
if tt.storageSize != nil {
361+
configMap["storage_size"] = tt.storageSize
362+
}
363+
364+
c, err := upcloudimport.NewConfig([]interface{}{configMap}...)
365+
366+
if tt.expectError {
367+
assert.Error(t, err)
368+
if tt.errorContains != "" {
369+
assert.Contains(t, err.Error(), tt.errorContains)
370+
}
371+
} else {
372+
assert.NoError(t, err)
373+
require.NotNil(t, c)
374+
assert.Equal(t, tt.expectedSize, c.StorageSize)
375+
}
376+
377+
require.NotNil(t, c)
378+
})
379+
}
380+
}

post-processor/upcloud-import/step_create_storage.go

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,17 @@ func (s *stepCreateStorage) Run(ctx context.Context, state multistep.StateBag) m
3030
if err != nil {
3131
return haltOnError(ui, state, err)
3232
}
33-
size := s.image.SizeGB()
34-
if size < storageMinSizeGB {
35-
size = storageMinSizeGB
33+
var size int
34+
if s.postProcessor.config.StorageSize > 0 {
35+
size = s.postProcessor.config.StorageSize
36+
ui.Say(fmt.Sprintf("Creating storage device (%dGB) for '%s' image using manually specified size", size, s.image.File()))
37+
} else {
38+
size = s.image.SizeGB()
39+
if size < storageMinSizeGB {
40+
size = storageMinSizeGB
41+
}
42+
ui.Say(fmt.Sprintf("Creating storage device (%dGB) for '%s' image", size, s.image.File()))
3643
}
37-
ui.Say(fmt.Sprintf("Creating storage device (%dGB) for '%s' image", size, s.image.File()))
3844
storage, err := s.postProcessor.driver.CreateTemplateStorage(ctx,
3945
fmt.Sprintf("%s-%s", BuilderID, time.Now().Format(timestampSuffixLayout)),
4046
s.postProcessor.config.Zones[0],

0 commit comments

Comments
 (0)