Skip to content

Commit

Permalink
feat(baremetal): add subscription_period attribute to `baremetal_of…
Browse files Browse the repository at this point in the history
…fer` (#1581)
  • Loading branch information
quantumsheep committed Nov 7, 2022
1 parent adf2b1c commit c3d5fbf
Show file tree
Hide file tree
Showing 7 changed files with 5,315 additions and 1,165 deletions.
2 changes: 2 additions & 0 deletions docs/data-sources/baremetal_offer.md
Expand Up @@ -28,6 +28,8 @@ data "scaleway_baremetal_offer" "my_offer" {

- `name` - (Optional) The offer name. Only one of `name` and `offer_id` should be specified.

- `subscription_period` - (Optional) Period of subscription the desired offer. Should be `hourly` or `monthly`.

- `offer_id` - (Optional) The offer id. Only one of `name` and `offer_id` should be specified.

- `allow_disabled` - (Optional, default `false`) Include disabled offers.
Expand Down
79 changes: 60 additions & 19 deletions scaleway/data_source_baremetal_offer.go
Expand Up @@ -6,6 +6,7 @@ import (

"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
"github.com/scaleway/scaleway-sdk-go/api/baremetal/v1"
"github.com/scaleway/scaleway-sdk-go/scw"
)
Expand All @@ -21,6 +22,17 @@ func dataSourceScalewayBaremetalOffer() *schema.Resource {
Description: "Exact name of the desired offer",
ConflictsWith: []string{"offer_id"},
},
"subscription_period": {
Type: schema.TypeString,
Optional: true,
ValidateFunc: validation.StringInSlice([]string{
baremetal.OfferSubscriptionPeriodUnknownSubscriptionPeriod.String(),
baremetal.OfferSubscriptionPeriodHourly.String(),
baremetal.OfferSubscriptionPeriodMonthly.String(),
}, false),
Description: "Period of subscription the desired offer",
ConflictsWith: []string{"offer_id"},
},
"offer_id": {
Type: schema.TypeString,
Optional: true,
Expand Down Expand Up @@ -138,35 +150,64 @@ func dataSourceScalewayBaremetalOfferRead(ctx context.Context, d *schema.Resourc
}

zone, offerID, _ := parseZonedID(datasourceNewZonedID(d.Get("offer_id"), fallBackZone))
res, err := baremetalAPI.ListOffers(&baremetal.ListOffersRequest{
Zone: zone,
}, scw.WithAllPages(), scw.WithContext(ctx))
if err != nil {
return diag.FromErr(err)
}

matches := []*baremetal.Offer(nil)
for _, offer := range res.Offers {
if offer.Name == d.Get("name") || offer.ID == offerID {
if !offer.Enable && !d.Get("include_disabled").(bool) {
return diag.FromErr(fmt.Errorf("offer %s (%s) found in zone %s but is disabled. Add allow_disabled=true in your terraform config to use it", offer.Name, offer.ID, zone))
var offer *baremetal.Offer

if offerID != "" {
// Temporary fix because GetOffer doesn't fetch monthly subscription offers
offer, err = baremetalFindOfferByID(ctx, baremetalAPI, zone, offerID)
if err != nil {
return diag.FromErr(err)
}
} else {
listOffersRequest := &baremetal.ListOffersRequest{
Zone: zone,
}
if subscriptionPeriod, ok := d.GetOk("subscription_period"); ok {
listOffersRequest.SubscriptionPeriod = baremetal.OfferSubscriptionPeriod(subscriptionPeriod.(string))
}

res, err := baremetalAPI.ListOffers(listOffersRequest, scw.WithAllPages(), scw.WithContext(ctx))
if err != nil {
return diag.FromErr(err)
}

matches := []*baremetal.Offer{}
for _, offer := range res.Offers {
if offer.Name == d.Get("name") {
if !offer.Enable && !d.Get("include_disabled").(bool) {
return diag.FromErr(fmt.Errorf("%s offer %s (%s) found in zone %s but is disabled. Add allow_disabled=true in your terraform config to use it", offer.SubscriptionPeriod, offer.Name, offer.ID, zone))
}

matches = append(matches, offer)
}
matches = append(matches, offer)
}
}
if len(matches) == 0 {
return diag.FromErr(fmt.Errorf("no offer found with the name %s in zone %s", d.Get("name"), zone))
}
if len(matches) > 1 {
return diag.FromErr(fmt.Errorf("%d offers found with the same name %s in zone %s", len(matches), d.Get("name"), zone))

if len(matches) == 0 {
if subscriptionPeriod, ok := d.GetOk("subscription_period"); ok {
return diag.FromErr(fmt.Errorf("no offer found with the name %s and %s subscription period in zone %s", d.Get("name"), subscriptionPeriod, zone))
}

return diag.FromErr(fmt.Errorf("no offer found with the name %s in zone %s", d.Get("name"), zone))
}

if len(matches) > 1 {
if subscriptionPeriod, ok := d.GetOk("subscription_period"); ok {
return diag.FromErr(fmt.Errorf("%d offers found with the same name %s and %s subscription period in zone %s", len(matches), d.Get("name"), subscriptionPeriod, zone))
}

return diag.FromErr(fmt.Errorf("%d offers found with the same name %s in zone %s", len(matches), d.Get("name"), zone))
}

offer = matches[0]
}

offer := matches[0]
zonedID := datasourceNewZonedID(offer.ID, zone)
d.SetId(zonedID)
_ = d.Set("offer_id", zonedID)
_ = d.Set("zone", zone)
_ = d.Set("name", offer.Name)
_ = d.Set("subscription_period", offer.SubscriptionPeriod)
_ = d.Set("include_disabled", !offer.Enable)
_ = d.Set("bandwidth", int(offer.Bandwidth))
_ = d.Set("commercial_range", offer.CommercialRange)
Expand Down
123 changes: 106 additions & 17 deletions scaleway/data_source_baremetal_offer_test.go
@@ -1,13 +1,13 @@
package scaleway

import (
"context"
"fmt"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
"github.com/scaleway/scaleway-sdk-go/api/baremetal/v1"
"github.com/scaleway/scaleway-sdk-go/scw"
)

func TestAccScalewayDataSourceBaremetalOffer_Basic(t *testing.T) {
Expand All @@ -25,20 +25,117 @@ func TestAccScalewayDataSourceBaremetalOffer_Basic(t *testing.T) {
}
data "scaleway_baremetal_offer" "test2" {
zone = "fr-par-2"
offer_id = "25dcf38b-c90c-4b18-97a2-6956e9d1e113"
offer_id = data.scaleway_baremetal_offer.test1.offer_id
}
`,
Check: resource.ComposeTestCheckFunc(
testAccCheckScalewayBaremetalOfferExists(tt, "data.scaleway_baremetal_offer.test1"),
resource.TestCheckResourceAttr("data.scaleway_baremetal_offer.test1", "name", "EM-A210R-HDD"),
testAccCheckScalewayBaremetalOfferExists(tt, "data.scaleway_baremetal_offer.test2"),
resource.TestCheckResourceAttrPair("data.scaleway_baremetal_offer.test2", "offer_id", "data.scaleway_baremetal_offer.test1", "offer_id"),
resource.TestCheckResourceAttr("data.scaleway_baremetal_offer.test2", "name", "EM-A210R-HDD"),
resource.TestCheckResourceAttr("data.scaleway_baremetal_offer.test2", "commercial_range", "aluminium"),
resource.TestCheckResourceAttr("data.scaleway_baremetal_offer.test2", "include_disabled", "false"),
resource.TestCheckResourceAttr("data.scaleway_baremetal_offer.test2", "bandwidth", "1000000000"),
resource.TestCheckResourceAttr("data.scaleway_baremetal_offer.test2", "commercial_range", "aluminium"),
// resource.TestCheckResourceAttr("data.scaleway_baremetal_offer.test2", "stock", "available"), // skipping this as stocks vary too much
resource.TestCheckResourceAttr("data.scaleway_baremetal_offer.test2", "cpu.0.name", "AMD Ryzen PRO 3600"),
resource.TestCheckResourceAttr("data.scaleway_baremetal_offer.test2", "cpu.0.core_count", "6"),
resource.TestCheckResourceAttr("data.scaleway_baremetal_offer.test2", "cpu.0.frequency", "3600"),
resource.TestCheckResourceAttr("data.scaleway_baremetal_offer.test2", "cpu.0.thread_count", "12"),
resource.TestCheckResourceAttr("data.scaleway_baremetal_offer.test2", "disk.0.type", "HDD"),
resource.TestCheckResourceAttr("data.scaleway_baremetal_offer.test2", "disk.0.capacity", "1000000000000"),
resource.TestCheckResourceAttr("data.scaleway_baremetal_offer.test2", "disk.1.type", "HDD"),
resource.TestCheckResourceAttr("data.scaleway_baremetal_offer.test2", "disk.1.capacity", "1000000000000"),
resource.TestCheckResourceAttr("data.scaleway_baremetal_offer.test2", "memory.0.type", "DDR4"),
resource.TestCheckResourceAttr("data.scaleway_baremetal_offer.test2", "memory.0.capacity", "16000000000"),
resource.TestCheckResourceAttr("data.scaleway_baremetal_offer.test2", "memory.0.frequency", "3200"),
resource.TestCheckResourceAttr("data.scaleway_baremetal_offer.test2", "memory.0.is_ecc", "true"),
),
},
},
})
}

func TestAccScalewayDataSourceBaremetalOffer_SubscriptionPeriodHourly(t *testing.T) {
tt := NewTestTools(t)
defer tt.Cleanup()
resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ProviderFactories: tt.ProviderFactories,
Steps: []resource.TestStep{
{
Config: `
data "scaleway_baremetal_offer" "test1" {
zone = "fr-par-2"
name = "EM-A210R-HDD"
subscription_period = "hourly"
}
data "scaleway_baremetal_offer" "test2" {
offer_id = data.scaleway_baremetal_offer.test1.offer_id
}
`,
Check: resource.ComposeTestCheckFunc(
testAccCheckScalewayBaremetalOfferExists(tt, "data.scaleway_baremetal_offer.test1"),
resource.TestCheckResourceAttr("data.scaleway_baremetal_offer.test1", "name", "EM-A210R-HDD"),
resource.TestCheckResourceAttr("data.scaleway_baremetal_offer.test1", "subscription_period", "hourly"),
testAccCheckScalewayBaremetalOfferExists(tt, "data.scaleway_baremetal_offer.test2"),
resource.TestCheckResourceAttrPair("data.scaleway_baremetal_offer.test2", "offer_id", "data.scaleway_baremetal_offer.test1", "offer_id"),
resource.TestCheckResourceAttr("data.scaleway_baremetal_offer.test2", "name", "EM-A210R-HDD"),
resource.TestCheckResourceAttr("data.scaleway_baremetal_offer.test2", "subscription_period", "hourly"),
resource.TestCheckResourceAttr("data.scaleway_baremetal_offer.test2", "commercial_range", "aluminium"),
resource.TestCheckResourceAttr("data.scaleway_baremetal_offer.test2", "include_disabled", "false"),
resource.TestCheckResourceAttr("data.scaleway_baremetal_offer.test2", "bandwidth", "1000000000"),
resource.TestCheckResourceAttr("data.scaleway_baremetal_offer.test2", "commercial_range", "aluminium"),
// resource.TestCheckResourceAttr("data.scaleway_baremetal_offer.test2", "stock", "available"), // skipping this as stocks vary too much
resource.TestCheckResourceAttr("data.scaleway_baremetal_offer.test2", "cpu.0.name", "AMD Ryzen PRO 3600"),
resource.TestCheckResourceAttr("data.scaleway_baremetal_offer.test2", "cpu.0.core_count", "6"),
resource.TestCheckResourceAttr("data.scaleway_baremetal_offer.test2", "cpu.0.frequency", "3600"),
resource.TestCheckResourceAttr("data.scaleway_baremetal_offer.test2", "cpu.0.thread_count", "12"),
resource.TestCheckResourceAttr("data.scaleway_baremetal_offer.test2", "disk.0.type", "HDD"),
resource.TestCheckResourceAttr("data.scaleway_baremetal_offer.test2", "disk.0.capacity", "1000000000000"),
resource.TestCheckResourceAttr("data.scaleway_baremetal_offer.test2", "disk.1.type", "HDD"),
resource.TestCheckResourceAttr("data.scaleway_baremetal_offer.test2", "disk.1.capacity", "1000000000000"),
resource.TestCheckResourceAttr("data.scaleway_baremetal_offer.test2", "memory.0.type", "DDR4"),
resource.TestCheckResourceAttr("data.scaleway_baremetal_offer.test2", "memory.0.capacity", "16000000000"),
resource.TestCheckResourceAttr("data.scaleway_baremetal_offer.test2", "memory.0.frequency", "3200"),
resource.TestCheckResourceAttr("data.scaleway_baremetal_offer.test2", "memory.0.is_ecc", "true"),
),
},
},
})
}

func TestAccScalewayDataSourceBaremetalOffer_SubscriptionPeriodMonthly(t *testing.T) {
tt := NewTestTools(t)
defer tt.Cleanup()
resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ProviderFactories: tt.ProviderFactories,
Steps: []resource.TestStep{
{
Config: `
data "scaleway_baremetal_offer" "test1" {
zone = "fr-par-2"
name = "EM-A210R-HDD"
subscription_period = "monthly"
}
data "scaleway_baremetal_offer" "test3" {
offer_id = "fr-par-2/25dcf38b-c90c-4b18-97a2-6956e9d1e113"
data "scaleway_baremetal_offer" "test2" {
offer_id = data.scaleway_baremetal_offer.test1.offer_id
}
`,
Check: resource.ComposeTestCheckFunc(
testAccCheckScalewayBaremetalOfferExists(tt, "data.scaleway_baremetal_offer.test1"),
resource.TestCheckResourceAttr("data.scaleway_baremetal_offer.test1", "name", "EM-A210R-HDD"),
resource.TestCheckResourceAttr("data.scaleway_baremetal_offer.test1", "subscription_period", "monthly"),
testAccCheckScalewayBaremetalOfferExists(tt, "data.scaleway_baremetal_offer.test2"),
resource.TestCheckResourceAttr("data.scaleway_baremetal_offer.test2", "offer_id", "fr-par-2/25dcf38b-c90c-4b18-97a2-6956e9d1e113"),
resource.TestCheckResourceAttrPair("data.scaleway_baremetal_offer.test2", "offer_id", "data.scaleway_baremetal_offer.test1", "offer_id"),
resource.TestCheckResourceAttr("data.scaleway_baremetal_offer.test2", "name", "EM-A210R-HDD"),
resource.TestCheckResourceAttr("data.scaleway_baremetal_offer.test2", "subscription_period", "monthly"),
resource.TestCheckResourceAttr("data.scaleway_baremetal_offer.test2", "commercial_range", "aluminium"),
resource.TestCheckResourceAttr("data.scaleway_baremetal_offer.test2", "include_disabled", "false"),
resource.TestCheckResourceAttr("data.scaleway_baremetal_offer.test2", "bandwidth", "1000000000"),
Expand All @@ -56,8 +153,6 @@ func TestAccScalewayDataSourceBaremetalOffer_Basic(t *testing.T) {
resource.TestCheckResourceAttr("data.scaleway_baremetal_offer.test2", "memory.0.capacity", "16000000000"),
resource.TestCheckResourceAttr("data.scaleway_baremetal_offer.test2", "memory.0.frequency", "3200"),
resource.TestCheckResourceAttr("data.scaleway_baremetal_offer.test2", "memory.0.is_ecc", "true"),
testAccCheckScalewayBaremetalOfferExists(tt, "data.scaleway_baremetal_offer.test3"),
resource.TestCheckResourceAttr("data.scaleway_baremetal_offer.test3", "name", "EM-A210R-HDD"),
),
},
},
Expand All @@ -78,17 +173,11 @@ func testAccCheckScalewayBaremetalOfferExists(tt *TestTools, n string) resource.
}

baremetalAPI := baremetal.NewAPI(tt.Meta.scwClient)
resp, err := baremetalAPI.ListOffers(&baremetal.ListOffersRequest{
Zone: zone,
}, scw.WithAllPages())
_, err = baremetalFindOfferByID(context.Background(), baremetalAPI, zone, id)
if err != nil {
return err
}
for _, offer := range resp.Offers {
if offer.ID == id {
return nil
}
}
return fmt.Errorf("offer %s not found in zone %s", id, zone)

return nil
}
}
26 changes: 26 additions & 0 deletions scaleway/helpers_baremetal.go
Expand Up @@ -2,6 +2,7 @@ package scaleway

import (
"context"
"fmt"
"time"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
Expand Down Expand Up @@ -145,3 +146,28 @@ func baremetalInstallServer(ctx context.Context, d *schema.ResourceData, baremet

return nil
}

func baremetalFindOfferByID(ctx context.Context, baremetalAPI *baremetal.API, zone scw.Zone, offerID string) (*baremetal.Offer, error) {
subscriptionPeriods := []baremetal.OfferSubscriptionPeriod{
baremetal.OfferSubscriptionPeriodHourly,
baremetal.OfferSubscriptionPeriodMonthly,
}

for _, subscriptionPeriod := range subscriptionPeriods {
res, err := baremetalAPI.ListOffers(&baremetal.ListOffersRequest{
Zone: zone,
SubscriptionPeriod: subscriptionPeriod,
}, scw.WithAllPages(), scw.WithContext(ctx))
if err != nil {
return nil, err
}

for _, offer := range res.Offers {
if offer.ID == offerID {
return offer, nil
}
}
}

return nil, fmt.Errorf("offer %s not found in zone %s", offerID, zone)
}

0 comments on commit c3d5fbf

Please sign in to comment.