Skip to content

Commit b1de477

Browse files
provider/random: random_id resource
This resource generates a cryptographically-strong set of bytes and provides them as base64, hexadecimal and decimal string representations. It is intended to be used for generating unique ids for resources elsewhere in the configuration, and thus the "keepers" would be set to any ForceNew attributes of the target resources, so that a new id is generated each time a new resource is generated.
1 parent 3e34ddb commit b1de477

3 files changed

Lines changed: 135 additions & 1 deletion

File tree

builtin/providers/random/provider.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ func Provider() terraform.ResourceProvider {
1111
Schema: map[string]*schema.Schema{},
1212

1313
ResourcesMap: map[string]*schema.Resource{
14-
//"random_id": resourceId(),
14+
"random_id": resourceId(),
1515
//"random_shuffle": resourceShuffle(),
1616
},
1717
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package random
2+
3+
import (
4+
"crypto/rand"
5+
"encoding/base64"
6+
"encoding/hex"
7+
"fmt"
8+
"math/big"
9+
10+
"github.com/hashicorp/terraform/helper/schema"
11+
)
12+
13+
func resourceId() *schema.Resource {
14+
return &schema.Resource{
15+
Create: CreateID,
16+
Read: stubRead,
17+
Delete: stubDelete,
18+
19+
Schema: map[string]*schema.Schema{
20+
"keepers": &schema.Schema{
21+
Type: schema.TypeMap,
22+
Optional: true,
23+
ForceNew: true,
24+
},
25+
26+
"byte_length": &schema.Schema{
27+
Type: schema.TypeInt,
28+
Required: true,
29+
ForceNew: true,
30+
},
31+
32+
"b64": &schema.Schema{
33+
Type: schema.TypeString,
34+
Computed: true,
35+
},
36+
37+
"hex": &schema.Schema{
38+
Type: schema.TypeString,
39+
Computed: true,
40+
},
41+
42+
"dec": &schema.Schema{
43+
Type: schema.TypeString,
44+
Computed: true,
45+
},
46+
},
47+
}
48+
}
49+
50+
func CreateID(d *schema.ResourceData, meta interface{}) error {
51+
52+
byteLength := d.Get("byte_length").(int)
53+
bytes := make([]byte, byteLength)
54+
55+
n, err := rand.Reader.Read(bytes)
56+
if n != byteLength {
57+
return fmt.Errorf("generated insufficient random bytes")
58+
}
59+
if err != nil {
60+
return fmt.Errorf("error generating random bytes: %s", err)
61+
}
62+
63+
b64Str := base64.RawURLEncoding.EncodeToString(bytes)
64+
hexStr := hex.EncodeToString(bytes)
65+
66+
int := big.Int{}
67+
int.SetBytes(bytes)
68+
decStr := int.String()
69+
70+
d.SetId(b64Str)
71+
d.Set("b64", b64Str)
72+
d.Set("hex", hexStr)
73+
d.Set("dec", decStr)
74+
75+
return nil
76+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package random
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
7+
"github.com/hashicorp/terraform/helper/resource"
8+
"github.com/hashicorp/terraform/terraform"
9+
)
10+
11+
func TestAccResourceID(t *testing.T) {
12+
resource.Test(t, resource.TestCase{
13+
PreCheck: func() { testAccPreCheck(t) },
14+
Providers: testAccProviders,
15+
Steps: []resource.TestStep{
16+
resource.TestStep{
17+
Config: testAccResourceIDConfig,
18+
Check: resource.ComposeTestCheckFunc(
19+
testAccResourceIDCheck("random_id.foo"),
20+
),
21+
},
22+
},
23+
})
24+
}
25+
26+
func testAccResourceIDCheck(id string) resource.TestCheckFunc {
27+
return func(s *terraform.State) error {
28+
rs, ok := s.RootModule().Resources[id]
29+
if !ok {
30+
return fmt.Errorf("Not found: %s", id)
31+
}
32+
if rs.Primary.ID == "" {
33+
return fmt.Errorf("No ID is set")
34+
}
35+
36+
b64Str := rs.Primary.Attributes["b64"]
37+
hexStr := rs.Primary.Attributes["hex"]
38+
decStr := rs.Primary.Attributes["dec"]
39+
40+
if got, want := len(b64Str), 6; got != want {
41+
return fmt.Errorf("base64 string length is %d; want %d", got, want)
42+
}
43+
if got, want := len(hexStr), 8; got != want {
44+
return fmt.Errorf("hex string length is %d; want %d", got, want)
45+
}
46+
if len(decStr) < 1 {
47+
return fmt.Errorf("decimal string is empty; want at least one digit")
48+
}
49+
50+
return nil
51+
}
52+
}
53+
54+
const testAccResourceIDConfig = `
55+
resource "random_id" "foo" {
56+
byte_length = 4
57+
}
58+
`

0 commit comments

Comments
 (0)