<commit_before>package bip39

import (
	"crypto/rand"
	"crypto/sha256"
	"crypto/sha512"
	"encoding/binary"
	"math/big"
	"strings"

	"golang.org/x/crypto/pbkdf2"
)

var (
	// Some bitwise operands for working with big.Ints
	last11BitsMask          = big.NewInt(2047)
	rightShift11BitsDivider = big.NewInt(2048)
	bigOne                  = big.NewInt(1)
	bigTwo                  = big.NewInt(2)

	// WordList sets the language used for the mnemonic
	WordList = EnglishWordList

	// ReverseWordMap is a reverse lookup of Wordlist
	ReverseWordMap = map[string]int{}
)

func init() {
	for i, v := range WordList {
		ReverseWordMap[v] = i
	}
}

// NewEntropy will create random entropy bytes
// so long as the requested size bitSize is an appropriate size.
func NewEntropy(bitSize int) ([]byte, error) {
	err := validateEntropyBitSize(bitSize)
	if err != nil {
		return nil, err
	}

	entropy := make([]byte, bitSize/8)
	_, err = rand.Read(entropy)
	return entropy, err
}

// NewMnemonic will return a string consisting of the mnemonic words for
// the given entropy.
// If the provide entropy is invalid, an error will be returned.
func NewMnemonic(entropy []byte) (string, error) {
	// Compute some lengths for convenience
	entropyBitLength := len(entropy) * 8
	checksumBitLength := entropyBitLength / 32
	sentenceLength := (entropyBitLength + checksumBitLength) / 11

	err := validateEntropyBitSize(entropyBitLength)
	if err != nil {
		return "", err
	}

	// Add checksum to entropy
	entropy = addChecksum(entropy)

	// Break entropy up into sentenceLength chunks of 11 bits
	// For each word AND mask the rightmost 11 bits and find the word at that index
	// Then bitshift entropy 11 bits right and repeat
	// Add to the last empty slot so we can work with LSBs instead of MSB

	// Entropy as an int so we can bitmask without worrying about bytes slices
	entropyInt := new(big.Int).SetBytes(entropy)

	// Slice to hold words in
	words := make([]string, sentenceLength)

	// Throw away big int for AND masking
	word := big.NewInt(0)

	for i := sentenceLength - 1; i >= 0; i-- {
		// Get 11 right most bits and bitshift 11 to the right for next time
		word.And(entropyInt, last11BitsMask)
		entropyInt.Div(entropyInt, rightShift11BitsDivider)

		// Get the bytes representing the 11 bits as a 2 byte slice
		wordBytes := padByteSlice(word.Bytes(), 2)

		// Convert bytes to an index and add that word to the list
		words[i] = WordList[binary.BigEndian.Uint16(wordBytes)]
	}

	return strings.Join(words, " "), nil
}

// MnemonicToByteArray takes a mnemonic string and turns it into a byte array
// suitable for creating another mnemonic.
// An error is returned if the mnemonic is invalid.
func MnemonicToByteArray(mnemonic string) ([]byte, error) {
	var (
		mnemonicSlice    = strings.Split(mnemonic, " ")
		entropyBitSize   = len(mnemonicSlice) * 11
		checksumBitSize  = entropyBitSize % 32
		fullByteSize     = (entropyBitSize-checksumBitSize)/8 + 1
		checksumByteSize = fullByteSize - (fullByteSize % 4)
	)

	// Pre validate
	if !IsMnemonicValid(mnemonic) {
		return nil, ErrInvalidMnemonic
	}

	err := validateEntropyWithChecksumBitSize(entropyBitSize)
	if err != nil {
		return nil, err
	}

	// Convert word indices to a `big.Int` representing the entropy
	checksummedEntropy := big.NewInt(0)
	modulo := big.NewInt(2048)
	for _, v := range mnemonicSlice {
		index, ok := ReverseWordMap[v]
		if !ok {
			return nil, UnknownWordErr{Word: v}
		}
		add := big.NewInt(int64(index))
		checksummedEntropy.Mul(checksummedEntropy, modulo)
		checksummedEntropy.Add(checksummedEntropy, add)
	}

	// Calculate the unchecksummed entropy so we can validate that the checksum is
	// correct
	checksumModulo := big.NewInt(0).Exp(bigTwo, big.NewInt(int64(checksumBitSize)), nil)
	rawEntropy := big.NewInt(0).Div(checksummedEntropy, checksumModulo)

	// Convert `big.Int`s to byte padded byte slices
	rawEntropyBytes := padByteSlice(rawEntropy.Bytes(), checksumByteSize)
	checksummedEntropyBytes := padByteSlice(checksummedEntropy.Bytes(), fullByteSize)

	// Validate that the checksum is correct
	newChecksummedEntropyBytes := padByteSlice(addChecksum(rawEntropyBytes), fullByteSize)
	if !compareByteSlices(checksummedEntropyBytes, newChecksummedEntropyBytes) {
		return nil, ErrChecksumIncorrect
	}

	return checksummedEntropyBytes, nil
}

// NewSeedWithErrorChecking creates a hashed seed output given the mnemonic string and a password.
// An error is returned if the mnemonic is not convertible to a byte array.
func NewSeedWithErrorChecking(mnemonic string, password string) ([]byte, error) {
	_, err := MnemonicToByteArray(mnemonic)
	if err != nil {
		return nil, err
	}
	return NewSeed(mnemonic, password), nil
}

// NewSeed creates a hashed seed output given a provided string and password.
// No checking is performed to validate that the string provided is a valid mnemonic.
func NewSeed(mnemonic string, password string) []byte {
	return pbkdf2.Key([]byte(mnemonic), []byte("mnemonic"+password), 2048, 64, sha512.New)
}

// IsMnemonicValid attempts to verify that the provided mnemonic is valid.
// Validity is determined by both the number of words being appropriate,
// and that all the words in the mnemonic are present in the word list.
func IsMnemonicValid(mnemonic string) bool {
	// Create a list of all the words in the mnemonic sentence
	words := strings.Fields(mnemonic)

	//Get num of words
	numOfWords := len(words)

	// The number of words should be 12, 15, 18, 21 or 24
	if numOfWords%3 != 0 || numOfWords < 12 || numOfWords > 24 {
		return false
	}

	// Check if all words belong in the wordlist
	for i := 0; i < numOfWords; i++ {
		if !contains(WordList, words[i]) {
			return false
		}
	}

	return true
}

// Appends to data the first (len(data) / 32)bits of the result of sha256(data)
// Currently only supports data up to 32 bytes
func addChecksum(data []byte) []byte {
	// Get first byte of sha256
	hasher := sha256.New()
	hasher.Write(data)
	hash := hasher.Sum(nil)
	firstChecksumByte := hash[0]

	// len() is in bytes so we divide by 4
	checksumBitLength := uint(len(data) / 4)

	// For each bit of check sum we want we shift the data one the left
	// and then set the (new) right most bit equal to checksum bit at that index
	// staring from the left
	dataBigInt := new(big.Int).SetBytes(data)
	for i := uint(0); i < checksumBitLength; i++ {
		// Bitshift 1 left
		dataBigInt.Mul(dataBigInt, bigTwo)

		// Set rightmost bit if leftmost checksum bit is set
		if uint8(firstChecksumByte&(1<<(7-i))) > 0 {
			dataBigInt.Or(dataBigInt, bigOne)
		}
	}

	return dataBigInt.Bytes()
}

// validateEntropyBitSize ensures that entropy is the correct size for being a
// mnemonic.
func validateEntropyBitSize(bitSize int) error {
	if (bitSize%32) != 0 || bitSize < 128 || bitSize > 256 {
		return ErrEntropyLengthInvalid
	}
	return nil
}

// validateEntropyWithChecksumBitSize ensures that the given number of bits is a
// valid length for seed entropy with an attached checksum.
func validateEntropyWithChecksumBitSize(bitSize int) error {
	if (bitSize != 128+4) && (bitSize != 160+5) && (bitSize != 192+6) && (bitSize != 224+7) && (bitSize != 256+8) {
		return EntropySizeErr{int((bitSize - bitSize%32) + (bitSize-bitSize%32)/32), bitSize}
	}
	return nil
}

// padByteSlice returns a byte slice of the given size with contents of the
// given slice left padded and any empty spaces filled with 0's.
func padByteSlice(slice []byte, length int) []byte {
	if len(slice) >= length {
		return slice
	}
	newSlice := make([]byte, length-len(slice))
	return append(newSlice, slice...)
}

// contains checks if a given string is in a given slice of strings.
func contains(s []string, e string) bool {
	for _, a := range s {
		if a == e {
			return true
		}
	}
	return false
}

// compareByteSlices returns true of the byte slices have equal contents and
// returns false otherwise.
func compareByteSlices(a, b []byte) bool {
	if len(a) != len(b) {
		return false
	}
	for i := range a {
		if a[i] != b[i] {
			return false
		}
	}
	return true
}
<commit_msg>FEATURE: Allow setting word list at runtime.<commit_after>package bip39

import (
	"crypto/rand"
	"crypto/sha256"
	"crypto/sha512"
	"encoding/binary"
	"math/big"
	"strings"

	"golang.org/x/crypto/pbkdf2"
)

var (
	// Some bitwise operands for working with big.Ints
	last11BitsMask          = big.NewInt(2047)
	rightShift11BitsDivider = big.NewInt(2048)
	bigOne                  = big.NewInt(1)
	bigTwo                  = big.NewInt(2)

	// WordList sets the language used for the mnemonic
	WordList []string

	// ReverseWordMap is a reverse lookup of Wordlist
	ReverseWordMap map[string]int

	// DefaultWordList specifies the wordlist to use upon initialization
	DefaultWordList = EnglishWordList
)

func init() {
	SetWordList(DefaultWordList)
}

// SetWordList sets the list of words to use for mnemonics. Currently the list
// that is set is used package-wide.
func SetWordList(wordList []string) {
	WordList = wordList
	ReverseWordMap = map[string]int{}
	for i, v := range WordList {
		ReverseWordMap[v] = i
	}
}

// NewEntropy will create random entropy bytes
// so long as the requested size bitSize is an appropriate size.
func NewEntropy(bitSize int) ([]byte, error) {
	err := validateEntropyBitSize(bitSize)
	if err != nil {
		return nil, err
	}

	entropy := make([]byte, bitSize/8)
	_, err = rand.Read(entropy)
	return entropy, err
}

// NewMnemonic will return a string consisting of the mnemonic words for
// the given entropy.
// If the provide entropy is invalid, an error will be returned.
func NewMnemonic(entropy []byte) (string, error) {
	// Compute some lengths for convenience
	entropyBitLength := len(entropy) * 8
	checksumBitLength := entropyBitLength / 32
	sentenceLength := (entropyBitLength + checksumBitLength) / 11

	err := validateEntropyBitSize(entropyBitLength)
	if err != nil {
		return "", err
	}

	// Add checksum to entropy
	entropy = addChecksum(entropy)

	// Break entropy up into sentenceLength chunks of 11 bits
	// For each word AND mask the rightmost 11 bits and find the word at that index
	// Then bitshift entropy 11 bits right and repeat
	// Add to the last empty slot so we can work with LSBs instead of MSB

	// Entropy as an int so we can bitmask without worrying about bytes slices
	entropyInt := new(big.Int).SetBytes(entropy)

	// Slice to hold words in
	words := make([]string, sentenceLength)

	// Throw away big int for AND masking
	word := big.NewInt(0)

	for i := sentenceLength - 1; i >= 0; i-- {
		// Get 11 right most bits and bitshift 11 to the right for next time
		word.And(entropyInt, last11BitsMask)
		entropyInt.Div(entropyInt, rightShift11BitsDivider)

		// Get the bytes representing the 11 bits as a 2 byte slice
		wordBytes := padByteSlice(word.Bytes(), 2)

		// Convert bytes to an index and add that word to the list
		words[i] = WordList[binary.BigEndian.Uint16(wordBytes)]
	}

	return strings.Join(words, " "), nil
}

// MnemonicToByteArray takes a mnemonic string and turns it into a byte array
// suitable for creating another mnemonic.
// An error is returned if the mnemonic is invalid.
func MnemonicToByteArray(mnemonic string) ([]byte, error) {
	var (
		mnemonicSlice    = strings.Split(mnemonic, " ")
		entropyBitSize   = len(mnemonicSlice) * 11
		checksumBitSize  = entropyBitSize % 32
		fullByteSize     = (entropyBitSize-checksumBitSize)/8 + 1
		checksumByteSize = fullByteSize - (fullByteSize % 4)
	)

	// Pre validate
	if !IsMnemonicValid(mnemonic) {
		return nil, ErrInvalidMnemonic
	}

	err := validateEntropyWithChecksumBitSize(entropyBitSize)
	if err != nil {
		return nil, err
	}

	// Convert word indices to a `big.Int` representing the entropy
	checksummedEntropy := big.NewInt(0)
	modulo := big.NewInt(2048)
	for _, v := range mnemonicSlice {
		index, ok := ReverseWordMap[v]
		if !ok {
			return nil, UnknownWordErr{Word: v}
		}
		add := big.NewInt(int64(index))
		checksummedEntropy.Mul(checksummedEntropy, modulo)
		checksummedEntropy.Add(checksummedEntropy, add)
	}

	// Calculate the unchecksummed entropy so we can validate that the checksum is
	// correct
	checksumModulo := big.NewInt(0).Exp(bigTwo, big.NewInt(int64(checksumBitSize)), nil)
	rawEntropy := big.NewInt(0).Div(checksummedEntropy, checksumModulo)

	// Convert `big.Int`s to byte padded byte slices
	rawEntropyBytes := padByteSlice(rawEntropy.Bytes(), checksumByteSize)
	checksummedEntropyBytes := padByteSlice(checksummedEntropy.Bytes(), fullByteSize)

	// Validate that the checksum is correct
	newChecksummedEntropyBytes := padByteSlice(addChecksum(rawEntropyBytes), fullByteSize)
	if !compareByteSlices(checksummedEntropyBytes, newChecksummedEntropyBytes) {
		return nil, ErrChecksumIncorrect
	}

	return checksummedEntropyBytes, nil
}

// NewSeedWithErrorChecking creates a hashed seed output given the mnemonic string and a password.
// An error is returned if the mnemonic is not convertible to a byte array.
func NewSeedWithErrorChecking(mnemonic string, password string) ([]byte, error) {
	_, err := MnemonicToByteArray(mnemonic)
	if err != nil {
		return nil, err
	}
	return NewSeed(mnemonic, password), nil
}

// NewSeed creates a hashed seed output given a provided string and password.
// No checking is performed to validate that the string provided is a valid mnemonic.
func NewSeed(mnemonic string, password string) []byte {
	return pbkdf2.Key([]byte(mnemonic), []byte("mnemonic"+password), 2048, 64, sha512.New)
}

// IsMnemonicValid attempts to verify that the provided mnemonic is valid.
// Validity is determined by both the number of words being appropriate,
// and that all the words in the mnemonic are present in the word list.
func IsMnemonicValid(mnemonic string) bool {
	// Create a list of all the words in the mnemonic sentence
	words := strings.Fields(mnemonic)

	//Get num of words
	numOfWords := len(words)

	// The number of words should be 12, 15, 18, 21 or 24
	if numOfWords%3 != 0 || numOfWords < 12 || numOfWords > 24 {
		return false
	}

	// Check if all words belong in the wordlist
	for i := 0; i < numOfWords; i++ {
		if !contains(WordList, words[i]) {
			return false
		}
	}

	return true
}

// Appends to data the first (len(data) / 32)bits of the result of sha256(data)
// Currently only supports data up to 32 bytes
func addChecksum(data []byte) []byte {
	// Get first byte of sha256
	hasher := sha256.New()
	hasher.Write(data)
	hash := hasher.Sum(nil)
	firstChecksumByte := hash[0]

	// len() is in bytes so we divide by 4
	checksumBitLength := uint(len(data) / 4)

	// For each bit of check sum we want we shift the data one the left
	// and then set the (new) right most bit equal to checksum bit at that index
	// staring from the left
	dataBigInt := new(big.Int).SetBytes(data)
	for i := uint(0); i < checksumBitLength; i++ {
		// Bitshift 1 left
		dataBigInt.Mul(dataBigInt, bigTwo)

		// Set rightmost bit if leftmost checksum bit is set
		if uint8(firstChecksumByte&(1<<(7-i))) > 0 {
			dataBigInt.Or(dataBigInt, bigOne)
		}
	}

	return dataBigInt.Bytes()
}

// validateEntropyBitSize ensures that entropy is the correct size for being a
// mnemonic.
func validateEntropyBitSize(bitSize int) error {
	if (bitSize%32) != 0 || bitSize < 128 || bitSize > 256 {
		return ErrEntropyLengthInvalid
	}
	return nil
}

// validateEntropyWithChecksumBitSize ensures that the given number of bits is a
// valid length for seed entropy with an attached checksum.
func validateEntropyWithChecksumBitSize(bitSize int) error {
	if (bitSize != 128+4) && (bitSize != 160+5) && (bitSize != 192+6) && (bitSize != 224+7) && (bitSize != 256+8) {
		return EntropySizeErr{int((bitSize - bitSize%32) + (bitSize-bitSize%32)/32), bitSize}
	}
	return nil
}

// padByteSlice returns a byte slice of the given size with contents of the
// given slice left padded and any empty spaces filled with 0's.
func padByteSlice(slice []byte, length int) []byte {
	if len(slice) >= length {
		return slice
	}
	newSlice := make([]byte, length-len(slice))
	return append(newSlice, slice...)
}

// contains checks if a given string is in a given slice of strings.
func contains(s []string, e string) bool {
	for _, a := range s {
		if a == e {
			return true
		}
	}
	return false
}

// compareByteSlices returns true of the byte slices have equal contents and
// returns false otherwise.
func compareByteSlices(a, b []byte) bool {
	if len(a) != len(b) {
		return false
	}
	for i := range a {
		if a[i] != b[i] {
			return false
		}
	}
	return true
}
<|endoftext|>


<commit_before>package templater

import (
	"reflect"
	"errors"
	"strings"
	"log"
	"strconv"
	"fmt"
	"regexp"

	"github.com/InnovaCo/serve/utils/templater/lexer"
	"github.com/InnovaCo/serve/utils/templater/token"
	"github.com/InnovaCo/serve/utils/gabs"
)

var ModifyFuncs = map[string]interface{}{
	"replace": replace,
	"same": same,
	"reverse": reverse,
}

func replace(old, r, new string) string {
	return regexp.MustCompile(r).ReplaceAllString(old, new)
}

func same(s string) string {
	return s
}

func reverse(s bool) bool {
	return !s
}

type Modify struct {
	context *gabs.Container
}

func (this Modify) SetFunc(name string, function interface{}) error {
	if _, ok := ModifyFuncs[name]; ok {
		return fmt.Errorf("function %s exist", name)
	}
	ModifyFuncs[name] = function
	return nil
}

func (this Modify) Call(name string, params ... interface{}) (reflect.Value, error) {
	log.Printf("modify call: func=%s args=%v\n", name, params)

	if _, ok := ModifyFuncs[name]; !ok {
		return reflect.Value{}, fmt.Errorf("function %v not register", name)
	}

    f := reflect.ValueOf(ModifyFuncs[name])
    if len(params) != f.Type().NumIn() {
		return reflect.Value{}, errors.New("The number of params is not adapted.")
    }
    in := make([]reflect.Value, len(params))
    for k, param := range params {
        in[k] = reflect.ValueOf(param)
    }
	return f.Call(in)[0], nil
}

func (this Modify) convert(val string) interface{} {
	if i, err := strconv.Atoi(val); err == nil {
		return i
	} else if f, err := strconv.ParseFloat(val, 64); err == nil {
		return f
	} else  if b, err := strconv.ParseBool(val); err == nil {
		return b
	}
	b := []byte(val)
	if (b[0] == []byte("\"")[0] && b[len(b) - 1] == []byte("\"")[0]) ||
		(b[0] == []byte("'")[0] && b[len(b) - 1] == []byte("'")[0])	{
		return string(b[1:len(val)-1])
	}
	return fmt.Sprintf("%v", val)
}

func (this Modify) clearFunc(s []byte) []string {
	return strings.Split(strings.TrimSpace(string([]byte(strings.TrimSpace(string(s)))[1:])), "(")
}

func (this Modify) clearArg(s []byte) string {
	a := []byte(strings.TrimSpace(string(s)))
	if a[0] == []byte(",")[0] {
		return strings.TrimSpace(string(a[1:]))
	}
	return string(a)
}

func (this Modify) parseFunc(s []byte) (string, []interface{}, error) {
	f := this.clearFunc(s)
	funcName := f[0]
	funcArgs := []interface{}{nil}
	if len(f) == 1 {
		return funcName, funcArgs, nil
	}
	fl := lexer.NewLexer([]byte(f[1]))
	for ftok := fl.Scan(); ftok.Type == token.TokMap.Type("arg"); ftok = fl.Scan() {
		funcArgs = append(funcArgs, this.convert(this.clearArg(ftok.Lit)))
	}
	return funcName, funcArgs, nil
}

func (this Modify) resolve(v string) (string, error) {
	//fmt.Printf("--> resolve: %v\n", v)
	if this.context == nil {
		//fmt.Printf("<-- resolve: %v\n", v)
		return v, nil
	}
	if value := this.context.Path(v).Data(); value != nil {
		//fmt.Printf("find: %v\n", value)
		v = fmt.Sprintf("%v", value)
	} else {
		//fmt.Println(this.context.String())
		//fmt.Printf("<-- resolve: %v\n", v)
		return v, nil
	}
	if s, err := Template(v, this.context); err != nil {
		//fmt.Println("<-- fuck", v)
		return v, nil
	} else {
		//fmt.Println("<--", v)
		return s, nil
	}
}

func (this Modify) Exec(s string) (interface{}, error) {
	l := lexer.NewLexer([]byte(s))
	var res interface{}
	res = nil

	for tok := l.Scan(); (tok.Type == token.TokMap.Type("var")) ||
						 (tok.Type == token.TokMap.Type("func")) ||
	                     (tok.Type == token.TokMap.Type("match")); tok = l.Scan() {
		switch {
			case tok.Type == token.TokMap.Type("var"):
				//fmt.Printf("var token: %v\n", string(tok.Lit))
				if val, err := this.resolve(string(tok.Lit)); err != nil {
					return nil, err
				} else {
					res = this.convert(val)
				}
			case tok.Type == token.TokMap.Type("func"):
				//fmt.Printf("func token: %v\n", string(tok.Lit))
				if funcName, funcArgs, err := this.parseFunc(tok.Lit); err == nil {
					funcArgs[0] = res
					if fv, err := this.Call(funcName, funcArgs...); err != nil {
						return nil, fmt.Errorf("execution error %s: %v", funcName, err)
					} else {
						res = this.convert(fv.String())
					}
				} else {
					return nil, fmt.Errorf("error parse %s: %v", tok.Lit, err )
				}
			case tok.Type == token.TokMap.Type("match"):
				//fmt.Printf("match token: %v\n", string(tok.Lit))
				return s, nil
			default:
				return nil, fmt.Errorf("unknown token %v\n", string(tok.Lit))
		}
	}
	return res, nil
}

func ModifyExec(s interface{}, context *gabs.Container) (interface{}, error) {
	switch s.(type) {
		case string:
			if strings.Contains(s.(string), "{{") && strings.Contains(s.(string), "}}") {
				return nil, fmt.Errorf("find symbols '{{' and '}}' in %v", s)
			}
			return Modify{context}.Exec(fmt.Sprintf("%v",s))
	}
	return s, nil
}<commit_msg>fix templater<commit_after>package templater

import (
	"reflect"
	"errors"
	"strings"
	"log"
	"strconv"
	"fmt"
	"regexp"

	"github.com/InnovaCo/serve/utils/templater/lexer"
	"github.com/InnovaCo/serve/utils/templater/token"
	"github.com/InnovaCo/serve/utils/gabs"
)

var ModifyFuncs = map[string]interface{}{
	"replace": replace,
	"same": same,
	"reverse": reverse,
}

func replace(old, r, new string) string {
	return regexp.MustCompile(r).ReplaceAllString(old, new)
}

func same(s string) string {
	return s
}

func reverse(s bool) bool {
	return !s
}

type Modify struct {
	context *gabs.Container
}

func (this Modify) SetFunc(name string, function interface{}) error {
	if _, ok := ModifyFuncs[name]; ok {
		return fmt.Errorf("function %s exist", name)
	}
	ModifyFuncs[name] = function
	return nil
}

func (this Modify) Call(name string, params ... interface{}) (reflect.Value, error) {
	log.Printf("modify call: func=%s args=%v\n", name, params)

	if _, ok := ModifyFuncs[name]; !ok {
		return reflect.Value{}, fmt.Errorf("function %v not register", name)
	}

    f := reflect.ValueOf(ModifyFuncs[name])
    if len(params) != f.Type().NumIn() {
		return reflect.Value{}, errors.New("The number of params is not adapted.")
    }
    in := make([]reflect.Value, len(params))
    for k, param := range params {
        in[k] = reflect.ValueOf(param)
    }
	return f.Call(in)[0], nil
}

func (this Modify) convert(val string) interface{} {
	if i, err := strconv.Atoi(val); err == nil {
		return i
	} else if f, err := strconv.ParseFloat(val, 64); err == nil {
		return f
	} else  if b, err := strconv.ParseBool(val); err == nil {
		return b
	}
	b := []byte(val)
	if (b[0] == []byte("\"")[0] && b[len(b) - 1] == []byte("\"")[0]) ||
		(b[0] == []byte("'")[0] && b[len(b) - 1] == []byte("'")[0])	{
		return string(b[1:len(val)-1])
	}
	return fmt.Sprintf("%v", val)
}

func (this Modify) clearFunc(s []byte) []string {
	return strings.Split(strings.TrimSpace(string([]byte(strings.TrimSpace(string(s)))[1:])), "(")
}

func (this Modify) clearArg(s []byte) string {
	a := []byte(strings.TrimSpace(string(s)))
	if a[0] == []byte(",")[0] {
		return strings.TrimSpace(string(a[1:]))
	}
	return string(a)
}

func (this Modify) parseFunc(s []byte) (string, []interface{}, error) {
	f := this.clearFunc(s)
	funcName := f[0]
	funcArgs := []interface{}{nil}
	if len(f) == 1 {
		return funcName, funcArgs, nil
	}
	fl := lexer.NewLexer([]byte(f[1]))
	for ftok := fl.Scan(); ftok.Type == token.TokMap.Type("arg"); ftok = fl.Scan() {
		funcArgs = append(funcArgs, this.convert(this.clearArg(ftok.Lit)))
	}
	return funcName, funcArgs, nil
}

func (this Modify) resolve(v string) (string, error) {
	//fmt.Printf("--> resolve: %v\n", v)
	if this.context == nil {
		//fmt.Printf("<-- resolve: %v\n", v)
		return v, nil
	}
	if value := this.context.Path(v).Data(); value != nil {
		//fmt.Printf("find: %v\n", value)
		v = fmt.Sprintf("%v", value)
	} else {
		//fmt.Println(this.context.String())
		//fmt.Printf("<-- resolve: %v\n", v)
		return v, nil
	}
	if s, err := Template(v, this.context); err != nil {
		//fmt.Println("<-- fuck", v)
		return v, nil
	} else {
		//fmt.Println("<--", v)
		return s, nil
	}
}

func (this Modify) Exec(s string) (interface{}, error) {
	l := lexer.NewLexer([]byte(s))
	var res interface{}
	res = nil

	for tok := l.Scan(); (tok.Type == token.TokMap.Type("var")) ||
						 (tok.Type == token.TokMap.Type("func")); tok = l.Scan() {
		switch {
			case tok.Type == token.TokMap.Type("var"):
				//fmt.Printf("var token: %v\n", string(tok.Lit))
				if val, err := this.resolve(string(tok.Lit)); err != nil {
					return nil, err
				} else {
					res = this.convert(val)
				}
			case tok.Type == token.TokMap.Type("func"):
				//fmt.Printf("func token: %v\n", string(tok.Lit))
				if funcName, funcArgs, err := this.parseFunc(tok.Lit); err == nil {
					funcArgs[0] = res
					if fv, err := this.Call(funcName, funcArgs...); err != nil {
						return nil, fmt.Errorf("execution error %s: %v", funcName, err)
					} else {
						res = this.convert(fv.String())
					}
				} else {
					return nil, fmt.Errorf("error parse %s: %v", tok.Lit, err )
				}
			default:
				return nil, fmt.Errorf("unknown token %v\n", string(tok.Lit))
		}
	}
	return res, nil
}

func ModifyExec(s interface{}, context *gabs.Container) (interface{}, error) {
	switch s.(type) {
		case string:
			if strings.Contains(s.(string), "{{") && strings.Contains(s.(string), "}}") {
				return nil, fmt.Errorf("find symbols '{{' and '}}' in %v", s)
			}
			return Modify{context}.Exec(fmt.Sprintf("%v",s))
	}
	return s, nil
}<|endoftext|>


<commit_before>/*
Copyright 2018 The Skaffold Authors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package acr

import (
	"bufio"
	"context"
	"io"
	"net/http"
	"strings"
	"time"

	cr "github.com/Azure/azure-sdk-for-go/services/containerregistry/mgmt/2018-09-01/containerregistry"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/build"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/build/tag"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/docker"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/util"
	"github.com/pkg/errors"
)

const BuildStatusHeader = "x-ms-meta-Complete"

func (b *Builder) Build(ctx context.Context, out io.Writer, tagger tag.Tagger, artifacts []*latest.Artifact) ([]build.Artifact, error) {
	return build.InParallel(ctx, out, tagger, artifacts, b.buildArtifact)
}

func (b *Builder) buildArtifact(ctx context.Context, out io.Writer, tagger tag.Tagger, artifact *latest.Artifact) (string, error) {
	client, err := b.NewRegistriesClient()
	if err != nil {
		return "", errors.Wrap(err, "get new registries client")
	}

	imageTag, err := tagger.GenerateFullyQualifiedImageName(artifact.Workspace, &tag.Options{
		Digest:    util.RandomID(),
		ImageName: artifact.ImageName,
	})
	if err != nil {
		return "", errors.Wrap(err, "create fully qualified image name")
	}
	registryName := getRegistryName(imageTag)

	resourceGroup, err := getResourceGroup(ctx, client, registryName)
	if err != nil {
		return "", errors.Wrap(err, "get resource group")
	}

	result, err := client.GetBuildSourceUploadURL(ctx, resourceGroup, registryName)
	if err != nil {
		return "", errors.Wrap(err, "build source upload url")
	}
	blob := NewBlobStorage(*result.UploadURL)

	err = docker.CreateDockerTarGzContext(ctx, blob.Buffer, artifact.Workspace, artifact.DockerArtifact)
	if err != nil {
		return "", errors.Wrap(err, "create context tar.gz")
	}

	err = blob.UploadFileToBlob()
	if err != nil {
		return "", errors.Wrap(err, "upload file to blob")
	}

	//acr needs the image tag formatted as <repository>:<tag>
	imageTag = getImageTagWithoutFQDN(imageTag)

	buildRequest := cr.DockerBuildRequest{
		ImageNames:     &[]string{imageTag},
		IsPushEnabled:  util.BoolPtr(true),
		SourceLocation: result.RelativePath,
		Platform: &cr.PlatformProperties{
			Variant:      cr.V8,
			Os:           cr.Linux,
			Architecture: cr.Amd64,
		},
		DockerFilePath: &artifact.DockerArtifact.DockerfilePath,
		Type:           cr.TypeDockerBuildRequest,
	}
	future, err := client.ScheduleRun(ctx, resourceGroup, registryName, buildRequest)
	if err != nil {
		return "", errors.Wrap(err, "schedule build request")
	}

	run, err := future.Result(*client)
	if err != nil {
		return "", errors.Wrap(err, "get run id")
	}
	runID := *run.RunID

	runsClient := cr.NewRunsClient(b.SubscriptionID)
	runsClient.Authorizer = client.Authorizer
	logURL, err := runsClient.GetLogSasURL(ctx, resourceGroup, registryName, runID)
	if err != nil {
		return "", errors.Wrap(err, "get log url")
	}

	err = streamBuildLogs(*logURL.LogLink, out)
	if err != nil {
		return "", errors.Wrap(err, "polling build status")
	}

	return imageTag, nil
}

func streamBuildLogs(logURL string, out io.Writer) error {
	offset := int32(0)
	for {
		resp, err := http.Get(logURL)
		if err != nil {
			return err
		}

		if resp.StatusCode == http.StatusNotFound {
			//if blob is not available yet, try again
			time.Sleep(2 * time.Second)
			continue
		}

		scanner := bufio.NewScanner(resp.Body)
		line := int32(0)
		for scanner.Scan() {
			if line >= offset {
				out.Write(scanner.Bytes())
				out.Write([]byte("\n"))
				offset++
			}
			line++
		}
		resp.Body.Close()

		if offset > 0 {
			switch resp.Header.Get(BuildStatusHeader) {
			case "":
				continue
			case "internalerror":
			case "failed":
				return errors.New("run failed")
			case "timedout":
				return errors.New("run timed out")
			case "canceled":
				return errors.New("run was canceled")
			default:
				return nil
			}
		}

		time.Sleep(2 * time.Second)
	}
}

func getResourceGroup(ctx context.Context, client *cr.RegistriesClient, registryName string) (string, error) {
	registryList, err := client.List(ctx)
	if err != nil {
		return "", err
	}

	for _, registry := range registryList.Values() {
		if strings.ToLower(*registry.Name) == registryName {
			//registry.ID returns the exact path to the container registry
			//e.g. /subscriptions/<subscriptionId>/resourceGroups/<resourceGroup>/...
			//so the resourceGroup is the fourth element of the split
			return strings.Split(*registry.ID, "/")[4], nil
		}
	}

	return "", errors.New("Couldn't find resource group of registry")
}

func getImageTagWithoutFQDN(imageTag string) string {
	return imageTag[strings.Index(imageTag, "/")+1:]
}

//acr URL is <registryname>.azurecr.io
func getRegistryName(imageTag string) string {
	return strings.ToLower(imageTag[:strings.Index(imageTag, ".")])
}
<commit_msg>Don't export build status header<commit_after>/*
Copyright 2018 The Skaffold Authors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package acr

import (
	"bufio"
	"context"
	"io"
	"net/http"
	"strings"
	"time"

	cr "github.com/Azure/azure-sdk-for-go/services/containerregistry/mgmt/2018-09-01/containerregistry"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/build"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/build/tag"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/docker"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/util"
	"github.com/pkg/errors"
)

const buildStatusHeader = "x-ms-meta-Complete"

func (b *Builder) Build(ctx context.Context, out io.Writer, tagger tag.Tagger, artifacts []*latest.Artifact) ([]build.Artifact, error) {
	return build.InParallel(ctx, out, tagger, artifacts, b.buildArtifact)
}

func (b *Builder) buildArtifact(ctx context.Context, out io.Writer, tagger tag.Tagger, artifact *latest.Artifact) (string, error) {
	client, err := b.NewRegistriesClient()
	if err != nil {
		return "", errors.Wrap(err, "get new registries client")
	}

	imageTag, err := tagger.GenerateFullyQualifiedImageName(artifact.Workspace, &tag.Options{
		Digest:    util.RandomID(),
		ImageName: artifact.ImageName,
	})
	if err != nil {
		return "", errors.Wrap(err, "create fully qualified image name")
	}
	registryName := getRegistryName(imageTag)

	resourceGroup, err := getResourceGroup(ctx, client, registryName)
	if err != nil {
		return "", errors.Wrap(err, "get resource group")
	}

	result, err := client.GetBuildSourceUploadURL(ctx, resourceGroup, registryName)
	if err != nil {
		return "", errors.Wrap(err, "build source upload url")
	}
	blob := NewBlobStorage(*result.UploadURL)

	err = docker.CreateDockerTarGzContext(ctx, blob.Buffer, artifact.Workspace, artifact.DockerArtifact)
	if err != nil {
		return "", errors.Wrap(err, "create context tar.gz")
	}

	err = blob.UploadFileToBlob()
	if err != nil {
		return "", errors.Wrap(err, "upload file to blob")
	}

	//acr needs the image tag formatted as <repository>:<tag>
	imageTag = getImageTagWithoutFQDN(imageTag)

	buildRequest := cr.DockerBuildRequest{
		ImageNames:     &[]string{imageTag},
		IsPushEnabled:  util.BoolPtr(true),
		SourceLocation: result.RelativePath,
		Platform: &cr.PlatformProperties{
			Variant:      cr.V8,
			Os:           cr.Linux,
			Architecture: cr.Amd64,
		},
		DockerFilePath: &artifact.DockerArtifact.DockerfilePath,
		Type:           cr.TypeDockerBuildRequest,
	}
	future, err := client.ScheduleRun(ctx, resourceGroup, registryName, buildRequest)
	if err != nil {
		return "", errors.Wrap(err, "schedule build request")
	}

	run, err := future.Result(*client)
	if err != nil {
		return "", errors.Wrap(err, "get run id")
	}
	runID := *run.RunID

	runsClient := cr.NewRunsClient(b.SubscriptionID)
	runsClient.Authorizer = client.Authorizer
	logURL, err := runsClient.GetLogSasURL(ctx, resourceGroup, registryName, runID)
	if err != nil {
		return "", errors.Wrap(err, "get log url")
	}

	err = streamBuildLogs(*logURL.LogLink, out)
	if err != nil {
		return "", errors.Wrap(err, "polling build status")
	}

	return imageTag, nil
}

func streamBuildLogs(logURL string, out io.Writer) error {
	offset := int32(0)
	for {
		resp, err := http.Get(logURL)
		if err != nil {
			return err
		}

		if resp.StatusCode == http.StatusNotFound {
			//if blob is not available yet, try again
			time.Sleep(2 * time.Second)
			continue
		}

		scanner := bufio.NewScanner(resp.Body)
		line := int32(0)
		for scanner.Scan() {
			if line >= offset {
				out.Write(scanner.Bytes())
				out.Write([]byte("\n"))
				offset++
			}
			line++
		}
		resp.Body.Close()

		if offset > 0 {
			switch resp.Header.Get(buildStatusHeader) {
			case "":
				continue
			case "internalerror":
			case "failed":
				return errors.New("run failed")
			case "timedout":
				return errors.New("run timed out")
			case "canceled":
				return errors.New("run was canceled")
			default:
				return nil
			}
		}

		time.Sleep(2 * time.Second)
	}
}

func getResourceGroup(ctx context.Context, client *cr.RegistriesClient, registryName string) (string, error) {
	registryList, err := client.List(ctx)
	if err != nil {
		return "", err
	}

	for _, registry := range registryList.Values() {
		if strings.ToLower(*registry.Name) == registryName {
			//registry.ID returns the exact path to the container registry
			//e.g. /subscriptions/<subscriptionId>/resourceGroups/<resourceGroup>/...
			//so the resourceGroup is the fourth element of the split
			return strings.Split(*registry.ID, "/")[4], nil
		}
	}

	return "", errors.New("Couldn't find resource group of registry")
}

func getImageTagWithoutFQDN(imageTag string) string {
	return imageTag[strings.Index(imageTag, "/")+1:]
}

//acr URL is <registryname>.azurecr.io
func getRegistryName(imageTag string) string {
	return strings.ToLower(imageTag[:strings.Index(imageTag, ".")])
}
<|endoftext|>


<commit_before>package xor

import (
	"testing"
	"time"
	"os"
	"fmt"
	"github.com/yaricom/goNEAT/neat"
	"github.com/yaricom/goNEAT/neat/genetics"
	"math/rand"
	"github.com/yaricom/goNEAT/experiments"
)

// The integration test running over multiple iterations in order to detect if any random errors occur.
func TestXOR(t *testing.T) {
	// the numbers will be different every time we run.
	rand.Seed(time.Now().Unix())

	out_dir_path, context_path, genome_path := "../../out", "../../data/xor.neat", "../../data/xorstartgenes"

	// Load context configuration
	configFile, err := os.Open(context_path)
	if err != nil {
		t.Error("Failed to load context", err)
		return
	}
	context := neat.LoadContext(configFile)
	neat.LogLevel = neat.LogLevelInfo

	// Load Genome
	fmt.Println("Loading start genome for XOR experiment")
	genomeFile, err := os.Open(genome_path)
	if err != nil {
		t.Error("Failed to open genome file")
		return
	}
	start_genome, err := genetics.ReadGenome(genomeFile, 1)
	if err != nil {
		t.Error("Failed to read start genome")
		return
	}

	// Check if output dir exists
	if _, err := os.Stat(out_dir_path); err == nil {
		// clear it
		os.RemoveAll(out_dir_path)
	}
	// create output dir
	err = os.MkdirAll(out_dir_path, os.ModePerm)
	if err != nil {
		t.Errorf("Failed to create output directory, reason: %s", err)
		return
	}

	// The 100 runs XOR experiment
	context.NumRuns = 100
	experiment := experiments.Experiment {
		Id:0,
		Trials:make(experiments.Trials, context.NumRuns),
	}
	err = XOR(context, start_genome, out_dir_path, &experiment)
	if err != nil {
		t.Error("Failed to perform XOR experiment:", err)
		return
	}

	// Find winner statistics
	avg_nodes, avg_genes, avg_evals := experiment.AvgWinnerNGE()

	// check results
	if avg_nodes < 5 {
		t.Error("avg_nodes < 5", avg_nodes)
	} else if avg_nodes > 15 {
		t.Error("avg_nodes > 15", avg_nodes)
	}

	if avg_genes < 7 {
		t.Error("avg_genes < 7", avg_genes)
	} else if avg_genes > 20 {
		t.Error("avg_genes > 20", avg_genes)
	}

	max_evals := float64(context.PopSize * context.NumGenerations)
	if avg_evals > max_evals {
		t.Error("avg_evals > max_evals", avg_evals, max_evals)
	}

	t.Logf("avg_nodes: %.1f, avg_genes: %.1f, avg_evals: %.1f\n", avg_nodes, avg_genes, avg_evals)
	mean_complexity, mean_diversity, mean_age := 0.0, 0.0, 0.0
	for _, t := range experiment.Trials {
		mean_complexity += t.Complexity().Mean()
		mean_diversity += t.Diversity().Mean()
		mean_age += t.Age().Mean()
	}
	count := float64(len(experiment.Trials))
	mean_complexity /= count
	mean_diversity /= count
	mean_age /= count
	t.Logf("mean: complexity=%.1f, diversity=%.1f, age=%.1f", mean_complexity, mean_diversity, mean_age)
}

// The XOR integration test for disconnected inputs running over multiple iterations in order to detect if any random errors occur.
func TestXOR_disconnected(t *testing.T) {
	// the numbers will be different every time we run.
	rand.Seed(time.Now().Unix())

	out_dir_path, context_path, genome_path := "../../out", "../../data/xor.neat", "../../data/xorstartgenes"

	// Load context configuration
	configFile, err := os.Open(context_path)
	if err != nil {
		t.Error("Failed to load context", err)
		return
	}
	context := neat.LoadContext(configFile)
	neat.LogLevel = neat.LogLevelInfo

	// Load Genome
	fmt.Println("Loading start genome for XOR experiment")
	genomeFile, err := os.Open(genome_path)
	if err != nil {
		t.Error("Failed to open genome file")
		return
	}
	start_genome, err := genetics.ReadGenome(genomeFile, 1)
	if err != nil {
		t.Error("Failed to read start genome")
		return
	}

	// Check if output dir exists
	if _, err := os.Stat(out_dir_path); err == nil {
		// clear it
		os.RemoveAll(out_dir_path)
	}
	// create output dir
	err = os.MkdirAll(out_dir_path, os.ModePerm)
	if err != nil {
		t.Errorf("Failed to create output directory, reason: %s", err)
		return
	}

	// The 100 runs XOR experiment
	context.NumRuns = 100
	experiment := experiments.Experiment {
		Id:0,
		Trials:make(experiments.Trials, context.NumRuns),
	}
	err = XOR(context, start_genome, out_dir_path, &experiment)
	if err != nil {
		t.Error("Failed to perform XOR experiment:", err)
		return
	}

	// Find winner statistics
	avg_nodes, avg_genes, avg_evals := experiment.AvgWinnerNGE()

	// check results
	if avg_nodes < 5 {
		t.Error("avg_nodes < 5", avg_nodes)
	} else if avg_nodes > 15 {
		t.Error("avg_nodes > 15", avg_nodes)
	}

	if avg_genes < 7 {
		t.Error("avg_genes < 7", avg_genes)
	} else if avg_genes > 20 {
		t.Error("avg_genes > 20", avg_genes)
	}

	max_evals := float64(context.PopSize * context.NumGenerations)
	if avg_evals > max_evals {
		t.Error("avg_evals > max_evals", avg_evals, max_evals)
	}

	t.Logf("avg_nodes: %.1f, avg_genes: %.1f, avg_evals: %.1f\n", avg_nodes, avg_genes, avg_evals)
	mean_complexity, mean_diversity, mean_age := 0.0, 0.0, 0.0
	for _, t := range experiment.Trials {
		mean_complexity += t.Complexity().Mean()
		mean_diversity += t.Diversity().Mean()
		mean_age += t.Age().Mean()
	}
	count := float64(len(experiment.Trials))
	mean_complexity /= count
	mean_diversity /= count
	mean_age /= count
	t.Logf("mean: complexity=%.1f, diversity=%.1f, age=%.1f", mean_complexity, mean_diversity, mean_age)
}<commit_msg>Fixes in order to use updated experiment generalization.<commit_after>package xor

import (
	"testing"
	"time"
	"os"
	"fmt"
	"github.com/yaricom/goNEAT/neat"
	"github.com/yaricom/goNEAT/neat/genetics"
	"math/rand"
	"github.com/yaricom/goNEAT/experiments"
)

// The integration test running over multiple iterations in order to detect if any random errors occur.
func TestXOR(t *testing.T) {
	// the numbers will be different every time we run.
	rand.Seed(time.Now().Unix())

	out_dir_path, context_path, genome_path := "../../out", "../../data/xor.neat", "../../data/xorstartgenes"

	// Load context configuration
	configFile, err := os.Open(context_path)
	if err != nil {
		t.Error("Failed to load context", err)
		return
	}
	context := neat.LoadContext(configFile)
	neat.LogLevel = neat.LogLevelInfo

	// Load Genome
	fmt.Println("Loading start genome for XOR experiment")
	genomeFile, err := os.Open(genome_path)
	if err != nil {
		t.Error("Failed to open genome file")
		return
	}
	start_genome, err := genetics.ReadGenome(genomeFile, 1)
	if err != nil {
		t.Error("Failed to read start genome")
		return
	}

	// Check if output dir exists
	if _, err := os.Stat(out_dir_path); err == nil {
		// clear it
		os.RemoveAll(out_dir_path)
	}
	// create output dir
	err = os.MkdirAll(out_dir_path, os.ModePerm)
	if err != nil {
		t.Errorf("Failed to create output directory, reason: %s", err)
		return
	}

	// The 100 runs XOR experiment
	context.NumRuns = 100
	experiment := experiments.Experiment {
		Id:0,
		Trials:make(experiments.Trials, context.NumRuns),
	}
	err = experiment.Execute(context, start_genome, XOREpochEvaluator{OutputPath:out_dir_path})
	if err != nil {
		t.Error("Failed to perform XOR experiment:", err)
		return
	}

	// Find winner statistics
	avg_nodes, avg_genes, avg_evals := experiment.AvgWinnerNGE()

	// check results
	if avg_nodes < 5 {
		t.Error("avg_nodes < 5", avg_nodes)
	} else if avg_nodes > 15 {
		t.Error("avg_nodes > 15", avg_nodes)
	}

	if avg_genes < 7 {
		t.Error("avg_genes < 7", avg_genes)
	} else if avg_genes > 20 {
		t.Error("avg_genes > 20", avg_genes)
	}

	max_evals := float64(context.PopSize * context.NumGenerations)
	if avg_evals > max_evals {
		t.Error("avg_evals > max_evals", avg_evals, max_evals)
	}

	t.Logf("avg_nodes: %.1f, avg_genes: %.1f, avg_evals: %.1f\n", avg_nodes, avg_genes, avg_evals)
	mean_complexity, mean_diversity, mean_age := 0.0, 0.0, 0.0
	for _, t := range experiment.Trials {
		mean_complexity += t.Complexity().Mean()
		mean_diversity += t.Diversity().Mean()
		mean_age += t.Age().Mean()
	}
	count := float64(len(experiment.Trials))
	mean_complexity /= count
	mean_diversity /= count
	mean_age /= count
	t.Logf("mean: complexity=%.1f, diversity=%.1f, age=%.1f", mean_complexity, mean_diversity, mean_age)
}

// The XOR integration test for disconnected inputs running over multiple iterations in order to detect if any random errors occur.
func TestXOR_disconnected(t *testing.T) {
	// the numbers will be different every time we run.
	rand.Seed(time.Now().Unix())

	out_dir_path, context_path, genome_path := "../../out", "../../data/xor.neat", "../../data/xorstartgenes"

	// Load context configuration
	configFile, err := os.Open(context_path)
	if err != nil {
		t.Error("Failed to load context", err)
		return
	}
	context := neat.LoadContext(configFile)
	neat.LogLevel = neat.LogLevelInfo

	// Load Genome
	fmt.Println("Loading start genome for XOR experiment")
	genomeFile, err := os.Open(genome_path)
	if err != nil {
		t.Error("Failed to open genome file")
		return
	}
	start_genome, err := genetics.ReadGenome(genomeFile, 1)
	if err != nil {
		t.Error("Failed to read start genome")
		return
	}

	// Check if output dir exists
	if _, err := os.Stat(out_dir_path); err == nil {
		// clear it
		os.RemoveAll(out_dir_path)
	}
	// create output dir
	err = os.MkdirAll(out_dir_path, os.ModePerm)
	if err != nil {
		t.Errorf("Failed to create output directory, reason: %s", err)
		return
	}

	// The 100 runs XOR experiment
	context.NumRuns = 100
	experiment := experiments.Experiment {
		Id:0,
		Trials:make(experiments.Trials, context.NumRuns),
	}
	err = experiment.Execute(context, start_genome, XOREpochEvaluator{OutputPath:out_dir_path})
	if err != nil {
		t.Error("Failed to perform XOR experiment:", err)
		return
	}

	// Find winner statistics
	avg_nodes, avg_genes, avg_evals := experiment.AvgWinnerNGE()

	// check results
	if avg_nodes < 5 {
		t.Error("avg_nodes < 5", avg_nodes)
	} else if avg_nodes > 15 {
		t.Error("avg_nodes > 15", avg_nodes)
	}

	if avg_genes < 7 {
		t.Error("avg_genes < 7", avg_genes)
	} else if avg_genes > 20 {
		t.Error("avg_genes > 20", avg_genes)
	}

	max_evals := float64(context.PopSize * context.NumGenerations)
	if avg_evals > max_evals {
		t.Error("avg_evals > max_evals", avg_evals, max_evals)
	}

	t.Logf("avg_nodes: %.1f, avg_genes: %.1f, avg_evals: %.1f\n", avg_nodes, avg_genes, avg_evals)
	mean_complexity, mean_diversity, mean_age := 0.0, 0.0, 0.0
	for _, t := range experiment.Trials {
		mean_complexity += t.Complexity().Mean()
		mean_diversity += t.Diversity().Mean()
		mean_age += t.Age().Mean()
	}
	count := float64(len(experiment.Trials))
	mean_complexity /= count
	mean_diversity /= count
	mean_age /= count
	t.Logf("mean: complexity=%.1f, diversity=%.1f, age=%.1f", mean_complexity, mean_diversity, mean_age)
}<|endoftext|>


<commit_before>/*
Copyright 2016 The Fission Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package cms

import (
	"context"
	"time"

	"go.uber.org/zap"
	apiv1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/fields"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/tools/cache"

	fv1 "github.com/fission/fission/pkg/apis/fission.io/v1"
	"github.com/fission/fission/pkg/crd"
	nd "github.com/fission/fission/pkg/executor/newdeploy"
	gpm "github.com/fission/fission/pkg/executor/poolmgr"
)

type (
	ConfigSecretController struct {
		logger *zap.Logger

		configmapController cache.Controller
		secretController    cache.Controller

		fissionClient *crd.FissionClient
	}
)

//MakeConfigSecretController makes a controller for configmaps and secrets which changes related functions
func MakeConfigSecretController(logger *zap.Logger, fissionClient *crd.FissionClient,
	kubernetesClient *kubernetes.Clientset, ndm *nd.NewDeploy, gpm *gpm.GenericPoolManager) *ConfigSecretController {
	logger.Debug("Creating ConfigMap & Secret Controller")
	_, cmcontroller := initConfigmapController(logger, fissionClient, kubernetesClient, ndm, gpm)
	_, scontroller := initSecretController(logger, fissionClient, kubernetesClient, ndm, gpm)
	cmsController := &ConfigSecretController{
		logger:              logger,
		configmapController: cmcontroller,
		secretController:    scontroller,
		fissionClient:       fissionClient,
	}
	return cmsController
}

//Run runs the controllers for configmaps and secrets
func (csController *ConfigSecretController) Run(ctx context.Context) {
	go csController.configmapController.Run(ctx.Done())
	go csController.secretController.Run(ctx.Done())
}

func initConfigmapController(logger *zap.Logger, fissionClient *crd.FissionClient,
	kubernetesClient *kubernetes.Clientset, ndm *nd.NewDeploy, gpm *gpm.GenericPoolManager) (cache.Store, cache.Controller) {
	resyncPeriod := 30 * time.Second
	listWatch := cache.NewListWatchFromClient(kubernetesClient.AppsV1().RESTClient(), "configmaps", metav1.NamespaceAll, fields.Everything())
	store, controller := cache.NewInformer(listWatch, &apiv1.ConfigMap{}, resyncPeriod, cache.ResourceEventHandlerFuncs{
		AddFunc:    func(obj interface{}) {},
		DeleteFunc: func(obj interface{}) {},
		UpdateFunc: func(oldObj interface{}, newObj interface{}) {
			oldCm := oldObj.(*apiv1.ConfigMap)
			newCm := newObj.(*apiv1.ConfigMap)
			if oldCm.ObjectMeta.ResourceVersion != newCm.ObjectMeta.ResourceVersion {
				if newCm.ObjectMeta.Namespace != "kube-system" {
					logger.Debug("Configmap changed",
						zap.String("configmap_name", newCm.ObjectMeta.Name),
						zap.String("configmap_namespace", newCm.ObjectMeta.Namespace))

				}

				funcs, err := getConfigmapRelatedFuncs(logger, &newCm.ObjectMeta, fissionClient)
				if err != nil {
					logger.Error("Failed to get functions related to secret", zap.String("secret_name", newCm.ObjectMeta.Name), zap.String("secret_namespace", newCm.ObjectMeta.Namespace))
				}
				recyclePods(logger, funcs, ndm, gpm)
			}

		},
	})
	return store, controller
}

func getConfigmapRelatedFuncs(logger *zap.Logger, m *metav1.ObjectMeta, fissionClient *crd.FissionClient) ([]fv1.Function, error) {
	funcList, err := fissionClient.Functions(metav1.NamespaceAll).List(metav1.ListOptions{})
	if err != nil {
		return nil, err
	}
	// In future a cache that populates at start and is updated on changes might be better solution
	relatedFunctions := make([]fv1.Function, 0)
	for _, f := range funcList.Items {
		for _, cm := range f.Spec.ConfigMaps {
			if (cm.Name == m.Name) && (cm.Namespace == m.Namespace) {
				relatedFunctions = append(relatedFunctions, f)
				break
			}
		}
	}
	return relatedFunctions, nil
}

func initSecretController(logger *zap.Logger, fissionClient *crd.FissionClient,
	kubernetesClient *kubernetes.Clientset, ndm *nd.NewDeploy, gpm *gpm.GenericPoolManager) (cache.Store, cache.Controller) {
	resyncPeriod := 30 * time.Second
	listWatch := cache.NewListWatchFromClient(kubernetesClient.AppsV1().RESTClient(), "secrets", metav1.NamespaceAll, fields.Everything())
	store, controller := cache.NewInformer(listWatch, &apiv1.Secret{}, resyncPeriod, cache.ResourceEventHandlerFuncs{
		AddFunc:    func(obj interface{}) {},
		DeleteFunc: func(obj interface{}) {},
		UpdateFunc: func(oldObj interface{}, newObj interface{}) {
			oldS := oldObj.(*apiv1.Secret)
			newS := newObj.(*apiv1.Secret)
			if oldS.ObjectMeta.ResourceVersion != newS.ObjectMeta.ResourceVersion {
				if newS.ObjectMeta.Namespace != "kube-system" {
					logger.Debug("Secret changed",
						zap.String("configmap_name", newS.ObjectMeta.Name),
						zap.String("configmap_namespace", newS.ObjectMeta.Namespace))

				}

				funcs, err := getSecretRelatedFuncs(logger, &newS.ObjectMeta, fissionClient)
				if err != nil {
					logger.Error("Failed to get functions related to secret", zap.String("secret_name", newS.ObjectMeta.Name), zap.String("secret_namespace", newS.ObjectMeta.Namespace))
				}
				recyclePods(logger, funcs, ndm, gpm)
			}

		},
	})
	return store, controller

}

func getSecretRelatedFuncs(logger *zap.Logger, m *metav1.ObjectMeta, fissionClient *crd.FissionClient) ([]fv1.Function, error) {
	funcList, err := fissionClient.Functions(metav1.NamespaceAll).List(metav1.ListOptions{})
	if err != nil {
		return nil, err
	}
	// In future a cache that populates at start and is updated on changes might be better solution
	relatedFunctions := make([]fv1.Function, 0)
	for _, f := range funcList.Items {
		for _, secret := range f.Spec.Secrets {
			if (secret.Name == m.Name) && (secret.Namespace == m.Namespace) {
				relatedFunctions = append(relatedFunctions, f)
				break
			}
		}
	}
	return relatedFunctions, nil
}

func recyclePods(logger *zap.Logger, funcs []fv1.Function, ndm *nd.NewDeploy, gpm *gpm.GenericPoolManager) {
	for _, f := range funcs {
		var err error

		switch f.Spec.InvokeStrategy.ExecutionStrategy.ExecutorType {
		case fv1.ExecutorTypeNewdeploy:
			err = ndm.RefreshFuncPods(logger, f)
		case fv1.ExecutorTypePoolmgr:
			err = gpm.RefreshFuncPods(logger, f)
		}

		if err != nil {
			logger.Error("Failed to recycle pods for function after configmap changed",
				zap.Error(err),
				zap.Any("function", f))
		}
	}
}
<commit_msg>Fix executor unable to list secrets/configmaps (#1307)<commit_after>/*
Copyright 2016 The Fission Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package cms

import (
	"context"
	"time"

	"go.uber.org/zap"
	apiv1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/fields"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/tools/cache"

	fv1 "github.com/fission/fission/pkg/apis/fission.io/v1"
	"github.com/fission/fission/pkg/crd"
	nd "github.com/fission/fission/pkg/executor/newdeploy"
	gpm "github.com/fission/fission/pkg/executor/poolmgr"
)

type (
	ConfigSecretController struct {
		logger *zap.Logger

		configmapController cache.Controller
		secretController    cache.Controller

		fissionClient *crd.FissionClient
	}
)

//MakeConfigSecretController makes a controller for configmaps and secrets which changes related functions
func MakeConfigSecretController(logger *zap.Logger, fissionClient *crd.FissionClient,
	kubernetesClient *kubernetes.Clientset, ndm *nd.NewDeploy, gpm *gpm.GenericPoolManager) *ConfigSecretController {
	logger.Debug("Creating ConfigMap & Secret Controller")
	_, cmcontroller := initConfigmapController(logger, fissionClient, kubernetesClient, ndm, gpm)
	_, scontroller := initSecretController(logger, fissionClient, kubernetesClient, ndm, gpm)
	cmsController := &ConfigSecretController{
		logger:              logger,
		configmapController: cmcontroller,
		secretController:    scontroller,
		fissionClient:       fissionClient,
	}
	return cmsController
}

//Run runs the controllers for configmaps and secrets
func (csController *ConfigSecretController) Run(ctx context.Context) {
	go csController.configmapController.Run(ctx.Done())
	go csController.secretController.Run(ctx.Done())
}

func initConfigmapController(logger *zap.Logger, fissionClient *crd.FissionClient,
	kubernetesClient *kubernetes.Clientset, ndm *nd.NewDeploy, gpm *gpm.GenericPoolManager) (cache.Store, cache.Controller) {
	resyncPeriod := 30 * time.Second
	listWatch := cache.NewListWatchFromClient(kubernetesClient.CoreV1().RESTClient(), "configmaps", metav1.NamespaceAll, fields.Everything())
	store, controller := cache.NewInformer(listWatch, &apiv1.ConfigMap{}, resyncPeriod, cache.ResourceEventHandlerFuncs{
		AddFunc:    func(obj interface{}) {},
		DeleteFunc: func(obj interface{}) {},
		UpdateFunc: func(oldObj interface{}, newObj interface{}) {
			oldCm := oldObj.(*apiv1.ConfigMap)
			newCm := newObj.(*apiv1.ConfigMap)
			if oldCm.ObjectMeta.ResourceVersion != newCm.ObjectMeta.ResourceVersion {
				if newCm.ObjectMeta.Namespace != "kube-system" {
					logger.Debug("Configmap changed",
						zap.String("configmap_name", newCm.ObjectMeta.Name),
						zap.String("configmap_namespace", newCm.ObjectMeta.Namespace))
				}

				funcs, err := getConfigmapRelatedFuncs(logger, &newCm.ObjectMeta, fissionClient)
				if err != nil {
					logger.Error("Failed to get functions related to secret", zap.String("secret_name", newCm.ObjectMeta.Name), zap.String("secret_namespace", newCm.ObjectMeta.Namespace))
				}
				recyclePods(logger, funcs, ndm, gpm)
			}
		},
	})
	return store, controller
}

func getConfigmapRelatedFuncs(logger *zap.Logger, m *metav1.ObjectMeta, fissionClient *crd.FissionClient) ([]fv1.Function, error) {
	funcList, err := fissionClient.Functions(metav1.NamespaceAll).List(metav1.ListOptions{})
	if err != nil {
		return nil, err
	}
	// In future a cache that populates at start and is updated on changes might be better solution
	relatedFunctions := make([]fv1.Function, 0)
	for _, f := range funcList.Items {
		for _, cm := range f.Spec.ConfigMaps {
			if (cm.Name == m.Name) && (cm.Namespace == m.Namespace) {
				relatedFunctions = append(relatedFunctions, f)
				break
			}
		}
	}
	return relatedFunctions, nil
}

func initSecretController(logger *zap.Logger, fissionClient *crd.FissionClient,
	kubernetesClient *kubernetes.Clientset, ndm *nd.NewDeploy, gpm *gpm.GenericPoolManager) (cache.Store, cache.Controller) {
	resyncPeriod := 30 * time.Second
	listWatch := cache.NewListWatchFromClient(kubernetesClient.CoreV1().RESTClient(), "secrets", metav1.NamespaceAll, fields.Everything())
	store, controller := cache.NewInformer(listWatch, &apiv1.Secret{}, resyncPeriod, cache.ResourceEventHandlerFuncs{
		AddFunc:    func(obj interface{}) {},
		DeleteFunc: func(obj interface{}) {},
		UpdateFunc: func(oldObj interface{}, newObj interface{}) {
			oldS := oldObj.(*apiv1.Secret)
			newS := newObj.(*apiv1.Secret)
			if oldS.ObjectMeta.ResourceVersion != newS.ObjectMeta.ResourceVersion {
				if newS.ObjectMeta.Namespace != "kube-system" {
					logger.Debug("Secret changed",
						zap.String("configmap_name", newS.ObjectMeta.Name),
						zap.String("configmap_namespace", newS.ObjectMeta.Namespace))

				}

				funcs, err := getSecretRelatedFuncs(logger, &newS.ObjectMeta, fissionClient)
				if err != nil {
					logger.Error("Failed to get functions related to secret", zap.String("secret_name", newS.ObjectMeta.Name), zap.String("secret_namespace", newS.ObjectMeta.Namespace))
				}
				recyclePods(logger, funcs, ndm, gpm)
			}

		},
	})
	return store, controller

}

func getSecretRelatedFuncs(logger *zap.Logger, m *metav1.ObjectMeta, fissionClient *crd.FissionClient) ([]fv1.Function, error) {
	funcList, err := fissionClient.Functions(metav1.NamespaceAll).List(metav1.ListOptions{})
	if err != nil {
		return nil, err
	}
	// In future a cache that populates at start and is updated on changes might be better solution
	relatedFunctions := make([]fv1.Function, 0)
	for _, f := range funcList.Items {
		for _, secret := range f.Spec.Secrets {
			if (secret.Name == m.Name) && (secret.Namespace == m.Namespace) {
				relatedFunctions = append(relatedFunctions, f)
				break
			}
		}
	}
	return relatedFunctions, nil
}

func recyclePods(logger *zap.Logger, funcs []fv1.Function, ndm *nd.NewDeploy, gpm *gpm.GenericPoolManager) {
	for _, f := range funcs {
		var err error

		switch f.Spec.InvokeStrategy.ExecutionStrategy.ExecutorType {
		case fv1.ExecutorTypeNewdeploy:
			err = ndm.RefreshFuncPods(logger, f)
		case fv1.ExecutorTypePoolmgr:
			err = gpm.RefreshFuncPods(logger, f)
		}

		if err != nil {
			logger.Error("Failed to recycle pods for function after configmap changed",
				zap.Error(err),
				zap.Any("function", f))
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2019 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package stack

import (
	"fmt"

	"gvisor.dev/gvisor/pkg/log"
	"gvisor.dev/gvisor/pkg/tcpip"
	"gvisor.dev/gvisor/pkg/tcpip/header"
)

// AcceptTarget accepts packets.
type AcceptTarget struct {
	// NetworkProtocol is the network protocol the target is used with.
	NetworkProtocol tcpip.NetworkProtocolNumber
}

// Action implements Target.Action.
func (*AcceptTarget) Action(*PacketBuffer, Hook, *Route, AddressableEndpoint) (RuleVerdict, int) {
	return RuleAccept, 0
}

// DropTarget drops packets.
type DropTarget struct {
	// NetworkProtocol is the network protocol the target is used with.
	NetworkProtocol tcpip.NetworkProtocolNumber
}

// Action implements Target.Action.
func (*DropTarget) Action(*PacketBuffer, Hook, *Route, AddressableEndpoint) (RuleVerdict, int) {
	return RuleDrop, 0
}

// ErrorTarget logs an error and drops the packet. It represents a target that
// should be unreachable.
type ErrorTarget struct {
	// NetworkProtocol is the network protocol the target is used with.
	NetworkProtocol tcpip.NetworkProtocolNumber
}

// Action implements Target.Action.
func (*ErrorTarget) Action(*PacketBuffer, Hook, *Route, AddressableEndpoint) (RuleVerdict, int) {
	log.Debugf("ErrorTarget triggered.")
	return RuleDrop, 0
}

// UserChainTarget marks a rule as the beginning of a user chain.
type UserChainTarget struct {
	// Name is the chain name.
	Name string

	// NetworkProtocol is the network protocol the target is used with.
	NetworkProtocol tcpip.NetworkProtocolNumber
}

// Action implements Target.Action.
func (*UserChainTarget) Action(*PacketBuffer, Hook, *Route, AddressableEndpoint) (RuleVerdict, int) {
	panic("UserChainTarget should never be called.")
}

// ReturnTarget returns from the current chain. If the chain is a built-in, the
// hook's underflow should be called.
type ReturnTarget struct {
	// NetworkProtocol is the network protocol the target is used with.
	NetworkProtocol tcpip.NetworkProtocolNumber
}

// Action implements Target.Action.
func (*ReturnTarget) Action(*PacketBuffer, Hook, *Route, AddressableEndpoint) (RuleVerdict, int) {
	return RuleReturn, 0
}

// RedirectTarget redirects the packet to this machine by modifying the
// destination port/IP. Outgoing packets are redirected to the loopback device,
// and incoming packets are redirected to the incoming interface (rather than
// forwarded).
type RedirectTarget struct {
	// Port indicates port used to redirect. It is immutable.
	Port uint16

	// NetworkProtocol is the network protocol the target is used with. It
	// is immutable.
	NetworkProtocol tcpip.NetworkProtocolNumber
}

// Action implements Target.Action.
func (rt *RedirectTarget) Action(pkt *PacketBuffer, hook Hook, r *Route, addressEP AddressableEndpoint) (RuleVerdict, int) {
	// Sanity check.
	if rt.NetworkProtocol != pkt.NetworkProtocolNumber {
		panic(fmt.Sprintf(
			"RedirectTarget.Action with NetworkProtocol %d called on packet with NetworkProtocolNumber %d",
			rt.NetworkProtocol, pkt.NetworkProtocolNumber))
	}

	// Packet is already manipulated.
	if pkt.NatDone {
		return RuleAccept, 0
	}

	// Drop the packet if network and transport header are not set.
	if pkt.NetworkHeader().View().IsEmpty() || pkt.TransportHeader().View().IsEmpty() {
		return RuleDrop, 0
	}

	// Change the address to loopback (127.0.0.1 or ::1) in Output and to
	// the primary address of the incoming interface in Prerouting.
	var address tcpip.Address
	switch hook {
	case Output:
		if pkt.NetworkProtocolNumber == header.IPv4ProtocolNumber {
			address = tcpip.Address([]byte{127, 0, 0, 1})
		} else {
			address = header.IPv6Loopback
		}
	case Prerouting:
		// addressEP is expected to be set for the prerouting hook.
		address = addressEP.MainAddress().Address
	default:
		panic("redirect target is supported only on output and prerouting hooks")
	}

	switch protocol := pkt.TransportProtocolNumber; protocol {
	case header.UDPProtocolNumber:
		udpHeader := header.UDP(pkt.TransportHeader().View())

		if hook == Output {
			// Only calculate the checksum if offloading isn't supported.
			requiresChecksum := r.RequiresTXTransportChecksum()
			rewritePacket(
				pkt.Network(),
				udpHeader,
				false, /* updateSRCFields */
				requiresChecksum,
				requiresChecksum,
				rt.Port,
				address,
			)
		} else {
			udpHeader.SetDestinationPort(rt.Port)
		}

		pkt.NatDone = true
	case header.TCPProtocolNumber:
		if t := pkt.tuple; t != nil {
			t.conn.performNAT(pkt, hook, r, rt.Port, address, true /* dnat */)
		}
	default:
		return RuleDrop, 0
	}

	return RuleAccept, 0
}

// SNATTarget modifies the source port/IP in the outgoing packets.
type SNATTarget struct {
	Addr tcpip.Address
	Port uint16

	// NetworkProtocol is the network protocol the target is used with. It
	// is immutable.
	NetworkProtocol tcpip.NetworkProtocolNumber
}

func snatAction(pkt *PacketBuffer, hook Hook, r *Route, port uint16, address tcpip.Address) (RuleVerdict, int) {
	// Packet is already manipulated.
	if pkt.NatDone {
		return RuleAccept, 0
	}

	// Drop the packet if network and transport header are not set.
	if pkt.NetworkHeader().View().IsEmpty() || pkt.TransportHeader().View().IsEmpty() {
		return RuleDrop, 0
	}

	// TODO(https://gvisor.dev/issue/5773): If the port is in use, pick a
	// different port.
	if port == 0 {
		switch protocol := pkt.TransportProtocolNumber; protocol {
		case header.UDPProtocolNumber:
			port = header.UDP(pkt.TransportHeader().View()).SourcePort()
		case header.TCPProtocolNumber:
			port = header.TCP(pkt.TransportHeader().View()).SourcePort()
		}
	}

	if t := pkt.tuple; t != nil {
		t.conn.performNAT(pkt, hook, r, port, address, false /* dnat */)
	}

	return RuleAccept, 0
}

// Action implements Target.Action.
func (st *SNATTarget) Action(pkt *PacketBuffer, hook Hook, r *Route, _ AddressableEndpoint) (RuleVerdict, int) {
	// Sanity check.
	if st.NetworkProtocol != pkt.NetworkProtocolNumber {
		panic(fmt.Sprintf(
			"SNATTarget.Action with NetworkProtocol %d called on packet with NetworkProtocolNumber %d",
			st.NetworkProtocol, pkt.NetworkProtocolNumber))
	}

	switch hook {
	case Postrouting, Input:
	case Prerouting, Output, Forward:
		panic(fmt.Sprintf("%s not supported", hook))
	default:
		panic(fmt.Sprintf("%s unrecognized", hook))
	}

	return snatAction(pkt, hook, r, st.Port, st.Addr)
}

// MasqueradeTarget modifies the source port/IP in the outgoing packets.
type MasqueradeTarget struct {
	// NetworkProtocol is the network protocol the target is used with. It
	// is immutable.
	NetworkProtocol tcpip.NetworkProtocolNumber
}

// Action implements Target.Action.
func (mt *MasqueradeTarget) Action(pkt *PacketBuffer, hook Hook, r *Route, addressEP AddressableEndpoint) (RuleVerdict, int) {
	// Sanity check.
	if mt.NetworkProtocol != pkt.NetworkProtocolNumber {
		panic(fmt.Sprintf(
			"MasqueradeTarget.Action with NetworkProtocol %d called on packet with NetworkProtocolNumber %d",
			mt.NetworkProtocol, pkt.NetworkProtocolNumber))
	}

	switch hook {
	case Postrouting:
	case Prerouting, Input, Forward, Output:
		panic(fmt.Sprintf("masquerade target is supported only on postrouting hook; hook = %d", hook))
	default:
		panic(fmt.Sprintf("%s unrecognized", hook))
	}

	// addressEP is expected to be set for the postrouting hook.
	ep := addressEP.AcquireOutgoingPrimaryAddress(pkt.Network().DestinationAddress(), false /* allowExpired */)
	if ep == nil {
		// No address exists that we can use as a source address.
		return RuleDrop, 0
	}

	address := ep.AddressWithPrefix().Address
	ep.DecRef()
	return snatAction(pkt, hook, r, 0 /* port */, address)
}

func rewritePacket(n header.Network, t header.ChecksummableTransport, updateSRCFields, fullChecksum, updatePseudoHeader bool, newPort uint16, newAddr tcpip.Address) {
	if updateSRCFields {
		if fullChecksum {
			t.SetSourcePortWithChecksumUpdate(newPort)
		} else {
			t.SetSourcePort(newPort)
		}
	} else {
		if fullChecksum {
			t.SetDestinationPortWithChecksumUpdate(newPort)
		} else {
			t.SetDestinationPort(newPort)
		}
	}

	if updatePseudoHeader {
		var oldAddr tcpip.Address
		if updateSRCFields {
			oldAddr = n.SourceAddress()
		} else {
			oldAddr = n.DestinationAddress()
		}

		t.UpdateChecksumPseudoHeaderAddress(oldAddr, newAddr, fullChecksum)
	}

	if checksummableNetHeader, ok := n.(header.ChecksummableNetwork); ok {
		if updateSRCFields {
			checksummableNetHeader.SetSourceAddressWithChecksumUpdate(newAddr)
		} else {
			checksummableNetHeader.SetDestinationAddressWithChecksumUpdate(newAddr)
		}
	} else if updateSRCFields {
		n.SetSourceAddress(newAddr)
	} else {
		n.SetDestinationAddress(newAddr)
	}
}
<commit_msg>Track UDP packets performing REDIRECT NAT<commit_after>// Copyright 2019 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package stack

import (
	"fmt"

	"gvisor.dev/gvisor/pkg/log"
	"gvisor.dev/gvisor/pkg/tcpip"
	"gvisor.dev/gvisor/pkg/tcpip/header"
)

// AcceptTarget accepts packets.
type AcceptTarget struct {
	// NetworkProtocol is the network protocol the target is used with.
	NetworkProtocol tcpip.NetworkProtocolNumber
}

// Action implements Target.Action.
func (*AcceptTarget) Action(*PacketBuffer, Hook, *Route, AddressableEndpoint) (RuleVerdict, int) {
	return RuleAccept, 0
}

// DropTarget drops packets.
type DropTarget struct {
	// NetworkProtocol is the network protocol the target is used with.
	NetworkProtocol tcpip.NetworkProtocolNumber
}

// Action implements Target.Action.
func (*DropTarget) Action(*PacketBuffer, Hook, *Route, AddressableEndpoint) (RuleVerdict, int) {
	return RuleDrop, 0
}

// ErrorTarget logs an error and drops the packet. It represents a target that
// should be unreachable.
type ErrorTarget struct {
	// NetworkProtocol is the network protocol the target is used with.
	NetworkProtocol tcpip.NetworkProtocolNumber
}

// Action implements Target.Action.
func (*ErrorTarget) Action(*PacketBuffer, Hook, *Route, AddressableEndpoint) (RuleVerdict, int) {
	log.Debugf("ErrorTarget triggered.")
	return RuleDrop, 0
}

// UserChainTarget marks a rule as the beginning of a user chain.
type UserChainTarget struct {
	// Name is the chain name.
	Name string

	// NetworkProtocol is the network protocol the target is used with.
	NetworkProtocol tcpip.NetworkProtocolNumber
}

// Action implements Target.Action.
func (*UserChainTarget) Action(*PacketBuffer, Hook, *Route, AddressableEndpoint) (RuleVerdict, int) {
	panic("UserChainTarget should never be called.")
}

// ReturnTarget returns from the current chain. If the chain is a built-in, the
// hook's underflow should be called.
type ReturnTarget struct {
	// NetworkProtocol is the network protocol the target is used with.
	NetworkProtocol tcpip.NetworkProtocolNumber
}

// Action implements Target.Action.
func (*ReturnTarget) Action(*PacketBuffer, Hook, *Route, AddressableEndpoint) (RuleVerdict, int) {
	return RuleReturn, 0
}

// RedirectTarget redirects the packet to this machine by modifying the
// destination port/IP. Outgoing packets are redirected to the loopback device,
// and incoming packets are redirected to the incoming interface (rather than
// forwarded).
type RedirectTarget struct {
	// Port indicates port used to redirect. It is immutable.
	Port uint16

	// NetworkProtocol is the network protocol the target is used with. It
	// is immutable.
	NetworkProtocol tcpip.NetworkProtocolNumber
}

// Action implements Target.Action.
func (rt *RedirectTarget) Action(pkt *PacketBuffer, hook Hook, r *Route, addressEP AddressableEndpoint) (RuleVerdict, int) {
	// Sanity check.
	if rt.NetworkProtocol != pkt.NetworkProtocolNumber {
		panic(fmt.Sprintf(
			"RedirectTarget.Action with NetworkProtocol %d called on packet with NetworkProtocolNumber %d",
			rt.NetworkProtocol, pkt.NetworkProtocolNumber))
	}

	// Packet is already manipulated.
	if pkt.NatDone {
		return RuleAccept, 0
	}

	// Drop the packet if network and transport header are not set.
	if pkt.NetworkHeader().View().IsEmpty() || pkt.TransportHeader().View().IsEmpty() {
		return RuleDrop, 0
	}

	// Change the address to loopback (127.0.0.1 or ::1) in Output and to
	// the primary address of the incoming interface in Prerouting.
	var address tcpip.Address
	switch hook {
	case Output:
		if pkt.NetworkProtocolNumber == header.IPv4ProtocolNumber {
			address = tcpip.Address([]byte{127, 0, 0, 1})
		} else {
			address = header.IPv6Loopback
		}
	case Prerouting:
		// addressEP is expected to be set for the prerouting hook.
		address = addressEP.MainAddress().Address
	default:
		panic("redirect target is supported only on output and prerouting hooks")
	}

	if t := pkt.tuple; t != nil {
		t.conn.performNAT(pkt, hook, r, rt.Port, address, true /* dnat */)
		return RuleAccept, 0
	}

	return RuleDrop, 0
}

// SNATTarget modifies the source port/IP in the outgoing packets.
type SNATTarget struct {
	Addr tcpip.Address
	Port uint16

	// NetworkProtocol is the network protocol the target is used with. It
	// is immutable.
	NetworkProtocol tcpip.NetworkProtocolNumber
}

func snatAction(pkt *PacketBuffer, hook Hook, r *Route, port uint16, address tcpip.Address) (RuleVerdict, int) {
	// Packet is already manipulated.
	if pkt.NatDone {
		return RuleAccept, 0
	}

	// Drop the packet if network and transport header are not set.
	if pkt.NetworkHeader().View().IsEmpty() || pkt.TransportHeader().View().IsEmpty() {
		return RuleDrop, 0
	}

	// TODO(https://gvisor.dev/issue/5773): If the port is in use, pick a
	// different port.
	if port == 0 {
		switch protocol := pkt.TransportProtocolNumber; protocol {
		case header.UDPProtocolNumber:
			port = header.UDP(pkt.TransportHeader().View()).SourcePort()
		case header.TCPProtocolNumber:
			port = header.TCP(pkt.TransportHeader().View()).SourcePort()
		}
	}

	if t := pkt.tuple; t != nil {
		t.conn.performNAT(pkt, hook, r, port, address, false /* dnat */)
	}

	return RuleAccept, 0
}

// Action implements Target.Action.
func (st *SNATTarget) Action(pkt *PacketBuffer, hook Hook, r *Route, _ AddressableEndpoint) (RuleVerdict, int) {
	// Sanity check.
	if st.NetworkProtocol != pkt.NetworkProtocolNumber {
		panic(fmt.Sprintf(
			"SNATTarget.Action with NetworkProtocol %d called on packet with NetworkProtocolNumber %d",
			st.NetworkProtocol, pkt.NetworkProtocolNumber))
	}

	switch hook {
	case Postrouting, Input:
	case Prerouting, Output, Forward:
		panic(fmt.Sprintf("%s not supported", hook))
	default:
		panic(fmt.Sprintf("%s unrecognized", hook))
	}

	return snatAction(pkt, hook, r, st.Port, st.Addr)
}

// MasqueradeTarget modifies the source port/IP in the outgoing packets.
type MasqueradeTarget struct {
	// NetworkProtocol is the network protocol the target is used with. It
	// is immutable.
	NetworkProtocol tcpip.NetworkProtocolNumber
}

// Action implements Target.Action.
func (mt *MasqueradeTarget) Action(pkt *PacketBuffer, hook Hook, r *Route, addressEP AddressableEndpoint) (RuleVerdict, int) {
	// Sanity check.
	if mt.NetworkProtocol != pkt.NetworkProtocolNumber {
		panic(fmt.Sprintf(
			"MasqueradeTarget.Action with NetworkProtocol %d called on packet with NetworkProtocolNumber %d",
			mt.NetworkProtocol, pkt.NetworkProtocolNumber))
	}

	switch hook {
	case Postrouting:
	case Prerouting, Input, Forward, Output:
		panic(fmt.Sprintf("masquerade target is supported only on postrouting hook; hook = %d", hook))
	default:
		panic(fmt.Sprintf("%s unrecognized", hook))
	}

	// addressEP is expected to be set for the postrouting hook.
	ep := addressEP.AcquireOutgoingPrimaryAddress(pkt.Network().DestinationAddress(), false /* allowExpired */)
	if ep == nil {
		// No address exists that we can use as a source address.
		return RuleDrop, 0
	}

	address := ep.AddressWithPrefix().Address
	ep.DecRef()
	return snatAction(pkt, hook, r, 0 /* port */, address)
}

func rewritePacket(n header.Network, t header.ChecksummableTransport, updateSRCFields, fullChecksum, updatePseudoHeader bool, newPort uint16, newAddr tcpip.Address) {
	if updateSRCFields {
		if fullChecksum {
			t.SetSourcePortWithChecksumUpdate(newPort)
		} else {
			t.SetSourcePort(newPort)
		}
	} else {
		if fullChecksum {
			t.SetDestinationPortWithChecksumUpdate(newPort)
		} else {
			t.SetDestinationPort(newPort)
		}
	}

	if updatePseudoHeader {
		var oldAddr tcpip.Address
		if updateSRCFields {
			oldAddr = n.SourceAddress()
		} else {
			oldAddr = n.DestinationAddress()
		}

		t.UpdateChecksumPseudoHeaderAddress(oldAddr, newAddr, fullChecksum)
	}

	if checksummableNetHeader, ok := n.(header.ChecksummableNetwork); ok {
		if updateSRCFields {
			checksummableNetHeader.SetSourceAddressWithChecksumUpdate(newAddr)
		} else {
			checksummableNetHeader.SetDestinationAddressWithChecksumUpdate(newAddr)
		}
	} else if updateSRCFields {
		n.SetSourceAddress(newAddr)
	} else {
		n.SetDestinationAddress(newAddr)
	}
}
<|endoftext|>


<commit_before>// SPDX-License-Identifier: Apache-2.0
// Copyright 2018 Authors of Cilium

//go:build !privileged_tests
// +build !privileged_tests

package dnsproxy

import (
	. "gopkg.in/check.v1"
)

type DNSProxyHelperTestSuite struct{}

var _ = Suite(&DNSProxyHelperTestSuite{})
<commit_msg>dnsproxy: unit test GetSelectorRegexMap<commit_after>// SPDX-License-Identifier: Apache-2.0
// Copyright 2018 Authors of Cilium

//go:build !privileged_tests
// +build !privileged_tests

package dnsproxy

import (
	"github.com/cilium/cilium/pkg/identity"
	"github.com/cilium/cilium/pkg/policy"
	"github.com/cilium/cilium/pkg/policy/api"
	"github.com/golang/groupcache/lru"
	. "gopkg.in/check.v1"
	"testing"
)

type DNSProxyHelperTestSuite struct{}

var _ = Suite(&DNSProxyHelperTestSuite{})

// Hook up gocheck into the "go test" runner.
func TestNonPrivileged(t *testing.T) {
	TestingT(t)
}

func (s *DNSProxyHelperTestSuite) TestGetSelectorRegexMap(c *C) {
	selector := MockCachedSelector{}

	dnsName := "example.name."

	l7 := policy.L7DataMap{
		selector: &policy.PerSelectorPolicy{
			L7Rules: api.L7Rules{DNS: []api.PortRuleDNS{
				{
					MatchName: dnsName,
				},
			}},
		},
	}
	cache := &lru.Cache{}
	m, err := GetSelectorRegexMap(l7, cache)

	c.Assert(err, Equals, nil)

	regex, ok := m[selector]

	c.Assert(ok, Equals, true)

	c.Assert(regex.MatchString(dnsName), Equals, true)
	c.Assert(regex.MatchString(dnsName+"trolo"), Equals, false)
}

type MockCachedSelector struct{}

func (m MockCachedSelector) GetSelections() []identity.NumericIdentity {
	return nil
}

func (m MockCachedSelector) Selects(_ identity.NumericIdentity) bool {
	return false
}

func (m MockCachedSelector) IsWildcard() bool {
	return false
}

func (m MockCachedSelector) IsNone() bool {
	return false
}

func (m MockCachedSelector) String() string {
	return "string"
}
<|endoftext|>


<commit_before>package alerting

import (
	"errors"
	"fmt"

	"golang.org/x/sync/errgroup"

	"github.com/grafana/grafana/pkg/bus"
	"github.com/grafana/grafana/pkg/components/imguploader"
	"github.com/grafana/grafana/pkg/components/renderer"
	"github.com/grafana/grafana/pkg/log"
	m "github.com/grafana/grafana/pkg/models"
)

type RootNotifier struct {
	log log.Logger
}

func NewRootNotifier() *RootNotifier {
	return &RootNotifier{
		log: log.New("alerting.notifier"),
	}
}

func (n *RootNotifier) GetType() string {
	return "root"
}

func (n *RootNotifier) NeedsImage() bool {
	return false
}

func (n *RootNotifier) PassesFilter(rule *Rule) bool {
	return false
}

func (n *RootNotifier) GetNotifierId() int64 {
	return 0
}

func (n *RootNotifier) GetIsDefault() bool {
	return false
}

func (n *RootNotifier) Notify(context *EvalContext) error {
	notifiers, err := n.getNotifiers(context.Rule.OrgId, context.Rule.Notifications, context)
	if err != nil {
		return err
	}

	n.log.Info("Sending notifications for", "ruleId", context.Rule.Id, "sent count", len(notifiers))

	if len(notifiers) == 0 {
		return nil
	}

	err = n.uploadImage(context)
	if err != nil {
		n.log.Error("Failed to upload alert panel image", "error", err)
		return err
	}

	return n.sendNotifications(context, notifiers)
}

func (n *RootNotifier) sendNotifications(context *EvalContext, notifiers []Notifier) error {
	g, _ := errgroup.WithContext(context.Ctx)

	for _, notifier := range notifiers {
		not := notifier //avoid updating scope variable in go routine
		n.log.Info("Sending notification", "type", not.GetType(), "id", not.GetNotifierId(), "isDefault", not.GetIsDefault())
		g.Go(func() error { return not.Notify(context) })
	}

	return g.Wait()
}

func (n *RootNotifier) uploadImage(context *EvalContext) (err error) {
	uploader, err := imguploader.NewImageUploader()
	if err != nil {
		return err
	}

	renderOpts := &renderer.RenderOpts{
		Width:   "800",
		Height:  "400",
		Timeout: "30",
		OrgId:   context.Rule.OrgId,
	}

	if slug, err := context.GetDashboardSlug(); err != nil {
		return err
	} else {
		renderOpts.Path = fmt.Sprintf("dashboard-solo/db/%s?&panelId=%d", slug, context.Rule.PanelId)
	}

	if imagePath, err := renderer.RenderToPng(renderOpts); err != nil {
		return err
	} else {
		context.ImageOnDiskPath = imagePath
	}

	context.ImagePublicUrl, err = uploader.Upload(context.ImageOnDiskPath)
	if err != nil {
		return err
	}

	n.log.Info("uploaded", "url", context.ImagePublicUrl)
	return nil
}

func (n *RootNotifier) getNotifiers(orgId int64, notificationIds []int64, context *EvalContext) ([]Notifier, error) {
	query := &m.GetAlertNotificationsToSendQuery{OrgId: orgId, Ids: notificationIds}

	if err := bus.Dispatch(query); err != nil {
		return nil, err
	}

	var result []Notifier
	for _, notification := range query.Result {
		if not, err := n.createNotifierFor(notification); err != nil {
			return nil, err
		} else {
			if shouldUseNotification(not, context) {
				result = append(result, not)
			}
		}
	}

	return result, nil
}

func (n *RootNotifier) createNotifierFor(model *m.AlertNotification) (Notifier, error) {
	factory, found := notifierFactories[model.Type]
	if !found {
		return nil, errors.New("Unsupported notification type")
	}

	return factory(model)
}

func shouldUseNotification(notifier Notifier, context *EvalContext) bool {
	if !context.Firing {
		return true
	}

	if context.Error != nil {
		return true
	}

	return notifier.PassesFilter(context.Rule)
}

type NotifierFactory func(notification *m.AlertNotification) (Notifier, error)

var notifierFactories map[string]NotifierFactory = make(map[string]NotifierFactory)

func RegisterNotifier(typeName string, factory NotifierFactory) {
	notifierFactories[typeName] = factory
}
<commit_msg>fix(notifications): failed image upload should not stop notification<commit_after>package alerting

import (
	"errors"
	"fmt"

	"golang.org/x/sync/errgroup"

	"github.com/grafana/grafana/pkg/bus"
	"github.com/grafana/grafana/pkg/components/imguploader"
	"github.com/grafana/grafana/pkg/components/renderer"
	"github.com/grafana/grafana/pkg/log"
	m "github.com/grafana/grafana/pkg/models"
)

type RootNotifier struct {
	log log.Logger
}

func NewRootNotifier() *RootNotifier {
	return &RootNotifier{
		log: log.New("alerting.notifier"),
	}
}

func (n *RootNotifier) GetType() string {
	return "root"
}

func (n *RootNotifier) NeedsImage() bool {
	return false
}

func (n *RootNotifier) PassesFilter(rule *Rule) bool {
	return false
}

func (n *RootNotifier) GetNotifierId() int64 {
	return 0
}

func (n *RootNotifier) GetIsDefault() bool {
	return false
}

func (n *RootNotifier) Notify(context *EvalContext) error {
	notifiers, err := n.getNotifiers(context.Rule.OrgId, context.Rule.Notifications, context)
	if err != nil {
		return err
	}

	n.log.Info("Sending notifications for", "ruleId", context.Rule.Id, "sent count", len(notifiers))

	if len(notifiers) == 0 {
		return nil
	}

	if err = n.uploadImage(context); err != nil {
		n.log.Error("Failed to upload alert panel image.", "error", err)
	}

	return n.sendNotifications(context, notifiers)
}

func (n *RootNotifier) sendNotifications(context *EvalContext, notifiers []Notifier) error {
	g, _ := errgroup.WithContext(context.Ctx)

	for _, notifier := range notifiers {
		not := notifier //avoid updating scope variable in go routine
		n.log.Info("Sending notification", "type", not.GetType(), "id", not.GetNotifierId(), "isDefault", not.GetIsDefault())
		g.Go(func() error { return not.Notify(context) })
	}

	return g.Wait()
}

func (n *RootNotifier) uploadImage(context *EvalContext) (err error) {
	uploader, err := imguploader.NewImageUploader()
	if err != nil {
		return err
	}

	renderOpts := &renderer.RenderOpts{
		Width:   "800",
		Height:  "400",
		Timeout: "30",
		OrgId:   context.Rule.OrgId,
	}

	if slug, err := context.GetDashboardSlug(); err != nil {
		return err
	} else {
		renderOpts.Path = fmt.Sprintf("dashboard-solo/db/%s?&panelId=%d", slug, context.Rule.PanelId)
	}

	if imagePath, err := renderer.RenderToPng(renderOpts); err != nil {
		return err
	} else {
		context.ImageOnDiskPath = imagePath
	}

	context.ImagePublicUrl, err = uploader.Upload(context.ImageOnDiskPath)
	if err != nil {
		return err
	}

	n.log.Info("uploaded", "url", context.ImagePublicUrl)
	return nil
}

func (n *RootNotifier) getNotifiers(orgId int64, notificationIds []int64, context *EvalContext) ([]Notifier, error) {
	query := &m.GetAlertNotificationsToSendQuery{OrgId: orgId, Ids: notificationIds}

	if err := bus.Dispatch(query); err != nil {
		return nil, err
	}

	var result []Notifier
	for _, notification := range query.Result {
		if not, err := n.createNotifierFor(notification); err != nil {
			return nil, err
		} else {
			if shouldUseNotification(not, context) {
				result = append(result, not)
			}
		}
	}

	return result, nil
}

func (n *RootNotifier) createNotifierFor(model *m.AlertNotification) (Notifier, error) {
	factory, found := notifierFactories[model.Type]
	if !found {
		return nil, errors.New("Unsupported notification type")
	}

	return factory(model)
}

func shouldUseNotification(notifier Notifier, context *EvalContext) bool {
	if !context.Firing {
		return true
	}

	if context.Error != nil {
		return true
	}

	return notifier.PassesFilter(context.Rule)
}

type NotifierFactory func(notification *m.AlertNotification) (Notifier, error)

var notifierFactories map[string]NotifierFactory = make(map[string]NotifierFactory)

func RegisterNotifier(typeName string, factory NotifierFactory) {
	notifierFactories[typeName] = factory
}
<|endoftext|>


<commit_before>package slack

// @NOTE: Blocks are in beta and subject to change.

// More Information: https://api.slack.com/block-kit

// MessageBlockType defines a named string type to define each block type
// as a constant for use within the package.
type MessageBlockType string

const (
	MBTSection MessageBlockType = "section"
	MBTDivider MessageBlockType = "divider"
	MBTImage   MessageBlockType = "image"
	MBTAction  MessageBlockType = "actions"
	MBTContext MessageBlockType = "context"
)

// Block defines an interface all block types should implement
// to ensure consistency between blocks.
type Block interface {
	BlockType() MessageBlockType
}

// Blocks is a convenience struct defined to allow dynamic unmarshalling of
// the "blocks" value in Slack's JSON response, which varies depending on block type
type Blocks struct {
	BlockSet []Block `json:"blocks,omitempty"`
}

// BlockAction is the action callback sent when a block is interacted with
type BlockAction struct {
	ActionID             string            `json:"action_id"`
	BlockID              string            `json:"block_id"`
	Type                 actionType        `json:"type"`
	Text                 TextBlockObject   `json:"text"`
	Value                string            `json:"value"`
	ActionTs             string            `json:"action_ts"`
	SelectedOption       OptionBlockObject `json:"selected_option"`
	SelectedUser         string            `json:"selected_user"`
	SelectedChannel      string            `json:"selected_channel"`
	SelectedConversation string            `json:"selected_conversation"`
	SelectedDate         string            `json:"selected_date"`
	InitialOption        OptionBlockObject `json:"initial_option"`
	InitialUser          string            `json:"initial_user"`
	InitialChannel       string            `json:"initial_channel"`
	InitialConversation  string            `json:"initial_conversation"`
	InitialDate          string            `json:"initial_date"`
}

// actionType returns the type of the action
func (b BlockAction) actionType() actionType {
	return b.Type
}

// NewBlockMessage creates a new Message that contains one or more blocks to be displayed
func NewBlockMessage(blocks ...Block) Message {
	return Message{
		Msg: Msg{
			Blocks: Blocks{
				BlockSet: blocks,
			},
		},
	}
}

// AddBlockMessage appends a block to the end of the existing list of blocks
func AddBlockMessage(message Message, newBlk Block) Message {
	message.Msg.Blocks.BlockSet = append(message.Msg.Blocks.BlockSet, newBlk)
	return message
}
<commit_msg>Add BlockAction missing SelectedOptions field<commit_after>package slack

// @NOTE: Blocks are in beta and subject to change.

// More Information: https://api.slack.com/block-kit

// MessageBlockType defines a named string type to define each block type
// as a constant for use within the package.
type MessageBlockType string

const (
	MBTSection MessageBlockType = "section"
	MBTDivider MessageBlockType = "divider"
	MBTImage   MessageBlockType = "image"
	MBTAction  MessageBlockType = "actions"
	MBTContext MessageBlockType = "context"
)

// Block defines an interface all block types should implement
// to ensure consistency between blocks.
type Block interface {
	BlockType() MessageBlockType
}

// Blocks is a convenience struct defined to allow dynamic unmarshalling of
// the "blocks" value in Slack's JSON response, which varies depending on block type
type Blocks struct {
	BlockSet []Block `json:"blocks,omitempty"`
}

// BlockAction is the action callback sent when a block is interacted with
type BlockAction struct {
	ActionID             string              `json:"action_id"`
	BlockID              string              `json:"block_id"`
	Type                 actionType          `json:"type"`
	Text                 TextBlockObject     `json:"text"`
	Value                string              `json:"value"`
	ActionTs             string              `json:"action_ts"`
	SelectedOption       OptionBlockObject   `json:"selected_option"`
	SelectedOptions      []OptionBlockObject `json:"selected_options"`
	SelectedUser         string              `json:"selected_user"`
	SelectedChannel      string              `json:"selected_channel"`
	SelectedConversation string              `json:"selected_conversation"`
	SelectedDate         string              `json:"selected_date"`
	InitialOption        OptionBlockObject   `json:"initial_option"`
	InitialUser          string              `json:"initial_user"`
	InitialChannel       string              `json:"initial_channel"`
	InitialConversation  string              `json:"initial_conversation"`
	InitialDate          string              `json:"initial_date"`
}

// actionType returns the type of the action
func (b BlockAction) actionType() actionType {
	return b.Type
}

// NewBlockMessage creates a new Message that contains one or more blocks to be displayed
func NewBlockMessage(blocks ...Block) Message {
	return Message{
		Msg: Msg{
			Blocks: Blocks{
				BlockSet: blocks,
			},
		},
	}
}

// AddBlockMessage appends a block to the end of the existing list of blocks
func AddBlockMessage(message Message, newBlk Block) Message {
	message.Msg.Blocks.BlockSet = append(message.Msg.Blocks.BlockSet, newBlk)
	return message
}
<|endoftext|>


<commit_before>package logging

import (
	"bytes"
	"fmt"
	"io"
)

// ErrorLogger provides the interface for outputting errors to a log sink
type ErrorLogger interface {
	Error(parameters ...interface{})
}

// Logger defines the expected methods to be provided by logging infrastructure.
// This interface uses different idioms than those used by golang's stdlib Logger.
type Logger interface {
	ErrorLogger

	Trace(parameters ...interface{})
	Debug(parameters ...interface{})
	Info(parameters ...interface{})
	Warn(parameters ...interface{})
}

// PrintLogger exposes a Printf method for infrastructure that uses that method
// for logging.
type PrintLogger struct {
	logger Logger
}

func (printLogger PrintLogger) Printf(format string, parameters ...interface{}) {
	allParameters := make([]interface{}, 0, len(parameters)+1)
	allParameters[0] = format
	copy(allParameters[1:], parameters)

	printLogger.logger.Info(allParameters...)
}

const (
	traceLevel string = "[TRACE] "
	debugLevel string = "[DEBUG] "
	infoLevel  string = "[INFO]  "
	warnLevel  string = "[WARN]  "
	errorLevel string = "[ERROR] "
	fatalLevel string = "[FATAL] "
)

// LoggerWriter is a default, built-in logging type that simply writes output
// to an embedded io.Writer.  This is a "poor man's" Logger.  It should normally
// only be used in utilities and tests.
//
// This logger will panic if any io errors occur.
type LoggerWriter struct {
	io.Writer
}

func (l *LoggerWriter) logf(level, format string, parameters []interface{}) {
	var buffer bytes.Buffer
	buffer.WriteString(level)

	if _, err := fmt.Fprintf(&buffer, format, parameters...); err != nil {
		panic(err)
	}

	buffer.WriteRune('\n')
	if _, err := l.Write(buffer.Bytes()); err != nil {
		panic(err)
	}
}

func (l *LoggerWriter) formatf(level string, parameters []interface{}) {
	if len(parameters) > 0 {
		format, ok := parameters[0].(string)
		if !ok {
			if stringer, ok := parameters[0].(fmt.Stringer); ok {
				format = stringer.String()
			} else {
				format = fmt.Sprintf("%v", parameters[0])
			}
		}

		l.logf(level, format, parameters[1:])
	} else {
		l.logf(level, "", parameters)
	}
}

func (l *LoggerWriter) Trace(parameters ...interface{}) { l.formatf(traceLevel, parameters) }
func (l *LoggerWriter) Debug(parameters ...interface{}) { l.formatf(debugLevel, parameters) }
func (l *LoggerWriter) Info(parameters ...interface{})  { l.formatf(infoLevel, parameters) }
func (l *LoggerWriter) Warn(parameters ...interface{})  { l.formatf(warnLevel, parameters) }
func (l *LoggerWriter) Error(parameters ...interface{}) { l.formatf(errorLevel, parameters) }

func (l *LoggerWriter) Printf(format string, parameters ...interface{}) {
	l.logf(infoLevel, format, parameters)
}
<commit_msg>Export delegate field<commit_after>package logging

import (
	"bytes"
	"fmt"
	"io"
)

// ErrorLogger provides the interface for outputting errors to a log sink
type ErrorLogger interface {
	Error(parameters ...interface{})
}

// Logger defines the expected methods to be provided by logging infrastructure.
// This interface uses different idioms than those used by golang's stdlib Logger.
type Logger interface {
	ErrorLogger

	Trace(parameters ...interface{})
	Debug(parameters ...interface{})
	Info(parameters ...interface{})
	Warn(parameters ...interface{})
}

// PrintLogger exposes a Printf method for infrastructure that uses that method
// for logging.
type PrintLogger struct {
	Delegate Logger
}

func (printLogger PrintLogger) Printf(format string, parameters ...interface{}) {
	allParameters := make([]interface{}, 0, len(parameters)+1)
	allParameters[0] = format
	copy(allParameters[1:], parameters)

	printLogger.Delegate.Info(allParameters...)
}

const (
	traceLevel string = "[TRACE] "
	debugLevel string = "[DEBUG] "
	infoLevel  string = "[INFO]  "
	warnLevel  string = "[WARN]  "
	errorLevel string = "[ERROR] "
	fatalLevel string = "[FATAL] "
)

// LoggerWriter is a default, built-in logging type that simply writes output
// to an embedded io.Writer.  This is a "poor man's" Logger.  It should normally
// only be used in utilities and tests.
//
// This logger will panic if any io errors occur.
type LoggerWriter struct {
	io.Writer
}

func (l *LoggerWriter) logf(level, format string, parameters []interface{}) {
	var buffer bytes.Buffer
	buffer.WriteString(level)

	if _, err := fmt.Fprintf(&buffer, format, parameters...); err != nil {
		panic(err)
	}

	buffer.WriteRune('\n')
	if _, err := l.Write(buffer.Bytes()); err != nil {
		panic(err)
	}
}

func (l *LoggerWriter) formatf(level string, parameters []interface{}) {
	if len(parameters) > 0 {
		format, ok := parameters[0].(string)
		if !ok {
			if stringer, ok := parameters[0].(fmt.Stringer); ok {
				format = stringer.String()
			} else {
				format = fmt.Sprintf("%v", parameters[0])
			}
		}

		l.logf(level, format, parameters[1:])
	} else {
		l.logf(level, "", parameters)
	}
}

func (l *LoggerWriter) Trace(parameters ...interface{}) { l.formatf(traceLevel, parameters) }
func (l *LoggerWriter) Debug(parameters ...interface{}) { l.formatf(debugLevel, parameters) }
func (l *LoggerWriter) Info(parameters ...interface{})  { l.formatf(infoLevel, parameters) }
func (l *LoggerWriter) Warn(parameters ...interface{})  { l.formatf(warnLevel, parameters) }
func (l *LoggerWriter) Error(parameters ...interface{}) { l.formatf(errorLevel, parameters) }

func (l *LoggerWriter) Printf(format string, parameters ...interface{}) {
	l.logf(infoLevel, format, parameters)
}
<|endoftext|>