<commit_before>package tictactoe

import (
	"errors"
	"github.com/jkomoros/boardgame"
)

type MovePlaceToken struct {
	//Which token to place the token
	Slot int
	//Which player we THINK is making the move.
	TargetPlayerIndex int
}

func (m *MovePlaceToken) Legal(payload boardgame.StatePayload) error {
	p := payload.(*statePayload)

	if p.game.CurrentPlayer != m.TargetPlayerIndex {
		return errors.New("The specified player is not the current player.")
	}

	if p.users[m.TargetPlayerIndex].UnusedTokens.Len() < 1 {
		return errors.New("There aren't any remaining tokens for the current player to place.")
	}

	if p.game.Slots.ComponentAt(m.Slot) != nil {
		return errors.New("The specified slot is already taken.")
	}

	return nil

}

func (m *MovePlaceToken) Apply(payload boardgame.StatePayload) boardgame.StatePayload {

	result := payload.Copy()

	p := result.(*statePayload)

	c := p.users[m.TargetPlayerIndex].UnusedTokens.RemoveFirst()

	p.game.Slots.InsertAtSlot(c, m.Slot)

	return result

}

func (m *MovePlaceToken) Name() string {
	return "Place Token"
}

func (m *MovePlaceToken) Description() string {
	return "Place a player's token in a specific space."
}

func (m *MovePlaceToken) Copy() boardgame.Move {
	var result MovePlaceToken
	result = *m
	return &result
}

func (m *MovePlaceToken) Props() []string {
	return boardgame.PropertyReaderPropsImpl(m)
}

func (m *MovePlaceToken) Prop(name string) interface{} {
	return boardgame.PropertyReaderPropImpl(m, name)
}

func (m *MovePlaceToken) SetProp(name string, val interface{}) error {
	return boardgame.PropertySetImpl(m, name, val)
}

func (m *MovePlaceToken) JSON() boardgame.JSONObject {
	return m
}

type MoveAdvancePlayer struct{}

func (m *MoveAdvancePlayer) Legal(payload boardgame.StatePayload) error {
	p := payload.(*statePayload)

	user := p.users[p.game.CurrentPlayer]

	if user.TokensToPlaceThisTurn > 0 {
		return errors.New("The current player still has tokens left to place this turn.")
	}

	return nil
}

func (m *MoveAdvancePlayer) Apply(payload boardgame.StatePayload) boardgame.StatePayload {
	result := payload.Copy()

	p := result.(*statePayload)

	p.game.CurrentPlayer++

	if p.game.CurrentPlayer >= len(p.users) {
		p.game.CurrentPlayer = 0
	}

	newUser := p.users[p.game.CurrentPlayer]

	newUser.TokensToPlaceThisTurn = 1

	return result

}

func (m *MoveAdvancePlayer) Name() string {
	return "Advance Player"
}

func (m *MoveAdvancePlayer) Description() string {
	return "After the current player has made all of their moves, this fix-up move advances to the next player."
}

func (m *MoveAdvancePlayer) Copy() boardgame.Move {
	var result MoveAdvancePlayer
	result = *m
	return &result
}

func (m *MoveAdvancePlayer) JSON() boardgame.JSONObject {
	return m
}

func (m *MoveAdvancePlayer) Prop(name string) interface{} {
	return boardgame.PropertyReaderPropImpl(m, name)
}

func (m *MoveAdvancePlayer) Props() []string {
	return boardgame.PropertyReaderPropsImpl(m)
}

func (m *MoveAdvancePlayer) SetProp(name string, val interface{}) error {
	return boardgame.PropertySetImpl(m, name, val)
}
<commit_msg>Placing a token decrements the MovesLeftThisTurn count. Still doesn't advance to next player because no ProposeFixUp exists. Part of #14.<commit_after>package tictactoe

import (
	"errors"
	"github.com/jkomoros/boardgame"
)

type MovePlaceToken struct {
	//Which token to place the token
	Slot int
	//Which player we THINK is making the move.
	TargetPlayerIndex int
}

func (m *MovePlaceToken) Legal(payload boardgame.StatePayload) error {
	p := payload.(*statePayload)

	if p.game.CurrentPlayer != m.TargetPlayerIndex {
		return errors.New("The specified player is not the current player.")
	}

	if p.users[m.TargetPlayerIndex].UnusedTokens.Len() < 1 {
		return errors.New("There aren't any remaining tokens for the current player to place.")
	}

	if p.game.Slots.ComponentAt(m.Slot) != nil {
		return errors.New("The specified slot is already taken.")
	}

	return nil

}

func (m *MovePlaceToken) Apply(payload boardgame.StatePayload) boardgame.StatePayload {

	result := payload.Copy()

	p := result.(*statePayload)

	u := p.users[m.TargetPlayerIndex]

	c := u.UnusedTokens.RemoveFirst()

	p.game.Slots.InsertAtSlot(c, m.Slot)

	u.TokensToPlaceThisTurn--

	return result

}

func (m *MovePlaceToken) Name() string {
	return "Place Token"
}

func (m *MovePlaceToken) Description() string {
	return "Place a player's token in a specific space."
}

func (m *MovePlaceToken) Copy() boardgame.Move {
	var result MovePlaceToken
	result = *m
	return &result
}

func (m *MovePlaceToken) Props() []string {
	return boardgame.PropertyReaderPropsImpl(m)
}

func (m *MovePlaceToken) Prop(name string) interface{} {
	return boardgame.PropertyReaderPropImpl(m, name)
}

func (m *MovePlaceToken) SetProp(name string, val interface{}) error {
	return boardgame.PropertySetImpl(m, name, val)
}

func (m *MovePlaceToken) JSON() boardgame.JSONObject {
	return m
}

type MoveAdvancePlayer struct{}

func (m *MoveAdvancePlayer) Legal(payload boardgame.StatePayload) error {
	p := payload.(*statePayload)

	user := p.users[p.game.CurrentPlayer]

	if user.TokensToPlaceThisTurn > 0 {
		return errors.New("The current player still has tokens left to place this turn.")
	}

	return nil
}

func (m *MoveAdvancePlayer) Apply(payload boardgame.StatePayload) boardgame.StatePayload {
	result := payload.Copy()

	p := result.(*statePayload)

	p.game.CurrentPlayer++

	if p.game.CurrentPlayer >= len(p.users) {
		p.game.CurrentPlayer = 0
	}

	newUser := p.users[p.game.CurrentPlayer]

	newUser.TokensToPlaceThisTurn = 1

	return result

}

func (m *MoveAdvancePlayer) Name() string {
	return "Advance Player"
}

func (m *MoveAdvancePlayer) Description() string {
	return "After the current player has made all of their moves, this fix-up move advances to the next player."
}

func (m *MoveAdvancePlayer) Copy() boardgame.Move {
	var result MoveAdvancePlayer
	result = *m
	return &result
}

func (m *MoveAdvancePlayer) JSON() boardgame.JSONObject {
	return m
}

func (m *MoveAdvancePlayer) Prop(name string) interface{} {
	return boardgame.PropertyReaderPropImpl(m, name)
}

func (m *MoveAdvancePlayer) Props() []string {
	return boardgame.PropertyReaderPropsImpl(m)
}

func (m *MoveAdvancePlayer) SetProp(name string, val interface{}) error {
	return boardgame.PropertySetImpl(m, name, val)
}
<|endoftext|>


<commit_before>package command

import (
	"os"
	"testing"

	"gotest.tools/v3/assert"
)

func contentTrustEnabled(t *testing.T) bool {
	var cli DockerCli
	assert.NilError(t, WithContentTrustFromEnv()(&cli))
	return cli.contentTrust
}

// NB: Do not t.Parallel() this test -- it messes with the process environment.
func TestWithContentTrustFromEnv(t *testing.T) {
	envvar := "DOCKER_CONTENT_TRUST"
	if orig, ok := os.LookupEnv(envvar); ok {
		defer func() {
			os.Setenv(envvar, orig)
		}()
	} else {
		defer func() {
			os.Unsetenv(envvar)
		}()
	}

	os.Setenv(envvar, "true")
	assert.Assert(t, contentTrustEnabled(t))
	os.Setenv(envvar, "false")
	assert.Assert(t, !contentTrustEnabled(t))
	os.Setenv(envvar, "invalid")
	assert.Assert(t, contentTrustEnabled(t))
	os.Unsetenv(envvar)
	assert.Assert(t, !contentTrustEnabled(t))
}
<commit_msg>linting: os.Setenv() can be replaced by `t.Setenv()` (tenv)<commit_after>package command

import (
	"os"
	"testing"

	"gotest.tools/v3/assert"
)

func contentTrustEnabled(t *testing.T) bool {
	var cli DockerCli
	assert.NilError(t, WithContentTrustFromEnv()(&cli))
	return cli.contentTrust
}

// NB: Do not t.Parallel() this test -- it messes with the process environment.
func TestWithContentTrustFromEnv(t *testing.T) {
	const envvar = "DOCKER_CONTENT_TRUST"
	t.Setenv(envvar, "true")
	assert.Check(t, contentTrustEnabled(t))
	t.Setenv(envvar, "false")
	assert.Check(t, !contentTrustEnabled(t))
	t.Setenv(envvar, "invalid")
	assert.Check(t, contentTrustEnabled(t))
	os.Unsetenv(envvar)
	assert.Check(t, !contentTrustEnabled(t))
}
<|endoftext|>


<commit_before>package image

import (
	"bytes"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"runtime"
	"sort"
	"syscall"
	"testing"

	"github.com/docker/cli/cli/command"
	"github.com/docker/cli/internal/test"
	"github.com/docker/docker/api/types"
	"github.com/docker/docker/pkg/archive"
	"github.com/gotestyourself/gotestyourself/assert"
	is "github.com/gotestyourself/gotestyourself/assert/cmp"
	"github.com/gotestyourself/gotestyourself/fs"
	"github.com/gotestyourself/gotestyourself/skip"
	"golang.org/x/net/context"
)

func TestRunBuildResetsUidAndGidInContext(t *testing.T) {
	skip.IfCondition(t, runtime.GOOS == "windows", "uid and gid not relevant on windows")
	dest := fs.NewDir(t, "test-build-context-dest")
	defer dest.Remove()

	fakeImageBuild := func(_ context.Context, context io.Reader, options types.ImageBuildOptions) (types.ImageBuildResponse, error) {
		assert.Check(t, archive.Untar(context, dest.Path(), nil))

		body := new(bytes.Buffer)
		return types.ImageBuildResponse{Body: ioutil.NopCloser(body)}, nil
	}
	cli := test.NewFakeCli(&fakeClient{imageBuildFunc: fakeImageBuild})

	dir := fs.NewDir(t, "test-build-context",
		fs.WithFile("foo", "some content", fs.AsUser(65534, 65534)),
		fs.WithFile("Dockerfile", `
			FROM alpine:3.6
			COPY foo bar /
		`),
	)
	defer dir.Remove()

	options := newBuildOptions()
	options.context = dir.Path()

	err := runBuild(cli, options)
	assert.NilError(t, err)

	files, err := ioutil.ReadDir(dest.Path())
	assert.NilError(t, err)
	for _, fileInfo := range files {
		assert.Check(t, is.Equal(uint32(0), fileInfo.Sys().(*syscall.Stat_t).Uid))
		assert.Check(t, is.Equal(uint32(0), fileInfo.Sys().(*syscall.Stat_t).Gid))
	}
}
func TestRunBuildDockerfileFromStdinWithCompress(t *testing.T) {
	dest, err := ioutil.TempDir("", "test-build-compress-dest")
	assert.NilError(t, err)
	defer os.RemoveAll(dest)

	var dockerfileName string
	fakeImageBuild := func(_ context.Context, context io.Reader, options types.ImageBuildOptions) (types.ImageBuildResponse, error) {
		buffer := new(bytes.Buffer)
		tee := io.TeeReader(context, buffer)

		assert.Check(t, archive.Untar(tee, dest, nil))
		dockerfileName = options.Dockerfile

		header := buffer.Bytes()[:10]
		assert.Check(t, is.Equal(archive.Gzip, archive.DetectCompression(header)))

		body := new(bytes.Buffer)
		return types.ImageBuildResponse{Body: ioutil.NopCloser(body)}, nil
	}

	cli := test.NewFakeCli(&fakeClient{imageBuildFunc: fakeImageBuild})
	dockerfile := bytes.NewBufferString(`
		FROM alpine:3.6
		COPY foo /
	`)
	cli.SetIn(command.NewInStream(ioutil.NopCloser(dockerfile)))

	dir, err := ioutil.TempDir("", "test-build-compress")
	assert.NilError(t, err)
	defer os.RemoveAll(dir)

	ioutil.WriteFile(filepath.Join(dir, "foo"), []byte("some content"), 0644)

	options := newBuildOptions()
	options.compress = true
	options.dockerfileName = "-"
	options.context = dir

	err = runBuild(cli, options)
	assert.NilError(t, err)

	files, err := ioutil.ReadDir(dest)
	assert.NilError(t, err)
	actual := []string{}
	for _, fileInfo := range files {
		actual = append(actual, fileInfo.Name())
	}
	sort.Strings(actual)
	assert.Check(t, is.DeepEqual([]string{dockerfileName, ".dockerignore", "foo"}, actual))
}

func TestRunBuildDockerfileOutsideContext(t *testing.T) {
	dir := fs.NewDir(t, t.Name(),
		fs.WithFile("data", "data file"),
	)
	defer dir.Remove()

	// Dockerfile outside of build-context
	df := fs.NewFile(t, t.Name(),
		fs.WithContent(`
FROM FOOBAR
COPY data /data
		`),
	)
	defer df.Remove()

	dest, err := ioutil.TempDir("", t.Name())
	assert.NilError(t, err)
	defer os.RemoveAll(dest)

	var dockerfileName string
	fakeImageBuild := func(_ context.Context, context io.Reader, options types.ImageBuildOptions) (types.ImageBuildResponse, error) {
		buffer := new(bytes.Buffer)
		tee := io.TeeReader(context, buffer)

		assert.Check(t, archive.Untar(tee, dest, nil))
		dockerfileName = options.Dockerfile

		body := new(bytes.Buffer)
		return types.ImageBuildResponse{Body: ioutil.NopCloser(body)}, nil
	}

	cli := test.NewFakeCli(&fakeClient{imageBuildFunc: fakeImageBuild})

	options := newBuildOptions()
	options.context = dir.Path()
	options.dockerfileName = df.Path()

	err = runBuild(cli, options)
	assert.NilError(t, err)

	files, err := ioutil.ReadDir(dest)
	assert.NilError(t, err)
	var actual []string
	for _, fileInfo := range files {
		actual = append(actual, fileInfo.Name())
	}
	sort.Strings(actual)
	assert.Check(t, is.DeepEqual([]string{dockerfileName, ".dockerignore", "data"}, actual))
}

// TestRunBuildFromLocalGitHubDirNonExistingRepo tests that build contexts
// starting with `github.com/` are special-cased, and the build command attempts
// to clone the remote repo.
func TestRunBuildFromGitHubSpecialCase(t *testing.T) {
	cmd := NewBuildCommand(test.NewFakeCli(nil))
	cmd.SetArgs([]string{"github.com/docker/no-such-repository"})
	cmd.SetOutput(ioutil.Discard)
	err := cmd.Execute()
	assert.ErrorContains(t, err, "unable to prepare context: unable to 'git clone'")
}

// TestRunBuildFromLocalGitHubDirNonExistingRepo tests that a local directory
// starting with `github.com` takes precedence over the `github.com` special
// case.
func TestRunBuildFromLocalGitHubDir(t *testing.T) {
	tmpDir, err := ioutil.TempDir("", "docker-build-from-local-dir-")
	assert.NilError(t, err)
	defer os.RemoveAll(tmpDir)

	buildDir := filepath.Join(tmpDir, "github.com", "docker", "no-such-repository")
	err = os.MkdirAll(buildDir, 0777)
	assert.NilError(t, err)
	err = ioutil.WriteFile(filepath.Join(buildDir, "Dockerfile"), []byte("FROM busybox\n"), 0644)
	assert.NilError(t, err)

	client := test.NewFakeCli(&fakeClient{})
	cmd := NewBuildCommand(client)
	cmd.SetArgs([]string{buildDir})
	cmd.SetOutput(ioutil.Discard)
	err = cmd.Execute()
	assert.NilError(t, err)
}
<commit_msg>dont prompt for github creds in unit test<commit_after>package image

import (
	"bytes"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"runtime"
	"sort"
	"syscall"
	"testing"

	"github.com/docker/cli/cli/command"
	"github.com/docker/cli/internal/test"
	"github.com/docker/docker/api/types"
	"github.com/docker/docker/pkg/archive"
	"github.com/gotestyourself/gotestyourself/assert"
	is "github.com/gotestyourself/gotestyourself/assert/cmp"
	"github.com/gotestyourself/gotestyourself/fs"
	"github.com/gotestyourself/gotestyourself/skip"
	"golang.org/x/net/context"
)

func TestRunBuildResetsUidAndGidInContext(t *testing.T) {
	skip.IfCondition(t, runtime.GOOS == "windows", "uid and gid not relevant on windows")
	dest := fs.NewDir(t, "test-build-context-dest")
	defer dest.Remove()

	fakeImageBuild := func(_ context.Context, context io.Reader, options types.ImageBuildOptions) (types.ImageBuildResponse, error) {
		assert.Check(t, archive.Untar(context, dest.Path(), nil))

		body := new(bytes.Buffer)
		return types.ImageBuildResponse{Body: ioutil.NopCloser(body)}, nil
	}
	cli := test.NewFakeCli(&fakeClient{imageBuildFunc: fakeImageBuild})

	dir := fs.NewDir(t, "test-build-context",
		fs.WithFile("foo", "some content", fs.AsUser(65534, 65534)),
		fs.WithFile("Dockerfile", `
			FROM alpine:3.6
			COPY foo bar /
		`),
	)
	defer dir.Remove()

	options := newBuildOptions()
	options.context = dir.Path()

	err := runBuild(cli, options)
	assert.NilError(t, err)

	files, err := ioutil.ReadDir(dest.Path())
	assert.NilError(t, err)
	for _, fileInfo := range files {
		assert.Check(t, is.Equal(uint32(0), fileInfo.Sys().(*syscall.Stat_t).Uid))
		assert.Check(t, is.Equal(uint32(0), fileInfo.Sys().(*syscall.Stat_t).Gid))
	}
}
func TestRunBuildDockerfileFromStdinWithCompress(t *testing.T) {
	dest, err := ioutil.TempDir("", "test-build-compress-dest")
	assert.NilError(t, err)
	defer os.RemoveAll(dest)

	var dockerfileName string
	fakeImageBuild := func(_ context.Context, context io.Reader, options types.ImageBuildOptions) (types.ImageBuildResponse, error) {
		buffer := new(bytes.Buffer)
		tee := io.TeeReader(context, buffer)

		assert.Check(t, archive.Untar(tee, dest, nil))
		dockerfileName = options.Dockerfile

		header := buffer.Bytes()[:10]
		assert.Check(t, is.Equal(archive.Gzip, archive.DetectCompression(header)))

		body := new(bytes.Buffer)
		return types.ImageBuildResponse{Body: ioutil.NopCloser(body)}, nil
	}

	cli := test.NewFakeCli(&fakeClient{imageBuildFunc: fakeImageBuild})
	dockerfile := bytes.NewBufferString(`
		FROM alpine:3.6
		COPY foo /
	`)
	cli.SetIn(command.NewInStream(ioutil.NopCloser(dockerfile)))

	dir, err := ioutil.TempDir("", "test-build-compress")
	assert.NilError(t, err)
	defer os.RemoveAll(dir)

	ioutil.WriteFile(filepath.Join(dir, "foo"), []byte("some content"), 0644)

	options := newBuildOptions()
	options.compress = true
	options.dockerfileName = "-"
	options.context = dir

	err = runBuild(cli, options)
	assert.NilError(t, err)

	files, err := ioutil.ReadDir(dest)
	assert.NilError(t, err)
	actual := []string{}
	for _, fileInfo := range files {
		actual = append(actual, fileInfo.Name())
	}
	sort.Strings(actual)
	assert.Check(t, is.DeepEqual([]string{dockerfileName, ".dockerignore", "foo"}, actual))
}

func TestRunBuildDockerfileOutsideContext(t *testing.T) {
	dir := fs.NewDir(t, t.Name(),
		fs.WithFile("data", "data file"),
	)
	defer dir.Remove()

	// Dockerfile outside of build-context
	df := fs.NewFile(t, t.Name(),
		fs.WithContent(`
FROM FOOBAR
COPY data /data
		`),
	)
	defer df.Remove()

	dest, err := ioutil.TempDir("", t.Name())
	assert.NilError(t, err)
	defer os.RemoveAll(dest)

	var dockerfileName string
	fakeImageBuild := func(_ context.Context, context io.Reader, options types.ImageBuildOptions) (types.ImageBuildResponse, error) {
		buffer := new(bytes.Buffer)
		tee := io.TeeReader(context, buffer)

		assert.Check(t, archive.Untar(tee, dest, nil))
		dockerfileName = options.Dockerfile

		body := new(bytes.Buffer)
		return types.ImageBuildResponse{Body: ioutil.NopCloser(body)}, nil
	}

	cli := test.NewFakeCli(&fakeClient{imageBuildFunc: fakeImageBuild})

	options := newBuildOptions()
	options.context = dir.Path()
	options.dockerfileName = df.Path()

	err = runBuild(cli, options)
	assert.NilError(t, err)

	files, err := ioutil.ReadDir(dest)
	assert.NilError(t, err)
	var actual []string
	for _, fileInfo := range files {
		actual = append(actual, fileInfo.Name())
	}
	sort.Strings(actual)
	assert.Check(t, is.DeepEqual([]string{dockerfileName, ".dockerignore", "data"}, actual))
}

// TestRunBuildFromLocalGitHubDirNonExistingRepo tests that build contexts
// starting with `github.com/` are special-cased, and the build command attempts
// to clone the remote repo.
// TODO: test "context selection" logic directly when runBuild is refactored
// to support testing (ex: docker/cli#294)
func TestRunBuildFromGitHubSpecialCase(t *testing.T) {
	cmd := NewBuildCommand(test.NewFakeCli(nil))
	// Clone a small repo that exists so git doesn't prompt for credentials
	cmd.SetArgs([]string{"github.com/docker/for-win"})
	cmd.SetOutput(ioutil.Discard)
	err := cmd.Execute()
	assert.ErrorContains(t, err, "unable to prepare context")
	assert.ErrorContains(t, err, "docker-build-git")
}

// TestRunBuildFromLocalGitHubDirNonExistingRepo tests that a local directory
// starting with `github.com` takes precedence over the `github.com` special
// case.
func TestRunBuildFromLocalGitHubDir(t *testing.T) {
	tmpDir, err := ioutil.TempDir("", "docker-build-from-local-dir-")
	assert.NilError(t, err)
	defer os.RemoveAll(tmpDir)

	buildDir := filepath.Join(tmpDir, "github.com", "docker", "no-such-repository")
	err = os.MkdirAll(buildDir, 0777)
	assert.NilError(t, err)
	err = ioutil.WriteFile(filepath.Join(buildDir, "Dockerfile"), []byte("FROM busybox\n"), 0644)
	assert.NilError(t, err)

	client := test.NewFakeCli(&fakeClient{})
	cmd := NewBuildCommand(client)
	cmd.SetArgs([]string{buildDir})
	cmd.SetOutput(ioutil.Discard)
	err = cmd.Execute()
	assert.NilError(t, err)
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package http

import (
	"bytes"
	"context"
	"io"
	"net/http"
	"time"

	"go.uber.org/yarpc/internal/errors"
	"go.uber.org/yarpc/internal/request"
	"go.uber.org/yarpc/transport"
	"go.uber.org/yarpc/transport/internal"

	"github.com/opentracing/opentracing-go"
	"github.com/opentracing/opentracing-go/ext"
)

func popHeader(h http.Header, n string) string {
	v := h.Get(n)
	h.Del(n)
	return v
}

// handler adapts a transport.Handler into a handler for net/http.
type handler struct {
	Registry transport.Registry
	Deps     transport.Deps
}

func (h handler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	start := time.Now()

	defer req.Body.Close()
	if req.Method != "POST" {
		http.NotFound(w, req)
		return
	}

	service := req.Header.Get(ServiceHeader)
	procedure := req.Header.Get(ProcedureHeader)

	err := h.callHandler(w, req, start)
	if err == nil {
		return
	}

	err = errors.AsHandlerError(service, procedure, err)
	status := http.StatusInternalServerError
	if transport.IsBadRequestError(err) {
		status = http.StatusBadRequest
	} else if transport.IsTimeoutError(err) {
		status = http.StatusGatewayTimeout
	}
	http.Error(w, err.Error(), status)
}

func (h handler) callHandler(w http.ResponseWriter, req *http.Request, start time.Time) error {
	treq := &transport.Request{
		Caller:    popHeader(req.Header, CallerHeader),
		Service:   popHeader(req.Header, ServiceHeader),
		Procedure: popHeader(req.Header, ProcedureHeader),
		Encoding:  transport.Encoding(popHeader(req.Header, EncodingHeader)),
		Headers:   applicationHeaders.FromHTTPHeaders(req.Header, transport.Headers{}),
		Body:      req.Body,
	}

	ctx := req.Context()

	v := request.Validator{Request: treq}
	ctx, cancel := v.ParseTTL(ctx, popHeader(req.Header, TTLMSHeader))
	defer cancel()

	ctx, span := h.createSpan(ctx, req, treq, start)

	treq, err := v.Validate(ctx)
	if err != nil {
		return err
	}

	spec, err := h.Registry.Choose(ctx, treq)
	if err != nil {
		return updateSpanWithErr(span, err)
	}

	switch spec.Type() {
	case transport.Unary:
		defer span.Finish()

		ctx, cancel := v.ParseTTL(ctx, popHeader(req.Header, TTLMSHeader))
		defer cancel()

		treq, err = v.ValidateUnary(ctx)
		if err != nil {
			return err
		}
		err = internal.SafelyCallUnaryHandler(ctx, spec.Unary(), start, treq, newResponseWriter(w))

	case transport.Oneway:
		treq, err = v.ValidateOneway(ctx)
		if err != nil {
			return err
		}
		err = handleOnewayRequest(ctx, span, treq, spec.Oneway())

	default:
		err = errors.UnsupportedTypeError{Transport: "HTTP", Type: string(spec.Type())}
	}

	return updateSpanWithErr(span, err)
}

func handleOnewayRequest(
	ctx context.Context,
	span opentracing.Span,
	treq *transport.Request,
	onewayHandler transport.OnewayHandler,
) error {
	// we will lose access to the body unless we read all the bytes before
	// returning from the request
	var buff bytes.Buffer
	if _, err := io.Copy(&buff, treq.Body); err != nil {
		return err
	}
	treq.Body = &buff

	go func() {
		// ensure the span lasts for length of the request in case of errors
		defer span.Finish()

		err := internal.SafelyCallOnewayHandler(ctx, onewayHandler, treq)
		updateSpanWithErr(span, err)
	}()
	return nil
}

func updateSpanWithErr(span opentracing.Span, err error) error {
	if err != nil {
		span.SetTag("error", true)
		span.LogEvent(err.Error())
	}

	return err
}

func (h handler) createSpan(ctx context.Context, req *http.Request, treq *transport.Request, start time.Time) (context.Context, opentracing.Span) {
	// Extract opentracing etc baggage from headers
	// Annotate the inbound context with a trace span
	tracer := h.Deps.Tracer()
	carrier := opentracing.HTTPHeadersCarrier(req.Header)
	parentSpanCtx, _ := tracer.Extract(opentracing.HTTPHeaders, carrier)
	// parentSpanCtx may be nil, ext.RPCServerOption handles a nil parent
	// gracefully.
	span := tracer.StartSpan(
		treq.Procedure,
		opentracing.StartTime(start),
		opentracing.Tags{
			"rpc.caller":    treq.Caller,
			"rpc.service":   treq.Service,
			"rpc.encoding":  treq.Encoding,
			"rpc.transport": "http",
		},
		ext.RPCServerOption(parentSpanCtx), // implies ChildOf
	)
	ext.PeerService.Set(span, treq.Caller)
	ctx = opentracing.ContextWithSpan(ctx, span)
	return ctx, span
}

// responseWriter adapts a http.ResponseWriter into a transport.ResponseWriter.
type responseWriter struct {
	w http.ResponseWriter
}

func newResponseWriter(w http.ResponseWriter) responseWriter {
	return responseWriter{w: w}
}

func (rw responseWriter) Write(s []byte) (int, error) {
	return rw.w.Write(s)
}

func (rw responseWriter) AddHeaders(h transport.Headers) {
	applicationHeaders.ToHTTPHeaders(h, rw.w.Header())
}

func (responseWriter) SetApplicationError() {
	// Nothing to do.
}
<commit_msg>create new context for HTTP oneway inbound requests<commit_after>// Copyright (c) 2016 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package http

import (
	"bytes"
	"context"
	"io"
	"net/http"
	"time"

	"go.uber.org/yarpc/internal/errors"
	"go.uber.org/yarpc/internal/request"
	"go.uber.org/yarpc/transport"
	"go.uber.org/yarpc/transport/internal"

	"github.com/opentracing/opentracing-go"
	"github.com/opentracing/opentracing-go/ext"
)

func popHeader(h http.Header, n string) string {
	v := h.Get(n)
	h.Del(n)
	return v
}

// handler adapts a transport.Handler into a handler for net/http.
type handler struct {
	Registry transport.Registry
	Deps     transport.Deps
}

func (h handler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	start := time.Now()

	defer req.Body.Close()
	if req.Method != "POST" {
		http.NotFound(w, req)
		return
	}

	service := req.Header.Get(ServiceHeader)
	procedure := req.Header.Get(ProcedureHeader)

	err := h.callHandler(w, req, start)
	if err == nil {
		return
	}

	err = errors.AsHandlerError(service, procedure, err)
	status := http.StatusInternalServerError
	if transport.IsBadRequestError(err) {
		status = http.StatusBadRequest
	} else if transport.IsTimeoutError(err) {
		status = http.StatusGatewayTimeout
	}
	http.Error(w, err.Error(), status)
}

func (h handler) callHandler(w http.ResponseWriter, req *http.Request, start time.Time) error {
	treq := &transport.Request{
		Caller:    popHeader(req.Header, CallerHeader),
		Service:   popHeader(req.Header, ServiceHeader),
		Procedure: popHeader(req.Header, ProcedureHeader),
		Encoding:  transport.Encoding(popHeader(req.Header, EncodingHeader)),
		Headers:   applicationHeaders.FromHTTPHeaders(req.Header, transport.Headers{}),
		Body:      req.Body,
	}

	ctx := req.Context()

	v := request.Validator{Request: treq}
	ctx, cancel := v.ParseTTL(ctx, popHeader(req.Header, TTLMSHeader))
	defer cancel()

	ctx, span := h.createSpan(ctx, req, treq, start)

	treq, err := v.Validate(ctx)
	if err != nil {
		return err
	}

	spec, err := h.Registry.Choose(ctx, treq)
	if err != nil {
		return updateSpanWithErr(span, err)
	}

	switch spec.Type() {
	case transport.Unary:
		defer span.Finish()

		ctx, cancel := v.ParseTTL(ctx, popHeader(req.Header, TTLMSHeader))
		defer cancel()

		treq, err = v.ValidateUnary(ctx)
		if err != nil {
			return err
		}
		err = internal.SafelyCallUnaryHandler(ctx, spec.Unary(), start, treq, newResponseWriter(w))

	case transport.Oneway:
		treq, err = v.ValidateOneway(ctx)
		if err != nil {
			return err
		}
		err = handleOnewayRequest(span, treq, spec.Oneway())

	default:
		err = errors.UnsupportedTypeError{Transport: "HTTP", Type: string(spec.Type())}
	}

	return updateSpanWithErr(span, err)
}

func handleOnewayRequest(
	span opentracing.Span,
	treq *transport.Request,
	onewayHandler transport.OnewayHandler,
) error {
	// we will lose access to the body unless we read all the bytes before
	// returning from the request
	var buff bytes.Buffer
	if _, err := io.Copy(&buff, treq.Body); err != nil {
		return err
	}
	treq.Body = &buff

	// create a new context for oneway requests since the HTTP handler cancels
	// http.Request's context when ServeHTTP returns
	ctx := opentracing.ContextWithSpan(context.Background(), span)

	go func() {
		// ensure the span lasts for length of the handler in case of errors
		defer span.Finish()

		err := internal.SafelyCallOnewayHandler(ctx, onewayHandler, treq)
		updateSpanWithErr(span, err)
	}()
	return nil
}

func updateSpanWithErr(span opentracing.Span, err error) error {
	if err != nil {
		span.SetTag("error", true)
		span.LogEvent(err.Error())
	}

	return err
}

func (h handler) createSpan(ctx context.Context, req *http.Request, treq *transport.Request, start time.Time) (context.Context, opentracing.Span) {
	// Extract opentracing etc baggage from headers
	// Annotate the inbound context with a trace span
	tracer := h.Deps.Tracer()
	carrier := opentracing.HTTPHeadersCarrier(req.Header)
	parentSpanCtx, _ := tracer.Extract(opentracing.HTTPHeaders, carrier)
	// parentSpanCtx may be nil, ext.RPCServerOption handles a nil parent
	// gracefully.
	span := tracer.StartSpan(
		treq.Procedure,
		opentracing.StartTime(start),
		opentracing.Tags{
			"rpc.caller":    treq.Caller,
			"rpc.service":   treq.Service,
			"rpc.encoding":  treq.Encoding,
			"rpc.transport": "http",
		},
		ext.RPCServerOption(parentSpanCtx), // implies ChildOf
	)
	ext.PeerService.Set(span, treq.Caller)
	ctx = opentracing.ContextWithSpan(ctx, span)
	return ctx, span
}

// responseWriter adapts a http.ResponseWriter into a transport.ResponseWriter.
type responseWriter struct {
	w http.ResponseWriter
}

func newResponseWriter(w http.ResponseWriter) responseWriter {
	return responseWriter{w: w}
}

func (rw responseWriter) Write(s []byte) (int, error) {
	return rw.w.Write(s)
}

func (rw responseWriter) AddHeaders(h transport.Headers) {
	applicationHeaders.ToHTTPHeaders(h, rw.w.Header())
}

func (responseWriter) SetApplicationError() {
	// Nothing to do.
}
<|endoftext|>


<commit_before>package main

func main() {

}
<commit_msg>途中だけどコミット<commit_after>package main

import (
	"github.com/pkg/errors"
	"io/ioutil"
	"fmt"
)

func main() {

	// TODO 途中.

	/*

		pkg/errors のサンプル実装

		# 参照
			https://github.com/pkg/errors

		# インストール
			go get -u github.com/pkg/errors
	*/

	err := a()
	if err != nil {
		fmt.Printf("エラーだよ. %v\n", err)
		fmt.Println("------------")
	} else {
		fmt.Println("無事に処理できました！")
	}

}

func a() error {
	err := b()
	if err != nil {
		return errors.Wrap(err, "〇〇しようと思ったけどエラー.")
	}
	return nil
}

func b() error {
	fpath := "notfound.txt"
	_, err := ioutil.ReadFile(fpath)
	if err != nil {
		return errors.Wrapf(err, "「%s」を読み込めませんでした", fpath)
	}
	return nil
}<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"time"

	"github.com/ninjasphere/go-ninja/channels"
	"github.com/ninjasphere/go-zigbee/gateway"
)

type OnOffChannel struct {
	Channel
	channel *channels.OnOffChannel
}

// -------- On/Off Protocol --------

func (c *OnOffChannel) TurnOn() error {
	return c.setState(gateway.GwOnOffStateT_ON_STATE.Enum())
}

func (c *OnOffChannel) TurnOff() error {
	return c.setState(gateway.GwOnOffStateT_OFF_STATE.Enum())
}

func (c *OnOffChannel) ToggleOnOff() error {
	return c.setState(gateway.GwOnOffStateT_TOGGLE_STATE.Enum())
}

func (c *OnOffChannel) SetOnOff(state bool) error {
	if state {
		return c.TurnOn()
	}

	return c.TurnOff()
}

func (c *OnOffChannel) init() error {
	log.Debugf("Initialising on/off channel of device %d", *c.device.deviceInfo.IeeeAddress)

	//clusterID := uint32(0x06)

	/*attributeID := uint32(0)
	minReportInterval := uint32(1)
	maxReportInterval := uint32(120)

	request := &gateway.GwSetAttributeReportingReq{
		DstAddress: &gateway.GwAddressStructT{
			AddressType: gateway.GwAddressTypeT_UNICAST.Enum(),
			IeeeAddr:    c.device.deviceInfo.IeeeAddress,
		},
		ClusterId: &clusterID,
		AttributeReportList: []*gateway.GwAttributeReportT{{
			AttributeId:       &attributeID,
			AttributeType:     gateway.GwZclAttributeDataTypesT_ZCL_DATATYPE_BOOLEAN.Enum(),
			MinReportInterval: &minReportInterval,
			MaxReportInterval: &maxReportInterval,
		}},
	}

	response := &gateway.GwSetAttributeReportingRspInd{}

	err := c.device.driver.gatewayConn.SendAsyncCommand(request, response, 20*time.Second)
	if err != nil {
		log.Errorf("Error enabling on/off reporting: %s", err)
	} else if response.Status.String() != "STATUS_SUCCESS" {
		log.Errorf("Failed to enable on/off reporting. status: %s", response.Status.String())
	}*/

	c.channel = channels.NewOnOffChannel(c)
	err = c.device.driver.Conn.ExportChannel(c.device, c.channel, c.ID)
	if err != nil {
		log.Fatalf("Failed to announce on/off channel: %s", err)
	}

	go func() {
		for {
			log.Debugf("Polling for on/off")
			err := c.fetchState()
			if err != nil {
				log.Errorf("Failed to poll for on/off state %s", err)
			}
			time.Sleep(10 * time.Second)
		}
	}()

	return nil

}

func (c *OnOffChannel) setState(state *gateway.GwOnOffStateT) error {
	request := &gateway.DevSetOnOffStateReq{
		DstAddress: &gateway.GwAddressStructT{
			AddressType: gateway.GwAddressTypeT_UNICAST.Enum(),
			IeeeAddr:    c.device.deviceInfo.IeeeAddress,
		},
		State: state,
	}

	response := &gateway.GwZigbeeGenericRspInd{}
	err := c.device.driver.gatewayConn.SendAsyncCommand(request, response, 2*time.Second)
	if err != nil {
		return fmt.Errorf("Error setting on/off state : %s", err)
	}
	if response.Status.String() != "STATUS_SUCCESS" {
		return fmt.Errorf("Failed to set on/off state. status: %s", response.Status.String())
	}

	return c.fetchState()
}

func (c *OnOffChannel) fetchState() error {
	request := &gateway.DevGetOnOffStateReq{
		DstAddress: &gateway.GwAddressStructT{
			AddressType: gateway.GwAddressTypeT_UNICAST.Enum(),
			IeeeAddr:    c.device.deviceInfo.IeeeAddress,
		},
	}

	response := &gateway.DevGetOnOffStateRspInd{}
	if c.device.driver == nil {
		log.Fatalf("assertion failed: c.device.driver != nil")
	}
	if c.device.driver.gatewayConn == nil {
		log.Fatalf("assertion failed: c.device.driver.gatewayConn != nil")
	}
	err := c.device.driver.gatewayConn.SendAsyncCommand(request, response, 10*time.Second)
	if err != nil {
		return fmt.Errorf("Error getting on/off state : %s", err)
	}
	if response.Status.String() != "STATUS_SUCCESS" {
		return fmt.Errorf("Failed to get on/off state. status: %s", response.Status.String())
	}

	c.channel.SendState(*response.StateValue == gateway.GwOnOffStateValueT_ON)

	return nil
}
<commit_msg>Only send on-off state when it changes, or when a command has been sent<commit_after>package main

import (
	"fmt"
	"time"

	"github.com/ninjasphere/go-ninja/channels"
	"github.com/ninjasphere/go-zigbee/gateway"
)

type OnOffChannel struct {
	Channel
	lastState *bool
	channel   *channels.OnOffChannel
}

// -------- On/Off Protocol --------

func (c *OnOffChannel) TurnOn() error {
	return c.setState(gateway.GwOnOffStateT_ON_STATE.Enum())
}

func (c *OnOffChannel) TurnOff() error {
	return c.setState(gateway.GwOnOffStateT_OFF_STATE.Enum())
}

func (c *OnOffChannel) ToggleOnOff() error {
	return c.setState(gateway.GwOnOffStateT_TOGGLE_STATE.Enum())
}

func (c *OnOffChannel) SetOnOff(state bool) error {
	if state {
		return c.TurnOn()
	}

	return c.TurnOff()
}

func (c *OnOffChannel) init() error {
	log.Debugf("Initialising on/off channel of device %d", *c.device.deviceInfo.IeeeAddress)

	//clusterID := uint32(0x06)

	/*attributeID := uint32(0)
	minReportInterval := uint32(1)
	maxReportInterval := uint32(120)

	request := &gateway.GwSetAttributeReportingReq{
		DstAddress: &gateway.GwAddressStructT{
			AddressType: gateway.GwAddressTypeT_UNICAST.Enum(),
			IeeeAddr:    c.device.deviceInfo.IeeeAddress,
		},
		ClusterId: &clusterID,
		AttributeReportList: []*gateway.GwAttributeReportT{{
			AttributeId:       &attributeID,
			AttributeType:     gateway.GwZclAttributeDataTypesT_ZCL_DATATYPE_BOOLEAN.Enum(),
			MinReportInterval: &minReportInterval,
			MaxReportInterval: &maxReportInterval,
		}},
	}

	response := &gateway.GwSetAttributeReportingRspInd{}

	err := c.device.driver.gatewayConn.SendAsyncCommand(request, response, 20*time.Second)
	if err != nil {
		log.Errorf("Error enabling on/off reporting: %s", err)
	} else if response.Status.String() != "STATUS_SUCCESS" {
		log.Errorf("Failed to enable on/off reporting. status: %s", response.Status.String())
	}*/

	c.channel = channels.NewOnOffChannel(c)
	err = c.device.driver.Conn.ExportChannel(c.device, c.channel, c.ID)
	if err != nil {
		log.Fatalf("Failed to announce on/off channel: %s", err)
	}

	go func() {
		for {
			log.Debugf("Polling for on/off")
			err := c.fetchState()
			if err != nil {
				log.Errorf("Failed to poll for on/off state %s", err)
			}
			time.Sleep(10 * time.Second)
		}
	}()

	return nil

}

func (c *OnOffChannel) setState(state *gateway.GwOnOffStateT) error {

	request := &gateway.DevSetOnOffStateReq{
		DstAddress: &gateway.GwAddressStructT{
			AddressType: gateway.GwAddressTypeT_UNICAST.Enum(),
			IeeeAddr:    c.device.deviceInfo.IeeeAddress,
		},
		State: state,
	}

	response := &gateway.GwZigbeeGenericRspInd{}
	err := c.device.driver.gatewayConn.SendAsyncCommand(request, response, 2*time.Second)
	if err != nil {
		return fmt.Errorf("Error setting on/off state : %s", err)
	}
	if response.Status.String() != "STATUS_SUCCESS" {
		return fmt.Errorf("Failed to set on/off state. status: %s", response.Status.String())
	}

	c.lastState = nil

	return c.fetchState()
}

func (c *OnOffChannel) fetchState() error {
	request := &gateway.DevGetOnOffStateReq{
		DstAddress: &gateway.GwAddressStructT{
			AddressType: gateway.GwAddressTypeT_UNICAST.Enum(),
			IeeeAddr:    c.device.deviceInfo.IeeeAddress,
		},
	}

	response := &gateway.DevGetOnOffStateRspInd{}
	if c.device.driver == nil {
		log.Fatalf("assertion failed: c.device.driver != nil")
	}
	if c.device.driver.gatewayConn == nil {
		log.Fatalf("assertion failed: c.device.driver.gatewayConn != nil")
	}
	err := c.device.driver.gatewayConn.SendAsyncCommand(request, response, 10*time.Second)
	if err != nil {
		return fmt.Errorf("Error getting on/off state : %s", err)
	}
	if response.Status.String() != "STATUS_SUCCESS" {
		return fmt.Errorf("Failed to get on/off state. status: %s", response.Status.String())
	}

	state := *response.StateValue == gateway.GwOnOffStateValueT_ON

	if c.lastState == nil || *c.lastState != state {
		c.lastState = &state
		c.channel.SendState(state)
	}

	return nil
}
<|endoftext|>


<commit_before>package fingerprint

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"strings"
	"time"

	cleanhttp "github.com/hashicorp/go-cleanhttp"
	log "github.com/hashicorp/go-hclog"

	"github.com/hashicorp/nomad/helper/useragent"
	"github.com/hashicorp/nomad/nomad/structs"
)

const (
	// AzureMetadataURL is where the Azure metadata server normally resides. We hardcode the
	// "instance" path as well since it's the only one we access here.
	AzureMetadataURL = "http://169.254.169.254/metadata/instance/"

	// AzureMetadataAPIVersion is the version used when contacting the Azure metadata
	// services.
	AzureMetadataAPIVersion = "2019-06-04"

	// AzureMetadataTimeout is the timeout used when contacting the Azure metadata
	// services.
	AzureMetadataTimeout = 2 * time.Second
)

type AzureMetadataTag struct {
	Name  string
	Value string
}

type AzureMetadataPair struct {
	path   string
	unique bool
}

// EnvAzureFingerprint is used to fingerprint Azure metadata
type EnvAzureFingerprint struct {
	StaticFingerprinter
	client      *http.Client
	logger      log.Logger
	metadataURL string
}

// NewEnvAzureFingerprint is used to create a fingerprint from Azure metadata
func NewEnvAzureFingerprint(logger log.Logger) Fingerprint {
	// Read the internal metadata URL from the environment, allowing test files to
	// provide their own
	metadataURL := os.Getenv("AZURE_ENV_URL")
	if metadataURL == "" {
		metadataURL = AzureMetadataURL
	}

	// assume 2 seconds is enough time for inside Azure network
	client := &http.Client{
		Timeout:   AzureMetadataTimeout,
		Transport: cleanhttp.DefaultTransport(),
	}

	return &EnvAzureFingerprint{
		client:      client,
		logger:      logger.Named("env_azure"),
		metadataURL: metadataURL,
	}
}

func (f *EnvAzureFingerprint) Get(attribute string, format string) (string, error) {
	reqURL := f.metadataURL + attribute + fmt.Sprintf("?api-version=%s&format=%s", AzureMetadataAPIVersion, format)
	parsedURL, err := url.Parse(reqURL)
	if err != nil {
		return "", err
	}

	req := &http.Request{
		Method: "GET",
		URL:    parsedURL,
		Header: http.Header{
			"Metadata":   []string{"true"},
			"User-Agent": []string{useragent.String()},
		},
	}

	res, err := f.client.Do(req)
	if err != nil {
		f.logger.Debug("could not read value for attribute", "attribute", attribute, "error", err)
		return "", err
	} else if res.StatusCode != http.StatusOK {
		f.logger.Debug("could not read value for attribute", "attribute", attribute, "resp_code", res.StatusCode)
		return "", err
	}

	resp, err := ioutil.ReadAll(res.Body)
	res.Body.Close()
	if err != nil {
		f.logger.Error("error reading response body for Azure attribute", "attribute", attribute, "error", err)
		return "", err
	}

	if res.StatusCode >= 400 {
		return "", ReqError{res.StatusCode}
	}

	return string(resp), nil
}

func checkAzureError(err error, logger log.Logger, desc string) error {
	// If it's a URL error, assume we're not actually in an Azure environment.
	// To the outer layers, this isn't an error so return nil.
	if _, ok := err.(*url.Error); ok {
		logger.Debug("error querying Azure attribute; skipping", "attribute", desc)
		return nil
	}
	// Otherwise pass the error through.
	return err
}

func (f *EnvAzureFingerprint) Fingerprint(request *FingerprintRequest, response *FingerprintResponse) error {
	cfg := request.Config

	// Check if we should tighten the timeout
	if cfg.ReadBoolDefault(TightenNetworkTimeoutsConfig, false) {
		f.client.Timeout = 1 * time.Millisecond
	}

	if !f.isAzure() {
		return nil
	}

	// Keys and whether they should be namespaced as unique. Any key whose value
	// uniquely identifies a node, such as ip, should be marked as unique. When
	// marked as unique, the key isn't included in the computed node class.
	keys := map[string]AzureMetadataPair{
		"id":             {unique: true, path: "compute/vmId"},
		"name":           {unique: true, path: "compute/name"}, // name might not be the same as hostname
		"location":       {unique: false, path: "compute/location"},
		"resource-group": {unique: false, path: "compute/resourceGroupName"},
		"scale-set":      {unique: false, path: "compute/vmScaleSetName"},
		"vm-size":        {unique: false, path: "compute/vmSize"},
		"local-ipv4":     {unique: true, path: "network/interface/0/ipv4/ipAddress/0/privateIpAddress"},
		"public-ipv4":    {unique: true, path: "network/interface/0/ipv4/ipAddress/0/publicIpAddress"},
		"local-ipv6":     {unique: true, path: "network/interface/0/ipv6/ipAddress/0/privateIpAddress"},
		"public-ipv6":    {unique: true, path: "network/interface/0/ipv6/ipAddress/0/publicIpAddress"},
		"mac":            {unique: true, path: "network/interface/0/macAddress"},
	}

	for k, attr := range keys {
		resp, err := f.Get(attr.path, "text")
		v := strings.TrimSpace(resp)
		if err != nil {
			return checkAzureError(err, f.logger, k)
		} else if v == "" {
			f.logger.Debug("read an empty value", "attribute", k)
			continue
		}

		// assume we want blank entries
		key := "platform.azure." + strings.Replace(k, "/", ".", -1)
		if attr.unique {
			key = structs.UniqueNamespace(key)
		}
		response.AddAttribute(key, v)
	}

	// copy over network specific information
	if val, ok := response.Attributes["unique.platform.azure.local-ipv4"]; ok && val != "" {
		response.AddAttribute("unique.network.ip-address", val)
	}

	var tagList []AzureMetadataTag
	value, err := f.Get("compute/tagsList", "json")
	if err != nil {
		return checkAzureError(err, f.logger, "tags")
	}
	if err := json.Unmarshal([]byte(value), &tagList); err != nil {
		f.logger.Warn("error decoding instance tags", "error", err)
	}
	for _, tag := range tagList {
		attr := "platform.azure.tag."
		var key string

		// If the tag is namespaced as unique, we strip it from the tag and
		// prepend to the whole attribute.
		if structs.IsUniqueNamespace(tag.Name) {
			tag.Name = strings.TrimPrefix(tag.Name, structs.NodeUniqueNamespace)
			key = fmt.Sprintf("%s%s%s", structs.NodeUniqueNamespace, attr, tag.Name)
		} else {
			key = fmt.Sprintf("%s%s", attr, tag.Name)
		}

		response.AddAttribute(key, tag.Value)
	}

	// populate Links
	if id, ok := response.Attributes["unique.platform.azure.id"]; ok {
		response.AddLink("azure", id)
	}

	response.Detected = true
	return nil
}

func (f *EnvAzureFingerprint) isAzure() bool {
	v, err := f.Get("compute/azEnvironment", "text")
	v = strings.TrimSpace(v)
	return err == nil && v != ""
}
<commit_msg>Add compute/zone to Azure fingerprinting<commit_after>package fingerprint

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"strings"
	"time"

	cleanhttp "github.com/hashicorp/go-cleanhttp"
	log "github.com/hashicorp/go-hclog"

	"github.com/hashicorp/nomad/helper/useragent"
	"github.com/hashicorp/nomad/nomad/structs"
)

const (
	// AzureMetadataURL is where the Azure metadata server normally resides. We hardcode the
	// "instance" path as well since it's the only one we access here.
	AzureMetadataURL = "http://169.254.169.254/metadata/instance/"

	// AzureMetadataAPIVersion is the version used when contacting the Azure metadata
	// services.
	AzureMetadataAPIVersion = "2019-06-04"

	// AzureMetadataTimeout is the timeout used when contacting the Azure metadata
	// services.
	AzureMetadataTimeout = 2 * time.Second
)

type AzureMetadataTag struct {
	Name  string
	Value string
}

type AzureMetadataPair struct {
	path   string
	unique bool
}

// EnvAzureFingerprint is used to fingerprint Azure metadata
type EnvAzureFingerprint struct {
	StaticFingerprinter
	client      *http.Client
	logger      log.Logger
	metadataURL string
}

// NewEnvAzureFingerprint is used to create a fingerprint from Azure metadata
func NewEnvAzureFingerprint(logger log.Logger) Fingerprint {
	// Read the internal metadata URL from the environment, allowing test files to
	// provide their own
	metadataURL := os.Getenv("AZURE_ENV_URL")
	if metadataURL == "" {
		metadataURL = AzureMetadataURL
	}

	// assume 2 seconds is enough time for inside Azure network
	client := &http.Client{
		Timeout:   AzureMetadataTimeout,
		Transport: cleanhttp.DefaultTransport(),
	}

	return &EnvAzureFingerprint{
		client:      client,
		logger:      logger.Named("env_azure"),
		metadataURL: metadataURL,
	}
}

func (f *EnvAzureFingerprint) Get(attribute string, format string) (string, error) {
	reqURL := f.metadataURL + attribute + fmt.Sprintf("?api-version=%s&format=%s", AzureMetadataAPIVersion, format)
	parsedURL, err := url.Parse(reqURL)
	if err != nil {
		return "", err
	}

	req := &http.Request{
		Method: "GET",
		URL:    parsedURL,
		Header: http.Header{
			"Metadata":   []string{"true"},
			"User-Agent": []string{useragent.String()},
		},
	}

	res, err := f.client.Do(req)
	if err != nil {
		f.logger.Debug("could not read value for attribute", "attribute", attribute, "error", err)
		return "", err
	} else if res.StatusCode != http.StatusOK {
		f.logger.Debug("could not read value for attribute", "attribute", attribute, "resp_code", res.StatusCode)
		return "", err
	}

	resp, err := ioutil.ReadAll(res.Body)
	res.Body.Close()
	if err != nil {
		f.logger.Error("error reading response body for Azure attribute", "attribute", attribute, "error", err)
		return "", err
	}

	if res.StatusCode >= 400 {
		return "", ReqError{res.StatusCode}
	}

	return string(resp), nil
}

func checkAzureError(err error, logger log.Logger, desc string) error {
	// If it's a URL error, assume we're not actually in an Azure environment.
	// To the outer layers, this isn't an error so return nil.
	if _, ok := err.(*url.Error); ok {
		logger.Debug("error querying Azure attribute; skipping", "attribute", desc)
		return nil
	}
	// Otherwise pass the error through.
	return err
}

func (f *EnvAzureFingerprint) Fingerprint(request *FingerprintRequest, response *FingerprintResponse) error {
	cfg := request.Config

	// Check if we should tighten the timeout
	if cfg.ReadBoolDefault(TightenNetworkTimeoutsConfig, false) {
		f.client.Timeout = 1 * time.Millisecond
	}

	if !f.isAzure() {
		return nil
	}

	// Keys and whether they should be namespaced as unique. Any key whose value
	// uniquely identifies a node, such as ip, should be marked as unique. When
	// marked as unique, the key isn't included in the computed node class.
	keys := map[string]AzureMetadataPair{
		"id":             {unique: true, path: "compute/vmId"},
		"name":           {unique: true, path: "compute/name"}, // name might not be the same as hostname
		"location":       {unique: false, path: "compute/location"},
		"resource-group": {unique: false, path: "compute/resourceGroupName"},
		"scale-set":      {unique: false, path: "compute/vmScaleSetName"},
		"vm-size":        {unique: false, path: "compute/vmSize"},
		"zone":           {unique: false, path: "compute/zone"},
		"local-ipv4":     {unique: true, path: "network/interface/0/ipv4/ipAddress/0/privateIpAddress"},
		"public-ipv4":    {unique: true, path: "network/interface/0/ipv4/ipAddress/0/publicIpAddress"},
		"local-ipv6":     {unique: true, path: "network/interface/0/ipv6/ipAddress/0/privateIpAddress"},
		"public-ipv6":    {unique: true, path: "network/interface/0/ipv6/ipAddress/0/publicIpAddress"},
		"mac":            {unique: true, path: "network/interface/0/macAddress"},
	}

	for k, attr := range keys {
		resp, err := f.Get(attr.path, "text")
		v := strings.TrimSpace(resp)
		if err != nil {
			return checkAzureError(err, f.logger, k)
		} else if v == "" {
			f.logger.Debug("read an empty value", "attribute", k)
			continue
		}

		// assume we want blank entries
		key := "platform.azure." + strings.Replace(k, "/", ".", -1)
		if attr.unique {
			key = structs.UniqueNamespace(key)
		}
		response.AddAttribute(key, v)
	}

	// copy over network specific information
	if val, ok := response.Attributes["unique.platform.azure.local-ipv4"]; ok && val != "" {
		response.AddAttribute("unique.network.ip-address", val)
	}

	var tagList []AzureMetadataTag
	value, err := f.Get("compute/tagsList", "json")
	if err != nil {
		return checkAzureError(err, f.logger, "tags")
	}
	if err := json.Unmarshal([]byte(value), &tagList); err != nil {
		f.logger.Warn("error decoding instance tags", "error", err)
	}
	for _, tag := range tagList {
		attr := "platform.azure.tag."
		var key string

		// If the tag is namespaced as unique, we strip it from the tag and
		// prepend to the whole attribute.
		if structs.IsUniqueNamespace(tag.Name) {
			tag.Name = strings.TrimPrefix(tag.Name, structs.NodeUniqueNamespace)
			key = fmt.Sprintf("%s%s%s", structs.NodeUniqueNamespace, attr, tag.Name)
		} else {
			key = fmt.Sprintf("%s%s", attr, tag.Name)
		}

		response.AddAttribute(key, tag.Value)
	}

	// populate Links
	if id, ok := response.Attributes["unique.platform.azure.id"]; ok {
		response.AddLink("azure", id)
	}

	response.Detected = true
	return nil
}

func (f *EnvAzureFingerprint) isAzure() bool {
	v, err := f.Get("compute/azEnvironment", "text")
	v = strings.TrimSpace(v)
	return err == nil && v != ""
}
<|endoftext|>


<commit_before>// Copyright ©2012 The bíogo.cluster 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 meanshift provides mean shift clustering for ℝⁿ data.
package meanshift

import (
	"code.google.com/p/biogo.cluster"
	"fmt"
)

type pnt []float64

func (p pnt) V() []float64 { return p }

type value struct {
	pnt
	w       float64
	cluster int
}

func (v *value) Weight() float64 { return v.w }
func (v *value) Cluster() int    { return v.cluster }

type center struct {
	pnt
	w       float64
	indices cluster.Indices
}

func (c *center) Members() cluster.Indices { return c.indices }

// Shifter implements a single step of the mean shift algorithm.
type Shifter interface {
	// Init initialises the Shifter with the provided data.
	Init(cluster.Interface)

	// Shift performs a single iteration of the mean shift algorithm and
	// returns the sum of squares differences between the initial state
	// and the final state.
	Shift() float64

	// Bandwidth returns the bandwidth parameter of the Shifter.
	Bandwidth() float64

	// Centers returns the cluster centers of the clustered data.
	Centers() []cluster.Center
}

// MeanShift implements data clustering using the mean shift algorithm.
type MeanShift struct {
	k       Shifter
	tol     float64
	maxIter int
	values  []value
	centers []center
	ci      []cluster.Indices
}

// New creates a new mean shift Clusterer object populated with data from an Interface value, data
// and using the Shifter k.
func New(data cluster.Interface, k Shifter, tol float64, maxIter int) *MeanShift {
	k.Init(data)
	return &MeanShift{
		k:       k,
		tol:     tol,
		maxIter: maxIter,
		values:  convert(data),
	}
}

// convert renders data to the internal float64 representation for a MeanShift.
func convert(data cluster.Interface) []value {
	va := make([]value, data.Len())
	for i := 0; i < data.Len(); i++ {
		va[i] = value{pnt: append(pnt(nil), data.Values(i)...)}
	}
	if w, ok := data.(cluster.Weighter); ok {
		for i := 0; i < data.Len(); i++ {
			va[i].w = w.Weight(i)
		}
	} else {
		for i := 0; i < data.Len(); i++ {
			va[i].w = 1
		}
	}

	return va
}

// Cluster runs a clustering of the data using the mean shift algorithm.
func (ms *MeanShift) Cluster() error {
	for i := 0; ; i++ {
		delta := ms.k.Shift()
		if delta <= ms.tol {
			break
		}
		if i > ms.maxIter {
			return fmt.Errorf("meanshift: exceeded maximum iterations: delta=%f", delta)
		}
	}

	var cen []cluster.Center
	cen = ms.k.Centers()
	ms.ci = make([]cluster.Indices, len(cen))
	ms.centers = make([]center, len(cen))
	for i, c := range cen {
		ms.ci[i] = c.Members()
		ms.centers[i] = center{pnt: c.V(), indices: ms.ci[i]}
		for _, j := range ms.ci[i] {
			ms.values[j].cluster = i
		}
	}

	return nil
}

// Total calculates the total sum of squares for the data relative to the data mean.
func (ms *MeanShift) Total() float64 {
	p := make([]float64, len(ms.values[0].pnt))

	for _, v := range ms.values {
		for i := range p {
			p[i] += v.pnt[i]
		}
	}
	inv := 1 / float64(len(ms.values))
	for i := range p {
		p[i] *= inv
	}

	var ss float64
	for _, v := range ms.values {
		for i := range p {
			d := p[i] - v.pnt[i]
			ss += d * d
		}
	}

	return ss
}

// Within calculates the sum of squares within each cluster. It returns nil if Cluster
// has not been called.
func (ms *MeanShift) Within() []float64 {
	if ms.centers == nil {
		return nil
	}
	ss := make([]float64, len(ms.centers))

	for _, v := range ms.values {
		for i := range ms.centers[0].pnt {
			d := ms.centers[v.cluster].pnt[i] - v.pnt[i]
			ss[v.cluster] += d * d
		}
	}

	return ss
}

// Centers returns the centers determined by a previous call to Cluster.
func (ms *MeanShift) Centers() []cluster.Center {
	cs := make([]cluster.Center, len(ms.centers))
	for i := range ms.centers {
		cs[i] = &ms.centers[i]
	}
	return cs
}

// Values returns a slice of the values in the MeanShift.
func (ms *MeanShift) Values() []cluster.Value {
	vs := make([]cluster.Value, len(ms.values))
	for i := range ms.values {
		vs[i] = &ms.values[i]
	}
	return vs
}
<commit_msg>meanshift: allow failed clustering to return best effort<commit_after>// Copyright ©2012 The bíogo.cluster 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 meanshift provides mean shift clustering for ℝⁿ data.
package meanshift

import (
	"code.google.com/p/biogo.cluster"
	"fmt"
)

type pnt []float64

func (p pnt) V() []float64 { return p }

type value struct {
	pnt
	w       float64
	cluster int
}

func (v *value) Weight() float64 { return v.w }
func (v *value) Cluster() int    { return v.cluster }

type center struct {
	pnt
	w       float64
	indices cluster.Indices
}

func (c *center) Members() cluster.Indices { return c.indices }

// Shifter implements a single step of the mean shift algorithm.
type Shifter interface {
	// Init initialises the Shifter with the provided data.
	Init(cluster.Interface)

	// Shift performs a single iteration of the mean shift algorithm and
	// returns the sum of squares differences between the initial state
	// and the final state.
	Shift() float64

	// Bandwidth returns the bandwidth parameter of the Shifter.
	Bandwidth() float64

	// Centers returns the cluster centers of the clustered data.
	Centers() []cluster.Center
}

// MeanShift implements data clustering using the mean shift algorithm.
type MeanShift struct {
	k       Shifter
	tol     float64
	maxIter int
	values  []value
	centers []center
	ci      []cluster.Indices
}

// New creates a new mean shift Clusterer object populated with data from an Interface value, data
// and using the Shifter k.
func New(data cluster.Interface, k Shifter, tol float64, maxIter int) *MeanShift {
	k.Init(data)
	return &MeanShift{
		k:       k,
		tol:     tol,
		maxIter: maxIter,
		values:  convert(data),
	}
}

// convert renders data to the internal float64 representation for a MeanShift.
func convert(data cluster.Interface) []value {
	va := make([]value, data.Len())
	for i := 0; i < data.Len(); i++ {
		va[i] = value{pnt: append(pnt(nil), data.Values(i)...)}
	}
	if w, ok := data.(cluster.Weighter); ok {
		for i := 0; i < data.Len(); i++ {
			va[i].w = w.Weight(i)
		}
	} else {
		for i := 0; i < data.Len(); i++ {
			va[i].w = 1
		}
	}

	return va
}

// Cluster runs a clustering of the data using the mean shift algorithm.
func (ms *MeanShift) Cluster() error {
	var err error
	for i := 0; ; i++ {
		delta := ms.k.Shift()
		if delta <= ms.tol {
			break
		}
		if i > ms.maxIter {
			err = fmt.Errorf("meanshift: exceeded maximum iterations: delta=%f", delta)
		}
	}

	var cen []cluster.Center
	cen = ms.k.Centers()
	ms.ci = make([]cluster.Indices, len(cen))
	ms.centers = make([]center, len(cen))
	for i, c := range cen {
		ms.ci[i] = c.Members()
		ms.centers[i] = center{pnt: c.V(), indices: ms.ci[i]}
		for _, j := range ms.ci[i] {
			ms.values[j].cluster = i
		}
	}

	return err
}

// Total calculates the total sum of squares for the data relative to the data mean.
func (ms *MeanShift) Total() float64 {
	p := make([]float64, len(ms.values[0].pnt))

	for _, v := range ms.values {
		for i := range p {
			p[i] += v.pnt[i]
		}
	}
	inv := 1 / float64(len(ms.values))
	for i := range p {
		p[i] *= inv
	}

	var ss float64
	for _, v := range ms.values {
		for i := range p {
			d := p[i] - v.pnt[i]
			ss += d * d
		}
	}

	return ss
}

// Within calculates the sum of squares within each cluster. It returns nil if Cluster
// has not been called.
func (ms *MeanShift) Within() []float64 {
	if ms.centers == nil {
		return nil
	}
	ss := make([]float64, len(ms.centers))

	for _, v := range ms.values {
		for i := range ms.centers[0].pnt {
			d := ms.centers[v.cluster].pnt[i] - v.pnt[i]
			ss[v.cluster] += d * d
		}
	}

	return ss
}

// Centers returns the centers determined by a previous call to Cluster.
func (ms *MeanShift) Centers() []cluster.Center {
	cs := make([]cluster.Center, len(ms.centers))
	for i := range ms.centers {
		cs[i] = &ms.centers[i]
	}
	return cs
}

// Values returns a slice of the values in the MeanShift.
func (ms *MeanShift) Values() []cluster.Value {
	vs := make([]cluster.Value, len(ms.values))
	for i := range ms.values {
		vs[i] = &ms.values[i]
	}
	return vs
}
<|endoftext|>


<commit_before>package client

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

	"github.com/docker/distribution/reference"
	"github.com/docker/distribution/registry/client/auth"
	"github.com/docker/distribution/registry/client/transport"
	authtypes "github.com/docker/docker/api/types"
	"github.com/docker/docker/registry"
	"github.com/pkg/errors"
)

type repositoryEndpoint struct {
	info     *registry.RepositoryInfo
	endpoint registry.APIEndpoint
}

// Name returns the repository name
func (r repositoryEndpoint) Name() string {
	repoName := r.info.Name.Name()
	// If endpoint does not support CanonicalName, use the RemoteName instead
	if r.endpoint.TrimHostname {
		repoName = reference.Path(r.info.Name)
	}
	return repoName
}

// BaseURL returns the endpoint url
func (r repositoryEndpoint) BaseURL() string {
	return r.endpoint.URL.String()
}

func newDefaultRepositoryEndpoint(ref reference.Named, insecure bool) (repositoryEndpoint, error) {
	repoInfo, err := registry.ParseRepositoryInfo(ref)
	if err != nil {
		return repositoryEndpoint{}, err
	}
	endpoint, err := getDefaultEndpointFromRepoInfo(repoInfo)
	if err != nil {
		return repositoryEndpoint{}, err
	}
	if insecure {
		endpoint.TLSConfig.InsecureSkipVerify = true
	}
	return repositoryEndpoint{info: repoInfo, endpoint: endpoint}, nil
}

func getDefaultEndpointFromRepoInfo(repoInfo *registry.RepositoryInfo) (registry.APIEndpoint, error) {
	var err error

	options := registry.ServiceOptions{}
	registryService, err := registry.NewService(options)
	if err != nil {
		return registry.APIEndpoint{}, err
	}
	endpoints, err := registryService.LookupPushEndpoints(reference.Domain(repoInfo.Name))
	if err != nil {
		return registry.APIEndpoint{}, err
	}
	// Default to the highest priority endpoint to return
	endpoint := endpoints[0]
	if !repoInfo.Index.Secure {
		for _, ep := range endpoints {
			if ep.URL.Scheme == "http" {
				endpoint = ep
			}
		}
	}
	return endpoint, nil
}

// getHTTPTransport builds a transport for use in communicating with a registry
func getHTTPTransport(authConfig authtypes.AuthConfig, endpoint registry.APIEndpoint, repoName string, userAgent string) (http.RoundTripper, error) {
	// get the http transport, this will be used in a client to upload manifest
	base := &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		Dial: (&net.Dialer{
			Timeout:   30 * time.Second,
			KeepAlive: 30 * time.Second,
			DualStack: true,
		}).Dial,
		TLSHandshakeTimeout: 10 * time.Second,
		TLSClientConfig:     endpoint.TLSConfig,
		DisableKeepAlives:   true,
	}

	modifiers := registry.Headers(userAgent, http.Header{})
	authTransport := transport.NewTransport(base, modifiers...)
	challengeManager, confirmedV2, err := registry.PingV2Registry(endpoint.URL, authTransport)
	if err != nil {
		return nil, errors.Wrap(err, "error pinging v2 registry")
	}
	if !confirmedV2 {
		return nil, fmt.Errorf("unsupported registry version")
	}
	if authConfig.RegistryToken != "" {
		passThruTokenHandler := &existingTokenHandler{token: authConfig.RegistryToken}
		modifiers = append(modifiers, auth.NewAuthorizer(challengeManager, passThruTokenHandler))
	} else {
		creds := registry.NewStaticCredentialStore(&authConfig)
		tokenHandler := auth.NewTokenHandler(authTransport, creds, repoName, "*")
		basicHandler := auth.NewBasicHandler(creds)
		modifiers = append(modifiers, auth.NewAuthorizer(challengeManager, tokenHandler, basicHandler))
	}
	return transport.NewTransport(base, modifiers...), nil
}

// RepoNameForReference returns the repository name from a reference
func RepoNameForReference(ref reference.Named) (string, error) {
	// insecure is fine since this only returns the name
	repo, err := newDefaultRepositoryEndpoint(ref, false)
	if err != nil {
		return "", err
	}
	return repo.Name(), nil
}

type existingTokenHandler struct {
	token string
}

func (th *existingTokenHandler) AuthorizeRequest(req *http.Request, params map[string]string) error {
	req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", th.token))
	return nil
}

func (th *existingTokenHandler) Scheme() string {
	return "bearer"
}
<commit_msg>specify specific permissions<commit_after>package client

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

	"github.com/docker/distribution/reference"
	"github.com/docker/distribution/registry/client/auth"
	"github.com/docker/distribution/registry/client/transport"
	authtypes "github.com/docker/docker/api/types"
	"github.com/docker/docker/registry"
	"github.com/pkg/errors"
)

type repositoryEndpoint struct {
	info     *registry.RepositoryInfo
	endpoint registry.APIEndpoint
}

// Name returns the repository name
func (r repositoryEndpoint) Name() string {
	repoName := r.info.Name.Name()
	// If endpoint does not support CanonicalName, use the RemoteName instead
	if r.endpoint.TrimHostname {
		repoName = reference.Path(r.info.Name)
	}
	return repoName
}

// BaseURL returns the endpoint url
func (r repositoryEndpoint) BaseURL() string {
	return r.endpoint.URL.String()
}

func newDefaultRepositoryEndpoint(ref reference.Named, insecure bool) (repositoryEndpoint, error) {
	repoInfo, err := registry.ParseRepositoryInfo(ref)
	if err != nil {
		return repositoryEndpoint{}, err
	}
	endpoint, err := getDefaultEndpointFromRepoInfo(repoInfo)
	if err != nil {
		return repositoryEndpoint{}, err
	}
	if insecure {
		endpoint.TLSConfig.InsecureSkipVerify = true
	}
	return repositoryEndpoint{info: repoInfo, endpoint: endpoint}, nil
}

func getDefaultEndpointFromRepoInfo(repoInfo *registry.RepositoryInfo) (registry.APIEndpoint, error) {
	var err error

	options := registry.ServiceOptions{}
	registryService, err := registry.NewService(options)
	if err != nil {
		return registry.APIEndpoint{}, err
	}
	endpoints, err := registryService.LookupPushEndpoints(reference.Domain(repoInfo.Name))
	if err != nil {
		return registry.APIEndpoint{}, err
	}
	// Default to the highest priority endpoint to return
	endpoint := endpoints[0]
	if !repoInfo.Index.Secure {
		for _, ep := range endpoints {
			if ep.URL.Scheme == "http" {
				endpoint = ep
			}
		}
	}
	return endpoint, nil
}

// getHTTPTransport builds a transport for use in communicating with a registry
func getHTTPTransport(authConfig authtypes.AuthConfig, endpoint registry.APIEndpoint, repoName string, userAgent string) (http.RoundTripper, error) {
	// get the http transport, this will be used in a client to upload manifest
	base := &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		Dial: (&net.Dialer{
			Timeout:   30 * time.Second,
			KeepAlive: 30 * time.Second,
			DualStack: true,
		}).Dial,
		TLSHandshakeTimeout: 10 * time.Second,
		TLSClientConfig:     endpoint.TLSConfig,
		DisableKeepAlives:   true,
	}

	modifiers := registry.Headers(userAgent, http.Header{})
	authTransport := transport.NewTransport(base, modifiers...)
	challengeManager, confirmedV2, err := registry.PingV2Registry(endpoint.URL, authTransport)
	if err != nil {
		return nil, errors.Wrap(err, "error pinging v2 registry")
	}
	if !confirmedV2 {
		return nil, fmt.Errorf("unsupported registry version")
	}
	if authConfig.RegistryToken != "" {
		passThruTokenHandler := &existingTokenHandler{token: authConfig.RegistryToken}
		modifiers = append(modifiers, auth.NewAuthorizer(challengeManager, passThruTokenHandler))
	} else {
		creds := registry.NewStaticCredentialStore(&authConfig)
		tokenHandler := auth.NewTokenHandler(authTransport, creds, repoName, "push", "pull")
		basicHandler := auth.NewBasicHandler(creds)
		modifiers = append(modifiers, auth.NewAuthorizer(challengeManager, tokenHandler, basicHandler))
	}
	return transport.NewTransport(base, modifiers...), nil
}

// RepoNameForReference returns the repository name from a reference
func RepoNameForReference(ref reference.Named) (string, error) {
	// insecure is fine since this only returns the name
	repo, err := newDefaultRepositoryEndpoint(ref, false)
	if err != nil {
		return "", err
	}
	return repo.Name(), nil
}

type existingTokenHandler struct {
	token string
}

func (th *existingTokenHandler) AuthorizeRequest(req *http.Request, params map[string]string) error {
	req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", th.token))
	return nil
}

func (th *existingTokenHandler) Scheme() string {
	return "bearer"
}
<|endoftext|>


<commit_before>package igc

import (
	"bytes"
	"testing"

	"github.com/d4l3k/messagediff"
	"github.com/twpayne/go-geom"
)

func TestDecode(t *testing.T) {
	for _, tc := range []struct {
		s string
		t *T
	}{
		{
			s: "AXTR20C38FF2C110\r\n" +
				"HFDTE151115\r\n" +
				"B1316284654230N00839078EA0147801630\r\n",
			t: &T{
				Headers: []Header{
					{Source: "F", Key: "DTE", KeyExtra: "", Value: "151115"},
				},
				LineString: geom.NewLineString(geom.Layout(5)).MustSetCoords([]geom.Coord{
					{8.6513, 46.90383333333333, 1630, 1447593388, 1478},
				}),
			},
		},
		{
			s: "ACPP274CPILOT - s/n:11002274\r\n" +
				"HFDTE020613\r\n" +
				"I033638FXA3940SIU4141TDS\r\n" +
				"B1053525151892N00203986WA0017900275000108\r\n",
			t: &T{
				Headers: []Header{
					{Source: "F", Key: "DTE", KeyExtra: "", Value: "020613"},
				},
				LineString: geom.NewLineString(geom.Layout(5)).MustSetCoords([]geom.Coord{
					{-2.0664333333333333, 51.864866666666664, 275, 1370170432.8, 179},
				}),
			},
		},
		{
			s: "AXCC64BCompCheck-3.2\r\n" +
				"HFDTE100810\r\n" +
				"I033637LAD3839LOD4040TDS\r\n" +
				"B1146174031985N00726775WA010040114912340",
			t: &T{
				Headers: []Header{
					{Source: "F", Key: "DTE", KeyExtra: "", Value: "100810"},
				},
				LineString: geom.NewLineString(geom.Layout(5)).MustSetCoords([]geom.Coord{
					{-7.446255666666667, 40.53308533333333, 1149, 1281440777, 1004},
				}),
			},
		},
		{
			s: "AXGD Flymaster LiveSD  SN03142  SW1.07b\r\n" +
				"HFDTEDATE:220418,01\r\n" +
				"B1316284654230N00839078EA0147801630\r\n",
			t: &T{
				Headers: []Header{
					{Source: "F", Key: "DTE", KeyExtra: "DATE", Value: "220418,01"},
				},
				LineString: geom.NewLineString(geom.Layout(5)).MustSetCoords([]geom.Coord{
					{8.6513, 46.90383333333333, 1630, 1524402988, 1478},
				}),
			},
		},
	} {
		got, err := Read(bytes.NewBufferString(tc.s))
		diff, equal := messagediff.PrettyDiff(tc.t, got)
		if err != nil || !equal {
			t.Errorf("Read(...(%#v)) == %#v, %v, want nil, %#v\n%s", tc.s, got, err, tc.t, diff)
		}
	}
}

func TestDecodeHeaders(t *testing.T) {
	for _, tc := range []struct {
		s string
		t *T
	}{
		{
			s: "AFLY05094\r\n" +
				"HFDTE210407\r\n" +
				"HFFXA100\r\n" +
				"HFPLTPILOT:Tom Payne\r\n" +
				"HFGTYGLIDERTYPE:Gradient Aspen\r\n" +
				"HFGIDGLIDERID:G12242505057\r\n" +
				"HFDTM100GPSDATUM:WGS84\r\n" +
				"HFGPSGPS:FURUNO GH-80\r\n" +
				"HFRFWFIRMWAREVERSION:1.16\r\n" +
				"HFRHWHARDWAREVERSION:1.00\r\n" +
				"HFFTYFRTYPE:FLYTEC,5020\r\n",
			t: &T{
				Headers: []Header{
					{Source: "F", Key: "DTE", KeyExtra: "", Value: "210407"},
					{Source: "F", Key: "FXA", KeyExtra: "", Value: "100"},
					{Source: "F", Key: "PLT", KeyExtra: "PILOT", Value: "Tom Payne"},
					{Source: "F", Key: "GTY", KeyExtra: "GLIDERTYPE", Value: "Gradient Aspen"},
					{Source: "F", Key: "GID", KeyExtra: "GLIDERID", Value: "G12242505057"},
					{Source: "F", Key: "DTM", KeyExtra: "100GPSDATUM", Value: "WGS84"},
					{Source: "F", Key: "GPS", KeyExtra: "GPS", Value: "FURUNO GH-80"},
					{Source: "F", Key: "RFW", KeyExtra: "FIRMWAREVERSION", Value: "1.16"},
					{Source: "F", Key: "RHW", KeyExtra: "HARDWAREVERSION", Value: "1.00"},
					{Source: "F", Key: "FTY", KeyExtra: "FRTYPE", Value: "FLYTEC,5020"},
				},
			},
		},
	} {
		got, err := Read(bytes.NewBufferString(tc.s))
		diff, equal := messagediff.PrettyDiff(got.Headers, tc.t.Headers)
		if err != nil || !equal {
			t.Errorf("Read(...(%#v)) == %#v, %v, want nil, %#v\n%s", tc.s, got, err, tc.t, diff)
		}
	}
}
<commit_msg>Print diffs in tests<commit_after>package igc

import (
	"bytes"
	"testing"

	"github.com/d4l3k/messagediff"
	"github.com/twpayne/go-geom"
)

func TestDecode(t *testing.T) {
	for _, tc := range []struct {
		s string
		t *T
	}{
		{
			s: "AXTR20C38FF2C110\r\n" +
				"HFDTE151115\r\n" +
				"B1316284654230N00839078EA0147801630\r\n",
			t: &T{
				Headers: []Header{
					{Source: "F", Key: "DTE", KeyExtra: "", Value: "151115"},
				},
				LineString: geom.NewLineString(geom.Layout(5)).MustSetCoords([]geom.Coord{
					{8.6513, 46.90383333333333, 1630, 1447593388, 1478},
				}),
			},
		},
		{
			s: "ACPP274CPILOT - s/n:11002274\r\n" +
				"HFDTE020613\r\n" +
				"I033638FXA3940SIU4141TDS\r\n" +
				"B1053525151892N00203986WA0017900275000108\r\n",
			t: &T{
				Headers: []Header{
					{Source: "F", Key: "DTE", KeyExtra: "", Value: "020613"},
				},
				LineString: geom.NewLineString(geom.Layout(5)).MustSetCoords([]geom.Coord{
					{-2.0664333333333333, 51.864866666666664, 275, 1370170432.8, 179},
				}),
			},
		},
		{
			s: "AXCC64BCompCheck-3.2\r\n" +
				"HFDTE100810\r\n" +
				"I033637LAD3839LOD4040TDS\r\n" +
				"B1146174031985N00726775WA010040114912340",
			t: &T{
				Headers: []Header{
					{Source: "F", Key: "DTE", KeyExtra: "", Value: "100810"},
				},
				LineString: geom.NewLineString(geom.Layout(5)).MustSetCoords([]geom.Coord{
					{-7.446255666666667, 40.53308533333333, 1149, 1281440777, 1004},
				}),
			},
		},
		{
			s: "AXGD Flymaster LiveSD  SN03142  SW1.07b\r\n" +
				"HFDTEDATE:220418,01\r\n" +
				"B1316284654230N00839078EA0147801630\r\n",
			t: &T{
				Headers: []Header{
					{Source: "F", Key: "DTE", KeyExtra: "DATE", Value: "220418,01"},
				},
				LineString: geom.NewLineString(geom.Layout(5)).MustSetCoords([]geom.Coord{
					{8.6513, 46.90383333333333, 1630, 1524402988, 1478},
				}),
			},
		},
	} {
		got, err := Read(bytes.NewBufferString(tc.s))
		diff, equal := "", true
		if err == nil {
			diff, equal = messagediff.PrettyDiff(tc.t, got)
		}
		if err != nil || !equal {
			t.Errorf("Read(...(%#v)) == %#v, %v, want nil, %#v\n%s", tc.s, got, err, tc.t, diff)
		}
	}
}

func TestDecodeHeaders(t *testing.T) {
	for _, tc := range []struct {
		s string
		t *T
	}{
		{
			s: "AFLY05094\r\n" +
				"HFDTE210407\r\n" +
				"HFFXA100\r\n" +
				"HFPLTPILOT:Tom Payne\r\n" +
				"HFGTYGLIDERTYPE:Gradient Aspen\r\n" +
				"HFGIDGLIDERID:G12242505057\r\n" +
				"HFDTM100GPSDATUM:WGS84\r\n" +
				"HFGPSGPS:FURUNO GH-80\r\n" +
				"HFRFWFIRMWAREVERSION:1.16\r\n" +
				"HFRHWHARDWAREVERSION:1.00\r\n" +
				"HFFTYFRTYPE:FLYTEC,5020\r\n",
			t: &T{
				Headers: []Header{
					{Source: "F", Key: "DTE", KeyExtra: "", Value: "210407"},
					{Source: "F", Key: "FXA", KeyExtra: "", Value: "100"},
					{Source: "F", Key: "PLT", KeyExtra: "PILOT", Value: "Tom Payne"},
					{Source: "F", Key: "GTY", KeyExtra: "GLIDERTYPE", Value: "Gradient Aspen"},
					{Source: "F", Key: "GID", KeyExtra: "GLIDERID", Value: "G12242505057"},
					{Source: "F", Key: "DTM", KeyExtra: "100GPSDATUM", Value: "WGS84"},
					{Source: "F", Key: "GPS", KeyExtra: "GPS", Value: "FURUNO GH-80"},
					{Source: "F", Key: "RFW", KeyExtra: "FIRMWAREVERSION", Value: "1.16"},
					{Source: "F", Key: "RHW", KeyExtra: "HARDWAREVERSION", Value: "1.00"},
					{Source: "F", Key: "FTY", KeyExtra: "FRTYPE", Value: "FLYTEC,5020"},
				},
			},
		},
	} {
		got, err := Read(bytes.NewBufferString(tc.s))
		diff, equal := "", true
		if err == nil {
			diff, equal = messagediff.PrettyDiff(tc.t.Headers, got.Headers)
		}
		if err != nil || !equal {
			t.Errorf("Read(...(%#v)) == %#v, %v, want nil, %#v\n%s", tc.s, got, err, tc.t, diff)
		}
	}
}
<|endoftext|>


<commit_before><commit_msg>Made local runs also output log data.<commit_after><|endoftext|>


<commit_before>// +build !linux

package main

import (
	"fmt"
	"os"
)

func main() {
	fmt.Println(
		"this driver was built on a non-linux machine, so it is " +
			"unavailable. Please re-build minikube on a linux machine to enable " +
			"it.",
	)
	os.Exit(1)
}
<commit_msg>Adding proper boilerplate<commit_after>// +build !linux

/*
Copyright 2016 The Kubernetes Authors All rights reserved.

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

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

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

package main

import (
	"fmt"
	"os"
)

func main() {
	fmt.Println(
		"this driver was built on a non-linux machine, so it is " +
			"unavailable. Please re-build minikube on a linux machine to enable " +
			"it.",
	)
	os.Exit(1)
}
<|endoftext|>


<commit_before>package mirror

import (
	"fmt"
	"net/http"
	_ "net/http/pprof"
	"os"
	"strings"
	"sync"
	"syscall"
	"time"

	"github.com/Shopify/sarama"
	"github.com/funkygao/gafka"
	"github.com/funkygao/gafka/ctx"
	"github.com/funkygao/gafka/zk"
	"github.com/funkygao/golib/gofmt"
	"github.com/funkygao/golib/ratelimiter"
	"github.com/funkygao/golib/signal"
	log "github.com/funkygao/log4go"
)

// target kafka auto.create.topics.enable=true
type Mirror struct {
	Config

	quit chan struct{}
	once sync.Once

	transferN     int64
	transferBytes int64

	bandwidthRateLimiter *ratelimiter.LeakyBucket
}

func New(cf *Config) *Mirror {
	return &Mirror{Config: *cf}
}

func (this *Mirror) Main() (exitCode int) {
	this.quit = make(chan struct{})
	signal.RegisterHandler(func(sig os.Signal) {
		log.Info("received signal: %s", strings.ToUpper(sig.String()))
		log.Info("quiting...")

		this.once.Do(func() {
			close(this.quit)
		})
	}, syscall.SIGINT, syscall.SIGTERM)

	limit := (1 << 20) * this.BandwidthLimit / 8
	if this.BandwidthLimit > 0 {
		this.bandwidthRateLimiter = ratelimiter.NewLeakyBucket(limit*10, time.Second*10)
	}

	log.Info("starting mirror@%s", gafka.BuildId)

	// pprof
	debugAddr := ":10009"
	go http.ListenAndServe(debugAddr, nil)
	log.Info("pprof ready on %s", debugAddr)

	z1 := zk.NewZkZone(zk.DefaultConfig(this.Z1, ctx.ZoneZkAddrs(this.Z1)))
	z2 := zk.NewZkZone(zk.DefaultConfig(this.Z2, ctx.ZoneZkAddrs(this.Z2)))
	c1 := z1.NewCluster(this.C1)
	c2 := z2.NewCluster(this.C2)

	this.runMirror(c1, c2, limit)

	log.Info("bye mirror@%s", gafka.BuildId)
	log.Close()

	return
}

func (this *Mirror) runMirror(c1, c2 *zk.ZkCluster, limit int64) {
	log.Info("start [%s/%s] -> [%s/%s] with bandwidth %sbps",
		c1.ZkZone().Name(), c1.Name(),
		c2.ZkZone().Name(), c2.Name(),
		gofmt.Comma(limit*8))

	pub, err := this.makePub(c2)
	if err != nil {
		panic(err)
	}
	log.Trace("pub[%s/%s] made", c2.ZkZone().Name(), c2.Name())

	go func(pub sarama.AsyncProducer, c *zk.ZkCluster) {
		for {
			select {
			case <-this.quit:
				return

			case err := <-pub.Errors():
				// TODO
				log.Error("pub[%s/%s] %v", c.ZkZone().Name(), c.Name(), err)
			}
		}
	}(pub, c2)

	group := this.groupName(c1, c2)
	ever := true
	for ever {
		topics, topicsChanges, err := c1.WatchTopics()
		if err != nil {
			log.Error("[%s/%s]watch topics: %v", c1.ZkZone().Name(), c1.Name(), err)
			time.Sleep(time.Second * 10)
			continue
		}

		// TODO remove '__consumer_offsets' from topics
		sub, err := this.makeSub(c1, group, topics)
		if err != nil {
			// TODO how to handle this err?
			log.Error(err)
			time.Sleep(time.Second * 10)
		}

		log.Info("starting pump [%s/%s] -> [%s/%s] with group %s",
			c1.ZkZone().Name(), c1.Name(),
			c2.ZkZone().Name(), c2.Name(), group)

		pumpStopper := make(chan struct{})
		pumpStopped := make(chan struct{})
		go this.pump(sub, pub, pumpStopper, pumpStopped)

		select {
		case <-topicsChanges:
			// TODO log the diff the topics
			log.Warn("[%s/%s] topics changed, stopping pump...", c1.Name(), c2.Name())
			pumpStopper <- struct{}{} // stop pump
			<-pumpStopped             // await pump cleanup

			// refresh c1 topics
			topics, err = c1.Topics()
			if err != nil {
				// TODO how to handle this err?
				log.Error(err)
				time.Sleep(time.Second * 10)
			}

			log.Info("[%s/%s] topics: %+v", c1.ZkZone().Name(), c1.Name(), topics)

		case <-this.quit:
			log.Info("awaiting pump cleanup...")
			<-pumpStopped

			ever = false

		case <-pumpStopped:
			// pump encounters problems, just retry
			log.Warn("pump stopped for ?")
		}
	}

	log.Info("total transferred: %s %smsgs",
		gofmt.ByteSize(this.transferBytes),
		gofmt.Comma(this.transferN))

	log.Info("closing pub...")
	pub.Close()
}

func (this *Mirror) groupName(c1, c2 *zk.ZkCluster) string {
	return fmt.Sprintf("_mirror_.%s.%s.%s.%s", c1.ZkZone().Name(), c1.Name(), c2.ZkZone().Name(), c2.Name())
}
<commit_msg>record life span of mirror<commit_after>package mirror

import (
	"fmt"
	"net/http"
	_ "net/http/pprof"
	"os"
	"strings"
	"sync"
	"syscall"
	"time"

	"github.com/Shopify/sarama"
	"github.com/funkygao/gafka"
	"github.com/funkygao/gafka/ctx"
	"github.com/funkygao/gafka/zk"
	"github.com/funkygao/golib/gofmt"
	"github.com/funkygao/golib/ratelimiter"
	"github.com/funkygao/golib/signal"
	log "github.com/funkygao/log4go"
)

// target kafka auto.create.topics.enable=true
type Mirror struct {
	Config

	startedAt time.Time
	quit      chan struct{}
	once      sync.Once

	transferN     int64
	transferBytes int64

	bandwidthRateLimiter *ratelimiter.LeakyBucket
}

func New(cf *Config) *Mirror {
	return &Mirror{Config: *cf}
}

func (this *Mirror) Main() (exitCode int) {
	this.quit = make(chan struct{})
	signal.RegisterHandler(func(sig os.Signal) {
		log.Info("received signal: %s", strings.ToUpper(sig.String()))
		log.Info("quiting...")

		this.once.Do(func() {
			close(this.quit)
		})
	}, syscall.SIGINT, syscall.SIGTERM)

	limit := (1 << 20) * this.BandwidthLimit / 8
	if this.BandwidthLimit > 0 {
		this.bandwidthRateLimiter = ratelimiter.NewLeakyBucket(limit*10, time.Second*10)
	}

	log.Info("starting mirror@%s", gafka.BuildId)

	// pprof
	debugAddr := ":10009"
	go http.ListenAndServe(debugAddr, nil)
	log.Info("pprof ready on %s", debugAddr)

	z1 := zk.NewZkZone(zk.DefaultConfig(this.Z1, ctx.ZoneZkAddrs(this.Z1)))
	z2 := zk.NewZkZone(zk.DefaultConfig(this.Z2, ctx.ZoneZkAddrs(this.Z2)))
	c1 := z1.NewCluster(this.C1)
	c2 := z2.NewCluster(this.C2)

	this.runMirror(c1, c2, limit)

	log.Info("bye mirror@%s, %s", gafka.BuildId, time.Since(this.startedAt))
	log.Close()

	return
}

func (this *Mirror) runMirror(c1, c2 *zk.ZkCluster, limit int64) {
	this.startedAt = time.Now()

	log.Info("start [%s/%s] -> [%s/%s] with bandwidth %sbps",
		c1.ZkZone().Name(), c1.Name(),
		c2.ZkZone().Name(), c2.Name(),
		gofmt.Comma(limit*8))

	pub, err := this.makePub(c2)
	if err != nil {
		panic(err)
	}
	log.Trace("pub[%s/%s] made", c2.ZkZone().Name(), c2.Name())

	go func(pub sarama.AsyncProducer, c *zk.ZkCluster) {
		for {
			select {
			case <-this.quit:
				return

			case err := <-pub.Errors():
				// TODO
				log.Error("pub[%s/%s] %v", c.ZkZone().Name(), c.Name(), err)
			}
		}
	}(pub, c2)

	group := this.groupName(c1, c2)
	ever := true
	for ever {
		topics, topicsChanges, err := c1.WatchTopics()
		if err != nil {
			log.Error("[%s/%s]watch topics: %v", c1.ZkZone().Name(), c1.Name(), err)
			time.Sleep(time.Second * 10)
			continue
		}

		// TODO remove '__consumer_offsets' from topics
		sub, err := this.makeSub(c1, group, topics)
		if err != nil {
			// TODO how to handle this err?
			log.Error(err)
			time.Sleep(time.Second * 10)
		}

		log.Info("starting pump [%s/%s] -> [%s/%s] with group %s",
			c1.ZkZone().Name(), c1.Name(),
			c2.ZkZone().Name(), c2.Name(), group)

		pumpStopper := make(chan struct{})
		pumpStopped := make(chan struct{})
		go this.pump(sub, pub, pumpStopper, pumpStopped)

		select {
		case <-topicsChanges:
			// TODO log the diff the topics
			log.Warn("[%s/%s] topics changed, stopping pump...", c1.Name(), c2.Name())
			pumpStopper <- struct{}{} // stop pump
			<-pumpStopped             // await pump cleanup

			// refresh c1 topics
			topics, err = c1.Topics()
			if err != nil {
				// TODO how to handle this err?
				log.Error(err)
				time.Sleep(time.Second * 10)
			}

			log.Info("[%s/%s] topics: %+v", c1.ZkZone().Name(), c1.Name(), topics)

		case <-this.quit:
			log.Info("awaiting pump cleanup...")
			<-pumpStopped

			ever = false

		case <-pumpStopped:
			// pump encounters problems, just retry
			log.Warn("pump stopped for ?")
		}
	}

	log.Info("total transferred: %s %smsgs",
		gofmt.ByteSize(this.transferBytes),
		gofmt.Comma(this.transferN))

	log.Info("closing pub...")
	pub.Close()
}

func (this *Mirror) groupName(c1, c2 *zk.ZkCluster) string {
	return fmt.Sprintf("_mirror_.%s.%s.%s.%s", c1.ZkZone().Name(), c1.Name(), c2.ZkZone().Name(), c2.Name())
}
<|endoftext|>


<commit_before>package swarm

import (
	"errors"
	"fmt"

	spipe "github.com/jbenet/go-ipfs/crypto/spipe"
	conn "github.com/jbenet/go-ipfs/net/conn"
	msg "github.com/jbenet/go-ipfs/net/message"
	version "github.com/jbenet/go-ipfs/net/version"

	proto "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto"
	ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
	manet "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr/net"
)

// Open listeners for each network the swarm should listen on
func (s *Swarm) listen() error {
	hasErr := false
	retErr := &ListenErr{
		Errors: make([]error, len(s.local.Addresses)),
	}

	// listen on every address
	for i, addr := range s.local.Addresses {
		err := s.connListen(addr)
		if err != nil {
			hasErr = true
			retErr.Errors[i] = err
			log.Error("Failed to listen on: %s - %s", addr, err)
		}
	}

	if hasErr {
		return retErr
	}
	return nil
}

// Listen for new connections on the given multiaddr
func (s *Swarm) connListen(maddr ma.Multiaddr) error {
	list, err := manet.Listen(maddr)
	if err != nil {
		return err
	}

	// NOTE: this may require a lock around it later. currently, only run on setup
	s.listeners = append(s.listeners, list)

	// Accept and handle new connections on this listener until it errors
	go func() {
		for {
			nconn, err := list.Accept()
			if err != nil {
				e := fmt.Errorf("Failed to accept connection: %s - %s", maddr, err)
				s.errChan <- e

				// if cancel is nil, we're closed.
				if s.cancel == nil {
					return
				}
			} else {
				go s.handleIncomingConn(nconn)
			}
		}
	}()

	return nil
}

// Handle getting ID from this peer, handshake, and adding it into the map
func (s *Swarm) handleIncomingConn(nconn manet.Conn) {

	addr := nconn.RemoteMultiaddr()

	// Construct conn with nil peer for now, because we don't know its ID yet.
	// connSetup will figure this out, and pull out / construct the peer.
	c, err := conn.NewConn(nil, addr, nconn)
	if err != nil {
		s.errChan <- err
		return
	}

	// Setup the new connection
	err = s.connSetup(c)
	if err != nil && err != ErrAlreadyOpen {
		s.errChan <- err
		c.Close()
	}
}

// connSetup adds the passed in connection to its peerMap and starts
// the fanIn routine for that connection
func (s *Swarm) connSetup(c *conn.Conn) error {
	if c == nil {
		return errors.New("Tried to start nil connection.")
	}

	if c.Peer != nil {
		log.Debug("Starting connection: %s", c.Peer)
	} else {
		log.Debug("Starting connection: [unknown peer]")
	}

	if err := s.connSecure(c); err != nil {
		return fmt.Errorf("Conn securing error: %v", err)
	}

	log.Debug("Secured connection: %s", c.Peer)

	// add address of connection to Peer. Maybe it should happen in connSecure.
	c.Peer.AddAddress(c.Addr)

	if err := s.connVersionExchange(c); err != nil {
		return fmt.Errorf("Conn version exchange error: %v", err)
	}

	// add to conns
	s.connsLock.Lock()
	if _, ok := s.conns[c.Peer.Key()]; ok {
		log.Debug("Conn already open!")
		s.connsLock.Unlock()
		return ErrAlreadyOpen
	}
	s.conns[c.Peer.Key()] = c
	log.Debug("Added conn to map!")
	s.connsLock.Unlock()

	// kick off reader goroutine
	go s.fanIn(c)
	return nil
}

// connSecure setups a secure remote connection.
func (s *Swarm) connSecure(c *conn.Conn) error {

	sp, err := spipe.NewSecurePipe(s.ctx, 10, s.local, s.peers)
	if err != nil {
		return err
	}

	err = sp.Wrap(s.ctx, spipe.Duplex{
		In:  c.Incoming.MsgChan,
		Out: c.Outgoing.MsgChan,
	})
	if err != nil {
		return err
	}

	if c.Peer == nil {
		c.Peer = sp.RemotePeer()

	} else if c.Peer != sp.RemotePeer() {
		panic("peers not being constructed correctly.")
	}

	c.Secure = sp
	return nil
}

// connVersionExchange exchanges local and remote versions and compares them
// closes remote and returns an error in case of major difference
func (s *Swarm) connVersionExchange(remote *conn.Conn) error {
	var remoteVersion, myVersion *version.SemVer
	myVersion = version.Current()

	myVersionMsg, err := msg.FromObject(s.local, myVersion)
	if err != nil {
		return fmt.Errorf("connVersionExchange: could not prepare local version: %q", err)
	}

	var gotTheirs, sendMine bool
	for {
		if gotTheirs && sendMine {
			break
		}

		select {
		case <-s.ctx.Done():
			// close Conn.
			remote.Close()
			return nil // BUG(cryptix): should this be an error?

		case <-remote.Closed:
			return errors.New("remote closed connection during version exchange")

		case remote.Secure.Out <- myVersionMsg.Data():
			log.Debug("[peer: %s] Send my version(%s) to %s", s.local, myVersion, remote.Peer)
			sendMine = true

		case data, ok := <-remote.Secure.In:
			if !ok {
				return fmt.Errorf("Error retrieving from conn: %v", remote.Peer)
			}

			log.Debug("[peer: %s] Received message [from = %s]", s.local, remote.Peer)

			remoteVersion = new(version.SemVer)
			err = proto.Unmarshal(data, remoteVersion)
			if err != nil {
				s.Close()
				return fmt.Errorf("connSetup: could not decode remote version: %q", err)
			}
			gotTheirs = true
		}
	}

	return errors.New("not yet")
}

// Handles the unwrapping + sending of messages to the right connection.
func (s *Swarm) fanOut() {
	for {
		select {
		case <-s.ctx.Done():
			return // told to close.

		case msg, ok := <-s.Outgoing:
			if !ok {
				return
			}

			s.connsLock.RLock()
			conn, found := s.conns[msg.Peer().Key()]
			s.connsLock.RUnlock()

			if !found {
				e := fmt.Errorf("Sent msg to peer without open conn: %v",
					msg.Peer)
				s.errChan <- e
				continue
			}

			// log.Debug("[peer: %s] Sent message [to = %s]", s.local, msg.Peer())

			// queue it in the connection's buffer
			conn.Secure.Out <- msg.Data()
		}
	}
}

// Handles the receiving + wrapping of messages, per conn.
// Consider using reflect.Select with one goroutine instead of n.
func (s *Swarm) fanIn(c *conn.Conn) {
	for {
		select {
		case <-s.ctx.Done():
			// close Conn.
			c.Close()
			goto out

		case <-c.Closed:
			goto out

		case data, ok := <-c.Secure.In:
			if !ok {
				e := fmt.Errorf("Error retrieving from conn: %v", c.Peer)
				s.errChan <- e
				goto out
			}

			// log.Debug("[peer: %s] Received message [from = %s]", s.local, c.Peer)

			msg := msg.New(c.Peer, data)
			s.Incoming <- msg
		}
	}

out:
	s.connsLock.Lock()
	delete(s.conns, c.Peer.Key())
	s.connsLock.Unlock()
}
<commit_msg>only send local version once<commit_after>package swarm

import (
	"errors"
	"fmt"

	spipe "github.com/jbenet/go-ipfs/crypto/spipe"
	conn "github.com/jbenet/go-ipfs/net/conn"
	msg "github.com/jbenet/go-ipfs/net/message"
	version "github.com/jbenet/go-ipfs/net/version"

	proto "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto"
	ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
	manet "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr/net"
)

// Open listeners for each network the swarm should listen on
func (s *Swarm) listen() error {
	hasErr := false
	retErr := &ListenErr{
		Errors: make([]error, len(s.local.Addresses)),
	}

	// listen on every address
	for i, addr := range s.local.Addresses {
		err := s.connListen(addr)
		if err != nil {
			hasErr = true
			retErr.Errors[i] = err
			log.Error("Failed to listen on: %s - %s", addr, err)
		}
	}

	if hasErr {
		return retErr
	}
	return nil
}

// Listen for new connections on the given multiaddr
func (s *Swarm) connListen(maddr ma.Multiaddr) error {
	list, err := manet.Listen(maddr)
	if err != nil {
		return err
	}

	// NOTE: this may require a lock around it later. currently, only run on setup
	s.listeners = append(s.listeners, list)

	// Accept and handle new connections on this listener until it errors
	go func() {
		for {
			nconn, err := list.Accept()
			if err != nil {
				e := fmt.Errorf("Failed to accept connection: %s - %s", maddr, err)
				s.errChan <- e

				// if cancel is nil, we're closed.
				if s.cancel == nil {
					return
				}
			} else {
				go s.handleIncomingConn(nconn)
			}
		}
	}()

	return nil
}

// Handle getting ID from this peer, handshake, and adding it into the map
func (s *Swarm) handleIncomingConn(nconn manet.Conn) {

	addr := nconn.RemoteMultiaddr()

	// Construct conn with nil peer for now, because we don't know its ID yet.
	// connSetup will figure this out, and pull out / construct the peer.
	c, err := conn.NewConn(nil, addr, nconn)
	if err != nil {
		s.errChan <- err
		return
	}

	// Setup the new connection
	err = s.connSetup(c)
	if err != nil && err != ErrAlreadyOpen {
		s.errChan <- err
		c.Close()
	}
}

// connSetup adds the passed in connection to its peerMap and starts
// the fanIn routine for that connection
func (s *Swarm) connSetup(c *conn.Conn) error {
	if c == nil {
		return errors.New("Tried to start nil connection.")
	}

	if c.Peer != nil {
		log.Debug("Starting connection: %s", c.Peer)
	} else {
		log.Debug("Starting connection: [unknown peer]")
	}

	if err := s.connSecure(c); err != nil {
		return fmt.Errorf("Conn securing error: %v", err)
	}

	log.Debug("Secured connection: %s", c.Peer)

	// add address of connection to Peer. Maybe it should happen in connSecure.
	c.Peer.AddAddress(c.Addr)

	if err := s.connVersionExchange(c); err != nil {
		return fmt.Errorf("Conn version exchange error: %v", err)
	}

	// add to conns
	s.connsLock.Lock()
	if _, ok := s.conns[c.Peer.Key()]; ok {
		log.Debug("Conn already open!")
		s.connsLock.Unlock()
		return ErrAlreadyOpen
	}
	s.conns[c.Peer.Key()] = c
	log.Debug("Added conn to map!")
	s.connsLock.Unlock()

	// kick off reader goroutine
	go s.fanIn(c)
	return nil
}

// connSecure setups a secure remote connection.
func (s *Swarm) connSecure(c *conn.Conn) error {

	sp, err := spipe.NewSecurePipe(s.ctx, 10, s.local, s.peers)
	if err != nil {
		return err
	}

	err = sp.Wrap(s.ctx, spipe.Duplex{
		In:  c.Incoming.MsgChan,
		Out: c.Outgoing.MsgChan,
	})
	if err != nil {
		return err
	}

	if c.Peer == nil {
		c.Peer = sp.RemotePeer()

	} else if c.Peer != sp.RemotePeer() {
		panic("peers not being constructed correctly.")
	}

	c.Secure = sp
	return nil
}

// connVersionExchange exchanges local and remote versions and compares them
// closes remote and returns an error in case of major difference
func (s *Swarm) connVersionExchange(remote *conn.Conn) error {
	var remoteVersion, myVersion *version.SemVer
	myVersion = version.Current()

	myVersionMsg, err := msg.FromObject(s.local, myVersion)
	if err != nil {
		return fmt.Errorf("connVersionExchange: could not prepare local version: %q", err)
	}

	// buffered channel to send our version just once
	outBuf := make(chan []byte, 1)
	outBuf <- myVersionMsg.Data()

	var gotTheirs, sendMine bool
	for {
		if gotTheirs && sendMine {
			break
		}

		select {
		case <-s.ctx.Done():
			// close Conn.
			remote.Close()
			return nil // BUG(cryptix): should this be an error?

		case <-remote.Closed:
			return errors.New("remote closed connection during version exchange")

		case our, ok := <-outBuf:
			if ok {
				remote.Secure.Out <- our
				sendMine = true
				close(outBuf) // only send local version once
				log.Debug("[peer: %s] Send my version(%s) to %s", s.local, myVersion, remote.Peer)
			}

		case data, ok := <-remote.Secure.In:
			if !ok {
				return fmt.Errorf("Error retrieving from conn: %v", remote.Peer)
			}

			log.Debug("[peer: %s] Received message [from = %s]", s.local, remote.Peer)

			remoteVersion = new(version.SemVer)
			err = proto.Unmarshal(data, remoteVersion)
			if err != nil {
				s.Close()
				return fmt.Errorf("connSetup: could not decode remote version: %q", err)
			}
			gotTheirs = true

			// BUG(cryptix): could add another case here to trigger resending our version
		}
	}

	return errors.New("not yet")
}

// Handles the unwrapping + sending of messages to the right connection.
func (s *Swarm) fanOut() {
	for {
		select {
		case <-s.ctx.Done():
			return // told to close.

		case msg, ok := <-s.Outgoing:
			if !ok {
				return
			}

			s.connsLock.RLock()
			conn, found := s.conns[msg.Peer().Key()]
			s.connsLock.RUnlock()

			if !found {
				e := fmt.Errorf("Sent msg to peer without open conn: %v",
					msg.Peer)
				s.errChan <- e
				continue
			}

			// log.Debug("[peer: %s] Sent message [to = %s]", s.local, msg.Peer())

			// queue it in the connection's buffer
			conn.Secure.Out <- msg.Data()
		}
	}
}

// Handles the receiving + wrapping of messages, per conn.
// Consider using reflect.Select with one goroutine instead of n.
func (s *Swarm) fanIn(c *conn.Conn) {
	for {
		select {
		case <-s.ctx.Done():
			// close Conn.
			c.Close()
			goto out

		case <-c.Closed:
			goto out

		case data, ok := <-c.Secure.In:
			if !ok {
				e := fmt.Errorf("Error retrieving from conn: %v", c.Peer)
				s.errChan <- e
				goto out
			}

			// log.Debug("[peer: %s] Received message [from = %s]", s.local, c.Peer)

			msg := msg.New(c.Peer, data)
			s.Incoming <- msg
		}
	}

out:
	s.connsLock.Lock()
	delete(s.conns, c.Peer.Key())
	s.connsLock.Unlock()
}
<|endoftext|>