<commit_before>package interp

import (
	"log"
	"reflect"
	"strconv"
)

// Cat defines interpreter type categories
type Cat uint

// Types for go language
const (
	UnsetT Cat = iota
	AliasT
	ArrayT
	BinT
	BinPkgT
	BoolT
	BuiltinT
	ByteT
	ChanT
	Complex64T
	Complex128T
	ErrorT
	Float32T
	Float64T
	FuncT
	InterfaceT
	IntT
	Int8T
	Int16T
	Int32T
	Int64T
	MapT
	PtrT
	RuneT
	SrcPkgT
	StringT
	StructT
	UintT
	Uint8T
	Uint16T
	Uint32T
	Uint64T
	UintptrT
	ValueT
)

var cats = [...]string{
	UnsetT:      "UnsetT",
	AliasT:      "AliasT",
	ArrayT:      "ArrayT",
	BinT:        "BinT",
	BinPkgT:     "BinPkgT",
	ByteT:       "ByteT",
	BoolT:       "BoolT",
	BuiltinT:    "BuiltinT",
	ChanT:       "ChanT",
	Complex64T:  "Complex64T",
	Complex128T: "Complex128T",
	ErrorT:      "ErrorT",
	Float32T:    "Float32",
	Float64T:    "Float64T",
	FuncT:       "FuncT",
	InterfaceT:  "InterfaceT",
	IntT:        "IntT",
	Int8T:       "Int8T",
	Int16T:      "Int16T",
	Int32T:      "Int32T",
	Int64T:      "Int64T",
	MapT:        "MapT",
	PtrT:        "PtrT",
	RuneT:       "RuneT",
	SrcPkgT:     "SrcPkgT",
	StringT:     "StringT",
	StructT:     "StructT",
	UintT:       "UintT",
	Uint8T:      "Uint8T",
	Uint16T:     "Uint16T",
	Uint32T:     "Uint32T",
	Uint64T:     "Uint64T",
	UintptrT:    "UintptrT",
	ValueT:      "ValueT",
}

func (c Cat) String() string {
	if c < Cat(len(cats)) {
		return cats[c]
	}
	return "Cat(" + strconv.Itoa(int(c)) + ")"
}

// StructField type defines a field in a struct
type StructField struct {
	name string
	typ  *Type
}

// Type defines the internal representation of types in the interpreter
type Type struct {
	cat        Cat           // Type category
	field      []StructField // Array of struct fields if StrucT or nil
	key        *Type         // Type of key element if MapT or nil
	val        *Type         // Type of value element if ChanT, MapT, PtrT, AliasT or ArrayT
	arg        []*Type       // Argument types if FuncT or nil
	ret        []*Type       // Return types if FuncT or nil
	method     []*Node       // Associated methods or nil
	size       int           // Size of array if ArrayT
	rtype      reflect.Type  // Reflection type if ValueT, or nil
	variadic   bool          // true if type is variadic
	incomplete bool          // true if type must be parsed again
	node       *Node         // root AST node of type definition
	scope      *Scope
}

// return a type definition for the corresponding AST subtree
func nodeType(interp *Interpreter, scope *Scope, n *Node) *Type {
	if n.typ != nil && !n.typ.incomplete {
		return n.typ
	}

	var t = &Type{node: n, scope: scope}

	switch n.kind {
	case Address, StarExpr:
		t.cat = PtrT
		t.val = nodeType(interp, scope, n.child[0])
		t.incomplete = t.val.incomplete

	case ArrayType:
		t.cat = ArrayT
		if len(n.child) > 1 {
			// An array size is defined
			var ok bool
			if t.size, ok = n.child[0].val.(int); !ok {
				if sym, _, ok := scope.lookup(n.child[0].ident); ok {
					// Resolve symbol to get size value
					if sym.typ != nil && sym.typ.cat == IntT {
						if t.size, ok = sym.val.(int); !ok {
							t.incomplete = true
						}
					} else {
						t.incomplete = true
					}
				} else {
					t.incomplete = true
				}
			}
			t.val = nodeType(interp, scope, n.child[1])
			t.incomplete = t.incomplete || t.val.incomplete
		} else {
			t.val = nodeType(interp, scope, n.child[0])
			t.incomplete = t.val.incomplete
		}

	case BasicLit:
		switch n.val.(type) {
		case bool:
			t.cat = BoolT
		case byte:
			t.cat = ByteT
		case float32:
			t.cat = Float32T
		case float64:
			t.cat = Float64T
		case int:
			t.cat = IntT
		case string:
			t.cat = StringT
		default:
			log.Panicf("Missing support for basic type %T, node %v\n", n.val, n.index)
		}

	case CallExpr, CompositeLitExpr:
		t = nodeType(interp, scope, n.child[0])

	case ChanType:
		t.cat = ChanT
		t.val = nodeType(interp, scope, n.child[0])
		t.incomplete = t.val.incomplete

	case Ellipsis:
		t = nodeType(interp, scope, n.child[0])
		t.variadic = true

	case FuncType:
		t.cat = FuncT
		for _, arg := range n.child[0].child {
			typ := nodeType(interp, scope, arg.child[len(arg.child)-1])
			t.arg = append(t.arg, typ)
			t.incomplete = t.incomplete || typ.incomplete
		}
		if len(n.child) == 2 {
			for _, ret := range n.child[1].child {
				typ := nodeType(interp, scope, ret.child[len(ret.child)-1])
				t.ret = append(t.ret, typ)
				t.incomplete = t.incomplete || typ.incomplete
			}
		}

	case Ident:
		if sym, _, found := scope.lookup(n.ident); found {
			t = sym.typ
		} else {
			t.incomplete = true
		}

	case InterfaceType:
		t.cat = InterfaceT
		//for _, method := range n.child[0].child {
		//	t.method = append(t.method, nodeType(interp, scope, method))
		//}

	case MapType:
		t.cat = MapT
		t.key = nodeType(interp, scope, n.child[0])
		t.val = nodeType(interp, scope, n.child[1])
		t.incomplete = t.key.incomplete || t.val.incomplete

	case SelectorExpr:
		pkgName, typeName := n.child[0].ident, n.child[1].ident
		if sym, _, found := scope.lookup(pkgName); found {
			if sym.typ != nil && sym.typ.cat == BinPkgT {
				pkg := interp.binType[sym.path]
				if typ, ok := pkg[typeName]; ok {
					t.cat = ValueT
					t.rtype = typ
				} else {
					t.incomplete = true
				}
			}
		} else {
			log.Panicln("unknown package", pkgName)
		}
		// TODO: handle pkgsrc types

	case StructType:
		t.cat = StructT
		for _, c := range n.child[0].child {
			if len(c.child) == 1 {
				typ := nodeType(interp, scope, c.child[0])
				t.field = append(t.field, StructField{typ: typ})
				t.incomplete = t.incomplete || typ.incomplete
			} else {
				l := len(c.child)
				typ := nodeType(interp, scope, c.child[l-1])
				t.incomplete = t.incomplete || typ.incomplete
				for _, d := range c.child[:l-1] {
					t.field = append(t.field, StructField{name: d.ident, typ: typ})
				}
			}
		}

	default:
		log.Panicln("type definition not implemented for node", n.index, n.kind)
	}

	return t
}

var zeroValues = [...]interface{}{
	BoolT:       false,
	ByteT:       byte(0),
	Complex64T:  complex64(0),
	Complex128T: complex128(0),
	ErrorT:      error(nil),
	Float32T:    float32(0),
	Float64T:    float64(0),
	IntT:        int(0),
	Int8T:       int8(0),
	Int16T:      int16(0),
	Int32T:      int32(0),
	Int64T:      int64(0),
	RuneT:       rune(0),
	StringT:     "",
	UintT:       uint(0),
	Uint8T:      uint8(0),
	Uint16T:     uint16(0),
	Uint32T:     uint32(0),
	Uint64T:     uint64(0),
	UintptrT:    uintptr(0),
}

// zero instantiates and return a zero value object for the given type during execution
func (t *Type) zero() interface{} {
	if t.incomplete {
		// Re-parse type at execution in lazy mode. Hopefully missing info is now present
		t = nodeType(t.node.interp, t.scope, t.node)
		t.node.typ = t
		if t.incomplete {
			log.Panicln("incomplete type", t.node.index)
		}
	}

	switch t.cat {
	case AliasT:
		return t.val.zero()

	case ArrayT:
		//a := make([]interface{}, t.size)
		//z := t.val.zero()
		//for i := 0; i < t.size; i++ {
		//	a[i] = z
		//}
		//return a
		if t.size > 0 {
			return reflect.MakeSlice(reflect.SliceOf(reflect.TypeOf(t.val.zero())), t.size, t.size).Interface()
		} else {
			return reflect.Zero(reflect.SliceOf(reflect.TypeOf(t.val.zero()))).Interface()
		}

	case StructT:
		z := make([]interface{}, len(t.field))
		for i, f := range t.field {
			z[i] = f.typ.zero()
		}
		return z

	case ValueT:
		return reflect.New(t.rtype).Elem().Interface()

	default:
		return zeroValues[t.cat]
	}
}

// fieldType returns the field type of a struct or *struct type
func (t *Type) fieldType(index int) *Type {
	if t.cat == PtrT {
		return t.val.fieldType(index)
	}
	return t.field[index].typ
}

// fieldIndex returns the field index from name in a struct, or -1 if not found
func (t *Type) fieldIndex(name string) int {
	if t.cat == PtrT {
		return t.val.fieldIndex(name)
	}
	for i, field := range t.field {
		if name == field.name {
			return i
		}
	}
	return -1
}

// lookupField return a list of indices, i.e. a path to access a field in a struct object
func (t *Type) lookupField(name string) []int {
	var index []int
	if fi := t.fieldIndex(name); fi < 0 {
		for i, f := range t.field {
			if f.name == "" {
				if index2 := f.typ.lookupField(name); len(index2) > 0 {
					index = append([]int{i}, index2...)
					break
				}
			}
		}
	} else {
		index = append(index, fi)
	}
	return index
}

// getMethod returns a pointer to the method definition
func (t *Type) getMethod(name string) *Node {
	for _, m := range t.method {
		if name == m.ident {
			return m
		}
	}
	return nil
}

// lookupMethod returns a pointer to method definition associated to type t
// and the list of indices to access the right struct field, in case of a promoted method
func (t *Type) lookupMethod(name string) (*Node, []int) {
	if t.cat == PtrT {
		m, index := t.val.lookupMethod(name)
		return m, index
	}
	var index []int
	if m := t.getMethod(name); m == nil {
		for i, f := range t.field {
			if f.name == "" {
				if m, index2 := f.typ.lookupMethod(name); m != nil {
					index = append([]int{i}, index2...)
					return m, index
				}
			}
		}
	} else {
		return m, index
	}
	return nil, index
}

// ptrTo returns the pointer type with element t.
func ptrTo(t *Type) *Type {
	return &Type{cat: PtrT, val: t}
}

// TypeOf returns the reflection type of dynamic interpreter type t.
func (t *Type) TypeOf() reflect.Type {
	switch t.cat {
	case ArrayT:
		return reflect.SliceOf(t.val.TypeOf())

	case ChanT:
		return reflect.ChanOf(reflect.BothDir, t.val.TypeOf())

	case ErrorT:
		var e = new(error)
		return reflect.TypeOf(e).Elem()

	case FuncT:
		in := make([]reflect.Type, len(t.arg))
		out := make([]reflect.Type, len(t.ret))
		for i, v := range t.arg {
			in[i] = v.TypeOf()
		}
		for i, v := range t.ret {
			out[i] = v.TypeOf()
		}
		return reflect.FuncOf(in, out, false)

	case MapT:
		return reflect.MapOf(t.key.TypeOf(), t.val.TypeOf())

	case PtrT:
		return reflect.PtrTo(t.val.TypeOf())

	case StructT:
		var fields = []reflect.StructField{}
		for _, f := range t.field {
			if !canExport(f.name) {
				continue
			}
			fields = append(fields, reflect.StructField{Name: f.name, Type: f.typ.TypeOf()})
		}
		return reflect.StructOf(fields)

	case ValueT:
		return t.rtype

	default:
		return reflect.TypeOf(t.zero())
	}
}
<commit_msg>type zero method now returns a reflect.Value<commit_after>package interp

import (
	"log"
	"reflect"
	"strconv"
)

// Cat defines interpreter type categories
type Cat uint

// Types for go language
const (
	UnsetT Cat = iota
	AliasT
	ArrayT
	BinT
	BinPkgT
	BoolT
	BuiltinT
	ByteT
	ChanT
	Complex64T
	Complex128T
	ErrorT
	Float32T
	Float64T
	FuncT
	InterfaceT
	IntT
	Int8T
	Int16T
	Int32T
	Int64T
	MapT
	PtrT
	RuneT
	SrcPkgT
	StringT
	StructT
	UintT
	Uint8T
	Uint16T
	Uint32T
	Uint64T
	UintptrT
	ValueT
	MaxT
)

var cats = [...]string{
	UnsetT:      "UnsetT",
	AliasT:      "AliasT",
	ArrayT:      "ArrayT",
	BinT:        "BinT",
	BinPkgT:     "BinPkgT",
	ByteT:       "ByteT",
	BoolT:       "BoolT",
	BuiltinT:    "BuiltinT",
	ChanT:       "ChanT",
	Complex64T:  "Complex64T",
	Complex128T: "Complex128T",
	ErrorT:      "ErrorT",
	Float32T:    "Float32",
	Float64T:    "Float64T",
	FuncT:       "FuncT",
	InterfaceT:  "InterfaceT",
	IntT:        "IntT",
	Int8T:       "Int8T",
	Int16T:      "Int16T",
	Int32T:      "Int32T",
	Int64T:      "Int64T",
	MapT:        "MapT",
	PtrT:        "PtrT",
	RuneT:       "RuneT",
	SrcPkgT:     "SrcPkgT",
	StringT:     "StringT",
	StructT:     "StructT",
	UintT:       "UintT",
	Uint8T:      "Uint8T",
	Uint16T:     "Uint16T",
	Uint32T:     "Uint32T",
	Uint64T:     "Uint64T",
	UintptrT:    "UintptrT",
	ValueT:      "ValueT",
}

func (c Cat) String() string {
	if c < Cat(len(cats)) {
		return cats[c]
	}
	return "Cat(" + strconv.Itoa(int(c)) + ")"
}

// StructField type defines a field in a struct
type StructField struct {
	name string
	typ  *Type
}

// Type defines the internal representation of types in the interpreter
type Type struct {
	cat        Cat           // Type category
	field      []StructField // Array of struct fields if StrucT or nil
	key        *Type         // Type of key element if MapT or nil
	val        *Type         // Type of value element if ChanT, MapT, PtrT, AliasT or ArrayT
	arg        []*Type       // Argument types if FuncT or nil
	ret        []*Type       // Return types if FuncT or nil
	method     []*Node       // Associated methods or nil
	size       int           // Size of array if ArrayT
	rtype      reflect.Type  // Reflection type if ValueT, or nil
	variadic   bool          // true if type is variadic
	incomplete bool          // true if type must be parsed again
	node       *Node         // root AST node of type definition
	scope      *Scope
}

// return a type definition for the corresponding AST subtree
func nodeType(interp *Interpreter, scope *Scope, n *Node) *Type {
	if n.typ != nil && !n.typ.incomplete {
		return n.typ
	}

	var t = &Type{node: n, scope: scope}

	switch n.kind {
	case Address, StarExpr:
		t.cat = PtrT
		t.val = nodeType(interp, scope, n.child[0])
		t.incomplete = t.val.incomplete

	case ArrayType:
		t.cat = ArrayT
		if len(n.child) > 1 {
			// An array size is defined
			var ok bool
			if t.size, ok = n.child[0].val.(int); !ok {
				if sym, _, ok := scope.lookup(n.child[0].ident); ok {
					// Resolve symbol to get size value
					if sym.typ != nil && sym.typ.cat == IntT {
						if t.size, ok = sym.val.(int); !ok {
							t.incomplete = true
						}
					} else {
						t.incomplete = true
					}
				} else {
					t.incomplete = true
				}
			}
			t.val = nodeType(interp, scope, n.child[1])
			t.incomplete = t.incomplete || t.val.incomplete
		} else {
			t.val = nodeType(interp, scope, n.child[0])
			t.incomplete = t.val.incomplete
		}

	case BasicLit:
		switch n.val.(type) {
		case bool:
			t.cat = BoolT
		case byte:
			t.cat = ByteT
		case float32:
			t.cat = Float32T
		case float64:
			t.cat = Float64T
		case int:
			t.cat = IntT
		case string:
			t.cat = StringT
		default:
			log.Panicf("Missing support for basic type %T, node %v\n", n.val, n.index)
		}

	case CallExpr, CompositeLitExpr:
		t = nodeType(interp, scope, n.child[0])

	case ChanType:
		t.cat = ChanT
		t.val = nodeType(interp, scope, n.child[0])
		t.incomplete = t.val.incomplete

	case Ellipsis:
		t = nodeType(interp, scope, n.child[0])
		t.variadic = true

	case FuncType:
		t.cat = FuncT
		for _, arg := range n.child[0].child {
			typ := nodeType(interp, scope, arg.child[len(arg.child)-1])
			t.arg = append(t.arg, typ)
			t.incomplete = t.incomplete || typ.incomplete
		}
		if len(n.child) == 2 {
			for _, ret := range n.child[1].child {
				typ := nodeType(interp, scope, ret.child[len(ret.child)-1])
				t.ret = append(t.ret, typ)
				t.incomplete = t.incomplete || typ.incomplete
			}
		}

	case Ident:
		if sym, _, found := scope.lookup(n.ident); found {
			t = sym.typ
		} else {
			t.incomplete = true
		}

	case InterfaceType:
		t.cat = InterfaceT
		//for _, method := range n.child[0].child {
		//	t.method = append(t.method, nodeType(interp, scope, method))
		//}

	case MapType:
		t.cat = MapT
		t.key = nodeType(interp, scope, n.child[0])
		t.val = nodeType(interp, scope, n.child[1])
		t.incomplete = t.key.incomplete || t.val.incomplete

	case SelectorExpr:
		pkgName, typeName := n.child[0].ident, n.child[1].ident
		if sym, _, found := scope.lookup(pkgName); found {
			if sym.typ != nil && sym.typ.cat == BinPkgT {
				pkg := interp.binType[sym.path]
				if typ, ok := pkg[typeName]; ok {
					t.cat = ValueT
					t.rtype = typ
				} else {
					t.incomplete = true
				}
			}
		} else {
			log.Panicln("unknown package", pkgName)
		}
		// TODO: handle pkgsrc types

	case StructType:
		t.cat = StructT
		for _, c := range n.child[0].child {
			if len(c.child) == 1 {
				typ := nodeType(interp, scope, c.child[0])
				t.field = append(t.field, StructField{typ: typ})
				t.incomplete = t.incomplete || typ.incomplete
			} else {
				l := len(c.child)
				typ := nodeType(interp, scope, c.child[l-1])
				t.incomplete = t.incomplete || typ.incomplete
				for _, d := range c.child[:l-1] {
					t.field = append(t.field, StructField{name: d.ident, typ: typ})
				}
			}
		}

	default:
		log.Panicln("type definition not implemented for node", n.index, n.kind)
	}

	return t
}

var zeroValues [MaxT]reflect.Value

func init() {
	zeroValues[BoolT] = reflect.ValueOf(false)
	zeroValues[ByteT] = reflect.ValueOf(byte(0))
	zeroValues[Complex64T] = reflect.ValueOf(complex64(0))
	zeroValues[Complex128T] = reflect.ValueOf(complex128(0))
	zeroValues[ErrorT] = reflect.ValueOf(error(nil))
	zeroValues[Float32T] = reflect.ValueOf(float32(0))
	zeroValues[Float64T] = reflect.ValueOf(float64(0))
	zeroValues[IntT] = reflect.ValueOf(int(0))
	zeroValues[Int8T] = reflect.ValueOf(int8(0))
	zeroValues[Int16T] = reflect.ValueOf(int16(0))
	zeroValues[Int32T] = reflect.ValueOf(int32(0))
	zeroValues[Int64T] = reflect.ValueOf(int64(0))
	zeroValues[RuneT] = reflect.ValueOf(rune(0))
	zeroValues[StringT] = reflect.ValueOf("")
	zeroValues[UintT] = reflect.ValueOf(uint(0))
	zeroValues[Uint8T] = reflect.ValueOf(uint8(0))
	zeroValues[Uint16T] = reflect.ValueOf(uint16(0))
	zeroValues[Uint32T] = reflect.ValueOf(uint32(0))
	zeroValues[Uint64T] = reflect.ValueOf(uint64(0))
	zeroValues[UintptrT] = reflect.ValueOf(uintptr(0))
}

// zero instantiates and return a zero value object for the given type during execution
func (t *Type) zero() reflect.Value {
	if t.incomplete {
		// Re-parse type at execution in lazy mode. Hopefully missing info is now present
		t = nodeType(t.node.interp, t.scope, t.node)
		t.node.typ = t
		if t.incomplete {
			log.Panicln("incomplete type", t.node.index)
		}
	}

	switch t.cat {
	case AliasT:
		return t.val.zero()

	case ArrayT:
		//a := make([]interface{}, t.size)
		//z := t.val.zero()
		//for i := 0; i < t.size; i++ {
		//	a[i] = z
		//}
		//return a
		if t.size > 0 {
			return reflect.MakeSlice(reflect.SliceOf(reflect.TypeOf(t.val.zero())), t.size, t.size)
		} else {
			return reflect.Zero(reflect.SliceOf(reflect.TypeOf(t.val.zero())))
		}

	case StructT:
		//z := make([]interface{}, len(t.field))
		//for i, f := range t.field {
		//	z[i] = f.typ.zero()
		//}
		return reflect.New(t.TypeOf()).Elem()

	case ValueT:
		return reflect.New(t.rtype).Elem()

	default:
		return zeroValues[t.cat]
	}
}

// fieldType returns the field type of a struct or *struct type
func (t *Type) fieldType(index int) *Type {
	if t.cat == PtrT {
		return t.val.fieldType(index)
	}
	return t.field[index].typ
}

// fieldIndex returns the field index from name in a struct, or -1 if not found
func (t *Type) fieldIndex(name string) int {
	if t.cat == PtrT {
		return t.val.fieldIndex(name)
	}
	for i, field := range t.field {
		if name == field.name {
			return i
		}
	}
	return -1
}

// lookupField return a list of indices, i.e. a path to access a field in a struct object
func (t *Type) lookupField(name string) []int {
	var index []int
	if fi := t.fieldIndex(name); fi < 0 {
		for i, f := range t.field {
			if f.name == "" {
				if index2 := f.typ.lookupField(name); len(index2) > 0 {
					index = append([]int{i}, index2...)
					break
				}
			}
		}
	} else {
		index = append(index, fi)
	}
	return index
}

// getMethod returns a pointer to the method definition
func (t *Type) getMethod(name string) *Node {
	for _, m := range t.method {
		if name == m.ident {
			return m
		}
	}
	return nil
}

// lookupMethod returns a pointer to method definition associated to type t
// and the list of indices to access the right struct field, in case of a promoted method
func (t *Type) lookupMethod(name string) (*Node, []int) {
	if t.cat == PtrT {
		m, index := t.val.lookupMethod(name)
		return m, index
	}
	var index []int
	if m := t.getMethod(name); m == nil {
		for i, f := range t.field {
			if f.name == "" {
				if m, index2 := f.typ.lookupMethod(name); m != nil {
					index = append([]int{i}, index2...)
					return m, index
				}
			}
		}
	} else {
		return m, index
	}
	return nil, index
}

// ptrTo returns the pointer type with element t.
func ptrTo(t *Type) *Type {
	return &Type{cat: PtrT, val: t}
}

// TypeOf returns the reflection type of dynamic interpreter type t.
func (t *Type) TypeOf() reflect.Type {
	switch t.cat {
	case ArrayT:
		return reflect.SliceOf(t.val.TypeOf())

	case ChanT:
		return reflect.ChanOf(reflect.BothDir, t.val.TypeOf())

	case ErrorT:
		var e = new(error)
		return reflect.TypeOf(e).Elem()

	case FuncT:
		in := make([]reflect.Type, len(t.arg))
		out := make([]reflect.Type, len(t.ret))
		for i, v := range t.arg {
			in[i] = v.TypeOf()
		}
		for i, v := range t.ret {
			out[i] = v.TypeOf()
		}
		return reflect.FuncOf(in, out, false)

	case MapT:
		return reflect.MapOf(t.key.TypeOf(), t.val.TypeOf())

	case PtrT:
		return reflect.PtrTo(t.val.TypeOf())

	case StructT:
		var fields = []reflect.StructField{}
		for _, f := range t.field {
			if !canExport(f.name) {
				continue
			}
			fields = append(fields, reflect.StructField{Name: f.name, Type: f.typ.TypeOf()})
		}
		return reflect.StructOf(fields)

	case ValueT:
		return t.rtype

	default:
		//return reflect.TypeOf(t.zero())
		return t.zero().Type()
	}
}
<|endoftext|>


<commit_before>/*
 *
 * Copyright 2014, Google Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

package transport

import (
	"fmt"
	"math"
	"sync"
	"time"

	"golang.org/x/net/http2"
)

const (
	// The default value of flow control window size in HTTP2 spec.
	defaultWindowSize = 65535
	// The initial window size for flow control.
	initialWindowSize       = defaultWindowSize * 32 // for an RPC
	initialConnWindowSize   = defaultWindowSize * 32 // for a connection
	infinity                = time.Duration(math.MaxInt64)
	defaultKeepaliveTime    = infinity
	defaultKeepaliveTimeout = time.Duration(20 * time.Second)
	defaultMaxStreamsClient = 100
)

// The following defines various control items which could flow through
// the control buffer of transport. They represent different aspects of
// control tasks, e.g., flow control, settings, streaming resetting, etc.
type windowUpdate struct {
	streamID  uint32
	increment uint32
}

func (*windowUpdate) item() {}

type settings struct {
	ack bool
	ss  []http2.Setting
}

func (*settings) item() {}

type resetStream struct {
	streamID uint32
	code     http2.ErrCode
}

func (*resetStream) item() {}

type goAway struct {
}

func (*goAway) item() {}

type flushIO struct {
}

func (*flushIO) item() {}

type ping struct {
	ack  bool
	data [8]byte
}

func (*ping) item() {}

// quotaPool is a pool which accumulates the quota and sends it to acquire()
// when it is available.
type quotaPool struct {
	c chan int

	mu    sync.Mutex
	quota int
}

// newQuotaPool creates a quotaPool which has quota q available to consume.
func newQuotaPool(q int) *quotaPool {
	qb := &quotaPool{
		c: make(chan int, 1),
	}
	if q > 0 {
		qb.c <- q
	} else {
		qb.quota = q
	}
	return qb
}

// add cancels the pending quota sent on acquired, incremented by v and sends
// it back on acquire.
func (qb *quotaPool) add(v int) {
	qb.mu.Lock()
	defer qb.mu.Unlock()
	select {
	case n := <-qb.c:
		qb.quota += n
	default:
	}
	qb.quota += v
	if qb.quota <= 0 {
		return
	}
	// After the pool has been created, this is the only place that sends on
	// the channel. Since mu is held at this point and any quota that was sent
	// on the channel has been retrieved, we know that this code will always
	// place any positive quota value on the channel.
	select {
	case qb.c <- qb.quota:
		qb.quota = 0
	default:
	}
}

// acquire returns the channel on which available quota amounts are sent.
func (qb *quotaPool) acquire() <-chan int {
	return qb.c
}

// inFlow deals with inbound flow control
type inFlow struct {
	// The inbound flow control limit for pending data.
	limit uint32

	mu sync.Mutex
	// pendingData is the overall data which have been received but not been
	// consumed by applications.
	pendingData uint32
	// The amount of data the application has consumed but grpc has not sent
	// window update for them. Used to reduce window update frequency.
	pendingUpdate uint32
}

// onData is invoked when some data frame is received. It updates pendingData.
func (f *inFlow) onData(n uint32) error {
	f.mu.Lock()
	defer f.mu.Unlock()
	f.pendingData += n
	if f.pendingData+f.pendingUpdate > f.limit {
		return fmt.Errorf("received %d-bytes data exceeding the limit %d bytes", f.pendingData+f.pendingUpdate, f.limit)
	}
	return nil
}

// onRead is invoked when the application reads the data. It returns the window size
// to be sent to the peer.
func (f *inFlow) onRead(n uint32) uint32 {
	f.mu.Lock()
	defer f.mu.Unlock()
	if f.pendingData == 0 {
		return 0
	}
	f.pendingData -= n
	f.pendingUpdate += n
	if f.pendingUpdate >= f.limit/4 {
		wu := f.pendingUpdate
		f.pendingUpdate = 0
		return wu
	}
	return 0
}

func (f *inFlow) resetPendingData() uint32 {
	f.mu.Lock()
	defer f.mu.Unlock()
	n := f.pendingData
	f.pendingData = 0
	return n
}
<commit_msg>transport: bump conn window size to 16 times RPC window size<commit_after>/*
 *
 * Copyright 2014, Google Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

package transport

import (
	"fmt"
	"math"
	"sync"
	"time"

	"golang.org/x/net/http2"
)

const (
	// The default value of flow control window size in HTTP2 spec.
	defaultWindowSize = 65535
	// The initial window size for flow control.
	initialWindowSize       = defaultWindowSize * 32 // for an RPC
	initialConnWindowSize   = initialWindowSize * 16 // for a connection
	infinity                = time.Duration(math.MaxInt64)
	defaultKeepaliveTime    = infinity
	defaultKeepaliveTimeout = time.Duration(20 * time.Second)
	defaultMaxStreamsClient = 100
)

// The following defines various control items which could flow through
// the control buffer of transport. They represent different aspects of
// control tasks, e.g., flow control, settings, streaming resetting, etc.
type windowUpdate struct {
	streamID  uint32
	increment uint32
}

func (*windowUpdate) item() {}

type settings struct {
	ack bool
	ss  []http2.Setting
}

func (*settings) item() {}

type resetStream struct {
	streamID uint32
	code     http2.ErrCode
}

func (*resetStream) item() {}

type goAway struct {
}

func (*goAway) item() {}

type flushIO struct {
}

func (*flushIO) item() {}

type ping struct {
	ack  bool
	data [8]byte
}

func (*ping) item() {}

// quotaPool is a pool which accumulates the quota and sends it to acquire()
// when it is available.
type quotaPool struct {
	c chan int

	mu    sync.Mutex
	quota int
}

// newQuotaPool creates a quotaPool which has quota q available to consume.
func newQuotaPool(q int) *quotaPool {
	qb := &quotaPool{
		c: make(chan int, 1),
	}
	if q > 0 {
		qb.c <- q
	} else {
		qb.quota = q
	}
	return qb
}

// add cancels the pending quota sent on acquired, incremented by v and sends
// it back on acquire.
func (qb *quotaPool) add(v int) {
	qb.mu.Lock()
	defer qb.mu.Unlock()
	select {
	case n := <-qb.c:
		qb.quota += n
	default:
	}
	qb.quota += v
	if qb.quota <= 0 {
		return
	}
	// After the pool has been created, this is the only place that sends on
	// the channel. Since mu is held at this point and any quota that was sent
	// on the channel has been retrieved, we know that this code will always
	// place any positive quota value on the channel.
	select {
	case qb.c <- qb.quota:
		qb.quota = 0
	default:
	}
}

// acquire returns the channel on which available quota amounts are sent.
func (qb *quotaPool) acquire() <-chan int {
	return qb.c
}

// inFlow deals with inbound flow control
type inFlow struct {
	// The inbound flow control limit for pending data.
	limit uint32

	mu sync.Mutex
	// pendingData is the overall data which have been received but not been
	// consumed by applications.
	pendingData uint32
	// The amount of data the application has consumed but grpc has not sent
	// window update for them. Used to reduce window update frequency.
	pendingUpdate uint32
}

// onData is invoked when some data frame is received. It updates pendingData.
func (f *inFlow) onData(n uint32) error {
	f.mu.Lock()
	defer f.mu.Unlock()
	f.pendingData += n
	if f.pendingData+f.pendingUpdate > f.limit {
		return fmt.Errorf("received %d-bytes data exceeding the limit %d bytes", f.pendingData+f.pendingUpdate, f.limit)
	}
	return nil
}

// onRead is invoked when the application reads the data. It returns the window size
// to be sent to the peer.
func (f *inFlow) onRead(n uint32) uint32 {
	f.mu.Lock()
	defer f.mu.Unlock()
	if f.pendingData == 0 {
		return 0
	}
	f.pendingData -= n
	f.pendingUpdate += n
	if f.pendingUpdate >= f.limit/4 {
		wu := f.pendingUpdate
		f.pendingUpdate = 0
		return wu
	}
	return 0
}

func (f *inFlow) resetPendingData() uint32 {
	f.mu.Lock()
	defer f.mu.Unlock()
	n := f.pendingData
	f.pendingData = 0
	return n
}
<|endoftext|>


<commit_before>// +build linux

package joystick

import (
	"golang.org/x/sys/unix"
	"os"
	"syscall"
	"unsafe"
)

const (
	_IOC_NRBITS   = 8
	_IOC_TYPEBITS = 8
	_IOC_SIZEBITS = 14
	_IOC_DIRBITS  = 2

	_IOC_NRMASK   = ((1 << _IOC_NRBITS) - 1)
	_IOC_TYPEMASK = ((1 << _IOC_TYPEBITS) - 1)
	_IOC_SIZEMASK = ((1 << _IOC_SIZEBITS) - 1)
	_IOC_DIRMASK  = ((1 << _IOC_DIRBITS) - 1)

	_IOC_NRSHIFT   = 0
	_IOC_TYPESHIFT = (_IOC_NRSHIFT + _IOC_NRBITS)
	_IOC_SIZESHIFT = (_IOC_TYPESHIFT + _IOC_TYPEBITS)
	_IOC_DIRSHIFT  = (_IOC_SIZESHIFT + _IOC_SIZEBITS)

	_IOC_NONE  = 0
	_IOC_WRITE = 1
	_IOC_READ  = 2
)

func _IOC(dir int, t int, nr int, size int) int {
	return (dir << _IOC_DIRSHIFT) | (t << _IOC_TYPESHIFT) | (nr << _IOC_NRSHIFT) | (size << _IOC_SIZESHIFT)
}

func _IOR(t int, nr int, size int) int {
	return IOC(_IOC_READ, t, nr, size)
}

func _IOW(t int, nr int, size int) int {
	return IOC(_IOC_WRITE, t, nr, size)
}

func ioctl(f *os.File, req int, ptr unsafe.Pointer) syscall.Errno {
	_, _, err := unix.Syscall(unix.SYS_IOCTL, uintptr(f.Fd()), uintptr(req), uintptr(ptr))
	return err
}
<commit_msg>fixed naming<commit_after>// +build linux

package joystick

import (
	"golang.org/x/sys/unix"
	"os"
	"syscall"
	"unsafe"
)

const (
	_IOC_NRBITS   = 8
	_IOC_TYPEBITS = 8
	_IOC_SIZEBITS = 14
	_IOC_DIRBITS  = 2

	_IOC_NRMASK   = ((1 << _IOC_NRBITS) - 1)
	_IOC_TYPEMASK = ((1 << _IOC_TYPEBITS) - 1)
	_IOC_SIZEMASK = ((1 << _IOC_SIZEBITS) - 1)
	_IOC_DIRMASK  = ((1 << _IOC_DIRBITS) - 1)

	_IOC_NRSHIFT   = 0
	_IOC_TYPESHIFT = (_IOC_NRSHIFT + _IOC_NRBITS)
	_IOC_SIZESHIFT = (_IOC_TYPESHIFT + _IOC_TYPEBITS)
	_IOC_DIRSHIFT  = (_IOC_SIZESHIFT + _IOC_SIZEBITS)

	_IOC_NONE  = 0
	_IOC_WRITE = 1
	_IOC_READ  = 2
)

func _IOC(dir int, t int, nr int, size int) int {
	return (dir << _IOC_DIRSHIFT) | (t << _IOC_TYPESHIFT) | (nr << _IOC_NRSHIFT) | (size << _IOC_SIZESHIFT)
}

func _IOR(t int, nr int, size int) int {
	return _IOC(_IOC_READ, t, nr, size)
}

func _IOW(t int, nr int, size int) int {
	return _IOC(_IOC_WRITE, t, nr, size)
}

func ioctl(f *os.File, req int, ptr unsafe.Pointer) syscall.Errno {
	_, _, err := unix.Syscall(unix.SYS_IOCTL, uintptr(f.Fd()), uintptr(req), uintptr(ptr))
	return err
}
<|endoftext|>


<commit_before>package check_test

import (
	"encoding/json"
	"testing"
	"time"

	"github.com/google/go-cmp/cmp"
	"github.com/google/go-cmp/cmp/cmpopts"
	"github.com/influxdata/flux/parser"
	"github.com/influxdata/influxdb/notification"

	"github.com/influxdata/influxdb/mock"

	"github.com/influxdata/influxdb"
	"github.com/influxdata/influxdb/notification/check"
	influxTesting "github.com/influxdata/influxdb/testing"
)

const (
	id1 = "020f755c3c082000"
	id2 = "020f755c3c082001"
	id3 = "020f755c3c082002"
)

var goodBase = check.Base{
	ID:                    influxTesting.MustIDBase16(id1),
	Name:                  "name1",
	OwnerID:               influxTesting.MustIDBase16(id2),
	OrgID:                 influxTesting.MustIDBase16(id3),
	StatusMessageTemplate: "temp1",
	Tags: []influxdb.Tag{
		{Key: "k1", Value: "v1"},
		{Key: "k2", Value: "v2"},
	},
}

func TestValidCheck(t *testing.T) {
	cases := []struct {
		name string
		src  influxdb.Check
		err  error
	}{
		{
			name: "invalid check id",
			src:  &check.Deadman{},
			err: &influxdb.Error{
				Code: influxdb.EInvalid,
				Msg:  "Check ID is invalid",
			},
		},
		{
			name: "empty name",
			src: &check.Threshold{
				Base: check.Base{
					ID: influxTesting.MustIDBase16(id1),
				},
			},
			err: &influxdb.Error{
				Code: influxdb.EInvalid,
				Msg:  "Check Name can't be empty",
			},
		},
		{
			name: "invalid owner id",
			src: &check.Threshold{
				Base: check.Base{
					ID:   influxTesting.MustIDBase16(id1),
					Name: "name1",
				},
			},
			err: &influxdb.Error{
				Code: influxdb.EInvalid,
				Msg:  "Check OwnerID is invalid",
			},
		},
		{
			name: "invalid org id",
			src: &check.Threshold{
				Base: check.Base{
					ID:      influxTesting.MustIDBase16(id1),
					Name:    "name1",
					OwnerID: influxTesting.MustIDBase16(id2),
				},
			},
			err: &influxdb.Error{
				Code: influxdb.EInvalid,
				Msg:  "Check OrgID is invalid",
			},
		},
		{
			name: "offset greater then interval",
			src: &check.Deadman{
				Base: check.Base{
					ID:      influxTesting.MustIDBase16(id1),
					Name:    "name1",
					OwnerID: influxTesting.MustIDBase16(id2),
					OrgID:   influxTesting.MustIDBase16(id3),
					Every:   mustDuration("1m"),
					Offset:  mustDuration("2m"),
				},
			},
			err: &influxdb.Error{
				Code: influxdb.EInvalid,
				Msg:  "Offset should not be equal or greater than the interval",
			},
		},
		{
			name: "invalid tag",
			src: &check.Deadman{
				Base: check.Base{
					ID:                    influxTesting.MustIDBase16(id1),
					Name:                  "name1",
					OwnerID:               influxTesting.MustIDBase16(id2),
					OrgID:                 influxTesting.MustIDBase16(id3),
					StatusMessageTemplate: "temp1",
					Tags:                  []influxdb.Tag{{Key: "key1"}},
				},
			},
			err: &influxdb.Error{
				Code: influxdb.EInvalid,
				Msg:  "tag must contain a key and a value",
			},
		},
		{
			name: "bad thredshold",
			src: &check.Threshold{
				Base: goodBase,
				Thresholds: []check.ThresholdConfig{
					&check.Range{Min: 200, Max: 100},
				},
			},
			err: &influxdb.Error{
				Code: influxdb.EInvalid,
				Msg:  "range threshold min can't be larger than max",
			},
		},
	}
	for _, c := range cases {
		got := c.src.Valid()
		influxTesting.ErrorsEqual(t, got, c.err)
	}
}

var timeGen1 = mock.TimeGenerator{FakeValue: time.Date(2006, time.July, 13, 4, 19, 10, 0, time.UTC)}
var timeGen2 = mock.TimeGenerator{FakeValue: time.Date(2006, time.July, 14, 5, 23, 53, 10, time.UTC)}

func mustDuration(d string) *notification.Duration {
	dur, err := parser.ParseDuration(d)
	if err != nil {
		panic(err)
	}

	return (*notification.Duration)(dur)
}

func TestJSON(t *testing.T) {
	cases := []struct {
		name string
		src  influxdb.Check
	}{
		{
			name: "simple Deadman",
			src: &check.Deadman{
				Base: check.Base{
					ID:      influxTesting.MustIDBase16(id1),
					OwnerID: influxTesting.MustIDBase16(id2),
					Name:    "name1",
					OrgID:   influxTesting.MustIDBase16(id3),
					Every:   mustDuration("1h"),
					Query: influxdb.DashboardQuery{
						BuilderConfig: influxdb.BuilderConfig{
							Buckets: []string{},
							Tags: []struct {
								Key    string   `json:"key"`
								Values []string `json:"values"`
							}{},
							Functions: []struct {
								Name string `json:"name"`
							}{},
						},
					},
					Tags: []influxdb.Tag{
						{
							Key:   "k1",
							Value: "v1",
						},
						{
							Key:   "k2",
							Value: "v2",
						},
					},
					CRUDLog: influxdb.CRUDLog{
						CreatedAt: timeGen1.Now(),
						UpdatedAt: timeGen2.Now(),
					},
				},
				TimeSince:  mustDuration("33s"),
				ReportZero: true,
				Level:      notification.Warn,
			},
		},
		{
			name: "simple threshold",
			src: &check.Threshold{
				Base: check.Base{
					ID:      influxTesting.MustIDBase16(id1),
					Name:    "name1",
					OwnerID: influxTesting.MustIDBase16(id2),
					OrgID:   influxTesting.MustIDBase16(id3),
					Every:   mustDuration("1h"),
					Query: influxdb.DashboardQuery{
						BuilderConfig: influxdb.BuilderConfig{
							Buckets: []string{},
							Tags: []struct {
								Key    string   `json:"key"`
								Values []string `json:"values"`
							}{},
							Functions: []struct {
								Name string `json:"name"`
							}{},
						},
					},
					Tags: []influxdb.Tag{
						{
							Key:   "k1",
							Value: "v1",
						},
						{
							Key:   "k2",
							Value: "v2",
						},
					},
					CRUDLog: influxdb.CRUDLog{
						CreatedAt: timeGen1.Now(),
						UpdatedAt: timeGen2.Now(),
					},
				},
				Thresholds: []check.ThresholdConfig{
					&check.Greater{ThresholdConfigBase: check.ThresholdConfigBase{AllValues: true}, Value: -1.36},
					&check.Range{Min: -10000, Max: 500},
					&check.Lesser{ThresholdConfigBase: check.ThresholdConfigBase{Level: notification.Critical}},
				},
			},
		},
	}
	for _, c := range cases {
		fn := func(t *testing.T) {
			b, err := json.Marshal(c.src)
			if err != nil {
				t.Fatalf("%s marshal failed, err: %s", c.name, err.Error())
			}
			got, err := check.UnmarshalJSON(b)
			if err != nil {
				t.Fatalf("%s unmarshal failed, err: %s", c.name, err.Error())
			}
			if diff := cmp.Diff(got, c.src, cmpopts.IgnoreFields(notification.Duration{}, "BaseNode")); diff != "" {
				t.Errorf("failed %s, Check are different -got/+want\ndiff %s", c.name, diff)
			}
		}
		t.Run(c.name, fn)
	}
}
<commit_msg>fix(tasks): validate check params new backend error message<commit_after>package check_test

import (
	"encoding/json"
	"testing"
	"time"

	"github.com/google/go-cmp/cmp"
	"github.com/google/go-cmp/cmp/cmpopts"
	"github.com/influxdata/flux/parser"
	"github.com/influxdata/influxdb/notification"

	"github.com/influxdata/influxdb/mock"

	"github.com/influxdata/influxdb"
	"github.com/influxdata/influxdb/notification/check"
	influxTesting "github.com/influxdata/influxdb/testing"
)

const (
	id1 = "020f755c3c082000"
	id2 = "020f755c3c082001"
	id3 = "020f755c3c082002"
)

var goodBase = check.Base{
	ID:                    influxTesting.MustIDBase16(id1),
	Name:                  "name1",
	OwnerID:               influxTesting.MustIDBase16(id2),
	OrgID:                 influxTesting.MustIDBase16(id3),
	StatusMessageTemplate: "temp1",
	Every:                 mustDuration("1m"),
	Tags: []influxdb.Tag{
		{Key: "k1", Value: "v1"},
		{Key: "k2", Value: "v2"},
	},
}

func TestValidCheck(t *testing.T) {
	cases := []struct {
		name string
		src  influxdb.Check
		err  error
	}{
		{
			name: "invalid check id",
			src:  &check.Deadman{},
			err: &influxdb.Error{
				Code: influxdb.EInvalid,
				Msg:  "Check ID is invalid",
			},
		},
		{
			name: "empty name",
			src: &check.Threshold{
				Base: check.Base{
					ID: influxTesting.MustIDBase16(id1),
				},
			},
			err: &influxdb.Error{
				Code: influxdb.EInvalid,
				Msg:  "Check Name can't be empty",
			},
		},
		{
			name: "invalid owner id",
			src: &check.Threshold{
				Base: check.Base{
					ID:   influxTesting.MustIDBase16(id1),
					Name: "name1",
				},
			},
			err: &influxdb.Error{
				Code: influxdb.EInvalid,
				Msg:  "Check OwnerID is invalid",
			},
		},
		{
			name: "invalid org id",
			src: &check.Threshold{
				Base: check.Base{
					ID:      influxTesting.MustIDBase16(id1),
					Name:    "name1",
					OwnerID: influxTesting.MustIDBase16(id2),
				},
			},
			err: &influxdb.Error{
				Code: influxdb.EInvalid,
				Msg:  "Check OrgID is invalid",
			},
		},
		{
			name: "nil every",
			src: &check.Deadman{
				Base: check.Base{
					ID:                    influxTesting.MustIDBase16(id1),
					Name:                  "name1",
					OwnerID:               influxTesting.MustIDBase16(id2),
					OrgID:                 influxTesting.MustIDBase16(id3),
					StatusMessageTemplate: "temp1",
					Tags:                  []influxdb.Tag{{Key: "key1"}},
				},
			},
			err: &influxdb.Error{
				Code: influxdb.EInvalid,
				Msg:  "Check Every must exist",
			},
		},
		{
			name: "empty every",
			src: &check.Deadman{
				Base: check.Base{
					ID:                    influxTesting.MustIDBase16(id1),
					Name:                  "name1",
					OwnerID:               influxTesting.MustIDBase16(id2),
					OrgID:                 influxTesting.MustIDBase16(id3),
					StatusMessageTemplate: "temp1",
					Every:                 mustDuration("0"),
					Tags:                  []influxdb.Tag{{Key: "key1"}},
				},
			},
			err: &influxdb.Error{
				Code: influxdb.EInvalid,
				Msg:  "Check Every can't be empty",
			},
		},
		{
			name: "empty offset",
			src: &check.Deadman{
				Base: check.Base{
					ID:                    influxTesting.MustIDBase16(id1),
					Name:                  "name1",
					OwnerID:               influxTesting.MustIDBase16(id2),
					OrgID:                 influxTesting.MustIDBase16(id3),
					StatusMessageTemplate: "temp1",
					Every:                 mustDuration("1m"),
					Offset:                mustDuration("0"),
					Tags:                  []influxdb.Tag{{Key: "key1"}},
				},
			},
			err: &influxdb.Error{
				Code: influxdb.EInvalid,
				Msg:  "Check Offset can't be empty",
			},
		},
		{
			name: "offset greater then interval",
			src: &check.Deadman{
				Base: check.Base{
					ID:      influxTesting.MustIDBase16(id1),
					Name:    "name1",
					OwnerID: influxTesting.MustIDBase16(id2),
					OrgID:   influxTesting.MustIDBase16(id3),
					Every:   mustDuration("1m"),
					Offset:  mustDuration("2m"),
				},
			},
			err: &influxdb.Error{
				Code: influxdb.EInvalid,
				Msg:  "Offset should not be equal or greater than the interval",
			},
		},
		{
			name: "invalid tag",
			src: &check.Deadman{
				Base: check.Base{
					ID:                    influxTesting.MustIDBase16(id1),
					Name:                  "name1",
					OwnerID:               influxTesting.MustIDBase16(id2),
					OrgID:                 influxTesting.MustIDBase16(id3),
					StatusMessageTemplate: "temp1",
					Every:                 mustDuration("1m"),
					Tags:                  []influxdb.Tag{{Key: "key1"}},
				},
			},
			err: &influxdb.Error{
				Code: influxdb.EInvalid,
				Msg:  "tag must contain a key and a value",
			},
		},
		{
			name: "bad thredshold",
			src: &check.Threshold{
				Base: goodBase,
				Thresholds: []check.ThresholdConfig{
					&check.Range{Min: 200, Max: 100},
				},
			},
			err: &influxdb.Error{
				Code: influxdb.EInvalid,
				Msg:  "range threshold min can't be larger than max",
			},
		},
	}
	for _, c := range cases {
		got := c.src.Valid()
		influxTesting.ErrorsEqual(t, got, c.err)
	}
}

var timeGen1 = mock.TimeGenerator{FakeValue: time.Date(2006, time.July, 13, 4, 19, 10, 0, time.UTC)}
var timeGen2 = mock.TimeGenerator{FakeValue: time.Date(2006, time.July, 14, 5, 23, 53, 10, time.UTC)}

func mustDuration(d string) *notification.Duration {
	dur, err := parser.ParseDuration(d)
	if err != nil {
		panic(err)
	}

	return (*notification.Duration)(dur)
}

func TestJSON(t *testing.T) {
	cases := []struct {
		name string
		src  influxdb.Check
	}{
		{
			name: "simple Deadman",
			src: &check.Deadman{
				Base: check.Base{
					ID:      influxTesting.MustIDBase16(id1),
					OwnerID: influxTesting.MustIDBase16(id2),
					Name:    "name1",
					OrgID:   influxTesting.MustIDBase16(id3),
					Every:   mustDuration("1h"),
					Query: influxdb.DashboardQuery{
						BuilderConfig: influxdb.BuilderConfig{
							Buckets: []string{},
							Tags: []struct {
								Key    string   `json:"key"`
								Values []string `json:"values"`
							}{},
							Functions: []struct {
								Name string `json:"name"`
							}{},
						},
					},
					Tags: []influxdb.Tag{
						{
							Key:   "k1",
							Value: "v1",
						},
						{
							Key:   "k2",
							Value: "v2",
						},
					},
					CRUDLog: influxdb.CRUDLog{
						CreatedAt: timeGen1.Now(),
						UpdatedAt: timeGen2.Now(),
					},
				},
				TimeSince:  mustDuration("33s"),
				ReportZero: true,
				Level:      notification.Warn,
			},
		},
		{
			name: "simple threshold",
			src: &check.Threshold{
				Base: check.Base{
					ID:      influxTesting.MustIDBase16(id1),
					Name:    "name1",
					OwnerID: influxTesting.MustIDBase16(id2),
					OrgID:   influxTesting.MustIDBase16(id3),
					Every:   mustDuration("1h"),
					Query: influxdb.DashboardQuery{
						BuilderConfig: influxdb.BuilderConfig{
							Buckets: []string{},
							Tags: []struct {
								Key    string   `json:"key"`
								Values []string `json:"values"`
							}{},
							Functions: []struct {
								Name string `json:"name"`
							}{},
						},
					},
					Tags: []influxdb.Tag{
						{
							Key:   "k1",
							Value: "v1",
						},
						{
							Key:   "k2",
							Value: "v2",
						},
					},
					CRUDLog: influxdb.CRUDLog{
						CreatedAt: timeGen1.Now(),
						UpdatedAt: timeGen2.Now(),
					},
				},
				Thresholds: []check.ThresholdConfig{
					&check.Greater{ThresholdConfigBase: check.ThresholdConfigBase{AllValues: true}, Value: -1.36},
					&check.Range{Min: -10000, Max: 500},
					&check.Lesser{ThresholdConfigBase: check.ThresholdConfigBase{Level: notification.Critical}},
				},
			},
		},
	}
	for _, c := range cases {
		fn := func(t *testing.T) {
			b, err := json.Marshal(c.src)
			if err != nil {
				t.Fatalf("%s marshal failed, err: %s", c.name, err.Error())
			}
			got, err := check.UnmarshalJSON(b)
			if err != nil {
				t.Fatalf("%s unmarshal failed, err: %s", c.name, err.Error())
			}
			if diff := cmp.Diff(got, c.src, cmpopts.IgnoreFields(notification.Duration{}, "BaseNode")); diff != "" {
				t.Errorf("failed %s, Check are different -got/+want\ndiff %s", c.name, diff)
			}
		}
		t.Run(c.name, fn)
	}
}
<|endoftext|>


<commit_before>package bencode

import "testing"
import "bytes"

type random_encode_test struct {
	value    interface{}
	expected string
}

type random_struct struct {
	ABC         int    `bencode:"abc"`
	SkipThisOne string `bencode:"-"`
	CDE         string
}

var random_encode_tests = []random_encode_test{
	{int(10), "i10e"},
	{uint(10), "i10e"},
	{"hello, world", "12:hello, world"},
	{true, "i1e"},
	{false, "i0e"},
	{int8(-8), "i-8e"},
	{int16(-16), "i-16e"},
	{int32(32), "i32e"},
	{int64(-64), "i-64e"},
	{uint8(8), "i8e"},
	{uint16(16), "i16e"},
	{uint32(32), "i32e"},
	{uint64(64), "i64e"},
	{random_struct{123, "nono", "hello"}, "d3:CDE5:hello3:abci123ee"},
	{map[string]string{"a": "b", "c": "d"}, "d1:a1:b1:c1:de"},
	{[]byte{1, 2, 3, 4}, "4:\x01\x02\x03\x04"},
	{[4]byte{1, 2, 3, 4}, "li1ei2ei3ei4ee"},
	{nil, ""},
	{[]byte{}, "0:"},
	{"", "0:"},
	{[]int{}, "le"},
	{map[string]int{}, "de"},
}

func TestRandomEncode(t *testing.T) {
	for _, test := range random_encode_tests {
		data, err := Marshal(test.value)
		if err != nil {
			t.Fatal(err)
		}
		if !bytes.Equal(data, []byte(test.expected)) {
			t.Errorf("got: %s, expected: %s\n",
				string(data), string(test.expected))
		}
	}
}
<commit_msg>Add MarshalBencode test.<commit_after>package bencode

import "testing"
import "bytes"
import "fmt"

type random_encode_test struct {
	value    interface{}
	expected string
}

type random_struct struct {
	ABC         int    `bencode:"abc"`
	SkipThisOne string `bencode:"-"`
	CDE         string
}

type dummy struct {
	a, b, c int
}

func (d *dummy) MarshalBencode() ([]byte, error) {
	var b bytes.Buffer
	_, err := fmt.Fprintf(&b, "i%dei%dei%de", d.a + 1, d.b + 1, d.c + 1)
	if err != nil {
		return nil, err
	}
	return b.Bytes(), nil
}

var random_encode_tests = []random_encode_test{
	{int(10), "i10e"},
	{uint(10), "i10e"},
	{"hello, world", "12:hello, world"},
	{true, "i1e"},
	{false, "i0e"},
	{int8(-8), "i-8e"},
	{int16(-16), "i-16e"},
	{int32(32), "i32e"},
	{int64(-64), "i-64e"},
	{uint8(8), "i8e"},
	{uint16(16), "i16e"},
	{uint32(32), "i32e"},
	{uint64(64), "i64e"},
	{random_struct{123, "nono", "hello"}, "d3:CDE5:hello3:abci123ee"},
	{map[string]string{"a": "b", "c": "d"}, "d1:a1:b1:c1:de"},
	{[]byte{1, 2, 3, 4}, "4:\x01\x02\x03\x04"},
	{[4]byte{1, 2, 3, 4}, "li1ei2ei3ei4ee"},
	{nil, ""},
	{[]byte{}, "0:"},
	{"", "0:"},
	{[]int{}, "le"},
	{map[string]int{}, "de"},
	{&dummy{1, 2, 3}, "i2ei3ei4e"},
}

func TestRandomEncode(t *testing.T) {
	for _, test := range random_encode_tests {
		data, err := Marshal(test.value)
		if err != nil {
			t.Fatal(err)
		}
		if !bytes.Equal(data, []byte(test.expected)) {
			t.Errorf("got: %s, expected: %s\n",
				string(data), string(test.expected))
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 The Prometheus 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.

// +build !nocpu

package collector

import (
	"errors"
	"fmt"
	"strconv"
	"strings"
	"unsafe"

	"github.com/prometheus/client_golang/prometheus"
)

/*
#cgo LDFLAGS:
#include <sys/sysctl.h>
#include <kinfo.h>
#include <stdlib.h>
#include <stdio.h>

static int mibs_set_up = 0;

static int mib_kern_cp_times[2];
static size_t mib_kern_cp_times_len = 2;

static const int mib_kern_clockrate[] = {CTL_KERN, KERN_CLOCKRATE};
static size_t mib_kern_clockrate_len = 2;

// Setup method for MIBs not available as constants.
// Calls to this method must be synchronized externally.
int
setupSysctlMIBs() {
	int ret = sysctlnametomib("kern.cputime", mib_kern_cp_times, &mib_kern_cp_times_len);
	if (ret == 0) mibs_set_up = 1;
	return ret;
}

int
getCPUTimes(int *ncpu, char **cputime) {
	size_t len;

	// Get number of cpu cores.
	int mib[2];
	mib[0] = CTL_HW;
	mib[1] = HW_NCPU;
	len = sizeof(*ncpu);
	if (sysctl(mib, 2, ncpu, &len, NULL, 0)) {
		return -1;
	}

	// Retrieve clockrate
	struct clockinfo clockrate;
	size_t clockrate_size = sizeof(clockrate);
	if (sysctl(mib_kern_clockrate, mib_kern_clockrate_len, &clockrate, &clockrate_size, NULL, 0) == -1 ||
	    sizeof(clockrate) != clockrate_size) {
		return -1;
	}

	long freq = clockrate.stathz > 0 ? clockrate.stathz : clockrate.hz;

	// Get the cpu times.
	struct kinfo_cputime cp_t[*ncpu];
	bzero(cp_t, sizeof(struct kinfo_cputime)*(*ncpu));
	len = sizeof(cp_t[0])*(*ncpu);
	if (sysctlbyname("kern.cputime", &cp_t, &len, NULL, 0)) {
		return -1;
	}

	// string needs to hold (5*ncpu)(uint64_t + char)
	// The char is the space between values.
	*cputime = (char *) malloc((sizeof(uint64_t)+sizeof(char))*(5*(*ncpu)));

	uint64_t user, nice, sys, intr, idle;
	user = nice = sys = intr = idle = 0;
	for (int i = 0; i < *ncpu; ++i) {
		user = ((double) cp_t[i].cp_user) / freq;
		nice = ((double) cp_t[i].cp_nice) / freq;
		sys  = ((double) cp_t[i].cp_sys) / freq;
		intr = ((double) cp_t[i].cp_intr) / freq;
		idle = ((double) cp_t[i].cp_idle) / freq;
		sprintf(*cputime + strlen(*cputime), "%llu %llu %llu %llu %llu ", user, nice, sys, intr, idle );
	}

	return 0;

}
*/
import "C"

const maxCPUTimesLen = C.MAXCPU * C.CPUSTATES

type statCollector struct {
	cpu *prometheus.Desc
}

func init() {
	Factories["cpu"] = NewStatCollector
}

// Takes a prometheus registry and returns a new Collector exposing
// CPU stats.
func NewStatCollector() (Collector, error) {
	if C.setupSysctlMIBs() == -1 {
		return nil, errors.New("could not initialize sysctl MIBs")
	}
	return &statCollector{
		cpu: prometheus.NewDesc(
			prometheus.BuildFQName(Namespace, "", "cpu"),
			"Seconds the cpus spent in each mode.",
			[]string{"cpu", "mode"}, nil,
		),
	}, nil
}

// Expose CPU stats using sysctl.
func (c *statCollector) Update(ch chan<- prometheus.Metric) error {

	// We want time spent per-cpu per CPUSTATE.
	// CPUSTATES (number of CPUSTATES) is defined as 5U.
	// States: CP_USER | CP_NICE | CP_SYS | CP_IDLE | CP_INTR
	//
	// Each value is a counter incremented at frequency
	//   kern.clockrate.(stathz | hz)
	//
	// Look into sys/kern/kern_clock.c for details.

	var ncpu C.int
	var cpuTimesC *C.char
	var fieldsCount = 5

	if C.getCPUTimes(&ncpu, &cpuTimesC) == -1 {
		return errors.New("could not retrieve CPU times")
	}

	// TODO: Find better way to remove trailing white space.
	cpuTimes := strings.Split(strings.TrimSpace(C.GoString(cpuTimesC)), " ")
	C.free(unsafe.Pointer(cpuTimesC))
	// TODO: Figure out why the string is always growing
	fmt.Println(cpuTimes)

	// Export order: user nice sys intr idle
	cpuFields := []string{"user", "nice", "sys", "interrupt", "idle"}
	for i, v := range cpuTimes {
		cpux := fmt.Sprintf("cpu%d", i/fieldsCount)
		value, err := strconv.ParseFloat(v, 64)
		if err != nil {
			return err
		}
		ch <- prometheus.MustNewConstMetric(c.cpu, prometheus.CounterValue, value, cpux, cpuFields[i%fieldsCount])
	}

	return nil
}
<commit_msg>Remove unused comment.<commit_after>// Copyright 2015 The Prometheus 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.

// +build !nocpu

package collector

import (
	"errors"
	"fmt"
	"strconv"
	"strings"
	"unsafe"

	"github.com/prometheus/client_golang/prometheus"
)

/*
#cgo LDFLAGS:
#include <sys/sysctl.h>
#include <kinfo.h>
#include <stdlib.h>
#include <stdio.h>

static int mibs_set_up = 0;

static int mib_kern_cp_times[2];
static size_t mib_kern_cp_times_len = 2;

static const int mib_kern_clockrate[] = {CTL_KERN, KERN_CLOCKRATE};
static size_t mib_kern_clockrate_len = 2;

// Setup method for MIBs not available as constants.
// Calls to this method must be synchronized externally.
int
setupSysctlMIBs() {
	int ret = sysctlnametomib("kern.cputime", mib_kern_cp_times, &mib_kern_cp_times_len);
	if (ret == 0) mibs_set_up = 1;
	return ret;
}

int
getCPUTimes(int *ncpu, char **cputime) {
	size_t len;

	// Get number of cpu cores.
	int mib[2];
	mib[0] = CTL_HW;
	mib[1] = HW_NCPU;
	len = sizeof(*ncpu);
	if (sysctl(mib, 2, ncpu, &len, NULL, 0)) {
		return -1;
	}

	// Retrieve clockrate
	struct clockinfo clockrate;
	size_t clockrate_size = sizeof(clockrate);
	if (sysctl(mib_kern_clockrate, mib_kern_clockrate_len, &clockrate, &clockrate_size, NULL, 0) == -1 ||
	    sizeof(clockrate) != clockrate_size) {
		return -1;
	}

	long freq = clockrate.stathz > 0 ? clockrate.stathz : clockrate.hz;

	// Get the cpu times.
	struct kinfo_cputime cp_t[*ncpu];
	bzero(cp_t, sizeof(struct kinfo_cputime)*(*ncpu));
	len = sizeof(cp_t[0])*(*ncpu);
	if (sysctlbyname("kern.cputime", &cp_t, &len, NULL, 0)) {
		return -1;
	}

	// string needs to hold (5*ncpu)(uint64_t + char)
	// The char is the space between values.
	*cputime = (char *) malloc((sizeof(uint64_t)+sizeof(char))*(5*(*ncpu)));

	uint64_t user, nice, sys, intr, idle;
	user = nice = sys = intr = idle = 0;
	for (int i = 0; i < *ncpu; ++i) {
		user = ((double) cp_t[i].cp_user) / freq;
		nice = ((double) cp_t[i].cp_nice) / freq;
		sys  = ((double) cp_t[i].cp_sys) / freq;
		intr = ((double) cp_t[i].cp_intr) / freq;
		idle = ((double) cp_t[i].cp_idle) / freq;
		sprintf(*cputime + strlen(*cputime), "%llu %llu %llu %llu %llu ", user, nice, sys, intr, idle );
	}

	return 0;

}
*/
import "C"

const maxCPUTimesLen = C.MAXCPU * C.CPUSTATES

type statCollector struct {
	cpu *prometheus.Desc
}

func init() {
	Factories["cpu"] = NewStatCollector
}

// Takes a prometheus registry and returns a new Collector exposing
// CPU stats.
func NewStatCollector() (Collector, error) {
	if C.setupSysctlMIBs() == -1 {
		return nil, errors.New("could not initialize sysctl MIBs")
	}
	return &statCollector{
		cpu: prometheus.NewDesc(
			prometheus.BuildFQName(Namespace, "", "cpu"),
			"Seconds the cpus spent in each mode.",
			[]string{"cpu", "mode"}, nil,
		),
	}, nil
}

// Expose CPU stats using sysctl.
func (c *statCollector) Update(ch chan<- prometheus.Metric) error {

	// We want time spent per-cpu per CPUSTATE.
	// CPUSTATES (number of CPUSTATES) is defined as 5U.
	// States: CP_USER | CP_NICE | CP_SYS | CP_IDLE | CP_INTR
	//
	// Each value is a counter incremented at frequency
	//   kern.clockrate.(stathz | hz)
	//
	// Look into sys/kern/kern_clock.c for details.

	var ncpu C.int
	var cpuTimesC *C.char
	var fieldsCount = 5

	if C.getCPUTimes(&ncpu, &cpuTimesC) == -1 {
		return errors.New("could not retrieve CPU times")
	}

	cpuTimes := strings.Split(strings.TrimSpace(C.GoString(cpuTimesC)), " ")
	C.free(unsafe.Pointer(cpuTimesC))
	// TODO: Figure out why the string is always growing
	fmt.Println(cpuTimes)

	// Export order: user nice sys intr idle
	cpuFields := []string{"user", "nice", "sys", "interrupt", "idle"}
	for i, v := range cpuTimes {
		cpux := fmt.Sprintf("cpu%d", i/fieldsCount)
		value, err := strconv.ParseFloat(v, 64)
		if err != nil {
			return err
		}
		ch <- prometheus.MustNewConstMetric(c.cpu, prometheus.CounterValue, value, cpux, cpuFields[i%fieldsCount])
	}

	return nil
}
<|endoftext|>


<commit_before>package http

import (
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"time"

	"github.com/gorilla/mux"
	"github.com/urfave/negroni"

	"github.com/rusenask/keel/provider"
	"github.com/rusenask/keel/types"
	"github.com/rusenask/keel/version"

	log "github.com/Sirupsen/logrus"
)

// Opts - http server options
type Opts struct {
	Port int

	// available providers
	Providers provider.Providers
}

// TriggerServer - webhook trigger & healthcheck server
type TriggerServer struct {
	providers provider.Providers
	port      int
	server    *http.Server
	router    *mux.Router
}

// NewTriggerServer - create new HTTP trigger based server
func NewTriggerServer(opts *Opts) *TriggerServer {
	return &TriggerServer{
		port:      opts.Port,
		providers: opts.Providers,
		router:    mux.NewRouter(),
	}
}

// Start - start server
func (s *TriggerServer) Start() error {

	s.registerRoutes(s.router)

	n := negroni.New(negroni.NewRecovery())
	n.UseHandler(s.router)

	s.server = &http.Server{
		Addr:    fmt.Sprintf(":%d", s.port),
		Handler: n,
	}

	log.WithFields(log.Fields{
		"port": s.port,
	}).Info("webhook trigger server starting...")
	return s.server.ListenAndServe()
}

// Stop - stop webhook server
func (s *TriggerServer) Stop() {
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()
	s.server.Shutdown(ctx)

}

func (s *TriggerServer) registerRoutes(mux *mux.Router) {
	// health endpoint for k8s to be happy
	mux.HandleFunc("/healthz", s.healthHandler).Methods("GET", "OPTIONS")
	// version handler
	mux.HandleFunc("/version", s.versionHandler).Methods("GET", "OPTIONS")
	// native webhooks handler
	mux.HandleFunc("/v1/webhooks/native", s.nativeHandler).Methods("POST", "OPTIONS")

	// dockerhub webhooks handler
	mux.HandleFunc("/v1/webhooks/dockerhub", s.dockerHubHandler).Methods("POST", "OPTIONS")
	mux.HandleFunc("/v1/webhooks/quay", s.quayHandler).Methods("POST", "OPTIONS")
}

func (s *TriggerServer) healthHandler(resp http.ResponseWriter, req *http.Request) {
	resp.WriteHeader(http.StatusOK)
}

func (s *TriggerServer) versionHandler(resp http.ResponseWriter, req *http.Request) {
	v := version.GetKeelVersion()

	encoded, err := json.Marshal(v)
	if err != nil {
		log.WithError(err).Error("trigger.http: failed to marshal version")
		resp.WriteHeader(http.StatusInternalServerError)
		return
	}

	resp.WriteHeader(http.StatusOK)
	resp.Write(encoded)
}

func (s *TriggerServer) trigger(event types.Event) error {
	return s.providers.Submit(event)
}
<commit_msg>manager<commit_after>package http

import (
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"time"

	"github.com/gorilla/mux"
	"github.com/urfave/negroni"

	"github.com/rusenask/keel/approvals"
	"github.com/rusenask/keel/provider"
	"github.com/rusenask/keel/types"
	"github.com/rusenask/keel/version"

	log "github.com/Sirupsen/logrus"
)

// Opts - http server options
type Opts struct {
	Port int

	// available providers
	Providers provider.Providers

	ApprovalManager approvals.Manager
}

// TriggerServer - webhook trigger & healthcheck server
type TriggerServer struct {
	providers        provider.Providers
	approvalsManager approvals.Manager
	port             int
	server           *http.Server
	router           *mux.Router
}

// NewTriggerServer - create new HTTP trigger based server
func NewTriggerServer(opts *Opts) *TriggerServer {
	return &TriggerServer{
		port:             opts.Port,
		providers:        opts.Providers,
		approvalsManager: opts.ApprovalManager,
		router:           mux.NewRouter(),
	}
}

// Start - start server
func (s *TriggerServer) Start() error {

	s.registerRoutes(s.router)

	n := negroni.New(negroni.NewRecovery())
	n.UseHandler(s.router)

	s.server = &http.Server{
		Addr:    fmt.Sprintf(":%d", s.port),
		Handler: n,
	}

	log.WithFields(log.Fields{
		"port": s.port,
	}).Info("webhook trigger server starting...")
	return s.server.ListenAndServe()
}

// Stop - stop webhook server
func (s *TriggerServer) Stop() {
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()
	s.server.Shutdown(ctx)

}

func (s *TriggerServer) registerRoutes(mux *mux.Router) {
	// health endpoint for k8s to be happy
	mux.HandleFunc("/healthz", s.healthHandler).Methods("GET", "OPTIONS")
	// version handler
	mux.HandleFunc("/version", s.versionHandler).Methods("GET", "OPTIONS")
	// native webhooks handler
	mux.HandleFunc("/v1/webhooks/native", s.nativeHandler).Methods("POST", "OPTIONS")

	// dockerhub webhooks handler
	mux.HandleFunc("/v1/webhooks/dockerhub", s.dockerHubHandler).Methods("POST", "OPTIONS")
	mux.HandleFunc("/v1/webhooks/quay", s.quayHandler).Methods("POST", "OPTIONS")
}

func (s *TriggerServer) healthHandler(resp http.ResponseWriter, req *http.Request) {
	resp.WriteHeader(http.StatusOK)
}

func (s *TriggerServer) versionHandler(resp http.ResponseWriter, req *http.Request) {
	v := version.GetKeelVersion()

	encoded, err := json.Marshal(v)
	if err != nil {
		log.WithError(err).Error("trigger.http: failed to marshal version")
		resp.WriteHeader(http.StatusInternalServerError)
		return
	}

	resp.WriteHeader(http.StatusOK)
	resp.Write(encoded)
}

func (s *TriggerServer) trigger(event types.Event) error {
	return s.providers.Submit(event)
}
<|endoftext|>


<commit_before>package nsqadmin

import (
	"encoding/json"
	"time"
)

type QueryPairs struct {
	FieldName  string `json:"fieldName"`
	FieldValue string `json:"fieldValue"`
}

type IndexFieldsQuery []QueryPairs

type TraceLogQueryInfo struct {
	Sort         string `json:"sort"`
	AppID        string `json:"appId"`
	AppName      string `json:"appName"`
	LogStoreID   string `json:"logStoreId"`
	LogStoreName string `json:"logStoreName"`
	Level        string `json:"level"`
	Host         string `json:"host"`
	Content      string `json:"content"`
	// 2017-01-01 00:00:00
	StartTime   string `json:"startTime"`
	EndTime     string `json:"endTime"`
	IndexFields string `json:"indexFields"`
	PageNumber  int    `json:"pageNumber"`
	PageSize    int    `json:"pageSize"`
}

func NewLogQueryInfo(appID string, appName string, logStoreID string,
	logStoreName string, span time.Duration, indexFields IndexFieldsQuery) *TraceLogQueryInfo {
	q := &TraceLogQueryInfo{
		Sort:         "time",
		AppID:        appID,
		AppName:      appName,
		LogStoreID:   logStoreID,
		LogStoreName: logStoreName,
		Level:        "ALL",
		EndTime:      time.Now().Format("2006-01-02 15:04:05"),
	}
	q.StartTime = time.Now().Add(-1 * span).Format("2006-01-02 15:04:05")
	d, _ := json.Marshal(indexFields)
	q.IndexFields = string(d)
	q.PageNumber = 1
	q.PageSize = 30
	return q
}

type TraceLogItemInfo struct {
	MsgID     uint64 `json:"msgid"`
	TraceID   uint64 `json:"traceid"`
	Topic     string `json:"topic"`
	Channel   string `json:"channel"`
	Timestamp int64  `json:"timestamp"`
	Action    string `json:"action"`
}

type TraceLogData struct {
	ID       string `json:"id"`
	Time     string `json:"time"`
	Level    string `json:"level"`
	HostIp   string `json:"hostIp"`
	HostName string `json:"hostName"`
	Content  string `json:"content"`
	Extra    string `json:"extra"`
	Extra1   string `json:"extra1"`
	TraceLogItemInfo
	RawMsgData string `json:"raw_msg_data"`
}

type TraceLog struct {
	LogDataDtos []TraceLogData `json:"logDataDtos"`
	TotalCount  int            `json:"totalCount"`
}

func (self *TraceLog) Len() int {
	return len(self.LogDataDtos)
}
func (self *TraceLog) Swap(i, j int) {
	self.LogDataDtos[i], self.LogDataDtos[j] = self.LogDataDtos[j], self.LogDataDtos[i]
}
func (self *TraceLog) Less(i, j int) bool {
	return self.LogDataDtos[i].Timestamp < self.LogDataDtos[j].Timestamp
}

type TraceLogResp struct {
	Success bool     `json:"success"`
	Code    int      `json:"code"`
	Msg     string   `json:"msg"`
	Data    TraceLog `json:"data"`
}
<commit_msg>change log search query<commit_after>package nsqadmin

import (
	"encoding/json"
	"time"
)

type QueryPairs struct {
	FieldName  string `json:"fieldName"`
	FieldValue string `json:"fieldValue"`
}

type IndexFieldsQuery []QueryPairs

type TraceLogQueryInfo struct {
	Sort         string `json:"sort"`
	AppID        string `json:"appId"`
	AppName      string `json:"appName"`
	LogStoreID   string `json:"logStoreId"`
	LogStoreName string `json:"logStoreName"`
	Level        string `json:"level"`
	Host         string `json:"host"`
	Content      string `json:"content"`
	// 2017-01-01 00:00:00
	StartTime   string `json:"startTime"`
	EndTime     string `json:"endTime"`
	IndexFields string `json:"indexFields"`
	PageNumber  int    `json:"pageNumber"`
	PageSize    int    `json:"pageSize"`
}

func NewLogQueryInfo(appID string, appName string, logStoreID string,
	logStoreName string, span time.Duration, indexFields IndexFieldsQuery) *TraceLogQueryInfo {
	q := &TraceLogQueryInfo{
		Sort:         "score",
		AppID:        appID,
		AppName:      appName,
		LogStoreID:   logStoreID,
		LogStoreName: logStoreName,
		Level:        "ALL",
		EndTime:      time.Now().Format("2006-01-02 15:04:05"),
	}
	q.StartTime = time.Now().Add(-1 * span).Format("2006-01-02 15:04:05")
	d, _ := json.Marshal(indexFields)
	q.IndexFields = string(d)
	q.PageNumber = 1
	q.PageSize = 60
	return q
}

type TraceLogItemInfo struct {
	MsgID     uint64 `json:"msgid"`
	TraceID   uint64 `json:"traceid"`
	Topic     string `json:"topic"`
	Channel   string `json:"channel"`
	Timestamp int64  `json:"timestamp"`
	Action    string `json:"action"`
}

type TraceLogData struct {
	ID       string `json:"id"`
	Time     string `json:"time"`
	Level    string `json:"level"`
	HostIp   string `json:"hostIp"`
	HostName string `json:"hostName"`
	Content  string `json:"content"`
	Extra    string `json:"extra"`
	Extra1   string `json:"extra1"`
	TraceLogItemInfo
	RawMsgData string `json:"raw_msg_data"`
}

type TraceLog struct {
	LogDataDtos []TraceLogData `json:"logDataDtos"`
	TotalCount  int            `json:"totalCount"`
}

func (self *TraceLog) Len() int {
	return len(self.LogDataDtos)
}
func (self *TraceLog) Swap(i, j int) {
	self.LogDataDtos[i], self.LogDataDtos[j] = self.LogDataDtos[j], self.LogDataDtos[i]
}
func (self *TraceLog) Less(i, j int) bool {
	return self.LogDataDtos[i].Timestamp < self.LogDataDtos[j].Timestamp
}

type TraceLogResp struct {
	Success bool     `json:"success"`
	Code    int      `json:"code"`
	Msg     string   `json:"msg"`
	Data    TraceLog `json:"data"`
}
<|endoftext|>


<commit_before>package handlers

import (
	"fmt"
	"github.com/gorilla/mux"
	"github.com/gorilla/schema"
	"net/http"
	"vmango/models"
	"vmango/web"
)

func MachineDelete(ctx *web.Context, w http.ResponseWriter, req *http.Request) error {
	machine := &models.VirtualMachine{
		Name: mux.Vars(req)["name"],
	}
	if exists, err := ctx.Machines.Get(machine); err != nil {
		return fmt.Errorf("failed to fetch machine info: %s", err)
	} else if !exists {
		return web.NotFound(fmt.Sprintf("Machine with name %s not found", machine.Name))
	}

	if req.Method == "POST" {
		if err := ctx.IPPool.Fetch(machine); err != nil {
			return err
		}
		if err := ctx.Machines.Remove(machine); err != nil {
			return err
		}
		if machine.Ip != nil {
			if err := ctx.IPPool.Release(machine.Ip); err != nil {
				return err
			}
		}
		url, err := ctx.Router.Get("machine-list").URL()
		if err != nil {
			panic(err)
		}
		http.Redirect(w, req, url.Path, http.StatusFound)
		return nil
	} else {
		ctx.Render.HTML(w, http.StatusOK, "machines/delete", map[string]interface{}{
			"Request": req,
			"Machine": machine,
		})
	}
	return nil
}

func MachineStateChange(ctx *web.Context, w http.ResponseWriter, req *http.Request) error {
	machine := &models.VirtualMachine{
		Name: mux.Vars(req)["name"],
	}
	if exists, err := ctx.Machines.Get(machine); err != nil {
		return fmt.Errorf("failed to fetch machine info: %s", err)
	} else if !exists {
		return web.NotFound(fmt.Sprintf("Machine with name %s not found", machine.Name))
	}

	action := mux.Vars(req)["action"]
	if req.Method == "POST" {
		switch action {
		case "stop":
			if err := ctx.Machines.Stop(machine); err != nil {
				return fmt.Errorf("failed to stop machine: %s", err)
			}
		case "start":
			if err := ctx.Machines.Start(machine); err != nil {
				return fmt.Errorf("failed to start machine: %s", err)
			}
		case "reboot":
			if err := ctx.Machines.Reboot(machine); err != nil {
				return fmt.Errorf("failed to reboot machine: %s", err)
			}
		default:
			return web.BadRequest(fmt.Sprintf("unknown action '%s' requested", action))
		}
		url, err := ctx.Router.Get("machine-detail").URL("name", machine.Name)
		if err != nil {
			panic(err)
		}
		http.Redirect(w, req, url.Path, http.StatusFound)
		return nil
	} else {
		ctx.Render.HTML(w, http.StatusOK, "machines/changestate", map[string]interface{}{
			"Request": req,
			"Machine": machine,
			"Action":  action,
		})
		return nil
	}
}

func MachineList(ctx *web.Context, w http.ResponseWriter, req *http.Request) error {
	machines := &models.VirtualMachineList{}
	if err := ctx.Machines.List(machines); err != nil {
		return err
	}
	ctx.RenderResponse(w, req, http.StatusOK, "machines/list", map[string]interface{}{
		"Machines": machines,
	})
	return nil
}

func MachineDetail(ctx *web.Context, w http.ResponseWriter, req *http.Request) error {
	machine := &models.VirtualMachine{
		Name: mux.Vars(req)["name"],
	}
	if exists, err := ctx.Machines.Get(machine); err != nil {
		return err
	} else if !exists {
		return web.NotFound(fmt.Sprintf("Machine with name %s not found", machine.Name))
	}
	if err := ctx.IPPool.Fetch(machine); err != nil {
		return err
	}
	ctx.RenderResponse(w, req, http.StatusOK, "machines/detail", map[string]interface{}{
		"Machine": machine,
	})
	return nil
}

type machineAddFormData struct {
	Name   string
	Plan   string
	Image  string
	SSHKey []string
}

func MachineAddForm(ctx *web.Context, w http.ResponseWriter, req *http.Request) error {
	if req.Method == "POST" {
		if err := req.ParseForm(); err != nil {
			return err
		}
		form := &machineAddFormData{}
		if err := schema.NewDecoder().Decode(form, req.PostForm); err != nil {
			return web.BadRequest(err.Error())
		}
		plan := &models.Plan{Name: form.Plan}
		if exists, err := ctx.Plans.Get(plan); err != nil {
			return err
		} else if !exists {
			return web.BadRequest(fmt.Sprintf(`plan "%s" not found`, form.Plan))
		}

		image := &models.Image{FullName: form.Image}
		if exists, err := ctx.Images.Get(image); err != nil {
			return err
		} else if !exists {
			return web.BadRequest(fmt.Sprintf(`image "%s" not found`, form.Image))
		}
		sshkeys := []*models.SSHKey{}
		for _, keyName := range form.SSHKey {
			key := models.SSHKey{Name: keyName}
			if exists, err := ctx.SSHKeys.Get(&key); err != nil {
				return fmt.Errorf("failed to fetch ssh key %s: %s", keyName, err)
			} else if !exists {
				return web.BadRequest(fmt.Sprintf("ssh key '%s' doesn't exist", keyName))
			}
			sshkeys = append(sshkeys, &key)
		}

		ip := &models.IP{}
		if exists, err := ctx.IPPool.Get(ip); err != nil {
			return fmt.Errorf("cannot find ip address for vm: %s", err)
		} else if !exists {
			return fmt.Errorf("no free ip address availaible")
		}

		vm := &models.VirtualMachine{
			Name:      form.Name,
			Memory:    plan.Memory,
			Cpus:      plan.Cpus,
			ImageName: image.FullName,
			Ip:        ip,
			SSHKeys:   sshkeys,
		}

		if exists, err := ctx.Machines.Get(vm); err != nil {
			return err
		} else if exists {
			return web.BadRequest(fmt.Sprintf("machine with name '%s' already exists", vm.Name))
		}
		if err := ctx.Machines.Create(vm, image, plan); err != nil {
			return fmt.Errorf("failed to create machine: %s", err)
		}
		vm = &models.VirtualMachine{Name: vm.Name}
		if exists, err := ctx.Machines.Get(vm); err != nil {
			return err
		} else if !exists {
			return fmt.Errorf("failed to fetch info for just created machine: %s")
		}

		if err := ctx.IPPool.Assign(ip, vm); err != nil {
			return fmt.Errorf("failed to mark ip as used: %s", err)
		}
		ip.UsedBy = vm.Name
		if err := ctx.Machines.Start(vm); err != nil {
			return fmt.Errorf("failed to start machine: %s", err)
		}
		url, err := ctx.Router.Get("machine-detail").URL("name", vm.Name)
		if err != nil {
			panic(err)
		}
		http.Redirect(w, req, url.Path, http.StatusFound)
	} else {
		plans := []*models.Plan{}
		if err := ctx.Plans.List(&plans); err != nil {
			return fmt.Errorf("failed to fetch plan list: %s", err)
		}
		ips := &models.IPList{}
		if err := ctx.IPPool.List(ips); err != nil {
			return fmt.Errorf("failed to fetch ip list: %s", err)
		}
		images := []*models.Image{}
		if err := ctx.Images.List(&images); err != nil {
			return fmt.Errorf("failed to fetch images list: %s", err)
		}
		sshkeys := []*models.SSHKey{}
		if err := ctx.SSHKeys.List(&sshkeys); err != nil {
			return fmt.Errorf("failed to fetch ssh keys list: %s", err)
		}
		ctx.Render.HTML(w, http.StatusOK, "machines/add", map[string]interface{}{
			"Request": req,
			"Plans":   plans,
			"Ips":     ips,
			"Images":  images,
			"SSHKeys": sshkeys,
		})
	}
	return nil
}
<commit_msg>Remove unneccesary fetch after machine creation<commit_after>package handlers

import (
	"fmt"
	"github.com/gorilla/mux"
	"github.com/gorilla/schema"
	"net/http"
	"vmango/models"
	"vmango/web"
)

func MachineDelete(ctx *web.Context, w http.ResponseWriter, req *http.Request) error {
	machine := &models.VirtualMachine{
		Name: mux.Vars(req)["name"],
	}
	if exists, err := ctx.Machines.Get(machine); err != nil {
		return fmt.Errorf("failed to fetch machine info: %s", err)
	} else if !exists {
		return web.NotFound(fmt.Sprintf("Machine with name %s not found", machine.Name))
	}

	if req.Method == "POST" {
		if err := ctx.IPPool.Fetch(machine); err != nil {
			return err
		}
		if err := ctx.Machines.Remove(machine); err != nil {
			return err
		}
		if machine.Ip != nil {
			if err := ctx.IPPool.Release(machine.Ip); err != nil {
				return err
			}
		}
		url, err := ctx.Router.Get("machine-list").URL()
		if err != nil {
			panic(err)
		}
		http.Redirect(w, req, url.Path, http.StatusFound)
		return nil
	} else {
		ctx.Render.HTML(w, http.StatusOK, "machines/delete", map[string]interface{}{
			"Request": req,
			"Machine": machine,
		})
	}
	return nil
}

func MachineStateChange(ctx *web.Context, w http.ResponseWriter, req *http.Request) error {
	machine := &models.VirtualMachine{
		Name: mux.Vars(req)["name"],
	}
	if exists, err := ctx.Machines.Get(machine); err != nil {
		return fmt.Errorf("failed to fetch machine info: %s", err)
	} else if !exists {
		return web.NotFound(fmt.Sprintf("Machine with name %s not found", machine.Name))
	}

	action := mux.Vars(req)["action"]
	if req.Method == "POST" {
		switch action {
		case "stop":
			if err := ctx.Machines.Stop(machine); err != nil {
				return fmt.Errorf("failed to stop machine: %s", err)
			}
		case "start":
			if err := ctx.Machines.Start(machine); err != nil {
				return fmt.Errorf("failed to start machine: %s", err)
			}
		case "reboot":
			if err := ctx.Machines.Reboot(machine); err != nil {
				return fmt.Errorf("failed to reboot machine: %s", err)
			}
		default:
			return web.BadRequest(fmt.Sprintf("unknown action '%s' requested", action))
		}
		url, err := ctx.Router.Get("machine-detail").URL("name", machine.Name)
		if err != nil {
			panic(err)
		}
		http.Redirect(w, req, url.Path, http.StatusFound)
		return nil
	} else {
		ctx.Render.HTML(w, http.StatusOK, "machines/changestate", map[string]interface{}{
			"Request": req,
			"Machine": machine,
			"Action":  action,
		})
		return nil
	}
}

func MachineList(ctx *web.Context, w http.ResponseWriter, req *http.Request) error {
	machines := &models.VirtualMachineList{}
	if err := ctx.Machines.List(machines); err != nil {
		return err
	}
	ctx.RenderResponse(w, req, http.StatusOK, "machines/list", map[string]interface{}{
		"Machines": machines,
	})
	return nil
}

func MachineDetail(ctx *web.Context, w http.ResponseWriter, req *http.Request) error {
	machine := &models.VirtualMachine{
		Name: mux.Vars(req)["name"],
	}
	if exists, err := ctx.Machines.Get(machine); err != nil {
		return err
	} else if !exists {
		return web.NotFound(fmt.Sprintf("Machine with name %s not found", machine.Name))
	}
	if err := ctx.IPPool.Fetch(machine); err != nil {
		return err
	}
	ctx.RenderResponse(w, req, http.StatusOK, "machines/detail", map[string]interface{}{
		"Machine": machine,
	})
	return nil
}

type machineAddFormData struct {
	Name   string
	Plan   string
	Image  string
	SSHKey []string
}

func MachineAddForm(ctx *web.Context, w http.ResponseWriter, req *http.Request) error {
	if req.Method == "POST" {
		if err := req.ParseForm(); err != nil {
			return err
		}
		form := &machineAddFormData{}
		if err := schema.NewDecoder().Decode(form, req.PostForm); err != nil {
			return web.BadRequest(err.Error())
		}
		plan := &models.Plan{Name: form.Plan}
		if exists, err := ctx.Plans.Get(plan); err != nil {
			return err
		} else if !exists {
			return web.BadRequest(fmt.Sprintf(`plan "%s" not found`, form.Plan))
		}

		image := &models.Image{FullName: form.Image}
		if exists, err := ctx.Images.Get(image); err != nil {
			return err
		} else if !exists {
			return web.BadRequest(fmt.Sprintf(`image "%s" not found`, form.Image))
		}
		sshkeys := []*models.SSHKey{}
		for _, keyName := range form.SSHKey {
			key := models.SSHKey{Name: keyName}
			if exists, err := ctx.SSHKeys.Get(&key); err != nil {
				return fmt.Errorf("failed to fetch ssh key %s: %s", keyName, err)
			} else if !exists {
				return web.BadRequest(fmt.Sprintf("ssh key '%s' doesn't exist", keyName))
			}
			sshkeys = append(sshkeys, &key)
		}

		ip := &models.IP{}
		if exists, err := ctx.IPPool.Get(ip); err != nil {
			return fmt.Errorf("cannot find ip address for vm: %s", err)
		} else if !exists {
			return fmt.Errorf("no free ip address availaible")
		}

		vm := &models.VirtualMachine{
			Name:      form.Name,
			Memory:    plan.Memory,
			Cpus:      plan.Cpus,
			ImageName: image.FullName,
			Ip:        ip,
			SSHKeys:   sshkeys,
		}

		if exists, err := ctx.Machines.Get(vm); err != nil {
			return err
		} else if exists {
			return web.BadRequest(fmt.Sprintf("machine with name '%s' already exists", vm.Name))
		}
		if err := ctx.Machines.Create(vm, image, plan); err != nil {
			return fmt.Errorf("failed to create machine: %s", err)
		}

		if err := ctx.IPPool.Assign(ip, vm); err != nil {
			return fmt.Errorf("failed to mark ip as used: %s", err)
		}
		ip.UsedBy = vm.Name
		if err := ctx.Machines.Start(vm); err != nil {
			return fmt.Errorf("failed to start machine: %s", err)
		}
		url, err := ctx.Router.Get("machine-detail").URL("name", vm.Name)
		if err != nil {
			panic(err)
		}
		http.Redirect(w, req, url.Path, http.StatusFound)
	} else {
		plans := []*models.Plan{}
		if err := ctx.Plans.List(&plans); err != nil {
			return fmt.Errorf("failed to fetch plan list: %s", err)
		}
		ips := &models.IPList{}
		if err := ctx.IPPool.List(ips); err != nil {
			return fmt.Errorf("failed to fetch ip list: %s", err)
		}
		images := []*models.Image{}
		if err := ctx.Images.List(&images); err != nil {
			return fmt.Errorf("failed to fetch images list: %s", err)
		}
		sshkeys := []*models.SSHKey{}
		if err := ctx.SSHKeys.List(&sshkeys); err != nil {
			return fmt.Errorf("failed to fetch ssh keys list: %s", err)
		}
		ctx.Render.HTML(w, http.StatusOK, "machines/add", map[string]interface{}{
			"Request": req,
			"Plans":   plans,
			"Ips":     ips,
			"Images":  images,
			"SSHKeys": sshkeys,
		})
	}
	return nil
}
<|endoftext|>


<commit_before>// Copyright 2017 Istio 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 main

import (
	"fmt"
	"strings"
	"time"

	"github.com/golang/glog"
	"k8s.io/api/core/v1"
	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

type egress struct {
	*infra
}

func (t *egress) String() string {
	return "egress"
}

func (t *egress) setup() error {
	if !t.Egress {
		return nil
	}
	if _, err := client.CoreV1().Services(t.Namespace).Create(&v1.Service{
		ObjectMeta: meta_v1.ObjectMeta{
			Name: "httpbin",
		},
		Spec: v1.ServiceSpec{
			Type:         "ExternalName",
			ExternalName: "httpbin.org",
			Ports: []v1.ServicePort{{
				Port: 80,
				Name: "http", // important to define protocol
			}},
		},
	}); err != nil {
		return err
	}
	if _, err := client.CoreV1().Services(t.Namespace).Create(&v1.Service{
		ObjectMeta: meta_v1.ObjectMeta{
			Name: "httpsgoogle",
		},
		Spec: v1.ServiceSpec{
			Type:         "ExternalName",
			ExternalName: "www.google.com",
			Ports: []v1.ServicePort{{
				Port: 443,
				Name: "https", // important to define protocol
			}},
		},
	}); err != nil {
		return err
	}
	return nil
}

func (t *egress) run() error {
	if !t.Egress {
		glog.Info("skipping test since egress is missing")
		return nil
	}
	extServices := map[string]string{
		"httpbin":         "/headers",
		"httpsgoogle:443": "",
	}

	funcs := make(map[string]func() status)
	for _, src := range []string{"a", "b"} {
		for dst, path := range extServices {
			name := fmt.Sprintf("External request from %s to %s", src, dst)
			funcs[name] = (func(src, dst string) func() status {
				url := fmt.Sprintf("http://%s%s", dst, path)
				trace := fmt.Sprint(time.Now().UnixNano())
				return func() status {
					resp := t.clientRequest(src, url, 1, fmt.Sprintf("-key Trace-Id -val %q", trace))
					if len(resp.code) > 0 && resp.code[0] == httpOk && strings.Contains(resp.body, trace) {
						return nil
					}
					return errAgain
				}
			})(src, dst)
		}
	}
	return parallel(funcs)
}

func (t *egress) teardown() {
	if !t.Egress {
		return
	}
	if err := client.CoreV1().Services(t.Namespace).Delete("httpbin", &meta_v1.DeleteOptions{}); err != nil {
		glog.Warning(err)
	}
	if err := client.CoreV1().Services(t.Namespace).Delete("httpsgoogle", &meta_v1.DeleteOptions{}); err != nil {
		glog.Warning(err)
	}
}
<commit_msg>use cloud.google.com instead of www.google.com in egress test (#1295)<commit_after>// Copyright 2017 Istio 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 main

import (
	"fmt"
	"strings"
	"time"

	"github.com/golang/glog"
	"k8s.io/api/core/v1"
	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

type egress struct {
	*infra
}

func (t *egress) String() string {
	return "egress"
}

func (t *egress) setup() error {
	if !t.Egress {
		return nil
	}
	if _, err := client.CoreV1().Services(t.Namespace).Create(&v1.Service{
		ObjectMeta: meta_v1.ObjectMeta{
			Name: "httpbin",
		},
		Spec: v1.ServiceSpec{
			Type:         "ExternalName",
			ExternalName: "httpbin.org",
			Ports: []v1.ServicePort{{
				Port: 80,
				Name: "http", // important to define protocol
			}},
		},
	}); err != nil {
		return err
	}
	if _, err := client.CoreV1().Services(t.Namespace).Create(&v1.Service{
		ObjectMeta: meta_v1.ObjectMeta{
			Name: "httpsgoogle",
		},
		Spec: v1.ServiceSpec{
			Type:         "ExternalName",
			ExternalName: "cloud.google.com",
			Ports: []v1.ServicePort{{
				Port: 443,
				Name: "https", // important to define protocol
			}},
		},
	}); err != nil {
		return err
	}
	return nil
}

func (t *egress) run() error {
	if !t.Egress {
		glog.Info("skipping test since egress is missing")
		return nil
	}
	extServices := map[string]string{
		"httpbin":         "/headers",
		"httpsgoogle:443": "",
	}

	funcs := make(map[string]func() status)
	for _, src := range []string{"a", "b"} {
		for dst, path := range extServices {
			name := fmt.Sprintf("External request from %s to %s", src, dst)
			funcs[name] = (func(src, dst string) func() status {
				url := fmt.Sprintf("http://%s%s", dst, path)
				trace := fmt.Sprint(time.Now().UnixNano())
				return func() status {
					resp := t.clientRequest(src, url, 1, fmt.Sprintf("-key Trace-Id -val %q", trace))
					if len(resp.code) > 0 && resp.code[0] == httpOk && strings.Contains(resp.body, trace) {
						return nil
					}
					return errAgain
				}
			})(src, dst)
		}
	}
	return parallel(funcs)
}

func (t *egress) teardown() {
	if !t.Egress {
		return
	}
	if err := client.CoreV1().Services(t.Namespace).Delete("httpbin", &meta_v1.DeleteOptions{}); err != nil {
		glog.Warning(err)
	}
	if err := client.CoreV1().Services(t.Namespace).Delete("httpsgoogle", &meta_v1.DeleteOptions{}); err != nil {
		glog.Warning(err)
	}
}
<|endoftext|>