<commit_before>package tcpoverdns

import (
	"bytes"
	"compress/flate"
	"compress/gzip"
	"compress/lzw"
	"compress/zlib"
	"crypto/rand"
	"encoding/base64"
	"fmt"
	"reflect"
	"testing"
	"time"
)

func TestSegment_Packet(t *testing.T) {
	want := Segment{
		ID:     12345,
		Flags:  FlagHandshakeAck & FlagHandshakeSyn,
		SeqNum: 23456,
		AckNum: 34567,
		Data:   []byte{1, 2, 3, 4},
	}

	packet := want.Packet()
	got := SegmentFromPacket(packet)
	if !reflect.DeepEqual(got, want) {
		t.Fatalf("recovered: %+#v original: %+#v", got, want)
	}

	want.Flags = FlagHandshakeSyn
	packet = want.Packet()
	got = SegmentFromPacket(packet)
	if !reflect.DeepEqual(got, Segment{Flags: FlagMalformed}) {
		t.Fatal("did not identify malformed segment without initiator config")
	}
}

func TestSegmentFromMalformedPacket(t *testing.T) {
	want := Segment{Flags: FlagMalformed}
	segWithData := Segment{Data: []byte{1, 2}}
	segWithMalformedLen := segWithData.Packet()
	for _, seg := range [][]byte{nil, {1}, segWithMalformedLen[:SegmentHeaderLen+1]} {
		if got := SegmentFromPacket(seg); !reflect.DeepEqual(got, want) {
			t.Fatalf("got: %+#v, want: %+#v", got, want)
		}
	}
}

func TestFlags(t *testing.T) {
	allFlags := FlagHandshakeSyn | FlagHandshakeAck | FlagAckOnly | FlagKeepAlive | FlagReset | FlagMalformed
	for _, flag := range []Flag{FlagHandshakeSyn, FlagHandshakeAck, FlagAckOnly, FlagKeepAlive, FlagReset, FlagMalformed} {
		if !allFlags.Has(flag) {
			t.Fatalf("missing %d", flag)
		}
	}
	if allFlags.Has(1 << 6) {
		t.Fatalf("should not have had flag %d", 1<<4)
	}
}

func TestSegment_Equals(t *testing.T) {
	original := Segment{
		ID:     12345,
		Flags:  FlagHandshakeAck & FlagHandshakeSyn,
		SeqNum: 23456,
		AckNum: 34567,
		Data:   []byte{1, 2, 3, 4},
	}
	if !original.Equals(original) {
		t.Errorf("should have been equal")
	}

	tests := []struct {
		a, b Segment
	}{
		{a: Segment{ID: 1}, b: Segment{ID: 2}},
		{a: Segment{Flags: 1}, b: Segment{Flags: 2}},
		{a: Segment{SeqNum: 1}, b: Segment{SeqNum: 2}},
		{a: Segment{AckNum: 1}, b: Segment{AckNum: 2}},
		{a: Segment{Data: []byte{0}}, b: Segment{Data: []byte{1}}},
	}
	for _, test := range tests {
		if test.a.Equals(test.b) {
			t.Errorf("should not have been equal: %+v, %+v", test.a, test.b)
		}
	}
}

func TestCompression(t *testing.T) {
	// original := `The words of the Teacher, son of David, king in Jerusalem: “Meaningless! Meaningless!” says the Teacher. “Utterly meaningless! Everything is meaningless.” What do people gain from all their labors at which they toil under the sun?`
	original := `<!doctype html><html itemscope="" itemtype="http://schema.org/WebPage" lang="en-IE"><head><meta charset="UTF-8"><meta content="dark" name="color-scheme"><meta content="origin" name="referrer"><meta content="/images/branding/googleg/1x/googleg_standard_colo`

	t.Run("zlib", func(t *testing.T) {
		var b bytes.Buffer
		w, err := zlib.NewWriterLevel(&b, zlib.BestCompression)
		if err != nil {
			t.Fatal(err)
		}
		w.Write([]byte(original))
		w.Close()
		fmt.Println("zlib", len(b.Bytes()), len(base64.StdEncoding.EncodeToString(b.Bytes())))
	})

	t.Run("lzw", func(t *testing.T) {
		var b bytes.Buffer
		w := lzw.NewWriter(&b, lzw.MSB, 8)
		w.Write([]byte(original))
		w.Close()
		fmt.Println("lzw", len(b.Bytes()), len(base64.StdEncoding.EncodeToString(b.Bytes())))
	})

	t.Run("flate", func(t *testing.T) {
		var b bytes.Buffer
		w, err := flate.NewWriter(&b, flate.BestCompression)
		if err != nil {
			t.Fatal(err)
		}
		w.Write([]byte(original))
		w.Close()
		fmt.Println("flate", len(b.Bytes()), len(base64.StdEncoding.EncodeToString(b.Bytes())))
	})

	t.Run("gzip", func(t *testing.T) {
		var b bytes.Buffer
		w, err := gzip.NewWriterLevel(&b, gzip.BestCompression)
		if err != nil {
			t.Fatal(err)
		}
		w.Write([]byte(original))
		w.Close()
		fmt.Println("gzip", len(b.Bytes()), len(base64.StdEncoding.EncodeToString(b.Bytes())))
	})

	t.Run("base64", func(t *testing.T) {
		fmt.Println(base64.StdEncoding.DecodeString("TQ=="))
	})
}

func TestCompressDecompressBytes(t *testing.T) {
	tests := [][]byte{
		{},
		{0},
		{0, 1},
		{0, 1, 2},
		[]byte(`<!doctype html><html itemscope="" itemtype="http://schema.org/WebPage" lang="en-IE"><head><meta charset="UTF-8"><meta content="dark" name="color-scheme"><meta content="origin" name="referrer"><meta content="/images/branding/googleg/1x/googleg_standard_colo`),
	}
	for _, original := range tests {
		compressed := CompressBytes(original)
		got, err := DecompressBytes(compressed)
		if err != nil || !reflect.DeepEqual(got, original) {
			t.Fatalf("DecompressBytes(%+v): got %+v, want %+v", compressed, got, original)
		}
	}
}

func TestSegment_DNSQuestion(t *testing.T) {
	randData := make([]byte, 100)
	if _, err := rand.Read(randData); err != nil {
		t.Fatal(err)
	}
	want := Segment{
		ID:     12345,
		Flags:  FlagHandshakeAck & FlagHandshakeSyn,
		SeqNum: 23456,
		AckNum: 34567,
		Data:   randData,
	}
	dnsQuestion := want.DNSQuestion("prefix-label", "example.com")
	fmt.Println(dnsQuestion.Name.String())
	got := SegmentFromDNSName(2, dnsQuestion.Name.String())
	if !reflect.DeepEqual(got, want) {
		t.Errorf("recovered: %+#v original: %+#v", got, want)
	}
	// Try the same conversion, but without the domain name.
	qWithoutDomain := want.DNSQuestion("prefix-label", "")
	fmt.Println(qWithoutDomain.Name.String())
	gotWithoutDomain := SegmentFromDNSName(0, qWithoutDomain.Name.String())
	if !reflect.DeepEqual(gotWithoutDomain, want) {
		t.Errorf("recovered: %+#v original: %+#v", got, want)
	}
}

func TestInitiatorConfig(t *testing.T) {
	wantTiming := TimingConfig{
		SlidingWindowWaitDuration: 1000 * time.Millisecond,
		RetransmissionInterval:    1234 * time.Millisecond,
		AckDelay:                  3456 * time.Millisecond,
		KeepAliveInterval:         4567 * time.Millisecond,
		ReadTimeout:               5678 * time.Millisecond,
		WriteTimeout:              7890 * time.Millisecond,
	}
	want := &InitiatorConfig{
		SetConfig:               true,
		MaxSegmentLenExclHeader: 123,
		Debug:                   true,
		Timing:                  wantTiming,
	}
	serialised := want.Bytes()
	got := DeserialiseInitiatorConfig(serialised)
	if !reflect.DeepEqual(got, want) {
		t.Fatalf("got: %+#v want: %+#v", got, want)
	}

	wantTC := &TransmissionControl{
		MaxSegmentLenExclHeader: 123,
		MaxSlidingWindow:        123 * 4,
		InitialTiming:           wantTiming,
		LiveTiming:              wantTiming,
		Debug:                   true,
	}
	gotTC := &TransmissionControl{}
	got.Config(gotTC)
	if !reflect.DeepEqual(gotTC, wantTC) {
		t.Fatalf("got: %+#v want: %+#v", gotTC, wantTC)
	}
}

func TestSegment_DNSNameQuery(t *testing.T) {
	randData := make([]byte, 100)
	if _, err := rand.Read(randData); err != nil {
		t.Fatal(err)
	}
	want := Segment{
		ID:     12345,
		Flags:  FlagHandshakeAck & FlagHandshakeSyn,
		SeqNum: 23456,
		AckNum: 34567,
		Data:   randData,
	}
	query := want.DNSNameQuery("prefix-label", "example.com")
	fmt.Println(query)
	got := SegmentFromDNSName(2, query)
	if !reflect.DeepEqual(got, want) {
		t.Errorf("recovered: %+#v original: %+#v", got, want)
	}
}
<commit_msg>tcpoverdns: fix failed DNSQuestion test<commit_after>package tcpoverdns

import (
	"bytes"
	"compress/flate"
	"compress/gzip"
	"compress/lzw"
	"compress/zlib"
	"crypto/rand"
	"encoding/base64"
	"fmt"
	"reflect"
	"testing"
	"time"
)

func TestSegment_Packet(t *testing.T) {
	want := Segment{
		ID:     12345,
		Flags:  FlagHandshakeAck & FlagHandshakeSyn,
		SeqNum: 23456,
		AckNum: 34567,
		Data:   []byte{1, 2, 3, 4},
	}

	packet := want.Packet()
	got := SegmentFromPacket(packet)
	if !reflect.DeepEqual(got, want) {
		t.Fatalf("recovered: %+#v original: %+#v", got, want)
	}

	want.Flags = FlagHandshakeSyn
	packet = want.Packet()
	got = SegmentFromPacket(packet)
	if !reflect.DeepEqual(got, Segment{Flags: FlagMalformed}) {
		t.Fatal("did not identify malformed segment without initiator config")
	}
}

func TestSegmentFromMalformedPacket(t *testing.T) {
	want := Segment{Flags: FlagMalformed}
	segWithData := Segment{Data: []byte{1, 2}}
	segWithMalformedLen := segWithData.Packet()
	for _, seg := range [][]byte{nil, {1}, segWithMalformedLen[:SegmentHeaderLen+1]} {
		if got := SegmentFromPacket(seg); !reflect.DeepEqual(got, want) {
			t.Fatalf("got: %+#v, want: %+#v", got, want)
		}
	}
}

func TestFlags(t *testing.T) {
	allFlags := FlagHandshakeSyn | FlagHandshakeAck | FlagAckOnly | FlagKeepAlive | FlagReset | FlagMalformed
	for _, flag := range []Flag{FlagHandshakeSyn, FlagHandshakeAck, FlagAckOnly, FlagKeepAlive, FlagReset, FlagMalformed} {
		if !allFlags.Has(flag) {
			t.Fatalf("missing %d", flag)
		}
	}
	if allFlags.Has(1 << 6) {
		t.Fatalf("should not have had flag %d", 1<<4)
	}
}

func TestSegment_Equals(t *testing.T) {
	original := Segment{
		ID:     12345,
		Flags:  FlagHandshakeAck & FlagHandshakeSyn,
		SeqNum: 23456,
		AckNum: 34567,
		Data:   []byte{1, 2, 3, 4},
	}
	if !original.Equals(original) {
		t.Errorf("should have been equal")
	}

	tests := []struct {
		a, b Segment
	}{
		{a: Segment{ID: 1}, b: Segment{ID: 2}},
		{a: Segment{Flags: 1}, b: Segment{Flags: 2}},
		{a: Segment{SeqNum: 1}, b: Segment{SeqNum: 2}},
		{a: Segment{AckNum: 1}, b: Segment{AckNum: 2}},
		{a: Segment{Data: []byte{0}}, b: Segment{Data: []byte{1}}},
	}
	for _, test := range tests {
		if test.a.Equals(test.b) {
			t.Errorf("should not have been equal: %+v, %+v", test.a, test.b)
		}
	}
}

func TestCompression(t *testing.T) {
	// original := `The words of the Teacher, son of David, king in Jerusalem: “Meaningless! Meaningless!” says the Teacher. “Utterly meaningless! Everything is meaningless.” What do people gain from all their labors at which they toil under the sun?`
	original := `<!doctype html><html itemscope="" itemtype="http://schema.org/WebPage" lang="en-IE"><head><meta charset="UTF-8"><meta content="dark" name="color-scheme"><meta content="origin" name="referrer"><meta content="/images/branding/googleg/1x/googleg_standard_colo`

	t.Run("zlib", func(t *testing.T) {
		var b bytes.Buffer
		w, err := zlib.NewWriterLevel(&b, zlib.BestCompression)
		if err != nil {
			t.Fatal(err)
		}
		w.Write([]byte(original))
		w.Close()
		fmt.Println("zlib", len(b.Bytes()), len(base64.StdEncoding.EncodeToString(b.Bytes())))
	})

	t.Run("lzw", func(t *testing.T) {
		var b bytes.Buffer
		w := lzw.NewWriter(&b, lzw.MSB, 8)
		w.Write([]byte(original))
		w.Close()
		fmt.Println("lzw", len(b.Bytes()), len(base64.StdEncoding.EncodeToString(b.Bytes())))
	})

	t.Run("flate", func(t *testing.T) {
		var b bytes.Buffer
		w, err := flate.NewWriter(&b, flate.BestCompression)
		if err != nil {
			t.Fatal(err)
		}
		w.Write([]byte(original))
		w.Close()
		fmt.Println("flate", len(b.Bytes()), len(base64.StdEncoding.EncodeToString(b.Bytes())))
	})

	t.Run("gzip", func(t *testing.T) {
		var b bytes.Buffer
		w, err := gzip.NewWriterLevel(&b, gzip.BestCompression)
		if err != nil {
			t.Fatal(err)
		}
		w.Write([]byte(original))
		w.Close()
		fmt.Println("gzip", len(b.Bytes()), len(base64.StdEncoding.EncodeToString(b.Bytes())))
	})

	t.Run("base64", func(t *testing.T) {
		fmt.Println(base64.StdEncoding.DecodeString("TQ=="))
	})
}

func TestCompressDecompressBytes(t *testing.T) {
	tests := [][]byte{
		{},
		{0},
		{0, 1},
		{0, 1, 2},
		[]byte(`<!doctype html><html itemscope="" itemtype="http://schema.org/WebPage" lang="en-IE"><head><meta charset="UTF-8"><meta content="dark" name="color-scheme"><meta content="origin" name="referrer"><meta content="/images/branding/googleg/1x/googleg_standard_colo`),
	}
	for _, original := range tests {
		compressed := CompressBytes(original)
		got, err := DecompressBytes(compressed)
		if err != nil || !reflect.DeepEqual(got, original) {
			t.Fatalf("DecompressBytes(%+v): got %+v, want %+v", compressed, got, original)
		}
	}
}

func TestSegment_DNSQuestion(t *testing.T) {
	randData := make([]byte, 100)
	if _, err := rand.Read(randData); err != nil {
		t.Fatal(err)
	}
	want := Segment{
		ID:     12345,
		Flags:  FlagHandshakeAck & FlagHandshakeSyn,
		SeqNum: 23456,
		AckNum: 34567,
		Data:   randData,
	}
	dnsQuestion := want.DNSQuestion("prefix-label", "example.com")
	fmt.Println(dnsQuestion.Name.String())
	got := SegmentFromDNSName(2, dnsQuestion.Name.String())
	if !reflect.DeepEqual(got, want) {
		t.Errorf("recovered: \n%+#v\noriginal: \n%+#v\n", got, want)
	}
}

func TestInitiatorConfig(t *testing.T) {
	wantTiming := TimingConfig{
		SlidingWindowWaitDuration: 1000 * time.Millisecond,
		RetransmissionInterval:    1234 * time.Millisecond,
		AckDelay:                  3456 * time.Millisecond,
		KeepAliveInterval:         4567 * time.Millisecond,
		ReadTimeout:               5678 * time.Millisecond,
		WriteTimeout:              7890 * time.Millisecond,
	}
	want := &InitiatorConfig{
		SetConfig:               true,
		MaxSegmentLenExclHeader: 123,
		Debug:                   true,
		Timing:                  wantTiming,
	}
	serialised := want.Bytes()
	got := DeserialiseInitiatorConfig(serialised)
	if !reflect.DeepEqual(got, want) {
		t.Fatalf("got: %+#v want: %+#v", got, want)
	}

	wantTC := &TransmissionControl{
		MaxSegmentLenExclHeader: 123,
		MaxSlidingWindow:        123 * 4,
		InitialTiming:           wantTiming,
		LiveTiming:              wantTiming,
		Debug:                   true,
	}
	gotTC := &TransmissionControl{}
	got.Config(gotTC)
	if !reflect.DeepEqual(gotTC, wantTC) {
		t.Fatalf("got: %+#v want: %+#v", gotTC, wantTC)
	}
}

func TestSegment_DNSNameQuery(t *testing.T) {
	randData := make([]byte, 100)
	if _, err := rand.Read(randData); err != nil {
		t.Fatal(err)
	}
	want := Segment{
		ID:     12345,
		Flags:  FlagHandshakeAck & FlagHandshakeSyn,
		SeqNum: 23456,
		AckNum: 34567,
		Data:   randData,
	}
	query := want.DNSNameQuery("prefix-label", "example.com")
	fmt.Println(query)
	got := SegmentFromDNSName(2, query)
	if !reflect.DeepEqual(got, want) {
		t.Errorf("recovered: %+#v original: %+#v", got, want)
	}
}
<|endoftext|>


<commit_before>package tracer

import (
	"fmt"
	"time"

	"github.com/tracer/tracer/pb"

	"github.com/golang/protobuf/ptypes"
	"github.com/prometheus/client_golang/prometheus"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
)

// GRPC is a gRPC-based transport for sending spans to a server.
type GRPC struct {
	client        pb.StorerClient
	queue         []RawSpan
	ch            chan RawSpan
	flushInterval time.Duration
	logger        Logger

	stored  prometheus.Counter
	dropped prometheus.Counter
}

// GRPCOptions are options for the GRPC storer.
type GRPCOptions struct {
	// How many spans to queue before sending them to the server.
	// Additionally, a buffer the size of 2*QueueSize will be used to
	// process new spans. If this buffer runs full, new spans will be
	// dropped.
	QueueSize int
	// How often to flush spans, even if the queue isn't full yet.
	FlushInterval time.Duration
	// Where to log errors. If nil, the default logger will be used.
	Logger Logger
}

// NewGRPC returns a new Storer that sends spans via gRPC to a server.
func NewGRPC(address string, grpcOpts *GRPCOptions, opts ...grpc.DialOption) (Storer, error) {
	if grpcOpts == nil {
		grpcOpts = &GRPCOptions{
			QueueSize:     1024,
			FlushInterval: 1 * time.Second,
		}
	}
	if grpcOpts.Logger == nil {
		grpcOpts.Logger = defaultLogger{}
	}
	conn, err := grpc.Dial(address, opts...)
	if err != nil {
		return nil, err
	}
	client := pb.NewStorerClient(conn)
	g := &GRPC{
		client:        client,
		queue:         make([]RawSpan, 0, grpcOpts.QueueSize),
		ch:            make(chan RawSpan, grpcOpts.QueueSize*2),
		flushInterval: grpcOpts.FlushInterval,

		stored: prometheus.NewCounter(prometheus.CounterOpts{
			Name: "tracer_stored_spans_total",
			Help: "Number of stored spans",
		}),
		dropped: prometheus.NewCounter(prometheus.CounterOpts{
			Name: "tracer_dropped_spans_total",
			Help: "Number of dropped spans",
		}),
	}
	err = prometheus.Register(g.dropped)
	if err != nil {
		g.logger.Printf("couldn't register prometheus counter: %s", err)
	}
	err = prometheus.Register(g.stored)
	if err != nil {
		g.logger.Printf("couldn't register prometheus counter: %s", err)
	}
	go g.loop()
	return g, nil
}

func (g *GRPC) loop() {
	t := time.NewTicker(g.flushInterval)
	for {
		select {
		case sp := <-g.ch:
			g.queue = append(g.queue, sp)
			if len(g.queue) == cap(g.queue) {
				if err := g.flush(); err != nil {
					g.logger.Printf("couldn't flush spans: %s", err)
				}
			}
		case <-t.C:
			if err := g.flush(); err != nil {
				g.logger.Printf("couldn't flush spans: %s", err)
			}
		}
	}
}

func (g *GRPC) flush() error {
	var pbs []*pb.Span
	for _, sp := range g.queue {
		pst, err := ptypes.TimestampProto(sp.StartTime)
		if err != nil {
			g.logger.Printf("dropping span because of error: %s", err)
			continue
		}
		pft, err := ptypes.TimestampProto(sp.FinishTime)
		if err != nil {
			g.logger.Printf("dropping span because of error: %s", err)
			continue
		}
		var tags []*pb.Tag
		for k, v := range sp.Tags {
			vs := fmt.Sprintf("%v", v) // XXX
			tags = append(tags, &pb.Tag{
				Key:   k,
				Value: vs,
			})
		}
		for _, l := range sp.Logs {
			t, err := ptypes.TimestampProto(l.Timestamp)
			if err != nil {
				g.logger.Printf("dropping log entry because of error: %s", err)
				continue
			}
			ps := fmt.Sprintf("%v", l.Payload) // XXX
			tags = append(tags, &pb.Tag{
				Key:   l.Event,
				Value: ps,
				Time:  t,
			})
		}
		psp := &pb.Span{
			SpanId:        sp.SpanID,
			ParentId:      sp.ParentID,
			TraceId:       sp.TraceID,
			ServiceName:   sp.ServiceName,
			OperationName: sp.OperationName,
			StartTime:     pst,
			FinishTime:    pft,
			Flags:         sp.Flags,
			Tags:          tags,
		}
		pbs = append(pbs, psp)
	}
	g.queue = g.queue[0:0]
	if _, err := g.client.Store(context.Background(), &pb.StoreRequest{Spans: pbs}); err != nil {
		return err
	}
	return nil
}

// Store implements the tracer.Storer interface.
func (g *GRPC) Store(sp RawSpan) error {
	select {
	case g.ch <- sp:
		g.stored.Inc()
	default:
		g.dropped.Inc()
	}
	return nil
}
<commit_msg>Correctly set logger<commit_after>package tracer

import (
	"fmt"
	"time"

	"github.com/tracer/tracer/pb"

	"github.com/golang/protobuf/ptypes"
	"github.com/prometheus/client_golang/prometheus"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
)

// GRPC is a gRPC-based transport for sending spans to a server.
type GRPC struct {
	client        pb.StorerClient
	queue         []RawSpan
	ch            chan RawSpan
	flushInterval time.Duration
	logger        Logger

	stored  prometheus.Counter
	dropped prometheus.Counter
}

// GRPCOptions are options for the GRPC storer.
type GRPCOptions struct {
	// How many spans to queue before sending them to the server.
	// Additionally, a buffer the size of 2*QueueSize will be used to
	// process new spans. If this buffer runs full, new spans will be
	// dropped.
	QueueSize int
	// How often to flush spans, even if the queue isn't full yet.
	FlushInterval time.Duration
	// Where to log errors. If nil, the default logger will be used.
	Logger Logger
}

// NewGRPC returns a new Storer that sends spans via gRPC to a server.
func NewGRPC(address string, grpcOpts *GRPCOptions, opts ...grpc.DialOption) (Storer, error) {
	if grpcOpts == nil {
		grpcOpts = &GRPCOptions{
			QueueSize:     1024,
			FlushInterval: 1 * time.Second,
		}
	}
	if grpcOpts.Logger == nil {
		grpcOpts.Logger = defaultLogger{}
	}
	conn, err := grpc.Dial(address, opts...)
	if err != nil {
		return nil, err
	}
	client := pb.NewStorerClient(conn)
	g := &GRPC{
		client:        client,
		queue:         make([]RawSpan, 0, grpcOpts.QueueSize),
		ch:            make(chan RawSpan, grpcOpts.QueueSize*2),
		flushInterval: grpcOpts.FlushInterval,
		logger:        grpcOpts.Logger,

		stored: prometheus.NewCounter(prometheus.CounterOpts{
			Name: "tracer_stored_spans_total",
			Help: "Number of stored spans",
		}),
		dropped: prometheus.NewCounter(prometheus.CounterOpts{
			Name: "tracer_dropped_spans_total",
			Help: "Number of dropped spans",
		}),
	}
	err = prometheus.Register(g.dropped)
	if err != nil {
		g.logger.Printf("couldn't register prometheus counter: %s", err)
	}
	err = prometheus.Register(g.stored)
	if err != nil {
		g.logger.Printf("couldn't register prometheus counter: %s", err)
	}
	go g.loop()
	return g, nil
}

func (g *GRPC) loop() {
	t := time.NewTicker(g.flushInterval)
	for {
		select {
		case sp := <-g.ch:
			g.queue = append(g.queue, sp)
			if len(g.queue) == cap(g.queue) {
				if err := g.flush(); err != nil {
					g.logger.Printf("couldn't flush spans: %s", err)
				}
			}
		case <-t.C:
			if err := g.flush(); err != nil {
				g.logger.Printf("couldn't flush spans: %s", err)
			}
		}
	}
}

func (g *GRPC) flush() error {
	var pbs []*pb.Span
	for _, sp := range g.queue {
		pst, err := ptypes.TimestampProto(sp.StartTime)
		if err != nil {
			g.logger.Printf("dropping span because of error: %s", err)
			continue
		}
		pft, err := ptypes.TimestampProto(sp.FinishTime)
		if err != nil {
			g.logger.Printf("dropping span because of error: %s", err)
			continue
		}
		var tags []*pb.Tag
		for k, v := range sp.Tags {
			vs := fmt.Sprintf("%v", v) // XXX
			tags = append(tags, &pb.Tag{
				Key:   k,
				Value: vs,
			})
		}
		for _, l := range sp.Logs {
			t, err := ptypes.TimestampProto(l.Timestamp)
			if err != nil {
				g.logger.Printf("dropping log entry because of error: %s", err)
				continue
			}
			ps := fmt.Sprintf("%v", l.Payload) // XXX
			tags = append(tags, &pb.Tag{
				Key:   l.Event,
				Value: ps,
				Time:  t,
			})
		}
		psp := &pb.Span{
			SpanId:        sp.SpanID,
			ParentId:      sp.ParentID,
			TraceId:       sp.TraceID,
			ServiceName:   sp.ServiceName,
			OperationName: sp.OperationName,
			StartTime:     pst,
			FinishTime:    pft,
			Flags:         sp.Flags,
			Tags:          tags,
		}
		pbs = append(pbs, psp)
	}
	g.queue = g.queue[0:0]
	if _, err := g.client.Store(context.Background(), &pb.StoreRequest{Spans: pbs}); err != nil {
		return err
	}
	return nil
}

// Store implements the tracer.Storer interface.
func (g *GRPC) Store(sp RawSpan) error {
	select {
	case g.ch <- sp:
		g.stored.Inc()
	default:
		g.dropped.Inc()
	}
	return nil
}
<|endoftext|>


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

package awsvpc

import (
	"encoding/json"
	"fmt"
	"net"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/aws/ec2metadata"
	"github.com/aws/aws-sdk-go/service/ec2"
	log "github.com/golang/glog"
	"golang.org/x/net/context"

	"github.com/coreos/flannel/backend"
	"github.com/coreos/flannel/pkg/ip"
	"github.com/coreos/flannel/subnet"
)

func init() {
	backend.Register("aws-vpc", New)
}

type AwsVpcBackend struct {
	sm       subnet.Manager
	extIface *backend.ExternalInterface
}

func New(sm subnet.Manager, extIface *backend.ExternalInterface) (backend.Backend, error) {
	be := AwsVpcBackend{
		sm:       sm,
		extIface: extIface,
	}
	return &be, nil
}

func (be *AwsVpcBackend) Run(ctx context.Context) {
	<-ctx.Done()
}

func (be *AwsVpcBackend) RegisterNetwork(ctx context.Context, network string, config *subnet.Config) (backend.Network, error) {
	// Parse our configuration
	cfg := struct {
		RouteTableID string
	}{}

	if len(config.Backend) > 0 {
		if err := json.Unmarshal(config.Backend, &cfg); err != nil {
			return nil, fmt.Errorf("error decoding VPC backend config: %v", err)
		}
	}

	// Acquire the lease form subnet manager
	attrs := subnet.LeaseAttrs{
		PublicIP: ip.FromIP(be.extIface.ExtAddr),
	}

	l, err := be.sm.AcquireLease(ctx, network, &attrs)
	switch err {
	case nil:

	case context.Canceled, context.DeadlineExceeded:
		return nil, err

	default:
		return nil, fmt.Errorf("failed to acquire lease: %v", err)
	}

	// Figure out this machine's EC2 instance ID and region
	metadataClient := ec2metadata.New(nil)
	region, err := metadataClient.Region()
	if err != nil {
		return nil, fmt.Errorf("error getting EC2 region name: %v", err)
	}
	instanceID, err := metadataClient.GetMetadata("instance-id")
	if err != nil {
		return nil, fmt.Errorf("error getting EC2 instance ID: %v", err)
	}

	ec2c := ec2.New(&aws.Config{Region: aws.String(region)})

	if _, err = be.disableSrcDestCheck(instanceID, ec2c); err != nil {
		log.Infof("Warning- disabling source destination check failed: %v", err)
	}

	if cfg.RouteTableID == "" {
		log.Infof("RouteTableID not passed as config parameter, detecting ...")
		if cfg.RouteTableID, err = be.detectRouteTableID(instanceID, ec2c); err != nil {
			return nil, err
		}
	}

	log.Info("RouteRouteTableID: ", cfg.RouteTableID)
	networkConfig, err := be.sm.GetNetworkConfig(ctx, network)

	err = be.cleanupInvalidRoutes(cfg.RouteTableID, networkConfig.Network, ec2c)
	if err != nil {
		log.Errorf("Error cleaning up route table: %v", err)
	}

	matchingRouteFound, err := be.checkMatchingRoutes(cfg.RouteTableID, instanceID, l.Subnet.String(), ec2c)
	if err != nil {
		log.Errorf("Error describing route tables: %v", err)

		if ec2Err, ok := err.(awserr.Error); ok {
			if ec2Err.Code() == "UnauthorizedOperation" {
				log.Errorf("Note: DescribeRouteTables permission cannot be bound to any resource")
			}
		}
	}

	if !matchingRouteFound {
		cidrBlock := l.Subnet.String()
		deleteRouteInput := &ec2.DeleteRouteInput{RouteTableId: &cfg.RouteTableID, DestinationCidrBlock: &cidrBlock}
		if _, err := ec2c.DeleteRoute(deleteRouteInput); err != nil {
			if ec2err, ok := err.(awserr.Error); !ok || ec2err.Code() != "InvalidRoute.NotFound" {
				// an error other than the route not already existing occurred
				return nil, fmt.Errorf("error deleting existing route for %s: %v", l.Subnet.String(), err)
			}
		}

		// Add the route for this machine's subnet
		if _, err := be.createRoute(cfg.RouteTableID, instanceID, l.Subnet.String(), ec2c); err != nil {
			return nil, fmt.Errorf("unable to add route %s: %v", l.Subnet.String(), err)
		}
	}

	return &backend.SimpleNetwork{
		SubnetLease: l,
		ExtIface:    be.extIface,
	}, nil
}

func (be *AwsVpcBackend) cleanupInvalidRoutes(routeTableID string, network ip.IP4Net, ec2c *ec2.EC2) error {
	filter := newFilter()
	filter.Add("route.state", "blackhole")

	input := ec2.DescribeRouteTablesInput{Filters: filter, RouteTableIds: []*string{&routeTableID}}
	resp, err := ec2c.DescribeRouteTables(&input)
	if err != nil {
		return err
	}

	for _, routeTable := range resp.RouteTables {
		for _, route := range routeTable.Routes {
			if *route.State == "blackhole" && route.DestinationCidrBlock != nil {
				_, subnet, err := net.ParseCIDR(*route.DestinationCidrBlock)
				if err == nil && network.Contains(ip.FromIP(subnet.IP)) {
					log.Info("Removing route: ", *route.DestinationCidrBlock)
					deleteRouteInput := &ec2.DeleteRouteInput{RouteTableId: &routeTableID, DestinationCidrBlock: route.DestinationCidrBlock}
					if _, err := ec2c.DeleteRoute(deleteRouteInput); err != nil {
						if ec2err, ok := err.(awserr.Error); !ok || ec2err.Code() != "InvalidRoute.NotFound" {
							// an error other than the route not already existing occurred
							return err
						}
					}
				}
			}
		}
	}

	return nil
}

func (be *AwsVpcBackend) checkMatchingRoutes(routeTableID, instanceID, subnet string, ec2c *ec2.EC2) (bool, error) {
	matchingRouteFound := false

	filter := newFilter()
	filter.Add("route.destination-cidr-block", subnet)
	filter.Add("route.state", "active")

	input := ec2.DescribeRouteTablesInput{Filters: filter, RouteTableIds: []*string{&routeTableID}}

	resp, err := ec2c.DescribeRouteTables(&input)
	if err != nil {
		return matchingRouteFound, err
	}

	for _, routeTable := range resp.RouteTables {
		for _, route := range routeTable.Routes {
			if route.DestinationCidrBlock != nil && subnet == *route.DestinationCidrBlock && *route.State == "active" {

				if *route.InstanceId == instanceID {
					matchingRouteFound = true
					break
				}

				log.Errorf("Deleting invalid *active* matching route: %s, %s \n", *route.DestinationCidrBlock, *route.InstanceId)
			}
		}
	}

	return matchingRouteFound, nil
}

func (be *AwsVpcBackend) createRoute(routeTableID, instanceID, subnet string, ec2c *ec2.EC2) (*ec2.CreateRouteOutput, error) {
	route := &ec2.CreateRouteInput{
		RouteTableId:         &routeTableID,
		InstanceId:           &instanceID,
		DestinationCidrBlock: &subnet,
	}

	return ec2c.CreateRoute(route)
}

func (be *AwsVpcBackend) disableSrcDestCheck(instanceID string, ec2c *ec2.EC2) (*ec2.ModifyInstanceAttributeOutput, error) {
	modifyAttributes := &ec2.ModifyInstanceAttributeInput{
		InstanceId:      aws.String(instanceID),
		SourceDestCheck: &ec2.AttributeBooleanValue{Value: aws.Bool(false)},
	}

	return ec2c.ModifyInstanceAttribute(modifyAttributes)
}

func (be *AwsVpcBackend) detectRouteTableID(instanceID string, ec2c *ec2.EC2) (string, error) {
	instancesInput := &ec2.DescribeInstancesInput{
		InstanceIds: []*string{&instanceID},
	}

	resp, err := ec2c.DescribeInstances(instancesInput)
	if err != nil {
		return "", fmt.Errorf("error getting instance info: %v", err)
	}

	if len(resp.Reservations) == 0 {
		return "", fmt.Errorf("no reservations found")
	}

	if len(resp.Reservations[0].Instances) == 0 {
		return "", fmt.Errorf("no matching instance found with id: %v", instanceID)
	}

	subnetID := resp.Reservations[0].Instances[0].SubnetId
	vpcID := resp.Reservations[0].Instances[0].VpcId

	log.Info("Subnet-ID: ", *subnetID)
	log.Info("VPC-ID: ", *vpcID)

	filter := newFilter()
	filter.Add("association.subnet-id", *subnetID)

	routeTablesInput := &ec2.DescribeRouteTablesInput{
		Filters: filter,
	}

	res, err := ec2c.DescribeRouteTables(routeTablesInput)
	if err != nil {
		return "", fmt.Errorf("error describing routeTables for subnetID %s: %v", *subnetID, err)
	}

	if len(res.RouteTables) != 0 {
		return *res.RouteTables[0].RouteTableId, nil
	}

	filter = newFilter()
	filter.Add("association.main", "true")
	filter.Add("vpc-id", *vpcID)

	routeTablesInput = &ec2.DescribeRouteTablesInput{
		Filters: filter,
	}

	res, err = ec2c.DescribeRouteTables(routeTablesInput)
	if err != nil {
		log.Info("error describing route tables: ", err)
	}

	if len(res.RouteTables) == 0 {
		return "", fmt.Errorf("main route table not found")
	}

	return *res.RouteTables[0].RouteTableId, nil
}
<commit_msg>backend: fixes and cleanups in awsvpc backend<commit_after>// Copyright 2015 flannel authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package awsvpc

import (
	"encoding/json"
	"fmt"
	"net"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/aws/ec2metadata"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/ec2"
	log "github.com/golang/glog"
	"golang.org/x/net/context"

	"github.com/coreos/flannel/backend"
	"github.com/coreos/flannel/pkg/ip"
	"github.com/coreos/flannel/subnet"
)

func init() {
	backend.Register("aws-vpc", New)
}

type AwsVpcBackend struct {
	sm       subnet.Manager
	extIface *backend.ExternalInterface
}

func New(sm subnet.Manager, extIface *backend.ExternalInterface) (backend.Backend, error) {
	be := AwsVpcBackend{
		sm:       sm,
		extIface: extIface,
	}
	return &be, nil
}

func (be *AwsVpcBackend) Run(ctx context.Context) {
	<-ctx.Done()
}

func (be *AwsVpcBackend) RegisterNetwork(ctx context.Context, network string, config *subnet.Config) (backend.Network, error) {
	// Parse our configuration
	cfg := struct {
		RouteTableID string
	}{}

	if len(config.Backend) > 0 {
		if err := json.Unmarshal(config.Backend, &cfg); err != nil {
			return nil, fmt.Errorf("error decoding VPC backend config: %v", err)
		}
	}

	// Acquire the lease form subnet manager
	attrs := subnet.LeaseAttrs{
		PublicIP: ip.FromIP(be.extIface.ExtAddr),
	}

	l, err := be.sm.AcquireLease(ctx, network, &attrs)
	switch err {
	case nil:

	case context.Canceled, context.DeadlineExceeded:
		return nil, err

	default:
		return nil, fmt.Errorf("failed to acquire lease: %v", err)
	}

	sess, _ := session.NewSession(aws.NewConfig().WithMaxRetries(5))

	// Figure out this machine's EC2 instance ID and region
	metadataClient := ec2metadata.New(sess)
	region, err := metadataClient.Region()
	if err != nil {
		return nil, fmt.Errorf("error getting EC2 region name: %v", err)
	}
	sess.Config.Region = aws.String(region)
	instanceID, err := metadataClient.GetMetadata("instance-id")
	if err != nil {
		return nil, fmt.Errorf("error getting EC2 instance ID: %v", err)
	}

	ec2c := ec2.New(sess)

	// Find ENI which contains the external network interface IP address
	eni, err := be.findENI(instanceID, ec2c)
	if err != nil || eni == nil {
		return nil, fmt.Errorf("unable to find ENI that matches the %s IP address. %s\n", be.extIface.IfaceAddr, err)
	}

	// Try to disable SourceDestCheck on the main network interface
	if err := be.disableSrcDestCheck(eni.NetworkInterfaceId, ec2c); err != nil {
		log.Warningf("failed to disable SourceDestCheck on %s: %s.\n", *eni.NetworkInterfaceId, err)
	}

	if cfg.RouteTableID == "" {
		if cfg.RouteTableID, err = be.detectRouteTableID(eni, ec2c); err != nil {
			return nil, err
		}
		log.Infof("Found route table %s.\n", cfg.RouteTableID)
	}

	networkConfig, err := be.sm.GetNetworkConfig(ctx, network)

	err = be.cleanupBlackholeRoutes(cfg.RouteTableID, networkConfig.Network, ec2c)
	if err != nil {
		log.Errorf("Error cleaning up blackhole routes: %v", err)
	}

	matchingRouteFound, err := be.checkMatchingRoutes(cfg.RouteTableID, l.Subnet.String(), eni.NetworkInterfaceId, ec2c)
	if err != nil {
		log.Errorf("Error describing route tables: %v", err)
	}

	if !matchingRouteFound {
		cidrBlock := l.Subnet.String()
		deleteRouteInput := &ec2.DeleteRouteInput{RouteTableId: &cfg.RouteTableID, DestinationCidrBlock: &cidrBlock}
		if _, err := ec2c.DeleteRoute(deleteRouteInput); err != nil {
			if ec2err, ok := err.(awserr.Error); !ok || ec2err.Code() != "InvalidRoute.NotFound" {
				// an error other than the route not already existing occurred
				return nil, fmt.Errorf("error deleting existing route for %s: %v", l.Subnet.String(), err)
			}
		}

		// Add the route for this machine's subnet
		if err := be.createRoute(cfg.RouteTableID, l.Subnet.String(), eni.NetworkInterfaceId, ec2c); err != nil {
			return nil, fmt.Errorf("unable to add route %s: %v", l.Subnet.String(), err)
		}
	}

	return &backend.SimpleNetwork{
		SubnetLease: l,
		ExtIface:    be.extIface,
	}, nil
}

func (be *AwsVpcBackend) cleanupBlackholeRoutes(routeTableID string, network ip.IP4Net, ec2c *ec2.EC2) error {
	filter := newFilter()
	filter.Add("route.state", "blackhole")

	input := ec2.DescribeRouteTablesInput{Filters: filter, RouteTableIds: []*string{&routeTableID}}
	resp, err := ec2c.DescribeRouteTables(&input)
	if err != nil {
		return err
	}

	for _, routeTable := range resp.RouteTables {
		for _, route := range routeTable.Routes {
			if *route.State == "blackhole" && route.DestinationCidrBlock != nil {
				_, subnet, err := net.ParseCIDR(*route.DestinationCidrBlock)
				if err == nil && network.Contains(ip.FromIP(subnet.IP)) {
					log.Info("Removing blackhole route: ", *route.DestinationCidrBlock)
					deleteRouteInput := &ec2.DeleteRouteInput{RouteTableId: &routeTableID, DestinationCidrBlock: route.DestinationCidrBlock}
					if _, err := ec2c.DeleteRoute(deleteRouteInput); err != nil {
						if ec2err, ok := err.(awserr.Error); !ok || ec2err.Code() != "InvalidRoute.NotFound" {
							// an error other than the route not already existing occurred
							return err
						}
					}
				}
			}
		}
	}

	return nil
}

func (be *AwsVpcBackend) checkMatchingRoutes(routeTableID, subnet string, eniID *string, ec2c *ec2.EC2) (bool, error) {
	matchingRouteFound := false

	filter := newFilter()
	filter.Add("route.destination-cidr-block", subnet)
	filter.Add("route.state", "active")

	input := ec2.DescribeRouteTablesInput{Filters: filter, RouteTableIds: []*string{&routeTableID}}

	resp, err := ec2c.DescribeRouteTables(&input)
	if err != nil {
		return matchingRouteFound, err
	}

	for _, routeTable := range resp.RouteTables {
		for _, route := range routeTable.Routes {
			if route.DestinationCidrBlock != nil && subnet == *route.DestinationCidrBlock &&
				*route.State == "active" && route.NetworkInterfaceId == eniID {
				matchingRouteFound = true
				break
			}
		}
	}

	return matchingRouteFound, nil
}

func (be *AwsVpcBackend) createRoute(routeTableID, subnet string, eniID *string, ec2c *ec2.EC2) error {
	route := &ec2.CreateRouteInput{
		RouteTableId:         &routeTableID,
		NetworkInterfaceId:   eniID,
		DestinationCidrBlock: &subnet,
	}

	if _, err := ec2c.CreateRoute(route); err != nil {
		return err
	}
	log.Infof("Route added %s - %s.\n", subnet, *eniID)
	return nil
}

func (be *AwsVpcBackend) disableSrcDestCheck(eniID *string, ec2c *ec2.EC2) error {
	attr := &ec2.ModifyNetworkInterfaceAttributeInput{
		NetworkInterfaceId: eniID,
		SourceDestCheck:    &ec2.AttributeBooleanValue{Value: aws.Bool(false)},
	}
	_, err := ec2c.ModifyNetworkInterfaceAttribute(attr)
	return err
}

// detectRouteTableID detect the routing table that is associated with the ENI,
// subnet can be implicitly associated with the main routing table
func (be *AwsVpcBackend) detectRouteTableID(eni *ec2.InstanceNetworkInterface, ec2c *ec2.EC2) (string, error) {
	subnetID := eni.SubnetId
	vpcID := eni.VpcId

	filter := newFilter()
	filter.Add("association.subnet-id", *subnetID)

	routeTablesInput := &ec2.DescribeRouteTablesInput{
		Filters: filter,
	}

	res, err := ec2c.DescribeRouteTables(routeTablesInput)
	if err != nil {
		return "", fmt.Errorf("error describing routeTables for subnetID %s: %v", *subnetID, err)
	}

	if len(res.RouteTables) != 0 {
		return *res.RouteTables[0].RouteTableId, nil
	}

	filter = newFilter()
	filter.Add("association.main", "true")
	filter.Add("vpc-id", *vpcID)

	routeTablesInput = &ec2.DescribeRouteTablesInput{
		Filters: filter,
	}

	res, err = ec2c.DescribeRouteTables(routeTablesInput)
	if err != nil {
		log.Info("error describing route tables: ", err)
	}

	if len(res.RouteTables) == 0 {
		return "", fmt.Errorf("main route table not found")
	}

	return *res.RouteTables[0].RouteTableId, nil
}

func (be *AwsVpcBackend) findENI(instanceID string, ec2c *ec2.EC2) (*ec2.InstanceNetworkInterface, error) {
	instance, err := ec2c.DescribeInstances(&ec2.DescribeInstancesInput{
		InstanceIds: []*string{aws.String(instanceID)}},
	)
	if err != nil {
		return nil, err
	}

	for _, n := range instance.Reservations[0].Instances[0].NetworkInterfaces {
		for _, a := range n.PrivateIpAddresses {
			if *a.PrivateIpAddress == be.extIface.IfaceAddr.String() {
				log.Infof("Found %s that has %s IP address.\n", *n.NetworkInterfaceId, be.extIface.IfaceAddr)
				return n, nil
			}
		}
	}
	return nil, err
}
<|endoftext|>


<commit_before>package parser

import (
	"crypto/md5"
	"encoding/hex"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strconv"
	"strings"

	"github.com/asdine/storm"
	"github.com/hacdias/filemanager"
	"github.com/hacdias/filemanager/bolt"
	"github.com/hacdias/filemanager/staticgen"
	"github.com/hacdias/fileutils"
	"github.com/mholt/caddy"
	"github.com/mholt/caddy/caddyhttp/httpserver"
	"github.com/spf13/viper"
)

// Parse ...
func Parse(c *caddy.Controller, plugin string) ([]*filemanager.FileManager, error) {
	var (
		configs []*filemanager.FileManager
		err     error
	)

	for c.Next() {
		u := &filemanager.User{
			Locale:        "en",
			AllowCommands: true,
			AllowEdit:     true,
			AllowNew:      true,
			AllowPublish:  true,
			Commands:      []string{"git", "svn", "hg"},
			CSS:           "",
			Rules: []*filemanager.Rule{{
				Regex:  true,
				Allow:  false,
				Regexp: &filemanager.Regexp{Raw: "\\/\\..+"},
			}},
		}

		baseURL := "/"
		scope := "."
		database := ""
		noAuth := false

		if plugin != "" {
			baseURL = "/admin"
		}

		// Get the baseURL and scope
		args := c.RemainingArgs()

		if plugin == "" {
			if len(args) >= 1 {
				baseURL = args[0]
			}

			if len(args) > 1 {
				scope = args[1]
			}
		} else {
			if len(args) >= 1 {
				scope = args[0]
			}

			if len(args) > 1 {
				baseURL = args[1]
			}
		}

		for c.NextBlock() {
			switch c.Val() {
			case "database":
				if !c.NextArg() {
					return nil, c.ArgErr()
				}

				database = c.Val()
			case "locale":
				if !c.NextArg() {
					return nil, c.ArgErr()
				}

				u.Locale = c.Val()
			case "allow_commands":
				if !c.NextArg() {
					u.AllowCommands = true
					continue
				}

				u.AllowCommands, err = strconv.ParseBool(c.Val())
				if err != nil {
					return nil, err
				}
			case "allow_edit":
				if !c.NextArg() {
					u.AllowEdit = true
					continue
				}

				u.AllowEdit, err = strconv.ParseBool(c.Val())
				if err != nil {
					return nil, err
				}
			case "allow_new":
				if !c.NextArg() {
					u.AllowNew = true
					continue
				}

				u.AllowNew, err = strconv.ParseBool(c.Val())
				if err != nil {
					return nil, err
				}
			case "allow_publish":
				if !c.NextArg() {
					u.AllowPublish = true
					continue
				}

				u.AllowPublish, err = strconv.ParseBool(c.Val())
				if err != nil {
					return nil, err
				}
			case "commands":
				if !c.NextArg() {
					return nil, c.ArgErr()
				}

				u.Commands = strings.Split(c.Val(), " ")
			case "css":
				if !c.NextArg() {
					return nil, c.ArgErr()
				}

				file := c.Val()
				css, err := ioutil.ReadFile(file)
				if err != nil {
					return nil, err
				}

				u.CSS = string(css)
			case "no_auth":
				if !c.NextArg() {
					noAuth = true
					continue
				}

				noAuth, err = strconv.ParseBool(c.Val())
				if err != nil {
					return nil, err
				}
			}
		}

		caddyConf := httpserver.GetConfig(c)

		path := filepath.Join(caddy.AssetsPath(), "filemanager")
		err := os.MkdirAll(path, 0700)
		if err != nil {
			return nil, err
		}

		// if there is a database path and it is not absolute,
		// it will be relative to Caddy folder.
		if !filepath.IsAbs(database) && database != "" {
			database = filepath.Join(path, database)
		}

		// If there is no database path on the settings,
		// store one in .caddy/filemanager/name.db.
		if database == "" {
			// The name of the database is the hashed value of a string composed
			// by the host, address path and the baseurl of this File Manager
			// instance.
			hasher := md5.New()
			hasher.Write([]byte(caddyConf.Addr.Host + caddyConf.Addr.Path + baseURL))
			sha := hex.EncodeToString(hasher.Sum(nil))
			database = filepath.Join(path, sha+".db")

			fmt.Println("[WARNING] A database is going to be created for your File Manager instace at " + database +
				". It is highly recommended that you set the 'database' option to '" + sha + ".db'\n")
		}

		u.Scope = scope
		u.FileSystem = fileutils.Dir(scope)

		db, err := storm.Open(database)
		if err != nil {
			return nil, err
		}

		m := &filemanager.FileManager{
			NoAuth:      viper.GetBool("NoAuth"),
			BaseURL:     "",
			PrefixURL:   "",
			DefaultUser: u,
			Store: &filemanager.Store{
				Config: bolt.ConfigStore{DB: db},
				Users:  bolt.UsersStore{DB: db},
				Share:  bolt.ShareStore{DB: db},
			},
			NewFS: func(scope string) filemanager.FileSystem {
				return fileutils.Dir(scope)
			},
		}

		err = m.Setup()
		if err != nil {
			return nil, err
		}

		switch plugin {
		case "hugo":
			// Initialize the default settings for Hugo.
			hugo := &staticgen.Hugo{
				Root:        scope,
				Public:      filepath.Join(scope, "public"),
				Args:        []string{},
				CleanPublic: true,
			}

			// Attaches Hugo plugin to this file manager instance.
			err = m.Attach(hugo)
			if err != nil {
				return nil, err
			}
		case "jekyll":
			// Initialize the default settings for Jekyll.
			jekyll := &staticgen.Jekyll{
				Root:        scope,
				Public:      filepath.Join(scope, "_site"),
				Args:        []string{},
				CleanPublic: true,
			}

			// Attaches Hugo plugin to this file manager instance.
			err = m.Attach(jekyll)
			if err != nil {
				return nil, err
			}
		}

		if err != nil {
			return nil, err
		}

		m.NoAuth = noAuth
		m.SetBaseURL(baseURL)
		m.SetPrefixURL(strings.TrimSuffix(caddyConf.Addr.Path, "/"))

		configs = append(configs, m)
	}

	return configs, nil
}
<commit_msg>Close #207<commit_after>package parser

import (
	"crypto/md5"
	"encoding/hex"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strconv"
	"strings"

	"github.com/asdine/storm"
	"github.com/hacdias/filemanager"
	"github.com/hacdias/filemanager/bolt"
	"github.com/hacdias/filemanager/staticgen"
	"github.com/hacdias/fileutils"
	"github.com/mholt/caddy"
	"github.com/mholt/caddy/caddyhttp/httpserver"
	"github.com/spf13/viper"
)

var databases = map[string]*storm.DB{}

// Parse ...
func Parse(c *caddy.Controller, plugin string) ([]*filemanager.FileManager, error) {
	var (
		configs []*filemanager.FileManager
		err     error
	)

	for c.Next() {
		u := &filemanager.User{
			Locale:        "en",
			AllowCommands: true,
			AllowEdit:     true,
			AllowNew:      true,
			AllowPublish:  true,
			Commands:      []string{"git", "svn", "hg"},
			CSS:           "",
			Rules: []*filemanager.Rule{{
				Regex:  true,
				Allow:  false,
				Regexp: &filemanager.Regexp{Raw: "\\/\\..+"},
			}},
		}

		baseURL := "/"
		scope := "."
		database := ""
		noAuth := false

		if plugin != "" {
			baseURL = "/admin"
		}

		// Get the baseURL and scope
		args := c.RemainingArgs()

		if plugin == "" {
			if len(args) >= 1 {
				baseURL = args[0]
			}

			if len(args) > 1 {
				scope = args[1]
			}
		} else {
			if len(args) >= 1 {
				scope = args[0]
			}

			if len(args) > 1 {
				baseURL = args[1]
			}
		}

		for c.NextBlock() {
			switch c.Val() {
			case "database":
				if !c.NextArg() {
					return nil, c.ArgErr()
				}

				database = c.Val()
			case "locale":
				if !c.NextArg() {
					return nil, c.ArgErr()
				}

				u.Locale = c.Val()
			case "allow_commands":
				if !c.NextArg() {
					u.AllowCommands = true
					continue
				}

				u.AllowCommands, err = strconv.ParseBool(c.Val())
				if err != nil {
					return nil, err
				}
			case "allow_edit":
				if !c.NextArg() {
					u.AllowEdit = true
					continue
				}

				u.AllowEdit, err = strconv.ParseBool(c.Val())
				if err != nil {
					return nil, err
				}
			case "allow_new":
				if !c.NextArg() {
					u.AllowNew = true
					continue
				}

				u.AllowNew, err = strconv.ParseBool(c.Val())
				if err != nil {
					return nil, err
				}
			case "allow_publish":
				if !c.NextArg() {
					u.AllowPublish = true
					continue
				}

				u.AllowPublish, err = strconv.ParseBool(c.Val())
				if err != nil {
					return nil, err
				}
			case "commands":
				if !c.NextArg() {
					return nil, c.ArgErr()
				}

				u.Commands = strings.Split(c.Val(), " ")
			case "css":
				if !c.NextArg() {
					return nil, c.ArgErr()
				}

				file := c.Val()
				css, err := ioutil.ReadFile(file)
				if err != nil {
					return nil, err
				}

				u.CSS = string(css)
			case "no_auth":
				if !c.NextArg() {
					noAuth = true
					continue
				}

				noAuth, err = strconv.ParseBool(c.Val())
				if err != nil {
					return nil, err
				}
			}
		}

		caddyConf := httpserver.GetConfig(c)

		path := filepath.Join(caddy.AssetsPath(), "filemanager")
		err := os.MkdirAll(path, 0700)
		if err != nil {
			return nil, err
		}

		// if there is a database path and it is not absolute,
		// it will be relative to Caddy folder.
		if !filepath.IsAbs(database) && database != "" {
			database = filepath.Join(path, database)
		}

		// If there is no database path on the settings,
		// store one in .caddy/filemanager/name.db.
		if database == "" {
			// The name of the database is the hashed value of a string composed
			// by the host, address path and the baseurl of this File Manager
			// instance.
			hasher := md5.New()
			hasher.Write([]byte(caddyConf.Addr.Host + caddyConf.Addr.Path + baseURL))
			sha := hex.EncodeToString(hasher.Sum(nil))
			database = filepath.Join(path, sha+".db")

			fmt.Println("[WARNING] A database is going to be created for your File Manager instace at " + database +
				". It is highly recommended that you set the 'database' option to '" + sha + ".db'\n")
		}

		u.Scope = scope
		u.FileSystem = fileutils.Dir(scope)

		var db *storm.DB
		if stored, ok := databases[database]; ok {
			db = stored
		} else {
			db, err = storm.Open(database)
			databases[database] = db
		}

		if err != nil {
			return nil, err
		}

		m := &filemanager.FileManager{
			NoAuth:      viper.GetBool("NoAuth"),
			BaseURL:     "",
			PrefixURL:   "",
			DefaultUser: u,
			Store: &filemanager.Store{
				Config: bolt.ConfigStore{DB: db},
				Users:  bolt.UsersStore{DB: db},
				Share:  bolt.ShareStore{DB: db},
			},
			NewFS: func(scope string) filemanager.FileSystem {
				return fileutils.Dir(scope)
			},
		}

		err = m.Setup()
		if err != nil {
			return nil, err
		}

		switch plugin {
		case "hugo":
			// Initialize the default settings for Hugo.
			hugo := &staticgen.Hugo{
				Root:        scope,
				Public:      filepath.Join(scope, "public"),
				Args:        []string{},
				CleanPublic: true,
			}

			// Attaches Hugo plugin to this file manager instance.
			err = m.Attach(hugo)
			if err != nil {
				return nil, err
			}
		case "jekyll":
			// Initialize the default settings for Jekyll.
			jekyll := &staticgen.Jekyll{
				Root:        scope,
				Public:      filepath.Join(scope, "_site"),
				Args:        []string{},
				CleanPublic: true,
			}

			// Attaches Hugo plugin to this file manager instance.
			err = m.Attach(jekyll)
			if err != nil {
				return nil, err
			}
		}

		if err != nil {
			return nil, err
		}

		m.NoAuth = noAuth
		m.SetBaseURL(baseURL)
		m.SetPrefixURL(strings.TrimSuffix(caddyConf.Addr.Path, "/"))

		configs = append(configs, m)
	}

	return configs, nil
}
<|endoftext|>


<commit_before>/* Callisto - Yet another Solar System simulator
 *
 * Copyright (c) 2016, Valerian Saliou <valerian@valeriansaliou.name>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *   * Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

package main

import (
  "math"

  "github.com/go-gl/gl/v4.1-core/gl"
  "github.com/go-gl/mathgl/mgl32"
)

// CameraData  Maps camera state
type CameraData struct {
  Camera         mgl32.Mat4
  CameraUniform  int32

  PositionEye    mgl32.Vec3
  PositionTarget mgl32.Vec3

  InertiaDrag    float64
  InertiaTurn    float64

  ObjectIndex    int
  ObjectMatrix   mgl32.Mat4
  ObjectRadius   float32
  ObjectList     *[]string
}

// InstanceCamera  Stores camera state
var InstanceCamera CameraData

func (camera_data *CameraData) getOrbitObjectName() (string) {
  if camera_data.ObjectIndex > 0 {
    return (*camera_data.ObjectList)[camera_data.ObjectIndex - 1]
  }

  return ""
}

func (camera_data *CameraData) getEyeX() (position float32) {
  return camera_data.PositionEye[0]
}

func (camera_data *CameraData) getEyeY() (position float32) {
  return camera_data.PositionEye[1]
}

func (camera_data *CameraData) getEyeZ() (position float32) {
  return camera_data.PositionEye[2]
}

func (camera_data *CameraData) getTargetX() (position float32) {
  return camera_data.PositionTarget[0]
}

func (camera_data *CameraData) getTargetY() (position float32) {
  return camera_data.PositionTarget[1]
}

func (camera_data *CameraData) getTargetZ() (position float32) {
  return camera_data.PositionTarget[2]
}

func (camera_data *CameraData) moveEyeX(increment float32) {
  camera_data.PositionEye[0] += increment
}

func (camera_data *CameraData) moveEyeY(increment float32) {
  camera_data.PositionEye[1] += increment
}

func (camera_data *CameraData) moveEyeZ(increment float32) {
  camera_data.PositionEye[2] += increment
}

func (camera_data *CameraData) moveTargetX(increment float32) {
  camera_data.PositionTarget[0] += increment
}

func (camera_data *CameraData) moveTargetY(increment float32) {
  camera_data.PositionTarget[1] += increment
}

func (camera_data *CameraData) moveTargetZ(increment float32) {
  camera_data.PositionTarget[2] += increment
}

func (camera_data *CameraData) setObjectIndex(object_index int) {
  camera_data.ObjectIndex = object_index
}

func (camera_data *CameraData) defaultEye() {
  camera_data.PositionEye = ConfigCameraDefaultEye
}

func (camera_data *CameraData) defaultTarget() {
  camera_data.PositionTarget = ConfigCameraDefaultTarget
}

func (camera_data *CameraData) defaultInertia() {
  camera_data.InertiaDrag = 0.0
  camera_data.InertiaTurn = 0.0
}

func getCamera() (*CameraData) {
  return &InstanceCamera
}

func createCamera(program uint32) {
  camera := getCamera()

  camera.CameraUniform = gl.GetUniformLocation(program, gl.Str("cameraUniform\x00"))

  // Default inertia (none)
  camera.defaultInertia()

  // Default camera position
  camera.defaultEye()
  camera.defaultTarget()
}

func produceInertia(inertia *float64, increment float64, celerity float64) {
  *inertia += increment * celerity

  // Cap inertia to maximum value
  if *inertia > celerity {
    *inertia = celerity
  } else if *inertia < -1.0 * celerity {
    *inertia = -1.0 * celerity
  }
}

func consumeInertia(inertia *float64) (float64) {
  if *inertia > 0 {
    *inertia += ConfigCameraInertiaConsumeForward
  } else if *inertia < 0 {
    *inertia += ConfigCameraInertiaConsumeBackward
  }

  return *inertia
}

func processEventCameraEye() {
  camera := getCamera()

  if camera.ObjectIndex == 0 {
    var (
      celerity    float64
      rotationX   float64
      rotationY   float64

      inertiaDrag float64
      inertiaTurn float64
    )

    // Free flight camera
    keyState := getEventKeyState()
    timeFactor := normalizedTimeFactor()

    // Decrease speed if diagonal move
    if keyState.MoveTurbo == true {
      celerity = ConfigCameraMoveCelerityTurbo
    } else {
      celerity = ConfigCameraMoveCelerityCruise
    }

    if (keyState.MoveUp == true || keyState.MoveDown == true) && (keyState.MoveLeft == true || keyState.MoveRight == true) {
      celerity /= math.Sqrt(2.0)
    }

    // Acquire rotation around axis
    rotationX = float64(camera.getTargetX())
    rotationY = float64(camera.getTargetY())

    // Process camera move position (keyboard)
    if keyState.MoveUp == true {
      produceInertia(&(camera.InertiaDrag), ConfigCameraInertiaProduceForward, celerity)
    }
    if keyState.MoveDown == true {
      produceInertia(&(camera.InertiaDrag), ConfigCameraInertiaProduceBackward, celerity)
    }
    if keyState.MoveLeft == true {
      produceInertia(&(camera.InertiaTurn), ConfigCameraInertiaProduceForward, celerity)
    }
    if keyState.MoveRight == true {
      produceInertia(&(camera.InertiaTurn), ConfigCameraInertiaProduceBackward, celerity)
    }

    // Apply new position with inertia
    inertiaDrag = consumeInertia(&(camera.InertiaDrag))
    inertiaTurn = consumeInertia(&(camera.InertiaTurn))

    camera.moveEyeX(timeFactor * float32(inertiaDrag * -1.0 * math.Sin(rotationY) + inertiaTurn * math.Cos(rotationY)))
    camera.moveEyeZ(timeFactor * float32(inertiaDrag * math.Cos(rotationY) + inertiaTurn * math.Sin(rotationY)))
    camera.moveEyeY(timeFactor * float32(inertiaDrag * math.Sin(rotationX)))
  } else {
    // Orbit camera
    size := normalizeObjectSize(camera.ObjectRadius)

    camera.PositionEye = mgl32.Vec3{0, 0, -1 * size * ConfigCameraOrbitMagnification}
  }

  // Translation: walk
  camera.Camera = camera.Camera.Mul4(mgl32.Translate3D(camera.getEyeX(), camera.getEyeY(), camera.getEyeZ()))
}

func processEventCameraTarget() {
  camera := getCamera()
  keyState := getEventKeyState()
  timeFactor := normalizedTimeFactor()

  camera.moveTargetX(timeFactor * keyState.WatchY * float32(math.Pi) * ConfigCameraTargetAmortizeFactor)
  camera.moveTargetY(timeFactor * keyState.WatchX * float32(math.Pi) * 2 * ConfigCameraTargetAmortizeFactor)

  // Rotation: view
  camera.Camera = camera.Camera.Mul4(mgl32.HomogRotate3D(camera.getTargetX(), mgl32.Vec3{1, 0, 0}))
  camera.Camera = camera.Camera.Mul4(mgl32.HomogRotate3D(camera.getTargetY(), mgl32.Vec3{0, 1, 0}))
  camera.Camera = camera.Camera.Mul4(mgl32.HomogRotate3D(camera.getTargetZ(), mgl32.Vec3{0, 0, 1}))
}

func updateCamera() {
  camera := getCamera()

  // Update overall camera position
  if camera.ObjectIndex == 0 {
    // Free flight
    camera.Camera = mgl32.Ident4()
  } else {
    // Orbit flight
    camera.Camera = camera.ObjectMatrix
  }

  // Orbit camera or free flight camera? (reverse rotation <> translation)
  if camera.ObjectIndex == 0 {
    // Orbit camera
    processEventCameraTarget()
    processEventCameraEye()
  } else {
    // Free flight camera
    processEventCameraEye()
    processEventCameraTarget()
  }
}

func toggleNextCameraObject() {
  camera := getCamera()

  // Go to next index
  camera.ObjectIndex++

  // Index overflow?
  if camera.ObjectIndex > len(*camera.ObjectList) {
    camera.ObjectIndex = 0
  }

  // Reset camera state
  resetCamera()
}

func resetCamera() {
  camera := getCamera()

  // Reset camera modifiers
  resetMouseCursor()

  // Reset camera itself
  camera.defaultInertia()

  camera.defaultEye()
  camera.defaultTarget()
}

func resetCameraObject() {
  getCamera().ObjectIndex = 0
}

func initializeCameraLocks(objects *[]Object) {
  // Initialize object list storage space
  object_list := make([]string, 0)

  getCamera().ObjectList = &object_list

  // Create camera locks (in object list)
  createCameraLocks(objects)
}

func createCameraLocks(objects *[]Object) {
  camera := getCamera()

  for o := range *objects {
    *camera.ObjectList = append(*camera.ObjectList, (*objects)[o].Name)

    // Create locks for child objects
    createCameraLocks(&((*objects)[o]).Objects)
  }
}

func bindCamera() {
  camera := getCamera()

  gl.UniformMatrix4fv(camera.CameraUniform, 1, false, &(camera.Camera[0]))
}
<commit_msg>Fix CI<commit_after>/* Callisto - Yet another Solar System simulator
 *
 * Copyright (c) 2016, Valerian Saliou <valerian@valeriansaliou.name>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *   * Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

package main

import (
  "math"

  "github.com/go-gl/gl/v4.1-core/gl"
  "github.com/go-gl/mathgl/mgl32"
)

// CameraData  Maps camera state
type CameraData struct {
  Camera         mgl32.Mat4
  CameraUniform  int32

  PositionEye    mgl32.Vec3
  PositionTarget mgl32.Vec3

  InertiaDrag    float64
  InertiaTurn    float64

  ObjectIndex    int
  ObjectMatrix   mgl32.Mat4
  ObjectRadius   float32
  ObjectList     *[]string
}

// InstanceCamera  Stores camera state
var InstanceCamera CameraData

func (cameraData *CameraData) getOrbitObjectName() (string) {
  if cameraData.ObjectIndex > 0 {
    return (*cameraData.ObjectList)[cameraData.ObjectIndex - 1]
  }

  return ""
}

func (cameraData *CameraData) getEyeX() (position float32) {
  return cameraData.PositionEye[0]
}

func (cameraData *CameraData) getEyeY() (position float32) {
  return cameraData.PositionEye[1]
}

func (cameraData *CameraData) getEyeZ() (position float32) {
  return cameraData.PositionEye[2]
}

func (cameraData *CameraData) getTargetX() (position float32) {
  return cameraData.PositionTarget[0]
}

func (cameraData *CameraData) getTargetY() (position float32) {
  return cameraData.PositionTarget[1]
}

func (cameraData *CameraData) getTargetZ() (position float32) {
  return cameraData.PositionTarget[2]
}

func (cameraData *CameraData) moveEyeX(increment float32) {
  cameraData.PositionEye[0] += increment
}

func (cameraData *CameraData) moveEyeY(increment float32) {
  cameraData.PositionEye[1] += increment
}

func (cameraData *CameraData) moveEyeZ(increment float32) {
  cameraData.PositionEye[2] += increment
}

func (cameraData *CameraData) moveTargetX(increment float32) {
  cameraData.PositionTarget[0] += increment
}

func (cameraData *CameraData) moveTargetY(increment float32) {
  cameraData.PositionTarget[1] += increment
}

func (cameraData *CameraData) moveTargetZ(increment float32) {
  cameraData.PositionTarget[2] += increment
}

func (cameraData *CameraData) setObjectIndex(objectIndex int) {
  cameraData.ObjectIndex = objectIndex
}

func (cameraData *CameraData) defaultEye() {
  cameraData.PositionEye = ConfigCameraDefaultEye
}

func (cameraData *CameraData) defaultTarget() {
  cameraData.PositionTarget = ConfigCameraDefaultTarget
}

func (cameraData *CameraData) defaultInertia() {
  cameraData.InertiaDrag = 0.0
  cameraData.InertiaTurn = 0.0
}

func getCamera() (*CameraData) {
  return &InstanceCamera
}

func createCamera(program uint32) {
  camera := getCamera()

  camera.CameraUniform = gl.GetUniformLocation(program, gl.Str("cameraUniform\x00"))

  // Default inertia (none)
  camera.defaultInertia()

  // Default camera position
  camera.defaultEye()
  camera.defaultTarget()
}

func produceInertia(inertia *float64, increment float64, celerity float64) {
  *inertia += increment * celerity

  // Cap inertia to maximum value
  if *inertia > celerity {
    *inertia = celerity
  } else if *inertia < -1.0 * celerity {
    *inertia = -1.0 * celerity
  }
}

func consumeInertia(inertia *float64) (float64) {
  if *inertia > 0 {
    *inertia += ConfigCameraInertiaConsumeForward
  } else if *inertia < 0 {
    *inertia += ConfigCameraInertiaConsumeBackward
  }

  return *inertia
}

func processEventCameraEye() {
  camera := getCamera()

  if camera.ObjectIndex == 0 {
    var (
      celerity    float64
      rotationX   float64
      rotationY   float64

      inertiaDrag float64
      inertiaTurn float64
    )

    // Free flight camera
    keyState := getEventKeyState()
    timeFactor := normalizedTimeFactor()

    // Decrease speed if diagonal move
    if keyState.MoveTurbo == true {
      celerity = ConfigCameraMoveCelerityTurbo
    } else {
      celerity = ConfigCameraMoveCelerityCruise
    }

    if (keyState.MoveUp == true || keyState.MoveDown == true) && (keyState.MoveLeft == true || keyState.MoveRight == true) {
      celerity /= math.Sqrt(2.0)
    }

    // Acquire rotation around axis
    rotationX = float64(camera.getTargetX())
    rotationY = float64(camera.getTargetY())

    // Process camera move position (keyboard)
    if keyState.MoveUp == true {
      produceInertia(&(camera.InertiaDrag), ConfigCameraInertiaProduceForward, celerity)
    }
    if keyState.MoveDown == true {
      produceInertia(&(camera.InertiaDrag), ConfigCameraInertiaProduceBackward, celerity)
    }
    if keyState.MoveLeft == true {
      produceInertia(&(camera.InertiaTurn), ConfigCameraInertiaProduceForward, celerity)
    }
    if keyState.MoveRight == true {
      produceInertia(&(camera.InertiaTurn), ConfigCameraInertiaProduceBackward, celerity)
    }

    // Apply new position with inertia
    inertiaDrag = consumeInertia(&(camera.InertiaDrag))
    inertiaTurn = consumeInertia(&(camera.InertiaTurn))

    camera.moveEyeX(timeFactor * float32(inertiaDrag * -1.0 * math.Sin(rotationY) + inertiaTurn * math.Cos(rotationY)))
    camera.moveEyeZ(timeFactor * float32(inertiaDrag * math.Cos(rotationY) + inertiaTurn * math.Sin(rotationY)))
    camera.moveEyeY(timeFactor * float32(inertiaDrag * math.Sin(rotationX)))
  } else {
    // Orbit camera
    size := normalizeObjectSize(camera.ObjectRadius)

    camera.PositionEye = mgl32.Vec3{0, 0, -1 * size * ConfigCameraOrbitMagnification}
  }

  // Translation: walk
  camera.Camera = camera.Camera.Mul4(mgl32.Translate3D(camera.getEyeX(), camera.getEyeY(), camera.getEyeZ()))
}

func processEventCameraTarget() {
  camera := getCamera()
  keyState := getEventKeyState()
  timeFactor := normalizedTimeFactor()

  camera.moveTargetX(timeFactor * keyState.WatchY * float32(math.Pi) * ConfigCameraTargetAmortizeFactor)
  camera.moveTargetY(timeFactor * keyState.WatchX * float32(math.Pi) * 2 * ConfigCameraTargetAmortizeFactor)

  // Rotation: view
  camera.Camera = camera.Camera.Mul4(mgl32.HomogRotate3D(camera.getTargetX(), mgl32.Vec3{1, 0, 0}))
  camera.Camera = camera.Camera.Mul4(mgl32.HomogRotate3D(camera.getTargetY(), mgl32.Vec3{0, 1, 0}))
  camera.Camera = camera.Camera.Mul4(mgl32.HomogRotate3D(camera.getTargetZ(), mgl32.Vec3{0, 0, 1}))
}

func updateCamera() {
  camera := getCamera()

  // Update overall camera position
  if camera.ObjectIndex == 0 {
    // Free flight
    camera.Camera = mgl32.Ident4()
  } else {
    // Orbit flight
    camera.Camera = camera.ObjectMatrix
  }

  // Orbit camera or free flight camera? (reverse rotation <> translation)
  if camera.ObjectIndex == 0 {
    // Orbit camera
    processEventCameraTarget()
    processEventCameraEye()
  } else {
    // Free flight camera
    processEventCameraEye()
    processEventCameraTarget()
  }
}

func toggleNextCameraObject() {
  camera := getCamera()

  // Go to next index
  camera.ObjectIndex++

  // Index overflow?
  if camera.ObjectIndex > len(*camera.ObjectList) {
    camera.ObjectIndex = 0
  }

  // Reset camera state
  resetCamera()
}

func resetCamera() {
  camera := getCamera()

  // Reset camera modifiers
  resetMouseCursor()

  // Reset camera itself
  camera.defaultInertia()

  camera.defaultEye()
  camera.defaultTarget()
}

func resetCameraObject() {
  getCamera().ObjectIndex = 0
}

func initializeCameraLocks(objects *[]Object) {
  // Initialize object list storage space
  var objectList []string

  getCamera().ObjectList = &objectList

  // Create camera locks (in object list)
  createCameraLocks(objects)
}

func createCameraLocks(objects *[]Object) {
  camera := getCamera()

  for o := range *objects {
    *camera.ObjectList = append(*camera.ObjectList, (*objects)[o].Name)

    // Create locks for child objects
    createCameraLocks(&((*objects)[o]).Objects)
  }
}

func bindCamera() {
  camera := getCamera()

  gl.UniformMatrix4fv(camera.CameraUniform, 1, false, &(camera.Camera[0]))
}
<|endoftext|>


<commit_before>// +build integration

/*
Copyright 2016 The Kubernetes Authors All rights reserved.

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

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

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

package integration

import (
	"context"
	"fmt"
	"net/http"
	"net/url"
	"os/exec"
	"path/filepath"
	"strings"
	"testing"
	"time"

	"github.com/hashicorp/go-retryablehttp"
	"k8s.io/minikube/pkg/kapi"
	"k8s.io/minikube/pkg/util/retry"
)

// TestAddons tests addons that require no special environment -- in parallel
func TestAddons(t *testing.T) {
	MaybeParallel(t)
	WaitForStartSlot(t)
	profile := UniqueProfileName("addons")
	ctx, cancel := context.WithTimeout(context.Background(), 40*time.Minute)
	defer CleanupWithLogs(t, profile, cancel)

	args := append([]string{"start", "-p", profile, "--wait=false", "--memory=2600", "--alsologtostderr", "-v=1", "--addons=ingress", "--addons=registry", "--addons=metrics-server"}, StartArgs()...)
	rr, err := Run(t, exec.CommandContext(ctx, Target(), args...))
	if err != nil {
		t.Fatalf("%s failed: %v", rr.Args, err)
	}

	// Parallelized tests
	t.Run("parallel", func(t *testing.T) {
		tests := []struct {
			name      string
			validator validateFunc
		}{
			{"Registry", validateRegistryAddon},
			{"Ingress", validateIngressAddon},
			{"MetricsServer", validateMetricsServerAddon},
		}
		for _, tc := range tests {
			tc := tc
			t.Run(tc.name, func(t *testing.T) {
				MaybeParallel(t)
				tc.validator(ctx, t, profile)
			})
		}
	})

	// Assert that disable/enable works offline
	rr, err = Run(t, exec.CommandContext(ctx, Target(), "stop", "-p", profile))
	if err != nil {
		t.Errorf("%s failed: %v", rr.Args, err)
	}
	rr, err = Run(t, exec.CommandContext(ctx, Target(), "addons", "enable", "dashboard", "-p", profile))
	if err != nil {
		t.Errorf("%s failed: %v", rr.Args, err)
	}
	rr, err = Run(t, exec.CommandContext(ctx, Target(), "addons", "disable", "dashboard", "-p", profile))
	if err != nil {
		t.Errorf("%s failed: %v", rr.Args, err)
	}
}

func validateIngressAddon(ctx context.Context, t *testing.T, profile string) {
	if NoneDriver() {
		t.Skipf("skipping: ssh unsupported by none")
	}

	client, err := kapi.Client(profile)
	if err != nil {
		t.Fatalf("kubernetes client: %v", client)
	}

	if err := kapi.WaitForDeploymentToStabilize(client, "kube-system", "nginx-ingress-controller", 6*time.Minute); err != nil {
		t.Errorf("waiting for ingress-controller deployment to stabilize: %v", err)
	}
	if _, err := PodWait(ctx, t, profile, "kube-system", "app.kubernetes.io/name=nginx-ingress-controller", 12*time.Minute); err != nil {
		t.Fatalf("wait: %v", err)
	}

	rr, err := Run(t, exec.CommandContext(ctx, "kubectl", "--context", profile, "replace", "--force", "-f", filepath.Join(*testdataDir, "nginx-ing.yaml")))
	if err != nil {
		t.Errorf("%s failed: %v", rr.Args, err)
	}
	rr, err = Run(t, exec.CommandContext(ctx, "kubectl", "--context", profile, "replace", "--force", "-f", filepath.Join(*testdataDir, "nginx-pod-svc.yaml")))
	if err != nil {
		t.Errorf("%s failed: %v", rr.Args, err)
	}

	if _, err := PodWait(ctx, t, profile, "default", "run=nginx", 4*time.Minute); err != nil {
		t.Fatalf("wait: %v", err)
	}
	if err := kapi.WaitForService(client, "default", "nginx", true, time.Millisecond*500, time.Minute*10); err != nil {
		t.Errorf("Error waiting for nginx service to be up")
	}

	want := "Welcome to nginx!"
	checkIngress := func() error {
		rr, err := Run(t, exec.CommandContext(ctx, Target(), "-p", profile, "ssh", fmt.Sprintf("curl http://127.0.0.1:80 -H 'Host: nginx.example.com'")))
		if err != nil {
			return err
		}
		if rr.Stderr.String() != "" {
			t.Logf("%v: unexpected stderr: %s", rr.Args, rr.Stderr)
		}
		if !strings.Contains(rr.Stdout.String(), want) {
			return fmt.Errorf("%v stdout = %q, want %q", rr.Args, rr.Stdout, want)
		}
		return nil
	}

	if err := retry.Expo(checkIngress, 500*time.Millisecond, time.Minute); err != nil {
		t.Errorf("ingress never responded as expected on 127.0.0.1:80: %v", err)
	}

	rr, err = Run(t, exec.CommandContext(ctx, Target(), "-p", profile, "addons", "disable", "ingress", "--alsologtostderr", "-v=1"))
	if err != nil {
		t.Errorf("%s failed: %v", rr.Args, err)
	}
}

func validateRegistryAddon(ctx context.Context, t *testing.T, profile string) {
	client, err := kapi.Client(profile)
	if err != nil {
		t.Fatalf("kubernetes client: %v", client)
	}

	start := time.Now()
	if err := kapi.WaitForRCToStabilize(client, "kube-system", "registry", 6*time.Minute); err != nil {
		t.Errorf("waiting for registry replicacontroller to stabilize: %v", err)
	}
	t.Logf("registry stabilized in %s", time.Since(start))

	if _, err := PodWait(ctx, t, profile, "kube-system", "actual-registry=true", 6*time.Minute); err != nil {
		t.Fatalf("wait: %v", err)
	}
	if _, err := PodWait(ctx, t, profile, "kube-system", "registry-proxy=true", 10*time.Minute); err != nil {
		t.Fatalf("wait: %v", err)
	}

	// Test from inside the cluster (no curl available on busybox)
	rr, err := Run(t, exec.CommandContext(ctx, "kubectl", "--context", profile, "delete", "po", "-l", "run=registry-test", "--now"))
	if err != nil {
		t.Logf("pre-cleanup %s failed: %v (not a problem)", rr.Args, err)
	}

	rr, err = Run(t, exec.CommandContext(ctx, "kubectl", "--context", profile, "run", "--rm", "registry-test", "--restart=Never", "--image=busybox", "-it", "--", "sh", "-c", "wget --spider -S http://registry.kube-system.svc.cluster.local"))
	if err != nil {
		t.Errorf("%s failed: %v", rr.Args, err)
	}
	want := "HTTP/1.1 200"
	if !strings.Contains(rr.Stdout.String(), want) {
		t.Errorf("curl = %q, want *%s*", rr.Stdout.String(), want)
	}

	// Test from outside the cluster
	rr, err = Run(t, exec.CommandContext(ctx, Target(), "-p", profile, "ip"))
	if err != nil {
		t.Fatalf("%s failed: %v", rr.Args, err)
	}
	if rr.Stderr.String() != "" {
		t.Errorf("%s: unexpected stderr: %s", rr.Args, rr.Stderr)
	}

	endpoint := fmt.Sprintf("http://%s:%d", strings.TrimSpace(rr.Stdout.String()), 5000)
	u, err := url.Parse(endpoint)
	if err != nil {
		t.Fatalf("failed to parse %q: %v", endpoint, err)
	}

	checkExternalAccess := func() error {
		resp, err := retryablehttp.Get(u.String())
		if err != nil {
			return err
		}
		if resp.StatusCode != http.StatusOK {
			return fmt.Errorf("%s = status code %d, want %d", u, resp.StatusCode, http.StatusOK)
		}
		return nil
	}

	if err := retry.Expo(checkExternalAccess, 500*time.Millisecond, 2*time.Minute); err != nil {
		t.Errorf(err.Error())
	}

	rr, err = Run(t, exec.CommandContext(ctx, Target(), "-p", profile, "addons", "disable", "registry", "--alsologtostderr", "-v=1"))
	if err != nil {
		t.Errorf("%s failed: %v", rr.Args, err)
	}
}

func validateMetricsServerAddon(ctx context.Context, t *testing.T, profile string) {
	client, err := kapi.Client(profile)
	if err != nil {
		t.Fatalf("kubernetes client: %v", client)
	}

	start := time.Now()
	if err := kapi.WaitForDeploymentToStabilize(client, "kube-system", "metrics-server", 6*time.Minute); err != nil {
		t.Errorf("waiting for metrics-server deployment to stabilize: %v", err)
	}
	t.Logf("metrics-server stabilized in %s", time.Since(start))

	if _, err := PodWait(ctx, t, profile, "kube-system", "k8s-app=metrics-server", 6*time.Minute); err != nil {
		t.Fatalf("wait: %v", err)
	}

	want := "CPU(cores)"
	checkMetricsServer := func() error {
		rr, err := Run(t, exec.CommandContext(ctx, "kubectl", "--context", profile, "top", "pods", "-n", "kube-system"))
		if err != nil {
			return err
		}
		if rr.Stderr.String() != "" {
			t.Logf("%v: unexpected stderr: %s", rr.Args, rr.Stderr)
		}
		if !strings.Contains(rr.Stdout.String(), want) {
			return fmt.Errorf("%v stdout = %q, want %q", rr.Args, rr.Stdout, want)
		}
		return nil
	}

	// metrics-server takes some time to be able to collect metrics
	if err := retry.Expo(checkMetricsServer, time.Minute, 5*time.Minute); err != nil {
		t.Errorf(err.Error())
	}

	rr, err := Run(t, exec.CommandContext(ctx, Target(), "-p", profile, "addons", "disable", "metrics-server", "--alsologtostderr", "-v=1"))
	if err != nil {
		t.Errorf("%s failed: %v", rr.Args, err)
	}
}
<commit_msg>try running addons test in sequence, since parallel test seems to be failing on virtualbox<commit_after>// +build integration

/*
Copyright 2016 The Kubernetes Authors All rights reserved.

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

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

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

package integration

import (
	"context"
	"fmt"
	"net/http"
	"net/url"
	"os/exec"
	"path/filepath"
	"strings"
	"testing"
	"time"

	"github.com/hashicorp/go-retryablehttp"
	"k8s.io/minikube/pkg/kapi"
	"k8s.io/minikube/pkg/util/retry"
)

// TestAddons tests addons that require no special environment -- in parallel
func TestAddons(t *testing.T) {
	WaitForStartSlot(t)
	profile := UniqueProfileName("addons")
	ctx, cancel := context.WithTimeout(context.Background(), 40*time.Minute)
	defer CleanupWithLogs(t, profile, cancel)

	args := append([]string{"start", "-p", profile, "--wait=false", "--memory=2600", "--alsologtostderr", "-v=1", "--addons=ingress", "--addons=registry", "--addons=metrics-server"}, StartArgs()...)
	rr, err := Run(t, exec.CommandContext(ctx, Target(), args...))
	if err != nil {
		t.Fatalf("%s failed: %v", rr.Args, err)
	}

	// Parallelized tests
	t.Run("parallel", func(t *testing.T) {
		tests := []struct {
			name      string
			validator validateFunc
		}{
			{"Registry", validateRegistryAddon},
			{"Ingress", validateIngressAddon},
			{"MetricsServer", validateMetricsServerAddon},
		}
		for _, tc := range tests {
			tc := tc
			t.Run(tc.name, func(t *testing.T) {
				tc.validator(ctx, t, profile)
			})
		}
	})

	// Assert that disable/enable works offline
	rr, err = Run(t, exec.CommandContext(ctx, Target(), "stop", "-p", profile))
	if err != nil {
		t.Errorf("%s failed: %v", rr.Args, err)
	}
	rr, err = Run(t, exec.CommandContext(ctx, Target(), "addons", "enable", "dashboard", "-p", profile))
	if err != nil {
		t.Errorf("%s failed: %v", rr.Args, err)
	}
	rr, err = Run(t, exec.CommandContext(ctx, Target(), "addons", "disable", "dashboard", "-p", profile))
	if err != nil {
		t.Errorf("%s failed: %v", rr.Args, err)
	}
}

func validateIngressAddon(ctx context.Context, t *testing.T, profile string) {
	if NoneDriver() {
		t.Skipf("skipping: ssh unsupported by none")
	}

	client, err := kapi.Client(profile)
	if err != nil {
		t.Fatalf("kubernetes client: %v", client)
	}

	if err := kapi.WaitForDeploymentToStabilize(client, "kube-system", "nginx-ingress-controller", 6*time.Minute); err != nil {
		t.Errorf("waiting for ingress-controller deployment to stabilize: %v", err)
	}
	if _, err := PodWait(ctx, t, profile, "kube-system", "app.kubernetes.io/name=nginx-ingress-controller", 12*time.Minute); err != nil {
		t.Fatalf("wait: %v", err)
	}

	rr, err := Run(t, exec.CommandContext(ctx, "kubectl", "--context", profile, "replace", "--force", "-f", filepath.Join(*testdataDir, "nginx-ing.yaml")))
	if err != nil {
		t.Errorf("%s failed: %v", rr.Args, err)
	}
	rr, err = Run(t, exec.CommandContext(ctx, "kubectl", "--context", profile, "replace", "--force", "-f", filepath.Join(*testdataDir, "nginx-pod-svc.yaml")))
	if err != nil {
		t.Errorf("%s failed: %v", rr.Args, err)
	}

	if _, err := PodWait(ctx, t, profile, "default", "run=nginx", 4*time.Minute); err != nil {
		t.Fatalf("wait: %v", err)
	}
	if err := kapi.WaitForService(client, "default", "nginx", true, time.Millisecond*500, time.Minute*10); err != nil {
		t.Errorf("Error waiting for nginx service to be up")
	}

	want := "Welcome to nginx!"
	checkIngress := func() error {
		rr, err := Run(t, exec.CommandContext(ctx, Target(), "-p", profile, "ssh", fmt.Sprintf("curl http://127.0.0.1:80 -H 'Host: nginx.example.com'")))
		if err != nil {
			return err
		}
		if rr.Stderr.String() != "" {
			t.Logf("%v: unexpected stderr: %s", rr.Args, rr.Stderr)
		}
		if !strings.Contains(rr.Stdout.String(), want) {
			return fmt.Errorf("%v stdout = %q, want %q", rr.Args, rr.Stdout, want)
		}
		return nil
	}

	if err := retry.Expo(checkIngress, 500*time.Millisecond, time.Minute); err != nil {
		t.Errorf("ingress never responded as expected on 127.0.0.1:80: %v", err)
	}

	rr, err = Run(t, exec.CommandContext(ctx, Target(), "-p", profile, "addons", "disable", "ingress", "--alsologtostderr", "-v=1"))
	if err != nil {
		t.Errorf("%s failed: %v", rr.Args, err)
	}
}

func validateRegistryAddon(ctx context.Context, t *testing.T, profile string) {
	client, err := kapi.Client(profile)
	if err != nil {
		t.Fatalf("kubernetes client: %v", client)
	}

	start := time.Now()
	if err := kapi.WaitForRCToStabilize(client, "kube-system", "registry", 6*time.Minute); err != nil {
		t.Errorf("waiting for registry replicacontroller to stabilize: %v", err)
	}
	t.Logf("registry stabilized in %s", time.Since(start))

	if _, err := PodWait(ctx, t, profile, "kube-system", "actual-registry=true", 6*time.Minute); err != nil {
		t.Fatalf("wait: %v", err)
	}
	if _, err := PodWait(ctx, t, profile, "kube-system", "registry-proxy=true", 10*time.Minute); err != nil {
		t.Fatalf("wait: %v", err)
	}

	// Test from inside the cluster (no curl available on busybox)
	rr, err := Run(t, exec.CommandContext(ctx, "kubectl", "--context", profile, "delete", "po", "-l", "run=registry-test", "--now"))
	if err != nil {
		t.Logf("pre-cleanup %s failed: %v (not a problem)", rr.Args, err)
	}

	rr, err = Run(t, exec.CommandContext(ctx, "kubectl", "--context", profile, "run", "--rm", "registry-test", "--restart=Never", "--image=busybox", "-it", "--", "sh", "-c", "wget --spider -S http://registry.kube-system.svc.cluster.local"))
	if err != nil {
		t.Errorf("%s failed: %v", rr.Args, err)
	}
	want := "HTTP/1.1 200"
	if !strings.Contains(rr.Stdout.String(), want) {
		t.Errorf("curl = %q, want *%s*", rr.Stdout.String(), want)
	}

	// Test from outside the cluster
	rr, err = Run(t, exec.CommandContext(ctx, Target(), "-p", profile, "ip"))
	if err != nil {
		t.Fatalf("%s failed: %v", rr.Args, err)
	}
	if rr.Stderr.String() != "" {
		t.Errorf("%s: unexpected stderr: %s", rr.Args, rr.Stderr)
	}

	endpoint := fmt.Sprintf("http://%s:%d", strings.TrimSpace(rr.Stdout.String()), 5000)
	u, err := url.Parse(endpoint)
	if err != nil {
		t.Fatalf("failed to parse %q: %v", endpoint, err)
	}

	checkExternalAccess := func() error {
		resp, err := retryablehttp.Get(u.String())
		if err != nil {
			return err
		}
		if resp.StatusCode != http.StatusOK {
			return fmt.Errorf("%s = status code %d, want %d", u, resp.StatusCode, http.StatusOK)
		}
		return nil
	}

	if err := retry.Expo(checkExternalAccess, 500*time.Millisecond, 2*time.Minute); err != nil {
		t.Errorf(err.Error())
	}

	rr, err = Run(t, exec.CommandContext(ctx, Target(), "-p", profile, "addons", "disable", "registry", "--alsologtostderr", "-v=1"))
	if err != nil {
		t.Errorf("%s failed: %v", rr.Args, err)
	}
}

func validateMetricsServerAddon(ctx context.Context, t *testing.T, profile string) {
	client, err := kapi.Client(profile)
	if err != nil {
		t.Fatalf("kubernetes client: %v", client)
	}

	start := time.Now()
	if err := kapi.WaitForDeploymentToStabilize(client, "kube-system", "metrics-server", 6*time.Minute); err != nil {
		t.Errorf("waiting for metrics-server deployment to stabilize: %v", err)
	}
	t.Logf("metrics-server stabilized in %s", time.Since(start))

	if _, err := PodWait(ctx, t, profile, "kube-system", "k8s-app=metrics-server", 6*time.Minute); err != nil {
		t.Fatalf("wait: %v", err)
	}

	want := "CPU(cores)"
	checkMetricsServer := func() error {
		rr, err := Run(t, exec.CommandContext(ctx, "kubectl", "--context", profile, "top", "pods", "-n", "kube-system"))
		if err != nil {
			return err
		}
		if rr.Stderr.String() != "" {
			t.Logf("%v: unexpected stderr: %s", rr.Args, rr.Stderr)
		}
		if !strings.Contains(rr.Stdout.String(), want) {
			return fmt.Errorf("%v stdout = %q, want %q", rr.Args, rr.Stdout, want)
		}
		return nil
	}

	// metrics-server takes some time to be able to collect metrics
	if err := retry.Expo(checkMetricsServer, time.Minute, 5*time.Minute); err != nil {
		t.Errorf(err.Error())
	}

	rr, err := Run(t, exec.CommandContext(ctx, Target(), "-p", profile, "addons", "disable", "metrics-server", "--alsologtostderr", "-v=1"))
	if err != nil {
		t.Errorf("%s failed: %v", rr.Args, err)
	}
}
<|endoftext|>


<commit_before>package utils

import (
	"strconv"
	"sync/atomic"
	"time"
)

// v2 types

type NonceGenerator interface {
	GetNonce() string
}

type EpochNonceGenerator struct {
	nonce uint64
}

// GetNonce is a naive nonce producer that takes the current Unix nano epoch
// and counts upwards.
// This is a naive approach because the nonce bound to the currently used API
// key and as such needs to be synchronised with other instances using the same
// key in order to avoid race conditions.
func (u *EpochNonceGenerator) GetNonce() string {
	return strconv.FormatUint(atomic.AddUint64(&u.nonce, 1), 10)
}

func NewEpochNonceGenerator() *EpochNonceGenerator {
	return &EpochNonceGenerator{
		nonce: uint64(time.Now().Unix()) * 1000,
	}
}

// v1 support

var nonce uint64

func init() {
	nonce = uint64(time.Now().UnixNano()) * 1000
}

// GetNonce is a naive nonce producer that takes the current Unix nano epoch
// and counts upwards.
// This is a naive approach because the nonce bound to the currently used API
// key and as such needs to be synchronised with other instances using the same
// key in order to avoid race conditions.
func GetNonce() string {
	return strconv.FormatUint(atomic.AddUint64(&nonce, 1), 10)
}
<commit_msg>fixing nonce issue to be compatible with other libraries<commit_after>package utils

import (
	"strconv"
	"sync/atomic"
	"time"
)

// v2 types

type NonceGenerator interface {
	GetNonce() string
}

type EpochNonceGenerator struct {
	nonce uint64
}

// GetNonce is a naive nonce producer that takes the current Unix nano epoch
// and counts upwards.
// This is a naive approach because the nonce bound to the currently used API
// key and as such needs to be synchronised with other instances using the same
// key in order to avoid race conditions.
func (u *EpochNonceGenerator) GetNonce() string {
	return strconv.FormatUint(atomic.AddUint64(&u.nonce, 1), 10)
}

func NewEpochNonceGenerator() *EpochNonceGenerator {
	return &EpochNonceGenerator{
		nonce: uint64(time.Now().Unix()) * 1000000,
	}
}

// v1 support

var nonce uint64

func init() {
	nonce = uint64(time.Now().UnixNano()) * 1000000
}

// GetNonce is a naive nonce producer that takes the current Unix nano epoch
// and counts upwards.
// This is a naive approach because the nonce bound to the currently used API
// key and as such needs to be synchronised with other instances using the same
// key in order to avoid race conditions.
func GetNonce() string {
	return strconv.FormatUint(atomic.AddUint64(&nonce, 1), 10)
}
<|endoftext|>


<commit_before>// Take well-formed json from either stdin or an input file and create an elasticsearch document to be used to
// generate user specific dashboards or highly contextual alerts.
//
// LICENSE:
//   Copyright 2015 Yieldbot. <devops@yieldbot.com>
//   Released under the MIT License; see LICENSE
//   for details.

package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"github.com/yieldbot/dhuran"
	"github.com/yieldbot/dracky"
	"github.com/olivere/elastic"
	"io/ioutil"
	"os"
	"time"
)

func main() {

	// set commandline flags
	es_indexPtr := flag.String("index", dracky.STATUS_ES_INDEX, "the elasticsearch index to use")
	es_hostPtr := flag.String("host", dracky.DEFAULT_ES_HOST, "the elasticsearch host")
	es_portPtr := flag.String("port", dracky.DEFAULT_ES_PORT, "the elasticsearch port")
	stdinPtr := flag.Bool("read-stdin", true, "read input from stdin")
	//timePtr := flag.string("t-format", "", "time format to suffix on the index name")
	input_filePtr := flag.String("input-file", "", "file to read json in from, check docs for proper format")

	flag.Parse()
	es_index := *es_indexPtr
	es_type := dracky.DEFAULT_ES_TYPE
	es_host := *es_hostPtr
	es_port := *es_portPtr
	rd_stdin := *stdinPtr
	input_file := *input_filePtr

	// I don't want to call these if they are not needed
	sensu_event := new(dracky.Sensu_Event)
	user_event := new(dracky.User_Event)
	//t_format := *timePtr

	sensu_env := dracky.Set_sensu_env()

	//   if t_format != "" {
	//     // get the format of the time
	//     es_index = es_index + t_format
	//   }

	if (rd_stdin == false) && (input_file != "") {
		user_input, err := ioutil.ReadFile(input_file)
		if err != nil {
			dhuran.Check(err)
		}
		err = json.Unmarshal(user_input, &user_event)
		if err != nil {
			dhuran.Check(err)
		}
		es_type = "user"
	} else if (rd_stdin == false) && (input_file == "") {
		fmt.Printf("Please enter a file to read from")
		os.Exit(1)
	} else {
		sensu_event = sensu_event.Acquire_sensu_event()
	}

	// Create a client
	client, err := elastic.NewClient(
		elastic.SetURL("http://" + es_host + ":" + es_port),
	)
	if err != nil {
		dhuran.Check(err)
	}

	// Check to see if the index exists and if not create it
	if client.IndexExists == nil { // need to test to make sure this does what I want
		_, err = client.CreateIndex(es_index).Do()
		if err != nil {
			dhuran.Check(err)
		}
	}

	// Create an Elasticsearch document. The document type will define the mapping used for the document.
	doc := make(map[string]string)
	var doc_id string
	switch es_type {
	case "sensu":
		doc_id = dracky.Event_name(sensu_event.Client.Name, sensu_event.Check.Name)
		doc["monitored_instance"] = sensu_event.Acquire_monitored_instance()
		doc["sensu_client"] = sensu_event.Client.Name
		doc["incident_timestamp"] = time.Unix(sensu_event.Check.Issued, 0).Format(time.RFC3339)
		doc["check_name"] = dracky.Create_check_name(sensu_event.Check.Name)
		doc["check_state"] = dracky.Define_status(sensu_event.Check.Status)
		doc["sensu_env"] = dracky.Define_sensu_env(sensu_env.Sensu.Environment)
		doc["instance_address"] = sensu_event.Client.Address
		doc["check_state_duration"] = dracky.Define_check_state_duration()
	case "user":
		doc["product"] = user_event.Product
		doc["data"] = user_event.Data
		doc["timestamp"] = time.Unix(sensu_event.Check.Issued, 0).Format(time.RFC3339) // dracky.Set_time(user_event.Timestamp)
	default:
		fmt.Printf("Type is not correctly set")
		os.Exit(2)
	}

	// Add a document to the Elasticsearch index
	_, err = client.Index().
		Index(es_index).
		Type(es_type).
		Id(doc_id).
		BodyJson(doc).
		Do()
	if err != nil {
		dhuran.Check(err)
	}

	// Log a successful document push to stdout. I don't add the id here as some id's are fixed but
	// the user has the ability to autogenerate an id if they don't want to provide one.
	fmt.Printf("Record added to ES\n")
}
<commit_msg>change from dhuran lib to dracky<commit_after>// Take well-formed json from either stdin or an input file and create an elasticsearch document to be used to
// generate user specific dashboards or highly contextual alerts.
//
// LICENSE:
//   Copyright 2015 Yieldbot. <devops@yieldbot.com>
//   Released under the MIT License; see LICENSE
//   for details.

package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"github.com/yieldbot/"
	"github.com/yieldbot/dracky"
	"github.com/olivere/elastic"
	"io/ioutil"
	"os"
	"time"
)

func main() {

	// set commandline flags
	es_indexPtr := flag.String("index", dracky.STATUS_ES_INDEX, "the elasticsearch index to use")
	es_hostPtr := flag.String("host", dracky.DEFAULT_ES_HOST, "the elasticsearch host")
	es_portPtr := flag.String("port", dracky.DEFAULT_ES_PORT, "the elasticsearch port")
	stdinPtr := flag.Bool("read-stdin", true, "read input from stdin")
	//timePtr := flag.string("t-format", "", "time format to suffix on the index name")
	input_filePtr := flag.String("input-file", "", "file to read json in from, check docs for proper format")

	flag.Parse()
	es_index := *es_indexPtr
	es_type := dracky.DEFAULT_ES_TYPE
	es_host := *es_hostPtr
	es_port := *es_portPtr
	rd_stdin := *stdinPtr
	input_file := *input_filePtr

	// I don't want to call these if they are not needed
	sensu_event := new(dracky.Sensu_Event)
	user_event := new(dracky.User_Event)
	//t_format := *timePtr

	sensu_env := dracky.Set_sensu_env()

	//   if t_format != "" {
	//     // get the format of the time
	//     es_index = es_index + t_format
	//   }

	if (rd_stdin == false) && (input_file != "") {
		user_input, err := ioutil.ReadFile(input_file)
		if err != nil {
			dracky.Check(err)
		}
		err = json.Unmarshal(user_input, &user_event)
		if err != nil {
			dracky.Check(err)
		}
		es_type = "user"
	} else if (rd_stdin == false) && (input_file == "") {
		fmt.Printf("Please enter a file to read from")
		os.Exit(1)
	} else {
		sensu_event = sensu_event.Acquire_sensu_event()
	}

	// Create a client
	client, err := elastic.NewClient(
		elastic.SetURL("http://" + es_host + ":" + es_port),
	)
	if err != nil {
		dracky.Check(err)
	}

	// Check to see if the index exists and if not create it
	if client.IndexExists == nil { // need to test to make sure this does what I want
		_, err = client.CreateIndex(es_index).Do()
		if err != nil {
			dracky.Check(err)
		}
	}

	// Create an Elasticsearch document. The document type will define the mapping used for the document.
	doc := make(map[string]string)
	var doc_id string
	switch es_type {
	case "sensu":
		doc_id = dracky.Event_name(sensu_event.Client.Name, sensu_event.Check.Name)
		doc["monitored_instance"] = sensu_event.Acquire_monitored_instance()
		doc["sensu_client"] = sensu_event.Client.Name
		doc["incident_timestamp"] = time.Unix(sensu_event.Check.Issued, 0).Format(time.RFC3339)
		doc["check_name"] = dracky.Create_check_name(sensu_event.Check.Name)
		doc["check_state"] = dracky.Define_status(sensu_event.Check.Status)
		doc["sensu_env"] = dracky.Define_sensu_env(sensu_env.Sensu.Environment)
		doc["instance_address"] = sensu_event.Client.Address
		doc["check_state_duration"] = dracky.Define_check_state_duration()
	case "user":
		doc["product"] = user_event.Product
		doc["data"] = user_event.Data
		doc["timestamp"] = time.Unix(sensu_event.Check.Issued, 0).Format(time.RFC3339) // dracky.Set_time(user_event.Timestamp)
	default:
		fmt.Printf("Type is not correctly set")
		os.Exit(2)
	}

	// Add a document to the Elasticsearch index
	_, err = client.Index().
		Index(es_index).
		Type(es_type).
		Id(doc_id).
		BodyJson(doc).
		Do()
	if err != nil {
		dracky.Check(err)
	}

	// Log a successful document push to stdout. I don't add the id here as some id's are fixed but
	// the user has the ability to autogenerate an id if they don't want to provide one.
	fmt.Printf("Record added to ES\n")
}
<|endoftext|>