<commit_before>// +build mage

package main

import (
	"bytes"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"time"

	"github.com/magefile/mage/mg" // mg contains helpful utility functions, like Deps
	"github.com/magefile/mage/sh" // mg contains helpful utility functions, like Deps
)

const localWorkDir = "./sparta"

var header = strings.Repeat("-", 80)

var ignoreSubdirectoryPaths = []string{
	".vendor",
	".sparta",
	".vscode",
	"/resources/describe",
}

// Default target to run when none is specified
// If not set, running mage will list available targets
// var Default = Build

func mageScript(commands [][]string) error {
	for _, eachCommand := range commands {
		var commandErr error
		if len(eachCommand) <= 1 {
			commandErr = sh.Run(eachCommand[0])
		} else {
			commandErr = sh.Run(eachCommand[0], eachCommand[1:]...)
		}
		if commandErr != nil {
			return commandErr
		}
	}
	return nil
}
func mageLog(formatSpecifier string, args ...interface{}) {
	if mg.Verbose() {
		if len(args) != 0 {
			log.Printf(formatSpecifier, args...)
		} else {
			log.Printf(formatSpecifier)
		}
	}
}

func sourceFilesOfType(extension string) ([]string, error) {
	testExtension := strings.TrimPrefix(extension, ".")
	testExtension = fmt.Sprintf(".%s", testExtension)

	files := make([]string, 0)
	walker := func(path string, info os.FileInfo, err error) error {
		contains := false
		for _, eachComponent := range ignoreSubdirectoryPaths {
			contains = strings.Contains(path, eachComponent)
			if contains {
				break
			}
		}
		if !contains && (filepath.Ext(path) == testExtension) {
			files = append(files, path)
		}
		return nil
	}
	goSourceFilesErr := filepath.Walk(".", walker)
	return files, goSourceFilesErr
}

func applyToSource(fileExtension string, commandParts ...string) error {
	if len(commandParts) <= 0 {
		return errors.New("applyToSource requires a command to apply to source files")
	}
	eligibleSourceFiles, eligibleSourceFilesErr := sourceFilesOfType(fileExtension)
	if eligibleSourceFilesErr != nil {
		return eligibleSourceFilesErr
	}

	mageLog(header)
	mageLog("Applying `%s` to %d `*.%s` source files", commandParts[0], len(eligibleSourceFiles), fileExtension)
	mageLog(header)

	commandArgs := []string{}
	if len(commandParts) > 1 {
		for _, eachPart := range commandParts[1:] {
			commandArgs = append(commandArgs, eachPart)
		}
	}
	for _, eachFile := range eligibleSourceFiles {
		applyArgs := append(commandArgs, eachFile)
		applyErr := sh.Run(commandParts[0], applyArgs...)
		if applyErr != nil {
			return applyErr
		}
	}
	return nil
}

func markdownSourceApply(commandParts ...string) error {
	return applyToSource("md", commandParts...)
}
func goSourceApply(commandParts ...string) error {
	return applyToSource("go", commandParts...)
}

func EnsureCleanTree() error {
	cleanTreeScript := [][]string{
		// No dirty trees
		{"git", "diff", "--exit-code"},
	}
	return mageScript(cleanTreeScript)
}

// GenerateBuildInfo creates the automatic buildinfo.go file so that we can
// stamp the SHA into the binaries we build...
func GenerateBuildInfo() error {
	mage.SerialDeps(EnsureCleanTree)

	// The first thing we need is the `git` SHA
	cmd := exec.Command("git", "rev-parse", "HEAD")
	var stdout, stderr bytes.Buffer
	cmd.Stdout = &stdout
	cmd.Stderr = &stderr
	err := cmd.Run()
	if err != nil {
		return err
	}
	stdOutResult := strings.TrimSpace(string(stdout.Bytes()))

	// Super = update the buildinfo data
	buildInfoTemplate := `package sparta

// THIS FILE IS AUTOMATICALLY GENERATED
// DO NOT EDIT
// CREATED: %s

// SpartaGitHash is the commit hash of this Sparta library
const SpartaGitHash = "%s"
`
	updatedInfo := fmt.Sprintf(buildInfoTemplate, time.Now().UTC(), stdOutResult)
	// Write it to the output location...
	writeErr := ioutil.WriteFile("./buildinfo.go", []byte(updatedInfo), os.ModePerm)

	if writeErr != nil {
		return writeErr
	}
	commitGenerateCommands := [][]string{
		// No dirty trees
		{"git", "commit", "-a", "-m", `"Autogenerated build info"`},
	}
	return mageScript(commitGenerateCommands)

}

// GenerateConstants runs the set of commands that update the embedded CONSTANTS
// for both local and AWS Lambda execution
func GenerateConstants() error {
	generateCommands := [][]string{
		// Create the embedded version
		{"go", "run", "$GOPATH/src/github.com/mjibson/esc/main.go", "-o", "./CONSTANTS.go", "-private", "-pkg", "sparta", "./resources"},
		//Create a secondary CONSTANTS_AWSBINARY.go file with empty content.
		{"go", "run", "$GOPATH/src/github.com/mjibson/esc/main.go", "-o", "./CONSTANTS_AWSBINARY.go", "-private", "-pkg", "sparta", "./resources/awsbinary/README.md"},
		//The next step will insert the
		// build tags at the head of each file so that they are mutually exclusive
		{"go", "run", "./cmd/insertTags/main.go", "./CONSTANTS", "!lambdabinary"},
		{"go", "run", "./cmd/insertTags/main.go", "./CONSTANTS_AWSBINARY", "lambdabinary"},
		{"git", "commit", "-a", "-m", "Autogenerated constants"},
	}
	return mageScript(generateCommands)
}

// InstallBuildRequirements installs or updates the dependent
// packages that aren't referenced by the source, but are needed
// to build the Sparta source
func InstallBuildRequirements() error {
	mageLog("`go get` update flags (env.GO_GET_FLAG): %s", os.Getenv("GO_GET_FLAG"))

	requirements := []string{
		"github.com/golang/dep/...",
		"honnef.co/go/tools/cmd/megacheck",
		"honnef.co/go/tools/cmd/gosimple",
		"honnef.co/go/tools/cmd/unused",
		"honnef.co/go/tools/cmd/staticcheck",
		"golang.org/x/tools/cmd/goimports",
		"github.com/fzipp/gocyclo",
		"github.com/golang/lint/golint",
		"github.com/mjibson/esc",
		"github.com/securego/gosec/cmd/gosec/...",
		"github.com/client9/misspell/cmd/misspell",
	}
	for _, eachDep := range requirements {
		cmdErr := sh.Run("go",
			"get",
			os.Getenv("GO_GET_FLAG"),
			eachDep)

		// cmdErr := exec.Command(.Run()
		if cmdErr != nil {
			return cmdErr
		}
	}
	return nil
}

// EnsureSpelling ensures that there are no misspellings in the source
func EnsureSpelling() error {
	goSpelling := func() error {
		return goSourceApply("misspell", "-error")
	}
	mdSpelling := func() error {
		return markdownSourceApply("misspell", "-error")
	}
	mg.SerialDeps(
		goSpelling,
		mdSpelling)
	return nil
}

// EnsureVet ensures that the source has been `go vet`ted
func EnsureVet() error {
	return goSourceApply("go", "tool", "vet")
}

// EnsureLint ensures that the source is `golint`ed
func EnsureLint() error {
	return goSourceApply("golint")
}

// EnsureFormatted ensures that the source code is formatted with goimports
func EnsureFormatted() error {
	return goSourceApply("goimports", "-d")
}

// EnsureStaticChecks ensures that the source code passes static code checks
func EnsureStaticChecks() error {
	// Megacheck
	megacheckErr := sh.Run("megacheck",
		"-ignore",
		"github.com/mweagle/Sparta/CONSTANTS.go:*")
	if megacheckErr != nil {
		return megacheckErr
	}
	// Gosec
	return sh.Run("gosec",
		"-exclude=G204,G505,G401",
		"./...")
}

// EnsureAllPreconditions ensures that the source passes *ALL* static `ensure*`
// precondition steps
func EnsureAllPreconditions() error {
	mg.SerialDeps(
		InstallBuildRequirements,
		EnsureVet,
		EnsureLint,
		EnsureFormatted,
		EnsureStaticChecks,
		EnsureSpelling,
	)
	return nil
}

// EnsureTravisBuildEnvironment is the command that sets up the Travis
// environment to run the build.
func EnsureTravisBuildEnvironment() error {
	mg.SerialDeps(InstallBuildRequirements)

	// Super run some commands
	travisComands := [][]string{
		[]string{"dep", "version"},
		[]string{"dep", "ensure", "-v"},
		[]string{"rsync", "-a", "--quiet", "--remove-source-files", "./vendor/", "$GOPATH/src"},
	}
	return mageScript(travisComands)
}

// Build the application
func Build() error {
	mg.Deps(EnsureAllPreconditions)
	return sh.Run("go", "build", ".")
}

// Clean the working directory
func Clean() error {
	cleanCommands := [][]string{
		[]string{"go", "clean", "."},
		[]string{"rm", "-rf", "./graph.html"},
		[]string{"rsync", "-a", "--quiet", "--remove-source-files", "./vendor/", "$GOPATH/src"},
	}
	return mageScript(cleanCommands)
}

// Describe runs the `TestDescribe` test to generate a describe HTML output
// file at graph.html
func Describe() error {
	describeCommands := [][]string{
		[]string{"rm", "-rf", "./graph.html"},
		[]string{"go", "test", "-v", "-run", "TestDescribe"},
	}
	return mageScript(describeCommands)
}

// Publish the latest source
func Publish() error {
	mg.SerialDeps(GenerateBuildInfo)

	describeCommands := [][]string{
		[]string{"echo", "Checking `git` tree status"},
		[]string{"git", "diff", "--exit-code"},
		// TODO - migrate to Go
		[]string{"./buildinfo.sh"},
		[]string{"git", "commit", "-a", "-m", "Tagging Sparta commit"},
		[]string{"git", "push", "origin"},
	}
	return mageScript(describeCommands)
}

// Test runs the Sparta tests
func Test() {
	testCommand := func() error {
		return sh.Run("go",
			"test",
			"-cover",
			"-race",
			"./...")
	}
	mg.SerialDeps(
		EnsureAllPreconditions,
		testCommand,
	)
}

// TestCover runs the test and opens up the resulting report
func TestCover() error {
	// mg.SerialDeps(
	// 	EnsureAllPreconditions,
	// )
	coverageReport := fmt.Sprintf("%s/cover.out", localWorkDir)
	testCoverCommands := [][]string{
		[]string{"go", "test", fmt.Sprintf("-coverprofile=%s", coverageReport), "."},
		[]string{"go", "tool", "cover", fmt.Sprintf("-html=%s", coverageReport)},
		[]string{"rm", coverageReport},
		[]string{"open", fmt.Sprintf("%s/cover.html", localWorkDir)},
	}
	return mageScript(testCoverCommands)
}

// TravisBuild is the task to build in the context of a Travis CI pipeline
func TravisBuild() error {
	mg.SerialDeps(EnsureTravisBuildEnvironment,
		Build,
		Test)
	return nil
}
<commit_msg>Proper scope<commit_after>// +build mage

package main

import (
	"bytes"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"time"

	"github.com/magefile/mage/mg" // mg contains helpful utility functions, like Deps
	"github.com/magefile/mage/sh" // mg contains helpful utility functions, like Deps
)

const localWorkDir = "./sparta"

var header = strings.Repeat("-", 80)

var ignoreSubdirectoryPaths = []string{
	".vendor",
	".sparta",
	".vscode",
	"/resources/describe",
}

// Default target to run when none is specified
// If not set, running mage will list available targets
// var Default = Build

func mageScript(commands [][]string) error {
	for _, eachCommand := range commands {
		var commandErr error
		if len(eachCommand) <= 1 {
			commandErr = sh.Run(eachCommand[0])
		} else {
			commandErr = sh.Run(eachCommand[0], eachCommand[1:]...)
		}
		if commandErr != nil {
			return commandErr
		}
	}
	return nil
}
func mageLog(formatSpecifier string, args ...interface{}) {
	if mg.Verbose() {
		if len(args) != 0 {
			log.Printf(formatSpecifier, args...)
		} else {
			log.Printf(formatSpecifier)
		}
	}
}

func sourceFilesOfType(extension string) ([]string, error) {
	testExtension := strings.TrimPrefix(extension, ".")
	testExtension = fmt.Sprintf(".%s", testExtension)

	files := make([]string, 0)
	walker := func(path string, info os.FileInfo, err error) error {
		contains := false
		for _, eachComponent := range ignoreSubdirectoryPaths {
			contains = strings.Contains(path, eachComponent)
			if contains {
				break
			}
		}
		if !contains && (filepath.Ext(path) == testExtension) {
			files = append(files, path)
		}
		return nil
	}
	goSourceFilesErr := filepath.Walk(".", walker)
	return files, goSourceFilesErr
}

func applyToSource(fileExtension string, commandParts ...string) error {
	if len(commandParts) <= 0 {
		return errors.New("applyToSource requires a command to apply to source files")
	}
	eligibleSourceFiles, eligibleSourceFilesErr := sourceFilesOfType(fileExtension)
	if eligibleSourceFilesErr != nil {
		return eligibleSourceFilesErr
	}

	mageLog(header)
	mageLog("Applying `%s` to %d `*.%s` source files", commandParts[0], len(eligibleSourceFiles), fileExtension)
	mageLog(header)

	commandArgs := []string{}
	if len(commandParts) > 1 {
		for _, eachPart := range commandParts[1:] {
			commandArgs = append(commandArgs, eachPart)
		}
	}
	for _, eachFile := range eligibleSourceFiles {
		applyArgs := append(commandArgs, eachFile)
		applyErr := sh.Run(commandParts[0], applyArgs...)
		if applyErr != nil {
			return applyErr
		}
	}
	return nil
}

func markdownSourceApply(commandParts ...string) error {
	return applyToSource("md", commandParts...)
}
func goSourceApply(commandParts ...string) error {
	return applyToSource("go", commandParts...)
}

func EnsureCleanTree() error {
	cleanTreeScript := [][]string{
		// No dirty trees
		{"git", "diff", "--exit-code"},
	}
	return mageScript(cleanTreeScript)
}

// GenerateBuildInfo creates the automatic buildinfo.go file so that we can
// stamp the SHA into the binaries we build...
func GenerateBuildInfo() error {
	mg.SerialDeps(EnsureCleanTree)

	// The first thing we need is the `git` SHA
	cmd := exec.Command("git", "rev-parse", "HEAD")
	var stdout, stderr bytes.Buffer
	cmd.Stdout = &stdout
	cmd.Stderr = &stderr
	err := cmd.Run()
	if err != nil {
		return err
	}
	stdOutResult := strings.TrimSpace(string(stdout.Bytes()))

	// Super = update the buildinfo data
	buildInfoTemplate := `package sparta

// THIS FILE IS AUTOMATICALLY GENERATED
// DO NOT EDIT
// CREATED: %s

// SpartaGitHash is the commit hash of this Sparta library
const SpartaGitHash = "%s"
`
	updatedInfo := fmt.Sprintf(buildInfoTemplate, time.Now().UTC(), stdOutResult)
	// Write it to the output location...
	writeErr := ioutil.WriteFile("./buildinfo.go", []byte(updatedInfo), os.ModePerm)

	if writeErr != nil {
		return writeErr
	}
	commitGenerateCommands := [][]string{
		// No dirty trees
		{"git", "commit", "-a", "-m", `"Autogenerated build info"`},
	}
	return mageScript(commitGenerateCommands)

}

// GenerateConstants runs the set of commands that update the embedded CONSTANTS
// for both local and AWS Lambda execution
func GenerateConstants() error {
	generateCommands := [][]string{
		// Create the embedded version
		{"go", "run", "$GOPATH/src/github.com/mjibson/esc/main.go", "-o", "./CONSTANTS.go", "-private", "-pkg", "sparta", "./resources"},
		//Create a secondary CONSTANTS_AWSBINARY.go file with empty content.
		{"go", "run", "$GOPATH/src/github.com/mjibson/esc/main.go", "-o", "./CONSTANTS_AWSBINARY.go", "-private", "-pkg", "sparta", "./resources/awsbinary/README.md"},
		//The next step will insert the
		// build tags at the head of each file so that they are mutually exclusive
		{"go", "run", "./cmd/insertTags/main.go", "./CONSTANTS", "!lambdabinary"},
		{"go", "run", "./cmd/insertTags/main.go", "./CONSTANTS_AWSBINARY", "lambdabinary"},
		{"git", "commit", "-a", "-m", "Autogenerated constants"},
	}
	return mageScript(generateCommands)
}

// InstallBuildRequirements installs or updates the dependent
// packages that aren't referenced by the source, but are needed
// to build the Sparta source
func InstallBuildRequirements() error {
	mageLog("`go get` update flags (env.GO_GET_FLAG): %s", os.Getenv("GO_GET_FLAG"))

	requirements := []string{
		"github.com/golang/dep/...",
		"honnef.co/go/tools/cmd/megacheck",
		"honnef.co/go/tools/cmd/gosimple",
		"honnef.co/go/tools/cmd/unused",
		"honnef.co/go/tools/cmd/staticcheck",
		"golang.org/x/tools/cmd/goimports",
		"github.com/fzipp/gocyclo",
		"github.com/golang/lint/golint",
		"github.com/mjibson/esc",
		"github.com/securego/gosec/cmd/gosec/...",
		"github.com/client9/misspell/cmd/misspell",
	}
	for _, eachDep := range requirements {
		cmdErr := sh.Run("go",
			"get",
			os.Getenv("GO_GET_FLAG"),
			eachDep)

		// cmdErr := exec.Command(.Run()
		if cmdErr != nil {
			return cmdErr
		}
	}
	return nil
}

// EnsureSpelling ensures that there are no misspellings in the source
func EnsureSpelling() error {
	goSpelling := func() error {
		return goSourceApply("misspell", "-error")
	}
	mdSpelling := func() error {
		return markdownSourceApply("misspell", "-error")
	}
	mg.SerialDeps(
		goSpelling,
		mdSpelling)
	return nil
}

// EnsureVet ensures that the source has been `go vet`ted
func EnsureVet() error {
	return goSourceApply("go", "tool", "vet")
}

// EnsureLint ensures that the source is `golint`ed
func EnsureLint() error {
	return goSourceApply("golint")
}

// EnsureFormatted ensures that the source code is formatted with goimports
func EnsureFormatted() error {
	return goSourceApply("goimports", "-d")
}

// EnsureStaticChecks ensures that the source code passes static code checks
func EnsureStaticChecks() error {
	// Megacheck
	megacheckErr := sh.Run("megacheck",
		"-ignore",
		"github.com/mweagle/Sparta/CONSTANTS.go:*")
	if megacheckErr != nil {
		return megacheckErr
	}
	// Gosec
	return sh.Run("gosec",
		"-exclude=G204,G505,G401",
		"./...")
}

// EnsureAllPreconditions ensures that the source passes *ALL* static `ensure*`
// precondition steps
func EnsureAllPreconditions() error {
	mg.SerialDeps(
		InstallBuildRequirements,
		EnsureVet,
		EnsureLint,
		EnsureFormatted,
		EnsureStaticChecks,
		EnsureSpelling,
	)
	return nil
}

// EnsureTravisBuildEnvironment is the command that sets up the Travis
// environment to run the build.
func EnsureTravisBuildEnvironment() error {
	mg.SerialDeps(InstallBuildRequirements)

	// Super run some commands
	travisComands := [][]string{
		[]string{"dep", "version"},
		[]string{"dep", "ensure", "-v"},
		[]string{"rsync", "-a", "--quiet", "--remove-source-files", "./vendor/", "$GOPATH/src"},
	}
	return mageScript(travisComands)
}

// Build the application
func Build() error {
	mg.Deps(EnsureAllPreconditions)
	return sh.Run("go", "build", ".")
}

// Clean the working directory
func Clean() error {
	cleanCommands := [][]string{
		[]string{"go", "clean", "."},
		[]string{"rm", "-rf", "./graph.html"},
		[]string{"rsync", "-a", "--quiet", "--remove-source-files", "./vendor/", "$GOPATH/src"},
	}
	return mageScript(cleanCommands)
}

// Describe runs the `TestDescribe` test to generate a describe HTML output
// file at graph.html
func Describe() error {
	describeCommands := [][]string{
		[]string{"rm", "-rf", "./graph.html"},
		[]string{"go", "test", "-v", "-run", "TestDescribe"},
	}
	return mageScript(describeCommands)
}

// Publish the latest source
func Publish() error {
	mg.SerialDeps(GenerateBuildInfo)

	describeCommands := [][]string{
		[]string{"echo", "Checking `git` tree status"},
		[]string{"git", "diff", "--exit-code"},
		// TODO - migrate to Go
		[]string{"./buildinfo.sh"},
		[]string{"git", "commit", "-a", "-m", "Tagging Sparta commit"},
		[]string{"git", "push", "origin"},
	}
	return mageScript(describeCommands)
}

// Test runs the Sparta tests
func Test() {
	testCommand := func() error {
		return sh.Run("go",
			"test",
			"-cover",
			"-race",
			"./...")
	}
	mg.SerialDeps(
		EnsureAllPreconditions,
		testCommand,
	)
}

// TestCover runs the test and opens up the resulting report
func TestCover() error {
	// mg.SerialDeps(
	// 	EnsureAllPreconditions,
	// )
	coverageReport := fmt.Sprintf("%s/cover.out", localWorkDir)
	testCoverCommands := [][]string{
		[]string{"go", "test", fmt.Sprintf("-coverprofile=%s", coverageReport), "."},
		[]string{"go", "tool", "cover", fmt.Sprintf("-html=%s", coverageReport)},
		[]string{"rm", coverageReport},
		[]string{"open", fmt.Sprintf("%s/cover.html", localWorkDir)},
	}
	return mageScript(testCoverCommands)
}

// TravisBuild is the task to build in the context of a Travis CI pipeline
func TravisBuild() error {
	mg.SerialDeps(EnsureTravisBuildEnvironment,
		Build,
		Test)
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"

	"github.com/justincarter/docker-workbench/cmd"
	"github.com/urfave/cli"
)

const version = "0.5"

func main() {

	if err := cmd.FlightCheck(); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	cli.AppHelpTemplate = templateAppHelp
	cli.CommandHelpTemplate = templateCommandHelp
	cli.VersionPrinter = cmd.Version

	app := cli.NewApp()
	app.Name = "docker-workbench"
	app.Version = version
	app.Usage = "Provision a Docker Workbench for use with docker-machine and docker-compose"

	app.CommandNotFound = cmd.NotFound
	app.Commands = cmd.Commands

	if err := app.Run(os.Args); err != nil {
		fmt.Println(err)
	}
}
<commit_msg>bump version to 1.0<commit_after>package main

import (
	"fmt"
	"os"

	"github.com/justincarter/docker-workbench/cmd"
	"github.com/urfave/cli"
)

const version = "1.0"

func main() {

	if err := cmd.FlightCheck(); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	cli.AppHelpTemplate = templateAppHelp
	cli.CommandHelpTemplate = templateCommandHelp
	cli.VersionPrinter = cmd.Version

	app := cli.NewApp()
	app.Name = "docker-workbench"
	app.Version = version
	app.Usage = "Provision a Docker Workbench for use with docker-machine and docker-compose"

	app.CommandNotFound = cmd.NotFound
	app.Commands = cmd.Commands

	if err := app.Run(os.Args); err != nil {
		fmt.Println(err)
	}
}
<|endoftext|>


<commit_before>// Copyright 2016, RadiantBlue Technologies, Inc.
//
// 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 elasticsearch

import (
	"encoding/json"

	"gopkg.in/olivere/elastic.v3"
)

type SeachResultHit struct {
	Id     string
	Source *json.RawMessage
}

type SearchResult struct {
	totalHits int64
	hits      []*SeachResultHit
}

func NewSearchResult(searchResult *elastic.SearchResult) *SearchResult {
	resp := &SearchResult{
		totalHits: searchResult.TotalHits(),
		hits:      make([]*SeachResultHit, searchResult.TotalHits()),
	}

	for i, hit := range searchResult.Hits.Hits {
		tmp := &SeachResultHit{
			Id:     hit.Id,
			Source: hit.Source,
		}
		resp.hits[i] = tmp
	}

	return resp
}

func (r *SearchResult) TotalHits() int64 {
	return r.totalHits
}

func (r *SearchResult) GetHits() *[]*SeachResultHit {
	return &r.hits
}

func (r *SearchResult) GetHit(i int) *SeachResultHit {
	arr := r.GetHits()
	return (*arr)[i]
}

type IndexResponse struct {
	Created bool
	Id      string
	Index   string
	Type    string
	Version int
}

func NewIndexResponse(indexResponse *elastic.IndexResponse) *IndexResponse {
	resp := &IndexResponse{
		Created: indexResponse.Created,
		Id:      indexResponse.Id,
		Index:   indexResponse.Index,
		Type:    indexResponse.Type,
		Version: indexResponse.Version,
	}
	return resp
}

type PercolateResponseMatch struct {
	Id    string
	Index string
}

type PercolateResponse struct {
	Total   int64
	Matches []*PercolateResponseMatch
}

func NewPercolateResponse(percolateResponse *elastic.PercolateResponse) *PercolateResponse {
	resp := &PercolateResponse{
		Total:   percolateResponse.Total,
		Matches: make([]*PercolateResponseMatch, len(percolateResponse.Matches)),
	}

	for i, v := range percolateResponse.Matches {
		m := &PercolateResponseMatch{
			Id:    v.Id,
			Index: v.Index,
		}
		resp.Matches[i] = m
	}

	return resp
}

type DeleteResponse struct {
	Found bool
	Id    string
}

func NewDeleteResponse(deleteResponse *elastic.DeleteResponse) *DeleteResponse {
	resp := &DeleteResponse{
		Found: deleteResponse.Found,
		Id:    deleteResponse.Id,
	}
	return resp
}

type GetResult struct {
	Id     string
	Source *json.RawMessage
	Found  bool
}

func NewGetResult(getResult *elastic.GetResult) *GetResult {
	resp := &GetResult{
		Id:     getResult.Id,
		Source: getResult.Source,
		Found:  getResult.Found,
	}
	return resp
}
<commit_msg>their TotalHits() is not what we want it to be<commit_after>// Copyright 2016, RadiantBlue Technologies, Inc.
//
// 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 elasticsearch

import (
	"encoding/json"

	"gopkg.in/olivere/elastic.v3"
)

type SeachResultHit struct {
	Id     string
	Source *json.RawMessage
}

type SearchResult struct {
	totalHits int64
	hits      []*SeachResultHit
}

func NewSearchResult(searchResult *elastic.SearchResult) *SearchResult {
	count := len(searchResult.Hits.Hits)

	resp := &SearchResult{
		totalHits: int64(count),
		hits:      make([]*SeachResultHit, count),
	}

	for i, hit := range searchResult.Hits.Hits {
		tmp := &SeachResultHit{
			Id:     hit.Id,
			Source: hit.Source,
		}
		resp.hits[i] = tmp
	}

	return resp
}

func (r *SearchResult) TotalHits() int64 {
	return r.totalHits
}

func (r *SearchResult) GetHits() *[]*SeachResultHit {
	return &r.hits
}

func (r *SearchResult) GetHit(i int) *SeachResultHit {
	arr := r.GetHits()
	return (*arr)[i]
}

type IndexResponse struct {
	Created bool
	Id      string
	Index   string
	Type    string
	Version int
}

func NewIndexResponse(indexResponse *elastic.IndexResponse) *IndexResponse {
	resp := &IndexResponse{
		Created: indexResponse.Created,
		Id:      indexResponse.Id,
		Index:   indexResponse.Index,
		Type:    indexResponse.Type,
		Version: indexResponse.Version,
	}
	return resp
}

type PercolateResponseMatch struct {
	Id    string
	Index string
}

type PercolateResponse struct {
	Total   int64
	Matches []*PercolateResponseMatch
}

func NewPercolateResponse(percolateResponse *elastic.PercolateResponse) *PercolateResponse {
	resp := &PercolateResponse{
		Total:   percolateResponse.Total,
		Matches: make([]*PercolateResponseMatch, len(percolateResponse.Matches)),
	}

	for i, v := range percolateResponse.Matches {
		m := &PercolateResponseMatch{
			Id:    v.Id,
			Index: v.Index,
		}
		resp.Matches[i] = m
	}

	return resp
}

type DeleteResponse struct {
	Found bool
	Id    string
}

func NewDeleteResponse(deleteResponse *elastic.DeleteResponse) *DeleteResponse {
	resp := &DeleteResponse{
		Found: deleteResponse.Found,
		Id:    deleteResponse.Id,
	}
	return resp
}

type GetResult struct {
	Id     string
	Source *json.RawMessage
	Found  bool
}

func NewGetResult(getResult *elastic.GetResult) *GetResult {
	resp := &GetResult{
		Id:     getResult.Id,
		Source: getResult.Source,
		Found:  getResult.Found,
	}
	return resp
}
<|endoftext|>


<commit_before>package signify

import (
	"bytes"
	"io/ioutil"
	"os"
	"testing"

	"github.com/agl/ed25519"
)

type readfiletest struct {
	file    string
	comment string
	content []byte
	parsed  interface{}
}

var readfiletests = []readfiletest{
	{
		file:    "_testdata/test.key",
		comment: "signify secret key",
		content: []byte{
			0x45, 0x64, 0x42, 0x4b, 0x00, 0x00, 0x00, 0x2a, 0xbb, 0x07, 0x17, 0x79, 0xb5, 0x84, 0x56, 0xe5,
			0xf6, 0x61, 0xdc, 0xe0, 0x44, 0x7b, 0x98, 0xd7, 0x42, 0x42, 0xc0, 0x8d, 0xc7, 0xc0, 0x52, 0x16,
			0xd3, 0xff, 0xb0, 0x73, 0xe8, 0x92, 0x09, 0x30, 0xd3, 0xdb, 0x4f, 0x63, 0xb2, 0x59, 0xa4, 0x78,
			0x26, 0x5a, 0x50, 0x04, 0xd3, 0x5a, 0xb5, 0xf8, 0x92, 0xb2, 0x75, 0x4c, 0x30, 0x12, 0x12, 0x63,
			0x6f, 0x15, 0x29, 0xd9, 0xdf, 0x41, 0x4c, 0xde, 0x4c, 0x14, 0x60, 0xb9, 0xb1, 0x14, 0x1c, 0xbc,
			0xc3, 0xde, 0xd1, 0xe7, 0x79, 0x6d, 0xd0, 0x12, 0xd7, 0xed, 0x92, 0x88, 0xf4, 0xf1, 0x6a, 0x2f,
			0x13, 0x38, 0x3d, 0x60, 0xb9, 0x35, 0x43, 0xd5},
		parsed: encryptedKey{
			PKAlgo:    [2]byte{'E', 'd'},
			KDFAlgo:   [2]byte{'B', 'K'},
			KDFRounds: 42,
			Salt: [16]byte{
				0xbb, 0x07, 0x17, 0x79, 0xb5, 0x84, 0x56, 0xe5, 0xf6, 0x61, 0xdc, 0xe0, 0x44, 0x7b, 0x98, 0xd7,
			},
			Checksum:    [8]byte{0x42, 0x42, 0xc0, 0x8d, 0xc7, 0xc0, 0x52, 0x16},
			Fingerprint: [8]byte{0xd3, 0xff, 0xb0, 0x73, 0xe8, 0x92, 0x09, 0x30},
			PrivateKey: [ed25519.PrivateKeySize]byte{
				0xd3, 0xdb, 0x4f, 0x63, 0xb2, 0x59, 0xa4, 0x78,
				0x26, 0x5a, 0x50, 0x04, 0xd3, 0x5a, 0xb5, 0xf8, 0x92, 0xb2, 0x75, 0x4c, 0x30, 0x12, 0x12, 0x63,
				0x6f, 0x15, 0x29, 0xd9, 0xdf, 0x41, 0x4c, 0xde, 0x4c, 0x14, 0x60, 0xb9, 0xb1, 0x14, 0x1c, 0xbc,
				0xc3, 0xde, 0xd1, 0xe7, 0x79, 0x6d, 0xd0, 0x12, 0xd7, 0xed, 0x92, 0x88, 0xf4, 0xf1, 0x6a, 0x2f,
				0x13, 0x38, 0x3d, 0x60, 0xb9, 0x35, 0x43, 0xd5,
			},
		},
	}, {
		file:    "_testdata/test.pub",
		comment: "signify public key",
		content: []byte{
			0x45, 0x64, 0xd3, 0xff, 0xb0, 0x73, 0xe8, 0x92, 0x09, 0x30, 0xc8, 0x02, 0xe8, 0xf6, 0x4c, 0x35,
			0x63, 0xc2, 0x2e, 0xa3, 0x03, 0x56, 0xaf, 0x63, 0xf6, 0x92, 0xce, 0x2a, 0x63, 0x5c, 0xf6, 0x6e,
			0x7d, 0x48, 0x6c, 0xa8, 0x48, 0x8d, 0xe2, 0x04, 0xa6, 0x05},
		parsed: pubkey{
			PKAlgo:      [2]byte{'E', 'd'},
			Fingerprint: [8]byte{0xd3, 0xff, 0xb0, 0x73, 0xe8, 0x92, 0x09, 0x30},
			PublicKey: [ed25519.PublicKeySize]byte{
				0xc8, 0x02, 0xe8, 0xf6, 0x4c, 0x35, 0x63, 0xc2, 0x2e, 0xa3, 0x03, 0x56, 0xaf, 0x63, 0xf6, 0x92,
				0xce, 0x2a, 0x63, 0x5c, 0xf6, 0x6e, 0x7d, 0x48, 0x6c, 0xa8, 0x48, 0x8d, 0xe2, 0x04, 0xa6, 0x05,
			},
		},
	}, {
		file:    "_testdata/test.msg.sig",
		comment: "signature from signify secret key",
		content: []byte{
			0x45, 0x64, 0xd3, 0xff, 0xb0, 0x73, 0xe8, 0x92, 0x09, 0x30, 0x9e, 0x9f, 0x91, 0x69, 0x08, 0x5d,
			0xa7, 0xb9, 0x1c, 0x82, 0x3c, 0x81, 0x69, 0x16, 0x16, 0x58, 0x7a, 0xd2, 0x53, 0xb4, 0xe9, 0x96,
			0x0b, 0x42, 0x3c, 0x8a, 0x40, 0x40, 0x47, 0x7e, 0xb0, 0x41, 0x74, 0x26, 0x47, 0x41, 0xa4, 0xe8,
			0x2f, 0xec, 0xfb, 0xde, 0xe2, 0x77, 0x58, 0x19, 0xca, 0xb0, 0x57, 0x5f, 0x73, 0x5f, 0x8b, 0xe2,
			0xac, 0x11, 0x00, 0x14, 0x55, 0xd6, 0xac, 0xd3, 0xd3, 0x03},
		parsed: sig{
			PKAlgo:      [2]byte{'E', 'd'},
			Fingerprint: [8]byte{0xd3, 0xff, 0xb0, 0x73, 0xe8, 0x92, 0x09, 0x30},
			Signature: [ed25519.SignatureSize]byte{
				0x9e, 0x9f, 0x91, 0x69, 0x08, 0x5d, 0xa7, 0xb9, 0x1c, 0x82, 0x3c, 0x81, 0x69, 0x16, 0x16, 0x58,
				0x7a, 0xd2, 0x53, 0xb4, 0xe9, 0x96, 0x0b, 0x42, 0x3c, 0x8a, 0x40, 0x40, 0x47, 0x7e, 0xb0, 0x41,
				0x74, 0x26, 0x47, 0x41, 0xa4, 0xe8, 0x2f, 0xec, 0xfb, 0xde, 0xe2, 0x77, 0x58, 0x19, 0xca, 0xb0,
				0x57, 0x5f, 0x73, 0x5f, 0x8b, 0xe2, 0xac, 0x11, 0x00, 0x14, 0x55, 0xd6, 0xac, 0xd3, 0xd3, 0x03,
			},
		},
	},
}

func testReadFile(t *testing.T, file, comment string, content []byte) {
	f, err := os.Open(file)
	if err != nil {
		t.Fatal(err)
	}
	defer f.Close()

	rcomment, rcontent, err := ReadFile(f)
	if err != nil {
		t.Fatal(err)
	}

	if rcomment != comment {
		t.Errorf("%s: comment\nexpected: %q\ngot %q\n", file, comment, rcomment)
	}

	if !bytes.Equal(rcontent, content) {
		t.Errorf("%s: content\nexpected: %x\ngot %x\n", file, content, rcontent)
	}
}

func TestReadFile(t *testing.T) {
	for _, tc := range readfiletests {
		testReadFile(t, tc.file, tc.comment, tc.content)
	}
}

func TestParsePrivateKey(t *testing.T) {
	for _, tc := range readfiletests {
		want, ok := tc.parsed.(encryptedKey);
		if !ok {
			continue
		}

		buf, err := ioutil.ReadFile(tc.file)
		if err != nil {
			t.Fatalf("%s: %s\n", tc.file, err)
		}

		_, data, err := ReadFile(bytes.NewReader(buf))
		if err != nil {
			t.Fatalf("%s: %s\n", tc.file, err)
		}

		ek, err := ParsePrivateKey(data, "")
		if err != nil {
			t.Errorf("%s: %s\n", tc.file, err)
			continue
		}

		if want != *ek {
			t.Errorf("%s: expected: %+v got: %+v\n", tc.file, want, ek)
		}
	}
}
<commit_msg>simplify test<commit_after>package signify

import (
	"bytes"
	"io/ioutil"
	"testing"

	"github.com/agl/ed25519"
)

type readfiletest struct {
	file    string
	comment string
	content []byte
	parsed  interface{}
}

var readfiletests = []readfiletest{
	{
		file:    "_testdata/test.key",
		comment: "signify secret key",
		content: []byte{
			0x45, 0x64, 0x42, 0x4b, 0x00, 0x00, 0x00, 0x2a, 0xbb, 0x07, 0x17, 0x79, 0xb5, 0x84, 0x56, 0xe5,
			0xf6, 0x61, 0xdc, 0xe0, 0x44, 0x7b, 0x98, 0xd7, 0x42, 0x42, 0xc0, 0x8d, 0xc7, 0xc0, 0x52, 0x16,
			0xd3, 0xff, 0xb0, 0x73, 0xe8, 0x92, 0x09, 0x30, 0xd3, 0xdb, 0x4f, 0x63, 0xb2, 0x59, 0xa4, 0x78,
			0x26, 0x5a, 0x50, 0x04, 0xd3, 0x5a, 0xb5, 0xf8, 0x92, 0xb2, 0x75, 0x4c, 0x30, 0x12, 0x12, 0x63,
			0x6f, 0x15, 0x29, 0xd9, 0xdf, 0x41, 0x4c, 0xde, 0x4c, 0x14, 0x60, 0xb9, 0xb1, 0x14, 0x1c, 0xbc,
			0xc3, 0xde, 0xd1, 0xe7, 0x79, 0x6d, 0xd0, 0x12, 0xd7, 0xed, 0x92, 0x88, 0xf4, 0xf1, 0x6a, 0x2f,
			0x13, 0x38, 0x3d, 0x60, 0xb9, 0x35, 0x43, 0xd5},
		parsed: encryptedKey{
			PKAlgo:    [2]byte{'E', 'd'},
			KDFAlgo:   [2]byte{'B', 'K'},
			KDFRounds: 42,
			Salt: [16]byte{
				0xbb, 0x07, 0x17, 0x79, 0xb5, 0x84, 0x56, 0xe5, 0xf6, 0x61, 0xdc, 0xe0, 0x44, 0x7b, 0x98, 0xd7,
			},
			Checksum:    [8]byte{0x42, 0x42, 0xc0, 0x8d, 0xc7, 0xc0, 0x52, 0x16},
			Fingerprint: [8]byte{0xd3, 0xff, 0xb0, 0x73, 0xe8, 0x92, 0x09, 0x30},
			PrivateKey: [ed25519.PrivateKeySize]byte{
				0xd3, 0xdb, 0x4f, 0x63, 0xb2, 0x59, 0xa4, 0x78,
				0x26, 0x5a, 0x50, 0x04, 0xd3, 0x5a, 0xb5, 0xf8, 0x92, 0xb2, 0x75, 0x4c, 0x30, 0x12, 0x12, 0x63,
				0x6f, 0x15, 0x29, 0xd9, 0xdf, 0x41, 0x4c, 0xde, 0x4c, 0x14, 0x60, 0xb9, 0xb1, 0x14, 0x1c, 0xbc,
				0xc3, 0xde, 0xd1, 0xe7, 0x79, 0x6d, 0xd0, 0x12, 0xd7, 0xed, 0x92, 0x88, 0xf4, 0xf1, 0x6a, 0x2f,
				0x13, 0x38, 0x3d, 0x60, 0xb9, 0x35, 0x43, 0xd5,
			},
		},
	}, {
		file:    "_testdata/test.pub",
		comment: "signify public key",
		content: []byte{
			0x45, 0x64, 0xd3, 0xff, 0xb0, 0x73, 0xe8, 0x92, 0x09, 0x30, 0xc8, 0x02, 0xe8, 0xf6, 0x4c, 0x35,
			0x63, 0xc2, 0x2e, 0xa3, 0x03, 0x56, 0xaf, 0x63, 0xf6, 0x92, 0xce, 0x2a, 0x63, 0x5c, 0xf6, 0x6e,
			0x7d, 0x48, 0x6c, 0xa8, 0x48, 0x8d, 0xe2, 0x04, 0xa6, 0x05},
		parsed: pubkey{
			PKAlgo:      [2]byte{'E', 'd'},
			Fingerprint: [8]byte{0xd3, 0xff, 0xb0, 0x73, 0xe8, 0x92, 0x09, 0x30},
			PublicKey: [ed25519.PublicKeySize]byte{
				0xc8, 0x02, 0xe8, 0xf6, 0x4c, 0x35, 0x63, 0xc2, 0x2e, 0xa3, 0x03, 0x56, 0xaf, 0x63, 0xf6, 0x92,
				0xce, 0x2a, 0x63, 0x5c, 0xf6, 0x6e, 0x7d, 0x48, 0x6c, 0xa8, 0x48, 0x8d, 0xe2, 0x04, 0xa6, 0x05,
			},
		},
	}, {
		file:    "_testdata/test.msg.sig",
		comment: "signature from signify secret key",
		content: []byte{
			0x45, 0x64, 0xd3, 0xff, 0xb0, 0x73, 0xe8, 0x92, 0x09, 0x30, 0x9e, 0x9f, 0x91, 0x69, 0x08, 0x5d,
			0xa7, 0xb9, 0x1c, 0x82, 0x3c, 0x81, 0x69, 0x16, 0x16, 0x58, 0x7a, 0xd2, 0x53, 0xb4, 0xe9, 0x96,
			0x0b, 0x42, 0x3c, 0x8a, 0x40, 0x40, 0x47, 0x7e, 0xb0, 0x41, 0x74, 0x26, 0x47, 0x41, 0xa4, 0xe8,
			0x2f, 0xec, 0xfb, 0xde, 0xe2, 0x77, 0x58, 0x19, 0xca, 0xb0, 0x57, 0x5f, 0x73, 0x5f, 0x8b, 0xe2,
			0xac, 0x11, 0x00, 0x14, 0x55, 0xd6, 0xac, 0xd3, 0xd3, 0x03},
		parsed: sig{
			PKAlgo:      [2]byte{'E', 'd'},
			Fingerprint: [8]byte{0xd3, 0xff, 0xb0, 0x73, 0xe8, 0x92, 0x09, 0x30},
			Signature: [ed25519.SignatureSize]byte{
				0x9e, 0x9f, 0x91, 0x69, 0x08, 0x5d, 0xa7, 0xb9, 0x1c, 0x82, 0x3c, 0x81, 0x69, 0x16, 0x16, 0x58,
				0x7a, 0xd2, 0x53, 0xb4, 0xe9, 0x96, 0x0b, 0x42, 0x3c, 0x8a, 0x40, 0x40, 0x47, 0x7e, 0xb0, 0x41,
				0x74, 0x26, 0x47, 0x41, 0xa4, 0xe8, 0x2f, 0xec, 0xfb, 0xde, 0xe2, 0x77, 0x58, 0x19, 0xca, 0xb0,
				0x57, 0x5f, 0x73, 0x5f, 0x8b, 0xe2, 0xac, 0x11, 0x00, 0x14, 0x55, 0xd6, 0xac, 0xd3, 0xd3, 0x03,
			},
		},
	},
}

func testReadFile(t *testing.T, file, comment string, content []byte) {
	buf, err := ioutil.ReadFile(file)
	if err != nil {
		t.Fatalf("%s: %s\n", file, err)
	}

	rcomment, rcontent, err := ReadFile(bytes.NewReader(buf))
	if err != nil {
		t.Fatal(err)
	}

	if rcomment != comment {
		t.Errorf("%s: comment\nexpected: %q\ngot %q\n", file, comment, rcomment)
	}

	if !bytes.Equal(rcontent, content) {
		t.Errorf("%s: content\nexpected: %x\ngot %x\n", file, content, rcontent)
	}
}

func TestReadFile(t *testing.T) {
	for _, tc := range readfiletests {
		testReadFile(t, tc.file, tc.comment, tc.content)
	}
}

func TestParsePrivateKey(t *testing.T) {
	for _, tc := range readfiletests {
		want, ok := tc.parsed.(encryptedKey);
		if !ok {
			continue
		}

		ek, err := ParsePrivateKey(tc.content, "")
		if err != nil {
			t.Errorf("%s: %s\n", tc.file, err)
			continue
		}

		if want != *ek {
			t.Errorf("%s: expected: %+v got: %+v\n", tc.file, want, ek)
		}
	}
}
<|endoftext|>


<commit_before>package server

import (
	"fmt"
	"net"
	"net/http"
	"os"
	"reflect"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/getlantern/fronted"
	"github.com/getlantern/go-igdman/igdman"
	"github.com/getlantern/golog"
	"github.com/getlantern/nattywad"
	"github.com/getlantern/waddell"

	"github.com/getlantern/flashlight/globals"
	"github.com/getlantern/flashlight/nattest"
	"github.com/getlantern/flashlight/statreporter"
	"github.com/getlantern/flashlight/statserver"
)

const (
	PortmapFailure = 50
)

var (
	log = golog.LoggerFor("flashlight.server")
)

type Server struct {
	// Addr: listen address in form of host:port
	Addr string

	// Host: FQDN that is guaranteed to hit this server
	Host string

	// ReadTimeout: (optional) timeout for read ops
	ReadTimeout time.Duration

	// WriteTimeout: (optional) timeout for write ops
	WriteTimeout time.Duration

	CertContext                *fronted.CertContext // context for certificate management
	AllowNonGlobalDestinations bool                 // if true, requests to LAN, Loopback, etc. will be allowed

	waddellClient  *waddell.Client
	nattywadServer *nattywad.Server
	cfg            *ServerConfig
	cfgMutex       sync.Mutex
}

func (server *Server) Configure(newCfg *ServerConfig) {
	server.cfgMutex.Lock()
	defer server.cfgMutex.Unlock()

	oldCfg := server.cfg

	log.Debug("Server.Configure() called")
	if oldCfg != nil && reflect.DeepEqual(oldCfg, newCfg) {
		log.Debugf("Server configuration unchanged")
		return
	}

	if oldCfg == nil || newCfg.Portmap != oldCfg.Portmap {
		// Portmap changed
		if oldCfg != nil && oldCfg.Portmap > 0 {
			log.Debugf("Attempting to unmap old external port %d", oldCfg.Portmap)
			err := unmapPort(oldCfg.Portmap)
			if err != nil {
				log.Errorf("Unable to unmap old external port: %s", err)
			}
			log.Debugf("Unmapped old external port %d", oldCfg.Portmap)
		}

		if newCfg.Portmap > 0 {
			log.Debugf("Attempting to map new external port %d", newCfg.Portmap)
			err := mapPort(server.Addr, newCfg.Portmap)
			if err != nil {
				log.Errorf("Unable to map new external port: %s", err)
				os.Exit(PortmapFailure)
			}
			log.Debugf("Mapped new external port %d", newCfg.Portmap)
		}
	}

	nattywadIsEnabled := newCfg.WaddellAddr != ""
	nattywadWasEnabled := server.nattywadServer != nil
	waddellAddrChanged := oldCfg == nil && newCfg.WaddellAddr != "" || oldCfg != nil && oldCfg.WaddellAddr != newCfg.WaddellAddr

	if waddellAddrChanged {
		if nattywadWasEnabled {
			server.stopNattywad()
		}
		if nattywadIsEnabled {
			server.startNattywad(newCfg.WaddellAddr)
		}
	}

	server.cfg = newCfg
}

func (server *Server) ListenAndServe() error {
	if server.Host != "" {
		log.Debugf("Running as host %s", server.Host)
	}

	fs := &fronted.Server{
		Addr:                       server.Addr,
		Host:                       server.Host,
		ReadTimeout:                server.ReadTimeout,
		WriteTimeout:               server.WriteTimeout,
		CertContext:                server.CertContext,
		AllowNonGlobalDestinations: server.AllowNonGlobalDestinations,
	}

	if server.cfg.Unencrypted {
		log.Debug("Running in unencrypted mode")
		fs.CertContext = nil
	}

	// Add callbacks to track bytes given
	fs.OnBytesReceived = func(ip string, destAddr string, req *http.Request, bytes int64) {
		onBytesGiven(destAddr, req, bytes)
		statserver.OnBytesReceived(ip, bytes)
	}
	fs.OnBytesSent = func(ip string, destAddr string, req *http.Request, bytes int64) {
		onBytesGiven(destAddr, req, bytes)
		statserver.OnBytesSent(ip, bytes)
	}

	l, err := fs.Listen()
	if err != nil {
		return fmt.Errorf("Unable to listen at %s: %s", server.Addr, err)
	}
	return fs.Serve(l)
}

func (server *Server) startNattywad(waddellAddr string) {
	log.Debugf("Connecting to waddell at: %s", waddellAddr)
	var err error
	server.waddellClient, err = waddell.NewClient(&waddell.ClientConfig{
		Dial: func() (net.Conn, error) {
			return net.Dial("tcp", waddellAddr)
		},
		ServerCert:        globals.WaddellCert,
		ReconnectAttempts: 10,
		OnId: func(id waddell.PeerId) {
			log.Debugf("Connected to Waddell!! Id is: %s", id)
		},
	})
	if err != nil {
		log.Errorf("Unable to connect to waddell: %s", err)
		server.waddellClient = nil
		return
	}
	server.nattywadServer = &nattywad.Server{
		Client: server.waddellClient,
		OnSuccess: func(local *net.UDPAddr, remote *net.UDPAddr) bool {
			err := nattest.Serve(local)
			if err != nil {
				log.Error(err.Error())
				return false
			}
			return true
		},
	}
	server.nattywadServer.Start()
}

func (server *Server) stopNattywad() {
	log.Debug("Stopping nattywad server")
	server.nattywadServer.Stop()
	server.nattywadServer = nil
	log.Debug("Stopping waddell client")
	server.waddellClient.Close()
	server.waddellClient = nil
}

func mapPort(addr string, port int) error {
	internalIP, internalPortString, err := net.SplitHostPort(addr)
	if err != nil {
		return fmt.Errorf("Unable to split host and port for %v: %v", addr, err)
	}

	internalPort, err := strconv.Atoi(internalPortString)
	if err != nil {
		return fmt.Errorf("Unable to parse local port: ")
	}

	if internalIP == "" {
		internalIP, err = determineInternalIP()
		if err != nil {
			return fmt.Errorf("Unable to determine internal IP: %s", err)
		}
	}

	igd, err := igdman.NewIGD()
	if err != nil {
		return fmt.Errorf("Unable to get IGD: %s", err)
	}

	igd.RemovePortMapping(igdman.TCP, port)
	err = igd.AddPortMapping(igdman.TCP, internalIP, internalPort, port, 0)
	if err != nil {
		return fmt.Errorf("Unable to map port with igdman %d: %s", port, err)
	}

	return nil
}

func unmapPort(port int) error {
	igd, err := igdman.NewIGD()
	if err != nil {
		return fmt.Errorf("Unable to get IGD: %s", err)
	}

	igd.RemovePortMapping(igdman.TCP, port)
	if err != nil {
		return fmt.Errorf("Unable to unmap port with igdman %d: %s", port, err)
	}

	return nil
}

// determineInternalIP determines the internal IP to use for mapping ports. It
// does this by dialing a website on the public Internet and then finding out
// the LocalAddr for the corresponding connection. This gives us an interface
// that we know has Internet access, which makes it suitable for port mapping.
func determineInternalIP() (string, error) {
	conn, err := net.DialTimeout("tcp", "s3.amazonaws.com:443", 20*time.Second)
	if err != nil {
		return "", fmt.Errorf("Unable to determine local IP: %s", err)
	}
	defer conn.Close()
	host, _, err := net.SplitHostPort(conn.LocalAddr().String())
	return host, err
}

func onBytesGiven(destAddr string, req *http.Request, bytes int64) {
	addr, port, _ := net.SplitHostPort(destAddr)
	if port == "" {
		port = "0"
	}

	given := statreporter.CountryDim().
		And("flserver", globals.InstanceId).
		And("destport", port)
	given.Increment("bytesGiven").Add(bytes)
	given.Increment("bytesGivenByFlashlight").Add(bytes)

	clientCountry := req.Header.Get("Cf-Ipcountry")
	if clientCountry != "" {
		givenTo := statreporter.Country(clientCountry)
		givenTo.Increment("bytesGivenTo").Add(bytes)
		givenTo.Increment("bytesGivenToByFlashlight").Add(bytes)
		givenTo.Member("distinctDestAddrs", addr)

		clientIp := req.Header.Get("X-Forwarded-For")
		if clientIp != "" {
			// clientIp may contain multiple ips, use the first
			ips := strings.Split(clientIp, ",")
			clientIp := strings.TrimSpace(ips[0])
			givenTo.Member("distinctClientIPs", clientIp)
		}

	}

}
<commit_msg>Changed distinctDestAddrs to distinctDestHosts<commit_after>package server

import (
	"fmt"
	"net"
	"net/http"
	"os"
	"reflect"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/getlantern/fronted"
	"github.com/getlantern/go-igdman/igdman"
	"github.com/getlantern/golog"
	"github.com/getlantern/nattywad"
	"github.com/getlantern/waddell"

	"github.com/getlantern/flashlight/globals"
	"github.com/getlantern/flashlight/nattest"
	"github.com/getlantern/flashlight/statreporter"
	"github.com/getlantern/flashlight/statserver"
)

const (
	PortmapFailure = 50
)

var (
	log = golog.LoggerFor("flashlight.server")
)

type Server struct {
	// Addr: listen address in form of host:port
	Addr string

	// Host: FQDN that is guaranteed to hit this server
	Host string

	// ReadTimeout: (optional) timeout for read ops
	ReadTimeout time.Duration

	// WriteTimeout: (optional) timeout for write ops
	WriteTimeout time.Duration

	CertContext                *fronted.CertContext // context for certificate management
	AllowNonGlobalDestinations bool                 // if true, requests to LAN, Loopback, etc. will be allowed

	waddellClient  *waddell.Client
	nattywadServer *nattywad.Server
	cfg            *ServerConfig
	cfgMutex       sync.Mutex
}

func (server *Server) Configure(newCfg *ServerConfig) {
	server.cfgMutex.Lock()
	defer server.cfgMutex.Unlock()

	oldCfg := server.cfg

	log.Debug("Server.Configure() called")
	if oldCfg != nil && reflect.DeepEqual(oldCfg, newCfg) {
		log.Debugf("Server configuration unchanged")
		return
	}

	if oldCfg == nil || newCfg.Portmap != oldCfg.Portmap {
		// Portmap changed
		if oldCfg != nil && oldCfg.Portmap > 0 {
			log.Debugf("Attempting to unmap old external port %d", oldCfg.Portmap)
			err := unmapPort(oldCfg.Portmap)
			if err != nil {
				log.Errorf("Unable to unmap old external port: %s", err)
			}
			log.Debugf("Unmapped old external port %d", oldCfg.Portmap)
		}

		if newCfg.Portmap > 0 {
			log.Debugf("Attempting to map new external port %d", newCfg.Portmap)
			err := mapPort(server.Addr, newCfg.Portmap)
			if err != nil {
				log.Errorf("Unable to map new external port: %s", err)
				os.Exit(PortmapFailure)
			}
			log.Debugf("Mapped new external port %d", newCfg.Portmap)
		}
	}

	nattywadIsEnabled := newCfg.WaddellAddr != ""
	nattywadWasEnabled := server.nattywadServer != nil
	waddellAddrChanged := oldCfg == nil && newCfg.WaddellAddr != "" || oldCfg != nil && oldCfg.WaddellAddr != newCfg.WaddellAddr

	if waddellAddrChanged {
		if nattywadWasEnabled {
			server.stopNattywad()
		}
		if nattywadIsEnabled {
			server.startNattywad(newCfg.WaddellAddr)
		}
	}

	server.cfg = newCfg
}

func (server *Server) ListenAndServe() error {
	if server.Host != "" {
		log.Debugf("Running as host %s", server.Host)
	}

	fs := &fronted.Server{
		Addr:                       server.Addr,
		Host:                       server.Host,
		ReadTimeout:                server.ReadTimeout,
		WriteTimeout:               server.WriteTimeout,
		CertContext:                server.CertContext,
		AllowNonGlobalDestinations: server.AllowNonGlobalDestinations,
	}

	if server.cfg.Unencrypted {
		log.Debug("Running in unencrypted mode")
		fs.CertContext = nil
	}

	// Add callbacks to track bytes given
	fs.OnBytesReceived = func(ip string, destAddr string, req *http.Request, bytes int64) {
		onBytesGiven(destAddr, req, bytes)
		statserver.OnBytesReceived(ip, bytes)
	}
	fs.OnBytesSent = func(ip string, destAddr string, req *http.Request, bytes int64) {
		onBytesGiven(destAddr, req, bytes)
		statserver.OnBytesSent(ip, bytes)
	}

	l, err := fs.Listen()
	if err != nil {
		return fmt.Errorf("Unable to listen at %s: %s", server.Addr, err)
	}
	return fs.Serve(l)
}

func (server *Server) startNattywad(waddellAddr string) {
	log.Debugf("Connecting to waddell at: %s", waddellAddr)
	var err error
	server.waddellClient, err = waddell.NewClient(&waddell.ClientConfig{
		Dial: func() (net.Conn, error) {
			return net.Dial("tcp", waddellAddr)
		},
		ServerCert:        globals.WaddellCert,
		ReconnectAttempts: 10,
		OnId: func(id waddell.PeerId) {
			log.Debugf("Connected to Waddell!! Id is: %s", id)
		},
	})
	if err != nil {
		log.Errorf("Unable to connect to waddell: %s", err)
		server.waddellClient = nil
		return
	}
	server.nattywadServer = &nattywad.Server{
		Client: server.waddellClient,
		OnSuccess: func(local *net.UDPAddr, remote *net.UDPAddr) bool {
			err := nattest.Serve(local)
			if err != nil {
				log.Error(err.Error())
				return false
			}
			return true
		},
	}
	server.nattywadServer.Start()
}

func (server *Server) stopNattywad() {
	log.Debug("Stopping nattywad server")
	server.nattywadServer.Stop()
	server.nattywadServer = nil
	log.Debug("Stopping waddell client")
	server.waddellClient.Close()
	server.waddellClient = nil
}

func mapPort(addr string, port int) error {
	internalIP, internalPortString, err := net.SplitHostPort(addr)
	if err != nil {
		return fmt.Errorf("Unable to split host and port for %v: %v", addr, err)
	}

	internalPort, err := strconv.Atoi(internalPortString)
	if err != nil {
		return fmt.Errorf("Unable to parse local port: ")
	}

	if internalIP == "" {
		internalIP, err = determineInternalIP()
		if err != nil {
			return fmt.Errorf("Unable to determine internal IP: %s", err)
		}
	}

	igd, err := igdman.NewIGD()
	if err != nil {
		return fmt.Errorf("Unable to get IGD: %s", err)
	}

	igd.RemovePortMapping(igdman.TCP, port)
	err = igd.AddPortMapping(igdman.TCP, internalIP, internalPort, port, 0)
	if err != nil {
		return fmt.Errorf("Unable to map port with igdman %d: %s", port, err)
	}

	return nil
}

func unmapPort(port int) error {
	igd, err := igdman.NewIGD()
	if err != nil {
		return fmt.Errorf("Unable to get IGD: %s", err)
	}

	igd.RemovePortMapping(igdman.TCP, port)
	if err != nil {
		return fmt.Errorf("Unable to unmap port with igdman %d: %s", port, err)
	}

	return nil
}

// determineInternalIP determines the internal IP to use for mapping ports. It
// does this by dialing a website on the public Internet and then finding out
// the LocalAddr for the corresponding connection. This gives us an interface
// that we know has Internet access, which makes it suitable for port mapping.
func determineInternalIP() (string, error) {
	conn, err := net.DialTimeout("tcp", "s3.amazonaws.com:443", 20*time.Second)
	if err != nil {
		return "", fmt.Errorf("Unable to determine local IP: %s", err)
	}
	defer conn.Close()
	host, _, err := net.SplitHostPort(conn.LocalAddr().String())
	return host, err
}

func onBytesGiven(destAddr string, req *http.Request, bytes int64) {
	host, port, _ := net.SplitHostPort(destAddr)
	if port == "" {
		port = "0"
	}

	given := statreporter.CountryDim().
		And("flserver", globals.InstanceId).
		And("destport", port)
	given.Increment("bytesGiven").Add(bytes)
	given.Increment("bytesGivenByFlashlight").Add(bytes)

	clientCountry := req.Header.Get("Cf-Ipcountry")
	if clientCountry != "" {
		givenTo := statreporter.Country(clientCountry)
		givenTo.Increment("bytesGivenTo").Add(bytes)
		givenTo.Increment("bytesGivenToByFlashlight").Add(bytes)
		givenTo.Member("distinctDestHosts", host)

		clientIp := req.Header.Get("X-Forwarded-For")
		if clientIp != "" {
			// clientIp may contain multiple ips, use the first
			ips := strings.Split(clientIp, ",")
			clientIp := strings.TrimSpace(ips[0])
			givenTo.Member("distinctClientIPs", clientIp)
		}

	}
}
<|endoftext|>


<commit_before>// Copyright 2016 VMware, Inc. 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.

// +build linux

// An implementation of the VmdkCmdRunner interface that mocks ESX. This removes the requirement forunning ESX at all when testing the plugin.

package vmdkops

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"strconv"
	"strings"
	"syscall"

	log "github.com/Sirupsen/logrus"
	"github.com/vmware/docker-volume-vsphere/vmdk_plugin/utils/fs"
)

// MockVmdkCmd struct
type MockVmdkCmd struct{}

const (
	backingRoot     = "/tmp/docker-volumes" // Files for loopback device backing stored here
	fileSizeInBytes = 100 * 1024 * 1024     // file size for loopback block device
)

func getBackingFileName(nameBase string) string {
	// make unique name - avoid clashes shall we find any garbage in the directory
	name := fmt.Sprintf("%s/%d/%s", backingRoot, os.Getpid(), nameBase)
	log.WithFields(log.Fields{"name": name}).Debug("Created tmp file for loopback")
	return name
}

// Run returns JSON responses to each command or an error
func (mockCmd MockVmdkCmd) Run(cmd string, name string, opts map[string]string) ([]byte, error) {
	// We store no in memory state, so just try to recreate backingRoot every time
	rootName := fmt.Sprintf("%s/%d", backingRoot, os.Getpid())
	err := fs.Mkdir(rootName)
	if err != nil {
		return nil, err
	}
	log.WithFields(log.Fields{"cmd": cmd}).Debug("Running Mock Cmd")
	switch cmd {
	case "create":
		err := createBlockDevice(name, opts)
		return nil, err
	case "list":
		return list()
	case "get":
		return nil, get(name)
	case "attach":
		return getBlockDeviceForName(name)
	case "detach":
		return nil, nil
	case "remove":
		err := remove(name)
		return nil, err
	}
	return []byte("null"), nil
}

func list() ([]byte, error) {
	rootName := fmt.Sprintf("%s/%d", backingRoot, os.Getpid())
	files, err := ioutil.ReadDir(rootName)
	if err != nil {
		return nil, fmt.Errorf("Failed to read %s", backingRoot)
	}
	volumes := make([]VolumeData, 0, len(files))
	for _, file := range files {
		volumes = append(volumes, VolumeData{Name: file.Name()})
	}
	return json.Marshal(volumes)
}

// validates that the volume exists, returns error or nil (for OK)
func get(name string) error {
	filePath := getBackingFileName(name)
	if _, err := os.Lstat(filePath); os.IsNotExist(err) {
		return fmt.Errorf("Unknown volume %s", name)
	} else if err != nil {
		return err
	}
	return nil
}

func remove(name string) error {
	backing := getBackingFileName(name)
	out, err := exec.Command("blkid", []string{"-L", name}...).CombinedOutput()
	if err != nil {
		return fmt.Errorf("Failed to find device for backing file %s via blkid", backing)
	}
	device := strings.TrimRight(string(out), " \n")
	fmt.Printf("Detaching loopback device %s\n", device)
	out, err = exec.Command("losetup", "-d", device).CombinedOutput()
	if err != nil {
		return fmt.Errorf("Failed to detach loopback device node %s with error: %s. Output = %s",
			device, err, out)
	}
	err = os.Remove(backing)
	if err != nil {
		return fmt.Errorf("Failed to remove backing file %s: %s", backing, err)
	}
	return os.Remove(device)
}

func createBlockDevice(label string, opts map[string]string) error {
	backing := getBackingFileName(label)
	err := createBackingFile(backing)
	if err != nil {
		return err
	}
	loopbackCount := getMaxLoopbackCount() + 1
	device := fmt.Sprintf("/dev/loop%d", loopbackCount)
	err = createDeviceNode(device, loopbackCount)
	if err != nil {
		return err
	}
	// Ignore output. This is to prevent spurious failures from old devices
	// that were removed, but not detached.
	exec.Command("losetup", "-d", device).CombinedOutput()
	err = setupLoopbackDevice(backing, device)
	if err != nil {
		return err
	}
	// Use default fstype if not specified
	if _, result := opts["fstype"]; result == false {
		opts["fstype"] = fs.FstypeDefault
	}
	mkfscmd := fs.MkfsLookup()[opts["fstype"]]
	return fs.Mkfs(mkfscmd, label, device)
}

func getBlockDeviceForName(name string) ([]byte, error) {
	backing := getBackingFileName(name)
	out, err := exec.Command("blkid", []string{"-L", name}...).CombinedOutput()
	if err != nil {
		return nil, fmt.Errorf("Failed to find device for backing file %s via blkid", backing)
	}
	device := strings.TrimRight(string(out), " \n")
	return []byte(device), nil
}

func getMaxLoopbackCount() int {
	// always start at 1000
	count := 1000
	files, err := ioutil.ReadDir("/dev")
	if err != nil {
		panic("Failed to read /dev")
	}
	for _, file := range files {
		trimmed := strings.TrimPrefix(file.Name(), "loop")
		if s, err := strconv.Atoi(trimmed); err == nil {
			if s > count {
				count = s
			}
		}
	}
	return count
}

func createBackingFile(backing string) error {
	flags := syscall.O_RDWR | syscall.O_CREAT | syscall.O_EXCL
	file, err := os.OpenFile(backing, flags, 0755)
	if err != nil {
		return fmt.Errorf("Failed to create backing file %s: %s.", backing, err)
	}
	err = syscall.Fallocate(int(file.Fd()), 0, 0, fileSizeInBytes)
	if err != nil {
		return fmt.Errorf("Failed to allocate %s: %s.", backing, err)
	}
	return nil
}

func createDeviceNode(device string, loopbackCount int) error {
	count := fmt.Sprintf("%d", loopbackCount)
	out, err := exec.Command("mknod", device, "b", "7", count).CombinedOutput()
	if err != nil {
		return fmt.Errorf("Failed to make device node %s: %s. Output = %s",
			device, err, out)
	}
	return nil
}

func setupLoopbackDevice(backing string, device string) error {
	out, err := exec.Command("losetup", device, backing).CombinedOutput()
	if err != nil {
		return fmt.Errorf("Failed to setup loopback device node %s for backing file %s: %s. Output = %s",
			device, backing, err, out)
	}
	return nil
}
<commit_msg>Check for error in mkfs lookup on createBlockDevice()<commit_after>// Copyright 2016 VMware, Inc. 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.

// +build linux

// An implementation of the VmdkCmdRunner interface that mocks ESX. This removes the requirement forunning ESX at all when testing the plugin.

package vmdkops

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"strconv"
	"strings"
	"syscall"

	log "github.com/Sirupsen/logrus"
	"github.com/vmware/docker-volume-vsphere/vmdk_plugin/utils/fs"
)

// MockVmdkCmd struct
type MockVmdkCmd struct{}

const (
	backingRoot     = "/tmp/docker-volumes" // Files for loopback device backing stored here
	fileSizeInBytes = 100 * 1024 * 1024     // file size for loopback block device
)

func getBackingFileName(nameBase string) string {
	// make unique name - avoid clashes shall we find any garbage in the directory
	name := fmt.Sprintf("%s/%d/%s", backingRoot, os.Getpid(), nameBase)
	log.WithFields(log.Fields{"name": name}).Debug("Created tmp file for loopback")
	return name
}

// Run returns JSON responses to each command or an error
func (mockCmd MockVmdkCmd) Run(cmd string, name string, opts map[string]string) ([]byte, error) {
	// We store no in memory state, so just try to recreate backingRoot every time
	rootName := fmt.Sprintf("%s/%d", backingRoot, os.Getpid())
	err := fs.Mkdir(rootName)
	if err != nil {
		return nil, err
	}
	log.WithFields(log.Fields{"cmd": cmd}).Debug("Running Mock Cmd")
	switch cmd {
	case "create":
		err := createBlockDevice(name, opts)
		return nil, err
	case "list":
		return list()
	case "get":
		return nil, get(name)
	case "attach":
		return getBlockDeviceForName(name)
	case "detach":
		return nil, nil
	case "remove":
		err := remove(name)
		return nil, err
	}
	return []byte("null"), nil
}

func list() ([]byte, error) {
	rootName := fmt.Sprintf("%s/%d", backingRoot, os.Getpid())
	files, err := ioutil.ReadDir(rootName)
	if err != nil {
		return nil, fmt.Errorf("Failed to read %s", backingRoot)
	}
	volumes := make([]VolumeData, 0, len(files))
	for _, file := range files {
		volumes = append(volumes, VolumeData{Name: file.Name()})
	}
	return json.Marshal(volumes)
}

// validates that the volume exists, returns error or nil (for OK)
func get(name string) error {
	filePath := getBackingFileName(name)
	if _, err := os.Lstat(filePath); os.IsNotExist(err) {
		return fmt.Errorf("Unknown volume %s", name)
	} else if err != nil {
		return err
	}
	return nil
}

func remove(name string) error {
	backing := getBackingFileName(name)
	out, err := exec.Command("blkid", []string{"-L", name}...).CombinedOutput()
	if err != nil {
		return fmt.Errorf("Failed to find device for backing file %s via blkid", backing)
	}
	device := strings.TrimRight(string(out), " \n")
	fmt.Printf("Detaching loopback device %s\n", device)
	out, err = exec.Command("losetup", "-d", device).CombinedOutput()
	if err != nil {
		return fmt.Errorf("Failed to detach loopback device node %s with error: %s. Output = %s",
			device, err, out)
	}
	err = os.Remove(backing)
	if err != nil {
		return fmt.Errorf("Failed to remove backing file %s: %s", backing, err)
	}
	return os.Remove(device)
}

func createBlockDevice(label string, opts map[string]string) error {
	backing := getBackingFileName(label)
	err := createBackingFile(backing)
	if err != nil {
		return err
	}
	loopbackCount := getMaxLoopbackCount() + 1
	device := fmt.Sprintf("/dev/loop%d", loopbackCount)
	err = createDeviceNode(device, loopbackCount)
	if err != nil {
		return err
	}
	// Ignore output. This is to prevent spurious failures from old devices
	// that were removed, but not detached.
	exec.Command("losetup", "-d", device).CombinedOutput()
	err = setupLoopbackDevice(backing, device)
	if err != nil {
		return err
	}
	// Use default fstype if not specified
	if _, result := opts["fstype"]; result == false {
		opts["fstype"] = fs.FstypeDefault
	}
	mkfscmd, result := fs.MkfsLookup()[opts["fstype"]]
	if result == false {
		return fmt.Errorf("Not found mkfs for %s", opts["fstype"])
	}
	return fs.Mkfs(mkfscmd, label, device)
}

func getBlockDeviceForName(name string) ([]byte, error) {
	backing := getBackingFileName(name)
	out, err := exec.Command("blkid", []string{"-L", name}...).CombinedOutput()
	if err != nil {
		return nil, fmt.Errorf("Failed to find device for backing file %s via blkid", backing)
	}
	device := strings.TrimRight(string(out), " \n")
	return []byte(device), nil
}

func getMaxLoopbackCount() int {
	// always start at 1000
	count := 1000
	files, err := ioutil.ReadDir("/dev")
	if err != nil {
		panic("Failed to read /dev")
	}
	for _, file := range files {
		trimmed := strings.TrimPrefix(file.Name(), "loop")
		if s, err := strconv.Atoi(trimmed); err == nil {
			if s > count {
				count = s
			}
		}
	}
	return count
}

func createBackingFile(backing string) error {
	flags := syscall.O_RDWR | syscall.O_CREAT | syscall.O_EXCL
	file, err := os.OpenFile(backing, flags, 0755)
	if err != nil {
		return fmt.Errorf("Failed to create backing file %s: %s.", backing, err)
	}
	err = syscall.Fallocate(int(file.Fd()), 0, 0, fileSizeInBytes)
	if err != nil {
		return fmt.Errorf("Failed to allocate %s: %s.", backing, err)
	}
	return nil
}

func createDeviceNode(device string, loopbackCount int) error {
	count := fmt.Sprintf("%d", loopbackCount)
	out, err := exec.Command("mknod", device, "b", "7", count).CombinedOutput()
	if err != nil {
		return fmt.Errorf("Failed to make device node %s: %s. Output = %s",
			device, err, out)
	}
	return nil
}

func setupLoopbackDevice(backing string, device string) error {
	out, err := exec.Command("losetup", device, backing).CombinedOutput()
	if err != nil {
		return fmt.Errorf("Failed to setup loopback device node %s for backing file %s: %s. Output = %s",
			device, backing, err, out)
	}
	return nil
}
<|endoftext|>


<commit_before>package magicnum

import (
	"bytes"
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	"strings"
)

const (
	Unknown    Format = iota // unknown format
	Gzip                     // Gzip compression format
	Tar                      // Tar format; normally used
	Tar1                     // Tar1 header format; normalizes to Tar
	Tar2                     // Tar1 header format; normalizes to Tar
	Zip                      // Zip archive
	ZipEmpty                 // Empty Zip Archive
	ZipSpanned               // Spanned Zip Archive
	Bzip2                    // Bzip2 compression
	LZW                      // LZW compression
	LZ4                      // LZ4 compression
)

// TODO: should Format be more specific? e.g. CompressionFormat, MediaFormat, etc.
type Format int

func (f Format) String() string {
	switch f {
	case Gzip:
		return "gzip"
	case Tar, Tar1, Tar2:
		return "tar"
	case Zip:
		return "zip"
	case ZipEmpty:
		return "empty zip archive"
	case ZipSpanned:
		return "spanned zip archive"
	case Bzip2:
		return "bzip2"
	case LZW:
		return "lzw"
	case LZ4:
		return "lz4"
	}
	return "unknown"
}

// Ext returns the extension for the format. Formats may have more than one
// accepted extension; alternate extensiona are not supported.
func (f Format) Ext() string {
	switch f {
	case Gzip:
		return ".gz"
	case Tar, Tar1, Tar2:
		return ".tar"
	case Zip, ZipEmpty, ZipSpanned:
		return ".zip"
	case Bzip2:
		return ".bz2"
	case LZW:
		return ".Z"
	case LZ4:
		return "lz4"
	}
	return "unknown"
}

func FormatFromString(s string) Format {
	s = strings.ToLower(s)
	switch s {
	case "gzip", "gz":
		return Gzip
	case "tar":
		return Tar
	case "zip":
		return Zip
	case "bzip2", "bz2":
		return Bzip2
	case "lzw", "Z":
		return LZW
	case "lz4":
		return LZ4
	}
	return Unknown
}

// Magic numbers for supported formats
var (
	headerGzip       = []byte{0x1f, 0x8b}
	headerTar1       = []byte{0x75, 0x73, 0x74, 0x61, 0x72, 0x00, 0x30, 0x30} // offset: 257
	headerTar2       = []byte{0x75, 0x73, 0x74, 0x61, 0x72, 0x00, 0x20, 0x00} // offset: 257
	headerZip        = []byte{0x50, 0x4b, 0x03, 0x04}
	headerZipEmpty   = []byte{0x50, 0x4b, 0x05, 0x06}
	headerZipSpanned = []byte{0x50, 0x4b, 0x07, 0x08}
	headerBzip2      = []byte{0x42, 0x5a, 0x68}
	headerLZW        = []byte{0x1F, 0x9d}
	headerLZ4        = []byte{0x18, 0x4d, 0x22, 0x04}
)

// GetFormat tries to match up the data in the Reader to a supported
// magic number, if a match isn't found, UnsupportedFmt is returned
//
// For zips, this will also match on files with empty zip or spanned zip magic
// numbers.  If you need to distinguich between the various zip formats, use
// something else.
func GetFormat(r io.ReaderAt) (Format, error) {
	ok, err := IsLZ4(r)
	if err != nil {
		return Unknown, err
	}
	if ok {
		return LZ4, nil
	}
	ok, err = IsGzip(r)
	if err != nil {
		return Unknown, err
	}
	if ok {
		return Gzip, nil
	}
	ok, err = IsZip(r)
	if err != nil {
		return Unknown, err
	}
	if ok {
		return Zip, nil
	}
	ok, err = IsTar(r)
	if err != nil {
		return Unknown, err
	}
	if ok {
		return Tar, nil
	}
	ok, err = IsBzip2(r)
	if err != nil {
		return Unknown, err
	}
	if ok {
		return Bzip2, nil
	}
	ok, err = IsLZW(r)
	if err != nil {
		return Unknown, err
	}
	if ok {
		return LZW, nil
	}
	return Unknown, errors.New("unsupported format: input format is not known")
}

// IsBzip2 checks to see if the received reader's contents are in bzip2 format
// by checking the magic numbers.
func IsBzip2(r io.ReaderAt) (bool, error) {
	h := make([]byte, 3)
	// Read the first 3 bytes
	_, err := r.ReadAt(h, 0)
	if err != nil {
		return false, err
	}
	var hb [3]byte
	// check for bzip2
	hbuf := bytes.NewReader(h)
	err = binary.Read(hbuf, binary.LittleEndian, &hb)
	if err != nil {
		return false, fmt.Errorf("error while checking if input matched bzip2's magic number: %s", err)
	}
	var cb [3]byte
	cbuf := bytes.NewBuffer(headerBzip2)
	err = binary.Read(cbuf, binary.BigEndian, &cb)
	if err != nil {
		return false, fmt.Errorf("error while converting bzip2 magic number for comparison: %s", err)
	}
	if hb == cb {
		return true, nil
	}
	return false, nil
}

// IsGzip checks to see if the received reader's contents are in gzip format
// by checking the magic numbers.
func IsGzip(r io.ReaderAt) (bool, error) {
	h := make([]byte, 2)
	// Read the first 2 bytes
	_, err := r.ReadAt(h, 0)
	if err != nil {
		return false, err
	}
	var h16 uint16
	// check for gzip
	hbuf := bytes.NewReader(h)
	err = binary.Read(hbuf, binary.BigEndian, &h16)
	if err != nil {
		return false, fmt.Errorf("error while checking if input matched bzip2's magic number: %s", err)
	}
	var c16 uint16
	cbuf := bytes.NewBuffer(headerGzip)
	err = binary.Read(cbuf, binary.BigEndian, &c16)
	if err != nil {
		return false, fmt.Errorf("error while converting bzip2 magic number for comparison: %s", err)
	}
	if h16 == c16 {
		return true, nil
	}
	return false, nil
}

// IsLZ4 checks to see if the received reader's contents are in LZ4 foramt by
// checking the magic numbers.
func IsLZ4(r io.ReaderAt) (bool, error) {
	h := make([]byte, 4)
	// Read the first 4 bytes
	_, err := r.ReadAt(h, 0)
	if err != nil {
		return false, err
	}
	var h32 uint32
	// check for lz4
	hbuf := bytes.NewReader(h)
	err = binary.Read(hbuf, binary.LittleEndian, &h32)
	if err != nil {
		return false, fmt.Errorf("error while checking if input matched LZ4's magic number: %s", err)
	}
	var c32 uint32
	cbuf := bytes.NewBuffer(headerLZ4)
	err = binary.Read(cbuf, binary.BigEndian, &c32)
	if err != nil {
		return false, fmt.Errorf("error while converting LZ4 magic number for comparison: %s", err)
	}
	if h32 == c32 {
		return true, nil
	}
	return false, nil
}

// IsLZW checks to see if the received reader's contents are in LZ4 format by
// checking the magic numbers.
func IsLZW(r io.ReaderAt) (bool, error) {
	h := make([]byte, 2)
	// Reat the first 8 bytes since that's where most magic numbers are
	_, err := r.ReadAt(h, 0)
	if err != nil {
		return false, err
	}
	var h16 uint16
	// check for lzw
	hbuf := bytes.NewReader(h)
	err = binary.Read(hbuf, binary.LittleEndian, &h16)
	if err != nil {
		return false, fmt.Errorf("error while checking if input matched LZW's magic number: %s", err)
	}
	var c16 uint16
	cbuf := bytes.NewBuffer(headerLZW)
	err = binary.Read(cbuf, binary.BigEndian, &c16)
	if err != nil {
		return false, fmt.Errorf("error while converting LZW magic number for comparison: %s", err)
	}
	if h16 == c16 {
		return true, nil
	}
	return false, nil
}

// IsTar checks to see if the received reader's contents are in the tar format
// by checking the magic numbers. This evaluates using both tar1 and tar2 magic
// numbers.
func IsTar(r io.ReaderAt) (bool, error) {
	h := make([]byte, 8)
	// Read the first 8 bytes at offset 257
	_, err := r.ReadAt(h, 257)
	if err != nil {
		return false, err
	}
	var h64 uint64
	// check for Zip
	hbuf := bytes.NewReader(h)
	err = binary.Read(hbuf, binary.BigEndian, &h64)
	if err != nil {
		return false, fmt.Errorf("error while checking if input matched tar's magic number: %s", err)
	}
	var c64 uint64
	cbuf := bytes.NewBuffer(headerTar1)
	err = binary.Read(cbuf, binary.BigEndian, &c64)
	if err != nil {
		return false, fmt.Errorf("error while converting the tar magic number for comparison: %s", err)
	}
	if h64 == c64 {
		return true, nil
	}
	cbuf = bytes.NewBuffer(headerTar2)
	err = binary.Read(cbuf, binary.BigEndian, &c64)
	if err != nil {
		return false, fmt.Errorf("error while converting the empty tar magic number for comparison: %s", err)
	}
	if h64 == c64 {
		return true, nil
	}
	return false, nil
}

// IsZip checks to see if the received reader's contents are in the zip format
// by checking the magic numbers. This will match on zip, empty zip and spanned
// zip magic numbers. If you need to distinguish between those, use something
// else.
func IsZip(r io.ReaderAt) (bool, error) {
	h := make([]byte, 4)
	// Read the first 4 bytes
	_, err := r.ReadAt(h, 0)
	if err != nil {
		return false, err
	}
	var h32 uint32
	// check for Zip
	hbuf := bytes.NewReader(h)
	err = binary.Read(hbuf, binary.BigEndian, &h32)
	if err != nil {
		return false, fmt.Errorf("error while checking if input matched zip's magic number: %s", err)
	}
	var c32 uint32
	cbuf := bytes.NewBuffer(headerZip)
	err = binary.Read(cbuf, binary.BigEndian, &c32)
	if err != nil {
		return false, fmt.Errorf("error while converting the zip magic number for comparison: %s", err)
	}
	if h32 == c32 {
		return true, nil
	}
	cbuf = bytes.NewBuffer(headerZipEmpty)
	err = binary.Read(cbuf, binary.BigEndian, &c32)
	if err != nil {
		return false, fmt.Errorf("error while converting the empty zip magic number for comparison: %s", err)
	}
	if h32 == c32 {
		return true, nil
	}
	cbuf = bytes.NewBuffer(headerZipSpanned)
	err = binary.Read(cbuf, binary.BigEndian, &c32)
	if err != nil {
		return false, fmt.Errorf("error while converting the spanned zip magic number for comparison: %s", err)
	}
	if h32 == c32 {
		return true, nil
	}
	return false, nil
}
<commit_msg>lz4 extension should start with a .<commit_after>package magicnum

import (
	"bytes"
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	"strings"
)

const (
	Unknown    Format = iota // unknown format
	Gzip                     // Gzip compression format
	Tar                      // Tar format; normally used
	Tar1                     // Tar1 header format; normalizes to Tar
	Tar2                     // Tar1 header format; normalizes to Tar
	Zip                      // Zip archive
	ZipEmpty                 // Empty Zip Archive
	ZipSpanned               // Spanned Zip Archive
	Bzip2                    // Bzip2 compression
	LZW                      // LZW compression
	LZ4                      // LZ4 compression
)

// TODO: should Format be more specific? e.g. CompressionFormat, MediaFormat, etc.
type Format int

func (f Format) String() string {
	switch f {
	case Gzip:
		return "gzip"
	case Tar, Tar1, Tar2:
		return "tar"
	case Zip:
		return "zip"
	case ZipEmpty:
		return "empty zip archive"
	case ZipSpanned:
		return "spanned zip archive"
	case Bzip2:
		return "bzip2"
	case LZW:
		return "lzw"
	case LZ4:
		return "lz4"
	}
	return "unknown"
}

// Ext returns the extension for the format. Formats may have more than one
// accepted extension; alternate extensiona are not supported.
func (f Format) Ext() string {
	switch f {
	case Gzip:
		return ".gz"
	case Tar, Tar1, Tar2:
		return ".tar"
	case Zip, ZipEmpty, ZipSpanned:
		return ".zip"
	case Bzip2:
		return ".bz2"
	case LZW:
		return ".Z"
	case LZ4:
		return ".lz4"
	}
	return "unknown"
}

func FormatFromString(s string) Format {
	s = strings.ToLower(s)
	switch s {
	case "gzip", "gz":
		return Gzip
	case "tar":
		return Tar
	case "zip":
		return Zip
	case "bzip2", "bz2":
		return Bzip2
	case "lzw", "Z":
		return LZW
	case "lz4":
		return LZ4
	}
	return Unknown
}

// Magic numbers for supported formats
var (
	headerGzip       = []byte{0x1f, 0x8b}
	headerTar1       = []byte{0x75, 0x73, 0x74, 0x61, 0x72, 0x00, 0x30, 0x30} // offset: 257
	headerTar2       = []byte{0x75, 0x73, 0x74, 0x61, 0x72, 0x00, 0x20, 0x00} // offset: 257
	headerZip        = []byte{0x50, 0x4b, 0x03, 0x04}
	headerZipEmpty   = []byte{0x50, 0x4b, 0x05, 0x06}
	headerZipSpanned = []byte{0x50, 0x4b, 0x07, 0x08}
	headerBzip2      = []byte{0x42, 0x5a, 0x68}
	headerLZW        = []byte{0x1F, 0x9d}
	headerLZ4        = []byte{0x18, 0x4d, 0x22, 0x04}
)

// GetFormat tries to match up the data in the Reader to a supported
// magic number, if a match isn't found, UnsupportedFmt is returned
//
// For zips, this will also match on files with empty zip or spanned zip magic
// numbers.  If you need to distinguich between the various zip formats, use
// something else.
func GetFormat(r io.ReaderAt) (Format, error) {
	ok, err := IsLZ4(r)
	if err != nil {
		return Unknown, err
	}
	if ok {
		return LZ4, nil
	}
	ok, err = IsGzip(r)
	if err != nil {
		return Unknown, err
	}
	if ok {
		return Gzip, nil
	}
	ok, err = IsZip(r)
	if err != nil {
		return Unknown, err
	}
	if ok {
		return Zip, nil
	}
	ok, err = IsTar(r)
	if err != nil {
		return Unknown, err
	}
	if ok {
		return Tar, nil
	}
	ok, err = IsBzip2(r)
	if err != nil {
		return Unknown, err
	}
	if ok {
		return Bzip2, nil
	}
	ok, err = IsLZW(r)
	if err != nil {
		return Unknown, err
	}
	if ok {
		return LZW, nil
	}
	return Unknown, errors.New("unsupported format: input format is not known")
}

// IsBzip2 checks to see if the received reader's contents are in bzip2 format
// by checking the magic numbers.
func IsBzip2(r io.ReaderAt) (bool, error) {
	h := make([]byte, 3)
	// Read the first 3 bytes
	_, err := r.ReadAt(h, 0)
	if err != nil {
		return false, err
	}
	var hb [3]byte
	// check for bzip2
	hbuf := bytes.NewReader(h)
	err = binary.Read(hbuf, binary.LittleEndian, &hb)
	if err != nil {
		return false, fmt.Errorf("error while checking if input matched bzip2's magic number: %s", err)
	}
	var cb [3]byte
	cbuf := bytes.NewBuffer(headerBzip2)
	err = binary.Read(cbuf, binary.BigEndian, &cb)
	if err != nil {
		return false, fmt.Errorf("error while converting bzip2 magic number for comparison: %s", err)
	}
	if hb == cb {
		return true, nil
	}
	return false, nil
}

// IsGzip checks to see if the received reader's contents are in gzip format
// by checking the magic numbers.
func IsGzip(r io.ReaderAt) (bool, error) {
	h := make([]byte, 2)
	// Read the first 2 bytes
	_, err := r.ReadAt(h, 0)
	if err != nil {
		return false, err
	}
	var h16 uint16
	// check for gzip
	hbuf := bytes.NewReader(h)
	err = binary.Read(hbuf, binary.BigEndian, &h16)
	if err != nil {
		return false, fmt.Errorf("error while checking if input matched bzip2's magic number: %s", err)
	}
	var c16 uint16
	cbuf := bytes.NewBuffer(headerGzip)
	err = binary.Read(cbuf, binary.BigEndian, &c16)
	if err != nil {
		return false, fmt.Errorf("error while converting bzip2 magic number for comparison: %s", err)
	}
	if h16 == c16 {
		return true, nil
	}
	return false, nil
}

// IsLZ4 checks to see if the received reader's contents are in LZ4 foramt by
// checking the magic numbers.
func IsLZ4(r io.ReaderAt) (bool, error) {
	h := make([]byte, 4)
	// Read the first 4 bytes
	_, err := r.ReadAt(h, 0)
	if err != nil {
		return false, err
	}
	var h32 uint32
	// check for lz4
	hbuf := bytes.NewReader(h)
	err = binary.Read(hbuf, binary.LittleEndian, &h32)
	if err != nil {
		return false, fmt.Errorf("error while checking if input matched LZ4's magic number: %s", err)
	}
	var c32 uint32
	cbuf := bytes.NewBuffer(headerLZ4)
	err = binary.Read(cbuf, binary.BigEndian, &c32)
	if err != nil {
		return false, fmt.Errorf("error while converting LZ4 magic number for comparison: %s", err)
	}
	if h32 == c32 {
		return true, nil
	}
	return false, nil
}

// IsLZW checks to see if the received reader's contents are in LZ4 format by
// checking the magic numbers.
func IsLZW(r io.ReaderAt) (bool, error) {
	h := make([]byte, 2)
	// Reat the first 8 bytes since that's where most magic numbers are
	_, err := r.ReadAt(h, 0)
	if err != nil {
		return false, err
	}
	var h16 uint16
	// check for lzw
	hbuf := bytes.NewReader(h)
	err = binary.Read(hbuf, binary.LittleEndian, &h16)
	if err != nil {
		return false, fmt.Errorf("error while checking if input matched LZW's magic number: %s", err)
	}
	var c16 uint16
	cbuf := bytes.NewBuffer(headerLZW)
	err = binary.Read(cbuf, binary.BigEndian, &c16)
	if err != nil {
		return false, fmt.Errorf("error while converting LZW magic number for comparison: %s", err)
	}
	if h16 == c16 {
		return true, nil
	}
	return false, nil
}

// IsTar checks to see if the received reader's contents are in the tar format
// by checking the magic numbers. This evaluates using both tar1 and tar2 magic
// numbers.
func IsTar(r io.ReaderAt) (bool, error) {
	h := make([]byte, 8)
	// Read the first 8 bytes at offset 257
	_, err := r.ReadAt(h, 257)
	if err != nil {
		return false, err
	}
	var h64 uint64
	// check for Zip
	hbuf := bytes.NewReader(h)
	err = binary.Read(hbuf, binary.BigEndian, &h64)
	if err != nil {
		return false, fmt.Errorf("error while checking if input matched tar's magic number: %s", err)
	}
	var c64 uint64
	cbuf := bytes.NewBuffer(headerTar1)
	err = binary.Read(cbuf, binary.BigEndian, &c64)
	if err != nil {
		return false, fmt.Errorf("error while converting the tar magic number for comparison: %s", err)
	}
	if h64 == c64 {
		return true, nil
	}
	cbuf = bytes.NewBuffer(headerTar2)
	err = binary.Read(cbuf, binary.BigEndian, &c64)
	if err != nil {
		return false, fmt.Errorf("error while converting the empty tar magic number for comparison: %s", err)
	}
	if h64 == c64 {
		return true, nil
	}
	return false, nil
}

// IsZip checks to see if the received reader's contents are in the zip format
// by checking the magic numbers. This will match on zip, empty zip and spanned
// zip magic numbers. If you need to distinguish between those, use something
// else.
func IsZip(r io.ReaderAt) (bool, error) {
	h := make([]byte, 4)
	// Read the first 4 bytes
	_, err := r.ReadAt(h, 0)
	if err != nil {
		return false, err
	}
	var h32 uint32
	// check for Zip
	hbuf := bytes.NewReader(h)
	err = binary.Read(hbuf, binary.BigEndian, &h32)
	if err != nil {
		return false, fmt.Errorf("error while checking if input matched zip's magic number: %s", err)
	}
	var c32 uint32
	cbuf := bytes.NewBuffer(headerZip)
	err = binary.Read(cbuf, binary.BigEndian, &c32)
	if err != nil {
		return false, fmt.Errorf("error while converting the zip magic number for comparison: %s", err)
	}
	if h32 == c32 {
		return true, nil
	}
	cbuf = bytes.NewBuffer(headerZipEmpty)
	err = binary.Read(cbuf, binary.BigEndian, &c32)
	if err != nil {
		return false, fmt.Errorf("error while converting the empty zip magic number for comparison: %s", err)
	}
	if h32 == c32 {
		return true, nil
	}
	cbuf = bytes.NewBuffer(headerZipSpanned)
	err = binary.Read(cbuf, binary.BigEndian, &c32)
	if err != nil {
		return false, fmt.Errorf("error while converting the spanned zip magic number for comparison: %s", err)
	}
	if h32 == c32 {
		return true, nil
	}
	return false, nil
}
<|endoftext|>


<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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 v4

import (
	"encoding/json"
	"github.com/apache/incubator-servicecomb-service-center/pkg/rest"
	"github.com/apache/incubator-servicecomb-service-center/pkg/util"
	"github.com/apache/incubator-servicecomb-service-center/server/core"
	pb "github.com/apache/incubator-servicecomb-service-center/server/core/proto"
	scerr "github.com/apache/incubator-servicecomb-service-center/server/error"
	"github.com/apache/incubator-servicecomb-service-center/server/rest/controller"
	"io/ioutil"
	"net/http"
	"strings"
)

type MicroServiceService struct {
	//
}

func (this *MicroServiceService) URLPatterns() []rest.Route {
	return []rest.Route{
		{rest.HTTP_METHOD_GET, "/v4/:project/registry/existence", this.GetExistence},
		{rest.HTTP_METHOD_GET, "/v4/:project/registry/microservices", this.GetServices},
		{rest.HTTP_METHOD_GET, "/v4/:project/registry/microservices/:serviceId", this.GetServiceOne},
		{rest.HTTP_METHOD_POST, "/v4/:project/registry/microservices", this.Register},
		{rest.HTTP_METHOD_PUT, "/v4/:project/registry/microservices/:serviceId/properties", this.Update},
		{rest.HTTP_METHOD_DELETE, "/v4/:project/registry/microservices/:serviceId", this.Unregister},
		{rest.HTTP_METHOD_DELETE, "/v4/:project/registry/microservices", this.UnregisterServices},
	}
}

func (this *MicroServiceService) Register(w http.ResponseWriter, r *http.Request) {
	message, err := ioutil.ReadAll(r.Body)
	if err != nil {
		util.Logger().Error("body err", err)
		controller.WriteError(w, scerr.ErrInvalidParams, err.Error())
		return
	}
	var request pb.CreateServiceRequest
	err = json.Unmarshal(message, &request)
	if err != nil {
		util.Logger().Error("Unmarshal error", err)
		controller.WriteError(w, scerr.ErrInvalidParams, err.Error())
		return
	}
	resp, err := core.ServiceAPI.Create(r.Context(), &request)
	respInternal := resp.Response
	resp.Response = nil
	controller.WriteResponse(w, respInternal, resp)
}

func (this *MicroServiceService) Update(w http.ResponseWriter, r *http.Request) {
	message, err := ioutil.ReadAll(r.Body)
	if err != nil {
		util.Logger().Error("body err", err)
		controller.WriteError(w, scerr.ErrInvalidParams, err.Error())
		return
	}
	request := &pb.UpdateServicePropsRequest{
		ServiceId: r.URL.Query().Get(":serviceId"),
	}
	err = json.Unmarshal(message, request)
	if err != nil {
		util.Logger().Error("Unmarshal error", err)
		controller.WriteError(w, scerr.ErrInvalidParams, err.Error())
		return
	}
	resp, err := core.ServiceAPI.UpdateProperties(r.Context(), request)
	controller.WriteResponse(w, resp.Response, nil)
}

func (this *MicroServiceService) Unregister(w http.ResponseWriter, r *http.Request) {
	force := r.URL.Query().Get("force")
	serviceId := r.URL.Query().Get(":serviceId")
	if force != "false" && force != "true" && strings.TrimSpace(force) != "" {
		controller.WriteError(w, scerr.ErrInvalidParams, "parameter force must be false or true")
		return
	}
	request := &pb.DeleteServiceRequest{
		ServiceId: serviceId,
		Force:     force == "true",
	}
	resp, _ := core.ServiceAPI.Delete(r.Context(), request)
	controller.WriteResponse(w, resp.Response, nil)
}

func (this *MicroServiceService) GetServices(w http.ResponseWriter, r *http.Request) {
	request := &pb.GetServicesRequest{}
	resp, _ := core.ServiceAPI.GetServices(r.Context(), request)
	respInternal := resp.Response
	resp.Response = nil
	controller.WriteResponse(w, respInternal, resp)
}

func (this *MicroServiceService) GetExistence(w http.ResponseWriter, r *http.Request) {
	request := &pb.GetExistenceRequest{
		Type:        r.URL.Query().Get("type"),
		Environment: r.URL.Query().Get("env"),
		AppId:       r.URL.Query().Get("appId"),
		ServiceName: r.URL.Query().Get("serviceName"),
		Version:     r.URL.Query().Get("version"),
		ServiceId:   r.URL.Query().Get("serviceId"),
		SchemaId:    r.URL.Query().Get("schemaId"),
	}
	resp, _ := core.ServiceAPI.Exist(r.Context(), request)
	w.Header().Add("X-Schema-Summary", resp.Summary)
	respInternal := resp.Response
	resp.Response = nil
	resp.Summary = ""
	controller.WriteResponse(w, respInternal, resp)
}

func (this *MicroServiceService) GetServiceOne(w http.ResponseWriter, r *http.Request) {
	request := &pb.GetServiceRequest{
		ServiceId: r.URL.Query().Get(":serviceId"),
	}
	resp, _ := core.ServiceAPI.GetOne(r.Context(), request)
	respInternal := resp.Response
	resp.Response = nil
	controller.WriteResponse(w, respInternal, resp)
}

func (this *MicroServiceService) UnregisterServices(w http.ResponseWriter, r *http.Request) {
	request_body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		util.Logger().Error("body ,err", err)
		controller.WriteError(w, scerr.ErrInvalidParams, err.Error())
		return
	}

	request := &pb.DelServicesRequest{}

	err = json.Unmarshal(request_body, request)
	if err != nil {
		util.Logger().Error("unmarshal ,err ", err)
		controller.WriteError(w, scerr.ErrInvalidParams, err.Error())
		return
	}

	resp, err := core.ServiceAPI.DeleteServices(r.Context(), request)
	respInternal := resp.Response
	resp.Response = nil
	controller.WriteResponse(w, respInternal, resp)
}
<commit_msg>SCB-622 Compatible with old version (#360)<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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 v4

import (
	"encoding/json"
	"github.com/apache/incubator-servicecomb-service-center/pkg/rest"
	"github.com/apache/incubator-servicecomb-service-center/pkg/util"
	"github.com/apache/incubator-servicecomb-service-center/server/core"
	pb "github.com/apache/incubator-servicecomb-service-center/server/core/proto"
	scerr "github.com/apache/incubator-servicecomb-service-center/server/error"
	"github.com/apache/incubator-servicecomb-service-center/server/rest/controller"
	"io/ioutil"
	"net/http"
)

var trueOrFalse = map[string]bool{"true": true, "false": false, "1": true, "0": false}

type MicroServiceService struct {
	//
}

func (this *MicroServiceService) URLPatterns() []rest.Route {
	return []rest.Route{
		{rest.HTTP_METHOD_GET, "/v4/:project/registry/existence", this.GetExistence},
		{rest.HTTP_METHOD_GET, "/v4/:project/registry/microservices", this.GetServices},
		{rest.HTTP_METHOD_GET, "/v4/:project/registry/microservices/:serviceId", this.GetServiceOne},
		{rest.HTTP_METHOD_POST, "/v4/:project/registry/microservices", this.Register},
		{rest.HTTP_METHOD_PUT, "/v4/:project/registry/microservices/:serviceId/properties", this.Update},
		{rest.HTTP_METHOD_DELETE, "/v4/:project/registry/microservices/:serviceId", this.Unregister},
		{rest.HTTP_METHOD_DELETE, "/v4/:project/registry/microservices", this.UnregisterServices},
	}
}

func (this *MicroServiceService) Register(w http.ResponseWriter, r *http.Request) {
	message, err := ioutil.ReadAll(r.Body)
	if err != nil {
		util.Logger().Error("body err", err)
		controller.WriteError(w, scerr.ErrInvalidParams, err.Error())
		return
	}
	var request pb.CreateServiceRequest
	err = json.Unmarshal(message, &request)
	if err != nil {
		util.Logger().Error("Unmarshal error", err)
		controller.WriteError(w, scerr.ErrInvalidParams, err.Error())
		return
	}
	resp, err := core.ServiceAPI.Create(r.Context(), &request)
	respInternal := resp.Response
	resp.Response = nil
	controller.WriteResponse(w, respInternal, resp)
}

func (this *MicroServiceService) Update(w http.ResponseWriter, r *http.Request) {
	message, err := ioutil.ReadAll(r.Body)
	if err != nil {
		util.Logger().Error("body err", err)
		controller.WriteError(w, scerr.ErrInvalidParams, err.Error())
		return
	}
	request := &pb.UpdateServicePropsRequest{
		ServiceId: r.URL.Query().Get(":serviceId"),
	}
	err = json.Unmarshal(message, request)
	if err != nil {
		util.Logger().Error("Unmarshal error", err)
		controller.WriteError(w, scerr.ErrInvalidParams, err.Error())
		return
	}
	resp, err := core.ServiceAPI.UpdateProperties(r.Context(), request)
	controller.WriteResponse(w, resp.Response, nil)
}

func (this *MicroServiceService) Unregister(w http.ResponseWriter, r *http.Request) {
	serviceId := r.URL.Query().Get(":serviceId")
	force := r.URL.Query().Get("force")

	b, ok := trueOrFalse[force]
	if force != "" && !ok {
		controller.WriteError(w, scerr.ErrInvalidParams, "parameter force must be false or true")
		return
	}

	request := &pb.DeleteServiceRequest{
		ServiceId: serviceId,
		Force:     b,
	}
	resp, _ := core.ServiceAPI.Delete(r.Context(), request)
	controller.WriteResponse(w, resp.Response, nil)
}

func (this *MicroServiceService) GetServices(w http.ResponseWriter, r *http.Request) {
	request := &pb.GetServicesRequest{}
	resp, _ := core.ServiceAPI.GetServices(r.Context(), request)
	respInternal := resp.Response
	resp.Response = nil
	controller.WriteResponse(w, respInternal, resp)
}

func (this *MicroServiceService) GetExistence(w http.ResponseWriter, r *http.Request) {
	request := &pb.GetExistenceRequest{
		Type:        r.URL.Query().Get("type"),
		Environment: r.URL.Query().Get("env"),
		AppId:       r.URL.Query().Get("appId"),
		ServiceName: r.URL.Query().Get("serviceName"),
		Version:     r.URL.Query().Get("version"),
		ServiceId:   r.URL.Query().Get("serviceId"),
		SchemaId:    r.URL.Query().Get("schemaId"),
	}
	resp, _ := core.ServiceAPI.Exist(r.Context(), request)
	w.Header().Add("X-Schema-Summary", resp.Summary)
	respInternal := resp.Response
	resp.Response = nil
	resp.Summary = ""
	controller.WriteResponse(w, respInternal, resp)
}

func (this *MicroServiceService) GetServiceOne(w http.ResponseWriter, r *http.Request) {
	request := &pb.GetServiceRequest{
		ServiceId: r.URL.Query().Get(":serviceId"),
	}
	resp, _ := core.ServiceAPI.GetOne(r.Context(), request)
	respInternal := resp.Response
	resp.Response = nil
	controller.WriteResponse(w, respInternal, resp)
}

func (this *MicroServiceService) UnregisterServices(w http.ResponseWriter, r *http.Request) {
	request_body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		util.Logger().Error("body ,err", err)
		controller.WriteError(w, scerr.ErrInvalidParams, err.Error())
		return
	}

	request := &pb.DelServicesRequest{}

	err = json.Unmarshal(request_body, request)
	if err != nil {
		util.Logger().Error("unmarshal ,err ", err)
		controller.WriteError(w, scerr.ErrInvalidParams, err.Error())
		return
	}

	resp, err := core.ServiceAPI.DeleteServices(r.Context(), request)
	respInternal := resp.Response
	resp.Response = nil
	controller.WriteResponse(w, respInternal, resp)
}
<|endoftext|>


<commit_before>package critter

type Slimupation uint64

const (
	SlimupationMage Slimupation = iota
	SlimupationBrute
	SlimupationSticky

	slimupationCount
)

var slimupationInfo = [slimupationCount]struct {
	title  string
	flavor string
}{
	SlimupationMage: {
		title:  "mage",
		flavor: "with magical properties.",
	},
	SlimupationBrute: {
		title:  "brute",
		flavor: "that can bench press a whole hero.",
	},
	SlimupationSticky: {
		title:  "citizen",
		flavor: "that's a little stickier than most.",
	},
}

func (s Slimupation) Name() string   { return slimupationInfo[s].title }
func (s Slimupation) Flavor() string { return slimupationInfo[s].flavor }
<commit_msg>data upgrade<commit_after>package critter

type Slimupation uint64

const (
	SlimupationMage Slimupation = iota
	SlimupationBrute
	SlimupationSticky

	slimupationCount
)

var slimupationInfo = [slimupationCount]struct {
	title  string
	flavor string
	color  string
	radius int
}{
	SlimupationMage: {
		title:  "mage",
		flavor: "with magical properties.",
<<<<<<< HEAD
	},
	SlimupationBrute: {
		title:  "brute",
		flavor: "that can bench press a whole hero.",
	},
	SlimupationSticky: {
		title:  "citizen",
		flavor: "that's a little stickier than most.",
	},
=======
		color:  "#00d",
		radius: 7},

	SlimupationBrute: {
		title:  "brute",
		flavor: "that can bench press a whole hero.",
		color:  "#d00",
		radius: 7},
	SlimupationSticky: {
		title:  "citizen",
		flavor: "that's a little stickier than most.",
		color:  "#0d0",
		radius: 14},
>>>>>>> data updated
}

func (s Slimupation) Name() string   { return slimupationInfo[s].title }
func (s Slimupation) Flavor() string { return slimupationInfo[s].flavor }
<|endoftext|>