Skip to content

Commit

Permalink
Add minimum character constraints to random_string
Browse files Browse the repository at this point in the history
  • Loading branch information
Payam Hekmat committed Apr 3, 2018
1 parent 71dd304 commit bc19e0b
Show file tree
Hide file tree
Showing 2 changed files with 111 additions and 8 deletions.
83 changes: 75 additions & 8 deletions random/resource_string.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ package random

import (
"crypto/rand"
"math/big"
"sort"

"github.com/hashicorp/errwrap"
"github.com/hashicorp/terraform/helper/schema"
)

Expand Down Expand Up @@ -53,6 +56,34 @@ func resourceString() *schema.Resource {
ForceNew: true,
},

"min_numeric": {
Type: schema.TypeInt,
Optional: true,
Default: 0,
ForceNew: true,
},

"min_upper": {
Type: schema.TypeInt,
Optional: true,
Default: 0,
ForceNew: true,
},

"min_lower": {
Type: schema.TypeInt,
Optional: true,
Default: 0,
ForceNew: true,
},

"min_special": {
Type: schema.TypeInt,
Optional: true,
Default: 0,
ForceNew: true,
},

"override_special": {
Type: schema.TypeString,
Optional: true,
Expand All @@ -75,9 +106,13 @@ func CreateString(d *schema.ResourceData, meta interface{}) error {

length := d.Get("length").(int)
upper := d.Get("upper").(bool)
minUpper := d.Get("min_upper").(int)
lower := d.Get("lower").(bool)
minLower := d.Get("min_lower").(int)
number := d.Get("number").(bool)
minNumeric := d.Get("min_numeric").(int)
special := d.Get("special").(bool)
minSpecial := d.Get("min_special").(int)
overrideSpecial := d.Get("override_special").(string)

if overrideSpecial != "" {
Expand All @@ -98,17 +133,49 @@ func CreateString(d *schema.ResourceData, meta interface{}) error {
chars += specialChars
}

var bytes = make([]byte, length)
var l = byte(len(chars))
minMapping := map[string]int{
numChars: minNumeric,
lowerChars: minLower,
upperChars: minUpper,
specialChars: minSpecial,
}
var result = make([]byte, 0, length)
for k, v := range minMapping {
s, err := generateRandomBytes(&k, v)
if err != nil {
return errwrap.Wrapf("error generating random bytes: {{err}}", err)
}
result = append(result, s...)
}
s, err := generateRandomBytes(&chars, length-len(result))
if err != nil {
return errwrap.Wrapf("error generating random bytes: {{err}}", err)
}
result = append(result, s...)
order := make([]byte, len(result))
if _, err := rand.Read(order); err != nil {
return errwrap.Wrapf("error generating random bytes: {{err}}", err)
}
sort.Slice(result, func(i, j int) bool {
return order[i] < order[j]
})

rand.Read(bytes)
d.Set("result", string(result))
d.SetId(string(result))
return nil
}

for i, b := range bytes {
bytes[i] = chars[b%l]
func generateRandomBytes(charSet *string, length int) ([]byte, error) {
bytes := make([]byte, length)
setLen := big.NewInt(int64(len(*charSet)))
for i := range bytes {
idx, err := rand.Int(rand.Reader, setLen)
if err != nil {
return nil, err
}
bytes[i] = (*charSet)[idx.Int64()]
}
d.Set("result", string(bytes))
d.SetId(string(bytes))
return nil
return bytes, nil
}

func ReadString(d *schema.ResourceData, meta interface{}) error {
Expand Down
36 changes: 36 additions & 0 deletions random/resource_string_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package random

import (
"fmt"
"regexp"
"testing"

"github.com/hashicorp/terraform/helper/resource"
Expand Down Expand Up @@ -30,6 +31,13 @@ func TestAccResourceString(t *testing.T) {
customLen: 4,
}),
patternMatch("random_string.three", "!!!!"),
testAccResourceStringCheck("random_string.min", &customLens{
customLen: 12,
}),
regexMatch("random_string.min", regexp.MustCompile(`([a-z])`), 2),
regexMatch("random_string.min", regexp.MustCompile(`([A-Z])`), 3),
regexMatch("random_string.min", regexp.MustCompile(`([0-9])`), 4),
regexMatch("random_string.min", regexp.MustCompile(`([!#@])`), 1),
),
},
},
Expand All @@ -56,6 +64,25 @@ func testAccResourceStringCheck(id string, want *customLens) resource.TestCheckF
}
}

func regexMatch(id string, exp *regexp.Regexp, requiredMatches int) 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")
}

customStr := rs.Primary.Attributes["result"]

if matches := exp.FindAllStringSubmatchIndex(customStr, -1); len(matches) < requiredMatches {
return fmt.Errorf("custom string is %s; did not match %s", customStr, exp)
}

return nil
}
}
func patternMatch(id string, want string) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[id]
Expand Down Expand Up @@ -93,5 +120,14 @@ resource "random_string" "three" {
number = false
}
resource "random_string" "min" {
length = 12
override_special = "!#@"
min_lower = 2
min_upper = 3
min_special = 1
min_numeric = 4
}
`
)

0 comments on commit bc19e0b

Please sign in to comment.