-
Notifications
You must be signed in to change notification settings - Fork 85
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1172 from vmware/sub-cluster
Add policy sub cluster resource
- Loading branch information
Showing
3 changed files
with
309 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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`. |