diff --git a/nsxt/provider.go b/nsxt/provider.go index 7e531921b..a005c6b9b 100644 --- a/nsxt/provider.go +++ b/nsxt/provider.go @@ -396,6 +396,7 @@ func Provider() *schema.Provider { "nsxt_policy_project": resourceNsxtPolicyProject(), "nsxt_edge_cluster": resourceNsxtEdgeCluster(), "nsxt_compute_manager": resourceNsxtComputeManager(), + "nsxt_license": resourceNsxtLicense(), }, ConfigureFunc: providerConfigure, diff --git a/nsxt/resource_nsxt_license.go b/nsxt/resource_nsxt_license.go new file mode 100644 index 000000000..4387d5377 --- /dev/null +++ b/nsxt/resource_nsxt_license.go @@ -0,0 +1,103 @@ +/* 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-mp/nsx" + "github.com/vmware/vsphere-automation-sdk-go/services/nsxt-mp/nsx/model" +) + +func resourceNsxtLicense() *schema.Resource { + return &schema.Resource{ + Create: resourceNsxtLicenseCreate, + Read: resourceNsxtLicenseRead, + Delete: resourceNsxtLicenseDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + Schema: map[string]*schema.Schema{ + "license_key": { + Type: schema.TypeString, + Description: "license key", + Required: true, + ForceNew: true, + }, + }, + } +} + +func resourceNsxtLicenseExists(licenseKey string, connector client.Connector) (bool, error) { + client := nsx.NewLicensesClient(connector) + + objList, err := client.List() + + if err != nil { + return false, fmt.Errorf("error during License read: %v", err) + } + + for _, obj := range objList.Results { + if *obj.LicenseKey == licenseKey { + return true, nil + } + } + return false, nil +} + +func resourceNsxtLicenseCreate(d *schema.ResourceData, m interface{}) error { + connector := getPolicyConnector(m) + client := nsx.NewLicensesClient(connector) + + licenseKey := d.Get("license_key").(string) + + obj := model.License{ + LicenseKey: &licenseKey, + } + + obj, err := client.Create(obj) + if err != nil { + return handleCreateError("License", licenseKey, err) + } + + log.Printf("[INFO] Creating License with ID %s", *obj.LicenseKey) + + d.SetId(licenseKey) + return resourceNsxtLicenseRead(d, m) +} + +func resourceNsxtLicenseRead(d *schema.ResourceData, m interface{}) error { + connector := getPolicyConnector(m) + id := d.Id() + if id == "" { + return fmt.Errorf("error obtaining logical object id") + } + + _, err := resourceNsxtLicenseExists(id, connector) + if err != nil { + return err + } + d.Set("license_key", id) + return nil +} + +func resourceNsxtLicenseDelete(d *schema.ResourceData, m interface{}) error { + connector := getPolicyConnector(m) + + id := d.Id() + if id == "" { + return fmt.Errorf("error obtaining logical object id") + } + + client := nsx.NewLicensesClient(connector) + + err := client.Delete(id) + if err != nil { + return fmt.Errorf("error during License delete: %v", err) + } + return nil +} diff --git a/nsxt/resource_nsxt_license_test.go b/nsxt/resource_nsxt_license_test.go new file mode 100644 index 000000000..c52e06365 --- /dev/null +++ b/nsxt/resource_nsxt_license_test.go @@ -0,0 +1,124 @@ +/* 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 TestAccResourceNsxtLicense_basic(t *testing.T) { + licenseKey := getTestNSXLicense() + testResourceName := "nsxt_license.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAccOnlyLocalManager(t) + testAccTestFabric(t) + testAccTestLicense(t) + testAccPreCheck(t) + }, + Providers: testAccProviders, + CheckDestroy: func(state *terraform.State) error { + return testAccNSXLicenseCheckDestroy(state, licenseKey) + }, + Steps: []resource.TestStep{ + { + Config: testAccNSXLicenseCreateTemplate(licenseKey), + Check: resource.ComposeTestCheckFunc( + testAccNSXLicenseExists(testResourceName, licenseKey), + resource.TestCheckResourceAttr(testResourceName, "license_key", licenseKey), + ), + }, + }, + }) +} + +func TestAccResourceNsxtLicense_importBasic(t *testing.T) { + licenseKey := getTestNSXLicense() + testResourceName := "nsxt_license.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccOnlyLocalManager(t); testAccTestFabric(t); testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: func(state *terraform.State) error { + return testAccNSXLicenseCheckDestroy(state, licenseKey) + }, + Steps: []resource.TestStep{ + { + Config: testAccNSXLicenseCreateTemplate(licenseKey), + }, + { + ResourceName: testResourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccNSXLicenseExists(resourceName, licenseKey string) resource.TestCheckFunc { + return func(state *terraform.State) error { + + connector := getPolicyConnector(testAccProvider.Meta().(nsxtClients)) + + mymap := state.RootModule().Resources + keys := make([]string, 0, len(mymap)) + for k := range mymap { + keys = append(keys, k) + } + rs, ok := state.RootModule().Resources[resourceName] + if !ok { + return fmt.Errorf("NSX License resource %s not found in resources", licenseKey) + } + + resourceID := rs.Primary.ID + if resourceID == "" { + return fmt.Errorf("NSX License resource ID not set in resources ") + } + + exists, err := resourceNsxtLicenseExists(resourceID, connector) + if err != nil { + return fmt.Errorf("error while retrieving License ID %s. Error: %v", resourceID, err) + } else if exists { + return nil + } + + return fmt.Errorf("NSX License %s wasn't found", licenseKey) + } +} + +func testAccNSXLicenseCheckDestroy(state *terraform.State, licenseKey string) error { + connector := getPolicyConnector(testAccProvider.Meta().(nsxtClients)) + + for _, rs := range state.RootModule().Resources { + if rs.Type != "nsxt_license" { + continue + } + + resourceID := rs.Primary.Attributes["license_key"] + exists, err := resourceNsxtLicenseExists(resourceID, connector) + + if err != nil { + return fmt.Errorf("error while retrieving License ID %s. Error: %v", resourceID, err) + } + + if exists { + return fmt.Errorf("NSX License %s still exists", licenseKey) + } + } + + return nil +} + +func testAccNSXLicenseCreateTemplate(licenseKey string) string { + return fmt.Sprintf(` +resource "nsxt_license" "test" { + license_key = "%s" +} +`, licenseKey) +} diff --git a/nsxt/utils_test.go b/nsxt/utils_test.go index 4bd30ac23..91fa12ba8 100644 --- a/nsxt/utils_test.go +++ b/nsxt/utils_test.go @@ -241,6 +241,16 @@ func testAccTestVCCredentials(t *testing.T) { } } +func getTestNSXLicense() string { + return os.Getenv("NSXT_TEST_LICENSE") +} + +func testAccTestLicense(t *testing.T) { + if getTestNSXLicense() == "" { + t.Skipf("This test requires a NSX license") + } +} + func testAccOnlyMultitenancy(t *testing.T) { testAccNSXVersion(t, "4.1.0") if !testAccIsMultitenancy() { diff --git a/website/docs/r/license.html.markdown b/website/docs/r/license.html.markdown new file mode 100644 index 000000000..38d58c949 --- /dev/null +++ b/website/docs/r/license.html.markdown @@ -0,0 +1,36 @@ +--- +subcategory: "Fabric" +layout: "nsxt" +page_title: "NSXT: nsxt_license" +description: A resource to configure a License. +--- + +# nsxt_license + +This resource provides a method for the management of a License. +This resource is supported with NSX 4.1.0 onwards. + +## Example Usage + +```hcl +resource "nsxt_license" "test" { + license_key = "11011-12121-12345-00000-11111" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `license_key` - (Required) license key. + +## Importing + +An existing License can be [imported][docs-import] into this resource, via the following command: + +[docs-import]: https://www.terraform.io/cli/import + +``` +terraform import nsxt_license.test LICENSE_KEY +``` +The above command imports License named `test` with the key `LICENSE_KEY`.