Skip to content

Commit

Permalink
Merge pull request #885 from ksamoray/multitenancy-proj-data
Browse files Browse the repository at this point in the history
Multitenancy project data source
  • Loading branch information
ksamoray authored Jun 20, 2023
2 parents e6bde64 + ef8a6b0 commit 81aed05
Show file tree
Hide file tree
Showing 11 changed files with 1,093 additions and 0 deletions.
128 changes: 128 additions & 0 deletions nsxt/data_source_nsxt_policy_project.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
/* Copyright © 2023 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/vmware/vsphere-automation-sdk-go/services/nsxt/model"
infra "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/orgs"
)

const defaultOrgID = "default"

func dataSourceNsxtPolicyProject() *schema.Resource {
return &schema.Resource{
Read: dataSourceNsxtPolicyProjectRead,

Schema: map[string]*schema.Schema{
"id": getDataSourceIDSchema(),
"display_name": getDataSourceDisplayNameSchema(),
"description": getDataSourceDescriptionSchema(),
"path": getPathSchema(),
"short_id": {
Type: schema.TypeString,
Optional: true,
},
"site_info": {
Type: schema.TypeList,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"edge_cluster_paths": {
Type: schema.TypeList,
Elem: &schema.Schema{
Type: schema.TypeString,
},
Optional: true,
},
"site_path": {
Type: schema.TypeString,
Optional: true,
},
},
},
Optional: true,
},
"tier0_gateway_paths": {
Type: schema.TypeList,
Elem: &schema.Schema{
Type: schema.TypeString,
},
Optional: true,
},
},
}
}

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

// As Project resource type paths reside under project and not under /infra or /global_infra or such, and since
// this data source fetches extra attributes, e.g site_info and tier0_gateway_paths, it's simpler to implement using .List()
// instead of using search API.

objID := d.Get("id").(string)
objName := d.Get("display_name").(string)
var obj model.Project
if objID != "" {
// Get by id
objGet, err := client.Get(defaultOrgID, objID)
if err != nil {
return handleDataSourceReadError(d, "Project", objID, err)
}
obj = objGet
} else if objName == "" {
return fmt.Errorf("Error obtaining Project ID or name during read")
} else {
// Get by full name/prefix
objList, err := client.List(defaultOrgID, nil, nil, nil, nil, nil, nil, nil)
if err != nil {
return handleListError("Project", err)
}
// go over the list to find the correct one (prefer a perfect match. If not - prefix match)
var perfectMatch []model.Project
var prefixMatch []model.Project
for _, objInList := range objList.Results {
if strings.HasPrefix(*objInList.DisplayName, objName) {
prefixMatch = append(prefixMatch, objInList)
}
if *objInList.DisplayName == objName {
perfectMatch = append(perfectMatch, objInList)
}
}
if len(perfectMatch) > 0 {
if len(perfectMatch) > 1 {
return fmt.Errorf("Found multiple Project with name '%s'", objName)
}
obj = perfectMatch[0]
} else if len(prefixMatch) > 0 {
if len(prefixMatch) > 1 {
return fmt.Errorf("Found multiple Projects with name starting with '%s'", objName)
}
obj = prefixMatch[0]
} else {
return fmt.Errorf("Project with name '%s' was not found", objName)
}
}

d.SetId(*obj.Id)
d.Set("display_name", obj.DisplayName)
d.Set("description", obj.Description)
d.Set("path", obj.Path)

var siteInfosList []map[string]interface{}
for _, item := range obj.SiteInfos {
data := make(map[string]interface{})
data["edge_cluster_paths"] = item.EdgeClusterPaths
data["site_path"] = item.SitePath
siteInfosList = append(siteInfosList, data)
}
d.Set("site_info", siteInfosList)
d.Set("tier0_gateway_paths", obj.Tier0s)

return nil
}
105 changes: 105 additions & 0 deletions nsxt/data_source_nsxt_policy_project_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/* Copyright © 2023 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/services/nsxt/model"
orgs "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/orgs"
)

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

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() {
testAccOnlyLocalManager(t)
testAccPreCheck(t)
testAccNSXVersion(t, "4.1.0")
},
Providers: testAccProviders,
CheckDestroy: func(state *terraform.State) error {
return testAccDataSourceNsxtPolicyProjectDeleteByName(name)
},
Steps: []resource.TestStep{
{
PreConfig: func() {
if err := testAccDataSourceNsxtPolicyProjectCreate(name); err != nil {
panic(err)
}
},
Config: testAccNsxtPolicyProjectReadTemplate(name),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(testResourceName, "display_name", name),
resource.TestCheckResourceAttr(testResourceName, "description", name),
resource.TestCheckResourceAttrSet(testResourceName, "path"),
resource.TestCheckResourceAttr(testResourceName, "tier0_gateway_paths.#", "1"),
),
},
},
})
}

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

var tier0s = []string{getTier0RouterPath(connector)}
client := orgs.NewProjectsClient(connector)

displayName := name
description := name
obj := model.Project{
Description: &description,
DisplayName: &displayName,
Tier0s: tier0s,
}

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

err = client.Patch(defaultOrgID, id, obj)
if err != nil {
return handleCreateError("Project", id, err)
}
return nil
}

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

// Find the object by name
objList, err := client.List(defaultOrgID, nil, nil, nil, nil, nil, nil, nil)
if err != nil {
return handleListError("Project", err)
}
for _, objInList := range objList.Results {
if *objInList.DisplayName == name {
err := client.Delete(defaultOrgID, *objInList.Id)
if err != nil {
return handleDeleteError("Project", *objInList.Id, err)
}
return nil
}
}
return fmt.Errorf("Error while deleting Project '%s': resource not found", name)
}

func testAccNsxtPolicyProjectReadTemplate(name string) string {
return fmt.Sprintf(`
data "nsxt_policy_project" "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 @@ -267,6 +267,7 @@ func Provider() *schema.Provider {
"nsxt_policy_ipsec_vpn_service": dataSourceNsxtPolicyIPSecVpnService(),
"nsxt_policy_l2_vpn_service": dataSourceNsxtPolicyL2VpnService(),
"nsxt_policy_segment": dataSourceNsxtPolicySegment(),
"nsxt_policy_project": dataSourceNsxtPolicyProject(),
},

ResourcesMap: map[string]*schema.Resource{
Expand Down
11 changes: 11 additions & 0 deletions nsxt/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import (
"testing"
"time"

"github.com/vmware/vsphere-automation-sdk-go/services/nsxt/infra"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
"github.com/vmware/go-vmware-nsxt/trust"
Expand Down Expand Up @@ -89,6 +91,15 @@ func getTier0RouterName() string {
return name
}

func getTier0RouterPath(connector client.Connector) string {
// Retrieve Tier0 path
routerName := getTier0RouterName()
t0client := infra.NewTier0sClient(connector)
tier0, _ := t0client.Get(routerName)

return *tier0.Path
}

func getEdgeClusterName() string {
name := os.Getenv("NSXT_TEST_EDGE_CLUSTER")
if name == "" {
Expand Down

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

Loading

0 comments on commit 81aed05

Please sign in to comment.