Skip to content

Commit

Permalink
Avoid applying lisence on every init
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
annakhm committed Oct 18, 2023
1 parent d341d2e commit bb50a2c
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 52 deletions.
79 changes: 38 additions & 41 deletions nsxt/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -51,7 +45,7 @@ type commonProviderConfig struct {
RetryStatusCodes []int
Username string
Password string
LicenseDiff listDiff
LicenseKeys []string
}

type nsxtClients struct {
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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}
Expand All @@ -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
}

Expand All @@ -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,
Expand All @@ -949,7 +946,7 @@ func initCommonConfig(d *schema.ResourceData) commonProviderConfig {
RetryStatusCodes: retryStatuses,
Username: username,
Password: password,
LicenseDiff: licDiff,
LicenseKeys: licenses,
}
}

Expand Down Expand Up @@ -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")
}
Expand Down
19 changes: 8 additions & 11 deletions website/docs/index.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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.
Expand Down

0 comments on commit bb50a2c

Please sign in to comment.