Skip to content

Commit 7a66386

Browse files
authored
Add new resource blockstorage_volume_type_access_v3 (terraform-provider-openstack#1223)
1 parent a1bd35c commit 7a66386

8 files changed

Lines changed: 386 additions & 1 deletion

‎go.mod‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ module github.com/terraform-provider-openstack/terraform-provider-openstack
33
go 1.15
44

55
require (
6-
github.com/gophercloud/gophercloud v0.16.1-0.20210310004848-3dc4bb870058
6+
github.com/gophercloud/gophercloud v0.16.1-0.20210401161025-513734676e64
77
github.com/gophercloud/utils v0.0.0-20210216074907-f6de111f2eae
88
github.com/hashicorp/terraform-plugin-sdk v1.16.0
99
github.com/mitchellh/go-homedir v1.1.0

‎go.sum‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,8 @@ github.com/gophercloud/gophercloud v0.16.0 h1:sWjPfypuzxRxjVbk3/MsU4H8jS0NNlyauZ
157157
github.com/gophercloud/gophercloud v0.16.0/go.mod h1:wRtmUelyIIv3CSSDI47aUwbs075O6i+LY+pXsKCBsb4=
158158
github.com/gophercloud/gophercloud v0.16.1-0.20210310004848-3dc4bb870058 h1:hPAQ2fnoMgzk5xOzaBDfL792GorxU5amuX5fBWODPVw=
159159
github.com/gophercloud/gophercloud v0.16.1-0.20210310004848-3dc4bb870058/go.mod h1:wRtmUelyIIv3CSSDI47aUwbs075O6i+LY+pXsKCBsb4=
160+
github.com/gophercloud/gophercloud v0.16.1-0.20210401161025-513734676e64 h1:EjfTIoyWvib2gz8YctnGveUDSTxb1NAcqibdagrIRXE=
161+
github.com/gophercloud/gophercloud v0.16.1-0.20210401161025-513734676e64/go.mod h1:wRtmUelyIIv3CSSDI47aUwbs075O6i+LY+pXsKCBsb4=
160162
github.com/gophercloud/utils v0.0.0-20210216074907-f6de111f2eae h1:Hi3IgB9RQDE15Kfovd8MTZrcana+UlQqNbOif8dLpA0=
161163
github.com/gophercloud/utils v0.0.0-20210216074907-f6de111f2eae/go.mod h1:wx8HMD8oQD0Ryhz6+6ykq75PJ79iPyEqYHfwZ4l7OsA=
162164
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package openstack
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
7+
"github.com/hashicorp/terraform-plugin-sdk/helper/acctest"
8+
"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
9+
)
10+
11+
func TestAccBlockStorageV3VolumeTypeAccess_importBasic(t *testing.T) {
12+
resourceName := "openstack_blockstorage_volume_type_access_v3.volume_type_access"
13+
14+
var projectName = fmt.Sprintf("ACCPTTEST-%s", acctest.RandString(5))
15+
var vtName = fmt.Sprintf("ACCPTTEST-%s", acctest.RandString(5))
16+
17+
resource.Test(t, resource.TestCase{
18+
PreCheck: func() {
19+
testAccPreCheck(t)
20+
testAccPreCheckAdminOnly(t)
21+
},
22+
Providers: testAccProviders,
23+
CheckDestroy: testAccCheckBlockstorageV3VolumeTypeAccessDestroy,
24+
Steps: []resource.TestStep{
25+
{
26+
Config: testAccBlockstorageV3VolumeTypeAccessBasic(projectName, vtName),
27+
},
28+
29+
{
30+
ResourceName: resourceName,
31+
ImportState: true,
32+
ImportStateVerify: true,
33+
},
34+
},
35+
})
36+
}

‎openstack/provider.go‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,7 @@ func Provider() terraform.ResourceProvider {
301301
"openstack_blockstorage_volume_v3": resourceBlockStorageVolumeV3(),
302302
"openstack_blockstorage_volume_attach_v2": resourceBlockStorageVolumeAttachV2(),
303303
"openstack_blockstorage_volume_attach_v3": resourceBlockStorageVolumeAttachV3(),
304+
"openstack_blockstorage_volume_type_access_v3": resourceBlockstorageVolumeTypeAccessV3(),
304305
"openstack_blockstorage_volume_type_v3": resourceBlockStorageVolumeTypeV3(),
305306
"openstack_compute_aggregate_v2": resourceComputeAggregateV2(),
306307
"openstack_compute_flavor_v2": resourceComputeFlavorV2(),
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
package openstack
2+
3+
import (
4+
"fmt"
5+
"strings"
6+
7+
"github.com/gophercloud/gophercloud/openstack/blockstorage/v3/volumetypes"
8+
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
9+
)
10+
11+
func resourceBlockstorageVolumeTypeAccessV3() *schema.Resource {
12+
return &schema.Resource{
13+
Create: resourceBlockstorageVolumeTypeAccessV3Create,
14+
Read: resourceBlockstorageVolumeTypeAccessV3Read,
15+
Delete: resourceBlockstorageVolumeTypeAccessV3Delete,
16+
Importer: &schema.ResourceImporter{
17+
State: schema.ImportStatePassthrough,
18+
},
19+
20+
Schema: map[string]*schema.Schema{
21+
"region": {
22+
Type: schema.TypeString,
23+
Optional: true,
24+
Computed: true,
25+
ForceNew: true,
26+
},
27+
"project_id": {
28+
Type: schema.TypeString,
29+
Required: true,
30+
ForceNew: true,
31+
},
32+
"volume_type_id": {
33+
Type: schema.TypeString,
34+
Required: true,
35+
ForceNew: true,
36+
},
37+
},
38+
}
39+
}
40+
41+
func resourceBlockstorageVolumeTypeAccessV3Create(d *schema.ResourceData, meta interface{}) error {
42+
config := meta.(*Config)
43+
blockStorageClient, err := config.BlockStorageV3Client(GetRegion(d, config))
44+
if err != nil {
45+
return fmt.Errorf("Error creating OpenStack block storage client: %s", err)
46+
}
47+
48+
projectID := d.Get("project_id").(string)
49+
vtID := d.Get("volume_type_id").(string)
50+
51+
accessOpts := volumetypes.AddAccessOpts{
52+
Project: projectID,
53+
}
54+
55+
if err := volumetypes.AddAccess(blockStorageClient, vtID, accessOpts).ExtractErr(); err != nil {
56+
return fmt.Errorf("Error creating openstack_blockstorage_volume_type_access_v3: %s", err)
57+
}
58+
59+
id := fmt.Sprintf("%s/%s", vtID, projectID)
60+
d.SetId(id)
61+
62+
return resourceBlockstorageVolumeTypeAccessV3Read(d, meta)
63+
}
64+
65+
func resourceBlockstorageVolumeTypeAccessV3Read(d *schema.ResourceData, meta interface{}) error {
66+
config := meta.(*Config)
67+
blockStorageClient, err := config.BlockStorageV3Client(GetRegion(d, config))
68+
if err != nil {
69+
return fmt.Errorf("Error creating OpenStack block storage client: %s", err)
70+
}
71+
72+
vtID, projectID, err := parseVolumeTypeAccessID(d.Id())
73+
if err != nil {
74+
return CheckDeleted(d, err, "Error parsing ID of openstack_blockstorage_volume_type_access_v3")
75+
}
76+
77+
allPages, err := volumetypes.ListAccesses(blockStorageClient, vtID).AllPages()
78+
if err != nil {
79+
return fmt.Errorf("Error retrieving accesses openstack_blockstorage_volume_type_access_v3 for vt: %s", vtID)
80+
}
81+
82+
allAccesses, err := volumetypes.ExtractAccesses(allPages)
83+
if err != nil {
84+
return fmt.Errorf("Error extracting accesses openstack_blockstorage_volume_type_access_v3 for vt: %s", vtID)
85+
}
86+
87+
found := false
88+
for _, access := range allAccesses {
89+
if access.VolumeTypeID == vtID && access.ProjectID == projectID {
90+
found = true
91+
break
92+
}
93+
}
94+
95+
if !found {
96+
return fmt.Errorf("Error getting volume type access openstack_blockstorage_volume_type_access_v3 for vt: %s", vtID)
97+
}
98+
99+
d.Set("region", GetRegion(d, config))
100+
d.Set("project_id", projectID)
101+
d.Set("volume_type_id", vtID)
102+
103+
return nil
104+
}
105+
106+
func resourceBlockstorageVolumeTypeAccessV3Delete(d *schema.ResourceData, meta interface{}) error {
107+
config := meta.(*Config)
108+
blockStorageClient, err := config.BlockStorageV3Client(GetRegion(d, config))
109+
if err != nil {
110+
return fmt.Errorf("Error creating OpenStack block storage client: %s", err)
111+
}
112+
113+
vtID, projectID, err := parseVolumeTypeAccessID(d.Id())
114+
if err != nil {
115+
return fmt.Errorf("Error parsing ID of openstack_blockstorage_volume_type_access_v3 %s: %s", d.Id(), err)
116+
}
117+
118+
removeOpts := volumetypes.RemoveAccessOpts{
119+
Project: projectID,
120+
}
121+
122+
if err := volumetypes.RemoveAccess(blockStorageClient, vtID, removeOpts).ExtractErr(); err != nil {
123+
return fmt.Errorf("Error removing openstack_blockstorage_volume_type_access_v3 %s: %s", d.Id(), err)
124+
}
125+
126+
return nil
127+
}
128+
129+
func parseVolumeTypeAccessID(id string) (string, string, error) {
130+
idParts := strings.Split(id, "/")
131+
if len(idParts) < 2 {
132+
return "", "", fmt.Errorf("Unable to determine volume type access ID %s", id)
133+
}
134+
135+
return idParts[0], idParts[1], nil
136+
}
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
package openstack
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
7+
"github.com/hashicorp/terraform-plugin-sdk/helper/acctest"
8+
"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
9+
"github.com/hashicorp/terraform-plugin-sdk/terraform"
10+
11+
"github.com/gophercloud/gophercloud/openstack/blockstorage/v3/volumetypes"
12+
"github.com/gophercloud/gophercloud/openstack/identity/v3/projects"
13+
)
14+
15+
func TestAccBlockstorageV3VolumeTypeAccess_basic(t *testing.T) {
16+
var project projects.Project
17+
var projectName = fmt.Sprintf("ACCPTTEST-%s", acctest.RandString(5))
18+
19+
var vt volumetypes.VolumeType
20+
var vtName = fmt.Sprintf("ACCPTTEST-%s", acctest.RandString(5))
21+
22+
resource.Test(t, resource.TestCase{
23+
PreCheck: func() {
24+
testAccPreCheck(t)
25+
testAccPreCheckAdminOnly(t)
26+
},
27+
Providers: testAccProviders,
28+
CheckDestroy: testAccCheckBlockstorageV3VolumeTypeAccessDestroy,
29+
Steps: []resource.TestStep{
30+
{
31+
Config: testAccBlockstorageV3VolumeTypeAccessBasic(projectName, vtName),
32+
Check: resource.ComposeTestCheckFunc(
33+
testAccCheckIdentityV3ProjectExists("openstack_identity_project_v3.project_1", &project),
34+
testAccCheckBlockStorageVolumeTypeV3Exists("openstack_blockstorage_volume_type_v3.volume_type_1", &vt),
35+
testAccCheckBlockstorageV3VolumeTypeAccessExists("openstack_blockstorage_volume_type_access_v3.volume_type_access"),
36+
resource.TestCheckResourceAttrPtr(
37+
"openstack_blockstorage_volume_type_access_v3.volume_type_access", "project_id", &project.ID),
38+
resource.TestCheckResourceAttrPtr(
39+
"openstack_blockstorage_volume_type_access_v3.volume_type_access", "volume_type_id", &vt.ID),
40+
),
41+
},
42+
},
43+
})
44+
}
45+
46+
func testAccCheckBlockstorageV3VolumeTypeAccessDestroy(s *terraform.State) error {
47+
config := testAccProvider.Meta().(*Config)
48+
blockStorageClient, err := config.BlockStorageV3Client(osRegionName)
49+
if err != nil {
50+
return fmt.Errorf("Error creating OpenStack block storage client: %s", err)
51+
}
52+
53+
for _, rs := range s.RootModule().Resources {
54+
if rs.Type != "openstack_blockstorage_volume_type_access_v3" {
55+
continue
56+
}
57+
58+
vtid, pid, err := parseVolumeTypeAccessID(rs.Primary.ID)
59+
if err != nil {
60+
return err
61+
}
62+
63+
allPages, err := volumetypes.ListAccesses(blockStorageClient, vtid).AllPages()
64+
if err == nil {
65+
allAccesses, err := volumetypes.ExtractAccesses(allPages)
66+
if err == nil {
67+
for _, access := range allAccesses {
68+
if access.VolumeTypeID == vtid && access.ProjectID == pid {
69+
return fmt.Errorf("VolumeType access still exists")
70+
}
71+
}
72+
}
73+
}
74+
}
75+
76+
return nil
77+
}
78+
79+
func testAccCheckBlockstorageV3VolumeTypeAccessExists(n string) resource.TestCheckFunc {
80+
return func(s *terraform.State) error {
81+
rs, ok := s.RootModule().Resources[n]
82+
if !ok {
83+
return fmt.Errorf("Not found: %s", n)
84+
}
85+
86+
if rs.Primary.ID == "" {
87+
return fmt.Errorf("No ID is set")
88+
}
89+
90+
config := testAccProvider.Meta().(*Config)
91+
blockStorageClient, err := config.BlockStorageV3Client(osRegionName)
92+
if err != nil {
93+
return fmt.Errorf("Error creating OpenStack block storage client: %s", err)
94+
}
95+
96+
vtid, pid, err := parseVolumeTypeAccessID(rs.Primary.ID)
97+
if err != nil {
98+
return err
99+
}
100+
101+
allPages, err := volumetypes.ListAccesses(blockStorageClient, vtid).AllPages()
102+
if err != nil {
103+
return fmt.Errorf("Error retrieving accesses for vt: %s", vtid)
104+
}
105+
106+
allAccesses, err := volumetypes.ExtractAccesses(allPages)
107+
if err != nil {
108+
return fmt.Errorf("Error extracting accesses for vt: %s", vtid)
109+
}
110+
111+
found := false
112+
for _, access := range allAccesses {
113+
if access.VolumeTypeID == vtid && access.ProjectID == pid {
114+
found = true
115+
break
116+
}
117+
}
118+
119+
if !found {
120+
return fmt.Errorf("Volume Type Access not found for vtid/pid: %s", rs.Primary.ID)
121+
}
122+
123+
return nil
124+
}
125+
}
126+
127+
func testAccBlockstorageV3VolumeTypeAccessBasic(projectName, vtName string) string {
128+
return fmt.Sprintf(`
129+
resource "openstack_identity_project_v3" "project_1" {
130+
name = "%s"
131+
}
132+
133+
resource "openstack_blockstorage_volume_type_v3" "volume_type_1" {
134+
name = "%s"
135+
is_public = false
136+
}
137+
138+
resource "openstack_blockstorage_volume_type_access_v3" "volume_type_access" {
139+
project_id = "${openstack_identity_project_v3.project_1.id}"
140+
volume_type_id = "${openstack_blockstorage_volume_type_v3.volume_type_1.id}"
141+
}
142+
`, projectName, vtName)
143+
}

0 commit comments

Comments
 (0)