Skip to content

Commit

Permalink
Extend how to upgrade RabbitMQ version (#295)
Browse files Browse the repository at this point in the history
### WHY are these changes introduced?

Missing the ability to specify the version to upgrade to, when using the `cloudamqp_upgrade_rabbitmq` resource.

Reference: #293.
 
### WHAT is this pull request doing?

Extend the `cloudamqp_upgrade_rabbitmq` resource to use multiple ways to invoke the upgrade.
- Specify an available version
- Bring to latest possible version with help of `cloudamqp_upgradable_versions`
- Support previous behaviour

### HOW can this pull request be tested?

Added new tests with fixtures
  • Loading branch information
tbroden84 authored Aug 19, 2024
1 parent 05841da commit 296ed96
Show file tree
Hide file tree
Showing 10 changed files with 6,298 additions and 22 deletions.
53 changes: 43 additions & 10 deletions api/upgrade_rabbitmq.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,23 +29,59 @@ func (api *API) ReadVersions(instanceID int) (map[string]any, error) {
}
}

// UpgradeRabbitMQ - Upgrade to latest possible versions for both RabbitMQ and Erlang.
func (api *API) UpgradeRabbitMQ(instanceID int) (string, error) {
// UpgradeRabbitMQ - Upgrade to latest possible version or a specific available version
func (api *API) UpgradeRabbitMQ(instanceID int, current_version, new_version string) (string, error) {
log.Printf("[DEBUG] api::upgrade_rabbitmq#upgrade_rabbitmq instanceID: %d, current_version: %s"+
", new_version: %s", instanceID, current_version, new_version)

// Keep old behaviour
if current_version == "" && new_version == "" {
return api.UpgradeToLatestVersion(instanceID)
} else if current_version != "" {
return api.UpgradeToLatestVersion(instanceID)
} else {
return api.UpgradeToSpecificVersion(instanceID, new_version)
}
}

func (api *API) UpgradeToSpecificVersion(instanceID int, version string) (string, error) {
var (
data map[string]any
failed map[string]any
path = fmt.Sprintf("api/instances/%d/actions/upgrade-rabbitmq", instanceID)
params = make(map[string]any)
)

params["version"] = version
log.Printf("[DEBUG] api::upgrade_rabbitmq#upgrade_to_specific_version path: %s, params: %v",
path, params)
response, err := api.sling.New().Post(path).BodyJSON(params).Receive(&data, &failed)
if err != nil {
return "", err
}

switch response.StatusCode {
case 200:
return api.waitUntilUpgraded(instanceID)
default:
return "", fmt.Errorf("upgrade RabbitMQ failed, status: %d, message: %s",
response.StatusCode, failed)
}
}

func (api *API) UpgradeToLatestVersion(instanceID int) (string, error) {
var (
data map[string]any
failed map[string]any
path = fmt.Sprintf("api/instances/%d/actions/upgrade-rabbitmq-erlang", instanceID)
)

log.Printf("[DEBUG] api::upgrade_rabbitmq#upgrade_rabbitmq path: %s", path)
log.Printf("[DEBUG] api::upgrade_rabbitmq#upgrade_to_latest_version path: %s", path)
response, err := api.sling.New().Post(path).Receive(&data, &failed)
if err != nil {
return "", err
}

log.Printf("[DEBUG] api::upgrade_rabbitmq::upgrade_rabbitmq_mq data: %v, status code: %d",
data, response.StatusCode)

switch response.StatusCode {
case 200:
return "Already at highest possible version", nil
Expand All @@ -69,15 +105,12 @@ func (api *API) waitUntilUpgraded(instanceID int) (string, error) {
if err != nil {
return "", err
}
log.Printf("[DEBUG] api::upgrade_rabbitmq#waitUntilUpgraded numberOfNodes: %d", len(data))

log.Printf("[DEBUG] api::upgrade_rabbitmq#waitUntilUpgraded data: %v", data)
ready := true
for _, node := range data {
log.Printf("[DEBUG] api::upgrade_rabbitmq#waitUntilUpgraded ready: %v, configured: %v",
ready, node["configured"])
ready = ready && node["configured"].(bool)
}
log.Printf("[DEBUG] api::upgrade_rabbitmq#waitUntilUpgraded ready: %v", ready)
if ready {
return "", nil
}
Expand Down
32 changes: 27 additions & 5 deletions cloudamqp/resource_cloudamqp_upgrade_rabbitmq.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,26 +12,44 @@ func resourceUpgradeRabbitMQ() *schema.Resource {
return &schema.Resource{
Create: resourceUpgradeRabbitMQInvoke,
Read: resourceUpgradeRabbitMQRead,
Update: resourceUpgradeRabbitMQUpdate,
Delete: resourceUpgradeRabbitMQRemove,
Schema: map[string]*schema.Schema{
"instance_id": {
Type: schema.TypeInt,
ForceNew: true,
Required: true,
Description: "The CloudAMQP instance identifier",
},
"current_version": {
Type: schema.TypeString,
Optional: true,
Description: "Helper argument to change upgrade behaviour to latest possible version",
},
"new_version": {
Type: schema.TypeString,
ForceNew: true,
Optional: true,
Description: "The new version to upgrade to",
},
},
}
}

func resourceUpgradeRabbitMQInvoke(d *schema.ResourceData, meta interface{}) error {
api := meta.(*api.API)
response, err := api.UpgradeRabbitMQ(d.Get("instance_id").(int))
var (
api = meta.(*api.API)
instanceID = d.Get("instance_id").(int)
current_version = d.Get("current_version").(string)
new_version = d.Get("new_version").(string)
)

log.Printf("[DEBUG] - Upgrading RabbitMQ instance %d to version %s", instanceID, new_version)
response, err := api.UpgradeRabbitMQ(instanceID, current_version, new_version)
if err != nil {
return err
}
id := strconv.Itoa(d.Get("instance_id").(int))
d.SetId(id)

d.SetId(strconv.Itoa(instanceID))

if len(response) > 0 {
log.Printf("[INFO] - " + response)
Expand All @@ -44,6 +62,10 @@ func resourceUpgradeRabbitMQRead(d *schema.ResourceData, meta interface{}) error
return nil
}

func resourceUpgradeRabbitMQUpdate(d *schema.ResourceData, meta interface{}) error {
return nil
}

func resourceUpgradeRabbitMQRemove(d *schema.ResourceData, meta interface{}) error {
return nil
}
193 changes: 193 additions & 0 deletions cloudamqp/resource_cloudamqp_upgrade_rabbitmq_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
package cloudamqp

import (
"fmt"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"

"github.com/cloudamqp/terraform-provider-cloudamqp/cloudamqp/vcr-testing/configuration"
"github.com/cloudamqp/terraform-provider-cloudamqp/cloudamqp/vcr-testing/converter"
)

// TestAccUpgradeRabbitMQ_Latest: Upgrade RabbitMQ to latest possible version, from 3.12.2 -> 3.13.2
// Extra checks are needed when comparing versions, because next step is executed before backend
// have been updated. Same reason unable to use cloudamqp_upgradable_versions data source correctly.
func TestAccUpgradeRabbitMQ_Latest(t *testing.T) {
var (
fileNames = []string{"instance_with_version", "data_source/nodes"}
instanceResourceName = "cloudamqp_instance.instance"
dataSourceNodesName = "data.cloudamqp_nodes.nodes"

params = map[string]string{
"InstanceName": "TestAccUpgradeRabbitMQ_Latest",
"InstanceTags": converter.CommaStringArray([]string{"terraform"}),
"InstanceID": fmt.Sprintf("%s.id", instanceResourceName),
"InstanceRmqVersion": "3.12.2",
}

fileNamesUpgrade = []string{"instance", "data_source/nodes", "upgrade_rabbitmq_latest"}

paramsUpgrade01 = map[string]string{
"InstanceName": "TestAccUpgradeRabbitMQ_Latest",
"InstanceTags": converter.CommaStringArray([]string{"terraform"}),
"InstanceID": fmt.Sprintf("%s.id", instanceResourceName),
"UpgradeRabbitMQCurrentVersion": "3.12.2",
"UpgradeRabbitMQNewVersion": "3.12.13",
}

paramsUpgrade02 = map[string]string{
"InstanceName": "TestAccUpgradeRabbitMQ_Latest",
"InstanceTags": converter.CommaStringArray([]string{"terraform"}),
"InstanceID": fmt.Sprintf("%s.id", instanceResourceName),
"UpgradeRabbitMQCurrentVersion": "3.12.13",
"UpgradeRabbitMQNewVersion": "3.13.2",
}

fileNamesCheckUpgrade = []string{"instance", "data_source/nodes"}
paramsCheck = map[string]string{
"InstanceName": "TestAccUpgradeRabbitMQ_Latest",
"InstanceTags": converter.CommaStringArray([]string{"terraform"}),
"InstanceID": fmt.Sprintf("%s.id", instanceResourceName),
}
)

cloudamqpResourceTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ProviderFactories: testAccProviderFactory,
Steps: []resource.TestStep{
{
Config: configuration.GetTemplatedConfig(t, fileNames, params),
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr(instanceResourceName, "name", params["InstanceName"]),
resource.TestCheckResourceAttr(instanceResourceName, "plan", "bunny-1"),
resource.TestCheckResourceAttr(instanceResourceName, "region", "amazon-web-services::us-east-1"),
resource.TestCheckResourceAttr(instanceResourceName, "rmq_version", params["InstanceRmqVersion"]),
resource.TestCheckResourceAttr(instanceResourceName, "tags.#", "1"),
resource.TestCheckResourceAttr(instanceResourceName, "tags.0", "terraform"),
resource.TestCheckResourceAttr(instanceResourceName, "nodes", "1"),
resource.TestCheckResourceAttr(dataSourceNodesName, "nodes.#", "1"),
resource.TestCheckResourceAttr(dataSourceNodesName, "nodes.0.rabbitmq_version", params["InstanceRmqVersion"]),
),
},
{
Config: configuration.GetTemplatedConfig(t, fileNamesUpgrade, paramsUpgrade01),
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr(dataSourceNodesName, "nodes.#", "1"),
resource.TestCheckResourceAttr(dataSourceNodesName, "nodes.0.rabbitmq_version", "3.12.2"),
),
},
{
Config: configuration.GetTemplatedConfig(t, fileNamesCheckUpgrade, paramsCheck),
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr(dataSourceNodesName, "nodes.#", "1"),
resource.TestCheckResourceAttr(dataSourceNodesName, "nodes.0.rabbitmq_version", "3.12.13"),
),
},
{
Config: configuration.GetTemplatedConfig(t, fileNamesUpgrade, paramsUpgrade02),
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr(dataSourceNodesName, "nodes.#", "1"),
resource.TestCheckResourceAttr(dataSourceNodesName, "nodes.0.rabbitmq_version", "3.12.13"),
),
},
{
Config: configuration.GetTemplatedConfig(t, fileNamesCheckUpgrade, paramsCheck),
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr(dataSourceNodesName, "nodes.#", "1"),
resource.TestCheckResourceAttr(dataSourceNodesName, "nodes.0.rabbitmq_version", "3.13.2"),
),
},
},
})
}

// TestAccUpgradeRabbitMQ_Specific: Upgrade RabbitMQ to a specific version, from 3.12.2 -> 3.13.2
// Extra checks are needed when comparing versions, because next step is executed before backend
// have been updated.
func TestAccUpgradeRabbitMQ_Specific(t *testing.T) {
var (
fileNames = []string{"instance_with_version", "data_source/nodes"}
instanceResourceName = "cloudamqp_instance.instance"
dataSourceNodesName = "data.cloudamqp_nodes.nodes"

params = map[string]string{
"InstanceName": "TestAccUpgradeRabbitMQ_Latest",
"InstanceTags": converter.CommaStringArray([]string{"terraform"}),
"InstanceID": fmt.Sprintf("%s.id", instanceResourceName),
"InstanceRmqVersion": "3.12.2",
}

fileNamesUpgrade = []string{"instance", "data_source/nodes", "upgrade_rabbitmq_latest"}

paramsUpgrade01 = map[string]string{
"InstanceName": "TestAccUpgradeRabbitMQ_Latest",
"InstanceTags": converter.CommaStringArray([]string{"terraform"}),
"InstanceID": fmt.Sprintf("%s.id", instanceResourceName),
"UpgradeRabbitMQNewVersion": "3.12.13",
}

paramsUpgrade02 = map[string]string{
"InstanceName": "TestAccUpgradeRabbitMQ_Latest",
"InstanceTags": converter.CommaStringArray([]string{"terraform"}),
"InstanceID": fmt.Sprintf("%s.id", instanceResourceName),
"UpgradeRabbitMQNewVersion": "3.13.2",
}

fileNamesCheckUpgrade = []string{"instance", "data_source/nodes"}
paramsCheck = map[string]string{
"InstanceName": "TestAccUpgradeRabbitMQ_Latest",
"InstanceTags": converter.CommaStringArray([]string{"terraform"}),
"InstanceID": fmt.Sprintf("%s.id", instanceResourceName),
}
)

cloudamqpResourceTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ProviderFactories: testAccProviderFactory,
Steps: []resource.TestStep{
{
Config: configuration.GetTemplatedConfig(t, fileNames, params),
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr(instanceResourceName, "name", params["InstanceName"]),
resource.TestCheckResourceAttr(instanceResourceName, "plan", "bunny-1"),
resource.TestCheckResourceAttr(instanceResourceName, "region", "amazon-web-services::us-east-1"),
resource.TestCheckResourceAttr(instanceResourceName, "rmq_version", params["InstanceRmqVersion"]),
resource.TestCheckResourceAttr(instanceResourceName, "tags.#", "1"),
resource.TestCheckResourceAttr(instanceResourceName, "tags.0", "terraform"),
resource.TestCheckResourceAttr(instanceResourceName, "nodes", "1"),
resource.TestCheckResourceAttr(dataSourceNodesName, "nodes.#", "1"),
resource.TestCheckResourceAttr(dataSourceNodesName, "nodes.0.rabbitmq_version", params["InstanceRmqVersion"]),
),
},
{
Config: configuration.GetTemplatedConfig(t, fileNamesUpgrade, paramsUpgrade01),
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr(dataSourceNodesName, "nodes.#", "1"),
resource.TestCheckResourceAttr(dataSourceNodesName, "nodes.0.rabbitmq_version", "3.12.2"),
),
},
{
Config: configuration.GetTemplatedConfig(t, fileNamesCheckUpgrade, paramsCheck),
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr(dataSourceNodesName, "nodes.#", "1"),
resource.TestCheckResourceAttr(dataSourceNodesName, "nodes.0.rabbitmq_version", "3.12.13"),
),
},
{
Config: configuration.GetTemplatedConfig(t, fileNamesUpgrade, paramsUpgrade02),
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr(dataSourceNodesName, "nodes.#", "1"),
resource.TestCheckResourceAttr(dataSourceNodesName, "nodes.0.rabbitmq_version", "3.12.13"),
),
},
{
Config: configuration.GetTemplatedConfig(t, fileNamesCheckUpgrade, paramsCheck),
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr(dataSourceNodesName, "nodes.#", "1"),
resource.TestCheckResourceAttr(dataSourceNodesName, "nodes.0.rabbitmq_version", "3.13.2"),
),
},
},
})
}
Loading

0 comments on commit 296ed96

Please sign in to comment.