<commit_before>package pyrahttp

import (
	"crypto/tls"
	"errors"
	"fmt"
	"net"
	"net/http"
	"os"
	"time"
)

// https://golang.org/src/net/http/server.go?s=59426:59517#L1988

func ListenAndServeTLS(addr string, certFile, keyFile string, handler http.Handler) error {
	srv := &http.Server{Addr: addr, Handler: handler}
	if addr == "" {
		addr = ":https"
	}
	config := cloneTLSConfig(srv.TLSConfig)
	if config.NextProtos == nil {
		config.NextProtos = []string{"http/1.1"}
	}

	if len(config.Certificates) == 0 || certFile != "" || keyFile != "" {
		var err error
		config.Certificates = make([]tls.Certificate, 1)
		config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
		if err != nil {
			return err
		}
	}

	ln, err := net.Listen("tcp", addr)
	if err != nil {
		return err
	}

	tlsListener := tls.NewListener(tcpKeepAliveListener{ln.(*net.TCPListener)}, config)
	return srv.Serve(tlsListener)
}

func ListenAndServeLetsEncrypt(addr string, certFile string, keyFile string, handler http.Handler) error {

	for {

		fmt.Println("ListenAndServeLetsEncrypt 1")

		srv := &http.Server{Addr: addr, Handler: handler}

		if addr == "" {
			addr = ":https"
		}
		config := cloneTLSConfig(srv.TLSConfig)
		if config.NextProtos == nil {
			config.NextProtos = []string{"http/1.1"}
		}

		fmt.Println("ListenAndServeLetsEncrypt 2")

		if len(config.Certificates) == 0 || certFile != "" || keyFile != "" {
			var err error
			config.Certificates = make([]tls.Certificate, 1)
			config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
			if err != nil {
				return err
			}
		}

		fmt.Println("ListenAndServeLetsEncrypt 3")

		ln, err := net.Listen("tcp", addr)
		if err != nil {
			return err
		}
		fmt.Println("ListenAndServeLetsEncrypt 3.5")

		tcpln, ok := ln.(*net.TCPListener)

		if !ok {
			return errors.New(fmt.Sprintf("failed wrap %#v", ln))
		}

		fmt.Println("ListenAndServeLetsEncrypt 4")
		// tlsListener := tls.NewListener(tcpKeepAliveListener{ln.(*net.TCPListener)}, config)
		tlsListener := tls.NewListener(tcpKeepAliveListener{tcpln}, config)

		sl, err := New(tlsListener, tcpln, certFile, keyFile)
		if err != nil {
			return err
		}
		fmt.Println("ListenAndServeLetsEncrypt 5")
		err = srv.Serve(sl)
		fmt.Println("ListenAndServeLetsEncrypt 6 ", err)

		if err == ReloadError {
			fmt.Printf("Reloading certs %s %s\n", keyFile, certFile)
			continue
		}

		fmt.Println("ListenAndServeLetsEncrypt 7 exit")
		return err
	}

}

// taken from https://golang.org/src/net/http/transport.go#L1396

// cloneTLSConfig returns a shallow clone of the exported
// fields of cfg, ignoring the unexported sync.Once, which
// contains a mutex and must not be copied.
//
// The cfg must not be in active use by tls.Server, or else
// there can still be a race with tls.Server updating SessionTicketKey
// and our copying it, and also a race with the server setting
// SessionTicketsDisabled=false on failure to set the random
// ticket key.
//
// If cfg is nil, a new zero tls.Config is returned.
func cloneTLSConfig(cfg *tls.Config) *tls.Config {
	if cfg == nil {
		return &tls.Config{}
	}
	return &tls.Config{
		Rand:                     cfg.Rand,
		Time:                     cfg.Time,
		Certificates:             cfg.Certificates,
		NameToCertificate:        cfg.NameToCertificate,
		GetCertificate:           cfg.GetCertificate,
		RootCAs:                  cfg.RootCAs,
		NextProtos:               cfg.NextProtos,
		ServerName:               cfg.ServerName,
		ClientAuth:               cfg.ClientAuth,
		ClientCAs:                cfg.ClientCAs,
		InsecureSkipVerify:       cfg.InsecureSkipVerify,
		CipherSuites:             cfg.CipherSuites,
		PreferServerCipherSuites: cfg.PreferServerCipherSuites,
		SessionTicketsDisabled:   cfg.SessionTicketsDisabled,
		SessionTicketKey:         cfg.SessionTicketKey,
		ClientSessionCache:       cfg.ClientSessionCache,
		MinVersion:               cfg.MinVersion,
		MaxVersion:               cfg.MaxVersion,
		CurvePreferences:         cfg.CurvePreferences,
	}
}

// https://github.com/hydrogen18/stoppableListener/blob/master/listener.go
type StoppableListener struct {
	*net.TCPListener //Wrapped listener
	certFile         string
	keyFile          string
	certTime         int64
	keyTime          int64
}

func New(l net.Listener, tcpL *net.TCPListener, certFile string, keyFile string) (*StoppableListener, error) {
	// tcpL, ok := l.(*net.TCPListener)

	// if !ok {
	// 	return nil, errors.New("Cannot wrap listener")
	// }

	retval := &StoppableListener{}
	retval.TCPListener = tcpL
	retval.certFile = certFile
	fi, err := os.Stat(certFile)
	if err != nil {
		return nil, err
	}
	retval.certTime = fi.ModTime().UnixNano()
	retval.keyFile = keyFile
	fi, err = os.Stat(keyFile)
	if err != nil {
		return nil, err
	}
	retval.keyTime = fi.ModTime().UnixNano()

	return retval, nil
}

var ReloadError = errors.New("Listener stopped")

func (sl *StoppableListener) Accept() (net.Conn, error) {

	for {
		//Wait up to one second for a new connection
		sl.SetDeadline(time.Now().Add(time.Minute))

		// newConn, err := sl.TCPListener.AcceptTCP()
		newConn, err := sl.TCPListener.Accept()

		// newConn.SetKeepAlive(true)
		// newConn.SetKeepAlivePeriod(3 * time.Minute)

		fmt.Print("checking cert ")
		fi, err1 := os.Stat(sl.certFile)
		if err1 == nil {
			fmt.Printf(" nil %d %d ", fi.ModTime().UnixNano(), sl.certTime)
			if fi.ModTime().UnixNano() != sl.certTime {
				fmt.Print(" reload\n")
				return nil, ReloadError
			}
		}

		fmt.Print(" key ")
		fi, err1 = os.Stat(sl.keyFile)
		if err1 == nil {
			fmt.Printf(" nil %d %d ", fi.ModTime().UnixNano(), sl.keyTime)
			if fi.ModTime().UnixNano() != sl.keyTime {
				fmt.Print(" reload\n")
				return nil, ReloadError
			}
		}

		fmt.Print(" --\n")

		if err != nil {
			netErr, ok := err.(net.Error)

			//If this is a timeout, then continue to wait for
			//new connections
			if ok && netErr.Timeout() && netErr.Temporary() {
				continue
			}
		}

		return newConn, err
	}
}

// tcpKeepAliveListener sets TCP keep-alive timeouts on accepted
// connections. It's used by ListenAndServe and ListenAndServeTLS so
// dead TCP connections (e.g. closing laptop mid-download) eventually
// go away.
type tcpKeepAliveListener struct {
	*net.TCPListener
}

func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
	tc, err := ln.AcceptTCP()
	if err != nil {
		return
	}
	tc.SetKeepAlive(true)
	tc.SetKeepAlivePeriod(3 * time.Minute)
	return tc, nil
}
<commit_msg>swapped wrappers<commit_after>package pyrahttp

import (
	"crypto/tls"
	"errors"
	"fmt"
	"net"
	"net/http"
	"os"
	"time"
)

// https://golang.org/src/net/http/server.go?s=59426:59517#L1988

func ListenAndServeTLS(addr string, certFile, keyFile string, handler http.Handler) error {
	srv := &http.Server{Addr: addr, Handler: handler}
	if addr == "" {
		addr = ":https"
	}
	config := cloneTLSConfig(srv.TLSConfig)
	if config.NextProtos == nil {
		config.NextProtos = []string{"http/1.1"}
	}

	if len(config.Certificates) == 0 || certFile != "" || keyFile != "" {
		var err error
		config.Certificates = make([]tls.Certificate, 1)
		config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
		if err != nil {
			return err
		}
	}

	ln, err := net.Listen("tcp", addr)
	if err != nil {
		return err
	}

	tlsListener := tls.NewListener(tcpKeepAliveListener{ln.(*net.TCPListener)}, config)
	return srv.Serve(tlsListener)
}

func ListenAndServeLetsEncrypt(addr string, certFile string, keyFile string, handler http.Handler) error {

	for {

		fmt.Println("ListenAndServeLetsEncrypt 1")

		srv := &http.Server{Addr: addr, Handler: handler}

		if addr == "" {
			addr = ":https"
		}
		config := cloneTLSConfig(srv.TLSConfig)
		if config.NextProtos == nil {
			config.NextProtos = []string{"http/1.1"}
		}

		fmt.Println("ListenAndServeLetsEncrypt 2")

		if len(config.Certificates) == 0 || certFile != "" || keyFile != "" {
			var err error
			config.Certificates = make([]tls.Certificate, 1)
			config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
			if err != nil {
				return err
			}
		}

		fmt.Println("ListenAndServeLetsEncrypt 3")

		ln, err := net.Listen("tcp", addr)
		if err != nil {
			return err
		}
		fmt.Println("ListenAndServeLetsEncrypt 3.5")

		tcpln, ok := ln.(*net.TCPListener)

		if !ok {
			return errors.New(fmt.Sprintf("failed wrap %#v", ln))
		}

		fmt.Println("ListenAndServeLetsEncrypt 4")
		// tlsListener := tls.NewListener(tcpKeepAliveListener{ln.(*net.TCPListener)}, config)

		sl, err := New(tcpKeepAliveListener{tcpln}, tcpln, certFile, keyFile)
		if err != nil {
			return err
		}

		tlsListener := tls.NewListener(sl, config)

		fmt.Println("ListenAndServeLetsEncrypt 5")
		err = srv.Serve(tlsListener)
		fmt.Println("ListenAndServeLetsEncrypt 6 ", err)

		if err == ReloadError {
			fmt.Printf("Reloading certs %s %s\n", keyFile, certFile)
			continue
		}

		fmt.Println("ListenAndServeLetsEncrypt 7 exit")
		return err
	}

}

// taken from https://golang.org/src/net/http/transport.go#L1396

// cloneTLSConfig returns a shallow clone of the exported
// fields of cfg, ignoring the unexported sync.Once, which
// contains a mutex and must not be copied.
//
// The cfg must not be in active use by tls.Server, or else
// there can still be a race with tls.Server updating SessionTicketKey
// and our copying it, and also a race with the server setting
// SessionTicketsDisabled=false on failure to set the random
// ticket key.
//
// If cfg is nil, a new zero tls.Config is returned.
func cloneTLSConfig(cfg *tls.Config) *tls.Config {
	if cfg == nil {
		return &tls.Config{}
	}
	return &tls.Config{
		Rand:                     cfg.Rand,
		Time:                     cfg.Time,
		Certificates:             cfg.Certificates,
		NameToCertificate:        cfg.NameToCertificate,
		GetCertificate:           cfg.GetCertificate,
		RootCAs:                  cfg.RootCAs,
		NextProtos:               cfg.NextProtos,
		ServerName:               cfg.ServerName,
		ClientAuth:               cfg.ClientAuth,
		ClientCAs:                cfg.ClientCAs,
		InsecureSkipVerify:       cfg.InsecureSkipVerify,
		CipherSuites:             cfg.CipherSuites,
		PreferServerCipherSuites: cfg.PreferServerCipherSuites,
		SessionTicketsDisabled:   cfg.SessionTicketsDisabled,
		SessionTicketKey:         cfg.SessionTicketKey,
		ClientSessionCache:       cfg.ClientSessionCache,
		MinVersion:               cfg.MinVersion,
		MaxVersion:               cfg.MaxVersion,
		CurvePreferences:         cfg.CurvePreferences,
	}
}

// https://github.com/hydrogen18/stoppableListener/blob/master/listener.go
type StoppableListener struct {
	*net.TCPListener //Wrapped listener
	certFile         string
	keyFile          string
	certTime         int64
	keyTime          int64
}

func New(l net.Listener, tcpL *net.TCPListener, certFile string, keyFile string) (*StoppableListener, error) {
	// tcpL, ok := l.(*net.TCPListener)

	// if !ok {
	// 	return nil, errors.New("Cannot wrap listener")
	// }

	retval := &StoppableListener{}
	retval.TCPListener = tcpL
	retval.certFile = certFile
	fi, err := os.Stat(certFile)
	if err != nil {
		return nil, err
	}
	retval.certTime = fi.ModTime().UnixNano()
	retval.keyFile = keyFile
	fi, err = os.Stat(keyFile)
	if err != nil {
		return nil, err
	}
	retval.keyTime = fi.ModTime().UnixNano()

	return retval, nil
}

var ReloadError = errors.New("Listener stopped")

func (sl *StoppableListener) Accept() (net.Conn, error) {

	for {
		//Wait up to one second for a new connection
		sl.SetDeadline(time.Now().Add(time.Minute))

		// newConn, err := sl.TCPListener.AcceptTCP()
		newConn, err := sl.TCPListener.Accept()

		// newConn.SetKeepAlive(true)
		// newConn.SetKeepAlivePeriod(3 * time.Minute)

		fmt.Print("checking cert ")
		fi, err1 := os.Stat(sl.certFile)
		if err1 == nil {
			fmt.Printf(" nil %d %d ", fi.ModTime().UnixNano(), sl.certTime)
			if fi.ModTime().UnixNano() != sl.certTime {
				fmt.Print(" reload\n")
				return nil, ReloadError
			}
		}

		fmt.Print(" key ")
		fi, err1 = os.Stat(sl.keyFile)
		if err1 == nil {
			fmt.Printf(" nil %d %d ", fi.ModTime().UnixNano(), sl.keyTime)
			if fi.ModTime().UnixNano() != sl.keyTime {
				fmt.Print(" reload\n")
				return nil, ReloadError
			}
		}

		fmt.Print(" --\n")

		if err != nil {
			netErr, ok := err.(net.Error)

			//If this is a timeout, then continue to wait for
			//new connections
			if ok && netErr.Timeout() && netErr.Temporary() {
				continue
			}
		}

		return newConn, err
	}
}

// tcpKeepAliveListener sets TCP keep-alive timeouts on accepted
// connections. It's used by ListenAndServe and ListenAndServeTLS so
// dead TCP connections (e.g. closing laptop mid-download) eventually
// go away.
type tcpKeepAliveListener struct {
	*net.TCPListener
}

func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
	tc, err := ln.AcceptTCP()
	if err != nil {
		return
	}
	tc.SetKeepAlive(true)
	tc.SetKeepAlivePeriod(3 * time.Minute)
	return tc, nil
}
<|endoftext|>


<commit_before>package command

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"os"
	"strings"

	"github.com/BurntSushi/toml"
	"github.com/tcnksm/gcli/skeleton"
)

// ApplyCommand is a Command that generates a new cli project
type ApplyCommand struct {
	Meta
}

// Run generates a new cli project. It returns exit code
func (c *ApplyCommand) Run(args []string) int {

	var (
		frameworkStr string
		skipTest     bool
		verbose      bool
	)

	uflag := flag.NewFlagSet("apply", flag.ContinueOnError)
	uflag.Usage = func() { c.UI.Error(c.Help()) }

	uflag.StringVar(&frameworkStr, "framework", "", "framework")
	uflag.StringVar(&frameworkStr, "F", "", "framework (short)")

	uflag.BoolVar(&skipTest, "skip-test", false, "skip-test")
	uflag.BoolVar(&skipTest, "T", false, "skip-test (short)")

	uflag.BoolVar(&verbose, "verbose", false, "verbose")
	uflag.BoolVar(&verbose, "V", false, "verbose (short)")

	errR, errW := io.Pipe()
	errScanner := bufio.NewScanner(errR)
	uflag.SetOutput(errW)

	go func() {
		for errScanner.Scan() {
			c.UI.Error(errScanner.Text())
		}
	}()

	if err := uflag.Parse(args); err != nil {
		return 1
	}

	parsedArgs := uflag.Args()
	if len(parsedArgs) != 1 {
		c.UI.Error("Invalid argument: Usage glic apply [options] FILE")
		return 1
	}

	planFile := parsedArgs[0]
	c.UI.Info(fmt.Sprintf(
		"Use plan file %q for generating new cli project", planFile))

	// Check file is exist or not
	if _, err := os.Stat(planFile); os.IsNotExist(err) {
		c.UI.Error(fmt.Sprintf(
			"Plan file does not exsit"))
		return 1
	}

	// Decode plan file as skeleton.Executable
	executable := skeleton.NewExecutable()
	if _, err := toml.DecodeFile(planFile, executable); err != nil {
		c.UI.Error(fmt.Sprintf(
			"Failed to decode plan file %q: %s", planFile, err))
		return 1
	}

	output := executable.Name
	if _, err := os.Stat(output); !os.IsNotExist(err) {
		msg := fmt.Sprintf("Cannot create directory %s: file exists", output)
		c.UI.Error(msg)
		return 1
	}

	// Check option input first and if it's specified use it
	if len(frameworkStr) == 0 {
		if len(executable.FrameworkStr) != 0 {
			// If FrameworStr is specified from design file use it
			frameworkStr = executable.FrameworkStr
		} else {
			frameworkStr = defaultFrameworkString
		}
	}

	fmt.Println(frameworkStr)
	framework, err := skeleton.FrameworkByName(frameworkStr)
	if err != nil {
		c.UI.Error(fmt.Sprintf("Failed to generate %q: %s", executable.Name, err.Error()))
		return 1
	}

	// Channels to receive artifact path (result) and error
	artifactCh, errCh := make(chan string), make(chan error)

	// Define Skeleton
	skeleton := &skeleton.Skeleton{
		Path:       output,
		Framework:  framework,
		SkipTest:   skipTest,
		Executable: executable,
		ArtifactCh: artifactCh,
		ErrCh:      errCh,
		Verbose:    verbose,
		LogWriter:  os.Stdout,
	}

	// Create project directory
	doneCh := skeleton.Generate()

	for {
		select {
		case artifact := <-artifactCh:
			c.UI.Output(fmt.Sprintf("  Created %s", artifact))
		case err := <-errCh:
			c.UI.Error(fmt.Sprintf("Failed to generate %s: %s", output, err.Error()))

			// If some file are created before error happend
			// Should be cleanuped
			if _, err := os.Stat(output); !os.IsNotExist(err) {
				c.UI.Output(fmt.Sprintf("Cleanup %s", output))
				os.RemoveAll(output)
			}
			return ExitCodeFailed
		case <-doneCh:
			c.UI.Info(fmt.Sprintf("====> Successfully generated %s", executable.Name))
			return ExitCodeOK
		}
	}
}

// Synopsis is a one-line, short synopsis of the command.
func (c *ApplyCommand) Synopsis() string {
	return "Apply design template file for generating cli project"
}

// Help is a long-form help text that includes the command-line
// usage, a brief few sentences explaining the function of the command,
// and the complete list of flags the command accepts.
func (c *ApplyCommand) Help() string {
	helpText := `
Usage: gcli apply [option] FILE

  Apply design template file for generating cli project. You can generate
  design template file via 'gcli design' command. If framework name is not
  specified gcli use codegangsta/cli. You can set framework name via '-F'
  option. To check cli framework you can use, run 'gcli list'.

Options:

   -framework=name, -F        Cli framework name. By default, gcli use "codegangsta/cli"
                              To check cli framework you can use, run 'gcli list'.
                              If you set invalid framework, it will be failed.

   -skip-test, -T             Skip generating *_test.go file. By default, gcli generates
                              test file If you specify this flag, gcli will not generate
                              test files.
`
	return strings.TrimSpace(helpText)
}
<commit_msg>Add flag only for test<commit_after>package command

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"os"
	"strings"

	"github.com/BurntSushi/toml"
	"github.com/tcnksm/gcli/skeleton"
)

// ApplyCommand is a Command that generates a new cli project
type ApplyCommand struct {
	Meta
}

// Run generates a new cli project. It returns exit code
func (c *ApplyCommand) Run(args []string) int {

	var (
		frameworkStr string
		skipTest     bool
		verbose      bool
		owner        string
		name         string
	)

	uflag := flag.NewFlagSet("apply", flag.ContinueOnError)
	uflag.Usage = func() { c.UI.Error(c.Help()) }

	uflag.StringVar(&frameworkStr, "framework", "", "framework")
	uflag.StringVar(&frameworkStr, "F", "", "framework (short)")

	uflag.BoolVar(&skipTest, "skip-test", false, "skip-test")
	uflag.BoolVar(&skipTest, "T", false, "skip-test (short)")

	uflag.BoolVar(&verbose, "verbose", false, "verbose")
	uflag.BoolVar(&verbose, "V", false, "verbose (short)")

	// These flags are supposed only to use in test
	uflag.StringVar(&owner, "owner", "", "owner (Should only for test)")
	uflag.StringVar(&name, "name", "", "name (Should only for test)")

	errR, errW := io.Pipe()
	errScanner := bufio.NewScanner(errR)
	uflag.SetOutput(errW)

	go func() {
		for errScanner.Scan() {
			c.UI.Error(errScanner.Text())
		}
	}()

	if err := uflag.Parse(args); err != nil {
		return 1
	}

	parsedArgs := uflag.Args()
	if len(parsedArgs) != 1 {
		c.UI.Error("Invalid argument: Usage glic apply [options] FILE")
		return 1
	}

	planFile := parsedArgs[0]
	c.UI.Info(fmt.Sprintf(
		"Use plan file %q for generating new cli project", planFile))

	// Check file is exist or not
	if _, err := os.Stat(planFile); os.IsNotExist(err) {
		c.UI.Error(fmt.Sprintf(
			"Plan file does not exsit"))
		return 1
	}

	// Decode plan file as skeleton.Executable
	executable := skeleton.NewExecutable()
	if _, err := toml.DecodeFile(planFile, executable); err != nil {
		c.UI.Error(fmt.Sprintf(
			"Failed to decode plan file %q: %s", planFile, err))
		return 1
	}

	output := executable.Name
	if _, err := os.Stat(output); !os.IsNotExist(err) {
		msg := fmt.Sprintf("Cannot create directory %s: file exists", output)
		c.UI.Error(msg)
		return 1
	}

	// Check option input first and if it's specified use it
	if len(frameworkStr) == 0 {
		if len(executable.FrameworkStr) != 0 {
			// If FrameworStr is specified from design file use it
			frameworkStr = executable.FrameworkStr
		} else {
			frameworkStr = defaultFrameworkString
		}
	}

	fmt.Println(frameworkStr)
	framework, err := skeleton.FrameworkByName(frameworkStr)
	if err != nil {
		c.UI.Error(fmt.Sprintf("Failed to generate %q: %s", executable.Name, err.Error()))
		return 1
	}

	if len(name) != 0 {
		executable.Name = name
		output = name
	}

	if len(owner) != 0 {
		executable.Owner = owner
	}

	// Channels to receive artifact path (result) and error
	artifactCh, errCh := make(chan string), make(chan error)

	// Define Skeleton
	skeleton := &skeleton.Skeleton{
		Path:       output,
		Framework:  framework,
		SkipTest:   skipTest,
		Executable: executable,
		ArtifactCh: artifactCh,
		ErrCh:      errCh,
		Verbose:    verbose,
		LogWriter:  os.Stdout,
	}

	// Create project directory
	doneCh := skeleton.Generate()

	for {
		select {
		case artifact := <-artifactCh:
			c.UI.Output(fmt.Sprintf("  Created %s", artifact))
		case err := <-errCh:
			c.UI.Error(fmt.Sprintf("Failed to generate %s: %s", output, err.Error()))

			// If some file are created before error happend
			// Should be cleanuped
			if _, err := os.Stat(output); !os.IsNotExist(err) {
				c.UI.Output(fmt.Sprintf("Cleanup %s", output))
				os.RemoveAll(output)
			}
			return ExitCodeFailed
		case <-doneCh:
			c.UI.Info(fmt.Sprintf("====> Successfully generated %s", executable.Name))
			return ExitCodeOK
		}
	}
}

// Synopsis is a one-line, short synopsis of the command.
func (c *ApplyCommand) Synopsis() string {
	return "Apply design template file for generating cli project"
}

// Help is a long-form help text that includes the command-line
// usage, a brief few sentences explaining the function of the command,
// and the complete list of flags the command accepts.
func (c *ApplyCommand) Help() string {
	helpText := `
Usage: gcli apply [option] FILE

  Apply design template file for generating cli project. You can generate
  design template file via 'gcli design' command. If framework name is not
  specified gcli use codegangsta/cli. You can set framework name via '-F'
  option. To check cli framework you can use, run 'gcli list'.

Options:

   -framework=name, -F        Cli framework name. By default, gcli use "codegangsta/cli"
                              To check cli framework you can use, run 'gcli list'.
                              If you set invalid framework, it will be failed.

   -skip-test, -T             Skip generating *_test.go file. By default, gcli generates
                              test file If you specify this flag, gcli will not generate
                              test files.
`
	return strings.TrimSpace(helpText)
}
<|endoftext|>


<commit_before>package command

import (
	"fmt"
	"strings"

	"github.com/go-almeria/gitx/api"
	"github.com/go-almeria/gitx/meta"
)

// CountCommand Outputs commit count
type CountCommand struct {
	meta.Meta
}

func (c *CountCommand) Run(args []string) int {
	var all bool

	flags := c.Meta.FlagSet("count", meta.FlagSetDefault)
	flags.BoolVar(&all, "all", false, "")
	flags.Usage = func() { c.Ui.Error(c.Help()) }
	if err := flags.Parse(args); err != nil {
		return 1
	}

	args = flags.Args()
	if len(args) > 1 {
		flags.Usage()
		c.Ui.Error(fmt.Sprintf("\ncount expects at most one argument"))
		return 1
	}

	var g api.Git = *api.NewGit()
	g.Args = strings.Fields("log")

	return 0
}

func (c *CountCommand) Synopsis() string {
	return "Outputs commit counts"
}

func (c *CountCommand) Help() string {
	helpText := `
Usage: gitx count [--all]
`
	return strings.TrimSpace(helpText)
}
<commit_msg>should omit type api.Git from declaration of var g, it will be inferred from the right-hand side<commit_after>package command

import (
	"fmt"
	"strings"

	"github.com/go-almeria/gitx/api"
	"github.com/go-almeria/gitx/meta"
)

// CountCommand Outputs commit count
type CountCommand struct {
	meta.Meta
}

func (c *CountCommand) Run(args []string) int {
	var all bool

	flags := c.Meta.FlagSet("count", meta.FlagSetDefault)
	flags.BoolVar(&all, "all", false, "")
	flags.Usage = func() { c.Ui.Error(c.Help()) }
	if err := flags.Parse(args); err != nil {
		return 1
	}

	args = flags.Args()
	if len(args) > 1 {
		flags.Usage()
		c.Ui.Error(fmt.Sprintf("\ncount expects at most one argument"))
		return 1
	}

	g := *api.NewGit()
	g.Args = strings.Fields("log")

	return 0
}

func (c *CountCommand) Synopsis() string {
	return "Outputs commit counts"
}

func (c *CountCommand) Help() string {
	helpText := `
Usage: gitx count [--all]
`
	return strings.TrimSpace(helpText)
}
<|endoftext|>


<commit_before>// Copyright (c) Alex Ellis 2017. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

package proxy

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"
	"time"

	"github.com/openfaas/faas-cli/stack"
	"github.com/openfaas/faas/gateway/requests"
)

// FunctionResourceRequest defines a request to set function resources
type FunctionResourceRequest struct {
	Limits   *stack.FunctionResources
	Requests *stack.FunctionResources
}

func DeployFunction(fprocess string, gateway string, functionName string, image string,
	language string, replace bool, envVars map[string]string, network string,
	constraints []string, update bool, secrets []string, labels map[string]string,
	functionResourceRequest1 FunctionResourceRequest) {

	statusCode := DeployFunctionImpl(fprocess, gateway, functionName, image, language, replace, envVars, network, constraints, update, secrets, labels, functionResourceRequest1)

	if update == true && statusCode == http.StatusNotFound {
		// Re-run the function with update=false
		update = false
		DeployFunctionImpl(fprocess, gateway, functionName, image, language, replace, envVars, network, constraints, update, secrets, labels, functionResourceRequest1)
	}

}

// DeployFunction call FaaS server to deploy a new function
func DeployFunctionImpl(fprocess string, gateway string, functionName string, image string,
	language string, replace bool, envVars map[string]string, network string,
	constraints []string, update bool, secrets []string, labels map[string]string,
	functionResourceRequest1 FunctionResourceRequest) int {

	// Need to alter Gateway to allow nil/empty string as fprocess, to avoid this repetition.
	var fprocessTemplate string
	if len(fprocess) > 0 {
		fprocessTemplate = fprocess
	}

	gateway = strings.TrimRight(gateway, "/")

	if replace {
		DeleteFunction(gateway, functionName)
	}

	req := requests.CreateFunctionRequest{
		EnvProcess:  fprocessTemplate,
		Image:       image,
		Network:     network,
		Service:     functionName,
		EnvVars:     envVars,
		Constraints: constraints,
		Secrets:     secrets, // TODO: allow registry auth to be specified or read from local Docker credentials store
		Labels:      &labels,
	}

	hasLimits := false
	req.Limits = &requests.FunctionResources{}
	if functionResourceRequest1.Limits != nil && len(functionResourceRequest1.Limits.Memory) > 0 {
		hasLimits = true
		req.Limits.Memory = functionResourceRequest1.Limits.Memory
	}
	if functionResourceRequest1.Limits != nil && len(functionResourceRequest1.Limits.CPU) > 0 {
		hasLimits = true
		req.Limits.CPU = functionResourceRequest1.Limits.CPU
	}
	if !hasLimits {
		req.Limits = nil
	}

	hasRequests := false
	req.Requests = &requests.FunctionResources{}
	if functionResourceRequest1.Requests != nil && len(functionResourceRequest1.Requests.Memory) > 0 {
		hasRequests = true
		req.Requests.Memory = functionResourceRequest1.Requests.Memory
	}
	if functionResourceRequest1.Requests != nil && len(functionResourceRequest1.Requests.CPU) > 0 {
		hasRequests = true
		req.Requests.CPU = functionResourceRequest1.Requests.CPU
	}

	if !hasRequests {
		req.Requests = nil
	}

	reqBytes, _ := json.Marshal(&req)
	reader := bytes.NewReader(reqBytes)
	var request *http.Request

	timeout := 60 * time.Second
	client := MakeHTTPClient(&timeout)

	method := http.MethodPost
	// "application/json"
	if update {
		method = http.MethodPut
	}

	var err error
	request, err = http.NewRequest(method, gateway+"/system/functions", reader)
	SetAuth(request, gateway)
	if err != nil {
		fmt.Println(err)
		return -1
	}

	res, err := client.Do(request)
	if err != nil {
		fmt.Println("Is FaaS deployed? Do you need to specify the --gateway flag?")
		fmt.Println(err)
		return -1
	}

	if res.Body != nil {
		defer res.Body.Close()
	}

	switch res.StatusCode {
	case http.StatusOK, http.StatusCreated, http.StatusAccepted:
		if update {
			fmt.Println("Updated.")
		} else {
			fmt.Println("Deployed.")
		}

		deployedURL := fmt.Sprintf("URL: %s/function/%s\n", gateway, functionName)
		fmt.Println(deployedURL)
	case http.StatusUnauthorized:
		fmt.Println("unauthorized access, run \"faas-cli login\" to setup authentication for this server")
	default:
		bytesOut, err := ioutil.ReadAll(res.Body)
		if err == nil {
			fmt.Printf("Unexpected status: %d, message: %s\n", res.StatusCode, string(bytesOut))
		}
	}

	fmt.Println(res.Status)
	return res.StatusCode
}
<commit_msg>Rename function, return 500 ISE on failure<commit_after>// Copyright (c) Alex Ellis 2017. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

package proxy

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"
	"time"

	"github.com/openfaas/faas-cli/stack"
	"github.com/openfaas/faas/gateway/requests"
)

// FunctionResourceRequest defines a request to set function resources
type FunctionResourceRequest struct {
	Limits   *stack.FunctionResources
	Requests *stack.FunctionResources
}

func DeployFunction(fprocess string, gateway string, functionName string, image string,
	language string, replace bool, envVars map[string]string, network string,
	constraints []string, update bool, secrets []string, labels map[string]string,
	functionResourceRequest1 FunctionResourceRequest) {

	statusCode := Deploy(fprocess, gateway, functionName, image, language, replace, envVars, network, constraints, update, secrets, labels, functionResourceRequest1)

	if update == true && statusCode == http.StatusNotFound {
		// Re-run the function with update=false
		update = false
		Deploy(fprocess, gateway, functionName, image, language, replace, envVars, network, constraints, update, secrets, labels, functionResourceRequest1)
	}
}

// Call FaaS server to deploy a new function
func Deploy(fprocess string, gateway string, functionName string, image string,
	language string, replace bool, envVars map[string]string, network string,
	constraints []string, update bool, secrets []string, labels map[string]string,
	functionResourceRequest1 FunctionResourceRequest) int {

	// Need to alter Gateway to allow nil/empty string as fprocess, to avoid this repetition.
	var fprocessTemplate string
	if len(fprocess) > 0 {
		fprocessTemplate = fprocess
	}

	gateway = strings.TrimRight(gateway, "/")

	if replace {
		DeleteFunction(gateway, functionName)
	}

	req := requests.CreateFunctionRequest{
		EnvProcess:  fprocessTemplate,
		Image:       image,
		Network:     network,
		Service:     functionName,
		EnvVars:     envVars,
		Constraints: constraints,
		Secrets:     secrets, // TODO: allow registry auth to be specified or read from local Docker credentials store
		Labels:      &labels,
	}

	hasLimits := false
	req.Limits = &requests.FunctionResources{}
	if functionResourceRequest1.Limits != nil && len(functionResourceRequest1.Limits.Memory) > 0 {
		hasLimits = true
		req.Limits.Memory = functionResourceRequest1.Limits.Memory
	}
	if functionResourceRequest1.Limits != nil && len(functionResourceRequest1.Limits.CPU) > 0 {
		hasLimits = true
		req.Limits.CPU = functionResourceRequest1.Limits.CPU
	}
	if !hasLimits {
		req.Limits = nil
	}

	hasRequests := false
	req.Requests = &requests.FunctionResources{}
	if functionResourceRequest1.Requests != nil && len(functionResourceRequest1.Requests.Memory) > 0 {
		hasRequests = true
		req.Requests.Memory = functionResourceRequest1.Requests.Memory
	}
	if functionResourceRequest1.Requests != nil && len(functionResourceRequest1.Requests.CPU) > 0 {
		hasRequests = true
		req.Requests.CPU = functionResourceRequest1.Requests.CPU
	}

	if !hasRequests {
		req.Requests = nil
	}

	reqBytes, _ := json.Marshal(&req)
	reader := bytes.NewReader(reqBytes)
	var request *http.Request

	timeout := 60 * time.Second
	client := MakeHTTPClient(&timeout)

	method := http.MethodPost
	// "application/json"
	if update {
		method = http.MethodPut
	}

	var err error
	request, err = http.NewRequest(method, gateway+"/system/functions", reader)
	SetAuth(request, gateway)
	if err != nil {
		fmt.Println(err)
		return http.StatusInternalServerError
	}

	res, err := client.Do(request)
	if err != nil {
		fmt.Println("Is FaaS deployed? Do you need to specify the --gateway flag?")
		fmt.Println(err)
		return http.StatusInternalServerError
	}

	if res.Body != nil {
		defer res.Body.Close()
	}

	switch res.StatusCode {
	case http.StatusOK, http.StatusCreated, http.StatusAccepted:
		if update {
			fmt.Println("Updated.")
		} else {
			fmt.Println("Deployed.")
		}

		deployedURL := fmt.Sprintf("URL: %s/function/%s\n", gateway, functionName)
		fmt.Println(deployedURL)
	case http.StatusUnauthorized:
		fmt.Println("unauthorized access, run \"faas-cli login\" to setup authentication for this server")
	default:
		bytesOut, err := ioutil.ReadAll(res.Body)
		if err == nil {
			fmt.Printf("Unexpected status: %d, message: %s\n", res.StatusCode, string(bytesOut))
		}
	}

	fmt.Println(res.Status)
	return res.StatusCode
}
<|endoftext|>


<commit_before>// +build integration

package ansible_test

import (
	"os"
	"strings"

	"github.com/flant/werf/integration/utils/werfexec"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = FDescribe("Stapel builder with ansible", func() {
	Context("when building image based on alpine, ubuntu or centos", func() {
		AfterEach(func() {
			werfPurge("general", werfexec.CommandOptions{})
		})

		It("should successfully build image using arbitrary ansible modules", func(done Done) {
			Expect(werfBuild("general", werfexec.CommandOptions{})).To(Succeed())
			close(done)
		}, 120)
	})

	Context("when building stapel image based on centos 6 and 7", func() {
		AfterEach(func() {
			werfPurge("yum1", werfexec.CommandOptions{})
		})

		It("successfully installs packages using yum module", func(done Done) {
			Expect(werfBuild("yum1", werfexec.CommandOptions{})).To(Succeed())
			close(done)
		}, 120)
	})

	Context("when building stapel image based on centos 8", func() {
		AfterEach(func() {
			werfPurge("yum2", werfexec.CommandOptions{})
		})

		It("successfully installs packages using yum module", func(done Done) {
			Skip("FIXME https://github.com/flant/werf/issues/1983")
			Expect(werfBuild("yum2", werfexec.CommandOptions{})).To(Succeed())
			close(done)
		}, 120)
	})

	Context("when become_user task option used", func() {
		AfterEach(func() {
			werfPurge("become_user", werfexec.CommandOptions{})
		})

		It("successfully installs packages using yum module", func(done Done) {
			Skip("FIXME https://github.com/flant/werf/issues/1806")
			Expect(werfBuild("become_user", werfexec.CommandOptions{})).To(Succeed())
			close(done)
		}, 120)
	})

	Context("when using apt_key module used (1)", func() {
		AfterEach(func() {
			werfPurge("apt_key1-001", werfexec.CommandOptions{})
		})

		It("should fail to install package without a key and succeed with the key", func(done Done) {
			gotNoPubkey := false
			Expect(werfBuild("apt_key1-001", werfexec.CommandOptions{
				OutputLineHandler: func(line string) {
					if strings.Index(line, `public key is not available: NO_PUBKEY`) != -1 {
						gotNoPubkey = true
					}
				},
			})).NotTo(Succeed())
			Expect(gotNoPubkey).To(BeTrue())

			gotPackageInstallDone := false
			Expect(werfBuild("apt_key1-002", werfexec.CommandOptions{
				OutputLineHandler: func(line string) {
					if strings.Index(line, `apt 'Install package from new repository' [clickhouse-client]`) != -1 {
						gotPackageInstallDone = true
					}
					Expect(line).NotTo(MatchRegexp(`apt 'Install package from new repository' \[clickhouse-client\] \(".*" seconds\) FAILED`))
				},
			})).To(Succeed())
			Expect(gotPackageInstallDone).To(BeTrue())

			close(done)
		}, 120)
	})

	Context("when using apt_key module used (2)", func() {
		AfterEach(func() {
			werfPurge("apt_key2", werfexec.CommandOptions{})
		})

		It("should fail to install package without a key and succeed with the key", func(done Done) {
			Expect(werfBuild("apt_key2", werfexec.CommandOptions{})).To(Succeed())
			close(done)
		}, 120)
	})

	Context("when apt-mark from apt module used (https://github.com/flant/werf/issues/1820)", func() {
		AfterEach(func() {
			werfPurge("apt_mark_panic_1820", werfexec.CommandOptions{})
		})

		It("should not panic in all supported ubuntu versions", func(done Done) {
			Expect(werfBuild("apt_mark_panic_1820", werfexec.CommandOptions{})).To(Succeed())
			close(done)
		}, 120)
	})

	Context("when using yarn module to install nodejs packages", func() {
		AfterEach(func() {
			werfPurge("yarn", werfexec.CommandOptions{})
			os.RemoveAll("yarn/.git")
			os.RemoveAll("yarn_repo")
		})

		It("should install packages successfully", func(done Done) {
			Expect(setGitRepoState("yarn", "yarn_repo", "initial commit")).To(Succeed())
			Expect(werfBuild("yarn", werfexec.CommandOptions{})).To(Succeed())
			close(done)
		}, 120)
	})

	Context("when installing python requirements using ansible and python files contain utf-8 chars", func() {
		AfterEach(func() {
			werfPurge("python_encoding", werfexec.CommandOptions{})
			os.RemoveAll("python_encoding/.git")
			os.RemoveAll("python_encoding_repo")
		})

		It("should install packages successfully without utf-8 related problems", func(done Done) {
			Expect(setGitRepoState("python_encoding", "python_encoding_repo", "initial commit")).To(Succeed())
			Expect(werfBuild("python_encoding", werfexec.CommandOptions{})).To(Succeed())
			close(done)
		}, 900)
	})

	Context("Non standard PATH used in the base image (https://github.com/flant/werf/issues/1836) ", func() {
		AfterEach(func() {
			werfPurge("path_redefined_in_stapel_1836", werfexec.CommandOptions{})
		})

		It("PATH should not be redefined in stapel build container", func(done Done) {
			Expect(werfBuild("path_redefined_in_stapel_1836", werfexec.CommandOptions{})).To(Succeed())
			close(done)
		}, 120)
	})
})
<commit_msg>[tests] Fix ansible test typo FDescribe->Describe<commit_after>// +build integration

package ansible_test

import (
	"os"
	"strings"

	"github.com/flant/werf/integration/utils/werfexec"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Stapel builder with ansible", func() {
	Context("when building image based on alpine, ubuntu or centos", func() {
		AfterEach(func() {
			werfPurge("general", werfexec.CommandOptions{})
		})

		It("should successfully build image using arbitrary ansible modules", func(done Done) {
			Expect(werfBuild("general", werfexec.CommandOptions{})).To(Succeed())
			close(done)
		}, 120)
	})

	Context("when building stapel image based on centos 6 and 7", func() {
		AfterEach(func() {
			werfPurge("yum1", werfexec.CommandOptions{})
		})

		It("successfully installs packages using yum module", func(done Done) {
			Expect(werfBuild("yum1", werfexec.CommandOptions{})).To(Succeed())
			close(done)
		}, 120)
	})

	Context("when building stapel image based on centos 8", func() {
		AfterEach(func() {
			werfPurge("yum2", werfexec.CommandOptions{})
		})

		It("successfully installs packages using yum module", func(done Done) {
			Skip("FIXME https://github.com/flant/werf/issues/1983")
			Expect(werfBuild("yum2", werfexec.CommandOptions{})).To(Succeed())
			close(done)
		}, 120)
	})

	Context("when become_user task option used", func() {
		AfterEach(func() {
			werfPurge("become_user", werfexec.CommandOptions{})
		})

		It("successfully installs packages using yum module", func(done Done) {
			Skip("FIXME https://github.com/flant/werf/issues/1806")
			Expect(werfBuild("become_user", werfexec.CommandOptions{})).To(Succeed())
			close(done)
		}, 120)
	})

	Context("when using apt_key module used (1)", func() {
		AfterEach(func() {
			werfPurge("apt_key1-001", werfexec.CommandOptions{})
		})

		It("should fail to install package without a key and succeed with the key", func(done Done) {
			gotNoPubkey := false
			Expect(werfBuild("apt_key1-001", werfexec.CommandOptions{
				OutputLineHandler: func(line string) {
					if strings.Index(line, `public key is not available: NO_PUBKEY`) != -1 {
						gotNoPubkey = true
					}
				},
			})).NotTo(Succeed())
			Expect(gotNoPubkey).To(BeTrue())

			gotPackageInstallDone := false
			Expect(werfBuild("apt_key1-002", werfexec.CommandOptions{
				OutputLineHandler: func(line string) {
					if strings.Index(line, `apt 'Install package from new repository' [clickhouse-client]`) != -1 {
						gotPackageInstallDone = true
					}
					Expect(line).NotTo(MatchRegexp(`apt 'Install package from new repository' \[clickhouse-client\] \(".*" seconds\) FAILED`))
				},
			})).To(Succeed())
			Expect(gotPackageInstallDone).To(BeTrue())

			close(done)
		}, 120)
	})

	Context("when using apt_key module used (2)", func() {
		AfterEach(func() {
			werfPurge("apt_key2", werfexec.CommandOptions{})
		})

		It("should fail to install package without a key and succeed with the key", func(done Done) {
			Expect(werfBuild("apt_key2", werfexec.CommandOptions{})).To(Succeed())
			close(done)
		}, 120)
	})

	Context("when apt-mark from apt module used (https://github.com/flant/werf/issues/1820)", func() {
		AfterEach(func() {
			werfPurge("apt_mark_panic_1820", werfexec.CommandOptions{})
		})

		It("should not panic in all supported ubuntu versions", func(done Done) {
			Expect(werfBuild("apt_mark_panic_1820", werfexec.CommandOptions{})).To(Succeed())
			close(done)
		}, 120)
	})

	Context("when using yarn module to install nodejs packages", func() {
		AfterEach(func() {
			werfPurge("yarn", werfexec.CommandOptions{})
			os.RemoveAll("yarn/.git")
			os.RemoveAll("yarn_repo")
		})

		It("should install packages successfully", func(done Done) {
			Expect(setGitRepoState("yarn", "yarn_repo", "initial commit")).To(Succeed())
			Expect(werfBuild("yarn", werfexec.CommandOptions{})).To(Succeed())
			close(done)
		}, 120)
	})

	Context("when installing python requirements using ansible and python files contain utf-8 chars", func() {
		AfterEach(func() {
			werfPurge("python_encoding", werfexec.CommandOptions{})
			os.RemoveAll("python_encoding/.git")
			os.RemoveAll("python_encoding_repo")
		})

		It("should install packages successfully without utf-8 related problems", func(done Done) {
			Expect(setGitRepoState("python_encoding", "python_encoding_repo", "initial commit")).To(Succeed())
			Expect(werfBuild("python_encoding", werfexec.CommandOptions{})).To(Succeed())
			close(done)
		}, 900)
	})

	Context("Non standard PATH used in the base image (https://github.com/flant/werf/issues/1836) ", func() {
		AfterEach(func() {
			werfPurge("path_redefined_in_stapel_1836", werfexec.CommandOptions{})
		})

		It("PATH should not be redefined in stapel build container", func(done Done) {
			Expect(werfBuild("path_redefined_in_stapel_1836", werfexec.CommandOptions{})).To(Succeed())
			close(done)
		}, 120)
	})
})
<|endoftext|>


<commit_before>package integration_test

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"path/filepath"
	"regexp"
	"strings"
	"time"

	"github.com/datawire/dlib/dlog"
	"github.com/telepresenceio/telepresence/v2/integration_test/itest"
)

// Test_RestartInterceptedPod build belongs to the interceptMountSuite because we want to
// verify that the mount survives the scaling
func (s *interceptMountSuite) Test_RestartInterceptedPod() {
	assert := s.Assert()
	require := s.Require()
	ctx := s.Context()
	rx := regexp.MustCompile(fmt.Sprintf(`Intercept name\s*: %s-%s\s+State\s*: ([^\n]+)\n`, s.ServiceName(), s.AppNamespace()))

	// Scale down to zero pods
	require.NoError(s.Kubectl(ctx, "scale", "deploy", s.ServiceName(), "--replicas", "0"))

	// Verify that intercept remains but that no agent is found. User require here
	// to avoid a hanging os.Stat call unless this succeeds.
	require.Eventually(func() bool {
		stdout := itest.TelepresenceOk(ctx, "--namespace", s.AppNamespace(), "list")
		if match := rx.FindStringSubmatch(stdout); match != nil {
			return match[1] == "WAITING" || strings.Contains(match[1], `No agent found for "`+s.ServiceName()+`"`)
		}
		return false
	}, 15*time.Second, time.Second)

	// Verify that volume mount is broken
	time.Sleep(time.Second) // avoid a stat just when the intercept became inactive as it sometimes causes a hang
	_, err := os.Stat(filepath.Join(s.mountPoint, "var"))
	assert.Error(err, "Stat on <mount point>/var succeeded although no agent was found")

	// Scale up again (start intercepted pod)
	assert.NoError(s.Kubectl(ctx, "scale", "deploy", s.ServiceName(), "--replicas", "1"))

	// Verify that intercept becomes active
	require.Eventually(func() bool {
		stdout := itest.TelepresenceOk(ctx, "--namespace", s.AppNamespace(), "list")
		if match := rx.FindStringSubmatch(stdout); match != nil {
			return match[1] == "ACTIVE"
		}
		return false
	}, 15*time.Second, time.Second)

	// Verify that volume mount is restored
	time.Sleep(time.Second) // avoid a stat just when the intercept became active as it sometimes causes a hang
	assert.Eventually(func() bool {
		st, err := os.Stat(filepath.Join(s.mountPoint, "var"))
		return err == nil && st.IsDir()
	}, 5*time.Second, time.Second)
}

// Test_StopInterceptedPodOfMany build belongs to the interceptMountSuite because we want to
// verify that the mount survives the scaling
func (s *interceptMountSuite) Test_StopInterceptedPodOfMany() {
	assert := s.Assert()
	require := s.Require()
	ctx := s.Context()

	// Terminating is not a state, so you may want to wrap calls to this function in an eventually
	// to give any pods that are terminating the chance to complete.
	// https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/
	helloPods := func() []string {
		pods, err := s.KubectlOut(ctx, "get", "pods",
			"--field-selector", "status.phase==Running",
			"-l", "app="+s.ServiceName(),
			"-o", "jsonpath={.items[*].metadata.name}")
		assert.NoError(err)
		pods = strings.TrimSpace(pods)
		dlog.Infof(ctx, "Pods = '%s'", pods)
		return strings.Split(pods, " ")
	}

	// Wait for exactly one active pod
	var currentPod string
	require.Eventually(func() bool {
		currentPods := helloPods()
		if len(currentPods) == 1 {
			currentPod = currentPods[0]
			return true
		}
		return false
	}, 20*time.Second, 2*time.Second)

	// Scale up to two pods
	require.NoError(s.Kubectl(ctx, "scale", "deploy", s.ServiceName(), "--replicas", "2"))
	defer func() {
		_ = s.Kubectl(ctx, "scale", "deploy", s.ServiceName(), "--replicas", "1")
	}()

	// Wait for second pod to arrive
	assert.Eventually(func() bool { return len(helloPods()) == 2 }, 5*time.Second, time.Second)
	s.CapturePodLogs(ctx, "app=echo", "traffic-agent", s.AppNamespace())

	// Delete the currently intercepted pod
	require.NoError(s.Kubectl(ctx, "delete", "pod", currentPod))

	// Wait for that pod to disappear
	assert.Eventually(
		func() bool {
			pods := helloPods()
			for _, zp := range pods {
				if zp == currentPod {
					return false
				}
			}
			return len(pods) == 2
		}, 15*time.Second, time.Second)
	s.CapturePodLogs(ctx, "app=echo", "traffic-agent", s.AppNamespace())

	// Verify that intercept is still active
	rx := regexp.MustCompile(fmt.Sprintf(`Intercept name\s*: ` + s.ServiceName() + `-` + s.AppNamespace() + `\s+State\s*: ([^\n]+)\n`))
	assert.Eventually(func() bool {
		stdout := itest.TelepresenceOk(ctx, "--namespace", s.AppNamespace(), "list", "--intercepts")
		dlog.Debugf(ctx, "match %q in %q", rx.String(), stdout)
		if match := rx.FindStringSubmatch(stdout); match != nil {
			return match[1] == "ACTIVE"
		}
		return false
	}, 15*time.Second, time.Second)

	// Verify response from intercepting client
	require.Eventually(func() bool {
		hc := http.Client{Timeout: time.Second}
		resp, err := hc.Get("http://" + s.ServiceName())
		if err != nil {
			return false
		}
		defer resp.Body.Close()
		body, err := io.ReadAll(resp.Body)
		if err != nil {
			return false
		}
		return s.ServiceName()+" from intercept at /" == string(body)
	}, 15*time.Second, time.Second)

	// Verify that volume mount is restored
	time.Sleep(3 * time.Second) // avoid a stat just when the intercept became active as it sometimes causes a hang
	st, err := os.Stat(filepath.Join(s.mountPoint, "var"))
	require.NoError(err, "Stat on <mount point>/var failed")
	require.True(st.IsDir(), "<mount point>/var is not a directory")
}
<commit_msg>Make the pod scaling tests more reliable.<commit_after>package integration_test

import (
	"bufio"
	"context"
	"fmt"
	"io"
	"net/http"
	"os"
	"path/filepath"
	"regexp"
	"strings"
	"time"

	"github.com/datawire/dlib/dlog"
	"github.com/telepresenceio/telepresence/v2/integration_test/itest"
)

// Test_RestartInterceptedPod build belongs to the interceptMountSuite because we want to
// verify that the mount survives the scaling
func (s *interceptMountSuite) Test_RestartInterceptedPod() {
	assert := s.Assert()
	require := s.Require()
	ctx := s.Context()
	rx := regexp.MustCompile(fmt.Sprintf(`Intercept name\s*: %s-%s\s+State\s*: ([^\n]+)\n`, s.ServiceName(), s.AppNamespace()))

	// Scale down to zero pods
	require.NoError(s.Kubectl(ctx, "scale", "deploy", s.ServiceName(), "--replicas", "0"))

	// Wait until the pods have terminated.
	require.Eventually(func() bool { return len(s.runningPods(ctx)) == 0 }, 30*time.Second, 2*time.Second)

	// Verify that intercept remains but that no agent is found. User require here
	// to avoid a hanging os.Stat call unless this succeeds.
	require.Eventually(func() bool {
		stdout := itest.TelepresenceOk(ctx, "--namespace", s.AppNamespace(), "list")
		if match := rx.FindStringSubmatch(stdout); match != nil {
			return match[1] == "WAITING" || strings.Contains(match[1], `No agent found for "`+s.ServiceName()+`"`)
		}
		return false
	}, 15*time.Second, time.Second)

	// Verify that volume mount is broken
	time.Sleep(time.Second) // avoid a stat just when the intercept became inactive as it sometimes causes a hang
	_, err := os.Stat(filepath.Join(s.mountPoint, "var"))
	assert.Error(err, "Stat on <mount point>/var succeeded although no agent was found")

	// Scale up again (start intercepted pod)
	assert.NoError(s.Kubectl(ctx, "scale", "deploy", s.ServiceName(), "--replicas", "1"))
	require.Eventually(func() bool { return len(s.runningPods(ctx)) == 1 }, 30*time.Second, 2*time.Second)

	// Verify that intercept becomes active
	require.Eventually(func() bool {
		stdout := itest.TelepresenceOk(ctx, "--namespace", s.AppNamespace(), "list")
		if match := rx.FindStringSubmatch(stdout); match != nil {
			return match[1] == "ACTIVE"
		}
		return false
	}, 15*time.Second, time.Second)

	// Verify that volume mount is restored
	time.Sleep(time.Second) // avoid a stat just when the intercept became active as it sometimes causes a hang
	assert.Eventually(func() bool {
		st, err := os.Stat(filepath.Join(s.mountPoint, "var"))
		return err == nil && st.IsDir()
	}, 5*time.Second, time.Second)
}

// Test_StopInterceptedPodOfMany build belongs to the interceptMountSuite because we want to
// verify that the mount survives the scaling
func (s *interceptMountSuite) Test_StopInterceptedPodOfMany() {
	assert := s.Assert()
	require := s.Require()
	ctx := s.Context()

	// Wait for exactly one active pod
	var currentPod string
	require.Eventually(func() bool {
		currentPods := s.runningPods(ctx)
		if len(currentPods) == 1 {
			currentPod = currentPods[0]
			return true
		}
		return false
	}, 20*time.Second, 2*time.Second)

	// Scale up to two pods
	require.NoError(s.Kubectl(ctx, "scale", "deploy", s.ServiceName(), "--replicas", "2"))
	defer func() {
		_ = s.Kubectl(ctx, "scale", "deploy", s.ServiceName(), "--replicas", "1")
	}()

	// Wait for second pod to arrive
	assert.Eventually(func() bool { return len(s.runningPods(ctx)) == 2 }, 5*time.Second, time.Second)
	s.CapturePodLogs(ctx, "app=echo", "traffic-agent", s.AppNamespace())

	// Delete the currently intercepted pod
	require.NoError(s.Kubectl(ctx, "delete", "pod", currentPod))

	// Wait for that pod to disappear
	assert.Eventually(
		func() bool {
			pods := s.runningPods(ctx)
			for _, zp := range pods {
				if zp == currentPod {
					return false
				}
			}
			return len(pods) == 2
		}, 15*time.Second, time.Second)
	s.CapturePodLogs(ctx, "app=echo", "traffic-agent", s.AppNamespace())

	// Verify that intercept is still active
	rx := regexp.MustCompile(fmt.Sprintf(`Intercept name\s*: ` + s.ServiceName() + `-` + s.AppNamespace() + `\s+State\s*: ([^\n]+)\n`))
	assert.Eventually(func() bool {
		stdout := itest.TelepresenceOk(ctx, "--namespace", s.AppNamespace(), "list", "--intercepts")
		dlog.Debugf(ctx, "match %q in %q", rx.String(), stdout)
		if match := rx.FindStringSubmatch(stdout); match != nil {
			return match[1] == "ACTIVE"
		}
		return false
	}, 15*time.Second, time.Second)

	// Verify response from intercepting client
	require.Eventually(func() bool {
		hc := http.Client{Timeout: time.Second}
		resp, err := hc.Get("http://" + s.ServiceName())
		if err != nil {
			return false
		}
		defer resp.Body.Close()
		body, err := io.ReadAll(resp.Body)
		if err != nil {
			return false
		}
		return s.ServiceName()+" from intercept at /" == string(body)
	}, 15*time.Second, time.Second)

	// Verify that volume mount is restored
	time.Sleep(3 * time.Second) // avoid a stat just when the intercept became active as it sometimes causes a hang
	st, err := os.Stat(filepath.Join(s.mountPoint, "var"))
	require.NoError(err, "Stat on <mount point>/var failed")
	require.True(st.IsDir(), "<mount point>/var is not a directory")
}

// Terminating is not a state, so you may want to wrap calls to this function in an eventually
// to give any pods that are terminating the chance to complete.
// https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/
func (s *interceptMountSuite) runningPods(ctx context.Context) (pods []string) {
	out, err := s.KubectlOut(ctx, "get", "pods", "--no-headers",
		"--field-selector", "status.phase=Running",
		"-l", "app="+s.ServiceName())
	s.NoError(err)
	if strings.HasPrefix(out, "No resources found") {
		return nil
	}
	sc := bufio.NewScanner(strings.NewReader(out))
	for sc.Scan() {
		txt := sc.Text()
		// Terminating is not a state: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/
		if strings.Contains(txt, "Terminating") {
			continue
		}
		txt = strings.TrimSpace(txt)
		if spi := strings.IndexByte(txt, ' '); spi > 0 {
			pods = append(pods, txt[:spi])
		}
	}
	return pods
}
<|endoftext|>


<commit_before>package gateway

import (
	"crypto/tls"
	"crypto/x509"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"sync"
	"time"

	log "github.com/sirupsen/logrus"
	"github.com/brocaar/loraserver/api/gw"
	"github.com/brocaar/loraserver/internal/backend"
	"github.com/brocaar/loraserver/internal/common"
	"github.com/brocaar/lorawan"
	"github.com/eclipse/paho.mqtt.golang"
	"github.com/garyburd/redigo/redis"
	"github.com/pkg/errors"
)

const rxTopic = "gateway/+/rx"
const statsTopic = "gateway/+/stats"
const uplinkLockTTL = time.Millisecond * 500
const statsLockTTL = time.Millisecond * 500

// Backend implements a MQTT pub-sub backend.
type Backend struct {
	conn            mqtt.Client
	rxPacketChan    chan gw.RXPacket
	statsPacketChan chan gw.GatewayStatsPacket
	wg              sync.WaitGroup
}

// NewBackend creates a new Backend.
func NewBackend(server, username, password, cafile string) (backend.Gateway, error) {
	b := Backend{
		rxPacketChan:    make(chan gw.RXPacket),
		statsPacketChan: make(chan gw.GatewayStatsPacket),
	}

	opts := mqtt.NewClientOptions()
	opts.AddBroker(server)
	opts.SetUsername(username)
	opts.SetPassword(password)
	opts.SetOnConnectHandler(b.onConnected)
	opts.SetConnectionLostHandler(b.onConnectionLost)

	if cafile != "" {
		tlsconfig, err := newTLSConfig(cafile)
		if err != nil {
			log.Fatalf("Error with the mqtt CA certificate: %s", err)
		} else {
			opts.SetTLSConfig(tlsconfig)
		}
	}

	log.WithField("server", server).Info("backend/gateway: connecting to mqtt broker")
	b.conn = mqtt.NewClient(opts)
	for {
		if token := b.conn.Connect(); token.Wait() && token.Error() != nil {
			log.Errorf("backend/gateway: connecting to mqtt broker failed, will retry in 2s: %s", token.Error())
			time.Sleep(2 * time.Second)
		} else {
			break
		}
	}

	return &b, nil
}

func newTLSConfig(cafile string) (*tls.Config, error) {
	// Import trusted certificates from CAfile.pem.

	cert, err := ioutil.ReadFile(cafile)
	if err != nil {
		log.Errorf("backend: couldn't load cafile: %s", err)
		return nil, err
	}

	certpool := x509.NewCertPool()
	certpool.AppendCertsFromPEM(cert)

	// Create tls.Config with desired tls properties
	return &tls.Config{
		// RootCAs = certs used to verify server cert.
		RootCAs: certpool,
	}, nil
}

// Close closes the backend.
// Note that this closes the backend one-way (gateway to backend).
// This makes it possible to perform a graceful shutdown (e.g. when there are
// still packets to send back to the gateway).
func (b *Backend) Close() error {
	log.Info("backend/gateway: closing backend")
	log.WithField("topic", rxTopic).Info("backend/gateway: unsubscribing from rx topic")
	if token := b.conn.Unsubscribe(rxTopic); token.Wait() && token.Error() != nil {
		return fmt.Errorf("backend/gateway: unsubscribe from %s error: %s", rxTopic, token.Error())
	}
	log.WithField("topic", statsTopic).Info("backend/gateway: unsubscribing from stats topic")
	if token := b.conn.Unsubscribe(statsTopic); token.Wait() && token.Error() != nil {
		return fmt.Errorf("backend/gateway: unsubscribe from %s error: %s", statsTopic, token.Error())
	}
	log.Info("backend/gateway: handling last messages")
	b.wg.Wait()
	close(b.rxPacketChan)
	close(b.statsPacketChan)
	return nil
}

// RXPacketChan returns the RXPacket channel.
func (b *Backend) RXPacketChan() chan gw.RXPacket {
	return b.rxPacketChan
}

// StatsPacketChan returns the gateway stats channel.
func (b *Backend) StatsPacketChan() chan gw.GatewayStatsPacket {
	return b.statsPacketChan
}

// SendTXPacket sends the given TXPacket to the gateway.
func (b *Backend) SendTXPacket(txPacket gw.TXPacket) error {
	phyB, err := txPacket.PHYPayload.MarshalBinary()
	if err != nil {
		return errors.Wrap(err, "marshal binary error")
	}
	bytes, err := json.Marshal(gw.TXPacketBytes{
		TXInfo:     txPacket.TXInfo,
		PHYPayload: phyB,
	})
	if err != nil {
		return fmt.Errorf("backend/gateway: tx packet marshal error: %s", err)
	}

	topic := fmt.Sprintf("gateway/%s/tx", txPacket.TXInfo.MAC)
	log.WithField("topic", topic).Info("backend/gateway: publishing tx packet")

	if token := b.conn.Publish(topic, 0, false, bytes); token.Wait() && token.Error() != nil {
		return fmt.Errorf("backend/gateway: publish tx packet failed: %s", token.Error())
	}
	return nil
}

func (b *Backend) rxPacketHandler(c mqtt.Client, msg mqtt.Message) {
	b.wg.Add(1)
	defer b.wg.Done()

	log.Info("backend/gateway: rx packet received")

	var phy lorawan.PHYPayload
	var rxPacketBytes gw.RXPacketBytes
	if err := json.Unmarshal(msg.Payload(), &rxPacketBytes); err != nil {
		log.WithFields(log.Fields{
			"data_base64": base64.StdEncoding.EncodeToString(msg.Payload()),
		}).Errorf("backend/gateway: unmarshal rx packet error: %s", err)
		return
	}

	if err := phy.UnmarshalBinary(rxPacketBytes.PHYPayload); err != nil {
		log.WithFields(log.Fields{
			"data_base64": base64.StdEncoding.EncodeToString(msg.Payload()),
		}).Errorf("backend/gateway: unmarshal phypayload error: %s", err)
	}

	// Since with MQTT all subscribers will receive the uplink messages sent
	// by all the gatewyas, the first instance receiving the message must lock it,
	// so that other instances can ignore the same message (from the same gw).
	// As an unique id, the gw mac + base64 encoded payload is used. This is because
	// we can't trust any of the data, as the MIC hasn't been validated yet.
	strB, err := phy.MarshalText()
	if err != nil {
		log.Errorf("backend/gateway: marshal text error: %s", err)
	}
	key := fmt.Sprintf("lora:ns:uplink:lock:%s:%s", rxPacketBytes.RXInfo.MAC, string(strB))
	redisConn := common.RedisPool.Get()
	defer redisConn.Close()

	_, err = redis.String(redisConn.Do("SET", key, "lock", "PX", int64(uplinkLockTTL/time.Millisecond), "NX"))
	if err != nil {
		if err == redis.ErrNil {
			// the payload is already being processed by an other instance
			return
		}
		log.Errorf("backend/gateway: acquire uplink payload lock error: %s", err)
		return
	}

	b.rxPacketChan <- gw.RXPacket{
		RXInfo:     rxPacketBytes.RXInfo,
		PHYPayload: phy,
	}
}

func (b *Backend) statsPacketHandler(c mqtt.Client, msg mqtt.Message) {
	b.wg.Add(1)
	defer b.wg.Done()

	var statsPacket gw.GatewayStatsPacket
	if err := json.Unmarshal(msg.Payload(), &statsPacket); err != nil {
		log.WithFields(log.Fields{
			"data_base64": base64.StdEncoding.EncodeToString(msg.Payload()),
		}).Errorf("backend/gateway: unmarshal stats packet error: %s", err)
		return
	}

	// Since with MQTT all subscribers will receive the uplink messages sent
	// by all the gatewyas, the first instance receiving the message must lock it,
	// so that other instances can ignore the same message (from the same gw).
	// As an unique id, the gw mac + base64 encoded payload is used. This is because
	// we can't trust any of the data, as the MIC hasn't been validated yet.
	key := fmt.Sprintf("lora:ns:stats:lock:%s", statsPacket.MAC)
	redisConn := common.RedisPool.Get()
	defer redisConn.Close()

	_, err := redis.String(redisConn.Do("SET", key, "lock", "PX", int64(statsLockTTL/time.Millisecond), "NX"))
	if err != nil {
		if err == redis.ErrNil {
			// the payload is already being processed by an other instance
			return
		}
		log.Errorf("backend/gateway: acquire stats lock error: %s", err)
		return
	}

	log.WithField("mac", statsPacket.MAC).Info("backend/gateway: gateway stats packet received")
	b.statsPacketChan <- statsPacket
}

func (b *Backend) onConnected(c mqtt.Client) {
	log.Info("backend/gateway: connected to mqtt server")
	for {
		log.WithField("topic", rxTopic).Info("backend/gateway: subscribing to rx topic")
		if token := b.conn.Subscribe(rxTopic, 2, b.rxPacketHandler); token.Wait() && token.Error() != nil {
			log.WithField("topic", rxTopic).Errorf("backend/gateway: subscribe error: %s", token.Error())
			time.Sleep(time.Second)
			continue
		}
		break
	}

	for {
		log.WithField("topic", statsTopic).Info("backend/gateway: subscribing to stats topic")
		if token := b.conn.Subscribe(statsTopic, 2, b.statsPacketHandler); token.Wait() && token.Error() != nil {
			log.WithField("topic", statsTopic).Errorf("backend/gateway: subscribe error: %s", token.Error())
			time.Sleep(time.Second)
			continue
		}
		break
	}
}

func (b *Backend) onConnectionLost(c mqtt.Client, reason error) {
	log.Errorf("backend/gateway: mqtt connection error: %s", reason)
}
<commit_msg>Add missing token.<commit_after>package gateway

import (
	"crypto/tls"
	"crypto/x509"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"sync"
	"time"

	"github.com/brocaar/loraserver/api/gw"
	"github.com/brocaar/loraserver/internal/backend"
	"github.com/brocaar/loraserver/internal/common"
	"github.com/brocaar/lorawan"
	"github.com/eclipse/paho.mqtt.golang"
	"github.com/garyburd/redigo/redis"
	"github.com/pkg/errors"
	log "github.com/sirupsen/logrus"
)

const rxTopic = "gateway/+/rx"
const statsTopic = "gateway/+/stats"
const uplinkLockTTL = time.Millisecond * 500
const statsLockTTL = time.Millisecond * 500

// Backend implements a MQTT pub-sub backend.
type Backend struct {
	conn            mqtt.Client
	rxPacketChan    chan gw.RXPacket
	statsPacketChan chan gw.GatewayStatsPacket
	wg              sync.WaitGroup
}

// NewBackend creates a new Backend.
func NewBackend(server, username, password, cafile string) (backend.Gateway, error) {
	b := Backend{
		rxPacketChan:    make(chan gw.RXPacket),
		statsPacketChan: make(chan gw.GatewayStatsPacket),
	}

	opts := mqtt.NewClientOptions()
	opts.AddBroker(server)
	opts.SetUsername(username)
	opts.SetPassword(password)
	opts.SetOnConnectHandler(b.onConnected)
	opts.SetConnectionLostHandler(b.onConnectionLost)

	if cafile != "" {
		tlsconfig, err := newTLSConfig(cafile)
		if err != nil {
			log.Fatalf("Error with the mqtt CA certificate: %s", err)
		} else {
			opts.SetTLSConfig(tlsconfig)
		}
	}

	log.WithField("server", server).Info("backend/gateway: connecting to mqtt broker")
	b.conn = mqtt.NewClient(opts)
	for {
		if token := b.conn.Connect(); token.Wait() && token.Error() != nil {
			log.Errorf("backend/gateway: connecting to mqtt broker failed, will retry in 2s: %s", token.Error())
			time.Sleep(2 * time.Second)
		} else {
			break
		}
	}

	return &b, nil
}

func newTLSConfig(cafile string) (*tls.Config, error) {
	// Import trusted certificates from CAfile.pem.

	cert, err := ioutil.ReadFile(cafile)
	if err != nil {
		log.Errorf("backend: couldn't load cafile: %s", err)
		return nil, err
	}

	certpool := x509.NewCertPool()
	certpool.AppendCertsFromPEM(cert)

	// Create tls.Config with desired tls properties
	return &tls.Config{
		// RootCAs = certs used to verify server cert.
		RootCAs: certpool,
	}, nil
}

// Close closes the backend.
// Note that this closes the backend one-way (gateway to backend).
// This makes it possible to perform a graceful shutdown (e.g. when there are
// still packets to send back to the gateway).
func (b *Backend) Close() error {
	log.Info("backend/gateway: closing backend")
	log.WithField("topic", rxTopic).Info("backend/gateway: unsubscribing from rx topic")
	if token := b.conn.Unsubscribe(rxTopic); token.Wait() && token.Error() != nil {
		return fmt.Errorf("backend/gateway: unsubscribe from %s error: %s", rxTopic, token.Error())
	}
	log.WithField("topic", statsTopic).Info("backend/gateway: unsubscribing from stats topic")
	if token := b.conn.Unsubscribe(statsTopic); token.Wait() && token.Error() != nil {
		return fmt.Errorf("backend/gateway: unsubscribe from %s error: %s", statsTopic, token.Error())
	}
	log.Info("backend/gateway: handling last messages")
	b.wg.Wait()
	close(b.rxPacketChan)
	close(b.statsPacketChan)
	return nil
}

// RXPacketChan returns the RXPacket channel.
func (b *Backend) RXPacketChan() chan gw.RXPacket {
	return b.rxPacketChan
}

// StatsPacketChan returns the gateway stats channel.
func (b *Backend) StatsPacketChan() chan gw.GatewayStatsPacket {
	return b.statsPacketChan
}

// SendTXPacket sends the given TXPacket to the gateway.
func (b *Backend) SendTXPacket(txPacket gw.TXPacket) error {
	phyB, err := txPacket.PHYPayload.MarshalBinary()
	if err != nil {
		return errors.Wrap(err, "marshal binary error")
	}
	bytes, err := json.Marshal(gw.TXPacketBytes{
		Token:      txPacket.Token,
		TXInfo:     txPacket.TXInfo,
		PHYPayload: phyB,
	})
	if err != nil {
		return fmt.Errorf("backend/gateway: tx packet marshal error: %s", err)
	}

	topic := fmt.Sprintf("gateway/%s/tx", txPacket.TXInfo.MAC)
	log.WithField("topic", topic).Info("backend/gateway: publishing tx packet")

	if token := b.conn.Publish(topic, 0, false, bytes); token.Wait() && token.Error() != nil {
		return fmt.Errorf("backend/gateway: publish tx packet failed: %s", token.Error())
	}
	return nil
}

func (b *Backend) rxPacketHandler(c mqtt.Client, msg mqtt.Message) {
	b.wg.Add(1)
	defer b.wg.Done()

	log.Info("backend/gateway: rx packet received")

	var phy lorawan.PHYPayload
	var rxPacketBytes gw.RXPacketBytes
	if err := json.Unmarshal(msg.Payload(), &rxPacketBytes); err != nil {
		log.WithFields(log.Fields{
			"data_base64": base64.StdEncoding.EncodeToString(msg.Payload()),
		}).Errorf("backend/gateway: unmarshal rx packet error: %s", err)
		return
	}

	if err := phy.UnmarshalBinary(rxPacketBytes.PHYPayload); err != nil {
		log.WithFields(log.Fields{
			"data_base64": base64.StdEncoding.EncodeToString(msg.Payload()),
		}).Errorf("backend/gateway: unmarshal phypayload error: %s", err)
	}

	// Since with MQTT all subscribers will receive the uplink messages sent
	// by all the gatewyas, the first instance receiving the message must lock it,
	// so that other instances can ignore the same message (from the same gw).
	// As an unique id, the gw mac + base64 encoded payload is used. This is because
	// we can't trust any of the data, as the MIC hasn't been validated yet.
	strB, err := phy.MarshalText()
	if err != nil {
		log.Errorf("backend/gateway: marshal text error: %s", err)
	}
	key := fmt.Sprintf("lora:ns:uplink:lock:%s:%s", rxPacketBytes.RXInfo.MAC, string(strB))
	redisConn := common.RedisPool.Get()
	defer redisConn.Close()

	_, err = redis.String(redisConn.Do("SET", key, "lock", "PX", int64(uplinkLockTTL/time.Millisecond), "NX"))
	if err != nil {
		if err == redis.ErrNil {
			// the payload is already being processed by an other instance
			return
		}
		log.Errorf("backend/gateway: acquire uplink payload lock error: %s", err)
		return
	}

	b.rxPacketChan <- gw.RXPacket{
		RXInfo:     rxPacketBytes.RXInfo,
		PHYPayload: phy,
	}
}

func (b *Backend) statsPacketHandler(c mqtt.Client, msg mqtt.Message) {
	b.wg.Add(1)
	defer b.wg.Done()

	var statsPacket gw.GatewayStatsPacket
	if err := json.Unmarshal(msg.Payload(), &statsPacket); err != nil {
		log.WithFields(log.Fields{
			"data_base64": base64.StdEncoding.EncodeToString(msg.Payload()),
		}).Errorf("backend/gateway: unmarshal stats packet error: %s", err)
		return
	}

	// Since with MQTT all subscribers will receive the uplink messages sent
	// by all the gatewyas, the first instance receiving the message must lock it,
	// so that other instances can ignore the same message (from the same gw).
	// As an unique id, the gw mac + base64 encoded payload is used. This is because
	// we can't trust any of the data, as the MIC hasn't been validated yet.
	key := fmt.Sprintf("lora:ns:stats:lock:%s", statsPacket.MAC)
	redisConn := common.RedisPool.Get()
	defer redisConn.Close()

	_, err := redis.String(redisConn.Do("SET", key, "lock", "PX", int64(statsLockTTL/time.Millisecond), "NX"))
	if err != nil {
		if err == redis.ErrNil {
			// the payload is already being processed by an other instance
			return
		}
		log.Errorf("backend/gateway: acquire stats lock error: %s", err)
		return
	}

	log.WithField("mac", statsPacket.MAC).Info("backend/gateway: gateway stats packet received")
	b.statsPacketChan <- statsPacket
}

func (b *Backend) onConnected(c mqtt.Client) {
	log.Info("backend/gateway: connected to mqtt server")
	for {
		log.WithField("topic", rxTopic).Info("backend/gateway: subscribing to rx topic")
		if token := b.conn.Subscribe(rxTopic, 2, b.rxPacketHandler); token.Wait() && token.Error() != nil {
			log.WithField("topic", rxTopic).Errorf("backend/gateway: subscribe error: %s", token.Error())
			time.Sleep(time.Second)
			continue
		}
		break
	}

	for {
		log.WithField("topic", statsTopic).Info("backend/gateway: subscribing to stats topic")
		if token := b.conn.Subscribe(statsTopic, 2, b.statsPacketHandler); token.Wait() && token.Error() != nil {
			log.WithField("topic", statsTopic).Errorf("backend/gateway: subscribe error: %s", token.Error())
			time.Sleep(time.Second)
			continue
		}
		break
	}
}

func (b *Backend) onConnectionLost(c mqtt.Client, reason error) {
	log.Errorf("backend/gateway: mqtt connection error: %s", reason)
}
<|endoftext|>


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

package gcsx

import (
	"errors"
	"io/ioutil"
	"strings"
	"testing"
	"testing/iotest"

	"github.com/jacobsa/gcloud/gcs"
	"github.com/jacobsa/gcloud/gcs/mock_gcs"
	. "github.com/jacobsa/oglematchers"
	. "github.com/jacobsa/oglemock"
	. "github.com/jacobsa/ogletest"
	"golang.org/x/net/context"
)

func TestRandomReader(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Invariant-checking random reader
////////////////////////////////////////////////////////////////////////

type checkingRandomReader struct {
	ctx     context.Context
	wrapped *randomReader
}

func (rr *checkingRandomReader) ReadAt(p []byte, offset int64) (int, error) {
	rr.wrapped.CheckInvariants()
	defer rr.wrapped.CheckInvariants()
	return rr.wrapped.ReadAt(rr.ctx, p, offset)
}

func (rr *checkingRandomReader) Destroy() {
	rr.wrapped.CheckInvariants()
	rr.wrapped.Destroy()
}

////////////////////////////////////////////////////////////////////////
// Boilerplate
////////////////////////////////////////////////////////////////////////

type RandomReaderTest struct {
	object *gcs.Object
	bucket mock_gcs.MockBucket
	rr     checkingRandomReader
}

func init() { RegisterTestSuite(&RandomReaderTest{}) }

var _ SetUpInterface = &RandomReaderTest{}
var _ TearDownInterface = &RandomReaderTest{}

func (t *RandomReaderTest) SetUp(ti *TestInfo) {
	// Manufacture an object record.
	t.object = &gcs.Object{Name: "foo", Generation: 17}

	// Create the bucket.
	t.bucket = mock_gcs.NewMockBucket(ti.MockController, "bucket")

	// Set up the reader.
	rr, err := NewRandomReader(t.object, t.bucket)
	AssertEq(nil, err)
	t.rr.wrapped = rr.(*randomReader)
}

func (t *RandomReaderTest) TearDown() {
	t.rr.Destroy()
}

////////////////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////////////////

func (t *RandomReaderTest) EmptyRead() {
	// Nothing should happen.
	buf := make([]byte, 0)

	n, err := t.rr.ReadAt(buf, 0)
	ExpectEq(0, n)
	ExpectEq(nil, err)
}

func (t *RandomReaderTest) NoExistingReader() {
	// The bucket should be called to set up a new reader.
	ExpectCall(t.bucket, "NewReader")(Any(), Any()).
		WillOnce(Return(nil, errors.New("")))

	buf := make([]byte, 1)
	t.rr.ReadAt(buf, 0)
}

func (t *RandomReaderTest) ExistingReader_WrongOffset() {
	// Simulate an existing reader.
	t.rr.wrapped.reader = ioutil.NopCloser(strings.NewReader("xxx"))
	t.rr.wrapped.cancel = func() {}
	t.rr.wrapped.start = 2
	t.rr.wrapped.limit = 5

	// The bucket should be called to set up a new reader.
	ExpectCall(t.bucket, "NewReader")(Any(), Any()).
		WillOnce(Return(nil, errors.New("")))

	buf := make([]byte, 1)
	t.rr.ReadAt(buf, 0)
}

func (t *RandomReaderTest) NewReaderReturnsError() {
	ExpectCall(t.bucket, "NewReader")(Any(), Any()).
		WillOnce(Return(nil, errors.New("taco")))

	buf := make([]byte, 1)
	_, err := t.rr.ReadAt(buf, 0)

	ExpectThat(err, Error(HasSubstr("NewReader")))
	ExpectThat(err, Error(HasSubstr("taco")))
}

func (t *RandomReaderTest) ReaderFails() {
	// Bucket
	r := iotest.OneByteReader(iotest.TimeoutReader(strings.NewReader("xxx")))
	rc := ioutil.NopCloser(r)

	ExpectCall(t.bucket, "NewReader")(Any(), Any()).
		WillOnce(Return(rc, nil))

	// Call
	buf := make([]byte, 3)
	_, err := t.rr.ReadAt(buf, 0)

	ExpectThat(err, Error(HasSubstr("ReadFull")))
	ExpectThat(err, Error(HasSubstr(iotest.ErrTimeout.Error())))
}

func (t *RandomReaderTest) ReaderOvershootsRange() {
	AssertTrue(false, "TODO")
}

func (t *RandomReaderTest) ReaderExhausted_ReadFinished() {
	AssertTrue(false, "TODO")
}

func (t *RandomReaderTest) ReaderExhausted_ReadNotFinished() {
	AssertTrue(false, "TODO")
}

func (t *RandomReaderTest) PropagatesCancellation() {
	AssertTrue(false, "TODO")
}

func (t *RandomReaderTest) DoesntPropagateCancellationAfterReturning() {
	AssertTrue(false, "TODO")
}

func (t *RandomReaderTest) UpgradesReadsToMinimumSize() {
	AssertTrue(false, "TODO")
}

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

package gcsx

import (
	"errors"
	"io/ioutil"
	"strings"
	"testing"
	"testing/iotest"

	"github.com/jacobsa/gcloud/gcs"
	"github.com/jacobsa/gcloud/gcs/mock_gcs"
	. "github.com/jacobsa/oglematchers"
	. "github.com/jacobsa/oglemock"
	. "github.com/jacobsa/ogletest"
	"golang.org/x/net/context"
)

func TestRandomReader(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Invariant-checking random reader
////////////////////////////////////////////////////////////////////////

type checkingRandomReader struct {
	ctx     context.Context
	wrapped *randomReader
}

func (rr *checkingRandomReader) ReadAt(p []byte, offset int64) (int, error) {
	rr.wrapped.CheckInvariants()
	defer rr.wrapped.CheckInvariants()
	return rr.wrapped.ReadAt(rr.ctx, p, offset)
}

func (rr *checkingRandomReader) Destroy() {
	rr.wrapped.CheckInvariants()
	rr.wrapped.Destroy()
}

////////////////////////////////////////////////////////////////////////
// Boilerplate
////////////////////////////////////////////////////////////////////////

type RandomReaderTest struct {
	object *gcs.Object
	bucket mock_gcs.MockBucket
	rr     checkingRandomReader
}

func init() { RegisterTestSuite(&RandomReaderTest{}) }

var _ SetUpInterface = &RandomReaderTest{}
var _ TearDownInterface = &RandomReaderTest{}

func (t *RandomReaderTest) SetUp(ti *TestInfo) {
	t.rr.ctx = ti.Ctx

	// Manufacture an object record.
	t.object = &gcs.Object{Name: "foo", Generation: 17}

	// Create the bucket.
	t.bucket = mock_gcs.NewMockBucket(ti.MockController, "bucket")

	// Set up the reader.
	rr, err := NewRandomReader(t.object, t.bucket)
	AssertEq(nil, err)
	t.rr.wrapped = rr.(*randomReader)
}

func (t *RandomReaderTest) TearDown() {
	t.rr.Destroy()
}

////////////////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////////////////

func (t *RandomReaderTest) EmptyRead() {
	// Nothing should happen.
	buf := make([]byte, 0)

	n, err := t.rr.ReadAt(buf, 0)
	ExpectEq(0, n)
	ExpectEq(nil, err)
}

func (t *RandomReaderTest) NoExistingReader() {
	// The bucket should be called to set up a new reader.
	ExpectCall(t.bucket, "NewReader")(Any(), Any()).
		WillOnce(Return(nil, errors.New("")))

	buf := make([]byte, 1)
	t.rr.ReadAt(buf, 0)
}

func (t *RandomReaderTest) ExistingReader_WrongOffset() {
	// Simulate an existing reader.
	t.rr.wrapped.reader = ioutil.NopCloser(strings.NewReader("xxx"))
	t.rr.wrapped.cancel = func() {}
	t.rr.wrapped.start = 2
	t.rr.wrapped.limit = 5

	// The bucket should be called to set up a new reader.
	ExpectCall(t.bucket, "NewReader")(Any(), Any()).
		WillOnce(Return(nil, errors.New("")))

	buf := make([]byte, 1)
	t.rr.ReadAt(buf, 0)
}

func (t *RandomReaderTest) NewReaderReturnsError() {
	ExpectCall(t.bucket, "NewReader")(Any(), Any()).
		WillOnce(Return(nil, errors.New("taco")))

	buf := make([]byte, 1)
	_, err := t.rr.ReadAt(buf, 0)

	ExpectThat(err, Error(HasSubstr("NewReader")))
	ExpectThat(err, Error(HasSubstr("taco")))
}

func (t *RandomReaderTest) ReaderFails() {
	// Bucket
	r := iotest.OneByteReader(iotest.TimeoutReader(strings.NewReader("xxx")))
	rc := ioutil.NopCloser(r)

	ExpectCall(t.bucket, "NewReader")(Any(), Any()).
		WillOnce(Return(rc, nil))

	// Call
	buf := make([]byte, 3)
	_, err := t.rr.ReadAt(buf, 0)

	ExpectThat(err, Error(HasSubstr("ReadFull")))
	ExpectThat(err, Error(HasSubstr(iotest.ErrTimeout.Error())))
}

func (t *RandomReaderTest) ReaderOvershootsRange() {
	AssertTrue(false, "TODO")
}

func (t *RandomReaderTest) ReaderExhausted_ReadFinished() {
	AssertTrue(false, "TODO")
}

func (t *RandomReaderTest) ReaderExhausted_ReadNotFinished() {
	AssertTrue(false, "TODO")
}

func (t *RandomReaderTest) PropagatesCancellation() {
	AssertTrue(false, "TODO")
}

func (t *RandomReaderTest) DoesntPropagateCancellationAfterReturning() {
	AssertTrue(false, "TODO")
}

func (t *RandomReaderTest) UpgradesReadsToMinimumSize() {
	AssertTrue(false, "TODO")
}

func (t *RandomReaderTest) UpgradesSequentialReads() {
	AssertTrue(false, "TODO")
}
<|endoftext|>


<commit_before>package handlers

import (
	"context"
	"errors"
	"github.com/yuin/gopher-lua"
)

const luaSecurityTypeName = "security"

func luaContextGetSecurities(L *lua.LState) (map[int64]*Security, error) {
	var security_map map[int64]*Security

	ctx := L.Context()

	tx, ok := ctx.Value(dbContextKey).(*Tx)
	if !ok {
		return nil, errors.New("Couldn't find tx in lua's Context")
	}

	security_map, ok = ctx.Value(securitiesContextKey).(map[int64]*Security)
	if !ok {
		user, ok := ctx.Value(userContextKey).(*User)
		if !ok {
			return nil, errors.New("Couldn't find User in lua's Context")
		}

		securities, err := GetSecurities(tx, user.UserId)
		if err != nil {
			return nil, err
		}

		security_map = make(map[int64]*Security)
		for i := range *securities {
			security_map[(*securities)[i].SecurityId] = (*securities)[i]
		}

		ctx = context.WithValue(ctx, securitiesContextKey, security_map)
		L.SetContext(ctx)
	}

	return security_map, nil
}

func luaContextGetDefaultCurrency(L *lua.LState) (*Security, error) {
	security_map, err := luaContextGetSecurities(L)
	if err != nil {
		return nil, err
	}

	ctx := L.Context()

	user, ok := ctx.Value(userContextKey).(*User)
	if !ok {
		return nil, errors.New("Couldn't find User in lua's Context")
	}

	if security, ok := security_map[user.DefaultCurrency]; ok {
		return security, nil
	} else {
		return nil, errors.New("DefaultCurrency not in lua security_map")
	}
}

func luaGetDefaultCurrency(L *lua.LState) int {
	defcurrency, err := luaContextGetDefaultCurrency(L)
	if err != nil {
		panic("luaGetDefaultCurrency couldn't fetch default currency")
	}

	L.Push(SecurityToLua(L, defcurrency))
	return 1
}

func luaGetSecurities(L *lua.LState) int {
	security_map, err := luaContextGetSecurities(L)
	if err != nil {
		panic("luaGetSecurities couldn't fetch securities")
	}

	table := L.NewTable()

	for securityid := range security_map {
		table.RawSetInt(int(securityid), SecurityToLua(L, security_map[securityid]))
	}

	L.Push(table)
	return 1
}

func luaRegisterSecurities(L *lua.LState) {
	mt := L.NewTypeMetatable(luaSecurityTypeName)
	L.SetGlobal("security", mt)
	L.SetField(mt, "__index", L.NewFunction(luaSecurity__index))
	L.SetField(mt, "__tostring", L.NewFunction(luaSecurity__tostring))
	L.SetField(mt, "__eq", L.NewFunction(luaSecurity__eq))
	L.SetField(mt, "__metatable", lua.LString("protected"))
	getSecuritiesFn := L.NewFunction(luaGetSecurities)
	L.SetField(mt, "get_all", getSecuritiesFn)
	getDefaultCurrencyFn := L.NewFunction(luaGetDefaultCurrency)
	L.SetField(mt, "get_default", getDefaultCurrencyFn)

	// also register the get_securities and get_default functions as globals in
	// their own right
	L.SetGlobal("get_securities", getSecuritiesFn)
	L.SetGlobal("get_default_currency", getDefaultCurrencyFn)
}

func SecurityToLua(L *lua.LState, security *Security) *lua.LUserData {
	ud := L.NewUserData()
	ud.Value = security
	L.SetMetatable(ud, L.GetTypeMetatable(luaSecurityTypeName))
	return ud
}

// Checks whether the first lua argument is a *LUserData with *Security and returns this *Security.
func luaCheckSecurity(L *lua.LState, n int) *Security {
	ud := L.CheckUserData(n)
	if security, ok := ud.Value.(*Security); ok {
		return security
	}
	L.ArgError(n, "security expected")
	return nil
}

func luaSecurity__index(L *lua.LState) int {
	a := luaCheckSecurity(L, 1)
	field := L.CheckString(2)

	switch field {
	case "SecurityId", "securityid":
		L.Push(lua.LNumber(float64(a.SecurityId)))
	case "Name", "name":
		L.Push(lua.LString(a.Name))
	case "Description", "description":
		L.Push(lua.LString(a.Description))
	case "Symbol", "symbol":
		L.Push(lua.LString(a.Symbol))
	case "Precision", "precision":
		L.Push(lua.LNumber(float64(a.Precision)))
	case "Type", "type":
		L.Push(lua.LNumber(float64(a.Type)))
	case "ClosestPrice", "closestprice":
		L.Push(L.NewFunction(luaClosestPrice))
	default:
		L.ArgError(2, "unexpected security attribute: "+field)
	}

	return 1
}

func luaClosestPrice(L *lua.LState) int {
	s := luaCheckSecurity(L, 1)
	c := luaCheckSecurity(L, 2)
	date := luaCheckTime(L, 3)

	ctx := L.Context()
	tx, ok := ctx.Value(dbContextKey).(*Tx)
	if !ok {
		panic("Couldn't find tx in lua's Context")
	}

	p, err := GetClosestPrice(tx, s, c, date)
	if err != nil {
		L.Push(lua.LNil)
	} else {
		L.Push(PriceToLua(L, p))
	}

	return 1
}

func luaSecurity__tostring(L *lua.LState) int {
	s := luaCheckSecurity(L, 1)

	L.Push(lua.LString(s.Name + " - " + s.Description + " (" + s.Symbol + ")"))

	return 1
}

func luaSecurity__eq(L *lua.LState) int {
	a := luaCheckSecurity(L, 1)
	b := luaCheckSecurity(L, 2)

	L.Push(lua.LBool(a.SecurityId == b.SecurityId))

	return 1
}
<commit_msg>Lua: Add Security.AlternateId getter<commit_after>package handlers

import (
	"context"
	"errors"
	"github.com/yuin/gopher-lua"
)

const luaSecurityTypeName = "security"

func luaContextGetSecurities(L *lua.LState) (map[int64]*Security, error) {
	var security_map map[int64]*Security

	ctx := L.Context()

	tx, ok := ctx.Value(dbContextKey).(*Tx)
	if !ok {
		return nil, errors.New("Couldn't find tx in lua's Context")
	}

	security_map, ok = ctx.Value(securitiesContextKey).(map[int64]*Security)
	if !ok {
		user, ok := ctx.Value(userContextKey).(*User)
		if !ok {
			return nil, errors.New("Couldn't find User in lua's Context")
		}

		securities, err := GetSecurities(tx, user.UserId)
		if err != nil {
			return nil, err
		}

		security_map = make(map[int64]*Security)
		for i := range *securities {
			security_map[(*securities)[i].SecurityId] = (*securities)[i]
		}

		ctx = context.WithValue(ctx, securitiesContextKey, security_map)
		L.SetContext(ctx)
	}

	return security_map, nil
}

func luaContextGetDefaultCurrency(L *lua.LState) (*Security, error) {
	security_map, err := luaContextGetSecurities(L)
	if err != nil {
		return nil, err
	}

	ctx := L.Context()

	user, ok := ctx.Value(userContextKey).(*User)
	if !ok {
		return nil, errors.New("Couldn't find User in lua's Context")
	}

	if security, ok := security_map[user.DefaultCurrency]; ok {
		return security, nil
	} else {
		return nil, errors.New("DefaultCurrency not in lua security_map")
	}
}

func luaGetDefaultCurrency(L *lua.LState) int {
	defcurrency, err := luaContextGetDefaultCurrency(L)
	if err != nil {
		panic("luaGetDefaultCurrency couldn't fetch default currency")
	}

	L.Push(SecurityToLua(L, defcurrency))
	return 1
}

func luaGetSecurities(L *lua.LState) int {
	security_map, err := luaContextGetSecurities(L)
	if err != nil {
		panic("luaGetSecurities couldn't fetch securities")
	}

	table := L.NewTable()

	for securityid := range security_map {
		table.RawSetInt(int(securityid), SecurityToLua(L, security_map[securityid]))
	}

	L.Push(table)
	return 1
}

func luaRegisterSecurities(L *lua.LState) {
	mt := L.NewTypeMetatable(luaSecurityTypeName)
	L.SetGlobal("security", mt)
	L.SetField(mt, "__index", L.NewFunction(luaSecurity__index))
	L.SetField(mt, "__tostring", L.NewFunction(luaSecurity__tostring))
	L.SetField(mt, "__eq", L.NewFunction(luaSecurity__eq))
	L.SetField(mt, "__metatable", lua.LString("protected"))
	getSecuritiesFn := L.NewFunction(luaGetSecurities)
	L.SetField(mt, "get_all", getSecuritiesFn)
	getDefaultCurrencyFn := L.NewFunction(luaGetDefaultCurrency)
	L.SetField(mt, "get_default", getDefaultCurrencyFn)

	// also register the get_securities and get_default functions as globals in
	// their own right
	L.SetGlobal("get_securities", getSecuritiesFn)
	L.SetGlobal("get_default_currency", getDefaultCurrencyFn)
}

func SecurityToLua(L *lua.LState, security *Security) *lua.LUserData {
	ud := L.NewUserData()
	ud.Value = security
	L.SetMetatable(ud, L.GetTypeMetatable(luaSecurityTypeName))
	return ud
}

// Checks whether the first lua argument is a *LUserData with *Security and returns this *Security.
func luaCheckSecurity(L *lua.LState, n int) *Security {
	ud := L.CheckUserData(n)
	if security, ok := ud.Value.(*Security); ok {
		return security
	}
	L.ArgError(n, "security expected")
	return nil
}

func luaSecurity__index(L *lua.LState) int {
	a := luaCheckSecurity(L, 1)
	field := L.CheckString(2)

	switch field {
	case "SecurityId", "securityid":
		L.Push(lua.LNumber(float64(a.SecurityId)))
	case "Name", "name":
		L.Push(lua.LString(a.Name))
	case "Description", "description":
		L.Push(lua.LString(a.Description))
	case "Symbol", "symbol":
		L.Push(lua.LString(a.Symbol))
	case "Precision", "precision":
		L.Push(lua.LNumber(float64(a.Precision)))
	case "Type", "type":
		L.Push(lua.LNumber(float64(a.Type)))
	case "ClosestPrice", "closestprice":
		L.Push(L.NewFunction(luaClosestPrice))
	case "AlternateId", "alternateid":
		L.Push(lua.LString(a.AlternateId))
	default:
		L.ArgError(2, "unexpected security attribute: "+field)
	}

	return 1
}

func luaClosestPrice(L *lua.LState) int {
	s := luaCheckSecurity(L, 1)
	c := luaCheckSecurity(L, 2)
	date := luaCheckTime(L, 3)

	ctx := L.Context()
	tx, ok := ctx.Value(dbContextKey).(*Tx)
	if !ok {
		panic("Couldn't find tx in lua's Context")
	}

	p, err := GetClosestPrice(tx, s, c, date)
	if err != nil {
		L.Push(lua.LNil)
	} else {
		L.Push(PriceToLua(L, p))
	}

	return 1
}

func luaSecurity__tostring(L *lua.LState) int {
	s := luaCheckSecurity(L, 1)

	L.Push(lua.LString(s.Name + " - " + s.Description + " (" + s.Symbol + ")"))

	return 1
}

func luaSecurity__eq(L *lua.LState) int {
	a := luaCheckSecurity(L, 1)
	b := luaCheckSecurity(L, 2)

	L.Push(lua.LBool(a.SecurityId == b.SecurityId))

	return 1
}
<|endoftext|>


<commit_before>package builders

import (
	"time"

	"github.com/docker/docker/api/types"
)

// Container creates a container with default values.
// Any number of container function builder can be passed to augment it.
func Container(name string, builders ...func(container *types.Container)) *types.Container {
	// now := time.Now()
	// onehourago := now.Add(-120 * time.Minute)
	container := &types.Container{
		ID:      "container_id",
		Names:   []string{"/" + name},
		Command: "top",
		Image:   "busybox:latest",
		Status:  "Up 1 second",
		Created: time.Now().UnixNano(),
	}

	for _, builder := range builders {
		builder(container)
	}

	return container
}

// WithLabel adds a label to the container
func WithLabel(key, value string) func(*types.Container) {
	return func(c *types.Container) {
		if c.Labels == nil {
			c.Labels = map[string]string{}
		}
		c.Labels[key] = value
	}
}

// WithName adds a name to the container
func WithName(name string) func(*types.Container) {
	return func(c *types.Container) {
		c.Names = append(c.Names, "/"+name)
	}
}

// WithPort adds a port mapping to the container
func WithPort(privateport, publicport uint16, builders ...func(*types.Port)) func(*types.Container) {
	return func(c *types.Container) {
		if c.Ports == nil {
			c.Ports = []types.Port{}
		}
		port := &types.Port{
			PrivatePort: privateport,
			PublicPort:  publicport,
		}
		for _, builder := range builders {
			builder(port)
		}
		c.Ports = append(c.Ports, *port)
	}
}

// IP sets the ip of the port
func IP(ip string) func(*types.Port) {
	return func(p *types.Port) {
		p.IP = ip
	}
}

// TCP sets the port to tcp
func TCP(p *types.Port) {
	p.Type = "tcp"
}

// UDP sets the port to udp
func UDP(p *types.Port) {
	p.Type = "udp"
}
<commit_msg>Fix container creation time in test/builders<commit_after>package builders

import (
	"time"

	"github.com/docker/docker/api/types"
)

// Container creates a container with default values.
// Any number of container function builder can be passed to augment it.
func Container(name string, builders ...func(container *types.Container)) *types.Container {
	// now := time.Now()
	// onehourago := now.Add(-120 * time.Minute)
	container := &types.Container{
		ID:      "container_id",
		Names:   []string{"/" + name},
		Command: "top",
		Image:   "busybox:latest",
		Status:  "Up 1 second",
		Created: time.Now().Unix(),
	}

	for _, builder := range builders {
		builder(container)
	}

	return container
}

// WithLabel adds a label to the container
func WithLabel(key, value string) func(*types.Container) {
	return func(c *types.Container) {
		if c.Labels == nil {
			c.Labels = map[string]string{}
		}
		c.Labels[key] = value
	}
}

// WithName adds a name to the container
func WithName(name string) func(*types.Container) {
	return func(c *types.Container) {
		c.Names = append(c.Names, "/"+name)
	}
}

// WithPort adds a port mapping to the container
func WithPort(privateport, publicport uint16, builders ...func(*types.Port)) func(*types.Container) {
	return func(c *types.Container) {
		if c.Ports == nil {
			c.Ports = []types.Port{}
		}
		port := &types.Port{
			PrivatePort: privateport,
			PublicPort:  publicport,
		}
		for _, builder := range builders {
			builder(port)
		}
		c.Ports = append(c.Ports, *port)
	}
}

// IP sets the ip of the port
func IP(ip string) func(*types.Port) {
	return func(p *types.Port) {
		p.IP = ip
	}
}

// TCP sets the port to tcp
func TCP(p *types.Port) {
	p.Type = "tcp"
}

// UDP sets the port to udp
func UDP(p *types.Port) {
	p.Type = "udp"
}
<|endoftext|>