Skip to content

Commit

Permalink
Add openstack_blockstorage_qos_v3
Browse files Browse the repository at this point in the history
Adds new resource for blockstorage v3 qos.
Bump gophercloud to include necessary calls.
Relates to: #1212
  • Loading branch information
nikParasyr committed Dec 1, 2021
1 parent 6a50fb0 commit bcdec00
Show file tree
Hide file tree
Showing 8 changed files with 425 additions and 1 deletion.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module github.com/terraform-provider-openstack/terraform-provider-openstack
go 1.17

require (
github.com/gophercloud/gophercloud v0.23.0
github.com/gophercloud/gophercloud v0.23.1-0.20211129155426-97dea84b37a5
github.com/gophercloud/utils v0.0.0-20210909165623-d7085207ff6d
github.com/hashicorp/terraform-plugin-sdk/v2 v2.7.1
github.com/mitchellh/go-homedir v1.1.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,8 @@ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5m
github.com/gophercloud/gophercloud v0.20.0/go.mod h1:wRtmUelyIIv3CSSDI47aUwbs075O6i+LY+pXsKCBsb4=
github.com/gophercloud/gophercloud v0.23.0 h1:I3P10oKlGu3DHP9PrEWMr1ya+/+3Rc9uRHNkRZ9wO7g=
github.com/gophercloud/gophercloud v0.23.0/go.mod h1:MRw6uyLj8uCGbIvBlqL7QW67t0QtNZnzydUzewo1Ioc=
github.com/gophercloud/gophercloud v0.23.1-0.20211129155426-97dea84b37a5 h1:EckX+4F7gL2lJgrQaqmZYomKv5EupJgzviarTTxDg4g=
github.com/gophercloud/gophercloud v0.23.1-0.20211129155426-97dea84b37a5/go.mod h1:MRw6uyLj8uCGbIvBlqL7QW67t0QtNZnzydUzewo1Ioc=
github.com/gophercloud/utils v0.0.0-20210909165623-d7085207ff6d h1:0Wsi5dvUuPF6dVn/CNfEA4xLxmaEtOt7tV2HD16xIf8=
github.com/gophercloud/utils v0.0.0-20210909165623-d7085207ff6d/go.mod h1:qOGlfG6OIJ193/c3Xt/XjOfHataNZdQcVgiu93LxBUM=
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
Expand Down
31 changes: 31 additions & 0 deletions openstack/import_openstack_blockstorage_qos_v3_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package openstack

import (
"testing"

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

func TestAccBlockStorageQosV3_importBasic(t *testing.T) {
resourceName := "openstack_blockstorage_qos_v3.qos"

resource.Test(t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
testAccPreCheckAdminOnly(t)
},
ProviderFactories: testAccProviders,
CheckDestroy: testAccCheckBlockStorageQosV3Destroy,
Steps: []resource.TestStep{
{
Config: testAccBlockStorageQosV3Basic,
},

{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
},
},
})
}
1 change: 1 addition & 0 deletions openstack/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,7 @@ func Provider() *schema.Provider {
},

ResourcesMap: map[string]*schema.Resource{
"openstack_blockstorage_qos_v3": resourceBlockStorageQosV3(),
"openstack_blockstorage_quotaset_v2": resourceBlockStorageQuotasetV2(),
"openstack_blockstorage_quotaset_v3": resourceBlockStorageQuotasetV3(),
"openstack_blockstorage_volume_v1": resourceBlockStorageVolumeV1(),
Expand Down
173 changes: 173 additions & 0 deletions openstack/resource_openstack_blockstorage_qos_v3.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
package openstack

import (
"context"
"log"

"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"

"github.com/gophercloud/gophercloud/openstack/blockstorage/v3/qos"
)

func resourceBlockStorageQosV3() *schema.Resource {
return &schema.Resource{
CreateContext: resourceBlockStorageQosV3Create,
ReadContext: resourceBlockStorageQosV3Read,
UpdateContext: resourceBlockStorageQosV3Update,
DeleteContext: resourceBlockStorageQosV3Delete,
Importer: &schema.ResourceImporter{
StateContext: schema.ImportStatePassthroughContext,
},

Schema: map[string]*schema.Schema{
"region": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ForceNew: true,
},

"name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},

"consumer": {
Type: schema.TypeString,
Optional: true,
ValidateFunc: validation.StringInSlice([]string{
"front-end", "back-end", "both",
}, false),
},

"specs": {
Type: schema.TypeMap,
Optional: true,
},
},
}
}

func resourceBlockStorageQosV3Create(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
config := meta.(*Config)
blockStorageClient, err := config.BlockStorageV3Client(GetRegion(d, config))
if err != nil {
return diag.Errorf("Error creating OpenStack block storage client: %s", err)
}

name := d.Get("name").(string)
consumer := qos.QoSConsumer(d.Get("consumer").(string))
specs := d.Get("specs").(map[string]interface{})
createOpts := qos.CreateOpts{
Name: name,
Consumer: consumer,
Specs: expandToMapStringString(specs),
}

log.Printf("[DEBUG] openstack_blockstorage_qos_v3 create options: %#v", createOpts)
qosRes, err := qos.Create(blockStorageClient, &createOpts).Extract()
if err != nil {
return diag.Errorf("Error creating openstack_blockstorage_qos_v3 %s: %s", name, err)
}

d.SetId(qosRes.ID)

return resourceBlockStorageQosV3Read(ctx, d, meta)
}

func resourceBlockStorageQosV3Read(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
config := meta.(*Config)
blockStorageClient, err := config.BlockStorageV3Client(GetRegion(d, config))
if err != nil {
return diag.Errorf("Error creating OpenStack block storage client: %s", err)
}

qosRes, err := qos.Get(blockStorageClient, d.Id()).Extract()
if err != nil {
return diag.FromErr(CheckDeleted(d, err, "Error retrieving openstack_blockstorage_qos_v3"))
}

log.Printf("[DEBUG] Retrieved openstack_blockstorage_qos_v3 %s: %#v", d.Id(), qosRes)

d.Set("region", GetRegion(d, config))
d.Set("name", qosRes.Name)
d.Set("consumer", qosRes.Consumer)

if err := d.Set("specs", qosRes.Specs); err != nil {
log.Printf("[WARN] Unable to set specs for openstack_blockstorage_qos_v3 %s: %s", d.Id(), err)
}

return nil
}

func resourceBlockStorageQosV3Update(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
config := meta.(*Config)
blockStorageClient, err := config.BlockStorageV3Client(GetRegion(d, config))
if err != nil {
return diag.Errorf("Error creating OpenStack block storage client: %s", err)
}

hasChange := false
var updateOpts qos.UpdateOpts

if d.HasChange("consumer") {
hasChange = true
consumer := qos.QoSConsumer(d.Get("consumer").(string))
updateOpts.Consumer = consumer
}

if d.HasChange("specs") {
oldSpecsRaw, newSpecsRaw := d.GetChange("specs")

// Delete all old specs.
var deleteKeys qos.DeleteKeysOpts
for oldKey := range oldSpecsRaw.(map[string]interface{}) {
deleteKeys = append(deleteKeys, oldKey)
}
err = qos.DeleteKeys(blockStorageClient, d.Id(), deleteKeys).ExtractErr()
if err != nil {
return diag.Errorf("Error deleting specs for openstack_blockstorage_qos_v3 %s: %s", d.Id(), err)
}

// Add new specs to UpdateOpts
newSpecs := expandToMapStringString(newSpecsRaw.(map[string]interface{}))
if len(newSpecs) > 0 {
hasChange = true
updateOpts.Specs = newSpecs
}
}

if hasChange {
_, err = qos.Update(blockStorageClient, d.Id(), updateOpts).Extract()
if err != nil {
return diag.Errorf("Error updating openstack_blockstorage_qos_v3 %s: %s", d.Id(), err)
}
}

return resourceBlockStorageQosV3Read(ctx, d, meta)
}

func resourceBlockStorageQosV3Delete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
config := meta.(*Config)
blockStorageClient, err := config.BlockStorageV3Client(GetRegion(d, config))
if err != nil {
return diag.Errorf("Error creating OpenStack block storage client: %s", err)
}

// remove all associations first
err = qos.DisassociateAll(blockStorageClient, d.Id()).ExtractErr()
if err != nil {
return diag.FromErr(CheckDeleted(d, err, "Error deleting openstack_blockstorage_qos_v3 associations"))
}

// Delete the QoS itself
err = qos.Delete(blockStorageClient, d.Id(), qos.DeleteOpts{}).ExtractErr()
if err != nil {
return diag.FromErr(CheckDeleted(d, err, "Error deleting openstack_blockstorage_qos_v3"))
}

return nil
}
153 changes: 153 additions & 0 deletions openstack/resource_openstack_blockstorage_qos_v3_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
package openstack

import (
"fmt"
"testing"

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

"github.com/gophercloud/gophercloud/openstack/blockstorage/v3/qos"
)

func TestAccBlockStorageQosV3_basic(t *testing.T) {
var qosTest qos.QoS

resource.Test(t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
testAccPreCheckAdminOnly(t)
},
ProviderFactories: testAccProviders,
CheckDestroy: testAccCheckBlockStorageQosV3Destroy,
Steps: []resource.TestStep{
{
Config: testAccBlockStorageQosV3Basic,
Check: resource.ComposeTestCheckFunc(
testAccCheckBlockStorageQosV3Exists("openstack_blockstorage_qos_v3.qos", &qosTest),
resource.TestCheckResourceAttr(
"openstack_blockstorage_qos_v3.qos", "name", "foo"),
resource.TestCheckResourceAttr(
"openstack_blockstorage_qos_v3.qos", "consumer", "front-end"),
resource.TestCheckResourceAttr(
"openstack_blockstorage_qos_v3.qos", "specs.%", "1"),
resource.TestCheckResourceAttr(
"openstack_blockstorage_qos_v3.qos", "specs.read_iops_sec", "20000"),
),
},
{
Config: testAccBlockStorageQosV3Update1,
Check: resource.ComposeTestCheckFunc(
testAccCheckBlockStorageQosV3Exists("openstack_blockstorage_qos_v3.qos", &qosTest),
resource.TestCheckResourceAttr(
"openstack_blockstorage_qos_v3.qos", "name", "foo"),
resource.TestCheckResourceAttr(
"openstack_blockstorage_qos_v3.qos", "consumer", "back-end"),
resource.TestCheckResourceAttr(
"openstack_blockstorage_qos_v3.qos", "specs.%", "2"),
resource.TestCheckResourceAttr(
"openstack_blockstorage_qos_v3.qos", "specs.read_iops_sec", "40000"),
resource.TestCheckResourceAttr(
"openstack_blockstorage_qos_v3.qos", "specs.write_iops_sec", "40000"),
),
},
{
Config: testAccBlockStorageQosV3Update2,
Check: resource.ComposeTestCheckFunc(
testAccCheckBlockStorageQosV3Exists("openstack_blockstorage_qos_v3.qos", &qosTest),
resource.TestCheckResourceAttr(
"openstack_blockstorage_qos_v3.qos", "name", "foo"),
resource.TestCheckResourceAttr(
"openstack_blockstorage_qos_v3.qos", "consumer", "back-end"),
resource.TestCheckResourceAttr(
"openstack_blockstorage_qos_v3.qos", "specs.%", "0"),
),
},
},
})
}

func testAccCheckBlockStorageQosV3Destroy(s *terraform.State) error {
config := testAccProvider.Meta().(*Config)
blockStorageClient, err := config.BlockStorageV3Client(osRegionName)
if err != nil {
return fmt.Errorf("Error creating OpenStack block storage client: %s", err)
}

for _, rs := range s.RootModule().Resources {
if rs.Type != "openstack_blockstorage_qos_v3" {
continue
}

_, err := qos.Get(blockStorageClient, rs.Primary.ID).Extract()
if err == nil {
return fmt.Errorf("Qos still exists")
}
}

return nil
}

func testAccCheckBlockStorageQosV3Exists(n string, qosTest *qos.QoS) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n]
if !ok {
return fmt.Errorf("Not found: %s", n)
}

if rs.Primary.ID == "" {
return fmt.Errorf("No ID is set")
}

config := testAccProvider.Meta().(*Config)
blockStorageClient, err := config.BlockStorageV3Client(osRegionName)
if err != nil {
return fmt.Errorf("Error creating OpenStack block storage client: %s", err)
}

found, err := qos.Get(blockStorageClient, rs.Primary.ID).Extract()
if err != nil {
return err
}

if found.ID != rs.Primary.ID {
return fmt.Errorf("Qos not found")
}

*qosTest = *found

return nil
}
}

const testAccBlockStorageQosV3Basic = `
resource "openstack_blockstorage_qos_v3" "qos" {
name = "foo"
consumer = "front-end"
specs = {
read_iops_sec = "20000"
}
}
`

const testAccBlockStorageQosV3Update1 = `
resource "openstack_blockstorage_qos_v3" "qos" {
name = "foo"
consumer = "back-end"
specs = {
read_iops_sec = "40000"
write_iops_sec = "40000"
}
}
`

const testAccBlockStorageQosV3Update2 = `
resource "openstack_blockstorage_qos_v3" "qos" {
name = "foo"
consumer = "back-end"
specs = {
}
}
`

0 comments on commit bcdec00

Please sign in to comment.