From bb50a2c21fece83865978f68749fe7e276c6f975 Mon Sep 17 00:00:00 2001 From: Anna Khmelnitsky Date: Fri, 6 Oct 2023 01:51:09 +0000 Subject: [PATCH] Avoid applying lisence on every init Previous code assumed GetChange SDK routine works for provider attributes, which it doesn't (provider attributes are not stored in state). In order to avoid reapplying licenses on every init, this change pulls license keys from backend and only applies the diff. The provider will never remove licenses, this is to avoid scenario when provider removes license that was manually applied on NSX. Signed-off-by: Anna Khmelnitsky --- nsxt/provider.go | 79 +++++++++++++++----------------- website/docs/index.html.markdown | 19 ++++---- 2 files changed, 46 insertions(+), 52 deletions(-) diff --git a/nsxt/provider.go b/nsxt/provider.go index c5fccf275..b4c95b827 100644 --- a/nsxt/provider.go +++ b/nsxt/provider.go @@ -34,12 +34,6 @@ import ( var defaultRetryOnStatusCodes = []int{400, 409, 429, 500, 503, 504} -// Struct to keep track of changes in schema List -type listDiff struct { - added []interface{} - removed []interface{} -} - // Provider configuration that is shared for policy and MP type commonProviderConfig struct { RemoteAuth bool @@ -51,7 +45,7 @@ type commonProviderConfig struct { RetryStatusCodes []int Username string Password string - LicenseDiff listDiff + LicenseKeys []string } type nsxtClients struct { @@ -707,7 +701,7 @@ func configurePolicyConnectorData(d *schema.ResourceData, clients *nsxtClients) } if !isVMC { - err = configureLicenses(getPolicyConnectorForInit(*clients), clients.CommonConfig.LicenseDiff) + err = configureLicenses(getPolicyConnectorForInit(*clients), clients.CommonConfig.LicenseKeys) if err != nil { return err } @@ -857,6 +851,26 @@ func (processor sessionHeaderProcessor) Process(req *http.Request) error { return nil } +func getLicenses(connector client.Connector) ([]string, error) { + var licenseList []string + client := nsx.NewLicensesClient(connector) + list, err := client.List() + if err != nil { + return licenseList, fmt.Errorf("Error during license create: %v", err) + } + + defaultLicenseMarkers := []string{"NSX for vShield Endpoint"} + for _, item := range list.Results { + // Ignore default licenses + if item.Description != nil && slices.Contains(defaultLicenseMarkers, *item.Description) { + continue + } + licenseList = append(licenseList, *item.LicenseKey) + } + + return licenseList, nil +} + func applyLicense(connector client.Connector, licenseKey string) error { client := nsx.NewLicensesClient(connector) license := model.License{LicenseKey: &licenseKey} @@ -878,44 +892,27 @@ func removeLicense(connector client.Connector, licenseKey string) error { return nil } -func getListDiffFromSchema(d *schema.ResourceData, attribute string) listDiff { - var diff listDiff - o, n := d.GetChange(attribute) - oldValues := interfaceListToStringList(o.([]interface{})) - newValues := interfaceListToStringList(n.([]interface{})) - // Check for new - for _, value := range newValues { - if !slices.Contains(oldValues, value) { - diff.added = append(diff.added, value) - } +// license keys are applied on terraform plan and are not removed +func configureLicenses(connector client.Connector, intentLicenses []string) error { + if len(intentLicenses) == 0 { + // Since we never remove licenses, nothing to do here + return nil } - - // Remove old licenses - for _, value := range oldValues { - if !slices.Contains(newValues, value) { - diff.removed = append(diff.removed, value) - } + existingLicenses, err := getLicenses(connector) + if err != nil { + return err } - return diff -} - -// license keys are applied on terraform plan and are not removed -func configureLicenses(connector client.Connector, diff listDiff) error { // Apply new licenses - for _, license := range diff.added { - err := applyLicense(connector, license.(string)) + for _, license := range intentLicenses { + if slices.Contains(existingLicenses, license) { + continue + } + err := applyLicense(connector, license) if err != nil { return fmt.Errorf("error applying license key: %s. %s", license, err.Error()) } } - // Remove old licenses - for _, license := range diff.removed { - err := removeLicense(connector, license.(string)) - if err != nil { - return fmt.Errorf("error deleting license key: %s. %s", license, err.Error()) - } - } return nil } @@ -939,7 +936,7 @@ func initCommonConfig(d *schema.ResourceData) commonProviderConfig { retryStatuses = append(retryStatuses, defaultRetryOnStatusCodes...) } - licDiff := getListDiffFromSchema(d, "license_keys") + licenses := interfaceListToStringList(d.Get("license_keys").([]interface{})) return commonProviderConfig{ RemoteAuth: remoteAuth, ToleratePartialSuccess: toleratePartialSuccess, @@ -949,7 +946,7 @@ func initCommonConfig(d *schema.ResourceData) commonProviderConfig { RetryStatusCodes: retryStatuses, Username: username, Password: password, - LicenseDiff: licDiff, + LicenseKeys: licenses, } } @@ -1060,7 +1057,7 @@ func getPolicyConnectorWithHeaders(clients interface{}, customHeaders *map[strin // This is also our indication to apply licenses, in case of delayed connection if nsxVersion == "" && !initFlow { initNSXVersion(connector) - err := configureLicenses(connector, c.CommonConfig.LicenseDiff) + err := configureLicenses(connector, c.CommonConfig.LicenseKeys) if err != nil { log.Printf("[ERROR]: Failed to apply NSX licenses") } diff --git a/website/docs/index.html.markdown b/website/docs/index.html.markdown index 10dcbbd75..efea6c71d 100644 --- a/website/docs/index.html.markdown +++ b/website/docs/index.html.markdown @@ -236,7 +236,8 @@ The following arguments are used to configure the VMware NSX-T Provider: * `global_manager` - (Optional) True if this is a global manager endpoint. False by default. * `license_keys` - (Optional) List of NSX-T license keys. License keys are applied - during plan or apply commands. + during plan or apply commands. Note that the provider will not remove license keys if + those are removed from provider config - please clean up licenses manually. * `on_demand_connection` - (Optional) Avoid verification on NSX connectivity on provider startup. Instead, initialize the connection on demand. This setting can not be turned on for VMC environments, and is not supported with deprecated NSX manager resources and @@ -247,17 +248,13 @@ The following arguments are used to configure the VMware NSX-T Provider: This release of the NSX-T Terraform Provider extends to cover NSX-T declarative API called Policy. This API aims to simplify the consumption of logical objects -and offer additional capabilities.The NSX-T Terraform Providerextends withadditional -resources and data sources covering layer 2, layer 3, firewall (distributed and -centralized), tags, load balancerand IP allocation (DHCP, IP pools, IP blocks etc...). -This typically allowsto expose new capabilities such as vRFlite on the Tier-0 which -are only made available from the Policy API. While you can still build topologies from -the imperative API and existing config files will continue to work, the recommendation +and offer additional capabilities.The NSX-T Terraform Provider covers most of NSX +functionality. +While you can still build topologies from the imperative API and existing config files +will continue to work, the recommendation is to build logical topologies from the declarative API(Policy Objects).The resources -and data sources using the policy API have _policy_ in their name. All these resources -and data sources are fully documented on the NSX-T Terraform Provider -page:•https://www.terraform.io/docs/providers/nsxt/index.html For more details on the -NSX-T Policy API usage, please look at NSX-T documentation. +and data sources using the policy API have _policy_ in their name. +For more details on the NSX-T Policy API usage, please refer to NSX-T documentation. The existing data sources and resources are still available to consume but using the new Policy based data sources and resources are recommended.