<commit_before>package protocol

import (
	"fmt"
	"io"
	"sync"

	context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"

	inet "github.com/jbenet/go-ipfs/p2p/net"
	eventlog "github.com/jbenet/go-ipfs/thirdparty/eventlog"
	lgbl "github.com/jbenet/go-ipfs/util/eventlog/loggables"
)

var log = eventlog.Logger("net/mux")

type streamHandlerMap map[ID]inet.StreamHandler

// Mux provides simple stream multixplexing.
// It helps you precisely when:
//  * You have many streams
//  * You have function handlers
//
// It contains the handlers for each protocol accepted.
// It dispatches handlers for streams opened by remote peers.
type Mux struct {
	// defaultHandler handles unknown protocols. Callers modify at your own risk.
	defaultHandler inet.StreamHandler

	lock     sync.RWMutex
	handlers streamHandlerMap
}

func NewMux() *Mux {
	return &Mux{
		handlers: streamHandlerMap{},
	}
}

// Protocols returns the list of protocols this muxer has handlers for
func (m *Mux) Protocols() []ID {
	m.lock.RLock()
	l := make([]ID, 0, len(m.handlers))
	for p := range m.handlers {
		l = append(l, p)
	}
	m.lock.RUnlock()
	return l
}

// readHeader reads the stream and returns the next Handler function
// according to the muxer encoding.
func (m *Mux) readHeader(s io.Reader) (ID, inet.StreamHandler, error) {
	// log.Error("ReadProtocolHeader")
	p, err := ReadHeader(s)
	if err != nil {
		return "", nil, err
	}

	// log.Debug("readHeader got:", p)
	m.lock.RLock()
	h, found := m.handlers[p]
	m.lock.RUnlock()

	switch {
	case !found && m.defaultHandler != nil:
		return p, m.defaultHandler, nil
	case !found && m.defaultHandler == nil:
		return p, nil, fmt.Errorf("%s no handler with name: %s (%d)", m, p, len(p))
	default:
		return p, h, nil
	}
}

// String returns the muxer's printing representation
func (m *Mux) String() string {
	m.lock.RLock()
	defer m.lock.RUnlock()
	return fmt.Sprintf("<Muxer %p %d>", m, len(m.handlers))
}

func (m *Mux) SetDefaultHandler(h inet.StreamHandler) {
	m.lock.Lock()
	m.defaultHandler = h
	m.lock.Unlock()
}

// SetHandler sets the protocol handler on the Network's Muxer.
// This operation is threadsafe.
func (m *Mux) SetHandler(p ID, h inet.StreamHandler) {
	log.Debugf("%s setting handler for protocol: %s (%d)", m, p, len(p))
	m.lock.Lock()
	m.handlers[p] = h
	m.lock.Unlock()
}

// Handle reads the next name off the Stream, and calls a handler function
// This is done in its own goroutine, to avoid blocking the caller.
func (m *Mux) Handle(s inet.Stream) {
	go m.HandleSync(s)
}

// HandleSync reads the next name off the Stream, and calls a handler function
// This is done synchronously. The handler function will return before
// HandleSync returns.
func (m *Mux) HandleSync(s inet.Stream) {
	ctx := context.Background()

	name, handler, err := m.readHeader(s)
	if err != nil {
		err = fmt.Errorf("protocol mux error: %s", err)
		log.Error(err)
		log.Event(ctx, "muxError", lgbl.Error(err))
		s.Close()
		return
	}

	log.Infof("muxer handle protocol: %s", name)
	log.Event(ctx, "muxHandle", eventlog.Metadata{"protocol": name})
	handler(s)
}

// ReadLengthPrefix reads the name from Reader with a length-byte-prefix.
func ReadLengthPrefix(r io.Reader) (string, error) {
	// c-string identifier
	// the first byte is our length
	l := make([]byte, 1)
	if _, err := io.ReadFull(r, l); err != nil {
		return "", err
	}
	length := int(l[0])

	// the next are our identifier
	name := make([]byte, length)
	if _, err := io.ReadFull(r, name); err != nil {
		return "", err
	}

	return string(name), nil
}
<commit_msg>eventlog: rm noisy low-signal statement<commit_after>package protocol

import (
	"fmt"
	"io"
	"sync"

	context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"

	inet "github.com/jbenet/go-ipfs/p2p/net"
	eventlog "github.com/jbenet/go-ipfs/thirdparty/eventlog"
	lgbl "github.com/jbenet/go-ipfs/util/eventlog/loggables"
)

var log = eventlog.Logger("net/mux")

type streamHandlerMap map[ID]inet.StreamHandler

// Mux provides simple stream multixplexing.
// It helps you precisely when:
//  * You have many streams
//  * You have function handlers
//
// It contains the handlers for each protocol accepted.
// It dispatches handlers for streams opened by remote peers.
type Mux struct {
	// defaultHandler handles unknown protocols. Callers modify at your own risk.
	defaultHandler inet.StreamHandler

	lock     sync.RWMutex
	handlers streamHandlerMap
}

func NewMux() *Mux {
	return &Mux{
		handlers: streamHandlerMap{},
	}
}

// Protocols returns the list of protocols this muxer has handlers for
func (m *Mux) Protocols() []ID {
	m.lock.RLock()
	l := make([]ID, 0, len(m.handlers))
	for p := range m.handlers {
		l = append(l, p)
	}
	m.lock.RUnlock()
	return l
}

// readHeader reads the stream and returns the next Handler function
// according to the muxer encoding.
func (m *Mux) readHeader(s io.Reader) (ID, inet.StreamHandler, error) {
	// log.Error("ReadProtocolHeader")
	p, err := ReadHeader(s)
	if err != nil {
		return "", nil, err
	}

	// log.Debug("readHeader got:", p)
	m.lock.RLock()
	h, found := m.handlers[p]
	m.lock.RUnlock()

	switch {
	case !found && m.defaultHandler != nil:
		return p, m.defaultHandler, nil
	case !found && m.defaultHandler == nil:
		return p, nil, fmt.Errorf("%s no handler with name: %s (%d)", m, p, len(p))
	default:
		return p, h, nil
	}
}

// String returns the muxer's printing representation
func (m *Mux) String() string {
	m.lock.RLock()
	defer m.lock.RUnlock()
	return fmt.Sprintf("<Muxer %p %d>", m, len(m.handlers))
}

func (m *Mux) SetDefaultHandler(h inet.StreamHandler) {
	m.lock.Lock()
	m.defaultHandler = h
	m.lock.Unlock()
}

// SetHandler sets the protocol handler on the Network's Muxer.
// This operation is threadsafe.
func (m *Mux) SetHandler(p ID, h inet.StreamHandler) {
	log.Debugf("%s setting handler for protocol: %s (%d)", m, p, len(p))
	m.lock.Lock()
	m.handlers[p] = h
	m.lock.Unlock()
}

// Handle reads the next name off the Stream, and calls a handler function
// This is done in its own goroutine, to avoid blocking the caller.
func (m *Mux) Handle(s inet.Stream) {
	go m.HandleSync(s)
}

// HandleSync reads the next name off the Stream, and calls a handler function
// This is done synchronously. The handler function will return before
// HandleSync returns.
func (m *Mux) HandleSync(s inet.Stream) {
	ctx := context.Background()

	name, handler, err := m.readHeader(s)
	if err != nil {
		err = fmt.Errorf("protocol mux error: %s", err)
		log.Error(err)
		log.Event(ctx, "muxError", lgbl.Error(err))
		s.Close()
		return
	}

	log.Infof("muxer handle protocol: %s", name)
	handler(s)
}

// ReadLengthPrefix reads the name from Reader with a length-byte-prefix.
func ReadLengthPrefix(r io.Reader) (string, error) {
	// c-string identifier
	// the first byte is our length
	l := make([]byte, 1)
	if _, err := io.ReadFull(r, l); err != nil {
		return "", err
	}
	length := int(l[0])

	// the next are our identifier
	name := make([]byte, length)
	if _, err := io.ReadFull(r, name); err != nil {
		return "", err
	}

	return string(name), nil
}
<|endoftext|>


<commit_before>package meta

import (
	"bytes"
	"encoding/binary"
	"fmt"

	log "github.com/inconshreveable/log15"
	"golang.org/x/net/context"

	"github.com/tsileo/blobstash/pkg/blob"
	"github.com/tsileo/blobstash/pkg/hub"
)

var (
	MetaBlobHeader   = "#blobstash/meta\n"
	MetaBlobVersion  = 1
	MetaBlobOverhead = len(MetaBlobHeader)
)

type MetaData interface {
	Type() string
	Dump() ([]byte, error)
	// Load([]byte)
}

type Meta struct {
	log        log.Logger
	applyFuncs map[string]func(string, []byte) error // map[<metadata type>]<load func>
	hub        *hub.Hub
}

func New(logger log.Logger, chub *hub.Hub) (*Meta, error) {
	meta := &Meta{
		log:        logger,
		hub:        chub,
		applyFuncs: map[string]func(string, []byte) error{},
	}
	// Subscribe to "new blob" notification
	meta.hub.Subscribe(hub.NewBlob, "meta", meta.newBlobCallback)
	meta.hub.Subscribe(hub.ScanBlob, "meta", meta.newBlobCallback)
	// XXX(tsileo): register to ScanBlob event too?
	return meta, nil
}

func (m *Meta) newBlobCallback(ctx context.Context, blob *blob.Blob) error {
	metaType, metaData, isMeta := IsMetaBlob(blob.Data)
	m.log.Debug("newBlobCallback", "is_meta", isMeta, "meta_type", metaType, "blob", string(blob.Data))
	if isMeta {
		// TODO(tsileo): should we check for already applied blobs and use the same callback for both scan and new blob?
		if _, ok := m.applyFuncs[metaType]; !ok {
			return fmt.Errorf("Unknown meta type \"%s\"", metaType)
		}
		return m.applyFuncs[metaType](blob.Hash, metaData)
	}
	return nil
}

// RegisterApplyFunc registers a callback func for the given meta type
func (m *Meta) RegisterApplyFunc(t string, f func(string, []byte) error) {
	m.applyFuncs[t] = f
}

// Build convert the MetaData into a blo
func (m *Meta) Build(data MetaData) (*blob.Blob, error) {
	var buf bytes.Buffer
	// <meta blob header> + <meta blob version> + <type size> + <type bytes> + <data size> + <data>
	buf.Write([]byte(MetaBlobHeader))
	tmp := make([]byte, 4)
	binary.BigEndian.PutUint32(tmp[:], uint32(MetaBlobVersion))
	buf.Write(tmp)
	binary.BigEndian.PutUint32(tmp[:], uint32(len(data.Type())))
	buf.Write(tmp)
	buf.WriteString(data.Type())
	serialized, err := data.Dump()
	if err != nil {
		return nil, fmt.Errorf("failed to dump MetaData: %v", err)
	}
	binary.BigEndian.PutUint32(tmp[:], uint32(len(serialized)))
	buf.Write(tmp)
	buf.Write(serialized)
	m.log.Debug("meta blob", "data", buf.String())
	metaBlob := blob.New(buf.Bytes())
	return metaBlob, nil
}

func (m *Meta) Scan() error {
	// FIXME(ts): Scan
	return nil
}

func IsMetaBlob(blob []byte) (string, []byte, bool) { // returns (string, bool) string => meta type
	// TODO add a test with a tiny blob
	if len(blob) < MetaBlobOverhead {
		return "", nil, false
	}
	if bytes.Equal(blob[0:MetaBlobOverhead], []byte(MetaBlobHeader)) {
		typeLen := int(binary.BigEndian.Uint32(blob[MetaBlobOverhead+4 : MetaBlobOverhead+8]))
		return string(blob[MetaBlobOverhead+8 : MetaBlobOverhead+8+typeLen]), blob[MetaBlobOverhead+12+typeLen : len(blob)], true
	}
	return "", nil, false
}
<commit_msg>meta: only log meta blobs<commit_after>package meta

import (
	"bytes"
	"encoding/binary"
	"fmt"

	log "github.com/inconshreveable/log15"
	"golang.org/x/net/context"

	"github.com/tsileo/blobstash/pkg/blob"
	"github.com/tsileo/blobstash/pkg/hub"
)

var (
	MetaBlobHeader   = "#blobstash/meta\n"
	MetaBlobVersion  = 1
	MetaBlobOverhead = len(MetaBlobHeader)
)

type MetaData interface {
	Type() string
	Dump() ([]byte, error)
	// Load([]byte)
}

type Meta struct {
	log        log.Logger
	applyFuncs map[string]func(string, []byte) error // map[<metadata type>]<load func>
	hub        *hub.Hub
}

func New(logger log.Logger, chub *hub.Hub) (*Meta, error) {
	meta := &Meta{
		log:        logger,
		hub:        chub,
		applyFuncs: map[string]func(string, []byte) error{},
	}
	// Subscribe to "new blob" notification
	meta.hub.Subscribe(hub.NewBlob, "meta", meta.newBlobCallback)
	meta.hub.Subscribe(hub.ScanBlob, "meta", meta.newBlobCallback)
	// XXX(tsileo): register to ScanBlob event too?
	return meta, nil
}

func (m *Meta) newBlobCallback(ctx context.Context, blob *blob.Blob) error {
	metaType, metaData, isMeta := IsMetaBlob(blob.Data)
	m.log.Debug("newBlobCallback", "is_meta", isMeta, "meta_type", metaType, "blob_size", len(blob.Data))
	if isMeta {
		m.log.Debug("blob callback", "blob", string(blob.Data))
		// TODO(tsileo): should we check for already applied blobs and use the same callback for both scan and new blob?
		if _, ok := m.applyFuncs[metaType]; !ok {
			return fmt.Errorf("Unknown meta type \"%s\"", metaType)
		}
		return m.applyFuncs[metaType](blob.Hash, metaData)
	}
	return nil
}

// RegisterApplyFunc registers a callback func for the given meta type
func (m *Meta) RegisterApplyFunc(t string, f func(string, []byte) error) {
	m.applyFuncs[t] = f
}

// Build convert the MetaData into a blo
func (m *Meta) Build(data MetaData) (*blob.Blob, error) {
	var buf bytes.Buffer
	// <meta blob header> + <meta blob version> + <type size> + <type bytes> + <data size> + <data>
	buf.Write([]byte(MetaBlobHeader))
	tmp := make([]byte, 4)
	binary.BigEndian.PutUint32(tmp[:], uint32(MetaBlobVersion))
	buf.Write(tmp)
	binary.BigEndian.PutUint32(tmp[:], uint32(len(data.Type())))
	buf.Write(tmp)
	buf.WriteString(data.Type())
	serialized, err := data.Dump()
	if err != nil {
		return nil, fmt.Errorf("failed to dump MetaData: %v", err)
	}
	binary.BigEndian.PutUint32(tmp[:], uint32(len(serialized)))
	buf.Write(tmp)
	buf.Write(serialized)
	m.log.Debug("meta blob", "data", buf.String())
	metaBlob := blob.New(buf.Bytes())
	return metaBlob, nil
}

func (m *Meta) Scan() error {
	// FIXME(ts): Scan
	return nil
}

func IsMetaBlob(blob []byte) (string, []byte, bool) { // returns (string, bool) string => meta type
	// TODO add a test with a tiny blob
	if len(blob) < MetaBlobOverhead {
		return "", nil, false
	}
	if bytes.Equal(blob[0:MetaBlobOverhead], []byte(MetaBlobHeader)) {
		typeLen := int(binary.BigEndian.Uint32(blob[MetaBlobOverhead+4 : MetaBlobOverhead+8]))
		return string(blob[MetaBlobOverhead+8 : MetaBlobOverhead+8+typeLen]), blob[MetaBlobOverhead+12+typeLen : len(blob)], true
	}
	return "", nil, false
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/tls"
	"crypto/x509"
	"encoding/pem"
	"fmt"
	"github.com/sorah/etcvault/engine"
	"github.com/sorah/etcvault/keys"
	"github.com/sorah/etcvault/proxy"
	"io/ioutil"
	"net"
	"net/http"
	"net/url"
	"os"
	"strings"
	"time"
)

func defaultHttpTransport() *http.Transport {
	return &http.Transport{
		// DefaultTransport
		Dial: (&net.Dialer{
			Timeout:   30 * time.Second,
			KeepAlive: 30 * time.Second,
		}).Dial,
		TLSHandshakeTimeout: 10 * time.Second,
	}
}

func caPool(caPath string) *x509.CertPool {
	pool := x509.NewCertPool()
	remainingPem, err := ioutil.ReadFile(caPath)
	if err != nil {
		fmt.Fprintf(os.Stderr, "error loading CA file %s: %s", caPath, err)
		os.Exit(1)
	}

	for { // load while file ends
		var block *pem.Block
		block, remainingPem = pem.Decode(remainingPem)
		if block == nil {
			return pool
		}
		cert, err := x509.ParseCertificate(block.Bytes)
		if err != nil {
			fmt.Fprintf(os.Stderr, "error while parsing CA PEM blocks: %s", err.Error())
			os.Exit(1)
		}
		pool.AddCert(cert)
	}
}

func parseTlsKeypair(certPath, keyPath string) *tls.Config {
	certBytes, err := ioutil.ReadFile(certPath)
	if err != nil {
		fmt.Fprintf(os.Stderr, "error loading certificate %s: %s\n", certPath, err.Error())
		os.Exit(1)
	}
	keyBytes, err := ioutil.ReadFile(keyPath)
	if err != nil {
		fmt.Fprintf(os.Stderr, "error loading certificate %s: %s\n", certPath, err.Error())
		os.Exit(1)
	}

	keypair, err := tls.X509KeyPair(certBytes, keyBytes)
	if err != nil {
		fmt.Printf("error loading keypair: %s", err.Error())
	}

	return &tls.Config{
		Certificates: []tls.Certificate{keypair},
		MinVersion:   tls.VersionTLS10,
	}
}

func tlsConfigurationForClientUse(config *tls.Config, caPath string) *tls.Config {
	if config == nil {
		config = &tls.Config{}
	}

	if caPath != "" {
		config.RootCAs = caPool(caPath)
	}

	return config
}

func tlsConfigurationForServerUse(config *tls.Config, caPath string) *tls.Config {
	if config == nil {
		config = &tls.Config{}
	}

	if caPath != "" {
		config.ClientAuth = tls.RequireAndVerifyClientCert
		config.ClientCAs = caPool(caPath)
	} else {
		config.ClientAuth = tls.NoClientCert
	}

	return config
}

type ProxyStarter struct {
	// arguments
	Listen       *url.URL
	AdvertiseUrl string

	keychainDir              string
	DiscoverySrvDomain       string
	initialBackendUrlStrings string

	clientCaFilePath   string
	clientCertFilePath string
	clientKeyFilePath  string

	peerCaFilePath   string
	peerCertFilePath string
	peerKeyFilePath  string

	listenCaFilePath   string
	listenCertFilePath string
	listenKeyFilePath  string

	readonly bool

	discoveryInterval time.Duration

	router *proxy.Router
}

func (starter *ProxyStarter) InitialBackendUrls() []*url.URL {
	urlStrings := strings.Split(starter.initialBackendUrlStrings, ",")
	urls := make([]*url.URL, len(urlStrings))

	for i, urlString := range urlStrings {
		u, err := url.Parse(urlString)
		if err != nil {
			fmt.Fprintf(os.Stderr, "failed to parse url %s: %s\n", urlString, err.Error())
			os.Exit(1)
		}
		urls[i] = u
	}

	return urls
}

func (starter *ProxyStarter) Keychain() *keys.Keychain {
	return keys.NewKeychain(starter.keychainDir)
}

func (starter *ProxyStarter) Engine() *engine.Engine {
	return engine.NewEngine(starter.Keychain())
}

func (starter *ProxyStarter) ListenTlsConfig() *tls.Config {
	if starter.listenKeyFilePath != "" && starter.listenCertFilePath != "" {
		return parseTlsKeypair(starter.listenCertFilePath, starter.listenKeyFilePath)
	} else {
		return nil
	}
}

func (starter *ProxyStarter) PeerTlsConfig() *tls.Config {
	if starter.peerKeyFilePath != "" && starter.peerCertFilePath != "" {
		return parseTlsKeypair(starter.peerCertFilePath, starter.peerKeyFilePath)
	} else {
		return nil
	}
}

func (starter *ProxyStarter) ClientTlsConfig() *tls.Config {
	if starter.clientKeyFilePath != "" && starter.clientCertFilePath != "" {
		return parseTlsKeypair(starter.clientCertFilePath, starter.clientKeyFilePath)
	} else {
		return nil
	}
}

func (starter *ProxyStarter) TlsConfigForServerUse() *tls.Config {
	if starter.listenKeyFilePath != "" && starter.listenCertFilePath != "" {
		return tlsConfigurationForServerUse(starter.ListenTlsConfig(), starter.listenCaFilePath)
	} else if starter.clientKeyFilePath != "" && starter.clientCertFilePath != "" {
		return tlsConfigurationForServerUse(starter.ClientTlsConfig(), starter.clientCaFilePath)
	} else {
		return nil
	}
}

func (starter *ProxyStarter) ClientTlsConfigForClientUse() *tls.Config {
	return tlsConfigurationForClientUse(starter.ClientTlsConfig(), starter.clientCaFilePath)
}

func (starter *ProxyStarter) PeerTlsConfigForClientUse() *tls.Config {
	return tlsConfigurationForClientUse(starter.PeerTlsConfig(), starter.peerCaFilePath)
}

func (starter *ProxyStarter) PeerHttpTransport() *http.Transport {
	transport := defaultHttpTransport()
	transport.TLSClientConfig = starter.PeerTlsConfigForClientUse()
	return transport
}

func (starter *ProxyStarter) ClientHttpTransport() *http.Transport {
	transport := defaultHttpTransport()
	transport.TLSClientConfig = starter.ClientTlsConfigForClientUse()
	return transport
}

func (starter *ProxyStarter) Listener() net.Listener {
	listener, err := net.Listen("tcp", starter.Listen.Host)
	if err != nil {
		fmt.Fprintf(os.Stderr, "failed to listen %s: %s", starter.Listen.String(), err.Error())
		os.Exit(1)
	}

	if starter.Listen.Scheme == "https" {
		tlsConfig := starter.TlsConfigForServerUse()
		listener = tls.NewListener(listener, tlsConfig)
	}

	return listener
}

func (starter *ProxyStarter) BackendUpdateFunc() proxy.BackendUpdateFunc {
	if starter.DiscoverySrvDomain != "" {
		transport := starter.PeerHttpTransport()
		return func() ([]*proxy.Backend, error) {
			return proxy.DiscoverBackendsFromDns(transport, starter.DiscoverySrvDomain)
		}
	} else {
		transport := starter.ClientHttpTransport()
		return func() ([]*proxy.Backend, error) {
			return proxy.DiscoverBackendsFromEtcd(transport, starter.InitialBackendUrls()), nil
		}
	}
}

func (starter *ProxyStarter) Router() *proxy.Router {
	if starter.router != nil {
		return starter.router
	}

	starter.router = proxy.NewRouter(starter.discoveryInterval, starter.BackendUpdateFunc())
	err := starter.router.StartUpdate()
	if err != nil {
		fmt.Fprintf(os.Stderr, "error starting backend discovery: %s", err.Error())
	}

	return starter.router
}

func (starter *ProxyStarter) Proxy() http.Handler {
	if starter.readonly {
		return proxy.NewReadonlyProxy(starter.ClientHttpTransport(), starter.Router(), starter.Engine(), starter.AdvertiseUrl)
	} else {
		return proxy.NewProxy(starter.ClientHttpTransport(), starter.Router(), starter.Engine(), starter.AdvertiseUrl)
	}
}

func (starter *ProxyStarter) HttpServer() *http.Server {
	return &http.Server{
		Handler:     starter.Proxy(),
		ReadTimeout: 5 * time.Minute,
	}
}

func (starter *ProxyStarter) Start() {
	fmt.Printf("Serving at %s\n", starter.Listen.String())
	starter.HttpServer().Serve(starter.Listener())
}
<commit_msg>missing newline<commit_after>package main

import (
	"crypto/tls"
	"crypto/x509"
	"encoding/pem"
	"fmt"
	"github.com/sorah/etcvault/engine"
	"github.com/sorah/etcvault/keys"
	"github.com/sorah/etcvault/proxy"
	"io/ioutil"
	"net"
	"net/http"
	"net/url"
	"os"
	"strings"
	"time"
)

func defaultHttpTransport() *http.Transport {
	return &http.Transport{
		// DefaultTransport
		Dial: (&net.Dialer{
			Timeout:   30 * time.Second,
			KeepAlive: 30 * time.Second,
		}).Dial,
		TLSHandshakeTimeout: 10 * time.Second,
	}
}

func caPool(caPath string) *x509.CertPool {
	pool := x509.NewCertPool()
	remainingPem, err := ioutil.ReadFile(caPath)
	if err != nil {
		fmt.Fprintf(os.Stderr, "error loading CA file %s: %s", caPath, err)
		os.Exit(1)
	}

	for { // load while file ends
		var block *pem.Block
		block, remainingPem = pem.Decode(remainingPem)
		if block == nil {
			return pool
		}
		cert, err := x509.ParseCertificate(block.Bytes)
		if err != nil {
			fmt.Fprintf(os.Stderr, "error while parsing CA PEM blocks: %s", err.Error())
			os.Exit(1)
		}
		pool.AddCert(cert)
	}
}

func parseTlsKeypair(certPath, keyPath string) *tls.Config {
	certBytes, err := ioutil.ReadFile(certPath)
	if err != nil {
		fmt.Fprintf(os.Stderr, "error loading certificate %s: %s\n", certPath, err.Error())
		os.Exit(1)
	}
	keyBytes, err := ioutil.ReadFile(keyPath)
	if err != nil {
		fmt.Fprintf(os.Stderr, "error loading certificate %s: %s\n", certPath, err.Error())
		os.Exit(1)
	}

	keypair, err := tls.X509KeyPair(certBytes, keyBytes)
	if err != nil {
		fmt.Printf("error loading keypair: %s\n", err.Error())
	}

	return &tls.Config{
		Certificates: []tls.Certificate{keypair},
		MinVersion:   tls.VersionTLS10,
	}
}

func tlsConfigurationForClientUse(config *tls.Config, caPath string) *tls.Config {
	if config == nil {
		config = &tls.Config{}
	}

	if caPath != "" {
		config.RootCAs = caPool(caPath)
	}

	return config
}

func tlsConfigurationForServerUse(config *tls.Config, caPath string) *tls.Config {
	if config == nil {
		config = &tls.Config{}
	}

	if caPath != "" {
		config.ClientAuth = tls.RequireAndVerifyClientCert
		config.ClientCAs = caPool(caPath)
	} else {
		config.ClientAuth = tls.NoClientCert
	}

	return config
}

type ProxyStarter struct {
	// arguments
	Listen       *url.URL
	AdvertiseUrl string

	keychainDir              string
	DiscoverySrvDomain       string
	initialBackendUrlStrings string

	clientCaFilePath   string
	clientCertFilePath string
	clientKeyFilePath  string

	peerCaFilePath   string
	peerCertFilePath string
	peerKeyFilePath  string

	listenCaFilePath   string
	listenCertFilePath string
	listenKeyFilePath  string

	readonly bool

	discoveryInterval time.Duration

	router *proxy.Router
}

func (starter *ProxyStarter) InitialBackendUrls() []*url.URL {
	urlStrings := strings.Split(starter.initialBackendUrlStrings, ",")
	urls := make([]*url.URL, len(urlStrings))

	for i, urlString := range urlStrings {
		u, err := url.Parse(urlString)
		if err != nil {
			fmt.Fprintf(os.Stderr, "failed to parse url %s: %s\n", urlString, err.Error())
			os.Exit(1)
		}
		urls[i] = u
	}

	return urls
}

func (starter *ProxyStarter) Keychain() *keys.Keychain {
	return keys.NewKeychain(starter.keychainDir)
}

func (starter *ProxyStarter) Engine() *engine.Engine {
	return engine.NewEngine(starter.Keychain())
}

func (starter *ProxyStarter) ListenTlsConfig() *tls.Config {
	if starter.listenKeyFilePath != "" && starter.listenCertFilePath != "" {
		return parseTlsKeypair(starter.listenCertFilePath, starter.listenKeyFilePath)
	} else {
		return nil
	}
}

func (starter *ProxyStarter) PeerTlsConfig() *tls.Config {
	if starter.peerKeyFilePath != "" && starter.peerCertFilePath != "" {
		return parseTlsKeypair(starter.peerCertFilePath, starter.peerKeyFilePath)
	} else {
		return nil
	}
}

func (starter *ProxyStarter) ClientTlsConfig() *tls.Config {
	if starter.clientKeyFilePath != "" && starter.clientCertFilePath != "" {
		return parseTlsKeypair(starter.clientCertFilePath, starter.clientKeyFilePath)
	} else {
		return nil
	}
}

func (starter *ProxyStarter) TlsConfigForServerUse() *tls.Config {
	if starter.listenKeyFilePath != "" && starter.listenCertFilePath != "" {
		return tlsConfigurationForServerUse(starter.ListenTlsConfig(), starter.listenCaFilePath)
	} else if starter.clientKeyFilePath != "" && starter.clientCertFilePath != "" {
		return tlsConfigurationForServerUse(starter.ClientTlsConfig(), starter.clientCaFilePath)
	} else {
		return nil
	}
}

func (starter *ProxyStarter) ClientTlsConfigForClientUse() *tls.Config {
	return tlsConfigurationForClientUse(starter.ClientTlsConfig(), starter.clientCaFilePath)
}

func (starter *ProxyStarter) PeerTlsConfigForClientUse() *tls.Config {
	return tlsConfigurationForClientUse(starter.PeerTlsConfig(), starter.peerCaFilePath)
}

func (starter *ProxyStarter) PeerHttpTransport() *http.Transport {
	transport := defaultHttpTransport()
	transport.TLSClientConfig = starter.PeerTlsConfigForClientUse()
	return transport
}

func (starter *ProxyStarter) ClientHttpTransport() *http.Transport {
	transport := defaultHttpTransport()
	transport.TLSClientConfig = starter.ClientTlsConfigForClientUse()
	return transport
}

func (starter *ProxyStarter) Listener() net.Listener {
	listener, err := net.Listen("tcp", starter.Listen.Host)
	if err != nil {
		fmt.Fprintf(os.Stderr, "failed to listen %s: %s", starter.Listen.String(), err.Error())
		os.Exit(1)
	}

	if starter.Listen.Scheme == "https" {
		tlsConfig := starter.TlsConfigForServerUse()
		listener = tls.NewListener(listener, tlsConfig)
	}

	return listener
}

func (starter *ProxyStarter) BackendUpdateFunc() proxy.BackendUpdateFunc {
	if starter.DiscoverySrvDomain != "" {
		transport := starter.PeerHttpTransport()
		return func() ([]*proxy.Backend, error) {
			return proxy.DiscoverBackendsFromDns(transport, starter.DiscoverySrvDomain)
		}
	} else {
		transport := starter.ClientHttpTransport()
		return func() ([]*proxy.Backend, error) {
			return proxy.DiscoverBackendsFromEtcd(transport, starter.InitialBackendUrls()), nil
		}
	}
}

func (starter *ProxyStarter) Router() *proxy.Router {
	if starter.router != nil {
		return starter.router
	}

	starter.router = proxy.NewRouter(starter.discoveryInterval, starter.BackendUpdateFunc())
	err := starter.router.StartUpdate()
	if err != nil {
		fmt.Fprintf(os.Stderr, "error starting backend discovery: %s", err.Error())
	}

	return starter.router
}

func (starter *ProxyStarter) Proxy() http.Handler {
	if starter.readonly {
		return proxy.NewReadonlyProxy(starter.ClientHttpTransport(), starter.Router(), starter.Engine(), starter.AdvertiseUrl)
	} else {
		return proxy.NewProxy(starter.ClientHttpTransport(), starter.Router(), starter.Engine(), starter.AdvertiseUrl)
	}
}

func (starter *ProxyStarter) HttpServer() *http.Server {
	return &http.Server{
		Handler:     starter.Proxy(),
		ReadTimeout: 5 * time.Minute,
	}
}

func (starter *ProxyStarter) Start() {
	fmt.Printf("Serving at %s\n", starter.Listen.String())
	starter.HttpServer().Serve(starter.Listener())
}
<|endoftext|>


<commit_before>package clover

import (
	"strings"
)

type TokenData struct {
	grantType GrantType
	grantData *GrantData
	client    Client
	Scope     []string
	ClientID  string
	UserID    string
	Data      map[string]interface{}
}

type tokenCtrl struct {
	store  ClientStore
	config *AuthServerConfig
}

func newTokenCtrl(store ClientStore, config *AuthServerConfig) *tokenCtrl {
	return &tokenCtrl{store, config}
}

func (t *tokenCtrl) token(tr *TokenRequest, respType AccessTokenRespType, grants map[string]GrantType) *Response {
	if respType == nil {
		return errInvalidRespType
	}

	td, resp := t.validate(tr, grants)
	if resp != nil {
		return resp
	}

	if resp = td.grantType.BeforeCreateAccessToken(tr, td); resp != nil {
		return resp
	}

	return respType.Response(td, td.grantType.IncludeRefreshToken())
}

func (t *tokenCtrl) validate(tr *TokenRequest, grants map[string]GrantType) (*TokenData, *Response) {
	var resp *Response
	td := &TokenData{}

	if td.grantType, resp = t.validateGrantType(tr, grants); resp != nil {
		return nil, resp
	}

	if td.grantData, resp = td.grantType.Validate(tr); resp != nil {
		return nil, resp
	}

	if td.client, resp = t.validateClient(tr, td.grantData); resp != nil {
		return nil, resp
	}

	if !checkGrantType(td.client.GetGrantType(), td.grantType.Name()) {
		return nil, errUnAuthorizedGrant
	}

	if td.Scope, resp = t.validateScope(tr, td.grantData, td.client); resp != nil {
		return nil, resp
	}

	td.ClientID = td.client.GetClientID()
	if td.grantData.UserID != "" {
		td.UserID = td.grantData.UserID
	}
	if len(td.grantData.Data) > 0 {
		td.Data = td.grantData.Data
	}

	return td, nil
}

func (t *tokenCtrl) validateGrantType(tr *TokenRequest, grants map[string]GrantType) (GrantType, *Response) {
	if tr.GrantType == "" {
		return nil, errGrantTypeRequired
	}

	grant, ok := grants[tr.GrantType]
	if !ok {
		return nil, errUnSupportedGrantType
	}

	return grant, nil
}

func (t *tokenCtrl) validateClient(tr *TokenRequest, grantData *GrantData) (Client, *Response) {
	var err error
	client, err := t.store.GetClient(tr.ClientID)
	if err != nil {
		return nil, errInvalidClientID
	}

	if grantData.ClientID != "" && grantData.ClientID != client.GetClientID() {
		return nil, errInvalidClientCredentail
	}

	return client, nil
}

func (t *tokenCtrl) validateScope(tr *TokenRequest, grantData *GrantData, client Client) ([]string, *Response) {
	scopes := strings.Fields(tr.Scope)
	if len(scopes) > 0 {
		if len(grantData.Scope) > 0 {
			if !checkScope(grantData.Scope, scopes...) {
				return nil, errInvalidScopeRequest
			}
		} else if len(client.GetScope()) > 0 {
			if !checkScope(client.GetScope(), scopes...) {
				return nil, errInvalidScopeRequest
			}
		} else {
			return nil, errUnSupportedScope
		}
	} else if len(grantData.Scope) > 0 {
		scopes = grantData.Scope
	} else if len(client.GetScope()) > 0 {
		scopes = client.GetScope()
	} else {
		if len(t.config.DefaultScopes) == 0 {
			return nil, errUnSupportedScope
		}

		scopes = t.config.DefaultScopes
	}

	return scopes, nil
}
<commit_msg>update<commit_after>package clover

import (
	"strings"
)

type TokenData struct {
	grantType GrantType
	grantData *GrantData
	client    Client
	Scope     []string
	ClientID  string
	UserID    string
	Data      map[string]interface{}
}

type tokenCtrl struct {
	store  ClientStore
	config *AuthServerConfig
}

func newTokenCtrl(store ClientStore, config *AuthServerConfig) *tokenCtrl {
	return &tokenCtrl{store, config}
}

func (t *tokenCtrl) token(tr *TokenRequest, respType AccessTokenRespType, grants map[string]GrantType) *Response {
	if respType == nil {
		return errInvalidRespType
	}

	td, resp := t.validate(tr, grants)
	if resp != nil {
		return resp
	}

	if resp = td.grantType.BeforeCreateAccessToken(tr, td); resp != nil {
		return resp
	}

	return respType.Response(td, td.grantType.IncludeRefreshToken())
}

func (t *tokenCtrl) validate(tr *TokenRequest, grants map[string]GrantType) (*TokenData, *Response) {
	var resp *Response
	td := &TokenData{}

	if td.grantType, resp = t.validateGrantType(tr, grants); resp != nil {
		return nil, resp
	}

	if td.grantData, resp = td.grantType.Validate(tr); resp != nil {
		return nil, resp
	}

	if td.client, resp = t.validateClient(tr, td.grantData); resp != nil {
		return nil, resp
	}

	if !checkGrantType(td.client.GetGrantType(), td.grantType.Name()) {
		return nil, errUnAuthorizedGrant
	}

	if td.Scope, resp = t.validateScope(tr, td.grantData, td.client); resp != nil {
		return nil, resp
	}

	td.ClientID = td.client.GetClientID()
	if td.grantData.UserID != "" {
		td.UserID = td.grantData.UserID
	}
	if len(td.grantData.Data) > 0 {
		td.Data = td.grantData.Data
	}

	return td, nil
}

func (t *tokenCtrl) validateGrantType(tr *TokenRequest, grants map[string]GrantType) (GrantType, *Response) {
	if tr.GrantType == "" {
		return nil, errGrantTypeRequired
	}

	grant, ok := grants[tr.GrantType]
	if !ok {
		return nil, errUnSupportedGrantType
	}

	return grant, nil
}

func (t *tokenCtrl) validateClient(tr *TokenRequest, grantData *GrantData) (Client, *Response) {
	var err error
	client, err := t.store.GetClient(tr.ClientID)
	if err != nil {
		return nil, errInvalidClientID
	}

	if grantData.ClientID != "" && grantData.ClientID != client.GetClientID() {
		return nil, errInvalidClientCredentail
	}

	return client, nil
}

func (t *tokenCtrl) validateScope(tr *TokenRequest, grantData *GrantData, client Client) ([]string, *Response) {
	scopes := strings.Fields(tr.Scope)
	if len(scopes) > 0 {
		if len(grantData.Scope) > 0 {
			if !checkScope(grantData.Scope, scopes...) {
				return nil, errInvalidScopeRequest
			}
		} else if len(client.GetScope()) > 0 {
			if !checkScope(client.GetScope(), scopes...) {
				return nil, errInvalidScopeRequest
			}
		} else {
			return scopes, nil
		}
	} else if len(grantData.Scope) > 0 {
		scopes = grantData.Scope
	} else if len(client.GetScope()) > 0 {
		scopes = client.GetScope()
	} else {
		if len(t.config.DefaultScopes) == 0 {
			return nil, errUnSupportedScope
		}

		scopes = t.config.DefaultScopes
	}

	return scopes, nil
}
<|endoftext|>


<commit_before>package replay

import (
	"testing"
)

func TestAddress(t *testing.T) {
	settings := &ReplaySettings{
		Host: "local",
		Port: 2,
	}

	settings.Parse()

	if settings.Address != "local:2" {
		t.Error("Address not match")
	}
}

func TestForwardAddress(t *testing.T) {
	settings := &ReplaySettings{
		Host:           "local",
		Port:           2,
		ForwardAddress: "host1:1,host2:2|10",
	}

	settings.Parse()

	forward_hosts := settings.ForwardedHosts()

	if len(forward_hosts) != 2 {
		t.Error("Should have 2 forward hosts")
	}

	if forward_hosts[0].Limit != 0 && forward_hosts[0].Url != "host1:1" {
		t.Error("Host should be host1:1 with no limit")
	}

	if forward_hosts[1].Limit != 10 && forward_hosts[0].Url != "host2:2" {
		t.Error("Host should be host2:2 with 10 limit")
	}
}

func TestElasticSearchSettings(t *testing.T) {
	settings := &ReplaySettings{
		Host:            "local",
		Port:            2,
		ForwardAddress:  "host1:1,host2:2|10",
		ElastiSearchURI: "host:10/index_name",
	}

	// FIXME: This is redundant. We could assign `Settings = *settings` to
	// check the code path in Init(), but it would result in the ES plugin
	// being registered twice.
	settings.Parse()

	esp := &ESPlugin{}
	esp.Init(settings.ElastiSearchURI)

	if esp.ApiPort != "10" {
		t.Error("Port not match")
	}

	if esp.Host != "host" {
		t.Error("Host not match")
	}

	if esp.Index != "index_name" {
		t.Error("Index not match")
	}
}
<commit_msg>Unit test the parsing of -header arguments<commit_after>package replay

import (
	"flag"
	"reflect"
	"testing"
)

func TestAddress(t *testing.T) {
	settings := &ReplaySettings{
		Host: "local",
		Port: 2,
	}

	settings.Parse()

	if settings.Address != "local:2" {
		t.Error("Address not match")
	}
}

func TestForwardAddress(t *testing.T) {
	settings := &ReplaySettings{
		Host:           "local",
		Port:           2,
		ForwardAddress: "host1:1,host2:2|10",
	}

	settings.Parse()

	forward_hosts := settings.ForwardedHosts()

	if len(forward_hosts) != 2 {
		t.Error("Should have 2 forward hosts")
	}

	if forward_hosts[0].Limit != 0 && forward_hosts[0].Url != "host1:1" {
		t.Error("Host should be host1:1 with no limit")
	}

	if forward_hosts[1].Limit != 10 && forward_hosts[0].Url != "host2:2" {
		t.Error("Host should be host2:2 with 10 limit")
	}
}

func TestElasticSearchSettings(t *testing.T) {
	settings := &ReplaySettings{
		Host:            "local",
		Port:            2,
		ForwardAddress:  "host1:1,host2:2|10",
		ElastiSearchURI: "host:10/index_name",
	}

	// FIXME: This is redundant. We could assign `Settings = *settings` to
	// check the code path in Init(), but it would result in the ES plugin
	// being registered twice.
	settings.Parse()

	esp := &ESPlugin{}
	esp.Init(settings.ElastiSearchURI)

	if esp.ApiPort != "10" {
		t.Error("Port not match")
	}

	if esp.Host != "host" {
		t.Error("Host not match")
	}

	if esp.Index != "index_name" {
		t.Error("Index not match")
	}
}

func TestAdditionalHeaders(t *testing.T) {
	args := []string{
		"-header", "Empty:",
		"-header", "Foo: contains:multiple:colons",
		"-header", "Host:nospaces.example.com",
		"-header", "Authorization: Basic Zm9vOmJhcg==",
		"-header", " User-Agent :  Contains leading and trailing space ",
	}
	out := Headers{
		{"Empty", ""},
		{"Foo", "contains:multiple:colons"},
		{"Host", "nospaces.example.com"},
		{"Authorization", "Basic Zm9vOmJhcg=="},
		{"User-Agent", "Contains leading and trailing space"},
	}

	headers := Headers{}
	fs := flag.NewFlagSet("TestHeaders", flag.ExitOnError)
	fs.Var(&headers, "header", "blah")
	fs.Parse(args)

	if !reflect.DeepEqual(headers, out) {
		t.Error("Headers not parsed as expected")
	}

	args = []string{
		"-header", "contains no colons",
	}
	headers = Headers{}
	fs = flag.NewFlagSet("TestHeaders", flag.ContinueOnError)
	fs.Var(&headers, "header", "blah")
	err := fs.Parse(args)

	if err == nil {
		t.Error("Invalid header should be rejected")
	}
}
<|endoftext|>


<commit_before>package optimizer

import (
	"math"
	"reflect"

	. "github.com/antonmedv/expr/ast"
)

type fold struct {
	applied bool
}

func (*fold) Enter(*Node) {}
func (fold *fold) Exit(node *Node) {
	patch := func(newNode Node) {
		fold.applied = true
		Patch(node, newNode)
	}
	// for IntegerNode the type may have been changed from int->float
	// preserve this information by setting the type after the Patch
	patchWithType := func(newNode Node, leafType reflect.Type) {
		fold.applied = true
		Patch(node, newNode)
		newNode.SetType(leafType)
	}

	switch n := (*node).(type) {
	case *UnaryNode:
		switch n.Operator {
		case "-":
			if i, ok := n.Node.(*IntegerNode); ok {
				patchWithType(&IntegerNode{Value: -i.Value}, n.Node.Type())
			}
		case "+":
			if i, ok := n.Node.(*IntegerNode); ok {
				patchWithType(&IntegerNode{Value: i.Value}, n.Node.Type())
			}
		}

	case *BinaryNode:
		switch n.Operator {
		case "+":
			if a, ok := n.Left.(*IntegerNode); ok {
				if b, ok := n.Right.(*IntegerNode); ok {
					patchWithType(&IntegerNode{Value: a.Value + b.Value}, a.Type())
				}
			}
			if a, ok := n.Left.(*StringNode); ok {
				if b, ok := n.Right.(*StringNode); ok {
					patch(&StringNode{Value: a.Value + b.Value})
				}
			}
		case "-":
			if a, ok := n.Left.(*IntegerNode); ok {
				if b, ok := n.Right.(*IntegerNode); ok {
					patchWithType(&IntegerNode{Value: a.Value - b.Value}, a.Type())
				}
			}
		case "*":
			if a, ok := n.Left.(*IntegerNode); ok {
				if b, ok := n.Right.(*IntegerNode); ok {
					patchWithType(&IntegerNode{Value: a.Value * b.Value}, a.Type())
				}
			}
		case "/":
			if a, ok := n.Left.(*IntegerNode); ok {
				if b, ok := n.Right.(*IntegerNode); ok {
					patchWithType(&IntegerNode{Value: a.Value / b.Value}, a.Type())
				}
			}
		case "%":
			if a, ok := n.Left.(*IntegerNode); ok {
				if b, ok := n.Right.(*IntegerNode); ok {
					patch(&IntegerNode{Value: a.Value % b.Value})
				}
			}
		case "**":
			if a, ok := n.Left.(*IntegerNode); ok {
				if b, ok := n.Right.(*IntegerNode); ok {
					patch(&FloatNode{Value: math.Pow(float64(a.Value), float64(b.Value))})
				}
			}
		}

	case *ArrayNode:
		if len(n.Nodes) > 0 {

			for _, a := range n.Nodes {
				if _, ok := a.(*IntegerNode); !ok {
					goto string
				}
			}
			{
				value := make([]int, len(n.Nodes))
				for i, a := range n.Nodes {
					value[i] = a.(*IntegerNode).Value
				}
				patch(&ConstantNode{Value: value})
			}

		string:
			for _, a := range n.Nodes {
				if _, ok := a.(*StringNode); !ok {
					return
				}
			}
			{
				value := make([]string, len(n.Nodes))
				for i, a := range n.Nodes {
					value[i] = a.(*StringNode).Value
				}
				patch(&ConstantNode{Value: value})
			}

		}
	}
}
<commit_msg>use patch func<commit_after>package optimizer

import (
	"math"
	"reflect"

	. "github.com/antonmedv/expr/ast"
)

type fold struct {
	applied bool
}

func (*fold) Enter(*Node) {}
func (fold *fold) Exit(node *Node) {
	patch := func(newNode Node) {
		fold.applied = true
		Patch(node, newNode)
	}
	// for IntegerNode the type may have been changed from int->float
	// preserve this information by setting the type after the Patch
	patchWithType := func(newNode Node, leafType reflect.Type) {
		patch(newNode)
		newNode.SetType(leafType)
	}

	switch n := (*node).(type) {
	case *UnaryNode:
		switch n.Operator {
		case "-":
			if i, ok := n.Node.(*IntegerNode); ok {
				patchWithType(&IntegerNode{Value: -i.Value}, n.Node.Type())
			}
		case "+":
			if i, ok := n.Node.(*IntegerNode); ok {
				patchWithType(&IntegerNode{Value: i.Value}, n.Node.Type())
			}
		}

	case *BinaryNode:
		switch n.Operator {
		case "+":
			if a, ok := n.Left.(*IntegerNode); ok {
				if b, ok := n.Right.(*IntegerNode); ok {
					patchWithType(&IntegerNode{Value: a.Value + b.Value}, a.Type())
				}
			}
			if a, ok := n.Left.(*StringNode); ok {
				if b, ok := n.Right.(*StringNode); ok {
					patch(&StringNode{Value: a.Value + b.Value})
				}
			}
		case "-":
			if a, ok := n.Left.(*IntegerNode); ok {
				if b, ok := n.Right.(*IntegerNode); ok {
					patchWithType(&IntegerNode{Value: a.Value - b.Value}, a.Type())
				}
			}
		case "*":
			if a, ok := n.Left.(*IntegerNode); ok {
				if b, ok := n.Right.(*IntegerNode); ok {
					patchWithType(&IntegerNode{Value: a.Value * b.Value}, a.Type())
				}
			}
		case "/":
			if a, ok := n.Left.(*IntegerNode); ok {
				if b, ok := n.Right.(*IntegerNode); ok {
					patchWithType(&IntegerNode{Value: a.Value / b.Value}, a.Type())
				}
			}
		case "%":
			if a, ok := n.Left.(*IntegerNode); ok {
				if b, ok := n.Right.(*IntegerNode); ok {
					patch(&IntegerNode{Value: a.Value % b.Value})
				}
			}
		case "**":
			if a, ok := n.Left.(*IntegerNode); ok {
				if b, ok := n.Right.(*IntegerNode); ok {
					patch(&FloatNode{Value: math.Pow(float64(a.Value), float64(b.Value))})
				}
			}
		}

	case *ArrayNode:
		if len(n.Nodes) > 0 {

			for _, a := range n.Nodes {
				if _, ok := a.(*IntegerNode); !ok {
					goto string
				}
			}
			{
				value := make([]int, len(n.Nodes))
				for i, a := range n.Nodes {
					value[i] = a.(*IntegerNode).Value
				}
				patch(&ConstantNode{Value: value})
			}

		string:
			for _, a := range n.Nodes {
				if _, ok := a.(*StringNode); !ok {
					return
				}
			}
			{
				value := make([]string, len(n.Nodes))
				for i, a := range n.Nodes {
					value[i] = a.(*StringNode).Value
				}
				patch(&ConstantNode{Value: value})
			}

		}
	}
}
<|endoftext|>


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

/*
Package testscript provides support for defining filesystem-based tests by
creating scripts in a directory.

To invoke the tests, call testscript.Run. For example:

	func TestFoo(t *testing.T) {
		testscript.Run(t, testscript.Params{
			Dir: "scripts",
		})
	}

A testscript directory holds test scripts *.txt run during 'go test'.
Each script defines a subtest; the exact set of allowable commands in a
script are defined by the parameters passed to the Run function.
To run a specific script foo.txt

	go test cmd/go -run=TestName/^foo$

where TestName is the name of the test that Run is called from.

To define an executable command (or several) that can be run as part of the script,
call RunMain with the functions that implement the command's functionality.
The command functions will be called in a separate process, so are
free to mutate global variables without polluting the top level test binary.

	func TestMain(m *testing.M) {
		os.Exit(testscript.RunMain(m, map[string] func() int{
			"testscript": testscriptMain,
		}))
	}

In general script files should have short names: a few words, not whole sentences.
The first word should be the general category of behavior being tested,
often the name of a subcommand to be tested or a concept (vendor, pattern).

Each script is a text archive (go doc github.com/rogpeppe/go-internal/txtar).
The script begins with an actual command script to run
followed by the content of zero or more supporting files to
create in the script's temporary file system before it starts executing.

As an example:

	# hello world
	exec cat hello
	stdout "hello world\n"
	! stderr .

	-- hello.txt--
	hello world

Each script runs in a fresh temporary work directory tree, available to scripts as $WORK.
Scripts also have access to these other environment variables:

	HOME=/no-home
	PATH=<actual PATH>
	TMPDIR=$WORK/tmp
	devnull=<value of os.DevNull>

The environment variable $exe (lowercase) is an empty string on most
systems, ".exe" on Windows.

The script's supporting files are unpacked relative to $WORK
and then the script begins execution in that
directory as well. Thus the example above runs in $WORK
with $WORK/hello.txt containing the listed contents.

The lines at the top of the script are a sequence of commands to be
executed by a small script engine in the testscript package (not the system
shell).  The script stops and the overall test fails if any particular
command fails.

Each line is parsed into a sequence of space-separated command words,
with environment variable expansion and # marking an end-of-line comment.
Adding single quotes around text keeps spaces in that text from being
treated as word separators and also disables environment variable
expansion.  Inside a single-quoted block of text, a repeated single
quote indicates a literal single quote, as in:

	'Don''t communicate by sharing memory.'

A line beginning with # is a comment and conventionally explains what is
being done or tested at the start of a new phase in the script.

The command prefix ! indicates that the command on the rest of the line
(typically go or a matching predicate) must fail, not succeed. Only certain
commands support this prefix. They are indicated below by [!] in the synopsis.

The command prefix [cond] indicates that the command on the rest of the line
should only run when the condition is satisfied. The predefined conditions are:

 - [short] for testing.Short()
 - [net] for whether the external network can be used
 - [link] for whether the OS has hard link support
 - [symlink] for whether the OS has symbolic link support
 - [exec:prog] for whether prog is available for execution (found by exec.LookPath)

A condition can be negated: [!short] means to run the rest of the line
when testing.Short() is false.

Additional conditions can be added by passing a function to Params.Condition.

The predefined commands are:

- cd dir
  Change to the given directory for future commands.

- chmod mode file

  Change the permissions of file or directory to the given octal mode (000 to 777).

- cmp file1 file2
  Check that the named files have the same content.
  By convention, file1 is the actual data and file2 the expected data.
  File1 can be "stdout" or "stderr" to use the standard output or standard error
  from the most recent exec or go command.
  (If the files have differing content, the failure prints a diff.)

- cp src... dst
  Copy the listed files to the target file or existing directory.

- env [key=value...]
  With no arguments, print the environment (useful for debugging).
  Otherwise add the listed key=value pairs to the environment.

- [!] exec program [args...]
  Run the given executable program with the arguments.
  It must (or must not) succeed.
  Note that 'exec' does not terminate the script (unlike in Unix shells).

- [!] exists [-readonly] file...
  Each of the listed files or directories must (or must not) exist.
  If -readonly is given, the files or directories must be unwritable.

- [!] grep [-count=N] pattern file
  The file's content must (or must not) match the regular expression pattern.
  For positive matches, -count=N specifies an exact number of matches to require.

- mkdir path...
  Create the listed directories, if they do not already exists.

- rm file...
  Remove the listed files or directories.

- skip [message]
  Mark the test skipped, including the message if given.

- [!] stderr [-count=N] pattern
  Apply the grep command (see above) to the standard error
  from the most recent exec or go command.

- [!] stdout [-count=N] pattern
  Apply the grep command (see above) to the standard output
  from the most recent exec or go command.

- stop [message]
  Stop the test early (marking it as passing), including the message if given.

- symlink file -> target
  Create file as a symlink to target. The -> (like in ls -l output) is required.

When TestScript runs a script and the script fails, by default TestScript shows
the execution of the most recent phase of the script (since the last # comment)
and only shows the # comments for earlier phases. For example, here is a
multi-phase script with a bug in it (TODO: make this example less go-command
specific):

	# GOPATH with p1 in d2, p2 in d2
	env GOPATH=$WORK/d1${:}$WORK/d2

	# build & install p1
	env
	go install -i p1
	! stale p1
	! stale p2

	# modify p2 - p1 should appear stale
	cp $WORK/p2x.go $WORK/d2/src/p2/p2.go
	stale p1 p2

	# build & install p1 again
	go install -i p11
	! stale p1
	! stale p2

	-- $WORK/d1/src/p1/p1.go --
	package p1
	import "p2"
	func F() { p2.F() }
	-- $WORK/d2/src/p2/p2.go --
	package p2
	func F() {}
	-- $WORK/p2x.go --
	package p2
	func F() {}
	func G() {}

The bug is that the final phase installs p11 instead of p1. The test failure looks like:

	$ go test -run=Script
	--- FAIL: TestScript (3.75s)
	    --- FAIL: TestScript/install_rebuild_gopath (0.16s)
	        script_test.go:223:
	            # GOPATH with p1 in d2, p2 in d2 (0.000s)
	            # build & install p1 (0.087s)
	            # modify p2 - p1 should appear stale (0.029s)
	            # build & install p1 again (0.022s)
	            > go install -i p11
	            [stderr]
	            can't load package: package p11: cannot find package "p11" in any of:
	            	/Users/rsc/go/src/p11 (from $GOROOT)
	            	$WORK/d1/src/p11 (from $GOPATH)
	            	$WORK/d2/src/p11
	            [exit status 1]
	            FAIL: unexpected go command failure

	        script_test.go:73: failed at testdata/script/install_rebuild_gopath.txt:15 in $WORK/gopath/src

	FAIL
	exit status 1
	FAIL	cmd/go	4.875s
	$

Note that the commands in earlier phases have been hidden, so that the relevant
commands are more easily found, and the elapsed time for a completed phase
is shown next to the phase heading. To see the entire execution, use "go test -v",
which also adds an initial environment dump to the beginning of the log.

Note also that in reported output, the actual name of the per-script temporary directory
has been consistently replaced with the literal string $WORK.

If Params.TestWork is true, it causes each test to log the name of its $WORK directory and other
environment variable settings and also to leave that directory behind when it exits,
for manual debugging of failing tests:

	$ go test -run=Script -work
	--- FAIL: TestScript (3.75s)
	    --- FAIL: TestScript/install_rebuild_gopath (0.16s)
	        script_test.go:223:
	            WORK=/tmp/cmd-go-test-745953508/script-install_rebuild_gopath
	            GOARCH=
	            GOCACHE=/Users/rsc/Library/Caches/go-build
	            GOOS=
	            GOPATH=$WORK/gopath
	            GOROOT=/Users/rsc/go
	            HOME=/no-home
	            TMPDIR=$WORK/tmp
	            exe=

	            # GOPATH with p1 in d2, p2 in d2 (0.000s)
	            # build & install p1 (0.085s)
	            # modify p2 - p1 should appear stale (0.030s)
	            # build & install p1 again (0.019s)
	            > go install -i p11
	            [stderr]
	            can't load package: package p11: cannot find package "p11" in any of:
	            	/Users/rsc/go/src/p11 (from $GOROOT)
	            	$WORK/d1/src/p11 (from $GOPATH)
	            	$WORK/d2/src/p11
	            [exit status 1]
	            FAIL: unexpected go command failure

	        script_test.go:73: failed at testdata/script/install_rebuild_gopath.txt:15 in $WORK/gopath/src

	FAIL
	exit status 1
	FAIL	cmd/go	4.875s
	$

	$ WORK=/tmp/cmd-go-test-745953508/script-install_rebuild_gopath
	$ cd $WORK/d1/src/p1
	$ cat p1.go
	package p1
	import "p2"
	func F() { p2.F() }
	$
*/
package testscript
<commit_msg>testscript: fix "hello world" doc example (#16)<commit_after>// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*
Package testscript provides support for defining filesystem-based tests by
creating scripts in a directory.

To invoke the tests, call testscript.Run. For example:

	func TestFoo(t *testing.T) {
		testscript.Run(t, testscript.Params{
			Dir: "scripts",
		})
	}

A testscript directory holds test scripts *.txt run during 'go test'.
Each script defines a subtest; the exact set of allowable commands in a
script are defined by the parameters passed to the Run function.
To run a specific script foo.txt

	go test cmd/go -run=TestName/^foo$

where TestName is the name of the test that Run is called from.

To define an executable command (or several) that can be run as part of the script,
call RunMain with the functions that implement the command's functionality.
The command functions will be called in a separate process, so are
free to mutate global variables without polluting the top level test binary.

	func TestMain(m *testing.M) {
		os.Exit(testscript.RunMain(m, map[string] func() int{
			"testscript": testscriptMain,
		}))
	}

In general script files should have short names: a few words, not whole sentences.
The first word should be the general category of behavior being tested,
often the name of a subcommand to be tested or a concept (vendor, pattern).

Each script is a text archive (go doc github.com/rogpeppe/go-internal/txtar).
The script begins with an actual command script to run
followed by the content of zero or more supporting files to
create in the script's temporary file system before it starts executing.

As an example:

	# hello world
	exec cat hello.text
	stdout 'hello world\n'
	! stderr .

	-- hello.text --
	hello world

Each script runs in a fresh temporary work directory tree, available to scripts as $WORK.
Scripts also have access to these other environment variables:

	HOME=/no-home
	PATH=<actual PATH>
	TMPDIR=$WORK/tmp
	devnull=<value of os.DevNull>

The environment variable $exe (lowercase) is an empty string on most
systems, ".exe" on Windows.

The script's supporting files are unpacked relative to $WORK
and then the script begins execution in that
directory as well. Thus the example above runs in $WORK
with $WORK/hello.txt containing the listed contents.

The lines at the top of the script are a sequence of commands to be
executed by a small script engine in the testscript package (not the system
shell).  The script stops and the overall test fails if any particular
command fails.

Each line is parsed into a sequence of space-separated command words,
with environment variable expansion and # marking an end-of-line comment.
Adding single quotes around text keeps spaces in that text from being
treated as word separators and also disables environment variable
expansion.  Inside a single-quoted block of text, a repeated single
quote indicates a literal single quote, as in:

	'Don''t communicate by sharing memory.'

A line beginning with # is a comment and conventionally explains what is
being done or tested at the start of a new phase in the script.

The command prefix ! indicates that the command on the rest of the line
(typically go or a matching predicate) must fail, not succeed. Only certain
commands support this prefix. They are indicated below by [!] in the synopsis.

The command prefix [cond] indicates that the command on the rest of the line
should only run when the condition is satisfied. The predefined conditions are:

 - [short] for testing.Short()
 - [net] for whether the external network can be used
 - [link] for whether the OS has hard link support
 - [symlink] for whether the OS has symbolic link support
 - [exec:prog] for whether prog is available for execution (found by exec.LookPath)

A condition can be negated: [!short] means to run the rest of the line
when testing.Short() is false.

Additional conditions can be added by passing a function to Params.Condition.

The predefined commands are:

- cd dir
  Change to the given directory for future commands.

- chmod mode file

  Change the permissions of file or directory to the given octal mode (000 to 777).

- cmp file1 file2
  Check that the named files have the same content.
  By convention, file1 is the actual data and file2 the expected data.
  File1 can be "stdout" or "stderr" to use the standard output or standard error
  from the most recent exec or go command.
  (If the files have differing content, the failure prints a diff.)

- cp src... dst
  Copy the listed files to the target file or existing directory.

- env [key=value...]
  With no arguments, print the environment (useful for debugging).
  Otherwise add the listed key=value pairs to the environment.

- [!] exec program [args...]
  Run the given executable program with the arguments.
  It must (or must not) succeed.
  Note that 'exec' does not terminate the script (unlike in Unix shells).

- [!] exists [-readonly] file...
  Each of the listed files or directories must (or must not) exist.
  If -readonly is given, the files or directories must be unwritable.

- [!] grep [-count=N] pattern file
  The file's content must (or must not) match the regular expression pattern.
  For positive matches, -count=N specifies an exact number of matches to require.

- mkdir path...
  Create the listed directories, if they do not already exists.

- rm file...
  Remove the listed files or directories.

- skip [message]
  Mark the test skipped, including the message if given.

- [!] stderr [-count=N] pattern
  Apply the grep command (see above) to the standard error
  from the most recent exec or go command.

- [!] stdout [-count=N] pattern
  Apply the grep command (see above) to the standard output
  from the most recent exec or go command.

- stop [message]
  Stop the test early (marking it as passing), including the message if given.

- symlink file -> target
  Create file as a symlink to target. The -> (like in ls -l output) is required.

When TestScript runs a script and the script fails, by default TestScript shows
the execution of the most recent phase of the script (since the last # comment)
and only shows the # comments for earlier phases. For example, here is a
multi-phase script with a bug in it (TODO: make this example less go-command
specific):

	# GOPATH with p1 in d2, p2 in d2
	env GOPATH=$WORK/d1${:}$WORK/d2

	# build & install p1
	env
	go install -i p1
	! stale p1
	! stale p2

	# modify p2 - p1 should appear stale
	cp $WORK/p2x.go $WORK/d2/src/p2/p2.go
	stale p1 p2

	# build & install p1 again
	go install -i p11
	! stale p1
	! stale p2

	-- $WORK/d1/src/p1/p1.go --
	package p1
	import "p2"
	func F() { p2.F() }
	-- $WORK/d2/src/p2/p2.go --
	package p2
	func F() {}
	-- $WORK/p2x.go --
	package p2
	func F() {}
	func G() {}

The bug is that the final phase installs p11 instead of p1. The test failure looks like:

	$ go test -run=Script
	--- FAIL: TestScript (3.75s)
	    --- FAIL: TestScript/install_rebuild_gopath (0.16s)
	        script_test.go:223:
	            # GOPATH with p1 in d2, p2 in d2 (0.000s)
	            # build & install p1 (0.087s)
	            # modify p2 - p1 should appear stale (0.029s)
	            # build & install p1 again (0.022s)
	            > go install -i p11
	            [stderr]
	            can't load package: package p11: cannot find package "p11" in any of:
	            	/Users/rsc/go/src/p11 (from $GOROOT)
	            	$WORK/d1/src/p11 (from $GOPATH)
	            	$WORK/d2/src/p11
	            [exit status 1]
	            FAIL: unexpected go command failure

	        script_test.go:73: failed at testdata/script/install_rebuild_gopath.txt:15 in $WORK/gopath/src

	FAIL
	exit status 1
	FAIL	cmd/go	4.875s
	$

Note that the commands in earlier phases have been hidden, so that the relevant
commands are more easily found, and the elapsed time for a completed phase
is shown next to the phase heading. To see the entire execution, use "go test -v",
which also adds an initial environment dump to the beginning of the log.

Note also that in reported output, the actual name of the per-script temporary directory
has been consistently replaced with the literal string $WORK.

If Params.TestWork is true, it causes each test to log the name of its $WORK directory and other
environment variable settings and also to leave that directory behind when it exits,
for manual debugging of failing tests:

	$ go test -run=Script -work
	--- FAIL: TestScript (3.75s)
	    --- FAIL: TestScript/install_rebuild_gopath (0.16s)
	        script_test.go:223:
	            WORK=/tmp/cmd-go-test-745953508/script-install_rebuild_gopath
	            GOARCH=
	            GOCACHE=/Users/rsc/Library/Caches/go-build
	            GOOS=
	            GOPATH=$WORK/gopath
	            GOROOT=/Users/rsc/go
	            HOME=/no-home
	            TMPDIR=$WORK/tmp
	            exe=

	            # GOPATH with p1 in d2, p2 in d2 (0.000s)
	            # build & install p1 (0.085s)
	            # modify p2 - p1 should appear stale (0.030s)
	            # build & install p1 again (0.019s)
	            > go install -i p11
	            [stderr]
	            can't load package: package p11: cannot find package "p11" in any of:
	            	/Users/rsc/go/src/p11 (from $GOROOT)
	            	$WORK/d1/src/p11 (from $GOPATH)
	            	$WORK/d2/src/p11
	            [exit status 1]
	            FAIL: unexpected go command failure

	        script_test.go:73: failed at testdata/script/install_rebuild_gopath.txt:15 in $WORK/gopath/src

	FAIL
	exit status 1
	FAIL	cmd/go	4.875s
	$

	$ WORK=/tmp/cmd-go-test-745953508/script-install_rebuild_gopath
	$ cd $WORK/d1/src/p1
	$ cat p1.go
	package p1
	import "p2"
	func F() { p2.F() }
	$
*/
package testscript
<|endoftext|>


<commit_before>package lua

import (
	log "github.com/Sirupsen/logrus"
	"github.com/loadimpact/speedboat"
	"github.com/loadimpact/speedboat/sampler"
	"github.com/valyala/fasthttp"
	"github.com/yuin/gopher-lua"
	"golang.org/x/net/context"
	"time"
)

type Runner struct {
	Filename string
	Source   string
	Client   *fasthttp.Client
}

func New(filename, src string) *Runner {
	return &Runner{
		Filename: filename,
		Source:   src,
		Client:   &fasthttp.Client{},
	}
}

func (r *Runner) RunVU(ctx context.Context, t speedboat.Test, id int) {
	mDuration := sampler.Stats("request.duration")
	mErrors := sampler.Counter("request.error")

	L := lua.NewState()
	defer L.Close()

	fn, err := L.LoadString(r.Source)
	if err != nil {
		log.WithError(err).Error("Couldn't compile script")
		return
	}

	L.SetGlobal("sleep", L.NewFunction(func(L *lua.LState) int {
		time.Sleep(time.Duration(L.ToInt64(1)) * time.Second)
		return 0
	}))
	L.SetGlobal("get", L.NewFunction(func(L *lua.LState) int {
		url := L.ToString(1)

		req := fasthttp.AcquireRequest()
		defer fasthttp.ReleaseRequest(req)

		req.SetRequestURI(url)

		res := fasthttp.AcquireResponse()
		defer fasthttp.ReleaseResponse(res)

		startTime := time.Now()
		err := r.Client.Do(req, res)
		duration := time.Since(startTime)

		mDuration.WithFields(sampler.Fields{
			"url":    url,
			"method": "GET",
			"status": res.StatusCode(),
		}).Duration(duration)

		if err != nil {
			log.WithError(err).Error("Request error")
			mErrors.WithFields(sampler.Fields{
				"url":    url,
				"method": "GET",
				"error":  err,
			}).Int(1)
		}

		return 0
	}))

	for {
		L.Push(fn)
		if err := L.PCall(0, 0, nil); err != nil {
			log.WithError(err).Error("Script error")
		}
	}
}
<commit_msg>[experiment] Loads and loads of connections<commit_after>package lua

import (
	log "github.com/Sirupsen/logrus"
	"github.com/loadimpact/speedboat"
	"github.com/loadimpact/speedboat/sampler"
	"github.com/valyala/fasthttp"
	"github.com/yuin/gopher-lua"
	"golang.org/x/net/context"
	"math"
	"time"
)

type Runner struct {
	Filename string
	Source   string
	Client   *fasthttp.Client
}

func New(filename, src string) *Runner {
	return &Runner{
		Filename: filename,
		Source:   src,
		Client: &fasthttp.Client{
			MaxConnsPerHost: math.MaxInt32,
		},
	}
}

func (r *Runner) RunVU(ctx context.Context, t speedboat.Test, id int) {
	mDuration := sampler.Stats("request.duration")
	mErrors := sampler.Counter("request.error")

	L := lua.NewState()
	defer L.Close()

	fn, err := L.LoadString(r.Source)
	if err != nil {
		log.WithError(err).Error("Couldn't compile script")
		return
	}

	L.SetGlobal("sleep", L.NewFunction(func(L *lua.LState) int {
		time.Sleep(time.Duration(L.ToInt64(1)) * time.Second)
		return 0
	}))
	L.SetGlobal("get", L.NewFunction(func(L *lua.LState) int {
		url := L.ToString(1)

		req := fasthttp.AcquireRequest()
		defer fasthttp.ReleaseRequest(req)

		req.SetRequestURI(url)

		res := fasthttp.AcquireResponse()
		defer fasthttp.ReleaseResponse(res)

		startTime := time.Now()
		err := r.Client.Do(req, res)
		duration := time.Since(startTime)

		mDuration.WithFields(sampler.Fields{
			"url":    url,
			"method": "GET",
			"status": res.StatusCode(),
		}).Duration(duration)

		if err != nil {
			log.WithError(err).Error("Request error")
			mErrors.WithFields(sampler.Fields{
				"url":    url,
				"method": "GET",
				"error":  err,
			}).Int(1)
		}

		return 0
	}))

	for {
		L.Push(fn)
		if err := L.PCall(0, 0, nil); err != nil {
			log.WithError(err).Error("Script error")
		}
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Kubernetes Authors 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 integration

import (
	"context"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"runtime"
	"strings"
	"testing"
	"time"

	"github.com/docker/machine/libmachine/state"

	"k8s.io/minikube/pkg/minikube/constants"
	"k8s.io/minikube/pkg/util/retry"

	"github.com/hashicorp/go-getter"
	pkgutil "k8s.io/minikube/pkg/util"
)

// TestVersionUpgrade downloads the latest version of minikube and runs with
// the oldest supported k8s version and then runs the current head minikube
// and tries to upgrade from the oldest supported k8s to newest supported k8s
func TestVersionUpgrade(t *testing.T) {
	MaybeParallel(t)
	profile := UniqueProfileName("vupgrade")
	ctx, cancel := context.WithTimeout(context.Background(), Minutes(55))

	defer CleanupWithLogs(t, profile, cancel)

	tf, err := ioutil.TempFile("", "minikube-release.*.exe")
	if err != nil {
		t.Fatalf("tempfile: %v", err)
	}
	defer os.Remove(tf.Name())
	tf.Close()

	url := pkgutil.GetBinaryDownloadURL("latest", runtime.GOOS)
	if err := retry.Expo(func() error { return getter.GetFile(tf.Name(), url) }, 3*time.Second, Minutes(3)); err != nil {
		t.Fatalf("get failed: %v", err)
	}

	if runtime.GOOS != "windows" {
		if err := os.Chmod(tf.Name(), 0700); err != nil {
			t.Errorf("chmod: %v", err)
		}
	}

	// Assert that --iso-url works without a sha checksum, and that we can upgrade from old ISO's
	// Some day, this will break an implicit assumption that a tool is available in the ISO :)
	oldISO := "https://storage.googleapis.com/minikube/iso/integration-test.iso"
	args := append([]string{"start", "-p", profile, "--memory=2200", fmt.Sprintf("--iso-url=%s", oldISO), fmt.Sprintf("--kubernetes-version=%s", constants.OldestKubernetesVersion), "--alsologtostderr"}, StartArgs()...)
	rr := &RunResult{}
	r := func() error {
		rr, err = Run(t, exec.CommandContext(ctx, tf.Name(), args...))
		return err
	}

	// Retry up to two times, to allow flakiness for the previous release
	if err := retry.Expo(r, 1*time.Second, Minutes(30), 2); err != nil {
		t.Fatalf("release start failed: %v", err)
	}

	rr, err = Run(t, exec.CommandContext(ctx, tf.Name(), "stop", "-p", profile))
	if err != nil {
		t.Fatalf("%s failed: %v", rr.Command(), err)
	}

	rr, err = Run(t, exec.CommandContext(ctx, tf.Name(), "-p", profile, "status", "--format={{.Host}}"))
	if err != nil {
		t.Logf("status error: %v (may be ok)", err)
	}

	got := strings.TrimSpace(rr.Stdout.String())
	if got != state.Stopped.String() {
		t.Errorf("FAILED: status = %q; want = %q", got, state.Stopped.String())
	}

	args = append([]string{"start", "-p", profile, "--memory=2200", fmt.Sprintf("--kubernetes-version=%s", constants.NewestKubernetesVersion), "--alsologtostderr", "-v=1"}, StartArgs()...)
	rr, err = Run(t, exec.CommandContext(ctx, Target(), args...))
	if err != nil {
		t.Errorf("failed to start minikube HEAD with newest k8s version. args: %s : %v", rr.Command(), err)
	}

	s, err := Run(t, exec.CommandContext(ctx, "kubectl", "--context", profile, "version", "--output=json"))
	if err != nil {
		t.Fatalf("error running kubectl: %v", err)
	}
	cv := struct {
		ServerVersion struct {
			GitVersion string `json:"gitVersion"`
		} `json:"serverVersion"`
	}{}
	err = json.Unmarshal(s.Stdout.Bytes(), &cv)

	if err != nil {
		t.Fatalf("error traversing json output: %v", err)
	}

	if cv.ServerVersion.GitVersion != constants.NewestKubernetesVersion {
		t.Fatalf("expected server version %s is not the same with latest version %s", cv.ServerVersion.GitVersion, constants.NewestKubernetesVersion)
	}

	t.Logf("Attempting to downgrade Kubernetes (should fail)")
	args = append([]string{"start", "-p", profile, "--memory=2200", fmt.Sprintf("--kubernetes-version=%s", constants.OldestKubernetesVersion)}, StartArgs()...)
	if rr, err := Run(t, exec.CommandContext(ctx, tf.Name(), args...)); err == nil {
		t.Fatalf("downgrading Kubernetes should not be allowed. expected to see error but got %v for %q", err, rr.Command())
	}

	t.Logf("Attempting restart after unsuccessful downgrade")
	args = append([]string{"start", "-p", profile, "--memory=2200", fmt.Sprintf("--kubernetes-version=%s", constants.NewestKubernetesVersion), "--alsologtostderr", "-v=1"}, StartArgs()...)
	rr, err = Run(t, exec.CommandContext(ctx, Target(), args...))
	if err != nil {
		t.Errorf("start after failed upgrade: %v", err)
	}
}

// TestMissingUpgrade tests a Docker upgrade where the underlying container is missing
func TestMissingUpgrade(t *testing.T) {
	if !DockerDriver() {
		t.Skipf("This test is only for Docker")
	}

	MaybeParallel(t)
	profile := UniqueProfileName("missing-upgrade")
	ctx, cancel := context.WithTimeout(context.Background(), Minutes(55))

	defer CleanupWithLogs(t, profile, cancel)

	legacyVersion := "v1.9.1"
	tf, err := ioutil.TempFile("", fmt.Sprintf("minikube-%s.*.exe", legacyVersion))
	if err != nil {
		t.Fatalf("tempfile: %v", err)
	}
	defer os.Remove(tf.Name())
	tf.Close()

	url := pkgutil.GetBinaryDownloadURL(legacyVersion, runtime.GOOS)
	if err := retry.Expo(func() error { return getter.GetFile(tf.Name(), url) }, 3*time.Second, Minutes(3)); err != nil {
		t.Fatalf("get failed: %v", err)
	}

	if runtime.GOOS != "windows" {
		if err := os.Chmod(tf.Name(), 0700); err != nil {
			t.Errorf("chmod: %v", err)
		}
	}

	args := append([]string{"start", "-p", profile, "--memory=2200"}, StartArgs()...)
	rr := &RunResult{}
	r := func() error {
		rr, err = Run(t, exec.CommandContext(ctx, tf.Name(), args...))
		return err
	}

	// Retry up to two times, to allow flakiness for the previous release
	if err := retry.Expo(r, 1*time.Second, Minutes(30), 2); err != nil {
		t.Fatalf("release start failed: %v", err)
	}

	rr, err = Run(t, exec.CommandContext(ctx, "docker", "stop", profile))
	if err != nil {
		t.Fatalf("%s failed: %v", rr.Command(), err)
	}

	rr, err = Run(t, exec.CommandContext(ctx, "docker", "rm", profile))
	if err != nil {
		t.Fatalf("%s failed: %v", rr.Command(), err)
	}

	args = append([]string{"start", "-p", profile, "--memory=2200", "--alsologtostderr", "-v=1"}, StartArgs()...)
	rr, err = Run(t, exec.CommandContext(ctx, Target(), args...))
	if err != nil {
		t.Errorf("failed to start minikube HEAD with newest k8s version. args: %s : %v", rr.Command(), err)
	}
}
<commit_msg>Improve failure message for TestMissingContainerUpgrade<commit_after>/*
Copyright 2019 The Kubernetes Authors 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 integration

import (
	"context"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"runtime"
	"strings"
	"testing"
	"time"

	"github.com/docker/machine/libmachine/state"

	"k8s.io/minikube/pkg/minikube/constants"
	"k8s.io/minikube/pkg/util/retry"

	"github.com/hashicorp/go-getter"
	pkgutil "k8s.io/minikube/pkg/util"
)

// TestVersionUpgrade downloads the latest version of minikube and runs with
// the oldest supported k8s version and then runs the current head minikube
// and tries to upgrade from the oldest supported k8s to newest supported k8s
func TestVersionUpgrade(t *testing.T) {
	MaybeParallel(t)
	profile := UniqueProfileName("vupgrade")
	ctx, cancel := context.WithTimeout(context.Background(), Minutes(55))

	defer CleanupWithLogs(t, profile, cancel)

	tf, err := ioutil.TempFile("", "minikube-release.*.exe")
	if err != nil {
		t.Fatalf("tempfile: %v", err)
	}
	defer os.Remove(tf.Name())
	tf.Close()

	url := pkgutil.GetBinaryDownloadURL("latest", runtime.GOOS)
	if err := retry.Expo(func() error { return getter.GetFile(tf.Name(), url) }, 3*time.Second, Minutes(3)); err != nil {
		t.Fatalf("get failed: %v", err)
	}

	if runtime.GOOS != "windows" {
		if err := os.Chmod(tf.Name(), 0700); err != nil {
			t.Errorf("chmod: %v", err)
		}
	}

	// Assert that --iso-url works without a sha checksum, and that we can upgrade from old ISO's
	// Some day, this will break an implicit assumption that a tool is available in the ISO :)
	oldISO := "https://storage.googleapis.com/minikube/iso/integration-test.iso"
	args := append([]string{"start", "-p", profile, "--memory=2200", fmt.Sprintf("--iso-url=%s", oldISO), fmt.Sprintf("--kubernetes-version=%s", constants.OldestKubernetesVersion), "--alsologtostderr"}, StartArgs()...)
	rr := &RunResult{}
	r := func() error {
		rr, err = Run(t, exec.CommandContext(ctx, tf.Name(), args...))
		return err
	}

	// Retry up to two times, to allow flakiness for the previous release
	if err := retry.Expo(r, 1*time.Second, Minutes(30), 2); err != nil {
		t.Fatalf("release start failed: %v", err)
	}

	rr, err = Run(t, exec.CommandContext(ctx, tf.Name(), "stop", "-p", profile))
	if err != nil {
		t.Fatalf("%s failed: %v", rr.Command(), err)
	}

	rr, err = Run(t, exec.CommandContext(ctx, tf.Name(), "-p", profile, "status", "--format={{.Host}}"))
	if err != nil {
		t.Logf("status error: %v (may be ok)", err)
	}

	got := strings.TrimSpace(rr.Stdout.String())
	if got != state.Stopped.String() {
		t.Errorf("FAILED: status = %q; want = %q", got, state.Stopped.String())
	}

	args = append([]string{"start", "-p", profile, "--memory=2200", fmt.Sprintf("--kubernetes-version=%s", constants.NewestKubernetesVersion), "--alsologtostderr", "-v=1"}, StartArgs()...)
	rr, err = Run(t, exec.CommandContext(ctx, Target(), args...))
	if err != nil {
		t.Errorf("failed to start minikube HEAD with newest k8s version. args: %s : %v", rr.Command(), err)
	}

	s, err := Run(t, exec.CommandContext(ctx, "kubectl", "--context", profile, "version", "--output=json"))
	if err != nil {
		t.Fatalf("error running kubectl: %v", err)
	}
	cv := struct {
		ServerVersion struct {
			GitVersion string `json:"gitVersion"`
		} `json:"serverVersion"`
	}{}
	err = json.Unmarshal(s.Stdout.Bytes(), &cv)

	if err != nil {
		t.Fatalf("error traversing json output: %v", err)
	}

	if cv.ServerVersion.GitVersion != constants.NewestKubernetesVersion {
		t.Fatalf("expected server version %s is not the same with latest version %s", cv.ServerVersion.GitVersion, constants.NewestKubernetesVersion)
	}

	t.Logf("Attempting to downgrade Kubernetes (should fail)")
	args = append([]string{"start", "-p", profile, "--memory=2200", fmt.Sprintf("--kubernetes-version=%s", constants.OldestKubernetesVersion)}, StartArgs()...)
	if rr, err := Run(t, exec.CommandContext(ctx, tf.Name(), args...)); err == nil {
		t.Fatalf("downgrading Kubernetes should not be allowed. expected to see error but got %v for %q", err, rr.Command())
	}

	t.Logf("Attempting restart after unsuccessful downgrade")
	args = append([]string{"start", "-p", profile, "--memory=2200", fmt.Sprintf("--kubernetes-version=%s", constants.NewestKubernetesVersion), "--alsologtostderr", "-v=1"}, StartArgs()...)
	rr, err = Run(t, exec.CommandContext(ctx, Target(), args...))
	if err != nil {
		t.Errorf("start after failed upgrade: %v", err)
	}
}

// TestMissingContainerUpgrade tests a Docker upgrade where the underlying container is missing
func TestMissingContainerUpgrade(t *testing.T) {
	if !DockerDriver() {
		t.Skipf("This test is only for Docker")
	}

	MaybeParallel(t)
	profile := UniqueProfileName("missing-upgrade")
	ctx, cancel := context.WithTimeout(context.Background(), Minutes(55))

	defer CleanupWithLogs(t, profile, cancel)

	legacyVersion := "v1.9.1"
	tf, err := ioutil.TempFile("", fmt.Sprintf("minikube-%s.*.exe", legacyVersion))
	if err != nil {
		t.Fatalf("tempfile: %v", err)
	}
	defer os.Remove(tf.Name())
	tf.Close()

	url := pkgutil.GetBinaryDownloadURL(legacyVersion, runtime.GOOS)
	if err := retry.Expo(func() error { return getter.GetFile(tf.Name(), url) }, 3*time.Second, Minutes(3)); err != nil {
		t.Fatalf("get failed: %v", err)
	}

	if runtime.GOOS != "windows" {
		if err := os.Chmod(tf.Name(), 0700); err != nil {
			t.Errorf("chmod: %v", err)
		}
	}

	args := append([]string{"start", "-p", profile, "--memory=2200"}, StartArgs()...)
	rr := &RunResult{}
	r := func() error {
		rr, err = Run(t, exec.CommandContext(ctx, tf.Name(), args...))
		return err
	}

	// Retry up to two times, to allow flakiness for the previous release
	if err := retry.Expo(r, 1*time.Second, Minutes(30), 2); err != nil {
		t.Fatalf("release start failed: %v", err)
	}

	rr, err = Run(t, exec.CommandContext(ctx, "docker", "stop", profile))
	if err != nil {
		t.Fatalf("%s failed: %v", rr.Command(), err)
	}

	rr, err = Run(t, exec.CommandContext(ctx, "docker", "rm", profile))
	if err != nil {
		t.Fatalf("%s failed: %v", rr.Command(), err)
	}

	args = append([]string{"start", "-p", profile, "--memory=2200", "--alsologtostderr", "-v=1"}, StartArgs()...)
	rr, err = Run(t, exec.CommandContext(ctx, Target(), args...))
	if err != nil {
		t.Errorf("failed missing container upgrade from %s. args: %s : %v", legacyVersion, rr.Command(), err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"strings"

	"github.com/spf13/cobra"

	"github.com/lxc/lxd/lxc/config"
	"github.com/lxc/lxd/lxc/utils"
	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/api"
	cli "github.com/lxc/lxd/shared/cmd"
	"github.com/lxc/lxd/shared/i18n"
)

// Start
type cmdStart struct {
	global *cmdGlobal
	action *cmdAction
}

func (c *cmdStart) Command() *cobra.Command {
	cmdAction := cmdAction{global: c.global}
	c.action = &cmdAction

	cmd := c.action.Command("start")
	cmd.Use = i18n.G("start [<remote>:]<container> [[<remote>:]<container>...]")
	cmd.Short = i18n.G("Start containers")
	cmd.Long = cli.FormatSection(i18n.G("Description"), i18n.G(
		`Start containers`))

	return cmd
}

// Pause
type cmdPause struct {
	global *cmdGlobal
	action *cmdAction
}

func (c *cmdPause) Command() *cobra.Command {
	cmdAction := cmdAction{global: c.global}
	c.action = &cmdAction

	cmd := c.action.Command("pause")
	cmd.Use = i18n.G("pause [<remote>:]<container> [[<remote>:]<container>...]")
	cmd.Short = i18n.G("Pause containers")
	cmd.Long = cli.FormatSection(i18n.G("Description"), i18n.G(
		`Pause containers`))
	cmd.Hidden = true

	return cmd
}

// Restart
type cmdRestart struct {
	global *cmdGlobal
	action *cmdAction
}

func (c *cmdRestart) Command() *cobra.Command {
	cmdAction := cmdAction{global: c.global}
	c.action = &cmdAction

	cmd := c.action.Command("restart")
	cmd.Use = i18n.G("restart [<remote>:]<container> [[<remote>:]<container>...]")
	cmd.Short = i18n.G("Restart containers")
	cmd.Long = cli.FormatSection(i18n.G("Description"), i18n.G(
		`Restart containers

The opposite of "lxc pause" is "lxc start".`))

	return cmd
}

// Stop
type cmdStop struct {
	global *cmdGlobal
	action *cmdAction
}

func (c *cmdStop) Command() *cobra.Command {
	cmdAction := cmdAction{global: c.global}
	c.action = &cmdAction

	cmd := c.action.Command("stop")
	cmd.Use = i18n.G("stop [<remote>:]<container> [[<remote>:]<container>...]")
	cmd.Short = i18n.G("Stop containers")
	cmd.Long = cli.FormatSection(i18n.G("Description"), i18n.G(
		`Stop containers`))

	return cmd
}

type cmdAction struct {
	global *cmdGlobal

	flagAll       bool
	flagForce     bool
	flagStateful  bool
	flagStateless bool
	flagTimeout   int
}

func (c *cmdAction) Command(action string) *cobra.Command {
	cmd := &cobra.Command{}
	cmd.RunE = c.Run

	cmd.Flags().BoolVar(&c.flagAll, "all", false, i18n.G("Run command against all containers"))

	if action == "stop" {
		cmd.Flags().BoolVar(&c.flagStateful, "stateful", false, i18n.G("Store the container state"))
	} else if action == "start" {
		cmd.Flags().BoolVar(&c.flagStateless, "stateless", false, i18n.G("Ignore the container state"))
	}

	if shared.StringInSlice(action, []string{"restart", "stop"}) {
		cmd.Flags().BoolVarP(&c.flagForce, "force", "f", false, i18n.G("Force the container to shutdown"))
		cmd.Flags().IntVar(&c.flagTimeout, "timeout", -1, i18n.G("Time to wait for the container before killing it")+"``")
	}

	return cmd
}

func (c *cmdAction) doAction(action string, conf *config.Config, nameArg string) error {
	state := false

	// Only store state if asked to
	if action == "stop" && c.flagStateful {
		state = true
	}

	remote, name, err := conf.ParseRemote(nameArg)
	if err != nil {
		return err
	}

	d, err := conf.GetContainerServer(remote)
	if err != nil {
		return err
	}

	if name == "" {
		return fmt.Errorf(i18n.G("Must supply container name for: ")+"\"%s\"", nameArg)
	}

	if action == "start" {
		current, _, err := d.GetContainer(name)
		if err != nil {
			return err
		}

		// "start" for a frozen container means "unfreeze"
		if current.StatusCode == api.Frozen {
			action = "unfreeze"
		}

		// Always restore state (if present) unless asked not to
		if action == "start" && current.Stateful && !c.flagStateless {
			state = true
		}
	}

	req := api.ContainerStatePut{
		Action:   action,
		Timeout:  c.flagTimeout,
		Force:    c.flagForce,
		Stateful: state,
	}

	op, err := d.UpdateContainerState(name, req, "")
	if err != nil {
		return err
	}

	progress := utils.ProgressRenderer{}
	_, err = op.AddHandler(progress.UpdateOp)
	if err != nil {
		progress.Done("")
		return err
	}

	err = op.Wait()
	progress.Done("")
	if err != nil {
		return fmt.Errorf("%s\n"+i18n.G("Try `lxc info --show-log %s` for more info"), err, nameArg)
	}

	return nil
}

func (c *cmdAction) Run(cmd *cobra.Command, args []string) error {
	conf := c.global.conf

	var names []string
	if len(args) == 0 {
		if !c.flagAll {
			cmd.Help()
			return nil
		}

		d, err := conf.GetContainerServer(conf.DefaultRemote)
		if err != nil {
			return err
		}

		ctslist, err := d.GetContainers()
		if err != nil {
			return err
		}

		for _, ct := range ctslist {
			names = append(names, ct.Name)
		}
	} else {
		if c.flagAll {
			return fmt.Errorf(i18n.G("Both --all and container name given"))
		}
		names = args
	}

	// Run the action for every listed container
	results := runBatch(names, func(name string) error { return c.doAction(cmd.Name(), conf, name) })

	// Single container is easy
	if len(results) == 1 {
		return results[0].err
	}

	// Do fancier rendering for batches
	success := true

	for _, result := range results {
		if result.err == nil {
			continue
		}

		success = false
		msg := fmt.Sprintf(i18n.G("error: %v"), result.err)
		for _, line := range strings.Split(msg, "\n") {
			fmt.Fprintln(os.Stderr, fmt.Sprintf("%s: %s", result.name, line))
		}
	}

	if !success {
		fmt.Fprintln(os.Stderr, "")
		return fmt.Errorf(i18n.G("Some containers failed to %s"), cmd.Name())
	}

	return nil
}
<commit_msg>lxc/action: Fix pause<commit_after>package main

import (
	"fmt"
	"os"
	"strings"

	"github.com/spf13/cobra"

	"github.com/lxc/lxd/lxc/config"
	"github.com/lxc/lxd/lxc/utils"
	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/api"
	cli "github.com/lxc/lxd/shared/cmd"
	"github.com/lxc/lxd/shared/i18n"
)

// Start
type cmdStart struct {
	global *cmdGlobal
	action *cmdAction
}

func (c *cmdStart) Command() *cobra.Command {
	cmdAction := cmdAction{global: c.global}
	c.action = &cmdAction

	cmd := c.action.Command("start")
	cmd.Use = i18n.G("start [<remote>:]<container> [[<remote>:]<container>...]")
	cmd.Short = i18n.G("Start containers")
	cmd.Long = cli.FormatSection(i18n.G("Description"), i18n.G(
		`Start containers`))

	return cmd
}

// Pause
type cmdPause struct {
	global *cmdGlobal
	action *cmdAction
}

func (c *cmdPause) Command() *cobra.Command {
	cmdAction := cmdAction{global: c.global}
	c.action = &cmdAction

	cmd := c.action.Command("pause")
	cmd.Use = i18n.G("pause [<remote>:]<container> [[<remote>:]<container>...]")
	cmd.Short = i18n.G("Pause containers")
	cmd.Long = cli.FormatSection(i18n.G("Description"), i18n.G(
		`Pause containers`))
	cmd.Hidden = true

	return cmd
}

// Restart
type cmdRestart struct {
	global *cmdGlobal
	action *cmdAction
}

func (c *cmdRestart) Command() *cobra.Command {
	cmdAction := cmdAction{global: c.global}
	c.action = &cmdAction

	cmd := c.action.Command("restart")
	cmd.Use = i18n.G("restart [<remote>:]<container> [[<remote>:]<container>...]")
	cmd.Short = i18n.G("Restart containers")
	cmd.Long = cli.FormatSection(i18n.G("Description"), i18n.G(
		`Restart containers

The opposite of "lxc pause" is "lxc start".`))

	return cmd
}

// Stop
type cmdStop struct {
	global *cmdGlobal
	action *cmdAction
}

func (c *cmdStop) Command() *cobra.Command {
	cmdAction := cmdAction{global: c.global}
	c.action = &cmdAction

	cmd := c.action.Command("stop")
	cmd.Use = i18n.G("stop [<remote>:]<container> [[<remote>:]<container>...]")
	cmd.Short = i18n.G("Stop containers")
	cmd.Long = cli.FormatSection(i18n.G("Description"), i18n.G(
		`Stop containers`))

	return cmd
}

type cmdAction struct {
	global *cmdGlobal

	flagAll       bool
	flagForce     bool
	flagStateful  bool
	flagStateless bool
	flagTimeout   int
}

func (c *cmdAction) Command(action string) *cobra.Command {
	cmd := &cobra.Command{}
	cmd.RunE = c.Run

	cmd.Flags().BoolVar(&c.flagAll, "all", false, i18n.G("Run command against all containers"))

	if action == "stop" {
		cmd.Flags().BoolVar(&c.flagStateful, "stateful", false, i18n.G("Store the container state"))
	} else if action == "start" {
		cmd.Flags().BoolVar(&c.flagStateless, "stateless", false, i18n.G("Ignore the container state"))
	}

	if shared.StringInSlice(action, []string{"restart", "stop"}) {
		cmd.Flags().BoolVarP(&c.flagForce, "force", "f", false, i18n.G("Force the container to shutdown"))
		cmd.Flags().IntVar(&c.flagTimeout, "timeout", -1, i18n.G("Time to wait for the container before killing it")+"``")
	}

	return cmd
}

func (c *cmdAction) doAction(action string, conf *config.Config, nameArg string) error {
	state := false

	// Pause is called freeze
	if action == "pause" {
		action = "freeze"
	}

	// Only store state if asked to
	if action == "stop" && c.flagStateful {
		state = true
	}

	remote, name, err := conf.ParseRemote(nameArg)
	if err != nil {
		return err
	}

	d, err := conf.GetContainerServer(remote)
	if err != nil {
		return err
	}

	if name == "" {
		return fmt.Errorf(i18n.G("Must supply container name for: ")+"\"%s\"", nameArg)
	}

	if action == "start" {
		current, _, err := d.GetContainer(name)
		if err != nil {
			return err
		}

		// "start" for a frozen container means "unfreeze"
		if current.StatusCode == api.Frozen {
			action = "unfreeze"
		}

		// Always restore state (if present) unless asked not to
		if action == "start" && current.Stateful && !c.flagStateless {
			state = true
		}
	}

	req := api.ContainerStatePut{
		Action:   action,
		Timeout:  c.flagTimeout,
		Force:    c.flagForce,
		Stateful: state,
	}

	op, err := d.UpdateContainerState(name, req, "")
	if err != nil {
		return err
	}

	progress := utils.ProgressRenderer{}
	_, err = op.AddHandler(progress.UpdateOp)
	if err != nil {
		progress.Done("")
		return err
	}

	err = op.Wait()
	progress.Done("")
	if err != nil {
		return fmt.Errorf("%s\n"+i18n.G("Try `lxc info --show-log %s` for more info"), err, nameArg)
	}

	return nil
}

func (c *cmdAction) Run(cmd *cobra.Command, args []string) error {
	conf := c.global.conf

	var names []string
	if len(args) == 0 {
		if !c.flagAll {
			cmd.Help()
			return nil
		}

		d, err := conf.GetContainerServer(conf.DefaultRemote)
		if err != nil {
			return err
		}

		ctslist, err := d.GetContainers()
		if err != nil {
			return err
		}

		for _, ct := range ctslist {
			names = append(names, ct.Name)
		}
	} else {
		if c.flagAll {
			return fmt.Errorf(i18n.G("Both --all and container name given"))
		}
		names = args
	}

	// Run the action for every listed container
	results := runBatch(names, func(name string) error { return c.doAction(cmd.Name(), conf, name) })

	// Single container is easy
	if len(results) == 1 {
		return results[0].err
	}

	// Do fancier rendering for batches
	success := true

	for _, result := range results {
		if result.err == nil {
			continue
		}

		success = false
		msg := fmt.Sprintf(i18n.G("error: %v"), result.err)
		for _, line := range strings.Split(msg, "\n") {
			fmt.Fprintln(os.Stderr, fmt.Sprintf("%s: %s", result.name, line))
		}
	}

	if !success {
		fmt.Fprintln(os.Stderr, "")
		return fmt.Errorf(i18n.G("Some containers failed to %s"), cmd.Name())
	}

	return nil
}
<|endoftext|>


<commit_before>/*
ProxyCache - universal cache filling algorithm

Idea

Instead of trying to making cache lookups and determining if you should perform some expensive
calculation, you pass calculation fetcher as a delegate into ProxyCache which will figure out
caching state by itself and use fetcher if necessary.

Parameters

Algorithm considers various parameters that might affect caching behavior: item expiration,
ttl (specified per-request), request timeout, throttle time between fetcher calls, results
of validation (preformed by validator func).
*/
package pcache

import (
	"errors"
	"reflect"
	"time"
)

type Fetcher func() (interface{}, error)
type Validator func(interface{}) bool

// Storage backend is assumed to implement some kind of cache replacement algorithm
type Store interface {
	Get(string, interface{}) (bool, *time.Time, *time.Time) // (key, target) -> (retrieved, creation_time, last_fetch_time)
	Set(string, interface{}, time.Duration) error           // (key, item, expire) -> error
}

type Locker interface {
	IsLocked(string) bool
	AcquireLock(string, time.Duration) Lock // (key, timeout) -> Lock
	WaitForRelease(string) bool             // key -> was_released
}

type Lock interface {
	Release()
}

type ResourceSpec struct {
	Store                          Store
	Locker                         Locker
	Validator                      Validator
	Expire, Ttl, Throttle, Timeout time.Duration
}

func ProxyCache(key string, target interface{}, fetcher Fetcher, spec *ResourceSpec) error {
	var expire time.Duration
	if spec.Expire > 0 {
		expire = spec.Expire
	} else {
		expire = -1
	}

	var getAfterRelease = func() bool {
		done_ch := make(chan bool, 1)
		go func() {
			done_ch <- spec.Locker.WaitForRelease(key)
		}()
		select {
		case <-time.After(spec.Timeout):
			return false
		case ok := <-done_ch:
			if ok {
				retrieved, _, _ := spec.Store.Get(key, target)
				return retrieved // TODO: optimize
			}
			return false
		}
	}
	var fetchAndSet = func() chan interface{} {
		ch := make(chan interface{}, 1)
		go func() {
			lock := spec.Locker.AcquireLock(key, spec.Timeout)
			if lock == nil {
				ch <- getAfterRelease()
				return
			}
			defer lock.Release()
			item, _ := fetcher()
			if spec.Validator(item) == true {
				ch <- item
				spec.Store.Set(key, item, expire)
			} else {
				ch <- nil
			}
		}()
		return ch
	}

	retrieved, creationTime, lastFetchTime := spec.Store.Get(key, target)

	switch {

	case retrieved:
		var invalid = false
		if spec.Validator != nil {
			invalid = spec.Validator(target) == false
		}
		if creationTime != nil || invalid {
			var now = time.Now()
			var age = now.Sub(*creationTime)
			var sinceLastFetch = now.Sub(*lastFetchTime)
			if age > spec.Ttl || invalid {
				if sinceLastFetch > spec.Throttle {
					go func() {
						<-fetchAndSet()
					}()
				}
			}
		}
		if invalid {
			return errors.New("invalid item retrieved")
		}
		return nil

	case spec.Locker.IsLocked(key):
		if getAfterRelease() {
			return nil
		} else {
			return errors.New("getAfterRelease not ok")
		}

	default:
		if lastFetchTime != nil {
			var sinceLastFetch = time.Now().Sub(*lastFetchTime)
			if sinceLastFetch < spec.Throttle {
				return errors.New("refresh throttled while item is nil")
			}
		}
		select {
		case result := <-fetchAndSet():
			if result == nil {
				return errors.New("invalid item fetched")
			}
			return copyValue(target, result)
		case <-time.After(spec.Timeout):
			return errors.New("timeout")
		}

	}
}

func copyValue(destination, source interface{}) error {
	var tgt, val reflect.Value
	tgt = reflect.Indirect(reflect.ValueOf(destination))
	val = reflect.ValueOf(source)
	if val.Type() == tgt.Type() {
		tgt.Set(val)
	} else {
		val = reflect.Indirect(val)
		if val.Type() == tgt.Type() {
			tgt.Set(val)
		}
	}
	return nil
}
<commit_msg>fix validator bug<commit_after>/*
ProxyCache - universal cache filling algorithm

Idea

Instead of trying to making cache lookups and determining if you should perform some expensive
calculation, you pass calculation fetcher as a delegate into ProxyCache which will figure out
caching state by itself and use fetcher if necessary.

Parameters

Algorithm considers various parameters that might affect caching behavior: item expiration,
ttl (specified per-request), request timeout, throttle time between fetcher calls, results
of validation (preformed by validator func).
*/
package pcache

import (
	"errors"
	"reflect"
	"time"
)

type Fetcher func() (interface{}, error)
type Validator func(interface{}) bool

// Storage backend is assumed to implement some kind of cache replacement algorithm
type Store interface {
	Get(string, interface{}) (bool, *time.Time, *time.Time) // (key, target) -> (retrieved, creation_time, last_fetch_time)
	Set(string, interface{}, time.Duration) error           // (key, item, expire) -> error
}

type Locker interface {
	IsLocked(string) bool
	AcquireLock(string, time.Duration) Lock // (key, timeout) -> Lock
	WaitForRelease(string) bool             // key -> was_released
}

type Lock interface {
	Release()
}

type ResourceSpec struct {
	Store                          Store
	Locker                         Locker
	Validator                      Validator
	Expire, Ttl, Throttle, Timeout time.Duration
}

func ProxyCache(key string, target interface{}, fetcher Fetcher, spec *ResourceSpec) error {
	var expire time.Duration
	if spec.Expire > 0 {
		expire = spec.Expire
	} else {
		expire = -1
	}

	var getAfterRelease = func() bool {
		done_ch := make(chan bool, 1)
		go func() {
			done_ch <- spec.Locker.WaitForRelease(key)
		}()
		select {
		case <-time.After(spec.Timeout):
			return false
		case ok := <-done_ch:
			if ok {
				retrieved, _, _ := spec.Store.Get(key, target)
				return retrieved // TODO: optimize
			}
			return false
		}
	}
	var fetchAndSet = func() chan interface{} {
		ch := make(chan interface{}, 1)
		go func() {
			lock := spec.Locker.AcquireLock(key, spec.Timeout)
			if lock == nil {
				ch <- getAfterRelease()
				return
			}
			defer lock.Release()
			item, _ := fetcher()
			if spec.Validator == nil || spec.Validator(item) == true {
				ch <- item
				spec.Store.Set(key, item, expire)
			} else {
				ch <- nil
			}
		}()
		return ch
	}

	retrieved, creationTime, lastFetchTime := spec.Store.Get(key, target)

	switch {

	case retrieved:
		var invalid = false
		if spec.Validator != nil {
			invalid = spec.Validator(target) == false
		}
		if creationTime != nil || invalid {
			var now = time.Now()
			var age = now.Sub(*creationTime)
			var sinceLastFetch = now.Sub(*lastFetchTime)
			if age > spec.Ttl || invalid {
				if sinceLastFetch > spec.Throttle {
					go func() {
						<-fetchAndSet()
					}()
				}
			}
		}
		if invalid {
			return errors.New("invalid item retrieved")
		}
		return nil

	case spec.Locker.IsLocked(key):
		if getAfterRelease() {
			return nil
		} else {
			return errors.New("getAfterRelease not ok")
		}

	default:
		if lastFetchTime != nil {
			var sinceLastFetch = time.Now().Sub(*lastFetchTime)
			if sinceLastFetch < spec.Throttle {
				return errors.New("refresh throttled while item is nil")
			}
		}
		select {
		case result := <-fetchAndSet():
			if result == nil {
				return errors.New("invalid item fetched")
			}
			return copyValue(target, result)
		case <-time.After(spec.Timeout):
			return errors.New("timeout")
		}

	}
}

func copyValue(destination, source interface{}) error {
	var tgt, val reflect.Value
	tgt = reflect.Indirect(reflect.ValueOf(destination))
	val = reflect.ValueOf(source)
	if val.Type() == tgt.Type() {
		tgt.Set(val)
	} else {
		val = reflect.Indirect(val)
		if val.Type() == tgt.Type() {
			tgt.Set(val)
		}
	}
	return nil
}
<|endoftext|>