<commit_before>/*
Copyright 2014 Google 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.
*/

// e2e.go runs the e2e test suite. No non-standard package dependencies; call with "go run".
package main

import (
	"bytes"
	"flag"
	"fmt"
	"log"
	"math/rand"
	"os"
	"os/exec"
	"os/signal"
	"path"
	"path/filepath"
	"sort"
	"strings"
	"time"
)

var (
	isup             = flag.Bool("isup", false, "Check to see if the e2e cluster is up, then exit.")
	build            = flag.Bool("build", false, "If true, build a new release. Otherwise, use whatever is there.")
	up               = flag.Bool("up", false, "If true, start the the e2e cluster. If cluster is already up, recreate it.")
	push             = flag.Bool("push", false, "If true, push to e2e cluster. Has no effect if -up is true.")
	pushup           = flag.Bool("pushup", false, "If true, push to e2e cluster if it's up, otherwise start the e2e cluster.")
	down             = flag.Bool("down", false, "If true, tear down the cluster before exiting.")
	orderseed        = flag.Int64("orderseed", 0, "If non-zero, seed of random test shuffle order. (Otherwise random.)")
	test             = flag.Bool("test", false, "Run all tests in hack/e2e-suite.")
	tests            = flag.String("tests", "", "Run only tests in hack/e2e-suite matching this glob. Ignored if -test is set.")
	root             = flag.String("root", absOrDie(filepath.Clean(filepath.Join(path.Base(os.Args[0]), ".."))), "Root directory of kubernetes repository.")
	verbose          = flag.Bool("v", false, "If true, print all command output.")
	trace_bash       = flag.Bool("trace-bash", false, "If true, pass -x to bash to trace all bash commands")
	checkVersionSkew = flag.Bool("check_version_skew", true, ""+
		"By default, verify that client and server have exact version match. "+
		"You can explicitly set to false if you're, e.g., testing client changes "+
		"for which the server version doesn't make a difference.")

	cfgCmd = flag.String("cfg", "", "If nonempty, pass this as an argument, and call kubecfg. Implies -v.")
	ctlCmd = flag.String("ctl", "", "If nonempty, pass this as an argument, and call kubectl. Implies -v. (-test, -cfg, -ctl are mutually exclusive)")
)

var signals = make(chan os.Signal, 100)

func absOrDie(path string) string {
	out, err := filepath.Abs(path)
	if err != nil {
		panic(err)
	}
	return out
}

func main() {
	flag.Parse()
	signal.Notify(signals, os.Interrupt)

	if *test {
		*tests = "*"
	}

	if *isup {
		status := 1
		if IsUp() {
			status = 0
			log.Printf("Cluster is UP")
		} else {
			log.Printf("Cluster is DOWN")
		}
		os.Exit(status)
	}

	if *build {
		if !runBash("build-release", `test-build-release`) {
			log.Fatal("Error building. Aborting.")
		}
	}

	if *pushup {
		if IsUp() {
			log.Printf("e2e cluster is up, pushing.")
			*up = false
			*push = true
		} else {
			log.Printf("e2e cluster is down, creating.")
			*up = true
			*push = false
		}
	}
	if *up {
		if !Up() {
			log.Fatal("Error starting e2e cluster. Aborting.")
		}
	} else if *push {
		if !runBash("push", path.Join(*root, "/cluster/kube-push.sh")) {
			log.Fatal("Error pushing e2e cluster. Aborting.")
		}
	}

	failure := false
	switch {
	case *cfgCmd != "":
		failure = !runBash("'kubecfg "+*cfgCmd+"'", "$KUBECFG "+*cfgCmd)
	case *ctlCmd != "":
		failure = !runBash("'kubectl "+*ctlCmd+"'", "$KUBECTL "+*ctlCmd)
	case *tests != "":
		failed, passed := Test()
		log.Printf("Passed tests: %v", passed)
		log.Printf("Failed tests: %v", failed)
		failure = len(failed) > 0
	}

	if *down {
		TearDown()
	}

	if failure {
		os.Exit(1)
	}
}

func TearDown() {
	runBash("teardown", "test-teardown")
}

func Up() bool {
	if !tryUp() {
		log.Printf("kube-up failed; will tear down and retry. (Possibly your cluster was in some partially created state?)")
		TearDown()
		return tryUp()
	}
	return true
}

// Is the e2e cluster up?
func IsUp() bool {
	return runBash("get status", `$KUBECFG -server_version`)
}

func tryUp() bool {
	return runBash("up", path.Join(*root, "/cluster/kube-up.sh; test-setup;"))
}

// Fisher-Yates shuffle using the given RNG r
func shuffleStrings(strings []string, r *rand.Rand) {
	for i := len(strings) - 1; i > 0; i-- {
		j := r.Intn(i + 1)
		strings[i], strings[j] = strings[j], strings[i]
	}
}

func Test() (failed, passed []string) {
	defer runBashUntil("watchEvents", "$KUBECTL --watch-only get events")()

	if !IsUp() {
		log.Fatal("Testing requested, but e2e cluster not up!")
	}

	// run tests!
	dir, err := os.Open(filepath.Join(*root, "hack", "e2e-suite"))
	if err != nil {
		log.Fatal("Couldn't open e2e-suite dir")
	}
	defer dir.Close()
	names, err := dir.Readdirnames(0)
	if err != nil {
		log.Fatal("Couldn't read names in e2e-suite dir")
	}

	toRun := make([]string, 0, len(names))
	for i := range names {
		name := names[i]
		if name == "." || name == ".." {
			continue
		}
		if match, err := path.Match(*tests, name); !match && err == nil {
			continue
		}
		if err != nil {
			log.Fatal("Bad test pattern: %v", tests)
		}
		toRun = append(toRun, name)
	}

	if *orderseed == 0 {
		// Use low order bits of NanoTime as the default seed. (Using
		// all the bits makes for a long, very similar looking seed
		// between runs.)
		*orderseed = time.Now().UnixNano() & (1<<32 - 1)
	}
	sort.Strings(toRun)
	shuffleStrings(toRun, rand.New(rand.NewSource(*orderseed)))
	log.Printf("Running tests matching %v shuffled with seed %#x: %v", *tests, *orderseed, toRun)
	for _, name := range toRun {
		absName := filepath.Join(*root, "hack", "e2e-suite", name)
		log.Printf("Starting test %v.", name)
		if runBash(name, absName) {
			log.Printf("%v passed", name)
			passed = append(passed, name)
		} else {
			log.Printf("%v failed", name)
			failed = append(failed, name)
		}
	}

	sort.Strings(passed)
	sort.Strings(failed)
	return
}

// All nonsense below is temporary until we have go versions of these things.

func runBash(stepName, bashFragment string) bool {
	cmd := exec.Command("bash", "-s")
	if *trace_bash {
		cmd.Args = append(cmd.Args, "-x")
	}
	cmd.Stdin = strings.NewReader(bashWrap(bashFragment))
	return finishRunning(stepName, cmd)
}

// call the returned anonymous function to stop.
func runBashUntil(stepName, bashFragment string) func() {
	cmd := exec.Command("bash", "-s")
	cmd.Stdin = strings.NewReader(bashWrap(bashFragment))
	log.Printf("Running in background: %v", stepName)
	stdout, stderr := bytes.NewBuffer(nil), bytes.NewBuffer(nil)
	cmd.Stdout, cmd.Stderr = stdout, stderr
	if err := cmd.Start(); err != nil {
		log.Printf("Unable to start '%v': '%v'", stepName, err)
		return func() {}
	}
	return func() {
		cmd.Process.Signal(os.Interrupt)
		fmt.Printf("%v stdout:\n------\n%v\n------\n", stepName, string(stdout.Bytes()))
		fmt.Printf("%v stderr:\n------\n%v\n------\n", stepName, string(stderr.Bytes()))
	}
}

func run(stepName, cmdPath string) bool {
	return finishRunning(stepName, exec.Command(filepath.Join(*root, cmdPath)))
}

func finishRunning(stepName string, cmd *exec.Cmd) bool {
	log.Printf("Running: %v", stepName)
	stdout, stderr := bytes.NewBuffer(nil), bytes.NewBuffer(nil)
	if *verbose {
		cmd.Stdout = os.Stdout
		cmd.Stderr = os.Stderr
	} else {
		cmd.Stdout = stdout
		cmd.Stderr = stderr
	}

	done := make(chan struct{})
	defer close(done)
	go func() {
		for {
			select {
			case <-done:
				return
			case s := <-signals:
				cmd.Process.Signal(s)
			}
		}
	}()

	if err := cmd.Run(); err != nil {
		log.Printf("Error running %v: %v", stepName, err)
		if !*verbose {
			fmt.Printf("stdout:\n------\n%v\n------\n", string(stdout.Bytes()))
			fmt.Printf("stderr:\n------\n%v\n------\n", string(stderr.Bytes()))
		}
		return false
	}
	return true
}

// returns either "", or a list of args intended for appending with the
// kubecfg or kubectl commands (begining with a space).
func kubecfgArgs() string {
	if *checkVersionSkew {
		return " -expect_version_match"
	}
	return ""
}

// returns either "", or a list of args intended for appending with the
// kubectl command (begining with a space).
func kubectlArgs() string {
	if *checkVersionSkew {
		return " --match-server-version"
	}
	return ""
}

func bashWrap(cmd string) string {
	return `
set -o errexit
set -o nounset
set -o pipefail

export KUBE_CONFIG_FILE="config-test.sh"

# TODO(jbeda): This will break on usage if there is a space in
# ${KUBE_ROOT}.  Covert to an array?  Or an exported function?
export KUBECFG="` + *root + `/cluster/kubecfg.sh` + kubecfgArgs() + `"
export KUBECTL="` + *root + `/cluster/kubectl.sh` + kubectlArgs() + `"

source "` + *root + `/cluster/kube-env.sh"
source "` + *root + `/cluster/${KUBERNETES_PROVIDER}/util.sh"

prepare-e2e

` + cmd + `
`
}
<commit_msg>Add --times to e2e.go<commit_after>/*
Copyright 2014 Google 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.
*/

// e2e.go runs the e2e test suite. No non-standard package dependencies; call with "go run".
package main

import (
	"bytes"
	"flag"
	"fmt"
	"log"
	"math/rand"
	"os"
	"os/exec"
	"os/signal"
	"path"
	"path/filepath"
	"sort"
	"strings"
	"time"
)

var (
	isup             = flag.Bool("isup", false, "Check to see if the e2e cluster is up, then exit.")
	build            = flag.Bool("build", false, "If true, build a new release. Otherwise, use whatever is there.")
	up               = flag.Bool("up", false, "If true, start the the e2e cluster. If cluster is already up, recreate it.")
	push             = flag.Bool("push", false, "If true, push to e2e cluster. Has no effect if -up is true.")
	pushup           = flag.Bool("pushup", false, "If true, push to e2e cluster if it's up, otherwise start the e2e cluster.")
	down             = flag.Bool("down", false, "If true, tear down the cluster before exiting.")
	orderseed        = flag.Int64("orderseed", 0, "If non-zero, seed of random test shuffle order. (Otherwise random.)")
	test             = flag.Bool("test", false, "Run all tests in hack/e2e-suite.")
	tests            = flag.String("tests", "", "Run only tests in hack/e2e-suite matching this glob. Ignored if -test is set.")
	times            = flag.Int("times", 1, "Number of times each test is eligible to be run. Individual order is determined by shuffling --times instances of each test using --orderseed (like a multi-deck shoe of cards).")
	root             = flag.String("root", absOrDie(filepath.Clean(filepath.Join(path.Base(os.Args[0]), ".."))), "Root directory of kubernetes repository.")
	verbose          = flag.Bool("v", false, "If true, print all command output.")
	trace_bash       = flag.Bool("trace-bash", false, "If true, pass -x to bash to trace all bash commands")
	checkVersionSkew = flag.Bool("check_version_skew", true, ""+
		"By default, verify that client and server have exact version match. "+
		"You can explicitly set to false if you're, e.g., testing client changes "+
		"for which the server version doesn't make a difference.")

	cfgCmd = flag.String("cfg", "", "If nonempty, pass this as an argument, and call kubecfg. Implies -v.")
	ctlCmd = flag.String("ctl", "", "If nonempty, pass this as an argument, and call kubectl. Implies -v. (-test, -cfg, -ctl are mutually exclusive)")
)

var signals = make(chan os.Signal, 100)

func absOrDie(path string) string {
	out, err := filepath.Abs(path)
	if err != nil {
		panic(err)
	}
	return out
}

type TestResult struct {
	Pass int
	Fail int
}

type ResultsByTest map[string]TestResult

func main() {
	flag.Parse()
	signal.Notify(signals, os.Interrupt)

	if *test {
		*tests = "*"
	}

	if *isup {
		status := 1
		if IsUp() {
			status = 0
			log.Printf("Cluster is UP")
		} else {
			log.Printf("Cluster is DOWN")
		}
		os.Exit(status)
	}

	if *build {
		if !runBash("build-release", `test-build-release`) {
			log.Fatal("Error building. Aborting.")
		}
	}

	if *pushup {
		if IsUp() {
			log.Printf("e2e cluster is up, pushing.")
			*up = false
			*push = true
		} else {
			log.Printf("e2e cluster is down, creating.")
			*up = true
			*push = false
		}
	}
	if *up {
		if !Up() {
			log.Fatal("Error starting e2e cluster. Aborting.")
		}
	} else if *push {
		if !runBash("push", path.Join(*root, "/cluster/kube-push.sh")) {
			log.Fatal("Error pushing e2e cluster. Aborting.")
		}
	}

	failure := false
	switch {
	case *cfgCmd != "":
		failure = !runBash("'kubecfg "+*cfgCmd+"'", "$KUBECFG "+*cfgCmd)
	case *ctlCmd != "":
		failure = !runBash("'kubectl "+*ctlCmd+"'", "$KUBECTL "+*ctlCmd)
	case *tests != "":
		failure = PrintResults(Test())
	}

	if *down {
		TearDown()
	}

	if failure {
		os.Exit(1)
	}
}

func TearDown() {
	runBash("teardown", "test-teardown")
}

func Up() bool {
	if !tryUp() {
		log.Printf("kube-up failed; will tear down and retry. (Possibly your cluster was in some partially created state?)")
		TearDown()
		return tryUp()
	}
	return true
}

// Is the e2e cluster up?
func IsUp() bool {
	return runBash("get status", `$KUBECFG -server_version`)
}

func tryUp() bool {
	return runBash("up", path.Join(*root, "/cluster/kube-up.sh; test-setup;"))
}

// Fisher-Yates shuffle using the given RNG r
func shuffleStrings(strings []string, r *rand.Rand) {
	for i := len(strings) - 1; i > 0; i-- {
		j := r.Intn(i + 1)
		strings[i], strings[j] = strings[j], strings[i]
	}
}

func Test() (results ResultsByTest) {
	defer runBashUntil("watchEvents", "$KUBECTL --watch-only get events")()

	if !IsUp() {
		log.Fatal("Testing requested, but e2e cluster not up!")
	}

	// run tests!
	dir, err := os.Open(filepath.Join(*root, "hack", "e2e-suite"))
	if err != nil {
		log.Fatal("Couldn't open e2e-suite dir")
	}
	defer dir.Close()
	names, err := dir.Readdirnames(0)
	if err != nil {
		log.Fatal("Couldn't read names in e2e-suite dir")
	}

	toRun := make([]string, 0, len(names))
	for i := range names {
		name := names[i]
		if name == "." || name == ".." {
			continue
		}
		if match, err := path.Match(*tests, name); !match && err == nil {
			continue
		}
		if err != nil {
			log.Fatal("Bad test pattern: %v", tests)
		}
		toRun = append(toRun, name)
	}

	if *orderseed == 0 {
		// Use low order bits of NanoTime as the default seed. (Using
		// all the bits makes for a long, very similar looking seed
		// between runs.)
		*orderseed = time.Now().UnixNano() & (1<<32 - 1)
	}
	sort.Strings(toRun)
	if *times != 1 {
		if *times <= 0 {
			log.Fatal("Invalid --times (negative or no testing requested)!")
		}
		newToRun := make([]string, 0, *times*len(toRun))
		for i := 0; i < *times; i++ {
			newToRun = append(newToRun, toRun...)
		}
		toRun = newToRun
	}
	shuffleStrings(toRun, rand.New(rand.NewSource(*orderseed)))
	log.Printf("Running tests matching %v shuffled with seed %#x: %v", *tests, *orderseed, toRun)
	results = ResultsByTest{}
	for i, name := range toRun {
		absName := filepath.Join(*root, "hack", "e2e-suite", name)
		log.Printf("Starting test [%v/%v]: %v", i+1, len(toRun), name)
		testResult := results[name]
		if runBash(name, absName) {
			log.Printf("%v passed", name)
			testResult.Pass++
		} else {
			log.Printf("%v failed", name)
			testResult.Fail++
		}
		results[name] = testResult
	}

	return
}

func PrintResults(results ResultsByTest) bool {
	failures := 0

	passed := []string{}
	flaky := []string{}
	failed := []string{}
	for test, result := range results {
		if result.Pass > 0 && result.Fail == 0 {
			passed = append(passed, test)
		} else if result.Pass > 0 && result.Fail > 0 {
			flaky = append(flaky, test)
			failures += result.Fail
		} else {
			failed = append(failed, test)
			failures += result.Fail
		}
	}
	sort.Strings(passed)
	sort.Strings(flaky)
	sort.Strings(failed)
	printSubreport("Passed", passed, results)
	printSubreport("Flaky", flaky, results)
	printSubreport("Failed", failed, results)
	if failures > 0 {
		log.Printf("%v test(s) failed.", failures)
	} else {
		log.Printf("Success!")
	}

	return failures > 0
}

func printSubreport(title string, tests []string, results ResultsByTest) {
	report := title + " tests:"

	for _, test := range tests {
		result := results[test]
		report += fmt.Sprintf(" %v[%v/%v]", test, result.Pass, result.Pass+result.Fail)
	}
	log.Printf(report)
}

// All nonsense below is temporary until we have go versions of these things.

func runBash(stepName, bashFragment string) bool {
	cmd := exec.Command("bash", "-s")
	if *trace_bash {
		cmd.Args = append(cmd.Args, "-x")
	}
	cmd.Stdin = strings.NewReader(bashWrap(bashFragment))
	return finishRunning(stepName, cmd)
}

// call the returned anonymous function to stop.
func runBashUntil(stepName, bashFragment string) func() {
	cmd := exec.Command("bash", "-s")
	cmd.Stdin = strings.NewReader(bashWrap(bashFragment))
	log.Printf("Running in background: %v", stepName)
	stdout, stderr := bytes.NewBuffer(nil), bytes.NewBuffer(nil)
	cmd.Stdout, cmd.Stderr = stdout, stderr
	if err := cmd.Start(); err != nil {
		log.Printf("Unable to start '%v': '%v'", stepName, err)
		return func() {}
	}
	return func() {
		cmd.Process.Signal(os.Interrupt)
		fmt.Printf("%v stdout:\n------\n%v\n------\n", stepName, string(stdout.Bytes()))
		fmt.Printf("%v stderr:\n------\n%v\n------\n", stepName, string(stderr.Bytes()))
	}
}

func run(stepName, cmdPath string) bool {
	return finishRunning(stepName, exec.Command(filepath.Join(*root, cmdPath)))
}

func finishRunning(stepName string, cmd *exec.Cmd) bool {
	log.Printf("Running: %v", stepName)
	stdout, stderr := bytes.NewBuffer(nil), bytes.NewBuffer(nil)
	if *verbose {
		cmd.Stdout = os.Stdout
		cmd.Stderr = os.Stderr
	} else {
		cmd.Stdout = stdout
		cmd.Stderr = stderr
	}

	done := make(chan struct{})
	defer close(done)
	go func() {
		for {
			select {
			case <-done:
				return
			case s := <-signals:
				cmd.Process.Signal(s)
			}
		}
	}()

	if err := cmd.Run(); err != nil {
		log.Printf("Error running %v: %v", stepName, err)
		if !*verbose {
			fmt.Printf("stdout:\n------\n%v\n------\n", string(stdout.Bytes()))
			fmt.Printf("stderr:\n------\n%v\n------\n", string(stderr.Bytes()))
		}
		return false
	}
	return true
}

// returns either "", or a list of args intended for appending with the
// kubecfg or kubectl commands (begining with a space).
func kubecfgArgs() string {
	if *checkVersionSkew {
		return " -expect_version_match"
	}
	return ""
}

// returns either "", or a list of args intended for appending with the
// kubectl command (begining with a space).
func kubectlArgs() string {
	if *checkVersionSkew {
		return " --match-server-version"
	}
	return ""
}

func bashWrap(cmd string) string {
	return `
set -o errexit
set -o nounset
set -o pipefail

export KUBE_CONFIG_FILE="config-test.sh"

# TODO(jbeda): This will break on usage if there is a space in
# ${KUBE_ROOT}.  Covert to an array?  Or an exported function?
export KUBECFG="` + *root + `/cluster/kubecfg.sh` + kubecfgArgs() + `"
export KUBECTL="` + *root + `/cluster/kubectl.sh` + kubectlArgs() + `"

source "` + *root + `/cluster/kube-env.sh"
source "` + *root + `/cluster/${KUBERNETES_PROVIDER}/util.sh"

prepare-e2e

` + cmd + `
`
}
<|endoftext|>


<commit_before>package kit

import (
	"crypto"
	"encoding/hex"
	"fmt"
	"net/http"
	"strconv"
	"strings"

	"github.com/inconshreveable/go-update"
)

var (
	ThemeKitVersion = version{Major: 0, Minor: 4, Patch: 4}
)

type versionComparisonResult int

const (
	// VersionLessThan is a versionComparisonResult for a version that is less than
	VersionLessThan versionComparisonResult = -1
	// VersionEqual is a versionComparisonResult for a version that is equal
	VersionEqual = 0
	// VersionEqual is a versionComparisonResult for a version that is greater than
	VersionGreaterThan = 1
)

// LibraryInfo will return a string array with information about the library used
// for logging.
func LibraryInfo() []string {
	return []string{
		"ThemeKit - Shopify Theme Utilities",
		ThemeKitVersion.String(),
	}
}

type version struct {
	Major int
	Minor int
	Patch int
}

func (v version) String() string {
	return fmt.Sprintf("v%d.%d.%d", v.Major, v.Minor, v.Patch)
}

func (v version) toArray() [3]int {
	return [3]int{v.Major, v.Minor, v.Patch}
}

// Compare ... I often get confused by comparison, so comparison results are going
// to be the same as what <=> would return in Ruby.
// http://ruby-doc.org/core-1.9.3/Comparable.html
func (v version) Compare(o version) versionComparisonResult {
	vAry := v.toArray()
	oAry := o.toArray()
	for i := 0; i < len(vAry); i++ {
		diff := vAry[i] - oAry[i]
		if diff < 0 {
			return VersionLessThan
		} else if diff > 0 {
			return VersionGreaterThan
		}
	}
	return VersionEqual
}

// ParseVersionString will parse a string and convert it into a version for comparison.
func ParseVersionString(ver string) version {
	sanitizedVer := strings.Replace(ver, "v", "", 1)
	expandedVersionString := strings.Split(sanitizedVer, ".")
	major, _ := strconv.Atoi(expandedVersionString[0])
	minor, _ := strconv.Atoi(expandedVersionString[1])
	patch, _ := strconv.Atoi(expandedVersionString[2])
	return version{Major: major, Minor: minor, Patch: patch}
}

// ApplyUpdate will take a url and digest and download the update specified, then
// apply it to the current version.
func ApplyUpdate(updateURL, digest string) error {
	checksum, err := hex.DecodeString(digest)
	if err != nil {
		return err
	}

	updateFile, err := http.Get(updateURL)
	if err != nil {
		return err
	}
	defer updateFile.Body.Close()

	err = update.Apply(updateFile.Body, update.Options{
		Hash:     crypto.MD5,
		Checksum: checksum,
	})
	if err != nil {
		if rerr := update.RollbackError(err); rerr != nil {
			fmt.Printf("Failed to rollback from bad update: %v", rerr)
		}
	}
	return err
}
<commit_msg>version update<commit_after>package kit

import (
	"crypto"
	"encoding/hex"
	"fmt"
	"net/http"
	"strconv"
	"strings"

	"github.com/inconshreveable/go-update"
)

var (
	ThemeKitVersion = version{Major: 0, Minor: 4, Patch: 6}
)

type versionComparisonResult int

const (
	// VersionLessThan is a versionComparisonResult for a version that is less than
	VersionLessThan versionComparisonResult = -1
	// VersionEqual is a versionComparisonResult for a version that is equal
	VersionEqual = 0
	// VersionEqual is a versionComparisonResult for a version that is greater than
	VersionGreaterThan = 1
)

// LibraryInfo will return a string array with information about the library used
// for logging.
func LibraryInfo() []string {
	return []string{
		"ThemeKit - Shopify Theme Utilities",
		ThemeKitVersion.String(),
	}
}

type version struct {
	Major int
	Minor int
	Patch int
}

func (v version) String() string {
	return fmt.Sprintf("v%d.%d.%d", v.Major, v.Minor, v.Patch)
}

func (v version) toArray() [3]int {
	return [3]int{v.Major, v.Minor, v.Patch}
}

// Compare ... I often get confused by comparison, so comparison results are going
// to be the same as what <=> would return in Ruby.
// http://ruby-doc.org/core-1.9.3/Comparable.html
func (v version) Compare(o version) versionComparisonResult {
	vAry := v.toArray()
	oAry := o.toArray()
	for i := 0; i < len(vAry); i++ {
		diff := vAry[i] - oAry[i]
		if diff < 0 {
			return VersionLessThan
		} else if diff > 0 {
			return VersionGreaterThan
		}
	}
	return VersionEqual
}

// ParseVersionString will parse a string and convert it into a version for comparison.
func ParseVersionString(ver string) version {
	sanitizedVer := strings.Replace(ver, "v", "", 1)
	expandedVersionString := strings.Split(sanitizedVer, ".")
	major, _ := strconv.Atoi(expandedVersionString[0])
	minor, _ := strconv.Atoi(expandedVersionString[1])
	patch, _ := strconv.Atoi(expandedVersionString[2])
	return version{Major: major, Minor: minor, Patch: patch}
}

// ApplyUpdate will take a url and digest and download the update specified, then
// apply it to the current version.
func ApplyUpdate(updateURL, digest string) error {
	checksum, err := hex.DecodeString(digest)
	if err != nil {
		return err
	}

	updateFile, err := http.Get(updateURL)
	if err != nil {
		return err
	}
	defer updateFile.Body.Close()

	err = update.Apply(updateFile.Body, update.Options{
		Hash:     crypto.MD5,
		Checksum: checksum,
	})
	if err != nil {
		if rerr := update.RollbackError(err); rerr != nil {
			fmt.Printf("Failed to rollback from bad update: %v", rerr)
		}
	}
	return err
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/sha1"
	"crypto/sha256"
	"database/sql"
	"encoding/base64"
	"encoding/xml"
	"fmt"
	log "github.com/Sirupsen/logrus"
	"github.com/coreos/go-omaha/omaha"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"path"
	"strconv"
)

const noupdateResponse = `
<?xml version="1.0" encoding="UTF-8"?>
<response protocol="3.0" server="update.core-os.net">
<daystart elapsed_seconds="0"></daystart>
<app appid="e96281a6-d1af-4bde-9a0a-97b76e56dc57" status="ok">
<updatecheck status="noupdate"></updatecheck>
</app>
</response>`

func homeHandler(w http.ResponseWriter, r *http.Request) {
	defer r.Body.Close()
	http.Error(w, "", 404)

	log.Infof("Someone tried to access '%s'", r.URL.String())
}

func fileHandler(w http.ResponseWriter, r *http.Request) {
	defer r.Body.Close()

	log.Infof("Someone tried to access '%s'", r.URL.String())

	fileid := r.URL.Query().Get("id")
	log.Infof("Handling request for %v", fileid)
	http.ServeFile(w, r, path.Join("storage", fileid))
}

func addPayloadHandler(w http.ResponseWriter, r *http.Request) {
	receivedSha1 := r.URL.Query().Get("sha1")
	if receivedSha1 == "" {
		http.Error(w, "Missing parameter 'sha1'", 400)
		return
	}
	receivedSha256 := r.URL.Query().Get("sha256")
	if receivedSha256 == "" {
		http.Error(w, "Missing parameter 'sha256'", 400)
		return
	}
	size := r.ContentLength
	versionString := r.URL.Query().Get("version")
	if versionString == "" {
		http.Error(w, "Missing parameter 'version'", 400)
		return
	}
	data := make([]byte, size)
	rcvsize, err := io.ReadFull(r.Body, data)
	if err != nil {
		http.Error(w, err.Error(), 500)
		return
	}

	versionData, err := parseVersionString(versionString)
	if err != nil {
		s := fmt.Sprintf("Could not parse 'version': %v", err.Error())
		http.Error(w, s, 400)
		return
	}

	log.Debugf("addPayloadHandler: received size is %v", rcvsize)

	rawSha1 := sha1.Sum(data)
	calculatedSha1 := base64.StdEncoding.EncodeToString(rawSha1[:])
	rawSha256 := sha256.Sum256(data)
	calculatedSha256 := base64.StdEncoding.EncodeToString(rawSha256[:])

	if receivedSha1 != calculatedSha1 {
		s := fmt.Sprintf("SHA1 validation failed, '%v' != '%v'", receivedSha1, calculatedSha1)
		http.Error(w, s, 400)
		return
	}

	if receivedSha256 != calculatedSha256 {
		s := fmt.Sprintf("SHA256 validation failed, '%v' != '%v'", receivedSha256, calculatedSha256)
		http.Error(w, s, 400)
		return
	}

	id, err := fileBE.Store(data)
	if err != nil {
		log.Errorf("addPayloadHandler: storing data: %v", err.Error())
	}
	err = db.AddPayload(id, calculatedSha1, calculatedSha256, size, versionData)
	if err != nil {
		log.Errorf("addPayloadHandler: adding payload to db: %v", err.Error())
	}
}

func shutdownHandler(w http.ResponseWriter, r *http.Request) {
	os.Exit(0)
}

func updateHandler(w http.ResponseWriter, r *http.Request) {
	defer r.Body.Close()

	log.Infof("Handling an update request from %v", r.RemoteAddr)

	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		http.Error(w, err.Error(), 500)
		log.Error(err.Error())
	}

	var reqStructure omaha.Request
	log.Debugf("%v", string(body[:len(body)]))
	err = xml.Unmarshal(body, &reqStructure)

	if n := len(reqStructure.Apps); n != 1 {
		log.Errorf("Client '%v' tried to update %v services", r.RemoteAddr, n)
		http.Error(w, "I can handle only 1 app update.", 400)
		return
	}

	log.Debugf("%#v", reqStructure)
	applicationUpdate(w, r, reqStructure.Apps[0])

}

func applicationUpdate(w http.ResponseWriter, r *http.Request, app *omaha.App) {
	if app.Id != coreOSAppID {
		s := fmt.Sprintf("Unknown app ID '%v'.", app.Id)
		log.Errorf("Client '%v' tried to update service '%v'.", r.RemoteAddr, app.Id)
		http.Error(w, s, 400)
		return
	}

	v, err := parseVersionString(app.Version)
	if err != nil {
		log.Errorf("Could not parse client's version string: %v", err.Error())
	}
	payload, err := db.GetNewerPayload(v)
	if err != nil {
		if err == sql.ErrNoRows {
			// TODO already at the newest version
		} else {
			log.Errorf("Failed checking for newer payload: %v", err.Error())
		}
	} else {
		// TODO. version to string
		// TODO client ID instead of IP
		log.Infof("Found update to version '%v' (id %v) for client '%v'", "1.2.3.4.5.6", payload.Url, r.RemoteAddr)
	}

	size := payload.Size
	sha1 := payload.SHA1
	sha256 := payload.SHA256
	id := payload.Url

	resp := omaha.NewResponse("coreos-update.protonet.info")
	newApp := resp.AddApp(coreOSAppID)
	newApp.Status = "ok"
	updateCheck := newApp.AddUpdateCheck()
	updateCheck.Status = "ok"
	updateCheck.AddUrl("http://10.0.2.2:8080/file?id=")
	//updateCheck.AddUrl("http://coreos-update.protorz.net:8080/coreos:latest/")
	manifest := updateCheck.AddManifest("1.0.2")
	manifest.AddPackage(sha1, id, strconv.FormatInt(size, 10), true)
	action := manifest.AddAction("postinstall")
	action.Sha256 = sha256
	action.DisablePayloadBackoff = true
	//action.MetadataSignatureRsa = "ixi6Oebo"
	//action.MetadataSize = "190"

	//data, err := xml.Marshal(resp)
	data, err := xml.MarshalIndent(resp, "", "  ")
	if err != nil {
		log.Error(err.Error())
		http.Error(w, "An internal error occured while marshalling a response", 500)
	}

	w.Header().Set("Content-Type", "application/xml")
	w.Write(data)
}
<commit_msg>exit on currently unhandled situations<commit_after>package main

import (
	"crypto/sha1"
	"crypto/sha256"
	"database/sql"
	"encoding/base64"
	"encoding/xml"
	"fmt"
	log "github.com/Sirupsen/logrus"
	"github.com/coreos/go-omaha/omaha"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"path"
	"strconv"
)

const noupdateResponse = `
<?xml version="1.0" encoding="UTF-8"?>
<response protocol="3.0" server="update.core-os.net">
<daystart elapsed_seconds="0"></daystart>
<app appid="e96281a6-d1af-4bde-9a0a-97b76e56dc57" status="ok">
<updatecheck status="noupdate"></updatecheck>
</app>
</response>`

func homeHandler(w http.ResponseWriter, r *http.Request) {
	defer r.Body.Close()
	http.Error(w, "", 404)

	log.Infof("Someone tried to access '%s'", r.URL.String())
}

func fileHandler(w http.ResponseWriter, r *http.Request) {
	defer r.Body.Close()

	log.Infof("Someone tried to access '%s'", r.URL.String())

	fileid := r.URL.Query().Get("id")
	log.Infof("Handling request for %v", fileid)
	http.ServeFile(w, r, path.Join("storage", fileid))
}

func addPayloadHandler(w http.ResponseWriter, r *http.Request) {
	receivedSha1 := r.URL.Query().Get("sha1")
	if receivedSha1 == "" {
		http.Error(w, "Missing parameter 'sha1'", 400)
		return
	}
	receivedSha256 := r.URL.Query().Get("sha256")
	if receivedSha256 == "" {
		http.Error(w, "Missing parameter 'sha256'", 400)
		return
	}
	size := r.ContentLength
	versionString := r.URL.Query().Get("version")
	if versionString == "" {
		http.Error(w, "Missing parameter 'version'", 400)
		return
	}
	data := make([]byte, size)
	rcvsize, err := io.ReadFull(r.Body, data)
	if err != nil {
		http.Error(w, err.Error(), 500)
		return
	}

	versionData, err := parseVersionString(versionString)
	if err != nil {
		s := fmt.Sprintf("Could not parse 'version': %v", err.Error())
		http.Error(w, s, 400)
		return
	}

	log.Debugf("addPayloadHandler: received size is %v", rcvsize)

	rawSha1 := sha1.Sum(data)
	calculatedSha1 := base64.StdEncoding.EncodeToString(rawSha1[:])
	rawSha256 := sha256.Sum256(data)
	calculatedSha256 := base64.StdEncoding.EncodeToString(rawSha256[:])

	if receivedSha1 != calculatedSha1 {
		s := fmt.Sprintf("SHA1 validation failed, '%v' != '%v'", receivedSha1, calculatedSha1)
		http.Error(w, s, 400)
		return
	}

	if receivedSha256 != calculatedSha256 {
		s := fmt.Sprintf("SHA256 validation failed, '%v' != '%v'", receivedSha256, calculatedSha256)
		http.Error(w, s, 400)
		return
	}

	id, err := fileBE.Store(data)
	if err != nil {
		log.Errorf("addPayloadHandler: storing data: %v", err.Error())
	}
	err = db.AddPayload(id, calculatedSha1, calculatedSha256, size, versionData)
	if err != nil {
		log.Errorf("addPayloadHandler: adding payload to db: %v", err.Error())
	}
}

func shutdownHandler(w http.ResponseWriter, r *http.Request) {
	os.Exit(0)
}

func updateHandler(w http.ResponseWriter, r *http.Request) {
	defer r.Body.Close()

	log.Infof("Handling an update request from %v", r.RemoteAddr)

	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		http.Error(w, err.Error(), 500)
		log.Error(err.Error())
	}

	var reqStructure omaha.Request
	log.Debugf("%v", string(body[:len(body)]))
	err = xml.Unmarshal(body, &reqStructure)

	if n := len(reqStructure.Apps); n != 1 {
		log.Errorf("Client '%v' tried to update %v services", r.RemoteAddr, n)
		http.Error(w, "I can handle only 1 app update.", 400)
		return
	}

	log.Debugf("%#v", reqStructure)
	applicationUpdate(w, r, reqStructure.Apps[0])
}

func applicationUpdate(w http.ResponseWriter, r *http.Request, app *omaha.App) {
	if app.Id != coreOSAppID {
		s := fmt.Sprintf("Unknown app ID '%v'.", app.Id)
		log.Errorf("Client '%v' tried to update service '%v'.", r.RemoteAddr, app.Id)
		http.Error(w, s, 400)
		return
	}

	v, err := parseVersionString(app.Version)
	if err != nil {
		log.Errorf("Could not parse client's version string: %v", err.Error())
	}
	payload, err := db.GetNewerPayload(v)
	if err != nil {
		if err == sql.ErrNoRows {
			// TODO already at the newest version response
			log.Infof("Client '%v' already up-to-date", r.RemoteAddr)
			return
		} else {
			log.Errorf("Failed checking for newer payload: %v", err.Error())
			return
		}
	} else {
		// TODO. version to string
		// TODO client ID instead of IP
		log.Infof("Found update to version '%v' (id %v) for client '%v'", "1.2.3.4.5.6", payload.Url, r.RemoteAddr)
	}

	size := payload.Size
	sha1 := payload.SHA1
	sha256 := payload.SHA256
	id := payload.Url

	resp := omaha.NewResponse("coreos-update.protonet.info")
	newApp := resp.AddApp(coreOSAppID)
	newApp.Status = "ok"
	updateCheck := newApp.AddUpdateCheck()
	updateCheck.Status = "ok"
	updateCheck.AddUrl("http://10.0.2.2:8080/file?id=")
	//updateCheck.AddUrl("http://coreos-update.protorz.net:8080/coreos:latest/")
	manifest := updateCheck.AddManifest("1.0.2")
	manifest.AddPackage(sha1, id, strconv.FormatInt(size, 10), true)
	action := manifest.AddAction("postinstall")
	action.Sha256 = sha256
	action.DisablePayloadBackoff = true
	//action.MetadataSignatureRsa = "ixi6Oebo"
	//action.MetadataSize = "190"

	//data, err := xml.Marshal(resp)
	data, err := xml.MarshalIndent(resp, "", "  ")
	if err != nil {
		log.Error(err.Error())
		http.Error(w, "An internal error occured while marshalling a response", 500)
	}

	w.Header().Set("Content-Type", "application/xml")
	w.Write(data)
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"net/url"

	"github.com/levigross/grequests"
)

// 机器人回复的数据的json绑定对象
type aiReply struct {
	code int
	Text string `json:"text"`
}

func tlAI(info string) string {
	tlURL := config.Ai.ApiUrl
	ro := &grequests.RequestOptions{
		Params: map[string]string{
			"key":  config.Ai.ApiKey,
			"info": info,
		},
	}

	r, err := grequests.Get(tlURL, ro)
	if err != nil {
		log.Println(err)
		return ""
	}

	defer r.Close()
	reply := new(aiReply)
	json.Unmarshal([]byte(r.String()), reply)
	return reply.Text
}

// 对机器人API发送请求
func ask(info string) string {
	URL := fmt.Sprintf(config.Ai.ApiUrl+"?key=%s&info=%s",
		config.Ai.ApiKey, url.QueryEscape(info))
	resp, err := http.Get(URL)
	if err != nil {
		log.Println(err)
		return config.Ai.Greeting
	}
	defer resp.Body.Close()
	reply := new(aiReply)
	decoder := json.NewDecoder(resp.Body)
	decoder.Decode(reply)
	return reply.Text
}
<commit_msg>删除了多余的API请求方法<commit_after>package main

import (
	"encoding/json"
	"log"

	"github.com/levigross/grequests"
)

// 机器人回复的数据的json绑定对象
type aiReply struct {
	code int
	Text string `json:"text"`
}

// 对机器人API发送请求
func tlAI(info string) string {
	tlURL := config.Ai.ApiUrl
	ro := &grequests.RequestOptions{
		Params: map[string]string{
			"key":  config.Ai.ApiKey,
			"info": info,
		},
	}

	r, err := grequests.Get(tlURL, ro)
	if err != nil {
		log.Println(err)
		return ""
	}

	defer r.Close()
	reply := new(aiReply)
	json.Unmarshal([]byte(r.String()), reply)
	return reply.Text
}
<|endoftext|>


<commit_before>package api

import (
	"github.com/go-martini/martini"
	"github.com/martini-contrib/render"
	"github.com/mdlayher/goset"
)

// APIVersion is the current version of the API
const APIVersion = "v0"

// APIDocumentation provides a link to the current API documentation
const APIDocumentation = "https://github.com/mdlayher/wavepipe/blob/master/API.md"

// apiVersionSet is the set of all currently supported API versions
var apiVersionSet = set.New(APIVersion)

// Error represents an error produced by the API
type Error struct {
	Code    int    `json:"code"`
	Message string `json:"message"`
}

// ErrorResponse represents the JSON response for endpoints which only return an error
type ErrorResponse struct {
	Error  *Error        `json:"error"`
	render render.Render `json:"-"`
}

// RenderError renders a JSON error message with the specified HTTP status code and message
func (e *ErrorResponse) RenderError(code int, message string) {
	// Render with specified HTTP status code
	e.render.JSON(code, &Error{
		Code:    code,
		Message: message,
	})
}

// ServerError is a shortcut to render a HTTP 500 with generic "server error" message
func (e *ErrorResponse) ServerError() {
	e.RenderError(500, "server error")
	return
}

// Information represents information about the API
type Information struct {
	Error         *Error   `json:"error"`
	Version       string   `json:"version"`
	Supported     []string `json:"supported"`
	Documentation string   `json:"documentation"`
}

// APIInfo returns information about the API
func APIInfo(r render.Render, params martini.Params) {
	// Output struct for errors
	errRes := ErrorResponse{render: r}

	// Enumerate available API versions
	versions := make([]string, 0)
	for _, v := range apiVersionSet.Enumerate() {
		versions = append(versions, v.(string))
	}

	// Output response
	res := Information{
		Error:         nil,
		Version:       APIVersion,
		Supported:     versions,
		Documentation: APIDocumentation,
	}

	// Check if a "version" was set
	if version, ok := params["version"]; ok {
		// Check if API version is supported
		if !apiVersionSet.Has(version) {
			errRes.RenderError(400, "unsupported API version: "+version)
			return
		}
	}

	// HTTP 200 OK
	r.JSON(200, res)
}
<commit_msg>Fix error object rendering<commit_after>package api

import (
	"github.com/go-martini/martini"
	"github.com/martini-contrib/render"
	"github.com/mdlayher/goset"
)

// APIVersion is the current version of the API
const APIVersion = "v0"

// APIDocumentation provides a link to the current API documentation
const APIDocumentation = "https://github.com/mdlayher/wavepipe/blob/master/API.md"

// apiVersionSet is the set of all currently supported API versions
var apiVersionSet = set.New(APIVersion)

// Error represents an error produced by the API
type Error struct {
	Code    int    `json:"code"`
	Message string `json:"message"`
}

// ErrorResponse represents the JSON response for endpoints which only return an error
type ErrorResponse struct {
	Error  *Error        `json:"error"`
	render render.Render `json:"-"`
}

// RenderError renders a JSON error message with the specified HTTP status code and message
func (e *ErrorResponse) RenderError(code int, message string) {
	// Render with specified HTTP status code
	e.render.JSON(code, ErrorResponse{
		Error: &Error{
			Code:    code,
			Message: message,
		},
	})
}

// ServerError is a shortcut to render a HTTP 500 with generic "server error" message
func (e *ErrorResponse) ServerError() {
	e.RenderError(500, "server error")
	return
}

// Information represents information about the API
type Information struct {
	Error         *Error   `json:"error"`
	Version       string   `json:"version"`
	Supported     []string `json:"supported"`
	Documentation string   `json:"documentation"`
}

// APIInfo returns information about the API
func APIInfo(r render.Render, params martini.Params) {
	// Output struct for errors
	errRes := ErrorResponse{render: r}

	// Enumerate available API versions
	versions := make([]string, 0)
	for _, v := range apiVersionSet.Enumerate() {
		versions = append(versions, v.(string))
	}

	// Output response
	res := Information{
		Error:         nil,
		Version:       APIVersion,
		Supported:     versions,
		Documentation: APIDocumentation,
	}

	// Check if a "version" was set
	if version, ok := params["version"]; ok {
		// Check if API version is supported
		if !apiVersionSet.Has(version) {
			errRes.RenderError(400, "unsupported API version: "+version)
			return
		}
	}

	// HTTP 200 OK
	r.JSON(200, res)
}
<|endoftext|>


<commit_before>// Jamie: This contains the go source code that will become shield.

package api

import (
	"fmt"
	"github.com/starkandwayne/shield/db"
	"net/http"
	"os"
)

func Run(bind string, template *db.DB, c chan int) {
	db := template.Copy()
	if err := db.Connect(); err != nil {
		fmt.Fprintf(os.Stderr, "failed to connect to %s database at %s: %s\n",
			db.Driver, db.DSN, err)
		return
	}

	http.Handle("/v1/ping", &PingAPI{})

	http.Handle("/v1/jobs", &JobAPI{Data: db, SuperChan: c})
	http.Handle("/v1/job", &JobAPI{Data: db})

	http.Handle("/v1/retention", &RetentionAPI{Data: db, SuperChan: c})

	http.Handle("/v1/archives", &ArchiveAPI{Data: db})
	http.Handle("/v1/archive", &ArchiveAPI{Data: db, SuperChan: c})

	http.Handle("/v1/schedules", &ScheduleAPI{Data: db})
	http.Handle("/v1/schedule", &ScheduleAPI{Data: db, SuperChan: c})

	http.Handle("/v1/stores", &StoreAPI{Data: db})
	http.Handle("/v1/store", &StoreAPI{Data: db, SuperChan: c})

	http.Handle("/v1/targets", &TargetAPI{Data: db})
	http.Handle("/v1/target", &TargetAPI{Data: db, SuperChan: c})

	http.ListenAndServe(bind, nil)
}
<commit_msg>DRY up API wiring<commit_after>// Jamie: This contains the go source code that will become shield.

package api

import (
	"fmt"
	"github.com/starkandwayne/shield/db"
	"net/http"
	"os"
)

func Run(bind string, template *db.DB, c chan int) {
	db := template.Copy()
	if err := db.Connect(); err != nil {
		fmt.Fprintf(os.Stderr, "failed to connect to %s database at %s: %s\n",
			db.Driver, db.DSN, err)
		return
	}

	ping := &PingAPI{}
	http.Handle("/v1/ping", ping)

	jobs := &JobAPI{Data: db, SuperChan: c}
	http.Handle("/v1/jobs", jobs)
	http.Handle("/v1/job", jobs)

	retention := &RetentionAPI{Data: db, SuperChan: c}
	http.Handle("/v1/retention", retention)

	archives := &ArchiveAPI{Data: db, SuperChan: c}
	http.Handle("/v1/archives", archives)
	http.Handle("/v1/archive", archives)

	schedules := &ScheduleAPI{Data: db, SuperChan: c}
	http.Handle("/v1/schedules", schedules)
	http.Handle("/v1/schedule", schedules)

	stores := &StoreAPI{Data: db, SuperChan: c}
	http.Handle("/v1/stores", stores)
	http.Handle("/v1/store", stores)

	targets := &TargetAPI{Data: db, SuperChan: c}
	http.Handle("/v1/targets", targets)
	http.Handle("/v1/target", targets)

	http.ListenAndServe(bind, nil)
}
<|endoftext|>


<commit_before>package ecs

import (
	"encoding/json"
	"strconv"
	"time"

	"github.com/denverdino/aliyungo/common"
	"github.com/denverdino/aliyungo/util"
)

// InstanceStatus represents instance status
type InstanceStatus string

// Constants of InstanceStatus
const (
	Creating = InstanceStatus("Creating")
	Running  = InstanceStatus("Running")
	Starting = InstanceStatus("Starting")

	Stopped  = InstanceStatus("Stopped")
	Stopping = InstanceStatus("Stopping")
)

type LockReason string

const (
	LockReasonFinancial = LockReason("financial")
	LockReasonSecurity  = LockReason("security")
)

type DescribeInstanceStatusArgs struct {
	RegionId common.Region
	ZoneId   string
	common.Pagination
}

//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/datatype&instancestatusitemtype
type InstanceStatusItemType struct {
	InstanceId string
	Status     InstanceStatus
}

type DescribeInstanceStatusResponse struct {
	common.Response
	common.PaginationResult
	InstanceStatuses struct {
		InstanceStatus []InstanceStatusItemType
	}
}

// DescribeInstanceStatus describes instance status
//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/instance&describeinstancestatus
func (client *Client) DescribeInstanceStatus(args *DescribeInstanceStatusArgs) (instanceStatuses []InstanceStatusItemType, pagination *common.PaginationResult, err error) {
	args.Validate()
	response := DescribeInstanceStatusResponse{}

	err = client.Invoke("DescribeInstanceStatus", args, &response)

	if err == nil {
		return response.InstanceStatuses.InstanceStatus, &response.PaginationResult, nil
	}

	return nil, nil, err
}

type StopInstanceArgs struct {
	InstanceId string
	ForceStop  bool
}

type StopInstanceResponse struct {
	common.Response
}

// StopInstance stops instance
//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/instance&stopinstance
func (client *Client) StopInstance(instanceId string, forceStop bool) error {
	args := StopInstanceArgs{
		InstanceId: instanceId,
		ForceStop:  forceStop,
	}
	response := StopInstanceResponse{}
	err := client.Invoke("StopInstance", &args, &response)
	return err
}

type StartInstanceArgs struct {
	InstanceId string
}

type StartInstanceResponse struct {
	common.Response
}

// StartInstance starts instance
//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/instance&startinstance
func (client *Client) StartInstance(instanceId string) error {
	args := StartInstanceArgs{InstanceId: instanceId}
	response := StartInstanceResponse{}
	err := client.Invoke("StartInstance", &args, &response)
	return err
}

type RebootInstanceArgs struct {
	InstanceId string
	ForceStop  bool
}

type RebootInstanceResponse struct {
	common.Response
}

// RebootInstance reboot instance
//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/instance&rebootinstance
func (client *Client) RebootInstance(instanceId string, forceStop bool) error {
	request := RebootInstanceArgs{
		InstanceId: instanceId,
		ForceStop:  forceStop,
	}
	response := RebootInstanceResponse{}
	err := client.Invoke("RebootInstance", &request, &response)
	return err
}

type DescribeInstanceAttributeArgs struct {
	InstanceId string
}

//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/datatype&operationlockstype
type OperationLocksType struct {
	LockReason []LockReason //enum for financial, security
}

//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/datatype&securitygroupidsettype
type SecurityGroupIdSetType struct {
	SecurityGroupId string
}

//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/datatype&ipaddresssettype
type IpAddressSetType struct {
	IpAddress []string
}

//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/datatype&vpcattributestype
type VpcAttributesType struct {
	VpcId            string
	VSwitchId        string
	PrivateIpAddress IpAddressSetType
	NatIpAddress     string
}

//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/datatype&eipaddressassociatetype
type EipAddressAssociateType struct {
	AllocationId       string
	IpAddress          string
	Bandwidth          int
	InternetChargeType common.InternetChargeType
}

//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/datatype&instanceattributestype
type InstanceAttributesType struct {
	InstanceId       string
	InstanceName     string
	Description      string
	ImageId          string
	RegionId         common.Region
	ZoneId           string
	ClusterId        string
	InstanceType     string
	HostName         string
	Status           InstanceStatus
	OperationLocks   OperationLocksType
	SecurityGroupIds struct {
		SecurityGroupId []string
	}
	PublicIpAddress         IpAddressSetType
	InnerIpAddress          IpAddressSetType
	InstanceNetworkType     string //enum Classic | Vpc
	InternetMaxBandwidthIn  int
	InternetMaxBandwidthOut int
	InternetChargeType      common.InternetChargeType
	CreationTime            util.ISO6801Time //time.Time
	VpcAttributes           VpcAttributesType
	EipAddress              EipAddressAssociateType
	IoOptimized             StringOrBool
}

type DescribeInstanceAttributeResponse struct {
	common.Response
	InstanceAttributesType
}

// DescribeInstanceAttribute describes instance attribute
//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/instance&describeinstanceattribute
func (client *Client) DescribeInstanceAttribute(instanceId string) (instance *InstanceAttributesType, err error) {
	args := DescribeInstanceAttributeArgs{InstanceId: instanceId}

	response := DescribeInstanceAttributeResponse{}
	err = client.Invoke("DescribeInstanceAttribute", &args, &response)
	if err != nil {
		return nil, err
	}
	return &response.InstanceAttributesType, err
}

type ModifyInstanceAttributeArgs struct {
	InstanceId   string
	InstanceName string
	Description  string
	Password     string
	HostName     string
}

type ModifyInstanceAttributeResponse struct {
	common.Response
}

//ModifyInstanceAttribute  modify instance attrbute
//
// You can read doc at https://help.aliyun.com/document_detail/ecs/open-api/instance/modifyinstanceattribute.html
func (client *Client) ModifyInstanceAttribute(args *ModifyInstanceAttributeArgs) error {
	response := ModifyInstanceAttributeResponse{}
	err := client.Invoke("ModifyInstanceAttribute", args, &response)
	return err
}

// Default timeout value for WaitForInstance method
const InstanceDefaultTimeout = 120

// WaitForInstance waits for instance to given status
func (client *Client) WaitForInstance(instanceId string, status InstanceStatus, timeout int) error {
	if timeout <= 0 {
		timeout = InstanceDefaultTimeout
	}
	for {
		instance, err := client.DescribeInstanceAttribute(instanceId)
		if err != nil {
			return err
		}
		if instance.Status == status {
			//TODO
			//Sleep one more time for timing issues
			time.Sleep(DefaultWaitForInterval * time.Second)
			break
		}
		timeout = timeout - DefaultWaitForInterval
		if timeout <= 0 {
			return common.GetClientErrorFromString("Timeout")
		}
		time.Sleep(DefaultWaitForInterval * time.Second)

	}
	return nil
}

type DescribeInstanceVncUrlArgs struct {
	RegionId   common.Region
	InstanceId string
}

type DescribeInstanceVncUrlResponse struct {
	common.Response
	VncUrl string
}

//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/instance&describeinstancevncurl
func (client *Client) DescribeInstanceVncUrl(args *DescribeInstanceVncUrlArgs) (string, error) {
	response := DescribeInstanceVncUrlResponse{}

	err := client.Invoke("DescribeInstanceVncUrl", args, &response)

	if err == nil {
		return response.VncUrl, nil
	}

	return "", err
}

type DescribeInstancesArgs struct {
	RegionId            common.Region
	VpcId               string
	VSwitchId           string
	ZoneId              string
	InstanceIds         string
	InstanceNetworkType string
	PrivateIpAddresses  string
	InnerIpAddresses    string
	PublicIpAddresses   string
	SecurityGroupId     string
	common.Pagination
}

type DescribeInstancesResponse struct {
	common.Response
	common.PaginationResult
	Instances struct {
		Instance []InstanceAttributesType
	}
}

// DescribeInstances describes instances
//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/instance&describeinstances
func (client *Client) DescribeInstances(args *DescribeInstancesArgs) (instances []InstanceAttributesType, pagination *common.PaginationResult, err error) {
	args.Validate()
	response := DescribeInstancesResponse{}

	err = client.Invoke("DescribeInstances", args, &response)

	if err == nil {
		return response.Instances.Instance, &response.PaginationResult, nil
	}

	return nil, nil, err
}

type DeleteInstanceArgs struct {
	InstanceId string
}

type DeleteInstanceResponse struct {
	common.Response
}

// DeleteInstance deletes instance
//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/instance&deleteinstance
func (client *Client) DeleteInstance(instanceId string) error {
	args := DeleteInstanceArgs{InstanceId: instanceId}
	response := DeleteInstanceResponse{}
	err := client.Invoke("DeleteInstance", &args, &response)
	return err
}

type DataDiskType struct {
	Size               int
	Category           DiskCategory //Enum cloud, ephemeral, ephemeral_ssd
	SnapshotId         string
	DiskName           string
	Description        string
	Device             string
	DeleteWithInstance bool
}

type SystemDiskType struct {
	Category    DiskCategory //Enum cloud, ephemeral, ephemeral_ssd
	DiskName    string
	Description string
}

type IoOptimized string

type StringOrBool struct {
	Value bool
}

// UnmarshalJSON implements the json.Unmarshaller interface.
func (io *StringOrBool) UnmarshalJSON(value []byte) error {
	if value[0] == '"' {
		var str string
		err := json.Unmarshal(value, &str)
		if err == nil {
			io.Value = (str == "true" || str == "optimized")
		}
		return err
	}
	var boolVal bool
	err := json.Unmarshal(value, &boolVal)
	if err == nil {
		io.Value = boolVal
	}
	return err
}

func (io StringOrBool) Bool() bool {
	return io.Value
}

func (io StringOrBool) String() string {
	return strconv.FormatBool(io.Value)
}

var (
	IoOptimizedNone      = IoOptimized("none")
	IoOptimizedOptimized = IoOptimized("optimized")
)

type CreateInstanceArgs struct {
	RegionId                common.Region
	ZoneId                  string
	ImageId                 string
	InstanceType            string
	SecurityGroupId         string
	InstanceName            string
	Description             string
	InternetChargeType      common.InternetChargeType
	InternetMaxBandwidthIn  int
	InternetMaxBandwidthOut int
	HostName                string
	Password                string
	IoOptimized             IoOptimized
	SystemDisk              SystemDiskType
	DataDisk                []DataDiskType
	VSwitchId               string
	PrivateIpAddress        string
	ClientToken             string
}

type CreateInstanceResponse struct {
	common.Response
	InstanceId string
}

// CreateInstance creates instance
//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/instance&createinstance
func (client *Client) CreateInstance(args *CreateInstanceArgs) (instanceId string, err error) {
	response := CreateInstanceResponse{}
	err = client.Invoke("CreateInstance", args, &response)
	if err != nil {
		return "", err
	}
	return response.InstanceId, err
}

type SecurityGroupArgs struct {
	InstanceId      string
	SecurityGroupId string
}

type SecurityGroupResponse struct {
	common.Response
}

//JoinSecurityGroup
//
//You can read doc at https://help.aliyun.com/document_detail/ecs/open-api/instance/joinsecuritygroup.html
func (client *Client) JoinSecurityGroup(instanceId string, securityGroupId string) error {
	args := SecurityGroupArgs{InstanceId: instanceId, SecurityGroupId: securityGroupId}
	response := SecurityGroupResponse{}
	err := client.Invoke("JoinSecurityGroup", &args, &response)
	return err
}

//LeaveSecurityGroup
//
//You can read doc at https://help.aliyun.com/document_detail/ecs/open-api/instance/leavesecuritygroup.html
func (client *Client) LeaveSecurityGroup(instanceId string, securityGroupId string) error {
	args := SecurityGroupArgs{InstanceId: instanceId, SecurityGroupId: securityGroupId}
	response := SecurityGroupResponse{}
	err := client.Invoke("LeaveSecurityGroup", &args, &response)
	return err
}
<commit_msg>fix ecs.LockReason unmarshal error<commit_after>package ecs

import (
	"encoding/json"
	"strconv"
	"time"

	"github.com/denverdino/aliyungo/common"
	"github.com/denverdino/aliyungo/util"
)

// InstanceStatus represents instance status
type InstanceStatus string

// Constants of InstanceStatus
const (
	Creating = InstanceStatus("Creating")
	Running  = InstanceStatus("Running")
	Starting = InstanceStatus("Starting")

	Stopped  = InstanceStatus("Stopped")
	Stopping = InstanceStatus("Stopping")
)

type LockReason struct {
	LockReason string
}

type DescribeInstanceStatusArgs struct {
	RegionId common.Region
	ZoneId   string
	common.Pagination
}

//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/datatype&instancestatusitemtype
type InstanceStatusItemType struct {
	InstanceId string
	Status     InstanceStatus
}

type DescribeInstanceStatusResponse struct {
	common.Response
	common.PaginationResult
	InstanceStatuses struct {
		InstanceStatus []InstanceStatusItemType
	}
}

// DescribeInstanceStatus describes instance status
//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/instance&describeinstancestatus
func (client *Client) DescribeInstanceStatus(args *DescribeInstanceStatusArgs) (instanceStatuses []InstanceStatusItemType, pagination *common.PaginationResult, err error) {
	args.Validate()
	response := DescribeInstanceStatusResponse{}

	err = client.Invoke("DescribeInstanceStatus", args, &response)

	if err == nil {
		return response.InstanceStatuses.InstanceStatus, &response.PaginationResult, nil
	}

	return nil, nil, err
}

type StopInstanceArgs struct {
	InstanceId string
	ForceStop  bool
}

type StopInstanceResponse struct {
	common.Response
}

// StopInstance stops instance
//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/instance&stopinstance
func (client *Client) StopInstance(instanceId string, forceStop bool) error {
	args := StopInstanceArgs{
		InstanceId: instanceId,
		ForceStop:  forceStop,
	}
	response := StopInstanceResponse{}
	err := client.Invoke("StopInstance", &args, &response)
	return err
}

type StartInstanceArgs struct {
	InstanceId string
}

type StartInstanceResponse struct {
	common.Response
}

// StartInstance starts instance
//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/instance&startinstance
func (client *Client) StartInstance(instanceId string) error {
	args := StartInstanceArgs{InstanceId: instanceId}
	response := StartInstanceResponse{}
	err := client.Invoke("StartInstance", &args, &response)
	return err
}

type RebootInstanceArgs struct {
	InstanceId string
	ForceStop  bool
}

type RebootInstanceResponse struct {
	common.Response
}

// RebootInstance reboot instance
//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/instance&rebootinstance
func (client *Client) RebootInstance(instanceId string, forceStop bool) error {
	request := RebootInstanceArgs{
		InstanceId: instanceId,
		ForceStop:  forceStop,
	}
	response := RebootInstanceResponse{}
	err := client.Invoke("RebootInstance", &request, &response)
	return err
}

type DescribeInstanceAttributeArgs struct {
	InstanceId string
}

//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/datatype&operationlockstype
type OperationLocksType struct {
	LockReason []LockReason //enum for financial, security
}

//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/datatype&securitygroupidsettype
type SecurityGroupIdSetType struct {
	SecurityGroupId string
}

//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/datatype&ipaddresssettype
type IpAddressSetType struct {
	IpAddress []string
}

//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/datatype&vpcattributestype
type VpcAttributesType struct {
	VpcId            string
	VSwitchId        string
	PrivateIpAddress IpAddressSetType
	NatIpAddress     string
}

//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/datatype&eipaddressassociatetype
type EipAddressAssociateType struct {
	AllocationId       string
	IpAddress          string
	Bandwidth          int
	InternetChargeType common.InternetChargeType
}

//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/datatype&instanceattributestype
type InstanceAttributesType struct {
	InstanceId       string
	InstanceName     string
	Description      string
	ImageId          string
	RegionId         common.Region
	ZoneId           string
	ClusterId        string
	InstanceType     string
	HostName         string
	Status           InstanceStatus
	OperationLocks   OperationLocksType
	SecurityGroupIds struct {
		SecurityGroupId []string
	}
	PublicIpAddress         IpAddressSetType
	InnerIpAddress          IpAddressSetType
	InstanceNetworkType     string //enum Classic | Vpc
	InternetMaxBandwidthIn  int
	InternetMaxBandwidthOut int
	InternetChargeType      common.InternetChargeType
	CreationTime            util.ISO6801Time //time.Time
	VpcAttributes           VpcAttributesType
	EipAddress              EipAddressAssociateType
	IoOptimized             StringOrBool
}

type DescribeInstanceAttributeResponse struct {
	common.Response
	InstanceAttributesType
}

// DescribeInstanceAttribute describes instance attribute
//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/instance&describeinstanceattribute
func (client *Client) DescribeInstanceAttribute(instanceId string) (instance *InstanceAttributesType, err error) {
	args := DescribeInstanceAttributeArgs{InstanceId: instanceId}

	response := DescribeInstanceAttributeResponse{}
	err = client.Invoke("DescribeInstanceAttribute", &args, &response)
	if err != nil {
		return nil, err
	}
	return &response.InstanceAttributesType, err
}

type ModifyInstanceAttributeArgs struct {
	InstanceId   string
	InstanceName string
	Description  string
	Password     string
	HostName     string
}

type ModifyInstanceAttributeResponse struct {
	common.Response
}

//ModifyInstanceAttribute  modify instance attrbute
//
// You can read doc at https://help.aliyun.com/document_detail/ecs/open-api/instance/modifyinstanceattribute.html
func (client *Client) ModifyInstanceAttribute(args *ModifyInstanceAttributeArgs) error {
	response := ModifyInstanceAttributeResponse{}
	err := client.Invoke("ModifyInstanceAttribute", args, &response)
	return err
}

// Default timeout value for WaitForInstance method
const InstanceDefaultTimeout = 120

// WaitForInstance waits for instance to given status
func (client *Client) WaitForInstance(instanceId string, status InstanceStatus, timeout int) error {
	if timeout <= 0 {
		timeout = InstanceDefaultTimeout
	}
	for {
		instance, err := client.DescribeInstanceAttribute(instanceId)
		if err != nil {
			return err
		}
		if instance.Status == status {
			//TODO
			//Sleep one more time for timing issues
			time.Sleep(DefaultWaitForInterval * time.Second)
			break
		}
		timeout = timeout - DefaultWaitForInterval
		if timeout <= 0 {
			return common.GetClientErrorFromString("Timeout")
		}
		time.Sleep(DefaultWaitForInterval * time.Second)

	}
	return nil
}

type DescribeInstanceVncUrlArgs struct {
	RegionId   common.Region
	InstanceId string
}

type DescribeInstanceVncUrlResponse struct {
	common.Response
	VncUrl string
}

//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/instance&describeinstancevncurl
func (client *Client) DescribeInstanceVncUrl(args *DescribeInstanceVncUrlArgs) (string, error) {
	response := DescribeInstanceVncUrlResponse{}

	err := client.Invoke("DescribeInstanceVncUrl", args, &response)

	if err == nil {
		return response.VncUrl, nil
	}

	return "", err
}

type DescribeInstancesArgs struct {
	RegionId            common.Region
	VpcId               string
	VSwitchId           string
	ZoneId              string
	InstanceIds         string
	InstanceNetworkType string
	PrivateIpAddresses  string
	InnerIpAddresses    string
	PublicIpAddresses   string
	SecurityGroupId     string
	common.Pagination
}

type DescribeInstancesResponse struct {
	common.Response
	common.PaginationResult
	Instances struct {
		Instance []InstanceAttributesType
	}
}

// DescribeInstances describes instances
//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/instance&describeinstances
func (client *Client) DescribeInstances(args *DescribeInstancesArgs) (instances []InstanceAttributesType, pagination *common.PaginationResult, err error) {
	args.Validate()
	response := DescribeInstancesResponse{}

	err = client.Invoke("DescribeInstances", args, &response)

	if err == nil {
		return response.Instances.Instance, &response.PaginationResult, nil
	}

	return nil, nil, err
}

type DeleteInstanceArgs struct {
	InstanceId string
}

type DeleteInstanceResponse struct {
	common.Response
}

// DeleteInstance deletes instance
//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/instance&deleteinstance
func (client *Client) DeleteInstance(instanceId string) error {
	args := DeleteInstanceArgs{InstanceId: instanceId}
	response := DeleteInstanceResponse{}
	err := client.Invoke("DeleteInstance", &args, &response)
	return err
}

type DataDiskType struct {
	Size               int
	Category           DiskCategory //Enum cloud, ephemeral, ephemeral_ssd
	SnapshotId         string
	DiskName           string
	Description        string
	Device             string
	DeleteWithInstance bool
}

type SystemDiskType struct {
	Category    DiskCategory //Enum cloud, ephemeral, ephemeral_ssd
	DiskName    string
	Description string
}

type IoOptimized string

type StringOrBool struct {
	Value bool
}

// UnmarshalJSON implements the json.Unmarshaller interface.
func (io *StringOrBool) UnmarshalJSON(value []byte) error {
	if value[0] == '"' {
		var str string
		err := json.Unmarshal(value, &str)
		if err == nil {
			io.Value = (str == "true" || str == "optimized")
		}
		return err
	}
	var boolVal bool
	err := json.Unmarshal(value, &boolVal)
	if err == nil {
		io.Value = boolVal
	}
	return err
}

func (io StringOrBool) Bool() bool {
	return io.Value
}

func (io StringOrBool) String() string {
	return strconv.FormatBool(io.Value)
}

var (
	IoOptimizedNone      = IoOptimized("none")
	IoOptimizedOptimized = IoOptimized("optimized")
)

type CreateInstanceArgs struct {
	RegionId                common.Region
	ZoneId                  string
	ImageId                 string
	InstanceType            string
	SecurityGroupId         string
	InstanceName            string
	Description             string
	InternetChargeType      common.InternetChargeType
	InternetMaxBandwidthIn  int
	InternetMaxBandwidthOut int
	HostName                string
	Password                string
	IoOptimized             IoOptimized
	SystemDisk              SystemDiskType
	DataDisk                []DataDiskType
	VSwitchId               string
	PrivateIpAddress        string
	ClientToken             string
}

type CreateInstanceResponse struct {
	common.Response
	InstanceId string
}

// CreateInstance creates instance
//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/instance&createinstance
func (client *Client) CreateInstance(args *CreateInstanceArgs) (instanceId string, err error) {
	response := CreateInstanceResponse{}
	err = client.Invoke("CreateInstance", args, &response)
	if err != nil {
		return "", err
	}
	return response.InstanceId, err
}

type SecurityGroupArgs struct {
	InstanceId      string
	SecurityGroupId string
}

type SecurityGroupResponse struct {
	common.Response
}

//JoinSecurityGroup
//
//You can read doc at https://help.aliyun.com/document_detail/ecs/open-api/instance/joinsecuritygroup.html
func (client *Client) JoinSecurityGroup(instanceId string, securityGroupId string) error {
	args := SecurityGroupArgs{InstanceId: instanceId, SecurityGroupId: securityGroupId}
	response := SecurityGroupResponse{}
	err := client.Invoke("JoinSecurityGroup", &args, &response)
	return err
}

//LeaveSecurityGroup
//
//You can read doc at https://help.aliyun.com/document_detail/ecs/open-api/instance/leavesecuritygroup.html
func (client *Client) LeaveSecurityGroup(instanceId string, securityGroupId string) error {
	args := SecurityGroupArgs{InstanceId: instanceId, SecurityGroupId: securityGroupId}
	response := SecurityGroupResponse{}
	err := client.Invoke("LeaveSecurityGroup", &args, &response)
	return err
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
	"sync"
	"syscall"
	"testing"
	"time"
)

var (
	maxOpenRe = regexp.MustCompile("Max open files\\s+(\\d+)")
	waitPy    = "python " + abs(filepath.Join("_testdata", "wait.py"))
)

func abs(p string) string {
	a, err := filepath.Abs(p)
	if err != nil {
		panic(err)
	}
	return a
}

func setLogger(t *testing.T, cfg *Config, value string) {
	cfg.Log = new(Logger)
	if err := cfg.Log.Parse(value); err != nil {
		t.Fatal(err)
	}
}

type bufWriter bytes.Buffer

func (w *bufWriter) Open(_ string) error { return nil }

func (w *bufWriter) Close() error { return nil }

func (w *bufWriter) Write(_ string, b []byte) error {
	(*bytes.Buffer)(w).Write(b)
	return nil
}

func (w *bufWriter) Flush() error { return nil }

func TestService(t *testing.T) {
	cfg := &Config{
		File:    "/non-existant",
		Command: "sleep 50000",
		Name:    "sleep",
	}
	setLogger(t, cfg, "file")
	s := newService(cfg)
	s.errCh = make(chan error)
	var wg sync.WaitGroup
	wg.Add(2)
	go func() {
		go func() {
			// This goroutine starts after s.Start() is called.
			if err := s.Stop(); err != nil {
				t.Fatalf("error stopping: %s", err)
			}
			wg.Done()
		}()
		if err := s.Start(); err != nil {
			t.Fatalf("error starting: %s", err)
		}
		wg.Done()
	}()
	wg.Wait()
	if s.State != StateStopped {
		t.Fatal("service is not stopped")
	}
	if err := s.Start(); err != nil {
		t.Fatalf("error starting again: %s", err)
	}
	// Kill it and check if it's restarted
	if err := exec.Command("killall", "-9", "sleep").Run(); err != nil {
		t.Fatalf("error killing: %s", err)
	}
	s.mu.Lock()
	state := s.State
	s.mu.Unlock()
	if state != StateStarted {
		t.Fatal("service is not started")
	}
	<-s.errCh
	s.mu.Lock()
	restarts := s.Restarts
	s.mu.Unlock()
	if restarts != 1 {
		t.Fatalf("expecting 1 restarts, got %d", restarts)
	}
	// Kill it and stop while it's restarting
	if err := exec.Command("killall", "-9", "sleep").Run(); err != nil {
		t.Fatalf("error killing: %s", err)
	}
	if err := s.Stop(); err != nil {
		t.Fatalf("error stopping: %s", err)
	}
}

func TestExitingService(t *testing.T) {
	cfg := &Config{
		File:    "/non-existant",
		Command: "true",
		Name:    "true",
	}
	setLogger(t, cfg, "none")
	s := newService(cfg)
	err := s.Start()
	if err == nil || !strings.Contains(err.Error(), "too fast") {
		t.Fatalf("expecting error due to fast exit, got %s instead", err)
	}
	if err := s.Stop(); err != nil {
		t.Fatalf("error stopping backoff service: %s", err)
	}
	// Wait until the next restart and make sure it doesn't happen
	time.Sleep(s.untilNextRestart() + time.Second)
	if s.Restarts > 0 {
		t.Fatalf("expecting no restarts, got %d instead", s.Restarts)
	}
}

func checkMaxOpenFiles(t *testing.T, s *Service, expect int) {
	buf := (*bytes.Buffer)(s.Config.Log.w.(*bufWriter))
	lines := strings.Split(buf.String(), "\n")
	var line string
	for _, v := range lines {
		if !strings.Contains(v, "start") && !strings.Contains(v, "error") {
			line = v
			break
		}
	}
	parts := strings.Split(line, "-")
	val, err := strconv.Atoi(strings.Trim(parts[1], "\n- "))
	if err != nil {
		t.Fatal(err)
	}
	if val != expect {
		t.Errorf("expecting max open files %d, got %d", expect, val)
	}
}

func getMaxOpenFiles(t *testing.T) int {
	var limit syscall.Rlimit
	if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil {
		t.Fatal(err)
	}
	return int(limit.Cur)
}

func TestServiceMaxOpenFiles(t *testing.T) {
	maxOpen1 := getMaxOpenFiles(t)
	cfg := &Config{
		File:    "wait",
		Command: waitPy,
		Name:    "wait",
	}
	setLogger(t, cfg, "none")
	buf := new(bytes.Buffer)
	cfg.Log.w = (*bufWriter)(buf)
	s := newService(cfg)
	if err := s.Start(); err != nil {
		t.Fatal(err)
	}
	checkMaxOpenFiles(t, s, maxOpen1)
	if err := s.Stop(); err != nil {
		t.Fatal(err)
	}
	sMaxOpen := maxOpen1 / 2
	cfg.MaxOpenFiles = sMaxOpen
	buf.Reset()
	if err := s.Start(); err != nil {
		t.Fatal(err)
	}
	checkMaxOpenFiles(t, s, sMaxOpen)
	if err := s.Stop(); err != nil {
		t.Fatal(err)
	}
	if os.Geteuid() == 0 {
		maxOpen2 := getMaxOpenFiles(t)
		if maxOpen1 != maxOpen2 {
			t.Errorf("max open files for this process changed from %d to %d", maxOpen1, maxOpen2)
		}
	} else {
		t.Log("skipping max open files value restoration test, must run as root")
	}
}

func init() {
	logDir = "/tmp/governator"
}
<commit_msg>Fix error format<commit_after>package main

import (
	"bytes"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
	"sync"
	"syscall"
	"testing"
	"time"
)

var (
	maxOpenRe = regexp.MustCompile("Max open files\\s+(\\d+)")
	waitPy    = "python " + abs(filepath.Join("_testdata", "wait.py"))
)

func abs(p string) string {
	a, err := filepath.Abs(p)
	if err != nil {
		panic(err)
	}
	return a
}

func setLogger(t *testing.T, cfg *Config, value string) {
	cfg.Log = new(Logger)
	if err := cfg.Log.Parse(value); err != nil {
		t.Fatal(err)
	}
}

type bufWriter bytes.Buffer

func (w *bufWriter) Open(_ string) error { return nil }

func (w *bufWriter) Close() error { return nil }

func (w *bufWriter) Write(_ string, b []byte) error {
	(*bytes.Buffer)(w).Write(b)
	return nil
}

func (w *bufWriter) Flush() error { return nil }

func TestService(t *testing.T) {
	cfg := &Config{
		File:    "/non-existant",
		Command: "sleep 50000",
		Name:    "sleep",
	}
	setLogger(t, cfg, "file")
	s := newService(cfg)
	s.errCh = make(chan error)
	var wg sync.WaitGroup
	wg.Add(2)
	go func() {
		go func() {
			// This goroutine starts after s.Start() is called.
			if err := s.Stop(); err != nil {
				t.Fatalf("error stopping: %s", err)
			}
			wg.Done()
		}()
		if err := s.Start(); err != nil {
			t.Fatalf("error starting: %s", err)
		}
		wg.Done()
	}()
	wg.Wait()
	if s.State != StateStopped {
		t.Fatal("service is not stopped")
	}
	if err := s.Start(); err != nil {
		t.Fatalf("error starting again: %s", err)
	}
	// Kill it and check if it's restarted
	if err := exec.Command("killall", "-9", "sleep").Run(); err != nil {
		t.Fatalf("error killing: %s", err)
	}
	s.mu.Lock()
	state := s.State
	s.mu.Unlock()
	if state != StateStarted {
		t.Fatal("service is not started")
	}
	<-s.errCh
	s.mu.Lock()
	restarts := s.Restarts
	s.mu.Unlock()
	if restarts != 1 {
		t.Fatalf("expecting 1 restarts, got %d", restarts)
	}
	// Kill it and stop while it's restarting
	if err := exec.Command("killall", "-9", "sleep").Run(); err != nil {
		t.Fatalf("error killing: %s", err)
	}
	if err := s.Stop(); err != nil {
		t.Fatalf("error stopping: %s", err)
	}
}

func TestExitingService(t *testing.T) {
	cfg := &Config{
		File:    "/non-existant",
		Command: "true",
		Name:    "true",
	}
	setLogger(t, cfg, "none")
	s := newService(cfg)
	err := s.Start()
	if err == nil || !strings.Contains(err.Error(), "too fast") {
		t.Fatalf("expecting error due to fast exit, got %v instead", err)
	}
	if err := s.Stop(); err != nil {
		t.Fatalf("error stopping backoff service: %s", err)
	}
	// Wait until the next restart and make sure it doesn't happen
	time.Sleep(s.untilNextRestart() + time.Second)
	if s.Restarts > 0 {
		t.Fatalf("expecting no restarts, got %d instead", s.Restarts)
	}
}

func checkMaxOpenFiles(t *testing.T, s *Service, expect int) {
	buf := (*bytes.Buffer)(s.Config.Log.w.(*bufWriter))
	lines := strings.Split(buf.String(), "\n")
	var line string
	for _, v := range lines {
		if !strings.Contains(v, "start") && !strings.Contains(v, "error") {
			line = v
			break
		}
	}
	parts := strings.Split(line, "-")
	val, err := strconv.Atoi(strings.Trim(parts[1], "\n- "))
	if err != nil {
		t.Fatal(err)
	}
	if val != expect {
		t.Errorf("expecting max open files %d, got %d", expect, val)
	}
}

func getMaxOpenFiles(t *testing.T) int {
	var limit syscall.Rlimit
	if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil {
		t.Fatal(err)
	}
	return int(limit.Cur)
}

func TestServiceMaxOpenFiles(t *testing.T) {
	maxOpen1 := getMaxOpenFiles(t)
	cfg := &Config{
		File:    "wait",
		Command: waitPy,
		Name:    "wait",
	}
	setLogger(t, cfg, "none")
	buf := new(bytes.Buffer)
	cfg.Log.w = (*bufWriter)(buf)
	s := newService(cfg)
	if err := s.Start(); err != nil {
		t.Fatal(err)
	}
	checkMaxOpenFiles(t, s, maxOpen1)
	if err := s.Stop(); err != nil {
		t.Fatal(err)
	}
	sMaxOpen := maxOpen1 / 2
	cfg.MaxOpenFiles = sMaxOpen
	buf.Reset()
	if err := s.Start(); err != nil {
		t.Fatal(err)
	}
	checkMaxOpenFiles(t, s, sMaxOpen)
	if err := s.Stop(); err != nil {
		t.Fatal(err)
	}
	if os.Geteuid() == 0 {
		maxOpen2 := getMaxOpenFiles(t)
		if maxOpen1 != maxOpen2 {
			t.Errorf("max open files for this process changed from %d to %d", maxOpen1, maxOpen2)
		}
	} else {
		t.Log("skipping max open files value restoration test, must run as root")
	}
}

func init() {
	logDir = "/tmp/governator"
}
<|endoftext|>


<commit_before>package bidirpc

import (
	"fmt"
	"net"
	"testing"
)

type Args struct {
	Name string
}

type Reply struct {
	Msg string
}

type Service struct {
	name      string
	callCount int
}

func (s *Service) SayHi(args Args, reply *Reply) error {
	reply.Msg = fmt.Sprintf("[%v] Hi %v, from %v", s.callCount, args.Name, s.name)
	s.callCount++
	return nil
}

func TestBasic(t *testing.T) {
	connYin, connYang := net.Pipe()

	sessionYin, err := NewSession(connYin, true)
	if err != nil {
		t.Fatalf("NewSession error: %v", err)
	}
	sessionYang, err := NewSession(connYang, false)
	if err != nil {
		t.Fatalf("NewSession error: %v", err)
	}

	serviceYin := &Service{name: "Yin"}
	err = sessionYin.Register(serviceYin)
	if err != nil {
		t.Fatalf("Register error: %v", err)
	}

	serviceYang := &Service{name: "Yang"}
	sessionYang.Register(serviceYang)
	if err != nil {
		t.Fatalf("Register error: %v", err)
	}

	for i := 0; i < 3; i++ {
		args := Args{"Windows"}
		reply := new(Reply)
		err = sessionYin.Call("Service.SayHi", args, reply)
		if err != nil {
			t.Fatalf("Call error: %v", err)
		}
		t.Logf("reply = %v\n", reply.Msg)

		args.Name = "OSX"
		err = sessionYang.Call("Service.SayHi", args, reply)
		if err != nil {
			t.Fatalf("Call error: %v", err)
		}
		t.Logf("reply = %v\n", reply.Msg)

		args.Name = "iOS"
		err = sessionYin.Call("Service.SayHi", args, reply)
		if err != nil {
			t.Fatalf("Call error: %v", err)
		}
		t.Logf("reply = %v\n", reply.Msg)
	}

	sessionYang.RegisterName("NewService", serviceYang)
	if err != nil {
		t.Fatalf("RegisterName error: %v", err)
	}
	args := Args{"Linux"}
	reply := new(Reply)
	call := sessionYin.Go("NewService.SayHi", args, reply, nil)
	<-call.Done
	if call.Error != nil {
		t.Fatalf("Go error: %v", call.Error)
	}
	t.Logf("reply = %v\n", reply.Msg)

	sessionYin.Close()
	sessionYang.Close()
}

func TestReadError(t *testing.T) {
	connYin, connYang := net.Pipe()
	connYang.Close()

	sessionYin, err := NewSession(connYin, true)
	if err != nil {
		t.Fatalf("NewSession error: %v", err)
	}

	args := Args{"Windows"}
	reply := new(Reply)
	err = sessionYin.Call("Service.SayHi", args, reply)
	if err == nil {
		t.Fatal("Call should return error, got nil")
	}

	sessionYin.Close()
}

func TestWriteError(t *testing.T) {
	connYin, _ := net.Pipe()
	connYin.Close()

	sessionYin, err := NewSession(connYin, true)
	if err != nil {
		t.Fatalf("NewSession error: %v", err)
	}

	args := Args{"Windows"}
	reply := new(Reply)
	err = sessionYin.Call("Service.SayHi", args, reply)
	if err == nil {
		t.Fatal("Call should return error, got nil")
	}

	sessionYin.Close()
}
<commit_msg>Add TestReadInvalidHeader,TestReadBodyError<commit_after>package bidirpc

import (
	"fmt"
	"net"
	"testing"
)

type Args struct {
	Name string
}

type Reply struct {
	Msg string
}

type Service struct {
	name      string
	callCount int
}

func (s *Service) SayHi(args Args, reply *Reply) error {
	reply.Msg = fmt.Sprintf("[%v] Hi %v, from %v", s.callCount, args.Name, s.name)
	s.callCount++
	return nil
}

func TestBasic(t *testing.T) {
	connYin, connYang := net.Pipe()

	sessionYin, err := NewSession(connYin, true)
	if err != nil {
		t.Fatalf("NewSession error: %v", err)
	}
	sessionYang, err := NewSession(connYang, false)
	if err != nil {
		t.Fatalf("NewSession error: %v", err)
	}

	serviceYin := &Service{name: "Yin"}
	err = sessionYin.Register(serviceYin)
	if err != nil {
		t.Fatalf("Register error: %v", err)
	}

	serviceYang := &Service{name: "Yang"}
	sessionYang.Register(serviceYang)
	if err != nil {
		t.Fatalf("Register error: %v", err)
	}

	for i := 0; i < 3; i++ {
		args := Args{"Windows"}
		reply := new(Reply)
		err = sessionYin.Call("Service.SayHi", args, reply)
		if err != nil {
			t.Fatalf("Call error: %v", err)
		}
		t.Logf("reply = %v\n", reply.Msg)

		args.Name = "OSX"
		err = sessionYang.Call("Service.SayHi", args, reply)
		if err != nil {
			t.Fatalf("Call error: %v", err)
		}
		t.Logf("reply = %v\n", reply.Msg)

		args.Name = "iOS"
		err = sessionYin.Call("Service.SayHi", args, reply)
		if err != nil {
			t.Fatalf("Call error: %v", err)
		}
		t.Logf("reply = %v\n", reply.Msg)
	}

	sessionYang.RegisterName("NewService", serviceYang)
	if err != nil {
		t.Fatalf("RegisterName error: %v", err)
	}
	args := Args{"Linux"}
	reply := new(Reply)
	call := sessionYin.Go("NewService.SayHi", args, reply, nil)
	<-call.Done
	if call.Error != nil {
		t.Fatalf("Go error: %v", call.Error)
	}
	t.Logf("reply = %v\n", reply.Msg)

	sessionYin.Close()
	sessionYang.Close()
}

func TestReadError(t *testing.T) {
	connYin, connYang := net.Pipe()
	connYang.Close()

	sessionYin, err := NewSession(connYin, true)
	if err != nil {
		t.Fatalf("NewSession error: %v", err)
	}

	args := Args{"Windows"}
	reply := new(Reply)
	err = sessionYin.Call("Service.SayHi", args, reply)
	if err == nil {
		t.Fatal("Call should return error, got nil")
	}

	sessionYin.Close()
}

func TestWriteError(t *testing.T) {
	connYin, _ := net.Pipe()
	connYin.Close()

	sessionYin, err := NewSession(connYin, true)
	if err != nil {
		t.Fatalf("NewSession error: %v", err)
	}

	args := Args{"Windows"}
	reply := new(Reply)
	err = sessionYin.Call("Service.SayHi", args, reply)
	if err == nil {
		t.Fatal("Call should return error, got nil")
	}

	sessionYin.Close()
}

func TestReadInvalidHeader(t *testing.T) {
	connYin, connYang := net.Pipe()

	sessionYin, err := NewSession(connYin, true)
	if err != nil {
		t.Fatalf("NewSession error: %v", err)
	}

	var header [4]byte
	connYang.Write(header[:])

	args := Args{"Windows"}
	reply := new(Reply)
	err = sessionYin.Call("Service.SayHi", args, reply)
	if err == nil {
		t.Fatal("Call should return error, got nil")
	}

	sessionYin.Close()
}

func TestReadBodyError(t *testing.T) {
	connYin, connYang := net.Pipe()

	sessionYin, err := NewSession(connYin, true)
	if err != nil {
		t.Fatalf("NewSession error: %v", err)
	}

	var header [4]byte
	encodeHeader(header[:], streamTypeYang, 10)
	connYang.Write(header[:])
	connYang.Close()

	args := Args{"Windows"}
	reply := new(Reply)
	err = sessionYin.Call("Service.SayHi", args, reply)
	if err == nil {
		t.Fatal("Call should return error, got nil")
	}

	sessionYin.Close()
}
<|endoftext|>


<commit_before>/*
Copyright 2018 The Knative Authors

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

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

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

package main

import (
	"fmt"
	"math"
	"net/http"
	"strconv"
	"sync"
	"time"

	"knative.dev/serving/test"
)

// Algorithm from https://stackoverflow.com/a/21854246

// Only primes less than or equal to N will be generated
func primes(N int) []int {

	var x, y, n int
	nsqrt := math.Sqrt(float64(N))

	isPrime := make([]bool, N)

	for x = 1; float64(x) <= nsqrt; x++ {
		for y = 1; float64(y) <= nsqrt; y++ {
			n = 4*(x*x) + y*y
			if n <= N && (n%12 == 1 || n%12 == 5) {
				isPrime[n] = !isPrime[n]
			}
			n = 3*(x*x) + y*y
			if n <= N && n%12 == 7 {
				isPrime[n] = !isPrime[n]
			}
			n = 3*(x*x) - y*y
			if x > y && n <= N && n%12 == 11 {
				isPrime[n] = !isPrime[n]
			}
		}
	}

	for n = 5; float64(n) <= nsqrt; n++ {
		if isPrime[n] {
			for y = n * n; y < N; y += n * n {
				isPrime[y] = false
			}
		}
	}

	isPrime[2] = true
	isPrime[3] = true

	primes := make([]int, 0, 1270606)
	for x = 0; x < len(isPrime)-1; x++ {
		if isPrime[x] {
			primes = append(primes, x)
		}
	}

	// primes is now a slice that contains all primes numbers up to N
	return primes
}

func bloat(mb int) string {
	b := make([]byte, mb*1024*1024)
	for i := 0; i < len(b); i++ {
		b[i] = 1
	}
	return fmt.Sprintf("Allocated %v Mb of memory.\n", mb)
}

func prime(max int) string {
	p := primes(max)
	if len(p) == 0 {
		return fmt.Sprintf("There are no primes smaller than %d.\n", max)
	}
	return fmt.Sprintf("The largest prime less than %d is %d.\n", max, p[len(p)-1])
}

func sleep(ms int) string {
	start := time.Now()
	time.Sleep(time.Duration(ms) * time.Millisecond)
	return fmt.Sprintf("Slept for %v.\n", time.Since(start))
}

func parseIntParam(r *http.Request, param string) (int, bool, error) {
	value := r.URL.Query().Get(param)
	if value == "" {
		return 0, false, nil
	}
	i, err := strconv.Atoi(value)
	if err != nil {
		return 0, false, err
	}
	return i, true, nil
}

func handler(w http.ResponseWriter, r *http.Request) {
	// Validate inputs.
	ms, hasMs, err := parseIntParam(r, "sleep")
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	max, hasMax, err := parseIntParam(r, "prime")
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	mb, hasMb, err := parseIntParam(r, "bloat")
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	// Consume time, cpu and memory in parallel.
	var wg sync.WaitGroup
	defer wg.Wait()
	if hasMs && ms > 0 {
		wg.Add(1)
		go func() {
			defer wg.Done()
			fmt.Fprint(w, sleep(ms))
		}()
	}
	if hasMax && max > 0 {
		wg.Add(1)
		go func() {
			defer wg.Done()
			fmt.Fprint(w, prime(max))
		}()
	}
	if hasMb && mb > 0 {
		wg.Add(1)
		go func() {
			defer wg.Done()
			fmt.Fprint(w, bloat(mb))
		}()
	}
}

func main() {
	test.ListenAndServeGracefully(":8080", handler)
}
<commit_msg>Generate random sleep time for autoscale test image (#4957)<commit_after>/*
Copyright 2018 The Knative Authors

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

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

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

package main

import (
	"fmt"
	"math"
	"math/rand"
	"net/http"
	"strconv"
	"sync"
	"time"

	"knative.dev/serving/test"
)

func init() {
	rand.Seed(time.Now().UnixNano())
}

// Algorithm from https://stackoverflow.com/a/21854246

// Only primes less than or equal to N will be generated
func primes(N int) []int {

	var x, y, n int
	nsqrt := math.Sqrt(float64(N))

	isPrime := make([]bool, N)

	for x = 1; float64(x) <= nsqrt; x++ {
		for y = 1; float64(y) <= nsqrt; y++ {
			n = 4*(x*x) + y*y
			if n <= N && (n%12 == 1 || n%12 == 5) {
				isPrime[n] = !isPrime[n]
			}
			n = 3*(x*x) + y*y
			if n <= N && n%12 == 7 {
				isPrime[n] = !isPrime[n]
			}
			n = 3*(x*x) - y*y
			if x > y && n <= N && n%12 == 11 {
				isPrime[n] = !isPrime[n]
			}
		}
	}

	for n = 5; float64(n) <= nsqrt; n++ {
		if isPrime[n] {
			for y = n * n; y < N; y += n * n {
				isPrime[y] = false
			}
		}
	}

	isPrime[2] = true
	isPrime[3] = true

	primes := make([]int, 0, 1270606)
	for x = 0; x < len(isPrime)-1; x++ {
		if isPrime[x] {
			primes = append(primes, x)
		}
	}

	// primes is now a slice that contains all primes numbers up to N
	return primes
}

func bloat(mb int) string {
	b := make([]byte, mb*1024*1024)
	for i := 0; i < len(b); i++ {
		b[i] = 1
	}
	return fmt.Sprintf("Allocated %v Mb of memory.\n", mb)
}

func prime(max int) string {
	p := primes(max)
	if len(p) == 0 {
		return fmt.Sprintf("There are no primes smaller than %d.\n", max)
	}
	return fmt.Sprintf("The largest prime less than %d is %d.\n", max, p[len(p)-1])
}

func sleep(ms int) string {
	start := time.Now()
	time.Sleep(time.Duration(ms) * time.Millisecond)
	return fmt.Sprintf("Slept for %v.\n", time.Since(start))
}

func randSleep(randSleepTimeMean, randSleepTimeStdDev int) string {
	start := time.Now()
	randRes := rand.NormFloat64()*float64(randSleepTimeMean) + float64(randSleepTimeStdDev)
	time.Sleep(time.Duration(randRes) * time.Millisecond)
	return fmt.Sprintf("Randomly slept for %v.\n", time.Since(start))
}

func parseIntParam(r *http.Request, param string) (int, bool, error) {
	value := r.URL.Query().Get(param)
	if value == "" {
		return 0, false, nil
	}
	i, err := strconv.Atoi(value)
	if err != nil {
		return 0, false, err
	}
	return i, true, nil
}

func handler(w http.ResponseWriter, r *http.Request) {
	// Validate inputs.
	ms, hasMs, err := parseIntParam(r, "sleep")
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	mssd, hasMssd, err := parseIntParam(r, "sleep-stddev")
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	max, hasMax, err := parseIntParam(r, "prime")
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	mb, hasMb, err := parseIntParam(r, "bloat")
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	// Consume time, cpu and memory in parallel.
	var wg sync.WaitGroup
	defer wg.Wait()
	if hasMs && !hasMssd && ms > 0 {
		wg.Add(1)
		go func() {
			defer wg.Done()
			fmt.Fprint(w, sleep(ms))
		}()
	}
	if hasMs && hasMssd && ms > 0 && mssd > 0 {
		wg.Add(1)
		go func() {
			defer wg.Done()
			fmt.Fprint(w, randSleep(ms, mssd))
		}()
	}
	if hasMax && max > 0 {
		wg.Add(1)
		go func() {
			defer wg.Done()
			fmt.Fprint(w, prime(max))
		}()
	}
	if hasMb && mb > 0 {
		wg.Add(1)
		go func() {
			defer wg.Done()
			fmt.Fprint(w, bloat(mb))
		}()
	}
}

func main() {
	test.ListenAndServeGracefully(":8080", handler)
}
<|endoftext|>


<commit_before>package index

type Index struct {
	br    *blob_reader
	Docs  map[uint32][]byte
	Attrs map[string][]IbDoc
}

func Open(name string) (*Index, error) {
	var in Index
	var err error

	in.br, err = open_blob_reader(name)
	if err != nil {
		return nil, err
	}

	in.Docs = make(map[uint32][]byte)
	for _, d := range in.br.get_documents() {
		in.Docs[d.Doc.Id] = in.br.get_document_data(&d)
	}

	in.Attrs = make(map[string][]IbDoc)
	for _, a := range in.br.get_invattrs() {
		in.Attrs[in.br.get_attr_name(&a)] = in.br.get_attr_docs(&a)
	}
	return &in, nil
}

func (in *Index) Close() {
	in.br.close()
}
<commit_msg>Implement meta by using the bconf package (separate repository).<commit_after>package index

import (
	"bconf"
)

type Index struct {
	br    *blob_reader
	Docs  map[uint32][]byte
	Attrs map[string][]IbDoc
	Meta bconf.Bconf
	header string
}

func Open(name string) (*Index, error) {
	var in Index
	var err error

	in.br, err = open_blob_reader(name)
	if err != nil {
		return nil, err
	}

	in.Docs = make(map[uint32][]byte)
	for _, d := range in.br.get_documents() {
		in.Docs[d.Doc.Id] = in.br.get_document_data(&d)
	}

	in.Attrs = make(map[string][]IbDoc)
	for _, a := range in.br.get_invattrs() {
		in.Attrs[in.br.get_attr_name(&a)] = in.br.get_attr_docs(&a)
	}

	in.Meta.LoadJson(in.br.get_meta())

	in.Header()	// Pre-cache the header to avoid race conditions.

	return &in, nil
}

func (in Index) Header() string {
	if in.header == "" {
		in.Meta.GetNode("attr", "order").ForeachSorted(func(k, v string) {
			if in.header != "" {
				in.header += "\t"
			}
			in.header += v
		})
	}
	return in.header
}

func (in Index) Close() {
	in.br.close()
}
<|endoftext|>