provider/random: random_shuffle resource
random_shuffle takes a list of strings and returns a new list with the same items in a random permutation. Optionally allows the result list to be a different length than the input list. A shorter result than input results in some items being excluded. A longer result than input results in some items being repeated, but never more often than the number of input items.
This commit is contained in:
parent
b1de477691
commit
eec6c88fd2
|
@ -12,7 +12,7 @@ func Provider() terraform.ResourceProvider {
|
|||
|
||||
ResourcesMap: map[string]*schema.Resource{
|
||||
"random_id": resourceId(),
|
||||
//"random_shuffle": resourceShuffle(),
|
||||
"random_shuffle": resourceShuffle(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
package random
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
)
|
||||
|
||||
func resourceShuffle() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: CreateShuffle,
|
||||
Read: stubRead,
|
||||
Delete: stubDelete,
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"keepers": &schema.Schema{
|
||||
Type: schema.TypeMap,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"seed": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"input": &schema.Schema{
|
||||
Type: schema.TypeList,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
Elem: &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
},
|
||||
},
|
||||
|
||||
"result": &schema.Schema{
|
||||
Type: schema.TypeList,
|
||||
Computed: true,
|
||||
Elem: &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
},
|
||||
},
|
||||
|
||||
"result_count": &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func CreateShuffle(d *schema.ResourceData, meta interface{}) error {
|
||||
input := d.Get("input").([]interface{})
|
||||
seed := d.Get("seed").(string)
|
||||
|
||||
resultCount := d.Get("result_count").(int)
|
||||
if resultCount == 0 {
|
||||
resultCount = len(input)
|
||||
}
|
||||
result := make([]interface{}, 0, resultCount)
|
||||
|
||||
rand := NewRand(seed)
|
||||
|
||||
// Keep producing permutations until we fill our result
|
||||
Batches:
|
||||
for {
|
||||
perm := rand.Perm(len(input))
|
||||
|
||||
for _, i := range perm {
|
||||
result = append(result, input[i])
|
||||
|
||||
if len(result) >= resultCount {
|
||||
break Batches
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
d.SetId("-")
|
||||
d.Set("result", result)
|
||||
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
package random
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
)
|
||||
|
||||
func TestAccResourceShuffle(t *testing.T) {
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccResourceShuffleConfig,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
// These results are current as of Go 1.6. The Go
|
||||
// "rand" package does not guarantee that the random
|
||||
// number generator will generate the same results
|
||||
// forever, but the maintainers endeavor not to change
|
||||
// it gratuitously.
|
||||
// These tests allow us to detect such changes and
|
||||
// document them when they arise, but the docs for this
|
||||
// resource specifically warn that results are not
|
||||
// guaranteed consistent across Terraform releases.
|
||||
testAccResourceShuffleCheck(
|
||||
"random_shuffle.default_length",
|
||||
[]string{"a", "c", "b", "e", "d"},
|
||||
),
|
||||
testAccResourceShuffleCheck(
|
||||
"random_shuffle.shorter_length",
|
||||
[]string{"a", "c", "b"},
|
||||
),
|
||||
testAccResourceShuffleCheck(
|
||||
"random_shuffle.longer_length",
|
||||
[]string{"a", "c", "b", "e", "d", "a", "e", "d", "c", "b", "a", "b"},
|
||||
),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccResourceShuffleCheck(id string, wants []string) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
rs, ok := s.RootModule().Resources[id]
|
||||
if !ok {
|
||||
return fmt.Errorf("Not found: %s", id)
|
||||
}
|
||||
if rs.Primary.ID == "" {
|
||||
return fmt.Errorf("No ID is set")
|
||||
}
|
||||
|
||||
attrs := rs.Primary.Attributes
|
||||
|
||||
gotLen := attrs["result.#"]
|
||||
wantLen := strconv.Itoa(len(wants))
|
||||
if gotLen != wantLen {
|
||||
return fmt.Errorf("got %s result items; want %s", gotLen, wantLen)
|
||||
}
|
||||
|
||||
for i, want := range wants {
|
||||
key := fmt.Sprintf("result.%d", i)
|
||||
if got := attrs[key]; got != want {
|
||||
return fmt.Errorf("index %d is %q; want %q", i, got, want)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
const testAccResourceShuffleConfig = `
|
||||
resource "random_shuffle" "default_length" {
|
||||
input = ["a", "b", "c", "d", "e"]
|
||||
seed = "-"
|
||||
}
|
||||
resource "random_shuffle" "shorter_length" {
|
||||
input = ["a", "b", "c", "d", "e"]
|
||||
seed = "-"
|
||||
result_count = 3
|
||||
}
|
||||
resource "random_shuffle" "longer_length" {
|
||||
input = ["a", "b", "c", "d", "e"]
|
||||
seed = "-"
|
||||
result_count = 12
|
||||
}
|
||||
`
|
|
@ -0,0 +1,24 @@
|
|||
package random
|
||||
|
||||
import (
|
||||
"hash/crc64"
|
||||
"math/rand"
|
||||
"time"
|
||||
)
|
||||
|
||||
// NewRand returns a seeded random number generator, using a seed derived
|
||||
// from the provided string.
|
||||
//
|
||||
// If the seed string is empty, the current time is used as a seed.
|
||||
func NewRand(seed string) *rand.Rand {
|
||||
var seedInt int64
|
||||
if seed != "" {
|
||||
crcTable := crc64.MakeTable(crc64.ISO)
|
||||
seedInt = int64(crc64.Checksum([]byte(seed), crcTable))
|
||||
} else {
|
||||
seedInt = time.Now().Unix()
|
||||
}
|
||||
|
||||
randSource := rand.NewSource(seedInt)
|
||||
return rand.New(randSource)
|
||||
}
|
Loading…
Reference in New Issue