<commit_before>// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package logging

import (
	"bufio"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"sync"
	"time"

	"github.com/ava-labs/avalanchego/utils/constants"
)

var (
	filePrefix = fmt.Sprintf("%s/", constants.AppName)
)

// Log ...
type Log struct {
	config Config

	messages []string
	size     int

	wg                               sync.WaitGroup
	flushLock, writeLock, configLock sync.Mutex
	needsFlush                       *sync.Cond

	closed bool

	writer RotatingWriter
}

// New ...
func New(config Config) (*Log, error) {
	if err := os.MkdirAll(config.Directory, os.ModePerm); err != nil {
		return nil, err
	}
	l := &Log{
		config: config,
		writer: &fileWriter{},
	}
	l.needsFlush = sync.NewCond(&l.flushLock)

	l.wg.Add(1)

	go l.RecoverAndPanic(l.run)

	return l, nil
}

func (l *Log) run() {
	defer l.wg.Done()

	l.writeLock.Lock()
	defer l.writeLock.Unlock()

	currentSize, err := l.writer.Initialize(l.config)
	if err != nil {
		panic(err)
	}

	closed := false
	nextRotation := time.Now().Add(l.config.RotationInterval)

	for !closed {
		l.writeLock.Unlock()
		l.flushLock.Lock()
		for l.size < l.config.FlushSize && !l.closed {
			l.needsFlush.Wait()
		}
		closed = l.closed
		prevMessages := l.messages
		l.messages = nil
		l.size = 0
		l.flushLock.Unlock()
		l.writeLock.Lock()

		for _, msg := range prevMessages {
			n, _ := l.writer.WriteString(msg)
			currentSize += n
		}

		if !l.config.DisableFlushOnWrite {
			// attempt to flush after the write
			_ = l.writer.Flush()
		}

		if now := time.Now(); nextRotation.Before(now) || currentSize > l.config.FileSize {
			nextRotation = now.Add(l.config.RotationInterval)
			currentSize = 0
			// attempt to flush before closing
			_ = l.writer.Flush()
			// attempt to close the file
			_ = l.writer.Close()

			if err := l.writer.Rotate(l.config.RotationSize); err != nil {
				panic(err)
			}
		}
	}
	// attempt to flush when exiting
	_ = l.writer.Flush()
	// attempt to close the file when exiting
	_ = l.writer.Close()
}

func (l *Log) Write(p []byte) (int, error) {
	if l == nil {
		return 0, nil
	}

	l.configLock.Lock()
	defer l.configLock.Unlock()

	if !l.config.DisableLogging {
		l.flushLock.Lock()
		l.messages = append(l.messages, string(p))
		l.size += len(p)
		l.needsFlush.Signal()
		l.flushLock.Unlock()
	}

	return len(p), nil
}

// Stop ...
func (l *Log) Stop() {
	l.flushLock.Lock()
	l.closed = true
	l.needsFlush.Signal()
	l.flushLock.Unlock()

	l.wg.Wait()
}

// Should only be called from [Level] functions.
func (l *Log) log(level Level, format string, args ...interface{}) {
	if l == nil {
		return
	}

	l.configLock.Lock()
	defer l.configLock.Unlock()

	shouldLog := !l.config.DisableLogging && level <= l.config.LogLevel
	shouldDisplay := (!l.config.DisableDisplaying && level <= l.config.DisplayLevel) || level == Fatal

	if !shouldLog && !shouldDisplay {
		return
	}

	output := l.format(level, format, args...)

	if shouldLog {
		l.flushLock.Lock()
		l.messages = append(l.messages, output)
		l.size += len(output)
		l.needsFlush.Signal()
		l.flushLock.Unlock()
	}

	if shouldDisplay {
		switch {
		case l.config.DisableContextualDisplaying:
			fmt.Println(fmt.Sprintf(format, args...))
		case l.config.DisplayHighlight == Plain:
			fmt.Print(output)
		default:
			fmt.Print(level.Color().Wrap(output))
		}
	}
}

func (l *Log) format(level Level, format string, args ...interface{}) string {
	loc := "?"
	if _, file, no, ok := runtime.Caller(3); ok {
		loc = fmt.Sprintf("%s#%d", file, no)
	}
	if i := strings.Index(loc, filePrefix); i != -1 {
		loc = loc[i+len(filePrefix):]
	}
	text := fmt.Sprintf("%s: %s", loc, fmt.Sprintf(format, args...))

	prefix := ""
	if l.config.MsgPrefix != "" {
		prefix = fmt.Sprintf(" <%s>", l.config.MsgPrefix)
	}

	return fmt.Sprintf("%s[%s]%s %s\n",
		level,
		time.Now().Format("01-02|15:04:05"),
		prefix,
		text)
}

// Fatal ...
func (l *Log) Fatal(format string, args ...interface{}) { l.log(Fatal, format, args...) }

// Error ...
func (l *Log) Error(format string, args ...interface{}) { l.log(Error, format, args...) }

// Warn ...
func (l *Log) Warn(format string, args ...interface{}) { l.log(Warn, format, args...) }

// Info ...
func (l *Log) Info(format string, args ...interface{}) { l.log(Info, format, args...) }

// Debug ...
func (l *Log) Debug(format string, args ...interface{}) { l.log(Debug, format, args...) }

// Verbo ...
func (l *Log) Verbo(format string, args ...interface{}) { l.log(Verbo, format, args...) }

// AssertNoError ...
func (l *Log) AssertNoError(err error) {
	if err != nil {
		l.log(Fatal, "%s", err)
	}
	if l.config.Assertions && err != nil {
		l.Stop()
		panic(err)
	}
}

// AssertTrue ...
func (l *Log) AssertTrue(b bool, format string, args ...interface{}) {
	if !b {
		l.log(Fatal, format, args...)
	}
	if l.config.Assertions && !b {
		l.Stop()
		panic(fmt.Sprintf(format, args...))
	}
}

// AssertDeferredTrue ...
func (l *Log) AssertDeferredTrue(f func() bool, format string, args ...interface{}) {
	// Note, the logger will only be notified here if assertions are enabled
	if l.config.Assertions && !f() {
		err := fmt.Sprintf(format, args...)
		l.log(Fatal, err)
		l.Stop()
		panic(err)
	}
}

// AssertDeferredNoError ...
func (l *Log) AssertDeferredNoError(f func() error) {
	if l.config.Assertions {
		err := f()
		if err != nil {
			l.log(Fatal, "%s", err)
		}
		if l.config.Assertions && err != nil {
			l.Stop()
			panic(err)
		}
	}
}

// StopOnPanic ...
func (l *Log) StopOnPanic() {
	if r := recover(); r != nil {
		l.Fatal("Panicing due to:\n%s\nFrom:\n%s", r, Stacktrace{})
		l.Stop()
		panic(r)
	}
}

// RecoverAndPanic ...
func (l *Log) RecoverAndPanic(f func()) { defer l.StopOnPanic(); f() }

func (l *Log) stopAndExit(exit func()) {
	if r := recover(); r != nil {
		l.Fatal("Panicing due to:\n%s\nFrom:\n%s", r, Stacktrace{})
		l.Stop()
		exit()
	}
}

// RecoverAndExit ...
func (l *Log) RecoverAndExit(f, exit func()) { defer l.stopAndExit(exit); f() }

// SetLogLevel ...
func (l *Log) SetLogLevel(lvl Level) {
	l.configLock.Lock()
	defer l.configLock.Unlock()

	l.config.LogLevel = lvl
}

// SetDisplayLevel ...
func (l *Log) SetDisplayLevel(lvl Level) {
	l.configLock.Lock()
	defer l.configLock.Unlock()

	l.config.DisplayLevel = lvl
}

// SetPrefix ...
func (l *Log) SetPrefix(prefix string) {
	l.configLock.Lock()
	defer l.configLock.Unlock()

	l.config.MsgPrefix = prefix
}

// SetLoggingEnabled ...
func (l *Log) SetLoggingEnabled(enabled bool) {
	l.configLock.Lock()
	defer l.configLock.Unlock()

	l.config.DisableLogging = !enabled
}

// SetDisplayingEnabled ...
func (l *Log) SetDisplayingEnabled(enabled bool) {
	l.configLock.Lock()
	defer l.configLock.Unlock()

	l.config.DisableDisplaying = !enabled
}

// SetContextualDisplayingEnabled ...
func (l *Log) SetContextualDisplayingEnabled(enabled bool) {
	l.configLock.Lock()
	defer l.configLock.Unlock()

	l.config.DisableContextualDisplaying = !enabled
}

type fileWriter struct {
	writer *bufio.Writer
	file   *os.File

	config Config
}

func (fw *fileWriter) Flush() error {
	return fw.writer.Flush()
}

func (fw *fileWriter) Write(b []byte) (int, error) {
	return fw.writer.Write(b)
}

func (fw *fileWriter) WriteString(s string) (int, error) {
	return fw.writer.WriteString(s)
}

func (fw *fileWriter) Close() error {
	return fw.file.Close()
}

func (fw *fileWriter) Rotate(RotationSize int) error {
	for i := RotationSize - 1; i >= 0; i-- {
		sourceFilename := filepath.Join(fw.config.Directory, fmt.Sprintf("%s.log.%d", fw.config.LoggerName, i))
		destFilename := filepath.Join(fw.config.Directory, fmt.Sprintf("%s.log.%d", fw.config.LoggerName, i+1))
		if _, err := os.Stat(sourceFilename); !os.IsNotExist(err) {
			os.Rename(sourceFilename, destFilename)
		}
	}
	sourceFilename := filepath.Join(fw.config.Directory, fmt.Sprintf("%s.log", fw.config.LoggerName))
	destFilename := filepath.Join(fw.config.Directory, fmt.Sprintf("%s.log.1", fw.config.LoggerName))
	os.Rename(sourceFilename, destFilename)
	writer, file, err := fw.create()
	if err != nil {
		return err
	}
	fw.file = file
	fw.writer = writer
	return nil
}

func (fw *fileWriter) create() (*bufio.Writer, *os.File, error) {
	filename := filepath.Join(fw.config.Directory, fmt.Sprintf("%s.log", fw.config.LoggerName))
	file, err := os.OpenFile(filename, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
	if err != nil {
		return nil, nil, err
	}
	writer := bufio.NewWriter(file)
	return writer, file, nil
}

func (fw *fileWriter) Initialize(config Config) (int, error) {
	fw.config = config
	writer, file, err := fw.create()
	if err != nil {
		return 0, err
	}
	fw.writer = writer
	fw.file = file
	fileSize, err := file.Seek(0, io.SeekEnd)
	if err != nil {
		return 0, err
	}
	return int(fileSize), nil
}
<commit_msg>Fix typo in log message format<commit_after>// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package logging

import (
	"bufio"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"sync"
	"time"

	"github.com/ava-labs/avalanchego/utils/constants"
)

var (
	filePrefix = fmt.Sprintf("%s/", constants.AppName)
)

// Log ...
type Log struct {
	config Config

	messages []string
	size     int

	wg                               sync.WaitGroup
	flushLock, writeLock, configLock sync.Mutex
	needsFlush                       *sync.Cond

	closed bool

	writer RotatingWriter
}

// New ...
func New(config Config) (*Log, error) {
	if err := os.MkdirAll(config.Directory, os.ModePerm); err != nil {
		return nil, err
	}
	l := &Log{
		config: config,
		writer: &fileWriter{},
	}
	l.needsFlush = sync.NewCond(&l.flushLock)

	l.wg.Add(1)

	go l.RecoverAndPanic(l.run)

	return l, nil
}

func (l *Log) run() {
	defer l.wg.Done()

	l.writeLock.Lock()
	defer l.writeLock.Unlock()

	currentSize, err := l.writer.Initialize(l.config)
	if err != nil {
		panic(err)
	}

	closed := false
	nextRotation := time.Now().Add(l.config.RotationInterval)

	for !closed {
		l.writeLock.Unlock()
		l.flushLock.Lock()
		for l.size < l.config.FlushSize && !l.closed {
			l.needsFlush.Wait()
		}
		closed = l.closed
		prevMessages := l.messages
		l.messages = nil
		l.size = 0
		l.flushLock.Unlock()
		l.writeLock.Lock()

		for _, msg := range prevMessages {
			n, _ := l.writer.WriteString(msg)
			currentSize += n
		}

		if !l.config.DisableFlushOnWrite {
			// attempt to flush after the write
			_ = l.writer.Flush()
		}

		if now := time.Now(); nextRotation.Before(now) || currentSize > l.config.FileSize {
			nextRotation = now.Add(l.config.RotationInterval)
			currentSize = 0
			// attempt to flush before closing
			_ = l.writer.Flush()
			// attempt to close the file
			_ = l.writer.Close()

			if err := l.writer.Rotate(l.config.RotationSize); err != nil {
				panic(err)
			}
		}
	}
	// attempt to flush when exiting
	_ = l.writer.Flush()
	// attempt to close the file when exiting
	_ = l.writer.Close()
}

func (l *Log) Write(p []byte) (int, error) {
	if l == nil {
		return 0, nil
	}

	l.configLock.Lock()
	defer l.configLock.Unlock()

	if !l.config.DisableLogging {
		l.flushLock.Lock()
		l.messages = append(l.messages, string(p))
		l.size += len(p)
		l.needsFlush.Signal()
		l.flushLock.Unlock()
	}

	return len(p), nil
}

// Stop ...
func (l *Log) Stop() {
	l.flushLock.Lock()
	l.closed = true
	l.needsFlush.Signal()
	l.flushLock.Unlock()

	l.wg.Wait()
}

// Should only be called from [Level] functions.
func (l *Log) log(level Level, format string, args ...interface{}) {
	if l == nil {
		return
	}

	l.configLock.Lock()
	defer l.configLock.Unlock()

	shouldLog := !l.config.DisableLogging && level <= l.config.LogLevel
	shouldDisplay := (!l.config.DisableDisplaying && level <= l.config.DisplayLevel) || level == Fatal

	if !shouldLog && !shouldDisplay {
		return
	}

	output := l.format(level, format, args...)

	if shouldLog {
		l.flushLock.Lock()
		l.messages = append(l.messages, output)
		l.size += len(output)
		l.needsFlush.Signal()
		l.flushLock.Unlock()
	}

	if shouldDisplay {
		switch {
		case l.config.DisableContextualDisplaying:
			fmt.Println(fmt.Sprintf(format, args...))
		case l.config.DisplayHighlight == Plain:
			fmt.Print(output)
		default:
			fmt.Print(level.Color().Wrap(output))
		}
	}
}

func (l *Log) format(level Level, format string, args ...interface{}) string {
	loc := "?"
	if _, file, no, ok := runtime.Caller(3); ok {
		loc = fmt.Sprintf("%s#%d", file, no)
	}
	if i := strings.Index(loc, filePrefix); i != -1 {
		loc = loc[i+len(filePrefix):]
	}
	text := fmt.Sprintf("%s: %s", loc, fmt.Sprintf(format, args...))

	prefix := ""
	if l.config.MsgPrefix != "" {
		prefix = fmt.Sprintf(" <%s>", l.config.MsgPrefix)
	}

	return fmt.Sprintf("%s[%s]%s %s\n",
		level,
		time.Now().Format("01-02|15:04:05"),
		prefix,
		text)
}

// Fatal ...
func (l *Log) Fatal(format string, args ...interface{}) { l.log(Fatal, format, args...) }

// Error ...
func (l *Log) Error(format string, args ...interface{}) { l.log(Error, format, args...) }

// Warn ...
func (l *Log) Warn(format string, args ...interface{}) { l.log(Warn, format, args...) }

// Info ...
func (l *Log) Info(format string, args ...interface{}) { l.log(Info, format, args...) }

// Debug ...
func (l *Log) Debug(format string, args ...interface{}) { l.log(Debug, format, args...) }

// Verbo ...
func (l *Log) Verbo(format string, args ...interface{}) { l.log(Verbo, format, args...) }

// AssertNoError ...
func (l *Log) AssertNoError(err error) {
	if err != nil {
		l.log(Fatal, "%s", err)
	}
	if l.config.Assertions && err != nil {
		l.Stop()
		panic(err)
	}
}

// AssertTrue ...
func (l *Log) AssertTrue(b bool, format string, args ...interface{}) {
	if !b {
		l.log(Fatal, format, args...)
	}
	if l.config.Assertions && !b {
		l.Stop()
		panic(fmt.Sprintf(format, args...))
	}
}

// AssertDeferredTrue ...
func (l *Log) AssertDeferredTrue(f func() bool, format string, args ...interface{}) {
	// Note, the logger will only be notified here if assertions are enabled
	if l.config.Assertions && !f() {
		err := fmt.Sprintf(format, args...)
		l.log(Fatal, err)
		l.Stop()
		panic(err)
	}
}

// AssertDeferredNoError ...
func (l *Log) AssertDeferredNoError(f func() error) {
	if l.config.Assertions {
		err := f()
		if err != nil {
			l.log(Fatal, "%s", err)
		}
		if l.config.Assertions && err != nil {
			l.Stop()
			panic(err)
		}
	}
}

// StopOnPanic ...
func (l *Log) StopOnPanic() {
	if r := recover(); r != nil {
		l.Fatal("Panicking due to:\n%s\nFrom:\n%s", r, Stacktrace{})
		l.Stop()
		panic(r)
	}
}

// RecoverAndPanic ...
func (l *Log) RecoverAndPanic(f func()) { defer l.StopOnPanic(); f() }

func (l *Log) stopAndExit(exit func()) {
	if r := recover(); r != nil {
		l.Fatal("Panicking due to:\n%s\nFrom:\n%s", r, Stacktrace{})
		l.Stop()
		exit()
	}
}

// RecoverAndExit ...
func (l *Log) RecoverAndExit(f, exit func()) { defer l.stopAndExit(exit); f() }

// SetLogLevel ...
func (l *Log) SetLogLevel(lvl Level) {
	l.configLock.Lock()
	defer l.configLock.Unlock()

	l.config.LogLevel = lvl
}

// SetDisplayLevel ...
func (l *Log) SetDisplayLevel(lvl Level) {
	l.configLock.Lock()
	defer l.configLock.Unlock()

	l.config.DisplayLevel = lvl
}

// SetPrefix ...
func (l *Log) SetPrefix(prefix string) {
	l.configLock.Lock()
	defer l.configLock.Unlock()

	l.config.MsgPrefix = prefix
}

// SetLoggingEnabled ...
func (l *Log) SetLoggingEnabled(enabled bool) {
	l.configLock.Lock()
	defer l.configLock.Unlock()

	l.config.DisableLogging = !enabled
}

// SetDisplayingEnabled ...
func (l *Log) SetDisplayingEnabled(enabled bool) {
	l.configLock.Lock()
	defer l.configLock.Unlock()

	l.config.DisableDisplaying = !enabled
}

// SetContextualDisplayingEnabled ...
func (l *Log) SetContextualDisplayingEnabled(enabled bool) {
	l.configLock.Lock()
	defer l.configLock.Unlock()

	l.config.DisableContextualDisplaying = !enabled
}

type fileWriter struct {
	writer *bufio.Writer
	file   *os.File

	config Config
}

func (fw *fileWriter) Flush() error {
	return fw.writer.Flush()
}

func (fw *fileWriter) Write(b []byte) (int, error) {
	return fw.writer.Write(b)
}

func (fw *fileWriter) WriteString(s string) (int, error) {
	return fw.writer.WriteString(s)
}

func (fw *fileWriter) Close() error {
	return fw.file.Close()
}

func (fw *fileWriter) Rotate(RotationSize int) error {
	for i := RotationSize - 1; i >= 0; i-- {
		sourceFilename := filepath.Join(fw.config.Directory, fmt.Sprintf("%s.log.%d", fw.config.LoggerName, i))
		destFilename := filepath.Join(fw.config.Directory, fmt.Sprintf("%s.log.%d", fw.config.LoggerName, i+1))
		if _, err := os.Stat(sourceFilename); !os.IsNotExist(err) {
			os.Rename(sourceFilename, destFilename)
		}
	}
	sourceFilename := filepath.Join(fw.config.Directory, fmt.Sprintf("%s.log", fw.config.LoggerName))
	destFilename := filepath.Join(fw.config.Directory, fmt.Sprintf("%s.log.1", fw.config.LoggerName))
	os.Rename(sourceFilename, destFilename)
	writer, file, err := fw.create()
	if err != nil {
		return err
	}
	fw.file = file
	fw.writer = writer
	return nil
}

func (fw *fileWriter) create() (*bufio.Writer, *os.File, error) {
	filename := filepath.Join(fw.config.Directory, fmt.Sprintf("%s.log", fw.config.LoggerName))
	file, err := os.OpenFile(filename, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
	if err != nil {
		return nil, nil, err
	}
	writer := bufio.NewWriter(file)
	return writer, file, nil
}

func (fw *fileWriter) Initialize(config Config) (int, error) {
	fw.config = config
	writer, file, err := fw.create()
	if err != nil {
		return 0, err
	}
	fw.writer = writer
	fw.file = file
	fileSize, err := file.Seek(0, io.SeekEnd)
	if err != nil {
		return 0, err
	}
	return int(fileSize), nil
}
<|endoftext|>


<commit_before>package registry

import (
	"encoding/json"

	"testing"
)

func TestEncodingEndpoints(t *testing.T) {
	eps := []*Endpoint{
		&Endpoint{
			Name: "endpoint1",
			Request: &Value{
				Name: "request",
				Type: "request",
			},
			Response: &Value{
				Name: "response",
				Type: "response",
			},
			Metadata: map[string]string{
				"foo1": "bar1",
			},
		},
		&Endpoint{
			Name: "endpoint2",
			Request: &Value{
				Name: "request",
				Type: "request",
			},
			Response: &Value{
				Name: "response",
				Type: "response",
			},
			Metadata: map[string]string{
				"foo2": "bar2",
			},
		},
		&Endpoint{
			Name: "endpoint3",
			Request: &Value{
				Name: "request",
				Type: "request",
			},
			Response: &Value{
				Name: "response",
				Type: "response",
			},
			Metadata: map[string]string{
				"foo3": "bar3",
			},
		},
	}

	testEp := func(ep *Endpoint, enc string) {
		// encode endpoint
		e := encodeEndpoints([]*Endpoint{ep})

		// check there are two tags; old and new
		if len(e) != 2 {
			t.Fatalf("Expected 2 encoded tags, got %v", e)
		}

		// check old encoding
		var seen bool

		for _, en := range e {
			if en == enc {
				seen = true
				break
			}
		}

		if !seen {
			t.Fatalf("Expected %s but not found", enc)
		}

		// decode
		d := decodeEndpoints([]string{enc})
		if len(d) == 0 {
			t.Fatalf("Expected %v got %v", ep, d)
		}

		// check name
		if d[0].Name != ep.Name {
			t.Fatalf("Expected ep %s got %s", ep.Name, d[0].Name)
		}

		// check all the metadata exists
		for k, v := range ep.Metadata {
			if gv := d[0].Metadata[k]; gv != v {
				t.Fatalf("Expected key %s val %s got val %s", k, v, gv)
			}
		}
	}

	for _, ep := range eps {
		// JSON encoded
		jencoded, err := json.Marshal(ep)
		if err != nil {
			t.Fatal(err)
		}

		// HEX encoded
		hencoded := encode(jencoded)
		// endpoint tag
		jepTag := "e=" + string(jencoded)
		hepTag := "e-" + hencoded

		// test old
		testEp(ep, jepTag)
		// test new
		testEp(ep, hepTag)
	}
}

func TestEncodingVersion(t *testing.T) {
	testData := []struct {
		decoded    string
		encoded    string
		oldEncoded string
	}{
		{"1.0.0", "v-789c32d433d03300040000ffff02ce00ee", "v=1.0.0"},
		{"latest", "v-789cca492c492d2e01040000ffff08cc028e", "v=latest"},
	}

	for _, data := range testData {
		e := encodeVersion(data.decoded)

		if e[1] != data.encoded {
			t.Fatalf("Expected %s got %s", data.encoded, e)
		}

		d, ok := decodeVersion(e)
		if !ok {
			t.Fatalf("Unexpected %t for %s", ok, data.encoded)
		}

		if d != data.decoded {
			t.Fatalf("Expected %s got %s", data.decoded, d)
		}

		d, ok = decodeVersion([]string{data.encoded})
		if !ok {
			t.Fatalf("Unexpected %t for %s", ok, data.encoded)
		}

		if d != data.decoded {
			t.Fatalf("Expected %s got %s", data.decoded, d)
		}

		d, ok = decodeVersion([]string{data.oldEncoded})
		if !ok {
			t.Fatalf("Unexpected %t for %s", ok, data.oldEncoded)
		}

		if d != data.decoded {
			t.Fatalf("Expected %s got %s", data.decoded, d)
		}
	}
}
<commit_msg>No longer need to test old encoding<commit_after>package registry

import (
	"encoding/json"

	"testing"
)

func TestEncodingEndpoints(t *testing.T) {
	eps := []*Endpoint{
		&Endpoint{
			Name: "endpoint1",
			Request: &Value{
				Name: "request",
				Type: "request",
			},
			Response: &Value{
				Name: "response",
				Type: "response",
			},
			Metadata: map[string]string{
				"foo1": "bar1",
			},
		},
		&Endpoint{
			Name: "endpoint2",
			Request: &Value{
				Name: "request",
				Type: "request",
			},
			Response: &Value{
				Name: "response",
				Type: "response",
			},
			Metadata: map[string]string{
				"foo2": "bar2",
			},
		},
		&Endpoint{
			Name: "endpoint3",
			Request: &Value{
				Name: "request",
				Type: "request",
			},
			Response: &Value{
				Name: "response",
				Type: "response",
			},
			Metadata: map[string]string{
				"foo3": "bar3",
			},
		},
	}

	testEp := func(ep *Endpoint, enc string) {
		// encode endpoint
		e := encodeEndpoints([]*Endpoint{ep})

		// check there are two tags; old and new
		if len(e) != 1 {
			t.Fatalf("Expected 1 encoded tags, got %v", e)
		}

		// check old encoding
		var seen bool

		for _, en := range e {
			if en == enc {
				seen = true
				break
			}
		}

		if !seen {
			t.Fatalf("Expected %s but not found", enc)
		}

		// decode
		d := decodeEndpoints([]string{enc})
		if len(d) == 0 {
			t.Fatalf("Expected %v got %v", ep, d)
		}

		// check name
		if d[0].Name != ep.Name {
			t.Fatalf("Expected ep %s got %s", ep.Name, d[0].Name)
		}

		// check all the metadata exists
		for k, v := range ep.Metadata {
			if gv := d[0].Metadata[k]; gv != v {
				t.Fatalf("Expected key %s val %s got val %s", k, v, gv)
			}
		}
	}

	for _, ep := range eps {
		// JSON encoded
		jencoded, err := json.Marshal(ep)
		if err != nil {
			t.Fatal(err)
		}

		// HEX encoded
		hencoded := encode(jencoded)
		// endpoint tag
		hepTag := "e-" + hencoded
		testEp(ep, hepTag)
	}
}

func TestEncodingVersion(t *testing.T) {
	testData := []struct {
		decoded string
		encoded string
	}{
		{"1.0.0", "v-789c32d433d03300040000ffff02ce00ee"},
		{"latest", "v-789cca492c492d2e01040000ffff08cc028e"},
	}

	for _, data := range testData {
		e := encodeVersion(data.decoded)

		if e[0] != data.encoded {
			t.Fatalf("Expected %s got %s", data.encoded, e)
		}

		d, ok := decodeVersion(e)
		if !ok {
			t.Fatalf("Unexpected %t for %s", ok, data.encoded)
		}

		if d != data.decoded {
			t.Fatalf("Expected %s got %s", data.decoded, d)
		}

		d, ok = decodeVersion([]string{data.encoded})
		if !ok {
			t.Fatalf("Unexpected %t for %s", ok, data.encoded)
		}

		if d != data.decoded {
			t.Fatalf("Expected %s got %s", data.decoded, d)
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 Brian J. Downs
//
// 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.

//
// weather.go
//
// This application will go out and get the weather for the given
// location and display it in the given data units (fahrenheit,
// celcius, or kelvin.  If the string "here" is provided as an
// argument to the -l flag, the app will try to figure out where
// it's being executed from based on geolocation from IP address.
//
// Examples:
//          go run weather.go --help
//          go run weather.go -w Philadelphia -u f -l en  # fahrenheit, English
//          go run weather.go -w here -u f -l ru          # fahrenheit, Russian
//          go run weather.go -w Dublin -u c -l fi        # celcius, Finnish
//          go run weather.go -w "Las Vegas" -u k -l es   # kelvin, Spanish
package main

import (
	"encoding/json"
	"flag"
	owm "github.com/briandowns/openweathermap" // "owm" for easier use
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strings"
	"text/template"
)

// URL is a constant that contains where to find the IP locale info
const URL = "http://ip-api.com/json"

// template used for output
const weatherTemplate = `Current weather for {{.Name}}:
    Conditions: {{range .Weather}} {{.Description}} {{end}}
    Now:         {{.Main.Temp}} {{.Unit}}
    High:        {{.Main.TempMax}} {{.Unit}}
    Low:         {{.Main.TempMin}} {{.Unit}}
`

// Pointers to hold the contents of the flag args.
var (
	whereFlag = flag.String("w", "", "Location to get weather.  If location has a space, wrap the location in double quotes.")
	unitFlag  = flag.String("u", "", "Unit of measure to display temps in")
	langFlag  = flag.String("l", "", "Language to display temps in")
)

// Data will hold the result of the query to get the IP
// address of the caller.
type Data struct {
	Status      string  `json:"status"`
	Country     string  `json:"country"`
	CountryCode string  `json:"countryCode"`
	Region      string  `json:"region"`
	RegionName  string  `json:"regionName"`
	City        string  `json:"city"`
	Zip         string  `json:"zip"`
	Lat         float64 `json:"lat"`
	Lon         float64 `json:"lon"`
	Timezone    string  `json:"timezone"`
	ISP         string  `json:"isp"`
	ORG         string  `json:"org"`
	AS          string  `json:"as"`
	Message     string  `json:"message"`
	Query       string  `json:"query"`
}

// getLocation will get the location details for where this
// application has been run from.
func getLocation() *Data {
	response, err := http.Get(URL)
	if err != nil {
		log.Fatalln(err)
	}
	defer response.Body.Close()

	result, err := ioutil.ReadAll(response.Body)
	if err != nil {
		log.Fatalln(err)
	}

	r := &Data{}
	err = json.Unmarshal(result, &r)
	if err != nil {
		log.Fatalln(err)
	}
	return r
}

// getCurrent gets the current weather for the provided
// location in the units provided.
func getCurrent(l, u, lang string) *owm.CurrentWeatherData {
	w, err := owm.NewCurrent(u, lang)
	if err != nil {
		log.Fatalln(err)
	}
	w.CurrentByName(l)
	return w
}

func main() {
	flag.Parse()

	// If there's any funkiness with cli args, tuck and roll...
	if len(*whereFlag) <= 1 || len(*unitFlag) != 1 || len(*langFlag) != 2 {
		flag.Usage()
		os.Exit(1)
	}

	// Process request for location of "here"
	if strings.ToLower(*whereFlag) == "here" {
		w := getCurrent(getLocation().City, *unitFlag, *langFlag)
		tmpl, err := template.New("weather").Parse(weatherTemplate)
		if err != nil {
			log.Fatalln(err)
		}

		// Render the template and display
		err = tmpl.Execute(os.Stdout, w)
		if err != nil {
			log.Fatalln(err)
		}
		os.Exit(0)
	}

	// Process request for the given location
	w := getCurrent(*whereFlag, *unitFlag, *langFlag)
	tmpl, err := template.New("weather").Parse(weatherTemplate)
	if err != nil {
		log.Fatalln(err)
	}

	// Render the template and display
	err = tmpl.Execute(os.Stdout, w)
	if err != nil {
		log.Fatalln(err)
	}
	os.Exit(0)
}
<commit_msg>fix comment in cli example<commit_after>// Copyright 2015 Brian J. Downs
//
// 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.

//
// weather.go
//
// This application will go out and get the weather for the given
// location and display it in the given data units (fahrenheit,
// celcius, or kelvin).  If the string "here" is provided as an
// argument to the -l flag, the app will try to figure out where
// it's being executed from based on geolocation from the IP address.
//
// Examples:
//          go run weather.go --help
//          go run weather.go -w Philadelphia -u f -l en  # fahrenheit, English
//          go run weather.go -w here -u f -l ru          # fahrenheit, Russian
//          go run weather.go -w Dublin -u c -l fi        # celcius, Finnish
//          go run weather.go -w "Las Vegas" -u k -l es   # kelvin, Spanish
package main

import (
	"encoding/json"
	"flag"
	owm "github.com/briandowns/openweathermap" // "owm" for easier use
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strings"
	"text/template"
)

// URL is a constant that contains where to find the IP locale info
const URL = "http://ip-api.com/json"

// template used for output
const weatherTemplate = `Current weather for {{.Name}}:
    Conditions: {{range .Weather}} {{.Description}} {{end}}
    Now:         {{.Main.Temp}} {{.Unit}}
    High:        {{.Main.TempMax}} {{.Unit}}
    Low:         {{.Main.TempMin}} {{.Unit}}
`

// Pointers to hold the contents of the flag args.
var (
	whereFlag = flag.String("w", "", "Location to get weather.  If location has a space, wrap the location in double quotes.")
	unitFlag  = flag.String("u", "", "Unit of measure to display temps in")
	langFlag  = flag.String("l", "", "Language to display temps in")
)

// Data will hold the result of the query to get the IP
// address of the caller.
type Data struct {
	Status      string  `json:"status"`
	Country     string  `json:"country"`
	CountryCode string  `json:"countryCode"`
	Region      string  `json:"region"`
	RegionName  string  `json:"regionName"`
	City        string  `json:"city"`
	Zip         string  `json:"zip"`
	Lat         float64 `json:"lat"`
	Lon         float64 `json:"lon"`
	Timezone    string  `json:"timezone"`
	ISP         string  `json:"isp"`
	ORG         string  `json:"org"`
	AS          string  `json:"as"`
	Message     string  `json:"message"`
	Query       string  `json:"query"`
}

// getLocation will get the location details for where this
// application has been run from.
func getLocation() *Data {
	response, err := http.Get(URL)
	if err != nil {
		log.Fatalln(err)
	}
	defer response.Body.Close()

	result, err := ioutil.ReadAll(response.Body)
	if err != nil {
		log.Fatalln(err)
	}

	r := &Data{}
	err = json.Unmarshal(result, &r)
	if err != nil {
		log.Fatalln(err)
	}
	return r
}

// getCurrent gets the current weather for the provided
// location in the units provided.
func getCurrent(l, u, lang string) *owm.CurrentWeatherData {
	w, err := owm.NewCurrent(u, lang)
	if err != nil {
		log.Fatalln(err)
	}
	w.CurrentByName(l)
	return w
}

func main() {
	flag.Parse()

	// If there's any funkiness with cli args, tuck and roll...
	if len(*whereFlag) <= 1 || len(*unitFlag) != 1 || len(*langFlag) != 2 {
		flag.Usage()
		os.Exit(1)
	}

	// Process request for location of "here"
	if strings.ToLower(*whereFlag) == "here" {
		w := getCurrent(getLocation().City, *unitFlag, *langFlag)
		tmpl, err := template.New("weather").Parse(weatherTemplate)
		if err != nil {
			log.Fatalln(err)
		}

		// Render the template and display
		err = tmpl.Execute(os.Stdout, w)
		if err != nil {
			log.Fatalln(err)
		}
		os.Exit(0)
	}

	// Process request for the given location
	w := getCurrent(*whereFlag, *unitFlag, *langFlag)
	tmpl, err := template.New("weather").Parse(weatherTemplate)
	if err != nil {
		log.Fatalln(err)
	}

	// Render the template and display
	err = tmpl.Execute(os.Stdout, w)
	if err != nil {
		log.Fatalln(err)
	}
	os.Exit(0)
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"math/rand"
	"net/http"
	"reflect"
	"time"

	"golang.org/x/net/context"

	"github.com/pressly/chi"
	"github.com/pressly/chi/middleware"
	"github.com/pressly/chi/render"
)

type RuntimeObject struct {
	ID       int      `json:"id"`
	AuthData string   `json:"auth_data"`
	Data     []string `json:"data"`
}

type PresenterObject struct {
	*RuntimeObject `json:",inline"`

	URL   string `json:"url"`
	False bool   `json:"false"`

	// Omit by default. Show explicitly for auth'd users only.
	AuthData interface{} `json:"auth_data,omitempty"`
}

type PresenterObjectV2 struct {
	*PresenterObject `json:",inline"`

	ResourceURL string `json:"resource_url"`

	// Omit.
	URL interface{} `json:"url,omitempty"`
}

type PresenterObjectV1 struct {
	*PresenterObjectV2 `json:",inline"`

	Data map[string]bool `json:"data"`
}

var (
	ErrUnauthorized = errors.New("Unauthorized")
	ErrForbidden    = errors.New("Forbidden")
	ErrNotFound     = errors.New("Resource not found")
)

func main() {
	r := chi.NewRouter()

	r.Use(middleware.RequestID)
	r.Use(middleware.Logger)
	r.Use(middleware.Recoverer)
	r.Use(render.ParseContentType)

	render.DefaultPresenter.Register(func(ctx context.Context, from *RuntimeObject) (*PresenterObject, error) {
		to := &PresenterObject{
			RuntimeObject: from,
			URL:           fmt.Sprintf("https://api.example.com/objects/%v", from.ID),
		}
		// Only show to auth'd user.
		if _, ok := ctx.Value("auth").(bool); ok {
			to.AuthData = from.AuthData
		}
		return to, nil
	})

	v2 := render.NewPresenter()
	v2.Register(func(ctx context.Context, from *PresenterObject) (*PresenterObjectV2, error) {
		return &PresenterObjectV2{PresenterObject: from, ResourceURL: from.URL}, nil
	})
	v2.RegisterFrom(render.DefaultPresenter)

	v1 := render.NewPresenter()
	v1.Register(func(ctx context.Context, from *PresenterObjectV2) (*PresenterObjectV1, error) {
		to := &PresenterObjectV1{
			PresenterObjectV2: from,
			Data:              map[string]bool{},
		}
		for _, item := range from.Data {
			to.Data[item] = true
		}
		return to, nil
	})
	v1.RegisterFrom(v2)

	render.Respond = func(ctx context.Context, w http.ResponseWriter, v interface{}) {
		// Set response status based on Error value/type.
		val := reflect.ValueOf(v)
		if err, ok := val.Interface().(error); ok {
			switch err {
			case ErrUnauthorized:
				ctx = render.Status(ctx, 401)
			case ErrForbidden:
				ctx = render.Status(ctx, 403)
			case ErrNotFound:
				ctx = render.Status(ctx, 404)
			default:
				ctx = render.Status(ctx, 500)
			}
			render.DefaultRespond(ctx, w, map[string]string{"error": err.Error()})
			return
		}

		render.DefaultRespond(ctx, w, v)
	}

	r.Get("/", objectHandler)
	r.Get("/v2", render.UsePresenter(v2), objectHandler)
	r.Get("/v1", render.UsePresenter(v1), objectHandler)

	r.Get("/error", randomErrorHandler)

	http.ListenAndServe(":3333", r)
}

func objectHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	obj := &RuntimeObject{
		ID:       1,
		AuthData: "secret data for auth'd users only",
		Data:     []string{"one", "two", "three", "four"},
	}

	// Simulate some context values (copy over from query params).
	if r.URL.Query().Get("auth") != "" {
		ctx = context.WithValue(ctx, "auth", true)
	}
	if r.URL.Query().Get("error") != "" {
		render.Respond(ctx, w, errors.New("error"))
		return
	}

	render.Respond(ctx, w, obj)
}

func randomErrorHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	errors := []error{ErrUnauthorized, ErrForbidden, ErrNotFound}

	rand.Seed(time.Now().Unix())
	render.Respond(ctx, w, errors[rand.Intn(len(errors))])
}
<commit_msg>Make example more readable<commit_after>package main

import (
	"errors"
	"fmt"
	"math/rand"
	"net/http"
	"reflect"
	"time"

	"golang.org/x/net/context"

	"github.com/pressly/chi"
	"github.com/pressly/chi/middleware"
	"github.com/pressly/chi/render"
)

type RuntimeObject struct {
	ID       int      `json:"id"`
	AuthData string   `json:"auth_data"`
	Data     []string `json:"data"`
}

type PresenterObject struct {
	*RuntimeObject `json:",inline"`

	URL   string `json:"url"`
	False bool   `json:"false"`

	// Omit by default. Show explicitly for auth'd users only.
	AuthData interface{} `json:"auth_data,omitempty"`
}

type PresenterObjectV2 struct {
	*PresenterObject `json:",inline"`

	ResourceURL string `json:"resource_url"`

	// Omit.
	URL interface{} `json:"url,omitempty"`
}

type PresenterObjectV1 struct {
	*PresenterObjectV2 `json:",inline"`

	Data map[string]bool `json:"data"`
}

var (
	ErrUnauthorized = errors.New("Unauthorized")
	ErrForbidden    = errors.New("Forbidden")
	ErrNotFound     = errors.New("Resource not found")
)

func main() {
	r := chi.NewRouter()

	r.Use(middleware.RequestID)
	r.Use(middleware.Logger)
	r.Use(middleware.Recoverer)
	r.Use(render.ParseContentType)

	render.DefaultPresenter.Register(func(ctx context.Context, from *RuntimeObject) (*PresenterObject, error) {
		to := &PresenterObject{
			RuntimeObject: from,
			URL:           fmt.Sprintf("https://api.example.com/objects/%v", from.ID),
		}
		// Only show to auth'd user.
		if _, ok := ctx.Value("auth").(bool); ok {
			to.AuthData = from.AuthData
		}
		return to, nil
	})

	v2 := render.NewPresenter()
	v2.RegisterFrom(render.DefaultPresenter)
	v2.Register(func(ctx context.Context, from *PresenterObject) (*PresenterObjectV2, error) {
		return &PresenterObjectV2{PresenterObject: from, ResourceURL: from.URL}, nil
	})

	v1 := render.NewPresenter()
	v1.RegisterFrom(v2)
	v1.Register(func(ctx context.Context, from *PresenterObjectV2) (*PresenterObjectV1, error) {
		to := &PresenterObjectV1{
			PresenterObjectV2: from,
			Data:              map[string]bool{},
		}
		for _, item := range from.Data {
			to.Data[item] = true
		}
		return to, nil
	})

	r.Get("/", objectHandler)
	r.Get("/v2", render.UsePresenter(v2), objectHandler)
	r.Get("/v1", render.UsePresenter(v1), objectHandler)

	r.Get("/error", randomErrorHandler)

	http.ListenAndServe(":3333", r)
}

func objectHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	obj := &RuntimeObject{
		ID:       1,
		AuthData: "secret data for auth'd users only",
		Data:     []string{"one", "two", "three", "four"},
	}

	// Simulate some context values (copy over from query params).
	if r.URL.Query().Get("auth") != "" {
		ctx = context.WithValue(ctx, "auth", true)
	}
	if r.URL.Query().Get("error") != "" {
		render.Respond(ctx, w, errors.New("error"))
		return
	}

	render.Respond(ctx, w, obj)
}

func randomErrorHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	errors := []error{ErrUnauthorized, ErrForbidden, ErrNotFound}

	rand.Seed(time.Now().Unix())
	render.Respond(ctx, w, errors[rand.Intn(len(errors))])
}

func init() {
	render.Respond = customRespond
}

func customRespond(ctx context.Context, w http.ResponseWriter, v interface{}) {
	// Set response status based on Error value/type.
	val := reflect.ValueOf(v)
	if err, ok := val.Interface().(error); ok {
		switch err {
		case ErrUnauthorized:
			ctx = render.Status(ctx, 401)
		case ErrForbidden:
			ctx = render.Status(ctx, 403)
		case ErrNotFound:
			ctx = render.Status(ctx, 404)
		default:
			ctx = render.Status(ctx, 500)
		}
		render.DefaultRespond(ctx, w, map[string]string{"error": err.Error()})
		return
	}

	render.DefaultRespond(ctx, w, v)
}
<|endoftext|>


<commit_before>package syssetup

import (
	"io/ioutil"
	"os/exec"

	"github.com/sirupsen/logrus"
)

var (
	callIPTablesFile = "/proc/sys/net/bridge/bridge-nf-call-iptables"
)

func Configure() error {
	exec.Command("modprobe", "br_netfilter").Run()
	if err := ioutil.WriteFile(callIPTablesFile, []byte("1"), 0640); err != nil {
		logrus.Warnf("failed to write value 1 at %s: %v", callIPTablesFile, err)
	}
	return nil
}
<commit_msg>Set /proc/sys/net/ipv4/ip_forward on agent start<commit_after>package syssetup

import (
	"io/ioutil"
	"os/exec"

	"github.com/sirupsen/logrus"
)

var (
	callIPTablesFile = "/proc/sys/net/bridge/bridge-nf-call-iptables"
	forward          = "/proc/sys/net/ipv4/ip_forward"
)

func Configure() error {
	exec.Command("modprobe", "br_netfilter").Run()
	if err := ioutil.WriteFile(callIPTablesFile, []byte("1"), 0640); err != nil {
		logrus.Warnf("failed to write value 1 at %s: %v", callIPTablesFile, err)
	}
	if err := ioutil.WriteFile(forward, []byte("1"), 0640); err != nil {
		logrus.Warnf("failed to write value 1 at %s: %v", forward, err)
	}
	return nil
}
<|endoftext|>


<commit_before>package api

import (
	"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
)

type RESTClient interface {
	Verb(verb string) *client.Request
	Put() *client.Request
	Post() *client.Request
	Delete() *client.Request
	Get() *client.Request
}

type ClientMappings map[string]struct {
	Kind   string
	Client RESTClient
	Codec  runtime.Codec
}
<commit_msg>Added missing godoc<commit_after>package api

import (
	"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
)

// RESTClient provides REST interface compatible with Kubernetes RESTClient
type RESTClient interface {
	Verb(verb string) *client.Request
	Put() *client.Request
	Post() *client.Request
	Delete() *client.Request
	Get() *client.Request
}

// ClientMappings stores mapping between kind and client and codec
// TODO: This struct is now obsoleted by kubectl
type ClientMappings map[string]struct {
	Kind   string
	Client RESTClient
	Codec  runtime.Codec
}
<|endoftext|>


<commit_before>package vault

import (
	"fmt"
	"log"
	"strings"
	"sync"
	"testing"

	"github.com/hashicorp/vault/logical"
)

type NoopBackend struct {
	sync.Mutex

	Root     []string
	Login    []string
	Paths    []string
	Requests []*logical.Request
	Response *logical.Response
	Logger   *log.Logger
}

func (n *NoopBackend) HandleRequest(req *logical.Request) (*logical.Response, error) {
	n.Lock()
	defer n.Unlock()

	requestCopy := *req
	n.Paths = append(n.Paths, req.Path)
	n.Requests = append(n.Requests, &requestCopy)
	if req.Storage == nil {
		return nil, fmt.Errorf("missing view")
	}

	return n.Response, nil
}

func (n *NoopBackend) SpecialPaths() *logical.Paths {
	return &logical.Paths{
		Root:            n.Root,
		Unauthenticated: n.Login,
	}
}

func (n *NoopBackend) SetLogger(l *log.Logger) {
	n.Logger = l
}

func TestRouter_Mount(t *testing.T) {
	r := NewRouter()
	_, barrier, _ := mockBarrier(t)
	view := NewBarrierView(barrier, "logical/")

	n := &NoopBackend{}
	err := r.Mount(n, "prod/aws/", generateUUID(), view)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	err = r.Mount(n, "prod/aws/", generateUUID(), view)
	if !strings.Contains(err.Error(), "cannot mount under existing mount") {
		t.Fatalf("err: %v", err)
	}

	if path := r.MatchingMount("prod/aws/foo"); path != "prod/aws/" {
		t.Fatalf("bad: %s", path)
	}

	if v := r.MatchingView("prod/aws/foo"); v != view {
		t.Fatalf("bad: %s", v)
	}

	if path := r.MatchingMount("stage/aws/foo"); path != "" {
		t.Fatalf("bad: %s", path)
	}

	if v := r.MatchingView("stage/aws/foo"); v != nil {
		t.Fatalf("bad: %s", v)
	}

	req := &logical.Request{
		Path: "prod/aws/foo",
	}
	resp, err := r.Route(req)
	if err != nil {
		t.Fatalf("err: %v", err)
	}
	if resp != nil {
		t.Fatalf("bad: %v", resp)
	}

	// Verify the path
	if len(n.Paths) != 1 || n.Paths[0] != "foo" {
		t.Fatalf("bad: %v", n.Paths)
	}
}

func TestRouter_Unmount(t *testing.T) {
	r := NewRouter()
	_, barrier, _ := mockBarrier(t)
	view := NewBarrierView(barrier, "logical/")

	n := &NoopBackend{}
	err := r.Mount(n, "prod/aws/", generateUUID(), view)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	err = r.Unmount("prod/aws/")
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	req := &logical.Request{
		Path: "prod/aws/foo",
	}
	_, err = r.Route(req)
	if !strings.Contains(err.Error(), "no handler for route") {
		t.Fatalf("err: %v", err)
	}
}

func TestRouter_Remount(t *testing.T) {
	r := NewRouter()
	_, barrier, _ := mockBarrier(t)
	view := NewBarrierView(barrier, "logical/")

	n := &NoopBackend{}
	err := r.Mount(n, "prod/aws/", generateUUID(), view)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	err = r.Remount("prod/aws/", "stage/aws/")
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	err = r.Remount("prod/aws/", "stage/aws/")
	if !strings.Contains(err.Error(), "no mount at") {
		t.Fatalf("err: %v", err)
	}

	req := &logical.Request{
		Path: "prod/aws/foo",
	}
	_, err = r.Route(req)
	if !strings.Contains(err.Error(), "no handler for route") {
		t.Fatalf("err: %v", err)
	}

	req = &logical.Request{
		Path: "stage/aws/foo",
	}
	_, err = r.Route(req)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	// Verify the path
	if len(n.Paths) != 1 || n.Paths[0] != "foo" {
		t.Fatalf("bad: %v", n.Paths)
	}
}

func TestRouter_RootPath(t *testing.T) {
	r := NewRouter()
	_, barrier, _ := mockBarrier(t)
	view := NewBarrierView(barrier, "logical/")

	n := &NoopBackend{
		Root: []string{
			"root",
			"policy/*",
		},
	}
	err := r.Mount(n, "prod/aws/", generateUUID(), view)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	type tcase struct {
		path   string
		expect bool
	}
	tcases := []tcase{
		{"random", false},
		{"prod/aws/foo", false},
		{"prod/aws/root", true},
		{"prod/aws/root-more", false},
		{"prod/aws/policy", false},
		{"prod/aws/policy/", true},
		{"prod/aws/policy/ops", true},
	}

	for _, tc := range tcases {
		out := r.RootPath(tc.path)
		if out != tc.expect {
			t.Fatalf("bad: path: %s expect: %v got %v", tc.path, tc.expect, out)
		}
	}
}

func TestRouter_LoginPath(t *testing.T) {
	r := NewRouter()
	_, barrier, _ := mockBarrier(t)
	view := NewBarrierView(barrier, "auth/")

	n := &NoopBackend{
		Login: []string{
			"login",
			"oauth/*",
		},
	}
	err := r.Mount(n, "auth/foo/", generateUUID(), view)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	type tcase struct {
		path   string
		expect bool
	}
	tcases := []tcase{
		{"random", false},
		{"auth/foo/bar", false},
		{"auth/foo/login", true},
		{"auth/foo/oauth", false},
		{"auth/foo/oauth/redirect", true},
	}

	for _, tc := range tcases {
		out := r.LoginPath(tc.path)
		if out != tc.expect {
			t.Fatalf("bad: path: %s expect: %v got %v", tc.path, tc.expect, out)
		}
	}
}

func TestRouter_Taint(t *testing.T) {
	r := NewRouter()
	_, barrier, _ := mockBarrier(t)
	view := NewBarrierView(barrier, "logical/")

	n := &NoopBackend{}
	err := r.Mount(n, "prod/aws/", generateUUID(), view)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	err = r.Taint("prod/aws/")
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	req := &logical.Request{
		Operation: logical.ReadOperation,
		Path:      "prod/aws/foo",
	}
	_, err = r.Route(req)
	if err.Error() != "no handler for route 'prod/aws/foo'" {
		t.Fatalf("err: %v", err)
	}

	// Rollback and Revoke should work
	req.Operation = logical.RollbackOperation
	_, err = r.Route(req)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	req.Operation = logical.RevokeOperation
	_, err = r.Route(req)
	if err != nil {
		t.Fatalf("err: %v", err)
	}
}

func TestRouter_Untaint(t *testing.T) {
	r := NewRouter()
	_, barrier, _ := mockBarrier(t)
	view := NewBarrierView(barrier, "logical/")

	n := &NoopBackend{}
	err := r.Mount(n, "prod/aws/", generateUUID(), view)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	err = r.Taint("prod/aws/")
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	err = r.Untaint("prod/aws/")
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	req := &logical.Request{
		Operation: logical.ReadOperation,
		Path:      "prod/aws/foo",
	}
	_, err = r.Route(req)
	if err != nil {
		t.Fatalf("err: %v", err)
	}
}

func TestPathsToRadix(t *testing.T) {
	// Provide real paths
	paths := []string{
		"foo",
		"foo/*",
		"sub/bar*",
	}
	r := pathsToRadix(paths)

	raw, ok := r.Get("foo")
	if !ok || raw.(bool) != false {
		t.Fatalf("bad: %v (foo)", raw)
	}

	raw, ok = r.Get("foo/")
	if !ok || raw.(bool) != true {
		t.Fatalf("bad: %v (foo/)", raw)
	}

	raw, ok = r.Get("sub/bar")
	if !ok || raw.(bool) != true {
		t.Fatalf("bad: %v (sub/bar)", raw)
	}
}
<commit_msg>Fixing tests<commit_after>package vault

import (
	"fmt"
	"log"
	"strings"
	"sync"
	"testing"

	"github.com/hashicorp/vault/logical"
)

type NoopBackend struct {
	sync.Mutex

	Root     []string
	Login    []string
	Paths    []string
	Requests []*logical.Request
	Response *logical.Response
	Logger   *log.Logger
}

func (n *NoopBackend) HandleRequest(req *logical.Request) (*logical.Response, error) {
	n.Lock()
	defer n.Unlock()

	requestCopy := *req
	n.Paths = append(n.Paths, req.Path)
	n.Requests = append(n.Requests, &requestCopy)
	if req.Storage == nil {
		return nil, fmt.Errorf("missing view")
	}

	return n.Response, nil
}

func (n *NoopBackend) SpecialPaths() *logical.Paths {
	return &logical.Paths{
		Root:            n.Root,
		Unauthenticated: n.Login,
	}
}

func (n *NoopBackend) SetLogger(l *log.Logger) {
	n.Logger = l
}

func TestRouter_Mount(t *testing.T) {
	r := NewRouter()
	_, barrier, _ := mockBarrier(t)
	view := NewBarrierView(barrier, "logical/")

	n := &NoopBackend{}
	err := r.Mount(n, "prod/aws/", generateUUID(), view)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	err = r.Mount(n, "prod/aws/", generateUUID(), view)
	if !strings.Contains(err.Error(), "cannot mount under existing mount") {
		t.Fatalf("err: %v", err)
	}

	if path := r.MatchingMount("prod/aws/foo"); path != "prod/aws/" {
		t.Fatalf("bad: %s", path)
	}

	if v := r.MatchingView("prod/aws/foo"); v != view {
		t.Fatalf("bad: %s", v)
	}

	if path := r.MatchingMount("stage/aws/foo"); path != "" {
		t.Fatalf("bad: %s", path)
	}

	if v := r.MatchingView("stage/aws/foo"); v != nil {
		t.Fatalf("bad: %s", v)
	}

	req := &logical.Request{
		Path: "prod/aws/foo",
	}
	resp, err := r.Route(req)
	if err != nil {
		t.Fatalf("err: %v", err)
	}
	if resp != nil {
		t.Fatalf("bad: %v", resp)
	}

	// Verify the path
	if len(n.Paths) != 1 || n.Paths[0] != "foo" {
		t.Fatalf("bad: %v", n.Paths)
	}
}

func TestRouter_Unmount(t *testing.T) {
	r := NewRouter()
	_, barrier, _ := mockBarrier(t)
	view := NewBarrierView(barrier, "logical/")

	n := &NoopBackend{}
	err := r.Mount(n, "prod/aws/", generateUUID(), view)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	err = r.Unmount("prod/aws/")
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	req := &logical.Request{
		Path: "prod/aws/foo",
	}
	_, err = r.Route(req)
	if !strings.Contains(err.Error(), "unsupported path") {
		t.Fatalf("err: %v", err)
	}
}

func TestRouter_Remount(t *testing.T) {
	r := NewRouter()
	_, barrier, _ := mockBarrier(t)
	view := NewBarrierView(barrier, "logical/")

	n := &NoopBackend{}
	err := r.Mount(n, "prod/aws/", generateUUID(), view)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	err = r.Remount("prod/aws/", "stage/aws/")
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	err = r.Remount("prod/aws/", "stage/aws/")
	if !strings.Contains(err.Error(), "no mount at") {
		t.Fatalf("err: %v", err)
	}

	req := &logical.Request{
		Path: "prod/aws/foo",
	}
	_, err = r.Route(req)
	if !strings.Contains(err.Error(), "unsupported path") {
		t.Fatalf("err: %v", err)
	}

	req = &logical.Request{
		Path: "stage/aws/foo",
	}
	_, err = r.Route(req)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	// Verify the path
	if len(n.Paths) != 1 || n.Paths[0] != "foo" {
		t.Fatalf("bad: %v", n.Paths)
	}
}

func TestRouter_RootPath(t *testing.T) {
	r := NewRouter()
	_, barrier, _ := mockBarrier(t)
	view := NewBarrierView(barrier, "logical/")

	n := &NoopBackend{
		Root: []string{
			"root",
			"policy/*",
		},
	}
	err := r.Mount(n, "prod/aws/", generateUUID(), view)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	type tcase struct {
		path   string
		expect bool
	}
	tcases := []tcase{
		{"random", false},
		{"prod/aws/foo", false},
		{"prod/aws/root", true},
		{"prod/aws/root-more", false},
		{"prod/aws/policy", false},
		{"prod/aws/policy/", true},
		{"prod/aws/policy/ops", true},
	}

	for _, tc := range tcases {
		out := r.RootPath(tc.path)
		if out != tc.expect {
			t.Fatalf("bad: path: %s expect: %v got %v", tc.path, tc.expect, out)
		}
	}
}

func TestRouter_LoginPath(t *testing.T) {
	r := NewRouter()
	_, barrier, _ := mockBarrier(t)
	view := NewBarrierView(barrier, "auth/")

	n := &NoopBackend{
		Login: []string{
			"login",
			"oauth/*",
		},
	}
	err := r.Mount(n, "auth/foo/", generateUUID(), view)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	type tcase struct {
		path   string
		expect bool
	}
	tcases := []tcase{
		{"random", false},
		{"auth/foo/bar", false},
		{"auth/foo/login", true},
		{"auth/foo/oauth", false},
		{"auth/foo/oauth/redirect", true},
	}

	for _, tc := range tcases {
		out := r.LoginPath(tc.path)
		if out != tc.expect {
			t.Fatalf("bad: path: %s expect: %v got %v", tc.path, tc.expect, out)
		}
	}
}

func TestRouter_Taint(t *testing.T) {
	r := NewRouter()
	_, barrier, _ := mockBarrier(t)
	view := NewBarrierView(barrier, "logical/")

	n := &NoopBackend{}
	err := r.Mount(n, "prod/aws/", generateUUID(), view)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	err = r.Taint("prod/aws/")
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	req := &logical.Request{
		Operation: logical.ReadOperation,
		Path:      "prod/aws/foo",
	}
	_, err = r.Route(req)
	if err.Error() != "unsupported path" {
		t.Fatalf("err: %v", err)
	}

	// Rollback and Revoke should work
	req.Operation = logical.RollbackOperation
	_, err = r.Route(req)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	req.Operation = logical.RevokeOperation
	_, err = r.Route(req)
	if err != nil {
		t.Fatalf("err: %v", err)
	}
}

func TestRouter_Untaint(t *testing.T) {
	r := NewRouter()
	_, barrier, _ := mockBarrier(t)
	view := NewBarrierView(barrier, "logical/")

	n := &NoopBackend{}
	err := r.Mount(n, "prod/aws/", generateUUID(), view)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	err = r.Taint("prod/aws/")
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	err = r.Untaint("prod/aws/")
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	req := &logical.Request{
		Operation: logical.ReadOperation,
		Path:      "prod/aws/foo",
	}
	_, err = r.Route(req)
	if err != nil {
		t.Fatalf("err: %v", err)
	}
}

func TestPathsToRadix(t *testing.T) {
	// Provide real paths
	paths := []string{
		"foo",
		"foo/*",
		"sub/bar*",
	}
	r := pathsToRadix(paths)

	raw, ok := r.Get("foo")
	if !ok || raw.(bool) != false {
		t.Fatalf("bad: %v (foo)", raw)
	}

	raw, ok = r.Get("foo/")
	if !ok || raw.(bool) != true {
		t.Fatalf("bad: %v (foo/)", raw)
	}

	raw, ok = r.Get("sub/bar")
	if !ok || raw.(bool) != true {
		t.Fatalf("bad: %v (sub/bar)", raw)
	}
}
<|endoftext|>


<commit_before>package registry

import (
	"errors"
	"fmt"
	"time"

	kapi "k8s.io/kubernetes/pkg/api"
	kcoreclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion"
	"k8s.io/kubernetes/pkg/fields"
	"k8s.io/kubernetes/pkg/watch"

	"github.com/openshift/origin/pkg/deploy/api"
	deployutil "github.com/openshift/origin/pkg/deploy/util"
)

var (
	// ErrUnknownDeploymentPhase is returned for WaitForRunningDeployment if an unknown phase is returned.
	ErrUnknownDeploymentPhase = errors.New("unknown deployment phase")
)

// WaitForRunningDeployment waits until the specified deployment is no longer New or Pending. Returns true if
// the deployment became running, complete, or failed within timeout, false if it did not, and an error if any
// other error state occurred. The last observed deployment state is returned.
func WaitForRunningDeployment(rn kcoreclient.ReplicationControllersGetter, observed *kapi.ReplicationController, timeout time.Duration) (*kapi.ReplicationController, bool, error) {
	fieldSelector := fields.Set{"metadata.name": observed.Name}.AsSelector()
	options := kapi.ListOptions{FieldSelector: fieldSelector, ResourceVersion: observed.ResourceVersion}
	w, err := rn.ReplicationControllers(observed.Namespace).Watch(options)
	if err != nil {
		return observed, false, err
	}
	defer w.Stop()

	if _, err := watch.Until(timeout, w, func(e watch.Event) (bool, error) {
		if e.Type == watch.Error {
			return false, fmt.Errorf("encountered error while watching for replication controller: %v", e.Object)
		}
		obj, isController := e.Object.(*kapi.ReplicationController)
		if !isController {
			return false, fmt.Errorf("received unknown object while watching for deployments: %v", obj)
		}
		observed = obj
		switch deployutil.DeploymentStatusFor(observed) {
		case api.DeploymentStatusRunning, api.DeploymentStatusFailed, api.DeploymentStatusComplete:
			return true, nil
		case api.DeploymentStatusNew, api.DeploymentStatusPending:
			return false, nil
		default:
			return false, ErrUnknownDeploymentPhase
		}
	}); err != nil {
		return observed, false, err
	}

	return observed, true, nil
}
<commit_msg>deployment: retry failed watch when observed controller has old resource version<commit_after>package registry

import (
	"errors"
	"fmt"
	"time"

	kapi "k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/api/unversioned"
	kcoreclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion"
	"k8s.io/kubernetes/pkg/fields"
	"k8s.io/kubernetes/pkg/watch"

	"github.com/golang/glog"
	"github.com/openshift/origin/pkg/deploy/api"
	deployutil "github.com/openshift/origin/pkg/deploy/util"
)

var (
	// ErrUnknownDeploymentPhase is returned for WaitForRunningDeployment if an unknown phase is returned.
	ErrUnknownDeploymentPhase = errors.New("unknown deployment phase")
	ErrTooOldResourceVersion  = errors.New("too old resource version")
)

// WaitForRunningDeployment waits until the specified deployment is no longer New or Pending. Returns true if
// the deployment became running, complete, or failed within timeout, false if it did not, and an error if any
// other error state occurred. The last observed deployment state is returned.
func WaitForRunningDeployment(rn kcoreclient.ReplicationControllersGetter, observed *kapi.ReplicationController, timeout time.Duration) (*kapi.ReplicationController, bool, error) {
	fieldSelector := fields.Set{"metadata.name": observed.Name}.AsSelector()
	options := kapi.ListOptions{FieldSelector: fieldSelector, ResourceVersion: observed.ResourceVersion}
	w, err := rn.ReplicationControllers(observed.Namespace).Watch(options)
	if err != nil {
		return observed, false, err
	}
	defer w.Stop()

	if _, err := watch.Until(timeout, w, func(e watch.Event) (bool, error) {
		if e.Type == watch.Error {
			// When we send too old resource version in observed replication controller to
			// watcher, restart the watch with latest available controller.
			switch t := e.Object.(type) {
			case *unversioned.Status:
				if t.Reason == unversioned.StatusReasonGone {
					glog.V(5).Infof("encountered error while watching for replication controller: %v (retrying)", t)
					return false, ErrTooOldResourceVersion
				}
			}
			return false, fmt.Errorf("encountered error while watching for replication controller: %v", e.Object)
		}
		obj, isController := e.Object.(*kapi.ReplicationController)
		if !isController {
			return false, fmt.Errorf("received unknown object while watching for deployments: %v", obj)
		}
		observed = obj
		switch deployutil.DeploymentStatusFor(observed) {
		case api.DeploymentStatusRunning, api.DeploymentStatusFailed, api.DeploymentStatusComplete:
			return true, nil
		case api.DeploymentStatusNew, api.DeploymentStatusPending:
			return false, nil
		default:
			return false, ErrUnknownDeploymentPhase
		}
	}); err != nil {
		if err == ErrTooOldResourceVersion {
			latestRC, err := rn.ReplicationControllers(observed.Namespace).Get(observed.Name)
			if err != nil {
				return observed, false, err
			}
			return WaitForRunningDeployment(rn, latestRC, timeout)
		}
		return observed, false, err
	}

	return observed, true, nil
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Jetstack cert-manager contributors.

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 vault

import (
	"crypto/x509"
	"errors"
	"fmt"
	"net/http"
	"path"
	"path/filepath"
	"strings"
	"time"

	vault "github.com/hashicorp/vault/api"
	"github.com/hashicorp/vault/helper/certutil"
	corelisters "k8s.io/client-go/listers/core/v1"

	"github.com/jetstack/cert-manager/pkg/apis/certmanager/v1alpha2"
	"github.com/jetstack/cert-manager/pkg/util/pki"
)

var _ Interface = &Vault{}

type VaultClientBuilder func(namespace string, secretsLister corelisters.SecretLister,
	issuer v1alpha2.GenericIssuer) (Interface, error)

type Interface interface {
	Sign(csrPEM []byte, duration time.Duration) (certPEM []byte, caPEM []byte, err error)
	Sys() *vault.Sys
}

type Client interface {
	NewRequest(method, requestPath string) *vault.Request
	RawRequest(r *vault.Request) (*vault.Response, error)
	SetToken(v string)
	Token() string
	Sys() *vault.Sys
}

type Vault struct {
	secretsLister corelisters.SecretLister
	issuer        v1alpha2.GenericIssuer
	namespace     string

	client Client
}

func New(namespace string, secretsLister corelisters.SecretLister,
	issuer v1alpha2.GenericIssuer) (Interface, error) {
	v := &Vault{
		secretsLister: secretsLister,
		namespace:     namespace,
		issuer:        issuer,
	}

	cfg, err := v.newConfig()
	if err != nil {
		return nil, err
	}

	client, err := vault.NewClient(cfg)
	if err != nil {
		return nil, fmt.Errorf("error initializing Vault client: %s", err.Error())
	}

	if err := v.setToken(client); err != nil {
		return nil, err
	}

	v.client = client

	return v, nil
}

func (v *Vault) Sign(csrPEM []byte, duration time.Duration) (cert []byte, ca []byte, err error) {
	csr, err := pki.DecodeX509CertificateRequestBytes(csrPEM)
	if err != nil {
		return nil, nil, fmt.Errorf("faild to decode CSR for signing: %s", err)
	}

	parameters := map[string]string{
		"common_name": csr.Subject.CommonName,
		"alt_names":   strings.Join(csr.DNSNames, ","),
		"ip_sans":     strings.Join(pki.IPAddressesToString(csr.IPAddresses), ","),
		"uri_sans":    strings.Join(pki.URLsToString(csr.URIs), ","),
		"ttl":         duration.String(),
		"csr":         string(csrPEM),

		"exclude_cn_from_sans": "true",
	}

	url := path.Join("/v1", v.issuer.GetSpec().Vault.Path)

	request := v.client.NewRequest("POST", url)

	if err := request.SetJSONBody(parameters); err != nil {
		return nil, nil, fmt.Errorf("failed to build vault request: %s", err)
	}

	resp, err := v.client.RawRequest(request)
	if err != nil {
		return nil, nil, fmt.Errorf("failed to sign certificate by vault: %s", err)
	}

	defer resp.Body.Close()

	vaultResult := certutil.Secret{}
	resp.DecodeJSON(&vaultResult)
	if err != nil {
		return nil, nil, fmt.Errorf("Failed to decode response returned by vault: %s", err)
	}

	parsedBundle, err := certutil.ParsePKIMap(vaultResult.Data)
	if err != nil {
		return nil, nil, fmt.Errorf("Failed to decode response returned by vault: %s", err)
	}

	bundle, err := parsedBundle.ToCertBundle()
	if err != nil {
		return nil, nil, fmt.Errorf("unable to convert certificate bundle to PEM bundle: %s", err.Error())
	}

	var caPem []byte = nil
	if len(bundle.CAChain) > 0 {
		caPem = []byte(bundle.CAChain[0])
	}

	return []byte(bundle.ToPEMBundle()), caPem, nil
}

func (v *Vault) setToken(client Client) error {
	tokenRef := v.issuer.GetSpec().Vault.Auth.TokenSecretRef
	if tokenRef != nil {
		token, err := v.tokenRef(tokenRef.Name, v.namespace, tokenRef.Key)
		if err != nil {
			return err
		}
		client.SetToken(token)

		return nil
	}

	appRole := v.issuer.GetSpec().Vault.Auth.AppRole
	if appRole != nil {
		token, err := v.requestTokenWithAppRoleRef(client, appRole)
		if err != nil {
			return err
		}
		client.SetToken(token)

		return nil
	}

	kubernetesAuth := v.issuer.GetSpec().Vault.Auth.Kubernetes
	if kubernetesAuth != nil {
		token, err := v.requestTokenWithKubernetesAuth(client, kubernetesAuth)
		if err != nil {
			return fmt.Errorf("error reading Kubernetes service account token from %s: %s", kubernetesAuth.SecretRef.Name, err.Error())
		}
		client.SetToken(token)
		return nil
	}

	return fmt.Errorf("error initializing Vault client: tokenSecretRef, appRoleSecretRef, or Kubernetes auth role not set")
}

func (v *Vault) newConfig() (*vault.Config, error) {
	cfg := vault.DefaultConfig()
	cfg.Address = v.issuer.GetSpec().Vault.Server

	certs := v.issuer.GetSpec().Vault.CABundle
	if len(certs) == 0 {
		return cfg, nil
	}

	caCertPool := x509.NewCertPool()
	ok := caCertPool.AppendCertsFromPEM(certs)
	if ok == false {
		return nil, fmt.Errorf("error loading Vault CA bundle")
	}

	cfg.HttpClient.Transport.(*http.Transport).TLSClientConfig.RootCAs = caCertPool

	return cfg, nil
}

func (v *Vault) tokenRef(name, namespace, key string) (string, error) {
	secret, err := v.secretsLister.Secrets(namespace).Get(name)
	if err != nil {
		return "", err
	}

	if key == "" {
		key = v1alpha2.DefaultVaultTokenAuthSecretKey
	}

	keyBytes, ok := secret.Data[key]
	if !ok {
		return "", fmt.Errorf("no data for %q in secret '%s/%s'", key, name, namespace)
	}

	token := string(keyBytes)
	token = strings.TrimSpace(token)

	return token, nil
}

func (v *Vault) appRoleRef(appRole *v1alpha2.VaultAppRole) (roleId, secretId string, err error) {
	roleId = strings.TrimSpace(appRole.RoleId)

	secret, err := v.secretsLister.Secrets(v.namespace).Get(appRole.SecretRef.Name)
	if err != nil {
		return "", "", err
	}

	key := appRole.SecretRef.Key

	keyBytes, ok := secret.Data[key]
	if !ok {
		return "", "", fmt.Errorf("no data for %q in secret '%s/%s'", key, v.namespace, appRole.SecretRef.Name)
	}

	secretId = string(keyBytes)
	secretId = strings.TrimSpace(secretId)

	return roleId, secretId, nil
}

func (v *Vault) requestTokenWithAppRoleRef(client Client, appRole *v1alpha2.VaultAppRole) (string, error) {
	roleId, secretId, err := v.appRoleRef(appRole)
	if err != nil {
		return "", err
	}

	parameters := map[string]string{
		"role_id":   roleId,
		"secret_id": secretId,
	}

	authPath := appRole.Path
	if authPath == "" {
		authPath = "approle"
	}

	url := path.Join("/v1", "auth", authPath, "login")

	request := client.NewRequest("POST", url)

	err = request.SetJSONBody(parameters)
	if err != nil {
		return "", fmt.Errorf("error encoding Vault parameters: %s", err.Error())
	}

	resp, err := client.RawRequest(request)
	if err != nil {
		return "", fmt.Errorf("error logging in to Vault server: %s", err.Error())
	}

	defer resp.Body.Close()

	vaultResult := vault.Secret{}
	if err := resp.DecodeJSON(&vaultResult); err != nil {
		return "", fmt.Errorf("unable to decode JSON payload: %s", err.Error())
	}

	token, err := vaultResult.TokenID()
	if err != nil {
		return "", fmt.Errorf("unable to read token: %s", err.Error())
	}

	if token == "" {
		return "", errors.New("no token returned")
	}

	return token, nil
}

func (v *Vault) requestTokenWithKubernetesAuth(client Client, kubernetesAuth *v1alpha2.VaultKubernetesAuth) (string, error) {
	secret, err := v.secretsLister.Secrets(v.namespace).Get(kubernetesAuth.SecretRef.Name)
	if err != nil {
		return "", err
	}

	key := kubernetesAuth.SecretRef.Key
	if key == "" {
		key = v1alpha2.DefaultVaultTokenAuthSecretKey
	}

	keyBytes, ok := secret.Data[key]
	if !ok {
		return "", fmt.Errorf("no data for %q in secret '%s/%s'", key, v.namespace, kubernetesAuth.SecretRef.Name)
	}

	jwt := string(keyBytes)

	parameters := map[string]string{
		"role": kubernetesAuth.Role,
		"jwt":  jwt,
	}

	mountPath := kubernetesAuth.Path
	if mountPath == "" {
		mountPath = v1alpha2.DefaultVaultKubernetesAuthMountPath
	}

	url := filepath.Join("/v1", "auth", mountPath, "login")
	request := client.NewRequest("POST", url)
	err = request.SetJSONBody(parameters)
	if err != nil {
		return "", fmt.Errorf("error encoding Vault parameters: %s", err.Error())
	}

	resp, err := client.RawRequest(request)
	if err != nil {
		return "", fmt.Errorf("error calling Vault server: %s", err.Error())
	}

	defer resp.Body.Close()
	vaultResult := vault.Secret{}
	err = resp.DecodeJSON(&vaultResult)
	if err != nil {
		return "", fmt.Errorf("unable to decode JSON payload: %s", err.Error())
	}

	token, err := vaultResult.TokenID()
	if err != nil {
		return "", fmt.Errorf("unable to read token: %s", err.Error())
	}

	return token, nil
}

func (v *Vault) Sys() *vault.Sys {
	return v.client.Sys()
}
<commit_msg>Fix to handle error<commit_after>/*
Copyright 2019 The Jetstack cert-manager contributors.

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 vault

import (
	"crypto/x509"
	"errors"
	"fmt"
	"net/http"
	"path"
	"path/filepath"
	"strings"
	"time"

	vault "github.com/hashicorp/vault/api"
	"github.com/hashicorp/vault/helper/certutil"
	corelisters "k8s.io/client-go/listers/core/v1"

	"github.com/jetstack/cert-manager/pkg/apis/certmanager/v1alpha2"
	"github.com/jetstack/cert-manager/pkg/util/pki"
)

var _ Interface = &Vault{}

type VaultClientBuilder func(namespace string, secretsLister corelisters.SecretLister,
	issuer v1alpha2.GenericIssuer) (Interface, error)

type Interface interface {
	Sign(csrPEM []byte, duration time.Duration) (certPEM []byte, caPEM []byte, err error)
	Sys() *vault.Sys
}

type Client interface {
	NewRequest(method, requestPath string) *vault.Request
	RawRequest(r *vault.Request) (*vault.Response, error)
	SetToken(v string)
	Token() string
	Sys() *vault.Sys
}

type Vault struct {
	secretsLister corelisters.SecretLister
	issuer        v1alpha2.GenericIssuer
	namespace     string

	client Client
}

func New(namespace string, secretsLister corelisters.SecretLister,
	issuer v1alpha2.GenericIssuer) (Interface, error) {
	v := &Vault{
		secretsLister: secretsLister,
		namespace:     namespace,
		issuer:        issuer,
	}

	cfg, err := v.newConfig()
	if err != nil {
		return nil, err
	}

	client, err := vault.NewClient(cfg)
	if err != nil {
		return nil, fmt.Errorf("error initializing Vault client: %s", err.Error())
	}

	if err := v.setToken(client); err != nil {
		return nil, err
	}

	v.client = client

	return v, nil
}

func (v *Vault) Sign(csrPEM []byte, duration time.Duration) (cert []byte, ca []byte, err error) {
	csr, err := pki.DecodeX509CertificateRequestBytes(csrPEM)
	if err != nil {
		return nil, nil, fmt.Errorf("faild to decode CSR for signing: %s", err)
	}

	parameters := map[string]string{
		"common_name": csr.Subject.CommonName,
		"alt_names":   strings.Join(csr.DNSNames, ","),
		"ip_sans":     strings.Join(pki.IPAddressesToString(csr.IPAddresses), ","),
		"uri_sans":    strings.Join(pki.URLsToString(csr.URIs), ","),
		"ttl":         duration.String(),
		"csr":         string(csrPEM),

		"exclude_cn_from_sans": "true",
	}

	url := path.Join("/v1", v.issuer.GetSpec().Vault.Path)

	request := v.client.NewRequest("POST", url)

	if err := request.SetJSONBody(parameters); err != nil {
		return nil, nil, fmt.Errorf("failed to build vault request: %s", err)
	}

	resp, err := v.client.RawRequest(request)
	if err != nil {
		return nil, nil, fmt.Errorf("failed to sign certificate by vault: %s", err)
	}

	defer resp.Body.Close()

	vaultResult := certutil.Secret{}
	err = resp.DecodeJSON(&vaultResult)
	if err != nil {
		return nil, nil, fmt.Errorf("failed to decode response returned by vault: %s", err)
	}

	parsedBundle, err := certutil.ParsePKIMap(vaultResult.Data)
	if err != nil {
		return nil, nil, fmt.Errorf("failed to decode response returned by vault: %s", err)
	}

	bundle, err := parsedBundle.ToCertBundle()
	if err != nil {
		return nil, nil, fmt.Errorf("unable to convert certificate bundle to PEM bundle: %s", err.Error())
	}

	var caPem []byte = nil
	if len(bundle.CAChain) > 0 {
		caPem = []byte(bundle.CAChain[0])
	}

	return []byte(bundle.ToPEMBundle()), caPem, nil
}

func (v *Vault) setToken(client Client) error {
	tokenRef := v.issuer.GetSpec().Vault.Auth.TokenSecretRef
	if tokenRef != nil {
		token, err := v.tokenRef(tokenRef.Name, v.namespace, tokenRef.Key)
		if err != nil {
			return err
		}
		client.SetToken(token)

		return nil
	}

	appRole := v.issuer.GetSpec().Vault.Auth.AppRole
	if appRole != nil {
		token, err := v.requestTokenWithAppRoleRef(client, appRole)
		if err != nil {
			return err
		}
		client.SetToken(token)

		return nil
	}

	kubernetesAuth := v.issuer.GetSpec().Vault.Auth.Kubernetes
	if kubernetesAuth != nil {
		token, err := v.requestTokenWithKubernetesAuth(client, kubernetesAuth)
		if err != nil {
			return fmt.Errorf("error reading Kubernetes service account token from %s: %s", kubernetesAuth.SecretRef.Name, err.Error())
		}
		client.SetToken(token)
		return nil
	}

	return fmt.Errorf("error initializing Vault client: tokenSecretRef, appRoleSecretRef, or Kubernetes auth role not set")
}

func (v *Vault) newConfig() (*vault.Config, error) {
	cfg := vault.DefaultConfig()
	cfg.Address = v.issuer.GetSpec().Vault.Server

	certs := v.issuer.GetSpec().Vault.CABundle
	if len(certs) == 0 {
		return cfg, nil
	}

	caCertPool := x509.NewCertPool()
	ok := caCertPool.AppendCertsFromPEM(certs)
	if ok == false {
		return nil, fmt.Errorf("error loading Vault CA bundle")
	}

	cfg.HttpClient.Transport.(*http.Transport).TLSClientConfig.RootCAs = caCertPool

	return cfg, nil
}

func (v *Vault) tokenRef(name, namespace, key string) (string, error) {
	secret, err := v.secretsLister.Secrets(namespace).Get(name)
	if err != nil {
		return "", err
	}

	if key == "" {
		key = v1alpha2.DefaultVaultTokenAuthSecretKey
	}

	keyBytes, ok := secret.Data[key]
	if !ok {
		return "", fmt.Errorf("no data for %q in secret '%s/%s'", key, name, namespace)
	}

	token := string(keyBytes)
	token = strings.TrimSpace(token)

	return token, nil
}

func (v *Vault) appRoleRef(appRole *v1alpha2.VaultAppRole) (roleId, secretId string, err error) {
	roleId = strings.TrimSpace(appRole.RoleId)

	secret, err := v.secretsLister.Secrets(v.namespace).Get(appRole.SecretRef.Name)
	if err != nil {
		return "", "", err
	}

	key := appRole.SecretRef.Key

	keyBytes, ok := secret.Data[key]
	if !ok {
		return "", "", fmt.Errorf("no data for %q in secret '%s/%s'", key, v.namespace, appRole.SecretRef.Name)
	}

	secretId = string(keyBytes)
	secretId = strings.TrimSpace(secretId)

	return roleId, secretId, nil
}

func (v *Vault) requestTokenWithAppRoleRef(client Client, appRole *v1alpha2.VaultAppRole) (string, error) {
	roleId, secretId, err := v.appRoleRef(appRole)
	if err != nil {
		return "", err
	}

	parameters := map[string]string{
		"role_id":   roleId,
		"secret_id": secretId,
	}

	authPath := appRole.Path
	if authPath == "" {
		authPath = "approle"
	}

	url := path.Join("/v1", "auth", authPath, "login")

	request := client.NewRequest("POST", url)

	err = request.SetJSONBody(parameters)
	if err != nil {
		return "", fmt.Errorf("error encoding Vault parameters: %s", err.Error())
	}

	resp, err := client.RawRequest(request)
	if err != nil {
		return "", fmt.Errorf("error logging in to Vault server: %s", err.Error())
	}

	defer resp.Body.Close()

	vaultResult := vault.Secret{}
	if err := resp.DecodeJSON(&vaultResult); err != nil {
		return "", fmt.Errorf("unable to decode JSON payload: %s", err.Error())
	}

	token, err := vaultResult.TokenID()
	if err != nil {
		return "", fmt.Errorf("unable to read token: %s", err.Error())
	}

	if token == "" {
		return "", errors.New("no token returned")
	}

	return token, nil
}

func (v *Vault) requestTokenWithKubernetesAuth(client Client, kubernetesAuth *v1alpha2.VaultKubernetesAuth) (string, error) {
	secret, err := v.secretsLister.Secrets(v.namespace).Get(kubernetesAuth.SecretRef.Name)
	if err != nil {
		return "", err
	}

	key := kubernetesAuth.SecretRef.Key
	if key == "" {
		key = v1alpha2.DefaultVaultTokenAuthSecretKey
	}

	keyBytes, ok := secret.Data[key]
	if !ok {
		return "", fmt.Errorf("no data for %q in secret '%s/%s'", key, v.namespace, kubernetesAuth.SecretRef.Name)
	}

	jwt := string(keyBytes)

	parameters := map[string]string{
		"role": kubernetesAuth.Role,
		"jwt":  jwt,
	}

	mountPath := kubernetesAuth.Path
	if mountPath == "" {
		mountPath = v1alpha2.DefaultVaultKubernetesAuthMountPath
	}

	url := filepath.Join("/v1", "auth", mountPath, "login")
	request := client.NewRequest("POST", url)
	err = request.SetJSONBody(parameters)
	if err != nil {
		return "", fmt.Errorf("error encoding Vault parameters: %s", err.Error())
	}

	resp, err := client.RawRequest(request)
	if err != nil {
		return "", fmt.Errorf("error calling Vault server: %s", err.Error())
	}

	defer resp.Body.Close()
	vaultResult := vault.Secret{}
	err = resp.DecodeJSON(&vaultResult)
	if err != nil {
		return "", fmt.Errorf("unable to decode JSON payload: %s", err.Error())
	}

	token, err := vaultResult.TokenID()
	if err != nil {
		return "", fmt.Errorf("unable to read token: %s", err.Error())
	}

	return token, nil
}

func (v *Vault) Sys() *vault.Sys {
	return v.client.Sys()
}
<|endoftext|>


<commit_before>/*
Copyright 2018 The Jetstack cert-manager contributors.

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 venafi

import (
	"crypto/x509"
	"errors"
	"fmt"
	"strings"
	"time"

	"github.com/Venafi/vcert/pkg/certificate"

	internalvanafiapi "github.com/jetstack/cert-manager/pkg/internal/venafi/api"
	"github.com/jetstack/cert-manager/pkg/util/pki"
)

// ErrCustomFieldsType provides a common error structure for an invalid Venafi custom field type
type ErrCustomFieldsType struct {
	Type internalvanafiapi.CustomFieldType
}

func (err ErrCustomFieldsType) Error() string {
	return fmt.Sprintf("certificate request contains an invalid Venafi custom fields type: %q", err.Type)
}

// This function sends a request to Venafi to for a signed certificate.
// The CSR will be decoded to be validated against the zone configuration policy.
// Upon the template being successfully defaulted and validated, the CSR will be sent, as is.
func (v *Venafi) Sign(csrPEM []byte, duration time.Duration, customFields []internalvanafiapi.CustomField) (cert []byte, err error) {
	// Retrieve a copy of the Venafi zone.
	// This contains default values and policy control info that we can apply
	// and check against locally.
	zoneCfg, err := v.client.ReadZoneConfiguration()
	if err != nil {
		return nil, err
	}

	tmpl, err := pki.GenerateTemplateFromCSRPEM(csrPEM, duration, false)
	if err != nil {
		return nil, err
	}

	// Create a vcert Request structure
	vreq := newVRequest(tmpl)

	// Add cert-manager origin tag
	vreq.CustomFields = []certificate.CustomField{
		{
			Type:  certificate.CustomFieldOrigin,
			Value: "Jetstack cert-manager",
		},
	}

	// Convert over custom fields from our struct type to venafi's
	if len(customFields) > 0 {
		for _, field := range customFields {
			var fieldType certificate.CustomFieldType
			switch field.Type {
			case internalvanafiapi.CustomFieldTypePlain, "":
				fieldType = certificate.CustomFieldPlain
			default:
				return nil, ErrCustomFieldsType{Type: field.Type}
			}

			vreq.CustomFields = append(vreq.CustomFields, certificate.CustomField{
				Type:  fieldType,
				Name:  field.Name,
				Value: field.Value,
			})
		}
	}

	// Apply default values from the Venafi zone
	zoneCfg.UpdateCertificateRequest(vreq)

	// Here we are validating the request using the current policy with
	// defaulting applied to the CSR. The CSR we send will not be defaulted
	// however, as this will be done again server side.
	err = zoneCfg.ValidateCertificateRequest(vreq)
	if err != nil {
		return nil, err
	}

	vreq.SetCSR(csrPEM)
	// Set options on the request
	vreq.CsrOrigin = certificate.UserProvidedCSR
	//// TODO: better set the timeout here. Right now, we'll block for this amount of time.
	vreq.Timeout = time.Minute * 5

	// Set the 'ObjectName' through the request friendly name. This is set in
	// order of precedence CN->DNS->URI.
	switch {
	case len(tmpl.Subject.CommonName) > 0:
		vreq.FriendlyName = tmpl.Subject.CommonName
		break
	case len(tmpl.DNSNames) > 0:
		vreq.FriendlyName = tmpl.DNSNames[0]
		break
	case len(tmpl.URIs) > 0:
		vreq.FriendlyName = tmpl.URIs[0].String()
		break
	default:
		return nil, errors.New(
			"certificate request contains no Common Name, DNS Name, nor URI SAN, at least one must be supplied to be used as the Venafi certificate objects name")
	}

	// Set the request CSR with the passed value
	if err := vreq.SetCSR(csrPEM); err != nil {
		return nil, err
	}

	// Send the certificate signing request to Venafi
	requestID, err := v.client.RequestCertificate(vreq)
	if err != nil {
		return nil, err
	}

	// Set the PickupID so vcert does not have to look it up by the fingerprint
	vreq.PickupID = requestID

	// Retrieve the certificate from request
	pemCollection, err := v.client.RetrieveCertificate(vreq)
	if err != nil {
		return nil, err
	}

	// Construct the certificate chain and return the new keypair
	cs := append([]string{pemCollection.Certificate}, pemCollection.Chain...)
	chain := strings.Join(cs, "\n")

	return []byte(chain), nil
}

func newVRequest(cert *x509.Certificate) *certificate.Request {
	req := certificate.NewRequest(cert)

	if len(cert.Subject.Organization) == 0 {
		// Venafi TPP errors on an empty DN
		// this applies the pre-0.15 default again if no other DN field is set
		cert.Subject.Organization = []string{"cert-manager"}
	}
	// overwrite entire Subject block
	req.Subject = cert.Subject
	return req
}
<commit_msg>Error on venafi CertificateRequest when DN is empty<commit_after>/*
Copyright 2018 The Jetstack cert-manager contributors.

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 venafi

import (
	"crypto/x509"
	"errors"
	"fmt"
	"strings"
	"time"

	"github.com/Venafi/vcert/pkg/certificate"

	internalvanafiapi "github.com/jetstack/cert-manager/pkg/internal/venafi/api"
	"github.com/jetstack/cert-manager/pkg/util/pki"
)

// ErrCustomFieldsType provides a common error structure for an invalid Venafi custom field type
type ErrCustomFieldsType struct {
	Type internalvanafiapi.CustomFieldType
}

func (err ErrCustomFieldsType) Error() string {
	return fmt.Sprintf("certificate request contains an invalid Venafi custom fields type: %q", err.Type)
}

var ErrorMissingSubject = errors.New("certificate needs a comon name or at least one field in the subject set to be processed by Venafi")

// This function sends a request to Venafi to for a signed certificate.
// The CSR will be decoded to be validated against the zone configuration policy.
// Upon the template being successfully defaulted and validated, the CSR will be sent, as is.
func (v *Venafi) Sign(csrPEM []byte, duration time.Duration, customFields []internalvanafiapi.CustomField) (cert []byte, err error) {
	// Retrieve a copy of the Venafi zone.
	// This contains default values and policy control info that we can apply
	// and check against locally.
	zoneCfg, err := v.client.ReadZoneConfiguration()
	if err != nil {
		return nil, err
	}

	tmpl, err := pki.GenerateTemplateFromCSRPEM(csrPEM, duration, false)
	if err != nil {
		return nil, err
	}

	if tmpl.Subject.String() == "" {
		return nil, ErrorMissingSubject
	}

	// Create a vcert Request structure
	vreq := newVRequest(tmpl)

	// Add cert-manager origin tag
	vreq.CustomFields = []certificate.CustomField{
		{
			Type:  certificate.CustomFieldOrigin,
			Value: "Jetstack cert-manager",
		},
	}

	// Convert over custom fields from our struct type to venafi's
	if len(customFields) > 0 {
		for _, field := range customFields {
			var fieldType certificate.CustomFieldType
			switch field.Type {
			case internalvanafiapi.CustomFieldTypePlain, "":
				fieldType = certificate.CustomFieldPlain
			default:
				return nil, ErrCustomFieldsType{Type: field.Type}
			}

			vreq.CustomFields = append(vreq.CustomFields, certificate.CustomField{
				Type:  fieldType,
				Name:  field.Name,
				Value: field.Value,
			})
		}
	}

	// Apply default values from the Venafi zone
	zoneCfg.UpdateCertificateRequest(vreq)

	// Here we are validating the request using the current policy with
	// defaulting applied to the CSR. The CSR we send will not be defaulted
	// however, as this will be done again server side.
	err = zoneCfg.ValidateCertificateRequest(vreq)
	if err != nil {
		return nil, err
	}

	vreq.SetCSR(csrPEM)
	// Set options on the request
	vreq.CsrOrigin = certificate.UserProvidedCSR
	//// TODO: better set the timeout here. Right now, we'll block for this amount of time.
	vreq.Timeout = time.Minute * 5

	// Set the 'ObjectName' through the request friendly name. This is set in
	// order of precedence CN->DNS->URI.
	switch {
	case len(tmpl.Subject.CommonName) > 0:
		vreq.FriendlyName = tmpl.Subject.CommonName
		break
	case len(tmpl.DNSNames) > 0:
		vreq.FriendlyName = tmpl.DNSNames[0]
		break
	case len(tmpl.URIs) > 0:
		vreq.FriendlyName = tmpl.URIs[0].String()
		break
	default:
		return nil, errors.New(
			"certificate request contains no Common Name, DNS Name, nor URI SAN, at least one must be supplied to be used as the Venafi certificate objects name")
	}

	// Set the request CSR with the passed value
	if err := vreq.SetCSR(csrPEM); err != nil {
		return nil, err
	}

	// Send the certificate signing request to Venafi
	requestID, err := v.client.RequestCertificate(vreq)
	if err != nil {
		return nil, err
	}

	// Set the PickupID so vcert does not have to look it up by the fingerprint
	vreq.PickupID = requestID

	// Retrieve the certificate from request
	pemCollection, err := v.client.RetrieveCertificate(vreq)
	if err != nil {
		return nil, err
	}

	// Construct the certificate chain and return the new keypair
	cs := append([]string{pemCollection.Certificate}, pemCollection.Chain...)
	chain := strings.Join(cs, "\n")

	return []byte(chain), nil
}

func newVRequest(cert *x509.Certificate) *certificate.Request {
	req := certificate.NewRequest(cert)

	// overwrite entire Subject block
	req.Subject = cert.Subject
	return req
}
<|endoftext|>


<commit_before>/*
 * Minio Cloud Storage, (C) 2016 Minio, 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 ioutils_test

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

	"github.com/minio/minio/pkg/ioutils"

	. "gopkg.in/check.v1"
)

func Test(t *testing.T) { TestingT(t) }

type MySuite struct{}

var _ = Suite(&MySuite{})

func (s *MySuite) TestIoutils(c *C) {
	path, err := ioutil.TempDir(os.TempDir(), "minio-ioutils_test")
	c.Assert(err, IsNil)
	defer os.RemoveAll(path)

	status, err := ioutils.IsDirEmpty(path)
	c.Assert(err, IsNil)
	c.Assert(status, Equals, True)
}
<commit_msg>pkg/ioutils: True should be true<commit_after>/*
 * Minio Cloud Storage, (C) 2016 Minio, 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 ioutils_test

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

	"github.com/minio/minio/pkg/ioutils"

	. "gopkg.in/check.v1"
)

func Test(t *testing.T) { TestingT(t) }

type MySuite struct{}

var _ = Suite(&MySuite{})

func (s *MySuite) TestIoutils(c *C) {
	path, err := ioutil.TempDir(os.TempDir(), "minio-ioutils_test")
	c.Assert(err, IsNil)
	defer os.RemoveAll(path)

	status, err := ioutils.IsDirEmpty(path)
	c.Assert(err, IsNil)
	c.Assert(status, Equals, true)
}
<|endoftext|>


<commit_before>package program

import (
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"runtime"
	"strings"
	"testing"

	"github.com/elves/elvish/pkg/buildinfo"
)

func parse(args []string) (*flag.FlagSet, *Flags) {
	f := Flags{}
	fs := newFlagSet(os.Stderr, &f)
	err := fs.Parse(args)
	if err != nil {
		panic(fmt.Sprintln("bad flags in test", args))
	}
	return fs, &f
}

type programTest struct {
	run   []string
	stdin string

	wantExit         int
	wantStdout       string
	wantStderr       string
	wantStdoutPrefix string
	wantStderrPrefix string
}

var programTests = []programTest{
	{
		run:        elvish("-version"),
		wantStdout: buildinfo.Version + "\n",
	},
	{
		run: elvish("-buildinfo"),
		wantStdout: fmt.Sprintf(
			"Version: %v\nGo version: %v\nReproducible build: %v\n",
			buildinfo.Version,
			runtime.Version(),
			buildinfo.Reproducible,
		),
	},
	{
		run: elvish("-buildinfo", "-json"),
		wantStdout: mustToJSON(struct {
			Version      string `json:"version"`
			GoVersion    string `json:"goversion"`
			Reproducible bool   `json:"reproducible"`
		}{
			buildinfo.Version,
			runtime.Version(),
			buildinfo.Reproducible == "true",
		}) + "\n",
	},
	{
		run:              elvish("-help"),
		wantStdoutPrefix: "Usage: elvish [flags] [script]",
	},
	// Bad usages.
	badUsage("flag provided but not defined: -bad-flag", "-bad-flag"),
	badUsage("arguments are not allowed with -web", "-web", "x"),
	badUsage("-c cannot be used together with -web", "-web", "-c"),
	badUsage("arguments are not allowed with -daemon", "-daemon", "x"),
}

func elvish(args ...string) []string {
	return append([]string{"elvish"}, args...)
}

func mustToJSON(v interface{}) string {
	b, err := json.Marshal(v)
	if err != nil {
		panic(err)
	}
	return string(b)
}

func badUsage(prefix string, args ...string) programTest {
	return programTest{
		run:              elvish(args...),
		wantStderrPrefix: prefix + "\nUsage: elvish [flags] [script]",
		wantExit:         2,
	}
}

func TestPrograms(t *testing.T) {
	for _, test := range programTests {
		t.Run(strings.Join(test.run, " "), func(t *testing.T) {
			fd0, fd0w := mustMakePipe()
			fd1r, fd1 := mustMakePipe()
			fd2r, fd2 := mustMakePipe()

			fd0w.WriteString(test.stdin)
			fd0w.Close()

			exit := Main([3]*os.File{fd0, fd1, fd2}, test.run)
			fd0.Close()
			fd1.Close()
			fd2.Close()

			stdout := mustReadAllAndClose(fd1r)
			stderr := mustReadAllAndClose(fd2r)
			testOutput(t, "stdout", stdout, test.wantStdout, test.wantStdoutPrefix)
			testOutput(t, "stderr", stderr, test.wantStderr, test.wantStderrPrefix)
			if exit != test.wantExit {
				t.Errorf("got exit %d, want %d", exit, test.wantExit)
			}
		})
	}
}

func testOutput(t *testing.T, name, got, want, wantPrefix string) {
	if wantPrefix != "" {
		if !strings.HasPrefix(got, wantPrefix) {
			t.Errorf("%s mismatch", name)
			t.Logf("got:\n%s", got)
			t.Logf("want prefix:\n%s", wantPrefix)
		}
	} else if got != want {
		t.Errorf("%s mismatch", name)
		t.Logf("got:\n%s", got)
		t.Logf("want:\n%s", want)
	}
}

func mustMakePipe() (r, w *os.File) {
	r, w, err := os.Pipe()
	if err != nil {
		panic(err)
	}
	return r, w
}

func mustReadAllAndClose(r io.ReadCloser) string {
	b, err := ioutil.ReadAll(r)
	if err != nil {
		panic(err)
	}
	r.Close()
	return string(b)
}
<commit_msg>pkg/program: Rewrite test with progtest.<commit_after>package program

import (
	"encoding/json"
	"fmt"
	"runtime"
	"testing"

	"github.com/elves/elvish/pkg/buildinfo"
	. "github.com/elves/elvish/pkg/program/progtest"
)

func TestVersion(t *testing.T) {
	f := Setup()
	defer f.Cleanup()

	Main(f.Fds(), elvish("-version"))

	f.TestOut(t, 1, buildinfo.Version+"\n")
}

func TestBuildInfo(t *testing.T) {
	f := Setup()
	defer f.Cleanup()

	Main(f.Fds(), elvish("-buildinfo"))

	f.TestOut(t, 1,
		fmt.Sprintf(
			"Version: %v\nGo version: %v\nReproducible build: %v\n",
			buildinfo.Version,
			runtime.Version(),
			buildinfo.Reproducible))
}

func TestBuildInfo_JSON(t *testing.T) {
	f := Setup()
	defer f.Cleanup()

	Main(f.Fds(), elvish("-buildinfo", "-json"))

	f.TestOut(t, 1,
		mustToJSON(struct {
			Version      string `json:"version"`
			GoVersion    string `json:"goversion"`
			Reproducible bool   `json:"reproducible"`
		}{
			buildinfo.Version,
			runtime.Version(),
			buildinfo.Reproducible == "true",
		})+"\n")
}

func TestHelp(t *testing.T) {
	f := Setup()
	defer f.Cleanup()

	Main(f.Fds(), elvish("-help"))

	f.TestOutSnippet(t, 1, "Usage: elvish [flags] [script]")
}

func TestBadFlag(t *testing.T) {
	f := Setup()
	defer f.Cleanup()

	exit := Main(f.Fds(), elvish("-bad-flag"))

	testError(t, f, exit, "flag provided but not defined: -bad-flag")
}

func TestWeb_SpuriousArgument(t *testing.T) {
	f := Setup()
	defer f.Cleanup()

	exit := Main(f.Fds(), elvish("-web", "x"))

	testError(t, f, exit, "arguments are not allowed with -web")
}

func TestWeb_SpuriousC(t *testing.T) {
	f := Setup()
	defer f.Cleanup()

	exit := Main(f.Fds(), elvish("-web", "-c"))

	testError(t, f, exit, "-c cannot be used together with -web")
}

func TestDaemon_SpuriousArgument(t *testing.T) {
	f := Setup()
	defer f.Cleanup()

	exit := Main(f.Fds(), elvish("-daemon", "x"))

	testError(t, f, exit, "arguments are not allowed with -daemon")
}

func elvish(args ...string) []string {
	return append([]string{"elvish"}, args...)
}

func mustToJSON(v interface{}) string {
	b, err := json.Marshal(v)
	if err != nil {
		panic(err)
	}
	return string(b)
}

func testError(t *testing.T, f *Fixture, exit int, wantErrSnippet string) {
	t.Helper()
	if exit != 2 {
		t.Errorf("got exit %v, want 2", exit)
	}
	f.TestOutSnippet(t, 2, wantErrSnippet)
}
<|endoftext|>


<commit_before>/*
Copyright 2018 the Heptio Ark contributors.

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 restic

import (
	"encoding/json"
	"os/exec"

	"github.com/pkg/errors"
)

// GetSnapshotID runs a 'restic snapshots' command to get the ID of the snapshot
// in the specified repo matching the set of provided tags, or an error if a
// unique snapshot cannot be identified.
func GetSnapshotID(repoIdentifier, passwordFile string, tags map[string]string) (string, error) {
	output, err := GetSnapshotCommand(repoIdentifier, passwordFile, tags).Cmd().Output()
	if err != nil {
		if exitErr, ok := err.(*exec.ExitError); ok {
			return "", errors.Wrapf(err, "error running command, stderr=%s", exitErr.Stderr)
		}
		return "", errors.Wrap(err, "error running command")
	}

	type snapshotID struct {
		ShortID string `json:"short_id"`
	}

	var snapshots []snapshotID
	if err := json.Unmarshal(output, &snapshots); err != nil {
		return "", errors.Wrap(err, "error unmarshalling restic snapshots result")
	}

	if len(snapshots) != 1 {
		return "", errors.Errorf("expected one matching snapshot, got %d", len(snapshots))
	}

	return snapshots[0].ShortID, nil
}
<commit_msg>use pkg/util/exec for running get snapshot id cmd<commit_after>/*
Copyright 2018 the Heptio Ark contributors.

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 restic

import (
	"encoding/json"

	"github.com/pkg/errors"

	"github.com/heptio/ark/pkg/util/exec"
)

// GetSnapshotID runs a 'restic snapshots' command to get the ID of the snapshot
// in the specified repo matching the set of provided tags, or an error if a
// unique snapshot cannot be identified.
func GetSnapshotID(repoIdentifier, passwordFile string, tags map[string]string) (string, error) {
	stdout, stderr, err := exec.RunCommand(GetSnapshotCommand(repoIdentifier, passwordFile, tags).Cmd())
	if err != nil {
		return "", errors.Wrapf(err, "error running command, stderr=%s", stderr)
	}

	type snapshotID struct {
		ShortID string `json:"short_id"`
	}

	var snapshots []snapshotID
	if err := json.Unmarshal([]byte(stdout), &snapshots); err != nil {
		return "", errors.Wrap(err, "error unmarshalling restic snapshots result")
	}

	if len(snapshots) != 1 {
		return "", errors.Errorf("expected one matching snapshot, got %d", len(snapshots))
	}

	return snapshots[0].ShortID, nil
}
<|endoftext|>