diff --git a/docs/resources/dedicated_server.md b/docs/resources/dedicated_server.md index 198dc6302..4fa4001de 100644 --- a/docs/resources/dedicated_server.md +++ b/docs/resources/dedicated_server.md @@ -91,8 +91,9 @@ resource "ovh_dedicated_server" "server" { * `label` - (Required) Identifier of the resource * `value` - (Required) Path to the resource in API.OVH.COM * `service_name` - (Optional, Forces replacement) The service_name of your dedicated server. This field can be used to avoid ordering a dedicated server at creation and just create the resource using an already existing service +* `range` - (Optional) Range of the dedicated server to order. Can be `standard` or `eco`. Defaults to `standard` -~> **Note** To get the available plans, you can use the API console to first [create a cart](https://eu.api.ovh.com/console/?section=%2Forder&branch=v1#post-/order/cart) and then use the created cart ID to fetch the available plans using [the following call](https://eu.api.ovh.com/console/?section=%2Forder&branch=v1#get-/order/cart/-cartId-/baremetalServers). Once you've found the right plan, you can use [this call](https://eu.api.ovh.com/console/?section=%2Forder&branch=v1#get-/order/cart/-cartId-/baremetalServers/options) to get the available options for this plan. +~> **Note** To get the available plans, you can use the API console to first [create a cart](https://eu.api.ovh.com/console/?section=%2Forder&branch=v1#post-/order/cart) and then use the created cart ID to fetch the available plans using [the following call](https://eu.api.ovh.com/console/?section=%2Forder&branch=v1#get-/order/cart/-cartId-/baremetalServers) (or `/order/cart/{cartId}/eco` for eco servers). Once you've found the right plan, you can use [this call](https://eu.api.ovh.com/console/?section=%2Forder&branch=v1#get-/order/cart/-cartId-/baremetalServers/options) to get the available options for this plan. ### Editable fields of a dedicated server diff --git a/ovh/provider_test.go b/ovh/provider_test.go index ed6b0f965..b4c82cdb4 100644 --- a/ovh/provider_test.go +++ b/ovh/provider_test.go @@ -472,6 +472,11 @@ func testAccPreCheckOrderDedicatedServer(t *testing.T) { checkEnvOrSkip(t, "OVH_TESTACC_ORDER_DEDICATED_SERVER") } +func testAccPreCheckOrderDedicatedServerEco(t *testing.T) { + testAccPreCheckCredentials(t) + checkEnvOrSkip(t, "OVH_TESTACC_ORDER_DEDICATED_SERVER_ECO") +} + func testAccPreCheckVPS(t *testing.T) { testAccPreCheckCredentials(t) checkEnvOrSkip(t, "OVH_VPS") diff --git a/ovh/resource_dedicated_server.go b/ovh/resource_dedicated_server.go index 1f7c75ef1..eb57a9f25 100644 --- a/ovh/resource_dedicated_server.go +++ b/ovh/resource_dedicated_server.go @@ -74,7 +74,13 @@ func (r *dedicatedServerResource) Create(ctx context.Context, req resource.Creat // If service_name is not provided, it means dedicated server has to be ordered if data.ServiceName.IsNull() || data.ServiceName.IsUnknown() { order := data.ToOrder() - if err := orderCreate(order, r.config, "baremetalServers", false, defaultOrderTimeout); err != nil { + // Map the user-facing "range" attribute to the API range type. + // "standard" (default) -> "baremetalServers", "eco" -> "eco" + rangeType := "baremetalServers" + if !data.Range.IsNull() && !data.Range.IsUnknown() && data.Range.ValueString() == "eco" { + rangeType = "eco" + } + if err := orderCreate(order, r.config, rangeType, false, defaultOrderTimeout); err != nil { resp.Diagnostics.AddError("failed to create order", err.Error()) return } diff --git a/ovh/resource_dedicated_server_gen.go b/ovh/resource_dedicated_server_gen.go index b66e96d34..85093343a 100644 --- a/ovh/resource_dedicated_server_gen.go +++ b/ovh/resource_dedicated_server_gen.go @@ -376,6 +376,18 @@ func DedicatedServerResourceSchema(ctx context.Context) schema.Schema { Description: "Defines whether the server should not be reinstalled when importing the resource", MarkdownDescription: "Defines whether the server should not be reinstalled when importing the resource", }, + "range": schema.StringAttribute{ + CustomType: ovhtypes.TfStringType{}, + Optional: true, + Description: "Range of the dedicated server to order. Can be 'standard' or 'eco'. Defaults to 'standard'", + MarkdownDescription: "Range of the dedicated server to order. Can be `standard` or `eco`. Defaults to `standard`", + Validators: []validator.String{ + stringvalidator.OneOf( + "standard", + "eco", + ), + }, + }, "region": schema.StringAttribute{ CustomType: ovhtypes.TfStringType{}, Computed: true, @@ -719,6 +731,7 @@ type DedicatedServerModel struct { Rack ovhtypes.TfStringValue `tfsdk:"rack" json:"rack"` PreventInstallOnCreate ovhtypes.TfBoolValue `tfsdk:"prevent_install_on_create" json:"-"` PreventInstallOnImport ovhtypes.TfBoolValue `tfsdk:"prevent_install_on_import" json:"-"` + Range ovhtypes.TfStringValue `tfsdk:"range" json:"-"` Region ovhtypes.TfStringValue `tfsdk:"region" json:"region"` RescueMail ovhtypes.TfStringValue `tfsdk:"rescue_mail" json:"rescueMail"` RescueSshKey ovhtypes.TfStringValue `tfsdk:"rescue_ssh_key" json:"rescueSshKey"` @@ -838,6 +851,10 @@ func (v *DedicatedServerModel) MergeWith(other *DedicatedServerModel) { v.PreventInstallOnImport = other.PreventInstallOnImport } + if (v.Range.IsUnknown() || v.Range.IsNull()) && !other.Range.IsUnknown() { + v.Range = other.Range + } + if (v.Region.IsUnknown() || v.Region.IsNull()) && !other.Region.IsUnknown() { v.Region = other.Region } diff --git a/ovh/resource_dedicated_server_test.go b/ovh/resource_dedicated_server_test.go index baf87eadf..57225b121 100644 --- a/ovh/resource_dedicated_server_test.go +++ b/ovh/resource_dedicated_server_test.go @@ -136,7 +136,153 @@ func TestAccDedicatedServer_basic(t *testing.T) { ImportStateVerify: true, ImportStateVerifyIdentifierAttribute: "service_name", ImportStateVerifyIgnore: []string{ - "display_name", "order", "ovh_subsidiary", "plan", "plan_option", + "display_name", "order", "ovh_subsidiary", "plan", "plan_option", "range", + }, + ImportStateIdFunc: func(s *terraform.State) (string, error) { + service, ok := s.RootModule().Resources["ovh_dedicated_server.server"] + if !ok { + return "", errors.New("ovh_dedicated_server.server not found") + } + return service.Primary.Attributes["service_name"], nil + }, + }, + }, + }) +} + +func dedicatedServerEcoResourceTestConfig(updated bool) string { + var ( + monitoring = true + noIntervention = false + operatingSystem = "debian11_64" + displayName = "First display name" + efiBootloaderPath = "" + ) + + if updated { + monitoring = false + noIntervention = true + operatingSystem = "debian12_64" + displayName = "Second display name" + efiBootloaderPath = `\\efi\\debian\\grubx64.efi` + } + + return fmt.Sprintf(` + data "ovh_me" "account" {} + + resource "ovh_dedicated_server" "server" { + ovh_subsidiary = data.ovh_me.account.ovh_subsidiary + range = "eco" + monitoring = %t + no_intervention = %t + os = "%s" + display_name = "%s" + efi_bootloader_path = "%s" + plan = [ + { + plan_code = "24sys012" + duration = "P1M" + pricing_mode = "default" + + configuration = [ + { + label = "dedicated_datacenter" + value = "rbx" + }, + { + label = "dedicated_os" + value = "none_64.en" + }, + { + label = "region" + value = "europe" + } + ] + } + ] + + plan_option = [ + { + duration = "P1M" + plan_code = "softraid-2x512nvme-24sys" + pricing_mode = "default" + quantity = 1 + }, + { + duration = "P1M" + plan_code = "vrack-bandwidth-500-24sys" + pricing_mode = "default" + quantity = 1 + }, + { + duration = "P1M" + plan_code = "bandwidth-1000-24sys" + pricing_mode = "default" + quantity = 1 + }, + { + duration = "P1M" + plan_code = "ram-32g-ecc-2666-24sys" + pricing_mode = "default" + quantity = 1 + } + ] + } + `, monitoring, noIntervention, operatingSystem, displayName, efiBootloaderPath) +} + +func TestAccDedicatedServer_eco(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheckOrderDedicatedServerEco(t) + }, + ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + { + Config: dedicatedServerEcoResourceTestConfig(false), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "ovh_dedicated_server.server", "monitoring", "true"), + resource.TestCheckResourceAttr( + "ovh_dedicated_server.server", "no_intervention", "false"), + resource.TestCheckResourceAttr( + "ovh_dedicated_server.server", "display_name", "First display name"), + resource.TestCheckResourceAttr( + "ovh_dedicated_server.server", "iam.display_name", "First display name"), + resource.TestCheckResourceAttr( + "ovh_dedicated_server.server", "os", "debian11_64"), + resource.TestCheckResourceAttr( + "ovh_dedicated_server.server", "efi_bootloader_path", ""), + resource.TestCheckResourceAttr( + "ovh_dedicated_server.server", "range", "eco"), + ), + }, + { + Config: dedicatedServerEcoResourceTestConfig(true), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "ovh_dedicated_server.server", "monitoring", "false"), + resource.TestCheckResourceAttr( + "ovh_dedicated_server.server", "no_intervention", "true"), + resource.TestCheckResourceAttr( + "ovh_dedicated_server.server", "display_name", "Second display name"), + resource.TestCheckResourceAttr( + "ovh_dedicated_server.server", "iam.display_name", "Second display name"), + resource.TestCheckResourceAttr( + "ovh_dedicated_server.server", "os", "debian12_64"), + resource.TestCheckResourceAttr( + "ovh_dedicated_server.server", "efi_bootloader_path", "\\efi\\debian\\grubx64.efi"), + resource.TestCheckResourceAttr( + "ovh_dedicated_server.server", "range", "eco"), + ), + }, + { + ResourceName: "ovh_dedicated_server.server", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: "service_name", + ImportStateVerifyIgnore: []string{ + "display_name", "order", "ovh_subsidiary", "plan", "plan_option", "range", }, ImportStateIdFunc: func(s *terraform.State) (string, error) { service, ok := s.RootModule().Resources["ovh_dedicated_server.server"] diff --git a/templates/resources/dedicated_server.md.tmpl b/templates/resources/dedicated_server.md.tmpl index e3e52df42..69785de2e 100644 --- a/templates/resources/dedicated_server.md.tmpl +++ b/templates/resources/dedicated_server.md.tmpl @@ -38,8 +38,9 @@ Use this resource to order and manage a dedicated server. * `label` - (Required) Identifier of the resource * `value` - (Required) Path to the resource in API.OVH.COM * `service_name` - (Optional, Forces replacement) The service_name of your dedicated server. This field can be used to avoid ordering a dedicated server at creation and just create the resource using an already existing service +* `range` - (Optional) Range of the dedicated server to order. Can be `standard` or `eco`. Defaults to `standard` -~> **Note** To get the available plans, you can use the API console to first [create a cart](https://eu.api.ovh.com/console/?section=%2Forder&branch=v1#post-/order/cart) and then use the created cart ID to fetch the available plans using [the following call](https://eu.api.ovh.com/console/?section=%2Forder&branch=v1#get-/order/cart/-cartId-/baremetalServers). Once you've found the right plan, you can use [this call](https://eu.api.ovh.com/console/?section=%2Forder&branch=v1#get-/order/cart/-cartId-/baremetalServers/options) to get the available options for this plan. +~> **Note** To get the available plans, you can use the API console to first [create a cart](https://eu.api.ovh.com/console/?section=%2Forder&branch=v1#post-/order/cart) and then use the created cart ID to fetch the available plans using [the following call](https://eu.api.ovh.com/console/?section=%2Forder&branch=v1#get-/order/cart/-cartId-/baremetalServers) (or `/order/cart/{cartId}/eco` for eco servers). Once you've found the right plan, you can use [this call](https://eu.api.ovh.com/console/?section=%2Forder&branch=v1#get-/order/cart/-cartId-/baremetalServers/options) to get the available options for this plan. ### Editable fields of a dedicated server