Merge pull request #12096 from jtopjian/openstack-image-updates

provider/openstack: Updates to openstack_images_image_v2 resource
This commit is contained in:
Joe Topjian 2017-02-19 14:34:36 -07:00 committed by GitHub
commit b25b6078b4
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) { func TestProvider(t *testing.T) {
if err := Provider().(*schema.Provider).InternalValidate(); err != nil { if err := Provider().(*schema.Provider).InternalValidate(); err != nil {
t.Fatalf("err: %s", err) t.Fatalf("err: %s", err)

View File

@ -141,9 +141,10 @@ func resourceImagesImageV2() *schema.Resource {
}, },
"tags": &schema.Schema{ "tags": &schema.Schema{
Type: schema.TypeList, Type: schema.TypeSet,
Optional: true, Optional: true,
Elem: &schema.Schema{Type: schema.TypeString}, Elem: &schema.Schema{Type: schema.TypeString},
Set: schema.HashString,
}, },
"update_at": &schema.Schema{ "update_at": &schema.Schema{
@ -156,7 +157,7 @@ func resourceImagesImageV2() *schema.Resource {
Optional: true, Optional: true,
ForceNew: false, ForceNew: false,
ValidateFunc: resourceImagesImageV2ValidateVisibility, 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 { if v, ok := d.GetOk("tags"); ok {
var tags []string tags := v.(*schema.Set).List()
for _, tag := range v.([]interface{}) { createOpts.Tags = resourceImagesImageV2BuildTags(tags)
tags = append(tags, tag.(string))
}
createOpts.Tags = tags
} }
d.Partial(true) d.Partial(true)
@ -273,9 +271,8 @@ func resourceImagesImageV2Read(d *schema.ResourceData, meta interface{}) error {
d.Set("name", img.Name) d.Set("name", img.Name)
d.Set("protected", img.Protected) d.Set("protected", img.Protected)
d.Set("size_bytes", img.SizeBytes) d.Set("size_bytes", img.SizeBytes)
d.Set("tags", resourceImagesImageV2RemoveEmptyTags(img.Tags)) d.Set("tags", img.Tags)
d.Set("visibility", img.Visibility) d.Set("visibility", img.Visibility)
return nil return nil
} }
@ -289,7 +286,8 @@ func resourceImagesImageV2Update(d *schema.ResourceData, meta interface{}) error
updateOpts := make(images.UpdateOpts, 0) updateOpts := make(images.UpdateOpts, 0)
if d.HasChange("visibility") { 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) updateOpts = append(updateOpts, v)
} }
@ -299,7 +297,10 @@ func resourceImagesImageV2Update(d *schema.ResourceData, meta interface{}) error
} }
if d.HasChange("tags") { 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) 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) { func resourceImagesImageV2ValidateVisibility(v interface{}, k string) (ws []string, errors []error) {
value := v.(images.ImageVisibility) value := v.(string)
if value == images.ImageVisibilityPublic || value == images.ImageVisibilityPrivate || value == images.ImageVisibilityShared || value == images.ImageVisibilityCommunity { validVisibilities := []string{
return "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 return
} }
@ -476,12 +487,11 @@ func resourceImagesImageV2RefreshFunc(client *gophercloud.ServiceClient, id stri
} }
} }
func resourceImagesImageV2RemoveEmptyTags(s []string) []string { func resourceImagesImageV2BuildTags(v []interface{}) []string {
var r []string var tags []string
for _, str := range s { for _, tag := range v {
if str != "" { tags = append(tags, tag.(string))
r = append(r, str)
}
} }
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 var image images.Image
resource.Test(t, resource.TestCase{ resource.Test(t, resource.TestCase{
@ -45,7 +45,35 @@ func TestAccImagesImageV2_with_tags(t *testing.T) {
CheckDestroy: testAccCheckImagesImageV2Destroy, CheckDestroy: testAccCheckImagesImageV2Destroy,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
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( Check: resource.ComposeTestCheckFunc(
testAccCheckImagesImageV2Exists("openstack_images_image_v2.image_1", &image), testAccCheckImagesImageV2Exists("openstack_images_image_v2.image_1", &image),
testAccCheckImagesImageV2HasTag("openstack_images_image_v2.image_1", "foo"), 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), 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" 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" { resource "openstack_images_image_v2" "image_1" {
name = "Rancher TerraformAccTest" name = "Rancher TerraformAccTest"
image_source_url = "https://releases.rancher.com/os/latest/rancheros-openstack.img" image_source_url = "https://releases.rancher.com/os/latest/rancheros-openstack.img"
@ -196,3 +290,39 @@ var testAccImagesImageV2_with_tags = `
disk_format = "qcow2" disk_format = "qcow2"
tags = ["foo","bar"] 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`. that will be uploaded to Glance. Conflicts with `image_source_url`.
* `image_cache_path` - (Optional) This is the directory where the images will * `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" 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 * `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 Glance is able to download image from internet but the `gophercloud` library
does not yet provide a way to do so. does not yet provide a way to do so.
Conflicts with `local_file_path`. 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. * `min_ram_mb` - (Optional) Amount of ram (in MB) required to boot image.
Defauts to 0. Defauts to 0.
* `name` - (Required) The name of the image. * `name` - (Required) The name of the image.
* `protected` - (Optional) If true, image will not be deletable. * `protected` - (Optional) If true, image will not be deletable.
Defaults to false. Defaults to false.
@ -61,9 +61,11 @@ The following arguments are supported:
is used. Changing this creates a new Image. is used. Changing this creates a new Image.
* `tags` - (Optional) The tags of the image. It must be a list of strings. * `tags` - (Optional) The tags of the image. It must be a list of strings.
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". * `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 Note: The `properties` attribute handling in the gophercloud library is currently buggy
and needs to be fixed before being implemented in this resource. 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. * `container_format` - See Argument Reference above.
* `created_at` - The date the image was created. * `created_at` - The date the image was created.
* `disk_format` - See Argument Reference above. * `disk_format` - See Argument Reference above.
* `file` - the trailing path after the glance * `file` - the trailing path after the glance
endpoint that represent the location of the image endpoint that represent the location of the image
or the path to retrieve it. or the path to retrieve it.
* `id` - A unique ID assigned by Glance. * `id` - A unique ID assigned by Glance.
* `metadata` - The metadata associated with the image. * `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. * `owner` - The id of the openstack user who owns the image.
* `protected` - See Argument Reference above. * `protected` - See Argument Reference above.
* `region` - See Argument Reference above. * `region` - See Argument Reference above.
* `schema` - The path to the JSON-schema that represent * `schema` - The path to the JSON-schema that represent
the image or image the image or image
* `size_bytes` - The size in bytes of the data associated with the 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" * `status` - The status of the image. It can be "queued", "active"
or "saving". or "saving".

View File

@ -49,6 +49,15 @@
</ul> </ul>
</li> </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/) %>> <li<%= sidebar_current(/^docs-openstack-resource-networking/) %>>
<a href="#">Networking Resources</a> <a href="#">Networking Resources</a>
<ul class="nav nav-visible"> <ul class="nav nav-visible">