<commit_before>package main

import (
	"context"
	"errors"
	"fmt"
	"log"
	"net"
	"sync"

	pb "github.com/taylorflatt/go-chat"
	"google.golang.org/grpc"
	"google.golang.org/grpc/reflection"
)

const (
	port = ":12021"
)

// Server is used to implement the RemoteCommandServer
type server struct{}

var clients = make(map[string]chan pb.ChatMessage, 100)
var groups = make(map[string]chan pb.ChatMessage, 100)
var groupClients = make(map[string][]string)

var lock = &sync.RWMutex{}

func addListener(name string, queue chan pb.ChatMessage) {

	lock.Lock()
	defer lock.Unlock()
	groups[name] = queue
}

func removeListener(name string) {

	lock.Lock()
	defer lock.Unlock()
	delete(groups, name)
}

func hasListener(name string) bool {

	lock.RLock()
	defer lock.RUnlock()
	_, ok := clients[name]
	return ok
}

func broadcast(client string, msg pb.ChatMessage) {

	lock.Lock()
	defer lock.Unlock()
	for sender, queue := range clients {
		if sender != client {
			queue <- msg
		}
	}
}

func clientExists(name string) bool {

	lock.RLock()
	defer lock.RUnlock()
	for c := range clients {
		if c == name {
			return true
		}
	}

	return false
}

func inGroup(name string) bool {

	lock.RLock()
	defer lock.RUnlock()
	for n, c := range groupClients {
		for _, s := range c {
			if name == s {
				return true
			}
		}
	}

	return false
}

func (s *server) EstablishConnection(ctx context.Context, in *pb.InviteRequest) (*pb.InviteRequest, error) {

	requester := in.Requester
	buddies := in.Clients
	numClients := len(buddies)

	// Check that all the clients are currently on the server and not already in groups.
	for _, name := range buddies {
		if !clientExists(name) {
			return nil, errors.New("connection failed: the client (" + name + ") isn't registered on the server anymore")
		} else if inGroup(name) {
			return nil, errors.New("connection failed: the client (" + name + ") is already in another group")
		}
	}

}

func (s *server) RouteChat(stream pb.Chat_RouteChatServer) error {

	msg, err := stream.Recv()

	if err != nil {
		return err
	}

	in := make(chan pb.ChatMessage, 100)
	var client string

	// Register the client with the server.
	if msg.Register {
		client = msg.Sender

		if hasListener(client) {
			return fmt.Errorf("this client already exists")
		}

		addListener(client, in)
	} else {
		return fmt.Errorf("you need to register prior to sending messages")
	}

	// Send/Receive messages.
	out := make(chan pb.Message, 100)
	go listenToClient(stream, out)

	for {
		select {
		case outbox := <-out:
			broadcast(client, outbox)
		case inbox := <-in:
			stream.Send(&inbox)
		}
	}

}

func main() {

	lis, err := net.Listen("tcp", port)

	if err != nil {
		log.Fatalf("Failed to listen %v", err)
	}

	// Initializes the gRPC server.
	s := grpc.NewServer()

	// Register the server with gRPC.
	pb.RegisterChatServer(s, &server{})

	// Register reflection service on gRPC server.
	reflection.Register(s)

	if err := s.Serve(lis); err != nil {
		log.Fatalf("Failed to serve: %v", err)
	}
}
<commit_msg>Finished Establish Connection<commit_after>package main

import (
	"context"
	"errors"
	"fmt"
	"log"
	"math/rand"
	"net"
	"sync"
	"time"

	pb "github.com/taylorflatt/go-chat"
	"google.golang.org/grpc"
	"google.golang.org/grpc/reflection"
)

const (
	port = ":12021"
)

// Server is used to implement the RemoteCommandServer
type server struct{}

var clients = make(map[string]chan pb.ChatMessage, 100)
var groups = make(map[int]chan pb.ChatMessage, 100)
var groupClients = make(map[int][]string)

var lock = &sync.RWMutex{}

func RandInt(min int, max int) int {
	rand.Seed(time.Now().Unix())
	return min + rand.Intn(max-min)
}

func addListener(name string, queue chan pb.ChatMessage) {

	lock.Lock()
	defer lock.Unlock()
	groups[name] = queue
}

func removeListener(name string) {

	lock.Lock()
	defer lock.Unlock()
	delete(groups, name)
}

func hasListener(name string) bool {

	lock.RLock()
	defer lock.RUnlock()
	_, ok := clients[name]
	return ok
}

func broadcast(client string, msg pb.ChatMessage) {

	lock.Lock()
	defer lock.Unlock()
	for sender, queue := range clients {
		if sender != client {
			queue <- msg
		}
	}
}

func clientExists(name string) bool {

	lock.RLock()
	defer lock.RUnlock()
	for c := range clients {
		if c == name {
			return true
		}
	}

	return false
}

func inGroup(name string) bool {

	lock.RLock()
	defer lock.RUnlock()
	for n, c := range groupClients {
		for _, s := range c {
			if name == s {
				return true
			}
		}
	}

	return false

}

func genGroupName() int {

	exists := false

	for {
		val := RandInt(1, 1000)
		// Look through all the groups to make sure it is unique.
		for g, _ := range groups {
			if val == g {
				exists = true
				break
			}
		}

		// If it is unique, return the new group name.
		if !exists {
			return val
		}
	}
}

func (s *server) EstablishConnection(ctx context.Context, in *pb.InviteRequest) (*pb.InviteResponse, error) {

	requester := in.Requester
	buddies := in.Clients
	numClients := len(buddies)

	// Check that all the clients are currently on the server and not already in groups.
	for _, name := range buddies {
		if !clientExists(name) {
			return &pb.InviteResponse{Response: false}, errors.New("connection failed: the client (" + name + ") isn't registered on the server anymore")
		} else if inGroup(name) {
			return &pb.InviteResponse{Response: false}, errors.New("connection failed: the client (" + name + ") is already in another group")
		}
	}

	// Now we need to create a group that contains all of the buddies with a single channel.
	name := genGroupName()
	groups[name] = make(chan pb.ChatMessage, 100)
	groupClients[name] = buddies

	return &pb.InviteResponse{Response: true}, nil
}

func (s *server) RouteChat(stream pb.Chat_RouteChatServer) error {

	msg, err := stream.Recv()

	if err != nil {
		return err
	}

	in := make(chan pb.ChatMessage, 100)
	var client string

	// Register the client with the server.
	if msg.Register {
		client = msg.Sender

		if hasListener(client) {
			return fmt.Errorf("this client already exists")
		}

		addListener(client, in)
	} else {
		return fmt.Errorf("you need to register prior to sending messages")
	}

	// Send/Receive messages.
	out := make(chan pb.Message, 100)
	go listenToClient(stream, out)

	for {
		select {
		case outbox := <-out:
			broadcast(client, outbox)
		case inbox := <-in:
			stream.Send(&inbox)
		}
	}

}

func main() {

	lis, err := net.Listen("tcp", port)

	if err != nil {
		log.Fatalf("Failed to listen %v", err)
	}

	// Initializes the gRPC server.
	s := grpc.NewServer()

	// Register the server with gRPC.
	pb.RegisterChatServer(s, &server{})

	// Register reflection service on gRPC server.
	reflection.Register(s)

	if err := s.Serve(lis); err != nil {
		log.Fatalf("Failed to serve: %v", err)
	}
}
<|endoftext|>


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

package agent

import (
	"github.com/gocd-contrib/gocd-golang-agent/protocol"
	"os"
	"path/filepath"
	"strings"
)

func CommandTest(s *BuildSession, cmd *protocol.BuildCommand) error {
	flag := cmd.Args["flag"]

	if flag == "-eq" || flag == "-neq" {
		output, err := s.processTestCommand(cmd.SubCommands[0])
		if err != nil {
			s.debugLog("test -eq exec command error: %v", err)
		}
		expected := strings.TrimSpace(cmd.Args["left"])
		actual := strings.TrimSpace(output.String())

		if flag == "-eq" {
			if expected != actual {
				return Err("expected '%v', but was '%v'", expected, actual)
			}
		} else {
			if expected == actual {
				return Err("expected different with '%v'", expected)
			}
		}
		return nil
	}

	targetPath := filepath.Join(s.wd, cmd.Args["left"])
	info, err := os.Stat(targetPath)
	switch flag {
	case "-d":
		if err != nil {
			return err
		}
		if info.IsDir() {
			return nil
		} else {
			return Err("%v is not a directory", targetPath)
		}
	case "-nd":
		if err != nil {
			if os.IsNotExist(err) {
				return nil
			}
			return err
		}
		if info.IsDir() {
			return Err("%v is a directory", targetPath)
		} else {
			return nil
		}
	case "-f":
		if err != nil {
			return err
		}
		if info.IsDir() {
			return Err("%v is not a file", targetPath)
		} else {
			return nil
		}
	case "-nf":
		if err != nil {
			if os.IsNotExist(err) {
				return nil
			}
			return err
		}
		if info.IsDir() {
			return nil
		} else {
			return Err("%v is a file", targetPath)
		}
	}

	return Err("unknown test flag: %v", flag)
}
<commit_msg>Adding -in and -nin flags to CommandTest<commit_after>/*
 * Copyright 2016 ThoughtWorks, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package agent

import (
	"github.com/gocd-contrib/gocd-golang-agent/protocol"
	"os"
	"path/filepath"
	"strings"
)

func CommandTest(s *BuildSession, cmd *protocol.BuildCommand) error {
	flag := cmd.Args["flag"]

	if flag == "-eq" || flag == "-neq" || flag == "-in" || flag == "-nin" {
		output, err := s.processTestCommand(cmd.SubCommands[0])
		if err != nil {
			s.debugLog("test -eq exec command error: %v", err)
		}
		expected := strings.TrimSpace(cmd.Args["left"])
		actual := strings.TrimSpace(output.String())

		if flag == "-eq" {
			if expected != actual {
				return Err("expected '%v', but was '%v'", expected, actual)
			}
		} else if flag == "-neq" {
			if expected == actual {
				return Err("expected different with '%v'", expected)
			}
		} else if flag == "-in" {
                  return strings.contains(expected, actual);
                } else if flag == "-nin" {
                  return !strings.contains(expected, actual);
                }
		return nil
	}

	targetPath := filepath.Join(s.wd, cmd.Args["left"])
	info, err := os.Stat(targetPath)
	switch flag {
	case "-d":
		if err != nil {
			return err
		}
		if info.IsDir() {
			return nil
		} else {
			return Err("%v is not a directory", targetPath)
		}
	case "-nd":
		if err != nil {
			if os.IsNotExist(err) {
				return nil
			}
			return err
		}
		if info.IsDir() {
			return Err("%v is a directory", targetPath)
		} else {
			return nil
		}
	case "-f":
		if err != nil {
			return err
		}
		if info.IsDir() {
			return Err("%v is not a file", targetPath)
		} else {
			return nil
		}
	case "-nf":
		if err != nil {
			if os.IsNotExist(err) {
				return nil
			}
			return err
		}
		if info.IsDir() {
			return nil
		} else {
			return Err("%v is a file", targetPath)
		}
	}

	return Err("unknown test flag: %v", flag)
}
<|endoftext|>


<commit_before>package handlers

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

	"github.com/cloudfoundry-samples/test-app/helpers"
)

type Hello struct {
	Time time.Time
}

func (p *Hello) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	index, _ := helpers.FetchIndex()

	styledTemplate.Execute(w, Body{Body: fmt.Sprintf(`

	InnovAtos 2018

My Index Is

%d

Uptime: %s

    `, index, time.Since(p.Time))})
}
<commit_msg>Update hello.go<commit_after>package handlers

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

	"github.com/cloudfoundry-samples/test-app/helpers"
)

type Hello struct {
	Time time.Time
}

func (p *Hello) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	index, _ := helpers.FetchIndex()

	styledTemplate.Execute(w, Body{Body: fmt.Sprintf(`

	InnovAtos 2016
  http://innovatos.hopto.org

My Index Is

%d

Uptime: %s

    `, index, time.Since(p.Time))})
}
<|endoftext|>


<commit_before>package haproxy

import (
	"log"
	"os"
	"os/exec"
	"strconv"
	"sync"
	"time"
)

type Event int
type Action int

const (
	HasStarted Event = 1 << iota
	HasStopped
	HasReloaded
)

const (
	WantsReload Action = 1 << iota
	WantsStop
)

type Server struct {
	Socket     string
	ActionChan chan Action
	cmd        *exec.Cmd
	sync.RWMutex
}

const BinaryPath = "/usr/local/bin/haproxy"

func (h *Server) createProcess() {
	h.cmd = exec.Command(BinaryPath, "-f", "config/haproxy.conf")
}

func (h *Server) setupStdout() {
	h.cmd.Stdout = os.Stdout
	h.cmd.Stderr = os.Stderr
}

func (h *Server) runProcess() error {
	return h.cmd.Start()
}

func (h *Server) Start(notify chan Event, action chan Action) {
	h.Lock()
	h.createProcess()
	h.setupStdout()

	err := h.runProcess()

	if err != nil {
		log.Fatal(err)
	}

	h.ActionChan = action
	h.Unlock()

	notify <- HasStarted

	// Wait for a stop signal, reload signal, or process death
	for {
		switch <-action {
		case WantsReload:
			h.reloadProcess()
			notify <- HasReloaded
		case WantsStop:
			h.stopProcess()
			notify <- HasStopped
			return
		}
	}
}

func (h *Server) reloadProcess() error {

	h.Lock()

	// Grab pid of current running process
	old := h.cmd
	pid := strconv.Itoa(h.cmd.Process.Pid)

	// Start a new process, telling it to replace the old process
	// This will signal the current process and tell it shutdown, which is why
	// we don't need to do it here.
	cmd := exec.Command("/usr/local/bin/haproxy", "-f", "config/haproxy.conf", "-sf", pid)

	// Start the new process and check for errors. We bail out if there is
	// an error and DON'T replace the old process.
	err := cmd.Start()

	if err != nil {
		return err
	}

	// No errors? Replace the old process
	h.cmd = cmd
	h.finishOrKill(10*time.Second, old)

	return nil
}

func (h *Server) finishOrKill(waitFor time.Duration, old *exec.Cmd) {
	// Create a channel and wait for the old process
	// to finish itself
	didFinish := make(chan error, 1)
	go func() {
		didFinish <- old.Wait()
	}()

	// Wait for the didFinish channel or force kill the process
	// if it takes longer than 10 seconds
	select {
	case <-time.After(waitFor):
		log.Println("manually killing process")
		if err := old.Process.Kill(); err != nil {
			log.Println("failed to kill ", err)
		}
	case err := <-didFinish:
		if err != nil {
			log.Println("process finished with error", err)
		}
	}
}

func (h *Server) stopProcess() error {
	return h.cmd.Process.Kill()
}
<commit_msg>treat constants appropriately<commit_after>package haproxy

import (
	"log"
	"os"
	"os/exec"
	"strconv"
	"sync"
	"time"
)

type Event int
type Action int

const (
	HasStarted Event = 1 << iota
	HasStopped
	HasReloaded
)

const (
	WantsReload Action = 1 << iota
	WantsStop
)

type Server struct {
	Socket     string
	ActionChan chan Action
	cmd        *exec.Cmd
	sync.RWMutex
}

const BINARYPATH = "/usr/local/bin/haproxy"

func (h *Server) createProcess() {
	h.cmd = exec.Command(BINARYPATH, "-f", "config/haproxy.conf")
}

func (h *Server) setupStdout() {
	h.cmd.Stdout = os.Stdout
	h.cmd.Stderr = os.Stderr
}

func (h *Server) runProcess() error {
	return h.cmd.Start()
}

func (h *Server) Start(notify chan Event, action chan Action) {
	h.Lock()
	h.createProcess()
	h.setupStdout()

	err := h.runProcess()

	if err != nil {
		log.Fatal(err)
	}

	h.ActionChan = action
	h.Unlock()

	notify <- HasStarted

	// Wait for a stop signal, reload signal, or process death
	for {
		switch <-action {
		case WantsReload:
			h.reloadProcess()
			notify <- HasReloaded
		case WantsStop:
			h.stopProcess()
			notify <- HasStopped
			return
		}
	}
}

func (h *Server) reloadProcess() error {

	h.Lock()

	// Grab pid of current running process
	old := h.cmd
	pid := strconv.Itoa(h.cmd.Process.Pid)

	// Start a new process, telling it to replace the old process
	// This will signal the current process and tell it shutdown, which is why
	// we don't need to do it here.
	cmd := exec.Command(BINARYPATH, "-f", "config/haproxy.conf", "-sf", pid)

	// Start the new process and check for errors. We bail out if there is
	// an error and DON'T replace the old process.
	err := cmd.Start()

	if err != nil {
		return err
	}

	// No errors? Replace the old process
	h.cmd = cmd
	h.finishOrKill(10*time.Second, old)

	return nil
}

func (h *Server) finishOrKill(waitFor time.Duration, old *exec.Cmd) {
	// Create a channel and wait for the old process
	// to finish itself
	didFinish := make(chan error, 1)
	go func() {
		didFinish <- old.Wait()
	}()

	// Wait for the didFinish channel or force kill the process
	// if it takes longer than 10 seconds
	select {
	case <-time.After(waitFor):
		log.Println("manually killing process")
		if err := old.Process.Kill(); err != nil {
			log.Println("failed to kill ", err)
		}
	case err := <-didFinish:
		if err != nil {
			log.Println("process finished with error", err)
		}
	}
}

func (h *Server) stopProcess() error {
	return h.cmd.Process.Kill()
}
<|endoftext|>


<commit_before>package installer

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"strings"

	"github.com/tsuru/tsuru-client/tsuru/installer/dm"
)

var defaultCompose = `
version: "3"

services:
  redis:
    image: redis:latest
    networks:
      - tsuru

  mongo:
    image: mongo:latest
    networks:
      - tsuru

  planb:
    image: tsuru/planb:latest
    command: --listen :8080 --read-redis-host redis --write-redis-host redis
    ports:
      - 80:8080
    networks:
      - tsuru

  registry:
    image: registry:2
    environment:
      - "REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY=/var/lib/registry"
      - "REGISTRY_HTTP_TLS_CERTIFICATE=/certs/{{CLUSTER_ADDR}}:5000/registry-cert.pem"
      - "REGISTRY_HTTP_TLS_KEY=/certs/{{CLUSTER_ADDR}}:5000/registry-key.pem"
    volumes:
      - "/var/lib/registry:/var/lib/registry"
      - "/etc/docker/certs.d:/certs:ro"
    ports:
      - 5000:5000
    networks:
      - tsuru

  tsuru:
    image: tsuru/api:v1
    volumes:
      - "/etc/docker/certs.d:/certs:ro"
    ports:
      - 8080:8080
    networks:
      - tsuru
    environment:
      - MONGODB_ADDR=mongo
      - MONGODB_PORT=27017
      - REDIS_ADDR=redis
      - REDIS_PORT=6379
      - HIPACHE_DOMAIN={{CLUSTER_ADDR}}.nip.io
      - REGISTRY_ADDR={{CLUSTER_PRIVATE_ADDR}}
      - REGISTRY_PORT=5000
      - TSURU_ADDR=http://{{CLUSTER_ADDR}}
      - TSURU_PORT=8080
      - IAAS_CONF={{IAAS_CONF}}

networks:
  tsuru:
    driver: overlay
    ipam:
      driver: default
      config:
        - subnet: 10.0.9.0/24
`

func resolveConfig(baseConfig string, customConfigs map[string]string) (string, error) {
	if baseConfig == "" {
		baseConfig = defaultCompose
	} else {
		b, err := ioutil.ReadFile(baseConfig)
		if err != nil {
			return "", err
		}
		baseConfig = string(b)
	}
	for k, v := range customConfigs {
		if v != "" {
			baseConfig = strings.Replace(baseConfig, fmt.Sprintf("{{%s}}", k), v, -1)
		}
	}
	return baseConfig, nil
}

func composeDeploy(c ServiceCluster, installConfig *InstallOpts) error {
	componentsConfig := installConfig.ComponentsConfig
	manager := c.GetManager()
	componentsConfig.IaaSConfig.Dockermachine.InsecureRegistry = fmt.Sprintf("%s:5000", dm.GetPrivateIP(manager))
	iaasConfig, err := json.Marshal(componentsConfig.IaaSConfig)
	if err != nil {
		return fmt.Errorf("failed to marshal iaas config: %s", err)
	}
	configs := map[string]string{
		"CLUSTER_ADDR":         manager.Base.Address,
		"CLUSTER_PRIVATE_ADDR": dm.GetPrivateIP(manager),
		"IAAS_CONF":            string(iaasConfig),
	}
	config, err := resolveConfig(installConfig.ComposeFile, configs)
	if err != nil {
		return err
	}
	remoteWriteCmdFmt := "printf '%%s' '%s' | sudo tee %s"
	_, err = manager.Host.RunSSHCommand(fmt.Sprintf(remoteWriteCmdFmt, config, "/tmp/compose.yml"))
	if err != nil {
		return fmt.Errorf("failed to write remote file: %s", err)
	}
	fmt.Printf("Deploying compose file in cluster manager....\n")
	output, err := manager.Host.RunSSHCommand("sudo docker deploy -c /tmp/compose.yml tsuru")
	if err != nil {
		return err
	}
	fmt.Printf(output)
	return nil
}
<commit_msg>installer/compose: use named volumes<commit_after>package installer

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"strings"

	"github.com/tsuru/tsuru-client/tsuru/installer/dm"
)

var defaultCompose = `
version: "3"

services:
  redis:
    image: redis:latest
    networks:
      - tsuru
    volumes:
      - redis-data:/data/db

  mongo:
    image: mongo:latest
    networks:
      - tsuru
    volumes:
      - mongo-data:/data

  planb:
    image: tsuru/planb:latest
    command: --listen :8080 --read-redis-host redis --write-redis-host redis
    ports:
      - 80:8080
    networks:
      - tsuru
    depends_on:
      - redis

  registry:
    image: registry:2
    environment:
      - "REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY=/var/lib/registry"
      - "REGISTRY_HTTP_TLS_CERTIFICATE=/certs/{{CLUSTER_ADDR}}:5000/registry-cert.pem"
      - "REGISTRY_HTTP_TLS_KEY=/certs/{{CLUSTER_ADDR}}:5000/registry-key.pem"
    volumes:
      - "/var/lib/registry:/var/lib/registry"
      - "/etc/docker/certs.d:/certs:ro"
      - registry-data:/var/lib/registry
    ports:
      - 5000:5000
    networks:
      - tsuru

  tsuru:
    image: tsuru/api:v1
    volumes:
      - "/etc/docker/certs.d:/certs:ro"
    ports:
      - 8080:8080
    networks:
      - tsuru
    depends_on:
      - redis
      - mongo
      - registry
      - planb
    environment:
      - MONGODB_ADDR=mongo
      - MONGODB_PORT=27017
      - REDIS_ADDR=redis
      - REDIS_PORT=6379
      - HIPACHE_DOMAIN={{CLUSTER_ADDR}}.nip.io
      - REGISTRY_ADDR={{CLUSTER_PRIVATE_ADDR}}
      - REGISTRY_PORT=5000
      - TSURU_ADDR=http://{{CLUSTER_ADDR}}
      - TSURU_PORT=8080
      - IAAS_CONF={{IAAS_CONF}}

networks:
  tsuru:
    driver: overlay
    ipam:
      driver: default
      config:
        - subnet: 10.0.9.0/24

volumes:
  mongo-data:
  redis-data:
  registry-data:
`

func resolveConfig(baseConfig string, customConfigs map[string]string) (string, error) {
	if baseConfig == "" {
		baseConfig = defaultCompose
	} else {
		b, err := ioutil.ReadFile(baseConfig)
		if err != nil {
			return "", err
		}
		baseConfig = string(b)
	}
	for k, v := range customConfigs {
		if v != "" {
			baseConfig = strings.Replace(baseConfig, fmt.Sprintf("{{%s}}", k), v, -1)
		}
	}
	return baseConfig, nil
}

func composeDeploy(c ServiceCluster, installConfig *InstallOpts) error {
	componentsConfig := installConfig.ComponentsConfig
	manager := c.GetManager()
	componentsConfig.IaaSConfig.Dockermachine.InsecureRegistry = fmt.Sprintf("%s:5000", dm.GetPrivateIP(manager))
	iaasConfig, err := json.Marshal(componentsConfig.IaaSConfig)
	if err != nil {
		return fmt.Errorf("failed to marshal iaas config: %s", err)
	}
	configs := map[string]string{
		"CLUSTER_ADDR":         manager.Base.Address,
		"CLUSTER_PRIVATE_ADDR": dm.GetPrivateIP(manager),
		"IAAS_CONF":            string(iaasConfig),
	}
	config, err := resolveConfig(installConfig.ComposeFile, configs)
	if err != nil {
		return err
	}
	remoteWriteCmdFmt := "printf '%%s' '%s' | sudo tee %s"
	_, err = manager.Host.RunSSHCommand(fmt.Sprintf(remoteWriteCmdFmt, config, "/tmp/compose.yml"))
	if err != nil {
		return fmt.Errorf("failed to write remote file: %s", err)
	}
	fmt.Printf("Deploying compose file in cluster manager....\n")
	output, err := manager.Host.RunSSHCommand("sudo docker deploy -c /tmp/compose.yml tsuru")
	if err != nil {
		return err
	}
	fmt.Printf(output)
	return nil
}
<|endoftext|>


<commit_before>package audio

import "time"

type Ctrl struct {
	Streamer Streamer
	Paused   bool
	Duration time.Duration
}

func (c *Ctrl) Stream(samples [][2]float64) (n int, ok bool) {
	if c.Streamer == nil {
		return 0, false
	}
	if c.Paused {
		for i := range samples {
			samples[i] = [2]float64{}
		}
		return len(samples), true
	}
	n, ok = c.Streamer.Stream(samples)
	c.Duration += time.Duration(n) * time.Second / time.Duration(SampleRate)
	return n, ok
}
<commit_msg>audio: rename Ctrl.Duration -> Ctrl.Position<commit_after>package audio

import "time"

type Ctrl struct {
	Streamer Streamer
	Paused   bool
	Position time.Duration
}

func (c *Ctrl) Stream(samples [][2]float64) (n int, ok bool) {
	if c.Streamer == nil {
		return 0, false
	}
	if c.Paused {
		for i := range samples {
			samples[i] = [2]float64{}
		}
		return len(samples), true
	}
	n, ok = c.Streamer.Stream(samples)
	c.Position += time.Duration(n) * time.Second / time.Duration(SampleRate)
	return n, ok
}
<|endoftext|>


<commit_before>// Copyright 2016 Factom Foundation
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.

package wallet

import (
	"encoding/hex"
	"errors"
	"fmt"
	"regexp"

	"github.com/FactomProject/btcutil/base58"
	"github.com/FactomProject/factom"
	"github.com/FactomProject/factomd/common/factoid"
	"github.com/FactomProject/factomd/common/interfaces"
	"github.com/FactomProject/factomd/common/primitives"
	"github.com/FactomProject/goleveldb/leveldb"
)

var (
	ErrNoSuchAddress = errors.New("wallet: No such address")
	ErrTXExists      = errors.New("wallet: Transaction name already exists")
	ErrTXNotExists   = errors.New("wallet: Transaction name was not found")
	ErrTXInvalidName = errors.New("wallet: Transaction name is not valid")
)

func (w *Wallet) NewTransaction(name string) error {
	if _, exist := w.transactions[name]; exist {
		return ErrTXExists
	}

	// check that the transaction name is valid
	if name == "" {
		return ErrTXInvalidName
	}
	if len(name) > 32 {
		return ErrTXInvalidName
	}
	if match, err := regexp.MatchString("[^a-zA-Z0-9_-]", name); err != nil {
		return err
	} else if match {
		return ErrTXInvalidName
	}

	t := new(factoid.Transaction)
	t.SetTimestamp(*interfaces.NewTimestampNow())
	w.transactions[name] = t
	return nil
}

func (w *Wallet) DeleteTransaction(name string) error {
	if _, exists := w.transactions[name]; !exists {
		return ErrTXNotExists
	}
	delete(w.transactions, name)
	return nil
}

func (w *Wallet) AddInput(name, address string, amount uint64) error {
	if _, exists := w.transactions[name]; !exists {
		return ErrTXNotExists
	}
	trans := w.transactions[name]

	a, err := w.GetFCTAddress(address)
	if err == leveldb.ErrNotFound {
		return ErrNoSuchAddress
	} else if err != nil {
		return err
	}
	adr := factoid.NewAddress(a.RCDHash())

	// First look if this is really an update
	for _, input := range trans.GetInputs() {
		if input.GetAddress().IsSameAs(adr) {
			input.SetAmount(amount)
			return nil
		}
	}

	// Add our new input
	trans.AddInput(adr, amount)
	trans.AddRCD(factoid.NewRCD_1(a.PubBytes()))

	return nil
}

func (w *Wallet) AddOutput(name, address string, amount uint64) error {
	if _, exists := w.transactions[name]; !exists {
		return ErrTXNotExists
	}
	trans := w.transactions[name]

	if !factom.IsValidAddress(address) {
		return errors.New("Invalid Address")
	}

	adr := factoid.NewAddress(base58.Decode(address)[2:34])

	trans.AddOutput(adr, amount)

	return nil
}

func (w *Wallet) AddECOutput(name, address string, amount uint64) error {
	if _, exists := w.transactions[name]; !exists {
		return ErrTXNotExists
	}
	trans := w.transactions[name]

	if !factom.IsValidAddress(address) {
		return errors.New("Invalid Address")
	}

	adr := factoid.NewAddress(base58.Decode(address)[2:34])

	trans.AddECOutput(adr, amount)

	return nil
}

func (w *Wallet) AddFee(name, address string, rate uint64) error {
	if _, exists := w.transactions[name]; !exists {
		return ErrTXNotExists
	}
	trans := w.transactions[name]

	{
		ins, err := trans.TotalInputs()
		if err != nil {
			return err
		}
		outs, err := trans.TotalOutputs()
		if err != nil {
			return err
		}
		ecs, err := trans.TotalECs()
		if err != nil {
			return err
		}

		if ins != outs+ecs {
			return fmt.Errorf("Inputs and outputs don't add up")
		}
	}

	transfee, err := trans.CalculateFee(rate)
	if err != nil {
		return err
	}

	a, err := w.GetFCTAddress(address)
	if err != nil {
		return err
	}
	adr := factoid.NewAddress(a.RCDHash())

	for _, input := range trans.GetInputs() {
		if input.GetAddress().IsSameAs(adr) {
			amt, err := factoid.ValidateAmounts(input.GetAmount(), transfee)
			if err != nil {
				return err
			}
			input.SetAmount(amt)
			return nil
		}
	}
	return fmt.Errorf("%s is not an input to the transaction.", address)
}

func (w *Wallet) SubFee(name, address string, rate uint64) error {
	if _, exists := w.transactions[name]; !exists {
		return ErrTXNotExists
	}
	trans := w.transactions[name]

	if !factom.IsValidAddress(address) {
		return errors.New("Invalid Address")
	}

	{
		ins, err := trans.TotalInputs()
		if err != nil {
			return err
		}
		outs, err := trans.TotalOutputs()
		if err != nil {
			return err
		}
		ecs, err := trans.TotalECs()
		if err != nil {
			return err
		}

		if ins != outs+ecs {
			return fmt.Errorf("Inputs and outputs don't add up")
		}
	}

	transfee, err := trans.CalculateFee(rate)
	if err != nil {
		return err
	}

	adr := factoid.NewAddress(base58.Decode(address)[2:34])

	for _, output := range trans.GetOutputs() {
		if output.GetAddress().IsSameAs(adr) {
			output.SetAmount(output.GetAmount() - transfee)
			return nil
		}
	}
	return fmt.Errorf("%s is not an output to the transaction.", address)
}

func (w *Wallet) SignTransaction(name string) error {
	if _, exists := w.transactions[name]; !exists {
		return ErrTXNotExists
	}
	trans := w.transactions[name]

	data, err := trans.MarshalBinarySig()
	if err != nil {
		return err
	}

	for i, rcd := range trans.GetRCDs() {
		a, err := rcd.GetAddress()
		if err != nil {
			return err
		}

		f, err := w.GetFCTAddress(primitives.ConvertFctAddressToUserStr(a))
		if err != nil {
			return err
		}
		sig := factoid.NewSingleSignatureBlock(f.SecBytes(), data)
		trans.SetSignatureBlock(i, sig)
	}

	return nil
}

func (w *Wallet) GetTransactions() map[string]*factoid.Transaction {
	return w.transactions
}

func (w *Wallet) ComposeTransaction(name string) (*factom.JSON2Request, error) {
	if _, exists := w.transactions[name]; !exists {
		return nil, ErrTXNotExists
	}
	trans := w.transactions[name]

	type txreq struct {
		Transaction string `json:"transaction"`
	}

	param := new(txreq)
	if p, err := trans.MarshalBinary(); err != nil {
		return nil, err
	} else {
		param.Transaction = hex.EncodeToString(p)
	}

	req := factom.NewJSON2Request("factoid-submit", apiCounter(), param)

	return req, nil
}
<commit_msg>update for timestamp refactor<commit_after>// Copyright 2016 Factom Foundation
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.

package wallet

import (
	"encoding/hex"
	"errors"
	"fmt"
	"regexp"

	"github.com/FactomProject/btcutil/base58"
	"github.com/FactomProject/factom"
	"github.com/FactomProject/factomd/common/factoid"
	"github.com/FactomProject/factomd/common/primitives"
	"github.com/FactomProject/goleveldb/leveldb"
)

var (
	ErrNoSuchAddress = errors.New("wallet: No such address")
	ErrTXExists      = errors.New("wallet: Transaction name already exists")
	ErrTXNotExists   = errors.New("wallet: Transaction name was not found")
	ErrTXInvalidName = errors.New("wallet: Transaction name is not valid")
)

func (w *Wallet) NewTransaction(name string) error {
	if _, exist := w.transactions[name]; exist {
		return ErrTXExists
	}

	// check that the transaction name is valid
	if name == "" {
		return ErrTXInvalidName
	}
	if len(name) > 32 {
		return ErrTXInvalidName
	}
	if match, err := regexp.MatchString("[^a-zA-Z0-9_-]", name); err != nil {
		return err
	} else if match {
		return ErrTXInvalidName
	}

	t := new(factoid.Transaction)
	t.SetTimestamp(primitives.NewTimestampNow())
	w.transactions[name] = t
	return nil
}

func (w *Wallet) DeleteTransaction(name string) error {
	if _, exists := w.transactions[name]; !exists {
		return ErrTXNotExists
	}
	delete(w.transactions, name)
	return nil
}

func (w *Wallet) AddInput(name, address string, amount uint64) error {
	if _, exists := w.transactions[name]; !exists {
		return ErrTXNotExists
	}
	trans := w.transactions[name]

	a, err := w.GetFCTAddress(address)
	if err == leveldb.ErrNotFound {
		return ErrNoSuchAddress
	} else if err != nil {
		return err
	}
	adr := factoid.NewAddress(a.RCDHash())

	// First look if this is really an update
	for _, input := range trans.GetInputs() {
		if input.GetAddress().IsSameAs(adr) {
			input.SetAmount(amount)
			return nil
		}
	}

	// Add our new input
	trans.AddInput(adr, amount)
	trans.AddRCD(factoid.NewRCD_1(a.PubBytes()))

	return nil
}

func (w *Wallet) AddOutput(name, address string, amount uint64) error {
	if _, exists := w.transactions[name]; !exists {
		return ErrTXNotExists
	}
	trans := w.transactions[name]

	if !factom.IsValidAddress(address) {
		return errors.New("Invalid Address")
	}

	adr := factoid.NewAddress(base58.Decode(address)[2:34])

	trans.AddOutput(adr, amount)

	return nil
}

func (w *Wallet) AddECOutput(name, address string, amount uint64) error {
	if _, exists := w.transactions[name]; !exists {
		return ErrTXNotExists
	}
	trans := w.transactions[name]

	if !factom.IsValidAddress(address) {
		return errors.New("Invalid Address")
	}

	adr := factoid.NewAddress(base58.Decode(address)[2:34])

	trans.AddECOutput(adr, amount)

	return nil
}

func (w *Wallet) AddFee(name, address string, rate uint64) error {
	if _, exists := w.transactions[name]; !exists {
		return ErrTXNotExists
	}
	trans := w.transactions[name]

	{
		ins, err := trans.TotalInputs()
		if err != nil {
			return err
		}
		outs, err := trans.TotalOutputs()
		if err != nil {
			return err
		}
		ecs, err := trans.TotalECs()
		if err != nil {
			return err
		}

		if ins != outs+ecs {
			return fmt.Errorf("Inputs and outputs don't add up")
		}
	}

	transfee, err := trans.CalculateFee(rate)
	if err != nil {
		return err
	}

	a, err := w.GetFCTAddress(address)
	if err != nil {
		return err
	}
	adr := factoid.NewAddress(a.RCDHash())

	for _, input := range trans.GetInputs() {
		if input.GetAddress().IsSameAs(adr) {
			amt, err := factoid.ValidateAmounts(input.GetAmount(), transfee)
			if err != nil {
				return err
			}
			input.SetAmount(amt)
			return nil
		}
	}
	return fmt.Errorf("%s is not an input to the transaction.", address)
}

func (w *Wallet) SubFee(name, address string, rate uint64) error {
	if _, exists := w.transactions[name]; !exists {
		return ErrTXNotExists
	}
	trans := w.transactions[name]

	if !factom.IsValidAddress(address) {
		return errors.New("Invalid Address")
	}

	{
		ins, err := trans.TotalInputs()
		if err != nil {
			return err
		}
		outs, err := trans.TotalOutputs()
		if err != nil {
			return err
		}
		ecs, err := trans.TotalECs()
		if err != nil {
			return err
		}

		if ins != outs+ecs {
			return fmt.Errorf("Inputs and outputs don't add up")
		}
	}

	transfee, err := trans.CalculateFee(rate)
	if err != nil {
		return err
	}

	adr := factoid.NewAddress(base58.Decode(address)[2:34])

	for _, output := range trans.GetOutputs() {
		if output.GetAddress().IsSameAs(adr) {
			output.SetAmount(output.GetAmount() - transfee)
			return nil
		}
	}
	return fmt.Errorf("%s is not an output to the transaction.", address)
}

func (w *Wallet) SignTransaction(name string) error {
	if _, exists := w.transactions[name]; !exists {
		return ErrTXNotExists
	}
	trans := w.transactions[name]

	data, err := trans.MarshalBinarySig()
	if err != nil {
		return err
	}

	for i, rcd := range trans.GetRCDs() {
		a, err := rcd.GetAddress()
		if err != nil {
			return err
		}

		f, err := w.GetFCTAddress(primitives.ConvertFctAddressToUserStr(a))
		if err != nil {
			return err
		}
		sig := factoid.NewSingleSignatureBlock(f.SecBytes(), data)
		trans.SetSignatureBlock(i, sig)
	}

	return nil
}

func (w *Wallet) GetTransactions() map[string]*factoid.Transaction {
	return w.transactions
}

func (w *Wallet) ComposeTransaction(name string) (*factom.JSON2Request, error) {
	if _, exists := w.transactions[name]; !exists {
		return nil, ErrTXNotExists
	}
	trans := w.transactions[name]

	type txreq struct {
		Transaction string `json:"transaction"`
	}

	param := new(txreq)
	if p, err := trans.MarshalBinary(); err != nil {
		return nil, err
	} else {
		param.Transaction = hex.EncodeToString(p)
	}

	req := factom.NewJSON2Request("factoid-submit", apiCounter(), param)

	return req, nil
}
<|endoftext|>


<commit_before>package resourceproviders

import (
	"context"
	"fmt"
	"log"
	"strings"
	"sync"

	"github.com/Azure/azure-sdk-for-go/profiles/2017-03-09/resources/mgmt/resources"
)

// DetermineResourceProvidersRequiringRegistration determines which Resource Providers require registration to be able to be used
func DetermineResourceProvidersRequiringRegistration(availableResourceProviders []resources.Provider, requiredResourceProviders map[string]struct{}) map[string]struct{} {
	providers := make(map[string]struct{})

	// filter out any providers already registered and not in the required list.
	for _, p := range availableResourceProviders {
		// Skip it if it's not in the required list.
		if _, ok := requiredResourceProviders[*p.Namespace]; !ok {
			continue
		}

		// If it's in the required list but not registered.
		if strings.ToLower(*p.RegistrationState) != "registered" {
			log.Printf("[DEBUG] Adding provider registration for namespace %s\n", *p.Namespace)
			providers[*p.Namespace] = requiredResourceProviders[*p.Namespace]
		}
	}

	return providers
}

// RegisterForSubscription registers the specified Resource Providers in the current Subscription
func RegisterForSubscription(ctx context.Context, client resources.ProvidersClient, providersToRegister map[string]struct{}) error {
	var err error
	var wg sync.WaitGroup
	wg.Add(len(providersToRegister))

	for providerName := range providersToRegister {
		go func(p string) {
			defer wg.Done()
			log.Printf("[DEBUG] Registering Resource Provider %q with namespace", p)
			if innerErr := registerWithSubscription(ctx, p, client); innerErr != nil {
				err = innerErr
			}
		}(providerName)
	}

	wg.Wait()

	return err
}

func registerWithSubscription(ctx context.Context, providerName string, client resources.ProvidersClient) error {
	if _, err := client.Register(ctx, providerName); err != nil {
		return fmt.Errorf("Cannot register provider %s with Azure Resource Manager: %s.", providerName, err)
	}

	return nil
}
<commit_msg>report all errors in resource providers registration<commit_after>package resourceproviders

import (
	"context"
	"fmt"
	"log"
	"strings"
	"sync"

	"github.com/Azure/azure-sdk-for-go/profiles/2017-03-09/resources/mgmt/resources"
)

// DetermineResourceProvidersRequiringRegistration determines which Resource Providers require registration to be able to be used
func DetermineResourceProvidersRequiringRegistration(availableResourceProviders []resources.Provider, requiredResourceProviders map[string]struct{}) map[string]struct{} {
	providers := make(map[string]struct{})

	// filter out any providers already registered and not in the required list.
	for _, p := range availableResourceProviders {
		// Skip it if it's not in the required list.
		if _, ok := requiredResourceProviders[*p.Namespace]; !ok {
			continue
		}

		// If it's in the required list but not registered.
		if strings.ToLower(*p.RegistrationState) != "registered" {
			log.Printf("[DEBUG] Adding provider registration for namespace %s\n", *p.Namespace)
			providers[*p.Namespace] = requiredResourceProviders[*p.Namespace]
		}
	}

	return providers
}

// RegisterForSubscription registers the specified Resource Providers in the current Subscription
func RegisterForSubscription(ctx context.Context, client resources.ProvidersClient, providersToRegister map[string]struct{}) error {
	var err error
	var failedProviders []string
	var wg sync.WaitGroup
	wg.Add(len(providersToRegister))

	for providerName := range providersToRegister {
		go func(p string) {
			defer wg.Done()
			log.Printf("[DEBUG] Registering Resource Provider %q with namespace", p)
			if innerErr := registerWithSubscription(ctx, p, client); innerErr != nil {
				failedProviders = append(failedProviders, p)
				if err == nil {
					err = innerErr
				} else {
					err = fmt.Errorf("%s\n%s", err, innerErr)
				}
			}
		}(providerName)
	}

	wg.Wait()

	return fmt.Errorf("Cannnot register providers: %s. Errors were: %w", strings.Join(failedProviders, ", "), err)
}

func registerWithSubscription(ctx context.Context, providerName string, client resources.ProvidersClient) error {
	if _, err := client.Register(ctx, providerName); err != nil {
		return fmt.Errorf("Cannot register provider %s with Azure Resource Manager: %s.", providerName, err)
	}

	return nil
}
<|endoftext|>


<commit_before>package resources

import (
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/cloudformation"
	"github.com/rebuy-de/aws-nuke/pkg/types"
)

func init() {
	register("CloudFormationStack", ListCloudFormationStacks)
}

func ListCloudFormationStacks(sess *session.Session) ([]Resource, error) {
	svc := cloudformation.New(sess)

	resp, err := svc.DescribeStacks(nil)
	if err != nil {
		return nil, err
	}

	resources := make([]Resource, 0)
	for _, stack := range resp.Stacks {
		resources = append(resources, &CloudFormationStack{
			svc:   svc,
			stack: stack,
		})
	}
	return resources, nil
}

type CloudFormationStack struct {
	svc   *cloudformation.CloudFormation
	stack *cloudformation.Stack
}

func (cfs *CloudFormationStack) Remove() error {
	_, err := cfs.svc.DeleteStack(&cloudformation.DeleteStackInput{
		StackName: cfs.stack.StackName,
	})
	return err
}

func (cfs *CloudFormationStack) Properties() types.Properties {
	properties := types.NewProperties()
	properties.Set("Name", cfs.stack.StackName)
	for _, tagValue := range cfs.stack.Tags {
		properties.SetTag(tagValue.Key, tagValue.Value)
	}

	return properties
}

func (cfs *CloudFormationStack) String() string {
	return *cfs.stack.StackName
}
<commit_msg>enable paging for CFN stacks<commit_after>package resources

import (
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/cloudformation"
	"github.com/rebuy-de/aws-nuke/pkg/types"
)

func init() {
	register("CloudFormationStack", ListCloudFormationStacks)
}

func ListCloudFormationStacks(sess *session.Session) ([]Resource, error) {
	svc := cloudformation.New(sess)

	params := &cloudformation.DescribeStacksInput{}
	resources := make([]Resource, 0)

	for {
		resp, err := svc.DescribeStacks(params)
		if err != nil {
			return nil, err
		}
		for _, stack := range resp.Stacks {
			resources = append(resources, &CloudFormationStack{
				svc:   svc,
				stack: stack,
			})
		}

		if resp.NextToken == nil {
			break
		}

		params.NextToken = resp.NextToken
	}

	return resources, nil
}

type CloudFormationStack struct {
	svc   *cloudformation.CloudFormation
	stack *cloudformation.Stack
}

func (cfs *CloudFormationStack) Remove() error {
	_, err := cfs.svc.DeleteStack(&cloudformation.DeleteStackInput{
		StackName: cfs.stack.StackName,
	})
	return err
}

func (cfs *CloudFormationStack) Properties() types.Properties {
	properties := types.NewProperties()
	properties.Set("Name", cfs.stack.StackName)
	for _, tagValue := range cfs.stack.Tags {
		properties.SetTag(tagValue.Key, tagValue.Value)
	}

	return properties
}

func (cfs *CloudFormationStack) String() string {
	return *cfs.stack.StackName
}
<|endoftext|>


<commit_before>package heartbeat

import (
	"testing"
	"time"
)

func TestHeartbeat(t *testing.T) {
	d := time.Millisecond * 50
	msg := "Test message"
	fired := false
	cleanup := func() {
		if m := recover(); m != nil {
			fired = true
			if msg != m {
				t.Errorf("Override panic message not set. Expected %s, got %s\n", msg, m)
			}
		}
	}
	h := Heartbeat(d, msg, cleanup)
	time.Sleep(2 * d)
	if !fired {
		t.Errorf("Heartbeat timer didn't fire")
	}
	h = Heartbeat(d, msg, nil)
	tt := time.NewTicker(d / 2)
	i := 0
	for {
		select {
		case <-tt.C:
			i++
			if i < 4 {
				h(false)
			} else if i == 4 {
				h(true)
			} else if i == 10 {
				return
			}
		}
	}
	// check that we can call h(true) multiple times
	h(true)
}

func ExampleHeartbeat_typical() {
	heartbeatExpiration := time.Second * 1
	callback := Heartbeat(heartbeatExpiration, "", nil)
	for i := 0; i < 5; i++ {
		time.Sleep(heartbeatExpiration / 2) // simulate some processing
		callback(false)                     // keep the heartbeat from expiring
	}
	callback(true) // cancel the heartbeat
}

func ExampleHeartbeat_cleanup() {
	heartbeatExpiration := time.Second * 1
	panicMessage := "Sample message"
	heartbeatFired := false
	cleanup := func() {
		if msg := recover(); msg != nil {
			// do whatever cleanup needs to be done for an expired heartbeat
			// msg will be "Sample message"
			heartbeatFired = true
		}
	}
	callback := Heartbeat(heartbeatExpiration, panicMessage, cleanup)
	time.Sleep(heartbeatExpiration * 2) // wait for the heartbeat to expire
	// heartbeatFired == true now
	callback(true) // no need to call this for an expired heartbeat, but it doesn't hurt
}

func ExampleHeartbeat_noCatch() {
	heartbeatExpiration := time.Second * 1
	panicMessage := "Sample message"
	Heartbeat(heartbeatExpiration, panicMessage, nil)
	time.Sleep(heartbeatExpiration * 2) // wait for the heartbeat to expire
	// we'll never get to here, because the heartbeat will have panic()'d
}
<commit_msg>add test for thread-safety<commit_after>package heartbeat

import (
	"sync"
	"testing"
	"time"
)

func TestHeartbeat(t *testing.T) {
	d := time.Millisecond * 50
	msg := "Test message"
	fired := false
	cleanup := func() {
		if m := recover(); m != nil {
			fired = true
			if msg != m {
				t.Errorf("Override panic message not set. Expected %s, got %s\n", msg, m)
			}
		}
	}
	h := Heartbeat(d, msg, cleanup)
	time.Sleep(2 * d)
	if !fired {
		t.Errorf("Heartbeat timer didn't fire")
	}
	h = Heartbeat(d, msg, nil)
	tt := time.NewTicker(d / 2)
	i := 0
	for {
		select {
		case <-tt.C:
			i++
			if i < 4 {
				h(false)
			} else if i == 4 {
				h(true)
			} else if i == 10 {
				return
			}
		}
	}
	// check that we can call h(true) multiple times
	h(true)
}

func TestConcurrentAccess(t *testing.T) {
	hb := Heartbeat(time.Minute, "", nil)
	wg := sync.WaitGroup{}
	for i := 0; i < 10; i++ {
		wg.Add(1)
		go func() {
			for j := 0; j < 10000; j++ {
				hb(false)
			}
			wg.Done()
		}()
	}
	wg.Wait()
}

func ExampleHeartbeat_typical() {
	heartbeatExpiration := time.Second * 1
	callback := Heartbeat(heartbeatExpiration, "", nil)
	for i := 0; i < 5; i++ {
		time.Sleep(heartbeatExpiration / 2) // simulate some processing
		callback(false)                     // keep the heartbeat from expiring
	}
	callback(true) // cancel the heartbeat
}

func ExampleHeartbeat_cleanup() {
	heartbeatExpiration := time.Second * 1
	panicMessage := "Sample message"
	heartbeatFired := false
	cleanup := func() {
		if msg := recover(); msg != nil {
			// do whatever cleanup needs to be done for an expired heartbeat
			// msg will be "Sample message"
			heartbeatFired = true
		}
	}
	callback := Heartbeat(heartbeatExpiration, panicMessage, cleanup)
	time.Sleep(heartbeatExpiration * 2) // wait for the heartbeat to expire
	// heartbeatFired == true now
	callback(true) // no need to call this for an expired heartbeat, but it doesn't hurt
}

func ExampleHeartbeat_noCatch() {
	heartbeatExpiration := time.Second * 1
	panicMessage := "Sample message"
	Heartbeat(heartbeatExpiration, panicMessage, nil)
	time.Sleep(heartbeatExpiration * 2) // wait for the heartbeat to expire
	// we'll never get to here, because the heartbeat will have panic()'d
}
<|endoftext|>


<commit_before>package rules

import (
	"github.com/gophercloud/gophercloud"
	"github.com/gophercloud/gophercloud/pagination"
)

// ListOpts allows the filtering and sorting of paginated collections through
// the API. Filtering is achieved by passing in struct field values that map to
// the security group attributes you want to see returned. SortKey allows you to
// sort by a particular network attribute. SortDir sets the direction, and is
// either `asc' or `desc'. Marker and Limit are used for pagination.
type ListOpts struct {
	Direction      string `q:"direction"`
	EtherType      string `q:"ethertype"`
	ID             string `q:"id"`
	PortRangeMax   int    `q:"port_range_max"`
	PortRangeMin   int    `q:"port_range_min"`
	Protocol       string `q:"protocol"`
	RemoteGroupID  string `q:"remote_group_id"`
	RemoteIPPrefix string `q:"remote_ip_prefix"`
	SecGroupID     string `q:"security_group_id"`
	TenantID       string `q:"tenant_id"`
	Limit          int    `q:"limit"`
	Marker         string `q:"marker"`
	SortKey        string `q:"sort_key"`
	SortDir        string `q:"sort_dir"`
}

// List returns a Pager which allows you to iterate over a collection of
// security group rules. It accepts a ListOpts struct, which allows you to filter
// and sort the returned collection for greater efficiency.
func List(c *gophercloud.ServiceClient, opts ListOpts) pagination.Pager {
	q, err := gophercloud.BuildQueryString(&opts)
	if err != nil {
		return pagination.Pager{Err: err}
	}
	u := rootURL(c) + q.String()
	return pagination.NewPager(c, u, func(r pagination.PageResult) pagination.Page {
		return SecGroupRulePage{pagination.LinkedPageBase{PageResult: r}}
	})
}

type RuleDirection string
type RuleProtocol string
type RuleEtherType string

// Constants useful for CreateOpts
const (
	DirIngress        RuleDirection = "ingress"
	DirEgress         RuleDirection = "egress"
	ProtocolTCP       RuleProtocol  = "tcp"
	ProtocolUDP       RuleProtocol  = "udp"
	ProtocolICMP      RuleProtocol  = "icmp"
	ProtocolAH        RuleProtocol  = "ah"
	ProtocolDCCP      RuleProtocol  = "dccp"
	ProtocolEGP       RuleProtocol  = "egp"
	ProtocolGRE       RuleProtocol  = "gre"
	ProtocolIGMP      RuleProtocol  = "igmp"
	ProtocolIPv6Encap RuleProtocol  = "ipv6-encap"
	ProtocolIPv6Frag  RuleProtocol  = "ipv6-frag"
	ProtocolIPv6ICMP  RuleProtocol  = "ipv6-icmp"
	ProtocolIPv6NoNxt RuleProtocol  = "ipv6-nonxt"
	ProtocolIPv6Opts  RuleProtocol  = "ipv6-opts"
	ProtocolOSPF      RuleProtocol  = "ospf"
	ProtocolPGM       RuleProtocol  = "pgm"
	ProtocolRSVP      RuleProtocol  = "rsvp"
	ProtocolSCTP      RuleProtocol  = "sctp"
	ProtocolUDPLite   RuleProtocol  = "udplite"
	ProtocolVRRP      RuleProtocol  = "vrrp"
	EtherType4        RuleEtherType = "IPv4"
	EtherType6        RuleEtherType = "IPv6"
)

// CreateOptsBuilder is what types must satisfy to be used as Create
// options.
type CreateOptsBuilder interface {
	ToSecGroupRuleCreateMap() (map[string]interface{}, error)
}

// CreateOpts contains all the values needed to create a new security group rule.
type CreateOpts struct {
	// Required. Must be either "ingress" or "egress": the direction in which the
	// security group rule is applied.
	Direction RuleDirection `json:"direction" required:"true"`
	// Required. Must be "IPv4" or "IPv6", and addresses represented in CIDR must
	// match the ingress or egress rules.
	EtherType RuleEtherType `json:"ethertype" required:"true"`
	// Required. The security group ID to associate with this security group rule.
	SecGroupID string `json:"security_group_id" required:"true"`
	// Optional. The maximum port number in the range that is matched by the
	// security group rule. The PortRangeMin attribute constrains the PortRangeMax
	// attribute. If the protocol is ICMP, this value must be an ICMP type.
	PortRangeMax int `json:"port_range_max,omitempty"`
	// Optional. The minimum port number in the range that is matched by the
	// security group rule. If the protocol is TCP or UDP, this value must be
	// less than or equal to the value of the PortRangeMax attribute. If the
	// protocol is ICMP, this value must be an ICMP type.
	PortRangeMin int `json:"port_range_min,omitempty"`
	// Optional. The protocol that is matched by the security group rule. Valid
	// values are "tcp", "udp", "icmp" or an empty string.
	Protocol RuleProtocol `json:"protocol,omitempty"`
	// Optional. The remote group ID to be associated with this security group
	// rule. You can specify either RemoteGroupID or RemoteIPPrefix.
	RemoteGroupID string `json:"remote_group_id,omitempty"`
	// Optional. The remote IP prefix to be associated with this security group
	// rule. You can specify either RemoteGroupID or RemoteIPPrefix. This
	// attribute matches the specified IP prefix as the source IP address of the
	// IP packet.
	RemoteIPPrefix string `json:"remote_ip_prefix,omitempty"`
	// Required for admins. Indicates the owner of the VIP.
	TenantID string `json:"tenant_id,omitempty"`
}

// ToSecGroupRuleCreateMap allows CreateOpts to satisfy the CreateOptsBuilder
// interface
func (opts CreateOpts) ToSecGroupRuleCreateMap() (map[string]interface{}, error) {
	return gophercloud.BuildRequestBody(opts, "security_group_rule")
}

// Create is an operation which adds a new security group rule and associates it
// with an existing security group (whose ID is specified in CreateOpts).
func Create(c *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) {
	b, err := opts.ToSecGroupRuleCreateMap()
	if err != nil {
		r.Err = err
		return
	}
	_, r.Err = c.Post(rootURL(c), b, &r.Body, nil)
	return
}

// Get retrieves a particular security group rule based on its unique ID.
func Get(c *gophercloud.ServiceClient, id string) (r GetResult) {
	_, r.Err = c.Get(resourceURL(c, id), &r.Body, nil)
	return
}

// Delete will permanently delete a particular security group rule based on its unique ID.
func Delete(c *gophercloud.ServiceClient, id string) (r DeleteResult) {
	_, r.Err = c.Delete(resourceURL(c, id), nil)
	return
}
<commit_msg>Add Missing Neutron v2 Protocol Constants<commit_after>package rules

import (
	"github.com/gophercloud/gophercloud"
	"github.com/gophercloud/gophercloud/pagination"
)

// ListOpts allows the filtering and sorting of paginated collections through
// the API. Filtering is achieved by passing in struct field values that map to
// the security group attributes you want to see returned. SortKey allows you to
// sort by a particular network attribute. SortDir sets the direction, and is
// either `asc' or `desc'. Marker and Limit are used for pagination.
type ListOpts struct {
	Direction      string `q:"direction"`
	EtherType      string `q:"ethertype"`
	ID             string `q:"id"`
	PortRangeMax   int    `q:"port_range_max"`
	PortRangeMin   int    `q:"port_range_min"`
	Protocol       string `q:"protocol"`
	RemoteGroupID  string `q:"remote_group_id"`
	RemoteIPPrefix string `q:"remote_ip_prefix"`
	SecGroupID     string `q:"security_group_id"`
	TenantID       string `q:"tenant_id"`
	Limit          int    `q:"limit"`
	Marker         string `q:"marker"`
	SortKey        string `q:"sort_key"`
	SortDir        string `q:"sort_dir"`
}

// List returns a Pager which allows you to iterate over a collection of
// security group rules. It accepts a ListOpts struct, which allows you to filter
// and sort the returned collection for greater efficiency.
func List(c *gophercloud.ServiceClient, opts ListOpts) pagination.Pager {
	q, err := gophercloud.BuildQueryString(&opts)
	if err != nil {
		return pagination.Pager{Err: err}
	}
	u := rootURL(c) + q.String()
	return pagination.NewPager(c, u, func(r pagination.PageResult) pagination.Page {
		return SecGroupRulePage{pagination.LinkedPageBase{PageResult: r}}
	})
}

type RuleDirection string
type RuleProtocol string
type RuleEtherType string

// Constants useful for CreateOpts
const (
	DirIngress        RuleDirection = "ingress"
	DirEgress         RuleDirection = "egress"
	EtherType4        RuleEtherType = "IPv4"
	EtherType6        RuleEtherType = "IPv6"
	ProtocolAH        RuleProtocol  = "ah"
	ProtocolDCCP      RuleProtocol  = "dccp"
	ProtocolEGP       RuleProtocol  = "egp"
	ProtocolESP       RuleProtocol  = "esp"
	ProtocolGRE       RuleProtocol  = "gre"
	ProtocolICMP      RuleProtocol  = "icmp"
	ProtocolIGMP      RuleProtocol  = "igmp"
	ProtocolIPv6Encap RuleProtocol  = "ipv6-encap"
	ProtocolIPv6Frag  RuleProtocol  = "ipv6-frag"
	ProtocolIPv6ICMP  RuleProtocol  = "ipv6-icmp"
	ProtocolIPv6NoNxt RuleProtocol  = "ipv6-nonxt"
	ProtocolIPv6Opts  RuleProtocol  = "ipv6-opts"
	ProtocolIPv6Route RuleProtocol  = "ipv6-route"
	ProtocolOSPF      RuleProtocol  = "ospf"
	ProtocolPGM       RuleProtocol  = "pgm"
	ProtocolRSVP      RuleProtocol  = "rsvp"
	ProtocolSCTP      RuleProtocol  = "sctp"
	ProtocolTCP       RuleProtocol  = "tcp"
	ProtocolUDP       RuleProtocol  = "udp"
	ProtocolUDPLite   RuleProtocol  = "udplite"
	ProtocolVRRP      RuleProtocol  = "vrrp"
)

// CreateOptsBuilder is what types must satisfy to be used as Create
// options.
type CreateOptsBuilder interface {
	ToSecGroupRuleCreateMap() (map[string]interface{}, error)
}

// CreateOpts contains all the values needed to create a new security group rule.
type CreateOpts struct {
	// Required. Must be either "ingress" or "egress": the direction in which the
	// security group rule is applied.
	Direction RuleDirection `json:"direction" required:"true"`
	// Required. Must be "IPv4" or "IPv6", and addresses represented in CIDR must
	// match the ingress or egress rules.
	EtherType RuleEtherType `json:"ethertype" required:"true"`
	// Required. The security group ID to associate with this security group rule.
	SecGroupID string `json:"security_group_id" required:"true"`
	// Optional. The maximum port number in the range that is matched by the
	// security group rule. The PortRangeMin attribute constrains the PortRangeMax
	// attribute. If the protocol is ICMP, this value must be an ICMP type.
	PortRangeMax int `json:"port_range_max,omitempty"`
	// Optional. The minimum port number in the range that is matched by the
	// security group rule. If the protocol is TCP or UDP, this value must be
	// less than or equal to the value of the PortRangeMax attribute. If the
	// protocol is ICMP, this value must be an ICMP type.
	PortRangeMin int `json:"port_range_min,omitempty"`
	// Optional. The protocol that is matched by the security group rule. Valid
	// values are "tcp", "udp", "icmp" or an empty string.
	Protocol RuleProtocol `json:"protocol,omitempty"`
	// Optional. The remote group ID to be associated with this security group
	// rule. You can specify either RemoteGroupID or RemoteIPPrefix.
	RemoteGroupID string `json:"remote_group_id,omitempty"`
	// Optional. The remote IP prefix to be associated with this security group
	// rule. You can specify either RemoteGroupID or RemoteIPPrefix. This
	// attribute matches the specified IP prefix as the source IP address of the
	// IP packet.
	RemoteIPPrefix string `json:"remote_ip_prefix,omitempty"`
	// Required for admins. Indicates the owner of the VIP.
	TenantID string `json:"tenant_id,omitempty"`
}

// ToSecGroupRuleCreateMap allows CreateOpts to satisfy the CreateOptsBuilder
// interface
func (opts CreateOpts) ToSecGroupRuleCreateMap() (map[string]interface{}, error) {
	return gophercloud.BuildRequestBody(opts, "security_group_rule")
}

// Create is an operation which adds a new security group rule and associates it
// with an existing security group (whose ID is specified in CreateOpts).
func Create(c *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) {
	b, err := opts.ToSecGroupRuleCreateMap()
	if err != nil {
		r.Err = err
		return
	}
	_, r.Err = c.Post(rootURL(c), b, &r.Body, nil)
	return
}

// Get retrieves a particular security group rule based on its unique ID.
func Get(c *gophercloud.ServiceClient, id string) (r GetResult) {
	_, r.Err = c.Get(resourceURL(c, id), &r.Body, nil)
	return
}

// Delete will permanently delete a particular security group rule based on its unique ID.
func Delete(c *gophercloud.ServiceClient, id string) (r DeleteResult) {
	_, r.Err = c.Delete(resourceURL(c, id), nil)
	return
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/kr/pty"
	"io"
	"log"
	"net"
	"net/rpc"
	"os"
	"os/exec"
	"sync"
	"time"
	"unicode/utf8"
)

type Console struct {
	file    *os.File
	command *exec.Cmd
}

type LockingConsoles struct {
	mutex sync.RWMutex
	byId  map[int64]Console
}

var consoles *LockingConsoles

func (c *LockingConsoles) deleteConsole(id int64) {
	c.mutex.Lock()
	defer c.mutex.Unlock()
	delete(c.byId, id)
}

func (c *LockingConsoles) addConsole(id int64, console Console) {
	c.mutex.Lock()
	defer c.mutex.Unlock()
	c.byId[id] = console
}

type ConsoleChunk struct {
	Id   int64
	Data []byte
}

var readChannel chan ConsoleChunk

func consoleReadLoop(output *os.File, id int64) {
	for {
		b := make([]byte, 1024)
		_, err := output.Read(b)
		if err == io.EOF {
			return
		}
		if err != nil {
			time.Sleep(100 * time.Millisecond)
			continue
		}
		out := fixUTF(string(b))
		readChannel <- ConsoleChunk{
			Id:   id,
			Data: []byte(out),
		}
	}
}

func fixUTF(s string) string {
	if !utf8.ValidString(s) {
		v := make([]rune, 0, len(s))
		for i, r := range s {
			if r == utf8.RuneError {
				_, size := utf8.DecodeRuneInString(s[i:])
				if size == 1 {
					continue
				}
			}
			v = append(v, r)
		}
		s = string(v)
	}
	return s
}

func consoleWriter(r io.Reader) {
	buffer := bufio.NewReader(r)
	for {
		str, err := buffer.ReadString('\n')
		if err != nil {
			continue
		}
		var chunk ConsoleChunk
		json.Unmarshal([]byte(str), &chunk)
		consoles.mutex.RLock()
		consoles.byId[chunk.Id].file.Write(chunk.Data)
		consoles.mutex.RUnlock()
	}
}

func consoleReader(c net.Conn) {
	for chunk := range readChannel {
		str, _ := json.Marshal(chunk)
		output := string(str) + "\n"
		_, err := c.Write([]byte(output))
		if err != nil {
			log.Println("Write: " + err.Error())
		}
	}
}

//console socket
func consoleListen() {
	l, err := net.Listen("unix", "@/tmp/vzconsole.sock")
	if err != nil {
		fmt.Println("listen error", err.Error())
		return
	}

	for {
		fd, err := l.Accept()
		if err != nil {
			fmt.Println("accept error", err.Error())
			return
		}
		go consoleReader(fd)
		go consoleWriter(fd)

	}
}

//rpc socket
func main() {
	log.Println("Started VZControl")
	consoles = &LockingConsoles{
		byId: make(map[int64]Console),
	}
	readChannel = make(chan ConsoleChunk)
	go consoleListen()
	vz := new(VZControl)
	rpc.Register(vz)
	listener, e := net.Listen("unix", "@/tmp/vzcontrol.sock")
	if e != nil {
		log.Fatal("listen error:", e)
	}

	for {
		if conn, err := listener.Accept(); err != nil {
			log.Fatal("accept error: " + err.Error())
		} else {
			log.Printf("new connection established\n")
			go rpc.ServeConn(conn)
		}
	}
}

type VZControl struct{}

func (vz *VZControl) ContainerCreate(cid int64, reply *int64) error {
	output, err := createContainer(cid)
	if err != nil {
		return errors.New(fmt.Sprintf("Create Error: %s\n Output:%s", err.Error(), output))
	}
	/*output, err = setupMount(cid)
	if err != nil {
		return errors.New(fmt.Sprintf("Mount Error: %s\n Output:%s", err.Error(), output))
	}
	output, err = startContainer(cid)*/
	if err != nil {
		return errors.New(fmt.Sprintf("Start Error: %s\n Output:%s", err.Error(), output))
	}
	reply = &cid
	return nil
}

func (vz *VZControl) ConsoleStart(cid int64, reply *int64) error {
	err := startConsole(cid)
	if err != nil {
		return errors.New(fmt.Sprintf("Console Start Error: %s", err.Error()))
	}
	reply = &cid
	return nil
}

func (vz *VZControl) ConsoleKill(cid int64, reply *int64) error {
	err := killConsole(cid)
	if err != nil {
		return errors.New(fmt.Sprintf("Console Kill Error: %s", err.Error()))
	}
	reply = &cid
	return nil
}

func (vz *VZControl) NetworkCreate(networkid int64, reply *int64) error {
	output, err := addBridge(networkid)
	if err != nil {
		return errors.New(fmt.Sprintf("Create Network Error: %s\n Output:%s", err.Error(), output))
	}
	reply = &networkid
	return nil
}

type NetworkAddArgs struct {
	Id, NetworkId int64
}

func (vz *VZControl) NetworkAdd(args *NetworkAddArgs, reply *int64) error {
	cid := args.Id
	networkid := args.NetworkId
	output, err := addInterface(cid, networkid)
	if err != nil {
		return errors.New(fmt.Sprintf("Interface Add Error: %s\n Output:%s", err.Error(), output))
	}
	output, err = connectBridge(cid, networkid)
	if err != nil {
		return errors.New(fmt.Sprintf("Bridge Connect Error: %s\n Output:%s", err.Error(), output))
	}
	reply = &cid
	return nil
}

func (vz *VZControl) Reset(someid int64, reply *int64) error {
	output, err := resetSystem()
	if err != nil {
		return errors.New(fmt.Sprintf("Reset Error: %s\n Output:%s", err.Error(), output))
	}
	consoles.mutex.RLock()
	consolesCopy := consoles.byId
	consoles.mutex.RUnlock()

	for cid, _ := range consolesCopy {
		killConsole(cid)
	}
	return nil
}

func resetSystem() (string, error) {
	command := exec.Command("./reset.sh")
	output, err := command.CombinedOutput()
	return string(output), err
}

func createContainer(id int64) (string, error) {
	command := exec.Command("vzctl", "create", fmt.Sprintf("%d", id), "--config", "ginux")
	output, err := command.CombinedOutput()
	return string(output), err
}

func setupMount(id int64) (string, error) {
	command := exec.Command("cp", "/etc/vz/conf/ginux.mount", fmt.Sprintf("/etc/vz/conf/%d.mount", id))
	output, err := command.CombinedOutput()
	return string(output), err
}

func startContainer(id int64) (string, error) {
	command := exec.Command("vzctl", "start", fmt.Sprintf("%d", id))
	output, err := command.CombinedOutput()
	return string(output), err
}

func addInterface(id int64, networkid int64) (string, error) {
	command := exec.Command("./addeth.sh", fmt.Sprintf("%d", id), fmt.Sprintf("%d", networkid))
	output, err := command.CombinedOutput()
	return string(output), err
}

func addBridge(networkid int64) (string, error) {
	command := exec.Command("./addbr.sh", fmt.Sprintf("%d", networkid))
	output, err := command.CombinedOutput()
	return string(output), err
}

func connectBridge(id int64, networkid int64) (string, error) {
	command := exec.Command("brctl", "addif", fmt.Sprintf("vzbr%d", networkid), fmt.Sprintf("veth%d.%d", id, networkid))
	output, err := command.CombinedOutput()
	return string(output), err
}

func startConsole(id int64) error {
	consoles.mutex.RLock()
	_, exists := consoles.byId[id]
	consoles.mutex.RUnlock()
	if exists {
		return errors.New(fmt.Sprintf("Console %d already is open", id))
	}
	cmd := exec.Command("vzctl", "console", fmt.Sprintf("%d", id))
	f, err := pty.Start(cmd)
	if err != nil {
		return err
	}
	con := Console{
		file:    f,
		command: cmd,
	}
	consoles.addConsole(id, con)
	go consoleReadLoop(f, id)
	return nil
}

func killConsole(id int64) error {
	consoles.mutex.RLock()
	console, ok := consoles.byId[id]
	consoles.mutex.RUnlock()
	if ok {
		if console.command != nil {
			err_kill := console.command.Process.Kill()
			if err_kill != nil {
				return err_kill
			}
			_, err_wait := console.command.Process.Wait()
			if err_wait != nil {
				return err_wait
			}
		}
	}
	consoles.deleteConsole(id)
	return nil
}
<commit_msg>Commented out too much<commit_after>package main

import (
	"bufio"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/kr/pty"
	"io"
	"log"
	"net"
	"net/rpc"
	"os"
	"os/exec"
	"sync"
	"time"
	"unicode/utf8"
)

type Console struct {
	file    *os.File
	command *exec.Cmd
}

type LockingConsoles struct {
	mutex sync.RWMutex
	byId  map[int64]Console
}

var consoles *LockingConsoles

func (c *LockingConsoles) deleteConsole(id int64) {
	c.mutex.Lock()
	defer c.mutex.Unlock()
	delete(c.byId, id)
}

func (c *LockingConsoles) addConsole(id int64, console Console) {
	c.mutex.Lock()
	defer c.mutex.Unlock()
	c.byId[id] = console
}

type ConsoleChunk struct {
	Id   int64
	Data []byte
}

var readChannel chan ConsoleChunk

func consoleReadLoop(output *os.File, id int64) {
	for {
		b := make([]byte, 1024)
		_, err := output.Read(b)
		if err == io.EOF {
			return
		}
		if err != nil {
			time.Sleep(100 * time.Millisecond)
			continue
		}
		out := fixUTF(string(b))
		readChannel <- ConsoleChunk{
			Id:   id,
			Data: []byte(out),
		}
	}
}

func fixUTF(s string) string {
	if !utf8.ValidString(s) {
		v := make([]rune, 0, len(s))
		for i, r := range s {
			if r == utf8.RuneError {
				_, size := utf8.DecodeRuneInString(s[i:])
				if size == 1 {
					continue
				}
			}
			v = append(v, r)
		}
		s = string(v)
	}
	return s
}

func consoleWriter(r io.Reader) {
	buffer := bufio.NewReader(r)
	for {
		str, err := buffer.ReadString('\n')
		if err != nil {
			continue
		}
		var chunk ConsoleChunk
		json.Unmarshal([]byte(str), &chunk)
		consoles.mutex.RLock()
		consoles.byId[chunk.Id].file.Write(chunk.Data)
		consoles.mutex.RUnlock()
	}
}

func consoleReader(c net.Conn) {
	for chunk := range readChannel {
		str, _ := json.Marshal(chunk)
		output := string(str) + "\n"
		_, err := c.Write([]byte(output))
		if err != nil {
			log.Println("Write: " + err.Error())
		}
	}
}

//console socket
func consoleListen() {
	l, err := net.Listen("unix", "@/tmp/vzconsole.sock")
	if err != nil {
		fmt.Println("listen error", err.Error())
		return
	}

	for {
		fd, err := l.Accept()
		if err != nil {
			fmt.Println("accept error", err.Error())
			return
		}
		go consoleReader(fd)
		go consoleWriter(fd)

	}
}

//rpc socket
func main() {
	log.Println("Started VZControl")
	consoles = &LockingConsoles{
		byId: make(map[int64]Console),
	}
	readChannel = make(chan ConsoleChunk)
	go consoleListen()
	vz := new(VZControl)
	rpc.Register(vz)
	listener, e := net.Listen("unix", "@/tmp/vzcontrol.sock")
	if e != nil {
		log.Fatal("listen error:", e)
	}

	for {
		if conn, err := listener.Accept(); err != nil {
			log.Fatal("accept error: " + err.Error())
		} else {
			log.Printf("new connection established\n")
			go rpc.ServeConn(conn)
		}
	}
}

type VZControl struct{}

func (vz *VZControl) ContainerCreate(cid int64, reply *int64) error {
	output, err := createContainer(cid)
	if err != nil {
		return errors.New(fmt.Sprintf("Create Error: %s\n Output:%s", err.Error(), output))
	}
	/*output, err = setupMount(cid)
	if err != nil {
		return errors.New(fmt.Sprintf("Mount Error: %s\n Output:%s", err.Error(), output))
	}*/
	output, err = startContainer(cid)
	if err != nil {
		return errors.New(fmt.Sprintf("Start Error: %s\n Output:%s", err.Error(), output))
	}
	reply = &cid
	return nil
}

func (vz *VZControl) ConsoleStart(cid int64, reply *int64) error {
	err := startConsole(cid)
	if err != nil {
		return errors.New(fmt.Sprintf("Console Start Error: %s", err.Error()))
	}
	reply = &cid
	return nil
}

func (vz *VZControl) ConsoleKill(cid int64, reply *int64) error {
	err := killConsole(cid)
	if err != nil {
		return errors.New(fmt.Sprintf("Console Kill Error: %s", err.Error()))
	}
	reply = &cid
	return nil
}

func (vz *VZControl) NetworkCreate(networkid int64, reply *int64) error {
	output, err := addBridge(networkid)
	if err != nil {
		return errors.New(fmt.Sprintf("Create Network Error: %s\n Output:%s", err.Error(), output))
	}
	reply = &networkid
	return nil
}

type NetworkAddArgs struct {
	Id, NetworkId int64
}

func (vz *VZControl) NetworkAdd(args *NetworkAddArgs, reply *int64) error {
	cid := args.Id
	networkid := args.NetworkId
	output, err := addInterface(cid, networkid)
	if err != nil {
		return errors.New(fmt.Sprintf("Interface Add Error: %s\n Output:%s", err.Error(), output))
	}
	output, err = connectBridge(cid, networkid)
	if err != nil {
		return errors.New(fmt.Sprintf("Bridge Connect Error: %s\n Output:%s", err.Error(), output))
	}
	reply = &cid
	return nil
}

func (vz *VZControl) Reset(someid int64, reply *int64) error {
	output, err := resetSystem()
	if err != nil {
		return errors.New(fmt.Sprintf("Reset Error: %s\n Output:%s", err.Error(), output))
	}
	consoles.mutex.RLock()
	consolesCopy := consoles.byId
	consoles.mutex.RUnlock()

	for cid, _ := range consolesCopy {
		killConsole(cid)
	}
	return nil
}

func resetSystem() (string, error) {
	command := exec.Command("./reset.sh")
	output, err := command.CombinedOutput()
	return string(output), err
}

func createContainer(id int64) (string, error) {
	command := exec.Command("vzctl", "create", fmt.Sprintf("%d", id), "--config", "ginux")
	output, err := command.CombinedOutput()
	return string(output), err
}

func setupMount(id int64) (string, error) {
	command := exec.Command("cp", "/etc/vz/conf/ginux.mount", fmt.Sprintf("/etc/vz/conf/%d.mount", id))
	output, err := command.CombinedOutput()
	return string(output), err
}

func startContainer(id int64) (string, error) {
	command := exec.Command("vzctl", "start", fmt.Sprintf("%d", id))
	output, err := command.CombinedOutput()
	return string(output), err
}

func addInterface(id int64, networkid int64) (string, error) {
	command := exec.Command("./addeth.sh", fmt.Sprintf("%d", id), fmt.Sprintf("%d", networkid))
	output, err := command.CombinedOutput()
	return string(output), err
}

func addBridge(networkid int64) (string, error) {
	command := exec.Command("./addbr.sh", fmt.Sprintf("%d", networkid))
	output, err := command.CombinedOutput()
	return string(output), err
}

func connectBridge(id int64, networkid int64) (string, error) {
	command := exec.Command("brctl", "addif", fmt.Sprintf("vzbr%d", networkid), fmt.Sprintf("veth%d.%d", id, networkid))
	output, err := command.CombinedOutput()
	return string(output), err
}

func startConsole(id int64) error {
	consoles.mutex.RLock()
	_, exists := consoles.byId[id]
	consoles.mutex.RUnlock()
	if exists {
		return errors.New(fmt.Sprintf("Console %d already is open", id))
	}
	cmd := exec.Command("vzctl", "console", fmt.Sprintf("%d", id))
	f, err := pty.Start(cmd)
	if err != nil {
		return err
	}
	con := Console{
		file:    f,
		command: cmd,
	}
	consoles.addConsole(id, con)
	go consoleReadLoop(f, id)
	return nil
}

func killConsole(id int64) error {
	consoles.mutex.RLock()
	console, ok := consoles.byId[id]
	consoles.mutex.RUnlock()
	if ok {
		if console.command != nil {
			err_kill := console.command.Process.Kill()
			if err_kill != nil {
				return err_kill
			}
			_, err_wait := console.command.Process.Wait()
			if err_wait != nil {
				return err_wait
			}
		}
	}
	consoles.deleteConsole(id)
	return nil
}
<|endoftext|>


<commit_before>package uploadService

import (
	"strings"
)

func CheckTrackers(trackers []string) bool {
	// TODO: move to runtime configuration
	var deadTrackers = []string{ // substring matches!
		"://open.nyaatorrents.info:6544",
		"://tracker.openbittorrent.com:80",
		"://tracker.publicbt.com:80",
		"://stats.anisource.net:2710",
		"://exodus.desync.com",
		"://open.demonii.com:1337",
		"://tracker.istole.it:80",
		"://tracker.ccc.de:80",
		"://bt2.careland.com.cn:6969",
		"://announce.torrentsmd.com:8080"}

	var numGood int
	for _, t := range trackers {
		good := true
		for _, check := range deadTrackers {
			if strings.Contains(t, check) {
				good = false
			}
		}
		if good {
			numGood++
		}
	}
	return numGood > 0
}
<commit_msg>Update list of dead trackers<commit_after>package uploadService

import (
	"strings"
)

func CheckTrackers(trackers []string) bool {
	// TODO: move to runtime configuration
	var deadTrackers = []string{ // substring matches!
		"://open.nyaatorrents.info:6544",
		"://tracker.openbittorrent.com:80",
		"://tracker.publicbt.com:80",
		"://stats.anisource.net:2710",
		"://exodus.desync.com",
		"://open.demonii.com:1337",
		"://tracker.istole.it:80",
		"://tracker.ccc.de:80",
		"://bt2.careland.com.cn:6969",
		"://announce.torrentsmd.com:8080",
		"://open.demonii.com:1337",
		"://tracker.btcake.com",
		"://tracker.prq.to",
		"://bt.rghost.net"}

	var numGood int
	for _, t := range trackers {
		good := true
		for _, check := range deadTrackers {
			if strings.Contains(t, check) {
				good = false
			}
		}
		if good {
			numGood++
		}
	}
	return numGood > 0
}
<|endoftext|>


<commit_before>package operation

import (
	"context"
	"fmt"
	"github.com/chrislusf/seaweedfs/weed/pb"
	"github.com/chrislusf/seaweedfs/weed/storage/needle"
	"google.golang.org/grpc"

	"github.com/chrislusf/seaweedfs/weed/pb/master_pb"
	"github.com/chrislusf/seaweedfs/weed/security"
)

type VolumeAssignRequest struct {
	Count               uint64
	Replication         string
	Collection          string
	Ttl                 string
	DiskType            string
	DataCenter          string
	Rack                string
	DataNode            string
	WritableVolumeCount uint32
}

type AssignResult struct {
	Fid       string              `json:"fid,omitempty"`
	Url       string              `json:"url,omitempty"`
	PublicUrl string              `json:"publicUrl,omitempty"`
	GrpcPort  int                 `json:"grpcPort,omitempty"`
	Count     uint64              `json:"count,omitempty"`
	Error     string              `json:"error,omitempty"`
	Auth      security.EncodedJwt `json:"auth,omitempty"`
	Replicas  []Location          `json:"replicas,omitempty"`
}

func Assign(masterFn GetMasterFn, grpcDialOption grpc.DialOption, primaryRequest *VolumeAssignRequest, alternativeRequests ...*VolumeAssignRequest) (*AssignResult, error) {

	var requests []*VolumeAssignRequest
	requests = append(requests, primaryRequest)
	requests = append(requests, alternativeRequests...)

	var lastError error
	ret := &AssignResult{}

	for i, request := range requests {
		if request == nil {
			continue
		}

		lastError = WithMasterServerClient(masterFn(), grpcDialOption, func(masterClient master_pb.SeaweedClient) error {

			req := &master_pb.AssignRequest{
				Count:               request.Count,
				Replication:         request.Replication,
				Collection:          request.Collection,
				Ttl:                 request.Ttl,
				DiskType:            request.DiskType,
				DataCenter:          request.DataCenter,
				Rack:                request.Rack,
				DataNode:            request.DataNode,
				WritableVolumeCount: request.WritableVolumeCount,
			}
			resp, grpcErr := masterClient.Assign(context.Background(), req)
			if grpcErr != nil {
				return grpcErr
			}

			ret.Count = resp.Count
			ret.Fid = resp.Fid
			ret.Url = resp.Location.Url
			ret.PublicUrl = resp.Location.PublicUrl
			ret.GrpcPort = int(resp.Location.GrpcPort)
			ret.Error = resp.Error
			ret.Auth = security.EncodedJwt(resp.Auth)
			for _, r := range resp.Replicas {
				ret.Replicas = append(ret.Replicas, Location{
					Url:       r.Url,
					PublicUrl: r.PublicUrl,
				})
			}

			if resp.Error != "" {
				return fmt.Errorf("assignRequest: %v", resp.Error)
			}

			return nil

		})

		if lastError != nil {
			continue
		}

		if ret.Count <= 0 {
			lastError = fmt.Errorf("assign failure %d: %v", i+1, ret.Error)
			continue
		}

		break
	}

	return ret, lastError
}

func LookupJwt(master pb.ServerAddress, grpcDialOption grpc.DialOption, fileId string) (token security.EncodedJwt) {

	WithMasterServerClient(master, grpcDialOption, func(masterClient master_pb.SeaweedClient) error {

		resp, grpcErr := masterClient.LookupVolume(context.Background(), &master_pb.LookupVolumeRequest{
			VolumeOrFileIds: []string{fileId},
		})
		if grpcErr != nil {
			return grpcErr
		}

		if len(resp.VolumeIdLocations) == 0 {
			return nil
		}

		token = security.EncodedJwt(resp.VolumeIdLocations[0].Auth)

		return nil

	})

	return
}

type StorageOption struct {
	Replication       string
	DiskType          string
	Collection        string
	DataCenter        string
	Rack              string
	TtlSeconds        int32
	Fsync             bool
	VolumeGrowthCount uint32
}

func (so *StorageOption) TtlString() string {
	return needle.SecondsToTTL(so.TtlSeconds)
}

func (so *StorageOption) ToAssignRequests(count int) (ar *VolumeAssignRequest, altRequest *VolumeAssignRequest) {
	ar = &VolumeAssignRequest{
		Count:               uint64(count),
		Replication:         so.Replication,
		Collection:          so.Collection,
		Ttl:                 so.TtlString(),
		DiskType:            so.DiskType,
		DataCenter:          so.DataCenter,
		Rack:                so.Rack,
		WritableVolumeCount: so.VolumeGrowthCount,
	}
	if so.DataCenter != "" || so.Rack != "" {
		altRequest = &VolumeAssignRequest{
			Count:               uint64(count),
			Replication:         so.Replication,
			Collection:          so.Collection,
			Ttl:                 so.TtlString(),
			DiskType:            so.DiskType,
			DataCenter:          "",
			Rack:                "",
			WritableVolumeCount: so.VolumeGrowthCount,
		}
	}
	return
}
<commit_msg>return error early<commit_after>package operation

import (
	"context"
	"fmt"
	"github.com/chrislusf/seaweedfs/weed/pb"
	"github.com/chrislusf/seaweedfs/weed/storage/needle"
	"google.golang.org/grpc"

	"github.com/chrislusf/seaweedfs/weed/pb/master_pb"
	"github.com/chrislusf/seaweedfs/weed/security"
)

type VolumeAssignRequest struct {
	Count               uint64
	Replication         string
	Collection          string
	Ttl                 string
	DiskType            string
	DataCenter          string
	Rack                string
	DataNode            string
	WritableVolumeCount uint32
}

type AssignResult struct {
	Fid       string              `json:"fid,omitempty"`
	Url       string              `json:"url,omitempty"`
	PublicUrl string              `json:"publicUrl,omitempty"`
	GrpcPort  int                 `json:"grpcPort,omitempty"`
	Count     uint64              `json:"count,omitempty"`
	Error     string              `json:"error,omitempty"`
	Auth      security.EncodedJwt `json:"auth,omitempty"`
	Replicas  []Location          `json:"replicas,omitempty"`
}

func Assign(masterFn GetMasterFn, grpcDialOption grpc.DialOption, primaryRequest *VolumeAssignRequest, alternativeRequests ...*VolumeAssignRequest) (*AssignResult, error) {

	var requests []*VolumeAssignRequest
	requests = append(requests, primaryRequest)
	requests = append(requests, alternativeRequests...)

	var lastError error
	ret := &AssignResult{}

	for i, request := range requests {
		if request == nil {
			continue
		}

		lastError = WithMasterServerClient(masterFn(), grpcDialOption, func(masterClient master_pb.SeaweedClient) error {

			req := &master_pb.AssignRequest{
				Count:               request.Count,
				Replication:         request.Replication,
				Collection:          request.Collection,
				Ttl:                 request.Ttl,
				DiskType:            request.DiskType,
				DataCenter:          request.DataCenter,
				Rack:                request.Rack,
				DataNode:            request.DataNode,
				WritableVolumeCount: request.WritableVolumeCount,
			}
			resp, grpcErr := masterClient.Assign(context.Background(), req)
			if grpcErr != nil {
				return grpcErr
			}

			if resp.Error != "" {
				return fmt.Errorf("assignRequest: %v", resp.Error)
			}

			ret.Count = resp.Count
			ret.Fid = resp.Fid
			ret.Url = resp.Location.Url
			ret.PublicUrl = resp.Location.PublicUrl
			ret.GrpcPort = int(resp.Location.GrpcPort)
			ret.Error = resp.Error
			ret.Auth = security.EncodedJwt(resp.Auth)
			for _, r := range resp.Replicas {
				ret.Replicas = append(ret.Replicas, Location{
					Url:       r.Url,
					PublicUrl: r.PublicUrl,
				})
			}

			return nil

		})

		if lastError != nil {
			continue
		}

		if ret.Count <= 0 {
			lastError = fmt.Errorf("assign failure %d: %v", i+1, ret.Error)
			continue
		}

		break
	}

	return ret, lastError
}

func LookupJwt(master pb.ServerAddress, grpcDialOption grpc.DialOption, fileId string) (token security.EncodedJwt) {

	WithMasterServerClient(master, grpcDialOption, func(masterClient master_pb.SeaweedClient) error {

		resp, grpcErr := masterClient.LookupVolume(context.Background(), &master_pb.LookupVolumeRequest{
			VolumeOrFileIds: []string{fileId},
		})
		if grpcErr != nil {
			return grpcErr
		}

		if len(resp.VolumeIdLocations) == 0 {
			return nil
		}

		token = security.EncodedJwt(resp.VolumeIdLocations[0].Auth)

		return nil

	})

	return
}

type StorageOption struct {
	Replication       string
	DiskType          string
	Collection        string
	DataCenter        string
	Rack              string
	TtlSeconds        int32
	Fsync             bool
	VolumeGrowthCount uint32
}

func (so *StorageOption) TtlString() string {
	return needle.SecondsToTTL(so.TtlSeconds)
}

func (so *StorageOption) ToAssignRequests(count int) (ar *VolumeAssignRequest, altRequest *VolumeAssignRequest) {
	ar = &VolumeAssignRequest{
		Count:               uint64(count),
		Replication:         so.Replication,
		Collection:          so.Collection,
		Ttl:                 so.TtlString(),
		DiskType:            so.DiskType,
		DataCenter:          so.DataCenter,
		Rack:                so.Rack,
		WritableVolumeCount: so.VolumeGrowthCount,
	}
	if so.DataCenter != "" || so.Rack != "" {
		altRequest = &VolumeAssignRequest{
			Count:               uint64(count),
			Replication:         so.Replication,
			Collection:          so.Collection,
			Ttl:                 so.TtlString(),
			DiskType:            so.DiskType,
			DataCenter:          "",
			Rack:                "",
			WritableVolumeCount: so.VolumeGrowthCount,
		}
	}
	return
}
<|endoftext|>


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

// Hello is a trivial example of a main package.
package main

import (
	"fmt"

	//"code.google.com/p/go.example/newmath"

	"newmath"
)

func main() {
	fmt.Printf("Hello, world.  Sqrt(2) = %v\n", newmath.Sqrt(2))
}
<commit_msg>Update hello.go<commit_after>// Copyright 2011 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Hello is a trivial example of a main package.
package main

import (
	"fmt"

	//"code.google.com/p/go.example/newmath"
	//comment out because:
	/*
	$ go get github.com/aspes/go.example/hello
	go: missing Mercurial command. See http://golang.org/s/gogetcmd
	package github.com/aspes/go.example/hello
        imports code.google.com/p/go.example/newmath: exec: "hg": executable file not found in %PATH%
        */

	//"newmath"
	//comment out because:
	/*
	imports newmath: unrecognized import path "newmath"
	*/

	"github.com/aspes/go.example/newmath"
)

func main() {
	fmt.Printf("Hello, world.  Sqrt(2) = %v\n", newmath.Sqrt(2))
}
<|endoftext|>


<commit_before>package sorter

import "testing"

// TestIsSorted tests the arrays if its sorted or not
func TestIsSorted(t *testing.T) {
	tests := []struct {
		arr      []int
		isSorted bool
	}{
		{[]int{0}, true},
		{[]int{0, 0}, true},
		{[]int{1, 2, 3}, true},
		{[]int{1, 2, 3, 4}, true},
		{[]int{0, 1, 2, 3, 4}, true},
		{[]int{0, 1, 1}, true},
		{[]int{0, 1, 2, 1}, false},
		{[]int{0, -1}, false},
		{[]int{0, 1, 2, 3, 4, 3}, false},
	}
	for _, test := range tests {
		// if we dont capture variable here, then its not guaranteed all the array
		// values will be tested
		test := test // capture range variable
		t.Run("", func(t *testing.T) {
			t.Parallel()
			// never ignore err
			// here we only check isSorted value
			isSorted, _ := IsSorted(test.arr)
			if isSorted != test.isSorted {
				t.Fatalf("result of isSorted %v should be %v\n", test.arr, test.isSorted)
			}
		})
	}
}

func TestGenerateArray(t *testing.T) {
	tests := []struct {
		item int
		err  error
	}{
		{-1, ErrArrayNoLength},
		{0, ErrArrayNoLength},
		{1, nil},
		{2, nil},
		{3, nil},
		{10, nil},
		{110, nil},
	}
	for _, test := range tests {
		// if we dont capture variable here, then its not guaranteed all the array
		// values will be tested
		test := test // capture range variable
		t.Run("", func(t *testing.T) {
			t.Parallel()
			// never ignore err
			// here we only check isSorted value
			arr, err := GenerateArray(test.item)
			if err != test.err {
				t.Fatalf("error should be %v, but got: %v", err, test.err)
			}
			if len(arr) > 0 && len(arr) != test.item {
				t.Fatalf("length of array should be %d, but got: %d", len(arr), test.item)
			}
		})
	}
}
<commit_msg>tests: fix comment<commit_after>package sorter

import "testing"

// TestIsSorted tests the arrays if its sorted or not
func TestIsSorted(t *testing.T) {
	tests := []struct {
		arr      []int
		isSorted bool
	}{
		{[]int{0}, true},
		{[]int{0, 0}, true},
		{[]int{1, 2, 3}, true},
		{[]int{1, 2, 3, 4}, true},
		{[]int{0, 1, 2, 3, 4}, true},
		{[]int{0, 1, 1}, true},
		{[]int{0, 1, 2, 1}, false},
		{[]int{0, -1}, false},
		{[]int{0, 1, 2, 3, 4, 3}, false},
	}
	for _, test := range tests {
		// if we dont capture variable here, then its not guaranteed all the array
		// values will be tested
		test := test // capture range variable
		t.Run("", func(t *testing.T) {
			t.Parallel()
			// note: never ignore errors
			// here we only check isSorted value
			isSorted, _ := IsSorted(test.arr)
			if isSorted != test.isSorted {
				t.Fatalf("result of isSorted %v should be %v\n", test.arr, test.isSorted)
			}
		})
	}
}

func TestGenerateArray(t *testing.T) {
	tests := []struct {
		item int
		err  error
	}{
		{-1, ErrArrayNoLength},
		{0, ErrArrayNoLength},
		{1, nil},
		{2, nil},
		{3, nil},
		{10, nil},
		{110, nil},
	}
	for _, test := range tests {
		// if we dont capture variable here, then its not guaranteed all the array
		// values will be tested
		test := test // capture range variable
		t.Run("", func(t *testing.T) {
			t.Parallel()
			// never ignore errors
			// here we only check isSorted value
			arr, err := GenerateArray(test.item)
			if err != test.err {
				t.Fatalf("error should be %v, but got: %v", err, test.err)
			}
			if len(arr) > 0 && len(arr) != test.item {
				t.Fatalf("length of array should be %d, but got: %d", len(arr), test.item)
			}
		})
	}
}
<|endoftext|>