-
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.
Implement ODS runbook invocation resource
Signed-off-by: Kobi Samoray <[email protected]>
- Loading branch information
Showing
4 changed files
with
419 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,202 @@ | ||
/* Copyright © 2023 VMware, Inc. All Rights Reserved. | ||
SPDX-License-Identifier: MPL-2.0 */ | ||
|
||
package nsxt | ||
|
||
import ( | ||
"fmt" | ||
|
||
"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/sha" | ||
"github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" | ||
) | ||
|
||
func resourceNsxtPolicyODSRunbookInvocation() *schema.Resource { | ||
return &schema.Resource{ | ||
Create: resourceNsxtPolicyODSRunbookInvocationCreate, | ||
Read: resourceNsxtPolicyODSRunbookInvocationRead, | ||
Update: resourceNsxtPolicyODSRunbookInvocationUpdate, | ||
Delete: resourceNsxtPolicyODSRunbookInvocationDelete, | ||
Importer: &schema.ResourceImporter{ | ||
State: nsxtPolicyPathResourceImporter, | ||
}, | ||
|
||
Schema: map[string]*schema.Schema{ | ||
"nsx_id": getNsxIDSchema(), | ||
"path": getPathSchema(), | ||
// Due to a bug, invocations with a display_name specification fail, and when there's none set, NSX assigns | ||
// the id value to the display name attribute. This should work around that bug. | ||
"display_name": { | ||
Type: schema.TypeString, | ||
Description: "Display name for this resource", | ||
Optional: true, | ||
Computed: true, | ||
}, | ||
"description": getDescriptionSchema(), | ||
"revision": getRevisionSchema(), | ||
"tag": getTagsSchema(), | ||
"argument": { | ||
Type: schema.TypeSet, | ||
Optional: true, | ||
Description: "Arguments for runbook invocation", | ||
Elem: &schema.Resource{ | ||
Schema: map[string]*schema.Schema{ | ||
"key": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
Description: "Key", | ||
}, | ||
"value": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
Description: "Value", | ||
}, | ||
}, | ||
}, | ||
}, | ||
"runbook_path": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
Description: "Path of runbook object", | ||
}, | ||
"target_node": { | ||
Type: schema.TypeString, | ||
Optional: true, | ||
Description: "Identifier of an appliance node or transport node", | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
func getODSRunbookInvocationFromSchema(id string, d *schema.ResourceData) model.OdsRunbookInvocation { | ||
displayName := d.Get("display_name").(string) | ||
description := d.Get("description").(string) | ||
tags := getPolicyTagsFromSchema(d) | ||
runbookPath := d.Get("runbook_path").(string) | ||
targetNode := d.Get("target_node").(string) | ||
|
||
var arguments []model.UnboundedKeyValuePair | ||
for _, arg := range d.Get("argument").(*schema.Set).List() { | ||
argMap := arg.(map[string]interface{}) | ||
key := argMap["key"].(string) | ||
value := argMap["value"].(string) | ||
item := model.UnboundedKeyValuePair{ | ||
Key: &key, | ||
Value: &value, | ||
} | ||
arguments = append(arguments, item) | ||
} | ||
|
||
obj := model.OdsRunbookInvocation{ | ||
Id: &id, | ||
Description: &description, | ||
Tags: tags, | ||
RunbookPath: &runbookPath, | ||
Arguments: arguments, | ||
TargetNode: &targetNode, | ||
} | ||
if displayName != "" { | ||
obj.DisplayName = &displayName | ||
} | ||
|
||
return obj | ||
} | ||
|
||
func resourceNsxtPolicyODSRunbookInvocationCreate(d *schema.ResourceData, m interface{}) error { | ||
// Initialize resource Id and verify this ID is not yet used | ||
id, err := getOrGenerateID(d, m, resourceNsxtPolicyODSRunbookInvocationExists) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
connector := getPolicyConnector(m) | ||
client := sha.NewRunbookInvocationsClient(connector) | ||
|
||
obj := getODSRunbookInvocationFromSchema(id, d) | ||
err = client.Create(id, obj) | ||
if err != nil { | ||
return handleCreateError("OdsRunbookInvocation", id, err) | ||
} | ||
|
||
d.SetId(id) | ||
d.Set("nsx_id", id) | ||
return resourceNsxtPolicyODSRunbookInvocationRead(d, m) | ||
} | ||
|
||
func resourceNsxtPolicyODSRunbookInvocationExists(id string, connector client.Connector, isGlobalManager bool) (bool, error) { | ||
var err error | ||
client := sha.NewRunbookInvocationsClient(connector) | ||
_, err = client.Get(id) | ||
|
||
if err == nil { | ||
return true, nil | ||
} | ||
|
||
if isNotFoundError(err) { | ||
return false, nil | ||
} | ||
|
||
return false, logAPIError("Error retrieving resource", err) | ||
} | ||
|
||
func resourceNsxtPolicyODSRunbookInvocationRead(d *schema.ResourceData, m interface{}) error { | ||
connector := getPolicyConnector(m) | ||
|
||
id := d.Id() | ||
if id == "" { | ||
return fmt.Errorf("error obtaining OdsRunbookInvocation ID") | ||
} | ||
|
||
client := sha.NewRunbookInvocationsClient(connector) | ||
var err error | ||
obj, err := client.Get(id) | ||
if err != nil { | ||
return handleReadError(d, "OdsRunbookInvocation", id, err) | ||
} | ||
|
||
if obj.DisplayName != nil && *obj.DisplayName != "" { | ||
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("runbook_path", obj.RunbookPath) | ||
d.Set("target_node", obj.TargetNode) | ||
|
||
var argList []map[string]interface{} | ||
for _, arg := range obj.Arguments { | ||
argData := make(map[string]interface{}) | ||
argData["key"] = arg.Key | ||
argData["value"] = arg.Value | ||
argList = append(argList, argData) | ||
} | ||
d.Set("argument", argList) | ||
|
||
return nil | ||
} | ||
|
||
func resourceNsxtPolicyODSRunbookInvocationUpdate(d *schema.ResourceData, m interface{}) error { | ||
return resourceNsxtPolicyODSRunbookInvocationRead(d, m) | ||
} | ||
|
||
func resourceNsxtPolicyODSRunbookInvocationDelete(d *schema.ResourceData, m interface{}) error { | ||
id := d.Id() | ||
if id == "" { | ||
return fmt.Errorf("error obtaining OdsRunbookInvocation ID") | ||
} | ||
|
||
connector := getPolicyConnector(m) | ||
var err error | ||
client := sha.NewRunbookInvocationsClient(connector) | ||
err = client.Delete(id) | ||
|
||
if err != nil { | ||
return handleDeleteError("OdsRunbookInvocation", id, err) | ||
} | ||
|
||
return nil | ||
} |
148 changes: 148 additions & 0 deletions
148
nsxt/resource_nsxt_policy_ods_runbook_invocation_test.go
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,148 @@ | ||
/* 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" | ||
) | ||
|
||
func TestAccResourceNsxtPolicyODSRunbookInvocation_basic(t *testing.T) { | ||
name := getAccTestResourceName() | ||
testResourceName := "nsxt_policy_ods_runbook_invocation.test" | ||
resource.Test(t, resource.TestCase{ | ||
PreCheck: func() { | ||
testAccOnlyLocalManager(t) | ||
testAccPreCheck(t) | ||
testAccEnvDefined(t, "NSXT_TEST_HOST_TRANSPORT_NODE") | ||
}, | ||
Providers: testAccProviders, | ||
CheckDestroy: func(state *terraform.State) error { | ||
return testAccNsxtPolicyODSRunbookInvocationCheckDestroy(state, name) | ||
}, | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: testAccNsxtPolicyODSRunbookInvocationCreateTemplate(name, "OverlayTunnel", ` | ||
argument { | ||
key = "src" | ||
value = "192.168.0.11" | ||
} | ||
argument { | ||
key = "dst" | ||
value = "192.168.0.10" | ||
} | ||
`), | ||
Check: resource.ComposeTestCheckFunc( | ||
testAccNsxtPolicyODSRunbookInvocationExists(name, testResourceName), | ||
resource.TestCheckResourceAttrSet(testResourceName, "target_node"), | ||
resource.TestCheckResourceAttrSet(testResourceName, "runbook_path"), | ||
), | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
func TestAccResourceNsxtPolicyODSRunbookInvocation_import(t *testing.T) { | ||
|
||
name := getAccTestResourceName() | ||
testResourceName := "nsxt_policy_ods_runbook_invocation.test" | ||
resource.Test(t, resource.TestCase{ | ||
PreCheck: func() { | ||
testAccPreCheck(t) | ||
testAccOnlyLocalManager(t) | ||
}, | ||
Providers: testAccProviders, | ||
CheckDestroy: func(state *terraform.State) error { | ||
return testAccNsxtPolicyODSRunbookInvocationCheckDestroy(state, name) | ||
}, | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: testAccNsxtPolicyODSRunbookInvocationCreateTemplate(name, "OverlayTunnel", ` | ||
argument { | ||
key = "src" | ||
value = "192.168.0.11" | ||
} | ||
argument { | ||
key = "dst" | ||
value = "192.168.0.10" | ||
} | ||
`), | ||
}, | ||
{ | ||
ResourceName: testResourceName, | ||
ImportState: true, | ||
ImportStateVerify: true, | ||
ImportStateIdFunc: testAccResourceNsxtPolicyImportIDRetriever(testResourceName), | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
func testAccNsxtPolicyODSRunbookInvocationCheckDestroy(state *terraform.State, displayName string) error { | ||
connector := getPolicyConnector(testAccProvider.Meta().(nsxtClients)) | ||
for _, rs := range state.RootModule().Resources { | ||
|
||
if rs.Type != "nsxt_policy_ods_runbook_invocation" { | ||
continue | ||
} | ||
|
||
resourceID := rs.Primary.Attributes["id"] | ||
exists, err := resourceNsxtPolicyODSRunbookInvocationExists(resourceID, connector, testAccIsGlobalManager()) | ||
if err == nil { | ||
return err | ||
} | ||
|
||
if exists { | ||
return fmt.Errorf("policy ODSRunbookInvocation %s still exists", displayName) | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
func testAccNsxtPolicyODSRunbookInvocationExists(displayName string, resourceName string) resource.TestCheckFunc { | ||
return func(state *terraform.State) error { | ||
|
||
connector := getPolicyConnector(testAccProvider.Meta().(nsxtClients)) | ||
|
||
rs, ok := state.RootModule().Resources[resourceName] | ||
if !ok { | ||
return fmt.Errorf("policy ODSRunbookInvocation resource %s not found in resources", resourceName) | ||
} | ||
|
||
resourceID := rs.Primary.ID | ||
if resourceID == "" { | ||
return fmt.Errorf("policy ODSRunbookInvocation resource ID not set in resources") | ||
} | ||
|
||
exists, err := resourceNsxtPolicyODSRunbookInvocationExists(resourceID, connector, testAccIsGlobalManager()) | ||
if err != nil { | ||
return err | ||
} | ||
if !exists { | ||
return fmt.Errorf("policy ODSRunbookInvocation %s does not exist", resourceID) | ||
} | ||
|
||
return nil | ||
} | ||
} | ||
|
||
func testAccNsxtPolicyODSRunbookInvocationCreateTemplate(name, runbook, arguments string) string { | ||
htnName := getHostTransportNodeName() | ||
return testAccNsxtPolicyODSPredefinedRunbookReadTemplate(runbook) + fmt.Sprintf(` | ||
data "nsxt_policy_host_transport_node" "test" { | ||
display_name = "%s" | ||
} | ||
resource "nsxt_policy_ods_runbook_invocation" "test" { | ||
// Use nsx_id here to address a backend issue. | ||
nsx_id = "%s" | ||
runbook_path = data.nsxt_policy_ods_pre_defined_runbook.test.path | ||
%s | ||
target_node = data.nsxt_policy_host_transport_node.test.unique_id | ||
} | ||
`, htnName, name, arguments) | ||
} |
Oops, something went wrong.