mirror of
				https://github.com/k3s-io/kubernetes.git
				synced 2025-10-31 05:40:42 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			76 lines
		
	
	
		
			2.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			76 lines
		
	
	
		
			2.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package protocol
 | |
| 
 | |
| import (
 | |
| 	"crypto/rand"
 | |
| 	"fmt"
 | |
| 	"reflect"
 | |
| )
 | |
| 
 | |
| // RandReader is the random reader the protocol package will use to read
 | |
| // random bytes from. This is exported for testing, and should not be used.
 | |
| var RandReader = rand.Reader
 | |
| 
 | |
| const idempotencyTokenFillTag = `idempotencyToken`
 | |
| 
 | |
| // CanSetIdempotencyToken returns true if the struct field should be
 | |
| // automatically populated with a Idempotency token.
 | |
| //
 | |
| // Only *string and string type fields that are tagged with idempotencyToken
 | |
| // which are not already set can be auto filled.
 | |
| func CanSetIdempotencyToken(v reflect.Value, f reflect.StructField) bool {
 | |
| 	switch u := v.Interface().(type) {
 | |
| 	// To auto fill an Idempotency token the field must be a string,
 | |
| 	// tagged for auto fill, and have a zero value.
 | |
| 	case *string:
 | |
| 		return u == nil && len(f.Tag.Get(idempotencyTokenFillTag)) != 0
 | |
| 	case string:
 | |
| 		return len(u) == 0 && len(f.Tag.Get(idempotencyTokenFillTag)) != 0
 | |
| 	}
 | |
| 
 | |
| 	return false
 | |
| }
 | |
| 
 | |
| // GetIdempotencyToken returns a randomly generated idempotency token.
 | |
| func GetIdempotencyToken() string {
 | |
| 	b := make([]byte, 16)
 | |
| 	RandReader.Read(b)
 | |
| 
 | |
| 	return UUIDVersion4(b)
 | |
| }
 | |
| 
 | |
| // SetIdempotencyToken will set the value provided with a Idempotency Token.
 | |
| // Given that the value can be set. Will panic if value is not setable.
 | |
| func SetIdempotencyToken(v reflect.Value) {
 | |
| 	if v.Kind() == reflect.Ptr {
 | |
| 		if v.IsNil() && v.CanSet() {
 | |
| 			v.Set(reflect.New(v.Type().Elem()))
 | |
| 		}
 | |
| 		v = v.Elem()
 | |
| 	}
 | |
| 	v = reflect.Indirect(v)
 | |
| 
 | |
| 	if !v.CanSet() {
 | |
| 		panic(fmt.Sprintf("unable to set idempotnecy token %v", v))
 | |
| 	}
 | |
| 
 | |
| 	b := make([]byte, 16)
 | |
| 	_, err := rand.Read(b)
 | |
| 	if err != nil {
 | |
| 		// TODO handle error
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	v.Set(reflect.ValueOf(UUIDVersion4(b)))
 | |
| }
 | |
| 
 | |
| // UUIDVersion4 returns a Version 4 random UUID from the byte slice provided
 | |
| func UUIDVersion4(u []byte) string {
 | |
| 	// https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_4_.28random.29
 | |
| 	// 13th character is "4"
 | |
| 	u[6] = (u[6] | 0x40) & 0x4F
 | |
| 	// 17th character is "8", "9", "a", or "b"
 | |
| 	u[8] = (u[8] | 0x80) & 0xBF
 | |
| 
 | |
| 	return fmt.Sprintf(`%X-%X-%X-%X-%X`, u[0:4], u[4:6], u[6:8], u[8:10], u[10:])
 | |
| }
 |