<commit_before>/*
 * Copyright (c) 2013 Conformal Systems LLC <info@conformal.com>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

package main

import (
	"bytes"
	"errors"
	"fmt"
	"github.com/conformal/btcscript"
	"github.com/conformal/btcutil"
	"github.com/conformal/btcwallet/tx"
	"github.com/conformal/btcwire"
	"sort"
	"sync"
	"time"
)

// ErrInsufficientFunds represents an error where there are not enough
// funds from unspent tx outputs for a wallet to create a transaction.
var ErrInsufficientFunds = errors.New("insufficient funds")

// ErrUnknownBitcoinNet represents an error where the parsed or
// requested bitcoin network is invalid (neither mainnet nor testnet).
var ErrUnknownBitcoinNet = errors.New("unknown bitcoin network")

// TxFee represents the global transaction fee added to newly-created
// transactions and sent as a reward to the block miner.
var TxFee struct {
	sync.Mutex
	i int64
}

// UnminedTXs holds a map of transaction IDs as keys mapping to a
// hex string of a raw transaction.  If sending a raw transaction
// succeeds, the tx is added to this map and checked again after each
// new block.  If the new block contains a tx, it is removed from
// this map.  Otherwise, btcwallet will resend the tx to btcd.
var UnminedTxs = struct {
	sync.Mutex
	m map[string]string
}{
	m: make(map[string]string),
}

// ByAmount defines the methods needed to satisify sort.Interface to
// sort a slice of Utxos by their amount.
type ByAmount []*tx.Utxo

func (u ByAmount) Len() int {
	return len(u)
}

func (u ByAmount) Less(i, j int) bool {
	return u[i].Amt < u[j].Amt
}

func (u ByAmount) Swap(i, j int) {
	u[i], u[j] = u[j], u[i]
}

// selectInputs selects the minimum number possible of unspent
// outputs to use to create a new transaction that spends amt satoshis.
// Previous outputs with less than minconf confirmations are ignored.  btcout
// is the total number of satoshis which would be spent by the combination
// of all selected previous outputs.  err will equal ErrInsufficientFunds if there
// are not enough unspent outputs to spend amt.
func selectInputs(s tx.UtxoStore, amt uint64, minconf int) (inputs []*tx.Utxo, btcout uint64, err error) {
	height := getCurHeight()

	// Create list of eligible unspent previous outputs to use as tx
	// inputs, and sort by the amount in reverse order so a minimum number
	// of inputs is needed.
	eligible := make([]*tx.Utxo, 0, len(s))
	for _, utxo := range s {
		// TODO(jrick): if Height is -1, the UTXO is the result of spending
		// to a change address, resulting in a UTXO not yet mined in a block.
		// For now, disallow creating transactions until these UTXOs are mined
		// into a block and show up as part of the balance.
		if utxo.Height != -1 && int(height-utxo.Height) >= minconf {
			eligible = append(eligible, utxo)
		}
	}
	sort.Sort(sort.Reverse(ByAmount(eligible)))

	// Iterate throguh eligible transactions, appending to outputs and
	// increasing btcout.  This is finished when btcout is greater than the
	// requested amt to spend.
	for _, u := range eligible {
		inputs = append(inputs, u)
		if btcout += u.Amt; btcout >= amt {
			return inputs, btcout, nil
		}
	}
	if btcout < amt {
		return nil, 0, ErrInsufficientFunds
	}

	return inputs, btcout, nil
}

// createdTx is a type holding information regarding a newly-created
// transaction, including the raw bytes, inputs, and a address and UTXO
// for change.
type createdTx struct {
	rawTx      []byte
	inputs     []*tx.Utxo
	changeAddr string
	changeUtxo *tx.Utxo
}

// txToPairs creates a raw transaction sending the amounts for each
// address/amount pair and fee to each address and the miner.  minconf
// specifies the minimum number of confirmations required before an
// unspent output is eligible for spending. Leftover input funds not sent
// to addr or as a fee for the miner are sent to a newly generated
// address. If change is needed to return funds back to an owned
// address, changeUtxo will point to a unconfirmed (height = -1, zeroed
// block hash) Utxo.  ErrInsufficientFunds is returned if there are not
// enough eligible unspent outputs to create the transaction.
func (w *BtcWallet) txToPairs(pairs map[string]uint64, fee uint64, minconf int) (*createdTx, error) {
	// Recorded unspent transactions should not be modified until this
	// finishes.
	w.UtxoStore.RLock()
	defer w.UtxoStore.RUnlock()

	// Create a new transaction which will include all input scripts.
	msgtx := btcwire.NewMsgTx()

	// Calculate minimum amount needed for inputs.
	var amt uint64
	for _, v := range pairs {
		amt += v
	}

	// Select unspent outputs to be used in transaction.
	inputs, btcout, err := selectInputs(w.UtxoStore.s, amt+fee, minconf)
	if err != nil {
		return nil, err
	}

	// Add outputs to new tx.
	for addr, amt := range pairs {
		addr160, _, err := btcutil.DecodeAddress(addr)
		if err != nil {
			return nil, fmt.Errorf("cannot decode address: %s", err)
		}

		// Spend amt to addr160
		pkScript, err := btcscript.PayToPubKeyHashScript(addr160)
		if err != nil {
			return nil, fmt.Errorf("cannot create txout script: %s", err)
		}
		txout := btcwire.NewTxOut(int64(amt), pkScript)
		msgtx.AddTxOut(txout)
	}

	// Check if there are leftover unspent outputs, and return coins back to
	// a new address we own.
	var changeUtxo *tx.Utxo
	var changeAddr string
	if btcout > amt+fee {
		// Create a new address to spend leftover outputs to.
		// TODO(jrick): use the next chained address, not the next unused.
		var err error
		changeAddr, err = w.NextUnusedAddress()
		if err != nil {
			return nil, fmt.Errorf("failed to get next unused address: %s", err)
		}

		// Spend change
		change := btcout - (amt + fee)
		changeAddrHash, _, err := btcutil.DecodeAddress(changeAddr)
		if err != nil {
			return nil, fmt.Errorf("cannot decode new address: %s", err)
		}
		pkScript, err := btcscript.PayToPubKeyHashScript(changeAddrHash)
		if err != nil {
			return nil, fmt.Errorf("cannot create txout script: %s", err)
		}
		msgtx.AddTxOut(btcwire.NewTxOut(int64(change), pkScript))

		changeUtxo = &tx.Utxo{
			Amt: change,
			Out: tx.OutPoint{
				// Hash is unset (zeroed) here and must be filled in
				// with the transaction hash of the complete
				// transaction.
				Index: uint32(len(pairs)),
			},
			Height:    -1,
			Subscript: pkScript,
		}
		copy(changeUtxo.AddrHash[:], changeAddrHash)
	}

	// Selected unspent outputs become new transaction's inputs.
	for _, ip := range inputs {
		msgtx.AddTxIn(btcwire.NewTxIn((*btcwire.OutPoint)(&ip.Out), nil))
	}
	for i, ip := range inputs {
		addrstr, err := btcutil.EncodeAddress(ip.AddrHash[:], w.Wallet.Net())
		if err != nil {
			return nil, err
		}
		privkey, err := w.GetAddressKey(addrstr)
		if err != nil {
			return nil, fmt.Errorf("cannot get address key: %v", err)
		}

		// TODO(jrick): we want compressed pubkeys.  Switch wallet to
		// generate addresses from the compressed key.  This will break
		// armory wallet compat but oh well.
		sigscript, err := btcscript.SignatureScript(msgtx, i,
			ip.Subscript, btcscript.SigHashAll, privkey, false)
		if err != nil {
			return nil, fmt.Errorf("cannot create sigscript: %s", err)
		}
		msgtx.TxIn[i].SignatureScript = sigscript
	}

	// Validate msgtx before returning the raw transaction.
	flags := btcscript.ScriptCanonicalSignatures
	bip16 := time.Now().After(btcscript.Bip16Activation)
	if bip16 {
		flags |= btcscript.ScriptBip16
	}
	for i, txin := range msgtx.TxIn {
		engine, err := btcscript.NewScript(txin.SignatureScript, inputs[i].Subscript, i,
			msgtx, flags)
		if err != nil {
			return nil, fmt.Errorf("cannot create script engine: %s", err)
		}
		if err = engine.Execute(); err != nil {
			return nil, fmt.Errorf("cannot validate transaction: %s", err)
		}
	}

	// Fill Tx hash of change outpoint with transaction hash.
	if changeUtxo != nil {
		txHash, err := msgtx.TxSha()
		if err != nil {
			return nil, fmt.Errorf("cannot create transaction hash: %s", err)
		}
		copy(changeUtxo.Out.Hash[:], txHash[:])
	}

	buf := new(bytes.Buffer)
	msgtx.BtcEncode(buf, btcwire.ProtocolVersion)
	return &createdTx{buf.Bytes(), inputs, changeAddr, changeUtxo}, nil
}
<commit_msg>Set a default fee of 0.0001 BTC.<commit_after>/*
 * Copyright (c) 2013 Conformal Systems LLC <info@conformal.com>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

package main

import (
	"bytes"
	"errors"
	"fmt"
	"github.com/conformal/btcscript"
	"github.com/conformal/btcutil"
	"github.com/conformal/btcwallet/tx"
	"github.com/conformal/btcwire"
	"sort"
	"sync"
	"time"
)

// ErrInsufficientFunds represents an error where there are not enough
// funds from unspent tx outputs for a wallet to create a transaction.
var ErrInsufficientFunds = errors.New("insufficient funds")

// ErrUnknownBitcoinNet represents an error where the parsed or
// requested bitcoin network is invalid (neither mainnet nor testnet).
var ErrUnknownBitcoinNet = errors.New("unknown bitcoin network")

// TxFee represents the global transaction fee added to newly-created
// transactions and sent as a reward to the block miner.  i is measured
// in satoshis.
var TxFee = struct {
	sync.Mutex
	i int64
}{
	i: 10000, // This is a fee of 0.0001 BTC.
}

// UnminedTXs holds a map of transaction IDs as keys mapping to a
// hex string of a raw transaction.  If sending a raw transaction
// succeeds, the tx is added to this map and checked again after each
// new block.  If the new block contains a tx, it is removed from
// this map.  Otherwise, btcwallet will resend the tx to btcd.
var UnminedTxs = struct {
	sync.Mutex
	m map[string]string
}{
	m: make(map[string]string),
}

// ByAmount defines the methods needed to satisify sort.Interface to
// sort a slice of Utxos by their amount.
type ByAmount []*tx.Utxo

func (u ByAmount) Len() int {
	return len(u)
}

func (u ByAmount) Less(i, j int) bool {
	return u[i].Amt < u[j].Amt
}

func (u ByAmount) Swap(i, j int) {
	u[i], u[j] = u[j], u[i]
}

// selectInputs selects the minimum number possible of unspent
// outputs to use to create a new transaction that spends amt satoshis.
// Previous outputs with less than minconf confirmations are ignored.  btcout
// is the total number of satoshis which would be spent by the combination
// of all selected previous outputs.  err will equal ErrInsufficientFunds if there
// are not enough unspent outputs to spend amt.
func selectInputs(s tx.UtxoStore, amt uint64, minconf int) (inputs []*tx.Utxo, btcout uint64, err error) {
	height := getCurHeight()

	// Create list of eligible unspent previous outputs to use as tx
	// inputs, and sort by the amount in reverse order so a minimum number
	// of inputs is needed.
	eligible := make([]*tx.Utxo, 0, len(s))
	for _, utxo := range s {
		// TODO(jrick): if Height is -1, the UTXO is the result of spending
		// to a change address, resulting in a UTXO not yet mined in a block.
		// For now, disallow creating transactions until these UTXOs are mined
		// into a block and show up as part of the balance.
		if utxo.Height != -1 && int(height-utxo.Height) >= minconf {
			eligible = append(eligible, utxo)
		}
	}
	sort.Sort(sort.Reverse(ByAmount(eligible)))

	// Iterate throguh eligible transactions, appending to outputs and
	// increasing btcout.  This is finished when btcout is greater than the
	// requested amt to spend.
	for _, u := range eligible {
		inputs = append(inputs, u)
		if btcout += u.Amt; btcout >= amt {
			return inputs, btcout, nil
		}
	}
	if btcout < amt {
		return nil, 0, ErrInsufficientFunds
	}

	return inputs, btcout, nil
}

// createdTx is a type holding information regarding a newly-created
// transaction, including the raw bytes, inputs, and a address and UTXO
// for change.
type createdTx struct {
	rawTx      []byte
	inputs     []*tx.Utxo
	changeAddr string
	changeUtxo *tx.Utxo
}

// txToPairs creates a raw transaction sending the amounts for each
// address/amount pair and fee to each address and the miner.  minconf
// specifies the minimum number of confirmations required before an
// unspent output is eligible for spending. Leftover input funds not sent
// to addr or as a fee for the miner are sent to a newly generated
// address. If change is needed to return funds back to an owned
// address, changeUtxo will point to a unconfirmed (height = -1, zeroed
// block hash) Utxo.  ErrInsufficientFunds is returned if there are not
// enough eligible unspent outputs to create the transaction.
func (w *BtcWallet) txToPairs(pairs map[string]uint64, fee uint64, minconf int) (*createdTx, error) {
	// Recorded unspent transactions should not be modified until this
	// finishes.
	w.UtxoStore.RLock()
	defer w.UtxoStore.RUnlock()

	// Create a new transaction which will include all input scripts.
	msgtx := btcwire.NewMsgTx()

	// Calculate minimum amount needed for inputs.
	var amt uint64
	for _, v := range pairs {
		amt += v
	}

	// Select unspent outputs to be used in transaction.
	inputs, btcout, err := selectInputs(w.UtxoStore.s, amt+fee, minconf)
	if err != nil {
		return nil, err
	}

	// Add outputs to new tx.
	for addr, amt := range pairs {
		addr160, _, err := btcutil.DecodeAddress(addr)
		if err != nil {
			return nil, fmt.Errorf("cannot decode address: %s", err)
		}

		// Spend amt to addr160
		pkScript, err := btcscript.PayToPubKeyHashScript(addr160)
		if err != nil {
			return nil, fmt.Errorf("cannot create txout script: %s", err)
		}
		txout := btcwire.NewTxOut(int64(amt), pkScript)
		msgtx.AddTxOut(txout)
	}

	// Check if there are leftover unspent outputs, and return coins back to
	// a new address we own.
	var changeUtxo *tx.Utxo
	var changeAddr string
	if btcout > amt+fee {
		// Create a new address to spend leftover outputs to.
		// TODO(jrick): use the next chained address, not the next unused.
		var err error
		changeAddr, err = w.NextUnusedAddress()
		if err != nil {
			return nil, fmt.Errorf("failed to get next unused address: %s", err)
		}

		// Spend change
		change := btcout - (amt + fee)
		changeAddrHash, _, err := btcutil.DecodeAddress(changeAddr)
		if err != nil {
			return nil, fmt.Errorf("cannot decode new address: %s", err)
		}
		pkScript, err := btcscript.PayToPubKeyHashScript(changeAddrHash)
		if err != nil {
			return nil, fmt.Errorf("cannot create txout script: %s", err)
		}
		msgtx.AddTxOut(btcwire.NewTxOut(int64(change), pkScript))

		changeUtxo = &tx.Utxo{
			Amt: change,
			Out: tx.OutPoint{
				// Hash is unset (zeroed) here and must be filled in
				// with the transaction hash of the complete
				// transaction.
				Index: uint32(len(pairs)),
			},
			Height:    -1,
			Subscript: pkScript,
		}
		copy(changeUtxo.AddrHash[:], changeAddrHash)
	}

	// Selected unspent outputs become new transaction's inputs.
	for _, ip := range inputs {
		msgtx.AddTxIn(btcwire.NewTxIn((*btcwire.OutPoint)(&ip.Out), nil))
	}
	for i, ip := range inputs {
		addrstr, err := btcutil.EncodeAddress(ip.AddrHash[:], w.Wallet.Net())
		if err != nil {
			return nil, err
		}
		privkey, err := w.GetAddressKey(addrstr)
		if err != nil {
			return nil, fmt.Errorf("cannot get address key: %v", err)
		}

		// TODO(jrick): we want compressed pubkeys.  Switch wallet to
		// generate addresses from the compressed key.  This will break
		// armory wallet compat but oh well.
		sigscript, err := btcscript.SignatureScript(msgtx, i,
			ip.Subscript, btcscript.SigHashAll, privkey, false)
		if err != nil {
			return nil, fmt.Errorf("cannot create sigscript: %s", err)
		}
		msgtx.TxIn[i].SignatureScript = sigscript
	}

	// Validate msgtx before returning the raw transaction.
	flags := btcscript.ScriptCanonicalSignatures
	bip16 := time.Now().After(btcscript.Bip16Activation)
	if bip16 {
		flags |= btcscript.ScriptBip16
	}
	for i, txin := range msgtx.TxIn {
		engine, err := btcscript.NewScript(txin.SignatureScript, inputs[i].Subscript, i,
			msgtx, flags)
		if err != nil {
			return nil, fmt.Errorf("cannot create script engine: %s", err)
		}
		if err = engine.Execute(); err != nil {
			return nil, fmt.Errorf("cannot validate transaction: %s", err)
		}
	}

	// Fill Tx hash of change outpoint with transaction hash.
	if changeUtxo != nil {
		txHash, err := msgtx.TxSha()
		if err != nil {
			return nil, fmt.Errorf("cannot create transaction hash: %s", err)
		}
		copy(changeUtxo.Out.Hash[:], txHash[:])
	}

	buf := new(bytes.Buffer)
	msgtx.BtcEncode(buf, btcwire.ProtocolVersion)
	return &createdTx{buf.Bytes(), inputs, changeAddr, changeUtxo}, nil
}
<|endoftext|>


<commit_before><commit_msg>corrected names of example funcs<commit_after><|endoftext|>


<commit_before>// Copyright (c) 2017 Huawei Technologies Co., Ltd. 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 cli

import (
	"os"
	"os/exec"
	"testing"

	c "github.com/opensds/opensds/client"
)

func init() {
	client = NewFakeClient(&c.Config{Endpoint: TestEp})
}

func TestReplicationAction(t *testing.T) {
	beCrasher := os.Getenv("BE_CRASHER")

	if beCrasher == "1" {
		volumeAttachmentAction(volumeAttachmentCommand, []string{})
		return
	}

	cmd := exec.Command(os.Args[0], "-test.run=TestReplicationAction")
	cmd.Env = append(os.Environ(), "BE_CRASHER=1")
	err := cmd.Run()
	e, ok := err.(*exec.ExitError)

	if ok && ("exit status 1" == e.Error()) {
		return
	}

	t.Fatalf("process ran with %s, want exit status 1", e.Error())
}

func TestReplicationCreateAction(t *testing.T) {
	var args = []string{
		"3fc90eda-4ef6-410d-b1b9-f39c6476683d",
		"e0bfd484-0a95-429a-9065-2a797f673d0d",
	}
	replicationCreateAction(replicationCreateCommand, args)
}

func TestReplicationShowAction(t *testing.T) {
	var args = []string{"f2dda3d2-bf79-11e7-8665-f750b088f63e"}
	replicationShowAction(replicationShowCommand, args)
}

func TestReplicationListAction(t *testing.T) {
	var args []string
	replicationListAction(replicationListCommand, args)
}

func TestReplicationDeleteAction(t *testing.T) {
	var args = []string{"f2dda3d2-bf79-11e7-8665-f750b088f63e"}
	replicationDeleteAction(replicationDeleteCommand, args)
}

func TestReplicationUpdateAction(t *testing.T) {
	var args = []string{"f2dda3d2-bf79-11e7-8665-f750b088f63e"}
	replicationUpdateAction(replicationUpdateCommand, args)
}

func TestReplicationEnableAction(t *testing.T) {
	var args = []string{"f2dda3d2-bf79-11e7-8665-f750b088f63e"}
	replicationEnableAction(replicationEnableCommand, args)
}
func TestReplicationDisableAction(t *testing.T) {
	var args = []string{"f2dda3d2-bf79-11e7-8665-f750b088f63e"}
	replicationDisableAction(replicationDisableCommand, args)
}
func TestReplicationFailoverAction(t *testing.T) {
	var args = []string{"f2dda3d2-bf79-11e7-8665-f750b088f63e"}
	replicationFailoverAction(replicationFailoverCommand, args)
}
<commit_msg>update the copyright date<commit_after>// Copyright (c) 2018 Huawei Technologies Co., Ltd. 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 cli

import (
	"os"
	"os/exec"
	"testing"

	c "github.com/opensds/opensds/client"
)

func init() {
	client = NewFakeClient(&c.Config{Endpoint: TestEp})
}

func TestReplicationAction(t *testing.T) {
	beCrasher := os.Getenv("BE_CRASHER")

	if beCrasher == "1" {
		volumeAttachmentAction(volumeAttachmentCommand, []string{})
		return
	}

	cmd := exec.Command(os.Args[0], "-test.run=TestReplicationAction")
	cmd.Env = append(os.Environ(), "BE_CRASHER=1")
	err := cmd.Run()
	e, ok := err.(*exec.ExitError)

	if ok && ("exit status 1" == e.Error()) {
		return
	}

	t.Fatalf("process ran with %s, want exit status 1", e.Error())
}

func TestReplicationCreateAction(t *testing.T) {
	var args = []string{
		"3fc90eda-4ef6-410d-b1b9-f39c6476683d",
		"e0bfd484-0a95-429a-9065-2a797f673d0d",
	}
	replicationCreateAction(replicationCreateCommand, args)
}

func TestReplicationShowAction(t *testing.T) {
	var args = []string{"f2dda3d2-bf79-11e7-8665-f750b088f63e"}
	replicationShowAction(replicationShowCommand, args)
}

func TestReplicationListAction(t *testing.T) {
	var args []string
	replicationListAction(replicationListCommand, args)
}

func TestReplicationDeleteAction(t *testing.T) {
	var args = []string{"f2dda3d2-bf79-11e7-8665-f750b088f63e"}
	replicationDeleteAction(replicationDeleteCommand, args)
}

func TestReplicationUpdateAction(t *testing.T) {
	var args = []string{"f2dda3d2-bf79-11e7-8665-f750b088f63e"}
	replicationUpdateAction(replicationUpdateCommand, args)
}

func TestReplicationEnableAction(t *testing.T) {
	var args = []string{"f2dda3d2-bf79-11e7-8665-f750b088f63e"}
	replicationEnableAction(replicationEnableCommand, args)
}
func TestReplicationDisableAction(t *testing.T) {
	var args = []string{"f2dda3d2-bf79-11e7-8665-f750b088f63e"}
	replicationDisableAction(replicationDisableCommand, args)
}
func TestReplicationFailoverAction(t *testing.T) {
	var args = []string{"f2dda3d2-bf79-11e7-8665-f750b088f63e"}
	replicationFailoverAction(replicationFailoverCommand, args)
}
<|endoftext|>


<commit_before>/*
Copyright IBM Corp. All Rights Reserved.

SPDX-License-Identifier: Apache-2.0
*/

package pkcs11

import (
	"crypto/ecdsa"
	"crypto/rsa"
	"crypto/x509"
	"os"

	"github.com/hyperledger/fabric/bccsp"
	"github.com/hyperledger/fabric/bccsp/sw"
	"github.com/hyperledger/fabric/common/flogging"
	"github.com/miekg/pkcs11"
	"github.com/pkg/errors"
)

var (
	logger           = flogging.MustGetLogger("bccsp_p11")
	sessionCacheSize = 10
)

// New WithParams returns a new instance of the software-based BCCSP
// set at the passed security level, hash family and KeyStore.
func New(opts PKCS11Opts, keyStore bccsp.KeyStore) (bccsp.BCCSP, error) {
	// Init config
	conf := &config{}
	err := conf.setSecurityLevel(opts.SecLevel, opts.HashFamily)
	if err != nil {
		return nil, errors.Wrapf(err, "Failed initializing configuration")
	}

	swCSP, err := sw.NewWithParams(opts.SecLevel, opts.HashFamily, keyStore)
	if err != nil {
		return nil, errors.Wrapf(err, "Failed initializing fallback SW BCCSP")
	}

	// Check KeyStore
	if keyStore == nil {
		return nil, errors.New("Invalid bccsp.KeyStore instance. It must be different from nil")
	}

	lib := opts.Library
	pin := opts.Pin
	label := opts.Label
	ctx, slot, session, err := loadLib(lib, pin, label)
	if err != nil {
		return nil, errors.Wrapf(err, "Failed initializing PKCS11 library %s %s",
			lib, label)
	}

	sessions := make(chan pkcs11.SessionHandle, sessionCacheSize)
	csp := &impl{swCSP, conf, keyStore, ctx, sessions, slot, lib, opts.SoftVerify, opts.Immutable}
	csp.returnSession(*session)
	return csp, nil
}

type impl struct {
	bccsp.BCCSP

	conf *config
	ks   bccsp.KeyStore

	ctx      *pkcs11.Ctx
	sessions chan pkcs11.SessionHandle
	slot     uint

	lib        string
	softVerify bool
	//Immutable flag makes object immutable
	immutable bool
}

// KeyGen generates a key using opts.
func (csp *impl) KeyGen(opts bccsp.KeyGenOpts) (k bccsp.Key, err error) {
	// Validate arguments
	if opts == nil {
		return nil, errors.New("Invalid Opts parameter. It must not be nil")
	}

	// Parse algorithm
	switch opts.(type) {
	case *bccsp.ECDSAKeyGenOpts:
		ski, pub, err := csp.generateECKey(csp.conf.ellipticCurve, opts.Ephemeral())
		if err != nil {
			return nil, errors.Wrapf(err, "Failed generating ECDSA key")
		}
		k = &ecdsaPrivateKey{ski, ecdsaPublicKey{ski, pub}}

	case *bccsp.ECDSAP256KeyGenOpts:
		ski, pub, err := csp.generateECKey(oidNamedCurveP256, opts.Ephemeral())
		if err != nil {
			return nil, errors.Wrapf(err, "Failed generating ECDSA P256 key")
		}

		k = &ecdsaPrivateKey{ski, ecdsaPublicKey{ski, pub}}

	case *bccsp.ECDSAP384KeyGenOpts:
		ski, pub, err := csp.generateECKey(oidNamedCurveP384, opts.Ephemeral())
		if err != nil {
			return nil, errors.Wrapf(err, "Failed generating ECDSA P384 key")
		}

		k = &ecdsaPrivateKey{ski, ecdsaPublicKey{ski, pub}}

	default:
		return csp.BCCSP.KeyGen(opts)
	}

	return k, nil
}

// KeyImport imports a key from its raw representation using opts.
// The opts argument should be appropriate for the primitive used.
func (csp *impl) KeyImport(raw interface{}, opts bccsp.KeyImportOpts) (k bccsp.Key, err error) {
	// Validate arguments
	if raw == nil {
		return nil, errors.New("Invalid raw. Cannot be nil")
	}

	if opts == nil {
		return nil, errors.New("Invalid Opts parameter. It must not be nil")
	}

	switch opts.(type) {

	case *bccsp.X509PublicKeyImportOpts:
		x509Cert, ok := raw.(*x509.Certificate)
		if !ok {
			return nil, errors.New("[X509PublicKeyImportOpts] Invalid raw material. Expected *x509.Certificate")
		}

		pk := x509Cert.PublicKey

		switch pk.(type) {
		case *ecdsa.PublicKey:
			return csp.KeyImport(pk, &bccsp.ECDSAGoPublicKeyImportOpts{Temporary: opts.Ephemeral()})
		case *rsa.PublicKey:
			return csp.KeyImport(pk, &bccsp.RSAGoPublicKeyImportOpts{Temporary: opts.Ephemeral()})
		default:
			return nil, errors.New("Certificate's public key type not recognized. Supported keys: [ECDSA, RSA]")
		}

	default:
		return csp.BCCSP.KeyImport(raw, opts)

	}
}

// GetKey returns the key this CSP associates to
// the Subject Key Identifier ski.
func (csp *impl) GetKey(ski []byte) (bccsp.Key, error) {
	pubKey, isPriv, err := csp.getECKey(ski)
	if err == nil {
		if isPriv {
			return &ecdsaPrivateKey{ski, ecdsaPublicKey{ski, pubKey}}, nil
		}
		return &ecdsaPublicKey{ski, pubKey}, nil
	}
	return csp.BCCSP.GetKey(ski)
}

// Sign signs digest using key k.
// The opts argument should be appropriate for the primitive used.
//
// Note that when a signature of a hash of a larger message is needed,
// the caller is responsible for hashing the larger message and passing
// the hash (as digest).
func (csp *impl) Sign(k bccsp.Key, digest []byte, opts bccsp.SignerOpts) ([]byte, error) {
	// Validate arguments
	if k == nil {
		return nil, errors.New("Invalid Key. It must not be nil")
	}
	if len(digest) == 0 {
		return nil, errors.New("Invalid digest. Cannot be empty")
	}

	// Check key type
	switch k.(type) {
	case *ecdsaPrivateKey:
		return csp.signECDSA(*k.(*ecdsaPrivateKey), digest, opts)
	default:
		return csp.BCCSP.Sign(k, digest, opts)
	}
}

// Verify verifies signature against key k and digest
func (csp *impl) Verify(k bccsp.Key, signature, digest []byte, opts bccsp.SignerOpts) (bool, error) {
	// Validate arguments
	if k == nil {
		return false, errors.New("Invalid Key. It must not be nil")
	}
	if len(signature) == 0 {
		return false, errors.New("Invalid signature. Cannot be empty")
	}
	if len(digest) == 0 {
		return false, errors.New("Invalid digest. Cannot be empty")
	}

	// Check key type
	switch k.(type) {
	case *ecdsaPrivateKey:
		return csp.verifyECDSA(k.(*ecdsaPrivateKey).pub, signature, digest, opts)
	case *ecdsaPublicKey:
		return csp.verifyECDSA(*k.(*ecdsaPublicKey), signature, digest, opts)
	default:
		return csp.BCCSP.Verify(k, signature, digest, opts)
	}
}

// Encrypt encrypts plaintext using key k.
// The opts argument should be appropriate for the primitive used.
func (csp *impl) Encrypt(k bccsp.Key, plaintext []byte, opts bccsp.EncrypterOpts) ([]byte, error) {
	// TODO: Add PKCS11 support for encryption, when fabric starts requiring it
	return csp.BCCSP.Encrypt(k, plaintext, opts)
}

// Decrypt decrypts ciphertext using key k.
// The opts argument should be appropriate for the primitive used.
func (csp *impl) Decrypt(k bccsp.Key, ciphertext []byte, opts bccsp.DecrypterOpts) ([]byte, error) {
	return csp.BCCSP.Decrypt(k, ciphertext, opts)
}

// FindPKCS11Lib IS ONLY USED FOR TESTING
// This is a convenience function. Useful to self-configure, for tests where usual configuration is not
// available
func FindPKCS11Lib() (lib, pin, label string) {
	//FIXME: Till we workout the configuration piece, look for the libraries in the familiar places
	lib = os.Getenv("PKCS11_LIB")
	if lib == "" {
		pin = "98765432"
		label = "ForFabric"
		possibilities := []string{
			"/usr/lib/softhsm/libsofthsm2.so",                            //Debian
			"/usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so",           //Ubuntu
			"/usr/lib/s390x-linux-gnu/softhsm/libsofthsm2.so",            //Ubuntu
			"/usr/lib/powerpc64le-linux-gnu/softhsm/libsofthsm2.so",      //Power
			"/usr/local/Cellar/softhsm/2.1.0/lib/softhsm/libsofthsm2.so", //MacOS
		}
		for _, path := range possibilities {
			if _, err := os.Stat(path); !os.IsNotExist(err) {
				lib = path
				break
			}
		}
	} else {
		pin = os.Getenv("PKCS11_PIN")
		label = os.Getenv("PKCS11_LABEL")
	}
	return lib, pin, label
}
<commit_msg>FAB-14523 Update macOS SoftHSM version<commit_after>/*
Copyright IBM Corp. All Rights Reserved.

SPDX-License-Identifier: Apache-2.0
*/

package pkcs11

import (
	"crypto/ecdsa"
	"crypto/rsa"
	"crypto/x509"
	"os"

	"github.com/hyperledger/fabric/bccsp"
	"github.com/hyperledger/fabric/bccsp/sw"
	"github.com/hyperledger/fabric/common/flogging"
	"github.com/miekg/pkcs11"
	"github.com/pkg/errors"
)

var (
	logger           = flogging.MustGetLogger("bccsp_p11")
	sessionCacheSize = 10
)

// New WithParams returns a new instance of the software-based BCCSP
// set at the passed security level, hash family and KeyStore.
func New(opts PKCS11Opts, keyStore bccsp.KeyStore) (bccsp.BCCSP, error) {
	// Init config
	conf := &config{}
	err := conf.setSecurityLevel(opts.SecLevel, opts.HashFamily)
	if err != nil {
		return nil, errors.Wrapf(err, "Failed initializing configuration")
	}

	swCSP, err := sw.NewWithParams(opts.SecLevel, opts.HashFamily, keyStore)
	if err != nil {
		return nil, errors.Wrapf(err, "Failed initializing fallback SW BCCSP")
	}

	// Check KeyStore
	if keyStore == nil {
		return nil, errors.New("Invalid bccsp.KeyStore instance. It must be different from nil")
	}

	lib := opts.Library
	pin := opts.Pin
	label := opts.Label
	ctx, slot, session, err := loadLib(lib, pin, label)
	if err != nil {
		return nil, errors.Wrapf(err, "Failed initializing PKCS11 library %s %s",
			lib, label)
	}

	sessions := make(chan pkcs11.SessionHandle, sessionCacheSize)
	csp := &impl{swCSP, conf, keyStore, ctx, sessions, slot, lib, opts.SoftVerify, opts.Immutable}
	csp.returnSession(*session)
	return csp, nil
}

type impl struct {
	bccsp.BCCSP

	conf *config
	ks   bccsp.KeyStore

	ctx      *pkcs11.Ctx
	sessions chan pkcs11.SessionHandle
	slot     uint

	lib        string
	softVerify bool
	//Immutable flag makes object immutable
	immutable bool
}

// KeyGen generates a key using opts.
func (csp *impl) KeyGen(opts bccsp.KeyGenOpts) (k bccsp.Key, err error) {
	// Validate arguments
	if opts == nil {
		return nil, errors.New("Invalid Opts parameter. It must not be nil")
	}

	// Parse algorithm
	switch opts.(type) {
	case *bccsp.ECDSAKeyGenOpts:
		ski, pub, err := csp.generateECKey(csp.conf.ellipticCurve, opts.Ephemeral())
		if err != nil {
			return nil, errors.Wrapf(err, "Failed generating ECDSA key")
		}
		k = &ecdsaPrivateKey{ski, ecdsaPublicKey{ski, pub}}

	case *bccsp.ECDSAP256KeyGenOpts:
		ski, pub, err := csp.generateECKey(oidNamedCurveP256, opts.Ephemeral())
		if err != nil {
			return nil, errors.Wrapf(err, "Failed generating ECDSA P256 key")
		}

		k = &ecdsaPrivateKey{ski, ecdsaPublicKey{ski, pub}}

	case *bccsp.ECDSAP384KeyGenOpts:
		ski, pub, err := csp.generateECKey(oidNamedCurveP384, opts.Ephemeral())
		if err != nil {
			return nil, errors.Wrapf(err, "Failed generating ECDSA P384 key")
		}

		k = &ecdsaPrivateKey{ski, ecdsaPublicKey{ski, pub}}

	default:
		return csp.BCCSP.KeyGen(opts)
	}

	return k, nil
}

// KeyImport imports a key from its raw representation using opts.
// The opts argument should be appropriate for the primitive used.
func (csp *impl) KeyImport(raw interface{}, opts bccsp.KeyImportOpts) (k bccsp.Key, err error) {
	// Validate arguments
	if raw == nil {
		return nil, errors.New("Invalid raw. Cannot be nil")
	}

	if opts == nil {
		return nil, errors.New("Invalid Opts parameter. It must not be nil")
	}

	switch opts.(type) {

	case *bccsp.X509PublicKeyImportOpts:
		x509Cert, ok := raw.(*x509.Certificate)
		if !ok {
			return nil, errors.New("[X509PublicKeyImportOpts] Invalid raw material. Expected *x509.Certificate")
		}

		pk := x509Cert.PublicKey

		switch pk.(type) {
		case *ecdsa.PublicKey:
			return csp.KeyImport(pk, &bccsp.ECDSAGoPublicKeyImportOpts{Temporary: opts.Ephemeral()})
		case *rsa.PublicKey:
			return csp.KeyImport(pk, &bccsp.RSAGoPublicKeyImportOpts{Temporary: opts.Ephemeral()})
		default:
			return nil, errors.New("Certificate's public key type not recognized. Supported keys: [ECDSA, RSA]")
		}

	default:
		return csp.BCCSP.KeyImport(raw, opts)

	}
}

// GetKey returns the key this CSP associates to
// the Subject Key Identifier ski.
func (csp *impl) GetKey(ski []byte) (bccsp.Key, error) {
	pubKey, isPriv, err := csp.getECKey(ski)
	if err == nil {
		if isPriv {
			return &ecdsaPrivateKey{ski, ecdsaPublicKey{ski, pubKey}}, nil
		}
		return &ecdsaPublicKey{ski, pubKey}, nil
	}
	return csp.BCCSP.GetKey(ski)
}

// Sign signs digest using key k.
// The opts argument should be appropriate for the primitive used.
//
// Note that when a signature of a hash of a larger message is needed,
// the caller is responsible for hashing the larger message and passing
// the hash (as digest).
func (csp *impl) Sign(k bccsp.Key, digest []byte, opts bccsp.SignerOpts) ([]byte, error) {
	// Validate arguments
	if k == nil {
		return nil, errors.New("Invalid Key. It must not be nil")
	}
	if len(digest) == 0 {
		return nil, errors.New("Invalid digest. Cannot be empty")
	}

	// Check key type
	switch k.(type) {
	case *ecdsaPrivateKey:
		return csp.signECDSA(*k.(*ecdsaPrivateKey), digest, opts)
	default:
		return csp.BCCSP.Sign(k, digest, opts)
	}
}

// Verify verifies signature against key k and digest
func (csp *impl) Verify(k bccsp.Key, signature, digest []byte, opts bccsp.SignerOpts) (bool, error) {
	// Validate arguments
	if k == nil {
		return false, errors.New("Invalid Key. It must not be nil")
	}
	if len(signature) == 0 {
		return false, errors.New("Invalid signature. Cannot be empty")
	}
	if len(digest) == 0 {
		return false, errors.New("Invalid digest. Cannot be empty")
	}

	// Check key type
	switch k.(type) {
	case *ecdsaPrivateKey:
		return csp.verifyECDSA(k.(*ecdsaPrivateKey).pub, signature, digest, opts)
	case *ecdsaPublicKey:
		return csp.verifyECDSA(*k.(*ecdsaPublicKey), signature, digest, opts)
	default:
		return csp.BCCSP.Verify(k, signature, digest, opts)
	}
}

// Encrypt encrypts plaintext using key k.
// The opts argument should be appropriate for the primitive used.
func (csp *impl) Encrypt(k bccsp.Key, plaintext []byte, opts bccsp.EncrypterOpts) ([]byte, error) {
	// TODO: Add PKCS11 support for encryption, when fabric starts requiring it
	return csp.BCCSP.Encrypt(k, plaintext, opts)
}

// Decrypt decrypts ciphertext using key k.
// The opts argument should be appropriate for the primitive used.
func (csp *impl) Decrypt(k bccsp.Key, ciphertext []byte, opts bccsp.DecrypterOpts) ([]byte, error) {
	return csp.BCCSP.Decrypt(k, ciphertext, opts)
}

// FindPKCS11Lib IS ONLY USED FOR TESTING
// This is a convenience function. Useful to self-configure, for tests where usual configuration is not
// available
func FindPKCS11Lib() (lib, pin, label string) {
	//FIXME: Till we workout the configuration piece, look for the libraries in the familiar places
	lib = os.Getenv("PKCS11_LIB")
	if lib == "" {
		pin = "98765432"
		label = "ForFabric"
		possibilities := []string{
			"/usr/lib/softhsm/libsofthsm2.so",                            //Debian
			"/usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so",           //Ubuntu
			"/usr/lib/s390x-linux-gnu/softhsm/libsofthsm2.so",            //Ubuntu
			"/usr/lib/powerpc64le-linux-gnu/softhsm/libsofthsm2.so",      //Power
			"/usr/local/Cellar/softhsm/2.5.0/lib/softhsm/libsofthsm2.so", //MacOS
		}
		for _, path := range possibilities {
			if _, err := os.Stat(path); !os.IsNotExist(err) {
				lib = path
				break
			}
		}
	} else {
		pin = os.Getenv("PKCS11_PIN")
		label = os.Getenv("PKCS11_LABEL")
	}
	return lib, pin, label
}
<|endoftext|>


<commit_before>/*
 *    Copyright (C) 2017 Christian Muehlhaeuser
 *
 *    This program is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU Affero General Public License as published
 *    by the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *    Authors:
 *      Christian Muehlhaeuser <muesli@gmail.com>
 */

// Package bees is Beehive's central module system.
package bees

import (
	"errors"
	"fmt"
	"strconv"
	"strings"
)

// PlaceholderSlice is an array of Placeholder.
type PlaceholderSlice []Placeholder

// Placeholder used by ins & outs of a bee.
type Placeholder struct {
	Name  string
	Type  string
	Value interface{}
}

// Value retrieves a value from a Placeholder slice.
func (ph PlaceholderSlice) Value(name string) interface{} {
	for _, p := range ph {
		if p.Name == name {
			return p.Value
		}
	}

	return nil
}

// Bind a value from a Placeholder slice.
func (ph PlaceholderSlice) Bind(name string, dst interface{}) error {
	v := ph.Value(name)
	if v == nil {
		return errors.New("Placeholder with name " + name + " not found")
	}

	return ConvertValue(v, dst)
}

// ConvertValue tries to convert v to dst.
func ConvertValue(v interface{}, dst interface{}) error {
	switch d := dst.(type) {
	case *string:
		switch vt := v.(type) {
		case string:
			*d = vt
		case bool:
			*d = strconv.FormatBool(vt)
		case int64:
			*d = strconv.FormatInt(vt, 10)
		case int:
			*d = strconv.FormatInt(int64(vt), 10)
		default:
			panic(fmt.Sprintf("Unhandled type %+v", vt))
		}

	case *bool:
		switch vt := v.(type) {
		case bool:
			*d = vt
		case string:
			vt = strings.ToLower(vt)
			if vt == "true" || vt == "on" || vt == "yes" || vt == "1" {
				*d = true
			}
		case int64:
			*d = vt > 0
		case int:
			*d = vt > 0
		case float64:
			*d = vt > 0
		default:
			panic(fmt.Sprintf("Unhandled type %+v", vt))
		}

	case *float64:
		switch vt := v.(type) {
		case float64:
			*d = vt
		case string:
			x, _ := strconv.Atoi(vt)
			*d = float64(x)
		default:
			panic(fmt.Sprintf("Unhandled type %+v", vt))
		}

	case *int:
		switch vt := v.(type) {
		case int:
			*d = vt
		case uint:
			*d = int(vt)
		case float64:
			*d = int(vt)
		case string:
			*d, _ = strconv.Atoi(vt)
		default:
			panic(fmt.Sprintf("Unhandled type %+v", vt))
		}

	default:
		panic(fmt.Sprintf("Unhandled dst type %+v", dst))
	}

	return nil
}
<commit_msg>Handle more conversion types automatically<commit_after>/*
 *    Copyright (C) 2017 Christian Muehlhaeuser
 *
 *    This program is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU Affero General Public License as published
 *    by the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *    Authors:
 *      Christian Muehlhaeuser <muesli@gmail.com>
 */

// Package bees is Beehive's central module system.
package bees

import (
	"errors"
	"fmt"
	"strconv"
	"strings"
)

// PlaceholderSlice is an array of Placeholder.
type PlaceholderSlice []Placeholder

// Placeholder used by ins & outs of a bee.
type Placeholder struct {
	Name  string
	Type  string
	Value interface{}
}

// Value retrieves a value from a Placeholder slice.
func (ph PlaceholderSlice) Value(name string) interface{} {
	for _, p := range ph {
		if p.Name == name {
			return p.Value
		}
	}

	return nil
}

// Bind a value from a Placeholder slice.
func (ph PlaceholderSlice) Bind(name string, dst interface{}) error {
	v := ph.Value(name)
	if v == nil {
		return errors.New("Placeholder with name " + name + " not found")
	}

	return ConvertValue(v, dst)
}

// ConvertValue tries to convert v to dst.
func ConvertValue(v interface{}, dst interface{}) error {
	switch d := dst.(type) {
	case *string:
		switch vt := v.(type) {
		case string:
			*d = vt
		case bool:
			*d = strconv.FormatBool(vt)
		case int64:
			*d = strconv.FormatInt(vt, 10)
		case float64:
			*d = strconv.FormatFloat(vt, 'f', -1, 64)
		case int:
			*d = strconv.FormatInt(int64(vt), 10)
		default:
			panic(fmt.Sprintf("Unhandled type %+v for string conversion", vt))
		}

	case *[]string:
		switch vt := v.(type) {
		case []string:
			*d = vt
		case string:
			*d = strings.Split(vt, ",")
		default:
			panic(fmt.Sprintf("Unhandled type %+v for []string conversion", vt))
		}

	case *bool:
		switch vt := v.(type) {
		case bool:
			*d = vt
		case string:
			vt = strings.ToLower(vt)
			if vt == "true" || vt == "on" || vt == "yes" || vt == "1" || vt == "t" {
				*d = true
			}
		case int64:
			*d = vt > 0
		case int:
			*d = vt > 0
		case uint64:
			*d = vt > 0
		case uint:
			*d = vt > 0
		case float64:
			*d = vt > 0
		default:
			panic(fmt.Sprintf("Unhandled type %+v for bool conversion", vt))
		}

	case *float64:
		switch vt := v.(type) {
		case int64:
			*d = float64(vt)
		case int32:
			*d = float64(vt)
		case int16:
			*d = float64(vt)
		case int8:
			*d = float64(vt)
		case int:
			*d = float64(vt)
		case uint64:
			*d = float64(vt)
		case uint32:
			*d = float64(vt)
		case uint16:
			*d = float64(vt)
		case uint8:
			*d = float64(vt)
		case uint:
			*d = float64(vt)
		case float64:
			*d = vt
		case float32:
			*d = float64(vt)
		case string:
			x, _ := strconv.Atoi(vt)
			*d = float64(x)
		default:
			panic(fmt.Sprintf("Unhandled type %+v for float64 conversion", vt))
		}

	case *int:
		switch vt := v.(type) {
		case int64:
			*d = int(vt)
		case int32:
			*d = int(vt)
		case int16:
			*d = int(vt)
		case int8:
			*d = int(vt)
		case int:
			*d = vt
		case uint64:
			*d = int(vt)
		case uint32:
			*d = int(vt)
		case uint16:
			*d = int(vt)
		case uint8:
			*d = int(vt)
		case uint:
			*d = int(vt)
		case float64:
			*d = int(vt)
		case float32:
			*d = int(vt)
		case string:
			*d, _ = strconv.Atoi(vt)
		default:
			panic(fmt.Sprintf("Unhandled type %+v for int conversion", vt))
		}

	default:
		panic(fmt.Sprintf("Unhandled dst type %+v", dst))
	}

	return nil
}
<|endoftext|>


<commit_before>package stopwatch

import (
	"fmt"
	"math"
	"sync"
	"testing"
	"time"
)

func TestLaps(t *testing.T) {
	sw := New(0, true)

	time.Sleep(time.Millisecond * 100)
	sw.Lap("Session Create")

	time.Sleep(time.Millisecond * 250)
	sw.Lap("Delete File")

	time.Sleep(time.Millisecond * 300)
	sw.LapWithData("Close DB", map[string]interface{}{
		"row_count": 2,
	})

	if len(sw.Laps()) != 3 {
		t.Fatalf("Created 3 laps but found %d laps.", len(sw.Laps()))
	}

	expected := []struct {
		state    string
		duration string
	}{
		{"Session Create", "100"},
		{"Delete File", "250"},
		{"Close DB", "300"},
	}

	laps := sw.Laps()

	for i, l := range expected {
		if l.state != laps[i].state ||
			l.duration != fmt.Sprintf("%d", int(math.Floor(100*laps[i].duration.Seconds())*10)) {
			t.Fatalf("Lap %d did not contain expected state: %s and/or duration: %s", i, l.state, l.duration)
		}
	}

	// check additional bag data
	lapWithData := laps[2]
	if lapWithData.data["row_count"] != 2 {
		t.Fatalf("Missing data bag with row_count of 2")
	}
}

func TestReset(t *testing.T) {
	sw := New(0, true)

	time.Sleep(time.Millisecond * 100)
	sw.Lap("Session Create")

	expected := []struct {
		state    string
		duration string
	}{
		{"Session Create", "100"},
	}

	laps := sw.Laps()

	for i, l := range expected {
		if l.state != laps[i].state ||
			l.duration != fmt.Sprintf("%d", int(math.Floor(100*laps[i].duration.Seconds())*10)) {
			t.Fatalf("Lap %d did not contain expected state: %s and/or duration: %s", i, l.state, l.duration)
		}
	}

	sw.Reset(0, true)

	time.Sleep(time.Millisecond * 200)
	sw.Lap("Another Session Create")

	expected = []struct {
		state    string
		duration string
	}{
		{"Another Session Create", "200"},
	}

	laps = sw.Laps()

	for i, l := range expected {
		if l.state != laps[i].state ||
			l.duration != fmt.Sprintf("%d", int(math.Floor(100*laps[i].duration.Seconds())*10)) {
			t.Fatalf("Lap %d did not contain expected state: %s and/or duration: %s", i, l.state, l.duration)
		}
	}
}

func TestMultiThreadLaps(t *testing.T) {
	// Create a new StopWatch that starts off counting
	sw := New(0, true)

	// Optionally, format that time.Duration how you need it
	//	sw.SetFormatter(func(duration time.Duration) string {
	//		return fmt.Sprintf("%.1f", duration.Seconds())
	//	})

	// Take measurement of various states
	sw.Lap("Create File")

	var wg sync.WaitGroup

	wg.Add(2)
	go func() {
		defer wg.Done()
		for i := 0; i < 2; i++ {
			time.Sleep(time.Millisecond * 200)
			task := fmt.Sprintf("task %d", i)
			sw.Lap(task)
		}
	}()

	go func() {
		defer wg.Done()
		time.Sleep(time.Millisecond * 1100)
		task := "task A"
		sw.LapWithData(task, map[string]interface{}{
			"filename": "word.doc",
		})
	}()

	// Simulate some time by sleeping
	time.Sleep(time.Second * 1)
	sw.Lap("Upload File")

	// Stop the timer
	wg.Wait()
	sw.Stop()

	expected := []struct {
		state    string
		duration string
	}{
		{"Create File", "0.0"},
		{"task 0", "0.2"},
		{"task 1", "0.2"},
		{"Upload File", "0.6"},
		{"task A", "0.1"},
	}

	laps := sw.Laps()

	for i, l := range expected {
		duration := fmt.Sprintf("%.1f", laps[i].duration.Seconds())
		if l.state != laps[i].state ||
			l.duration != duration {
			t.Fatalf(
				"Lap %d: got state: %s, duration: %s. expected state: %s and/or duration: %s",
				i, laps[i].state, duration, l.state, l.duration,
			)
		}
	}
}

func TestPrintLaps(t *testing.T) {
	sw := New(0, true)
	sw.Lap("lap1")
	sw.Lap("lap2")
	laps := sw.Laps()
	go laps[0].String()
	go laps[1].String()
}

func TestLapTime(t *testing.T) {
	sw := New(0, true)
	sw.Start()
	time.Sleep(100 * time.Millisecond)
	laptime1 := sw.LapTime()
	time.Sleep(100 * time.Millisecond)
	laptime2 := sw.LapTime()
	if diff := laptime2.Seconds() - laptime1.Seconds(); diff < 0.1 {
		t.Errorf("LapTime should be at least 100 milliseconds apart")
	}
}

func TestInactiveStart(t *testing.T) {
	sw := New(0, false)
	sw.Start()
	sw.Lap("running lap")
	sw.Stop()
	sw.Lap("stopped lap")
	if laps := sw.Laps(); len(laps) != 2 {
		t.Errorf("Should capture laps even after Stop()")
	}
	sw.Reset(0, false)
	if laps := sw.Laps(); len(laps) != 0 {
		t.Errorf("After Reset(), Laps() should be empty")
	}
}
<commit_msg>make multithreaded test deterministic. remove time.Sleep<commit_after>package stopwatch

import (
	"fmt"
	"sync"
	"testing"
)

func TestLaps(t *testing.T) {
	sw := New(0, true)

	sw.Lap("Session Create")
	sw.Lap("Delete File")
	sw.LapWithData("Close DB", map[string]interface{}{
		"row_count": 2,
	})

	if len(sw.Laps()) != 3 {
		t.Fatalf("Created 3 laps but found %d laps.", len(sw.Laps()))
	}

	expected := []string{"Session Create", "Delete File", "Close DB"}

	laps := sw.Laps()

	for i, state := range expected {
		if state != laps[i].state {
			t.Fatalf("Lap %d did not contain expected state: %s", i, state)
		}
	}

	// check additional bag data
	lapWithData := laps[2]
	if lapWithData.data["row_count"] != 2 {
		t.Fatalf("Missing data bag with row_count of 2")
	}
}

func TestReset(t *testing.T) {
	sw := New(0, true)

	sw.Lap("Session Create")

	expected := []string{"Session Create"}

	laps := sw.Laps()

	for i, state := range expected {
		if state != laps[i].state {
			t.Fatalf("Lap %d did not contain expected state: %s", i, state)
		}
	}

	sw.Reset(0, true)

	sw.Lap("Another Session Create")

	expected = []string{"Another Session Create"}

	laps = sw.Laps()

	for i, state := range expected {
		if state != laps[i].state {
			t.Fatalf("Lap %d did not contain expected state: %s", i, state)
		}
	}
}

func TestMultiThreadLaps(t *testing.T) {
	// Create a new StopWatch that starts off counting
	sw := New(0, true)

	// Optionally, format that time.Duration how you need it
	//	sw.SetFormatter(func(duration time.Duration) string {
	//		return fmt.Sprintf("%.1f", duration.Seconds())
	//	})

	// Take measurement of various states
	sw.Lap("Create File")

	var wg sync.WaitGroup

	wg.Add(2)
	go func() {
		defer wg.Done()
		for i := 0; i < 2; i++ {
			task := fmt.Sprintf("task %d", i)
			sw.Lap(task)
		}
	}()

	go func() {
		defer wg.Done()
		task := "task A"
		sw.LapWithData(task, map[string]interface{}{
			"filename": "word.doc",
		})
	}()

	// Simulate some time by sleeping
	sw.Lap("Upload File")

	// Stop the timer
	wg.Wait()
	sw.Stop()

	expected := map[string]struct{}{
		"Create File": struct{}{},
		"task 0":      struct{}{},
		"task 1":      struct{}{},
		"Upload File": struct{}{},
		"task A":      struct{}{},
	}

	laps := sw.Laps()

	if len(laps) != len(expected) {
		t.Fatalf("Did not get the expected number of lap %d, instead got %d",
			len(expected), len(laps))
	}

	for i, l := range laps {
		if _, found := expected[l.state]; !found {
			t.Fatalf("Lap %d: got state: %s expected state: %s", i, laps[i].state, l.state)
		}
	}
}

func TestPrintLaps(t *testing.T) {
	sw := New(0, true)
	sw.Lap("lap1")
	sw.Lap("lap2")
	laps := sw.Laps()
	go laps[0].String()
	go laps[1].String()
}

func TestLapTime(t *testing.T) {
	sw := New(0, true)
	sw.Start()
	laptime1 := sw.LapTime()
	laptime2 := sw.LapTime()
	if diff := laptime2.Nanoseconds() - laptime1.Nanoseconds(); diff <= 0 {
		t.Errorf("LapTime difference should be greater than zero")
	}
}

func TestInactiveStart(t *testing.T) {
	sw := New(0, false)
	sw.Start()
	sw.Lap("running lap")
	sw.Stop()
	sw.Lap("stopped lap")
	if laps := sw.Laps(); len(laps) != 2 {
		t.Errorf("Should capture laps even after Stop()")
	}
	sw.Reset(0, false)
	if laps := sw.Laps(); len(laps) != 0 {
		t.Errorf("After Reset(), Laps() should be empty")
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2014 Couchbase, Inc.
// 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 main

import (
	"flag"
	"log"
	_ "net/http/pprof"
	"os"
	"os/signal"
	"runtime/pprof"

	"github.com/couchbase/indexing/secondary/common"
	"github.com/couchbase/indexing/secondary/indexer"
)

var logLevel = flag.Int("log", common.LogLevelInfo, "Log Level - 1(Info), 2(Debug), 3(Trace)")
var numVbuckets = flag.Int("vbuckets", indexer.MAX_NUM_VBUCKETS, "Number of vbuckets configured in Couchbase")
var cluster = flag.String("cluster", indexer.DEFAULT_CLUSTER_ENDPOINT, "Couchbase cluster address")
var enableManager = flag.Bool("enable_manager", false, "Enable Index Manager")

func main() {

	flag.Parse()

	go dumpOnSignalForPlatform()
	go common.ExitOnStdinClose()

	common.SetLogLevel(*logLevel)
	config := common.SystemConfig.SectionConfig("indexer.", true)

	config = config.SetValue("clusterAddr", *cluster)
	config = config.SetValue("numVbuckets", *numVbuckets)
	config = config.SetValue("enableManager", *enableManager)

	_, msg := indexer.NewIndexer(config)

	if msg.GetMsgType() != indexer.MSG_SUCCESS {
		log.Printf("Indexer Failure to Init %v", msg)
	}

}

func dumpOnSignal(signals ...os.Signal) {
	c := make(chan os.Signal, 1)
	signal.Notify(c, signals...)
	for _ = range c {
		pprof.Lookup("goroutine").WriteTo(os.Stderr, 1)
	}
}
<commit_msg>indexer: Read all indexer port numbers through cmdline params<commit_after>// Copyright (c) 2014 Couchbase, Inc.
// 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 main

import (
	"flag"
	"log"
	_ "net/http/pprof"
	"os"
	"os/signal"
	"runtime/pprof"

	"github.com/couchbase/indexing/secondary/common"
	"github.com/couchbase/indexing/secondary/indexer"
)

var (
	logLevel          = flag.Int("log", common.LogLevelInfo, "Log Level - 1(Info), 2(Debug), 3(Trace)")
	numVbuckets       = flag.Int("vbuckets", indexer.MAX_NUM_VBUCKETS, "Number of vbuckets configured in Couchbase")
	cluster           = flag.String("cluster", indexer.DEFAULT_CLUSTER_ENDPOINT, "Couchbase cluster address")
	adminPort         = flag.String("adminPort", "9100", "Index ddl and status port")
	scanPort          = flag.String("scanPort", "9101", "Index scanner port")
	streamInitPort    = flag.String("streamInitPort", "9102", "Index initial stream port")
	streamCatchupPort = flag.String("streamCatchupPort", "9103", "Index catchup stream port")
	streamMaintPort   = flag.String("streamMaintPort", "9104", "Index maintenance stream port")
	enableManager     = flag.Bool("enable_manager", false, "Enable Index Manager")
)

func main() {

	flag.Parse()

	go dumpOnSignalForPlatform()
	go common.ExitOnStdinClose()

	common.SetLogLevel(*logLevel)
	config := common.SystemConfig.SectionConfig("indexer.", true)

	config = config.SetValue("clusterAddr", *cluster)
	config = config.SetValue("numVbuckets", *numVbuckets)
	config = config.SetValue("enableManager", *enableManager)
	config = config.SetValue("adminPort", *adminPort)
	config = config.SetValue("scanPort", *scanPort)
	config = config.SetValue("streamInitPort", *streamInitPort)
	config = config.SetValue("streamCatchupPort", *streamCatchupPort)
	config = config.SetValue("streamMaintPort", *streamMaintPort)

	_, msg := indexer.NewIndexer(config)

	if msg.GetMsgType() != indexer.MSG_SUCCESS {
		log.Printf("Indexer Failure to Init %v", msg)
	}
}

func dumpOnSignal(signals ...os.Signal) {
	c := make(chan os.Signal, 1)
	signal.Notify(c, signals...)
	for _ = range c {
		pprof.Lookup("goroutine").WriteTo(os.Stderr, 1)
	}
}
<|endoftext|>


<commit_before><commit_msg>tail utility.<commit_after><|endoftext|>


<commit_before>// Copyright 2009 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.

// Simple logging package. It defines a type, Logger, with methods
// for formatting output. It also has a predefined 'standard' Logger
// accessible through helper functions Print[f|ln], Exit[f|ln], and
// Panic[f|ln], which are easier to use than creating a Logger manually.
// That logger writes to standard error and prints the date and time
// of each logged message.
// The Exit functions call os.Exit(1) after writing the log message.
// The Panic functions call panic after writing the log message.
package log

import (
	"bytes"
	"fmt"
	"io"
	"runtime"
	"os"
	"time"
)

// These flags define the output Loggers produce.
const (
	// Bits or'ed together to control what's printed. There is no control over the
	// order they appear (the order listed here) or the format they present (as
	// described in the comments).  A colon appears after these items:
	//	2009/0123 01:23:23.123123 /a/b/c/d.go:23: message
	Ldate         = 1 << iota // the date: 2009/0123
	Ltime                     // the time: 01:23:23
	Lmicroseconds             // microsecond resolution: 01:23:23.123123.  assumes Ltime.
	Llongfile                 // full file name and line number: /a/b/c/d.go:23
	Lshortfile                // final file name element and line number: d.go:23. overrides Llongfile
)

// Logger represents an active logging object.
type Logger struct {
	out    io.Writer // destination for output
	prefix string    // prefix to write at beginning of each line
	flag   int       // properties
}

// New creates a new Logger.   The out variable sets the
// destination to which log data will be written.
// The prefix appears at the beginning of each generated log line.
// The flag argument defines the logging properties.
func New(out io.Writer, prefix string, flag int) *Logger {
	return &Logger{out, prefix, flag}
}

var (
	std    = New(os.Stderr, "", Ldate|Ltime)
	stdout = New(os.Stdout, "", Ldate|Ltime) // Deprecated.
)

// Cheap integer to fixed-width decimal ASCII.  Give a negative width to avoid zero-padding.
// Knows the buffer has capacity.
func itoa(buf *bytes.Buffer, i int, wid int) {
	var u uint = uint(i)
	if u == 0 && wid <= 1 {
		buf.WriteByte('0')
		return
	}

	// Assemble decimal in reverse order.
	var b [32]byte
	bp := len(b)
	for ; u > 0 || wid > 0; u /= 10 {
		bp--
		wid--
		b[bp] = byte(u%10) + '0'
	}

	// avoid slicing b to avoid an allocation.
	for bp < len(b) {
		buf.WriteByte(b[bp])
		bp++
	}
}

func (l *Logger) formatHeader(buf *bytes.Buffer, ns int64, calldepth int) {
	buf.WriteString(l.prefix)
	if l.flag&(Ldate|Ltime|Lmicroseconds) != 0 {
		t := time.SecondsToLocalTime(ns / 1e9)
		if l.flag&Ldate != 0 {
			itoa(buf, int(t.Year), 4)
			buf.WriteByte('/')
			itoa(buf, int(t.Month), 2)
			buf.WriteByte('/')
			itoa(buf, int(t.Day), 2)
			buf.WriteByte(' ')
		}
		if l.flag&(Ltime|Lmicroseconds) != 0 {
			itoa(buf, int(t.Hour), 2)
			buf.WriteByte(':')
			itoa(buf, int(t.Minute), 2)
			buf.WriteByte(':')
			itoa(buf, int(t.Second), 2)
			if l.flag&Lmicroseconds != 0 {
				buf.WriteByte('.')
				itoa(buf, int(ns%1e9)/1e3, 6)
			}
			buf.WriteByte(' ')
		}
	}
	if l.flag&(Lshortfile|Llongfile) != 0 {
		_, file, line, ok := runtime.Caller(calldepth)
		if ok {
			if l.flag&Lshortfile != 0 {
				short := file
				for i := len(file) - 1; i > 0; i-- {
					if file[i] == '/' {
						short = file[i+1:]
						break
					}
				}
				file = short
			}
		} else {
			file = "???"
			line = 0
		}
		buf.WriteString(file)
		buf.WriteByte(':')
		itoa(buf, line, -1)
		buf.WriteString(": ")
	}
}

// Output writes the output for a logging event.  The string s contains the text to print after
// the time stamp;  calldepth is used to recover the PC.  It is provided for generality, although
// at the moment on all pre-defined paths it will be 2.
func (l *Logger) Output(calldepth int, s string) os.Error {
	now := time.Nanoseconds() // get this early.
	buf := new(bytes.Buffer)
	l.formatHeader(buf, now, calldepth+1)
	buf.WriteString(s)
	if len(s) > 0 && s[len(s)-1] != '\n' {
		buf.WriteByte('\n')
	}
	_, err := l.out.Write(buf.Bytes())
	return err
}

// Printf prints to the logger in the manner of fmt.Printf.
func (l *Logger) Printf(format string, v ...interface{}) {
	l.Output(2, fmt.Sprintf(format, v...))
}

// Print prints to the logger in the manner of fmt.Print.
func (l *Logger) Print(v ...interface{}) { l.Output(2, fmt.Sprint(v...)) }

// Println prints to the logger in the manner of fmt.Println.
func (l *Logger) Println(v ...interface{}) { l.Output(2, fmt.Sprintln(v...)) }

// SetOutput sets the output destination for the standard logger.
func SetOutput(w io.Writer) {
	std.out = w
}

// SetFlags sets the output flags for the standard logger.
func SetFlags(flag int) {
	std.flag = flag
}

// SetPrefix sets the output prefix for the standard logger.
func SetPrefix(prefix string) {
	std.prefix = prefix
}

// These functions write to the standard logger.

// Print prints to the standard logger in the manner of fmt.Print.
func Print(v ...interface{}) {
	std.Output(2, fmt.Sprint(v...))
}

// Printf prints to the standard logger in the manner of fmt.Printf.
func Printf(format string, v ...interface{}) {
	std.Output(2, fmt.Sprintf(format, v...))
}

// Println prints to the standard logger in the manner of fmt.Println.
func Println(v ...interface{}) {
	std.Output(2, fmt.Sprintln(v...))
}

// Exit is equivalent to Print() followed by a call to os.Exit(1).
func Exit(v ...interface{}) {
	std.Output(2, fmt.Sprint(v...))
	os.Exit(1)
}

// Exitf is equivalent to Printf() followed by a call to os.Exit(1).
func Exitf(format string, v ...interface{}) {
	std.Output(2, fmt.Sprintf(format, v...))
	os.Exit(1)
}

// Exitln is equivalent to Println() followed by a call to os.Exit(1).
func Exitln(v ...interface{}) {
	std.Output(2, fmt.Sprintln(v...))
	os.Exit(1)
}

// Panic is equivalent to Print() followed by a call to panic().
func Panic(v ...interface{}) {
	s := fmt.Sprint(v...)
	std.Output(2, s)
	panic(s)
}

// Panicf is equivalent to Printf() followed by a call to panic().
func Panicf(format string, v ...interface{}) {
	s := fmt.Sprintf(format, v...)
	std.Output(2, s)
	panic(s)
}

// Panicln is equivalent to Println() followed by a call to panic().
func Panicln(v ...interface{}) {
	s := fmt.Sprintln(v...)
	std.Output(2, s)
	panic(s)
}

// Everything from here on is deprecated and will be removed after the next release.

// Logf is analogous to Printf() for a Logger.
// Deprecated.
func (l *Logger) Logf(format string, v ...interface{}) {
	l.Output(2, fmt.Sprintf(format, v...))
}

// Log is analogous to Print() for a Logger.
// Deprecated.
func (l *Logger) Log(v ...interface{}) { l.Output(2, fmt.Sprintln(v...)) }

// Stdout is a helper function for easy logging to stdout. It is analogous to Print().
// Deprecated.
func Stdout(v ...interface{}) { stdout.Output(2, fmt.Sprint(v...)) }

// Stderr is a helper function for easy logging to stderr. It is analogous to Fprint(os.Stderr).
// Deprecated.
func Stderr(v ...interface{}) { std.Output(2, fmt.Sprintln(v...)) }

// Stdoutf is a helper functions for easy formatted logging to stdout. It is analogous to Printf().
// Deprecated.
func Stdoutf(format string, v ...interface{}) { stdout.Output(2, fmt.Sprintf(format, v...)) }

// Stderrf is a helper function for easy formatted logging to stderr. It is analogous to Fprintf(os.Stderr).
// Deprecated.
func Stderrf(format string, v ...interface{}) { std.Output(2, fmt.Sprintf(format, v...)) }

// Crash is equivalent to Stderr() followed by a call to panic().
// Deprecated.
func Crash(v ...interface{}) { Panicln(v...) }

// Crashf is equivalent to Stderrf() followed by a call to panic().
// Deprecated.
func Crashf(format string, v ...interface{}) { Panicf(format, v...) }
<commit_msg>log: roll back the rollback of the deprecation of the old interface.<commit_after>// Copyright 2009 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.

// Simple logging package. It defines a type, Logger, with methods
// for formatting output. It also has a predefined 'standard' Logger
// accessible through helper functions Print[f|ln], Exit[f|ln], and
// Panic[f|ln], which are easier to use than creating a Logger manually.
// That logger writes to standard error and prints the date and time
// of each logged message.
// The Exit functions call os.Exit(1) after writing the log message.
// The Panic functions call panic after writing the log message.
package log

import (
	"bytes"
	"fmt"
	"io"
	"runtime"
	"os"
	"time"
)

// These flags define the output Loggers produce.
const (
	// Bits or'ed together to control what's printed. There is no control over the
	// order they appear (the order listed here) or the format they present (as
	// described in the comments).  A colon appears after these items:
	//	2009/0123 01:23:23.123123 /a/b/c/d.go:23: message
	Ldate         = 1 << iota // the date: 2009/0123
	Ltime                     // the time: 01:23:23
	Lmicroseconds             // microsecond resolution: 01:23:23.123123.  assumes Ltime.
	Llongfile                 // full file name and line number: /a/b/c/d.go:23
	Lshortfile                // final file name element and line number: d.go:23. overrides Llongfile
)

// Logger represents an active logging object.
type Logger struct {
	out    io.Writer // destination for output
	prefix string    // prefix to write at beginning of each line
	flag   int       // properties
}

// New creates a new Logger.   The out variable sets the
// destination to which log data will be written.
// The prefix appears at the beginning of each generated log line.
// The flag argument defines the logging properties.
func New(out io.Writer, prefix string, flag int) *Logger {
	return &Logger{out, prefix, flag}
}

var std = New(os.Stderr, "", Ldate|Ltime)

// Cheap integer to fixed-width decimal ASCII.  Give a negative width to avoid zero-padding.
// Knows the buffer has capacity.
func itoa(buf *bytes.Buffer, i int, wid int) {
	var u uint = uint(i)
	if u == 0 && wid <= 1 {
		buf.WriteByte('0')
		return
	}

	// Assemble decimal in reverse order.
	var b [32]byte
	bp := len(b)
	for ; u > 0 || wid > 0; u /= 10 {
		bp--
		wid--
		b[bp] = byte(u%10) + '0'
	}

	// avoid slicing b to avoid an allocation.
	for bp < len(b) {
		buf.WriteByte(b[bp])
		bp++
	}
}

func (l *Logger) formatHeader(buf *bytes.Buffer, ns int64, calldepth int) {
	buf.WriteString(l.prefix)
	if l.flag&(Ldate|Ltime|Lmicroseconds) != 0 {
		t := time.SecondsToLocalTime(ns / 1e9)
		if l.flag&Ldate != 0 {
			itoa(buf, int(t.Year), 4)
			buf.WriteByte('/')
			itoa(buf, int(t.Month), 2)
			buf.WriteByte('/')
			itoa(buf, int(t.Day), 2)
			buf.WriteByte(' ')
		}
		if l.flag&(Ltime|Lmicroseconds) != 0 {
			itoa(buf, int(t.Hour), 2)
			buf.WriteByte(':')
			itoa(buf, int(t.Minute), 2)
			buf.WriteByte(':')
			itoa(buf, int(t.Second), 2)
			if l.flag&Lmicroseconds != 0 {
				buf.WriteByte('.')
				itoa(buf, int(ns%1e9)/1e3, 6)
			}
			buf.WriteByte(' ')
		}
	}
	if l.flag&(Lshortfile|Llongfile) != 0 {
		_, file, line, ok := runtime.Caller(calldepth)
		if ok {
			if l.flag&Lshortfile != 0 {
				short := file
				for i := len(file) - 1; i > 0; i-- {
					if file[i] == '/' {
						short = file[i+1:]
						break
					}
				}
				file = short
			}
		} else {
			file = "???"
			line = 0
		}
		buf.WriteString(file)
		buf.WriteByte(':')
		itoa(buf, line, -1)
		buf.WriteString(": ")
	}
}

// Output writes the output for a logging event.  The string s contains the text to print after
// the time stamp;  calldepth is used to recover the PC.  It is provided for generality, although
// at the moment on all pre-defined paths it will be 2.
func (l *Logger) Output(calldepth int, s string) os.Error {
	now := time.Nanoseconds() // get this early.
	buf := new(bytes.Buffer)
	l.formatHeader(buf, now, calldepth+1)
	buf.WriteString(s)
	if len(s) > 0 && s[len(s)-1] != '\n' {
		buf.WriteByte('\n')
	}
	_, err := l.out.Write(buf.Bytes())
	return err
}

// Printf prints to the logger in the manner of fmt.Printf.
func (l *Logger) Printf(format string, v ...interface{}) {
	l.Output(2, fmt.Sprintf(format, v...))
}

// Print prints to the logger in the manner of fmt.Print.
func (l *Logger) Print(v ...interface{}) { l.Output(2, fmt.Sprint(v...)) }

// Println prints to the logger in the manner of fmt.Println.
func (l *Logger) Println(v ...interface{}) { l.Output(2, fmt.Sprintln(v...)) }

// SetOutput sets the output destination for the standard logger.
func SetOutput(w io.Writer) {
	std.out = w
}

// SetFlags sets the output flags for the standard logger.
func SetFlags(flag int) {
	std.flag = flag
}

// SetPrefix sets the output prefix for the standard logger.
func SetPrefix(prefix string) {
	std.prefix = prefix
}

// These functions write to the standard logger.

// Print prints to the standard logger in the manner of fmt.Print.
func Print(v ...interface{}) {
	std.Output(2, fmt.Sprint(v...))
}

// Printf prints to the standard logger in the manner of fmt.Printf.
func Printf(format string, v ...interface{}) {
	std.Output(2, fmt.Sprintf(format, v...))
}

// Println prints to the standard logger in the manner of fmt.Println.
func Println(v ...interface{}) {
	std.Output(2, fmt.Sprintln(v...))
}

// Exit is equivalent to Print() followed by a call to os.Exit(1).
func Exit(v ...interface{}) {
	std.Output(2, fmt.Sprint(v...))
	os.Exit(1)
}

// Exitf is equivalent to Printf() followed by a call to os.Exit(1).
func Exitf(format string, v ...interface{}) {
	std.Output(2, fmt.Sprintf(format, v...))
	os.Exit(1)
}

// Exitln is equivalent to Println() followed by a call to os.Exit(1).
func Exitln(v ...interface{}) {
	std.Output(2, fmt.Sprintln(v...))
	os.Exit(1)
}

// Panic is equivalent to Print() followed by a call to panic().
func Panic(v ...interface{}) {
	s := fmt.Sprint(v...)
	std.Output(2, s)
	panic(s)
}

// Panicf is equivalent to Printf() followed by a call to panic().
func Panicf(format string, v ...interface{}) {
	s := fmt.Sprintf(format, v...)
	std.Output(2, s)
	panic(s)
}

// Panicln is equivalent to Println() followed by a call to panic().
func Panicln(v ...interface{}) {
	s := fmt.Sprintln(v...)
	std.Output(2, s)
	panic(s)
}
<|endoftext|>


<commit_before>package rpcd

import (
	"encoding/gob"
	"errors"
	"flag"
	"fmt"
	"github.com/Symantec/Dominator/lib/format"
	"github.com/Symantec/Dominator/lib/fsutil"
	"github.com/Symantec/Dominator/lib/hash"
	"github.com/Symantec/Dominator/lib/objectcache"
	objectclient "github.com/Symantec/Dominator/lib/objectserver/client"
	"github.com/Symantec/Dominator/lib/srpc"
	"github.com/Symantec/Dominator/proto/sub"
	"io"
	"os"
	"path"
	"syscall"
	"time"
)

const filePerms = syscall.S_IRUSR | syscall.S_IWUSR | syscall.S_IRGRP

var (
	exitOnFetchFailure = flag.Bool("exitOnFetchFailure", false,
		"If true, exit if there are fetch failures. For debugging only")
)

func (t *rpcType) Fetch(conn *srpc.Conn) error {
	defer conn.Flush()
	var request sub.FetchRequest
	var response sub.FetchResponse
	decoder := gob.NewDecoder(conn)
	if err := decoder.Decode(&request); err != nil {
		_, err = conn.WriteString(err.Error() + "\n")
		return err
	}
	if err := t.fetch(request, &response); err != nil {
		_, err = conn.WriteString(err.Error() + "\n")
		return err
	}
	if _, err := conn.WriteString("\n"); err != nil {
		return err
	}
	return gob.NewEncoder(conn).Encode(response)
}

func (t *rpcType) fetch(request sub.FetchRequest,
	reply *sub.FetchResponse) error {
	if *readOnly {
		txt := "Fetch() rejected due to read-only mode"
		t.logger.Println(txt)
		return errors.New(txt)
	}
	t.rwLock.Lock()
	defer t.rwLock.Unlock()
	t.logger.Printf("Fetch(%s) %d objects\n",
		request.ServerAddress, len(request.Hashes))
	if t.fetchInProgress {
		t.logger.Println("Error: fetch already in progress")
		return errors.New("fetch already in progress")
	}
	if t.updateInProgress {
		t.logger.Println("Error: update in progress")
		return errors.New("update in progress")
	}
	t.fetchInProgress = true
	go func() {
		t.lastFetchError = t.doFetch(request)
		if t.lastFetchError != nil && *exitOnFetchFailure {
			os.Exit(1)
		}
	}()
	return nil
}

func (t *rpcType) doFetch(request sub.FetchRequest) error {
	defer t.clearFetchInProgress()
	objectServer := objectclient.NewObjectClient(request.ServerAddress)
	benchmark := false
	if t.networkReaderContext.MaximumSpeed() < 1 {
		benchmark = enoughBytesForBenchmark(objectServer, request)
		if benchmark {
			objectServer.SetExclusiveGetObjects(true)
			t.logger.Println("Benchmarking network speed")
		}
	}
	objectsReader, err := objectServer.GetObjects(request.Hashes)
	if err != nil {
		t.logger.Printf("Error getting object reader:\t%s\n", err.Error())
		return err
	}
	defer objectsReader.Close()
	var totalLength uint64
	defer func() { t.rescanObjectCacheChannel <- true }()
	timeStart := time.Now()
	for _, hash := range request.Hashes {
		length, reader, err := objectsReader.NextObject()
		if err != nil {
			t.logger.Println(err)
			return err
		}
		err = readOne(t.objectsDir, hash, length,
			t.networkReaderContext.NewReader(reader))
		reader.Close()
		if err != nil {
			t.logger.Println(err)
			return err
		}
		totalLength += length
	}
	duration := time.Since(timeStart)
	speed := uint64(float64(totalLength) / duration.Seconds())
	if benchmark {
		file, err := os.Create(t.netbenchFilename)
		if err == nil {
			fmt.Fprintf(file, "%d\n", speed)
			file.Close()
		}
		t.networkReaderContext.InitialiseMaximumSpeed(speed)
	}
	t.logger.Printf("Fetch() complete. Read: %s in %s (%s/s)\n",
		format.FormatBytes(totalLength), duration, format.FormatBytes(speed))
	return nil
}

func enoughBytesForBenchmark(objectServer *objectclient.ObjectClient,
	request sub.FetchRequest) bool {
	lengths, err := objectServer.CheckObjects(request.Hashes)
	if err != nil {
		return false
	}
	var totalLength uint64
	for _, length := range lengths {
		totalLength += length
	}
	if totalLength > 1024*1024*64 {
		return true
	}
	return false
}

func readOne(objectsDir string, hash hash.Hash, length uint64,
	reader io.Reader) error {
	filename := path.Join(objectsDir, objectcache.HashToFilename(hash))
	dirname := path.Dir(filename)
	if err := os.MkdirAll(dirname, syscall.S_IRWXU); err != nil {
		return err
	}
	return fsutil.CopyToFile(filename, filePerms, reader, length)
}

func (t *rpcType) clearFetchInProgress() {
	t.rwLock.Lock()
	defer t.rwLock.Unlock()
	t.fetchInProgress = false
}
<commit_msg>Do not limit transfer speed for localhost in Subd.Fetch() RPC method.<commit_after>package rpcd

import (
	"encoding/gob"
	"errors"
	"flag"
	"fmt"
	"github.com/Symantec/Dominator/lib/format"
	"github.com/Symantec/Dominator/lib/fsutil"
	"github.com/Symantec/Dominator/lib/hash"
	"github.com/Symantec/Dominator/lib/objectcache"
	objectclient "github.com/Symantec/Dominator/lib/objectserver/client"
	"github.com/Symantec/Dominator/lib/srpc"
	"github.com/Symantec/Dominator/proto/sub"
	"io"
	"os"
	"path"
	"strings"
	"syscall"
	"time"
)

const filePerms = syscall.S_IRUSR | syscall.S_IWUSR | syscall.S_IRGRP

var (
	exitOnFetchFailure = flag.Bool("exitOnFetchFailure", false,
		"If true, exit if there are fetch failures. For debugging only")
)

func (t *rpcType) Fetch(conn *srpc.Conn) error {
	defer conn.Flush()
	var request sub.FetchRequest
	var response sub.FetchResponse
	decoder := gob.NewDecoder(conn)
	if err := decoder.Decode(&request); err != nil {
		_, err = conn.WriteString(err.Error() + "\n")
		return err
	}
	if err := t.fetch(request, &response); err != nil {
		_, err = conn.WriteString(err.Error() + "\n")
		return err
	}
	if _, err := conn.WriteString("\n"); err != nil {
		return err
	}
	return gob.NewEncoder(conn).Encode(response)
}

func (t *rpcType) fetch(request sub.FetchRequest,
	reply *sub.FetchResponse) error {
	if *readOnly {
		txt := "Fetch() rejected due to read-only mode"
		t.logger.Println(txt)
		return errors.New(txt)
	}
	t.rwLock.Lock()
	defer t.rwLock.Unlock()
	t.logger.Printf("Fetch(%s) %d objects\n",
		request.ServerAddress, len(request.Hashes))
	if t.fetchInProgress {
		t.logger.Println("Error: fetch already in progress")
		return errors.New("fetch already in progress")
	}
	if t.updateInProgress {
		t.logger.Println("Error: update in progress")
		return errors.New("update in progress")
	}
	t.fetchInProgress = true
	go func() {
		t.lastFetchError = t.doFetch(request)
		if t.lastFetchError != nil && *exitOnFetchFailure {
			os.Exit(1)
		}
	}()
	return nil
}

func (t *rpcType) doFetch(request sub.FetchRequest) error {
	defer t.clearFetchInProgress()
	objectServer := objectclient.NewObjectClient(request.ServerAddress)
	benchmark := false
	localObjectServer := false
	if fields := strings.Split(request.ServerAddress, ":"); len(fields) == 2 {
		if fields[0] == "localhost" {
			// We must be in testing mode. Go full throttle.
			localObjectServer = true
		}
	}
	if !localObjectServer && t.networkReaderContext.MaximumSpeed() < 1 {
		benchmark = enoughBytesForBenchmark(objectServer, request)
		if benchmark {
			objectServer.SetExclusiveGetObjects(true)
			t.logger.Println("Benchmarking network speed")
		}
	}
	objectsReader, err := objectServer.GetObjects(request.Hashes)
	if err != nil {
		t.logger.Printf("Error getting object reader:\t%s\n", err.Error())
		return err
	}
	defer objectsReader.Close()
	var totalLength uint64
	defer func() { t.rescanObjectCacheChannel <- true }()
	timeStart := time.Now()
	for _, hash := range request.Hashes {
		length, reader, err := objectsReader.NextObject()
		if err != nil {
			t.logger.Println(err)
			return err
		}
		r := io.Reader(reader)
		if !localObjectServer && !benchmark {
			r = t.networkReaderContext.NewReader(reader)
		}
		err = readOne(t.objectsDir, hash, length, r)
		reader.Close()
		if err != nil {
			t.logger.Println(err)
			return err
		}
		totalLength += length
	}
	duration := time.Since(timeStart)
	speed := uint64(float64(totalLength) / duration.Seconds())
	if benchmark {
		file, err := os.Create(t.netbenchFilename)
		if err == nil {
			fmt.Fprintf(file, "%d\n", speed)
			file.Close()
		}
		t.networkReaderContext.InitialiseMaximumSpeed(speed)
	}
	t.logger.Printf("Fetch() complete. Read: %s in %s (%s/s)\n",
		format.FormatBytes(totalLength), duration, format.FormatBytes(speed))
	return nil
}

func enoughBytesForBenchmark(objectServer *objectclient.ObjectClient,
	request sub.FetchRequest) bool {
	lengths, err := objectServer.CheckObjects(request.Hashes)
	if err != nil {
		return false
	}
	var totalLength uint64
	for _, length := range lengths {
		totalLength += length
	}
	if totalLength > 1024*1024*64 {
		return true
	}
	return false
}

func readOne(objectsDir string, hash hash.Hash, length uint64,
	reader io.Reader) error {
	filename := path.Join(objectsDir, objectcache.HashToFilename(hash))
	dirname := path.Dir(filename)
	if err := os.MkdirAll(dirname, syscall.S_IRWXU); err != nil {
		return err
	}
	return fsutil.CopyToFile(filename, filePerms, reader, length)
}

func (t *rpcType) clearFetchInProgress() {
	t.rwLock.Lock()
	defer t.rwLock.Unlock()
	t.fetchInProgress = false
}
<|endoftext|>


<commit_before>// Package msg helps to build a dnstap Message.
package msg

import (
	"time"

	"github.com/coredns/coredns/request"

	tap "github.com/dnstap/golang-dnstap"
	"github.com/miekg/dns"
	"github.com/pkg/errors"
)

// Data helps to build a dnstap Message.
// It can be transformed into the actual Message using ToMsg.
type Data struct {
	Type        tap.Message_Type
	Packed      []byte
	SocketProto tap.SocketProtocol
	SocketFam   tap.SocketFamily
	Address     []byte
	Port        uint32
	TimeSec     uint64
}

func FromRequest(d *Data, r request.Request) error {
	if err := networkFromWriter(d, r.W); err != nil {
		return err
	}
	socket(d, &r)
	return nil
}

func Pack(d *Data, m *dns.Msg) error {
	packed, err := m.Pack()
	if err != nil {
		return err
	}
	d.Packed = packed
	return nil
}

func Epoch(d *Data) {
	d.TimeSec = uint64(time.Now().Unix())
}
func ToMsg(d *Data) *tap.Message {
	m := tap.Message{
		Type:           &d.Type,
		SocketFamily:   &d.SocketFam,
		SocketProtocol: &d.SocketProto,
	}
	switch *m.Type {
	case tap.Message_CLIENT_QUERY,
		tap.Message_RESOLVER_QUERY,
		tap.Message_AUTH_QUERY,
		tap.Message_FORWARDER_QUERY,
		tap.Message_TOOL_QUERY:
		// is query
		m.QueryTimeSec = &d.TimeSec
		m.QueryMessage = d.Packed
	default:
		// is response
		m.ResponseTimeSec = &d.TimeSec
		m.ResponseMessage = d.Packed
	}

	// get the remote address and port depending on the event type
	switch *m.Type {
	case tap.Message_CLIENT_QUERY,
		tap.Message_CLIENT_RESPONSE,
		tap.Message_AUTH_QUERY,
		tap.Message_AUTH_RESPONSE:
		m.QueryAddress = d.Address
		m.QueryPort = &d.Port
	default:
		m.ResponseAddress = d.Address
		m.ResponsePort = &d.Port
	}

	return &m
}

func socket(d *Data, r *request.Request) {
	d.SocketFam = tap.SocketFamily_INET
	if r.Family() == 2 {
		d.SocketFam = tap.SocketFamily_INET6
	}

	d.SocketProto = tap.SocketProtocol_UDP
	if r.Proto() == "tcp" {
		d.SocketProto = tap.SocketProtocol_TCP
	}
}
func networkFromWriter(d *Data, w dns.ResponseWriter) error {
	ip, port, err := ipPort(w.RemoteAddr())
	if err != nil {
		return errors.Wrap(err, "response host")
	}
	d.Address = ip
	d.Port = port
	return nil
}
<commit_msg>msg.ToMsg alternatives<commit_after>// Package msg helps to build a dnstap Message.
package msg

import (
	"time"

	"github.com/coredns/coredns/request"

	tap "github.com/dnstap/golang-dnstap"
	"github.com/miekg/dns"
	"github.com/pkg/errors"
)

// Data helps to build a dnstap Message.
// It can be transformed into the actual Message using ToMsg.
type Data struct {
	Type        tap.Message_Type
	Packed      []byte
	SocketProto tap.SocketProtocol
	SocketFam   tap.SocketFamily
	Address     []byte
	Port        uint32
	TimeSec     uint64
}

func FromRequest(d *Data, r request.Request) error {
	if err := networkFromWriter(d, r.W); err != nil {
		return err
	}
	socket(d, &r)
	return nil
}

func Pack(d *Data, m *dns.Msg) error {
	packed, err := m.Pack()
	if err != nil {
		return err
	}
	d.Packed = packed
	return nil
}

func Epoch(d *Data) {
	d.TimeSec = uint64(time.Now().Unix())
}

// Transform the data into the actual message based on the type.
func ToMsg(d *Data) *tap.Message {
	m := tap.Message{
		Type:           &d.Type,
		SocketFamily:   &d.SocketFam,
		SocketProtocol: &d.SocketProto,
	}
	switch *m.Type {
	case tap.Message_CLIENT_QUERY,
		tap.Message_RESOLVER_QUERY,
		tap.Message_AUTH_QUERY,
		tap.Message_FORWARDER_QUERY,
		tap.Message_TOOL_QUERY:
		// is query
		m.QueryTimeSec = &d.TimeSec
		m.QueryMessage = d.Packed
	default:
		// is response
		m.ResponseTimeSec = &d.TimeSec
		m.ResponseMessage = d.Packed
	}

	// get the remote address and port depending on the event type
	switch *m.Type {
	case tap.Message_CLIENT_QUERY,
		tap.Message_CLIENT_RESPONSE,
		tap.Message_AUTH_QUERY,
		tap.Message_AUTH_RESPONSE:
		m.QueryAddress = d.Address
		m.QueryPort = &d.Port
	default:
		m.ResponseAddress = d.Address
		m.ResponsePort = &d.Port
	}

	return &m
}

// Transform the data into a client response message.
// Alternative to ToMsg.
func ToClientResponse(d *Data) *tap.Message {
	d.Type = tap.Message_CLIENT_RESPONSE
	return &tap.Message{
		Type:            &d.Type,
		SocketFamily:    &d.SocketFam,
		SocketProtocol:  &d.SocketProto,
		ResponseTimeSec: &d.TimeSec,
		ResponseMessage: d.Packed,
		QueryAddress:    d.Address,
		QueryPort:       &d.Port,
	}
}

// Transform the data into a client query message.
// Alternative to ToMsg.
func ToClientQuery(d *Data) *tap.Message {
	d.Type = tap.Message_CLIENT_QUERY
	return &tap.Message{
		Type:           &d.Type,
		SocketFamily:   &d.SocketFam,
		SocketProtocol: &d.SocketProto,
		QueryTimeSec:   &d.TimeSec,
		QueryMessage:   d.Packed,
		QueryAddress:   d.Address,
		QueryPort:      &d.Port,
	}
}

func socket(d *Data, r *request.Request) {
	d.SocketFam = tap.SocketFamily_INET
	if r.Family() == 2 {
		d.SocketFam = tap.SocketFamily_INET6
	}

	d.SocketProto = tap.SocketProtocol_UDP
	if r.Proto() == "tcp" {
		d.SocketProto = tap.SocketProtocol_TCP
	}
}
func networkFromWriter(d *Data, w dns.ResponseWriter) error {
	ip, port, err := ipPort(w.RemoteAddr())
	if err != nil {
		return errors.Wrap(err, "response host")
	}
	d.Address = ip
	d.Port = port
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"net/url"
	"os"
	"time"

	"github.com/levenlabs/go-llog"
	"github.com/levenlabs/go-srvclient"
	"github.com/levenlabs/golib/rpcutil"
	"github.com/mediocregopher/lever"
)

func main() {
	l := lever.New("rpc-cli", &lever.Opts{
		HelpHeader:         "Usage: rpc-cli [options] <url> <service.method> <parameters>\n",
		DisallowConfigFile: true,
	})
	l.Add(lever.Param{
		Name:        "--llog",
		Description: "Instead of outputting the return as json, output a llog-style message with the returned json object as the key/value params",
		Flag:        true,
	})
	l.Parse()

	argv := l.ParamRest()
	if len(argv) != 3 {
		fmt.Print(l.Help())
		exit(0)
	}

	u, method, body := argv[0], argv[1], argv[2]
	if uo, err := url.Parse(u); err == nil {
		uo.Host = srvclient.MaybeSRV(uo.Host)
		if uo.Scheme == "" {
			uo.Scheme = "http"
		}
		u = uo.String()
	}

	var ret interface{}
	err := rpcutil.JSONRPC2RawCall(u, &ret, method, body)
	if err != nil {
		llog.Error("error calling rpc method", llog.KV{"err": err})
		exit(1)
	}

	if l.ParamFlag("--llog") {
		retm, ok := ret.(map[string]interface{})
		if !ok {
			llog.Error("return value not a json object, can't llog")
			exit(1)
		}
		llog.Info("output from "+method, llog.KV(retm))
		exit(0)
	}

	out, err := json.MarshalIndent(ret, "", "    ")
	if err != nil {
		llog.Error("error marshalling json", llog.KV{"err": err})
		exit(1)
	}

	fmt.Println(string(out))
}

func exit(i int) {
	time.Sleep(100 * time.Millisecond)
	os.Exit(i)
}
<commit_msg>use srvclient.MyabeSRVURL instead of doing the logic here<commit_after>package main

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

	"github.com/levenlabs/go-llog"
	"github.com/levenlabs/go-srvclient"
	"github.com/levenlabs/golib/rpcutil"
	"github.com/mediocregopher/lever"
)

func main() {
	l := lever.New("rpc-cli", &lever.Opts{
		HelpHeader:         "Usage: rpc-cli [options] <url> <service.method> <parameters>\n",
		DisallowConfigFile: true,
	})
	l.Add(lever.Param{
		Name:        "--llog",
		Description: "Instead of outputting the return as json, output a llog-style message with the returned json object as the key/value params",
		Flag:        true,
	})
	l.Parse()

	argv := l.ParamRest()
	if len(argv) != 3 {
		fmt.Print(l.Help())
		exit(0)
	}

	u, method, body := argv[0], argv[1], argv[2]
	u = srvclient.MaybeSRVURL(u)

	var ret interface{}
	err := rpcutil.JSONRPC2RawCall(u, &ret, method, body)
	if err != nil {
		llog.Error("error calling rpc method", llog.KV{"err": err})
		exit(1)
	}

	if l.ParamFlag("--llog") {
		retm, ok := ret.(map[string]interface{})
		if !ok {
			llog.Error("return value not a json object, can't llog")
			exit(1)
		}
		llog.Info("output from "+method, llog.KV(retm))
		exit(0)
	}

	out, err := json.MarshalIndent(ret, "", "    ")
	if err != nil {
		llog.Error("error marshalling json", llog.KV{"err": err})
		exit(1)
	}

	fmt.Println(string(out))
}

func exit(i int) {
	time.Sleep(100 * time.Millisecond)
	os.Exit(i)
}
<|endoftext|>


<commit_before>package memberlist

import (
	"testing"
	"time"
)

func TestSuspicion(t *testing.T) {
	const k = 3
	const min = 500 * time.Millisecond
	const max = 2 * time.Second

	cases := []struct {
		numConfirmations int32
		confirmations    []string
		expected         time.Duration
	}{
		{0, []string{}, max},
		{1, []string{"foo"}, 1250 * time.Millisecond},
		{1, []string{"foo", "foo", "foo"}, 1250 * time.Millisecond},
		{2, []string{"foo", "bar"}, 810 * time.Millisecond},
		{3, []string{"foo", "bar", "baz"}, min},
		{4, []string{"foo", "bar", "baz", "zoo"}, min},
	}
	for i, c := range cases {
		ch := make(chan time.Duration, 1)
		start := time.Now()
		f := func(numConfirmations int32) {
			if numConfirmations != c.numConfirmations {
				t.Errorf("case %d: bad %d != %d", i, numConfirmations, c.numConfirmations)
			}

			ch <- time.Now().Sub(start)
		}

		s := newSuspicion(k, min, max, f)
		for _, peer := range c.confirmations {
			s.Corroborate(peer)
		}

		// Wait until right before the timeout and make sure the
		// timer hasn't fired.
		fudge := 100 * time.Millisecond
		time.Sleep(c.expected - fudge)
		select {
		case d := <-ch:
			t.Fatalf("case %d: should not have fired (%9.6f)", i, d.Seconds())
		default:
		}

		// Wait through the timeout and a little after and make sure it
		// fires.
		time.Sleep(2 * fudge)
		select {
		case <-ch:
		default:
			t.Fatalf("case %d: should have fired", i)
		}

		// Corroborate after to make sure it handles a negative remaining
		// time correctly and doesn't fire again.
		s.Corroborate("late")
		time.Sleep(c.expected + 2*fudge)
		select {
		case d := <-ch:
			t.Fatalf("case %d: should not have fired (%9.6f)", i, d.Seconds())
		default:
		}
	}
}
<commit_msg>Tightens up the dogpile test timing.<commit_after>package memberlist

import (
	"testing"
	"time"
)

func TestSuspicion(t *testing.T) {
	const k = 3
	const min = 500 * time.Millisecond
	const max = 2 * time.Second

	cases := []struct {
		numConfirmations int32
		confirmations    []string
		expected         time.Duration
	}{
		{0, []string{}, max},
		{1, []string{"foo"}, 1250 * time.Millisecond},
		{1, []string{"foo", "foo", "foo"}, 1250 * time.Millisecond},
		{2, []string{"foo", "bar"}, 810 * time.Millisecond},
		{3, []string{"foo", "bar", "baz"}, min},
		{4, []string{"foo", "bar", "baz", "zoo"}, min},
	}
	for i, c := range cases {
		ch := make(chan time.Duration, 1)
		start := time.Now()
		f := func(numConfirmations int32) {
			if numConfirmations != c.numConfirmations {
				t.Errorf("case %d: bad %d != %d", i, numConfirmations, c.numConfirmations)
			}

			ch <- time.Now().Sub(start)
		}

		s := newSuspicion(k, min, max, f)
		for _, peer := range c.confirmations {
			s.Corroborate(peer)
		}

		// Wait until right before the timeout and make sure the
		// timer hasn't fired.
		fudge := 25 * time.Millisecond
		time.Sleep(c.expected - fudge)
		select {
		case d := <-ch:
			t.Fatalf("case %d: should not have fired (%9.6f)", i, d.Seconds())
		default:
		}

		// Wait through the timeout and a little after and make sure it
		// fires.
		time.Sleep(2 * fudge)
		select {
		case <-ch:
		default:
			t.Fatalf("case %d: should have fired", i)
		}

		// Corroborate after to make sure it handles a negative remaining
		// time correctly and doesn't fire again.
		s.Corroborate("late")
		time.Sleep(c.expected + 2*fudge)
		select {
		case d := <-ch:
			t.Fatalf("case %d: should not have fired (%9.6f)", i, d.Seconds())
		default:
		}
	}
}
<|endoftext|>