github.com/hashicorp/terraform-plugin-sdk@v1.17.2/helper/acctest/random.go (about)

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