| package acctest |
| |
| import ( |
| "bytes" |
| crand "crypto/rand" |
| "crypto/rsa" |
| "crypto/x509" |
| "crypto/x509/pkix" |
| "encoding/pem" |
| "fmt" |
| "math/big" |
| "math/rand" |
| "net" |
| "strings" |
| "time" |
| |
| "golang.org/x/crypto/ssh" |
| |
| "github.com/apparentlymart/go-cidr/cidr" |
| ) |
| |
| func init() { |
| rand.Seed(time.Now().UTC().UnixNano()) |
| } |
| |
| // Helpers for generating random tidbits for use in identifiers to prevent |
| // collisions in acceptance tests. |
| |
| // RandInt generates a random integer |
| func RandInt() int { |
| return rand.New(rand.NewSource(time.Now().UnixNano())).Int() |
| } |
| |
| // RandomWithPrefix is used to generate a unique name with a prefix, for |
| // randomizing names in acceptance tests |
| func RandomWithPrefix(name string) string { |
| return fmt.Sprintf("%s-%d", name, rand.New(rand.NewSource(time.Now().UnixNano())).Int()) |
| } |
| |
| func RandIntRange(min int, max int) int { |
| source := rand.New(rand.NewSource(time.Now().UnixNano())) |
| rangeMax := max - min |
| |
| return int(source.Int31n(int32(rangeMax))) |
| } |
| |
| // RandString generates a random alphanumeric string of the length specified |
| func RandString(strlen int) string { |
| return RandStringFromCharSet(strlen, CharSetAlphaNum) |
| } |
| |
| // RandStringFromCharSet generates a random string by selecting characters from |
| // the charset provided |
| func RandStringFromCharSet(strlen int, charSet string) string { |
| result := make([]byte, strlen) |
| for i := 0; i < strlen; i++ { |
| result[i] = charSet[rand.Intn(len(charSet))] |
| } |
| return string(result) |
| } |
| |
| // RandSSHKeyPair generates a public and private SSH key pair. The public key is |
| // returned in OpenSSH format, and the private key is PEM encoded. |
| func RandSSHKeyPair(comment string) (string, string, error) { |
| privateKey, privateKeyPEM, err := genPrivateKey() |
| if err != nil { |
| return "", "", err |
| } |
| |
| publicKey, err := ssh.NewPublicKey(&privateKey.PublicKey) |
| if err != nil { |
| return "", "", err |
| } |
| keyMaterial := strings.TrimSpace(string(ssh.MarshalAuthorizedKey(publicKey))) |
| return fmt.Sprintf("%s %s", keyMaterial, comment), privateKeyPEM, nil |
| } |
| |
| // RandTLSCert generates a self-signed TLS certificate with a newly created |
| // private key, and returns both the cert and the private key PEM encoded. |
| func RandTLSCert(orgName string) (string, string, error) { |
| template := &x509.Certificate{ |
| SerialNumber: big.NewInt(int64(RandInt())), |
| Subject: pkix.Name{ |
| Organization: []string{orgName}, |
| }, |
| NotBefore: time.Now(), |
| NotAfter: time.Now().Add(24 * time.Hour), |
| KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, |
| ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, |
| BasicConstraintsValid: true, |
| } |
| |
| privateKey, privateKeyPEM, err := genPrivateKey() |
| if err != nil { |
| return "", "", err |
| } |
| |
| cert, err := x509.CreateCertificate(crand.Reader, template, template, &privateKey.PublicKey, privateKey) |
| if err != nil { |
| return "", "", err |
| } |
| |
| certPEM, err := pemEncode(cert, "CERTIFICATE") |
| if err != nil { |
| return "", "", err |
| } |
| |
| return certPEM, privateKeyPEM, nil |
| } |
| |
| // RandIpAddress returns a random IP address in the specified CIDR block. |
| // The prefix length must be less than 31. |
| func RandIpAddress(s string) (string, error) { |
| _, network, err := net.ParseCIDR(s) |
| if err != nil { |
| return "", err |
| } |
| |
| firstIp, lastIp := cidr.AddressRange(network) |
| first := &big.Int{} |
| first.SetBytes([]byte(firstIp)) |
| last := &big.Int{} |
| last.SetBytes([]byte(lastIp)) |
| r := &big.Int{} |
| r.Sub(last, first) |
| if len := r.BitLen(); len > 31 { |
| return "", fmt.Errorf("CIDR range is too large: %d", len) |
| } |
| |
| max := int(r.Int64()) |
| if max == 0 { |
| // panic: invalid argument to Int31n |
| return firstIp.String(), nil |
| } |
| |
| host, err := cidr.Host(network, RandIntRange(0, max)) |
| if err != nil { |
| return "", err |
| } |
| |
| return host.String(), nil |
| } |
| |
| func genPrivateKey() (*rsa.PrivateKey, string, error) { |
| privateKey, err := rsa.GenerateKey(crand.Reader, 1024) |
| if err != nil { |
| return nil, "", err |
| } |
| |
| privateKeyPEM, err := pemEncode(x509.MarshalPKCS1PrivateKey(privateKey), "RSA PRIVATE KEY") |
| if err != nil { |
| return nil, "", err |
| } |
| |
| return privateKey, privateKeyPEM, nil |
| } |
| |
| func pemEncode(b []byte, block string) (string, error) { |
| var buf bytes.Buffer |
| pb := &pem.Block{Type: block, Bytes: b} |
| if err := pem.Encode(&buf, pb); err != nil { |
| return "", err |
| } |
| |
| return buf.String(), nil |
| } |
| |
| const ( |
| // CharSetAlphaNum is the alphanumeric character set for use with |
| // RandStringFromCharSet |
| CharSetAlphaNum = "abcdefghijklmnopqrstuvwxyz012346789" |
| |
| // CharSetAlpha is the alphabetical character set for use with |
| // RandStringFromCharSet |
| CharSetAlpha = "abcdefghijklmnopqrstuvwxyz" |
| ) |