<commit_before>package runtime

import (
	"io"
	"os"

	"github.com/bruston/roost/parser"
)

type Value interface {
	Type() ValueType
	Value() interface{}
}

type Stack struct {
	data []Value
	top  int
}

func (s *Stack) Push(v Value) {
	s.top++
	s.data[s.top] = v
}

func (s *Stack) Pop() Value {
	v := s.data[s.top]
	s.data[s.top] = nil
	s.top--
	return v
}

func (s *Stack) Peek() Value { return s.data[s.top] }

func (s *Stack) Dup() { s.Push(s.data[s.top]) }

func (s *Stack) Drop() { s.Pop() }

func (s *Stack) Swap() {
	s.data[s.top], s.data[s.top-1] = s.data[s.top-1], s.data[s.top]
}

func (s *Stack) PushBool(b bool) { s.Push(BoolValue{ValueBool, b}) }

func (s *Stack) PushNum(n float64) { s.Push(NumValue{ValueNum, n}) }

func (s *Stack) PushString(str string) { s.Push(StringValue{ValueString, str}) }

func (s *Stack) PushBlob(b []byte) { s.Push(&BlobValue{ValueBlob, b}) }

func NewStack(size int) *Stack { return &Stack{data: make([]Value, size), top: -1} }

type Env struct {
	Stack   *Stack
	Return  *Stack
	Stdin   io.Reader
	Stdout  io.Writer
	Stderr  io.Writer
	Builtin map[string]FuncValue
	Vars    map[string]Value
	Words   map[string]*parser.NodeWordDef
}

func New(stackSize int) *Env {
	return &Env{
		Stack:   NewStack(stackSize),
		Return:  NewStack(stackSize),
		Stdin:   os.Stdin,
		Stdout:  os.Stdout,
		Stderr:  os.Stderr,
		Builtin: Builtin,
		Vars:    make(map[string]Value),
		Words:   make(map[string]*parser.NodeWordDef),
	}
}

func (ev *Evaluator) Visit(node parser.Node) parser.Visitor {
	switch n := node.(type) {
	case *parser.NodeWordDef:
		ev.env.Words[n.Identifier] = n
	case parser.NodeWord:
		if word, ok := ev.env.Words[n.Identifier]; ok {
			for _, c := range word.Body {
				parser.Walk(ev, c)
			}
			return ev
		}
		if word, ok := ev.env.Builtin[n.Identifier]; ok {
			word(ev.env)
		}
	case parser.NodeStringLit:
		ev.env.Stack.PushString(n.Value)
	case parser.NodeNumLit:
		ev.env.Stack.PushNum(n.Value)
	case parser.NodeVarDef:
		ref := parser.NodeRef(n.Identifier)
		ev.env.Words[n.Identifier] = &parser.NodeWordDef{
			Identifier: n.Identifier,
			Body:       []parser.Node{ref},
		}
		ev.env.Stack.Push(RefValue{ValueRef, n.Identifier})
	case parser.NodeRef:
		ev.env.Stack.Push(RefValue{ValueRef, string(n)})
	case *parser.NodeIf:
		cond := ev.env.Stack.Pop()
		if cond.Value() == true || cond.Value() == 1 {
			for _, c := range n.Body {
				parser.Walk(ev, c)
			}
			return ev
		}
		for _, c := range n.Else.Body {
			parser.Walk(ev, c)
		}
	case *parser.NodeFor:
		ev.env.Stack.Swap()
		ev.env.Return.Push(ev.env.Stack.Pop())
		ev.env.Return.Push(ev.env.Stack.Pop())
		for {
			index := ev.env.Return.Pop()
			limit := ev.env.Return.Peek()
			if index.Type() != ValueNum || limit.Type() != ValueNum {
				return ev
			}
			if index.Value().(float64) < limit.Value().(float64) || limit.Value().(float64) == 0 {
				ev.env.Return.Push(index)
				for _, c := range n.Body {
					parser.Walk(ev, c)
				}
				ev.env.Return.Drop()
				ev.env.Return.PushNum(index.Value().(float64) + 1)
				continue
			}
			break
		}
	case *parser.NodeCollection:
		collection := newCollection(n.Type)
		for _, node := range n.Body {
			collection.Insert(ev.evalNode(node))
		}
		ev.env.Stack.Push(collection)
	}
	return ev
}

func newCollection(n parser.CollectionType) Collection {
	if n == parser.VectorCollection {
		return &VectorValue{ValueType: ValueVector}
	}
	if n == parser.ListCollection {
		return &ListValue{ValueType: ValueList}
	}
	return nil
}

func (ev *Evaluator) evalNode(node parser.Node) Value {
	switch n := node.(type) {
	case parser.NodeNumLit:
		return NumValue{ValueNum, n.Value}
	case parser.NodeStringLit:
		return StringValue{ValueString, n.Value}
	case *parser.NodeCollection:
		collection := newCollection(n.Type)
		for _, c := range n.Body {
			collection.Insert(ev.evalNode(c))
		}
		return collection
	case parser.NodeWord:
		if n.Identifier == "true" {
			return BoolValue{ValueBool, true}
		}
		if n.Identifier == "false" {
			return BoolValue{ValueBool, false}
		}
	case parser.NodeRef:
		// TODO
	}
	return nil
}

func Eval(env *Env, ast []parser.Node) {
	eval := &Evaluator{
		env: env,
	}
	for _, node := range ast {
		parser.Walk(eval, node)
	}
}

type Evaluator struct {
	env *Env
}
<commit_msg>Recover stack underflow panics<commit_after>package runtime

import (
	"fmt"
	"io"
	"os"

	"github.com/bruston/roost/parser"
)

type Value interface {
	Type() ValueType
	Value() interface{}
}

type Stack struct {
	data []Value
	top  int
}

func (s *Stack) Push(v Value) {
	s.top++
	s.data[s.top] = v
}

func (s *Stack) Pop() Value {
	v := s.data[s.top]
	s.data[s.top] = nil
	s.top--
	return v
}

func (s *Stack) Peek() Value { return s.data[s.top] }

func (s *Stack) Dup() { s.Push(s.data[s.top]) }

func (s *Stack) Drop() { s.Pop() }

func (s *Stack) Swap() {
	s.data[s.top], s.data[s.top-1] = s.data[s.top-1], s.data[s.top]
}

func (s *Stack) PushBool(b bool) { s.Push(BoolValue{ValueBool, b}) }

func (s *Stack) PushNum(n float64) { s.Push(NumValue{ValueNum, n}) }

func (s *Stack) PushString(str string) { s.Push(StringValue{ValueString, str}) }

func (s *Stack) PushBlob(b []byte) { s.Push(&BlobValue{ValueBlob, b}) }

func NewStack(size int) *Stack { return &Stack{data: make([]Value, size), top: -1} }

type Env struct {
	Stack   *Stack
	Return  *Stack
	Stdin   io.Reader
	Stdout  io.Writer
	Stderr  io.Writer
	Builtin map[string]FuncValue
	Vars    map[string]Value
	Words   map[string]*parser.NodeWordDef
}

func New(stackSize int) *Env {
	return &Env{
		Stack:   NewStack(stackSize),
		Return:  NewStack(stackSize),
		Stdin:   os.Stdin,
		Stdout:  os.Stdout,
		Stderr:  os.Stderr,
		Builtin: Builtin,
		Vars:    make(map[string]Value),
		Words:   make(map[string]*parser.NodeWordDef),
	}
}

func (ev *Evaluator) Visit(node parser.Node) parser.Visitor {
	defer func() {
		if r := recover(); r != nil {
			fmt.Fprintln(ev.env.Stderr, "%s", r)
		}
	}()
	switch n := node.(type) {
	case *parser.NodeWordDef:
		ev.env.Words[n.Identifier] = n
	case parser.NodeWord:
		if word, ok := ev.env.Words[n.Identifier]; ok {
			for _, c := range word.Body {
				parser.Walk(ev, c)
			}
			return ev
		}
		if word, ok := ev.env.Builtin[n.Identifier]; ok {
			word(ev.env)
		}
	case parser.NodeStringLit:
		ev.env.Stack.PushString(n.Value)
	case parser.NodeNumLit:
		ev.env.Stack.PushNum(n.Value)
	case parser.NodeVarDef:
		ref := parser.NodeRef(n.Identifier)
		ev.env.Words[n.Identifier] = &parser.NodeWordDef{
			Identifier: n.Identifier,
			Body:       []parser.Node{ref},
		}
		ev.env.Stack.Push(RefValue{ValueRef, n.Identifier})
	case parser.NodeRef:
		ev.env.Stack.Push(RefValue{ValueRef, string(n)})
	case *parser.NodeIf:
		cond := ev.env.Stack.Pop()
		if cond.Value() == true || cond.Value() == 1 {
			for _, c := range n.Body {
				parser.Walk(ev, c)
			}
			return ev
		}
		for _, c := range n.Else.Body {
			parser.Walk(ev, c)
		}
	case *parser.NodeFor:
		ev.env.Stack.Swap()
		ev.env.Return.Push(ev.env.Stack.Pop())
		ev.env.Return.Push(ev.env.Stack.Pop())
		for {
			index := ev.env.Return.Pop()
			limit := ev.env.Return.Peek()
			if index.Type() != ValueNum || limit.Type() != ValueNum {
				return ev
			}
			if index.Value().(float64) < limit.Value().(float64) || limit.Value().(float64) == 0 {
				ev.env.Return.Push(index)
				for _, c := range n.Body {
					parser.Walk(ev, c)
				}
				ev.env.Return.Drop()
				ev.env.Return.PushNum(index.Value().(float64) + 1)
				continue
			}
			break
		}
	case *parser.NodeCollection:
		collection := newCollection(n.Type)
		for _, node := range n.Body {
			collection.Insert(ev.evalNode(node))
		}
		ev.env.Stack.Push(collection)
	}
	return ev
}

func newCollection(n parser.CollectionType) Collection {
	if n == parser.VectorCollection {
		return &VectorValue{ValueType: ValueVector}
	}
	if n == parser.ListCollection {
		return &ListValue{ValueType: ValueList}
	}
	return nil
}

func (ev *Evaluator) evalNode(node parser.Node) Value {
	switch n := node.(type) {
	case parser.NodeNumLit:
		return NumValue{ValueNum, n.Value}
	case parser.NodeStringLit:
		return StringValue{ValueString, n.Value}
	case *parser.NodeCollection:
		collection := newCollection(n.Type)
		for _, c := range n.Body {
			collection.Insert(ev.evalNode(c))
		}
		return collection
	case parser.NodeWord:
		if n.Identifier == "true" {
			return BoolValue{ValueBool, true}
		}
		if n.Identifier == "false" {
			return BoolValue{ValueBool, false}
		}
	case parser.NodeRef:
		// TODO
	}
	return nil
}

func Eval(env *Env, ast []parser.Node) {
	eval := &Evaluator{
		env: env,
	}
	for _, node := range ast {
		parser.Walk(eval, node)
	}
}

type Evaluator struct {
	env *Env
}
<|endoftext|>


<commit_before>package smarty_sdk

import (
	"testing"
	"net/http"
	"github.com/smartystreets/assertions"
	"github.com/smartystreets/assertions/should"
)

func TestHTTPStatusError(t *testing.T) {
	err := NewHTTPStatusError(http.StatusTeapot, []byte("Hello, World!"))

	assert := assertions.New(t)
	assert.So(err.Error(), should.Equal, http.StatusText(http.StatusTeapot))
	assert.So(err.StatusCode(), should.Equal, http.StatusTeapot)
	assert.So(err.Content(), should.Resemble, []byte("Hello, World!"))
}

func TestNilHTTPStatusErrorBehavesLikeHTTP200(t *testing.T) {
	var err *HTTPStatusError

	assert := assertions.New(t)
	assert.So(err, should.BeNil)
	assert.So(err.Error(), should.Equal, http.StatusText(http.StatusOK))
	assert.So(err.StatusCode(), should.Equal, http.StatusOK)
	assert.So(err.Content(), should.BeNil)
}
<commit_msg>Marked tests as parallel.<commit_after>package smarty_sdk

import (
	"testing"
	"net/http"
	"github.com/smartystreets/assertions"
	"github.com/smartystreets/assertions/should"
)

func TestHTTPStatusError(t *testing.T) {
	t.Parallel()

	err := NewHTTPStatusError(http.StatusTeapot, []byte("Hello, World!"))

	assert := assertions.New(t)
	assert.So(err.Error(), should.Equal, http.StatusText(http.StatusTeapot))
	assert.So(err.StatusCode(), should.Equal, http.StatusTeapot)
	assert.So(err.Content(), should.Resemble, []byte("Hello, World!"))
}

func TestNilHTTPStatusErrorBehavesLikeHTTP200(t *testing.T) {
	t.Parallel()

	var err *HTTPStatusError

	assert := assertions.New(t)
	assert.So(err, should.BeNil)
	assert.So(err.Error(), should.Equal, http.StatusText(http.StatusOK))
	assert.So(err.StatusCode(), should.Equal, http.StatusOK)
	assert.So(err.Content(), should.BeNil)
}
<|endoftext|>


<commit_before>package log

import (
	"container/list"
	"fmt"
	"io"
	"runtime"
	"strings"
	"sync"
	"time"
)

type Worker struct {
	Prefix  string
	Level   LogLevel
	Writers []LogWriter
}

type LogHandler struct {
	Message string
	Worker  *Worker
}

type LogMsg struct {
	Message string
	Out     LogWriter
}

type LogMaster struct {
	workers *list.List
}

var (
	logMaster  = &LogMaster{}
	msgChannel chan LogMsg
)

func init() {
	logMaster.workers = list.New()
	// root logger
	Register("/", DEBUG, NewConsoleAppender(false))
	// buffered channels are asynchronous
	msgChannel = make(chan LogMsg, 100)
	go log()
}

/*
func SetLogMaster(master LogMaster) {
	if logMaster != nil {
		logMaster.Close()
	}
	logMaster = master
}
*/

// normalize namespace
func normalizeNamespace(namespace string) string {
	if !strings.HasPrefix(namespace, "/") {
		namespace = "/" + namespace
	}
	if !strings.HasSuffix(namespace, "/") {
		namespace += "/"
	}
	return namespace
}

func Register(namespace string, level LogLevel, writers ...LogWriter) {
	namespace = normalizeNamespace(namespace)

	// if there is no supplied writers use the ones from the parent
	worker := &Worker{Prefix: namespace, Level: level, Writers: writers}
	if writers == nil {
		wrk := logMaster.fetchWorker(namespace)
		worker.Writers = wrk.Writers
	}

	// Iterate through list of workers
	var processed bool
	for e := logMaster.workers.Front(); e != nil; e = e.Next() {
		wrk := e.Value.(*Worker)
		if namespace == wrk.Prefix {
			// replace
			e.Value = worker
			processed = true
		} else if namespace > wrk.Prefix {
			logMaster.workers.InsertBefore(worker, e)
			processed = true
			break
		}
	}

	// namespaces are positioned in descending order
	if !processed {
		logMaster.workers.PushBack(worker)
	}
}

func LoggerFor(namespace string) *Logger {
	logger := new(Logger)
	logger.tag = namespace
	return logger
}

func (this *LogMaster) fetchWorker(tag string) *Worker {
	namespace := normalizeNamespace(tag)
	for e := this.workers.Front(); e != nil; e = e.Next() {
		wrk := e.Value.(*Worker)
		if strings.HasPrefix(namespace, wrk.Prefix) {
			return wrk
		}
	}
	panic(fmt.Sprintf("No Worker was found for %s", namespace))
}

func shutdown() {
	// signal shutdown to the go routine
	close(msgChannel)
}

func log() {
	for {
		msg, ok := <-msgChannel
		if !ok {
			// EXIT
			return
		}

		msg.Out.Write([]byte(msg.Message))
	}
}

type LogLevel int

func (this LogLevel) String() string {
	switch this {
	case DEBUG:
		return "DEBUG"
	case INFO:
		return "INFO"
	case WARN:
		return "WARN"
	case ERROR:
		return "ERROR"
	case FATAL:
		return "FATAL"
	}
	return ""
}

const (
	DEBUG LogLevel = iota
	INFO
	WARN
	ERROR
	FATAL
	NONE
)

type Logger struct {
	sync.Mutex

	tag       string
	worker    *Worker
	calldepth int
}

func (this *Logger) loadWorker() {
	this.Lock()
	defer this.Unlock()

	if this.worker == nil {
		this.worker = logMaster.fetchWorker(this.tag)
	}
}

func (this *Logger) Level() LogLevel {
	if this.worker == nil {
		this.loadWorker()
	}
	return this.worker.Level
}

func (this *Logger) Namespace() string {
	return this.tag
}

func (this *Logger) CallDepth(depth int) {
	this.calldepth = depth
}

func (this *Logger) logStamp(level LogLevel) string {
	t := time.Now()
	var fl string
	if this.calldepth > 0 {
		_, file, line, ok := runtime.Caller(this.calldepth + 2)
		if ok {
			short := file
			for i := len(file) - 1; i > 0; i-- {
				if file[i] == '/' {
					short = file[i+1:]
					break
				}
			}
			file = short
		} else {
			file = "<Undetermined Caller>"
			line = 0
		}
		fl = fmt.Sprintf(" %s:%d", file, line)
	}
	return fmt.Sprintf("%d/%02d/%02d-%02d:%02d:%02d %s%s: ",
		t.Year(),
		t.Month(),
		t.Day(),
		t.Hour(),
		t.Minute(),
		t.Second(),
		level,
		fl)
}

func (this *Logger) IsActive(level LogLevel) bool {
	return level >= this.Level()
}

func (this *Logger) logf(level LogLevel, format string, what ...interface{}) {
	if this.IsActive(level) {
		str := this.logStamp(level)
		if len(what) > 0 {
			str += fmt.Sprintf(format+"\n", what...)
		} else {
			str += format + "\n"
		}
		//fmt.Printf("=====> %s", str)
		flush(str, this.worker.Writers)
	}
}

func (this *Logger) logF(level LogLevel, handler func() string) {
	if this.IsActive(level) {
		str := this.logStamp(level) + handler() + "\n"
		flush(str, this.worker.Writers)
	}
}

type LogWriter interface {
	io.Writer
	IsAsync() bool
}

func flush(msg string, workers []LogWriter) {
	for _, v := range workers {
		if v.IsAsync() {
			msgChannel <- LogMsg{msg, v}
		} else {
			v.Write([]byte(msg))
		}
	}
}

func (this *Logger) Debugf(format string, what ...interface{}) {
	this.logf(DEBUG, format, what...)
}

func (this *Logger) DebugF(handler func() string) {
	this.logF(DEBUG, handler)
}

func (this *Logger) Infof(format string, what ...interface{}) {
	this.logf(INFO, format, what...)
}

func (this *Logger) InfoF(handler func() string) {
	this.logF(INFO, handler)
}

func (this *Logger) Warnf(format string, what ...interface{}) {
	this.logf(WARN, format, what...)
}

func (this *Logger) WarnF(handler func() string) {
	this.logF(WARN, handler)
}

func (this *Logger) Errorf(format string, what ...interface{}) {
	this.logf(ERROR, format, what...)
}

func (this *Logger) ErrorF(handler func() string) {
	this.logF(ERROR, handler)
}

func (this *Logger) Fatalf(format string, what ...interface{}) {
	this.logf(FATAL, format, what...)
}

func (this *Logger) FatalF(handler func() string) {
	this.logF(FATAL, handler)
}
<commit_msg>remove println<commit_after>package log

import (
	"container/list"
	"fmt"
	"io"
	"runtime"
	"strings"
	"sync"
	"time"
)

type Worker struct {
	Prefix  string
	Level   LogLevel
	Writers []LogWriter
}

type LogHandler struct {
	Message string
	Worker  *Worker
}

type LogMsg struct {
	Message string
	Out     LogWriter
}

type LogMaster struct {
	workers *list.List
}

var (
	logMaster  = &LogMaster{}
	msgChannel chan LogMsg
)

func init() {
	logMaster.workers = list.New()
	// root logger
	Register("/", DEBUG, NewConsoleAppender(false))
	// buffered channels are asynchronous
	msgChannel = make(chan LogMsg, 100)
	go log()
}

/*
func SetLogMaster(master LogMaster) {
	if logMaster != nil {
		logMaster.Close()
	}
	logMaster = master
}
*/

// normalize namespace
func normalizeNamespace(namespace string) string {
	if !strings.HasPrefix(namespace, "/") {
		namespace = "/" + namespace
	}
	if !strings.HasSuffix(namespace, "/") {
		namespace += "/"
	}
	return namespace
}

func Register(namespace string, level LogLevel, writers ...LogWriter) {
	namespace = normalizeNamespace(namespace)

	// if there is no supplied writers use the ones from the parent
	worker := &Worker{Prefix: namespace, Level: level, Writers: writers}
	if writers == nil {
		wrk := logMaster.fetchWorker(namespace)
		worker.Writers = wrk.Writers
	}

	// Iterate through list of workers
	var processed bool
	for e := logMaster.workers.Front(); e != nil; e = e.Next() {
		wrk := e.Value.(*Worker)
		if namespace == wrk.Prefix {
			// replace
			e.Value = worker
			processed = true
		} else if namespace > wrk.Prefix {
			logMaster.workers.InsertBefore(worker, e)
			processed = true
			break
		}
	}

	// namespaces are positioned in descending order
	if !processed {
		logMaster.workers.PushBack(worker)
	}
}

func LoggerFor(namespace string) *Logger {
	logger := new(Logger)
	logger.tag = namespace
	return logger
}

func (this *LogMaster) fetchWorker(tag string) *Worker {
	namespace := normalizeNamespace(tag)
	for e := this.workers.Front(); e != nil; e = e.Next() {
		wrk := e.Value.(*Worker)
		if strings.HasPrefix(namespace, wrk.Prefix) {
			return wrk
		}
	}
	panic(fmt.Sprintf("No Worker was found for %s", namespace))
}

func shutdown() {
	// signal shutdown to the go routine
	close(msgChannel)
}

func log() {
	for {
		msg, ok := <-msgChannel
		if !ok {
			// EXIT
			return
		}

		msg.Out.Write([]byte(msg.Message))
	}
}

type LogLevel int

func (this LogLevel) String() string {
	switch this {
	case DEBUG:
		return "DEBUG"
	case INFO:
		return "INFO"
	case WARN:
		return "WARN"
	case ERROR:
		return "ERROR"
	case FATAL:
		return "FATAL"
	}
	return ""
}

const (
	DEBUG LogLevel = iota
	INFO
	WARN
	ERROR
	FATAL
	NONE
)

type Logger struct {
	sync.Mutex

	tag       string
	worker    *Worker
	calldepth int
}

func (this *Logger) loadWorker() {
	this.Lock()
	defer this.Unlock()

	if this.worker == nil {
		this.worker = logMaster.fetchWorker(this.tag)
	}
}

func (this *Logger) Level() LogLevel {
	if this.worker == nil {
		this.loadWorker()
	}
	return this.worker.Level
}

func (this *Logger) Namespace() string {
	return this.tag
}

func (this *Logger) CallDepth(depth int) {
	this.calldepth = depth
}

func (this *Logger) logStamp(level LogLevel) string {
	t := time.Now()
	var fl string
	if this.calldepth > 0 {
		_, file, line, ok := runtime.Caller(this.calldepth + 2)
		if ok {
			short := file
			for i := len(file) - 1; i > 0; i-- {
				if file[i] == '/' {
					short = file[i+1:]
					break
				}
			}
			file = short
		} else {
			file = "<Undetermined Caller>"
			line = 0
		}
		fl = fmt.Sprintf(" %s:%d", file, line)
	}
	return fmt.Sprintf("%d/%02d/%02d-%02d:%02d:%02d %s%s: ",
		t.Year(),
		t.Month(),
		t.Day(),
		t.Hour(),
		t.Minute(),
		t.Second(),
		level,
		fl)
}

func (this *Logger) IsActive(level LogLevel) bool {
	return level >= this.Level()
}

func (this *Logger) logf(level LogLevel, format string, what ...interface{}) {
	if this.IsActive(level) {
		str := this.logStamp(level)
		if len(what) > 0 {
			str += fmt.Sprintf(format+"\n", what...)
		} else {
			str += format + "\n"
		}
		flush(str, this.worker.Writers)
	}
}

func (this *Logger) logF(level LogLevel, handler func() string) {
	if this.IsActive(level) {
		str := this.logStamp(level) + handler() + "\n"
		flush(str, this.worker.Writers)
	}
}

type LogWriter interface {
	io.Writer
	IsAsync() bool
}

func flush(msg string, workers []LogWriter) {
	for _, v := range workers {
		if v.IsAsync() {
			msgChannel <- LogMsg{msg, v}
		} else {
			v.Write([]byte(msg))
		}
	}
}

func (this *Logger) Debugf(format string, what ...interface{}) {
	this.logf(DEBUG, format, what...)
}

func (this *Logger) DebugF(handler func() string) {
	this.logF(DEBUG, handler)
}

func (this *Logger) Infof(format string, what ...interface{}) {
	this.logf(INFO, format, what...)
}

func (this *Logger) InfoF(handler func() string) {
	this.logF(INFO, handler)
}

func (this *Logger) Warnf(format string, what ...interface{}) {
	this.logf(WARN, format, what...)
}

func (this *Logger) WarnF(handler func() string) {
	this.logF(WARN, handler)
}

func (this *Logger) Errorf(format string, what ...interface{}) {
	this.logf(ERROR, format, what...)
}

func (this *Logger) ErrorF(handler func() string) {
	this.logF(ERROR, handler)
}

func (this *Logger) Fatalf(format string, what ...interface{}) {
	this.logf(FATAL, format, what...)
}

func (this *Logger) FatalF(handler func() string) {
	this.logF(FATAL, handler)
}
<|endoftext|>


<commit_before>package httpclient

import (
	"crypto/tls"
	"fmt"
	"io"
	"log"
	"net/http"
	"net/http/httptrace"
	"net/http/httputil"
	"os"
	"strconv"
	"time"
)

// A transport that prints request and response

type LoggingTransport struct {
	t            *http.Transport
	requestBody  bool
	responseBody bool
	timing       bool
}

func (lt *LoggingTransport) RoundTrip(req *http.Request) (resp *http.Response, err error) {
	dreq, _ := httputil.DumpRequest(req, lt.requestBody)
	//fmt.Println("REQUEST:", strconv.Quote(string(dreq)))
	fmt.Println("REQUEST:", string(dreq))

	for _, t := range req.TransferEncoding {
		fmt.Println("Transfer-Encoding:", t)
	}

	fmt.Println("")

	var startTime time.Time
	var elapsed time.Duration

	if lt.timing {
		startTime = time.Now()
	}

	resp, err = lt.t.RoundTrip(req)

	if lt.timing {
		elapsed = time.Since(startTime)
	}

	if err != nil {
		if lt.requestBody {
			// don't print the body twice
			dreq, _ = httputil.DumpRequest(req, false)
		}
		fmt.Println("ERROR:", err, "REQUEST:", strconv.Quote(string(dreq)))
	}
	if resp != nil {
		dresp, _ := httputil.DumpResponse(resp, lt.responseBody)
		fmt.Println("RESPONSE:", string(dresp))

		for _, t := range resp.Request.TransferEncoding {
			fmt.Println("RQ Transfer-Encoding:", t)
		}
	}

	if elapsed > 0 {
		fmt.Println("ELAPSED TIME:", elapsed.Round(time.Millisecond))
	}

	fmt.Println("")
	return
}

func (lt *LoggingTransport) CancelRequest(req *http.Request) {
	dreq, _ := httputil.DumpRequest(req, false)
	fmt.Println("CANCEL REQUEST:", strconv.Quote(string(dreq)))
	lt.t.CancelRequest(req)
}

// Enable logging requests/response headers
//
// if requestBody == true, also log request body
// if responseBody == true, also log response body
// if timing == true, also log elapsed time
func StartLogging(requestBody, responseBody, timing bool) {
	http.DefaultTransport = &LoggingTransport{&http.Transport{}, requestBody, responseBody, timing}
}

// Disable logging requests/responses
func StopLogging() {
	http.DefaultTransport = &http.Transport{}
}

// Wrap input transport into a LoggingTransport
func LoggedTransport(t *http.Transport, requestBody, responseBody, timing bool) http.RoundTripper {
	return &LoggingTransport{t, requestBody, responseBody, timing}
}

// A Reader that "logs" progress

type ProgressReader struct {
	r         io.Reader
	c         [1]byte
	threshold int
	curr      int
}

func NewProgressReader(r io.Reader, c byte, threshold int) *ProgressReader {
	if c == 0 {
		c = '.'
	}
	if threshold <= 0 {
		threshold = 10240
	}
	p := &ProgressReader{r: r, c: [1]byte{c}, threshold: threshold, curr: 0}
	return p
}

func (p *ProgressReader) Read(b []byte) (int, error) {
	n, err := p.r.Read(b)

	p.curr += n

	if err == io.EOF {
		os.Stdout.Write([]byte{'\n'})
		os.Stdout.Sync()
	} else if p.curr >= p.threshold {
		p.curr -= p.threshold

		os.Stdout.Write(p.c[:])
		os.Stdout.Sync()
	}

	return n, err
}

func (p *ProgressReader) Close() error {
	if rc, ok := p.r.(io.ReadCloser); ok {
		return rc.Close()
	} else {
		return nil
	}
}

// A Logger that can be disabled

type DebugLog bool

func (d DebugLog) Println(args ...interface{}) {
	if d {
		log.Println(args...)
	}
}

func (d DebugLog) Printf(fmt string, args ...interface{}) {
	if d {
		log.Printf(fmt, args...)
	}
}

// A ClientTrace implementation that collects request time

type RequestTrace struct {
	DNS          time.Duration
	Connect      time.Duration
	Connected    bool
	TLSHandshake time.Duration
	Request      time.Duration
	Wait         time.Duration
	Response     time.Duration

	startTime time.Time
}

func (r *RequestTrace) Reset() {
	r.DNS = 0
	r.Connect = 0
	r.Connected = false
	r.TLSHandshake = 0
	r.Request = 0
	r.Wait = 0
	r.Response = 0
}

func (r *RequestTrace) NewClientTrace(trace bool) *httptrace.ClientTrace {
	return &httptrace.ClientTrace{
		GotConn: func(info httptrace.GotConnInfo) {
			r.Connected = info.WasIdle

			if trace {
				log.Println("GotConn", info.Conn.RemoteAddr(), "reused:", info.Reused, "wasIdle:", info.WasIdle)
			}
		},

		ConnectStart: func(network, addr string) {
			r.startTime = time.Now()

			if trace {
				log.Println("ConnectStart", network, addr)
			}
		},

		ConnectDone: func(network, addr string, err error) {
			r.Connect = time.Since(r.startTime)
			r.startTime = time.Time{}

			if trace {
				log.Println("ConnectDone", network, addr, err, r.Connect)
			}
		},

		DNSStart: func(info httptrace.DNSStartInfo) {
			r.startTime = time.Now()

			if trace {
				log.Println("DNSStart", info.Host)
			}
		},

		DNSDone: func(info httptrace.DNSDoneInfo) {
			r.DNS = time.Since(r.startTime)
			r.startTime = time.Time{}

			if trace {
				log.Println("DNSDone", info.Addrs, r.DNS)
			}
		},

		TLSHandshakeStart: func() {
			r.startTime = time.Now()

			if trace {
				log.Println("TLSHandshakeStart")
			}
		},

		TLSHandshakeDone: func(state tls.ConnectionState, err error) {
			r.TLSHandshake = time.Since(r.startTime)
			r.startTime = time.Time{}

			if trace {
				log.Println("TLSHandshakeDone", err, r.TLSHandshake)
			}
		},

		WroteHeaderField: func(string, []string) {
			if r.startTime.IsZero() {
				r.startTime = time.Now()

				if trace {
					log.Println("WroteHeader")
				}
			}
		},

		WroteRequest: func(info httptrace.WroteRequestInfo) {
			r.Request = time.Since(r.startTime)
			r.startTime = time.Now()

			if trace {
				log.Println("WroteRequest", r.Request)
			}
		},

		GotFirstResponseByte: func() {
			r.Wait = time.Since(r.startTime)
			r.startTime = time.Now()

			if trace {
				log.Println("GotFirstResponseByte", r.Wait)
			}
		},
	}
}

// Call this after the response has been received to set the Response duration
// (there is no callback for this)

func (r *RequestTrace) Done() {
	r.Response = time.Since(r.startTime)
	r.startTime = time.Now()
}
<commit_msg>Added RequestTrace.String() to quickly print tracing info.<commit_after>package httpclient

import (
	"crypto/tls"
	"fmt"
	"io"
	"log"
	"net/http"
	"net/http/httptrace"
	"net/http/httputil"
	"os"
	"strconv"
	"time"
)

// A transport that prints request and response

type LoggingTransport struct {
	t            *http.Transport
	requestBody  bool
	responseBody bool
	timing       bool
}

func (lt *LoggingTransport) RoundTrip(req *http.Request) (resp *http.Response, err error) {
	dreq, _ := httputil.DumpRequest(req, lt.requestBody)
	//fmt.Println("REQUEST:", strconv.Quote(string(dreq)))
	fmt.Println("REQUEST:", string(dreq))

	for _, t := range req.TransferEncoding {
		fmt.Println("Transfer-Encoding:", t)
	}

	fmt.Println("")

	var startTime time.Time
	var elapsed time.Duration

	if lt.timing {
		startTime = time.Now()
	}

	resp, err = lt.t.RoundTrip(req)

	if lt.timing {
		elapsed = time.Since(startTime)
	}

	if err != nil {
		if lt.requestBody {
			// don't print the body twice
			dreq, _ = httputil.DumpRequest(req, false)
		}
		fmt.Println("ERROR:", err, "REQUEST:", strconv.Quote(string(dreq)))
	}
	if resp != nil {
		dresp, _ := httputil.DumpResponse(resp, lt.responseBody)
		fmt.Println("RESPONSE:", string(dresp))

		for _, t := range resp.Request.TransferEncoding {
			fmt.Println("RQ Transfer-Encoding:", t)
		}
	}

	if elapsed > 0 {
		fmt.Println("ELAPSED TIME:", elapsed.Round(time.Millisecond))
	}

	fmt.Println("")
	return
}

func (lt *LoggingTransport) CancelRequest(req *http.Request) {
	dreq, _ := httputil.DumpRequest(req, false)
	fmt.Println("CANCEL REQUEST:", strconv.Quote(string(dreq)))
	lt.t.CancelRequest(req)
}

// Enable logging requests/response headers
//
// if requestBody == true, also log request body
// if responseBody == true, also log response body
// if timing == true, also log elapsed time
func StartLogging(requestBody, responseBody, timing bool) {
	http.DefaultTransport = &LoggingTransport{&http.Transport{}, requestBody, responseBody, timing}
}

// Disable logging requests/responses
func StopLogging() {
	http.DefaultTransport = &http.Transport{}
}

// Wrap input transport into a LoggingTransport
func LoggedTransport(t *http.Transport, requestBody, responseBody, timing bool) http.RoundTripper {
	return &LoggingTransport{t, requestBody, responseBody, timing}
}

// A Reader that "logs" progress

type ProgressReader struct {
	r         io.Reader
	c         [1]byte
	threshold int
	curr      int
}

func NewProgressReader(r io.Reader, c byte, threshold int) *ProgressReader {
	if c == 0 {
		c = '.'
	}
	if threshold <= 0 {
		threshold = 10240
	}
	p := &ProgressReader{r: r, c: [1]byte{c}, threshold: threshold, curr: 0}
	return p
}

func (p *ProgressReader) Read(b []byte) (int, error) {
	n, err := p.r.Read(b)

	p.curr += n

	if err == io.EOF {
		os.Stdout.Write([]byte{'\n'})
		os.Stdout.Sync()
	} else if p.curr >= p.threshold {
		p.curr -= p.threshold

		os.Stdout.Write(p.c[:])
		os.Stdout.Sync()
	}

	return n, err
}

func (p *ProgressReader) Close() error {
	if rc, ok := p.r.(io.ReadCloser); ok {
		return rc.Close()
	} else {
		return nil
	}
}

// A Logger that can be disabled

type DebugLog bool

func (d DebugLog) Println(args ...interface{}) {
	if d {
		log.Println(args...)
	}
}

func (d DebugLog) Printf(fmt string, args ...interface{}) {
	if d {
		log.Printf(fmt, args...)
	}
}

// A ClientTrace implementation that collects request time

type RequestTrace struct {
	DNS          time.Duration
	Connect      time.Duration
	Connected    bool
	TLSHandshake time.Duration
	Request      time.Duration
	Wait         time.Duration
	Response     time.Duration

	startTime time.Time
}

func (r *RequestTrace) Reset() {
	r.DNS = 0
	r.Connect = 0
	r.Connected = false
	r.TLSHandshake = 0
	r.Request = 0
	r.Wait = 0
	r.Response = 0
}

func (r *RequestTrace) NewClientTrace(trace bool) *httptrace.ClientTrace {
	return &httptrace.ClientTrace{
		GotConn: func(info httptrace.GotConnInfo) {
			r.Connected = info.WasIdle

			if trace {
				log.Println("GotConn", info.Conn.RemoteAddr(), "reused:", info.Reused, "wasIdle:", info.WasIdle)
			}
		},

		ConnectStart: func(network, addr string) {
			r.startTime = time.Now()

			if trace {
				log.Println("ConnectStart", network, addr)
			}
		},

		ConnectDone: func(network, addr string, err error) {
			r.Connect = time.Since(r.startTime)
			r.startTime = time.Time{}

			if trace {
				log.Println("ConnectDone", network, addr, err, r.Connect)
			}
		},

		DNSStart: func(info httptrace.DNSStartInfo) {
			r.startTime = time.Now()

			if trace {
				log.Println("DNSStart", info.Host)
			}
		},

		DNSDone: func(info httptrace.DNSDoneInfo) {
			r.DNS = time.Since(r.startTime)
			r.startTime = time.Time{}

			if trace {
				log.Println("DNSDone", info.Addrs, r.DNS)
			}
		},

		TLSHandshakeStart: func() {
			r.startTime = time.Now()

			if trace {
				log.Println("TLSHandshakeStart")
			}
		},

		TLSHandshakeDone: func(state tls.ConnectionState, err error) {
			r.TLSHandshake = time.Since(r.startTime)
			r.startTime = time.Time{}

			if trace {
				log.Println("TLSHandshakeDone", err, r.TLSHandshake)
			}
		},

		WroteHeaderField: func(string, []string) {
			if r.startTime.IsZero() {
				r.startTime = time.Now()

				if trace {
					log.Println("WroteHeader")
				}
			}
		},

		WroteRequest: func(info httptrace.WroteRequestInfo) {
			r.Request = time.Since(r.startTime)
			r.startTime = time.Now()

			if trace {
				log.Println("WroteRequest", r.Request)
			}
		},

		GotFirstResponseByte: func() {
			r.Wait = time.Since(r.startTime)
			r.startTime = time.Now()

			if trace {
				log.Println("GotFirstResponseByte", r.Wait)
			}
		},
	}
}

// Call this after the response has been received to set the Response duration
// (there is no callback for this)

func (r *RequestTrace) Done() {
	r.Response = time.Since(r.startTime)
	r.startTime = time.Now()
}

func (r *RequestTrace) String() string {
	return fmt.Sprintf("{DNS:%v, Connect:%v, Connected:%v, TLSHandshake:%v, Request:%v, Wait:%v, Response:%v}",
		r.DNS, r.Connect, r.Connected, r.TLSHandshake, r.Request, r.Wait, r.Response)
}
<|endoftext|>


<commit_before>package bongo

import (
	"os"

	"github.com/gernest/bongo-contrib/loaders"
	"github.com/gernest/bongo-contrib/matters"
	"github.com/gernest/bongo-contrib/models"
	"github.com/gernest/bongo-contrib/renderers"
)

type defaultApp struct {
	loaders.DefaultLoader
	*matters.Matter
	renderers.DefaultRenderer
}

func newDefaultApp() *defaultApp {
	app := &defaultApp{}
	app.Matter = matters.NewYAML()
	return app
}

//App is the main bongo application
type App struct {
	gene models.Generator
}

//New creates a new App which uses default models.Generator implementation
func New() *App {
	return NewApp(newDefaultApp())
}

//NewApp creates a new app, that uses g as the generator
func NewApp(g models.Generator) *App {
	return &App{gene: g}
}

// Run runs the app
func (g *App) Run(root string) error {
	files, err := g.gene.Load(root)
	if err != nil {
		return err
	}
	var pages models.PageList
	send := make(chan *models.Page)
	errs := make(chan error)
	for _, f := range files {
		go func(file string) {
			f, err := os.Open(file)
			if err != nil {
				errs <- err
				return
			}
			defer f.Close()
			front, body, err := g.gene.Parse(f)
			if err != nil {
				errs <- err
				return
			}
			stat, err := f.Stat()
			if err != nil {
				errs <- err
				return
			}
			send <- &models.Page{Path: file, Body: body, Data: front, ModTime: stat.ModTime()}
		}(f)
	}
	n := 0
	var fish error
END:
	for {
		select {
		case pg := <-send:
			pages = append(pages, pg)
			n++
		case perr := <-errs:
			fish = perr
			break END

		default:
			if len(files) <= n {
				break END
			}
		}

	}
	if fish != nil {
		return fish
	}
	err = g.gene.Render(root, pages)
	if err != nil {
		renderers.Rollback(root) // roll back before exiting
		return err
	}
	return nil

}
<commit_msg>fixed imports<commit_after>package bongo

import (
	"os"

	"github.com/bongo-contrib/loaders"
	"github.com/bongo-contrib/matters"
	"github.com/bongo-contrib/models"
	"github.com/bongo-contrib/renderers"
)

type defaultApp struct {
	loaders.DefaultLoader
	*matters.Matter
	renderers.DefaultRenderer
}

func newDefaultApp() *defaultApp {
	app := &defaultApp{}
	app.Matter = matters.NewYAML()
	return app
}

//App is the main bongo application
type App struct {
	gene models.Generator
}

//New creates a new App which uses default models.Generator implementation
func New() *App {
	return NewApp(newDefaultApp())
}

//NewApp creates a new app, that uses g as the generator
func NewApp(g models.Generator) *App {
	return &App{gene: g}
}

// Run runs the app
func (g *App) Run(root string) error {
	files, err := g.gene.Load(root)
	if err != nil {
		return err
	}
	var pages models.PageList
	send := make(chan *models.Page)
	errs := make(chan error)
	for _, f := range files {
		go func(file string) {
			f, err := os.Open(file)
			if err != nil {
				errs <- err
				return
			}
			defer f.Close()
			front, body, err := g.gene.Parse(f)
			if err != nil {
				errs <- err
				return
			}
			stat, err := f.Stat()
			if err != nil {
				errs <- err
				return
			}
			send <- &models.Page{Path: file, Body: body, Data: front, ModTime: stat.ModTime()}
		}(f)
	}
	n := 0
	var fish error
END:
	for {
		select {
		case pg := <-send:
			pages = append(pages, pg)
			n++
		case perr := <-errs:
			fish = perr
			break END

		default:
			if len(files) <= n {
				break END
			}
		}

	}
	if fish != nil {
		return fish
	}
	err = g.gene.Render(root, pages)
	if err != nil {
		renderers.Rollback(root) // roll back before exiting
		return err
	}
	return nil

}
<|endoftext|>


<commit_before>package client

import (
	"errors"

	kapi "k8s.io/kubernetes/pkg/api"
	apierrs "k8s.io/kubernetes/pkg/api/errors"
	"k8s.io/kubernetes/pkg/watch"

	imageapi "github.com/openshift/origin/pkg/image/api"
	quotautil "github.com/openshift/origin/pkg/quota/util"
)

var ErrImageStreamImportUnsupported = errors.New("the server does not support directly importing images - create an image stream with tags or the dockerImageRepository field set")

// ImageStreamsNamespacer has methods to work with ImageStream resources in a namespace
type ImageStreamsNamespacer interface {
	ImageStreams(namespace string) ImageStreamInterface
}

// ImageStreamInterface exposes methods on ImageStream resources.
type ImageStreamInterface interface {
	List(opts kapi.ListOptions) (*imageapi.ImageStreamList, error)
	Get(name string) (*imageapi.ImageStream, error)
	Create(stream *imageapi.ImageStream) (*imageapi.ImageStream, error)
	Update(stream *imageapi.ImageStream) (*imageapi.ImageStream, error)
	Delete(name string) error
	Watch(opts kapi.ListOptions) (watch.Interface, error)
	UpdateStatus(stream *imageapi.ImageStream) (*imageapi.ImageStream, error)
	Import(isi *imageapi.ImageStreamImport) (*imageapi.ImageStreamImport, error)
}

// ImageStreamNamespaceGetter exposes methods to get ImageStreams by Namespace
type ImageStreamNamespaceGetter interface {
	GetByNamespace(namespace, name string) (*imageapi.ImageStream, error)
}

// imageStreams implements ImageStreamsNamespacer interface
type imageStreams struct {
	r  *Client
	ns string
}

// newImageStreams returns an imageStreams
func newImageStreams(c *Client, namespace string) *imageStreams {
	return &imageStreams{
		r:  c,
		ns: namespace,
	}
}

// List returns a list of image streams that match the label and field selectors.
func (c *imageStreams) List(opts kapi.ListOptions) (result *imageapi.ImageStreamList, err error) {
	result = &imageapi.ImageStreamList{}
	err = c.r.Get().
		Namespace(c.ns).
		Resource("imageStreams").
		VersionedParams(&opts, kapi.ParameterCodec).
		Do().
		Into(result)
	return
}

// Get returns information about a particular image stream and error if one occurs.
func (c *imageStreams) Get(name string) (result *imageapi.ImageStream, err error) {
	result = &imageapi.ImageStream{}
	err = c.r.Get().Namespace(c.ns).Resource("imageStreams").Name(name).Do().Into(result)
	return
}

// GetByNamespace returns information about a particular image stream in a particular namespace and error if one occurs.
func (c *imageStreams) GetByNamespace(namespace, name string) (result *imageapi.ImageStream, err error) {
	result = &imageapi.ImageStream{}
	c.r.Get().Namespace(namespace).Resource("imageStreams").Name(name).Do().Into(result)
	return
}

// Create create a new image stream. Returns the server's representation of the image stream and error if one occurs.
func (c *imageStreams) Create(stream *imageapi.ImageStream) (result *imageapi.ImageStream, err error) {
	result = &imageapi.ImageStream{}
	err = c.r.Post().Namespace(c.ns).Resource("imageStreams").Body(stream).Do().Into(result)
	return
}

// Update updates the image stream on the server. Returns the server's representation of the image stream and error if one occurs.
func (c *imageStreams) Update(stream *imageapi.ImageStream) (result *imageapi.ImageStream, err error) {
	result = &imageapi.ImageStream{}
	err = c.r.Put().Namespace(c.ns).Resource("imageStreams").Name(stream.Name).Body(stream).Do().Into(result)
	return
}

// Delete deletes an image stream, returns error if one occurs.
func (c *imageStreams) Delete(name string) (err error) {
	err = c.r.Delete().Namespace(c.ns).Resource("imageStreams").Name(name).Do().Error()
	return
}

// Watch returns a watch.Interface that watches the requested image streams.
func (c *imageStreams) Watch(opts kapi.ListOptions) (watch.Interface, error) {
	return c.r.Get().
		Prefix("watch").
		Namespace(c.ns).
		Resource("imageStreams").
		VersionedParams(&opts, kapi.ParameterCodec).
		Watch()
}

// UpdateStatus updates the image stream's status. Returns the server's representation of the image stream, and an error, if it occurs.
func (c *imageStreams) UpdateStatus(stream *imageapi.ImageStream) (result *imageapi.ImageStream, err error) {
	result = &imageapi.ImageStream{}
	err = c.r.Put().Namespace(c.ns).Resource("imageStreams").Name(stream.Name).SubResource("status").Body(stream).Do().Into(result)
	return
}

// Import makes a call to the server to retrieve information about the requested images or to perform an import. ImageStreamImport
// will be returned if no actual import was requested (the to fields were not set), or an ImageStream if import was requested.
func (c *imageStreams) Import(isi *imageapi.ImageStreamImport) (*imageapi.ImageStreamImport, error) {
	result := &imageapi.ImageStreamImport{}
	if err := c.r.Post().Namespace(c.ns).Resource("imageStreamImports").Body(isi).Do().Into(result); err != nil {
		return nil, transformUnsupported(err)
	}
	return result, nil
}

// transformUnsupported converts specific error conditions to unsupported
func transformUnsupported(err error) error {
	if err == nil {
		return nil
	}
	if apierrs.IsNotFound(err) {
		status, ok := err.(apierrs.APIStatus)
		if !ok {
			return ErrImageStreamImportUnsupported
		}
		if status.Status().Details == nil || status.Status().Details.Kind == "" {
			return ErrImageStreamImportUnsupported
		}
	}
	// The ImageStreamImport resource exists in v1.1.1 of origin but is not yet
	// enabled by policy. A create request will return a Forbidden(403) error.
	// We want to return ErrImageStreamImportUnsupported to allow fallback behavior
	// in clients.
	if apierrs.IsForbidden(err) && !quotautil.IsErrorQuotaExceeded(err) {
		return ErrImageStreamImportUnsupported
	}
	return err
}
<commit_msg>Add a missing err return<commit_after>package client

import (
	"errors"

	kapi "k8s.io/kubernetes/pkg/api"
	apierrs "k8s.io/kubernetes/pkg/api/errors"
	"k8s.io/kubernetes/pkg/watch"

	imageapi "github.com/openshift/origin/pkg/image/api"
	quotautil "github.com/openshift/origin/pkg/quota/util"
)

var ErrImageStreamImportUnsupported = errors.New("the server does not support directly importing images - create an image stream with tags or the dockerImageRepository field set")

// ImageStreamsNamespacer has methods to work with ImageStream resources in a namespace
type ImageStreamsNamespacer interface {
	ImageStreams(namespace string) ImageStreamInterface
}

// ImageStreamInterface exposes methods on ImageStream resources.
type ImageStreamInterface interface {
	List(opts kapi.ListOptions) (*imageapi.ImageStreamList, error)
	Get(name string) (*imageapi.ImageStream, error)
	Create(stream *imageapi.ImageStream) (*imageapi.ImageStream, error)
	Update(stream *imageapi.ImageStream) (*imageapi.ImageStream, error)
	Delete(name string) error
	Watch(opts kapi.ListOptions) (watch.Interface, error)
	UpdateStatus(stream *imageapi.ImageStream) (*imageapi.ImageStream, error)
	Import(isi *imageapi.ImageStreamImport) (*imageapi.ImageStreamImport, error)
}

// ImageStreamNamespaceGetter exposes methods to get ImageStreams by Namespace
type ImageStreamNamespaceGetter interface {
	GetByNamespace(namespace, name string) (*imageapi.ImageStream, error)
}

// imageStreams implements ImageStreamsNamespacer interface
type imageStreams struct {
	r  *Client
	ns string
}

// newImageStreams returns an imageStreams
func newImageStreams(c *Client, namespace string) *imageStreams {
	return &imageStreams{
		r:  c,
		ns: namespace,
	}
}

// List returns a list of image streams that match the label and field selectors.
func (c *imageStreams) List(opts kapi.ListOptions) (result *imageapi.ImageStreamList, err error) {
	result = &imageapi.ImageStreamList{}
	err = c.r.Get().
		Namespace(c.ns).
		Resource("imageStreams").
		VersionedParams(&opts, kapi.ParameterCodec).
		Do().
		Into(result)
	return
}

// Get returns information about a particular image stream and error if one occurs.
func (c *imageStreams) Get(name string) (result *imageapi.ImageStream, err error) {
	result = &imageapi.ImageStream{}
	err = c.r.Get().Namespace(c.ns).Resource("imageStreams").Name(name).Do().Into(result)
	return
}

// Create create a new image stream. Returns the server's representation of the image stream and error if one occurs.
func (c *imageStreams) Create(stream *imageapi.ImageStream) (result *imageapi.ImageStream, err error) {
	result = &imageapi.ImageStream{}
	err = c.r.Post().Namespace(c.ns).Resource("imageStreams").Body(stream).Do().Into(result)
	return
}

// Update updates the image stream on the server. Returns the server's representation of the image stream and error if one occurs.
func (c *imageStreams) Update(stream *imageapi.ImageStream) (result *imageapi.ImageStream, err error) {
	result = &imageapi.ImageStream{}
	err = c.r.Put().Namespace(c.ns).Resource("imageStreams").Name(stream.Name).Body(stream).Do().Into(result)
	return
}

// Delete deletes an image stream, returns error if one occurs.
func (c *imageStreams) Delete(name string) (err error) {
	err = c.r.Delete().Namespace(c.ns).Resource("imageStreams").Name(name).Do().Error()
	return
}

// Watch returns a watch.Interface that watches the requested image streams.
func (c *imageStreams) Watch(opts kapi.ListOptions) (watch.Interface, error) {
	return c.r.Get().
		Prefix("watch").
		Namespace(c.ns).
		Resource("imageStreams").
		VersionedParams(&opts, kapi.ParameterCodec).
		Watch()
}

// UpdateStatus updates the image stream's status. Returns the server's representation of the image stream, and an error, if it occurs.
func (c *imageStreams) UpdateStatus(stream *imageapi.ImageStream) (result *imageapi.ImageStream, err error) {
	result = &imageapi.ImageStream{}
	err = c.r.Put().Namespace(c.ns).Resource("imageStreams").Name(stream.Name).SubResource("status").Body(stream).Do().Into(result)
	return
}

// Import makes a call to the server to retrieve information about the requested images or to perform an import. ImageStreamImport
// will be returned if no actual import was requested (the to fields were not set), or an ImageStream if import was requested.
func (c *imageStreams) Import(isi *imageapi.ImageStreamImport) (*imageapi.ImageStreamImport, error) {
	result := &imageapi.ImageStreamImport{}
	if err := c.r.Post().Namespace(c.ns).Resource("imageStreamImports").Body(isi).Do().Into(result); err != nil {
		return nil, transformUnsupported(err)
	}
	return result, nil
}

// transformUnsupported converts specific error conditions to unsupported
func transformUnsupported(err error) error {
	if err == nil {
		return nil
	}
	if apierrs.IsNotFound(err) {
		status, ok := err.(apierrs.APIStatus)
		if !ok {
			return ErrImageStreamImportUnsupported
		}
		if status.Status().Details == nil || status.Status().Details.Kind == "" {
			return ErrImageStreamImportUnsupported
		}
	}
	// The ImageStreamImport resource exists in v1.1.1 of origin but is not yet
	// enabled by policy. A create request will return a Forbidden(403) error.
	// We want to return ErrImageStreamImportUnsupported to allow fallback behavior
	// in clients.
	if apierrs.IsForbidden(err) && !quotautil.IsErrorQuotaExceeded(err) {
		return ErrImageStreamImportUnsupported
	}
	return err
}
<|endoftext|>


<commit_before>/*
Copyright 2014 The Kubernetes Authors.

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

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

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

package version

import (
	"encoding/json"
	"errors"
	"fmt"

	"github.com/spf13/cobra"
	"sigs.k8s.io/yaml"

	apimachineryversion "k8s.io/apimachinery/pkg/version"
	"k8s.io/cli-runtime/pkg/genericclioptions"
	"k8s.io/client-go/discovery"
	"k8s.io/client-go/tools/clientcmd"
	"k8s.io/component-base/version"
	cmdutil "k8s.io/kubectl/pkg/cmd/util"
	"k8s.io/kubectl/pkg/util/i18n"
	"k8s.io/kubectl/pkg/util/templates"
)

// Version is a struct for version information
type Version struct {
	ClientVersion *apimachineryversion.Info `json:"clientVersion,omitempty" yaml:"clientVersion,omitempty"`
	ServerVersion *apimachineryversion.Info `json:"serverVersion,omitempty" yaml:"serverVersion,omitempty"`
}

var (
	versionExample = templates.Examples(i18n.T(`
		# Print the client and server versions for the current context
		kubectl version`))
)

// Options is a struct to support version command
type Options struct {
	ClientOnly bool
	Short      bool
	Output     string

	discoveryClient discovery.CachedDiscoveryInterface

	genericclioptions.IOStreams
}

// NewOptions returns initialized Options
func NewOptions(ioStreams genericclioptions.IOStreams) *Options {
	return &Options{
		IOStreams: ioStreams,
	}

}

// NewCmdVersion returns a cobra command for fetching versions
func NewCmdVersion(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
	o := NewOptions(ioStreams)
	cmd := &cobra.Command{
		Use:     "version",
		Short:   i18n.T("Print the client and server version information"),
		Long:    "Print the client and server version information for the current context",
		Example: versionExample,
		Run: func(cmd *cobra.Command, args []string) {
			cmdutil.CheckErr(o.Complete(f, cmd))
			cmdutil.CheckErr(o.Validate())
			cmdutil.CheckErr(o.Run())
		},
	}
	cmd.Flags().BoolVar(&o.ClientOnly, "client", o.ClientOnly, "Client version only (no server required).")
	cmd.Flags().BoolVar(&o.Short, "short", o.Short, "Print just the version number.")
	cmd.Flags().StringVarP(&o.Output, "output", "o", o.Output, "One of 'yaml' or 'json'.")
	return cmd
}

// Complete completes all the required options
func (o *Options) Complete(f cmdutil.Factory, cmd *cobra.Command) error {
	var err error
	if o.ClientOnly {
		return nil
	}
	o.discoveryClient, err = f.ToDiscoveryClient()
	// if we had an empty rest.Config, continue and just print out client information.
	// if we had an error other than being unable to build a rest.Config, fail.
	if err != nil && !clientcmd.IsEmptyConfig(err) {
		return err
	}
	return nil
}

// Validate validates the provided options
func (o *Options) Validate() error {
	if o.Output != "" && o.Output != "yaml" && o.Output != "json" {
		return errors.New(`--output must be 'yaml' or 'json'`)
	}

	return nil
}

// Run executes version command
func (o *Options) Run() error {
	var (
		serverVersion *apimachineryversion.Info
		serverErr     error
		versionInfo   Version
	)

	clientVersion := version.Get()
	versionInfo.ClientVersion = &clientVersion

	if !o.ClientOnly && o.discoveryClient != nil {
		// Always request fresh data from the server
		o.discoveryClient.Invalidate()
		serverVersion, serverErr = o.discoveryClient.ServerVersion()
		versionInfo.ServerVersion = serverVersion
	}

	switch o.Output {
	case "":
		if o.Short {
			fmt.Fprintf(o.Out, "Client Version: %s\n", clientVersion.GitVersion)
			if serverVersion != nil {
				fmt.Fprintf(o.Out, "Server Version: %s\n", serverVersion.GitVersion)
			}
		} else {
			fmt.Fprintf(o.Out, "Client Version: %s\n", fmt.Sprintf("%#v", clientVersion))
			if serverVersion != nil {
				fmt.Fprintf(o.Out, "Server Version: %s\n", fmt.Sprintf("%#v", *serverVersion))
			}
		}
	case "yaml":
		marshalled, err := yaml.Marshal(&versionInfo)
		if err != nil {
			return err
		}
		fmt.Fprintln(o.Out, string(marshalled))
	case "json":
		marshalled, err := json.MarshalIndent(&versionInfo, "", "  ")
		if err != nil {
			return err
		}
		fmt.Fprintln(o.Out, string(marshalled))
	default:
		// There is a bug in the program if we hit this case.
		// However, we follow a policy of never panicking.
		return fmt.Errorf("VersionOptions were not validated: --output=%q should have been rejected", o.Output)
	}

	return serverErr
}
<commit_msg>optimize kubectl version help info<commit_after>/*
Copyright 2014 The Kubernetes Authors.

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

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

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

package version

import (
	"encoding/json"
	"errors"
	"fmt"

	"github.com/spf13/cobra"
	"sigs.k8s.io/yaml"

	apimachineryversion "k8s.io/apimachinery/pkg/version"
	"k8s.io/cli-runtime/pkg/genericclioptions"
	"k8s.io/client-go/discovery"
	"k8s.io/client-go/tools/clientcmd"
	"k8s.io/component-base/version"
	cmdutil "k8s.io/kubectl/pkg/cmd/util"
	"k8s.io/kubectl/pkg/util/i18n"
	"k8s.io/kubectl/pkg/util/templates"
)

// Version is a struct for version information
type Version struct {
	ClientVersion *apimachineryversion.Info `json:"clientVersion,omitempty" yaml:"clientVersion,omitempty"`
	ServerVersion *apimachineryversion.Info `json:"serverVersion,omitempty" yaml:"serverVersion,omitempty"`
}

var (
	versionExample = templates.Examples(i18n.T(`
		# Print the client and server versions for the current context
		kubectl version`))
)

// Options is a struct to support version command
type Options struct {
	ClientOnly bool
	Short      bool
	Output     string

	discoveryClient discovery.CachedDiscoveryInterface

	genericclioptions.IOStreams
}

// NewOptions returns initialized Options
func NewOptions(ioStreams genericclioptions.IOStreams) *Options {
	return &Options{
		IOStreams: ioStreams,
	}

}

// NewCmdVersion returns a cobra command for fetching versions
func NewCmdVersion(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
	o := NewOptions(ioStreams)
	cmd := &cobra.Command{
		Use:     "version",
		Short:   i18n.T("Print the client and server version information"),
		Long:    "Print the client and server version information for the current context",
		Example: versionExample,
		Run: func(cmd *cobra.Command, args []string) {
			cmdutil.CheckErr(o.Complete(f, cmd))
			cmdutil.CheckErr(o.Validate())
			cmdutil.CheckErr(o.Run())
		},
	}
	cmd.Flags().BoolVar(&o.ClientOnly, "client", o.ClientOnly, "If true, shows client version only (no server required).")
	cmd.Flags().BoolVar(&o.Short, "short", o.Short, "If true, print just the version number.")
	cmd.Flags().StringVarP(&o.Output, "output", "o", o.Output, "One of 'yaml' or 'json'.")
	return cmd
}

// Complete completes all the required options
func (o *Options) Complete(f cmdutil.Factory, cmd *cobra.Command) error {
	var err error
	if o.ClientOnly {
		return nil
	}
	o.discoveryClient, err = f.ToDiscoveryClient()
	// if we had an empty rest.Config, continue and just print out client information.
	// if we had an error other than being unable to build a rest.Config, fail.
	if err != nil && !clientcmd.IsEmptyConfig(err) {
		return err
	}
	return nil
}

// Validate validates the provided options
func (o *Options) Validate() error {
	if o.Output != "" && o.Output != "yaml" && o.Output != "json" {
		return errors.New(`--output must be 'yaml' or 'json'`)
	}

	return nil
}

// Run executes version command
func (o *Options) Run() error {
	var (
		serverVersion *apimachineryversion.Info
		serverErr     error
		versionInfo   Version
	)

	clientVersion := version.Get()
	versionInfo.ClientVersion = &clientVersion

	if !o.ClientOnly && o.discoveryClient != nil {
		// Always request fresh data from the server
		o.discoveryClient.Invalidate()
		serverVersion, serverErr = o.discoveryClient.ServerVersion()
		versionInfo.ServerVersion = serverVersion
	}

	switch o.Output {
	case "":
		if o.Short {
			fmt.Fprintf(o.Out, "Client Version: %s\n", clientVersion.GitVersion)
			if serverVersion != nil {
				fmt.Fprintf(o.Out, "Server Version: %s\n", serverVersion.GitVersion)
			}
		} else {
			fmt.Fprintf(o.Out, "Client Version: %s\n", fmt.Sprintf("%#v", clientVersion))
			if serverVersion != nil {
				fmt.Fprintf(o.Out, "Server Version: %s\n", fmt.Sprintf("%#v", *serverVersion))
			}
		}
	case "yaml":
		marshalled, err := yaml.Marshal(&versionInfo)
		if err != nil {
			return err
		}
		fmt.Fprintln(o.Out, string(marshalled))
	case "json":
		marshalled, err := json.MarshalIndent(&versionInfo, "", "  ")
		if err != nil {
			return err
		}
		fmt.Fprintln(o.Out, string(marshalled))
	default:
		// There is a bug in the program if we hit this case.
		// However, we follow a policy of never panicking.
		return fmt.Errorf("VersionOptions were not validated: --output=%q should have been rejected", o.Output)
	}

	return serverErr
}
<|endoftext|>


<commit_before>package controller

import (
	"fmt"
	"path"
	"sync"
	"time"

	"github.com/go-kit/kit/log"
	"github.com/gophercloud/gophercloud/openstack/identity/v3/tokens"
	api_v1 "k8s.io/api/core/v1"
	apiextensionsclient "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
	kubernetes_informers "k8s.io/client-go/informers"
	"k8s.io/client-go/kubernetes/scheme"
	typedcorev1 "k8s.io/client-go/kubernetes/typed/core/v1"
	"k8s.io/client-go/tools/record"

	v1 "github.com/sapcc/kubernikus/pkg/apis/kubernikus/v1"
	helmutil "github.com/sapcc/kubernikus/pkg/client/helm"
	kube "github.com/sapcc/kubernikus/pkg/client/kubernetes"
	"github.com/sapcc/kubernikus/pkg/client/kubernikus"
	"github.com/sapcc/kubernikus/pkg/client/openstack"
	"github.com/sapcc/kubernikus/pkg/controller/certs"
	"github.com/sapcc/kubernikus/pkg/controller/config"
	"github.com/sapcc/kubernikus/pkg/controller/deorbit"
	"github.com/sapcc/kubernikus/pkg/controller/flight"
	"github.com/sapcc/kubernikus/pkg/controller/hammertime"
	"github.com/sapcc/kubernikus/pkg/controller/launch"
	"github.com/sapcc/kubernikus/pkg/controller/migration"
	"github.com/sapcc/kubernikus/pkg/controller/nodeobservatory"
	"github.com/sapcc/kubernikus/pkg/controller/routegc"
	kubernikus_informers "github.com/sapcc/kubernikus/pkg/generated/informers/externalversions"
	_ "github.com/sapcc/kubernikus/pkg/util/workqueue/prometheus"
	"github.com/sapcc/kubernikus/pkg/version"
)

type KubernikusOperatorOptions struct {
	KubeConfig string
	Context    string

	ChartDirectory string

	AuthURL           string
	AuthUsername      string
	AuthPassword      string
	AuthDomain        string
	AuthProject       string
	AuthProjectDomain string
	Region            string

	KubernikusDomain    string
	KubernikusProjectID string
	KubernikusNetworkID string
	Namespace           string
	Controllers         []string
	MetricPort          int
	LogLevel            int

	NodeUpdateHoldoff time.Duration
}

type KubernikusOperator struct {
	config.Config
	config.Factories
	config.Clients
	Logger log.Logger
}

const (
	DEFAULT_RECONCILIATION = 5 * time.Minute
)

func NewKubernikusOperator(options *KubernikusOperatorOptions, logger log.Logger) (*KubernikusOperator, error) {
	var err error

	imageRegistry, err := version.NewImageRegistry(path.Join(options.ChartDirectory, "images.yaml"), options.Region)
	if err != nil {
		return nil, fmt.Errorf("Unable to initialize image registry: %s", err)
	}

	o := &KubernikusOperator{
		Config: config.Config{
			Openstack: config.OpenstackConfig{
				AuthURL:           options.AuthURL,
				AuthUsername:      options.AuthUsername,
				AuthPassword:      options.AuthPassword,
				AuthProject:       options.AuthProjectDomain,
				AuthProjectDomain: options.AuthProjectDomain,
			},
			Helm: config.HelmConfig{
				ChartDirectory: options.ChartDirectory,
			},
			Kubernikus: config.KubernikusConfig{
				Domain:      options.KubernikusDomain,
				Namespace:   options.Namespace,
				ProjectID:   options.KubernikusProjectID,
				NetworkID:   options.KubernikusNetworkID,
				Controllers: make(map[string]config.Controller),
			},
			Images: *imageRegistry,
		},
		Logger: logger,
	}

	o.Clients.Kubernetes, err = kube.NewClient(options.KubeConfig, options.Context, logger)

	if err != nil {
		return nil, fmt.Errorf("Failed to create kubernetes clients: %s", err)
	}

	o.Clients.Kubernikus, err = kubernikus.NewClient(options.KubeConfig, options.Context)
	if err != nil {
		return nil, fmt.Errorf("Failed to create kubernikus clients: %s", err)
	}

	config, err := kube.NewConfig(options.KubeConfig, options.Context)
	if err != nil {
		return nil, fmt.Errorf("Failed to create kubernetes config: %s", err)
	}
	o.Clients.Helm, err = helmutil.NewClient(o.Clients.Kubernetes, config, logger)
	if err != nil {
		return nil, fmt.Errorf("Failed to create helm client: %s", err)
	}

	apiextensionsclientset, err := apiextensionsclient.NewForConfig(config)
	if err != nil {
		return nil, fmt.Errorf("Failed to create apiextenstionsclient: %s", err)
	}

	if err := kube.EnsureCRD(apiextensionsclientset, logger); err != nil {
		return nil, fmt.Errorf("Couldn't create CRD: %s", err)
	}

	adminAuthOptions := &tokens.AuthOptions{
		IdentityEndpoint: options.AuthURL,
		Username:         options.AuthUsername,
		Password:         options.AuthPassword,
		DomainName:       options.AuthDomain,
		AllowReauth:      true,
		Scope: tokens.Scope{
			ProjectName: options.AuthProject,
			DomainName:  options.AuthProjectDomain,
		},
	}

	o.Factories.Kubernikus = kubernikus_informers.NewFilteredSharedInformerFactory(o.Clients.Kubernikus, DEFAULT_RECONCILIATION, options.Namespace, nil)
	o.Factories.Kubernetes = kubernetes_informers.NewFilteredSharedInformerFactory(o.Clients.Kubernetes, DEFAULT_RECONCILIATION, options.Namespace, nil)

	klusters := o.Factories.Kubernikus.Kubernikus().V1().Klusters().Informer()

	if options.AuthURL != "" {
		o.Factories.Openstack = openstack.NewSharedOpenstackClientFactory(o.Clients.Kubernetes, klusters, adminAuthOptions, logger)
	} else {
		o.Factories.Openstack = openstack.NotAvailableFactory{}
	}

	o.Clients.Satellites = kube.NewSharedClientFactory(o.Clients.Kubernetes, klusters, logger)

	o.Factories.NodesObservatory = nodeobservatory.NewInformerFactory(o.Factories.Kubernikus.Kubernikus().V1().Klusters(), o.Clients.Satellites, logger)

	// Add kubernikus types to the default Kubernetes Scheme so events can be
	// logged for those types.
	v1.AddToScheme(scheme.Scheme)
	eventBroadcaster := record.NewBroadcaster()
	eventBroadcaster.StartEventWatcher(func(e *api_v1.Event) {
		logger.Log(
			"controller", "operator",
			"resource", "event",
			"msg", e.Message,
			"reason", e.Reason,
			"type", e.Type,
			"kind", e.InvolvedObject.Kind,
			"namespace", e.InvolvedObject.Namespace,
			"name", e.InvolvedObject.Name,
			"v", 2)
	})

	eventBroadcaster.StartRecordingToSink(&typedcorev1.EventSinkImpl{Interface: o.Clients.Kubernetes.CoreV1().Events(o.Config.Kubernikus.Namespace)})
	recorder := eventBroadcaster.NewRecorder(scheme.Scheme, api_v1.EventSource{Component: "operator"})

	for _, k := range options.Controllers {
		switch k {
		case "groundctl":
			o.Config.Kubernikus.Controllers["groundctl"] = NewGroundController(10, o.Factories, o.Clients, recorder, o.Config, logger)
		case "launchctl":
			o.Config.Kubernikus.Controllers["launchctl"] = launch.NewController(10, o.Factories, o.Clients, recorder, o.Config.Images, logger)
		case "routegc":
			o.Config.Kubernikus.Controllers["routegc"] = routegc.New(300*time.Second, o.Factories, logger)
		case "deorbiter":
			o.Config.Kubernikus.Controllers["deorbiter"] = deorbit.NewController(10, o.Factories, o.Clients, recorder, logger)
		case "flight":
			o.Config.Kubernikus.Controllers["flight"] = flight.NewController(10, o.Factories, o.Clients, recorder, logger)
		case "migration":
			o.Config.Kubernikus.Controllers["migration"] = migration.NewController(10, o.Factories, o.Clients, recorder, logger)
		case "hammertime":
			o.Config.Kubernikus.Controllers["hammertime"] = hammertime.New(10*time.Second, 20*time.Second, o.Factories, o.Clients, recorder, logger)
			//		case "servicing":
			//			o.Config.Kubernikus.Controllers["servicing"] = servicing.NewController(10, o.Factories, o.Clients, recorder, options.NodeUpdateHoldoff, logger)
		case "certs":
			o.Config.Kubernikus.Controllers["certs"] = certs.New(12*time.Hour, o.Factories, o.Config, o.Clients, logger)
		}
	}

	return o, err
}

func (o *KubernikusOperator) Run(stopCh <-chan struct{}, wg *sync.WaitGroup) {
	o.Logger.Log(
		"msg", "starting kubernikus operator",
		"namespace", o.Config.Kubernikus.Namespace,
		"version", version.GitCommit)

	kube.WaitForServer(o.Clients.Kubernetes, stopCh, o.Logger)

	o.Factories.Kubernikus.Start(stopCh)
	o.Factories.Kubernetes.Start(stopCh)
	o.Factories.NodesObservatory.Start(stopCh)

	o.Factories.Kubernikus.WaitForCacheSync(stopCh)
	o.Factories.Kubernetes.WaitForCacheSync(stopCh)

	o.Logger.Log("msg", "Cache primed")
	if _, found := o.Config.Kubernikus.Controllers["migration"]; found {
		migration.UpdateMigrationStatus(o.Clients.Kubernikus, o.Factories.Kubernikus.Kubernikus().V1().Klusters().Lister())
	}
	o.Logger.Log("msg", "Starting controllers")
	for _, controller := range o.Config.Kubernikus.Controllers {
		go controller.Run(stopCh, wg)
	}
}
<commit_msg>Revert "Disable servicing controller" (#642)<commit_after>package controller

import (
	"fmt"
	"path"
	"sync"
	"time"

	"github.com/go-kit/kit/log"
	"github.com/gophercloud/gophercloud/openstack/identity/v3/tokens"
	api_v1 "k8s.io/api/core/v1"
	apiextensionsclient "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
	kubernetes_informers "k8s.io/client-go/informers"
	"k8s.io/client-go/kubernetes/scheme"
	typedcorev1 "k8s.io/client-go/kubernetes/typed/core/v1"
	"k8s.io/client-go/tools/record"

	v1 "github.com/sapcc/kubernikus/pkg/apis/kubernikus/v1"
	helmutil "github.com/sapcc/kubernikus/pkg/client/helm"
	kube "github.com/sapcc/kubernikus/pkg/client/kubernetes"
	"github.com/sapcc/kubernikus/pkg/client/kubernikus"
	"github.com/sapcc/kubernikus/pkg/client/openstack"
	"github.com/sapcc/kubernikus/pkg/controller/certs"
	"github.com/sapcc/kubernikus/pkg/controller/config"
	"github.com/sapcc/kubernikus/pkg/controller/deorbit"
	"github.com/sapcc/kubernikus/pkg/controller/flight"
	"github.com/sapcc/kubernikus/pkg/controller/hammertime"
	"github.com/sapcc/kubernikus/pkg/controller/launch"
	"github.com/sapcc/kubernikus/pkg/controller/migration"
	"github.com/sapcc/kubernikus/pkg/controller/nodeobservatory"
	"github.com/sapcc/kubernikus/pkg/controller/routegc"
	"github.com/sapcc/kubernikus/pkg/controller/servicing"
	kubernikus_informers "github.com/sapcc/kubernikus/pkg/generated/informers/externalversions"
	_ "github.com/sapcc/kubernikus/pkg/util/workqueue/prometheus"
	"github.com/sapcc/kubernikus/pkg/version"
)

type KubernikusOperatorOptions struct {
	KubeConfig string
	Context    string

	ChartDirectory string

	AuthURL           string
	AuthUsername      string
	AuthPassword      string
	AuthDomain        string
	AuthProject       string
	AuthProjectDomain string
	Region            string

	KubernikusDomain    string
	KubernikusProjectID string
	KubernikusNetworkID string
	Namespace           string
	Controllers         []string
	MetricPort          int
	LogLevel            int

	NodeUpdateHoldoff time.Duration
}

type KubernikusOperator struct {
	config.Config
	config.Factories
	config.Clients
	Logger log.Logger
}

const (
	DEFAULT_RECONCILIATION = 5 * time.Minute
)

func NewKubernikusOperator(options *KubernikusOperatorOptions, logger log.Logger) (*KubernikusOperator, error) {
	var err error

	imageRegistry, err := version.NewImageRegistry(path.Join(options.ChartDirectory, "images.yaml"), options.Region)
	if err != nil {
		return nil, fmt.Errorf("Unable to initialize image registry: %s", err)
	}

	o := &KubernikusOperator{
		Config: config.Config{
			Openstack: config.OpenstackConfig{
				AuthURL:           options.AuthURL,
				AuthUsername:      options.AuthUsername,
				AuthPassword:      options.AuthPassword,
				AuthProject:       options.AuthProjectDomain,
				AuthProjectDomain: options.AuthProjectDomain,
			},
			Helm: config.HelmConfig{
				ChartDirectory: options.ChartDirectory,
			},
			Kubernikus: config.KubernikusConfig{
				Domain:      options.KubernikusDomain,
				Namespace:   options.Namespace,
				ProjectID:   options.KubernikusProjectID,
				NetworkID:   options.KubernikusNetworkID,
				Controllers: make(map[string]config.Controller),
			},
			Images: *imageRegistry,
		},
		Logger: logger,
	}

	o.Clients.Kubernetes, err = kube.NewClient(options.KubeConfig, options.Context, logger)

	if err != nil {
		return nil, fmt.Errorf("Failed to create kubernetes clients: %s", err)
	}

	o.Clients.Kubernikus, err = kubernikus.NewClient(options.KubeConfig, options.Context)
	if err != nil {
		return nil, fmt.Errorf("Failed to create kubernikus clients: %s", err)
	}

	config, err := kube.NewConfig(options.KubeConfig, options.Context)
	if err != nil {
		return nil, fmt.Errorf("Failed to create kubernetes config: %s", err)
	}
	o.Clients.Helm, err = helmutil.NewClient(o.Clients.Kubernetes, config, logger)
	if err != nil {
		return nil, fmt.Errorf("Failed to create helm client: %s", err)
	}

	apiextensionsclientset, err := apiextensionsclient.NewForConfig(config)
	if err != nil {
		return nil, fmt.Errorf("Failed to create apiextenstionsclient: %s", err)
	}

	if err := kube.EnsureCRD(apiextensionsclientset, logger); err != nil {
		return nil, fmt.Errorf("Couldn't create CRD: %s", err)
	}

	adminAuthOptions := &tokens.AuthOptions{
		IdentityEndpoint: options.AuthURL,
		Username:         options.AuthUsername,
		Password:         options.AuthPassword,
		DomainName:       options.AuthDomain,
		AllowReauth:      true,
		Scope: tokens.Scope{
			ProjectName: options.AuthProject,
			DomainName:  options.AuthProjectDomain,
		},
	}

	o.Factories.Kubernikus = kubernikus_informers.NewFilteredSharedInformerFactory(o.Clients.Kubernikus, DEFAULT_RECONCILIATION, options.Namespace, nil)
	o.Factories.Kubernetes = kubernetes_informers.NewFilteredSharedInformerFactory(o.Clients.Kubernetes, DEFAULT_RECONCILIATION, options.Namespace, nil)

	klusters := o.Factories.Kubernikus.Kubernikus().V1().Klusters().Informer()

	if options.AuthURL != "" {
		o.Factories.Openstack = openstack.NewSharedOpenstackClientFactory(o.Clients.Kubernetes, klusters, adminAuthOptions, logger)
	} else {
		o.Factories.Openstack = openstack.NotAvailableFactory{}
	}

	o.Clients.Satellites = kube.NewSharedClientFactory(o.Clients.Kubernetes, klusters, logger)

	o.Factories.NodesObservatory = nodeobservatory.NewInformerFactory(o.Factories.Kubernikus.Kubernikus().V1().Klusters(), o.Clients.Satellites, logger)

	// Add kubernikus types to the default Kubernetes Scheme so events can be
	// logged for those types.
	v1.AddToScheme(scheme.Scheme)
	eventBroadcaster := record.NewBroadcaster()
	eventBroadcaster.StartEventWatcher(func(e *api_v1.Event) {
		logger.Log(
			"controller", "operator",
			"resource", "event",
			"msg", e.Message,
			"reason", e.Reason,
			"type", e.Type,
			"kind", e.InvolvedObject.Kind,
			"namespace", e.InvolvedObject.Namespace,
			"name", e.InvolvedObject.Name,
			"v", 2)
	})

	eventBroadcaster.StartRecordingToSink(&typedcorev1.EventSinkImpl{Interface: o.Clients.Kubernetes.CoreV1().Events(o.Config.Kubernikus.Namespace)})
	recorder := eventBroadcaster.NewRecorder(scheme.Scheme, api_v1.EventSource{Component: "operator"})

	for _, k := range options.Controllers {
		switch k {
		case "groundctl":
			o.Config.Kubernikus.Controllers["groundctl"] = NewGroundController(10, o.Factories, o.Clients, recorder, o.Config, logger)
		case "launchctl":
			o.Config.Kubernikus.Controllers["launchctl"] = launch.NewController(10, o.Factories, o.Clients, recorder, o.Config.Images, logger)
		case "routegc":
			o.Config.Kubernikus.Controllers["routegc"] = routegc.New(300*time.Second, o.Factories, logger)
		case "deorbiter":
			o.Config.Kubernikus.Controllers["deorbiter"] = deorbit.NewController(10, o.Factories, o.Clients, recorder, logger)
		case "flight":
			o.Config.Kubernikus.Controllers["flight"] = flight.NewController(10, o.Factories, o.Clients, recorder, logger)
		case "migration":
			o.Config.Kubernikus.Controllers["migration"] = migration.NewController(10, o.Factories, o.Clients, recorder, logger)
		case "hammertime":
			o.Config.Kubernikus.Controllers["hammertime"] = hammertime.New(10*time.Second, 20*time.Second, o.Factories, o.Clients, recorder, logger)
		case "servicing":
			o.Config.Kubernikus.Controllers["servicing"] = servicing.NewController(10, o.Factories, o.Clients, recorder, options.NodeUpdateHoldoff, logger)
		case "certs":
			o.Config.Kubernikus.Controllers["certs"] = certs.New(12*time.Hour, o.Factories, o.Config, o.Clients, logger)
		}
	}

	return o, err
}

func (o *KubernikusOperator) Run(stopCh <-chan struct{}, wg *sync.WaitGroup) {
	o.Logger.Log(
		"msg", "starting kubernikus operator",
		"namespace", o.Config.Kubernikus.Namespace,
		"version", version.GitCommit)

	kube.WaitForServer(o.Clients.Kubernetes, stopCh, o.Logger)

	o.Factories.Kubernikus.Start(stopCh)
	o.Factories.Kubernetes.Start(stopCh)
	o.Factories.NodesObservatory.Start(stopCh)

	o.Factories.Kubernikus.WaitForCacheSync(stopCh)
	o.Factories.Kubernetes.WaitForCacheSync(stopCh)

	o.Logger.Log("msg", "Cache primed")
	if _, found := o.Config.Kubernikus.Controllers["migration"]; found {
		migration.UpdateMigrationStatus(o.Clients.Kubernikus, o.Factories.Kubernikus.Kubernikus().V1().Klusters().Lister())
	}
	o.Logger.Log("msg", "Starting controllers")
	for _, controller := range o.Config.Kubernikus.Controllers {
		go controller.Run(stopCh, wg)
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2017 The Kubernetes Authors.

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

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

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

import (
	"context"
	"crypto/x509"
	"fmt"
	"net"
	"net/url"
	"strings"
	"time"

	"github.com/grpc-ecosystem/go-grpc-middleware/util/metautils"
	"github.com/libopenstorage/openstorage/pkg/util"
	"github.com/sirupsen/logrus"
	"google.golang.org/grpc"
	"google.golang.org/grpc/connectivity"
	"google.golang.org/grpc/credentials"
	"google.golang.org/grpc/metadata"
)

// GetTlsDialOptions returns the appropriate gRPC dial options to connect to a gRPC server over TLS.
// If caCertData is nil then it will use the CA from the host.
func GetTlsDialOptions(caCertData []byte) ([]grpc.DialOption, error) {
	// Read the provided CA cert from the user
	capool, err := x509.SystemCertPool()
	if err != nil || capool == nil {
		logrus.Warnf("cannot load system root certificates: %v", err)
		capool = x509.NewCertPool()
	}

	// If user provided CA cert, then append it to systemCertPool.
	if len(caCertData) != 0 {
		if !capool.AppendCertsFromPEM(caCertData) {
			return nil, fmt.Errorf("cannot parse CA certificate")
		}
	}

	dialOptions := []grpc.DialOption{grpc.WithTransportCredentials(
		credentials.NewClientTLSFromCert(capool, ""))}
	return dialOptions, nil
}

// Connect to address by grpc
func Connect(address string, dialOptions []grpc.DialOption) (*grpc.ClientConn, error) {
	u, err := url.Parse(address)
	if err == nil && (!u.IsAbs() || u.Scheme == "unix") {
		dialOptions = append(dialOptions,
			grpc.WithDialer(
				func(addr string, timeout time.Duration) (net.Conn, error) {
					return net.DialTimeout("unix", u.Path, timeout)
				}))
	}

	dialOptions = append(dialOptions, grpc.WithBackoffMaxDelay(time.Second))
	conn, err := grpc.Dial(address, dialOptions...)
	if err != nil {
		return nil, err
	}

	// We wait for 1 minute until conn.GetState() is READY.
	// The interval for this check is 1 second.
	if err := util.WaitFor(1*time.Minute, 10*time.Millisecond, func() (bool, error) {
		if conn.GetState() == connectivity.Ready {
			return false, nil
		}
		return true, nil
	}); err != nil {
		// Clean up the connection
		if err := conn.Close(); err != nil {
			logrus.Warnf("Failed to close connection to %v: %v", address, err)
		}
		return nil, fmt.Errorf("Connection timed out")
	}

	return conn, nil
}

func AddMetadataToContext(ctx context.Context, k, v string) context.Context {
	md, _ := metadata.FromOutgoingContext(ctx)
	md = metadata.Join(md, metadata.New(map[string]string{
		k: v,
	}))
	return metadata.NewOutgoingContext(ctx, md)
}

func GetMetadataValueFromKey(ctx context.Context, k string) string {
	return metautils.ExtractIncoming(ctx).Get(k)
}

// GetMethodInformation returns the service and API of a gRPC fullmethod string.
// For example, if the full method is:
//   /openstorage.api.OpenStorage<service>/<method>
// Then, to extract the service and api we would call it as follows:
//   s, a := GetMethodInformation("openstorage.api.OpenStorage", info.FullMethod)
//      where info.FullMethod comes from the gRPC interceptor
func GetMethodInformation(constPath, fullmethod string) (service, api string) {
	parts := strings.Split(fullmethod, "/")

	if len(parts) > 1 {
		service = strings.TrimPrefix(strings.ToLower(parts[1]), strings.ToLower(constPath))
	}

	if len(parts) > 2 {
		api = strings.ToLower(parts[2])
	}

	return service, api
}
<commit_msg>Grpc connect util with a timeout<commit_after>/*
Copyright 2017 The Kubernetes Authors.

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

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

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

import (
	"context"
	"crypto/x509"
	"fmt"
	"net"
	"net/url"
	"strings"
	"time"

	"github.com/grpc-ecosystem/go-grpc-middleware/util/metautils"
	"github.com/libopenstorage/openstorage/pkg/util"
	"github.com/sirupsen/logrus"
	"google.golang.org/grpc"
	"google.golang.org/grpc/connectivity"
	"google.golang.org/grpc/credentials"
	"google.golang.org/grpc/metadata"
)

// GetTlsDialOptions returns the appropriate gRPC dial options to connect to a gRPC server over TLS.
// If caCertData is nil then it will use the CA from the host.
func GetTlsDialOptions(caCertData []byte) ([]grpc.DialOption, error) {
	// Read the provided CA cert from the user
	capool, err := x509.SystemCertPool()
	if err != nil || capool == nil {
		logrus.Warnf("cannot load system root certificates: %v", err)
		capool = x509.NewCertPool()
	}

	// If user provided CA cert, then append it to systemCertPool.
	if len(caCertData) != 0 {
		if !capool.AppendCertsFromPEM(caCertData) {
			return nil, fmt.Errorf("cannot parse CA certificate")
		}
	}

	dialOptions := []grpc.DialOption{grpc.WithTransportCredentials(
		credentials.NewClientTLSFromCert(capool, ""))}
	return dialOptions, nil
}

// Connect to address by grpc
func Connect(address string, dialOptions []grpc.DialOption) (*grpc.ClientConn, error) {
	return ConnectWithTimeout(address, dialOptions, 1*time.Minute)
}

// ConnectWithTimeout to address by grpc with timeout
func ConnectWithTimeout(address string, dialOptions []grpc.DialOption, timeout time.Duration) (*grpc.ClientConn, error) {
	u, err := url.Parse(address)
	if err == nil && (!u.IsAbs() || u.Scheme == "unix") {
		dialOptions = append(dialOptions,
			grpc.WithDialer(
				func(addr string, timeout time.Duration) (net.Conn, error) {
					return net.DialTimeout("unix", u.Path, timeout)
				}))
	}

	dialOptions = append(dialOptions, grpc.WithBackoffMaxDelay(time.Second))
	conn, err := grpc.Dial(address, dialOptions...)
	if err != nil {
		return nil, err
	}

	// We wait for given timeout until conn.GetState() is READY.
	// The interval for this check is 10 ms.
	if err := util.WaitFor(timeout, 10*time.Millisecond, func() (bool, error) {
		if conn.GetState() == connectivity.Ready {
			return false, nil
		}
		return true, nil
	}); err != nil {
		// Clean up the connection
		if err := conn.Close(); err != nil {
			logrus.Warnf("Failed to close connection to %v: %v", address, err)
		}
		return nil, fmt.Errorf("Connection timed out")
	}

	return conn, nil
}

func AddMetadataToContext(ctx context.Context, k, v string) context.Context {
	md, _ := metadata.FromOutgoingContext(ctx)
	md = metadata.Join(md, metadata.New(map[string]string{
		k: v,
	}))
	return metadata.NewOutgoingContext(ctx, md)
}

func GetMetadataValueFromKey(ctx context.Context, k string) string {
	return metautils.ExtractIncoming(ctx).Get(k)
}

// GetMethodInformation returns the service and API of a gRPC fullmethod string.
// For example, if the full method is:
//   /openstorage.api.OpenStorage<service>/<method>
// Then, to extract the service and api we would call it as follows:
//   s, a := GetMethodInformation("openstorage.api.OpenStorage", info.FullMethod)
//      where info.FullMethod comes from the gRPC interceptor
func GetMethodInformation(constPath, fullmethod string) (service, api string) {
	parts := strings.Split(fullmethod, "/")

	if len(parts) > 1 {
		service = strings.TrimPrefix(strings.ToLower(parts[1]), strings.ToLower(constPath))
	}

	if len(parts) > 2 {
		api = strings.ToLower(parts[2])
	}

	return service, api
}
<|endoftext|>