Skip to content

Commit

Permalink
Add policy sub cluster resource
Browse files Browse the repository at this point in the history
Signed-off-by: Anna Khmelnitsky <[email protected]>
  • Loading branch information
annakhm committed Apr 9, 2024
1 parent 6eafd85 commit 7ef72f9
Show file tree
Hide file tree
Showing 3 changed files with 309 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 @@ -484,6 +484,7 @@ func Provider() *schema.Provider {
"nsxt_policy_global_manager": resourceNsxtPolicyGlobalManager(),
"nsxt_policy_metadata_proxy": resourceNsxtPolicyMetadataProxy(),
"nsxt_edge_transport_node_rtep": resourceNsxtEdgeTransportNodeRTEP(),
"nsxt_policy_compute_sub_cluster": resourceNsxtPolicyComputeSubCluster(),
},

ConfigureFunc: providerConfigure,
Expand Down
256 changes: 256 additions & 0 deletions nsxt/resource_nsxt_policy_compute_sub_cluster.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,256 @@
/* Copyright © 2024 Broadcom, 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 resourceNsxtPolicyComputeSubCluster() *schema.Resource {
return &schema.Resource{
Create: resourceNsxtPolicyComputeSubClusterCreate,
Read: resourceNsxtPolicyComputeSubClusterRead,
Update: resourceNsxtPolicyComputeSubClusterUpdate,
Delete: resourceNsxtPolicyComputeSubClusterDelete,
Importer: &schema.ResourceImporter{
State: resourceNsxtPolicyComputeSubClusterImporter,
},

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 subcluster belongs to",
Optional: true,
ForceNew: true,
Default: defaultInfraSitePath,
ValidateFunc: validatePolicyPath(),
},
"enforcement_point": {
Type: schema.TypeString,
Description: "ID of the enforcement point this subcluster belongs to",
Optional: true,
ForceNew: true,
Default: "default",
},
"compute_collection_id": {
Type: schema.TypeString,
Description: "Compute collection ID under which subcluster is created",
Required: true,
},
"discovered_node_ids": {
Type: schema.TypeList,
Description: "Discovered node IDs under this subcluster",
Optional: true,
Computed: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
},
}
}

func resourceNsxtPolicyComputeSubClusterRead(d *schema.ResourceData, m interface{}) error {
connector := getPolicyConnector(m)
scClient := enforcement_points.NewSubClustersClient(connector)

id, siteID, epID, err := policyIDSiteEPTuple(d, m)
if err != nil {
return err
}

obj, err := scClient.Get(siteID, epID, id)
if err != nil {
return handleReadError(d, "SubCluster", 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("compute_collection_id", obj.ComputeCollectionId)
if obj.SubClusterInfo != nil {
d.Set("discovered_node_ids", obj.SubClusterInfo.DiscoveredNodeIds)
}

return nil
}

func resourceNsxtPolicyComputeSubClusterExists(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)
}
scClient := enforcement_points.NewSubClustersClient(connector)
_, err = scClient.Get(siteID, epID, id)

if err == nil {
return true, nil
}

if isNotFoundError(err) {
return false, nil
}

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

func policyComputeSubClusterPatch(siteID, epID, id string, d *schema.ResourceData, m interface{}, isUpdate bool, isDelete bool) error {
connector := getPolicyConnector(m)
scClient := enforcement_points.NewSubClustersClient(connector)

description := d.Get("description").(string)
displayName := d.Get("display_name").(string)
collectionID := d.Get("compute_collection_id").(string)
tags := getPolicyTagsFromSchema(d)
discoveredNodes := getStringListFromSchemaList(d, "discovered_node_ids")
revision := int64(d.Get("revision").(int))
// Only manual type is supported for now
manual := model.SubClusterInfo_SUB_CLUSTER_TYPE_MANUAL
subClusterInfo := &model.SubClusterInfo{
SubClusterType: &manual,
}
obj := model.SubCluster{
Description: &description,
DisplayName: &displayName,
Tags: tags,
ComputeCollectionId: &collectionID,
SubClusterInfo: subClusterInfo,
}

if len(discoveredNodes) > 0 && !isDelete {
// NSX requires us to remove all nodes before deletion,
// This Patch call will remove all nodes during delete flow,
// hence the line below is skipped
obj.SubClusterInfo.DiscoveredNodeIds = discoveredNodes
}

if isUpdate {
obj.Revision = &revision
_, err := scClient.Update(siteID, epID, id, obj)
return err
}

_, err := scClient.Patch(siteID, epID, id, obj)
return err
}

func resourceNsxtPolicyComputeSubClusterCreate(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 := resourceNsxtPolicyComputeSubClusterExists(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 SubCluster with ID %s under site %s enforcement point %s", id, siteID, epID)
err = policyComputeSubClusterPatch(siteID, epID, id, d, m, false, false)
if err != nil {
return handleCreateError("SubCluster", id, err)
}

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

return resourceNsxtPolicyComputeSubClusterRead(d, m)
}

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

log.Printf("[INFO] Updating SubCluster with ID %s", id)
err = policyComputeSubClusterPatch(siteID, epID, id, d, m, true, false)
if err != nil {
return handleUpdateError("SubCluster", id, err)
}

return resourceNsxtPolicyComputeSubClusterRead(d, m)
}

func resourceNsxtPolicyComputeSubClusterDelete(d *schema.ResourceData, m interface{}) error {
connector := getPolicyConnector(m)
htnClient := enforcement_points.NewSubClustersClient(connector)

id, siteID, epID, err := policyIDSiteEPTuple(d, m)
if err != nil {
return err
}

// If nodes are present, NSX requires to delete them first
discoveredNodes := getStringListFromSchemaList(d, "discovered_node_ids")
if len(discoveredNodes) > 0 {
err = policyComputeSubClusterPatch(siteID, epID, id, d, m, true, true)
if err != nil {
return handleUpdateError("SubCluster", id, err)
}
}

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

return nil
}

func resourceNsxtPolicyComputeSubClusterImporter(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/", "/sub-clusters/", 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
}
52 changes: 52 additions & 0 deletions website/docs/r/policy_compute_sub_cluster.html.markdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
---
subcategory: "Beta"
layout: "nsxt"
page_title: "NSXT: nsxt_policy_compute_sub_cluster"
description: A resource to configure a Sub Cluster.
---

# nsxt_policy_compute_sub_cluster

This resource provides a method for the management of Compute Sub Cluster.
This resource is supported with NSX 3.2.2 onwards.

## Example Usage

```hcl
resource "nsxt_policy_compute_sub_cluster" "test" {
display_name = "subcluster1"
compute_collection_id = data.nsxt_compute_collection.cc1.id
discovered_node_ids = data.nsxt_discover_node.dn.id
}
```

## Argument Reference

The following arguments are supported:

* `display_name` - (Required) Display name of the resource.
* `description` - (Optional) Description of the resource.
* `tag` - (Optional) A list of scope + tag pairs to associate with this resource.
* `site_path` - (Optional) The path of the site which this Sub Cluster belongs to. `path` field of the existing `nsxt_policy_site` can be used here. Defaults to default site path.
* `enforcement_point` - (Optional) The ID of enforcement point under given `site_path` to manage the Host Transport Node. Defaults to default enforcement point.
* `compute_collection_id` - (Required) ID of compute collection under which sub-cluster is created
* `discovered_node_ids` - (Optional) Discovered node IDs under this subcluster

## 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.
* `discovered_node_ids` - (Optional) Discovered node IDs under this subcluster

## Importing

An existing Sub Cluster can be [imported][docs-import] into this resource, via the following command:

[docs-import]: https://www.terraform.io/cli/import

```
terraform import nsxt_policy_compute_sub_cluster.test POLICY_PATH
```
The above command imports Sub Cluster named `test` with the policy path `POLICY_PATH`.

0 comments on commit 7ef72f9

Please sign in to comment.