Skip to content

Commit

Permalink
Merge pull request #711 from ovh/dev/aamstutz/add-baremetal-resource
Browse files Browse the repository at this point in the history
feat: Add ovh_dedicated_server resource
  • Loading branch information
amstuta authored Sep 6, 2024
2 parents c22ccde + a4bc7fe commit 2dc82b1
Show file tree
Hide file tree
Showing 16 changed files with 2,488 additions and 81 deletions.
69 changes: 56 additions & 13 deletions ovh/order.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package ovh

import (
"context"
"errors"
"fmt"
"log"
Expand All @@ -10,6 +11,7 @@ import (
"time"

"github.com/hashicorp/terraform-plugin-framework/types/basetypes"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/ovh/go-ovh/ovh"
Expand Down Expand Up @@ -222,11 +224,11 @@ func genericOrderSchema(withOptions bool) map[string]*schema.Schema {
return orderSchema
}

func orderCreateFromResource(d *schema.ResourceData, meta interface{}, product string) error {
func orderCreateFromResource(d *schema.ResourceData, meta interface{}, product string, waitForCompletion bool) error {
config := meta.(*Config)
order := (&OrderModel{}).FromResource(d)

err := orderCreate(order, config, product)
err := orderCreate(order, config, product, waitForCompletion)
if err != nil {
return err
}
Expand All @@ -236,7 +238,7 @@ func orderCreateFromResource(d *schema.ResourceData, meta interface{}, product s
return nil
}

func orderCreate(d *OrderModel, config *Config, product string) error {
func orderCreate(d *OrderModel, config *Config, product string, waitForCompletion bool) error {
// create Cart
cartParams := &OrderCartCreateOpts{
OvhSubsidiary: strings.ToUpper(d.OvhSubsidiary.ValueString()),
Expand Down Expand Up @@ -377,23 +379,31 @@ func orderCreate(d *OrderModel, config *Config, product string) error {

}

// Wait for order status
stateConf := &resource.StateChangeConf{
// Wait for order to be completed
if waitForCompletion {
if err := waitOrderCompletion(config, checkout.OrderID); err != nil {
return fmt.Errorf("waiting for order (%d): %s", checkout.OrderID, err)
}
}

d.Order.OrderId = types.TfInt64Value{Int64Value: basetypes.NewInt64Value(checkout.OrderID)}

return nil
}

func waitOrderCompletion(config *Config, orderID int64) error {
stateConf := &retry.StateChangeConf{
Pending: []string{"checking", "delivering", "ignoreerror"},
Target: []string{"delivered"},
Refresh: waitForOrder(config.OVHClient, checkout.OrderID),
Refresh: waitForOrder(config.OVHClient, orderID),
Timeout: 30 * time.Minute,
Delay: 10 * time.Second,
MinTimeout: 3 * time.Second,
}

if _, err := stateConf.WaitForState(); err != nil {
return fmt.Errorf("waiting for order (%d): %s", checkout.OrderID, err)
}

d.Order.OrderId = types.TfInt64Value{Int64Value: basetypes.NewInt64Value(checkout.OrderID)}
_, err := stateConf.WaitForState()

return nil
return err
}

func orderReadInResource(d *schema.ResourceData, meta interface{}) (*MeOrder, []*MeOrderDetail, error) {
Expand Down Expand Up @@ -573,7 +583,7 @@ func serviceNameFromOrder(c *ovh.Client, orderId int64, plan string) (string, er
return "", errors.New("serviceName not found")
}

func waitForOrder(c *ovh.Client, id int64) resource.StateRefreshFunc {
func waitForOrder(c *ovh.Client, id int64) retry.StateRefreshFunc {
return func() (interface{}, string, error) {
var r string
endpoint := fmt.Sprintf("/me/order/%d/status", id)
Expand All @@ -592,6 +602,39 @@ func waitForOrder(c *ovh.Client, id int64) resource.StateRefreshFunc {
}
}

func waitOrderCompletionV2(ctx context.Context, config *Config, orderID int64) (string, error) {
endpoint := fmt.Sprintf("/me/order/%d/status", orderID)

stateConf := &retry.StateChangeConf{
Pending: []string{"checking", "delivering"},
Target: []string{"delivered"},
Refresh: func() (interface{}, string, error) {
var status string
if err := config.OVHClient.Get(endpoint, &status); err != nil {
if errOvh, ok := err.(*ovh.APIError); ok && errOvh.Code == 404 {
log.Printf("[DEBUG] order id %d deleted", orderID)
return nil, "deleted", nil
}

log.Printf("[WARNING] order id %d, got error: %v", orderID, err)
return nil, "error", err
}

return status, status, nil
},
Timeout: time.Hour,
Delay: 10 * time.Second,
MinTimeout: 3 * time.Second,
}

result, err := stateConf.WaitForStateContext(ctx)
if err != nil {
return "error", err
}

return result.(string), err
}

func orderDetailOperations(c *ovh.Client, orderId int64, orderDetailId int64) ([]*MeOrderDetailOperation, error) {
log.Printf("[DEBUG] Will list order detail operations %d/%d", orderId, orderDetailId)
operationsIds := []int64{}
Expand Down
68 changes: 7 additions & 61 deletions ovh/order_resource_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions ovh/provider_new.go
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ func (p *OvhProvider) Resources(_ context.Context) []func() resource.Resource {
NewCloudProjectAlertingResource,
NewCloudProjectGatewayInterfaceResource,
NewDbaasLogsTokenResource,
NewDedicatedServerResource,
NewDomainZoneDnssecResource,
NewDomainZoneImportResource,
NewIpFirewallResource,
Expand Down
5 changes: 5 additions & 0 deletions ovh/provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,11 @@ func testAccPreCheckDedicatedServer(t *testing.T) {
checkEnvOrSkip(t, "OVH_DEDICATED_SERVER")
}

func testAccPreCheckOrderDedicatedServer(t *testing.T) {
testAccPreCheckCredentials(t)
checkEnvOrSkip(t, "OVH_TESTACC_ORDER_DEDICATED_SERVER")
}

func testAccPreCheckVPS(t *testing.T) {
testAccPreCheckCredentials(t)
checkEnvOrSkip(t, "OVH_VPS")
Expand Down
2 changes: 1 addition & 1 deletion ovh/resource_cloud_project.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ func resourceCloudProjectSchema() map[string]*schema.Schema {
}

func resourceCloudProjectCreate(d *schema.ResourceData, meta interface{}) error {
if err := orderCreateFromResource(d, meta, "cloud"); err != nil {
if err := orderCreateFromResource(d, meta, "cloud", true); err != nil {
return fmt.Errorf("Could not order cloud project: %q", err)
}

Expand Down
Loading

0 comments on commit 2dc82b1

Please sign in to comment.