<commit_before>package hash

import (
	"testing"
)

// Representative of small and medium subjects.
var smlKey = []byte("foo")
var medKey = []byte("apcera.continuum.router.foo.bar")

func Benchmark_Bernstein_SmallKey(b *testing.B) {
	b.SetBytes(1)
	for i := 0; i < b.N; i++ {
		Bernstein(smlKey)
	}
}

func Benchmark_Murmur3___SmallKey(b *testing.B) {
	b.SetBytes(1)
	for i := 0; i < b.N; i++ {
		Murmur3(smlKey, M3Seed)
	}
}

func Benchmark_FNV1A_____SmallKey(b *testing.B) {
	b.SetBytes(1)
	for i := 0; i < b.N; i++ {
		FNV1A(smlKey)
	}
}

func Benchmark_Meiyan____SmallKey(b *testing.B) {
	b.SetBytes(1)
	for i := 0; i < b.N; i++ {
		Meiyan(smlKey)
	}
}

func Benchmark_Jesteress_SmallKey(b *testing.B) {
	b.SetBytes(1)
	for i := 0; i < b.N; i++ {
		Jesteress(smlKey)
	}
}

func Benchmark_Yorikke___SmallKey(b *testing.B) {
	b.SetBytes(1)
	for i := 0; i < b.N; i++ {
		Yorikke(smlKey)
	}
}

func Benchmark_Bernstein___MedKey(b *testing.B) {
	b.SetBytes(1)
	for i := 0; i < b.N; i++ {
		Bernstein(medKey)
	}
}

func Benchmark_Murmur3_____MedKey(b *testing.B) {
	b.SetBytes(1)
	for i := 0; i < b.N; i++ {
		Murmur3(medKey, M3Seed)
	}
}

func Benchmark_FNV1A_______MedKey(b *testing.B) {
	b.SetBytes(1)
	for i := 0; i < b.N; i++ {
		FNV1A(medKey)
	}
}

func Benchmark_Meiyan______MedKey(b *testing.B) {
	b.SetBytes(1)
	for i := 0; i < b.N; i++ {
		Meiyan(medKey)
	}
}

func Benchmark_Jesteress___MedKey(b *testing.B) {
	b.SetBytes(1)
	for i := 0; i < b.N; i++ {
		Jesteress(medKey)
	}
}

func Benchmark_Yorikke_____MedKey(b *testing.B) {
	b.SetBytes(1)
	for i := 0; i < b.N; i++ {
		Yorikke(medKey)
	}
}
<commit_msg>Added tests in addition to benchmarks<commit_after>package hash

import (
	"testing"
)

var keys = [][]byte{
	[]byte("foo"),
	[]byte("bar"),
	[]byte("apcera.continuum.router.foo.bar"),
	[]byte("apcera.continuum.router.foo.bar.baz"),
}

func TestBernstein(t *testing.T) {
	results := []uint32{193491849, 193487034, 2487287557, 3139297488}
	for i, key := range keys {
		h := Bernstein(key)
		if h != results[i] {
			t.Fatalf("hash is incorrect, expected %d, got %d\n",
				results[i], h)
		}
	}
}

func TestFNV1A(t *testing.T) {
	results := []uint32{2851307223, 1991736602, 1990810707, 1244015104}
	for i, key := range keys {
		h := FNV1A(key)
		if h != results[i] {
			t.Fatalf("hash is incorrect, expected %d, got %d\n",
				results[i], h)
		}
	}
}

func TestJesteress(t *testing.T) {
	results := []uint32{1058908168, 1061739001, 4242539713, 3332038527}
	for i, key := range keys {
		h := Jesteress(key)
		if h != results[i] {
			t.Fatalf("hash is incorrect, expected %d, got %d\n",
				results[i], h)
		}
	}
}

func TestMeiyan(t *testing.T) {
	results := []uint32{1058908168, 1061739001, 2891236487, 3332038527}
	for i, key := range keys {
		h := Meiyan(key)
		if h != results[i] {
			t.Fatalf("hash is incorrect, expected %d, got %d\n",
				results[i], h)
		}
	}
}

func TestYorikke(t *testing.T) {
	results := []uint32{3523423968, 2222334353, 407908456, 359111667}
	for i, key := range keys {
		h := Yorikke(key)
		if h != results[i] {
			t.Fatalf("hash is incorrect, expected %d, got %d\n",
				results[i], h)
		}
	}
}

func TestMurmur3(t *testing.T) {
	results := []uint32{659908353, 522989004, 135963738, 990328005}
	for i, key := range keys {
		h := Murmur3(key, M3Seed)
		if h != results[i] {
			t.Fatalf("hash is incorrect, expected %d, got %d\n",
				results[i], h)
		}
	}
}

// Representative of small and medium subjects.
var smlKey = []byte("foo")
var medKey = []byte("apcera.continuum.router.foo.bar")

func Benchmark_Bernstein_SmallKey(b *testing.B) {
	b.SetBytes(1)
	for i := 0; i < b.N; i++ {
		Bernstein(smlKey)
	}
}

func Benchmark_Murmur3___SmallKey(b *testing.B) {
	b.SetBytes(1)
	for i := 0; i < b.N; i++ {
		Murmur3(smlKey, M3Seed)
	}
}

func Benchmark_FNV1A_____SmallKey(b *testing.B) {
	b.SetBytes(1)
	for i := 0; i < b.N; i++ {
		FNV1A(smlKey)
	}
}

func Benchmark_Meiyan____SmallKey(b *testing.B) {
	b.SetBytes(1)
	for i := 0; i < b.N; i++ {
		Meiyan(smlKey)
	}
}

func Benchmark_Jesteress_SmallKey(b *testing.B) {
	b.SetBytes(1)
	for i := 0; i < b.N; i++ {
		Jesteress(smlKey)
	}
}

func Benchmark_Yorikke___SmallKey(b *testing.B) {
	b.SetBytes(1)
	for i := 0; i < b.N; i++ {
		Yorikke(smlKey)
	}
}

func Benchmark_Bernstein___MedKey(b *testing.B) {
	b.SetBytes(1)
	for i := 0; i < b.N; i++ {
		Bernstein(medKey)
	}
}

func Benchmark_Murmur3_____MedKey(b *testing.B) {
	b.SetBytes(1)
	for i := 0; i < b.N; i++ {
		Murmur3(medKey, M3Seed)
	}
}

func Benchmark_FNV1A_______MedKey(b *testing.B) {
	b.SetBytes(1)
	for i := 0; i < b.N; i++ {
		FNV1A(medKey)
	}
}

func Benchmark_Meiyan______MedKey(b *testing.B) {
	b.SetBytes(1)
	for i := 0; i < b.N; i++ {
		Meiyan(medKey)
	}
}

func Benchmark_Jesteress___MedKey(b *testing.B) {
	b.SetBytes(1)
	for i := 0; i < b.N; i++ {
		Jesteress(medKey)
	}
}

func Benchmark_Yorikke_____MedKey(b *testing.B) {
	b.SetBytes(1)
	for i := 0; i < b.N; i++ {
		Yorikke(medKey)
	}
}
<|endoftext|>


<commit_before>package hashicorp

import (
	"bytes"
	"fmt"
	"io"
	"sync/atomic"
	"time"

	"golang.org/x/net/context"

	"github.com/Sirupsen/logrus"
	"github.com/hashicorp/go-msgpack/codec"
	hraft "github.com/hashicorp/raft"
	"github.com/relab/raft"
	"github.com/relab/raft/commonpb"
)

type future struct {
	apply hraft.ApplyFuture
	index hraft.IndexFuture
	res   chan raft.Result
	start time.Time
	lat   *raft.Latency
}

func (f *future) ResultCh() <-chan raft.Result {
	go func() {
		confChange := false
		var g hraft.Future = f.apply
		if g == nil {
			confChange = true
			g = f.index
		}
		err := g.Error()

		if err != nil {
			f.res <- raft.Result{
				Value: err,
			}
			return
		}

		f.lat.Record(f.start)

		if !confChange {
			f.res <- raft.Result{
				Index: f.apply.Index(),
				Value: f.apply.Response(),
			}
			return
		}
		f.res <- raft.Result{
			Index: f.index.Index(),
			Value: &commonpb.ReconfResponse{
				Status: commonpb.ReconfOK,
			},
		}
	}()

	return f.res
}

// Wrapper wraps a hashicorp/raft.Raft and implements relab/raft.Raft.
type Wrapper struct {
	id      hraft.ServerID
	n       *hraft.Raft
	sm      raft.StateMachine
	servers []hraft.Server
	conf    hraft.Configuration
	lat     *raft.Latency
	event   *raft.Event
	leader  uint64
	logger  logrus.FieldLogger
}

func NewRaft(logger logrus.FieldLogger,
	sm raft.StateMachine, cfg *hraft.Config, servers []hraft.Server, trans hraft.Transport,
	logs hraft.LogStore, stable hraft.StableStore, snaps hraft.SnapshotStore,
	enabled []uint64,
	lat *raft.Latency, event *raft.Event,
	leaderOut chan struct{},
	id uint64,
	checkQuorum bool,
) *Wrapper {
	w := &Wrapper{
		id:      cfg.LocalID,
		sm:      sm,
		servers: servers,
		lat:     lat,
		event:   event,
		logger:  logger,
	}

	node, err := hraft.NewRaft(cfg, w, logs, stable, snaps, trans, event, checkQuorum)
	if err != nil {
		panic(err)
	}

	voters := make([]hraft.Server, len(enabled))

	for i, id := range enabled {
		voters[i] = servers[id-1]
	}

	w.conf = hraft.Configuration{Servers: voters}

	if servers[id-1].Suffrage == hraft.Voter {
		f := node.BootstrapCluster(w.conf)
		if err := f.Error(); err != nil {
			panic(err)
		}
	}

	w.n = node
	rmetrics.leader.Set(0)

	go func() {
		for {
			if <-node.LeaderCh() {
				atomic.StoreUint64(&w.leader, 1)
				event.Record(raft.EventBecomeLeader)
				rmetrics.leader.Set(float64(id))
				select {
				case leaderOut <- struct{}{}:
					w.logger.Warnln("Sent become leader")
				default:
					w.logger.Warnln("Skipped sending become leader")
				}
			} else {
				atomic.StoreUint64(&w.leader, 0)
				rmetrics.leader.Set(0)
			}
		}
	}()

	return w
}

func (w *Wrapper) ProposeCmd(ctx context.Context, req []byte) (raft.Future, error) {
	deadline, _ := ctx.Deadline()
	timeout := time.Until(deadline)
	ff := &future{lat: w.lat, start: time.Now(), res: make(chan raft.Result, 1)}
	ff.apply = w.n.Apply(req, timeout)

	return ff, nil
}

func (w *Wrapper) ReadCmd(context.Context, []byte) (raft.Future, error) {
	panic("ReadCmd not implemented")
}

func (w *Wrapper) ProposeConf(ctx context.Context, req *commonpb.ReconfRequest) (raft.Future, error) {
	deadline, _ := ctx.Deadline()
	timeout := time.Until(deadline)
	server := w.servers[req.ServerID-1]
	ff := &future{lat: w.lat, start: time.Now(), res: make(chan raft.Result, 1)}

	switch req.ReconfType {
	case commonpb.ReconfAdd:
		w.event.Record(raft.EventProposeAddServer)
		ff.index = w.n.AddVoter(server.ID, server.Address, 0, timeout)
	case commonpb.ReconfRemove:
		w.event.Record(raft.EventProposeRemoveServer)
		ff.index = w.n.RemoveServer(server.ID, 0, timeout)
	default:
		panic("invalid reconf type")
	}

	return ff, nil
}

func (w *Wrapper) Apply(logentry *hraft.Log) interface{} {
	rmetrics.commitIndex.Set(float64(logentry.Index))
	if atomic.LoadUint64(&w.leader) != 1 {
		w.lat.Record(time.Now())
	}

	switch logentry.Type {
	case hraft.LogCommand:
		res := w.sm.Apply(&commonpb.Entry{
			Term:      logentry.Term,
			Index:     logentry.Index,
			EntryType: commonpb.EntryNormal,
			Data:      logentry.Data,
		})
		return res
	case hraft.LogConfiguration:
		var configuration hraft.Configuration
		if err := decodeMsgPack(logentry.Data, &configuration); err != nil {
			panic(fmt.Errorf("failed to decode configuration: %v", err))
		}
		w.logger.WithField("Configuration", configuration).Warnln("Configuration change")
		// If the server didn't have a vote in the previous conf., but
		// have a vote in the new configuration, this follower have
		// recently been added and are now caught up.
		if !hasVote(w.conf, w.id) && hasVote(configuration, w.id) {
			w.event.Record(raft.EventCaughtUp)
		}
		if len(w.conf.Servers) < len(configuration.Servers) {
			w.event.Record(raft.EventAdded)
		} else {
			w.event.Record(raft.EventRemoved)
		}
		w.conf = configuration
		return nil
	}

	panic(fmt.Sprintf("no case for logtype: %v", logentry.Type))
}

func (w *Wrapper) Snapshot() (hraft.FSMSnapshot, error) { return &snapStore{}, nil }
func (w *Wrapper) Restore(io.ReadCloser) error          { return nil }

type snapStore struct{}

func (s *snapStore) Persist(sink hraft.SnapshotSink) error { return nil }
func (s *snapStore) Release()                              {}

// Decode reverses the encode operation on a byte slice input.
// From hashicorp/raft/util.go.
func decodeMsgPack(buf []byte, out interface{}) error {
	r := bytes.NewBuffer(buf)
	hd := codec.MsgpackHandle{}
	dec := codec.NewDecoder(r, &hd)
	return dec.Decode(out)
}

// hasVote returns true if the server identified by 'id' is a Voter in the
// provided Configuration.
// From hashicorp/raft/configuration.go.
func hasVote(configuration hraft.Configuration, id hraft.ServerID) bool {
	for _, server := range configuration.Servers {
		if server.ID == id {
			return server.Suffrage == hraft.Voter
		}
	}
	return false
}
<commit_msg>hashicorp/raft.go: Fix reconf. entries not applied to state machine<commit_after>package hashicorp

import (
	"bytes"
	"io"
	"sync/atomic"
	"time"

	"golang.org/x/net/context"

	"github.com/Sirupsen/logrus"
	"github.com/hashicorp/go-msgpack/codec"
	hraft "github.com/hashicorp/raft"
	"github.com/relab/raft"
	"github.com/relab/raft/commonpb"
)

type future struct {
	apply hraft.ApplyFuture
	index hraft.IndexFuture
	res   chan raft.Result
	start time.Time
	lat   *raft.Latency
	event *raft.Event
}

func (f *future) ResultCh() <-chan raft.Result {
	go func() {
		confChange := false
		var g hraft.Future = f.apply
		if g == nil {
			confChange = true
			g = f.index
		}
		err := g.Error()

		if err != nil {
			f.res <- raft.Result{
				Value: err,
			}
			return
		}

		f.lat.Record(f.start)

		if !confChange {
			f.res <- raft.Result{
				Index: f.apply.Index(),
				Value: f.apply.Response(),
			}
			return
		}
		// If recorded on the server being added, this is also the
		// caught up event.
		f.event.Record(raft.EventAdded)
		f.res <- raft.Result{
			Index: f.index.Index(),
			Value: &commonpb.ReconfResponse{
				Status: commonpb.ReconfOK,
			},
		}
	}()

	return f.res
}

// Wrapper wraps a hashicorp/raft.Raft and implements relab/raft.Raft.
type Wrapper struct {
	id      hraft.ServerID
	n       *hraft.Raft
	sm      raft.StateMachine
	servers []hraft.Server
	conf    hraft.Configuration
	lat     *raft.Latency
	event   *raft.Event
	leader  uint64
	logger  logrus.FieldLogger
}

func NewRaft(logger logrus.FieldLogger,
	sm raft.StateMachine, cfg *hraft.Config, servers []hraft.Server, trans hraft.Transport,
	logs hraft.LogStore, stable hraft.StableStore, snaps hraft.SnapshotStore,
	enabled []uint64,
	lat *raft.Latency, event *raft.Event,
	leaderOut chan struct{},
	id uint64,
	checkQuorum bool,
) *Wrapper {
	w := &Wrapper{
		id:      cfg.LocalID,
		sm:      sm,
		servers: servers,
		lat:     lat,
		event:   event,
		logger:  logger,
	}

	node, err := hraft.NewRaft(cfg, w, logs, stable, snaps, trans, event, checkQuorum)
	if err != nil {
		panic(err)
	}

	voters := make([]hraft.Server, len(enabled))

	for i, id := range enabled {
		voters[i] = servers[id-1]
	}

	w.conf = hraft.Configuration{Servers: voters}

	if servers[id-1].Suffrage == hraft.Voter {
		f := node.BootstrapCluster(w.conf)
		if err := f.Error(); err != nil {
			panic(err)
		}
	}

	w.n = node
	rmetrics.leader.Set(0)

	go func() {
		for {
			if <-node.LeaderCh() {
				atomic.StoreUint64(&w.leader, 1)
				event.Record(raft.EventBecomeLeader)
				rmetrics.leader.Set(float64(id))
				select {
				case leaderOut <- struct{}{}:
					w.logger.Warnln("Sent become leader")
				default:
					w.logger.Warnln("Skipped sending become leader")
				}
			} else {
				atomic.StoreUint64(&w.leader, 0)
				rmetrics.leader.Set(0)
			}
		}
	}()

	return w
}

func (w *Wrapper) ProposeCmd(ctx context.Context, req []byte) (raft.Future, error) {
	deadline, _ := ctx.Deadline()
	timeout := time.Until(deadline)
	ff := &future{lat: w.lat, start: time.Now(), res: make(chan raft.Result, 1)}
	ff.apply = w.n.Apply(req, timeout)

	return ff, nil
}

func (w *Wrapper) ReadCmd(context.Context, []byte) (raft.Future, error) {
	panic("ReadCmd not implemented")
}

func (w *Wrapper) ProposeConf(ctx context.Context, req *commonpb.ReconfRequest) (raft.Future, error) {
	deadline, _ := ctx.Deadline()
	timeout := time.Until(deadline)
	server := w.servers[req.ServerID-1]
	ff := &future{event: w.event, lat: w.lat, start: time.Now(), res: make(chan raft.Result, 1)}

	switch req.ReconfType {
	case commonpb.ReconfAdd:
		w.event.Record(raft.EventProposeAddServer)
		ff.index = w.n.AddVoter(server.ID, server.Address, 0, timeout)
	case commonpb.ReconfRemove:
		w.event.Record(raft.EventProposeRemoveServer)
		ff.index = w.n.RemoveServer(server.ID, 0, timeout)
	default:
		panic("invalid reconf type")
	}

	return ff, nil
}

func (w *Wrapper) Apply(logentry *hraft.Log) interface{} {
	rmetrics.commitIndex.Set(float64(logentry.Index))
	if atomic.LoadUint64(&w.leader) != 1 {
		w.lat.Record(time.Now())
	}

	res := w.sm.Apply(&commonpb.Entry{
		Term:      logentry.Term,
		Index:     logentry.Index,
		EntryType: commonpb.EntryNormal,
		Data:      logentry.Data,
	})
	return res
}

func (w *Wrapper) Snapshot() (hraft.FSMSnapshot, error) { return &snapStore{}, nil }
func (w *Wrapper) Restore(io.ReadCloser) error          { return nil }

type snapStore struct{}

func (s *snapStore) Persist(sink hraft.SnapshotSink) error { return nil }
func (s *snapStore) Release()                              {}

// Decode reverses the encode operation on a byte slice input.
// From hashicorp/raft/util.go.
func decodeMsgPack(buf []byte, out interface{}) error {
	r := bytes.NewBuffer(buf)
	hd := codec.MsgpackHandle{}
	dec := codec.NewDecoder(r, &hd)
	return dec.Decode(out)
}

// hasVote returns true if the server identified by 'id' is a Voter in the
// provided Configuration.
// From hashicorp/raft/configuration.go.
func hasVote(configuration hraft.Configuration, id hraft.ServerID) bool {
	for _, server := range configuration.Servers {
		if server.ID == id {
			return server.Suffrage == hraft.Voter
		}
	}
	return false
}
<|endoftext|>


<commit_before>package db

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/url"
	"strings"

	"github.com/ponzu-cms/ponzu/system/admin/config"

	"github.com/boltdb/bolt"
	"github.com/gorilla/schema"
)

var configCache url.Values

func init() {
	configCache = make(url.Values)
}

// SetConfig sets key:value pairs in the db for configuration settings
func SetConfig(data url.Values) error {
	err := store.Update(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte("__config"))

		// check for any multi-value fields (ex. checkbox fields)
		// and correctly format for db storage. Essentially, we need
		// fieldX.0: value1, fieldX.1: value2 => fieldX: []string{value1, value2}
		var discardKeys []string
		for k, v := range data {
			if strings.Contains(k, ".") {
				key := strings.Split(k, ".")[0]

				if data.Get(key) == "" {
					data.Set(key, v[0])
				} else {
					data.Add(key, v[0])
				}

				discardKeys = append(discardKeys, k)
			}
		}

		for _, discardKey := range discardKeys {
			data.Del(discardKey)
		}

		cfg := &config.Config{}
		dec := schema.NewDecoder()
		dec.SetAliasTag("json")     // allows simpler struct tagging when creating a content type
		dec.IgnoreUnknownKeys(true) // will skip over form values submitted, but not in struct
		err := dec.Decode(cfg, data)
		if err != nil {
			return err
		}

		// check for "invalidate" value to reset the Etag
		if len(cfg.CacheInvalidate) > 0 && cfg.CacheInvalidate[0] == "invalidate" {
			cfg.Etag = NewEtag()
			cfg.CacheInvalidate = []string{}
		}

		j, err := json.Marshal(cfg)
		if err != nil {
			return err
		}

		err = b.Put([]byte("settings"), j)
		if err != nil {
			return err
		}

		return nil
	})
	if err != nil {
		return err
	}

	configCache = data

	return nil
}

// Config gets the value of a key in the configuration from the db
func Config(key string) ([]byte, error) {
	kv := make(map[string]interface{})

	cfg, err := ConfigAll()
	if err != nil {
		return nil, err
	}

	if len(cfg) < 1 {
		return nil, nil
	}

	err = json.Unmarshal(cfg, &kv)
	if err != nil {
		return nil, err
	}

	return []byte(kv[key].(string)), nil
}

// ConfigAll gets the configuration from the db
func ConfigAll() ([]byte, error) {
	val := &bytes.Buffer{}
	err := store.View(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte("__config"))
		if b == nil {
			return fmt.Errorf("Error finding bucket: %s", "__config")
		}
		_, err := val.Write(b.Get([]byte("settings")))
		if err != nil {
			return err
		}

		return nil
	})
	if err != nil {
		return nil, err
	}

	return val.Bytes(), nil
}

// PutConfig updates a single k/v in the config
func PutConfig(key string, value interface{}) error {
	kv := make(map[string]interface{})

	c, err := ConfigAll()
	if err != nil {
		return err
	}

	if c == nil {
		return nil
	}

	err = json.Unmarshal(c, &kv)
	if err != nil {
		return err
	}

	// set k/v from params to decoded map
	kv[key] = value

	data := make(url.Values)
	for k, v := range kv {
		switch v.(type) {
		case string:
			data.Set(k, v.(string))

		case []string:
			vv := v.([]string)
			for i := range vv {
				data.Add(k, vv[i])
			}

		default:
			data.Set(k, fmt.Sprintf("%v", v))
		}
	}

	err = SetConfig(data)
	if err != nil {
		return err
	}

	return nil
}

// ConfigCache is a in-memory cache of the Configs for quicker lookups
// 'key' is the JSON tag associated with the config field
func ConfigCache(key string) interface{} {
	return configCache.Get(key)
}

// LoadCacheConfig loads the config into a cache to be accessed by ConfigCache()
func LoadCacheConfig() error {
	c, err := ConfigAll()
	if err != nil {
		return err
	}

	if c == nil {
		configCache = make(url.Values)
		return nil
	}

	// convert json => map[string]interface{} => url.Values
	var kv map[string]interface{}
	err = json.Unmarshal(c, &kv)
	if err != nil {
		return err
	}

	data := make(url.Values)
	for k, v := range kv {
		switch v.(type) {
		case []string:
			s := v.([]string)
			for i := range s {
				if i == 0 {
					data.Set(k, s[i])
				}

				data.Add(k, s[i])
			}
		default:
			data.Set(k, fmt.Sprintf("%v", v))
		}
	}

	configCache = data

	return nil
}
<commit_msg>adding empty config helper in case config has no data<commit_after>package db

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/url"
	"strings"

	"github.com/ponzu-cms/ponzu/system/admin/config"

	"github.com/boltdb/bolt"
	"github.com/gorilla/schema"
)

var configCache url.Values

func init() {
	configCache = make(url.Values)
}

// SetConfig sets key:value pairs in the db for configuration settings
func SetConfig(data url.Values) error {
	err := store.Update(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte("__config"))

		// check for any multi-value fields (ex. checkbox fields)
		// and correctly format for db storage. Essentially, we need
		// fieldX.0: value1, fieldX.1: value2 => fieldX: []string{value1, value2}
		var discardKeys []string
		for k, v := range data {
			if strings.Contains(k, ".") {
				key := strings.Split(k, ".")[0]

				if data.Get(key) == "" {
					data.Set(key, v[0])
				} else {
					data.Add(key, v[0])
				}

				discardKeys = append(discardKeys, k)
			}
		}

		for _, discardKey := range discardKeys {
			data.Del(discardKey)
		}

		cfg := &config.Config{}
		dec := schema.NewDecoder()
		dec.SetAliasTag("json")     // allows simpler struct tagging when creating a content type
		dec.IgnoreUnknownKeys(true) // will skip over form values submitted, but not in struct
		err := dec.Decode(cfg, data)
		if err != nil {
			return err
		}

		// check for "invalidate" value to reset the Etag
		if len(cfg.CacheInvalidate) > 0 && cfg.CacheInvalidate[0] == "invalidate" {
			cfg.Etag = NewEtag()
			cfg.CacheInvalidate = []string{}
		}

		j, err := json.Marshal(cfg)
		if err != nil {
			return err
		}

		err = b.Put([]byte("settings"), j)
		if err != nil {
			return err
		}

		return nil
	})
	if err != nil {
		return err
	}

	configCache = data

	return nil
}

// Config gets the value of a key in the configuration from the db
func Config(key string) ([]byte, error) {
	kv := make(map[string]interface{})

	cfg, err := ConfigAll()
	if err != nil {
		return nil, err
	}

	if len(cfg) < 1 {
		return nil, nil
	}

	err = json.Unmarshal(cfg, &kv)
	if err != nil {
		return nil, err
	}

	return []byte(kv[key].(string)), nil
}

// ConfigAll gets the configuration from the db
func ConfigAll() ([]byte, error) {
	val := &bytes.Buffer{}
	err := store.View(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte("__config"))
		if b == nil {
			return fmt.Errorf("Error finding bucket: %s", "__config")
		}
		_, err := val.Write(b.Get([]byte("settings")))
		if err != nil {
			return err
		}

		return nil
	})
	if err != nil {
		return nil, err
	}

	return val.Bytes(), nil
}

// PutConfig updates a single k/v in the config
func PutConfig(key string, value interface{}) error {
	kv := make(map[string]interface{})

	c, err := ConfigAll()
	if err != nil {
		return err
	}

	if c == nil {
		c, err = emptyConfig()
		if err != nil {
			return err
		}
	}

	err = json.Unmarshal(c, &kv)
	if err != nil {
		return err
	}

	// set k/v from params to decoded map
	kv[key] = value

	data := make(url.Values)
	for k, v := range kv {
		switch v.(type) {
		case string:
			data.Set(k, v.(string))

		case []string:
			vv := v.([]string)
			for i := range vv {
				data.Add(k, vv[i])
			}

		default:
			data.Set(k, fmt.Sprintf("%v", v))
		}
	}

	err = SetConfig(data)
	if err != nil {
		return err
	}

	return nil
}

// ConfigCache is a in-memory cache of the Configs for quicker lookups
// 'key' is the JSON tag associated with the config field
func ConfigCache(key string) interface{} {
	return configCache.Get(key)
}

// LoadCacheConfig loads the config into a cache to be accessed by ConfigCache()
func LoadCacheConfig() error {
	c, err := ConfigAll()
	if err != nil {
		return err
	}

	if c == nil {
		c, err = emptyConfig()
		if err != nil {
			return err
		}
	}

	// convert json => map[string]interface{} => url.Values
	var kv map[string]interface{}
	err = json.Unmarshal(c, &kv)
	if err != nil {
		return err
	}

	data := make(url.Values)
	for k, v := range kv {
		switch v.(type) {
		case []string:
			s := v.([]string)
			for i := range s {
				if i == 0 {
					data.Set(k, s[i])
				}

				data.Add(k, s[i])
			}
		default:
			data.Set(k, fmt.Sprintf("%v", v))
		}
	}

	configCache = data

	return nil
}

func emptyConfig() ([]byte, error) {
	cfg := &config.Config{}

	data, err := json.Marshal(cfg)
	if err != nil {
		return nil, err
	}

	return data, nil
}
<|endoftext|>


<commit_before>package main

import (
	"testing"
)

func TestNodeAddresses(t *testing.T) {
	testblob := "c4521f18b3e40291db6d4da1948ccc5776198a22"
	tests := []struct {
		in      StorageNode
		expaddr string
		expurl  string
	}{
		{StorageNode{Addr: "1.2.3.4", BindAddr: ":8484"},
			"1.2.3.4:8484",
			"http://1.2.3.4:8484/.cbfs/blob/c4521f18b3e40291db6d4da1948ccc5776198a22",
		},
		{StorageNode{Addr: "1.2.3.4", BindAddr: "5.6.7.8:8484"},
			"5.6.7.8:8484",
			"http://5.6.7.8:8484/.cbfs/blob/c4521f18b3e40291db6d4da1948ccc5776198a22",
		},
	}

	for _, test := range tests {
		if test.in.Address() != test.expaddr {
			t.Errorf("Expected %v for %v, got %v",
				test.expaddr, test.in, test.in.Address())
			t.Fail()
		}
		if test.in.BlobURL(testblob) != test.expurl {
			t.Errorf("Expected %v for %v, got %v",
				test.expurl, test.in, test.in.BlobURL(testblob))
			t.Fail()
		}
	}
}
<commit_msg>Test nano parsing.<commit_after>package main

import (
	"testing"
	"time"
)

func TestNodeAddresses(t *testing.T) {
	testblob := "c4521f18b3e40291db6d4da1948ccc5776198a22"
	tests := []struct {
		in      StorageNode
		expaddr string
		expurl  string
	}{
		{StorageNode{Addr: "1.2.3.4", BindAddr: ":8484"},
			"1.2.3.4:8484",
			"http://1.2.3.4:8484/.cbfs/blob/c4521f18b3e40291db6d4da1948ccc5776198a22",
		},
		{StorageNode{Addr: "1.2.3.4", BindAddr: "5.6.7.8:8484"},
			"5.6.7.8:8484",
			"http://5.6.7.8:8484/.cbfs/blob/c4521f18b3e40291db6d4da1948ccc5776198a22",
		},
	}

	for _, test := range tests {
		if test.in.Address() != test.expaddr {
			t.Errorf("Expected %v for %v, got %v",
				test.expaddr, test.in, test.in.Address())
			t.Fail()
		}
		if test.in.BlobURL(testblob) != test.expurl {
			t.Errorf("Expected %v for %v, got %v",
				test.expurl, test.in, test.in.BlobURL(testblob))
			t.Fail()
		}
	}
}

func TestDateParsing(t *testing.T) {
	tm, err := time.Parse(time.RFC3339Nano,
		"2012-09-17T22:12:09.894702Z")
	if err != nil {
		t.Fatalf("Error parsing time: %v", err)
	}
	exp, got := int64(1347919929894702000), tm.UnixNano()
	if exp != got {
		t.Fatalf("Expected %v, got %v", exp, got)
	}
}
<|endoftext|>


<commit_before>// Copyright 2016, RadiantBlue Technologies, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package uuidgen_systest

import (
	"testing"
	"time"

	uuidpkg "github.com/pborman/uuid"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/suite"
	"github.com/venicegeo/pz-gocommon/gocommon"
	"github.com/venicegeo/pz-uuidgen/uuidgen"
)

func sleep() {
	time.Sleep(1 * time.Second)
}

type UuidgenTester struct {
	suite.Suite
	client *uuidgen.Client
	url    string
	apiKey string
}

func (suite *UuidgenTester) setupFixture() {
	t := suite.T()
	assert := assert.New(t)

	var err error

	suite.url = "https://pz-uuidgen.int.geointservices.io"

	suite.apiKey, err = piazza.GetApiKey("int")
	assert.NoError(err)

	client, err := uuidgen.NewClient2(suite.url, suite.apiKey)
	assert.NoError(err)
	suite.client = client
}

func (suite *UuidgenTester) teardownFixture() {
}

func TestRunSuite(t *testing.T) {
	s := &UuidgenTester{}
	suite.Run(t, s)
}

func isValid(uuid string) bool {
	return uuidpkg.Parse(uuid) != nil
}

func (suite *UuidgenTester) TestGet() {
	t := suite.T()
	assert := assert.New(t)

	suite.setupFixture()
	defer suite.teardownFixture()

	client := suite.client

	uuid, err := client.GetUuid()
	assert.NoError(err)

	assert.True(isValid(uuid))
}

func (suite *UuidgenTester) TestPost() {
	t := suite.T()
	assert := assert.New(t)

	suite.setupFixture()
	defer suite.teardownFixture()

	client := suite.client

	uuids, err := client.PostUuids(17)
	assert.NoError(err)
	assert.Len(*uuids, 17)

	for i := 0; i < 17; i++ {
		a := (*uuids)[i]
		assert.True(isValid(a))
		for j := i + 1; j < 17; j++ {
			b := (*uuids)[j]
			assert.NotEqual(a, b)
		}
	}
}

func (suite *UuidgenTester) TestAdmin() {
	t := suite.T()
	assert := assert.New(t)

	suite.setupFixture()
	defer suite.teardownFixture()

	client := suite.client

	stats, err := client.GetStats()
	assert.NoError(err, "GetFromAdminStats")

	assert.NotZero(stats.NumUUIDs)
	assert.NotZero(stats.NumRequests)
}
<commit_msg>start of test app<commit_after>// Copyright 2016, RadiantBlue Technologies, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package workflow_systest

import (
	"strconv"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/suite"
	"github.com/venicegeo/pz-gocommon/elasticsearch"
	"github.com/venicegeo/pz-gocommon/gocommon"
	"github.com/venicegeo/pz-workflow/workflow"
)

func sleep() {
	time.Sleep(1 * time.Second)
}

type WorkflowTester struct {
	suite.Suite
	client *workflow.Client
	url    string
	apiKey string
}

func (suite *WorkflowTester) setupFixture() {
	t := suite.T()
	assert := assert.New(t)

	var err error

	suite.url = "https://pz-workflow.int.geointservices.io"

	suite.apiKey, err = piazza.GetApiKey("int")
	assert.NoError(err)

	client, err := workflow.NewClient2(suite.url, suite.apiKey)
	assert.NoError(err)
	suite.client = client
}

func (suite *WorkflowTester) teardownFixture() {
}

func TestRunSuite(t *testing.T) {
	s := &WorkflowTester{}
	suite.Run(t, s)
}

func (suite *WorkflowTester) TestGet() {
	t := suite.T()
	assert := assert.New(t)

	suite.setupFixture()
	defer suite.teardownFixture()

	client := suite.client

	eventTypes, err := client.GetAllEventTypes()
	assert.NoError(err)

	assert.True(len(*eventTypes) > 1)
}

func (suite *WorkflowTester) TestPost() {
	t := suite.T()
	assert := assert.New(t)

	suite.setupFixture()
	defer suite.teardownFixture()

	client := suite.client

	uniq := "systest$" + strconv.Itoa(time.Now().Nanosecond())

	eventType := &workflow.EventType{
		Name: uniq,
		Mapping: map[string]elasticsearch.MappingElementTypeName{
			"filename": elasticsearch.MappingElementTypeString,
			"code":     elasticsearch.MappingElementTypeString,
			"severity": elasticsearch.MappingElementTypeInteger,
		},
	}

	ack, err := client.PostEventType(eventType)
	assert.NoError(err)
	assert.NotNil(ack)
}

func (suite *WorkflowTester) TestAdmin() {
	t := suite.T()
	assert := assert.New(t)

	suite.setupFixture()
	defer suite.teardownFixture()

	client := suite.client

	stats, err := client.GetStats()
	assert.NoError(err, "GetFromAdminStats")

	assert.NotZero(stats.NumEvents)
}
<|endoftext|>


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

package lxc

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"

	"launchpad.net/golxc"
	"launchpad.net/loggo"

	"launchpad.net/juju-core/agent/tools"
	"launchpad.net/juju-core/constraints"
	"launchpad.net/juju-core/environs"
	"launchpad.net/juju-core/environs/cloudinit"
	"launchpad.net/juju-core/environs/config"
	"launchpad.net/juju-core/instance"
	"launchpad.net/juju-core/state"
	"launchpad.net/juju-core/state/api"
)

var logger = loggo.GetLogger("juju.container.lxc")

var (
	defaultTemplate     = "ubuntu-cloud"
	containerDir        = "/var/lib/juju/containers"
	removedContainerDir = "/var/lib/juju/removed-containers"
	lxcContainerDir     = "/var/lib/lxc"
	lxcRestartDir       = "/etc/lxc/auto"
	lxcObjectFactory    = golxc.Factory()
)

const (
	// BridgeNetwork will have the container use the lxc bridge.
	bridgeNetwork = "bridge"
	// PhyscialNetwork will have the container use a specified network device.
	physicalNetwork = "physical"
	// DefaultLxcBridge is the package created container bridge
	DefaultLxcBridge = "lxcbr0"
)

// NetworkConfig defines how the container network will be configured.
type NetworkConfig struct {
	networkType string
	device      string
}

// DefaultNetworkConfig returns a valid NetworkConfig to use the
// defaultLxcBridge that is created by the lxc package.
func DefaultNetworkConfig() *NetworkConfig {
	return &NetworkConfig{bridgeNetwork, DefaultLxcBridge}
}

// BridgeNetworkConfig returns a valid NetworkConfig to use the specified
// device as a network bridge for the container.
func BridgeNetworkConfig(device string) *NetworkConfig {
	return &NetworkConfig{bridgeNetwork, device}
}

// PhysicalNetworkConfig returns a valid NetworkConfig to use the specified
// device as the network device for the container.
func PhysicalNetworkConfig(device string) *NetworkConfig {
	return &NetworkConfig{physicalNetwork, device}
}

// ManagerConfig contains the initialization parameters for the ContainerManager.
type ManagerConfig struct {
	Name   string
	LogDir string
}

// ContainerManager is responsible for starting containers, and stopping and
// listing containers that it has started.  The name of the manager is used to
// namespace the lxc containers on the machine.
type ContainerManager interface {
	// StartContainer creates and starts a new lxc container for the specified machine.
	StartContainer(
		machineId, series, nonce string,
		network *NetworkConfig,
		tools *tools.Tools,
		environConfig *config.Config,
		stateInfo *state.Info,
		apiInfo *api.Info) (instance.Instance, error)
	// StopContainer stops and destroyes the lxc container identified by Instance.
	StopContainer(instance.Instance) error
	// ListContainers return a list of containers that have been started by
	// this manager.
	ListContainers() ([]instance.Instance, error)
}

type containerManager struct {
	name   string
	logdir string
}

// NewContainerManager returns a manager object that can start and stop lxc
// containers. The containers that are created are namespaced by the name
// parameter.
func NewContainerManager(conf ManagerConfig) ContainerManager {
	logdir := "/var/log/juju"
	if conf.LogDir != "" {
		logdir = conf.LogDir
	}
	return &containerManager{name: conf.Name, logdir: logdir}
}

func (manager *containerManager) StartContainer(
	machineId, series, nonce string,
	network *NetworkConfig,
	tools *tools.Tools,
	environConfig *config.Config,
	stateInfo *state.Info,
	apiInfo *api.Info) (instance.Instance, error) {

	name := state.MachineTag(machineId)
	if manager.name != "" {
		name = fmt.Sprintf("%s-%s", manager.name, name)
	}
	// Note here that the lxcObjectFacotry only returns a valid container
	// object, and doesn't actually construct the underlying lxc container on
	// disk.
	container := lxcObjectFactory.New(name)

	// Create the cloud-init.
	directory := jujuContainerDirectory(name)
	logger.Tracef("create directory: %s", directory)
	if err := os.MkdirAll(directory, 0755); err != nil {
		logger.Errorf("failed to create container directory: %v", err)
		return nil, err
	}
	logger.Tracef("write cloud-init")
	userDataFilename, err := writeUserData(directory, machineId, nonce, tools, environConfig, stateInfo, apiInfo)
	if err != nil {
		logger.Errorf("failed to write user data: %v", err)
		return nil, err
	}
	logger.Tracef("write the lxc.conf file")
	configFile, err := writeLxcConfig(network, directory, manager.logdir)
	if err != nil {
		logger.Errorf("failed to write config file: %v", err)
		return nil, err
	}
	templateParams := []string{
		"--debug",                      // Debug errors in the cloud image
		"--userdata", userDataFilename, // Our groovey cloud-init
		"--hostid", name, // Use the container name as the hostid
		"-r", series,
	}
	// Create the container.
	logger.Tracef("create the container")
	if err := container.Create(configFile, defaultTemplate, templateParams...); err != nil {
		logger.Errorf("lxc container creation failed: %v", err)
		return nil, err
	}
	// Make sure that the mount dir has been created.
	logger.Tracef("make the mount dir for the shard logs")
	if err := os.MkdirAll(internalLogDir(name), 0755); err != nil {
		logger.Errorf("failed to create internal /var/log/juju mount dir: %v", err)
		return nil, err
	}
	logger.Tracef("lxc container created")
	// Now symlink the config file into the restart directory.
	containerConfigFile := filepath.Join(lxcContainerDir, name, "config")
	if err := os.Symlink(containerConfigFile, restartSymlink(name)); err != nil {
		return nil, err
	}
	logger.Tracef("auto-restart link created")

	// Start the lxc container with the appropriate settings for grabbing the
	// console output and a log file.
	consoleFile := filepath.Join(directory, "console.log")
	container.SetLogFile(filepath.Join(directory, "container.log"), golxc.LogDebug)
	logger.Tracef("start the container")
	// We explicitly don't pass through the config file to the container.Start
	// method as we have passed it through at container creation time.  This
	// is necessary to get the appropriate rootfs reference without explicitly
	// setting it ourselves.
	if err = container.Start("", consoleFile); err != nil {
		logger.Errorf("container failed to start: %v", err)
		return nil, err
	}
	logger.Tracef("container started")
	return &lxcInstance{name}, nil
}

func (manager *containerManager) StopContainer(instance instance.Instance) error {
	name := string(instance.Id())
	container := lxcObjectFactory.New(name)
	if err := container.Stop(); err != nil {
		logger.Errorf("failed to stop lxc container: %v", err)
		return err
	}
	// Destroy removes the restart symlink for us.
	if err := container.Destroy(); err != nil {
		logger.Errorf("failed to destroy lxc container: %v", err)
		return err
	}

	// Move the directory.
	logger.Tracef("create old container dir: %s", removedContainerDir)
	if err := os.MkdirAll(removedContainerDir, 0755); err != nil {
		logger.Errorf("failed to create removed container directory: %v", err)
		return err
	}
	removedDir, err := uniqueDirectory(removedContainerDir, name)
	if err != nil {
		logger.Errorf("was not able to generate a unique directory: %v", err)
		return err
	}
	if err := os.Rename(jujuContainerDirectory(name), removedDir); err != nil {
		logger.Errorf("failed to rename container directory: %v", err)
		return err
	}
	return nil
}

func (manager *containerManager) ListContainers() (result []instance.Instance, err error) {
	containers, err := lxcObjectFactory.List()
	if err != nil {
		logger.Errorf("failed getting all instances: %v", err)
		return
	}
	managerPrefix := ""
	if manager.name != "" {
		managerPrefix = fmt.Sprintf("%s-", manager.name)
	}

	for _, container := range containers {
		// Filter out those not starting with our name.
		name := container.Name()
		if !strings.HasPrefix(name, managerPrefix) {
			continue
		}
		if container.IsRunning() {
			result = append(result, &lxcInstance{name})
		}
	}
	return
}

func jujuContainerDirectory(containerName string) string {
	return filepath.Join(containerDir, containerName)
}

const internalLogDirTemplate = "%s/%s/rootfs/var/log/juju"

func internalLogDir(containerName string) string {
	return fmt.Sprintf(internalLogDirTemplate, lxcContainerDir, containerName)
}

func restartSymlink(name string) string {
	return filepath.Join(lxcRestartDir, name+".conf")
}

const localConfig = `%s
lxc.mount.entry=%s var/log/juju none defaults,bind 0 0
`

const networkTemplate = `
lxc.network.type = %s
lxc.network.link = %s
lxc.network.flags = up
`

func networkConfigTemplate(networkType, networkLink string) string {
	return fmt.Sprintf(networkTemplate, networkType, networkLink)
}

func generateNetworkConfig(network *NetworkConfig) string {
	if network == nil {
		logger.Warningf("network unspecified, using default networking config")
		network = DefaultNetworkConfig()
	}
	switch network.networkType {
	case physicalNetwork:
		return networkConfigTemplate("phys", network.device)
	default:
		logger.Warningf("Unknown network config type %q: using bridge", network.networkType)
		fallthrough
	case bridgeNetwork:
		return networkConfigTemplate("veth", network.device)
	}
	panic("unreachable")
}

func writeLxcConfig(network *NetworkConfig, directory, logdir string) (string, error) {
	networkConfig := generateNetworkConfig(network)
	configFilename := filepath.Join(directory, "lxc.conf")
	configContent := fmt.Sprintf(localConfig, networkConfig, logdir)
	if err := ioutil.WriteFile(configFilename, []byte(configContent), 0644); err != nil {
		return "", err
	}
	return configFilename, nil
}

func writeUserData(
	directory, machineId, nonce string,
	tools *tools.Tools,
	environConfig *config.Config,
	stateInfo *state.Info,
	apiInfo *api.Info,
) (string, error) {
	userData, err := cloudInitUserData(machineId, nonce, tools, environConfig, stateInfo, apiInfo)
	if err != nil {
		logger.Errorf("failed to create user data: %v", err)
		return "", err
	}
	userDataFilename := filepath.Join(directory, "cloud-init")
	if err := ioutil.WriteFile(userDataFilename, userData, 0644); err != nil {
		logger.Errorf("failed to write user data: %v", err)
		return "", err
	}
	return userDataFilename, nil
}

func cloudInitUserData(
	machineId, nonce string,
	tools *tools.Tools,
	environConfig *config.Config,
	stateInfo *state.Info,
	apiInfo *api.Info,
) ([]byte, error) {
	machineConfig := &cloudinit.MachineConfig{
		MachineId:            machineId,
		MachineNonce:         nonce,
		MachineContainerType: instance.LXC,
		StateInfo:            stateInfo,
		APIInfo:              apiInfo,
		DataDir:              "/var/lib/juju",
		Tools:                tools,
	}
	if err := environs.FinishMachineConfig(machineConfig, environConfig, constraints.Value{}); err != nil {
		return nil, err
	}
	cloudConfig, err := cloudinit.New(machineConfig)
	if err != nil {
		return nil, err
	}
	data, err := cloudConfig.Render()
	if err != nil {
		return nil, err
	}
	return data, nil
}

// uniqueDirectory returns "path/name" if that directory doesn't exist.  If it
// does, the method starts appending .1, .2, etc until a unique name is found.
func uniqueDirectory(path, name string) (string, error) {
	dir := filepath.Join(path, name)
	_, err := os.Stat(dir)
	if os.IsNotExist(err) {
		return dir, nil
	}
	for i := 1; ; i++ {
		dir := filepath.Join(path, fmt.Sprintf("%s.%d", name, i))
		_, err := os.Stat(dir)
		if os.IsNotExist(err) {
			return dir, nil
		} else if err != nil {
			return "", err
		}
	}
	panic("unreachable")
}
<commit_msg>Get the lxc cloud init script to run ifconfig to log the ip addresses.<commit_after>// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package lxc

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"

	"launchpad.net/golxc"
	"launchpad.net/loggo"

	"launchpad.net/juju-core/agent/tools"
	"launchpad.net/juju-core/constraints"
	"launchpad.net/juju-core/environs"
	"launchpad.net/juju-core/environs/cloudinit"
	"launchpad.net/juju-core/environs/config"
	"launchpad.net/juju-core/instance"
	"launchpad.net/juju-core/state"
	"launchpad.net/juju-core/state/api"
)

var logger = loggo.GetLogger("juju.container.lxc")

var (
	defaultTemplate     = "ubuntu-cloud"
	containerDir        = "/var/lib/juju/containers"
	removedContainerDir = "/var/lib/juju/removed-containers"
	lxcContainerDir     = "/var/lib/lxc"
	lxcRestartDir       = "/etc/lxc/auto"
	lxcObjectFactory    = golxc.Factory()
)

const (
	// BridgeNetwork will have the container use the lxc bridge.
	bridgeNetwork = "bridge"
	// PhyscialNetwork will have the container use a specified network device.
	physicalNetwork = "physical"
	// DefaultLxcBridge is the package created container bridge
	DefaultLxcBridge = "lxcbr0"
)

// NetworkConfig defines how the container network will be configured.
type NetworkConfig struct {
	networkType string
	device      string
}

// DefaultNetworkConfig returns a valid NetworkConfig to use the
// defaultLxcBridge that is created by the lxc package.
func DefaultNetworkConfig() *NetworkConfig {
	return &NetworkConfig{bridgeNetwork, DefaultLxcBridge}
}

// BridgeNetworkConfig returns a valid NetworkConfig to use the specified
// device as a network bridge for the container.
func BridgeNetworkConfig(device string) *NetworkConfig {
	return &NetworkConfig{bridgeNetwork, device}
}

// PhysicalNetworkConfig returns a valid NetworkConfig to use the specified
// device as the network device for the container.
func PhysicalNetworkConfig(device string) *NetworkConfig {
	return &NetworkConfig{physicalNetwork, device}
}

// ManagerConfig contains the initialization parameters for the ContainerManager.
type ManagerConfig struct {
	Name   string
	LogDir string
}

// ContainerManager is responsible for starting containers, and stopping and
// listing containers that it has started.  The name of the manager is used to
// namespace the lxc containers on the machine.
type ContainerManager interface {
	// StartContainer creates and starts a new lxc container for the specified machine.
	StartContainer(
		machineId, series, nonce string,
		network *NetworkConfig,
		tools *tools.Tools,
		environConfig *config.Config,
		stateInfo *state.Info,
		apiInfo *api.Info) (instance.Instance, error)
	// StopContainer stops and destroyes the lxc container identified by Instance.
	StopContainer(instance.Instance) error
	// ListContainers return a list of containers that have been started by
	// this manager.
	ListContainers() ([]instance.Instance, error)
}

type containerManager struct {
	name   string
	logdir string
}

// NewContainerManager returns a manager object that can start and stop lxc
// containers. The containers that are created are namespaced by the name
// parameter.
func NewContainerManager(conf ManagerConfig) ContainerManager {
	logdir := "/var/log/juju"
	if conf.LogDir != "" {
		logdir = conf.LogDir
	}
	return &containerManager{name: conf.Name, logdir: logdir}
}

func (manager *containerManager) StartContainer(
	machineId, series, nonce string,
	network *NetworkConfig,
	tools *tools.Tools,
	environConfig *config.Config,
	stateInfo *state.Info,
	apiInfo *api.Info) (instance.Instance, error) {

	name := state.MachineTag(machineId)
	if manager.name != "" {
		name = fmt.Sprintf("%s-%s", manager.name, name)
	}
	// Note here that the lxcObjectFacotry only returns a valid container
	// object, and doesn't actually construct the underlying lxc container on
	// disk.
	container := lxcObjectFactory.New(name)

	// Create the cloud-init.
	directory := jujuContainerDirectory(name)
	logger.Tracef("create directory: %s", directory)
	if err := os.MkdirAll(directory, 0755); err != nil {
		logger.Errorf("failed to create container directory: %v", err)
		return nil, err
	}
	logger.Tracef("write cloud-init")
	userDataFilename, err := writeUserData(directory, machineId, nonce, tools, environConfig, stateInfo, apiInfo)
	if err != nil {
		logger.Errorf("failed to write user data: %v", err)
		return nil, err
	}
	logger.Tracef("write the lxc.conf file")
	configFile, err := writeLxcConfig(network, directory, manager.logdir)
	if err != nil {
		logger.Errorf("failed to write config file: %v", err)
		return nil, err
	}
	templateParams := []string{
		"--debug",                      // Debug errors in the cloud image
		"--userdata", userDataFilename, // Our groovey cloud-init
		"--hostid", name, // Use the container name as the hostid
		"-r", series,
	}
	// Create the container.
	logger.Tracef("create the container")
	if err := container.Create(configFile, defaultTemplate, templateParams...); err != nil {
		logger.Errorf("lxc container creation failed: %v", err)
		return nil, err
	}
	// Make sure that the mount dir has been created.
	logger.Tracef("make the mount dir for the shard logs")
	if err := os.MkdirAll(internalLogDir(name), 0755); err != nil {
		logger.Errorf("failed to create internal /var/log/juju mount dir: %v", err)
		return nil, err
	}
	logger.Tracef("lxc container created")
	// Now symlink the config file into the restart directory.
	containerConfigFile := filepath.Join(lxcContainerDir, name, "config")
	if err := os.Symlink(containerConfigFile, restartSymlink(name)); err != nil {
		return nil, err
	}
	logger.Tracef("auto-restart link created")

	// Start the lxc container with the appropriate settings for grabbing the
	// console output and a log file.
	consoleFile := filepath.Join(directory, "console.log")
	container.SetLogFile(filepath.Join(directory, "container.log"), golxc.LogDebug)
	logger.Tracef("start the container")
	// We explicitly don't pass through the config file to the container.Start
	// method as we have passed it through at container creation time.  This
	// is necessary to get the appropriate rootfs reference without explicitly
	// setting it ourselves.
	if err = container.Start("", consoleFile); err != nil {
		logger.Errorf("container failed to start: %v", err)
		return nil, err
	}
	logger.Tracef("container started")
	return &lxcInstance{name}, nil
}

func (manager *containerManager) StopContainer(instance instance.Instance) error {
	name := string(instance.Id())
	container := lxcObjectFactory.New(name)
	if err := container.Stop(); err != nil {
		logger.Errorf("failed to stop lxc container: %v", err)
		return err
	}
	// Destroy removes the restart symlink for us.
	if err := container.Destroy(); err != nil {
		logger.Errorf("failed to destroy lxc container: %v", err)
		return err
	}

	// Move the directory.
	logger.Tracef("create old container dir: %s", removedContainerDir)
	if err := os.MkdirAll(removedContainerDir, 0755); err != nil {
		logger.Errorf("failed to create removed container directory: %v", err)
		return err
	}
	removedDir, err := uniqueDirectory(removedContainerDir, name)
	if err != nil {
		logger.Errorf("was not able to generate a unique directory: %v", err)
		return err
	}
	if err := os.Rename(jujuContainerDirectory(name), removedDir); err != nil {
		logger.Errorf("failed to rename container directory: %v", err)
		return err
	}
	return nil
}

func (manager *containerManager) ListContainers() (result []instance.Instance, err error) {
	containers, err := lxcObjectFactory.List()
	if err != nil {
		logger.Errorf("failed getting all instances: %v", err)
		return
	}
	managerPrefix := ""
	if manager.name != "" {
		managerPrefix = fmt.Sprintf("%s-", manager.name)
	}

	for _, container := range containers {
		// Filter out those not starting with our name.
		name := container.Name()
		if !strings.HasPrefix(name, managerPrefix) {
			continue
		}
		if container.IsRunning() {
			result = append(result, &lxcInstance{name})
		}
	}
	return
}

func jujuContainerDirectory(containerName string) string {
	return filepath.Join(containerDir, containerName)
}

const internalLogDirTemplate = "%s/%s/rootfs/var/log/juju"

func internalLogDir(containerName string) string {
	return fmt.Sprintf(internalLogDirTemplate, lxcContainerDir, containerName)
}

func restartSymlink(name string) string {
	return filepath.Join(lxcRestartDir, name+".conf")
}

const localConfig = `%s
lxc.mount.entry=%s var/log/juju none defaults,bind 0 0
`

const networkTemplate = `
lxc.network.type = %s
lxc.network.link = %s
lxc.network.flags = up
`

func networkConfigTemplate(networkType, networkLink string) string {
	return fmt.Sprintf(networkTemplate, networkType, networkLink)
}

func generateNetworkConfig(network *NetworkConfig) string {
	if network == nil {
		logger.Warningf("network unspecified, using default networking config")
		network = DefaultNetworkConfig()
	}
	switch network.networkType {
	case physicalNetwork:
		return networkConfigTemplate("phys", network.device)
	default:
		logger.Warningf("Unknown network config type %q: using bridge", network.networkType)
		fallthrough
	case bridgeNetwork:
		return networkConfigTemplate("veth", network.device)
	}
	panic("unreachable")
}

func writeLxcConfig(network *NetworkConfig, directory, logdir string) (string, error) {
	networkConfig := generateNetworkConfig(network)
	configFilename := filepath.Join(directory, "lxc.conf")
	configContent := fmt.Sprintf(localConfig, networkConfig, logdir)
	if err := ioutil.WriteFile(configFilename, []byte(configContent), 0644); err != nil {
		return "", err
	}
	return configFilename, nil
}

func writeUserData(
	directory, machineId, nonce string,
	tools *tools.Tools,
	environConfig *config.Config,
	stateInfo *state.Info,
	apiInfo *api.Info,
) (string, error) {
	userData, err := cloudInitUserData(machineId, nonce, tools, environConfig, stateInfo, apiInfo)
	if err != nil {
		logger.Errorf("failed to create user data: %v", err)
		return "", err
	}
	userDataFilename := filepath.Join(directory, "cloud-init")
	if err := ioutil.WriteFile(userDataFilename, userData, 0644); err != nil {
		logger.Errorf("failed to write user data: %v", err)
		return "", err
	}
	return userDataFilename, nil
}

func cloudInitUserData(
	machineId, nonce string,
	tools *tools.Tools,
	environConfig *config.Config,
	stateInfo *state.Info,
	apiInfo *api.Info,
) ([]byte, error) {
	machineConfig := &cloudinit.MachineConfig{
		MachineId:            machineId,
		MachineNonce:         nonce,
		MachineContainerType: instance.LXC,
		StateInfo:            stateInfo,
		APIInfo:              apiInfo,
		DataDir:              "/var/lib/juju",
		Tools:                tools,
	}
	if err := environs.FinishMachineConfig(machineConfig, environConfig, constraints.Value{}); err != nil {
		return nil, err
	}
	cloudConfig, err := cloudinit.New(machineConfig)
	if err != nil {
		return nil, err
	}
	// Run ifconfig to get the addresses of the internal container at least
	// logged in the host.
	cloudConfig.AddRunCmd("ifconfig")
	data, err := cloudConfig.Render()
	if err != nil {
		return nil, err
	}
	return data, nil
}

// uniqueDirectory returns "path/name" if that directory doesn't exist.  If it
// does, the method starts appending .1, .2, etc until a unique name is found.
func uniqueDirectory(path, name string) (string, error) {
	dir := filepath.Join(path, name)
	_, err := os.Stat(dir)
	if os.IsNotExist(err) {
		return dir, nil
	}
	for i := 1; ; i++ {
		dir := filepath.Join(path, fmt.Sprintf("%s.%d", name, i))
		_, err := os.Stat(dir)
		if os.IsNotExist(err) {
			return dir, nil
		} else if err != nil {
			return "", err
		}
	}
	panic("unreachable")
}
<|endoftext|>


<commit_before>package goku

import (
    "bytes"
    "encoding/json"
    "fmt"
    "net/http"
)

// http context
type HttpContext struct {
    Request        *http.Request       // http request
    responseWriter http.ResponseWriter // http response
    Method         string              // http method

    //self fields
    RouteData *RouteData             // route data
    ViewData  map[string]interface{} // view data for template
    Data      map[string]interface{} // data for httpcontex
    Result    ActionResulter         // action result
    Err       error                  // process error
    User      string                 // user name
    Canceled  bool                   // cancel continue process the request and return

    // private fileds
    requestHandler       *RequestHandler
    responseContentCache *bytes.Buffer // cache response content, will write at end request
    responseStatusCode   int           // cache response status code, will write at end request
    //responseHeaderCache  Header        // cache response header, will write at end request
}

func (ctx *HttpContext) flushToResponse() {
    // if len(ctx.responseHeaderCache) > 0 {
    // 	for k, v := range ctx.responseHeaderCache {
    // 		ctx.responseWriter.Header().Set(key, value)
    // 	}
    // }
    if ctx.responseStatusCode > 0 {
        ctx.responseWriter.WriteHeader(ctx.responseStatusCode)
    }
    if ctx.responseContentCache.Len() > 0 {
        ctx.responseContentCache.WriteTo(ctx.responseWriter)
    }
}

// Try not to use this unless you know exactly what you are doing
func (ctx *HttpContext) ResponseWriter() http.ResponseWriter {
    return ctx.responseWriter
}

// get the requert param,
// get from RouteData first,
// if no, get from Requet.FormValue
func (ctx *HttpContext) Get(name string) string {
    v, ok := ctx.RouteData.Get(name)
    if ok {
        return v
    }
    return ctx.Request.FormValue(name)
}

// get the response header
func (ctx *HttpContext) Header() http.Header {
    return ctx.responseWriter.Header()
}

// set the response header
func (ctx *HttpContext) SetHeader(key string, value string) {
    ctx.responseWriter.Header().Set(key, value)
    //ctx.responseHeaderCache.Set(key, value)
}

// add response header
func (ctx *HttpContext) AddHeader(key string, value string) {
    ctx.responseWriter.Header().Add(key, value)
}

// set response cookie header
func (ctx *HttpContext) SetCookie(cookie *http.Cookie) {
    ctx.responseWriter.Header().Add("Set-Cookie", cookie.String())
}

func (ctx *HttpContext) GetHeader(key string) string {
    return ctx.Request.Header.Get(key)
}

func (ctx *HttpContext) ContentType(ctype string) {
    ctx.responseWriter.Header().Set("Content-Type", ctype)
    //ctx.responseHeaderCache["Content-Type"] = ctype
}

func (ctx *HttpContext) Status(code int) {
    //ctx.responseWriter.WriteHeader(code)
    ctx.responseStatusCode = code
}

func (ctx *HttpContext) Write(b []byte) (int, error) {
    //return ctx.ResponseWriter.Write(b)
    return ctx.responseContentCache.Write(b)
}

func (ctx *HttpContext) WriteBuffer(bf *bytes.Buffer) {
    //bf.WriteTo(ctx.ResponseWriter)
    bf.WriteTo(ctx.responseContentCache)
}

func (ctx *HttpContext) WriteString(content string) {
    //ctx.ResponseWriter.Write([]byte(content))
    ctx.responseContentCache.Write([]byte(content))
}

func (ctx *HttpContext) WriteHeader(code int) {
    //ctx.responseWriter.WriteHeader(code)
    ctx.responseStatusCode = code
}

// get whether the request is by ajax
func (ctx *HttpContext) IsAjax() bool {
    return ctx.GetHeader("X-Requested-With") == "XMLHttpRequest"
}

// render the view and return a ActionResulter
// it will find the view in these rules:
//      1. /{ViewPath}/{Controller}/{viewName}
//      2. /{ViewPath}/shared/{viewName}
func (ctx *HttpContext) Render(viewName string, viewModel interface{}) ActionResulter {
    vr := &ViewResult{
        ViewEngine: ctx.requestHandler.ViewEnginer,
        ViewData:   ctx.ViewData,
        ViewModel:  viewModel,
        ViewName:   viewName,
    }
    vr.Body = new(bytes.Buffer)
    vr.Headers = map[string]string{"Content-Type": "text/html"}
    return vr
}

// render the view and return a ActionResulter
// it will find the view in these rules:
//      1. /{ViewPath}/{Controller}/{action}
//      2. /{ViewPath}/shared/{action}
func (ctx *HttpContext) View(viewData interface{}) ActionResulter {
    return ctx.Render("", viewData)
}

func (ctx *HttpContext) Redirect(url_ string) ActionResulter {
    return &ActionResult{
        StatusCode: http.StatusFound,
        Headers:    map[string]string{"Content-Type": "text/html", "Location": url_},
        Body:       bytes.NewBufferString("Redirecting to: " + url_),
    }
}

func (ctx *HttpContext) RedirectPermanent(url_ string) ActionResulter {
    return &ActionResult{
        StatusCode: http.StatusMovedPermanently,
        Headers:    map[string]string{"Content-Type": "text/html", "Location": url_},
        Body:       bytes.NewBufferString("Redirecting to: " + url_),
    }
}

// page not found
func (ctx *HttpContext) NotFound(message string) ActionResulter {
    if message == "" {
        message = "Page Not Found!"
    }
    return &ActionResult{
        StatusCode: http.StatusNotFound,
        Headers:    map[string]string{"Content-Type": "text/html"},
        Body:       bytes.NewBufferString(message),
    }
}

// content not modified
func (ctx *HttpContext) NotModified() ActionResulter {
    return &ActionResult{
        StatusCode: http.StatusNotModified,
    }
}

func (ctx *HttpContext) Error(err interface{}) ActionResulter {
    msg := fmt.Sprintf("%v", err)
    return &ActionResult{
        StatusCode: http.StatusInternalServerError,
        Headers:    map[string]string{"Content-Type": "text/plain"},
        Body:       bytes.NewBufferString(msg),
    }

}

func (ctx *HttpContext) Raw(data string) ActionResulter {
    return &ActionResult{
        StatusCode: http.StatusOK,
        Headers:    map[string]string{"Content-Type": "text/plain"},
        Body:       bytes.NewBufferString(data),
    }
}

func (ctx *HttpContext) Html(data string) ActionResulter {
    return &ActionResult{
        StatusCode: http.StatusOK,
        Headers:    map[string]string{"Content-Type": "text/html"},
        Body:       bytes.NewBufferString(data),
    }
}

// return json string result
// ctx.Json(obj) or ctx.Json(obj, "text/html")
func (ctx *HttpContext) Json(data interface{}, contentType ...string) ActionResulter {
    var ct string
    if len(contentType) == 1 {
        ct = contentType[0]
    } else {
        ct = "text/javascript"
    }
    ar := &ActionResult{
        StatusCode: http.StatusOK,
        Headers:    map[string]string{"Content-Type": ct},
        Body:       new(bytes.Buffer),
    }
    ec := json.NewEncoder(ar.Body)
    ec.Encode(data)
    return ar
}

// this.content = function(filename) {
//   return new ContentResult(filename);
// }
<commit_msg>cxt path<commit_after>package goku

import (
    "bytes"
    "encoding/json"
    "fmt"
    "net/http"
    "path"
)

// http context
type HttpContext struct {
    Request        *http.Request       // http request
    responseWriter http.ResponseWriter // http response
    Method         string              // http method

    //self fields
    RouteData *RouteData             // route data
    ViewData  map[string]interface{} // view data for template
    Data      map[string]interface{} // data for httpcontex
    Result    ActionResulter         // action result
    Err       error                  // process error
    User      string                 // user name
    Canceled  bool                   // cancel continue process the request and return

    // private fileds
    requestHandler       *RequestHandler
    responseContentCache *bytes.Buffer // cache response content, will write at end request
    responseStatusCode   int           // cache response status code, will write at end request
    //responseHeaderCache  Header        // cache response header, will write at end request
}

func (ctx *HttpContext) flushToResponse() {
    // if len(ctx.responseHeaderCache) > 0 {
    // 	for k, v := range ctx.responseHeaderCache {
    // 		ctx.responseWriter.Header().Set(key, value)
    // 	}
    // }
    if ctx.responseStatusCode > 0 {
        ctx.responseWriter.WriteHeader(ctx.responseStatusCode)
    }
    if ctx.responseContentCache.Len() > 0 {
        ctx.responseContentCache.WriteTo(ctx.responseWriter)
    }
}

// Try not to use this unless you know exactly what you are doing
func (ctx *HttpContext) ResponseWriter() http.ResponseWriter {
    return ctx.responseWriter
}

func (ctx *HttpContext) RootDir() string {
    return ctx.requestHandler.ServerConfig.RootDir
}

func (ctx *HttpContext) StaticPath() string {
    return path.Join(ctx.RootDir(), ctx.requestHandler.ServerConfig.StaticPath)
}

func (ctx *HttpContext) ViewPath() string {
    return path.Join(ctx.RootDir(), ctx.requestHandler.ServerConfig.ViewPath)
}

// get the requert param,
// get from RouteData first,
// if no, get from Requet.FormValue
func (ctx *HttpContext) Get(name string) string {
    v, ok := ctx.RouteData.Get(name)
    if ok {
        return v
    }
    return ctx.Request.FormValue(name)
}

// get the response header
func (ctx *HttpContext) Header() http.Header {
    return ctx.responseWriter.Header()
}

// set the response header
func (ctx *HttpContext) SetHeader(key string, value string) {
    ctx.responseWriter.Header().Set(key, value)
    //ctx.responseHeaderCache.Set(key, value)
}

// add response header
func (ctx *HttpContext) AddHeader(key string, value string) {
    ctx.responseWriter.Header().Add(key, value)
}

// set response cookie header
func (ctx *HttpContext) SetCookie(cookie *http.Cookie) {
    ctx.responseWriter.Header().Add("Set-Cookie", cookie.String())
}

func (ctx *HttpContext) GetHeader(key string) string {
    return ctx.Request.Header.Get(key)
}

func (ctx *HttpContext) ContentType(ctype string) {
    ctx.responseWriter.Header().Set("Content-Type", ctype)
    //ctx.responseHeaderCache["Content-Type"] = ctype
}

func (ctx *HttpContext) Status(code int) {
    //ctx.responseWriter.WriteHeader(code)
    ctx.responseStatusCode = code
}

func (ctx *HttpContext) Write(b []byte) (int, error) {
    //return ctx.ResponseWriter.Write(b)
    return ctx.responseContentCache.Write(b)
}

func (ctx *HttpContext) WriteBuffer(bf *bytes.Buffer) {
    //bf.WriteTo(ctx.ResponseWriter)
    bf.WriteTo(ctx.responseContentCache)
}

func (ctx *HttpContext) WriteString(content string) {
    //ctx.ResponseWriter.Write([]byte(content))
    ctx.responseContentCache.Write([]byte(content))
}

func (ctx *HttpContext) WriteHeader(code int) {
    //ctx.responseWriter.WriteHeader(code)
    ctx.responseStatusCode = code
}

// get whether the request is by ajax
func (ctx *HttpContext) IsAjax() bool {
    return ctx.GetHeader("X-Requested-With") == "XMLHttpRequest"
}

// render the view and return a ActionResulter
// it will find the view in these rules:
//      1. /{ViewPath}/{Controller}/{viewName}
//      2. /{ViewPath}/shared/{viewName}
func (ctx *HttpContext) Render(viewName string, viewModel interface{}) ActionResulter {
    vr := &ViewResult{
        ViewEngine: ctx.requestHandler.ViewEnginer,
        ViewData:   ctx.ViewData,
        ViewModel:  viewModel,
        ViewName:   viewName,
    }
    vr.Body = new(bytes.Buffer)
    vr.Headers = map[string]string{"Content-Type": "text/html"}
    return vr
}

// render the view and return a ActionResulter
// it will find the view in these rules:
//      1. /{ViewPath}/{Controller}/{action}
//      2. /{ViewPath}/shared/{action}
func (ctx *HttpContext) View(viewData interface{}) ActionResulter {
    return ctx.Render("", viewData)
}

func (ctx *HttpContext) Redirect(url_ string) ActionResulter {
    return &ActionResult{
        StatusCode: http.StatusFound,
        Headers:    map[string]string{"Content-Type": "text/html", "Location": url_},
        Body:       bytes.NewBufferString("Redirecting to: " + url_),
    }
}

func (ctx *HttpContext) RedirectPermanent(url_ string) ActionResulter {
    return &ActionResult{
        StatusCode: http.StatusMovedPermanently,
        Headers:    map[string]string{"Content-Type": "text/html", "Location": url_},
        Body:       bytes.NewBufferString("Redirecting to: " + url_),
    }
}

// page not found
func (ctx *HttpContext) NotFound(message string) ActionResulter {
    if message == "" {
        message = "Page Not Found!"
    }
    return &ActionResult{
        StatusCode: http.StatusNotFound,
        Headers:    map[string]string{"Content-Type": "text/html"},
        Body:       bytes.NewBufferString(message),
    }
}

// content not modified
func (ctx *HttpContext) NotModified() ActionResulter {
    return &ActionResult{
        StatusCode: http.StatusNotModified,
    }
}

func (ctx *HttpContext) Error(err interface{}) ActionResulter {
    msg := fmt.Sprintf("%v", err)
    return &ActionResult{
        StatusCode: http.StatusInternalServerError,
        Headers:    map[string]string{"Content-Type": "text/plain"},
        Body:       bytes.NewBufferString(msg),
    }

}

func (ctx *HttpContext) Raw(data string) ActionResulter {
    return &ActionResult{
        StatusCode: http.StatusOK,
        Headers:    map[string]string{"Content-Type": "text/plain"},
        Body:       bytes.NewBufferString(data),
    }
}

func (ctx *HttpContext) Html(data string) ActionResulter {
    return &ActionResult{
        StatusCode: http.StatusOK,
        Headers:    map[string]string{"Content-Type": "text/html"},
        Body:       bytes.NewBufferString(data),
    }
}

// return json string result
// ctx.Json(obj) or ctx.Json(obj, "text/html")
func (ctx *HttpContext) Json(data interface{}, contentType ...string) ActionResulter {
    var ct string
    if len(contentType) == 1 {
        ct = contentType[0]
    } else {
        ct = "text/javascript"
    }
    ar := &ActionResult{
        StatusCode: http.StatusOK,
        Headers:    map[string]string{"Content-Type": ct},
        Body:       new(bytes.Buffer),
    }
    ec := json.NewEncoder(ar.Body)
    ec.Encode(data)
    return ar
}

// this.content = function(filename) {
//   return new ContentResult(filename);
// }
<|endoftext|>


<commit_before>// Copyright 2016 Burak Sezer
//
// 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 httptimeout

import (
	"crypto/tls"
	"net"
	"net/http"
	"time"
)

// Conn wraps a net.Conn, and sets a deadline for every read
// and write operation.
type Conn struct {
	net.Conn
	ReadTimeout  time.Duration
	WriteTimeout time.Duration
}

// Read wraps the net.Conn's original Read method.
func (c *Conn) Read(b []byte) (int, error) {
	err := c.Conn.SetReadDeadline(time.Now().Add(c.ReadTimeout))
	if err != nil {
		return 0, err
	}
	return c.Conn.Read(b)
}

// Write wraps the net.Conn's original Write method.
func (c *Conn) Write(b []byte) (int, error) {
	err := c.Conn.SetWriteDeadline(time.Now().Add(c.WriteTimeout))
	if err != nil {
		return 0, err
	}
	return c.Conn.Write(b)
}

// NewTransport returns http/Transport instance with timeout support
func NewTransport(addr string, timeout time.Duration) *http.Transport {
	t := &http.Transport{}
	t.Dial = func(network, addr string) (net.Conn, error) {
		conn, err := net.DialTimeout(network, addr, timeout)
		if err != nil {
			return nil, err
		}
		tc := &Conn{
			Conn:         conn,
			ReadTimeout:  timeout,
			WriteTimeout: timeout,
		}
		return tc, nil
	}
	return t
}

// Listener wraps a net.Listener, and gives a place to store the timeout
// parameters. On Accept, it will wrap the net.Conn with our own Conn for us.
type Listener struct {
	net.Listener
	ReadTimeout  time.Duration
	WriteTimeout time.Duration
}

// Accept wraps the Accept method of the original Listener. It waits for the next call and returns
// a Conn which wraps the net.Conn with timeout.
func (l *Listener) Accept() (net.Conn, error) {
	c, err := l.Listener.Accept()
	if err != nil {
		return nil, err
	}
	tc := &Conn{
		Conn:         c,
		ReadTimeout:  l.ReadTimeout,
		WriteTimeout: l.WriteTimeout,
	}
	return tc, nil
}

// NewListener runs net.Listen and announces on the network address addr with timeout.
// The network net must be a stream-oriented network: "tcp", "tcp4", "tcp6", "unix" or "unixpacket".
// For TCP and UDP, the syntax of addr is "host:port", like "127.0.0.1:8080".
// If host is omitted, as in ":8080", Listen listens on all available interfaces instead of just the interface with the
// given host address.
func NewListener(network, addr string, readTimeout, writeTimeout time.Duration) (net.Listener, error) {
	conn, err := net.Listen(network, addr)
	if err != nil {
		return nil, err
	}

	tl := &Listener{
		Listener:     conn,
		ReadTimeout:  readTimeout,
		WriteTimeout: writeTimeout,
	}
	return tl, nil
}

// NewListenerTLS is just a TLS enabled version of NewListener.
func NewListenerTLS(network, addr, certFile, keyFile string, readTimeout, writeTimeout time.Duration) (net.Listener, error) {
	config := &tls.Config{}
	if config.NextProtos == nil {
		config.NextProtos = []string{"http/1.1"}
	}

	var err error
	config.Certificates = make([]tls.Certificate, 1)
	config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
	if err != nil {
		return nil, err
	}

	conn, err := net.Listen(network, addr)
	if err != nil {
		return nil, err
	}
	tl := &Listener{
		Listener:     tls.NewListener(conn, config),
		ReadTimeout:  readTimeout,
		WriteTimeout: writeTimeout,
	}
	return tl, nil
}
<commit_msg>use different read/write timeout values<commit_after>// Copyright 2016 Burak Sezer
//
// 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 httptimeout

import (
	"crypto/tls"
	"net"
	"net/http"
	"time"
)

// Conn wraps a net.Conn, and sets a deadline for every read
// and write operation.
type Conn struct {
	net.Conn
	ReadTimeout  time.Duration
	WriteTimeout time.Duration
}

// Read wraps the net.Conn's original Read method.
func (c *Conn) Read(b []byte) (int, error) {
	err := c.Conn.SetReadDeadline(time.Now().Add(c.ReadTimeout))
	if err != nil {
		return 0, err
	}
	return c.Conn.Read(b)
}

// Write wraps the net.Conn's original Write method.
func (c *Conn) Write(b []byte) (int, error) {
	err := c.Conn.SetWriteDeadline(time.Now().Add(c.WriteTimeout))
	if err != nil {
		return 0, err
	}
	return c.Conn.Write(b)
}

// NewTransport returns http/Transport instance with timeout support
func NewTransport(addr string, readTimeout, writeTimeout time.Duration) *http.Transport {
	t := &http.Transport{}
	t.Dial = func(network, addr string) (net.Conn, error) {
		conn, err := net.DialTimeout(network, addr, readTimeout)
		if err != nil {
			return nil, err
		}
		tc := &Conn{
			Conn:         conn,
			ReadTimeout:  readTimeout,
			WriteTimeout: writeTimeout,
		}
		return tc, nil
	}
	return t
}

// Listener wraps a net.Listener, and gives a place to store the timeout
// parameters. On Accept, it will wrap the net.Conn with our own Conn for us.
type Listener struct {
	net.Listener
	ReadTimeout  time.Duration
	WriteTimeout time.Duration
}

// Accept wraps the Accept method of the original Listener. It waits for the next call and returns
// a Conn which wraps the net.Conn with timeout.
func (l *Listener) Accept() (net.Conn, error) {
	c, err := l.Listener.Accept()
	if err != nil {
		return nil, err
	}
	tc := &Conn{
		Conn:         c,
		ReadTimeout:  l.ReadTimeout,
		WriteTimeout: l.WriteTimeout,
	}
	return tc, nil
}

// NewListener runs net.Listen and announces on the network address addr with timeout.
// The network net must be a stream-oriented network: "tcp", "tcp4", "tcp6", "unix" or "unixpacket".
// For TCP and UDP, the syntax of addr is "host:port", like "127.0.0.1:8080".
// If host is omitted, as in ":8080", Listen listens on all available interfaces instead of just the interface with the
// given host address.
func NewListener(network, addr string, readTimeout, writeTimeout time.Duration) (net.Listener, error) {
	conn, err := net.Listen(network, addr)
	if err != nil {
		return nil, err
	}

	tl := &Listener{
		Listener:     conn,
		ReadTimeout:  readTimeout,
		WriteTimeout: writeTimeout,
	}
	return tl, nil
}

// NewListenerTLS is just a TLS enabled version of NewListener.
func NewListenerTLS(network, addr, certFile, keyFile string, readTimeout, writeTimeout time.Duration) (net.Listener, error) {
	config := &tls.Config{}
	if config.NextProtos == nil {
		config.NextProtos = []string{"http/1.1"}
	}

	var err error
	config.Certificates = make([]tls.Certificate, 1)
	config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
	if err != nil {
		return nil, err
	}

	conn, err := net.Listen(network, addr)
	if err != nil {
		return nil, err
	}
	tl := &Listener{
		Listener:     tls.NewListener(conn, config),
		ReadTimeout:  readTimeout,
		WriteTimeout: writeTimeout,
	}
	return tl, nil
}
<|endoftext|>