-
Notifications
You must be signed in to change notification settings - Fork 85
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #988 from ksamoray/edge_ha_profile
Implement edge high availability profile resource
- Loading branch information
Showing
4 changed files
with
411 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,195 @@ | ||
/* Copyright © 2023 VMware, Inc. All Rights Reserved. | ||
SPDX-License-Identifier: MPL-2.0 */ | ||
|
||
package nsxt | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" | ||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" | ||
"github.com/vmware/vsphere-automation-sdk-go/runtime/bindings" | ||
"github.com/vmware/vsphere-automation-sdk-go/runtime/data" | ||
"github.com/vmware/vsphere-automation-sdk-go/services/nsxt-mp/nsx" | ||
"github.com/vmware/vsphere-automation-sdk-go/services/nsxt-mp/nsx/model" | ||
) | ||
|
||
func resourceNsxtEdgeHighAvailabilityProfile() *schema.Resource { | ||
return &schema.Resource{ | ||
Create: resourceNsxtEdgeHighAvailabilityProfileCreate, | ||
Read: resourceNsxtEdgeHighAvailabilityProfileRead, | ||
Update: resourceNsxtEdgeHighAvailabilityProfileUpdate, | ||
Delete: resourceNsxtEdgeHighAvailabilityProfileDelete, | ||
Importer: &schema.ResourceImporter{ | ||
State: schema.ImportStatePassthrough, | ||
}, | ||
Schema: map[string]*schema.Schema{ | ||
"revision": getRevisionSchema(), | ||
"description": getDescriptionSchema(), | ||
"display_name": getDisplayNameSchema(), | ||
"tag": getTagsSchema(), | ||
"bfd_allowed_hops": { | ||
Type: schema.TypeInt, | ||
Optional: true, | ||
Default: 255, | ||
Description: "BFD allowed hops", | ||
ValidateFunc: validation.IntBetween(1, 255), | ||
}, | ||
"bfd_declare_dead_multiple": { | ||
Type: schema.TypeInt, | ||
Optional: true, | ||
Default: 3, | ||
Description: "Number of times a packet is missed before BFD declares the neighbor down", | ||
ValidateFunc: validation.IntBetween(2, 16), | ||
}, | ||
"bfd_probe_interval": { | ||
Type: schema.TypeInt, | ||
Optional: true, | ||
Default: 500, | ||
Description: "the time interval (in millisecond) between probe packets for heartbeat purpose", | ||
ValidateFunc: validation.IntBetween(50, 60000), | ||
}, | ||
"standby_relocation_threshold": { | ||
Type: schema.TypeInt, | ||
Optional: true, | ||
Default: 30, | ||
Description: "Standby service context relocation wait time", | ||
ValidateFunc: validation.IntBetween(10, 20000), | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
func resourceNsxtEdgeHighAvailabilityProfileCreate(d *schema.ResourceData, m interface{}) error { | ||
connector := getPolicyConnector(m) | ||
client := nsx.NewClusterProfilesClient(connector) | ||
description := d.Get("description").(string) | ||
displayName := d.Get("display_name").(string) | ||
tags := getMPTagsFromSchema(d) | ||
bfdAllowedHops := int64(d.Get("bfd_allowed_hops").(int)) | ||
bfdDeclareDeadMultiple := int64(d.Get("bfd_declare_dead_multiple").(int)) | ||
bfdProbeInterval := int64(d.Get("bfd_probe_interval").(int)) | ||
standbyRelocationThreshold := int64(d.Get("standby_relocation_threshold").(int)) | ||
|
||
obj := model.EdgeHighAvailabilityProfile{ | ||
Description: &description, | ||
DisplayName: &displayName, | ||
Tags: tags, | ||
BfdAllowedHops: &bfdAllowedHops, | ||
BfdDeclareDeadMultiple: &bfdDeclareDeadMultiple, | ||
BfdProbeInterval: &bfdProbeInterval, | ||
StandbyRelocationConfig: &model.StandbyRelocationConfig{ | ||
StandbyRelocationThreshold: &standbyRelocationThreshold, | ||
}, | ||
ResourceType: model.EdgeHighAvailabilityProfile__TYPE_IDENTIFIER, | ||
} | ||
converter := bindings.NewTypeConverter() | ||
dataValue, errs := converter.ConvertToVapi(obj, model.EdgeHighAvailabilityProfileBindingType()) | ||
if errs != nil { | ||
return errs[0] | ||
} | ||
|
||
structValue, err := client.Create(dataValue.(*data.StructValue)) | ||
if err != nil { | ||
return handleCreateError("Edge High Availability Profile", displayName, err) | ||
} | ||
o, errs := converter.ConvertToGolang(structValue, model.EdgeHighAvailabilityProfileBindingType()) | ||
if errs != nil { | ||
return errs[0] | ||
} | ||
obj = o.(model.EdgeHighAvailabilityProfile) | ||
|
||
d.SetId(*obj.Id) | ||
return resourceNsxtEdgeHighAvailabilityProfileRead(d, m) | ||
} | ||
|
||
func resourceNsxtEdgeHighAvailabilityProfileRead(d *schema.ResourceData, m interface{}) error { | ||
connector := getPolicyConnector(m) | ||
id := d.Id() | ||
if id == "" { | ||
return fmt.Errorf("error obtaining logical object id") | ||
} | ||
client := nsx.NewClusterProfilesClient(connector) | ||
structValue, err := client.Get(id) | ||
if err != nil { | ||
return handleReadError(d, "Edge High Availability Profile", id, err) | ||
} | ||
converter := bindings.NewTypeConverter() | ||
o, errs := converter.ConvertToGolang(structValue, model.EdgeHighAvailabilityProfileBindingType()) | ||
if errs != nil { | ||
return errs[0] | ||
} | ||
obj := o.(model.EdgeHighAvailabilityProfile) | ||
d.Set("revision", obj.Revision) | ||
d.Set("description", obj.Description) | ||
d.Set("display_name", obj.DisplayName) | ||
setMPTagsInSchema(d, obj.Tags) | ||
d.Set("bfd_allowed_hops", obj.BfdAllowedHops) | ||
d.Set("bfd_declare_dead_multiple", obj.BfdDeclareDeadMultiple) | ||
d.Set("bfd_probe_interval", obj.BfdProbeInterval) | ||
if obj.StandbyRelocationConfig != nil { | ||
d.Set("standby_relocation_threshold", obj.StandbyRelocationConfig.StandbyRelocationThreshold) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func resourceNsxtEdgeHighAvailabilityProfileUpdate(d *schema.ResourceData, m interface{}) error { | ||
connector := getPolicyConnector(m) | ||
id := d.Id() | ||
if id == "" { | ||
return fmt.Errorf("error obtaining logical object id") | ||
} | ||
client := nsx.NewClusterProfilesClient(connector) | ||
revision := int64(d.Get("revision").(int)) | ||
description := d.Get("description").(string) | ||
displayName := d.Get("display_name").(string) | ||
tags := getMPTagsFromSchema(d) | ||
bfdAllowedHops := int64(d.Get("bfd_allowed_hops").(int)) | ||
bfdDeclareDeadMultiple := int64(d.Get("bfd_declare_dead_multiple").(int)) | ||
bfdProbeInterval := int64(d.Get("bfd_probe_interval").(int)) | ||
standbyRelocationThreshold := int64(d.Get("standby_relocation_threshold").(int)) | ||
|
||
obj := model.EdgeHighAvailabilityProfile{ | ||
Revision: &revision, | ||
Description: &description, | ||
DisplayName: &displayName, | ||
Tags: tags, | ||
BfdAllowedHops: &bfdAllowedHops, | ||
BfdDeclareDeadMultiple: &bfdDeclareDeadMultiple, | ||
BfdProbeInterval: &bfdProbeInterval, | ||
StandbyRelocationConfig: &model.StandbyRelocationConfig{ | ||
StandbyRelocationThreshold: &standbyRelocationThreshold, | ||
}, | ||
ResourceType: model.EdgeHighAvailabilityProfile__TYPE_IDENTIFIER, | ||
} | ||
converter := bindings.NewTypeConverter() | ||
dataValue, errs := converter.ConvertToVapi(obj, model.EdgeHighAvailabilityProfileBindingType()) | ||
if errs != nil { | ||
return errs[0] | ||
} | ||
|
||
_, err := client.Update(id, dataValue.(*data.StructValue)) | ||
if err != nil { | ||
return handleUpdateError("Edge High Availability Profile", id, err) | ||
} | ||
|
||
return resourceNsxtEdgeHighAvailabilityProfileRead(d, m) | ||
} | ||
|
||
func resourceNsxtEdgeHighAvailabilityProfileDelete(d *schema.ResourceData, m interface{}) error { | ||
connector := getPolicyConnector(m) | ||
|
||
id := d.Id() | ||
if id == "" { | ||
return fmt.Errorf("error obtaining logical object id") | ||
} | ||
|
||
client := nsx.NewClusterProfilesClient(connector) | ||
|
||
err := client.Delete(id) | ||
if err != nil { | ||
return handleDeleteError("Edge High Availability Profile", id, err) | ||
} | ||
return nil | ||
} |
158 changes: 158 additions & 0 deletions
158
nsxt/resource_nsxt_edge_high_availability_profile_test.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,158 @@ | ||
/* Copyright © 2023 VMware, Inc. All Rights Reserved. | ||
SPDX-License-Identifier: MPL-2.0 */ | ||
|
||
package nsxt | ||
|
||
import ( | ||
"fmt" | ||
"testing" | ||
"time" | ||
|
||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" | ||
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform" | ||
"github.com/vmware/vsphere-automation-sdk-go/runtime/bindings" | ||
"github.com/vmware/vsphere-automation-sdk-go/services/nsxt-mp/nsx" | ||
"github.com/vmware/vsphere-automation-sdk-go/services/nsxt-mp/nsx/model" | ||
) | ||
|
||
func TestAccResourceNsxtEdgeHighAvailabilityProfile_basic(t *testing.T) { | ||
profileName := getAccTestResourceName() | ||
updateProfileName := "updated-" + profileName | ||
testResourceName := "nsxt_edge_high_availability_profile.test" | ||
|
||
resource.Test(t, resource.TestCase{ | ||
PreCheck: func() { testAccOnlyLocalManager(t); testAccTestFabric(t); testAccPreCheck(t) }, | ||
Providers: testAccProviders, | ||
CheckDestroy: func(state *terraform.State) error { | ||
return testAccNSXEdgeHighAvailabilityProfileCheckDestroy(state, updateProfileName) | ||
}, | ||
|
||
Steps: []resource.TestStep{ | ||
{ | ||
Config: testAccNSXEdgeHighAvailabilityProfileCreateTemplate(profileName), | ||
Check: resource.ComposeTestCheckFunc( | ||
testAccNSXEdgeHighAvailabilityProfileExists(profileName, testResourceName), | ||
resource.TestCheckResourceAttr(testResourceName, "display_name", profileName), | ||
resource.TestCheckResourceAttr(testResourceName, "description", "Terraform test edge high availability profile"), | ||
resource.TestCheckResourceAttr(testResourceName, "tag.#", "1"), | ||
), | ||
}, | ||
{ | ||
Config: testAccNSXEdgeHighAvailabilityProfileCreateTemplate(updateProfileName), | ||
Check: resource.ComposeTestCheckFunc( | ||
testAccNSXEdgeHighAvailabilityProfileExists(updateProfileName, testResourceName), | ||
resource.TestCheckResourceAttr(testResourceName, "display_name", updateProfileName), | ||
resource.TestCheckResourceAttr(testResourceName, "description", "Terraform test edge high availability profile"), | ||
resource.TestCheckResourceAttr(testResourceName, "tag.#", "1"), | ||
), | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
func TestAccResourceNsxtEdgeHighAvailabilityProfile_importBasic(t *testing.T) { | ||
name := getAccTestResourceName() | ||
profileName := getAccTestResourceName() | ||
testResourceName := "nsxt_edge_high_availability_profile.test" | ||
|
||
resource.Test(t, resource.TestCase{ | ||
PreCheck: func() { testAccOnlyLocalManager(t); testAccTestFabric(t); testAccPreCheck(t) }, | ||
Providers: testAccProviders, | ||
CheckDestroy: func(state *terraform.State) error { | ||
return testAccNSXEdgeHighAvailabilityProfileCheckDestroy(state, name) | ||
}, | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: testAccNSXEdgeHighAvailabilityProfileCreateTemplate(profileName), | ||
}, | ||
{ | ||
ResourceName: testResourceName, | ||
ImportState: true, | ||
ImportStateVerify: true, | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
func testAccNSXEdgeHighAvailabilityProfileExists(displayName string, resourceName string) resource.TestCheckFunc { | ||
return func(state *terraform.State) error { | ||
|
||
connector := getPolicyConnector(testAccProvider.Meta().(nsxtClients)) | ||
rs, ok := state.RootModule().Resources[resourceName] | ||
if !ok { | ||
return fmt.Errorf("NSX Edge High Availability Profile resource %s not found in resources", resourceName) | ||
} | ||
|
||
resourceID := rs.Primary.ID | ||
if resourceID == "" { | ||
return fmt.Errorf("NSX Edge High Availability Profile resource ID not set in resources ") | ||
} | ||
|
||
client := nsx.NewClusterProfilesClient(connector) | ||
structValue, err := client.Get(resourceID) | ||
if err != nil { | ||
return fmt.Errorf("error while retrieving Edge High Availability Profile ID %s. Error: %v", resourceID, err) | ||
} | ||
converter := bindings.NewTypeConverter() | ||
o, errs := converter.ConvertToGolang(structValue, model.EdgeHighAvailabilityProfileBindingType()) | ||
if errs != nil { | ||
return errs[0] | ||
} | ||
obj := o.(model.EdgeHighAvailabilityProfile) | ||
|
||
if displayName == *obj.DisplayName { | ||
return nil | ||
} | ||
return fmt.Errorf("NSX Edge High Availability Profile %s wasn't found", displayName) | ||
} | ||
} | ||
|
||
func testAccNSXEdgeHighAvailabilityProfileCheckDestroy(state *terraform.State, displayName string) error { | ||
connector := getPolicyConnector(testAccProvider.Meta().(nsxtClients)) | ||
|
||
// This addresses the fact that object is retrieved even though it had been deleted | ||
time.Sleep(1 * time.Second) | ||
|
||
for _, rs := range state.RootModule().Resources { | ||
if rs.Type != "nsxt_edge_high_availability_profile" { | ||
continue | ||
} | ||
|
||
resourceID := rs.Primary.Attributes["id"] | ||
client := nsx.NewClusterProfilesClient(connector) | ||
structValue, err := client.Get(resourceID) | ||
|
||
if isNotFoundError(err) { | ||
return nil | ||
} | ||
|
||
if err != nil { | ||
return fmt.Errorf("error while retrieving Edge High Availability Profile ID %s. Error: %v", resourceID, err) | ||
} | ||
converter := bindings.NewTypeConverter() | ||
o, errs := converter.ConvertToGolang(structValue, model.EdgeHighAvailabilityProfileBindingType()) | ||
if errs != nil { | ||
return errs[0] | ||
} | ||
obj := o.(model.EdgeHighAvailabilityProfile) | ||
|
||
if obj.DisplayName != nil && displayName == *obj.DisplayName { | ||
return fmt.Errorf("NSX Edge High Availability Profile %s still exists", displayName) | ||
} | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func testAccNSXEdgeHighAvailabilityProfileCreateTemplate(displayName string) string { | ||
return fmt.Sprintf(` | ||
resource "nsxt_edge_high_availability_profile" "test" { | ||
description = "Terraform test edge high availability profile" | ||
display_name = "%s" | ||
tag { | ||
scope = "scope1" | ||
tag = "tag1" | ||
} | ||
} | ||
`, displayName) | ||
} |
Oops, something went wrong.