Skip to content

Commit

Permalink
Merge pull request #965 from ksamoray/host_transport_node_collection
Browse files Browse the repository at this point in the history
Implement host transport node collection resource
  • Loading branch information
ksamoray authored Oct 7, 2023
2 parents d341d2e + 7b1ff98 commit 6ed3a27
Show file tree
Hide file tree
Showing 4 changed files with 361 additions and 1 deletion.
1 change: 1 addition & 0 deletions nsxt/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,7 @@ func Provider() *schema.Provider {
"nsxt_policy_host_transport_node_profile": resourceNsxtPolicyHostTransportNodeProfile(),
"nsxt_policy_host_transport_node": resourceNsxtPolicyHostTransportNode(),
"nsxt_edge_high_availability_profile": resourceNsxtEdgeHighAvailabilityProfile(),
"nsxt_policy_host_transport_node_collection": resourceNsxtPolicyHostTransportNodeCollection(),
},

ConfigureFunc: providerConfigure,
Expand Down
297 changes: 297 additions & 0 deletions nsxt/resource_nsxt_policy_host_transport_node_collection.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,297 @@
/* Copyright © 2023 VMware, Inc. All Rights Reserved.
SPDX-License-Identifier: MPL-2.0 */

package nsxt

import (
"fmt"
"log"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"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/infra/sites/enforcement_points"
"github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model"
)

func resourceNsxtPolicyHostTransportNodeCollection() *schema.Resource {
return &schema.Resource{
Create: resourceNsxtPolicyHostTransportNodeCollectionCreate,
Read: resourceNsxtPolicyHostTransportNodeCollectionRead,
Update: resourceNsxtPolicyHostTransportNodeCollectionUpdate,
Delete: resourceNsxtPolicyHostTransportNodeCollectionDelete,
Importer: &schema.ResourceImporter{
State: resourceNsxtPolicyHostTransportNodeCollectionImporter,
},

Schema: map[string]*schema.Schema{
"nsx_id": getNsxIDSchema(),
"path": getPathSchema(),
"display_name": getDisplayNameSchema(),
"description": getDescriptionSchema(),
"revision": getRevisionSchema(),
"tag": getTagsSchema(),
"site_path": {
Type: schema.TypeString,
Description: "Path to the site this resource belongs to",
Optional: true,
ForceNew: true,
Default: defaultInfraSitePath,
ValidateFunc: validatePolicyPath(),
},
"enforcement_point": {
Type: schema.TypeString,
Description: "ID of the enforcement point this resource belongs to",
Optional: true,
ForceNew: true,
Computed: true,
},
"compute_collection_id": {
Type: schema.TypeString,
Required: true,
Description: "Compute collection id",
},
"sub_cluster_config": {
Type: schema.TypeList,
Optional: true,
Description: "List of sub-cluster configuration",
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"host_switch_config_source": {
Type: schema.TypeList,
Required: true,
Description: "List of overridden HostSwitch configuration",
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"host_switch_id": {
Type: schema.TypeString,
Required: true,
Description: "HostSwitch Id",
},
"transport_node_profile_sub_config_name": {
Type: schema.TypeString,
Required: true,
Description: "Name of the TransportNodeProfile sub configuration to be used",
},
},
},
},
"sub_cluster_id": {
Type: schema.TypeString,
Required: true,
Description: "sub-cluster Id",
},
},
},
},
"transport_node_profile_path": {
Type: schema.TypeString,
Optional: true,
Description: "Transport Node Profile Path",
},
},
}
}

func resourceNsxtPolicyHostTransportNodeCollectionExists(siteID, epID, id string, connector client.Connector) (bool, error) {
// Check site existence first
siteClient := infra.NewSitesClient(connector)
_, err := siteClient.Get(siteID)
if err != nil {
msg := fmt.Sprintf("Failed to read site %s", siteID)
return false, logAPIError(msg, err)
}

client := enforcement_points.NewTransportNodeCollectionsClient(connector)
_, err = client.Get(siteID, epID, id)
if err == nil {
return true, nil
}

if isNotFoundError(err) {
return false, nil
}

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

func policyHostTransportNodeCollectionUpdate(siteID, epID, id string, applyProfileParam bool, d *schema.ResourceData, m interface{}) error {
connector := getPolicyConnector(m)

displayName := d.Get("display_name").(string)
description := d.Get("description").(string)
tags := getPolicyTagsFromSchema(d)

computeCollectionID := d.Get("compute_collection_id").(string)
transportNodeProfileID := d.Get("transport_node_profile_path").(string)
var subClusterConfigs []model.SubClusterConfig
for _, scc := range d.Get("sub_cluster_config").([]interface{}) {
subClusterConfig := scc.(map[string]interface{})
var hostSwitchConfigSources []model.HostSwitchConfigSource
for _, hss := range subClusterConfig["host_switch_config_source"].([]interface{}) {
hsSource := hss.(map[string]interface{})
hostSwitchID := hsSource["host_switch_id"].(string)
transportNodeProfileSubConfigName := hsSource["transport_node_profile_sub_config_name"].(string)
elem := model.HostSwitchConfigSource{
HostSwitchId: &hostSwitchID,
TransportNodeProfileSubConfigName: &transportNodeProfileSubConfigName,
}
hostSwitchConfigSources = append(hostSwitchConfigSources, elem)
}
subClusterID := subClusterConfig["sub_cluster_id"].(string)
elem := model.SubClusterConfig{
SubClusterId: &subClusterID,
HostSwitchConfigSources: hostSwitchConfigSources,
}
subClusterConfigs = append(subClusterConfigs, elem)
}
obj := model.HostTransportNodeCollection{
DisplayName: &displayName,
Description: &description,
Tags: tags,
ComputeCollectionId: &computeCollectionID,
TransportNodeProfileId: &transportNodeProfileID,
SubClusterConfig: subClusterConfigs,
}

client := enforcement_points.NewTransportNodeCollectionsClient(connector)
_, err := client.Update(siteID, epID, id, obj, &applyProfileParam, nil)

return err
}

func resourceNsxtPolicyHostTransportNodeCollectionCreate(d *schema.ResourceData, m interface{}) error {
connector := getPolicyConnector(m)
id := d.Get("nsx_id").(string)
if id == "" {
id = newUUID()
}
sitePath := d.Get("site_path").(string)
siteID := getResourceIDFromResourcePath(sitePath, "sites")
if siteID == "" {
return fmt.Errorf("error obtaining Site ID from site path %s", sitePath)
}
epID := d.Get("enforcement_point").(string)
if epID == "" {
epID = getPolicyEnforcementPoint(m)
}

exists, err := resourceNsxtPolicyHostTransportNodeCollectionExists(siteID, epID, id, connector)
if err != nil {
return err
}
if exists {
return fmt.Errorf("resource with ID %s already exists", id)
}

// Create the resource using PATCH
log.Printf("[INFO] Creating HostTransportNodeCollection with ID %s under site %s enforcement point %s", id, siteID, epID)
err = policyHostTransportNodeCollectionUpdate(siteID, epID, id, true, d, m)
if err != nil {
return handleCreateError("HostTransportNodeCollection", id, err)
}

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

return resourceNsxtPolicyHostTransportNodeCollectionRead(d, m)
}

func resourceNsxtPolicyHostTransportNodeCollectionRead(d *schema.ResourceData, m interface{}) error {
connector := getPolicyConnector(m)
client := enforcement_points.NewTransportNodeCollectionsClient(connector)
// (TODO) Reusing this code here - maybe worthwhile renaming this func as it's usable for other resources
id, siteID, epID, err := policyIDSiteEPTuple(d, m)
if err != nil {
return err
}
obj, err := client.Get(siteID, epID, id)
if err != nil {
return handleReadError(d, "HostTransportNodeCollection", id, err)
}

d.Set("enforcement_point", epID)
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("compute_collection_id", obj.ComputeCollectionId)
if obj.SubClusterConfig != nil {
var sccList []map[string]interface{}
for _, cfg := range obj.SubClusterConfig {
scc := make(map[string]interface{})

if cfg.HostSwitchConfigSources != nil {
var hscsList []map[string]interface{}
for _, src := range cfg.HostSwitchConfigSources {
hscs := make(map[string]interface{})
hscs["host_switch_id"] = src.HostSwitchId
hscs["transport_node_profile_sub_config_name"] = src.TransportNodeProfileSubConfigName
hscsList = append(hscsList, hscs)
}
scc["host_switch_config_source"] = hscsList
}

scc["sub_cluster_id"] = cfg.SubClusterId
sccList = append(sccList, scc)
}
d.Set("sub_cluster_config", sccList)
}
d.Set("transport_node_profile_path", obj.TransportNodeProfileId)
return nil
}

func resourceNsxtPolicyHostTransportNodeCollectionUpdate(d *schema.ResourceData, m interface{}) error {
id, siteID, epID, err := policyIDSiteEPTuple(d, m)
if err != nil {
return err
}

log.Printf("[INFO] Updating HostTransportNodeCollection with ID %s", id)
err = policyHostTransportNodeCollectionUpdate(siteID, epID, id, false, d, m)

if err != nil {
return handleUpdateError("HostTransportNodeCollection", id, err)
}

return resourceNsxtPolicyHostTransportNodeCollectionRead(d, m)
}

func resourceNsxtPolicyHostTransportNodeCollectionDelete(d *schema.ResourceData, m interface{}) error {
connector := getPolicyConnector(m)
client := enforcement_points.NewTransportNodeCollectionsClient(connector)
id, siteID, epID, err := policyIDSiteEPTuple(d, m)
if err != nil {
return err
}

log.Printf("[INFO] Deleting HostTransportNodeCollection with ID %s", id)
err = client.Delete(siteID, epID, id)
if err != nil {
return handleDeleteError("HostTransportNodeCollection", id, err)
}

return nil
}

func resourceNsxtPolicyHostTransportNodeCollectionImporter(d *schema.ResourceData, m interface{}) ([]*schema.ResourceData, error) {
importID := d.Id()
rd, err := nsxtPolicyPathResourceImporterHelper(d, m)
if err != nil {
return rd, err
}

epID, err := getParameterFromPolicyPath("/enforcement-points/", "/transport-node-collections/", importID)
if err != nil {
return nil, err
}
d.Set("enforcement_point", epID)
sitePath, err := getSitePathFromChildResourcePath(importID)
if err != nil {
return rd, err
}
d.Set("site_path", sitePath)
return rd, nil
}
2 changes: 1 addition & 1 deletion nsxt/resource_nsxt_policy_transport_zone.go
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ func resourceNsxtPolicyTransportZoneUpdate(d *schema.ResourceData, m interface{}
return err
}

log.Printf("[INFO] Updateing TransportZone with ID %s", id)
log.Printf("[INFO] Updating TransportZone with ID %s", id)
err = policyTransportZonePatch(siteID, epID, id, d, m)
if err != nil {
return handleUpdateError("TransportZone", id, err)
Expand Down
62 changes: 62 additions & 0 deletions website/docs/r/policy_host_transport_node_collection.html.markdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
---
subcategory: "Fabric"
layout: "nsxt"
page_title: "NSXT: nsxt_policy_host_transport_node_collection"
description: A resource to configure Policy Host Transport Node Collection.
---

# nsxt_policy_host_transport_node_collection

This resource provides a method for the management of a Host Transport Node Collection.

# Example Usage

```hcl
data "vsphere_compute_cluster" "compute_cluster" {
provider = vsphere.vsphere-nsxcfg-data
name = "Compute-Cluster"
datacenter_id = data.vsphere_datacenter.datacenter.id
}
resource "nsxt_policy_host_transport_node_collection" "htnc1" {
display_name = "HostTransportNodeCollection1"
compute_collection_id = data.vsphere_compute_cluster.compute_cluster.id
transport_node_profile_path = nsxt_policy_host_transport_node_profile.tnp.path
tag {
scope = "color"
tag = "red"
}
}
```

## Argument Reference

The following arguments are supported:

* `display_name` - (Optional) The Display Name of the Transport Zone.
* `description` - (Optional) Description of the Transport Zone.
* `tag` - (Optional) A list of scope + tag pairs to associate with this resource.
* `nsx_id` - (Optional) The NSX ID of this resource. If set, this ID will be used to create the policy resource.
* `compute_collection_id` - (Required) Compute collection id.
* `sub_cluster_config` - (Optional) List of sub-cluster configuration.
* `host_switch_config_source` - (Required) List of overridden HostSwitch configuration.
* `host_switch_id` - (Required) HostSwitch ID.
* `transport_node_profile_sub_config_name` - (Required) Name of the TransportNodeProfile sub configuration to be used.
* `sub_cluster_id` - (Required) sub-cluster ID.
* `transport_node_profile_path` - (Optional) Transport Node Profile Path.

## Attributes Reference

In addition to arguments listed above, the following attributes are exported:

* `id` - ID of the resource.
* `revision` - Indicates current revision number of the object as seen by NSX-T API server. This attribute can be useful for debugging.
* `path` - The NSX path of the policy resource.

## Importing

An existing policy Host Transport Node Collection can be [imported][docs-import] into this resource, via the following command:

terraform import nsxt_policy_host_transport_node_collection.test POLICY_PATH

The above command imports Policy Host Transport Node Collection named test with NSX policy path POLICY_PATH.

0 comments on commit 6ed3a27

Please sign in to comment.