<commit_before>package sftp

// ssh_FXP_ATTRS support
// see http://tools.ietf.org/html/draft-ietf-secsh-filexfer-02#section-5

import (
	"os"
	"syscall"
	"time"
)

const (
	ssh_FILEXFER_ATTR_SIZE        = 0x00000001
	ssh_FILEXFER_ATTR_UIDGID      = 0x00000002
	ssh_FILEXFER_ATTR_PERMISSIONS = 0x00000004
	ssh_FILEXFER_ATTR_ACMODTIME   = 0x00000008
	ssh_FILEXFER_ATTR_EXTENDED    = 0x80000000
)

// fileInfo is an artificial type designed to satisfy os.FileInfo.
type fileInfo struct {
	name string
	size int64
	mode os.FileMode
	mtime time.Time
	sys interface{}
}

// Name returns the base name of the file.
func (a *fileInfo) Name() string { return a.name }

// Size returns the length in bytes for regular files; system-dependent for others.
func (a *fileInfo) Size() int64 { return a.size }

// Mode returns file mode bits.
func (a *fileInfo) Mode() os.FileMode { return a.mode }

// ModTime returns the last modification time of the file.
func (a *fileInfo) ModTime() time.Time { return a.mtime }

// IsDir returns true if the file is a directory.
func (a *fileInfo) IsDir() bool { return a.Mode().IsDir() }

func (a *fileInfo) Sys() interface{} { return a.sys }

// FileStat holds the original unmarshalled values from a call LSTAT.
type FileStat struct {
	Size  uint64
	Mode  uint32
	Mtime uint32
	Atime uint32
	Uid uint32
	Gid uint32
	Extended []StatExtended
}

type StatExtended struct {
	ExtType string
	ExtData string
}

func fileInfoFromStat(st *FileStat, name string) os.FileInfo {
	fs := &fileInfo{
		name: name,
		size: int64(st.Size),
		mode: toFileMode(st.Mode),
		mtime: time.Unix(int64(st.Mtime), 0),
		sys: st,
	}
	return fs
}

func unmarshalAttrs(b []byte) (*FileStat, []byte) {
	flags, b := unmarshalUint32(b)
	var a FileStat
	if flags&ssh_FILEXFER_ATTR_SIZE == ssh_FILEXFER_ATTR_SIZE {
		a.Size, b = unmarshalUint64(b)
	}
	if flags&ssh_FILEXFER_ATTR_UIDGID == ssh_FILEXFER_ATTR_UIDGID {
		a.Uid, b = unmarshalUint32(b)
	}
	if flags&ssh_FILEXFER_ATTR_UIDGID == ssh_FILEXFER_ATTR_UIDGID {
		a.Gid, b = unmarshalUint32(b)
	}
	if flags&ssh_FILEXFER_ATTR_PERMISSIONS == ssh_FILEXFER_ATTR_PERMISSIONS {
		a.Mode, b = unmarshalUint32(b)
	}
	if flags&ssh_FILEXFER_ATTR_ACMODTIME == ssh_FILEXFER_ATTR_ACMODTIME {
		a.Atime, b = unmarshalUint32(b)
		a.Mtime, b = unmarshalUint32(b)
	}
	if flags&ssh_FILEXFER_ATTR_EXTENDED == ssh_FILEXFER_ATTR_EXTENDED {
		var count uint32
		count, b = unmarshalUint32(b)
		ext := make([]StatExtended,count,count)
		for i := uint32(0); i < count; i++ {
			var typ string
			var data string
			typ, b = unmarshalString(b)
			data, b = unmarshalString(b)
			ext[i] = StatExtended{typ,data}
		}
		a.Extended = ext
	}
	return &a, b
}

// toFileMode converts sftp filemode bits to the os.FileMode specification
func toFileMode(mode uint32) os.FileMode {
	var fm = os.FileMode(mode & 0777)
	switch mode & syscall.S_IFMT {
	case syscall.S_IFBLK:
		fm |= os.ModeDevice
	case syscall.S_IFCHR:
		fm |= os.ModeDevice | os.ModeCharDevice
	case syscall.S_IFDIR:
		fm |= os.ModeDir
	case syscall.S_IFIFO:
		fm |= os.ModeNamedPipe
	case syscall.S_IFLNK:
		fm |= os.ModeSymlink
	case syscall.S_IFREG:
		// nothing to do
	case syscall.S_IFSOCK:
		fm |= os.ModeSocket
	}
	if mode&syscall.S_ISGID != 0 {
		fm |= os.ModeSetgid
	}
	if mode&syscall.S_ISUID != 0 {
		fm |= os.ModeSetuid
	}
	if mode&syscall.S_ISVTX != 0 {
		fm |= os.ModeSticky
	}
	return fm
}
<commit_msg>Refactor to make vars and receivers consistent with types used.<commit_after>package sftp

// ssh_FXP_ATTRS support
// see http://tools.ietf.org/html/draft-ietf-secsh-filexfer-02#section-5

import (
	"os"
	"syscall"
	"time"
)

const (
	ssh_FILEXFER_ATTR_SIZE        = 0x00000001
	ssh_FILEXFER_ATTR_UIDGID      = 0x00000002
	ssh_FILEXFER_ATTR_PERMISSIONS = 0x00000004
	ssh_FILEXFER_ATTR_ACMODTIME   = 0x00000008
	ssh_FILEXFER_ATTR_EXTENDED    = 0x80000000
)

// fileInfo is an artificial type designed to satisfy os.FileInfo.
type fileInfo struct {
	name string
	size int64
	mode os.FileMode
	mtime time.Time
	sys interface{}
}

// Name returns the base name of the file.
func (fi *fileInfo) Name() string { return fi.name }

// Size returns the length in bytes for regular files; system-dependent for others.
func (fi *fileInfo) Size() int64 { return fi.size }

// Mode returns file mode bits.
func (fi *fileInfo) Mode() os.FileMode { return fi.mode }

// ModTime returns the last modification time of the file.
func (fi *fileInfo) ModTime() time.Time { return fi.mtime }

// IsDir returns true if the file is a directory.
func (fi *fileInfo) IsDir() bool { return fi.Mode().IsDir() }

func (fi *fileInfo) Sys() interface{} { return fi.sys }

// FileStat holds the original unmarshalled values from a call LSTAT.
type FileStat struct {
	Size  uint64
	Mode  uint32
	Mtime uint32
	Atime uint32
	Uid uint32
	Gid uint32
	Extended []StatExtended
}

type StatExtended struct {
	ExtType string
	ExtData string
}

func fileInfoFromStat(st *FileStat, name string) os.FileInfo {
	fs := &fileInfo{
		name: name,
		size: int64(st.Size),
		mode: toFileMode(st.Mode),
		mtime: time.Unix(int64(st.Mtime), 0),
		sys: st,
	}
	return fs
}

func unmarshalAttrs(b []byte) (*FileStat, []byte) {
	flags, b := unmarshalUint32(b)
	var fs FileStat
	if flags&ssh_FILEXFER_ATTR_SIZE == ssh_FILEXFER_ATTR_SIZE {
		fs.Size, b = unmarshalUint64(b)
	}
	if flags&ssh_FILEXFER_ATTR_UIDGID == ssh_FILEXFER_ATTR_UIDGID {
		fs.Uid, b = unmarshalUint32(b)
	}
	if flags&ssh_FILEXFER_ATTR_UIDGID == ssh_FILEXFER_ATTR_UIDGID {
		fs.Gid, b = unmarshalUint32(b)
	}
	if flags&ssh_FILEXFER_ATTR_PERMISSIONS == ssh_FILEXFER_ATTR_PERMISSIONS {
		fs.Mode, b = unmarshalUint32(b)
	}
	if flags&ssh_FILEXFER_ATTR_ACMODTIME == ssh_FILEXFER_ATTR_ACMODTIME {
		fs.Atime, b = unmarshalUint32(b)
		fs.Mtime, b = unmarshalUint32(b)
	}
	if flags&ssh_FILEXFER_ATTR_EXTENDED == ssh_FILEXFER_ATTR_EXTENDED {
		var count uint32
		count, b = unmarshalUint32(b)
		ext := make([]StatExtended,count,count)
		for i := uint32(0); i < count; i++ {
			var typ string
			var data string
			typ, b = unmarshalString(b)
			data, b = unmarshalString(b)
			ext[i] = StatExtended{typ,data}
		}
		fs.Extended = ext
	}
	return &fs, b
}

// toFileMode converts sftp filemode bits to the os.FileMode specification
func toFileMode(mode uint32) os.FileMode {
	var fm = os.FileMode(mode & 0777)
	switch mode & syscall.S_IFMT {
	case syscall.S_IFBLK:
		fm |= os.ModeDevice
	case syscall.S_IFCHR:
		fm |= os.ModeDevice | os.ModeCharDevice
	case syscall.S_IFDIR:
		fm |= os.ModeDir
	case syscall.S_IFIFO:
		fm |= os.ModeNamedPipe
	case syscall.S_IFLNK:
		fm |= os.ModeSymlink
	case syscall.S_IFREG:
		// nothing to do
	case syscall.S_IFSOCK:
		fm |= os.ModeSocket
	}
	if mode&syscall.S_ISGID != 0 {
		fm |= os.ModeSetgid
	}
	if mode&syscall.S_ISUID != 0 {
		fm |= os.ModeSetuid
	}
	if mode&syscall.S_ISVTX != 0 {
		fm |= os.ModeSticky
	}
	return fm
}
<|endoftext|>


<commit_before>package application

import (
	"context"
	"os"
	"time"

	"github.com/vardius/shutdown"

	"github.com/vardius/go-api-boilerplate/pkg/log"
)

// Adapter interface
type Adapter interface {
	Start(ctx context.Context) error
	Stop(ctx context.Context) error
}

// App represents application service
type App struct {
	adapters        []Adapter
	shutdownTimeout time.Duration

	logger *log.Logger
}

// New provides new service application
func New(logger *log.Logger) *App {
	return &App{
		shutdownTimeout: 5 * time.Second, // Default shutdown timeout
		logger:          logger,
	}
}

// AddAdapters adds adapters to application service
func (app *App) AddAdapters(adapters ...Adapter) {
	app.adapters = append(app.adapters, adapters...)
}

// WithShutdownTimeout overrides default shutdown timout
func (app *App) WithShutdownTimeout(timeout time.Duration) {
	app.shutdownTimeout = timeout
}

// Run runs the service application
func (app *App) Run(ctx context.Context) {
	stop := func() {
		ctxWithTimeout, cancel := context.WithTimeout(ctx, app.shutdownTimeout)
		defer cancel()

		app.logger.Info(ctxWithTimeout, "shutting down...\n")

		errCh := make(chan error, len(app.adapters))

		for _, adapter := range app.adapters {
			go func(adapter Adapter) {
				errCh <- adapter.Stop(ctxWithTimeout)
			}(adapter)
		}

		for i := 0; i < len(app.adapters); i++ {
			if err := <-errCh; err != nil {
				app.logger.Critical(ctxWithTimeout, "shutdown error: %v\n", err)
				// calling Goexit terminates that goroutine without returning (previous defers would not run)
				defer os.Exit(1)
				return
			}
		}

		app.logger.Info(ctxWithTimeout, "gracefully stopped\n")
	}

	for _, adapter := range app.adapters {
		go func(adapter Adapter) {
			app.logger.Critical(ctx, "adapter start error: %v\n", adapter.Start(ctx))
			os.Exit(1)
		}(adapter)
	}

	shutdown.GracefulStop(stop)
}
<commit_msg>Remove warning<commit_after>package application

import (
	"context"
	"os"
	"time"

	"github.com/vardius/shutdown"

	"github.com/vardius/go-api-boilerplate/pkg/log"
)

// Adapter interface
type Adapter interface {
	Start(ctx context.Context) error
	Stop(ctx context.Context) error
}

// App represents application service
type App struct {
	adapters        []Adapter
	shutdownTimeout time.Duration

	logger *log.Logger
}

// New provides new service application
func New(logger *log.Logger) *App {
	return &App{
		shutdownTimeout: 5 * time.Second, // Default shutdown timeout
		logger:          logger,
	}
}

// AddAdapters adds adapters to application service
func (app *App) AddAdapters(adapters ...Adapter) {
	app.adapters = append(app.adapters, adapters...)
}

// WithShutdownTimeout overrides default shutdown timout
func (app *App) WithShutdownTimeout(timeout time.Duration) {
	app.shutdownTimeout = timeout
}

// Run runs the service application
func (app *App) Run(ctx context.Context) {
	stop := func() {
		ctxWithTimeout, cancel := context.WithTimeout(ctx, app.shutdownTimeout)
		defer cancel()

		app.logger.Info(ctxWithTimeout, "shutting down...\n")

		errCh := make(chan error, len(app.adapters))

		for _, adapter := range app.adapters {
			go func(adapter Adapter) {
				errCh <- adapter.Stop(ctxWithTimeout)
			}(adapter)
		}

		for i := 0; i < len(app.adapters); i++ {
			if err := <-errCh; err != nil {
				// calling Goexit terminates that goroutine without returning (previous defers would not run)
				go func(err error) {
					app.logger.Critical(ctxWithTimeout, "shutdown error: %v\n", err)
					os.Exit(1)
				}(err)
				return
			}
		}

		app.logger.Info(ctxWithTimeout, "gracefully stopped\n")
	}

	for _, adapter := range app.adapters {
		go func(adapter Adapter) {
			app.logger.Critical(ctx, "adapter start error: %v\n", adapter.Start(ctx))
			os.Exit(1)
		}(adapter)
	}

	shutdown.GracefulStop(stop)
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Vitess 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 vreplication

import (
	"bytes"
	"fmt"
	"io"
	"strconv"
	"strings"
	"time"

	"github.com/golang/protobuf/proto"
	"golang.org/x/net/context"

	"vitess.io/vitess/go/mysql"
	"vitess.io/vitess/go/sqltypes"
	"vitess.io/vitess/go/vt/binlog/binlogplayer"
	"vitess.io/vitess/go/vt/log"
	"vitess.io/vitess/go/vt/sqlparser"

	binlogdatapb "vitess.io/vitess/go/vt/proto/binlogdata"
	querypb "vitess.io/vitess/go/vt/proto/query"
)

type vcopier struct {
	vr        *vreplicator
	tablePlan *TablePlan
}

func newVCopier(vr *vreplicator) *vcopier {
	return &vcopier{
		vr: vr,
	}
}

func (vc *vcopier) initTablesForCopy(ctx context.Context) error {
	defer vc.vr.dbClient.Rollback()

	plan, err := buildReplicatorPlan(vc.vr.source.Filter, vc.vr.tableKeys, nil)
	if err != nil {
		return err
	}
	if err := vc.vr.dbClient.Begin(); err != nil {
		return err
	}
	// Insert the table list only if at least one table matches.
	if len(plan.TargetTables) != 0 {
		var buf strings.Builder
		buf.WriteString("insert into _vt.copy_state(vrepl_id, table_name) values ")
		prefix := ""
		for name := range plan.TargetTables {
			fmt.Fprintf(&buf, "%s(%d, %s)", prefix, vc.vr.id, encodeString(name))
			prefix = ", "
		}
		if _, err := vc.vr.dbClient.Execute(buf.String()); err != nil {
			return err
		}
		if err := vc.vr.setState(binlogplayer.VReplicationCopying, ""); err != nil {
			return err
		}
	} else {
		if err := vc.vr.setState(binlogplayer.BlpStopped, "There is nothing to replicate"); err != nil {
			return err
		}
	}
	return vc.vr.dbClient.Commit()
}

func (vc *vcopier) copyNext(ctx context.Context, settings binlogplayer.VRSettings) error {
	qr, err := vc.vr.dbClient.Execute(fmt.Sprintf("select table_name, lastpk from _vt.copy_state where vrepl_id=%d", vc.vr.id))
	if err != nil {
		return err
	}
	var tableToCopy string
	copyState := make(map[string]*sqltypes.Result)
	for _, row := range qr.Rows {
		tableName := row[0].ToString()
		lastpk := row[1].ToString()
		if tableToCopy == "" {
			tableToCopy = tableName
		}
		copyState[tableName] = nil
		if lastpk != "" {
			var r querypb.QueryResult
			if err := proto.UnmarshalText(lastpk, &r); err != nil {
				return err
			}
			copyState[tableName] = sqltypes.Proto3ToResult(&r)
		}
	}
	if len(copyState) == 0 {
		return fmt.Errorf("unexpected: there are no tables to copy")
	}
	if err := vc.catchup(ctx, copyState); err != nil {
		return err
	}
	return vc.copyTable(ctx, tableToCopy, copyState)
}

func (vc *vcopier) catchup(ctx context.Context, copyState map[string]*sqltypes.Result) error {
	ctx, cancel := context.WithCancel(ctx)
	defer cancel()

	settings, err := binlogplayer.ReadVRSettings(vc.vr.dbClient, vc.vr.id)
	if err != nil {
		return err
	}
	// If there's no start position, it means we're copying the
	// first table. So, there's nothing to catch up to.
	if settings.StartPos.IsZero() {
		return nil
	}

	// Start vreplication.
	errch := make(chan error, 1)
	go func() {
		errch <- newVPlayer(vc.vr, settings, copyState, mysql.Position{}).play(ctx)
	}()

	// Wait for catchup.
	tkr := time.NewTicker(waitRetryTime)
	defer tkr.Stop()
	seconds := int64(replicaLagTolerance / time.Second)
	for {
		sbm := vc.vr.stats.SecondsBehindMaster.Get()
		if sbm < seconds {
			cancel()
			// Make sure vplayer returns before returning.
			<-errch
			return nil
		}
		select {
		case err := <-errch:
			if err != nil {
				return err
			}
			return io.EOF
		case <-ctx.Done():
			// Make sure vplayer returns before returning.
			<-errch
			return io.EOF
		case <-tkr.C:
		}
	}
}

func (vc *vcopier) copyTable(ctx context.Context, tableName string, copyState map[string]*sqltypes.Result) error {
	defer vc.vr.dbClient.Rollback()

	log.Infof("Copying table %s, lastpk: %v", tableName, copyState[tableName])

	plan, err := buildReplicatorPlan(vc.vr.source.Filter, vc.vr.tableKeys, nil)
	if err != nil {
		return err
	}

	initialPlan, ok := plan.TargetTables[tableName]
	if !ok {
		return fmt.Errorf("plan not found for table: %s, current plans are: %#v", tableName, plan.TargetTables)
	}

	err = vc.vr.sourceVStreamer.Open(ctx)
	if err != nil {
		return fmt.Errorf("error opening vsclient: %v", err)
	}
	defer vc.vr.sourceVStreamer.Close(ctx)

	ctx, cancel := context.WithTimeout(ctx, copyTimeout)
	defer cancel()

	var lastpkpb *querypb.QueryResult
	if lastpkqr := copyState[tableName]; lastpkqr != nil {
		lastpkpb = sqltypes.ResultToProto3(lastpkqr)
	}

	var pkfields []*querypb.Field
	var updateCopyState *sqlparser.ParsedQuery
	err = vc.vr.sourceVStreamer.VStreamRows(ctx, initialPlan.SendRule.Filter, lastpkpb, func(rows *binlogdatapb.VStreamRowsResponse) error {
		select {
		case <-ctx.Done():
			return io.EOF
		default:
		}
		if vc.tablePlan == nil {
			if len(rows.Fields) == 0 {
				return fmt.Errorf("expecting field event first, got: %v", rows)
			}
			if err := vc.fastForward(ctx, copyState, rows.Gtid); err != nil {
				return err
			}
			fieldEvent := &binlogdatapb.FieldEvent{
				TableName: initialPlan.SendRule.Match,
				Fields:    rows.Fields,
			}
			vc.tablePlan, err = plan.buildExecutionPlan(fieldEvent)
			if err != nil {
				return err
			}
			pkfields = rows.Pkfields
			buf := sqlparser.NewTrackedBuffer(nil)
			buf.Myprintf("update _vt.copy_state set lastpk=%a where vrepl_id=%s and table_name=%s", ":lastpk", strconv.Itoa(int(vc.vr.id)), encodeString(tableName))
			updateCopyState = buf.ParsedQuery()
		}
		if len(rows.Rows) == 0 {
			return nil
		}
		// The number of rows we receive depends on the packet size set
		// for the row streamer. Since the packet size is roughly equivalent
		// to data size, this should map to a uniform amount of pages affected
		// per statement. A packet size of 30K will roughly translate to 8
		// mysql pages of 4K each.
		if err := vc.vr.dbClient.Begin(); err != nil {
			return err
		}

		_, err = vc.tablePlan.applyBulkInsert(rows, func(sql string) (*sqltypes.Result, error) {
			return vc.vr.dbClient.ExecuteWithRetry(ctx, sql)
		})
		if err != nil {
			return err
		}

		var buf bytes.Buffer
		err = proto.CompactText(&buf, &querypb.QueryResult{
			Fields: pkfields,
			Rows:   []*querypb.Row{rows.Lastpk},
		})
		if err != nil {
			return err
		}
		bv := map[string]*querypb.BindVariable{
			"lastpk": {
				Type:  sqltypes.VarBinary,
				Value: buf.Bytes(),
			},
		}
		updateState, err := updateCopyState.GenerateQuery(bv, nil)
		if err != nil {
			return err
		}
		if _, err := vc.vr.dbClient.Execute(updateState); err != nil {
			return err
		}

		if err := vc.vr.dbClient.Commit(); err != nil {
			return err
		}
		return nil
	})
	// If there was a timeout, return without an error.
	select {
	case <-ctx.Done():
		return nil
	default:
	}
	if err != nil {
		return err
	}
	buf := sqlparser.NewTrackedBuffer(nil)
	buf.Myprintf("delete from _vt.copy_state where vrepl_id=%s and table_name=%s", strconv.Itoa(int(vc.vr.id)), encodeString(tableName))
	if _, err := vc.vr.dbClient.Execute(buf.String()); err != nil {
		return err
	}
	return nil
}

func (vc *vcopier) fastForward(ctx context.Context, copyState map[string]*sqltypes.Result, gtid string) error {
	pos, err := mysql.DecodePosition(gtid)
	if err != nil {
		return err
	}
	settings, err := binlogplayer.ReadVRSettings(vc.vr.dbClient, vc.vr.id)
	if err != nil {
		return err
	}
	if settings.StartPos.IsZero() {
		update := binlogplayer.GenerateUpdatePos(vc.vr.id, pos, time.Now().Unix(), 0)
		_, err := vc.vr.dbClient.Execute(update)
		return err
	}
	return newVPlayer(vc.vr, settings, copyState, pos).play(ctx)
}
<commit_msg>Enables vreplication to run directly from MySQL<commit_after>/*
Copyright 2019 The Vitess 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 vreplication

import (
	"bytes"
	"fmt"
	"io"
	"strconv"
	"strings"
	"time"

	"github.com/golang/protobuf/proto"
	"golang.org/x/net/context"

	"vitess.io/vitess/go/mysql"
	"vitess.io/vitess/go/sqltypes"
	"vitess.io/vitess/go/vt/binlog/binlogplayer"
	"vitess.io/vitess/go/vt/log"
	"vitess.io/vitess/go/vt/sqlparser"

	binlogdatapb "vitess.io/vitess/go/vt/proto/binlogdata"
	querypb "vitess.io/vitess/go/vt/proto/query"
)

type vcopier struct {
	vr        *vreplicator
	tablePlan *TablePlan
}

func newVCopier(vr *vreplicator) *vcopier {
	return &vcopier{
		vr: vr,
	}
}

func (vc *vcopier) initTablesForCopy(ctx context.Context) error {
	defer vc.vr.dbClient.Rollback()

	plan, err := buildReplicatorPlan(vc.vr.source.Filter, vc.vr.tableKeys, nil)
	if err != nil {
		return err
	}
	if err := vc.vr.dbClient.Begin(); err != nil {
		return err
	}
	// Insert the table list only if at least one table matches.
	if len(plan.TargetTables) != 0 {
		var buf strings.Builder
		buf.WriteString("insert into _vt.copy_state(vrepl_id, table_name) values ")
		prefix := ""
		for name := range plan.TargetTables {
			fmt.Fprintf(&buf, "%s(%d, %s)", prefix, vc.vr.id, encodeString(name))
			prefix = ", "
		}
		if _, err := vc.vr.dbClient.Execute(buf.String()); err != nil {
			return err
		}
		if err := vc.vr.setState(binlogplayer.VReplicationCopying, ""); err != nil {
			return err
		}
	} else {
		if err := vc.vr.setState(binlogplayer.BlpStopped, "There is nothing to replicate"); err != nil {
			return err
		}
	}
	return vc.vr.dbClient.Commit()
}

func (vc *vcopier) copyNext(ctx context.Context, settings binlogplayer.VRSettings) error {
	qr, err := vc.vr.dbClient.Execute(fmt.Sprintf("select table_name, lastpk from _vt.copy_state where vrepl_id=%d", vc.vr.id))
	if err != nil {
		return err
	}
	var tableToCopy string
	copyState := make(map[string]*sqltypes.Result)
	for _, row := range qr.Rows {
		tableName := row[0].ToString()
		lastpk := row[1].ToString()
		if tableToCopy == "" {
			tableToCopy = tableName
		}
		copyState[tableName] = nil
		if lastpk != "" {
			var r querypb.QueryResult
			if err := proto.UnmarshalText(lastpk, &r); err != nil {
				return err
			}
			copyState[tableName] = sqltypes.Proto3ToResult(&r)
		}
	}
	if len(copyState) == 0 {
		return fmt.Errorf("unexpected: there are no tables to copy")
	}
	if err := vc.catchup(ctx, copyState); err != nil {
		return err
	}
	return vc.copyTable(ctx, tableToCopy, copyState)
}

func (vc *vcopier) catchup(ctx context.Context, copyState map[string]*sqltypes.Result) error {
	ctx, cancel := context.WithCancel(ctx)
	defer cancel()

	settings, err := binlogplayer.ReadVRSettings(vc.vr.dbClient, vc.vr.id)
	if err != nil {
		return err
	}
	// If there's no start position, it means we're copying the
	// first table. So, there's nothing to catch up to.
	if settings.GtidStartPos.IsZero() {
		return nil
	}

	// Start vreplication.
	errch := make(chan error, 1)
	go func() {
		errch <- newVPlayer(vc.vr, settings, copyState, mysql.Position{}).play(ctx)
	}()

	// Wait for catchup.
	tkr := time.NewTicker(waitRetryTime)
	defer tkr.Stop()
	seconds := int64(replicaLagTolerance / time.Second)
	for {
		sbm := vc.vr.stats.SecondsBehindMaster.Get()
		if sbm < seconds {
			cancel()
			// Make sure vplayer returns before returning.
			<-errch
			return nil
		}
		select {
		case err := <-errch:
			if err != nil {
				return err
			}
			return io.EOF
		case <-ctx.Done():
			// Make sure vplayer returns before returning.
			<-errch
			return io.EOF
		case <-tkr.C:
		}
	}
}

func (vc *vcopier) copyTable(ctx context.Context, tableName string, copyState map[string]*sqltypes.Result) error {
	defer vc.vr.dbClient.Rollback()

	log.Infof("Copying table %s, lastpk: %v", tableName, copyState[tableName])

	plan, err := buildReplicatorPlan(vc.vr.source.Filter, vc.vr.tableKeys, nil)
	if err != nil {
		return err
	}

	initialPlan, ok := plan.TargetTables[tableName]
	if !ok {
		return fmt.Errorf("plan not found for table: %s, current plans are: %#v", tableName, plan.TargetTables)
	}

	err = vc.vr.sourceVStreamer.Open(ctx)
	if err != nil {
		return fmt.Errorf("error opening vsclient: %v", err)
	}
	defer vc.vr.sourceVStreamer.Close(ctx)

	ctx, cancel := context.WithTimeout(ctx, copyTimeout)
	defer cancel()

	var lastpkpb *querypb.QueryResult
	if lastpkqr := copyState[tableName]; lastpkqr != nil {
		lastpkpb = sqltypes.ResultToProto3(lastpkqr)
	}

	var pkfields []*querypb.Field
	var updateCopyState *sqlparser.ParsedQuery
	err = vc.vr.sourceVStreamer.VStreamRows(ctx, initialPlan.SendRule.Filter, lastpkpb, func(rows *binlogdatapb.VStreamRowsResponse) error {
		select {
		case <-ctx.Done():
			return io.EOF
		default:
		}
		if vc.tablePlan == nil {
			if len(rows.Fields) == 0 {
				return fmt.Errorf("expecting field event first, got: %v", rows)
			}
			if err := vc.fastForward(ctx, copyState, rows.Gtid); err != nil {
				return err
			}
			fieldEvent := &binlogdatapb.FieldEvent{
				TableName: initialPlan.SendRule.Match,
				Fields:    rows.Fields,
			}
			vc.tablePlan, err = plan.buildExecutionPlan(fieldEvent)
			if err != nil {
				return err
			}
			pkfields = rows.Pkfields
			buf := sqlparser.NewTrackedBuffer(nil)
			buf.Myprintf("update _vt.copy_state set lastpk=%a where vrepl_id=%s and table_name=%s", ":lastpk", strconv.Itoa(int(vc.vr.id)), encodeString(tableName))
			updateCopyState = buf.ParsedQuery()
		}
		if len(rows.Rows) == 0 {
			return nil
		}
		// The number of rows we receive depends on the packet size set
		// for the row streamer. Since the packet size is roughly equivalent
		// to data size, this should map to a uniform amount of pages affected
		// per statement. A packet size of 30K will roughly translate to 8
		// mysql pages of 4K each.
		if err := vc.vr.dbClient.Begin(); err != nil {
			return err
		}

		_, err = vc.tablePlan.applyBulkInsert(rows, func(sql string) (*sqltypes.Result, error) {
			return vc.vr.dbClient.ExecuteWithRetry(ctx, sql)
		})
		if err != nil {
			return err
		}

		var buf bytes.Buffer
		err = proto.CompactText(&buf, &querypb.QueryResult{
			Fields: pkfields,
			Rows:   []*querypb.Row{rows.Lastpk},
		})
		if err != nil {
			return err
		}
		bv := map[string]*querypb.BindVariable{
			"lastpk": {
				Type:  sqltypes.VarBinary,
				Value: buf.Bytes(),
			},
		}
		updateState, err := updateCopyState.GenerateQuery(bv, nil)
		if err != nil {
			return err
		}
		if _, err := vc.vr.dbClient.Execute(updateState); err != nil {
			return err
		}

		if err := vc.vr.dbClient.Commit(); err != nil {
			return err
		}
		return nil
	})
	// If there was a timeout, return without an error.
	select {
	case <-ctx.Done():
		return nil
	default:
	}
	if err != nil {
		return err
	}
	buf := sqlparser.NewTrackedBuffer(nil)
	buf.Myprintf("delete from _vt.copy_state where vrepl_id=%s and table_name=%s", strconv.Itoa(int(vc.vr.id)), encodeString(tableName))
	if _, err := vc.vr.dbClient.Execute(buf.String()); err != nil {
		return err
	}
	return nil
}

func (vc *vcopier) fastForward(ctx context.Context, copyState map[string]*sqltypes.Result, gtid string) error {
	pos, err := mysql.DecodePosition(gtid)
	if err != nil {
		return err
	}
	settings, err := binlogplayer.ReadVRSettings(vc.vr.dbClient, vc.vr.id)
	if err != nil {
		return err
	}
	if settings.GtidStartPos.IsZero() {
		update := binlogplayer.GenerateUpdatePos(vc.vr.id, pos, time.Now().Unix(), 0)
		_, err := vc.vr.dbClient.Execute(update)
		return err
	}
	return newVPlayer(vc.vr, settings, copyState, pos).play(ctx)
}
<|endoftext|>


<commit_before>package main

import (
	"database/sql"
	"database/sql/driver"
	"log"
	"fmt"
	"os"

	"github.com/shogo82148/go-sql-proxy"
	"github.com/mattn/go-sqlite3"
)

var _ = fmt.Print

func main() {
	fmt.Printf("Remove\n")
	os.Remove("./go_sql_proxy.sqlite3")
	db, err := open("./go_sql_proxy.sqlite3", true)
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()
	fmt.Printf("db = %v\n", db)

	create := `
	create table test (id integer not null primary key, name text);
	delete from test;
	`

	result, err := db.Exec(create)
	if err != nil {
		log.Fatal(err)
	}
	affected, err := result.RowsAffected()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("result = %v\n", affected)
}

func open(dsn string, useProxy bool) (*sql.DB, error) {
	if useProxy {
		hooks := &proxy.Hooks{
			PreExec: func(stmt *proxy.Stmt, args []driver.Value) (interface{}, error) {
				fmt.Printf("PreExec: stmt=%v\n", stmt.QueryString)
				//panic(stmt.QueryString)
				return nil, nil
			},
			PreQuery: func(stmt *proxy.Stmt, args []driver.Value) (interface{}, error) {
				return nil, nil
			},
			PreBegin: func(_ *proxy.Conn) (interface{}, error) {
				return nil, nil
			},
			PreCommit: func(_ *proxy.Tx) (interface{}, error) {
				return nil, nil
			},
			PreRollback: func(_ *proxy.Tx) (interface{}, error) {
				return nil, nil
			},
		}
		sql.Register("sqlite3-trace", proxy.NewProxy(&sqlite3.SQLiteDriver{}, hooks))
		return sql.Open("sqlite3-trace", dsn)
	} else {
		return sql.Open("sqlite3", dsn)
	}
}
<commit_msg>Check<commit_after>package main

import (
	"database/sql"
	"database/sql/driver"
	"log"
	"fmt"
	"os"

	"github.com/shogo82148/go-sql-proxy"
	"github.com/mattn/go-sqlite3"
)

var _ = fmt.Print

func main() {
	fmt.Printf("Remove\n")
	os.Remove("./go_sql_proxy.sqlite3")
	db, err := open("./go_sql_proxy.sqlite3", true)
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()
	fmt.Printf("db = %v\n", db)

	create := `
	create table test (id integer not null primary key, name text);
	delete from test;
	`

	result, err := db.Exec(create)
	if err != nil {
		log.Fatal(err)
	}
	affected, err := result.RowsAffected()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("result = %v\n", affected)
}

func open(dsn string, useProxy bool) (*sql.DB, error) {
	if useProxy {
		hooks := &proxy.Hooks{
			PreExec: func(stmt *proxy.Stmt, args []driver.Value) (interface{}, error) {
				fmt.Printf("PreExec: stmt=%v\n", stmt.QueryString)
				return nil, fmt.Errorf("error from go-sql-proxy!")
				//return nil, nil
			},
			PreQuery: func(stmt *proxy.Stmt, args []driver.Value) (interface{}, error) {
				return nil, nil
			},
			PreBegin: func(_ *proxy.Conn) (interface{}, error) {
				return nil, nil
			},
			PreCommit: func(_ *proxy.Tx) (interface{}, error) {
				return nil, nil
			},
			PreRollback: func(_ *proxy.Tx) (interface{}, error) {
				return nil, nil
			},
		}
		sql.Register("sqlite3-trace", proxy.NewProxy(&sqlite3.SQLiteDriver{}, hooks))
		return sql.Open("sqlite3-trace", dsn)
	} else {
		return sql.Open("sqlite3", dsn)
	}
}
<|endoftext|>


<commit_before>package mount

import (
	"strings"
)

// Parse fstab type mount options into mount() flags
// and device specific data
func parseOptions(options string) (int, string) {
	var (
		flag int
		data []string
	)

	flags := map[string]struct {
		clear bool
		flag  int
	}{
		"defaults":      {false, 0},
		"ro":            {false, RDONLY},
		"rw":            {true, RDONLY},
		"suid":          {true, NOSUID},
		"nosuid":        {false, NOSUID},
		"dev":           {true, NODEV},
		"nodev":         {false, NODEV},
		"exec":          {true, NOEXEC},
		"noexec":        {false, NOEXEC},
		"sync":          {false, SYNCHRONOUS},
		"async":         {true, SYNCHRONOUS},
		"dirsync":       {false, DIRSYNC},
		"remount":       {false, REMOUNT},
		"mand":          {false, MANDLOCK},
		"nomand":        {true, MANDLOCK},
		"atime":         {true, NOATIME},
		"noatime":       {false, NOATIME},
		"diratime":      {true, NODIRATIME},
		"nodiratime":    {false, NODIRATIME},
		"bind":          {false, BIND},
		"rbind":         {false, RBIND},
		"unbindable":    {false, UNBINDABLE},
		"runbindable":   {false, RUNBINDABLE},
		"private":       {false, PRIVATE},
		"rprivate":      {false, RPRIVATE},
		"shared":        {false, SHARED},
		"rshared":       {false, RSHARED},
		"slave":         {false, SLAVE},
		"rslave":        {false, RSLAVE},
		"relatime":      {false, RELATIME},
		"norelatime":    {true, RELATIME},
		"strictatime":   {false, STRICTATIME},
		"nostrictatime": {true, STRICTATIME},
	}

	for _, o := range strings.Split(options, ",") {
		// If the option does not exist in the flags table or the flag
		// is not supported on the platform,
		// then it is a data value for a specific fs type
		if f, exists := flags[o]; exists && f.flag != 0 {
			if f.clear {
				flag &= ^f.flag
			} else {
				flag |= f.flag
			}
		} else {
			data = append(data, o)
		}
	}
	return flag, strings.Join(data, ",")
}
<commit_msg>This patch adds --tmpfs as a option for mounting tmpfs on directories<commit_after>package mount

import (
	"fmt"
	"strings"
)

// Parse fstab type mount options into mount() flags
// and device specific data
func parseOptions(options string) (int, string) {
	var (
		flag int
		data []string
	)

	flags := map[string]struct {
		clear bool
		flag  int
	}{
		"defaults":      {false, 0},
		"ro":            {false, RDONLY},
		"rw":            {true, RDONLY},
		"suid":          {true, NOSUID},
		"nosuid":        {false, NOSUID},
		"dev":           {true, NODEV},
		"nodev":         {false, NODEV},
		"exec":          {true, NOEXEC},
		"noexec":        {false, NOEXEC},
		"sync":          {false, SYNCHRONOUS},
		"async":         {true, SYNCHRONOUS},
		"dirsync":       {false, DIRSYNC},
		"remount":       {false, REMOUNT},
		"mand":          {false, MANDLOCK},
		"nomand":        {true, MANDLOCK},
		"atime":         {true, NOATIME},
		"noatime":       {false, NOATIME},
		"diratime":      {true, NODIRATIME},
		"nodiratime":    {false, NODIRATIME},
		"bind":          {false, BIND},
		"rbind":         {false, RBIND},
		"unbindable":    {false, UNBINDABLE},
		"runbindable":   {false, RUNBINDABLE},
		"private":       {false, PRIVATE},
		"rprivate":      {false, RPRIVATE},
		"shared":        {false, SHARED},
		"rshared":       {false, RSHARED},
		"slave":         {false, SLAVE},
		"rslave":        {false, RSLAVE},
		"relatime":      {false, RELATIME},
		"norelatime":    {true, RELATIME},
		"strictatime":   {false, STRICTATIME},
		"nostrictatime": {true, STRICTATIME},
	}

	for _, o := range strings.Split(options, ",") {
		// If the option does not exist in the flags table or the flag
		// is not supported on the platform,
		// then it is a data value for a specific fs type
		if f, exists := flags[o]; exists && f.flag != 0 {
			if f.clear {
				flag &= ^f.flag
			} else {
				flag |= f.flag
			}
		} else {
			data = append(data, o)
		}
	}
	return flag, strings.Join(data, ",")
}

// ParseTmpfsOptions parse fstab type mount options into flags and data
func ParseTmpfsOptions(options string) (int, string, error) {
	flags, data := parseOptions(options)
	validFlags := map[string]bool{
		"size":      true,
		"mode":      true,
		"uid":       true,
		"gid":       true,
		"nr_inodes": true,
		"nr_blocks": true,
		"mpol":      true,
	}
	for _, o := range strings.Split(data, ",") {
		opt := strings.SplitN(o, "=", 2)
		if !validFlags[opt[0]] {
			return 0, "", fmt.Errorf("Invalid tmpfs option %q", opt)
		}
	}
	return flags, data, nil
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Skaffold 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 validator

import (
	"context"
	"fmt"
	"testing"

	"github.com/GoogleContainerTools/skaffold/testutil"
	"github.com/google/go-cmp/cmp"
	v1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	fakekubeclientset "k8s.io/client-go/kubernetes/fake"

	"github.com/GoogleContainerTools/skaffold/proto"
)

func TestRun(t *testing.T) {
	tests := []struct {
		description string
		pods        []*v1.Pod
		events      []v1.Event
		expected    []Resource
	}{
		{
			description: "pod don't exist in test namespace",
			pods: []*v1.Pod{{
				ObjectMeta: metav1.ObjectMeta{
					Name:      "foo",
					Namespace: "foo-ns",
				},
				TypeMeta: metav1.TypeMeta{Kind: "Pod"}},
			},
			expected: nil,
		},
		{
			description: "pod is Waiting conditions with error",
			pods: []*v1.Pod{{
				ObjectMeta: metav1.ObjectMeta{
					Name:      "foo",
					Namespace: "test",
				},
				TypeMeta: metav1.TypeMeta{Kind: "Pod"},
				Status: v1.PodStatus{
					Phase:      v1.PodPending,
					Conditions: []v1.PodCondition{{Type: v1.PodScheduled, Status: v1.ConditionTrue}},
					ContainerStatuses: []v1.ContainerStatus{
						{
							Name:  "foo-container",
							Image: "foo-image",
							State: v1.ContainerState{
								Waiting: &v1.ContainerStateWaiting{
									Reason:  "ErrImagePull",
									Message: "rpc error: code = Unknown desc = Error response from daemon: pull access denied for leeroy-web1, repository does not exist or may require 'docker login': denied: requested access to the resource is denied",
								},
							},
						},
					},
				},
			}},
			expected: []Resource{NewResource("test", "Pod", "foo", "Pending",
				fmt.Errorf("container foo-container is waiting to start: foo-image can't be pulled"),
				proto.StatusCode_STATUSCHECK_IMAGE_PULL_ERR)},
		},
		{
			description: "pod is Waiting condition due to ErrImageBackOffPullErr",
			pods: []*v1.Pod{{
				ObjectMeta: metav1.ObjectMeta{
					Name:      "foo",
					Namespace: "test",
				},
				TypeMeta: metav1.TypeMeta{Kind: "Pod"},
				Status: v1.PodStatus{
					Phase:      v1.PodPending,
					Conditions: []v1.PodCondition{{Type: v1.PodScheduled, Status: v1.ConditionTrue}},
					ContainerStatuses: []v1.ContainerStatus{
						{
							Name:  "foo-container",
							Image: "foo-image",
							State: v1.ContainerState{
								Waiting: &v1.ContainerStateWaiting{
									Reason:  "ErrImagePullBackOff",
									Message: "rpc error: code = Unknown desc = Error response from daemon: pull access denied for leeroy-web1, repository does not exist or may require 'docker login': denied: requested access to the resource is denied",
								},
							},
						},
					},
				},
			}},
			expected: []Resource{NewResource("test", "Pod", "foo", "Pending",
				fmt.Errorf("container foo-container is waiting to start: foo-image can't be pulled"),
				proto.StatusCode_STATUSCHECK_IMAGE_PULL_ERR)},
		},
		{
			description: "pod is Waiting due to Image Backoff Pull error",
			pods: []*v1.Pod{{
				ObjectMeta: metav1.ObjectMeta{
					Name:      "foo",
					Namespace: "test",
				},
				TypeMeta: metav1.TypeMeta{Kind: "Pod"},
				Status: v1.PodStatus{
					Phase:      v1.PodPending,
					Conditions: []v1.PodCondition{{Type: v1.PodScheduled, Status: v1.ConditionTrue}},
					ContainerStatuses: []v1.ContainerStatus{
						{
							Name:  "foo-container",
							Image: "foo-image",
							State: v1.ContainerState{
								Waiting: &v1.ContainerStateWaiting{
									Reason:  "ImagePullBackOff",
									Message: "rpc error: code = Unknown desc = Error response from daemon: pull access denied for leeroy-web1, repository does not exist or may require 'docker login': denied: requested access to the resource is denied",
								},
							},
						},
					},
				},
			}},
			expected: []Resource{NewResource("test", "Pod", "foo", "Pending",
				fmt.Errorf("container foo-container is waiting to start: foo-image can't be pulled"),
				proto.StatusCode_STATUSCHECK_IMAGE_PULL_ERR)},
		},
		{
			description: "pod is in Terminated State",
			pods: []*v1.Pod{{
				ObjectMeta: metav1.ObjectMeta{
					Name:      "foo",
					Namespace: "test",
				},
				TypeMeta: metav1.TypeMeta{Kind: "Pod"},
				Status: v1.PodStatus{
					Phase:      v1.PodSucceeded,
					Conditions: []v1.PodCondition{{Type: v1.PodScheduled, Status: v1.ConditionTrue}},
				},
			}},
			expected: []Resource{NewResource("test", "Pod", "foo", "Succeeded", nil,
				proto.StatusCode_STATUSCHECK_SUCCESS)},
		},
		{
			description: "pod is in Stable State",
			pods: []*v1.Pod{{
				ObjectMeta: metav1.ObjectMeta{
					Name:      "foo",
					Namespace: "test",
				},
				TypeMeta: metav1.TypeMeta{Kind: "Pod"},
				Status: v1.PodStatus{
					Phase:      v1.PodRunning,
					Conditions: []v1.PodCondition{{Type: v1.PodScheduled, Status: v1.ConditionTrue}},
					ContainerStatuses: []v1.ContainerStatus{
						{
							Name:  "foo-container",
							State: v1.ContainerState{Running: &v1.ContainerStateRunning{}},
						},
					},
				},
			}},
			expected: []Resource{NewResource("test", "Pod", "foo", "Running", nil,
				proto.StatusCode_STATUSCHECK_SUCCESS)},
		},
		{
			description: "pod condition unknown",
			pods: []*v1.Pod{{
				ObjectMeta: metav1.ObjectMeta{
					Name:      "foo",
					Namespace: "test",
				},
				TypeMeta: metav1.TypeMeta{Kind: "Pod"},
				Status: v1.PodStatus{
					Phase: v1.PodPending,
					Conditions: []v1.PodCondition{{
						Type:    v1.PodScheduled,
						Status:  v1.ConditionUnknown,
						Message: "could not determine",
					}},
				},
			}},
			expected: []Resource{NewResource("test", "Pod", "foo", "Pending",
				fmt.Errorf("could not determine"), proto.StatusCode_STATUSCHECK_UNKNOWN)},
		},
		{
			description: "pod could not be scheduled",
			pods: []*v1.Pod{{
				ObjectMeta: metav1.ObjectMeta{
					Name:      "foo",
					Namespace: "test",
				},
				TypeMeta: metav1.TypeMeta{Kind: "Pod"},
				Status: v1.PodStatus{
					Phase: v1.PodPending,
					Conditions: []v1.PodCondition{{
						Type:    v1.PodScheduled,
						Status:  v1.ConditionFalse,
						Reason:  v1.PodReasonUnschedulable,
						Message: "0/2 nodes are available: 1 node(s) had taint {node.kubernetes.io/disk-pressure: }, that the pod didn't tolerate, 1 node(s) had taint {node.kubernetes.io/unreachable: }, that the pod didn't tolerate",
					}},
				},
			}},
			expected: []Resource{NewResource("test", "Pod", "foo", "Pending",
				fmt.Errorf("Unschedulable: 0/2 nodes available: 1 node has disk pressure, 1 node is unreachable"),
				proto.StatusCode_STATUSCHECK_NODE_DISK_PRESSURE)},
		},
		{
			description: "pod is running but container terminated",
			pods: []*v1.Pod{{
				ObjectMeta: metav1.ObjectMeta{
					Name:      "foo",
					Namespace: "test",
				},
				TypeMeta: metav1.TypeMeta{Kind: "Pod"},
				Status: v1.PodStatus{
					Phase:      v1.PodRunning,
					Conditions: []v1.PodCondition{{Type: v1.PodScheduled, Status: v1.ConditionTrue}},
					ContainerStatuses: []v1.ContainerStatus{
						{
							Name:  "foo-container",
							State: v1.ContainerState{Terminated: &v1.ContainerStateTerminated{ExitCode: 1}},
						},
					},
				},
			}},
			expected: []Resource{NewResource("test", "Pod", "foo", "Running",
				fmt.Errorf("container foo-container terminated with exit code 1"),
				proto.StatusCode_STATUSCHECK_CONTAINER_TERMINATED)},
		},
		// Events Test cases
		{
			description: "pod condition with events",
			pods: []*v1.Pod{{
				ObjectMeta: metav1.ObjectMeta{
					Name:      "foo",
					Namespace: "test",
				},
				TypeMeta: metav1.TypeMeta{Kind: "Pod"},
				Status: v1.PodStatus{
					Phase: v1.PodPending,
					Conditions: []v1.PodCondition{{
						Type:    v1.PodScheduled,
						Status:  v1.ConditionUnknown,
						Message: "could not determine",
					}},
				},
			}},
			events: []v1.Event{
				{
					ObjectMeta: metav1.ObjectMeta{Namespace: "test"},
					Reason:     "eventCode", Type: "Warning", Message: "dummy event",
				},
			},
			expected: []Resource{NewResource("test", "Pod", "foo", "Pending",
				fmt.Errorf("eventCode: dummy event"), proto.StatusCode_STATUSCHECK_UNKNOWN)},
		},
		{
			description: "pod condition a warning event followed up normal",
			pods: []*v1.Pod{{
				ObjectMeta: metav1.ObjectMeta{
					Name:      "foo",
					Namespace: "test",
				},
				TypeMeta: metav1.TypeMeta{Kind: "Pod"},
				Status: v1.PodStatus{
					Phase: v1.PodPending,
					Conditions: []v1.PodCondition{{
						Type:    v1.PodScheduled,
						Status:  v1.ConditionUnknown,
						Message: "could not determine",
					}},
				},
			}},
			events: []v1.Event{
				{
					ObjectMeta: metav1.ObjectMeta{Name: "one", Namespace: "test"},
					Reason:     "eventCode", Type: "Warning", Message: "dummy event",
				},
				{
					ObjectMeta: metav1.ObjectMeta{Name: "two", Namespace: "test"},
					Reason:     "eventCode", Type: "Normal", Message: "success",
				},
			},
			expected: []Resource{NewResource("test", "Pod", "foo", "Pending",
				fmt.Errorf("could not determine"), proto.StatusCode_STATUSCHECK_UNKNOWN)},
		},
		{
			description: "pod condition a warning event followed up normal adds last warning seen",
			pods: []*v1.Pod{{
				ObjectMeta: metav1.ObjectMeta{
					Name:      "foo",
					Namespace: "test",
				},
				TypeMeta: metav1.TypeMeta{Kind: "Pod"},
				Status: v1.PodStatus{
					Phase: v1.PodPending,
					Conditions: []v1.PodCondition{{
						Type:    v1.PodScheduled,
						Status:  v1.ConditionUnknown,
						Message: "could not determine",
					}},
				},
			}},
			events: []v1.Event{
				{
					ObjectMeta: metav1.ObjectMeta{Name: "one", Namespace: "test"},
					Reason:     "eventCode", Type: "Warning", Message: "dummy event",
				},
				{
					ObjectMeta: metav1.ObjectMeta{Name: "two", Namespace: "test"}, Reason: "FailedScheduling", Type: "Warning",
					Message: "0/1 nodes are available: 1 node(s) had taint {key: value}, that the pod didn't tolerate.",
				},
			},
			expected: []Resource{NewResource("test", "Pod", "foo", "Pending",
				fmt.Errorf("0/1 nodes are available: 1 node(s) had taint {key: value}, that the pod didn't tolerate."), proto.StatusCode_STATUSCHECK_FAILED_SCHEDULING)},
		},
	}

	for _, test := range tests {
		testutil.Run(t, test.description, func(t *testutil.T) {
			rs := make([]runtime.Object, len(test.pods))
			for i, p := range test.pods {
				rs[i] = p
			}
			rs = append(rs, &v1.EventList{Items: test.events})
			f := fakekubeclientset.NewSimpleClientset(rs...)

			actual, err := NewPodValidator(f).Validate(context.Background(), "test", metav1.ListOptions{})
			t.CheckNoError(err)
			t.CheckDeepEqual(test.expected, actual, cmp.AllowUnexported(Resource{}), cmp.Comparer(func(x, y error) bool {
				if x == nil && y == nil {
					return true
				} else if x != nil && y != nil {
					return x.Error() == y.Error()
				}
				return false
			}))
		})
	}
}
<commit_msg>remove error capitalization<commit_after>/*
Copyright 2019 The Skaffold 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 validator

import (
	"context"
	"fmt"
	"testing"

	"github.com/GoogleContainerTools/skaffold/testutil"
	"github.com/google/go-cmp/cmp"
	v1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	fakekubeclientset "k8s.io/client-go/kubernetes/fake"

	"github.com/GoogleContainerTools/skaffold/proto"
)

func TestRun(t *testing.T) {
	tests := []struct {
		description string
		pods        []*v1.Pod
		events      []v1.Event
		expected    []Resource
	}{
		{
			description: "pod don't exist in test namespace",
			pods: []*v1.Pod{{
				ObjectMeta: metav1.ObjectMeta{
					Name:      "foo",
					Namespace: "foo-ns",
				},
				TypeMeta: metav1.TypeMeta{Kind: "Pod"}},
			},
			expected: nil,
		},
		{
			description: "pod is Waiting conditions with error",
			pods: []*v1.Pod{{
				ObjectMeta: metav1.ObjectMeta{
					Name:      "foo",
					Namespace: "test",
				},
				TypeMeta: metav1.TypeMeta{Kind: "Pod"},
				Status: v1.PodStatus{
					Phase:      v1.PodPending,
					Conditions: []v1.PodCondition{{Type: v1.PodScheduled, Status: v1.ConditionTrue}},
					ContainerStatuses: []v1.ContainerStatus{
						{
							Name:  "foo-container",
							Image: "foo-image",
							State: v1.ContainerState{
								Waiting: &v1.ContainerStateWaiting{
									Reason:  "ErrImagePull",
									Message: "rpc error: code = Unknown desc = Error response from daemon: pull access denied for leeroy-web1, repository does not exist or may require 'docker login': denied: requested access to the resource is denied",
								},
							},
						},
					},
				},
			}},
			expected: []Resource{NewResource("test", "Pod", "foo", "Pending",
				fmt.Errorf("container foo-container is waiting to start: foo-image can't be pulled"),
				proto.StatusCode_STATUSCHECK_IMAGE_PULL_ERR)},
		},
		{
			description: "pod is Waiting condition due to ErrImageBackOffPullErr",
			pods: []*v1.Pod{{
				ObjectMeta: metav1.ObjectMeta{
					Name:      "foo",
					Namespace: "test",
				},
				TypeMeta: metav1.TypeMeta{Kind: "Pod"},
				Status: v1.PodStatus{
					Phase:      v1.PodPending,
					Conditions: []v1.PodCondition{{Type: v1.PodScheduled, Status: v1.ConditionTrue}},
					ContainerStatuses: []v1.ContainerStatus{
						{
							Name:  "foo-container",
							Image: "foo-image",
							State: v1.ContainerState{
								Waiting: &v1.ContainerStateWaiting{
									Reason:  "ErrImagePullBackOff",
									Message: "rpc error: code = Unknown desc = Error response from daemon: pull access denied for leeroy-web1, repository does not exist or may require 'docker login': denied: requested access to the resource is denied",
								},
							},
						},
					},
				},
			}},
			expected: []Resource{NewResource("test", "Pod", "foo", "Pending",
				fmt.Errorf("container foo-container is waiting to start: foo-image can't be pulled"),
				proto.StatusCode_STATUSCHECK_IMAGE_PULL_ERR)},
		},
		{
			description: "pod is Waiting due to Image Backoff Pull error",
			pods: []*v1.Pod{{
				ObjectMeta: metav1.ObjectMeta{
					Name:      "foo",
					Namespace: "test",
				},
				TypeMeta: metav1.TypeMeta{Kind: "Pod"},
				Status: v1.PodStatus{
					Phase:      v1.PodPending,
					Conditions: []v1.PodCondition{{Type: v1.PodScheduled, Status: v1.ConditionTrue}},
					ContainerStatuses: []v1.ContainerStatus{
						{
							Name:  "foo-container",
							Image: "foo-image",
							State: v1.ContainerState{
								Waiting: &v1.ContainerStateWaiting{
									Reason:  "ImagePullBackOff",
									Message: "rpc error: code = Unknown desc = Error response from daemon: pull access denied for leeroy-web1, repository does not exist or may require 'docker login': denied: requested access to the resource is denied",
								},
							},
						},
					},
				},
			}},
			expected: []Resource{NewResource("test", "Pod", "foo", "Pending",
				fmt.Errorf("container foo-container is waiting to start: foo-image can't be pulled"),
				proto.StatusCode_STATUSCHECK_IMAGE_PULL_ERR)},
		},
		{
			description: "pod is in Terminated State",
			pods: []*v1.Pod{{
				ObjectMeta: metav1.ObjectMeta{
					Name:      "foo",
					Namespace: "test",
				},
				TypeMeta: metav1.TypeMeta{Kind: "Pod"},
				Status: v1.PodStatus{
					Phase:      v1.PodSucceeded,
					Conditions: []v1.PodCondition{{Type: v1.PodScheduled, Status: v1.ConditionTrue}},
				},
			}},
			expected: []Resource{NewResource("test", "Pod", "foo", "Succeeded", nil,
				proto.StatusCode_STATUSCHECK_SUCCESS)},
		},
		{
			description: "pod is in Stable State",
			pods: []*v1.Pod{{
				ObjectMeta: metav1.ObjectMeta{
					Name:      "foo",
					Namespace: "test",
				},
				TypeMeta: metav1.TypeMeta{Kind: "Pod"},
				Status: v1.PodStatus{
					Phase:      v1.PodRunning,
					Conditions: []v1.PodCondition{{Type: v1.PodScheduled, Status: v1.ConditionTrue}},
					ContainerStatuses: []v1.ContainerStatus{
						{
							Name:  "foo-container",
							State: v1.ContainerState{Running: &v1.ContainerStateRunning{}},
						},
					},
				},
			}},
			expected: []Resource{NewResource("test", "Pod", "foo", "Running", nil,
				proto.StatusCode_STATUSCHECK_SUCCESS)},
		},
		{
			description: "pod condition unknown",
			pods: []*v1.Pod{{
				ObjectMeta: metav1.ObjectMeta{
					Name:      "foo",
					Namespace: "test",
				},
				TypeMeta: metav1.TypeMeta{Kind: "Pod"},
				Status: v1.PodStatus{
					Phase: v1.PodPending,
					Conditions: []v1.PodCondition{{
						Type:    v1.PodScheduled,
						Status:  v1.ConditionUnknown,
						Message: "could not determine",
					}},
				},
			}},
			expected: []Resource{NewResource("test", "Pod", "foo", "Pending",
				fmt.Errorf("could not determine"), proto.StatusCode_STATUSCHECK_UNKNOWN)},
		},
		{
			description: "pod could not be scheduled",
			pods: []*v1.Pod{{
				ObjectMeta: metav1.ObjectMeta{
					Name:      "foo",
					Namespace: "test",
				},
				TypeMeta: metav1.TypeMeta{Kind: "Pod"},
				Status: v1.PodStatus{
					Phase: v1.PodPending,
					Conditions: []v1.PodCondition{{
						Type:    v1.PodScheduled,
						Status:  v1.ConditionFalse,
						Reason:  v1.PodReasonUnschedulable,
						Message: "0/2 nodes are available: 1 node(s) had taint {node.kubernetes.io/disk-pressure: }, that the pod didn't tolerate, 1 node(s) had taint {node.kubernetes.io/unreachable: }, that the pod didn't tolerate",
					}},
				},
			}},
			expected: []Resource{NewResource("test", "Pod", "foo", "Pending",
				fmt.Errorf("Unschedulable: 0/2 nodes available: 1 node has disk pressure, 1 node is unreachable"),
				proto.StatusCode_STATUSCHECK_NODE_DISK_PRESSURE)},
		},
		{
			description: "pod is running but container terminated",
			pods: []*v1.Pod{{
				ObjectMeta: metav1.ObjectMeta{
					Name:      "foo",
					Namespace: "test",
				},
				TypeMeta: metav1.TypeMeta{Kind: "Pod"},
				Status: v1.PodStatus{
					Phase:      v1.PodRunning,
					Conditions: []v1.PodCondition{{Type: v1.PodScheduled, Status: v1.ConditionTrue}},
					ContainerStatuses: []v1.ContainerStatus{
						{
							Name:  "foo-container",
							State: v1.ContainerState{Terminated: &v1.ContainerStateTerminated{ExitCode: 1}},
						},
					},
				},
			}},
			expected: []Resource{NewResource("test", "Pod", "foo", "Running",
				fmt.Errorf("container foo-container terminated with exit code 1"),
				proto.StatusCode_STATUSCHECK_CONTAINER_TERMINATED)},
		},
		// Events Test cases
		{
			description: "pod condition with events",
			pods: []*v1.Pod{{
				ObjectMeta: metav1.ObjectMeta{
					Name:      "foo",
					Namespace: "test",
				},
				TypeMeta: metav1.TypeMeta{Kind: "Pod"},
				Status: v1.PodStatus{
					Phase: v1.PodPending,
					Conditions: []v1.PodCondition{{
						Type:    v1.PodScheduled,
						Status:  v1.ConditionUnknown,
						Message: "could not determine",
					}},
				},
			}},
			events: []v1.Event{
				{
					ObjectMeta: metav1.ObjectMeta{Namespace: "test"},
					Reason:     "eventCode", Type: "Warning", Message: "dummy event",
				},
			},
			expected: []Resource{NewResource("test", "Pod", "foo", "Pending",
				fmt.Errorf("eventCode: dummy event"), proto.StatusCode_STATUSCHECK_UNKNOWN)},
		},
		{
			description: "pod condition a warning event followed up normal",
			pods: []*v1.Pod{{
				ObjectMeta: metav1.ObjectMeta{
					Name:      "foo",
					Namespace: "test",
				},
				TypeMeta: metav1.TypeMeta{Kind: "Pod"},
				Status: v1.PodStatus{
					Phase: v1.PodPending,
					Conditions: []v1.PodCondition{{
						Type:    v1.PodScheduled,
						Status:  v1.ConditionUnknown,
						Message: "could not determine",
					}},
				},
			}},
			events: []v1.Event{
				{
					ObjectMeta: metav1.ObjectMeta{Name: "one", Namespace: "test"},
					Reason:     "eventCode", Type: "Warning", Message: "dummy event",
				},
				{
					ObjectMeta: metav1.ObjectMeta{Name: "two", Namespace: "test"},
					Reason:     "eventCode", Type: "Normal", Message: "success",
				},
			},
			expected: []Resource{NewResource("test", "Pod", "foo", "Pending",
				fmt.Errorf("could not determine"), proto.StatusCode_STATUSCHECK_UNKNOWN)},
		},
		{
			description: "pod condition a warning event followed up normal adds last warning seen",
			pods: []*v1.Pod{{
				ObjectMeta: metav1.ObjectMeta{
					Name:      "foo",
					Namespace: "test",
				},
				TypeMeta: metav1.TypeMeta{Kind: "Pod"},
				Status: v1.PodStatus{
					Phase: v1.PodPending,
					Conditions: []v1.PodCondition{{
						Type:    v1.PodScheduled,
						Status:  v1.ConditionUnknown,
						Message: "could not determine",
					}},
				},
			}},
			events: []v1.Event{
				{
					ObjectMeta: metav1.ObjectMeta{Name: "one", Namespace: "test"},
					Reason:     "eventCode", Type: "Warning", Message: "dummy event",
				},
				{
					ObjectMeta: metav1.ObjectMeta{Name: "two", Namespace: "test"}, Reason: "FailedScheduling", Type: "Warning",
					Message: "0/1 nodes are available: 1 node(s) had taint {key: value}, that the pod didn't tolerate",
				},
			},
			expected: []Resource{NewResource("test", "Pod", "foo", "Pending",
				fmt.Errorf("0/1 nodes are available: 1 node(s) had taint {key: value}, that the pod didn't tolerate"), proto.StatusCode_STATUSCHECK_FAILED_SCHEDULING)},
		},
	}

	for _, test := range tests {
		testutil.Run(t, test.description, func(t *testutil.T) {
			rs := make([]runtime.Object, len(test.pods))
			for i, p := range test.pods {
				rs[i] = p
			}
			rs = append(rs, &v1.EventList{Items: test.events})
			f := fakekubeclientset.NewSimpleClientset(rs...)

			actual, err := NewPodValidator(f).Validate(context.Background(), "test", metav1.ListOptions{})
			t.CheckNoError(err)
			t.CheckDeepEqual(test.expected, actual, cmp.AllowUnexported(Resource{}), cmp.Comparer(func(x, y error) bool {
				if x == nil && y == nil {
					return true
				} else if x != nil && y != nil {
					return x.Error() == y.Error()
				}
				return false
			}))
		})
	}
}
<|endoftext|>


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

package oracle

import (
	"fmt"
	"go/ast"
	"go/build"
	"go/token"
	"os"
	"path/filepath"
	"sort"
	"strings"

	"golang.org/x/tools/go/ast/astutil"
	"golang.org/x/tools/oracle/serial"
)

// what reports all the information about the query selection that can be
// obtained from parsing only its containing source file.
// It is intended to be a very low-latency query callable from GUI
// tools, e.g. to populate a menu of options of slower queries about
// the selected location.
//
func what(q *Query) error {
	qpos, err := fastQueryPos(q.Pos)
	if err != nil {
		return err
	}
	q.Fset = qpos.fset

	// (ignore errors)
	srcdir, importPath, _ := guessImportPath(q.Fset.File(qpos.start).Name(), q.Build)

	// Determine which query modes are applicable to the selection.
	enable := map[string]bool{
		"describe": true, // any syntax; always enabled
	}

	if qpos.end > qpos.start {
		enable["freevars"] = true // nonempty selection?
	}

	for _, n := range qpos.path {
		switch n := n.(type) {
		case *ast.Ident:
			enable["definition"] = true
			enable["referrers"] = true
			enable["implements"] = true
		case *ast.CallExpr:
			enable["callees"] = true
		case *ast.FuncDecl:
			enable["callers"] = true
			enable["callstack"] = true
		case *ast.SendStmt:
			enable["peers"] = true
		case *ast.UnaryExpr:
			if n.Op == token.ARROW {
				enable["peers"] = true
			}
		}

		// For implements, we approximate findInterestingNode.
		if _, ok := enable["implements"]; !ok {
			switch n.(type) {
			case *ast.ArrayType,
				*ast.StructType,
				*ast.FuncType,
				*ast.InterfaceType,
				*ast.MapType,
				*ast.ChanType:
				enable["implements"] = true
			}
		}

		// For pointsto, we approximate findInterestingNode.
		if _, ok := enable["pointsto"]; !ok {
			switch n.(type) {
			case ast.Stmt,
				*ast.ArrayType,
				*ast.StructType,
				*ast.FuncType,
				*ast.InterfaceType,
				*ast.MapType,
				*ast.ChanType:
				enable["pointsto"] = false // not an expr

			case ast.Expr, ast.Decl, *ast.ValueSpec:
				enable["pointsto"] = true // an expr, maybe

			default:
				// Comment, Field, KeyValueExpr, etc: ascend.
			}
		}
	}

	// If we don't have an exact selection, disable modes that need one.
	if !qpos.exact {
		enable["callees"] = false
		enable["pointsto"] = false
		enable["whicherrs"] = false
		enable["describe"] = false
	}

	var modes []string
	for mode := range enable {
		modes = append(modes, mode)
	}
	sort.Strings(modes)

	q.result = &whatResult{
		path:       qpos.path,
		srcdir:     srcdir,
		importPath: importPath,
		modes:      modes,
	}
	return nil
}

// guessImportPath finds the package containing filename, and returns
// its source directory (an element of $GOPATH) and its import path
// relative to it.
//
// TODO(adonovan): what about _test.go files that are not part of the
// package?
//
func guessImportPath(filename string, buildContext *build.Context) (srcdir, importPath string, err error) {
	absFile, err := filepath.Abs(filename)
	if err != nil {
		err = fmt.Errorf("can't form absolute path of %s", filename)
		return
	}
	absFileDir := segments(filepath.Dir(absFile))

	// Find the innermost directory in $GOPATH that encloses filename.
	minD := 1024
	for _, gopathDir := range buildContext.SrcDirs() {
		absDir, err := filepath.Abs(gopathDir)
		if err != nil {
			continue // e.g. non-existent dir on $GOPATH
		}
		d := prefixLen(segments(absDir), absFileDir)
		// If there are multiple matches,
		// prefer the innermost enclosing directory
		// (smallest d).
		if d >= 0 && d < minD {
			minD = d
			srcdir = gopathDir
			importPath = strings.Join(absFileDir[len(absFileDir)-minD:], string(os.PathSeparator))
		}
	}
	if srcdir == "" {
		err = fmt.Errorf("can't find package for file %s", filename)
	}
	return
}

func segments(path string) []string {
	return strings.Split(path, string(os.PathSeparator))
}

// prefixLen returns the length of the remainder of y if x is a prefix
// of y, a negative number otherwise.
func prefixLen(x, y []string) int {
	d := len(y) - len(x)
	if d >= 0 {
		for i := range x {
			if y[i] != x[i] {
				return -1 // not a prefix
			}
		}
	}
	return d
}

type whatResult struct {
	path       []ast.Node
	modes      []string
	srcdir     string
	importPath string
}

func (r *whatResult) display(printf printfFunc) {
	for _, n := range r.path {
		printf(n, "%s", astutil.NodeDescription(n))
	}
	printf(nil, "modes: %s", r.modes)
	printf(nil, "srcdir: %s", r.srcdir)
	printf(nil, "import path: %s", r.importPath)
}

func (r *whatResult) toSerial(res *serial.Result, fset *token.FileSet) {
	var enclosing []serial.SyntaxNode
	for _, n := range r.path {
		enclosing = append(enclosing, serial.SyntaxNode{
			Description: astutil.NodeDescription(n),
			Start:       fset.Position(n.Pos()).Offset,
			End:         fset.Position(n.End()).Offset,
		})
	}
	res.What = &serial.What{
		Modes:      r.modes,
		SrcDir:     r.srcdir,
		ImportPath: r.importPath,
		Enclosing:  enclosing,
	}
}
<commit_msg>oracle: report a better error if query is outside GOROOT/GOPATH<commit_after>// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package oracle

import (
	"fmt"
	"go/ast"
	"go/build"
	"go/token"
	"os"
	"path/filepath"
	"sort"
	"strings"

	"golang.org/x/tools/go/ast/astutil"
	"golang.org/x/tools/oracle/serial"
)

// what reports all the information about the query selection that can be
// obtained from parsing only its containing source file.
// It is intended to be a very low-latency query callable from GUI
// tools, e.g. to populate a menu of options of slower queries about
// the selected location.
//
func what(q *Query) error {
	qpos, err := fastQueryPos(q.Pos)
	if err != nil {
		return err
	}
	q.Fset = qpos.fset

	// (ignore errors)
	srcdir, importPath, _ := guessImportPath(q.Fset.File(qpos.start).Name(), q.Build)

	// Determine which query modes are applicable to the selection.
	enable := map[string]bool{
		"describe": true, // any syntax; always enabled
	}

	if qpos.end > qpos.start {
		enable["freevars"] = true // nonempty selection?
	}

	for _, n := range qpos.path {
		switch n := n.(type) {
		case *ast.Ident:
			enable["definition"] = true
			enable["referrers"] = true
			enable["implements"] = true
		case *ast.CallExpr:
			enable["callees"] = true
		case *ast.FuncDecl:
			enable["callers"] = true
			enable["callstack"] = true
		case *ast.SendStmt:
			enable["peers"] = true
		case *ast.UnaryExpr:
			if n.Op == token.ARROW {
				enable["peers"] = true
			}
		}

		// For implements, we approximate findInterestingNode.
		if _, ok := enable["implements"]; !ok {
			switch n.(type) {
			case *ast.ArrayType,
				*ast.StructType,
				*ast.FuncType,
				*ast.InterfaceType,
				*ast.MapType,
				*ast.ChanType:
				enable["implements"] = true
			}
		}

		// For pointsto, we approximate findInterestingNode.
		if _, ok := enable["pointsto"]; !ok {
			switch n.(type) {
			case ast.Stmt,
				*ast.ArrayType,
				*ast.StructType,
				*ast.FuncType,
				*ast.InterfaceType,
				*ast.MapType,
				*ast.ChanType:
				enable["pointsto"] = false // not an expr

			case ast.Expr, ast.Decl, *ast.ValueSpec:
				enable["pointsto"] = true // an expr, maybe

			default:
				// Comment, Field, KeyValueExpr, etc: ascend.
			}
		}
	}

	// If we don't have an exact selection, disable modes that need one.
	if !qpos.exact {
		enable["callees"] = false
		enable["pointsto"] = false
		enable["whicherrs"] = false
		enable["describe"] = false
	}

	var modes []string
	for mode := range enable {
		modes = append(modes, mode)
	}
	sort.Strings(modes)

	q.result = &whatResult{
		path:       qpos.path,
		srcdir:     srcdir,
		importPath: importPath,
		modes:      modes,
	}
	return nil
}

// guessImportPath finds the package containing filename, and returns
// its source directory (an element of $GOPATH) and its import path
// relative to it.
//
// TODO(adonovan): what about _test.go files that are not part of the
// package?
//
func guessImportPath(filename string, buildContext *build.Context) (srcdir, importPath string, err error) {
	absFile, err := filepath.Abs(filename)
	if err != nil {
		err = fmt.Errorf("can't form absolute path of %s", filename)
		return
	}
	absFileDir := segments(filepath.Dir(absFile))

	// Find the innermost directory in $GOPATH that encloses filename.
	minD := 1024
	for _, gopathDir := range buildContext.SrcDirs() {
		absDir, err := filepath.Abs(gopathDir)
		if err != nil {
			continue // e.g. non-existent dir on $GOPATH
		}
		d := prefixLen(segments(absDir), absFileDir)
		// If there are multiple matches,
		// prefer the innermost enclosing directory
		// (smallest d).
		if d >= 0 && d < minD {
			minD = d
			srcdir = gopathDir
			importPath = strings.Join(absFileDir[len(absFileDir)-minD:], string(os.PathSeparator))
		}
	}
	if srcdir == "" {
		err = fmt.Errorf("directory %s is not beneath GOROOT or GOPATH: %s",
			filepath.Dir(absFile), strings.Join(buildContext.SrcDirs(), ", "))
	}
	return
}

func segments(path string) []string {
	return strings.Split(path, string(os.PathSeparator))
}

// prefixLen returns the length of the remainder of y if x is a prefix
// of y, a negative number otherwise.
func prefixLen(x, y []string) int {
	d := len(y) - len(x)
	if d >= 0 {
		for i := range x {
			if y[i] != x[i] {
				return -1 // not a prefix
			}
		}
	}
	return d
}

type whatResult struct {
	path       []ast.Node
	modes      []string
	srcdir     string
	importPath string
}

func (r *whatResult) display(printf printfFunc) {
	for _, n := range r.path {
		printf(n, "%s", astutil.NodeDescription(n))
	}
	printf(nil, "modes: %s", r.modes)
	printf(nil, "srcdir: %s", r.srcdir)
	printf(nil, "import path: %s", r.importPath)
}

func (r *whatResult) toSerial(res *serial.Result, fset *token.FileSet) {
	var enclosing []serial.SyntaxNode
	for _, n := range r.path {
		enclosing = append(enclosing, serial.SyntaxNode{
			Description: astutil.NodeDescription(n),
			Start:       fset.Position(n.Pos()).Offset,
			End:         fset.Position(n.End()).Offset,
		})
	}
	res.What = &serial.What{
		Modes:      r.modes,
		SrcDir:     r.srcdir,
		ImportPath: r.importPath,
		Enclosing:  enclosing,
	}
}
<|endoftext|>


<commit_before>package google

import (
	"bytes"
	"fmt"
	"log"
	"reflect"
	"sort"
	"testing"

	"github.com/hashicorp/terraform/helper/acctest"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/terraform"
)

// Test that services can be enabled and disabled on a project
func TestAccProjectServices_basic(t *testing.T) {
	t.Parallel()

	org := getTestOrgFromEnv(t)
	pid := "terraform-" + acctest.RandString(10)
	services1 := []string{"cloudbuild.googleapis.com", "cloudresourcemanager.googleapis.com"}
	services2 := []string{"cloudresourcemanager.googleapis.com"}
	oobService := "cloudbuild.googleapis.com"
	resource.Test(t, resource.TestCase{
		PreCheck:  func() { testAccPreCheck(t) },
		Providers: testAccProviders,
		Steps: []resource.TestStep{
			// Create a new project with some services
			resource.TestStep{
				Config: testAccProjectAssociateServicesBasic(services1, pid, pname, org),
				Check: resource.ComposeTestCheckFunc(
					testProjectServicesMatch(services1, pid),
				),
			},
			// Update services to remove one
			resource.TestStep{
				Config: testAccProjectAssociateServicesBasic(services2, pid, pname, org),
				Check: resource.ComposeTestCheckFunc(
					testProjectServicesMatch(services2, pid),
				),
			},
			// Add a service out-of-band and ensure it is removed
			resource.TestStep{
				PreConfig: func() {
					config := testAccProvider.Meta().(*Config)
					enableService(oobService, pid, config)
				},
				Config: testAccProjectAssociateServicesBasic(services2, pid, pname, org),
				Check: resource.ComposeTestCheckFunc(
					testProjectServicesMatch(services2, pid),
				),
			},
			resource.TestStep{
				ResourceName:            "google_project_services.acceptance",
				ImportState:             true,
				ImportStateId:           pid,
				ImportStateVerify:       true,
				ImportStateVerifyIgnore: []string{"disable_on_destroy"},
			},
		},
	})
}

// Test that services are authoritative when a project has existing
// sevices not represented in config
func TestAccProjectServices_authoritative(t *testing.T) {
	t.Parallel()

	org := getTestOrgFromEnv(t)
	pid := "terraform-" + acctest.RandString(10)
	services := []string{"cloudresourcemanager.googleapis.com"}
	oobService := "cloudbuild.googleapis.com"
	resource.Test(t, resource.TestCase{
		PreCheck:  func() { testAccPreCheck(t) },
		Providers: testAccProviders,
		Steps: []resource.TestStep{
			// Create a new project with no services
			resource.TestStep{
				Config: testAccProject_create(pid, pname, org),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckGoogleProjectExists("google_project.acceptance", pid),
				),
			},
			// Add a service out-of-band, then apply a config that creates a service.
			// It should remove the out-of-band service.
			resource.TestStep{
				PreConfig: func() {
					config := testAccProvider.Meta().(*Config)
					enableService(oobService, pid, config)
				},
				Config: testAccProjectAssociateServicesBasic(services, pid, pname, org),
				Check: resource.ComposeTestCheckFunc(
					testProjectServicesMatch(services, pid),
				),
			},
		},
	})
}

// Test that services are authoritative when a project has existing
// sevices, some which are represented in the config and others
// that are not
func TestAccProjectServices_authoritative2(t *testing.T) {
	t.Parallel()

	org := getTestOrgFromEnv(t)
	pid := "terraform-" + acctest.RandString(10)
	oobServices := []string{"cloudbuild.googleapis.com", "cloudresourcemanager.googleapis.com"}
	services := []string{"cloudbuild.googleapis.com"}

	resource.Test(t, resource.TestCase{
		PreCheck:  func() { testAccPreCheck(t) },
		Providers: testAccProviders,
		Steps: []resource.TestStep{
			// Create a new project with no services
			resource.TestStep{
				Config: testAccProject_create(pid, pname, org),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckGoogleProjectExists("google_project.acceptance", pid),
				),
			},
			// Add a service out-of-band, then apply a config that creates a service.
			// It should remove the out-of-band service.
			resource.TestStep{
				PreConfig: func() {
					config := testAccProvider.Meta().(*Config)
					for _, s := range oobServices {
						enableService(s, pid, config)
					}
				},
				Config: testAccProjectAssociateServicesBasic(services, pid, pname, org),
				Check: resource.ComposeTestCheckFunc(
					testProjectServicesMatch(services, pid),
				),
			},
		},
	})
}

// Test that services that can't be enabled on their own (such as dataproc-control.googleapis.com)
// don't end up causing diffs when they are enabled as a side-effect of a different service's
// enablement.
func TestAccProjectServices_ignoreUnenablableServices(t *testing.T) {
	t.Parallel()

	org := getTestOrgFromEnv(t)
	billingId := getTestBillingAccountFromEnv(t)
	pid := "terraform-" + acctest.RandString(10)
	services := []string{
		"dataproc.googleapis.com",
		// The following services are enabled as a side-effect of dataproc's enablement
		"storage-component.googleapis.com",
		"deploymentmanager.googleapis.com",
		"replicapool.googleapis.com",
		"replicapoolupdater.googleapis.com",
		"resourceviews.googleapis.com",
		"compute.googleapis.com",
		"container.googleapis.com",
		"containerregistry.googleapis.com",
		"storage-api.googleapis.com",
		"pubsub.googleapis.com",
		"oslogin.googleapis.com",
		"bigquery-json.googleapis.com",
	}

	resource.Test(t, resource.TestCase{
		PreCheck:  func() { testAccPreCheck(t) },
		Providers: testAccProviders,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccProjectAssociateServicesBasic_withBilling(services, pid, pname, org, billingId),
				Check: resource.ComposeTestCheckFunc(
					testProjectServicesMatch(services, pid),
				),
			},
		},
	})
}

func TestAccProjectServices_pagination(t *testing.T) {
	t.Parallel()

	org := getTestOrgFromEnv(t)
	billingId := getTestBillingAccountFromEnv(t)
	pid := "terraform-" + acctest.RandString(10)

	// we need at least 50 services (doesn't matter what they are) to exercise the
	// pagination handling code.
	services := []string{
		"actions.googleapis.com",
		"appengine.googleapis.com",
		"appengineflex.googleapis.com",
		"bigquery-json.googleapis.com",
		"bigquerydatatransfer.googleapis.com",
		"bigtableadmin.googleapis.com",
		"bigtabletableadmin.googleapis.com",
		"cloudbuild.googleapis.com",
		"clouderrorreporting.googleapis.com",
		"cloudfunctions.googleapis.com",
		"cloudiot.googleapis.com",
		"cloudkms.googleapis.com",
		"cloudmonitoring.googleapis.com",
		"cloudresourcemanager.googleapis.com",
		"cloudtrace.googleapis.com",
		"compute.googleapis.com",
		"container.googleapis.com",
		"containerregistry.googleapis.com",
		"dataflow.googleapis.com",
		"dataproc.googleapis.com",
		"datastore.googleapis.com",
		"deploymentmanager.googleapis.com",
		"dialogflow.googleapis.com",
		"dns.googleapis.com",
		"endpoints.googleapis.com",
		"firebaserules.googleapis.com",
		"firestore.googleapis.com",
		"genomics.googleapis.com",
		"iam.googleapis.com",
		"iamcredentials.googleapis.com",
		"language.googleapis.com",
		"logging.googleapis.com",
		"ml.googleapis.com",
		"monitoring.googleapis.com",
		"oslogin.googleapis.com",
		"pubsub.googleapis.com",
		"replicapool.googleapis.com",
		"replicapoolupdater.googleapis.com",
		"resourceviews.googleapis.com",
		"runtimeconfig.googleapis.com",
		"servicecontrol.googleapis.com",
		"servicemanagement.googleapis.com",
		"sourcerepo.googleapis.com",
		"spanner.googleapis.com",
		"speech.googleapis.com",
		"sql-component.googleapis.com",
		"storage-api.googleapis.com",
		"storage-component.googleapis.com",
		"storagetransfer.googleapis.com",
		"testing.googleapis.com",
		"toolresults.googleapis.com",
		"translate.googleapis.com",
		"videointelligence.googleapis.com",
		"vision.googleapis.com",
		"zync.googleapis.com",
	}

	resource.Test(t, resource.TestCase{
		PreCheck:  func() { testAccPreCheck(t) },
		Providers: testAccProviders,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccProjectAssociateServicesBasic_withBilling(services, pid, pname, org, billingId),
				Check: resource.ComposeTestCheckFunc(
					testProjectServicesMatch(services, pid),
				),
			},
		},
	})
}

func testAccProjectAssociateServicesBasic(services []string, pid, name, org string) string {
	return fmt.Sprintf(`
resource "google_project" "acceptance" {
  project_id = "%s"
  name       = "%s"
  org_id     = "%s"
}
resource "google_project_services" "acceptance" {
  project            = "${google_project.acceptance.project_id}"
  services           = [%s]
  disable_on_destroy = true
}
`, pid, name, org, testStringsToString(services))
}

func testAccProjectAssociateServicesBasic_withBilling(services []string, pid, name, org, billing string) string {
	return fmt.Sprintf(`
resource "google_project" "acceptance" {
  project_id      = "%s"
  name            = "%s"
  org_id          = "%s"
  billing_account = "%s"
}
resource "google_project_services" "acceptance" {
  project            = "${google_project.acceptance.project_id}"
  services           = [%s]
  disable_on_destroy = false
}
`, pid, name, org, billing, testStringsToString(services))
}

func testProjectServicesMatch(services []string, pid string) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		config := testAccProvider.Meta().(*Config)

		apiServices, err := getApiServices(pid, config, ignoreProjectServices)
		if err != nil {
			return fmt.Errorf("Error listing services for project %q: %v", pid, err)
		}

		sort.Strings(services)
		sort.Strings(apiServices)
		if !reflect.DeepEqual(services, apiServices) {
			return fmt.Errorf("Services in config (%v) do not exactly match services returned by API (%v)", services, apiServices)
		}

		return nil
	}
}

func testStringsToString(s []string) string {
	var b bytes.Buffer
	for i, v := range s {
		b.WriteString(fmt.Sprintf("\"%s\"", v))
		if i < len(s)-1 {
			b.WriteString(",")
		}
	}
	r := b.String()
	log.Printf("[DEBUG]: Converted list of strings to %s", r)
	return b.String()
}
<commit_msg>Fix project services tests by using a service without any dependencies (#214)<commit_after>package google

import (
	"bytes"
	"fmt"
	"log"
	"reflect"
	"sort"
	"testing"

	"github.com/hashicorp/terraform/helper/acctest"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/terraform"
)

// Test that services can be enabled and disabled on a project
func TestAccProjectServices_basic(t *testing.T) {
	t.Parallel()

	org := getTestOrgFromEnv(t)
	pid := "terraform-" + acctest.RandString(10)
	services1 := []string{"logging.googleapis.com", "cloudresourcemanager.googleapis.com"}
	services2 := []string{"cloudresourcemanager.googleapis.com"}
	oobService := "logging.googleapis.com"
	resource.Test(t, resource.TestCase{
		PreCheck:  func() { testAccPreCheck(t) },
		Providers: testAccProviders,
		Steps: []resource.TestStep{
			// Create a new project with some services
			resource.TestStep{
				Config: testAccProjectAssociateServicesBasic(services1, pid, pname, org),
				Check: resource.ComposeTestCheckFunc(
					testProjectServicesMatch(services1, pid),
				),
			},
			// Update services to remove one
			resource.TestStep{
				Config: testAccProjectAssociateServicesBasic(services2, pid, pname, org),
				Check: resource.ComposeTestCheckFunc(
					testProjectServicesMatch(services2, pid),
				),
			},
			// Add a service out-of-band and ensure it is removed
			resource.TestStep{
				PreConfig: func() {
					config := testAccProvider.Meta().(*Config)
					enableService(oobService, pid, config)
				},
				Config: testAccProjectAssociateServicesBasic(services2, pid, pname, org),
				Check: resource.ComposeTestCheckFunc(
					testProjectServicesMatch(services2, pid),
				),
			},
			resource.TestStep{
				ResourceName:            "google_project_services.acceptance",
				ImportState:             true,
				ImportStateId:           pid,
				ImportStateVerify:       true,
				ImportStateVerifyIgnore: []string{"disable_on_destroy"},
			},
		},
	})
}

// Test that services are authoritative when a project has existing
// sevices not represented in config
func TestAccProjectServices_authoritative(t *testing.T) {
	t.Parallel()

	org := getTestOrgFromEnv(t)
	pid := "terraform-" + acctest.RandString(10)
	services := []string{"cloudresourcemanager.googleapis.com"}
	oobService := "logging.googleapis.com"
	resource.Test(t, resource.TestCase{
		PreCheck:  func() { testAccPreCheck(t) },
		Providers: testAccProviders,
		Steps: []resource.TestStep{
			// Create a new project with no services
			resource.TestStep{
				Config: testAccProject_create(pid, pname, org),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckGoogleProjectExists("google_project.acceptance", pid),
				),
			},
			// Add a service out-of-band, then apply a config that creates a service.
			// It should remove the out-of-band service.
			resource.TestStep{
				PreConfig: func() {
					config := testAccProvider.Meta().(*Config)
					enableService(oobService, pid, config)
				},
				Config: testAccProjectAssociateServicesBasic(services, pid, pname, org),
				Check: resource.ComposeTestCheckFunc(
					testProjectServicesMatch(services, pid),
				),
			},
		},
	})
}

// Test that services are authoritative when a project has existing
// sevices, some which are represented in the config and others
// that are not
func TestAccProjectServices_authoritative2(t *testing.T) {
	t.Parallel()

	org := getTestOrgFromEnv(t)
	pid := "terraform-" + acctest.RandString(10)
	oobServices := []string{"logging.googleapis.com", "cloudresourcemanager.googleapis.com"}
	services := []string{"logging.googleapis.com"}

	resource.Test(t, resource.TestCase{
		PreCheck:  func() { testAccPreCheck(t) },
		Providers: testAccProviders,
		Steps: []resource.TestStep{
			// Create a new project with no services
			resource.TestStep{
				Config: testAccProject_create(pid, pname, org),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckGoogleProjectExists("google_project.acceptance", pid),
				),
			},
			// Add a service out-of-band, then apply a config that creates a service.
			// It should remove the out-of-band service.
			resource.TestStep{
				PreConfig: func() {
					config := testAccProvider.Meta().(*Config)
					for _, s := range oobServices {
						enableService(s, pid, config)
					}
				},
				Config: testAccProjectAssociateServicesBasic(services, pid, pname, org),
				Check: resource.ComposeTestCheckFunc(
					testProjectServicesMatch(services, pid),
				),
			},
		},
	})
}

// Test that services that can't be enabled on their own (such as dataproc-control.googleapis.com)
// don't end up causing diffs when they are enabled as a side-effect of a different service's
// enablement.
func TestAccProjectServices_ignoreUnenablableServices(t *testing.T) {
	t.Parallel()

	org := getTestOrgFromEnv(t)
	billingId := getTestBillingAccountFromEnv(t)
	pid := "terraform-" + acctest.RandString(10)
	services := []string{
		"dataproc.googleapis.com",
		// The following services are enabled as a side-effect of dataproc's enablement
		"storage-component.googleapis.com",
		"deploymentmanager.googleapis.com",
		"replicapool.googleapis.com",
		"replicapoolupdater.googleapis.com",
		"resourceviews.googleapis.com",
		"compute.googleapis.com",
		"container.googleapis.com",
		"containerregistry.googleapis.com",
		"storage-api.googleapis.com",
		"pubsub.googleapis.com",
		"oslogin.googleapis.com",
		"bigquery-json.googleapis.com",
	}

	resource.Test(t, resource.TestCase{
		PreCheck:  func() { testAccPreCheck(t) },
		Providers: testAccProviders,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccProjectAssociateServicesBasic_withBilling(services, pid, pname, org, billingId),
				Check: resource.ComposeTestCheckFunc(
					testProjectServicesMatch(services, pid),
				),
			},
		},
	})
}

func TestAccProjectServices_pagination(t *testing.T) {
	t.Parallel()

	org := getTestOrgFromEnv(t)
	billingId := getTestBillingAccountFromEnv(t)
	pid := "terraform-" + acctest.RandString(10)

	// we need at least 50 services (doesn't matter what they are) to exercise the
	// pagination handling code.
	services := []string{
		"actions.googleapis.com",
		"appengine.googleapis.com",
		"appengineflex.googleapis.com",
		"bigquery-json.googleapis.com",
		"bigquerydatatransfer.googleapis.com",
		"bigtableadmin.googleapis.com",
		"bigtabletableadmin.googleapis.com",
		"cloudbuild.googleapis.com",
		"clouderrorreporting.googleapis.com",
		"cloudfunctions.googleapis.com",
		"cloudiot.googleapis.com",
		"cloudkms.googleapis.com",
		"cloudmonitoring.googleapis.com",
		"cloudresourcemanager.googleapis.com",
		"cloudtrace.googleapis.com",
		"compute.googleapis.com",
		"container.googleapis.com",
		"containerregistry.googleapis.com",
		"dataflow.googleapis.com",
		"dataproc.googleapis.com",
		"datastore.googleapis.com",
		"deploymentmanager.googleapis.com",
		"dialogflow.googleapis.com",
		"dns.googleapis.com",
		"endpoints.googleapis.com",
		"firebaserules.googleapis.com",
		"firestore.googleapis.com",
		"genomics.googleapis.com",
		"iam.googleapis.com",
		"iamcredentials.googleapis.com",
		"language.googleapis.com",
		"logging.googleapis.com",
		"ml.googleapis.com",
		"monitoring.googleapis.com",
		"oslogin.googleapis.com",
		"pubsub.googleapis.com",
		"replicapool.googleapis.com",
		"replicapoolupdater.googleapis.com",
		"resourceviews.googleapis.com",
		"runtimeconfig.googleapis.com",
		"servicecontrol.googleapis.com",
		"servicemanagement.googleapis.com",
		"sourcerepo.googleapis.com",
		"spanner.googleapis.com",
		"speech.googleapis.com",
		"sql-component.googleapis.com",
		"storage-api.googleapis.com",
		"storage-component.googleapis.com",
		"storagetransfer.googleapis.com",
		"testing.googleapis.com",
		"toolresults.googleapis.com",
		"translate.googleapis.com",
		"videointelligence.googleapis.com",
		"vision.googleapis.com",
		"zync.googleapis.com",
	}

	resource.Test(t, resource.TestCase{
		PreCheck:  func() { testAccPreCheck(t) },
		Providers: testAccProviders,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccProjectAssociateServicesBasic_withBilling(services, pid, pname, org, billingId),
				Check: resource.ComposeTestCheckFunc(
					testProjectServicesMatch(services, pid),
				),
			},
		},
	})
}

func testAccProjectAssociateServicesBasic(services []string, pid, name, org string) string {
	return fmt.Sprintf(`
resource "google_project" "acceptance" {
  project_id = "%s"
  name       = "%s"
  org_id     = "%s"
}
resource "google_project_services" "acceptance" {
  project            = "${google_project.acceptance.project_id}"
  services           = [%s]
  disable_on_destroy = true
}
`, pid, name, org, testStringsToString(services))
}

func testAccProjectAssociateServicesBasic_withBilling(services []string, pid, name, org, billing string) string {
	return fmt.Sprintf(`
resource "google_project" "acceptance" {
  project_id      = "%s"
  name            = "%s"
  org_id          = "%s"
  billing_account = "%s"
}
resource "google_project_services" "acceptance" {
  project            = "${google_project.acceptance.project_id}"
  services           = [%s]
  disable_on_destroy = false
}
`, pid, name, org, billing, testStringsToString(services))
}

func testProjectServicesMatch(services []string, pid string) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		config := testAccProvider.Meta().(*Config)

		apiServices, err := getApiServices(pid, config, ignoreProjectServices)
		if err != nil {
			return fmt.Errorf("Error listing services for project %q: %v", pid, err)
		}

		sort.Strings(services)
		sort.Strings(apiServices)
		if !reflect.DeepEqual(services, apiServices) {
			return fmt.Errorf("Services in config (%v) do not exactly match services returned by API (%v)", services, apiServices)
		}

		return nil
	}
}

func testStringsToString(s []string) string {
	var b bytes.Buffer
	for i, v := range s {
		b.WriteString(fmt.Sprintf("\"%s\"", v))
		if i < len(s)-1 {
			b.WriteString(",")
		}
	}
	r := b.String()
	log.Printf("[DEBUG]: Converted list of strings to %s", r)
	return b.String()
}
<|endoftext|>


<commit_before>package version

import "fmt"

const (
	// VersionMajor is for an API incompatible changes
	VersionMajor = 5
	// VersionMinor is for functionality in a backwards-compatible manner
	VersionMinor = 0
	// VersionPatch is for backwards-compatible bug fixes
	VersionPatch = 1

	// VersionDev indicates development branch. Releases will be empty string.
	VersionDev = "-dev"
)

// Version is the specification version that the package types support.
var Version = fmt.Sprintf("%d.%d.%d%s", VersionMajor, VersionMinor, VersionPatch, VersionDev)
<commit_msg>Bump to v5.1.0<commit_after>package version

import "fmt"

const (
	// VersionMajor is for an API incompatible changes
	VersionMajor = 5
	// VersionMinor is for functionality in a backwards-compatible manner
	VersionMinor = 1
	// VersionPatch is for backwards-compatible bug fixes
	VersionPatch = 0

	// VersionDev indicates development branch. Releases will be empty string.
	VersionDev = ""
)

// Version is the specification version that the package types support.
var Version = fmt.Sprintf("%d.%d.%d%s", VersionMajor, VersionMinor, VersionPatch, VersionDev)
<|endoftext|>


<commit_before>// Flake generates unique identifiers that are roughly sortable by time. Flake can
// run on a cluster of machines and still generate unique IDs without requiring
// worker coordination.
//
// A Flake ID is a 64-bit integer will the following components:
//  - 41 bits is the timestamp with millisecond precision
//  - 10 bits is the host id (uses IP modulo 2^10)
//  - 13 bits is an auto-incrementing sequence for ID requests within the same millisecond
//
// Note: In order to make a millisecond timestamp fit within 41 bits, a custom
// epoch of Jan 1, 2014 00:00:00 is used.

package flake

import (
	"net"
	"os"
	"strconv"
	"sync"
	"time"
)

//-----------------------------------------------------------------------------

const (
	HostBits     = 10
	SequenceBits = 13
)

var (
	// Custom Epoch so the timestamp can fit into 41 bits.
	// Jan 1, 2014 00:00:00 UTC
	Epoch       time.Time = time.Date(2014, 1, 1, 0, 0, 0, 0, time.UTC)
	MaxHostId   uint64    = (1 << HostBits) - 1
	MaxSequence uint64    = (1 << SequenceBits) - 1
)

// Id represents a unique k-ordered Id
type Id uint64

// String formats the Id as a 16 character hexadecimal string
func (id *Id) String() string {
	return strconv.FormatUint(uint64(*id), 16)
}

// Flake is a unique Id generator
type Flake struct {
	prevTime uint64
	hostId   uint64
	sequence uint64
	mu       sync.Mutex
}

// New returns a new Id generator and a possible error condition
func New() (*Flake, error) {
	hostId, err := getHostId()

	if err != nil {
		return nil, err
	}

	return &Flake{
		sequence: 0,
		prevTime: getTimestamp(),
		hostId:   hostId,
	}, nil
}

// NextId returns a new Id from the generator
func (f *Flake) NextId() Id {
	f.mu.Lock()
	defer f.mu.Unlock()

	now := getTimestamp()

	if now < f.prevTime {
		now = f.prevTime
	}

	// Use the sequence number if the id request is in the same millisecond as
	// the previous request.
	if now == f.prevTime {
		f.sequence += 1
	} else {
		f.sequence = 0
	}

	// Bump the timestamp by 1ms if we run out of sequence bits.
	if f.sequence > MaxSequence {
		now += 1
		f.sequence = 0
	}

	f.prevTime = now

	timestamp := now << (HostBits + SequenceBits)
	hostid := f.hostId << SequenceBits

	return Id(timestamp | hostid | f.sequence)
}

// getTimestamp returns the timestamp in milliseconds adjusted for the custom
// epoch
func getTimestamp() uint64 {
	return uint64(time.Since(Epoch).Nanoseconds() / 1e6)
}

// getHostId returns the host id using the IP address of the machine
func getHostId() (uint64, error) {
	h, err := os.Hostname()

	if err != nil {
		return 0, err
	}

	addrs, err := net.LookupIP(h)

	if err != nil {
		return 0, err
	}

	a := addrs[0].To4()
	ip := uint64((a[0] * 1 << 24) + (a[1] * 1 << 16) + (a[2] * 1 << 8) + a[3])

	return ip % MaxHostId, nil
}
<commit_msg>Add Uint64()<commit_after>// Flake generates unique identifiers that are roughly sortable by time. Flake can
// run on a cluster of machines and still generate unique IDs without requiring
// worker coordination.
//
// A Flake ID is a 64-bit integer will the following components:
//  - 41 bits is the timestamp with millisecond precision
//  - 10 bits is the host id (uses IP modulo 2^10)
//  - 13 bits is an auto-incrementing sequence for ID requests within the same millisecond
//
// Note: In order to make a millisecond timestamp fit within 41 bits, a custom
// epoch of Jan 1, 2014 00:00:00 is used.

package flake

import (
	"net"
	"os"
	"strconv"
	"sync"
	"time"
)

//-----------------------------------------------------------------------------

const (
	HostBits     = 10
	SequenceBits = 13
)

var (
	// Custom Epoch so the timestamp can fit into 41 bits.
	// Jan 1, 2014 00:00:00 UTC
	Epoch       time.Time = time.Date(2014, 1, 1, 0, 0, 0, 0, time.UTC)
	MaxHostId   uint64    = (1 << HostBits) - 1
	MaxSequence uint64    = (1 << SequenceBits) - 1
)

// Id represents a unique k-ordered Id
type Id uint64

// String formats the Id as a 16 character hexadecimal string
func (id *Id) String() string {
	return strconv.FormatUint(uint64(*id), 16)
}

// Uint64 formats the Id as an unsigned integer
func (id *Id) Uint64() uint64 {
	return uint64(*id)
}

// Flake is a unique Id generator
type Flake struct {
	prevTime uint64
	hostId   uint64
	sequence uint64
	mu       sync.Mutex
}

// New returns a new Id generator and a possible error condition
func New() (*Flake, error) {
	hostId, err := getHostId()

	if err != nil {
		return nil, err
	}

	return &Flake{
		sequence: 0,
		prevTime: getTimestamp(),
		hostId:   hostId,
	}, nil
}

// NextId returns a new Id from the generator
func (f *Flake) NextId() Id {
	f.mu.Lock()
	defer f.mu.Unlock()

	now := getTimestamp()

	if now < f.prevTime {
		now = f.prevTime
	}

	// Use the sequence number if the id request is in the same millisecond as
	// the previous request.
	if now == f.prevTime {
		f.sequence += 1
	} else {
		f.sequence = 0
	}

	// Bump the timestamp by 1ms if we run out of sequence bits.
	if f.sequence > MaxSequence {
		now += 1
		f.sequence = 0
	}

	f.prevTime = now

	timestamp := now << (HostBits + SequenceBits)
	hostid := f.hostId << SequenceBits

	return Id(timestamp | hostid | f.sequence)
}

// getTimestamp returns the timestamp in milliseconds adjusted for the custom
// epoch
func getTimestamp() uint64 {
	return uint64(time.Since(Epoch).Nanoseconds() / 1e6)
}

// getHostId returns the host id using the IP address of the machine
func getHostId() (uint64, error) {
	h, err := os.Hostname()

	if err != nil {
		return 0, err
	}

	addrs, err := net.LookupIP(h)

	if err != nil {
		return 0, err
	}

	a := addrs[0].To4()
	ip := uint64((a[0] * 1 << 24) + (a[1] * 1 << 16) + (a[2] * 1 << 8) + a[3])

	return ip % MaxHostId, nil
}
<|endoftext|>


<commit_before>package stage

import (
	"context"
	"fmt"

	"github.com/werf/werf/pkg/container_runtime"
	"github.com/werf/werf/pkg/giterminism_inspector"
	imagePkg "github.com/werf/werf/pkg/image"
)

func newGitStage(name StageName, baseStageOptions *NewBaseStageOptions) *GitStage {
	s := &GitStage{}
	s.BaseStage = newBaseStage(name, baseStageOptions)
	return s
}

type GitStage struct {
	*BaseStage
}

func (s *GitStage) IsEmpty(ctx context.Context, _ Conveyor, _ container_runtime.ImageInterface) (bool, error) {
	return s.isEmpty(ctx), nil
}

func (s *GitStage) isEmpty(_ context.Context) bool {
	return len(s.gitMappings) == 0
}

func (s *GitStage) PrepareImage(ctx context.Context, c Conveyor, prevBuiltImage, image container_runtime.ImageInterface) error {
	if err := s.BaseStage.PrepareImage(ctx, c, prevBuiltImage, image); err != nil {
		return err
	}

	if giterminism_inspector.DevMode {
		image.DockerfileImageBuilder().AppendBuildArgs(fmt.Sprintf("--label=%s=true", imagePkg.WerfDevLabel))
	}

	return nil
}
<commit_msg>[stapel, dev] Fix adding dev label to the building image<commit_after>package stage

import (
	"context"

	"github.com/werf/werf/pkg/container_runtime"
	"github.com/werf/werf/pkg/giterminism_inspector"
	imagePkg "github.com/werf/werf/pkg/image"
)

func newGitStage(name StageName, baseStageOptions *NewBaseStageOptions) *GitStage {
	s := &GitStage{}
	s.BaseStage = newBaseStage(name, baseStageOptions)
	return s
}

type GitStage struct {
	*BaseStage
}

func (s *GitStage) IsEmpty(ctx context.Context, _ Conveyor, _ container_runtime.ImageInterface) (bool, error) {
	return s.isEmpty(ctx), nil
}

func (s *GitStage) isEmpty(_ context.Context) bool {
	return len(s.gitMappings) == 0
}

func (s *GitStage) PrepareImage(ctx context.Context, c Conveyor, prevBuiltImage, image container_runtime.ImageInterface) error {
	if err := s.BaseStage.PrepareImage(ctx, c, prevBuiltImage, image); err != nil {
		return err
	}

	if giterminism_inspector.DevMode {
		image.BuilderContainer().AddLabel(map[string]string{imagePkg.WerfDevLabel: "true"})
	}

	return nil
}
<|endoftext|>


<commit_before>// Package version holds some version data common to bosun and scollector.
// Most of these values will be inserted at build time with `-ldFlags` directives for official builds.
package version // import "bosun.org/version"

import (
	"fmt"
	"time"
)

// These variables will be set at linking time for official builds.
// build.go will set date and sha, but `go get` will set none of these.
var (
	// Version number for official releases Updated manually before each release.
	Version = "0.5.0-alpha"

	// Set to any non-empty value by official release script
	OfficialBuild string
	// Date and time of build. Should be in YYYYMMDDHHMMSS format
	VersionDate string
	// VersionSHA should be set at build time as the most recent commit hash.
	VersionSHA string
)

// Get a string representing the version information for the current binary.
func GetVersionInfo(app string) string {
	var sha, build string
	version := ShortVersion()
	if buildTime, err := time.Parse("20060102150405", VersionDate); err == nil {
		build = " built " + buildTime.Format(time.RFC3339)
	}
	if VersionSHA != "" {
		sha = fmt.Sprintf(" (%s)", VersionSHA)
	}
	return fmt.Sprintf("%s version %s%s%s", app, version, sha, build)
}

func ShortVersion() string {
	version := Version

	if OfficialBuild == "" {
		version += "-dev"
	}

	return version
}
<commit_msg>Update version.go<commit_after>// Package version holds some version data common to bosun and scollector.
// Most of these values will be inserted at build time with `-ldFlags` directives for official builds.
package version // import "bosun.org/version"

import (
	"fmt"
	"time"
)

// These variables will be set at linking time for official builds.
// build.go will set date and sha, but `go get` will set none of these.
var (
	// Version number for official releases Updated manually before each release.
	Version = "0.5.0-rc1"

	// Set to any non-empty value by official release script
	OfficialBuild string
	// Date and time of build. Should be in YYYYMMDDHHMMSS format
	VersionDate string
	// VersionSHA should be set at build time as the most recent commit hash.
	VersionSHA string
)

// Get a string representing the version information for the current binary.
func GetVersionInfo(app string) string {
	var sha, build string
	version := ShortVersion()
	if buildTime, err := time.Parse("20060102150405", VersionDate); err == nil {
		build = " built " + buildTime.Format(time.RFC3339)
	}
	if VersionSHA != "" {
		sha = fmt.Sprintf(" (%s)", VersionSHA)
	}
	return fmt.Sprintf("%s version %s%s%s", app, version, sha, build)
}

func ShortVersion() string {
	version := Version

	if OfficialBuild == "" {
		version += "-dev"
	}

	return version
}
<|endoftext|>