Skip to content

Commit

Permalink
Resource to prepare for NSXT cluster upgrade
Browse files Browse the repository at this point in the history
Signed-off-by: Shizhao Liu <[email protected]>
  • Loading branch information
Shizhao Liu committed Jan 9, 2024
1 parent b8b33d1 commit 6b42c52
Show file tree
Hide file tree
Showing 5 changed files with 432 additions and 0 deletions.
2 changes: 2 additions & 0 deletions nsxt/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,8 @@ func Provider() *schema.Provider {
"nsxt_policy_lb_http_application_profile": resourceNsxtPolicyLBHttpApplicationProfile(),
"nsxt_policy_security_policy_rule": resourceNsxtPolicySecurityPolicyRule(),
"nsxt_policy_parent_security_policy": resourceNsxtPolicyParentSecurityPolicy(),
"nsxt_upgrade_prepare": resourceNsxtUpgradePrepare(),
"nsxt_upgrade_precheck_acknowledge": resourceNsxtUpgradePrecheckAcknowledge(),
},

ConfigureFunc: providerConfigure,
Expand Down
88 changes: 88 additions & 0 deletions nsxt/resource_nsxt_upgrade_precheck_acknowledge.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/* Copyright © 2023 VMware, Inc. All Rights Reserved.
SPDX-License-Identifier: MPL-2.0 */

package nsxt

import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
nsxModel "github.com/vmware/vsphere-automation-sdk-go/services/nsxt-mp/nsx/model"
"github.com/vmware/vsphere-automation-sdk-go/services/nsxt-mp/nsx/upgrade"
)

func resourceNsxtUpgradePrecheckAcknowledge() *schema.Resource {
return &schema.Resource{
Create: resourceNsxtUpgradePrecheckAcknowledgeCreate,
Read: resourceNsxtUpgradePrecheckAcknowledgeRead,
Update: resourceNsxtUpgradePrecheckAcknowledgeUpdate,
Delete: resourceNsxtUpgradePrecheckAcknowledgeDelete,

Schema: map[string]*schema.Schema{
"precheck_id": {
Type: schema.TypeList,
Description: "IDs of failed prechecks that user wants to acknowledge before upgrade",
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"id": {
Type: schema.TypeString,
Description: "ID of failed precheck to acknowledge",
Required: true,
},
},
},
Required: true,
},
},
}
}

func resourceNsxtUpgradePrecheckAcknowledgeCreate(d *schema.ResourceData, m interface{}) error {
id := d.Id()
if id == "" {
id = newUUID()
}
d.SetId(id)
precheckIDs := interface2StringList(d.Get("precheck_id").([]interface{}))
connector := getPolicyConnector(m)
client := upgrade.NewPreUpgradeChecksClient(connector)
for _, precheckID := range precheckIDs {
err := client.Acknowledge(precheckID)
if err != nil {
return handleCreateError("NsxtUpgradePrecheckAcknowledge", id, err)
}
}
return resourceNsxtUpgradePrecheckAcknowledgeRead(d, m)
}

func resourceNsxtUpgradePrecheckAcknowledgeRead(d *schema.ResourceData, m interface{}) error {
id := d.Id()
precheckWarnings, err := getPrecheckErrors(m, nsxModel.UpgradeCheckFailure_TYPE_WARNING)
if err != nil {
return handleReadError(d, "NsxtUpgradePrecheckAcknowledge", id, err)
}
err = setAcknowledgedPrecheckIDsInSchema(d, precheckWarnings)
if err != nil {
return handleReadError(d, "NsxtUpgradePrecheckAcknowledge", id, err)
}
return nil
}

func setAcknowledgedPrecheckIDsInSchema(d *schema.ResourceData, precheckWarnings []nsxModel.UpgradeCheckFailure) error {
var precheckWarningIDs []map[string]interface{}
for _, precheckWarning := range precheckWarnings {
elem := make(map[string]interface{})
if !(*precheckWarning.NeedsAck) {
id := *precheckWarning.Id
elem["id"] = id
precheckWarningIDs = append(precheckWarningIDs, elem)
}
}
return d.Set("precheck_id", precheckWarningIDs)
}

func resourceNsxtUpgradePrecheckAcknowledgeUpdate(d *schema.ResourceData, m interface{}) error {
return nil
}

func resourceNsxtUpgradePrecheckAcknowledgeDelete(d *schema.ResourceData, m interface{}) error {
return nil
}
263 changes: 263 additions & 0 deletions nsxt/resource_nsxt_upgrade_prepare.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,263 @@
/* Copyright © 2023 VMware, Inc. All Rights Reserved.
SPDX-License-Identifier: MPL-2.0 */

package nsxt

import (
"fmt"
"log"
"time"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/vmware/vsphere-automation-sdk-go/services/nsxt-mp/nsx"
nsxModel "github.com/vmware/vsphere-automation-sdk-go/services/nsxt-mp/nsx/model"
"github.com/vmware/vsphere-automation-sdk-go/services/nsxt-mp/nsx/upgrade"
"github.com/vmware/vsphere-automation-sdk-go/services/nsxt-mp/nsx/upgrade/bundles"
"github.com/vmware/vsphere-automation-sdk-go/services/nsxt-mp/nsx/upgrade/eula"
"github.com/vmware/vsphere-automation-sdk-go/services/nsxt-mp/nsx/upgrade/pre_upgrade_checks"
)

// URL to the upgrade bundle of an NSX build >= 4.1.1, will be used to upgrade UC if need to upload precheck bundle on NSX version < 4.1.1
const nsxt412UpgradeBundleURL string = "http://build-squid.eng.vmware.com/build/mts/release/bora-23074069/publish/upgrade/VMware-NSX-upgrade-bundle-4.1.2.2.0.23074069.mub"
const nsxt412Version string = "4.1.2"

func resourceNsxtUpgradePrepare() *schema.Resource {
return &schema.Resource{
Create: resourceNsxtUpgradePrepareCreate,
Read: resourceNsxtUpgradePrepareRead,
Update: resourceNsxtUpgradePrepareUpdate,
Delete: resourceNsxtUpgradePrepareDelete,

Schema: map[string]*schema.Schema{
"upgrade_bundle_url": {
Type: schema.TypeString,
Description: "URL of the NSXT Upgrade bundle",
Required: true,
},
"precheck_bundle_url": {
Type: schema.TypeString,
Description: "URL of the NSXT Upgrade precheck bundle",
Optional: true,
},
"version": {
Type: schema.TypeString,
Description: "Version for the upgrade",
Required: true,
},
"accept_user_agreement": {
Type: schema.TypeBool,
Description: "Whether to accept the user agreement",
Required: true,
},
"failed_prechecks": {
Type: schema.TypeList,
Description: "List of failed prechecks for the upgrade, only include warnings, if precheck failed with error then the resource creation will fail",
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"id": {
Type: schema.TypeString,
Description: "ID of failed precheck",
Computed: true,
},
"message": {
Type: schema.TypeString,
Description: "Message of the failed precheck",
Computed: true,
},
},
},
Computed: true,
},
},
}
}

func uploadPrecheckAndUpgradeBundle(d *schema.ResourceData, m interface{}) error {
upgradeBundleURL := d.Get("upgrade_bundle_url").(string)
precheckBundleURL := d.Get("precheck_bundle_url").(string)
upgradeBundleType := nsxModel.UpgradeBundleFetchRequest_BUNDLE_TYPE_UPGRADE
precheckBundleType := nsxModel.UpgradeBundleFetchRequest_BUNDLE_TYPE_PRE_UPGRADE
version := d.Get("version").(string)
installParam := false
c := m.(nsxtClients)
userName := c.NsxtClientConfig.UserName
password := c.NsxtClientConfig.Password
// Upgrade coordinator on NSX version lower than 4.1.1 does not support uploading precheck bundle,
// however this can be solved by upgrading the UC using a manager bundle from higher version.
// Therefore if current NSX version is lower than 4.1.1 and precheck bundle is specified,
// we first upload the Manager bundle from higher version (does not have to be upgrade target version)
// Then upgrade precheck bundles.
if nsxVersionLower("4.1.1") && len(precheckBundleURL) > 0 {
url := nsxt412UpgradeBundleURL
version := nsxt412Version
err := uploadUpgradeBundle(m, url, userName, password, upgradeBundleType, version, installParam)
if err != nil {
return err
}
}
if len(precheckBundleURL) > 0 {
err := uploadUpgradeBundle(m, precheckBundleURL, userName, password, precheckBundleType, version, installParam)
if err != nil {
return fmt.Errorf("Failed to upload precheck bundle: %s", err)
}
}
err := uploadUpgradeBundle(m, upgradeBundleURL, userName, password, upgradeBundleType, version, installParam)
if err != nil {
return fmt.Errorf("Failed to upload upgrade bundle: %s", err)
}
return nil
}

func uploadUpgradeBundle(m interface{}, url string, userName string, password string, bundleType string, version string, installParam bool) error {
connector := getPolicyConnector(m)
client := upgrade.NewBundlesClient(connector)
bundleFetchRequest := nsxModel.UpgradeBundleFetchRequest{
BundleType: &bundleType,
Password: &password,
Username: &userName,
Url: &url,
Version: &version,
}
bundleID, err := client.Create(bundleFetchRequest, &installParam)
if err != nil {
return fmt.Errorf("Failed to upload upgrade bundle with ID %s: %s", bundleID, err)
}
return waitForBundleUpload(m, *bundleID.BundleId)
}

func acceptUserAgreement(d *schema.ResourceData, m interface{}) error {
connector := getPolicyConnector(m)
acceptUserAgreement := d.Get("accept_user_agreement").(bool)
if !acceptUserAgreement {
return fmt.Errorf("To proceed with upgrade, you must accept user agreement")
}
client := eula.NewAcceptClient(connector)
err := client.Create()
if err != nil {
return handleCreateError("NsxtUpgradePrepare", "", err)
}
return nil
}

func executePreupgradeChecks(m interface{}) error {
connector := getPolicyConnector(m)
client := nsx.NewUpgradeClient(connector)
return client.Executepreupgradechecks(nil, nil, nil, nil, nil, nil)
}

func getPrecheckErrors(m interface{}, typeParam string) ([]nsxModel.UpgradeCheckFailure, error) {
connector := getPolicyConnector(m)
client := pre_upgrade_checks.NewFailuresClient(connector)
resultList, err := client.List(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, &typeParam, nil, nil)
if err != nil {
return nil, err
}
return resultList.Results, nil
}

func setFailedPrechecksInSchema(d *schema.ResourceData, precheckWarnings []nsxModel.UpgradeCheckFailure) error {
var failedPrechecksList []map[string]interface{}
for _, warning := range precheckWarnings {
id := *warning.Id
message := *(warning.Message.Message)
elem := make(map[string]interface{})
elem["id"] = id
elem["message"] = message
failedPrechecksList = append(failedPrechecksList, elem)
}
return d.Set("failed_prechecks", failedPrechecksList)
}

func resourceNsxtUpgradePrepareCreate(d *schema.ResourceData, m interface{}) error {
id := d.Id()
if id == "" {
id = newUUID()
}
d.SetId(id)
err := prepareForUpgrade(d, m)
if err != nil {
return handleCreateError("NsxtUpgradePrepare", id, err)
}
return resourceNsxtUpgradePrepareRead(d, m)
}

func prepareForUpgrade(d *schema.ResourceData, m interface{}) error {
// 1. Upload upgrade bundle and wait for upload to complete,
// UC will be automatically upgraded after this step
err := uploadPrecheckAndUpgradeBundle(d, m)
if err != nil {
return fmt.Errorf("Failed to upload upgrade bundle: %s", err)
}
// 2. Accept user agreement
err = acceptUserAgreement(d, m)
if err != nil {
return err
}
// 3. Execute pre-upgrade checks
err = executePreupgradeChecks(m)
if err != nil {
return fmt.Errorf("Failed to execute pre-upgrade checks: %s", err)
}
// 4. Check if there is error in prechecks
precheckFailures, err := getPrecheckErrors(m, nsxModel.UpgradeCheckFailure_TYPE_FAILURE)
if err != nil {
return fmt.Errorf("Failed to get precheck errors: %s", err)
}
if len(precheckFailures) > 0 {
return fmt.Errorf("Encounter errors in precheck %s", *(precheckFailures[0].Message.Message))
}
return nil
}

func resourceNsxtUpgradePrepareRead(d *schema.ResourceData, m interface{}) error {
id := d.Id()
precheckWarnings, err := getPrecheckErrors(m, nsxModel.UpgradeCheckFailure_TYPE_WARNING)
if err != nil {
return handleReadError(d, "NsxtUpgradePrepare", id, err)
}
err = setFailedPrechecksInSchema(d, precheckWarnings)
if err != nil {
return handleReadError(d, "NsxtUpgradePrepare", id, err)
}
return nil
}

func resourceNsxtUpgradePrepareUpdate(d *schema.ResourceData, m interface{}) error {
id := d.Id()
err := prepareForUpgrade(d, m)
if err != nil {
return handleUpdateError("NsxtUpgradePrepare", id, err)
}
return resourceNsxtUpgradePrepareRead(d, m)
}

func resourceNsxtUpgradePrepareDelete(d *schema.ResourceData, m interface{}) error {
return nil
}

func waitForBundleUpload(m interface{}, bundleID string) error {
connector := getPolicyConnector(m)
client := bundles.NewUploadStatusClient(connector)
// c := m.(nsxtClients)
// Todo:
// 1. utilize Min/Max RetryInterval in provider config
interval := 20000
maxRetry := 50
for i := 0; i < 50; i++ {
uploadStatus, err := client.Get(bundleID)
if err != nil {
return err
}
if *uploadStatus.Status == nsxModel.UpgradeBundleUploadStatus_STATUS_FAILED {
return fmt.Errorf("Failed to upload upgrade bundle with id %s", bundleID)
}
if *uploadStatus.Status == nsxModel.UpgradeBundleUploadStatus_STATUS_SUCCESS {
log.Printf("[DEBUG]: successfully uploaded upgrade bundle %s", bundleID)
return nil
}
// interval := (rand.Intn(max-min) + min)
time.Sleep(time.Duration(interval) * time.Millisecond)
log.Printf("[DEBUG]: Waited %d ms before retrying getting upgrade bundle upload status", interval)
}
return fmt.Errorf("Upload bundle %s exceed timeout %v seconds", bundleID, (interval*maxRetry)/1000)
}
32 changes: 32 additions & 0 deletions website/docs/r/upgrade_precheck_acknowledge.html.markdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
---
subcategory: "Beta"
layout: "nsxt"
page_title: "NSXT: nsxt_upgrade_precheck_acknowledge"
description: A resource to acknowledge failed NSXT upgrade prechecks.
---

# nsxt_upgrade_precheck_acknowledge

This resource provides a method for acknowledging the failed prechecks
for NSXT upgrade.

## Example Usage

```hcl
resource "nsxt_upgrade_precheck_acknowledge" "test" {
precheck_id {
id = "backupOperationCheck"
}
}
```

## Argument Reference

The following arguments are supported:

* `precheck_id` - (Required) List of ids of failed prechecks user want to acknowledge.
* `id` - (Required) Id of failed prechecks.

## Importing

Importing is not supported for this resource.
Loading

0 comments on commit 6b42c52

Please sign in to comment.