<commit_before>package parser

import (
	"container/list"
	"fmt"

	"github.com/ark-lang/ark-go/util"
)

type Node interface {
	String() string
}

type Stat interface {
	Node
	statNode()
}

type Expr interface {
	Node
	exprNode()
}

type Decl interface {
	Node
	declNode()
}

type Variable struct {
	Type    Type
	Name    string
	Mutable bool
}

func (v *Variable) String() string {
	mut := ""
	if v.Mutable {
		mut = util.Green("[mutable] ")
	}
	return "(" + util.Blue("Variable") + ": " + mut + v.Name + ": " + util.Green(v.Type.GetTypeName()) + ")"
}

type Function struct {
	Name       string
	Parameters *List
	Type       Type
	Mutable    bool
}

func (v *Function) String() string {
	mut := ""
	if v.Mutable {
		mut = util.Green("[mutable] ")
	}
	return "(" + util.Blue("Function") + ": " + mut + v.Name + " " + v.Parameters.String() + ": " + util.Green(v.Type.GetTypeName()) + ")"
}

//
// Nodes
//

type Block struct {
	Nodes []Node
}

func newBlock() *Block {
	return &Block{Nodes: make([]Node, 0)}
}

func (v *Block) String() string {
	if len(v.Nodes) == 0 {
		return "(" + util.Blue("Block") + ": )"
	}

	result := "(" + util.Blue("Block") + ":\n"
	for _, n := range v.Nodes {
		result += "\t" + n.String() + "\n"
	}
	return result + ")"
}

func (v *Block) appendNode(n Node) {
	v.Nodes = append(v.Nodes, n)
}

/**
 * Declarations
 */

// VariableDecl

type VariableDecl struct {
	Variable   *Variable
	Assignment Expr
}

func (v *VariableDecl) declNode() {}

func (v *VariableDecl) String() string {
	if v.Assignment == nil {
		return "(" + util.Blue("VariableDecl") + ": " + v.Variable.String() + ")"
	} else {
		return "(" + util.Blue("VariableDecl") + ": " + v.Variable.String() +
			" = " + v.Assignment.String() + ")"
	}
}

// StructDecl

type StructDecl struct {
	Struct *StructType
}

func (v *StructDecl) declNode() {}

func (v *StructDecl) String() string {
	return "(" + util.Blue("StructDecl") + ": " + v.Struct.String() + ")"
}

// FunctionDecl

type FunctionDecl struct {
	Function *Function
	Body     *Block
}

func (v *FunctionDecl) declNode() {}

func (v *FunctionDecl) String() string {
	result := "(" + util.Blue("FunctionDecl") + ": " + v.Function.String() + " "
	if v.Body != nil {
		result += v.Body.String()
	}
	return result + ")"
}

/**
 * Statements
 */

type ReturnStat struct {
	Value Expr
}

func (v *ReturnStat) statNode() {}

func (v *ReturnStat) String() string {
	return "(" + util.Green("ReturnStat") + ": " +
		v.Value.String() + ")"
}

/**
 * Expressions
 */

// RuneLiteral

type RuneLiteral struct {
	Value rune
}

func (v *RuneLiteral) exprNode() {}

func (v *RuneLiteral) String() string {
	return fmt.Sprintf("("+util.Blue("RuneLiteral")+": "+util.Yellow("%c")+")", v.Value)
}

// IntegerLiteral

type IntegerLiteral struct {
	Value uint64
}

func (v *IntegerLiteral) exprNode() {}

func (v *IntegerLiteral) String() string {
	return fmt.Sprintf("("+util.Blue("IntegerLiteral")+": "+util.Yellow("%d")+")", v.Value)
}

// FloatingLiteral

type FloatingLiteral struct {
	Value float64
}

func (v *FloatingLiteral) exprNode() {}

func (v *FloatingLiteral) String() string {
	return fmt.Sprintf("("+util.Blue("FloatingLiteral")+": "+util.Yellow("%f")+")", v.Value)
}

// StringLiteral

type StringLiteral struct {
	Value string
}

func (v *StringLiteral) exprNode() {}

func (v *StringLiteral) String() string {
	return "(" + util.Blue("StringLiteral") + ": " + util.Yellow(v.Value) + ")"
}

// BinaryExpr

type BinaryExpr struct {
	Lhand, Rhand Expr
	Op           BinOpType
}

func (v *BinaryExpr) exprNode() {}

func (v *BinaryExpr) String() string {
	return "(" + util.Blue("BinaryExpr") + ": " + v.Lhand.String() + " " +
		v.Op.String() + " " +
		v.Rhand.String() + ")"
}

// List

type List struct {
	Items list.List
}

func (v *List) listNode() {}

func (v *List) String() string {
	var result = "(" + util.Blue("List") + ": "
	for item := v.Items.Front(); item != nil; item = item.Next() {
		result += item.Value.(*VariableDecl).String()
		if item.Next() != nil {
			result += " "
		}
	}
	result += ")"
	return result
}

// UnaryExpr

type UnaryExpr struct {
	Expr Expr
	Op   UnOpType
}

func (v *UnaryExpr) exprNode() {}

func (v *UnaryExpr) String() string {
	return "(" + util.Blue("UnaryExpr") + ": " +
		v.Op.String() + " " + v.Expr.String() + ")"
}
<commit_msg>fix returnstat colour<commit_after>package parser

import (
	"container/list"
	"fmt"

	"github.com/ark-lang/ark-go/util"
)

type Node interface {
	String() string
}

type Stat interface {
	Node
	statNode()
}

type Expr interface {
	Node
	exprNode()
}

type Decl interface {
	Node
	declNode()
}

type Variable struct {
	Type    Type
	Name    string
	Mutable bool
}

func (v *Variable) String() string {
	mut := ""
	if v.Mutable {
		mut = util.Green("[mutable] ")
	}
	return "(" + util.Blue("Variable") + ": " + mut + v.Name + ": " + util.Green(v.Type.GetTypeName()) + ")"
}

type Function struct {
	Name       string
	Parameters *List
	Type       Type
	Mutable    bool
}

func (v *Function) String() string {
	mut := ""
	if v.Mutable {
		mut = util.Green("[mutable] ")
	}
	return "(" + util.Blue("Function") + ": " + mut + v.Name + " " + v.Parameters.String() + ": " + util.Green(v.Type.GetTypeName()) + ")"
}

//
// Nodes
//

type Block struct {
	Nodes []Node
}

func newBlock() *Block {
	return &Block{Nodes: make([]Node, 0)}
}

func (v *Block) String() string {
	if len(v.Nodes) == 0 {
		return "(" + util.Blue("Block") + ": )"
	}

	result := "(" + util.Blue("Block") + ":\n"
	for _, n := range v.Nodes {
		result += "\t" + n.String() + "\n"
	}
	return result + ")"
}

func (v *Block) appendNode(n Node) {
	v.Nodes = append(v.Nodes, n)
}

/**
 * Declarations
 */

// VariableDecl

type VariableDecl struct {
	Variable   *Variable
	Assignment Expr
}

func (v *VariableDecl) declNode() {}

func (v *VariableDecl) String() string {
	if v.Assignment == nil {
		return "(" + util.Blue("VariableDecl") + ": " + v.Variable.String() + ")"
	} else {
		return "(" + util.Blue("VariableDecl") + ": " + v.Variable.String() +
			" = " + v.Assignment.String() + ")"
	}
}

// StructDecl

type StructDecl struct {
	Struct *StructType
}

func (v *StructDecl) declNode() {}

func (v *StructDecl) String() string {
	return "(" + util.Blue("StructDecl") + ": " + v.Struct.String() + ")"
}

// FunctionDecl

type FunctionDecl struct {
	Function *Function
	Body     *Block
}

func (v *FunctionDecl) declNode() {}

func (v *FunctionDecl) String() string {
	result := "(" + util.Blue("FunctionDecl") + ": " + v.Function.String() + " "
	if v.Body != nil {
		result += v.Body.String()
	}
	return result + ")"
}

/**
 * Statements
 */

type ReturnStat struct {
	Value Expr
}

func (v *ReturnStat) statNode() {}

func (v *ReturnStat) String() string {
	return "(" + util.Blue("ReturnStat") + ": " +
		v.Value.String() + ")"
}

/**
 * Expressions
 */

// RuneLiteral

type RuneLiteral struct {
	Value rune
}

func (v *RuneLiteral) exprNode() {}

func (v *RuneLiteral) String() string {
	return fmt.Sprintf("("+util.Blue("RuneLiteral")+": "+util.Yellow("%c")+")", v.Value)
}

// IntegerLiteral

type IntegerLiteral struct {
	Value uint64
}

func (v *IntegerLiteral) exprNode() {}

func (v *IntegerLiteral) String() string {
	return fmt.Sprintf("("+util.Blue("IntegerLiteral")+": "+util.Yellow("%d")+")", v.Value)
}

// FloatingLiteral

type FloatingLiteral struct {
	Value float64
}

func (v *FloatingLiteral) exprNode() {}

func (v *FloatingLiteral) String() string {
	return fmt.Sprintf("("+util.Blue("FloatingLiteral")+": "+util.Yellow("%f")+")", v.Value)
}

// StringLiteral

type StringLiteral struct {
	Value string
}

func (v *StringLiteral) exprNode() {}

func (v *StringLiteral) String() string {
	return "(" + util.Blue("StringLiteral") + ": " + util.Yellow(v.Value) + ")"
}

// BinaryExpr

type BinaryExpr struct {
	Lhand, Rhand Expr
	Op           BinOpType
}

func (v *BinaryExpr) exprNode() {}

func (v *BinaryExpr) String() string {
	return "(" + util.Blue("BinaryExpr") + ": " + v.Lhand.String() + " " +
		v.Op.String() + " " +
		v.Rhand.String() + ")"
}

// List

type List struct {
	Items list.List
}

func (v *List) listNode() {}

func (v *List) String() string {
	var result = "(" + util.Blue("List") + ": "
	for item := v.Items.Front(); item != nil; item = item.Next() {
		result += item.Value.(*VariableDecl).String()
		if item.Next() != nil {
			result += " "
		}
	}
	result += ")"
	return result
}

// UnaryExpr

type UnaryExpr struct {
	Expr Expr
	Op   UnOpType
}

func (v *UnaryExpr) exprNode() {}

func (v *UnaryExpr) String() string {
	return "(" + util.Blue("UnaryExpr") + ": " +
		v.Op.String() + " " + v.Expr.String() + ")"
}
<|endoftext|>


<commit_before>package vm

type ListType struct {
	first *Thunk
	rest  *Thunk
}

var emptyList = ListType{nil, nil}

func NewList(ts ...*Thunk) *Thunk {
	return App(Prepend, append(ts, Normal(emptyList))...)
}

func (l1 ListType) equal(e equalable) Object {
	l2 := e.(ListType)

	if l1 == emptyList || l2 == emptyList {
		return rawBool(l1 == l2)
	}

	for _, t := range []*Thunk{
		// Don't evaluate these parallely for short circuit behavior.
		App(Equal, l1.first, l2.first),
		App(Equal, l1.rest, l2.rest),
	} {
		o := t.Eval()
		b, ok := o.(BoolType)

		if !ok {
			return notBoolError(o)
		} else if !b {
			return False
		}
	}

	return True
}

var Prepend = NewLazyFunction(func(ts ...*Thunk) Object {
	switch len(ts) {
	case 0:
		return NumArgsError("prepend", "> 1")
	case 1:
		return ts[0]
	}

	last := len(ts) - 1
	l := cons(ts[last-1], ts[last])

	for i := last - 2; i >= 0; i-- {
		l = cons(ts[i], Normal(l))
	}

	return l
})

func cons(t1, t2 *Thunk) ListType {
	return ListType{t1, t2}
}

var First = NewStrictFunction(func(os ...Object) Object {
	if len(os) != 1 {
		return NumArgsError("first", "1")
	}

	o := os[0]
	l, ok := o.(ListType)

	if !ok {
		return notListError(o)
	} else if l == emptyList {
		return emptyListError()
	}

	return l.first
})

var Rest = NewStrictFunction(func(os ...Object) Object {
	if len(os) != 1 {
		return NumArgsError("rest", "1")
	}

	o := os[0]
	l, ok := o.(ListType)

	if !ok {
		return notListError(o)
	} else if l == emptyList {
		return emptyListError()
	}

	return l.rest
})

var Append = NewLazyFunction(appendFunc)

func appendFunc(ts ...*Thunk) Object {
	o := ts[0].Eval()
	l, ok := o.(ListType)

	if !ok {
		return notListError(o)
	}

	if l == emptyList {
		return NewList(ts[1])
	}

	return cons(l.first, App(NewLazyFunction(appendFunc), l.rest, ts[1]))
}

func notListError(o Object) *Thunk {
	return TypeError(o, "List")
}

func emptyListError() *Thunk {
	return ValueError("The list is empty. You cannot apply rest.")
}

func (l ListType) merge(ts ...*Thunk) Object {
	if l == emptyList {
		return App(Merge, ts...)
	}

	return cons(l.first, App(Merge, append([]*Thunk{l.rest}, ts...)...))
}

// ordered

func (l1 ListType) less(ord ordered) bool {
	l2 := ord.(ListType)

	if l2 == emptyList {
		return false
	} else if l1 == emptyList {
		return true
	}

	// Compare firsts

	o1 := l1.first.Eval()
	o2 := l2.first.Eval()

	if less(o1, o2) {
		return true
	} else if less(o2, o1) {
		return false
	}

	// Compare rests

	return less(l1.rest.Eval(), l2.rest.Eval())
}

func (l ListType) ToThunks() ([]*Thunk, Object) {
	ts := make([]*Thunk, 0)

	for l != emptyList {
		ts = append(ts, l.first)

		o := l.rest.Eval()
		var ok bool
		l, ok = o.(ListType)

		if !ok {
			return nil, notListError(o)
		}
	}

	return ts, nil
}

func (l ListType) ToObjects() ([]Object, Object) {
	ts, err := l.ToThunks()

	if err != nil {
		return nil, err
	}

	os := make([]Object, len(ts))

	for _, t := range ts {
		go t.Eval()
	}

	for i, t := range ts {
		os[i] = t.Eval()
	}

	return os, nil
}
<commit_msg>Change signature of prepend function<commit_after>package vm

import "fmt"

type ListType struct {
	first *Thunk
	rest  *Thunk
}

var emptyList = ListType{nil, nil}

func NewList(ts ...*Thunk) *Thunk {
	l := Normal(emptyList)

	for i := len(ts) - 1; i >= 0; i-- {
		l = Normal(cons(ts[i], l))
	}

	return l
}

func (l1 ListType) equal(e equalable) Object {
	l2 := e.(ListType)

	if l1 == emptyList || l2 == emptyList {
		return rawBool(l1 == l2)
	}

	for _, t := range []*Thunk{
		// Don't evaluate these parallely for short circuit behavior.
		App(Equal, l1.first, l2.first),
		App(Equal, l1.rest, l2.rest),
	} {
		o := t.Eval()
		b, ok := o.(BoolType)

		if !ok {
			return notBoolError(o)
		} else if !b {
			return False
		}
	}

	return True
}

var Prepend = NewLazyFunction(func(ts ...*Thunk) Object {
	t := ts[0]

	o := ts[1].Eval()
	l, ok := o.(ListType)

	if !ok {
		panic(fmt.Sprintf("Rest arguments must be a list. %v", o))
	}

	ts, err := l.ToThunks()

	if err != nil {
		return err
	}

	for i := len(ts) - 1; i >= 0; i-- {
		t = Normal(cons(ts[i], t))
	}

	return t
})

func cons(t1, t2 *Thunk) ListType {
	return ListType{t1, t2}
}

var First = NewStrictFunction(func(os ...Object) Object {
	if len(os) != 1 {
		return NumArgsError("first", "1")
	}

	o := os[0]
	l, ok := o.(ListType)

	if !ok {
		return notListError(o)
	} else if l == emptyList {
		return emptyListError()
	}

	return l.first
})

var Rest = NewStrictFunction(func(os ...Object) Object {
	if len(os) != 1 {
		return NumArgsError("rest", "1")
	}

	o := os[0]
	l, ok := o.(ListType)

	if !ok {
		return notListError(o)
	} else if l == emptyList {
		return emptyListError()
	}

	return l.rest
})

var Append = NewLazyFunction(appendFunc)

func appendFunc(ts ...*Thunk) Object {
	o := ts[0].Eval()
	l, ok := o.(ListType)

	if !ok {
		return notListError(o)
	}

	if l == emptyList {
		return NewList(ts[1])
	}

	return cons(l.first, App(NewLazyFunction(appendFunc), l.rest, ts[1]))
}

func notListError(o Object) *Thunk {
	return TypeError(o, "List")
}

func emptyListError() *Thunk {
	return ValueError("The list is empty. You cannot apply rest.")
}

func (l ListType) merge(ts ...*Thunk) Object {
	if l == emptyList {
		return App(Merge, ts...)
	}

	return cons(l.first, App(Merge, append([]*Thunk{l.rest}, ts...)...))
}

// ordered

func (l1 ListType) less(ord ordered) bool {
	l2 := ord.(ListType)

	if l2 == emptyList {
		return false
	} else if l1 == emptyList {
		return true
	}

	// Compare firsts

	o1 := l1.first.Eval()
	o2 := l2.first.Eval()

	if less(o1, o2) {
		return true
	} else if less(o2, o1) {
		return false
	}

	// Compare rests

	return less(l1.rest.Eval(), l2.rest.Eval())
}

func (l ListType) ToThunks() ([]*Thunk, Object) {
	ts := make([]*Thunk, 0)

	for l != emptyList {
		ts = append(ts, l.first)

		o := l.rest.Eval()
		var ok bool
		l, ok = o.(ListType)

		if !ok {
			return nil, notListError(o)
		}
	}

	return ts, nil
}

func (l ListType) ToObjects() ([]Object, Object) {
	ts, err := l.ToThunks()

	if err != nil {
		return nil, err
	}

	os := make([]Object, len(ts))

	for _, t := range ts {
		go t.Eval()
	}

	for i, t := range ts {
		os[i] = t.Eval()
	}

	return os, nil
}
<|endoftext|>


<commit_before>package routes

import (
	"fmt"
	"log"
	"net/http"

	"github.com/julienschmidt/httprouter"
	"github.com/votinginfoproject/sms-web/queue"
	"github.com/votinginfoproject/sms-web/sms"
	"github.com/votinginfoproject/sms-web/status"
)

type Server struct {
	handler http.Handler
}

func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()

	log.Print(fmt.Sprintf("[INFO] [REQUEST] Method: %s - Path: %s - Host: %s, FormData: %s", r.Method, r.URL.RequestURI(), r.Host, r.Form))

	s.handler.ServeHTTP(w, r)
}

func New(q queue.ExternalQueueService) *Server {
	routes := httprouter.New()

	routes.PanicHandler = func(res http.ResponseWriter, req *http.Request, _ interface{}) {
		res.WriteHeader(http.StatusInternalServerError)
		res.Header().Set("Content-Type", "text/plain")
		log.Print("[ERROR] : ", req)
	}

	routes.GET("/status", status.Get)

	if q != nil {
		sms.WireUp(q)
		q.Connect()
	}
	routes.POST("/", sms.Receive)

	return &Server{routes}
}
<commit_msg>remove dupe connect call<commit_after>package routes

import (
	"fmt"
	"log"
	"net/http"

	"github.com/julienschmidt/httprouter"
	"github.com/votinginfoproject/sms-web/queue"
	"github.com/votinginfoproject/sms-web/sms"
	"github.com/votinginfoproject/sms-web/status"
)

type Server struct {
	handler http.Handler
}

func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()

	log.Print(fmt.Sprintf("[INFO] [REQUEST] Method: %s - Path: %s - Host: %s, FormData: %s", r.Method, r.URL.RequestURI(), r.Host, r.Form))

	s.handler.ServeHTTP(w, r)
}

func New(q queue.ExternalQueueService) *Server {
	routes := httprouter.New()

	routes.PanicHandler = func(res http.ResponseWriter, req *http.Request, _ interface{}) {
		res.WriteHeader(http.StatusInternalServerError)
		res.Header().Set("Content-Type", "text/plain")
		log.Print("[ERROR] : ", req)
	}

	routes.GET("/status", status.Get)

	if q != nil {
		sms.WireUp(q)
	}
	routes.POST("/", sms.Receive)

	return &Server{routes}
}
<|endoftext|>


<commit_before>package gron

import (
	"fmt"
	"testing"
	"time"

	"github.com/roylee0704/gron/xtime"
)

func TestPeriodicNext(t *testing.T) {

	tests := []struct {
		time   string
		period time.Duration
		want   string
	}{

		//Wraps around days
		{
			time:   "Mon Jun 6 23:46 2016",
			period: 15 * time.Minute,
			want:   "Mon Jun 7 00:01 2016",
		},
		{
			time:   "Mon Jun 6 23:59:40 2016",
			period: 21 * time.Second,
			want:   "Mon Jun 7 00:00:01 2016",
		},
		{
			time:   "Mon Jun 6 23:30:19 2016",
			period: 29*time.Minute + 41*time.Second,
			want:   "Mon Jun 7 00:00:00 2016",
		},
		{
			time:   "Mon Jun 6 23:46:20 2016",
			period: 15*time.Minute + 40*time.Second,
			want:   "Mon Jun 7 00:02:00 2016",
		},

		// Wrap around months
		{
			time:   "Mon Jun 6 16:49 2016",
			period: 30 * xtime.Day, // adds 30 days, equates to #days in June.
			want:   "Mon Jul 6 16:49 2016",
		},

		// Wrap around minute, hour, day, month, and year
		{

			time:   "Sat Dec 31 23:59:59 2016",
			period: 1 * time.Second,
			want:   "Sun Jan 1 00:00:00 2017",
		},

		// Round to nearest second on the period
		{
			time:   "Mon Jun 6 12:45 2016",
			period: 15*time.Minute + 100*time.Nanosecond,
			want:   "Mon Jun 6 13:00 2016",
		},

		// Round to 1 second if the duration is less
		{
			time:   "Mon Jun 6 17:38:01 2016",
			period: 59 * time.Millisecond,
			want:   "Mon Jun 6 17:38:02 2016",
		},

		// Round to nearest second when calculating the next time.
		{"Mon Jun 6 17:38:01.009 2016", 15 * time.Minute, "Mon Jun 6 17:53:01 2016"},

		// Round to nearest second for both
		{"Mon Jun 6 17:38:01.009 2016", 15*time.Minute + 50*time.Nanosecond, "Mon Jun 6 17:53:01 2016"},
	}

	for i, test := range tests {

		got := Every(test.period).Next(getTime(test.time))
		want := getTime(test.want)

		fmt.Println(got)
		fmt.Println(want)

		if got != want {
			t.Errorf("case[%d], %s, \"%s\": (want) %v != %v (got)", i, test.time, test.period, want, got)
		}
	}

}

func getTime(value string) time.Time {
	if value == "" {
		return time.Time{}
	}
	t, err := time.Parse("Mon Jan 2 15:04 2006", value)
	if err != nil {
		t, err = time.Parse("Mon Jan 2 15:04:05 2006", value)
		if err != nil {
			t, err = time.Parse("2006-01-02T15:04:05-0700", value)
			if err != nil {
				panic(err)
			}
			// Daylight savings time tests require location
			if ny, err := time.LoadLocation("UTC"); err == nil {
				t = t.In(ny)
			}
		}
	}

	return t
}
<commit_msg>added test case for naive hhss parsing<commit_after>package gron

import (
	"errors"
	"fmt"
	"testing"
	"time"

	"github.com/roylee0704/gron/xtime"
)

func TestPeriodicNext(t *testing.T) {

	tests := []struct {
		time   string
		period time.Duration
		want   string
	}{

		//Wraps around days
		{
			time:   "Mon Jun 6 23:46 2016",
			period: 15 * time.Minute,
			want:   "Mon Jun 7 00:01 2016",
		},
		{
			time:   "Mon Jun 6 23:59:40 2016",
			period: 21 * time.Second,
			want:   "Mon Jun 7 00:00:01 2016",
		},
		{
			time:   "Mon Jun 6 23:30:19 2016",
			period: 29*time.Minute + 41*time.Second,
			want:   "Mon Jun 7 00:00:00 2016",
		},
		{
			time:   "Mon Jun 6 23:46:20 2016",
			period: 15*time.Minute + 40*time.Second,
			want:   "Mon Jun 7 00:02:00 2016",
		},

		// Wrap around months
		{
			time:   "Mon Jun 6 16:49 2016",
			period: 30 * xtime.Day, // adds 30 days, equates to #days in June.
			want:   "Mon Jul 6 16:49 2016",
		},

		// Wrap around minute, hour, day, month, and year
		{

			time:   "Sat Dec 31 23:59:59 2016",
			period: 1 * time.Second,
			want:   "Sun Jan 1 00:00:00 2017",
		},

		// Round to nearest second on the period
		{
			time:   "Mon Jun 6 12:45 2016",
			period: 15*time.Minute + 100*time.Nanosecond,
			want:   "Mon Jun 6 13:00 2016",
		},

		// Round to 1 second if the duration is less
		{
			time:   "Mon Jun 6 17:38:01 2016",
			period: 59 * time.Millisecond,
			want:   "Mon Jun 6 17:38:02 2016",
		},

		// Round to nearest second when calculating the next time.
		{"Mon Jun 6 17:38:01.009 2016", 15 * time.Minute, "Mon Jun 6 17:53:01 2016"},

		// Round to nearest second for both
		{"Mon Jun 6 17:38:01.009 2016", 15*time.Minute + 50*time.Nanosecond, "Mon Jun 6 17:53:01 2016"},
	}

	for i, test := range tests {

		got := Every(test.period).Next(getTime(test.time))
		want := getTime(test.want)

		fmt.Println(got)
		fmt.Println(want)

		if got != want {
			t.Errorf("case[%d], %s, \"%s\": (want) %v != %v (got)", i, test.time, test.period, want, got)
		}
	}

}

func TestNaiveParse(t *testing.T) {

	tests := []struct {
		hhss   string
		hh, ss int
		err    error
	}{
		// sample test
		{"10:11", 10, 11, nil},
		{"24:44", 24, 44, nil},

		// edge test
		{"25:11", 0, 0, errors.New("invalid hh format")},
		{"25:70", 0, 0, errors.New("invalid hh format")},
		{"24:70", 0, 0, errors.New("invalid ss format")},
	}

	for _, test := range tests {
		h, s, err := parse(test.hhss)
		if h != test.hh || s != test.ss {
			t.Errorf("invalid input (%s):  (want) %d:%d != %d:%d (got)", test.hhss, test.hh, test.ss, h, s)
		}
		if err != nil && err.Error() != test.err.Error() {
			t.Errorf("failed to catch formatting error: %s != %s", test.err, err)
		}
	}

}

func getTime(value string) time.Time {
	if value == "" {
		return time.Time{}
	}
	t, err := time.Parse("Mon Jan 2 15:04 2006", value)
	if err != nil {
		t, err = time.Parse("Mon Jan 2 15:04:05 2006", value)
		if err != nil {
			t, err = time.Parse("2006-01-02T15:04:05-0700", value)
			if err != nil {
				panic(err)
			}
			// Daylight savings time tests require location
			if ny, err := time.LoadLocation("UTC"); err == nil {
				t = t.In(ny)
			}
		}
	}

	return t
}
<|endoftext|>


<commit_before>package geom

// IntersectionWorkspace contains various fields useful for speeding up
// ray-tetrahedron intersection checks.
//
// Workspaces should not be shared between threads.
type IntersectionWorkspace struct {
	bLeave, bEnter TetraFaceBary
}

func (w *IntersectionWorkspace) IntersectionBary(
	pt *PluckerTetra, p *PluckerVec,
) (bEnter, bLeave *TetraFaceBary) {
	fEnter, fLeave := -1, -1

	for face := 3; face >= 0; face-- {
		if face == 0 && (fEnter == -1 && fLeave == -1) {
			return nil, nil
		}

		i0, flip0 := pt.EdgeIdx(face, 0)
		i1, flip1 := pt.EdgeIdx(face, 1)
		i2, flip2 := pt.EdgeIdx(face, 2)

		p0, p1, p2 := &pt[i0], &pt[i1], &pt[i2]
		d0, s0 := p.SignDot(p0, flip0)
		d1, s1 := p.SignDot(p1, flip1)
		d2, s2 := p.SignDot(p2, flip2)

		if fEnter == -1 && s0 >= 0 && s1 >= 0 && s2 >= 0 {
			fEnter = face
			w.bEnter.w[0], w.bEnter.w[1], w.bEnter.w[2] = d0, d1, d2
			w.bEnter.face = face
			if fLeave != -1 { break }
		} else if fLeave == - 1 && s0 <= 0 && s1 <= 0 && s2 <= 0 {
			fLeave = face
			w.bLeave.w[0], w.bLeave.w[1], w.bLeave.w[2] = d0, d1, d2
			w.bLeave.face = face
			if fEnter != -1 { break }
		}
	}

	if fEnter == -1 || fLeave == -1 { return nil, nil }
	return &w.bEnter, &w.bLeave
}

func (w *IntersectionWorkspace) IntersectionDistance(
	pt *PluckerTetra, t *Tetra, ap *AnchoredPluckerVec,
) (lEnter, lLeave float32, ok bool) {
	bEnter, bLeave := w.IntersectionBary(pt, &ap.PluckerVec)
	if bEnter == nil { return 0, 0, false }
	return t.Distance(ap, bEnter), t.Distance(ap, bLeave), true
}
<commit_msg>Documented intersection functions and made their return signatures consistent with one another.<commit_after>package geom

// IntersectionWorkspace contains various fields useful for speeding up
// ray-tetrahedron intersection checks.
//
// Workspaces should not be shared between threads.
type IntersectionWorkspace struct {
	bLeave, bEnter TetraFaceBary
}

// IntersectionBary tests for intersection between the ray represented by p and
// the tetrahedron represented by pt and returns the barycentric coordinates of
// the intersection points if they exist.
//
// ok is returned as true if there is an intersection and as false if there
// is no intersection.
//
// The ray represented by ap extends infinitely in both directions.
func (w *IntersectionWorkspace) IntersectionBary(
	pt *PluckerTetra, p *PluckerVec,
) (bEnter, bLeave *TetraFaceBary, ok bool) {
	fEnter, fLeave := -1, -1

	for face := 3; face >= 0; face-- {
		if face == 0 && (fEnter == -1 && fLeave == -1) {
			return nil, nil, false
		}

		i0, flip0 := pt.EdgeIdx(face, 0)
		i1, flip1 := pt.EdgeIdx(face, 1)
		i2, flip2 := pt.EdgeIdx(face, 2)

		p0, p1, p2 := &pt[i0], &pt[i1], &pt[i2]
		d0, s0 := p.SignDot(p0, flip0)
		d1, s1 := p.SignDot(p1, flip1)
		d2, s2 := p.SignDot(p2, flip2)

		if fEnter == -1 && s0 >= 0 && s1 >= 0 && s2 >= 0 {
			fEnter = face
			w.bEnter.w[0], w.bEnter.w[1], w.bEnter.w[2] = d0, d1, d2
			w.bEnter.face = face
			if fLeave != -1 { break }
		} else if fLeave == - 1 && s0 <= 0 && s1 <= 0 && s2 <= 0 {
			fLeave = face
			w.bLeave.w[0], w.bLeave.w[1], w.bLeave.w[2] = d0, d1, d2
			w.bLeave.face = face
			if fEnter != -1 { break }
		}
	}

	if fEnter == -1 || fLeave == -1 { return nil, nil, false }
	return &w.bEnter, &w.bLeave, true
}

// IntersectionDistance tests for intersection between the ray represented b
// ap and the tetrahedron represented by t and pt and returns the distance to
// the intersection points from the origin of ap if they exist.
//
// ok is returned as true if there is an intersection and as false if there
// is no intersection.
//
// The ray represented by ap extends infinitely in both directions, so negative
// distances are valid return values.
func (w *IntersectionWorkspace) IntersectionDistance(
	pt *PluckerTetra, t *Tetra, ap *AnchoredPluckerVec,
) (lEnter, lLeave float32, ok bool) {
	bEnter, bLeave, ok := w.IntersectionBary(pt, &ap.PluckerVec)
	if !ok { return 0, 0, false }
	return t.Distance(ap, bEnter), t.Distance(ap, bLeave), true
}
<|endoftext|>


<commit_before>package lifecycle

import (
	"fmt"
	"net/url"

	"github.com/lxc/lxd/shared/api"
)

// ProjectAction represents a lifecycle event action for project devices.
type ProjectAction string

// All supported lifecycle events for project devices.
const (
	ProjectCreated = ProjectAction("created")
	ProjectDeleted = ProjectAction("deleted")
	ProjectUpdated = ProjectAction("updated")
	ProjectRenamed = ProjectAction("renamed")
)

// Event creates the lifecycle event for an action on a project device.
func (a ProjectAction) Event(name string, ctx map[string]interface{}) api.EventLifecycle {
	eventType := fmt.Sprintf("project-%s", a)
	u := fmt.Sprintf("/1.0/projects/%s", url.PathEscape(name))

	return api.EventLifecycle{
		Action:    eventType,
		Source:    u,
		Context:   ctx,
		Requestor: nil,
	}
}
<commit_msg>lxd/lifecycle/project: accept api.EventLifecycleRequestor as parameter<commit_after>package lifecycle

import (
	"fmt"
	"net/url"

	"github.com/lxc/lxd/shared/api"
)

// ProjectAction represents a lifecycle event action for project devices.
type ProjectAction string

// All supported lifecycle events for project devices.
const (
	ProjectCreated = ProjectAction("created")
	ProjectDeleted = ProjectAction("deleted")
	ProjectUpdated = ProjectAction("updated")
	ProjectRenamed = ProjectAction("renamed")
)

// Event creates the lifecycle event for an action on a project device.
func (a ProjectAction) Event(name string, requestor *api.EventLifecycleRequestor, ctx map[string]interface{}) api.EventLifecycle {
	eventType := fmt.Sprintf("project-%s", a)
	u := fmt.Sprintf("/1.0/projects/%s", url.PathEscape(name))

	return api.EventLifecycle{
		Action:    eventType,
		Source:    u,
		Context:   ctx,
		Requestor: requestor,
	}
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/lxc/lxd/shared/logger"
)

/*
#ifndef _GNU_SOURCE
#define _GNU_SOURCE 1
#endif
#include <errno.h>
#include <fcntl.h>
#include <linux/kcmp.h>
#include <linux/types.h>
#include <poll.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <sched.h>
#include <signal.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <syscall.h>
#include <linux/seccomp.h>
#include <linux/filter.h>
#include <linux/audit.h>
#include <sys/ptrace.h>

#include "../shared/netutils/netns_getifaddrs.c"
#include "include/compiler.h"
#include "include/lxd_seccomp.h"
#include "include/memory_utils.h"

__ro_after_init bool netnsid_aware = false;
__ro_after_init bool uevent_aware = false;
__ro_after_init int seccomp_notify_aware = 0;
__ro_after_init char errbuf[4096];

extern int can_inject_uevent(const char *uevent, size_t len);
extern int wait_for_pid(pid_t pid);

static int netns_set_nsid(int fd)
{
	__do_close_prot_errno int sockfd = -EBADF;
	int ret;
	char buf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
		 NLMSG_ALIGN(sizeof(struct rtgenmsg)) +
		 NLMSG_ALIGN(1024)];
	struct nlmsghdr *hdr;
	struct rtgenmsg *msg;
	__s32 ns_id = -1;
	__u32 netns_fd = fd;

	sockfd = netlink_open(NETLINK_ROUTE);
	if (sockfd < 0)
		return -1;

	memset(buf, 0, sizeof(buf));
	hdr = (struct nlmsghdr *)buf;
	msg = (struct rtgenmsg *)NLMSG_DATA(hdr);

	hdr->nlmsg_len = NLMSG_LENGTH(sizeof(*msg));
	hdr->nlmsg_type = RTM_NEWNSID;
	hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
	hdr->nlmsg_pid = 0;
	hdr->nlmsg_seq = RTM_NEWNSID;
	msg->rtgen_family = AF_UNSPEC;

	addattr(hdr, 1024, __LXC_NETNSA_FD, &netns_fd, sizeof(netns_fd));
	addattr(hdr, 1024, __LXC_NETNSA_NSID, &ns_id, sizeof(ns_id));

	ret = netlink_transaction(sockfd, hdr, hdr);
	if (ret < 0)
		return -1;

	return 0;
}

void is_netnsid_aware(int *hostnetns_fd, int *newnetns_fd)
{
	__do_close_prot_errno int sock_fd = -EBADF;
	int netnsid, ret;

	*hostnetns_fd = open("/proc/self/ns/net", O_RDONLY | O_CLOEXEC);
	if (*hostnetns_fd < 0) {
		(void)sprintf(errbuf, "%s", "Failed to preserve host network namespace");
		return;
	}

	ret = unshare(CLONE_NEWNET);
	if (ret < 0) {
		(void)sprintf(errbuf, "%s", "Failed to unshare network namespace");
		return;
	}

	*newnetns_fd = open("/proc/self/ns/net", O_RDONLY | O_CLOEXEC);
	if (*newnetns_fd < 0) {
		(void)sprintf(errbuf, "%s", "Failed to preserve new network namespace");
		return;
	}

	ret = netns_set_nsid(*hostnetns_fd);
	if (ret < 0) {
		(void)sprintf(errbuf, "%s", "failed to set network namespace identifier");
		return;
	}

	netnsid = netns_get_nsid(*hostnetns_fd);
	if (netnsid < 0) {
		(void)sprintf(errbuf, "%s", "Failed to get network namespace identifier");
		return;
	}

	sock_fd = socket(PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE);
	if (sock_fd < 0) {
		(void)sprintf(errbuf, "%s", "Failed to open netlink routing socket");
		return;
	}

	ret = setsockopt(sock_fd, SOL_NETLINK, NETLINK_GET_STRICT_CHK, &(int){1}, sizeof(int));
	if (ret < 0) {
		// NETLINK_GET_STRICT_CHK isn't supported
		return;
	}

	// NETLINK_GET_STRICT_CHK is supported
	netnsid_aware = true;
}

static void is_uevent_aware(void)
{
	if (can_inject_uevent("dummy", 6) < 0)
		return;

	uevent_aware = true;
}

#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))

static int user_trap_syscall(int nr, unsigned int flags)
{
	struct sock_filter filter[] = {
		BPF_STMT(BPF_LD+BPF_W+BPF_ABS,
			offsetof(struct seccomp_data, nr)),
		BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, nr, 0, 1),
		BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_USER_NOTIF),
		BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW),
	};

	struct sock_fprog prog = {
		.len = (unsigned short)ARRAY_SIZE(filter),
		.filter = filter,
	};

	return syscall(__NR_seccomp, SECCOMP_SET_MODE_FILTER, flags, &prog);
}

// The ifdef can be safely ignored. We don't work on a kernel that old.
static int filecmp(pid_t pid1, pid_t pid2, int fd1, int fd2)
{
#ifdef __NR_kcmp
	return syscall(__NR_kcmp, pid1, pid2, KCMP_FILE, fd1, fd2);
#else
	errno = ENOSYS;
	return -1;
#endif
}

__noreturn static void __do_user_notification_continue(void)
{
	__do_close_prot_errno int listener = -EBADF;
	pid_t pid;
	int ret;
	struct seccomp_notif req = {};
	struct seccomp_notif_resp resp = {};
	struct pollfd pollfd;

	listener = user_trap_syscall(__NR_dup, SECCOMP_FILTER_FLAG_NEW_LISTENER);
	if (listener < 0)
		_exit(EXIT_FAILURE);

	pid = fork();
	if (pid < 0)
		_exit(EXIT_FAILURE);

	if (pid == 0) {
		int dup_fd, pipe_fds[2];
		pid_t self;

		// Don't bother cleaning up. On child exit all of those
		// will be closed anyway.
		ret = pipe(pipe_fds);
		if (ret < 0)
			_exit(EXIT_FAILURE);

		// O_CLOEXEC doesn't matter as we're in the child and we're
		// not going to exec.
		dup_fd = dup(pipe_fds[0]);
		if (dup_fd < 0)
			_exit(EXIT_FAILURE);

		self = getpid();

		ret = filecmp(self, self, pipe_fds[0], dup_fd);
		if (ret)
			_exit(EXIT_FAILURE);

		_exit(EXIT_SUCCESS);
	}

	pollfd.fd = listener;
	pollfd.events = POLLIN | POLLOUT;

	ret = poll(&pollfd, 1, 5000);
	if (ret <= 0)
		goto cleanup_sigkill;

	if (!(pollfd.revents & POLLIN))
		goto cleanup_sigkill;

	ret = ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, &req);
	if (ret)
		goto cleanup_sigkill;

	pollfd.fd = listener;
	pollfd.events = POLLIN | POLLOUT;

	ret = poll(&pollfd, 1, 5000);
	if (ret <= 0)
		goto cleanup_sigkill;

	if (!(pollfd.revents & POLLOUT))
		goto cleanup_sigkill;

	if (req.data.nr != __NR_dup)
		goto cleanup_sigkill;

	resp.id = req.id;
	resp.flags |= SECCOMP_USER_NOTIF_FLAG_CONTINUE;
	ret = ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp);
	resp.error = -EPERM;
	resp.flags = 0;
	if (ret) {
		ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp);
		goto cleanup_sigkill;
	}

cleanup_wait:
	ret = wait_for_pid(pid);
	if (ret)
		_exit(EXIT_FAILURE);
	_exit(EXIT_SUCCESS);

cleanup_sigkill:
	kill(pid, SIGKILL);
	goto cleanup_wait;
}

static void is_user_notification_continue_aware(void)
{
	int ret;
	pid_t pid;

	pid = fork();
	if (pid < 0)
		return;

	if (pid == 0) {
		__do_user_notification_continue();
		// Should not be reached.
		_exit(EXIT_FAILURE);
	}

	ret = wait_for_pid(pid);
	if (!ret)
		seccomp_notify_aware = 2;
}

static void is_seccomp_notify_aware(void)
{
	__u32 action[] = { SECCOMP_RET_USER_NOTIF };

	if (syscall(__NR_seccomp, SECCOMP_GET_ACTION_AVAIL, 0, &action[0]) == 0) {
		seccomp_notify_aware = 1;
		is_user_notification_continue_aware();
	}

}

void checkfeature(void)
{
	__do_close_prot_errno int hostnetns_fd = -EBADF, newnetns_fd = -EBADF;

	is_netnsid_aware(&hostnetns_fd, &newnetns_fd);
	is_uevent_aware();
	is_seccomp_notify_aware();

	if (setns(hostnetns_fd, CLONE_NEWNET) < 0)
		(void)sprintf(errbuf, "%s", "Failed to attach to host network namespace");

}

static bool is_empty_string(char *s)
{
	return (errbuf[0] == '\0');
}
*/
import "C"

func CanUseNetnsGetifaddrs() bool {
	if !bool(C.is_empty_string(&C.errbuf[0])) {
		logger.Debugf("%s", C.GoString(&C.errbuf[0]))
	}

	return bool(C.netnsid_aware)
}

func CanUseUeventInjection() bool {
	return bool(C.uevent_aware)
}

func CanUseSeccompListener() bool {
	return bool(C.seccomp_notify_aware > 0)
}

func CanUseSeccompListenerContinue() bool {
	return bool(C.seccomp_notify_aware == 2)
}
<commit_msg>lxd/main_checkfeature: don't depend on kcmp header<commit_after>package main

import (
	"github.com/lxc/lxd/shared/logger"
)

/*
#ifndef _GNU_SOURCE
#define _GNU_SOURCE 1
#endif
#include <errno.h>
#include <fcntl.h>
#include <linux/types.h>
#include <poll.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <sched.h>
#include <signal.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <syscall.h>
#include <linux/seccomp.h>
#include <linux/filter.h>
#include <linux/audit.h>
#include <sys/ptrace.h>

#include "../shared/netutils/netns_getifaddrs.c"
#include "include/compiler.h"
#include "include/lxd_seccomp.h"
#include "include/memory_utils.h"

__ro_after_init bool netnsid_aware = false;
__ro_after_init bool uevent_aware = false;
__ro_after_init int seccomp_notify_aware = 0;
__ro_after_init char errbuf[4096];

extern int can_inject_uevent(const char *uevent, size_t len);
extern int wait_for_pid(pid_t pid);

static int netns_set_nsid(int fd)
{
	__do_close_prot_errno int sockfd = -EBADF;
	int ret;
	char buf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
		 NLMSG_ALIGN(sizeof(struct rtgenmsg)) +
		 NLMSG_ALIGN(1024)];
	struct nlmsghdr *hdr;
	struct rtgenmsg *msg;
	__s32 ns_id = -1;
	__u32 netns_fd = fd;

	sockfd = netlink_open(NETLINK_ROUTE);
	if (sockfd < 0)
		return -1;

	memset(buf, 0, sizeof(buf));
	hdr = (struct nlmsghdr *)buf;
	msg = (struct rtgenmsg *)NLMSG_DATA(hdr);

	hdr->nlmsg_len = NLMSG_LENGTH(sizeof(*msg));
	hdr->nlmsg_type = RTM_NEWNSID;
	hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
	hdr->nlmsg_pid = 0;
	hdr->nlmsg_seq = RTM_NEWNSID;
	msg->rtgen_family = AF_UNSPEC;

	addattr(hdr, 1024, __LXC_NETNSA_FD, &netns_fd, sizeof(netns_fd));
	addattr(hdr, 1024, __LXC_NETNSA_NSID, &ns_id, sizeof(ns_id));

	ret = netlink_transaction(sockfd, hdr, hdr);
	if (ret < 0)
		return -1;

	return 0;
}

void is_netnsid_aware(int *hostnetns_fd, int *newnetns_fd)
{
	__do_close_prot_errno int sock_fd = -EBADF;
	int netnsid, ret;

	*hostnetns_fd = open("/proc/self/ns/net", O_RDONLY | O_CLOEXEC);
	if (*hostnetns_fd < 0) {
		(void)sprintf(errbuf, "%s", "Failed to preserve host network namespace");
		return;
	}

	ret = unshare(CLONE_NEWNET);
	if (ret < 0) {
		(void)sprintf(errbuf, "%s", "Failed to unshare network namespace");
		return;
	}

	*newnetns_fd = open("/proc/self/ns/net", O_RDONLY | O_CLOEXEC);
	if (*newnetns_fd < 0) {
		(void)sprintf(errbuf, "%s", "Failed to preserve new network namespace");
		return;
	}

	ret = netns_set_nsid(*hostnetns_fd);
	if (ret < 0) {
		(void)sprintf(errbuf, "%s", "failed to set network namespace identifier");
		return;
	}

	netnsid = netns_get_nsid(*hostnetns_fd);
	if (netnsid < 0) {
		(void)sprintf(errbuf, "%s", "Failed to get network namespace identifier");
		return;
	}

	sock_fd = socket(PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE);
	if (sock_fd < 0) {
		(void)sprintf(errbuf, "%s", "Failed to open netlink routing socket");
		return;
	}

	ret = setsockopt(sock_fd, SOL_NETLINK, NETLINK_GET_STRICT_CHK, &(int){1}, sizeof(int));
	if (ret < 0) {
		// NETLINK_GET_STRICT_CHK isn't supported
		return;
	}

	// NETLINK_GET_STRICT_CHK is supported
	netnsid_aware = true;
}

static void is_uevent_aware(void)
{
	if (can_inject_uevent("dummy", 6) < 0)
		return;

	uevent_aware = true;
}

#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))

static int user_trap_syscall(int nr, unsigned int flags)
{
	struct sock_filter filter[] = {
		BPF_STMT(BPF_LD+BPF_W+BPF_ABS,
			offsetof(struct seccomp_data, nr)),
		BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, nr, 0, 1),
		BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_USER_NOTIF),
		BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW),
	};

	struct sock_fprog prog = {
		.len = (unsigned short)ARRAY_SIZE(filter),
		.filter = filter,
	};

	return syscall(__NR_seccomp, SECCOMP_SET_MODE_FILTER, flags, &prog);
}

// The ifdef can be safely ignored. We don't work on a kernel that old.
static int filecmp(pid_t pid1, pid_t pid2, int fd1, int fd2)
{
#ifdef __NR_kcmp
#ifndef KCMP_FILE
#define KCMP_FILE 0
#endif
	return syscall(__NR_kcmp, pid1, pid2, 0, fd1, fd2);
#else
	errno = ENOSYS;
	return -1;
#endif
}

__noreturn static void __do_user_notification_continue(void)
{
	__do_close_prot_errno int listener = -EBADF;
	pid_t pid;
	int ret;
	struct seccomp_notif req = {};
	struct seccomp_notif_resp resp = {};
	struct pollfd pollfd;

	listener = user_trap_syscall(__NR_dup, SECCOMP_FILTER_FLAG_NEW_LISTENER);
	if (listener < 0)
		_exit(EXIT_FAILURE);

	pid = fork();
	if (pid < 0)
		_exit(EXIT_FAILURE);

	if (pid == 0) {
		int dup_fd, pipe_fds[2];
		pid_t self;

		// Don't bother cleaning up. On child exit all of those
		// will be closed anyway.
		ret = pipe(pipe_fds);
		if (ret < 0)
			_exit(EXIT_FAILURE);

		// O_CLOEXEC doesn't matter as we're in the child and we're
		// not going to exec.
		dup_fd = dup(pipe_fds[0]);
		if (dup_fd < 0)
			_exit(EXIT_FAILURE);

		self = getpid();

		ret = filecmp(self, self, pipe_fds[0], dup_fd);
		if (ret)
			_exit(EXIT_FAILURE);

		_exit(EXIT_SUCCESS);
	}

	pollfd.fd = listener;
	pollfd.events = POLLIN | POLLOUT;

	ret = poll(&pollfd, 1, 5000);
	if (ret <= 0)
		goto cleanup_sigkill;

	if (!(pollfd.revents & POLLIN))
		goto cleanup_sigkill;

	ret = ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, &req);
	if (ret)
		goto cleanup_sigkill;

	pollfd.fd = listener;
	pollfd.events = POLLIN | POLLOUT;

	ret = poll(&pollfd, 1, 5000);
	if (ret <= 0)
		goto cleanup_sigkill;

	if (!(pollfd.revents & POLLOUT))
		goto cleanup_sigkill;

	if (req.data.nr != __NR_dup)
		goto cleanup_sigkill;

	resp.id = req.id;
	resp.flags |= SECCOMP_USER_NOTIF_FLAG_CONTINUE;
	ret = ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp);
	resp.error = -EPERM;
	resp.flags = 0;
	if (ret) {
		ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp);
		goto cleanup_sigkill;
	}

cleanup_wait:
	ret = wait_for_pid(pid);
	if (ret)
		_exit(EXIT_FAILURE);
	_exit(EXIT_SUCCESS);

cleanup_sigkill:
	kill(pid, SIGKILL);
	goto cleanup_wait;
}

static void is_user_notification_continue_aware(void)
{
	int ret;
	pid_t pid;

	pid = fork();
	if (pid < 0)
		return;

	if (pid == 0) {
		__do_user_notification_continue();
		// Should not be reached.
		_exit(EXIT_FAILURE);
	}

	ret = wait_for_pid(pid);
	if (!ret)
		seccomp_notify_aware = 2;
}

static void is_seccomp_notify_aware(void)
{
	__u32 action[] = { SECCOMP_RET_USER_NOTIF };

	if (syscall(__NR_seccomp, SECCOMP_GET_ACTION_AVAIL, 0, &action[0]) == 0) {
		seccomp_notify_aware = 1;
		is_user_notification_continue_aware();
	}

}

void checkfeature(void)
{
	__do_close_prot_errno int hostnetns_fd = -EBADF, newnetns_fd = -EBADF;

	is_netnsid_aware(&hostnetns_fd, &newnetns_fd);
	is_uevent_aware();
	is_seccomp_notify_aware();

	if (setns(hostnetns_fd, CLONE_NEWNET) < 0)
		(void)sprintf(errbuf, "%s", "Failed to attach to host network namespace");

}

static bool is_empty_string(char *s)
{
	return (errbuf[0] == '\0');
}
*/
import "C"

func CanUseNetnsGetifaddrs() bool {
	if !bool(C.is_empty_string(&C.errbuf[0])) {
		logger.Debugf("%s", C.GoString(&C.errbuf[0]))
	}

	return bool(C.netnsid_aware)
}

func CanUseUeventInjection() bool {
	return bool(C.uevent_aware)
}

func CanUseSeccompListener() bool {
	return bool(C.seccomp_notify_aware > 0)
}

func CanUseSeccompListenerContinue() bool {
	return bool(C.seccomp_notify_aware == 2)
}
<|endoftext|>


<commit_before>package zone

import (
	"fmt"
	"net"
	"strings"
	"time"

	log "gopkg.in/inconshreveable/log15.v2"

	"github.com/lxc/lxd/client"
	"github.com/lxc/lxd/lxd/cluster"
	"github.com/lxc/lxd/lxd/cluster/request"
	"github.com/lxc/lxd/lxd/db"
	"github.com/lxc/lxd/lxd/network"
	"github.com/lxc/lxd/lxd/revert"
	"github.com/lxc/lxd/lxd/state"
	"github.com/lxc/lxd/lxd/util"
	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/api"
	"github.com/lxc/lxd/shared/logger"
	"github.com/lxc/lxd/shared/logging"
	"github.com/lxc/lxd/shared/validate"
	"github.com/lxc/lxd/shared/version"
)

// zone represents a Network zone.
type zone struct {
	logger      logger.Logger
	state       *state.State
	id          int64
	projectName string
	info        *api.NetworkZone
}

// init initialise internal variables.
func (d *zone) init(state *state.State, id int64, projectName string, info *api.NetworkZone) {
	if info == nil {
		d.info = &api.NetworkZone{}
	} else {
		d.info = info
	}

	d.logger = logging.AddContext(logger.Log, log.Ctx{"project": projectName, "networkzone": d.info.Name})
	d.id = id
	d.projectName = projectName
	d.state = state

	if d.info.Config == nil {
		d.info.Config = make(map[string]string)
	}
}

// ID returns the Network zone ID.
func (d *zone) ID() int64 {
	return d.id
}

// Name returns the project.
func (d *zone) Project() string {
	return d.projectName
}

// Info returns copy of internal info for the Network zone.
func (d *zone) Info() *api.NetworkZone {
	// Copy internal info to prevent modification externally.
	info := api.NetworkZone{}
	info.Name = d.info.Name
	info.Description = d.info.Description
	info.Config = util.CopyConfig(d.info.Config)
	info.UsedBy = nil // To indicate its not populated (use Usedby() function to populate).

	return &info
}

// usedBy returns a list of API endpoints referencing this zone.
// If firstOnly is true then search stops at first result.
func (d *zone) usedBy(firstOnly bool) ([]string, error) {
	usedBy := []string{}

	// Find networks using the zone.
	networkNames, err := d.state.Cluster.GetCreatedNetworks(d.projectName)
	if err != nil && err != db.ErrNoSuchObject {
		return nil, fmt.Errorf("Failed loading networks for project %q: %w", d.projectName, err)
	}

	for _, networkName := range networkNames {
		_, network, _, err := d.state.Cluster.GetNetworkInAnyState(d.projectName, networkName)
		if err != nil {
			return nil, fmt.Errorf("Failed to get network config for %q: %w", networkName, err)
		}

		uri := fmt.Sprintf("/%s/networks/%s", version.APIVersion, networkName)
		if shared.StringInSlice(uri, usedBy) {
			// Skip if the network is already listed in UsedBy.
			continue
		}

		// Check if the network is using this zone.
		if shared.StringInSlice(d.info.Name, []string{network.Config["dns.zone.forward"], network.Config["dns.zone.reverse.ipv4"], network.Config["dns.zone.reverse.ipv6"]}) {
			usedBy = append(usedBy, fmt.Sprintf("/%s/networks/%s", version.APIVersion, networkName))
			if firstOnly {
				return usedBy, nil
			}
		}
	}

	return usedBy, nil
}

// UsedBy returns a list of API endpoints referencing this zone.
func (d *zone) UsedBy() ([]string, error) {
	return d.usedBy(false)
}

// isUsed returns whether or not the zone is in use.
func (d *zone) isUsed() (bool, error) {
	usedBy, err := d.usedBy(true)
	if err != nil {
		return false, err
	}

	return len(usedBy) > 0, nil
}

// Etag returns the values used for etag generation.
func (d *zone) Etag() []interface{} {
	return []interface{}{d.info.Name, d.info.Description, d.info.Config}
}

// validateName checks name is valid.
func (d *zone) validateName(name string) error {
	if name == "" {
		return fmt.Errorf("Name is required")
	}

	return nil
}

// validateConfig checks the config and rules are valid.
func (d *zone) validateConfig(info *api.NetworkZonePut) error {
	rules := map[string]func(value string) error{}

	// Regular config keys.
	rules["dns.nameservers"] = validate.IsListOf(validate.IsAny)
	rules["network.nat"] = validate.Optional(validate.IsBool)

	// Validate peer config.
	for k := range info.Config {
		if !strings.HasPrefix(k, "peers.") {
			continue
		}

		// Validate remote name in key.
		fields := strings.Split(k, ".")
		if len(fields) != 3 {
			return fmt.Errorf("Invalid network zone configuration key %q", k)
		}

		peerKey := fields[2]

		// Add the correct validation rule for the dynamic field based on last part of key.
		switch peerKey {
		case "address":
			rules[k] = validate.Optional(validate.IsNetworkAddress)
		case "key":
			rules[k] = validate.Optional(validate.IsAny)
		}
	}

	err := d.validateConfigMap(info.Config, rules)
	if err != nil {
		return err
	}

	return nil
}

// validateConfigMap checks zone config map against rules.
func (d *zone) validateConfigMap(config map[string]string, rules map[string]func(value string) error) error {
	checkedFields := map[string]struct{}{}

	// Run the validator against each field.
	for k, validator := range rules {
		checkedFields[k] = struct{}{} //Mark field as checked.
		err := validator(config[k])
		if err != nil {
			return fmt.Errorf("Invalid value for config option %q: %w", k, err)
		}
	}

	// Look for any unchecked fields, as these are unknown fields and validation should fail.
	for k := range config {
		_, checked := checkedFields[k]
		if checked {
			continue
		}

		// User keys are not validated.
		if shared.IsUserConfig(k) {
			continue
		}

		return fmt.Errorf("Invalid config option %q", k)
	}

	return nil
}

// Update applies the supplied config to the zone.
func (d *zone) Update(config *api.NetworkZonePut, clientType request.ClientType) error {
	err := d.validateConfig(config)
	if err != nil {
		return err
	}

	revert := revert.New()
	defer revert.Fail()

	// Update the database and notify the rest of the cluster.
	if clientType == request.ClientTypeNormal {
		oldConfig := d.info.NetworkZonePut

		// Update database.
		err = d.state.Cluster.UpdateNetworkZone(d.id, config)
		if err != nil {
			return err
		}

		// Apply changes internally and reinitialise.
		d.info.NetworkZonePut = *config
		d.init(d.state, d.id, d.projectName, d.info)

		revert.Add(func() {
			d.state.Cluster.UpdateNetworkZone(d.id, &oldConfig)
			d.info.NetworkZonePut = oldConfig
			d.init(d.state, d.id, d.projectName, d.info)
		})

		// Notify all other nodes to update the network zone if no target specified.
		notifier, err := cluster.NewNotifier(d.state, d.state.Endpoints.NetworkCert(), d.state.ServerCert(), cluster.NotifyAll)
		if err != nil {
			return err
		}

		err = notifier(func(client lxd.InstanceServer) error {
			return client.UseProject(d.projectName).UpdateNetworkZone(d.info.Name, d.info.NetworkZonePut, "")
		})
		if err != nil {
			return err
		}
	}

	// Trigger a refresh of the TSIG entries.
	err = d.state.DNS.UpdateTSIG()
	if err != nil {
		return err
	}

	revert.Success()
	return nil
}

// Delete deletes the zone.
func (d *zone) Delete() error {
	isUsed, err := d.isUsed()
	if err != nil {
		return err
	}

	if isUsed {
		return fmt.Errorf("Cannot delete a zone that is in use")
	}

	// Delete the database record.
	err = d.state.Cluster.DeleteNetworkZone(d.id)
	if err != nil {
		return err
	}

	// Trigger a refresh of the TSIG entries.
	err = d.state.DNS.UpdateTSIG()
	if err != nil {
		return err
	}

	return nil
}

// Content returns the DNS zone content.
func (d *zone) Content() (*strings.Builder, error) {
	records := []map[string]string{}

	// Check if we should include NAT records.
	val, ok := d.info.Config["network.nat"]
	includeNAT := !ok || shared.IsTrue(val)

	// Load all networks for the zone.
	networks, err := d.state.Cluster.GetNetworksForZone(d.projectName, d.info.Name)
	if err != nil {
		return nil, err
	}

	for _, netName := range networks {
		// Load the network.
		n, err := network.LoadByName(d.state, d.projectName, netName)
		if err != nil {
			return nil, err
		}

		// Load the leases.
		leases, err := n.Leases(d.projectName, request.ClientTypeNormal)
		if err != nil {
			return nil, err
		}

		// Check whether what records to include.
		val, _ = n.Config()["ipv4.nat"]
		includeV4 := includeNAT || !shared.IsTrue(val)

		val, _ = n.Config()["ipv6.nat"]
		includeV6 := includeNAT || !shared.IsTrue(val)

		// Check if dealing with a reverse zone.
		isReverse4 := strings.HasSuffix(d.info.Name, ip4Arpa)
		isReverse6 := strings.HasSuffix(d.info.Name, ip6Arpa)
		isReverse := isReverse4 || isReverse6
		forwardZone := n.Config()["dns.zone.forward"]

		genRecord := func(name string, addr string) map[string]string {
			isV4 := net.ParseIP(addr).To4() != nil

			// Skip disabled families.
			if isV4 && !includeV4 {
				return nil
			}

			if !isV4 && !includeV6 {
				return nil
			}

			record := map[string]string{}
			record["ttl"] = "300"
			if !isReverse {
				if isV4 {
					record["type"] = "A"
				} else {
					record["type"] = "AAAA"
				}

				record["name"] = name
				record["value"] = addr
			} else {
				// Skip PTR records if no forward zone.
				if forwardZone == "" {
					return nil
				}

				// Skip PTR records for wrong family.
				if isV4 && !isReverse4 {
					return nil
				}

				if !isV4 && !isReverse6 {
					return nil
				}

				// Get the ARPA record.
				reverseAddr := reverse(addr)
				if reverseAddr == "" {
					return nil
				}

				record["type"] = "PTR"
				record["name"] = strings.TrimSuffix(reverseAddr, "."+d.info.Name+".")
				record["value"] = name + "." + forwardZone + "."
			}

			return record
		}

		// Convert leases to usable records.
		for _, lease := range leases {
			// Get the record.
			record := genRecord(lease.Hostname, lease.Address)
			if record == nil {
				continue
			}

			records = append(records, record)
		}

		// Add gateways.
		for _, addr := range []string{n.Config()["ipv4.address"], n.Config()["ipv6.address"]} {
			if addr == "" || addr == "none" {
				continue
			}

			// Strip the mask.
			addr = strings.Split(addr, "/")[0]

			// Get the record.
			record := genRecord(n.Name()+".gw", addr)
			if record == nil {
				continue
			}

			records = append(records, record)
		}
	}

	// Get the nameservers.
	nameservers := []string{}
	for _, entry := range strings.Split(d.info.Config["dns.nameservers"], ",") {
		entry = strings.TrimSpace(entry)
		if entry == "" {
			continue
		}

		nameservers = append(nameservers, entry)
	}

	primary := "hostmaster." + d.info.Name
	if len(nameservers) > 0 {
		primary = nameservers[0]
	}

	// Template the zone file.
	sb := &strings.Builder{}
	err = zoneTemplate.Execute(sb, map[string]interface{}{
		"primary":     primary,
		"nameservers": nameservers,
		"zone":        d.info.Name,
		"serial":      time.Now().Unix(),
		"records":     records,
	})
	if err != nil {
		return nil, err
	}

	return sb, nil
}
<commit_msg>lxd/network/zone: Add extra records to DNS<commit_after>package zone

import (
	"fmt"
	"net"
	"strings"
	"time"

	log "gopkg.in/inconshreveable/log15.v2"

	"github.com/lxc/lxd/client"
	"github.com/lxc/lxd/lxd/cluster"
	"github.com/lxc/lxd/lxd/cluster/request"
	"github.com/lxc/lxd/lxd/db"
	"github.com/lxc/lxd/lxd/network"
	"github.com/lxc/lxd/lxd/revert"
	"github.com/lxc/lxd/lxd/state"
	"github.com/lxc/lxd/lxd/util"
	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/api"
	"github.com/lxc/lxd/shared/logger"
	"github.com/lxc/lxd/shared/logging"
	"github.com/lxc/lxd/shared/validate"
	"github.com/lxc/lxd/shared/version"
)

// zone represents a Network zone.
type zone struct {
	logger      logger.Logger
	state       *state.State
	id          int64
	projectName string
	info        *api.NetworkZone
}

// init initialise internal variables.
func (d *zone) init(state *state.State, id int64, projectName string, info *api.NetworkZone) {
	if info == nil {
		d.info = &api.NetworkZone{}
	} else {
		d.info = info
	}

	d.logger = logging.AddContext(logger.Log, log.Ctx{"project": projectName, "networkzone": d.info.Name})
	d.id = id
	d.projectName = projectName
	d.state = state

	if d.info.Config == nil {
		d.info.Config = make(map[string]string)
	}
}

// ID returns the Network zone ID.
func (d *zone) ID() int64 {
	return d.id
}

// Name returns the project.
func (d *zone) Project() string {
	return d.projectName
}

// Info returns copy of internal info for the Network zone.
func (d *zone) Info() *api.NetworkZone {
	// Copy internal info to prevent modification externally.
	info := api.NetworkZone{}
	info.Name = d.info.Name
	info.Description = d.info.Description
	info.Config = util.CopyConfig(d.info.Config)
	info.UsedBy = nil // To indicate its not populated (use Usedby() function to populate).

	return &info
}

// usedBy returns a list of API endpoints referencing this zone.
// If firstOnly is true then search stops at first result.
func (d *zone) usedBy(firstOnly bool) ([]string, error) {
	usedBy := []string{}

	// Find networks using the zone.
	networkNames, err := d.state.Cluster.GetCreatedNetworks(d.projectName)
	if err != nil && err != db.ErrNoSuchObject {
		return nil, fmt.Errorf("Failed loading networks for project %q: %w", d.projectName, err)
	}

	for _, networkName := range networkNames {
		_, network, _, err := d.state.Cluster.GetNetworkInAnyState(d.projectName, networkName)
		if err != nil {
			return nil, fmt.Errorf("Failed to get network config for %q: %w", networkName, err)
		}

		uri := fmt.Sprintf("/%s/networks/%s", version.APIVersion, networkName)
		if shared.StringInSlice(uri, usedBy) {
			// Skip if the network is already listed in UsedBy.
			continue
		}

		// Check if the network is using this zone.
		if shared.StringInSlice(d.info.Name, []string{network.Config["dns.zone.forward"], network.Config["dns.zone.reverse.ipv4"], network.Config["dns.zone.reverse.ipv6"]}) {
			usedBy = append(usedBy, fmt.Sprintf("/%s/networks/%s", version.APIVersion, networkName))
			if firstOnly {
				return usedBy, nil
			}
		}
	}

	return usedBy, nil
}

// UsedBy returns a list of API endpoints referencing this zone.
func (d *zone) UsedBy() ([]string, error) {
	return d.usedBy(false)
}

// isUsed returns whether or not the zone is in use.
func (d *zone) isUsed() (bool, error) {
	usedBy, err := d.usedBy(true)
	if err != nil {
		return false, err
	}

	return len(usedBy) > 0, nil
}

// Etag returns the values used for etag generation.
func (d *zone) Etag() []interface{} {
	return []interface{}{d.info.Name, d.info.Description, d.info.Config}
}

// validateName checks name is valid.
func (d *zone) validateName(name string) error {
	if name == "" {
		return fmt.Errorf("Name is required")
	}

	return nil
}

// validateConfig checks the config and rules are valid.
func (d *zone) validateConfig(info *api.NetworkZonePut) error {
	rules := map[string]func(value string) error{}

	// Regular config keys.
	rules["dns.nameservers"] = validate.IsListOf(validate.IsAny)
	rules["network.nat"] = validate.Optional(validate.IsBool)

	// Validate peer config.
	for k := range info.Config {
		if !strings.HasPrefix(k, "peers.") {
			continue
		}

		// Validate remote name in key.
		fields := strings.Split(k, ".")
		if len(fields) != 3 {
			return fmt.Errorf("Invalid network zone configuration key %q", k)
		}

		peerKey := fields[2]

		// Add the correct validation rule for the dynamic field based on last part of key.
		switch peerKey {
		case "address":
			rules[k] = validate.Optional(validate.IsNetworkAddress)
		case "key":
			rules[k] = validate.Optional(validate.IsAny)
		}
	}

	err := d.validateConfigMap(info.Config, rules)
	if err != nil {
		return err
	}

	return nil
}

// validateConfigMap checks zone config map against rules.
func (d *zone) validateConfigMap(config map[string]string, rules map[string]func(value string) error) error {
	checkedFields := map[string]struct{}{}

	// Run the validator against each field.
	for k, validator := range rules {
		checkedFields[k] = struct{}{} //Mark field as checked.
		err := validator(config[k])
		if err != nil {
			return fmt.Errorf("Invalid value for config option %q: %w", k, err)
		}
	}

	// Look for any unchecked fields, as these are unknown fields and validation should fail.
	for k := range config {
		_, checked := checkedFields[k]
		if checked {
			continue
		}

		// User keys are not validated.
		if shared.IsUserConfig(k) {
			continue
		}

		return fmt.Errorf("Invalid config option %q", k)
	}

	return nil
}

// Update applies the supplied config to the zone.
func (d *zone) Update(config *api.NetworkZonePut, clientType request.ClientType) error {
	err := d.validateConfig(config)
	if err != nil {
		return err
	}

	revert := revert.New()
	defer revert.Fail()

	// Update the database and notify the rest of the cluster.
	if clientType == request.ClientTypeNormal {
		oldConfig := d.info.NetworkZonePut

		// Update database.
		err = d.state.Cluster.UpdateNetworkZone(d.id, config)
		if err != nil {
			return err
		}

		// Apply changes internally and reinitialise.
		d.info.NetworkZonePut = *config
		d.init(d.state, d.id, d.projectName, d.info)

		revert.Add(func() {
			d.state.Cluster.UpdateNetworkZone(d.id, &oldConfig)
			d.info.NetworkZonePut = oldConfig
			d.init(d.state, d.id, d.projectName, d.info)
		})

		// Notify all other nodes to update the network zone if no target specified.
		notifier, err := cluster.NewNotifier(d.state, d.state.Endpoints.NetworkCert(), d.state.ServerCert(), cluster.NotifyAll)
		if err != nil {
			return err
		}

		err = notifier(func(client lxd.InstanceServer) error {
			return client.UseProject(d.projectName).UpdateNetworkZone(d.info.Name, d.info.NetworkZonePut, "")
		})
		if err != nil {
			return err
		}
	}

	// Trigger a refresh of the TSIG entries.
	err = d.state.DNS.UpdateTSIG()
	if err != nil {
		return err
	}

	revert.Success()
	return nil
}

// Delete deletes the zone.
func (d *zone) Delete() error {
	isUsed, err := d.isUsed()
	if err != nil {
		return err
	}

	if isUsed {
		return fmt.Errorf("Cannot delete a zone that is in use")
	}

	// Delete the database record.
	err = d.state.Cluster.DeleteNetworkZone(d.id)
	if err != nil {
		return err
	}

	// Trigger a refresh of the TSIG entries.
	err = d.state.DNS.UpdateTSIG()
	if err != nil {
		return err
	}

	return nil
}

// Content returns the DNS zone content.
func (d *zone) Content() (*strings.Builder, error) {
	records := []map[string]string{}

	// Check if we should include NAT records.
	val, ok := d.info.Config["network.nat"]
	includeNAT := !ok || shared.IsTrue(val)

	// Load all networks for the zone.
	networks, err := d.state.Cluster.GetNetworksForZone(d.projectName, d.info.Name)
	if err != nil {
		return nil, err
	}

	for _, netName := range networks {
		// Load the network.
		n, err := network.LoadByName(d.state, d.projectName, netName)
		if err != nil {
			return nil, err
		}

		// Load the leases.
		leases, err := n.Leases(d.projectName, request.ClientTypeNormal)
		if err != nil {
			return nil, err
		}

		// Check whether what records to include.
		val, _ = n.Config()["ipv4.nat"]
		includeV4 := includeNAT || !shared.IsTrue(val)

		val, _ = n.Config()["ipv6.nat"]
		includeV6 := includeNAT || !shared.IsTrue(val)

		// Check if dealing with a reverse zone.
		isReverse4 := strings.HasSuffix(d.info.Name, ip4Arpa)
		isReverse6 := strings.HasSuffix(d.info.Name, ip6Arpa)
		isReverse := isReverse4 || isReverse6
		forwardZone := n.Config()["dns.zone.forward"]

		genRecord := func(name string, addr string) map[string]string {
			isV4 := net.ParseIP(addr).To4() != nil

			// Skip disabled families.
			if isV4 && !includeV4 {
				return nil
			}

			if !isV4 && !includeV6 {
				return nil
			}

			record := map[string]string{}
			record["ttl"] = "300"
			if !isReverse {
				if isV4 {
					record["type"] = "A"
				} else {
					record["type"] = "AAAA"
				}

				record["name"] = name
				record["value"] = addr
			} else {
				// Skip PTR records if no forward zone.
				if forwardZone == "" {
					return nil
				}

				// Skip PTR records for wrong family.
				if isV4 && !isReverse4 {
					return nil
				}

				if !isV4 && !isReverse6 {
					return nil
				}

				// Get the ARPA record.
				reverseAddr := reverse(addr)
				if reverseAddr == "" {
					return nil
				}

				record["type"] = "PTR"
				record["name"] = strings.TrimSuffix(reverseAddr, "."+d.info.Name+".")
				record["value"] = name + "." + forwardZone + "."
			}

			return record
		}

		// Convert leases to usable records.
		for _, lease := range leases {
			// Get the record.
			record := genRecord(lease.Hostname, lease.Address)
			if record == nil {
				continue
			}

			records = append(records, record)
		}

		// Add gateways.
		for _, addr := range []string{n.Config()["ipv4.address"], n.Config()["ipv6.address"]} {
			if addr == "" || addr == "none" {
				continue
			}

			// Strip the mask.
			addr = strings.Split(addr, "/")[0]

			// Get the record.
			record := genRecord(n.Name()+".gw", addr)
			if record == nil {
				continue
			}

			records = append(records, record)
		}
	}

	// Add the extra records.
	extraRecords, err := d.GetRecords()
	if err != nil {
		return nil, err
	}

	for _, extraRecord := range extraRecords {
		for _, entry := range extraRecord.Entries {
			record := map[string]string{}
			if entry.TTL > 0 {
				record["ttl"] = fmt.Sprintf("%d", entry.TTL)
			} else {
				record["ttl"] = "300"
			}

			record["type"] = entry.Type
			record["name"] = extraRecord.Name
			record["value"] = entry.Value

			records = append(records, record)
		}
	}

	// Get the nameservers.
	nameservers := []string{}
	for _, entry := range strings.Split(d.info.Config["dns.nameservers"], ",") {
		entry = strings.TrimSpace(entry)
		if entry == "" {
			continue
		}

		nameservers = append(nameservers, entry)
	}

	primary := "hostmaster." + d.info.Name
	if len(nameservers) > 0 {
		primary = nameservers[0]
	}

	// Template the zone file.
	sb := &strings.Builder{}
	err = zoneTemplate.Execute(sb, map[string]interface{}{
		"primary":     primary,
		"nameservers": nameservers,
		"zone":        d.info.Name,
		"serial":      time.Now().Unix(),
		"records":     records,
	})
	if err != nil {
		return nil, err
	}

	return sb, nil
}
<|endoftext|>


<commit_before>// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package vlog

import (
	"flag"
	"fmt"

	"github.com/cosnicolaou/llog"
)

var (
	toStderr        bool
	alsoToStderr    bool
	logDir          string
	verbosity       Level
	stderrThreshold StderrThreshold = StderrThreshold(llog.ErrorLog)
	vmodule         ModuleSpec
	vpath           FilepathSpec

	traceLocation   TraceLocation
	maxStackBufSize int
)

var flagDefs = []struct {
	name         string
	variable     interface{}
	defaultValue interface{}
	description  string
}{
	{"log_dir", &logDir, "", "if non-empty, write log files to this directory"},
	{"logtostderr", &toStderr, false, "log to standard error instead of files"},
	{"alsologtostderr", &alsoToStderr, true, "log to standard error as well as files"},
	{"max_stack_buf_size", &maxStackBufSize, 4192 * 1024, "max size in bytes of the buffer to use for logging stack traces"},
	{"v", &verbosity, nil, "log level for V logs"},
	{"stderrthreshold", &stderrThreshold, nil, "logs at or above this threshold go to stderr"},
	{"vmodule", &vmodule, nil, "comma-separated list of globpattern=N settings for filename-filtered logging (without the .go suffix).  E.g. foo/bar/baz.go is matched by patterns baz or *az or b* but not by bar/baz or baz.go or az or b.*"},
	{"vpath", &vpath, nil, "comma-separated list of regexppattern=N settings for file pathname-filtered logging (without the .go suffix).  E.g. foo/bar/baz.go is matched by patterns foo/bar/baz or fo.*az or oo/ba or b.z but not by foo/bar/baz.go or fo*az"},
	{"log_backtrace_at", &traceLocation, nil, "when logging hits line file:N, emit a stack trace"},
}

func init() {
	istest := false
	if flag.CommandLine.Lookup("test.v") != nil {
		istest = true
	}
	for _, flagDef := range flagDefs {
		if istest && flagDef.name == "v" {
			continue
		}
		switch v := flagDef.variable.(type) {
		case *string:
			flag.StringVar(v, flagDef.name,
				flagDef.defaultValue.(string), flagDef.description)
		case *bool:
			flag.BoolVar(v, flagDef.name,
				flagDef.defaultValue.(bool), flagDef.description)
		case *int:
			flag.IntVar(v, flagDef.name,
				flagDef.defaultValue.(int), flagDef.description)
		case flag.Value:
			if flagDef.defaultValue != nil {
				panic(fmt.Sprintf("default value not supported for flag %s", flagDef.name))
			}
			flag.Var(v, flagDef.name, flagDef.description)
		default:
			panic("invalid flag type")
		}
	}
}

// ConfigureLibraryLoggerFromFlags will configure the internal global logger
// using command line flags.  It assumes that flag.Parse() has already been
// called to initialize the flag variables.
func ConfigureLibraryLoggerFromFlags() error {
	return Log.ConfigureFromFlags()
}

func (l *Logger) String() string {
	return l.log.String()
}

// ConfigureFromFlags will configure the logger using
// command line flags.
func (l *Logger) ConfigureFromFlags() error {
	return l.Configure(
		LogToStderr(toStderr),
		AlsoLogToStderr(alsoToStderr),
		LogDir(logDir),
		Level(verbosity),
		StderrThreshold(stderrThreshold),
		ModuleSpec(vmodule),
		FilepathSpec(vpath),
		TraceLocation(traceLocation),
		MaxStackBufSize(maxStackBufSize),
	)
}

// ExplicitlySetFlags returns a map of the logging command line flags and their
// values formatted as strings.  Only the flags that were explicitly set are
// returned. This is intended for use when an application needs to know what
// value the flags were set to, for example when creating subprocesses.
func (l *Logger) ExplicitlySetFlags() map[string]string {
	logFlagNames := make(map[string]bool)
	for _, flagDef := range flagDefs {
		logFlagNames[flagDef.name] = true
	}
	args := make(map[string]string)
	flag.Visit(func(f *flag.Flag) {
		if logFlagNames[f.Name] {
			args[f.Name] = f.Value.String()
		}
	})
	return args
}
<commit_msg>v.io/x/lib/vlog: allow for configuration via a function call rather than just flags<commit_after>// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package vlog

import (
	"flag"
	"fmt"

	"github.com/cosnicolaou/llog"
)

var (
	// Reexport the logging severity levels from the underlying llog package.
	InfoLog    = llog.InfoLog
	WarningLog = llog.WarningLog
	ErrorLog   = llog.ErrorLog
	FatalLog   = llog.FatalLog
)

var (
	toStderr        bool
	alsoToStderr    bool
	logDir          string
	verbosity       Level
	stderrThreshold StderrThreshold = StderrThreshold(llog.ErrorLog)
	vmodule         ModuleSpec
	vpath           FilepathSpec

	traceLocation   TraceLocation
	maxStackBufSize int
)

var flagDefs = []struct {
	name         string
	variable     interface{}
	defaultValue interface{}
	description  string
}{
	{"log_dir", &logDir, "", "if non-empty, write log files to this directory"},
	{"logtostderr", &toStderr, false, "log to standard error instead of files"},
	{"alsologtostderr", &alsoToStderr, true, "log to standard error as well as files"},
	{"max_stack_buf_size", &maxStackBufSize, 4192 * 1024, "max size in bytes of the buffer to use for logging stack traces"},
	{"v", &verbosity, nil, "log level for V logs"},
	{"stderrthreshold", &stderrThreshold, nil, "logs at or above this threshold go to stderr"},
	{"vmodule", &vmodule, nil, "comma-separated list of globpattern=N settings for filename-filtered logging (without the .go suffix).  E.g. foo/bar/baz.go is matched by patterns baz or *az or b* but not by bar/baz or baz.go or az or b.*"},
	{"vpath", &vpath, nil, "comma-separated list of regexppattern=N settings for file pathname-filtered logging (without the .go suffix).  E.g. foo/bar/baz.go is matched by patterns foo/bar/baz or fo.*az or oo/ba or b.z but not by foo/bar/baz.go or fo*az"},
	{"log_backtrace_at", &traceLocation, nil, "when logging hits line file:N, emit a stack trace"},
}

func init() {
	istest := false
	if flag.CommandLine.Lookup("test.v") != nil {
		istest = true
	}
	for _, flagDef := range flagDefs {
		if istest && flagDef.name == "v" {
			continue
		}
		switch v := flagDef.variable.(type) {
		case *string:
			flag.StringVar(v, flagDef.name,
				flagDef.defaultValue.(string), flagDef.description)
		case *bool:
			flag.BoolVar(v, flagDef.name,
				flagDef.defaultValue.(bool), flagDef.description)
		case *int:
			flag.IntVar(v, flagDef.name,
				flagDef.defaultValue.(int), flagDef.description)
		case flag.Value:
			if flagDef.defaultValue != nil {
				panic(fmt.Sprintf("default value not supported for flag %s", flagDef.name))
			}
			flag.Var(v, flagDef.name, flagDef.description)
		default:
			panic("invalid flag type")
		}
	}
}

// ConfigureLibraryLoggerFromFlags will configure the internal global logger
// using command line flags.  It assumes that flag.Parse() has already been
// called to initialize the flag variables.
func ConfigureLibraryLoggerFromFlags() error {
	return Log.ConfigureFromFlags()
}

func (l *Logger) String() string {
	return l.log.String()
}

// ConfigureFromFlags will configure the logger using command line flags.
func (l *Logger) ConfigureFromFlags() error {
	return l.Configure(
		LogToStderr(toStderr),
		AlsoLogToStderr(alsoToStderr),
		LogDir(logDir),
		Level(verbosity),
		StderrThreshold(stderrThreshold),
		ModuleSpec(vmodule),
		FilepathSpec(vpath),
		TraceLocation(traceLocation),
		MaxStackBufSize(maxStackBufSize),
	)
}

// ConfigureFromArgs will configure the logger using the supplied args.
func (l *Logger) ConfigureFromArgs(opts ...LoggingOpts) error {
  return l.Configure(opts...)
}

// ExplicitlySetFlags returns a map of the logging command line flags and their
// values formatted as strings.  Only the flags that were explicitly set are
// returned. This is intended for use when an application needs to know what
// value the flags were set to, for example when creating subprocesses.
func (l *Logger) ExplicitlySetFlags() map[string]string {
	logFlagNames := make(map[string]bool)
	for _, flagDef := range flagDefs {
		logFlagNames[flagDef.name] = true
	}
	args := make(map[string]string)
	flag.Visit(func(f *flag.Flag) {
		if logFlagNames[f.Name] {
			args[f.Name] = f.Value.String()
		}
	})
	return args
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/armon/consul-api"
	"testing"
	"time"
)

func TestShouldStop(t *testing.T) {
	ch := make(chan struct{})
	if shouldStop(ch) {
		t.Fatalf("bad")
	}
	close(ch)
	if !shouldStop(ch) {
		t.Fatalf("bad")
	}
}

func TestAsyncNotify(t *testing.T) {
	ch := make(chan struct{}, 1)
	asyncNotify(ch)
	asyncNotify(ch)
	asyncNotify(ch)

	select {
	case <-ch:
	default:
		t.Fatalf("should work")
	}
	select {
	case <-ch:
		t.Fatalf("should not work")
	default:
	}

}

func TestMin(t *testing.T) {
	if min(1, 2) != 1 {
		t.Fatalf("Bad")
	}
	if min(2, 1) != 1 {
		t.Fatalf("Bad")
	}
}

func TestBackoff(t *testing.T) {
	type val struct {
		fail   int
		expect time.Duration
	}
	inps := []val{
		{1, 3 * time.Second},
		{2, 6 * time.Second},
		{3, 12 * time.Second},
		{4, 24 * time.Second},
	}
	for _, inp := range inps {
		if out := backoff(3*time.Second, inp.fail); out != inp.expect {
			t.Fatalf("bad: %v %v", inp, out)
		}
	}
}

func TestFormatOutput(t *testing.T) {
	inp := map[string][]*consulapi.ServiceEntry{
		"foo": []*consulapi.ServiceEntry{
			&consulapi.ServiceEntry{
				Node:    &consulapi.Node{Node: "node1", Address: "127.0.0.1"},
				Service: &consulapi.AgentService{ID: "redis", Port: 8000},
			},
			&consulapi.ServiceEntry{
				Node:    &consulapi.Node{Node: "node3", Address: "127.0.0.3"},
				Service: &consulapi.AgentService{ID: "redis", Port: 1234},
			},
		},
		"bar": []*consulapi.ServiceEntry{
			&consulapi.ServiceEntry{
				Node:    &consulapi.Node{Node: "node2", Address: "127.0.0.2"},
				Service: &consulapi.AgentService{ID: "memcache", Port: 80},
			},
			&consulapi.ServiceEntry{
				Node:    &consulapi.Node{Node: "node4", Address: "127.0.0.4"},
				Service: &consulapi.AgentService{ID: "memcache", Port: 10000},
			},
		},
	}

	output := formatOutput(inp)
	if len(output) != 2 {
		t.Fatalf("bad: %v", output)
	}
	foo := output["foo"]
	if len(foo) != 2 {
		t.Fatalf("bad: %v", foo)
	}
	if foo[0] != "server node1_redis 127.0.0.1:8000" {
		t.Fatalf("Bad: %v", foo)
	}
	if foo[1] != "server node3_redis 127.0.0.3:1234" {
		t.Fatalf("Bad: %v", foo)
	}

	bar := output["bar"]
	if len(bar) != 2 {
		t.Fatalf("bad: %v", bar)
	}
	if bar[0] != "server node2_memcache 127.0.0.2:80" {
		t.Fatalf("Bad: %v", bar)
	}
	if bar[1] != "server node4_memcache 127.0.0.4:10000" {
		t.Fatalf("Bad: %v", bar)
	}
}
<commit_msg>Reload tests<commit_after>package main

import (
	"github.com/armon/consul-api"
	"io/ioutil"
	"os"
	"testing"
	"time"
)

func TestReload(t *testing.T) {
	os.Remove("test_out")
	conf := &Config{
		ReloadCommand: "echo 'foo' > test_out",
	}
	if err := reload(conf); err != nil {
		t.Fatalf("err: %v", err)
	}
	bytes, err := ioutil.ReadFile("test_out")
	if err != nil {
		t.Fatalf("err: %v", err)
	}
	if string(bytes) != "foo\n" {
		t.Fatalf("bad: %v", bytes)
	}
}

func TestShouldStop(t *testing.T) {
	ch := make(chan struct{})
	if shouldStop(ch) {
		t.Fatalf("bad")
	}
	close(ch)
	if !shouldStop(ch) {
		t.Fatalf("bad")
	}
}

func TestAsyncNotify(t *testing.T) {
	ch := make(chan struct{}, 1)
	asyncNotify(ch)
	asyncNotify(ch)
	asyncNotify(ch)

	select {
	case <-ch:
	default:
		t.Fatalf("should work")
	}
	select {
	case <-ch:
		t.Fatalf("should not work")
	default:
	}

}

func TestMin(t *testing.T) {
	if min(1, 2) != 1 {
		t.Fatalf("Bad")
	}
	if min(2, 1) != 1 {
		t.Fatalf("Bad")
	}
}

func TestBackoff(t *testing.T) {
	type val struct {
		fail   int
		expect time.Duration
	}
	inps := []val{
		{1, 3 * time.Second},
		{2, 6 * time.Second},
		{3, 12 * time.Second},
		{4, 24 * time.Second},
	}
	for _, inp := range inps {
		if out := backoff(3*time.Second, inp.fail); out != inp.expect {
			t.Fatalf("bad: %v %v", inp, out)
		}
	}
}

func TestFormatOutput(t *testing.T) {
	inp := map[string][]*consulapi.ServiceEntry{
		"foo": []*consulapi.ServiceEntry{
			&consulapi.ServiceEntry{
				Node:    &consulapi.Node{Node: "node1", Address: "127.0.0.1"},
				Service: &consulapi.AgentService{ID: "redis", Port: 8000},
			},
			&consulapi.ServiceEntry{
				Node:    &consulapi.Node{Node: "node3", Address: "127.0.0.3"},
				Service: &consulapi.AgentService{ID: "redis", Port: 1234},
			},
		},
		"bar": []*consulapi.ServiceEntry{
			&consulapi.ServiceEntry{
				Node:    &consulapi.Node{Node: "node2", Address: "127.0.0.2"},
				Service: &consulapi.AgentService{ID: "memcache", Port: 80},
			},
			&consulapi.ServiceEntry{
				Node:    &consulapi.Node{Node: "node4", Address: "127.0.0.4"},
				Service: &consulapi.AgentService{ID: "memcache", Port: 10000},
			},
		},
	}

	output := formatOutput(inp)
	if len(output) != 2 {
		t.Fatalf("bad: %v", output)
	}
	foo := output["foo"]
	if len(foo) != 2 {
		t.Fatalf("bad: %v", foo)
	}
	if foo[0] != "server node1_redis 127.0.0.1:8000" {
		t.Fatalf("Bad: %v", foo)
	}
	if foo[1] != "server node3_redis 127.0.0.3:1234" {
		t.Fatalf("Bad: %v", foo)
	}

	bar := output["bar"]
	if len(bar) != 2 {
		t.Fatalf("bad: %v", bar)
	}
	if bar[0] != "server node2_memcache 127.0.0.2:80" {
		t.Fatalf("Bad: %v", bar)
	}
	if bar[1] != "server node4_memcache 127.0.0.4:10000" {
		t.Fatalf("Bad: %v", bar)
	}
}
<|endoftext|>


<commit_before>// Code generated by private/model/cli/gen-api/main.go. DO NOT EDIT.

package wafv2

import (
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/client"
	"github.com/aws/aws-sdk-go/aws/client/metadata"
	"github.com/aws/aws-sdk-go/aws/request"
	"github.com/aws/aws-sdk-go/aws/signer/v4"
	"github.com/aws/aws-sdk-go/private/protocol/jsonrpc"
)

// WAFV2 provides the API operation methods for making requests to
// AWS WAFV2. See this package's package overview docs
// for details on the service.
//
// WAFV2 methods are safe to use concurrently. It is not safe to
// modify mutate any of the struct's properties though.
type WAFV2 struct {
	*client.Client
}

// Used for custom client initialization logic
var initClient func(*client.Client)

// Used for custom request initialization logic
var initRequest func(*request.Request)

// Service information constants
const (
	ServiceName = "WAFV2" // Name of service.
	EndpointsID = "wafv2" // ID to lookup a service endpoint with.
	ServiceID   = "WAFV2" // ServiceID is a unique identifer of a specific service.
)

// New creates a new instance of the WAFV2 client with a session.
// If additional configuration is needed for the client instance use the optional
// aws.Config parameter to add your extra config.
//
// Example:
//     mySession := session.Must(session.NewSession())
//
//     // Create a WAFV2 client from just a session.
//     svc := wafv2.New(mySession)
//
//     // Create a WAFV2 client with additional configuration
//     svc := wafv2.New(mySession, aws.NewConfig().WithRegion("us-west-2"))
func New(p client.ConfigProvider, cfgs ...*aws.Config) *WAFV2 {
	c := p.ClientConfig(EndpointsID, cfgs...)
	return newClient(*c.Config, c.Handlers, c.PartitionID, c.Endpoint, c.SigningRegion, c.SigningName)
}

// newClient creates, initializes and returns a new service client instance.
func newClient(cfg aws.Config, handlers request.Handlers, partitionID, endpoint, signingRegion, signingName string) *WAFV2 {
	svc := &WAFV2{
		Client: client.New(
			cfg,
			metadata.ClientInfo{
				ServiceName:   ServiceName,
				ServiceID:     ServiceID,
				SigningName:   signingName,
				SigningRegion: signingRegion,
				PartitionID:   partitionID,
				Endpoint:      endpoint,
				APIVersion:    "2019-07-29",
				JSONVersion:   "1.1",
				TargetPrefix:  "AWSWAF_20190729",
			},
			handlers,
		),
	}

	// Handlers
	svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler)
	svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler)
	svc.Handlers.Unmarshal.PushBackNamed(jsonrpc.UnmarshalHandler)
	svc.Handlers.UnmarshalMeta.PushBackNamed(jsonrpc.UnmarshalMetaHandler)
	svc.Handlers.UnmarshalError.PushBackNamed(jsonrpc.UnmarshalErrorHandler)

	// Run custom client initialization if present
	if initClient != nil {
		initClient(svc.Client)
	}

	return svc
}

// newRequest creates a new request for a WAFV2 operation and runs any
// custom request initialization.
func (c *WAFV2) newRequest(op *request.Operation, params, data interface{}) *request.Request {
	req := c.NewRequest(op, params, data)

	// Run custom request initialization if present
	if initRequest != nil {
		initRequest(req)
	}

	return req
}
<commit_msg>deps: Update github.com/aws/aws-sdk-go/service/wafv2 vendor directory to match current dependency<commit_after>// Code generated by private/model/cli/gen-api/main.go. DO NOT EDIT.

package wafv2

import (
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/client"
	"github.com/aws/aws-sdk-go/aws/client/metadata"
	"github.com/aws/aws-sdk-go/aws/request"
	"github.com/aws/aws-sdk-go/aws/signer/v4"
	"github.com/aws/aws-sdk-go/private/protocol/jsonrpc"
)

// WAFV2 provides the API operation methods for making requests to
// AWS WAFV2. See this package's package overview docs
// for details on the service.
//
// WAFV2 methods are safe to use concurrently. It is not safe to
// modify mutate any of the struct's properties though.
type WAFV2 struct {
	*client.Client
}

// Used for custom client initialization logic
var initClient func(*client.Client)

// Used for custom request initialization logic
var initRequest func(*request.Request)

// Service information constants
const (
	ServiceName = "WAFV2" // Name of service.
	EndpointsID = "wafv2" // ID to lookup a service endpoint with.
	ServiceID   = "WAFV2" // ServiceID is a unique identifier of a specific service.
)

// New creates a new instance of the WAFV2 client with a session.
// If additional configuration is needed for the client instance use the optional
// aws.Config parameter to add your extra config.
//
// Example:
//     mySession := session.Must(session.NewSession())
//
//     // Create a WAFV2 client from just a session.
//     svc := wafv2.New(mySession)
//
//     // Create a WAFV2 client with additional configuration
//     svc := wafv2.New(mySession, aws.NewConfig().WithRegion("us-west-2"))
func New(p client.ConfigProvider, cfgs ...*aws.Config) *WAFV2 {
	c := p.ClientConfig(EndpointsID, cfgs...)
	return newClient(*c.Config, c.Handlers, c.PartitionID, c.Endpoint, c.SigningRegion, c.SigningName)
}

// newClient creates, initializes and returns a new service client instance.
func newClient(cfg aws.Config, handlers request.Handlers, partitionID, endpoint, signingRegion, signingName string) *WAFV2 {
	svc := &WAFV2{
		Client: client.New(
			cfg,
			metadata.ClientInfo{
				ServiceName:   ServiceName,
				ServiceID:     ServiceID,
				SigningName:   signingName,
				SigningRegion: signingRegion,
				PartitionID:   partitionID,
				Endpoint:      endpoint,
				APIVersion:    "2019-07-29",
				JSONVersion:   "1.1",
				TargetPrefix:  "AWSWAF_20190729",
			},
			handlers,
		),
	}

	// Handlers
	svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler)
	svc.Handlers.Build.PushBackNamed(jsonrpc.BuildHandler)
	svc.Handlers.Unmarshal.PushBackNamed(jsonrpc.UnmarshalHandler)
	svc.Handlers.UnmarshalMeta.PushBackNamed(jsonrpc.UnmarshalMetaHandler)
	svc.Handlers.UnmarshalError.PushBackNamed(jsonrpc.UnmarshalErrorHandler)

	// Run custom client initialization if present
	if initClient != nil {
		initClient(svc.Client)
	}

	return svc
}

// newRequest creates a new request for a WAFV2 operation and runs any
// custom request initialization.
func (c *WAFV2) newRequest(op *request.Operation, params, data interface{}) *request.Request {
	req := c.NewRequest(op, params, data)

	// Run custom request initialization if present
	if initRequest != nil {
		initRequest(req)
	}

	return req
}
<|endoftext|>


<commit_before>package volumeplugin

import (
	"encoding/json"
	"fmt"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/docker/go-plugins-helpers/volume"
	"github.com/pkg/errors"
	"github.com/rancher/go-rancher-metadata/metadata"
	"github.com/rancher/go-rancher/v2"
)

const (
	metadataURL = "http://169.254.169.250/2015-12-19"
)

var goodStates = map[string]bool{
	"active":       true,
	"activating":   true,
	"deactivating": true,
	"detached":     true,
	"removing":     true,
}

type RancherState struct {
	client   *client.RancherClient
	driver   string
	hostID   string
	driverID string
}

func NewRancherState(driver string, client *client.RancherClient) (*RancherState, error) {
	host, err := getHostID(client)
	if err != nil {
		return nil, errors.Wrap(err, "getting host ID")
	}
	driverID, err := getDriverID(driver, client)
	if err != nil {
		return nil, errors.Wrap(err, "getting host ID")
	}

	logrus.Infof("Running on host %s(%s) with driver %s(%s)", host.Hostname, host.Id, driver, driverID)
	return &RancherState{
		client:   client,
		driver:   driver,
		hostID:   host.Id,
		driverID: driverID,
	}, nil
}

func (r *RancherState) IsCreated(name string) (bool, error) {
	_, _, err := r.Get(name)
	if err == errNoSuchVolume {
		return false, nil
	}
	if err != nil {
		return false, err
	}
	return true, nil
}

func (r *RancherState) Save(name string, options map[string]string) error {
	// Wait for the volume to be created by Rancher
	_, vol, err := r.getAny(name)
	for tries := 1; err != nil; tries++ {
		if tries == 10 {
			return errors.Wrap(err, "Max tries reached")
		}

		_, vol, err = r.getAny(name)

		if err != nil {
			if err == errNoSuchVolume {
				time.Sleep(time.Second)
				continue
			} else {
				return err
			}
		} else {
			break
		}
	}

	//logrus.Infof("Update volume name=%s state=%s in Rancher", name, vol.State)
	_, err = r.client.Volume.Update(vol, &client.Volume{
		Name:            name,
		Driver:          r.driver,
		StorageDriverId: r.driverID,
		DriverOpts:      toMapInterface(options),
		HostId:          r.hostID,
	})
	return err
}

func (r *RancherState) List() ([]*volume.Volume, error) {
	vols, err := r.client.Volume.List(&client.ListOpts{
		Filters: map[string]interface{}{
			"removed_null":    "true",
			"limit":           "-1",
			"storageDriverId": r.driverID,
		},
	})
	if err != nil {
		return nil, err
	}
	result := []*volume.Volume{}
	for _, vol := range vols.Data {
		if isCreated(r.driver, vol) {
			result = append(result, volToVol(vol))
		}
	}

	return result, nil
}

func isCreated(driver string, vol client.Volume) bool {
	return goodStates[vol.State]
}

func (r *RancherState) getAny(name string) (*volume.Volume, *client.Volume, error) {
	vols, err := r.client.Volume.List(&client.ListOpts{
		Filters: map[string]interface{}{
			"name":            name,
			"removed_null":    "true",
			"storageDriverId": r.driverID,
		},
	})
	if err != nil {
		return nil, nil, err
	}

	if len(vols.Data) == 0 {
		return nil, nil, errNoSuchVolume
	}

	return volToVol(vols.Data[0]), &vols.Data[0], nil
}

func (r *RancherState) Get(name string) (*volume.Volume, *client.Volume, error) {
	vols, err := r.client.Volume.List(&client.ListOpts{
		Filters: map[string]interface{}{
			"name":            name,
			"removed_null":    "true",
			"storageDriverId": r.driverID,
		},
	})
	if err != nil {
		return nil, nil, err
	}

	if len(vols.Data) > 1 {
		logrus.Warnf("%d volumes with name=%s found in Rancher", len(vols.Data), name)
	}

	for _, vol := range vols.Data {
		if isCreated(r.driver, vol) {
			return volToVol(vol), &vol, nil
		}
	}

	return nil, nil, errNoSuchVolume
}

func volToVol(vol client.Volume) *volume.Volume {
	result := &volume.Volume{
		Name:   vol.Name,
		Status: map[string]interface{}{},
	}
	bytes, err := json.Marshal(vol)
	if err == nil {
		json.Unmarshal(bytes, &result.Status)
	}
	return result
}

func toMapInterface(data map[string]string) map[string]interface{} {
	result := map[string]interface{}{}
	for k, v := range data {
		result[k] = v
	}
	return result
}

func getDriverID(driver string, c *client.RancherClient) (string, error) {
	drivers, err := c.StorageDriver.List(&client.ListOpts{
		Filters: map[string]interface{}{
			"name":         driver,
			"removed_null": true,
		},
	})
	if err != nil {
		return "", err
	}
	if len(drivers.Data) != 1 {
		return "", fmt.Errorf("%s is not a driver registered with the current Rancher environment", driver)
	}
	return drivers.Data[0].Id, nil
}

func getHostID(c *client.RancherClient) (*client.Host, error) {
	m, err := metadata.NewClientAndWait(metadataURL)
	if err != nil {
		return nil, errors.Wrap(err, "initializing metadata")
	}
	mHost, err := m.GetSelfHost()
	if err != nil {
		return nil, err
	}
	hosts, err := c.Host.List(&client.ListOpts{
		Filters: map[string]interface{}{
			"uuid": mHost.UUID,
		},
	})
	if len(hosts.Data) != 1 {
		return nil, fmt.Errorf("Failed to find current host %s, got %d host(s)", mHost.UUID, len(hosts.Data))
	}
	return &hosts.Data[0], nil
}
<commit_msg>wait 30s for rancher to create volume<commit_after>package volumeplugin

import (
	"encoding/json"
	"fmt"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/docker/go-plugins-helpers/volume"
	"github.com/pkg/errors"
	"github.com/rancher/go-rancher-metadata/metadata"
	"github.com/rancher/go-rancher/v2"
)

const (
	metadataURL = "http://169.254.169.250/2015-12-19"
)

var goodStates = map[string]bool{
	"active":       true,
	"activating":   true,
	"deactivating": true,
	"detached":     true,
	"removing":     true,
}

type RancherState struct {
	client   *client.RancherClient
	driver   string
	hostID   string
	driverID string
}

func NewRancherState(driver string, client *client.RancherClient) (*RancherState, error) {
	host, err := getHostID(client)
	if err != nil {
		return nil, errors.Wrap(err, "getting host ID")
	}
	driverID, err := getDriverID(driver, client)
	if err != nil {
		return nil, errors.Wrap(err, "getting host ID")
	}

	logrus.Infof("Running on host %s(%s) with driver %s(%s)", host.Hostname, host.Id, driver, driverID)
	return &RancherState{
		client:   client,
		driver:   driver,
		hostID:   host.Id,
		driverID: driverID,
	}, nil
}

func (r *RancherState) IsCreated(name string) (bool, error) {
	_, _, err := r.Get(name)
	if err == errNoSuchVolume {
		return false, nil
	}
	if err != nil {
		return false, err
	}
	return true, nil
}

func (r *RancherState) Save(name string, options map[string]string) error {
	// Wait for the volume to be created by Rancher
	_, vol, err := r.getAny(name)
	for tries := 1; err != nil; tries++ {
		if tries == 30 {
			return errors.Wrap(err, "Max tries reached")
		}

		_, vol, err = r.getAny(name)

		if err != nil {
			if err == errNoSuchVolume {
				time.Sleep(time.Second)
				continue
			} else {
				return err
			}
		} else {
			break
		}
	}

	//logrus.Infof("Update volume name=%s state=%s in Rancher", name, vol.State)
	_, err = r.client.Volume.Update(vol, &client.Volume{
		Name:            name,
		Driver:          r.driver,
		StorageDriverId: r.driverID,
		DriverOpts:      toMapInterface(options),
		HostId:          r.hostID,
	})
	return err
}

func (r *RancherState) List() ([]*volume.Volume, error) {
	vols, err := r.client.Volume.List(&client.ListOpts{
		Filters: map[string]interface{}{
			"removed_null":    "true",
			"limit":           "-1",
			"storageDriverId": r.driverID,
		},
	})
	if err != nil {
		return nil, err
	}
	result := []*volume.Volume{}
	for _, vol := range vols.Data {
		if isCreated(r.driver, vol) {
			result = append(result, volToVol(vol))
		}
	}

	return result, nil
}

func isCreated(driver string, vol client.Volume) bool {
	return goodStates[vol.State]
}

func (r *RancherState) getAny(name string) (*volume.Volume, *client.Volume, error) {
	vols, err := r.client.Volume.List(&client.ListOpts{
		Filters: map[string]interface{}{
			"name":            name,
			"removed_null":    "true",
			"storageDriverId": r.driverID,
		},
	})
	if err != nil {
		return nil, nil, err
	}

	if len(vols.Data) == 0 {
		return nil, nil, errNoSuchVolume
	}

	return volToVol(vols.Data[0]), &vols.Data[0], nil
}

func (r *RancherState) Get(name string) (*volume.Volume, *client.Volume, error) {
	vols, err := r.client.Volume.List(&client.ListOpts{
		Filters: map[string]interface{}{
			"name":            name,
			"removed_null":    "true",
			"storageDriverId": r.driverID,
		},
	})
	if err != nil {
		return nil, nil, err
	}

	if len(vols.Data) > 1 {
		logrus.Warnf("%d volumes with name=%s found in Rancher", len(vols.Data), name)
	}

	for _, vol := range vols.Data {
		if isCreated(r.driver, vol) {
			return volToVol(vol), &vol, nil
		}
	}

	return nil, nil, errNoSuchVolume
}

func volToVol(vol client.Volume) *volume.Volume {
	result := &volume.Volume{
		Name:   vol.Name,
		Status: map[string]interface{}{},
	}
	bytes, err := json.Marshal(vol)
	if err == nil {
		json.Unmarshal(bytes, &result.Status)
	}
	return result
}

func toMapInterface(data map[string]string) map[string]interface{} {
	result := map[string]interface{}{}
	for k, v := range data {
		result[k] = v
	}
	return result
}

func getDriverID(driver string, c *client.RancherClient) (string, error) {
	drivers, err := c.StorageDriver.List(&client.ListOpts{
		Filters: map[string]interface{}{
			"name":         driver,
			"removed_null": true,
		},
	})
	if err != nil {
		return "", err
	}
	if len(drivers.Data) != 1 {
		return "", fmt.Errorf("%s is not a driver registered with the current Rancher environment", driver)
	}
	return drivers.Data[0].Id, nil
}

func getHostID(c *client.RancherClient) (*client.Host, error) {
	m, err := metadata.NewClientAndWait(metadataURL)
	if err != nil {
		return nil, errors.Wrap(err, "initializing metadata")
	}
	mHost, err := m.GetSelfHost()
	if err != nil {
		return nil, err
	}
	hosts, err := c.Host.List(&client.ListOpts{
		Filters: map[string]interface{}{
			"uuid": mHost.UUID,
		},
	})
	if len(hosts.Data) != 1 {
		return nil, fmt.Errorf("Failed to find current host %s, got %d host(s)", mHost.UUID, len(hosts.Data))
	}
	return &hosts.Data[0], nil
}
<|endoftext|>