122 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			122 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			Go
		
	
	
	
| package util
 | |
| 
 | |
| import (
 | |
| 	"crypto/md5"
 | |
| 	"encoding/hex"
 | |
| 	"math/rand"
 | |
| 	"regexp"
 | |
| 	"strings"
 | |
| 	"time"
 | |
| 
 | |
| 	"github.com/motomux/pretty"
 | |
| 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | |
| 
 | |
| 	"github.com/zalando-incubator/postgres-operator/pkg/spec"
 | |
| )
 | |
| 
 | |
| const (
 | |
| 	md5prefix = "md5"
 | |
| )
 | |
| 
 | |
| var passwordChars = []byte("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
 | |
| 
 | |
| func init() {
 | |
| 	rand.Seed(time.Now().Unix())
 | |
| }
 | |
| 
 | |
| // RandomPassword generates random alphanumeric password of a given length.
 | |
| func RandomPassword(n int) string {
 | |
| 	b := make([]byte, n)
 | |
| 	for i := range b {
 | |
| 		b[i] = passwordChars[rand.Intn(len(passwordChars))]
 | |
| 	}
 | |
| 
 | |
| 	return string(b)
 | |
| }
 | |
| 
 | |
| // NameFromMeta converts a metadata object to the NamespacedName name representation.
 | |
| func NameFromMeta(meta metav1.ObjectMeta) spec.NamespacedName {
 | |
| 	return spec.NamespacedName{
 | |
| 		Namespace: meta.Namespace,
 | |
| 		Name:      meta.Name,
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // PGUserPassword is used to generate md5 password hash for a given user. It does nothing for already hashed passwords.
 | |
| func PGUserPassword(user spec.PgUser) string {
 | |
| 	if (len(user.Password) == md5.Size*2+len(md5prefix) && user.Password[:3] == md5prefix) || user.Password == "" {
 | |
| 		// Avoid processing already encrypted or empty passwords
 | |
| 		return user.Password
 | |
| 	}
 | |
| 	s := md5.Sum([]byte(user.Password + user.Name))
 | |
| 	return md5prefix + hex.EncodeToString(s[:])
 | |
| }
 | |
| 
 | |
| // Diff returns diffs between 2 objects
 | |
| func Diff(a, b interface{}) []string {
 | |
| 	return pretty.Diff(a, b)
 | |
| }
 | |
| 
 | |
| // PrettyDiff shows the diff between 2 objects in an easy to understand format. It is mainly used for debugging output.
 | |
| func PrettyDiff(a, b interface{}) string {
 | |
| 	return strings.Join(Diff(a, b), "\n")
 | |
| }
 | |
| 
 | |
| // SubstractStringSlices finds elements in a that are not in b and return them as a result slice.
 | |
| func SubstractStringSlices(a []string, b []string) (result []string, equal bool) {
 | |
| 	// Slices are assumed to contain unique elements only
 | |
| OUTER:
 | |
| 	for _, vala := range a {
 | |
| 		for _, valb := range b {
 | |
| 			if vala == valb {
 | |
| 				continue OUTER
 | |
| 			}
 | |
| 		}
 | |
| 		result = append(result, vala)
 | |
| 	}
 | |
| 	return result, len(result) == 0
 | |
| }
 | |
| 
 | |
| // FindNamedStringSubmatch returns a map of strings holding the text of the matches of the r regular expression
 | |
| func FindNamedStringSubmatch(r *regexp.Regexp, s string) map[string]string {
 | |
| 	matches := r.FindStringSubmatch(s)
 | |
| 	grNames := r.SubexpNames()
 | |
| 
 | |
| 	if matches == nil {
 | |
| 		return nil
 | |
| 	}
 | |
| 
 | |
| 	groupMatches := 0
 | |
| 	res := make(map[string]string, len(grNames))
 | |
| 	for i, n := range grNames {
 | |
| 		if n == "" {
 | |
| 			continue
 | |
| 		}
 | |
| 
 | |
| 		res[n] = matches[i]
 | |
| 		groupMatches++
 | |
| 	}
 | |
| 
 | |
| 	if groupMatches == 0 {
 | |
| 		return nil
 | |
| 	}
 | |
| 
 | |
| 	return res
 | |
| }
 | |
| 
 | |
| // MapContains returns true if and only if haystack contains all the keys from the needle with matching corresponding values
 | |
| func MapContains(haystack, needle map[string]string) bool {
 | |
| 	if len(haystack) < len(needle) {
 | |
| 		return false
 | |
| 	}
 | |
| 
 | |
| 	for k, v := range needle {
 | |
| 		v2, ok := haystack[k]
 | |
| 		if !ok || v2 != v {
 | |
| 			return false
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return true
 | |
| }
 |