diff --git a/.web-docs/components/builder/upcloud/README.md b/.web-docs/components/builder/upcloud/README.md index 9c6d071..7e23126 100644 --- a/.web-docs/components/builder/upcloud/README.md +++ b/.web-docs/components/builder/upcloud/README.md @@ -36,6 +36,8 @@ The upcloud builder is used to generate storage templates on UpCloud. - `token` (string) - The API token to use when interfacing with the UpCloud API. This is mutually exclusive with username and password. +- `server_plan` (string) - Server plan to use for the builder server. Defaults to `1xCPU-2GB`. + - `storage_name` (string) - The name of the storage that will be used to find the first matching storage in the list of existing templates. Note that `storage_uuid` parameter has higher priority. You should use either `storage_uuid` or `storage_name` for not strict matching (e.g "ubuntu server 24.04"). diff --git a/CHANGELOG.md b/CHANGELOG.md index 3158daf..7476dd1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ See updating [Changelog example here](https://keepachangelog.com/en/1.0.0/) ## [Unreleased] +### Added + +- `server_plan` parameter to builder configuration for selecting server plan to use during build. + ## [1.9.2] - 2025-10-16 ### Changed diff --git a/builder/upcloud/artifact.go b/builder/upcloud/artifact.go index f94db7e..a7ed1d8 100644 --- a/builder/upcloud/artifact.go +++ b/builder/upcloud/artifact.go @@ -32,7 +32,7 @@ func (a *Artifact) Files() []string { } func (a *Artifact) Id() string { //nolint:revive // method is required by packer-plugin-sdk - result := []string{} + result := make([]string, 0, len(a.Templates)) for _, t := range a.Templates { result = append(result, t.UUID) } diff --git a/builder/upcloud/artifact_test.go b/builder/upcloud/artifact_test.go index 97bff0d..9de2569 100644 --- a/builder/upcloud/artifact_test.go +++ b/builder/upcloud/artifact_test.go @@ -24,7 +24,7 @@ func TestArtifact_Id(t *testing.T) { uuid2 := "some-uuid-2" expected := fmt.Sprintf("%s,%s", uuid1, uuid2) - templates := []*upcloud.Storage{} + templates := make([]*upcloud.Storage, 0, 2) templates = append(templates, &upcloud.Storage{UUID: uuid1}, &upcloud.Storage{UUID: uuid2}) a := &Artifact{Templates: templates} @@ -39,7 +39,7 @@ func TestArtifact_String(t *testing.T) { t.Parallel() expected := `Storage template created, UUID: some-uuid` - templates := []*upcloud.Storage{} + templates := make([]*upcloud.Storage, 0, 1) templates = append(templates, &upcloud.Storage{UUID: "some-uuid"}) a := &Artifact{Templates: templates} @@ -52,7 +52,7 @@ func TestArtifact_String(t *testing.T) { func TestArtifact_Metadata(t *testing.T) { t.Parallel() - templates := []*upcloud.Storage{} + templates := make([]*upcloud.Storage, 0, 2) templates = append(templates, &upcloud.Storage{ UUID: "some-uuid", diff --git a/builder/upcloud/builder_acc_test.go b/builder/upcloud/builder_acc_test.go index f316977..fa00cf2 100644 --- a/builder/upcloud/builder_acc_test.go +++ b/builder/upcloud/builder_acc_test.go @@ -38,8 +38,8 @@ var testBuilderStorageName string //go:embed test-fixtures/json/networking.json var testBuilderNetworking string -//go:embed test-fixtures/json/basic_standard_tier.json -var testBuilderBasicStandardTier string +//go:embed test-fixtures/json/plan_and_tier.json +var testBuilderPlanAndTier string func TestBuilderAcc_default(t *testing.T) { t.Parallel() @@ -78,12 +78,12 @@ func TestBuilderAcc_storageName(t *testing.T) { acctest.TestPlugin(t, testCase) } -func TestBuilderAcc_standardTier(t *testing.T) { +func TestBuilderAcc_planAndTier(t *testing.T) { t.Parallel() testAccPreCheck(t) testCase := &acctest.PluginTestCase{ Name: t.Name(), - Template: testBuilderBasicStandardTier, + Template: testBuilderPlanAndTier, Check: checkTestResult(t), Teardown: teardown(t, t.Name()), } @@ -107,6 +107,9 @@ func TestBuilderAcc_networking(t *testing.T) { //go:embed test-fixtures/hcl2/basic.pkr.hcl var testBuildBasicHcl string +//go:embed test-fixtures/hcl2/plan_and_tier.pkr.hcl +var testBuilderPlanAndTierHcl string + //go:embed test-fixtures/hcl2/storage-uuid.pkr.hcl var testBuilderStorageUUIDHcl string @@ -128,6 +131,18 @@ func TestBuilderAcc_default_hcl(t *testing.T) { acctest.TestPlugin(t, testCase) } +func TestBuilderAcc_planAndTier_hcl(t *testing.T) { + t.Parallel() + testAccPreCheck(t) + testCase := &acctest.PluginTestCase{ + Name: t.Name(), + Template: testBuilderPlanAndTierHcl, + Check: checkTestResult(t), + Teardown: teardown(t, t.Name()), + } + acctest.TestPlugin(t, testCase) +} + func TestBuilderAcc_storageUuid_hcl(t *testing.T) { t.Parallel() testAccPreCheck(t) @@ -152,7 +167,7 @@ func TestBuilderAcc_storageName_hcl(t *testing.T) { acctest.TestPlugin(t, testCase) } -func TestBuilderAcc_network_interfaces(t *testing.T) { +func TestBuilderAcc_network_interfaces_hcl(t *testing.T) { t.Parallel() testAccPreCheck(t) testCase := &acctest.PluginTestCase{ diff --git a/builder/upcloud/config.go b/builder/upcloud/config.go index 11eb74d..9d25b7e 100644 --- a/builder/upcloud/config.go +++ b/builder/upcloud/config.go @@ -74,6 +74,9 @@ type Config struct { // The zone in which the server and template should be created (e.g. nl-ams1). Zone string `mapstructure:"zone" required:"true"` + // Server plan to use for the builder server. Defaults to `1xCPU-2GB`. + ServerPlan string `mapstructure:"server_plan"` + // The UUID of the storage you want to use as a template when creating the server. // // Optionally use `storage_name` parameter to find matching storage diff --git a/builder/upcloud/config.hcl2spec.go b/builder/upcloud/config.hcl2spec.go index 9473784..f27c57e 100644 --- a/builder/upcloud/config.hcl2spec.go +++ b/builder/upcloud/config.hcl2spec.go @@ -71,6 +71,7 @@ type FlatConfig struct { Password *string `mapstructure:"password" cty:"password" hcl:"password"` Token *string `mapstructure:"token" cty:"token" hcl:"token"` Zone *string `mapstructure:"zone" required:"true" cty:"zone" hcl:"zone"` + ServerPlan *string `mapstructure:"server_plan" cty:"server_plan" hcl:"server_plan"` StorageUUID *string `mapstructure:"storage_uuid" required:"true" cty:"storage_uuid" hcl:"storage_uuid"` StorageName *string `mapstructure:"storage_name" cty:"storage_name" hcl:"storage_name"` TemplatePrefix *string `mapstructure:"template_prefix" cty:"template_prefix" hcl:"template_prefix"` @@ -158,6 +159,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { "password": &hcldec.AttrSpec{Name: "password", Type: cty.String, Required: false}, "token": &hcldec.AttrSpec{Name: "token", Type: cty.String, Required: false}, "zone": &hcldec.AttrSpec{Name: "zone", Type: cty.String, Required: false}, + "server_plan": &hcldec.AttrSpec{Name: "server_plan", Type: cty.String, Required: false}, "storage_uuid": &hcldec.AttrSpec{Name: "storage_uuid", Type: cty.String, Required: false}, "storage_name": &hcldec.AttrSpec{Name: "storage_name", Type: cty.String, Required: false}, "template_prefix": &hcldec.AttrSpec{Name: "template_prefix", Type: cty.String, Required: false}, diff --git a/builder/upcloud/step_create_server.go b/builder/upcloud/step_create_server.go index b16c84b..dbb304c 100644 --- a/builder/upcloud/step_create_server.go +++ b/builder/upcloud/step_create_server.go @@ -93,6 +93,7 @@ func (s *StepCreateServer) createServer(ctx context.Context, ui packer.Ui, drv d } response, err := drv.CreateServer(ctx, &driver.ServerOpts{ + ServerPlan: s.Config.ServerPlan, StorageUUID: storage.UUID, StorageSize: s.Config.StorageSize, Zone: s.Config.Zone, diff --git a/builder/upcloud/test-fixtures/hcl2/basic_standard_tier.hcl b/builder/upcloud/test-fixtures/hcl2/plan_and_tier.pkr.hcl similarity index 87% rename from builder/upcloud/test-fixtures/hcl2/basic_standard_tier.hcl rename to builder/upcloud/test-fixtures/hcl2/plan_and_tier.pkr.hcl index 1202ef4..9bb8bdc 100644 --- a/builder/upcloud/test-fixtures/hcl2/basic_standard_tier.hcl +++ b/builder/upcloud/test-fixtures/hcl2/plan_and_tier.pkr.hcl @@ -1,9 +1,10 @@ source "upcloud" "standard-tier" { + server_plan = "2xCPU-4GB" storage_uuid = "01000000-0000-4000-8000-000150020100" # Rocky Linux 9 - zone = "pl-waw1" storage_tier = "standard" + zone = "pl-waw1" } build { sources = ["source.upcloud.standard-tier"] -} \ No newline at end of file +} \ No newline at end of file diff --git a/builder/upcloud/test-fixtures/json/basic_standard_tier.json b/builder/upcloud/test-fixtures/json/plan_and_tier.json similarity index 83% rename from builder/upcloud/test-fixtures/json/basic_standard_tier.json rename to builder/upcloud/test-fixtures/json/plan_and_tier.json index 8088bb7..91fdcee 100644 --- a/builder/upcloud/test-fixtures/json/basic_standard_tier.json +++ b/builder/upcloud/test-fixtures/json/plan_and_tier.json @@ -2,6 +2,7 @@ "builders": [{ "type": "upcloud", "zone": "nl-ams1", + "server_plan": "2xCPU-4GB", "storage_uuid": "01000000-0000-4000-8000-000150020100", "storage_tier": "standard" }] diff --git a/builder/upcloud/utils.go b/builder/upcloud/utils.go index bb573d7..986b91c 100644 --- a/builder/upcloud/utils.go +++ b/builder/upcloud/utils.go @@ -63,9 +63,9 @@ func sshHostCallback(state multistep.StateBag) (string, error) { } func convertNetworkTypes(rawNetworking []NetworkInterface) []request.CreateServerInterface { - networking := []request.CreateServerInterface{} + networking := make([]request.CreateServerInterface, 0, len(rawNetworking)) for _, iface := range rawNetworking { - ips := []request.CreateServerIPAddress{} + ips := make([]request.CreateServerIPAddress, 0, len(iface.IPAddresses)) for _, ip := range iface.IPAddresses { ips = append(ips, request.CreateServerIPAddress{Family: ip.Family, Address: ip.Address}) } diff --git a/docs-partials/builder/upcloud/Config-not-required.mdx b/docs-partials/builder/upcloud/Config-not-required.mdx index 0e6160b..8a577ad 100644 --- a/docs-partials/builder/upcloud/Config-not-required.mdx +++ b/docs-partials/builder/upcloud/Config-not-required.mdx @@ -6,6 +6,8 @@ - `token` (string) - The API token to use when interfacing with the UpCloud API. This is mutually exclusive with username and password. +- `server_plan` (string) - Server plan to use for the builder server. Defaults to `1xCPU-2GB`. + - `storage_name` (string) - The name of the storage that will be used to find the first matching storage in the list of existing templates. Note that `storage_uuid` parameter has higher priority. You should use either `storage_uuid` or `storage_name` for not strict matching (e.g "ubuntu server 24.04"). diff --git a/internal/driver/driver.go b/internal/driver/driver.go index 538f848..0c56366 100644 --- a/internal/driver/driver.go +++ b/internal/driver/driver.go @@ -82,6 +82,7 @@ type ( } ServerOpts struct { + ServerPlan string StorageUUID string StorageSize int Zone string @@ -409,13 +410,17 @@ func (d *driver) GetServerStorage(ctx context.Context, serverUUID string) (*upcl func (d *driver) prepareCreateRequest(opts *ServerOpts) *request.CreateServerRequest { title := fmt.Sprintf("packer-%s-%s", DefaultHostname, getNowString()) titleDisk := fmt.Sprintf("%s-disk1", DefaultHostname) + plan := opts.ServerPlan + if plan == "" { + plan = DefaultPlan + } request := request.CreateServerRequest{ Title: title, Hostname: DefaultHostname, Zone: opts.Zone, PasswordDelivery: request.PasswordDeliveryNone, - Plan: DefaultPlan, + Plan: plan, StorageDevices: []request.CreateServerStorageDevice{ { Action: request.CreateServerStorageDeviceActionClone, diff --git a/post-processor/upcloud-import/config_test.go b/post-processor/upcloud-import/config_test.go index 0fa54ac..cae48e5 100644 --- a/post-processor/upcloud-import/config_test.go +++ b/post-processor/upcloud-import/config_test.go @@ -60,8 +60,8 @@ func TestNewConfig_BothAuthMethods(t *testing.T) { assert.NoError(t, err) assert.Equal(t, "test-api-token", c.Token) - assert.Equal(t, "", c.Username) - assert.Equal(t, "", c.Password) + assert.Empty(t, c.Username) + assert.Empty(t, c.Password) } func TestNewConfig_NoAuthMethods(t *testing.T) {