Skip to content

Commit

Permalink
Add data source for HTTP app profiles
Browse files Browse the repository at this point in the history
Fixes: vmware#720
Signed-off-by: Kobi Samoray <[email protected]>
  • Loading branch information
ksamoray committed Sep 6, 2022
1 parent 8e4241b commit 3589785
Show file tree
Hide file tree
Showing 3 changed files with 363 additions and 0 deletions.
214 changes: 214 additions & 0 deletions nsxt/data_source_nsxt_policy_lb_http_app_profile.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
/* Copyright © 2022 VMware, Inc. All Rights Reserved.
SPDX-License-Identifier: MPL-2.0 */

package nsxt

import (
"fmt"
"strings"

"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/infra"
"github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model"
)

var lbHTTPAppProfileTypeValues = []string{"HTTP"}
var lbHTTPAppProfileTypeMap = map[string]string{
model.LBAppProfile_RESOURCE_TYPE_LBHTTPPROFILE: "HTTP",
}

var lbHTTPAppProfileXFFValues = []string{"INSERT", "REPLACE"}

func dataSourceNsxtPolicyLBHTTPAppProfile() *schema.Resource {
return &schema.Resource{
Read: dataSourceNsxtPolicyLBHTTPAppProfileRead,

Schema: map[string]*schema.Schema{
"id": getDataSourceIDSchema(),
"type": {
Type: schema.TypeString,
Description: "Application Profile Type",
Optional: true,
Default: "HTTP",
ValidateFunc: validation.StringInSlice(lbHTTPAppProfileTypeValues, false),
},
"display_name": getDataSourceDisplayNameSchema(),
"description": getDataSourceDescriptionSchema(),
"path": getPathSchema(),
"http_direct_to": {
Type: schema.TypeString,
Description: "Target URL when virtual server is down",
Optional: true,
ValidateFunc: validation.IsURLWithHTTPorHTTPS,
},
"http_redirect_to_https": {
Type: schema.TypeBool,
Description: "Force Redirect via HTTPS",
Optional: true,
},
"idle_timeout": {
Type: schema.TypeInt,
Description: "Idle timeout",
Optional: true,
},
"ntlm": {
Type: schema.TypeBool,
Description: "NTLM Authentication",
Optional: true,
},
"request_body_size": {
Type: schema.TypeInt,
Description: "Request body size",
Optional: true,
},
"request_header_size": {
Type: schema.TypeInt,
Description: "Request header size",
Optional: true,
},
"response_buffering": {
Type: schema.TypeBool,
Description: "Response buffering",
Optional: true,
},
"response_header_size": {
Type: schema.TypeInt,
Description: "Request header size",
Optional: true,
},
"response_timeout": {
Type: schema.TypeInt,
Description: "Request timeout",
Optional: true,
},
"server_keep_alive": {
Type: schema.TypeBool,
Description: "Server keep alive",
Optional: true,
},
"x_forwarded_for": {
Type: schema.TypeString,
Description: "Insert or replace x_forwarded_for",
Optional: true,
ValidateFunc: validation.StringInSlice(lbHTTPAppProfileXFFValues, false),
},
},
}
}

func policyLbHTTPAppProfileConvert(obj *data.StructValue, requestedType string) (*model.LBHttpProfile, error) {
converter := bindings.NewTypeConverter()
converter.SetMode(bindings.REST)

data, errs := converter.ConvertToGolang(obj, model.LBHttpProfileBindingType())
if errs != nil {
return nil, errs[0]
}

profile := data.(model.LBHttpProfile)
profileType, ok := lbHTTPAppProfileTypeMap[profile.ResourceType]
if !ok {
return nil, fmt.Errorf("Unknown LB Application Profile type %s", profile.ResourceType)
}
if (requestedType != "HTTP") && (requestedType != profileType) {
return nil, nil
}
return &profile, nil
}

func dataSourceNsxtPolicyLBHTTPAppProfileRead(d *schema.ResourceData, m interface{}) error {
connector := getPolicyConnector(m)
client := infra.NewLbAppProfilesClient(connector)

objID := d.Get("id").(string)
objTypeValue, typeSet := d.GetOk("type")
objType := objTypeValue.(string)
objName := d.Get("display_name").(string)
var result *model.LBHttpProfile
if objID != "" {
// Get by id
objGet, err := client.Get(objID)

if err != nil {
return handleDataSourceReadError(d, "LBHttpProfile", objID, err)
}
result, err = policyLbHTTPAppProfileConvert(objGet, objType)
if err != nil {
return fmt.Errorf("Error while converting LBHttpProfile %s: %v", objID, err)
}
if result == nil {
return fmt.Errorf("LBHttpProfile with ID '%s' and type %s was not found", objID, objType)
}
} else if objName == "" && !typeSet {
return fmt.Errorf("Error obtaining LBHttpProfile ID or name or type during read")
} else {
// Get by full name/prefix
includeMarkForDeleteObjectsParam := false
objList, err := client.List(nil, &includeMarkForDeleteObjectsParam, nil, nil, nil, nil)
if err != nil {
return handleListError("LBHttpProfile", err)
}
// go over the list to find the correct one (prefer a perfect match. If not - prefix match)
var perfectMatch []model.LBHttpProfile
var prefixMatch []model.LBHttpProfile
for _, objInList := range objList.Results {
resourceType, err := objInList.String("resource_type")
if err != nil {
return fmt.Errorf("Couldn't read resource_type %s: %v", objID, err)
}
if resourceType == "LBHttpProfile" {
obj, err := policyLbHTTPAppProfileConvert(objInList, objType)
if err != nil {
return fmt.Errorf("Error while converting LBHttpProfile %s: %v", objID, err)
}
if obj == nil {
continue
}
if objName != "" && obj.DisplayName != nil && strings.HasPrefix(*obj.DisplayName, objName) {
prefixMatch = append(prefixMatch, *obj)
}
if obj.DisplayName != nil && *obj.DisplayName == objName {
perfectMatch = append(perfectMatch, *obj)
}
if objName == "" && typeSet {
// match only by type
perfectMatch = append(perfectMatch, *obj)
}
}
if len(perfectMatch) > 0 {
if len(perfectMatch) > 1 {
return fmt.Errorf("Found multiple LBHttpProfiles with name '%s'", objName)
}
result = &perfectMatch[0]
} else if len(prefixMatch) > 0 {
if len(prefixMatch) > 1 {
return fmt.Errorf("Found multiple LBHttpProfiles with name starting with '%s'", objName)
}
result = &prefixMatch[0]
} else {
return fmt.Errorf("LBHttpProfile with name '%s' and type %s was not found", objName, objType)
}
}
}

d.SetId(*result.Id)
d.Set("display_name", result.DisplayName)
d.Set("type", lbHTTPAppProfileTypeMap[result.ResourceType])
d.Set("description", result.Description)
d.Set("path", result.Path)
d.Set("http_direct_to", result.HttpRedirectTo)
d.Set("http_redirect_to_https", result.HttpRedirectToHttps)
d.Set("idle_timeout", result.IdleTimeout)
d.Set("ntlm", result.Ntlm)
d.Set("request_body_size", result.RequestBodySize)
d.Set("request_header_size", result.RequestHeaderSize)
d.Set("response_buffering", result.ResponseBuffering)
d.Set("response_header_size", result.ResponseHeaderSize)
d.Set("response_timeout", result.ResponseTimeout)
d.Set("server_keep_alive", result.ServerKeepAlive)
d.Set("x_forwarded_for", result.XForwardedFor)
return nil
}
148 changes: 148 additions & 0 deletions nsxt/data_source_nsxt_policy_lb_http_app_profile_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
/* Copyright © 2022 VMware, 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"
"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/infra"
"github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model"
)

func TestAccDataSourceNsxtPolicyLBHTTPAppProfile_basic(t *testing.T) {
name := getAccTestDataSourceName()
testResourceName := "data.nsxt_policy_lb_http_app_profile.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccOnlyLocalManager(t); testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: func(state *terraform.State) error {
return testAccDataSourceNsxtPolicyLBHTTPAppProfileDeleteByName(name)
},
Steps: []resource.TestStep{
{
PreConfig: func() {
if err := testAccDataSourceNsxtPolicyLBHTTPAppProfileCreate(name); err != nil {
panic(err)
}
},
Config: testAccNsxtPolicyLBHTTPAppProfileReadTemplate(name),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(testResourceName, "display_name", name),
resource.TestCheckResourceAttr(testResourceName, "description", name),
resource.TestCheckResourceAttr(testResourceName, "type", "HTTP"),
resource.TestCheckResourceAttrSet(testResourceName, "path"),
),
},
{
/* fetch test profile by name only */
Config: testAccNsxtPolicyLBHTTPAppProfileNameOnlyTemplate(name),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(testResourceName, "display_name", name),
resource.TestCheckResourceAttr(testResourceName, "description", name),
resource.TestCheckResourceAttr(testResourceName, "type", "HTTP"),
resource.TestCheckResourceAttrSet(testResourceName, "path"),
),
},
{
/* fetch default HTTP profile */
Config: testAccNsxtPolicyLBHTTPAppProfileTypeOnlyTemplate("HTTP"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrSet(testResourceName, "display_name"),
resource.TestCheckResourceAttr(testResourceName, "type", "HTTP"),
resource.TestCheckResourceAttrSet(testResourceName, "path"),
),
},
},
})
}

func testAccDataSourceNsxtPolicyLBHTTPAppProfileCreate(name string) error {
connector, err := testAccGetPolicyConnector()
if err != nil {
return fmt.Errorf("Error during test client initialization: %v", err)
}
client := infra.NewLbAppProfilesClient(connector)
converter := bindings.NewTypeConverter()
converter.SetMode(bindings.REST)

displayName := name
description := name
profileType := "LBHttpProfile"
obj := model.LBHttpProfile{
Description: &description,
DisplayName: &displayName,
ResourceType: profileType,
}

dataValue, errs := converter.ConvertToVapi(obj, model.LBHttpProfileBindingType())
if errs != nil {
return fmt.Errorf("Error during conversion of LBHttpProfile: %v", errs[0])
}

// Generate a random ID for the resource
id := newUUID()

err = client.Patch(id, dataValue.(*data.StructValue))
if err != nil {
return handleCreateError("LBHttpProfile", id, err)
}
return nil
}

func testAccDataSourceNsxtPolicyLBHTTPAppProfileDeleteByName(name string) error {
connector, err := testAccGetPolicyConnector()
if err != nil {
return fmt.Errorf("Error during test client initialization: %v", err)
}
client := infra.NewLbAppProfilesClient(connector)

// Find the object by name
objList, err := client.List(nil, nil, nil, nil, nil, nil)
if err != nil {
return handleListError("LBHttpProfile", err)
}
force := true
for _, objInList := range objList.Results {
result, err := policyLbAppProfileConvert(objInList, "ANY")
if err != nil {
return fmt.Errorf("Error during LBHttpProfile conversion: %v", err)
}
if result != nil && *result.DisplayName == name {
err := client.Delete(*result.Id, &force)
if err != nil {
return handleDeleteError("LBHttpProfile", *result.Id, err)
}
return nil
}
}
return fmt.Errorf("Error while deleting LBHttpProfile '%s': resource not found", name)
}

func testAccNsxtPolicyLBHTTPAppProfileReadTemplate(name string) string {
return fmt.Sprintf(`
data "nsxt_policy_lb_http_app_profile" "test" {
type = "TCP"
display_name = "%s"
}`, name)
}

func testAccNsxtPolicyLBHTTPAppProfileTypeOnlyTemplate(pType string) string {
return fmt.Sprintf(`
data "nsxt_policy_lb_http_app_profile" "test" {
type = "%s"
}`, pType)
}

func testAccNsxtPolicyLBHTTPAppProfileNameOnlyTemplate(name string) string {
return fmt.Sprintf(`
data "nsxt_policy_lb_http_app_profile" "test" {
display_name = "%s"
}`, name)
}
1 change: 1 addition & 0 deletions nsxt/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ func Provider() *schema.Provider {
"nsxt_policy_vm": dataSourceNsxtPolicyVM(),
"nsxt_policy_vms": dataSourceNsxtPolicyVMs(),
"nsxt_policy_lb_app_profile": dataSourceNsxtPolicyLBAppProfile(),
"nsxt_policy_lb_http_app_profile": dataSourceNsxtPolicyLBHTTPAppProfile(),
"nsxt_policy_lb_client_ssl_profile": dataSourceNsxtPolicyLBClientSslProfile(),
"nsxt_policy_lb_server_ssl_profile": dataSourceNsxtPolicyLBServerSslProfile(),
"nsxt_policy_lb_monitor": dataSourceNsxtPolicyLBMonitor(),
Expand Down

0 comments on commit 3589785

Please sign in to comment.