Skip to content

Commit

Permalink
Merge pull request vmware#1145 from ksamoray/md_proxy
Browse files Browse the repository at this point in the history
Implement MD proxy and use in segment resources
  • Loading branch information
ksamoray authored Mar 26, 2024
2 parents fb06307 + 014dd61 commit d255fda
Show file tree
Hide file tree
Showing 8 changed files with 466 additions and 0 deletions.
1 change: 1 addition & 0 deletions nsxt/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,7 @@ func Provider() *schema.Provider {
"nsxt_policy_vtep_ha_host_switch_profile": resourceNsxtVtepHAHostSwitchProfile(),
"nsxt_policy_site": resourceNsxtPolicySite(),
"nsxt_policy_global_manager": resourceNsxtPolicyGlobalManager(),
"nsxt_policy_metadata_proxy": resourceNsxtPolicyMetadataProxy(),
},

ConfigureFunc: providerConfigure,
Expand Down
212 changes: 212 additions & 0 deletions nsxt/resource_nsxt_policy_metadata_proxy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
/* Copyright © 2024 Broadcom, 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/protocol/client"
"github.com/vmware/vsphere-automation-sdk-go/services/nsxt/infra"
"github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model"
)

var cryptoProtocolsValues = []string{"TLS_V1", "TLS_V1_1", "TLS_V1_2"}

func resourceNsxtPolicyMetadataProxy() *schema.Resource {
return &schema.Resource{
Create: resourceNsxtPolicyMetadataProxyCreate,
Read: resourceNsxtPolicyMetadataProxyRead,
Update: resourceNsxtPolicyMetadataProxyUpdate,
Delete: resourceNsxtPolicyMetadataProxyDelete,
Importer: &schema.ResourceImporter{
State: nsxtPolicyPathResourceImporter,
},

Schema: map[string]*schema.Schema{
"nsx_id": getNsxIDSchema(),
"path": getPathSchema(),
"display_name": getDisplayNameSchema(),
"description": getDescriptionSchema(),
"revision": getRevisionSchema(),
"tag": getTagsSchema(),
"crypto_protocols": {
Type: schema.TypeList,
Computed: true,
Optional: true,
Description: "Metadata proxy supported cryptographic protocols",
Elem: &schema.Schema{
Type: schema.TypeString,
ValidateFunc: validation.StringInSlice(cryptoProtocolsValues, false),
},
},
"edge_cluster_path": {
Type: schema.TypeString,
Required: true,
Description: "Policy path to Edge Cluster",
ValidateFunc: validatePolicyPath(),
},
"enable_standby_relocation": {
Type: schema.TypeBool,
Optional: true,
Default: false,
Description: "Flag to enable standby relocation",
},
"preferred_edge_paths": {
Type: schema.TypeList,
Optional: true,
Description: "Preferred Edge Paths",
Elem: &schema.Schema{
Type: schema.TypeString,
ValidateFunc: validatePolicyPath(),
},
},
"secret": {
Type: schema.TypeString,
Required: true,
Sensitive: true,
Description: "Secret",
},
"server_address": {
Type: schema.TypeString,
Required: true,
Description: "Server Address",
},
"server_certificates": {
Type: schema.TypeList,
Optional: true,
Description: "Policy paths to Certificate Authority (CA) certificates",
Sensitive: true,
Elem: &schema.Schema{
Type: schema.TypeString,
Sensitive: true,
},
},
},
}
}

func resourceNsxtPolicyMetadataProxyExists(id string, connector client.Connector, isGlobalManager bool) (bool, error) {
client := infra.NewMetadataProxiesClient(connector)
_, err := client.Get(id)
if err == nil {
return true, nil
}

if isNotFoundError(err) {
return false, nil
}

return false, logAPIError("Error retrieving resource", err)
}

func getMetadataProxyFromSchema(d *schema.ResourceData) model.MetadataProxyConfig {
displayName := d.Get("display_name").(string)
description := d.Get("description").(string)
tags := getPolicyTagsFromSchema(d)

cryptoProtocols := interfaceListToStringList(d.Get("crypto_protocols").([]interface{}))
edgeClusterPath := d.Get("edge_cluster_path").(string)
enableStandbyRelocation := d.Get("enable_standby_relocation").(bool)
preferredEdgePaths := interfaceListToStringList(d.Get("preferred_edge_paths").([]interface{}))
secret := d.Get("secret").(string)
serverAddress := d.Get("server_address").(string)
serverCertificates := interfaceListToStringList(d.Get("server_certificates").([]interface{}))
return model.MetadataProxyConfig{
DisplayName: &displayName,
Description: &description,
Tags: tags,
CryptoProtocols: cryptoProtocols,
EdgeClusterPath: &edgeClusterPath,
EnableStandbyRelocation: &enableStandbyRelocation,
PreferredEdgePaths: preferredEdgePaths,
Secret: &secret,
ServerAddress: &serverAddress,
ServerCertificates: serverCertificates,
}
}

func resourceNsxtPolicyMetadataProxyCreate(d *schema.ResourceData, m interface{}) error {
// Initialize resource Id and verify this ID is not yet used
id, err := getOrGenerateID(d, m, resourceNsxtPolicyMetadataProxyExists)
if err != nil {
return err
}

connector := getPolicyConnector(m)
client := infra.NewMetadataProxiesClient(connector)
obj := getMetadataProxyFromSchema(d)
err = client.Patch(id, obj)
if err != nil {
return handleCreateError("PolicyMetadataProxy", id, err)
}

d.SetId(id)
d.Set("nsx_id", id)

return resourceNsxtPolicyMetadataProxyRead(d, m)
}

func resourceNsxtPolicyMetadataProxyRead(d *schema.ResourceData, m interface{}) error {
connector := getPolicyConnector(m)

id := d.Id()
if id == "" {
return fmt.Errorf("Error obtaining PolicyMetadataProxy ID")
}
client := infra.NewMetadataProxiesClient(connector)
obj, err := client.Get(id)
if err != nil {
return handleReadError(d, "PolicyMetadataProxy", id, err)
}

d.Set("display_name", obj.DisplayName)
d.Set("description", obj.Description)
setPolicyTagsInSchema(d, obj.Tags)
d.Set("nsx_id", id)
d.Set("path", obj.Path)
d.Set("revision", obj.Revision)
d.Set("crypto_protocols", stringList2Interface(obj.CryptoProtocols))
d.Set("edge_cluster_path", obj.EdgeClusterPath)
d.Set("enable_standby_relocation", obj.EnableStandbyRelocation)
d.Set("preferred_edge_paths", stringList2Interface(obj.PreferredEdgePaths))
d.Set("server_address", obj.ServerAddress)

return nil
}

func resourceNsxtPolicyMetadataProxyUpdate(d *schema.ResourceData, m interface{}) error {
id := d.Id()
if id == "" {
return fmt.Errorf("Error obtaining PolicyMetadataProxy ID")
}

connector := getPolicyConnector(m)
client := infra.NewMetadataProxiesClient(connector)

obj := getMetadataProxyFromSchema(d)
revision := int64(d.Get("revision").(int))
obj.Revision = &revision
_, err := client.Update(id, obj)
if err != nil {
return handleUpdateError("PolicyMetadataProxy", id, err)
}

return resourceNsxtPolicyMetadataProxyRead(d, m)
}

func resourceNsxtPolicyMetadataProxyDelete(d *schema.ResourceData, m interface{}) error {
id := d.Id()
if id == "" {
return fmt.Errorf("error obtaining PolicyMetadataProxy ID")
}
connector := getPolicyConnector(m)
client := infra.NewMetadataProxiesClient(connector)
err := client.Delete(id)
if err != nil {
return handleDeleteError("PolicyMetadataProxy", id, err)
}
return nil
}
170 changes: 170 additions & 0 deletions nsxt/resource_nsxt_policy_metadata_proxy_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
/* Copyright © 2024 Broadcom, Inc. All Rights Reserved.
SPDX-License-Identifier: MPL-2.0 */

package nsxt

import (
"fmt"
"testing"

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

var accTestPolicyMetadataProxyCreateAttributes = map[string]string{
"display_name": getAccTestResourceName(),
"description": "terraform created",
"secret": "topsecret!!",
"server_address": "http://1.1.1.120:6000",
}

var accTestPolicyMetadataProxyUpdateAttributes = map[string]string{
"display_name": getAccTestResourceName(),
"description": "terraform updated",
"secret": "donottell:)",
"server_address": "http://1.1.1.123:6000",
}

func TestAccResourceNsxtPolicyMetadataProxy_basic(t *testing.T) {
testResourceName := "nsxt_policy_metadata_proxy.test"
resource.ParallelTest(t, resource.TestCase{
PreCheck: func() {
testAccOnlyLocalManager(t)
testAccPreCheck(t)
},
Providers: testAccProviders,
CheckDestroy: func(state *terraform.State) error {
return testAccNsxtPolicyMetadataProxyCheckDestroy(state, accTestPolicyMetadataProxyUpdateAttributes["display_name"])
},
Steps: []resource.TestStep{
{
Config: testAccNsxtPolicyMetadataProxyTemplate(true),
Check: resource.ComposeTestCheckFunc(
testAccNsxtPolicyMetadataProxyExists(accTestPolicyMetadataProxyCreateAttributes["display_name"], testResourceName),
resource.TestCheckResourceAttr(testResourceName, "display_name", accTestPolicyMetadataProxyCreateAttributes["display_name"]),
resource.TestCheckResourceAttr(testResourceName, "description", accTestPolicyMetadataProxyCreateAttributes["description"]),

resource.TestCheckResourceAttr(testResourceName, "secret", accTestPolicyMetadataProxyCreateAttributes["secret"]),
resource.TestCheckResourceAttr(testResourceName, "server_address", accTestPolicyMetadataProxyCreateAttributes["server_address"]),

resource.TestCheckResourceAttrSet(testResourceName, "nsx_id"),
resource.TestCheckResourceAttrSet(testResourceName, "path"),
resource.TestCheckResourceAttrSet(testResourceName, "revision"),
resource.TestCheckResourceAttr(testResourceName, "tag.#", "1"),
),
},
{
Config: testAccNsxtPolicyMetadataProxyTemplate(false),
Check: resource.ComposeTestCheckFunc(
testAccNsxtPolicyMetadataProxyExists(accTestPolicyMetadataProxyUpdateAttributes["display_name"], testResourceName),
resource.TestCheckResourceAttr(testResourceName, "display_name", accTestPolicyMetadataProxyUpdateAttributes["display_name"]),
resource.TestCheckResourceAttr(testResourceName, "description", accTestPolicyMetadataProxyUpdateAttributes["description"]),

resource.TestCheckResourceAttr(testResourceName, "secret", accTestPolicyMetadataProxyUpdateAttributes["secret"]),
resource.TestCheckResourceAttr(testResourceName, "server_address", accTestPolicyMetadataProxyUpdateAttributes["server_address"]),

resource.TestCheckResourceAttrSet(testResourceName, "nsx_id"),
resource.TestCheckResourceAttrSet(testResourceName, "path"),
resource.TestCheckResourceAttrSet(testResourceName, "revision"),
resource.TestCheckResourceAttr(testResourceName, "tag.#", "1"),
),
},
},
})
}

func TestAccResourceNsxtPolicyMetadataProxy_importBasic(t *testing.T) {
testResourceName := "nsxt_policy_metadata_proxy.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() {
testAccOnlyLocalManager(t)
testAccPreCheck(t)
},
Providers: testAccProviders,
CheckDestroy: func(state *terraform.State) error {
return testAccNsxtPolicyMetadataProxyCheckDestroy(state, accTestPolicyMetadataProxyUpdateAttributes["display_name"])
},
Steps: []resource.TestStep{
{
Config: testAccNsxtPolicyMetadataProxyTemplate(true),
},
{
ResourceName: testResourceName,
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"secret"}, // Secret isn't returned by NSX as it's a secret...
},
},
})
}

func testAccNsxtPolicyMetadataProxyExists(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("PolicyMetadataProxy resource %s not found in resources", resourceName)
}

resourceID := rs.Primary.ID
if resourceID == "" {
return fmt.Errorf("PolicyMetadataProxy resource ID not set in resources")
}

exists, err := resourceNsxtPolicyMetadataProxyExists(resourceID, connector, testAccIsGlobalManager())
if err != nil {
return err
}
if !exists {
return fmt.Errorf("PolicyMetadataProxy %s does not exist", resourceID)
}

return nil
}
}

func testAccNsxtPolicyMetadataProxyCheckDestroy(state *terraform.State, displayName string) error {
connector := getPolicyConnector(testAccProvider.Meta().(nsxtClients))
for _, rs := range state.RootModule().Resources {

if rs.Type != "nsxt_policy_metadata_proxy" {
continue
}

resourceID := rs.Primary.Attributes["id"]
exists, err := resourceNsxtPolicyMetadataProxyExists(resourceID, connector, testAccIsGlobalManager())
if err == nil {
return err
}

if exists {
return fmt.Errorf("PolicyMetadataProxy %s still exists", displayName)
}
}
return nil
}

func testAccNsxtPolicyMetadataProxyTemplate(createFlow bool) string {
var attrMap map[string]string
if createFlow {
attrMap = accTestPolicyMetadataProxyCreateAttributes
} else {
attrMap = accTestPolicyMetadataProxyUpdateAttributes
}
return testAccNsxtPolicyEdgeClusterReadTemplate(getEdgeClusterName()) + fmt.Sprintf(`
resource "nsxt_policy_metadata_proxy" "test" {
display_name = "%s"
description = "%s"
edge_cluster_path = data.nsxt_policy_edge_cluster.test.path
secret = "%s"
server_address = "%s"
tag {
scope = "scope1"
tag = "tag1"
}
}
`, attrMap["display_name"], attrMap["description"], attrMap["secret"], attrMap["server_address"])
}
Loading

0 comments on commit d255fda

Please sign in to comment.