<commit_before>// Copyright 2019, OpenTelemetry 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 core

import (
	"context"
	"fmt"
	"strconv"

	"google.golang.org/grpc/codes"

	"github.com/open-telemetry/opentelemetry-go/api/unit"
)

type ScopeID struct {
	EventID
	SpanContext
}

type SpanContext struct {
	TraceIDHigh uint64
	TraceIDLow  uint64
	SpanID      uint64
}

type EventID uint64

type BaseMeasure interface {
	Name() string
	Description() string
	Unit() unit.Unit

	DefinitionID() EventID
}

type Measure interface {
	BaseMeasure

	M(float64) Measurement
	V(float64) KeyValue
}

type Measurement struct {
	// NOTE: If we add a ScopeID field this can carry
	// pre-aggregated measures via the stats.Record API.
	Measure Measure
	Value   float64
	ScopeID ScopeID
}

type Key interface {
	BaseMeasure

	Value(ctx context.Context) KeyValue

	Bool(v bool) KeyValue

	Int(v int) KeyValue
	Int32(v int32) KeyValue
	Int64(v int64) KeyValue

	Uint(v uint) KeyValue
	Uint32(v uint32) KeyValue
	Uint64(v uint64) KeyValue

	Float32(v float32) KeyValue
	Float64(v float64) KeyValue

	String(v string) KeyValue
	Bytes(v []byte) KeyValue
}

type KeyValue struct {
	Key   Key
	Value Value
}

type ValueType int

type Value struct {
	Type    ValueType
	Bool    bool
	Int64   int64
	Uint64  uint64
	Float64 float64
	String  string
	Bytes   []byte

	// TODO Lazy value type?
}

type MutatorOp int

type Mutator struct {
	MutatorOp
	KeyValue
	MeasureMetadata
}

type MeasureMetadata struct {
	MaxHops int // -1 == infinite, 0 == do not propagate

	// TODO time to live?
}

const (
	INVALID ValueType = iota
	BOOL
	INT32
	INT64
	UINT32
	UINT64
	FLOAT32
	FLOAT64
	STRING
	BYTES

	INSERT MutatorOp = iota
	UPDATE
	UPSERT
	DELETE
)

var (
	// INVALID_SPAN_CONTEXT is meant for internal use to return invalid span context during error
	// conditions.
	INVALID_SPAN_CONTEXT = SpanContext{}
)

func (sc SpanContext) HasTraceID() bool {
	return sc.TraceIDHigh != 0 || sc.TraceIDLow != 0
}

func (sc SpanContext) HasSpanID() bool {
	return sc.SpanID != 0
}

func (sc SpanContext) SpanIDString() string {
	p := fmt.Sprintf("%.16x", sc.SpanID)
	return p[0:3] + ".." + p[13:16]
}

func (sc SpanContext) TraceIDString() string {
	p1 := fmt.Sprintf("%.16x", sc.TraceIDHigh)
	p2 := fmt.Sprintf("%.16x", sc.TraceIDLow)
	return p1[0:3] + ".." + p2[13:16]
}

// TODO make this a lazy one-time conversion.
func (v Value) Emit() string {
	switch v.Type {
	case BOOL:
		return fmt.Sprint(v.Bool)
	case INT32, INT64:
		return fmt.Sprint(v.Int64)
	case UINT32, UINT64:
		return fmt.Sprint(v.Uint64)
	case FLOAT32, FLOAT64:
		return fmt.Sprint(v.Float64)
	case STRING:
		return v.String
	case BYTES:
		return string(v.Bytes)
	}
	return "unknown"
}

func (m Mutator) WithMaxHops(hops int) Mutator {
	m.MaxHops = hops
	return m
}

func (e EventID) Scope() ScopeID {
	return ScopeID{
		EventID: e,
	}
}

func (s SpanContext) Scope() ScopeID {
	return ScopeID{
		SpanContext: s,
	}
}

func (m Measurement) With(id ScopeID) Measurement {
	m.ScopeID = id
	return m
}

func GrpcCodeToString(s codes.Code) string {
	switch c := s; c {
	case codes.OK:
		return "OK"
	case codes.Canceled:
		return "CANCELLED"
	case codes.Unknown:
		return "UNKNOWN"
	case codes.InvalidArgument:
		return "INVALID_ARGUMENT"
	case codes.DeadlineExceeded:
		return "DEADLINE_EXCEEDED"
	case codes.NotFound:
		return "NOT_FOUND"
	case codes.AlreadyExists:
		return "ALREADY_EXISTS"
	case codes.PermissionDenied:
		return "PERMISSION_DENIED"
	case codes.ResourceExhausted:
		return "RESOURCE_EXHAUSTED"
	case codes.FailedPrecondition:
		return "FAILED_PRECONDITION"
	case codes.Aborted:
		return "ABORTED"
	case codes.OutOfRange:
		return "OUT_OF_RANGE"
	case codes.Unimplemented:
		return "UNIMPLEMENTED"
	case codes.Internal:
		return "INTERNAL"
	case codes.Unavailable:
		return "UNAVAILABLE"
	case codes.DataLoss:
		return "DATA_LOSS"
	case codes.Unauthenticated:
		return "UNAUTHENTICATED"
	default:
		return "STATUS_" + strconv.FormatInt(int64(c), 10)
	}
}
<commit_msg>use grpc.codes.String instead of custom switch (#32)<commit_after>// Copyright 2019, OpenTelemetry 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 core

import (
	"context"
	"fmt"

	"google.golang.org/grpc/codes"

	"github.com/open-telemetry/opentelemetry-go/api/unit"
)

type ScopeID struct {
	EventID
	SpanContext
}

type SpanContext struct {
	TraceIDHigh uint64
	TraceIDLow  uint64
	SpanID      uint64
}

type EventID uint64

type BaseMeasure interface {
	Name() string
	Description() string
	Unit() unit.Unit

	DefinitionID() EventID
}

type Measure interface {
	BaseMeasure

	M(float64) Measurement
	V(float64) KeyValue
}

type Measurement struct {
	// NOTE: If we add a ScopeID field this can carry
	// pre-aggregated measures via the stats.Record API.
	Measure Measure
	Value   float64
	ScopeID ScopeID
}

type Key interface {
	BaseMeasure

	Value(ctx context.Context) KeyValue

	Bool(v bool) KeyValue

	Int(v int) KeyValue
	Int32(v int32) KeyValue
	Int64(v int64) KeyValue

	Uint(v uint) KeyValue
	Uint32(v uint32) KeyValue
	Uint64(v uint64) KeyValue

	Float32(v float32) KeyValue
	Float64(v float64) KeyValue

	String(v string) KeyValue
	Bytes(v []byte) KeyValue
}

type KeyValue struct {
	Key   Key
	Value Value
}

type ValueType int

type Value struct {
	Type    ValueType
	Bool    bool
	Int64   int64
	Uint64  uint64
	Float64 float64
	String  string
	Bytes   []byte

	// TODO Lazy value type?
}

type MutatorOp int

type Mutator struct {
	MutatorOp
	KeyValue
	MeasureMetadata
}

type MeasureMetadata struct {
	MaxHops int // -1 == infinite, 0 == do not propagate

	// TODO time to live?
}

const (
	INVALID ValueType = iota
	BOOL
	INT32
	INT64
	UINT32
	UINT64
	FLOAT32
	FLOAT64
	STRING
	BYTES

	INSERT MutatorOp = iota
	UPDATE
	UPSERT
	DELETE
)

var (
	// INVALID_SPAN_CONTEXT is meant for internal use to return invalid span context during error
	// conditions.
	INVALID_SPAN_CONTEXT = SpanContext{}
)

func (sc SpanContext) HasTraceID() bool {
	return sc.TraceIDHigh != 0 || sc.TraceIDLow != 0
}

func (sc SpanContext) HasSpanID() bool {
	return sc.SpanID != 0
}

func (sc SpanContext) SpanIDString() string {
	p := fmt.Sprintf("%.16x", sc.SpanID)
	return p[0:3] + ".." + p[13:16]
}

func (sc SpanContext) TraceIDString() string {
	p1 := fmt.Sprintf("%.16x", sc.TraceIDHigh)
	p2 := fmt.Sprintf("%.16x", sc.TraceIDLow)
	return p1[0:3] + ".." + p2[13:16]
}

// TODO make this a lazy one-time conversion.
func (v Value) Emit() string {
	switch v.Type {
	case BOOL:
		return fmt.Sprint(v.Bool)
	case INT32, INT64:
		return fmt.Sprint(v.Int64)
	case UINT32, UINT64:
		return fmt.Sprint(v.Uint64)
	case FLOAT32, FLOAT64:
		return fmt.Sprint(v.Float64)
	case STRING:
		return v.String
	case BYTES:
		return string(v.Bytes)
	}
	return "unknown"
}

func (m Mutator) WithMaxHops(hops int) Mutator {
	m.MaxHops = hops
	return m
}

func (e EventID) Scope() ScopeID {
	return ScopeID{
		EventID: e,
	}
}

func (s SpanContext) Scope() ScopeID {
	return ScopeID{
		SpanContext: s,
	}
}

func (m Measurement) With(id ScopeID) Measurement {
	m.ScopeID = id
	return m
}

func GrpcCodeToString(c codes.Code) string {
	return c.String()
}
<|endoftext|>


<commit_before>package main

import (
    "fmt"
    "encoding/json"
    "errors"

    "github.com/hyperledger/fabric/core/chaincode/shim"
    pb "github.com/hyperledger/fabric/protos/peer"
)

/*
 * Checks the car numberplate.
 *
 * The numberplate is handed out by the DOT.
 */
func IsConfirmed(car *Car) bool {
    // cannot have a numberplate without car papers
    if (!IsRegistered(car)) {
        return false
    }

    // cannot give you a numberplate without insurance contract
    if (!IsInsured(car)) {
        return false
    }

    confirmed := car.Certificate.Numberplate != ""

    // because the car is registered, the car VIN can be trusted
    if (confirmed) {
        fmt.Printf("Car with VIN '%s' is confirmed\n", car.Vin)
    } else {
        fmt.Printf("Car with VIN '%s' has no valid numberplate\n", car.Vin)
    }

    return confirmed
}

/*
 * Checks for a valid car VIN.
 *
 * The car VIN is valid if the DOT certificate contains
 * the same information. Registration guarantees that
 * certificate VIN and a car VIN are equal and that
 * a certificate was issued by the DOT at least once.
 */
func IsRegistered(car *Car) bool {
    // cannot be registered without certificate
    if (car.Certificate.Vin == "") {
        fmt.Printf("Car created at ts '%d' is not yet registered\n", car.CreatedTs)
        return false
    }

    // validate car VIN
    carVin := car.Vin
    registered := car.Certificate.Vin == carVin

    if (registered) {
        fmt.Printf("Car created at ts '%d' is registered with VIN '%s'\n", car.CreatedTs, carVin)
    } else {
        fmt.Printf("Car created at ts '%d' is not yet registered\n", car.CreatedTs)
    }

    return registered
}

/*
 * Returns the registration proposal index with all
 * registration proposals.
 */
func (t *CarChaincode) getRegistrationProposals(stub shim.ChaincodeStubInterface) (map[string]RegistrationProposal, error) {
    response := t.read(stub, registrationProposalIndexStr)
    proposalIndex := make(map[string]RegistrationProposal)
    err := json.Unmarshal(response.Payload, &proposalIndex)
    if err != nil {
        return nil, errors.New("Error parsing registration proposal index")
    }

    return proposalIndex, nil
}

/*
 * Reads all registration proposals.
 */
func (t *CarChaincode) readRegistrationProposals(stub shim.ChaincodeStubInterface) pb.Response {
    proposalIndex, err := t.getRegistrationProposals(stub)
    if err != nil {
        return shim.Error("Error reading registration proposal index")
    }

    indexAsBytes, _ := json.Marshal(proposalIndex)
    return shim.Success(indexAsBytes)
}

/*
 * Returns a registration proposal for a car.
 */
func (t *CarChaincode) getRegistrationProposal(stub shim.ChaincodeStubInterface, car string) pb.Response {
    // load all proposals
    proposalIndex, err := t.getRegistrationProposals(stub)
    if err != nil {
        return shim.Error("Error reading registration proposal index")
    }

    ret := proposalIndex[car]
    retAsBytes, _ := json.Marshal(ret)
    return shim.Success(retAsBytes)
}

/*
 * Registers a car.
 *
 * Registration guarantees that certificate VIN
 * and a car VIN are equal and that a certificate
 * was issued by the DOT at least once.
 *
 * On success,
 * returns the car with certificate.
 */
func (t *CarChaincode) register(stub shim.ChaincodeStubInterface, username string, vin string) pb.Response {
    // reading the car already checks that the user
    // is the actual owner of the car
    carResponse := t.readCar(stub, username, vin)
    car := Car {}
    json.Unmarshal(carResponse.Payload, &car)
    if vin != car.Vin {
        return shim.Error(fmt.Sprintf("Cannot register, invalid VIN.\nCar VIN is '%s' and you want to register VIN '%s'", car.Vin, vin))
    }

    // get all registration proposals
    proposals, err := t.getRegistrationProposals(stub)
    if err != nil {
        return shim.Error("Error reading registration proposal index")
    }

    // check if there exists a registration proposal for that car
    if proposals[car.Vin].Car != vin {
        return shim.Error(fmt.Sprintf("There exists no registration proposal for car with VIN: %s", vin))
    }

    // create a certificate, approve vin
    // and update the car in the ledger
    cert := Certificate { Username: username,
                          Vin:      vin }
    car.Certificate = cert
    carAsBytes, _ := json.Marshal(car)
    err = stub.PutState(car.Vin, carAsBytes)
    if err != nil {
        return shim.Error("Error writing car")
    }

    // remove the proposal we just registered
    delete(proposals, car.Vin)

    // save the new proposal index
    // without the car we just registered
    proposalsAsBytes, _ := json.Marshal(proposals)
    err = stub.PutState(registrationProposalIndexStr, proposalsAsBytes)
    if err != nil {
        return shim.Error("Error writing proposal index")
    }

    fmt.Printf("Successfully registered car created at ts '%d' with VIN '%s'\n", car.CreatedTs, vin)

    return shim.Success(carAsBytes)
}<commit_msg>explains register(), RegistrationProposal<commit_after>package main

import (
    "fmt"
    "encoding/json"
    "errors"

    "github.com/hyperledger/fabric/core/chaincode/shim"
    pb "github.com/hyperledger/fabric/protos/peer"
)

/*
 * Checks the car numberplate.
 *
 * The numberplate is handed out by the DOT.
 */
func IsConfirmed(car *Car) bool {
    // cannot have a numberplate without car papers
    if (!IsRegistered(car)) {
        return false
    }

    // cannot give you a numberplate without insurance contract
    if (!IsInsured(car)) {
        return false
    }

    confirmed := car.Certificate.Numberplate != ""

    // because the car is registered, the car VIN can be trusted
    if (confirmed) {
        fmt.Printf("Car with VIN '%s' is confirmed\n", car.Vin)
    } else {
        fmt.Printf("Car with VIN '%s' has no valid numberplate\n", car.Vin)
    }

    return confirmed
}

/*
 * Checks for a valid car VIN.
 *
 * The car VIN is valid if the DOT certificate contains
 * the same information. Registration guarantees that
 * certificate VIN and a car VIN are equal and that
 * a certificate was issued by the DOT at least once.
 */
func IsRegistered(car *Car) bool {
    // cannot be registered without certificate
    if (car.Certificate.Vin == "") {
        fmt.Printf("Car created at ts '%d' is not yet registered\n", car.CreatedTs)
        return false
    }

    // validate car VIN
    carVin := car.Vin
    registered := car.Certificate.Vin == carVin

    if (registered) {
        fmt.Printf("Car created at ts '%d' is registered with VIN '%s'\n", car.CreatedTs, carVin)
    } else {
        fmt.Printf("Car created at ts '%d' is not yet registered\n", car.CreatedTs)
    }

    return registered
}

/*
 * Returns the registration proposal index with all
 * registration proposals.
 */
func (t *CarChaincode) getRegistrationProposals(stub shim.ChaincodeStubInterface) (map[string]RegistrationProposal, error) {
    response := t.read(stub, registrationProposalIndexStr)
    proposalIndex := make(map[string]RegistrationProposal)
    err := json.Unmarshal(response.Payload, &proposalIndex)
    if err != nil {
        return nil, errors.New("Error parsing registration proposal index")
    }

    return proposalIndex, nil
}

/*
 * Reads all registration proposals.
 */
func (t *CarChaincode) readRegistrationProposals(stub shim.ChaincodeStubInterface) pb.Response {
    proposalIndex, err := t.getRegistrationProposals(stub)
    if err != nil {
        return shim.Error("Error reading registration proposal index")
    }

    indexAsBytes, _ := json.Marshal(proposalIndex)
    return shim.Success(indexAsBytes)
}

/*
 * Returns a registration proposal for a car.
 */
func (t *CarChaincode) getRegistrationProposal(stub shim.ChaincodeStubInterface, car string) pb.Response {
    // load all proposals
    proposalIndex, err := t.getRegistrationProposals(stub)
    if err != nil {
        return shim.Error("Error reading registration proposal index")
    }

    ret := proposalIndex[car]
    retAsBytes, _ := json.Marshal(ret)
    return shim.Success(retAsBytes)
}

/*
 * Registers a car.
 *
 * Registration guarantees that certificate VIN
 * and a car VIN are equal and that a certificate
 * was issued by the DOT at least once.
 *
 * To register a car, a RegistrationProposal needs to be present.
 * This proposal is removed/deleted after successfull registration.
 * This is not consistent with reality, but serves the purpose
 * for now, because the Form 13.20 A (RegistrationProposal)
 * is not used anywhere else right now. Like this, the RegistrationProposal
 * only serves the purpose to signal the DOT, that there is a new
 * car waiting for registration.
 *
 * On success,
 * returns the car with certificate.
 */
func (t *CarChaincode) register(stub shim.ChaincodeStubInterface, username string, vin string) pb.Response {
    // reading the car already checks that the user
    // is the actual owner of the car
    carResponse := t.readCar(stub, username, vin)
    car := Car {}
    json.Unmarshal(carResponse.Payload, &car)
    if vin != car.Vin {
        return shim.Error(fmt.Sprintf("Cannot register, invalid VIN.\nCar VIN is '%s' and you want to register VIN '%s'", car.Vin, vin))
    }

    // get all registration proposals
    proposals, err := t.getRegistrationProposals(stub)
    if err != nil {
        return shim.Error("Error reading registration proposal index")
    }

    // check if there exists a registration proposal for that car
    if proposals[car.Vin].Car != vin {
        return shim.Error(fmt.Sprintf("There exists no registration proposal for car with VIN: %s", vin))
    }

    // create a certificate, approve vin
    // and update the car in the ledger
    cert := Certificate { Username: username,
                          Vin:      vin }
    car.Certificate = cert
    carAsBytes, _ := json.Marshal(car)
    err = stub.PutState(car.Vin, carAsBytes)
    if err != nil {
        return shim.Error("Error writing car")
    }

    // remove the proposal we just registered
    delete(proposals, car.Vin)

    // save the new proposal index
    // without the car we just registered
    proposalsAsBytes, _ := json.Marshal(proposals)
    err = stub.PutState(registrationProposalIndexStr, proposalsAsBytes)
    if err != nil {
        return shim.Error("Error writing proposal index")
    }

    fmt.Printf("Successfully registered car created at ts '%d' with VIN '%s'\n", car.CreatedTs, vin)

    return shim.Success(carAsBytes)
}<|endoftext|>


<commit_before>package ostent

import (
	"fmt"
	"net/http"
	"net/url"
	"strings"
	"sync"
	"time"

	gorillawebsocket "github.com/gorilla/websocket"

	"github.com/ostrost/ostent/client"
	"github.com/ostrost/ostent/flags"
)

type backgroundHandler func(flags.Period)

var (
	jobs = struct {
		mutex sync.Mutex
		added []backgroundHandler
	}{}
)

func AddBackground(j backgroundHandler) {
	jobs.mutex.Lock()
	defer jobs.mutex.Unlock()
	jobs.added = append(jobs.added, j)
}

func RunBackground(defaultPeriod flags.Period) {
	jobs.mutex.Lock()
	defer jobs.mutex.Unlock()
	for _, j := range jobs.added {
		go j(defaultPeriod)
	}
}

func init() {
	AddBackground(Loop)
}

// SleepTilNextSecond sleeps til precisely next second.
func SleepTilNextSecond() {
	now := time.Now()
	nextsecond := now.Truncate(time.Second).Add(time.Second).Sub(now)
	time.Sleep(nextsecond)
}

// Loop is the ostent background job
func Loop(flags.Period) {
	go func() {
		for {
			SleepTilNextSecond()

			Connections.tick()

			if exes := Connections.expired(); len(exes) != 0 {
				lastInfo.collect(&Machine{})
				for _, c := range exes {
					c.Tack()
				}
			}
		}
	}()

	go func() {
		if err := vgwatch(); err != nil { // vagrant
			// ignoring the error
		}
	}()

	for {
		select {
		case update := <-iUPDATES:
			Connections.Push(update)

		case conn := <-Register:
			Connections.reg(conn)

		case conn := <-unregister:
			Connections.unreg(conn)
			/*
				if Connections.unreg(conn) == 0 { // if no connections left
					lastInfo.reset_prev()
				} // */
		}
	}
}

type conn struct {
	Conn *gorillawebsocket.Conn

	requestOrigin *http.Request

	receive chan *received
	pushch  chan *IndexUpdate
	full    client.Client
	access  *logger

	mutex      sync.Mutex
	writemutex sync.Mutex
}

func (c *conn) Expired() bool {
	c.mutex.Lock()
	defer c.mutex.Unlock()
	return c.full.Expired()
}

func (c *conn) Tick() {
	c.mutex.Lock()
	defer c.mutex.Unlock()
	c.full.Tick()
}

func (c *conn) Tack() {
	c.mutex.Lock()
	defer c.mutex.Unlock()
	c.receive <- nil
}

func (c *conn) Push(update *IndexUpdate) {
	c.mutex.Lock()
	defer c.mutex.Unlock()
	c.pushch <- update
}

type receiver interface {
	Tick()
	Tack()
	Push(*IndexUpdate)
	Reload()
	Expired() bool
	CloseChans()
}

type connmap map[receiver]struct{}
type conns struct {
	connmap
	mutex sync.Mutex
}

func (cs *conns) Tack() {
	cs.mutex.Lock()
	defer cs.mutex.Unlock()

	for c := range cs.connmap {
		c.Tack()
	}
}

// Reload sends reload signal to all the connections, returns false if there were no connections
func (cs *conns) Reload() bool {
	cs.mutex.Lock()
	defer cs.mutex.Unlock()

	var reloaded bool
	for c := range cs.connmap {
		c.Reload()
		reloaded = true
	}
	return reloaded
}

func (cs *conns) Push(update *IndexUpdate) {
	cs.mutex.Lock()
	defer cs.mutex.Unlock()

	for c := range cs.connmap {
		c.Push(update)
	}
}

func (cs *conns) reg(r receiver) {
	cs.mutex.Lock()
	defer cs.mutex.Unlock()

	cs.connmap[r] = struct{}{}
}

func (c *conn) CloseChans() {
	c.mutex.Lock()
	defer func() {
		defer c.mutex.Unlock()
		if e := recover(); e != nil {
			if err, ok := e.(error); ok {
				fmt.Printf("CLOSE? PANIC %s\n", err.Error())
			} else {
				fmt.Printf("CLOSE? PANIC (UNDESCRIPT) %+v\n", e)
			}
			panic(e)
		}
	}()
	close(c.receive)
	close(c.pushch)
}

// Len return the number of active connections
func (cs *conns) Len() int {
	cs.mutex.Lock()
	defer cs.mutex.Unlock()
	return len(cs.connmap)
}

func (cs *conns) unreg(r receiver) {
	r.CloseChans()

	cs.mutex.Lock()
	defer cs.mutex.Unlock()

	delete(cs.connmap, r)
}

func (cs *conns) tick() {
	cs.mutex.Lock()
	defer cs.mutex.Unlock()
	for c := range cs.connmap {
		c.Tick()
	}
}

func (cs *conns) expired() []receiver {
	cs.mutex.Lock()
	defer cs.mutex.Unlock()
	exes := []receiver{}

	for c := range cs.connmap {
		if c.Expired() {
			exes = append(exes, c)
		}
	}
	return exes
}

var (
	// Connections is an instance of unexported conns type to hold
	// active websocket connections. The only method is Reload.
	Connections = conns{connmap: make(map[receiver]struct{})}

	iUPDATES   = make(chan *IndexUpdate) // the channel for off-the-clock IndexUpdate to push
	unregister = make(chan receiver)
	Register   = make(chan receiver, 1)
)

type received struct {
	Search *string
	Client *client.RecvClient
}

type served struct {
	conn     *conn // passing conn into received.ServeHTTP
	received *received
}

func (c *conn) writeJSON(data interface{}) error {
	c.writemutex.Lock()
	defer c.writemutex.Unlock()
	return c.Conn.WriteJSON(data)
}

func (c *conn) Reload() {
	c.writeJSON(struct {
		Reload bool
	}{true})
}

func (c *conn) writeError(err error) bool {
	return nil == c.writeJSON(struct {
		Error string
	}{err.Error()})
}

func (c *conn) receiveLoop(stop chan<- struct{}) { // read from the conn
	for {
		rd := new(received)
		if err := c.Conn.ReadJSON(&rd); err != nil {
			stop <- struct{}{}
			return
		}
		c.receive <- rd
	}
}

func (c *conn) updateLoop(stop <-chan struct{}) { // write to the conn
loop:
	for {
		select {
		case rd, ok := <-c.receive:
			if !ok {
				return
			}
			if next := c.process(rd); next != nil {
				if *next {
					continue loop
				} else {
					return
				}
			}
		case update, ok := <-c.pushch:
			if !ok {
				return
			}
			if next := c.writeUpdate(*update); !next {
				return
			}
		case _ = <-stop:
			return
		}
	}
}

func (c *conn) process(rd *received) *bool {
	c.mutex.Lock()
	defer func() {
		c.mutex.Unlock()
		if e := recover(); e != nil {
			stack := ""
			/* The stack to be fmt.Printf-d. Not sure if I should
			sbuf := make([]byte, 4096)
			size := runtime.Stack(sbuf, false)
			stack = string(sbuf[:size])
			*/

			if err, ok := e.(error); ok {
				c.writeError(err) // an alert for the client

				fmt.Printf("PANIC %s\n%s\n", err.Error(), stack)
			} else {
				fmt.Printf("PANIC (UNDESCRIPT) %+v\n%s\n", e, stack)
			}
			panic(e)
		}
	}()

	var req *http.Request
	if form, err := rd.form(); err != nil {
		// if !c.writeError(err) { return newfalse() } // should I write an error?
		return newtrue() // continue receiving
	} else if form != nil {
		// compile an actual Request
		r := *c.requestOrigin
		r.Form = form
		req = &r // http.Request{Form: form}
	}

	sd := served{conn: c, received: rd}
	serve := sd.ServeHTTP // sd.ServeHTTP survives req being nil

	if req != nil && c.access != nil { // the only case when req.Form is not nil
		// a non-nil req is no-go for access anyway
		serve = c.access.Constructor(sd).ServeHTTP
	}

	w := dummyStatus{}
	serve(w, req)

	if w.status == http.StatusBadRequest {
		return newfalse() // write failure, stop receiving
	}
	return nil
}

func (rd *received) form() (url.Values, error) {
	if rd == nil || rd.Search == nil {
		return nil, nil
	}
	return url.ParseQuery(strings.TrimPrefix(*rd.Search, "?"))
	// url.ParseQuery should not return a nil url.Values without an error
}

func (sd served) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	stop := func() {
		w.WriteHeader(http.StatusBadRequest) // well, not a bad request but a write failure
	}
	send := client.SendClient{}
	if sd.received != nil {
		if sd.received.Client != nil {
			if err := sd.received.Client.MergeRefresh(&sd.conn.full, &send); err != nil {
				// if !sd.conn.Conn.writeError(err) { stop(); return }
				send.DebugError = new(string)
				*send.DebugError = err.Error()
			}
			sd.conn.full.Merge(*sd.received.Client, &send)
		}
	}

	update, err := getUpdates(r, &sd.conn.full, send, sd.received != nil && sd.received.Client != nil)
	if err != nil || update == (IndexUpdate{}) { // nothing scheduled for the moment, no update
		return
	}

	if sd.conn.writeJSON(update) != nil {
		stop()
		return
	}
	w.WriteHeader(http.StatusSwitchingProtocols) // last change to WriteHeader. 101 is 200
}

func (c *conn) writeUpdate(update IndexUpdate) bool {
	if *c.full.HideVG {
		// TODO other .Vagrant* fields may not be discarded
		update.VagrantMachines = nil
	}
	return c.writeJSON(update) == nil
}

type dummyStatus struct { // yet another ResponseWriter
	status int
}

func (w dummyStatus) WriteHeader(s int) {
	w.status = s
	// don't expect any actual WriteHeader. This is dummy after all
}

func (w dummyStatus) Header() http.Header {
	panic("dummyStatus.Header: SHOULD NOT BE USED")
	// return w.ResponseWriter.Header()
	// return make(http.Header) // IF TO RETURN ANYTHING, THAT SHOULD BE ONE http.Header PER dummyStatus
}

func (w dummyStatus) Write(b []byte) (int, error) {
	panic("dummyStatus.Write: SHOULD NOT BE USED")
	// return w.ResponseWriter.Write(b)
	// return len(b), nil
}

func IndexWSFunc(access *logger, minperiod flags.Period) func(http.ResponseWriter, *http.Request) {
	return func(w http.ResponseWriter, req *http.Request) {
		IndexWS(access, minperiod, w, req)
	}
}

func IndexWS(access *logger, minperiod flags.Period, w http.ResponseWriter, req *http.Request) {
	// Upgrader.Upgrade() has Origin check if .CheckOrigin is nil
	upgrader := gorillawebsocket.Upgrader{}
	wsconn, err := upgrader.Upgrade(w, req, nil)
	if err != nil { // Upgrade() does http.Error() to the client
		return
	}

	// req.Method == "GET" asserted by the mux
	req.Form = nil // reset reused later .Form
	c := &conn{
		Conn: wsconn,

		requestOrigin: req,

		receive: make(chan *received, 2),
		pushch:  make(chan *IndexUpdate, 2),
		full:    client.DefaultClient(minperiod),
		access:  access,
	}
	Register <- c
	defer func() {
		unregister <- c
		c.Conn.Close()
	}()
	stop := make(chan struct{}, 1)
	go c.receiveLoop(stop) // read from the client
	c.updateLoop(stop)     // write to the client
}

func newfalse() *bool      { return new(bool) }
func newtrue() *bool       { return newbool(true) }
func newbool(v bool) *bool { b := new(bool); *b = v; return b }
<commit_msg>websocket timeouts set<commit_after>package ostent

import (
	"fmt"
	"net/http"
	"net/url"
	"strings"
	"sync"
	"time"

	gorillawebsocket "github.com/gorilla/websocket"

	"github.com/ostrost/ostent/client"
	"github.com/ostrost/ostent/flags"
)

type backgroundHandler func(flags.Period)

var (
	jobs = struct {
		mutex sync.Mutex
		added []backgroundHandler
	}{}
)

func AddBackground(j backgroundHandler) {
	jobs.mutex.Lock()
	defer jobs.mutex.Unlock()
	jobs.added = append(jobs.added, j)
}

func RunBackground(defaultPeriod flags.Period) {
	jobs.mutex.Lock()
	defer jobs.mutex.Unlock()
	for _, j := range jobs.added {
		go j(defaultPeriod)
	}
}

func init() {
	AddBackground(Loop)
}

// SleepTilNextSecond sleeps til precisely next second.
func SleepTilNextSecond() {
	now := time.Now()
	nextsecond := now.Truncate(time.Second).Add(time.Second).Sub(now)
	time.Sleep(nextsecond)
}

// Loop is the ostent background job
func Loop(flags.Period) {
	go func() {
		for {
			SleepTilNextSecond()

			Connections.tick()

			if exes := Connections.expired(); len(exes) != 0 {
				lastInfo.collect(&Machine{})
				for _, c := range exes {
					c.Tack()
				}
			}
		}
	}()

	go func() {
		if err := vgwatch(); err != nil { // vagrant
			// ignoring the error
		}
	}()

	for {
		select {
		case update := <-iUPDATES:
			Connections.Push(update)

		case conn := <-Register:
			Connections.reg(conn)

		case conn := <-unregister:
			Connections.unreg(conn)
			/*
				if Connections.unreg(conn) == 0 { // if no connections left
					lastInfo.reset_prev()
				} // */
		}
	}
}

type conn struct {
	Conn *gorillawebsocket.Conn

	requestOrigin *http.Request

	receive chan *received
	pushch  chan *IndexUpdate
	full    client.Client
	access  *logger

	mutex      sync.Mutex
	writemutex sync.Mutex
}

func (c *conn) Expired() bool {
	c.mutex.Lock()
	defer c.mutex.Unlock()
	return c.full.Expired()
}

func (c *conn) Tick() {
	c.mutex.Lock()
	defer c.mutex.Unlock()
	c.full.Tick()
}

func (c *conn) Tack() {
	c.mutex.Lock()
	defer c.mutex.Unlock()
	c.receive <- nil
}

func (c *conn) Push(update *IndexUpdate) {
	c.mutex.Lock()
	defer c.mutex.Unlock()
	c.pushch <- update
}

type receiver interface {
	Tick()
	Tack()
	Push(*IndexUpdate)
	Reload()
	Expired() bool
	CloseChans()
}

type connmap map[receiver]struct{}
type conns struct {
	connmap
	mutex sync.Mutex
}

func (cs *conns) Tack() {
	cs.mutex.Lock()
	defer cs.mutex.Unlock()

	for c := range cs.connmap {
		c.Tack()
	}
}

// Reload sends reload signal to all the connections, returns false if there were no connections
func (cs *conns) Reload() bool {
	cs.mutex.Lock()
	defer cs.mutex.Unlock()

	var reloaded bool
	for c := range cs.connmap {
		c.Reload()
		reloaded = true
	}
	return reloaded
}

func (cs *conns) Push(update *IndexUpdate) {
	cs.mutex.Lock()
	defer cs.mutex.Unlock()

	for c := range cs.connmap {
		c.Push(update)
	}
}

func (cs *conns) reg(r receiver) {
	cs.mutex.Lock()
	defer cs.mutex.Unlock()

	cs.connmap[r] = struct{}{}
}

func (c *conn) CloseChans() {
	c.mutex.Lock()
	defer func() {
		defer c.mutex.Unlock()
		if e := recover(); e != nil {
			if err, ok := e.(error); ok {
				fmt.Printf("CLOSE? PANIC %s\n", err.Error())
			} else {
				fmt.Printf("CLOSE? PANIC (UNDESCRIPT) %+v\n", e)
			}
			panic(e)
		}
	}()
	close(c.receive)
	close(c.pushch)
}

// Len return the number of active connections
func (cs *conns) Len() int {
	cs.mutex.Lock()
	defer cs.mutex.Unlock()
	return len(cs.connmap)
}

func (cs *conns) unreg(r receiver) {
	r.CloseChans()

	cs.mutex.Lock()
	defer cs.mutex.Unlock()

	delete(cs.connmap, r)
}

func (cs *conns) tick() {
	cs.mutex.Lock()
	defer cs.mutex.Unlock()
	for c := range cs.connmap {
		c.Tick()
	}
}

func (cs *conns) expired() []receiver {
	cs.mutex.Lock()
	defer cs.mutex.Unlock()
	exes := []receiver{}

	for c := range cs.connmap {
		if c.Expired() {
			exes = append(exes, c)
		}
	}
	return exes
}

var (
	// Connections is an instance of unexported conns type to hold
	// active websocket connections. The only method is Reload.
	Connections = conns{connmap: make(map[receiver]struct{})}

	iUPDATES   = make(chan *IndexUpdate) // the channel for off-the-clock IndexUpdate to push
	unregister = make(chan receiver)
	Register   = make(chan receiver, 1)
)

type received struct {
	Search *string
	Client *client.RecvClient
}

type served struct {
	conn     *conn // passing conn into received.ServeHTTP
	received *received
}

func (c *conn) writeJSON(data interface{}) error {
	c.writemutex.Lock()
	defer c.writemutex.Unlock()
	errch := make(chan error, 1)
	go func() { errch <- c.Conn.WriteJSON(data) }()
	select {
	case err := <-errch:
		return err
	case <-time.After(5 * time.Second):
		return fmt.Errorf("timed out (5s)")
	}
}

func (c *conn) Reload() {
	c.writeJSON(struct {
		Reload bool
	}{true})
}

func (c *conn) writeError(err error) bool {
	return nil == c.writeJSON(struct {
		Error string
	}{err.Error()})
}

func (c *conn) receiveLoop(stop chan<- struct{}) { // read from the conn
	for {
		rd := new(received)
		if err := c.Conn.ReadJSON(&rd); err != nil {
			stop <- struct{}{}
			return
		}
		c.receive <- rd
	}
}

func (c *conn) updateLoop(stop <-chan struct{}) { // write to the conn
loop:
	for {
		select {
		case rd, ok := <-c.receive:
			if !ok {
				return
			}
			if next := c.process(rd); next != nil {
				if *next {
					continue loop
				} else {
					return
				}
			}
		case update, ok := <-c.pushch:
			if !ok {
				return
			}
			if next := c.writeUpdate(*update); !next {
				return
			}
		case _ = <-stop:
			return
		}
	}
}

func (c *conn) process(rd *received) *bool {
	c.mutex.Lock()
	defer func() {
		c.mutex.Unlock()
		if e := recover(); e != nil {
			stack := ""
			/* The stack to be fmt.Printf-d. Not sure if I should
			sbuf := make([]byte, 4096)
			size := runtime.Stack(sbuf, false)
			stack = string(sbuf[:size])
			*/

			if err, ok := e.(error); ok {
				c.writeError(err) // an alert for the client

				fmt.Printf("PANIC %s\n%s\n", err.Error(), stack)
			} else {
				fmt.Printf("PANIC (UNDESCRIPT) %+v\n%s\n", e, stack)
			}
			panic(e)
		}
	}()

	var req *http.Request
	if form, err := rd.form(); err != nil {
		// if !c.writeError(err) { return newfalse() } // should I write an error?
		return newtrue() // continue receiving
	} else if form != nil {
		// compile an actual Request
		r := *c.requestOrigin
		r.Form = form
		req = &r // http.Request{Form: form}
	}

	sd := served{conn: c, received: rd}
	serve := sd.ServeHTTP // sd.ServeHTTP survives req being nil

	if req != nil && c.access != nil { // the only case when req.Form is not nil
		// a non-nil req is no-go for access anyway
		serve = c.access.Constructor(sd).ServeHTTP
	}

	w := dummyStatus{}
	serve(w, req)

	if w.status == http.StatusBadRequest {
		return newfalse() // write failure, stop receiving
	}
	return nil
}

func (rd *received) form() (url.Values, error) {
	if rd == nil || rd.Search == nil {
		return nil, nil
	}
	return url.ParseQuery(strings.TrimPrefix(*rd.Search, "?"))
	// url.ParseQuery should not return a nil url.Values without an error
}

func (sd served) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	stop := func() {
		w.WriteHeader(http.StatusBadRequest) // well, not a bad request but a write failure
	}
	send := client.SendClient{}
	if sd.received != nil {
		if sd.received.Client != nil {
			if err := sd.received.Client.MergeRefresh(&sd.conn.full, &send); err != nil {
				// if !sd.conn.Conn.writeError(err) { stop(); return }
				send.DebugError = new(string)
				*send.DebugError = err.Error()
			}
			sd.conn.full.Merge(*sd.received.Client, &send)
		}
	}

	update, err := getUpdates(r, &sd.conn.full, send, sd.received != nil && sd.received.Client != nil)
	if err != nil || update == (IndexUpdate{}) { // nothing scheduled for the moment, no update
		return
	}

	if sd.conn.writeJSON(update) != nil {
		stop()
		return
	}
	w.WriteHeader(http.StatusSwitchingProtocols) // last change to WriteHeader. 101 is 200
}

func (c *conn) writeUpdate(update IndexUpdate) bool {
	if *c.full.HideVG {
		// TODO other .Vagrant* fields may not be discarded
		update.VagrantMachines = nil
	}
	return c.writeJSON(update) == nil
}

type dummyStatus struct { // yet another ResponseWriter
	status int
}

func (w dummyStatus) WriteHeader(s int) {
	w.status = s
	// don't expect any actual WriteHeader. This is dummy after all
}

func (w dummyStatus) Header() http.Header {
	panic("dummyStatus.Header: SHOULD NOT BE USED")
	// return w.ResponseWriter.Header()
	// return make(http.Header) // IF TO RETURN ANYTHING, THAT SHOULD BE ONE http.Header PER dummyStatus
}

func (w dummyStatus) Write(b []byte) (int, error) {
	panic("dummyStatus.Write: SHOULD NOT BE USED")
	// return w.ResponseWriter.Write(b)
	// return len(b), nil
}

func IndexWSFunc(access *logger, minperiod flags.Period) func(http.ResponseWriter, *http.Request) {
	return func(w http.ResponseWriter, req *http.Request) {
		IndexWS(access, minperiod, w, req)
	}
}

func IndexWS(access *logger, minperiod flags.Period, w http.ResponseWriter, req *http.Request) {
	// Upgrader.Upgrade() has Origin check if .CheckOrigin is nil
	upgrader := gorillawebsocket.Upgrader{
		HandshakeTimeout: 5 * time.Second,
	}
	wsconn, err := upgrader.Upgrade(w, req, nil)
	if err != nil { // Upgrade() does http.Error() to the client
		return
	}

	// req.Method == "GET" asserted by the mux
	req.Form = nil // reset reused later .Form
	c := &conn{
		Conn: wsconn,

		requestOrigin: req,

		receive: make(chan *received, 2),
		pushch:  make(chan *IndexUpdate, 2),
		full:    client.DefaultClient(minperiod),
		access:  access,
	}
	Register <- c
	defer func() {
		unregister <- c
		c.Conn.Close()
	}()
	stop := make(chan struct{}, 1)
	go c.receiveLoop(stop) // read from the client
	c.updateLoop(stop)     // write to the client
}

func newfalse() *bool      { return new(bool) }
func newtrue() *bool       { return newbool(true) }
func newbool(v bool) *bool { b := new(bool); *b = v; return b }
<|endoftext|>


<commit_before>package missinggo

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

func fileInfoAccessTime(fi os.FileInfo) time.Time {
	ts := fi.Sys().(syscall.Win32FileAttributeData).LastAccessTime
	return time.Unix(0, int64(ts.Nanoseconds()))
}
<commit_msg>Fix FileInfoAccessTime on windows<commit_after>package missinggo

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

func fileInfoAccessTime(fi os.FileInfo) time.Time {
	ts := fi.Sys().(*syscall.Win32FileAttributeData).LastAccessTime
	return time.Unix(0, int64(ts.Nanoseconds()))
}
<|endoftext|>


<commit_before>package radar

import (
	"sync"
	"time"

	"github.com/concourse/atc/builds"
	"github.com/concourse/atc/config"

	"github.com/pivotal-golang/lager"
)

type VersionDB interface {
	SaveVersionedResource(builds.VersionedResource) error
	GetLatestVersionedResource(string) (builds.VersionedResource, error)
}

type ResourceChecker interface {
	CheckResource(config.Resource, builds.Version) ([]builds.Version, error)
}

type Radar struct {
	logger lager.Logger

	checker  ResourceChecker
	tracker  VersionDB
	interval time.Duration

	stop     chan struct{}
	scanning *sync.WaitGroup
}

func NewRadar(
	logger lager.Logger,
	checker ResourceChecker,
	tracker VersionDB,
	interval time.Duration,
) *Radar {
	return &Radar{
		logger: logger,

		checker:  checker,
		tracker:  tracker,
		interval: interval,

		stop:     make(chan struct{}),
		scanning: new(sync.WaitGroup),
	}
}

func (radar *Radar) Scan(resource config.Resource) {
	radar.scanning.Add(1)

	go func() {
		defer radar.scanning.Done()

		ticker := time.NewTicker(radar.interval)

		for {
			select {
			case <-radar.stop:
				return

			case <-ticker.C:
				var from builds.Version

				if vr, err := radar.tracker.GetLatestVersionedResource(resource.Name); err == nil {
					from = vr.Version
				}

				log := radar.logger.Session("radar", lager.Data{
					"resource": resource.Name,
					"from":     from,
				})

				log.Debug("check")

				newVersions, err := radar.checker.CheckResource(resource, from)
				if err != nil {
					log.Error("failed-to-check", err)
					break
				}

				if len(newVersions) == 0 {
					break
				}

				log.Info("versions-found", lager.Data{
					"versions": newVersions,
					"total":    len(newVersions),
				})

				for _, version := range newVersions {
					err = radar.tracker.SaveVersionedResource(builds.VersionedResource{
						Name:    resource.Name,
						Type:    resource.Type,
						Source:  resource.Source,
						Version: version,
					})
					if err != nil {
						log.Error("failed-to-save-current-version", err, lager.Data{
							"version": version,
						})
					}
				}
			}
		}
	}()
}

func (radar *Radar) Stop() {
	close(radar.stop)
	radar.scanning.Wait()
}
<commit_msg>log resource type when checking<commit_after>package radar

import (
	"sync"
	"time"

	"github.com/concourse/atc/builds"
	"github.com/concourse/atc/config"

	"github.com/pivotal-golang/lager"
)

type VersionDB interface {
	SaveVersionedResource(builds.VersionedResource) error
	GetLatestVersionedResource(string) (builds.VersionedResource, error)
}

type ResourceChecker interface {
	CheckResource(config.Resource, builds.Version) ([]builds.Version, error)
}

type Radar struct {
	logger lager.Logger

	checker  ResourceChecker
	tracker  VersionDB
	interval time.Duration

	stop     chan struct{}
	scanning *sync.WaitGroup
}

func NewRadar(
	logger lager.Logger,
	checker ResourceChecker,
	tracker VersionDB,
	interval time.Duration,
) *Radar {
	return &Radar{
		logger: logger,

		checker:  checker,
		tracker:  tracker,
		interval: interval,

		stop:     make(chan struct{}),
		scanning: new(sync.WaitGroup),
	}
}

func (radar *Radar) Scan(resource config.Resource) {
	radar.scanning.Add(1)

	go func() {
		defer radar.scanning.Done()

		ticker := time.NewTicker(radar.interval)

		for {
			select {
			case <-radar.stop:
				return

			case <-ticker.C:
				var from builds.Version

				if vr, err := radar.tracker.GetLatestVersionedResource(resource.Name); err == nil {
					from = vr.Version
				}

				log := radar.logger.Session("radar", lager.Data{
					"type":     resource.Type,
					"resource": resource.Name,
					"from":     from,
				})

				log.Debug("check")

				newVersions, err := radar.checker.CheckResource(resource, from)
				if err != nil {
					log.Error("failed-to-check", err)
					break
				}

				if len(newVersions) == 0 {
					break
				}

				log.Info("versions-found", lager.Data{
					"versions": newVersions,
					"total":    len(newVersions),
				})

				for _, version := range newVersions {
					err = radar.tracker.SaveVersionedResource(builds.VersionedResource{
						Name:    resource.Name,
						Type:    resource.Type,
						Source:  resource.Source,
						Version: version,
					})
					if err != nil {
						log.Error("failed-to-save-current-version", err, lager.Data{
							"version": version,
						})
					}
				}
			}
		}
	}()
}

func (radar *Radar) Stop() {
	close(radar.stop)
	radar.scanning.Wait()
}
<|endoftext|>


<commit_before>// Copyright 2015 The etcd 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 raft

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"
)

type Logger interface {
	Debug(v ...interface{})
	Debugf(format string, v ...interface{})

	Error(v ...interface{})
	Errorf(format string, v ...interface{})

	Info(v ...interface{})
	Infof(format string, v ...interface{})

	Warning(v ...interface{})
	Warningf(format string, v ...interface{})

	Fatal(v ...interface{})
	Fatalf(format string, v ...interface{})

	Panic(v ...interface{})
	Panicf(format string, v ...interface{})
}

func SetLogger(l Logger) { raftLogger = l }

var (
	defaultLogger = &DefaultLogger{Logger: log.New(os.Stderr, "raft", log.LstdFlags)}
	discardLogger = &DefaultLogger{Logger: log.New(ioutil.Discard, "", 0)}
	raftLogger    = Logger(defaultLogger)
)

const (
	calldepth = 2
)

// DefaultLogger is a default implementation of the Logger interface.
type DefaultLogger struct {
	*log.Logger
	debug bool
}

func (l *DefaultLogger) EnableTimestamps() {
	l.SetFlags(l.Flags() | log.Ldate | log.Ltime)
}

func (l *DefaultLogger) EnableDebug() {
	l.debug = true
}

func (l *DefaultLogger) Debug(v ...interface{}) {
	if l.debug {
		l.Output(calldepth, header("DEBUG", fmt.Sprint(v...)))
	}
}

func (l *DefaultLogger) Debugf(format string, v ...interface{}) {
	if l.debug {
		l.Output(calldepth, header("DEBUG", fmt.Sprintf(format, v...)))
	}
}

func (l *DefaultLogger) Info(v ...interface{}) {
	l.Output(calldepth, header("INFO", fmt.Sprint(v...)))
}

func (l *DefaultLogger) Infof(format string, v ...interface{}) {
	l.Output(calldepth, header("INFO", fmt.Sprintf(format, v...)))
}

func (l *DefaultLogger) Error(v ...interface{}) {
	l.Output(calldepth, header("ERROR", fmt.Sprint(v...)))
}

func (l *DefaultLogger) Errorf(format string, v ...interface{}) {
	l.Output(calldepth, header("ERROR", fmt.Sprintf(format, v...)))
}

func (l *DefaultLogger) Warning(v ...interface{}) {
	l.Output(calldepth, header("WARN", fmt.Sprint(v...)))
}

func (l *DefaultLogger) Warningf(format string, v ...interface{}) {
	l.Output(calldepth, header("WARN", fmt.Sprintf(format, v...)))
}

func (l *DefaultLogger) Fatal(v ...interface{}) {
	l.Output(calldepth, header("FATAL", fmt.Sprint(v...)))
	os.Exit(1)
}

func (l *DefaultLogger) Fatalf(format string, v ...interface{}) {
	l.Output(calldepth, header("FATAL", fmt.Sprintf(format, v...)))
	os.Exit(1)
}

func (l *DefaultLogger) Panic(v ...interface{}) {
	l.Logger.Panic(v...)
}

func (l *DefaultLogger) Panicf(format string, v ...interface{}) {
	l.Logger.Panicf(format, v...)
}

func header(lvl, msg string) string {
	return fmt.Sprintf("%s: %s", lvl, msg)
}
<commit_msg>raft: use mutex in "SetLogger" to avoid race conditions in tests<commit_after>// Copyright 2015 The etcd 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 raft

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"sync"
)

type Logger interface {
	Debug(v ...interface{})
	Debugf(format string, v ...interface{})

	Error(v ...interface{})
	Errorf(format string, v ...interface{})

	Info(v ...interface{})
	Infof(format string, v ...interface{})

	Warning(v ...interface{})
	Warningf(format string, v ...interface{})

	Fatal(v ...interface{})
	Fatalf(format string, v ...interface{})

	Panic(v ...interface{})
	Panicf(format string, v ...interface{})
}

func SetLogger(l Logger) {
	raftLoggerMu.Lock()
	raftLogger = l
	raftLoggerMu.Unlock()
}

var (
	defaultLogger = &DefaultLogger{Logger: log.New(os.Stderr, "raft", log.LstdFlags)}
	discardLogger = &DefaultLogger{Logger: log.New(ioutil.Discard, "", 0)}
	raftLoggerMu  sync.Mutex
	raftLogger    = Logger(defaultLogger)
)

const (
	calldepth = 2
)

// DefaultLogger is a default implementation of the Logger interface.
type DefaultLogger struct {
	*log.Logger
	debug bool
}

func (l *DefaultLogger) EnableTimestamps() {
	l.SetFlags(l.Flags() | log.Ldate | log.Ltime)
}

func (l *DefaultLogger) EnableDebug() {
	l.debug = true
}

func (l *DefaultLogger) Debug(v ...interface{}) {
	if l.debug {
		l.Output(calldepth, header("DEBUG", fmt.Sprint(v...)))
	}
}

func (l *DefaultLogger) Debugf(format string, v ...interface{}) {
	if l.debug {
		l.Output(calldepth, header("DEBUG", fmt.Sprintf(format, v...)))
	}
}

func (l *DefaultLogger) Info(v ...interface{}) {
	l.Output(calldepth, header("INFO", fmt.Sprint(v...)))
}

func (l *DefaultLogger) Infof(format string, v ...interface{}) {
	l.Output(calldepth, header("INFO", fmt.Sprintf(format, v...)))
}

func (l *DefaultLogger) Error(v ...interface{}) {
	l.Output(calldepth, header("ERROR", fmt.Sprint(v...)))
}

func (l *DefaultLogger) Errorf(format string, v ...interface{}) {
	l.Output(calldepth, header("ERROR", fmt.Sprintf(format, v...)))
}

func (l *DefaultLogger) Warning(v ...interface{}) {
	l.Output(calldepth, header("WARN", fmt.Sprint(v...)))
}

func (l *DefaultLogger) Warningf(format string, v ...interface{}) {
	l.Output(calldepth, header("WARN", fmt.Sprintf(format, v...)))
}

func (l *DefaultLogger) Fatal(v ...interface{}) {
	l.Output(calldepth, header("FATAL", fmt.Sprint(v...)))
	os.Exit(1)
}

func (l *DefaultLogger) Fatalf(format string, v ...interface{}) {
	l.Output(calldepth, header("FATAL", fmt.Sprintf(format, v...)))
	os.Exit(1)
}

func (l *DefaultLogger) Panic(v ...interface{}) {
	l.Logger.Panic(v...)
}

func (l *DefaultLogger) Panicf(format string, v ...interface{}) {
	l.Logger.Panicf(format, v...)
}

func header(lvl, msg string) string {
	return fmt.Sprintf("%s: %s", lvl, msg)
}
<|endoftext|>


<commit_before>package balanced

import (
	"fmt"
	"net/http"
	"time"
)

type CustomerService struct {
	client *Client
}

type Customer struct {
	*Address     `json:"address,omitempty"`
	BusinessName string `json:"business_name,omitempty"`
	Customers    string `json:"customers,omitempty"`
	DobMonth     int    `json:"dob_month,omitempty"`
	DobYear      int    `json:"dob_year,omitempty"`
	Ein          string `json:"ein,omitempty"`
	Name         string `json:"ein,omitempty"`
	Phone        string `json:"phone,omitempty"`

	Email          string                 `json:"email,omitempty"`
	Href           string                 `json:"href,omitempty"`
	Id             string                 `json:"id,omitempty"`
	Links          CustomerLinks          `json:"links,omitempty"`
	MerchantStatus string                 `json:"merchant_status,omitempty"`
	Meta           map[string]interface{} `json:"meta,omitempty"`
	SsnLast4       string                 `json:"ssn_last4,omitempty"`
	CreatedAt      *time.Time             `json:"created_at,omitempty"`
	UpdatedAt      *time.Time             `json:"updated_at,omitempty"`
}

type CustomerLinks struct {
	Destination string `json:"destination,omitempty"`
	Source      string `json:"source,omitempty"`
}

// CustomerPage holds a paginated set of customers
type CustomerPage struct {
	Customers []Customer
	*PaginationParams
}

type CustomerResponse struct {
	Customers []Customer             `json:"customers"`
	Links     CustomerResponseLinks  `json:"links"`
	Meta      map[string]interface{} `json:"meta"`
}

type CustomerResponseLinks struct {
	BankAccounts     string `json:"customers.bank_accounts"`
	CardHolds        string `json:"customers.card_holds"`
	Cards            string `json:"customers.cards"`
	Credits          string `json:"customers.credits"`
	Debits           string `json:"customers.debits"`
	Destination      string `json:"customers.destination"`
	ExternalAccounts string `json:"customers.external_accounts"`
	Orders           string `json:"customers.orders"`
	Refunds          string `json:"customers.refunds"`
	Reversals        string `json:"customers.reversals"`
	Source           string `json:"customers.source"`
	Transactions     string `json:"customers.transactions"`
}

func (s *CustomerService) Create(customer *Customer) (*Customer, *http.Response, error) {
	customerResponse := new(CustomerResponse)
	httpResponse, err := s.client.POST("/customers", nil, customer, customerResponse)
	if err != nil {
		return nil, httpResponse, err
	}
	return &customerResponse.Customers[0], httpResponse, nil
}

func (s *CustomerService) Delete(customerId string) (bool, *http.Response, error) {
	path := fmt.Sprintf("/customers/%v", customerId)
	httpResponse, err := s.client.DELETE(path, nil, nil, nil)
	if err != nil {
		return false, httpResponse, err
	}
	code := httpResponse.StatusCode
	didDelete := 200 <= code && code < 300
	return didDelete, httpResponse, nil
}

func (s *CustomerService) List(args ...interface{}) (*CustomerPage, *http.Response, error) {
	// Turns args into a map[string]int with "offset" and "limit" keys
	query := paginatedArgsToQuery(args)
	customerResponse := new(CustomerResponse)
	httpResponse, err := s.client.GET("/customers", query, nil, customerResponse)
	if err != nil {
		return nil, httpResponse, err
	}
	return &CustomerPage{
		Customers:        customerResponse.Customers,
		PaginationParams: NewPaginationParams(customerResponse.Meta),
	}, httpResponse, nil
}

func (s *CustomerService) Fetch(customerId string) (*Customer, *http.Response, error) {
	path := fmt.Sprintf("/customers/%v", customerId)
	customerResponse := new(CustomerResponse)
	httpResponse, err := s.client.GET(path, nil, nil, customerResponse)
	if err != nil {
		return nil, httpResponse, err
	}
	return &customerResponse.Customers[0], httpResponse, nil
}

func (s *CustomerService) Update(customerId string, params map[string]interface{}) (*Customer, *http.Response, error) {
	path := fmt.Sprintf("/customers/%v", customerId)
	customerResponse := new(CustomerResponse)
	httpResponse, err := s.client.PUT(path, nil, params, customerResponse)
	if err != nil {
		return nil, httpResponse, err
	}
	return &customerResponse.Customers[0], httpResponse, nil
}

func (s *CustomerService) AssociateWithCard(customerId, cardId string) (*Card, *http.Response, error) {
	return s.client.Card.AssociateWithCustomer(cardId, customerId)
}

func (s *CustomerService) AssociateWithBankAccount(customerId, accountId string) (*BankAccount, *http.Response, error) {
	return s.client.BankAccount.AssociateWithCustomer(accountId, customerId)
}
<commit_msg>Customer Links should be a pointer. Rm unnecessary omitempty<commit_after>package balanced

import (
	"fmt"
	"net/http"
	"time"
)

type CustomerService struct {
	client *Client
}

type Customer struct {
	*Address     `json:"address,omitempty"`
	BusinessName string `json:"business_name,omitempty"`
	Customers    string `json:"customers,omitempty"`
	DobMonth     int    `json:"dob_month,omitempty"`
	DobYear      int    `json:"dob_year,omitempty"`
	Ein          string `json:"ein,omitempty"`
	Name         string `json:"ein,omitempty"`
	Phone        string `json:"phone,omitempty"`

	Email          string                 `json:"email,omitempty"`
	Href           string                 `json:"href,omitempty"`
	Id             string                 `json:"id,omitempty"`
	Links          *CustomerLinks         `json:"links,omitempty"`
	MerchantStatus string                 `json:"merchant_status,omitempty"`
	Meta           map[string]interface{} `json:"meta,omitempty"`
	SsnLast4       string                 `json:"ssn_last4,omitempty"`
	CreatedAt      *time.Time             `json:"created_at,omitempty"`
	UpdatedAt      *time.Time             `json:"updated_at,omitempty"`
}

type CustomerLinks struct {
	Destination string `json:"destination"`
	Source      string `json:"source"`
}

// CustomerPage holds a paginated set of customers
type CustomerPage struct {
	Customers []Customer
	*PaginationParams
}

type CustomerResponse struct {
	Customers []Customer             `json:"customers"`
	Links     CustomerResponseLinks  `json:"links"`
	Meta      map[string]interface{} `json:"meta"`
}

type CustomerResponseLinks struct {
	BankAccounts     string `json:"customers.bank_accounts"`
	CardHolds        string `json:"customers.card_holds"`
	Cards            string `json:"customers.cards"`
	Credits          string `json:"customers.credits"`
	Debits           string `json:"customers.debits"`
	Destination      string `json:"customers.destination"`
	ExternalAccounts string `json:"customers.external_accounts"`
	Orders           string `json:"customers.orders"`
	Refunds          string `json:"customers.refunds"`
	Reversals        string `json:"customers.reversals"`
	Source           string `json:"customers.source"`
	Transactions     string `json:"customers.transactions"`
}

func (s *CustomerService) Create(customer *Customer) (*Customer, *http.Response, error) {
	customerResponse := new(CustomerResponse)
	httpResponse, err := s.client.POST("/customers", nil, customer, customerResponse)
	if err != nil {
		return nil, httpResponse, err
	}
	return &customerResponse.Customers[0], httpResponse, nil
}

func (s *CustomerService) Delete(customerId string) (bool, *http.Response, error) {
	path := fmt.Sprintf("/customers/%v", customerId)
	httpResponse, err := s.client.DELETE(path, nil, nil, nil)
	if err != nil {
		return false, httpResponse, err
	}
	code := httpResponse.StatusCode
	didDelete := 200 <= code && code < 300
	return didDelete, httpResponse, nil
}

func (s *CustomerService) List(args ...interface{}) (*CustomerPage, *http.Response, error) {
	// Turns args into a map[string]int with "offset" and "limit" keys
	query := paginatedArgsToQuery(args)
	customerResponse := new(CustomerResponse)
	httpResponse, err := s.client.GET("/customers", query, nil, customerResponse)
	if err != nil {
		return nil, httpResponse, err
	}
	return &CustomerPage{
		Customers:        customerResponse.Customers,
		PaginationParams: NewPaginationParams(customerResponse.Meta),
	}, httpResponse, nil
}

func (s *CustomerService) Fetch(customerId string) (*Customer, *http.Response, error) {
	path := fmt.Sprintf("/customers/%v", customerId)
	customerResponse := new(CustomerResponse)
	httpResponse, err := s.client.GET(path, nil, nil, customerResponse)
	if err != nil {
		return nil, httpResponse, err
	}
	return &customerResponse.Customers[0], httpResponse, nil
}

func (s *CustomerService) Update(customerId string, params map[string]interface{}) (*Customer, *http.Response, error) {
	path := fmt.Sprintf("/customers/%v", customerId)
	customerResponse := new(CustomerResponse)
	httpResponse, err := s.client.PUT(path, nil, params, customerResponse)
	if err != nil {
		return nil, httpResponse, err
	}
	return &customerResponse.Customers[0], httpResponse, nil
}

func (s *CustomerService) AssociateWithCard(customerId, cardId string) (*Card, *http.Response, error) {
	return s.client.Card.AssociateWithCustomer(cardId, customerId)
}

func (s *CustomerService) AssociateWithBankAccount(customerId, accountId string) (*BankAccount, *http.Response, error) {
	return s.client.BankAccount.AssociateWithCustomer(accountId, customerId)
}
<|endoftext|>


<commit_before>// Copyright 2018 The Terraformer 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 providerwrapper //nolint

import (
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"runtime"
	"strings"
	"time"

	"github.com/GoogleCloudPlatform/terraformer/terraformutils/terraformerstring"

	"github.com/zclconf/go-cty/cty"

	"github.com/hashicorp/go-hclog"
	"github.com/hashicorp/go-plugin"
	"github.com/hashicorp/terraform/configs/configschema"
	tfplugin "github.com/hashicorp/terraform/plugin"
	"github.com/hashicorp/terraform/providers"
	"github.com/hashicorp/terraform/terraform"
	"github.com/hashicorp/terraform/version"
)

// DefaultDataDir is the default directory for storing local data.
const DefaultDataDir = ".terraform"

// DefaultPluginVendorDir is the location in the config directory to look for
// user-added plugin binaries. Terraform only reads from this path if it
// exists, it is never created by terraform.
const DefaultPluginVendorDirV12 = "terraform.d/plugins/" + pluginMachineName

// pluginMachineName is the directory name used in new plugin paths.
const pluginMachineName = runtime.GOOS + "_" + runtime.GOARCH

type ProviderWrapper struct {
	Provider     *tfplugin.GRPCProvider
	client       *plugin.Client
	rpcClient    plugin.ClientProtocol
	providerName string
	config       cty.Value
	schema       *providers.GetSchemaResponse
}

func NewProviderWrapper(providerName string, providerConfig cty.Value, verbose bool) (*ProviderWrapper, error) {
	p := &ProviderWrapper{}
	p.providerName = providerName
	p.config = providerConfig
	err := p.initProvider(verbose)

	return p, err
}

func (p *ProviderWrapper) Kill() {
	p.client.Kill()
}

func (p *ProviderWrapper) GetSchema() *providers.GetSchemaResponse {
	if p.schema == nil {
		r := p.Provider.GetSchema()
		p.schema = &r
	}
	return p.schema
}

func (p *ProviderWrapper) GetReadOnlyAttributes(resourceTypes []string) (map[string][]string, error) {
	r := p.GetSchema()

	if r.Diagnostics.HasErrors() {
		return nil, r.Diagnostics.Err()
	}
	readOnlyAttributes := map[string][]string{}
	for resourceName, obj := range r.ResourceTypes {
		if terraformerstring.ContainsString(resourceTypes, resourceName) {
			readOnlyAttributes[resourceName] = append(readOnlyAttributes[resourceName], "^id$")
			for k, v := range obj.Block.Attributes {
				if !v.Optional && !v.Required {
					if v.Type.IsListType() || v.Type.IsSetType() {
						readOnlyAttributes[resourceName] = append(readOnlyAttributes[resourceName], "^"+k+".(.*)")
					} else {
						readOnlyAttributes[resourceName] = append(readOnlyAttributes[resourceName], "^"+k+"$")
					}
				}
			}
			readOnlyAttributes[resourceName] = p.readObjBlocks(obj.Block.BlockTypes, readOnlyAttributes[resourceName], "-1")
		}
	}
	return readOnlyAttributes, nil
}

func (p *ProviderWrapper) readObjBlocks(block map[string]*configschema.NestedBlock, readOnlyAttributes []string, parent string) []string {
	for k, v := range block {
		if len(v.BlockTypes) > 0 {
			readOnlyAttributes = p.readObjBlocks(v.BlockTypes, readOnlyAttributes, k)
		}
		fieldCount := 0
		for key, l := range v.Attributes {
			if !l.Optional && !l.Required {
				fieldCount++
				switch v.Nesting {
				case configschema.NestingList:
					if parent == "-1" {
						readOnlyAttributes = append(readOnlyAttributes, "^"+k+".[0-9]."+key+"($|\\.[0-9]|\\.#)")
					} else {
						readOnlyAttributes = append(readOnlyAttributes, "^"+parent+".(.*)."+key+"$")
					}
				case configschema.NestingSet:
					if parent == "-1" {
						readOnlyAttributes = append(readOnlyAttributes, "^"+k+".[0-9]."+key+"$")
					} else {
						readOnlyAttributes = append(readOnlyAttributes, "^"+parent+".(.*)."+key+"($|\\.(.*))")
					}
				case configschema.NestingMap:
					readOnlyAttributes = append(readOnlyAttributes, parent+"."+key)
				default:
					readOnlyAttributes = append(readOnlyAttributes, parent+"."+key+"$")
				}
			}
		}
		if fieldCount == len(v.Block.Attributes) && fieldCount > 0 {
			readOnlyAttributes = append(readOnlyAttributes, "^"+k)
		}
	}
	return readOnlyAttributes
}

func (p *ProviderWrapper) Refresh(info *terraform.InstanceInfo, state *terraform.InstanceState) (*terraform.InstanceState, error) {
	schema := p.GetSchema()
	impliedType := schema.ResourceTypes[info.Type].Block.ImpliedType()
	priorState, err := state.AttrsAsObjectValue(impliedType)
	if err != nil {
		return nil, err
	}
	successReadResource := false
	resp := providers.ReadResourceResponse{}
	for i := 0; i < 5; i++ {
		resp = p.Provider.ReadResource(providers.ReadResourceRequest{
			TypeName:   info.Type,
			PriorState: priorState,
			Private:    []byte{},
		})
		if resp.Diagnostics.HasErrors() {
			log.Println("WARN: Fail read resource from provider, wait 300ms before retry")
			time.Sleep(300 * time.Millisecond)
			continue
		} else {
			successReadResource = true
			break
		}
	}

	if !successReadResource {
		log.Println("Fail read resource from provider, trying import command")
		// retry with regular import command - without resource attributes
		importResponse := p.Provider.ImportResourceState(providers.ImportResourceStateRequest{
			TypeName: info.Type,
			ID:       state.ID,
		})
		if importResponse.Diagnostics.HasErrors() {
			return nil, resp.Diagnostics.Err()
		}
		if len(importResponse.ImportedResources) == 0 {
			return nil, errors.New("not able to import resource for a given ID")
		}
		return terraform.NewInstanceStateShimmedFromValue(importResponse.ImportedResources[0].State, int(schema.ResourceTypes[info.Type].Version)), nil
	}

	if resp.NewState.IsNull() {
		msg := fmt.Sprintf("ERROR: Read resource response is null for resource %s", info.Id)
		return nil, errors.New(msg)
	}

	return terraform.NewInstanceStateShimmedFromValue(resp.NewState, int(schema.ResourceTypes[info.Type].Version)), nil
}

func (p *ProviderWrapper) initProvider(verbose bool) error {
	providerFilePath, err := getProviderFileName(p.providerName)
	if err != nil {
		return err
	}
	options := hclog.LoggerOptions{
		Name:   "plugin",
		Level:  hclog.Error,
		Output: os.Stdout,
	}
	if verbose {
		options.Level = hclog.Trace
	}
	logger := hclog.New(&options)
	p.client = plugin.NewClient(
		&plugin.ClientConfig{
			Cmd:              exec.Command(providerFilePath),
			HandshakeConfig:  tfplugin.Handshake,
			VersionedPlugins: tfplugin.VersionedPlugins,
			Managed:          true,
			Logger:           logger,
			AllowedProtocols: []plugin.Protocol{plugin.ProtocolGRPC},
			AutoMTLS:         true,
		})
	p.rpcClient, err = p.client.Client()
	if err != nil {
		return err
	}
	raw, err := p.rpcClient.Dispense(tfplugin.ProviderPluginName)
	if err != nil {
		return err
	}

	p.Provider = raw.(*tfplugin.GRPCProvider)

	config, err := p.GetSchema().Provider.Block.CoerceValue(p.config)
	if err != nil {
		return err
	}
	p.Provider.Configure(providers.ConfigureRequest{
		TerraformVersion: version.Version,
		Config:           config,
	})

	return nil
}

func getProviderFileName(providerName string) (string, error) {
	defaultDataDir := os.Getenv("TF_DATA_DIR")
	if defaultDataDir == "" {
		defaultDataDir = DefaultDataDir
	}
	providerFilePath, err := getProviderFileNameV13(defaultDataDir, providerName)
	if err != nil || providerFilePath == "" {
		providerFilePath, err = getProviderFileNameV13(os.Getenv("HOME")+string(os.PathSeparator)+
			".terraform.d", providerName)
	}
	if err != nil || providerFilePath == "" {
		return getProviderFileNameV12(providerName)
	}
	return providerFilePath, nil
}

func getProviderFileNameV13(prefix, providerName string) (string, error) {

	registryDir := prefix + string(os.PathSeparator) + "plugins" + string(os.PathSeparator) +
		"registry.terraform.io"
	providerDirs, err := ioutil.ReadDir(registryDir)
	if err != nil {
		return "", err
	}
	providerFilePath := ""
	for _, providerDir := range providerDirs {
		pluginPath := registryDir + string(os.PathSeparator) + providerDir.Name() +
			string(os.PathSeparator) + providerName
		dirs, err := ioutil.ReadDir(pluginPath)
		if err != nil {
			continue
		}
		for _, dir := range dirs {
			if !dir.IsDir() {
				continue
			}
			for _, dir := range dirs {
				fullPluginPath := pluginPath + string(os.PathSeparator) + dir.Name() +
					string(os.PathSeparator) + runtime.GOOS + "_" + runtime.GOARCH
				files, err := ioutil.ReadDir(fullPluginPath)
				if err == nil {
					for _, file := range files {
						if strings.HasPrefix(file.Name(), "terraform-provider-"+providerName) {
							providerFilePath = fullPluginPath + string(os.PathSeparator) + file.Name()
						}
					}
				}
			}
		}
	}
	return providerFilePath, nil
}

func getProviderFileNameV12(providerName string) (string, error) {
	defaultDataDir := os.Getenv("TF_DATA_DIR")
	if defaultDataDir == "" {
		defaultDataDir = DefaultDataDir
	}
	pluginPath := defaultDataDir + string(os.PathSeparator) + "plugins" + string(os.PathSeparator) + runtime.GOOS + "_" + runtime.GOARCH
	files, err := ioutil.ReadDir(pluginPath)
	if err != nil {
		pluginPath = os.Getenv("HOME") + string(os.PathSeparator) + "." + DefaultPluginVendorDirV12
		files, err = ioutil.ReadDir(pluginPath)
		if err != nil {
			return "", err
		}
	}
	providerFilePath := ""
	for _, file := range files {
		if file.IsDir() {
			continue
		}
		if strings.HasPrefix(file.Name(), "terraform-provider-"+providerName) {
			providerFilePath = pluginPath + string(os.PathSeparator) + file.Name()
		}
	}
	return providerFilePath, nil
}

func GetProviderVersion(providerName string) string {
	providerFilePath, err := getProviderFileName(providerName)
	if err != nil {
		log.Println("Can't find provider file path. Ensure that you are following https://www.terraform.io/docs/configuration/providers.html#third-party-plugins.")
		return ""
	}
	t := strings.Split(providerFilePath, string(os.PathSeparator))
	providerFileName := t[len(t)-1]
	providerFileNameParts := strings.Split(providerFileName, "_")
	if len(providerFileNameParts) < 2 {
		log.Println("Can't find provider version. Ensure that you are following https://www.terraform.io/docs/configuration/providers.html#plugin-names-and-versions.")
		return ""
	}
	providerVersion := providerFileNameParts[1]
	return "~> " + strings.TrimPrefix(providerVersion, "v")
}
<commit_msg>add support for terraform v14 plugin path<commit_after>// Copyright 2018 The Terraformer 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 providerwrapper //nolint

import (
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"runtime"
	"strings"
	"time"

	"github.com/GoogleCloudPlatform/terraformer/terraformutils/terraformerstring"

	"github.com/zclconf/go-cty/cty"

	"github.com/hashicorp/go-hclog"
	"github.com/hashicorp/go-plugin"
	"github.com/hashicorp/terraform/configs/configschema"
	tfplugin "github.com/hashicorp/terraform/plugin"
	"github.com/hashicorp/terraform/providers"
	"github.com/hashicorp/terraform/terraform"
	"github.com/hashicorp/terraform/version"
)

// DefaultDataDir is the default directory for storing local data.
const DefaultDataDir = ".terraform"

// DefaultPluginVendorDir is the location in the config directory to look for
// user-added plugin binaries. Terraform only reads from this path if it
// exists, it is never created by terraform.
const DefaultPluginVendorDirV12 = "terraform.d/plugins/" + pluginMachineName

// pluginMachineName is the directory name used in new plugin paths.
const pluginMachineName = runtime.GOOS + "_" + runtime.GOARCH

type ProviderWrapper struct {
	Provider     *tfplugin.GRPCProvider
	client       *plugin.Client
	rpcClient    plugin.ClientProtocol
	providerName string
	config       cty.Value
	schema       *providers.GetSchemaResponse
}

func NewProviderWrapper(providerName string, providerConfig cty.Value, verbose bool) (*ProviderWrapper, error) {
	p := &ProviderWrapper{}
	p.providerName = providerName
	p.config = providerConfig
	err := p.initProvider(verbose)

	return p, err
}

func (p *ProviderWrapper) Kill() {
	p.client.Kill()
}

func (p *ProviderWrapper) GetSchema() *providers.GetSchemaResponse {
	if p.schema == nil {
		r := p.Provider.GetSchema()
		p.schema = &r
	}
	return p.schema
}

func (p *ProviderWrapper) GetReadOnlyAttributes(resourceTypes []string) (map[string][]string, error) {
	r := p.GetSchema()

	if r.Diagnostics.HasErrors() {
		return nil, r.Diagnostics.Err()
	}
	readOnlyAttributes := map[string][]string{}
	for resourceName, obj := range r.ResourceTypes {
		if terraformerstring.ContainsString(resourceTypes, resourceName) {
			readOnlyAttributes[resourceName] = append(readOnlyAttributes[resourceName], "^id$")
			for k, v := range obj.Block.Attributes {
				if !v.Optional && !v.Required {
					if v.Type.IsListType() || v.Type.IsSetType() {
						readOnlyAttributes[resourceName] = append(readOnlyAttributes[resourceName], "^"+k+".(.*)")
					} else {
						readOnlyAttributes[resourceName] = append(readOnlyAttributes[resourceName], "^"+k+"$")
					}
				}
			}
			readOnlyAttributes[resourceName] = p.readObjBlocks(obj.Block.BlockTypes, readOnlyAttributes[resourceName], "-1")
		}
	}
	return readOnlyAttributes, nil
}

func (p *ProviderWrapper) readObjBlocks(block map[string]*configschema.NestedBlock, readOnlyAttributes []string, parent string) []string {
	for k, v := range block {
		if len(v.BlockTypes) > 0 {
			readOnlyAttributes = p.readObjBlocks(v.BlockTypes, readOnlyAttributes, k)
		}
		fieldCount := 0
		for key, l := range v.Attributes {
			if !l.Optional && !l.Required {
				fieldCount++
				switch v.Nesting {
				case configschema.NestingList:
					if parent == "-1" {
						readOnlyAttributes = append(readOnlyAttributes, "^"+k+".[0-9]."+key+"($|\\.[0-9]|\\.#)")
					} else {
						readOnlyAttributes = append(readOnlyAttributes, "^"+parent+".(.*)."+key+"$")
					}
				case configschema.NestingSet:
					if parent == "-1" {
						readOnlyAttributes = append(readOnlyAttributes, "^"+k+".[0-9]."+key+"$")
					} else {
						readOnlyAttributes = append(readOnlyAttributes, "^"+parent+".(.*)."+key+"($|\\.(.*))")
					}
				case configschema.NestingMap:
					readOnlyAttributes = append(readOnlyAttributes, parent+"."+key)
				default:
					readOnlyAttributes = append(readOnlyAttributes, parent+"."+key+"$")
				}
			}
		}
		if fieldCount == len(v.Block.Attributes) && fieldCount > 0 {
			readOnlyAttributes = append(readOnlyAttributes, "^"+k)
		}
	}
	return readOnlyAttributes
}

func (p *ProviderWrapper) Refresh(info *terraform.InstanceInfo, state *terraform.InstanceState) (*terraform.InstanceState, error) {
	schema := p.GetSchema()
	impliedType := schema.ResourceTypes[info.Type].Block.ImpliedType()
	priorState, err := state.AttrsAsObjectValue(impliedType)
	if err != nil {
		return nil, err
	}
	successReadResource := false
	resp := providers.ReadResourceResponse{}
	for i := 0; i < 5; i++ {
		resp = p.Provider.ReadResource(providers.ReadResourceRequest{
			TypeName:   info.Type,
			PriorState: priorState,
			Private:    []byte{},
		})
		if resp.Diagnostics.HasErrors() {
			log.Println("WARN: Fail read resource from provider, wait 300ms before retry")
			time.Sleep(300 * time.Millisecond)
			continue
		} else {
			successReadResource = true
			break
		}
	}

	if !successReadResource {
		log.Println("Fail read resource from provider, trying import command")
		// retry with regular import command - without resource attributes
		importResponse := p.Provider.ImportResourceState(providers.ImportResourceStateRequest{
			TypeName: info.Type,
			ID:       state.ID,
		})
		if importResponse.Diagnostics.HasErrors() {
			return nil, resp.Diagnostics.Err()
		}
		if len(importResponse.ImportedResources) == 0 {
			return nil, errors.New("not able to import resource for a given ID")
		}
		return terraform.NewInstanceStateShimmedFromValue(importResponse.ImportedResources[0].State, int(schema.ResourceTypes[info.Type].Version)), nil
	}

	if resp.NewState.IsNull() {
		msg := fmt.Sprintf("ERROR: Read resource response is null for resource %s", info.Id)
		return nil, errors.New(msg)
	}

	return terraform.NewInstanceStateShimmedFromValue(resp.NewState, int(schema.ResourceTypes[info.Type].Version)), nil
}

func (p *ProviderWrapper) initProvider(verbose bool) error {
	providerFilePath, err := getProviderFileName(p.providerName)
	if err != nil {
		return err
	}
	options := hclog.LoggerOptions{
		Name:   "plugin",
		Level:  hclog.Error,
		Output: os.Stdout,
	}
	if verbose {
		options.Level = hclog.Trace
	}
	logger := hclog.New(&options)
	p.client = plugin.NewClient(
		&plugin.ClientConfig{
			Cmd:              exec.Command(providerFilePath),
			HandshakeConfig:  tfplugin.Handshake,
			VersionedPlugins: tfplugin.VersionedPlugins,
			Managed:          true,
			Logger:           logger,
			AllowedProtocols: []plugin.Protocol{plugin.ProtocolGRPC},
			AutoMTLS:         true,
		})
	p.rpcClient, err = p.client.Client()
	if err != nil {
		return err
	}
	raw, err := p.rpcClient.Dispense(tfplugin.ProviderPluginName)
	if err != nil {
		return err
	}

	p.Provider = raw.(*tfplugin.GRPCProvider)

	config, err := p.GetSchema().Provider.Block.CoerceValue(p.config)
	if err != nil {
		return err
	}
	p.Provider.Configure(providers.ConfigureRequest{
		TerraformVersion: version.Version,
		Config:           config,
	})

	return nil
}

func getProviderFileName(providerName string) (string, error) {
	defaultDataDir := os.Getenv("TF_DATA_DIR")
	if defaultDataDir == "" {
		defaultDataDir = DefaultDataDir
	}
	providerFilePath, err := getProviderFileNameV13andV14(defaultDataDir, providerName)
	if err != nil || providerFilePath == "" {
		providerFilePath, err = getProviderFileNameV13andV14(os.Getenv("HOME")+string(os.PathSeparator)+
			".terraform.d", providerName)
	}
	if err != nil || providerFilePath == "" {
		return getProviderFileNameV12(providerName)
	}
	return providerFilePath, nil
}

func getProviderFileNameV13andV14(prefix, providerName string) (string, error) {
	// Read terraform v14 file path
	registryDir := prefix + string(os.PathSeparator) + "providers" + string(os.PathSeparator) +
		"registry.terraform.io"
	providerDirs, err := ioutil.ReadDir(registryDir)
	if err != nil {
		// Read terraform v13 file path
		registryDir = prefix + string(os.PathSeparator) + "plugins" + string(os.PathSeparator) +
			"registry.terraform.io"
		providerDirs, err = ioutil.ReadDir(registryDir)
		if err != nil {
			return "", err
		}
	}
	providerFilePath := ""
	for _, providerDir := range providerDirs {
		pluginPath := registryDir + string(os.PathSeparator) + providerDir.Name() +
			string(os.PathSeparator) + providerName
		dirs, err := ioutil.ReadDir(pluginPath)
		if err != nil {
			continue
		}
		for _, dir := range dirs {
			if !dir.IsDir() {
				continue
			}
			for _, dir := range dirs {
				fullPluginPath := pluginPath + string(os.PathSeparator) + dir.Name() +
					string(os.PathSeparator) + runtime.GOOS + "_" + runtime.GOARCH
				files, err := ioutil.ReadDir(fullPluginPath)
				if err == nil {
					for _, file := range files {
						if strings.HasPrefix(file.Name(), "terraform-provider-"+providerName) {
							providerFilePath = fullPluginPath + string(os.PathSeparator) + file.Name()
						}
					}
				}
			}
		}
	}
	return providerFilePath, nil
}

func getProviderFileNameV12(providerName string) (string, error) {
	defaultDataDir := os.Getenv("TF_DATA_DIR")
	if defaultDataDir == "" {
		defaultDataDir = DefaultDataDir
	}
	pluginPath := defaultDataDir + string(os.PathSeparator) + "plugins" + string(os.PathSeparator) + runtime.GOOS + "_" + runtime.GOARCH
	files, err := ioutil.ReadDir(pluginPath)
	if err != nil {
		pluginPath = os.Getenv("HOME") + string(os.PathSeparator) + "." + DefaultPluginVendorDirV12
		files, err = ioutil.ReadDir(pluginPath)
		if err != nil {
			return "", err
		}
	}
	providerFilePath := ""
	for _, file := range files {
		if file.IsDir() {
			continue
		}
		if strings.HasPrefix(file.Name(), "terraform-provider-"+providerName) {
			providerFilePath = pluginPath + string(os.PathSeparator) + file.Name()
		}
	}
	return providerFilePath, nil
}

func GetProviderVersion(providerName string) string {
	providerFilePath, err := getProviderFileName(providerName)
	if err != nil {
		log.Println("Can't find provider file path. Ensure that you are following https://www.terraform.io/docs/configuration/providers.html#third-party-plugins.")
		return ""
	}
	t := strings.Split(providerFilePath, string(os.PathSeparator))
	providerFileName := t[len(t)-1]
	providerFileNameParts := strings.Split(providerFileName, "_")
	if len(providerFileNameParts) < 2 {
		log.Println("Can't find provider version. Ensure that you are following https://www.terraform.io/docs/configuration/providers.html#plugin-names-and-versions.")
		return ""
	}
	providerVersion := providerFileNameParts[1]
	return "~> " + strings.TrimPrefix(providerVersion, "v")
}
<|endoftext|>


<commit_before>// +build integration

/*
Copyright 2016 The Kubernetes Authors All rights reserved.

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

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

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

package integration

import (
	"fmt"
	"net"
	"strings"
	"testing"
	"time"

	"github.com/docker/machine/libmachine/state"
	"k8s.io/minikube/pkg/minikube/constants"
	"k8s.io/minikube/test/integration/util"
)

func TestStartStop(t *testing.T) {
	p := profile(t) // profile name
	if isTestNoneDriver() {
		p = "minikube"
	} else {
		t.Parallel()
	}
	mk := NewMinikubeRunner(t, p)
	if !isTestNoneDriver() { // none driver doesn't need to be deleted
		defer mk.TearDown(t)
	}

	tests := []struct {
		name string
		args []string
	}{
		{"nocache_oldest", []string{
			"--cache-images=false",
			fmt.Sprintf("--kubernetes-version=%s", constants.OldestKubernetesVersion),
			// default is the network created by libvirt, if we change the name minikube won't boot
			// because the given network doesn't exist
			"--kvm-network=default",
			"--kvm-qemu-uri=qemu:///system",
		}},
		{"feature_gates_newest_cni", []string{
			"--feature-gates",
			"ServerSideApply=true",
			"--network-plugin=cni",
			"--extra-config=kubelet.network-plugin=cni",
			"--extra-config=kubeadm.pod-network-cidr=192.168.111.111/16",
			fmt.Sprintf("--kubernetes-version=%s", constants.NewestKubernetesVersion),
		}},
		{"containerd_and_non_default_apiserver_port", []string{
			"--container-runtime=containerd",
			"--docker-opt containerd=/var/run/containerd/containerd.sock",
			"--apiserver-port=8444",
		}},
		{"crio_ignore_preflights", []string{
			"--container-runtime=crio",
			"--extra-config",
			"kubeadm.ignore-preflight-errors=SystemVerification",
		}},
	}

	for _, tc := range tests {
		t.Run(tc.name, func(t *testing.T) {
			mk := NewMinikubeRunner(t, p)
			// TODO : check does this ever happen ?
			if !strings.Contains(tc.name, "docker") && isTestNoneDriver() {
				t.Skipf("skipping %s - incompatible with none driver", tc.name)
			}

			mk.RunCommand("config set WantReportErrorPrompt false", true)
			mk.RunCommand("delete", false)
			mk.CheckStatus(state.None.String())

			stdout, stderr, err := mk.Start(tc.args...)
			if err != nil {
				t.Fatalf("%s minikube start failed : %v\nstdout: %s\nstderr: %s", p, err, stdout, stderr)
			}

			mk.CheckStatus(state.Running.String())

			ip := mk.RunCommand("ip", true)
			ip = strings.TrimRight(ip, "\n")
			if net.ParseIP(ip) == nil {
				t.Fatalf("IP command returned an invalid address: %s", ip)
			}

			// check for the current-context before and after the stop
			// TODO: medya move this test to a non-parallel test so we can do more parallel
			// kr := util.NewKubectlRunner(t, p)
			// currentContext, err := kr.RunCommand([]string{"config", "current-context"}, false)
			// if err != nil {
			// 	t.Fatalf("Failed to fetch current-context")
			// }
			// if strings.TrimRight(string(currentContext), "\n") != p {
			// 	t.Fatalf("got current-context - %q, want  current-context %q", string(currentContext), p)
			// }

			checkStop := func() error {
				mk.RunCommand("stop", true)
				return mk.CheckStatusNoFail(state.Stopped.String())
			}

			if err := util.Retry(t, checkStop, 10*time.Second, 3); err != nil {
				t.Fatalf("timed out while checking stopped status: %v", err)
			}

			// TODO medyagh:  the commented code beollow was not correct ! I leave it for another PR
			// https://github.com/kubernetes/minikube/issues/4854

			// running this command results in error when the current-context is not set
			// if err := mk.Run("config current-context"); err != nil {
			// 	t.Logf("current-context is not set to minikube")
			// }

			stdout, stderr, err = mk.Start(tc.args...)
			if err != nil {
				t.Fatalf("%s minikube start failed : %v\nstdout: %s\nstderr: %s", t.Name(), err, stdout, stderr)
			}

			mk.CheckStatus(state.Running.String())

			mk.RunCommand("delete", true)
			mk.CheckStatus(state.None.String())
		})
	}
}
<commit_msg>Create a new run group for start_stop_delete tests<commit_after>// +build integration

/*
Copyright 2016 The Kubernetes Authors All rights reserved.

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

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

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

package integration

import (
	"fmt"
	"net"
	"strings"
	"testing"
	"time"

	"github.com/docker/machine/libmachine/state"
	"k8s.io/minikube/pkg/minikube/constants"
	"k8s.io/minikube/test/integration/util"
)

func TestStartStop(t *testing.T) {
	p := profile(t) // profile name
	if isTestNoneDriver() {
		p = "minikube"
	} else {
		t.Parallel()
	}
	mk := NewMinikubeRunner(t, p)
	if !isTestNoneDriver() { // none driver doesn't need to be deleted
		defer mk.TearDown(t)
	}

	tests := []struct {
		name string
		args []string
	}{
		{"nocache_oldest", []string{
			"--cache-images=false",
			fmt.Sprintf("--kubernetes-version=%s", constants.OldestKubernetesVersion),
			// default is the network created by libvirt, if we change the name minikube won't boot
			// because the given network doesn't exist
			"--kvm-network=default",
			"--kvm-qemu-uri=qemu:///system",
		}},
		{"feature_gates_newest_cni", []string{
			"--feature-gates",
			"ServerSideApply=true",
			"--network-plugin=cni",
			"--extra-config=kubelet.network-plugin=cni",
			"--extra-config=kubeadm.pod-network-cidr=192.168.111.111/16",
			fmt.Sprintf("--kubernetes-version=%s", constants.NewestKubernetesVersion),
		}},
		{"containerd_and_non_default_apiserver_port", []string{
			"--container-runtime=containerd",
			"--docker-opt containerd=/var/run/containerd/containerd.sock",
			"--apiserver-port=8444",
		}},
		{"crio_ignore_preflights", []string{
			"--container-runtime=crio",
			"--extra-config",
			"kubeadm.ignore-preflight-errors=SystemVerification",
		}},
	}
	t.Run("group", func(t *testing.T) {
		for _, tc := range tests {
			t.Run(tc.name, func(t *testing.T) {
				t.Parallel()
				mk := NewMinikubeRunner(t, p+tc.name)
				// TODO : redundant first clause, this test never happens for none
				if !strings.Contains(tc.name, "docker") && isTestNoneDriver() {
					t.Skipf("skipping %s - incompatible with none driver", tc.name)
				}

				mk.RunCommand("config set WantReportErrorPrompt false", true)
				mk.RunCommand("delete", false)
				mk.CheckStatus(state.None.String())

				stdout, stderr, err := mk.Start(tc.args...)
				if err != nil {
					t.Fatalf("%s minikube start failed : %v\nstdout: %s\nstderr: %s", p, err, stdout, stderr)
				}

				mk.CheckStatus(state.Running.String())

				ip := mk.RunCommand("ip", true)
				ip = strings.TrimRight(ip, "\n")
				if net.ParseIP(ip) == nil {
					t.Fatalf("IP command returned an invalid address: %s", ip)
				}

				// check for the current-context before and after the stop
				// TODO: medya move this test to a non-parallel test so we can do more parallel
				// kr := util.NewKubectlRunner(t, p)
				// currentContext, err := kr.RunCommand([]string{"config", "current-context"}, false)
				// if err != nil {
				// 	t.Fatalf("Failed to fetch current-context")
				// }
				// if strings.TrimRight(string(currentContext), "\n") != p {
				// 	t.Fatalf("got current-context - %q, want  current-context %q", string(currentContext), p)
				// }

				checkStop := func() error {
					mk.RunCommand("stop", true)
					return mk.CheckStatusNoFail(state.Stopped.String())
				}

				if err := util.Retry(t, checkStop, 10*time.Second, 3); err != nil {
					t.Fatalf("timed out while checking stopped status: %v", err)
				}

				// TODO medyagh:  the commented code beollow was not correct ! I leave it for another PR
				// https://github.com/kubernetes/minikube/issues/4854

				// running this command results in error when the current-context is not set
				// if err := mk.Run("config current-context"); err != nil {
				// 	t.Logf("current-context is not set to minikube")
				// }

				stdout, stderr, err = mk.Start(tc.args...)
				if err != nil {
					t.Fatalf("%s minikube start failed : %v\nstdout: %s\nstderr: %s", t.Name(), err, stdout, stderr)
				}

				mk.CheckStatus(state.Running.String())

				mk.RunCommand("delete", true)
				mk.CheckStatus(state.None.String())
			})
		}
	})
}
<|endoftext|>