<commit_before>package main

import (
	"bytes"
	"encoding/binary"
	"errors"
	"fmt"
	"sort"
	"strings"
	"sync"
	"time"

	"github.com/dgryski/go-tsz"
	"github.com/gocql/gocql"
	"github.com/grafana/grafana/pkg/log"
	"github.com/raintank/met"
)

// write aggregated data to cassandra.

const month_sec = 60 * 60 * 24 * 28

const keyspace_schema = `CREATE KEYSPACE IF NOT EXISTS raintank WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1}  AND durable_writes = true`
const table_schema = `CREATE TABLE IF NOT EXISTS raintank.metric (
    key ascii,
    ts int,
    data blob,
    PRIMARY KEY (key, ts)
) WITH COMPACT STORAGE
    AND CLUSTERING ORDER BY (ts DESC)
    AND compaction = {'class': 'org.apache.cassandra.db.compaction.DateTieredCompactionStrategy'}
    AND compression = {'sstable_compression': 'org.apache.cassandra.io.compress.LZ4Compressor'}
    AND read_repair_chance = 0.0
    AND dclocal_read_repair_chance = 0`

/*
https://godoc.org/github.com/gocql/gocql#Session
Session is the interface used by users to interact with the database.
It's safe for concurrent use by multiple goroutines and a typical usage scenario is to have one global session
object to interact with the whole Cassandra cluster.
*/

type cassandraStore struct {
	session          *gocql.Session
	workerQueues     []chan *ChunkWriteRequest
	writeQueueMeters []met.Meter
}

func NewCassandraStore(stats met.Backend, addrs, consistency string, timeout, writers int) (*cassandraStore, error) {
	cluster := gocql.NewCluster(strings.Split(addrs, ",")...)
	cluster.Consistency = gocql.ParseConsistency(consistency)
	cluster.Timeout = time.Duration(timeout) * time.Millisecond
	cluster.NumConns = writers
	var err error
	tmpSession, err := cluster.CreateSession()
	if err != nil {
		return nil, err
	}
	// ensure the keyspace and table exist.
	err = tmpSession.Query(keyspace_schema).Exec()
	if err != nil {
		return nil, err
	}
	err = tmpSession.Query(table_schema).Exec()
	if err != nil {
		return nil, err
	}
	tmpSession.Close()
	cluster.Keyspace = "raintank"
	session, err := cluster.CreateSession()
	if err != nil {
		return nil, err
	}
	c := &cassandraStore{
		session:          session,
		workerQueues:     make([]chan *ChunkWriteRequest, *cassandraWriteConcurrency),
		writeQueueMeters: make([]met.Meter, *cassandraWriteConcurrency),
	}

	for i := 0; i < *cassandraWriteConcurrency; i++ {
		c.workerQueues[i] = make(chan *ChunkWriteRequest, *cassandraWriteQueueSize)
		c.writeQueueMeters[i] = stats.NewMeter(fmt.Sprintf("cassandra.write_queue.%d.items", i+1), 0)
		go c.processWriteQueue(c.workerQueues[i], c.writeQueueMeters[i])
	}

	return c, err
}

func (c *cassandraStore) Add(cwr *ChunkWriteRequest) {
	sum := 0
	for _, char := range cwr.key {
		sum += int(char)
	}
	which := sum % *cassandraWriteConcurrency
	c.writeQueueMeters[which].Value(int64(len(c.workerQueues[which])))
	c.workerQueues[which] <- cwr
	c.writeQueueMeters[which].Value(int64(len(c.workerQueues[which])))
}

/* process writeQueue.
 */
func (c *cassandraStore) processWriteQueue(queue chan *ChunkWriteRequest, meter met.Meter) {
	tick := time.Tick(time.Duration(1) * time.Second)
	for {
		select {
		case <-tick:
			meter.Value(int64(len(queue)))
		case cwr := <-queue:
			meter.Value(int64(len(queue)))
			log.Debug("starting to save %s:%d %v", cwr.key, cwr.chunk.T0, cwr.chunk)
			//log how long the chunk waited in the queue before we attempted to save to cassandra
			cassBlockDuration.Value(time.Now().Sub(cwr.timestamp))

			data := cwr.chunk.Series.Bytes()
			chunkSizeAtSave.Value(int64(len(data)))
			version := FormatStandardGoTsz
			buf := new(bytes.Buffer)
			err := binary.Write(buf, binary.LittleEndian, uint8(version))
			if err != nil {
				// TODO
			}
			_, err = buf.Write(data)
			if err != nil {
				// TODO
			}
			success := false
			attempts := 0
			for !success {
				err := c.insertChunk(cwr.key, cwr.chunk.T0, buf.Bytes(), int(cwr.ttl))
				if err == nil {
					success = true
					cwr.chunk.Saved = true
					SendPersistMessage(cwr.key, cwr.chunk.T0)
					log.Debug("save complete. %s:%d %v", cwr.key, cwr.chunk.T0, cwr.chunk)
					chunkSaveOk.Inc(1)
				} else {
					if (attempts % 20) == 0 {
						log.Warn("failed to save chunk to cassandra after %d attempts. %v, %s", attempts+1, cwr.chunk, err)
					}
					chunkSaveFail.Inc(1)
					sleepTime := 100 * attempts
					if sleepTime > 2000 {
						sleepTime = 2000
					}
					time.Sleep(time.Duration(sleepTime) * time.Millisecond)
					attempts++
				}
			}
		}
	}
}

// Insert Chunks into Cassandra.
//
// key: is the metric_id
// ts: is the start of the aggregated time range.
// data: is the payload as bytes.
func (c *cassandraStore) insertChunk(key string, t0 uint32, data []byte, ttl int) error {
	// for unit tests
	if c.session == nil {
		return nil
	}
	query := fmt.Sprintf("INSERT INTO metric (key, ts, data) values(?,?,?) USING TTL %d", ttl)
	row_key := fmt.Sprintf("%s_%d", key, t0/month_sec) // "month number" based on unix timestamp (rounded down)
	pre := time.Now()
	ret := c.session.Query(query, row_key, t0, data).Exec()
	cassPutDuration.Value(time.Now().Sub(pre))
	return ret
}

type outcome struct {
	month   uint32
	sortKey uint32
	i       *gocql.Iter
}
type asc []outcome

func (o asc) Len() int           { return len(o) }
func (o asc) Swap(i, j int)      { o[i], o[j] = o[j], o[i] }
func (o asc) Less(i, j int) bool { return o[i].sortKey < o[j].sortKey }

// Basic search of cassandra.
// start inclusive, end exclusive
func (c *cassandraStore) Search(key string, start, end uint32) ([]Iter, error) {
	iters := make([]Iter, 0)
	if start > end {
		return iters, fmt.Errorf("start must be before end.")
	}

	results := make(chan outcome)
	wg := &sync.WaitGroup{}

	query := func(month, sortKey uint32, q string, p ...interface{}) {
		wg.Add(1)
		go func() {
			results <- outcome{month, sortKey, c.session.Query(q, p...).Iter()}
			wg.Done()
		}()
	}

	start_month := start - (start % month_sec)       // starting row has to be at, or before, requested start
	end_month := (end - 1) - ((end - 1) % month_sec) // ending row has to be include the last point we might need

	pre := time.Now()

	// unfortunately in the database we only have the t0's of all chunks.
	// this means we can easily make sure to include the correct last chunk (just query for a t0 < end, the last chunk will contain the last needed data)
	// but it becomes hard to find which should be the first chunk to include. we can't just query for start <= t0 because than will miss some data at the beginning
	// we can't assume we know the chunkSpan so we can't just calculate the t0 >= start - <some-predefined-number> because chunkSpans may change over time.
	// we effectively need all chunks with a t0 > start, as well as the last chunk with a t0 <= start.
	// since we make sure that you can only use chunkSpans so that month_sec % chunkSpan == 0, we know that this previous chunk will always be in the same row
	// as the one that has start_month.

	row_key := fmt.Sprintf("%s_%d", key, start_month/month_sec)
	query(start_month, start_month, "SELECT ts, data FROM metric WHERE key=? AND ts <= ? Limit 1", row_key, start)

	if start_month == end_month {
		// we need a selection of the row between startTs and endTs
		row_key = fmt.Sprintf("%s_%d", key, start_month/month_sec)
		query(start_month, start_month+1, "SELECT ts, data FROM metric WHERE key = ? AND ts > ? AND ts < ? ORDER BY ts ASC", row_key, start, end)
	} else {
		// get row_keys for each row we need to query.
		for month := start_month; month <= end_month; month += month_sec {
			row_key = fmt.Sprintf("%s_%d", key, month/month_sec)
			if month == start_month {
				// we want from startTs to the end of the row.
				query(month, month+1, "SELECT ts, data FROM metric WHERE key = ? AND ts >= ? ORDER BY ts ASC", row_key, start+1)
			} else if month == end_month {
				// we want from start of the row till the endTs.
				query(month, month, "SELECT ts, data FROM metric WHERE key = ? AND ts <= ? ORDER BY ts ASC", row_key, end-1)
			} else {
				// we want all columns
				query(month, month, "SELECT ts, data FROM metric WHERE key = ? ORDER BY ts ASC", row_key)
			}
		}
	}
	outcomes := make([]outcome, 0)

	// wait for all queries to complete then close the results channel so that the following
	// for loop ends.
	go func() {
		wg.Wait()
		cassGetDuration.Value(time.Now().Sub(pre))
		close(results)
	}()
	pre = time.Now()

	for o := range results {
		outcomes = append(outcomes, o)
	}
	// we have all of the results, but they could have arrived in any order.
	sort.Sort(asc(outcomes))

	var b []byte
	var ts int
	for _, outcome := range outcomes {
		chunks := int64(0)
		for outcome.i.Scan(&ts, &b) {
			chunks += 1
			chunkSizeAtLoad.Value(int64(len(b)))
			if len(b) < 2 {
				err := errors.New("unpossibly small chunk in cassandra")
				log.Error(3, err.Error())
				return iters, err
			}
			startByte := 1
			if Format(b[0]) != FormatStandardGoTsz {
				// Production currently has a few weeks of data that does not have
				// a format byte.  In 1 month (20th Jan 2016), this can be removed.
				//err := errors.New("unrecognized chunk format in cassandra")
				//log.Error(3, err.Error())
				//return iters, err
				startByte = 0
			}
			iter, err := tsz.NewIterator(b[startByte:])
			if err != nil {
				log.Error(3, "failed to unpack cassandra payload. %s", err)
				return iters, err
			}
			iters = append(iters, NewIter(iter, "cassandra month=%d t0=%d", outcome.month, ts))
		}
		cassChunksPerRow.Value(chunks)
		err := outcome.i.Close()
		if err != nil {
			log.Error(3, "cassandra query error. %s", err)
		}
	}
	cassToIterDuration.Value(time.Now().Sub(pre))
	cassRowsPerResponse.Value(int64(len(outcomes)))
	log.Debug("searchCassandra(): %d outcomes (queries), %d total iters", len(outcomes), len(iters))
	return iters, nil
}

func (c *cassandraStore) Stop() {
	c.session.Close()
}
<commit_msg>remove support for chunks without version id<commit_after>package main

import (
	"bytes"
	"encoding/binary"
	"errors"
	"fmt"
	"sort"
	"strings"
	"sync"
	"time"

	"github.com/dgryski/go-tsz"
	"github.com/gocql/gocql"
	"github.com/grafana/grafana/pkg/log"
	"github.com/raintank/met"
)

// write aggregated data to cassandra.

const month_sec = 60 * 60 * 24 * 28

const keyspace_schema = `CREATE KEYSPACE IF NOT EXISTS raintank WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1}  AND durable_writes = true`
const table_schema = `CREATE TABLE IF NOT EXISTS raintank.metric (
    key ascii,
    ts int,
    data blob,
    PRIMARY KEY (key, ts)
) WITH COMPACT STORAGE
    AND CLUSTERING ORDER BY (ts DESC)
    AND compaction = {'class': 'org.apache.cassandra.db.compaction.DateTieredCompactionStrategy'}
    AND compression = {'sstable_compression': 'org.apache.cassandra.io.compress.LZ4Compressor'}
    AND read_repair_chance = 0.0
    AND dclocal_read_repair_chance = 0`

/*
https://godoc.org/github.com/gocql/gocql#Session
Session is the interface used by users to interact with the database.
It's safe for concurrent use by multiple goroutines and a typical usage scenario is to have one global session
object to interact with the whole Cassandra cluster.
*/

type cassandraStore struct {
	session          *gocql.Session
	workerQueues     []chan *ChunkWriteRequest
	writeQueueMeters []met.Meter
}

func NewCassandraStore(stats met.Backend, addrs, consistency string, timeout, writers int) (*cassandraStore, error) {
	cluster := gocql.NewCluster(strings.Split(addrs, ",")...)
	cluster.Consistency = gocql.ParseConsistency(consistency)
	cluster.Timeout = time.Duration(timeout) * time.Millisecond
	cluster.NumConns = writers
	var err error
	tmpSession, err := cluster.CreateSession()
	if err != nil {
		return nil, err
	}
	// ensure the keyspace and table exist.
	err = tmpSession.Query(keyspace_schema).Exec()
	if err != nil {
		return nil, err
	}
	err = tmpSession.Query(table_schema).Exec()
	if err != nil {
		return nil, err
	}
	tmpSession.Close()
	cluster.Keyspace = "raintank"
	session, err := cluster.CreateSession()
	if err != nil {
		return nil, err
	}
	c := &cassandraStore{
		session:          session,
		workerQueues:     make([]chan *ChunkWriteRequest, *cassandraWriteConcurrency),
		writeQueueMeters: make([]met.Meter, *cassandraWriteConcurrency),
	}

	for i := 0; i < *cassandraWriteConcurrency; i++ {
		c.workerQueues[i] = make(chan *ChunkWriteRequest, *cassandraWriteQueueSize)
		c.writeQueueMeters[i] = stats.NewMeter(fmt.Sprintf("cassandra.write_queue.%d.items", i+1), 0)
		go c.processWriteQueue(c.workerQueues[i], c.writeQueueMeters[i])
	}

	return c, err
}

func (c *cassandraStore) Add(cwr *ChunkWriteRequest) {
	sum := 0
	for _, char := range cwr.key {
		sum += int(char)
	}
	which := sum % *cassandraWriteConcurrency
	c.writeQueueMeters[which].Value(int64(len(c.workerQueues[which])))
	c.workerQueues[which] <- cwr
	c.writeQueueMeters[which].Value(int64(len(c.workerQueues[which])))
}

/* process writeQueue.
 */
func (c *cassandraStore) processWriteQueue(queue chan *ChunkWriteRequest, meter met.Meter) {
	tick := time.Tick(time.Duration(1) * time.Second)
	for {
		select {
		case <-tick:
			meter.Value(int64(len(queue)))
		case cwr := <-queue:
			meter.Value(int64(len(queue)))
			log.Debug("starting to save %s:%d %v", cwr.key, cwr.chunk.T0, cwr.chunk)
			//log how long the chunk waited in the queue before we attempted to save to cassandra
			cassBlockDuration.Value(time.Now().Sub(cwr.timestamp))

			data := cwr.chunk.Series.Bytes()
			chunkSizeAtSave.Value(int64(len(data)))
			version := FormatStandardGoTsz
			buf := new(bytes.Buffer)
			err := binary.Write(buf, binary.LittleEndian, uint8(version))
			if err != nil {
				// TODO
			}
			_, err = buf.Write(data)
			if err != nil {
				// TODO
			}
			success := false
			attempts := 0
			for !success {
				err := c.insertChunk(cwr.key, cwr.chunk.T0, buf.Bytes(), int(cwr.ttl))
				if err == nil {
					success = true
					cwr.chunk.Saved = true
					SendPersistMessage(cwr.key, cwr.chunk.T0)
					log.Debug("save complete. %s:%d %v", cwr.key, cwr.chunk.T0, cwr.chunk)
					chunkSaveOk.Inc(1)
				} else {
					if (attempts % 20) == 0 {
						log.Warn("failed to save chunk to cassandra after %d attempts. %v, %s", attempts+1, cwr.chunk, err)
					}
					chunkSaveFail.Inc(1)
					sleepTime := 100 * attempts
					if sleepTime > 2000 {
						sleepTime = 2000
					}
					time.Sleep(time.Duration(sleepTime) * time.Millisecond)
					attempts++
				}
			}
		}
	}
}

// Insert Chunks into Cassandra.
//
// key: is the metric_id
// ts: is the start of the aggregated time range.
// data: is the payload as bytes.
func (c *cassandraStore) insertChunk(key string, t0 uint32, data []byte, ttl int) error {
	// for unit tests
	if c.session == nil {
		return nil
	}
	query := fmt.Sprintf("INSERT INTO metric (key, ts, data) values(?,?,?) USING TTL %d", ttl)
	row_key := fmt.Sprintf("%s_%d", key, t0/month_sec) // "month number" based on unix timestamp (rounded down)
	pre := time.Now()
	ret := c.session.Query(query, row_key, t0, data).Exec()
	cassPutDuration.Value(time.Now().Sub(pre))
	return ret
}

type outcome struct {
	month   uint32
	sortKey uint32
	i       *gocql.Iter
}
type asc []outcome

func (o asc) Len() int           { return len(o) }
func (o asc) Swap(i, j int)      { o[i], o[j] = o[j], o[i] }
func (o asc) Less(i, j int) bool { return o[i].sortKey < o[j].sortKey }

// Basic search of cassandra.
// start inclusive, end exclusive
func (c *cassandraStore) Search(key string, start, end uint32) ([]Iter, error) {
	iters := make([]Iter, 0)
	if start > end {
		return iters, fmt.Errorf("start must be before end.")
	}

	results := make(chan outcome)
	wg := &sync.WaitGroup{}

	query := func(month, sortKey uint32, q string, p ...interface{}) {
		wg.Add(1)
		go func() {
			results <- outcome{month, sortKey, c.session.Query(q, p...).Iter()}
			wg.Done()
		}()
	}

	start_month := start - (start % month_sec)       // starting row has to be at, or before, requested start
	end_month := (end - 1) - ((end - 1) % month_sec) // ending row has to be include the last point we might need

	pre := time.Now()

	// unfortunately in the database we only have the t0's of all chunks.
	// this means we can easily make sure to include the correct last chunk (just query for a t0 < end, the last chunk will contain the last needed data)
	// but it becomes hard to find which should be the first chunk to include. we can't just query for start <= t0 because than will miss some data at the beginning
	// we can't assume we know the chunkSpan so we can't just calculate the t0 >= start - <some-predefined-number> because chunkSpans may change over time.
	// we effectively need all chunks with a t0 > start, as well as the last chunk with a t0 <= start.
	// since we make sure that you can only use chunkSpans so that month_sec % chunkSpan == 0, we know that this previous chunk will always be in the same row
	// as the one that has start_month.

	row_key := fmt.Sprintf("%s_%d", key, start_month/month_sec)
	query(start_month, start_month, "SELECT ts, data FROM metric WHERE key=? AND ts <= ? Limit 1", row_key, start)

	if start_month == end_month {
		// we need a selection of the row between startTs and endTs
		row_key = fmt.Sprintf("%s_%d", key, start_month/month_sec)
		query(start_month, start_month+1, "SELECT ts, data FROM metric WHERE key = ? AND ts > ? AND ts < ? ORDER BY ts ASC", row_key, start, end)
	} else {
		// get row_keys for each row we need to query.
		for month := start_month; month <= end_month; month += month_sec {
			row_key = fmt.Sprintf("%s_%d", key, month/month_sec)
			if month == start_month {
				// we want from startTs to the end of the row.
				query(month, month+1, "SELECT ts, data FROM metric WHERE key = ? AND ts >= ? ORDER BY ts ASC", row_key, start+1)
			} else if month == end_month {
				// we want from start of the row till the endTs.
				query(month, month, "SELECT ts, data FROM metric WHERE key = ? AND ts <= ? ORDER BY ts ASC", row_key, end-1)
			} else {
				// we want all columns
				query(month, month, "SELECT ts, data FROM metric WHERE key = ? ORDER BY ts ASC", row_key)
			}
		}
	}
	outcomes := make([]outcome, 0)

	// wait for all queries to complete then close the results channel so that the following
	// for loop ends.
	go func() {
		wg.Wait()
		cassGetDuration.Value(time.Now().Sub(pre))
		close(results)
	}()
	pre = time.Now()

	for o := range results {
		outcomes = append(outcomes, o)
	}
	// we have all of the results, but they could have arrived in any order.
	sort.Sort(asc(outcomes))

	var b []byte
	var ts int
	for _, outcome := range outcomes {
		chunks := int64(0)
		for outcome.i.Scan(&ts, &b) {
			chunks += 1
			chunkSizeAtLoad.Value(int64(len(b)))
			if len(b) < 2 {
				err := errors.New("unpossibly small chunk in cassandra")
				log.Error(3, err.Error())
				return iters, err
			}
			if Format(b[0]) != FormatStandardGoTsz {
				err := errors.New("unrecognized chunk format in cassandra")
				log.Error(3, err.Error())
				return iters, err
			}
			iter, err := tsz.NewIterator(b[1:])
			if err != nil {
				log.Error(3, "failed to unpack cassandra payload. %s", err)
				return iters, err
			}
			iters = append(iters, NewIter(iter, "cassandra month=%d t0=%d", outcome.month, ts))
		}
		cassChunksPerRow.Value(chunks)
		err := outcome.i.Close()
		if err != nil {
			log.Error(3, "cassandra query error. %s", err)
		}
	}
	cassToIterDuration.Value(time.Now().Sub(pre))
	cassRowsPerResponse.Value(int64(len(outcomes)))
	log.Debug("searchCassandra(): %d outcomes (queries), %d total iters", len(outcomes), len(iters))
	return iters, nil
}

func (c *cassandraStore) Stop() {
	c.session.Close()
}
<|endoftext|>


<commit_before>package config

import (
	"testing"
)

var (
	testAppHome    = "/Users/abs/workbench/GoLang/src/github.com/metrilyx/metrilyx-dashboarder"
	testConfigFile = testAppHome + "/etc/metrilyx/metrilyx.json"
	testErrCfgFile = testAppHome + "/testdata/bad_json.json"
)

func Test_LoadConfig(t *testing.T) {

	testConfig, err := LoadConfig(testConfigFile)
	if err != nil {
		t.Errorf("FAILED: %s", err)
		t.FailNow()
	}
	t.Logf("%#v", testConfig)
}

func Test_LoadConfig_ErrorNotFound(t *testing.T) {
	_, err := LoadConfig("/not/existing/path")
	if err == nil {
		t.Fatalf("Error check failed: file existence")
	}
}

func Test_LoadConfig_ErrorBadJson(t *testing.T) {
	_, err := LoadConfig(testErrCfgFile)
	if err == nil {
		t.Fatalf("Error check failed: load error")
	}
}
<commit_msg>Test fix for configs<commit_after>package config

import (
	"path/filepath"
	"testing"
)

var (
	testConfigFile, _ = filepath.Abs("../../etc/metrilyx/metrilyx.json")
	testErrCfgFile, _ = filepath.Abs("../../testdata/bad_json.json")
)

func Test_LoadConfig(t *testing.T) {

	testConfig, err := LoadConfig(testConfigFile)
	if err != nil {
		t.Errorf("FAILED: %s", err)
		t.FailNow()
	}
	t.Logf("%#v", testConfig)
}

func Test_LoadConfig_ErrorNotFound(t *testing.T) {
	_, err := LoadConfig("/not/existing/path")
	if err == nil {
		t.Fatalf("Error check failed: file existence")
	}
}

func Test_LoadConfig_ErrorBadJson(t *testing.T) {
	_, err := LoadConfig(testErrCfgFile)
	if err == nil {
		t.Fatalf("Error check failed: load error")
	}
}
<|endoftext|>


<commit_before>// Copyright 2014 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

// Package metricsmanager contains the implementation of an api endpoint
// for calling metrics functions in state.
package metricsmanager

import (
	"github.com/juju/errors"
	"github.com/juju/loggo"
	"github.com/juju/utils/clock"
	"gopkg.in/juju/names.v2"

	"github.com/juju/juju/apiserver/common"
	"github.com/juju/juju/apiserver/facade"
	"github.com/juju/juju/apiserver/metricsender"
	"github.com/juju/juju/apiserver/params"
	"github.com/juju/juju/state"
)

var (
	logger            = loggo.GetLogger("juju.apiserver.metricsmanager")
	maxBatchesPerSend = metricsender.DefaultMaxBatchesPerSend()

	sender = metricsender.DefaultMetricSender()
)

func init() {
	common.RegisterStandardFacade("MetricsManager", 1, newMetricsManagerAPI)
}

// MetricsManager defines the methods on the metricsmanager API end point.
type MetricsManager interface {
	CleanupOldMetrics(arg params.Entities) (params.ErrorResults, error)
	SendMetrics(args params.Entities) (params.ErrorResults, error)
}

// MetricsManagerAPI implements the metrics manager interface and is the concrete
// implementation of the api end point.
type MetricsManagerAPI struct {
	state *state.State

	accessEnviron common.GetAuthFunc
	clock         clock.Clock
}

var _ MetricsManager = (*MetricsManagerAPI)(nil)

// newMetricsManagerAPI wraps NewMetricsManagerAPI for RegisterStandardFacade.
func newMetricsManagerAPI(
	st *state.State,
	resources facade.Resources,
	authorizer facade.Authorizer,
) (*MetricsManagerAPI, error) {
	return NewMetricsManagerAPI(st, resources, authorizer, clock.WallClock)
}

// NewMetricsManagerAPI creates a new API endpoint for calling metrics manager functions.
func NewMetricsManagerAPI(
	st *state.State,
	resources facade.Resources,
	authorizer facade.Authorizer,
	clock clock.Clock,
) (*MetricsManagerAPI, error) {
	if !(authorizer.AuthMachineAgent() && authorizer.AuthModelManager()) {
		return nil, common.ErrPerm
	}

	// Allow access only to the current environment.
	accessEnviron := func() (common.AuthFunc, error) {
		return func(tag names.Tag) bool {
			if tag == nil {
				return false
			}
			return tag == st.ModelTag()
		}, nil
	}

	return &MetricsManagerAPI{
		state:         st,
		accessEnviron: accessEnviron,
		clock:         clock,
	}, nil
}

// CleanupOldMetrics removes old metrics from the collection.
// The single arg params is expected to contain and environment uuid.
// Even though the call will delete all metrics across environments
// it serves to validate that the connection has access to at least one environment.
func (api *MetricsManagerAPI) CleanupOldMetrics(args params.Entities) (params.ErrorResults, error) {
	result := params.ErrorResults{
		Results: make([]params.ErrorResult, len(args.Entities)),
	}
	if len(args.Entities) == 0 {
		return result, nil
	}
	canAccess, err := api.accessEnviron()
	if err != nil {
		return result, err
	}
	for i, arg := range args.Entities {
		tag, err := names.ParseModelTag(arg.Tag)
		if err != nil {
			result.Results[i].Error = common.ServerError(common.ErrPerm)
			continue
		}
		if !canAccess(tag) {
			result.Results[i].Error = common.ServerError(common.ErrPerm)
			continue
		}
		modelState := api.state
		if tag != api.state.ModelTag() {
			modelState, err = api.state.ForModel(tag)
			if err != nil {
				err = errors.Annotatef(err, "failed to access state for %s", tag)
				result.Results[i].Error = common.ServerError(err)
				continue
			}
		}

		err = modelState.CleanupOldMetrics()
		if err != nil {
			err = errors.Annotatef(err, "failed to cleanup old metrics for %s", tag)
			result.Results[i].Error = common.ServerError(err)
		}
	}
	return result, nil
}

// SendMetrics will send any unsent metrics onto the metric collection service.
func (api *MetricsManagerAPI) SendMetrics(args params.Entities) (params.ErrorResults, error) {
	result := params.ErrorResults{
		Results: make([]params.ErrorResult, len(args.Entities)),
	}
	if len(args.Entities) == 0 {
		return result, nil
	}
	canAccess, err := api.accessEnviron()
	if err != nil {
		return result, err
	}
	for i, arg := range args.Entities {
		tag, err := names.ParseModelTag(arg.Tag)
		if err != nil {
			result.Results[i].Error = common.ServerError(err)
			continue
		}
		if !canAccess(tag) {
			result.Results[i].Error = common.ServerError(common.ErrPerm)
			continue
		}
		modelState := api.state
		if tag != api.state.ModelTag() {
			modelState, err = api.state.ForModel(tag)
			if err != nil {
				err = errors.Annotatef(err, "failed to access state for %s", tag)
				result.Results[i].Error = common.ServerError(err)
				continue
			}
		}
		txVendorMetrics, err := transmitVendorMetrics(modelState)
		if err != nil {
			result.Results[i].Error = common.ServerError(err)
			continue
		}
		err = metricsender.SendMetrics(modelState, sender, api.clock, maxBatchesPerSend, txVendorMetrics)
		if err != nil {
			err = errors.Annotatef(err, "failed to send metrics for %s", tag)
			logger.Warningf("%v", err)
			result.Results[i].Error = common.ServerError(err)
			continue
		}
	}
	return result, nil
}

func transmitVendorMetrics(st *state.State) (bool, error) {
	cfg, err := st.ModelConfig()
	if err != nil {
		return false, errors.Annotatef(err, "failed to get model config for %s", st.ModelTag())
	}
	return cfg.TransmitVendorMetrics(), nil
}
<commit_msg>Close state objects opened.<commit_after>// Copyright 2014 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

// Package metricsmanager contains the implementation of an api endpoint
// for calling metrics functions in state.
package metricsmanager

import (
	"github.com/juju/errors"
	"github.com/juju/loggo"
	"github.com/juju/utils/clock"
	"gopkg.in/juju/names.v2"

	"github.com/juju/juju/apiserver/common"
	"github.com/juju/juju/apiserver/facade"
	"github.com/juju/juju/apiserver/metricsender"
	"github.com/juju/juju/apiserver/params"
	"github.com/juju/juju/state"
)

var (
	logger            = loggo.GetLogger("juju.apiserver.metricsmanager")
	maxBatchesPerSend = metricsender.DefaultMaxBatchesPerSend()

	sender = metricsender.DefaultMetricSender()
)

func init() {
	common.RegisterStandardFacade("MetricsManager", 1, newMetricsManagerAPI)
}

// MetricsManager defines the methods on the metricsmanager API end point.
type MetricsManager interface {
	CleanupOldMetrics(arg params.Entities) (params.ErrorResults, error)
	SendMetrics(args params.Entities) (params.ErrorResults, error)
}

// MetricsManagerAPI implements the metrics manager interface and is the concrete
// implementation of the api end point.
type MetricsManagerAPI struct {
	state *state.State

	accessEnviron common.GetAuthFunc
	clock         clock.Clock
}

var _ MetricsManager = (*MetricsManagerAPI)(nil)

// newMetricsManagerAPI wraps NewMetricsManagerAPI for RegisterStandardFacade.
func newMetricsManagerAPI(
	st *state.State,
	resources facade.Resources,
	authorizer facade.Authorizer,
) (*MetricsManagerAPI, error) {
	return NewMetricsManagerAPI(st, resources, authorizer, clock.WallClock)
}

// NewMetricsManagerAPI creates a new API endpoint for calling metrics manager functions.
func NewMetricsManagerAPI(
	st *state.State,
	resources facade.Resources,
	authorizer facade.Authorizer,
	clock clock.Clock,
) (*MetricsManagerAPI, error) {
	if !(authorizer.AuthMachineAgent() && authorizer.AuthModelManager()) {
		return nil, common.ErrPerm
	}

	// Allow access only to the current environment.
	accessEnviron := func() (common.AuthFunc, error) {
		return func(tag names.Tag) bool {
			if tag == nil {
				return false
			}
			return tag == st.ModelTag()
		}, nil
	}

	return &MetricsManagerAPI{
		state:         st,
		accessEnviron: accessEnviron,
		clock:         clock,
	}, nil
}

// CleanupOldMetrics removes old metrics from the collection.
// The single arg params is expected to contain and environment uuid.
// Even though the call will delete all metrics across environments
// it serves to validate that the connection has access to at least one environment.
func (api *MetricsManagerAPI) CleanupOldMetrics(args params.Entities) (params.ErrorResults, error) {
	result := params.ErrorResults{
		Results: make([]params.ErrorResult, len(args.Entities)),
	}
	if len(args.Entities) == 0 {
		return result, nil
	}
	canAccess, err := api.accessEnviron()
	if err != nil {
		return result, err
	}
	for i, arg := range args.Entities {
		tag, err := names.ParseModelTag(arg.Tag)
		if err != nil {
			result.Results[i].Error = common.ServerError(common.ErrPerm)
			continue
		}
		if !canAccess(tag) {
			result.Results[i].Error = common.ServerError(common.ErrPerm)
			continue
		}
		modelState := api.state
		if tag != api.state.ModelTag() {
			modelState, err = api.state.ForModel(tag)
			if err != nil {
				err = errors.Annotatef(err, "failed to access state for %s", tag)
				result.Results[i].Error = common.ServerError(err)
				continue
			}
			defer modelState.Close()
		}

		err = modelState.CleanupOldMetrics()
		if err != nil {
			err = errors.Annotatef(err, "failed to cleanup old metrics for %s", tag)
			result.Results[i].Error = common.ServerError(err)
		}
	}
	return result, nil
}

// SendMetrics will send any unsent metrics onto the metric collection service.
func (api *MetricsManagerAPI) SendMetrics(args params.Entities) (params.ErrorResults, error) {
	result := params.ErrorResults{
		Results: make([]params.ErrorResult, len(args.Entities)),
	}
	if len(args.Entities) == 0 {
		return result, nil
	}
	canAccess, err := api.accessEnviron()
	if err != nil {
		return result, err
	}
	for i, arg := range args.Entities {
		tag, err := names.ParseModelTag(arg.Tag)
		if err != nil {
			result.Results[i].Error = common.ServerError(err)
			continue
		}
		if !canAccess(tag) {
			result.Results[i].Error = common.ServerError(common.ErrPerm)
			continue
		}
		modelState := api.state
		if tag != api.state.ModelTag() {
			modelState, err = api.state.ForModel(tag)
			if err != nil {
				err = errors.Annotatef(err, "failed to access state for %s", tag)
				result.Results[i].Error = common.ServerError(err)
				continue
			}
			defer modelState.Close()
		}
		txVendorMetrics, err := transmitVendorMetrics(modelState)
		if err != nil {
			result.Results[i].Error = common.ServerError(err)
			continue
		}
		err = metricsender.SendMetrics(modelState, sender, api.clock, maxBatchesPerSend, txVendorMetrics)
		if err != nil {
			err = errors.Annotatef(err, "failed to send metrics for %s", tag)
			logger.Warningf("%v", err)
			result.Results[i].Error = common.ServerError(err)
			continue
		}
	}
	return result, nil
}

func transmitVendorMetrics(st *state.State) (bool, error) {
	cfg, err := st.ModelConfig()
	if err != nil {
		return false, errors.Annotatef(err, "failed to get model config for %s", st.ModelTag())
	}
	return cfg.TransmitVendorMetrics(), nil
}
<|endoftext|>


<commit_before>// +build !fasthttp

package gateway

import (
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	glog "log"
	"net/http"
	"net/http/httptest"
	"os"
	"strconv"
	"strings"
	"sync"
	"testing"
	"time"

	"github.com/funkygao/gafka"
	"github.com/funkygao/gafka/cmd/kateway/meta"
	"github.com/funkygao/gafka/cmd/kateway/meta/zkmeta"
	"github.com/funkygao/gafka/cmd/kateway/store"
	"github.com/funkygao/gafka/cmd/kateway/store/kafka"
	"github.com/funkygao/gafka/ctx"
	"github.com/funkygao/gafka/mpool"
	"github.com/funkygao/gafka/zk"
	"github.com/funkygao/httprouter"
	log "github.com/funkygao/log4go"
	"github.com/gorilla/mux"
)

type neverEnding byte

var gw *Gateway

func init() {
	gafka.BuildId = "test"
	log.AddFilter("stdout", log.ERROR, log.NewConsoleLogWriter())
}

func (b neverEnding) Read(p []byte) (n int, err error) {
	if len(p) < 16 {
		for i := range p {
			p[i] = byte(b)
		}
	} else {
		b.Read(p[:len(p)/2])
		copy(p[len(p)/2:], p)
	}
	return len(p), nil
}

func BenchmarkNeverending(b *testing.B) {
	buf := make([]byte, 4096)
	A := neverEnding('A')
	for i := 0; i < b.N; i++ {
		A.Read(buf)
	}
}

func BenchmarkStrconvItoa(b *testing.B) {
	for i := 0; i < b.N; i++ {
		strconv.Itoa(100000)
	}
}

func newGatewayForTest(b *testing.B, store string) *Gateway {
	Options.Zone = "local"
	Options.PubHttpAddr = ":9191"
	Options.SubHttpAddr = ":9192"
	Options.Store = store
	Options.PubPoolCapcity = 100
	Options.Debug = false
	Options.ManagerStore = "dummy"
	Options.DummyCluster = "me"
	Options.DisableMetrics = false
	Options.MaxPubSize = 1 << 20
	Options.MetaRefresh = time.Hour

	ctx.LoadFromHome()

	gw := New("1")
	if err := gw.Start(); err != nil {
		b.Fatal(err)
	}

	return gw
}

func runBenchmarkPub(b *testing.B, store string, msgSize int64) {
	if gw == nil {
		gw = newGatewayForTest(b, store)
	}

	b.ReportAllocs()

	req, err := mockHttpRequest()
	if err != nil {
		b.Fatal(err)
	}

	rw := httptest.NewRecorder()
	lr := io.LimitReader(neverEnding('a'), msgSize)
	body := ioutil.NopCloser(lr)

	param := httprouter.Params{
		httprouter.Param{Key: "topic", Value: "foobar"},
		httprouter.Param{Key: "ver", Value: "v1"},
	}

	for i := 0; i < b.N; i++ {
		rw.Body.Reset()
		lr.(*io.LimitedReader).N = msgSize
		req.Body = body
		gw.pubServer.pubHandler(rw, req, param)
	}
}

func BenchmarkDirectKafkaProduce1K(b *testing.B) {
	msgSize := 1 << 10
	b.ReportAllocs()
	b.SetBytes(int64(msgSize))

	ctx.LoadFromHome()

	cf := zkmeta.DefaultConfig()
	zkzone := zk.NewZkZone(zk.DefaultConfig("local", ctx.ZoneZkAddrs("local")))
	cf.Refresh = time.Hour
	meta.Default = zkmeta.New(cf, zkzone)
	meta.Default.Start()
	var wg sync.WaitGroup
	store.DefaultPubStore = kafka.NewPubStore(100, 0, false, &wg, false, true)
	store.DefaultPubStore.Start()

	data := []byte(strings.Repeat("X", msgSize))
	for i := 0; i < b.N; i++ {
		store.DefaultPubStore.SyncPub("me", "foobar", nil, data)
	}
}

func BenchmarkKatewayPubKafka1K(b *testing.B) {
	runBenchmarkPub(b, "kafka", 1<<10)
}

func BenchmarkKatewayPubDummy1K(b *testing.B) {
	runBenchmarkPub(b, "dummy", 1<<10)
}

func BenchmarkGorillaMux(b *testing.B) {
	b.Skip("skip for now")

	router := mux.NewRouter()
	handler := func(w http.ResponseWriter, r *http.Request) {}
	router.HandleFunc("/topics/{topic}/{ver}", handler)
	router.HandleFunc("/ws/topics/{topic}/{ver}", handler)
	router.HandleFunc("/ver", handler)
	router.HandleFunc("/help", handler)
	router.HandleFunc("/stat", handler)
	router.HandleFunc("/ping", handler)
	router.HandleFunc("/clusters", handler)

	request, _ := http.NewRequest("GET", "/topics/anything/v1", nil)
	for i := 0; i < b.N; i++ {
		router.ServeHTTP(nil, request)
	}
}

func BenchmarkHttpRouter(b *testing.B) {
	b.Skip("skip for now")

	router := httprouter.New()
	handler := func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {}
	router.POST("/topics/:topic/:ver", handler)
	router.POST("/ws/topics/:topic/:ver", handler)
	router.GET("/ver", handler)
	router.GET("/help", handler)
	router.GET("/stat", handler)
	router.GET("/ping", handler)
	router.GET("/clusters", handler)

	request, _ := http.NewRequest("POST", "/topics/anything/v1", nil)
	for i := 0; i < b.N; i++ {
		router.ServeHTTP(nil, request)
	}
}

func BenchmxarkPubJsonResponse(b *testing.B) {
	type pubResponse struct {
		Partition int32 `json:"partition"`
		Offset    int64 `json:"offset"`
	}

	response := pubResponse{
		Partition: 5,
		Offset:    32,
	}
	for i := 0; i < b.N; i++ {
		json.Marshal(response)
	}
}

func BenchmarkPubManualJsonResponse(b *testing.B) {
	for i := 0; i < b.N; i++ {
		_ = fmt.Sprintf(`{"partition":%d,"offset:%d"}`, 5, 32)
	}
}

func BenchmarkManualCreateJson(b *testing.B) {
	for i := 0; i < b.N; i++ {
		buffer := mpool.BytesBufferGet()

		buffer.Reset()
		buffer.WriteString(`{"partition":`)
		buffer.WriteString(strconv.Itoa(int(6)))
		buffer.WriteString(`,"offset":`)
		buffer.WriteString(strconv.Itoa(int(7)))
		buffer.WriteString(`}`)

		mpool.BytesBufferPut(buffer)
	}
}

// 1k log line
// on the vm, go1.5
// 12614 ns/op	81.18 MB/s	3680 B/op  5 allocs/op
// 85k line/second
// on the physical server, go1.4
// 9944 ns/op	102.97 MB/ 3714 B/op   7 allocs/op
// 100k line/second
//
// 0.5k log line
// on the vm, go1.5
// 8111 ns/op	61.64 MB/s	 528 B/op  2 allocs/op
// 135k line/second
// on the physical server, go1.4
// 4677 ns/op	106.89 MB/s	 547 B/op  4 allocs/op
// 200k line/second
func BenchmarkLogAppend(b *testing.B) {
	sz := 1 << 10
	line := strings.Repeat("X", sz)
	f, err := os.OpenFile("log.log", os.O_CREATE|os.O_APPEND|os.O_RDWR, 0666)
	if err != nil {
		panic(err)
	}

	l := glog.New(f, "", glog.LstdFlags)
	for i := 0; i < b.N; i++ {
		l.Println(line)
	}
	b.SetBytes(int64(sz))
	os.Remove("log.log")
}
<commit_msg>suppress the err log during benchmark<commit_after>// +build !fasthttp

package gateway

import (
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	glog "log"
	"net/http"
	"net/http/httptest"
	"os"
	"strconv"
	"strings"
	"sync"
	"testing"
	"time"

	"github.com/funkygao/gafka"
	"github.com/funkygao/gafka/cmd/kateway/meta"
	"github.com/funkygao/gafka/cmd/kateway/meta/zkmeta"
	"github.com/funkygao/gafka/cmd/kateway/store"
	"github.com/funkygao/gafka/cmd/kateway/store/kafka"
	"github.com/funkygao/gafka/ctx"
	"github.com/funkygao/gafka/mpool"
	"github.com/funkygao/gafka/zk"
	"github.com/funkygao/httprouter"
	log "github.com/funkygao/log4go"
	"github.com/gorilla/mux"
)

type neverEnding byte

var gw *Gateway

func init() {
	gafka.BuildId = "test"
	log.AddFilter("stdout", log.ERROR, log.NewConsoleLogWriter())
}

func (b neverEnding) Read(p []byte) (n int, err error) {
	if len(p) < 16 {
		for i := range p {
			p[i] = byte(b)
		}
	} else {
		b.Read(p[:len(p)/2])
		copy(p[len(p)/2:], p)
	}
	return len(p), nil
}

func BenchmarkNeverending(b *testing.B) {
	buf := make([]byte, 4096)
	A := neverEnding('A')
	for i := 0; i < b.N; i++ {
		A.Read(buf)
	}
}

func BenchmarkStrconvItoa(b *testing.B) {
	for i := 0; i < b.N; i++ {
		strconv.Itoa(100000)
	}
}

func newGatewayForTest(b *testing.B, store string) *Gateway {
	Options.Zone = "local"
	Options.PubHttpAddr = ":9191"
	Options.SubHttpAddr = ":9192"
	Options.Store = store
	Options.PubPoolCapcity = 100
	Options.Debug = false
	Options.ManagerStore = "dummy"
	Options.DummyCluster = "me"
	Options.DisableMetrics = false
	Options.MaxPubSize = 1 << 20
	Options.MetaRefresh = time.Hour
	Options.ReporterInterval = time.Hour
	Options.InfluxServer = "none"
	Options.InfluxDbName = "none"

	ctx.LoadFromHome()

	gw := New("1")
	if err := gw.Start(); err != nil {
		b.Fatal(err)
	}

	return gw
}

func runBenchmarkPub(b *testing.B, store string, msgSize int64) {
	if gw == nil {
		gw = newGatewayForTest(b, store)
	}

	b.ReportAllocs()

	req, err := mockHttpRequest()
	if err != nil {
		b.Fatal(err)
	}

	rw := httptest.NewRecorder()
	lr := io.LimitReader(neverEnding('a'), msgSize)
	body := ioutil.NopCloser(lr)

	param := httprouter.Params{
		httprouter.Param{Key: "topic", Value: "foobar"},
		httprouter.Param{Key: "ver", Value: "v1"},
	}

	for i := 0; i < b.N; i++ {
		rw.Body.Reset()
		lr.(*io.LimitedReader).N = msgSize
		req.Body = body
		gw.pubServer.pubHandler(rw, req, param)
	}
}

func BenchmarkDirectKafkaProduce1K(b *testing.B) {
	msgSize := 1 << 10
	b.ReportAllocs()
	b.SetBytes(int64(msgSize))

	ctx.LoadFromHome()

	cf := zkmeta.DefaultConfig()
	zkzone := zk.NewZkZone(zk.DefaultConfig("local", ctx.ZoneZkAddrs("local")))
	cf.Refresh = time.Hour
	meta.Default = zkmeta.New(cf, zkzone)
	meta.Default.Start()
	var wg sync.WaitGroup
	store.DefaultPubStore = kafka.NewPubStore(100, 0, false, &wg, false, true)
	store.DefaultPubStore.Start()

	data := []byte(strings.Repeat("X", msgSize))
	for i := 0; i < b.N; i++ {
		store.DefaultPubStore.SyncPub("me", "foobar", nil, data)
	}
}

func BenchmarkKatewayPubKafka1K(b *testing.B) {
	runBenchmarkPub(b, "kafka", 1<<10)
}

func BenchmarkKatewayPubDummy1K(b *testing.B) {
	runBenchmarkPub(b, "dummy", 1<<10)
}

func BenchmarkGorillaMux(b *testing.B) {
	b.Skip("skip for now")

	router := mux.NewRouter()
	handler := func(w http.ResponseWriter, r *http.Request) {}
	router.HandleFunc("/topics/{topic}/{ver}", handler)
	router.HandleFunc("/ws/topics/{topic}/{ver}", handler)
	router.HandleFunc("/ver", handler)
	router.HandleFunc("/help", handler)
	router.HandleFunc("/stat", handler)
	router.HandleFunc("/ping", handler)
	router.HandleFunc("/clusters", handler)

	request, _ := http.NewRequest("GET", "/topics/anything/v1", nil)
	for i := 0; i < b.N; i++ {
		router.ServeHTTP(nil, request)
	}
}

func BenchmarkHttpRouter(b *testing.B) {
	b.Skip("skip for now")

	router := httprouter.New()
	handler := func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {}
	router.POST("/topics/:topic/:ver", handler)
	router.POST("/ws/topics/:topic/:ver", handler)
	router.GET("/ver", handler)
	router.GET("/help", handler)
	router.GET("/stat", handler)
	router.GET("/ping", handler)
	router.GET("/clusters", handler)

	request, _ := http.NewRequest("POST", "/topics/anything/v1", nil)
	for i := 0; i < b.N; i++ {
		router.ServeHTTP(nil, request)
	}
}

func BenchmxarkPubJsonResponse(b *testing.B) {
	type pubResponse struct {
		Partition int32 `json:"partition"`
		Offset    int64 `json:"offset"`
	}

	response := pubResponse{
		Partition: 5,
		Offset:    32,
	}
	for i := 0; i < b.N; i++ {
		json.Marshal(response)
	}
}

func BenchmarkPubManualJsonResponse(b *testing.B) {
	for i := 0; i < b.N; i++ {
		_ = fmt.Sprintf(`{"partition":%d,"offset:%d"}`, 5, 32)
	}
}

func BenchmarkManualCreateJson(b *testing.B) {
	for i := 0; i < b.N; i++ {
		buffer := mpool.BytesBufferGet()

		buffer.Reset()
		buffer.WriteString(`{"partition":`)
		buffer.WriteString(strconv.Itoa(int(6)))
		buffer.WriteString(`,"offset":`)
		buffer.WriteString(strconv.Itoa(int(7)))
		buffer.WriteString(`}`)

		mpool.BytesBufferPut(buffer)
	}
}

// 1k log line
// on the vm, go1.5
// 12614 ns/op	81.18 MB/s	3680 B/op  5 allocs/op
// 85k line/second
// on the physical server, go1.4
// 9944 ns/op	102.97 MB/ 3714 B/op   7 allocs/op
// 100k line/second
//
// 0.5k log line
// on the vm, go1.5
// 8111 ns/op	61.64 MB/s	 528 B/op  2 allocs/op
// 135k line/second
// on the physical server, go1.4
// 4677 ns/op	106.89 MB/s	 547 B/op  4 allocs/op
// 200k line/second
func BenchmarkLogAppend(b *testing.B) {
	sz := 1 << 10
	line := strings.Repeat("X", sz)
	f, err := os.OpenFile("log.log", os.O_CREATE|os.O_APPEND|os.O_RDWR, 0666)
	if err != nil {
		panic(err)
	}

	l := glog.New(f, "", glog.LstdFlags)
	for i := 0; i < b.N; i++ {
		l.Println(line)
	}
	b.SetBytes(int64(sz))
	os.Remove("log.log")
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"strconv"

	"github.com/spf13/cobra"
	"k8s.io/kops/upup/pkg/fi/cloudup"
	"k8s.io/kops/upup/pkg/kutil"
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/api/v1"
	"k8s.io/kubernetes/pkg/client/clientset_generated/release_1_3"
	"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
)

type RollingUpdateClusterCmd struct {
	Yes   bool
	Force bool

	cobraCommand *cobra.Command
}

var rollingupdateCluster = RollingUpdateClusterCmd{
	cobraCommand: &cobra.Command{
		Use:   "cluster",
		Short: "rolling-update cluster",
		Long:  `rolling-updates a k8s cluster.`,
	},
}

func init() {
	cmd := rollingupdateCluster.cobraCommand
	rollingUpdateCommand.cobraCommand.AddCommand(cmd)

	cmd.Flags().BoolVar(&rollingupdateCluster.Yes, "yes", false, "perform rolling update without confirmation")
	cmd.Flags().BoolVar(&rollingupdateCluster.Force, "force", false, "Force rolling update, even if no changes")

	cmd.Run = func(cmd *cobra.Command, args []string) {
		err := rollingupdateCluster.Run(args)
		if err != nil {
			exitWithError(err)
		}
	}
}

func (c *RollingUpdateClusterCmd) Run(args []string) error {
	err := rootCommand.ProcessArgs(args)
	if err != nil {
		return err
	}

	_, cluster, err := rootCommand.Cluster()
	if err != nil {
		return err
	}

	contextName := cluster.Name
	config, err := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(
		clientcmd.NewDefaultClientConfigLoadingRules(),
		&clientcmd.ConfigOverrides{CurrentContext: contextName}).ClientConfig()
	if err != nil {
		return fmt.Errorf("cannot load kubecfg settings for %q: %v", contextName, err)
	}

	k8sClient, err := release_1_3.NewForConfig(config)
	if err != nil {
		return fmt.Errorf("cannot build kube client for %q: %v", contextName, err)
	}

	nodes, err := k8sClient.Core().Nodes().List(api.ListOptions{})
	if err != nil {
		return fmt.Errorf("error listing nodes in cluster: %v", err)
	}

	instanceGroupRegistry, err := rootCommand.InstanceGroupRegistry()
	if err != nil {
		return err
	}

	instancegroups, err := instanceGroupRegistry.ReadAll()
	if err != nil {
		return err
	}

	cloud, err := cloudup.BuildCloud(cluster)
	if err != nil {
		return err
	}

	d := &kutil.RollingUpdateCluster{}
	d.Cloud = cloud

	warnUnmatched := true
	groups, err := kutil.FindCloudInstanceGroups(cloud, cluster, instancegroups, warnUnmatched, nodes.Items)
	if err != nil {
		return err
	}

	{
		t := &Table{}
		t.AddColumn("NAME", func(r *kutil.CloudInstanceGroup) string {
			return r.InstanceGroup.Name
		})
		t.AddColumn("STATUS", func(r *kutil.CloudInstanceGroup) string {
			return r.Status
		})
		t.AddColumn("NEEDUPDATE", func(r *kutil.CloudInstanceGroup) string {
			return strconv.Itoa(len(r.NeedUpdate))
		})
		t.AddColumn("READY", func(r *kutil.CloudInstanceGroup) string {
			return strconv.Itoa(len(r.Ready))
		})
		t.AddColumn("MIN", func(r *kutil.CloudInstanceGroup) string {
			return strconv.Itoa(r.MinSize())
		})
		t.AddColumn("MAX", func(r *kutil.CloudInstanceGroup) string {
			return strconv.Itoa(r.MaxSize())
		})
		t.AddColumn("NODES", func(r *kutil.CloudInstanceGroup) string {
			var nodes []*v1.Node
			for _, i := range r.Ready {
				if i.Node != nil {
					nodes = append(nodes, i.Node)
				}
			}
			for _, i := range r.NeedUpdate {
				if i.Node != nil {
					nodes = append(nodes, i.Node)
				}
			}
			return strconv.Itoa(len(nodes))
		})
		var l []*kutil.CloudInstanceGroup
		for _, v := range groups {
			l = append(l, v)
		}

		err := t.Render(l, os.Stdout, "NAME", "STATUS", "NEEDUPDATE", "READY", "MIN", "MAX", "NODES")
		if err != nil {
			return err
		}
	}

	needUpdate := false
	for _, group := range groups {
		if len(group.NeedUpdate) != 0 {
			needUpdate = true
		}
	}

	if !needUpdate && !c.Force {
		fmt.Printf("\nNo rolling-update required\n")
		return nil
	}

	if !c.Yes {
		fmt.Printf("\nMust specify --yes to rolling-update\n")
		return nil
	}

	return d.RollingUpdate(groups, c.Force, k8sClient)
}
<commit_msg>If the API is down in a rolling-update, support --cloudonly<commit_after>package main

import (
	"fmt"
	"os"
	"strconv"

	"github.com/spf13/cobra"
	"k8s.io/kops/upup/pkg/fi/cloudup"
	"k8s.io/kops/upup/pkg/kutil"
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/api/v1"
	"k8s.io/kubernetes/pkg/client/clientset_generated/release_1_3"
	"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
)

type RollingUpdateClusterCmd struct {
	Yes       bool
	Force     bool
	CloudOnly bool

	cobraCommand *cobra.Command
}

var rollingupdateCluster = RollingUpdateClusterCmd{
	cobraCommand: &cobra.Command{
		Use:   "cluster",
		Short: "rolling-update cluster",
		Long:  `rolling-updates a k8s cluster.`,
	},
}

func init() {
	cmd := rollingupdateCluster.cobraCommand
	rollingUpdateCommand.cobraCommand.AddCommand(cmd)

	cmd.Flags().BoolVar(&rollingupdateCluster.Yes, "yes", false, "perform rolling update without confirmation")
	cmd.Flags().BoolVar(&rollingupdateCluster.Force, "force", false, "Force rolling update, even if no changes")
	cmd.Flags().BoolVar(&rollingupdateCluster.CloudOnly, "cloudonly", false, "Perform rolling update without confirming progress with k8s")

	cmd.Run = func(cmd *cobra.Command, args []string) {
		err := rollingupdateCluster.Run(args)
		if err != nil {
			exitWithError(err)
		}
	}
}

func (c *RollingUpdateClusterCmd) Run(args []string) error {
	err := rootCommand.ProcessArgs(args)
	if err != nil {
		return err
	}

	_, cluster, err := rootCommand.Cluster()
	if err != nil {
		return err
	}

	contextName := cluster.Name
	config, err := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(
		clientcmd.NewDefaultClientConfigLoadingRules(),
		&clientcmd.ConfigOverrides{CurrentContext: contextName}).ClientConfig()
	if err != nil {
		return fmt.Errorf("cannot load kubecfg settings for %q: %v", contextName, err)
	}

	var nodes []v1.Node
	var k8sClient *release_1_3.Clientset
	if !c.CloudOnly {
		k8sClient, err = release_1_3.NewForConfig(config)
		if err != nil {
			return fmt.Errorf("cannot build kube client for %q: %v", contextName, err)
		}

		nodeList, err := k8sClient.Core().Nodes().List(api.ListOptions{})
		if err != nil {
			fmt.Fprintf(os.Stderr, "Unable to reach the kubernetes API.\n")
			fmt.Fprintf(os.Stderr, "Use --cloudonly to do a rolling-update without confirming progress with the k8s API\n\n")
			return fmt.Errorf("error listing nodes in cluster: %v", err)
		}

		if nodeList != nil {
			nodes = nodeList.Items
		}
	}

	instanceGroupRegistry, err := rootCommand.InstanceGroupRegistry()
	if err != nil {
		return err
	}

	instancegroups, err := instanceGroupRegistry.ReadAll()
	if err != nil {
		return err
	}

	cloud, err := cloudup.BuildCloud(cluster)
	if err != nil {
		return err
	}

	d := &kutil.RollingUpdateCluster{}
	d.Cloud = cloud

	warnUnmatched := true
	groups, err := kutil.FindCloudInstanceGroups(cloud, cluster, instancegroups, warnUnmatched, nodes)
	if err != nil {
		return err
	}

	{
		t := &Table{}
		t.AddColumn("NAME", func(r *kutil.CloudInstanceGroup) string {
			return r.InstanceGroup.Name
		})
		t.AddColumn("STATUS", func(r *kutil.CloudInstanceGroup) string {
			return r.Status
		})
		t.AddColumn("NEEDUPDATE", func(r *kutil.CloudInstanceGroup) string {
			return strconv.Itoa(len(r.NeedUpdate))
		})
		t.AddColumn("READY", func(r *kutil.CloudInstanceGroup) string {
			return strconv.Itoa(len(r.Ready))
		})
		t.AddColumn("MIN", func(r *kutil.CloudInstanceGroup) string {
			return strconv.Itoa(r.MinSize())
		})
		t.AddColumn("MAX", func(r *kutil.CloudInstanceGroup) string {
			return strconv.Itoa(r.MaxSize())
		})
		t.AddColumn("NODES", func(r *kutil.CloudInstanceGroup) string {
			var nodes []*v1.Node
			for _, i := range r.Ready {
				if i.Node != nil {
					nodes = append(nodes, i.Node)
				}
			}
			for _, i := range r.NeedUpdate {
				if i.Node != nil {
					nodes = append(nodes, i.Node)
				}
			}
			return strconv.Itoa(len(nodes))
		})
		var l []*kutil.CloudInstanceGroup
		for _, v := range groups {
			l = append(l, v)
		}

		columns := []string{"NAME", "STATUS", "NEEDUPDATE", "READY", "MIN", "MAX"}
		if !c.CloudOnly {
			columns = append(columns, "NODES")
		}
		err := t.Render(l, os.Stdout, columns...)
		if err != nil {
			return err
		}
	}

	needUpdate := false
	for _, group := range groups {
		if len(group.NeedUpdate) != 0 {
			needUpdate = true
		}
	}

	if !needUpdate && !c.Force {
		fmt.Printf("\nNo rolling-update required\n")
		return nil
	}

	if !c.Yes {
		fmt.Printf("\nMust specify --yes to rolling-update\n")
		return nil
	}

	return d.RollingUpdate(groups, c.Force, k8sClient)
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Skaffold Authors

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

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

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

package cmd

import (
	"io/ioutil"
	"os"
	"path/filepath"
	"testing"

	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema"

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

func TestInit(t *testing.T) {
	tests := []struct {
		name string
		dir  string
		args []string
	}{
		//TODO: mocked kompose test
		{
			name: "getting-started",
			dir:  "testdata/init/hello",
		},
		{
			name: "ignore existing tags",
			dir:  "testdata/init/ignore-tags",
		},
		{
			name: "microservices (backwards compatibility)",
			dir:  "testdata/init/microservices",
			args: []string{
				"-a", `leeroy-app/Dockerfile=gcr.io/k8s-skaffold/leeroy-app`,
				"-a", `leeroy-web/Dockerfile=gcr.io/k8s-skaffold/leeroy-web`,
			},
		},
		{
			name: "microservices",
			dir:  "testdata/init/microservices",
			args: []string{
				"-a", `{"builder":"Docker","payload":{"path":"leeroy-app/Dockerfile"},"image":"gcr.io/k8s-skaffold/leeroy-app"}`,
				"-a", `{"builder":"Docker","payload":{"path":"leeroy-web/Dockerfile"},"image":"gcr.io/k8s-skaffold/leeroy-web"}`,
			},
		},
	}
	for _, test := range tests {

		testutil.Run(t, test.name, func(t *testutil.T) {
			config := "skaffold.yaml.out"
			initArgs := append([]string{"init", "--force", "-f", config}, test.args...)
			os.Args = initArgs
			wd, _ := os.Getwd()
			os.Chdir(test.dir)
			defer os.Chdir(wd)
			init := NewCmdInit()
			if err := init.Execute(); err != nil {
				t.Fail()
			}
			checkGeneratedConfig(t, ".")

			// Make sure the skaffold yaml can be parsed
			_, err := schema.ParseConfig(config, false)
			t.CheckError(false, err)
		})
	}
}

func checkGeneratedConfig(t *testutil.T, dir string) {
	expectedOutput, err := ioutil.ReadFile(filepath.Join(dir, "skaffold.yaml"))
	t.CheckNoError(err)

	output, err := ioutil.ReadFile(filepath.Join(dir, "skaffold.yaml.out"))
	t.CheckNoError(err)
	t.CheckDeepEqual(string(expectedOutput), string(output))
}
<commit_msg>fix windows init_test<commit_after>/*
Copyright 2019 The Skaffold Authors

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

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

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

package cmd

import (
	"os"
	"path/filepath"
	"testing"

	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema"
	"github.com/GoogleContainerTools/skaffold/testutil"
)

func TestInit(t *testing.T) {
	tests := []struct {
		name string
		dir  string
		args []string
	}{
		//TODO: mocked kompose test
		{
			name: "getting-started",
			dir:  "testdata/init/hello",
		},
		{
			name: "ignore existing tags",
			dir:  "testdata/init/ignore-tags",
		},
		{
			name: "microservices (backwards compatibility)",
			dir:  "testdata/init/microservices",
			args: []string{
				"-a", `leeroy-app/Dockerfile=gcr.io/k8s-skaffold/leeroy-app`,
				"-a", `leeroy-web/Dockerfile=gcr.io/k8s-skaffold/leeroy-web`,
			},
		},
		{
			name: "microservices",
			dir:  "testdata/init/microservices",
			args: []string{
				"-a", `{"builder":"Docker","payload":{"path":"leeroy-app/Dockerfile"},"image":"gcr.io/k8s-skaffold/leeroy-app"}`,
				"-a", `{"builder":"Docker","payload":{"path":"leeroy-web/Dockerfile"},"image":"gcr.io/k8s-skaffold/leeroy-web"}`,
			},
		},
	}
	for _, test := range tests {
		testutil.Run(t, test.name, func(t *testutil.T) {
			config := "skaffold.yaml.out"
			initArgs := append([]string{"init", "--force", "-f", config}, test.args...)
			os.Args = initArgs
			wd, _ := os.Getwd()
			os.Chdir(test.dir)
			defer os.Chdir(wd)
			init := NewCmdInit()
			if err := init.Execute(); err != nil {
				t.Fail()
			}
			checkGeneratedConfig(t, ".")
		})
	}
}

func checkGeneratedConfig(t *testutil.T, dir string) {
	expectedOutput, err := schema.ParseConfig(filepath.Join(dir, "skaffold.yaml"), false)
	t.CheckNoError(err)

	output, err := schema.ParseConfig(filepath.Join(dir, "skaffold.yaml.out"), false)
	t.CheckNoError(err)
	t.CheckDeepEqual(expectedOutput, output)
}
<|endoftext|>


<commit_before>package siri

import (
	"bytes"
	"fmt"
	"text/template"
	"time"

	"github.com/jbowtie/gokogiri"
	"github.com/jbowtie/gokogiri/xml"
)

type XMLGeneralMessageResponse struct {
	ResponseXMLStructure

	xmlGeneralMessages []*XMLGeneralMessage
}

type XMLGeneralMessage struct {
	XMLStructure

	recordedAtTime        time.Time
	validUntilTime        time.Time
	itemIdentifier        string
	infoMessageIdentifier string
	infoChannelRef        string
	formatRef             string
	infoMessageVersion    int
	numberOfLines         int
	numberOfCharPerLine   int
	content               interface{}
}

type IDFGeneralMessageStructure struct {
	XMLStructure

	messages          []*XMLMessage
	lineRef           string
	stopPointRef      string
	journeyPatternRef string
	destinationRef    string
	routeRef          string
	format            string
	groupOfLinesRef   string
	lineSection       IDFLineSectionStructure
}

type XMLMessage struct {
	XMLStructure

	messageText         string
	messageType         string
	numberOfLines       int
	numberOfCharPerLine int
}

type IDFLineSectionStructure struct {
	XMLStructure

	firstStop string
	lastStop  string
	lineRef   string
}

type SIRIGeneralMessageResponse struct {
	SIRIGeneralMessageDelivery

	Address                   string
	ProducerRef               string
	ResponseMessageIdentifier string
}

type SIRIGeneralMessageDelivery struct {
	RequestMessageRef string
	Status            bool
	ErrorType         string
	ErrorNumber       int
	ErrorText         string
	ResponseTimestamp time.Time

	GeneralMessages []*SIRIGeneralMessage
}

type SIRIGeneralMessage struct {
	RecordedAtTime        time.Time
	ValidUntilTime        time.Time
	ItemIdentifier        string
	InfoMessageIdentifier string
	FormatRef             string
	InfoMessageVersion    int64
	InfoChannelRef        string

	LineRefContent    string
	StopPointRef      string
	JourneyPatternRef string
	DestinationRef    string
	RouteRef          string
	GroupOfLinesRef   string

	Messages []*SIRIMessage

	FirstStop string
	LastStop  string
	LineRef   string
}

type SIRIMessage struct {
	Content             string
	Type                string
	NumberOfLines       int
	NumberOfCharPerLine int
}

const generalMessageTemplate = `<ns3:GeneralMessageDelivery version="2.0:FR-IDF-2.4">
				  <ns3:ResponseTimestamp>{{ .ResponseTimestamp.Format "2006-01-02T15:04:05.000Z07:00" }}</ns3:ResponseTimestamp>
					<ns3:Status>{{.Status}}</ns3:Status>{{range .GeneralMessages}}
					<ns3:GeneralMessage>
						<ns3:RecordedAtTime>{{ .RecordedAtTime.Format "2006-01-02T15:04:05.000Z07:00" }}</ns3:RecordedAtTime>
						<ns3:InfoMessageIdentifier>{{.InfoMessageIdentifier}}</ns3:InfoMessageIdentifier>
						<ns3:InfoMessageVersion>{{.InfoMessageVersion}}</ns3:InfoMessageVersion>
						<ns3:formatRef>{{ .FormatRef }}</ns3:formatRef>
						<ns3:InfoChannelRef>{{.InfoChannelRef}}</ns3:InfoChannelRef>
						<ns3:ValidUntilTime>{{ .ValidUntilTime.Format "2006-01-02T15:04:05.000Z07:00" }}</ns3:ValidUntilTime>
						<ns3:Content xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
						xsi:type="ns9:IDFLineSectionStructure">{{range .Messages}}
							<Message>{{if .Type}}
								<MessageType>{{ .Type }}</MessageType>{{end}}{{if .Content}}
								<MessageText>{{ .Content }}</MessageText>{{end}}{{if .NumberOfLines}}
								<NumberOfLines>{{ .NumberOfLines }}</NumberOfLines>{{end}}{{if .NumberOfCharPerLine}}
								<NumberOfCharPerLine>{{ .NumberOfCharPerLine }}</NumberOfCharPerLine>{{end}}
							</Message>{{end}}{{ if or .FirstStop .LastStop .LineRef}}
							<LineSection>{{ if .FirstStop }}
								<FirstStop>{{.FirstStop}}</FirstStop>{{end}}{{if .LastStop}}
							  <LastStop>{{.LastStop}}</LastStop>{{end}}{{if .LineRef}}
							  <LineRef>{{.LineRef}}</LineRef>{{end}}
							</LineSection>{{end}}
						</ns3:Content>
					</ns3:GeneralMessage>{{end}}
				</ns3:GeneralMessageDelivery>`

const generalMessageDeliveryTemplate = `<ns8:GetGeneralMessageResponse xmlns:ns3="http://www.siri.org.uk/siri"
															 xmlns:ns4="http://www.ifopt.org.uk/acsb"
															 xmlns:ns5="http://www.ifopt.org.uk/ifopt"
															 xmlns:ns6="http://datex2.eu/schema/2_0RC1/2_0"
															 xmlns:ns7="http://scma/siri"
															 xmlns:ns8="http://wsdl.siri.org.uk"
															 xmlns:ns9="http://wsdl.siri.org.uk/siri">
	<ServiceDeliveryInfo>
		<ns3:ResponseTimestamp>{{ .ResponseTimestamp.Format "2006-01-02T15:04:05.000Z07:00" }}</ns3:ResponseTimestamp>
		<ns3:ProducerRef>{{ .ProducerRef }}</ns3:ProducerRef>{{ if .Address }}
		<ns3:Address>{{ .Address }}</ns3:Address>{{ end }}
		<ns3:ResponseMessageIdentifier>{{ .ResponseMessageIdentifier }}</ns3:ResponseMessageIdentifier>
		<ns3:RequestMessageRef>{{ .RequestMessageRef }}</ns3:RequestMessageRef>
	</ServiceDeliveryInfo>
	<Answer>
		{{ .BuildGeneralMessageXML }}
	</Answer>
	<AnswerExtension/>
</ns8:GetGeneralMessageResponse>`

func (response *XMLGeneralMessageResponse) XMLGeneralMessage() []*XMLGeneralMessage {
	if len(response.xmlGeneralMessages) == 0 {
		nodes := response.findNodes("GeneralMessage")
		if nodes == nil {
			return response.xmlGeneralMessages
		}
		for _, generalMessage := range nodes {
			response.xmlGeneralMessages = append(response.xmlGeneralMessages, NewXMLGeneralMessage(generalMessage))
		}
	}
	return response.xmlGeneralMessages
}

func (visit *IDFGeneralMessageStructure) Messages() []*XMLMessage {
	if len(visit.messages) == 0 {
		nodes := visit.findNodes("Message")
		if nodes == nil {
			return visit.messages
		}
		for _, messageNode := range nodes {
			visit.messages = append(visit.messages, NewXMLMessage(messageNode))
		}
	}
	return visit.messages
}

func NewXMLGeneralMessageResponseFromContent(content []byte) (*XMLGeneralMessageResponse, error) {
	doc, err := gokogiri.ParseXml(content)
	if err != nil {
		return nil, err
	}
	response := NewXMLGeneralMessageResponse(doc.Root().XmlNode)
	return response, nil
}

func NewXMLGeneralMessageResponse(node xml.Node) *XMLGeneralMessageResponse {
	xmlGeneralMessageResponse := &XMLGeneralMessageResponse{}
	xmlGeneralMessageResponse.node = NewXMLNode(node)
	return xmlGeneralMessageResponse
}

func NewXMLGeneralMessage(node XMLNode) *XMLGeneralMessage {
	generalMessage := &XMLGeneralMessage{}
	generalMessage.node = node
	return generalMessage
}

func NewXMLMessage(node XMLNode) *XMLMessage {
	message := &XMLMessage{}
	message.node = node
	return message
}

func (visit *XMLGeneralMessage) RecordedAtTime() time.Time {
	if visit.recordedAtTime.IsZero() {
		visit.recordedAtTime = visit.findTimeChildContent("RecordedAtTime")
	}
	return visit.recordedAtTime
}

func (visit *XMLGeneralMessage) ValidUntilTime() time.Time {
	if visit.validUntilTime.IsZero() {
		visit.validUntilTime = visit.findTimeChildContent("ValidUntilTime")
	}
	return visit.validUntilTime
}

func (visit *XMLGeneralMessage) ItemIdentifier() string {
	if visit.itemIdentifier == "" {
		visit.itemIdentifier = visit.findStringChildContent("ItemIdentifier")
	}
	return visit.itemIdentifier
}

func (visit *XMLGeneralMessage) InfoMessageIdentifier() string {
	if visit.infoMessageIdentifier == "" {
		visit.infoMessageIdentifier = visit.findStringChildContent("InfoMessageIdentifier")
	}
	return visit.infoMessageIdentifier
}

func (visit *XMLGeneralMessage) InfoMessageVersion() int {
	if visit.infoMessageVersion == 0 {
		visit.infoMessageVersion = visit.findIntChildContent("InfoMessageVersion")
	}
	return visit.infoMessageVersion
}

func (visit *XMLGeneralMessage) InfoChannelRef() string {
	if visit.infoChannelRef == "" {
		visit.infoChannelRef = visit.findStringChildContent("InfoChannelRef")
	}
	return visit.infoChannelRef
}

func (visit *XMLGeneralMessage) FormatRef() string {
	if visit.formatRef == "" {
		visit.formatRef = visit.findStringChildContent("formatRef")
	}
	return visit.formatRef
}

func (visit *XMLGeneralMessage) createNewContent() IDFGeneralMessageStructure {
	content := IDFGeneralMessageStructure{}
	content.node = NewXMLNode(visit.findNode("Content"))
	return content
}

func (visit *XMLGeneralMessage) Content() interface{} {
	if visit.content != nil {
		return visit.content
	}
	visit.content = visit.createNewContent()
	return visit.content
}

func (visit *IDFGeneralMessageStructure) GroupOfLinesRef() string {
	if visit.groupOfLinesRef == "" {
		visit.groupOfLinesRef = visit.findStringChildContent("GroupOfLinesRef")
	}
	return visit.groupOfLinesRef
}

func (visit *IDFGeneralMessageStructure) RouteRef() string {
	if visit.routeRef == "" {
		visit.routeRef = visit.findStringChildContent("RouteRef")
	}
	return visit.routeRef
}

func (visit *IDFGeneralMessageStructure) DestinationRef() string {
	if visit.destinationRef == "" {
		visit.destinationRef = visit.findStringChildContent("DestinationRef")
	}
	return visit.destinationRef
}

func (visit *IDFGeneralMessageStructure) JourneyPatternRef() string {
	if visit.journeyPatternRef == "" {
		visit.journeyPatternRef = visit.findStringChildContent("JourneyPatternRef")
	}
	return visit.journeyPatternRef
}

func (visit *IDFGeneralMessageStructure) StopPointRef() string {
	if visit.stopPointRef == "" {
		visit.stopPointRef = visit.findStringChildContent("StopPointRef")
	}
	return visit.stopPointRef
}

func (visit *IDFGeneralMessageStructure) LineRef() string {
	if visit.lineRef == "" {
		visit.lineRef = visit.findStringChildContent("LineRef")
	}
	return visit.lineRef
}

func (visit *IDFGeneralMessageStructure) createNewLineSection() IDFLineSectionStructure {
	visit.lineSection = IDFLineSectionStructure{}
	fmt.Println(visit.findNode("LineSection"))
	visit.lineSection.node = NewXMLNode(visit.findNode("LineSection"))
	return visit.lineSection
}

func (visit *IDFGeneralMessageStructure) LineSection() IDFLineSectionStructure {
	emptyStruct := IDFLineSectionStructure{}
	if visit.lineSection != emptyStruct {
		return visit.lineSection
	}
	return visit.createNewLineSection()
}

func (visit *IDFLineSectionStructure) FirstStop() string {
	if visit.firstStop == "" {
		visit.firstStop = visit.findStringChildContent("FirstStop")
	}
	return visit.firstStop
}

func (visit *IDFLineSectionStructure) LastStop() string {
	if visit.lastStop == "" {
		visit.lastStop = visit.findStringChildContent("LastStop")
	}
	return visit.lastStop
}

func (visit *IDFLineSectionStructure) LineRef() string {
	if visit.lineRef == "" {
		visit.lineRef = visit.findStringChildContent("LineRef")
	}
	return visit.lineRef
}

func (message *XMLMessage) MessageText() string {
	if message.messageText == "" {
		message.messageText = message.findStringChildContent("MessageText")
	}
	return message.messageText
}

func (message *XMLMessage) MessageType() string {
	if message.messageType == "" {
		message.messageType = message.findStringChildContent("MessageType")
	}
	return message.messageType
}

func (message *XMLMessage) NumberOfLines() int {
	if message.numberOfLines == 0 {
		message.numberOfLines = message.findIntChildContent("NumberOfLines")
	}
	return message.numberOfLines
}

func (message *XMLMessage) NumberOfCharPerLine() int {
	if message.numberOfCharPerLine == 0 {
		message.numberOfCharPerLine = message.findIntChildContent("NumberOfCharPerLine")
	}
	return message.numberOfCharPerLine
}

func (response *SIRIGeneralMessageResponse) BuildXML() (string, error) {
	var buffer bytes.Buffer
	var generalMessage = template.Must(template.New("generalMessage").Parse(generalMessageDeliveryTemplate))
	if err := generalMessage.Execute(&buffer, response); err != nil {
		return "", err
	}
	return buffer.String(), nil
}

func (delivery *SIRIGeneralMessageDelivery) BuildGeneralMessageXML() (string, error) {
	var buffer bytes.Buffer
	var generalMessageDelivery = template.Must(template.New("generalMessageDelivery").Parse(generalMessageTemplate))
	if err := generalMessageDelivery.Execute(&buffer, delivery); err != nil {
		return "", err
	}
	return buffer.String(), nil
}
<commit_msg>Refs #3276 Balise formatRef maintenant avant RecordedAtTime<commit_after>package siri

import (
	"bytes"
	"fmt"
	"text/template"
	"time"

	"github.com/jbowtie/gokogiri"
	"github.com/jbowtie/gokogiri/xml"
)

type XMLGeneralMessageResponse struct {
	ResponseXMLStructure

	xmlGeneralMessages []*XMLGeneralMessage
}

type XMLGeneralMessage struct {
	XMLStructure

	recordedAtTime        time.Time
	validUntilTime        time.Time
	itemIdentifier        string
	infoMessageIdentifier string
	infoChannelRef        string
	formatRef             string
	infoMessageVersion    int
	numberOfLines         int
	numberOfCharPerLine   int
	content               interface{}
}

type IDFGeneralMessageStructure struct {
	XMLStructure

	messages          []*XMLMessage
	lineRef           string
	stopPointRef      string
	journeyPatternRef string
	destinationRef    string
	routeRef          string
	format            string
	groupOfLinesRef   string
	lineSection       IDFLineSectionStructure
}

type XMLMessage struct {
	XMLStructure

	messageText         string
	messageType         string
	numberOfLines       int
	numberOfCharPerLine int
}

type IDFLineSectionStructure struct {
	XMLStructure

	firstStop string
	lastStop  string
	lineRef   string
}

type SIRIGeneralMessageResponse struct {
	SIRIGeneralMessageDelivery

	Address                   string
	ProducerRef               string
	ResponseMessageIdentifier string
}

type SIRIGeneralMessageDelivery struct {
	RequestMessageRef string
	Status            bool
	ErrorType         string
	ErrorNumber       int
	ErrorText         string
	ResponseTimestamp time.Time

	GeneralMessages []*SIRIGeneralMessage
}

type SIRIGeneralMessage struct {
	RecordedAtTime        time.Time
	ValidUntilTime        time.Time
	ItemIdentifier        string
	InfoMessageIdentifier string
	FormatRef             string
	InfoMessageVersion    int64
	InfoChannelRef        string

	LineRefContent    string
	StopPointRef      string
	JourneyPatternRef string
	DestinationRef    string
	RouteRef          string
	GroupOfLinesRef   string

	Messages []*SIRIMessage

	FirstStop string
	LastStop  string
	LineRef   string
}

type SIRIMessage struct {
	Content             string
	Type                string
	NumberOfLines       int
	NumberOfCharPerLine int
}

const generalMessageTemplate = `<ns3:GeneralMessageDelivery version="2.0:FR-IDF-2.4">
				  <ns3:ResponseTimestamp>{{ .ResponseTimestamp.Format "2006-01-02T15:04:05.000Z07:00" }}</ns3:ResponseTimestamp>
					<ns3:Status>{{.Status}}</ns3:Status>{{range .GeneralMessages}}
					<ns3:GeneralMessage>
						<ns3:formatRef>{{ .FormatRef }}</ns3:formatRef>
						<ns3:RecordedAtTime>{{ .RecordedAtTime.Format "2006-01-02T15:04:05.000Z07:00" }}</ns3:RecordedAtTime>
						<ns3:InfoMessageIdentifier>{{.InfoMessageIdentifier}}</ns3:InfoMessageIdentifier>
						<ns3:InfoMessageVersion>{{.InfoMessageVersion}}</ns3:InfoMessageVersion>
						<ns3:InfoChannelRef>{{.InfoChannelRef}}</ns3:InfoChannelRef>
						<ns3:ValidUntilTime>{{ .ValidUntilTime.Format "2006-01-02T15:04:05.000Z07:00" }}</ns3:ValidUntilTime>
						<ns3:Content xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
						xsi:type="ns9:IDFLineSectionStructure">{{range .Messages}}
							<Message>{{if .Type}}
								<MessageType>{{ .Type }}</MessageType>{{end}}{{if .Content}}
								<MessageText>{{ .Content }}</MessageText>{{end}}{{if .NumberOfLines}}
								<NumberOfLines>{{ .NumberOfLines }}</NumberOfLines>{{end}}{{if .NumberOfCharPerLine}}
								<NumberOfCharPerLine>{{ .NumberOfCharPerLine }}</NumberOfCharPerLine>{{end}}
							</Message>{{end}}{{ if or .FirstStop .LastStop .LineRef}}
							<LineSection>{{ if .FirstStop }}
								<FirstStop>{{.FirstStop}}</FirstStop>{{end}}{{if .LastStop}}
							  <LastStop>{{.LastStop}}</LastStop>{{end}}{{if .LineRef}}
							  <LineRef>{{.LineRef}}</LineRef>{{end}}
							</LineSection>{{end}}
						</ns3:Content>
					</ns3:GeneralMessage>{{end}}
				</ns3:GeneralMessageDelivery>`

const generalMessageDeliveryTemplate = `<ns8:GetGeneralMessageResponse xmlns:ns3="http://www.siri.org.uk/siri"
															 xmlns:ns4="http://www.ifopt.org.uk/acsb"
															 xmlns:ns5="http://www.ifopt.org.uk/ifopt"
															 xmlns:ns6="http://datex2.eu/schema/2_0RC1/2_0"
															 xmlns:ns7="http://scma/siri"
															 xmlns:ns8="http://wsdl.siri.org.uk"
															 xmlns:ns9="http://wsdl.siri.org.uk/siri">
	<ServiceDeliveryInfo>
		<ns3:ResponseTimestamp>{{ .ResponseTimestamp.Format "2006-01-02T15:04:05.000Z07:00" }}</ns3:ResponseTimestamp>
		<ns3:ProducerRef>{{ .ProducerRef }}</ns3:ProducerRef>{{ if .Address }}
		<ns3:Address>{{ .Address }}</ns3:Address>{{ end }}
		<ns3:ResponseMessageIdentifier>{{ .ResponseMessageIdentifier }}</ns3:ResponseMessageIdentifier>
		<ns3:RequestMessageRef>{{ .RequestMessageRef }}</ns3:RequestMessageRef>
	</ServiceDeliveryInfo>
	<Answer>
		{{ .BuildGeneralMessageXML }}
	</Answer>
	<AnswerExtension/>
</ns8:GetGeneralMessageResponse>`

func (response *XMLGeneralMessageResponse) XMLGeneralMessage() []*XMLGeneralMessage {
	if len(response.xmlGeneralMessages) == 0 {
		nodes := response.findNodes("GeneralMessage")
		if nodes == nil {
			return response.xmlGeneralMessages
		}
		for _, generalMessage := range nodes {
			response.xmlGeneralMessages = append(response.xmlGeneralMessages, NewXMLGeneralMessage(generalMessage))
		}
	}
	return response.xmlGeneralMessages
}

func (visit *IDFGeneralMessageStructure) Messages() []*XMLMessage {
	if len(visit.messages) == 0 {
		nodes := visit.findNodes("Message")
		if nodes == nil {
			return visit.messages
		}
		for _, messageNode := range nodes {
			visit.messages = append(visit.messages, NewXMLMessage(messageNode))
		}
	}
	return visit.messages
}

func NewXMLGeneralMessageResponseFromContent(content []byte) (*XMLGeneralMessageResponse, error) {
	doc, err := gokogiri.ParseXml(content)
	if err != nil {
		return nil, err
	}
	response := NewXMLGeneralMessageResponse(doc.Root().XmlNode)
	return response, nil
}

func NewXMLGeneralMessageResponse(node xml.Node) *XMLGeneralMessageResponse {
	xmlGeneralMessageResponse := &XMLGeneralMessageResponse{}
	xmlGeneralMessageResponse.node = NewXMLNode(node)
	return xmlGeneralMessageResponse
}

func NewXMLGeneralMessage(node XMLNode) *XMLGeneralMessage {
	generalMessage := &XMLGeneralMessage{}
	generalMessage.node = node
	return generalMessage
}

func NewXMLMessage(node XMLNode) *XMLMessage {
	message := &XMLMessage{}
	message.node = node
	return message
}

func (visit *XMLGeneralMessage) RecordedAtTime() time.Time {
	if visit.recordedAtTime.IsZero() {
		visit.recordedAtTime = visit.findTimeChildContent("RecordedAtTime")
	}
	return visit.recordedAtTime
}

func (visit *XMLGeneralMessage) ValidUntilTime() time.Time {
	if visit.validUntilTime.IsZero() {
		visit.validUntilTime = visit.findTimeChildContent("ValidUntilTime")
	}
	return visit.validUntilTime
}

func (visit *XMLGeneralMessage) ItemIdentifier() string {
	if visit.itemIdentifier == "" {
		visit.itemIdentifier = visit.findStringChildContent("ItemIdentifier")
	}
	return visit.itemIdentifier
}

func (visit *XMLGeneralMessage) InfoMessageIdentifier() string {
	if visit.infoMessageIdentifier == "" {
		visit.infoMessageIdentifier = visit.findStringChildContent("InfoMessageIdentifier")
	}
	return visit.infoMessageIdentifier
}

func (visit *XMLGeneralMessage) InfoMessageVersion() int {
	if visit.infoMessageVersion == 0 {
		visit.infoMessageVersion = visit.findIntChildContent("InfoMessageVersion")
	}
	return visit.infoMessageVersion
}

func (visit *XMLGeneralMessage) InfoChannelRef() string {
	if visit.infoChannelRef == "" {
		visit.infoChannelRef = visit.findStringChildContent("InfoChannelRef")
	}
	return visit.infoChannelRef
}

func (visit *XMLGeneralMessage) FormatRef() string {
	if visit.formatRef == "" {
		visit.formatRef = visit.findStringChildContent("formatRef")
	}
	return visit.formatRef
}

func (visit *XMLGeneralMessage) createNewContent() IDFGeneralMessageStructure {
	content := IDFGeneralMessageStructure{}
	content.node = NewXMLNode(visit.findNode("Content"))
	return content
}

func (visit *XMLGeneralMessage) Content() interface{} {
	if visit.content != nil {
		return visit.content
	}
	visit.content = visit.createNewContent()
	return visit.content
}

func (visit *IDFGeneralMessageStructure) GroupOfLinesRef() string {
	if visit.groupOfLinesRef == "" {
		visit.groupOfLinesRef = visit.findStringChildContent("GroupOfLinesRef")
	}
	return visit.groupOfLinesRef
}

func (visit *IDFGeneralMessageStructure) RouteRef() string {
	if visit.routeRef == "" {
		visit.routeRef = visit.findStringChildContent("RouteRef")
	}
	return visit.routeRef
}

func (visit *IDFGeneralMessageStructure) DestinationRef() string {
	if visit.destinationRef == "" {
		visit.destinationRef = visit.findStringChildContent("DestinationRef")
	}
	return visit.destinationRef
}

func (visit *IDFGeneralMessageStructure) JourneyPatternRef() string {
	if visit.journeyPatternRef == "" {
		visit.journeyPatternRef = visit.findStringChildContent("JourneyPatternRef")
	}
	return visit.journeyPatternRef
}

func (visit *IDFGeneralMessageStructure) StopPointRef() string {
	if visit.stopPointRef == "" {
		visit.stopPointRef = visit.findStringChildContent("StopPointRef")
	}
	return visit.stopPointRef
}

func (visit *IDFGeneralMessageStructure) LineRef() string {
	if visit.lineRef == "" {
		visit.lineRef = visit.findStringChildContent("LineRef")
	}
	return visit.lineRef
}

func (visit *IDFGeneralMessageStructure) createNewLineSection() IDFLineSectionStructure {
	visit.lineSection = IDFLineSectionStructure{}
	fmt.Println(visit.findNode("LineSection"))
	visit.lineSection.node = NewXMLNode(visit.findNode("LineSection"))
	return visit.lineSection
}

func (visit *IDFGeneralMessageStructure) LineSection() IDFLineSectionStructure {
	emptyStruct := IDFLineSectionStructure{}
	if visit.lineSection != emptyStruct {
		return visit.lineSection
	}
	return visit.createNewLineSection()
}

func (visit *IDFLineSectionStructure) FirstStop() string {
	if visit.firstStop == "" {
		visit.firstStop = visit.findStringChildContent("FirstStop")
	}
	return visit.firstStop
}

func (visit *IDFLineSectionStructure) LastStop() string {
	if visit.lastStop == "" {
		visit.lastStop = visit.findStringChildContent("LastStop")
	}
	return visit.lastStop
}

func (visit *IDFLineSectionStructure) LineRef() string {
	if visit.lineRef == "" {
		visit.lineRef = visit.findStringChildContent("LineRef")
	}
	return visit.lineRef
}

func (message *XMLMessage) MessageText() string {
	if message.messageText == "" {
		message.messageText = message.findStringChildContent("MessageText")
	}
	return message.messageText
}

func (message *XMLMessage) MessageType() string {
	if message.messageType == "" {
		message.messageType = message.findStringChildContent("MessageType")
	}
	return message.messageType
}

func (message *XMLMessage) NumberOfLines() int {
	if message.numberOfLines == 0 {
		message.numberOfLines = message.findIntChildContent("NumberOfLines")
	}
	return message.numberOfLines
}

func (message *XMLMessage) NumberOfCharPerLine() int {
	if message.numberOfCharPerLine == 0 {
		message.numberOfCharPerLine = message.findIntChildContent("NumberOfCharPerLine")
	}
	return message.numberOfCharPerLine
}

func (response *SIRIGeneralMessageResponse) BuildXML() (string, error) {
	var buffer bytes.Buffer
	var generalMessage = template.Must(template.New("generalMessage").Parse(generalMessageDeliveryTemplate))
	if err := generalMessage.Execute(&buffer, response); err != nil {
		return "", err
	}
	return buffer.String(), nil
}

func (delivery *SIRIGeneralMessageDelivery) BuildGeneralMessageXML() (string, error) {
	var buffer bytes.Buffer
	var generalMessageDelivery = template.Must(template.New("generalMessageDelivery").Parse(generalMessageTemplate))
	if err := generalMessageDelivery.Execute(&buffer, delivery); err != nil {
		return "", err
	}
	return buffer.String(), nil
}
<|endoftext|>


<commit_before>package common

import (
	gossh "code.google.com/p/go.crypto/ssh"
	"fmt"
	"github.com/mitchellh/goamz/ec2"
	"github.com/mitchellh/packer/communicator/ssh"
)

// SSHAddress returns a function that can be given to the SSH communicator
// for determining the SSH address based on the instance DNS name.
func SSHAddress(port int) func(map[string]interface{}) (string, error) {
	return func(state map[string]interface{}) (string, error) {
		instance := state["instance"].(*ec2.Instance)
		return fmt.Sprintf("%s:%d", instance.DNSName, port), nil
	}
}

// SSHConfig returns a function that can be used for the SSH communicator
// config for connecting to the instance created over SSH using the generated
// private key.
func SSHConfig(username string) func(map[string]interface{}) (*gossh.ClientConfig, error) {
	return func(state map[string]interface{}) (*gossh.ClientConfig, error) {
		privateKey := state["privateKey"].(string)

		keyring := new(ssh.SimpleKeychain)
		if err := keyring.AddPEMKey(privateKey); err != nil {
			return nil, fmt.Errorf("Error setting up SSH config: %s", err)
		}

		return &gossh.ClientConfig{
			User: username,
			Auth: []gossh.ClientAuth{
				gossh.ClientAuthKeyring(keyring),
			},
		}, nil
	}
}
<commit_msg>builder/amazon/common: SSH into private IP if in VPC<commit_after>package common

import (
	gossh "code.google.com/p/go.crypto/ssh"
	"fmt"
	"github.com/mitchellh/goamz/ec2"
	"github.com/mitchellh/packer/communicator/ssh"
)

// SSHAddress returns a function that can be given to the SSH communicator
// for determining the SSH address based on the instance DNS name.
func SSHAddress(port int) func(map[string]interface{}) (string, error) {
	return func(state map[string]interface{}) (string, error) {
		var host string
		instance := state["instance"].(*ec2.Instance)
		if instance.VpcId != "" {
			host = instance.PrivateIpAddress
		} else {
			host = instance.DNSName
		}

		return fmt.Sprintf("%s:%d", host, port), nil
	}
}

// SSHConfig returns a function that can be used for the SSH communicator
// config for connecting to the instance created over SSH using the generated
// private key.
func SSHConfig(username string) func(map[string]interface{}) (*gossh.ClientConfig, error) {
	return func(state map[string]interface{}) (*gossh.ClientConfig, error) {
		privateKey := state["privateKey"].(string)

		keyring := new(ssh.SimpleKeychain)
		if err := keyring.AddPEMKey(privateKey); err != nil {
			return nil, fmt.Errorf("Error setting up SSH config: %s", err)
		}

		return &gossh.ClientConfig{
			User: username,
			Auth: []gossh.ClientAuth{
				gossh.ClientAuthKeyring(keyring),
			},
		}, nil
	}
}
<|endoftext|>


<commit_before>package v7

import (
	"code.cloudfoundry.org/cli/actor/actionerror"
	"code.cloudfoundry.org/cli/command/flag"
)

type ShareRouteCommand struct {
	BaseCommand

	RequireArgs      flag.Domain      `positional-args:"yes"`
	Hostname         string           `long:"hostname" short:"n" description:"Hostname for the HTTP route (required for shared domains)"`
	Path             flag.V7RoutePath `long:"path" description:"Path for the HTTP route"`
	DestinationOrg   string           `short:"o" description:"The org of the destination space (Default: targeted org)"` // ToDo: fix me
	DestinationSpace string           `short:"s" description:"The space the route will be shared with (Default: targeted space)"`

	relatedCommands interface{} `related_commands:"create-route, map-route, unmap-route, routes"`
}

func (cmd ShareRouteCommand) Usage() string {
	return `
Share an existing route in between two spaces:
	CF_NAME share-route DOMAIN [--hostname HOSTNAME] [--path PATH] -s OTHER_SPACE [-o OTHER_ORG]`
}

func (cmd ShareRouteCommand) Examples() string {
	return `
CF_NAME share-route example.com --hostname myHost --path foo -s TargetSpace -o TargetOrg        # myhost.example.com/foo
CF_NAME share-route example.com --hostname myHost -s TargetSpace                                # myhost.example.com
CF_NAME share-route example.com --hostname myHost -s TargetSpace -o TargetOrg                   # myhost.example.com`
}

func (cmd ShareRouteCommand) Execute(args []string) error {
	err := cmd.SharedActor.CheckTarget(true, true)
	if err != nil {
		return err
	}

	user, err := cmd.Actor.GetCurrentUser()
	if err != nil {
		return err
	}

	domain, warnings, err := cmd.Actor.GetDomainByName(cmd.RequireArgs.Domain)
	cmd.UI.DisplayWarnings(warnings)
	if err != nil {
		return err
	}

	path := cmd.Path.Path
	route, warnings, err := cmd.Actor.GetRouteByAttributes(domain, cmd.Hostname, path, 0)
	cmd.UI.DisplayWarnings(warnings)
	if err != nil {
		if _, ok := err.(actionerror.RouteNotFoundError); ok {
			cmd.UI.DisplayText("Can not share route:")
			return err
		}
	}

	destinationOrgName := cmd.DestinationOrg

	if destinationOrgName == "" {
		destinationOrgName = cmd.Config.TargetedOrganizationName()
	}

	destinationOrg, warnings, err := cmd.Actor.GetOrganizationByName(destinationOrgName)

	if err != nil {
		if _, ok := err.(actionerror.OrganizationNotFoundError); ok {
			cmd.UI.DisplayText("Can not share route:")
			return err
		}
	}

	targetedSpace, warnings, err := cmd.Actor.GetSpaceByNameAndOrganization(cmd.DestinationSpace, destinationOrg.GUID)
	if err != nil {
		if _, ok := err.(actionerror.SpaceNotFoundError); ok {
			cmd.UI.DisplayText("Can not share route:")
			return err
		}
	}

	url := desiredURL(domain.Name, cmd.Hostname, path, 0)
	cmd.UI.DisplayTextWithFlavor("Sharing route {{.URL}} to space {{.DestinationSpace}} as {{.User}}",
		map[string]interface{}{
			"URL":              url,
			"DestinationSpace": cmd.DestinationSpace,
			"User":             user.Name,
		})
	warnings, err = cmd.Actor.ShareRoute(
		route.GUID,
		targetedSpace.GUID,
	)
	cmd.UI.DisplayWarnings(warnings)
	if err != nil {
		return err
	}
	cmd.UI.DisplayOK()

	return nil
}
<commit_msg>remove todo<commit_after>package v7

import (
	"code.cloudfoundry.org/cli/actor/actionerror"
	"code.cloudfoundry.org/cli/command/flag"
)

type ShareRouteCommand struct {
	BaseCommand

	RequireArgs      flag.Domain      `positional-args:"yes"`
	Hostname         string           `long:"hostname" short:"n" description:"Hostname for the HTTP route (required for shared domains)"`
	Path             flag.V7RoutePath `long:"path" description:"Path for the HTTP route"`
	DestinationOrg   string           `short:"o" description:"The org of the destination space (Default: targeted org)"`
	DestinationSpace string           `short:"s" description:"The space the route will be shared with (Default: targeted space)"`

	relatedCommands interface{} `related_commands:"create-route, map-route, unmap-route, routes"`
}

func (cmd ShareRouteCommand) Usage() string {
	return `
Share an existing route in between two spaces:
	CF_NAME share-route DOMAIN [--hostname HOSTNAME] [--path PATH] -s OTHER_SPACE [-o OTHER_ORG]`
}

func (cmd ShareRouteCommand) Examples() string {
	return `
CF_NAME share-route example.com --hostname myHost --path foo -s TargetSpace -o TargetOrg        # myhost.example.com/foo
CF_NAME share-route example.com --hostname myHost -s TargetSpace                                # myhost.example.com
CF_NAME share-route example.com --hostname myHost -s TargetSpace -o TargetOrg                   # myhost.example.com`
}

func (cmd ShareRouteCommand) Execute(args []string) error {
	err := cmd.SharedActor.CheckTarget(true, true)
	if err != nil {
		return err
	}

	user, err := cmd.Actor.GetCurrentUser()
	if err != nil {
		return err
	}

	domain, warnings, err := cmd.Actor.GetDomainByName(cmd.RequireArgs.Domain)
	cmd.UI.DisplayWarnings(warnings)
	if err != nil {
		return err
	}

	path := cmd.Path.Path
	route, warnings, err := cmd.Actor.GetRouteByAttributes(domain, cmd.Hostname, path, 0)
	cmd.UI.DisplayWarnings(warnings)
	if err != nil {
		if _, ok := err.(actionerror.RouteNotFoundError); ok {
			cmd.UI.DisplayText("Can not share route:")
			return err
		}
	}

	destinationOrgName := cmd.DestinationOrg

	if destinationOrgName == "" {
		destinationOrgName = cmd.Config.TargetedOrganizationName()
	}

	destinationOrg, warnings, err := cmd.Actor.GetOrganizationByName(destinationOrgName)

	if err != nil {
		if _, ok := err.(actionerror.OrganizationNotFoundError); ok {
			cmd.UI.DisplayText("Can not share route:")
			return err
		}
	}

	targetedSpace, warnings, err := cmd.Actor.GetSpaceByNameAndOrganization(cmd.DestinationSpace, destinationOrg.GUID)
	if err != nil {
		if _, ok := err.(actionerror.SpaceNotFoundError); ok {
			cmd.UI.DisplayText("Can not share route:")
			return err
		}
	}

	url := desiredURL(domain.Name, cmd.Hostname, path, 0)
	cmd.UI.DisplayTextWithFlavor("Sharing route {{.URL}} to space {{.DestinationSpace}} as {{.User}}",
		map[string]interface{}{
			"URL":              url,
			"DestinationSpace": cmd.DestinationSpace,
			"User":             user.Name,
		})
	warnings, err = cmd.Actor.ShareRoute(
		route.GUID,
		targetedSpace.GUID,
	)
	cmd.UI.DisplayWarnings(warnings)
	if err != nil {
		return err
	}
	cmd.UI.DisplayOK()

	return nil
}
<|endoftext|>


<commit_before>/*
Copyright 2020 The Knative 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 mtping

import (
	"context"
	"reflect"
	"testing"
	"time"

	adaptertesting "knative.dev/eventing/pkg/adapter/v2/test"
	duckv1 "knative.dev/pkg/apis/duck/v1"
	logtesting "knative.dev/pkg/logging/testing"
)

func TestAddRunRemoveSchedules(t *testing.T) {

	testCases := map[string]struct {
		wantCEOverrides *duckv1.CloudEventOverrides
	}{
		"TestAddRunRemoveSchedule": {
			wantCEOverrides: nil,
		}, "TestAddRunRemoveScheduleWithExtensionOverride": {
			wantCEOverrides: &duckv1.CloudEventOverrides{Extensions: map[string]string{"1": "one", "2": "two"}},
		},
	}
	for n, tc := range testCases {
		t.Run(n, func(t *testing.T) {
			logger := logtesting.TestLogger(t)
			ce := adaptertesting.NewTestClient()

			runner := NewCronJobsRunner(ce, logger)

			entryId, err := runner.AddSchedule("test-ns", "test-name", "* * * * ?", "some data",
				"a sink", tc.wantCEOverrides)

			if err != nil {
				t.Errorf("Should not throw error %v", err)
			}

			entry := runner.cron.Entry(entryId)
			if entry.ID != entryId {
				t.Error("Entry has not been added")
			}

			entry.Job.Run()

			validateSent(t, ce, `{"body":"some data"}`, tc.wantCEOverrides)

			runner.RemoveSchedule(entryId)

			entry = runner.cron.Entry(entryId)
			if entry.ID == entryId {
				t.Error("Entry has not been removed")
			}
		})
	}
}

func TestStartStopCron(t *testing.T) {
	logger := logtesting.TestLogger(t)
	ce := adaptertesting.NewTestClient()

	runner := NewCronJobsRunner(ce, logger)

	ctx, cancel := context.WithCancel(context.Background())
	wctx, wcancel := context.WithCancel(context.Background())

	go func() {
		err := runner.Start(ctx.Done())
		if err != nil {
			t.Errorf("Cron job runner couldn't start %v", err)
		}
		wcancel()
	}()

	cancel()

	select {
	case <-time.After(2 * time.Second):
		t.Fatal("expected cron to be stopped after 2 seconds")
	case <-wctx.Done():
	}

}

func validateSent(t *testing.T, ce *adaptertesting.TestCloudEventsClient, wantData string,
	wantCEOverrides *duckv1.CloudEventOverrides) {
	if got := len(ce.Sent()); got != 1 {
		t.Errorf("Expected 1 event to be sent, got %d", got)
	}

	if got := ce.Sent()[0].Data(); string(got) != wantData {
		t.Errorf("Expected %q event to be sent, got %q", wantData, got)
	}

	gotExtensions := ce.Sent()[0].Context.GetExtensions()

	if wantCEOverrides == nil && gotExtensions != nil {
		t.Errorf("Expected event with no extention overrides got %v", gotExtensions)
	}

	if wantCEOverrides != nil && gotExtensions == nil {
		t.Errorf("Expected event with extention overrides got nil")
	}
	if wantCEOverrides != nil {
		compareTo := map[string]interface{}{}
		for k, v := range wantCEOverrides.Extensions {
			compareTo[k] = v
		}
		if !reflect.DeepEqual(compareTo, gotExtensions) {
			t.Errorf("Expected event with extention overrides to be the same want: %v, but got: %v", wantCEOverrides, gotExtensions)
		}
	}
}
<commit_msg>[master] Fix spelling errors (#3332)<commit_after>/*
Copyright 2020 The Knative 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 mtping

import (
	"context"
	"reflect"
	"testing"
	"time"

	adaptertesting "knative.dev/eventing/pkg/adapter/v2/test"
	duckv1 "knative.dev/pkg/apis/duck/v1"
	logtesting "knative.dev/pkg/logging/testing"
)

func TestAddRunRemoveSchedules(t *testing.T) {

	testCases := map[string]struct {
		wantCEOverrides *duckv1.CloudEventOverrides
	}{
		"TestAddRunRemoveSchedule": {
			wantCEOverrides: nil,
		}, "TestAddRunRemoveScheduleWithExtensionOverride": {
			wantCEOverrides: &duckv1.CloudEventOverrides{Extensions: map[string]string{"1": "one", "2": "two"}},
		},
	}
	for n, tc := range testCases {
		t.Run(n, func(t *testing.T) {
			logger := logtesting.TestLogger(t)
			ce := adaptertesting.NewTestClient()

			runner := NewCronJobsRunner(ce, logger)

			entryId, err := runner.AddSchedule("test-ns", "test-name", "* * * * ?", "some data",
				"a sink", tc.wantCEOverrides)

			if err != nil {
				t.Errorf("Should not throw error %v", err)
			}

			entry := runner.cron.Entry(entryId)
			if entry.ID != entryId {
				t.Error("Entry has not been added")
			}

			entry.Job.Run()

			validateSent(t, ce, `{"body":"some data"}`, tc.wantCEOverrides)

			runner.RemoveSchedule(entryId)

			entry = runner.cron.Entry(entryId)
			if entry.ID == entryId {
				t.Error("Entry has not been removed")
			}
		})
	}
}

func TestStartStopCron(t *testing.T) {
	logger := logtesting.TestLogger(t)
	ce := adaptertesting.NewTestClient()

	runner := NewCronJobsRunner(ce, logger)

	ctx, cancel := context.WithCancel(context.Background())
	wctx, wcancel := context.WithCancel(context.Background())

	go func() {
		err := runner.Start(ctx.Done())
		if err != nil {
			t.Errorf("Cron job runner couldn't start %v", err)
		}
		wcancel()
	}()

	cancel()

	select {
	case <-time.After(2 * time.Second):
		t.Fatal("expected cron to be stopped after 2 seconds")
	case <-wctx.Done():
	}

}

func validateSent(t *testing.T, ce *adaptertesting.TestCloudEventsClient, wantData string,
	wantCEOverrides *duckv1.CloudEventOverrides) {
	if got := len(ce.Sent()); got != 1 {
		t.Errorf("Expected 1 event to be sent, got %d", got)
	}

	if got := ce.Sent()[0].Data(); string(got) != wantData {
		t.Errorf("Expected %q event to be sent, got %q", wantData, got)
	}

	gotExtensions := ce.Sent()[0].Context.GetExtensions()

	if wantCEOverrides == nil && gotExtensions != nil {
		t.Errorf("Expected event with no extension overrides got %v", gotExtensions)
	}

	if wantCEOverrides != nil && gotExtensions == nil {
		t.Errorf("Expected event with extension overrides got nil")
	}
	if wantCEOverrides != nil {
		compareTo := map[string]interface{}{}
		for k, v := range wantCEOverrides.Extensions {
			compareTo[k] = v
		}
		if !reflect.DeepEqual(compareTo, gotExtensions) {
			t.Errorf("Expected event with extension overrides to be the same want: %v, but got: %v", wantCEOverrides, gotExtensions)
		}
	}
}
<|endoftext|>