-
Notifications
You must be signed in to change notification settings - Fork 359
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adds new resource for blockstorage v3 qos. Bump gophercloud to include necessary calls. Relates to: #1212
- Loading branch information
1 parent
6a50fb0
commit bcdec00
Showing
8 changed files
with
425 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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, | ||
}, | ||
}, | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
153
openstack/resource_openstack_blockstorage_qos_v3_test.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 = { | ||
} | ||
} | ||
` |
Oops, something went wrong.