<commit_before>package rollrus

import (
	"bytes"
	"fmt"
	"io"
	"reflect"
	"testing"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/pkg/errors"
	"github.com/stvp/roll"
)

func ExampleSetupLogging() {
	SetupLogging("some-long-token", "staging")

	// This will not be reported to Rollbar
	logrus.Info("OHAI")

	// This will be reported to Rollbar
	logrus.WithFields(logrus.Fields{"hi": "there"}).Fatal("The end.")
}

func ExampleNewHook() {
	log := logrus.New()
	hook := NewHook("my-secret-token", "production")
	log.Hooks.Add(hook)

	// This will not be reported to Rollbar
	log.WithFields(logrus.Fields{"power_level": "9001"}).Debug("It's over 9000!")

	// This will be reported to Rollbar
	log.Panic("Boom.")
}

func TestIntConversion(t *testing.T) {
	i := make(logrus.Fields)
	i["test"] = 5

	r := convertFields(i)

	v, ok := r["test"]
	if !ok {
		t.Fatal("Expected test key, but did not find it")
	}

	if v != "5" {
		t.Fatal("Expected value to equal 5, but instead it is: ", v)
	}
}

func TestErrConversion(t *testing.T) {
	i := make(logrus.Fields)
	i["test"] = fmt.Errorf("This is an error")

	r := convertFields(i)

	v, ok := r["test"]
	if !ok {
		t.Fatal("Expected test key, but did not find it")
	}

	if v != "This is an error" {
		t.Fatal("Expected value to be a string of the error but instead it is: ", v)
	}
}

func TestStringConversion(t *testing.T) {
	i := make(logrus.Fields)
	i["test"] = "This is a string"

	r := convertFields(i)

	v, ok := r["test"]
	if !ok {
		t.Fatal("Expected test key, but did not find it")
	}

	if v != "This is a string" {
		t.Fatal("Expected value to equal a certain string, but instead it is: ", v)
	}
}

func TestTimeConversion(t *testing.T) {
	now := time.Now()
	i := make(logrus.Fields)
	i["test"] = now

	r := convertFields(i)

	v, ok := r["test"]
	if !ok {
		t.Fatal("Expected test key, but did not find it")
	}

	if v != now.Format(time.RFC3339) {
		t.Fatal("Expected value to equal, but instead it is: ", v)
	}
}

func TestExtractError(t *testing.T) {
	entry := logrus.NewEntry(nil)
	entry.Data["err"] = fmt.Errorf("foo bar baz")

	cause, trace := extractError(entry)
	if len(trace) != 0 {
		t.Fatal("Expected length of trace to be equal to 0, but instead is: ", len(trace))
	}

	if cause.Error() != "foo bar baz" {
		t.Fatalf("Expected error as string to be 'foo bar baz', but was instead: %q", cause)
	}
}

func TestExtractErrorDefault(t *testing.T) {
	entry := logrus.NewEntry(nil)
	entry.Data["no-err"] = fmt.Errorf("foo bar baz")
	entry.Message = "message error"

	cause, trace := extractError(entry)
	if len(trace) != 0 {
		t.Fatal("Expected length of trace to be equal to 0, but instead is: ", len(trace))
	}

	if cause.Error() != "message error" {
		t.Fatalf("Expected error as string to be 'message error', but was instead: %q", cause)
	}
}

func TestExtractErrorFromStackTracer(t *testing.T) {
	entry := logrus.NewEntry(nil)
	entry.Data["err"] = errors.Errorf("foo bar baz")

	cause, trace := extractError(entry)
	if len(trace) != 3 {
		t.Fatal("Expected length of trace to be == 3, but instead is: ", len(trace))
	}

	if cause.Error() != "foo bar baz" {
		t.Fatalf("Expected error as string to be 'foo bar baz', but was instead: %q", cause.Error())
	}
}

func TestTriggerLevels(t *testing.T) {
	client := roll.New("foobar", "testing")
	underTest := &Hook{Client: client}
	if !reflect.DeepEqual(underTest.Levels(), defaultTriggerLevels) {
		t.Fatal("Expected Levels() to return defaultTriggerLevels")
	}

	newLevels := []logrus.Level{logrus.InfoLevel}
	underTest.triggers = newLevels
	if !reflect.DeepEqual(underTest.Levels(), newLevels) {
		t.Fatal("Expected Levels() to return newLevels")
	}
}

func TestWithIgnoredErrors(t *testing.T) {
	hook := NewHook("foobar", "testing", WithIgnoredErrors(io.EOF))

	out := new(bytes.Buffer)

	l := logrus.New()
	l.Out = out
	l.Hooks.Add(hook)

	l.WithError(io.EOF).Error()
	if hook.reported {
		t.Fatal("expected no report to have happened")
	}

	l.WithError(errors.New("hello")).Error()
	if !hook.reported {
		t.Fatal("expected a report to have happened")
	}
}
<commit_msg>Improve tests some more<commit_after>package rollrus

import (
	"bytes"
	"fmt"
	"io"
	"reflect"
	"testing"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/pkg/errors"
	"github.com/stvp/roll"
)

func ExampleSetupLogging() {
	SetupLogging("some-long-token", "staging")

	// This will not be reported to Rollbar
	logrus.Info("OHAI")

	// This will be reported to Rollbar
	logrus.WithFields(logrus.Fields{"hi": "there"}).Fatal("The end.")
}

func ExampleNewHook() {
	log := logrus.New()
	hook := NewHook("my-secret-token", "production")
	log.Hooks.Add(hook)

	// This will not be reported to Rollbar
	log.WithFields(logrus.Fields{"power_level": "9001"}).Debug("It's over 9000!")

	// This will be reported to Rollbar
	log.Panic("Boom.")
}

func TestIntConversion(t *testing.T) {
	i := make(logrus.Fields)
	i["test"] = 5

	r := convertFields(i)

	v, ok := r["test"]
	if !ok {
		t.Fatal("Expected test key, but did not find it")
	}

	if v != "5" {
		t.Fatal("Expected value to equal 5, but instead it is: ", v)
	}
}

func TestErrConversion(t *testing.T) {
	i := make(logrus.Fields)
	i["test"] = fmt.Errorf("This is an error")

	r := convertFields(i)

	v, ok := r["test"]
	if !ok {
		t.Fatal("Expected test key, but did not find it")
	}

	if v != "This is an error" {
		t.Fatal("Expected value to be a string of the error but instead it is: ", v)
	}
}

func TestStringConversion(t *testing.T) {
	i := make(logrus.Fields)
	i["test"] = "This is a string"

	r := convertFields(i)

	v, ok := r["test"]
	if !ok {
		t.Fatal("Expected test key, but did not find it")
	}

	if v != "This is a string" {
		t.Fatal("Expected value to equal a certain string, but instead it is: ", v)
	}
}

func TestTimeConversion(t *testing.T) {
	now := time.Now()
	i := make(logrus.Fields)
	i["test"] = now

	r := convertFields(i)

	v, ok := r["test"]
	if !ok {
		t.Fatal("Expected test key, but did not find it")
	}

	if v != now.Format(time.RFC3339) {
		t.Fatal("Expected value to equal, but instead it is: ", v)
	}
}

func TestExtractError(t *testing.T) {
	entry := logrus.NewEntry(nil)
	entry.Data["err"] = fmt.Errorf("foo bar baz")

	cause, trace := extractError(entry)
	if len(trace) != 0 {
		t.Fatal("Expected length of trace to be equal to 0, but instead is: ", len(trace))
	}

	if cause.Error() != "foo bar baz" {
		t.Fatalf("Expected error as string to be 'foo bar baz', but was instead: %q", cause)
	}
}

func TestExtractErrorDefault(t *testing.T) {
	entry := logrus.NewEntry(nil)
	entry.Data["no-err"] = fmt.Errorf("foo bar baz")
	entry.Message = "message error"

	cause, trace := extractError(entry)
	if len(trace) != 0 {
		t.Fatal("Expected length of trace to be equal to 0, but instead is: ", len(trace))
	}

	if cause.Error() != "message error" {
		t.Fatalf("Expected error as string to be 'message error', but was instead: %q", cause)
	}
}

func TestExtractErrorFromStackTracer(t *testing.T) {
	entry := logrus.NewEntry(nil)
	entry.Data["err"] = errors.Errorf("foo bar baz")

	cause, trace := extractError(entry)
	if len(trace) != 3 {
		t.Fatal("Expected length of trace to be == 3, but instead is: ", len(trace))
	}

	if cause.Error() != "foo bar baz" {
		t.Fatalf("Expected error as string to be 'foo bar baz', but was instead: %q", cause.Error())
	}
}

func TestTriggerLevels(t *testing.T) {
	client := roll.New("foobar", "testing")
	underTest := &Hook{Client: client}
	if !reflect.DeepEqual(underTest.Levels(), defaultTriggerLevels) {
		t.Fatal("Expected Levels() to return defaultTriggerLevels")
	}

	newLevels := []logrus.Level{logrus.InfoLevel}
	underTest.triggers = newLevels
	if !reflect.DeepEqual(underTest.Levels(), newLevels) {
		t.Fatal("Expected Levels() to return newLevels")
	}
}

func TestWithIgnoredErrors(t *testing.T) {
	hook := NewHook("foobar", "testing", WithIgnoredErrors(io.EOF))

	out := new(bytes.Buffer)

	l := logrus.New()
	l.Out = out
	l.Hooks.Add(hook)

	// direct, naked error is skipped
	l.WithError(io.EOF).Error()
	if hook.reported {
		t.Fatal("expected no report to have happened")
	}

	// similarly, if an error was wrapped, it's still skipped
	l.WithError(errors.Wrap(io.EOF, "hello")).Error()
	if hook.reported {
		t.Fatal("expected no report to have happened")
	}

	// non white listed errors must still go through.
	l.WithError(errors.New("hello")).Error()
	if !hook.reported {
		t.Fatal("expected a report to have happened")
	}
}
<|endoftext|>


<commit_before>package txdb

import (
	"bytes"
	"database/sql"
	"sort"

	"golang.org/x/net/context"

	"chain/database/pg"
	"chain/errors"
	"chain/fedchain/bc"
	"chain/strings"
)

// PoolTxs loads all pooled transactions from the database in order received.
// TODO(jeffomatic) - at some point in the future, will we want to keep this
// cached in an in-memory pool, a la btcd's TxMemPool?
func PoolTxs(ctx context.Context) ([]*bc.Tx, error) {
	const q = `SELECT data FROM pool_txs ORDER BY sort_id`
	rows, err := pg.FromContext(ctx).Query(q)
	if err != nil {
		return nil, errors.Wrap(err, "select query")
	}
	defer rows.Close()

	var txs []*bc.Tx
	for rows.Next() {
		tx := new(bc.Tx)
		err := rows.Scan(tx)
		if err != nil {
			return nil, errors.Wrap(err, "row scan")
		}
		txs = append(txs, tx)
	}

	if err := rows.Err(); err != nil {
		return nil, errors.Wrap(err, "end row scan loop")
	}

	return txs, nil
}

// GetTxs looks up transactions by their hashes
// in the block chain and in the pool.
func GetTxs(ctx context.Context, hashes ...string) (map[string]*bc.Tx, error) {
	sort.Strings(hashes)
	hashes = strings.Uniq(hashes)
	const q = `SELECT data FROM txs WHERE tx_hash=ANY($1)`
	rows, err := pg.FromContext(ctx).Query(q, pg.Strings(hashes))
	if err != nil {
		return nil, errors.Wrap(err, "get txs query")
	}
	defer rows.Close()

	txs := make(map[string]*bc.Tx, len(hashes))
	for rows.Next() {
		tx := new(bc.Tx)
		err = rows.Scan(&tx)
		if err != nil {
			return nil, errors.Wrap(err, "rows scan")
		}
		txs[tx.Hash().String()] = tx
	}
	if err := rows.Err(); err != nil {
		return nil, errors.Wrap(err, "rows end")
	}
	if len(txs) < len(hashes) {
		return nil, errors.Wrap(pg.ErrUserInputNotFound, "missing tx")
	}
	return txs, nil
}

// LatestBlock returns the most recent block.
func LatestBlock(ctx context.Context) (*bc.Block, error) {
	const q = `SELECT data FROM blocks ORDER BY height DESC LIMIT 1`
	b := new(bc.Block)
	err := pg.FromContext(ctx).QueryRow(q).Scan(b)
	if err == sql.ErrNoRows {
		return nil, errors.Wrap(err, "blocks table is empty; please seed with genesis block")
	}
	if err != nil {
		return nil, errors.Wrap(err, "select query")
	}
	return b, nil
}

func InsertBlock(ctx context.Context, block *bc.Block) error {
	const q = `
		INSERT INTO blocks (block_hash, height, data)
		VALUES ($1, $2, $3)
	`
	_, err := pg.FromContext(ctx).Exec(q, block.Hash().String(), block.Height, block)
	if err != nil {
		return errors.Wrap(err, "insert query")
	}
	return insertBlockTxs(ctx, block)
}

func InsertTx(ctx context.Context, tx *bc.Tx) error {
	const q = `INSERT INTO txs (tx_hash, data) VALUES($1, $2)`
	_, err := pg.FromContext(ctx).Exec(q, tx.Hash(), tx)
	return errors.Wrap(err, "insert query")
}

func insertBlockTxs(ctx context.Context, block *bc.Block) error {
	var (
		hashes []string
		data   [][]byte
	)
	for _, tx := range block.Transactions {
		hashes = append(hashes, tx.Hash().String())
		var buf bytes.Buffer
		_, err := tx.WriteTo(&buf)
		if err != nil {
			return errors.Wrap(err, "serializing tx")
		}
		data = append(data, buf.Bytes())
	}

	const txQ = `
		INSERT INTO txs (tx_hash, data)
		SELECT unnest($1::text[]) AS txid, unnest($2::bytea[])
		WHERE txid NOT IN (SELECT tx_hash FROM txs);
	`
	_, err := pg.FromContext(ctx).Exec(txQ, pg.Strings(hashes), pg.Byteas(data))
	if err != nil {
		return errors.Wrap(err, "insert txs")
	}

	const blockTxQ = `
		INSERT INTO blocks_txs (tx_hash, block_hash)
		unnest($1::text[], $2);
	`
	_, err = pg.FromContext(ctx).Exec(blockTxQ, pg.Strings(hashes), block.Hash())
	return errors.Wrap(err, "insert block txs")
}

// ListBlocks returns a list of the most recent blocks,
// potentially offset by a previous query's results.
func ListBlocks(ctx context.Context, prev string, limit int) ([]*bc.Block, error) {
	const q = `
		SELECT data FROM blocks WHERE ($1='' OR height<$1::bigint)
		ORDER BY height DESC LIMIT $2
	`
	rows, err := pg.FromContext(ctx).Query(q, prev, limit)
	if err != nil {
		return nil, errors.Wrap(err, "select query")
	}
	defer rows.Close()
	var blocks []*bc.Block
	for rows.Next() {
		var block bc.Block
		err := rows.Scan(&block)
		if err != nil {
			return nil, errors.Wrap(err, "row scan")
		}
		blocks = append(blocks, &block)
	}
	if err := rows.Err(); err != nil {
		return nil, errors.Wrap(err, "rows loop")
	}
	return blocks, nil
}

// GetBlock fetches a block by its hash
func GetBlock(ctx context.Context, hash string) (*bc.Block, error) {
	const q = `SELECT data FROM blocks WHERE block_hash=$1`
	block := new(bc.Block)
	err := pg.FromContext(ctx).QueryRow(q, hash).Scan(block)
	if err == sql.ErrNoRows {
		err = pg.ErrUserInputNotFound
	}
	return block, errors.WithDetailf(err, "block hash=%v", hash)
}

func RemoveBlockSpentOutputs(ctx context.Context, delta []*Output) error {
	var (
		txids []string
		ids   []uint32
	)
	for _, out := range delta {
		if !out.Spent {
			continue
		}
		txids = append(txids, out.Outpoint.Hash.String())
		ids = append(ids, out.Outpoint.Index)
	}

	const q = `
		DELETE FROM utxos
		WHERE (txid, index) IN (SELECT unnest($1::text[]), unnest($2::integer[]))
	`
	_, err := pg.FromContext(ctx).Exec(q, pg.Strings(txids), pg.Uint32s(ids))
	if err != nil {
		return errors.Wrap(err, "delete query")
	}

	return nil
}

func InsertBlockOutputs(ctx context.Context, block *bc.Block, delta []*Output) error {
	var outs utxoSet
	for _, out := range delta {
		if out.Spent {
			continue
		}
		outs.txid = append(outs.txid, out.Outpoint.Hash.String())
		outs.index = append(outs.index, out.Outpoint.Index)
		outs.assetID = append(outs.assetID, out.AssetID.String())
		outs.amount = append(outs.amount, int64(out.Value))
		outs.accountID = append(outs.accountID, out.AccountID)
		outs.managerNodeID = append(outs.managerNodeID, out.ManagerNodeID)
		outs.aIndex = append(outs.aIndex, toKeyIndex(out.AddrIndex[:]))
		outs.script = append(outs.script, out.Script)
		outs.metadata = append(outs.metadata, out.Metadata)
	}

	const q = `
		INSERT INTO utxos (
			txid, index, asset_id, amount,
			account_id, manager_node_id, addr_index,
			script, metadata,
			block_hash, block_height
		)
		SELECT
			unnest($1::text[]),
			unnest($2::bigint[]),
			unnest($3::text[]),
			unnest($4::bigint[]),
			unnest($5::text[]),
			unnest($6::text[]),
			unnest($7::bigint[]),
			unnest($8::bytea[]),
			unnest($9::bytea[]),
			$10,
			$11
	`
	_, err := pg.FromContext(ctx).Exec(q,
		outs.txid,
		outs.index,
		outs.assetID,
		outs.amount,
		outs.accountID,
		outs.managerNodeID,
		outs.aIndex,
		outs.script,
		outs.metadata,
		block.Hash().String(),
		block.Height,
	)
	return errors.Wrap(err)
}
<commit_msg>api/txdb: fix some SQL errors<commit_after>package txdb

import (
	"bytes"
	"database/sql"
	"sort"

	"golang.org/x/net/context"

	"chain/database/pg"
	"chain/errors"
	"chain/fedchain/bc"
	"chain/strings"
)

// PoolTxs loads all pooled transactions from the database in order received.
// TODO(jeffomatic) - at some point in the future, will we want to keep this
// cached in an in-memory pool, a la btcd's TxMemPool?
func PoolTxs(ctx context.Context) ([]*bc.Tx, error) {
	const q = `SELECT data FROM pool_txs ORDER BY sort_id`
	rows, err := pg.FromContext(ctx).Query(q)
	if err != nil {
		return nil, errors.Wrap(err, "select query")
	}
	defer rows.Close()

	var txs []*bc.Tx
	for rows.Next() {
		tx := new(bc.Tx)
		err := rows.Scan(tx)
		if err != nil {
			return nil, errors.Wrap(err, "row scan")
		}
		txs = append(txs, tx)
	}

	if err := rows.Err(); err != nil {
		return nil, errors.Wrap(err, "end row scan loop")
	}

	return txs, nil
}

// GetTxs looks up transactions by their hashes
// in the block chain and in the pool.
func GetTxs(ctx context.Context, hashes ...string) (map[string]*bc.Tx, error) {
	sort.Strings(hashes)
	hashes = strings.Uniq(hashes)
	const q = `SELECT data FROM txs WHERE tx_hash=ANY($1)`
	rows, err := pg.FromContext(ctx).Query(q, pg.Strings(hashes))
	if err != nil {
		return nil, errors.Wrap(err, "get txs query")
	}
	defer rows.Close()

	txs := make(map[string]*bc.Tx, len(hashes))
	for rows.Next() {
		tx := new(bc.Tx)
		err = rows.Scan(&tx)
		if err != nil {
			return nil, errors.Wrap(err, "rows scan")
		}
		txs[tx.Hash().String()] = tx
	}
	if err := rows.Err(); err != nil {
		return nil, errors.Wrap(err, "rows end")
	}
	if len(txs) < len(hashes) {
		return nil, errors.Wrap(pg.ErrUserInputNotFound, "missing tx")
	}
	return txs, nil
}

// LatestBlock returns the most recent block.
func LatestBlock(ctx context.Context) (*bc.Block, error) {
	const q = `SELECT data FROM blocks ORDER BY height DESC LIMIT 1`
	b := new(bc.Block)
	err := pg.FromContext(ctx).QueryRow(q).Scan(b)
	if err == sql.ErrNoRows {
		return nil, errors.Wrap(err, "blocks table is empty; please seed with genesis block")
	}
	if err != nil {
		return nil, errors.Wrap(err, "select query")
	}
	return b, nil
}

func InsertBlock(ctx context.Context, block *bc.Block) error {
	const q = `
		INSERT INTO blocks (block_hash, height, data)
		VALUES ($1, $2, $3)
	`
	_, err := pg.FromContext(ctx).Exec(q, block.Hash().String(), block.Height, block)
	if err != nil {
		return errors.Wrap(err, "insert query")
	}
	return insertBlockTxs(ctx, block)
}

func InsertTx(ctx context.Context, tx *bc.Tx) error {
	const q = `INSERT INTO txs (tx_hash, data) VALUES($1, $2)`
	_, err := pg.FromContext(ctx).Exec(q, tx.Hash(), tx)
	return errors.Wrap(err, "insert query")
}

func insertBlockTxs(ctx context.Context, block *bc.Block) error {
	var (
		hashes []string
		data   [][]byte
	)
	for _, tx := range block.Transactions {
		hashes = append(hashes, tx.Hash().String())
		var buf bytes.Buffer
		_, err := tx.WriteTo(&buf)
		if err != nil {
			return errors.Wrap(err, "serializing tx")
		}
		data = append(data, buf.Bytes())
	}

	const txQ = `
		WITH t AS (SELECT unnest($1::text[]) txid, unnest($2::bytea[]) dat)
		INSERT INTO txs (tx_hash, data)
		SELECT txid, dat FROM t
		WHERE t.txid NOT IN (SELECT tx_hash FROM txs);
	`
	_, err := pg.FromContext(ctx).Exec(txQ, pg.Strings(hashes), pg.Byteas(data))
	if err != nil {
		return errors.Wrap(err, "insert txs")
	}

	const blockTxQ = `
		INSERT INTO blocks_txs (tx_hash, block_hash)
		SELECT unnest($1::text[]), $2;
	`
	_, err = pg.FromContext(ctx).Exec(blockTxQ, pg.Strings(hashes), block.Hash())
	return errors.Wrap(err, "insert block txs")
}

// ListBlocks returns a list of the most recent blocks,
// potentially offset by a previous query's results.
func ListBlocks(ctx context.Context, prev string, limit int) ([]*bc.Block, error) {
	const q = `
		SELECT data FROM blocks WHERE ($1='' OR height<$1::bigint)
		ORDER BY height DESC LIMIT $2
	`
	rows, err := pg.FromContext(ctx).Query(q, prev, limit)
	if err != nil {
		return nil, errors.Wrap(err, "select query")
	}
	defer rows.Close()
	var blocks []*bc.Block
	for rows.Next() {
		var block bc.Block
		err := rows.Scan(&block)
		if err != nil {
			return nil, errors.Wrap(err, "row scan")
		}
		blocks = append(blocks, &block)
	}
	if err := rows.Err(); err != nil {
		return nil, errors.Wrap(err, "rows loop")
	}
	return blocks, nil
}

// GetBlock fetches a block by its hash
func GetBlock(ctx context.Context, hash string) (*bc.Block, error) {
	const q = `SELECT data FROM blocks WHERE block_hash=$1`
	block := new(bc.Block)
	err := pg.FromContext(ctx).QueryRow(q, hash).Scan(block)
	if err == sql.ErrNoRows {
		err = pg.ErrUserInputNotFound
	}
	return block, errors.WithDetailf(err, "block hash=%v", hash)
}

func RemoveBlockSpentOutputs(ctx context.Context, delta []*Output) error {
	var (
		txids []string
		ids   []uint32
	)
	for _, out := range delta {
		if !out.Spent {
			continue
		}
		txids = append(txids, out.Outpoint.Hash.String())
		ids = append(ids, out.Outpoint.Index)
	}

	const q = `
		DELETE FROM utxos
		WHERE (txid, index) IN (SELECT unnest($1::text[]), unnest($2::integer[]))
	`
	_, err := pg.FromContext(ctx).Exec(q, pg.Strings(txids), pg.Uint32s(ids))
	if err != nil {
		return errors.Wrap(err, "delete query")
	}

	return nil
}

func InsertBlockOutputs(ctx context.Context, block *bc.Block, delta []*Output) error {
	var outs utxoSet
	for _, out := range delta {
		if out.Spent {
			continue
		}
		outs.txid = append(outs.txid, out.Outpoint.Hash.String())
		outs.index = append(outs.index, out.Outpoint.Index)
		outs.assetID = append(outs.assetID, out.AssetID.String())
		outs.amount = append(outs.amount, int64(out.Value))
		outs.accountID = append(outs.accountID, out.AccountID)
		outs.managerNodeID = append(outs.managerNodeID, out.ManagerNodeID)
		outs.aIndex = append(outs.aIndex, toKeyIndex(out.AddrIndex[:]))
		outs.script = append(outs.script, out.Script)
		outs.metadata = append(outs.metadata, out.Metadata)
	}

	const q = `
		INSERT INTO utxos (
			txid, index, asset_id, amount,
			account_id, manager_node_id, addr_index,
			script, metadata,
			block_hash, block_height
		)
		SELECT
			unnest($1::text[]),
			unnest($2::bigint[]),
			unnest($3::text[]),
			unnest($4::bigint[]),
			unnest($5::text[]),
			unnest($6::text[]),
			unnest($7::bigint[]),
			unnest($8::bytea[]),
			unnest($9::bytea[]),
			$10,
			$11
	`
	_, err := pg.FromContext(ctx).Exec(q,
		outs.txid,
		outs.index,
		outs.assetID,
		outs.amount,
		outs.accountID,
		outs.managerNodeID,
		outs.aIndex,
		outs.script,
		outs.metadata,
		block.Hash().String(),
		block.Height,
	)
	return errors.Wrap(err)
}
<|endoftext|>


<commit_before>package api

import (
	"encoding/json"
	"fmt"
	"github.com/svdberg/syncmysport-runkeeper/Godeps/_workspace/src/github.com/strava/go.strava"
	sync "github.com/svdberg/syncmysport-runkeeper/sync"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"time"
)

const startTime = -1 * time.Duration(1) * time.Hour * 24 * 365 //1 year ago
const RkClientId = "73664cff18ed4800aab6cffc7ef8f4e1"

var (
	DbConnectionString string
	RkSecret           string
	StvSecret          string
	RedirectUriRk      string
	RedirectUriStv     string
	authenticator      *strava.OAuthAuthenticator
)

func Start(connString string, port int, secretRk string, redirectRk string, secretStv string, redirectStv string) {
	DbConnectionString = connString
	RkSecret = secretRk
	RedirectUriRk = redirectRk
	RedirectUriStv = redirectStv
	StvSecret = secretStv
	portString := fmt.Sprintf(":%d", port)

	strava.ClientId = 9667
	strava.ClientSecret = StvSecret

	//for strava
	authenticator = &strava.OAuthAuthenticator{
		CallbackURL:            RedirectUriStv,
		RequestClientGenerator: nil,
	}

	log.Printf("callback url: %s", authenticator.AuthorizationURL("state1", strava.Permissions.Public, true))
	router := NewRouter()
	router.Methods("GET").Path("/exchange_token").Name("STVOAuthCallback").Handler(authenticator.HandlerFunc(oAuthSuccess, oAuthFailure))
	router.PathPrefix("/").Handler(http.FileServer(http.Dir("./api/static/")))
	log.Fatal(http.ListenAndServe(portString, router))
}

func oAuthSuccess(auth *strava.AuthorizationResponse, w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "SUCCESS:\nAt this point you can use this information to create a new user or link the account to one of your existing users\n")
	fmt.Fprintf(w, "State: %s\n\n", auth.State)
	fmt.Fprintf(w, "Access Token: %s\n\n", auth.AccessToken)

	fmt.Fprintf(w, "The Authenticated Athlete (you):\n")
	content, _ := json.MarshalIndent(auth.Athlete, "", " ")
	fmt.Fprint(w, string(content))

	db := sync.CreateSyncDbRepo(DbConnectionString)
	task, err := db.FindSyncTaskByToken(auth.AccessToken)
	if task == nil || err != nil {
		syncTask := sync.CreateSyncTask("", "", -1)
		syncTask.StravaToken = auth.AccessToken
		db.StoreSyncTask(*syncTask)
	} else {
		if task.StravaToken != auth.AccessToken {
			task.StravaToken = auth.AccessToken
			db.UpdateSyncTask(*task)
		} else {
			log.Printf("Token %s is already stored for task id: %d", auth.AccessToken, task.Uid)
		}
	}
}

func oAuthFailure(err error, w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Authorization Failure:\n")

	// some standard error checking
	if err == strava.OAuthAuthorizationDeniedErr {
		fmt.Fprint(w, "The user clicked the 'Do not Authorize' button on the previous page.\n")
		fmt.Fprint(w, "This is the main error your application should handle.")
	} else if err == strava.OAuthInvalidCredentialsErr {
		fmt.Fprint(w, "You provided an incorrect client_id or client_secret.\nDid you remember to set them at the begininng of this file?")
	} else if err == strava.OAuthInvalidCodeErr {
		fmt.Fprint(w, "The temporary token was not recognized, this shouldn't happen normally")
	} else if err == strava.OAuthServerErr {
		fmt.Fprint(w, "There was some sort of server error, try again to see if the problem continues")
	} else {
		fmt.Fprint(w, err)
	}
}
func OAuthCallback(response http.ResponseWriter, request *http.Request) {
	code := request.URL.Query().Get("code")
	go ObtainBearerToken(code)
	//redirect to sign up page with Acknowledgement of success..
	response.Write([]uint8("Called Back!\n"))
}

func ObtainBearerToken(code string) {
	tokenUrl := "https://runkeeper.com/apps/token"
	formData := make(map[string][]string)
	formData["grant_type"] = []string{"authorization_code"}
	formData["code"] = []string{code}
	formData["client_id"] = []string{RkClientId}
	formData["client_secret"] = []string{RkSecret}
	formData["redirect_uri"] = []string{RedirectUriRk}
	client := new(http.Client)
	response, err := client.PostForm(tokenUrl, formData)
	responseJson := make(map[string]string)
	if err == nil {
		responseBody, _ := ioutil.ReadAll(response.Body)
		json.Unmarshal(responseBody, &responseJson)
		token := responseJson["access_token"]
		db := sync.CreateSyncDbRepo(DbConnectionString)
		task, err := db.FindSyncTaskByToken(token)
		if task == nil || err != nil {
			syncTask := sync.CreateSyncTask("", "", -1)
			syncTask.RunkeeperToken = token
			db.StoreSyncTask(*syncTask)
		} else {
			if task.RunkeeperToken != token {
				task.RunkeeperToken = token
				db.UpdateSyncTask(*task)
			} else {
				log.Printf("Token %s is already stored for task id: %d", token, task.Uid)
			}
		}
	} else {
		fmt.Print(err)
	}
}

func SyncTaskIndex(response http.ResponseWriter, request *http.Request) {
}

func SyncTaskShow(response http.ResponseWriter, request *http.Request) {
}

func SyncTaskCreate(w http.ResponseWriter, r *http.Request) {
	//TODO. Check if there already is a task with either of the keys
	syncTask := sync.CreateSyncTask("", "", -1)
	body, err := ioutil.ReadAll(io.LimitReader(r.Body, 1048576))
	if err != nil {
		panic(err)
	}
	if err := r.Body.Close(); err != nil {
		panic(err)
	}
	if err := json.Unmarshal(body, &syncTask); err != nil {
		w.Header().Set("Content-Type", "application/json; charset=UTF-8")
		w.WriteHeader(422) // unprocessable entity
		if err := json.NewEncoder(w).Encode(err); err != nil {
			panic(err)
		}
	}

	//Creation set the last know timestamp to 1 year ago
	syncTask.LastSeenTimestamp = int(time.Now().Add(startTime).Unix())
	db := sync.CreateSyncDbRepo(DbConnectionString)
	_, _, st, _ := db.StoreSyncTask(*syncTask)

	w.Header().Set("Content-Type", "application/json; charset=UTF-8")
	w.WriteHeader(http.StatusCreated)
	if err := json.NewEncoder(w).Encode(st); err != nil {
		panic(err)
	}
}
<commit_msg>Set the Lastseen time to one hour ago for new SyncTasks<commit_after>package api

import (
	"encoding/json"
	"fmt"
	"github.com/svdberg/syncmysport-runkeeper/Godeps/_workspace/src/github.com/strava/go.strava"
	sync "github.com/svdberg/syncmysport-runkeeper/sync"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"time"
)

const startTime = -1 * time.Duration(1) * time.Hour * 24 * 365 //1 year ago
const RkClientId = "73664cff18ed4800aab6cffc7ef8f4e1"

var (
	DbConnectionString string
	RkSecret           string
	StvSecret          string
	RedirectUriRk      string
	RedirectUriStv     string
	authenticator      *strava.OAuthAuthenticator
)

func Start(connString string, port int, secretRk string, redirectRk string, secretStv string, redirectStv string) {
	DbConnectionString = connString
	RkSecret = secretRk
	RedirectUriRk = redirectRk
	RedirectUriStv = redirectStv
	StvSecret = secretStv
	portString := fmt.Sprintf(":%d", port)

	strava.ClientId = 9667
	strava.ClientSecret = StvSecret

	//for strava
	authenticator = &strava.OAuthAuthenticator{
		CallbackURL:            RedirectUriStv,
		RequestClientGenerator: nil,
	}

	log.Printf("callback url: %s", authenticator.AuthorizationURL("state1", strava.Permissions.Public, true))
	router := NewRouter()
	router.Methods("GET").Path("/exchange_token").Name("STVOAuthCallback").Handler(authenticator.HandlerFunc(oAuthSuccess, oAuthFailure))
	router.PathPrefix("/").Handler(http.FileServer(http.Dir("./api/static/")))
	log.Fatal(http.ListenAndServe(portString, router))
}

func oAuthSuccess(auth *strava.AuthorizationResponse, w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "SUCCESS:\nAt this point you can use this information to create a new user or link the account to one of your existing users\n")
	fmt.Fprintf(w, "State: %s\n\n", auth.State)
	fmt.Fprintf(w, "Access Token: %s\n\n", auth.AccessToken)

	fmt.Fprintf(w, "The Authenticated Athlete (you):\n")
	content, _ := json.MarshalIndent(auth.Athlete, "", " ")
	fmt.Fprint(w, string(content))

	db := sync.CreateSyncDbRepo(DbConnectionString)
	task, err := db.FindSyncTaskByToken(auth.AccessToken)
	if task == nil || err != nil {
		syncTask := sync.CreateSyncTask("", "", -1)
		syncTask.StravaToken = auth.AccessToken
		syncTask.LastSeenTimestamp = nowMinusOneHourInUnix()
		db.StoreSyncTask(*syncTask)
	} else {
		if task.StravaToken != auth.AccessToken {
			task.StravaToken = auth.AccessToken
			db.UpdateSyncTask(*task)
		} else {
			log.Printf("Token %s is already stored for task id: %d", auth.AccessToken, task.Uid)
		}
	}
}

func oAuthFailure(err error, w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Authorization Failure:\n")

	// some standard error checking
	if err == strava.OAuthAuthorizationDeniedErr {
		fmt.Fprint(w, "The user clicked the 'Do not Authorize' button on the previous page.\n")
		fmt.Fprint(w, "This is the main error your application should handle.")
	} else if err == strava.OAuthInvalidCredentialsErr {
		fmt.Fprint(w, "You provided an incorrect client_id or client_secret.\nDid you remember to set them at the begininng of this file?")
	} else if err == strava.OAuthInvalidCodeErr {
		fmt.Fprint(w, "The temporary token was not recognized, this shouldn't happen normally")
	} else if err == strava.OAuthServerErr {
		fmt.Fprint(w, "There was some sort of server error, try again to see if the problem continues")
	} else {
		fmt.Fprint(w, err)
	}
}
func OAuthCallback(response http.ResponseWriter, request *http.Request) {
	code := request.URL.Query().Get("code")
	go ObtainBearerToken(code)
	//redirect to sign up page with Acknowledgement of success..
	response.Write([]uint8("Called Back!\n"))
}

func ObtainBearerToken(code string) {
	tokenUrl := "https://runkeeper.com/apps/token"
	formData := make(map[string][]string)
	formData["grant_type"] = []string{"authorization_code"}
	formData["code"] = []string{code}
	formData["client_id"] = []string{RkClientId}
	formData["client_secret"] = []string{RkSecret}
	formData["redirect_uri"] = []string{RedirectUriRk}
	client := new(http.Client)
	response, err := client.PostForm(tokenUrl, formData)
	responseJson := make(map[string]string)
	if err == nil {
		responseBody, _ := ioutil.ReadAll(response.Body)
		json.Unmarshal(responseBody, &responseJson)
		token := responseJson["access_token"]
		db := sync.CreateSyncDbRepo(DbConnectionString)
		task, err := db.FindSyncTaskByToken(token)
		if task == nil || err != nil {
			syncTask := sync.CreateSyncTask("", "", -1)
			syncTask.RunkeeperToken = token
			syncTask.LastSeenTimestamp = nowMinusOneHourInUnix()
			db.StoreSyncTask(*syncTask)
		} else {
			if task.RunkeeperToken != token {
				task.RunkeeperToken = token
				db.UpdateSyncTask(*task)
			} else {
				log.Printf("Token %s is already stored for task id: %d", token, task.Uid)
			}
		}
	} else {
		fmt.Print(err)
	}
}

func SyncTaskIndex(response http.ResponseWriter, request *http.Request) {
}

func SyncTaskShow(response http.ResponseWriter, request *http.Request) {
}

func nowMinusOneHourInUnix() int {
	now := time.Now().UTC()
	nowMinusOneHour := now.Add(time.Duration(1) * time.Hour)
	return int(nowMinusOneHour.Unix())
}

func SyncTaskCreate(w http.ResponseWriter, r *http.Request) {
	//TODO. Check if there already is a task with either of the keys
	syncTask := sync.CreateSyncTask("", "", -1)
	body, err := ioutil.ReadAll(io.LimitReader(r.Body, 1048576))
	if err != nil {
		panic(err)
	}
	if err := r.Body.Close(); err != nil {
		panic(err)
	}
	if err := json.Unmarshal(body, &syncTask); err != nil {
		w.Header().Set("Content-Type", "application/json; charset=UTF-8")
		w.WriteHeader(422) // unprocessable entity
		if err := json.NewEncoder(w).Encode(err); err != nil {
			panic(err)
		}
	}

	//Creation set the last know timestamp to 1 hour ago
	syncTask.LastSeenTimestamp = nowMinusOneHourInUnix()

	db := sync.CreateSyncDbRepo(DbConnectionString)
	_, _, st, _ := db.StoreSyncTask(*syncTask)

	w.Header().Set("Content-Type", "application/json; charset=UTF-8")
	w.WriteHeader(http.StatusCreated)
	if err := json.NewEncoder(w).Encode(st); err != nil {
		panic(err)
	}
}
<|endoftext|>


<commit_before>package tfinstall

import (
  "archive/zip"
  "os"
  "io"
  "path/filepath"
  "os/exec"
  "fmt"

  "github.com/fatih/color"
)

func check(e error) {
    if e != nil {
        panic(e)
    }
}

func Unzip(archive, target string) error {
  	reader, err := zip.OpenReader(archive)
  	check(err)

  	if err := os.MkdirAll(target, 0755); err != nil {
  		  return err
  	}

  	for _, file := range reader.File {
    		path := filepath.Join(target, file.Name)
    		if file.FileInfo().IsDir() {
      			os.MkdirAll(path, file.Mode())
      			continue
    		}

    		fileReader, err := file.Open()
    		check(err)
    		defer fileReader.Close()

    		targetFile, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, file.Mode())
    		check(err)
    		defer targetFile.Close()

    		if _, err := io.Copy(targetFile, fileReader); err != nil {
    			   return err
    		}

        err = os.Remove(archive)
        check(err)
  	}

  	return nil
}

func Run(version string)  {

    var (
      err error
      cmd *exec.Cmd
    )

    good := color.New(color.FgGreen, color.Bold)

    // Unzip zip archive
    fmt.Printf("Unzip file ...\n")
    err = Unzip("/tmp/terraform-" + version + ".zip", "/tmp/")
    check(err)

    // Create alias command
    fmt.Printf("Install the binary file ...\n")
    cmd = exec.Command("alias", "terraform=/tmp/terraform")
    err = cmd.Run()
    check(err)

    good.Printf("Installed %s, Thanks ! ♥", version)
}
<commit_msg>~ Fix display Installed %s, Thanks! ♥, return to line<commit_after>package tfinstall

import (
  "archive/zip"
  "os"
  "io"
  "path/filepath"
  "os/exec"
  "fmt"

  "github.com/fatih/color"
)

func check(e error) {
    if e != nil {
        panic(e)
    }
}

func Unzip(archive, target string) error {
  	reader, err := zip.OpenReader(archive)
  	check(err)

  	if err := os.MkdirAll(target, 0755); err != nil {
  		  return err
  	}

  	for _, file := range reader.File {
    		path := filepath.Join(target, file.Name)
    		if file.FileInfo().IsDir() {
      			os.MkdirAll(path, file.Mode())
      			continue
    		}

    		fileReader, err := file.Open()
    		check(err)
    		defer fileReader.Close()

    		targetFile, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, file.Mode())
    		check(err)
    		defer targetFile.Close()

    		if _, err := io.Copy(targetFile, fileReader); err != nil {
    			   return err
    		}

        err = os.Remove(archive)
        check(err)
  	}

  	return nil
}

func Run(version string)  {

    var (
      err error
      cmd *exec.Cmd
    )

    good := color.New(color.FgGreen, color.Bold)

    // Unzip zip archive
    fmt.Printf("Unzip file ...\n")
    err = Unzip("/tmp/terraform-" + version + ".zip", "/tmp/")
    check(err)

    // Create alias command
    fmt.Printf("Install the binary file ...\n")
    cmd = exec.Command("alias", "terraform=/tmp/terraform")
    err = cmd.Run()
    check(err)

    good.Printf("Installed %s, Thanks ! ♥\n", version)
}
<|endoftext|>


<commit_before>/*
Copyright 2016 The Kubernetes Authors.

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

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

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

package vsphere_volume

import (
	"fmt"
	"os"
	"path"
	"strings"

	"github.com/golang/glog"
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/api/resource"
	"k8s.io/kubernetes/pkg/types"
	"k8s.io/kubernetes/pkg/util/exec"
	"k8s.io/kubernetes/pkg/util/mount"
	utilstrings "k8s.io/kubernetes/pkg/util/strings"
	"k8s.io/kubernetes/pkg/volume"
)

// This is the primary entrypoint for volume plugins.
func ProbeVolumePlugins() []volume.VolumePlugin {
	return []volume.VolumePlugin{&vsphereVolumePlugin{}}
}

type vsphereVolumePlugin struct {
	host volume.VolumeHost
}

var _ volume.VolumePlugin = &vsphereVolumePlugin{}
var _ volume.PersistentVolumePlugin = &vsphereVolumePlugin{}
var _ volume.DeletableVolumePlugin = &vsphereVolumePlugin{}
var _ volume.ProvisionableVolumePlugin = &vsphereVolumePlugin{}

const (
	vsphereVolumePluginName = "kubernetes.io/vsphere-volume"
)

// vSphere Volume Plugin
func (plugin *vsphereVolumePlugin) Init(host volume.VolumeHost) error {
	plugin.host = host
	return nil
}

func (plugin *vsphereVolumePlugin) GetPluginName() string {
	return vsphereVolumePluginName
}

func (plugin *vsphereVolumePlugin) GetVolumeName(spec *volume.Spec) (string, error) {
	volumeSource, _, err := getVolumeSource(spec)
	if err != nil {
		return "", err
	}

	return volumeSource.VolumePath, nil
}

func (plugin *vsphereVolumePlugin) CanSupport(spec *volume.Spec) bool {
	return (spec.PersistentVolume != nil && spec.PersistentVolume.Spec.VsphereVolume != nil) ||
		(spec.Volume != nil && spec.Volume.VsphereVolume != nil)
}

func (plugin *vsphereVolumePlugin) RequiresRemount() bool {
	return false
}

func (plugin *vsphereVolumePlugin) NewMounter(spec *volume.Spec, pod *api.Pod, _ volume.VolumeOptions) (volume.Mounter, error) {
	return plugin.newMounterInternal(spec, pod.UID, &VsphereDiskUtil{}, plugin.host.GetMounter())
}

func (plugin *vsphereVolumePlugin) NewUnmounter(volName string, podUID types.UID) (volume.Unmounter, error) {
	return plugin.newUnmounterInternal(volName, podUID, &VsphereDiskUtil{}, plugin.host.GetMounter())
}

func (plugin *vsphereVolumePlugin) newMounterInternal(spec *volume.Spec, podUID types.UID, manager vdManager, mounter mount.Interface) (volume.Mounter, error) {
	vvol, _, err := getVolumeSource(spec)
	if err != nil {
		return nil, err
	}

	volPath := vvol.VolumePath
	fsType := vvol.FSType

	return &vsphereVolumeMounter{
		vsphereVolume: &vsphereVolume{
			podUID:  podUID,
			volName: spec.Name(),
			volPath: volPath,
			manager: manager,
			mounter: mounter,
			plugin:  plugin,
		},
		fsType:      fsType,
		diskMounter: &mount.SafeFormatAndMount{Interface: mounter, Runner: exec.New()}}, nil
}

func (plugin *vsphereVolumePlugin) newUnmounterInternal(volName string, podUID types.UID, manager vdManager, mounter mount.Interface) (volume.Unmounter, error) {
	return &vsphereVolumeUnmounter{
		&vsphereVolume{
			podUID:  podUID,
			volName: volName,
			manager: manager,
			mounter: mounter,
			plugin:  plugin,
		}}, nil
}

func (plugin *vsphereVolumePlugin) ConstructVolumeSpec(volumeName, mountPath string) (*volume.Spec, error) {
	mounter := plugin.host.GetMounter()
	pluginDir := plugin.host.GetPluginDir(plugin.GetPluginName())
	volumePath, err := mounter.GetDeviceNameFromMount(mountPath, pluginDir)
	if err != nil {
		return nil, err
	}
	volumePath = strings.Replace(volumePath, "\\040", " ", -1)
	glog.V(5).Infof("vSphere volume path is %q", volumePath)
	vsphereVolume := &api.Volume{
		Name: volumeName,
		VolumeSource: api.VolumeSource{
			VsphereVolume: &api.VsphereVirtualDiskVolumeSource{
				VolumePath: volumePath,
			},
		},
	}
	return volume.NewSpecFromVolume(vsphereVolume), nil
}

// Abstract interface to disk operations.
type vdManager interface {
	// Creates a volume
	CreateVolume(provisioner *vsphereVolumeProvisioner) (vmDiskPath string, volumeSizeGB int, err error)
	// Deletes a volume
	DeleteVolume(deleter *vsphereVolumeDeleter) error
}

// vspherePersistentDisk volumes are disk resources are attached to the kubelet's host machine and exposed to the pod.
type vsphereVolume struct {
	volName string
	podUID  types.UID
	// Unique identifier of the volume, used to find the disk resource in the provider.
	volPath string
	// Filesystem type, optional.
	fsType string
	//diskID for detach disk
	diskID string
	// Utility interface that provides API calls to the provider to attach/detach disks.
	manager vdManager
	// Mounter interface that provides system calls to mount the global path to the pod local path.
	mounter mount.Interface
	// diskMounter provides the interface that is used to mount the actual block device.
	diskMounter mount.Interface
	plugin      *vsphereVolumePlugin
	volume.MetricsNil
}

var _ volume.Mounter = &vsphereVolumeMounter{}

type vsphereVolumeMounter struct {
	*vsphereVolume
	fsType      string
	diskMounter *mount.SafeFormatAndMount
}

func (b *vsphereVolumeMounter) GetAttributes() volume.Attributes {
	return volume.Attributes{
		SupportsSELinux: true,
	}
}

// SetUp attaches the disk and bind mounts to the volume path.
func (b *vsphereVolumeMounter) SetUp(fsGroup *int64) error {
	return b.SetUpAt(b.GetPath(), fsGroup)
}

// Checks prior to mount operations to verify that the required components (binaries, etc.)
// to mount the volume are available on the underlying node.
// If not, it returns an error
func (b *vsphereVolumeMounter) CanMount() error {
	return nil
}

// SetUp attaches the disk and bind mounts to the volume path.
func (b *vsphereVolumeMounter) SetUpAt(dir string, fsGroup *int64) error {
	glog.V(5).Infof("vSphere volume setup %s to %s", b.volPath, dir)

	// TODO: handle failed mounts here.
	notmnt, err := b.mounter.IsLikelyNotMountPoint(dir)
	if err != nil && !os.IsNotExist(err) {
		glog.V(4).Infof("IsLikelyNotMountPoint failed: %v", err)
		return err
	}
	if !notmnt {
		glog.V(4).Infof("Something is already mounted to target %s", dir)
		return nil
	}

	if err := os.MkdirAll(dir, 0750); err != nil {
		glog.V(4).Infof("Could not create directory %s: %v", dir, err)
		return err
	}

	options := []string{"bind"}

	// Perform a bind mount to the full path to allow duplicate mounts of the same PD.
	globalPDPath := makeGlobalPDPath(b.plugin.host, b.volPath)
	err = b.mounter.Mount(globalPDPath, dir, "", options)
	if err != nil {
		notmnt, mntErr := b.mounter.IsLikelyNotMountPoint(dir)
		if mntErr != nil {
			glog.Errorf("IsLikelyNotMountPoint check failed: %v", mntErr)
			return err
		}
		if !notmnt {
			if mntErr = b.mounter.Unmount(dir); mntErr != nil {
				glog.Errorf("Failed to unmount: %v", mntErr)
				return err
			}
			notmnt, mntErr := b.mounter.IsLikelyNotMountPoint(dir)
			if mntErr != nil {
				glog.Errorf("IsLikelyNotMountPoint check failed: %v", mntErr)
				return err
			}
			if !notmnt {
				glog.Errorf("%s is still mounted, despite call to unmount().  Will try again next sync loop.", b.GetPath())
				return err
			}
		}
		os.Remove(dir)
		return err
	}
	glog.V(3).Infof("vSphere volume %s mounted to %s", b.volPath, dir)

	return nil
}

var _ volume.Unmounter = &vsphereVolumeUnmounter{}

type vsphereVolumeUnmounter struct {
	*vsphereVolume
}

// Unmounts the bind mount, and detaches the disk only if the PD
// resource was the last reference to that disk on the kubelet.
func (v *vsphereVolumeUnmounter) TearDown() error {
	return v.TearDownAt(v.GetPath())
}

// Unmounts the bind mount, and detaches the disk only if the PD
// resource was the last reference to that disk on the kubelet.
func (v *vsphereVolumeUnmounter) TearDownAt(dir string) error {
	glog.V(5).Infof("vSphere Volume TearDown of %s", dir)
	notMnt, err := v.mounter.IsLikelyNotMountPoint(dir)
	if err != nil {
		return err
	}
	if notMnt {
		return os.Remove(dir)
	}
	if err := v.mounter.Unmount(dir); err != nil {
		return err
	}
	notMnt, mntErr := v.mounter.IsLikelyNotMountPoint(dir)
	if mntErr != nil {
		glog.Errorf("IsLikelyNotMountPoint check failed: %v", mntErr)
		return err
	}
	if notMnt {
		return os.Remove(dir)
	}
	return fmt.Errorf("Failed to unmount volume dir")
}

func makeGlobalPDPath(host volume.VolumeHost, devName string) string {
	return path.Join(host.GetPluginDir(vsphereVolumePluginName), mount.MountsInGlobalPDPath, devName)
}

func (vv *vsphereVolume) GetPath() string {
	name := vsphereVolumePluginName
	return vv.plugin.host.GetPodVolumeDir(vv.podUID, utilstrings.EscapeQualifiedNameForDisk(name), vv.volName)
}

// vSphere Persistent Volume Plugin
func (plugin *vsphereVolumePlugin) GetAccessModes() []api.PersistentVolumeAccessMode {
	return []api.PersistentVolumeAccessMode{
		api.ReadWriteOnce,
	}
}

// vSphere Deletable Volume Plugin
type vsphereVolumeDeleter struct {
	*vsphereVolume
}

var _ volume.Deleter = &vsphereVolumeDeleter{}

func (plugin *vsphereVolumePlugin) NewDeleter(spec *volume.Spec) (volume.Deleter, error) {
	return plugin.newDeleterInternal(spec, &VsphereDiskUtil{})
}

func (plugin *vsphereVolumePlugin) newDeleterInternal(spec *volume.Spec, manager vdManager) (volume.Deleter, error) {
	if spec.PersistentVolume != nil && spec.PersistentVolume.Spec.VsphereVolume == nil {
		return nil, fmt.Errorf("spec.PersistentVolumeSource.VsphereVolume is nil")
	}
	return &vsphereVolumeDeleter{
		&vsphereVolume{
			volName: spec.Name(),
			volPath: spec.PersistentVolume.Spec.VsphereVolume.VolumePath,
			manager: manager,
			plugin:  plugin,
		}}, nil
}

func (r *vsphereVolumeDeleter) Delete() error {
	return r.manager.DeleteVolume(r)
}

// vSphere Provisionable Volume Plugin
type vsphereVolumeProvisioner struct {
	*vsphereVolume
	options volume.VolumeOptions
}

var _ volume.Provisioner = &vsphereVolumeProvisioner{}

func (plugin *vsphereVolumePlugin) NewProvisioner(options volume.VolumeOptions) (volume.Provisioner, error) {
	if len(options.AccessModes) == 0 {
		options.AccessModes = plugin.GetAccessModes()
	}
	return plugin.newProvisionerInternal(options, &VsphereDiskUtil{})
}

func (plugin *vsphereVolumePlugin) newProvisionerInternal(options volume.VolumeOptions, manager vdManager) (volume.Provisioner, error) {
	return &vsphereVolumeProvisioner{
		vsphereVolume: &vsphereVolume{
			manager: manager,
			plugin:  plugin,
		},
		options: options,
	}, nil
}

func (v *vsphereVolumeProvisioner) Provision() (*api.PersistentVolume, error) {
	vmDiskPath, sizeKB, err := v.manager.CreateVolume(v)
	if err != nil {
		return nil, err
	}

	pv := &api.PersistentVolume{
		ObjectMeta: api.ObjectMeta{
			Name:   v.options.PVName,
			Labels: map[string]string{},
			Annotations: map[string]string{
				"kubernetes.io/createdby": "vsphere-volume-dynamic-provisioner",
			},
		},
		Spec: api.PersistentVolumeSpec{
			PersistentVolumeReclaimPolicy: v.options.PersistentVolumeReclaimPolicy,
			AccessModes:                   v.options.AccessModes,
			Capacity: api.ResourceList{
				api.ResourceName(api.ResourceStorage): resource.MustParse(fmt.Sprintf("%dKi", sizeKB)),
			},
			PersistentVolumeSource: api.PersistentVolumeSource{
				VsphereVolume: &api.VsphereVirtualDiskVolumeSource{
					VolumePath: vmDiskPath,
					FSType:     "ext4",
				},
			},
		},
	}
	return pv, nil
}

func getVolumeSource(
	spec *volume.Spec) (*api.VsphereVirtualDiskVolumeSource, bool, error) {
	if spec.Volume != nil && spec.Volume.VsphereVolume != nil {
		return spec.Volume.VsphereVolume, spec.ReadOnly, nil
	} else if spec.PersistentVolume != nil &&
		spec.PersistentVolume.Spec.VsphereVolume != nil {
		return spec.PersistentVolume.Spec.VsphereVolume, spec.ReadOnly, nil
	}

	return nil, false, fmt.Errorf("Spec does not reference a VSphere volume type")
}
<commit_msg>Fix fsGroup to vSphere<commit_after>/*
Copyright 2016 The Kubernetes Authors.

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

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

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

package vsphere_volume

import (
	"fmt"
	"os"
	"path"
	"strings"

	"github.com/golang/glog"
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/api/resource"
	"k8s.io/kubernetes/pkg/types"
	"k8s.io/kubernetes/pkg/util/exec"
	"k8s.io/kubernetes/pkg/util/mount"
	utilstrings "k8s.io/kubernetes/pkg/util/strings"
	"k8s.io/kubernetes/pkg/volume"
)

// This is the primary entrypoint for volume plugins.
func ProbeVolumePlugins() []volume.VolumePlugin {
	return []volume.VolumePlugin{&vsphereVolumePlugin{}}
}

type vsphereVolumePlugin struct {
	host volume.VolumeHost
}

var _ volume.VolumePlugin = &vsphereVolumePlugin{}
var _ volume.PersistentVolumePlugin = &vsphereVolumePlugin{}
var _ volume.DeletableVolumePlugin = &vsphereVolumePlugin{}
var _ volume.ProvisionableVolumePlugin = &vsphereVolumePlugin{}

const (
	vsphereVolumePluginName = "kubernetes.io/vsphere-volume"
)

// vSphere Volume Plugin
func (plugin *vsphereVolumePlugin) Init(host volume.VolumeHost) error {
	plugin.host = host
	return nil
}

func (plugin *vsphereVolumePlugin) GetPluginName() string {
	return vsphereVolumePluginName
}

func (plugin *vsphereVolumePlugin) GetVolumeName(spec *volume.Spec) (string, error) {
	volumeSource, _, err := getVolumeSource(spec)
	if err != nil {
		return "", err
	}

	return volumeSource.VolumePath, nil
}

func (plugin *vsphereVolumePlugin) CanSupport(spec *volume.Spec) bool {
	return (spec.PersistentVolume != nil && spec.PersistentVolume.Spec.VsphereVolume != nil) ||
		(spec.Volume != nil && spec.Volume.VsphereVolume != nil)
}

func (plugin *vsphereVolumePlugin) RequiresRemount() bool {
	return false
}

func (plugin *vsphereVolumePlugin) NewMounter(spec *volume.Spec, pod *api.Pod, _ volume.VolumeOptions) (volume.Mounter, error) {
	return plugin.newMounterInternal(spec, pod.UID, &VsphereDiskUtil{}, plugin.host.GetMounter())
}

func (plugin *vsphereVolumePlugin) NewUnmounter(volName string, podUID types.UID) (volume.Unmounter, error) {
	return plugin.newUnmounterInternal(volName, podUID, &VsphereDiskUtil{}, plugin.host.GetMounter())
}

func (plugin *vsphereVolumePlugin) newMounterInternal(spec *volume.Spec, podUID types.UID, manager vdManager, mounter mount.Interface) (volume.Mounter, error) {
	vvol, _, err := getVolumeSource(spec)
	if err != nil {
		return nil, err
	}

	volPath := vvol.VolumePath
	fsType := vvol.FSType

	return &vsphereVolumeMounter{
		vsphereVolume: &vsphereVolume{
			podUID:  podUID,
			volName: spec.Name(),
			volPath: volPath,
			manager: manager,
			mounter: mounter,
			plugin:  plugin,
		},
		fsType:      fsType,
		diskMounter: &mount.SafeFormatAndMount{Interface: mounter, Runner: exec.New()}}, nil
}

func (plugin *vsphereVolumePlugin) newUnmounterInternal(volName string, podUID types.UID, manager vdManager, mounter mount.Interface) (volume.Unmounter, error) {
	return &vsphereVolumeUnmounter{
		&vsphereVolume{
			podUID:  podUID,
			volName: volName,
			manager: manager,
			mounter: mounter,
			plugin:  plugin,
		}}, nil
}

func (plugin *vsphereVolumePlugin) ConstructVolumeSpec(volumeName, mountPath string) (*volume.Spec, error) {
	mounter := plugin.host.GetMounter()
	pluginDir := plugin.host.GetPluginDir(plugin.GetPluginName())
	volumePath, err := mounter.GetDeviceNameFromMount(mountPath, pluginDir)
	if err != nil {
		return nil, err
	}
	volumePath = strings.Replace(volumePath, "\\040", " ", -1)
	glog.V(5).Infof("vSphere volume path is %q", volumePath)
	vsphereVolume := &api.Volume{
		Name: volumeName,
		VolumeSource: api.VolumeSource{
			VsphereVolume: &api.VsphereVirtualDiskVolumeSource{
				VolumePath: volumePath,
			},
		},
	}
	return volume.NewSpecFromVolume(vsphereVolume), nil
}

// Abstract interface to disk operations.
type vdManager interface {
	// Creates a volume
	CreateVolume(provisioner *vsphereVolumeProvisioner) (vmDiskPath string, volumeSizeGB int, err error)
	// Deletes a volume
	DeleteVolume(deleter *vsphereVolumeDeleter) error
}

// vspherePersistentDisk volumes are disk resources are attached to the kubelet's host machine and exposed to the pod.
type vsphereVolume struct {
	volName string
	podUID  types.UID
	// Unique identifier of the volume, used to find the disk resource in the provider.
	volPath string
	// Filesystem type, optional.
	fsType string
	//diskID for detach disk
	diskID string
	// Utility interface that provides API calls to the provider to attach/detach disks.
	manager vdManager
	// Mounter interface that provides system calls to mount the global path to the pod local path.
	mounter mount.Interface
	// diskMounter provides the interface that is used to mount the actual block device.
	diskMounter mount.Interface
	plugin      *vsphereVolumePlugin
	volume.MetricsNil
}

var _ volume.Mounter = &vsphereVolumeMounter{}

type vsphereVolumeMounter struct {
	*vsphereVolume
	fsType      string
	diskMounter *mount.SafeFormatAndMount
}

func (b *vsphereVolumeMounter) GetAttributes() volume.Attributes {
	return volume.Attributes{
		SupportsSELinux: true,
	}
}

// SetUp attaches the disk and bind mounts to the volume path.
func (b *vsphereVolumeMounter) SetUp(fsGroup *int64) error {
	return b.SetUpAt(b.GetPath(), fsGroup)
}

// Checks prior to mount operations to verify that the required components (binaries, etc.)
// to mount the volume are available on the underlying node.
// If not, it returns an error
func (b *vsphereVolumeMounter) CanMount() error {
	return nil
}

// SetUp attaches the disk and bind mounts to the volume path.
func (b *vsphereVolumeMounter) SetUpAt(dir string, fsGroup *int64) error {
	glog.V(5).Infof("vSphere volume setup %s to %s", b.volPath, dir)

	// TODO: handle failed mounts here.
	notmnt, err := b.mounter.IsLikelyNotMountPoint(dir)
	if err != nil && !os.IsNotExist(err) {
		glog.V(4).Infof("IsLikelyNotMountPoint failed: %v", err)
		return err
	}
	if !notmnt {
		glog.V(4).Infof("Something is already mounted to target %s", dir)
		return nil
	}

	if err := os.MkdirAll(dir, 0750); err != nil {
		glog.V(4).Infof("Could not create directory %s: %v", dir, err)
		return err
	}

	options := []string{"bind"}

	// Perform a bind mount to the full path to allow duplicate mounts of the same PD.
	globalPDPath := makeGlobalPDPath(b.plugin.host, b.volPath)
	err = b.mounter.Mount(globalPDPath, dir, "", options)
	if err != nil {
		notmnt, mntErr := b.mounter.IsLikelyNotMountPoint(dir)
		if mntErr != nil {
			glog.Errorf("IsLikelyNotMountPoint check failed: %v", mntErr)
			return err
		}
		if !notmnt {
			if mntErr = b.mounter.Unmount(dir); mntErr != nil {
				glog.Errorf("Failed to unmount: %v", mntErr)
				return err
			}
			notmnt, mntErr := b.mounter.IsLikelyNotMountPoint(dir)
			if mntErr != nil {
				glog.Errorf("IsLikelyNotMountPoint check failed: %v", mntErr)
				return err
			}
			if !notmnt {
				glog.Errorf("%s is still mounted, despite call to unmount().  Will try again next sync loop.", b.GetPath())
				return err
			}
		}
		os.Remove(dir)
		return err
	}
	volume.SetVolumeOwnership(b, fsGroup)
	glog.V(3).Infof("vSphere volume %s mounted to %s", b.volPath, dir)

	return nil
}

var _ volume.Unmounter = &vsphereVolumeUnmounter{}

type vsphereVolumeUnmounter struct {
	*vsphereVolume
}

// Unmounts the bind mount, and detaches the disk only if the PD
// resource was the last reference to that disk on the kubelet.
func (v *vsphereVolumeUnmounter) TearDown() error {
	return v.TearDownAt(v.GetPath())
}

// Unmounts the bind mount, and detaches the disk only if the PD
// resource was the last reference to that disk on the kubelet.
func (v *vsphereVolumeUnmounter) TearDownAt(dir string) error {
	glog.V(5).Infof("vSphere Volume TearDown of %s", dir)
	notMnt, err := v.mounter.IsLikelyNotMountPoint(dir)
	if err != nil {
		return err
	}
	if notMnt {
		return os.Remove(dir)
	}
	if err := v.mounter.Unmount(dir); err != nil {
		return err
	}
	notMnt, mntErr := v.mounter.IsLikelyNotMountPoint(dir)
	if mntErr != nil {
		glog.Errorf("IsLikelyNotMountPoint check failed: %v", mntErr)
		return err
	}
	if notMnt {
		return os.Remove(dir)
	}
	return fmt.Errorf("Failed to unmount volume dir")
}

func makeGlobalPDPath(host volume.VolumeHost, devName string) string {
	return path.Join(host.GetPluginDir(vsphereVolumePluginName), mount.MountsInGlobalPDPath, devName)
}

func (vv *vsphereVolume) GetPath() string {
	name := vsphereVolumePluginName
	return vv.plugin.host.GetPodVolumeDir(vv.podUID, utilstrings.EscapeQualifiedNameForDisk(name), vv.volName)
}

// vSphere Persistent Volume Plugin
func (plugin *vsphereVolumePlugin) GetAccessModes() []api.PersistentVolumeAccessMode {
	return []api.PersistentVolumeAccessMode{
		api.ReadWriteOnce,
	}
}

// vSphere Deletable Volume Plugin
type vsphereVolumeDeleter struct {
	*vsphereVolume
}

var _ volume.Deleter = &vsphereVolumeDeleter{}

func (plugin *vsphereVolumePlugin) NewDeleter(spec *volume.Spec) (volume.Deleter, error) {
	return plugin.newDeleterInternal(spec, &VsphereDiskUtil{})
}

func (plugin *vsphereVolumePlugin) newDeleterInternal(spec *volume.Spec, manager vdManager) (volume.Deleter, error) {
	if spec.PersistentVolume != nil && spec.PersistentVolume.Spec.VsphereVolume == nil {
		return nil, fmt.Errorf("spec.PersistentVolumeSource.VsphereVolume is nil")
	}
	return &vsphereVolumeDeleter{
		&vsphereVolume{
			volName: spec.Name(),
			volPath: spec.PersistentVolume.Spec.VsphereVolume.VolumePath,
			manager: manager,
			plugin:  plugin,
		}}, nil
}

func (r *vsphereVolumeDeleter) Delete() error {
	return r.manager.DeleteVolume(r)
}

// vSphere Provisionable Volume Plugin
type vsphereVolumeProvisioner struct {
	*vsphereVolume
	options volume.VolumeOptions
}

var _ volume.Provisioner = &vsphereVolumeProvisioner{}

func (plugin *vsphereVolumePlugin) NewProvisioner(options volume.VolumeOptions) (volume.Provisioner, error) {
	if len(options.AccessModes) == 0 {
		options.AccessModes = plugin.GetAccessModes()
	}
	return plugin.newProvisionerInternal(options, &VsphereDiskUtil{})
}

func (plugin *vsphereVolumePlugin) newProvisionerInternal(options volume.VolumeOptions, manager vdManager) (volume.Provisioner, error) {
	return &vsphereVolumeProvisioner{
		vsphereVolume: &vsphereVolume{
			manager: manager,
			plugin:  plugin,
		},
		options: options,
	}, nil
}

func (v *vsphereVolumeProvisioner) Provision() (*api.PersistentVolume, error) {
	vmDiskPath, sizeKB, err := v.manager.CreateVolume(v)
	if err != nil {
		return nil, err
	}

	pv := &api.PersistentVolume{
		ObjectMeta: api.ObjectMeta{
			Name:   v.options.PVName,
			Labels: map[string]string{},
			Annotations: map[string]string{
				"kubernetes.io/createdby": "vsphere-volume-dynamic-provisioner",
			},
		},
		Spec: api.PersistentVolumeSpec{
			PersistentVolumeReclaimPolicy: v.options.PersistentVolumeReclaimPolicy,
			AccessModes:                   v.options.AccessModes,
			Capacity: api.ResourceList{
				api.ResourceName(api.ResourceStorage): resource.MustParse(fmt.Sprintf("%dKi", sizeKB)),
			},
			PersistentVolumeSource: api.PersistentVolumeSource{
				VsphereVolume: &api.VsphereVirtualDiskVolumeSource{
					VolumePath: vmDiskPath,
					FSType:     "ext4",
				},
			},
		},
	}
	return pv, nil
}

func getVolumeSource(
	spec *volume.Spec) (*api.VsphereVirtualDiskVolumeSource, bool, error) {
	if spec.Volume != nil && spec.Volume.VsphereVolume != nil {
		return spec.Volume.VsphereVolume, spec.ReadOnly, nil
	} else if spec.PersistentVolume != nil &&
		spec.PersistentVolume.Spec.VsphereVolume != nil {
		return spec.PersistentVolume.Spec.VsphereVolume, spec.ReadOnly, nil
	}

	return nil, false, fmt.Errorf("Spec does not reference a VSphere volume type")
}
<|endoftext|>


<commit_before>package rados_test

import "testing"
//import "bytes"
import "github.com/noahdesu/go-rados"
import "github.com/stretchr/testify/assert"
import "os"
import "os/exec"
import "io"
import "io/ioutil"
import "time"
import "net"
import "fmt"

func GetUUID() string {
    out, _ := exec.Command("uuidgen").Output()
    return string(out[:36])
}

func TestVersion(t *testing.T) {
    var major, minor, patch = rados.Version()
    assert.False(t, major < 0 || major > 1000, "invalid major")
    assert.False(t, minor < 0 || minor > 1000, "invalid minor")
    assert.False(t, patch < 0 || patch > 1000, "invalid patch")
}

func TestGetSetConfigOption(t *testing.T) {
    conn, _ := rados.NewConn()

    // rejects invalid options
    err := conn.SetConfigOption("wefoijweojfiw", "welfkwjelkfj")
    assert.Error(t, err, "Invalid option")

    // verify SetConfigOption changes a values
    log_file_val, err := conn.GetConfigOption("log_file")
    assert.NotEqual(t, log_file_val, "/dev/null")

    err = conn.SetConfigOption("log_file", "/dev/null")
    assert.NoError(t, err, "Invalid option")

    log_file_val, err = conn.GetConfigOption("log_file")
    assert.Equal(t, log_file_val, "/dev/null")
}

func TestParseDefaultConfigEnv(t *testing.T) {
    conn, _ := rados.NewConn()

    log_file_val, _ := conn.GetConfigOption("log_file")
    assert.NotEqual(t, log_file_val, "/dev/null")

    err := os.Setenv("CEPH_ARGS", "--log-file /dev/null")
    assert.NoError(t, err)

    err = conn.ParseDefaultConfigEnv()
    assert.NoError(t, err)

    log_file_val, _ = conn.GetConfigOption("log_file")
    assert.Equal(t, log_file_val, "/dev/null")
}

func TestParseCmdLineArgs(t *testing.T) {
    conn, _ := rados.NewConn()
    conn.ReadDefaultConfigFile()

    mon_host_val, _ := conn.GetConfigOption("mon_host")
    assert.NotEqual(t, mon_host_val, "1.1.1.1")

    args := []string{ "--mon-host", "1.1.1.1" }
    err := conn.ParseCmdLineArgs(args)
    assert.NoError(t, err)

    mon_host_val, _ = conn.GetConfigOption("mon_host")
    assert.Equal(t, mon_host_val, "1.1.1.1")
}

func TestGetClusterStats(t *testing.T) {
    conn, _ := rados.NewConn()
    conn.ReadDefaultConfigFile()
    conn.Connect()

    poolname := GetUUID()
    err := conn.MakePool(poolname)
    assert.NoError(t, err)

    pool, err := conn.OpenPool(poolname)
    assert.NoError(t, err)

    buf := make([]byte, 1<<22)
    pool.Write("obj", buf, 0)

    for i := 0; i < 30; i++ {
        stat, err := conn.GetClusterStats()
        assert.NoError(t, err)

        // wait a second if stats are zero
        if stat.Kb == 0 || stat.Kb_used == 0 ||
            stat.Kb_avail == 0 || stat.Num_objects == 0 {
            fmt.Println("waiting for cluster stats to refresh")
            time.Sleep(time.Second)
        } else {
            // success
            conn.Shutdown()
            return
        }
    }

    t.Error("Cluster stats are zero")

    conn.Shutdown()
}

func TestGetFSID(t *testing.T) {
    conn, _ := rados.NewConn()
    conn.ReadDefaultConfigFile()
    conn.Connect()

    fsid, err := conn.GetFSID()
    assert.NoError(t, err)
    assert.NotEqual(t, fsid, "")

    conn.Shutdown()
}

func TestGetInstanceID(t *testing.T) {
    conn, _ := rados.NewConn()
    conn.ReadDefaultConfigFile()
    conn.Connect()

    id := conn.GetInstanceID()
    assert.NotEqual(t, id, 0)

    conn.Shutdown()
}

func TestMakeDeletePool(t *testing.T) {
    conn, _ := rados.NewConn()
    conn.ReadDefaultConfigFile()
    conn.Connect()

    // get current list of pool
    pools, err := conn.ListPools()
    assert.NoError(t, err)

    // check that new pool name is unique
    new_name := GetUUID()
    for _, poolname := range pools {
        if new_name == poolname {
            t.Error("Random pool name exists!")
            return
        }
    }

    // create pool
    err = conn.MakePool(new_name)
    assert.NoError(t, err)

    // get updated list of pools
    pools, err = conn.ListPools()
    assert.NoError(t, err)

    // verify that the new pool name exists
    found := false
    for _, poolname := range pools {
        if new_name == poolname {
            found = true
        }
    }

    if !found {
        t.Error("Cannot find newly created pool")
    }

    // delete the pool
    err = conn.DeletePool(new_name)
    assert.NoError(t, err)

    // verify that it is gone

    // get updated list of pools
    pools, err = conn.ListPools()
    assert.NoError(t, err)

    // verify that the new pool name exists
    found = false
    for _, poolname := range pools {
        if new_name == poolname {
            found = true
        }
    }

    if found {
        t.Error("Deleted pool still exists")
    }

    conn.Shutdown()
}

func TestPingMonitor(t *testing.T) {
    conn, _ := rados.NewConn()
    conn.ReadDefaultConfigFile()
    conn.Connect()

    // mon id that should work with vstart.sh
    reply, err := conn.PingMonitor("a")
    if err == nil {
        assert.NotEqual(t, reply, "")
        return
    }

    // try to use a hostname as the monitor id
    mon_addr, _ := conn.GetConfigOption("mon_host")
    hosts, _ := net.LookupAddr(mon_addr)
    for _, host := range hosts {
        reply, err := conn.PingMonitor(host)
        if err == nil {
            assert.NotEqual(t, reply, "")
            return
        }
    }

    t.Error("Could not find a valid monitor id")

    conn.Shutdown()
}

func TestReadConfigFile(t *testing.T) {
    conn, _ := rados.NewConn()

    // check current log_file value
    log_file_val, err := conn.GetConfigOption("log_file")
    assert.NoError(t, err)
    assert.NotEqual(t, log_file_val, "/dev/null")

    // create a temporary ceph.conf file that changes the log_file conf
    // option.
    file, err := ioutil.TempFile("/tmp", "go-rados")
    assert.NoError(t, err)

    _, err = io.WriteString(file, "[global]\nlog_file = /dev/null\n")
    assert.NoError(t, err)

    // parse the config file
    err = conn.ReadConfigFile(file.Name())
    assert.NoError(t, err)

    // check current log_file value
    log_file_val, err = conn.GetConfigOption("log_file")
    assert.NoError(t, err)
    assert.Equal(t, log_file_val, "/dev/null")

    // cleanup
    file.Close()
    os.Remove(file.Name())
}

func TestWaitForLatestOSDMap(t *testing.T) {
    conn, _ := rados.NewConn()
    conn.ReadDefaultConfigFile()
    conn.Connect()

    err := conn.WaitForLatestOSDMap()
    assert.NoError(t, err)

    conn.Shutdown()
}
<commit_msg>test: check numeric osd id<commit_after>package rados_test

import "testing"
//import "bytes"
import "github.com/noahdesu/go-rados"
import "github.com/stretchr/testify/assert"
import "os"
import "os/exec"
import "io"
import "io/ioutil"
import "time"
import "net"
import "fmt"

func GetUUID() string {
    out, _ := exec.Command("uuidgen").Output()
    return string(out[:36])
}

func TestVersion(t *testing.T) {
    var major, minor, patch = rados.Version()
    assert.False(t, major < 0 || major > 1000, "invalid major")
    assert.False(t, minor < 0 || minor > 1000, "invalid minor")
    assert.False(t, patch < 0 || patch > 1000, "invalid patch")
}

func TestGetSetConfigOption(t *testing.T) {
    conn, _ := rados.NewConn()

    // rejects invalid options
    err := conn.SetConfigOption("wefoijweojfiw", "welfkwjelkfj")
    assert.Error(t, err, "Invalid option")

    // verify SetConfigOption changes a values
    log_file_val, err := conn.GetConfigOption("log_file")
    assert.NotEqual(t, log_file_val, "/dev/null")

    err = conn.SetConfigOption("log_file", "/dev/null")
    assert.NoError(t, err, "Invalid option")

    log_file_val, err = conn.GetConfigOption("log_file")
    assert.Equal(t, log_file_val, "/dev/null")
}

func TestParseDefaultConfigEnv(t *testing.T) {
    conn, _ := rados.NewConn()

    log_file_val, _ := conn.GetConfigOption("log_file")
    assert.NotEqual(t, log_file_val, "/dev/null")

    err := os.Setenv("CEPH_ARGS", "--log-file /dev/null")
    assert.NoError(t, err)

    err = conn.ParseDefaultConfigEnv()
    assert.NoError(t, err)

    log_file_val, _ = conn.GetConfigOption("log_file")
    assert.Equal(t, log_file_val, "/dev/null")
}

func TestParseCmdLineArgs(t *testing.T) {
    conn, _ := rados.NewConn()
    conn.ReadDefaultConfigFile()

    mon_host_val, _ := conn.GetConfigOption("mon_host")
    assert.NotEqual(t, mon_host_val, "1.1.1.1")

    args := []string{ "--mon-host", "1.1.1.1" }
    err := conn.ParseCmdLineArgs(args)
    assert.NoError(t, err)

    mon_host_val, _ = conn.GetConfigOption("mon_host")
    assert.Equal(t, mon_host_val, "1.1.1.1")
}

func TestGetClusterStats(t *testing.T) {
    conn, _ := rados.NewConn()
    conn.ReadDefaultConfigFile()
    conn.Connect()

    poolname := GetUUID()
    err := conn.MakePool(poolname)
    assert.NoError(t, err)

    pool, err := conn.OpenPool(poolname)
    assert.NoError(t, err)

    buf := make([]byte, 1<<22)
    pool.Write("obj", buf, 0)

    for i := 0; i < 30; i++ {
        stat, err := conn.GetClusterStats()
        assert.NoError(t, err)

        // wait a second if stats are zero
        if stat.Kb == 0 || stat.Kb_used == 0 ||
            stat.Kb_avail == 0 || stat.Num_objects == 0 {
            fmt.Println("waiting for cluster stats to refresh")
            time.Sleep(time.Second)
        } else {
            // success
            conn.Shutdown()
            return
        }
    }

    t.Error("Cluster stats are zero")

    conn.Shutdown()
}

func TestGetFSID(t *testing.T) {
    conn, _ := rados.NewConn()
    conn.ReadDefaultConfigFile()
    conn.Connect()

    fsid, err := conn.GetFSID()
    assert.NoError(t, err)
    assert.NotEqual(t, fsid, "")

    conn.Shutdown()
}

func TestGetInstanceID(t *testing.T) {
    conn, _ := rados.NewConn()
    conn.ReadDefaultConfigFile()
    conn.Connect()

    id := conn.GetInstanceID()
    assert.NotEqual(t, id, 0)

    conn.Shutdown()
}

func TestMakeDeletePool(t *testing.T) {
    conn, _ := rados.NewConn()
    conn.ReadDefaultConfigFile()
    conn.Connect()

    // get current list of pool
    pools, err := conn.ListPools()
    assert.NoError(t, err)

    // check that new pool name is unique
    new_name := GetUUID()
    for _, poolname := range pools {
        if new_name == poolname {
            t.Error("Random pool name exists!")
            return
        }
    }

    // create pool
    err = conn.MakePool(new_name)
    assert.NoError(t, err)

    // get updated list of pools
    pools, err = conn.ListPools()
    assert.NoError(t, err)

    // verify that the new pool name exists
    found := false
    for _, poolname := range pools {
        if new_name == poolname {
            found = true
        }
    }

    if !found {
        t.Error("Cannot find newly created pool")
    }

    // delete the pool
    err = conn.DeletePool(new_name)
    assert.NoError(t, err)

    // verify that it is gone

    // get updated list of pools
    pools, err = conn.ListPools()
    assert.NoError(t, err)

    // verify that the new pool name exists
    found = false
    for _, poolname := range pools {
        if new_name == poolname {
            found = true
        }
    }

    if found {
        t.Error("Deleted pool still exists")
    }

    conn.Shutdown()
}

func TestPingMonitor(t *testing.T) {
    conn, _ := rados.NewConn()
    conn.ReadDefaultConfigFile()
    conn.Connect()

    // mon id that should work with vstart.sh
    reply, err := conn.PingMonitor("a")
    if err == nil {
        assert.NotEqual(t, reply, "")
        return
    }

    // mon id that should work with micro-osd.sh
    reply, err = conn.PingMonitor("0")
    if err == nil {
        assert.NotEqual(t, reply, "")
        return
    }

    // try to use a hostname as the monitor id
    mon_addr, _ := conn.GetConfigOption("mon_host")
    hosts, _ := net.LookupAddr(mon_addr)
    for _, host := range hosts {
        reply, err := conn.PingMonitor(host)
        if err == nil {
            assert.NotEqual(t, reply, "")
            return
        }
    }

    t.Error("Could not find a valid monitor id")

    conn.Shutdown()
}

func TestReadConfigFile(t *testing.T) {
    conn, _ := rados.NewConn()

    // check current log_file value
    log_file_val, err := conn.GetConfigOption("log_file")
    assert.NoError(t, err)
    assert.NotEqual(t, log_file_val, "/dev/null")

    // create a temporary ceph.conf file that changes the log_file conf
    // option.
    file, err := ioutil.TempFile("/tmp", "go-rados")
    assert.NoError(t, err)

    _, err = io.WriteString(file, "[global]\nlog_file = /dev/null\n")
    assert.NoError(t, err)

    // parse the config file
    err = conn.ReadConfigFile(file.Name())
    assert.NoError(t, err)

    // check current log_file value
    log_file_val, err = conn.GetConfigOption("log_file")
    assert.NoError(t, err)
    assert.Equal(t, log_file_val, "/dev/null")

    // cleanup
    file.Close()
    os.Remove(file.Name())
}

func TestWaitForLatestOSDMap(t *testing.T) {
    conn, _ := rados.NewConn()
    conn.ReadDefaultConfigFile()
    conn.Connect()

    err := conn.WaitForLatestOSDMap()
    assert.NoError(t, err)

    conn.Shutdown()
}
<|endoftext|>


<commit_before>package main

import (
  "github.com/pilu/traffic"
)

type ResponseData struct {
  Message string
}

func RootHandler(w traffic.ResponseWriter, r *traffic.Request) {
  responseData := &ResponseData{ "Hello World" }
  w.Render("index", responseData)
}

<commit_msg>go go go fmt<commit_after>package main

import (
	"github.com/pilu/traffic"
)

type ResponseData struct {
	Message string
}

func RootHandler(w traffic.ResponseWriter, r *traffic.Request) {
	responseData := &ResponseData{"Hello World"}
	w.Render("index", responseData)
}
<|endoftext|>


<commit_before>package genericsite

import (
	"strings"

	. "github.com/xyproto/browserspeak"
	"github.com/xyproto/web"
)

type MenuEntry struct {
	id string
	text string
	url string
}

type MenuEntries []*MenuEntry

// Generate a menu ID based on the first word in the menu text
func (me *MenuEntry) AutoId() {
	firstword := me.text
	if strings.Contains(me.text, " ") {
		// Get the first word of the menu text
		firstword = strings.SplitN(me.text, " ", 2)[0]
	}
	me.id = firstword
}

// Takes something like "Admin:/admin" and returns a *MenuEntry
func NewMenuEntry(text_and_url string) *MenuEntry {
	var me MenuEntry
	me.text, me.url = ColonSplit(text_and_url)
	me.AutoId()
	return &me
}

func Links2menuEntries(links []string) MenuEntries {
	menuEntries := make(MenuEntries, len(links))
	for i, text_and_url := range links {
		menuEntries[i] = NewMenuEntry(text_and_url)
	}
	return menuEntries
}

// Generate tags for the menu based on a list of "MenuDescription:/menu/url"
func MenuSnippet(menuEntries MenuEntries) *Page {
	var a, li, sep *Tag

	page, ul := CowboyTag("ul")
	ul.AddAttr("class", "menuList")
	//ul.AddStyle("list-style-type", "none")
	//ul.AddStyle("float", "left")
	//ul.AddStyle("margin", "0")

	for i, menuEntry := range menuEntries {

		li = ul.AddNewTag("li")
		li.AddAttr("class", "menuEntry")

		// TODO: Make sure not duplicate ids are added for two menu entries named "Hi there" and "Hi you"
		menuId := "menu" + menuEntry.id
		li.AddAttr("id", menuId)

		// All menu entries are now hidden by default!
		//li.AddStyle("display", "none")
		//li.AddStyle("display", "inline")
		li.SansSerif()
		//li.CustomSansSerif("Armata")

		// For every element, but not the first one
		if i > 0 {
			// Insert a '|' character in a div
			sep = li.AddNewTag("div")
			sep.AddContent("|")
			sep.AddAttr("class", "separator")
		}

		a = li.AddNewTag("a")
		a.AddAttr("class", "menulink")
		a.AddAttr("href", menuEntry.url)
		a.AddContent(menuEntry.text)

	}

	return page
}

// Checks if a *MenuEntry exists in a []*MenuEntry (MenuEntries)
func HasEntry(checkEntry *MenuEntry, menuEntries MenuEntries) bool {
	for _, menuEntry := range menuEntries {
		if menuEntry.url == checkEntry.url {
			return true
		}
	}
	return false
}

func AddIfNotAdded(url string, currentMenuURL string, filteredMenuEntries *MenuEntries, menuEntry *MenuEntry) {
	if currentMenuURL != url {
		if menuEntry.url == url {
			if !HasEntry(menuEntry, *filteredMenuEntries) {
				*filteredMenuEntries = append(*filteredMenuEntries, menuEntry)
			}
		}
	}
}

/*
 * Functions that generate functions that generate content that can be used in templates.
 * type TemplateValues map[string]string
 * type TemplateValueGenerator func(*web.Context) TemplateValues
 * type TemplateValueGeneratorFactory func(*UserState) TemplateValueGenerator
 */
// TODO: Take the same parameters as the old menu generating code
// TODO: Put one if these in each engine then combine them somehow
// TODO: Check for the menyEntry.url first, then check the rights, not the other way around
// TODO: Fix and refactor this one
func DynamicMenuFactoryGenerator(currentMenuURL string, menuEntries MenuEntries) TemplateValueGeneratorFactory {
	return func(state *UserState) TemplateValueGenerator {
		return func(ctx *web.Context) TemplateValues {

			var filteredMenuEntries MenuEntries
			var logoutEntry *MenuEntry = nil

			// Build up filteredMenuEntries based on what should be shown or not
			for _, menuEntry := range menuEntries {

				// Don't add duplicates
				if HasEntry(menuEntry, filteredMenuEntries) {
					continue
				}

				// Add this one last
				if menuEntry.url == "/logout" {
					if state.UserRights(ctx) {
						logoutEntry = menuEntry
					}
					continue
				}

				// Always show the Overview menu
				AddIfNotAdded("/", currentMenuURL, &filteredMenuEntries, menuEntry)
				//if menuEntry.url == "/" {
				//	if !HasEntry(menuEntry, filteredMenuEntries) {
				//		filteredMenuEntries = append(filteredMenuEntries, menuEntry)
				//	}
				//}

				// If logged in, show Logout and the content
				if state.UserRights(ctx) {

					// Add every link except the current page we're on
					if menuEntry.url != currentMenuURL {
						if !HasEntry(menuEntry, filteredMenuEntries) {
							if (menuEntry.url != "/login") && (menuEntry.url != "/register") {
								filteredMenuEntries = append(filteredMenuEntries, menuEntry)
							}
						}
					}

					// Show admin content
					if state.AdminRights(ctx) {
						AddIfNotAdded("/admin", currentMenuURL, &filteredMenuEntries, menuEntry)
					}
				} else {
					// Only show Login and Register
					AddIfNotAdded("/login", currentMenuURL, &filteredMenuEntries, menuEntry)
					AddIfNotAdded("/register", currentMenuURL, &filteredMenuEntries, menuEntry)
				}

			}

			if logoutEntry != nil {
				AddIfNotAdded("/logout", "", &filteredMenuEntries, logoutEntry)
			}

			page := MenuSnippet(filteredMenuEntries)
			retval := page.String()

			// TODO: Return the CSS as well somehow
			//css := page.CSS()

			return TemplateValues{"menu": retval}
		}
	}
}

// Combines two TemplateValueGenerators into one TemplateValueGenerator by adding the strings per key
func TemplateValueGeneratorCombinator(tvg1, tvg2 TemplateValueGenerator) TemplateValueGenerator {
	return func(ctx *web.Context) TemplateValues {
		tv1 := tvg1(ctx)
		tv2 := tvg2(ctx)
		for key, value := range tv2 {
			// TODO: Check if key exists in tv1 first
			tv1[key] += value
		}
		return tv1
	}
}
<commit_msg>Comment<commit_after>package genericsite

import (
	"strings"

	. "github.com/xyproto/browserspeak"
	"github.com/xyproto/web"
)

type MenuEntry struct {
	id string
	text string
	url string
}

type MenuEntries []*MenuEntry

// Generate a menu ID based on the first word in the menu text
func (me *MenuEntry) AutoId() {
	firstword := me.text
	if strings.Contains(me.text, " ") {
		// Get the first word of the menu text
		firstword = strings.SplitN(me.text, " ", 2)[0]
	}
	me.id = firstword
}

// Takes something like "Admin:/admin" and returns a *MenuEntry
func NewMenuEntry(text_and_url string) *MenuEntry {
	var me MenuEntry
	me.text, me.url = ColonSplit(text_and_url)
	me.AutoId()
	return &me
}

func Links2menuEntries(links []string) MenuEntries {
	menuEntries := make(MenuEntries, len(links))
	for i, text_and_url := range links {
		menuEntries[i] = NewMenuEntry(text_and_url)
	}
	return menuEntries
}

// Generate tags for the menu based on a list of "MenuDescription:/menu/url"
func MenuSnippet(menuEntries MenuEntries) *Page {
	var a, li, sep *Tag

	page, ul := CowboyTag("ul")
	ul.AddAttr("class", "menuList")
	//ul.AddStyle("list-style-type", "none")
	//ul.AddStyle("float", "left")
	//ul.AddStyle("margin", "0")

	for i, menuEntry := range menuEntries {

		li = ul.AddNewTag("li")
		li.AddAttr("class", "menuEntry")

		// TODO: Make sure not duplicate ids are added for two menu entries named "Hi there" and "Hi you"
		menuId := "menu" + menuEntry.id
		li.AddAttr("id", menuId)

		// All menu entries are now hidden by default!
		//li.AddStyle("display", "none")
		//li.AddStyle("display", "inline")
		li.SansSerif()
		//li.CustomSansSerif("Armata")

		// For every element, but not the first one
		if i > 0 {
			// Insert a '|' character in a div
			sep = li.AddNewTag("div")
			sep.AddContent("|")
			sep.AddAttr("class", "separator")
		}

		a = li.AddNewTag("a")
		a.AddAttr("class", "menulink")
		a.AddAttr("href", menuEntry.url)
		a.AddContent(menuEntry.text)

	}

	return page
}

// Checks if a *MenuEntry exists in a []*MenuEntry (MenuEntries)
func HasEntry(checkEntry *MenuEntry, menuEntries MenuEntries) bool {
	for _, menuEntry := range menuEntries {
		if menuEntry.url == checkEntry.url {
			return true
		}
	}
	return false
}

func AddIfNotAdded(url string, currentMenuURL string, filteredMenuEntries *MenuEntries, menuEntry *MenuEntry) {
	if currentMenuURL != url {
		if menuEntry.url == url {
			if !HasEntry(menuEntry, *filteredMenuEntries) {
				*filteredMenuEntries = append(*filteredMenuEntries, menuEntry)
			}
		}
	}
}

/*
 * Functions that generate functions that generate content that can be used in templates.
 * type TemplateValues map[string]string
 * type TemplateValueGenerator func(*web.Context) TemplateValues
 * type TemplateValueGeneratorFactory func(*UserState) TemplateValueGenerator
 */
// TODO: Take the same parameters as the old menu generating code
// TODO: Put one if these in each engine then combine them somehow
// TODO: Check for the menyEntry.url first, then check the rights, not the other way around
// TODO: Fix and refactor this one
// TODO: Check the user status _once_, and the admin status _once_, then generate the menu
func DynamicMenuFactoryGenerator(currentMenuURL string, menuEntries MenuEntries) TemplateValueGeneratorFactory {
	return func(state *UserState) TemplateValueGenerator {
		return func(ctx *web.Context) TemplateValues {

			var filteredMenuEntries MenuEntries
			var logoutEntry *MenuEntry = nil

			// Build up filteredMenuEntries based on what should be shown or not
			for _, menuEntry := range menuEntries {

				// Don't add duplicates
				if HasEntry(menuEntry, filteredMenuEntries) {
					continue
				}

				// Add this one last
				if menuEntry.url == "/logout" {
					if state.UserRights(ctx) {
						logoutEntry = menuEntry
					}
					continue
				}

				// Always show the Overview menu
				AddIfNotAdded("/", currentMenuURL, &filteredMenuEntries, menuEntry)
				//if menuEntry.url == "/" {
				//	if !HasEntry(menuEntry, filteredMenuEntries) {
				//		filteredMenuEntries = append(filteredMenuEntries, menuEntry)
				//	}
				//}

				// If logged in, show Logout and the content
				if state.UserRights(ctx) {

					// Add every link except the current page we're on
					if menuEntry.url != currentMenuURL {
						if !HasEntry(menuEntry, filteredMenuEntries) {
							if (menuEntry.url != "/login") && (menuEntry.url != "/register") {
								filteredMenuEntries = append(filteredMenuEntries, menuEntry)
							}
						}
					}

					// Show admin content
					if state.AdminRights(ctx) {
						AddIfNotAdded("/admin", currentMenuURL, &filteredMenuEntries, menuEntry)
					}
				} else {
					// Only show Login and Register
					AddIfNotAdded("/login", currentMenuURL, &filteredMenuEntries, menuEntry)
					AddIfNotAdded("/register", currentMenuURL, &filteredMenuEntries, menuEntry)
				}

			}

			if logoutEntry != nil {
				AddIfNotAdded("/logout", "", &filteredMenuEntries, logoutEntry)
			}

			page := MenuSnippet(filteredMenuEntries)
			retval := page.String()

			// TODO: Return the CSS as well somehow
			//css := page.CSS()

			return TemplateValues{"menu": retval}
		}
	}
}

// Combines two TemplateValueGenerators into one TemplateValueGenerator by adding the strings per key
func TemplateValueGeneratorCombinator(tvg1, tvg2 TemplateValueGenerator) TemplateValueGenerator {
	return func(ctx *web.Context) TemplateValues {
		tv1 := tvg1(ctx)
		tv2 := tvg2(ctx)
		for key, value := range tv2 {
			// TODO: Check if key exists in tv1 first
			tv1[key] += value
		}
		return tv1
	}
}
<|endoftext|>


<commit_before>// Package api is an API Gateway
package api

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

	"github.com/gorilla/mux"
	"github.com/micro/cli"
	"github.com/micro/go-api"
	ahandler "github.com/micro/go-api/handler"
	"github.com/micro/go-api/handler/event"
	"github.com/micro/go-api/router"
	"github.com/micro/go-api/server"
	"github.com/micro/go-log"
	"github.com/micro/go-micro"
	"github.com/micro/micro/internal/handler"
	"github.com/micro/micro/internal/helper"
	"github.com/micro/micro/internal/stats"
	"github.com/micro/micro/plugin"
)

var (
	Name         = "go.micro.api"
	Address      = ":8080"
	Handler      = string(api.Default)
	RPCPath      = "/rpc"
	APIPath      = "/"
	ProxyPath    = "/{service:[a-zA-Z0-9]+}"
	Namespace    = "go.micro.api"
	HeaderPrefix = "X-Micro-"
	CORS         = map[string]bool{"*": true}
)

type srv struct {
	*mux.Router
}

func (s *srv) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if origin := r.Header.Get("Origin"); CORS[origin] {
		w.Header().Set("Access-Control-Allow-Origin", origin)
	} else if len(origin) > 0 && CORS["*"] {
		w.Header().Set("Access-Control-Allow-Origin", origin)
	}

	w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
	w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
	w.Header().Set("Access-Control-Allow-Credentials", "true")

	if r.Method == "OPTIONS" {
		return
	}

	s.Router.ServeHTTP(w, r)
}

func run(ctx *cli.Context) {
	if len(ctx.GlobalString("server_name")) > 0 {
		Name = ctx.GlobalString("server_name")
	}
	if len(ctx.String("address")) > 0 {
		Address = ctx.String("address")
	}
	if len(ctx.String("handler")) > 0 {
		Handler = ctx.String("handler")
	}
	if len(ctx.String("namespace")) > 0 {
		Namespace = ctx.String("namespace")
	}
	if len(ctx.String("cors")) > 0 {
		origins := make(map[string]bool)
		for _, origin := range strings.Split(ctx.String("cors"), ",") {
			origins[origin] = true
		}
		CORS = origins
	}

	// Init plugins
	for _, p := range Plugins() {
		p.Init(ctx)
	}

	// Init API
	var opts []server.Option

	if ctx.GlobalBool("enable_acme") {
		hosts := helper.ACMEHosts(ctx)
		opts = append(opts, server.EnableACME(true))
		opts = append(opts, server.ACMEHosts(hosts...))
	} else if ctx.GlobalBool("enable_tls") {
		config, err := helper.TLSConfig(ctx)
		if err != nil {
			fmt.Println(err.Error())
			return
		}

		opts = append(opts, server.EnableTLS(true))
		opts = append(opts, server.TLSConfig(config))
	}

	// create the router
	r := mux.NewRouter()
	s := &srv{r}
	var h http.Handler = s

	if ctx.GlobalBool("enable_stats") {
		st := stats.New()
		r.HandleFunc("/stats", st.StatsHandler)
		h = st.ServeHTTP(s)
		st.Start()
		defer st.Stop()
	}

	log.Logf("Registering RPC Handler at %s", RPCPath)
	r.HandleFunc(RPCPath, handler.RPC)

	switch Handler {
	case "rpc":
		log.Logf("Registering API RPC Handler at %s", APIPath)
		rt := router.NewRouter(router.WithNamespace(Namespace), router.WithHandler(api.Rpc))
		r.PathPrefix(APIPath).Handler(handler.RPCX(rt, nil))
	case "proxy":
		log.Logf("Registering API Proxy Handler at %s", ProxyPath)
		rt := router.NewRouter(router.WithNamespace(Namespace), router.WithHandler(api.Proxy))
		r.PathPrefix(ProxyPath).Handler(handler.Proxy(rt, nil, false))
	case "api":
		log.Logf("Registering API Request Handler at %s", APIPath)
		rt := router.NewRouter(router.WithNamespace(Namespace), router.WithHandler(api.Api))
		r.PathPrefix(APIPath).Handler(handler.API(rt, nil))
	case "event":
		log.Logf("Registering API Event Handler at %s", APIPath)
		rt := router.NewRouter(router.WithNamespace(Namespace), router.WithHandler(api.Event))
		ev := event.NewHandler(ahandler.WithNamespace(Namespace), ahandler.WithRouter(rt))
		r.PathPrefix(APIPath).Handler(ev)
	default:
		log.Logf("Registering API Default Handler at %s", APIPath)
		r.PathPrefix(APIPath).Handler(handler.Meta(Namespace))
	}

	// reverse wrap handler
	plugins := append(Plugins(), plugin.Plugins()...)
	for i := len(plugins); i > 0; i-- {
		h = plugins[i-1].Handler()(h)
	}

	// create the server
	api := server.NewServer(Address)
	api.Init(opts...)
	api.Handle("/", h)

	// Initialise Server
	service := micro.NewService(
		micro.Name(Name),
		micro.RegisterTTL(
			time.Duration(ctx.GlobalInt("register_ttl"))*time.Second,
		),
		micro.RegisterInterval(
			time.Duration(ctx.GlobalInt("register_interval"))*time.Second,
		),
	)

	// Start API
	if err := api.Start(); err != nil {
		log.Fatal(err)
	}

	// Run server
	if err := service.Run(); err != nil {
		log.Fatal(err)
	}

	// Stop API
	if err := api.Stop(); err != nil {
		log.Fatal(err)
	}
}

func Commands() []cli.Command {
	command := cli.Command{
		Name:   "api",
		Usage:  "Run the micro API",
		Action: run,
		Flags: []cli.Flag{
			cli.StringFlag{
				Name:   "address",
				Usage:  "Set the api address e.g 0.0.0.0:8080",
				EnvVar: "MICRO_API_ADDRESS",
			},
			cli.StringFlag{
				Name:   "handler",
				Usage:  "Specify the request handler to be used for mapping HTTP requests to services; {api, proxy, rpc}",
				EnvVar: "MICRO_API_HANDLER",
			},
			cli.StringFlag{
				Name:   "namespace",
				Usage:  "Set the namespace used by the API e.g. com.example.api",
				EnvVar: "MICRO_API_NAMESPACE",
			},
			cli.StringFlag{
				Name:   "cors",
				Usage:  "Comma separated whitelist of allowed origins for CORS",
				EnvVar: "MICRO_API_CORS",
			},
		},
	}

	for _, p := range Plugins() {
		if cmds := p.Commands(); len(cmds) > 0 {
			command.Subcommands = append(command.Subcommands, cmds...)
		}

		if flags := p.Flags(); len(flags) > 0 {
			command.Flags = append(command.Flags, flags...)
		}
	}

	return []cli.Command{command}
}
<commit_msg>Added event as a option to micro api --handler<commit_after>// Package api is an API Gateway
package api

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

	"github.com/gorilla/mux"
	"github.com/micro/cli"
	"github.com/micro/go-api"
	ahandler "github.com/micro/go-api/handler"
	"github.com/micro/go-api/handler/event"
	"github.com/micro/go-api/router"
	"github.com/micro/go-api/server"
	"github.com/micro/go-log"
	"github.com/micro/go-micro"
	"github.com/micro/micro/internal/handler"
	"github.com/micro/micro/internal/helper"
	"github.com/micro/micro/internal/stats"
	"github.com/micro/micro/plugin"
)

var (
	Name         = "go.micro.api"
	Address      = ":8080"
	Handler      = string(api.Default)
	RPCPath      = "/rpc"
	APIPath      = "/"
	ProxyPath    = "/{service:[a-zA-Z0-9]+}"
	Namespace    = "go.micro.api"
	HeaderPrefix = "X-Micro-"
	CORS         = map[string]bool{"*": true}
)

type srv struct {
	*mux.Router
}

func (s *srv) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if origin := r.Header.Get("Origin"); CORS[origin] {
		w.Header().Set("Access-Control-Allow-Origin", origin)
	} else if len(origin) > 0 && CORS["*"] {
		w.Header().Set("Access-Control-Allow-Origin", origin)
	}

	w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
	w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
	w.Header().Set("Access-Control-Allow-Credentials", "true")

	if r.Method == "OPTIONS" {
		return
	}

	s.Router.ServeHTTP(w, r)
}

func run(ctx *cli.Context) {
	if len(ctx.GlobalString("server_name")) > 0 {
		Name = ctx.GlobalString("server_name")
	}
	if len(ctx.String("address")) > 0 {
		Address = ctx.String("address")
	}
	if len(ctx.String("handler")) > 0 {
		Handler = ctx.String("handler")
	}
	if len(ctx.String("namespace")) > 0 {
		Namespace = ctx.String("namespace")
	}
	if len(ctx.String("cors")) > 0 {
		origins := make(map[string]bool)
		for _, origin := range strings.Split(ctx.String("cors"), ",") {
			origins[origin] = true
		}
		CORS = origins
	}

	// Init plugins
	for _, p := range Plugins() {
		p.Init(ctx)
	}

	// Init API
	var opts []server.Option

	if ctx.GlobalBool("enable_acme") {
		hosts := helper.ACMEHosts(ctx)
		opts = append(opts, server.EnableACME(true))
		opts = append(opts, server.ACMEHosts(hosts...))
	} else if ctx.GlobalBool("enable_tls") {
		config, err := helper.TLSConfig(ctx)
		if err != nil {
			fmt.Println(err.Error())
			return
		}

		opts = append(opts, server.EnableTLS(true))
		opts = append(opts, server.TLSConfig(config))
	}

	// create the router
	r := mux.NewRouter()
	s := &srv{r}
	var h http.Handler = s

	if ctx.GlobalBool("enable_stats") {
		st := stats.New()
		r.HandleFunc("/stats", st.StatsHandler)
		h = st.ServeHTTP(s)
		st.Start()
		defer st.Stop()
	}

	log.Logf("Registering RPC Handler at %s", RPCPath)
	r.HandleFunc(RPCPath, handler.RPC)

	switch Handler {
	case "rpc":
		log.Logf("Registering API RPC Handler at %s", APIPath)
		rt := router.NewRouter(router.WithNamespace(Namespace), router.WithHandler(api.Rpc))
		r.PathPrefix(APIPath).Handler(handler.RPCX(rt, nil))
	case "proxy":
		log.Logf("Registering API Proxy Handler at %s", ProxyPath)
		rt := router.NewRouter(router.WithNamespace(Namespace), router.WithHandler(api.Proxy))
		r.PathPrefix(ProxyPath).Handler(handler.Proxy(rt, nil, false))
	case "api":
		log.Logf("Registering API Request Handler at %s", APIPath)
		rt := router.NewRouter(router.WithNamespace(Namespace), router.WithHandler(api.Api))
		r.PathPrefix(APIPath).Handler(handler.API(rt, nil))
	case "event":
		log.Logf("Registering API Event Handler at %s", APIPath)
		rt := router.NewRouter(router.WithNamespace(Namespace), router.WithHandler(api.Event))
		ev := event.NewHandler(ahandler.WithNamespace(Namespace), ahandler.WithRouter(rt))
		r.PathPrefix(APIPath).Handler(ev)
	default:
		log.Logf("Registering API Default Handler at %s", APIPath)
		r.PathPrefix(APIPath).Handler(handler.Meta(Namespace))
	}

	// reverse wrap handler
	plugins := append(Plugins(), plugin.Plugins()...)
	for i := len(plugins); i > 0; i-- {
		h = plugins[i-1].Handler()(h)
	}

	// create the server
	api := server.NewServer(Address)
	api.Init(opts...)
	api.Handle("/", h)

	// Initialise Server
	service := micro.NewService(
		micro.Name(Name),
		micro.RegisterTTL(
			time.Duration(ctx.GlobalInt("register_ttl"))*time.Second,
		),
		micro.RegisterInterval(
			time.Duration(ctx.GlobalInt("register_interval"))*time.Second,
		),
	)

	// Start API
	if err := api.Start(); err != nil {
		log.Fatal(err)
	}

	// Run server
	if err := service.Run(); err != nil {
		log.Fatal(err)
	}

	// Stop API
	if err := api.Stop(); err != nil {
		log.Fatal(err)
	}
}

func Commands() []cli.Command {
	command := cli.Command{
		Name:   "api",
		Usage:  "Run the micro API",
		Action: run,
		Flags: []cli.Flag{
			cli.StringFlag{
				Name:   "address",
				Usage:  "Set the api address e.g 0.0.0.0:8080",
				EnvVar: "MICRO_API_ADDRESS",
			},
			cli.StringFlag{
				Name:   "handler",
				Usage:  "Specify the request handler to be used for mapping HTTP requests to services; {api, proxy, rpc, event}",
				EnvVar: "MICRO_API_HANDLER",
			},
			cli.StringFlag{
				Name:   "namespace",
				Usage:  "Set the namespace used by the API e.g. com.example.api",
				EnvVar: "MICRO_API_NAMESPACE",
			},
			cli.StringFlag{
				Name:   "cors",
				Usage:  "Comma separated whitelist of allowed origins for CORS",
				EnvVar: "MICRO_API_CORS",
			},
		},
	}

	for _, p := range Plugins() {
		if cmds := p.Commands(); len(cmds) > 0 {
			command.Subcommands = append(command.Subcommands, cmds...)
		}

		if flags := p.Flags(); len(flags) > 0 {
			command.Flags = append(command.Flags, flags...)
		}
	}

	return []cli.Command{command}
}
<|endoftext|>