<commit_before>package server

import (
	"crypto/tls"
	"errors"
	"io"
	"net"
	"sync"
	"time"

	"github.com/emersion/go-imap"
	"github.com/emersion/go-imap/backend"
)

// Conn is a connection to a client.
type Conn interface {
	io.Reader

	// Server returns this connection's server.
	Server() *Server
	// Context returns this connection's context.
	Context() *Context
	// Capabilities returns a list of capabilities enabled for this connection.
	Capabilities() []string
	// WriteResp writes a response to this connection.
	WriteResp(res imap.WriterTo) error
	// IsTLS returns true if TLS is enabled.
	IsTLS() bool
	// TLSState returns the TLS connection state if TLS is enabled, nil otherwise.
	TLSState() *tls.ConnectionState
	// Upgrade upgrades a connection, e.g. wrap an unencrypted connection with an
	// encrypted tunnel.
	Upgrade(upgrader imap.ConnUpgrader) error
	// Close closes this connection.
	Close() error

	setTLSConn(*tls.Conn)
	silent() *bool // TODO: remove this
	serve(Conn) error
	commandHandler(cmd *imap.Command) (hdlr Handler, err error)
}

// Context stores a connection's metadata.
type Context struct {
	// This connection's current state.
	State imap.ConnState
	// If the client is logged in, the user.
	User backend.User
	// If the client has selected a mailbox, the mailbox.
	Mailbox backend.Mailbox
	// True if the currently selected mailbox has been opened in read-only mode.
	MailboxReadOnly bool
	// Responses to send to the client.
	Responses chan<- imap.WriterTo
	// Closed when the client is logged out.
	LoggedOut <-chan struct{}
}

type conn struct {
	*imap.Conn

	conn      Conn // With extensions overrides
	s         *Server
	ctx       *Context
	l         sync.Locker
	tlsConn   *tls.Conn
	continues chan bool
	responses chan imap.WriterTo
	loggedOut chan struct{}
	silentVal bool
}

func newConn(s *Server, c net.Conn) *conn {
	// Create an imap.Reader and an imap.Writer
	continues := make(chan bool)
	r := imap.NewServerReader(nil, continues)
	w := imap.NewWriter(nil)

	responses := make(chan imap.WriterTo)
	loggedOut := make(chan struct{})

	tlsConn, _ := c.(*tls.Conn)

	conn := &conn{
		Conn: imap.NewConn(c, r, w),

		s: s,
		l: &sync.Mutex{},
		ctx: &Context{
			State:     imap.ConnectingState,
			Responses: responses,
			LoggedOut: loggedOut,
		},
		tlsConn:   tlsConn,
		continues: continues,
		responses: responses,
		loggedOut: loggedOut,
	}

	if s.Debug != nil {
		conn.Conn.SetDebug(s.Debug)
	}
	if s.MaxLiteralSize > 0 {
		conn.Conn.MaxLiteralSize = s.MaxLiteralSize
	}

	conn.l.Lock()
	go conn.send()

	return conn
}

func (c *conn) Server() *Server {
	return c.s
}

func (c *conn) Context() *Context {
	return c.ctx
}

type response struct {
	response imap.WriterTo
	done     chan struct{}
}

func (r *response) WriteTo(w *imap.Writer) error {
	err := r.response.WriteTo(w)
	close(r.done)
	return err
}

func (c *conn) setDeadline() {
	if c.s.AutoLogout == 0 {
		return
	}

	dur := c.s.AutoLogout
	if dur < MinAutoLogout {
		dur = MinAutoLogout
	}
	t := time.Now().Add(dur)

	c.Conn.SetDeadline(t)
}

func (c *conn) WriteResp(r imap.WriterTo) error {
	done := make(chan struct{})
	c.responses <- &response{r, done}
	<-done
	c.setDeadline()
	return nil
}

func (c *conn) Close() error {
	if c.ctx.User != nil {
		c.ctx.User.Logout()
	}

	return c.Conn.Close()
}

func (c *conn) Capabilities() []string {
	caps := []string{"IMAP4rev1"}

	if c.ctx.State == imap.NotAuthenticatedState {
		if !c.IsTLS() && c.s.TLSConfig != nil {
			caps = append(caps, "STARTTLS")
		}

		if !c.canAuth() {
			caps = append(caps, "LOGINDISABLED")
		} else {
			for name := range c.s.auths {
				caps = append(caps, "AUTH="+name)
			}
		}
	}

	for _, ext := range c.s.extensions {
		caps = append(caps, ext.Capabilities(c)...)
	}

	return caps
}

func (c *conn) send() {
	// Send continuation requests
	go func() {
		for range c.continues {
			resp := &imap.ContinuationReq{Info: "send literal"}
			if err := resp.WriteTo(c.Writer); err != nil {
				c.Server().ErrorLog.Println("cannot send continuation request: ", err)
			} else if err := c.Writer.Flush(); err != nil {
				c.Server().ErrorLog.Println("cannot flush connection: ", err)
			}
		}
	}()

	// Send responses
	for {
		// Get a response that needs to be sent
		select {
		case res := <-c.responses:
			// Request to send the response
			c.l.Lock()

			// Send the response
			if err := res.WriteTo(c.Writer); err != nil {
				c.Server().ErrorLog.Println("cannot send response: ", err)
			} else if err := c.Writer.Flush(); err != nil {
				c.Server().ErrorLog.Println("cannot flush connection: ", err)
			}

			c.l.Unlock()
		case <-c.loggedOut:
			return
		}
	}
}

func (c *conn) greet() error {
	c.ctx.State = imap.NotAuthenticatedState

	caps := c.Capabilities()
	args := make([]interface{}, len(caps))
	for i, cap := range caps {
		args[i] = cap
	}

	greeting := &imap.StatusResp{
		Type:      imap.StatusRespOk,
		Code:      imap.CodeCapability,
		Arguments: args,
		Info:      "IMAP4rev1 Service Ready",
	}

	c.l.Unlock()
	defer c.l.Lock()

	return c.WriteResp(greeting)
}

func (c *conn) setTLSConn(tlsConn *tls.Conn) {
	c.tlsConn = tlsConn
}

func (c *conn) IsTLS() bool {
	return c.tlsConn != nil
}

func (c *conn) TLSState() *tls.ConnectionState {
	if c.tlsConn != nil {
		state := c.tlsConn.ConnectionState()
		return &state
	}
	return nil
}

// canAuth checks if the client can use plain text authentication.
func (c *conn) canAuth() bool {
	return c.IsTLS() || c.s.AllowInsecureAuth
}

func (c *conn) silent() *bool {
	return &c.silentVal
}

func (c *conn) serve(conn Conn) error {
	c.conn = conn

	defer func() {
		c.ctx.State = imap.LogoutState
		close(c.continues)
		close(c.loggedOut)
	}()

	// Send greeting
	if err := c.greet(); err != nil {
		return err
	}

	for {
		if c.ctx.State == imap.LogoutState {
			return nil
		}

		var res *imap.StatusResp
		var up Upgrader

		c.Wait()
		fields, err := c.ReadLine()
		if err == io.EOF || c.ctx.State == imap.LogoutState {
			return nil
		}
		c.setDeadline()

		if err != nil {
			if imap.IsParseError(err) {
				res = &imap.StatusResp{
					Type: imap.StatusRespBad,
					Info: err.Error(),
				}
			} else {
				c.s.ErrorLog.Println("cannot read command:", err)
				return err
			}
		} else {
			cmd := &imap.Command{}
			if err := cmd.Parse(fields); err != nil {
				res = &imap.StatusResp{
					Tag:  cmd.Tag,
					Type: imap.StatusRespBad,
					Info: err.Error(),
				}
			} else {
				var err error
				res, up, err = c.handleCommand(cmd)
				if err != nil {
					res = &imap.StatusResp{
						Tag:  cmd.Tag,
						Type: imap.StatusRespBad,
						Info: err.Error(),
					}
				}
			}
		}

		if res != nil {
			c.l.Unlock()

			if err := c.WriteResp(res); err != nil {
				c.s.ErrorLog.Println("cannot write response:", err)
				c.l.Lock()
				continue
			}

			if up != nil && res.Type == imap.StatusRespOk {
				if err := up.Upgrade(c.conn); err != nil {
					c.s.ErrorLog.Println("cannot upgrade connection:", err)
					return err
				}
			}

			c.l.Lock()
		}
	}
}

func (c *conn) commandHandler(cmd *imap.Command) (hdlr Handler, err error) {
	newHandler := c.s.Command(cmd.Name)
	if newHandler == nil {
		err = errors.New("Unknown command")
		return
	}

	hdlr = newHandler()
	err = hdlr.Parse(cmd.Arguments)
	return
}

func (c *conn) handleCommand(cmd *imap.Command) (res *imap.StatusResp, up Upgrader, err error) {
	hdlr, err := c.commandHandler(cmd)
	if err != nil {
		return
	}

	c.l.Unlock()
	defer c.l.Lock()

	hdlrErr := hdlr.Handle(c.conn)
	if statusErr, ok := hdlrErr.(*errStatusResp); ok {
		res = statusErr.resp
	} else if hdlrErr != nil {
		res = &imap.StatusResp{
			Type: imap.StatusRespNo,
			Info: hdlrErr.Error(),
		}
	} else {
		res = &imap.StatusResp{
			Type: imap.StatusRespOk,
		}
	}

	if res != nil {
		res.Tag = cmd.Tag

		if res.Type == imap.StatusRespOk && res.Info == "" {
			res.Info = cmd.Name + " completed"
		}
	}

	up, _ = hdlr.(Upgrader)
	return
}
<commit_msg>Fix data race with server continuation requests<commit_after>package server

import (
	"crypto/tls"
	"errors"
	"io"
	"net"
	"time"

	"github.com/emersion/go-imap"
	"github.com/emersion/go-imap/backend"
)

// Conn is a connection to a client.
type Conn interface {
	io.Reader

	// Server returns this connection's server.
	Server() *Server
	// Context returns this connection's context.
	Context() *Context
	// Capabilities returns a list of capabilities enabled for this connection.
	Capabilities() []string
	// WriteResp writes a response to this connection.
	WriteResp(res imap.WriterTo) error
	// IsTLS returns true if TLS is enabled.
	IsTLS() bool
	// TLSState returns the TLS connection state if TLS is enabled, nil otherwise.
	TLSState() *tls.ConnectionState
	// Upgrade upgrades a connection, e.g. wrap an unencrypted connection with an
	// encrypted tunnel.
	Upgrade(upgrader imap.ConnUpgrader) error
	// Close closes this connection.
	Close() error

	setTLSConn(*tls.Conn)
	silent() *bool // TODO: remove this
	serve(Conn) error
	commandHandler(cmd *imap.Command) (hdlr Handler, err error)
}

// Context stores a connection's metadata.
type Context struct {
	// This connection's current state.
	State imap.ConnState
	// If the client is logged in, the user.
	User backend.User
	// If the client has selected a mailbox, the mailbox.
	Mailbox backend.Mailbox
	// True if the currently selected mailbox has been opened in read-only mode.
	MailboxReadOnly bool
	// Responses to send to the client.
	Responses chan<- imap.WriterTo
	// Closed when the client is logged out.
	LoggedOut <-chan struct{}
}

type conn struct {
	*imap.Conn

	conn      Conn // With extensions overrides
	s         *Server
	ctx       *Context
	tlsConn   *tls.Conn
	continues chan bool
	responses chan imap.WriterTo
	loggedOut chan struct{}
	silentVal bool
}

func newConn(s *Server, c net.Conn) *conn {
	// Create an imap.Reader and an imap.Writer
	continues := make(chan bool)
	r := imap.NewServerReader(nil, continues)
	w := imap.NewWriter(nil)

	responses := make(chan imap.WriterTo)
	loggedOut := make(chan struct{})

	tlsConn, _ := c.(*tls.Conn)

	conn := &conn{
		Conn: imap.NewConn(c, r, w),

		s: s,
		ctx: &Context{
			State:     imap.ConnectingState,
			Responses: responses,
			LoggedOut: loggedOut,
		},
		tlsConn:   tlsConn,
		continues: continues,
		responses: responses,
		loggedOut: loggedOut,
	}

	if s.Debug != nil {
		conn.Conn.SetDebug(s.Debug)
	}
	if s.MaxLiteralSize > 0 {
		conn.Conn.MaxLiteralSize = s.MaxLiteralSize
	}

	go conn.send()

	return conn
}

func (c *conn) Server() *Server {
	return c.s
}

func (c *conn) Context() *Context {
	return c.ctx
}

type response struct {
	response imap.WriterTo
	done     chan struct{}
}

func (r *response) WriteTo(w *imap.Writer) error {
	err := r.response.WriteTo(w)
	close(r.done)
	return err
}

func (c *conn) setDeadline() {
	if c.s.AutoLogout == 0 {
		return
	}

	dur := c.s.AutoLogout
	if dur < MinAutoLogout {
		dur = MinAutoLogout
	}
	t := time.Now().Add(dur)

	c.Conn.SetDeadline(t)
}

func (c *conn) WriteResp(r imap.WriterTo) error {
	done := make(chan struct{})
	c.responses <- &response{r, done}
	<-done
	c.setDeadline()
	return nil
}

func (c *conn) Close() error {
	if c.ctx.User != nil {
		c.ctx.User.Logout()
	}

	return c.Conn.Close()
}

func (c *conn) Capabilities() []string {
	caps := []string{"IMAP4rev1"}

	if c.ctx.State == imap.NotAuthenticatedState {
		if !c.IsTLS() && c.s.TLSConfig != nil {
			caps = append(caps, "STARTTLS")
		}

		if !c.canAuth() {
			caps = append(caps, "LOGINDISABLED")
		} else {
			for name := range c.s.auths {
				caps = append(caps, "AUTH="+name)
			}
		}
	}

	for _, ext := range c.s.extensions {
		caps = append(caps, ext.Capabilities(c)...)
	}

	return caps
}

func (c *conn) writeAndFlush(w imap.WriterTo) error {
	if err := w.WriteTo(c.Writer); err != nil {
		return err
	}
	return c.Writer.Flush()
}

func (c *conn) send() {
	// Send responses
	for {
		select {
		case needCont := <-c.continues:
			// Send continuation requests
			if needCont {
				resp := &imap.ContinuationReq{Info: "send literal"}
				if err := c.writeAndFlush(resp); err != nil {
					c.Server().ErrorLog.Println("cannot send continuation request: ", err)
				}
			}
		case res := <-c.responses:
			// Got a response that needs to be sent
			// Request to send the response
			if err := c.writeAndFlush(res); err != nil {
				c.Server().ErrorLog.Println("cannot send response: ", err)
			}
		case <-c.loggedOut:
			return
		}
	}
}

func (c *conn) greet() error {
	c.ctx.State = imap.NotAuthenticatedState

	caps := c.Capabilities()
	args := make([]interface{}, len(caps))
	for i, cap := range caps {
		args[i] = cap
	}

	greeting := &imap.StatusResp{
		Type:      imap.StatusRespOk,
		Code:      imap.CodeCapability,
		Arguments: args,
		Info:      "IMAP4rev1 Service Ready",
	}

	return c.WriteResp(greeting)
}

func (c *conn) setTLSConn(tlsConn *tls.Conn) {
	c.tlsConn = tlsConn
}

func (c *conn) IsTLS() bool {
	return c.tlsConn != nil
}

func (c *conn) TLSState() *tls.ConnectionState {
	if c.tlsConn != nil {
		state := c.tlsConn.ConnectionState()
		return &state
	}
	return nil
}

// canAuth checks if the client can use plain text authentication.
func (c *conn) canAuth() bool {
	return c.IsTLS() || c.s.AllowInsecureAuth
}

func (c *conn) silent() *bool {
	return &c.silentVal
}

func (c *conn) serve(conn Conn) error {
	c.conn = conn

	defer func() {
		c.ctx.State = imap.LogoutState
		close(c.loggedOut)
	}()

	// Send greeting
	if err := c.greet(); err != nil {
		return err
	}

	for {
		if c.ctx.State == imap.LogoutState {
			return nil
		}

		var res *imap.StatusResp
		var up Upgrader

		c.Wait()
		fields, err := c.ReadLine()
		if err == io.EOF || c.ctx.State == imap.LogoutState {
			return nil
		}
		c.setDeadline()

		if err != nil {
			if imap.IsParseError(err) {
				res = &imap.StatusResp{
					Type: imap.StatusRespBad,
					Info: err.Error(),
				}
			} else {
				c.s.ErrorLog.Println("cannot read command:", err)
				return err
			}
		} else {
			cmd := &imap.Command{}
			if err := cmd.Parse(fields); err != nil {
				res = &imap.StatusResp{
					Tag:  cmd.Tag,
					Type: imap.StatusRespBad,
					Info: err.Error(),
				}
			} else {
				var err error
				res, up, err = c.handleCommand(cmd)
				if err != nil {
					res = &imap.StatusResp{
						Tag:  cmd.Tag,
						Type: imap.StatusRespBad,
						Info: err.Error(),
					}
				}
			}
		}

		if res != nil {

			if err := c.WriteResp(res); err != nil {
				c.s.ErrorLog.Println("cannot write response:", err)
				continue
			}

			if up != nil && res.Type == imap.StatusRespOk {
				if err := up.Upgrade(c.conn); err != nil {
					c.s.ErrorLog.Println("cannot upgrade connection:", err)
					return err
				}
			}
		}
	}
}

func (c *conn) commandHandler(cmd *imap.Command) (hdlr Handler, err error) {
	newHandler := c.s.Command(cmd.Name)
	if newHandler == nil {
		err = errors.New("Unknown command")
		return
	}

	hdlr = newHandler()
	err = hdlr.Parse(cmd.Arguments)
	return
}

func (c *conn) handleCommand(cmd *imap.Command) (res *imap.StatusResp, up Upgrader, err error) {
	hdlr, err := c.commandHandler(cmd)
	if err != nil {
		return
	}

	hdlrErr := hdlr.Handle(c.conn)
	if statusErr, ok := hdlrErr.(*errStatusResp); ok {
		res = statusErr.resp
	} else if hdlrErr != nil {
		res = &imap.StatusResp{
			Type: imap.StatusRespNo,
			Info: hdlrErr.Error(),
		}
	} else {
		res = &imap.StatusResp{
			Type: imap.StatusRespOk,
		}
	}

	if res != nil {
		res.Tag = cmd.Tag

		if res.Type == imap.StatusRespOk && res.Info == "" {
			res.Info = cmd.Name + " completed"
		}
	}

	up, _ = hdlr.(Upgrader)
	return
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Tekton Authors

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

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

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

package v1alpha1

import (
	"fmt"
	"path/filepath"
	"strings"

	corev1 "k8s.io/api/core/v1"
)

func getSecretEnvVarsAndVolumeMounts(name, mountPath string, secrets []SecretParam) ([]corev1.EnvVar, []corev1.VolumeMount) {
	mountPaths := make(map[string]struct{})
	var (
		envVars           []corev1.EnvVar
		secretVolumeMount []corev1.VolumeMount
	)

	allowedFields := map[string]bool{
		"GOOGLE_APPLICATION_CREDENTIALS": false,
		"BOTO_CONFIG": false,
	}

	for _, secretParam := range secrets {
		if authVar, ok := allowedFields[secretParam.FieldName]; ok && !authVar {
			allowedFields[secretParam.FieldName] = true
			mountPath := filepath.Join(mountPath, secretParam.SecretName)

			envVars = append(envVars, corev1.EnvVar{
				Name:  strings.ToUpper(secretParam.FieldName),
				Value: filepath.Join(mountPath, secretParam.SecretKey),
			})

			if _, ok := mountPaths[mountPath]; !ok {
				secretVolumeMount = append(secretVolumeMount, corev1.VolumeMount{
					Name:      fmt.Sprintf("volume-%s-%s", name, secretParam.SecretName),
					MountPath: mountPath,
				})
				mountPaths[mountPath] = struct{}{}
			}
		}
	}
	return envVars, secretVolumeMount
}
<commit_msg>appease linter<commit_after>/*
Copyright 2019 The Tekton Authors

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

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

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

package v1alpha1

import (
	"fmt"
	"path/filepath"
	"strings"

	corev1 "k8s.io/api/core/v1"
)

func getSecretEnvVarsAndVolumeMounts(name, mountPath string, secrets []SecretParam) ([]corev1.EnvVar, []corev1.VolumeMount) {
	mountPaths := make(map[string]struct{})
	var (
		envVars           []corev1.EnvVar
		secretVolumeMount []corev1.VolumeMount
	)

	allowedFields := map[string]bool{
		"GOOGLE_APPLICATION_CREDENTIALS": false,
		"BOTO_CONFIG":                    false,
	}

	for _, secretParam := range secrets {
		if authVar, ok := allowedFields[secretParam.FieldName]; ok && !authVar {
			allowedFields[secretParam.FieldName] = true
			mountPath := filepath.Join(mountPath, secretParam.SecretName)

			envVars = append(envVars, corev1.EnvVar{
				Name:  strings.ToUpper(secretParam.FieldName),
				Value: filepath.Join(mountPath, secretParam.SecretKey),
			})

			if _, ok := mountPaths[mountPath]; !ok {
				secretVolumeMount = append(secretVolumeMount, corev1.VolumeMount{
					Name:      fmt.Sprintf("volume-%s-%s", name, secretParam.SecretName),
					MountPath: mountPath,
				})
				mountPaths[mountPath] = struct{}{}
			}
		}
	}
	return envVars, secretVolumeMount
}
<|endoftext|>


<commit_before>package healthsyncer

import (
	"time"

	"context"

	"reflect"

	"sort"

	"github.com/pkg/errors"
	"github.com/rancher/norman/condition"
	"github.com/rancher/rancher/pkg/ticker"
	corev1 "github.com/rancher/types/apis/core/v1"
	v3 "github.com/rancher/types/apis/management.cattle.io/v3"
	"github.com/rancher/types/config"
	"github.com/sirupsen/logrus"
	v1 "k8s.io/api/core/v1"
	apierrors "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
)

const (
	syncInterval = 15 * time.Second
)

type ClusterControllerLifecycle interface {
	Stop(cluster *v3.Cluster)
}

type HealthSyncer struct {
	ctx               context.Context
	clusterName       string
	clusterLister     v3.ClusterLister
	clusters          v3.ClusterInterface
	componentStatuses corev1.ComponentStatusInterface
	clusterManager    ClusterControllerLifecycle
}

func Register(ctx context.Context, workload *config.UserContext, clusterManager ClusterControllerLifecycle) {
	h := &HealthSyncer{
		ctx:               ctx,
		clusterName:       workload.ClusterName,
		clusterLister:     workload.Management.Management.Clusters("").Controller().Lister(),
		clusters:          workload.Management.Management.Clusters(""),
		componentStatuses: workload.Core.ComponentStatuses(""),
		clusterManager:    clusterManager,
	}

	go h.syncHealth(ctx, syncInterval)
}

func (h *HealthSyncer) syncHealth(ctx context.Context, syncHealth time.Duration) {
	for range ticker.Context(ctx, syncHealth) {
		err := h.updateClusterHealth()
		if err != nil && !apierrors.IsConflict(err) {
			logrus.Error(err)
		}
	}
}

func (h *HealthSyncer) getComponentStatus(cluster *v3.Cluster) error {
	cses, err := h.componentStatuses.List(metav1.ListOptions{})
	if err != nil {
		return condition.Error("ComponentStatsFetchingFailure", errors.Wrap(err, "Failed to communicate with API server"))
	}
	cluster.Status.ComponentStatuses = []v3.ClusterComponentStatus{}
	for _, cs := range cses.Items {
		clusterCS := convertToClusterComponentStatus(&cs)
		cluster.Status.ComponentStatuses = append(cluster.Status.ComponentStatuses, *clusterCS)
	}
	sort.Slice(cluster.Status.ComponentStatuses, func(i, j int) bool {
		return cluster.Status.ComponentStatuses[i].Name < cluster.Status.ComponentStatuses[j].Name
	})
	return nil
}

func (h *HealthSyncer) updateClusterHealth() error {
	oldCluster, err := h.getCluster()
	if err != nil {
		return err
	}
	cluster := oldCluster.DeepCopy()
	if !v3.ClusterConditionProvisioned.IsTrue(cluster) {
		logrus.Debugf("Skip updating cluster health - cluster [%s] not provisioned yet", h.clusterName)
		return nil
	}

	newObj, err := v3.ClusterConditionReady.Do(cluster, func() (runtime.Object, error) {
		for i := 0; ; i++ {
			err := h.getComponentStatus(cluster)
			if err == nil || i > 2 {
				return cluster, err
			}
			select {
			case <-h.ctx.Done():
				return cluster, err
			case <-time.After(5 * time.Second):
			}
		}
	})

	if err == nil {
		v3.ClusterConditionWaiting.True(newObj)
		v3.ClusterConditionWaiting.Message(newObj, "")
	}

	if !reflect.DeepEqual(oldCluster, newObj) {
		if _, err := h.clusters.Update(newObj.(*v3.Cluster)); err != nil {
			return errors.Wrapf(err, "Failed to update cluster [%s]", cluster.Name)
		}
	}

	// Purposefully not return error.  This is so when the cluster goes unavailable we don't just keep failing
	// which will essentially keep the controller alive forever, instead of shutting down.
	return nil
}

func (h *HealthSyncer) getCluster() (*v3.Cluster, error) {
	return h.clusterLister.Get("", h.clusterName)
}

func convertToClusterComponentStatus(cs *v1.ComponentStatus) *v3.ClusterComponentStatus {
	return &v3.ClusterComponentStatus{
		Name:       cs.Name,
		Conditions: cs.Conditions,
	}
}
<commit_msg>Alternative API check in getComponentStatus for k8s v1.14<commit_after>package healthsyncer

import (
	"time"

	"context"

	"reflect"

	"sort"

	"github.com/pkg/errors"
	"github.com/rancher/norman/condition"
	"github.com/rancher/rancher/pkg/ticker"
	corev1 "github.com/rancher/types/apis/core/v1"
	v3 "github.com/rancher/types/apis/management.cattle.io/v3"
	"github.com/rancher/types/config"
	"github.com/sirupsen/logrus"
	v1 "k8s.io/api/core/v1"
	apierrors "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
)

const (
	syncInterval = 15 * time.Second
)

type ClusterControllerLifecycle interface {
	Stop(cluster *v3.Cluster)
}

type HealthSyncer struct {
	ctx               context.Context
	clusterName       string
	clusterLister     v3.ClusterLister
	clusters          v3.ClusterInterface
	componentStatuses corev1.ComponentStatusInterface
	namespaces        corev1.NamespaceInterface
	clusterManager    ClusterControllerLifecycle
}

func Register(ctx context.Context, workload *config.UserContext, clusterManager ClusterControllerLifecycle) {
	h := &HealthSyncer{
		ctx:               ctx,
		clusterName:       workload.ClusterName,
		clusterLister:     workload.Management.Management.Clusters("").Controller().Lister(),
		clusters:          workload.Management.Management.Clusters(""),
		componentStatuses: workload.Core.ComponentStatuses(""),
		namespaces:        workload.Core.Namespaces(""),
		clusterManager:    clusterManager,
	}

	go h.syncHealth(ctx, syncInterval)
}

func (h *HealthSyncer) syncHealth(ctx context.Context, syncHealth time.Duration) {
	for range ticker.Context(ctx, syncHealth) {
		err := h.updateClusterHealth()
		if err != nil && !apierrors.IsConflict(err) {
			logrus.Error(err)
		}
	}
}

func (h *HealthSyncer) getComponentStatus(cluster *v3.Cluster) error {
	// Prior to k8s v1.14, we only needed to list the ComponentStatuses from the user cluster.
	// As of k8s v1.14, kubeapi returns a successfull ComponentStatuses response even if etcd is not available.
	// To work around this, now we try to get a namespace from the API, even if not found, it means the API is up.
	if _, err := h.namespaces.Get("kube-system", metav1.GetOptions{}); err != nil && !apierrors.IsNotFound(err) {
		return condition.Error("ComponentStatsFetchingFailure", errors.Wrap(err, "Failed to communicate with API server"))
	}

	cses, err := h.componentStatuses.List(metav1.ListOptions{})
	if err != nil {
		return condition.Error("ComponentStatsFetchingFailure", errors.Wrap(err, "Failed to communicate with API server"))
	}
	cluster.Status.ComponentStatuses = []v3.ClusterComponentStatus{}
	for _, cs := range cses.Items {
		clusterCS := convertToClusterComponentStatus(&cs)
		cluster.Status.ComponentStatuses = append(cluster.Status.ComponentStatuses, *clusterCS)
	}
	sort.Slice(cluster.Status.ComponentStatuses, func(i, j int) bool {
		return cluster.Status.ComponentStatuses[i].Name < cluster.Status.ComponentStatuses[j].Name
	})
	return nil
}

func (h *HealthSyncer) updateClusterHealth() error {
	oldCluster, err := h.getCluster()
	if err != nil {
		return err
	}
	cluster := oldCluster.DeepCopy()
	if !v3.ClusterConditionProvisioned.IsTrue(cluster) {
		logrus.Debugf("Skip updating cluster health - cluster [%s] not provisioned yet", h.clusterName)
		return nil
	}

	newObj, err := v3.ClusterConditionReady.Do(cluster, func() (runtime.Object, error) {
		for i := 0; ; i++ {
			err := h.getComponentStatus(cluster)
			if err == nil || i > 2 {
				return cluster, err
			}
			select {
			case <-h.ctx.Done():
				return cluster, err
			case <-time.After(5 * time.Second):
			}
		}
	})

	if err == nil {
		v3.ClusterConditionWaiting.True(newObj)
		v3.ClusterConditionWaiting.Message(newObj, "")
	}

	if !reflect.DeepEqual(oldCluster, newObj) {
		if _, err := h.clusters.Update(newObj.(*v3.Cluster)); err != nil {
			return errors.Wrapf(err, "Failed to update cluster [%s]", cluster.Name)
		}
	}

	// Purposefully not return error.  This is so when the cluster goes unavailable we don't just keep failing
	// which will essentially keep the controller alive forever, instead of shutting down.
	return nil
}

func (h *HealthSyncer) getCluster() (*v3.Cluster, error) {
	return h.clusterLister.Get("", h.clusterName)
}

func convertToClusterComponentStatus(cs *v1.ComponentStatus) *v3.ClusterComponentStatus {
	return &v3.ClusterComponentStatus{
		Name:       cs.Name,
		Conditions: cs.Conditions,
	}
}
<|endoftext|>


<commit_before>package migrations

import . "github.com/grafana/grafana/pkg/services/sqlstore/migrator"

func addDashboardMigration(mg *Migrator) {
	var dashboardV1 = Table{
		Name: "dashboard",
		Columns: []*Column{
			{Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true},
			{Name: "version", Type: DB_Int, Nullable: false},
			{Name: "slug", Type: DB_NVarchar, Length: 189, Nullable: false},
			{Name: "title", Type: DB_NVarchar, Length: 255, Nullable: false},
			{Name: "data", Type: DB_Text, Nullable: false},
			{Name: "account_id", Type: DB_BigInt, Nullable: false},
			{Name: "created", Type: DB_DateTime, Nullable: false},
			{Name: "updated", Type: DB_DateTime, Nullable: false},
		},
		Indices: []*Index{
			{Cols: []string{"account_id"}},
			{Cols: []string{"account_id", "slug"}, Type: UniqueIndex},
		},
	}

	mg.AddMigration("create dashboard table", NewAddTableMigration(dashboardV1))

	//-------  indexes ------------------
	mg.AddMigration("add index dashboard.account_id", NewAddIndexMigration(dashboardV1, dashboardV1.Indices[0]))
	mg.AddMigration("add unique index dashboard_account_id_slug", NewAddIndexMigration(dashboardV1, dashboardV1.Indices[1]))

	dashboardTagV1 := Table{
		Name: "dashboard_tag",
		Columns: []*Column{
			{Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true},
			{Name: "dashboard_id", Type: DB_BigInt, Nullable: false},
			{Name: "term", Type: DB_NVarchar, Length: 50, Nullable: false},
		},
		Indices: []*Index{
			{Cols: []string{"dashboard_id", "term"}, Type: UniqueIndex},
		},
	}

	mg.AddMigration("create dashboard_tag table", NewAddTableMigration(dashboardTagV1))
	mg.AddMigration("add unique index dashboard_tag.dasboard_id_term", NewAddIndexMigration(dashboardTagV1, dashboardTagV1.Indices[0]))

	// ---------------------
	// account -> org changes

	//-------  drop dashboard indexes ------------------
	addDropAllIndicesMigrations(mg, "v1", dashboardTagV1)
	//------- rename table ------------------
	addTableRenameMigration(mg, "dashboard", "dashboard_v1", "v1")

	// dashboard v2
	var dashboardV2 = Table{
		Name: "dashboard",
		Columns: []*Column{
			{Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true},
			{Name: "version", Type: DB_Int, Nullable: false},
			{Name: "slug", Type: DB_NVarchar, Length: 189, Nullable: false},
			{Name: "title", Type: DB_NVarchar, Length: 255, Nullable: false},
			{Name: "data", Type: DB_Text, Nullable: false},
			{Name: "org_id", Type: DB_BigInt, Nullable: false},
			{Name: "created", Type: DB_DateTime, Nullable: false},
			{Name: "updated", Type: DB_DateTime, Nullable: false},
		},
		Indices: []*Index{
			{Cols: []string{"org_id"}},
			{Cols: []string{"org_id", "slug"}, Type: UniqueIndex},
		},
	}

	// recreate table
	mg.AddMigration("create dashboard v2", NewAddTableMigration(dashboardV2))
	// recreate indices
	addTableIndicesMigrations(mg, "v2", dashboardV2)
	// copy data
	mg.AddMigration("copy dashboard v1 to v2", NewCopyTableDataMigration("dashboard", "dashboard_v1", map[string]string{
		"id":      "id",
		"version": "version",
		"slug":    "slug",
		"title":   "title",
		"data":    "data",
		"org_id":  "account_id",
		"created": "created",
		"updated": "updated",
	}))

	mg.AddMigration("drop table dashboard_v1", NewDropTableMigration("dashboard_v1"))

	// change column type of dashboard.data
	mg.AddMigration("alter dashboard.data to mediumtext v1", new(RawSqlMigration).
		Sqlite("SELECT 0 WHERE 0;").
		Postgres("SELECT 0;").
		Mysql("ALTER TABLE dashboard MODIFY data MEDIUMTEXT;"))

	// add column to store updater of a dashboard
	mg.AddMigration("Add column updated_by in dashboard - v2", NewAddColumnMigration(dashboardV2, &Column{
		Name: "updated_by", Type: DB_Int, Nullable: true,
	}))

	// add column to store creator of a dashboard
	mg.AddMigration("Add column created_by in dashboard - v2", NewAddColumnMigration(dashboardV2, &Column{
		Name: "created_by", Type: DB_Int, Nullable: true,
	}))

	// add column to store gnetId
	mg.AddMigration("Add column gnetId in dashboard", NewAddColumnMigration(dashboardV2, &Column{
		Name: "gnet_id", Type: DB_BigInt, Nullable: true,
	}))

	mg.AddMigration("Add index for gnetId in dashboard", NewAddIndexMigration(dashboardV2, &Index{
		Cols: []string{"gnet_id"}, Type: IndexType,
	}))

	// add column to store plugin_id
	mg.AddMigration("Add column plugin_id in dashboard", NewAddColumnMigration(dashboardV2, &Column{
		Name: "plugin_id", Type: DB_NVarchar, Nullable: true, Length: 189,
	}))

	mg.AddMigration("Add index for plugin_id in dashboard", NewAddIndexMigration(dashboardV2, &Index{
		Cols: []string{"org_id", "plugin_id"}, Type: IndexType,
	}))

	// dashboard_id index for dashboard_tag table
	mg.AddMigration("Add index for dashboard_id in dashboard_tag", NewAddIndexMigration(dashboardTagV1, &Index{
		Cols: []string{"dashboard_id"}, Type: IndexType,
	}))

	mg.AddMigration("Update dashboard table charset", NewTableCharsetMigration("dashboard", []*Column{
		{Name: "slug", Type: DB_NVarchar, Length: 189, Nullable: false},
		{Name: "title", Type: DB_NVarchar, Length: 255, Nullable: false},
		{Name: "plugin_id", Type: DB_NVarchar, Nullable: true, Length: 189},
		{Name: "data", Type: DB_MediumText, Nullable: false},
	}))

	mg.AddMigration("Update dashboard_tag table charset", NewTableCharsetMigration("dashboard_tag", []*Column{
		{Name: "term", Type: DB_NVarchar, Length: 50, Nullable: false},
	}))

	// add column to store folder_id for dashboard folder structure
	mg.AddMigration("Add column folder_id in dashboard", NewAddColumnMigration(dashboardV2, &Column{
		Name: "folder_id", Type: DB_BigInt, Nullable: false, Default: "0",
	}))

	mg.AddMigration("Add column isFolder in dashboard", NewAddColumnMigration(dashboardV2, &Column{
		Name: "is_folder", Type: DB_Bool, Nullable: false, Default: "0",
	}))

	// add column to flag if dashboard has an ACL
	mg.AddMigration("Add column has_acl in dashboard", NewAddColumnMigration(dashboardV2, &Column{
		Name: "has_acl", Type: DB_Bool, Nullable: false, Default: "0",
	}))

	// new uid column
	mg.AddMigration("Add column uid in dashboard", NewAddColumnMigration(dashboardV2, &Column{
		Name: "uid", Type: DB_NVarchar, Length: 12, Nullable: true,
	}))

	mg.AddMigration("Set uid column values", new(RawSqlMigration).
		Sqlite("UPDATE dashboard SET uid=printf('%09d',id) WHERE uid IS NULL;").
		Postgres("UPDATE dashboard SET uid=lpad('' || id,9,'0') WHERE uid IS NULL;").
		Mysql("UPDATE dashboard SET uid=lpad(id,9,'0') WHERE uid IS NULL;"))
}
<commit_msg>db: add migrations for creating a unique index for uid. #7883<commit_after>package migrations

import . "github.com/grafana/grafana/pkg/services/sqlstore/migrator"

func addDashboardMigration(mg *Migrator) {
	var dashboardV1 = Table{
		Name: "dashboard",
		Columns: []*Column{
			{Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true},
			{Name: "version", Type: DB_Int, Nullable: false},
			{Name: "slug", Type: DB_NVarchar, Length: 189, Nullable: false},
			{Name: "title", Type: DB_NVarchar, Length: 255, Nullable: false},
			{Name: "data", Type: DB_Text, Nullable: false},
			{Name: "account_id", Type: DB_BigInt, Nullable: false},
			{Name: "created", Type: DB_DateTime, Nullable: false},
			{Name: "updated", Type: DB_DateTime, Nullable: false},
		},
		Indices: []*Index{
			{Cols: []string{"account_id"}},
			{Cols: []string{"account_id", "slug"}, Type: UniqueIndex},
		},
	}

	mg.AddMigration("create dashboard table", NewAddTableMigration(dashboardV1))

	//-------  indexes ------------------
	mg.AddMigration("add index dashboard.account_id", NewAddIndexMigration(dashboardV1, dashboardV1.Indices[0]))
	mg.AddMigration("add unique index dashboard_account_id_slug", NewAddIndexMigration(dashboardV1, dashboardV1.Indices[1]))

	dashboardTagV1 := Table{
		Name: "dashboard_tag",
		Columns: []*Column{
			{Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true},
			{Name: "dashboard_id", Type: DB_BigInt, Nullable: false},
			{Name: "term", Type: DB_NVarchar, Length: 50, Nullable: false},
		},
		Indices: []*Index{
			{Cols: []string{"dashboard_id", "term"}, Type: UniqueIndex},
		},
	}

	mg.AddMigration("create dashboard_tag table", NewAddTableMigration(dashboardTagV1))
	mg.AddMigration("add unique index dashboard_tag.dasboard_id_term", NewAddIndexMigration(dashboardTagV1, dashboardTagV1.Indices[0]))

	// ---------------------
	// account -> org changes

	//-------  drop dashboard indexes ------------------
	addDropAllIndicesMigrations(mg, "v1", dashboardTagV1)
	//------- rename table ------------------
	addTableRenameMigration(mg, "dashboard", "dashboard_v1", "v1")

	// dashboard v2
	var dashboardV2 = Table{
		Name: "dashboard",
		Columns: []*Column{
			{Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true},
			{Name: "version", Type: DB_Int, Nullable: false},
			{Name: "slug", Type: DB_NVarchar, Length: 189, Nullable: false},
			{Name: "title", Type: DB_NVarchar, Length: 255, Nullable: false},
			{Name: "data", Type: DB_Text, Nullable: false},
			{Name: "org_id", Type: DB_BigInt, Nullable: false},
			{Name: "created", Type: DB_DateTime, Nullable: false},
			{Name: "updated", Type: DB_DateTime, Nullable: false},
		},
		Indices: []*Index{
			{Cols: []string{"org_id"}},
			{Cols: []string{"org_id", "slug"}, Type: UniqueIndex},
		},
	}

	// recreate table
	mg.AddMigration("create dashboard v2", NewAddTableMigration(dashboardV2))
	// recreate indices
	addTableIndicesMigrations(mg, "v2", dashboardV2)
	// copy data
	mg.AddMigration("copy dashboard v1 to v2", NewCopyTableDataMigration("dashboard", "dashboard_v1", map[string]string{
		"id":      "id",
		"version": "version",
		"slug":    "slug",
		"title":   "title",
		"data":    "data",
		"org_id":  "account_id",
		"created": "created",
		"updated": "updated",
	}))

	mg.AddMigration("drop table dashboard_v1", NewDropTableMigration("dashboard_v1"))

	// change column type of dashboard.data
	mg.AddMigration("alter dashboard.data to mediumtext v1", new(RawSqlMigration).
		Sqlite("SELECT 0 WHERE 0;").
		Postgres("SELECT 0;").
		Mysql("ALTER TABLE dashboard MODIFY data MEDIUMTEXT;"))

	// add column to store updater of a dashboard
	mg.AddMigration("Add column updated_by in dashboard - v2", NewAddColumnMigration(dashboardV2, &Column{
		Name: "updated_by", Type: DB_Int, Nullable: true,
	}))

	// add column to store creator of a dashboard
	mg.AddMigration("Add column created_by in dashboard - v2", NewAddColumnMigration(dashboardV2, &Column{
		Name: "created_by", Type: DB_Int, Nullable: true,
	}))

	// add column to store gnetId
	mg.AddMigration("Add column gnetId in dashboard", NewAddColumnMigration(dashboardV2, &Column{
		Name: "gnet_id", Type: DB_BigInt, Nullable: true,
	}))

	mg.AddMigration("Add index for gnetId in dashboard", NewAddIndexMigration(dashboardV2, &Index{
		Cols: []string{"gnet_id"}, Type: IndexType,
	}))

	// add column to store plugin_id
	mg.AddMigration("Add column plugin_id in dashboard", NewAddColumnMigration(dashboardV2, &Column{
		Name: "plugin_id", Type: DB_NVarchar, Nullable: true, Length: 189,
	}))

	mg.AddMigration("Add index for plugin_id in dashboard", NewAddIndexMigration(dashboardV2, &Index{
		Cols: []string{"org_id", "plugin_id"}, Type: IndexType,
	}))

	// dashboard_id index for dashboard_tag table
	mg.AddMigration("Add index for dashboard_id in dashboard_tag", NewAddIndexMigration(dashboardTagV1, &Index{
		Cols: []string{"dashboard_id"}, Type: IndexType,
	}))

	mg.AddMigration("Update dashboard table charset", NewTableCharsetMigration("dashboard", []*Column{
		{Name: "slug", Type: DB_NVarchar, Length: 189, Nullable: false},
		{Name: "title", Type: DB_NVarchar, Length: 255, Nullable: false},
		{Name: "plugin_id", Type: DB_NVarchar, Nullable: true, Length: 189},
		{Name: "data", Type: DB_MediumText, Nullable: false},
	}))

	mg.AddMigration("Update dashboard_tag table charset", NewTableCharsetMigration("dashboard_tag", []*Column{
		{Name: "term", Type: DB_NVarchar, Length: 50, Nullable: false},
	}))

	// add column to store folder_id for dashboard folder structure
	mg.AddMigration("Add column folder_id in dashboard", NewAddColumnMigration(dashboardV2, &Column{
		Name: "folder_id", Type: DB_BigInt, Nullable: false, Default: "0",
	}))

	mg.AddMigration("Add column isFolder in dashboard", NewAddColumnMigration(dashboardV2, &Column{
		Name: "is_folder", Type: DB_Bool, Nullable: false, Default: "0",
	}))

	// add column to flag if dashboard has an ACL
	mg.AddMigration("Add column has_acl in dashboard", NewAddColumnMigration(dashboardV2, &Column{
		Name: "has_acl", Type: DB_Bool, Nullable: false, Default: "0",
	}))

	// new uid column
	mg.AddMigration("Add column uid in dashboard", NewAddColumnMigration(dashboardV2, &Column{
		Name: "uid", Type: DB_NVarchar, Length: 12, Nullable: true,
	}))

	mg.AddMigration("Set uid column values", new(RawSqlMigration).
		Sqlite("UPDATE dashboard SET uid=printf('%09d',id) WHERE uid IS NULL;").
		Postgres("UPDATE dashboard SET uid=lpad('' || id,9,'0') WHERE uid IS NULL;").
		Mysql("UPDATE dashboard SET uid=lpad(id,9,'0') WHERE uid IS NULL;"))

	mg.AddMigration("Add index for uid in dashboard", NewAddIndexMigration(dashboardV2, &Index{
		Cols: []string{"uid"}, Type: UniqueIndex,
	}))
}
<|endoftext|>


<commit_before>// Copyright 2019 Google Inc. All Rights Reserved.
// This file is available under the Apache license.

package mtail_test

import (
	"io/ioutil"
	"path"
	"strings"
	"testing"

	"github.com/google/mtail/internal/mtail"
	"github.com/google/mtail/internal/testutil"
)

func TestBadProgramFailsCompilation(t *testing.T) {
	t.Skip("broken, need to handle compile error correctly.")
	testutil.SkipIfShort(t)
	progDir, rmProgDir := testutil.TestTempDir(t)
	defer rmProgDir()
	logDir, rmLogDir := testutil.TestTempDir(t)
	defer rmLogDir()

	err := ioutil.WriteFile(path.Join(progDir, "bad.mtail"), []byte("asdfasdf\n"), 0666)
	testutil.FatalIfErr(t, err)

	// Compile-only fails program compilation at server start, not after it's running.
	_ = mtail.TestMakeServer(t, 0, 0, mtail.ProgramPath(progDir), mtail.LogPathPatterns(logDir), mtail.CompileOnly)
	if err == nil {
		t.Error("expected error from mtail")
	}
	if !strings.Contains(err.Error(), "compile failed") {
		t.Error("compile failed not reported")
	}
}
<commit_msg>Unskip compilation error test.<commit_after>// Copyright 2019 Google Inc. All Rights Reserved.
// This file is available under the Apache license.

package mtail_test

import (
	"context"
	"io/ioutil"
	"path"
	"strings"
	"testing"

	"github.com/google/mtail/internal/metrics"
	"github.com/google/mtail/internal/mtail"
	"github.com/google/mtail/internal/testutil"
)

func TestBadProgramFailsCompilation(t *testing.T) {
	testutil.SkipIfShort(t)
	progDir, rmProgDir := testutil.TestTempDir(t)
	defer rmProgDir()

	err := ioutil.WriteFile(path.Join(progDir, "bad.mtail"), []byte("asdfasdf\n"), 0666)
	testutil.FatalIfErr(t, err)

	ctx := context.Background()
	// Compile-only fails program compilation at server start, not after it's running.
	_, err = mtail.New(ctx, metrics.NewStore(), mtail.ProgramPath(progDir), mtail.CompileOnly)
	if err == nil {
		t.Error("expected error from mtail")
	}
	if !strings.Contains(err.Error(), "compile failed") {
		t.Error("compile failed not reported")
	}
}
<|endoftext|>


<commit_before>// Package boltdbresumer provides a Resumer implementation that uses a Bolt database file as storage.
package boltdbresumer

import (
	"encoding/json"
	"fmt"
	"strconv"
	"time"

	"go.etcd.io/bbolt"
)

// Keys for the persisten storage.
var Keys = struct {
	InfoHash        []byte
	Port            []byte
	Name            []byte
	Trackers        []byte
	URLList         []byte
	FixedPeers      []byte
	Dest            []byte
	Info            []byte
	Bitfield        []byte
	AddedAt         []byte
	BytesDownloaded []byte
	BytesUploaded   []byte
	BytesWasted     []byte
	SeededFor       []byte
	Started         []byte
}{
	InfoHash:        []byte("info_hash"),
	Port:            []byte("port"),
	Name:            []byte("name"),
	Trackers:        []byte("trackers"),
	URLList:         []byte("url_list"),
	FixedPeers:      []byte("fixed_peers"),
	Dest:            []byte("dest"),
	Info:            []byte("info"),
	Bitfield:        []byte("bitfield"),
	AddedAt:         []byte("added_at"),
	BytesDownloaded: []byte("bytes_downloaded"),
	BytesUploaded:   []byte("bytes_uploaded"),
	BytesWasted:     []byte("bytes_wasted"),
	SeededFor:       []byte("seeded_for"),
	Started:         []byte("started"),
}

// Resumer contains methods for saving/loading resume information of a torrent to a BoltDB database.
type Resumer struct {
	db     *bbolt.DB
	bucket []byte
}

// New returns a new Resumer.
func New(db *bbolt.DB, bucket []byte) (*Resumer, error) {
	err := db.Update(func(tx *bbolt.Tx) error {
		_, err2 := tx.CreateBucketIfNotExists(bucket)
		return err2
	})
	if err != nil {
		return nil, err
	}
	return &Resumer{
		db:     db,
		bucket: bucket,
	}, nil
}

// Write the torrent spec for torrent with `torrentID`.
func (r *Resumer) Write(torrentID string, spec *Spec) error {
	port := strconv.Itoa(spec.Port)
	trackers, err := json.Marshal(spec.Trackers)
	if err != nil {
		return err
	}
	urlList, err := json.Marshal(spec.URLList)
	if err != nil {
		return err
	}
	fixedPeers, err := json.Marshal(spec.FixedPeers)
	if err != nil {
		return err
	}
	return r.db.Update(func(tx *bbolt.Tx) error {
		b, err := tx.Bucket(r.bucket).CreateBucketIfNotExists([]byte(torrentID))
		if err != nil {
			return err
		}
		_ = b.Put(Keys.InfoHash, spec.InfoHash)
		_ = b.Put(Keys.Port, []byte(port))
		_ = b.Put(Keys.Name, []byte(spec.Name))
		_ = b.Put(Keys.Trackers, trackers)
		_ = b.Put(Keys.URLList, urlList)
		_ = b.Put(Keys.FixedPeers, fixedPeers)
		_ = b.Put(Keys.Info, spec.Info)
		_ = b.Put(Keys.Bitfield, spec.Bitfield)
		_ = b.Put(Keys.AddedAt, []byte(spec.AddedAt.Format(time.RFC3339)))
		_ = b.Put(Keys.BytesDownloaded, []byte(strconv.FormatInt(spec.BytesDownloaded, 10)))
		_ = b.Put(Keys.BytesUploaded, []byte(strconv.FormatInt(spec.BytesUploaded, 10)))
		_ = b.Put(Keys.BytesWasted, []byte(strconv.FormatInt(spec.BytesWasted, 10)))
		_ = b.Put(Keys.SeededFor, []byte(spec.SeededFor.String()))
		_ = b.Put(Keys.Started, []byte(strconv.FormatBool(spec.Started)))
		return nil
	})
}

// WriteInfo writes only the info dict of a torrent.
func (r *Resumer) WriteInfo(torrentID string, value []byte) error {
	return r.db.Update(func(tx *bbolt.Tx) error {
		b := tx.Bucket(r.bucket).Bucket([]byte(torrentID))
		if b == nil {
			return nil
		}
		return b.Put(Keys.Info, value)
	})
}

// WriteBitfield writes only bitfield of a torrent.
func (r *Resumer) WriteBitfield(torrentID string, value []byte) error {
	return r.db.Update(func(tx *bbolt.Tx) error {
		b := tx.Bucket(r.bucket).Bucket([]byte(torrentID))
		if b == nil {
			return nil
		}
		return b.Put(Keys.Bitfield, value)
	})
}

// WriteStarted writes the start status of a torrent.
func (r *Resumer) WriteStarted(torrentID string, value bool) error {
	return r.db.Update(func(tx *bbolt.Tx) error {
		b := tx.Bucket(r.bucket).Bucket([]byte(torrentID))
		if b == nil {
			return nil
		}
		return b.Put(Keys.Started, []byte(strconv.FormatBool(value)))
	})
}

func (r *Resumer) Read(torrentID string) (spec *Spec, err error) {
	err = r.db.Update(func(tx *bbolt.Tx) error {
		b := tx.Bucket(r.bucket).Bucket([]byte(torrentID))
		if b == nil {
			return fmt.Errorf("bucket not found: %q", torrentID)
		}

		value := b.Get(Keys.InfoHash)
		if value == nil {
			return fmt.Errorf("key not found: %q", string(Keys.InfoHash))
		}

		spec = new(Spec)
		spec.InfoHash = make([]byte, len(value))
		copy(spec.InfoHash, value)

		var err error
		value = b.Get(Keys.Port)
		spec.Port, err = strconv.Atoi(string(value))
		if err != nil {
			return err
		}

		value = b.Get(Keys.Name)
		if value != nil {
			spec.Name = string(value)
		}

		value = b.Get(Keys.Trackers)
		if value != nil {
			err = json.Unmarshal(value, &spec.Trackers)
			if err != nil {
				// Try to unmarshal old format `[]string`
				trackers := make([]string, 0)
				err = json.Unmarshal(value, &trackers)
				if err != nil {
					return err
				}
				// Migrate to new format `[][]string`
				spec.Trackers = make([][]string, len(trackers))
				for i, t := range trackers {
					spec.Trackers[i] = []string{t}
				}
				// Save in new format
				bt, err := json.Marshal(spec.Trackers)
				if err != nil {
					return err
				}
				err = b.Put(Keys.Trackers, bt)
				if err != nil {
					return err
				}
			}
		}

		value = b.Get(Keys.URLList)
		if value != nil {
			err = json.Unmarshal(value, &spec.URLList)
			if err != nil {
				return err
			}
		}

		value = b.Get(Keys.FixedPeers)
		if value != nil {
			err = json.Unmarshal(value, &spec.FixedPeers)
			if err != nil {
				return err
			}
		}

		value = b.Get(Keys.Info)
		if value != nil {
			spec.Info = make([]byte, len(value))
			copy(spec.Info, value)
		}

		value = b.Get(Keys.Bitfield)
		if value != nil {
			spec.Bitfield = make([]byte, len(value))
			copy(spec.Bitfield, value)
		}

		value = b.Get(Keys.AddedAt)
		if value != nil {
			spec.AddedAt, err = time.Parse(time.RFC3339, string(value))
			if err != nil {
				return err
			}
		}

		value = b.Get(Keys.BytesDownloaded)
		if value != nil {
			spec.BytesDownloaded, err = strconv.ParseInt(string(value), 10, 64)
			if err != nil {
				return err
			}
		}

		value = b.Get(Keys.BytesUploaded)
		if value != nil {
			spec.BytesUploaded, err = strconv.ParseInt(string(value), 10, 64)
			if err != nil {
				return err
			}
		}

		value = b.Get(Keys.BytesWasted)
		if value != nil {
			spec.BytesWasted, err = strconv.ParseInt(string(value), 10, 64)
			if err != nil {
				return err
			}
		}

		value = b.Get(Keys.SeededFor)
		if value != nil {
			spec.SeededFor, err = time.ParseDuration(string(value))
			if err != nil {
				return err
			}
		}

		value = b.Get(Keys.Started)
		if value != nil {
			spec.Started, err = strconv.ParseBool(string(value))
			if err != nil {
				return err
			}
		}

		return nil
	})
	return spec, err
}
<commit_msg>skip corrupt torrents in db at startup<commit_after>// Package boltdbresumer provides a Resumer implementation that uses a Bolt database file as storage.
package boltdbresumer

import (
	"encoding/json"
	"fmt"
	"runtime/debug"
	"strconv"
	"time"

	"go.etcd.io/bbolt"
)

// Keys for the persisten storage.
var Keys = struct {
	InfoHash        []byte
	Port            []byte
	Name            []byte
	Trackers        []byte
	URLList         []byte
	FixedPeers      []byte
	Dest            []byte
	Info            []byte
	Bitfield        []byte
	AddedAt         []byte
	BytesDownloaded []byte
	BytesUploaded   []byte
	BytesWasted     []byte
	SeededFor       []byte
	Started         []byte
}{
	InfoHash:        []byte("info_hash"),
	Port:            []byte("port"),
	Name:            []byte("name"),
	Trackers:        []byte("trackers"),
	URLList:         []byte("url_list"),
	FixedPeers:      []byte("fixed_peers"),
	Dest:            []byte("dest"),
	Info:            []byte("info"),
	Bitfield:        []byte("bitfield"),
	AddedAt:         []byte("added_at"),
	BytesDownloaded: []byte("bytes_downloaded"),
	BytesUploaded:   []byte("bytes_uploaded"),
	BytesWasted:     []byte("bytes_wasted"),
	SeededFor:       []byte("seeded_for"),
	Started:         []byte("started"),
}

// Resumer contains methods for saving/loading resume information of a torrent to a BoltDB database.
type Resumer struct {
	db     *bbolt.DB
	bucket []byte
}

// New returns a new Resumer.
func New(db *bbolt.DB, bucket []byte) (*Resumer, error) {
	err := db.Update(func(tx *bbolt.Tx) error {
		_, err2 := tx.CreateBucketIfNotExists(bucket)
		return err2
	})
	if err != nil {
		return nil, err
	}
	return &Resumer{
		db:     db,
		bucket: bucket,
	}, nil
}

// Write the torrent spec for torrent with `torrentID`.
func (r *Resumer) Write(torrentID string, spec *Spec) error {
	port := strconv.Itoa(spec.Port)
	trackers, err := json.Marshal(spec.Trackers)
	if err != nil {
		return err
	}
	urlList, err := json.Marshal(spec.URLList)
	if err != nil {
		return err
	}
	fixedPeers, err := json.Marshal(spec.FixedPeers)
	if err != nil {
		return err
	}
	return r.db.Update(func(tx *bbolt.Tx) error {
		b, err := tx.Bucket(r.bucket).CreateBucketIfNotExists([]byte(torrentID))
		if err != nil {
			return err
		}
		_ = b.Put(Keys.InfoHash, spec.InfoHash)
		_ = b.Put(Keys.Port, []byte(port))
		_ = b.Put(Keys.Name, []byte(spec.Name))
		_ = b.Put(Keys.Trackers, trackers)
		_ = b.Put(Keys.URLList, urlList)
		_ = b.Put(Keys.FixedPeers, fixedPeers)
		_ = b.Put(Keys.Info, spec.Info)
		_ = b.Put(Keys.Bitfield, spec.Bitfield)
		_ = b.Put(Keys.AddedAt, []byte(spec.AddedAt.Format(time.RFC3339)))
		_ = b.Put(Keys.BytesDownloaded, []byte(strconv.FormatInt(spec.BytesDownloaded, 10)))
		_ = b.Put(Keys.BytesUploaded, []byte(strconv.FormatInt(spec.BytesUploaded, 10)))
		_ = b.Put(Keys.BytesWasted, []byte(strconv.FormatInt(spec.BytesWasted, 10)))
		_ = b.Put(Keys.SeededFor, []byte(spec.SeededFor.String()))
		_ = b.Put(Keys.Started, []byte(strconv.FormatBool(spec.Started)))
		return nil
	})
}

// WriteInfo writes only the info dict of a torrent.
func (r *Resumer) WriteInfo(torrentID string, value []byte) error {
	return r.db.Update(func(tx *bbolt.Tx) error {
		b := tx.Bucket(r.bucket).Bucket([]byte(torrentID))
		if b == nil {
			return nil
		}
		return b.Put(Keys.Info, value)
	})
}

// WriteBitfield writes only bitfield of a torrent.
func (r *Resumer) WriteBitfield(torrentID string, value []byte) error {
	return r.db.Update(func(tx *bbolt.Tx) error {
		b := tx.Bucket(r.bucket).Bucket([]byte(torrentID))
		if b == nil {
			return nil
		}
		return b.Put(Keys.Bitfield, value)
	})
}

// WriteStarted writes the start status of a torrent.
func (r *Resumer) WriteStarted(torrentID string, value bool) error {
	return r.db.Update(func(tx *bbolt.Tx) error {
		b := tx.Bucket(r.bucket).Bucket([]byte(torrentID))
		if b == nil {
			return nil
		}
		return b.Put(Keys.Started, []byte(strconv.FormatBool(value)))
	})
}

func (r *Resumer) Read(torrentID string) (spec *Spec, err error) {
	defer debug.SetPanicOnFault(debug.SetPanicOnFault(true))
	defer func() {
		if r := recover(); r != nil {
			err = fmt.Errorf("cannot read torrent %q from db: %s", torrentID, r)
		}
	}()
	err = r.db.Update(func(tx *bbolt.Tx) error {
		b := tx.Bucket(r.bucket).Bucket([]byte(torrentID))
		if b == nil {
			return fmt.Errorf("bucket not found: %q", torrentID)
		}

		value := b.Get(Keys.InfoHash)
		if value == nil {
			return fmt.Errorf("key not found: %q", string(Keys.InfoHash))
		}

		spec = new(Spec)
		spec.InfoHash = make([]byte, len(value))
		copy(spec.InfoHash, value)

		var err error
		value = b.Get(Keys.Port)
		spec.Port, err = strconv.Atoi(string(value))
		if err != nil {
			return err
		}

		value = b.Get(Keys.Name)
		if value != nil {
			spec.Name = string(value)
		}

		value = b.Get(Keys.Trackers)
		if value != nil {
			err = json.Unmarshal(value, &spec.Trackers)
			if err != nil {
				// Try to unmarshal old format `[]string`
				trackers := make([]string, 0)
				err = json.Unmarshal(value, &trackers)
				if err != nil {
					return err
				}
				// Migrate to new format `[][]string`
				spec.Trackers = make([][]string, len(trackers))
				for i, t := range trackers {
					spec.Trackers[i] = []string{t}
				}
				// Save in new format
				bt, err := json.Marshal(spec.Trackers)
				if err != nil {
					return err
				}
				err = b.Put(Keys.Trackers, bt)
				if err != nil {
					return err
				}
			}
		}

		value = b.Get(Keys.URLList)
		if value != nil {
			err = json.Unmarshal(value, &spec.URLList)
			if err != nil {
				return err
			}
		}

		value = b.Get(Keys.FixedPeers)
		if value != nil {
			err = json.Unmarshal(value, &spec.FixedPeers)
			if err != nil {
				return err
			}
		}

		value = b.Get(Keys.Info)
		if value != nil {
			spec.Info = make([]byte, len(value))
			copy(spec.Info, value)
		}

		value = b.Get(Keys.Bitfield)
		if value != nil {
			spec.Bitfield = make([]byte, len(value))
			copy(spec.Bitfield, value)
		}

		value = b.Get(Keys.AddedAt)
		if value != nil {
			spec.AddedAt, err = time.Parse(time.RFC3339, string(value))
			if err != nil {
				return err
			}
		}

		value = b.Get(Keys.BytesDownloaded)
		if value != nil {
			spec.BytesDownloaded, err = strconv.ParseInt(string(value), 10, 64)
			if err != nil {
				return err
			}
		}

		value = b.Get(Keys.BytesUploaded)
		if value != nil {
			spec.BytesUploaded, err = strconv.ParseInt(string(value), 10, 64)
			if err != nil {
				return err
			}
		}

		value = b.Get(Keys.BytesWasted)
		if value != nil {
			spec.BytesWasted, err = strconv.ParseInt(string(value), 10, 64)
			if err != nil {
				return err
			}
		}

		value = b.Get(Keys.SeededFor)
		if value != nil {
			spec.SeededFor, err = time.ParseDuration(string(value))
			if err != nil {
				return err
			}
		}

		value = b.Get(Keys.Started)
		if value != nil {
			spec.Started, err = strconv.ParseBool(string(value))
			if err != nil {
				return err
			}
		}

		return nil
	})
	return
}
<|endoftext|>


<commit_before>// Copyright (c) 2021 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package stdscript

import (
	"bytes"
	"testing"

	"github.com/decred/dcrd/txscript/v4"
)

// complexScriptV0 is a version 0 script comprised of half as many opcodes as
// the maximum allowed followed by as many max size data pushes fit without
// exceeding the max allowed script size.
var complexScriptV0 = func() []byte {
	const (
		maxScriptSize        = txscript.MaxScriptSize
		maxScriptElementSize = txscript.MaxScriptElementSize
	)
	var scriptLen int
	builder := txscript.NewScriptBuilder()
	for i := 0; i < txscript.MaxOpsPerScript/2; i++ {
		builder.AddOp(txscript.OP_TRUE)
		scriptLen++
	}
	maxData := bytes.Repeat([]byte{0x02}, maxScriptElementSize)
	for i := 0; i < (maxScriptSize-scriptLen)/maxScriptElementSize; i++ {
		builder.AddData(maxData)
	}
	script, err := builder.Script()
	if err != nil {
		panic(err)
	}
	return script
}()

// makeBenchmarks constructs a slice of tests to use in the benchmarks as
// follows:
// - Start with a version 0 complex non standard script
// - Add all tests for which the provided filter function returns true
func makeBenchmarks(filterFn func(test scriptTest) bool) []scriptTest {
	benches := make([]scriptTest, 0, 5)
	benches = append(benches, scriptTest{
		name:    "v0 complex non standard",
		version: 0,
		script:  complexScriptV0,
	})
	for _, test := range scriptV0Tests {
		if filterFn(test) {
			benches = append(benches, test)
		}
	}
	return benches
}

// benchIsX is a convenience function that runs benchmarks for the entries that
// match the provided filter function using the given script type determination
// function and ensures the result matches the expected one.
func benchIsX(b *testing.B, filterFn func(test scriptTest) bool, isXFn func(scriptVersion uint16, script []byte) bool) {
	benches := makeBenchmarks(filterFn)
	for _, bench := range benches {
		want := filterFn(bench)
		b.Run(bench.name, func(b *testing.B) {
			b.ReportAllocs()
			b.ResetTimer()
			for i := 0; i < b.N; i++ {
				got := isXFn(bench.version, bench.script)
				if got != want {
					b.Fatalf("%q: unexpected result -- got %v, want %v",
						bench.name, got, want)
				}
			}
		})
	}
}

// BenchmarkIsPubKeyScript benchmarks the performance of analyzing various
// public key scripts to determine if they are p2pk-ecdsa-secp256k1 scripts.
func BenchmarkIsPubKeyScript(b *testing.B) {
	filterFn := func(test scriptTest) bool {
		return test.wantType == STPubKeyEcdsaSecp256k1
	}
	benchIsX(b, filterFn, IsPubKeyScript)
}
<commit_msg>stdscript: Add v0 p2pk-ed25519 benchmark.<commit_after>// Copyright (c) 2021 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package stdscript

import (
	"bytes"
	"testing"

	"github.com/decred/dcrd/txscript/v4"
)

// complexScriptV0 is a version 0 script comprised of half as many opcodes as
// the maximum allowed followed by as many max size data pushes fit without
// exceeding the max allowed script size.
var complexScriptV0 = func() []byte {
	const (
		maxScriptSize        = txscript.MaxScriptSize
		maxScriptElementSize = txscript.MaxScriptElementSize
	)
	var scriptLen int
	builder := txscript.NewScriptBuilder()
	for i := 0; i < txscript.MaxOpsPerScript/2; i++ {
		builder.AddOp(txscript.OP_TRUE)
		scriptLen++
	}
	maxData := bytes.Repeat([]byte{0x02}, maxScriptElementSize)
	for i := 0; i < (maxScriptSize-scriptLen)/maxScriptElementSize; i++ {
		builder.AddData(maxData)
	}
	script, err := builder.Script()
	if err != nil {
		panic(err)
	}
	return script
}()

// makeBenchmarks constructs a slice of tests to use in the benchmarks as
// follows:
// - Start with a version 0 complex non standard script
// - Add all tests for which the provided filter function returns true
func makeBenchmarks(filterFn func(test scriptTest) bool) []scriptTest {
	benches := make([]scriptTest, 0, 5)
	benches = append(benches, scriptTest{
		name:    "v0 complex non standard",
		version: 0,
		script:  complexScriptV0,
	})
	for _, test := range scriptV0Tests {
		if filterFn(test) {
			benches = append(benches, test)
		}
	}
	return benches
}

// benchIsX is a convenience function that runs benchmarks for the entries that
// match the provided filter function using the given script type determination
// function and ensures the result matches the expected one.
func benchIsX(b *testing.B, filterFn func(test scriptTest) bool, isXFn func(scriptVersion uint16, script []byte) bool) {
	b.Helper()

	benches := makeBenchmarks(filterFn)
	for _, bench := range benches {
		want := filterFn(bench)
		b.Run(bench.name, func(b *testing.B) {
			b.ReportAllocs()
			b.ResetTimer()
			for i := 0; i < b.N; i++ {
				got := isXFn(bench.version, bench.script)
				if got != want {
					b.Fatalf("%q: unexpected result -- got %v, want %v",
						bench.name, got, want)
				}
			}
		})
	}
}

// BenchmarkIsPubKeyScript benchmarks the performance of analyzing various
// public key scripts to determine if they are p2pk-ecdsa-secp256k1 scripts.
func BenchmarkIsPubKeyScript(b *testing.B) {
	filterFn := func(test scriptTest) bool {
		return test.wantType == STPubKeyEcdsaSecp256k1
	}
	benchIsX(b, filterFn, IsPubKeyScript)
}

// BenchmarkIsPubKeyEd25519Script benchmarks the performance of analyzing
// various public key scripts to determine if they are p2pkh-ed25519 scripts.
func BenchmarkIsPubKeyEd25519Script(b *testing.B) {
	filterFn := func(test scriptTest) bool {
		return test.wantType == STPubKeyEd25519
	}
	benchIsX(b, filterFn, IsPubKeyEd25519Script)
}
<|endoftext|>


<commit_before>/*
Copyright 2018 Google LLC

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 spanner

import (
	"strings"

	"cloud.google.com/go/internal/testutil"
	"github.com/google/go-cmp/cmp"
)

// TODO(deklerk): move this to internal/testutil
func testEqual(a, b interface{}) bool {
	return testutil.Equal(a, b,
		cmp.AllowUnexported(TimestampBound{}, Error{}, TransactionOutcomeUnknownError{},
			Mutation{}, Row{}, Partition{}, BatchReadOnlyTransactionID{}),
		cmp.FilterPath(func(path cmp.Path) bool {
			// Ignore Error.state, Error.sizeCache, and Error.unknownFields
			if strings.HasSuffix(path.GoString(), ".err.(*status.Error).state") {
				return true
			}
			if strings.HasSuffix(path.GoString(), ".err.(*status.Error).sizeCache") {
				return true
			}
			if strings.HasSuffix(path.GoString(), ".err.(*status.Error).unknownFields") {
				return true
			}
			if strings.Contains(path.GoString(), "{*status.Error}.state") {
				return true
			}
			if strings.Contains(path.GoString(), "{*status.Error}.sizeCache") {
				return true
			}
			if strings.Contains(path.GoString(), "{*status.Error}.unknownFields") {
				return true
			}
			return false
		}, cmp.Ignore()))
}
<commit_msg>fix(spanner): add extra field to ignore with cmp (#2577)<commit_after>/*
Copyright 2018 Google LLC

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 spanner

import (
	"strings"

	"cloud.google.com/go/internal/testutil"
	"github.com/google/go-cmp/cmp"
)

// TODO(deklerk): move this to internal/testutil
func testEqual(a, b interface{}) bool {
	return testutil.Equal(a, b,
		cmp.AllowUnexported(TimestampBound{}, Error{}, TransactionOutcomeUnknownError{},
			Mutation{}, Row{}, Partition{}, BatchReadOnlyTransactionID{}),
		cmp.FilterPath(func(path cmp.Path) bool {
			// Ignore Error.state, Error.sizeCache, and Error.unknownFields
			if strings.HasSuffix(path.GoString(), ".err.(*status.Error).state") {
				return true
			}
			if strings.HasSuffix(path.GoString(), ".err.(*status.Error).sizeCache") {
				return true
			}
			if strings.HasSuffix(path.GoString(), ".err.(*status.Error).unknownFields") {
				return true
			}
			if strings.HasSuffix(path.GoString(), ".err.(*status.Error).e") {
				return true
			}
			if strings.Contains(path.GoString(), "{*status.Error}.state") {
				return true
			}
			if strings.Contains(path.GoString(), "{*status.Error}.sizeCache") {
				return true
			}
			if strings.Contains(path.GoString(), "{*status.Error}.unknownFields") {
				return true
			}
			return false
		}, cmp.Ignore()))
}
<|endoftext|>


<commit_before>/*
Copyright 2015 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 e2e

import (
	"time"

	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/apis/extensions"

	. "github.com/onsi/ginkgo"
)

const (
	kindRC         = "replicationController"
	kindDeployment = "deployment"
	subresource    = "scale"
)

var _ = Describe("Horizontal pod autoscaling (scale resource: CPU) [Skipped]", func() {
	var rc *ResourceConsumer
	f := NewFramework("horizontal-pod-autoscaling")

	titleUp := "Should scale from 1 pod to 3 pods and from 3 to 5"
	titleDown := "Should scale from 5 pods to 3 pods and from 3 to 1"

	Describe("Deployment [Feature:Deployment]", func() {
		// CPU tests via deployments
		It(titleUp, func() {
			scaleUp("deployment", kindDeployment, rc, f)
		})
		It(titleDown, func() {
			scaleDown("deployment", kindDeployment, rc, f)
		})
	})

	Describe("ReplicationController [Feature:Autoscaling]", func() {
		// CPU tests via replication controllers
		It(titleUp, func() {
			scaleUp("rc", kindRC, rc, f)
		})
		It(titleDown, func() {
			scaleDown("rc", kindRC, rc, f)
		})
	})
})

// HPAScaleTest struct is used by the scale(...) function.
type HPAScaleTest struct {
	initPods          int
	cpuStart          int
	maxCPU            int64
	idealCPU          int
	minPods           int
	maxPods           int
	firstScale        int
	firstScaleStasis  time.Duration
	cpuBurst          int
	secondScale       int
	secondScaleStasis time.Duration
}

// run is a method which runs an HPA lifecycle, from a starting state, to an expected
// The initial state is defined by the initPods parameter.
// The first state change is due to the CPU being consumed initially, which HPA responds to by changing pod counts.
// The second state change is due to the CPU burst parameter, which HPA again responds to.
// TODO The use of 3 states is arbitrary, we could eventually make this test handle "n" states once this test stabilizes.
func (scaleTest *HPAScaleTest) run(name, kind string, rc *ResourceConsumer, f *Framework) {
	rc = NewDynamicResourceConsumer(name, kind, scaleTest.initPods, scaleTest.cpuStart, 0, scaleTest.maxCPU, 100, f)
	defer rc.CleanUp()
	createCPUHorizontalPodAutoscaler(rc, scaleTest.idealCPU, scaleTest.minPods, scaleTest.maxPods)
	rc.WaitForReplicas(scaleTest.firstScale)
	rc.EnsureDesiredReplicas(scaleTest.firstScale, scaleTest.firstScaleStasis)
	rc.ConsumeCPU(scaleTest.cpuBurst)
	rc.WaitForReplicas(scaleTest.secondScale)
}

func scaleUp(name, kind string, rc *ResourceConsumer, f *Framework) {
	scaleTest := &HPAScaleTest{
		initPods:         1,
		cpuStart:         250,
		maxCPU:           500,
		idealCPU:         .2 * 100,
		minPods:          1,
		maxPods:          5,
		firstScale:       3,
		firstScaleStasis: 10 * time.Minute,
		cpuBurst:         700,
		secondScale:      5,
	}
	scaleTest.run(name, kind, rc, f)
}

func scaleDown(name, kind string, rc *ResourceConsumer, f *Framework) {
	scaleTest := &HPAScaleTest{
		initPods:         5,
		cpuStart:         400,
		maxCPU:           500,
		idealCPU:         .3 * 100,
		minPods:          1,
		maxPods:          5,
		firstScale:       3,
		firstScaleStasis: 10 * time.Minute,
		cpuBurst:         100,
		secondScale:      1,
	}
	scaleTest.run(name, kind, rc, f)
}

func createCPUHorizontalPodAutoscaler(rc *ResourceConsumer, cpu, minReplicas, maxRepl int) {
	hpa := &extensions.HorizontalPodAutoscaler{
		ObjectMeta: api.ObjectMeta{
			Name:      rc.name,
			Namespace: rc.framework.Namespace.Name,
		},
		Spec: extensions.HorizontalPodAutoscalerSpec{
			ScaleRef: extensions.SubresourceReference{
				Kind:        rc.kind,
				Name:        rc.name,
				Subresource: subresource,
			},
			MinReplicas:    &minReplicas,
			MaxReplicas:    maxRepl,
			CPUUtilization: &extensions.CPUTargetUtilization{TargetPercentage: cpu},
		},
	}
	_, errHPA := rc.framework.Client.Extensions().HorizontalPodAutoscalers(rc.framework.Namespace.Name).Create(hpa)
	expectNoError(errHPA)
}
<commit_msg>Classify all HPA tests as [Feature:Autoscaling]<commit_after>/*
Copyright 2015 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 e2e

import (
	"time"

	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/apis/extensions"

	. "github.com/onsi/ginkgo"
)

const (
	kindRC         = "replicationController"
	kindDeployment = "deployment"
	subresource    = "scale"
)

var _ = Describe("Horizontal pod autoscaling (scale resource: CPU) [Feature:Autoscaling]", func() {
	var rc *ResourceConsumer
	f := NewFramework("horizontal-pod-autoscaling")

	titleUp := "Should scale from 1 pod to 3 pods and from 3 to 5"
	titleDown := "Should scale from 5 pods to 3 pods and from 3 to 1"

	Describe("Deployment", func() {
		// CPU tests via deployments
		It(titleUp, func() {
			scaleUp("deployment", kindDeployment, rc, f)
		})
		It(titleDown, func() {
			scaleDown("deployment", kindDeployment, rc, f)
		})
	})

	Describe("ReplicationController", func() {
		// CPU tests via replication controllers
		It(titleUp, func() {
			scaleUp("rc", kindRC, rc, f)
		})
		It(titleDown, func() {
			scaleDown("rc", kindRC, rc, f)
		})
	})
})

// HPAScaleTest struct is used by the scale(...) function.
type HPAScaleTest struct {
	initPods          int
	cpuStart          int
	maxCPU            int64
	idealCPU          int
	minPods           int
	maxPods           int
	firstScale        int
	firstScaleStasis  time.Duration
	cpuBurst          int
	secondScale       int
	secondScaleStasis time.Duration
}

// run is a method which runs an HPA lifecycle, from a starting state, to an expected
// The initial state is defined by the initPods parameter.
// The first state change is due to the CPU being consumed initially, which HPA responds to by changing pod counts.
// The second state change is due to the CPU burst parameter, which HPA again responds to.
// TODO The use of 3 states is arbitrary, we could eventually make this test handle "n" states once this test stabilizes.
func (scaleTest *HPAScaleTest) run(name, kind string, rc *ResourceConsumer, f *Framework) {
	rc = NewDynamicResourceConsumer(name, kind, scaleTest.initPods, scaleTest.cpuStart, 0, scaleTest.maxCPU, 100, f)
	defer rc.CleanUp()
	createCPUHorizontalPodAutoscaler(rc, scaleTest.idealCPU, scaleTest.minPods, scaleTest.maxPods)
	rc.WaitForReplicas(scaleTest.firstScale)
	rc.EnsureDesiredReplicas(scaleTest.firstScale, scaleTest.firstScaleStasis)
	rc.ConsumeCPU(scaleTest.cpuBurst)
	rc.WaitForReplicas(scaleTest.secondScale)
}

func scaleUp(name, kind string, rc *ResourceConsumer, f *Framework) {
	scaleTest := &HPAScaleTest{
		initPods:         1,
		cpuStart:         250,
		maxCPU:           500,
		idealCPU:         .2 * 100,
		minPods:          1,
		maxPods:          5,
		firstScale:       3,
		firstScaleStasis: 10 * time.Minute,
		cpuBurst:         700,
		secondScale:      5,
	}
	scaleTest.run(name, kind, rc, f)
}

func scaleDown(name, kind string, rc *ResourceConsumer, f *Framework) {
	scaleTest := &HPAScaleTest{
		initPods:         5,
		cpuStart:         400,
		maxCPU:           500,
		idealCPU:         .3 * 100,
		minPods:          1,
		maxPods:          5,
		firstScale:       3,
		firstScaleStasis: 10 * time.Minute,
		cpuBurst:         100,
		secondScale:      1,
	}
	scaleTest.run(name, kind, rc, f)
}

func createCPUHorizontalPodAutoscaler(rc *ResourceConsumer, cpu, minReplicas, maxRepl int) {
	hpa := &extensions.HorizontalPodAutoscaler{
		ObjectMeta: api.ObjectMeta{
			Name:      rc.name,
			Namespace: rc.framework.Namespace.Name,
		},
		Spec: extensions.HorizontalPodAutoscalerSpec{
			ScaleRef: extensions.SubresourceReference{
				Kind:        rc.kind,
				Name:        rc.name,
				Subresource: subresource,
			},
			MinReplicas:    &minReplicas,
			MaxReplicas:    maxRepl,
			CPUUtilization: &extensions.CPUTargetUtilization{TargetPercentage: cpu},
		},
	}
	_, errHPA := rc.framework.Client.Extensions().HorizontalPodAutoscalers(rc.framework.Namespace.Name).Create(hpa)
	expectNoError(errHPA)
}
<|endoftext|>


<commit_before>package server

import (
	"encoding/json"
	"errors"
	"github.com/gin-gonic/gin"
	"github.com/jkomoros/boardgame"
	"net/http"
	"os"
	"reflect"
	"unicode"
)

type Server struct {
	game *boardgame.Game
}

type MoveForm struct {
	Name        string
	Description string
	Fields      []*MoveFormField
}

type MoveFormFieldType int

const (
	FieldUnknown MoveFormFieldType = iota
	FieldInt
	FieldBool
)

type MoveFormField struct {
	Name string
	Type MoveFormFieldType
}

func NewServer(game *boardgame.Game) *Server {
	return &Server{
		game: game,
	}
}

const (
	pathToLib = "$GOPATH/src/github.com/jkomoros/boardgame/server/"
)

func (s *Server) viewHandler(c *gin.Context) {

	var errorMessage string

	if c.Request.Method == http.MethodPost {

		if err := s.makeMove(c); err != nil {
			errorMessage = err.Error()
		}

	}

	args := gin.H{
		"State":   string(boardgame.Serialize(s.game.State.JSON())),
		"Diagram": s.game.State.Payload.Diagram(),
		"Chest":   s.renderChest(),
		"Forms":   s.generateForms(),
		"Game":    s.game,
		"Error":   errorMessage,
	}

	c.HTML(http.StatusOK, "main.tmpl", args)

}

func (s *Server) makeMove(c *gin.Context) error {

	//This method is passed a context mainly just to get info from request.

	move := s.game.MoveByName(c.PostForm("MoveType"))

	if move == nil {
		return errors.New("Invalid MoveType")
	}

	//TODO: actually make the move.

	return errors.New("This functionality is not yet implemented")
}

func (s *Server) generateForms() []*MoveForm {

	var result []*MoveForm

	for _, move := range s.game.Moves() {
		moveItem := &MoveForm{
			Name:        move.Name(),
			Description: move.Description(),
			Fields:      formFields(move),
		}
		result = append(result, moveItem)
	}

	return result
}

func moveFieldNameShouldBeIncluded(name string) bool {
	//TODO: this is recreated a number of places, which implies it should be
	//in the base library.

	if len(name) < 1 {
		return false
	}

	firstChar := []rune(name)[0]

	if firstChar != unicode.ToUpper(firstChar) {
		//It was not upper case, thus private, thus should not be included.
		return false
	}

	return true
}

func formFields(move boardgame.Move) []*MoveFormField {

	var result []*MoveFormField

	s := reflect.ValueOf(move).Elem()
	typeOfT := s.Type()
	for i := 0; i < s.NumField(); i++ {
		f := s.Field(i)
		fieldName := typeOfT.Field(i).Name
		if !moveFieldNameShouldBeIncluded(fieldName) {
			continue
		}

		var fieldType MoveFormFieldType

		switch f.Type().Name() {
		case "int":
			fieldType = FieldInt
		case "bool":
			fieldType = FieldBool
		default:
			fieldType = FieldUnknown
		}

		result = append(result, &MoveFormField{
			Name: fieldName,
			Type: fieldType,
		})
	}

	return result
}

func (s *Server) renderChest() string {
	//Substantially copied from cli.renderChest().

	deck := make(map[string][]interface{})

	for _, name := range s.game.Chest().DeckNames() {

		components := s.game.Chest().Deck(name).Components()

		values := make([]interface{}, len(components))

		for i, component := range components {
			values[i] = struct {
				Index  int
				Values interface{}
			}{
				i,
				component.Values,
			}
		}

		deck[name] = values
	}

	json, err := json.MarshalIndent(deck, "", "  ")

	if err != nil {
		panic(err)
	}

	return string(json)
}

//Start is where you start the server, and it never returns until it's time to shut down.
func (s *Server) Start() {

	router := gin.Default()

	router.LoadHTMLGlob(os.ExpandEnv(pathToLib) + "templates/*")

	router.GET("/", s.viewHandler)
	router.POST("/", s.viewHandler)

	router.Run(":8080")

}
<commit_msg>Use PropReader in server, instaed of doing reflection ourselves. this is actually how it's supposed to be... Part of #52.<commit_after>package server

import (
	"encoding/json"
	"errors"
	"github.com/gin-gonic/gin"
	"github.com/jkomoros/boardgame"
	"net/http"
	"os"
)

type Server struct {
	game *boardgame.Game
}

type MoveForm struct {
	Name        string
	Description string
	Fields      []*MoveFormField
}

type MoveFormFieldType int

const (
	FieldUnknown MoveFormFieldType = iota
	FieldInt
	FieldBool
)

type MoveFormField struct {
	Name string
	Type MoveFormFieldType
}

func NewServer(game *boardgame.Game) *Server {
	return &Server{
		game: game,
	}
}

const (
	pathToLib = "$GOPATH/src/github.com/jkomoros/boardgame/server/"
)

func (s *Server) viewHandler(c *gin.Context) {

	var errorMessage string

	if c.Request.Method == http.MethodPost {

		if err := s.makeMove(c); err != nil {
			errorMessage = err.Error()
		}

	}

	args := gin.H{
		"State":   string(boardgame.Serialize(s.game.State.JSON())),
		"Diagram": s.game.State.Payload.Diagram(),
		"Chest":   s.renderChest(),
		"Forms":   s.generateForms(),
		"Game":    s.game,
		"Error":   errorMessage,
	}

	c.HTML(http.StatusOK, "main.tmpl", args)

}

func (s *Server) makeMove(c *gin.Context) error {

	//This method is passed a context mainly just to get info from request.

	move := s.game.MoveByName(c.PostForm("MoveType"))

	if move == nil {
		return errors.New("Invalid MoveType")
	}

	//TODO: actually make the move.

	return errors.New("This functionality is not yet implemented")
}

func (s *Server) generateForms() []*MoveForm {

	var result []*MoveForm

	for _, move := range s.game.Moves() {
		moveItem := &MoveForm{
			Name:        move.Name(),
			Description: move.Description(),
			Fields:      formFields(move),
		}
		result = append(result, moveItem)
	}

	return result
}

func formFields(move boardgame.Move) []*MoveFormField {

	var result []*MoveFormField

	for _, fieldName := range move.Props() {

		val := move.Prop(fieldName)

		var fieldType MoveFormFieldType

		switch val.(type) {
		default:
			fieldType = FieldUnknown
		case int:
			fieldType = FieldInt
		case bool:
			fieldType = FieldBool
		}

		result = append(result, &MoveFormField{
			Name: fieldName,
			Type: fieldType,
		})

	}

	return result
}

func (s *Server) renderChest() string {
	//Substantially copied from cli.renderChest().

	deck := make(map[string][]interface{})

	for _, name := range s.game.Chest().DeckNames() {

		components := s.game.Chest().Deck(name).Components()

		values := make([]interface{}, len(components))

		for i, component := range components {
			values[i] = struct {
				Index  int
				Values interface{}
			}{
				i,
				component.Values,
			}
		}

		deck[name] = values
	}

	json, err := json.MarshalIndent(deck, "", "  ")

	if err != nil {
		panic(err)
	}

	return string(json)
}

//Start is where you start the server, and it never returns until it's time to shut down.
func (s *Server) Start() {

	router := gin.Default()

	router.LoadHTMLGlob(os.ExpandEnv(pathToLib) + "templates/*")

	router.GET("/", s.viewHandler)
	router.POST("/", s.viewHandler)

	router.Run(":8080")

}
<|endoftext|>


<commit_before>package server

import (
	"fmt"
	"github.com/gorilla/mux"
	"net/http"
)

type Instance struct {
	ListenAddress string
	ListenPort    string

	Router *mux.Router
}

func New() Instance {
	fmt.Printf("in server New()\n")

	var instance Instance
	return instance
}

func (instance *Instance) Initialize() {
	router := mux.NewRouter()

	router.HandleFunc("/status/", StatusHandler)
	router.HandleFunc("/api/", ApiHandler)
	router.Handle("/static/{staticPath}",
		http.StripPrefix(
			"/static/",
			http.FileServer(
				http.Dir(
					"static"))))

	instance.Router = router
}

func (instance *Instance) Run() {
	fmt.Printf("in server.Run().\n")
	http.ListenAndServe(":8080", instance.Router)
}

func StatusHandler(respW http.ResponseWriter, req *http.Request) {
	fmt.Printf("in status handler.\n")
}

func ApiHandler(respW http.ResponseWriter, req *http.Request) {
	fmt.Printf("in api handler.\n")
}

// func StaticHandler() http.HandlerFunc {
// 	fmt.Printf("in static handler.\n")
// 	return http.FileServer(http.Dir("/Users/maxgarvey/go/src/github.com/maxgarvey/conflagration/static")).ServeHTTP
// }
<commit_msg>fix up finer details of static file server.<commit_after>package server

import (
	"fmt"
	"io"
	"net/http"

	"github.com/gorilla/mux"
)

type Instance struct {
	ListenAddress string
	ListenPort    string

	StaticFilesDirectory string

	Router *mux.Router
}

func New() Instance {
	fmt.Printf("in server New()\n")

	var instance Instance
	return instance
}

func (instance *Instance) Initialize() {
	router := mux.NewRouter()

	router.HandleFunc("/status", StatusHandler)
	router.HandleFunc("/api", ApiHandler)
	router.PathPrefix("/static").Handler(
		http.StripPrefix("/static",
			http.FileServer(
				http.Dir(
					// TODO: replace "static" with instance.StaticFilesDirectory
					"./static")),
		),
	)

	instance.Router = router
}

func (instance *Instance) Run() {
	fmt.Printf("in server.Run().\n")
	http.ListenAndServe(
		// TODO: replace the "8080" with instance.ListenPort
		fmt.Sprintf(":%d", 8080),
		instance.Router,
	)
}

func StatusHandler(respW http.ResponseWriter, req *http.Request) {
	fmt.Printf("in status handler.\n")

	respW.WriteHeader(http.StatusOK)
	io.WriteString(respW, "status OK\n")
}

func ApiHandler(respW http.ResponseWriter, req *http.Request) {
	fmt.Printf("in api handler.\n")

	respW.WriteHeader(http.StatusOK)
	io.WriteString(respW, "api response here\n")
}
<|endoftext|>


<commit_before>package command

import (
	"encoding/json"
	"fmt"
	. "github.com/heroku/force/error"
	. "github.com/heroku/force/lib"
	"os"
	"os/exec"
	"path"
)

var cmdUseDXAuth = &Command{
	Run:   runUseDXAuth,
	Usage: "usedxauth [dx-username or alias]",
	Short: "Authenticate with SFDX Scratch Org User",
	Long: `
Authenticate with SFDX Scratch Org User. If a user or alias is passed to the command then an attempt is made to find that user authentication info.  If no user or alias is passed an attempt is made to find the default user based on sfdx config.

Examples:

  force usedxauth test-d1df0gyckgpr@dcarroll_company.net
  force usedxauth ScratchUserAlias
  force usedxauth
`,
}

func init() {
}

func runUseDXAuth(cmd *Command, args []string) {
	var auth map[string]interface{}
	var err error
	if len(args) == 0 {
		fmt.Println("Determining default user...")
		auth, _ = getDefaultItem()
	} else {
		user := args[0]
		fmt.Printf("Looking for %s in DX orgs...\n", user)
		auth, err = getOrgListItem(user)
		if err != nil {
			ErrorAndExit(err.Error())
		}
	}

	connStatus := fmt.Sprintf("%s", auth["connectedStatus"])
	username := fmt.Sprintf("%s", auth["username"])
	alias := fmt.Sprintf("%s", auth["alias"])
	if connStatus == "Connected" || connStatus == "Unknown" {
		authData := getSFDXAuth(username)
		authData.Alias = alias
		authData.Username = username
		SetActiveCreds(authData)
		if len(authData.Alias) > 0 {
			fmt.Printf("Now using DX credentials for %s (%s)\n", username, alias)
		} else {
			fmt.Printf("Now using DX credentials for %s\n", username)
		}
	} else {
		ErrorAndExit("Could not determine connection status for %s", username)
	}
}

func inProjectDir() bool {
	dir, err := os.Getwd()
	_, err = os.Stat(path.Join(dir, ".sfdx"))

	return err == nil
}

func getOrgListItem(user string) (data map[string]interface{}, err error) {
	md, err := getOrgList()
	data, err = findUserInOrgList(user, md)
	return
}

func getOrgList() (data map[string]interface{}, err error) {
	cmd := exec.Command("sfdx", "force:org:list", "--json")
	stdout, err := cmd.StdoutPipe()

	if err != nil {
		ErrorAndExit(err.Error())
	}
	if err := cmd.Start(); err != nil {
		ErrorAndExit(err.Error())
	}
	type Orgs struct {
		NonScratchOrgs map[string]interface{}
		ScratchOrgs    map[string]interface{}
	}

	if err := json.NewDecoder(stdout).Decode(&data); err != nil {
		ErrorAndExit(err.Error())
	}
	if err := cmd.Wait(); err != nil {
		ErrorAndExit(err.Error())
	}

	return
}

func findUserInOrgList(user string, md map[string]interface{}) (data map[string]interface{}, err error) {
	for k, v := range md {
		switch vv := v.(type) {
		case float64:
		case interface{}:
			for _, u := range vv.(map[string]interface{}) {
				for _, y := range u.([]interface{}) {
					auth := y.(map[string]interface{})
					//check if user matches alias or username
					if auth["username"] == user || auth["alias"] == user {
						if len(fmt.Sprintf("%s", auth["alias"])) > 0 {
							fmt.Printf("Getting auth for %s (%s)...\n", auth["username"], auth["alias"])
						} else {
							fmt.Printf("Getting auth for %s\n...", auth["username"])
						}
						data = auth
						err = nil
						return
					}
				}
			}
		default:
			fmt.Println(k, "is of a type I don't know how to handle")
		}
	}
	err = fmt.Errorf("Could not find and alias or username that matches %s", user)
	return
}

func findDefaultUserInOrgList(md map[string]interface{}) (data []map[string]interface{}, err error) {
	for k, v := range md {
		switch vv := v.(type) {
		case float64:
		case interface{}:
			for _, u := range vv.(map[string]interface{}) {
				for _, y := range u.([]interface{}) {
					auth := y.(map[string]interface{})
					//check if user matches alias or username
					if auth["isDefaultUsername"] == true || auth["isDefaultDevHubUsername"] == true {
						// Add auth to slice
						data = append(data, auth)
					}
				}
			}
		default:
			fmt.Println(k, "is of a type I don't know how to handle")
		}
	}
	if len(data) == 0 {
		err = fmt.Errorf("Could not find a default user")
	}
	return
}

func getDefaultItem() (data map[string]interface{}, err error) {
	md, err := getOrgList()
	defUsers, err := findDefaultUserInOrgList(md)

	if len(defUsers) == 0 {
		ErrorAndExit("No default user logins found")
	}

	if len(defUsers) == 1 {
		data = defUsers[0]
	} else {
		var hubUser map[string]interface{}
		var scrUser map[string]interface{}
		for _, y := range defUsers {
			if y["defaultMarker"] == "(D)" {
				hubUser = y
			} else {
				scrUser = y
			}
		}
		if inProjectDir() == true {
			data = scrUser
		} else {
			data = hubUser
		}
	}
	if len(fmt.Sprintf("%s", data["alias"])) > 0 {
		fmt.Printf("Getting auth for %s (%s)...\n", data["username"], data["alias"])
	} else {
		fmt.Printf("Getting auth for %s\n...", data["username"])
	}
	return
}

func getSFDXAuth(user string) (auth UserAuth) {
	cmd := exec.Command("sfdx", "force:org:display", "-u"+user, "--json")

	stdout, err := cmd.StdoutPipe()
	if err != nil {
		ErrorAndExit(err.Error())
	}
	if err := cmd.Start(); err != nil {
		ErrorAndExit(err.Error())
	}

	type authData struct {
		Result UserAuth
	}
	var aData authData
	if err := json.NewDecoder(stdout).Decode(&aData); err != nil {
		ErrorAndExit(err.Error())
	}
	if err := cmd.Wait(); err != nil {
		ErrorAndExit(err.Error())
	}
	return aData.Result
}
<commit_msg>Fix usedxauth Without Alias<commit_after>package command

import (
	"encoding/json"
	"fmt"
	. "github.com/heroku/force/error"
	. "github.com/heroku/force/lib"
	"os"
	"os/exec"
	"path"
)

var cmdUseDXAuth = &Command{
	Run:   runUseDXAuth,
	Usage: "usedxauth [dx-username or alias]",
	Short: "Authenticate with SFDX Scratch Org User",
	Long: `
Authenticate with SFDX Scratch Org User. If a user or alias is passed to the command then an attempt is made to find that user authentication info.  If no user or alias is passed an attempt is made to find the default user based on sfdx config.

Examples:

  force usedxauth test-d1df0gyckgpr@dcarroll_company.net
  force usedxauth ScratchUserAlias
  force usedxauth
`,
}

func init() {
}

func runUseDXAuth(cmd *Command, args []string) {
	var auth map[string]interface{}
	var err error
	if len(args) == 0 {
		fmt.Println("Determining default user...")
		auth, _ = getDefaultItem()
	} else {
		user := args[0]
		fmt.Printf("Looking for %s in DX orgs...\n", user)
		auth, err = getOrgListItem(user)
		if err != nil {
			ErrorAndExit(err.Error())
		}
	}

	connStatus := fmt.Sprintf("%s", auth["connectedStatus"])
	username := fmt.Sprintf("%s", auth["username"])
	if connStatus == "Connected" || connStatus == "Unknown" {
		authData := getSFDXAuth(username)
		if val, ok := auth["alias"]; ok {
			authData.Alias = val.(string)
		}
		authData.Username = username
		SetActiveCreds(authData)
		if len(authData.Alias) > 0 {
			fmt.Printf("Now using DX credentials for %s (%s)\n", username, authData.Alias)
		} else {
			fmt.Printf("Now using DX credentials for %s\n", username)
		}
	} else {
		ErrorAndExit("Could not determine connection status for %s", username)
	}
}

func inProjectDir() bool {
	dir, err := os.Getwd()
	_, err = os.Stat(path.Join(dir, ".sfdx"))

	return err == nil
}

func getOrgListItem(user string) (data map[string]interface{}, err error) {
	md, err := getOrgList()
	data, err = findUserInOrgList(user, md)
	return
}

func getOrgList() (data map[string]interface{}, err error) {
	cmd := exec.Command("sfdx", "force:org:list", "--json")
	stdout, err := cmd.StdoutPipe()

	if err != nil {
		ErrorAndExit(err.Error())
	}
	if err := cmd.Start(); err != nil {
		ErrorAndExit(err.Error())
	}
	type Orgs struct {
		NonScratchOrgs map[string]interface{}
		ScratchOrgs    map[string]interface{}
	}

	if err := json.NewDecoder(stdout).Decode(&data); err != nil {
		ErrorAndExit(err.Error())
	}
	if err := cmd.Wait(); err != nil {
		ErrorAndExit(err.Error())
	}

	return
}

func findUserInOrgList(user string, md map[string]interface{}) (data map[string]interface{}, err error) {
	for k, v := range md {
		switch vv := v.(type) {
		case float64:
		case interface{}:
			for _, u := range vv.(map[string]interface{}) {
				for _, y := range u.([]interface{}) {
					auth := y.(map[string]interface{})
					//check if user matches alias or username
					if auth["username"] == user || auth["alias"] == user {
						if _, ok := auth["alias"]; ok {
							fmt.Printf("Getting auth for %s (%s)...\n", auth["username"], auth["alias"])
						} else {
							fmt.Printf("Getting auth for %s\n...", auth["username"])
						}
						data = auth
						err = nil
						return
					}
				}
			}
		default:
			fmt.Println(k, "is of a type I don't know how to handle")
		}
	}
	err = fmt.Errorf("Could not find and alias or username that matches %s", user)
	return
}

func findDefaultUserInOrgList(md map[string]interface{}) (data []map[string]interface{}, err error) {
	for k, v := range md {
		switch vv := v.(type) {
		case float64:
		case interface{}:
			for _, u := range vv.(map[string]interface{}) {
				for _, y := range u.([]interface{}) {
					auth := y.(map[string]interface{})
					//check if user matches alias or username
					if auth["isDefaultUsername"] == true || auth["isDefaultDevHubUsername"] == true {
						// Add auth to slice
						data = append(data, auth)
					}
				}
			}
		default:
			fmt.Println(k, "is of a type I don't know how to handle")
		}
	}
	if len(data) == 0 {
		err = fmt.Errorf("Could not find a default user")
	}
	return
}

func getDefaultItem() (data map[string]interface{}, err error) {
	md, err := getOrgList()
	defUsers, err := findDefaultUserInOrgList(md)

	if len(defUsers) == 0 {
		ErrorAndExit("No default user logins found")
	}

	if len(defUsers) == 1 {
		data = defUsers[0]
	} else {
		var hubUser map[string]interface{}
		var scrUser map[string]interface{}
		for _, y := range defUsers {
			if y["defaultMarker"] == "(D)" {
				hubUser = y
			} else {
				scrUser = y
			}
		}
		if inProjectDir() == true {
			data = scrUser
		} else {
			data = hubUser
		}
	}
	if _, ok := data["alias"]; ok {
		fmt.Printf("Getting auth for %s (%s)...\n", data["username"], data["alias"])
	} else {
		fmt.Printf("Getting auth for %s\n...", data["username"])
	}
	return
}

func getSFDXAuth(user string) (auth UserAuth) {
	cmd := exec.Command("sfdx", "force:org:display", "-u"+user, "--json")

	stdout, err := cmd.StdoutPipe()
	if err != nil {
		ErrorAndExit(err.Error())
	}
	if err := cmd.Start(); err != nil {
		ErrorAndExit(err.Error())
	}

	type authData struct {
		Result UserAuth
	}
	var aData authData
	if err := json.NewDecoder(stdout).Decode(&aData); err != nil {
		ErrorAndExit(err.Error())
	}
	if err := cmd.Wait(); err != nil {
		ErrorAndExit(err.Error())
	}
	return aData.Result
}
<|endoftext|>