github.com/terramate-io/tf@v0.0.0-20230830114523-fce866b4dfcd/legacy/helper/acctest/random.go (about) 1 // Copyright (c) HashiCorp, Inc. 2 // SPDX-License-Identifier: MPL-2.0 3 4 package acctest 5 6 import ( 7 "bytes" 8 crand "crypto/rand" 9 "crypto/rsa" 10 "crypto/x509" 11 "crypto/x509/pkix" 12 "encoding/pem" 13 "fmt" 14 "math/big" 15 "math/rand" 16 "net" 17 "strings" 18 "time" 19 20 "golang.org/x/crypto/ssh" 21 22 "github.com/apparentlymart/go-cidr/cidr" 23 ) 24 25 func init() { 26 rand.Seed(time.Now().UTC().UnixNano()) 27 } 28 29 // Helpers for generating random tidbits for use in identifiers to prevent 30 // collisions in acceptance tests. 31 32 // RandInt generates a random integer 33 func RandInt() int { 34 return rand.New(rand.NewSource(time.Now().UnixNano())).Int() 35 } 36 37 // RandomWithPrefix is used to generate a unique name with a prefix, for 38 // randomizing names in acceptance tests 39 func RandomWithPrefix(name string) string { 40 return fmt.Sprintf("%s-%d", name, rand.New(rand.NewSource(time.Now().UnixNano())).Int()) 41 } 42 43 func RandIntRange(min int, max int) int { 44 source := rand.New(rand.NewSource(time.Now().UnixNano())) 45 rangeMax := max - min 46 47 return int(source.Int31n(int32(rangeMax))) 48 } 49 50 // RandString generates a random alphanumeric string of the length specified 51 func RandString(strlen int) string { 52 return RandStringFromCharSet(strlen, CharSetAlphaNum) 53 } 54 55 // RandStringFromCharSet generates a random string by selecting characters from 56 // the charset provided 57 func RandStringFromCharSet(strlen int, charSet string) string { 58 result := make([]byte, strlen) 59 for i := 0; i < strlen; i++ { 60 result[i] = charSet[rand.Intn(len(charSet))] 61 } 62 return string(result) 63 } 64 65 // RandSSHKeyPair generates a public and private SSH key pair. The public key is 66 // returned in OpenSSH format, and the private key is PEM encoded. 67 func RandSSHKeyPair(comment string) (string, string, error) { 68 privateKey, privateKeyPEM, err := genPrivateKey() 69 if err != nil { 70 return "", "", err 71 } 72 73 publicKey, err := ssh.NewPublicKey(&privateKey.PublicKey) 74 if err != nil { 75 return "", "", err 76 } 77 keyMaterial := strings.TrimSpace(string(ssh.MarshalAuthorizedKey(publicKey))) 78 return fmt.Sprintf("%s %s", keyMaterial, comment), privateKeyPEM, nil 79 } 80 81 // RandTLSCert generates a self-signed TLS certificate with a newly created 82 // private key, and returns both the cert and the private key PEM encoded. 83 func RandTLSCert(orgName string) (string, string, error) { 84 template := &x509.Certificate{ 85 SerialNumber: big.NewInt(int64(RandInt())), 86 Subject: pkix.Name{ 87 Organization: []string{orgName}, 88 }, 89 NotBefore: time.Now(), 90 NotAfter: time.Now().Add(24 * time.Hour), 91 KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, 92 ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, 93 BasicConstraintsValid: true, 94 } 95 96 privateKey, privateKeyPEM, err := genPrivateKey() 97 if err != nil { 98 return "", "", err 99 } 100 101 cert, err := x509.CreateCertificate(crand.Reader, template, template, &privateKey.PublicKey, privateKey) 102 if err != nil { 103 return "", "", err 104 } 105 106 certPEM, err := pemEncode(cert, "CERTIFICATE") 107 if err != nil { 108 return "", "", err 109 } 110 111 return certPEM, privateKeyPEM, nil 112 } 113 114 // RandIpAddress returns a random IP address in the specified CIDR block. 115 // The prefix length must be less than 31. 116 func RandIpAddress(s string) (string, error) { 117 _, network, err := net.ParseCIDR(s) 118 if err != nil { 119 return "", err 120 } 121 122 firstIp, lastIp := cidr.AddressRange(network) 123 first := &big.Int{} 124 first.SetBytes([]byte(firstIp)) 125 last := &big.Int{} 126 last.SetBytes([]byte(lastIp)) 127 r := &big.Int{} 128 r.Sub(last, first) 129 if len := r.BitLen(); len > 31 { 130 return "", fmt.Errorf("CIDR range is too large: %d", len) 131 } 132 133 max := int(r.Int64()) 134 if max == 0 { 135 // panic: invalid argument to Int31n 136 return firstIp.String(), nil 137 } 138 139 host, err := cidr.Host(network, RandIntRange(0, max)) 140 if err != nil { 141 return "", err 142 } 143 144 return host.String(), nil 145 } 146 147 func genPrivateKey() (*rsa.PrivateKey, string, error) { 148 privateKey, err := rsa.GenerateKey(crand.Reader, 1024) 149 if err != nil { 150 return nil, "", err 151 } 152 153 privateKeyPEM, err := pemEncode(x509.MarshalPKCS1PrivateKey(privateKey), "RSA PRIVATE KEY") 154 if err != nil { 155 return nil, "", err 156 } 157 158 return privateKey, privateKeyPEM, nil 159 } 160 161 func pemEncode(b []byte, block string) (string, error) { 162 var buf bytes.Buffer 163 pb := &pem.Block{Type: block, Bytes: b} 164 if err := pem.Encode(&buf, pb); err != nil { 165 return "", err 166 } 167 168 return buf.String(), nil 169 } 170 171 const ( 172 // CharSetAlphaNum is the alphanumeric character set for use with 173 // RandStringFromCharSet 174 CharSetAlphaNum = "abcdefghijklmnopqrstuvwxyz012346789" 175 176 // CharSetAlpha is the alphabetical character set for use with 177 // RandStringFromCharSet 178 CharSetAlpha = "abcdefghijklmnopqrstuvwxyz" 179 )