Skip to content

Commit

Permalink
Refactor reflect and some util code to own pkg
Browse files Browse the repository at this point in the history
Signed-off-by: Shawn Wang <[email protected]>
  • Loading branch information
wsquan171 committed May 31, 2024
1 parent 35caab6 commit 65f673f
Show file tree
Hide file tree
Showing 34 changed files with 548 additions and 481 deletions.
4 changes: 3 additions & 1 deletion nsxt/data_source_nsxt_policy_edge_node.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import (
"strconv"
"strings"

"github.com/vmware/terraform-provider-nsxt/nsxt/util"

"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"
Expand Down Expand Up @@ -42,7 +44,7 @@ func dataSourceNsxtPolicyEdgeNodeRead(d *schema.ResourceData, m interface{}) err
// for bool types, but in this case it works and GetOk doesn't
memberIndex, memberIndexSet := d.GetOkExists("member_index")

if isPolicyGlobalManager(m) || nsxVersionHigherOrEqual("3.2.0") {
if isPolicyGlobalManager(m) || util.NsxVersionHigherOrEqual("3.2.0") {
query := make(map[string]string)
query["parent_path"] = edgeClusterPath
if memberIndexSet {
Expand Down
13 changes: 7 additions & 6 deletions nsxt/gateway_common.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ import (
"log"
"strings"

nsx_policy "github.com/vmware/terraform-provider-nsxt/api"
utl "github.com/vmware/terraform-provider-nsxt/api/utl"
"github.com/vmware/terraform-provider-nsxt/nsxt/util"

"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"
Expand All @@ -15,9 +19,6 @@ import (
gm_model "github.com/vmware/vsphere-automation-sdk-go/services/nsxt-gm/model"
"github.com/vmware/vsphere-automation-sdk-go/services/nsxt/infra/tier_0s"
"github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model"

nsx_policy "github.com/vmware/terraform-provider-nsxt/api"
utl "github.com/vmware/terraform-provider-nsxt/api/utl"
)

var nsxtPolicyTier0GatewayRedistributionRuleTypes = []string{
Expand Down Expand Up @@ -534,7 +535,7 @@ func setLocaleServiceRedistributionRulesConfig(rulesConfig []interface{}, config
rule.RouteMapPath = &routeMapPath
}

if nsxVersionHigherOrEqual("3.1.0") {
if util.NsxVersionHigherOrEqual("3.1.0") {
if bgp {
rule.Destinations = append(rule.Destinations, model.Tier0RouteRedistributionRule_DESTINATIONS_BGP)
}
Expand Down Expand Up @@ -565,7 +566,7 @@ func setLocaleServiceRedistributionConfig(redistributionConfigs []interface{}, s
BgpEnabled: &bgpEnabled,
}

if nsxVersionHigherOrEqual("3.1.0") {
if util.NsxVersionHigherOrEqual("3.1.0") {
redistributionStruct.OspfEnabled = &ospfEnabled
}

Expand All @@ -580,7 +581,7 @@ func getLocaleServiceRedistributionRuleConfig(config *model.Tier0RouteRedistribu
rule["name"] = ruleConfig.Name
rule["route_map_path"] = ruleConfig.RouteMapPath
rule["types"] = ruleConfig.RouteRedistributionTypes
if nsxVersionHigherOrEqual("3.1.0") {
if util.NsxVersionHigherOrEqual("3.1.0") {
bgp := false
ospf := false
for _, destination := range ruleConfig.Destinations {
Expand Down
183 changes: 183 additions & 0 deletions nsxt/metadata/metadata.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
package metadata

import (
"log"
"reflect"

"github.com/vmware/terraform-provider-nsxt/nsxt/util"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

type Metadata struct {
// we need a separate schema type, in addition to terraform SDK type,
// in order to distinguish between single subclause and a list of entries
SchemaType string
ReadOnly bool
SdkFieldName string
// This attribute is parent path for the object
IsParentPath bool
IntroducedInVersion string
// skip handling of this attribute - it will be done manually
Skip bool
ReflectType reflect.Type
TestData Testdata
}

type ExtendedSchema struct {
Schema schema.Schema
Metadata Metadata
}

type ExtendedResource struct {
Schema map[string]*ExtendedSchema
}

type Testdata struct {
CreateValue interface{}
UpdateValue interface{}
}

// GetExtendedSchema is a helper to convert terraform sdk schema to extended schema
func GetExtendedSchema(sch *schema.Schema) *ExtendedSchema {
shallowCopy := *sch
return &ExtendedSchema{
Schema: shallowCopy,
Metadata: Metadata{
Skip: true,
},
}
}

// GetSchemaFromExtendedSchema gets terraform sdk schema from extended schema definition
func GetSchemaFromExtendedSchema(ext map[string]*ExtendedSchema) map[string]*schema.Schema {
result := make(map[string]*schema.Schema)

for key, value := range ext {
log.Printf("[INFO] inspecting schema key %s, value %v", key, value)
shallowCopy := value.Schema
if (value.Schema.Type == schema.TypeList) || (value.Schema.Type == schema.TypeSet) {
elem, ok := shallowCopy.Elem.(*ExtendedSchema)
if ok {
shallowCopy.Elem = elem.Schema
} else {
elem, ok := shallowCopy.Elem.(*ExtendedResource)
if ok {
shallowCopy.Elem = &schema.Resource{
Schema: GetSchemaFromExtendedSchema(elem.Schema),
}
}
}
}
// TODO: deepcopy needed?
result[key] = &shallowCopy
}

return result
}

// StructToSchema converts NSX model struct to terraform schema
// currently supports nested subtype and trivial types
// TODO - support a list of structs
func StructToSchema(elem reflect.Value, d *schema.ResourceData, metadata map[string]*ExtendedSchema, parent string, parentMap map[string]interface{}) {
for key, item := range metadata {
if item.Metadata.Skip {
continue
}

log.Printf("[INFO] inspecting key %s", key)
if len(parent) > 0 {
log.Printf("[INFO] parent %s key %s", parent, key)
}
if item.Metadata.SchemaType == "struct" {
nestedObj := elem.FieldByName(item.Metadata.SdkFieldName)
nestedSchema := make(map[string]interface{})
childElem := item.Schema.Elem.(*ExtendedResource)
StructToSchema(nestedObj.Elem(), d, childElem.Schema, key, nestedSchema)
log.Printf("[INFO] assigning struct %v to %s", nestedObj, key)
// TODO - get the schema from nested type if parent in present
var nestedSlice []map[string]interface{}
nestedSlice = append(nestedSlice, nestedSchema)
if len(parent) > 0 {
parentMap[key] = nestedSlice
} else {
d.Set(key, nestedSlice)
}
} else {
if len(parent) > 0 {
log.Printf("[INFO] assigning nested value %v to %s", elem.FieldByName(item.Metadata.SdkFieldName).Interface(), key)
parentMap[key] = elem.FieldByName(item.Metadata.SdkFieldName).Interface()
} else {
log.Printf("[INFO] assigning value %v to %s", elem.FieldByName(item.Metadata.SdkFieldName).Interface(), key)
d.Set(key, elem.FieldByName(item.Metadata.SdkFieldName).Interface())
}
}
}
}

// SchemaToStruct converts terraform schema to NSX model struct
// currently supports nested subtype and trivial types
// TODO - support a list of structs
func SchemaToStruct(elem reflect.Value, d *schema.ResourceData, metadata map[string]*ExtendedSchema, parent string, parentMap map[string]interface{}) {
for key, item := range metadata {
if item.Metadata.ReadOnly || item.Metadata.Skip {
continue
}
if item.Metadata.IntroducedInVersion != "" && util.NsxVersionLower(item.Metadata.IntroducedInVersion) {
continue
}

log.Printf("[INFO] inspecting key %s", key)
if len(parent) > 0 {
log.Printf("[INFO] parent %s key %s", parent, key)
}
if item.Metadata.SchemaType == "string" {
var value string
if len(parent) > 0 {
value = parentMap[key].(string)
} else {
value = d.Get(key).(string)
}
log.Printf("[INFO] assigning string %v to %s", value, key)
elem.FieldByName(item.Metadata.SdkFieldName).Set(reflect.ValueOf(&value))
}
if item.Metadata.SchemaType == "bool" {
var value bool
if len(parent) > 0 {
value = parentMap[key].(bool)
} else {
value = d.Get(key).(bool)
}
log.Printf("[INFO] assigning bool %v to %s", value, key)
elem.FieldByName(item.Metadata.SdkFieldName).Set(reflect.ValueOf(&value))
}
if item.Metadata.SchemaType == "int" {
var value int64
if len(parent) > 0 {
value = int64(parentMap[key].(int))
} else {
value = int64(d.Get(key).(int))
}
log.Printf("[INFO] assigning int %v to %s", value, key)
elem.FieldByName(item.Metadata.SdkFieldName).Set(reflect.ValueOf(&value))
}
if item.Metadata.SchemaType == "struct" {
nestedObj := reflect.New(item.Metadata.ReflectType)
/*
// Helper for list of structs
slice := reflect.MakeSlice(reflect.TypeOf(nestedObj), 1, 1)
*/
nestedSchemaList := d.Get(key).([]interface{})
if len(nestedSchemaList) == 0 {
continue
}
nestedSchema := nestedSchemaList[0].(map[string]interface{})

childElem := item.Schema.Elem.(*ExtendedResource)
SchemaToStruct(nestedObj.Elem(), d, childElem.Schema, key, nestedSchema)
log.Printf("[INFO] assigning struct %v to %s", nestedObj, key)
elem.FieldByName(item.Metadata.SdkFieldName).Set(nestedObj)
// TODO - get the schema from nested type if parent in present
}
}
}
7 changes: 4 additions & 3 deletions nsxt/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ import (
"strings"
"time"

tf_api "github.com/vmware/terraform-provider-nsxt/api/utl"
"github.com/vmware/terraform-provider-nsxt/nsxt/util"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
api "github.com/vmware/go-vmware-nsxt"
Expand All @@ -29,8 +32,6 @@ import (
"github.com/vmware/vsphere-automation-sdk-go/services/nsxt-mp/nsx"
"github.com/vmware/vsphere-automation-sdk-go/services/nsxt-mp/nsx/model"
"golang.org/x/exp/slices"

tf_api "github.com/vmware/terraform-provider-nsxt/api/utl"
)

var defaultRetryOnStatusCodes = []int{400, 409, 429, 500, 503, 504}
Expand Down Expand Up @@ -1182,7 +1183,7 @@ func getPolicyConnectorWithHeaders(clients interface{}, customHeaders *map[strin
// Init NSX version on demand if not done yet
// This is also our indication to apply licenses, in case of delayed connection
// This step is skipped if the connector is for special purpose, or for different endpoint
if nsxVersion == "" && !standaloneFlow {
if util.NsxVersion == "" && !standaloneFlow {
initNSXVersion(connector)
err := configureLicenses(connector, c.CommonConfig.LicenseKeys)
if err != nil {
Expand Down
14 changes: 8 additions & 6 deletions nsxt/provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import (
"strings"
"testing"

"github.com/vmware/terraform-provider-nsxt/nsxt/util"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
api "github.com/vmware/go-vmware-nsxt"
Expand Down Expand Up @@ -89,7 +91,7 @@ func testAccGetClient() (*api.APIClient, error) {
}

func testAccNSXVersion(t *testing.T, requiredVersion string) {
if nsxVersion == "" {
if util.NsxVersion == "" {
connector, err := testAccGetPolicyConnector()
if err != nil {
t.Errorf("Failed to get policy connector")
Expand All @@ -103,13 +105,13 @@ func testAccNSXVersion(t *testing.T, requiredVersion string) {
}
}

if nsxVersionLower(requiredVersion) {
t.Skipf("This test can only run in NSX %s or above (Current version %s)", requiredVersion, nsxVersion)
if util.NsxVersionLower(requiredVersion) {
t.Skipf("This test can only run in NSX %s or above (Current version %s)", requiredVersion, util.NsxVersion)
}
}

func testAccNSXVersionLessThan(t *testing.T, requiredVersion string) {
if nsxVersion == "" {
if util.NsxVersion == "" {
connector, err := testAccGetPolicyConnector()
if err != nil {
t.Errorf("Failed to get policy connector")
Expand All @@ -123,8 +125,8 @@ func testAccNSXVersionLessThan(t *testing.T, requiredVersion string) {
}
}

if nsxVersionHigherOrEqual(requiredVersion) {
t.Skipf("This test can only run in NSX below %s (Current version %s)", requiredVersion, nsxVersion)
if util.NsxVersionHigherOrEqual(requiredVersion) {
t.Skipf("This test can only run in NSX below %s (Current version %s)", requiredVersion, util.NsxVersion)
}
}

Expand Down
6 changes: 4 additions & 2 deletions nsxt/resource_nsxt_cluster_virtual_ip.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import (
"fmt"
"log"

"github.com/vmware/terraform-provider-nsxt/nsxt/util"

"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/services/nsxt-mp/nsx/cluster"
Expand Down Expand Up @@ -104,7 +106,7 @@ func setClusterVirtualIP(d *schema.ResourceData, m interface{}) error {
forceStr = nsxModel.ClusterVirtualIpProperties_FORCE_FALSE
}
var err error
if nsxVersionHigherOrEqual("4.0.0") {
if util.NsxVersionHigherOrEqual("4.0.0") {
_, err = client.Setvirtualip(&forceStr, &ipv6Address, &ipAddress)
} else {
// IPv6 not supported
Expand Down Expand Up @@ -138,7 +140,7 @@ func resourceNsxtClusterVirualIPDelete(d *schema.ResourceData, m interface{}) er
log.Printf("[WARNING] Failed to clear virtual ip: %v", err)
return handleDeleteError("ClusterVirtualIP", id, err)
}
if nsxVersionHigherOrEqual("4.0.0") {
if util.NsxVersionHigherOrEqual("4.0.0") {
_, err = client.Clearvirtualip6()
if err != nil {
log.Printf("[WARNING] Failed to clear virtual ipv6 ip: %v", err)
Expand Down
4 changes: 3 additions & 1 deletion nsxt/resource_nsxt_edge_transport_node.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import (
"reflect"
"time"

"github.com/vmware/terraform-provider-nsxt/nsxt/util"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
Expand Down Expand Up @@ -896,7 +898,7 @@ func getEdgeNodeSettingsFromSchema(s interface{}) (*model.EdgeNodeSettings, erro
SearchDomains: searchDomains,
SyslogServers: syslogServers,
}
if nsxVersionHigherOrEqual("4.0.0") {
if util.NsxVersionHigherOrEqual("4.0.0") {
obj.EnableUptMode = &enableUptMode
}
return obj, nil
Expand Down
4 changes: 3 additions & 1 deletion nsxt/resource_nsxt_firewall_section.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import (
"log"
"net/http"

"github.com/vmware/terraform-provider-nsxt/nsxt/util"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
"github.com/vmware/go-vmware-nsxt/manager"
Expand Down Expand Up @@ -379,7 +381,7 @@ func resourceNsxtFirewallSectionUpdate(d *schema.ResourceData, m interface{}) er

var resp *http.Response
var err error
if len(rules) == 0 || nsxVersionLower("2.2.0") {
if len(rules) == 0 || util.NsxVersionLower("2.2.0") {
// Due to an NSX bug, the empty update should also be called to update ToS & tags fields
section := *firewallSection.GetFirewallSection()
// Update the section ignoring the rules
Expand Down
Loading

0 comments on commit 65f673f

Please sign in to comment.