provider/openstack: Updates to openstack_images_image_v2 resource

This commit has a few more fixes to the recently added
openstack_images_image_v2 resource:

* tags were changed to a Set because the OpenStack Image API does
not seem to respect ordering.
* The visibility argument was fixed.
* Acceptance tests for all updatable fields has been implemented.
* Documentation updates, including a new entry in the sidebar.
This commit is contained in:
Joe Topjian 2017-02-19 21:20:29 +00:00
parent 75e068f146
commit 9188a80192
5 changed files with 194 additions and 36 deletions

View File

@ -60,6 +60,13 @@ func testAccPreCheck(t *testing.T) {
}
}
func testAccPreCheckAdminOnly(t *testing.T) {
v := os.Getenv("OS_USERNAME")
if v != "admin" {
t.Skip("Skipping test because it requires the admin user")
}
}
func TestProvider(t *testing.T) {
if err := Provider().(*schema.Provider).InternalValidate(); err != nil {
t.Fatalf("err: %s", err)

View File

@ -141,9 +141,10 @@ func resourceImagesImageV2() *schema.Resource {
},
"tags": &schema.Schema{
Type: schema.TypeList,
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Schema{Type: schema.TypeString},
Set: schema.HashString,
},
"update_at": &schema.Schema{
@ -156,7 +157,7 @@ func resourceImagesImageV2() *schema.Resource {
Optional: true,
ForceNew: false,
ValidateFunc: resourceImagesImageV2ValidateVisibility,
Default: images.ImageVisibilityPrivate,
Default: "private",
},
},
}
@ -182,11 +183,8 @@ func resourceImagesImageV2Create(d *schema.ResourceData, meta interface{}) error
}
if v, ok := d.GetOk("tags"); ok {
var tags []string
for _, tag := range v.([]interface{}) {
tags = append(tags, tag.(string))
}
createOpts.Tags = tags
tags := v.(*schema.Set).List()
createOpts.Tags = resourceImagesImageV2BuildTags(tags)
}
d.Partial(true)
@ -273,9 +271,8 @@ func resourceImagesImageV2Read(d *schema.ResourceData, meta interface{}) error {
d.Set("name", img.Name)
d.Set("protected", img.Protected)
d.Set("size_bytes", img.SizeBytes)
d.Set("tags", resourceImagesImageV2RemoveEmptyTags(img.Tags))
d.Set("tags", img.Tags)
d.Set("visibility", img.Visibility)
return nil
}
@ -289,7 +286,8 @@ func resourceImagesImageV2Update(d *schema.ResourceData, meta interface{}) error
updateOpts := make(images.UpdateOpts, 0)
if d.HasChange("visibility") {
v := images.UpdateVisibility{Visibility: d.Get("visibility").(images.ImageVisibility)}
visibility := resourceImagesImageV2VisibilityFromString(d.Get("visibility").(string))
v := images.UpdateVisibility{Visibility: visibility}
updateOpts = append(updateOpts, v)
}
@ -299,7 +297,10 @@ func resourceImagesImageV2Update(d *schema.ResourceData, meta interface{}) error
}
if d.HasChange("tags") {
v := images.ReplaceImageTags{NewTags: d.Get("tags").([]string)}
tags := d.Get("tags").(*schema.Set).List()
v := images.ReplaceImageTags{
NewTags: resourceImagesImageV2BuildTags(tags),
}
updateOpts = append(updateOpts, v)
}
@ -330,12 +331,22 @@ func resourceImagesImageV2Delete(d *schema.ResourceData, meta interface{}) error
}
func resourceImagesImageV2ValidateVisibility(v interface{}, k string) (ws []string, errors []error) {
value := v.(images.ImageVisibility)
if value == images.ImageVisibilityPublic || value == images.ImageVisibilityPrivate || value == images.ImageVisibilityShared || value == images.ImageVisibilityCommunity {
return
value := v.(string)
validVisibilities := []string{
"public",
"private",
"shared",
"community",
}
errors = append(errors, fmt.Errorf("%q must be one of %q, %q, %q, %q", k, images.ImageVisibilityPublic, images.ImageVisibilityPrivate, images.ImageVisibilityCommunity, images.ImageVisibilityShared))
for _, v := range validVisibilities {
if value == v {
return
}
}
err := fmt.Errorf("%s must be one of %s", k, validVisibilities)
errors = append(errors, err)
return
}
@ -476,12 +487,11 @@ func resourceImagesImageV2RefreshFunc(client *gophercloud.ServiceClient, id stri
}
}
func resourceImagesImageV2RemoveEmptyTags(s []string) []string {
var r []string
for _, str := range s {
if str != "" {
r = append(r, str)
}
func resourceImagesImageV2BuildTags(v []interface{}) []string {
var tags []string
for _, tag := range v {
tags = append(tags, tag.(string))
}
return r
return tags
}

View File

@ -36,7 +36,7 @@ func TestAccImagesImageV2_basic(t *testing.T) {
})
}
func TestAccImagesImageV2_with_tags(t *testing.T) {
func TestAccImagesImageV2_name(t *testing.T) {
var image images.Image
resource.Test(t, resource.TestCase{
@ -45,7 +45,35 @@ func TestAccImagesImageV2_with_tags(t *testing.T) {
CheckDestroy: testAccCheckImagesImageV2Destroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccImagesImageV2_with_tags,
Config: testAccImagesImageV2_name_1,
Check: resource.ComposeTestCheckFunc(
testAccCheckImagesImageV2Exists("openstack_images_image_v2.image_1", &image),
resource.TestCheckResourceAttr(
"openstack_images_image_v2.image_1", "name", "Rancher TerraformAccTest"),
),
},
resource.TestStep{
Config: testAccImagesImageV2_name_2,
Check: resource.ComposeTestCheckFunc(
testAccCheckImagesImageV2Exists("openstack_images_image_v2.image_1", &image),
resource.TestCheckResourceAttr(
"openstack_images_image_v2.image_1", "name", "TerraformAccTest Rancher"),
),
},
},
})
}
func TestAccImagesImageV2_tags(t *testing.T) {
var image images.Image
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckImagesImageV2Destroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccImagesImageV2_tags_1,
Check: resource.ComposeTestCheckFunc(
testAccCheckImagesImageV2Exists("openstack_images_image_v2.image_1", &image),
testAccCheckImagesImageV2HasTag("openstack_images_image_v2.image_1", "foo"),
@ -53,6 +81,56 @@ func TestAccImagesImageV2_with_tags(t *testing.T) {
testAccCheckImagesImageV2TagCount("openstack_images_image_v2.image_1", 2),
),
},
resource.TestStep{
Config: testAccImagesImageV2_tags_2,
Check: resource.ComposeTestCheckFunc(
testAccCheckImagesImageV2Exists("openstack_images_image_v2.image_1", &image),
testAccCheckImagesImageV2HasTag("openstack_images_image_v2.image_1", "foo"),
testAccCheckImagesImageV2HasTag("openstack_images_image_v2.image_1", "bar"),
testAccCheckImagesImageV2HasTag("openstack_images_image_v2.image_1", "baz"),
testAccCheckImagesImageV2TagCount("openstack_images_image_v2.image_1", 3),
),
},
resource.TestStep{
Config: testAccImagesImageV2_tags_3,
Check: resource.ComposeTestCheckFunc(
testAccCheckImagesImageV2Exists("openstack_images_image_v2.image_1", &image),
testAccCheckImagesImageV2HasTag("openstack_images_image_v2.image_1", "foo"),
testAccCheckImagesImageV2HasTag("openstack_images_image_v2.image_1", "baz"),
testAccCheckImagesImageV2TagCount("openstack_images_image_v2.image_1", 2),
),
},
},
})
}
func TestAccImagesImageV2_visibility(t *testing.T) {
var image images.Image
resource.Test(t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
testAccPreCheckAdminOnly(t)
},
Providers: testAccProviders,
CheckDestroy: testAccCheckImagesImageV2Destroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccImagesImageV2_visibility_1,
Check: resource.ComposeTestCheckFunc(
testAccCheckImagesImageV2Exists("openstack_images_image_v2.image_1", &image),
resource.TestCheckResourceAttr(
"openstack_images_image_v2.image_1", "visibility", "private"),
),
},
resource.TestStep{
Config: testAccImagesImageV2_visibility_2,
Check: resource.ComposeTestCheckFunc(
testAccCheckImagesImageV2Exists("openstack_images_image_v2.image_1", &image),
resource.TestCheckResourceAttr(
"openstack_images_image_v2.image_1", "visibility", "public"),
),
},
},
})
}
@ -188,7 +266,23 @@ var testAccImagesImageV2_basic = `
disk_format = "qcow2"
}`
var testAccImagesImageV2_with_tags = `
var testAccImagesImageV2_name_1 = `
resource "openstack_images_image_v2" "image_1" {
name = "Rancher TerraformAccTest"
image_source_url = "https://releases.rancher.com/os/latest/rancheros-openstack.img"
container_format = "bare"
disk_format = "qcow2"
}`
var testAccImagesImageV2_name_2 = `
resource "openstack_images_image_v2" "image_1" {
name = "TerraformAccTest Rancher"
image_source_url = "https://releases.rancher.com/os/latest/rancheros-openstack.img"
container_format = "bare"
disk_format = "qcow2"
}`
var testAccImagesImageV2_tags_1 = `
resource "openstack_images_image_v2" "image_1" {
name = "Rancher TerraformAccTest"
image_source_url = "https://releases.rancher.com/os/latest/rancheros-openstack.img"
@ -196,3 +290,39 @@ var testAccImagesImageV2_with_tags = `
disk_format = "qcow2"
tags = ["foo","bar"]
}`
var testAccImagesImageV2_tags_2 = `
resource "openstack_images_image_v2" "image_1" {
name = "Rancher TerraformAccTest"
image_source_url = "https://releases.rancher.com/os/latest/rancheros-openstack.img"
container_format = "bare"
disk_format = "qcow2"
tags = ["foo","bar","baz"]
}`
var testAccImagesImageV2_tags_3 = `
resource "openstack_images_image_v2" "image_1" {
name = "Rancher TerraformAccTest"
image_source_url = "https://releases.rancher.com/os/latest/rancheros-openstack.img"
container_format = "bare"
disk_format = "qcow2"
tags = ["foo","baz"]
}`
var testAccImagesImageV2_visibility_1 = `
resource "openstack_images_image_v2" "image_1" {
name = "Rancher TerraformAccTest"
image_source_url = "https://releases.rancher.com/os/latest/rancheros-openstack.img"
container_format = "bare"
disk_format = "qcow2"
visibility = "private"
}`
var testAccImagesImageV2_visibility_2 = `
resource "openstack_images_image_v2" "image_1" {
name = "Rancher TerraformAccTest"
image_source_url = "https://releases.rancher.com/os/latest/rancheros-openstack.img"
container_format = "bare"
disk_format = "qcow2"
visibility = "public"
}`

View File

@ -35,11 +35,11 @@ The following arguments are supported:
that will be uploaded to Glance. Conflicts with `image_source_url`.
* `image_cache_path` - (Optional) This is the directory where the images will
be downloaded. Images will be stored with a filename corresponding to
be downloaded. Images will be stored with a filename corresponding to
the url's md5 hash. Defaults to "$HOME/.terraform/image_cache"
* `image_source_url` - (Optional) This is the url of the raw image that will
be downloaded in the `image_cache_path` before being uploaded to Glance.
be downloaded in the `image_cache_path` before being uploaded to Glance.
Glance is able to download image from internet but the `gophercloud` library
does not yet provide a way to do so.
Conflicts with `local_file_path`.
@ -49,9 +49,9 @@ The following arguments are supported:
* `min_ram_mb` - (Optional) Amount of ram (in MB) required to boot image.
Defauts to 0.
* `name` - (Required) The name of the image.
* `protected` - (Optional) If true, image will not be deletable.
Defaults to false.
@ -61,9 +61,11 @@ The following arguments are supported:
is used. Changing this creates a new Image.
* `tags` - (Optional) The tags of the image. It must be a list of strings.
* `visibility` - (Optional) The visibility of the image. Must be one of
"public", "private", "community", or "shared".
At this time, it is not possible to delete all tags of an image.
* `visibility` - (Optional) The visibility of the image. Must be one of
"public", "private", "community", or "shared". The ability to set the
visibility depends upon the configuration of the OpenStack cloud.
Note: The `properties` attribute handling in the gophercloud library is currently buggy
and needs to be fixed before being implemented in this resource.
@ -76,8 +78,8 @@ The following attributes are exported:
* `container_format` - See Argument Reference above.
* `created_at` - The date the image was created.
* `disk_format` - See Argument Reference above.
* `file` - the trailing path after the glance
endpoint that represent the location of the image
* `file` - the trailing path after the glance
endpoint that represent the location of the image
or the path to retrieve it.
* `id` - A unique ID assigned by Glance.
* `metadata` - The metadata associated with the image.
@ -89,8 +91,8 @@ The following attributes are exported:
* `owner` - The id of the openstack user who owns the image.
* `protected` - See Argument Reference above.
* `region` - See Argument Reference above.
* `schema` - The path to the JSON-schema that represent
the image or image
* `schema` - The path to the JSON-schema that represent
the image or image
* `size_bytes` - The size in bytes of the data associated with the image.
* `status` - The status of the image. It can be "queued", "active"
or "saving".

View File

@ -49,6 +49,15 @@
</ul>
</li>
<li<%= sidebar_current(/^docs-openstack-resource-images/) %>>
<a href="#">Images Resources</a>
<ul class="nav nav-visible">
<li<%= sidebar_current("docs-openstack-resource-images-image-v2") %>>
<a href="/docs/providers/openstack/r/images_image_v2.html">openstack_images_image_v2</a>
</li>
</ul>
</li>
<li<%= sidebar_current(/^docs-openstack-resource-networking/) %>>
<a href="#">Networking Resources</a>
<ul class="nav nav-visible">