mirror of
https://github.com/opentofu/opentofu.git
synced 2025-02-25 18:45:20 -06:00
Add DigitalOcean datasource digitalocean_image (#13787)
Add a new data source for Digital Ocean that finds snapshots by name. Signed-off-by: Julien Pivotto <roidelapluie@inuits.eu>
This commit is contained in:
parent
be0390e561
commit
c2a1e688cb
@ -0,0 +1,93 @@
|
|||||||
|
package digitalocean
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/digitalocean/godo"
|
||||||
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func dataSourceDigitalOceanImage() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
Read: dataSourceDigitalOceanImageRead,
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
|
||||||
|
"name": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
Description: "name of the image",
|
||||||
|
},
|
||||||
|
// computed attributes
|
||||||
|
"image": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "slug or id of the image",
|
||||||
|
},
|
||||||
|
"min_disk_size": &schema.Schema{
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Computed: true,
|
||||||
|
Description: "minimum disk size required by the image",
|
||||||
|
},
|
||||||
|
"private": &schema.Schema{
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Is the image private or non-private",
|
||||||
|
},
|
||||||
|
"regions": &schema.Schema{
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Computed: true,
|
||||||
|
Description: "list of the regions that the image is available in",
|
||||||
|
Elem: &schema.Schema{Type: schema.TypeString},
|
||||||
|
},
|
||||||
|
"type": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "type of the image",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSourceDigitalOceanImageRead(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
client := meta.(*godo.Client)
|
||||||
|
|
||||||
|
opts := &godo.ListOptions{}
|
||||||
|
|
||||||
|
images, _, err := client.Images.ListUser(opts)
|
||||||
|
if err != nil {
|
||||||
|
d.SetId("")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
image, err := findImageByName(images, d.Get("name").(string))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
d.SetId(image.Name)
|
||||||
|
d.Set("name", image.Name)
|
||||||
|
d.Set("image", strconv.Itoa(image.ID))
|
||||||
|
d.Set("min_disk_size", image.MinDiskSize)
|
||||||
|
d.Set("private", !image.Public)
|
||||||
|
d.Set("regions", image.Regions)
|
||||||
|
d.Set("type", image.Type)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func findImageByName(images []godo.Image, name string) (*godo.Image, error) {
|
||||||
|
results := make([]godo.Image, 0)
|
||||||
|
for _, v := range images {
|
||||||
|
if v.Name == name {
|
||||||
|
results = append(results, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(results) == 1 {
|
||||||
|
return &results[0], nil
|
||||||
|
}
|
||||||
|
if len(results) == 0 {
|
||||||
|
return nil, fmt.Errorf("no user image found with name %s", name)
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("too many user images found with name %s (found %d, expected 1)", name, len(results))
|
||||||
|
}
|
@ -0,0 +1,122 @@
|
|||||||
|
package digitalocean
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"regexp"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/digitalocean/godo"
|
||||||
|
"github.com/hashicorp/terraform/helper/acctest"
|
||||||
|
"github.com/hashicorp/terraform/helper/resource"
|
||||||
|
"github.com/hashicorp/terraform/terraform"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAccDigitalOceanImage_Basic(t *testing.T) {
|
||||||
|
var droplet godo.Droplet
|
||||||
|
var snapshotsId []int
|
||||||
|
rInt := acctest.RandInt()
|
||||||
|
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
Providers: testAccProviders,
|
||||||
|
CheckDestroy: testAccCheckDigitalOceanDropletDestroy,
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
{
|
||||||
|
Config: testAccCheckDigitalOceanDropletConfig_basic(rInt),
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccCheckDigitalOceanDropletExists("digitalocean_droplet.foobar", &droplet),
|
||||||
|
takeSnapshotsOfDroplet(rInt, &droplet, &snapshotsId),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Config: testAccCheckDigitalOceanImageConfig_basic(rInt, 1),
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
resource.TestCheckResourceAttr(
|
||||||
|
"data.digitalocean_image.foobar", "name", fmt.Sprintf("snap-%d-1", rInt)),
|
||||||
|
resource.TestCheckResourceAttr(
|
||||||
|
"data.digitalocean_image.foobar", "min_disk_size", "20"),
|
||||||
|
resource.TestCheckResourceAttr(
|
||||||
|
"data.digitalocean_image.foobar", "private", "true"),
|
||||||
|
resource.TestCheckResourceAttr(
|
||||||
|
"data.digitalocean_image.foobar", "type", "snapshot"),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Config: testAccCheckDigitalOceanImageConfig_basic(rInt, 0),
|
||||||
|
ExpectError: regexp.MustCompile(`.*too many user images found with name snap-.*\ .found 2, expected 1.`),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Config: testAccCheckDigitalOceanImageConfig_nonexisting(rInt),
|
||||||
|
Destroy: false,
|
||||||
|
ExpectError: regexp.MustCompile(`.*no user image found with name snap-.*-nonexisting`),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Config: " ",
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
deleteSnapshots(&snapshotsId),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func takeSnapshotsOfDroplet(rInt int, droplet *godo.Droplet, snapshotsId *[]int) resource.TestCheckFunc {
|
||||||
|
return func(s *terraform.State) error {
|
||||||
|
client := testAccProvider.Meta().(*godo.Client)
|
||||||
|
for i := 0; i < 3; i++ {
|
||||||
|
err := takeSnapshotOfDroplet(rInt, i%2, droplet)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
retrieveDroplet, _, err := client.Droplets.Get((*droplet).ID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*snapshotsId = retrieveDroplet.SnapshotIDs
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func takeSnapshotOfDroplet(rInt, sInt int, droplet *godo.Droplet) error {
|
||||||
|
client := testAccProvider.Meta().(*godo.Client)
|
||||||
|
action, _, err := client.DropletActions.Snapshot((*droplet).ID, fmt.Sprintf("snap-%d-%d", rInt, sInt))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
waitForAction(client, action)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteSnapshots(snapshotsId *[]int) resource.TestCheckFunc {
|
||||||
|
return func(s *terraform.State) error {
|
||||||
|
log.Printf("XXX Deleting snaps")
|
||||||
|
client := testAccProvider.Meta().(*godo.Client)
|
||||||
|
snapshots := *snapshotsId
|
||||||
|
for _, value := range snapshots {
|
||||||
|
log.Printf("XXX Deleting %d", value)
|
||||||
|
_, err := client.Images.Delete(value)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccCheckDigitalOceanImageConfig_basic(rInt, sInt int) string {
|
||||||
|
return fmt.Sprintf(`
|
||||||
|
data "digitalocean_image" "foobar" {
|
||||||
|
name = "snap-%d-%d"
|
||||||
|
}
|
||||||
|
`, rInt, sInt)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccCheckDigitalOceanImageConfig_nonexisting(rInt int) string {
|
||||||
|
return fmt.Sprintf(`
|
||||||
|
data "digitalocean_image" "foobar" {
|
||||||
|
name = "snap-%d-nonexisting"
|
||||||
|
}
|
||||||
|
`, rInt)
|
||||||
|
}
|
@ -17,6 +17,10 @@ func Provider() terraform.ResourceProvider {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
DataSourcesMap: map[string]*schema.Resource{
|
||||||
|
"digitalocean_image": dataSourceDigitalOceanImage(),
|
||||||
|
},
|
||||||
|
|
||||||
ResourcesMap: map[string]*schema.Resource{
|
ResourcesMap: map[string]*schema.Resource{
|
||||||
"digitalocean_domain": resourceDigitalOceanDomain(),
|
"digitalocean_domain": resourceDigitalOceanDomain(),
|
||||||
"digitalocean_droplet": resourceDigitalOceanDroplet(),
|
"digitalocean_droplet": resourceDigitalOceanDroplet(),
|
||||||
|
58
website/source/docs/providers/do/d/image.html.md
Normal file
58
website/source/docs/providers/do/d/image.html.md
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
---
|
||||||
|
layout: "digitalocean"
|
||||||
|
page_title: "DigitalOcean: digitalocean_image"
|
||||||
|
sidebar_current: "docs-do-datasource-image"
|
||||||
|
description: |-
|
||||||
|
Get information on an snapshot.
|
||||||
|
---
|
||||||
|
|
||||||
|
# digitalocean_image
|
||||||
|
|
||||||
|
Get information on an snapshot images. The aim of this datasource is to enable
|
||||||
|
you to build droplets based on snapshot names.
|
||||||
|
|
||||||
|
An error is triggered if zero or more than one result is returned by the query.
|
||||||
|
|
||||||
|
## Example Usage
|
||||||
|
|
||||||
|
Get the data about a snapshot:
|
||||||
|
|
||||||
|
```hcl
|
||||||
|
data "digitalocean_image" "example1" {
|
||||||
|
name = "example-1.0.0"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Reuse the data about a snapshot to create a droplet:
|
||||||
|
|
||||||
|
```hcl
|
||||||
|
data "digitalocean_image" "example1" {
|
||||||
|
name = "example-1.0.0"
|
||||||
|
}
|
||||||
|
resource "digitalocean_droplet" "example1" {
|
||||||
|
image = "${data.digitalocean_image.example1.image}"
|
||||||
|
name = "example-1"
|
||||||
|
region = "nyc2"
|
||||||
|
size = "512mb"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Argument Reference
|
||||||
|
|
||||||
|
The following arguments are supported:
|
||||||
|
|
||||||
|
* `name` - The name of the image.
|
||||||
|
|
||||||
|
## Attributes Reference
|
||||||
|
|
||||||
|
The following attributes are exported:
|
||||||
|
|
||||||
|
* `name` - See Argument Reference above.
|
||||||
|
* `image` - The id of the image.
|
||||||
|
* `min_disk_size`: The minimum 'disk' required for the image.
|
||||||
|
* `private` - Is image a public image or not. Public images represents
|
||||||
|
Linux distributions or Application, while non-public images represent
|
||||||
|
snapshots and backups and are only available within your account.
|
||||||
|
* `regions`: The regions that the image is available in.
|
||||||
|
* `size_gigabytes`: The size of the image in gigabytes.
|
||||||
|
* `type`: Type of the image. Can be "snapshot" or "backup".
|
Loading…
Reference in New Issue
Block a user