<commit_before>package monitor

import (
	"bufio"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	_ "io/ioutil"
	"log"
	"os"
	"os/exec"
	"regexp"
)

type ipdata struct {
	Epoch       string `json:"Epoch"`
	SourceIP    string `json:"SourceIP"`
	SourcePort  string `json:"SourcePort"`
	ReceiveIP   string `json:"ReceiveIP"`
	ReceivePort string `json:"ReceivePort"`
}

/* The Monitor interface defines a series of methods which will be defined on
 * monitor structs. The Start method takes a channel to send messages over,
 * back to the configurator. The Stop method kills the process which is
 * performing the actual monitoring.
 */
type Monitor interface {
	Start(messages chan<- []byte, dockerComposeName string)
	Stop()
}

/* Store the MonitorName, which is the name of the program to execute, the
 * DockerDirs which are the directories to monitor which our Docker containers
 * of interest live in, and a pointer to the exec.Cmd struct which describes
 * the running command.
 */
type FSMonitor struct {
	MonitorName   string
	DockerDirs    []string
	fsWatcherProc *exec.Cmd
}

type ExecMonitor struct {
	MonitorName  string
	ContainerIds []string
}

type NetMonitor struct {
	MonitorName  string
	ContainerIds []string
}

// Memoize these. They're kind of expensive to get.
var dockerContainerIds = []string{}
var dockerContainerProcessIds = []string{}

func runCommandAndSlurpOutput(commandname string, args []string) ([]string, error) {
	command := exec.Command(commandname, args...)
	fmt.Print("running the command: ")
	fmt.Println(commandname, args)
	stdout, err := command.StdoutPipe()
	if err != nil {
		return nil, err
	}
	stderr, err := command.StderrPipe()
	if err != nil {
		return nil, err
	}

	go io.Copy(os.Stderr, stderr)
	command.Start()
	defer command.Wait()

	output := []string{}
	stdoutreader := bufio.NewReader(stdout)
	slurp := true
	for slurp {
		fetch := true
		line := []byte{}
		for fetch {
			partial_line, f, err := stdoutreader.ReadLine()
			fetch = f
			line = append(line, partial_line...)
			if err == io.EOF {
				slurp = false
				break
			} else if err != nil {
				return nil, err
			}
		}
		if len(line) > 0 {
			output = append(output, string(line))
		}
	}
	return output, nil
}

func runCommandAndChannelOutput(commandname string, args []string, output chan<- []byte) error {
	command := exec.Command(commandname, args...)
	fmt.Print("running the command: ")
	fmt.Println(commandname, args)
	stdout, err := command.StdoutPipe()
	if err != nil {
		return err
	}
	stderr, err := command.StderrPipe()
	if err != nil {
		return err
	}

	go io.Copy(os.Stderr, stderr)
	command.Start()
	defer command.Wait()

	stdoutreader := bufio.NewReader(stdout)
	slurp := true
	for slurp {
		fetch := true
		line := []byte{}
		for fetch {
			partial_line, f, err := stdoutreader.ReadLine()
			fetch = f
			line = append(line, partial_line...)
			if err == io.EOF {
				slurp = false
				break
			} else if err != nil {
				return err
			}
		}
		if len(line) > 0 {
			output <- line
		}
	}
	return nil
}

func getDockerContainerIds(dockerComposeName string) []string {
	if len(dockerContainerIds) != 0 {
		return dockerContainerIds
	}
	ids, err := runCommandAndSlurpOutput("docker-compose", []string{"ps", "-q"})
	if err != nil {
		panic(err)
	}
	dockerContainerIds = ids
	return ids
}

func getDockerContainerProcessIds(dockerComposeName string) []string {
	// Memoize this function
	if len(dockerContainerProcessIds) > 0 {
		return dockerContainerProcessIds
	}
	ids := getDockerContainerIds(dockerComposeName)
	arguments := []string{"inspect", "-f", "{{ .State.Pid }}"}
	arguments = append(arguments, ids...)
	output, err := runCommandAndSlurpOutput("docker", arguments)
	for i, out := range output {
		// FIXME: do we want to throw an error instead?
		if out == "0" {
			fmt.Println("Container isn't running: ", out)
			output = append(output[:i], output[i+1:]...)
			continue
		}
		output[i] = out
	}

	if err != nil {
		panic(err)
	}
	dockerContainerProcessIds = output
	return output
}

func (e ExecMonitor) Start(messages chan<- []byte, dockerComposeName string) {
	ids := getDockerContainerIds(dockerComposeName)
	err := runCommandAndChannelOutput("cproc_monitor/proc", ids, messages)
	if err != nil {
		fmt.Println("Exec monitor failed")
		panic(err)
	}
}

func (n NetMonitor) Start(messages chan<- []byte, dockerComposeName string) {
	output := getDockerContainerProcessIds(dockerComposeName)
	nmProcessorChan := make(chan []byte)
	go networkMonitorProcessor(messages, nmProcessorChan)
	for _, procId := range output {
		err := setSymlink(procId, procId)
		if err != nil {
			panic(err)
		}
		go startIPProcess(nmProcessorChan, procId, "tcpdump", "-tt", "-nn", "-i", "any", "-l")
	}
}

func networkMonitorProcessor(sending chan<- []byte, receiving <-chan []byte) error {
	platform := []byte{}
	carlson := []byte{}
	pattern := "(\\d+\\.\\d+) IP (\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})\\.(\\d+) > (\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})\\.(\\d+)"
	compiled_pattern, err := regexp.Compile(pattern)
	if err != nil {
		return err
	}
	for {
		platform = <-receiving
		matches := compiled_pattern.FindSubmatch(platform)
		if len(matches) == 0 {
			fmt.Println("Output did not match regex: ", string(platform))
			continue
		}
		carl := ipdata{
			Epoch:       string(matches[1]),
			SourceIP:    string(matches[2]),
			SourcePort:  string(matches[3]),
			ReceiveIP:   string(matches[4]),
			ReceivePort: string(matches[5]),
		}
		carlson, err = json.Marshal(carl)
		if err != nil {
			return err
		}
		fmt.Println("Sending json: ", string(carlson))
		sending <- carlson
	}

	return nil
}
func startIPProcess(messages chan<- []byte, procId string, watcherName string,
	watcherArgs ...string) {
	arguments := []string{"netns", "exec", procId, watcherName}
	arguments = append(arguments, watcherArgs...)
	err := runCommandAndChannelOutput("ip", arguments, messages)
	if err != nil {
		panic(err)
	}
}

func setSymlink(procId string, destination string) error {
	nameSpaceDir := "/var/run/netns/"
	target := nameSpaceDir + destination
	source := "/proc/" + procId + "/ns/net"

	err := os.MkdirAll(nameSpaceDir, 0777)
	if err != nil {
		return err
	}
	_, err = os.Stat(target)
	if err == nil {
		err = os.Remove(target)
		if err != nil {
			return err
		}
	}

	_, err = os.Stat(source)
	if os.IsNotExist(err) {
		return errors.New("Could not set symlink: Target directory " +
			target + " does not exist")
	}

	err = os.Symlink(source, target)
	return err
}

/* Returns the root directories of all of the Docker containers being monitored
 * as a list of strings.
 */
func (m FSMonitor) getDockerFSDirectory(dockerComposeName string) []string {
	pids := getDockerContainerProcessIds(dockerComposeName)
	roots := make([]string, len(pids))
	for i, pid := range pids {
		roots[i] = "/proc/" + pid + "/root"
	}
	return roots
}

/* Start the process running on the honeypot host to monitor the Docker
 * container. The Docker container's filesystem is mounted on the host. Find
 * the location of this filesystem with the getDockerFSDirectory function and
 * store it in the struct. Then create and start the process and forward
 * the output of the process on to the messages channel.
 */
func (m FSMonitor) Start(messages chan<- []byte, dockerComposeName string) {
	m.DockerDirs = m.getDockerFSDirectory(dockerComposeName)
	// FIXME Make arguments configurable
	arguments := append([]string{"-tea"}, m.DockerDirs...)
	fmt.Println(m.MonitorName, arguments)
	m.fsWatcherProc = exec.Command(m.MonitorName, arguments...)
	defer m.fsWatcherProc.Wait()

	outpipe, err := m.fsWatcherProc.StdoutPipe()
	if err != nil {
		log.Println("Could not open the ", m.MonitorName, "stdout pipe")
		panic(err)
	}
	stderr, err := m.fsWatcherProc.StderrPipe()
	if err != nil {
		log.Println("Could not open the ", m.MonitorName, "stderr pipe")
		panic(err)
	}
	go io.Copy(os.Stderr, stderr)

	m.fsWatcherProc.Start()

	stdoutReader := bufio.NewReader(outpipe)

	for {
		fetch := true
		line := []byte{}
		for fetch {
			partial_line, f, err := stdoutReader.ReadLine()
			if err != nil {
				fmt.Println("File monitor stopped")
				panic(err)
			}
			fetch = f
			line = append(line, partial_line...)
		}
		messages <- line

	}
}

/* Stop the filesystem monitor. Kill the process monitoring the Docker
 * container's filesysem.
 */
func (m FSMonitor) Stop() {
	err := m.fsWatcherProc.Process.Kill()
	if err != nil {
		log.Fatal("Could not kill ", m.MonitorName, err)
	}
}
<commit_msg>Close go channel after finishing<commit_after>package monitor

import (
	"bufio"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	_ "io/ioutil"
	"log"
	"os"
	"os/exec"
	"regexp"
)

type ipdata struct {
	Epoch       string `json:"Epoch"`
	SourceIP    string `json:"SourceIP"`
	SourcePort  string `json:"SourcePort"`
	ReceiveIP   string `json:"ReceiveIP"`
	ReceivePort string `json:"ReceivePort"`
}

/* The Monitor interface defines a series of methods which will be defined on
 * monitor structs. The Start method takes a channel to send messages over,
 * back to the configurator. The Stop method kills the process which is
 * performing the actual monitoring.
 */
type Monitor interface {
	Start(messages chan<- []byte, dockerComposeName string)
	Stop()
}

/* Store the MonitorName, which is the name of the program to execute, the
 * DockerDirs which are the directories to monitor which our Docker containers
 * of interest live in, and a pointer to the exec.Cmd struct which describes
 * the running command.
 */
type FSMonitor struct {
	MonitorName   string
	DockerDirs    []string
	fsWatcherProc *exec.Cmd
}

type ExecMonitor struct {
	MonitorName  string
	ContainerIds []string
}

type NetMonitor struct {
	MonitorName  string
	ContainerIds []string
}

// Memoize these. They're kind of expensive to get.
var dockerContainerIds = []string{}
var dockerContainerProcessIds = []string{}

func runCommandAndSlurpOutput(commandname string, args []string) ([]string, error) {
	command := exec.Command(commandname, args...)
	fmt.Print("running the command: ")
	fmt.Println(commandname, args)
	stdout, err := command.StdoutPipe()
	if err != nil {
		return nil, err
	}
	stderr, err := command.StderrPipe()
	if err != nil {
		return nil, err
	}

	go io.Copy(os.Stderr, stderr)
	command.Start()
	defer command.Wait()

	output := []string{}
	stdoutreader := bufio.NewReader(stdout)
	slurp := true
	for slurp {
		fetch := true
		line := []byte{}
		for fetch {
			partial_line, f, err := stdoutreader.ReadLine()
			fetch = f
			line = append(line, partial_line...)
			if err == io.EOF {
				slurp = false
				break
			} else if err != nil {
				return nil, err
			}
		}
		if len(line) > 0 {
			output = append(output, string(line))
		}
	}
	return output, nil
}

func runCommandAndChannelOutput(commandname string, args []string, output chan<- []byte) error {
	command := exec.Command(commandname, args...)
	fmt.Print("running the command: ")
	fmt.Println(commandname, args)
	stdout, err := command.StdoutPipe()
	if err != nil {
		return err
	}
	stderr, err := command.StderrPipe()
	if err != nil {
		return err
	}

	go io.Copy(os.Stderr, stderr)
	command.Start()
	defer command.Wait()

	stdoutreader := bufio.NewReader(stdout)
	slurp := true
	for slurp {
		fetch := true
		line := []byte{}
		for fetch {
			partial_line, f, err := stdoutreader.ReadLine()
			fetch = f
			line = append(line, partial_line...)
			if err == io.EOF {
				slurp = false
				break
			} else if err != nil {
				return err
			}
		}
		if len(line) > 0 {
			output <- line
		}
	}
	close(output)
	return nil
}

func getDockerContainerIds(dockerComposeName string) []string {
	if len(dockerContainerIds) != 0 {
		return dockerContainerIds
	}
	ids, err := runCommandAndSlurpOutput("docker-compose", []string{"ps", "-q"})
	if err != nil {
		panic(err)
	}
	dockerContainerIds = ids
	return ids
}

func getDockerContainerProcessIds(dockerComposeName string) []string {
	// Memoize this function
	if len(dockerContainerProcessIds) > 0 {
		return dockerContainerProcessIds
	}
	ids := getDockerContainerIds(dockerComposeName)
	arguments := []string{"inspect", "-f", "{{ .State.Pid }}"}
	arguments = append(arguments, ids...)
	output, err := runCommandAndSlurpOutput("docker", arguments)
	for i, out := range output {
		// FIXME: do we want to throw an error instead?
		if out == "0" {
			fmt.Println("Container isn't running: ", out)
			output = append(output[:i], output[i+1:]...)
			continue
		}
		output[i] = out
	}

	if err != nil {
		panic(err)
	}
	dockerContainerProcessIds = output
	return output
}

func (e ExecMonitor) Start(messages chan<- []byte, dockerComposeName string) {
	ids := getDockerContainerIds(dockerComposeName)
	err := runCommandAndChannelOutput("cproc_monitor/proc", ids, messages)
	if err != nil {
		fmt.Println("Exec monitor failed")
		panic(err)
	}
}

func (n NetMonitor) Start(messages chan<- []byte, dockerComposeName string) {
	output := getDockerContainerProcessIds(dockerComposeName)
	nmProcessorChan := make(chan []byte)
	go networkMonitorProcessor(messages, nmProcessorChan)
	for _, procId := range output {
		err := setSymlink(procId, procId)
		if err != nil {
			panic(err)
		}
		go startIPProcess(nmProcessorChan, procId, "tcpdump", "-tt", "-nn", "-i", "any", "-l")
	}
}

func networkMonitorProcessor(sending chan<- []byte, receiving <-chan []byte) error {
	platform := []byte{}
	carlson := []byte{}
	pattern := "(\\d+\\.\\d+) IP (\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})\\.(\\d+) > (\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})\\.(\\d+)"
	compiled_pattern, err := regexp.Compile(pattern)
	if err != nil {
		return err
	}
	for {
		platform = <-receiving
		matches := compiled_pattern.FindSubmatch(platform)
		if len(matches) == 0 {
			fmt.Println("Output did not match regex: ", string(platform))
			continue
		}
		carl := ipdata{
			Epoch:       string(matches[1]),
			SourceIP:    string(matches[2]),
			SourcePort:  string(matches[3]),
			ReceiveIP:   string(matches[4]),
			ReceivePort: string(matches[5]),
		}
		carlson, err = json.Marshal(carl)
		if err != nil {
			return err
		}
		fmt.Println("Sending json: ", string(carlson))
		sending <- carlson
	}

	return nil
}
func startIPProcess(messages chan<- []byte, procId string, watcherName string,
	watcherArgs ...string) {
	arguments := []string{"netns", "exec", procId, watcherName}
	arguments = append(arguments, watcherArgs...)
	err := runCommandAndChannelOutput("ip", arguments, messages)
	if err != nil {
		panic(err)
	}
}

func setSymlink(procId string, destination string) error {
	nameSpaceDir := "/var/run/netns/"
	target := nameSpaceDir + destination
	source := "/proc/" + procId + "/ns/net"

	err := os.MkdirAll(nameSpaceDir, 0777)
	if err != nil {
		return err
	}
	_, err = os.Stat(target)
	if err == nil {
		err = os.Remove(target)
		if err != nil {
			return err
		}
	}

	_, err = os.Stat(source)
	if os.IsNotExist(err) {
		return errors.New("Could not set symlink: Target directory " +
			target + " does not exist")
	}

	err = os.Symlink(source, target)
	return err
}

/* Returns the root directories of all of the Docker containers being monitored
 * as a list of strings.
 */
func (m FSMonitor) getDockerFSDirectory(dockerComposeName string) []string {
	pids := getDockerContainerProcessIds(dockerComposeName)
	roots := make([]string, len(pids))
	for i, pid := range pids {
		roots[i] = "/proc/" + pid + "/root"
	}
	return roots
}

/* Start the process running on the honeypot host to monitor the Docker
 * container. The Docker container's filesystem is mounted on the host. Find
 * the location of this filesystem with the getDockerFSDirectory function and
 * store it in the struct. Then create and start the process and forward
 * the output of the process on to the messages channel.
 */
func (m FSMonitor) Start(messages chan<- []byte, dockerComposeName string) {
	m.DockerDirs = m.getDockerFSDirectory(dockerComposeName)
	// FIXME Make arguments configurable
	arguments := append([]string{"-tea"}, m.DockerDirs...)
	fmt.Println(m.MonitorName, arguments)
	m.fsWatcherProc = exec.Command(m.MonitorName, arguments...)
	defer m.fsWatcherProc.Wait()

	outpipe, err := m.fsWatcherProc.StdoutPipe()
	if err != nil {
		log.Println("Could not open the ", m.MonitorName, "stdout pipe")
		panic(err)
	}
	stderr, err := m.fsWatcherProc.StderrPipe()
	if err != nil {
		log.Println("Could not open the ", m.MonitorName, "stderr pipe")
		panic(err)
	}
	go io.Copy(os.Stderr, stderr)

	m.fsWatcherProc.Start()

	stdoutReader := bufio.NewReader(outpipe)

	for {
		fetch := true
		line := []byte{}
		for fetch {
			partial_line, f, err := stdoutReader.ReadLine()
			if err != nil {
				fmt.Println("File monitor stopped")
				panic(err)
			}
			fetch = f
			line = append(line, partial_line...)
		}
		messages <- line

	}
}

/* Stop the filesystem monitor. Kill the process monitoring the Docker
 * container's filesysem.
 */
func (m FSMonitor) Stop() {
	err := m.fsWatcherProc.Process.Kill()
	if err != nil {
		log.Fatal("Could not kill ", m.MonitorName, err)
	}
}
<|endoftext|>


<commit_before>/* Here be dragons. */

package thumbnail

import (
    "io"
    "math"
    "github.com/pixiv/go-thumber/jpeg"
    "github.com/pixiv/go-thumber/swscale"
)

type ThumbnailParameters struct {
    Width int
    Height int
    Upscale bool
    ForceAspect bool
    Quality int
    Optimize bool
    PrescaleFactor float64
}

func MakeThumbnail(src io.Reader, dst io.Writer, params ThumbnailParameters) error {
    var dparams jpeg.DecompressionParameters
    if params.PrescaleFactor > 0 {
        dparams.TargetWidth = int(math.Ceil(float64(params.Width) * params.PrescaleFactor))
        dparams.TargetHeight = int(math.Ceil(float64(params.Height) * params.PrescaleFactor))
    }
    img, err := jpeg.ReadJPEG(src, dparams)
    if err != nil {
        return err
    }
    //fmt.Printf("%dx%d\n", img.Width, img.Height);

    // If Upscale is enabled, always scale unless the image is already the target size
    // Otherwise, scale if either component is
    if (params.Upscale && (img.Width < params.Width || img.Height < params.Height) ||
        (img.Width > params.Width) ||
        (img.Height > params.Height) ||
        params.ForceAspect && (img.Width != params.Width || img.Height != params.Height)) {

        var opts swscale.ScaleOptions
        opts.DstWidth = params.Width
        opts.DstHeight = params.Height
        if !params.ForceAspect {
            if opts.DstWidth > params.Height * img.Width / img.Height {
                opts.DstWidth = int(float64(params.Height * img.Width) / float64(img.Height) + 0.5)
            } else if opts.DstHeight > params.Width * img.Height / img.Width {
                opts.DstHeight = int(float64(params.Width * img.Height) / float64(img.Width) + 0.5)
            }
        }
        opts.Filter = swscale.LANCZOS
        // swscale can't handle images smaller than this; punt and don't scale
        // them.
        if opts.DstWidth >= 8 && img.Width >= 4 {
            img, err = swscale.Scale(img, opts)
            if err != nil {
                return err
            }
        }
    }

    //fmt.Printf("%dx%d\n", img.Width, img.Height);

    var cparams jpeg.CompressionParameters

    cparams.Optimize = params.Optimize
    cparams.Quality = params.Quality

    return jpeg.WriteJPEG(img, dst, cparams)
}
<commit_msg>Fix rescaling logic, make it always transcode if needed<commit_after>/* Here be dragons. */

package thumbnail

import (
    "io"
    "math"
    "github.com/pixiv/go-thumber/jpeg"
    "github.com/pixiv/go-thumber/swscale"
)

type ThumbnailParameters struct {
    Width int
    Height int
    Upscale bool
    ForceAspect bool
    Quality int
    Optimize bool
    PrescaleFactor float64
}

func MakeThumbnail(src io.Reader, dst io.Writer, params ThumbnailParameters) error {
    var dparams jpeg.DecompressionParameters
    if params.PrescaleFactor > 0 {
        dparams.TargetWidth = int(math.Ceil(float64(params.Width) * params.PrescaleFactor))
        dparams.TargetHeight = int(math.Ceil(float64(params.Height) * params.PrescaleFactor))
    }
    img, err := jpeg.ReadJPEG(src, dparams)
    if err != nil {
        return err
    }
    //fmt.Printf("%dx%d\n", img.Width, img.Height);

    if !params.Upscale && !params.ForceAspect &&
        img.Width < params.Width && img.Height < params.Height {
        params.Width = img.Width
        params.Height = img.Height
    }

    if (img.Width != params.Width || img.Height != params.Height ||
        (img.Format != jpeg.YUV444 && img.Format != jpeg.Grayscale)) {

        var opts swscale.ScaleOptions
        opts.DstWidth = params.Width
        opts.DstHeight = params.Height
        if !params.ForceAspect {
            if opts.DstWidth > params.Height * img.Width / img.Height {
                opts.DstWidth = int(float64(params.Height * img.Width) / float64(img.Height) + 0.5)
            } else if opts.DstHeight > params.Width * img.Height / img.Width {
                opts.DstHeight = int(float64(params.Width * img.Height) / float64(img.Width) + 0.5)
            }
        }
        opts.Filter = swscale.LANCZOS
        // swscale can't handle images smaller than this; punt and don't scale
        // them.
        if opts.DstWidth >= 8 && img.Width >= 4 {
            img, err = swscale.Scale(img, opts)
            if err != nil {
                return err
            }
        }
    }

    //fmt.Printf("%dx%d\n", img.Width, img.Height);

    var cparams jpeg.CompressionParameters

    cparams.Optimize = params.Optimize
    cparams.Quality = params.Quality

    return jpeg.WriteJPEG(img, dst, cparams)
}
<|endoftext|>


<commit_before>package native

import (
	"encoding/json"
	"fmt"
	"github.com/dotcloud/docker/execdriver"
	"github.com/dotcloud/docker/pkg/cgroups"
	"github.com/dotcloud/docker/pkg/libcontainer"
	"github.com/dotcloud/docker/pkg/libcontainer/apparmor"
	"github.com/dotcloud/docker/pkg/libcontainer/nsinit"
	"github.com/dotcloud/docker/pkg/system"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"strings"
	"syscall"
)

const (
	DriverName = "native"
	Version    = "0.1"
)

func init() {
	execdriver.RegisterInitFunc(DriverName, func(args *execdriver.InitArgs) error {
		var (
			container *libcontainer.Container
			ns        = nsinit.NewNsInit(&nsinit.DefaultCommandFactory{}, &nsinit.DefaultStateWriter{args.Root})
		)
		f, err := os.Open(filepath.Join(args.Root, "container.json"))
		if err != nil {
			return err
		}
		if err := json.NewDecoder(f).Decode(&container); err != nil {
			f.Close()
			return err
		}
		f.Close()

		cwd, err := os.Getwd()
		if err != nil {
			return err
		}
		syncPipe, err := nsinit.NewSyncPipeFromFd(0, uintptr(args.Pipe))
		if err != nil {
			return err
		}
		if err := ns.Init(container, cwd, args.Console, syncPipe, args.Args); err != nil {
			return err
		}
		return nil
	})
}

type driver struct {
	root string
}

func NewDriver(root string) (*driver, error) {
	if err := os.MkdirAll(root, 0700); err != nil {
		return nil, err
	}
	if err := apparmor.InstallDefaultProfile(); err != nil {
		return nil, err
	}
	return &driver{
		root: root,
	}, nil
}

func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (int, error) {
	if err := d.validateCommand(c); err != nil {
		return -1, err
	}
	var (
		term        nsinit.Terminal
		container   = createContainer(c)
		factory     = &dockerCommandFactory{c: c, driver: d}
		stateWriter = &dockerStateWriter{
			callback: startCallback,
			c:        c,
			dsw:      &nsinit.DefaultStateWriter{filepath.Join(d.root, c.ID)},
		}
		ns   = nsinit.NewNsInit(factory, stateWriter)
		args = append([]string{c.Entrypoint}, c.Arguments...)
	)
	if err := d.createContainerRoot(c.ID); err != nil {
		return -1, err
	}
	defer d.removeContainerRoot(c.ID)

	if c.Tty {
		term = &dockerTtyTerm{
			pipes: pipes,
		}
	} else {
		term = &dockerStdTerm{
			pipes: pipes,
		}
	}
	c.Terminal = term
	if err := d.writeContainerFile(container, c.ID); err != nil {
		return -1, err
	}
	return ns.Exec(container, term, args)
}

func (d *driver) Kill(p *execdriver.Command, sig int) error {
	err := syscall.Kill(p.Process.Pid, syscall.Signal(sig))
	d.removeContainerRoot(p.ID)
	return err
}

func (d *driver) Info(id string) execdriver.Info {
	return &info{
		ID:     id,
		driver: d,
	}
}

func (d *driver) Name() string {
	return fmt.Sprintf("%s-%s", DriverName, Version)
}

// TODO: this can be improved with our driver
// there has to be a better way to do this
func (d *driver) GetPidsForContainer(id string) ([]int, error) {
	pids := []int{}

	subsystem := "devices"
	cgroupRoot, err := cgroups.FindCgroupMountpoint(subsystem)
	if err != nil {
		return pids, err
	}
	cgroupDir, err := cgroups.GetThisCgroupDir(subsystem)
	if err != nil {
		return pids, err
	}

	filename := filepath.Join(cgroupRoot, cgroupDir, id, "tasks")
	if _, err := os.Stat(filename); os.IsNotExist(err) {
		filename = filepath.Join(cgroupRoot, cgroupDir, "docker", id, "tasks")
	}

	output, err := ioutil.ReadFile(filename)
	if err != nil {
		return pids, err
	}
	for _, p := range strings.Split(string(output), "\n") {
		if len(p) == 0 {
			continue
		}
		pid, err := strconv.Atoi(p)
		if err != nil {
			return pids, fmt.Errorf("Invalid pid '%s': %s", p, err)
		}
		pids = append(pids, pid)
	}
	return pids, nil
}

func (d *driver) writeContainerFile(container *libcontainer.Container, id string) error {
	data, err := json.Marshal(container)
	if err != nil {
		return err
	}
	return ioutil.WriteFile(filepath.Join(d.root, id, "container.json"), data, 0655)
}

func (d *driver) createContainerRoot(id string) error {
	return os.MkdirAll(filepath.Join(d.root, id), 0655)
}

func (d *driver) removeContainerRoot(id string) error {
	return os.RemoveAll(filepath.Join(d.root, id))
}

func (d *driver) validateCommand(c *execdriver.Command) error {
	// we need to check the Config of the command to make sure that we
	// do not have any of the lxc-conf variables
	for _, conf := range c.Config {
		if strings.Contains(conf, "lxc") {
			return fmt.Errorf("%s is not supported by the native driver", conf)
		}
	}
	return nil
}

func getEnv(key string, env []string) string {
	for _, pair := range env {
		parts := strings.Split(pair, "=")
		if parts[0] == key {
			return parts[1]
		}
	}
	return ""
}

type dockerCommandFactory struct {
	c      *execdriver.Command
	driver *driver
}

// createCommand will return an exec.Cmd with the Cloneflags set to the proper namespaces
// defined on the container's configuration and use the current binary as the init with the
// args provided
func (d *dockerCommandFactory) Create(container *libcontainer.Container, console string, syncFile *os.File, args []string) *exec.Cmd {
	// we need to join the rootfs because nsinit will setup the rootfs and chroot
	initPath := filepath.Join(d.c.Rootfs, d.c.InitPath)

	d.c.Path = initPath
	d.c.Args = append([]string{
		initPath,
		"-driver", DriverName,
		"-console", console,
		"-pipe", "3",
		"-root", filepath.Join(d.driver.root, d.c.ID),
		"--",
	}, args...)

	// set this to nil so that when we set the clone flags anything else is reset
	d.c.SysProcAttr = nil
	system.SetCloneFlags(&d.c.Cmd, uintptr(nsinit.GetNamespaceFlags(container.Namespaces)))
	d.c.ExtraFiles = []*os.File{syncFile}

	d.c.Env = container.Env
	d.c.Dir = d.c.Rootfs

	return &d.c.Cmd
}

type dockerStateWriter struct {
	dsw      nsinit.StateWriter
	c        *execdriver.Command
	callback execdriver.StartCallback
}

func (d *dockerStateWriter) WritePid(pid int) error {
	d.c.ContainerPid = pid
	err := d.dsw.WritePid(pid)
	if d.callback != nil {
		d.callback(d.c)
	}
	return err
}

func (d *dockerStateWriter) DeletePid() error {
	return d.dsw.DeletePid()
}
<commit_msg>restore function to native driver added<commit_after>package native

import (
	"encoding/json"
	"fmt"
	"github.com/dotcloud/docker/execdriver"
	"github.com/dotcloud/docker/pkg/cgroups"
	"github.com/dotcloud/docker/pkg/libcontainer"
	"github.com/dotcloud/docker/pkg/libcontainer/apparmor"
	"github.com/dotcloud/docker/pkg/libcontainer/nsinit"
	"github.com/dotcloud/docker/pkg/system"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"strings"
	"syscall"
)

const (
	DriverName = "native"
	Version    = "0.1"
)

func init() {
	execdriver.RegisterInitFunc(DriverName, func(args *execdriver.InitArgs) error {
		var (
			container *libcontainer.Container
			ns        = nsinit.NewNsInit(&nsinit.DefaultCommandFactory{}, &nsinit.DefaultStateWriter{args.Root})
		)
		f, err := os.Open(filepath.Join(args.Root, "container.json"))
		if err != nil {
			return err
		}
		if err := json.NewDecoder(f).Decode(&container); err != nil {
			f.Close()
			return err
		}
		f.Close()

		cwd, err := os.Getwd()
		if err != nil {
			return err
		}
		syncPipe, err := nsinit.NewSyncPipeFromFd(0, uintptr(args.Pipe))
		if err != nil {
			return err
		}
		if err := ns.Init(container, cwd, args.Console, syncPipe, args.Args); err != nil {
			return err
		}
		return nil
	})
}

type driver struct {
	root string
}

func NewDriver(root string) (*driver, error) {
	if err := os.MkdirAll(root, 0700); err != nil {
		return nil, err
	}
	if err := apparmor.InstallDefaultProfile(); err != nil {
		return nil, err
	}
	return &driver{
		root: root,
	}, nil
}

func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (int, error) {
	if err := d.validateCommand(c); err != nil {
		return -1, err
	}
	var (
		term        nsinit.Terminal
		container   = createContainer(c)
		factory     = &dockerCommandFactory{c: c, driver: d}
		stateWriter = &dockerStateWriter{
			callback: startCallback,
			c:        c,
			dsw:      &nsinit.DefaultStateWriter{filepath.Join(d.root, c.ID)},
		}
		ns   = nsinit.NewNsInit(factory, stateWriter)
		args = append([]string{c.Entrypoint}, c.Arguments...)
	)
	if err := d.createContainerRoot(c.ID); err != nil {
		return -1, err
	}
	defer d.removeContainerRoot(c.ID)

	if c.Tty {
		term = &dockerTtyTerm{
			pipes: pipes,
		}
	} else {
		term = &dockerStdTerm{
			pipes: pipes,
		}
	}
	c.Terminal = term
	if err := d.writeContainerFile(container, c.ID); err != nil {
		return -1, err
	}
	return ns.Exec(container, term, args)
}

func (d *driver) Kill(p *execdriver.Command, sig int) error {
	err := syscall.Kill(p.Process.Pid, syscall.Signal(sig))
	d.removeContainerRoot(p.ID)
	return err
}

func (d *driver) Restore(c *execdriver.Command) error {
    return nil
}

func (d *driver) Info(id string) execdriver.Info {
	return &info{
		ID:     id,
		driver: d,
	}
}

func (d *driver) Name() string {
	return fmt.Sprintf("%s-%s", DriverName, Version)
}

// TODO: this can be improved with our driver
// there has to be a better way to do this
func (d *driver) GetPidsForContainer(id string) ([]int, error) {
	pids := []int{}

	subsystem := "devices"
	cgroupRoot, err := cgroups.FindCgroupMountpoint(subsystem)
	if err != nil {
		return pids, err
	}
	cgroupDir, err := cgroups.GetThisCgroupDir(subsystem)
	if err != nil {
		return pids, err
	}

	filename := filepath.Join(cgroupRoot, cgroupDir, id, "tasks")
	if _, err := os.Stat(filename); os.IsNotExist(err) {
		filename = filepath.Join(cgroupRoot, cgroupDir, "docker", id, "tasks")
	}

	output, err := ioutil.ReadFile(filename)
	if err != nil {
		return pids, err
	}
	for _, p := range strings.Split(string(output), "\n") {
		if len(p) == 0 {
			continue
		}
		pid, err := strconv.Atoi(p)
		if err != nil {
			return pids, fmt.Errorf("Invalid pid '%s': %s", p, err)
		}
		pids = append(pids, pid)
	}
	return pids, nil
}

func (d *driver) writeContainerFile(container *libcontainer.Container, id string) error {
	data, err := json.Marshal(container)
	if err != nil {
		return err
	}
	return ioutil.WriteFile(filepath.Join(d.root, id, "container.json"), data, 0655)
}

func (d *driver) createContainerRoot(id string) error {
	return os.MkdirAll(filepath.Join(d.root, id), 0655)
}

func (d *driver) removeContainerRoot(id string) error {
	return os.RemoveAll(filepath.Join(d.root, id))
}

func (d *driver) validateCommand(c *execdriver.Command) error {
	// we need to check the Config of the command to make sure that we
	// do not have any of the lxc-conf variables
	for _, conf := range c.Config {
		if strings.Contains(conf, "lxc") {
			return fmt.Errorf("%s is not supported by the native driver", conf)
		}
	}
	return nil
}

func getEnv(key string, env []string) string {
	for _, pair := range env {
		parts := strings.Split(pair, "=")
		if parts[0] == key {
			return parts[1]
		}
	}
	return ""
}

type dockerCommandFactory struct {
	c      *execdriver.Command
	driver *driver
}

// createCommand will return an exec.Cmd with the Cloneflags set to the proper namespaces
// defined on the container's configuration and use the current binary as the init with the
// args provided
func (d *dockerCommandFactory) Create(container *libcontainer.Container, console string, syncFile *os.File, args []string) *exec.Cmd {
	// we need to join the rootfs because nsinit will setup the rootfs and chroot
	initPath := filepath.Join(d.c.Rootfs, d.c.InitPath)

	d.c.Path = initPath
	d.c.Args = append([]string{
		initPath,
		"-driver", DriverName,
		"-console", console,
		"-pipe", "3",
		"-root", filepath.Join(d.driver.root, d.c.ID),
		"--",
	}, args...)

	// set this to nil so that when we set the clone flags anything else is reset
	d.c.SysProcAttr = nil
	system.SetCloneFlags(&d.c.Cmd, uintptr(nsinit.GetNamespaceFlags(container.Namespaces)))
	d.c.ExtraFiles = []*os.File{syncFile}

	d.c.Env = container.Env
	d.c.Dir = d.c.Rootfs

	return &d.c.Cmd
}

type dockerStateWriter struct {
	dsw      nsinit.StateWriter
	c        *execdriver.Command
	callback execdriver.StartCallback
}

func (d *dockerStateWriter) WritePid(pid int) error {
	d.c.ContainerPid = pid
	err := d.dsw.WritePid(pid)
	if d.callback != nil {
		d.callback(d.c)
	}
	return err
}

func (d *dockerStateWriter) DeletePid() error {
	return d.dsw.DeletePid()
}
<|endoftext|>


<commit_before>/*
 *
 * Copyright IBM Corp. All Rights Reserved.
 *
 * SPDX-License-Identifier: Apache-2.0
 * /
 *
 */

package gossip

import (
	"fmt"
	"io/ioutil"
	"os"
	"syscall"
	"time"

	docker "github.com/fsouza/go-dockerclient"
	"github.com/hyperledger/fabric/integration/nwo"
	"github.com/hyperledger/fabric/integration/nwo/commands"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gbytes"
	"github.com/onsi/gomega/gexec"
	"github.com/tedsuo/ifrit"
)

var _ = Describe("Gossip Test", func() {
	var (
		testDir   string
		client    *docker.Client
		network   *nwo.Network
		chaincode nwo.Chaincode
		process   ifrit.Process
	)

	BeforeEach(func() {
		var err error
		testDir, err = ioutil.TempDir("", "e2e")
		Expect(err).NotTo(HaveOccurred())

		client, err = docker.NewClientFromEnv()
		Expect(err).NotTo(HaveOccurred())

		chaincode = nwo.Chaincode{
			Name:    "mycc",
			Version: "0.0",
			Path:    "github.com/hyperledger/fabric/integration/chaincode/simple/cmd",
			Ctor:    `{"Args":["init","a","100","b","200"]}`,
			Policy:  `OR ('Org1MSP.member','Org2MSP.member')`,
		}
	})

	AfterEach(func() {
		if process != nil {
			process.Signal(syscall.SIGTERM)
			Eventually(process.Wait(), network.EventuallyTimeout).Should(Receive())
		}
		if network != nil {
			network.Cleanup()
		}
		os.RemoveAll(testDir)
	})

	PDescribe("State transfer test", func() {
		var (
			ordererProcess ifrit.Process
			peerProcesses  = map[string]ifrit.Process{}
		)

		BeforeEach(func() {
			network = nwo.New(nwo.BasicSolo(), testDir, client, StartPort(), components)

			network.GenerateConfigTree()
			network.Bootstrap()
		})

		AfterEach(func() {
			if ordererProcess != nil {
				ordererProcess.Signal(syscall.SIGTERM)
				Eventually(ordererProcess.Wait(), network.EventuallyTimeout).Should(Receive())
			}

			for _, process := range peerProcesses {
				process.Signal(syscall.SIGTERM)
				Eventually(process.Wait(), network.EventuallyTimeout).Should(Receive())
			}
		})

		It("solo network with 2 orgs, 2 peers each, should sync from the peer if no orderer available", func() {
			orderer := network.Orderer("orderer")
			ordererRunner := network.OrdererRunner(orderer)
			ordererProcess = ifrit.Invoke(ordererRunner)

			peer0Org1, peer1Org1 := network.Peer("Org1", "peer0"), network.Peer("Org1", "peer1")
			peer0Org2, peer1Org2 := network.Peer("Org2", "peer0"), network.Peer("Org2", "peer1")

			for _, peer := range []*nwo.Peer{peer0Org1, peer1Org1, peer0Org2, peer1Org2} {
				runner := network.PeerRunner(peer)
				peerProcesses[peer.ID()] = ifrit.Invoke(runner)
			}

			channelName := "testchannel"
			network.CreateChannel(channelName, orderer, peer0Org1)
			network.JoinChannel(channelName, orderer, peer0Org1, peer1Org1, peer0Org2, peer1Org2)

			nwo.DeployChaincodeLegacy(network, channelName, orderer, chaincode, peer0Org1)
			network.UpdateChannelAnchors(orderer, channelName)

			for _, peer := range []*nwo.Peer{peer0Org1, peer1Org1, peer0Org2, peer1Org2} {
				Eventually(func() int {
					return nwo.GetLedgerHeight(network, peer, channelName)
				}).Should(BeNumerically(">=", 2))
			}

			By("stop peers to make sure they cannot get blocks from orderer")
			for id, proc := range peerProcesses {
				if id == peer0Org1.ID() {
					continue
				}
				proc.Signal(syscall.SIGTERM)
				Eventually(proc.Wait(), network.EventuallyTimeout).Should(Receive())
				delete(peerProcesses, id)
			}

			By("create transactions")
			for i := 0; i < 10; i++ {
				sess, err := network.PeerUserSession(peer0Org1, "User1", commands.ChaincodeInvoke{
					ChannelID: channelName,
					Orderer:   network.OrdererAddress(orderer, nwo.ListenPort),
					Name:      "mycc",
					Ctor:      `{"Args":["invoke","a","b","10"]}`,
					PeerAddresses: []string{
						network.PeerAddress(peer0Org1, nwo.ListenPort),
					},
					WaitForEvent: true,
				})
				Expect(err).NotTo(HaveOccurred())
				Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit(0))
				Expect(sess.Err).To(gbytes.Say("Chaincode invoke successful. result: status:200"))
			}

			peer0LedgerHeight := nwo.GetLedgerHeight(network, peer0Org1, channelName)

			By("turning down ordering service")
			ordererProcess.Signal(syscall.SIGTERM)
			Eventually(ordererProcess.Wait(), network.EventuallyTimeout).Should(Receive())
			ordererProcess = nil

			By("wait for rest of the peers to join and startup")
			for _, peer := range []*nwo.Peer{peer1Org1, peer0Org2, peer1Org2} {
				runner := network.PeerRunner(peer, fmt.Sprint("CORE_PEER_GOSSIP_STATE_CHECKINTERVAL=200ms"),
					fmt.Sprint("FABRIC_LOGGING_SPEC=info:gossip.state=debug"),
				)
				peerProcesses[peer.ID()] = ifrit.Invoke(runner)
			}

			By("Make sure peers are synced up")
			for _, peer := range []*nwo.Peer{peer1Org1, peer0Org2, peer1Org2} {
				Eventually(func() int {
					return nwo.GetLedgerHeight(network, peer, channelName)
				}, time.Second*10).Should(Equal(peer0LedgerHeight))
			}
		})
	})
})
<commit_msg>[FAB-15980] IT: stop the leader peer<commit_after>/*
 *
 * Copyright IBM Corp. All Rights Reserved.
 *
 * SPDX-License-Identifier: Apache-2.0
 * /
 *
 */

package gossip

import (
	"fmt"
	"io/ioutil"
	"os"
	"syscall"
	"time"

	docker "github.com/fsouza/go-dockerclient"
	"github.com/hyperledger/fabric/integration/nwo"
	"github.com/hyperledger/fabric/integration/nwo/commands"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gbytes"
	"github.com/onsi/gomega/gexec"
	"github.com/tedsuo/ifrit"
	"github.com/tedsuo/ifrit/ginkgomon"
)

var _ = Describe("Gossip Test", func() {
	var (
		testDir   string
		client    *docker.Client
		network   *nwo.Network
		chaincode nwo.Chaincode
		process   ifrit.Process
	)

	BeforeEach(func() {
		var err error
		testDir, err = ioutil.TempDir("", "e2e")
		Expect(err).NotTo(HaveOccurred())

		client, err = docker.NewClientFromEnv()
		Expect(err).NotTo(HaveOccurred())

		chaincode = nwo.Chaincode{
			Name:    "mycc",
			Version: "0.0",
			Path:    "github.com/hyperledger/fabric/integration/chaincode/simple/cmd",
			Ctor:    `{"Args":["init","a","100","b","200"]}`,
			Policy:  `OR ('Org1MSP.member','Org2MSP.member')`,
		}
	})

	AfterEach(func() {
		if process != nil {
			process.Signal(syscall.SIGTERM)
			Eventually(process.Wait(), network.EventuallyTimeout).Should(Receive())
		}
		if network != nil {
			network.Cleanup()
		}
		os.RemoveAll(testDir)
	})

	PDescribe("State transfer test", func() {
		var (
			ordererProcess ifrit.Process
			peerProcesses  = map[string]ifrit.Process{}
			peerRunners    = map[string]*ginkgomon.Runner{}
		)

		BeforeEach(func() {
			network = nwo.New(nwo.BasicSolo(), testDir, client, StartPort(), components)

			network.GenerateConfigTree()
			network.Bootstrap()
		})

		AfterEach(func() {
			if ordererProcess != nil {
				ordererProcess.Signal(syscall.SIGTERM)
				Eventually(ordererProcess.Wait(), network.EventuallyTimeout).Should(Receive())
			}

			for _, process := range peerProcesses {
				process.Signal(syscall.SIGTERM)
				Eventually(process.Wait(), network.EventuallyTimeout).Should(Receive())
			}
		})

		It("solo network with 2 orgs, 2 peers each, should sync from the peer if no orderer available", func() {
			orderer := network.Orderer("orderer")
			ordererRunner := network.OrdererRunner(orderer)
			ordererProcess = ifrit.Invoke(ordererRunner)

			peer0Org1, peer1Org1 := network.Peer("Org1", "peer0"), network.Peer("Org1", "peer1")
			peer0Org2, peer1Org2 := network.Peer("Org2", "peer0"), network.Peer("Org2", "peer1")

			for _, peer := range []*nwo.Peer{peer0Org1, peer1Org1, peer0Org2, peer1Org2} {
				runner := network.PeerRunner(peer)
				peerProcesses[peer.ID()] = ifrit.Invoke(runner)
				peerRunners[peer.ID()] = runner
			}

			channelName := "testchannel"
			network.CreateChannel(channelName, orderer, peer0Org1)
			network.JoinChannel(channelName, orderer, peer0Org1, peer1Org1, peer0Org2, peer1Org2)

			nwo.DeployChaincodeLegacy(network, channelName, orderer, chaincode, peer0Org1)
			network.UpdateChannelAnchors(orderer, channelName)

			for _, peer := range []*nwo.Peer{peer0Org1, peer1Org1, peer0Org2, peer1Org2} {
				Eventually(func() int {
					return nwo.GetLedgerHeight(network, peer, channelName)
				}).Should(BeNumerically(">=", 2))
			}

			By("stop peers except peer0Org1 to make sure they cannot get blocks from orderer")
			for id, proc := range peerProcesses {
				if id == peer0Org1.ID() {
					continue
				}
				proc.Signal(syscall.SIGTERM)
				Eventually(proc.Wait(), network.EventuallyTimeout).Should(Receive())
				delete(peerProcesses, id)
			}

			By("create transactions")
			runTransactions(network, orderer, peer0Org1, "mycc", channelName)

			peer0LedgerHeight := nwo.GetLedgerHeight(network, peer0Org1, channelName)

			By("turning down ordering service")
			ordererProcess.Signal(syscall.SIGTERM)
			Eventually(ordererProcess.Wait(), network.EventuallyTimeout).Should(Receive())
			ordererProcess = nil

			By("restart the three peers that were stopped")
			peerList := []*nwo.Peer{peer1Org1, peer0Org2, peer1Org2}
			peersRestart(network, orderer, peerList, peerProcesses, peerRunners)

			By("Make sure peers are synced up")
			assertPeersLedgerHeight(network, orderer, peerList, peer0LedgerHeight, channelName)

			By("start the orderer")
			orderer = network.Orderer("orderer")
			ordererRunner = network.OrdererRunner(orderer)
			ordererProcess = ifrit.Invoke(ordererRunner)

			By("install chaincode")
			nwo.InstallChaincodeLegacy(network, chaincode, peer1Org1)

			By("stop leader, peer0Org1, to make sure it cannot get blocks from orderer")
			id := peer0Org1.ID()
			proc := peerProcesses[id]
			proc.Signal(syscall.SIGTERM)
			Eventually(proc.Wait(), network.EventuallyTimeout).Should(Receive())

			expectedMsg := "Stopped being a leader"
			Eventually(peerRunners[id].Err(), time.Minute).Should(gbytes.Say(expectedMsg))

			delete(peerProcesses, id)

			By("create transactions")
			runTransactions(network, orderer, peer1Org1, "mycc", channelName)

			peer1LedgerHeight := nwo.GetLedgerHeight(network, peer1Org1, channelName)

			By("turning down ordering service")
			ordererProcess.Signal(syscall.SIGTERM)
			Eventually(ordererProcess.Wait(), network.EventuallyTimeout).Should(Receive())
			ordererProcess = nil

			By("restart peer0Org1")
			peerList = []*nwo.Peer{peer0Org1}
			peersRestart(network, orderer, peerList, peerProcesses, peerRunners)

			By("Make sure peer0Org1 is synced up")
			assertPeersLedgerHeight(network, orderer, peerList, peer1LedgerHeight, channelName)
		})
	})
})

func runTransactions(n *nwo.Network, orderer *nwo.Orderer, peer *nwo.Peer, chaincodeName string, channelID string) {
	for i := 0; i < 10; i++ {
		sess, err := n.PeerUserSession(peer, "User1", commands.ChaincodeInvoke{
			ChannelID: channelID,
			Orderer:   n.OrdererAddress(orderer, nwo.ListenPort),
			Name:      chaincodeName,
			Ctor:      `{"Args":["invoke","a","b","10"]}`,
			PeerAddresses: []string{
				n.PeerAddress(peer, nwo.ListenPort),
			},
			WaitForEvent: true,
		})
		Expect(err).NotTo(HaveOccurred())
		Eventually(sess, n.EventuallyTimeout).Should(gexec.Exit(0))
		Expect(sess.Err).To(gbytes.Say("Chaincode invoke successful. result: status:200"))
	}
}

func peersRestart(n *nwo.Network, orderer *nwo.Orderer, peerList []*nwo.Peer, peerProc map[string]ifrit.Process, peerRun map[string]*ginkgomon.Runner) {
	for _, peer := range peerList {
		runner := n.PeerRunner(peer, fmt.Sprint("CORE_PEER_GOSSIP_STATE_CHECKINTERVAL=200ms"),
			fmt.Sprint("FABRIC_LOGGING_SPEC=info:gossip.state=debug"),
		)
		peerProc[peer.ID()] = ifrit.Invoke(runner)
		peerRun[peer.ID()] = runner
	}
}

func assertPeersLedgerHeight(n *nwo.Network, orderer *nwo.Orderer, peerList []*nwo.Peer, expectedVal int, channelID string) {
	for _, peer := range peerList {
		Eventually(func() int {
			return nwo.GetLedgerHeight(n, peer, channelID)
		}, time.Second*10).Should(Equal(expectedVal))
	}
}
<|endoftext|>


<commit_before>package storage

import (
	"testing"

	"github.com/kylelemons/godebug/pretty"
	"github.com/yuuki/diamondb/lib/series"
)

func TestSeriesMapSortedNames(t *testing.T) {
	sm := seriesMap{
		"server3.loadavg5": newSeriesPoint("server2.loadavg5", datapoints{}, 60),
		"server1.loadavg5": newSeriesPoint("server1.loadavg5", datapoints{}, 60),
		"server2.loadavg5": newSeriesPoint("server2.loadavg5", datapoints{}, 60),
	}
	expected := []string{"server1.loadavg5", "server2.loadavg5", "server3.loadavg5"}
	if diff := pretty.Compare(sm.SortedNames(), expected); diff != "" {
		t.Fatalf("diff: (-actual +expected)\n%s", diff)
	}
}

func TestSeriesMapMerge(t *testing.T) {
	sm1 := seriesMap{
		"server1.loadavg5": newSeriesPoint("server1.loadavg5", datapoints{}, 60),
		"server2.loadavg5": newSeriesPoint("server2.loadavg5", datapoints{}, 60),
	}
	sm2 := seriesMap{
		"server1.loadavg5": newSeriesPoint("server1.loadavg5", datapoints{}, 60),
		"server3.loadavg5": newSeriesPoint("server3.loadavg5", datapoints{}, 60),
		"server4.loadavg5": newSeriesPoint("server4.loadavg5", datapoints{}, 60),
	}
	expected := seriesMap{
		"server1.loadavg5": newSeriesPoint("server1.loadavg5", datapoints{}, 60),
		"server2.loadavg5": newSeriesPoint("server2.loadavg5", datapoints{}, 60),
		"server3.loadavg5": newSeriesPoint("server3.loadavg5", datapoints{}, 60),
		"server4.loadavg5": newSeriesPoint("server4.loadavg5", datapoints{}, 60),
	}
	sm := sm1.Merge(sm2)
	if diff := pretty.Compare(sm, expected); diff != "" {
		t.Fatalf("diff: (-actual +expected)\n%s", diff)
	}
}

func TestMergePointsToMap(t *testing.T) {
	sm1 := seriesMap{
		"server1.loadavg5": newSeriesPoint("server1.loadavg5", datapoints{
			newDataPoint(1000, 0.1),
			newDataPoint(1060, 0.2),
			newDataPoint(1120, 0.3),
		}, 60),
	}
	sm2 := seriesMap{
		"server1.loadavg5": newSeriesPoint("server1.loadavg5", datapoints{
			newDataPoint(1120, 0.1),
			newDataPoint(1180, 0.2),
			newDataPoint(1240, 0.3),
		}, 60),
		"server2.loadavg5": newSeriesPoint("server2.loadavg5", datapoints{
			newDataPoint(1120, 0.1),
		}, 60),
	}

	sm := sm1.MergePointsToMap(sm2)

	expected := seriesMap{
		"server1.loadavg5": newSeriesPoint("server1.loadavg5", datapoints{
			newDataPoint(1000, 0.1),
			newDataPoint(1060, 0.2),
			newDataPoint(1120, 0.3), // TODO remove duplicated timestamp
			newDataPoint(1120, 0.1),
			newDataPoint(1180, 0.2),
			newDataPoint(1240, 0.3),
		}, 60),
		"server2.loadavg5": newSeriesPoint("server2.loadavg5", datapoints{
			newDataPoint(1120, 0.1),
		}, 60),
	}

	if diff := pretty.Compare(sm, expected); diff != "" {
		t.Fatalf("diff: (-actual +expected)\n%s", diff)
	}
}

func TestMergePointsToSlice(t *testing.T) {
	sm1 := seriesMap{
		"server1.loadavg5": newSeriesPoint("server1.loadavg5", datapoints{
			newDataPoint(1000, 0.1),
			newDataPoint(1060, 0.2),
			newDataPoint(1120, 0.3),
		}, 60),
	}
	sm2 := seriesMap{
		"server1.loadavg5": newSeriesPoint("server1.loadavg5", datapoints{
			newDataPoint(1120, 0.1),
			newDataPoint(1180, 0.2),
			newDataPoint(1240, 0.3),
		}, 60),
		"server2.loadavg5": newSeriesPoint("server2.loadavg5", datapoints{
			newDataPoint(1120, 0.1),
		}, 60),
	}

	sl := sm1.MergePointsToSlice(sm2)

	expected := series.SeriesSlice{
		series.NewSeries("server1.loadavg5", []float64{0.1, 0.2, 0.3, 0.1, 0.2, 0.3}, 1000, 60),
		series.NewSeries("server2.loadavg5", []float64{0.1}, 1120, 60),
	}
	if diff := pretty.Compare(sl, expected); diff != "" {
		t.Fatalf("diff: (-actual +expected)\n%s", diff)
	}
}
<commit_msg>Fix test for deduplication<commit_after>package storage

import (
	"testing"

	"github.com/kylelemons/godebug/pretty"
	"github.com/yuuki/diamondb/lib/series"
)

func TestSeriesMapSortedNames(t *testing.T) {
	sm := seriesMap{
		"server3.loadavg5": newSeriesPoint("server2.loadavg5", datapoints{}, 60),
		"server1.loadavg5": newSeriesPoint("server1.loadavg5", datapoints{}, 60),
		"server2.loadavg5": newSeriesPoint("server2.loadavg5", datapoints{}, 60),
	}
	expected := []string{"server1.loadavg5", "server2.loadavg5", "server3.loadavg5"}
	if diff := pretty.Compare(sm.SortedNames(), expected); diff != "" {
		t.Fatalf("diff: (-actual +expected)\n%s", diff)
	}
}

func TestSeriesMapMerge(t *testing.T) {
	sm1 := seriesMap{
		"server1.loadavg5": newSeriesPoint("server1.loadavg5", datapoints{}, 60),
		"server2.loadavg5": newSeriesPoint("server2.loadavg5", datapoints{}, 60),
	}
	sm2 := seriesMap{
		"server1.loadavg5": newSeriesPoint("server1.loadavg5", datapoints{}, 60),
		"server3.loadavg5": newSeriesPoint("server3.loadavg5", datapoints{}, 60),
		"server4.loadavg5": newSeriesPoint("server4.loadavg5", datapoints{}, 60),
	}
	expected := seriesMap{
		"server1.loadavg5": newSeriesPoint("server1.loadavg5", datapoints{}, 60),
		"server2.loadavg5": newSeriesPoint("server2.loadavg5", datapoints{}, 60),
		"server3.loadavg5": newSeriesPoint("server3.loadavg5", datapoints{}, 60),
		"server4.loadavg5": newSeriesPoint("server4.loadavg5", datapoints{}, 60),
	}
	sm := sm1.Merge(sm2)
	if diff := pretty.Compare(sm, expected); diff != "" {
		t.Fatalf("diff: (-actual +expected)\n%s", diff)
	}
}

func TestMergePointsToMap(t *testing.T) {
	sm1 := seriesMap{
		"server1.loadavg5": newSeriesPoint("server1.loadavg5", datapoints{
			newDataPoint(1000, 0.1),
			newDataPoint(1060, 0.2),
			newDataPoint(1120, 0.3),
		}, 60),
	}
	sm2 := seriesMap{
		"server1.loadavg5": newSeriesPoint("server1.loadavg5", datapoints{
			newDataPoint(1120, 0.1),
			newDataPoint(1180, 0.2),
			newDataPoint(1240, 0.3),
		}, 60),
		"server2.loadavg5": newSeriesPoint("server2.loadavg5", datapoints{
			newDataPoint(1120, 0.1),
		}, 60),
	}

	sm := sm1.MergePointsToMap(sm2)

	expected := seriesMap{
		"server1.loadavg5": newSeriesPoint("server1.loadavg5", datapoints{
			newDataPoint(1000, 0.1),
			newDataPoint(1060, 0.2),
			newDataPoint(1120, 0.1),
			newDataPoint(1180, 0.2),
			newDataPoint(1240, 0.3),
		}, 60),
		"server2.loadavg5": newSeriesPoint("server2.loadavg5", datapoints{
			newDataPoint(1120, 0.1),
		}, 60),
	}

	if diff := pretty.Compare(sm, expected); diff != "" {
		t.Fatalf("diff: (-actual +expected)\n%s", diff)
	}
}

func TestMergePointsToSlice(t *testing.T) {
	sm1 := seriesMap{
		"server1.loadavg5": newSeriesPoint("server1.loadavg5", datapoints{
			newDataPoint(1000, 0.1),
			newDataPoint(1060, 0.2),
			newDataPoint(1120, 0.3),
		}, 60),
	}
	sm2 := seriesMap{
		"server1.loadavg5": newSeriesPoint("server1.loadavg5", datapoints{
			newDataPoint(1120, 0.1),
			newDataPoint(1180, 0.2),
			newDataPoint(1240, 0.3),
		}, 60),
		"server2.loadavg5": newSeriesPoint("server2.loadavg5", datapoints{
			newDataPoint(1120, 0.1),
		}, 60),
	}

	sl := sm1.MergePointsToSlice(sm2)

	expected := series.SeriesSlice{
		series.NewSeries("server1.loadavg5", []float64{0.1, 0.2, 0.1, 0.2, 0.3}, 1000, 60),
		series.NewSeries("server2.loadavg5", []float64{0.1}, 1120, 60),
	}
	if diff := pretty.Compare(sl, expected); diff != "" {
		t.Fatalf("diff: (-actual +expected)\n%s", diff)
	}
}
<|endoftext|>


<commit_before>package slb

import (
	"os"

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

type Client struct {
	common.Client
}

const (
	// SLBDefaultEndpoint is the default API endpoint of SLB services
	SLBDefaultEndpoint = "https://slb.aliyuncs.com"
	SLBAPIVersion      = "2014-05-15"

	SLBServiceCode = "slb"
)

// NewClient creates a new instance of ECS client
func NewClient(accessKeyId, accessKeySecret string) *Client {
	endpoint := os.Getenv("SLB_ENDPOINT")
	if endpoint == "" {
		endpoint = SLBDefaultEndpoint
	}
	return NewClientWithEndpoint(endpoint, accessKeyId, accessKeySecret)
}

func NewClientWithEndpoint(endpoint string, accessKeyId, accessKeySecret string) *Client {
	client := &Client{}
	client.Init(endpoint, SLBAPIVersion, accessKeyId, accessKeySecret)
	return client
}

func NewSLBClient(accessKeyId, accessKeySecret string, regionID common.Region) *Client {
	endpoint := os.Getenv("SLB_ENDPOINT")
	if endpoint == "" {
		endpoint = SLBDefaultEndpoint
	}

	return NewClientWithRegion(endpoint, accessKeyId, accessKeySecret, regionID)
}

func NewClientWithRegion(endpoint string, accessKeyId, accessKeySecret string, regionID common.Region) *Client {
	client := &Client{}
	client.NewInit(endpoint, SLBAPIVersion, accessKeyId, accessKeySecret, SLBServiceCode, regionID)
	return client
}

func NewSLBClientWithSecurityToken(accessKeyId string, accessKeySecret string, securityToken string, regionID common.Region) *Client {
	endpoint := os.Getenv("SLB_ENDPOINT")
	if endpoint == "" {
		endpoint = SLBDefaultEndpoint
	}

	return NewSLBClientWithEndpointAndSecurityToken(endpoint, accessKeyId, accessKeySecret, securityToken, regionID)
}

//Only for hangzhou
func NewSLBClientWithSecurityToken4RegionalDomain(accessKeyId string, accessKeySecret string, securityToken string, regionID common.Region) *Client {
	endpoint := os.Getenv("SLB_ENDPOINT")
	if endpoint == "" {
		return NewSLBClientWithEndpointAndSecurityToken(endpoint, accessKeyId, accessKeySecret, securityToken, regionID)
	}

	return NewSLBClientWithEndpointAndSecurityToken4RegionalDomain(endpoint, accessKeyId, accessKeySecret, securityToken, regionID)
}

func NewSLBClientWithEndpointAndSecurityToken(endpoint string, accessKeyId string, accessKeySecret string, securityToken string, regionID common.Region) *Client {
	client := &Client{}
	client.WithEndpoint(endpoint).
		WithVersion(SLBAPIVersion).
		WithAccessKeyId(accessKeyId).
		WithAccessKeySecret(accessKeySecret).
		WithSecurityToken(securityToken).
		WithServiceCode(SLBServiceCode).
		WithRegionID(regionID).
		InitClient()
	return client
}

//only for hangzhou
func NewSLBClientWithEndpointAndSecurityToken4RegionalDomain(endpoint string, accessKeyId string, accessKeySecret string, securityToken string, regionID common.Region) *Client {
	client := &Client{}
	client.WithEndpoint(endpoint).
		WithVersion(SLBAPIVersion).
		WithAccessKeyId(accessKeyId).
		WithAccessKeySecret(accessKeySecret).
		WithSecurityToken(securityToken).
		WithServiceCode(SLBServiceCode).
		WithRegionID(regionID).
		InitClient4RegionalDomain()
	return client
}
<commit_msg>fix setting slb endpoint by env do not work<commit_after>package slb

import (
	"os"

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

type Client struct {
	common.Client
}

const (
	// SLBDefaultEndpoint is the default API endpoint of SLB services
	SLBDefaultEndpoint = "https://slb.aliyuncs.com"
	SLBAPIVersion      = "2014-05-15"

	SLBServiceCode = "slb"
)

// NewClient creates a new instance of ECS client
func NewClient(accessKeyId, accessKeySecret string) *Client {
	endpoint := os.Getenv("SLB_ENDPOINT")
	if endpoint == "" {
		endpoint = SLBDefaultEndpoint
	}
	return NewClientWithEndpoint(endpoint, accessKeyId, accessKeySecret)
}

func NewClientWithEndpoint(endpoint string, accessKeyId, accessKeySecret string) *Client {
	client := &Client{}
	client.Init(endpoint, SLBAPIVersion, accessKeyId, accessKeySecret)
	return client
}

func NewSLBClient(accessKeyId, accessKeySecret string, regionID common.Region) *Client {
	endpoint := os.Getenv("SLB_ENDPOINT")
	if endpoint == "" {
		endpoint = SLBDefaultEndpoint
	}

	return NewClientWithRegion(endpoint, accessKeyId, accessKeySecret, regionID)
}

func NewClientWithRegion(endpoint string, accessKeyId, accessKeySecret string, regionID common.Region) *Client {
	client := &Client{}
	client.NewInit(endpoint, SLBAPIVersion, accessKeyId, accessKeySecret, SLBServiceCode, regionID)
	return client
}

func NewSLBClientWithSecurityToken(accessKeyId string, accessKeySecret string, securityToken string, regionID common.Region) *Client {
	endpoint := os.Getenv("SLB_ENDPOINT")
	if endpoint == "" {
		endpoint = SLBDefaultEndpoint
	}

	return NewSLBClientWithEndpointAndSecurityToken(endpoint, accessKeyId, accessKeySecret, securityToken, regionID)
}

//Only for hangzhou
func NewSLBClientWithSecurityToken4RegionalDomain(accessKeyId string, accessKeySecret string, securityToken string, regionID common.Region) *Client {
	endpoint := os.Getenv("SLB_ENDPOINT")
	if endpoint != "" {
		return NewSLBClientWithEndpointAndSecurityToken(endpoint, accessKeyId, accessKeySecret, securityToken, regionID)
	}

	return NewSLBClientWithEndpointAndSecurityToken4RegionalDomain(endpoint, accessKeyId, accessKeySecret, securityToken, regionID)
}

func NewSLBClientWithEndpointAndSecurityToken(endpoint string, accessKeyId string, accessKeySecret string, securityToken string, regionID common.Region) *Client {
	client := &Client{}
	client.WithEndpoint(endpoint).
		WithVersion(SLBAPIVersion).
		WithAccessKeyId(accessKeyId).
		WithAccessKeySecret(accessKeySecret).
		WithSecurityToken(securityToken).
		WithServiceCode(SLBServiceCode).
		WithRegionID(regionID).
		InitClient()
	return client
}

//only for hangzhou
func NewSLBClientWithEndpointAndSecurityToken4RegionalDomain(endpoint string, accessKeyId string, accessKeySecret string, securityToken string, regionID common.Region) *Client {
	client := &Client{}
	client.WithEndpoint(endpoint).
		WithVersion(SLBAPIVersion).
		WithAccessKeyId(accessKeyId).
		WithAccessKeySecret(accessKeySecret).
		WithSecurityToken(securityToken).
		WithServiceCode(SLBServiceCode).
		WithRegionID(regionID).
		InitClient4RegionalDomain()
	return client
}
<|endoftext|>


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

package dao

import (
	"github.com/vmware/harbor/src/common"
	"github.com/vmware/harbor/src/common/models"

	"fmt"
	"time"

	//"github.com/vmware/harbor/src/common/utils/log"
)

//TODO:transaction, return err

// AddProject adds a project to the database along with project roles information and access log records.
func AddProject(project models.Project) (int64, error) {

	o := GetOrmer()
	p, err := o.Raw("insert into project (owner_id, name, creation_time, update_time, deleted, public) values (?, ?, ?, ?, ?, ?)").Prepare()
	if err != nil {
		return 0, err
	}

	now := time.Now()
	r, err := p.Exec(project.OwnerID, project.Name, now, now, project.Deleted, project.Public)
	if err != nil {
		return 0, err
	}

	projectID, err := r.LastInsertId()
	if err != nil {
		return 0, err
	}

	err = AddProjectMember(projectID, project.OwnerID, models.PROJECTADMIN)
	return projectID, err
}

/*
// IsProjectPublic ...
func IsProjectPublic(projectName string) bool {
	project, err := GetProjectByName(projectName)
	if err != nil {
		log.Errorf("Error occurred in GetProjectByName: %v", err)
		return false
	}
	if project == nil {
		return false
	}
	return project.Public == 1
}

//ProjectExists returns whether the project exists according to its name of ID.
func ProjectExists(nameOrID interface{}) (bool, error) {
	o := GetOrmer()
	type dummy struct{}
	sql := `select project_id from project where deleted = 0 and `
	switch nameOrID.(type) {
	case int64:
		sql += `project_id = ?`
	case string:
		sql += `name = ?`
	default:
		return false, fmt.Errorf("Invalid nameOrId: %v", nameOrID)
	}

	var d []dummy
	num, err := o.Raw(sql, nameOrID).QueryRows(&d)
	if err != nil {
		return false, err
	}
	return num > 0, nil

}
*/
// GetProjectByID ...
func GetProjectByID(id int64) (*models.Project, error) {
	o := GetOrmer()

	sql := `select p.project_id, p.name, u.username as owner_name, p.owner_id, p.creation_time, p.update_time, p.public
		from project p left join user u on p.owner_id = u.user_id where p.deleted = 0 and p.project_id = ?`
	queryParam := make([]interface{}, 1)
	queryParam = append(queryParam, id)

	p := []models.Project{}
	count, err := o.Raw(sql, queryParam).QueryRows(&p)

	if err != nil {
		return nil, err
	}

	if count == 0 {
		return nil, nil
	}

	return &p[0], nil
}

// GetProjectByName ...
func GetProjectByName(name string) (*models.Project, error) {
	o := GetOrmer()
	var p []models.Project
	n, err := o.Raw(`select * from project where name = ? and deleted = 0`, name).QueryRows(&p)
	if err != nil {
		return nil, err
	}

	if n == 0 {
		return nil, nil
	}

	return &p[0], nil
}

/*
// GetPermission gets roles that the user has according to the project.
func GetPermission(username, projectName string) (string, error) {
	o := GetOrmer()

	sql := `select r.role_code from role as r
		inner join project_member as pm on r.role_id = pm.role
		inner join user as u on u.user_id = pm.user_id
		inner join project p on p.project_id = pm.project_id
		where u.username = ? and p.name = ? and u.deleted = 0 and p.deleted = 0`

	var r []models.Role
	n, err := o.Raw(sql, username, projectName).QueryRows(&r)
	if err != nil {
		return "", err
	}

	if n == 0 {
		return "", nil
	}

	return r[0].RoleCode, nil
}
*/
// ToggleProjectPublicity toggles the publicity of the project.
func ToggleProjectPublicity(projectID int64, publicity int) error {
	o := GetOrmer()
	sql := "update project set public = ? where project_id = ?"
	_, err := o.Raw(sql, publicity, projectID).Exec()
	return err
}

// GetHasReadPermProjects returns a project list,
// which satisfies the following conditions:
// 1. the project is not deleted
// 2. the prject is public or the user is a member of the project
func GetHasReadPermProjects(username string) ([]*models.Project, error) {
	user, err := GetUser(models.User{
		Username: username,
	})
	if err != nil {
		return nil, err
	}

	o := GetOrmer()

	sql :=
		`select distinct p.project_id, p.name, p.public,
			p.owner_id, p.creation_time, p.update_time
		from project p
		left join project_member pm
		on p.project_id = pm.project_id
		where (pm.user_id = ? or p.public = 1)
		and p.deleted = 0 `

	var projects []*models.Project

	if _, err := o.Raw(sql, user.UserID).QueryRows(&projects); err != nil {
		return nil, err
	}

	return projects, nil
}

// GetTotalOfProjects returns the total count of projects
// according to the query conditions
func GetTotalOfProjects(query *models.ProjectQueryParam, base ...*models.BaseProjectCollection) (int64, error) {

	var (
		owner  string
		name   string
		public *bool
		member string
		role   int
	)

	if query != nil {
		owner = query.Owner
		name = query.Name
		public = query.Public
		if query.Member != nil {
			member = query.Member.Name
			role = query.Member.Role
		}
	}

	sql, params := projectQueryConditions(owner, name, public, member, role, base...)

	sql = `select count(*) ` + sql

	var total int64
	err := GetOrmer().Raw(sql, params).QueryRow(&total)
	return total, err
}

// GetProjects returns a project list according to the query conditions
func GetProjects(query *models.ProjectQueryParam, base ...*models.BaseProjectCollection) ([]*models.Project, error) {

	var (
		owner  string
		name   string
		public *bool
		member string
		role   int
		page   int64
		size   int64
	)

	if query != nil {
		owner = query.Owner
		name = query.Name
		public = query.Public
		if query.Member != nil {
			member = query.Member.Name
			role = query.Member.Role
		}
		if query.Pagination != nil {
			page = query.Pagination.Page
			size = query.Pagination.Size
		}
	}

	sql, params := projectQueryConditions(owner, name, public, member, role, base...)

	sql = `select distinct p.project_id, p.name, p.public, p.owner_id,
				p.creation_time, p.update_time ` + sql
	if size > 0 {
		sql += ` limit ?`
		params = append(params, size)

		if page > 0 {
			sql += ` offset ?`
			params = append(params, (page-1)*size)
		}
	}

	var projects []*models.Project
	_, err := GetOrmer().Raw(sql, params).QueryRows(&projects)
	return projects, err
}

func projectQueryConditions(owner, name string, public *bool, member string,
	role int, base ...*models.BaseProjectCollection) (string, []interface{}) {
	params := []interface{}{}

	// the base project collections:
	// 1. all projects
	// 2. public projects
	// 3. public projects and projects which the user is a member of
	collection := `project `
	if len(base) != 0 && base[0] != nil {
		if len(base[0].Member) == 0 && base[0].Public {
			collection = `(select * from project pr
					where pr.public=1) `
		}
		if len(base[0].Member) > 0 && base[0].Public {
			collection = `(select pr.project_id, pr.owner_id, pr.name, pr.
						creation_time, pr.update_time, pr.deleted, pr.public
					from project pr
					join project_member prm
						on pr.project_id = prm.project_id
					join user ur
						on prm.user_id=ur.user_id
					where ur.username=?  or pr.public=1 )`
			params = append(params, base[0].Member)
		}
	}

	sql := ` from ` + collection + ` as p`

	if len(owner) != 0 {
		sql += ` join user u1
					on p.owner_id = u1.user_id`
	}

	if len(member) != 0 {
		sql += ` join project_member pm
					on p.project_id = pm.project_id
					join user u2
					on pm.user_id=u2.user_id`
	}
	sql += ` where p.deleted=0`

	if len(owner) != 0 {
		sql += ` and u1.username=?`
		params = append(params, owner)
	}

	if len(name) != 0 {
		sql += ` and p.name like ?`
		params = append(params, "%"+escape(name)+"%")
	}

	if public != nil {
		sql += ` and p.public = ?`
		if *public {
			params = append(params, 1)
		} else {
			params = append(params, 0)
		}
	}

	if len(member) != 0 {
		sql += ` and u2.username=?`
		params = append(params, member)

		if role > 0 {
			sql += ` and pm.role = ?`
			roleID := 0
			switch role {
			case common.RoleProjectAdmin:
				roleID = 1
			case common.RoleDeveloper:
				roleID = 2
			case common.RoleGuest:
				roleID = 3

			}
			params = append(params, roleID)
		}
	}

	sql += ` order by p.name`

	return sql, params
}

// DeleteProject ...
func DeleteProject(id int64) error {
	project, err := GetProjectByID(id)
	if err != nil {
		return err
	}

	name := fmt.Sprintf("%s#%d", project.Name, project.ProjectID)

	sql := `update project
		set deleted = 1, name = ?
		where project_id = ?`
	_, err = GetOrmer().Raw(sql, name, id).Exec()
	return err
}
<commit_msg>update<commit_after>// Copyright (c) 2017 VMware, Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package dao

import (
	"github.com/vmware/harbor/src/common"
	"github.com/vmware/harbor/src/common/models"

	"fmt"
	"time"

	//"github.com/vmware/harbor/src/common/utils/log"
)

//TODO:transaction, return err

// AddProject adds a project to the database along with project roles information and access log records.
func AddProject(project models.Project) (int64, error) {

	o := GetOrmer()
	p, err := o.Raw("insert into project (owner_id, name, creation_time, update_time, deleted, public) values (?, ?, ?, ?, ?, ?)").Prepare()
	if err != nil {
		return 0, err
	}

	now := time.Now()
	r, err := p.Exec(project.OwnerID, project.Name, now, now, project.Deleted, project.Public)
	if err != nil {
		return 0, err
	}

	projectID, err := r.LastInsertId()
	if err != nil {
		return 0, err
	}

	err = AddProjectMember(projectID, project.OwnerID, models.PROJECTADMIN)
	return projectID, err
}

/*
// IsProjectPublic ...
func IsProjectPublic(projectName string) bool {
	project, err := GetProjectByName(projectName)
	if err != nil {
		log.Errorf("Error occurred in GetProjectByName: %v", err)
		return false
	}
	if project == nil {
		return false
	}
	return project.Public == 1
}

//ProjectExists returns whether the project exists according to its name of ID.
func ProjectExists(nameOrID interface{}) (bool, error) {
	o := GetOrmer()
	type dummy struct{}
	sql := `select project_id from project where deleted = 0 and `
	switch nameOrID.(type) {
	case int64:
		sql += `project_id = ?`
	case string:
		sql += `name = ?`
	default:
		return false, fmt.Errorf("Invalid nameOrId: %v", nameOrID)
	}

	var d []dummy
	num, err := o.Raw(sql, nameOrID).QueryRows(&d)
	if err != nil {
		return false, err
	}
	return num > 0, nil

}
*/

// GetProjectByID ...
func GetProjectByID(id int64) (*models.Project, error) {
	o := GetOrmer()

	sql := `select p.project_id, p.name, u.username as owner_name, p.owner_id, p.creation_time, p.update_time, p.public
		from project p left join user u on p.owner_id = u.user_id where p.deleted = 0 and p.project_id = ?`
	queryParam := make([]interface{}, 1)
	queryParam = append(queryParam, id)

	p := []models.Project{}
	count, err := o.Raw(sql, queryParam).QueryRows(&p)

	if err != nil {
		return nil, err
	}

	if count == 0 {
		return nil, nil
	}

	return &p[0], nil
}

// GetProjectByName ...
func GetProjectByName(name string) (*models.Project, error) {
	o := GetOrmer()
	var p []models.Project
	n, err := o.Raw(`select * from project where name = ? and deleted = 0`, name).QueryRows(&p)
	if err != nil {
		return nil, err
	}

	if n == 0 {
		return nil, nil
	}

	return &p[0], nil
}

/*
// GetPermission gets roles that the user has according to the project.
func GetPermission(username, projectName string) (string, error) {
	o := GetOrmer()

	sql := `select r.role_code from role as r
		inner join project_member as pm on r.role_id = pm.role
		inner join user as u on u.user_id = pm.user_id
		inner join project p on p.project_id = pm.project_id
		where u.username = ? and p.name = ? and u.deleted = 0 and p.deleted = 0`

	var r []models.Role
	n, err := o.Raw(sql, username, projectName).QueryRows(&r)
	if err != nil {
		return "", err
	}

	if n == 0 {
		return "", nil
	}

	return r[0].RoleCode, nil
}
*/

// ToggleProjectPublicity toggles the publicity of the project.
func ToggleProjectPublicity(projectID int64, publicity int) error {
	o := GetOrmer()
	sql := "update project set public = ? where project_id = ?"
	_, err := o.Raw(sql, publicity, projectID).Exec()
	return err
}

// GetHasReadPermProjects returns a project list,
// which satisfies the following conditions:
// 1. the project is not deleted
// 2. the prject is public or the user is a member of the project
func GetHasReadPermProjects(username string) ([]*models.Project, error) {
	user, err := GetUser(models.User{
		Username: username,
	})
	if err != nil {
		return nil, err
	}

	o := GetOrmer()

	sql :=
		`select distinct p.project_id, p.name, p.public,
			p.owner_id, p.creation_time, p.update_time
		from project p
		left join project_member pm
		on p.project_id = pm.project_id
		where (pm.user_id = ? or p.public = 1)
		and p.deleted = 0 `

	var projects []*models.Project

	if _, err := o.Raw(sql, user.UserID).QueryRows(&projects); err != nil {
		return nil, err
	}

	return projects, nil
}

// GetTotalOfProjects returns the total count of projects
// according to the query conditions
func GetTotalOfProjects(query *models.ProjectQueryParam, base ...*models.BaseProjectCollection) (int64, error) {

	var (
		owner  string
		name   string
		public *bool
		member string
		role   int
	)

	if query != nil {
		owner = query.Owner
		name = query.Name
		public = query.Public
		if query.Member != nil {
			member = query.Member.Name
			role = query.Member.Role
		}
	}

	sql, params := projectQueryConditions(owner, name, public, member, role, base...)

	sql = `select count(*) ` + sql

	var total int64
	err := GetOrmer().Raw(sql, params).QueryRow(&total)
	return total, err
}

// GetProjects returns a project list according to the query conditions
func GetProjects(query *models.ProjectQueryParam, base ...*models.BaseProjectCollection) ([]*models.Project, error) {

	var (
		owner  string
		name   string
		public *bool
		member string
		role   int
		page   int64
		size   int64
	)

	if query != nil {
		owner = query.Owner
		name = query.Name
		public = query.Public
		if query.Member != nil {
			member = query.Member.Name
			role = query.Member.Role
		}
		if query.Pagination != nil {
			page = query.Pagination.Page
			size = query.Pagination.Size
		}
	}

	sql, params := projectQueryConditions(owner, name, public, member, role, base...)

	sql = `select distinct p.project_id, p.name, p.public, p.owner_id,
				p.creation_time, p.update_time ` + sql
	if size > 0 {
		sql += ` limit ?`
		params = append(params, size)

		if page > 0 {
			sql += ` offset ?`
			params = append(params, (page-1)*size)
		}
	}

	var projects []*models.Project
	_, err := GetOrmer().Raw(sql, params).QueryRows(&projects)
	return projects, err
}

func projectQueryConditions(owner, name string, public *bool, member string,
	role int, base ...*models.BaseProjectCollection) (string, []interface{}) {
	params := []interface{}{}

	// the base project collections:
	// 1. all projects
	// 2. public projects
	// 3. public projects and projects which the user is a member of
	collection := `project `
	if len(base) != 0 && base[0] != nil {
		if len(base[0].Member) == 0 && base[0].Public {
			collection = `(select * from project pr
					where pr.public=1) `
		}
		if len(base[0].Member) > 0 && base[0].Public {
			collection = `(select pr.project_id, pr.owner_id, pr.name, pr.
						creation_time, pr.update_time, pr.deleted, pr.public
					from project pr
					join project_member prm
						on pr.project_id = prm.project_id
					join user ur
						on prm.user_id=ur.user_id
					where ur.username=?  or pr.public=1 )`
			params = append(params, base[0].Member)
		}
	}

	sql := ` from ` + collection + ` as p`

	if len(owner) != 0 {
		sql += ` join user u1
					on p.owner_id = u1.user_id`
	}

	if len(member) != 0 {
		sql += ` join project_member pm
					on p.project_id = pm.project_id
					join user u2
					on pm.user_id=u2.user_id`
	}
	sql += ` where p.deleted=0`

	if len(owner) != 0 {
		sql += ` and u1.username=?`
		params = append(params, owner)
	}

	if len(name) != 0 {
		sql += ` and p.name like ?`
		params = append(params, "%"+escape(name)+"%")
	}

	if public != nil {
		sql += ` and p.public = ?`
		if *public {
			params = append(params, 1)
		} else {
			params = append(params, 0)
		}
	}

	if len(member) != 0 {
		sql += ` and u2.username=?`
		params = append(params, member)

		if role > 0 {
			sql += ` and pm.role = ?`
			roleID := 0
			switch role {
			case common.RoleProjectAdmin:
				roleID = 1
			case common.RoleDeveloper:
				roleID = 2
			case common.RoleGuest:
				roleID = 3

			}
			params = append(params, roleID)
		}
	}

	sql += ` order by p.name`

	return sql, params
}

// DeleteProject ...
func DeleteProject(id int64) error {
	project, err := GetProjectByID(id)
	if err != nil {
		return err
	}

	name := fmt.Sprintf("%s#%d", project.Name, project.ProjectID)

	sql := `update project
		set deleted = 1, name = ?
		where project_id = ?`
	_, err = GetOrmer().Raw(sql, name, id).Exec()
	return err
}
<|endoftext|>


<commit_before>package web

import (
	"errors"
	"math/rand"
	"net/http"
	"regexp"
	"strings"
	"time"

	"github.com/micro/go-micro/v2/api/resolver"
	res "github.com/micro/go-micro/v2/api/resolver"
	"github.com/micro/go-micro/v2/registry"
	"github.com/micro/go-micro/v2/router"
	// "github.com/micro/go-micro/v2/selector"
)

var re = regexp.MustCompile("^[a-zA-Z0-9]+([a-zA-Z0-9-]*[a-zA-Z0-9]*)?$")

type Resolver struct {
	// Options
	Options resolver.Options
	// selector to choose from a pool of nodes
	// Selector selector.Selector
	// router to lookup routes
	Router router.Router
}

func (r *Resolver) String() string {
	return "web/resolver"
}

// Resolve replaces the values of Host, Path, Scheme to calla backend service
// It accounts for subdomains for service names based on namespace
func (r *Resolver) Resolve(req *http.Request, opts ...res.ResolveOption) (*res.Endpoint, error) {
	// parse the options
	options := resolver.NewResolveOptions(opts...)

	parts := strings.Split(req.URL.Path, "/")
	if len(parts) < 2 {
		return nil, errors.New("unknown service")
	}

	if !re.MatchString(parts[1]) {
		return nil, res.ErrInvalidPath
	}

	// lookup the routes for the service
	query := []router.QueryOption{
		router.QueryService(r.Options.ServicePrefix + "." + parts[1]),
		router.QueryNetwork(options.Domain),
	}

	routes, err := r.Router.Lookup(query...)
	if err == router.ErrRouteNotFound {
		return nil, res.ErrNotFound
	} else if err != nil {
		return nil, err
	} else if len(routes) == 0 {
		return nil, res.ErrNotFound
	}

	// select a random route to use
	// todo: update to use selector once go-micro has updated the interface
	// route, err := r.Selector.Select(routes...)
	// if err != nil {
	// 	return nil, err
	// }
	rand.Seed(time.Now().UnixNano())
	route := routes[rand.Intn(len(routes))]

	// we're done
	return &res.Endpoint{
		Name:   parts[1],
		Method: req.Method,
		Host:   route.Address,
		Path:   "/" + strings.Join(parts[2:], "/"),
		Domain: registry.DefaultDomain,
	}, nil
}
<commit_msg>Update internal/resolver/web/resolver.go<commit_after>package web

import (
	"errors"
	"math/rand"
	"net/http"
	"regexp"
	"strings"
	"time"

	"github.com/micro/go-micro/v2/api/resolver"
	res "github.com/micro/go-micro/v2/api/resolver"
	"github.com/micro/go-micro/v2/registry"
	"github.com/micro/go-micro/v2/router"
)

var re = regexp.MustCompile("^[a-zA-Z0-9]+([a-zA-Z0-9-]*[a-zA-Z0-9]*)?$")

type Resolver struct {
	// Options
	Options resolver.Options
	// selector to choose from a pool of nodes
	// Selector selector.Selector
	// router to lookup routes
	Router router.Router
}

func (r *Resolver) String() string {
	return "web/resolver"
}

// Resolve replaces the values of Host, Path, Scheme to calla backend service
// It accounts for subdomains for service names based on namespace
func (r *Resolver) Resolve(req *http.Request, opts ...res.ResolveOption) (*res.Endpoint, error) {
	// parse the options
	options := resolver.NewResolveOptions(opts...)

	parts := strings.Split(req.URL.Path, "/")
	if len(parts) < 2 {
		return nil, errors.New("unknown service")
	}

	if !re.MatchString(parts[1]) {
		return nil, res.ErrInvalidPath
	}

	// lookup the routes for the service
	query := []router.QueryOption{
		router.QueryService(r.Options.ServicePrefix + "." + parts[1]),
		router.QueryNetwork(options.Domain),
	}

	routes, err := r.Router.Lookup(query...)
	if err == router.ErrRouteNotFound {
		return nil, res.ErrNotFound
	} else if err != nil {
		return nil, err
	} else if len(routes) == 0 {
		return nil, res.ErrNotFound
	}

	// select a random route to use
	// todo: update to use selector once go-micro has updated the interface
	// route, err := r.Selector.Select(routes...)
	// if err != nil {
	// 	return nil, err
	// }
	rand.Seed(time.Now().UnixNano())
	route := routes[rand.Intn(len(routes))]

	// we're done
	return &res.Endpoint{
		Name:   parts[1],
		Method: req.Method,
		Host:   route.Address,
		Path:   "/" + strings.Join(parts[2:], "/"),
		Domain: registry.DefaultDomain,
	}, nil
}
<|endoftext|>


<commit_before>package web

import (
	"errors"
	"net"
	"net/http"
	"regexp"
	"strings"

	res "github.com/micro/go-micro/v2/api/resolver"
	"github.com/micro/go-micro/v2/auth"
	"github.com/micro/go-micro/v2/client/selector"
	"golang.org/x/net/publicsuffix"
)

var (
	re               = regexp.MustCompile("^[a-zA-Z0-9]+([a-zA-Z0-9-]*[a-zA-Z0-9]*)?$")
	defaultNamespace = auth.DefaultNamespace + ".web"
)

type Resolver struct {
	// Type of resolver e.g path, domain
	Type string
	// a function which returns the namespace of the request
	Namespace func(*http.Request) string
	// selector to find services
	Selector selector.Selector
}

func reverse(s []string) {
	for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
		s[i], s[j] = s[j], s[i]
	}
}

func (r *Resolver) String() string {
	return "web/resolver"
}

// Info checks whether this is a web request.
// It returns host, namespace and whether its internal
func (r *Resolver) Info(req *http.Request) (string, string, bool) {
	// set to host
	host := req.URL.Hostname()

	// set as req.Host if blank
	if len(host) == 0 {
		host = req.Host
	}

	// split out ip
	if h, _, err := net.SplitHostPort(host); err == nil {
		host = h
	}

	// determine the namespace of the request
	namespace := r.Namespace(req)

	// overide host if the namespace is go.micro.web, since
	// this will also catch localhost & 127.0.0.1, resulting
	// in a more consistent dev experience
	if host == "localhost" || host == "127.0.0.1" {
		host = "web.micro.mu"
	}

	// if the type is path, always resolve using the path
	if r.Type == "path" {
		return host, namespace, true
	}

	// if the namespace is not the default (go.micro.web),
	// we always resolve using path
	if namespace != defaultNamespace {
		return host, namespace, true
	}

	// check to see if this request is for a micro.mu subdomain
	if host != "web.micro.mu" {
		return host, namespace, false
	}

	// Check if the request is a top level path
	isWeb := strings.Count(req.URL.Path, "/") == 1
	return host, namespace, isWeb
}

// Resolve replaces the values of Host, Path, Scheme to calla backend service
// It accounts for subdomains for service names based on namespace
func (r *Resolver) Resolve(req *http.Request) (*res.Endpoint, error) {
	// get host, namespace and if its an internal request
	host, namespace, webReq := r.Info(req)

	// use path based resolution if its web dashboard related.
	if webReq {
		parts := strings.Split(req.URL.Path, "/")
		if len(parts) < 2 {
			return nil, errors.New("unknown service")
		}

		if !re.MatchString(parts[1]) {
			return nil, res.ErrInvalidPath
		}

		next, err := r.Selector.Select(namespace + "." + parts[1])
		if err == selector.ErrNotFound {
			return nil, res.ErrNotFound
		} else if err != nil {
			return nil, err
		}

		// TODO: better retry strategy
		s, err := next()
		if err != nil {
			return nil, err
		}

		// we're done
		return &res.Endpoint{
			Name:   parts[1],
			Method: req.Method,
			Host:   s.Address,
			Path:   "/" + strings.Join(parts[2:], "/"),
		}, nil
	}

	domain, err := publicsuffix.EffectiveTLDPlusOne(host)
	if err != nil {
		return nil, err
	}

	// get and reverse the subdomain
	subdomain := strings.TrimSuffix(host, "."+domain)
	parts := strings.Split(subdomain, ".")
	reverse(parts)

	// turn it into an alias
	alias := strings.Join(parts, ".")
	if len(alias) == 0 {
		return nil, errors.New("unknown host")
	}

	// set name to lookup
	name := defaultNamespace + "." + alias

	// get namespace + subdomain
	next, err := r.Selector.Select(name)
	if err == selector.ErrNotFound {
		return nil, res.ErrNotFound
	} else if err != nil {
		return nil, err
	}

	// TODO: better retry strategy
	s, err := next()
	if err != nil {
		return nil, err
	}

	// we're done
	return &res.Endpoint{
		Name:   alias,
		Method: req.Method,
		Host:   s.Address,
		Path:   req.URL.Path,
	}, nil
}
<commit_msg>Fallback to path resolution (#769)<commit_after>package web

import (
	"errors"
	"net"
	"net/http"
	"regexp"
	"strings"

	res "github.com/micro/go-micro/v2/api/resolver"
	"github.com/micro/go-micro/v2/auth"
	"github.com/micro/go-micro/v2/client/selector"
	"golang.org/x/net/publicsuffix"
)

var (
	re               = regexp.MustCompile("^[a-zA-Z0-9]+([a-zA-Z0-9-]*[a-zA-Z0-9]*)?$")
	defaultNamespace = auth.DefaultNamespace + ".web"
)

type Resolver struct {
	// Type of resolver e.g path, domain
	Type string
	// a function which returns the namespace of the request
	Namespace func(*http.Request) string
	// selector to find services
	Selector selector.Selector
}

func reverse(s []string) {
	for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
		s[i], s[j] = s[j], s[i]
	}
}

func (r *Resolver) String() string {
	return "web/resolver"
}

// Info checks whether this is a web request.
// It returns host, namespace and whether its internal
func (r *Resolver) Info(req *http.Request) (string, string, bool) {
	// set to host
	host := req.URL.Hostname()

	// set as req.Host if blank
	if len(host) == 0 {
		host = req.Host
	}

	// split out ip
	if h, _, err := net.SplitHostPort(host); err == nil {
		host = h
	}

	// determine the namespace of the request
	namespace := r.Namespace(req)

	// overide host if the namespace is go.micro.web, since
	// this will also catch localhost & 127.0.0.1, resulting
	// in a more consistent dev experience
	if host == "localhost" || host == "127.0.0.1" {
		host = "web.micro.mu"
	}

	// if the type is path, always resolve using the path
	if r.Type == "path" {
		return host, namespace, true
	}

	// if the namespace is not the default (go.micro.web),
	// we always resolve using path
	if namespace != defaultNamespace {
		return host, namespace, true
	}

	// check to see if this request is for a micro.mu subdomain
	if host != "web.micro.mu" {
		return host, namespace, false
	}

	// Check if the request is a top level path
	isWeb := strings.Count(req.URL.Path, "/") == 1
	return host, namespace, isWeb
}

// Resolve replaces the values of Host, Path, Scheme to calla backend service
// It accounts for subdomains for service names based on namespace
func (r *Resolver) Resolve(req *http.Request) (*res.Endpoint, error) {
	// get host, namespace and if its an internal request
	host, _, webReq := r.Info(req)

	// use path based resolution if its web dashboard related.
	if webReq {
		return r.resolveWithPath(req)
	}

	domain, err := publicsuffix.EffectiveTLDPlusOne(host)
	if err != nil {
		return nil, err
	}

	// get and reverse the subdomain
	subdomain := strings.TrimSuffix(host, "."+domain)
	parts := strings.Split(subdomain, ".")
	reverse(parts)

	// turn it into an alias
	alias := strings.Join(parts, ".")
	if len(alias) == 0 {
		return nil, errors.New("unknown host")
	}

	// set name to lookup
	name := defaultNamespace + "." + alias

	// get namespace + subdomain
	next, err := r.Selector.Select(name)
	if err == selector.ErrNotFound {
		// fallback to path based
		return r.resolveWithPath(req)
	} else if err != nil {
		return nil, err
	}

	// TODO: better retry strategy
	s, err := next()
	if err != nil {
		return nil, err
	}

	// we're done
	return &res.Endpoint{
		Name:   alias,
		Method: req.Method,
		Host:   s.Address,
		Path:   req.URL.Path,
	}, nil
}

func (r *Resolver) resolveWithPath(req *http.Request) (*res.Endpoint, error) {
	parts := strings.Split(req.URL.Path, "/")
	if len(parts) < 2 {
		return nil, errors.New("unknown service")
	}

	if !re.MatchString(parts[1]) {
		return nil, res.ErrInvalidPath
	}

	_, namespace, _ := r.Info(req)
	next, err := r.Selector.Select(namespace + "." + parts[1])
	if err == selector.ErrNotFound {
		return nil, res.ErrNotFound
	} else if err != nil {
		return nil, err
	}

	// TODO: better retry strategy
	s, err := next()
	if err != nil {
		return nil, err
	}

	// we're done
	return &res.Endpoint{
		Name:   parts[1],
		Method: req.Method,
		Host:   s.Address,
		Path:   "/" + strings.Join(parts[2:], "/"),
	}, nil
}
<|endoftext|>


<commit_before>package version

import (
	"sort"

	"github.com/kezhuw/leveldb/internal/endian"
	"github.com/kezhuw/leveldb/internal/iterator"
	"github.com/kezhuw/leveldb/internal/keys"
	"github.com/kezhuw/leveldb/internal/options"
	"github.com/kezhuw/leveldb/internal/table"
)

type fileIterator struct {
	open    bool
	icmp    keys.Comparator
	index   int
	files   []FileMeta
	cache   *table.Cache
	opts    *options.ReadOptions
	scratch [16]byte
}

func (it *fileIterator) First() bool {
	it.open = true
	it.index = 0
	return true
}

func (it *fileIterator) Last() bool {
	it.open = true
	it.index = len(it.files) - 1
	return true
}

func (it *fileIterator) Next() bool {
	if !it.open {
		return it.First()
	}
	it.index++
	return it.Valid()
}

func (it *fileIterator) Prev() bool {
	if !it.open {
		return it.Last()
	}
	it.index--
	return it.Valid()
}

func (it *fileIterator) Seek(ikey []byte) bool {
	it.open = true
	it.index = sort.Search(len(it.files), func(i int) bool { return it.icmp.Compare(ikey, it.files[i].Largest) <= 0 })
	return it.Valid()
}

func (it *fileIterator) Valid() bool {
	return it.index >= 0 && it.index < len(it.files)
}

func (it *fileIterator) Key() []byte {
	return it.files[it.index].Largest
}

func (it *fileIterator) Value() []byte {
	endian.PutUint64(it.scratch[:8], it.files[it.index].Number)
	endian.PutUint64(it.scratch[8:], it.files[it.index].Size)
	return it.scratch[:]
}

func (it *fileIterator) child(value []byte) iterator.Iterator {
	fileNumber := endian.Uint64(value[:8])
	fileSize := endian.Uint64(value[8:])
	return it.cache.NewIterator(fileNumber, fileSize, it.opts)
}

func (it *fileIterator) Err() error {
	return nil
}

func (it *fileIterator) Release() error {
	it.index = 0
	it.icmp = nil
	it.files = nil
	return nil
}

func newFileIterator(files []FileMeta, icmp keys.Comparator) iterator.Iterator {
	n := len(files)
	if n == 0 {
		return iterator.Empty()
	}
	return &fileIterator{icmp: icmp, files: files}
}

func newSortedFileIterator(icmp keys.Comparator, files []FileMeta, cache *table.Cache, opts *options.ReadOptions) iterator.Iterator {
	n := len(files)
	if n == 0 {
		return iterator.Empty()
	}
	index := &fileIterator{icmp: icmp, files: files, cache: cache, opts: opts}
	return iterator.NewIndexIterator(index, index.child)
}
<commit_msg>Unlink all references in file iterator's Release<commit_after>package version

import (
	"sort"

	"github.com/kezhuw/leveldb/internal/endian"
	"github.com/kezhuw/leveldb/internal/iterator"
	"github.com/kezhuw/leveldb/internal/keys"
	"github.com/kezhuw/leveldb/internal/options"
	"github.com/kezhuw/leveldb/internal/table"
)

type fileIterator struct {
	open    bool
	icmp    keys.Comparator
	index   int
	files   []FileMeta
	cache   *table.Cache
	opts    *options.ReadOptions
	scratch [16]byte
}

func (it *fileIterator) First() bool {
	it.open = true
	it.index = 0
	return true
}

func (it *fileIterator) Last() bool {
	it.open = true
	it.index = len(it.files) - 1
	return true
}

func (it *fileIterator) Next() bool {
	if !it.open {
		return it.First()
	}
	it.index++
	return it.Valid()
}

func (it *fileIterator) Prev() bool {
	if !it.open {
		return it.Last()
	}
	it.index--
	return it.Valid()
}

func (it *fileIterator) Seek(ikey []byte) bool {
	it.open = true
	it.index = sort.Search(len(it.files), func(i int) bool { return it.icmp.Compare(ikey, it.files[i].Largest) <= 0 })
	return it.Valid()
}

func (it *fileIterator) Valid() bool {
	return it.index >= 0 && it.index < len(it.files)
}

func (it *fileIterator) Key() []byte {
	return it.files[it.index].Largest
}

func (it *fileIterator) Value() []byte {
	endian.PutUint64(it.scratch[:8], it.files[it.index].Number)
	endian.PutUint64(it.scratch[8:], it.files[it.index].Size)
	return it.scratch[:]
}

func (it *fileIterator) child(value []byte) iterator.Iterator {
	fileNumber := endian.Uint64(value[:8])
	fileSize := endian.Uint64(value[8:])
	return it.cache.NewIterator(fileNumber, fileSize, it.opts)
}

func (it *fileIterator) Err() error {
	return nil
}

func (it *fileIterator) Release() error {
	it.opts = nil
	it.icmp = nil
	it.files = nil
	it.index = 0
	it.cache = nil
	return nil
}

func newFileIterator(files []FileMeta, icmp keys.Comparator) iterator.Iterator {
	n := len(files)
	if n == 0 {
		return iterator.Empty()
	}
	return &fileIterator{icmp: icmp, files: files}
}

func newSortedFileIterator(icmp keys.Comparator, files []FileMeta, cache *table.Cache, opts *options.ReadOptions) iterator.Iterator {
	n := len(files)
	if n == 0 {
		return iterator.Empty()
	}
	index := &fileIterator{icmp: icmp, files: files, cache: cache, opts: opts}
	return iterator.NewIndexIterator(index, index.child)
}
<|endoftext|>


<commit_before>package parser

import (
	"reflect"
	"strings"
	"testing"

	"github.com/elpinal/coco3/extra/ast"
)

func TestParse(t *testing.T) {
	tests := []struct {
		src  string
		name string
		args []ast.Expr
	}{
		{
			src:  "aa 'b'",
			name: "aa",
			args: []ast.Expr{&ast.String{Lit: "b"}},
		},
		{
			src:  "a 'u' : 'v' : []",
			name: "a",
			args: []ast.Expr{
				&ast.Cons{
					Head: "u",
					Tail: &ast.Cons{
						Head: "v",
						Tail: &ast.Empty{},
					},
				},
			},
		},
		{
			src:  "a-b ['u', 'v']",
			name: "a-b",
			args: []ast.Expr{
				&ast.Cons{
					Head: "u",
					Tail: &ast.Cons{
						Head: "v",
						Tail: &ast.Empty{},
					},
				},
			},
		},
		{
			src:  "a-b1-2190 [''] 8",
			name: "a-b1-2190",
			args: []ast.Expr{
				&ast.Cons{
					Head: "",
					Tail: &ast.Empty{},
				},
				&ast.Int{
					Lit: "8",
				},
			},
		},
		{
			src:  `a '{{range .Imports}}{{. | printf "%s\\n"}}{{end}}'`,
			name: "a",
			args: []ast.Expr{
				&ast.String{
					Lit: `{{range .Imports}}{{. | printf "%s\n"}}{{end}}`,
				},
			},
		},
		{
			src:  "!cmd",
			name: "exec",
			args: []ast.Expr{&ast.String{Lit: "cmd"}},
		},
		{
			src:  "!cmd []",
			name: "exec",
			args: []ast.Expr{&ast.String{Lit: "cmd"}, &ast.Empty{}},
		},
		{
			src:  "! cmd ['arg']",
			name: "exec",
			args: []ast.Expr{
				&ast.String{Lit: "cmd"},
				&ast.Cons{Head: "arg", Tail: &ast.Empty{}},
			},
		},
	}
	for _, test := range tests {
		x, err := Parse([]byte(test.src))
		if err != nil {
			t.Fatalf("Parse(%q): %v", test.src, err)
		}
		if x.Name.Lit != test.name {
			t.Fatalf("Parse(%q).Lit != %s; got %s", test.src, test.name, x.Name.Lit)
		}
		if !reflect.DeepEqual(x.Args, test.args) {
			t.Errorf("Parse(%q).Args != %v; got %v", test.src, test.args, x.Args)
		}
	}
}

func TestParseFail(t *testing.T) {
	tests := []string{
		"aa '",
		"'a'",
		"12",
		"a :",
		"a [",
		"a ?--#b",
		`a "bc\3df"`,
		"a ['",
	}
	for _, src := range tests {
		got, err := Parse([]byte(src))
		if err == nil {
			t.Errorf("Parse(%q): unexpectedly succeeded", src)
			t.Fatalf("got: %v", got)
		}
	}
}

func match(s, q string) bool {
	return strings.Contains(s, q)
}

func TestInvalidEscapeSequence(t *testing.T) {
	_, err := Parse([]byte(`a '\Z'`))
	if err == nil {
		t.Fatalf("Parse: unexpectedly succeeded")
	}
	p := `unknown escape sequence: \Z`
	if !match(err.(*ParseError).Msg, p) {
		t.Log("missing message about escape sequence in error message")
		t.Logf("pattern %q not found", p)
		t.FailNow()
	}
}
<commit_msg>Add more fail case<commit_after>package parser

import (
	"reflect"
	"strings"
	"testing"

	"github.com/elpinal/coco3/extra/ast"
)

func TestParse(t *testing.T) {
	tests := []struct {
		src  string
		name string
		args []ast.Expr
	}{
		{
			src:  "aa 'b'",
			name: "aa",
			args: []ast.Expr{&ast.String{Lit: "b"}},
		},
		{
			src:  "a 'u' : 'v' : []",
			name: "a",
			args: []ast.Expr{
				&ast.Cons{
					Head: "u",
					Tail: &ast.Cons{
						Head: "v",
						Tail: &ast.Empty{},
					},
				},
			},
		},
		{
			src:  "a-b ['u', 'v']",
			name: "a-b",
			args: []ast.Expr{
				&ast.Cons{
					Head: "u",
					Tail: &ast.Cons{
						Head: "v",
						Tail: &ast.Empty{},
					},
				},
			},
		},
		{
			src:  "a-b1-2190 [''] 8",
			name: "a-b1-2190",
			args: []ast.Expr{
				&ast.Cons{
					Head: "",
					Tail: &ast.Empty{},
				},
				&ast.Int{
					Lit: "8",
				},
			},
		},
		{
			src:  `a '{{range .Imports}}{{. | printf "%s\\n"}}{{end}}'`,
			name: "a",
			args: []ast.Expr{
				&ast.String{
					Lit: `{{range .Imports}}{{. | printf "%s\n"}}{{end}}`,
				},
			},
		},
		{
			src:  "!cmd",
			name: "exec",
			args: []ast.Expr{&ast.String{Lit: "cmd"}},
		},
		{
			src:  "!cmd []",
			name: "exec",
			args: []ast.Expr{&ast.String{Lit: "cmd"}, &ast.Empty{}},
		},
		{
			src:  "! cmd ['arg']",
			name: "exec",
			args: []ast.Expr{
				&ast.String{Lit: "cmd"},
				&ast.Cons{Head: "arg", Tail: &ast.Empty{}},
			},
		},
	}
	for _, test := range tests {
		x, err := Parse([]byte(test.src))
		if err != nil {
			t.Fatalf("Parse(%q): %v", test.src, err)
		}
		if x.Name.Lit != test.name {
			t.Fatalf("Parse(%q).Lit != %s; got %s", test.src, test.name, x.Name.Lit)
		}
		if !reflect.DeepEqual(x.Args, test.args) {
			t.Errorf("Parse(%q).Args != %v; got %v", test.src, test.args, x.Args)
		}
	}
}

func TestParseFail(t *testing.T) {
	tests := []string{
		"aa '",
		"'a'",
		"12",
		"a :",
		"a [",
		"a ?--#b",
		`a "bc\3df"`,
		"a ['",
		"!",
	}
	for _, src := range tests {
		got, err := Parse([]byte(src))
		if err == nil {
			t.Errorf("Parse(%q): unexpectedly succeeded", src)
			t.Fatalf("got: %v", got)
		}
	}
}

func match(s, q string) bool {
	return strings.Contains(s, q)
}

func TestInvalidEscapeSequence(t *testing.T) {
	_, err := Parse([]byte(`a '\Z'`))
	if err == nil {
		t.Fatalf("Parse: unexpectedly succeeded")
	}
	p := `unknown escape sequence: \Z`
	if !match(err.(*ParseError).Msg, p) {
		t.Log("missing message about escape sequence in error message")
		t.Logf("pattern %q not found", p)
		t.FailNow()
	}
}
<|endoftext|>