<commit_before>package commands

import (
	"errors"
	"flag"
	"fmt"
	"github.com/orchardup/go-orchard/authenticator"
	"github.com/orchardup/go-orchard/proxy"
	"github.com/orchardup/go-orchard/tlsconfig"
	"github.com/orchardup/go-orchard/utils"
	"github.com/orchardup/go-orchard/vendor/crypto/tls"
	"io/ioutil"
	"net"
	"os"
	"os/exec"
	"os/signal"
	"path"
	"strings"
	"syscall"
	"text/tabwriter"
)

type Command struct {
	Run       func(cmd *Command, args []string) error
	UsageLine string
	Short     string
	Long      string
	Flag      flag.FlagSet
}

func (c *Command) Name() string {
	name := c.UsageLine
	i := strings.Index(name, " ")
	if i >= 0 {
		name = name[:i]
	}
	return name
}

func (c *Command) Usage() {
	fmt.Fprintf(os.Stderr, "Usage: %s\n\n", c.UsageLine)
	fmt.Fprintf(os.Stderr, "%s\n", strings.TrimSpace(c.Long))
	os.Exit(2)
}

func (c *Command) UsageError(format string, args ...interface{}) error {
	fmt.Fprintf(os.Stderr, format, args...)
	fmt.Fprintf(os.Stderr, "\nUsage: %s\n", c.UsageLine)
	os.Exit(2)
	return fmt.Errorf(format, args...)
}

var All = []*Command{
	Hosts,
	Docker,
	Proxy,
}

var HostSubcommands = []*Command{
	CreateHost,
	RemoveHost,
}

func init() {
	Hosts.Run = RunHosts
	CreateHost.Run = RunCreateHost
	RemoveHost.Run = RunRemoveHost
	Docker.Run = RunDocker
	Proxy.Run = RunProxy
}

var Hosts = &Command{
	UsageLine: "hosts",
	Short:     "Manage hosts",
	Long: `Manage hosts.

Usage: orchard hosts [COMMAND] [ARGS...]

Commands:
  ls          List hosts (default)
  create      Create a host
  rm          Remove a host

Run 'orchard hosts COMMAND -h' for more information on a command.
`,
}

var CreateHost = &Command{
	UsageLine: "create [-m MEMORY] [NAME]",
	Short:     "Create a host",
	Long: fmt.Sprintf(`Create a host.

You can optionally specify a name for the host - if not, it will be
named 'default', and 'orchard docker' commands will use it automatically.

You can also specify how much RAM the host should have with -m.
Valid amounts are %s.`, validSizes),
}

var flCreateSize = CreateHost.Flag.String("m", "512M", "")
var validSizes = "512M, 1G, 2G, 4G and 8G"

var RemoveHost = &Command{
	UsageLine: "rm [NAME]",
	Short:     "Remove a host",
	Long: `Remove a host.

You can optionally specify which host to remove - if you don't, the default
host (named 'default') will be removed.`,
}

var Docker = &Command{
	UsageLine: "docker [-H HOST] [COMMAND...]",
	Short:     "Run a Docker command against a host",
	Long: `Run a Docker command against a host.

Wraps the 'docker' command-line tool - see the Docker website for reference:

    http://docs.docker.io/en/latest/reference/commandline/

You can optionally specify a host by name - if you don't, the default host
will be used.`,
}

var flDockerHost = Docker.Flag.String("H", "", "")

var Proxy = &Command{
	UsageLine: "proxy [-H HOST]",
	Short:     "Start a local proxy to a host's Docker daemon",
	Long: `Start a local proxy to a host's Docker daemon.

Prints out a URL to pass to the 'docker' command, e.g.

    $ orchard proxy
    Started proxy at unix:///tmp/orchard-12345/orchard.sock

    $ docker -H unix:///tmp/orchard-12345/orchard.sock run ubuntu echo hello world
    hello world
`,
}

var flProxyHost = Proxy.Flag.String("H", "", "")

func RunHosts(cmd *Command, args []string) error {
	list := len(args) == 0 || (len(args) == 1 && args[0] == "ls")

	if !list {
		for _, subcommand := range HostSubcommands {
			if subcommand.Name() == args[0] {
				subcommand.Flag.Usage = func() { subcommand.Usage() }
				subcommand.Flag.Parse(args[1:])
				args = subcommand.Flag.Args()
				err := subcommand.Run(subcommand, args)
				return err
			}
		}

		return fmt.Errorf("Unknown `hosts` subcommand: %s", args[0])
	}

	httpClient, err := authenticator.Authenticate()
	if err != nil {
		return err
	}

	hosts, err := httpClient.GetHosts()
	if err != nil {
		return err
	}

	writer := tabwriter.NewWriter(os.Stdout, 20, 1, 3, ' ', 0)
	fmt.Fprintln(writer, "NAME\tSIZE\tIP")
	for _, host := range hosts {
		fmt.Fprintf(writer, "%s\t%s\t%s\n", host.Name, utils.HumanSize(host.Size*1024*1024), host.IPAddress)
	}
	writer.Flush()

	return nil
}

func RunCreateHost(cmd *Command, args []string) error {
	if len(args) > 1 {
		return cmd.UsageError("`orchard hosts create` expects at most 1 argument, but got more: %s", strings.Join(args[1:], " "))
	}

	httpClient, err := authenticator.Authenticate()
	if err != nil {
		return err
	}

	hostName, humanName := GetHostName(args)
	humanName = utils.Capitalize(humanName)

	size, sizeString := GetHostSize()
	if size == -1 {
		fmt.Fprintf(os.Stderr, "Sorry, %q isn't a size we support.\nValid sizes are %s.\n", sizeString, validSizes)
		return nil
	}

	host, err := httpClient.CreateHost(hostName, size)
	if err != nil {
		// HACK. api.go should decode JSON and return a specific type of error for this case.
		if strings.Contains(err.Error(), "already exists") {
			fmt.Fprintf(os.Stderr, "%s is already running.\nYou can create additional hosts with `orchard hosts create [NAME]`.\n", humanName)
			return nil
		}
		if strings.Contains(err.Error(), "Invalid value") {
			fmt.Fprintf(os.Stderr, "Sorry, '%s' isn't a valid host name.\nHost names can only contain lowercase letters, numbers and underscores.\n", hostName)
			return nil
		}
		if strings.Contains(err.Error(), "Unsupported size") {
			fmt.Fprintf(os.Stderr, "Sorry, %q isn't a size we support.\nValid sizes are %s.\n", sizeString, validSizes)
			return nil
		}

		return err
	}
	fmt.Fprintf(os.Stderr, "%s running at %s\n", humanName, host.IPAddress)

	return nil
}

func RunRemoveHost(cmd *Command, args []string) error {
	if len(args) > 1 {
		return cmd.UsageError("`orchard hosts rm` expects at most 1 argument, but got more: %s", strings.Join(args[1:], " "))
	}

	hostName, humanName := GetHostName(args)

	var confirm string
	fmt.Printf("Going to remove %s. All data on it will be lost.\n", humanName)
	fmt.Print("Are you sure you're ready? [yN] ")
	fmt.Scanln(&confirm)

	if strings.ToLower(confirm) != "y" {
		return nil
	}

	httpClient, err := authenticator.Authenticate()
	if err != nil {
		return err
	}

	err = httpClient.DeleteHost(hostName)
	if err != nil {
		// HACK. api.go should decode JSON and return a specific type of error for this case.
		if strings.Contains(err.Error(), "Not found") {
			fmt.Fprintf(os.Stderr, "%s doesn't seem to be running.\nYou can view your running hosts with `orchard hosts`.\n", utils.Capitalize(humanName))
			return nil
		}

		return err
	}
	fmt.Fprintf(os.Stderr, "Removed %s\n", humanName)

	return nil
}

func RunDocker(cmd *Command, args []string) error {
	return WithDockerProxy(func(socketPath string) error {
		err := CallDocker(args, []string{"DOCKER_HOST=unix://" + socketPath})
		if err != nil {
			return fmt.Errorf("Docker exited with error")
		}
		return nil
	})
}

func RunProxy(cmd *Command, args []string) error {
	if len(args) > 0 {
		return cmd.UsageError("`orchard proxy` doesn't expect any arguments, but got: %s", strings.Join(args, " "))
	}

	return WithDockerProxy(func(socketPath string) error {
		fmt.Fprintln(os.Stderr, "Started proxy at unix://"+socketPath)

		c := make(chan os.Signal)
		signal.Notify(c, syscall.SIGINT, syscall.SIGKILL)
		<-c

		fmt.Fprintln(os.Stderr, "\nStopping proxy")
		return nil
	})
}

func WithDockerProxy(callback func(string) error) error {
	hostName := "default"
	if *flDockerHost != "" {
		hostName = *flDockerHost
	}

	dirname, err := ioutil.TempDir("/tmp", "orchard-")
	if err != nil {
		return fmt.Errorf("Error creating temporary directory: %s\n", err)
	}
	defer os.RemoveAll(dirname)
	socketPath := path.Join(dirname, "orchard.sock")

	p, err := MakeProxy(socketPath, hostName)
	if err != nil {
		return fmt.Errorf("Error starting proxy: %v\n", err)
	}

	go p.Start()
	defer p.Stop()

	if err := <-p.ErrorChannel; err != nil {
		return fmt.Errorf("Error starting proxy: %v\n", err)
	}

	if err := callback(socketPath); err != nil {
		return err
	}

	return nil
}

func MakeProxy(socketPath string, hostName string) (*proxy.Proxy, error) {
	httpClient, err := authenticator.Authenticate()
	if err != nil {
		return nil, err
	}

	host, err := httpClient.GetHost(hostName)
	if err != nil {
		return nil, err
	}
	destination := host.IPAddress + ":4243"

	certData := []byte(host.ClientCert)
	keyData := []byte(host.ClientKey)
	config, err := tlsconfig.GetTLSConfig(certData, keyData)
	if err != nil {
		return nil, err
	}

	return proxy.New(
		func() (net.Listener, error) { return net.Listen("unix", socketPath) },
		func() (net.Conn, error) { return tls.Dial("tcp", destination, config) },
	), nil
}

func CallDocker(args []string, env []string) error {
	dockerPath := GetDockerPath()
	if dockerPath == "" {
		return errors.New("Can't find `docker` executable in $PATH.\nYou might need to install it: http://docs.docker.io/en/latest/installation/#installation-list")
	}

	cmd := exec.Command(dockerPath, args...)
	cmd.Env = env
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	return cmd.Run()
}

func GetDockerPath() string {
	for _, dir := range strings.Split(os.Getenv("PATH"), ":") {
		dockerPath := path.Join(dir, "docker")
		_, err := os.Stat(dockerPath)
		if err == nil {
			return dockerPath
		}
	}
	return ""
}

func GetHostName(args []string) (string, string) {
	hostName := "default"
	humanName := "default host"

	if len(args) > 0 {
		hostName = args[0]
		humanName = fmt.Sprintf("host '%s'", hostName)
	}

	return hostName, humanName
}

func GetHostSize() (int, string) {
	sizeString := *flCreateSize

	bytes, err := utils.RAMInBytes(sizeString)
	if err != nil {
		return -1, sizeString
	}

	megs := bytes / (1024 * 1024)
	if megs < 1 {
		return -1, sizeString
	}

	return int(megs), sizeString
}
<commit_msg>Sensible error in 'orchard docker' if host isn't running<commit_after>package commands

import (
	"errors"
	"flag"
	"fmt"
	"github.com/orchardup/go-orchard/authenticator"
	"github.com/orchardup/go-orchard/proxy"
	"github.com/orchardup/go-orchard/tlsconfig"
	"github.com/orchardup/go-orchard/utils"
	"github.com/orchardup/go-orchard/vendor/crypto/tls"
	"io/ioutil"
	"net"
	"os"
	"os/exec"
	"os/signal"
	"path"
	"strings"
	"syscall"
	"text/tabwriter"
)

type Command struct {
	Run       func(cmd *Command, args []string) error
	UsageLine string
	Short     string
	Long      string
	Flag      flag.FlagSet
}

func (c *Command) Name() string {
	name := c.UsageLine
	i := strings.Index(name, " ")
	if i >= 0 {
		name = name[:i]
	}
	return name
}

func (c *Command) Usage() {
	fmt.Fprintf(os.Stderr, "Usage: %s\n\n", c.UsageLine)
	fmt.Fprintf(os.Stderr, "%s\n", strings.TrimSpace(c.Long))
	os.Exit(2)
}

func (c *Command) UsageError(format string, args ...interface{}) error {
	fmt.Fprintf(os.Stderr, format, args...)
	fmt.Fprintf(os.Stderr, "\nUsage: %s\n", c.UsageLine)
	os.Exit(2)
	return fmt.Errorf(format, args...)
}

var All = []*Command{
	Hosts,
	Docker,
	Proxy,
}

var HostSubcommands = []*Command{
	CreateHost,
	RemoveHost,
}

func init() {
	Hosts.Run = RunHosts
	CreateHost.Run = RunCreateHost
	RemoveHost.Run = RunRemoveHost
	Docker.Run = RunDocker
	Proxy.Run = RunProxy
}

var Hosts = &Command{
	UsageLine: "hosts",
	Short:     "Manage hosts",
	Long: `Manage hosts.

Usage: orchard hosts [COMMAND] [ARGS...]

Commands:
  ls          List hosts (default)
  create      Create a host
  rm          Remove a host

Run 'orchard hosts COMMAND -h' for more information on a command.
`,
}

var CreateHost = &Command{
	UsageLine: "create [-m MEMORY] [NAME]",
	Short:     "Create a host",
	Long: fmt.Sprintf(`Create a host.

You can optionally specify a name for the host - if not, it will be
named 'default', and 'orchard docker' commands will use it automatically.

You can also specify how much RAM the host should have with -m.
Valid amounts are %s.`, validSizes),
}

var flCreateSize = CreateHost.Flag.String("m", "512M", "")
var validSizes = "512M, 1G, 2G, 4G and 8G"

var RemoveHost = &Command{
	UsageLine: "rm [NAME]",
	Short:     "Remove a host",
	Long: `Remove a host.

You can optionally specify which host to remove - if you don't, the default
host (named 'default') will be removed.`,
}

var Docker = &Command{
	UsageLine: "docker [-H HOST] [COMMAND...]",
	Short:     "Run a Docker command against a host",
	Long: `Run a Docker command against a host.

Wraps the 'docker' command-line tool - see the Docker website for reference:

    http://docs.docker.io/en/latest/reference/commandline/

You can optionally specify a host by name - if you don't, the default host
will be used.`,
}

var flDockerHost = Docker.Flag.String("H", "", "")

var Proxy = &Command{
	UsageLine: "proxy [-H HOST]",
	Short:     "Start a local proxy to a host's Docker daemon",
	Long: `Start a local proxy to a host's Docker daemon.

Prints out a URL to pass to the 'docker' command, e.g.

    $ orchard proxy
    Started proxy at unix:///tmp/orchard-12345/orchard.sock

    $ docker -H unix:///tmp/orchard-12345/orchard.sock run ubuntu echo hello world
    hello world
`,
}

var flProxyHost = Proxy.Flag.String("H", "", "")

func RunHosts(cmd *Command, args []string) error {
	list := len(args) == 0 || (len(args) == 1 && args[0] == "ls")

	if !list {
		for _, subcommand := range HostSubcommands {
			if subcommand.Name() == args[0] {
				subcommand.Flag.Usage = func() { subcommand.Usage() }
				subcommand.Flag.Parse(args[1:])
				args = subcommand.Flag.Args()
				err := subcommand.Run(subcommand, args)
				return err
			}
		}

		return fmt.Errorf("Unknown `hosts` subcommand: %s", args[0])
	}

	httpClient, err := authenticator.Authenticate()
	if err != nil {
		return err
	}

	hosts, err := httpClient.GetHosts()
	if err != nil {
		return err
	}

	writer := tabwriter.NewWriter(os.Stdout, 20, 1, 3, ' ', 0)
	fmt.Fprintln(writer, "NAME\tSIZE\tIP")
	for _, host := range hosts {
		fmt.Fprintf(writer, "%s\t%s\t%s\n", host.Name, utils.HumanSize(host.Size*1024*1024), host.IPAddress)
	}
	writer.Flush()

	return nil
}

func RunCreateHost(cmd *Command, args []string) error {
	if len(args) > 1 {
		return cmd.UsageError("`orchard hosts create` expects at most 1 argument, but got more: %s", strings.Join(args[1:], " "))
	}

	httpClient, err := authenticator.Authenticate()
	if err != nil {
		return err
	}

	hostName, humanName := GetHostName(args)
	humanName = utils.Capitalize(humanName)

	size, sizeString := GetHostSize()
	if size == -1 {
		fmt.Fprintf(os.Stderr, "Sorry, %q isn't a size we support.\nValid sizes are %s.\n", sizeString, validSizes)
		return nil
	}

	host, err := httpClient.CreateHost(hostName, size)
	if err != nil {
		// HACK. api.go should decode JSON and return a specific type of error for this case.
		if strings.Contains(err.Error(), "already exists") {
			fmt.Fprintf(os.Stderr, "%s is already running.\nYou can create additional hosts with `orchard hosts create [NAME]`.\n", humanName)
			return nil
		}
		if strings.Contains(err.Error(), "Invalid value") {
			fmt.Fprintf(os.Stderr, "Sorry, '%s' isn't a valid host name.\nHost names can only contain lowercase letters, numbers and underscores.\n", hostName)
			return nil
		}
		if strings.Contains(err.Error(), "Unsupported size") {
			fmt.Fprintf(os.Stderr, "Sorry, %q isn't a size we support.\nValid sizes are %s.\n", sizeString, validSizes)
			return nil
		}

		return err
	}
	fmt.Fprintf(os.Stderr, "%s running at %s\n", humanName, host.IPAddress)

	return nil
}

func RunRemoveHost(cmd *Command, args []string) error {
	if len(args) > 1 {
		return cmd.UsageError("`orchard hosts rm` expects at most 1 argument, but got more: %s", strings.Join(args[1:], " "))
	}

	hostName, humanName := GetHostName(args)

	var confirm string
	fmt.Printf("Going to remove %s. All data on it will be lost.\n", humanName)
	fmt.Print("Are you sure you're ready? [yN] ")
	fmt.Scanln(&confirm)

	if strings.ToLower(confirm) != "y" {
		return nil
	}

	httpClient, err := authenticator.Authenticate()
	if err != nil {
		return err
	}

	err = httpClient.DeleteHost(hostName)
	if err != nil {
		// HACK. api.go should decode JSON and return a specific type of error for this case.
		if strings.Contains(err.Error(), "Not found") {
			fmt.Fprintf(os.Stderr, "%s doesn't seem to be running.\nYou can view your running hosts with `orchard hosts`.\n", utils.Capitalize(humanName))
			return nil
		}

		return err
	}
	fmt.Fprintf(os.Stderr, "Removed %s\n", humanName)

	return nil
}

func RunDocker(cmd *Command, args []string) error {
	return WithDockerProxy(func(socketPath string) error {
		err := CallDocker(args, []string{"DOCKER_HOST=unix://" + socketPath})
		if err != nil {
			return fmt.Errorf("Docker exited with error")
		}
		return nil
	})
}

func RunProxy(cmd *Command, args []string) error {
	if len(args) > 0 {
		return cmd.UsageError("`orchard proxy` doesn't expect any arguments, but got: %s", strings.Join(args, " "))
	}

	return WithDockerProxy(func(socketPath string) error {
		fmt.Fprintln(os.Stderr, "Started proxy at unix://"+socketPath)

		c := make(chan os.Signal)
		signal.Notify(c, syscall.SIGINT, syscall.SIGKILL)
		<-c

		fmt.Fprintln(os.Stderr, "\nStopping proxy")
		return nil
	})
}

func WithDockerProxy(callback func(string) error) error {
	hostName := "default"
	if *flDockerHost != "" {
		hostName = *flDockerHost
	}

	dirname, err := ioutil.TempDir("/tmp", "orchard-")
	if err != nil {
		return fmt.Errorf("Error creating temporary directory: %s\n", err)
	}
	defer os.RemoveAll(dirname)
	socketPath := path.Join(dirname, "orchard.sock")

	p, err := MakeProxy(socketPath, hostName)
	if err != nil {
		return fmt.Errorf("Error starting proxy: %v\n", err)
	}

	go p.Start()
	defer p.Stop()

	if err := <-p.ErrorChannel; err != nil {
		return fmt.Errorf("Error starting proxy: %v\n", err)
	}

	if err := callback(socketPath); err != nil {
		return err
	}

	return nil
}

func MakeProxy(socketPath string, hostName string) (*proxy.Proxy, error) {
	httpClient, err := authenticator.Authenticate()
	if err != nil {
		return nil, err
	}

	host, err := httpClient.GetHost(hostName)
	if err != nil {
		// HACK. api.go should decode JSON and return a specific type of error for this case.
		if strings.Contains(err.Error(), "Not found") {
			humanName := GetHumanHostName(hostName)
			return nil, fmt.Errorf("%s doesn't seem to be running.\nYou can create it with `orchard hosts create %s`.", utils.Capitalize(humanName), hostName)
		}

		return nil, err
	}
	destination := host.IPAddress + ":4243"

	certData := []byte(host.ClientCert)
	keyData := []byte(host.ClientKey)
	config, err := tlsconfig.GetTLSConfig(certData, keyData)
	if err != nil {
		return nil, err
	}

	return proxy.New(
		func() (net.Listener, error) { return net.Listen("unix", socketPath) },
		func() (net.Conn, error) { return tls.Dial("tcp", destination, config) },
	), nil
}

func CallDocker(args []string, env []string) error {
	dockerPath := GetDockerPath()
	if dockerPath == "" {
		return errors.New("Can't find `docker` executable in $PATH.\nYou might need to install it: http://docs.docker.io/en/latest/installation/#installation-list")
	}

	cmd := exec.Command(dockerPath, args...)
	cmd.Env = env
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	return cmd.Run()
}

func GetDockerPath() string {
	for _, dir := range strings.Split(os.Getenv("PATH"), ":") {
		dockerPath := path.Join(dir, "docker")
		_, err := os.Stat(dockerPath)
		if err == nil {
			return dockerPath
		}
	}
	return ""
}

func GetHostName(args []string) (string, string) {
	hostName := "default"

	if len(args) > 0 {
		hostName = args[0]
	}

	return hostName, GetHumanHostName(hostName)
}

func GetHumanHostName(hostName string) string {
	if hostName == "default" {
		return "default host"
	} else {
		return fmt.Sprintf("host '%s'", hostName)
	}
}

func GetHostSize() (int, string) {
	sizeString := *flCreateSize

	bytes, err := utils.RAMInBytes(sizeString)
	if err != nil {
		return -1, sizeString
	}

	megs := bytes / (1024 * 1024)
	if megs < 1 {
		return -1, sizeString
	}

	return int(megs), sizeString
}
<|endoftext|>


<commit_before>// Copyright (c) 2003-2005 Maxim Sobolev. All rights reserved.
// Copyright (c) 2006-2015 Sippy Software, Inc. All rights reserved.
// Copyright (c) 2015 Andrii Pylypenko. All rights reserved.
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation and/or
// other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package sippy

import (
    "time"

    "sippy/conf"
    "sippy/headers"
    "sippy/types"
    "sippy/time"
)

type UacStateIdle struct {
    *uaStateGeneric
    config sippy_conf.Config
}

func NewUacStateIdle(ua sippy_types.UA, config sippy_conf.Config) *UacStateIdle {
    return &UacStateIdle{
        uaStateGeneric  : newUaStateGeneric(ua),
        config          : config,
    }
}

func (self *UacStateIdle) OnActivation() {
}

func (self *UacStateIdle) String() string {
    return "Idle(UAC)"
}

func (self *UacStateIdle) RecvEvent(_event sippy_types.CCEvent) (sippy_types.UaState, error) {
    var err error
    switch event := _event.(type) {
    case *CCEventTry:
        if self.ua.GetSetupTs() == nil {
            self.ua.SetSetupTs(event.rtime)
        }
        self.ua.SetOrigin("callee")
        if event.GetBody() != nil && event.GetBody().NeedsUpdate() && self.ua.HasOnLocalSdpChange() {
            self.ua.OnLocalSdpChange(event.GetBody(), event, func(sippy_types.MsgBody) { self.ua.RecvEvent(event) })
            return nil, nil
        }
        if event.GetSipCallId() == nil {
            self.ua.SetCallId(sippy_header.GenerateSipCallId(self.config))
        } else {
            self.ua.SetCallId(event.GetSipCallId().GetCopy())
        }
        self.ua.SetRTarget(sippy_header.NewSipURL(event.GetCLD(), self.ua.GetRAddr0().Host, self.ua.GetRAddr0().Port, false))
        self.ua.SetRUri(sippy_header.NewSipTo(sippy_header.NewSipAddress("", self.ua.GetRTarget().GetCopy()), self.config))
        if self.ua.GetRuriUserparams() != nil {
            self.ua.GetRTarget().SetUserparams(self.ua.GetRuriUserparams())
        }
        self.ua.GetRUri().GetUrl().Port = nil
        if self.ua.GetToUsername() != "" {
            self.ua.GetRUri().GetUrl().Username = self.ua.GetToUsername()
        }
        self.ua.SetLUri(sippy_header.NewSipFrom(sippy_header.NewSipAddress(event.GetCallerName(), sippy_header.NewSipURL(event.GetCLI(), self.config.GetMyAddress(), self.config.GetMyPort(), false)), self.config))
        self.ua.SipTM().RegConsumer(self.ua, self.ua.GetCallId().CallId)
        self.ua.GetLUri().GetUrl().Port = nil
        if self.ua.GetFromDomain() != "" {
            self.ua.GetLUri().GetUrl().Host = sippy_conf.NewMyAddress(self.ua.GetFromDomain())
        }
        self.ua.GetLUri().SetTag(self.ua.GetLTag())
        self.ua.SetLCSeq(200)
        if self.ua.GetLContact() == nil {
            self.ua.SetLContact(sippy_header.NewSipContact(self.config))
        }
        self.ua.GetLContact().GetUrl().Username = event.GetCLI()
        self.ua.SetRoutes(make([]*sippy_header.SipRoute, 0))
        self.ua.SetCGUID(event.GetSipCiscoGUID())
        self.ua.SetLSDP(event.GetBody())
        eh := event.GetExtraHeaders()
        if event.GetMaxForwards() != nil {
            eh = append(eh, event.GetMaxForwards())
        }
        req := self.ua.GenRequest("INVITE", event.GetBody(), /*nonce*/ "", /*realm*/ "", /*SipXXXAuthorization*/ nil, eh...)
        self.ua.IncLCSeq()
        var tr sippy_types.ClientTransaction
        tr, err = self.ua.SipTM().NewClientTransaction(req, self.ua, self.ua.GetSessionLock(), /*laddress =*/ self.ua.GetSourceAddress(), /*udp_server*/ nil)
        if err != nil {
            return nil, err
        }
        tr.SetOutboundProxy(self.ua.GetOutboundProxy())
        self.ua.SetClientTransaction(tr)
        self.ua.SetAuth(nil)

        if self.ua.GetExpireTime() != 0 {
            self.ua.SetExMtime(event.GetRtime().Add(self.ua.GetExpireTime()))
        }
        if self.ua.GetNoProgressTime() != 0 && (self.ua.GetExpireTime() == 0 || self.ua.GetNoProgressTime() < self.ua.GetExpireTime()) {
            self.ua.SetNpMtime(event.GetRtime().Add(self.ua.GetNoProgressTime()))
        }
        if (self.ua.GetNoReplyTime() != 0 && self.ua.GetNoReplyTime() < time.Duration(32 * time.Second)) &&
          (self.ua.GetExpireTime() == 0 || self.ua.GetNoReplyTime() < self.ua.GetExpireTime()) &&
          (self.ua.GetNoProgressTime() == 0 || self.ua.GetNoReplyTime() < self.ua.GetNoProgressTime()) {
            self.ua.SetNrMtime(event.GetRtime().Add(self.ua.GetNoReplyTime()))
        }
        if self.ua.GetNrMtime() != nil {
            self.ua.StartNoReplyTimer(self.ua.GetNrMtime())
        } else if self.ua.GetNpMtime() != nil {
            self.ua.StartNoProgressTimer(self.ua.GetNpMtime())
        } else if self.ua.GetExMtime() != nil {
            self.ua.StartExpireTimer(self.ua.GetExMtime())
        }
        return NewUacStateTrying(self.ua), nil
    case *CCEventFail:
    case *CCEventRedirect:
    case *CCEventDisconnect:
    default:
        return nil, nil
    }
    if self.ua.GetSetupTs() != nil && ! _event.GetRtime().Before(self.ua.GetSetupTs()) {
        self.ua.SetDisconnectTs(_event.GetRtime())
    } else {
        disconnect_ts, _ := sippy_time.NewMonoTime()
        self.ua.SetDisconnectTs(disconnect_ts)
    }
    return NewUaStateDead(self.ua, _event.GetRtime(), _event.GetOrigin()), nil
}
<commit_msg>Add missed code.<commit_after>// Copyright (c) 2003-2005 Maxim Sobolev. All rights reserved.
// Copyright (c) 2006-2015 Sippy Software, Inc. All rights reserved.
// Copyright (c) 2015 Andrii Pylypenko. All rights reserved.
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation and/or
// other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package sippy

import (
    "time"

    "sippy/conf"
    "sippy/headers"
    "sippy/types"
    "sippy/time"
)

type UacStateIdle struct {
    *uaStateGeneric
    config sippy_conf.Config
}

func NewUacStateIdle(ua sippy_types.UA, config sippy_conf.Config) *UacStateIdle {
    return &UacStateIdle{
        uaStateGeneric  : newUaStateGeneric(ua),
        config          : config,
    }
}

func (self *UacStateIdle) OnActivation() {
}

func (self *UacStateIdle) String() string {
    return "Idle(UAC)"
}

func (self *UacStateIdle) RecvEvent(_event sippy_types.CCEvent) (sippy_types.UaState, error) {
    var err error
    switch event := _event.(type) {
    case *CCEventTry:
        if self.ua.GetSetupTs() == nil {
            self.ua.SetSetupTs(event.rtime)
        }
        self.ua.SetOrigin("callee")
        if event.GetBody() != nil {
            if event.GetBody().NeedsUpdate() && self.ua.HasOnLocalSdpChange() {
                self.ua.OnLocalSdpChange(event.GetBody(), event, func(sippy_types.MsgBody) { self.ua.RecvEvent(event) })
                return nil, nil
            }
        } else {
            self.ua.SetLateMedia(true)
        }
        if event.GetSipCallId() == nil {
            self.ua.SetCallId(sippy_header.GenerateSipCallId(self.config))
        } else {
            self.ua.SetCallId(event.GetSipCallId().GetCopy())
        }
        self.ua.SetRTarget(sippy_header.NewSipURL(event.GetCLD(), self.ua.GetRAddr0().Host, self.ua.GetRAddr0().Port, false))
        self.ua.SetRUri(sippy_header.NewSipTo(sippy_header.NewSipAddress("", self.ua.GetRTarget().GetCopy()), self.config))
        if self.ua.GetRuriUserparams() != nil {
            self.ua.GetRTarget().SetUserparams(self.ua.GetRuriUserparams())
        }
        self.ua.GetRUri().GetUrl().Port = nil
        if self.ua.GetToUsername() != "" {
            self.ua.GetRUri().GetUrl().Username = self.ua.GetToUsername()
        }
        self.ua.SetLUri(sippy_header.NewSipFrom(sippy_header.NewSipAddress(event.GetCallerName(), sippy_header.NewSipURL(event.GetCLI(), self.config.GetMyAddress(), self.config.GetMyPort(), false)), self.config))
        self.ua.SipTM().RegConsumer(self.ua, self.ua.GetCallId().CallId)
        self.ua.GetLUri().GetUrl().Port = nil
        if self.ua.GetFromDomain() != "" {
            self.ua.GetLUri().GetUrl().Host = sippy_conf.NewMyAddress(self.ua.GetFromDomain())
        }
        self.ua.GetLUri().SetTag(self.ua.GetLTag())
        self.ua.SetLCSeq(200)
        if self.ua.GetLContact() == nil {
            self.ua.SetLContact(sippy_header.NewSipContact(self.config))
        }
        self.ua.GetLContact().GetUrl().Username = event.GetCLI()
        self.ua.SetRoutes(make([]*sippy_header.SipRoute, 0))
        self.ua.SetCGUID(event.GetSipCiscoGUID())
        self.ua.SetLSDP(event.GetBody())
        eh := event.GetExtraHeaders()
        if event.GetMaxForwards() != nil {
            eh = append(eh, event.GetMaxForwards())
        }
        req := self.ua.GenRequest("INVITE", event.GetBody(), /*nonce*/ "", /*realm*/ "", /*SipXXXAuthorization*/ nil, eh...)
        self.ua.IncLCSeq()
        var tr sippy_types.ClientTransaction
        tr, err = self.ua.SipTM().NewClientTransaction(req, self.ua, self.ua.GetSessionLock(), /*laddress =*/ self.ua.GetSourceAddress(), /*udp_server*/ nil)
        if err != nil {
            return nil, err
        }
        tr.SetOutboundProxy(self.ua.GetOutboundProxy())
        self.ua.SetClientTransaction(tr)
        self.ua.SetAuth(nil)

        if self.ua.GetExpireTime() != 0 {
            self.ua.SetExMtime(event.GetRtime().Add(self.ua.GetExpireTime()))
        }
        if self.ua.GetNoProgressTime() != 0 && (self.ua.GetExpireTime() == 0 || self.ua.GetNoProgressTime() < self.ua.GetExpireTime()) {
            self.ua.SetNpMtime(event.GetRtime().Add(self.ua.GetNoProgressTime()))
        }
        if (self.ua.GetNoReplyTime() != 0 && self.ua.GetNoReplyTime() < time.Duration(32 * time.Second)) &&
          (self.ua.GetExpireTime() == 0 || self.ua.GetNoReplyTime() < self.ua.GetExpireTime()) &&
          (self.ua.GetNoProgressTime() == 0 || self.ua.GetNoReplyTime() < self.ua.GetNoProgressTime()) {
            self.ua.SetNrMtime(event.GetRtime().Add(self.ua.GetNoReplyTime()))
        }
        if self.ua.GetNrMtime() != nil {
            self.ua.StartNoReplyTimer(self.ua.GetNrMtime())
        } else if self.ua.GetNpMtime() != nil {
            self.ua.StartNoProgressTimer(self.ua.GetNpMtime())
        } else if self.ua.GetExMtime() != nil {
            self.ua.StartExpireTimer(self.ua.GetExMtime())
        }
        return NewUacStateTrying(self.ua), nil
    case *CCEventFail:
    case *CCEventRedirect:
    case *CCEventDisconnect:
    default:
        return nil, nil
    }
    if self.ua.GetSetupTs() != nil && ! _event.GetRtime().Before(self.ua.GetSetupTs()) {
        self.ua.SetDisconnectTs(_event.GetRtime())
    } else {
        disconnect_ts, _ := sippy_time.NewMonoTime()
        self.ua.SetDisconnectTs(disconnect_ts)
    }
    return NewUaStateDead(self.ua, _event.GetRtime(), _event.GetOrigin()), nil
}
<|endoftext|>


<commit_before>package commands

import (
	"bytes"
	"fmt"
	"regexp"
	"strings"

	"github.com/github/hub/utils"
	flag "github.com/ogier/pflag"
)

var (
	NameRe          = "[\\w.][\\w.-]*"
	OwnerRe         = "[a-zA-Z0-9][a-zA-Z0-9-]*"
	NameWithOwnerRe = fmt.Sprintf("^(?:%s|%s\\/%s)$", NameRe, OwnerRe, NameRe)

	CmdRunner = NewRunner()
)

type Command struct {
	Run  func(cmd *Command, args *Args)
	Flag flag.FlagSet

	Key          string
	Usage        string
	Long         string
	GitExtension bool

	subCommands map[string]*Command
}

func (c *Command) Call(args *Args) (err error) {
	runCommand, err := c.lookupSubCommand(args)
	if err != nil {
		return
	}

	if !c.GitExtension {
		err = runCommand.parseArguments(args)
		if err != nil {
			return
		}
	}

	runCommand.Run(runCommand, args)

	return
}

type ErrHelp struct {
	err string
}

func (e ErrHelp) Error() string {
	return e.err
}

func hasFlags(fs *flag.FlagSet) (found bool) {
	fs.VisitAll(func(f *flag.Flag) {
		found = true
	})
	return
}

func (c *Command) parseArguments(args *Args) error {
	if !hasFlags(&c.Flag) {
		args.Flag = utils.NewArgsParserWithUsage("-h, --help\n" + c.Long)
		if rest, err := args.Flag.Parse(args.Params); err == nil {
			if args.Flag.Bool("--help") {
				return &ErrHelp{err: c.Synopsis()}
			}
			args.Params = rest
			args.Terminator = args.Flag.HasTerminated
			return nil
		} else {
			return fmt.Errorf("%s\n%s", err, c.Synopsis())
		}
	}

	c.Flag.SetInterspersed(true)
	c.Flag.Init(c.Name(), flag.ContinueOnError)
	c.Flag.Usage = func() {
	}
	var flagBuf bytes.Buffer
	c.Flag.SetOutput(&flagBuf)

	err := c.Flag.Parse(args.Params)
	if err == nil {
		for _, arg := range args.Params {
			if arg == "--" {
				args.Terminator = true
			}
		}
		args.Params = c.Flag.Args()
	} else if err == flag.ErrHelp {
		err = &ErrHelp{err: c.Synopsis()}
	} else {
		return fmt.Errorf("%s\n%s", err, c.Synopsis())
	}
	return err
}

func (c *Command) FlagPassed(name string) bool {
	found := false
	c.Flag.Visit(func(f *flag.Flag) {
		if f.Name == name {
			found = true
		}
	})
	return found
}

func (c *Command) Use(subCommand *Command) {
	if c.subCommands == nil {
		c.subCommands = make(map[string]*Command)
	}
	c.subCommands[subCommand.Name()] = subCommand
}

func (c *Command) UsageError(msg string) error {
	nl := ""
	if msg != "" {
		nl = "\n"
	}
	return fmt.Errorf("%s%s%s", msg, nl, c.Synopsis())
}

func (c *Command) Synopsis() string {
	lines := []string{}
	usagePrefix := "Usage:"

	for _, line := range strings.Split(c.Usage, "\n") {
		if line != "" {
			usage := fmt.Sprintf("%s hub %s", usagePrefix, line)
			usagePrefix = "      "
			lines = append(lines, usage)
		}
	}
	return strings.Join(lines, "\n")
}

func (c *Command) HelpText() string {
	usage := strings.Replace(c.Usage, "-^", "`-^`", 1)
	usageRe := regexp.MustCompile(`(?m)^([a-z-]+)(.*)$`)
	usage = usageRe.ReplaceAllString(usage, "`hub $1`$2  ")
	usage = strings.TrimSpace(usage)

	var desc string
	long := strings.TrimSpace(c.Long)
	if lines := strings.Split(long, "\n"); len(lines) > 1 {
		desc = lines[0]
		long = strings.Join(lines[1:], "\n")
	}

	long = strings.Replace(long, "'", "`", -1)
	headingRe := regexp.MustCompile(`(?m)^(## .+):$`)
	long = headingRe.ReplaceAllString(long, "$1")

	indentRe := regexp.MustCompile(`(?m)^\t`)
	long = indentRe.ReplaceAllLiteralString(long, "")
	definitionListRe := regexp.MustCompile(`(?m)^(\* )?([^#\s][^\n]*?):?\n\t`)
	long = definitionListRe.ReplaceAllString(long, "$2\n:\t")

	return fmt.Sprintf("hub-%s(1) -- %s\n===\n\n## Synopsis\n\n%s\n%s", c.Name(), desc, usage, long)
}

func (c *Command) Name() string {
	if c.Key != "" {
		return c.Key
	}
	usageLine := strings.Split(strings.TrimSpace(c.Usage), "\n")[0]
	return strings.Split(usageLine, " ")[0]
}

func (c *Command) Runnable() bool {
	return c.Run != nil
}

func (c *Command) lookupSubCommand(args *Args) (runCommand *Command, err error) {
	if len(c.subCommands) > 0 && args.HasSubcommand() {
		subCommandName := args.FirstParam()
		if subCommand, ok := c.subCommands[subCommandName]; ok {
			runCommand = subCommand
			args.Params = args.Params[1:]
		} else {
			err = fmt.Errorf("error: Unknown subcommand: %s", subCommandName)
		}
	} else {
		runCommand = c
	}

	return
}
<commit_msg>Fix usage synopsis for nested commands<commit_after>package commands

import (
	"bytes"
	"fmt"
	"regexp"
	"strings"

	"github.com/github/hub/utils"
	flag "github.com/ogier/pflag"
)

var (
	NameRe          = "[\\w.][\\w.-]*"
	OwnerRe         = "[a-zA-Z0-9][a-zA-Z0-9-]*"
	NameWithOwnerRe = fmt.Sprintf("^(?:%s|%s\\/%s)$", NameRe, OwnerRe, NameRe)

	CmdRunner = NewRunner()
)

type Command struct {
	Run  func(cmd *Command, args *Args)
	Flag flag.FlagSet

	Key          string
	Usage        string
	Long         string
	GitExtension bool

	subCommands   map[string]*Command
	parentCommand *Command
}

func (c *Command) Call(args *Args) (err error) {
	runCommand, err := c.lookupSubCommand(args)
	if err != nil {
		return
	}

	if !c.GitExtension {
		err = runCommand.parseArguments(args)
		if err != nil {
			return
		}
	}

	runCommand.Run(runCommand, args)

	return
}

type ErrHelp struct {
	err string
}

func (e ErrHelp) Error() string {
	return e.err
}

func hasFlags(fs *flag.FlagSet) (found bool) {
	fs.VisitAll(func(f *flag.Flag) {
		found = true
	})
	return
}

func (c *Command) parseArguments(args *Args) error {
	if !hasFlags(&c.Flag) {
		args.Flag = utils.NewArgsParserWithUsage("-h, --help\n" + c.Long)
		if rest, err := args.Flag.Parse(args.Params); err == nil {
			if args.Flag.Bool("--help") {
				return &ErrHelp{err: c.Synopsis()}
			}
			args.Params = rest
			args.Terminator = args.Flag.HasTerminated
			return nil
		} else {
			return fmt.Errorf("%s\n%s", err, c.Synopsis())
		}
	}

	c.Flag.SetInterspersed(true)
	c.Flag.Init(c.Name(), flag.ContinueOnError)
	c.Flag.Usage = func() {
	}
	var flagBuf bytes.Buffer
	c.Flag.SetOutput(&flagBuf)

	err := c.Flag.Parse(args.Params)
	if err == nil {
		for _, arg := range args.Params {
			if arg == "--" {
				args.Terminator = true
			}
		}
		args.Params = c.Flag.Args()
	} else if err == flag.ErrHelp {
		err = &ErrHelp{err: c.Synopsis()}
	} else {
		return fmt.Errorf("%s\n%s", err, c.Synopsis())
	}
	return err
}

func (c *Command) FlagPassed(name string) bool {
	found := false
	c.Flag.Visit(func(f *flag.Flag) {
		if f.Name == name {
			found = true
		}
	})
	return found
}

func (c *Command) Use(subCommand *Command) {
	if c.subCommands == nil {
		c.subCommands = make(map[string]*Command)
	}
	c.subCommands[subCommand.Name()] = subCommand
	subCommand.parentCommand = c
}

func (c *Command) UsageError(msg string) error {
	nl := ""
	if msg != "" {
		nl = "\n"
	}
	return fmt.Errorf("%s%s%s", msg, nl, c.Synopsis())
}

func (c *Command) Synopsis() string {
	lines := []string{}
	usagePrefix := "Usage:"
	usageStr := c.Usage
	if usageStr == "" && c.parentCommand != nil {
		usageStr = c.parentCommand.Usage
	}

	for _, line := range strings.Split(usageStr, "\n") {
		if line != "" {
			usage := fmt.Sprintf("%s hub %s", usagePrefix, line)
			usagePrefix = "      "
			lines = append(lines, usage)
		}
	}
	return strings.Join(lines, "\n")
}

func (c *Command) HelpText() string {
	usage := strings.Replace(c.Usage, "-^", "`-^`", 1)
	usageRe := regexp.MustCompile(`(?m)^([a-z-]+)(.*)$`)
	usage = usageRe.ReplaceAllString(usage, "`hub $1`$2  ")
	usage = strings.TrimSpace(usage)

	var desc string
	long := strings.TrimSpace(c.Long)
	if lines := strings.Split(long, "\n"); len(lines) > 1 {
		desc = lines[0]
		long = strings.Join(lines[1:], "\n")
	}

	long = strings.Replace(long, "'", "`", -1)
	headingRe := regexp.MustCompile(`(?m)^(## .+):$`)
	long = headingRe.ReplaceAllString(long, "$1")

	indentRe := regexp.MustCompile(`(?m)^\t`)
	long = indentRe.ReplaceAllLiteralString(long, "")
	definitionListRe := regexp.MustCompile(`(?m)^(\* )?([^#\s][^\n]*?):?\n\t`)
	long = definitionListRe.ReplaceAllString(long, "$2\n:\t")

	return fmt.Sprintf("hub-%s(1) -- %s\n===\n\n## Synopsis\n\n%s\n%s", c.Name(), desc, usage, long)
}

func (c *Command) Name() string {
	if c.Key != "" {
		return c.Key
	}
	usageLine := strings.Split(strings.TrimSpace(c.Usage), "\n")[0]
	return strings.Split(usageLine, " ")[0]
}

func (c *Command) Runnable() bool {
	return c.Run != nil
}

func (c *Command) lookupSubCommand(args *Args) (runCommand *Command, err error) {
	if len(c.subCommands) > 0 && args.HasSubcommand() {
		subCommandName := args.FirstParam()
		if subCommand, ok := c.subCommands[subCommandName]; ok {
			runCommand = subCommand
			args.Params = args.Params[1:]
		} else {
			err = fmt.Errorf("error: Unknown subcommand: %s", subCommandName)
		}
	} else {
		runCommand = c
	}

	return
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Knative Authors

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

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

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

package ingress

import (
	"testing"

	"k8s.io/apimachinery/pkg/util/intstr"
	"knative.dev/networking/pkg/apis/networking"
	"knative.dev/networking/pkg/apis/networking/v1alpha1"
	"knative.dev/networking/test"
)

// TestMultipleHosts verifies that an Ingress can respond to multiple hosts.
func TestMultipleHosts(t *testing.T) {
	t.Parallel()
	clients := test.Setup(t)

	name, port, cancel := CreateRuntimeService(t, clients, networking.ServicePortNameHTTP1)
	defer cancel()

	// TODO(mattmoor): Once .svc.cluster.local stops being a special case
	// for Visibility, add it here.
	hosts := []string{
		"foo.com",
		"www.foo.com",
		"a-b-1.something-really-really-long.knative.dev",
		"add.your.interesting.domain.here.io",
	}

	// Create a simple Ingress over the Service.
	_, client, cancel := CreateIngressReady(t, clients, v1alpha1.IngressSpec{
		Rules: []v1alpha1.IngressRule{{
			Hosts:      hosts,
			Visibility: v1alpha1.IngressVisibilityExternalIP,
			HTTP: &v1alpha1.HTTPIngressRuleValue{
				Paths: []v1alpha1.HTTPIngressPath{{
					Splits: []v1alpha1.IngressBackendSplit{{
						IngressBackend: v1alpha1.IngressBackend{
							ServiceName:      name,
							ServiceNamespace: test.ServingNamespace,
							ServicePort:      intstr.FromInt(port),
						},
					}},
				}},
			},
		}},
	})
	defer cancel()

	for _, host := range hosts {
		RuntimeRequest(t, client, "http://"+host)
	}
}
<commit_msg>Randomize the hostnames in TestMultipleHosts. (#76)<commit_after>/*
Copyright 2019 The Knative Authors

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

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

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

package ingress

import (
	"testing"

	"k8s.io/apimachinery/pkg/util/intstr"
	"knative.dev/networking/pkg/apis/networking"
	"knative.dev/networking/pkg/apis/networking/v1alpha1"
	"knative.dev/networking/test"
)

// TestMultipleHosts verifies that an Ingress can respond to multiple hosts.
func TestMultipleHosts(t *testing.T) {
	t.Parallel()
	clients := test.Setup(t)

	name, port, cancel := CreateRuntimeService(t, clients, networking.ServicePortNameHTTP1)
	defer cancel()

	// TODO(mattmoor): Once .svc.cluster.local stops being a special case
	// for Visibility, add it here.
	hosts := []string{
		"foo.com",
		"www.foo.com",
		"a-b-1.something-really-really-long.knative.dev",
		"add.your.interesting.domain.here.io",
	}

	// Using fixed hostnames can lead to conflicts when -count=N>1
	// so pseudo-randomize the hostnames to avoid conflicts.
	for i, host := range hosts {
		hosts[i] = name + "." + host
	}

	// Create a simple Ingress over the Service.
	_, client, cancel := CreateIngressReady(t, clients, v1alpha1.IngressSpec{
		Rules: []v1alpha1.IngressRule{{
			Hosts:      hosts,
			Visibility: v1alpha1.IngressVisibilityExternalIP,
			HTTP: &v1alpha1.HTTPIngressRuleValue{
				Paths: []v1alpha1.HTTPIngressPath{{
					Splits: []v1alpha1.IngressBackendSplit{{
						IngressBackend: v1alpha1.IngressBackend{
							ServiceName:      name,
							ServiceNamespace: test.ServingNamespace,
							ServicePort:      intstr.FromInt(port),
						},
					}},
				}},
			},
		}},
	})
	defer cancel()

	for _, host := range hosts {
		RuntimeRequest(t, client, "http://"+host)
	}
}
<|endoftext|>


<commit_before>package classfile

//import "errors"

/*
ClassFile {
    u4             magic;
    u2             minor_version;
    u2             major_version;
    u2             constant_pool_count;
    cp_info        constant_pool[constant_pool_count-1];
    u2             access_flags;
    u2             this_class;
    u2             super_class;
    u2             interfaces_count;
    u2             interfaces[interfaces_count];
    u2             fields_count;
    field_info     fields[fields_count];
    u2             methods_count;
    method_info    methods[methods_count];
    u2             attributes_count;
    attribute_info attributes[attributes_count];
}
*/
type ClassFile struct {
  //magic           uint32
    minorVersion    uint16
    majorVersion    uint16
    constantPool    *ConstantPool
    accessFlags     uint16
    thisClass       uint16
    superClass      uint16
    interfaces      []uint16
    fields          []*FieldInfo
    methods         []*MethodInfo
    attributes      []AttributeInfo
}

func (self *ClassFile) read(reader *ClassReader) {
    self.readAndCheckMagic(reader)
    self.readVersions(reader)
    self.readConstantPool(reader)
    self.accessFlags = reader.readUint16()
    self.thisClass = reader.readUint16()
    self.superClass = reader.readUint16()
    self.readInterfaces(reader)
    self.readFields(reader)
    self.readMethods(reader)
    self.attributes = readAttributes(reader, self.constantPool)
}

func (self *ClassFile) readAndCheckMagic(reader *ClassReader) {
    magic := reader.readUint32()
    if magic != 0xCAFEBABE {
        panic("Bad magic!")
    }
}

func (self *ClassFile) readVersions(reader *ClassReader) {
    self.minorVersion = reader.readUint16()
    self.majorVersion = reader.readUint16()
    // todo check versions
}

func (self *ClassFile) readConstantPool(reader *ClassReader) {
    self.constantPool = &ConstantPool{}
    self.constantPool.read(reader)
}

func (self *ClassFile) readInterfaces(reader *ClassReader) {
    interfacesCount := reader.readUint16()
    self.interfaces = make([]uint16, interfacesCount)
    for i := uint16(0); i < interfacesCount; i++ {
        self.interfaces[i] = reader.readUint16()
    }
}

func (self *ClassFile) readFields(reader *ClassReader) {
    fieldsCount := reader.readUint16()
    self.fields = make([]*FieldInfo, fieldsCount)
    for i := uint16(0); i < fieldsCount; i++ {
        self.fields[i] = &FieldInfo{}
        self.fields[i].read(reader, self.constantPool)
    }
}

func (self *ClassFile) readMethods(reader *ClassReader) {
    methodsCount := reader.readUint16()
    self.methods = make([]*MethodInfo, methodsCount)
    for i := uint16(0); i < methodsCount; i++ {
        self.methods[i] = &MethodInfo{}
        self.methods[i].read(reader, self.constantPool)
    }
}

func (self *ClassFile) ConstantPool() (*ConstantPool) {
    return self.constantPool
}

func (self *ClassFile) SuperClassName() (string) {
    if self.superClass != 0 {
        return self.constantPool.getClassName(self.superClass)
    } else {
        // todo Object
        return ""
    }
}

func (self *ClassFile) InterfaceNames() ([]string) {
    interfaceNames := make([]string, len(self.interfaces))
    for i, cpIndex := range self.interfaces {
        interfaceNames[i] = self.constantPool.getClassName(cpIndex)
    }
    return interfaceNames
}
<commit_msg>use for range<commit_after>package classfile

//import "errors"

/*
ClassFile {
    u4             magic;
    u2             minor_version;
    u2             major_version;
    u2             constant_pool_count;
    cp_info        constant_pool[constant_pool_count-1];
    u2             access_flags;
    u2             this_class;
    u2             super_class;
    u2             interfaces_count;
    u2             interfaces[interfaces_count];
    u2             fields_count;
    field_info     fields[fields_count];
    u2             methods_count;
    method_info    methods[methods_count];
    u2             attributes_count;
    attribute_info attributes[attributes_count];
}
*/
type ClassFile struct {
  //magic           uint32
    minorVersion    uint16
    majorVersion    uint16
    constantPool    *ConstantPool
    accessFlags     uint16
    thisClass       uint16
    superClass      uint16
    interfaces      []uint16
    fields          []*FieldInfo
    methods         []*MethodInfo
    attributes      []AttributeInfo
}

func (self *ClassFile) read(reader *ClassReader) {
    self.readAndCheckMagic(reader)
    self.readVersions(reader)
    self.readConstantPool(reader)
    self.accessFlags = reader.readUint16()
    self.thisClass = reader.readUint16()
    self.superClass = reader.readUint16()
    self.readInterfaces(reader)
    self.readFields(reader)
    self.readMethods(reader)
    self.attributes = readAttributes(reader, self.constantPool)
}

func (self *ClassFile) readAndCheckMagic(reader *ClassReader) {
    magic := reader.readUint32()
    if magic != 0xCAFEBABE {
        panic("Bad magic!")
    }
}

func (self *ClassFile) readVersions(reader *ClassReader) {
    self.minorVersion = reader.readUint16()
    self.majorVersion = reader.readUint16()
    // todo check versions
}

func (self *ClassFile) readConstantPool(reader *ClassReader) {
    self.constantPool = &ConstantPool{}
    self.constantPool.read(reader)
}

func (self *ClassFile) readInterfaces(reader *ClassReader) {
    interfacesCount := reader.readUint16()
    self.interfaces = make([]uint16, interfacesCount)
    for i := range self.interfaces {
        self.interfaces[i] = reader.readUint16()
    }
}

func (self *ClassFile) readFields(reader *ClassReader) {
    fieldsCount := reader.readUint16()
    self.fields = make([]*FieldInfo, fieldsCount)
    for i := range self.fields {
        self.fields[i] = &FieldInfo{}
        self.fields[i].read(reader, self.constantPool)
    }
}

func (self *ClassFile) readMethods(reader *ClassReader) {
    methodsCount := reader.readUint16()
    self.methods = make([]*MethodInfo, methodsCount)
    for i := range self.methods {
        self.methods[i] = &MethodInfo{}
        self.methods[i].read(reader, self.constantPool)
    }
}

func (self *ClassFile) ConstantPool() (*ConstantPool) {
    return self.constantPool
}

func (self *ClassFile) SuperClassName() (string) {
    if self.superClass != 0 {
        return self.constantPool.getClassName(self.superClass)
    } else {
        // todo Object
        return ""
    }
}

func (self *ClassFile) InterfaceNames() ([]string) {
    interfaceNames := make([]string, len(self.interfaces))
    for i, cpIndex := range self.interfaces {
        interfaceNames[i] = self.constantPool.getClassName(cpIndex)
    }
    return interfaceNames
}
<|endoftext|>


<commit_before>// Copyright 2015 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package commands

import (
	"github.com/juju/cmd"
	"github.com/juju/errors"
	"github.com/juju/testing"
	gc "gopkg.in/check.v1"

	"github.com/juju/juju/cmd/modelcmd"
)

var _ = gc.Suite(&commandsSuite{})

type commandsSuite struct {
	stub    *testing.Stub
	command *stubCommand
}

func (s *commandsSuite) SetUpTest(c *gc.C) {
	s.stub = &testing.Stub{}
	s.command = &stubCommand{stub: s.stub}
}

func (s *commandsSuite) TearDownTest(c *gc.C) {
	registeredCommands = nil
	registeredEnvCommands = nil
}

func (s *commandsSuite) TestRegisterCommand(c *gc.C) {
	RegisterCommand(func() cmd.Command {
		return s.command
	})

	// We can't compare functions directly, so...
	c.Check(registeredEnvCommands, gc.HasLen, 0)
	c.Assert(registeredCommands, gc.HasLen, 1)
	command := registeredCommands[0]()
	c.Check(command, gc.Equals, s.command)
}

func (s *commandsSuite) TestRegisterEnvCommand(c *gc.C) {
	RegisterEnvCommand(func() modelcmd.ModelCommand {
		return s.command
	})

	// We can't compare functions directly, so...
	c.Assert(registeredCommands, gc.HasLen, 0)
	c.Assert(registeredEnvCommands, gc.HasLen, 1)
	command := registeredEnvCommands[0]()
	c.Check(command, gc.Equals, s.command)
}

type stubCommand struct {
	modelcmd.ModelCommandBase
	stub    *testing.Stub
	info    *cmd.Info
	envName string
}

func (c *stubCommand) Info() *cmd.Info {
	c.stub.AddCall("Info")
	c.stub.NextErr() // pop one off

	if c.info == nil {
		return &cmd.Info{
			Name: "some-command",
		}
	}
	return c.info
}

func (c *stubCommand) Run(ctx *cmd.Context) error {
	c.stub.AddCall("Run", ctx)
	if err := c.stub.NextErr(); err != nil {
		return errors.Trace(err)
	}

	return nil
}

func (c *stubCommand) SetModelName(name string) error {
	c.stub.AddCall("SetModelName", name)
	c.envName = name
	return c.stub.NextErr()
}

func (c *stubCommand) ModelName() string {
	c.stub.AddCall("ModelName")
	c.stub.NextErr() // pop one off

	return c.envName
}

type stubRegistry struct {
	stub *testing.Stub

	names []string
}

func (r *stubRegistry) Register(subcmd cmd.Command) {
	r.stub.AddCall("Register", subcmd)
	r.stub.NextErr() // pop one off

	r.names = append(r.names, subcmd.Info().Name)
	for _, name := range subcmd.Info().Aliases {
		r.names = append(r.names, name)
	}
}

func (r *stubRegistry) RegisterSuperAlias(name, super, forName string, check cmd.DeprecationCheck) {
	r.stub.AddCall("RegisterSuperAlias", name, super, forName)
	r.stub.NextErr() // pop one off

	r.names = append(r.names, name)
}

func (r *stubRegistry) RegisterDeprecated(subcmd cmd.Command, check cmd.DeprecationCheck) {
	r.stub.AddCall("RegisterDeprecated", subcmd, check)
	r.stub.NextErr() // pop one off

	r.names = append(r.names, subcmd.Info().Name)
	for _, name := range subcmd.Info().Aliases {
		r.names = append(r.names, name)
	}
}
<commit_msg>cmd/juju/commands: More reliable register tests<commit_after>// Copyright 2015 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package commands

import (
	"github.com/juju/cmd"
	"github.com/juju/errors"
	"github.com/juju/testing"
	gc "gopkg.in/check.v1"

	"github.com/juju/juju/cmd/modelcmd"
)

var _ = gc.Suite(&commandsSuite{})

type commandsSuite struct {
	testing.CleanupSuite

	stub    *testing.Stub
	command *stubCommand
}

func (s *commandsSuite) SetUpTest(c *gc.C) {
	s.CleanupSuite.SetUpTest(c)

	s.PatchValue(&registeredCommands, nil)
	s.PatchValue(&registeredEnvCommands, nil)

	s.stub = &testing.Stub{}
	s.command = &stubCommand{stub: s.stub}
}

func (s *commandsSuite) TestRegisterCommand(c *gc.C) {
	RegisterCommand(func() cmd.Command {
		return s.command
	})

	// We can't compare functions directly, so...
	c.Check(registeredEnvCommands, gc.HasLen, 0)
	c.Assert(registeredCommands, gc.HasLen, 1)
	command := registeredCommands[0]()
	c.Check(command, gc.Equals, s.command)
}

func (s *commandsSuite) TestRegisterEnvCommand(c *gc.C) {
	RegisterEnvCommand(func() modelcmd.ModelCommand {
		return s.command
	})

	// We can't compare functions directly, so...
	c.Assert(registeredCommands, gc.HasLen, 0)
	c.Assert(registeredEnvCommands, gc.HasLen, 1)
	command := registeredEnvCommands[0]()
	c.Check(command, gc.Equals, s.command)
}

type stubCommand struct {
	modelcmd.ModelCommandBase
	stub    *testing.Stub
	info    *cmd.Info
	envName string
}

func (c *stubCommand) Info() *cmd.Info {
	c.stub.AddCall("Info")
	c.stub.NextErr() // pop one off

	if c.info == nil {
		return &cmd.Info{
			Name: "some-command",
		}
	}
	return c.info
}

func (c *stubCommand) Run(ctx *cmd.Context) error {
	c.stub.AddCall("Run", ctx)
	if err := c.stub.NextErr(); err != nil {
		return errors.Trace(err)
	}

	return nil
}

func (c *stubCommand) SetModelName(name string) error {
	c.stub.AddCall("SetModelName", name)
	c.envName = name
	return c.stub.NextErr()
}

func (c *stubCommand) ModelName() string {
	c.stub.AddCall("ModelName")
	c.stub.NextErr() // pop one off

	return c.envName
}

type stubRegistry struct {
	stub *testing.Stub

	names []string
}

func (r *stubRegistry) Register(subcmd cmd.Command) {
	r.stub.AddCall("Register", subcmd)
	r.stub.NextErr() // pop one off

	r.names = append(r.names, subcmd.Info().Name)
	for _, name := range subcmd.Info().Aliases {
		r.names = append(r.names, name)
	}
}

func (r *stubRegistry) RegisterSuperAlias(name, super, forName string, check cmd.DeprecationCheck) {
	r.stub.AddCall("RegisterSuperAlias", name, super, forName)
	r.stub.NextErr() // pop one off

	r.names = append(r.names, name)
}

func (r *stubRegistry) RegisterDeprecated(subcmd cmd.Command, check cmd.DeprecationCheck) {
	r.stub.AddCall("RegisterDeprecated", subcmd, check)
	r.stub.NextErr() // pop one off

	r.names = append(r.names, subcmd.Info().Name)
	for _, name := range subcmd.Info().Aliases {
		r.names = append(r.names, name)
	}
}
<|endoftext|>


<commit_before>package keystore

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

	"github.com/appc/spec/schema/types"
)

func newStore() *Keystore {
	storePath, err := ioutil.TempDir(".", "test.store.")
	if err != nil {
		panic(err)
	}

	return New(storePath)
}

func testImport(t *testing.T, prefix types.ACName, subdir string) {
	ks := newStore()
	defer os.RemoveAll(ks.Path)

	for i, key := range sampleKeys {
		fingerprint := sampleKeyFingerprints[i]
		keyPath, err := ks.StoreTrustedKey(prefix, bytes.NewReader([]byte(key)))

		if err != nil {
			t.Errorf("Error storing key #%d: %v\n", i, err)
		}

		expectedPath := filepath.Join(ks.Path, subdir, fingerprint)
		if keyPath != expectedPath {
			t.Errorf("Unexpected key path: %v, expected %v (key %d, store %v, prefix %v, fingerprint %v)\n",
				keyPath, expectedPath, i, ks.Path, prefix, fingerprint)
		}

		if keyBytes, err := ioutil.ReadFile(keyPath); err != nil {
			t.Errorf("Error reading back saved key %d: %v", i, err)
		} else if string(keyBytes) != key {
			t.Errorf("Saved key %d different than original", i)
		}
	}
}

func TestImportRoot(t *testing.T) {
	testImport(t, Root, "_")
}

func TestImportPrefix(t *testing.T) {
	testImport(t, types.ACName("example.com"), "_example.com")
}

func TestImportPrefixEscaped(t *testing.T) {
	testImport(t, types.ACName("example.com/foo"), "_example.com%2Ffoo")
}

func checkKeyCount(t *testing.T, ks *Keystore, expected map[types.ACName]int) {
	for name, expectedKeys := range expected {
		if kr, err := ks.GetKeyring(name); err != nil {
			t.Errorf("Error getting keyring for %v: %v\n", name, err)
		} else if actualKeys := kr.Len(); actualKeys != expectedKeys {
			t.Errorf("Expected %d keys for %v, got %d instead\n", expectedKeys, name, actualKeys)
		}
	}
}

func TestGetKeyring(t *testing.T) {
	ks := newStore()
	defer os.RemoveAll(ks.Path)

	if _, err := ks.StoreTrustedKey(types.ACName("example.com/foo"), bytes.NewReader([]byte(sampleKeys[0]))); err != nil {
		t.Errorf("Error storing key: %v\n", err)
	}

	if _, err := ks.StoreTrustedKey(types.ACName("example.com/foo/bar"), bytes.NewReader([]byte(sampleKeys[1]))); err != nil {
		t.Errorf("Error storing key: %v\n", err)
	}

	checkKeyCount(t, ks, map[types.ACName]int{
		types.ACName("eggsample.com"):           0,
		types.ACName("eggsample.com/foo"):       0,
		types.ACName("eggsample.com/foo/bar"):   0,
		types.ACName("example.com"):             0,
		types.ACName("example.com/foo"):         1,
		types.ACName("example.com/foo/baz"):     1,
		types.ACName("example.com/foo/bar"):     2,
		types.ACName("example.com/foo/bar/baz"): 2,
		types.ACName("example.com/foobar"):      1,
		types.ACName("example.com/baz"):         0,
	})

	if _, err := ks.StoreTrustedKey(Root, bytes.NewReader([]byte(sampleKeys[2]))); err != nil {
		t.Errorf("Error storing key: %v\n", err)
	}

	checkKeyCount(t, ks, map[types.ACName]int{
		types.ACName("eggsample.com"):           1,
		types.ACName("eggsample.com/foo"):       1,
		types.ACName("eggsample.com/foo/bar"):   1,
		types.ACName("example.com"):             1,
		types.ACName("example.com/foo"):         2,
		types.ACName("example.com/foo/baz"):     2,
		types.ACName("example.com/foo/bar"):     3,
		types.ACName("example.com/foo/bar/baz"): 3,
		types.ACName("example.com/foobar"):      2,
		types.ACName("example.com/baz"):         1,
	})
}

func countKeys(kr *Keyring) map[types.ACName]int {
	rv := make(map[types.ACName]int)
	for _, prefix := range kr.prefixes {
		rv[prefix] = rv[prefix] + 1
	}
	return rv
}

func TestGetAllKeyrings(t *testing.T) {
	ks := newStore()
	defer os.RemoveAll(ks.Path)

	prefix := types.ACName("example.com/foo")

	if _, err := ks.StoreTrustedKey(prefix, bytes.NewReader([]byte(sampleKeys[0]))); err != nil {
		t.Errorf("Error storing key: %v\n", err)
	}

	if _, err := ks.StoreTrustedKey(prefix, bytes.NewReader([]byte(sampleKeys[1]))); err != nil {
		t.Errorf("Error storing key: %v\n", err)
	}

	if _, err := ks.StoreTrustedKey(Root, bytes.NewReader([]byte(sampleKeys[2]))); err != nil {
		t.Errorf("Error storing key: %v\n", err)
	}

	kr, err := ks.GetKeyring(Root)
	if err != nil {
		t.Errorf("Error getting all keyrings: %v\n", err)
		t.FailNow()
	}

	kc := countKeys(kr)

	if len(kc) != 2 {
		t.Errorf("Got %d keyrings, expected 2: %v\n", len(kc), kc)
	}

	if rkc, ok := kc[Root]; !ok {
		t.Error("No root keyring")
	} else if rkc != 1 {
		t.Error("Root keyring %d long, expected 1\n", rkc)
	}

	if pkc, ok := kc[prefix]; !ok {
		t.Error("No prefix keyring")
	} else if pkc != 2 {
		t.Error("Prefix keyring %d long, expected 2\n", kc)
	}
}

type acNames []types.ACName

// sort.Interface
func (acn acNames) Len() int           { return len(acn) }
func (acn acNames) Less(i, j int) bool { return acn[i].String() < acn[j].String() }
func (acn acNames) Swap(i, j int)      { acn[i], acn[j] = acn[j], acn[i] }

func TestUntrustKey(t *testing.T) {
	ks := newStore()
	defer os.RemoveAll(ks.Path)

	prefix := types.ACName("example.com/foo")
	prefix2 := types.ACName("example.org/bar")

	if _, err := ks.StoreTrustedKey(prefix, bytes.NewReader([]byte(sampleKeys[0]))); err != nil {
		t.Errorf("Error storing key: %v\n", err)
	}

	if _, err := ks.StoreTrustedKey(prefix, bytes.NewReader([]byte(sampleKeys[1]))); err != nil {
		t.Errorf("Error storing key: %v\n", err)
	}

	if _, err := ks.StoreTrustedKey(prefix2, bytes.NewReader([]byte(sampleKeys[1]))); err != nil {
		t.Errorf("Error storing key: %v\n", err)
	}

	if _, err := ks.StoreTrustedKey(prefix2, bytes.NewReader([]byte(sampleKeys[2]))); err != nil {
		t.Errorf("Error storing key: %v\n", err)
	}

	if _, err := ks.StoreTrustedKey(Root, bytes.NewReader([]byte(sampleKeys[2]))); err != nil {
		t.Errorf("Error storing key: %v\n", err)
	}

	kr, err := ks.GetKeyring(Root)
	if err != nil {
		panic(err)
	}
	kc := countKeys(kr)

	if kc[Root] != 1 || kc[prefix] != 2 || kc[prefix2] != 2 {
		t.Errorf("Wrong keyrings even before remove: %v\n", kc)
	}

	if prefixes, err := ks.UntrustKey(sampleKeyFingerprints[2]); err != nil {
		t.Errorf("Error untrusting key: %v %v\n", err, prefixes)
	} else {
		sort.Sort(acNames(prefixes))
		expectedPrefixes := []types.ACName{Root, prefix2}
		if !reflect.DeepEqual(prefixes, expectedPrefixes) {
			t.Errorf("Expected removed prefixes to be %v, got %v instead.\n", expectedPrefixes, prefixes)
		}
	}

	kr, err = ks.GetKeyring(Root)
	if err != nil {
		panic(err)
	}
	kc = countKeys(kr)

	if kc[Root] != 0 || kc[prefix] != 2 || kc[prefix2] != 1 {
		t.Errorf("Wrong counts after remove: %v\n", kc)
	}
}
<commit_msg>WIP: fix keystore tests<commit_after>package keystore

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

	"github.com/appc/spec/schema/types"
)

func newStore() *Keystore {
	storePath, err := ioutil.TempDir(".", "test.store.")
	if err != nil {
		panic(err)
	}

	return New(storePath)
}

func testImport(t *testing.T, prefix types.ACName, subdir string) {
	ks := newStore()
	defer os.RemoveAll(ks.Path)

	for i, key := range sampleKeys {
		fingerprint := sampleKeyFingerprints[i]
		keyPath, err := ks.StoreTrustedKey(prefix, bytes.NewReader([]byte(key)), true)

		if err != nil {
			t.Errorf("Error storing key #%d: %v\n", i, err)
		}

		expectedPath := filepath.Join(ks.Path, subdir, fingerprint)
		if keyPath != expectedPath {
			t.Errorf("Unexpected key path: %v, expected %v (key %d, store %v, prefix %v, fingerprint %v)\n",
				keyPath, expectedPath, i, ks.Path, prefix, fingerprint)
		}

		if keyBytes, err := ioutil.ReadFile(keyPath); err != nil {
			t.Errorf("Error reading back saved key %d: %v", i, err)
		} else if string(keyBytes) != key {
			t.Errorf("Saved key %d different than original", i)
		}
	}
}

func TestImportRoot(t *testing.T) {
	testImport(t, Root, "_")
}

func TestImportPrefix(t *testing.T) {
	testImport(t, types.ACName("example.com"), "_example.com")
}

func TestImportPrefixEscaped(t *testing.T) {
	testImport(t, types.ACName("example.com/foo"), "_example.com%2Ffoo")
}

func checkKeyCount(t *testing.T, ks *Keystore, expected map[types.ACName]int) {
	for name, expectedKeys := range expected {
		if kr, err := ks.GetKeyring(name); err != nil {
			t.Errorf("Error getting keyring for %v: %v\n", name, err)
		} else if actualKeys := kr.Len(); actualKeys != expectedKeys {
			t.Errorf("Expected %d keys for %v, got %d instead\n", expectedKeys, name, actualKeys)
		}
	}
}

func TestGetKeyring(t *testing.T) {
	ks := newStore()
	defer os.RemoveAll(ks.Path)

	if _, err := ks.StoreTrustedKey(types.ACName("example.com/foo"), bytes.NewReader([]byte(sampleKeys[0])), true); err != nil {
		t.Errorf("Error storing key: %v\n", err)
	}

	if _, err := ks.StoreTrustedKey(types.ACName("example.com/foo/bar"), bytes.NewReader([]byte(sampleKeys[1])), true); err != nil {
		t.Errorf("Error storing key: %v\n", err)
	}

	checkKeyCount(t, ks, map[types.ACName]int{
		types.ACName("eggsample.com"):           0,
		types.ACName("eggsample.com/foo"):       0,
		types.ACName("eggsample.com/foo/bar"):   0,
		types.ACName("example.com"):             0,
		types.ACName("example.com/foo"):         1,
		types.ACName("example.com/foo/baz"):     1,
		types.ACName("example.com/foo/bar"):     2,
		types.ACName("example.com/foo/bar/baz"): 2,
		types.ACName("example.com/foobar"):      1,
		types.ACName("example.com/baz"):         0,
	})

	if _, err := ks.StoreTrustedKey(Root, bytes.NewReader([]byte(sampleKeys[2])), true); err != nil {
		t.Errorf("Error storing key: %v\n", err)
	}

	checkKeyCount(t, ks, map[types.ACName]int{
		types.ACName("eggsample.com"):           1,
		types.ACName("eggsample.com/foo"):       1,
		types.ACName("eggsample.com/foo/bar"):   1,
		types.ACName("example.com"):             1,
		types.ACName("example.com/foo"):         2,
		types.ACName("example.com/foo/baz"):     2,
		types.ACName("example.com/foo/bar"):     3,
		types.ACName("example.com/foo/bar/baz"): 3,
		types.ACName("example.com/foobar"):      2,
		types.ACName("example.com/baz"):         1,
	})
}

func countKeys(kr *Keyring) map[types.ACName]int {
	rv := make(map[types.ACName]int)
	for _, prefix := range kr.prefixes {
		rv[prefix] = rv[prefix] + 1
	}
	return rv
}

func TestGetAllKeyrings(t *testing.T) {
	ks := newStore()
	defer os.RemoveAll(ks.Path)

	prefix := types.ACName("example.com/foo")

	if _, err := ks.StoreTrustedKey(prefix, bytes.NewReader([]byte(sampleKeys[0])), true); err != nil {
		t.Errorf("Error storing key: %v\n", err)
	}

	if _, err := ks.StoreTrustedKey(prefix, bytes.NewReader([]byte(sampleKeys[1])), true); err != nil {
		t.Errorf("Error storing key: %v\n", err)
	}

	if _, err := ks.StoreTrustedKey(Root, bytes.NewReader([]byte(sampleKeys[2])), true); err != nil {
		t.Errorf("Error storing key: %v\n", err)
	}

	kr, err := ks.GetKeyring(Root)
	if err != nil {
		t.Errorf("Error getting all keyrings: %v\n", err)
		t.FailNow()
	}

	kc := countKeys(kr)

	if len(kc) != 2 {
		t.Errorf("Got %d keyrings, expected 2: %v\n", len(kc), kc)
	}

	if rkc, ok := kc[Root]; !ok {
		t.Error("No root keyring")
	} else if rkc != 1 {
		t.Error("Root keyring %d long, expected 1\n", rkc)
	}

	if pkc, ok := kc[prefix]; !ok {
		t.Error("No prefix keyring")
	} else if pkc != 2 {
		t.Error("Prefix keyring %d long, expected 2\n", kc)
	}
}

type acNames []types.ACName

// sort.Interface
func (acn acNames) Len() int           { return len(acn) }
func (acn acNames) Less(i, j int) bool { return acn[i].String() < acn[j].String() }
func (acn acNames) Swap(i, j int)      { acn[i], acn[j] = acn[j], acn[i] }

func TestUntrustKey(t *testing.T) {
	ks := newStore()
	defer os.RemoveAll(ks.Path)

	prefix := types.ACName("example.com/foo")
	prefix2 := types.ACName("example.org/bar")

	if _, err := ks.StoreTrustedKey(prefix, bytes.NewReader([]byte(sampleKeys[0])), true); err != nil {
		t.Errorf("Error storing key: %v\n", err)
	}

	if _, err := ks.StoreTrustedKey(prefix, bytes.NewReader([]byte(sampleKeys[1])), true); err != nil {
		t.Errorf("Error storing key: %v\n", err)
	}

	if _, err := ks.StoreTrustedKey(prefix2, bytes.NewReader([]byte(sampleKeys[1])), true); err != nil {
		t.Errorf("Error storing key: %v\n", err)
	}

	if _, err := ks.StoreTrustedKey(prefix2, bytes.NewReader([]byte(sampleKeys[2])), true); err != nil {
		t.Errorf("Error storing key: %v\n", err)
	}

	if _, err := ks.StoreTrustedKey(Root, bytes.NewReader([]byte(sampleKeys[2])), true); err != nil {
		t.Errorf("Error storing key: %v\n", err)
	}

	kr, err := ks.GetKeyring(Root)
	if err != nil {
		panic(err)
	}
	kc := countKeys(kr)

	if kc[Root] != 1 || kc[prefix] != 2 || kc[prefix2] != 2 {
		t.Errorf("Wrong keyrings even before remove: %v\n", kc)
	}

	if prefixes, err := ks.UntrustKey(sampleKeyFingerprints[2]); err != nil {
		t.Errorf("Error untrusting key: %v %v\n", err, prefixes)
	} else {
		sort.Sort(acNames(prefixes))
		expectedPrefixes := []types.ACName{Root, prefix2}
		if !reflect.DeepEqual(prefixes, expectedPrefixes) {
			t.Errorf("Expected removed prefixes to be %v, got %v instead.\n", expectedPrefixes, prefixes)
		}
	}

	kr, err = ks.GetKeyring(Root)
	if err != nil {
		panic(err)
	}
	kc = countKeys(kr)

	if kc[Root] != 0 || kc[prefix] != 2 || kc[prefix2] != 1 {
		t.Errorf("Wrong counts after remove: %v\n", kc)
	}
}
<|endoftext|>


<commit_before>package network

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/pkg/errors"

	"github.com/lxc/lxd/lxd/db"
	deviceConfig "github.com/lxc/lxd/lxd/device/config"
	"github.com/lxc/lxd/lxd/device/pci"
	"github.com/lxc/lxd/lxd/instance/instancetype"
	"github.com/lxc/lxd/lxd/ip"
	"github.com/lxc/lxd/lxd/state"
	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/api"
	"github.com/lxc/lxd/shared/logger"
)

// sriovReservedDevicesMutex used to coordinate access for checking reserved devices.
var sriovReservedDevicesMutex sync.Mutex

// SRIOVGetHostDevicesInUse returns a map of host device names that have been used by devices in other instances
// and networks on the local node. Used when selecting physical and SR-IOV VF devices to avoid conflicts.
func SRIOVGetHostDevicesInUse(s *state.State) (map[string]struct{}, error) {
	sriovReservedDevicesMutex.Lock()
	defer sriovReservedDevicesMutex.Unlock()

	var err error
	var localNode string
	var projectNetworks map[string]map[int64]api.Network

	err = s.Cluster.Transaction(func(tx *db.ClusterTx) error {
		localNode, err = tx.GetLocalNodeName()
		if err != nil {
			return errors.Wrapf(err, "Failed to get local node name")
		}

		// Get all managed networks across all projects.
		projectNetworks, err = tx.GetCreatedNetworks()
		if err != nil {
			return errors.Wrapf(err, "Failed to load all networks")
		}

		return err
	})
	if err != nil {
		return nil, err
	}

	filter := db.InstanceFilter{
		Project: "", // All projects.
		Node:    localNode,
		Type:    instancetype.Any,
	}

	reservedDevices := map[string]struct{}{}

	// Check if any instances are using the VF device.
	err = s.Cluster.InstanceList(&filter, func(dbInst db.Instance, p api.Project, profiles []api.Profile) error {
		// Expand configs so we take into account profile devices.
		dbInst.Config = db.ExpandInstanceConfig(dbInst.Config, profiles)
		dbInst.Devices = db.ExpandInstanceDevices(deviceConfig.NewDevices(dbInst.Devices), profiles).CloneNative()

		for devName, devConfig := range dbInst.Devices {
			// If device references a parent host interface name, mark that as reserved.
			parent := devConfig["parent"]
			if parent != "" {
				reservedDevices[parent] = struct{}{}
			}

			// If device references a volatile host interface name, mark that as reserved.
			hostName := dbInst.Config[fmt.Sprintf("volatile.%s.host_name", devName)]
			if hostName != "" {
				reservedDevices[hostName] = struct{}{}
			}
		}

		return nil
	})
	if err != nil {
		return nil, err
	}

	// Check if any networks are using the VF device.
	for _, networks := range projectNetworks {
		for _, ni := range networks {
			// If network references a parent host interface name, mark that as reserved.
			parent := ni.Config["parent"]
			if parent != "" {
				reservedDevices[parent] = struct{}{}
			}
		}
	}

	return reservedDevices, nil
}

// SRIOVFindFreeVirtualFunction looks on the specified parent device for an unused virtual function.
// Returns the name of the interface and virtual function index ID if found, error if not.
func SRIOVFindFreeVirtualFunction(s *state.State, parentDev string) (string, int, error) {
	reservedDevices, err := SRIOVGetHostDevicesInUse(s)
	if err != nil {
		return "", -1, errors.Wrapf(err, "Failed getting in use device list")
	}

	sriovNumVFsFile := fmt.Sprintf("/sys/class/net/%s/device/sriov_numvfs", parentDev)
	sriovTotalVFsFile := fmt.Sprintf("/sys/class/net/%s/device/sriov_totalvfs", parentDev)

	// Verify that this is indeed a SR-IOV enabled device.
	if !shared.PathExists(sriovNumVFsFile) {
		return "", -1, fmt.Errorf("Parent device %q doesn't support SR-IOV", parentDev)
	}

	// Get parent dev_port and dev_id values.
	pfDevPort, err := ioutil.ReadFile(fmt.Sprintf("/sys/class/net/%s/dev_port", parentDev))
	if err != nil {
		return "", -1, err
	}

	pfDevID, err := ioutil.ReadFile(fmt.Sprintf("/sys/class/net/%s/dev_id", parentDev))
	if err != nil {
		return "", -1, err
	}

	// Get number of currently enabled VFs.
	sriovNumVFsBuf, err := ioutil.ReadFile(sriovNumVFsFile)
	if err != nil {
		return "", -1, err
	}

	sriovNumVFs, err := strconv.Atoi(strings.TrimSpace(string(sriovNumVFsBuf)))
	if err != nil {
		return "", -1, err
	}

	// Get number of possible VFs.
	sriovTotalVFsBuf, err := ioutil.ReadFile(sriovTotalVFsFile)
	if err != nil {
		return "", -1, err
	}

	sriovTotalVFs, err := strconv.Atoi(strings.TrimSpace(string(sriovTotalVFsBuf)))
	if err != nil {
		return "", -1, err
	}

	// Ensure parent is up (needed for Intel at least).
	link := &ip.Link{Name: parentDev}
	err = link.SetUp()
	if err != nil {
		return "", -1, err
	}

	// Check if any free VFs are already enabled.
	vfID, nicName, err := sriovGetFreeVFInterface(reservedDevices, parentDev, sriovNumVFs, 0, pfDevID, pfDevPort)
	if err != nil {
		return "", -1, err
	}

	// Found a free VF.
	if nicName != "" {
		return nicName, vfID, nil
	} else if sriovNumVFs < sriovTotalVFs {
		logger.Debugf("Attempting to grow available VFs from %d to %d on device %q", sriovNumVFs, sriovTotalVFs, parentDev)

		// Bump the number of VFs to the maximum if not there yet.
		err = ioutil.WriteFile(sriovNumVFsFile, []byte(fmt.Sprintf("%d", sriovTotalVFs)), 0644)
		if err != nil {
			return "", -1, errors.Wrapf(err, "Failed growing available VFs from %d to %d on device %q", sriovNumVFs, sriovTotalVFs, parentDev)
		}

		time.Sleep(time.Second) // Allow time for new VFs to appear.

		// Use next free VF index starting from the first newly created VF.
		vfID, nicName, err = sriovGetFreeVFInterface(reservedDevices, parentDev, sriovTotalVFs, sriovNumVFs, pfDevID, pfDevPort)
		if err != nil {
			return "", -1, err
		}

		// Found a free VF.
		if nicName != "" {
			return nicName, vfID, nil
		}
	}

	return "", -1, fmt.Errorf("All virtual functions on parent device %q are already in use", parentDev)
}

// sriovGetFreeVFInterface checks the system for a free VF interface that belongs to the same device and port as
// the parent device starting from the startVFID to the vfCount-1. Returns VF ID and VF interface name if found or
// -1 and empty string if no free interface found. A free interface is one that is bound on the host, not in the
// reservedDevices map, is down and has no global IPs defined on it.
func sriovGetFreeVFInterface(reservedDevices map[string]struct{}, parentDev string, vfCount int, startVFID int, pfDevID []byte, pfDevPort []byte) (int, string, error) {
	for vfID := startVFID; vfID < vfCount; vfID++ {
		vfListPath := fmt.Sprintf("/sys/class/net/%s/device/virtfn%d/net", parentDev, vfID)

		if !shared.PathExists(vfListPath) {
			continue // The vfListPath won't exist if the VF has been unbound and used with a VM.
		}

		ents, err := ioutil.ReadDir(vfListPath)
		if err != nil {
			return -1, "", errors.Wrapf(err, "Failed reading VF interface directory %q", vfListPath)
		}

		for _, ent := range ents {
			// We expect the entry to be a directory for the VF's interface name.
			if !ent.IsDir() {
				continue
			}

			nicName := ent.Name()

			// We can't use this VF interface as it is reserved by another device.
			_, exists := reservedDevices[nicName]
			if exists {
				continue
			}

			// Get VF dev_port and dev_id values.
			vfDevPort, err := ioutil.ReadFile(fmt.Sprintf("%s/%s/dev_port", vfListPath, nicName))
			if err != nil {
				return -1, "", err
			}

			vfDevID, err := ioutil.ReadFile(fmt.Sprintf("%s/%s/dev_id", vfListPath, nicName))
			if err != nil {
				return -1, "", err
			}

			// Skip VFs if they do not relate to the same device and port as the parent PF.
			// Some card vendors change the device ID for each port.
			if bytes.Compare(pfDevPort, vfDevPort) != 0 || bytes.Compare(pfDevID, vfDevID) != 0 {
				continue
			}

			addresses, isUp, err := InterfaceStatus(nicName)
			if err != nil {
				return -1, "", err
			}

			// Ignore if interface is up or if interface has unicast IP addresses (may be in use by
			// another application already).
			if isUp || len(addresses) > 0 {
				continue
			}

			// Found a free VF.
			return vfID, nicName, err
		}
	}

	return -1, "", nil
}

// SRIOVGetVFDevicePCISlot returns the PCI slot name for a network virtual function device.
func SRIOVGetVFDevicePCISlot(parentDev string, vfID string) (pci.Device, error) {
	ueventFile := fmt.Sprintf("/sys/class/net/%s/device/virtfn%s/uevent", parentDev, vfID)
	pciDev, err := pci.ParseUeventFile(ueventFile)
	if err != nil {
		return pciDev, err
	}

	return pciDev, nil
}
<commit_msg>lxd/network/network/utils/sriov: Add mutex to SRIOVFindFreeVirtualFunction to prevent concurrent start races<commit_after>package network

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/pkg/errors"

	"github.com/lxc/lxd/lxd/db"
	deviceConfig "github.com/lxc/lxd/lxd/device/config"
	"github.com/lxc/lxd/lxd/device/pci"
	"github.com/lxc/lxd/lxd/instance/instancetype"
	"github.com/lxc/lxd/lxd/ip"
	"github.com/lxc/lxd/lxd/state"
	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/api"
	"github.com/lxc/lxd/shared/logger"
)

// sriovReservedDevicesMutex used to coordinate access for checking reserved devices.
var sriovReservedDevicesMutex sync.Mutex

// sriovFindFreeVirtualFunctionMutex used to coordinate access for finding free virtual functions.
var sriovFindFreeVirtualFunctionMutex sync.Mutex

// SRIOVGetHostDevicesInUse returns a map of host device names that have been used by devices in other instances
// and networks on the local node. Used when selecting physical and SR-IOV VF devices to avoid conflicts.
func SRIOVGetHostDevicesInUse(s *state.State) (map[string]struct{}, error) {
	sriovReservedDevicesMutex.Lock()
	defer sriovReservedDevicesMutex.Unlock()

	var err error
	var localNode string
	var projectNetworks map[string]map[int64]api.Network

	err = s.Cluster.Transaction(func(tx *db.ClusterTx) error {
		localNode, err = tx.GetLocalNodeName()
		if err != nil {
			return errors.Wrapf(err, "Failed to get local node name")
		}

		// Get all managed networks across all projects.
		projectNetworks, err = tx.GetCreatedNetworks()
		if err != nil {
			return errors.Wrapf(err, "Failed to load all networks")
		}

		return err
	})
	if err != nil {
		return nil, err
	}

	filter := db.InstanceFilter{
		Project: "", // All projects.
		Node:    localNode,
		Type:    instancetype.Any,
	}

	reservedDevices := map[string]struct{}{}

	// Check if any instances are using the VF device.
	err = s.Cluster.InstanceList(&filter, func(dbInst db.Instance, p api.Project, profiles []api.Profile) error {
		// Expand configs so we take into account profile devices.
		dbInst.Config = db.ExpandInstanceConfig(dbInst.Config, profiles)
		dbInst.Devices = db.ExpandInstanceDevices(deviceConfig.NewDevices(dbInst.Devices), profiles).CloneNative()

		for devName, devConfig := range dbInst.Devices {
			// If device references a parent host interface name, mark that as reserved.
			parent := devConfig["parent"]
			if parent != "" {
				reservedDevices[parent] = struct{}{}
			}

			// If device references a volatile host interface name, mark that as reserved.
			hostName := dbInst.Config[fmt.Sprintf("volatile.%s.host_name", devName)]
			if hostName != "" {
				reservedDevices[hostName] = struct{}{}
			}
		}

		return nil
	})
	if err != nil {
		return nil, err
	}

	// Check if any networks are using the VF device.
	for _, networks := range projectNetworks {
		for _, ni := range networks {
			// If network references a parent host interface name, mark that as reserved.
			parent := ni.Config["parent"]
			if parent != "" {
				reservedDevices[parent] = struct{}{}
			}
		}
	}

	return reservedDevices, nil
}

// SRIOVFindFreeVirtualFunction looks on the specified parent device for an unused virtual function.
// Returns the name of the interface and virtual function index ID if found, error if not.
func SRIOVFindFreeVirtualFunction(s *state.State, parentDev string) (string, int, error) {
	sriovFindFreeVirtualFunctionMutex.Lock()
	defer sriovFindFreeVirtualFunctionMutex.Unlock()

	reservedDevices, err := SRIOVGetHostDevicesInUse(s)
	if err != nil {
		return "", -1, errors.Wrapf(err, "Failed getting in use device list")
	}

	sriovNumVFsFile := fmt.Sprintf("/sys/class/net/%s/device/sriov_numvfs", parentDev)
	sriovTotalVFsFile := fmt.Sprintf("/sys/class/net/%s/device/sriov_totalvfs", parentDev)

	// Verify that this is indeed a SR-IOV enabled device.
	if !shared.PathExists(sriovNumVFsFile) {
		return "", -1, fmt.Errorf("Parent device %q doesn't support SR-IOV", parentDev)
	}

	// Get parent dev_port and dev_id values.
	pfDevPort, err := ioutil.ReadFile(fmt.Sprintf("/sys/class/net/%s/dev_port", parentDev))
	if err != nil {
		return "", -1, err
	}

	pfDevID, err := ioutil.ReadFile(fmt.Sprintf("/sys/class/net/%s/dev_id", parentDev))
	if err != nil {
		return "", -1, err
	}

	// Get number of currently enabled VFs.
	sriovNumVFsBuf, err := ioutil.ReadFile(sriovNumVFsFile)
	if err != nil {
		return "", -1, err
	}

	sriovNumVFs, err := strconv.Atoi(strings.TrimSpace(string(sriovNumVFsBuf)))
	if err != nil {
		return "", -1, err
	}

	// Get number of possible VFs.
	sriovTotalVFsBuf, err := ioutil.ReadFile(sriovTotalVFsFile)
	if err != nil {
		return "", -1, err
	}

	sriovTotalVFs, err := strconv.Atoi(strings.TrimSpace(string(sriovTotalVFsBuf)))
	if err != nil {
		return "", -1, err
	}

	// Ensure parent is up (needed for Intel at least).
	link := &ip.Link{Name: parentDev}
	err = link.SetUp()
	if err != nil {
		return "", -1, err
	}

	// Check if any free VFs are already enabled.
	vfID, nicName, err := sriovGetFreeVFInterface(reservedDevices, parentDev, sriovNumVFs, 0, pfDevID, pfDevPort)
	if err != nil {
		return "", -1, err
	}

	// Found a free VF.
	if nicName != "" {
		return nicName, vfID, nil
	} else if sriovNumVFs < sriovTotalVFs {
		logger.Debugf("Attempting to grow available VFs from %d to %d on device %q", sriovNumVFs, sriovTotalVFs, parentDev)

		// Bump the number of VFs to the maximum if not there yet.
		err = ioutil.WriteFile(sriovNumVFsFile, []byte(fmt.Sprintf("%d", sriovTotalVFs)), 0644)
		if err != nil {
			return "", -1, errors.Wrapf(err, "Failed growing available VFs from %d to %d on device %q", sriovNumVFs, sriovTotalVFs, parentDev)
		}

		time.Sleep(time.Second) // Allow time for new VFs to appear.

		// Use next free VF index starting from the first newly created VF.
		vfID, nicName, err = sriovGetFreeVFInterface(reservedDevices, parentDev, sriovTotalVFs, sriovNumVFs, pfDevID, pfDevPort)
		if err != nil {
			return "", -1, err
		}

		// Found a free VF.
		if nicName != "" {
			return nicName, vfID, nil
		}
	}

	return "", -1, fmt.Errorf("All virtual functions on parent device %q are already in use", parentDev)
}

// sriovGetFreeVFInterface checks the system for a free VF interface that belongs to the same device and port as
// the parent device starting from the startVFID to the vfCount-1. Returns VF ID and VF interface name if found or
// -1 and empty string if no free interface found. A free interface is one that is bound on the host, not in the
// reservedDevices map, is down and has no global IPs defined on it.
func sriovGetFreeVFInterface(reservedDevices map[string]struct{}, parentDev string, vfCount int, startVFID int, pfDevID []byte, pfDevPort []byte) (int, string, error) {
	for vfID := startVFID; vfID < vfCount; vfID++ {
		vfListPath := fmt.Sprintf("/sys/class/net/%s/device/virtfn%d/net", parentDev, vfID)

		if !shared.PathExists(vfListPath) {
			continue // The vfListPath won't exist if the VF has been unbound and used with a VM.
		}

		ents, err := ioutil.ReadDir(vfListPath)
		if err != nil {
			return -1, "", errors.Wrapf(err, "Failed reading VF interface directory %q", vfListPath)
		}

		for _, ent := range ents {
			// We expect the entry to be a directory for the VF's interface name.
			if !ent.IsDir() {
				continue
			}

			nicName := ent.Name()

			// We can't use this VF interface as it is reserved by another device.
			_, exists := reservedDevices[nicName]
			if exists {
				continue
			}

			// Get VF dev_port and dev_id values.
			vfDevPort, err := ioutil.ReadFile(fmt.Sprintf("%s/%s/dev_port", vfListPath, nicName))
			if err != nil {
				return -1, "", err
			}

			vfDevID, err := ioutil.ReadFile(fmt.Sprintf("%s/%s/dev_id", vfListPath, nicName))
			if err != nil {
				return -1, "", err
			}

			// Skip VFs if they do not relate to the same device and port as the parent PF.
			// Some card vendors change the device ID for each port.
			if bytes.Compare(pfDevPort, vfDevPort) != 0 || bytes.Compare(pfDevID, vfDevID) != 0 {
				continue
			}

			addresses, isUp, err := InterfaceStatus(nicName)
			if err != nil {
				return -1, "", err
			}

			// Ignore if interface is up or if interface has unicast IP addresses (may be in use by
			// another application already).
			if isUp || len(addresses) > 0 {
				continue
			}

			// Found a free VF.
			return vfID, nicName, err
		}
	}

	return -1, "", nil
}

// SRIOVGetVFDevicePCISlot returns the PCI slot name for a network virtual function device.
func SRIOVGetVFDevicePCISlot(parentDev string, vfID string) (pci.Device, error) {
	ueventFile := fmt.Sprintf("/sys/class/net/%s/device/virtfn%s/uevent", parentDev, vfID)
	pciDev, err := pci.ParseUeventFile(ueventFile)
	if err != nil {
		return pciDev, err
	}

	return pciDev, nil
}
<|endoftext|>


<commit_before>package controllers

import (
	"bytes"
	"errors"
	"fmt"
	"net/http"
	"regexp"
	"strconv"

	"code.google.com/p/freetype-go/freetype/truetype"
	"github.com/robfig/revel"
	"github.com/slok/gummyimage"
)

type Application struct {
	*revel.Controller
}

type ImageResponse struct {
	sizeX   int
	sizeY   int
	bgColor string
	fgColor string
	text    string
	format  string
}

// Global variable
var (
	font              *truetype.Font
	regularSizeRegex  = regexp.MustCompile(`^(.+)[xX](.+)$`)
	aspectSizeRegex   = regexp.MustCompile(`^(.+):(.+)$`)
	correctColorRegex = regexp.MustCompile(`^[A-Fa-f0-9]{2,6}$`)
	formatRegex       = regexp.MustCompile(`\.(jpg|jpeg|JPG|JPEG|gif|GIF|png|PNG)`)
)

// Custom responses -----------------------------------------------------------
// Custom response for image
func (r ImageResponse) Apply(req *revel.Request, resp *revel.Response) {

	// FIX:
	// If settings loaded out of actions then revel throws nil pointer, so we
	// load here the first time only
	if font == nil {
		fontPath, _ := revel.Config.String("gummyimage.fontpath")
		font, _ = gummyimage.LoadFont(fontPath)
	}

	resp.WriteHeader(http.StatusOK, "image/png")

	g, _ := gummyimage.NewDefaultGummy(r.sizeX, r.sizeY, r.bgColor)
	g.Font = font

	// Custom text?
	if len(r.text) == 0 {
		g.DrawTextSize(r.fgColor)
	} else {
		g.DrawTextCenter(r.text, r.fgColor)
	}

	b := new(bytes.Buffer)
	g.Get(r.format, b)
	resp.Out.Write(b.Bytes())
}

// Actions --------------------------------------------------------------------
func (c Application) Index() revel.Result {
	return c.Render()
}

func (c Application) CreateImage() revel.Result {

	// Get params by dict because we use this action for 3 different url routes
	// with different url params
	var bgColor, fgColor string
	format, _ := revel.Config.String("gummyimage.format.default")
	text := c.Params.Get("text")

	tmpValues := []string{
		c.Params.Get("size"),
		c.Params.Get("bgcolor"),
		c.Params.Get("fgcolor"),
	}

	// Get format
	for k, i := range tmpValues {
		if f := formatRegex.FindStringSubmatch(i); len(f) > 0 {
			format = f[1]
			tmpValues[k] = formatRegex.ReplaceAllString(i, "")
		}
	}

	x, y, err := getSize(tmpValues[0])
	bgColor, err = colorOk(tmpValues[1])

	if len(tmpValues[2]) > 0 {
		fgColor, err = colorOk(tmpValues[2])
	}

	if err != nil {
		return c.RenderText("Wrong size format")
	}

	// Check limits, don't allow gigantic images :P
	maxY, _ := revel.Config.String("gummyimage.max.height")
	maxX, _ := revel.Config.String("gummyimage.max.width")
	tmx, _ := strconv.Atoi(maxX)
	tmy, _ := strconv.Atoi(maxY)
	if x > tmx || y > tmy {
		return c.RenderText("wow, very big, too image,// Color in HEX format: FAFAFA much pixels")
	}

	return ImageResponse(ImageResponse{x, y, bgColor, fgColor, text, format})
}

// Helpers--------------------------------------------------------------------

// Gets the correct size based on the patern
// Supports:
//  - Predefined sizes (in app.conf)
//  - Aspect sizes: nnnXnn:nn & nn:nnXnnn
//  - Square: nnn
//  - Regular: nnnXnnn & nnnxnnn
func getSize(size string) (x, y int, err error) {

	// Check if is a standard size
	if s, found := revel.Config.String(fmt.Sprintf("size.%v", size)); found {
		size = s
	}

	// Normal size (nnnxnnn, nnnXnnn)
	sizes := regularSizeRegex.FindStringSubmatch(size)
	if len(sizes) > 0 {
		// Check if aspect (nn:nn)

		left := aspectSizeRegex.FindStringSubmatch(sizes[1])
		right := aspectSizeRegex.FindStringSubmatch(sizes[2])

		// If both scale then error
		if len(left) > 0 && len(right) > 0 {
			err = errors.New("Not correct size")
			return

		} else if len(left) > 0 { // nn:nnXnnn
			y, _ = strconv.Atoi(sizes[2])
			tll, _ := strconv.Atoi(left[1])
			tlr, _ := strconv.Atoi(left[2])
			x = y * tll / tlr
		} else if len(right) > 0 { // nnnXnn:nn
			x, _ = strconv.Atoi(sizes[1])
			trl, _ := strconv.Atoi(right[1])
			trr, _ := strconv.Atoi(right[2])
			y = x * trr / trl
		} else { // nnnXnnn
			x, _ = strconv.Atoi(sizes[1])
			y, _ = strconv.Atoi(sizes[2])
		}

	} else { // Square (nnn)
		x, _ = strconv.Atoi(size)
		y = x
	}

	if x == 0 || y == 0 {
		err = errors.New("Not correct size")
	}
	return
}

func colorOk(color string) (newColor string, err error) {

	// Set defaults
	if color == "" {
		newColor, _ = revel.Config.String("gummyimage.bgcolor.default")
		return
	} else if !correctColorRegex.MatchString(color) {
		newColor, _ = revel.Config.String("gummyimage.bgcolor.default")
		err = errors.New("Wrong color format")
		return
	} else {
		switch len(color) {
		case 1:
			newColor = ""
			for i := 0; i < 6; i++ {
				newColor += color
			}
			return
		case 2:
			newColor = fmt.Sprintf("%s%s%s", color, color, color)
			return
		case 3:
			c1 := string(color[0])
			c2 := string(color[1])
			c3 := string(color[2])
			newColor = fmt.Sprintf("%s%s%s%s%s%s", c1, c1, c2, c2, c3, c3)
			return
		}
	}
	newColor = color
	return
}
<commit_msg>Fixed text color 1 char expansion<commit_after>package controllers

import (
	"bytes"
	"errors"
	"fmt"
	"net/http"
	"regexp"
	"strconv"

	"code.google.com/p/freetype-go/freetype/truetype"
	"github.com/robfig/revel"
	"github.com/slok/gummyimage"
)

type Application struct {
	*revel.Controller
}

type ImageResponse struct {
	sizeX   int
	sizeY   int
	bgColor string
	fgColor string
	text    string
	format  string
}

// Global variable
var (
	font              *truetype.Font
	regularSizeRegex  = regexp.MustCompile(`^(.+)[xX](.+)$`)
	aspectSizeRegex   = regexp.MustCompile(`^(.+):(.+)$`)
	correctColorRegex = regexp.MustCompile(`^[A-Fa-f0-9]{1,6}$`)
	formatRegex       = regexp.MustCompile(`\.(jpg|jpeg|JPG|JPEG|gif|GIF|png|PNG)`)
)

// Custom responses -----------------------------------------------------------
// Custom response for image
func (r ImageResponse) Apply(req *revel.Request, resp *revel.Response) {

	// FIX:
	// If settings loaded out of actions then revel throws nil pointer, so we
	// load here the first time only
	if font == nil {
		fontPath, _ := revel.Config.String("gummyimage.fontpath")
		font, _ = gummyimage.LoadFont(fontPath)
	}

	resp.WriteHeader(http.StatusOK, "image/png")

	g, _ := gummyimage.NewDefaultGummy(r.sizeX, r.sizeY, r.bgColor)
	g.Font = font

	// Custom text?
	if len(r.text) == 0 {
		g.DrawTextSize(r.fgColor)
	} else {
		g.DrawTextCenter(r.text, r.fgColor)
	}

	b := new(bytes.Buffer)
	g.Get(r.format, b)
	resp.Out.Write(b.Bytes())
}

// Actions --------------------------------------------------------------------
func (c Application) Index() revel.Result {
	return c.Render()
}

func (c Application) CreateImage() revel.Result {

	// Get params by dict because we use this action for 3 different url routes
	// with different url params
	var bgColor, fgColor string
	format, _ := revel.Config.String("gummyimage.format.default")
	text := c.Params.Get("text")

	tmpValues := []string{
		c.Params.Get("size"),
		c.Params.Get("bgcolor"),
		c.Params.Get("fgcolor"),
	}

	// Get format
	for k, i := range tmpValues {
		if f := formatRegex.FindStringSubmatch(i); len(f) > 0 {
			format = f[1]
			tmpValues[k] = formatRegex.ReplaceAllString(i, "")
		}
	}

	x, y, err := getSize(tmpValues[0])
	bgColor, err = colorOk(tmpValues[1])

	if len(tmpValues[2]) > 0 {
		fgColor, err = colorOk(tmpValues[2])
	}

	if err != nil {
		return c.RenderText("Wrong size format")
	}

	// Check limits, don't allow gigantic images :P
	maxY, _ := revel.Config.String("gummyimage.max.height")
	maxX, _ := revel.Config.String("gummyimage.max.width")
	tmx, _ := strconv.Atoi(maxX)
	tmy, _ := strconv.Atoi(maxY)
	if x > tmx || y > tmy {
		return c.RenderText("wow, very big, too image,// Color in HEX format: FAFAFA much pixels")
	}

	return ImageResponse(ImageResponse{x, y, bgColor, fgColor, text, format})
}

// Helpers--------------------------------------------------------------------

// Gets the correct size based on the patern
// Supports:
//  - Predefined sizes (in app.conf)
//  - Aspect sizes: nnnXnn:nn & nn:nnXnnn
//  - Square: nnn
//  - Regular: nnnXnnn & nnnxnnn
func getSize(size string) (x, y int, err error) {

	// Check if is a standard size
	if s, found := revel.Config.String(fmt.Sprintf("size.%v", size)); found {
		size = s
	}

	// Normal size (nnnxnnn, nnnXnnn)
	sizes := regularSizeRegex.FindStringSubmatch(size)
	if len(sizes) > 0 {
		// Check if aspect (nn:nn)

		left := aspectSizeRegex.FindStringSubmatch(sizes[1])
		right := aspectSizeRegex.FindStringSubmatch(sizes[2])

		// If both scale then error
		if len(left) > 0 && len(right) > 0 {
			err = errors.New("Not correct size")
			return

		} else if len(left) > 0 { // nn:nnXnnn
			y, _ = strconv.Atoi(sizes[2])
			tll, _ := strconv.Atoi(left[1])
			tlr, _ := strconv.Atoi(left[2])
			x = y * tll / tlr
		} else if len(right) > 0 { // nnnXnn:nn
			x, _ = strconv.Atoi(sizes[1])
			trl, _ := strconv.Atoi(right[1])
			trr, _ := strconv.Atoi(right[2])
			y = x * trr / trl
		} else { // nnnXnnn
			x, _ = strconv.Atoi(sizes[1])
			y, _ = strconv.Atoi(sizes[2])
		}

	} else { // Square (nnn)
		x, _ = strconv.Atoi(size)
		y = x
	}

	if x == 0 || y == 0 {
		err = errors.New("Not correct size")
	}
	return
}

func colorOk(color string) (newColor string, err error) {

	// Set defaults
	if color == "" {
		newColor, _ = revel.Config.String("gummyimage.bgcolor.default")
		return
	} else if !correctColorRegex.MatchString(color) {
		newColor, _ = revel.Config.String("gummyimage.bgcolor.default")
		err = errors.New("Wrong color format")
		return
	} else {
		switch len(color) {
		case 1:
			newColor = ""
			for i := 0; i < 6; i++ {
				newColor += color
			}
			return
		case 2:
			newColor = fmt.Sprintf("%s%s%s", color, color, color)
			return
		case 3:
			c1 := string(color[0])
			c2 := string(color[1])
			c3 := string(color[2])
			newColor = fmt.Sprintf("%s%s%s%s%s%s", c1, c1, c2, c2, c3, c3)
			return
		}
	}
	newColor = color
	return
}
<|endoftext|>