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

package mat64

import (
	"math"
	"testing"

	"github.com/gonum/blas/blas64"
	"gopkg.in/check.v1"
)

func (s *S) TestInner(c *check.C) {
	for i, test := range []struct {
		x []float64
		y []float64
		m [][]float64
	}{
		{
			x: []float64{5},
			y: []float64{10},
			m: [][]float64{{2}},
		},
		{
			x: []float64{5, 6, 1},
			y: []float64{10},
			m: [][]float64{{2}, {-3}, {5}},
		},
		{
			x: []float64{5},
			y: []float64{10, 15},
			m: [][]float64{{2, -3}},
		},
		{
			x: []float64{1, 5},
			y: []float64{10, 15},
			m: [][]float64{
				{2, -3},
				{4, -1},
			},
		},
		{
			x: []float64{2, 3, 9},
			y: []float64{8, 9},
			m: [][]float64{
				{2, 3},
				{4, 5},
				{6, 7},
			},
		},
		{
			x: []float64{2, 3},
			y: []float64{8, 9, 9},
			m: [][]float64{
				{2, 3, 6},
				{4, 5, 7},
			},
		},
	} {
		for _, inc := range []struct{ x, y int }{
			{1, 1},
			{1, 2},
			{2, 1},
			{2, 2},
		} {
			x := NewDense(1, len(test.x), test.x)
			m := NewDense(flatten(test.m))
			mWant := NewDense(flatten(test.m))
			y := NewDense(len(test.y), 1, test.y)

			var tmp, cell Dense
			tmp.Mul(mWant, y)
			cell.Mul(x, &tmp)

			rm, cm := cell.Dims()
			c.Check(rm, check.Equals, 1, check.Commentf("Test %v result doesn't have 1 row", i))
			c.Check(cm, check.Equals, 1, check.Commentf("Test %v result doesn't have 1 column", i))

			want := cell.At(0, 0)

			got := Inner(makeVectorInc(inc.x, test.x), m, makeVectorInc(inc.y, test.y))
			c.Check(want, check.Equals, got, check.Commentf("Test %v: want %v, got %v", i, want, got))
		}
	}
}

func (s *S) TestInnerSym(c *check.C) {
	for _, inc := range []struct{ x, y int }{
		{1, 1},
		{1, 2},
		{2, 1},
		{2, 2},
	} {
		n := 10
		xData := make([]float64, n)
		yData := make([]float64, n)
		data := make([]float64, n*n)
		for i := 0; i < n; i++ {
			xData[i] = float64(i)
			yData[i] = float64(i)
			for j := i; j < n; j++ {
				data[i*n+j] = float64(i*n + j)
				data[j*n+i] = data[i*n+j]
			}
		}
		x := makeVectorInc(inc.x, xData)
		y := makeVectorInc(inc.y, yData)
		m := NewDense(n, n, data)
		ans := Inner(x, m, y)
		sym := NewSymDense(n, data)
		// Poison the lower half of data to ensure it is not used.
		for i := 1; i < n; i++ {
			for j := 0; j < i; j++ {
				data[i*n+j] = math.NaN()
			}
		}

		if math.Abs(Inner(x, sym, y)-ans) > 1e-14 {
			c.Error("inner different symmetric and dense")
		}
	}
}

func makeVectorInc(inc int, f []float64) *Vector {
	v := &Vector{
		n: len(f),
		mat: blas64.Vector{
			Inc:  inc,
			Data: make([]float64, (len(f)-1)*inc+1),
		},
	}

	// Contaminate backing data in all positions...
	const base = 100
	for i := range v.mat.Data {
		v.mat.Data[i] = float64(i + base)
	}

	// then write real elements.
	for i := range f {
		v.mat.Data[i*inc] = f[i]
	}
	return v
}

func benchmarkInner(b *testing.B, m, n int) {
	x := NewVector(m, nil)
	randomSlice(x.mat.Data)
	y := NewVector(n, nil)
	randomSlice(y.mat.Data)
	data := make([]float64, m*n)
	randomSlice(data)
	mat := &Dense{mat: blas64.General{Rows: m, Cols: n, Stride: n, Data: data}, capRows: m, capCols: n}
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		Inner(x, mat, y)
	}
}

func BenchmarkInnerSmSm(b *testing.B) {
	benchmarkInner(b, Sm, Sm)
}

func BenchmarkInnerMedMed(b *testing.B) {
	benchmarkInner(b, Med, Med)
}

func BenchmarkInnerLgLg(b *testing.B) {
	benchmarkInner(b, Lg, Lg)
}

func BenchmarkInnerLgSm(b *testing.B) {
	benchmarkInner(b, Lg, Sm)
}
<commit_msg>mat64: refactor Inner tests<commit_after>// Copyright ©2014 The gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package mat64

import (
	"math"
	"testing"

	"github.com/gonum/blas/blas64"
	"gopkg.in/check.v1"
)

func (s *S) TestInner(c *check.C) {
	for i, test := range []struct {
		x []float64
		y []float64
		m [][]float64
	}{
		{
			x: []float64{5},
			y: []float64{10},
			m: [][]float64{{2}},
		},
		{
			x: []float64{5, 6, 1},
			y: []float64{10},
			m: [][]float64{{2}, {-3}, {5}},
		},
		{
			x: []float64{5},
			y: []float64{10, 15},
			m: [][]float64{{2, -3}},
		},
		{
			x: []float64{1, 5},
			y: []float64{10, 15},
			m: [][]float64{
				{2, -3},
				{4, -1},
			},
		},
		{
			x: []float64{2, 3, 9},
			y: []float64{8, 9},
			m: [][]float64{
				{2, 3},
				{4, 5},
				{6, 7},
			},
		},
		{
			x: []float64{2, 3},
			y: []float64{8, 9, 9},
			m: [][]float64{
				{2, 3, 6},
				{4, 5, 7},
			},
		},
	} {
		for _, inc := range []struct{ x, y int }{
			{1, 1},
			{1, 2},
			{2, 1},
			{2, 2},
		} {
			x := NewDense(1, len(test.x), test.x)
			m := NewDense(flatten(test.m))
			mWant := NewDense(flatten(test.m))
			y := NewDense(len(test.y), 1, test.y)

			var tmp, cell Dense
			tmp.Mul(mWant, y)
			cell.Mul(x, &tmp)

			rm, cm := cell.Dims()
			if rm != 1 {
				c.Errorf("Test %d result doesn't have 1 row", i)
			}
			if cm != 1 {
				c.Errorf("Test %d result doesn't have 1 column", i)
			}

			want := cell.At(0, 0)
			got := Inner(makeVectorInc(inc.x, test.x), m, makeVectorInc(inc.y, test.y))
			if got != want {
				c.Errorf("Test %v: want %v, got %v", i, want, got)
			}
		}
	}
}

func (s *S) TestInnerSym(c *check.C) {
	for _, inc := range []struct{ x, y int }{
		{1, 1},
		{1, 2},
		{2, 1},
		{2, 2},
	} {
		n := 10
		xData := make([]float64, n)
		yData := make([]float64, n)
		data := make([]float64, n*n)
		for i := 0; i < n; i++ {
			xData[i] = float64(i)
			yData[i] = float64(i)
			for j := i; j < n; j++ {
				data[i*n+j] = float64(i*n + j)
				data[j*n+i] = data[i*n+j]
			}
		}
		x := makeVectorInc(inc.x, xData)
		y := makeVectorInc(inc.y, yData)
		m := NewDense(n, n, data)
		ans := Inner(x, m, y)
		sym := NewSymDense(n, data)
		// Poison the lower half of data to ensure it is not used.
		for i := 1; i < n; i++ {
			for j := 0; j < i; j++ {
				data[i*n+j] = math.NaN()
			}
		}

		if math.Abs(Inner(x, sym, y)-ans) > 1e-14 {
			c.Error("inner different symmetric and dense")
		}
	}
}

func makeVectorInc(inc int, f []float64) *Vector {
	v := &Vector{
		n: len(f),
		mat: blas64.Vector{
			Inc:  inc,
			Data: make([]float64, (len(f)-1)*inc+1),
		},
	}

	// Contaminate backing data in all positions...
	const base = 100
	for i := range v.mat.Data {
		v.mat.Data[i] = float64(i + base)
	}

	// then write real elements.
	for i := range f {
		v.mat.Data[i*inc] = f[i]
	}
	return v
}

func benchmarkInner(b *testing.B, m, n int) {
	x := NewVector(m, nil)
	randomSlice(x.mat.Data)
	y := NewVector(n, nil)
	randomSlice(y.mat.Data)
	data := make([]float64, m*n)
	randomSlice(data)
	mat := &Dense{mat: blas64.General{Rows: m, Cols: n, Stride: n, Data: data}, capRows: m, capCols: n}
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		Inner(x, mat, y)
	}
}

func BenchmarkInnerSmSm(b *testing.B) {
	benchmarkInner(b, Sm, Sm)
}

func BenchmarkInnerMedMed(b *testing.B) {
	benchmarkInner(b, Med, Med)
}

func BenchmarkInnerLgLg(b *testing.B) {
	benchmarkInner(b, Lg, Lg)
}

func BenchmarkInnerLgSm(b *testing.B) {
	benchmarkInner(b, Lg, Sm)
}
<|endoftext|>


<commit_before>package match

import (
	"testing"
)

func TestBTree(t *testing.T) {
	for id, test := range []struct {
		tree BTree
		str  string
		exp  bool
	}{
		{
			NewBTree(NewText("abc"), Super{}, Super{}),
			"abc",
			true,
		},
		{
			NewBTree(NewText("a"), Single{}, Single{}),
			"aaa",
			true,
		},
		{
			NewBTree(NewText("b"), Single{}, nil),
			"bbb",
			false,
		},
		{
			NewBTree(
				NewText("c"),
				NewBTree(
					Single{},
					Super{},
					nil,
				),
				nil,
			),
			"abc",
			true,
		},
	} {
		act := test.tree.Match(test.str)
		if act != test.exp {
			t.Errorf("#%d match %q error: act: %t; exp: %t", id, test.str, act, test.exp)
			continue
		}
	}
}

type fakeMatcher struct {
	len  int
	name string
}

func (f *fakeMatcher) Match(string) bool {
	return true
}
func (f *fakeMatcher) Index(s string) (int, []int) {
	return 0, []int{1}
}
func (f *fakeMatcher) Len() int {
	return f.len
}
func (f *fakeMatcher) String() string {
	return f.name
}

func BenchmarkMatchBTree(b *testing.B) {
	l := &fakeMatcher{4, "left_fake"}
	r := &fakeMatcher{4, "right_fake"}
	v := &fakeMatcher{2, "value_fake"}

	// must be <= len(l + r + v)
	fixture := "abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij"

	bt := NewBTree(v, l, r)

	b.SetParallelism(1)
	for i := 0; i < b.N; i++ {
		bt.Match(fixture)
	}
}
<commit_msg>test parallel<commit_after>package match

import (
	"testing"
)

func TestBTree(t *testing.T) {
	for id, test := range []struct {
		tree BTree
		str  string
		exp  bool
	}{
		{
			NewBTree(NewText("abc"), Super{}, Super{}),
			"abc",
			true,
		},
		{
			NewBTree(NewText("a"), Single{}, Single{}),
			"aaa",
			true,
		},
		{
			NewBTree(NewText("b"), Single{}, nil),
			"bbb",
			false,
		},
		{
			NewBTree(
				NewText("c"),
				NewBTree(
					Single{},
					Super{},
					nil,
				),
				nil,
			),
			"abc",
			true,
		},
	} {
		act := test.tree.Match(test.str)
		if act != test.exp {
			t.Errorf("#%d match %q error: act: %t; exp: %t", id, test.str, act, test.exp)
			continue
		}
	}
}

type fakeMatcher struct {
	len  int
	name string
}

func (f *fakeMatcher) Match(string) bool {
	return true
}
func (f *fakeMatcher) Index(s string) (int, []int) {
	return 0, []int{1}
}
func (f *fakeMatcher) Len() int {
	return f.len
}
func (f *fakeMatcher) String() string {
	return f.name
}

func BenchmarkMatchBTree(b *testing.B) {
	l := &fakeMatcher{4, "left_fake"}
	r := &fakeMatcher{4, "right_fake"}
	v := &fakeMatcher{2, "value_fake"}

	// must be <= len(l + r + v)
	fixture := "abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij"

	bt := NewBTree(v, l, r)

	b.RunParallel(func(pb *testing.PB) {
		for pb.Next() {
			bt.Match(fixture)
		}
	})
}
<|endoftext|>


<commit_before>/*
Copyright 2020 The Knative 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 config

import (
	"fmt"
	"math"
	"net"
	"os"
	"strconv"
	"time"

	v2 "github.com/envoyproxy/go-control-plane/envoy/api/v2"
	core "github.com/envoyproxy/go-control-plane/envoy/api/v2/core"
	endpoint "github.com/envoyproxy/go-control-plane/envoy/api/v2/endpoint"
	extAuthService "github.com/envoyproxy/go-control-plane/envoy/config/filter/http/ext_authz/v2"
	httpconnectionmanagerv2 "github.com/envoyproxy/go-control-plane/envoy/config/filter/network/http_connection_manager/v2"
	"github.com/envoyproxy/go-control-plane/pkg/wellknown"
	"github.com/golang/protobuf/ptypes"
	"github.com/kelseyhightower/envconfig"
)

const extAuthzClusterName = "extAuthz"

var ExternalAuthz = &ExternalAuthzConfig{
	Enabled: false,
}

type ExternalAuthzConfig struct {
	Enabled    bool
	Cluster    *v2.Cluster
	HTTPFilter *httpconnectionmanagerv2.HttpFilter
}

type config struct {
	Host             string `split_words:"true"`
	FailureModeAllow bool   `split_words:"true"`
	MaxRequestBytes  uint32 `split_words:"true" default:"8192"`
	Timeout          int    `split_words:"true" default:"2000"`
}

func init() {
	if host := os.Getenv("KOURIER_EXTAUTHZ_HOST"); host == "" {
		// No ExtAuthz setup.
		return
	}

	var env config
	envconfig.MustProcess("KOURIER_EXTAUTHZ", &env)

	host, portStr, err := net.SplitHostPort(env.Host)
	if err != nil {
		panic(err)
	}

	port, err := strconv.Atoi(portStr)
	if err != nil {
		panic(err)
	}

	if port > 65535 {
		// Bail out if we exceed the maximum port number.
		// See https://en.wikipedia.org/wiki/Registered_port.
		panic(fmt.Sprintf("port %d bigger than %d", port, math.MaxUint32))
	}

	timeout := time.Duration(env.Timeout) * time.Millisecond

	ExternalAuthz = &ExternalAuthzConfig{
		Enabled:    true,
		Cluster:    extAuthzCluster(host, uint32(port)),
		HTTPFilter: externalAuthZFilter(extAuthzClusterName, timeout, env.FailureModeAllow, env.MaxRequestBytes),
	}
}

func extAuthzCluster(host string, port uint32) *v2.Cluster {
	return &v2.Cluster{
		Name: extAuthzClusterName,
		ClusterDiscoveryType: &v2.Cluster_Type{
			Type: v2.Cluster_STRICT_DNS,
		},
		Http2ProtocolOptions: &core.Http2ProtocolOptions{},
		ConnectTimeout:       ptypes.DurationProto(5 * time.Second),
		LoadAssignment: &v2.ClusterLoadAssignment{
			ClusterName: extAuthzClusterName,
			Endpoints: []*endpoint.LocalityLbEndpoints{{
				LbEndpoints: []*endpoint.LbEndpoint{{
					HostIdentifier: &endpoint.LbEndpoint_Endpoint{
						Endpoint: &endpoint.Endpoint{
							Address: &core.Address{
								Address: &core.Address_SocketAddress{
									SocketAddress: &core.SocketAddress{
										Protocol: core.SocketAddress_TCP,
										Address:  host,
										PortSpecifier: &core.SocketAddress_PortValue{
											PortValue: port,
										},
										Ipv4Compat: true,
									},
								},
							},
						},
					},
				}},
			}},
		},
	}
}

func externalAuthZFilter(clusterName string, timeout time.Duration, failureModeAllow bool, maxRequestBytes uint32) *httpconnectionmanagerv2.HttpFilter {
	extAuthConfig := &extAuthService.ExtAuthz{
		Services: &extAuthService.ExtAuthz_GrpcService{
			GrpcService: &core.GrpcService{
				TargetSpecifier: &core.GrpcService_EnvoyGrpc_{
					EnvoyGrpc: &core.GrpcService_EnvoyGrpc{
						ClusterName: clusterName,
					},
				},
				Timeout: ptypes.DurationProto(timeout),
				InitialMetadata: []*core.HeaderValue{{
					Key:   "client",
					Value: "kourier",
				}},
			},
		},
		FailureModeAllow: failureModeAllow,
		WithRequestBody: &extAuthService.BufferSettings{
			MaxRequestBytes:     maxRequestBytes,
			AllowPartialMessage: true,
		},
		ClearRouteCache: false,
	}

	envoyConf, err := ptypes.MarshalAny(extAuthConfig)
	if err != nil {
		panic(err)
	}

	return &httpconnectionmanagerv2.HttpFilter{
		Name: wellknown.HTTPExternalAuthorization,
		ConfigType: &httpconnectionmanagerv2.HttpFilter_TypedConfig{
			TypedConfig: envoyConf,
		},
	}
}
<commit_msg>Fix max port comparison (#385)<commit_after>/*
Copyright 2020 The Knative 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 config

import (
	"fmt"
	"net"
	"os"
	"strconv"
	"time"

	v2 "github.com/envoyproxy/go-control-plane/envoy/api/v2"
	core "github.com/envoyproxy/go-control-plane/envoy/api/v2/core"
	endpoint "github.com/envoyproxy/go-control-plane/envoy/api/v2/endpoint"
	extAuthService "github.com/envoyproxy/go-control-plane/envoy/config/filter/http/ext_authz/v2"
	httpconnectionmanagerv2 "github.com/envoyproxy/go-control-plane/envoy/config/filter/network/http_connection_manager/v2"
	"github.com/envoyproxy/go-control-plane/pkg/wellknown"
	"github.com/golang/protobuf/ptypes"
	"github.com/kelseyhightower/envconfig"
)

const (
	extAuthzClusterName = "extAuthz"
	// See https://en.wikipedia.org/wiki/Registered_port.
	unixMaxPort = 65535
)

var ExternalAuthz = &ExternalAuthzConfig{
	Enabled: false,
}

type ExternalAuthzConfig struct {
	Enabled    bool
	Cluster    *v2.Cluster
	HTTPFilter *httpconnectionmanagerv2.HttpFilter
}

type config struct {
	Host             string `split_words:"true"`
	FailureModeAllow bool   `split_words:"true"`
	MaxRequestBytes  uint32 `split_words:"true" default:"8192"`
	Timeout          int    `split_words:"true" default:"2000"`
}

func init() {
	if host := os.Getenv("KOURIER_EXTAUTHZ_HOST"); host == "" {
		// No ExtAuthz setup.
		return
	}

	var env config
	envconfig.MustProcess("KOURIER_EXTAUTHZ", &env)

	host, portStr, err := net.SplitHostPort(env.Host)
	if err != nil {
		panic(err)
	}

	port, err := strconv.Atoi(portStr)
	if err != nil {
		panic(err)
	}

	if port > unixMaxPort {
		// Bail out if we exceed the maximum port number.
		panic(fmt.Sprintf("port %d bigger than %d", port, unixMaxPort))
	}

	timeout := time.Duration(env.Timeout) * time.Millisecond

	ExternalAuthz = &ExternalAuthzConfig{
		Enabled:    true,
		Cluster:    extAuthzCluster(host, uint32(port)),
		HTTPFilter: externalAuthZFilter(extAuthzClusterName, timeout, env.FailureModeAllow, env.MaxRequestBytes),
	}
}

func extAuthzCluster(host string, port uint32) *v2.Cluster {
	return &v2.Cluster{
		Name: extAuthzClusterName,
		ClusterDiscoveryType: &v2.Cluster_Type{
			Type: v2.Cluster_STRICT_DNS,
		},
		Http2ProtocolOptions: &core.Http2ProtocolOptions{},
		ConnectTimeout:       ptypes.DurationProto(5 * time.Second),
		LoadAssignment: &v2.ClusterLoadAssignment{
			ClusterName: extAuthzClusterName,
			Endpoints: []*endpoint.LocalityLbEndpoints{{
				LbEndpoints: []*endpoint.LbEndpoint{{
					HostIdentifier: &endpoint.LbEndpoint_Endpoint{
						Endpoint: &endpoint.Endpoint{
							Address: &core.Address{
								Address: &core.Address_SocketAddress{
									SocketAddress: &core.SocketAddress{
										Protocol: core.SocketAddress_TCP,
										Address:  host,
										PortSpecifier: &core.SocketAddress_PortValue{
											PortValue: port,
										},
										Ipv4Compat: true,
									},
								},
							},
						},
					},
				}},
			}},
		},
	}
}

func externalAuthZFilter(clusterName string, timeout time.Duration, failureModeAllow bool, maxRequestBytes uint32) *httpconnectionmanagerv2.HttpFilter {
	extAuthConfig := &extAuthService.ExtAuthz{
		Services: &extAuthService.ExtAuthz_GrpcService{
			GrpcService: &core.GrpcService{
				TargetSpecifier: &core.GrpcService_EnvoyGrpc_{
					EnvoyGrpc: &core.GrpcService_EnvoyGrpc{
						ClusterName: clusterName,
					},
				},
				Timeout: ptypes.DurationProto(timeout),
				InitialMetadata: []*core.HeaderValue{{
					Key:   "client",
					Value: "kourier",
				}},
			},
		},
		FailureModeAllow: failureModeAllow,
		WithRequestBody: &extAuthService.BufferSettings{
			MaxRequestBytes:     maxRequestBytes,
			AllowPartialMessage: true,
		},
		ClearRouteCache: false,
	}

	envoyConf, err := ptypes.MarshalAny(extAuthConfig)
	if err != nil {
		panic(err)
	}

	return &httpconnectionmanagerv2.HttpFilter{
		Name: wellknown.HTTPExternalAuthorization,
		ConfigType: &httpconnectionmanagerv2.HttpFilter_TypedConfig{
			TypedConfig: envoyConf,
		},
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2017 The Kubernetes 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 csicommon

import (
	"fmt"
	"regexp"
	"strings"

	"github.com/container-storage-interface/spec/lib/go/csi"
	"github.com/golang/glog"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
)

func ParseEndpoint(ep string) (string, string, error) {
	if strings.HasPrefix(strings.ToLower(ep), "unix://") || strings.HasPrefix(strings.ToLower(ep), "tcp://") {
		s := strings.SplitN(ep, "://", 2)
		if s[1] != "" {
			return s[0], s[1], nil
		}
	}
	return "", "", fmt.Errorf("Invalid endpoint: %v", ep)
}

func NewVolumeCapabilityAccessMode(mode csi.VolumeCapability_AccessMode_Mode) *csi.VolumeCapability_AccessMode {
	return &csi.VolumeCapability_AccessMode{Mode: mode}
}

func NewDefaultNodeServer(d *CSIDriver) *DefaultNodeServer {
	return &DefaultNodeServer{
		Driver: d,
	}
}

func NewDefaultIdentityServer(d *CSIDriver) *DefaultIdentityServer {
	return &DefaultIdentityServer{
		Driver: d,
	}
}

func NewDefaultControllerServer(d *CSIDriver) *DefaultControllerServer {
	return &DefaultControllerServer{
		Driver: d,
	}
}

func NewControllerServiceCapability(cap csi.ControllerServiceCapability_RPC_Type) *csi.ControllerServiceCapability {
	return &csi.ControllerServiceCapability{
		Type: &csi.ControllerServiceCapability_Rpc{
			Rpc: &csi.ControllerServiceCapability_RPC{
				Type: cap,
			},
		},
	}
}

func RunNodePublishServer(endpoint string, d *CSIDriver, ns csi.NodeServer) {
	ids := NewDefaultIdentityServer(d)

	s := NewNonBlockingGRPCServer()
	s.Start(endpoint, ids, nil, ns)
	s.Wait()
}

func RunControllerPublishServer(endpoint string, d *CSIDriver, cs csi.ControllerServer) {
	ids := NewDefaultIdentityServer(d)

	s := NewNonBlockingGRPCServer()
	s.Start(endpoint, ids, cs, nil)
	s.Wait()
}

func RunControllerandNodePublishServer(endpoint string, d *CSIDriver, cs csi.ControllerServer, ns csi.NodeServer) {
	ids := NewDefaultIdentityServer(d)

	s := NewNonBlockingGRPCServer()
	s.Start(endpoint, ids, cs, ns)
	s.Wait()
}

func logGRPC(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
	glog.V(3).Infof("GRPC call: %s", info.FullMethod)
	logRedactedRequest(req)
	resp, err := handler(ctx, req)
	if err != nil {
		glog.Errorf("GRPC error: %v", err)
	} else {
		glog.V(5).Infof("GRPC response: %+v", resp)
	}
	return resp, err
}

func logRedactedRequest(req interface{}) {
	re, _ := regexp.Compile(`^(\\S{4})(\\S|\\s)*(\\S{4})$`)

	r, ok := req.(*csi.NodePublishVolumeRequest)
	if !ok {
		glog.V(5).Infof("GRPC request: %+v", req)
		return
	}

	req1 := *r
	redactedSecrets := make(map[string]string)

	secrets := req1.GetSecrets()
	for k, v := range secrets {
		switch k {
		case "clientid", "clientsecret":
			redactedSecrets[k] = re.ReplaceAllString(v, "$1##### REDACTED #####$3")
		default:
			redactedSecrets[k] = v
		}
	}
	req1.Secrets = redactedSecrets
	glog.V(5).Infof("GRPC request: %+v", req1)
}
<commit_msg>update regex<commit_after>/*
Copyright 2017 The Kubernetes 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 csicommon

import (
	"fmt"
	"regexp"
	"strings"

	"github.com/container-storage-interface/spec/lib/go/csi"
	"github.com/golang/glog"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
)

func ParseEndpoint(ep string) (string, string, error) {
	if strings.HasPrefix(strings.ToLower(ep), "unix://") || strings.HasPrefix(strings.ToLower(ep), "tcp://") {
		s := strings.SplitN(ep, "://", 2)
		if s[1] != "" {
			return s[0], s[1], nil
		}
	}
	return "", "", fmt.Errorf("Invalid endpoint: %v", ep)
}

func NewVolumeCapabilityAccessMode(mode csi.VolumeCapability_AccessMode_Mode) *csi.VolumeCapability_AccessMode {
	return &csi.VolumeCapability_AccessMode{Mode: mode}
}

func NewDefaultNodeServer(d *CSIDriver) *DefaultNodeServer {
	return &DefaultNodeServer{
		Driver: d,
	}
}

func NewDefaultIdentityServer(d *CSIDriver) *DefaultIdentityServer {
	return &DefaultIdentityServer{
		Driver: d,
	}
}

func NewDefaultControllerServer(d *CSIDriver) *DefaultControllerServer {
	return &DefaultControllerServer{
		Driver: d,
	}
}

func NewControllerServiceCapability(cap csi.ControllerServiceCapability_RPC_Type) *csi.ControllerServiceCapability {
	return &csi.ControllerServiceCapability{
		Type: &csi.ControllerServiceCapability_Rpc{
			Rpc: &csi.ControllerServiceCapability_RPC{
				Type: cap,
			},
		},
	}
}

func RunNodePublishServer(endpoint string, d *CSIDriver, ns csi.NodeServer) {
	ids := NewDefaultIdentityServer(d)

	s := NewNonBlockingGRPCServer()
	s.Start(endpoint, ids, nil, ns)
	s.Wait()
}

func RunControllerPublishServer(endpoint string, d *CSIDriver, cs csi.ControllerServer) {
	ids := NewDefaultIdentityServer(d)

	s := NewNonBlockingGRPCServer()
	s.Start(endpoint, ids, cs, nil)
	s.Wait()
}

func RunControllerandNodePublishServer(endpoint string, d *CSIDriver, cs csi.ControllerServer, ns csi.NodeServer) {
	ids := NewDefaultIdentityServer(d)

	s := NewNonBlockingGRPCServer()
	s.Start(endpoint, ids, cs, ns)
	s.Wait()
}

func logGRPC(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
	glog.V(3).Infof("GRPC call: %s", info.FullMethod)
	logRedactedRequest(req)
	resp, err := handler(ctx, req)
	if err != nil {
		glog.Errorf("GRPC error: %v", err)
	} else {
		glog.V(5).Infof("GRPC response: %+v", resp)
	}
	return resp, err
}

func logRedactedRequest(req interface{}) {
	re, _ := regexp.Compile(`^(\S{4})(\S|\s)*(\S{4})$`)

	r, ok := req.(*csi.NodePublishVolumeRequest)
	if !ok {
		glog.V(5).Infof("GRPC request: %+v", req)
		return
	}

	req1 := *r
	redactedSecrets := make(map[string]string)

	secrets := req1.GetSecrets()
	for k, v := range secrets {
		switch k {
		case "clientid", "clientsecret":
			redactedSecrets[k] = re.ReplaceAllString(v, "$1##### REDACTED #####$3")
		default:
			redactedSecrets[k] = v
		}
	}
	req1.Secrets = redactedSecrets
	glog.V(5).Infof("GRPC request: %+v", req1)
}
<|endoftext|>


<commit_before>package acme

import (
	"context"
	"fmt"
	nethttp "net/http"

	"github.com/golang/glog"
	"golang.org/x/crypto/acme"
	corev1 "k8s.io/api/core/v1"
	"k8s.io/client-go/kubernetes"
	corelisters "k8s.io/client-go/listers/core/v1"
	"k8s.io/client-go/tools/record"

	"github.com/jetstack/cert-manager/pkg/apis/certmanager/v1alpha1"
	clientset "github.com/jetstack/cert-manager/pkg/client/clientset/versioned"
	"github.com/jetstack/cert-manager/pkg/issuer"
	"github.com/jetstack/cert-manager/pkg/issuer/acme/dns"
	"github.com/jetstack/cert-manager/pkg/issuer/acme/http"
	"github.com/jetstack/cert-manager/pkg/util"
	"github.com/jetstack/cert-manager/pkg/util/kube"
)

// Acme is an issuer for an ACME server. It can be used to register and obtain
// certificates from any ACME server. It supports DNS01 and HTTP01 challenge
// mechanisms.
type Acme struct {
	issuer v1alpha1.GenericIssuer

	client   kubernetes.Interface
	cmClient clientset.Interface
	recorder record.EventRecorder

	secretsLister corelisters.SecretLister

	dnsSolver  solver
	httpSolver solver

	// issuerResourcesNamespace is a namespace to store resources in. This is
	// here so we can easily support ClusterIssuers with the same codepath. By
	// setting this field to either the namespace of the Issuer, or the
	// clusterResourceNamespace specified on the CLI, we can easily continue
	// to work with supplemental (e.g. secrets) resources without significant
	// refactoring.
	issuerResourcesNamespace string

	// ambientCredentials determines whether a given acme solver may draw
	// credentials ambiently, e.g. from metadata services or environment
	// variables.
	// Currently, only AWS ambient credential control is implemented.
	ambientCredentials bool
}

// solver solves ACME challenges by presenting the given token and key in an
// appropriate way given the config in the Issuer and Certificate.
type solver interface {
	Present(ctx context.Context, crt *v1alpha1.Certificate, domain, token, key string) error
	Wait(ctx context.Context, crt *v1alpha1.Certificate, domain, token, key string) error
	CleanUp(ctx context.Context, crt *v1alpha1.Certificate, domain, token, key string) error
}

// New returns a new ACME issuer interface for the given issuer.
func New(issuer v1alpha1.GenericIssuer,
	client kubernetes.Interface,
	cmClient clientset.Interface,
	recorder record.EventRecorder,
	resourceNamespace string,
	acmeHTTP01SolverImage string,
	secretsLister corelisters.SecretLister,
	ambientCreds bool) (issuer.Interface, error) {
	if issuer.GetSpec().ACME == nil {
		return nil, fmt.Errorf("acme config may not be empty")
	}

	if issuer.GetSpec().ACME.Server == "" ||
		issuer.GetSpec().ACME.PrivateKey.Name == "" ||
		issuer.GetSpec().ACME.Email == "" {
		return nil, fmt.Errorf("acme server, private key and email are required fields")
	}

	if resourceNamespace == "" {
		return nil, fmt.Errorf("resource namespace cannot be empty")
	}

	return &Acme{
		issuer:                   issuer,
		client:                   client,
		cmClient:                 cmClient,
		recorder:                 recorder,
		secretsLister:            secretsLister,
		dnsSolver:                dns.NewSolver(issuer, client, secretsLister, resourceNamespace, ambientCreds),
		httpSolver:               http.NewSolver(issuer, client, secretsLister, acmeHTTP01SolverImage),
		issuerResourcesNamespace: resourceNamespace,
	}, nil
}

func (a *Acme) acmeClient() (*acme.Client, error) {
	secretName, secretKey := a.acmeAccountPrivateKeyMeta()
	glog.V(4).Infof("getting private key (%s->%s) for acme issuer %s/%s", secretName, secretKey, a.issuerResourcesNamespace, a.issuer.GetObjectMeta().Name)
	accountPrivKey, err := kube.SecretTLSKeyRef(a.secretsLister, a.issuerResourcesNamespace, secretName, secretKey)
	if err != nil {
		return nil, err
	}

	cl := &acme.Client{
		Key:          accountPrivKey,
		DirectoryURL: a.issuer.GetSpec().ACME.Server,
		HTTPClient: &nethttp.Client{
			// Stopgap user-agent roundtripper until the upstream 'crypto/acme'
			// provides a better method for setting user-agent.
			Transport: util.UserAgentRoundTripper(nethttp.DefaultTransport),
		},
	}
	return cl, nil
}

// acmeAccountPrivateKeyMeta returns the name and the secret 'key' that stores
// the ACME account private key.
func (a *Acme) acmeAccountPrivateKeyMeta() (name string, key string) {
	secretName := a.issuer.GetSpec().ACME.PrivateKey.Name
	secretKey := a.issuer.GetSpec().ACME.PrivateKey.Key
	if len(secretKey) == 0 {
		secretKey = corev1.TLSPrivateKeyKey
	}
	return secretName, secretKey
}

func (a *Acme) solverFor(challengeType string) (solver, error) {
	switch challengeType {
	case "http-01":
		return a.httpSolver, nil
	case "dns-01":
		return a.dnsSolver, nil
	}
	return nil, fmt.Errorf("no solver implemented")
}

// Register this Issuer with the issuer factory
func init() {
	issuer.Register(issuer.IssuerACME, func(i v1alpha1.GenericIssuer, ctx *issuer.Context) (issuer.Interface, error) {
		issuerResourcesNamespace := i.GetObjectMeta().Namespace
		if issuerResourcesNamespace == "" {
			issuerResourcesNamespace = ctx.ClusterResourceNamespace
		}

		ambientCreds := false
		switch i.(type) {
		case *v1alpha1.ClusterIssuer:
			ambientCreds = ctx.ClusterIssuerAmbientCredentials
		case *v1alpha1.Issuer:
			ambientCreds = ctx.IssuerAmbientCredentials
		default:
			return nil, fmt.Errorf("issuer was neither an 'Issuer' nor 'ClusterIssuer'; was %T", i)
		}

		return New(
			i,
			ctx.Client,
			ctx.CMClient,
			ctx.Recorder,
			issuerResourcesNamespace,
			ctx.ACMEHTTP01SolverImage,
			ctx.KubeSharedInformerFactory.Core().V1().Secrets().Lister(),
			ambientCreds,
		)
	})
}
<commit_msg>issuer/acme: add a timeout to the http client<commit_after>package acme

import (
	"context"
	"fmt"
	nethttp "net/http"
	"time"

	"github.com/golang/glog"
	"golang.org/x/crypto/acme"
	corev1 "k8s.io/api/core/v1"
	"k8s.io/client-go/kubernetes"
	corelisters "k8s.io/client-go/listers/core/v1"
	"k8s.io/client-go/tools/record"

	"github.com/jetstack/cert-manager/pkg/apis/certmanager/v1alpha1"
	clientset "github.com/jetstack/cert-manager/pkg/client/clientset/versioned"
	"github.com/jetstack/cert-manager/pkg/issuer"
	"github.com/jetstack/cert-manager/pkg/issuer/acme/dns"
	"github.com/jetstack/cert-manager/pkg/issuer/acme/http"
	"github.com/jetstack/cert-manager/pkg/util"
	"github.com/jetstack/cert-manager/pkg/util/kube"
)

// Acme is an issuer for an ACME server. It can be used to register and obtain
// certificates from any ACME server. It supports DNS01 and HTTP01 challenge
// mechanisms.
type Acme struct {
	issuer v1alpha1.GenericIssuer

	client   kubernetes.Interface
	cmClient clientset.Interface
	recorder record.EventRecorder

	secretsLister corelisters.SecretLister

	dnsSolver  solver
	httpSolver solver

	// issuerResourcesNamespace is a namespace to store resources in. This is
	// here so we can easily support ClusterIssuers with the same codepath. By
	// setting this field to either the namespace of the Issuer, or the
	// clusterResourceNamespace specified on the CLI, we can easily continue
	// to work with supplemental (e.g. secrets) resources without significant
	// refactoring.
	issuerResourcesNamespace string

	// ambientCredentials determines whether a given acme solver may draw
	// credentials ambiently, e.g. from metadata services or environment
	// variables.
	// Currently, only AWS ambient credential control is implemented.
	ambientCredentials bool
}

// solver solves ACME challenges by presenting the given token and key in an
// appropriate way given the config in the Issuer and Certificate.
type solver interface {
	Present(ctx context.Context, crt *v1alpha1.Certificate, domain, token, key string) error
	Wait(ctx context.Context, crt *v1alpha1.Certificate, domain, token, key string) error
	CleanUp(ctx context.Context, crt *v1alpha1.Certificate, domain, token, key string) error
}

// New returns a new ACME issuer interface for the given issuer.
func New(issuer v1alpha1.GenericIssuer,
	client kubernetes.Interface,
	cmClient clientset.Interface,
	recorder record.EventRecorder,
	resourceNamespace string,
	acmeHTTP01SolverImage string,
	secretsLister corelisters.SecretLister,
	ambientCreds bool) (issuer.Interface, error) {
	if issuer.GetSpec().ACME == nil {
		return nil, fmt.Errorf("acme config may not be empty")
	}

	if issuer.GetSpec().ACME.Server == "" ||
		issuer.GetSpec().ACME.PrivateKey.Name == "" ||
		issuer.GetSpec().ACME.Email == "" {
		return nil, fmt.Errorf("acme server, private key and email are required fields")
	}

	if resourceNamespace == "" {
		return nil, fmt.Errorf("resource namespace cannot be empty")
	}

	return &Acme{
		issuer:                   issuer,
		client:                   client,
		cmClient:                 cmClient,
		recorder:                 recorder,
		secretsLister:            secretsLister,
		dnsSolver:                dns.NewSolver(issuer, client, secretsLister, resourceNamespace, ambientCreds),
		httpSolver:               http.NewSolver(issuer, client, secretsLister, acmeHTTP01SolverImage),
		issuerResourcesNamespace: resourceNamespace,
	}, nil
}

func (a *Acme) acmeClient() (*acme.Client, error) {
	secretName, secretKey := a.acmeAccountPrivateKeyMeta()
	glog.V(4).Infof("getting private key (%s->%s) for acme issuer %s/%s", secretName, secretKey, a.issuerResourcesNamespace, a.issuer.GetObjectMeta().Name)
	accountPrivKey, err := kube.SecretTLSKeyRef(a.secretsLister, a.issuerResourcesNamespace, secretName, secretKey)
	if err != nil {
		return nil, err
	}

	cl := &acme.Client{
		Key:          accountPrivKey,
		DirectoryURL: a.issuer.GetSpec().ACME.Server,
		HTTPClient: &nethttp.Client{
			// Stopgap user-agent roundtripper until the upstream 'crypto/acme'
			// provides a better method for setting user-agent.
			Transport: util.UserAgentRoundTripper(nethttp.DefaultTransport),
			Timeout:   30 * time.Second,
		},
	}
	return cl, nil
}

// acmeAccountPrivateKeyMeta returns the name and the secret 'key' that stores
// the ACME account private key.
func (a *Acme) acmeAccountPrivateKeyMeta() (name string, key string) {
	secretName := a.issuer.GetSpec().ACME.PrivateKey.Name
	secretKey := a.issuer.GetSpec().ACME.PrivateKey.Key
	if len(secretKey) == 0 {
		secretKey = corev1.TLSPrivateKeyKey
	}
	return secretName, secretKey
}

func (a *Acme) solverFor(challengeType string) (solver, error) {
	switch challengeType {
	case "http-01":
		return a.httpSolver, nil
	case "dns-01":
		return a.dnsSolver, nil
	}
	return nil, fmt.Errorf("no solver implemented")
}

// Register this Issuer with the issuer factory
func init() {
	issuer.Register(issuer.IssuerACME, func(i v1alpha1.GenericIssuer, ctx *issuer.Context) (issuer.Interface, error) {
		issuerResourcesNamespace := i.GetObjectMeta().Namespace
		if issuerResourcesNamespace == "" {
			issuerResourcesNamespace = ctx.ClusterResourceNamespace
		}

		ambientCreds := false
		switch i.(type) {
		case *v1alpha1.ClusterIssuer:
			ambientCreds = ctx.ClusterIssuerAmbientCredentials
		case *v1alpha1.Issuer:
			ambientCreds = ctx.IssuerAmbientCredentials
		default:
			return nil, fmt.Errorf("issuer was neither an 'Issuer' nor 'ClusterIssuer'; was %T", i)
		}

		return New(
			i,
			ctx.Client,
			ctx.CMClient,
			ctx.Recorder,
			issuerResourcesNamespace,
			ctx.ACMEHTTP01SolverImage,
			ctx.KubeSharedInformerFactory.Core().V1().Secrets().Lister(),
			ambientCreds,
		)
	})
}
<|endoftext|>


<commit_before>package pubsub

import (
	"sync"
	"time"
)

// NewPublisher creates a new pub/sub publisher to broadcast messages.
// The duration is used as the send timeout as to not block the publisher publishing
// messages to other clients if one client is slow or unresponsive.
// The buffer is used when creating new channels for subscribers.
func NewPublisher(publishTimeout time.Duration, buffer int) *Publisher {
	return &Publisher{
		buffer:      buffer,
		timeout:     publishTimeout,
		subscribers: make(map[subscriber]struct{}),
	}
}

type subscriber chan interface{}

type Publisher struct {
	m           sync.RWMutex
	buffer      int
	timeout     time.Duration
	subscribers map[subscriber]struct{}
}

// Len returns the number of subscribers for the publisher
func (p *Publisher) Len() int {
	p.m.RLock()
	i := len(p.subscribers)
	p.m.RUnlock()
	return i
}

// Subscribe adds a new subscriber to the publisher returning the channel.
func (p *Publisher) Subscribe() chan interface{} {
	ch := make(chan interface{}, p.buffer)
	p.m.Lock()
	p.subscribers[ch] = struct{}{}
	p.m.Unlock()
	return ch
}

// Evict removes the specified subscriber from receiving any more messages.
func (p *Publisher) Evict(sub chan interface{}) {
	p.m.Lock()
	delete(p.subscribers, sub)
	close(sub)
	p.m.Unlock()
}

// Publish sends the data in v to all subscribers currently registered with the publisher.
func (p *Publisher) Publish(v interface{}) {
	p.m.RLock()
	for sub := range p.subscribers {
		// send under a select as to not block if the receiver is unavailable
		select {
		case sub <- v:
		case <-time.After(p.timeout):
		}
	}
	p.m.RUnlock()
}

// Close closes the channels to all subscribers registered with the publisher.
func (p *Publisher) Close() {
	p.m.Lock()
	for sub := range p.subscribers {
		close(sub)
	}
	p.m.Unlock()
}
<commit_msg>Fix send on closed channel bug<commit_after>package pubsub

import (
	"sync"
	"time"
)

// NewPublisher creates a new pub/sub publisher to broadcast messages.
// The duration is used as the send timeout as to not block the publisher publishing
// messages to other clients if one client is slow or unresponsive.
// The buffer is used when creating new channels for subscribers.
func NewPublisher(publishTimeout time.Duration, buffer int) *Publisher {
	return &Publisher{
		buffer:      buffer,
		timeout:     publishTimeout,
		subscribers: make(map[subscriber]struct{}),
	}
}

type subscriber chan interface{}

type Publisher struct {
	m           sync.RWMutex
	buffer      int
	timeout     time.Duration
	subscribers map[subscriber]struct{}
}

// Len returns the number of subscribers for the publisher
func (p *Publisher) Len() int {
	p.m.RLock()
	i := len(p.subscribers)
	p.m.RUnlock()
	return i
}

// Subscribe adds a new subscriber to the publisher returning the channel.
func (p *Publisher) Subscribe() chan interface{} {
	ch := make(chan interface{}, p.buffer)
	p.m.Lock()
	p.subscribers[ch] = struct{}{}
	p.m.Unlock()
	return ch
}

// Evict removes the specified subscriber from receiving any more messages.
func (p *Publisher) Evict(sub chan interface{}) {
	p.m.Lock()
	delete(p.subscribers, sub)
	close(sub)
	p.m.Unlock()
}

// Publish sends the data in v to all subscribers currently registered with the publisher.
func (p *Publisher) Publish(v interface{}) {
	p.m.RLock()
	for sub := range p.subscribers {
		// send under a select as to not block if the receiver is unavailable
		select {
		case sub <- v:
		case <-time.After(p.timeout):
		}
	}
	p.m.RUnlock()
}

// Close closes the channels to all subscribers registered with the publisher.
func (p *Publisher) Close() {
	p.m.Lock()
	for sub := range p.subscribers {
		delete(p.subscribers, sub)
		close(sub)
	}
	p.m.Unlock()
}
<|endoftext|>


<commit_before>package mssql

import (
	"context"
	"encoding/json"
	"fmt"
	"net/url"
	"reflect"
	"regexp"
	"strconv"
	"strings"

	mssql "github.com/denisenkom/go-mssqldb"
	"github.com/grafana/grafana-plugin-sdk-go/backend"
	"github.com/grafana/grafana-plugin-sdk-go/backend/datasource"
	"github.com/grafana/grafana-plugin-sdk-go/backend/instancemgmt"
	"github.com/grafana/grafana-plugin-sdk-go/data"
	"github.com/grafana/grafana-plugin-sdk-go/data/sqlutil"
	"github.com/grafana/grafana/pkg/infra/log"
	"github.com/grafana/grafana/pkg/setting"
	"github.com/grafana/grafana/pkg/tsdb/sqleng"
	"github.com/grafana/grafana/pkg/util"
)

var logger = log.New("tsdb.mssql")

type Service struct {
	im instancemgmt.InstanceManager
}

func ProvideService(cfg *setting.Cfg) *Service {
	return &Service{
		im: datasource.NewInstanceManager(newInstanceSettings(cfg)),
	}
}

func (s *Service) getDataSourceHandler(pluginCtx backend.PluginContext) (*sqleng.DataSourceHandler, error) {
	i, err := s.im.Get(pluginCtx)
	if err != nil {
		return nil, err
	}
	instance := i.(*sqleng.DataSourceHandler)
	return instance, nil
}

func (s *Service) QueryData(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
	dsHandler, err := s.getDataSourceHandler(req.PluginContext)
	if err != nil {
		return nil, err
	}
	return dsHandler.QueryData(ctx, req)
}

func newInstanceSettings(cfg *setting.Cfg) datasource.InstanceFactoryFunc {
	return func(settings backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
		jsonData := sqleng.JsonData{
			MaxOpenConns:    0,
			MaxIdleConns:    2,
			ConnMaxLifetime: 14400,
			Encrypt:         "false",
		}

		err := json.Unmarshal(settings.JSONData, &jsonData)
		if err != nil {
			return nil, fmt.Errorf("error reading settings: %w", err)
		}
		dsInfo := sqleng.DataSourceInfo{
			JsonData:                jsonData,
			URL:                     settings.URL,
			User:                    settings.User,
			Database:                settings.Database,
			ID:                      settings.ID,
			Updated:                 settings.Updated,
			UID:                     settings.UID,
			DecryptedSecureJSONData: settings.DecryptedSecureJSONData,
		}
		cnnstr, err := generateConnectionString(dsInfo)
		if err != nil {
			return nil, err
		}

		if cfg.Env == setting.Dev {
			logger.Debug("getEngine", "connection", cnnstr)
		}
		config := sqleng.DataPluginConfiguration{
			DriverName:        "mssql",
			ConnectionString:  cnnstr,
			DSInfo:            dsInfo,
			MetricColumnTypes: []string{"VARCHAR", "CHAR", "NVARCHAR", "NCHAR"},
			RowLimit:          cfg.DataProxyRowLimit,
		}

		queryResultTransformer := mssqlQueryResultTransformer{
			log: logger,
		}

		return sqleng.NewQueryDataHandler(config, &queryResultTransformer, newMssqlMacroEngine(), logger)
	}
}

// ParseURL tries to parse an MSSQL URL string into a URL object.
func ParseURL(u string) (*url.URL, error) {
	logger.Debug("Parsing MSSQL URL", "url", u)

	// Recognize ODBC connection strings like host\instance:1234
	reODBC := regexp.MustCompile(`^[^\\:]+(?:\\[^:]+)?(?::\d+)?(?:;.+)?$`)
	var host string
	switch {
	case reODBC.MatchString(u):
		logger.Debug("Recognized as ODBC URL format", "url", u)
		host = u
	default:
		logger.Debug("Couldn't recognize as valid MSSQL URL", "url", u)
		return nil, fmt.Errorf("unrecognized MSSQL URL format: %q", u)
	}
	return &url.URL{
		Scheme: "sqlserver",
		Host:   host,
	}, nil
}

func generateConnectionString(dsInfo sqleng.DataSourceInfo) (string, error) {
	const dfltPort = "0"
	var addr util.NetworkAddress
	if dsInfo.URL != "" {
		u, err := ParseURL(dsInfo.URL)
		if err != nil {
			return "", err
		}
		addr, err = util.SplitHostPortDefault(u.Host, "localhost", dfltPort)
		if err != nil {
			return "", err
		}
	} else {
		addr = util.NetworkAddress{
			Host: "localhost",
			Port: dfltPort,
		}
	}

	args := []interface{}{
		"url", dsInfo.URL, "host", addr.Host,
	}
	if addr.Port != "0" {
		args = append(args, "port", addr.Port)
	}
	logger.Debug("Generating connection string", args...)

	encrypt := dsInfo.JsonData.Encrypt
	tlsSkipVerify := dsInfo.JsonData.TlsSkipVerify
	hostNameInCertificate := dsInfo.JsonData.Servername
	certificate := dsInfo.JsonData.RootCertFile
	connStr := fmt.Sprintf("server=%s;database=%s;user id=%s;password=%s;",
		addr.Host,
		dsInfo.Database,
		dsInfo.User,
		dsInfo.DecryptedSecureJSONData["password"],
	)
	// Port number 0 means to determine the port automatically, so we can let the driver choose
	if addr.Port != "0" {
		connStr += fmt.Sprintf("port=%s;", addr.Port)
	}
	if encrypt == "true" {
		connStr += fmt.Sprintf("encrypt=%s;TrustServerCertificate=%t;", encrypt, tlsSkipVerify)
		if hostNameInCertificate != "" {
			connStr += fmt.Sprintf("hostNameInCertificate=%s;", hostNameInCertificate)
		}

		if certificate != "" {
			connStr += fmt.Sprintf("certificate=%s;", certificate)
		}
	}
	return connStr, nil
}

type mssqlQueryResultTransformer struct {
	log log.Logger
}

func (t *mssqlQueryResultTransformer) TransformQueryError(err error) error {
	// go-mssql overrides source error, so we currently match on string
	// ref https://github.com/denisenkom/go-mssqldb/blob/045585d74f9069afe2e115b6235eb043c8047043/tds.go#L904
	if strings.HasPrefix(strings.ToLower(err.Error()), "unable to open tcp connection with host") {
		t.log.Error("query error", "err", err)
		return sqleng.ErrConnectionFailed
	}

	return err
}

func (t *mssqlQueryResultTransformer) GetConverterList() []sqlutil.StringConverter {
	return []sqlutil.StringConverter{
		{
			Name:           "handle MONEY",
			InputScanKind:  reflect.Slice,
			InputTypeName:  "MONEY",
			ConversionFunc: func(in *string) (*string, error) { return in, nil },
			Replacer: &sqlutil.StringFieldReplacer{
				OutputFieldType: data.FieldTypeNullableFloat64,
				ReplaceFunc: func(in *string) (interface{}, error) {
					if in == nil {
						return nil, nil
					}
					v, err := strconv.ParseFloat(*in, 64)
					if err != nil {
						return nil, err
					}
					return &v, nil
				},
			},
		},
		{
			Name:           "handle SMALLMONEY",
			InputScanKind:  reflect.Slice,
			InputTypeName:  "SMALLMONEY",
			ConversionFunc: func(in *string) (*string, error) { return in, nil },
			Replacer: &sqlutil.StringFieldReplacer{
				OutputFieldType: data.FieldTypeNullableFloat64,
				ReplaceFunc: func(in *string) (interface{}, error) {
					if in == nil {
						return nil, nil
					}
					v, err := strconv.ParseFloat(*in, 64)
					if err != nil {
						return nil, err
					}
					return &v, nil
				},
			},
		},
		{
			Name:           "handle DECIMAL",
			InputScanKind:  reflect.Slice,
			InputTypeName:  "DECIMAL",
			ConversionFunc: func(in *string) (*string, error) { return in, nil },
			Replacer: &sqlutil.StringFieldReplacer{
				OutputFieldType: data.FieldTypeNullableFloat64,
				ReplaceFunc: func(in *string) (interface{}, error) {
					if in == nil {
						return nil, nil
					}
					v, err := strconv.ParseFloat(*in, 64)
					if err != nil {
						return nil, err
					}
					return &v, nil
				},
			},
		},
		{
			Name:           "handle UNIQUEIDENTIFIER",
			InputScanKind:  reflect.Slice,
			InputTypeName:  "UNIQUEIDENTIFIER",
			ConversionFunc: func(in *string) (*string, error) { return in, nil },
			Replacer: &sqlutil.StringFieldReplacer{
				OutputFieldType: data.FieldTypeNullableString,
				ReplaceFunc: func(in *string) (interface{}, error) {
					if in == nil {
						return nil, nil
					}
					uuid := &mssql.UniqueIdentifier{}
					if err := uuid.Scan([]byte(*in)); err != nil {
						return nil, err
					}
					v := uuid.String()
					return &v, nil
				},
			},
		},
	}
}
<commit_msg>mssql: explicit disable encryption when its disabled (#46546)<commit_after>package mssql

import (
	"context"
	"encoding/json"
	"fmt"
	"net/url"
	"reflect"
	"regexp"
	"strconv"
	"strings"

	mssql "github.com/denisenkom/go-mssqldb"
	"github.com/grafana/grafana-plugin-sdk-go/backend"
	"github.com/grafana/grafana-plugin-sdk-go/backend/datasource"
	"github.com/grafana/grafana-plugin-sdk-go/backend/instancemgmt"
	"github.com/grafana/grafana-plugin-sdk-go/data"
	"github.com/grafana/grafana-plugin-sdk-go/data/sqlutil"
	"github.com/grafana/grafana/pkg/infra/log"
	"github.com/grafana/grafana/pkg/setting"
	"github.com/grafana/grafana/pkg/tsdb/sqleng"
	"github.com/grafana/grafana/pkg/util"
)

var logger = log.New("tsdb.mssql")

type Service struct {
	im instancemgmt.InstanceManager
}

func ProvideService(cfg *setting.Cfg) *Service {
	return &Service{
		im: datasource.NewInstanceManager(newInstanceSettings(cfg)),
	}
}

func (s *Service) getDataSourceHandler(pluginCtx backend.PluginContext) (*sqleng.DataSourceHandler, error) {
	i, err := s.im.Get(pluginCtx)
	if err != nil {
		return nil, err
	}
	instance := i.(*sqleng.DataSourceHandler)
	return instance, nil
}

func (s *Service) QueryData(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
	dsHandler, err := s.getDataSourceHandler(req.PluginContext)
	if err != nil {
		return nil, err
	}
	return dsHandler.QueryData(ctx, req)
}

func newInstanceSettings(cfg *setting.Cfg) datasource.InstanceFactoryFunc {
	return func(settings backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
		jsonData := sqleng.JsonData{
			MaxOpenConns:    0,
			MaxIdleConns:    2,
			ConnMaxLifetime: 14400,
			Encrypt:         "false",
		}

		err := json.Unmarshal(settings.JSONData, &jsonData)
		if err != nil {
			return nil, fmt.Errorf("error reading settings: %w", err)
		}
		dsInfo := sqleng.DataSourceInfo{
			JsonData:                jsonData,
			URL:                     settings.URL,
			User:                    settings.User,
			Database:                settings.Database,
			ID:                      settings.ID,
			Updated:                 settings.Updated,
			UID:                     settings.UID,
			DecryptedSecureJSONData: settings.DecryptedSecureJSONData,
		}
		cnnstr, err := generateConnectionString(dsInfo)
		if err != nil {
			return nil, err
		}

		if cfg.Env == setting.Dev {
			logger.Debug("getEngine", "connection", cnnstr)
		}
		config := sqleng.DataPluginConfiguration{
			DriverName:        "mssql",
			ConnectionString:  cnnstr,
			DSInfo:            dsInfo,
			MetricColumnTypes: []string{"VARCHAR", "CHAR", "NVARCHAR", "NCHAR"},
			RowLimit:          cfg.DataProxyRowLimit,
		}

		queryResultTransformer := mssqlQueryResultTransformer{
			log: logger,
		}

		return sqleng.NewQueryDataHandler(config, &queryResultTransformer, newMssqlMacroEngine(), logger)
	}
}

// ParseURL tries to parse an MSSQL URL string into a URL object.
func ParseURL(u string) (*url.URL, error) {
	logger.Debug("Parsing MSSQL URL", "url", u)

	// Recognize ODBC connection strings like host\instance:1234
	reODBC := regexp.MustCompile(`^[^\\:]+(?:\\[^:]+)?(?::\d+)?(?:;.+)?$`)
	var host string
	switch {
	case reODBC.MatchString(u):
		logger.Debug("Recognized as ODBC URL format", "url", u)
		host = u
	default:
		logger.Debug("Couldn't recognize as valid MSSQL URL", "url", u)
		return nil, fmt.Errorf("unrecognized MSSQL URL format: %q", u)
	}
	return &url.URL{
		Scheme: "sqlserver",
		Host:   host,
	}, nil
}

func generateConnectionString(dsInfo sqleng.DataSourceInfo) (string, error) {
	const dfltPort = "0"
	var addr util.NetworkAddress
	if dsInfo.URL != "" {
		u, err := ParseURL(dsInfo.URL)
		if err != nil {
			return "", err
		}
		addr, err = util.SplitHostPortDefault(u.Host, "localhost", dfltPort)
		if err != nil {
			return "", err
		}
	} else {
		addr = util.NetworkAddress{
			Host: "localhost",
			Port: dfltPort,
		}
	}

	args := []interface{}{
		"url", dsInfo.URL, "host", addr.Host,
	}
	if addr.Port != "0" {
		args = append(args, "port", addr.Port)
	}
	logger.Debug("Generating connection string", args...)

	encrypt := dsInfo.JsonData.Encrypt
	tlsSkipVerify := dsInfo.JsonData.TlsSkipVerify
	hostNameInCertificate := dsInfo.JsonData.Servername
	certificate := dsInfo.JsonData.RootCertFile
	connStr := fmt.Sprintf("server=%s;database=%s;user id=%s;password=%s;",
		addr.Host,
		dsInfo.Database,
		dsInfo.User,
		dsInfo.DecryptedSecureJSONData["password"],
	)
	// Port number 0 means to determine the port automatically, so we can let the driver choose
	if addr.Port != "0" {
		connStr += fmt.Sprintf("port=%s;", addr.Port)
	}
	if encrypt == "true" {
		connStr += fmt.Sprintf("encrypt=%s;TrustServerCertificate=%t;", encrypt, tlsSkipVerify)
		if hostNameInCertificate != "" {
			connStr += fmt.Sprintf("hostNameInCertificate=%s;", hostNameInCertificate)
		}

		if certificate != "" {
			connStr += fmt.Sprintf("certificate=%s;", certificate)
		}
	} else if encrypt == "disable" {
		connStr += fmt.Sprintf("encrypt=%s;", dsInfo.JsonData.Encrypt)
	}
	return connStr, nil
}

type mssqlQueryResultTransformer struct {
	log log.Logger
}

func (t *mssqlQueryResultTransformer) TransformQueryError(err error) error {
	// go-mssql overrides source error, so we currently match on string
	// ref https://github.com/denisenkom/go-mssqldb/blob/045585d74f9069afe2e115b6235eb043c8047043/tds.go#L904
	if strings.HasPrefix(strings.ToLower(err.Error()), "unable to open tcp connection with host") {
		t.log.Error("query error", "err", err)
		return sqleng.ErrConnectionFailed
	}

	return err
}

func (t *mssqlQueryResultTransformer) GetConverterList() []sqlutil.StringConverter {
	return []sqlutil.StringConverter{
		{
			Name:           "handle MONEY",
			InputScanKind:  reflect.Slice,
			InputTypeName:  "MONEY",
			ConversionFunc: func(in *string) (*string, error) { return in, nil },
			Replacer: &sqlutil.StringFieldReplacer{
				OutputFieldType: data.FieldTypeNullableFloat64,
				ReplaceFunc: func(in *string) (interface{}, error) {
					if in == nil {
						return nil, nil
					}
					v, err := strconv.ParseFloat(*in, 64)
					if err != nil {
						return nil, err
					}
					return &v, nil
				},
			},
		},
		{
			Name:           "handle SMALLMONEY",
			InputScanKind:  reflect.Slice,
			InputTypeName:  "SMALLMONEY",
			ConversionFunc: func(in *string) (*string, error) { return in, nil },
			Replacer: &sqlutil.StringFieldReplacer{
				OutputFieldType: data.FieldTypeNullableFloat64,
				ReplaceFunc: func(in *string) (interface{}, error) {
					if in == nil {
						return nil, nil
					}
					v, err := strconv.ParseFloat(*in, 64)
					if err != nil {
						return nil, err
					}
					return &v, nil
				},
			},
		},
		{
			Name:           "handle DECIMAL",
			InputScanKind:  reflect.Slice,
			InputTypeName:  "DECIMAL",
			ConversionFunc: func(in *string) (*string, error) { return in, nil },
			Replacer: &sqlutil.StringFieldReplacer{
				OutputFieldType: data.FieldTypeNullableFloat64,
				ReplaceFunc: func(in *string) (interface{}, error) {
					if in == nil {
						return nil, nil
					}
					v, err := strconv.ParseFloat(*in, 64)
					if err != nil {
						return nil, err
					}
					return &v, nil
				},
			},
		},
		{
			Name:           "handle UNIQUEIDENTIFIER",
			InputScanKind:  reflect.Slice,
			InputTypeName:  "UNIQUEIDENTIFIER",
			ConversionFunc: func(in *string) (*string, error) { return in, nil },
			Replacer: &sqlutil.StringFieldReplacer{
				OutputFieldType: data.FieldTypeNullableString,
				ReplaceFunc: func(in *string) (interface{}, error) {
					if in == nil {
						return nil, nil
					}
					uuid := &mssql.UniqueIdentifier{}
					if err := uuid.Scan([]byte(*in)); err != nil {
						return nil, err
					}
					v := uuid.String()
					return &v, nil
				},
			},
		},
	}
}
<|endoftext|>


<commit_before>package utils

import (
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Utils", func() {
	It("must format a short name", func() {
		chain := FormatChainName("test", "1234")
		Expect(len(chain)).To(Equal(maxChainLength))
		Expect(chain).To(Equal("CNI-2bbe0c48b91a7d1b8a6753a8b"))
	})

	It("must truncate a long name", func() {
		chain := FormatChainName("testalongnamethatdoesnotmakesense", "1234")
		Expect(len(chain)).To(Equal(maxChainLength))
		Expect(chain).To(Equal("CNI-374f33fe84ab0ed84dcdebe38"))
	})

	It("must be predictable", func() {
		chain1 := FormatChainName("testalongnamethatdoesnotmakesense", "1234")
		chain2 := FormatChainName("testalongnamethatdoesnotmakesense", "1234")
		Expect(len(chain1)).To(Equal(maxChainLength))
		Expect(len(chain2)).To(Equal(maxChainLength))
		Expect(chain1).To(Equal(chain2))
	})

	It("must change when a character changes", func() {
		chain1 := FormatChainName("testalongnamethatdoesnotmakesense", "1234")
		chain2 := FormatChainName("testalongnamethatdoesnotmakesense", "1235")
		Expect(len(chain1)).To(Equal(maxChainLength))
		Expect(len(chain2)).To(Equal(maxChainLength))
		Expect(chain1).To(Equal("CNI-374f33fe84ab0ed84dcdebe38"))
		Expect(chain1).NotTo(Equal(chain2))
	})
})
<commit_msg>pkg/utils: correct the test's expected chain names<commit_after>package utils

import (
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Utils", func() {
	It("must format a short name", func() {
		chain := FormatChainName("test", "1234")
		Expect(len(chain)).To(Equal(maxChainLength))
		Expect(chain).To(Equal("CNI-2bbe0c48b91a7d1b8a6753a8"))
	})

	It("must truncate a long name", func() {
		chain := FormatChainName("testalongnamethatdoesnotmakesense", "1234")
		Expect(len(chain)).To(Equal(maxChainLength))
		Expect(chain).To(Equal("CNI-374f33fe84ab0ed84dcdebe3"))
	})

	It("must be predictable", func() {
		chain1 := FormatChainName("testalongnamethatdoesnotmakesense", "1234")
		chain2 := FormatChainName("testalongnamethatdoesnotmakesense", "1234")
		Expect(len(chain1)).To(Equal(maxChainLength))
		Expect(len(chain2)).To(Equal(maxChainLength))
		Expect(chain1).To(Equal(chain2))
	})

	It("must change when a character changes", func() {
		chain1 := FormatChainName("testalongnamethatdoesnotmakesense", "1234")
		chain2 := FormatChainName("testalongnamethatdoesnotmakesense", "1235")
		Expect(len(chain1)).To(Equal(maxChainLength))
		Expect(len(chain2)).To(Equal(maxChainLength))
		Expect(chain1).To(Equal("CNI-374f33fe84ab0ed84dcdebe3"))
		Expect(chain1).NotTo(Equal(chain2))
	})
})
<|endoftext|>


<commit_before>// Copyright 2015 Google LLC
//
// 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 bigquery provides a client for the BigQuery service.

The following assumes a basic familiarity with BigQuery concepts.
See https://cloud.google.com/bigquery/docs.

See https://godoc.org/cloud.google.com/go for authentication, timeouts,
connection pooling and similar aspects of this package.

Creating a Client

To start working with this package, create a client:

    ctx := context.Background()
    client, err := bigquery.NewClient(ctx, projectID)
    if err != nil {
        // TODO: Handle error.
    }

Querying

To query existing tables, create a Query and call its Read method:

    q := client.Query(`
        SELECT year, SUM(number) as num
        FROM ` + "`bigquery-public-data.usa_names.usa_1910_2013`" + `
        WHERE name = "William"
        GROUP BY year
        ORDER BY year
    `)
    it, err := q.Read(ctx)
    if err != nil {
        // TODO: Handle error.
    }

Then iterate through the resulting rows. You can store a row using
anything that implements the ValueLoader interface, or with a slice or map of bigquery.Value.
A slice is simplest:

    for {
        var values []bigquery.Value
        err := it.Next(&values)
        if err == iterator.Done {
            break
        }
        if err != nil {
            // TODO: Handle error.
        }
        fmt.Println(values)
    }

You can also use a struct whose exported fields match the query:

    type Count struct {
        Year int
        Num  int
    }
    for {
        var c Count
        err := it.Next(&c)
        if err == iterator.Done {
            break
        }
        if err != nil {
            // TODO: Handle error.
        }
        fmt.Println(c)
    }

You can also start the query running and get the results later.
Create the query as above, but call Run instead of Read. This returns a Job,
which represents an asynchronous operation.

    job, err := q.Run(ctx)
    if err != nil {
        // TODO: Handle error.
    }

Get the job's ID, a printable string. You can save this string to retrieve
the results at a later time, even in another process.

    jobID := job.ID()
    fmt.Printf("The job ID is %s\n", jobID)

To retrieve the job's results from the ID, first look up the Job:

    job, err = client.JobFromID(ctx, jobID)
    if err != nil {
        // TODO: Handle error.
    }

Use the Job.Read method to obtain an iterator, and loop over the rows.
Query.Read is just a convenience method that combines Query.Run and Job.Read.

    it, err = job.Read(ctx)
    if err != nil {
        // TODO: Handle error.
    }
    // Proceed with iteration as above.

Datasets and Tables

You can refer to datasets in the client's project with the Dataset method, and
in other projects with the DatasetInProject method:

    myDataset := client.Dataset("my_dataset")
    yourDataset := client.DatasetInProject("your-project-id", "your_dataset")

These methods create references to datasets, not the datasets themselves. You can have
a dataset reference even if the dataset doesn't exist yet. Use Dataset.Create to
create a dataset from a reference:

    if err := myDataset.Create(ctx, nil); err != nil {
        // TODO: Handle error.
    }

You can refer to tables with Dataset.Table. Like bigquery.Dataset, bigquery.Table is a reference
to an object in BigQuery that may or may not exist.

    table := myDataset.Table("my_table")

You can create, delete and update the metadata of tables with methods on Table.
For instance, you could create a temporary table with:

    err = myDataset.Table("temp").Create(ctx, &bigquery.TableMetadata{
        ExpirationTime: time.Now().Add(1*time.Hour)})
    if err != nil {
        // TODO: Handle error.
    }

We'll see how to create a table with a schema in the next section.

Schemas

There are two ways to construct schemas with this package.
You can build a schema by hand, like so:

    schema1 := bigquery.Schema{
        {Name: "Name", Required: true, Type: bigquery.StringFieldType},
        {Name: "Grades", Repeated: true, Type: bigquery.IntegerFieldType},
        {Name: "Optional", Required: false, Type: bigquery.IntegerFieldType},
    }

Or you can infer the schema from a struct:

    type student struct {
        Name   string
        Grades []int
        Optional bigquery.NullInt64
    }
    schema2, err := bigquery.InferSchema(student{})
    if err != nil {
        // TODO: Handle error.
    }
    // schema1 and schema2 are identical.

Struct inference supports tags like those of the encoding/json package, so you can
change names, ignore fields, or mark a field as nullable (non-required). Fields
declared as one of the Null types (NullInt64, NullFloat64, NullString, NullBool,
NullTimestamp, NullDate, NullTime, NullDateTime, and NullGeography) are
automatically inferred as nullable, so the "nullable" tag is only needed for []byte,
*big.Rat and pointer-to-struct fields.

    type student2 struct {
        Name     string `bigquery:"full_name"`
        Grades   []int
        Secret   string `bigquery:"-"`
        Optional []byte `bigquery:",nullable"`
    }
    schema3, err := bigquery.InferSchema(student2{})
    if err != nil {
        // TODO: Handle error.
    }
    // schema3 has required fields "full_name" and "Grade", and nullable BYTES field "Optional".

Having constructed a schema, you can create a table with it like so:

    if err := table.Create(ctx, &bigquery.TableMetadata{Schema: schema1}); err != nil {
        // TODO: Handle error.
    }

Copying

You can copy one or more tables to another table. Begin by constructing a Copier
describing the copy. Then set any desired copy options, and finally call Run to get a Job:

    copier := myDataset.Table("dest").CopierFrom(myDataset.Table("src"))
    copier.WriteDisposition = bigquery.WriteTruncate
    job, err = copier.Run(ctx)
    if err != nil {
        // TODO: Handle error.
    }

You can chain the call to Run if you don't want to set options:

    job, err = myDataset.Table("dest").CopierFrom(myDataset.Table("src")).Run(ctx)
    if err != nil {
        // TODO: Handle error.
    }

You can wait for your job to complete:

    status, err := job.Wait(ctx)
    if err != nil {
        // TODO: Handle error.
    }

Job.Wait polls with exponential backoff. You can also poll yourself, if you
wish:

    for {
        status, err := job.Status(ctx)
        if err != nil {
            // TODO: Handle error.
        }
        if status.Done() {
            if status.Err() != nil {
                log.Fatalf("Job failed with error %v", status.Err())
            }
            break
        }
        time.Sleep(pollInterval)
    }

Loading and Uploading

There are two ways to populate a table with this package: load the data from a Google Cloud Storage
object, or upload rows directly from your program.

For loading, first create a GCSReference, configuring it if desired. Then make a Loader, optionally configure
it as well, and call its Run method.

    gcsRef := bigquery.NewGCSReference("gs://my-bucket/my-object")
    gcsRef.AllowJaggedRows = true
    loader := myDataset.Table("dest").LoaderFrom(gcsRef)
    loader.CreateDisposition = bigquery.CreateNever
    job, err = loader.Run(ctx)
    // Poll the job for completion if desired, as above.

To upload, first define a type that implements the ValueSaver interface, which has a single method named Save.
Then create an Inserter, and call its Put method with a slice of values.

    u := table.Inserter()
    // Item implements the ValueSaver interface.
    items := []*Item{
        {Name: "n1", Size: 32.6, Count: 7},
        {Name: "n2", Size: 4, Count: 2},
        {Name: "n3", Size: 101.5, Count: 1},
    }
    if err := u.Put(ctx, items); err != nil {
        // TODO: Handle error.
    }

You can also upload a struct that doesn't implement ValueSaver. Use the StructSaver type
to specify the schema and insert ID by hand, or just supply the struct or struct pointer
directly and the schema will be inferred:

    type Item2 struct {
        Name  string
        Size  float64
        Count int
    }
    // Item implements the ValueSaver interface.
    items2 := []*Item2{
        {Name: "n1", Size: 32.6, Count: 7},
        {Name: "n2", Size: 4, Count: 2},
        {Name: "n3", Size: 101.5, Count: 1},
    }
    if err := u.Put(ctx, items2); err != nil {
        // TODO: Handle error.
    }

BigQuery allows for higher throughput when omitting insertion IDs.  To enable this,
specify the sentinel `NoDedupeID` value for the insertion ID when implementing a ValueSaver.

Extracting

If you've been following so far, extracting data from a BigQuery table
into a Google Cloud Storage object will feel familiar. First create an
Extractor, then optionally configure it, and lastly call its Run method.

    extractor := table.ExtractorTo(gcsRef)
    extractor.DisableHeader = true
    job, err = extractor.Run(ctx)
    // Poll the job for completion if desired, as above.

Errors

Errors returned by this client are often of the type googleapi.Error: https://godoc.org/google.golang.org/api/googleapi#Error

These errors can be introspected for more information by using `xerrors.As` with the richer *googleapi.Error type. For example:

	var e *googleapi.Error
	if ok := xerrors.As(err, &e); ok {
		  if e.Code = 409 { ... }
    }

In some cases, your client may received unstructured googleapi.Error error responses.  In such cases, it is likely that
you have exceeded BigQuery request limits, documented at: https://cloud.google.com/bigquery/quotas

*/
package bigquery // import "cloud.google.com/go/bigquery"
<commit_msg>docs(bigquery): use equality operator in Errors example (#5201)<commit_after>// Copyright 2015 Google LLC
//
// 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 bigquery provides a client for the BigQuery service.

The following assumes a basic familiarity with BigQuery concepts.
See https://cloud.google.com/bigquery/docs.

See https://godoc.org/cloud.google.com/go for authentication, timeouts,
connection pooling and similar aspects of this package.

Creating a Client

To start working with this package, create a client:

    ctx := context.Background()
    client, err := bigquery.NewClient(ctx, projectID)
    if err != nil {
        // TODO: Handle error.
    }

Querying

To query existing tables, create a Query and call its Read method:

    q := client.Query(`
        SELECT year, SUM(number) as num
        FROM ` + "`bigquery-public-data.usa_names.usa_1910_2013`" + `
        WHERE name = "William"
        GROUP BY year
        ORDER BY year
    `)
    it, err := q.Read(ctx)
    if err != nil {
        // TODO: Handle error.
    }

Then iterate through the resulting rows. You can store a row using
anything that implements the ValueLoader interface, or with a slice or map of bigquery.Value.
A slice is simplest:

    for {
        var values []bigquery.Value
        err := it.Next(&values)
        if err == iterator.Done {
            break
        }
        if err != nil {
            // TODO: Handle error.
        }
        fmt.Println(values)
    }

You can also use a struct whose exported fields match the query:

    type Count struct {
        Year int
        Num  int
    }
    for {
        var c Count
        err := it.Next(&c)
        if err == iterator.Done {
            break
        }
        if err != nil {
            // TODO: Handle error.
        }
        fmt.Println(c)
    }

You can also start the query running and get the results later.
Create the query as above, but call Run instead of Read. This returns a Job,
which represents an asynchronous operation.

    job, err := q.Run(ctx)
    if err != nil {
        // TODO: Handle error.
    }

Get the job's ID, a printable string. You can save this string to retrieve
the results at a later time, even in another process.

    jobID := job.ID()
    fmt.Printf("The job ID is %s\n", jobID)

To retrieve the job's results from the ID, first look up the Job:

    job, err = client.JobFromID(ctx, jobID)
    if err != nil {
        // TODO: Handle error.
    }

Use the Job.Read method to obtain an iterator, and loop over the rows.
Query.Read is just a convenience method that combines Query.Run and Job.Read.

    it, err = job.Read(ctx)
    if err != nil {
        // TODO: Handle error.
    }
    // Proceed with iteration as above.

Datasets and Tables

You can refer to datasets in the client's project with the Dataset method, and
in other projects with the DatasetInProject method:

    myDataset := client.Dataset("my_dataset")
    yourDataset := client.DatasetInProject("your-project-id", "your_dataset")

These methods create references to datasets, not the datasets themselves. You can have
a dataset reference even if the dataset doesn't exist yet. Use Dataset.Create to
create a dataset from a reference:

    if err := myDataset.Create(ctx, nil); err != nil {
        // TODO: Handle error.
    }

You can refer to tables with Dataset.Table. Like bigquery.Dataset, bigquery.Table is a reference
to an object in BigQuery that may or may not exist.

    table := myDataset.Table("my_table")

You can create, delete and update the metadata of tables with methods on Table.
For instance, you could create a temporary table with:

    err = myDataset.Table("temp").Create(ctx, &bigquery.TableMetadata{
        ExpirationTime: time.Now().Add(1*time.Hour)})
    if err != nil {
        // TODO: Handle error.
    }

We'll see how to create a table with a schema in the next section.

Schemas

There are two ways to construct schemas with this package.
You can build a schema by hand, like so:

    schema1 := bigquery.Schema{
        {Name: "Name", Required: true, Type: bigquery.StringFieldType},
        {Name: "Grades", Repeated: true, Type: bigquery.IntegerFieldType},
        {Name: "Optional", Required: false, Type: bigquery.IntegerFieldType},
    }

Or you can infer the schema from a struct:

    type student struct {
        Name   string
        Grades []int
        Optional bigquery.NullInt64
    }
    schema2, err := bigquery.InferSchema(student{})
    if err != nil {
        // TODO: Handle error.
    }
    // schema1 and schema2 are identical.

Struct inference supports tags like those of the encoding/json package, so you can
change names, ignore fields, or mark a field as nullable (non-required). Fields
declared as one of the Null types (NullInt64, NullFloat64, NullString, NullBool,
NullTimestamp, NullDate, NullTime, NullDateTime, and NullGeography) are
automatically inferred as nullable, so the "nullable" tag is only needed for []byte,
*big.Rat and pointer-to-struct fields.

    type student2 struct {
        Name     string `bigquery:"full_name"`
        Grades   []int
        Secret   string `bigquery:"-"`
        Optional []byte `bigquery:",nullable"`
    }
    schema3, err := bigquery.InferSchema(student2{})
    if err != nil {
        // TODO: Handle error.
    }
    // schema3 has required fields "full_name" and "Grade", and nullable BYTES field "Optional".

Having constructed a schema, you can create a table with it like so:

    if err := table.Create(ctx, &bigquery.TableMetadata{Schema: schema1}); err != nil {
        // TODO: Handle error.
    }

Copying

You can copy one or more tables to another table. Begin by constructing a Copier
describing the copy. Then set any desired copy options, and finally call Run to get a Job:

    copier := myDataset.Table("dest").CopierFrom(myDataset.Table("src"))
    copier.WriteDisposition = bigquery.WriteTruncate
    job, err = copier.Run(ctx)
    if err != nil {
        // TODO: Handle error.
    }

You can chain the call to Run if you don't want to set options:

    job, err = myDataset.Table("dest").CopierFrom(myDataset.Table("src")).Run(ctx)
    if err != nil {
        // TODO: Handle error.
    }

You can wait for your job to complete:

    status, err := job.Wait(ctx)
    if err != nil {
        // TODO: Handle error.
    }

Job.Wait polls with exponential backoff. You can also poll yourself, if you
wish:

    for {
        status, err := job.Status(ctx)
        if err != nil {
            // TODO: Handle error.
        }
        if status.Done() {
            if status.Err() != nil {
                log.Fatalf("Job failed with error %v", status.Err())
            }
            break
        }
        time.Sleep(pollInterval)
    }

Loading and Uploading

There are two ways to populate a table with this package: load the data from a Google Cloud Storage
object, or upload rows directly from your program.

For loading, first create a GCSReference, configuring it if desired. Then make a Loader, optionally configure
it as well, and call its Run method.

    gcsRef := bigquery.NewGCSReference("gs://my-bucket/my-object")
    gcsRef.AllowJaggedRows = true
    loader := myDataset.Table("dest").LoaderFrom(gcsRef)
    loader.CreateDisposition = bigquery.CreateNever
    job, err = loader.Run(ctx)
    // Poll the job for completion if desired, as above.

To upload, first define a type that implements the ValueSaver interface, which has a single method named Save.
Then create an Inserter, and call its Put method with a slice of values.

    u := table.Inserter()
    // Item implements the ValueSaver interface.
    items := []*Item{
        {Name: "n1", Size: 32.6, Count: 7},
        {Name: "n2", Size: 4, Count: 2},
        {Name: "n3", Size: 101.5, Count: 1},
    }
    if err := u.Put(ctx, items); err != nil {
        // TODO: Handle error.
    }

You can also upload a struct that doesn't implement ValueSaver. Use the StructSaver type
to specify the schema and insert ID by hand, or just supply the struct or struct pointer
directly and the schema will be inferred:

    type Item2 struct {
        Name  string
        Size  float64
        Count int
    }
    // Item implements the ValueSaver interface.
    items2 := []*Item2{
        {Name: "n1", Size: 32.6, Count: 7},
        {Name: "n2", Size: 4, Count: 2},
        {Name: "n3", Size: 101.5, Count: 1},
    }
    if err := u.Put(ctx, items2); err != nil {
        // TODO: Handle error.
    }

BigQuery allows for higher throughput when omitting insertion IDs.  To enable this,
specify the sentinel `NoDedupeID` value for the insertion ID when implementing a ValueSaver.

Extracting

If you've been following so far, extracting data from a BigQuery table
into a Google Cloud Storage object will feel familiar. First create an
Extractor, then optionally configure it, and lastly call its Run method.

    extractor := table.ExtractorTo(gcsRef)
    extractor.DisableHeader = true
    job, err = extractor.Run(ctx)
    // Poll the job for completion if desired, as above.

Errors

Errors returned by this client are often of the type googleapi.Error: https://godoc.org/google.golang.org/api/googleapi#Error

These errors can be introspected for more information by using `xerrors.As` with the richer *googleapi.Error type. For example:

	var e *googleapi.Error
	if ok := xerrors.As(err, &e); ok {
		  if e.Code == 409 { ... }
    }

In some cases, your client may received unstructured googleapi.Error error responses.  In such cases, it is likely that
you have exceeded BigQuery request limits, documented at: https://cloud.google.com/bigquery/quotas

*/
package bigquery // import "cloud.google.com/go/bigquery"
<|endoftext|>


<commit_before>package testblas

import (
	"testing"

	"github.com/gonum/blas"
)

type Dgbmver interface {
	Dgbmv(tA blas.Transpose, m, n, kL, kU int, alpha float64, a []float64, lda int, x []float64, incX int, beta float64, y []float64, incY int)
}

// TODO: Redo this test with row major implementation
func DgbmvTest(t *testing.T, blasser Dgbmver) {
	for i, test := range []struct {
		tA     blas.Transpose
		m, n   int
		kL, kU int
		alpha  float64
		a      [][]float64
		lda    int
		x      []float64
		beta   float64
		y      []float64
		ans    []float64
	}{
		{
			tA:    blas.NoTrans,
			m:     9,
			n:     6,
			lda:   4,
			kL:    2,
			kU:    1,
			alpha: 3.0,
			beta:  2.0,
			a: [][]float64{
				{5, 3, 0, 0, 0, 0},
				{-1, 2, 9, 0, 0, 0},
				{4, 8, 3, 6, 0, 0},
				{0, -1, 8, 2, 1, 0},
				{0, 0, 9, 9, 9, 5},
				{0, 0, 0, 2, -3, 2},
				{0, 0, 0, 0, 1, 5},
				{0, 0, 0, 0, 0, 6},
				{0, 0, 0, 0, 0, 0},
			},
			x:   []float64{1, 2, 3, 4, 5, 6},
			y:   []float64{-1, -2, -3, -4, -5, -6, -7, -8, -9},
			ans: []float64{31, 86, 153, 97, 404, 3, 91, 92, -18},
		},
		{
			tA:    blas.Trans,
			m:     9,
			n:     6,
			lda:   4,
			kL:    2,
			kU:    1,
			alpha: 3.0,
			beta:  2.0,
			a: [][]float64{
				{5, 3, 0, 0, 0, 0},
				{-1, 2, 9, 0, 0, 0},
				{4, 8, 3, 6, 0, 0},
				{0, -1, 8, 2, 1, 0},
				{0, 0, 9, 9, 9, 5},
				{0, 0, 0, 2, -3, 2},
				{0, 0, 0, 0, 1, 5},
				{0, 0, 0, 0, 0, 6},
				{0, 0, 0, 0, 0, 0},
			},
			x:   []float64{1, 2, 3, 4, 5, 6, 7, 8, 9},
			y:   []float64{-1, -2, -3, -4, -5, -6},
			ans: []float64{43, 77, 306, 241, 104, 348},
		},
	} {
		extra := 3
		aFlat := flattenBanded(test.a, test.kU, test.kL)
		incTest := func(incX, incY, extra int) {
			xnew := makeIncremented(test.x, incX, extra)
			ynew := makeIncremented(test.y, incY, extra)
			ans := makeIncremented(test.ans, incY, extra)
			blasser.Dgbmv(test.tA, test.m, test.n, test.kL, test.kU, test.alpha, aFlat, test.lda, xnew, incX, test.beta, ynew, incY)
			if !dSliceTolEqual(ans, ynew) {
				t.Errorf("Case %v: Want %v, got %v", i, ans, ynew)
			}
		}
		incTest(1, 1, extra)
		incTest(1, 3, extra)
		incTest(1, -3, extra)
		incTest(2, 3, extra)
		incTest(2, -3, extra)
		incTest(3, 2, extra)
		incTest(-3, 2, extra)
	}
}
<commit_msg>Added outdated comment<commit_after>package testblas

import (
	"testing"

	"github.com/gonum/blas"
)

type Dgbmver interface {
	Dgbmv(tA blas.Transpose, m, n, kL, kU int, alpha float64, a []float64, lda int, x []float64, incX int, beta float64, y []float64, incY int)
}

func DgbmvTest(t *testing.T, blasser Dgbmver) {
	for i, test := range []struct {
		tA     blas.Transpose
		m, n   int
		kL, kU int
		alpha  float64
		a      [][]float64
		lda    int
		x      []float64
		beta   float64
		y      []float64
		ans    []float64
	}{
		{
			tA:    blas.NoTrans,
			m:     9,
			n:     6,
			lda:   4,
			kL:    2,
			kU:    1,
			alpha: 3.0,
			beta:  2.0,
			a: [][]float64{
				{5, 3, 0, 0, 0, 0},
				{-1, 2, 9, 0, 0, 0},
				{4, 8, 3, 6, 0, 0},
				{0, -1, 8, 2, 1, 0},
				{0, 0, 9, 9, 9, 5},
				{0, 0, 0, 2, -3, 2},
				{0, 0, 0, 0, 1, 5},
				{0, 0, 0, 0, 0, 6},
				{0, 0, 0, 0, 0, 0},
			},
			x:   []float64{1, 2, 3, 4, 5, 6},
			y:   []float64{-1, -2, -3, -4, -5, -6, -7, -8, -9},
			ans: []float64{31, 86, 153, 97, 404, 3, 91, 92, -18},
		},
		{
			tA:    blas.Trans,
			m:     9,
			n:     6,
			lda:   4,
			kL:    2,
			kU:    1,
			alpha: 3.0,
			beta:  2.0,
			a: [][]float64{
				{5, 3, 0, 0, 0, 0},
				{-1, 2, 9, 0, 0, 0},
				{4, 8, 3, 6, 0, 0},
				{0, -1, 8, 2, 1, 0},
				{0, 0, 9, 9, 9, 5},
				{0, 0, 0, 2, -3, 2},
				{0, 0, 0, 0, 1, 5},
				{0, 0, 0, 0, 0, 6},
				{0, 0, 0, 0, 0, 0},
			},
			x:   []float64{1, 2, 3, 4, 5, 6, 7, 8, 9},
			y:   []float64{-1, -2, -3, -4, -5, -6},
			ans: []float64{43, 77, 306, 241, 104, 348},
		},
	} {
		extra := 3
		aFlat := flattenBanded(test.a, test.kU, test.kL)
		incTest := func(incX, incY, extra int) {
			xnew := makeIncremented(test.x, incX, extra)
			ynew := makeIncremented(test.y, incY, extra)
			ans := makeIncremented(test.ans, incY, extra)
			blasser.Dgbmv(test.tA, test.m, test.n, test.kL, test.kU, test.alpha, aFlat, test.lda, xnew, incX, test.beta, ynew, incY)
			if !dSliceTolEqual(ans, ynew) {
				t.Errorf("Case %v: Want %v, got %v", i, ans, ynew)
			}
		}
		incTest(1, 1, extra)
		incTest(1, 3, extra)
		incTest(1, -3, extra)
		incTest(2, 3, extra)
		incTest(2, -3, extra)
		incTest(3, 2, extra)
		incTest(-3, 2, extra)
	}
}
<|endoftext|>


<commit_before>// An example FTP server build on top of go-raval. graval handles the details
// of the FTP protocol, we just provide a basic in-memory persistence driver.
//
// If you're looking to create a custom graval driver, this example is a
// reasonable starting point. I suggest copying this file and changing the
// function bodies as required.
//
// USAGE:
//
//    go get github.com/yob/graval
//    go install github.com/yob/graval/graval-mem
//    ./bin/graval-mem
//
package main

import (
	"github.com/yob/graval"
	"io"
	"io/ioutil"
	"log"
	"os"
	"strings"
	"time"
)

const (
	fileOne = "This is the first file available for download.\n\nBy Jàmes"
	fileTwo = "This is file number two.\n\n2012-12-04"
)

// A minimal driver for graval that stores everything in memory. The authentication
// details are fixed and the user is unable to upload, delete or rename any files.
//
// This really just exists as a minimal demonstration of the interface graval
// drivers are required to implement.
type MemDriver struct{}

func (driver *MemDriver) Authenticate(user string, pass string) bool {
	return user == "test" && pass == "1234"
}
func (driver *MemDriver) Bytes(path string) (bytes int64) {
	switch path {
	case "/one.txt":
		bytes = int64(len(fileOne))
		break
	case "/files/two.txt":
		bytes = int64(len(fileTwo))
		break
	default:
		bytes = -1
	}
	return
}
func (driver *MemDriver) ModifiedTime(path string) (time.Time, error) {
	return time.Now(), nil
}
func (driver *MemDriver) ChangeDir(path string) bool {
	return path == "/" || path == "/files"
}
func (driver *MemDriver) DirContents(path string) (files []os.FileInfo) {
	files = []os.FileInfo{}
	switch path {
	case "/":
		files = append(files, graval.NewDirItem("files"))
		files = append(files, graval.NewFileItem("one.txt", len(fileOne)))
	case "/files":
		files = append(files, graval.NewFileItem("two.txt", len(fileOne)))
	}
	return files
}

func (driver *MemDriver) DeleteDir(path string) bool {
	return false
}
func (driver *MemDriver) DeleteFile(path string) bool {
	return false
}
func (driver *MemDriver) Rename(fromPath string, toPath string) bool {
	return false
}
func (driver *MemDriver) MakeDir(path string) bool {
	return false
}
func (driver *MemDriver) GetFile(path string) (reader io.ReadCloser, err error) {
	switch path {
	case "/one.txt":
		reader = ioutil.NopCloser(strings.NewReader(fileOne))
	case "/files/two.txt":
		reader = ioutil.NopCloser(strings.NewReader(fileTwo))
	}
	return
}
func (driver *MemDriver) PutFile(destPath string, data io.Reader) bool {
	return false
}

// graval requires a factory that will create a new driver instance for each
// client connection. Generally the factory will be fairly minimal. This is
// a good place to read any required config for your driver.
type MemDriverFactory struct{}

func (factory *MemDriverFactory) NewDriver() (graval.FTPDriver, error) {
	return &MemDriver{}, nil
}

// it's alive!
func main() {
	factory := &MemDriverFactory{}
	opts := &graval.FTPServerOpts{
		Factory:     factory,
		ServerName:  "graval-mem, the in memory FTP server",
		PasvMinPort: 60200,
		PasvMaxPort: 60300,
	}
	ftpServer := graval.NewFTPServer(opts)
	err := ftpServer.ListenAndServe()
	if err != nil {
		log.Print(err)
		log.Fatal("Error starting server!")
	}
}
<commit_msg>update graval-mem driver to work with changed graval.NewFileItem<commit_after>// An example FTP server build on top of go-raval. graval handles the details
// of the FTP protocol, we just provide a basic in-memory persistence driver.
//
// If you're looking to create a custom graval driver, this example is a
// reasonable starting point. I suggest copying this file and changing the
// function bodies as required.
//
// USAGE:
//
//    go get github.com/yob/graval
//    go install github.com/yob/graval/graval-mem
//    ./bin/graval-mem
//
package main

import (
	"github.com/yob/graval"
	"io"
	"io/ioutil"
	"log"
	"os"
	"strings"
	"time"
)

const (
	fileOne = "This is the first file available for download.\n\nBy Jàmes"
	fileTwo = "This is file number two.\n\n2012-12-04"
)

// A minimal driver for graval that stores everything in memory. The authentication
// details are fixed and the user is unable to upload, delete or rename any files.
//
// This really just exists as a minimal demonstration of the interface graval
// drivers are required to implement.
type MemDriver struct{}

func (driver *MemDriver) Authenticate(user string, pass string) bool {
	return user == "test" && pass == "1234"
}
func (driver *MemDriver) Bytes(path string) (bytes int64) {
	switch path {
	case "/one.txt":
		bytes = int64(len(fileOne))
		break
	case "/files/two.txt":
		bytes = int64(len(fileTwo))
		break
	default:
		bytes = -1
	}
	return
}
func (driver *MemDriver) ModifiedTime(path string) (time.Time, error) {
	return time.Now(), nil
}
func (driver *MemDriver) ChangeDir(path string) bool {
	return path == "/" || path == "/files"
}
func (driver *MemDriver) DirContents(path string) (files []os.FileInfo) {
	files = []os.FileInfo{}
	switch path {
	case "/":
		files = append(files, graval.NewDirItem("files"))
		files = append(files, graval.NewFileItem("one.txt", int64(len(fileOne)), time.Now()))
	case "/files":
		files = append(files, graval.NewFileItem("two.txt", int64(len(fileOne)), time.Now()))
	}
	return files
}

func (driver *MemDriver) DeleteDir(path string) bool {
	return false
}
func (driver *MemDriver) DeleteFile(path string) bool {
	return false
}
func (driver *MemDriver) Rename(fromPath string, toPath string) bool {
	return false
}
func (driver *MemDriver) MakeDir(path string) bool {
	return false
}
func (driver *MemDriver) GetFile(path string) (reader io.ReadCloser, err error) {
	switch path {
	case "/one.txt":
		reader = ioutil.NopCloser(strings.NewReader(fileOne))
	case "/files/two.txt":
		reader = ioutil.NopCloser(strings.NewReader(fileTwo))
	}
	return
}
func (driver *MemDriver) PutFile(destPath string, data io.Reader) bool {
	return false
}

// graval requires a factory that will create a new driver instance for each
// client connection. Generally the factory will be fairly minimal. This is
// a good place to read any required config for your driver.
type MemDriverFactory struct{}

func (factory *MemDriverFactory) NewDriver() (graval.FTPDriver, error) {
	return &MemDriver{}, nil
}

// it's alive!
func main() {
	factory := &MemDriverFactory{}
	opts := &graval.FTPServerOpts{
		Factory:     factory,
		ServerName:  "graval-mem, the in memory FTP server",
		PasvMinPort: 60200,
		PasvMaxPort: 60300,
	}
	ftpServer := graval.NewFTPServer(opts)
	err := ftpServer.ListenAndServe()
	if err != nil {
		log.Print(err)
		log.Fatal("Error starting server!")
	}
}
<|endoftext|>


<commit_before>package fake

import (
	"strconv"
	"strings"
)

func UserName() string {
	return lookup(lang, "usernames", true)
}

func TopLevelDomain() string {
	return lookup(lang, "top_level_domains", true)
}

func DomainName() string {
	return Company() + "." + TopLevelDomain()
}

func EmailAddress() string {
	return UserName() + "@" + DomainName()
}

func EmailSubject() string {
	return Sentence()
}

func EmailBody() string {
	return Paragraphs()
}

func DomainZone() string {
	return lookup(lang, "domain_zones", true)
}

func IPv4() string {
	ip := make([]string, 4)
	for i := 0; i < 4; i++ {
		ip[i] = strconv.Itoa(r.Intn(256))
	}
	return strings.Join(ip, ".")
}
<commit_msg>UserName method reimplemented<commit_after>package fake

import (
	"strconv"
	"strings"
)

func UserName() string {
	gender := randGender()
	switch r.Intn(2) {
	case 0:
		return lookup("en", gender+"_first_names", false) + lookup(lang, gender+"_last_names", false)
	case 1:
		return Character() + lookup(lang, gender+"_last_names", false)
	default:
		return strings.Replace(WordsN(r.Intn(3)+1), " ", "_", -1)
	}
}

func TopLevelDomain() string {
	return lookup(lang, "top_level_domains", true)
}

func DomainName() string {
	return Company() + "." + TopLevelDomain()
}

func EmailAddress() string {
	return UserName() + "@" + DomainName()
}

func EmailSubject() string {
	return Sentence()
}

func EmailBody() string {
	return Paragraphs()
}

func DomainZone() string {
	return lookup(lang, "domain_zones", true)
}

func IPv4() string {
	ip := make([]string, 4)
	for i := 0; i < 4; i++ {
		ip[i] = strconv.Itoa(r.Intn(256))
	}
	return strings.Join(ip, ".")
}
<|endoftext|>