diff --git a/api/upgrade_lavinmq.go b/api/upgrade_lavinmq.go new file mode 100644 index 00000000..153be163 --- /dev/null +++ b/api/upgrade_lavinmq.go @@ -0,0 +1,116 @@ +package api + +import ( + "fmt" + "log" + "time" +) + +// ReadVersions - Read versions LavinMQ can upgrade to +func (api *API) ReadLavinMQVersions(instanceID int) (map[string]any, error) { + var ( + data map[string]any + failed map[string]any + path = fmt.Sprintf("api/instances/%d/actions/new-lavinmq-versions", instanceID) + ) + + log.Printf("[DEBUG] api::upgrade_lavinmq#read_versions path: %s", path) + response, err := api.sling.New().Path(path).Receive(&data, &failed) + if err != nil { + return nil, err + } + + switch response.StatusCode { + case 200: + return data, nil + default: + return nil, fmt.Errorf("ReadVersions failed, status: %d, message: %s", + response.StatusCode, failed) + } +} + +// UpgradeLavinMQ - Upgrade to latest possible version or a specific available version +func (api *API) UpgradeLavinMQ(instanceID int, new_version string) (string, error) { + log.Printf("[DEBUG] api::upgrade_lavinmq#upgrade_lavinmq instanceID: %d"+ + ", new_version: %s", instanceID, new_version) + + if new_version == "" { + return api.UpgradeToLatestLavinMQVersion(instanceID) + } else { + return api.UpgradeToSpecificLavinMQVersion(instanceID, new_version) + } +} + +func (api *API) UpgradeToSpecificLavinMQVersion(instanceID int, version string) (string, error) { + var ( + data map[string]any + failed map[string]any + path = fmt.Sprintf("api/instances/%d/actions/upgrade-lavinmq", instanceID) + params = make(map[string]any) + ) + + params["version"] = version + log.Printf("[DEBUG] api::upgrade_lavinmq#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.waitUntilLavinMQUpgraded(instanceID) + default: + return "", fmt.Errorf("upgrade LavinMQ failed, status: %d, message: %s", + response.StatusCode, failed) + } +} + +func (api *API) UpgradeToLatestLavinMQVersion(instanceID int) (string, error) { + var ( + data map[string]any + failed map[string]any + path = fmt.Sprintf("api/instances/%d/actions/upgrade-lavinmq", instanceID) + ) + + log.Printf("[DEBUG] api::upgrade_lavinmq#upgrade_to_latest_version path: %s", path) + response, err := api.sling.New().Post(path).Receive(&data, &failed) + if err != nil { + return "", err + } + + switch response.StatusCode { + case 200: + return "Already at highest possible version", nil + case 202: + return api.waitUntilLavinMQUpgraded(instanceID) + default: + return "", fmt.Errorf("upgrade LavinMQ failed, status: %d, message: %s", + response.StatusCode, failed) + } +} + +func (api *API) waitUntilLavinMQUpgraded(instanceID int) (string, error) { + var ( + data []map[string]any + failed map[string]any + path = fmt.Sprintf("api/instances/%d/nodes", instanceID) + ) + + for { + _, err := api.sling.New().Path(path).Receive(&data, &failed) + if err != nil { + return "", err + } + + log.Printf("[DEBUG] api::upgrade_lavinmq#waitUntilUpgraded data: %v", data) + ready := true + for _, node := range data { + ready = ready && node["configured"].(bool) + } + if ready { + return "", nil + } + time.Sleep(10 * time.Second) + } +} diff --git a/cloudamqp/provider.go b/cloudamqp/provider.go index 42227bab..99b8bb2d 100644 --- a/cloudamqp/provider.go +++ b/cloudamqp/provider.go @@ -68,6 +68,7 @@ func Provider(v string, client *http.Client) *schema.Provider { "cloudamqp_rabbitmq_configuration": resourceRabbitMqConfiguration(), "cloudamqp_security_firewall": resourceSecurityFirewall(), "cloudamqp_upgrade_rabbitmq": resourceUpgradeRabbitMQ(), + "cloudamqp_upgrade_lavinmq": resourceUpgradeLavinMQ(), "cloudamqp_vpc_connect": resourceVpcConnect(), "cloudamqp_vpc_gcp_peering": resourceVpcGcpPeering(), "cloudamqp_vpc_peering": resourceVpcPeering(), diff --git a/cloudamqp/resource_cloudamqp_upgrade_lavinmq.go b/cloudamqp/resource_cloudamqp_upgrade_lavinmq.go new file mode 100644 index 00000000..e72a091e --- /dev/null +++ b/cloudamqp/resource_cloudamqp_upgrade_lavinmq.go @@ -0,0 +1,65 @@ +package cloudamqp + +import ( + "log" + "strconv" + + "github.com/cloudamqp/terraform-provider-cloudamqp/api" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func resourceUpgradeLavinMQ() *schema.Resource { + return &schema.Resource{ + Create: resourceUpgradeLavinMQInvoke, + Read: resourceUpgradeLavinMQRead, + Update: resourceUpgradeLavinMQUpdate, + Delete: resourceUpgradeLavinMQRemove, + Schema: map[string]*schema.Schema{ + "instance_id": { + Type: schema.TypeInt, + Required: true, + Description: "The CloudAMQP instance identifier", + }, + "new_version": { + Type: schema.TypeString, + ForceNew: true, + Optional: true, + Description: "The new version to upgrade to", + }, + }, + } +} + +func resourceUpgradeLavinMQInvoke(d *schema.ResourceData, meta interface{}) error { + var ( + api = meta.(*api.API) + instanceID = d.Get("instance_id").(int) + new_version = d.Get("new_version").(string) + ) + + log.Printf("[DEBUG] - Upgrading LavinMQ instance %d to version %s", instanceID, new_version) + response, err := api.UpgradeLavinMQ(instanceID, new_version) + if err != nil { + return err + } + + d.SetId(strconv.Itoa(instanceID)) + + if len(response) > 0 { + log.Printf("[INFO] - " + response) + } + + return nil +} + +func resourceUpgradeLavinMQRead(d *schema.ResourceData, meta interface{}) error { + return nil +} + +func resourceUpgradeLavinMQUpdate(d *schema.ResourceData, meta interface{}) error { + return nil +} + +func resourceUpgradeLavinMQRemove(d *schema.ResourceData, meta interface{}) error { + return nil +} diff --git a/docs/resources/upgrade_lavinmq.md b/docs/resources/upgrade_lavinmq.md new file mode 100644 index 00000000..f73d9766 --- /dev/null +++ b/docs/resources/upgrade_lavinmq.md @@ -0,0 +1,92 @@ +--- +layout: "cloudamqp" +page_title: "CloudAMQP: cloudamqp_upgrade_lavinmq" +description: |- + Invoke upgrade to latest possible upgradable versions for LavinMQ. +--- + +# cloudamqp_upgrade_lavinmq + +This resource allows you to upgrade LavinMQ version. + +There is two different ways to trigger the version upgrade + +> - Specify LavinMQ version to upgrade to +> - Upgrade to latest LavinMQ version + +See, below example usage for the difference. + +Only available for dedicated subscription plans running ***LavinMQ***. + +## Example Usage + +
+ + + Specify version upgrade, from v1.31.0 + + + +Specify the version to upgrade to. List available upgradable versions, use [CloudAMQP API](https://docs.cloudamqp.com/cloudamqp_api.html#get-available-versions). +After the upgrade finished, there can still be newer versions available. + +```hcl +resource "cloudamqp_instance" "instance" { + name = "lavinmq-version-upgrade-test" + plan = "lynx-1" + region = "amazon-web-services::us-west-1" +} + +resource "cloudamqp_upgrade_lavinmq" "upgrade" { + instance_id = cloudamqp_instance.instance.id + new_version = "1.3.1" +} +``` + +
+ +
+ + + Upgrade to latest possible version, from v1.31.0 + + + +This will upgrade LavinMQ to the latest possible version detected by the data source `cloudamqp_upgradable_versions`. + +```hcl +resource "cloudamqp_instance" "instance" { + name = "lavinmq-version-upgrade-test" + plan = "lynx-1" + region = "amazon-web-services::us-west-1" +} + +data "cloudamqp_upgradable_versions" "upgradable_versions" { + instance_id = cloudamqp_instance.instance.id +} + +resource "cloudamqp_upgrade_lavinmq" "upgrade" { + instance_id = cloudamqp_instance.instance.id + current_version = cloudamqp_instance.instance.rmq_version + new_version = data.cloudamqp_upgradable_versions.upgradable_versions.new_lavinmq_version +} +``` + +
+ + +## Argument Reference + +The following arguments are supported: + +* `instance_id` - (Required) The CloudAMQP instance identifier +* `new_version` - (Optional/ForceNew) The new version to upgrade to + +## Import + +Not possible to import this resource. + +## Important Upgrade Information + +> - All single node upgrades will require some downtime since LavinMQ needs a restart. +> - Auto delete queues (queues that are marked AD) will be deleted during the update.